Rocko's round 2 candidate, approved by Darkwing (#1519 comment 26757).
build.patch 40d7e838, manifest 61519059, 24 files under packages/bus,
schema v3b (179ffe35, lead decision 60). Integration gate in a git
worktree of 942dca9e (S1 in the tree) plus the patch: bus 43/43 and
business 60/60 on Node 24 and 26, every package test and every
scripts/test-*.sh green, test-task 98/98 with the live-provider cases.
Rulings from lead decisions 62 and 63: the human proof is cooperative in
slice 1, and a self-raised cross-role decision routes to the human.
Single-use gated approvals follow in row 43.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
45 lines
1.7 KiB
JavaScript
45 lines
1.7 KiB
JavaScript
import { connect } from 'node:net';
|
|
import { BusError } from './broker.mjs';
|
|
export class Client {
|
|
constructor({ path, cap, human, timeout = 5000 }) {
|
|
this.path = path;
|
|
this.cap = cap;
|
|
this.human = human;
|
|
this.timeout = timeout;
|
|
}
|
|
call(verb, args = {}) {
|
|
const request =
|
|
JSON.stringify({ ...(this.human ? { human: this.human } : { cap: this.cap }), verb, args }) + '\n';
|
|
if (Buffer.byteLength(request) > 65536) return Promise.reject(new BusError('request-too-large'));
|
|
return new Promise((resolve, reject) => {
|
|
const socket = connect(this.path);
|
|
let input = Buffer.alloc(0),
|
|
settled = false;
|
|
const end = (error, value) => {
|
|
if (settled) return;
|
|
settled = true;
|
|
socket.destroy();
|
|
error ? reject(error) : resolve(value);
|
|
};
|
|
socket.setTimeout(this.timeout, () => end(new BusError('outcome-unknown')));
|
|
socket.on('connect', () => socket.write(request));
|
|
socket.on('error', () => end(new BusError('outcome-unknown')));
|
|
socket.on('end', () => end(new BusError('outcome-unknown')));
|
|
socket.on('data', (b) => {
|
|
input = Buffer.concat([input, b]);
|
|
if (input.length > 4 * 1024 * 1024) return end(new BusError('response-too-large'));
|
|
if (!input.includes(10)) return;
|
|
try {
|
|
const r = JSON.parse(input.toString('utf8'));
|
|
if (r.ok === true) end(null, r.result);
|
|
else if (r.ok === false && typeof r.error === 'string' && /^[a-z-]{1,64}$/.test(r.error))
|
|
end(new BusError(r.error));
|
|
else end(new BusError('invalid-response'));
|
|
} catch {
|
|
end(new BusError('invalid-response'));
|
|
}
|
|
});
|
|
});
|
|
}
|
|
}
|