@earendil-works/chord 1.1.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.
Files changed (190) hide show
  1. package/CHANGELOG.md +78 -0
  2. package/README.md +79 -195
  3. package/dist/cell.d.ts +122 -0
  4. package/dist/cell.d.ts.map +1 -0
  5. package/dist/cell.js +356 -0
  6. package/dist/cell.js.map +1 -0
  7. package/dist/cluster.d.ts +27 -0
  8. package/dist/cluster.d.ts.map +1 -0
  9. package/dist/cluster.js +230 -0
  10. package/dist/cluster.js.map +1 -0
  11. package/dist/connection.d.ts +270 -0
  12. package/dist/connection.d.ts.map +1 -0
  13. package/dist/connection.js +1216 -0
  14. package/dist/connection.js.map +1 -0
  15. package/dist/context/index.d.ts +12 -1
  16. package/dist/context/index.d.ts.map +1 -1
  17. package/dist/context/index.js.map +1 -1
  18. package/dist/contract.d.ts +208 -0
  19. package/dist/contract.d.ts.map +1 -0
  20. package/dist/contract.js +246 -0
  21. package/dist/contract.js.map +1 -0
  22. package/dist/declare.d.ts +33 -0
  23. package/dist/declare.d.ts.map +1 -0
  24. package/dist/declare.js +2 -0
  25. package/dist/declare.js.map +1 -0
  26. package/dist/delta/apply-immutable-trusted.js.map +1 -1
  27. package/dist/delta/diff.d.ts +1 -1
  28. package/dist/delta/diff.d.ts.map +1 -1
  29. package/dist/delta/diff.js.map +1 -1
  30. package/dist/delta/index.d.ts +4 -3
  31. package/dist/delta/index.d.ts.map +1 -1
  32. package/dist/delta/index.js +45 -0
  33. package/dist/delta/index.js.map +1 -1
  34. package/dist/delta/revision-validator.d.ts +1 -1
  35. package/dist/delta/revision-validator.d.ts.map +1 -1
  36. package/dist/delta/revision-validator.js.map +1 -1
  37. package/dist/delta/tracker.d.ts +1 -1
  38. package/dist/delta/tracker.d.ts.map +1 -1
  39. package/dist/delta/tracker.js +40 -4
  40. package/dist/delta/tracker.js.map +1 -1
  41. package/dist/errors.d.ts +28 -0
  42. package/dist/errors.d.ts.map +1 -0
  43. package/dist/errors.js +59 -0
  44. package/dist/errors.js.map +1 -0
  45. package/dist/host.d.ts +348 -0
  46. package/dist/host.d.ts.map +1 -0
  47. package/dist/host.js +1000 -0
  48. package/dist/host.js.map +1 -0
  49. package/dist/index.d.ts +17 -10
  50. package/dist/index.d.ts.map +1 -1
  51. package/dist/index.js +8 -8
  52. package/dist/index.js.map +1 -1
  53. package/dist/json.d.ts +9 -1
  54. package/dist/json.d.ts.map +1 -1
  55. package/dist/json.js.map +1 -1
  56. package/dist/link.d.ts +107 -0
  57. package/dist/link.d.ts.map +1 -0
  58. package/dist/link.js +355 -0
  59. package/dist/link.js.map +1 -0
  60. package/dist/loader.d.ts +4 -0
  61. package/dist/loader.d.ts.map +1 -0
  62. package/dist/loader.js +73 -0
  63. package/dist/loader.js.map +1 -0
  64. package/dist/manager.d.ts +115 -0
  65. package/dist/manager.d.ts.map +1 -0
  66. package/dist/manager.js +345 -0
  67. package/dist/manager.js.map +1 -0
  68. package/dist/node.d.ts +3 -4
  69. package/dist/node.d.ts.map +1 -1
  70. package/dist/node.js +3 -2
  71. package/dist/node.js.map +1 -1
  72. package/dist/object.d.ts +438 -0
  73. package/dist/object.d.ts.map +1 -0
  74. package/dist/object.js +1571 -0
  75. package/dist/object.js.map +1 -0
  76. package/dist/output.d.ts +85 -0
  77. package/dist/output.d.ts.map +1 -0
  78. package/dist/output.js +350 -0
  79. package/dist/output.js.map +1 -0
  80. package/dist/publish.d.ts +5 -0
  81. package/dist/publish.d.ts.map +1 -0
  82. package/dist/publish.js +40 -0
  83. package/dist/publish.js.map +1 -0
  84. package/dist/registry.d.ts +25 -0
  85. package/dist/registry.d.ts.map +1 -0
  86. package/dist/registry.js +6 -0
  87. package/dist/registry.js.map +1 -0
  88. package/dist/reload.d.ts +126 -0
  89. package/dist/reload.d.ts.map +1 -0
  90. package/dist/reload.js +653 -0
  91. package/dist/reload.js.map +1 -0
  92. package/dist/remote.d.ts +165 -0
  93. package/dist/remote.d.ts.map +1 -0
  94. package/dist/remote.js +612 -0
  95. package/dist/remote.js.map +1 -0
  96. package/dist/schema.d.ts +21 -0
  97. package/dist/schema.d.ts.map +1 -0
  98. package/dist/schema.js +228 -0
  99. package/dist/schema.js.map +1 -0
  100. package/dist/state.d.ts +92 -0
  101. package/dist/state.d.ts.map +1 -0
  102. package/dist/{services/state.js → state.js} +28 -138
  103. package/dist/state.js.map +1 -0
  104. package/dist/types.d.ts +69 -258
  105. package/dist/types.d.ts.map +1 -1
  106. package/dist/types.js.map +1 -1
  107. package/dist/websocket.d.ts +15 -0
  108. package/dist/websocket.d.ts.map +1 -0
  109. package/dist/websocket.js +16 -0
  110. package/dist/websocket.js.map +1 -0
  111. package/dist/wire.d.ts +216 -0
  112. package/dist/wire.d.ts.map +1 -0
  113. package/dist/wire.js +165 -0
  114. package/dist/wire.js.map +1 -0
  115. package/docs/guide.md +814 -0
  116. package/docs/spec.md +288 -0
  117. package/docs/tutorial.md +931 -0
  118. package/package.json +14 -10
  119. package/src/delta/README.md +5 -3
  120. package/dist/api.d.ts +0 -20
  121. package/dist/api.d.ts.map +0 -1
  122. package/dist/api.js +0 -77
  123. package/dist/api.js.map +0 -1
  124. package/dist/bundler.d.ts +0 -6
  125. package/dist/bundler.d.ts.map +0 -1
  126. package/dist/bundler.js +0 -3
  127. package/dist/bundler.js.map +0 -1
  128. package/dist/facets/host.d.ts +0 -12
  129. package/dist/facets/host.d.ts.map +0 -1
  130. package/dist/facets/host.js +0 -763
  131. package/dist/facets/host.js.map +0 -1
  132. package/dist/facets/loader.d.ts +0 -3
  133. package/dist/facets/loader.d.ts.map +0 -1
  134. package/dist/facets/loader.js +0 -5
  135. package/dist/facets/loader.js.map +0 -1
  136. package/dist/node/bundle-loader.d.ts +0 -30
  137. package/dist/node/bundle-loader.d.ts.map +0 -1
  138. package/dist/node/bundle-loader.js +0 -377
  139. package/dist/node/bundle-loader.js.map +0 -1
  140. package/dist/node/bundle.d.ts +0 -26
  141. package/dist/node/bundle.d.ts.map +0 -1
  142. package/dist/node/bundle.js +0 -183
  143. package/dist/node/bundle.js.map +0 -1
  144. package/dist/node/manifest.d.ts +0 -36
  145. package/dist/node/manifest.d.ts.map +0 -1
  146. package/dist/node/manifest.js +0 -6
  147. package/dist/node/manifest.js.map +0 -1
  148. package/dist/node/package.d.ts +0 -15
  149. package/dist/node/package.d.ts.map +0 -1
  150. package/dist/node/package.js +0 -199
  151. package/dist/node/package.js.map +0 -1
  152. package/dist/services/consumer.d.ts +0 -11
  153. package/dist/services/consumer.d.ts.map +0 -1
  154. package/dist/services/consumer.js +0 -585
  155. package/dist/services/consumer.js.map +0 -1
  156. package/dist/services/errors.d.ts +0 -8
  157. package/dist/services/errors.d.ts.map +0 -1
  158. package/dist/services/errors.js +0 -22
  159. package/dist/services/errors.js.map +0 -1
  160. package/dist/services/handle.d.ts +0 -15
  161. package/dist/services/handle.d.ts.map +0 -1
  162. package/dist/services/handle.js +0 -101
  163. package/dist/services/handle.js.map +0 -1
  164. package/dist/services/instances.d.ts +0 -26
  165. package/dist/services/instances.d.ts.map +0 -1
  166. package/dist/services/instances.js +0 -140
  167. package/dist/services/instances.js.map +0 -1
  168. package/dist/services/loopback.d.ts +0 -5
  169. package/dist/services/loopback.d.ts.map +0 -1
  170. package/dist/services/loopback.js +0 -15
  171. package/dist/services/loopback.js.map +0 -1
  172. package/dist/services/provider.d.ts +0 -37
  173. package/dist/services/provider.d.ts.map +0 -1
  174. package/dist/services/provider.js +0 -521
  175. package/dist/services/provider.js.map +0 -1
  176. package/dist/services/state-codec.d.ts +0 -15
  177. package/dist/services/state-codec.d.ts.map +0 -1
  178. package/dist/services/state-codec.js +0 -133
  179. package/dist/services/state-codec.js.map +0 -1
  180. package/dist/services/state-internals.d.ts +0 -13
  181. package/dist/services/state-internals.d.ts.map +0 -1
  182. package/dist/services/state-internals.js +0 -10
  183. package/dist/services/state-internals.js.map +0 -1
  184. package/dist/services/state.d.ts +0 -28
  185. package/dist/services/state.d.ts.map +0 -1
  186. package/dist/services/state.js.map +0 -1
  187. package/dist/services/wire.d.ts +0 -63
  188. package/dist/services/wire.d.ts.map +0 -1
  189. package/dist/services/wire.js +0 -186
  190. package/dist/services/wire.js.map +0 -1
