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')); } }); }); } }