export const controllerDevToolsCommandContentType = 'application/vnd.agl.devtools-commands.v1' as const; export const controllerDevToolsEventContentType = 'application/vnd.agl.devtools-events.v1' as const; export const controllerDevToolsCommandBytes = 1024 * 1024; export const controllerDevToolsEventBytes = 8 * 1024 * 1024; export const controllerDevToolsWriteBytes = 1024 * 1024; /** CDP messages are length-prefixed because they can exceed a logical stream write. */ export const encodeControllerDevToolsMessage = (message: string, maximumBytes: number): Uint8Array => { const body = new TextEncoder().encode(message); if (!body.length || body.length > maximumBytes) throw new Error('DevTools message exceeds the size limit.'); const packet = new Uint8Array(body.length + 4); new DataView(packet.buffer).setUint32(0, body.length); packet.set(body, 4); return packet; }; /** Allocates once per bounded message and accepts arbitrarily fragmented stream chunks. */ export class ControllerDevToolsMessageDecoder { private header = new Uint8Array(4); private headerBytes = 0; private body?: Uint8Array; private bodyBytes = 0; private decoder = new TextDecoder('utf-8', { fatal: true }); constructor(private maximumBytes: number) {} public *push(chunk: Uint8Array): Generator { let offset = 0; while (offset < chunk.length) { if (!this.body) { const count = Math.min(4 - this.headerBytes, chunk.length - offset); this.header.set(chunk.subarray(offset, offset + count), this.headerBytes); offset += count; this.headerBytes += count; if (this.headerBytes !== 4) continue; const length = new DataView(this.header.buffer).getUint32(0); if (!length || length > this.maximumBytes) throw new Error('Invalid DevTools message length.'); this.body = new Uint8Array(length); } const count = Math.min(this.body.length - this.bodyBytes, chunk.length - offset); this.body.set(chunk.subarray(offset, offset + count), this.bodyBytes); offset += count; this.bodyBytes += count; if (this.bodyBytes === this.body.length) { const message = this.decoder.decode(this.body); this.body = undefined; this.bodyBytes = 0; this.headerBytes = 0; yield message; } } } public finish(): void { if (this.headerBytes || this.body) throw new Error('Incomplete DevTools message.'); } }