@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
@@ -0,0 +1,345 @@
1
+ // Host manager (Node only): runs a child host process and keeps at most one instance of it alive.
2
+ import { fork } from "node:child_process";
3
+ import { createHash } from "node:crypto";
4
+ import { unlinkSync } from "node:fs";
5
+ import { lstat, mkdir, rm } from "node:fs/promises";
6
+ import { connect, createServer } from "node:net";
7
+ import { tmpdir } from "node:os";
8
+ import { join } from "node:path";
9
+ import { ChordError } from "./errors.js";
10
+ import { ipcLink } from "./link.js";
11
+ /**
12
+ * A process lock owned by the kernel for the holder's lifetime: an abstract socket (Linux, Android) or a named pipe
13
+ * (Windows) vanishes with its process, so there is no stale state to take over and no race between two would-be
14
+ * owners. Other platforms need a socket file, removed on exit; a leftover one nobody accepts on is taken over.
15
+ * The child acquires it (before opening storage), so the lock follows the process that owns the data.
16
+ */
17
+ export async function processLock(name) {
18
+ const key = createHash("sha256").update(name).digest("hex").slice(0, 32);
19
+ const file = process.platform !== "win32" && process.platform !== "linux" && process.platform !== "android";
20
+ const address = process.platform === "win32"
21
+ ? `\\\\.\\pipe\\chord2-${key}`
22
+ : file
23
+ ? await lockSocketPath(`chord2-${key}.sock`)
24
+ : `\0chord2-${key}`;
25
+ const server = createServer((socket) => socket.end());
26
+ for (;;) {
27
+ try {
28
+ await new Promise((resolve, reject) => {
29
+ server.once("error", reject);
30
+ server.listen(address, () => {
31
+ server.removeListener("error", reject);
32
+ resolve();
33
+ });
34
+ });
35
+ break;
36
+ }
37
+ catch (error) {
38
+ if (error.code !== "EADDRINUSE")
39
+ throw error;
40
+ if (!file || (await accepting(address))) {
41
+ throw new ChordError("unavailable", `lock ${name} is held by another process`, { reason: "locked" });
42
+ }
43
+ await rm(address, { force: true });
44
+ }
45
+ }
46
+ const removeFile = () => {
47
+ try {
48
+ unlinkSync(address);
49
+ }
50
+ catch {
51
+ // Already gone.
52
+ }
53
+ };
54
+ if (file)
55
+ process.once("exit", removeFile);
56
+ return () => new Promise((resolve, reject) => {
57
+ if (file)
58
+ process.removeListener("exit", removeFile);
59
+ server.close((error) => (error ? reject(error) : resolve()));
60
+ });
61
+ }
62
+ /** sun_path references 104 bytes on macOS and the BSDs, including the terminating NUL. */
63
+ const MAX_SOCKET_PATH_BYTES = 103;
64
+ /**
65
+ * The lock socket's path: in the temporary directory, or, when that path does not fit in sun_path (a deep TMPDIR,
66
+ * such as a test runner's below macOS's per-user one), in a private per-user directory under /tmp. Other users must
67
+ * not be able to create or remove sockets there, so the directory has to be ours and closed to everyone else.
68
+ */
69
+ async function lockSocketPath(file) {
70
+ const preferred = join(tmpdir(), file);
71
+ if (Buffer.byteLength(preferred) <= MAX_SOCKET_PATH_BYTES)
72
+ return preferred;
73
+ const uid = process.getuid?.() ?? 0;
74
+ const directory = `/tmp/chord2-${uid}`;
75
+ await mkdir(directory, { mode: 0o700, recursive: true });
76
+ const stats = await lstat(directory);
77
+ if (!stats.isDirectory() || stats.uid !== uid || (stats.mode & 0o077) !== 0) {
78
+ throw new ChordError("unavailable", `lock directory ${directory} must be a directory only its owner can access`);
79
+ }
80
+ return join(directory, file);
81
+ }
82
+ function accepting(address) {
83
+ return new Promise((resolve) => {
84
+ const socket = connect(address);
85
+ socket.once("connect", () => {
86
+ socket.destroy();
87
+ resolve(true);
88
+ });
89
+ socket.once("error", (error) => resolve(error.code !== "ECONNREFUSED" && error.code !== "ENOENT"));
90
+ });
91
+ }
92
+ const LOCK_ENV = "CHORD2_LOCK";
93
+ /** A control message to a peer process that is gone: dropped (its exit or `disconnect` is reported separately). */
94
+ const ignoreSendError = () => { };
95
+ export function forkDriver(options) {
96
+ return {
97
+ spawn() {
98
+ // A lock this process inherited (e.g. as a child host itself) is not the child's: it gets only its own.
99
+ const env = { ...process.env };
100
+ delete env[LOCK_ENV];
101
+ Object.assign(env, options.env);
102
+ if (options.lock !== undefined)
103
+ env[LOCK_ENV] = options.lock;
104
+ // Detached: the child leads a process group, so the whole tree can be killed.
105
+ const child = fork(options.entry, [...(options.args ?? [])], {
106
+ env,
107
+ execArgv: [...(options.execArgv ?? [])],
108
+ detached: true,
109
+ stdio: ["ignore", options.onOutput ? "pipe" : "inherit", options.onOutput ? "pipe" : "inherit", "ipc"],
110
+ });
111
+ if (options.onOutput) {
112
+ for (const stream of ["stdout", "stderr"]) {
113
+ child[stream]?.on("data", (chunk) => {
114
+ options.onOutput(stream, chunk);
115
+ process[stream].write(chunk);
116
+ });
117
+ }
118
+ }
119
+ const pid = child.pid ?? -1;
120
+ const killGroup = () => {
121
+ try {
122
+ process.kill(-pid, "SIGKILL");
123
+ }
124
+ catch {
125
+ // No group left.
126
+ }
127
+ };
128
+ const exited = new Promise((resolve) => {
129
+ child.once("exit", (code, signal) => {
130
+ // However the leader ended (graceful, crash, kill), nothing it spawned outlives it.
131
+ killGroup();
132
+ resolve({ code, signal });
133
+ });
134
+ });
135
+ const listeners = new Set();
136
+ child.on("message", (message) => {
137
+ options.onMessage?.(message);
138
+ const control = message?.chord2control;
139
+ if (control !== undefined)
140
+ for (const listener of listeners)
141
+ listener(control);
142
+ });
143
+ const send = (message) => {
144
+ // A child that exited before the channel reported it fails the write (EPIPE): its exit is what counts.
145
+ if (child.connected)
146
+ child.send({ chord2control: message }, ignoreSendError);
147
+ };
148
+ if (options.init !== undefined)
149
+ send({ type: "init", value: options.init });
150
+ return {
151
+ pid,
152
+ link: ipcLink(child),
153
+ exited,
154
+ send,
155
+ killTree: () => {
156
+ try {
157
+ process.kill(-pid, "SIGKILL");
158
+ }
159
+ catch {
160
+ child.kill("SIGKILL");
161
+ }
162
+ },
163
+ onControl: (listener) => listeners.add(listener),
164
+ };
165
+ },
166
+ };
167
+ }
168
+ export function createHostManager(options) {
169
+ let status = "stopped";
170
+ let instance;
171
+ let queue = Promise.resolve();
172
+ let report = { activeCalls: 0, viewers: 0, durableTasks: 0 };
173
+ /** When the child last became idle; undefined while it reports work. */
174
+ let idleSince;
175
+ let booting = false;
176
+ let timer;
177
+ const serialized = (step) => {
178
+ const next = queue.then(step, step);
179
+ queue = next.catch(() => { });
180
+ return next;
181
+ };
182
+ const liveness = () => ({
183
+ booting,
184
+ ...report,
185
+ idleFor: idleSince === undefined ? 0 : Date.now() - idleSince,
186
+ });
187
+ const doStop = async () => {
188
+ const current = instance;
189
+ if (current === undefined) {
190
+ status = "stopped";
191
+ booting = false;
192
+ return;
193
+ }
194
+ status = "stopping";
195
+ if (timer !== undefined)
196
+ clearInterval(timer);
197
+ current.send({ type: "shutdown" });
198
+ let graceTimer;
199
+ const graceful = await Promise.race([
200
+ current.exited.then(() => true),
201
+ new Promise((resolve) => {
202
+ graceTimer = setTimeout(() => resolve(false), options.grace ?? 5000);
203
+ }),
204
+ ]);
205
+ clearTimeout(graceTimer);
206
+ if (!graceful)
207
+ current.killTree();
208
+ await current.exited;
209
+ if (instance === current)
210
+ instance = undefined;
211
+ status = "stopped";
212
+ };
213
+ const doStart = async () => {
214
+ if (instance !== undefined && status === "running")
215
+ return instance;
216
+ status = "starting";
217
+ booting = true;
218
+ report = { activeCalls: 0, viewers: 0, durableTasks: 0 };
219
+ let current;
220
+ try {
221
+ current = options.driver.spawn();
222
+ }
223
+ catch (error) {
224
+ status = "stopped";
225
+ booting = false;
226
+ throw error;
227
+ }
228
+ instance = current;
229
+ current.exited.then((exit) => {
230
+ if (instance === current) {
231
+ instance = undefined;
232
+ status = "stopped";
233
+ if (timer !== undefined)
234
+ clearInterval(timer);
235
+ }
236
+ options.onExit?.(exit);
237
+ });
238
+ await new Promise((resolve, reject) => {
239
+ const timeout = setTimeout(() => reject(new ChordError("unavailable", "child not ready in time")), options.readyTimeout ?? 30_000);
240
+ const settle = (fn) => {
241
+ clearTimeout(timeout);
242
+ fn();
243
+ };
244
+ current.exited.then((exit) => settle(() => reject(new ChordError("unavailable", `child exited before ready (${exit.code ?? exit.signal})`))));
245
+ current.onControl((message) => {
246
+ if (message.type === "ready")
247
+ settle(resolve);
248
+ else if (message.type === "fatal")
249
+ settle(() => reject(new ChordError("unavailable", `child failed: ${message.message}`, { reason: message.reason })));
250
+ else if (message.type === "status") {
251
+ report = {
252
+ activeCalls: message.activeCalls ?? 0,
253
+ viewers: message.viewers ?? 0,
254
+ durableTasks: message.durableTasks ?? 0,
255
+ };
256
+ // The idle clock starts at the busy → idle transition, not at the last busy report.
257
+ if (report.activeCalls + report.viewers + report.durableTasks > 0)
258
+ idleSince = undefined;
259
+ else
260
+ idleSince ??= Date.now();
261
+ }
262
+ });
263
+ }).catch(async (error) => {
264
+ current.killTree();
265
+ await current.exited;
266
+ throw error;
267
+ });
268
+ booting = false;
269
+ if (report.activeCalls + report.viewers + report.durableTasks === 0)
270
+ idleSince ??= Date.now();
271
+ status = "running";
272
+ if (options.keepAlive !== undefined) {
273
+ const keepAlive = options.keepAlive;
274
+ timer = setInterval(() => {
275
+ if (status === "running" && !keepAlive(liveness()))
276
+ void serialized(doStop);
277
+ }, options.checkInterval ?? 1000);
278
+ timer.unref?.();
279
+ }
280
+ return current;
281
+ };
282
+ return {
283
+ get status() {
284
+ return status;
285
+ },
286
+ get instance() {
287
+ return instance;
288
+ },
289
+ get liveness() {
290
+ return liveness();
291
+ },
292
+ start: () => serialized(doStart),
293
+ stop: () => serialized(doStop),
294
+ replace: () => serialized(async () => {
295
+ await doStop();
296
+ return doStart();
297
+ }),
298
+ };
299
+ }
300
+ /** The child side of the control channel (call in the child's entry). */
301
+ export function childControl(channel = process) {
302
+ const send = (message) => {
303
+ // A parent that is gone fails the write (EPIPE); the `disconnect` that follows is how a child notices.
304
+ if (channel.connected)
305
+ channel.send?.({ chord2control: message }, undefined, undefined, ignoreSendError);
306
+ };
307
+ let resolveInit = () => { };
308
+ const init = new Promise((resolve) => {
309
+ resolveInit = resolve;
310
+ });
311
+ const shutdown = new Set();
312
+ channel.on("message", (message) => {
313
+ const control = message?.chord2control;
314
+ if (control?.type === "init")
315
+ resolveInit(control.value);
316
+ if (control?.type === "shutdown")
317
+ for (const handler of shutdown)
318
+ void handler();
319
+ });
320
+ const fatal = (error) => send({
321
+ type: "fatal",
322
+ message: error instanceof Error ? error.message : String(error),
323
+ ...(error instanceof ChordError && error.reason !== undefined ? { reason: error.reason } : {}),
324
+ });
325
+ return {
326
+ init,
327
+ lock: async () => {
328
+ const name = process.env[LOCK_ENV];
329
+ if (name === undefined)
330
+ return;
331
+ try {
332
+ await processLock(name);
333
+ }
334
+ catch (error) {
335
+ fatal(error);
336
+ throw error;
337
+ }
338
+ },
339
+ ready: () => send({ type: "ready" }),
340
+ fatal,
341
+ report: (status) => send({ type: "status", ...status }),
342
+ onShutdown: (handler) => shutdown.add(handler),
343
+ };
344
+ }
345
+ //# sourceMappingURL=manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manager.js","sourceRoot":"","sources":["../src/manager.ts"],"names":[],"mappings":"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","sourcesContent":["// Host manager (Node only): runs a child host process and keeps at most one instance of it alive.\nimport { type ChildProcess, fork } from \"node:child_process\";\nimport { createHash } from \"node:crypto\";\nimport { unlinkSync } from \"node:fs\";\nimport { lstat, mkdir, rm } from \"node:fs/promises\";\nimport { connect, createServer } from \"node:net\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { ChordError } from \"./errors.ts\";\nimport { type IpcChannel, type IpcLink, ipcLink } from \"./link.ts\";\n\n/** Control messages share the IPC channel with chord frames: `{ chord2control: message }`. */\nexport type ControlMessage =\n\t| { readonly type: \"init\"; readonly value: unknown }\n\t| { readonly type: \"ready\" }\n\t| { readonly type: \"fatal\"; readonly message: string; readonly reason?: string }\n\t| { readonly type: \"shutdown\" }\n\t| {\n\t\t\treadonly type: \"status\";\n\t\t\treadonly activeCalls?: number;\n\t\t\treadonly viewers?: number;\n\t\t\treadonly durableTasks?: number;\n\t };\n\nexport interface Liveness {\n\t/** Started but not ready yet. */\n\treadonly booting: boolean;\n\treadonly activeCalls: number;\n\t/** Viewers the child reports (it counts heartbeating subscribers). */\n\treadonly viewers: number;\n\treadonly durableTasks: number;\n\t/** Milliseconds since the child last reported work (calls, viewers or tasks), or since it became ready. */\n\treadonly idleFor: number;\n}\n\nexport interface Exit {\n\treadonly code: number | null;\n\treadonly signal: string | null;\n}\n\n/** A running child: its link (for `host.accept`) and its exit. */\nexport interface Instance {\n\treadonly pid: number;\n\treadonly link: IpcLink;\n\treadonly exited: Promise<Exit>;\n\tsend(message: ControlMessage): void;\n\t/** Kills the child and everything it spawned. */\n\tkillTree(): void;\n\tonControl(listener: (message: ControlMessage) => void): void;\n}\n\nexport interface Driver {\n\tspawn(): Instance;\n}\n\nexport interface ForkDriverOptions {\n\t/** The child's entry module. */\n\treadonly entry: string;\n\treadonly args?: readonly string[];\n\treadonly env?: Readonly<Record<string, string>>;\n\t/** Node flags for the child, e.g. `[\"--import\", sourceResolver]` (default: none). */\n\treadonly execArgv?: readonly string[];\n\t/** Sent to the child as its first control message (`childControl().init`). */\n\treadonly init?: unknown;\n\t/**\n\t * A lock name: one live process per name, across managers and processes. The child acquires it as a kernel lock\n\t * (`childControl().lock()`, before opening its storage); a second child fails to start with `unavailable/locked`.\n\t */\n\treadonly lock?: string;\n\t/** Optional stdout/stderr tap. Streams are still mirrored to the parent's standard output. */\n\treadonly onOutput?: (stream: \"stdout\" | \"stderr\", chunk: Uint8Array) => void;\n\t/** Optional application metadata tap; control messages and chord frames keep their normal handling. */\n\treadonly onMessage?: (message: unknown) => void;\n}\n\n/**\n * A process lock owned by the kernel for the holder's lifetime: an abstract socket (Linux, Android) or a named pipe\n * (Windows) vanishes with its process, so there is no stale state to take over and no race between two would-be\n * owners. Other platforms need a socket file, removed on exit; a leftover one nobody accepts on is taken over.\n * The child acquires it (before opening storage), so the lock follows the process that owns the data.\n */\nexport async function processLock(name: string): Promise<() => Promise<void>> {\n\tconst key = createHash(\"sha256\").update(name).digest(\"hex\").slice(0, 32);\n\tconst file = process.platform !== \"win32\" && process.platform !== \"linux\" && process.platform !== \"android\";\n\tconst address =\n\t\tprocess.platform === \"win32\"\n\t\t\t? `\\\\\\\\.\\\\pipe\\\\chord2-${key}`\n\t\t\t: file\n\t\t\t\t? await lockSocketPath(`chord2-${key}.sock`)\n\t\t\t\t: `\\0chord2-${key}`;\n\tconst server = createServer((socket) => socket.end());\n\tfor (;;) {\n\t\ttry {\n\t\t\tawait new Promise<void>((resolve, reject) => {\n\t\t\t\tserver.once(\"error\", reject);\n\t\t\t\tserver.listen(address, () => {\n\t\t\t\t\tserver.removeListener(\"error\", reject);\n\t\t\t\t\tresolve();\n\t\t\t\t});\n\t\t\t});\n\t\t\tbreak;\n\t\t} catch (error) {\n\t\t\tif ((error as NodeJS.ErrnoException).code !== \"EADDRINUSE\") throw error;\n\t\t\tif (!file || (await accepting(address))) {\n\t\t\t\tthrow new ChordError(\"unavailable\", `lock ${name} is held by another process`, { reason: \"locked\" });\n\t\t\t}\n\t\t\tawait rm(address, { force: true });\n\t\t}\n\t}\n\tconst removeFile = (): void => {\n\t\ttry {\n\t\t\tunlinkSync(address);\n\t\t} catch {\n\t\t\t// Already gone.\n\t\t}\n\t};\n\tif (file) process.once(\"exit\", removeFile);\n\treturn () =>\n\t\tnew Promise<void>((resolve, reject) => {\n\t\t\tif (file) process.removeListener(\"exit\", removeFile);\n\t\t\tserver.close((error) => (error ? reject(error) : resolve()));\n\t\t});\n}\n\n/** sun_path references 104 bytes on macOS and the BSDs, including the terminating NUL. */\nconst MAX_SOCKET_PATH_BYTES = 103;\n\n/**\n * The lock socket's path: in the temporary directory, or, when that path does not fit in sun_path (a deep TMPDIR,\n * such as a test runner's below macOS's per-user one), in a private per-user directory under /tmp. Other users must\n * not be able to create or remove sockets there, so the directory has to be ours and closed to everyone else.\n */\nasync function lockSocketPath(file: string): Promise<string> {\n\tconst preferred = join(tmpdir(), file);\n\tif (Buffer.byteLength(preferred) <= MAX_SOCKET_PATH_BYTES) return preferred;\n\tconst uid = process.getuid?.() ?? 0;\n\tconst directory = `/tmp/chord2-${uid}`;\n\tawait mkdir(directory, { mode: 0o700, recursive: true });\n\tconst stats = await lstat(directory);\n\tif (!stats.isDirectory() || stats.uid !== uid || (stats.mode & 0o077) !== 0) {\n\t\tthrow new ChordError(\"unavailable\", `lock directory ${directory} must be a directory only its owner can access`);\n\t}\n\treturn join(directory, file);\n}\n\nfunction accepting(address: string): Promise<boolean> {\n\treturn new Promise((resolve) => {\n\t\tconst socket = connect(address);\n\t\tsocket.once(\"connect\", () => {\n\t\t\tsocket.destroy();\n\t\t\tresolve(true);\n\t\t});\n\t\tsocket.once(\"error\", (error: NodeJS.ErrnoException) =>\n\t\t\tresolve(error.code !== \"ECONNREFUSED\" && error.code !== \"ENOENT\"),\n\t\t);\n\t});\n}\n\nconst LOCK_ENV = \"CHORD2_LOCK\";\n\n/** A control message to a peer process that is gone: dropped (its exit or `disconnect` is reported separately). */\nconst ignoreSendError = (): void => {};\n\nexport function forkDriver(options: ForkDriverOptions): Driver {\n\treturn {\n\t\tspawn() {\n\t\t\t// A lock this process inherited (e.g. as a child host itself) is not the child's: it gets only its own.\n\t\t\tconst env: NodeJS.ProcessEnv = { ...process.env };\n\t\t\tdelete env[LOCK_ENV];\n\t\t\tObject.assign(env, options.env);\n\t\t\tif (options.lock !== undefined) env[LOCK_ENV] = options.lock;\n\t\t\t// Detached: the child leads a process group, so the whole tree can be killed.\n\t\t\tconst child: ChildProcess = fork(options.entry, [...(options.args ?? [])], {\n\t\t\t\tenv,\n\t\t\t\texecArgv: [...(options.execArgv ?? [])],\n\t\t\t\tdetached: true,\n\t\t\t\tstdio: [\"ignore\", options.onOutput ? \"pipe\" : \"inherit\", options.onOutput ? \"pipe\" : \"inherit\", \"ipc\"],\n\t\t\t});\n\t\t\tif (options.onOutput) {\n\t\t\t\tfor (const stream of [\"stdout\", \"stderr\"] as const) {\n\t\t\t\t\tchild[stream]?.on(\"data\", (chunk: Buffer) => {\n\t\t\t\t\t\toptions.onOutput!(stream, chunk);\n\t\t\t\t\t\tprocess[stream].write(chunk);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst pid = child.pid ?? -1;\n\t\t\tconst killGroup = (): void => {\n\t\t\t\ttry {\n\t\t\t\t\tprocess.kill(-pid, \"SIGKILL\");\n\t\t\t\t} catch {\n\t\t\t\t\t// No group left.\n\t\t\t\t}\n\t\t\t};\n\t\t\tconst exited = new Promise<Exit>((resolve) => {\n\t\t\t\tchild.once(\"exit\", (code, signal) => {\n\t\t\t\t\t// However the leader ended (graceful, crash, kill), nothing it spawned outlives it.\n\t\t\t\t\tkillGroup();\n\t\t\t\t\tresolve({ code, signal });\n\t\t\t\t});\n\t\t\t});\n\t\t\tconst listeners = new Set<(message: ControlMessage) => void>();\n\t\t\tchild.on(\"message\", (message) => {\n\t\t\t\toptions.onMessage?.(message);\n\t\t\t\tconst control = (message as { chord2control?: ControlMessage } | null)?.chord2control;\n\t\t\t\tif (control !== undefined) for (const listener of listeners) listener(control);\n\t\t\t});\n\t\t\tconst send = (message: ControlMessage): void => {\n\t\t\t\t// A child that exited before the channel reported it fails the write (EPIPE): its exit is what counts.\n\t\t\t\tif (child.connected) child.send({ chord2control: message }, ignoreSendError);\n\t\t\t};\n\t\t\tif (options.init !== undefined) send({ type: \"init\", value: options.init });\n\t\t\treturn {\n\t\t\t\tpid,\n\t\t\t\tlink: ipcLink(child as unknown as IpcChannel),\n\t\t\t\texited,\n\t\t\t\tsend,\n\t\t\t\tkillTree: () => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tprocess.kill(-pid, \"SIGKILL\");\n\t\t\t\t\t} catch {\n\t\t\t\t\t\tchild.kill(\"SIGKILL\");\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tonControl: (listener) => listeners.add(listener),\n\t\t\t};\n\t\t},\n\t};\n}\n\nexport interface HostManagerOptions {\n\treadonly driver: Driver;\n\t/** Evaluated every `checkInterval` while running; `false` stops the child. */\n\treadonly keepAlive?: (liveness: Liveness) => boolean;\n\treadonly checkInterval?: number;\n\t/** Milliseconds a child may take to shut down before its process tree is killed (default 5000). */\n\treadonly grace?: number;\n\t/** Milliseconds to wait for `ready` (default 30000). */\n\treadonly readyTimeout?: number;\n\t/** The child exited on its own (crash, fatal) or after a stop. */\n\treadonly onExit?: (exit: Exit) => void;\n}\n\nexport interface HostManager {\n\treadonly status: \"stopped\" | \"starting\" | \"running\" | \"stopping\";\n\treadonly instance: Instance | undefined;\n\treadonly liveness: Liveness;\n\t/** Starts the child (or returns the running one) once it reported ready. Serialized with stop/replace. */\n\tstart(): Promise<Instance>;\n\t/** Asks the child to shut down, then kills its process tree after the grace period. */\n\tstop(): Promise<void>;\n\t/** Stop, wait for the exit, start. */\n\treplace(): Promise<Instance>;\n}\n\nexport function createHostManager(options: HostManagerOptions): HostManager {\n\tlet status: HostManager[\"status\"] = \"stopped\";\n\tlet instance: Instance | undefined;\n\tlet queue: Promise<unknown> = Promise.resolve();\n\tlet report = { activeCalls: 0, viewers: 0, durableTasks: 0 };\n\t/** When the child last became idle; undefined while it reports work. */\n\tlet idleSince: number | undefined;\n\tlet booting = false;\n\tlet timer: ReturnType<typeof setInterval> | undefined;\n\n\tconst serialized = <T>(step: () => Promise<T>): Promise<T> => {\n\t\tconst next = queue.then(step, step);\n\t\tqueue = next.catch(() => {});\n\t\treturn next;\n\t};\n\n\tconst liveness = (): Liveness => ({\n\t\tbooting,\n\t\t...report,\n\t\tidleFor: idleSince === undefined ? 0 : Date.now() - idleSince,\n\t});\n\n\tconst doStop = async (): Promise<void> => {\n\t\tconst current = instance;\n\t\tif (current === undefined) {\n\t\t\tstatus = \"stopped\";\n\t\t\tbooting = false;\n\t\t\treturn;\n\t\t}\n\t\tstatus = \"stopping\";\n\t\tif (timer !== undefined) clearInterval(timer);\n\t\tcurrent.send({ type: \"shutdown\" });\n\t\tlet graceTimer: ReturnType<typeof setTimeout> | undefined;\n\t\tconst graceful = await Promise.race([\n\t\t\tcurrent.exited.then(() => true),\n\t\t\tnew Promise<boolean>((resolve) => {\n\t\t\t\tgraceTimer = setTimeout(() => resolve(false), options.grace ?? 5000);\n\t\t\t}),\n\t\t]);\n\t\tclearTimeout(graceTimer);\n\t\tif (!graceful) current.killTree();\n\t\tawait current.exited;\n\t\tif (instance === current) instance = undefined;\n\t\tstatus = \"stopped\";\n\t};\n\n\tconst doStart = async (): Promise<Instance> => {\n\t\tif (instance !== undefined && status === \"running\") return instance;\n\t\tstatus = \"starting\";\n\t\tbooting = true;\n\t\treport = { activeCalls: 0, viewers: 0, durableTasks: 0 };\n\t\tlet current: Instance;\n\t\ttry {\n\t\t\tcurrent = options.driver.spawn();\n\t\t} catch (error) {\n\t\t\tstatus = \"stopped\";\n\t\t\tbooting = false;\n\t\t\tthrow error;\n\t\t}\n\t\tinstance = current;\n\t\tcurrent.exited.then((exit) => {\n\t\t\tif (instance === current) {\n\t\t\t\tinstance = undefined;\n\t\t\t\tstatus = \"stopped\";\n\t\t\t\tif (timer !== undefined) clearInterval(timer);\n\t\t\t}\n\t\t\toptions.onExit?.(exit);\n\t\t});\n\t\tawait new Promise<void>((resolve, reject) => {\n\t\t\tconst timeout = setTimeout(\n\t\t\t\t() => reject(new ChordError(\"unavailable\", \"child not ready in time\")),\n\t\t\t\toptions.readyTimeout ?? 30_000,\n\t\t\t);\n\t\t\tconst settle = (fn: () => void): void => {\n\t\t\t\tclearTimeout(timeout);\n\t\t\t\tfn();\n\t\t\t};\n\t\t\tcurrent.exited.then((exit) =>\n\t\t\t\tsettle(() =>\n\t\t\t\t\treject(new ChordError(\"unavailable\", `child exited before ready (${exit.code ?? exit.signal})`)),\n\t\t\t\t),\n\t\t\t);\n\t\t\tcurrent.onControl((message) => {\n\t\t\t\tif (message.type === \"ready\") settle(resolve);\n\t\t\t\telse if (message.type === \"fatal\")\n\t\t\t\t\tsettle(() =>\n\t\t\t\t\t\treject(new ChordError(\"unavailable\", `child failed: ${message.message}`, { reason: message.reason })),\n\t\t\t\t\t);\n\t\t\t\telse if (message.type === \"status\") {\n\t\t\t\t\treport = {\n\t\t\t\t\t\tactiveCalls: message.activeCalls ?? 0,\n\t\t\t\t\t\tviewers: message.viewers ?? 0,\n\t\t\t\t\t\tdurableTasks: message.durableTasks ?? 0,\n\t\t\t\t\t};\n\t\t\t\t\t// The idle clock starts at the busy → idle transition, not at the last busy report.\n\t\t\t\t\tif (report.activeCalls + report.viewers + report.durableTasks > 0) idleSince = undefined;\n\t\t\t\t\telse idleSince ??= Date.now();\n\t\t\t\t}\n\t\t\t});\n\t\t}).catch(async (error: unknown) => {\n\t\t\tcurrent.killTree();\n\t\t\tawait current.exited;\n\t\t\tthrow error;\n\t\t});\n\t\tbooting = false;\n\t\tif (report.activeCalls + report.viewers + report.durableTasks === 0) idleSince ??= Date.now();\n\t\tstatus = \"running\";\n\t\tif (options.keepAlive !== undefined) {\n\t\t\tconst keepAlive = options.keepAlive;\n\t\t\ttimer = setInterval(() => {\n\t\t\t\tif (status === \"running\" && !keepAlive(liveness())) void serialized(doStop);\n\t\t\t}, options.checkInterval ?? 1000);\n\t\t\ttimer.unref?.();\n\t\t}\n\t\treturn current;\n\t};\n\n\treturn {\n\t\tget status() {\n\t\t\treturn status;\n\t\t},\n\t\tget instance() {\n\t\t\treturn instance;\n\t\t},\n\t\tget liveness() {\n\t\t\treturn liveness();\n\t\t},\n\t\tstart: () => serialized(doStart),\n\t\tstop: () => serialized(doStop),\n\t\treplace: () =>\n\t\t\tserialized(async () => {\n\t\t\t\tawait doStop();\n\t\t\t\treturn doStart();\n\t\t\t}),\n\t};\n}\n\n/** The child side of the control channel (call in the child's entry). */\nexport function childControl(channel: NodeJS.Process = process): {\n\treadonly init: Promise<unknown>;\n\t/**\n\t * Acquires the manager's lock (if one was configured) as a kernel lock held for this process's lifetime. Call it\n\t * before opening storage. Fails with `unavailable/locked`, also reported to the manager as a fatal start error.\n\t */\n\tlock(): Promise<void>;\n\tready(): void;\n\tfatal(error: unknown): void;\n\treport(status: { activeCalls?: number; viewers?: number; durableTasks?: number }): void;\n\tonShutdown(handler: () => void | Promise<void>): void;\n} {\n\tconst send = (message: ControlMessage): void => {\n\t\t// A parent that is gone fails the write (EPIPE); the `disconnect` that follows is how a child notices.\n\t\tif (channel.connected) channel.send?.({ chord2control: message }, undefined, undefined, ignoreSendError);\n\t};\n\tlet resolveInit: (value: unknown) => void = () => {};\n\tconst init = new Promise<unknown>((resolve) => {\n\t\tresolveInit = resolve;\n\t});\n\tconst shutdown = new Set<() => void | Promise<void>>();\n\tchannel.on(\"message\", (message: unknown) => {\n\t\tconst control = (message as { chord2control?: ControlMessage } | null)?.chord2control;\n\t\tif (control?.type === \"init\") resolveInit(control.value);\n\t\tif (control?.type === \"shutdown\") for (const handler of shutdown) void handler();\n\t});\n\tconst fatal = (error: unknown): void =>\n\t\tsend({\n\t\t\ttype: \"fatal\",\n\t\t\tmessage: error instanceof Error ? error.message : String(error),\n\t\t\t...(error instanceof ChordError && error.reason !== undefined ? { reason: error.reason } : {}),\n\t\t});\n\treturn {\n\t\tinit,\n\t\tlock: async () => {\n\t\t\tconst name = process.env[LOCK_ENV];\n\t\t\tif (name === undefined) return;\n\t\t\ttry {\n\t\t\t\tawait processLock(name);\n\t\t\t} catch (error) {\n\t\t\t\tfatal(error);\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t},\n\t\tready: () => send({ type: \"ready\" }),\n\t\tfatal,\n\t\treport: (status) => send({ type: \"status\", ...status }),\n\t\tonShutdown: (handler) => shutdown.add(handler),\n\t};\n}\n"]}
package/dist/node.d.ts CHANGED
@@ -1,5 +1,4 @@
1
- export type { FacetBundleArtifactLoaderOptions, FacetBundleExternalResolver, FacetBundleLoaderOptions, } from "./node/bundle-loader.ts";
2
- export { createFacetBundleArtifactLoader, createFacetBundleLoader, readFacetBundleArtifact, readFacetBundleManifest, } from "./node/bundle-loader.ts";
3
- export type { FacetBundleArtifact, FacetBundleEntry, FacetBundleManifest, FacetBundlePlugin, } from "./node/manifest.ts";
4
- export { FACET_BUNDLE_ARTIFACT_FORMAT, FACET_BUNDLE_ARTIFACT_FORMAT_VERSION, FACET_BUNDLE_FORMAT, FACET_BUNDLE_FORMAT_VERSION, FACET_BUNDLE_MANIFEST_FILE, } from "./node/manifest.ts";
1
+ /** Node-only parts of Chord: child host processes, their manager, and the facet module loader. */
2
+ export { nodeLoader } from "./loader.ts";
3
+ export { type ControlMessage, childControl, createHostManager, type Driver, type Exit, type ForkDriverOptions, forkDriver, type HostManager, type HostManagerOptions, type Instance, type Liveness, processLock, } from "./manager.ts";
5
4
  //# sourceMappingURL=node.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":"AAAA,YAAY,EACX,gCAAgC,EAChC,2BAA2B,EAC3B,wBAAwB,GACxB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACN,+BAA+B,EAC/B,uBAAuB,EACvB,uBAAuB,EACvB,uBAAuB,GACvB,MAAM,yBAAyB,CAAC;AACjC,YAAY,EACX,mBAAmB,EACnB,gBAAgB,EAChB,mBAAmB,EACnB,iBAAiB,GACjB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACN,4BAA4B,EAC5B,oCAAoC,EACpC,mBAAmB,EACnB,2BAA2B,EAC3B,0BAA0B,GAC1B,MAAM,oBAAoB,CAAC"}
