posipaki 0.49.1 → 0.49.2

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.
@@ -13,6 +13,9 @@ function held(inner) {
13
13
  const failers = /* @__PURE__ */ new Set();
14
14
  const kept = [];
15
15
  let live = false;
16
+ /** The ending, kept for a reader that arrives after it: a channel that is over is not one to wait on. */
17
+ let ending = null;
18
+ let failed = null;
16
19
  const emit = (frame) => {
17
20
  for (const reader of [...readers]) reader(frame);
18
21
  };
@@ -30,9 +33,11 @@ function held(inner) {
30
33
  emit(frame);
31
34
  });
32
35
  inner.onClose((reason) => {
36
+ ending = { reason };
33
37
  for (const closer of [...closers]) closer(reason);
34
38
  });
35
39
  inner.onError((error) => {
40
+ failed = { error };
36
41
  for (const failer of [...failers]) failer(error);
37
42
  });
38
43
  return {
@@ -45,12 +50,20 @@ function held(inner) {
45
50
  };
46
51
  },
47
52
  onClose(handler) {
53
+ if (ending !== null) {
54
+ handler(ending.reason);
55
+ return () => {};
56
+ }
48
57
  closers.add(handler);
49
58
  return () => {
50
59
  closers.delete(handler);
51
60
  };
52
61
  },
