posipaki 0.51.0 → 0.51.1

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.
@@ -43,7 +43,9 @@ function held(inner) {
43
43
  send: (frame) => inner.send(frame),
44
44
  onFrame(handler) {
45
45
  readers.add(handler);
46
- for (const frame of kept) handler(frame);
46
+ const keptNow = [...kept];
47
+ kept.length = 0;
48
+ for (const frame of keptNow) handler(frame);
47
49
  return () => {
48
50
  readers.delete(handler);
49
51
  };
@@ -200,7 +202,8 @@ function splitChannel(inner, announced = NOTHING) {
200
202
  },
201
203
  info: inner.info,
202
204
  control: (command) => inner.control(command),
203
- hasFrames: async () => false
205
+ /** A complete line is emitted the moment its bytes arrive: nothing of ours is ever standing. */
206
+ hasFrames: () => inner.hasFrames()
204
207
  });
205
208
  inner.onFrame((chunk) => {
206
209
  if (ended) return;
@@ -393,4 +396,4 @@ function named(url, error) {
393
396
  //#endregion
394
397
  export { held as a, splitChannel as i, fetchPort as n, portActor as r, HttpRefusal as t };
395
398
 
396
- //# sourceMappingURL=fetch-D72Xvuoc.js.map
399
+ //# sourceMappingURL=fetch-hZVNhkgP.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetch-hZVNhkgP.js","names":[],"sources":["../src/port/held.ts","../src/port/split.ts","../src/port/actor.ts","../src/port/fetch.ts"],"sourcesContent":["// ── a channel that keeps what nobody was reading yet ────────────────────────\n//\n// A medium can deliver a frame in the same turn a reader is being installed, and a channel with no subscriber\n// drops it. This wraps a channel so nothing is dropped for want of a listener: what arrives while nobody is\n// subscribed is kept and handed to the first reader that arrives.\n//\n// After that the channel is live, and a subscriber that comes later has missed what went before it. That is not a\n// limitation of this adapter: a channel delivers a frame once, and a channel that replayed its history to every new\n// subscriber could never say whether anything was standing for one.\nimport type { Channel } from \"./channel.js\";\n\n/**\n * `inner`, with the frames that arrive before anyone is subscribed kept for the readers that follow.\n *\n * The kept frames are not bounded, because a bound depends on what the far end may say before anyone listens,\n * and that is not something this adapter can know.\n */\nexport function held<F, C>(inner: Channel<F, C>): Channel<F, C> {\n const readers = new Set<(frame: F) => void>();\n const closers = new Set<(reason: C) => void>();\n const failers = new Set<(error: unknown) => void>();\n const kept: F[] = [];\n let live = false;\n /** The ending, kept for a reader that arrives after it: a channel that is over is not one to wait on. */\n let ending: { reason: C } | null = null;\n let failed: { error: unknown } | null = null;\n\n const emit = (frame: F): void => {\n for (const reader of [...readers]) reader(frame);\n };\n\n inner.onFrame((frame) => {\n if (live) {\n emit(frame);\n return;\n }\n if (readers.size === 0) {\n kept.push(frame);\n return;\n }\n // Somebody is reading: from here the channel is live, and what was kept has been taken.\n live = true;\n kept.length = 0;\n emit(frame);\n });\n inner.onClose((reason) => {\n ending = { reason };\n for (const closer of [...closers]) closer(reason);\n });\n inner.onError((error) => {\n failed = { error };\n for (const failer of [...failers]) failer(error);\n });\n\n return {\n send: (frame) => inner.send(frame),\n onFrame(handler) {\n readers.add(handler);\n // Handed to the first reader and taken: a frame is delivered once, and what came before this one is not a\n // later reader's to have.\n const keptNow = [...kept];\n kept.length = 0;\n for (const frame of keptNow) handler(frame);\n return () => {\n readers.delete(handler);\n };\n },\n /** What it kept is handed to whoever subscribes next; what it will *push* is the inner channel's business. */\n hasFrames: () => inner.hasFrames(),\n onClose(handler) {\n if (ending !== null) {\n handler(ending.reason);\n return () => {};\n }\n closers.add(handler);\n return () => {\n closers.delete(handler);\n };\n },\n onError(handler) {\n if (failed !== null) {\n handler(failed.error);\n return () => {};\n }\n failers.add(handler);\n return () => {\n failers.delete(handler);\n };\n },\n close: (reason) => inner.close(reason),\n info: inner.info,\n control: (command) => inner.control(command),\n };\n}\n","// ── bytes into parts: the splitter ──────────────────────────────────────────\n//\n// Cuts a stream of bytes on 0x0a; what lies between two cuts is a line. Every byte medium does this: a stdio pair,\n// a socket, an HTTP body.\n//\n// Splitting on the byte is safe for UTF-8: a continuation byte is never 0x0a, so a character cannot be cut in\n// half, and a line is decoded only when all of its octets are in hand. A character that straddles two chunks\n// waits in the buffer, which is why this file needs no decoder of its own — and no `node:` import, because\n// `posipaki/port` is the entry a browser takes.\n\nimport type { Channel, Part } from \"./channel.js\";\nimport { held } from \"./held.js\";\n\nconst NL = 0x0a;\nconst CR = 0x0d;\n\nconst EMPTY = new Uint8Array(0);\nconst decoder = new TextDecoder();\n\n/** Two octet strings as one: the one place this file would otherwise reach for `Buffer`. */\nfunction joined(first: Uint8Array, second: Uint8Array): Uint8Array {\n if (first.length === 0) return second;\n if (second.length === 0) return first;\n const whole = new Uint8Array(first.length + second.length);\n whole.set(first, 0);\n whole.set(second, first.length);\n return whole;\n}\n/** Given a line, how many raw octets follow it. Default: none, this is a plain line. */\nexport type Announcement = (line: string) => number | null;\n\nconst NOTHING: Announcement = () => null;\n\n/**\n * One byte channel in, one channel of parts out.\n *\n * The returned channel's `send` is the same rule backwards: a part becomes its line, a terminator, and the\n * octets it carried.\n */\nexport function splitChannel<C = string>(\n inner: Channel<Uint8Array, C>,\n announced: Announcement = NOTHING,\n): Channel<Part, C> {\n const readers = new Set<(part: Part) => void>();\n const closers = new Set<(reason: C) => void>();\n const failers = new Set<(error: unknown) => void>();\n\n /** Bytes that are not yet a frame: a line, or the octets a line announced. */\n let buffered: Uint8Array = EMPTY;\n /** The line whose announced octets are still arriving. */\n let pending: { line: string; bytes: number } | null = null;\n let ended = false;\n let reason: C | null = null;\n\n const emit = (part: Part): void => {\n for (const reader of [...readers]) reader(part);\n };\n\n /** The far end is gone: our own readers hear it. */\n const close = (why: C): void => {\n if (ended) return;\n ended = true;\n reason = why;\n for (const closer of [...closers]) closer(why);\n };\n\n /**\n * End it here: the far end hears a close, our own readers do not, because we are the one who asked. The\n * reason stays null: a sentence from this side is not `C`, which is what the other end had to say.\n */\n const shut = (): void => {\n if (ended) return;\n ended = true;\n };\n\n /** Hand over what the buffer holds, as far as the framing allows. */\n const drain = (): void => {\n while (!ended) {\n if (pending !== null) {\n if (buffered.length < pending.bytes) return;\n const bytes = buffered.subarray(0, pending.bytes);\n buffered = buffered.subarray(pending.bytes);\n const line = pending.line;\n pending = null;\n emit({ line, bytes: new Uint8Array(bytes) });\n continue;\n }\n const cut = buffered.indexOf(NL);\n if (cut === -1) return;\n const raw = buffered.subarray(0, cut);\n buffered = buffered.subarray(cut + 1);\n const line = raw.length > 0 && raw[raw.length - 1] === CR ? raw.subarray(0, raw.length - 1) : raw;\n const text = decoder.decode(line);\n const count = announced(text);\n if (count === null) {\n emit({ line: text, bytes: null });\n continue;\n }\n pending = { line: text, bytes: count };\n if (count === 0) {\n pending = null;\n emit({ line: text, bytes: new Uint8Array(0) });\n }\n }\n };\n\n // Built and wrapped before the inner channel is read: the medium may have kept frames for its first\n // reader, and subscribing drains them at once — a part produced then must be a reader's to find, not the\n // wire's to lose.\n const parts: Channel<Part, C> = held<Part, C>({\n send: async (part: Part) => {\n const head = new TextEncoder().encode(`${part.line}\\n`);\n await inner.send(part.bytes === null ? head : joined(head, part.bytes));\n },\n onFrame: (handler) => {\n readers.add(handler);\n return () => {\n readers.delete(handler);\n };\n },\n onClose: (handler) => {\n if (ended && reason !== null) {\n handler(reason);\n return () => {};\n }\n closers.add(handler);\n return () => {\n closers.delete(handler);\n };\n },\n onError: (handler) => {\n failers.add(handler);\n return () => {\n failers.delete(handler);\n };\n },\n close: async (why = \"closed here\") => {\n shut();\n await inner.close(why);\n },\n info: inner.info,\n control: (command) => inner.control(command),\n /** A complete line is emitted the moment its bytes arrive: nothing of ours is ever standing. */\n hasFrames: () => inner.hasFrames(),\n });\n\n inner.onFrame((chunk) => {\n if (ended) return;\n buffered = joined(buffered, chunk);\n drain();\n });\n inner.onError((error) => {\n for (const failer of [...failers]) failer(error);\n });\n inner.onClose((why) => {\n if (ended) return;\n // Whatever is left without a terminator is still a line: a peer that hangs up after writing has said\n // something, and dropping it would be the framing deciding to lose the last word.\n if (pending === null && buffered.length > 0) {\n const rest = buffered;\n buffered = EMPTY;\n emit({ line: decoder.decode(rest), bytes: null });\n }\n close(why);\n });\n\n return parts;\n}\n","// ── a port as an actor ──────────────────────────────────────────────────────\n//\n// One actor that owns one channel and speaks for it: what it is told to send goes in, what the channel delivers\n// comes out as DATA, and the way the channel ended is left in the actor's state, where a parent reads anyway.\n//\n// The channel is opened in `setup`, which the runtime awaits, so an actor that is ready has a channel: a send is\n// never asked to wait for one, and a port that cannot open fails its start rather than looking alive. What a\n// channel is — a process, a socket, a pair in memory — is `open`'s business; the actor knows only that it has one.\n\nimport type { ActorDefinition } from \"../actor-types.js\";\nimport { defineActor, defineMessages } from \"../define-actor.js\";\nimport type { Message } from \"../types.js\";\nimport type { Channel } from \"./channel.js\";\n\n/** Write this to the channel. */\nexport interface SendMessage<F> extends Message {\n type: \"SEND\";\n data: F;\n}\n\n/** Ask the channel's own world to act on what is behind it; a medium without one ignores it. */\nexport interface SignalMessage extends Message {\n type: \"SIGNAL\";\n signal: string;\n}\n\n/** A frame the channel delivered. */\nexport interface DataMessage<F> extends Message {\n type: \"DATA\";\n data: F;\n}\n\nexport type PortIn<F> = SendMessage<F> | SignalMessage;\nexport type PortOut<F> = DataMessage<F>;\n\n/** What a parent may read of a port. The ending is here because it is state, not news. */\nexport interface PortPublic<C> {\n /** The channel is open. False before it opens and after it has ended. */\n alive: boolean;\n /** How it ended, or null while it has not. */\n end: C | null;\n /** What the medium knows about itself — a process its pid — as the channel reported it. */\n info: Record<string, unknown>;\n}\n\n/** What a medium's actor is handed: a name, and a way to open the channel it will own. */\nexport interface PortActorSpec<Args, F, C = string> {\n name: string;\n /** Opens the channel this actor owns. Called once, when the actor starts. */\n open(args: Args): Promise<Channel<F, C>>;\n}\n\ntype PortState<F, C> = {\n public: PortPublic<C>;\n private: { channel: Channel<F, C>; args: unknown };\n};\n\n/**\n * An actor over one channel.\n *\n * In `SEND {data}` writes to it and `SIGNAL {signal}` asks the medium to act on what is behind it, through\n * the channel's own `control`; posipaki's `STOP` ends the actor, which closes the channel. Out `DATA {data}`\n * for every frame. The channel's ending is left in `state.end`, what the medium knows about itself in\n * `state.info`, and then the actor stops.\n */\nexport function portActor<Args, F, C = string>(\n spec: PortActorSpec<Args, F, C>,\n): ActorDefinition<Args, PortState<F, C>, PortIn<F>, PortOut<F>, {}> {\n return defineActor({\n name: spec.name,\n inMessages: defineMessages<PortIn<F>>(),\n outMessages: defineMessages<PortOut<F>>(),\n setup: async (args: Args): Promise<PortState<F, C>> => {\n const channel = await spec.open(args);\n return {\n public: { alive: true, end: null, info: channel.info },\n private: { channel, args },\n };\n },\n afterStart() {\n const { channel } = this.state.private;\n channel.onFrame((data) => {\n this.emit({ type: \"DATA\", data });\n });\n channel.onClose((reason) => {\n this.state.public.alive = false;\n this.state.public.end = reason;\n this.exit();\n });\n },\n async beforeEnd() {\n this.state.public.alive = false;\n await this.state.private.channel.close();\n },\n handlers: {\n async SEND(msg: SendMessage<F>) {\n await this.state.private.channel.send(msg.data);\n },\n SIGNAL(msg: SignalMessage) {\n this.state.private.channel.control({ signal: msg.signal });\n },\n },\n });\n}\n","// ── an HTTP request as a port ───────────────────────────────────────────────\n//\n// The response body is the channel's frames, `close()` aborts the request, and the ending is what the response\n// said about itself. A request that never got a response is a rejection, the way a spawner that cannot connect\n// is: a non-2xx, a refused connection, a promise that never settles.\n\nimport type { Channel } from \"./channel.js\";\nimport { held } from \"./held.js\";\n\n/** What a response said when its body was over. */\nexport interface HttpEnd {\n /** The status the far end answered with. The frames that came before it are its body. */\n readonly status: number;\n}\n\nexport interface FetchPortOptions {\n /** Passed to `fetch`: method, headers, body. The request's own signal is not read; `close()` aborts. */\n init?: RequestInit;\n /** How long to wait for the response head. No bound by default: a stream may be long. */\n connectMs?: number;\n}\n\n/**\n * A URL as a channel of the body it answers with.\n *\n * Frames are the chunks of the body as they arrive, so a caller reads a stream rather than waiting for a whole\n * response. `close()` aborts the request, and the far side hears it.\n */\nexport async function fetchPort(url: string, options: FetchPortOptions = {}): Promise<Channel<Uint8Array, HttpEnd>> {\n const controller = new AbortController();\n const response = await answered(url, { ...options.init, signal: controller.signal }, options.connectMs);\n\n const readers = new Set<(frame: Uint8Array) => void>();\n const closers = new Set<(reason: HttpEnd) => void>();\n const failers = new Set<(error: unknown) => void>();\n const ending: HttpEnd = { status: response.status };\n let ended = false;\n\n const end = (): void => {\n if (ended) return;\n ended = true;\n for (const closer of [...closers]) closer(ending);\n };\n\n const frames: Channel<Uint8Array, HttpEnd> = {\n send: () => Promise.reject(new Error(\"a response body has no input; send on the request instead\")),\n onFrame(handler) {\n readers.add(handler);\n return () => {\n readers.delete(handler);\n };\n },\n onClose(handler) {\n if (ended) {\n handler(ending);\n return () => {};\n }\n closers.add(handler);\n return () => {\n closers.delete(handler);\n };\n },\n onError(handler) {\n failers.add(handler);\n return () => {\n failers.delete(handler);\n };\n },\n async close() {\n controller.abort();\n await reader?.cancel().catch(() => undefined);\n },\n info: { url, status: response.status },\n control: () => {},\n hasFrames: async () => false,\n };\n\n const reader = response.body?.getReader();\n // Wrapped before the first read: a body can deliver a chunk in the same turn the port is handed over.\n const port = held(frames);\n\n const pump = async (): Promise<void> => {\n if (reader === undefined) {\n end();\n return;\n }\n try {\n for (;;) {\n const chunk = await reader.read();\n if (chunk.done) {\n end();\n return;\n }\n for (const target of [...readers]) target(chunk.value);\n }\n } catch (error) {\n for (const failer of [...failers]) failer(error);\n end();\n }\n };\n void pump();\n\n return port;\n}\n\n/** The response head, or a rejection that says why there is none. */\n/**\n * A response that is not a stream: the far end answered, and the answer was a refusal.\n *\n * The status is here as a fact and in the sentence, because a caller that decides what to do next wants the\n * number and a caller reading a log wants the words.\n */\nexport class HttpRefusal extends Error {\n constructor(\n readonly status: number,\n message: string,\n ) {\n super(message);\n this.name = \"HttpRefusal\";\n }\n}\n\nasync function answered(url: string, init: RequestInit, connectMs: number | undefined): Promise<Response> {\n const attempt = fetch(url, init).catch((error: unknown) => Promise.reject(named(url, error)));\n const response =\n connectMs === undefined\n ? await attempt\n : await Promise.race([\n attempt,\n new Promise<never>((_resolve, reject) =>\n setTimeout(() => reject(new Error(`fetchPort: ${url} answered nothing within ${connectMs}ms`)), connectMs),\n ),\n ]);\n\n if (!response.ok) {\n const body = await response.text().catch(() => \"\");\n throw new HttpRefusal(\n response.status,\n `fetchPort: ${url} answered ${response.status}${body === \"\" ? \"\" : `: ${body.slice(0, 200)}`}`,\n );\n }\n return response;\n}\n\nfunction named(url: string, error: unknown): Error {\n return new Error(`fetchPort: ${url}: ${error instanceof Error ? error.message : String(error)}`);\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index-BQH-ok2x.d.ts","names":[],"sources":["../src/port/memory.ts","../src/port/split.ts","../src/port/stream.ts","../src/port/combine.ts","../src/port/held.ts","../src/port/fetch.ts","../src/port/duplex.ts","../src/port/map.ts","../src/port/lines.ts","../src/port/testing.ts","../src/port/read.ts","../src/port/sse.ts","../src/port/node/file/file.ts"],"mappings":";;;;UAUiB,UAAU,WAAW,QAAQ;;EAE5C,KAAK;;UAGU,YAAY;EAC3B,MAAM,UAAU;EAChB,KAAK,UAAU;;;iBAgBD,kBAAkB,MAAM,YAAY;;;;KCJxC,gBAAgB;;;;;;;iBAUZ,aAAa,YAC3B,OAAO,QAAQ,YAAY,IAC3B,YAAW,eACV,QAAQ,MAAM;;;;UC1BA;EACf,MAAM;EACN,OAAO;;;;;;;;;iBAyBO,cAAc,MAAM,aAAa,QAAQ;;;;UC5BxC,QAAQ,GAAG;WACjB,QAAQ;WACR,OAAO;;;UAID,MAAM,GAAG;WACf,QAAQ;WACR,QAAQ;;;;;;;;iBAaH,IAAI,kBAAkB,GAAG,GAAG,SAAS,OAAO,GAAG,QAAQ,GAAG,MAAM,QAAQ,QAAQ,GAAG,IAAI;;;;;;;iBAmEvF,QAAQ,kBAAkB,GAAG,GAC3C,SAAS,OAAO,GAAG,QAAQ,GAAG,MAC7B,QAAQ,QAAQ,GAAG,KAAK,MAAM,GAAG;;;;;;;;;iBCvFpB,KAAK,GAAG,GAAG,OAAO,QAAQ,GAAG,KAAK,QAAQ,GAAG;;;;UCR5C;;WAEN;;UAGM;;EAEf,OAAO;;EAEP;;;;;;;;iBASoB,UAAU,aAAa,UAAS,mBAAwB,QAAQ,QAAQ,YAAY;;;;;;;;cAoF7F,oBAAoB;WAEpB;EADX,YACW,gBACT;;;;;iBCvGY,cAAc,GAAG,UAAU;WAChC,SAAS,QAAQ,GAAG;WACpB,UAAU,QAAQ,GAAG;IAC5B,QAAQ,GAAG;;;;cCNF;;;;;;;;iBASG,WAAW,GAAG,GAAG,GAC/B,OAAO,QAAQ,GAAG,IAClB,OAAO,OAAO,MAAM,WAAW,MAC/B,KAAK,OAAO,MAAM,WAAW,OAC5B,QAAQ,GAAG;;;;iBCTE,aAAa,YAAY,OAAO,QAAQ,YAAY,KAAK,gBAAgB;;;cCN5E,SAAM,iBAAmB;cACzB,SAAM,OAAW;;UAGb;EACf,MAAM;EACN;EACA;;;iBAIc;EAAe,KAAK,QAAQ;EAAmB,SAAS;;;iBAsBxD;EACd,SAAS,QAAQ;EACjB,QAAQ;EACR,QAAQ,OAAO;EACf;;;;;;;;;;;iBCDoB,YAAY,GAAG,GAAG,SAAS,QAAQ,GAAG,KAAK,QAAQ;;;;;;;;iBAcnD,iBAAiB,GAAG,GAAG,SAAS,QAAQ,GAAG,KAAK,QAAQ;iBACxD,iBAAiB,GAAG,GAAG,GAC3C,SAAS,QAAQ,GAAG,IACpB,SAAS,IACR,QAAQ,IAAI;;;;iBClCC,WAAW,GAAG,OAAO,QAAQ,MAAM,KAAK,gBAAgB;;;;;;;iBAwFxD,UAAU,GAAG,KAAK,QAAQ,YAAY,KAAK,gBAAgB;;;;iBCjG3D,YAAY,eAAe,QAAQ"}
1
+ {"version":3,"file":"index-BQH-ok2x.d.ts","names":[],"sources":["../src/port/memory.ts","../src/port/split.ts","../src/port/stream.ts","../src/port/combine.ts","../src/port/held.ts","../src/port/fetch.ts","../src/port/duplex.ts","../src/port/map.ts","../src/port/lines.ts","../src/port/testing.ts","../src/port/read.ts","../src/port/sse.ts","../src/port/node/file/file.ts"],"mappings":";;;;UAUiB,UAAU,WAAW,QAAQ;;EAE5C,KAAK;;UAGU,YAAY;EAC3B,MAAM,UAAU;EAChB,KAAK,UAAU;;;iBAgBD,kBAAkB,MAAM,YAAY;;;;KCJxC,gBAAgB;;;;;;;iBAUZ,aAAa,YAC3B,OAAO,QAAQ,YAAY,IAC3B,YAAW,eACV,QAAQ,MAAM;;;;UC1BA;EACf,MAAM;EACN,OAAO;;;;;;;;;iBAyBO,cAAc,MAAM,aAAa,QAAQ;;;;UC5BxC,QAAQ,GAAG;WACjB,QAAQ;WACR,OAAO;;;UAID,MAAM,GAAG;WACf,QAAQ;WACR,QAAQ;;;;;;;;iBAaH,IAAI,kBAAkB,GAAG,GAAG,SAAS,OAAO,GAAG,QAAQ,GAAG,MAAM,QAAQ,QAAQ,GAAG,IAAI;;;;;;;iBAmEvF,QAAQ,kBAAkB,GAAG,GAC3C,SAAS,OAAO,GAAG,QAAQ,GAAG,MAC7B,QAAQ,QAAQ,GAAG,KAAK,MAAM,GAAG;;;;;;;;;iBCxFpB,KAAK,GAAG,GAAG,OAAO,QAAQ,GAAG,KAAK,QAAQ,GAAG;;;;UCP5C;;WAEN;;UAGM;;EAEf,OAAO;;EAEP;;;;;;;;iBASoB,UAAU,aAAa,UAAS,mBAAwB,QAAQ,QAAQ,YAAY;;;;;;;;cAoF7F,oBAAoB;WAEpB;EADX,YACW,gBACT;;;;;iBCvGY,cAAc,GAAG,UAAU;WAChC,SAAS,QAAQ,GAAG;WACpB,UAAU,QAAQ,GAAG;IAC5B,QAAQ,GAAG;;;;cCNF;;;;;;;;iBASG,WAAW,GAAG,GAAG,GAC/B,OAAO,QAAQ,GAAG,IAClB,OAAO,OAAO,MAAM,WAAW,MAC/B,KAAK,OAAO,MAAM,WAAW,OAC5B,QAAQ,GAAG;;;;iBCTE,aAAa,YAAY,OAAO,QAAQ,YAAY,KAAK,gBAAgB;;;cCN5E,SAAM,iBAAmB;cACzB,SAAM,OAAW;;UAGb;EACf,MAAM;EACN;EACA;;;iBAIc;EAAe,KAAK,QAAQ;EAAmB,SAAS;;;iBAsBxD;EACd,SAAS,QAAQ;EACjB,QAAQ;EACR,QAAQ,OAAO;EACf;;;;;;;;;;;iBCDoB,YAAY,GAAG,GAAG,SAAS,QAAQ,GAAG,KAAK,QAAQ;;;;;;;;iBAcnD,iBAAiB,GAAG,GAAG,SAAS,QAAQ,GAAG,KAAK,QAAQ;iBACxD,iBAAiB,GAAG,GAAG,GAC3C,SAAS,QAAQ,GAAG,IACpB,SAAS,IACR,QAAQ,IAAI;;;;iBClCC,WAAW,GAAG,OAAO,QAAQ,MAAM,KAAK,gBAAgB;;;;;;;iBAwFxD,UAAU,GAAG,KAAK,QAAQ,YAAY,KAAK,gBAAgB;;;;iBCjG3D,YAAY,eAAe,QAAQ"}
package/dist/index.d.ts CHANGED
@@ -20,7 +20,7 @@ declare function defineActor<Args, InternalState, InMsg extends Message, OutMsg
20
20
  //#endregion
21
21
  //#region src/version.d.ts
22
22
  /** posipaki's release version. Must equal package.json's `version`. */
23
- declare const LIB_VERSION = "0.51.0";
23
+ declare const LIB_VERSION = "0.51.1";
24
24
  //#endregion
25
25
  export { type ActorConfig, type ActorContext, type ActorDecorated, type ActorDefinition, type ActorPlugin, type ActorReflection, type AnyProcess, AsyncProcess, type AsyncProcessFn, type ExitMessage, type HandlerFn, type HandlerOptions, type HookResult, LIB_VERSION, type Message, type MethodOptions, type PluginTransform, Process, type ProcessCtx, type ProcessFn, type SenderInfo, type SenderOrigin, type SpawnedFrom, type StopMessage, type WithSender, type WithoutSender, asyncify, callHook, chainHook, defineActor, defineMessages, mergeConfigs, propagateError, runDispatch, runDispatchAsync, spawn, spawnAsync, stopPropagation };
26
26
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@ import { i as runDispatch } from "./util-Brtfgv68.js";
2
2
  import { a as spawnAsync, i as runDispatchAsync, o as asyncify, t as AsyncProcess } from "./process.async-B1FqZyD1.js";
3
3
  import { n as chainHook, o as propagateError, r as mergeConfigs, s as stopPropagation, t as callHook } from "./hooks-CgXhmY4r.js";
4
4
  import { n as defineMessages, t as defineActor } from "./define-actor-DR1P1PA5.js";
5
- import { t as LIB_VERSION } from "./version-C6CYx8YW.js";
5
+ import { t as LIB_VERSION } from "./version-5peFmjFA.js";
6
6
  //#region src/process.ts
7
7
  /** @deprecated Use {@link spawnAsync} instead. */
8
8
  function spawn(fn, pname, tp) {
@@ -1,3 +1,3 @@
1
- import { _ as streamChannel, a as readMessageMaybe, c as incoming, d as SKIP, f as mapChannel, g as settled, h as all, i as readMessage, l as recording, m as portReactor, n as sseChannel, o as decode, p as duplexChannel, r as sseWriter, s as encode, t as fileChannel, u as linesChannel, v as memoryChannelPair, y as ChannelClosed } from "../port-CDK2CsXP.js";
2
- import { a as held, i as splitChannel, n as fetchPort, r as portActor, t as HttpRefusal } from "../fetch-D72Xvuoc.js";
1
+ import { _ as streamChannel, a as readMessageMaybe, c as incoming, d as SKIP, f as mapChannel, g as settled, h as all, i as readMessage, l as recording, m as portReactor, n as sseChannel, o as decode, p as duplexChannel, r as sseWriter, s as encode, t as fileChannel, u as linesChannel, v as memoryChannelPair, y as ChannelClosed } from "../port-DgOpPTSr.js";
2
+ import { a as held, i as splitChannel, n as fetchPort, r as portActor, t as HttpRefusal } from "../fetch-hZVNhkgP.js";
3
3
  export { ChannelClosed, HttpRefusal, SKIP, all, decode, duplexChannel, encode, fetchPort, fileChannel, held, incoming, linesChannel, mapChannel, memoryChannelPair, portActor, portReactor, readMessage, readMessageMaybe, recording, settled, splitChannel, sseChannel, sseWriter, streamChannel };
package/dist/port/node.js CHANGED
@@ -1,4 +1,4 @@
1
- import { a as held, i as splitChannel, r as portActor, t as HttpRefusal } from "../fetch-D72Xvuoc.js";
1
+ import { a as held, i as splitChannel, r as portActor, t as HttpRefusal } from "../fetch-hZVNhkgP.js";
2
2
  import { spawn } from "node:child_process";
3
3
  import { createServer } from "node:http";
4
4
  //#region src/port/node/spawn.ts
@@ -1,4 +1,4 @@
1
- import { a as held, i as splitChannel } from "./fetch-D72Xvuoc.js";
1
+ import { a as held, i as splitChannel } from "./fetch-hZVNhkgP.js";
2
2
  import { appendFile, open, stat } from "node:fs/promises";
3
3
  //#region src/port/channel.ts
4
4
  /** What is thrown when a frame is sent on a channel that is over. */
@@ -862,4 +862,4 @@ function fileChannel(path) {
862
862
  //#endregion
863
863
  export { streamChannel as _, readMessageMaybe as a, incoming as c, SKIP as d, mapChannel as f, settled as g, all as h, readMessage as i, recording as l, portReactor as m, sseChannel as n, decode as o, duplexChannel as p, sseWriter as r, encode as s, fileChannel as t, linesChannel as u, memoryChannelPair as v, ChannelClosed as y };
864
864
 
865
- //# sourceMappingURL=port-CDK2CsXP.js.map
865
+ //# sourceMappingURL=port-DgOpPTSr.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"port-CDK2CsXP.js","names":[],"sources":["../src/port/channel.ts","../src/port/memory.ts","../src/port/stream.ts","../src/port/combine.ts","../src/port/reactor.ts","../src/port/duplex.ts","../src/port/map.ts","../src/port/lines.ts","../src/port/testing.ts","../src/port/read.ts","../src/port/sse.ts","../src/port/node/file/read.ts","../src/port/node/file/wake.ts","../src/port/node/file/write.ts","../src/port/node/file/file.ts"],"sourcesContent":["// ── A channel ───────────────────────────────────────────────────────────────\n//\n// Carries values of one type between two ends. The type parameter is what crosses: bytes, a line and the\n// octets it announced, a decoded frame. A medium produces one; a protocol adapter wraps one into another.\n//\n// It ends one of three ways, and each has its own callback:\n//\n// close() this side ends it; the far end hears a close, this side's callers hear nothing\n// onClose the far end is gone, with the reason it gave\n// onError the wire failed; once, and always before onClose\n//\n// `close()` is idempotent. `send()` rejects once the channel is over, from either side.\n\n/**\n * A line of a channel that carries lines, and the octets it announced.\n *\n * A line may announce octets after it, as a stream chunk does on the remote seam, so a part is the line and\n * what it announced. A medium that moves whole messages, a websocket for instance, produces parts with no\n * octets. A byte medium produces none until the splitter has run.\n */\nexport interface Part {\n /** One line, without its terminator. */\n line: string;\n /** The octets the line announced, when it announced any. */\n bytes: Uint8Array | null;\n}\n\n/**\n * Values of one type, between two ends.\n *\n * `C` is what the far end says when it closes — a sentence for a medium, or whatever the medium has to say for\n * itself: a spawned process ends with an exit status, and that is the fact worth having. `close()` takes a\n * sentence from this side, because the close we ask for is ours.\n */\nexport interface Channel<F, C = string> {\n /**\n * Put a frame on it.\n *\n * Rejects when the channel is over, from either side: there is no reader left, and a resolved promise\n * would say the frame had been taken.\n */\n send(frame: F): Promise<void>;\n /** A frame arrived. The returned function stops this reader and no other. */\n onFrame(handler: (frame: F) => void): () => void;\n /**\n * Is a frame ready to be handed to a reader?\n *\n * `true` — one is standing and will be delivered. `false` — nothing is standing and nothing is being fetched,\n * so a reader would wait for something that has not started. `null` — this channel cannot say: a stream has no\n * end to reach, and answering `false` there would be a lie about the future.\n *\n * The question waits for what the medium is doing: a file being read answers once the read has finished, not\n * before. It is about now, and a source that grows a moment later answers `true` again.\n */\n hasFrames(): Promise<true | false | null>;\n /** The far end closed, and this is what it said. Once, after any frames already read. */\n onClose(handler: (reason: C) => void): () => void;\n /** The wire failed. Once, and always followed by a close. */\n onError(handler: (error: unknown) => void): () => void;\n /**\n * Close it from this side.\n *\n * Idempotent: a second call does nothing. The far end hears a close; the callers on this side do not,\n * because they are the ones who asked.\n */\n close(reason?: string): Promise<void>;\n /** What the medium knows about itself: a process its pid, a socket its peer. Empty when it knows nothing. */\n readonly info: Record<string, unknown>;\n /**\n * Ask the medium to act on what is behind the channel — signal a process, resize a terminal.\n *\n * A medium with nothing behind it does nothing. The command is the medium's own vocabulary; the channel\n * only carries it.\n */\n control(command: Record<string, unknown>): void;\n}\n\n/** What is thrown when a frame is sent on a channel that is over. */\nexport class ChannelClosed extends Error {\n constructor(reason: string) {\n super(`the channel is closed: ${reason}`);\n this.name = \"ChannelClosed\";\n }\n}\n","// ── A channel with no medium ────────────────────────────────────────────────\n//\n// Two ends over nothing: what one sends, the other reads. For testing an adapter or a protocol without a\n// socket, a child or a file, and for exercising the endings without faking one.\n//\n// No buffer: a frame reaches the other end before `send` settles.\n\nimport { ChannelClosed, type Channel } from \"./channel.js\";\n\n/** One end of a pair. `fail` is the hook this double adds: it breaks the wire the way a socket would. */\nexport interface MemoryEnd<F> extends Channel<F> {\n /** Break the wire: the far end hears an error, and then a close. */\n fail(error: unknown): void;\n}\n\nexport interface ChannelPair<F> {\n near: MemoryEnd<F>;\n far: MemoryEnd<F>;\n}\n\ntype Side = \"near\" | \"far\";\n\ninterface End<F> {\n frames: Set<(frame: F) => void>;\n closes: Set<(reason: string) => void>;\n errors: Set<(error: unknown) => void>;\n}\n\nfunction end<F>(): End<F> {\n return { frames: new Set(), closes: new Set(), errors: new Set() };\n}\n\n/** The two halves of one channel. */\nexport function memoryChannelPair<F>(): ChannelPair<F> {\n const near = end<F>();\n const far = end<F>();\n const closed: Record<Side, string | null> = { near: null, far: null };\n const other = (side: Side): Side => (side === \"near\" ? \"far\" : \"near\");\n\n /** One side's own state and the other side's, which is all a channel is. */\n const make = (side: Side): MemoryEnd<F> => {\n const mine = side === \"near\" ? near : far;\n const theirs = side === \"near\" ? far : near;\n return {\n send: async (frame: F) => {\n const ended = closed[side] ?? closed[other(side)];\n if (ended !== null) throw new ChannelClosed(ended);\n for (const handler of [...theirs.frames]) handler(frame);\n },\n onFrame: (handler) => {\n mine.frames.add(handler);\n return () => {\n mine.frames.delete(handler);\n };\n },\n // Nothing is ever kept: a frame reaches the other end before `send` settles, so a reader never waits on a\n // buffer and there is never anything standing.\n hasFrames: async () => false,\n onClose: (handler) => {\n mine.closes.add(handler);\n return () => {\n mine.closes.delete(handler);\n };\n },\n onError: (handler) => {\n mine.errors.add(handler);\n return () => {\n mine.errors.delete(handler);\n };\n },\n close: async (reason = \"closed here\") => {\n if (closed[side] !== null) return;\n const peer = other(side);\n closed[side] = reason;\n if (closed[peer] !== null) return;\n closed[peer] = reason;\n for (const handler of [...theirs.closes]) handler(reason);\n },\n info: {},\n control: () => {},\n fail: (error: unknown) => {\n if (closed[side] !== null) return;\n const peer = other(side);\n if (closed[peer] !== null) return;\n for (const handler of [...theirs.errors]) handler(error);\n for (const handler of [...theirs.closes]) handler(\"the wire failed\");\n closed[side] = \"the wire failed\";\n closed[peer] = \"the wire failed\";\n },\n };\n };\n\n return { near: make(\"near\"), far: make(\"far\") };\n}\n","// ── a stream pair as a channel of bytes ────────────────────────────────\n//\n// Chunks out as they arrive, chunks in as they are written, and an ending. Framing, splitting and the meaning\n// of a frame compose on top of this.\n//\n// A send settles when the stream has flushed the chunk, not when it has accepted it into a buffer, so a writer\n// cannot run ahead of the pipe without waiting.\n//\n// Two of the three endings are discovered here rather than declared: a read side that ends is a peer that\n// closed, and a broken stream is a wire that failed.\n\nimport type { Readable, Writable } from \"node:stream\";\n\nimport { ChannelClosed, type Channel } from \"./channel.js\";\n\n/** What the channel talks over: something to read from, something to write to. */\nexport interface StreamPair {\n read: Readable;\n write: Writable;\n}\n\n/** A write error that means the peer has already hung up. */\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 asBytes(chunk: Buffer | string): Uint8Array {\n if (typeof chunk === \"string\") return new Uint8Array(Buffer.from(chunk, \"utf8\"));\n return new Uint8Array(chunk.buffer, chunk.byteOffset, chunk.byteLength);\n}\n\n/**\n * A channel of bytes over a stream pair.\n *\n * `close()` ends the write side, so the far end hears an end of stream, and destroys the read side, so no\n * more chunks arrive after this side has said it is done. A peer that goes away is a close of this side's\n * own readers, and the reason says which of the two it was.\n */\nexport function streamChannel(pair: StreamPair): Channel<Uint8Array> {\n const frames = new Set<(frame: Uint8Array) => void>();\n const closers = new Set<(reason: string) => void>();\n const failers = new Set<(error: unknown) => void>();\n /** What this side's readers were told, and null while they have been told nothing. */\n let reported: string | null = null;\n let ended = false;\n\n const release = (): void => {\n // Best effort: a stream whose peer is gone throws from `destroy` and from `end`, and teardown is not\n // the place to find out.\n try {\n pair.read.destroy();\n } catch {\n /* already gone */\n }\n try {\n if (!pair.write.writableEnded) pair.write.end();\n } catch {\n /* already gone */\n }\n };\n\n /** End it from this side: the far end hears it, and this side's readers do not — they asked. */\n const shut = (): void => {\n if (ended) return;\n ended = true;\n release();\n };\n\n /** The far end is gone, and this side's readers hear it. */\n const finish = (reason: string): void => {\n if (ended) return;\n ended = true;\n reported = reason;\n release();\n for (const closer of [...closers]) closer(reason);\n };\n\n /** The wire failed: this side hears the error once, and then a close. */\n const fail = (error: unknown): void => {\n if (ended) return;\n ended = true;\n reported = \"the wire failed\";\n release();\n for (const failer of [...failers]) failer(error);\n for (const closer of [...closers]) closer(\"the wire failed\");\n };\n\n pair.read.on(\"data\", (chunk: Buffer | string) => {\n if (ended) return;\n const bytes = asBytes(chunk);\n for (const reader of [...frames]) reader(bytes);\n });\n pair.read.on(\"end\", () => finish(\"the far end closed\"));\n // A stream destroyed without an end — a socket whose peer vanished — says so only here.\n pair.read.on(\"close\", () => finish(\"the far end closed\"));\n pair.read.on(\"error\", (error: Error) => fail(error));\n pair.write.on(\"error\", (error: Error) => fail(error));\n\n const send = (frame: Uint8Array): Promise<void> =>\n new Promise<void>((resolve, reject) => {\n if (ended) {\n reject(new ChannelClosed(reported ?? \"closed here\"));\n return;\n }\n const done = (err?: Error | null): void => {\n if (err === undefined || err === null) {\n resolve();\n return;\n }\n if (peerGone((err as { code?: unknown }).code)) {\n finish(\"the peer is gone\");\n reject(new ChannelClosed(\"the peer is gone\"));\n return;\n }\n fail(err);\n reject(err);\n };\n try {\n pair.write.write(frame, done);\n } catch (err) {\n fail(err);\n reject(err);\n }\n });\n\n return {\n send,\n onFrame: (handler) => {\n frames.add(handler);\n return () => {\n frames.delete(handler);\n };\n },\n onClose: (handler) => {\n if (reported !== null) {\n handler(reported);\n return () => {};\n }\n closers.add(handler);\n return () => {\n closers.delete(handler);\n };\n },\n onError: (handler) => {\n failers.add(handler);\n return () => {\n failers.delete(handler);\n };\n },\n close: () => {\n shut();\n return Promise.resolve();\n },\n info: {},\n control: () => {},\n hasFrames: async () => false,\n };\n}\n","// ── several channels as one ─────────────────────────────────────────────────\n//\n// Two combinators, named after the promise pair because the choice is the same one: do you stop at the first\n// ending, or do you wait for every channel to say how it ended?\n//\n// `all` is the first: a frame from any source arrives tagged with the source, and the first ending ends the\n// combined channel with that source's reason. `settled` is the second: every ending arrives as a frame of its\n// own, tagged the same way, and the combined channel closes once all of them have.\n//\n// Neither sends. A combined channel is made of others, so a frame put on it has no destination; `send`\n// rejects and says so, and `close` closes every source.\n\nimport type { Channel } from \"./channel.js\";\n\n/** A frame, and which of the combined channels it arrived on. */\nexport interface Sourced<T, F> {\n readonly source: T;\n readonly frame: F;\n}\n\n/** An ending, and which of the combined channels ended. */\nexport interface Ended<T, C> {\n readonly source: T;\n readonly ending: C;\n}\n\nfunction sendRefusal<T>(sources: T[]): Error {\n return new Error(`this channel is made of ${sources.length}: send on one of them, not on the combination`);\n}\n\n/**\n * Every frame from every source, tagged; the first ending ends it.\n *\n * The ending is the first one to arrive, and the others are ignored afterwards. This is what a process wants\n * by default: its stdout ending means the process is gone, and that is the news.\n */\nexport function all<T extends string, F, C>(sources: Record<T, Channel<F, C>>): Channel<Sourced<T, F>, C> {\n const names = Object.keys(sources) as T[];\n const readers = new Set<(frame: Sourced<T, F>) => void>();\n const closers = new Set<(reason: C) => void>();\n const failers = new Set<(error: unknown) => void>();\n let ended = false;\n /** What the first ending said, for a reader that subscribes after it. */\n let ending: C | undefined;\n\n const end = (reason: C): void => {\n if (ended) return;\n ended = true;\n ending = reason;\n for (const closer of [...closers]) closer(reason);\n };\n\n for (const name of names) {\n const source = sources[name];\n source.onFrame((frame) => {\n for (const reader of [...readers]) reader({ source: name, frame });\n });\n source.onClose(end);\n source.onError((error) => {\n for (const failer of [...failers]) failer(error);\n });\n }\n\n return {\n send: () => Promise.reject(sendRefusal(names)),\n onFrame(handler) {\n readers.add(handler);\n return () => {\n readers.delete(handler);\n };\n },\n onClose(handler) {\n if (ending !== undefined) {\n handler(ending);\n return () => {};\n }\n closers.add(handler);\n return () => {\n closers.delete(handler);\n };\n },\n onError(handler) {\n failers.add(handler);\n return () => {\n failers.delete(handler);\n };\n },\n async close(reason?: string) {\n ended = true;\n await Promise.all(names.map((name) => sources[name].close(reason)));\n },\n info: {},\n control: () => {},\n hasFrames: async () => false,\n };\n}\n\n/**\n * Every frame from every source, tagged, and every ending as a frame of its own.\n *\n * It closes once all of them have ended, and that close carries nothing: the endings already arrived as frames,\n * each one saying which source it belongs to.\n */\nexport function settled<T extends string, F, C>(\n sources: Record<T, Channel<F, C>>,\n): Channel<Sourced<T, F> | Ended<T, C>, void> {\n const names = Object.keys(sources) as T[];\n const readers = new Set<(frame: Sourced<T, F> | Ended<T, C>) => void>();\n const closers = new Set<(reason: void) => void>();\n const failers = new Set<(error: unknown) => void>();\n let remaining = names.length;\n let ended = false;\n\n const emit = (frame: Sourced<T, F> | Ended<T, C>): void => {\n for (const reader of [...readers]) reader(frame);\n };\n\n const end = (): void => {\n if (ended) return;\n ended = true;\n for (const closer of [...closers]) closer(undefined);\n };\n\n for (const name of names) {\n const source = sources[name];\n source.onFrame((frame) => emit({ source: name, frame }));\n source.onClose((ending) => {\n emit({ source: name, ending });\n remaining -= 1;\n if (remaining === 0) end();\n });\n source.onError((error) => {\n for (const failer of [...failers]) failer(error);\n });\n }\n\n return {\n send: () => Promise.reject(sendRefusal(names)),\n onFrame(handler) {\n readers.add(handler);\n return () => {\n readers.delete(handler);\n };\n },\n onClose(handler) {\n if (ended) {\n handler(undefined);\n return () => {};\n }\n closers.add(handler);\n return () => {\n closers.delete(handler);\n };\n },\n onError(handler) {\n failers.add(handler);\n return () => {\n failers.delete(handler);\n };\n },\n async close(reason?: string) {\n ended = true;\n await Promise.all(names.map((name) => sources[name].close(reason)));\n },\n info: {},\n control: () => {},\n hasFrames: async () => false,\n };\n}\n","// ── the loop, at the port level ─────────────────────────────────────────────\n//\n// A listener yields a pair of ports per accept, and one handler runs on that pair. The same loop the connection\n// reactor runs, one level down: there the unit is a connection that speaks a protocol, here it is a pair of\n// channels and nothing above them.\n\nimport type { Channel } from \"./channel.js\";\n\n/** One accepted exchange: what the far side sends, and what we send back. */\nexport interface PortPair<In, Out, Meta = unknown, C = void> {\n readonly inbound: Channel<In, C>;\n readonly outbound: Channel<Out, C>;\n /** Whatever the listener resolved about the caller: admission, a path, a token's subject. */\n readonly meta: Meta;\n}\n\n/** Where pairs arrive. The listener owns the medium and its admission. */\nexport interface PortListener<In, Out, Meta = unknown, C = void> {\n accept(): Promise<PortPair<In, Out, Meta, C>>;\n close(): Promise<void>;\n}\n\nexport interface PortReactorOptions<In, Out, Meta, C = void> {\n /** Called once a pair has been accepted and its handler has been given it. */\n onSession?(pair: PortPair<In, Out, Meta, C>): void;\n /** Called when a session is over, with whatever the handler threw. */\n onClosed?(pair: PortPair<In, Out, Meta, C>, error: unknown): void;\n /** A handler that throws is reported here, and the loop goes on. */\n onError?(error: unknown): void;\n}\n\nexport interface PortReactor {\n /** How many handlers are running now. */\n readonly live: number;\n /** Close the listener, stop accepting, and wait for the handlers to finish. */\n stop(): Promise<void>;\n}\n\n/**\n * One handler per accepted pair, in arrival order.\n *\n * The loop ends when the listener's `accept()` rejects, which a closed listener does. A handler that throws is\n * reported and its session ends; the loop carries on with the next pair.\n */\nexport function portReactor<In, Out, Meta, C = void>(\n listener: PortListener<In, Out, Meta, C>,\n handle: (pair: PortPair<In, Out, Meta, C>) => void | Promise<void>,\n options: PortReactorOptions<In, Out, Meta, C> = {},\n): PortReactor {\n const running = new Set<Promise<void>>();\n let stopped = false;\n\n const serve = (pair: PortPair<In, Out, Meta, C>): void => {\n const session = (async () => {\n options.onSession?.(pair);\n try {\n await handle(pair);\n } catch (error) {\n options.onError?.(error);\n options.onClosed?.(pair, error);\n return;\n }\n options.onClosed?.(pair, undefined);\n })();\n running.add(session);\n void session.finally(() => running.delete(session));\n };\n\n const loop = (async () => {\n for (;;) {\n let pair: PortPair<In, Out, Meta, C>;\n try {\n pair = await listener.accept();\n } catch {\n return;\n }\n if (stopped) return;\n serve(pair);\n }\n })();\n\n return {\n get live() {\n return running.size;\n },\n async stop() {\n stopped = true;\n await listener.close();\n await loop;\n await Promise.all([...running]);\n },\n };\n}\n","// ── a pair of channels as one ───────────────────────────────────────────────\n//\n// A medium that has an inbound side and an outbound side — a request and its answer, a socket's reader and its\n// writer — arrives as two channels. A channel has one frame type, so this is only for a pair whose two sides\n// carry the same one: frames arrive from the inbound side, `send` writes to the outbound side, `close()` ends it.\n//\n// The ending is the inbound side's: when the far side has sent everything, this channel closes with whatever that\n// side said. Closing it here closes the outbound side, which is how an answer is finished.\n\nimport type { Channel } from \"./channel.js\";\n\n/** A pair whose two sides carry the same frame type, read as one channel. */\nexport function duplexChannel<F, C = void>(pair: {\n readonly inbound: Channel<F, C>;\n readonly outbound: Channel<F, C>;\n}): Channel<F, C> {\n return {\n send: (frame) => pair.outbound.send(frame),\n onFrame: (handler) => pair.inbound.onFrame(handler),\n onClose: (handler) => pair.inbound.onClose(handler),\n onError: (handler) => pair.inbound.onError(handler),\n close: async (reason) => {\n await pair.outbound.close(reason);\n },\n info: { ...pair.inbound.info, ...pair.outbound.info },\n control: (command) => pair.inbound.control(command),\n hasFrames: async () => false,\n };\n}\n","// ── one vocabulary as another ─────────────────────────────────────────────\n//\n// One layer of a stack: what this side sends is mapped down, what arrives is mapped up, and a value its mapper\n// skips goes nowhere. The ending, the info and the control of the channel below are forwarded untouched — a\n// layer above does not own the medium.\n\nimport type { Channel } from \"./channel.js\";\n\n/** What a mapper returns when a value has nothing to say in the other vocabulary. */\nexport const SKIP = Symbol('skip');\n\n/**\n * A channel of `I` over a channel of `O`.\n *\n * `down` maps what is sent and `up` maps what arrives; either may answer `SKIP`, and then nothing is written\n * or delivered. Everything else — close, error, info, control — is the channel below's own, forwarded as it\n * is, because this layer carries a vocabulary and not a medium.\n */\nexport function mapChannel<I, O, C>(\n inner: Channel<O, C>,\n down: (value: I) => O | typeof SKIP,\n up: (value: O) => I | typeof SKIP,\n): Channel<I, C> {\n return {\n async send(value: I): Promise<void> {\n const frame = down(value);\n if (frame === SKIP) return;\n await inner.send(frame);\n },\n onFrame(handler: (frame: I) => void): () => void {\n return inner.onFrame((frame: O) => {\n const value = up(frame);\n if (value === SKIP) return;\n handler(value);\n });\n },\n onClose: (handler) => inner.onClose(handler),\n onError: (handler) => inner.onError(handler),\n close: (reason) => inner.close(reason),\n get info() {\n return inner.info;\n },\n control: (command) => inner.control(command),\n hasFrames: () => inner.hasFrames(),\n };\n}\n","// ── octets, as lines ────────────────────────────────────────────────────────\n//\n// A line is handed over once its newline has arrived; what follows the last newline waits for the next read, so a\n// half-written line is not a line. Sent, a line is its octets and a newline.\n//\n// This is `splitChannel` with the announcement dropped: the cutting, the buffering of a half line and the decoding\n// of a character that straddles two chunks are the splitter's, and this file adds nothing but the vocabulary.\n\nimport type { Channel } from \"./channel.js\";\nimport { mapChannel } from \"./map.js\";\nimport { splitChannel } from \"./split.js\";\n\n/** A channel of octets, read and written as lines. */\nexport function linesChannel<C = string>(inner: Channel<Uint8Array, C>): Channel<string, C> {\n return mapChannel(\n splitChannel(inner),\n (line: string): { line: string; bytes: null } => ({ line, bytes: null }),\n (part): string => part.line,\n );\n}\n","// ── the doubles these adapters are tested against ─────────────────────────\n//\n// A port is a channel, so a double is a channel too: one that records what was written, and one the test\n// writes into. Nothing here knows what a protocol is.\n\nimport type { Channel } from \"./channel.js\";\n\nexport const encode = (text: string): Uint8Array => new TextEncoder().encode(text);\nexport const decode = (bytes: Uint8Array): string => new TextDecoder().decode(bytes);\n\n/** What was written to an outbound port: the head it was told, the frames, and whether it ended. */\nexport interface Written {\n head: Record<string, unknown> | null;\n frames: string[];\n ended: boolean;\n}\n\n/** An outbound port that records instead of writing, so a head is asserted as the command it is. */\nexport function recording(): { out: Channel<Uint8Array, void>; written: Written } {\n const written: Written = { head: null, frames: [], ended: false };\n const out: Channel<Uint8Array, void> = {\n send: async (frame) => {\n written.frames.push(decode(frame));\n },\n onFrame: () => () => {},\n onClose: () => () => {},\n onError: () => () => {},\n close: async () => {\n written.ended = true;\n },\n info: {},\n hasFrames: async () => false,\n control: (command) => {\n written.head = command['head'] as Record<string, unknown>;\n },\n };\n return { out, written };\n}\n\n/** An inbound port the test writes into, and then ends. */\nexport function incoming(): {\n inbound: Channel<Uint8Array, void>;\n write: (text: string) => void;\n bytes: (chunk: Uint8Array) => void;\n end: () => void;\n} {\n const readers = new Set<(chunk: Uint8Array) => void>();\n const closers = new Set<() => void>();\n let ended = false;\n const inbound: Channel<Uint8Array, void> = {\n send: () => Promise.reject(new Error('a request body has no input')),\n onFrame: (handler) => {\n readers.add(handler);\n return () => {\n readers.delete(handler);\n };\n },\n onClose: (handler) => {\n if (ended) {\n handler();\n return () => {};\n }\n closers.add(handler);\n return () => {\n closers.delete(handler);\n };\n },\n onError: () => () => {},\n close: async () => {\n ended = true;\n },\n info: {},\n hasFrames: async () => false,\n control: () => {},\n };\n return {\n inbound,\n bytes: (chunk) => {\n for (const reader of readers) reader(chunk);\n },\n write: (text) => {\n for (const reader of readers) reader(encode(text));\n },\n end: () => {\n ended = true;\n for (const closer of closers) closer();\n },\n };\n}\n","// ── one message at a time ─────────────────────────────────────────────────\n//\n// A channel hands a frame to whoever is subscribed when it arrives. A caller that wants one frame, now,\n// subscribes and takes the first — and the frame behind it has nowhere to go, which is what this keeps.\n\nimport { held } from \"./held.js\";\nimport type { Channel } from \"./channel.js\";\n\n/** What one channel's reads stand on: the frames nobody has asked for yet, and who is waiting for one. */\ninterface Waiters<T> {\n standing: T[];\n waiting: Array<(frame: T) => void>;\n}\n\n/**\n * One reader per channel, made the first time somebody reads it.\n *\n * The channel is wrapped in `held` here, so a frame that lands while a read is being handed out waits for the\n * next one instead of being lost. A weak table, because the reader lives exactly as long as the channel does\n * and there is one of it per channel, not one per call.\n */\nconst readers = new WeakMap<object, Waiters<unknown>>();\n\nfunction waitersFor<T, C>(channel: Channel<T, C>): Waiters<T> {\n const known = readers.get(channel) as Waiters<T> | undefined;\n if (known !== undefined) return known;\n const made: Waiters<T> = { standing: [], waiting: [] };\n readers.set(channel, made as Waiters<unknown>);\n held(channel).onFrame((frame: T) => {\n const next = made.waiting.shift();\n if (next === undefined) made.standing.push(frame);\n else next(frame);\n });\n return made;\n}\n\n/**\n * The next message on a channel, and no further.\n *\n * Reads of one channel are served in order: what arrived while a caller was waiting goes to the next caller\n * rather than being dropped. What arrived before the first read is not kept here — a channel whose early\n * frames matter is wrapped in `held` where it is made.\n */\nexport async function readMessage<T, C>(channel: Channel<T, C>): Promise<T> {\n const waiters = waitersFor(channel);\n const standing = waiters.standing.shift();\n if (standing !== undefined) return standing;\n return await new Promise<T>((resolve) => waiters.waiting.push(resolve));\n}\n\n/**\n * The next message, or `nothing` when this channel has none and nothing is coming.\n *\n * `nothing` is answered once the channel says it is quiet — `hasFrames()` answering `false` — and a channel that\n * cannot say waits instead, because \"no frame now\" is not something it can promise. What is already standing on\n * this channel is taken first, so a frame that arrived while nobody was waiting is not lost to the question.\n */\nexport async function readMessageMaybe<T, C>(channel: Channel<T, C>): Promise<T | null>;\nexport async function readMessageMaybe<T, C, N>(\n channel: Channel<T, C>,\n nothing: N,\n): Promise<T | N>;\nexport async function readMessageMaybe<T, C, N>(\n channel: Channel<T, C>,\n nothing?: N,\n): Promise<T | N | null> {\n const waiters = waitersFor(channel);\n const standing = waiters.standing.shift();\n if (standing !== undefined) return standing;\n // `false` is the channel saying it has nothing and is fetching nothing; `null` is it saying it cannot know,\n // and a reader that needs an answer waits for a frame rather than taking a silence for one.\n if ((await channel.hasFrames()) === false) return nothing ?? null;\n // A frame may have arrived while the channel was being asked, so the read re-checks what is standing before it\n // waits: the question and the queue are two views of one moment, and only one of them is atomic.\n return await readMessage(channel);\n}\n","// ── SSE: events out of lines ────────────────────────────────────────────────\n//\n// Server-sent events are a wire format, not a medium: one event is the `data:` lines that belong together,\n// joined by a newline, and an empty line ends it. Everything else on the wire belongs to the transport —\n// `event:`, `id:`, `retry:`, and a comment that starts with `:`.\n//\n// So this is an adapter over lines, the way `json1` is an adapter over parts: bytes → `splitChannel` →\n// here. What the payload *means* (JSON-RPC, a task update) is the reader's business.\n\nimport type { Channel, Part } from \"./channel.js\";\nimport { held } from \"./held.js\";\n\n/**\n * The `data` a line carries.\n *\n * `data:` is SSE's own field. A2A also answers a subscription it will not serve with one JSON document\n * instead of a stream — a JSON-RPC refusal — so a whole line that is an object is taken as an event as well.\n * Everything else on the wire (`event:`, `id:`, `retry:`, a comment) belongs to the transport.\n */\nfunction payloadOf(line: string): string | null {\n const trimmed = line.trimStart();\n if (trimmed.startsWith('data:')) return trimmed.slice('data:'.length).trimStart();\n if (trimmed.startsWith('{')) return trimmed;\n return null;\n}\n\n/** A channel of lines, read as SSE events: one value per event, the empty ones skipped. */\nexport function sseChannel<C>(parts: Channel<Part, C>): Channel<string, C> {\n const readers = new Set<(event: string) => void>();\n const closers = new Set<(reason: C) => void>();\n const failers = new Set<(error: unknown) => void>();\n /** The `data` lines of the event being read, in the order they arrived. */\n let pending: string[] = [];\n let ended = false;\n let reason: C | null = null;\n\n const deliver = (event: string): void => {\n for (const reader of readers) reader(event);\n };\n\n /** An empty line ends an event; an event with no `data` line is not one and is dropped. */\n const boundary = (): void => {\n if (pending.length === 0) return;\n const event = pending.join('\\n');\n pending = [];\n deliver(event);\n };\n\n const close = (why: C): void => {\n if (ended) return;\n ended = true;\n reason = why;\n for (const closer of closers) closer(why);\n };\n\n // Held before the lines are read: the medium may have kept what it produced for its first reader, and that\n // arrives the moment this subscribes.\n const events: Channel<string, C> = held<string, C>({\n send: () => Promise.reject(new Error('an event source has no input')),\n onFrame(handler) {\n readers.add(handler);\n return () => {\n readers.delete(handler);\n };\n },\n onClose(handler) {\n if (ended && reason !== null) {\n handler(reason);\n return () => {};\n }\n closers.add(handler);\n return () => {\n closers.delete(handler);\n };\n },\n onError(handler) {\n failers.add(handler);\n return () => {\n failers.delete(handler);\n };\n },\n close: (why) => parts.close(why),\n info: parts.info,\n control: (command) => parts.control(command),\n // The events of a stream are read as they arrive: what is standing below is the transport's business.\n hasFrames: () => parts.hasFrames(),\n });\n\n parts.onFrame(({ line }) => {\n if (ended) return;\n if (line.trim() === '') {\n boundary();\n return;\n }\n const data = payloadOf(line);\n if (data !== null) pending.push(data);\n });\n parts.onError((error) => {\n for (const failer of failers) failer(error);\n });\n parts.onClose((why) => {\n // A peer that hangs up after writing its last field has said something: the event is flushed, not lost.\n boundary();\n close(why);\n });\n\n return events;\n}\n\n/**\n * The other direction: events into a body.\n *\n * An event's lines each become a `data:` field and a blank line ends it — the inverse of `sseChannel`, so a\n * server's answer and a client's reading are one vocabulary over the same bytes.\n */\nexport function sseWriter<C>(out: Channel<Uint8Array, C>): Channel<string, C> {\n const encoder = new TextEncoder();\n return {\n send: (event: string) => {\n const fields = event.split('\\n').map((line) => `data: ${line}\\n`);\n return out.send(encoder.encode(`${fields.join('')}\\n`));\n },\n // An answer body is written, never read: a frame arriving on it is not this channel's business.\n onFrame: () => () => {},\n onClose: (handler) => out.onClose(handler),\n hasFrames: async () => false,\n onError: (handler) => out.onError(handler),\n close: (reason) => out.close(reason),\n // An answer body is written and never read, so nothing is ever standing on it.\n info: out.info,\n control: (command) => out.control(command),\n };\n}\n","// ── a file, read from an offset ─────────────────────────────────────────────\n//\n// A read names where it starts and answers with what the file holds from there, so a reader that has read once\n// asks for the rest rather than the whole file again.\n//\n// A file that is not there answers nothing: it may be written later. Any other failure reaches `onError`.\n\nimport { open } from 'node:fs/promises';\n\nimport { ChannelClosed, type Channel } from '../../channel.js';\n\n/** Where a read starts: the octets before it have already been read. */\nexport interface FileRead {\n from: number;\n}\n\n/** What a read found: the octets from that offset, and where the next read starts. */\nexport interface FileBytes {\n from: number;\n next: number;\n bytes: Uint8Array;\n}\n\n/** A message a read channel carries, either way: what is asked, and what came back. */\nexport type FileMessage = FileRead | FileBytes;\n\n/** True for a path that is not there, which a reader treats as nothing to read yet. */\nfunction isMissing(error: unknown): boolean {\n return error instanceof Error && (error as NodeJS.ErrnoException).code === 'ENOENT';\n}\n\n/** The file at `path`, read from wherever a caller says. Its end is the caller's, not the file's. */\nexport function readBinaryFile(path: string): Channel<FileMessage, string> {\n const readers = new Set<(frame: FileMessage) => void>();\n const failers = new Set<(error: unknown) => void>();\n let ended: string | null = null;\n\n return {\n async send({ from }: FileRead): Promise<void> {\n if (ended !== null) throw new ChannelClosed(ended);\n let handle;\n try {\n handle = await open(path, 'r');\n } catch (error) {\n if (isMissing(error)) return;\n for (const failer of failers) failer(error);\n return;\n }\n try {\n const { size } = await handle.stat();\n if (size <= from) return;\n const buffer = new Uint8Array(size - from);\n const { bytesRead } = await handle.read(buffer, 0, buffer.length, from);\n // Nothing to hand over is not a frame: a read that found no new octets says nothing.\n if (bytesRead === 0) return;\n const frame: FileBytes = {\n from,\n next: from + bytesRead,\n bytes: buffer.subarray(0, bytesRead),\n };\n for (const reader of readers) reader(frame);\n } finally {\n await handle.close();\n }\n },\n onFrame(handler) {\n readers.add(handler);\n return () => readers.delete(handler);\n },\n // A read has no far end to close it, so only this side can, and the side that closed it does not hear.\n onClose: () => () => {},\n onError(handler) {\n failers.add(handler);\n return () => failers.delete(handler);\n },\n close: async (reason = 'the file is closed') => {\n if (ended !== null) return;\n ended = reason;\n readers.clear();\n },\n info: { path },\n // This side is told to read, it does not push: nothing is ever standing on it.\n hasFrames: async () => false,\n control: () => {},\n };\n}\n","// ── a write, heard by every reader of the path ───────────────────────────────\n//\n// The file is the queue: a reader of a path learns that there is more to read from a writer of that path, in\n// this process and no other. Nothing watches the file, so a write by another process is read at the next write\n// this one makes.\n\n/** Every channel reading one path, and how it is woken. */\nconst waiting = new Map<string, Set<() => Promise<void>>>();\n\n/** Wake whoever reads this path, after one of them has written to it. */\nexport async function woke(path: string): Promise<void> {\n for (const wake of waiting.get(path) ?? []) await wake();\n}\n\n/** Have `wake` called whenever this path is written, until the returned function is called. */\nexport function wakeOn(path: string, wake: () => Promise<void>): () => void {\n const known = waiting.get(path);\n if (known === undefined) waiting.set(path, new Set([wake]));\n else known.add(wake);\n return () => {\n const readers = waiting.get(path);\n if (readers === undefined) return;\n readers.delete(wake);\n if (readers.size === 0) waiting.delete(path);\n };\n}\n","// ── a file, appended to ─────────────────────────────────────────────────────\n//\n// What is sent is appended, and every channel reading the same path is woken: a writer is how a reader learns\n// that there is more to read.\n\nimport { appendFile } from 'node:fs/promises';\n\nimport { ChannelClosed, type Channel } from '../../channel.js';\n\nimport { woke } from './wake.js';\n\n/** The file at `path`, appended to. It has nothing to say back, so its frames are `never`. */\nexport function writeBinaryFile(path: string): Channel<Uint8Array, never> {\n let ended: string | null = null;\n\n return {\n async send(bytes: Uint8Array): Promise<void> {\n if (ended !== null) throw new ChannelClosed(ended);\n await appendFile(path, bytes);\n await woke(path);\n },\n onFrame: () => () => {},\n onClose: () => () => {},\n onError: () => () => {},\n close: async (reason = 'the file is closed') => {\n if (ended !== null) return;\n ended = reason;\n },\n info: { path },\n // A file being appended to has nothing to hand back.\n hasFrames: async () => false,\n control: () => {},\n };\n}\n","// ── a file, both ways ───────────────────────────────────────────────────────\n//\n// One channel over one path: what is sent is appended, and what the file gained since this channel last read\n// arrives as a frame. A channel opened on a file that already holds something reads it on the first\n// subscription, so a file written while nobody read is still read.\n//\n// A write by anybody in this process wakes every channel on the path, this one included; that is how a sent\n// frame comes back to the same reader, and how two channels on one journal see one sequence.\n\nimport { stat } from 'node:fs/promises';\n\nimport { ChannelClosed, type Channel } from '../../channel.js';\n\nimport { readBinaryFile, type FileMessage } from './read.js';\nimport { wakeOn } from './wake.js';\nimport { writeBinaryFile } from './write.js';\n\n/** Where this channel has read up to: every frame it has handed over ends at this offset. */\nexport function fileChannel(path: string): Channel<Uint8Array, string> {\n const read = readBinaryFile(path);\n const write = writeBinaryFile(path);\n const readers = new Set<(bytes: Uint8Array) => void>();\n const failers = new Set<(error: unknown) => void>();\n let cursor = 0;\n let ended: string | null = null;\n /** One read at a time: two racing reads would hand the same octets over twice. */\n let reading: Promise<void> = Promise.resolve();\n\n read.onFrame((frame: FileMessage) => {\n if (!('bytes' in frame)) return;\n cursor = frame.next;\n for (const reader of readers) reader(frame.bytes);\n });\n read.onError((error) => {\n for (const failer of failers) failer(error);\n });\n\n /** How many reads are in flight: a read that is running is a frame that is coming. */\n let inFlight = 0;\n\n const again = async (): Promise<void> => {\n if (ended !== null) return;\n inFlight += 1;\n try {\n await read.send({ from: cursor });\n } finally {\n inFlight -= 1;\n }\n };\n const restart = (): Promise<void> => (reading = reading.then(again, again));\n const leave = wakeOn(path, restart);\n\n return {\n async send(bytes: Uint8Array): Promise<void> {\n if (ended !== null) throw new ChannelClosed(ended);\n // The append wakes this channel too, so what was written is read back the way any other frame is.\n await write.send(bytes);\n },\n onFrame(handler) {\n readers.add(handler);\n void restart();\n return () => readers.delete(handler);\n },\n // A file has no far end to close it, so only this side can, and the side that closed it does not hear.\n onClose: () => () => {},\n onError(handler) {\n failers.add(handler);\n return () => failers.delete(handler);\n },\n close: async (reason = 'the file is closed') => {\n if (ended !== null) return;\n ended = reason;\n leave();\n readers.clear();\n await read.close(reason);\n await write.close(reason);\n },\n info: { path },\n /**\n * Whether a frame is standing: bytes past this cursor, or a read already in flight for them.\n *\n * A file can always answer, because its length is a fact: what it holds past the cursor is what this channel\n * has not handed over yet. It grows a moment later and the answer becomes `true` again.\n */\n async hasFrames(): Promise<boolean> {\n if (ended !== null) return false;\n if (inFlight > 0) return true;\n const size = await stat(path).then((found) => found.size, () => 0);\n return size > cursor;\n },\n control: () => {},\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"port-DgOpPTSr.js","names":[],"sources":["../src/port/channel.ts","../src/port/memory.ts","../src/port/stream.ts","../src/port/combine.ts","../src/port/reactor.ts","../src/port/duplex.ts","../src/port/map.ts","../src/port/lines.ts","../src/port/testing.ts","../src/port/read.ts","../src/port/sse.ts","../src/port/node/file/read.ts","../src/port/node/file/wake.ts","../src/port/node/file/write.ts","../src/port/node/file/file.ts"],"sourcesContent":["// ── A channel ───────────────────────────────────────────────────────────────\n//\n// Carries values of one type between two ends. The type parameter is what crosses: bytes, a line and the\n// octets it announced, a decoded frame. A medium produces one; a protocol adapter wraps one into another.\n//\n// It ends one of three ways, and each has its own callback:\n//\n// close() this side ends it; the far end hears a close, this side's callers hear nothing\n// onClose the far end is gone, with the reason it gave\n// onError the wire failed; once, and always before onClose\n//\n// `close()` is idempotent. `send()` rejects once the channel is over, from either side.\n\n/**\n * A line of a channel that carries lines, and the octets it announced.\n *\n * A line may announce octets after it, as a stream chunk does on the remote seam, so a part is the line and\n * what it announced. A medium that moves whole messages, a websocket for instance, produces parts with no\n * octets. A byte medium produces none until the splitter has run.\n */\nexport interface Part {\n /** One line, without its terminator. */\n line: string;\n /** The octets the line announced, when it announced any. */\n bytes: Uint8Array | null;\n}\n\n/**\n * Values of one type, between two ends.\n *\n * `C` is what the far end says when it closes — a sentence for a medium, or whatever the medium has to say for\n * itself: a spawned process ends with an exit status, and that is the fact worth having. `close()` takes a\n * sentence from this side, because the close we ask for is ours.\n */\nexport interface Channel<F, C = string> {\n /**\n * Put a frame on it.\n *\n * Rejects when the channel is over, from either side: there is no reader left, and a resolved promise\n * would say the frame had been taken.\n */\n send(frame: F): Promise<void>;\n /** A frame arrived. The returned function stops this reader and no other. */\n onFrame(handler: (frame: F) => void): () => void;\n /**\n * Is a frame ready to be handed to a reader?\n *\n * `true` — one is standing and will be delivered. `false` — nothing is standing and nothing is being fetched,\n * so a reader would wait for something that has not started. `null` — this channel cannot say: a stream has no\n * end to reach, and answering `false` there would be a lie about the future.\n *\n * The question waits for what the medium is doing: a file being read answers once the read has finished, not\n * before. It is about now, and a source that grows a moment later answers `true` again.\n */\n hasFrames(): Promise<true | false | null>;\n /** The far end closed, and this is what it said. Once, after any frames already read. */\n onClose(handler: (reason: C) => void): () => void;\n /** The wire failed. Once, and always followed by a close. */\n onError(handler: (error: unknown) => void): () => void;\n /**\n * Close it from this side.\n *\n * Idempotent: a second call does nothing. The far end hears a close; the callers on this side do not,\n * because they are the ones who asked.\n */\n close(reason?: string): Promise<void>;\n /** What the medium knows about itself: a process its pid, a socket its peer. Empty when it knows nothing. */\n readonly info: Record<string, unknown>;\n /**\n * Ask the medium to act on what is behind the channel — signal a process, resize a terminal.\n *\n * A medium with nothing behind it does nothing. The command is the medium's own vocabulary; the channel\n * only carries it.\n */\n control(command: Record<string, unknown>): void;\n}\n\n/** What is thrown when a frame is sent on a channel that is over. */\nexport class ChannelClosed extends Error {\n constructor(reason: string) {\n super(`the channel is closed: ${reason}`);\n this.name = \"ChannelClosed\";\n }\n}\n","// ── A channel with no medium ────────────────────────────────────────────────\n//\n// Two ends over nothing: what one sends, the other reads. For testing an adapter or a protocol without a\n// socket, a child or a file, and for exercising the endings without faking one.\n//\n// No buffer: a frame reaches the other end before `send` settles.\n\nimport { ChannelClosed, type Channel } from \"./channel.js\";\n\n/** One end of a pair. `fail` is the hook this double adds: it breaks the wire the way a socket would. */\nexport interface MemoryEnd<F> extends Channel<F> {\n /** Break the wire: the far end hears an error, and then a close. */\n fail(error: unknown): void;\n}\n\nexport interface ChannelPair<F> {\n near: MemoryEnd<F>;\n far: MemoryEnd<F>;\n}\n\ntype Side = \"near\" | \"far\";\n\ninterface End<F> {\n frames: Set<(frame: F) => void>;\n closes: Set<(reason: string) => void>;\n errors: Set<(error: unknown) => void>;\n}\n\nfunction end<F>(): End<F> {\n return { frames: new Set(), closes: new Set(), errors: new Set() };\n}\n\n/** The two halves of one channel. */\nexport function memoryChannelPair<F>(): ChannelPair<F> {\n const near = end<F>();\n const far = end<F>();\n const closed: Record<Side, string | null> = { near: null, far: null };\n const other = (side: Side): Side => (side === \"near\" ? \"far\" : \"near\");\n\n /** One side's own state and the other side's, which is all a channel is. */\n const make = (side: Side): MemoryEnd<F> => {\n const mine = side === \"near\" ? near : far;\n const theirs = side === \"near\" ? far : near;\n return {\n send: async (frame: F) => {\n const ended = closed[side] ?? closed[other(side)];\n if (ended !== null) throw new ChannelClosed(ended);\n for (const handler of [...theirs.frames]) handler(frame);\n },\n onFrame: (handler) => {\n mine.frames.add(handler);\n return () => {\n mine.frames.delete(handler);\n };\n },\n // Nothing is ever kept: a frame reaches the other end before `send` settles, so a reader never waits on a\n // buffer and there is never anything standing.\n hasFrames: async () => false,\n onClose: (handler) => {\n mine.closes.add(handler);\n return () => {\n mine.closes.delete(handler);\n };\n },\n onError: (handler) => {\n mine.errors.add(handler);\n return () => {\n mine.errors.delete(handler);\n };\n },\n close: async (reason = \"closed here\") => {\n if (closed[side] !== null) return;\n const peer = other(side);\n closed[side] = reason;\n if (closed[peer] !== null) return;\n closed[peer] = reason;\n for (const handler of [...theirs.closes]) handler(reason);\n },\n info: {},\n control: () => {},\n fail: (error: unknown) => {\n if (closed[side] !== null) return;\n const peer = other(side);\n if (closed[peer] !== null) return;\n for (const handler of [...theirs.errors]) handler(error);\n for (const handler of [...theirs.closes]) handler(\"the wire failed\");\n closed[side] = \"the wire failed\";\n closed[peer] = \"the wire failed\";\n },\n };\n };\n\n return { near: make(\"near\"), far: make(\"far\") };\n}\n","// ── a stream pair as a channel of bytes ────────────────────────────────\n//\n// Chunks out as they arrive, chunks in as they are written, and an ending. Framing, splitting and the meaning\n// of a frame compose on top of this.\n//\n// A send settles when the stream has flushed the chunk, not when it has accepted it into a buffer, so a writer\n// cannot run ahead of the pipe without waiting.\n//\n// Two of the three endings are discovered here rather than declared: a read side that ends is a peer that\n// closed, and a broken stream is a wire that failed.\n\nimport type { Readable, Writable } from \"node:stream\";\n\nimport { ChannelClosed, type Channel } from \"./channel.js\";\n\n/** What the channel talks over: something to read from, something to write to. */\nexport interface StreamPair {\n read: Readable;\n write: Writable;\n}\n\n/** A write error that means the peer has already hung up. */\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 asBytes(chunk: Buffer | string): Uint8Array {\n if (typeof chunk === \"string\") return new Uint8Array(Buffer.from(chunk, \"utf8\"));\n return new Uint8Array(chunk.buffer, chunk.byteOffset, chunk.byteLength);\n}\n\n/**\n * A channel of bytes over a stream pair.\n *\n * `close()` ends the write side, so the far end hears an end of stream, and destroys the read side, so no\n * more chunks arrive after this side has said it is done. A peer that goes away is a close of this side's\n * own readers, and the reason says which of the two it was.\n */\nexport function streamChannel(pair: StreamPair): Channel<Uint8Array> {\n const frames = new Set<(frame: Uint8Array) => void>();\n const closers = new Set<(reason: string) => void>();\n const failers = new Set<(error: unknown) => void>();\n /** What this side's readers were told, and null while they have been told nothing. */\n let reported: string | null = null;\n let ended = false;\n\n const release = (): void => {\n // Best effort: a stream whose peer is gone throws from `destroy` and from `end`, and teardown is not\n // the place to find out.\n try {\n pair.read.destroy();\n } catch {\n /* already gone */\n }\n try {\n if (!pair.write.writableEnded) pair.write.end();\n } catch {\n /* already gone */\n }\n };\n\n /** End it from this side: the far end hears it, and this side's readers do not — they asked. */\n const shut = (): void => {\n if (ended) return;\n ended = true;\n release();\n };\n\n /** The far end is gone, and this side's readers hear it. */\n const finish = (reason: string): void => {\n if (ended) return;\n ended = true;\n reported = reason;\n release();\n for (const closer of [...closers]) closer(reason);\n };\n\n /** The wire failed: this side hears the error once, and then a close. */\n const fail = (error: unknown): void => {\n if (ended) return;\n ended = true;\n reported = \"the wire failed\";\n release();\n for (const failer of [...failers]) failer(error);\n for (const closer of [...closers]) closer(\"the wire failed\");\n };\n\n pair.read.on(\"data\", (chunk: Buffer | string) => {\n if (ended) return;\n const bytes = asBytes(chunk);\n for (const reader of [...frames]) reader(bytes);\n });\n pair.read.on(\"end\", () => finish(\"the far end closed\"));\n // A stream destroyed without an end — a socket whose peer vanished — says so only here.\n pair.read.on(\"close\", () => finish(\"the far end closed\"));\n pair.read.on(\"error\", (error: Error) => fail(error));\n pair.write.on(\"error\", (error: Error) => fail(error));\n\n const send = (frame: Uint8Array): Promise<void> =>\n new Promise<void>((resolve, reject) => {\n if (ended) {\n reject(new ChannelClosed(reported ?? \"closed here\"));\n return;\n }\n const done = (err?: Error | null): void => {\n if (err === undefined || err === null) {\n resolve();\n return;\n }\n if (peerGone((err as { code?: unknown }).code)) {\n finish(\"the peer is gone\");\n reject(new ChannelClosed(\"the peer is gone\"));\n return;\n }\n fail(err);\n reject(err);\n };\n try {\n pair.write.write(frame, done);\n } catch (err) {\n fail(err);\n reject(err);\n }\n });\n\n return {\n send,\n onFrame: (handler) => {\n frames.add(handler);\n return () => {\n frames.delete(handler);\n };\n },\n onClose: (handler) => {\n if (reported !== null) {\n handler(reported);\n return () => {};\n }\n closers.add(handler);\n return () => {\n closers.delete(handler);\n };\n },\n onError: (handler) => {\n failers.add(handler);\n return () => {\n failers.delete(handler);\n };\n },\n close: () => {\n shut();\n return Promise.resolve();\n },\n info: {},\n control: () => {},\n hasFrames: async () => false,\n };\n}\n","// ── several channels as one ─────────────────────────────────────────────────\n//\n// Two combinators, named after the promise pair because the choice is the same one: do you stop at the first\n// ending, or do you wait for every channel to say how it ended?\n//\n// `all` is the first: a frame from any source arrives tagged with the source, and the first ending ends the\n// combined channel with that source's reason. `settled` is the second: every ending arrives as a frame of its\n// own, tagged the same way, and the combined channel closes once all of them have.\n//\n// Neither sends. A combined channel is made of others, so a frame put on it has no destination; `send`\n// rejects and says so, and `close` closes every source.\n\nimport type { Channel } from \"./channel.js\";\n\n/** A frame, and which of the combined channels it arrived on. */\nexport interface Sourced<T, F> {\n readonly source: T;\n readonly frame: F;\n}\n\n/** An ending, and which of the combined channels ended. */\nexport interface Ended<T, C> {\n readonly source: T;\n readonly ending: C;\n}\n\nfunction sendRefusal<T>(sources: T[]): Error {\n return new Error(`this channel is made of ${sources.length}: send on one of them, not on the combination`);\n}\n\n/**\n * Every frame from every source, tagged; the first ending ends it.\n *\n * The ending is the first one to arrive, and the others are ignored afterwards. This is what a process wants\n * by default: its stdout ending means the process is gone, and that is the news.\n */\nexport function all<T extends string, F, C>(sources: Record<T, Channel<F, C>>): Channel<Sourced<T, F>, C> {\n const names = Object.keys(sources) as T[];\n const readers = new Set<(frame: Sourced<T, F>) => void>();\n const closers = new Set<(reason: C) => void>();\n const failers = new Set<(error: unknown) => void>();\n let ended = false;\n /** What the first ending said, for a reader that subscribes after it. */\n let ending: C | undefined;\n\n const end = (reason: C): void => {\n if (ended) return;\n ended = true;\n ending = reason;\n for (const closer of [...closers]) closer(reason);\n };\n\n for (const name of names) {\n const source = sources[name];\n source.onFrame((frame) => {\n for (const reader of [...readers]) reader({ source: name, frame });\n });\n source.onClose(end);\n source.onError((error) => {\n for (const failer of [...failers]) failer(error);\n });\n }\n\n return {\n send: () => Promise.reject(sendRefusal(names)),\n onFrame(handler) {\n readers.add(handler);\n return () => {\n readers.delete(handler);\n };\n },\n onClose(handler) {\n if (ending !== undefined) {\n handler(ending);\n return () => {};\n }\n closers.add(handler);\n return () => {\n closers.delete(handler);\n };\n },\n onError(handler) {\n failers.add(handler);\n return () => {\n failers.delete(handler);\n };\n },\n async close(reason?: string) {\n ended = true;\n await Promise.all(names.map((name) => sources[name].close(reason)));\n },\n info: {},\n control: () => {},\n hasFrames: async () => false,\n };\n}\n\n/**\n * Every frame from every source, tagged, and every ending as a frame of its own.\n *\n * It closes once all of them have ended, and that close carries nothing: the endings already arrived as frames,\n * each one saying which source it belongs to.\n */\nexport function settled<T extends string, F, C>(\n sources: Record<T, Channel<F, C>>,\n): Channel<Sourced<T, F> | Ended<T, C>, void> {\n const names = Object.keys(sources) as T[];\n const readers = new Set<(frame: Sourced<T, F> | Ended<T, C>) => void>();\n const closers = new Set<(reason: void) => void>();\n const failers = new Set<(error: unknown) => void>();\n let remaining = names.length;\n let ended = false;\n\n const emit = (frame: Sourced<T, F> | Ended<T, C>): void => {\n for (const reader of [...readers]) reader(frame);\n };\n\n const end = (): void => {\n if (ended) return;\n ended = true;\n for (const closer of [...closers]) closer(undefined);\n };\n\n for (const name of names) {\n const source = sources[name];\n source.onFrame((frame) => emit({ source: name, frame }));\n source.onClose((ending) => {\n emit({ source: name, ending });\n remaining -= 1;\n if (remaining === 0) end();\n });\n source.onError((error) => {\n for (const failer of [...failers]) failer(error);\n });\n }\n\n return {\n send: () => Promise.reject(sendRefusal(names)),\n onFrame(handler) {\n readers.add(handler);\n return () => {\n readers.delete(handler);\n };\n },\n onClose(handler) {\n if (ended) {\n handler(undefined);\n return () => {};\n }\n closers.add(handler);\n return () => {\n closers.delete(handler);\n };\n },\n onError(handler) {\n failers.add(handler);\n return () => {\n failers.delete(handler);\n };\n },\n async close(reason?: string) {\n ended = true;\n await Promise.all(names.map((name) => sources[name].close(reason)));\n },\n info: {},\n control: () => {},\n hasFrames: async () => false,\n };\n}\n","// ── the loop, at the port level ─────────────────────────────────────────────\n//\n// A listener yields a pair of ports per accept, and one handler runs on that pair. The same loop the connection\n// reactor runs, one level down: there the unit is a connection that speaks a protocol, here it is a pair of\n// channels and nothing above them.\n\nimport type { Channel } from \"./channel.js\";\n\n/** One accepted exchange: what the far side sends, and what we send back. */\nexport interface PortPair<In, Out, Meta = unknown, C = void> {\n readonly inbound: Channel<In, C>;\n readonly outbound: Channel<Out, C>;\n /** Whatever the listener resolved about the caller: admission, a path, a token's subject. */\n readonly meta: Meta;\n}\n\n/** Where pairs arrive. The listener owns the medium and its admission. */\nexport interface PortListener<In, Out, Meta = unknown, C = void> {\n accept(): Promise<PortPair<In, Out, Meta, C>>;\n close(): Promise<void>;\n}\n\nexport interface PortReactorOptions<In, Out, Meta, C = void> {\n /** Called once a pair has been accepted and its handler has been given it. */\n onSession?(pair: PortPair<In, Out, Meta, C>): void;\n /** Called when a session is over, with whatever the handler threw. */\n onClosed?(pair: PortPair<In, Out, Meta, C>, error: unknown): void;\n /** A handler that throws is reported here, and the loop goes on. */\n onError?(error: unknown): void;\n}\n\nexport interface PortReactor {\n /** How many handlers are running now. */\n readonly live: number;\n /** Close the listener, stop accepting, and wait for the handlers to finish. */\n stop(): Promise<void>;\n}\n\n/**\n * One handler per accepted pair, in arrival order.\n *\n * The loop ends when the listener's `accept()` rejects, which a closed listener does. A handler that throws is\n * reported and its session ends; the loop carries on with the next pair.\n */\nexport function portReactor<In, Out, Meta, C = void>(\n listener: PortListener<In, Out, Meta, C>,\n handle: (pair: PortPair<In, Out, Meta, C>) => void | Promise<void>,\n options: PortReactorOptions<In, Out, Meta, C> = {},\n): PortReactor {\n const running = new Set<Promise<void>>();\n let stopped = false;\n\n const serve = (pair: PortPair<In, Out, Meta, C>): void => {\n const session = (async () => {\n options.onSession?.(pair);\n try {\n await handle(pair);\n } catch (error) {\n options.onError?.(error);\n options.onClosed?.(pair, error);\n return;\n }\n options.onClosed?.(pair, undefined);\n })();\n running.add(session);\n void session.finally(() => running.delete(session));\n };\n\n const loop = (async () => {\n for (;;) {\n let pair: PortPair<In, Out, Meta, C>;\n try {\n pair = await listener.accept();\n } catch {\n return;\n }\n if (stopped) return;\n serve(pair);\n }\n })();\n\n return {\n get live() {\n return running.size;\n },\n async stop() {\n stopped = true;\n await listener.close();\n await loop;\n await Promise.all([...running]);\n },\n };\n}\n","// ── a pair of channels as one ───────────────────────────────────────────────\n//\n// A medium that has an inbound side and an outbound side — a request and its answer, a socket's reader and its\n// writer — arrives as two channels. A channel has one frame type, so this is only for a pair whose two sides\n// carry the same one: frames arrive from the inbound side, `send` writes to the outbound side, `close()` ends it.\n//\n// The ending is the inbound side's: when the far side has sent everything, this channel closes with whatever that\n// side said. Closing it here closes the outbound side, which is how an answer is finished.\n\nimport type { Channel } from \"./channel.js\";\n\n/** A pair whose two sides carry the same frame type, read as one channel. */\nexport function duplexChannel<F, C = void>(pair: {\n readonly inbound: Channel<F, C>;\n readonly outbound: Channel<F, C>;\n}): Channel<F, C> {\n return {\n send: (frame) => pair.outbound.send(frame),\n onFrame: (handler) => pair.inbound.onFrame(handler),\n onClose: (handler) => pair.inbound.onClose(handler),\n onError: (handler) => pair.inbound.onError(handler),\n close: async (reason) => {\n await pair.outbound.close(reason);\n },\n info: { ...pair.inbound.info, ...pair.outbound.info },\n control: (command) => pair.inbound.control(command),\n hasFrames: async () => false,\n };\n}\n","// ── one vocabulary as another ─────────────────────────────────────────────\n//\n// One layer of a stack: what this side sends is mapped down, what arrives is mapped up, and a value its mapper\n// skips goes nowhere. The ending, the info and the control of the channel below are forwarded untouched — a\n// layer above does not own the medium.\n\nimport type { Channel } from \"./channel.js\";\n\n/** What a mapper returns when a value has nothing to say in the other vocabulary. */\nexport const SKIP = Symbol('skip');\n\n/**\n * A channel of `I` over a channel of `O`.\n *\n * `down` maps what is sent and `up` maps what arrives; either may answer `SKIP`, and then nothing is written\n * or delivered. Everything else — close, error, info, control — is the channel below's own, forwarded as it\n * is, because this layer carries a vocabulary and not a medium.\n */\nexport function mapChannel<I, O, C>(\n inner: Channel<O, C>,\n down: (value: I) => O | typeof SKIP,\n up: (value: O) => I | typeof SKIP,\n): Channel<I, C> {\n return {\n async send(value: I): Promise<void> {\n const frame = down(value);\n if (frame === SKIP) return;\n await inner.send(frame);\n },\n onFrame(handler: (frame: I) => void): () => void {\n return inner.onFrame((frame: O) => {\n const value = up(frame);\n if (value === SKIP) return;\n handler(value);\n });\n },\n onClose: (handler) => inner.onClose(handler),\n onError: (handler) => inner.onError(handler),\n close: (reason) => inner.close(reason),\n get info() {\n return inner.info;\n },\n control: (command) => inner.control(command),\n hasFrames: () => inner.hasFrames(),\n };\n}\n","// ── octets, as lines ────────────────────────────────────────────────────────\n//\n// A line is handed over once its newline has arrived; what follows the last newline waits for the next read, so a\n// half-written line is not a line. Sent, a line is its octets and a newline.\n//\n// This is `splitChannel` with the announcement dropped: the cutting, the buffering of a half line and the decoding\n// of a character that straddles two chunks are the splitter's, and this file adds nothing but the vocabulary.\n\nimport type { Channel } from \"./channel.js\";\nimport { mapChannel } from \"./map.js\";\nimport { splitChannel } from \"./split.js\";\n\n/** A channel of octets, read and written as lines. */\nexport function linesChannel<C = string>(inner: Channel<Uint8Array, C>): Channel<string, C> {\n return mapChannel(\n splitChannel(inner),\n (line: string): { line: string; bytes: null } => ({ line, bytes: null }),\n (part): string => part.line,\n );\n}\n","// ── the doubles these adapters are tested against ─────────────────────────\n//\n// A port is a channel, so a double is a channel too: one that records what was written, and one the test\n// writes into. Nothing here knows what a protocol is.\n\nimport type { Channel } from \"./channel.js\";\n\nexport const encode = (text: string): Uint8Array => new TextEncoder().encode(text);\nexport const decode = (bytes: Uint8Array): string => new TextDecoder().decode(bytes);\n\n/** What was written to an outbound port: the head it was told, the frames, and whether it ended. */\nexport interface Written {\n head: Record<string, unknown> | null;\n frames: string[];\n ended: boolean;\n}\n\n/** An outbound port that records instead of writing, so a head is asserted as the command it is. */\nexport function recording(): { out: Channel<Uint8Array, void>; written: Written } {\n const written: Written = { head: null, frames: [], ended: false };\n const out: Channel<Uint8Array, void> = {\n send: async (frame) => {\n written.frames.push(decode(frame));\n },\n onFrame: () => () => {},\n onClose: () => () => {},\n onError: () => () => {},\n close: async () => {\n written.ended = true;\n },\n info: {},\n hasFrames: async () => false,\n control: (command) => {\n written.head = command['head'] as Record<string, unknown>;\n },\n };\n return { out, written };\n}\n\n/** An inbound port the test writes into, and then ends. */\nexport function incoming(): {\n inbound: Channel<Uint8Array, void>;\n write: (text: string) => void;\n bytes: (chunk: Uint8Array) => void;\n end: () => void;\n} {\n const readers = new Set<(chunk: Uint8Array) => void>();\n const closers = new Set<() => void>();\n let ended = false;\n const inbound: Channel<Uint8Array, void> = {\n send: () => Promise.reject(new Error('a request body has no input')),\n onFrame: (handler) => {\n readers.add(handler);\n return () => {\n readers.delete(handler);\n };\n },\n onClose: (handler) => {\n if (ended) {\n handler();\n return () => {};\n }\n closers.add(handler);\n return () => {\n closers.delete(handler);\n };\n },\n onError: () => () => {},\n close: async () => {\n ended = true;\n },\n info: {},\n hasFrames: async () => false,\n control: () => {},\n };\n return {\n inbound,\n bytes: (chunk) => {\n for (const reader of readers) reader(chunk);\n },\n write: (text) => {\n for (const reader of readers) reader(encode(text));\n },\n end: () => {\n ended = true;\n for (const closer of closers) closer();\n },\n };\n}\n","// ── one message at a time ─────────────────────────────────────────────────\n//\n// A channel hands a frame to whoever is subscribed when it arrives. A caller that wants one frame, now,\n// subscribes and takes the first — and the frame behind it has nowhere to go, which is what this keeps.\n\nimport { held } from \"./held.js\";\nimport type { Channel } from \"./channel.js\";\n\n/** What one channel's reads stand on: the frames nobody has asked for yet, and who is waiting for one. */\ninterface Waiters<T> {\n standing: T[];\n waiting: Array<(frame: T) => void>;\n}\n\n/**\n * One reader per channel, made the first time somebody reads it.\n *\n * The channel is wrapped in `held` here, so a frame that lands while a read is being handed out waits for the\n * next one instead of being lost. A weak table, because the reader lives exactly as long as the channel does\n * and there is one of it per channel, not one per call.\n */\nconst readers = new WeakMap<object, Waiters<unknown>>();\n\nfunction waitersFor<T, C>(channel: Channel<T, C>): Waiters<T> {\n const known = readers.get(channel) as Waiters<T> | undefined;\n if (known !== undefined) return known;\n const made: Waiters<T> = { standing: [], waiting: [] };\n readers.set(channel, made as Waiters<unknown>);\n held(channel).onFrame((frame: T) => {\n const next = made.waiting.shift();\n if (next === undefined) made.standing.push(frame);\n else next(frame);\n });\n return made;\n}\n\n/**\n * The next message on a channel, and no further.\n *\n * Reads of one channel are served in order: what arrived while a caller was waiting goes to the next caller\n * rather than being dropped. What arrived before the first read is not kept here — a channel whose early\n * frames matter is wrapped in `held` where it is made.\n */\nexport async function readMessage<T, C>(channel: Channel<T, C>): Promise<T> {\n const waiters = waitersFor(channel);\n const standing = waiters.standing.shift();\n if (standing !== undefined) return standing;\n return await new Promise<T>((resolve) => waiters.waiting.push(resolve));\n}\n\n/**\n * The next message, or `nothing` when this channel has none and nothing is coming.\n *\n * `nothing` is answered once the channel says it is quiet — `hasFrames()` answering `false` — and a channel that\n * cannot say waits instead, because \"no frame now\" is not something it can promise. What is already standing on\n * this channel is taken first, so a frame that arrived while nobody was waiting is not lost to the question.\n */\nexport async function readMessageMaybe<T, C>(channel: Channel<T, C>): Promise<T | null>;\nexport async function readMessageMaybe<T, C, N>(\n channel: Channel<T, C>,\n nothing: N,\n): Promise<T | N>;\nexport async function readMessageMaybe<T, C, N>(\n channel: Channel<T, C>,\n nothing?: N,\n): Promise<T | N | null> {\n const waiters = waitersFor(channel);\n const standing = waiters.standing.shift();\n if (standing !== undefined) return standing;\n // `false` is the channel saying it has nothing and is fetching nothing; `null` is it saying it cannot know,\n // and a reader that needs an answer waits for a frame rather than taking a silence for one.\n if ((await channel.hasFrames()) === false) return nothing ?? null;\n // A frame may have arrived while the channel was being asked, so the read re-checks what is standing before it\n // waits: the question and the queue are two views of one moment, and only one of them is atomic.\n return await readMessage(channel);\n}\n","// ── SSE: events out of lines ────────────────────────────────────────────────\n//\n// Server-sent events are a wire format, not a medium: one event is the `data:` lines that belong together,\n// joined by a newline, and an empty line ends it. Everything else on the wire belongs to the transport —\n// `event:`, `id:`, `retry:`, and a comment that starts with `:`.\n//\n// So this is an adapter over lines, the way `json1` is an adapter over parts: bytes → `splitChannel` →\n// here. What the payload *means* (JSON-RPC, a task update) is the reader's business.\n\nimport type { Channel, Part } from \"./channel.js\";\nimport { held } from \"./held.js\";\n\n/**\n * The `data` a line carries.\n *\n * `data:` is SSE's own field. A2A also answers a subscription it will not serve with one JSON document\n * instead of a stream — a JSON-RPC refusal — so a whole line that is an object is taken as an event as well.\n * Everything else on the wire (`event:`, `id:`, `retry:`, a comment) belongs to the transport.\n */\nfunction payloadOf(line: string): string | null {\n const trimmed = line.trimStart();\n if (trimmed.startsWith('data:')) return trimmed.slice('data:'.length).trimStart();\n if (trimmed.startsWith('{')) return trimmed;\n return null;\n}\n\n/** A channel of lines, read as SSE events: one value per event, the empty ones skipped. */\nexport function sseChannel<C>(parts: Channel<Part, C>): Channel<string, C> {\n const readers = new Set<(event: string) => void>();\n const closers = new Set<(reason: C) => void>();\n const failers = new Set<(error: unknown) => void>();\n /** The `data` lines of the event being read, in the order they arrived. */\n let pending: string[] = [];\n let ended = false;\n let reason: C | null = null;\n\n const deliver = (event: string): void => {\n for (const reader of readers) reader(event);\n };\n\n /** An empty line ends an event; an event with no `data` line is not one and is dropped. */\n const boundary = (): void => {\n if (pending.length === 0) return;\n const event = pending.join('\\n');\n pending = [];\n deliver(event);\n };\n\n const close = (why: C): void => {\n if (ended) return;\n ended = true;\n reason = why;\n for (const closer of closers) closer(why);\n };\n\n // Held before the lines are read: the medium may have kept what it produced for its first reader, and that\n // arrives the moment this subscribes.\n const events: Channel<string, C> = held<string, C>({\n send: () => Promise.reject(new Error('an event source has no input')),\n onFrame(handler) {\n readers.add(handler);\n return () => {\n readers.delete(handler);\n };\n },\n onClose(handler) {\n if (ended && reason !== null) {\n handler(reason);\n return () => {};\n }\n closers.add(handler);\n return () => {\n closers.delete(handler);\n };\n },\n onError(handler) {\n failers.add(handler);\n return () => {\n failers.delete(handler);\n };\n },\n close: (why) => parts.close(why),\n info: parts.info,\n control: (command) => parts.control(command),\n // The events of a stream are read as they arrive: what is standing below is the transport's business.\n hasFrames: () => parts.hasFrames(),\n });\n\n parts.onFrame(({ line }) => {\n if (ended) return;\n if (line.trim() === '') {\n boundary();\n return;\n }\n const data = payloadOf(line);\n if (data !== null) pending.push(data);\n });\n parts.onError((error) => {\n for (const failer of failers) failer(error);\n });\n parts.onClose((why) => {\n // A peer that hangs up after writing its last field has said something: the event is flushed, not lost.\n boundary();\n close(why);\n });\n\n return events;\n}\n\n/**\n * The other direction: events into a body.\n *\n * An event's lines each become a `data:` field and a blank line ends it — the inverse of `sseChannel`, so a\n * server's answer and a client's reading are one vocabulary over the same bytes.\n */\nexport function sseWriter<C>(out: Channel<Uint8Array, C>): Channel<string, C> {\n const encoder = new TextEncoder();\n return {\n send: (event: string) => {\n const fields = event.split('\\n').map((line) => `data: ${line}\\n`);\n return out.send(encoder.encode(`${fields.join('')}\\n`));\n },\n // An answer body is written, never read: a frame arriving on it is not this channel's business.\n onFrame: () => () => {},\n onClose: (handler) => out.onClose(handler),\n hasFrames: async () => false,\n onError: (handler) => out.onError(handler),\n close: (reason) => out.close(reason),\n // An answer body is written and never read, so nothing is ever standing on it.\n info: out.info,\n control: (command) => out.control(command),\n };\n}\n","// ── a file, read from an offset ─────────────────────────────────────────────\n//\n// A read names where it starts and answers with what the file holds from there, so a reader that has read once\n// asks for the rest rather than the whole file again.\n//\n// A file that is not there answers nothing: it may be written later. Any other failure reaches `onError`.\n\nimport { open } from 'node:fs/promises';\n\nimport { ChannelClosed, type Channel } from '../../channel.js';\n\n/** Where a read starts: the octets before it have already been read. */\nexport interface FileRead {\n from: number;\n}\n\n/** What a read found: the octets from that offset, and where the next read starts. */\nexport interface FileBytes {\n from: number;\n next: number;\n bytes: Uint8Array;\n}\n\n/** A message a read channel carries, either way: what is asked, and what came back. */\nexport type FileMessage = FileRead | FileBytes;\n\n/** True for a path that is not there, which a reader treats as nothing to read yet. */\nfunction isMissing(error: unknown): boolean {\n return error instanceof Error && (error as NodeJS.ErrnoException).code === 'ENOENT';\n}\n\n/** The file at `path`, read from wherever a caller says. Its end is the caller's, not the file's. */\nexport function readBinaryFile(path: string): Channel<FileMessage, string> {\n const readers = new Set<(frame: FileMessage) => void>();\n const failers = new Set<(error: unknown) => void>();\n let ended: string | null = null;\n\n return {\n async send({ from }: FileRead): Promise<void> {\n if (ended !== null) throw new ChannelClosed(ended);\n let handle;\n try {\n handle = await open(path, 'r');\n } catch (error) {\n if (isMissing(error)) return;\n for (const failer of failers) failer(error);\n return;\n }\n try {\n const { size } = await handle.stat();\n if (size <= from) return;\n const buffer = new Uint8Array(size - from);\n const { bytesRead } = await handle.read(buffer, 0, buffer.length, from);\n // Nothing to hand over is not a frame: a read that found no new octets says nothing.\n if (bytesRead === 0) return;\n const frame: FileBytes = {\n from,\n next: from + bytesRead,\n bytes: buffer.subarray(0, bytesRead),\n };\n for (const reader of readers) reader(frame);\n } finally {\n await handle.close();\n }\n },\n onFrame(handler) {\n readers.add(handler);\n return () => readers.delete(handler);\n },\n // A read has no far end to close it, so only this side can, and the side that closed it does not hear.\n onClose: () => () => {},\n onError(handler) {\n failers.add(handler);\n return () => failers.delete(handler);\n },\n close: async (reason = 'the file is closed') => {\n if (ended !== null) return;\n ended = reason;\n readers.clear();\n },\n info: { path },\n // This side is told to read, it does not push: nothing is ever standing on it.\n hasFrames: async () => false,\n control: () => {},\n };\n}\n","// ── a write, heard by every reader of the path ───────────────────────────────\n//\n// The file is the queue: a reader of a path learns that there is more to read from a writer of that path, in\n// this process and no other. Nothing watches the file, so a write by another process is read at the next write\n// this one makes.\n\n/** Every channel reading one path, and how it is woken. */\nconst waiting = new Map<string, Set<() => Promise<void>>>();\n\n/** Wake whoever reads this path, after one of them has written to it. */\nexport async function woke(path: string): Promise<void> {\n for (const wake of waiting.get(path) ?? []) await wake();\n}\n\n/** Have `wake` called whenever this path is written, until the returned function is called. */\nexport function wakeOn(path: string, wake: () => Promise<void>): () => void {\n const known = waiting.get(path);\n if (known === undefined) waiting.set(path, new Set([wake]));\n else known.add(wake);\n return () => {\n const readers = waiting.get(path);\n if (readers === undefined) return;\n readers.delete(wake);\n if (readers.size === 0) waiting.delete(path);\n };\n}\n","// ── a file, appended to ─────────────────────────────────────────────────────\n//\n// What is sent is appended, and every channel reading the same path is woken: a writer is how a reader learns\n// that there is more to read.\n\nimport { appendFile } from 'node:fs/promises';\n\nimport { ChannelClosed, type Channel } from '../../channel.js';\n\nimport { woke } from './wake.js';\n\n/** The file at `path`, appended to. It has nothing to say back, so its frames are `never`. */\nexport function writeBinaryFile(path: string): Channel<Uint8Array, never> {\n let ended: string | null = null;\n\n return {\n async send(bytes: Uint8Array): Promise<void> {\n if (ended !== null) throw new ChannelClosed(ended);\n await appendFile(path, bytes);\n await woke(path);\n },\n onFrame: () => () => {},\n onClose: () => () => {},\n onError: () => () => {},\n close: async (reason = 'the file is closed') => {\n if (ended !== null) return;\n ended = reason;\n },\n info: { path },\n // A file being appended to has nothing to hand back.\n hasFrames: async () => false,\n control: () => {},\n };\n}\n","// ── a file, both ways ───────────────────────────────────────────────────────\n//\n// One channel over one path: what is sent is appended, and what the file gained since this channel last read\n// arrives as a frame. A channel opened on a file that already holds something reads it on the first\n// subscription, so a file written while nobody read is still read.\n//\n// A write by anybody in this process wakes every channel on the path, this one included; that is how a sent\n// frame comes back to the same reader, and how two channels on one journal see one sequence.\n\nimport { stat } from 'node:fs/promises';\n\nimport { ChannelClosed, type Channel } from '../../channel.js';\n\nimport { readBinaryFile, type FileMessage } from './read.js';\nimport { wakeOn } from './wake.js';\nimport { writeBinaryFile } from './write.js';\n\n/** Where this channel has read up to: every frame it has handed over ends at this offset. */\nexport function fileChannel(path: string): Channel<Uint8Array, string> {\n const read = readBinaryFile(path);\n const write = writeBinaryFile(path);\n const readers = new Set<(bytes: Uint8Array) => void>();\n const failers = new Set<(error: unknown) => void>();\n let cursor = 0;\n let ended: string | null = null;\n /** One read at a time: two racing reads would hand the same octets over twice. */\n let reading: Promise<void> = Promise.resolve();\n\n read.onFrame((frame: FileMessage) => {\n if (!('bytes' in frame)) return;\n cursor = frame.next;\n for (const reader of readers) reader(frame.bytes);\n });\n read.onError((error) => {\n for (const failer of failers) failer(error);\n });\n\n /** How many reads are in flight: a read that is running is a frame that is coming. */\n let inFlight = 0;\n\n const again = async (): Promise<void> => {\n if (ended !== null) return;\n inFlight += 1;\n try {\n await read.send({ from: cursor });\n } finally {\n inFlight -= 1;\n }\n };\n const restart = (): Promise<void> => (reading = reading.then(again, again));\n const leave = wakeOn(path, restart);\n\n return {\n async send(bytes: Uint8Array): Promise<void> {\n if (ended !== null) throw new ChannelClosed(ended);\n // The append wakes this channel too, so what was written is read back the way any other frame is.\n await write.send(bytes);\n },\n onFrame(handler) {\n readers.add(handler);\n void restart();\n return () => readers.delete(handler);\n },\n // A file has no far end to close it, so only this side can, and the side that closed it does not hear.\n onClose: () => () => {},\n onError(handler) {\n failers.add(handler);\n return () => failers.delete(handler);\n },\n close: async (reason = 'the file is closed') => {\n if (ended !== null) return;\n ended = reason;\n leave();\n readers.clear();\n await read.close(reason);\n await write.close(reason);\n },\n info: { path },\n /**\n * Whether a frame is standing: bytes past this cursor, or a read already in flight for them.\n *\n * A file can always answer, because its length is a fact: what it holds past the cursor is what this channel\n * has not handed over yet. It grows a moment later and the answer becomes `true` again.\n */\n async hasFrames(): Promise<boolean> {\n if (ended !== null) return false;\n if (inFlight > 0) return true;\n const size = await stat(path).then((found) => found.size, () => 0);\n return size > cursor;\n },\n control: () => {},\n };\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"process-eCAv2tIS.d.ts","names":[],"sources":["../src/process.d.ts"],"mappings":";;;iBAKwB,MAAM,GAAG,GAAG,WAAW,UAAU,SAAS,WAAW,UAAU,aAAa,IAAI,UAAU,GAAG,GAAG,IAAI,KAAK,eAAe,MAAM,GAAG,IAAI,MAAM,uBAAuB,GAAG,MAAM,QAAQ,GAAG,GAAG,IAAI;;;cAGvM,QAAQ,GAAG,GAAG,WAAW,SAAS,WAAW,iBAAiB,aAAa,GAAG,GAAG,IAAI;EAC/F,YAAY,IAAI,UAAU,GAAG,GAAG,IAAI,KAAK,eAAe,MAAM,GAAG,IAAI,MAAM;EAC3E,MAAM,GAAG;EACT,QAAQ"}
1
+ {"version":3,"file":"process-eCAv2tIS.d.ts","names":[],"sources":["../src/process.ts"],"mappings":";;;iBAQgB,MAAM,GAAG,GAAG,WAAW,UAAU,SAAS,WAAW,UAAU,aAC7E,IAAI,UAAU,GAAG,GAAG,IAAI,KACxB,eACA,MAAM,GAAG,IAAI,MAAM,uBACjB,GAAG,MAAM,QAAQ,GAAG,GAAG,IAAI;;;cAMzB,QAAQ,GAAG,GAAG,WAAW,SAAS,WAAW,iBAAiB,aAAa,GAAG,GAAG,IAAI;EACzF,YAAY,IAAI,UAAU,GAAG,GAAG,IAAI,KAAK,eAAe,MAAM,GAAG,IAAI,MAAM;EAI3E,MAAM,GAAG;EAIT,QAAQ"}
@@ -1,4 +1,4 @@
1
- import { $ as readFrame, B as isRelease, C as RemoteStream, D as isStreamRef, E as isBytesRef, F as isExit, G as VERSION, H as isState, I as isInit, J as decode, K as badFrame, L as isMsg, M as errorReason, N as frameReaders, O as makeSender, P as isError, Q as json1Channel, R as isPause, S as RemoteBlob, T as isBlobRef, U as isStop, V as isResume, W as BAD_PREFIX_LIMIT, X as isBad, Y as encode, Z as json1, _ as HandshakeError, a as remoteClient, b as protoFrame, c as oneConnection, d as frameChannel, et as PROCESS_REF, f as jsonSeam, g as HANDSHAKE_TIMEOUT_MS, h as seamOf, i as CHANNEL_LOST, j as errorFrame, k as RemoteProcess, l as reactor, m as seamAnnounced, n as WebSocketTransport, o as pumpOutput, p as jsonSeamParts, q as badReason, rt as rootIdFor, s as stderrSink, t as WS_OPEN, tt as isRemoteProcess, u as serveRemoteActor, v as PROTO_KEY, w as StreamStore, x as protoVersion, y as handshake, z as isProto } from "../websocket-Cj4yT9YK.js";
1
+ import { $ as readFrame, B as isRelease, C as RemoteStream, D as isStreamRef, E as isBytesRef, F as isExit, G as VERSION, H as isState, I as isInit, J as decode, K as badFrame, L as isMsg, M as errorReason, N as frameReaders, O as makeSender, P as isError, Q as json1Channel, R as isPause, S as RemoteBlob, T as isBlobRef, U as isStop, V as isResume, W as BAD_PREFIX_LIMIT, X as isBad, Y as encode, Z as json1, _ as HandshakeError, a as remoteClient, b as protoFrame, c as oneConnection, d as frameChannel, et as PROCESS_REF, f as jsonSeam, g as HANDSHAKE_TIMEOUT_MS, h as seamOf, i as CHANNEL_LOST, j as errorFrame, k as RemoteProcess, l as reactor, m as seamAnnounced, n as WebSocketTransport, o as pumpOutput, p as jsonSeamParts, q as badReason, rt as rootIdFor, s as stderrSink, t as WS_OPEN, tt as isRemoteProcess, u as serveRemoteActor, v as PROTO_KEY, w as StreamStore, x as protoVersion, y as handshake, z as isProto } from "../websocket-CjwdJ_80.js";
2
2
  //#region src/remote/transports/worker.ts
3
3
  /** The worker encoding: native structured clone (no JSON). */
4
4
  const WORKER_VERSION = "clone.v1";
@@ -1,6 +1,6 @@
1
- import { t as LIB_VERSION } from "../version-C6CYx8YW.js";
2
- import { _ as streamChannel } from "../port-CDK2CsXP.js";
3
- import { A as channelThrough, G as VERSION, M as errorReason$1, Q as json1Channel, a as remoteClient, f as jsonSeam, h as seamOf, j as errorFrame$1, n as WebSocketTransport, nt as lowBand, o as pumpOutput, r as readParts, s as stderrSink, u as serveRemoteActor, w as StreamStore, z as isProto } from "../websocket-Cj4yT9YK.js";
1
+ import { t as LIB_VERSION } from "../version-5peFmjFA.js";
2
+ import { _ as streamChannel } from "../port-DgOpPTSr.js";
3
+ import { A as channelThrough, G as VERSION, M as errorReason$1, Q as json1Channel, a as remoteClient, f as jsonSeam, h as seamOf, j as errorFrame$1, n as WebSocketTransport, nt as lowBand, o as pumpOutput, r as readParts, s as stderrSink, u as serveRemoteActor, w as StreamStore, z as isProto } from "../websocket-CjwdJ_80.js";
4
4
  import { chmod, mkdir, mkdtemp, open, readFile, rm, stat, unlink } from "node:fs/promises";
5
5
  import { execFile, spawn } from "node:child_process";
6
6
  import { createHash, randomUUID } from "node:crypto";
@@ -1,7 +1,7 @@
1
1
  //#region src/version.ts
2
2
  /** posipaki's release version. Must equal package.json's `version`. */
3
- const LIB_VERSION = "0.51.0";
3
+ const LIB_VERSION = "0.51.1";
4
4
  //#endregion
5
5
  export { LIB_VERSION as t };
6
6
 
7
- //# sourceMappingURL=version-C6CYx8YW.js.map
7
+ //# sourceMappingURL=version-5peFmjFA.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"version-C6CYx8YW.js","names":[],"sources":["../src/version.ts"],"sourcesContent":["// ── Library identity ───────────────────────────────────────────────────────\n//\n// posipaki's own release version, as a plain inlined string. A consumer that\n// stages artifacts onto a host it knows nothing about has to name those\n// artifacts after which posipaki they speak, and the bundle that runs there has\n// no node_modules and no posipaki on disk — it can never read a file to find out.\n//\n// It is not the protocol version: that is `VERSION` in ./remote (`json.v1`), and\n// it does not move between releases. The two answer different questions.\n//\n// version.test.ts pins this to package.json, so a release that forgets to bump it\n// fails the suite rather than shipping a lie.\n\n/** posipaki's release version. Must equal package.json's `version`. */\nexport const LIB_VERSION = \"0.51.0\";\n"],"mappings":";;AAcA,MAAa,cAAc"}
1
+ {"version":3,"file":"version-5peFmjFA.js","names":[],"sources":["../src/version.ts"],"sourcesContent":["// ── Library identity ───────────────────────────────────────────────────────\n//\n// posipaki's own release version, as a plain inlined string. A consumer that\n// stages artifacts onto a host it knows nothing about has to name those\n// artifacts after which posipaki they speak, and the bundle that runs there has\n// no node_modules and no posipaki on disk — it can never read a file to find out.\n//\n// It is not the protocol version: that is `VERSION` in ./remote (`json.v1`), and\n// it does not move between releases. The two answer different questions.\n//\n// version.test.ts pins this to package.json, so a release that forgets to bump it\n// fails the suite rather than shipping a lie.\n\n/** posipaki's release version. Must equal package.json's `version`. */\nexport const LIB_VERSION = \"0.51.1\";\n"],"mappings":";;AAcA,MAAa,cAAc"}
@@ -2,8 +2,8 @@ import { r as makeWaiter } from "./util-Brtfgv68.js";
2
2
  import { r as isProcess } from "./process.async-B1FqZyD1.js";
3
3
  import { s as stopPropagation } from "./hooks-CgXhmY4r.js";
4
4
  import { t as defineActor } from "./define-actor-DR1P1PA5.js";
5
- import "./port-CDK2CsXP.js";
6
- import { a as held, i as splitChannel } from "./fetch-D72Xvuoc.js";
5
+ import "./port-DgOpPTSr.js";
6
+ import { a as held, i as splitChannel } from "./fetch-hZVNhkgP.js";
7
7
  //#region src/remote/process-ref.ts
8
8
  /** The key that marks a process reference inside an otherwise JSON value. */
9
9
  const PROCESS_REF = "$p";
@@ -3315,4 +3315,4 @@ var WebSocketTransport = class {
3315
3315
  //#endregion
3316
3316
  export { readFrame as $, channelThrough as A, isRelease as B, RemoteStream as C, isStreamRef as D, isBytesRef as E, isExit as F, VERSION as G, isState as H, isInit as I, decode as J, badFrame as K, isMsg as L, errorReason as M, frameReaders as N, makeSender as O, isError as P, json1Channel as Q, isPause as R, RemoteBlob as S, isBlobRef as T, isStop as U, isResume as V, BAD_PREFIX_LIMIT as W, isBad as X, encode as Y, json1 as Z, HandshakeError as _, remoteClient as a, protoFrame as b, oneConnection as c, frameChannel as d, PROCESS_REF as et, jsonSeam as f, HANDSHAKE_TIMEOUT_MS as g, seamOf as h, CHANNEL_LOST as i, errorFrame as j, RemoteProcess as k, reactor as l, seamAnnounced as m, WebSocketTransport as n, lowBand as nt, pumpOutput as o, jsonSeamParts as p, badReason as q, readParts as r, rootIdFor as rt, stderrSink as s, WS_OPEN as t, isRemoteProcess as tt, serveRemoteActor as u, PROTO_KEY as v, StreamStore as w, protoVersion as x, handshake as y, isProto as z };
3317
3317
 
3318
- //# sourceMappingURL=websocket-Cj4yT9YK.js.map
3318
+ //# sourceMappingURL=websocket-CjwdJ_80.js.map