1
+ {"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":"AAAA,kGAAkG;AAClG,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EACN,KAAK,cAAc,EACnB,YAAY,EACZ,iBAAiB,EACjB,KAAK,MAAM,EACX,KAAK,IAAI,EACT,KAAK,iBAAiB,EACtB,UAAU,EACV,KAAK,WAAW,EAChB,KAAK,kBAAkB,EACvB,KAAK,QAAQ,EACb,KAAK,QAAQ,EACb,WAAW,GACX,MAAM,cAAc,CAAC"}
package/dist/node.js CHANGED
@@ -1,3 +1,4 @@
1
- export { createFacetBundleArtifactLoader, createFacetBundleLoader, readFacetBundleArtifact, readFacetBundleManifest, } from "./node/bundle-loader.js";
2
- export { FACET_BUNDLE_ARTIFACT_FORMAT, FACET_BUNDLE_ARTIFACT_FORMAT_VERSION, FACET_BUNDLE_FORMAT, FACET_BUNDLE_FORMAT_VERSION, FACET_BUNDLE_MANIFEST_FILE, } from "./node/manifest.js";
1
+ /** Node-only parts of Chord: child host processes, their manager, and the facet module loader. */
2
+ export { nodeLoader } from "./loader.js";
3
+ export { childControl, createHostManager, forkDriver, processLock, } from "./manager.js";
3
4
  //# sourceMappingURL=node.js.map