package/dist/link.js ADDED
@@ -0,0 +1,355 @@
1
+ /** Shared plumbing: receive queue, close handlers, `bye`. Transports implement `transmit` and `shutdown`. */
2
+ class BaseLink {
3
+ #handler;
4
+ #queue = [];
5
+ #closeHandlers = new Set();
6
+ #closed = false;
7
+ /** The tail of frames being decoded asynchronously; undefined when none is. */
8
+ #decoding;
9
+ get closed() {
10
+ return this.#closed;
11
+ }
12
+ send(frame) {
13
+ if (this.#closed)
14
+ return undefined;
15
+ return this.transmit(frame);
16
+ }
17
+ receive(handler) {
18
+ this.#handler = handler;
19
+ for (const frame of this.#queue.splice(0))
20
+ handler(frame);
21
+ }
22
+ onClose(handler) {
23
+ if (this.#closed)
24
+ handler("closed");
25
+ else
26
+ this.#closeHandlers.add(handler);
27
+ }
28
+ close(reason = "closed") {
29
+ if (this.#closed)
30
+ return;
31
+ try {
32
+ this.transmit({ t: "bye", reason });
33
+ }
34
+ catch {
35
+ // The transport may already be gone.
36
+ }
37
+ this.ended(reason);
38
+ }
39
+ /** Delivers a parsed frame from the transport, after any frame still being decoded (`deliverLater`). */
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) {
58
+ if (this.#closed)
59
+ return;
60
+ if (frame.t === "bye") {
61
+ this.ended(frame.reason ?? "peer closed");
62
+ return;
63
+ }
64
+ if (this.#handler === undefined)
65
+ this.#queue.push(frame);
66
+ else
67
+ this.#handler(frame);
68
+ }
69
+ /** Marks the link closed (transport ended) and notifies once. */
70
+ ended(reason) {
71
+ if (this.#closed)
72
+ return;
73
+ this.#closed = true;
74
+ this.#queue = [];
75
+ try {
76
+ this.shutdown();
77
+ }
78
+ finally {
79
+ for (const handler of this.#closeHandlers)
80
+ handler(reason);
81
+ this.#closeHandlers.clear();
82
+ }
83
+ }
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
+ }
207
+ /** Parses a JSON frame; anything else is a protocol error. */
208
+ function parseFrame(data) {
209
+ const frame = unpackObject(JSON.parse(data));
210
+ if (frame === null || typeof frame !== "object" || typeof frame.t !== "string")
211
+ throw new TypeError("not a frame");
212
+ return frame;
213
+ }
214
+ // ─── memory ──────────────────────────────────────────────────────────────────
215
+ export class MemoryLink extends BaseLink {
216
+ peer;
217
+ #severed = false;
218
+ #pending = Promise.resolve();
219
+ /** Simulates a dead network: frames are dropped silently in both directions and no close is signalled. */
220
+ sever() {
221
+ this.#severed = true;
222
+ if (this.peer)
223
+ this.peer.#severed = true;
224
+ }
225
+ transmit(frame) {
226
+ if (this.#severed)
227
+ return undefined;
228
+ // A JSON round trip detaches the frame (and rejects what JSON would mangle silently, e.g. bigint).
229
+ const data = JSON.stringify(packObject(frame, true));
230
+ const peer = this.peer;
231
+ // One promise chain per direction keeps delivery FIFO and asynchronous, like a real transport.
232
+ this.#pending = this.#pending.then(() => {
233
+ if (!this.#severed && peer !== undefined)
234
+ peer.deliver(parseFrame(data));
235
+ });
236
+ return data.length;
237
+ }
238
+ shutdown() {
239
+ const peer = this.peer;
240
+ this.#pending = this.#pending.then(() => peer?.ended("peer closed"));
241
+ }
242
+ }
243
+ /** Two connected in-memory links (tests). */
244
+ export function memoryLinkPair() {
245
+ const a = new MemoryLink();
246
+ const b = new MemoryLink();
247
+ a.peer = b;
248
+ b.peer = a;
249
+ return [a, b];
250
+ }
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
+ */
256
+ export class IpcLink extends BaseLink {
257
+ #channel;
258
+ #onMessage = (message) => {
259
+ const frame = message?.chord2;
260
+ if (frame === undefined)
261
+ return;
262
+ try {
263
+ this.deliver(unpackObject(frame));
264
+ }
265
+ catch {
266
+ this.close("protocol error");
267
+ }
268
+ };
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
+ };
278
+ constructor(channel) {
279
+ super();
280
+ this.#channel = channel;
281
+ channel.on("message", this.#onMessage);
282
+ channel.on("disconnect", this.#onDisconnect);
283
+ }
284
+ transmit(frame) {
285
+ if (this.#channel.connected)
286
+ this.#channel.send({ chord2: packObject(frame, true) }, this.#onSent);
287
+ return undefined;
288
+ }
289
+ shutdown() {
290
+ this.#channel.off("message", this.#onMessage);
291
+ this.#channel.off("disconnect", this.#onDisconnect);
292
+ }
293
+ }
294
+ export const ipcLink = (channel) => new IpcLink(channel);
295
+ const OPEN = 1;
296
+ export class WebSocketLink extends BaseLink {
297
+ #socket;
298
+ #compress;
299
+ #outbox = [];
300
+ constructor(socket, options = {}) {
301
+ super();
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";
308
+ socket.addEventListener("open", () => {
309
+ for (const data of this.#outbox.splice(0))
310
+ socket.send(data);
311
+ });
312
+ socket.addEventListener("message", (event) => {
313
+ try {
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 })));
333
+ }
334
+ catch {
335
+ this.close("protocol error");
336
+ }
337
+ });
338
+ socket.addEventListener("close", () => this.ended("socket closed"));
339
+ }
340
+ transmit(frame) {
341
+ const data = packMessage(frame, this.#compress);
342
+ if (this.#socket.readyState === OPEN)
343
+ this.#socket.send(data);
344
+ else
345
+ this.#outbox.push(data);
346
+ return typeof data === "string" ? data.length : data.byteLength;
347
+ }
348
+ shutdown() {
349
+ this.#outbox = [];
350
+ if (this.#socket.readyState <= OPEN)
351
+ this.#socket.close(1000);
352
+ }
353
+ }
354
+ export const webSocketLink = (socket, options) => new WebSocketLink(socket, options);
355
+ //# sourceMappingURL=link.js.map
@@ -0,0 +1 @@
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"]}
@@ -0,0 +1,4 @@
1
+ import type { FacetLoader } from "./host.ts";
2
+ /** Imports fresh copies of facet modules (default export: a FacetDefinition); each facet is named by its URL. */
3
+ export declare const nodeLoader: FacetLoader;
4
+ //# sourceMappingURL=loader.d.ts.map
@@ -0,0 +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,WAuBxB,CAAC"}
package/dist/loader.js ADDED
@@ -0,0 +1,73 @@
1
+ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
2
+ if (typeof path === "string" && /^\.\.?\//.test(path)) {
3
+ return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
4
+ return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
5
+ });
6
+ }
7
+ return path;
8
+ };
9
+ // Node facet loader: `createHost({ loader: nodeLoader })`. Kept out of index.ts so the core stays browser-safe.
10
+ //
11
+ // TODO(loader): replace with an isolating, evicting loader. Every reload imports fresh module copies under a new
12
+ // query and the old copies are never evicted (they leak until the process exits). TUI plugins need isolation, which
13
+ // this loader does not provide.
14
+ import { registerHooks } from "node:module";
15
+ import { pathToFileURL } from "node:url";
16
+ const PARAM = "chord2-reload";
17
+ /** Directory URLs (trailing slash) of loaded facet modules; their files are re-imported on reload. */
18
+ const roots = new Set();
19
+ let hooked = false;
20
+ let generation = 0;
21
+ /**
22
+ * A query on the entry URL only re-imports the entry module: its relative imports would resolve to cached copies.
23
+ * This hook carries the reload query from a re-imported parent to children inside a facet module's directory.
24
+ * Modules outside (Chord itself, shared code) stay single instances.
25
+ */
26
+ function hook() {
27
+ if (hooked)
28
+ return;
29
+ hooked = true;
30
+ registerHooks({
31
+ resolve(specifier, context, nextResolve) {
32
+ const result = nextResolve(specifier, context);
33
+ const version = context.parentURL === undefined ? null : new URL(context.parentURL).searchParams.get(PARAM);
34
+ if (version === null || !result.url.startsWith("file:"))
35
+ return result;
36
+ const url = new URL(result.url);
37
+ if (url.searchParams.has(PARAM) || ![...roots].some((root) => url.href.startsWith(root)))
38
+ return result;
39
+ url.searchParams.set(PARAM, version);
40
+ return { ...result, url: url.href };
41
+ },
42
+ });
43
+ }
44
+ const toUrl = (module) => module instanceof URL
45
+ ? new URL(module.href)
46
+ : new URL(module.startsWith("file:") ? module : pathToFileURL(module).href);
47
+ /** Imports fresh copies of facet modules (default export: a FacetDefinition); each facet is named by its URL. */
48
+ export const nodeLoader = async (modules) => {
49
+ hook();
50
+ const version = String(++generation);
51
+ const facets = [];
52
+ const urls = modules.map((module) => {
53
+ const url = toUrl(module);
54
+ url.search = "";
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)
59
+ roots.add(new URL(".", url).href);
60
+ for (const url of urls) {
61
+ const name = url.href;
62
+ url.searchParams.set(PARAM, version);
63
+ // Owner-approved exception to the no-dynamic-import rule; see TODO(loader) above.
64
+ const loaded = (await import(__rewriteRelativeImportExtension(url.href)));
65
+ const definition = loaded.default;
66
+ if (definition === undefined || typeof definition.setup !== "function") {
67
+ throw new TypeError(`${name}: default export must be a facet (defineFacet)`);
68
+ }
69
+ facets.push({ name, setup: definition.setup, uses: definition.uses });
70
+ }
71
+ return facets;
72
+ };
73
+ //# sourceMappingURL=loader.js.map
@@ -0,0 +1 @@
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"]}
@@ -0,0 +1,115 @@
1
+ import { type IpcLink } from "./link.ts";
2
+ /** Control messages share the IPC channel with chord frames: `{ chord2control: message }`. */
3
+ export type ControlMessage = {
4
+ readonly type: "init";
5
+ readonly value: unknown;
6
+ } | {
7
+ readonly type: "ready";
8
+ } | {
9
+ readonly type: "fatal";
10
+ readonly message: string;
11
+ readonly reason?: string;
12
+ } | {
13
+ readonly type: "shutdown";
14
+ } | {
15
+ readonly type: "status";
16
+ readonly activeCalls?: number;
17
+ readonly viewers?: number;
18
+ readonly durableTasks?: number;
19
+ };
20
+ export interface Liveness {
21
+ /** Started but not ready yet. */
22
+ readonly booting: boolean;
23
+ readonly activeCalls: number;
24
+ /** Viewers the child reports (it counts heartbeating subscribers). */
25
+ readonly viewers: number;
26
+ readonly durableTasks: number;
27
+ /** Milliseconds since the child last reported work (calls, viewers or tasks), or since it became ready. */
28
+ readonly idleFor: number;
29
+ }
30
+ export interface Exit {
31
+ readonly code: number | null;
32
+ readonly signal: string | null;
33
+ }
34
+ /** A running child: its link (for `host.accept`) and its exit. */
35
+ export interface Instance {
36
+ readonly pid: number;
37
+ readonly link: IpcLink;
38
+ readonly exited: Promise<Exit>;
39
+ send(message: ControlMessage): void;
40
+ /** Kills the child and everything it spawned. */
41
+ killTree(): void;
42
+ onControl(listener: (message: ControlMessage) => void): void;
43
+ }
44
+ export interface Driver {
45
+ spawn(): Instance;
46
+ }
47
+ export interface ForkDriverOptions {
48
+ /** The child's entry module. */
49
+ readonly entry: string;
50
+ readonly args?: readonly string[];
51
+ readonly env?: Readonly<Record<string, string>>;
52
+ /** Node flags for the child, e.g. `["--import", sourceResolver]` (default: none). */
53
+ readonly execArgv?: readonly string[];
54
+ /** Sent to the child as its first control message (`childControl().init`). */
55
+ readonly init?: unknown;
56
+ /**
57
+ * A lock name: one live process per name, across managers and processes. The child acquires it as a kernel lock
58
+ * (`childControl().lock()`, before opening its storage); a second child fails to start with `unavailable/locked`.
59
+ */
60
+ readonly lock?: string;
61
+ /** Optional stdout/stderr tap. Streams are still mirrored to the parent's standard output. */
62
+ readonly onOutput?: (stream: "stdout" | "stderr", chunk: Uint8Array) => void;
63
+ /** Optional application metadata tap; control messages and chord frames keep their normal handling. */
64
+ readonly onMessage?: (message: unknown) => void;
65
+ }
66
+ /**
67
+ * A process lock owned by the kernel for the holder's lifetime: an abstract socket (Linux, Android) or a named pipe
68
+ * (Windows) vanishes with its process, so there is no stale state to take over and no race between two would-be
69
+ * owners. Other platforms need a socket file, removed on exit; a leftover one nobody accepts on is taken over.
70
+ * The child acquires it (before opening storage), so the lock follows the process that owns the data.
71
+ */
72
+ export declare function processLock(name: string): Promise<() => Promise<void>>;
73
+ export declare function forkDriver(options: ForkDriverOptions): Driver;
74
+ export interface HostManagerOptions {
75
+ readonly driver: Driver;
76
+ /** Evaluated every `checkInterval` while running; `false` stops the child. */
77
+ readonly keepAlive?: (liveness: Liveness) => boolean;
78
+ readonly checkInterval?: number;
79
+ /** Milliseconds a child may take to shut down before its process tree is killed (default 5000). */
80
+ readonly grace?: number;
81
+ /** Milliseconds to wait for `ready` (default 30000). */
82
+ readonly readyTimeout?: number;
83
+ /** The child exited on its own (crash, fatal) or after a stop. */
84
+ readonly onExit?: (exit: Exit) => void;
85
+ }
86
+ export interface HostManager {
87
+ readonly status: "stopped" | "starting" | "running" | "stopping";
88
+ readonly instance: Instance | undefined;
89
+ readonly liveness: Liveness;
90
+ /** Starts the child (or returns the running one) once it reported ready. Serialized with stop/replace. */
91
+ start(): Promise<Instance>;
92
+ /** Asks the child to shut down, then kills its process tree after the grace period. */
93
+ stop(): Promise<void>;
94
+ /** Stop, wait for the exit, start. */
95
+ replace(): Promise<Instance>;
96
+ }
97
+ export declare function createHostManager(options: HostManagerOptions): HostManager;
98
+ /** The child side of the control channel (call in the child's entry). */
99
+ export declare function childControl(channel?: NodeJS.Process): {
100
+ readonly init: Promise<unknown>;
101
+ /**
102
+ * Acquires the manager's lock (if one was configured) as a kernel lock held for this process's lifetime. Call it
103
+ * before opening storage. Fails with `unavailable/locked`, also reported to the manager as a fatal start error.
104
+ */
105
+ lock(): Promise<void>;
106
+ ready(): void;
107
+ fatal(error: unknown): void;
108
+ report(status: {
109
+ activeCalls?: number;
110
+ viewers?: number;
111
+ durableTasks?: number;
112
+ }): void;
113
+ onShutdown(handler: () => void | Promise<void>): void;
114
+ };
115
+ //# sourceMappingURL=manager.d.ts.map
@@ -0,0 +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;AAyCD,wBAAgB,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,MAAM,CAiE7D;AAED,MAAM,WAAW,kBAAkB;IAClC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,8EAA8E;IAC9E,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,KAAK,OAAO,CAAC;IACrD,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,mGAAmG;IACnG,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,wDAAwD;IACxD,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,kEAAkE;IAClE,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;CACvC;AAED,MAAM,WAAW,WAAW;IAC3B,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,UAAU,GAAG,SAAS,GAAG,UAAU,CAAC;IACjE,QAAQ,CAAC,QAAQ,EAAE,QAAQ,GAAG,SAAS,CAAC;IACxC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,0GAA0G;IAC1G,KAAK,IAAI,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC3B,uFAAuF;IACvF,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACtB,sCAAsC;IACtC,OAAO,IAAI,OAAO,CAAC,QAAQ,CAAC,CAAC;CAC7B;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,kBAAkB,GAAG,WAAW,CAuI1E;AAED,yEAAyE;AACzE,wBAAgB,YAAY,CAAC,OAAO,GAAE,MAAM,CAAC,OAAiB,GAAG;IAChE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IAChC;;;OAGG;IACH,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACtB,KAAK,IAAI,IAAI,CAAC;IACd,KAAK,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAAC;IAC5B,MAAM,CAAC,MAAM,EAAE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACxF,UAAU,CAAC,OAAO,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CACtD,CAsCA"}