Files
paseo/packages/protocol/src/binary-frames/host-route.ts
T
Mohamed Boudra 5ab9b8dcd4 fix(hosts): share daemon links across isolated routed sessions
Multiplex logical sessions over the monitored daemon connection and wrap original binary bytes in routing headers. Admit channels under their authenticated parent and current grants; preserve scoped delivery and physical send completion.
2026-10-20 07:59:01 +02:00

34 lines
1.6 KiB
TypeScript

import { MAX_WEBSOCKET_MESSAGE_BYTES } from "../websocket-message-limit.js";
/** Routing adds a bounded header; the enclosed terminal/file frame is never re-encoded. */
export const HOST_ROUTE_OPCODE = 0x30;
export const MAX_HOST_ROUTE_ID_BYTES = 256;
export const MAX_HOST_ROUTE_HEADER_BYTES = 3 + MAX_HOST_ROUTE_ID_BYTES;
export const MAX_ROUTED_PAYLOAD_BYTES = MAX_WEBSOCKET_MESSAGE_BYTES - MAX_HOST_ROUTE_HEADER_BYTES;
export interface HostRouteFrame {
routeId: string;
payload: Uint8Array;
}
export function encodeHostRouteFrame(routeId: string, payload: Uint8Array): Uint8Array {
const id = new TextEncoder().encode(routeId);
if (!id.length || id.length > MAX_HOST_ROUTE_ID_BYTES) throw new Error("Invalid host route ID");
if (payload.byteLength > MAX_ROUTED_PAYLOAD_BYTES) throw new Error("Host frame is too large");
const frame = new Uint8Array(3 + id.length + payload.byteLength);
frame[0] = HOST_ROUTE_OPCODE;
new DataView(frame.buffer).setUint16(1, id.length);
frame.set(id, 3);
frame.set(payload, 3 + id.length);
return frame;
}
export function decodeHostRouteFrame(bytes: Uint8Array): HostRouteFrame | null {
if (bytes[0] !== HOST_ROUTE_OPCODE || bytes.length < 3) return null;
const length = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength).getUint16(1);
if (!length || length > MAX_HOST_ROUTE_ID_BYTES || bytes.length < 3 + length) return null;
if (bytes.length - 3 - length > MAX_ROUTED_PAYLOAD_BYTES) return null;
try {
const routeId = new TextDecoder("utf-8", { fatal: true }).decode(bytes.subarray(3, 3 + length));
return { routeId, payload: bytes.subarray(3 + length) };
} catch {
return null;
}
}