import type { Socket } from "net"; export const MAX_FRAME_BYTES = 4 * 1024 * 1024; /** * Write a length-prefixed message to a socket. * Format: 4-byte big-endian length + JSON payload */ export function writeMessage(socket: Socket, msg: unknown): void { const json = JSON.stringify(msg); const payload = Buffer.from(json, "utf-8"); if (payload.length > MAX_FRAME_BYTES) { throw new Error(`Intercom message exceeds ${MAX_FRAME_BYTES} byte limit`); } const header = Buffer.alloc(4); header.writeUInt32BE(payload.length, 0); socket.write(Buffer.concat([header, payload])); } /** * Create a message reader that handles partial reads. * Calls onMessage for each complete message received. * Protocol or handler errors are reported to onError so the caller can close the socket. */ export function createMessageReader( onMessage: (msg: unknown) => void, onError: (error: Error) => void, ) { let buffer = Buffer.alloc(0); return (data: Buffer) => { buffer = Buffer.concat([buffer, data]); while (buffer.length >= 4) { const length = buffer.readUInt32BE(0); if (length > MAX_FRAME_BYTES) { buffer = Buffer.alloc(0); onError(new Error(`Intercom frame exceeds ${MAX_FRAME_BYTES} byte limit`)); return; } if (buffer.length > 4 + MAX_FRAME_BYTES) { buffer = Buffer.alloc(0); onError(new Error(`Intercom frame buffer exceeds ${MAX_FRAME_BYTES} byte limit`)); return; } if (buffer.length < 4 + length) { break; } const payload = buffer.subarray(4, 4 + length); buffer = buffer.subarray(4 + length); let msg: unknown; try { msg = JSON.parse(payload.toString("utf-8")); } catch (error) { const message = error instanceof Error ? error.message : String(error); onError(new Error(`Failed to parse intercom message: ${message}`, { cause: error })); return; } try { onMessage(msg); } catch (error) { const message = error instanceof Error ? error.message : String(error); onError(new Error(`Failed to handle intercom message: ${message}`, { cause: error })); return; } } }; }