53
62
  onError(handler) {
63
+ if (failed !== null) {
64
+ handler(failed.error);
65
+ return () => {};
66
+ }
54
67
  failers.add(handler);
55
68
  return () => {
56
69
  failers.delete(handler);
@@ -260,4 +273,4 @@ function portActor(spec) {
260
273
  //#endregion
261
274
  export { splitChannel as n, held as r, portActor as t };
262
275
 
263
- //# sourceMappingURL=actor-MIvmdVJD.js.map
276
+ //# sourceMappingURL=actor-B5EJRlY8.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"actor-MIvmdVJD.js","names":[],"sources":["../src/port/held.ts","../src/port/split.ts","../src/port/actor.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 every subscriber that arrives before the first frame is delivered is given it.\n//\n// The window ends at the first delivery. After that the channel is live, and a subscriber that comes later has\n// missed what went before it — which is what any live channel means, and the alternative would be an unbounded\n// copy of everything ever said.\n\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\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 for (const closer of [...closers]) closer(reason);\n });\n inner.onError((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 every subscriber that arrives before the first delivery, not only to the first.\n for (const frame of kept) handler(frame);\n return () => {\n readers.delete(handler);\n };\n },\n onClose(handler) {\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: (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. A character that straddles two chunks waits in the buffer until the rest arrives.\n//\n// Text is decoded by a StringDecoder for the same reason: half a character waits rather than becoming two\n// replacement marks.\n//\n// A line may announce octets after it. The splitter does not know that rule, so it is passed in: given a line,\n// how many raw octets follow it? The seam answers with `$chunk`; a medium with no such thing answers none.\n\nimport { StringDecoder } from \"node:string_decoder\";\n\nimport type { Channel, Part } from \"./channel.js\";\nimport { held } from \"./held.js\";\n\nconst NL = 0x0a;\nconst CR = 0x0d;\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 const decoder = new StringDecoder(\"utf8\");\n /** Bytes that are not yet a frame: a line, or the octets a line announced. */\n let buffered = Buffer.alloc(0);\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.write(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 = Buffer.from(`${part.line}\\n`, \"utf8\");\n const body = part.bytes === null ? head : Buffer.concat([head, Buffer.from(part.bytes)]);\n await inner.send(new Uint8Array(body));\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 });\n\n inner.onFrame((chunk) => {\n if (ended) return;\n buffered = buffered.length === 0 ? Buffer.from(chunk) : Buffer.concat([buffered, Buffer.from(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 = Buffer.alloc(0);\n emit({ line: decoder.write(rest) + decoder.end(), bytes: null });\n } else {\n decoder.end();\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"],"mappings":"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"}
1
+ {"version":3,"file":"actor-B5EJRlY8.js","names":[],"sources":["../src/port/held.ts","../src/port/split.ts","../src/port/actor.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 every subscriber that arrives before the first frame is delivered is given it.\n//\n// The window ends at the first delivery. After that the channel is live, and a subscriber that comes later has\n// missed what went before it — which is what any live channel means, and the alternative would be an unbounded\n// copy of everything ever said.\n\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 every subscriber that arrives before the first delivery, not only to the first.\n for (const frame of kept) handler(frame);\n return () => {\n readers.delete(handler);\n };\n },\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. A character that straddles two chunks waits in the buffer until the rest arrives.\n//\n// Text is decoded by a StringDecoder for the same reason: half a character waits rather than becoming two\n// replacement marks.\n//\n// A line may announce octets after it. The splitter does not know that rule, so it is passed in: given a line,\n// how many raw octets follow it? The seam answers with `$chunk`; a medium with no such thing answers none.\n\nimport { StringDecoder } from \"node:string_decoder\";\n\nimport type { Channel, Part } from \"./channel.js\";\nimport { held } from \"./held.js\";\n\nconst NL = 0x0a;\nconst CR = 0x0d;\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 const decoder = new StringDecoder(\"utf8\");\n /** Bytes that are not yet a frame: a line, or the octets a line announced. */\n let buffered = Buffer.alloc(0);\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.write(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 = Buffer.from(`${part.line}\\n`, \"utf8\");\n const body = part.bytes === null ? head : Buffer.concat([head, Buffer.from(part.bytes)]);\n await inner.send(new Uint8Array(body));\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 });\n\n inner.onFrame((chunk) => {\n if (ended) return;\n buffered = buffered.length === 0 ? Buffer.from(chunk) : Buffer.concat([buffered, Buffer.from(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 = Buffer.alloc(0);\n emit({ line: decoder.write(rest) + decoder.end(), bytes: null });\n } else {\n decoder.end();\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"],"mappings":"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"}
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.49.1";
23
+ declare const LIB_VERSION = "0.49.2";
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-DNJbW_di.js";
5
+ import { t as LIB_VERSION } from "./version-De-M910s.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 { a as all, c as memoryChannelPair, i as fetchPort, l as ChannelClosed, n as portReactor, o as settled, r as HttpRefusal, s as streamChannel, t as duplexChannel } from "../port-0vYKSxBM.js";
2
- import { n as splitChannel, r as held, t as portActor } from "../actor-MIvmdVJD.js";
1
+ import { a as all, c as memoryChannelPair, i as fetchPort, l as ChannelClosed, n as portReactor, o as settled, r as HttpRefusal, s as streamChannel, t as duplexChannel } from "../port-DLpNfoyX.js";
2
+ import { n as splitChannel, r as held, t as portActor } from "../actor-B5EJRlY8.js";
3
3
  export { ChannelClosed, HttpRefusal, all, duplexChannel, fetchPort, held, memoryChannelPair, portActor, portReactor, settled, splitChannel, streamChannel };
package/dist/port/node.js CHANGED
@@ -1,4 +1,4 @@
1
- import { n as splitChannel, r as held, t as portActor } from "../actor-MIvmdVJD.js";
1
+ import { n as splitChannel, r as held, t as portActor } from "../actor-B5EJRlY8.js";
2
2
  import { spawn } from "node:child_process";
3
3
  //#region src/port/node/spawn.ts
4
4
  const DEFAULT_KILL_AFTER_MS = 5e3;
@@ -1,4 +1,4 @@
1
- import { r as held } from "./actor-MIvmdVJD.js";
1
+ import { r as held } from "./actor-B5EJRlY8.js";
2
2
  //#region src/port/channel.ts
3
3
  /** What is thrown when a frame is sent on a channel that is over. */
4
4
  var ChannelClosed = class extends Error {
@@ -521,4 +521,4 @@ function duplexChannel(pair) {
521
521
  //#endregion
522
522
  export { all as a, memoryChannelPair as c, fetchPort as i, ChannelClosed as l, portReactor as n, settled as o, HttpRefusal as r, streamChannel as s, duplexChannel as t };
523
523
 
524
- //# sourceMappingURL=port-0vYKSxBM.js.map
524
+ //# sourceMappingURL=port-DLpNfoyX.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"port-0vYKSxBM.js","names":[],"sources":["../src/port/channel.ts","../src/port/memory.ts","../src/port/stream.ts","../src/port/combine.ts","../src/port/fetch.ts","../src/port/reactor.ts","../src/port/duplex.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 /** 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 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 };\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 };\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 };\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 };\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","// ── 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 };\n}\n"],"mappings":";;;AAmEA,IAAa,gBAAb,cAAmC,MAAM;CACvC,YAAY,QAAgB;EAC1B,MAAM,0BAA0B,QAAQ;EACxC,KAAK,OAAO;CACd;AACF;;;AC5CA,SAAS,MAAiB;CACxB,OAAO;EAAE,wBAAQ,IAAI,IAAI;EAAG,wBAAQ,IAAI,IAAI;EAAG,wBAAQ,IAAI,IAAI;CAAE;AACnE;;AAGA,SAAgB,oBAAuC;CACrD,MAAM,OAAO,IAAO;CACpB,MAAM,MAAM,IAAO;CACnB,MAAM,SAAsC;EAAE,MAAM;EAAM,KAAK;CAAK;CACpE,MAAM,SAAS,SAAsB,SAAS,SAAS,QAAQ;;CAG/D,MAAM,QAAQ,SAA6B;EACzC,MAAM,OAAO,SAAS,SAAS,OAAO;EACtC,MAAM,SAAS,SAAS,SAAS,MAAM;EACvC,OAAO;GACL,MAAM,OAAO,UAAa;IACxB,MAAM,QAAQ,OAAO,SAAS,OAAO,MAAM,IAAI;IAC/C,IAAI,UAAU,MAAM,MAAM,IAAI,cAAc,KAAK;IACjD,KAAK,MAAM,WAAW,CAAC,GAAG,OAAO,MAAM,GAAG,QAAQ,KAAK;GACzD;GACA,UAAU,YAAY;IACpB,KAAK,OAAO,IAAI,OAAO;IACvB,aAAa;KACX,KAAK,OAAO,OAAO,OAAO;IAC5B;GACF;GACA,UAAU,YAAY;IACpB,KAAK,OAAO,IAAI,OAAO;IACvB,aAAa;KACX,KAAK,OAAO,OAAO,OAAO;IAC5B;GACF;GACA,UAAU,YAAY;IACpB,KAAK,OAAO,IAAI,OAAO;IACvB,aAAa;KACX,KAAK,OAAO,OAAO,OAAO;IAC5B;GACF;GACA,OAAO,OAAO,SAAS,kBAAkB;IACvC,IAAI,OAAO,UAAU,MAAM;IAC3B,MAAM,OAAO,MAAM,IAAI;IACvB,OAAO,QAAQ;IACf,IAAI,OAAO,UAAU,MAAM;IAC3B,OAAO,QAAQ;IACf,KAAK,MAAM,WAAW,CAAC,GAAG,OAAO,MAAM,GAAG,QAAQ,MAAM;GAC1D;GACA,MAAM,CAAC;GACP,eAAe,CAAC;GAChB,OAAO,UAAmB;IACxB,IAAI,OAAO,UAAU,MAAM;IAC3B,MAAM,OAAO,MAAM,IAAI;IACvB,IAAI,OAAO,UAAU,MAAM;IAC3B,KAAK,MAAM,WAAW,CAAC,GAAG,OAAO,MAAM,GAAG,QAAQ,KAAK;IACvD,KAAK,MAAM,WAAW,CAAC,GAAG,OAAO,MAAM,GAAG,QAAQ,iBAAiB;IACnE,OAAO,QAAQ;IACf,OAAO,QAAQ;GACjB;EACF;CACF;CAEA,OAAO;EAAE,MAAM,KAAK,MAAM;EAAG,KAAK,KAAK,KAAK;CAAE;AAChD;;;;ACpEA,SAAS,SAAS,MAAwB;CACxC,OACE,SAAS,WACT,SAAS,0BACT,SAAS,gCACT,SAAS;AAEb;AAEA,SAAS,QAAQ,OAAoC;CACnD,IAAI,OAAO,UAAU,UAAU,OAAO,IAAI,WAAW,OAAO,KAAK,OAAO,MAAM,CAAC;CAC/E,OAAO,IAAI,WAAW,MAAM,QAAQ,MAAM,YAAY,MAAM,UAAU;AACxE;;;;;;;;AASA,SAAgB,cAAc,MAAuC;CACnE,MAAM,yBAAS,IAAI,IAAiC;CACpD,MAAM,0BAAU,IAAI,IAA8B;CAClD,MAAM,0BAAU,IAAI,IAA8B;;CAElD,IAAI,WAA0B;CAC9B,IAAI,QAAQ;CAEZ,MAAM,gBAAsB;EAG1B,IAAI;GACF,KAAK,KAAK,QAAQ;EACpB,QAAQ,CAER;EACA,IAAI;GACF,IAAI,CAAC,KAAK,MAAM,eAAe,KAAK,MAAM,IAAI;EAChD,QAAQ,CAER;CACF;;CAGA,MAAM,aAAmB;EACvB,IAAI,OAAO;EACX,QAAQ;EACR,QAAQ;CACV;;CAGA,MAAM,UAAU,WAAyB;EACvC,IAAI,OAAO;EACX,QAAQ;EACR,WAAW;EACX,QAAQ;EACR,KAAK,MAAM,UAAU,CAAC,GAAG,OAAO,GAAG,OAAO,MAAM;CAClD;;CAGA,MAAM,QAAQ,UAAyB;EACrC,IAAI,OAAO;EACX,QAAQ;EACR,WAAW;EACX,QAAQ;EACR,KAAK,MAAM,UAAU,CAAC,GAAG,OAAO,GAAG,OAAO,KAAK;EAC/C,KAAK,MAAM,UAAU,CAAC,GAAG,OAAO,GAAG,OAAO,iBAAiB;CAC7D;CAEA,KAAK,KAAK,GAAG,SAAS,UAA2B;EAC/C,IAAI,OAAO;EACX,MAAM,QAAQ,QAAQ,KAAK;EAC3B,KAAK,MAAM,UAAU,CAAC,GAAG,MAAM,GAAG,OAAO,KAAK;CAChD,CAAC;CACD,KAAK,KAAK,GAAG,aAAa,OAAO,oBAAoB,CAAC;CAEtD,KAAK,KAAK,GAAG,eAAe,OAAO,oBAAoB,CAAC;CACxD,KAAK,KAAK,GAAG,UAAU,UAAiB,KAAK,KAAK,CAAC;CACnD,KAAK,MAAM,GAAG,UAAU,UAAiB,KAAK,KAAK,CAAC;CAEpD,MAAM,QAAQ,UACZ,IAAI,SAAe,SAAS,WAAW;EACrC,IAAI,OAAO;GACT,OAAO,IAAI,cAAc,YAAY,aAAa,CAAC;GACnD;EACF;EACA,MAAM,QAAQ,QAA6B;GACzC,IAAI,QAAQ,KAAA,KAAa,QAAQ,MAAM;IACrC,QAAQ;IACR;GACF;GACA,IAAI,SAAU,IAA2B,IAAI,GAAG;IAC9C,OAAO,kBAAkB;IACzB,OAAO,IAAI,cAAc,kBAAkB,CAAC;IAC5C;GACF;GACA,KAAK,GAAG;GACR,OAAO,GAAG;EACZ;EACA,IAAI;GACF,KAAK,MAAM,MAAM,OAAO,IAAI;EAC9B,SAAS,KAAK;GACZ,KAAK,GAAG;GACR,OAAO,GAAG;EACZ;CACF,CAAC;CAEH,OAAO;EACL;EACA,UAAU,YAAY;GACpB,OAAO,IAAI,OAAO;GAClB,aAAa;IACX,OAAO,OAAO,OAAO;GACvB;EACF;EACA,UAAU,YAAY;GACpB,IAAI,aAAa,MAAM;IACrB,QAAQ,QAAQ;IAChB,aAAa,CAAC;GAChB;GACA,QAAQ,IAAI,OAAO;GACnB,aAAa;IACX,QAAQ,OAAO,OAAO;GACxB;EACF;EACA,UAAU,YAAY;GACpB,QAAQ,IAAI,OAAO;GACnB,aAAa;IACX,QAAQ,OAAO,OAAO;GACxB;EACF;EACA,aAAa;GACX,KAAK;GACL,OAAO,QAAQ,QAAQ;EACzB;EACA,MAAM,CAAC;EACP,eAAe,CAAC;CAClB;AACF;;;ACvIA,SAAS,YAAe,SAAqB;CAC3C,uBAAO,IAAI,MAAM,2BAA2B,QAAQ,OAAO,8CAA8C;AAC3G;;;;;;;AAQA,SAAgB,IAA4B,SAA8D;CACxG,MAAM,QAAQ,OAAO,KAAK,OAAO;CACjC,MAAM,0BAAU,IAAI,IAAoC;CACxD,MAAM,0BAAU,IAAI,IAAyB;CAC7C,MAAM,0BAAU,IAAI,IAA8B;CAClD,IAAI,QAAQ;;CAEZ,IAAI;CAEJ,MAAM,OAAO,WAAoB;EAC/B,IAAI,OAAO;EACX,QAAQ;EACR,SAAS;EACT,KAAK,MAAM,UAAU,CAAC,GAAG,OAAO,GAAG,OAAO,MAAM;CAClD;CAEA,KAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,SAAS,QAAQ;EACvB,OAAO,SAAS,UAAU;GACxB,KAAK,MAAM,UAAU,CAAC,GAAG,OAAO,GAAG,OAAO;IAAE,QAAQ;IAAM;GAAM,CAAC;EACnE,CAAC;EACD,OAAO,QAAQ,GAAG;EAClB,OAAO,SAAS,UAAU;GACxB,KAAK,MAAM,UAAU,CAAC,GAAG,OAAO,GAAG,OAAO,KAAK;EACjD,CAAC;CACH;CAEA,OAAO;EACL,YAAY,QAAQ,OAAO,YAAY,KAAK,CAAC;EAC7C,QAAQ,SAAS;GACf,QAAQ,IAAI,OAAO;GACnB,aAAa;IACX,QAAQ,OAAO,OAAO;GACxB;EACF;EACA,QAAQ,SAAS;GACf,IAAI,WAAW,KAAA,GAAW;IACxB,QAAQ,MAAM;IACd,aAAa,CAAC;GAChB;GACA,QAAQ,IAAI,OAAO;GACnB,aAAa;IACX,QAAQ,OAAO,OAAO;GACxB;EACF;EACA,QAAQ,SAAS;GACf,QAAQ,IAAI,OAAO;GACnB,aAAa;IACX,QAAQ,OAAO,OAAO;GACxB;EACF;EACA,MAAM,MAAM,QAAiB;GAC3B,QAAQ;GACR,MAAM,QAAQ,IAAI,MAAM,KAAK,SAAS,QAAQ,KAAK,CAAC,MAAM,MAAM,CAAC,CAAC;EACpE;EACA,MAAM,CAAC;EACP,eAAe,CAAC;CAClB;AACF;;;;;;;AAQA,SAAgB,QACd,SAC4C;CAC5C,MAAM,QAAQ,OAAO,KAAK,OAAO;CACjC,MAAM,0BAAU,IAAI,IAAkD;CACtE,MAAM,0BAAU,IAAI,IAA4B;CAChD,MAAM,0BAAU,IAAI,IAA8B;CAClD,IAAI,YAAY,MAAM;CACtB,IAAI,QAAQ;CAEZ,MAAM,QAAQ,UAA6C;EACzD,KAAK,MAAM,UAAU,CAAC,GAAG,OAAO,GAAG,OAAO,KAAK;CACjD;CAEA,MAAM,YAAkB;EACtB,IAAI,OAAO;EACX,QAAQ;EACR,KAAK,MAAM,UAAU,CAAC,GAAG,OAAO,GAAG,OAAO,KAAA,CAAS;CACrD;CAEA,KAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,SAAS,QAAQ;EACvB,OAAO,SAAS,UAAU,KAAK;GAAE,QAAQ;GAAM;EAAM,CAAC,CAAC;EACvD,OAAO,SAAS,WAAW;GACzB,KAAK;IAAE,QAAQ;IAAM;GAAO,CAAC;GAC7B,aAAa;GACb,IAAI,cAAc,GAAG,IAAI;EAC3B,CAAC;EACD,OAAO,SAAS,UAAU;GACxB,KAAK,MAAM,UAAU,CAAC,GAAG,OAAO,GAAG,OAAO,KAAK;EACjD,CAAC;CACH;CAEA,OAAO;EACL,YAAY,QAAQ,OAAO,YAAY,KAAK,CAAC;EAC7C,QAAQ,SAAS;GACf,QAAQ,IAAI,OAAO;GACnB,aAAa;IACX,QAAQ,OAAO,OAAO;GACxB;EACF;EACA,QAAQ,SAAS;GACf,IAAI,OAAO;IACT,QAAQ,KAAA,CAAS;IACjB,aAAa,CAAC;GAChB;GACA,QAAQ,IAAI,OAAO;GACnB,aAAa;IACX,QAAQ,OAAO,OAAO;GACxB;EACF;EACA,QAAQ,SAAS;GACf,QAAQ,IAAI,OAAO;GACnB,aAAa;IACX,QAAQ,OAAO,OAAO;GACxB;EACF;EACA,MAAM,MAAM,QAAiB;GAC3B,QAAQ;GACR,MAAM,QAAQ,IAAI,MAAM,KAAK,SAAS,QAAQ,KAAK,CAAC,MAAM,MAAM,CAAC,CAAC;EACpE;EACA,MAAM,CAAC;EACP,eAAe,CAAC;CAClB;AACF;;;;;;;;;AC1IA,eAAsB,UAAU,KAAa,UAA4B,CAAC,GAA0C;CAClH,MAAM,aAAa,IAAI,gBAAgB;CACvC,MAAM,WAAW,MAAM,SAAS,KAAK;EAAE,GAAG,QAAQ;EAAM,QAAQ,WAAW;CAAO,GAAG,QAAQ,SAAS;CAEtG,MAAM,0BAAU,IAAI,IAAiC;CACrD,MAAM,0BAAU,IAAI,IAA+B;CACnD,MAAM,0BAAU,IAAI,IAA8B;CAClD,MAAM,SAAkB,EAAE,QAAQ,SAAS,OAAO;CAClD,IAAI,QAAQ;CAEZ,MAAM,YAAkB;EACtB,IAAI,OAAO;EACX,QAAQ;EACR,KAAK,MAAM,UAAU,CAAC,GAAG,OAAO,GAAG,OAAO,MAAM;CAClD;CAEA,MAAM,SAAuC;EAC3C,YAAY,QAAQ,uBAAO,IAAI,MAAM,2DAA2D,CAAC;EACjG,QAAQ,SAAS;GACf,QAAQ,IAAI,OAAO;GACnB,aAAa;IACX,QAAQ,OAAO,OAAO;GACxB;EACF;EACA,QAAQ,SAAS;GACf,IAAI,OAAO;IACT,QAAQ,MAAM;IACd,aAAa,CAAC;GAChB;GACA,QAAQ,IAAI,OAAO;GACnB,aAAa;IACX,QAAQ,OAAO,OAAO;GACxB;EACF;EACA,QAAQ,SAAS;GACf,QAAQ,IAAI,OAAO;GACnB,aAAa;IACX,QAAQ,OAAO,OAAO;GACxB;EACF;EACA,MAAM,QAAQ;GACZ,WAAW,MAAM;GACjB,MAAM,QAAQ,OAAO,CAAC,CAAC,YAAY,KAAA,CAAS;EAC9C;EACA,MAAM;GAAE;GAAK,QAAQ,SAAS;EAAO;EACrC,eAAe,CAAC;CAClB;CAEA,MAAM,SAAS,SAAS,MAAM,UAAU;CAExC,MAAM,OAAO,KAAK,MAAM;CAExB,MAAM,OAAO,YAA2B;EACtC,IAAI,WAAW,KAAA,GAAW;GACxB,IAAI;GACJ;EACF;EACA,IAAI;GACF,SAAS;IACP,MAAM,QAAQ,MAAM,OAAO,KAAK;IAChC,IAAI,MAAM,MAAM;KACd,IAAI;KACJ;IACF;IACA,KAAK,MAAM,UAAU,CAAC,GAAG,OAAO,GAAG,OAAO,MAAM,KAAK;GACvD;EACF,SAAS,OAAO;GACd,KAAK,MAAM,UAAU,CAAC,GAAG,OAAO,GAAG,OAAO,KAAK;GAC/C,IAAI;EACN;CACF;CACA,KAAU;CAEV,OAAO;AACT;;;;;;;;AASA,IAAa,cAAb,cAAiC,MAAM;CACrC,YACE,QACA,SACA;EACA,MAAM,OAAO;EAHJ,KAAA,SAAA;EAIT,KAAK,OAAO;CACd;AACF;AAEA,eAAe,SAAS,KAAa,MAAmB,WAAkD;CACxG,MAAM,UAAU,MAAM,KAAK,IAAI,CAAC,CAAC,OAAO,UAAmB,QAAQ,OAAO,MAAM,KAAK,KAAK,CAAC,CAAC;CAC5F,MAAM,WACJ,cAAc,KAAA,IACV,MAAM,UACN,MAAM,QAAQ,KAAK,CACjB,SACA,IAAI,SAAgB,UAAU,WAC5B,iBAAiB,uBAAO,IAAI,MAAM,cAAc,IAAI,2BAA2B,UAAU,GAAG,CAAC,GAAG,SAAS,CAC3G,CACF,CAAC;CAEP,IAAI,CAAC,SAAS,IAAI;EAChB,MAAM,OAAO,MAAM,SAAS,KAAK,CAAC,CAAC,YAAY,EAAE;EACjD,MAAM,IAAI,YACR,SAAS,QACT,cAAc,IAAI,YAAY,SAAS,SAAS,SAAS,KAAK,KAAK,KAAK,KAAK,MAAM,GAAG,GAAG,KAC3F;CACF;CACA,OAAO;AACT;AAEA,SAAS,MAAM,KAAa,OAAuB;CACjD,uBAAO,IAAI,MAAM,cAAc,IAAI,IAAI,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GAAG;AACjG;;;;;;;;;ACrGA,SAAgB,YACd,UACA,QACA,UAAgD,CAAC,GACpC;CACb,MAAM,0BAAU,IAAI,IAAmB;CACvC,IAAI,UAAU;CAEd,MAAM,SAAS,SAA2C;EACxD,MAAM,WAAW,YAAY;GAC3B,QAAQ,YAAY,IAAI;GACxB,IAAI;IACF,MAAM,OAAO,IAAI;GACnB,SAAS,OAAO;IACd,QAAQ,UAAU,KAAK;IACvB,QAAQ,WAAW,MAAM,KAAK;IAC9B;GACF;GACA,QAAQ,WAAW,MAAM,KAAA,CAAS;EACpC,EAAA,CAAG;EACH,QAAQ,IAAI,OAAO;EACnB,QAAa,cAAc,QAAQ,OAAO,OAAO,CAAC;CACpD;CAEA,MAAM,QAAQ,YAAY;EACxB,SAAS;GACP,IAAI;GACJ,IAAI;IACF,OAAO,MAAM,SAAS,OAAO;GAC/B,QAAQ;IACN;GACF;GACA,IAAI,SAAS;GACb,MAAM,IAAI;EACZ;CACF,EAAA,CAAG;CAEH,OAAO;EACL,IAAI,OAAO;GACT,OAAO,QAAQ;EACjB;EACA,MAAM,OAAO;GACX,UAAU;GACV,MAAM,SAAS,MAAM;GACrB,MAAM;GACN,MAAM,QAAQ,IAAI,CAAC,GAAG,OAAO,CAAC;EAChC;CACF;AACF;;;;AChFA,SAAgB,cAA2B,MAGzB;CAChB,OAAO;EACL,OAAO,UAAU,KAAK,SAAS,KAAK,KAAK;EACzC,UAAU,YAAY,KAAK,QAAQ,QAAQ,OAAO;EAClD,UAAU,YAAY,KAAK,QAAQ,QAAQ,OAAO;EAClD,UAAU,YAAY,KAAK,QAAQ,QAAQ,OAAO;EAClD,OAAO,OAAO,WAAW;GACvB,MAAM,KAAK,SAAS,MAAM,MAAM;EAClC;EACA,MAAM;GAAE,GAAG,KAAK,QAAQ;GAAM,GAAG,KAAK,SAAS;EAAK;EACpD,UAAU,YAAY,KAAK,QAAQ,QAAQ,OAAO;CACpD;AACF"}
1
+ {"version":3,"file":"port-DLpNfoyX.js","names":[],"sources":["../src/port/channel.ts","../src/port/memory.ts","../src/port/stream.ts","../src/port/combine.ts","../src/port/fetch.ts","../src/port/reactor.ts","../src/port/duplex.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 /** 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 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 };\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 };\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 };\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 };\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","// ── 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 };\n}\n"],"mappings":"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"}
@@ -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-By6xlyLp.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-Dm2eqDOA.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-DNJbW_di.js";
2
- import { s as streamChannel } from "../port-0vYKSxBM.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-By6xlyLp.js";
1
+ import { t as LIB_VERSION } from "../version-De-M910s.js";
2
+ import { s as streamChannel } from "../port-DLpNfoyX.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-Dm2eqDOA.js";
4
4
  import { execFile, spawn } from "node:child_process";
5
5
  import { chmod, mkdir, mkdtemp, open, readFile, rm, stat, unlink } from "node:fs/promises";
6
6
  import { createHash, randomUUID } from "node:crypto";
@@ -1 +1 @@
1
- {"version":3,"file":"types-U3NvKgpg.d.ts","names":[],"sources":["../src/process.async.ts","../src/types.d.ts"],"mappings":"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"}
1
+ {"version":3,"file":"types-U3NvKgpg.d.ts","names":[],"sources":["../src/process.async.d.ts","../src/types.d.ts"],"mappings":"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"}
@@ -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.49.1";
3
+ const LIB_VERSION = "0.49.2";
4
4
  //#endregion
5
5
  export { LIB_VERSION as t };
6
6
 
7
- //# sourceMappingURL=version-DNJbW_di.js.map
7
+ //# sourceMappingURL=version-De-M910s.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"version-DNJbW_di.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.49.1\";\n"],"mappings":";;AAcA,MAAa,cAAc"}
1
+ {"version":3,"file":"version-De-M910s.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.49.2\";\n"],"mappings":";;AAcA,MAAa,cAAc"}
@@ -2,7 +2,7 @@ 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 { n as splitChannel, r as held } from "./actor-MIvmdVJD.js";
5
+ import { n as splitChannel, r as held } from "./actor-B5EJRlY8.js";
6
6
  //#region src/remote/process-ref.ts
7
7
  /** The key that marks a process reference inside an otherwise JSON value. */
8
8
  const PROCESS_REF = "$p";
@@ -3311,4 +3311,4 @@ var WebSocketTransport = class {
3311
3311
  //#endregion
3312
3312
  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 };
3313
3313
 
3314
- //# sourceMappingURL=websocket-By6xlyLp.js.map
3314
+ //# sourceMappingURL=websocket-Dm2eqDOA.js.map