package/dist/node.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"node.js","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":"AAKA,OAAO,EACN,+BAA+B,EAC/B,uBAAuB,EACvB,uBAAuB,EACvB,uBAAuB,GACvB,MAAM,yBAAyB,CAAC;AAOjC,OAAO,EACN,4BAA4B,EAC5B,oCAAoC,EACpC,mBAAmB,EACnB,2BAA2B,EAC3B,0BAA0B,GAC1B,MAAM,oBAAoB,CAAC","sourcesContent":["export type {\n\tFacetBundleArtifactLoaderOptions,\n\tFacetBundleExternalResolver,\n\tFacetBundleLoaderOptions,\n} from \"./node/bundle-loader.ts\";\nexport {\n\tcreateFacetBundleArtifactLoader,\n\tcreateFacetBundleLoader,\n\treadFacetBundleArtifact,\n\treadFacetBundleManifest,\n} from \"./node/bundle-loader.ts\";\nexport type {\n\tFacetBundleArtifact,\n\tFacetBundleEntry,\n\tFacetBundleManifest,\n\tFacetBundlePlugin,\n} from \"./node/manifest.ts\";\nexport {\n\tFACET_BUNDLE_ARTIFACT_FORMAT,\n\tFACET_BUNDLE_ARTIFACT_FORMAT_VERSION,\n\tFACET_BUNDLE_FORMAT,\n\tFACET_BUNDLE_FORMAT_VERSION,\n\tFACET_BUNDLE_MANIFEST_FILE,\n} from \"./node/manifest.ts\";\n"]}
1
+ {"version":3,"file":"node.js","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":"AAAA,kGAAkG;AAClG,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAEN,YAAY,EACZ,iBAAiB,EAIjB,UAAU,EAKV,WAAW,GACX,MAAM,cAAc,CAAC","sourcesContent":["/** Node-only parts of Chord: child host processes, their manager, and the facet module loader. */\nexport { nodeLoader } from \"./loader.ts\";\nexport {\n\ttype ControlMessage,\n\tchildControl,\n\tcreateHostManager,\n\ttype Driver,\n\ttype Exit,\n\ttype ForkDriverOptions,\n\tforkDriver,\n\ttype HostManager,\n\ttype HostManagerOptions,\n\ttype Instance,\n\ttype Liveness,\n\tprocessLock,\n} from \"./manager.ts\";\n"]}