@earendil-works/chord 1.2.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +58 -0
- package/README.md +14 -13
- package/dist/cell.d.ts +30 -9
- package/dist/cell.d.ts.map +1 -1
- package/dist/cell.js +52 -12
- package/dist/cell.js.map +1 -1
- package/dist/cluster.d.ts +4 -3
- package/dist/cluster.d.ts.map +1 -1
- package/dist/cluster.js +58 -42
- package/dist/cluster.js.map +1 -1
- package/dist/connection.d.ts +171 -58
- package/dist/connection.d.ts.map +1 -1
- package/dist/connection.js +676 -217
- package/dist/connection.js.map +1 -1
- package/dist/contract.d.ts +120 -45
- package/dist/contract.d.ts.map +1 -1
- package/dist/contract.js +104 -15
- package/dist/contract.js.map +1 -1
- package/dist/declare.d.ts +11 -48
- package/dist/declare.d.ts.map +1 -1
- package/dist/declare.js +1 -21
- package/dist/declare.js.map +1 -1
- package/dist/delta/index.d.ts +2 -1
- package/dist/delta/index.d.ts.map +1 -1
- package/dist/delta/index.js +4 -0
- package/dist/delta/index.js.map +1 -1
- package/dist/errors.d.ts +4 -3
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +15 -0
- package/dist/errors.js.map +1 -1
- package/dist/host.d.ts +214 -120
- package/dist/host.d.ts.map +1 -1
- package/dist/host.js +446 -241
- package/dist/host.js.map +1 -1
- package/dist/index.d.ts +8 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/dist/link.d.ts +47 -12
- package/dist/link.d.ts.map +1 -1
- package/dist/link.js +200 -14
- package/dist/link.js.map +1 -1
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +7 -2
- package/dist/loader.js.map +1 -1
- package/dist/manager.d.ts.map +1 -1
- package/dist/manager.js +35 -9
- package/dist/manager.js.map +1 -1
- package/dist/object.d.ts +438 -0
- package/dist/object.d.ts.map +1 -0
- package/dist/{record.js → object.js} +614 -335
- package/dist/object.js.map +1 -0
- package/dist/output.d.ts +85 -0
- package/dist/output.d.ts.map +1 -0
- package/dist/output.js +350 -0
- package/dist/output.js.map +1 -0
- package/dist/registry.d.ts +3 -3
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +1 -1
- package/dist/registry.js.map +1 -1
- package/dist/reload.d.ts +35 -27
- package/dist/reload.d.ts.map +1 -1
- package/dist/reload.js +256 -192
- package/dist/reload.js.map +1 -1
- package/dist/remote.d.ts +130 -35
- package/dist/remote.d.ts.map +1 -1
- package/dist/remote.js +493 -189
- package/dist/remote.js.map +1 -1
- package/dist/types.d.ts +39 -28
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/websocket.d.ts +4 -5
- package/dist/websocket.d.ts.map +1 -1
- package/dist/websocket.js +3 -2
- package/dist/websocket.js.map +1 -1
- package/dist/wire.d.ts +210 -129
- package/dist/wire.d.ts.map +1 -1
- package/dist/wire.js +108 -55
- package/dist/wire.js.map +1 -1
- package/docs/guide.md +267 -203
- package/docs/spec.md +141 -114
- package/docs/tutorial.md +257 -235
- package/package.json +6 -1
- package/dist/record.d.ts +0 -320
- package/dist/record.d.ts.map +0 -1
- package/dist/record.js.map +0 -1
package/dist/link.d.ts
CHANGED
|
@@ -2,7 +2,12 @@ import type { Frame } from "./wire.ts";
|
|
|
2
2
|
/** An ordered (FIFO), bidirectional frame channel between two hosts. */
|
|
3
3
|
export interface Link {
|
|
4
4
|
readonly closed: boolean;
|
|
5
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Returns the size of the encoded frame as sent (JSON text length, or bytes of a packed message) when the transport
|
|
7
|
+
* knows it. The connection's flow control counts these sizes; frames without one count as zero, so a link that never
|
|
8
|
+
* reports sizes is not windowed.
|
|
9
|
+
*/
|
|
10
|
+
send(frame: Frame): number | undefined;
|
|
6
11
|
/** Sets the single receiver. Frames arriving earlier are queued. */
|
|
7
12
|
receive(handler: (frame: Frame) => void): void;
|
|
8
13
|
onClose(handler: (reason: string) => void): void;
|
|
@@ -13,23 +18,39 @@ export interface Link {
|
|
|
13
18
|
declare abstract class BaseLink implements Link {
|
|
14
19
|
#private;
|
|
15
20
|
get closed(): boolean;
|
|
16
|
-
protected abstract transmit(frame: Frame):
|
|
21
|
+
protected abstract transmit(frame: Frame): number | undefined;
|
|
17
22
|
protected abstract shutdown(): void;
|
|
18
|
-
send(frame: Frame):
|
|
23
|
+
send(frame: Frame): number | undefined;
|
|
19
24
|
receive(handler: (frame: Frame) => void): void;
|
|
20
25
|
onClose(handler: (reason: string) => void): void;
|
|
21
26
|
close(reason?: string): void;
|
|
22
|
-
/** Delivers a parsed frame from the transport. */
|
|
27
|
+
/** Delivers a parsed frame from the transport, after any frame still being decoded (`deliverLater`). */
|
|
23
28
|
protected deliver(frame: Frame): void;
|
|
29
|
+
/** Delivers a frame that is still being decoded (inflated in a browser); later frames wait for it, in order. */
|
|
30
|
+
protected deliverLater(frame: Promise<Frame>): void;
|
|
24
31
|
/** Marks the link closed (transport ended) and notifies once. */
|
|
25
32
|
protected ended(reason: string): void;
|
|
26
33
|
}
|
|
34
|
+
/** Payloads whose JSON is longer than this many characters are deflated. */
|
|
35
|
+
export declare const PACK_THRESHOLD: number;
|
|
36
|
+
/** A deflated JSON payload, kept as received until a host uses it. */
|
|
37
|
+
export declare class Packed {
|
|
38
|
+
readonly bytes: Uint8Array;
|
|
39
|
+
constructor(bytes: Uint8Array);
|
|
40
|
+
}
|
|
41
|
+
/** A frame payload as its user needs it: inflated and parsed if it arrived packed. */
|
|
42
|
+
export declare function unpack(value: unknown): unknown;
|
|
43
|
+
/**
|
|
44
|
+
* The text frame of a binary (packed) WebSocket message, inflated: for a transport that relays text frames only (the
|
|
45
|
+
* TUI launcher feeding its sandbox). Needs zlib.
|
|
46
|
+
*/
|
|
47
|
+
export declare function inflateMessage(data: Uint8Array): string;
|
|
27
48
|
export declare class MemoryLink extends BaseLink {
|
|
28
49
|
#private;
|
|
29
50
|
peer: MemoryLink | undefined;
|
|
30
51
|
/** Simulates a dead network: frames are dropped silently in both directions and no close is signalled. */
|
|
31
52
|
sever(): void;
|
|
32
|
-
protected transmit(frame: Frame):
|
|
53
|
+
protected transmit(frame: Frame): number | undefined;
|
|
33
54
|
protected shutdown(): void;
|
|
34
55
|
}
|
|
35
56
|
/** Two connected in-memory links (tests). */
|
|
@@ -37,36 +58,50 @@ export declare function memoryLinkPair(): [MemoryLink, MemoryLink];
|
|
|
37
58
|
/** `process` in a forked child, or the parent's `ChildProcess`. Structural, so Chord needs no Node types here. */
|
|
38
59
|
export interface IpcChannel {
|
|
39
60
|
readonly connected: boolean;
|
|
40
|
-
|
|
61
|
+
/**
|
|
62
|
+
* With a callback, Node reports a failed write (the peer process exited and the pipe is broken: `EPIPE`) to it
|
|
63
|
+
* instead of emitting `error`, which nobody would handle.
|
|
64
|
+
*/
|
|
65
|
+
send(message: unknown, callback?: (error: Error | null) => void): boolean;
|
|
41
66
|
on(event: "message", listener: (message: unknown) => void): unknown;
|
|
42
67
|
on(event: "disconnect", listener: () => void): unknown;
|
|
43
68
|
off(event: "message", listener: (message: unknown) => void): unknown;
|
|
44
69
|
off(event: "disconnect", listener: () => void): unknown;
|
|
45
70
|
}
|
|
46
|
-
/**
|
|
71
|
+
/**
|
|
72
|
+
* Chord frames on an IPC channel are wrapped as `{ chord2: frame }`; other messages (control) pass by. Both ends are
|
|
73
|
+
* Node processes of one application, so large payloads are packed both ways. Node serializes the messages itself, so
|
|
74
|
+
* the link reports no sizes and is not windowed: both ends are local processes.
|
|
75
|
+
*/
|
|
47
76
|
export declare class IpcLink extends BaseLink {
|
|
48
77
|
#private;
|
|
49
78
|
constructor(channel: IpcChannel);
|
|
50
|
-
protected transmit(frame: Frame):
|
|
79
|
+
protected transmit(frame: Frame): undefined;
|
|
51
80
|
protected shutdown(): void;
|
|
52
81
|
}
|
|
53
82
|
export declare const ipcLink: (channel: IpcChannel) => IpcLink;
|
|
54
83
|
/** The WHATWG WebSocket surface: the browser `WebSocket`, Node's global `WebSocket`, and `ws` sockets. */
|
|
55
84
|
export interface WebSocketLike {
|
|
56
85
|
readonly readyState: number;
|
|
57
|
-
send(data: string): void;
|
|
86
|
+
send(data: string | Uint8Array): void;
|
|
58
87
|
close(code?: number, reason?: string): void;
|
|
59
88
|
addEventListener(type: "message", listener: (event: {
|
|
60
89
|
readonly data: unknown;
|
|
61
90
|
}) => void): void;
|
|
62
91
|
addEventListener(type: "open" | "close" | "error", listener: () => void): void;
|
|
63
92
|
}
|
|
93
|
+
export interface WebSocketLinkOptions {
|
|
94
|
+
/** Deflate large payloads of outgoing frames (default false; the server's side of client sockets). */
|
|
95
|
+
readonly compress?: boolean;
|
|
96
|
+
/** Accept packed (binary) frames from the peer (default true; false for a server's untrusted clients). */
|
|
97
|
+
readonly acceptPacked?: boolean;
|
|
98
|
+
}
|
|
64
99
|
export declare class WebSocketLink extends BaseLink {
|
|
65
100
|
#private;
|
|
66
|
-
constructor(socket: WebSocketLike);
|
|
67
|
-
protected transmit(frame: Frame):
|
|
101
|
+
constructor(socket: WebSocketLike, options?: WebSocketLinkOptions);
|
|
102
|
+
protected transmit(frame: Frame): number;
|
|
68
103
|
protected shutdown(): void;
|
|
69
104
|
}
|
|
70
|
-
export declare const webSocketLink: (socket: WebSocketLike) => WebSocketLink;
|
|
105
|
+
export declare const webSocketLink: (socket: WebSocketLike, options?: WebSocketLinkOptions) => WebSocketLink;
|
|
71
106
|
export {};
|
|
72
107
|
//# sourceMappingURL=link.d.ts.map
|
package/dist/link.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"link.d.ts","sourceRoot":"","sources":["../src/link.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"link.d.ts","sourceRoot":"","sources":["../src/link.ts"],"names":[],"mappings":"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"}
|
package/dist/link.js
CHANGED
|
@@ -4,13 +4,15 @@ class BaseLink {
|
|
|
4
4
|
#queue = [];
|
|
5
5
|
#closeHandlers = new Set();
|
|
6
6
|
#closed = false;
|
|
7
|
+
/** The tail of frames being decoded asynchronously; undefined when none is. */
|
|
8
|
+
#decoding;
|
|
7
9
|
get closed() {
|
|
8
10
|
return this.#closed;
|
|
9
11
|
}
|
|
10
12
|
send(frame) {
|
|
11
13
|
if (this.#closed)
|
|
12
|
-
return;
|
|
13
|
-
this.transmit(frame);
|
|
14
|
+
return undefined;
|
|
15
|
+
return this.transmit(frame);
|
|
14
16
|
}
|
|
15
17
|
receive(handler) {
|
|
16
18
|
this.#handler = handler;
|
|
@@ -34,8 +36,25 @@ class BaseLink {
|
|
|
34
36
|
}
|
|
35
37
|
this.ended(reason);
|
|
36
38
|
}
|
|
37
|
-
/** Delivers a parsed frame from the transport. */
|
|
39
|
+
/** Delivers a parsed frame from the transport, after any frame still being decoded (`deliverLater`). */
|
|
38
40
|
deliver(frame) {
|
|
41
|
+
if (this.#decoding !== undefined)
|
|
42
|
+
this.deliverLater(Promise.resolve(frame));
|
|
43
|
+
else
|
|
44
|
+
this.#deliverNow(frame);
|
|
45
|
+
}
|
|
46
|
+
/** Delivers a frame that is still being decoded (inflated in a browser); later frames wait for it, in order. */
|
|
47
|
+
deliverLater(frame) {
|
|
48
|
+
const next = (this.#decoding ?? Promise.resolve())
|
|
49
|
+
.then(() => frame)
|
|
50
|
+
.then((decoded) => this.#deliverNow(decoded), () => this.close("protocol error"))
|
|
51
|
+
.finally(() => {
|
|
52
|
+
if (this.#decoding === next)
|
|
53
|
+
this.#decoding = undefined;
|
|
54
|
+
});
|
|
55
|
+
this.#decoding = next;
|
|
56
|
+
}
|
|
57
|
+
#deliverNow(frame) {
|
|
39
58
|
if (this.#closed)
|
|
40
59
|
return;
|
|
41
60
|
if (frame.t === "bye") {
|
|
@@ -63,9 +82,131 @@ class BaseLink {
|
|
|
63
82
|
}
|
|
64
83
|
}
|
|
65
84
|
}
|
|
85
|
+
// ─── payload packing ─────────────────────────────────────────────────────────
|
|
86
|
+
//
|
|
87
|
+
// A transport optimization, invisible above the links. A frame's payload (call args, a result value, a state snapshot)
|
|
88
|
+
// whose JSON exceeds `PACK_THRESHOLD` characters is sent deflated. A host that only relays the frame forwards the
|
|
89
|
+
// deflated bytes unread (`Packed`); the host that uses the payload inflates it (`unpack`). Only hosts with Node's zlib
|
|
90
|
+
// deflate (synchronously, so frames keep their order); a browser inflates with `DecompressionStream` before delivery.
|
|
91
|
+
/** Payloads whose JSON is longer than this many characters are deflated. */
|
|
92
|
+
export const PACK_THRESHOLD = 64 * 1024;
|
|
93
|
+
const zlib = globalThis.process?.getBuiltinModule?.("node:zlib");
|
|
94
|
+
/** A deflated JSON payload, kept as received until a host uses it. */
|
|
95
|
+
export class Packed {
|
|
96
|
+
bytes;
|
|
97
|
+
constructor(bytes) {
|
|
98
|
+
this.bytes = bytes;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
/** A frame payload as its user needs it: inflated and parsed if it arrived packed. */
|
|
102
|
+
export function unpack(value) {
|
|
103
|
+
if (!(value instanceof Packed))
|
|
104
|
+
return value;
|
|
105
|
+
if (zlib === undefined)
|
|
106
|
+
throw new TypeError("packed payload without zlib");
|
|
107
|
+
return JSON.parse(zlib.inflateRawSync(value.bytes).toString("utf8"));
|
|
108
|
+
}
|
|
109
|
+
const PAYLOAD_FIELDS = new Set(["args", "value"]);
|
|
110
|
+
function payloadField(frame) {
|
|
111
|
+
if (frame.t === "call")
|
|
112
|
+
return frame.args === undefined ? undefined : "args";
|
|
113
|
+
if (frame.t === "result" || frame.t === "state")
|
|
114
|
+
return frame.value === undefined ? undefined : "value";
|
|
115
|
+
return undefined;
|
|
116
|
+
}
|
|
117
|
+
/** The frame without its payload field (the envelope). */
|
|
118
|
+
function envelopeOf(frame, field) {
|
|
119
|
+
const envelope = { ...frame };
|
|
120
|
+
delete envelope[field];
|
|
121
|
+
return envelope;
|
|
122
|
+
}
|
|
123
|
+
/** The payload's deflated bytes: as received, or deflated now if large. Undefined: send it as JSON. */
|
|
124
|
+
function packedBytes(value, compress, json) {
|
|
125
|
+
if (value instanceof Packed)
|
|
126
|
+
return value.bytes;
|
|
127
|
+
if (!compress || zlib === undefined || json === undefined || json.length <= PACK_THRESHOLD)
|
|
128
|
+
return undefined;
|
|
129
|
+
return zlib.deflateRawSync(json, { level: 1 });
|
|
130
|
+
}
|
|
131
|
+
/** For object transports (Node IPC, memory): a packed payload travels as `z: [field, base64]`. */
|
|
132
|
+
function packObject(frame, compress) {
|
|
133
|
+
const field = payloadField(frame);
|
|
134
|
+
if (field === undefined)
|
|
135
|
+
return frame;
|
|
136
|
+
const value = frame[field];
|
|
137
|
+
const bytes = packedBytes(value, compress, compress && zlib !== undefined ? JSON.stringify(value) : undefined);
|
|
138
|
+
if (bytes === undefined)
|
|
139
|
+
return frame;
|
|
140
|
+
return {
|
|
141
|
+
...envelopeOf(frame, field),
|
|
142
|
+
z: [field, Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength).toString("base64")],
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
function unpackObject(message) {
|
|
146
|
+
if (message === null || typeof message !== "object" || !("z" in message))
|
|
147
|
+
return message;
|
|
148
|
+
const { z, ...rest } = message;
|
|
149
|
+
if (!Array.isArray(z) || !PAYLOAD_FIELDS.has(z[0]) || typeof z[1] !== "string")
|
|
150
|
+
throw new TypeError("bad packed payload");
|
|
151
|
+
return { ...rest, [z[0]]: new Packed(Buffer.from(z[1], "base64")) };
|
|
152
|
+
}
|
|
153
|
+
const encoder = new TextEncoder();
|
|
154
|
+
const decoder = new TextDecoder();
|
|
155
|
+
/**
|
|
156
|
+
* For WebSockets: a frame with a packed payload is a binary message, `[envelope length: u32 BE][envelope JSON, with
|
|
157
|
+
* z: field][deflated payload]`; any other frame is text. The payload's JSON is spliced in, not encoded twice.
|
|
158
|
+
*/
|
|
159
|
+
function packMessage(frame, compress) {
|
|
160
|
+
const field = payloadField(frame);
|
|
161
|
+
if (field === undefined)
|
|
162
|
+
return JSON.stringify(frame);
|
|
163
|
+
const value = frame[field];
|
|
164
|
+
const json = value instanceof Packed ? undefined : JSON.stringify(value);
|
|
165
|
+
const bytes = packedBytes(value, compress, json);
|
|
166
|
+
const envelope = envelopeOf(frame, field);
|
|
167
|
+
if (bytes === undefined) {
|
|
168
|
+
const head = JSON.stringify(envelope);
|
|
169
|
+
return `${head.slice(0, -1)},${JSON.stringify(field)}:${json}}`;
|
|
170
|
+
}
|
|
171
|
+
const head = encoder.encode(JSON.stringify({ ...envelope, z: field }));
|
|
172
|
+
const message = new Uint8Array(4 + head.byteLength + bytes.byteLength);
|
|
173
|
+
new DataView(message.buffer).setUint32(0, head.byteLength);
|
|
174
|
+
message.set(head, 4);
|
|
175
|
+
message.set(bytes, 4 + head.byteLength);
|
|
176
|
+
return message;
|
|
177
|
+
}
|
|
178
|
+
/** The envelope of a binary message and its payload bytes. */
|
|
179
|
+
function splitMessage(data) {
|
|
180
|
+
const length = new DataView(data.buffer, data.byteOffset, data.byteLength).getUint32(0);
|
|
181
|
+
const envelope = JSON.parse(decoder.decode(data.subarray(4, 4 + length)));
|
|
182
|
+
if (envelope === null || typeof envelope !== "object")
|
|
183
|
+
throw new TypeError("bad envelope");
|
|
184
|
+
const { z: field, ...rest } = envelope;
|
|
185
|
+
if (typeof field !== "string" || !PAYLOAD_FIELDS.has(field))
|
|
186
|
+
throw new TypeError("bad packed payload");
|
|
187
|
+
return { envelope: rest, field: field, bytes: data.slice(4 + length) };
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* The text frame of a binary (packed) WebSocket message, inflated: for a transport that relays text frames only (the
|
|
191
|
+
* TUI launcher feeding its sandbox). Needs zlib.
|
|
192
|
+
*/
|
|
193
|
+
export function inflateMessage(data) {
|
|
194
|
+
if (zlib === undefined)
|
|
195
|
+
throw new TypeError("inflateMessage needs zlib");
|
|
196
|
+
const { envelope, field, bytes } = splitMessage(data);
|
|
197
|
+
const head = JSON.stringify(envelope);
|
|
198
|
+
return `${head.slice(0, -1)},${JSON.stringify(field)}:${zlib.inflateRawSync(bytes).toString("utf8")}}`;
|
|
199
|
+
}
|
|
200
|
+
/** Inflates without zlib (browsers). */
|
|
201
|
+
async function inflate(bytes) {
|
|
202
|
+
const stream = new Blob([bytes])
|
|
203
|
+
.stream()
|
|
204
|
+
.pipeThrough(new DecompressionStream("deflate-raw"));
|
|
205
|
+
return JSON.parse(await new Response(stream).text());
|
|
206
|
+
}
|
|
66
207
|
/** Parses a JSON frame; anything else is a protocol error. */
|
|
67
208
|
function parseFrame(data) {
|
|
68
|
-
const frame = JSON.parse(data);
|
|
209
|
+
const frame = unpackObject(JSON.parse(data));
|
|
69
210
|
if (frame === null || typeof frame !== "object" || typeof frame.t !== "string")
|
|
70
211
|
throw new TypeError("not a frame");
|
|
71
212
|
return frame;
|
|
@@ -83,15 +224,16 @@ export class MemoryLink extends BaseLink {
|
|
|
83
224
|
}
|
|
84
225
|
transmit(frame) {
|
|
85
226
|
if (this.#severed)
|
|
86
|
-
return;
|
|
227
|
+
return undefined;
|
|
87
228
|
// A JSON round trip detaches the frame (and rejects what JSON would mangle silently, e.g. bigint).
|
|
88
|
-
const data = JSON.stringify(frame);
|
|
229
|
+
const data = JSON.stringify(packObject(frame, true));
|
|
89
230
|
const peer = this.peer;
|
|
90
231
|
// One promise chain per direction keeps delivery FIFO and asynchronous, like a real transport.
|
|
91
232
|
this.#pending = this.#pending.then(() => {
|
|
92
233
|
if (!this.#severed && peer !== undefined)
|
|
93
234
|
peer.deliver(parseFrame(data));
|
|
94
235
|
});
|
|
236
|
+
return data.length;
|
|
95
237
|
}
|
|
96
238
|
shutdown() {
|
|
97
239
|
const peer = this.peer;
|
|
@@ -106,15 +248,33 @@ export function memoryLinkPair() {
|
|
|
106
248
|
b.peer = a;
|
|
107
249
|
return [a, b];
|
|
108
250
|
}
|
|
109
|
-
/**
|
|
251
|
+
/**
|
|
252
|
+
* Chord frames on an IPC channel are wrapped as `{ chord2: frame }`; other messages (control) pass by. Both ends are
|
|
253
|
+
* Node processes of one application, so large payloads are packed both ways. Node serializes the messages itself, so
|
|
254
|
+
* the link reports no sizes and is not windowed: both ends are local processes.
|
|
255
|
+
*/
|
|
110
256
|
export class IpcLink extends BaseLink {
|
|
111
257
|
#channel;
|
|
112
258
|
#onMessage = (message) => {
|
|
113
259
|
const frame = message?.chord2;
|
|
114
|
-
if (frame
|
|
115
|
-
|
|
260
|
+
if (frame === undefined)
|
|
261
|
+
return;
|
|
262
|
+
try {
|
|
263
|
+
this.deliver(unpackObject(frame));
|
|
264
|
+
}
|
|
265
|
+
catch {
|
|
266
|
+
this.close("protocol error");
|
|
267
|
+
}
|
|
116
268
|
};
|
|
117
269
|
#onDisconnect = () => this.ended("ipc disconnected");
|
|
270
|
+
/**
|
|
271
|
+
* A write can fail after the peer exited and before the channel reports `disconnect` (an `ack` or a `bye` sent then).
|
|
272
|
+
* The peer is gone either way: the link ends, as on `disconnect`.
|
|
273
|
+
*/
|
|
274
|
+
#onSent = (error) => {
|
|
275
|
+
if (error !== null)
|
|
276
|
+
this.ended(`ipc send failed: ${error.code ?? error.message}`);
|
|
277
|
+
};
|
|
118
278
|
constructor(channel) {
|
|
119
279
|
super();
|
|
120
280
|
this.#channel = channel;
|
|
@@ -123,7 +283,8 @@ export class IpcLink extends BaseLink {
|
|
|
123
283
|
}
|
|
124
284
|
transmit(frame) {
|
|
125
285
|
if (this.#channel.connected)
|
|
126
|
-
this.#channel.send({ chord2: frame });
|
|
286
|
+
this.#channel.send({ chord2: packObject(frame, true) }, this.#onSent);
|
|
287
|
+
return undefined;
|
|
127
288
|
}
|
|
128
289
|
shutdown() {
|
|
129
290
|
this.#channel.off("message", this.#onMessage);
|
|
@@ -134,17 +295,41 @@ export const ipcLink = (channel) => new IpcLink(channel);
|
|
|
134
295
|
const OPEN = 1;
|
|
135
296
|
export class WebSocketLink extends BaseLink {
|
|
136
297
|
#socket;
|
|
298
|
+
#compress;
|
|
137
299
|
#outbox = [];
|
|
138
|
-
constructor(socket) {
|
|
300
|
+
constructor(socket, options = {}) {
|
|
139
301
|
super();
|
|
140
302
|
this.#socket = socket;
|
|
303
|
+
this.#compress = options.compress ?? false;
|
|
304
|
+
const acceptPacked = options.acceptPacked ?? true;
|
|
305
|
+
// Binary messages as ArrayBuffer (browsers and Node's WebSocket default to Blob).
|
|
306
|
+
if ("binaryType" in socket)
|
|
307
|
+
socket.binaryType = "arraybuffer";
|
|
141
308
|
socket.addEventListener("open", () => {
|
|
142
309
|
for (const data of this.#outbox.splice(0))
|
|
143
310
|
socket.send(data);
|
|
144
311
|
});
|
|
145
312
|
socket.addEventListener("message", (event) => {
|
|
146
313
|
try {
|
|
147
|
-
|
|
314
|
+
const data = event.data;
|
|
315
|
+
if (typeof data === "string") {
|
|
316
|
+
this.deliver(parseFrame(data));
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
if (!acceptPacked)
|
|
320
|
+
throw new TypeError("packed frames are not accepted");
|
|
321
|
+
const bytes = data instanceof ArrayBuffer
|
|
322
|
+
? new Uint8Array(data)
|
|
323
|
+
: ArrayBuffer.isView(data)
|
|
324
|
+
? new Uint8Array(data.buffer, data.byteOffset, data.byteLength)
|
|
325
|
+
: undefined;
|
|
326
|
+
if (bytes === undefined)
|
|
327
|
+
throw new TypeError("unknown message type");
|
|
328
|
+
const { envelope, field, bytes: payload } = splitMessage(bytes);
|
|
329
|
+
if (zlib !== undefined)
|
|
330
|
+
this.deliver({ ...envelope, [field]: new Packed(payload) });
|
|
331
|
+
else
|
|
332
|
+
this.deliverLater(inflate(payload).then((value) => ({ ...envelope, [field]: value })));
|
|
148
333
|
}
|
|
149
334
|
catch {
|
|
150
335
|
this.close("protocol error");
|
|
@@ -153,11 +338,12 @@ export class WebSocketLink extends BaseLink {
|
|
|
153
338
|
socket.addEventListener("close", () => this.ended("socket closed"));
|
|
154
339
|
}
|
|
155
340
|
transmit(frame) {
|
|
156
|
-
const data =
|
|
341
|
+
const data = packMessage(frame, this.#compress);
|
|
157
342
|
if (this.#socket.readyState === OPEN)
|
|
158
343
|
this.#socket.send(data);
|
|
159
344
|
else
|
|
160
345
|
this.#outbox.push(data);
|
|
346
|
+
return typeof data === "string" ? data.length : data.byteLength;
|
|
161
347
|
}
|
|
162
348
|
shutdown() {
|
|
163
349
|
this.#outbox = [];
|
|
@@ -165,5 +351,5 @@ export class WebSocketLink extends BaseLink {
|
|
|
165
351
|
this.#socket.close(1000);
|
|
166
352
|
}
|
|
167
353
|
}
|
|
168
|
-
export const webSocketLink = (socket) => new WebSocketLink(socket);
|
|
354
|
+
export const webSocketLink = (socket, options) => new WebSocketLink(socket, options);
|
|
169
355
|
//# sourceMappingURL=link.js.map
|
package/dist/link.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"link.js","sourceRoot":"","sources":["../src/link.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Frame } from \"./wire.ts\";\n\n/** An ordered (FIFO), bidirectional frame channel between two hosts. */\nexport interface Link {\n\treadonly closed: boolean;\n\tsend(frame: Frame): void;\n\t/** Sets the single receiver. Frames arriving earlier are queued. */\n\treceive(handler: (frame: Frame) => void): void;\n\tonClose(handler: (reason: string) => void): void;\n\t/** Closes both ends: the peer gets a `bye`. */\n\tclose(reason?: string): void;\n}\n\n/** Shared plumbing: receive queue, close handlers, `bye`. Transports implement `transmit` and `shutdown`. */\nabstract class BaseLink implements Link {\n\t#handler: ((frame: Frame) => void) | undefined;\n\t#queue: Frame[] = [];\n\treadonly #closeHandlers = new Set<(reason: string) => void>();\n\t#closed = false;\n\n\tget closed(): boolean {\n\t\treturn this.#closed;\n\t}\n\n\tprotected abstract transmit(frame: Frame): void;\n\tprotected abstract shutdown(): void;\n\n\tsend(frame: Frame): void {\n\t\tif (this.#closed) return;\n\t\tthis.transmit(frame);\n\t}\n\n\treceive(handler: (frame: Frame) => void): void {\n\t\tthis.#handler = handler;\n\t\tfor (const frame of this.#queue.splice(0)) handler(frame);\n\t}\n\n\tonClose(handler: (reason: string) => void): void {\n\t\tif (this.#closed) handler(\"closed\");\n\t\telse this.#closeHandlers.add(handler);\n\t}\n\n\tclose(reason = \"closed\"): void {\n\t\tif (this.#closed) return;\n\t\ttry {\n\t\t\tthis.transmit({ t: \"bye\", reason });\n\t\t} catch {\n\t\t\t// The transport may already be gone.\n\t\t}\n\t\tthis.ended(reason);\n\t}\n\n\t/** Delivers a parsed frame from the transport. */\n\tprotected deliver(frame: Frame): void {\n\t\tif (this.#closed) return;\n\t\tif (frame.t === \"bye\") {\n\t\t\tthis.ended(frame.reason ?? \"peer closed\");\n\t\t\treturn;\n\t\t}\n\t\tif (this.#handler === undefined) this.#queue.push(frame);\n\t\telse this.#handler(frame);\n\t}\n\n\t/** Marks the link closed (transport ended) and notifies once. */\n\tprotected ended(reason: string): void {\n\t\tif (this.#closed) return;\n\t\tthis.#closed = true;\n\t\tthis.#queue = [];\n\t\ttry {\n\t\t\tthis.shutdown();\n\t\t} finally {\n\t\t\tfor (const handler of this.#closeHandlers) handler(reason);\n\t\t\tthis.#closeHandlers.clear();\n\t\t}\n\t}\n}\n\n/** Parses a JSON frame; anything else is a protocol error. */\nfunction parseFrame(data: string): Frame {\n\tconst frame = JSON.parse(data) as Frame;\n\tif (frame === null || typeof frame !== \"object\" || typeof frame.t !== \"string\") throw new TypeError(\"not a frame\");\n\treturn frame;\n}\n\n// ─── memory ──────────────────────────────────────────────────────────────────\n\nexport class MemoryLink extends BaseLink {\n\tpeer: MemoryLink | undefined;\n\t#severed = false;\n\t#pending = Promise.resolve();\n\n\t/** Simulates a dead network: frames are dropped silently in both directions and no close is signalled. */\n\tsever(): void {\n\t\tthis.#severed = true;\n\t\tif (this.peer) this.peer.#severed = true;\n\t}\n\n\tprotected transmit(frame: Frame): void {\n\t\tif (this.#severed) return;\n\t\t// A JSON round trip detaches the frame (and rejects what JSON would mangle silently, e.g. bigint).\n\t\tconst data = JSON.stringify(frame);\n\t\tconst peer = this.peer;\n\t\t// One promise chain per direction keeps delivery FIFO and asynchronous, like a real transport.\n\t\tthis.#pending = this.#pending.then(() => {\n\t\t\tif (!this.#severed && peer !== undefined) peer.deliver(parseFrame(data));\n\t\t});\n\t}\n\n\tprotected shutdown(): void {\n\t\tconst peer = this.peer;\n\t\tthis.#pending = this.#pending.then(() => peer?.ended(\"peer closed\"));\n\t}\n}\n\n/** Two connected in-memory links (tests). */\nexport function memoryLinkPair(): [MemoryLink, MemoryLink] {\n\tconst a = new MemoryLink();\n\tconst b = new MemoryLink();\n\ta.peer = b;\n\tb.peer = a;\n\treturn [a, b];\n}\n\n// ─── Node IPC ────────────────────────────────────────────────────────────────\n\n/** `process` in a forked child, or the parent's `ChildProcess`. Structural, so Chord needs no Node types here. */\nexport interface IpcChannel {\n\treadonly connected: boolean;\n\tsend(message: unknown): boolean;\n\ton(event: \"message\", listener: (message: unknown) => void): unknown;\n\ton(event: \"disconnect\", listener: () => void): unknown;\n\toff(event: \"message\", listener: (message: unknown) => void): unknown;\n\toff(event: \"disconnect\", listener: () => void): unknown;\n}\n\n/** Chord frames on an IPC channel are wrapped as `{ chord2: frame }`; other messages (control) pass by. */\nexport class IpcLink extends BaseLink {\n\treadonly #channel: IpcChannel;\n\treadonly #onMessage = (message: unknown): void => {\n\t\tconst frame = (message as { chord2?: Frame } | null)?.chord2;\n\t\tif (frame !== undefined) this.deliver(frame);\n\t};\n\treadonly #onDisconnect = (): void => this.ended(\"ipc disconnected\");\n\n\tconstructor(channel: IpcChannel) {\n\t\tsuper();\n\t\tthis.#channel = channel;\n\t\tchannel.on(\"message\", this.#onMessage);\n\t\tchannel.on(\"disconnect\", this.#onDisconnect);\n\t}\n\n\tprotected transmit(frame: Frame): void {\n\t\tif (this.#channel.connected) this.#channel.send({ chord2: frame });\n\t}\n\n\tprotected shutdown(): void {\n\t\tthis.#channel.off(\"message\", this.#onMessage);\n\t\tthis.#channel.off(\"disconnect\", this.#onDisconnect);\n\t}\n}\n\nexport const ipcLink = (channel: IpcChannel): IpcLink => new IpcLink(channel);\n\n// ─── WebSocket ───────────────────────────────────────────────────────────────\n\n/** The WHATWG WebSocket surface: the browser `WebSocket`, Node's global `WebSocket`, and `ws` sockets. */\nexport interface WebSocketLike {\n\treadonly readyState: number;\n\tsend(data: string): void;\n\tclose(code?: number, reason?: string): void;\n\taddEventListener(type: \"message\", listener: (event: { readonly data: unknown }) => void): void;\n\taddEventListener(type: \"open\" | \"close\" | \"error\", listener: () => void): void;\n}\n\nconst OPEN = 1;\n\nexport class WebSocketLink extends BaseLink {\n\treadonly #socket: WebSocketLike;\n\t#outbox: string[] = [];\n\n\tconstructor(socket: WebSocketLike) {\n\t\tsuper();\n\t\tthis.#socket = socket;\n\t\tsocket.addEventListener(\"open\", () => {\n\t\t\tfor (const data of this.#outbox.splice(0)) socket.send(data);\n\t\t});\n\t\tsocket.addEventListener(\"message\", (event) => {\n\t\t\ttry {\n\t\t\t\tthis.deliver(parseFrame(typeof event.data === \"string\" ? event.data : String(event.data)));\n\t\t\t} catch {\n\t\t\t\tthis.close(\"protocol error\");\n\t\t\t}\n\t\t});\n\t\tsocket.addEventListener(\"close\", () => this.ended(\"socket closed\"));\n\t}\n\n\tprotected transmit(frame: Frame): void {\n\t\tconst data = JSON.stringify(frame);\n\t\tif (this.#socket.readyState === OPEN) this.#socket.send(data);\n\t\telse this.#outbox.push(data);\n\t}\n\n\tprotected shutdown(): void {\n\t\tthis.#outbox = [];\n\t\tif (this.#socket.readyState <= OPEN) this.#socket.close(1000);\n\t}\n}\n\nexport const webSocketLink = (socket: WebSocketLike): WebSocketLink => new WebSocketLink(socket);\n"]}
|
|
1
|
+
{"version":3,"file":"link.js","sourceRoot":"","sources":["../src/link.ts"],"names":[],"mappings":"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","sourcesContent":["import type * as Zlib from \"node:zlib\";\nimport type { Frame } from \"./wire.ts\";\n\n/** An ordered (FIFO), bidirectional frame channel between two hosts. */\nexport interface Link {\n\treadonly closed: boolean;\n\t/**\n\t * Returns the size of the encoded frame as sent (JSON text length, or bytes of a packed message) when the transport\n\t * knows it. The connection's flow control counts these sizes; frames without one count as zero, so a link that never\n\t * reports sizes is not windowed.\n\t */\n\tsend(frame: Frame): number | undefined;\n\t/** Sets the single receiver. Frames arriving earlier are queued. */\n\treceive(handler: (frame: Frame) => void): void;\n\tonClose(handler: (reason: string) => void): void;\n\t/** Closes both ends: the peer gets a `bye`. */\n\tclose(reason?: string): void;\n}\n\n/** Shared plumbing: receive queue, close handlers, `bye`. Transports implement `transmit` and `shutdown`. */\nabstract class BaseLink implements Link {\n\t#handler: ((frame: Frame) => void) | undefined;\n\t#queue: Frame[] = [];\n\treadonly #closeHandlers = new Set<(reason: string) => void>();\n\t#closed = false;\n\t/** The tail of frames being decoded asynchronously; undefined when none is. */\n\t#decoding: Promise<void> | undefined;\n\n\tget closed(): boolean {\n\t\treturn this.#closed;\n\t}\n\n\tprotected abstract transmit(frame: Frame): number | undefined;\n\tprotected abstract shutdown(): void;\n\n\tsend(frame: Frame): number | undefined {\n\t\tif (this.#closed) return undefined;\n\t\treturn this.transmit(frame);\n\t}\n\n\treceive(handler: (frame: Frame) => void): void {\n\t\tthis.#handler = handler;\n\t\tfor (const frame of this.#queue.splice(0)) handler(frame);\n\t}\n\n\tonClose(handler: (reason: string) => void): void {\n\t\tif (this.#closed) handler(\"closed\");\n\t\telse this.#closeHandlers.add(handler);\n\t}\n\n\tclose(reason = \"closed\"): void {\n\t\tif (this.#closed) return;\n\t\ttry {\n\t\t\tthis.transmit({ t: \"bye\", reason });\n\t\t} catch {\n\t\t\t// The transport may already be gone.\n\t\t}\n\t\tthis.ended(reason);\n\t}\n\n\t/** Delivers a parsed frame from the transport, after any frame still being decoded (`deliverLater`). */\n\tprotected deliver(frame: Frame): void {\n\t\tif (this.#decoding !== undefined) this.deliverLater(Promise.resolve(frame));\n\t\telse this.#deliverNow(frame);\n\t}\n\n\t/** Delivers a frame that is still being decoded (inflated in a browser); later frames wait for it, in order. */\n\tprotected deliverLater(frame: Promise<Frame>): void {\n\t\tconst next = (this.#decoding ?? Promise.resolve())\n\t\t\t.then(() => frame)\n\t\t\t.then(\n\t\t\t\t(decoded) => this.#deliverNow(decoded),\n\t\t\t\t() => this.close(\"protocol error\"),\n\t\t\t)\n\t\t\t.finally(() => {\n\t\t\t\tif (this.#decoding === next) this.#decoding = undefined;\n\t\t\t});\n\t\tthis.#decoding = next;\n\t}\n\n\t#deliverNow(frame: Frame): void {\n\t\tif (this.#closed) return;\n\t\tif (frame.t === \"bye\") {\n\t\t\tthis.ended(frame.reason ?? \"peer closed\");\n\t\t\treturn;\n\t\t}\n\t\tif (this.#handler === undefined) this.#queue.push(frame);\n\t\telse this.#handler(frame);\n\t}\n\n\t/** Marks the link closed (transport ended) and notifies once. */\n\tprotected ended(reason: string): void {\n\t\tif (this.#closed) return;\n\t\tthis.#closed = true;\n\t\tthis.#queue = [];\n\t\ttry {\n\t\t\tthis.shutdown();\n\t\t} finally {\n\t\t\tfor (const handler of this.#closeHandlers) handler(reason);\n\t\t\tthis.#closeHandlers.clear();\n\t\t}\n\t}\n}\n\n// ─── payload packing ─────────────────────────────────────────────────────────\n//\n// A transport optimization, invisible above the links. A frame's payload (call args, a result value, a state snapshot)\n// whose JSON exceeds `PACK_THRESHOLD` characters is sent deflated. A host that only relays the frame forwards the\n// deflated bytes unread (`Packed`); the host that uses the payload inflates it (`unpack`). Only hosts with Node's zlib\n// deflate (synchronously, so frames keep their order); a browser inflates with `DecompressionStream` before delivery.\n\n/** Payloads whose JSON is longer than this many characters are deflated. */\nexport const PACK_THRESHOLD = 64 * 1024;\n\nconst zlib: typeof Zlib | undefined = (\n\tglobalThis as { process?: { getBuiltinModule?(id: \"node:zlib\"): typeof Zlib } }\n).process?.getBuiltinModule?.(\"node:zlib\");\n\n/** A deflated JSON payload, kept as received until a host uses it. */\nexport class Packed {\n\treadonly bytes: Uint8Array;\n\tconstructor(bytes: Uint8Array) {\n\t\tthis.bytes = bytes;\n\t}\n}\n\n/** A frame payload as its user needs it: inflated and parsed if it arrived packed. */\nexport function unpack(value: unknown): unknown {\n\tif (!(value instanceof Packed)) return value;\n\tif (zlib === undefined) throw new TypeError(\"packed payload without zlib\");\n\treturn JSON.parse(zlib.inflateRawSync(value.bytes).toString(\"utf8\"));\n}\n\ntype PayloadField = \"args\" | \"value\";\nconst PAYLOAD_FIELDS: ReadonlySet<string> = new Set<PayloadField>([\"args\", \"value\"]);\n\nfunction payloadField(frame: Frame): PayloadField | undefined {\n\tif (frame.t === \"call\") return frame.args === undefined ? undefined : \"args\";\n\tif (frame.t === \"result\" || frame.t === \"state\") return frame.value === undefined ? undefined : \"value\";\n\treturn undefined;\n}\n\n/** The frame without its payload field (the envelope). */\nfunction envelopeOf(frame: Frame, field: PayloadField): Record<string, unknown> {\n\tconst envelope: Record<string, unknown> = { ...frame };\n\tdelete envelope[field];\n\treturn envelope;\n}\n\n/** The payload's deflated bytes: as received, or deflated now if large. Undefined: send it as JSON. */\nfunction packedBytes(value: unknown, compress: boolean, json?: string): Uint8Array | undefined {\n\tif (value instanceof Packed) return value.bytes;\n\tif (!compress || zlib === undefined || json === undefined || json.length <= PACK_THRESHOLD) return undefined;\n\treturn zlib.deflateRawSync(json, { level: 1 });\n}\n\n/** For object transports (Node IPC, memory): a packed payload travels as `z: [field, base64]`. */\nfunction packObject(frame: Frame, compress: boolean): unknown {\n\tconst field = payloadField(frame);\n\tif (field === undefined) return frame;\n\tconst value = (frame as Record<string, unknown>)[field];\n\tconst bytes = packedBytes(value, compress, compress && zlib !== undefined ? JSON.stringify(value) : undefined);\n\tif (bytes === undefined) return frame;\n\treturn {\n\t\t...envelopeOf(frame, field),\n\t\tz: [field, Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength).toString(\"base64\")],\n\t};\n}\n\nfunction unpackObject(message: unknown): unknown {\n\tif (message === null || typeof message !== \"object\" || !(\"z\" in message)) return message;\n\tconst { z, ...rest } = message as { z: unknown } & Record<string, unknown>;\n\tif (!Array.isArray(z) || !PAYLOAD_FIELDS.has(z[0]) || typeof z[1] !== \"string\")\n\t\tthrow new TypeError(\"bad packed payload\");\n\treturn { ...rest, [z[0]]: new Packed(Buffer.from(z[1], \"base64\")) };\n}\n\nconst encoder = new TextEncoder();\nconst decoder = new TextDecoder();\n\n/**\n * For WebSockets: a frame with a packed payload is a binary message, `[envelope length: u32 BE][envelope JSON, with\n * z: field][deflated payload]`; any other frame is text. The payload's JSON is spliced in, not encoded twice.\n */\nfunction packMessage(frame: Frame, compress: boolean): string | Uint8Array {\n\tconst field = payloadField(frame);\n\tif (field === undefined) return JSON.stringify(frame);\n\tconst value = (frame as Record<string, unknown>)[field];\n\tconst json = value instanceof Packed ? undefined : JSON.stringify(value);\n\tconst bytes = packedBytes(value, compress, json);\n\tconst envelope = envelopeOf(frame, field);\n\tif (bytes === undefined) {\n\t\tconst head = JSON.stringify(envelope);\n\t\treturn `${head.slice(0, -1)},${JSON.stringify(field)}:${json}}`;\n\t}\n\tconst head = encoder.encode(JSON.stringify({ ...envelope, z: field }));\n\tconst message = new Uint8Array(4 + head.byteLength + bytes.byteLength);\n\tnew DataView(message.buffer).setUint32(0, head.byteLength);\n\tmessage.set(head, 4);\n\tmessage.set(bytes, 4 + head.byteLength);\n\treturn message;\n}\n\n/** The envelope of a binary message and its payload bytes. */\nfunction splitMessage(data: Uint8Array): { envelope: Record<string, unknown>; field: PayloadField; bytes: Uint8Array } {\n\tconst length = new DataView(data.buffer, data.byteOffset, data.byteLength).getUint32(0);\n\tconst envelope = JSON.parse(decoder.decode(data.subarray(4, 4 + length))) as unknown;\n\tif (envelope === null || typeof envelope !== \"object\") throw new TypeError(\"bad envelope\");\n\tconst { z: field, ...rest } = envelope as { z?: unknown } & Record<string, unknown>;\n\tif (typeof field !== \"string\" || !PAYLOAD_FIELDS.has(field)) throw new TypeError(\"bad packed payload\");\n\treturn { envelope: rest, field: field as PayloadField, bytes: data.slice(4 + length) };\n}\n\n/**\n * The text frame of a binary (packed) WebSocket message, inflated: for a transport that relays text frames only (the\n * TUI launcher feeding its sandbox). Needs zlib.\n */\nexport function inflateMessage(data: Uint8Array): string {\n\tif (zlib === undefined) throw new TypeError(\"inflateMessage needs zlib\");\n\tconst { envelope, field, bytes } = splitMessage(data);\n\tconst head = JSON.stringify(envelope);\n\treturn `${head.slice(0, -1)},${JSON.stringify(field)}:${zlib.inflateRawSync(bytes).toString(\"utf8\")}}`;\n}\n\n/** Inflates without zlib (browsers). */\nasync function inflate(bytes: Uint8Array): Promise<unknown> {\n\tconst stream = new Blob([bytes as Uint8Array<ArrayBuffer>])\n\t\t.stream()\n\t\t.pipeThrough(new DecompressionStream(\"deflate-raw\"));\n\treturn JSON.parse(await new Response(stream).text());\n}\n\n/** Parses a JSON frame; anything else is a protocol error. */\nfunction parseFrame(data: string): Frame {\n\tconst frame = unpackObject(JSON.parse(data)) as Frame;\n\tif (frame === null || typeof frame !== \"object\" || typeof frame.t !== \"string\") throw new TypeError(\"not a frame\");\n\treturn frame;\n}\n\n// ─── memory ──────────────────────────────────────────────────────────────────\n\nexport class MemoryLink extends BaseLink {\n\tpeer: MemoryLink | undefined;\n\t#severed = false;\n\t#pending = Promise.resolve();\n\n\t/** Simulates a dead network: frames are dropped silently in both directions and no close is signalled. */\n\tsever(): void {\n\t\tthis.#severed = true;\n\t\tif (this.peer) this.peer.#severed = true;\n\t}\n\n\tprotected transmit(frame: Frame): number | undefined {\n\t\tif (this.#severed) return undefined;\n\t\t// A JSON round trip detaches the frame (and rejects what JSON would mangle silently, e.g. bigint).\n\t\tconst data = JSON.stringify(packObject(frame, true));\n\t\tconst peer = this.peer;\n\t\t// One promise chain per direction keeps delivery FIFO and asynchronous, like a real transport.\n\t\tthis.#pending = this.#pending.then(() => {\n\t\t\tif (!this.#severed && peer !== undefined) peer.deliver(parseFrame(data));\n\t\t});\n\t\treturn data.length;\n\t}\n\n\tprotected shutdown(): void {\n\t\tconst peer = this.peer;\n\t\tthis.#pending = this.#pending.then(() => peer?.ended(\"peer closed\"));\n\t}\n}\n\n/** Two connected in-memory links (tests). */\nexport function memoryLinkPair(): [MemoryLink, MemoryLink] {\n\tconst a = new MemoryLink();\n\tconst b = new MemoryLink();\n\ta.peer = b;\n\tb.peer = a;\n\treturn [a, b];\n}\n\n// ─── Node IPC ────────────────────────────────────────────────────────────────\n\n/** `process` in a forked child, or the parent's `ChildProcess`. Structural, so Chord needs no Node types here. */\nexport interface IpcChannel {\n\treadonly connected: boolean;\n\t/**\n\t * With a callback, Node reports a failed write (the peer process exited and the pipe is broken: `EPIPE`) to it\n\t * instead of emitting `error`, which nobody would handle.\n\t */\n\tsend(message: unknown, callback?: (error: Error | null) => void): boolean;\n\ton(event: \"message\", listener: (message: unknown) => void): unknown;\n\ton(event: \"disconnect\", listener: () => void): unknown;\n\toff(event: \"message\", listener: (message: unknown) => void): unknown;\n\toff(event: \"disconnect\", listener: () => void): unknown;\n}\n\n/**\n * Chord frames on an IPC channel are wrapped as `{ chord2: frame }`; other messages (control) pass by. Both ends are\n * Node processes of one application, so large payloads are packed both ways. Node serializes the messages itself, so\n * the link reports no sizes and is not windowed: both ends are local processes.\n */\nexport class IpcLink extends BaseLink {\n\treadonly #channel: IpcChannel;\n\treadonly #onMessage = (message: unknown): void => {\n\t\tconst frame = (message as { chord2?: unknown } | null)?.chord2;\n\t\tif (frame === undefined) return;\n\t\ttry {\n\t\t\tthis.deliver(unpackObject(frame) as Frame);\n\t\t} catch {\n\t\t\tthis.close(\"protocol error\");\n\t\t}\n\t};\n\treadonly #onDisconnect = (): void => this.ended(\"ipc disconnected\");\n\t/**\n\t * A write can fail after the peer exited and before the channel reports `disconnect` (an `ack` or a `bye` sent then).\n\t * The peer is gone either way: the link ends, as on `disconnect`.\n\t */\n\treadonly #onSent = (error: Error | null): void => {\n\t\tif (error !== null) this.ended(`ipc send failed: ${(error as { code?: string }).code ?? error.message}`);\n\t};\n\n\tconstructor(channel: IpcChannel) {\n\t\tsuper();\n\t\tthis.#channel = channel;\n\t\tchannel.on(\"message\", this.#onMessage);\n\t\tchannel.on(\"disconnect\", this.#onDisconnect);\n\t}\n\n\tprotected transmit(frame: Frame): undefined {\n\t\tif (this.#channel.connected) this.#channel.send({ chord2: packObject(frame, true) }, this.#onSent);\n\t\treturn undefined;\n\t}\n\n\tprotected shutdown(): void {\n\t\tthis.#channel.off(\"message\", this.#onMessage);\n\t\tthis.#channel.off(\"disconnect\", this.#onDisconnect);\n\t}\n}\n\nexport const ipcLink = (channel: IpcChannel): IpcLink => new IpcLink(channel);\n\n// ─── WebSocket ───────────────────────────────────────────────────────────────\n\n/** The WHATWG WebSocket surface: the browser `WebSocket`, Node's global `WebSocket`, and `ws` sockets. */\nexport interface WebSocketLike {\n\treadonly readyState: number;\n\tsend(data: string | Uint8Array): void;\n\tclose(code?: number, reason?: string): void;\n\taddEventListener(type: \"message\", listener: (event: { readonly data: unknown }) => void): void;\n\taddEventListener(type: \"open\" | \"close\" | \"error\", listener: () => void): void;\n}\n\nconst OPEN = 1;\n\nexport interface WebSocketLinkOptions {\n\t/** Deflate large payloads of outgoing frames (default false; the server's side of client sockets). */\n\treadonly compress?: boolean;\n\t/** Accept packed (binary) frames from the peer (default true; false for a server's untrusted clients). */\n\treadonly acceptPacked?: boolean;\n}\n\nexport class WebSocketLink extends BaseLink {\n\treadonly #socket: WebSocketLike;\n\treadonly #compress: boolean;\n\t#outbox: (string | Uint8Array)[] = [];\n\n\tconstructor(socket: WebSocketLike, options: WebSocketLinkOptions = {}) {\n\t\tsuper();\n\t\tthis.#socket = socket;\n\t\tthis.#compress = options.compress ?? false;\n\t\tconst acceptPacked = options.acceptPacked ?? true;\n\t\t// Binary messages as ArrayBuffer (browsers and Node's WebSocket default to Blob).\n\t\tif (\"binaryType\" in socket) (socket as { binaryType: string }).binaryType = \"arraybuffer\";\n\t\tsocket.addEventListener(\"open\", () => {\n\t\t\tfor (const data of this.#outbox.splice(0)) socket.send(data);\n\t\t});\n\t\tsocket.addEventListener(\"message\", (event) => {\n\t\t\ttry {\n\t\t\t\tconst data = event.data;\n\t\t\t\tif (typeof data === \"string\") {\n\t\t\t\t\tthis.deliver(parseFrame(data));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (!acceptPacked) throw new TypeError(\"packed frames are not accepted\");\n\t\t\t\tconst bytes =\n\t\t\t\t\tdata instanceof ArrayBuffer\n\t\t\t\t\t\t? new Uint8Array(data)\n\t\t\t\t\t\t: ArrayBuffer.isView(data)\n\t\t\t\t\t\t\t? new Uint8Array(data.buffer, data.byteOffset, data.byteLength)\n\t\t\t\t\t\t\t: undefined;\n\t\t\t\tif (bytes === undefined) throw new TypeError(\"unknown message type\");\n\t\t\t\tconst { envelope, field, bytes: payload } = splitMessage(bytes);\n\t\t\t\tif (zlib !== undefined) this.deliver({ ...envelope, [field]: new Packed(payload) } as Frame);\n\t\t\t\telse this.deliverLater(inflate(payload).then((value) => ({ ...envelope, [field]: value }) as Frame));\n\t\t\t} catch {\n\t\t\t\tthis.close(\"protocol error\");\n\t\t\t}\n\t\t});\n\t\tsocket.addEventListener(\"close\", () => this.ended(\"socket closed\"));\n\t}\n\n\tprotected transmit(frame: Frame): number {\n\t\tconst data = packMessage(frame, this.#compress);\n\t\tif (this.#socket.readyState === OPEN) this.#socket.send(data);\n\t\telse this.#outbox.push(data);\n\t\treturn typeof data === \"string\" ? data.length : data.byteLength;\n\t}\n\n\tprotected shutdown(): void {\n\t\tthis.#outbox = [];\n\t\tif (this.#socket.readyState <= OPEN) this.#socket.close(1000);\n\t}\n}\n\nexport const webSocketLink = (socket: WebSocketLike, options?: WebSocketLinkOptions): WebSocketLink =>\n\tnew WebSocketLink(socket, options);\n"]}
|
package/dist/loader.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAA0B,WAAW,EAAE,MAAM,WAAW,CAAC;AAmCrE,iHAAiH;AACjH,eAAO,MAAM,UAAU,EAAE,
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAA0B,WAAW,EAAE,MAAM,WAAW,CAAC;AAmCrE,iHAAiH;AACjH,eAAO,MAAM,UAAU,EAAE,WAuBxB,CAAC"}
|
package/dist/loader.js
CHANGED
|
@@ -49,11 +49,16 @@ export const nodeLoader = async (modules) => {
|
|
|
49
49
|
hook();
|
|
50
50
|
const version = String(++generation);
|
|
51
51
|
const facets = [];
|
|
52
|
-
|
|
52
|
+
const urls = modules.map((module) => {
|
|
53
53
|
const url = toUrl(module);
|
|
54
54
|
url.search = "";
|
|
55
|
-
|
|
55
|
+
return url;
|
|
56
|
+
});
|
|
57
|
+
// Every root first: a facet importing another facet's directory gets this load's copy, whatever the order.
|
|
58
|
+
for (const url of urls)
|
|
56
59
|
roots.add(new URL(".", url).href);
|
|
60
|
+
for (const url of urls) {
|
|
61
|
+
const name = url.href;
|
|
57
62
|
url.searchParams.set(PARAM, version);
|
|
58
63
|
// Owner-approved exception to the no-dynamic-import rule; see TODO(loader) above.
|
|
59
64
|
const loaded = (await import(__rewriteRelativeImportExtension(url.href)));
|
package/dist/loader.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":";;;;;;;;AAAA,gHAAgH;AAChH,EAAE;AACF,iHAAiH;AACjH,oHAAoH;AACpH,gCAAgC;AAChC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAGzC,MAAM,KAAK,GAAG,eAAe,CAAC;AAE9B,sGAAsG;AACtG,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;AAChC,IAAI,MAAM,GAAG,KAAK,CAAC;AACnB,IAAI,UAAU,GAAG,CAAC,CAAC;AAEnB;;;;GAIG;AACH,SAAS,IAAI;IACZ,IAAI,MAAM;QAAE,OAAO;IACnB,MAAM,GAAG,IAAI,CAAC;IACd,aAAa,CAAC;QACb,OAAO,CAAC,SAAS,EAAE,OAAO,EAAE,WAAW;YACtC,MAAM,MAAM,GAAG,WAAW,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;YAC/C,MAAM,OAAO,GAAG,OAAO,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YAC5G,IAAI,OAAO,KAAK,IAAI,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC;gBAAE,OAAO,MAAM,CAAC;YACvE,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAChC,IAAI,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;gBAAE,OAAO,MAAM,CAAC;YACxG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;YACrC,OAAO,EAAE,GAAG,MAAM,EAAE,GAAG,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC;QACrC,CAAC;KACD,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,KAAK,GAAG,CAAC,MAAoB,EAAO,EAAE,CAC3C,MAAM,YAAY,GAAG;IACpB,CAAC,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC;IACtB,CAAC,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC;AAE9E,iHAAiH;AACjH,MAAM,CAAC,MAAM,UAAU,GAAgB,KAAK,EAAE,OAAO,EAAE,EAAE;IACxD,IAAI,EAAE,CAAC;IACP,MAAM,OAAO,GAAG,MAAM,CAAC,EAAE,UAAU,CAAC,CAAC;IACrC,MAAM,MAAM,GAAY,EAAE,CAAC;IAC3B,
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":"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","sourcesContent":["// Node facet loader: `createHost({ loader: nodeLoader })`. Kept out of index.ts so the core stays browser-safe.\n//\n// TODO(loader): replace with an isolating, evicting loader. Every reload imports fresh module copies under a new\n// query and the old copies are never evicted (they leak until the process exits). TUI plugins need isolation, which\n// this loader does not provide.\nimport { registerHooks } from \"node:module\";\nimport { pathToFileURL } from \"node:url\";\nimport type { Facet, FacetDefinition, FacetLoader } from \"./host.ts\";\n\nconst PARAM = \"chord2-reload\";\n\n/** Directory URLs (trailing slash) of loaded facet modules; their files are re-imported on reload. */\nconst roots = new Set<string>();\nlet hooked = false;\nlet generation = 0;\n\n/**\n * A query on the entry URL only re-imports the entry module: its relative imports would resolve to cached copies.\n * This hook carries the reload query from a re-imported parent to children inside a facet module's directory.\n * Modules outside (Chord itself, shared code) stay single instances.\n */\nfunction hook(): void {\n\tif (hooked) return;\n\thooked = true;\n\tregisterHooks({\n\t\tresolve(specifier, context, nextResolve) {\n\t\t\tconst result = nextResolve(specifier, context);\n\t\t\tconst version = context.parentURL === undefined ? null : new URL(context.parentURL).searchParams.get(PARAM);\n\t\t\tif (version === null || !result.url.startsWith(\"file:\")) return result;\n\t\t\tconst url = new URL(result.url);\n\t\t\tif (url.searchParams.has(PARAM) || ![...roots].some((root) => url.href.startsWith(root))) return result;\n\t\t\turl.searchParams.set(PARAM, version);\n\t\t\treturn { ...result, url: url.href };\n\t\t},\n\t});\n}\n\nconst toUrl = (module: string | URL): URL =>\n\tmodule instanceof URL\n\t\t? new URL(module.href)\n\t\t: new URL(module.startsWith(\"file:\") ? module : pathToFileURL(module).href);\n\n/** Imports fresh copies of facet modules (default export: a FacetDefinition); each facet is named by its URL. */\nexport const nodeLoader: FacetLoader = async (modules) => {\n\thook();\n\tconst version = String(++generation);\n\tconst facets: Facet[] = [];\n\tconst urls = modules.map((module) => {\n\t\tconst url = toUrl(module);\n\t\turl.search = \"\";\n\t\treturn url;\n\t});\n\t// Every root first: a facet importing another facet's directory gets this load's copy, whatever the order.\n\tfor (const url of urls) roots.add(new URL(\".\", url).href);\n\tfor (const url of urls) {\n\t\tconst name = url.href;\n\t\turl.searchParams.set(PARAM, version);\n\t\t// Owner-approved exception to the no-dynamic-import rule; see TODO(loader) above.\n\t\tconst loaded = (await import(url.href)) as { default?: FacetDefinition };\n\t\tconst definition = loaded.default;\n\t\tif (definition === undefined || typeof definition.setup !== \"function\") {\n\t\t\tthrow new TypeError(`${name}: default export must be a facet (defineFacet)`);\n\t\t}\n\t\tfacets.push({ name, setup: definition.setup, uses: definition.uses });\n\t}\n\treturn facets;\n};\n"]}
|
package/dist/manager.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../src/manager.ts"],"names":[],"mappings":"AASA,OAAO,EAAmB,KAAK,OAAO,EAAW,MAAM,WAAW,CAAC;AAEnE,8FAA8F;AAC9F,MAAM,MAAM,cAAc,GACvB;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;CAAE,GAClD;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;CAAE,GAC1B;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAC9E;IAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAA;CAAE,GAC7B;IACA,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;CAC9B,CAAC;AAEL,MAAM,WAAW,QAAQ;IACxB,iCAAiC;IACjC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,sEAAsE;IACtE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,2GAA2G;IAC3G,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,IAAI;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED,kEAAkE;AAClE,MAAM,WAAW,QAAQ;IACxB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/B,IAAI,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI,CAAC;IACpC,iDAAiD;IACjD,QAAQ,IAAI,IAAI,CAAC;IACjB,SAAS,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,IAAI,GAAG,IAAI,CAAC;CAC7D;AAED,MAAM,WAAW,MAAM;IACtB,KAAK,IAAI,QAAQ,CAAC;CAClB;AAED,MAAM,WAAW,iBAAiB;IACjC,gCAAgC;IAChC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,QAAQ,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAChD,qFAAqF;IACrF,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,8EAA8E;IAC9E,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IACxB;;;OAGG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,8FAA8F;IAC9F,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,QAAQ,GAAG,QAAQ,EAAE,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;IAC7E,uGAAuG;IACvG,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;CAChD;AAED;;;;;GAKG;AACH,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,CAyC5E;
|
|
1
|
+
{"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../src/manager.ts"],"names":[],"mappings":"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"}
|