posipaki 0.45.0 → 0.46.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"gateway-cli.js","names":["errorFrame","wireErrorFrame","errorText","Lines"],"sources":["../../src/remote/process-ref.ts","../../src/remote/channel.ts","../../src/remote/protocols/json1.ts","../../src/remote/stream.ts","../../src/remote/lines.ts","../../src/remote/stdio.ts","../../src/remote/transports/fifo.ts","../../src/remote/gateway.ts","../../src/remote/gateway-cli.ts"],"sourcesContent":["// ── Process references on the wire ─────────────────────────────────────────\n//\n// A process is not JSON: it holds state, children and methods. So a reflection\n// method that returns one cannot answer with the process itself — it answers\n// with a reference, and the caller is handed what it can read: a name, and an id\n// this connection uses for that process.\n//\n// The id belongs to the connection and to the side that holds the process: that\n// side allocates it, and both sides then know the process by it. Allocated once\n// per process — handed over twice, it is the same reference both times — and\n// never reused, so an id whose process is gone resolves to nothing rather than to\n// whatever came after it.\n//\n// The two sides allocate from one space, split by parity: the client takes the\n// odd ids, the server the even ones. Every connection also has a root, and a root is\n// numbered like anything else — the first id of the parity of the side that holds it:\n// 0 on the even side (the server), 1 on the odd one (the client). So an id says on\n// its own which side holds the process it names, the two roots included, and a frame's\n// address means the same thing whoever reads it.\n//\n// A side's own root is the process the connection is, and the far side's root is a\n// handle here like any of theirs. Neither end has to be told which number belongs to\n// whom: each root is the first id of its own parity.\n\nimport { isProcess } from \"../process.async.js\";\nimport type { RemoteProcess } from \"./remote-process.js\";\nimport { isPlainObject, isStreamLike } from \"./channel.js\";\n\n/** The key that marks a process reference inside an otherwise JSON value. */\nexport const PROCESS_REF = \"$p\";\n\n/**\n * The id a side gives its own root: the first id of its parity. The two ends of a\n * connection therefore number their roots differently, and an id says whose root it is\n * as it says who holds every other process. A side hands out its next id from two\n * steps further on, the one in between belonging to the root of the side it talks to.\n */\nexport function rootIdFor(parity: IdParity): number {\n return parity === \"odd\" ? 1 : 0;\n}\n\n/** What a served root is called when the client states no name for it. A client that\n * states one — and the library's own does, in `$init` — is served under that name instead:\n * the process across the seam is the one its proxy was forked as, and it should be called\n * the same on both sides. This is the name for a connection that says nothing. */\nexport const SERVED_ROOT_NAME = \"remote\";\n\n/** What crosses the wire in place of a process. */\nexport interface ProcessRef {\n id: number;\n pname: string;\n}\n\n/** The little a table needs of what it holds to name it: what it is called, and\n * the symbol that identifies it in this build. */\nexport interface ProcessHandle {\n readonly pname: string;\n readonly id: symbol;\n}\n\n/** Which ids a side hands out: the client takes the odd ones, the server the\n * even ones, so one number can never name a process on both sides at once. */\nexport type IdParity = \"odd\" | \"even\";\n/** The end of the low band: ids 0 and 1 are the two roots, 2 through 8 belong to a party that speaks\n * on a connection it otherwise only relays — the first stage's own streams — and nothing allocates\n * inside it, so a band id can never collide with one either end mints. */\nexport const LOW_BAND_END = 8;\n\n/**\n * The ids one side of a connection hands out: its own parity, from the far side of the low band.\n *\n * Everything numbered on the connection draws from one space — a process reference and a stream alike —\n * so a number names one thing, and the parity says which side made it. Each side builds its own and\n * hands the same one to whatever allocates.\n */\nexport class IdSpace {\n private pvtNext: number;\n /** True for a space inside the low band, which refuses to leave it. */\n private readonly pvtBand: boolean;\n\n constructor(\n readonly parity: IdParity,\n first: number = parity === \"odd\" ? LOW_BAND_END + 1 : LOW_BAND_END + 2,\n ) {\n this.pvtNext = first;\n this.pvtBand = first <= LOW_BAND_END;\n }\n\n /** This side's own end of the connection: the first id of its parity, never handed out. */\n root(): number {\n return rootIdFor(this.parity);\n }\n\n /** The next id of this side's parity, and never the same one twice. */\n next(): number {\n if (this.pvtBand && this.pvtNext > LOW_BAND_END) throw new Error(\"IdSpace: the low band is spent\");\n const id = this.pvtNext;\n this.pvtNext += 2;\n return id;\n }\n}\n\n/**\n * A space inside the low band, for a party that speaks on a connection it otherwise relays: its ids\n * come from a range no end allocates in, so announcing something of its own cannot take a number\n * either end might mint.\n */\nexport function lowBand(parity: IdParity): IdSpace {\n return new IdSpace(parity, parity === \"odd\" ? 3 : 2);\n}\n\n/**\n * The processes one connection knows, by the ids that name them. One table per\n * connection, because an id means nothing on any other one, and it lives exactly\n * as long as the connection that owns it.\n *\n * It holds two sets, told apart by parity rather than kept apart by a rule: the\n * processes this side holds — the root, and anything it hands over — and the ones\n * the far side holds, which this side knows as handles. A frame's address is\n * looked up in both, and exactly one can answer.\n */\nexport class ProcessTable<P extends ProcessHandle = ProcessHandle> {\n /** This side's own processes, by the ids it gave them. */\n private pvtMine = new Map<number, P>();\n private pvtMineIds = new Map<P, number>();\n /** The far side's processes, by the ids they came with. */\n private pvtTheirs = new Map<number, P>();\n /** The id of this side's own root: the first of its parity. */\n private pvtRootId: number;\n /** The id the far side gave its root: the first of its parity, and the number this\n * side's own numbering skips. */\n private pvtFarRootId: number;\n /** Told the first time a process is numbered — the moment it is about to\n * cross the connection. */\n private pvtOnCrossed: ((proc: P, id: number) => void) | undefined;\n /** Where the ids come from: one space per side, shared with whatever else numbers something. */\n private readonly ids: IdSpace;\n\n constructor(parity: IdParity, onCrossed?: (proc: P, id: number) => void, ids: IdSpace = new IdSpace(parity)) {\n this.ids = ids;\n this.pvtRootId = ids.root();\n this.pvtFarRootId = rootIdFor(parity === \"odd\" ? \"even\" : \"odd\");\n this.pvtOnCrossed = onCrossed;\n }\n\n /** The id of this side's own end of the connection. */\n rootId(): number {\n return this.pvtRootId;\n }\n\n /** The id the far side knows its own end by: the root this side reaches as a handle,\n * and the one it never hands out for anything of its own. */\n farRootId(): number {\n return this.pvtFarRootId;\n }\n\n /** Bind this side's own end of the connection — the root — to its id. */\n bindRoot(proc: P): void {\n const bound = this.pvtMine.get(this.pvtRootId);\n if (bound !== undefined && bound !== proc) {\n throw new Error(\"ProcessTable: the root is already bound\");\n }\n this.pvtMine.set(this.pvtRootId, proc);\n this.pvtMineIds.set(proc, this.pvtRootId);\n }\n\n /** The id this side gives a process it holds, allocating one the first time. */\n handleFor(proc: P): number {\n const known = this.pvtMineIds.get(proc);\n if (known !== undefined) return known;\n const id = this.ids.next();\n this.pvtMine.set(id, proc);\n this.pvtMineIds.set(proc, id);\n this.pvtOnCrossed?.(proc, id);\n return id;\n }\n\n /** A process this side holds, by the id it gave it. */\n processFor(id: number): P | undefined {\n return this.pvtMine.get(id);\n }\n\n /**\n * Register a process the far side holds — a handle — under the id it arrived\n * with. A root is one of these as much as anything else: both ends hold one at 0,\n * so the far side's root is a handle here, and the one this side has of itself\n * stays what it was.\n */\n bindFar(id: number, proc: P): void {\n this.pvtTheirs.set(id, proc);\n }\n\n /** A process the far side holds, by the id it gave it. */\n farHandleFor(id: number): P | undefined {\n return this.pvtTheirs.get(id);\n }\n\n /**\n * Whatever this connection knows `id` to mean: a process this side holds, or a\n * handle on one the far side holds. Only one of the two can answer, because\n * the two sides take their ids from different halves of the space — so what\n * comes back does not depend on which way the frame was going.\n */\n resolve(id: number): P | undefined {\n return this.pvtMine.get(id) ?? this.pvtTheirs.get(id);\n }\n\n /**\n * Let go of an id: the process behind it is not this connection's business any\n * more, so it is no longer known by it. Both sides' ids go the same way — the\n * side that lets a handle go names the far side's id, the side that is asked to\n * forget names its own — and an id let go is never handed out again, so nothing\n * that still names it can come to mean another process.\n *\n * Neither root is let go of: one is this side's own end of the connection, and the\n * other is what this side is talking to.\n */\n release(id: number): P | undefined {\n if (id === this.pvtRootId || id === this.pvtFarRootId) return undefined;\n const mine = this.pvtMine.get(id);\n if (mine !== undefined) {\n this.pvtMine.delete(id);\n this.pvtMineIds.delete(mine);\n return mine;\n }\n const theirs = this.pvtTheirs.get(id);\n if (theirs !== undefined) this.pvtTheirs.delete(id);\n return theirs;\n }\n\n /** Every handle this side holds on a process of the far side. */\n handles(): P[] {\n return [...this.pvtTheirs.values()];\n }\n}\n\n/** Whether `value` is the wire form of a reference. */\nexport function asProcessRef(value: unknown): ProcessRef | null {\n if (typeof value !== \"object\" || value === null) return null;\n const ref = (value as Record<string, unknown>)[PROCESS_REF];\n if (typeof ref !== \"object\" || ref === null) return null;\n const { id, pname } = ref as Record<string, unknown>;\n if (typeof id !== \"number\" || typeof pname !== \"string\") return null;\n return { id, pname };\n}\n\n/** Whether `value` has the shape of a handle on a far-side process. Judged by\n * what it holds rather than by `instanceof`, for the reason a process is: one\n * build can hold two copies of the class. */\nexport function isRemoteProcess(value: unknown): value is RemoteProcess {\n if (typeof value !== \"object\" || value === null) return false;\n const candidate = value as { pname?: unknown; id?: unknown; ref?: unknown; send?: unknown };\n return (\n typeof candidate.pname === \"string\" &&\n typeof candidate.id === \"symbol\" &&\n typeof candidate.send === \"function\" &&\n asProcessRef({ [PROCESS_REF]: candidate.ref }) !== null\n );\n}\n\n/**\n * Replace every process in `value` with the reference this connection uses for\n * it, so what is left is JSON that says which processes the answer is about.\n *\n * A handle goes back as the reference it came with, id and all: that id is the\n * far side's own, the one it will be read by.\n *\n * Containers are copied rather than rewritten: the objects belong to the actor\n * that returned them, and a state it is still running on is not ours to edit. A\n * node already seen is left where it is — a cycle is the encoder's to report, not\n * something to walk forever.\n */\nexport function encodeProcessRefs(\n value: unknown,\n table: ProcessTable,\n seen: Set<unknown> = new Set(),\n): unknown {\n // A stream is carried by reference too, and its behaviour lives on a symbol-keyed property a\n // copy would drop. It is the stream layer's value to offer, so it is left as it is here.\n if (isStreamLike(value)) return value;\n if (isRemoteProcess(value)) {\n return { [PROCESS_REF]: { id: value.ref.id, pname: value.ref.pname } };\n }\n if (isProcess(value)) {\n return { [PROCESS_REF]: { id: table.handleFor(value), pname: value.pname } };\n }\n if (Array.isArray(value)) {\n if (seen.has(value)) return value;\n seen.add(value);\n return value.map((item) => encodeProcessRefs(item, table, seen));\n }\n if (isPlainObject(value)) {\n if (seen.has(value)) return value;\n seen.add(value);\n const copy: Record<string, unknown> = {};\n for (const [key, item] of Object.entries(value)) {\n copy[key] = encodeProcessRefs(item, table, seen);\n }\n return copy;\n }\n return value;\n}\n\n/** How a side turns a reference into something it can hold: a handle. */\nexport type RefResolver = (ref: ProcessRef) => unknown;\n\n/** Replace every reference in `value` with what `resolve` makes of it. */\nexport function decodeProcessRefs(\n value: unknown,\n resolve: RefResolver,\n seen: Set<unknown> = new Set(),\n): unknown {\n // A stream is carried by reference too, and its behaviour lives on a symbol-keyed property a\n // copy would drop. It is the stream layer's value to offer, so it is left as it is here.\n if (isStreamLike(value)) return value;\n const ref = asProcessRef(value);\n if (ref) return resolve(ref);\n if (Array.isArray(value)) {\n if (seen.has(value)) return value;\n seen.add(value);\n return value.map((item) => decodeProcessRefs(item, resolve, seen));\n }\n if (isPlainObject(value)) {\n if (seen.has(value)) return value;\n seen.add(value);\n const copy: Record<string, unknown> = {};\n for (const [key, item] of Object.entries(value)) {\n copy[key] = decodeProcessRefs(item, resolve, seen);\n }\n return copy;\n }\n return value;\n}\n","// ── Frame channel ──────────────────────────────────────────────────────────\n//\n// The seam's shared vocabulary. A StringTransport moves encoded frames\n// (strings); a Channel moves decoded frame objects. The frame guards narrow a\n// decoded frame to one of the `$`-key shapes. server.ts / client.ts speak only\n// in Channels and these guards — they never see a specific protocol or\n// transport.\n\nimport type { FrameChannel, Message } from \"../types.js\";\nimport {\n decodeProcessRefs,\n encodeProcessRefs,\n type ProcessTable,\n type RefResolver,\n} from \"./process-ref.js\";\n\nexport interface StringTransport {\n send(frame: string): void | Promise<void>;\n /**\n * A line arrived. Answer with the number of raw octets that follow it, if any: a frame\n * may announce a run of bytes (a chunk of a stream), and the transport then hands those\n * octets over instead of reading them as more lines.\n */\n onMessage(handler: (frame: string) => number | void): void;\n /** The octets a line announced, whole, in the order they were sent. */\n onBytes(handler: (bytes: Uint8Array) => void): void;\n removeHandler(): void;\n /** Raw octets, written after whatever went before them. */\n sendBytes(bytes: Uint8Array): void | Promise<void>;\n /** Fires when the peer disconnects (transport closes from the other side). */\n onClose(handler: () => void): void;\n close(): Promise<void>;\n}\n\n/**\n * What the frame layer needs of a connection's values: two walks, and no knowledge of how the\n * bytes travel. The frame vocabulary lives in this file and the machinery in\n * `stream.ts`, so a store comes in as this shape rather than as an import from here.\n */\nexport interface ValueCodec {\n /** Replace every value that must cross by reference with one this connection serves. */\n encode(value: unknown): unknown;\n /** Replace every reference in a value with something the reader can hold. */\n decode(value: unknown): unknown;\n}\n\n/**\n * Several codecs over one connection, each value through all of them, in the order given.\n *\n * A connection carries more than one kind of thing by reference — a blob, a stream — and each\n * store knows only its own. Walking a value through every store in turn is what keeps them\n * from having to know about each other.\n */\nexport function combineCodecs(...codecs: ValueCodec[]): ValueCodec {\n return {\n encode: (value) => codecs.reduce((current, codec) => codec.encode(current), value),\n decode: (value) => codecs.reduce((current, codec) => codec.decode(current), value),\n };\n}\n\n/** The frames of one connection, as the remote layer speaks them: the process's own `FrameChannel`,\n * where a reader has the unsubscribe `onMessage` returned rather than a handler to take back. */\nexport type Channel = FrameChannel;\n\n/** Is this something JSON would carry as an object, rather than an instance with behaviour? */\nexport function isPlainObject(value: unknown): value is Record<string, unknown> {\n if (typeof value !== \"object\" || value === null) return false;\n const prototype = Object.getPrototypeOf(value) as object | null;\n return prototype === Object.prototype || prototype === null;\n}\n\n/**\n * Is this a stream — a value whose bytes come later, carried by reference?\n *\n * The question every walk that copies containers has to ask: copying a stream keeps the object and\n * loses the behaviour, because its iterator is a symbol-keyed property and `Object.entries` does not\n * see those. What such a value is belongs to `stream.ts`; that it must be left alone belongs to\n * every layer that walks a message.\n */\nexport function isStreamLike(value: unknown): value is AsyncIterable<Uint8Array> {\n if (typeof value !== \"object\" || value === null) return false;\n return typeof (value as Partial<AsyncIterable<Uint8Array>>)[Symbol.asyncIterator] === \"function\";\n}\n\n/**\n * One handler on the wire, however many readers on it. A transport holds one handler — and reports a\n * second one as a mistake — so the layer above keeps the readers and installs a single handler; the\n * subscribe this returns is what a reader calls to leave. The handler goes on with the first reader and\n * stays for the life of the connection: taking it off between readers would drop whatever arrives in\n * between, and a connection is not paused by nobody reading it.\n */\nexport function frameReaders(\n install: (deliver: (frame: Record<string, unknown>) => void) => void,\n): (handler: (frame: Record<string, unknown>) => void) => () => void {\n const readers = new Set<(frame: Record<string, unknown>) => void>();\n let installed = false;\n return (handler) => {\n if (!installed) {\n installed = true;\n install((frame) => {\n // Over a copy: a reader that leaves as it is handed a frame must not cut the rest short.\n for (const reader of [...readers]) reader(frame);\n });\n }\n readers.add(handler);\n return () => {\n readers.delete(handler);\n };\n };\n}\n\n/**\n * A channel that is `base`, with every incoming frame offered to `onFrame` first — and not handed\n * on when it is claimed.\n *\n * Every wrapper above a protocol wants this one thing, and none of them may lose the octets: a\n * connection that carries segments keeps carrying them through whatever wraps it, or a stream\n * dies one layer above the wire it was written for.\n */\nexport function channelThrough(base: Channel, onFrame: (frame: Record<string, unknown>) => boolean): Channel {\n const wrapped: Channel = {\n send: (frame) => base.send(frame),\n onMessage: (handler) =>\n base.onMessage((frame) => {\n if (onFrame(frame)) return;\n handler(frame);\n }),\n onClose: (handler) => base.onClose(handler),\n close: () => base.close(),\n };\n if (base.sendSegment) {\n wrapped.sendSegment = (frame, bytes) => base.sendSegment?.(frame, bytes);\n }\n if (base.onSegment) {\n wrapped.onSegment = (handler) => base.onSegment?.(handler) ?? (() => {});\n }\n return wrapped;\n}\n\n// ── the address on a frame ─────────────────────────────────────────────────\n//\n// A frame that is about a process carries that process's id as `to`, at the top level\n// of the frame rather than inside its body: the frame is the envelope, and the address\n// says who it is for whatever kind it turns out to be. Every frame that is about a\n// process names it, the root of the connection included, since both ends number their\n// own root and neither has to be guessed at.\n\n/** The id a frame addresses, or null when it names no process. */\nexport function frameTo(frame: Record<string, unknown>): number | null {\n const to = frame.to;\n return typeof to === \"number\" ? to : null;\n}\n\n/**\n * A frame on its way out: every process in it becomes the reference this\n * connection uses for that process, and the process the frame addresses is\n * written down as `to`.\n */\nexport function encodeFrame(\n frame: Record<string, unknown>,\n table: ProcessTable,\n to: number,\n codecs?: ValueCodec,\n): Record<string, unknown> {\n const withProcesses = encodeProcessRefs(frame, table) as Record<string, unknown>;\n const encoded = codecs === undefined ? withProcesses : (codecs.encode(withProcesses) as Record<string, unknown>);\n return { ...encoded, to };\n}\n\n/**\n * A frame just read: every reference in it becomes a handle on that process — or\n * the handle this side already made for it, since the same process handed over\n * twice is one process.\n */\nexport function decodeFrame(\n frame: Record<string, unknown>,\n resolve: RefResolver,\n codecs?: ValueCodec,\n): Record<string, unknown> {\n const resolved = decodeProcessRefs(frame, resolve) as Record<string, unknown>;\n return codecs === undefined ? resolved : (codecs.decode(resolved) as Record<string, unknown>);\n}\n\n// ── frame guards ──────────────────────────────────────────────────────────\n//\n// Each guard narrows a decoded frame to the frame it is, and each of those types is\n// named, so the whole set can be written down once (see `Frame`, at the foot of this\n// file). A guard asks only whether the key is there: the body under it belongs to\n// whoever wrote it.\n\nexport type ProtoFrame = {\n $proto: string;\n};\nexport type InitFrame = {\n $init: Record<string, unknown>;\n};\nexport type StateFrame = {\n $state: Record<string, unknown>;\n};\nexport type MsgFrame = {\n $msg: { fromName: string; body: Message };\n};\nexport type ExitFrame = {\n $exit: { code: number; state: unknown };\n};\n\nexport function isProto(msg: Record<string, unknown>): msg is ProtoFrame {\n return \"$proto\" in msg;\n}\nexport function isInit(msg: Record<string, unknown>): msg is InitFrame {\n return \"$init\" in msg;\n}\nexport function isState(msg: Record<string, unknown>): msg is StateFrame {\n return \"$state\" in msg;\n}\nexport function isMsg(msg: Record<string, unknown>): msg is MsgFrame {\n return \"$msg\" in msg;\n}\nexport function isExit(msg: Record<string, unknown>): msg is ExitFrame {\n return \"$exit\" in msg;\n}\n\n// ── a wire that could not be read ─────────────────────────────────────────\n//\n// Two frames are about the wire itself and not about a process: what a codec could\n// not read, and what a side says when the wire is over. Neither is addressed to\n// anything, and both are decided before a frame is looked up as news or as an ask —\n// a frame about the wire is about the ground the other frames stand on.\n//\n// {\"$bad\": {\"reason\": \"…\", \"raw\": \"…\"}} this side could not read that frame\n// {\"$error\": \"…\"} the wire cannot be spoken over, and why\n//\n// They are frames rather than raised errors on purpose. A frame is read inside the\n// transport's own callback — a socket's `message` event, a stream's line reader —\n// where a throw belongs to nobody: it arrives at the host as an uncaught exception,\n// and one unreadable frame from one peer takes the process down, every other\n// connection in it included. An unreadable frame is the connection's business, not\n// the process's, so it is carried as a frame the connection can answer: `$bad` is how\n// a reader says it inward, and `$error` is how a side says it outward before ending\n// that connection.\n//\n// `$error` is not a refused call — a call that is refused says so about itself, in\n// `$r.result.<name>` (see below). This one is about the wire the calls travel on.\n\nconst BAD_KEY = \"$bad\";\n\n/** How much of an unreadable line is carried: enough to see what it was, never enough to be it.\n * A line that failed to parse is the one line nobody vouched for, so quoting it whole would move\n * whatever it holds — a credential in a paste accident is how that happens — into every log,\n * transcript and context window that later reads the frame. Why, how long, and a short head of\n * it. (`reason` carries a little of the line on its own: a JSON parser says where it gave up and\n * quotes what it was looking at. That is the parser's business, not a promise this file makes.) */\nexport const BAD_PREFIX_LIMIT = 32;\n\nexport type BadFrame = {\n $bad: { reason: string };\n};\n\nexport function isBad(msg: Record<string, unknown>): msg is BadFrame {\n return BAD_KEY in msg;\n}\n\n/** The frame that says a frame could not be read: why, how long it was, and the head of it. */\nexport function badFrame(reason: string, raw: string): Record<string, unknown> {\n const prefix = raw.length > BAD_PREFIX_LIMIT ? `${raw.slice(0, BAD_PREFIX_LIMIT)}…` : raw;\n return { [BAD_KEY]: { reason, length: raw.length, prefix } };\n}\n\n/** Why a frame could not be read, or null when it is not a frame that says so. */\nexport function badReason(msg: Record<string, unknown>): string | null {\n const body = msg[BAD_KEY];\n if (typeof body !== \"object\" || body === null) return null;\n const reason = (body as { reason?: unknown }).reason;\n return typeof reason === \"string\" ? reason : null;\n}\n\nconst ERROR_KEY = \"$error\";\n\nexport type ErrorFrame = {\n $error: string;\n};\n\nexport function isError(msg: Record<string, unknown>): msg is ErrorFrame {\n return ERROR_KEY in msg;\n}\n\n/** The frame that says the wire is over: the reason, and the connection ends with it. */\nexport function errorFrame(reason: string): Record<string, unknown> {\n return { [ERROR_KEY]: reason };\n}\n\n/** The reason a wire error carries, or null when it is not one. */\nexport function errorReason(msg: Record<string, unknown>): string | null {\n const reason = msg[ERROR_KEY];\n return typeof reason === \"string\" ? reason : null;\n}\n\n// A process that crossed can be asked for less than everything, or for nothing at\n// all: what crosses about it is three categories, and only the ones asked for are\n// sent. Silence is the empty list, so a handle that asks for nothing hears\n// nothing — not its state, not its messages, and not that it is gone.\n//\n// {\"$tune\": {\"streams\": [\"state\"]}, \"to\": 3} this much about it, and no more\n\nexport type StreamKind = \"message\" | \"state\" | \"exit\";\n\n/** The three, in the one order they are ever named in — the order a tune frame\n * carries them in, so two ways of asking for the same thing look the same. */\nexport const STREAM_KINDS: StreamKind[] = [\"message\", \"state\", \"exit\"];\n\nexport function isStreamKind(value: unknown): value is StreamKind {\n return typeof value === \"string\" && (STREAM_KINDS as string[]).includes(value);\n}\n\n// ── control frames ─────────────────────────────────────────────────────────\n//\n// What the holder of a handle can ask of a process on the far side, beside\n// sending it a message. Each is a frame of its own rather than a message, so\n// nothing an actor reads is ever a control signal by accident:\n//\n// {\"$stop\": {}, \"to\": 3} stop it; it ends, and its `$exit` crosses back\n// {\"$pause\": {}, \"to\": 3} stop feeding it messages\n// {\"$resume\": {}, \"to\": 3} feed it again\n// {\"$release\": {}, \"to\": 3} let it go: forget this id, and stop telling me\n// about the process behind it\n// {\"$tune\": {\"streams\": [...]}, \"to\": 3}\n// say this much about it and no more: a subset of\n// message, state and exit, or the empty list for\n// silence\n//\n// They address the process they are about, so they are answered by whoever holds\n// that process — the side that can act on it. Stopping the *root* of a connection\n// is not one of these: that stays the STOP message it always was, since the root\n// is not a handle but the process this side is talking through.\n\nexport type StopFrame = {\n $stop: Record<string, unknown>;\n};\nexport type PauseFrame = {\n $pause: Record<string, unknown>;\n};\nexport type ResumeFrame = {\n $resume: Record<string, unknown>;\n};\nexport type ReleaseFrame = {\n $release: Record<string, unknown>;\n};\nexport type TuneFrame = {\n $tune: Record<string, unknown>;\n};\n\nexport function isStop(msg: Record<string, unknown>): msg is StopFrame {\n return \"$stop\" in msg;\n}\nexport function isPause(msg: Record<string, unknown>): msg is PauseFrame {\n return \"$pause\" in msg;\n}\nexport function isResume(msg: Record<string, unknown>): msg is ResumeFrame {\n return \"$resume\" in msg;\n}\nexport function isRelease(msg: Record<string, unknown>): msg is ReleaseFrame {\n return \"$release\" in msg;\n}\nexport function isTune(msg: Record<string, unknown>): msg is TuneFrame {\n return \"$tune\" in msg;\n}\n\n/**\n * The categories a tune frame asks for, in the order they are named in — or null\n * when the frame says something this vocabulary has no word for, which is a frame\n * to ignore rather than to guess at.\n */\nexport function tuneFrame(frame: { $tune: unknown }): StreamKind[] | null {\n const body = frame.$tune;\n if (typeof body !== \"object\" || body === null) return null;\n const streams = (body as { streams?: unknown }).streams;\n if (!Array.isArray(streams)) return null;\n if (!streams.every(isStreamKind)) return null;\n return STREAM_KINDS.filter((kind) => (streams as StreamKind[]).includes(kind));\n}\n\n// ── reflection frames ──────────────────────────────────────────────────────\n//\n// A reflection call crosses the seam as one frame and its answer as another, and\n// both go both ways: whoever holds a process is the one that answers for it.\n//\n// {\"$r.methods\": [\"inspect.getTree\", …]} what a process can answer, once, when\n// it crosses (and, for the root, once\n// when the connection opens)\n// {\"$r.call.<name>\": {seq, args}} asking, addressed to the process\n// {\"$r.result.<name>\": {seq, value}} answered\n// {\"$r.result.<name>\": {seq, error}} refused\n//\n// The method name is in the frame key, so a frame says what it is without a\n// table, and `seq` — one connection's, never reused — tells two calls to the\n// same method apart while both are in flight. An answer is about the call and not\n// about a process, so it carries no address: it names the seq it settles.\n\nexport const REFLECT_METHODS = \"$r.methods\";\nexport const REFLECT_CALL = \"$r.call.\";\nexport const REFLECT_RESULT = \"$r.result.\";\n\nexport interface ReflectionCall {\n name: string;\n seq: number;\n args: unknown[];\n}\n\nexport interface ReflectionResult {\n name: string;\n seq: number;\n value?: unknown;\n error?: string;\n}\n\nexport type ReflectionMethodsFrame = {\n \"$r.methods\": string[];\n};\n\n/** A call frame: the method in the key, the call in the body (`$r.call.<name>`). */\nexport type ReflectionCallFrame = {\n [key: `$r.call.${string}`]: { seq: number; args?: unknown[] };\n};\n\n/** An answer frame: `value` or `error`, naming the seq it settles. */\nexport type ReflectionResultFrame = {\n [key: `$r.result.${string}`]: { seq: number; value?: unknown; error?: string };\n};\n\nexport function isReflectionMethods(msg: Record<string, unknown>): msg is ReflectionMethodsFrame {\n const names = msg[REFLECT_METHODS];\n return Array.isArray(names) && names.every((name) => typeof name === \"string\");\n}\n\nfunction reflectionBody(\n frame: Record<string, unknown>,\n prefix: string,\n): { name: string; body: Record<string, unknown> } | null {\n for (const key of Object.keys(frame)) {\n if (!key.startsWith(prefix) || key.length === prefix.length) continue;\n const body = frame[key];\n if (typeof body !== \"object\" || body === null) return null;\n return { name: key.slice(prefix.length), body: body as Record<string, unknown> };\n }\n return null;\n}\n\n/** A call frame, or null — a malformed one is not worth an answer. */\nexport function asReflectionCall(frame: Record<string, unknown>): ReflectionCall | null {\n const parsed = reflectionBody(frame, REFLECT_CALL);\n if (!parsed || typeof parsed.body.seq !== \"number\") return null;\n const args = parsed.body.args;\n return {\n name: parsed.name,\n seq: parsed.body.seq,\n args: Array.isArray(args) ? args : [],\n };\n}\n\n/** An answer frame, or null. `error` present means the call was refused. */\nexport function asReflectionResult(frame: Record<string, unknown>): ReflectionResult | null {\n const parsed = reflectionBody(frame, REFLECT_RESULT);\n if (!parsed || typeof parsed.body.seq !== \"number\") return null;\n const { seq, value, error } = parsed.body;\n return typeof error === \"string\"\n ? { name: parsed.name, seq, error }\n : { name: parsed.name, seq, value };\n}\n\n/**\n * Why a value cannot cross a frame, or null when it can. Only JSON data\n * crosses: a function, a symbol or a bigint cannot be written down at all, and\n * a value with a cycle or a bigint inside it makes the encoder throw. What\n * JSON itself would quietly drop — a function stored inside an object — is the\n * caller's business, not something to invent a policy for here.\n */\nexport function jsonProblem(value: unknown): string | null {\n const kind = typeof value;\n if (kind === \"function\" || kind === \"symbol\" || kind === \"bigint\") return `a ${kind}`;\n if (kind !== \"object\" || value === null) return null;\n try {\n JSON.stringify(value);\n } catch (err) {\n return err instanceof Error ? err.message : String(err);\n }\n return null;\n}\n\n// ── the frames, as one type ────────────────────────────────────────────────\n//\n// The guards above say what a frame is one at a time; this is the same set as one type.\n// Neither direction nor protocol is in it — who may send which is the two ends' business,\n// and the handshake names the protocol that writes them. The address a frame carries\n// (`to`, `frameTo`) is the envelope the connection writes around it, not the frame.\n\nexport type Frame =\n | ProtoFrame\n | InitFrame\n | StateFrame\n | MsgFrame\n | ExitFrame\n | BadFrame\n | ErrorFrame\n | StopFrame\n | PauseFrame\n | ResumeFrame\n | ReleaseFrame\n | TuneFrame\n | ReflectionMethodsFrame\n | ReflectionCallFrame\n | ReflectionResultFrame;\n","// ── json1 wire protocol ────────────────────────────────────────────────────\n//\n// One JSON object per frame: `{\"$key\": value}`. encode/decode turn a decoded\n// frame object into a string and back. json1Channel wraps a StringTransport so\n// it moves frame objects instead of strings.\n//\n// This is the boundary where the wire's bytes become a frame, and it is the one\n// place a bad peer can throw into a callback that belongs to nobody but the host:\n// the handler runs where the transport called it — a socket's `message` event, a\n// line reader — so a `SyntaxError` here is an uncaught exception and takes the\n// process down. So a line that will not parse is not thrown at the caller: it\n// becomes the frame that says so (`$bad`, channel.ts) and travels inward like any\n// other, where the connection it came from can answer for it.\n//\n// One frame is one JSON *object*: a line that parses to a number, a string, an\n// array or `null` is not a frame either, and reading one as a frame (`\"$init\" in 7`)\n// throws just as surely as a line that never parsed.\n\nimport { badFrame, type Channel, type StringTransport } from \"../channel.js\";\n\nexport const VERSION = \"json.v1\";\n\n/** The frames this protocol carries. The shapes and the union are in channel.ts; a protocol\n * owns that the connection speaks them, and how they are written down. */\nexport type { Frame } from \"../channel.js\";\n\nexport function encode(frame: Record<string, unknown>): string {\n return JSON.stringify(frame);\n}\n\n/** The frame a line carries, throwing on a line that is not JSON. `readFrame` is how the\n * seam reads a line; this is the primitive underneath it. */\nexport function decode(str: string): Record<string, unknown> {\n return JSON.parse(str);\n}\n\n/** A line read as a frame: the frame itself, or the frame that says this one could not be\n * read. Never throws — see the note at the top of this file. */\nexport function readFrame(str: string): Record<string, unknown> {\n let parsed: unknown;\n try {\n parsed = decode(str);\n } catch (err) {\n return badFrame(err instanceof Error ? err.message : String(err), str);\n }\n if (typeof parsed !== \"object\" || parsed === null || Array.isArray(parsed)) {\n return badFrame(`a frame is one JSON object, and this was ${kindOf(parsed)}`, str);\n }\n return parsed as Record<string, unknown>;\n}\n\nfunction kindOf(value: unknown): string {\n if (value === null) return \"null\";\n if (Array.isArray(value)) return \"an array\";\n return `a ${typeof value}`;\n}\n\n/**\n * The octets a frame announces after it, or null when it announces none.\n *\n * One shape only: a chunk head carries the number of raw octets that follow, and that number\n * is what keeps the reader's framing. A head without one is not a segment — it goes on as a\n * frame, and whoever reads it refuses it by name.\n */\nexport function announcedOctets(frame: Record<string, unknown>): number | null {\n const head = frame.$chunk;\n if (typeof head !== \"object\" || head === null) return null;\n const bytes = (head as { bytes?: unknown }).bytes;\n return typeof bytes === \"number\" && Number.isInteger(bytes) && bytes >= 0 ? bytes : null;\n}\n\nexport function json1Channel(transport: StringTransport): Channel {\n const frameReaders = new Set<(frame: Record<string, unknown>) => void>();\n const segmentReaders = new Set<(frame: Record<string, unknown>, bytes: Uint8Array) => void>();\n /** The head whose octets are on their way: set between the line and the run it announced. */\n let expecting: Record<string, unknown> | null = null;\n\n const deliver = (frame: Record<string, unknown>): void => {\n // Over a copy: a reader that leaves as it is handed a frame must not cut the rest short.\n for (const reader of [...frameReaders]) reader(frame);\n };\n\n // Both handlers go on at once: the octets have to be read even when nobody is listening for\n // them, or the next line starts in the wrong place and the connection is lost.\n transport.onMessage((str) => {\n const frame = readFrame(str);\n const octets = announcedOctets(frame);\n if (octets === null) {\n deliver(frame);\n return;\n }\n expecting = frame;\n return octets;\n });\n transport.onBytes((bytes) => {\n const frame = expecting;\n expecting = null;\n // Octets nobody announced are a peer talking past the protocol: they are said out loud\n // rather than attached to whatever frame happened to arrive last.\n if (frame === null) {\n deliver(badFrame(`${bytes.length} octets arrived that no frame announced`, \"\"));\n return;\n }\n for (const reader of [...segmentReaders]) reader(frame, bytes);\n });\n\n return {\n send(frame) {\n return transport.send(encode(frame));\n },\n onMessage(handler) {\n frameReaders.add(handler);\n return () => {\n frameReaders.delete(handler);\n };\n },\n async sendSegment(frame, bytes) {\n // The line first, then its octets, each written before the next is asked for: a chunk\n // that was queued behind a megabyte of earlier chunks is a chunk the writer ran ahead of\n // its reader with.\n await transport.send(encode(frame));\n await transport.sendBytes(bytes);\n },\n onSegment(handler) {\n segmentReaders.add(handler);\n return () => {\n segmentReaders.delete(handler);\n };\n },\n onClose(handler) {\n transport.onClose(handler);\n },\n close() {\n return transport.close();\n },\n };\n}\n","// ── streams on the wire ────────────────────────────────────────────────────\n//\n// A stream is bytes arriving over time. A blob has to be whole before anybody can look at it,\n// so the reader waits for all of it, the writer has nothing to slow it down, and a file bigger\n// than memory cannot cross at all. A stream is what a file already is on a connection: asked\n// for at the rate the reader can take it.\n//\n// What the octets mean is not the announcement's business. The value that references them says\n// what they are and carries the facts about them: a stream has none, a typed array has its\n// length, a blob has its size, type and name.\n//\n// {\"$stream\": {\"id\": 7}} announced first: octets are coming\n// {\"$msg\": {\"fromName\": \"a\", \"body\": {\"feed\": {\"$s\": {\"id\": 7}}}}} a stream\n// {\"$msg\": {\"fromName\": \"a\", \"body\": {\"data\": {\"$bytes\": {\"id\": 7, \"size\": 4}}}}} a typed array\n// {\"$msg\": {\"fromName\": \"a\", \"body\": {\"shot\": {\"$blob\": {\"id\": 7, \"size\": 4, \"type\": \"image/png\", \"name\": \"a.png\"}}}}}\n// {\"$streamAsk\": {\"id\": 7, \"credit\": 262144}} the reader's demand, in bytes\n// {\"$chunk\": {\"id\": 7, \"seq\": 1, \"bytes\": 65536}} a chunk: its head…\n// <65536 raw octets> …its bytes…\n// {\"$chunkEnd\": {\"id\": 7, \"seq\": 1, \"crc32\": 2663770700}} …and the checksum, after them\n// {\"$streamDone\": {\"id\": 7}} or {\"$streamFail\": {…, \"reason\": …}}\n// {\"$streamCancel\": {\"id\": 7}} a reader that stops early\n//\n// The announcement goes out before the frame that references it, so a reader never receives a\n// reference to something it has not been told about. The head's `bytes` is what keeps the\n// framing: a reader that does not know the stream still skips exactly that many octets, and a\n// head whose length is a lie is the one thing that costs the connection rather than the stream.\n//\n// Credit is the flow control, counted in bytes: the reader grants a window and the writer sends\n// whole chunks until it is spent. Nothing is written ahead of demand, so a slow consumer slows\n// the writer instead of filling a buffer somewhere. The one eager case is a typed array: the\n// reference arriving is the demand, so the reader asks at once and puts the array back together\n// as the chunks land.\n\nimport { isPlainObject, isStreamLike, type Channel, type ValueCodec } from \"./channel.js\";\n\nexport { isStreamLike };\nimport { IdSpace, type IdParity } from \"./process-ref.js\";\n\n/** The chunk size, which bounds one segment. */\nexport const DEFAULT_CHUNK_BYTES = 64 * 1024;\n\n/** How far ahead of the consumer a writer may run: the credit window, in bytes. */\nexport const DEFAULT_WINDOW_BYTES = 4 * DEFAULT_CHUNK_BYTES;\n\n/** The largest stream this side will take: a reader that will not read a 5 GB file should say so\n * before the first chunk, not after the last. */\nexport const DEFAULT_MAX_BYTES = 64 * 1024 * 1024;\n\n/** What a blob knows about itself: the facts ride the reference, not the stream behind it. */\nexport interface BlobFacts {\n /** Bytes in total. A blob is whole by definition, so this is always known. */\n readonly size: number;\n /** The media type, when the sender knows it. */\n readonly type?: string;\n /** A name for a file, when one had it. */\n readonly name?: string;\n}\n\n/** What the far side made of an announcement: the stream itself, a blob over it, or an array. */\ntype ValueForm = \"stream\" | \"blob\" | \"bytes\";\n\n/** A stream of octets: what the library takes at one end of a connection and gives at the other.\n * It says nothing about what the octets are — that belongs to the value that references it. */\nexport type Stream = AsyncIterable<Uint8Array>;\n\n/** What a message carries in place of a stream: an id, or the name the far side announced it under. */\nexport interface StreamRef {\n $s: { id: number } | { name: string };\n}\n\nexport function isStreamRef(value: unknown): value is StreamRef {\n const body = (value as { $s?: { id?: unknown; name?: unknown } } | null)?.$s;\n return typeof body?.id === \"number\" || typeof body?.name === \"string\";\n}\n\n/** What a message carries in place of a typed array: its octets, and the length they add up to. */\nexport interface BytesRef {\n $bytes: { id: number; size: number };\n}\n\nexport function isBytesRef(value: unknown): value is BytesRef {\n const body = (value as { $bytes?: { id?: unknown; size?: unknown } } | null)?.$bytes;\n return typeof body?.id === \"number\" && typeof body?.size === \"number\";\n}\n\n/** What a message carries in place of a blob: its octets and the facts about them. */\nexport interface BlobRef {\n $blob: { id: number } & BlobFacts;\n}\n\nexport function isBlobRef(value: unknown): value is BlobRef {\n const body = (value as { $blob?: { id?: unknown; size?: unknown } } | null)?.$blob;\n return typeof body?.id === \"number\" && typeof body?.size === \"number\";\n}\n\n/** What may be offered in place of a whole file: sized, and read on demand. A platform `Blob` or\n * `File` is one as it stands, and so is a `RemoteBlob` that arrived from a connection — which is how\n * a file that was received can be passed on without being read here. */\nexport interface BlobSource {\n readonly size: number;\n readonly type?: string;\n readonly name?: string;\n /** A window of the bytes, when the value can give one without reading the rest. */\n readonly slice?: (start?: number, end?: number) => BlobSource;\n readonly arrayBuffer: () => Promise<ArrayBuffer>;\n /** The bytes over time, for a value that cannot be sliced. */\n readonly stream?: () => AsyncIterable<Uint8Array>;\n}\n\nexport function isBlob(value: unknown): value is BlobSource {\n if (typeof value !== \"object\" || value === null) return false;\n const candidate = value as { size?: unknown; arrayBuffer?: unknown; slice?: unknown; stream?: unknown };\n if (typeof candidate.size !== \"number\") return false;\n if (typeof candidate.arrayBuffer !== \"function\") return false;\n return typeof candidate.slice === \"function\" || typeof candidate.stream === \"function\";\n}\n\n/** What a message carries in place of a blob: the same value, read off the connection. */\nexport interface Blob {\n readonly size?: number;\n readonly type?: string;\n readonly name?: string;\n /** Read it once: the bytes are on the wire, not here. */\n stream(): Stream;\n arrayBuffer(): Promise<ArrayBuffer>;\n}\n\n/** Every octet of a stream, in one array. */\nexport async function bytesOf(stream: AsyncIterable<Uint8Array>): Promise<Uint8Array> {\n const parts: Uint8Array[] = [];\n let total = 0;\n for await (const part of stream) {\n parts.push(part);\n total += part.length;\n }\n const all = new Uint8Array(total);\n let at = 0;\n for (const part of parts) {\n all.set(part, at);\n at += part.length;\n }\n return all;\n}\n\n\n// ── the checksum ───────────────────────────────────────────────────────────\n//\n// CRC-32, because it is the one the runtime already has: `Bun.hash.crc32` costs 0.1 ms for a\n// 64 KiB chunk here and a table written in TypeScript costs 65 ms on a box without a JIT. The\n// numbers are in docs/proposals/streams.md; the polynomial is the same everywhere, so either\n// side verifies the other's.\n\ntype Crc = (bytes: Uint8Array) => number;\n\nlet pvtCrc: Crc | null = null;\n\nfunction crcOf(): Crc {\n if (pvtCrc !== null) return pvtCrc;\n const bun = (globalThis as { Bun?: { hash?: { crc32?: (data: Uint8Array) => number } } }).Bun;\n if (typeof bun?.hash?.crc32 === \"function\") {\n const native = bun.hash.crc32;\n pvtCrc = (bytes) => native(bytes) >>> 0;\n return pvtCrc;\n }\n // Node 22 has it on `zlib`, reachable without importing anything the browser cannot parse.\n const builtin = (globalThis as { process?: { getBuiltinModule?: (name: string) => unknown } }).process\n ?.getBuiltinModule?.(\"node:zlib\") as { crc32?: (data: Uint8Array) => number } | undefined;\n if (typeof builtin?.crc32 === \"function\") {\n const native = builtin.crc32;\n pvtCrc = (bytes) => native(bytes) >>> 0;\n return pvtCrc;\n }\n pvtCrc = tableCrc;\n return pvtCrc;\n}\n\n/** CRC-32 by hand, for a runtime that has none. Correct, and slow where nothing is a JIT. */\nfunction tableCrc(bytes: Uint8Array): number {\n let crc = 0xffff_ffff;\n for (const byte of bytes) {\n crc = (crc >>> 8) ^ pvtTable[(crc ^ byte) & 0xff]!;\n }\n return (crc ^ 0xffff_ffff) >>> 0;\n}\n\nconst pvtTable: number[] = (() => {\n const table: number[] = [];\n for (let i = 0; i < 256; i += 1) {\n let value = i;\n for (let bit = 0; bit < 8; bit += 1) value = value & 1 ? 0xed_b8_83_20 ^ (value >>> 1) : value >>> 1;\n table.push(value >>> 0);\n }\n return table;\n})();\n\n/** The checksum a chunk's tail carries. */\nexport function crc32(bytes: Uint8Array): number {\n return crcOf()(bytes);\n}\n\n// ── the reader's side ──────────────────────────────────────────────────────\n\n/** What a stream on this side costs and asks for, without knowing the connection. */\ninterface ReaderHooks {\n /** Octets taken by the consumer: credit spent, and the writer may be asked for more. */\n consumed(bytes: number): void;\n /** The consumer will take no more. */\n cancelled(reason: string): void;\n /** The consumer is waiting for octets: what the far side may now be asked for. */\n wanted(): void;\n}\n\n/**\n * Bytes the far side offers, read at the consumer's pace.\n *\n * An async iterable of octets, and nothing more: turning it into an array, a `Blob` or a digest\n * is the platform's job — `new Response(stream).arrayBuffer()` where there is a `Response`,\n * `for await` where there is not.\n */\nexport class RemoteStream implements Stream {\n private readonly queue: Uint8Array[] = [];\n private readonly waiting: Array<{ resolve: (r: IteratorResult<Uint8Array>) => void; reject: (e: Error) => void }> =\n [];\n private ended = false;\n private failure: Error | null = null;\n private stopped = false;\n private platform: ReadableStream<Uint8Array> | null = null;\n\n constructor(private readonly hooks: ReaderHooks) {}\n\n /** The far side sent more of it. */\n push(bytes: Uint8Array): void {\n if (this.ended || this.failure || this.stopped) return;\n const waiting = this.waiting.shift();\n if (!waiting) {\n this.queue.push(bytes);\n return;\n }\n this.hooks.consumed(bytes.length);\n waiting.resolve({ value: bytes, done: false });\n }\n\n /** The far side has sent all of it. */\n end(): void {\n if (this.ended || this.failure) return;\n this.ended = true;\n for (const waiting of this.waiting.splice(0)) waiting.resolve({ value: undefined, done: true });\n }\n\n /** The far side gave up on it, or it arrived corrupt. */\n fail(reason: string): void {\n if (this.ended || this.failure) return;\n this.failure = new Error(reason);\n for (const waiting of this.waiting.splice(0)) waiting.reject(this.failure);\n }\n\n /** Take no more of it. Said to the far side, so it stops reading its source. */\n cancel(reason = \"the reader stopped\"): void {\n if (this.stopped || this.ended) return;\n this.stopped = true;\n this.queue.length = 0;\n for (const waiting of this.waiting.splice(0)) waiting.resolve({ value: undefined, done: true });\n this.hooks.cancelled(reason);\n }\n\n async next(): Promise<IteratorResult<Uint8Array>> {\n const queued = this.queue.shift();\n if (queued) {\n this.hooks.consumed(queued.length);\n return { value: queued, done: false };\n }\n if (this.failure) throw this.failure;\n if (this.ended || this.stopped) return { value: undefined, done: true };\n // Nothing flows until somebody waits for it: a blob nobody opens is not read at all.\n this.hooks.wanted();\n return new Promise<IteratorResult<Uint8Array>>((resolve, reject) => {\n this.waiting.push({ resolve, reject });\n });\n }\n\n async return(): Promise<IteratorResult<Uint8Array>> {\n this.cancel();\n return { value: undefined, done: true };\n }\n\n /**\n * The runtime's own stream, built over this one the first time something asks for it. What a\n * sender usually hands over is a `ReadableStream`, so what arrives offers the same interface —\n * `getReader()`, `pipeTo()`, `tee()` — rather than a narrower shape of its own. A runtime\n * without `ReadableStream` keeps the iterable, which is the library's own interface.\n */\n asReadableStream(): ReadableStream<Uint8Array> {\n const ctor = globalThis.ReadableStream;\n if (typeof ctor !== \"function\") throw new Error(\"this runtime has no ReadableStream: read the stream with `for await`\");\n this.platform ??= new ctor({\n pull: async (controller) => {\n const next = await this.next();\n if (next.done) controller.close();\n else controller.enqueue(next.value);\n },\n cancel: (reason: unknown) => {\n this.cancel(typeof reason === \"string\" ? reason : \"the reader stopped\");\n },\n });\n return this.platform;\n }\n\n getReader(): ReadableStreamDefaultReader<Uint8Array> {\n return this.asReadableStream().getReader();\n }\n\n pipeTo(destination: WritableStream<Uint8Array>, options?: StreamPipeOptions): Promise<void> {\n return this.asReadableStream().pipeTo(destination, options);\n }\n\n tee(): [ReadableStream<Uint8Array>, ReadableStream<Uint8Array>] {\n return this.asReadableStream().tee();\n }\n\n /** One consumer, whichever door it comes through: where the runtime has a platform stream this\n * path goes through it, so the lock and the queue are the platform's and not two of ours. */\n async *[Symbol.asyncIterator](): AsyncIterator<Uint8Array> {\n if (typeof globalThis.ReadableStream !== \"function\") {\n for (;;) {\n const next = await this.next();\n if (next.done) return;\n yield next.value;\n }\n }\n const reader = this.asReadableStream().getReader();\n let finished = false;\n try {\n for (;;) {\n const next = await reader.read();\n if (next.done) {\n finished = true;\n return;\n }\n yield next.value;\n }\n } finally {\n reader.releaseLock();\n // A reader that walks away is a reader that takes no more: the far side is told to stop.\n if (!finished) this.cancel();\n }\n }\n}\n\n/**\n * A blob that came over a connection: the same value the far side offered, with its bytes still\n * over there. Reading it is what asks for them — and only at the pace the reader takes them, so a\n * file nobody opens costs nothing on the wire.\n */\nexport class RemoteBlob implements Blob {\n private readonly body: RemoteStream;\n\n constructor(\n body: RemoteStream,\n readonly facts: BlobFacts,\n ) {\n this.body = body;\n }\n\n get size(): number {\n return this.facts.size;\n }\n\n get type(): string | undefined {\n return this.facts.type;\n }\n\n get name(): string | undefined {\n return this.facts.name;\n }\n\n stream(): Stream {\n return this.body;\n }\n\n async arrayBuffer(): Promise<ArrayBuffer> {\n const all = await bytesOf(this.body);\n return all.buffer as ArrayBuffer;\n }\n}\n\n/**\n * Bytes that crossed a connection: the sender's array, taken apart into a stream and put back\n * together here as the chunks arrive. Not lazy — the sender was asked the moment the reference\n * arrived — so awaiting this is waiting for the last chunk, not for a read to start.\n */\nexport class RemoteBytes implements PromiseLike<Uint8Array> {\n /** The length the sender stated, which the octets must add up to. */\n readonly size: number;\n private readonly body: RemoteStream;\n private filling: Promise<Uint8Array> | null = null;\n\n constructor(body: RemoteStream, size: number) {\n this.body = body;\n this.size = size;\n }\n\n /** Start re-assembling. Called by the store once its record for this stream is in place. */\n start(): void {\n void this.bytes().catch(() => {});\n }\n\n /** The octets, once they are all here. */\n bytes(): Promise<Uint8Array> {\n this.filling ??= this.pvtFill();\n return this.filling;\n }\n\n /** The same octets as an array's buffer, for a caller that wants the platform's shape. */\n async arrayBuffer(): Promise<ArrayBuffer> {\n return (await this.bytes()).buffer as ArrayBuffer;\n }\n\n then<TResult1 = Uint8Array, TResult2 = never>(\n onfulfilled?: ((value: Uint8Array) => TResult1 | PromiseLike<TResult1>) | null,\n onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null,\n ): Promise<TResult1 | TResult2> {\n return this.bytes().then(onfulfilled, onrejected);\n }\n\n private async pvtFill(): Promise<Uint8Array> {\n const all = new Uint8Array(this.size);\n let at = 0;\n for await (const chunk of this.body) {\n if (at + chunk.length > all.length) throw new Error(`the array is longer than the ${this.size} bytes it stated`);\n all.set(chunk, at);\n at += chunk.length;\n }\n if (at !== all.length) throw new Error(`the array is short: ${at} of ${this.size} octets arrived`);\n return all;\n }\n}\n\n// ── the store ──────────────────────────────────────────────────────────────\n\n/** What this side is sending: the source, the credit it has been given, and what is left of a chunk. */\ninterface Offered {\n id: number;\n source: AsyncIterator<Uint8Array>;\n /** The rest of a piece the source gave us, not yet cut into chunks. */\n pending: Uint8Array | null;\n /** Octets the reader has asked for and not been sent. */\n credit: number;\n seq: number;\n pumping: boolean;\n dropped: boolean;\n}\n\n/** What this side is reading. */\ninterface Incoming {\n id: number;\n reader: RemoteStream;\n /** What the far side made of it: a stream until a reference says otherwise. */\n form: ValueForm;\n /** The value a reference asked for, built once: a stream, a blob over it, or bytes. */\n value?: RemoteStream | RemoteBlob | RemoteBytes;\n /** Octets asked for, and octets the consumer has taken: what may still be in flight. */\n asked: number;\n consumed: number;\n /** Octets that have arrived, for a value whose size this side was never told. */\n received: number;\n /** The chunk whose head and bytes have arrived, waiting for its tail. */\n chunk: { seq: number; bytes: Uint8Array } | null;\n done: boolean;\n}\n\nexport interface StreamStoreOptions {\n chunkBytes?: number;\n windowBytes?: number;\n maxBytes?: number;\n /** Where stream ids come from. One space per side, shared with the process table so a number\n * names one thing on the connection whatever it names. */\n ids?: IdSpace;\n /** Whether the store reads the connection itself. A party that carries a connection it does not\n * speak — a first stage — sets this false and hands frames in with `handle()`, so the far side's\n * frames are never mistaken for its own. */\n attach?: boolean;\n}\n\n/**\n * One connection's streams, as this side sees them.\n *\n * Both directions are in one table, because both are the same numbering: what this side offers\n * (and answers asks for) and what it may read from the far side. Ids follow the process table's\n * parity, so an id names one stream on one connection and nothing anywhere else.\n */\nexport class StreamStore implements ValueCodec {\n private readonly channel: Channel;\n private readonly chunkBytes: number;\n private readonly windowBytes: number;\n readonly maxBytes: number;\n private readonly pvtOffers = new Map<number, Offered>();\n private readonly pvtIncoming = new Map<number, Incoming>();\n private readonly ids: IdSpace;\n /** Why streams that are over failed, for a reference that arrives after the fact. */\n private readonly pvtRefused = new Map<number, { reason: string; form: ValueForm }>();\n /** What this side announced under a name, and what the far side did. A name is taken while it is\n * in either map, so the two directions never answer to one name at once. */\n private readonly pvtNamesOut = new Map<string, number>();\n private readonly pvtNamesIn = new Map<string, number>();\n /** Told about every named stream the far side announces: the live ones replay, then each arrival. */\n private readonly pvtNamedListeners = new Set<(name: string, stream: RemoteStream) => void>();\n private readonly pvtOff: () => void;\n private readonly pvtSegmentOff: (() => void) | null = null;\n private pvtClosed = false;\n\n constructor(channel: Channel, parity: IdParity, options: StreamStoreOptions = {}) {\n this.channel = channel;\n this.chunkBytes = options.chunkBytes ?? DEFAULT_CHUNK_BYTES;\n this.windowBytes = options.windowBytes ?? DEFAULT_WINDOW_BYTES;\n this.maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES;\n this.ids = options.ids ?? new IdSpace(parity);\n const attached = options.attach !== false;\n this.pvtOff = attached\n ? channel.onMessage((frame) => {\n this.onFrame(frame);\n })\n : () => {};\n this.pvtSegmentOff = attached ? (channel.onSegment?.((head, bytes) => this.onSegment(head, bytes)) ?? null) : null;\n }\n\n /** Whether this connection can carry a stream at all: it must carry octets beside its lines. */\n get canCarryStreams(): boolean {\n return this.pvtSegmentOff !== null && this.channel.sendSegment !== undefined;\n }\n\n /**\n * Offer a stream to the connection: the announcement goes out now, and the bytes when the far\n * side asks for them. What comes back is what a message carries in their place.\n *\n * A `name` makes the stream findable: the far side can reference it by that name instead of the\n * id, and ask for it with `named()` without waiting for a message to carry a reference.\n */\n offer(stream: Stream, name?: string): StreamRef {\n return { $s: { id: this.pvtAnnounce(stream[Symbol.asyncIterator](), name) } };\n }\n\n /**\n * Offer a blob — a whole file, read on demand. It crosses as a stream over its bytes and arrives\n * on the far side as a `RemoteBlob`, so nothing of it is read until somebody wants the bytes.\n */\n offerBlob(blob: BlobSource): BlobRef {\n const { size, type, name } = blob;\n const id = this.pvtAnnounce(this.pvtBlobChunks(blob));\n return { $blob: { id, size, ...(type === undefined ? {} : { type }), ...(name === undefined ? {} : { name }) } };\n }\n\n /**\n * Offer bytes this side already holds. The reference states the length, so the far side can\n * check it against its bound and size the array before the first chunk arrives — a typed array\n * is one piece, so the wire carries it as a stream of one.\n */\n offerBytes(bytes: Uint8Array): BytesRef {\n return { $bytes: { id: this.pvtAnnounce(this.pvtOnePiece(bytes)), size: bytes.length } };\n }\n\n private pvtAnnounce(source: AsyncIterator<Uint8Array>, name?: string): number {\n const id = this.ids.next();\n this.pvtOffers.set(id, { id, source, pending: null, credit: 0, seq: 0, pumping: false, dropped: false });\n if (name !== undefined) this.pvtNamesOut.set(name, id);\n void this.channel.send(name === undefined ? { $stream: { id } } : { $stream: { id, name } });\n return id;\n }\n\n private async *pvtOnePiece(bytes: Uint8Array): AsyncGenerator<Uint8Array> {\n if (bytes.length > 0) yield bytes;\n }\n\n /** A blob's octets, a window at a time: sliced where the value can, streamed where it cannot. */\n private async *pvtBlobChunks(blob: BlobSource): AsyncGenerator<Uint8Array> {\n const slice = blob.slice;\n if (slice) {\n for (let at = 0; at < blob.size; at += this.chunkBytes) {\n const end = Math.min(at + this.chunkBytes, blob.size);\n yield new Uint8Array(await slice.call(blob, at, end).arrayBuffer());\n }\n return;\n }\n const stream = blob.stream;\n if (!stream) throw new TypeError(\"a blob must offer a slice or a stream\");\n yield* stream.call(blob);\n }\n\n /** A value on its way out: every stream in it becomes an announcement and a reference. */\n encode(value: unknown): unknown {\n return this.pvtEncode(value, new Set());\n }\n\n /** A value just read: every reference in it becomes something this side can read. */\n decode(value: unknown): unknown {\n return this.pvtDecode(value, new Set());\n }\n\n /** Drop every stream of this connection, in both directions. Called when it ends. */\n close(): void {\n if (this.pvtClosed) return;\n this.pvtClosed = true;\n this.pvtOff();\n this.pvtSegmentOff?.();\n for (const offered of this.pvtOffers.values()) {\n offered.dropped = true;\n void offered.source.return?.();\n }\n this.pvtOffers.clear();\n for (const incoming of this.pvtIncoming.values()) incoming.reader.fail(\"the connection ended\");\n this.pvtIncoming.clear();\n }\n\n /** The ids this side is holding, in the order they were offered. */\n held(): number[] {\n return [...this.pvtOffers.keys()];\n }\n\n /**\n * Take a frame if it is one this store answers for, and say whether it did. A party that carries a\n * connection it does not speak — a first stage, relaying a client to a payload — has to know which\n * inbound frames are its own and which belong to the far side, and this is the question it asks.\n * Only frames about a stream this side offered are claimed, so a stream the far side offers passes\n * through untouched.\n */\n handle(frame: Record<string, unknown>): boolean {\n if (this.pvtClosed) return false;\n const id = frameId(frame);\n if (id === null || !this.pvtOffers.has(id)) return false;\n this.onFrame(frame);\n return true;\n }\n\n /**\n * The stream the far side announced under `name`, if it is still live — the way a caller finds a\n * stream nobody sent it a reference to. A name that was never announced answers `undefined`, and a\n * name whose stream is over does too: the sentence lives on the value the reference would give.\n */\n named(name: string): RemoteStream | undefined {\n const id = this.pvtNamesIn.get(name);\n if (id === undefined) return undefined;\n return this.pvtValueFor(id, \"stream\") as RemoteStream;\n }\n\n /**\n * Every named stream the far side announces, now and later. The listener is called for the names\n * already live when it is installed and for each new one as it arrives, so a caller that wires a\n * sink to `stdout` does not have to know whether the far side has printed yet.\n */\n onNamed(listener: (name: string, stream: RemoteStream) => void): () => void {\n this.pvtNamedListeners.add(listener);\n for (const [name, id] of this.pvtNamesIn) {\n if (this.pvtIncoming.has(id)) listener(name, this.pvtValueFor(id, \"stream\") as RemoteStream);\n }\n return () => {\n this.pvtNamedListeners.delete(listener);\n };\n }\n\n // ── writing ────────────────────────────────────────────────────────────\n\n private pvtSend(frame: Record<string, unknown>): Promise<void> {\n return Promise.resolve(this.channel.send(frame));\n }\n\n private pvtEncode(value: unknown, seen: Set<unknown>): unknown {\n if (typeof value !== \"object\" || value === null) return value;\n // Offering reads the source's own facts (`size`, `type`, `name`), so it is asked before the\n // walk decides the value is a plain object to copy.\n // A blob is offered before a stream is looked for: it is a value with bytes behind it, not the\n // iterator itself, and the far side is given a blob back.\n if (isBlob(value)) return this.offerBlob(value);\n if (isStreamLike(value)) return this.offer(value);\n if (seen.has(value)) return value;\n seen.add(value);\n if (Array.isArray(value)) return value.map((item) => this.pvtEncode(item, seen));\n if (ArrayBuffer.isView(value) || value instanceof ArrayBuffer) return this.offerBytes(asOctets(value));\n // Only a plain object is walked into: a handle, a logger, anything with its own prototype is\n // the application's and is left as it is. Copying one would take its methods away.\n if (!isPlainObject(value)) return value;\n const copy: Record<string, unknown> = {};\n for (const [key, item] of Object.entries(value)) copy[key] = this.pvtEncode(item, seen);\n return copy;\n }\n\n private pvtTake(offered: Offered): Uint8Array | null {\n if (offered.pending === null) return null;\n const size = Math.min(offered.pending.length, this.chunkBytes, offered.credit);\n const piece = offered.pending.subarray(0, size);\n offered.pending = size === offered.pending.length ? null : offered.pending.subarray(size);\n return piece;\n }\n\n private async pvtPull(offered: Offered): Promise<boolean> {\n const next = await offered.source.next();\n if (next.done) return false;\n const value: unknown = next.value;\n const bytes =\n value instanceof Uint8Array\n ? value\n : ArrayBuffer.isView(value)\n ? new Uint8Array(value.buffer, value.byteOffset, value.byteLength)\n : value instanceof ArrayBuffer\n ? new Uint8Array(value)\n : null;\n if (bytes === null) throw new TypeError(\"a stream may only yield octets\");\n if (bytes.length === 0) return true;\n offered.pending = bytes;\n return true;\n }\n\n private async pvtPump(offered: Offered): Promise<void> {\n if (offered.pumping || offered.dropped || this.pvtClosed) return;\n offered.pumping = true;\n try {\n while (!offered.dropped && offered.credit > 0) {\n if (offered.pending === null && !(await this.pvtPull(offered))) {\n await this.channel.send({ $streamDone: { id: offered.id } });\n this.pvtDrop(offered);\n return;\n }\n const piece = this.pvtTake(offered);\n if (piece === null) continue;\n const seq = offered.seq;\n offered.seq += 1;\n offered.credit -= piece.length;\n await this.channel.sendSegment?.({ $chunk: { id: offered.id, seq, bytes: piece.length } }, piece);\n await this.channel.send({ $chunkEnd: { id: offered.id, seq, crc32: crc32(piece) } });\n }\n } catch (error) {\n await this.pvtSend({ $streamFail: { id: offered.id, reason: reasonOf(error) } }).catch(() => {});\n this.pvtDrop(offered);\n } finally {\n offered.pumping = false;\n }\n }\n\n private pvtDrop(offered: Offered): void {\n if (offered.dropped) return;\n offered.dropped = true;\n this.pvtOffers.delete(offered.id);\n this.pvtRelease(offered.id);\n }\n\n /**\n * Take a stream out of the live table and remember why it ended, for a reference that arrives\n * after the fact: \"no stream was announced\" is the wrong sentence for a stream that was refused.\n */\n private pvtRetire(id: number, reason: string, form: ValueForm = \"stream\"): void {\n this.pvtIncoming.delete(id);\n this.pvtRelease(id);\n this.pvtRefused.set(id, { reason, form });\n // A connection lives a long time and a refusal is rare; past a bound the oldest reason goes.\n if (this.pvtRefused.size > 64) {\n const oldest = this.pvtRefused.keys().next();\n if (!oldest.done) this.pvtRefused.delete(oldest.value);\n }\n }\n\n /** A stream that is over gives its name back, so the next announcement of it is not a duplicate. */\n private pvtRelease(id: number): void {\n for (const [name, bound] of this.pvtNamesIn) if (bound === id) this.pvtNamesIn.delete(name);\n for (const [name, bound] of this.pvtNamesOut) if (bound === id) this.pvtNamesOut.delete(name);\n }\n\n // ── reading ────────────────────────────────────────────────────────────\n\n private pvtDecode(value: unknown, seen: Set<unknown>): unknown {\n if (typeof value !== \"object\" || value === null) return value;\n if (isBytesRef(value)) return this.pvtValueFor(value.$bytes.id, \"bytes\", { size: value.$bytes.size });\n if (isBlobRef(value)) {\n const { id, size, type, name } = value.$blob;\n return this.pvtValueFor(id, \"blob\", { size, type, name });\n }\n if (isStreamRef(value)) {\n const ref = value.$s;\n return \"id\" in ref ? this.pvtValueFor(ref.id, \"stream\") : this.pvtValueForNamed(ref.name);\n }\n if (seen.has(value)) return value;\n seen.add(value);\n if (Array.isArray(value)) return value.map((item) => this.pvtDecode(item, seen));\n if (ArrayBuffer.isView(value) || value instanceof ArrayBuffer) return value;\n // Whatever a store earlier in the chain already turned into a handle is not a plain object any\n // more, and copying it here would strip what makes it one.\n if (!isPlainObject(value)) return value;\n const copy: Record<string, unknown> = {};\n for (const [key, item] of Object.entries(value)) copy[key] = this.pvtDecode(item, seen);\n return copy;\n }\n\n private pvtValueFor(id: number, form: ValueForm, facts?: BlobFacts): RemoteStream | RemoteBlob | RemoteBytes {\n const incoming = this.pvtIncoming.get(id);\n if (!incoming) {\n // A reference to a stream that is over, or one this side was never told about. The value says\n // so when it is read rather than throwing in the middle of a decoded frame: it was the message's\n // fault, not the connection's.\n const ended = this.pvtRefused.get(id);\n const failed = new RemoteStream({ consumed() {}, cancelled() {}, wanted() {} });\n failed.fail(ended?.reason ?? `no stream was announced with id ${id}`);\n return this.pvtBuild(failed, ended?.form ?? form, facts);\n }\n if (incoming.value) return incoming.value;\n incoming.form = form;\n const value = (incoming.value = this.pvtBuild(incoming.reader, form, facts));\n // The size is on the reference now, so a value this side will not read is refused before a\n // chunk is asked for. A plain stream has no size to check: its bound is counted as it arrives.\n if (facts !== undefined && facts.size > this.maxBytes) {\n const reason = `stream ${id} is ${facts.size} bytes, over this side's bound of ${this.maxBytes}`;\n incoming.done = true;\n incoming.reader.fail(reason);\n this.pvtRetire(id, reason, form);\n void this.channel.send({ $streamFail: { id, reason: \"over the reader's bound\" } });\n }\n if (value instanceof RemoteBytes) value.start();\n return value;\n }\n\n /** The value a name the far side announced stands for — or one that says it was never announced. */\n private pvtValueForNamed(name: string): RemoteStream {\n const id = this.pvtNamesIn.get(name);\n if (id !== undefined && this.pvtIncoming.has(id)) return this.pvtValueFor(id, \"stream\") as RemoteStream;\n const failed = new RemoteStream({ consumed() {}, cancelled() {}, wanted() {} });\n failed.fail(`no stream was announced with the name ${name}`);\n return failed;\n }\n\n private pvtBuild(reader: RemoteStream, form: ValueForm, facts?: BlobFacts): RemoteStream | RemoteBlob | RemoteBytes {\n if (form === \"blob\" && facts !== undefined) return new RemoteBlob(reader, facts);\n if (form === \"bytes\" && facts !== undefined) return new RemoteBytes(reader, facts.size);\n return reader;\n }\n\n private pvtAsk(incoming: Incoming): void {\n if (incoming.done || this.pvtClosed) return;\n const outstanding = incoming.asked - incoming.consumed;\n if (outstanding >= this.windowBytes / 2) return;\n const credit = this.windowBytes - outstanding;\n incoming.asked += credit;\n void this.channel.send({ $streamAsk: { id: incoming.id, credit } });\n }\n\n private pvtAnnounced(id: number, name?: string): void {\n const existing = this.pvtIncoming.get(id);\n existing?.reader.fail(`a stream was announced twice with id ${id}`);\n if (name !== undefined) {\n const taken = this.pvtNamesIn.get(name);\n // A name already live is refused: a reference to it would otherwise resolve to whichever of the\n // two arrived last, and neither side would be able to say which.\n if (taken !== undefined) {\n const reason = `a stream named ${name} is already live (id ${taken})`;\n this.pvtRetire(id, reason, \"stream\");\n void this.channel.send({ $streamFail: { id, reason } });\n return;\n }\n this.pvtNamesIn.set(name, id);\n }\n // The reader is built before the record it lives in: its callbacks close over that record and only run\n // once a chunk or a cancel arrives, which is after the assignment below.\n let incoming: Incoming;\n const reader = new RemoteStream({\n consumed: (bytes) => {\n incoming.consumed += bytes;\n this.pvtAsk(incoming);\n },\n wanted: () => {\n this.pvtAsk(incoming);\n },\n cancelled: (reason) => {\n incoming.done = true;\n this.pvtIncoming.delete(id);\n this.pvtRelease(id);\n void this.channel.send({ $streamCancel: { id, reason } });\n },\n });\n incoming = { id, reader, form: \"stream\", asked: 0, consumed: 0, received: 0, chunk: null, done: false };\n this.pvtIncoming.set(id, incoming);\n if (name !== undefined) {\n const stream = this.pvtValueFor(id, \"stream\") as RemoteStream;\n for (const listener of this.pvtNamedListeners) listener(name, stream);\n }\n }\n\n private onSegment(head: Record<string, unknown>, bytes: Uint8Array): void {\n const chunk = head.$chunk as { id?: unknown; seq?: unknown; bytes?: unknown } | undefined;\n if (typeof chunk?.id !== \"number\" || typeof chunk.seq !== \"number\") return;\n const incoming = this.pvtIncoming.get(chunk.id);\n if (!incoming || incoming.done) {\n // A stream this side has dropped or never heard of: the octets are skipped, and that is what\n // the head's own length is for.\n return;\n }\n incoming.received += bytes.length;\n if (incoming.received > this.maxBytes) {\n const reason = `stream ${incoming.id} passed this side's bound of ${this.maxBytes} bytes`;\n incoming.done = true;\n incoming.reader.fail(reason);\n this.pvtRetire(incoming.id, reason, incoming.form);\n void this.channel.send({ $streamFail: { id: incoming.id, reason: \"over the reader's bound\" } });\n return;\n }\n incoming.chunk = { seq: chunk.seq, bytes };\n }\n\n private onFrame(frame: Record<string, unknown>): void {\n if (this.pvtClosed) return;\n if (\"$stream\" in frame) {\n const body = frame.$stream as { id?: unknown; name?: unknown } | undefined;\n if (typeof body?.id !== \"number\") return;\n this.pvtAnnounced(body.id, typeof body.name === \"string\" ? body.name : undefined);\n return;\n }\n if (\"$streamAsk\" in frame) {\n const body = frame.$streamAsk as { id?: unknown; credit?: unknown } | undefined;\n const offered = typeof body?.id === \"number\" ? this.pvtOffers.get(body.id) : undefined;\n if (!offered || typeof body?.credit !== \"number\" || body.credit <= 0) return;\n offered.credit += body.credit;\n void this.pvtPump(offered);\n return;\n }\n if (\"$chunkEnd\" in frame) {\n const body = frame.$chunkEnd as { id?: unknown; seq?: unknown; crc32?: unknown } | undefined;\n const incoming = typeof body?.id === \"number\" ? this.pvtIncoming.get(body.id) : undefined;\n if (!incoming) return;\n const chunk = incoming.chunk;\n incoming.chunk = null;\n if (chunk === null || chunk.seq !== body?.seq) {\n incoming.done = true;\n incoming.reader.fail(`stream ${incoming.id} lost its framing: a chunk ended that never began`);\n this.pvtRetire(incoming.id, `stream ${incoming.id} lost its framing: a chunk ended that never began`, incoming.form);\n void this.channel.send({ $streamFail: { id: incoming.id, reason: \"lost the framing\" } });\n return;\n }\n if (typeof body?.crc32 === \"number\" && crc32(chunk.bytes) !== body.crc32) {\n incoming.done = true;\n incoming.reader.fail(`stream ${incoming.id} arrived corrupt: chunk ${chunk.seq} failed its checksum`);\n this.pvtRetire(incoming.id, `stream ${incoming.id} arrived corrupt: chunk ${chunk.seq} failed its checksum`, incoming.form);\n void this.channel.send({ $streamFail: { id: incoming.id, reason: \"a chunk failed its checksum\" } });\n return;\n }\n incoming.reader.push(chunk.bytes);\n return;\n }\n if (\"$streamDone\" in frame) {\n const body = frame.$streamDone as { id?: unknown } | undefined;\n const incoming = typeof body?.id === \"number\" ? this.pvtIncoming.get(body.id) : undefined;\n if (!incoming) return;\n incoming.done = true;\n this.pvtIncoming.delete(incoming.id);\n this.pvtRelease(incoming.id);\n incoming.reader.end();\n return;\n }\n if (\"$streamFail\" in frame) {\n const body = frame.$streamFail as { id?: unknown; reason?: unknown } | undefined;\n const incoming = typeof body?.id === \"number\" ? this.pvtIncoming.get(body.id) : undefined;\n if (!incoming) return;\n const reason = typeof body?.reason === \"string\" ? body.reason : `stream ${incoming.id} failed`;\n incoming.done = true;\n incoming.reader.fail(reason);\n this.pvtRetire(incoming.id, reason, incoming.form);\n return;\n }\n if (\"$streamCancel\" in frame) {\n const body = frame.$streamCancel as { id?: unknown } | undefined;\n const offered = typeof body?.id === \"number\" ? this.pvtOffers.get(body.id) : undefined;\n if (!offered) return;\n this.pvtDrop(offered);\n void offered.source.return?.();\n }\n }\n}\n\n/** A typed array or an `ArrayBuffer` as the octets the wire carries. */\nfunction asOctets(value: ArrayBuffer | ArrayBufferView): Uint8Array {\n if (ArrayBuffer.isView(value)) return new Uint8Array(value.buffer, value.byteOffset, value.byteLength);\n return new Uint8Array(value);\n}\n\nfunction reasonOf(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\n/** The stream id a control frame names, or null when it names none of them. */\nfunction frameId(frame: Record<string, unknown>): number | null {\n for (const key of [\"$streamAsk\", \"$streamCancel\", \"$streamDone\", \"$streamFail\"]) {\n const body = frame[key] as { id?: unknown } | undefined;\n if (typeof body?.id === \"number\") return body.id;\n }\n return null;\n}\n","// ── bytes on a stream, and the lines they carry ─────────────────────────────\n//\n// A line transport's reader, and the number that made it a file of its own: 13.3 MB of\n// 87 KB frames read through `node:readline` costs 4.0 s on this box, and through a buffer\n// and an `indexOf` it costs 76 ms. The difference is not the parsing — it is that a\n// frame the size of a file chunk is the normal case here and readline is built for the\n// other one.\n//\n// Splitting on the byte 0x0a is safe for UTF-8: a continuation byte is never 0x0a, so a\n// line boundary cannot fall inside a character, and a chunk boundary inside one is\n// carried by the accumulator until the rest of it arrives.\n//\n// CRLF is read as a line ending rather than as part of the frame, which is what the line\n// reader it replaces did; the frames this library writes end in \"\\n\" alone.\n//\n// ── a line may carry octets after it ───────────────────────────────────────\n//\n// Not every frame on the wire is text: a chunk of a stream is a JSON head, the raw\n// octets it announces, and a JSON tail. So a line is also a question — how many octets\n// follow — and the answer says where the next line starts. `PartReader` is that state\n// machine, over bytes as they arrive however the carrier splits them; a carrier that\n// moves whole messages (a websocket) feeds it one message at a time and the machine\n// cannot tell the difference.\n\nimport type { Readable } from \"node:stream\";\n\n/** A reader, and the one way to stop it. */\nexport interface LineReader {\n /** Stop reading and drop what is buffered. Idempotent. */\n stop(): void;\n}\n\nconst NL = 0x0a;\nconst CR = 0x0d;\n\nfunction withoutCr(line: Buffer<ArrayBufferLike>): Buffer<ArrayBufferLike> {\n return line.length > 0 && line[line.length - 1] === CR ? line.subarray(0, line.length - 1) : line;\n}\n\n/**\n * The wire as a sequence of lines, where a line may announce raw octets to follow it.\n *\n * `onLine` gets a line and answers how many octets come next — none, for every frame but\n * one that carries them. Those octets reach `onBytes` whole, however many reads they\n * arrived in, and the reader goes back to looking for a newline.\n */\nexport class PartReader {\n private acc: Buffer<ArrayBufferLike> = Buffer.alloc(0);\n /** How many octets the octet run still needs, or 0 while looking for a line. */\n private want = 0;\n private done = false;\n\n constructor(\n private readonly onLine: (line: string) => number | void,\n private readonly onBytes: (bytes: Uint8Array) => void,\n ) {}\n\n feed(chunk: Uint8Array): void {\n if (this.done) return;\n this.acc = this.acc.length === 0 ? Buffer.from(chunk.buffer, chunk.byteOffset, chunk.byteLength) : Buffer.concat([this.acc, chunk]);\n this.pump();\n }\n\n /** The stream is over: whatever is left of a line is still a line, as `readline` said. */\n end(): void {\n if (this.done) return;\n const rest = this.acc;\n this.acc = Buffer.alloc(0);\n this.done = true;\n if (rest.length > 0 && this.want === 0) this.onLine(withoutCr(rest).toString(\"utf8\"));\n }\n\n private pump(): void {\n for (;;) {\n if (this.want > 0) {\n if (this.acc.length < this.want) return;\n const bytes = this.acc.subarray(0, this.want);\n this.acc = this.acc.subarray(this.want);\n this.want = 0;\n this.onBytes(bytes);\n continue;\n }\n const at = this.acc.indexOf(NL);\n if (at < 0) return;\n const line = this.acc.subarray(0, at);\n this.acc = this.acc.subarray(at + 1);\n const asked = this.onLine(withoutCr(line).toString(\"utf8\"));\n if (typeof asked === \"number\") {\n // A run of no octets is still a run: the line said what follows, and it follows as nothing.\n if (asked > 0) this.want = asked;\n else this.onBytes(new Uint8Array(0));\n }\n }\n }\n}\n\n/**\n * Read `stream` as lines, with the octets a line announces.\n *\n * `onEnd` is called once when the stream is over, after the last line: a stream that\n * ends without its final newline still gives up its last line, because that is what the\n * peer meant to say.\n */\nexport function readParts(\n stream: Readable,\n onLine: (line: string) => number | void,\n onBytes: (bytes: Uint8Array) => void,\n onEnd?: () => void,\n): LineReader {\n const reader = new PartReader(onLine, onBytes);\n return readChunks(\n stream,\n (chunk) => reader.feed(chunk),\n () => {\n reader.end();\n onEnd?.();\n },\n );\n}\n\n/** Read `stream` a line at a time, with no octets: the plain line carrier. */\nexport function readLines(stream: Readable, onLine: (line: string) => void, onEnd?: () => void): LineReader {\n return readParts(\n stream,\n (line) => {\n onLine(line);\n },\n () => {\n // A carrier that never announces octets never delivers any; a peer that sends them\n // anyway is talking past the protocol, and the bytes are dropped rather than guessed at.\n },\n onEnd,\n );\n}\n\n/** The bytes a stream carries, before anything is made of them. */\nexport function readChunks(stream: Readable, onChunk: (chunk: Uint8Array) => void, onEnd?: () => void): LineReader {\n let stopped = false;\n\n const onData = (chunk: Buffer | string): void => {\n if (stopped) return;\n onChunk(typeof chunk === \"string\" ? Buffer.from(chunk, \"utf8\") : chunk);\n };\n\n const finish = (): void => {\n if (stopped) return;\n stopped = true;\n stream.off(\"data\", onData);\n onEnd?.();\n };\n\n stream.on(\"data\", onData);\n stream.once(\"end\", finish);\n\n return {\n stop(): void {\n stopped = true;\n stream.off(\"data\", onData);\n stream.off(\"end\", finish);\n },\n };\n}\n","// ── stdio wire ─────────────────────────────────────────────────────────────\n//\n// A newline-delimited JSON channel over a pair of streams: the one wire every\n// way into a foreign execution context can carry. Two callers rely on it, and\n// they are two halves of the same thing:\n//\n// * the client of a spawn we make ourselves, on fds handed to the child (see\n// `fdStreams`) — private fds, so the child's own stdout stays free;\n// * a first-stage command on its own stdin/stdout, over ssh, under `sudo`, in\n// a container — where stdio is the only channel there is.\n//\n// Frames are one JSON object per line. Whatever the far end prints is carried as an *output\n// frame* (`$fd`), so it can never be mistaken for a frame of the protocol itself; a failed start\n// is carried as an `$error` frame.\n//\n// Output frames are routed above the protocol step, by whoever holds the connection (output.ts):\n// every line decodes to a frame, and the ones that are the far end's own print go to that\n// holder's sink instead of to the seam. The handshake below reads the first frame that is the\n// protocol's, since the far end's own print may come first.\n\nimport { createReadStream, createWriteStream } from \"node:fs\";\nimport { readParts } from \"./lines.js\";\nimport type { Readable, Writable } from \"node:stream\";\nimport {\n errorFrame as wireErrorFrame,\n errorReason as wireErrorReason,\n isProto,\n\n type Channel,\n\n type StringTransport,\n} from \"./channel.js\";\nimport { VERSION, json1Channel } from \"./protocols/json1.js\";\n\n\n/** The stream pair a line transport talks over. */\nexport interface LineStreams {\n read: Readable;\n write: Writable;\n}\n\n/** How long to wait for the far end's first protocol frame. */\nexport const HANDSHAKE_TIMEOUT_MS = 15_000;\n\n/** Raised when the wire itself fails: no frame, the wrong protocol, a peer that went away. */\nexport class StdioWireError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"StdioWireError\";\n }\n}\n\n/** An `$error` frame as a line. The word and its shape are the shared vocabulary's\n * (channel.ts) — one word for a wire that cannot be spoken over, whether the failure was at\n * the start of a session or in the middle of one; what this file owns is its line form. */\nexport function errorFrame(reason: string): string {\n return JSON.stringify(wireErrorFrame(reason));\n}\n\n/** The reason an `$error` frame carries, or null when it is not one. */\nexport function errorReason(frame: Record<string, unknown>): string | null {\n return wireErrorReason(frame);\n}\n\n// ── transports ─────────────────────────────────────────────────────────────\n\n/** Is this write error just a peer that already left? */\nfunction peerGone(code: unknown): boolean {\n return (\n code === \"EPIPE\" ||\n code === \"ERR_STREAM_DESTROYED\" ||\n code === \"ERR_STREAM_WRITE_AFTER_END\" ||\n code === \"ERR_STREAM_ALREADY_FINISHED\"\n );\n}\n\nfunction errorText(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n\n/**\n * A `StringTransport` over a read/write stream pair, one JSON frame per line.\n *\n * `close()` is idempotent and never throws: teardown races are normal here —\n * the peer exits, the read side ends, and a write arrives a moment later.\n */\nexport class LineTransport implements StringTransport {\n private readonly streams: LineStreams;\n private pvtOnMessage: ((line: string) => number | void) | null = null;\n private pvtOnBytes: ((bytes: Uint8Array) => void) | null = null;\n private pvtOnClose: (() => void) | null = null;\n private pvtClosed = false;\n private pvtClosing: Promise<void> | null = null;\n\n constructor(streams: LineStreams) {\n this.streams = streams;\n readParts(\n streams.read,\n (line) => (this.pvtClosed ? undefined : this.pvtOnMessage?.(line)),\n (bytes) => {\n if (!this.pvtClosed) this.pvtOnBytes?.(bytes);\n },\n () => {\n this.pvtOnClose?.();\n void this.close();\n },\n );\n // A stream error is a peer that went away, not a reason to take the process\n // down with an unhandled 'error' event.\n streams.read.on(\"error\", () => {\n void this.close();\n });\n streams.write.on(\"error\", () => {\n void this.close();\n });\n }\n\n get closed(): boolean {\n return this.pvtClosed;\n }\n\n get hasHandler(): boolean {\n return this.pvtOnMessage !== null;\n }\n\n onMessage(handler: (line: string) => number | void): void {\n if (this.pvtClosed) throw new StdioWireError(\"stdio transport: closed\");\n if (this.pvtOnMessage !== null) {\n throw new StdioWireError(\"stdio transport: handler already set — call removeHandler()\");\n }\n this.pvtOnMessage = handler;\n }\n\n onBytes(handler: (bytes: Uint8Array) => void): void {\n if (this.pvtClosed) throw new StdioWireError(\"stdio transport: closed\");\n this.pvtOnBytes = handler;\n }\n\n removeHandler(): ((line: string) => number | void) | null {\n const previous = this.pvtOnMessage;\n this.pvtOnMessage = null;\n return previous;\n }\n\n onClose(handler: () => void): void {\n this.pvtOnClose = handler;\n }\n\n send(frame: string): Promise<void> {\n const line = frame.endsWith(\"\\n\") ? frame : `${frame}\\n`;\n return this.pvtWrite(line);\n }\n\n sendBytes(bytes: Uint8Array): Promise<void> {\n return this.pvtWrite(bytes);\n }\n\n private pvtWrite(data: string | Uint8Array): Promise<void> {\n if (this.pvtClosed) {\n return Promise.resolve();\n }\n return new Promise<void>((resolve, reject) => {\n try {\n this.streams.write.write(data, (err?: Error | null) => {\n if (!err) return resolve();\n const code = (err as { code?: unknown }).code;\n // A peer that has hung up cannot be told anything; the write that\n // races its exit is not an error in this transport.\n if (peerGone(code)) {\n return resolve();\n }\n reject(new StdioWireError(`stdio transport: ${err.message}`));\n });\n } catch (err) {\n reject(new StdioWireError(`stdio transport: ${errorText(err)}`));\n }\n });\n }\n\n async close(): Promise<void> {\n this.pvtClosing ??= this.pvtClose();\n await this.pvtClosing;\n }\n\n private async pvtClose(): Promise<void> {\n await Promise.resolve();\n\n this.pvtClosed = true;\n // Best effort: a half-open stream (the peer is already gone) must not turn\n // teardown into an exception.\n try {\n this.streams.read.destroy?.();\n } catch {\n /* already gone */\n }\n try {\n if (!this.streams.write.writableEnded) this.streams.write.end();\n } catch {\n /* already gone */\n }\n }\n}\n\n/** Streams over two fds of *our own* process — the child side of an fd wire. */\nexport function fdStreams(readFd: number, writeFd: number): LineStreams {\n const read = createReadStream(\"\", { fd: readFd, autoClose: false });\n const write = createWriteStream(\"\", { fd: writeFd, autoClose: false });\n return { read, write };\n}\n\n// ── handshakes ─────────────────────────────────────────────────────────────\n\n/** The next frame that is the protocol's, or a timeout. */\nasync function nextFrame(channel: Channel, timeoutMs: number): Promise<Record<string, unknown>> {\n return await new Promise((resolve, reject) => {\n const timer = setTimeout(\n () => reject(new StdioWireError(`no protocol frame within ${timeoutMs}ms`)),\n timeoutMs,\n );\n timer.unref?.();\n const off = channel.onMessage((frame) => {\n off();\n clearTimeout(timer);\n resolve(frame);\n });\n });\n}\n\nexport interface ClientChannelOptions {\n /** How long to wait for the peer's protocol frame. Defaults to {@link HANDSHAKE_TIMEOUT_MS}. */\n timeoutMs?: number;\n}\n\n/**\n * The client end of the connection: hand the streams to the seam and wait for the peer's `$proto`.\n * A first stage reports a failed start as an `$error` frame instead.\n *\n * What the far end prints is not here: it arrives as a stream the far end announces under a name,\n * and whoever wants it reads it by that name.\n */\nexport async function clientChannel(\n streams: LineStreams,\n opts: ClientChannelOptions = {},\n): Promise<Channel> {\n const channel = json1Channel(new LineTransport(streams));\n const frame = await nextFrame(channel, opts.timeoutMs ?? HANDSHAKE_TIMEOUT_MS);\n\n const reason = errorReason(frame);\n if (reason) throw new StdioWireError(reason);\n if (!isProto(frame)) {\n throw new StdioWireError(`unexpected first frame: ${JSON.stringify(frame).slice(0, 120)}`);\n }\n if (frame.$proto !== VERSION) {\n throw new StdioWireError(`unsupported protocol ${String(frame.$proto)}, expected ${VERSION}`);\n }\n return channel;\n}\n\n/** The server end of the wire — a payload speaking stdio itself. */\nexport async function serverChannel(streams: LineStreams): Promise<Channel> {\n const channel = json1Channel(new LineTransport(streams));\n await channel.send({ $proto: VERSION });\n return channel;\n}\n","// ── FIFO transport ─────────────────────────────────────────────────────────\n//\n// Newline-delimited UTF-8 over named fifos. Strict handler lifecycle:\n// onMessage() throws if a handler is already set; call removeHandler() first.\n\nimport { open, type FileHandle } from \"node:fs/promises\";\nimport type { ReadStream, WriteStream } from \"node:fs\";\nimport { readParts, type LineReader } from \"../lines.js\";\nimport type { StringTransport } from \"../channel.js\";\n\nexport class FifoUtf8NlineTransport implements StringTransport {\n private readFd: FileHandle | null;\n private writeFd: FileHandle | null;\n private reader: LineReader | null;\n private rs: ReadStream | null;\n private ws: WriteStream | null;\n private pvtOnMessage: ((line: string) => number | void) | null = null;\n private pvtOnBytes: ((bytes: Uint8Array) => void) | null = null;\n private pvtOnClose: (() => void) | null = null;\n private closed = false;\n private closingPromise: Promise<void> | null = null;\n private pvtError: Error | null = null;\n\n private constructor(opts: { readFd?: FileHandle; writeFd?: FileHandle }) {\n this.readFd = opts.readFd ?? null;\n this.writeFd = opts.writeFd ?? null;\n\n if (this.readFd) {\n this.rs = this.readFd.createReadStream();\n this.reader = readParts(\n this.rs,\n (line) => (this.closed ? undefined : this.pvtOnMessage?.(line)),\n (bytes) => {\n if (!this.closed) this.pvtOnBytes?.(bytes);\n },\n () => {\n this.pvtOnClose?.();\n void this.close();\n },\n );\n\n this.rs.on(\"error\", (err: Error) => {\n this.pvtError = err;\n this.close();\n });\n } else {\n this.rs = null;\n this.reader = null;\n }\n\n if (this.writeFd) {\n this.ws = this.writeFd.createWriteStream({});\n this.ws.on(\"error\", (err: Error) => {\n this.pvtError = err;\n this.close();\n });\n } else {\n this.ws = null;\n }\n }\n\n // ── factories ──────────────────────────────────────────────────────────\n\n static openReaderFd(readFd: FileHandle): FifoUtf8NlineTransport {\n return new FifoUtf8NlineTransport({ readFd });\n }\n\n static openWriterFd(writeFd: FileHandle): FifoUtf8NlineTransport {\n return new FifoUtf8NlineTransport({ writeFd });\n }\n\n static fromFds(readFd: FileHandle, writeFd: FileHandle): FifoUtf8NlineTransport {\n return new FifoUtf8NlineTransport({ readFd, writeFd });\n }\n\n // ── bidirectional connection ───────────────────────────────────────────\n\n /**\n * Start opening a bidirectional connection. Opens readPath for reading\n * in the background, returns a promise. The caller should do whatever\n * setup is needed to unblock the read (e.g. spawn a process that opens\n * readPath for writing), then await the returned transport.\n *\n * The transport itself is built only once both directions are open. A read\n * stream created while no writer exists on its fifo is handed an immediate\n * end-of-stream by some runtimes (bun), which closes a channel that has not\n * carried a byte yet — so the writes side is opened before the reader exists.\n */\n static beginConnect(\n readPath: string,\n writePath: string,\n ): { transport: Promise<FifoUtf8NlineTransport> } {\n const readFdPromise = open(readPath, \"r\");\n\n const transport = readFdPromise.then(async (readFd) => {\n const writeFd = await open(writePath, \"w\");\n return FifoUtf8NlineTransport.fromFds(readFd, writeFd);\n });\n\n return { transport };\n }\n\n /**\n * Open a bidirectional connection. Opens writePath for writing first\n * (unblocking the peer's read), starts reading readPath in the\n * background, then awaits both.\n *\n * Use this when you are the side that responds to the peer's beginConnect\n * (i.e. you don't need to interleave any setup between the read and write\n * opens). Built like `beginConnect`: the transport exists only after both\n * directions do.\n */\n static async connect(readPath: string, writePath: string): Promise<FifoUtf8NlineTransport> {\n const readFdPromise = open(readPath, \"r\");\n const writeFd = await open(writePath, \"w\");\n const readFd = await readFdPromise;\n return FifoUtf8NlineTransport.fromFds(readFd, writeFd);\n }\n\n // ── public API ─────────────────────────────────────────────────────────\n\n get canSend(): boolean {\n return this.writeFd !== null && !this.closed;\n }\n\n onBytes(handler: (bytes: Uint8Array) => void): void {\n if (this.closed) throw new Error(\"FifoUtf8NlineTransport: closed\");\n if (this.readFd === null) throw new Error(\"FifoUtf8NlineTransport: not a reader\");\n this.pvtOnBytes = handler;\n }\n\n onMessage(handler: (line: string) => number | void): void {\n if (this.closed) throw new Error(\"FifoUtf8NlineTransport: closed\");\n if (this.readFd === null) throw new Error(\"FifoUtf8NlineTransport: not a reader\");\n if (this.pvtOnMessage !== null) {\n throw new Error(\"FifoUtf8NlineTransport: handler already set — call removeHandler() first\");\n }\n this.pvtOnMessage = handler;\n }\n\n removeHandler(): ((line: string) => number | void) | null {\n const prev = this.pvtOnMessage;\n this.pvtOnMessage = null;\n return prev;\n }\n\n onClose(handler: () => void): void {\n this.pvtOnClose = handler;\n }\n\n get hasHandler(): boolean {\n return this.pvtOnMessage !== null;\n }\n\n get lastError(): Error | null {\n return this.pvtError;\n }\n\n async send(line: string): Promise<void> {\n if (this.closed) throw new Error(\"FifoUtf8NlineTransport: closed\");\n if (this.writeFd === null) throw new Error(\"FifoUtf8NlineTransport: not a writer\");\n if (!line.endsWith(\"\\n\")) line += \"\\n\";\n await this.ws?.write(line);\n }\n\n async sendBytes(bytes: Uint8Array): Promise<void> {\n if (this.closed) throw new Error(\"FifoUtf8NlineTransport: closed\");\n if (this.writeFd === null) throw new Error(\"FifoUtf8NlineTransport: not a writer\");\n await this.ws?.write(bytes);\n }\n\n async close(): Promise<void> {\n this.closingPromise = this.closingPromise || this.pvtClose();\n await this.closingPromise;\n this.closed = true;\n }\n\n private async pvtClose(): Promise<void> {\n // tranfser control back to caller\n // so they can capture the promise reference\n // and prevent reentry\n await Promise.resolve();\n\n if (this.reader) {\n this.reader.stop();\n this.reader = null;\n }\n if (this.rs) {\n this.rs.destroy();\n this.rs = null;\n }\n if (this.ws) {\n await new Promise<void>((resolve) => {\n try {\n this.ws?.end(\"\", resolve);\n } catch {\n resolve();\n }\n });\n this.ws = null;\n }\n\n if (this.readFd) {\n try {\n await this.readFd.close();\n } catch {}\n this.readFd = null;\n }\n if (this.writeFd) {\n try {\n await this.writeFd.close();\n } catch {}\n this.writeFd = null;\n }\n }\n}\n","// ── Gateway ────────────────────────────────────────────────────────────────\n//\n// The first-stage command. Run this *inside* a foreign environment — directly,\n// under `sudo`, over ssh, in a container — and it:\n//\n// 1. creates the channel to the payload (fifo paths it makes itself, in a\n// private temp dir, so they belong to the uid that will open them),\n// 2. starts the payload — the first argument, required — hands it everything else it was\n// given (the host version among it) and relays frames between stdin/stdout,\n// 3. carries whatever the payload prints to the client as output frames\n// (`$fd`), so the payload's own stdout can never be mistaken for protocol.\n//\n// Why a gateway at all: a fifo path created on the client side is useless when the\n// payload runs as another uid (it cannot open it) or on another host (the path is\n// not there). stdio is the one channel every way into an environment gives us, so\n// the wire is stdio and the fifo stays inside the environment.\n//\n// The gateway reads nothing out of what it carries and owns no flag: the payload's path and\n// every argument after it go through verbatim, in order. The payload is the one who refuses a\n// host version it is not, and a relay that judged would be a second place for that decision.\n//\n// Directories and processes are cleaned up on every exit path, which is also why\n// the client never sees a transport being closed twice.\n//\n// It imports nothing but node builtins and this package, so the payload behind it\n// can be anything the runtime there can start.\n\nimport { execFile, spawn, type ChildProcess } from \"node:child_process\";\nimport { mkdtemp, rm } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { basename, join } from \"node:path\";\nimport { promisify } from \"node:util\";\nimport { channelThrough } from \"./channel.js\";\nimport { json1Channel } from \"./protocols/json1.js\";\nimport { lowBand } from \"./process-ref.js\";\nimport { StreamStore } from \"./stream.js\";\nimport { errorFrame } from \"./stdio.js\";\nimport type { LineTransport } from \"./stdio.js\";\nimport { LineTransport as Lines } from \"./stdio.js\";\nimport { FifoUtf8NlineTransport } from \"./transports/fifo.js\";\n\nconst run = promisify(execFile);\n\n/** How much of a dying payload's own words travels in the reason a failed start carries. */\nconst REASON_TAIL = 4096;\n\n/** Exit code for \"this environment could not be set up\". */\nexport const GATEWAY_FAILED = 1;\n\nexport interface GatewayBoot {\n /**\n * The program to start for the payload: the first word of the command the client composed —\n * a runtime, or a program that runs itself. Required, and first, and the gateway has no\n * opinion of its own about which it is.\n */\n worker: string;\n /**\n * Everything after the payload, carried to it **as is** and in order: the consumer's own\n * arguments, and posipaki's own facts among them (the host version travels this way). The\n * gateway reads nothing by name and owns no flag, so nothing of the caller's is interpreted,\n * eaten, re-ordered or re-spelled — and the next fact added to that line needs no new\n * vocabulary here.\n */\n passthrough: string[];\n}\n\nfunction errorText(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n\n/**\n * A label for the gateway's own temp directory: the program this environment was made for.\n * It is the gateway's business alone — the payload is not told which label it is.\n */\nfunction label(worker: string): string {\n const name = basename(worker).replace(/[^A-Za-z0-9.+@_-]/g, \"-\").slice(0, 60);\n return name === \"\" ? \"payload\" : name;\n}\n\n/**\n * The argv that boots this gateway — built by the client, read by\n * {@link gatewayBoot}, so the two halves cannot drift apart.\n *\n * The payload comes first and its arguments after it, so a positional argument of the\n * payload's own can never be mistaken for the payload.\n */\nexport function gatewayArgs(boot: GatewayBoot): string[] {\n return [boot.worker, ...boot.passthrough];\n}\n\n/** The boot a gateway was started with, or the reason it cannot start. */\nexport function gatewayBoot(argv: string[]): GatewayBoot {\n const [worker, ...passthrough] = argv;\n if (worker === undefined || worker.startsWith(\"--\")) {\n throw new Error(\"no <payload>: the gateway relays to a payload, named as its first argument\");\n }\n return { passthrough, worker };\n}\n\n/**\n * End a start that failed. The reason has already gone out on the wire, and\n * returning is not enough: the `open()` on a fifo no payload will ever write sits\n * in the threadpool forever, so the loop never drains and the gateway would linger\n * with a dead payload on its books.\n */\nfunction abandon(): never {\n process.exit(GATEWAY_FAILED);\n}\n\n/** Carry a failed start to the client, then let the caller exit non-zero. */\nasync function fail(wire: LineTransport, reason: string): Promise<void> {\n process.stderr.write(`gateway: ${reason}\\n`);\n try {\n await wire.send(errorFrame(reason));\n } catch {\n /* the client is gone too — the exit code still says what happened */\n }\n}\n\n/** The payload's own prints, as a stream: the pipe's chunks as they arrive. */\nasync function* chunksOf(stream: NodeJS.ReadableStream, prefix = \"\"): AsyncIterable<Uint8Array> {\n if (prefix.length > 0) yield new TextEncoder().encode(prefix);\n for await (const chunk of stream as AsyncIterable<Buffer | string>) {\n yield typeof chunk === \"string\" ? new TextEncoder().encode(chunk) : new Uint8Array(chunk);\n }\n}\n\n/** Everything a payload printed into its pipes, up to the point they end: what a start that dies\n * before its channel says about itself. A stream cannot carry it — there is no connection yet. */\n\n/**\n * Serve one environment over stdin/stdout. Returns the exit code; the caller\n * turns it into `process.exitCode`.\n */\nexport async function runGateway(argv: string[] = process.argv.slice(2)): Promise<number> {\n const wire = new Lines({ read: process.stdin, write: process.stdout });\n // One channel on the client wire, and the ids this gateway speaks from: the low band, which neither\n // the client nor the payload allocates in, so a stream of its own cannot collide with one of theirs.\n // The store answers only for the streams it offered; everything else belongs to the far side.\n const client = json1Channel(wire);\n const output = new StreamStore(client, \"even\", { ids: lowBand(\"even\"), attach: false });\n\n let booted: GatewayBoot;\n try {\n booted = gatewayBoot(argv);\n } catch (err) {\n // Nothing has been started yet, so there is nothing to tear down — but the\n // client still deserves the reason rather than a channel that closes on it,\n // and the loop can outlive us: an open stdin nobody will close keeps the\n // process alive, so this is an exit, not a return.\n await fail(wire, errorText(err));\n abandon();\n }\n const { passthrough, worker } = booted;\n\n const dir = await mkdtemp(join(tmpdir(), `posipaki-${label(worker)}-`));\n const fifoIn = join(dir, \"in\"); // the payload writes, we read\n const fifoOut = join(dir, \"out\"); // we write, the payload reads\n\n let child: ChildProcess | null = null;\n let fifo: FifoUtf8NlineTransport | null = null;\n\n /**\n * Everything this gateway owns, undone. All of it is idempotent, because the\n * exit path and the signal path can both arrive.\n */\n const teardown = async (): Promise<void> => {\n child?.kill();\n await fifo?.close().catch(() => {});\n await rm(dir, { recursive: true, force: true }).catch(() => {});\n };\n\n /**\n * A client that gives up stops us with a signal, and a gateway that died on the\n * spot would leave its payload behind in the environment — a process holding a\n * fifo nobody will ever write, which is a leak the environment cannot clean up\n * for us. So the signals do what the exit path does.\n */\n const onTerminate = () => {\n void teardown()\n .catch(() => {})\n .then(() => process.exit(GATEWAY_FAILED));\n };\n for (const signal of [\"SIGTERM\", \"SIGINT\", \"SIGHUP\"] as const) process.on(signal, onTerminate);\n\n try {\n await run(\"mkfifo\", [\"-m\", \"600\", fifoIn, fifoOut]);\n } catch (err) {\n await fail(wire, `cannot create the environment's fifos: ${errorText(err)}`);\n await teardown();\n abandon();\n }\n\n // Open the read side in the background, then start the payload that unblocks\n // it — the order the fifo handshake requires.\n const connection = FifoUtf8NlineTransport.beginConnect(fifoIn, fifoOut);\n const workerArgs = [worker, ...passthrough, `--fifo-in=${fifoIn}`, `--fifo-out=${fifoOut}`];\n // Whatever the client said starts the payload, run as it said: a runtime with a script of\n // ours, or a program of the caller's own. The gateway does not know which it is, and does\n // not choose a runtime on the far end's behalf.\n const workerProc = spawn(workerArgs[0]!, workerArgs.slice(1), {\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n });\n child = workerProc;\n /** What the payload printed before the client spoke: a start that dies that early has no connection\n * to announce a stream on, and its words are the only way to say why it went. Kept per stream, so\n * the output that comes after is still attributed to the right one. */\n const early = { stdout: \"\", stderr: \"\" };\n const keep =\n (name: \"stdout\" | \"stderr\") =>\n (chunk: Buffer | string): void => {\n early[name] = (early[name] + String(chunk)).slice(-REASON_TAIL);\n };\n const keepOut = keep(\"stdout\");\n const keepErr = keep(\"stderr\");\n workerProc.stdout?.on(\"data\", keepOut);\n workerProc.stderr?.on(\"data\", keepErr);\n\n /** Announce the payload's own output as the two streams a program's prints belong on, with whatever\n * it said before the connection could carry it replayed as the first chunk. */\n const offerOutput = (): void => {\n const sides = [\n { stream: workerProc.stdout, name: \"stdout\", keep: keepOut },\n { stream: workerProc.stderr, name: \"stderr\", keep: keepErr },\n ] as const;\n for (const { stream, name, keep: drop } of sides) {\n if (!stream) continue;\n stream.off(\"data\", drop);\n stream.pause();\n output.offer(chunksOf(stream, early[name]), name);\n }\n };\n\n const exited = new Promise<number>((settle) => {\n // A payload killed by a signal (the client hung up, and we killed it) has no\n // code — for us that is a clean end, not a failure.\n workerProc.once(\"exit\", (code) => settle(code ?? 0));\n });\n\n try {\n fifo = await Promise.race([\n connection.transport,\n exited.then((code) => {\n throw new Error(`the payload exited with code ${code} before it opened its channel`);\n }),\n ]);\n } catch (err) {\n // A payload that dies before it opens its channel printed into pipes nobody is reading yet: its\n // last words are the only way to say why, and they are not a stream because no connection exists\n // to announce one on.\n const said = `${early.stdout}${early.stderr}`.trim();\n await fail(wire, `${errorText(err)}${said ? `: ${said}` : \"\"}`);\n await teardown();\n abandon();\n }\n\n // Relay frames, not lines: the gateway has streams of its own now — the payload's output — and one\n // the store claims is the gateway's, not the payload's business. Everything else crosses unchanged.\n // `fifo` is settled by the race above: a start that failed took the exit path and never got here.\n const payload = json1Channel(fifo as FifoUtf8NlineTransport);\n const fromClient = channelThrough(client, (frame) => output.handle(frame));\n const forward = (send: (frame: Record<string, unknown>) => unknown, frame: Record<string, unknown>): void => {\n void Promise.resolve(send(frame)).catch(() => {\n /* the far side is gone; its own exit path cleans up */\n });\n };\n let offered = false;\n fromClient.onMessage((frame) => {\n if (!offered) {\n offered = true;\n // The client has spoken, which means its store exists: an announcement made before that would\n // land in a connection with nobody listening for it.\n offerOutput();\n }\n forward((next) => payload.send(next), frame);\n });\n fromClient.onSegment?.((head, bytes) => {\n payload.sendSegment?.(head, bytes);\n });\n payload.onMessage((frame) => {\n forward((next) => client.send(next), frame);\n });\n payload.onSegment?.((head, bytes) => {\n client.sendSegment?.(head, bytes);\n });\n client.onClose(() => {\n child?.kill();\n });\n\n const code = await exited;\n await teardown();\n await wire.close();\n return code;\n}\n","// ── The gateway, as a program ──────────────────────────────────────────────\n//\n// A gateway is something a client runs: the first-stage command that makes a fifo\n// inside a foreign environment and relays frames between its own stdin/stdout and\n// the payload. That is this file's whole job — it always serves, and it exits with\n// the code the run ended in.\n//\n// Serving lives in ./gateway.js and starts nothing by itself. A file cannot decide\n// \"am I the program?\" from where it is: a consumer that bundles the node surface\n// into its own program carries this code along, and there the bundle *is* the\n// program — a payload would find a gateway booting on its wire. So the decision is\n// in the layout instead: importing a module never starts anything, and running this\n// one always does.\n//\n// The client names it either way: `posipaki/remote/gateway-cli.js` is a published\n// specifier, so `import.meta.resolve` answers with the built file, and a consumer\n// with a program of its own stages that instead. Nothing here works out its own\n// location — a path derived from `import.meta.url` is a guess about a layout the\n// bundler owns, and the guess is wrong the moment the module moves into a chunk.\n\nimport { GATEWAY_FAILED, runGateway } from \"./gateway.js\";\n\nvoid (async () => {\n try {\n process.exitCode = await runGateway();\n } catch (err) {\n process.stderr.write(`gateway: ${err instanceof Error ? err.message : String(err)}\\n`);\n process.exitCode = GATEWAY_FAILED;\n }\n})();\n"],"mappings":"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"}
1
+ {"version":3,"file":"gateway-cli.js","names":["errorFrame","wireErrorFrame","errorText","Lines"],"sources":["../../src/remote/process-ref.ts","../../src/remote/channel.ts","../../src/remote/protocols/json1.ts","../../src/remote/stream.ts","../../src/remote/lines.ts","../../src/remote/stdio.ts","../../src/remote/transports/fifo.ts","../../src/remote/gateway.ts","../../src/remote/gateway-cli.ts"],"sourcesContent":["// ── Process references on the wire ─────────────────────────────────────────\n//\n// A process is not JSON: it holds state, children and methods. So a reflection\n// method that returns one cannot answer with the process itself — it answers\n// with a reference, and the caller is handed what it can read: a name, and an id\n// this connection uses for that process.\n//\n// The id belongs to the connection and to the side that holds the process: that\n// side allocates it, and both sides then know the process by it. Allocated once\n// per process — handed over twice, it is the same reference both times — and\n// never reused, so an id whose process is gone resolves to nothing rather than to\n// whatever came after it.\n//\n// The two sides allocate from one space, split by parity: the client takes the\n// odd ids, the server the even ones. Every connection also has a root, and a root is\n// numbered like anything else — the first id of the parity of the side that holds it:\n// 0 on the even side (the server), 1 on the odd one (the client). So an id says on\n// its own which side holds the process it names, the two roots included, and a frame's\n// address means the same thing whoever reads it.\n//\n// A side's own root is the process the connection is, and the far side's root is a\n// handle here like any of theirs. Neither end has to be told which number belongs to\n// whom: each root is the first id of its own parity.\n\nimport { isProcess } from \"../process.async.js\";\nimport type { RemoteProcess } from \"./remote-process.js\";\nimport { isPlainObject, isStreamLike } from \"./channel.js\";\n\n/** The key that marks a process reference inside an otherwise JSON value. */\nexport const PROCESS_REF = \"$p\";\n\n/**\n * The id a side gives its own root: the first id of its parity. The two ends of a\n * connection therefore number their roots differently, and an id says whose root it is\n * as it says who holds every other process. A side hands out its next id from two\n * steps further on, the one in between belonging to the root of the side it talks to.\n */\nexport function rootIdFor(parity: IdParity): number {\n return parity === \"odd\" ? 1 : 0;\n}\n\n/** What a served root is called when the client states no name for it. A client that\n * states one — and the library's own does, in `$init` — is served under that name instead:\n * the process across the seam is the one its proxy was forked as, and it should be called\n * the same on both sides. This is the name for a connection that says nothing. */\nexport const SERVED_ROOT_NAME = \"remote\";\n\n/** What crosses the wire in place of a process. */\nexport interface ProcessRef {\n id: number;\n pname: string;\n}\n\n/** The little a table needs of what it holds to name it: what it is called, and\n * the symbol that identifies it in this build. */\nexport interface ProcessHandle {\n readonly pname: string;\n readonly id: symbol;\n}\n\n/** Which ids a side hands out: the client takes the odd ones, the server the\n * even ones, so one number can never name a process on both sides at once. */\nexport type IdParity = \"odd\" | \"even\";\n/** The end of the low band: ids 0 and 1 are the two roots, 2 through 8 belong to a party that speaks\n * on a connection it otherwise only relays — the first stage's own streams — and nothing allocates\n * inside it, so a band id can never collide with one either end mints. */\nexport const LOW_BAND_END = 8;\n\n/**\n * The ids one side of a connection hands out: its own parity, from the far side of the low band.\n *\n * Everything numbered on the connection draws from one space — a process reference and a stream alike —\n * so a number names one thing, and the parity says which side made it. Each side builds its own and\n * hands the same one to whatever allocates.\n */\nexport class IdSpace {\n private pvtNext: number;\n /** True for a space inside the low band, which refuses to leave it. */\n private readonly pvtBand: boolean;\n\n constructor(\n readonly parity: IdParity,\n first: number = parity === \"odd\" ? LOW_BAND_END + 1 : LOW_BAND_END + 2,\n ) {\n this.pvtNext = first;\n this.pvtBand = first <= LOW_BAND_END;\n }\n\n /** This side's own end of the connection: the first id of its parity, never handed out. */\n root(): number {\n return rootIdFor(this.parity);\n }\n\n /** The next id of this side's parity, and never the same one twice. */\n next(): number {\n if (this.pvtBand && this.pvtNext > LOW_BAND_END) throw new Error(\"IdSpace: the low band is spent\");\n const id = this.pvtNext;\n this.pvtNext += 2;\n return id;\n }\n}\n\n/**\n * A space inside the low band, for a party that speaks on a connection it otherwise relays: its ids\n * come from a range no end allocates in, so announcing something of its own cannot take a number\n * either end might mint.\n */\nexport function lowBand(parity: IdParity): IdSpace {\n return new IdSpace(parity, parity === \"odd\" ? 3 : 2);\n}\n\n/**\n * The processes one connection knows, by the ids that name them. One table per\n * connection, because an id means nothing on any other one, and it lives exactly\n * as long as the connection that owns it.\n *\n * It holds two sets, told apart by parity rather than kept apart by a rule: the\n * processes this side holds — the root, and anything it hands over — and the ones\n * the far side holds, which this side knows as handles. A frame's address is\n * looked up in both, and exactly one can answer.\n */\nexport class ProcessTable<P extends ProcessHandle = ProcessHandle> {\n /** This side's own processes, by the ids it gave them. */\n private pvtMine = new Map<number, P>();\n private pvtMineIds = new Map<P, number>();\n /** The far side's processes, by the ids they came with. */\n private pvtTheirs = new Map<number, P>();\n /** The id of this side's own root: the first of its parity. */\n private pvtRootId: number;\n /** The id the far side gave its root: the first of its parity, and the number this\n * side's own numbering skips. */\n private pvtFarRootId: number;\n /** Told the first time a process is numbered — the moment it is about to\n * cross the connection. */\n private pvtOnCrossed: ((proc: P, id: number) => void) | undefined;\n /** Where the ids come from: one space per side, shared with whatever else numbers something. */\n private readonly ids: IdSpace;\n\n constructor(parity: IdParity, onCrossed?: (proc: P, id: number) => void, ids: IdSpace = new IdSpace(parity)) {\n this.ids = ids;\n this.pvtRootId = ids.root();\n this.pvtFarRootId = rootIdFor(parity === \"odd\" ? \"even\" : \"odd\");\n this.pvtOnCrossed = onCrossed;\n }\n\n /** The id of this side's own end of the connection. */\n rootId(): number {\n return this.pvtRootId;\n }\n\n /** The id the far side knows its own end by: the root this side reaches as a handle,\n * and the one it never hands out for anything of its own. */\n farRootId(): number {\n return this.pvtFarRootId;\n }\n\n /** Bind this side's own end of the connection — the root — to its id. */\n bindRoot(proc: P): void {\n const bound = this.pvtMine.get(this.pvtRootId);\n if (bound !== undefined && bound !== proc) {\n throw new Error(\"ProcessTable: the root is already bound\");\n }\n this.pvtMine.set(this.pvtRootId, proc);\n this.pvtMineIds.set(proc, this.pvtRootId);\n }\n\n /** The id this side gives a process it holds, allocating one the first time. */\n handleFor(proc: P): number {\n const known = this.pvtMineIds.get(proc);\n if (known !== undefined) return known;\n const id = this.ids.next();\n this.pvtMine.set(id, proc);\n this.pvtMineIds.set(proc, id);\n this.pvtOnCrossed?.(proc, id);\n return id;\n }\n\n /** A process this side holds, by the id it gave it. */\n processFor(id: number): P | undefined {\n return this.pvtMine.get(id);\n }\n\n /**\n * Register a process the far side holds — a handle — under the id it arrived\n * with. A root is one of these as much as anything else: both ends hold one at 0,\n * so the far side's root is a handle here, and the one this side has of itself\n * stays what it was.\n */\n bindFar(id: number, proc: P): void {\n this.pvtTheirs.set(id, proc);\n }\n\n /** A process the far side holds, by the id it gave it. */\n farHandleFor(id: number): P | undefined {\n return this.pvtTheirs.get(id);\n }\n\n /**\n * Whatever this connection knows `id` to mean: a process this side holds, or a\n * handle on one the far side holds. Only one of the two can answer, because\n * the two sides take their ids from different halves of the space — so what\n * comes back does not depend on which way the frame was going.\n */\n resolve(id: number): P | undefined {\n return this.pvtMine.get(id) ?? this.pvtTheirs.get(id);\n }\n\n /**\n * Let go of an id: the process behind it is not this connection's business any\n * more, so it is no longer known by it. Both sides' ids go the same way — the\n * side that lets a handle go names the far side's id, the side that is asked to\n * forget names its own — and an id let go is never handed out again, so nothing\n * that still names it can come to mean another process.\n *\n * Neither root is let go of: one is this side's own end of the connection, and the\n * other is what this side is talking to.\n */\n release(id: number): P | undefined {\n if (id === this.pvtRootId || id === this.pvtFarRootId) return undefined;\n const mine = this.pvtMine.get(id);\n if (mine !== undefined) {\n this.pvtMine.delete(id);\n this.pvtMineIds.delete(mine);\n return mine;\n }\n const theirs = this.pvtTheirs.get(id);\n if (theirs !== undefined) this.pvtTheirs.delete(id);\n return theirs;\n }\n\n /** Every handle this side holds on a process of the far side. */\n handles(): P[] {\n return [...this.pvtTheirs.values()];\n }\n}\n\n/** Whether `value` is the wire form of a reference. */\nexport function asProcessRef(value: unknown): ProcessRef | null {\n if (typeof value !== \"object\" || value === null) return null;\n const ref = (value as Record<string, unknown>)[PROCESS_REF];\n if (typeof ref !== \"object\" || ref === null) return null;\n const { id, pname } = ref as Record<string, unknown>;\n if (typeof id !== \"number\" || typeof pname !== \"string\") return null;\n return { id, pname };\n}\n\n/** Whether `value` has the shape of a handle on a far-side process. Judged by\n * what it holds rather than by `instanceof`, for the reason a process is: one\n * build can hold two copies of the class. */\nexport function isRemoteProcess(value: unknown): value is RemoteProcess {\n if (typeof value !== \"object\" || value === null) return false;\n const candidate = value as { pname?: unknown; id?: unknown; ref?: unknown; send?: unknown };\n return (\n typeof candidate.pname === \"string\" &&\n typeof candidate.id === \"symbol\" &&\n typeof candidate.send === \"function\" &&\n asProcessRef({ [PROCESS_REF]: candidate.ref }) !== null\n );\n}\n\n/**\n * Replace every process in `value` with the reference this connection uses for\n * it, so what is left is JSON that says which processes the answer is about.\n *\n * A handle goes back as the reference it came with, id and all: that id is the\n * far side's own, the one it will be read by.\n *\n * Containers are copied rather than rewritten: the objects belong to the actor\n * that returned them, and a state it is still running on is not ours to edit. A\n * node already seen is left where it is — a cycle is the encoder's to report, not\n * something to walk forever.\n */\nexport function encodeProcessRefs(\n value: unknown,\n table: ProcessTable,\n seen: Set<unknown> = new Set(),\n): unknown {\n // A stream is carried by reference too, and its behaviour lives on a symbol-keyed property a\n // copy would drop. It is the stream layer's value to offer, so it is left as it is here.\n if (isStreamLike(value)) return value;\n if (isRemoteProcess(value)) {\n return { [PROCESS_REF]: { id: value.ref.id, pname: value.ref.pname } };\n }\n if (isProcess(value)) {\n return { [PROCESS_REF]: { id: table.handleFor(value), pname: value.pname } };\n }\n if (Array.isArray(value)) {\n if (seen.has(value)) return value;\n seen.add(value);\n return value.map((item) => encodeProcessRefs(item, table, seen));\n }\n if (isPlainObject(value)) {\n if (seen.has(value)) return value;\n seen.add(value);\n const copy: Record<string, unknown> = {};\n for (const [key, item] of Object.entries(value)) {\n copy[key] = encodeProcessRefs(item, table, seen);\n }\n return copy;\n }\n return value;\n}\n\n/** How a side turns a reference into something it can hold: a handle. */\nexport type RefResolver = (ref: ProcessRef) => unknown;\n\n/** Replace every reference in `value` with what `resolve` makes of it. */\nexport function decodeProcessRefs(\n value: unknown,\n resolve: RefResolver,\n seen: Set<unknown> = new Set(),\n): unknown {\n // A stream is carried by reference too, and its behaviour lives on a symbol-keyed property a\n // copy would drop. It is the stream layer's value to offer, so it is left as it is here.\n if (isStreamLike(value)) return value;\n const ref = asProcessRef(value);\n if (ref) return resolve(ref);\n if (Array.isArray(value)) {\n if (seen.has(value)) return value;\n seen.add(value);\n return value.map((item) => decodeProcessRefs(item, resolve, seen));\n }\n if (isPlainObject(value)) {\n if (seen.has(value)) return value;\n seen.add(value);\n const copy: Record<string, unknown> = {};\n for (const [key, item] of Object.entries(value)) {\n copy[key] = decodeProcessRefs(item, resolve, seen);\n }\n return copy;\n }\n return value;\n}\n","// ── Frame channel ──────────────────────────────────────────────────────────\n//\n// The seam's shared vocabulary. A StringTransport moves encoded frames\n// (strings); a Channel moves decoded frame objects. The frame guards narrow a\n// decoded frame to one of the `$`-key shapes. server.ts / client.ts speak only\n// in Channels and these guards — they never see a specific protocol or\n// transport.\n\nimport type { FrameChannel, Message } from \"../types.js\";\nimport {\n decodeProcessRefs,\n encodeProcessRefs,\n type ProcessTable,\n type RefResolver,\n} from \"./process-ref.js\";\n\nexport interface StringTransport {\n send(frame: string): void | Promise<void>;\n /**\n * A line arrived. Answer with the number of raw octets that follow it, if any: a frame\n * may announce a run of bytes (a chunk of a stream), and the transport then hands those\n * octets over instead of reading them as more lines.\n */\n onMessage(handler: (frame: string) => number | void): void;\n /** The octets a line announced, whole, in the order they were sent. */\n onBytes(handler: (bytes: Uint8Array) => void): void;\n removeHandler(): void;\n /** Raw octets, written after whatever went before them. */\n sendBytes(bytes: Uint8Array): void | Promise<void>;\n /** Fires when the peer disconnects (transport closes from the other side). */\n onClose(handler: () => void): void;\n close(): Promise<void>;\n}\n\n/**\n * What the frame layer needs of a connection's values: two walks, and no knowledge of how the\n * bytes travel. The frame vocabulary lives in this file and the machinery in\n * `stream.ts`, so a store comes in as this shape rather than as an import from here.\n */\nexport interface ValueCodec {\n /** Replace every value that must cross by reference with one this connection serves. */\n encode(value: unknown): unknown;\n /** Replace every reference in a value with something the reader can hold. */\n decode(value: unknown): unknown;\n}\n\n/**\n * Several codecs over one connection, each value through all of them, in the order given.\n *\n * A connection carries more than one kind of thing by reference — a blob, a stream — and each\n * store knows only its own. Walking a value through every store in turn is what keeps them\n * from having to know about each other.\n */\nexport function combineCodecs(...codecs: ValueCodec[]): ValueCodec {\n return {\n encode: (value) => codecs.reduce((current, codec) => codec.encode(current), value),\n decode: (value) => codecs.reduce((current, codec) => codec.decode(current), value),\n };\n}\n\n/** The frames of one connection, as the remote layer speaks them: the process's own `FrameChannel`,\n * where a reader has the unsubscribe `onMessage` returned rather than a handler to take back. */\nexport type Channel = FrameChannel;\n\n/** Is this something JSON would carry as an object, rather than an instance with behaviour? */\nexport function isPlainObject(value: unknown): value is Record<string, unknown> {\n if (typeof value !== \"object\" || value === null) return false;\n const prototype = Object.getPrototypeOf(value) as object | null;\n return prototype === Object.prototype || prototype === null;\n}\n\n/**\n * Is this a stream — a value whose bytes come later, carried by reference?\n *\n * The question every walk that copies containers has to ask: copying a stream keeps the object and\n * loses the behaviour, because its iterator is a symbol-keyed property and `Object.entries` does not\n * see those. What such a value is belongs to `stream.ts`; that it must be left alone belongs to\n * every layer that walks a message.\n */\nexport function isStreamLike(value: unknown): value is AsyncIterable<Uint8Array> {\n if (typeof value !== \"object\" || value === null) return false;\n return typeof (value as Partial<AsyncIterable<Uint8Array>>)[Symbol.asyncIterator] === \"function\";\n}\n\n/**\n * One handler on the wire, however many readers on it. A transport holds one handler — and reports a\n * second one as a mistake — so the layer above keeps the readers and installs a single handler; the\n * subscribe this returns is what a reader calls to leave. The handler goes on with the first reader and\n * stays for the life of the connection: taking it off between readers would drop whatever arrives in\n * between, and a connection is not paused by nobody reading it.\n */\nexport function frameReaders(\n install: (deliver: (frame: Record<string, unknown>) => void) => void,\n): (handler: (frame: Record<string, unknown>) => void) => () => void {\n const readers = new Set<(frame: Record<string, unknown>) => void>();\n let installed = false;\n return (handler) => {\n if (!installed) {\n installed = true;\n install((frame) => {\n // Over a copy: a reader that leaves as it is handed a frame must not cut the rest short.\n for (const reader of [...readers]) reader(frame);\n });\n }\n readers.add(handler);\n return () => {\n readers.delete(handler);\n };\n };\n}\n\n/**\n * A channel that is `base`, with every incoming frame offered to `onFrame` first — and not handed\n * on when it is claimed.\n *\n * Every wrapper above a protocol wants this one thing, and none of them may lose the octets: a\n * connection that carries segments keeps carrying them through whatever wraps it, or a stream\n * dies one layer above the wire it was written for.\n */\nexport function channelThrough(base: Channel, onFrame: (frame: Record<string, unknown>) => boolean): Channel {\n const wrapped: Channel = {\n send: (frame) => base.send(frame),\n onMessage: (handler) =>\n base.onMessage((frame) => {\n if (onFrame(frame)) return;\n handler(frame);\n }),\n onClose: (handler) => base.onClose(handler),\n close: () => base.close(),\n };\n if (base.sendSegment) {\n wrapped.sendSegment = (frame, bytes) => base.sendSegment?.(frame, bytes);\n }\n if (base.onSegment) {\n wrapped.onSegment = (handler) => base.onSegment?.(handler) ?? (() => {});\n }\n return wrapped;\n}\n\n// ── the address on a frame ─────────────────────────────────────────────────\n//\n// A frame that is about a process carries that process's id as `to`, at the top level\n// of the frame rather than inside its body: the frame is the envelope, and the address\n// says who it is for whatever kind it turns out to be. Every frame that is about a\n// process names it, the root of the connection included, since both ends number their\n// own root and neither has to be guessed at.\n\n/** The id a frame addresses, or null when it names no process. */\nexport function frameTo(frame: Record<string, unknown>): number | null {\n const to = frame.to;\n return typeof to === \"number\" ? to : null;\n}\n\n/**\n * A frame on its way out: every process in it becomes the reference this\n * connection uses for that process, and the process the frame addresses is\n * written down as `to`.\n */\nexport function encodeFrame(\n frame: Record<string, unknown>,\n table: ProcessTable,\n to: number,\n codecs?: ValueCodec,\n): Record<string, unknown> {\n const withProcesses = encodeProcessRefs(frame, table) as Record<string, unknown>;\n const encoded = codecs === undefined ? withProcesses : (codecs.encode(withProcesses) as Record<string, unknown>);\n return { ...encoded, to };\n}\n\n/**\n * A frame just read: every reference in it becomes a handle on that process — or\n * the handle this side already made for it, since the same process handed over\n * twice is one process.\n */\nexport function decodeFrame(\n frame: Record<string, unknown>,\n resolve: RefResolver,\n codecs?: ValueCodec,\n): Record<string, unknown> {\n const resolved = decodeProcessRefs(frame, resolve) as Record<string, unknown>;\n return codecs === undefined ? resolved : (codecs.decode(resolved) as Record<string, unknown>);\n}\n\n// ── frame guards ──────────────────────────────────────────────────────────\n//\n// Each guard narrows a decoded frame to the frame it is, and each of those types is\n// named, so the whole set can be written down once (see `Frame`, at the foot of this\n// file). A guard asks only whether the key is there: the body under it belongs to\n// whoever wrote it.\n\nexport type ProtoFrame = {\n $proto: string;\n};\nexport type InitFrame = {\n $init: Record<string, unknown>;\n};\nexport type StateFrame = {\n $state: Record<string, unknown>;\n};\nexport type MsgFrame = {\n $msg: { fromName: string; body: Message };\n};\nexport type ExitFrame = {\n $exit: { code: number; state: unknown };\n};\n\nexport function isProto(msg: Record<string, unknown>): msg is ProtoFrame {\n return \"$proto\" in msg;\n}\nexport function isInit(msg: Record<string, unknown>): msg is InitFrame {\n return \"$init\" in msg;\n}\nexport function isState(msg: Record<string, unknown>): msg is StateFrame {\n return \"$state\" in msg;\n}\nexport function isMsg(msg: Record<string, unknown>): msg is MsgFrame {\n return \"$msg\" in msg;\n}\nexport function isExit(msg: Record<string, unknown>): msg is ExitFrame {\n return \"$exit\" in msg;\n}\n\n// ── a wire that could not be read ─────────────────────────────────────────\n//\n// Two frames are about the wire itself and not about a process: what a codec could\n// not read, and what a side says when the wire is over. Neither is addressed to\n// anything, and both are decided before a frame is looked up as news or as an ask —\n// a frame about the wire is about the ground the other frames stand on.\n//\n// {\"$bad\": {\"reason\": \"…\", \"raw\": \"…\"}} this side could not read that frame\n// {\"$error\": \"…\"} the wire cannot be spoken over, and why\n//\n// They are frames rather than raised errors on purpose. A frame is read inside the\n// transport's own callback — a socket's `message` event, a stream's line reader —\n// where a throw belongs to nobody: it arrives at the host as an uncaught exception,\n// and one unreadable frame from one peer takes the process down, every other\n// connection in it included. An unreadable frame is the connection's business, not\n// the process's, so it is carried as a frame the connection can answer: `$bad` is how\n// a reader says it inward, and `$error` is how a side says it outward before ending\n// that connection.\n//\n// `$error` is not a refused call — a call that is refused says so about itself, in\n// `$r.result.<name>` (see below). This one is about the wire the calls travel on.\n\nconst BAD_KEY = \"$bad\";\n\n/** How much of an unreadable line is carried: enough to see what it was, never enough to be it.\n * A line that failed to parse is the one line nobody vouched for, so quoting it whole would move\n * whatever it holds — a credential in a paste accident is how that happens — into every log,\n * transcript and context window that later reads the frame. Why, how long, and a short head of\n * it. (`reason` carries a little of the line on its own: a JSON parser says where it gave up and\n * quotes what it was looking at. That is the parser's business, not a promise this file makes.) */\nexport const BAD_PREFIX_LIMIT = 32;\n\nexport type BadFrame = {\n $bad: { reason: string };\n};\n\nexport function isBad(msg: Record<string, unknown>): msg is BadFrame {\n return BAD_KEY in msg;\n}\n\n/** The frame that says a frame could not be read: why, how long it was, and the head of it. */\nexport function badFrame(reason: string, raw: string): Record<string, unknown> {\n const prefix = raw.length > BAD_PREFIX_LIMIT ? `${raw.slice(0, BAD_PREFIX_LIMIT)}…` : raw;\n return { [BAD_KEY]: { reason, length: raw.length, prefix } };\n}\n\n/** Why a frame could not be read, or null when it is not a frame that says so. */\nexport function badReason(msg: Record<string, unknown>): string | null {\n const body = msg[BAD_KEY];\n if (typeof body !== \"object\" || body === null) return null;\n const reason = (body as { reason?: unknown }).reason;\n return typeof reason === \"string\" ? reason : null;\n}\n\nconst ERROR_KEY = \"$error\";\n\nexport type ErrorFrame = {\n $error: string;\n};\n\nexport function isError(msg: Record<string, unknown>): msg is ErrorFrame {\n return ERROR_KEY in msg;\n}\n\n/** The frame that says the wire is over: the reason, and the connection ends with it. */\nexport function errorFrame(reason: string): Record<string, unknown> {\n return { [ERROR_KEY]: reason };\n}\n\n/** The reason a wire error carries, or null when it is not one. */\nexport function errorReason(msg: Record<string, unknown>): string | null {\n const reason = msg[ERROR_KEY];\n return typeof reason === \"string\" ? reason : null;\n}\n\n// A process that crossed can be asked for less than everything, or for nothing at\n// all: what crosses about it is three categories, and only the ones asked for are\n// sent. Silence is the empty list, so a handle that asks for nothing hears\n// nothing — not its state, not its messages, and not that it is gone.\n//\n// {\"$tune\": {\"streams\": [\"state\"]}, \"to\": 3} this much about it, and no more\n\nexport type StreamKind = \"message\" | \"state\" | \"exit\";\n\n/** The three, in the one order they are ever named in — the order a tune frame\n * carries them in, so two ways of asking for the same thing look the same. */\nexport const STREAM_KINDS: StreamKind[] = [\"message\", \"state\", \"exit\"];\n\nexport function isStreamKind(value: unknown): value is StreamKind {\n return typeof value === \"string\" && (STREAM_KINDS as string[]).includes(value);\n}\n\n// ── control frames ─────────────────────────────────────────────────────────\n//\n// What the holder of a handle can ask of a process on the far side, beside\n// sending it a message. Each is a frame of its own rather than a message, so\n// nothing an actor reads is ever a control signal by accident:\n//\n// {\"$stop\": {}, \"to\": 3} stop it; it ends, and its `$exit` crosses back\n// {\"$pause\": {}, \"to\": 3} stop feeding it messages\n// {\"$resume\": {}, \"to\": 3} feed it again\n// {\"$release\": {}, \"to\": 3} let it go: forget this id, and stop telling me\n// about the process behind it\n// {\"$tune\": {\"streams\": [...]}, \"to\": 3}\n// say this much about it and no more: a subset of\n// message, state and exit, or the empty list for\n// silence\n//\n// They address the process they are about, so they are answered by whoever holds\n// that process — the side that can act on it. Stopping the *root* of a connection\n// is not one of these: that stays the STOP message it always was, since the root\n// is not a handle but the process this side is talking through.\n\nexport type StopFrame = {\n $stop: Record<string, unknown>;\n};\nexport type PauseFrame = {\n $pause: Record<string, unknown>;\n};\nexport type ResumeFrame = {\n $resume: Record<string, unknown>;\n};\nexport type ReleaseFrame = {\n $release: Record<string, unknown>;\n};\nexport type TuneFrame = {\n $tune: Record<string, unknown>;\n};\n\nexport function isStop(msg: Record<string, unknown>): msg is StopFrame {\n return \"$stop\" in msg;\n}\nexport function isPause(msg: Record<string, unknown>): msg is PauseFrame {\n return \"$pause\" in msg;\n}\nexport function isResume(msg: Record<string, unknown>): msg is ResumeFrame {\n return \"$resume\" in msg;\n}\nexport function isRelease(msg: Record<string, unknown>): msg is ReleaseFrame {\n return \"$release\" in msg;\n}\nexport function isTune(msg: Record<string, unknown>): msg is TuneFrame {\n return \"$tune\" in msg;\n}\n\n/**\n * The categories a tune frame asks for, in the order they are named in — or null\n * when the frame says something this vocabulary has no word for, which is a frame\n * to ignore rather than to guess at.\n */\nexport function tuneFrame(frame: { $tune: unknown }): StreamKind[] | null {\n const body = frame.$tune;\n if (typeof body !== \"object\" || body === null) return null;\n const streams = (body as { streams?: unknown }).streams;\n if (!Array.isArray(streams)) return null;\n if (!streams.every(isStreamKind)) return null;\n return STREAM_KINDS.filter((kind) => (streams as StreamKind[]).includes(kind));\n}\n\n// ── reflection frames ──────────────────────────────────────────────────────\n//\n// A reflection call crosses the seam as one frame and its answer as another, and\n// both go both ways: whoever holds a process is the one that answers for it.\n//\n// {\"$r.methods\": [\"inspect.getTree\", …]} what a process can answer, once, when\n// it crosses (and, for the root, once\n// when the connection opens)\n// {\"$r.call.<name>\": {seq, args}} asking, addressed to the process\n// {\"$r.result.<name>\": {seq, value}} answered\n// {\"$r.result.<name>\": {seq, error}} refused\n//\n// The method name is in the frame key, so a frame says what it is without a\n// table, and `seq` — one connection's, never reused — tells two calls to the\n// same method apart while both are in flight. An answer is about the call and not\n// about a process, so it carries no address: it names the seq it settles.\n\nexport const REFLECT_METHODS = \"$r.methods\";\nexport const REFLECT_CALL = \"$r.call.\";\nexport const REFLECT_RESULT = \"$r.result.\";\n\nexport interface ReflectionCall {\n name: string;\n seq: number;\n args: unknown[];\n}\n\nexport interface ReflectionResult {\n name: string;\n seq: number;\n value?: unknown;\n error?: string;\n}\n\nexport type ReflectionMethodsFrame = {\n \"$r.methods\": string[];\n};\n\n/** A call frame: the method in the key, the call in the body (`$r.call.<name>`). */\nexport type ReflectionCallFrame = {\n [key: `$r.call.${string}`]: { seq: number; args?: unknown[] };\n};\n\n/** An answer frame: `value` or `error`, naming the seq it settles. */\nexport type ReflectionResultFrame = {\n [key: `$r.result.${string}`]: { seq: number; value?: unknown; error?: string };\n};\n\nexport function isReflectionMethods(msg: Record<string, unknown>): msg is ReflectionMethodsFrame {\n const names = msg[REFLECT_METHODS];\n return Array.isArray(names) && names.every((name) => typeof name === \"string\");\n}\n\nfunction reflectionBody(\n frame: Record<string, unknown>,\n prefix: string,\n): { name: string; body: Record<string, unknown> } | null {\n for (const key of Object.keys(frame)) {\n if (!key.startsWith(prefix) || key.length === prefix.length) continue;\n const body = frame[key];\n if (typeof body !== \"object\" || body === null) return null;\n return { name: key.slice(prefix.length), body: body as Record<string, unknown> };\n }\n return null;\n}\n\n/** A call frame, or null — a malformed one is not worth an answer. */\nexport function asReflectionCall(frame: Record<string, unknown>): ReflectionCall | null {\n const parsed = reflectionBody(frame, REFLECT_CALL);\n if (!parsed || typeof parsed.body.seq !== \"number\") return null;\n const args = parsed.body.args;\n return {\n name: parsed.name,\n seq: parsed.body.seq,\n args: Array.isArray(args) ? args : [],\n };\n}\n\n/** An answer frame, or null. `error` present means the call was refused. */\nexport function asReflectionResult(frame: Record<string, unknown>): ReflectionResult | null {\n const parsed = reflectionBody(frame, REFLECT_RESULT);\n if (!parsed || typeof parsed.body.seq !== \"number\") return null;\n const { seq, value, error } = parsed.body;\n return typeof error === \"string\"\n ? { name: parsed.name, seq, error }\n : { name: parsed.name, seq, value };\n}\n\n/**\n * Why a value cannot cross a frame, or null when it can. Only JSON data\n * crosses: a function, a symbol or a bigint cannot be written down at all, and\n * a value with a cycle or a bigint inside it makes the encoder throw. What\n * JSON itself would quietly drop — a function stored inside an object — is the\n * caller's business, not something to invent a policy for here.\n */\nexport function jsonProblem(value: unknown): string | null {\n const kind = typeof value;\n if (kind === \"function\" || kind === \"symbol\" || kind === \"bigint\") return `a ${kind}`;\n if (kind !== \"object\" || value === null) return null;\n try {\n JSON.stringify(value);\n } catch (err) {\n return err instanceof Error ? err.message : String(err);\n }\n return null;\n}\n\n// ── the frames, as one type ────────────────────────────────────────────────\n//\n// The guards above say what a frame is one at a time; this is the same set as one type.\n// Neither direction nor protocol is in it — who may send which is the two ends' business,\n// and the handshake names the protocol that writes them. The address a frame carries\n// (`to`, `frameTo`) is the envelope the connection writes around it, not the frame.\n\nexport type Frame =\n | ProtoFrame\n | InitFrame\n | StateFrame\n | MsgFrame\n | ExitFrame\n | BadFrame\n | ErrorFrame\n | StopFrame\n | PauseFrame\n | ResumeFrame\n | ReleaseFrame\n | TuneFrame\n | ReflectionMethodsFrame\n | ReflectionCallFrame\n | ReflectionResultFrame;\n","// ── json1 wire protocol ────────────────────────────────────────────────────\n//\n// One JSON object per frame: `{\"$key\": value}`. encode/decode turn a decoded\n// frame object into a string and back. json1Channel wraps a StringTransport so\n// it moves frame objects instead of strings.\n//\n// This is the boundary where the wire's bytes become a frame, and it is the one\n// place a bad peer can throw into a callback that belongs to nobody but the host:\n// the handler runs where the transport called it — a socket's `message` event, a\n// line reader — so a `SyntaxError` here is an uncaught exception and takes the\n// process down. So a line that will not parse is not thrown at the caller: it\n// becomes the frame that says so (`$bad`, channel.ts) and travels inward like any\n// other, where the connection it came from can answer for it.\n//\n// One frame is one JSON *object*: a line that parses to a number, a string, an\n// array or `null` is not a frame either, and reading one as a frame (`\"$init\" in 7`)\n// throws just as surely as a line that never parsed.\n\nimport { badFrame, type Channel, type StringTransport } from \"../channel.js\";\n\nexport const VERSION = \"json.v1\";\n\n/** The frames this protocol carries. The shapes and the union are in channel.ts; a protocol\n * owns that the connection speaks them, and how they are written down. */\nexport type { Frame } from \"../channel.js\";\n\nexport function encode(frame: Record<string, unknown>): string {\n return JSON.stringify(frame);\n}\n\n/** The frame a line carries, throwing on a line that is not JSON. `readFrame` is how the\n * seam reads a line; this is the primitive underneath it. */\nexport function decode(str: string): Record<string, unknown> {\n return JSON.parse(str);\n}\n\n/** A line read as a frame: the frame itself, or the frame that says this one could not be\n * read. Never throws — see the note at the top of this file. */\nexport function readFrame(str: string): Record<string, unknown> {\n let parsed: unknown;\n try {\n parsed = decode(str);\n } catch (err) {\n return badFrame(err instanceof Error ? err.message : String(err), str);\n }\n if (typeof parsed !== \"object\" || parsed === null || Array.isArray(parsed)) {\n return badFrame(`a frame is one JSON object, and this was ${kindOf(parsed)}`, str);\n }\n return parsed as Record<string, unknown>;\n}\n\nfunction kindOf(value: unknown): string {\n if (value === null) return \"null\";\n if (Array.isArray(value)) return \"an array\";\n return `a ${typeof value}`;\n}\n\n/**\n * The octets a frame announces after it, or null when it announces none.\n *\n * One shape only: a chunk head carries the number of raw octets that follow, and that number\n * is what keeps the reader's framing. A head without one is not a segment — it goes on as a\n * frame, and whoever reads it refuses it by name.\n */\nexport function announcedOctets(frame: Record<string, unknown>): number | null {\n const head = frame.$chunk;\n if (typeof head !== \"object\" || head === null) return null;\n const bytes = (head as { bytes?: unknown }).bytes;\n return typeof bytes === \"number\" && Number.isInteger(bytes) && bytes >= 0 ? bytes : null;\n}\n\nexport function json1Channel(transport: StringTransport): Channel {\n const frameReaders = new Set<(frame: Record<string, unknown>) => void>();\n const segmentReaders = new Set<(frame: Record<string, unknown>, bytes: Uint8Array) => void>();\n const closeReaders = new Set<() => void>();\n /** The wire goes once, whoever ends it: the peer hanging up, or this side closing it. */\n let closed = false;\n const sayClosed = (): void => {\n if (closed) return;\n closed = true;\n for (const reader of [...closeReaders]) reader();\n };\n /** The head whose octets are on their way: set between the line and the run it announced. */\n let expecting: Record<string, unknown> | null = null;\n\n const deliver = (frame: Record<string, unknown>): void => {\n // Over a copy: a reader that leaves as it is handed a frame must not cut the rest short.\n for (const reader of [...frameReaders]) reader(frame);\n };\n\n // Both handlers go on at once: the octets have to be read even when nobody is listening for\n // them, or the next line starts in the wrong place and the connection is lost.\n transport.onMessage((str) => {\n const frame = readFrame(str);\n const octets = announcedOctets(frame);\n if (octets === null) {\n deliver(frame);\n return;\n }\n expecting = frame;\n return octets;\n });\n transport.onBytes((bytes) => {\n const frame = expecting;\n expecting = null;\n // Octets nobody announced are a peer talking past the protocol: they are said out loud\n // rather than attached to whatever frame happened to arrive last.\n if (frame === null) {\n deliver(badFrame(`${bytes.length} octets arrived that no frame announced`, \"\"));\n return;\n }\n for (const reader of [...segmentReaders]) reader(frame, bytes);\n });\n transport.onClose(sayClosed);\n\n return {\n send(frame) {\n return transport.send(encode(frame));\n },\n onMessage(handler) {\n frameReaders.add(handler);\n return () => {\n frameReaders.delete(handler);\n };\n },\n async sendSegment(frame, bytes) {\n // The line first, then its octets, each written before the next is asked for: a chunk\n // that was queued behind a megabyte of earlier chunks is a chunk the writer ran ahead of\n // its reader with.\n await transport.send(encode(frame));\n await transport.sendBytes(bytes);\n },\n onSegment(handler) {\n segmentReaders.add(handler);\n return () => {\n segmentReaders.delete(handler);\n };\n },\n onClose(handler) {\n closeReaders.add(handler);\n },\n async close() {\n // Closing here is news to everyone above as well: a spawner ends the wire when its child dies,\n // and a client that was not told would wait for a peer that is already gone.\n sayClosed();\n await transport.close();\n },\n };\n}\n","// ── streams on the wire ────────────────────────────────────────────────────\n//\n// A stream is bytes arriving over time. A blob has to be whole before anybody can look at it,\n// so the reader waits for all of it, the writer has nothing to slow it down, and a file bigger\n// than memory cannot cross at all. A stream is what a file already is on a connection: asked\n// for at the rate the reader can take it.\n//\n// What the octets mean is not the announcement's business. The value that references them says\n// what they are and carries the facts about them: a stream has none, a typed array has its\n// length, a blob has its size, type and name.\n//\n// {\"$stream\": {\"id\": 7}} announced first: octets are coming\n// {\"$msg\": {\"fromName\": \"a\", \"body\": {\"feed\": {\"$s\": {\"id\": 7}}}}} a stream\n// {\"$msg\": {\"fromName\": \"a\", \"body\": {\"data\": {\"$bytes\": {\"id\": 7, \"size\": 4}}}}} a typed array\n// {\"$msg\": {\"fromName\": \"a\", \"body\": {\"shot\": {\"$blob\": {\"id\": 7, \"size\": 4, \"type\": \"image/png\", \"name\": \"a.png\"}}}}}\n// {\"$streamAsk\": {\"id\": 7, \"credit\": 262144}} the reader's demand, in bytes\n// {\"$chunk\": {\"id\": 7, \"seq\": 1, \"bytes\": 65536}} a chunk: its head…\n// <65536 raw octets> …its bytes…\n// {\"$chunkEnd\": {\"id\": 7, \"seq\": 1, \"crc32\": 2663770700}} …and the checksum, after them\n// {\"$streamDone\": {\"id\": 7}} or {\"$streamFail\": {…, \"reason\": …}}\n// {\"$streamCancel\": {\"id\": 7}} a reader that stops early\n//\n// The announcement goes out before the frame that references it, so a reader never receives a\n// reference to something it has not been told about. The head's `bytes` is what keeps the\n// framing: a reader that does not know the stream still skips exactly that many octets, and a\n// head whose length is a lie is the one thing that costs the connection rather than the stream.\n//\n// Credit is the flow control, counted in bytes: the reader grants a window and the writer sends\n// whole chunks until it is spent. Nothing is written ahead of demand, so a slow consumer slows\n// the writer instead of filling a buffer somewhere. The one eager case is a typed array: the\n// reference arriving is the demand, so the reader asks at once and puts the array back together\n// as the chunks land.\n\nimport { isPlainObject, isStreamLike, type Channel, type ValueCodec } from \"./channel.js\";\n\nexport { isStreamLike };\nimport { IdSpace, type IdParity } from \"./process-ref.js\";\n\n/** The chunk size, which bounds one segment. */\nexport const DEFAULT_CHUNK_BYTES = 64 * 1024;\n\n/** How far ahead of the consumer a writer may run: the credit window, in bytes. */\nexport const DEFAULT_WINDOW_BYTES = 4 * DEFAULT_CHUNK_BYTES;\n\n/** The largest stream this side will take: a reader that will not read a 5 GB file should say so\n * before the first chunk, not after the last. */\nexport const DEFAULT_MAX_BYTES = 64 * 1024 * 1024;\n\n/** What a blob knows about itself: the facts ride the reference, not the stream behind it. */\nexport interface BlobFacts {\n /** Bytes in total. A blob is whole by definition, so this is always known. */\n readonly size: number;\n /** The media type, when the sender knows it. */\n readonly type?: string;\n /** A name for a file, when one had it. */\n readonly name?: string;\n}\n\n/** What the far side made of an announcement: the stream itself, a blob over it, or an array. */\ntype ValueForm = \"stream\" | \"blob\" | \"bytes\";\n\n/** A stream of octets: what the library takes at one end of a connection and gives at the other.\n * It says nothing about what the octets are — that belongs to the value that references it. */\nexport type Stream = AsyncIterable<Uint8Array>;\n\n/** What a message carries in place of a stream: an id, or the name the far side announced it under. */\nexport interface StreamRef {\n $s: { id: number } | { name: string };\n}\n\nexport function isStreamRef(value: unknown): value is StreamRef {\n const body = (value as { $s?: { id?: unknown; name?: unknown } } | null)?.$s;\n return typeof body?.id === \"number\" || typeof body?.name === \"string\";\n}\n\n/** The element kinds that keep their identity on the wire. A `DataView` and an `ArrayBuffer` have no\n * element kind to keep, so they cross as octets and arrive as a `Uint8Array`. */\nexport type TypedArrayName =\n | \"Int8Array\"\n | \"Uint8Array\"\n | \"Uint8ClampedArray\"\n | \"Int16Array\"\n | \"Uint16Array\"\n | \"Int32Array\"\n | \"Uint32Array\"\n | \"Float32Array\"\n | \"Float64Array\"\n | \"BigInt64Array\"\n | \"BigUint64Array\";\n\n/** A typed array as it arrived: the sender's own kind, whole. */\nexport type RemoteArray =\n | Int8Array\n | Uint8Array\n | Uint8ClampedArray\n | Int16Array\n | Uint16Array\n | Int32Array\n | Uint32Array\n | Float32Array\n | Float64Array\n | BigInt64Array\n | BigUint64Array;\n\n/** What a typed array's reference says about it: its octets, its element kind and its element count. */\nexport interface BytesFacts {\n readonly size: number;\n readonly type?: TypedArrayName;\n readonly length?: number;\n}\n\n/** What a message carries in place of a typed array: where its octets are, and what they add up to. */\nexport interface BytesRef {\n $bytes: { id: number } & BytesFacts;\n}\n\nexport function isBytesRef(value: unknown): value is BytesRef {\n const body = (value as { $bytes?: { id?: unknown; size?: unknown } } | null)?.$bytes;\n return typeof body?.id === \"number\" && typeof body?.size === \"number\";\n}\n\n/** What a message carries in place of a blob: its octets and the facts about them. */\nexport interface BlobRef {\n $blob: { id: number } & BlobFacts;\n}\n\nexport function isBlobRef(value: unknown): value is BlobRef {\n const body = (value as { $blob?: { id?: unknown; size?: unknown } } | null)?.$blob;\n return typeof body?.id === \"number\" && typeof body?.size === \"number\";\n}\n\n/** What may be offered in place of a whole file: sized, and read on demand. A platform `Blob` or\n * `File` is one as it stands, and so is a `RemoteBlob` that arrived from a connection — which is how\n * a file that was received can be passed on without being read here. */\nexport interface BlobSource {\n readonly size: number;\n readonly type?: string;\n readonly name?: string;\n /** A window of the bytes, when the value can give one without reading the rest. */\n readonly slice?: (start?: number, end?: number) => BlobSource;\n readonly arrayBuffer: () => Promise<ArrayBuffer>;\n /** The bytes over time, for a value that cannot be sliced. */\n readonly stream?: () => AsyncIterable<Uint8Array>;\n}\n\nexport function isBlob(value: unknown): value is BlobSource {\n if (typeof value !== \"object\" || value === null) return false;\n const candidate = value as { size?: unknown; arrayBuffer?: unknown; slice?: unknown; stream?: unknown };\n if (typeof candidate.size !== \"number\") return false;\n if (typeof candidate.arrayBuffer !== \"function\") return false;\n return typeof candidate.slice === \"function\" || typeof candidate.stream === \"function\";\n}\n\n/** What a message carries in place of a blob: the same value, read off the connection. */\nexport interface Blob {\n readonly size?: number;\n readonly type?: string;\n readonly name?: string;\n /** Read it once: the bytes are on the wire, not here. */\n stream(): Stream;\n arrayBuffer(): Promise<ArrayBuffer>;\n}\n\n/** Every octet of a stream, in one array. */\nexport async function bytesOf(stream: AsyncIterable<Uint8Array>): Promise<Uint8Array> {\n const parts: Uint8Array[] = [];\n let total = 0;\n for await (const part of stream) {\n parts.push(part);\n total += part.length;\n }\n const all = new Uint8Array(total);\n let at = 0;\n for (const part of parts) {\n all.set(part, at);\n at += part.length;\n }\n return all;\n}\n\n\n// ── the checksum ───────────────────────────────────────────────────────────\n//\n// CRC-32, because it is the one the runtime already has: `Bun.hash.crc32` costs 0.1 ms for a\n// 64 KiB chunk here and a table written in TypeScript costs 65 ms on a box without a JIT. The\n// numbers are in docs/proposals/streams.md; the polynomial is the same everywhere, so either\n// side verifies the other's.\n\ntype Crc = (bytes: Uint8Array) => number;\n\nlet pvtCrc: Crc | null = null;\n\nfunction crcOf(): Crc {\n if (pvtCrc !== null) return pvtCrc;\n const bun = (globalThis as { Bun?: { hash?: { crc32?: (data: Uint8Array) => number } } }).Bun;\n if (typeof bun?.hash?.crc32 === \"function\") {\n const native = bun.hash.crc32;\n pvtCrc = (bytes) => native(bytes) >>> 0;\n return pvtCrc;\n }\n // Node 22 has it on `zlib`, reachable without importing anything the browser cannot parse.\n const builtin = (globalThis as { process?: { getBuiltinModule?: (name: string) => unknown } }).process\n ?.getBuiltinModule?.(\"node:zlib\") as { crc32?: (data: Uint8Array) => number } | undefined;\n if (typeof builtin?.crc32 === \"function\") {\n const native = builtin.crc32;\n pvtCrc = (bytes) => native(bytes) >>> 0;\n return pvtCrc;\n }\n pvtCrc = tableCrc;\n return pvtCrc;\n}\n\n/** CRC-32 by hand, for a runtime that has none. Correct, and slow where nothing is a JIT. */\nfunction tableCrc(bytes: Uint8Array): number {\n let crc = 0xffff_ffff;\n for (const byte of bytes) {\n crc = (crc >>> 8) ^ pvtTable[(crc ^ byte) & 0xff]!;\n }\n return (crc ^ 0xffff_ffff) >>> 0;\n}\n\nconst pvtTable: number[] = (() => {\n const table: number[] = [];\n for (let i = 0; i < 256; i += 1) {\n let value = i;\n for (let bit = 0; bit < 8; bit += 1) value = value & 1 ? 0xed_b8_83_20 ^ (value >>> 1) : value >>> 1;\n table.push(value >>> 0);\n }\n return table;\n})();\n\n/** The checksum a chunk's tail carries. */\nexport function crc32(bytes: Uint8Array): number {\n return crcOf()(bytes);\n}\n\n// ── the reader's side ──────────────────────────────────────────────────────\n\n/** What a stream on this side costs and asks for, without knowing the connection. */\ninterface ReaderHooks {\n /** Octets taken by the consumer: credit spent, and the writer may be asked for more. */\n consumed(bytes: number): void;\n /** The consumer will take no more. */\n cancelled(reason: string): void;\n /** The consumer is waiting for octets: what the far side may now be asked for. */\n wanted(): void;\n}\n\n/**\n * Bytes the far side offers, read at the consumer's pace.\n *\n * An async iterable of octets, and nothing more: turning it into an array, a `Blob` or a digest\n * is the platform's job — `new Response(stream).arrayBuffer()` where there is a `Response`,\n * `for await` where there is not.\n */\nexport class RemoteStream implements Stream {\n private readonly queue: Uint8Array[] = [];\n private readonly waiting: Array<{ resolve: (r: IteratorResult<Uint8Array>) => void; reject: (e: Error) => void }> =\n [];\n private ended = false;\n private failure: Error | null = null;\n private stopped = false;\n private platform: ReadableStream<Uint8Array> | null = null;\n\n constructor(private readonly hooks: ReaderHooks) {}\n\n /** The far side sent more of it. */\n push(bytes: Uint8Array): void {\n if (this.ended || this.failure || this.stopped) return;\n const waiting = this.waiting.shift();\n if (!waiting) {\n this.queue.push(bytes);\n return;\n }\n this.hooks.consumed(bytes.length);\n waiting.resolve({ value: bytes, done: false });\n }\n\n /** The far side has sent all of it. */\n end(): void {\n if (this.ended || this.failure) return;\n this.ended = true;\n for (const waiting of this.waiting.splice(0)) waiting.resolve({ value: undefined, done: true });\n }\n\n /** The far side gave up on it, or it arrived corrupt. */\n fail(reason: string): void {\n if (this.ended || this.failure) return;\n this.failure = new Error(reason);\n for (const waiting of this.waiting.splice(0)) waiting.reject(this.failure);\n }\n\n /** Take no more of it. Said to the far side, so it stops reading its source. */\n cancel(reason = \"the reader stopped\"): void {\n if (this.stopped || this.ended) return;\n this.stopped = true;\n this.queue.length = 0;\n for (const waiting of this.waiting.splice(0)) waiting.resolve({ value: undefined, done: true });\n this.hooks.cancelled(reason);\n }\n\n async next(): Promise<IteratorResult<Uint8Array>> {\n const queued = this.queue.shift();\n if (queued) {\n this.hooks.consumed(queued.length);\n return { value: queued, done: false };\n }\n if (this.failure) throw this.failure;\n if (this.ended || this.stopped) return { value: undefined, done: true };\n // Nothing flows until somebody waits for it: a blob nobody opens is not read at all.\n this.hooks.wanted();\n return new Promise<IteratorResult<Uint8Array>>((resolve, reject) => {\n this.waiting.push({ resolve, reject });\n });\n }\n\n async return(): Promise<IteratorResult<Uint8Array>> {\n this.cancel();\n return { value: undefined, done: true };\n }\n\n /**\n * The runtime's own stream, built over this one the first time something asks for it. What a\n * sender usually hands over is a `ReadableStream`, so what arrives offers the same interface —\n * `getReader()`, `pipeTo()`, `tee()` — rather than a narrower shape of its own. A runtime\n * without `ReadableStream` keeps the iterable, which is the library's own interface.\n */\n asReadableStream(): ReadableStream<Uint8Array> {\n const ctor = globalThis.ReadableStream;\n if (typeof ctor !== \"function\") throw new Error(\"this runtime has no ReadableStream: read the stream with `for await`\");\n this.platform ??= new ctor({\n pull: async (controller) => {\n const next = await this.next();\n if (next.done) controller.close();\n else controller.enqueue(next.value);\n },\n cancel: (reason: unknown) => {\n this.cancel(typeof reason === \"string\" ? reason : \"the reader stopped\");\n },\n });\n return this.platform;\n }\n\n getReader(): ReadableStreamDefaultReader<Uint8Array> {\n return this.asReadableStream().getReader();\n }\n\n pipeTo(destination: WritableStream<Uint8Array>, options?: StreamPipeOptions): Promise<void> {\n return this.asReadableStream().pipeTo(destination, options);\n }\n\n tee(): [ReadableStream<Uint8Array>, ReadableStream<Uint8Array>] {\n return this.asReadableStream().tee();\n }\n\n /** One consumer, whichever door it comes through: where the runtime has a platform stream this\n * path goes through it, so the lock and the queue are the platform's and not two of ours. */\n async *[Symbol.asyncIterator](): AsyncIterator<Uint8Array> {\n if (typeof globalThis.ReadableStream !== \"function\") {\n for (;;) {\n const next = await this.next();\n if (next.done) return;\n yield next.value;\n }\n }\n const reader = this.asReadableStream().getReader();\n let finished = false;\n try {\n for (;;) {\n const next = await reader.read();\n if (next.done) {\n finished = true;\n return;\n }\n yield next.value;\n }\n } finally {\n reader.releaseLock();\n // A reader that walks away is a reader that takes no more: the far side is told to stop.\n if (!finished) this.cancel();\n }\n }\n}\n\n/**\n * A blob that came over a connection: the same value the far side offered, with its bytes still\n * over there. Reading it is what asks for them — and only at the pace the reader takes them, so a\n * file nobody opens costs nothing on the wire.\n */\nexport class RemoteBlob implements Blob {\n private readonly body: RemoteStream;\n\n constructor(\n body: RemoteStream,\n readonly facts: BlobFacts,\n ) {\n this.body = body;\n }\n\n get size(): number {\n return this.facts.size;\n }\n\n get type(): string | undefined {\n return this.facts.type;\n }\n\n get name(): string | undefined {\n return this.facts.name;\n }\n\n stream(): Stream {\n return this.body;\n }\n\n async arrayBuffer(): Promise<ArrayBuffer> {\n const all = await bytesOf(this.body);\n return all.buffer as ArrayBuffer;\n }\n}\n\n// ── the store ──────────────────────────────────────────────────────────────\n\n/** What this side is sending: the source, the credit it has been given, and what is left of a chunk. */\ninterface Offered {\n id: number;\n source: AsyncIterator<Uint8Array>;\n /** The rest of a piece the source gave us, not yet cut into chunks. */\n pending: Uint8Array | null;\n /** Octets the reader has asked for and not been sent. */\n credit: number;\n seq: number;\n pumping: boolean;\n dropped: boolean;\n}\n\n/** What this side is reading. */\ninterface Incoming {\n id: number;\n reader: RemoteStream;\n /** What the far side made of it: a stream until a reference says otherwise. */\n form: ValueForm;\n /** The value a reference asked for, built once: a stream, a blob over it, or the array itself. */\n value?: RemoteStream | RemoteBlob | RemoteArray;\n /** Octets asked for, and octets the consumer has taken: what may still be in flight. */\n asked: number;\n consumed: number;\n /** Octets that have arrived, for a value whose size this side was never told. */\n received: number;\n /** The chunk whose head and bytes have arrived, waiting for its tail. */\n chunk: { seq: number; bytes: Uint8Array } | null;\n done: boolean;\n}\n\nexport interface StreamStoreOptions {\n chunkBytes?: number;\n windowBytes?: number;\n maxBytes?: number;\n /** Where stream ids come from. One space per side, shared with the process table so a number\n * names one thing on the connection whatever it names. */\n ids?: IdSpace;\n /** Whether the store reads the connection itself. A party that carries a connection it does not\n * speak — a first stage — sets this false and hands frames in with `handle()`, so the far side's\n * frames are never mistaken for its own. */\n attach?: boolean;\n}\n\n/**\n * One connection's streams, as this side sees them.\n *\n * Both directions are in one table, because both are the same numbering: what this side offers\n * (and answers asks for) and what it may read from the far side. Ids follow the process table's\n * parity, so an id names one stream on one connection and nothing anywhere else.\n */\nexport class StreamStore implements ValueCodec {\n private readonly channel: Channel;\n private readonly chunkBytes: number;\n private readonly windowBytes: number;\n readonly maxBytes: number;\n private readonly pvtOffers = new Map<number, Offered>();\n private readonly pvtIncoming = new Map<number, Incoming>();\n private readonly ids: IdSpace;\n /** Why streams that are over failed, for a reference that arrives after the fact. */\n private readonly pvtRefused = new Map<number, { reason: string; form: ValueForm }>();\n /** What this side announced under a name, and what the far side did. A name is taken while it is\n * in either map, so the two directions never answer to one name at once. */\n private readonly pvtNamesOut = new Map<string, number>();\n private readonly pvtNamesIn = new Map<string, number>();\n /** The arrays a value that was just decoded is still waiting for: a message is handed on after them. */\n private pvtPending: Promise<void>[] = [];\n /** Told about every named stream the far side announces: the live ones replay, then each arrival. */\n private readonly pvtNamedListeners = new Set<(name: string, stream: RemoteStream) => void>();\n private readonly pvtOff: () => void;\n private readonly pvtSegmentOff: (() => void) | null = null;\n private pvtClosed = false;\n\n constructor(channel: Channel, parity: IdParity, options: StreamStoreOptions = {}) {\n this.channel = channel;\n this.chunkBytes = options.chunkBytes ?? DEFAULT_CHUNK_BYTES;\n this.windowBytes = options.windowBytes ?? DEFAULT_WINDOW_BYTES;\n this.maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES;\n this.ids = options.ids ?? new IdSpace(parity);\n const attached = options.attach !== false;\n this.pvtOff = attached\n ? channel.onMessage((frame) => {\n this.onFrame(frame);\n })\n : () => {};\n this.pvtSegmentOff = attached ? (channel.onSegment?.((head, bytes) => this.onSegment(head, bytes)) ?? null) : null;\n }\n\n /** Whether this connection can carry a stream at all: it must carry octets beside its lines. */\n get canCarryStreams(): boolean {\n return this.pvtSegmentOff !== null && this.channel.sendSegment !== undefined;\n }\n\n /**\n * Offer a stream to the connection: the announcement goes out now, and the bytes when the far\n * side asks for them. What comes back is what a message carries in their place.\n *\n * A `name` makes the stream findable: the far side can reference it by that name instead of the\n * id, and ask for it with `named()` without waiting for a message to carry a reference.\n */\n offer(stream: Stream, name?: string): StreamRef {\n return { $s: { id: this.pvtAnnounce(stream[Symbol.asyncIterator](), name) } };\n }\n\n /**\n * Offer a blob — a whole file, read on demand. It crosses as a stream over its bytes and arrives\n * on the far side as a `RemoteBlob`, so nothing of it is read until somebody wants the bytes.\n */\n offerBlob(blob: BlobSource): BlobRef {\n const { size, type, name } = blob;\n const id = this.pvtAnnounce(this.pvtBlobChunks(blob));\n return { $blob: { id, size, ...(type === undefined ? {} : { type }), ...(name === undefined ? {} : { name }) } };\n }\n\n /**\n * Offer bytes this side already holds. The reference states the length, so the far side can check\n * it against its bound and make room before the first chunk arrives — and, when the value is a typed\n * array, the element kind and count too, so the same kind of array is made on the other side. The\n * octets are one piece, and the wire carries them as a stream of one.\n */\n offerBytes(value: ArrayBuffer | ArrayBufferView): BytesRef {\n const { bytes, type, length } = octetsOf(value);\n return {\n $bytes: {\n id: this.pvtAnnounce(this.pvtOnePiece(bytes)),\n size: bytes.length,\n ...(type === undefined ? {} : { type }),\n ...(length === undefined ? {} : { length }),\n },\n };\n }\n\n private pvtAnnounce(source: AsyncIterator<Uint8Array>, name?: string): number {\n const id = this.ids.next();\n this.pvtOffers.set(id, { id, source, pending: null, credit: 0, seq: 0, pumping: false, dropped: false });\n if (name !== undefined) this.pvtNamesOut.set(name, id);\n void this.channel.send(name === undefined ? { $stream: { id } } : { $stream: { id, name } });\n return id;\n }\n\n private async *pvtOnePiece(bytes: Uint8Array): AsyncGenerator<Uint8Array> {\n if (bytes.length > 0) yield bytes;\n }\n\n /** A blob's octets, a window at a time: sliced where the value can, streamed where it cannot. */\n private async *pvtBlobChunks(blob: BlobSource): AsyncGenerator<Uint8Array> {\n const slice = blob.slice;\n if (slice) {\n for (let at = 0; at < blob.size; at += this.chunkBytes) {\n const end = Math.min(at + this.chunkBytes, blob.size);\n yield new Uint8Array(await slice.call(blob, at, end).arrayBuffer());\n }\n return;\n }\n const stream = blob.stream;\n if (!stream) throw new TypeError(\"a blob must offer a slice or a stream\");\n yield* stream.call(blob);\n }\n\n /** A value on its way out: every stream in it becomes an announcement and a reference. */\n encode(value: unknown): unknown {\n return this.pvtEncode(value, new Set());\n }\n\n /** A value just read: every reference in it becomes something this side can read. */\n decode(value: unknown): unknown {\n this.pvtPending = [];\n return this.pvtDecode(value, new Set());\n }\n\n /**\n * What the octets of a just-decoded value still owe. A message is handed to its process only once\n * this has settled, so a typed array in a body is whole when the handler reads it; a stream, a blob\n * and a plain value carry no octets of their own and settle at once.\n */\n owed(): Promise<void> | null {\n if (this.pvtPending.length === 0) return null;\n return Promise.all(this.pvtPending).then(() => undefined);\n }\n\n /** The same question as a promise, for a caller that would rather always await. */\n settled(): Promise<void> {\n return this.owed() ?? Promise.resolve();\n }\n\n /** Drop every stream of this connection, in both directions. Called when it ends. */\n close(): void {\n if (this.pvtClosed) return;\n this.pvtClosed = true;\n this.pvtOff();\n this.pvtSegmentOff?.();\n for (const offered of this.pvtOffers.values()) {\n offered.dropped = true;\n // A reader still waiting is told the stream is over rather than left on a connection that is\n // about to end: the frames may still go out, and a send that cannot is nobody's to hear.\n void Promise.resolve(this.channel.send({ $streamDone: { id: offered.id } })).catch(() => {});\n void offered.source.return?.();\n }\n this.pvtOffers.clear();\n for (const incoming of this.pvtIncoming.values()) incoming.reader.fail(\"the connection ended\");\n this.pvtIncoming.clear();\n }\n\n /** The ids this side is holding, in the order they were offered. */\n held(): number[] {\n return [...this.pvtOffers.keys()];\n }\n\n /**\n * Take a frame if it is one this store answers for, and say whether it did. A party that carries a\n * connection it does not speak — a first stage, relaying a client to a payload — has to know which\n * inbound frames are its own and which belong to the far side, and this is the question it asks.\n * Only frames about a stream this side offered are claimed, so a stream the far side offers passes\n * through untouched.\n */\n handle(frame: Record<string, unknown>): boolean {\n if (this.pvtClosed) return false;\n const id = frameId(frame);\n if (id === null || !this.pvtOffers.has(id)) return false;\n this.onFrame(frame);\n return true;\n }\n\n /**\n * The stream the far side announced under `name`, if it is still live — the way a caller finds a\n * stream nobody sent it a reference to. A name that was never announced answers `undefined`, and a\n * name whose stream is over does too: the sentence lives on the value the reference would give.\n */\n named(name: string): RemoteStream | undefined {\n const id = this.pvtNamesIn.get(name);\n if (id === undefined) return undefined;\n return this.pvtValueFor(id, \"stream\") as RemoteStream;\n }\n\n /**\n * Every named stream the far side announces, now and later. The listener is called for the names\n * already live when it is installed and for each new one as it arrives, so a caller that wires a\n * sink to `stdout` does not have to know whether the far side has printed yet.\n */\n onNamed(listener: (name: string, stream: RemoteStream) => void): () => void {\n this.pvtNamedListeners.add(listener);\n for (const [name, id] of this.pvtNamesIn) {\n if (this.pvtIncoming.has(id)) listener(name, this.pvtValueFor(id, \"stream\") as RemoteStream);\n }\n return () => {\n this.pvtNamedListeners.delete(listener);\n };\n }\n\n // ── writing ────────────────────────────────────────────────────────────\n\n private pvtSend(frame: Record<string, unknown>): Promise<void> {\n return Promise.resolve(this.channel.send(frame));\n }\n\n private pvtEncode(value: unknown, seen: Set<unknown>): unknown {\n if (typeof value !== \"object\" || value === null) return value;\n // Offering reads the source's own facts (`size`, `type`, `name`), so it is asked before the\n // walk decides the value is a plain object to copy.\n // A blob is offered before a stream is looked for: it is a value with bytes behind it, not the\n // iterator itself, and the far side is given a blob back.\n if (isBlob(value)) return this.offerBlob(value);\n if (isStreamLike(value)) return this.offer(value);\n if (seen.has(value)) return value;\n seen.add(value);\n if (Array.isArray(value)) return value.map((item) => this.pvtEncode(item, seen));\n if (ArrayBuffer.isView(value) || value instanceof ArrayBuffer) return this.offerBytes(value);\n // Only a plain object is walked into: a handle, a logger, anything with its own prototype is\n // the application's and is left as it is. Copying one would take its methods away.\n if (!isPlainObject(value)) return value;\n const copy: Record<string, unknown> = {};\n for (const [key, item] of Object.entries(value)) copy[key] = this.pvtEncode(item, seen);\n return copy;\n }\n\n private pvtTake(offered: Offered): Uint8Array | null {\n if (offered.pending === null) return null;\n const size = Math.min(offered.pending.length, this.chunkBytes, offered.credit);\n const piece = offered.pending.subarray(0, size);\n offered.pending = size === offered.pending.length ? null : offered.pending.subarray(size);\n return piece;\n }\n\n private async pvtPull(offered: Offered): Promise<boolean> {\n const next = await offered.source.next();\n if (next.done) return false;\n const value: unknown = next.value;\n const bytes =\n value instanceof Uint8Array\n ? value\n : ArrayBuffer.isView(value)\n ? new Uint8Array(value.buffer, value.byteOffset, value.byteLength)\n : value instanceof ArrayBuffer\n ? new Uint8Array(value)\n : null;\n if (bytes === null) throw new TypeError(\"a stream may only yield octets\");\n if (bytes.length === 0) return true;\n offered.pending = bytes;\n return true;\n }\n\n private async pvtPump(offered: Offered): Promise<void> {\n if (offered.pumping || offered.dropped || this.pvtClosed) return;\n offered.pumping = true;\n try {\n while (!offered.dropped && offered.credit > 0) {\n if (offered.pending === null && !(await this.pvtPull(offered))) {\n await this.channel.send({ $streamDone: { id: offered.id } });\n this.pvtDrop(offered);\n return;\n }\n const piece = this.pvtTake(offered);\n if (piece === null) continue;\n const seq = offered.seq;\n offered.seq += 1;\n offered.credit -= piece.length;\n await this.channel.sendSegment?.({ $chunk: { id: offered.id, seq, bytes: piece.length } }, piece);\n await this.channel.send({ $chunkEnd: { id: offered.id, seq, crc32: crc32(piece) } });\n }\n } catch (error) {\n await this.pvtSend({ $streamFail: { id: offered.id, reason: reasonOf(error) } }).catch(() => {});\n this.pvtDrop(offered);\n } finally {\n offered.pumping = false;\n }\n }\n\n private pvtDrop(offered: Offered): void {\n if (offered.dropped) return;\n offered.dropped = true;\n this.pvtOffers.delete(offered.id);\n this.pvtRelease(offered.id);\n }\n\n /**\n * Take a stream out of the live table and remember why it ended, for a reference that arrives\n * after the fact: \"no stream was announced\" is the wrong sentence for a stream that was refused.\n */\n private pvtRetire(id: number, reason: string, form: ValueForm = \"stream\"): void {\n this.pvtIncoming.delete(id);\n this.pvtRelease(id);\n this.pvtRefused.set(id, { reason, form });\n // A connection lives a long time and a refusal is rare; past a bound the oldest reason goes.\n if (this.pvtRefused.size > 64) {\n const oldest = this.pvtRefused.keys().next();\n if (!oldest.done) this.pvtRefused.delete(oldest.value);\n }\n }\n\n /** A stream that is over gives its name back, so the next announcement of it is not a duplicate. */\n private pvtRelease(id: number): void {\n for (const [name, bound] of this.pvtNamesIn) if (bound === id) this.pvtNamesIn.delete(name);\n for (const [name, bound] of this.pvtNamesOut) if (bound === id) this.pvtNamesOut.delete(name);\n }\n\n // ── reading ────────────────────────────────────────────────────────────\n\n private pvtDecode(value: unknown, seen: Set<unknown>): unknown {\n if (typeof value !== \"object\" || value === null) return value;\n if (isBytesRef(value)) return this.pvtValueFor(value.$bytes.id, \"bytes\", value.$bytes);\n if (isBlobRef(value)) {\n const { id, size, type, name } = value.$blob;\n return this.pvtValueFor(id, \"blob\", { size, type, name });\n }\n if (isStreamRef(value)) {\n const ref = value.$s;\n return \"id\" in ref ? this.pvtValueFor(ref.id, \"stream\") : this.pvtValueForNamed(ref.name);\n }\n if (seen.has(value)) return value;\n seen.add(value);\n if (Array.isArray(value)) return value.map((item) => this.pvtDecode(item, seen));\n if (ArrayBuffer.isView(value) || value instanceof ArrayBuffer) return value;\n // Whatever a store earlier in the chain already turned into a handle is not a plain object any\n // more, and copying it here would strip what makes it one.\n if (!isPlainObject(value)) return value;\n const copy: Record<string, unknown> = {};\n for (const [key, item] of Object.entries(value)) copy[key] = this.pvtDecode(item, seen);\n return copy;\n }\n\n private pvtValueFor(id: number, form: ValueForm, facts?: BlobFacts | BytesFacts): RemoteStream | RemoteBlob | RemoteArray {\n const incoming = this.pvtIncoming.get(id);\n if (!incoming) {\n // A reference to a stream that is over, or one this side was never told about. The value says\n // so when it is read rather than throwing in the middle of a decoded frame: it was the message's\n // fault, not the connection's.\n const ended = this.pvtRefused.get(id);\n const failed = new RemoteStream({ consumed() {}, cancelled() {}, wanted() {} });\n failed.fail(ended?.reason ?? `no stream was announced with id ${id}`);\n return this.pvtBuild(failed, ended?.form ?? form, facts);\n }\n if (incoming.value) return incoming.value;\n incoming.form = form;\n // The size is on the reference now, so a value this side will not read is refused before a\n // chunk is asked for. A plain stream has no size to check: its bound is counted as it arrives.\n if (facts !== undefined && facts.size > this.maxBytes) {\n const reason = `stream ${id} is ${facts.size} bytes, over this side's bound of ${this.maxBytes}`;\n incoming.done = true;\n incoming.reader.fail(reason);\n this.pvtRetire(id, reason, form);\n void this.channel.send({ $streamFail: { id, reason: \"over the reader's bound\" } });\n }\n return (incoming.value = this.pvtBuild(incoming.reader, form, facts));\n }\n\n /** The value a name the far side announced stands for — or one that says it was never announced. */\n private pvtValueForNamed(name: string): RemoteStream {\n const id = this.pvtNamesIn.get(name);\n if (id !== undefined && this.pvtIncoming.has(id)) return this.pvtValueFor(id, \"stream\") as RemoteStream;\n const failed = new RemoteStream({ consumed() {}, cancelled() {}, wanted() {} });\n failed.fail(`no stream was announced with the name ${name}`);\n return failed;\n }\n\n private pvtBuild(reader: RemoteStream, form: ValueForm, facts?: BlobFacts | BytesFacts): RemoteStream | RemoteBlob | RemoteArray {\n if (facts === undefined) return reader;\n if (form === \"blob\") return new RemoteBlob(reader, { size: facts.size, type: facts.type, name: \"name\" in facts ? facts.name : undefined });\n if (form === \"bytes\") return this.pvtArray(reader, facts);\n return reader;\n }\n\n /**\n * The array the far side is sending: the kind it was, made here at the size its reference stated,\n * and filled as the octets land. The fill loop is the stream's one consumer, so the credit\n * machinery asks for exactly what can be stored and the array is complete before `settled` resolves.\n */\n private pvtArray(reader: RemoteStream, facts: BytesFacts | BlobFacts): RemoteArray {\n // Nothing is made for a value this side has refused or never heard of: the size it states is not\n // an allocation this side has to honour.\n const value =\n facts.size > this.maxBytes\n ? new Uint8Array(0)\n : allocateBytes(facts.size, facts.type, \"length\" in facts ? facts.length : undefined);\n const filling = fillArray(value, reader, facts.size);\n // Reported through `settled`; a decode nobody waits on must not raise an unhandled rejection.\n void filling.catch(() => {});\n this.pvtPending.push(filling);\n return value;\n }\n\n private pvtAsk(incoming: Incoming): void {\n if (incoming.done || this.pvtClosed) return;\n const outstanding = incoming.asked - incoming.consumed;\n if (outstanding >= this.windowBytes / 2) return;\n const credit = this.windowBytes - outstanding;\n incoming.asked += credit;\n void this.channel.send({ $streamAsk: { id: incoming.id, credit } });\n }\n\n private pvtAnnounced(id: number, name?: string): void {\n const existing = this.pvtIncoming.get(id);\n existing?.reader.fail(`a stream was announced twice with id ${id}`);\n if (name !== undefined) {\n const taken = this.pvtNamesIn.get(name);\n // A name already live is refused: a reference to it would otherwise resolve to whichever of the\n // two arrived last, and neither side would be able to say which.\n if (taken !== undefined) {\n const reason = `a stream named ${name} is already live (id ${taken})`;\n this.pvtRetire(id, reason, \"stream\");\n void this.channel.send({ $streamFail: { id, reason } });\n return;\n }\n this.pvtNamesIn.set(name, id);\n }\n // The reader is built before the record it lives in: its callbacks close over that record and only run\n // once a chunk or a cancel arrives, which is after the assignment below.\n let incoming: Incoming;\n const reader = new RemoteStream({\n consumed: (bytes) => {\n incoming.consumed += bytes;\n this.pvtAsk(incoming);\n },\n wanted: () => {\n this.pvtAsk(incoming);\n },\n cancelled: (reason) => {\n incoming.done = true;\n this.pvtIncoming.delete(id);\n this.pvtRelease(id);\n void this.channel.send({ $streamCancel: { id, reason } });\n },\n });\n incoming = { id, reader, form: \"stream\", asked: 0, consumed: 0, received: 0, chunk: null, done: false };\n this.pvtIncoming.set(id, incoming);\n if (name !== undefined) {\n const stream = this.pvtValueFor(id, \"stream\") as RemoteStream;\n for (const listener of this.pvtNamedListeners) listener(name, stream);\n }\n }\n\n private onSegment(head: Record<string, unknown>, bytes: Uint8Array): void {\n const chunk = head.$chunk as { id?: unknown; seq?: unknown; bytes?: unknown } | undefined;\n if (typeof chunk?.id !== \"number\" || typeof chunk.seq !== \"number\") return;\n const incoming = this.pvtIncoming.get(chunk.id);\n if (!incoming || incoming.done) {\n // A stream this side has dropped or never heard of: the octets are skipped, and that is what\n // the head's own length is for.\n return;\n }\n incoming.received += bytes.length;\n if (incoming.received > this.maxBytes) {\n const reason = `stream ${incoming.id} passed this side's bound of ${this.maxBytes} bytes`;\n incoming.done = true;\n incoming.reader.fail(reason);\n this.pvtRetire(incoming.id, reason, incoming.form);\n void this.channel.send({ $streamFail: { id: incoming.id, reason: \"over the reader's bound\" } });\n return;\n }\n incoming.chunk = { seq: chunk.seq, bytes };\n }\n\n private onFrame(frame: Record<string, unknown>): void {\n if (this.pvtClosed) return;\n if (\"$stream\" in frame) {\n const body = frame.$stream as { id?: unknown; name?: unknown } | undefined;\n if (typeof body?.id !== \"number\") return;\n this.pvtAnnounced(body.id, typeof body.name === \"string\" ? body.name : undefined);\n return;\n }\n if (\"$streamAsk\" in frame) {\n const body = frame.$streamAsk as { id?: unknown; credit?: unknown } | undefined;\n const offered = typeof body?.id === \"number\" ? this.pvtOffers.get(body.id) : undefined;\n if (!offered || typeof body?.credit !== \"number\" || body.credit <= 0) return;\n offered.credit += body.credit;\n void this.pvtPump(offered);\n return;\n }\n if (\"$chunkEnd\" in frame) {\n const body = frame.$chunkEnd as { id?: unknown; seq?: unknown; crc32?: unknown } | undefined;\n const incoming = typeof body?.id === \"number\" ? this.pvtIncoming.get(body.id) : undefined;\n if (!incoming) return;\n const chunk = incoming.chunk;\n incoming.chunk = null;\n if (chunk === null || chunk.seq !== body?.seq) {\n incoming.done = true;\n incoming.reader.fail(`stream ${incoming.id} lost its framing: a chunk ended that never began`);\n this.pvtRetire(incoming.id, `stream ${incoming.id} lost its framing: a chunk ended that never began`, incoming.form);\n void this.channel.send({ $streamFail: { id: incoming.id, reason: \"lost the framing\" } });\n return;\n }\n if (typeof body?.crc32 === \"number\" && crc32(chunk.bytes) !== body.crc32) {\n incoming.done = true;\n incoming.reader.fail(`stream ${incoming.id} arrived corrupt: chunk ${chunk.seq} failed its checksum`);\n this.pvtRetire(incoming.id, `stream ${incoming.id} arrived corrupt: chunk ${chunk.seq} failed its checksum`, incoming.form);\n void this.channel.send({ $streamFail: { id: incoming.id, reason: \"a chunk failed its checksum\" } });\n return;\n }\n incoming.reader.push(chunk.bytes);\n return;\n }\n if (\"$streamDone\" in frame) {\n const body = frame.$streamDone as { id?: unknown } | undefined;\n const incoming = typeof body?.id === \"number\" ? this.pvtIncoming.get(body.id) : undefined;\n if (!incoming) return;\n incoming.done = true;\n this.pvtIncoming.delete(incoming.id);\n this.pvtRelease(incoming.id);\n incoming.reader.end();\n return;\n }\n if (\"$streamFail\" in frame) {\n const body = frame.$streamFail as { id?: unknown; reason?: unknown } | undefined;\n const incoming = typeof body?.id === \"number\" ? this.pvtIncoming.get(body.id) : undefined;\n if (!incoming) return;\n const reason = typeof body?.reason === \"string\" ? body.reason : `stream ${incoming.id} failed`;\n incoming.done = true;\n incoming.reader.fail(reason);\n this.pvtRetire(incoming.id, reason, incoming.form);\n return;\n }\n if (\"$streamCancel\" in frame) {\n const body = frame.$streamCancel as { id?: unknown } | undefined;\n const offered = typeof body?.id === \"number\" ? this.pvtOffers.get(body.id) : undefined;\n if (!offered) return;\n this.pvtDrop(offered);\n void offered.source.return?.();\n }\n }\n}\n\n/** A typed array or an `ArrayBuffer` as the octets the wire carries. */\n/** How many octets an element of each kind takes. A name that came off the wire is looked up here\n * rather than handed to `globalThis`, so a peer cannot name a constructor this side would run. */\nconst TYPED_ARRAY_STRIDE: ReadonlyMap<string, number> = new Map([\n [\"Int8Array\", 1],\n [\"Uint8Array\", 1],\n [\"Uint8ClampedArray\", 1],\n [\"Int16Array\", 2],\n [\"Uint16Array\", 2],\n [\"Int32Array\", 4],\n [\"Uint32Array\", 4],\n [\"Float32Array\", 4],\n [\"Float64Array\", 8],\n [\"BigInt64Array\", 8],\n [\"BigUint64Array\", 8],\n]);\n\nfunction isTypedArrayName(name: string): name is TypedArrayName {\n return TYPED_ARRAY_STRIDE.has(name);\n}\n\ninterface Octets {\n bytes: Uint8Array;\n type?: TypedArrayName;\n length?: number;\n}\n\n/** The octets of a value about to cross — and, for a typed array, what they are made of. */\nfunction octetsOf(value: ArrayBuffer | ArrayBufferView): Octets {\n if (!ArrayBuffer.isView(value)) return { bytes: new Uint8Array(value) };\n const bytes = new Uint8Array(value.buffer, value.byteOffset, value.byteLength);\n if (value instanceof DataView) return { bytes };\n // The tag is the same in every realm, where `instanceof` is only true in this one.\n const name = Object.prototype.toString.call(value).slice(8, -1);\n if (!isTypedArrayName(name)) return { bytes };\n const stride = TYPED_ARRAY_STRIDE.get(name) ?? 1;\n if (bytes.length % stride !== 0) return { bytes };\n return { bytes, type: name, length: bytes.length / stride };\n}\n\n/** The sender's kind of array, made at the element count its reference stated. */\nfunction allocateBytes(size: number, type: string | undefined, length: number | undefined): RemoteArray {\n if (type === undefined || !isTypedArrayName(type)) return new Uint8Array(size);\n const stride = TYPED_ARRAY_STRIDE.get(type) ?? 1;\n if (size % stride !== 0) return new Uint8Array(size);\n const count = length !== undefined && length * stride === size ? length : size / stride;\n switch (type) {\n case \"Int8Array\":\n return new Int8Array(count);\n case \"Uint8Array\":\n return new Uint8Array(count);\n case \"Uint8ClampedArray\":\n return new Uint8ClampedArray(count);\n case \"Int16Array\":\n return new Int16Array(count);\n case \"Uint16Array\":\n return new Uint16Array(count);\n case \"Int32Array\":\n return new Int32Array(count);\n case \"Uint32Array\":\n return new Uint32Array(count);\n case \"Float32Array\":\n return new Float32Array(count);\n case \"Float64Array\":\n return new Float64Array(count);\n case \"BigInt64Array\":\n return new BigInt64Array(count);\n case \"BigUint64Array\":\n return new BigUint64Array(count);\n }\n}\n\n/** Fill the array as its octets arrive. A view of the same memory is how every element kind is\n * written the same way, and how a `BigInt64Array` is filled without mixing element types. */\nasync function fillArray(value: RemoteArray, body: Stream, size: number): Promise<void> {\n const octets = new Uint8Array(value.buffer, value.byteOffset, value.byteLength);\n let at = 0;\n for await (const chunk of body) {\n if (at + chunk.length > octets.length) throw new Error(`the array is longer than the ${size} bytes it stated`);\n octets.set(chunk, at);\n at += chunk.length;\n }\n if (at !== octets.length) throw new Error(`the array is short: ${at} of ${size} octets arrived`);\n}\n\nfunction reasonOf(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\n/** The stream id a control frame names, or null when it names none of them. */\nfunction frameId(frame: Record<string, unknown>): number | null {\n for (const key of [\"$streamAsk\", \"$streamCancel\", \"$streamDone\", \"$streamFail\"]) {\n const body = frame[key] as { id?: unknown } | undefined;\n if (typeof body?.id === \"number\") return body.id;\n }\n return null;\n}\n","// ── bytes on a stream, and the lines they carry ─────────────────────────────\n//\n// A line transport's reader, and the number that made it a file of its own: 13.3 MB of\n// 87 KB frames read through `node:readline` costs 4.0 s on this box, and through a buffer\n// and an `indexOf` it costs 76 ms. The difference is not the parsing — it is that a\n// frame the size of a file chunk is the normal case here and readline is built for the\n// other one.\n//\n// Splitting on the byte 0x0a is safe for UTF-8: a continuation byte is never 0x0a, so a\n// line boundary cannot fall inside a character, and a chunk boundary inside one is\n// carried by the accumulator until the rest of it arrives.\n//\n// CRLF is read as a line ending rather than as part of the frame, which is what the line\n// reader it replaces did; the frames this library writes end in \"\\n\" alone.\n//\n// ── a line may carry octets after it ───────────────────────────────────────\n//\n// Not every frame on the wire is text: a chunk of a stream is a JSON head, the raw\n// octets it announces, and a JSON tail. So a line is also a question — how many octets\n// follow — and the answer says where the next line starts. `PartReader` is that state\n// machine, over bytes as they arrive however the carrier splits them; a carrier that\n// moves whole messages (a websocket) feeds it one message at a time and the machine\n// cannot tell the difference.\n\nimport type { Readable } from \"node:stream\";\n\n/** A reader, and the one way to stop it. */\nexport interface LineReader {\n /** Stop reading and drop what is buffered. Idempotent. */\n stop(): void;\n}\n\nconst NL = 0x0a;\nconst CR = 0x0d;\n\nfunction withoutCr(line: Buffer<ArrayBufferLike>): Buffer<ArrayBufferLike> {\n return line.length > 0 && line[line.length - 1] === CR ? line.subarray(0, line.length - 1) : line;\n}\n\n/**\n * The wire as a sequence of lines, where a line may announce raw octets to follow it.\n *\n * `onLine` gets a line and answers how many octets come next — none, for every frame but\n * one that carries them. Those octets reach `onBytes` whole, however many reads they\n * arrived in, and the reader goes back to looking for a newline.\n */\nexport class PartReader {\n private acc: Buffer<ArrayBufferLike> = Buffer.alloc(0);\n /** How many octets the octet run still needs, or 0 while looking for a line. */\n private want = 0;\n private done = false;\n\n constructor(\n private readonly onLine: (line: string) => number | void,\n private readonly onBytes: (bytes: Uint8Array) => void,\n ) {}\n\n feed(chunk: Uint8Array): void {\n if (this.done) return;\n this.acc = this.acc.length === 0 ? Buffer.from(chunk.buffer, chunk.byteOffset, chunk.byteLength) : Buffer.concat([this.acc, chunk]);\n this.pump();\n }\n\n /** The stream is over: whatever is left of a line is still a line, as `readline` said. */\n end(): void {\n if (this.done) return;\n const rest = this.acc;\n this.acc = Buffer.alloc(0);\n this.done = true;\n if (rest.length > 0 && this.want === 0) this.onLine(withoutCr(rest).toString(\"utf8\"));\n }\n\n private pump(): void {\n for (;;) {\n if (this.want > 0) {\n if (this.acc.length < this.want) return;\n const bytes = this.acc.subarray(0, this.want);\n this.acc = this.acc.subarray(this.want);\n this.want = 0;\n this.onBytes(bytes);\n continue;\n }\n const at = this.acc.indexOf(NL);\n if (at < 0) return;\n const line = this.acc.subarray(0, at);\n this.acc = this.acc.subarray(at + 1);\n const asked = this.onLine(withoutCr(line).toString(\"utf8\"));\n if (typeof asked === \"number\") {\n // A run of no octets is still a run: the line said what follows, and it follows as nothing.\n if (asked > 0) this.want = asked;\n else this.onBytes(new Uint8Array(0));\n }\n }\n }\n}\n\n/**\n * Read `stream` as lines, with the octets a line announces.\n *\n * `onEnd` is called once when the stream is over, after the last line: a stream that\n * ends without its final newline still gives up its last line, because that is what the\n * peer meant to say.\n */\nexport function readParts(\n stream: Readable,\n onLine: (line: string) => number | void,\n onBytes: (bytes: Uint8Array) => void,\n onEnd?: () => void,\n): LineReader {\n const reader = new PartReader(onLine, onBytes);\n return readChunks(\n stream,\n (chunk) => reader.feed(chunk),\n () => {\n reader.end();\n onEnd?.();\n },\n );\n}\n\n/** Read `stream` a line at a time, with no octets: the plain line carrier. */\nexport function readLines(stream: Readable, onLine: (line: string) => void, onEnd?: () => void): LineReader {\n return readParts(\n stream,\n (line) => {\n onLine(line);\n },\n () => {\n // A carrier that never announces octets never delivers any; a peer that sends them\n // anyway is talking past the protocol, and the bytes are dropped rather than guessed at.\n },\n onEnd,\n );\n}\n\n/** The bytes a stream carries, before anything is made of them. */\nexport function readChunks(stream: Readable, onChunk: (chunk: Uint8Array) => void, onEnd?: () => void): LineReader {\n let stopped = false;\n\n const onData = (chunk: Buffer | string): void => {\n if (stopped) return;\n onChunk(typeof chunk === \"string\" ? Buffer.from(chunk, \"utf8\") : chunk);\n };\n\n const finish = (): void => {\n if (stopped) return;\n stopped = true;\n stream.off(\"data\", onData);\n onEnd?.();\n };\n\n stream.on(\"data\", onData);\n // A pipe finishes in more than one way. `end` is a peer that closes politely; one that vanishes —\n // a socket destroyed, a write that fails, a process killed — reports `close` or `error` and never\n // an end at all, and a reader that waits for the end alone hangs on a connection that is gone.\n stream.once(\"end\", finish);\n stream.once(\"close\", finish);\n stream.once(\"error\", finish);\n\n return {\n stop(): void {\n stopped = true;\n stream.off(\"data\", onData);\n stream.off(\"end\", finish);\n stream.off(\"close\", finish);\n stream.off(\"error\", finish);\n },\n };\n}\n","// ── stdio wire ─────────────────────────────────────────────────────────────\n//\n// A newline-delimited JSON channel over a pair of streams: the one wire every\n// way into a foreign execution context can carry. Two callers rely on it, and\n// they are two halves of the same thing:\n//\n// * the client of a spawn we make ourselves, on fds handed to the child (see\n// `fdStreams`) — private fds, so the child's own stdout stays free;\n// * a first-stage command on its own stdin/stdout, over ssh, under `sudo`, in\n// a container — where stdio is the only channel there is.\n//\n// Frames are one JSON object per line. Whatever the far end prints is carried as an *output\n// frame* (`$fd`), so it can never be mistaken for a frame of the protocol itself; a failed start\n// is carried as an `$error` frame.\n//\n// Output frames are routed above the protocol step, by whoever holds the connection (output.ts):\n// every line decodes to a frame, and the ones that are the far end's own print go to that\n// holder's sink instead of to the seam. The handshake below reads the first frame that is the\n// protocol's, since the far end's own print may come first.\n\nimport { createReadStream, createWriteStream } from \"node:fs\";\nimport { readParts } from \"./lines.js\";\nimport type { Readable, Writable } from \"node:stream\";\nimport {\n errorFrame as wireErrorFrame,\n errorReason as wireErrorReason,\n isProto,\n\n type Channel,\n\n type StringTransport,\n} from \"./channel.js\";\nimport { VERSION, json1Channel } from \"./protocols/json1.js\";\n\n\n/** The stream pair a line transport talks over. */\nexport interface LineStreams {\n read: Readable;\n write: Writable;\n}\n\n/** How long to wait for the far end's first protocol frame. */\nexport const HANDSHAKE_TIMEOUT_MS = 15_000;\n\n/** Raised when the wire itself fails: no frame, the wrong protocol, a peer that went away. */\nexport class StdioWireError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"StdioWireError\";\n }\n}\n\n/** An `$error` frame as a line. The word and its shape are the shared vocabulary's\n * (channel.ts) — one word for a wire that cannot be spoken over, whether the failure was at\n * the start of a session or in the middle of one; what this file owns is its line form. */\nexport function errorFrame(reason: string): string {\n return JSON.stringify(wireErrorFrame(reason));\n}\n\n/** The reason an `$error` frame carries, or null when it is not one. */\nexport function errorReason(frame: Record<string, unknown>): string | null {\n return wireErrorReason(frame);\n}\n\n// ── transports ─────────────────────────────────────────────────────────────\n\n/** Is this write error just a peer that already left? */\nfunction peerGone(code: unknown): boolean {\n return (\n code === \"EPIPE\" ||\n code === \"ERR_STREAM_DESTROYED\" ||\n code === \"ERR_STREAM_WRITE_AFTER_END\" ||\n code === \"ERR_STREAM_ALREADY_FINISHED\"\n );\n}\n\nfunction errorText(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n\n/**\n * A `StringTransport` over a read/write stream pair, one JSON frame per line.\n *\n * `close()` is idempotent and never throws: teardown races are normal here —\n * the peer exits, the read side ends, and a write arrives a moment later.\n */\nexport class LineTransport implements StringTransport {\n private readonly streams: LineStreams;\n private pvtOnMessage: ((line: string) => number | void) | null = null;\n private pvtOnBytes: ((bytes: Uint8Array) => void) | null = null;\n private pvtOnClose: (() => void) | null = null;\n private pvtClosed = false;\n private pvtClosing: Promise<void> | null = null;\n\n constructor(streams: LineStreams) {\n this.streams = streams;\n readParts(\n streams.read,\n (line) => (this.pvtClosed ? undefined : this.pvtOnMessage?.(line)),\n (bytes) => {\n if (!this.pvtClosed) this.pvtOnBytes?.(bytes);\n },\n () => {\n this.pvtOnClose?.();\n void this.close();\n },\n );\n // A stream error is a peer that went away, not a reason to take the process\n // down with an unhandled 'error' event.\n streams.read.on(\"error\", () => {\n void this.close();\n });\n streams.write.on(\"error\", () => {\n void this.close();\n });\n }\n\n get closed(): boolean {\n return this.pvtClosed;\n }\n\n get hasHandler(): boolean {\n return this.pvtOnMessage !== null;\n }\n\n onMessage(handler: (line: string) => number | void): void {\n if (this.pvtClosed) throw new StdioWireError(\"stdio transport: closed\");\n if (this.pvtOnMessage !== null) {\n throw new StdioWireError(\"stdio transport: handler already set — call removeHandler()\");\n }\n this.pvtOnMessage = handler;\n }\n\n onBytes(handler: (bytes: Uint8Array) => void): void {\n if (this.pvtClosed) throw new StdioWireError(\"stdio transport: closed\");\n this.pvtOnBytes = handler;\n }\n\n removeHandler(): ((line: string) => number | void) | null {\n const previous = this.pvtOnMessage;\n this.pvtOnMessage = null;\n return previous;\n }\n\n onClose(handler: () => void): void {\n this.pvtOnClose = handler;\n }\n\n send(frame: string): Promise<void> {\n const line = frame.endsWith(\"\\n\") ? frame : `${frame}\\n`;\n return this.pvtWrite(line);\n }\n\n sendBytes(bytes: Uint8Array): Promise<void> {\n return this.pvtWrite(bytes);\n }\n\n private pvtWrite(data: string | Uint8Array): Promise<void> {\n if (this.pvtClosed) {\n return Promise.resolve();\n }\n return new Promise<void>((resolve, reject) => {\n try {\n this.streams.write.write(data, (err?: Error | null) => {\n if (!err) return resolve();\n const code = (err as { code?: unknown }).code;\n // A peer that has hung up cannot be told anything; the write that\n // races its exit is not an error in this transport.\n if (peerGone(code)) {\n return resolve();\n }\n reject(new StdioWireError(`stdio transport: ${err.message}`));\n });\n } catch (err) {\n reject(new StdioWireError(`stdio transport: ${errorText(err)}`));\n }\n });\n }\n\n async close(): Promise<void> {\n this.pvtClosing ??= this.pvtClose();\n await this.pvtClosing;\n }\n\n private async pvtClose(): Promise<void> {\n await Promise.resolve();\n\n this.pvtClosed = true;\n // Best effort: a half-open stream (the peer is already gone) must not turn\n // teardown into an exception.\n try {\n this.streams.read.destroy?.();\n } catch {\n /* already gone */\n }\n try {\n if (!this.streams.write.writableEnded) this.streams.write.end();\n } catch {\n /* already gone */\n }\n }\n}\n\n/** Streams over two fds of *our own* process — the child side of an fd wire. */\nexport function fdStreams(readFd: number, writeFd: number): LineStreams {\n const read = createReadStream(\"\", { fd: readFd, autoClose: false });\n const write = createWriteStream(\"\", { fd: writeFd, autoClose: false });\n return { read, write };\n}\n\n// ── handshakes ─────────────────────────────────────────────────────────────\n\n/** The next frame that is the protocol's, or a timeout. */\nasync function nextFrame(channel: Channel, timeoutMs: number): Promise<Record<string, unknown>> {\n return await new Promise((resolve, reject) => {\n const timer = setTimeout(\n () => reject(new StdioWireError(`no protocol frame within ${timeoutMs}ms`)),\n timeoutMs,\n );\n timer.unref?.();\n const off = channel.onMessage((frame) => {\n off();\n clearTimeout(timer);\n resolve(frame);\n });\n });\n}\n\nexport interface ClientChannelOptions {\n /** How long to wait for the peer's protocol frame. Defaults to {@link HANDSHAKE_TIMEOUT_MS}. */\n timeoutMs?: number;\n}\n\n/**\n * The client end of the connection: hand the streams to the seam and wait for the peer's `$proto`.\n * A first stage reports a failed start as an `$error` frame instead.\n *\n * What the far end prints is not here: it arrives as a stream the far end announces under a name,\n * and whoever wants it reads it by that name.\n */\nexport async function clientChannel(\n streams: LineStreams,\n opts: ClientChannelOptions = {},\n): Promise<Channel> {\n const channel = json1Channel(new LineTransport(streams));\n const frame = await nextFrame(channel, opts.timeoutMs ?? HANDSHAKE_TIMEOUT_MS);\n\n const reason = errorReason(frame);\n if (reason) throw new StdioWireError(reason);\n if (!isProto(frame)) {\n throw new StdioWireError(`unexpected first frame: ${JSON.stringify(frame).slice(0, 120)}`);\n }\n if (frame.$proto !== VERSION) {\n throw new StdioWireError(`unsupported protocol ${String(frame.$proto)}, expected ${VERSION}`);\n }\n return channel;\n}\n\n/** The server end of the wire — a payload speaking stdio itself. */\nexport async function serverChannel(streams: LineStreams): Promise<Channel> {\n const channel = json1Channel(new LineTransport(streams));\n await channel.send({ $proto: VERSION });\n return channel;\n}\n","// ── FIFO transport ─────────────────────────────────────────────────────────\n//\n// Newline-delimited UTF-8 over named fifos. Strict handler lifecycle:\n// onMessage() throws if a handler is already set; call removeHandler() first.\n\nimport { open, type FileHandle } from \"node:fs/promises\";\nimport type { ReadStream, WriteStream } from \"node:fs\";\nimport { readParts, type LineReader } from \"../lines.js\";\nimport type { StringTransport } from \"../channel.js\";\n\nexport class FifoUtf8NlineTransport implements StringTransport {\n private readFd: FileHandle | null;\n private writeFd: FileHandle | null;\n private reader: LineReader | null;\n private rs: ReadStream | null;\n private ws: WriteStream | null;\n private pvtOnMessage: ((line: string) => number | void) | null = null;\n private pvtOnBytes: ((bytes: Uint8Array) => void) | null = null;\n private pvtOnClose: (() => void) | null = null;\n private closed = false;\n private closingPromise: Promise<void> | null = null;\n private pvtError: Error | null = null;\n\n private constructor(opts: { readFd?: FileHandle; writeFd?: FileHandle }) {\n this.readFd = opts.readFd ?? null;\n this.writeFd = opts.writeFd ?? null;\n\n if (this.readFd) {\n this.rs = this.readFd.createReadStream();\n this.reader = readParts(\n this.rs,\n (line) => (this.closed ? undefined : this.pvtOnMessage?.(line)),\n (bytes) => {\n if (!this.closed) this.pvtOnBytes?.(bytes);\n },\n () => {\n this.pvtOnClose?.();\n void this.close();\n },\n );\n\n this.rs.on(\"error\", (err: Error) => {\n this.pvtError = err;\n this.close();\n });\n } else {\n this.rs = null;\n this.reader = null;\n }\n\n if (this.writeFd) {\n this.ws = this.writeFd.createWriteStream({});\n this.ws.on(\"error\", (err: Error) => {\n this.pvtError = err;\n this.close();\n });\n } else {\n this.ws = null;\n }\n }\n\n // ── factories ──────────────────────────────────────────────────────────\n\n static openReaderFd(readFd: FileHandle): FifoUtf8NlineTransport {\n return new FifoUtf8NlineTransport({ readFd });\n }\n\n static openWriterFd(writeFd: FileHandle): FifoUtf8NlineTransport {\n return new FifoUtf8NlineTransport({ writeFd });\n }\n\n static fromFds(readFd: FileHandle, writeFd: FileHandle): FifoUtf8NlineTransport {\n return new FifoUtf8NlineTransport({ readFd, writeFd });\n }\n\n // ── bidirectional connection ───────────────────────────────────────────\n\n /**\n * Start opening a bidirectional connection. Opens readPath for reading\n * in the background, returns a promise. The caller should do whatever\n * setup is needed to unblock the read (e.g. spawn a process that opens\n * readPath for writing), then await the returned transport.\n *\n * The transport itself is built only once both directions are open. A read\n * stream created while no writer exists on its fifo is handed an immediate\n * end-of-stream by some runtimes (bun), which closes a channel that has not\n * carried a byte yet — so the writes side is opened before the reader exists.\n */\n static beginConnect(\n readPath: string,\n writePath: string,\n ): { transport: Promise<FifoUtf8NlineTransport> } {\n const readFdPromise = open(readPath, \"r\");\n\n const transport = readFdPromise.then(async (readFd) => {\n const writeFd = await open(writePath, \"w\");\n return FifoUtf8NlineTransport.fromFds(readFd, writeFd);\n });\n\n return { transport };\n }\n\n /**\n * Open a bidirectional connection. Opens writePath for writing first\n * (unblocking the peer's read), starts reading readPath in the\n * background, then awaits both.\n *\n * Use this when you are the side that responds to the peer's beginConnect\n * (i.e. you don't need to interleave any setup between the read and write\n * opens). Built like `beginConnect`: the transport exists only after both\n * directions do.\n */\n static async connect(readPath: string, writePath: string): Promise<FifoUtf8NlineTransport> {\n const readFdPromise = open(readPath, \"r\");\n const writeFd = await open(writePath, \"w\");\n const readFd = await readFdPromise;\n return FifoUtf8NlineTransport.fromFds(readFd, writeFd);\n }\n\n // ── public API ─────────────────────────────────────────────────────────\n\n get canSend(): boolean {\n return this.writeFd !== null && !this.closed;\n }\n\n onBytes(handler: (bytes: Uint8Array) => void): void {\n if (this.closed) throw new Error(\"FifoUtf8NlineTransport: closed\");\n if (this.readFd === null) throw new Error(\"FifoUtf8NlineTransport: not a reader\");\n this.pvtOnBytes = handler;\n }\n\n onMessage(handler: (line: string) => number | void): void {\n if (this.closed) throw new Error(\"FifoUtf8NlineTransport: closed\");\n if (this.readFd === null) throw new Error(\"FifoUtf8NlineTransport: not a reader\");\n if (this.pvtOnMessage !== null) {\n throw new Error(\"FifoUtf8NlineTransport: handler already set — call removeHandler() first\");\n }\n this.pvtOnMessage = handler;\n }\n\n removeHandler(): ((line: string) => number | void) | null {\n const prev = this.pvtOnMessage;\n this.pvtOnMessage = null;\n return prev;\n }\n\n onClose(handler: () => void): void {\n this.pvtOnClose = handler;\n }\n\n get hasHandler(): boolean {\n return this.pvtOnMessage !== null;\n }\n\n get lastError(): Error | null {\n return this.pvtError;\n }\n\n async send(line: string): Promise<void> {\n if (this.closed) throw new Error(\"FifoUtf8NlineTransport: closed\");\n if (this.writeFd === null) throw new Error(\"FifoUtf8NlineTransport: not a writer\");\n if (!line.endsWith(\"\\n\")) line += \"\\n\";\n await this.ws?.write(line);\n }\n\n async sendBytes(bytes: Uint8Array): Promise<void> {\n if (this.closed) throw new Error(\"FifoUtf8NlineTransport: closed\");\n if (this.writeFd === null) throw new Error(\"FifoUtf8NlineTransport: not a writer\");\n await this.ws?.write(bytes);\n }\n\n async close(): Promise<void> {\n this.closingPromise = this.closingPromise || this.pvtClose();\n await this.closingPromise;\n this.closed = true;\n }\n\n private async pvtClose(): Promise<void> {\n // tranfser control back to caller\n // so they can capture the promise reference\n // and prevent reentry\n await Promise.resolve();\n\n if (this.reader) {\n this.reader.stop();\n this.reader = null;\n }\n if (this.rs) {\n this.rs.destroy();\n this.rs = null;\n }\n if (this.ws) {\n await new Promise<void>((resolve) => {\n try {\n this.ws?.end(\"\", resolve);\n } catch {\n resolve();\n }\n });\n this.ws = null;\n }\n\n if (this.readFd) {\n try {\n await this.readFd.close();\n } catch {}\n this.readFd = null;\n }\n if (this.writeFd) {\n try {\n await this.writeFd.close();\n } catch {}\n this.writeFd = null;\n }\n }\n}\n","// ── Gateway ────────────────────────────────────────────────────────────────\n//\n// The first-stage command. Run this *inside* a foreign environment — directly,\n// under `sudo`, over ssh, in a container — and it:\n//\n// 1. creates the channel to the payload (fifo paths it makes itself, in a\n// private temp dir, so they belong to the uid that will open them),\n// 2. starts the payload — the first argument, required — hands it everything else it was\n// given (the host version among it) and relays frames between stdin/stdout,\n// 3. carries whatever the payload prints to the client as output frames\n// (`$fd`), so the payload's own stdout can never be mistaken for protocol.\n//\n// Why a gateway at all: a fifo path created on the client side is useless when the\n// payload runs as another uid (it cannot open it) or on another host (the path is\n// not there). stdio is the one channel every way into an environment gives us, so\n// the wire is stdio and the fifo stays inside the environment.\n//\n// The gateway reads nothing out of what it carries and owns no flag: the payload's path and\n// every argument after it go through verbatim, in order. The payload is the one who refuses a\n// host version it is not, and a relay that judged would be a second place for that decision.\n//\n// Directories and processes are cleaned up on every exit path, which is also why\n// the client never sees a transport being closed twice.\n//\n// It imports nothing but node builtins and this package, so the payload behind it\n// can be anything the runtime there can start.\n\nimport { execFile, spawn, type ChildProcess } from \"node:child_process\";\nimport { mkdtemp, rm } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { basename, join } from \"node:path\";\nimport { promisify } from \"node:util\";\nimport { channelThrough } from \"./channel.js\";\nimport { json1Channel } from \"./protocols/json1.js\";\nimport { lowBand } from \"./process-ref.js\";\nimport { StreamStore } from \"./stream.js\";\nimport { errorFrame } from \"./stdio.js\";\nimport type { LineTransport } from \"./stdio.js\";\nimport { LineTransport as Lines } from \"./stdio.js\";\nimport { FifoUtf8NlineTransport } from \"./transports/fifo.js\";\n\nconst run = promisify(execFile);\n\n/** How much of a dying payload's own words travels in the reason a failed start carries. */\nconst REASON_TAIL = 4096;\n\n/** Exit code for \"this environment could not be set up\". */\nexport const GATEWAY_FAILED = 1;\n\nexport interface GatewayBoot {\n /**\n * The program to start for the payload: the first word of the command the client composed —\n * a runtime, or a program that runs itself. Required, and first, and the gateway has no\n * opinion of its own about which it is.\n */\n worker: string;\n /**\n * Everything after the payload, carried to it **as is** and in order: the consumer's own\n * arguments, and posipaki's own facts among them (the host version travels this way). The\n * gateway reads nothing by name and owns no flag, so nothing of the caller's is interpreted,\n * eaten, re-ordered or re-spelled — and the next fact added to that line needs no new\n * vocabulary here.\n */\n passthrough: string[];\n}\n\nfunction errorText(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n\n/**\n * A label for the gateway's own temp directory: the program this environment was made for.\n * It is the gateway's business alone — the payload is not told which label it is.\n */\nfunction label(worker: string): string {\n const name = basename(worker).replace(/[^A-Za-z0-9.+@_-]/g, \"-\").slice(0, 60);\n return name === \"\" ? \"payload\" : name;\n}\n\n/**\n * The argv that boots this gateway — built by the client, read by\n * {@link gatewayBoot}, so the two halves cannot drift apart.\n *\n * The payload comes first and its arguments after it, so a positional argument of the\n * payload's own can never be mistaken for the payload.\n */\nexport function gatewayArgs(boot: GatewayBoot): string[] {\n return [boot.worker, ...boot.passthrough];\n}\n\n/** The boot a gateway was started with, or the reason it cannot start. */\nexport function gatewayBoot(argv: string[]): GatewayBoot {\n const [worker, ...passthrough] = argv;\n if (worker === undefined || worker.startsWith(\"--\")) {\n throw new Error(\"no <payload>: the gateway relays to a payload, named as its first argument\");\n }\n return { passthrough, worker };\n}\n\n/**\n * End a start that failed. The reason has already gone out on the wire, and\n * returning is not enough: the `open()` on a fifo no payload will ever write sits\n * in the threadpool forever, so the loop never drains and the gateway would linger\n * with a dead payload on its books.\n */\nfunction abandon(): never {\n process.exit(GATEWAY_FAILED);\n}\n\n/** Carry a failed start to the client, then let the caller exit non-zero. */\nasync function fail(wire: LineTransport, reason: string): Promise<void> {\n process.stderr.write(`gateway: ${reason}\\n`);\n try {\n await wire.send(errorFrame(reason));\n } catch {\n /* the client is gone too — the exit code still says what happened */\n }\n}\n\n/** The payload's own prints, as a stream: the pipe's chunks as they arrive. */\nasync function* chunksOf(stream: NodeJS.ReadableStream, prefix = \"\"): AsyncIterable<Uint8Array> {\n if (prefix.length > 0) yield new TextEncoder().encode(prefix);\n for await (const chunk of stream as AsyncIterable<Buffer | string>) {\n yield typeof chunk === \"string\" ? new TextEncoder().encode(chunk) : new Uint8Array(chunk);\n }\n}\n\n/** Everything a payload printed into its pipes, up to the point they end: what a start that dies\n * before its channel says about itself. A stream cannot carry it — there is no connection yet. */\n\n/**\n * Serve one environment over stdin/stdout. Returns the exit code; the caller\n * turns it into `process.exitCode`.\n */\nexport async function runGateway(argv: string[] = process.argv.slice(2)): Promise<number> {\n const wire = new Lines({ read: process.stdin, write: process.stdout });\n // One channel on the client wire, and the ids this gateway speaks from: the low band, which neither\n // the client nor the payload allocates in, so a stream of its own cannot collide with one of theirs.\n // The store answers only for the streams it offered; everything else belongs to the far side.\n const client = json1Channel(wire);\n const output = new StreamStore(client, \"even\", { ids: lowBand(\"even\"), attach: false });\n\n let booted: GatewayBoot;\n try {\n booted = gatewayBoot(argv);\n } catch (err) {\n // Nothing has been started yet, so there is nothing to tear down — but the\n // client still deserves the reason rather than a channel that closes on it,\n // and the loop can outlive us: an open stdin nobody will close keeps the\n // process alive, so this is an exit, not a return.\n await fail(wire, errorText(err));\n abandon();\n }\n const { passthrough, worker } = booted;\n\n const dir = await mkdtemp(join(tmpdir(), `posipaki-${label(worker)}-`));\n const fifoIn = join(dir, \"in\"); // the payload writes, we read\n const fifoOut = join(dir, \"out\"); // we write, the payload reads\n\n let child: ChildProcess | null = null;\n let fifo: FifoUtf8NlineTransport | null = null;\n\n /**\n * Everything this gateway owns, undone. All of it is idempotent, because the\n * exit path and the signal path can both arrive.\n */\n const teardown = async (): Promise<void> => {\n child?.kill();\n await fifo?.close().catch(() => {});\n await rm(dir, { recursive: true, force: true }).catch(() => {});\n };\n\n /**\n * A client that gives up stops us with a signal, and a gateway that died on the\n * spot would leave its payload behind in the environment — a process holding a\n * fifo nobody will ever write, which is a leak the environment cannot clean up\n * for us. So the signals do what the exit path does.\n */\n const onTerminate = () => {\n void teardown()\n .catch(() => {})\n .then(() => process.exit(GATEWAY_FAILED));\n };\n for (const signal of [\"SIGTERM\", \"SIGINT\", \"SIGHUP\"] as const) process.on(signal, onTerminate);\n\n try {\n await run(\"mkfifo\", [\"-m\", \"600\", fifoIn, fifoOut]);\n } catch (err) {\n await fail(wire, `cannot create the environment's fifos: ${errorText(err)}`);\n await teardown();\n abandon();\n }\n\n // Open the read side in the background, then start the payload that unblocks\n // it — the order the fifo handshake requires.\n const connection = FifoUtf8NlineTransport.beginConnect(fifoIn, fifoOut);\n const workerArgs = [worker, ...passthrough, `--fifo-in=${fifoIn}`, `--fifo-out=${fifoOut}`];\n // Whatever the client said starts the payload, run as it said: a runtime with a script of\n // ours, or a program of the caller's own. The gateway does not know which it is, and does\n // not choose a runtime on the far end's behalf.\n const workerProc = spawn(workerArgs[0]!, workerArgs.slice(1), {\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n });\n child = workerProc;\n /** What the payload printed before the client spoke: a start that dies that early has no connection\n * to announce a stream on, and its words are the only way to say why it went. Kept per stream, so\n * the output that comes after is still attributed to the right one. */\n const early = { stdout: \"\", stderr: \"\" };\n const keep =\n (name: \"stdout\" | \"stderr\") =>\n (chunk: Buffer | string): void => {\n early[name] = (early[name] + String(chunk)).slice(-REASON_TAIL);\n };\n const keepOut = keep(\"stdout\");\n const keepErr = keep(\"stderr\");\n workerProc.stdout?.on(\"data\", keepOut);\n workerProc.stderr?.on(\"data\", keepErr);\n\n /** Announce the payload's own output as the two streams a program's prints belong on, with whatever\n * it said before the connection could carry it replayed as the first chunk. */\n const offerOutput = (): void => {\n const sides = [\n { stream: workerProc.stdout, name: \"stdout\", keep: keepOut },\n { stream: workerProc.stderr, name: \"stderr\", keep: keepErr },\n ] as const;\n for (const { stream, name, keep: drop } of sides) {\n if (!stream) continue;\n stream.off(\"data\", drop);\n stream.pause();\n output.offer(chunksOf(stream, early[name]), name);\n }\n };\n\n const exited = new Promise<number>((settle) => {\n // A payload killed by a signal (the client hung up, and we killed it) has no\n // code — for us that is a clean end, not a failure.\n workerProc.once(\"exit\", (code) => settle(code ?? 0));\n });\n\n try {\n fifo = await Promise.race([\n connection.transport,\n exited.then((code) => {\n throw new Error(`the payload exited with code ${code} before it opened its channel`);\n }),\n ]);\n } catch (err) {\n // A payload that dies before it opens its channel printed into pipes nobody is reading yet: its\n // last words are the only way to say why, and they are not a stream because no connection exists\n // to announce one on.\n const said = `${early.stdout}${early.stderr}`.trim();\n await fail(wire, `${errorText(err)}${said ? `: ${said}` : \"\"}`);\n await teardown();\n abandon();\n }\n\n // Relay frames, not lines: the gateway has streams of its own now — the payload's output — and one\n // the store claims is the gateway's, not the payload's business. Everything else crosses unchanged.\n // `fifo` is settled by the race above: a start that failed took the exit path and never got here.\n const payload = json1Channel(fifo as FifoUtf8NlineTransport);\n const fromClient = channelThrough(client, (frame) => output.handle(frame));\n const forward = (send: (frame: Record<string, unknown>) => unknown, frame: Record<string, unknown>): void => {\n void Promise.resolve(send(frame)).catch(() => {\n /* the far side is gone; its own exit path cleans up */\n });\n };\n let offered = false;\n fromClient.onMessage((frame) => {\n if (!offered) {\n offered = true;\n // The client has spoken, which means its store exists: an announcement made before that would\n // land in a connection with nobody listening for it.\n offerOutput();\n }\n forward((next) => payload.send(next), frame);\n });\n fromClient.onSegment?.((head, bytes) => {\n payload.sendSegment?.(head, bytes);\n });\n payload.onMessage((frame) => {\n forward((next) => client.send(next), frame);\n });\n payload.onSegment?.((head, bytes) => {\n client.sendSegment?.(head, bytes);\n });\n client.onClose(() => {\n child?.kill();\n });\n\n const code = await exited;\n await teardown();\n await wire.close();\n return code;\n}\n","// ── The gateway, as a program ──────────────────────────────────────────────\n//\n// A gateway is something a client runs: the first-stage command that makes a fifo\n// inside a foreign environment and relays frames between its own stdin/stdout and\n// the payload. That is this file's whole job — it always serves, and it exits with\n// the code the run ended in.\n//\n// Serving lives in ./gateway.js and starts nothing by itself. A file cannot decide\n// \"am I the program?\" from where it is: a consumer that bundles the node surface\n// into its own program carries this code along, and there the bundle *is* the\n// program — a payload would find a gateway booting on its wire. So the decision is\n// in the layout instead: importing a module never starts anything, and running this\n// one always does.\n//\n// The client names it either way: `posipaki/remote/gateway-cli.js` is a published\n// specifier, so `import.meta.resolve` answers with the built file, and a consumer\n// with a program of its own stages that instead. Nothing here works out its own\n// location — a path derived from `import.meta.url` is a guess about a layout the\n// bundler owns, and the guess is wrong the moment the module moves into a chunk.\n\nimport { GATEWAY_FAILED, runGateway } from \"./gateway.js\";\n\nvoid (async () => {\n try {\n process.exitCode = await runGateway();\n } catch (err) {\n process.stderr.write(`gateway: ${err instanceof Error ? err.message : String(err)}\\n`);\n process.exitCode = GATEWAY_FAILED;\n }\n})();\n"],"mappings":"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"}