posipaki 0.40.0 → 0.41.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{client-PWS8gJ0-.d.ts → client-GrwWOUBV.d.ts} +25 -2
- package/dist/client-GrwWOUBV.d.ts.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/{json1-B-oUZzI_.js → json1-BWi4HzI4.js} +114 -10
- package/dist/json1-BWi4HzI4.js.map +1 -0
- package/dist/remote/gateway-cli.js +11 -2
- package/dist/remote/gateway-cli.js.map +1 -1
- package/dist/remote/index.d.ts +7 -2
- package/dist/remote/index.d.ts.map +1 -1
- package/dist/remote/index.js +2 -2
- package/dist/remote/node.d.ts +4 -1
- package/dist/remote/node.d.ts.map +1 -1
- package/dist/remote/node.js +7 -6
- package/dist/remote/node.js.map +1 -1
- package/dist/{version-D4C9wBG0.js → version-CYQgj_GV.js} +2 -2
- package/dist/{version-D4C9wBG0.js.map → version-CYQgj_GV.js.map} +1 -1
- package/package.json +1 -1
- package/dist/client-PWS8gJ0-.d.ts.map +0 -1
- package/dist/json1-B-oUZzI_.js.map +0 -1
|
@@ -38,6 +38,29 @@ declare function isExit(msg: Record<string, unknown>): msg is {
|
|
|
38
38
|
state: unknown;
|
|
39
39
|
};
|
|
40
40
|
};
|
|
41
|
+
/** How much of an unreadable line is carried: enough to see what it was, never enough to be it.
|
|
42
|
+
* A line that failed to parse is the one line nobody vouched for, so quoting it whole would move
|
|
43
|
+
* whatever it holds — a credential in a paste accident is how that happens — into every log,
|
|
44
|
+
* transcript and context window that later reads the frame. Why, how long, and a short head of
|
|
45
|
+
* it. (`reason` carries a little of the line on its own: a JSON parser says where it gave up and
|
|
46
|
+
* quotes what it was looking at. That is the parser's business, not a promise this file makes.) */
|
|
47
|
+
declare const BAD_PREFIX_LIMIT = 32;
|
|
48
|
+
declare function isBad(msg: Record<string, unknown>): msg is {
|
|
49
|
+
$bad: {
|
|
50
|
+
reason: string;
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
/** The frame that says a frame could not be read: why, how long it was, and the head of it. */
|
|
54
|
+
declare function badFrame(reason: string, raw: string): Record<string, unknown>;
|
|
55
|
+
/** Why a frame could not be read, or null when it is not a frame that says so. */
|
|
56
|
+
declare function badReason(msg: Record<string, unknown>): string | null;
|
|
57
|
+
declare function isError(msg: Record<string, unknown>): msg is {
|
|
58
|
+
$error: string;
|
|
59
|
+
};
|
|
60
|
+
/** The frame that says the wire is over: the reason, and the connection ends with it. */
|
|
61
|
+
declare function errorFrame(reason: string): Record<string, unknown>;
|
|
62
|
+
/** The reason a wire error carries, or null when it is not one. */
|
|
63
|
+
declare function errorReason(msg: Record<string, unknown>): string | null;
|
|
41
64
|
type StreamKind = "message" | "state" | "exit";
|
|
42
65
|
declare function isStop(msg: Record<string, unknown>): msg is {
|
|
43
66
|
$stop: Record<string, unknown>;
|
|
@@ -66,5 +89,5 @@ type ClientSpawner<Args> = (args: Args) => Promise<Channel>;
|
|
|
66
89
|
declare const CHANNEL_LOST = "channel-lost";
|
|
67
90
|
declare function remoteClient<Args, State, InMsg extends Message, OutMsg extends Message, Methods extends MethodOptions = MethodOptions, Handlers extends HandlerOptions<InMsg> = HandlerOptions<InMsg>, R extends ReflectionOptions = ReflectionOptions>(name: string, spawner: ClientSpawner<Args>): ActorDefinition<Args, State, InMsg, OutMsg, R>;
|
|
68
91
|
//#endregion
|
|
69
|
-
export {
|
|
70
|
-
//# sourceMappingURL=client-
|
|
92
|
+
export { isStop as S, isPause as _, Channel as a, isResume as b, badFrame as c, errorReason as d, isBad as f, isMsg as g, isInit as h, BAD_PREFIX_LIMIT as i, badReason as l, isExit as m, ClientSpawner as n, StreamKind as o, isError as p, remoteClient as r, StringTransport as s, CHANNEL_LOST as t, errorFrame as u, isProto as v, isState as x, isRelease as y };
|
|
93
|
+
//# sourceMappingURL=client-GrwWOUBV.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client-GrwWOUBV.d.ts","names":[],"sources":["../src/remote/channel.ts","../src/remote/client.ts"],"mappings":";;;UAgBiB;EACf,KAAK,uBAAuB;EAC5B,UAAU,UAAU;EACpB;;EAEA,QAAQ;EACR,SAAS;;UAGM;EACf,KAAK,OAAO,iCAAiC;EAC7C,UAAU,UAAU,OAAO;EAC3B;;EAEA,QAAQ;EACR,SAAS;;iBA6CK,QAAQ,KAAK,0BAA0B;EAAS;;iBAGhD,OAAO,KAAK,0BAA0B;EAAS,OAAO;;iBAGtD,QAAQ,KAAK,0BAA0B;EAAS,QAAQ;;iBAGxD,MACd,KAAK,0BACJ;EAAS;IAAQ;IAAkB,MAAM;;;iBAG5B,OACd,KAAK,0BACJ;EAAS;IAAS;IAAc;;;;;;;;;cAkCtB;iBAEG,MAAM,KAAK,0BAA0B;EAAS;IAAQ;;;;iBAKtD,SAAS,gBAAgB,cAAc;;iBAMvC,UAAU,KAAK;iBASf,QAAQ,KAAK,0BAA0B;EAAS;;;iBAKhD,WAAW,iBAAiB;;iBAK5B,YAAY,KAAK;KAcrB;iBA+BI,OAAO,KAAK,0BAA0B;EAAS,OAAO;;iBAGtD,QAAQ,KAAK,0BAA0B;EAAS,QAAQ;;iBAGxD,SAAS,KAAK,0BAA0B;EAAS,SAAS;;iBAG1D,UAAU,KAAK,0BAA0B;EAAS,UAAU;;;;KCxKhE,cAAc,SAAS,MAAM,SAAS,QAAQ;;;;;;;;;;cAY7C;iBAEG,aACd,MACA,OACA,cAAc,SACd,eAAe,SACf,gBAAgB,gBAAgB,eAChC,iBAAiB,eAAe,SAAS,eAAe,QACxD,UAAU,oBAAoB,mBAE9B,cACA,SAAS,cAAc,QACtB,gBAAgB,MAAM,OAAO,OAAO,QAAQ"}
|
package/dist/index.d.ts
CHANGED
|
@@ -20,7 +20,7 @@ declare function defineActor<Args, InternalState, InMsg extends Message, OutMsg
|
|
|
20
20
|
//#endregion
|
|
21
21
|
//#region src/version.d.ts
|
|
22
22
|
/** posipaki's release version. Must equal package.json's `version`. */
|
|
23
|
-
declare const LIB_VERSION = "0.
|
|
23
|
+
declare const LIB_VERSION = "0.41.0";
|
|
24
24
|
//#endregion
|
|
25
25
|
export { type ActorConfig, type ActorContext, type ActorDecorated, type ActorDefinition, type ActorPlugin, type ActorReflection, type AnyProcess, AsyncProcess, type AsyncProcessFn, type ExitMessage, type HandlerFn, type HandlerOptions, type HookResult, LIB_VERSION, type Message, type MethodOptions, type PluginTransform, Process, type ProcessCtx, type ProcessFn, type SenderInfo, type SenderOrigin, type SpawnedFrom, type StopMessage, type WithSender, type WithoutSender, asyncify, callHook, chainHook, defineActor, defineMessages, mergeConfigs, propagateError, runDispatch, runDispatchAsync, spawn, spawnAsync, stopPropagation };
|
|
26
26
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import { i as runDispatch } from "./util-Brtfgv68.js";
|
|
|
2
2
|
import { a as spawnAsync, i as runDispatchAsync, o as asyncify, t as AsyncProcess } from "./process.async-C_-NpMFX.js";
|
|
3
3
|
import { n as chainHook, o as propagateError, r as mergeConfigs, s as stopPropagation, t as callHook } from "./hooks-CgXhmY4r.js";
|
|
4
4
|
import { n as defineMessages, t as defineActor } from "./define-actor-D7c9vn6S.js";
|
|
5
|
-
import { t as LIB_VERSION } from "./version-
|
|
5
|
+
import { t as LIB_VERSION } from "./version-CYQgj_GV.js";
|
|
6
6
|
//#region src/process.ts
|
|
7
7
|
/** @deprecated Use {@link spawnAsync} instead. */
|
|
8
8
|
function spawn(fn, pname, tp) {
|
|
@@ -238,6 +238,46 @@ function isMsg(msg) {
|
|
|
238
238
|
function isExit(msg) {
|
|
239
239
|
return "$exit" in msg;
|
|
240
240
|
}
|
|
241
|
+
const BAD_KEY = "$bad";
|
|
242
|
+
/** How much of an unreadable line is carried: enough to see what it was, never enough to be it.
|
|
243
|
+
* A line that failed to parse is the one line nobody vouched for, so quoting it whole would move
|
|
244
|
+
* whatever it holds — a credential in a paste accident is how that happens — into every log,
|
|
245
|
+
* transcript and context window that later reads the frame. Why, how long, and a short head of
|
|
246
|
+
* it. (`reason` carries a little of the line on its own: a JSON parser says where it gave up and
|
|
247
|
+
* quotes what it was looking at. That is the parser's business, not a promise this file makes.) */
|
|
248
|
+
const BAD_PREFIX_LIMIT = 32;
|
|
249
|
+
function isBad(msg) {
|
|
250
|
+
return BAD_KEY in msg;
|
|
251
|
+
}
|
|
252
|
+
/** The frame that says a frame could not be read: why, how long it was, and the head of it. */
|
|
253
|
+
function badFrame(reason, raw) {
|
|
254
|
+
const prefix = raw.length > 32 ? `${raw.slice(0, 32)}…` : raw;
|
|
255
|
+
return { [BAD_KEY]: {
|
|
256
|
+
reason,
|
|
257
|
+
length: raw.length,
|
|
258
|
+
prefix
|
|
259
|
+
} };
|
|
260
|
+
}
|
|
261
|
+
/** Why a frame could not be read, or null when it is not a frame that says so. */
|
|
262
|
+
function badReason(msg) {
|
|
263
|
+
const body = msg[BAD_KEY];
|
|
264
|
+
if (typeof body !== "object" || body === null) return null;
|
|
265
|
+
const reason = body.reason;
|
|
266
|
+
return typeof reason === "string" ? reason : null;
|
|
267
|
+
}
|
|
268
|
+
const ERROR_KEY = "$error";
|
|
269
|
+
function isError(msg) {
|
|
270
|
+
return ERROR_KEY in msg;
|
|
271
|
+
}
|
|
272
|
+
/** The frame that says the wire is over: the reason, and the connection ends with it. */
|
|
273
|
+
function errorFrame(reason) {
|
|
274
|
+
return { [ERROR_KEY]: reason };
|
|
275
|
+
}
|
|
276
|
+
/** The reason a wire error carries, or null when it is not one. */
|
|
277
|
+
function errorReason(msg) {
|
|
278
|
+
const reason = msg[ERROR_KEY];
|
|
279
|
+
return typeof reason === "string" ? reason : null;
|
|
280
|
+
}
|
|
241
281
|
/** The three, in the one order they are ever named in — the order a tune frame
|
|
242
282
|
* carries them in, so two ways of asking for the same thing look the same. */
|
|
243
283
|
const STREAM_KINDS = [
|
|
@@ -1019,7 +1059,13 @@ async function serveRemoteActor(actor, spawner) {
|
|
|
1019
1059
|
});
|
|
1020
1060
|
});
|
|
1021
1061
|
channel.removeHandler();
|
|
1022
|
-
const
|
|
1062
|
+
const firstFrame = waiting.shift();
|
|
1063
|
+
const initProblem = badReason(firstFrame) ?? errorReason(firstFrame);
|
|
1064
|
+
if (initProblem !== null) {
|
|
1065
|
+
await write(errorFrame(`expected $init: ${initProblem}`)).catch(() => void 0);
|
|
1066
|
+
throw new Error(`serveRemoteActor: expected $init (${initProblem})`);
|
|
1067
|
+
}
|
|
1068
|
+
const initFrame = decodeFrame(firstFrame, handleFor);
|
|
1023
1069
|
if (!isInit(initFrame)) throw new Error("serveRemoteActor: expected $init");
|
|
1024
1070
|
const init = initFrame.$init;
|
|
1025
1071
|
const stated = init.rootName;
|
|
@@ -1040,7 +1086,28 @@ async function serveRemoteActor(actor, spawner) {
|
|
|
1040
1086
|
channel.onClose(() => {
|
|
1041
1087
|
proc.stop();
|
|
1042
1088
|
});
|
|
1089
|
+
/**
|
|
1090
|
+
* A frame that was not a frame is the connection's problem and not the process's: the far side is
|
|
1091
|
+
* told what could not be read, and then this connection ends — the actor it was serving ends with
|
|
1092
|
+
* it, that being what it was spawned for. The host everything else runs in is never the cost of
|
|
1093
|
+
* one peer that is not speaking the protocol.
|
|
1094
|
+
*
|
|
1095
|
+
* The write is awaited only so the reason is out before the wire closes. A wire that has already
|
|
1096
|
+
* gone ends nothing twice, and the ending is the part that matters.
|
|
1097
|
+
*/
|
|
1098
|
+
const endUnreadable = async (reason) => {
|
|
1099
|
+
console.warn(`a frame from the far side could not be read: ${reason}`);
|
|
1100
|
+
try {
|
|
1101
|
+
await write(errorFrame(reason));
|
|
1102
|
+
} catch {}
|
|
1103
|
+
await proc.stop();
|
|
1104
|
+
};
|
|
1043
1105
|
function dispatch(raw) {
|
|
1106
|
+
const wireProblem = badReason(raw) ?? errorReason(raw);
|
|
1107
|
+
if (wireProblem !== null) {
|
|
1108
|
+
endUnreadable(wireProblem);
|
|
1109
|
+
return;
|
|
1110
|
+
}
|
|
1044
1111
|
const frame = decodeFrame(raw, handleFor);
|
|
1045
1112
|
if (calls.settle(frame)) return;
|
|
1046
1113
|
const to = frameTo(frame);
|
|
@@ -1204,7 +1271,30 @@ function remoteClient(name, spawner) {
|
|
|
1204
1271
|
code: null,
|
|
1205
1272
|
state: currentState
|
|
1206
1273
|
}));
|
|
1274
|
+
/**
|
|
1275
|
+
* The wire is over, whoever ended it: the far side stopped talking, or stopped making sense.
|
|
1276
|
+
* What was in flight fails, handles disconnect, nothing more is said about the processes of
|
|
1277
|
+
* this side's own, and the proxy ends with CHANNEL_LOST — a proxy that stayed up would be one
|
|
1278
|
+
* whose parent still believes the far side is listening, which is exactly the belief a display
|
|
1279
|
+
* panel that went dark punishes.
|
|
1280
|
+
*
|
|
1281
|
+
* Said once: a wire can go in more than one way at once, and it only goes once.
|
|
1282
|
+
*/
|
|
1283
|
+
let wireEnded = false;
|
|
1284
|
+
const wireGone = () => {
|
|
1285
|
+
if (wireEnded) return;
|
|
1286
|
+
wireEnded = true;
|
|
1287
|
+
calls.rejectAll();
|
|
1288
|
+
for (const held of table.handles()) if (isRemoteProcess(held)) held.disconnect();
|
|
1289
|
+
streams.stopAll();
|
|
1290
|
+
this.exit(CHANNEL_LOST);
|
|
1291
|
+
};
|
|
1207
1292
|
channel.onMessage((raw) => {
|
|
1293
|
+
if ((badReason(raw) ?? errorReason(raw)) !== null) {
|
|
1294
|
+
channel.close();
|
|
1295
|
+
wireGone();
|
|
1296
|
+
return;
|
|
1297
|
+
}
|
|
1208
1298
|
const frame = decodeFrame(raw, handleFor);
|
|
1209
1299
|
if (calls.settle(frame)) return;
|
|
1210
1300
|
const to = frameTo(frame);
|
|
@@ -1256,12 +1346,7 @@ function remoteClient(name, spawner) {
|
|
|
1256
1346
|
const call = asReflectionCall(frame);
|
|
1257
1347
|
if (call) answerCall(call, mine, write, table);
|
|
1258
1348
|
});
|
|
1259
|
-
channel.onClose(() =>
|
|
1260
|
-
calls.rejectAll();
|
|
1261
|
-
for (const held of table.handles()) if (isRemoteProcess(held)) held.disconnect();
|
|
1262
|
-
streams.stopAll();
|
|
1263
|
-
this.exit(CHANNEL_LOST);
|
|
1264
|
-
});
|
|
1349
|
+
channel.onClose(() => wireGone());
|
|
1265
1350
|
await start;
|
|
1266
1351
|
return {
|
|
1267
1352
|
public: currentState,
|
|
@@ -1296,16 +1381,35 @@ const VERSION = "json.v1";
|
|
|
1296
1381
|
function encode(frame) {
|
|
1297
1382
|
return JSON.stringify(frame);
|
|
1298
1383
|
}
|
|
1384
|
+
/** The frame a line carries, throwing on a line that is not JSON. `readFrame` is how the
|
|
1385
|
+
* seam reads a line; this is the primitive underneath it. */
|
|
1299
1386
|
function decode(str) {
|
|
1300
1387
|
return JSON.parse(str);
|
|
1301
1388
|
}
|
|
1389
|
+
/** A line read as a frame: the frame itself, or the frame that says this one could not be
|
|
1390
|
+
* read. Never throws — see the note at the top of this file. */
|
|
1391
|
+
function readFrame(str) {
|
|
1392
|
+
let parsed;
|
|
1393
|
+
try {
|
|
1394
|
+
parsed = decode(str);
|
|
1395
|
+
} catch (err) {
|
|
1396
|
+
return badFrame(err instanceof Error ? err.message : String(err), str);
|
|
1397
|
+
}
|
|
1398
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return badFrame(`a frame is one JSON object, and this was ${kindOf(parsed)}`, str);
|
|
1399
|
+
return parsed;
|
|
1400
|
+
}
|
|
1401
|
+
function kindOf(value) {
|
|
1402
|
+
if (value === null) return "null";
|
|
1403
|
+
if (Array.isArray(value)) return "an array";
|
|
1404
|
+
return `a ${typeof value}`;
|
|
1405
|
+
}
|
|
1302
1406
|
function json1Channel(transport) {
|
|
1303
1407
|
return {
|
|
1304
1408
|
send(frame) {
|
|
1305
1409
|
return transport.send(encode(frame));
|
|
1306
1410
|
},
|
|
1307
1411
|
onMessage(handler) {
|
|
1308
|
-
transport.onMessage((str) => handler(
|
|
1412
|
+
transport.onMessage((str) => handler(readFrame(str)));
|
|
1309
1413
|
},
|
|
1310
1414
|
removeHandler() {
|
|
1311
1415
|
transport.removeHandler();
|
|
@@ -1319,6 +1423,6 @@ function json1Channel(transport) {
|
|
|
1319
1423
|
};
|
|
1320
1424
|
}
|
|
1321
1425
|
//#endregion
|
|
1322
|
-
export { isState as _,
|
|
1426
|
+
export { isRelease as C, PROCESS_REF as D, isStop as E, isRemoteProcess as O, isProto as S, isState as T, isError as _, readFrame as a, isMsg as b, serveRemoteActor as c, BAD_PREFIX_LIMIT as d, badFrame as f, isBad as g, errorReason as h, json1Channel as i, rootIdFor as k, makeSender as l, errorFrame as m, decode as n, CHANNEL_LOST as o, badReason as p, encode as r, remoteClient as s, VERSION as t, RemoteProcess as u, isExit as v, isResume as w, isPause as x, isInit as y };
|
|
1323
1427
|
|
|
1324
|
-
//# sourceMappingURL=json1-
|
|
1428
|
+
//# sourceMappingURL=json1-BWi4HzI4.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json1-BWi4HzI4.js","names":[],"sources":["../src/remote/process-ref.ts","../src/remote/channel.ts","../src/remote/remote-process.ts","../src/remote/process-streams.ts","../src/remote/sender.ts","../src/remote/call-side.ts","../src/remote/server.ts","../src/remote/client.ts","../src/remote/protocols/json1.ts"],"sourcesContent":["// ── Process references on the wire ─────────────────────────────────────────\n//\n// A process is not JSON: it holds state, children and methods. So a reflection\n// method that returns one cannot answer with the process itself — it answers\n// with a reference, and the caller is handed what it can read: a name, and an id\n// this connection uses for that process.\n//\n// The id belongs to the connection and to the side that holds the process: that\n// side allocates it, and both sides then know the process by it. Allocated once\n// per process — handed over twice, it is the same reference both times — and\n// never reused, so an id whose process is gone resolves to nothing rather than to\n// whatever came after it.\n//\n// The two sides allocate from one space, split by parity: the client takes the\n// odd ids, the server the even ones. Every connection also has a root, and a root is\n// numbered like anything else — the first id of the parity of the side that holds it:\n// 0 on the even side (the server), 1 on the odd one (the client). So an id says on\n// its own which side holds the process it names, the two roots included, and a frame's\n// address means the same thing whoever reads it.\n//\n// A side's own root is the process the connection is, and the far side's root is a\n// handle here like any of theirs. Neither end has to be told which number belongs to\n// whom: each root is the first id of its own parity.\n\nimport { isProcess } from \"../process.async.js\";\nimport type { RemoteProcess } from \"./remote-process.js\";\n\n/** The key that marks a process reference inside an otherwise JSON value. */\nexport const PROCESS_REF = \"$p\";\n\n/**\n * The id a side gives its own root: the first id of its parity. The two ends of a\n * connection therefore number their roots differently, and an id says whose root it is\n * as it says who holds every other process. A side hands out its next id from two\n * steps further on, the one in between belonging to the root of the side it talks to.\n */\nexport function rootIdFor(parity: IdParity): number {\n return parity === \"odd\" ? 1 : 0;\n}\n\n/** What a served root is called when the client states no name for it. A client that\n * states one — and the library's own does, in `$init` — is served under that name instead:\n * the process across the seam is the one its proxy was forked as, and it should be called\n * the same on both sides. This is the name for a connection that says nothing. */\nexport const SERVED_ROOT_NAME = \"remote\";\n\n/** What crosses the wire in place of a process. */\nexport interface ProcessRef {\n id: number;\n pname: string;\n}\n\n/** The little a table needs of what it holds to name it: what it is called, and\n * the symbol that identifies it in this build. */\nexport interface ProcessHandle {\n readonly pname: string;\n readonly id: symbol;\n}\n\n/** Which ids a side hands out: the client takes the odd ones, the server the\n * even ones, so one number can never name a process on both sides at once. */\nexport type IdParity = \"odd\" | \"even\";\n\n/**\n * The processes one connection knows, by the ids that name them. One table per\n * connection, because an id means nothing on any other one, and it lives exactly\n * as long as the connection that owns it.\n *\n * It holds two sets, told apart by parity rather than kept apart by a rule: the\n * processes this side holds — the root, and anything it hands over — and the ones\n * the far side holds, which this side knows as handles. A frame's address is\n * looked up in both, and exactly one can answer.\n */\nexport class ProcessTable<P extends ProcessHandle = ProcessHandle> {\n /** This side's own processes, by the ids it gave them. */\n private pvtMine = new Map<number, P>();\n private pvtMineIds = new Map<P, number>();\n /** The far side's processes, by the ids they came with. */\n private pvtTheirs = new Map<number, P>();\n /** The id of this side's own root: the first of its parity. */\n private pvtRootId: number;\n /** The id the far side gave its root: the first of its parity, and the number this\n * side's own numbering skips. */\n private pvtFarRootId: number;\n /** The next id this side may hand out: its own parity, from two steps past its own\n * root, the one in between belonging to the far side's root. */\n private pvtNext: number;\n /** Told the first time a process is numbered — the moment it is about to\n * cross the connection. */\n private pvtOnCrossed: ((proc: P, id: number) => void) | undefined;\n\n constructor(parity: IdParity, onCrossed?: (proc: P, id: number) => void) {\n this.pvtRootId = rootIdFor(parity);\n this.pvtFarRootId = rootIdFor(parity === \"odd\" ? \"even\" : \"odd\");\n this.pvtNext = this.pvtRootId + 2;\n this.pvtOnCrossed = onCrossed;\n }\n\n /** The id of this side's own end of the connection. */\n rootId(): number {\n return this.pvtRootId;\n }\n\n /** The id the far side knows its own end by: the root this side reaches as a handle,\n * and the one it never hands out for anything of its own. */\n farRootId(): number {\n return this.pvtFarRootId;\n }\n\n /** Bind this side's own end of the connection — the root — to its id. */\n bindRoot(proc: P): void {\n const bound = this.pvtMine.get(this.pvtRootId);\n if (bound !== undefined && bound !== proc) {\n throw new Error(\"ProcessTable: the root is already bound\");\n }\n this.pvtMine.set(this.pvtRootId, proc);\n this.pvtMineIds.set(proc, this.pvtRootId);\n }\n\n /** The id this side gives a process it holds, allocating one the first time. */\n handleFor(proc: P): number {\n const known = this.pvtMineIds.get(proc);\n if (known !== undefined) return known;\n const id = this.pvtNext;\n this.pvtNext += 2;\n this.pvtMine.set(id, proc);\n this.pvtMineIds.set(proc, id);\n this.pvtOnCrossed?.(proc, id);\n return id;\n }\n\n /** A process this side holds, by the id it gave it. */\n processFor(id: number): P | undefined {\n return this.pvtMine.get(id);\n }\n\n /**\n * Register a process the far side holds — a handle — under the id it arrived\n * with. A root is one of these as much as anything else: both ends hold one at 0,\n * so the far side's root is a handle here, and the one this side has of itself\n * stays what it was.\n */\n bindFar(id: number, proc: P): void {\n this.pvtTheirs.set(id, proc);\n }\n\n /** A process the far side holds, by the id it gave it. */\n farHandleFor(id: number): P | undefined {\n return this.pvtTheirs.get(id);\n }\n\n /**\n * Whatever this connection knows `id` to mean: a process this side holds, or a\n * handle on one the far side holds. Only one of the two can answer, because\n * the two sides take their ids from different halves of the space — so what\n * comes back does not depend on which way the frame was going.\n */\n resolve(id: number): P | undefined {\n return this.pvtMine.get(id) ?? this.pvtTheirs.get(id);\n }\n\n /**\n * Let go of an id: the process behind it is not this connection's business any\n * more, so it is no longer known by it. Both sides' ids go the same way — the\n * side that lets a handle go names the far side's id, the side that is asked to\n * forget names its own — and an id let go is never handed out again, so nothing\n * that still names it can come to mean another process.\n *\n * Neither root is let go of: one is this side's own end of the connection, and the\n * other is what this side is talking to.\n */\n release(id: number): P | undefined {\n if (id === this.pvtRootId || id === this.pvtFarRootId) return undefined;\n const mine = this.pvtMine.get(id);\n if (mine !== undefined) {\n this.pvtMine.delete(id);\n this.pvtMineIds.delete(mine);\n return mine;\n }\n const theirs = this.pvtTheirs.get(id);\n if (theirs !== undefined) this.pvtTheirs.delete(id);\n return theirs;\n }\n\n /** Every handle this side holds on a process of the far side. */\n handles(): P[] {\n return [...this.pvtTheirs.values()];\n }\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n if (typeof value !== \"object\" || value === null) return false;\n const proto = Object.getPrototypeOf(value) as object | null;\n return proto === Object.prototype || proto === null;\n}\n\n/** Whether `value` is the wire form of a reference. */\nexport function asProcessRef(value: unknown): ProcessRef | null {\n if (typeof value !== \"object\" || value === null) return null;\n const ref = (value as Record<string, unknown>)[PROCESS_REF];\n if (typeof ref !== \"object\" || ref === null) return null;\n const { id, pname } = ref as Record<string, unknown>;\n if (typeof id !== \"number\" || typeof pname !== \"string\") return null;\n return { id, pname };\n}\n\n/** Whether `value` has the shape of a handle on a far-side process. Judged by\n * what it holds rather than by `instanceof`, for the reason a process is: one\n * build can hold two copies of the class. */\nexport function isRemoteProcess(value: unknown): value is RemoteProcess {\n if (typeof value !== \"object\" || value === null) return false;\n const candidate = value as { pname?: unknown; id?: unknown; ref?: unknown; send?: unknown };\n return (\n typeof candidate.pname === \"string\" &&\n typeof candidate.id === \"symbol\" &&\n typeof candidate.send === \"function\" &&\n asProcessRef({ [PROCESS_REF]: candidate.ref }) !== null\n );\n}\n\n/**\n * Replace every process in `value` with the reference this connection uses for\n * it, so what is left is JSON that says which processes the answer is about.\n *\n * A handle goes back as the reference it came with, id and all: that id is the\n * far side's own, the one it will be read by.\n *\n * Containers are copied rather than rewritten: the objects belong to the actor\n * that returned them, and a state it is still running on is not ours to edit. A\n * node already seen is left where it is — a cycle is the encoder's to report, not\n * something to walk forever.\n */\nexport function encodeProcessRefs(\n value: unknown,\n table: ProcessTable,\n seen: Set<unknown> = new Set(),\n): unknown {\n if (isRemoteProcess(value)) {\n return { [PROCESS_REF]: { id: value.ref.id, pname: value.ref.pname } };\n }\n if (isProcess(value)) {\n return { [PROCESS_REF]: { id: table.handleFor(value), pname: value.pname } };\n }\n if (Array.isArray(value)) {\n if (seen.has(value)) return value;\n seen.add(value);\n return value.map((item) => encodeProcessRefs(item, table, seen));\n }\n if (isPlainObject(value)) {\n if (seen.has(value)) return value;\n seen.add(value);\n const copy: Record<string, unknown> = {};\n for (const [key, item] of Object.entries(value)) {\n copy[key] = encodeProcessRefs(item, table, seen);\n }\n return copy;\n }\n return value;\n}\n\n/** How a side turns a reference into something it can hold: a handle. */\nexport type RefResolver = (ref: ProcessRef) => unknown;\n\n/** Replace every reference in `value` with what `resolve` makes of it. */\nexport function decodeProcessRefs(\n value: unknown,\n resolve: RefResolver,\n seen: Set<unknown> = new Set(),\n): unknown {\n const ref = asProcessRef(value);\n if (ref) return resolve(ref);\n if (Array.isArray(value)) {\n if (seen.has(value)) return value;\n seen.add(value);\n return value.map((item) => decodeProcessRefs(item, resolve, seen));\n }\n if (isPlainObject(value)) {\n if (seen.has(value)) return value;\n seen.add(value);\n const copy: Record<string, unknown> = {};\n for (const [key, item] of Object.entries(value)) {\n copy[key] = decodeProcessRefs(item, resolve, seen);\n }\n return copy;\n }\n return value;\n}\n","// ── Frame channel ──────────────────────────────────────────────────────────\n//\n// The seam's shared vocabulary. A StringTransport moves encoded frames\n// (strings); a Channel moves decoded frame objects. The frame guards narrow a\n// decoded frame to one of the `$`-key shapes. server.ts / client.ts speak only\n// in Channels and these guards — they never see a specific protocol or\n// transport.\n\nimport type { Message } from \"../types.js\";\nimport {\n decodeProcessRefs,\n encodeProcessRefs,\n type ProcessTable,\n type RefResolver,\n} from \"./process-ref.js\";\n\nexport interface StringTransport {\n send(frame: string): void | Promise<void>;\n onMessage(handler: (frame: string) => void): void;\n removeHandler(): void;\n /** Fires when the peer disconnects (transport closes from the other side). */\n onClose(handler: () => void): void;\n close(): Promise<void>;\n}\n\nexport interface Channel {\n send(frame: Record<string, unknown>): void | Promise<void>;\n onMessage(handler: (frame: Record<string, unknown>) => void): void;\n removeHandler(): void;\n /** Fires when the peer disconnects (transport closes from the other side). */\n onClose(handler: () => void): void;\n close(): Promise<void>;\n}\n\n// ── the address on a frame ─────────────────────────────────────────────────\n//\n// A frame that is about a process carries that process's id as `to`, at the top level\n// of the frame rather than inside its body: the frame is the envelope, and the address\n// says who it is for whatever kind it turns out to be. Every frame that is about a\n// process names it, the root of the connection included, since both ends number their\n// own root and neither has to be guessed at.\n\n/** The id a frame addresses, or null when it names no process. */\nexport function frameTo(frame: Record<string, unknown>): number | null {\n const to = frame.to;\n return typeof to === \"number\" ? to : null;\n}\n\n/**\n * A frame on its way out: every process in it becomes the reference this\n * connection uses for that process, and the process the frame addresses is\n * written down as `to`.\n */\nexport function encodeFrame(\n frame: Record<string, unknown>,\n table: ProcessTable,\n to: number,\n): Record<string, unknown> {\n const encoded = encodeProcessRefs(frame, table) as Record<string, unknown>;\n return { ...encoded, to };\n}\n\n/**\n * A frame just read: every reference in it becomes a handle on that process — or\n * the handle this side already made for it, since the same process handed over\n * twice is one process.\n */\nexport function decodeFrame(\n frame: Record<string, unknown>,\n resolve: RefResolver,\n): Record<string, unknown> {\n return decodeProcessRefs(frame, resolve) as Record<string, unknown>;\n}\n\n// ── frame guards ──────────────────────────────────────────────────────────\n\nexport function isProto(msg: Record<string, unknown>): msg is { $proto: string } {\n return \"$proto\" in msg;\n}\nexport function isInit(msg: Record<string, unknown>): msg is { $init: Record<string, unknown> } {\n return \"$init\" in msg;\n}\nexport function isState(msg: Record<string, unknown>): msg is { $state: Record<string, unknown> } {\n return \"$state\" in msg;\n}\nexport function isMsg(\n msg: Record<string, unknown>,\n): msg is { $msg: { fromName: string; body: Message } } {\n return \"$msg\" in msg;\n}\nexport function isExit(\n msg: Record<string, unknown>,\n): msg is { $exit: { code: number; state: unknown } } {\n return \"$exit\" in msg;\n}\n\n// ── a wire that could not be read ─────────────────────────────────────────\n//\n// Two frames are about the wire itself and not about a process: what a codec could\n// not read, and what a side says when the wire is over. Neither is addressed to\n// anything, and both are decided before a frame is looked up as news or as an ask —\n// a frame about the wire is about the ground the other frames stand on.\n//\n// {\"$bad\": {\"reason\": \"…\", \"raw\": \"…\"}} this side could not read that frame\n// {\"$error\": \"…\"} the wire cannot be spoken over, and why\n//\n// They are frames rather than raised errors on purpose. A frame is read inside the\n// transport's own callback — a socket's `message` event, a stream's line reader —\n// where a throw belongs to nobody: it arrives at the host as an uncaught exception,\n// and one unreadable frame from one peer takes the process down, every other\n// connection in it included. An unreadable frame is the connection's business, not\n// the process's, so it is carried as a frame the connection can answer: `$bad` is how\n// a reader says it inward, and `$error` is how a side says it outward before ending\n// that connection.\n//\n// `$error` is not a refused call — a call that is refused says so about itself, in\n// `$r.result.<name>` (see below). This one is about the wire the calls travel on.\n\nconst BAD_KEY = \"$bad\";\n\n/** How much of an unreadable line is carried: enough to see what it was, never enough to be it.\n * A line that failed to parse is the one line nobody vouched for, so quoting it whole would move\n * whatever it holds — a credential in a paste accident is how that happens — into every log,\n * transcript and context window that later reads the frame. Why, how long, and a short head of\n * it. (`reason` carries a little of the line on its own: a JSON parser says where it gave up and\n * quotes what it was looking at. That is the parser's business, not a promise this file makes.) */\nexport const BAD_PREFIX_LIMIT = 32;\n\nexport function isBad(msg: Record<string, unknown>): msg is { $bad: { reason: string } } {\n return BAD_KEY in msg;\n}\n\n/** The frame that says a frame could not be read: why, how long it was, and the head of it. */\nexport function badFrame(reason: string, raw: string): Record<string, unknown> {\n const prefix = raw.length > BAD_PREFIX_LIMIT ? `${raw.slice(0, BAD_PREFIX_LIMIT)}…` : raw;\n return { [BAD_KEY]: { reason, length: raw.length, prefix } };\n}\n\n/** Why a frame could not be read, or null when it is not a frame that says so. */\nexport function badReason(msg: Record<string, unknown>): string | null {\n const body = msg[BAD_KEY];\n if (typeof body !== \"object\" || body === null) return null;\n const reason = (body as { reason?: unknown }).reason;\n return typeof reason === \"string\" ? reason : null;\n}\n\nconst ERROR_KEY = \"$error\";\n\nexport function isError(msg: Record<string, unknown>): msg is { $error: string } {\n return ERROR_KEY in msg;\n}\n\n/** The frame that says the wire is over: the reason, and the connection ends with it. */\nexport function errorFrame(reason: string): Record<string, unknown> {\n return { [ERROR_KEY]: reason };\n}\n\n/** The reason a wire error carries, or null when it is not one. */\nexport function errorReason(msg: Record<string, unknown>): string | null {\n const reason = msg[ERROR_KEY];\n return typeof reason === \"string\" ? reason : null;\n}\n\n// ── what is said about a crossed process ────────────────────────────────────\n//\n// A process that crossed can be asked for less than everything, or for nothing at\n// all: what crosses about it is three categories, and only the ones asked for are\n// sent. Silence is the empty list, so a handle that asks for nothing hears\n// nothing — not its state, not its messages, and not that it is gone.\n//\n// {\"$tune\": {\"streams\": [\"state\"]}, \"to\": 3} this much about it, and no more\n\nexport type StreamKind = \"message\" | \"state\" | \"exit\";\n\n/** The three, in the one order they are ever named in — the order a tune frame\n * carries them in, so two ways of asking for the same thing look the same. */\nexport const STREAM_KINDS: StreamKind[] = [\"message\", \"state\", \"exit\"];\n\nexport function isStreamKind(value: unknown): value is StreamKind {\n return typeof value === \"string\" && (STREAM_KINDS as string[]).includes(value);\n}\n\n// ── control frames ─────────────────────────────────────────────────────────\n//\n// What the holder of a handle can ask of a process on the far side, beside\n// sending it a message. Each is a frame of its own rather than a message, so\n// nothing an actor reads is ever a control signal by accident:\n//\n// {\"$stop\": {}, \"to\": 3} stop it; it ends, and its `$exit` crosses back\n// {\"$pause\": {}, \"to\": 3} stop feeding it messages\n// {\"$resume\": {}, \"to\": 3} feed it again\n// {\"$release\": {}, \"to\": 3} let it go: forget this id, and stop telling me\n// about the process behind it\n// {\"$tune\": {\"streams\": [...]}, \"to\": 3}\n// say this much about it and no more: a subset of\n// message, state and exit, or the empty list for\n// silence\n//\n// They address the process they are about, so they are answered by whoever holds\n// that process — the side that can act on it. Stopping the *root* of a connection\n// is not one of these: that stays the STOP message it always was, since the root\n// is not a handle but the process this side is talking through.\n\nexport function isStop(msg: Record<string, unknown>): msg is { $stop: Record<string, unknown> } {\n return \"$stop\" in msg;\n}\nexport function isPause(msg: Record<string, unknown>): msg is { $pause: Record<string, unknown> } {\n return \"$pause\" in msg;\n}\nexport function isResume(msg: Record<string, unknown>): msg is { $resume: Record<string, unknown> } {\n return \"$resume\" in msg;\n}\nexport function isRelease(msg: Record<string, unknown>): msg is { $release: Record<string, unknown> } {\n return \"$release\" in msg;\n}\n\nexport function isTune(msg: Record<string, unknown>): msg is { $tune: Record<string, unknown> } {\n return \"$tune\" in msg;\n}\n\n/**\n * The categories a tune frame asks for, in the order they are named in — or null\n * when the frame says something this vocabulary has no word for, which is a frame\n * to ignore rather than to guess at.\n */\nexport function tuneFrame(frame: { $tune: unknown }): StreamKind[] | null {\n const body = frame.$tune;\n if (typeof body !== \"object\" || body === null) return null;\n const streams = (body as { streams?: unknown }).streams;\n if (!Array.isArray(streams)) return null;\n if (!streams.every(isStreamKind)) return null;\n return STREAM_KINDS.filter((kind) => (streams as StreamKind[]).includes(kind));\n}\n\n// ── reflection frames ──────────────────────────────────────────────────────\n//\n// A reflection call crosses the seam as one frame and its answer as another, and\n// both go both ways: whoever holds a process is the one that answers for it.\n//\n// {\"$r.methods\": [\"inspect.getTree\", …]} what a process can answer, once, when\n// it crosses (and, for the root, once\n// when the connection opens)\n// {\"$r.call.<name>\": {seq, args}} asking, addressed to the process\n// {\"$r.result.<name>\": {seq, value}} answered\n// {\"$r.result.<name>\": {seq, error}} refused\n//\n// The method name is in the frame key, so a frame says what it is without a\n// table, and `seq` — one connection's, never reused — tells two calls to the\n// same method apart while both are in flight. An answer is about the call and not\n// about a process, so it carries no address: it names the seq it settles.\n\nexport const REFLECT_METHODS = \"$r.methods\";\nexport const REFLECT_CALL = \"$r.call.\";\nexport const REFLECT_RESULT = \"$r.result.\";\n\nexport interface ReflectionCall {\n name: string;\n seq: number;\n args: unknown[];\n}\n\nexport interface ReflectionResult {\n name: string;\n seq: number;\n value?: unknown;\n error?: string;\n}\n\nexport function isReflectionMethods(\n msg: Record<string, unknown>,\n): msg is { \"$r.methods\": string[] } {\n const names = msg[REFLECT_METHODS];\n return Array.isArray(names) && names.every((name) => typeof name === \"string\");\n}\n\nfunction reflectionBody(\n frame: Record<string, unknown>,\n prefix: string,\n): { name: string; body: Record<string, unknown> } | null {\n for (const key of Object.keys(frame)) {\n if (!key.startsWith(prefix) || key.length === prefix.length) continue;\n const body = frame[key];\n if (typeof body !== \"object\" || body === null) return null;\n return { name: key.slice(prefix.length), body: body as Record<string, unknown> };\n }\n return null;\n}\n\n/** A call frame, or null — a malformed one is not worth an answer. */\nexport function asReflectionCall(frame: Record<string, unknown>): ReflectionCall | null {\n const parsed = reflectionBody(frame, REFLECT_CALL);\n if (!parsed || typeof parsed.body.seq !== \"number\") return null;\n const args = parsed.body.args;\n return {\n name: parsed.name,\n seq: parsed.body.seq,\n args: Array.isArray(args) ? args : [],\n };\n}\n\n/** An answer frame, or null. `error` present means the call was refused. */\nexport function asReflectionResult(frame: Record<string, unknown>): ReflectionResult | null {\n const parsed = reflectionBody(frame, REFLECT_RESULT);\n if (!parsed || typeof parsed.body.seq !== \"number\") return null;\n const { seq, value, error } = parsed.body;\n return typeof error === \"string\"\n ? { name: parsed.name, seq, error }\n : { name: parsed.name, seq, value };\n}\n\n/**\n * Why a value cannot cross a frame, or null when it can. Only JSON data\n * crosses: a function, a symbol or a bigint cannot be written down at all, and\n * a value with a cycle or a bigint inside it makes the encoder throw. What\n * JSON itself would quietly drop — a function stored inside an object — is the\n * caller's business, not something to invent a policy for here.\n */\nexport function jsonProblem(value: unknown): string | null {\n const kind = typeof value;\n if (kind === \"function\" || kind === \"symbol\" || kind === \"bigint\") return `a ${kind}`;\n if (kind !== \"object\" || value === null) return null;\n try {\n JSON.stringify(value);\n } catch (err) {\n return err instanceof Error ? err.message : String(err);\n }\n return null;\n}\n","// ── A process on the far side, as this side can use it ─────────────────────\n//\n// A handle. It knows the name the far side calls the process and the id this\n// connection knows it by, and one thing more than a bare reference has: a way to\n// put a frame on the wire with that id. Everything else it offers is what comes\n// back because of it — the state that streams for it, the messages it emits, the\n// methods it announced.\n//\n// A handle is not a process of this side's tree. Nothing has to make it one:\n// the far side's tree is already reachable through reflection, so asking the\n// proxy for it walks that side and gives that tree. A handle is how something\n// on the far side is talked to, not where it sits here.\n\nimport type { Message } from \"../types.js\";\nimport { makeWaiter, type Waiter } from \"../util.js\";\nimport { PROCESS_REF, isRemoteProcess } from \"./process-ref.js\";\nimport { STREAM_KINDS, type StreamKind } from \"./channel.js\";\nimport type { ProcessRef } from \"./process-ref.js\";\n\n/**\n * What a reference with nothing keeping it amounts to. It names a process this side can\n * hear nothing from and ask nothing of, so it is not a process in any sense that matters\n * here, and it is written as what it is wherever it turns up: a state somebody is reading,\n * a log line, anything at all that stringifies.\n */\nexport const UNSTABLE_REFERENCE = \"UnstableReference\";\n\n/** What a process left behind when it ended. */\n/**\n * The references inside a value that crossed. A handle is the one thing in a frame that is\n * not JSON, so wherever one sits, it came here on somebody else's frame and whoever is\n * holding that value is holding it. Plain objects and arrays only: a value of another kind\n * is not a shape this walks, and its references are not found.\n */\nfunction refsInside(value: unknown): RemoteProcess[] {\n const found: RemoteProcess[] = [];\n const seen = new Set<unknown>();\n const walk = (node: unknown): void => {\n if (isRemoteProcess(node)) {\n found.push(node);\n return;\n }\n if (typeof node !== \"object\" || node === null) return;\n if (seen.has(node)) return;\n seen.add(node);\n if (Array.isArray(node)) {\n for (const item of node) walk(item);\n return;\n }\n const proto = Object.getPrototypeOf(node) as object | null;\n if (proto !== Object.prototype && proto !== null) return;\n for (const item of Object.values(node as Record<string, unknown>)) walk(item);\n };\n walk(value);\n return found;\n}\n\nexport interface RemoteExit {\n code: number;\n state: unknown;\n}\n\n/** How a handle gets a frame onto the connection it belongs to, addressed to a\n * process the far side holds. The answer is handed back when a caller has to know\n * the frame is out — the root's end is said that way, just before the wire closes. */\nexport type FrameSink = (frame: Record<string, unknown>, to: number) => void | Promise<void>;\n\n/** What a side does when it lets go of a handle: stop knowing the id, so nothing\n * arriving for it can land here again. */\nexport type ReleaseHook = (id: number) => void;\n\n/** An out-message of the far process, and the name it came with. */\nexport type RemoteMessage<OutMsg extends Message = Message> = (msg: OutMsg, fromName: string) => void;\n\nexport class RemoteProcess<InMsg extends Message = Message, OutMsg extends Message = Message> {\n /** The name the far side knows it by. */\n readonly pname: string;\n /** The id this connection knows it by — the far side's own, since it is the\n * side that holds the process. */\n readonly ref: ProcessRef;\n /** A symbol of this side's own, so a handle can be told apart from any other\n * the way a process is: by holding one. */\n readonly id: symbol;\n /** What the far side has said about its state so far. */\n state: Record<string, unknown> | null = null;\n /** The methods the far side announced it can answer. */\n readonly $reflection: Record<string, (...args: unknown[]) => Promise<unknown>> = {};\n\n private pvtSend: FrameSink;\n private pvtFromName: string;\n private pvtConnected = true;\n /** This side let it go: nothing more is asked of it, and nothing arriving for it\n * is news any more. Not the same as ending, and not the same as the connection\n * going: in all three the handle is dead, and only the reason differs. */\n private pvtReleased = false;\n private pvtLetGo: ReleaseHook | undefined;\n /** What the far side said when it ended, or null while it is running. */\n private pvtExit: RemoteExit | null = null;\n private pvtExitWaiter: Waiter<RemoteExit> | null = null;\n private pvtMessageSubs: Array<RemoteMessage<OutMsg>> = [];\n private pvtStateSubs: Array<() => void> = [];\n /** Whoever is waiting to hear what it holds, settled by the first word of it. */\n private pvtReadyWaiters: Array<() => void> = [];\n /** How many times this reference has been kept. Nothing is heard about a process\n * nothing here keeps, so the count is what makes a handle usable rather than a name. */\n private pvtRefCount = 0;\n /** The handles this one keeps because they sit in what it holds. Counted, and given\n * back when this one is let go of: the thing holding them is here. */\n private pvtOwnedRefs: RemoteProcess[] = [];\n /** The handles that arrived here on their way somewhere else, in a message or an answer.\n * Not counted — nobody here asked for them, and whoever receives them is the one to deal\n * with them — but remembered, so that one nobody ever keeps is let go of after all. */\n private pvtTransientRefs: RemoteProcess[] = [];\n /** What this side has asked to be told about it. A process that crosses is\n * silent, so a handle starts out having asked for nothing and hears nothing\n * until something here wants it — which is the same rule the far side holds,\n * written from the other end. */\n private pvtWanted: Set<StreamKind> = new Set();\n\n constructor(ref: ProcessRef, send: FrameSink, fromName: string, letGo?: ReleaseHook) {\n this.ref = ref;\n this.pname = ref.pname;\n this.id = Symbol(ref.pname);\n this.pvtSend = send;\n this.pvtFromName = fromName;\n this.pvtLetGo = letGo;\n }\n\n /**\n * Whether the process this handle names can still be reached: the wire is there, and\n * this side has not let the handle go.\n *\n * Reaching it is not the same as it being alive. A process that has ended is still\n * one this side has a handle on — it is what the handle points at, and what it left\n * behind is here — so an end does not put it out of reach; `hasEnded()` is that\n * answer, and the two are asked separately. From the two ways out there is no coming\n * back: no reconnect, and no way to un-release.\n */\n isConnected(): boolean {\n return this.pvtConnected && !this.pvtReleased;\n }\n\n /**\n * The connection is gone. Every handle this side holds goes out of reach with it,\n * and says so: there is no reconnect to wait for, so a send fails here and now\n * rather than disappearing into nothing.\n */\n disconnect(): void {\n if (!this.pvtConnected) return;\n this.pvtConnected = false;\n this.pvtStateSubs.forEach((fn) => fn());\n this.pvtSettleReady();\n // Whoever is waiting for it to end is waiting for news that can no longer come.\n this.pvtExitWaiter?.reject(new Error(`${this.pname} cannot be reached: the connection is closed`));\n }\n\n /** Whether the process it names has ended, as far as this side has been told. */\n hasEnded(): boolean {\n return this.pvtExit !== null;\n }\n\n /** Why nothing can be asked *of the process* — let go, ended, or out of reach — or\n * nothing when something can. Those are not one thing said three ways: an ended\n * process is still reached, it simply has nothing left to receive. */\n private pvtWhyNotAskable(): string | null {\n if (this.pvtReleased) return `${this.pname} was released`;\n if (this.pvtExit !== null) return `${this.pname} has ended`;\n if (!this.pvtConnected) return `${this.pname} cannot be reached: the connection is closed`;\n return null;\n }\n\n private pvtRequireAskable(): void {\n const why = this.pvtWhyNotAskable();\n if (why !== null) throw new Error(why);\n }\n\n /**\n * Keep this reference: from here it is counted, which is what lets anything be asked of\n * it. It returns the handle, so what is kept is written in one line —\n * `this.pvtRemoteRefsHeld.push(ref.holdRef())` — and a table of them reads as what it is.\n */\n holdRef(): this {\n this.pvtRefCount += 1;\n return this;\n }\n\n /**\n * Give the count back. Whoever gives the last one back lets the reference go, which is\n * what tells the far side that nothing here wants to hear about the process again. A\n * reference nobody ever kept is let go of by this too, which is how whoever receives one\n * they do not want is rid of it.\n */\n releaseRef(): void {\n if (this.pvtRefCount > 0) this.pvtRefCount -= 1;\n if (this.pvtRefCount > 0) return;\n // The last count going means this reference is nobody's here. One that can still be\n // asked is let go of, which is what tells the far side to stop saying anything about it.\n // One that has ended, or whose connection went, has nothing left to be told: what there\n // is to drop is the binding here, and there is nobody to ask about it.\n if (this.pvtWhyNotAskable() === null) {\n this.release();\n return;\n }\n this.pvtDropBinding();\n }\n\n /** Let go of the binding here without asking the far side for anything: what the process\n * was is over, or the wire that carried it is. */\n private pvtDropBinding(): void {\n if (this.pvtReleased) return;\n this.pvtReleased = true;\n this.pvtLetGo?.(this.ref.id);\n this.pvtSettleReady();\n }\n\n /** How many times this reference has been kept. */\n refCount(): number {\n return this.pvtRefCount;\n }\n\n /**\n * What this is, as text: a handle nothing here keeps is an unstable reference and says\n * so, and one that is kept says which process it names and by which id.\n */\n [Symbol.for(\"nodejs.util.inspect.custom\")](): string {\n return this.pvtRefCount === 0 ? UNSTABLE_REFERENCE : `RemoteProcess(${this.ref.id}: ${this.pname})`;\n }\n\n /**\n * What this is, in JSON: the same reference the wire would carry, or the unstable thing\n * it is when nothing keeps it. Written so that an unheld reference cannot be mistaken\n * for a process that merely looks odd in a state, and so that one that is kept reads as\n * the reference it is rather than as whatever fields it happens to have.\n */\n toJSON(): unknown {\n if (this.pvtRefCount === 0) return UNSTABLE_REFERENCE;\n return { [PROCESS_REF]: { id: this.ref.id, pname: this.pname } };\n }\n\n /**\n * Remember the references inside a value that arrived here to be passed on. They are not\n * counted — the receiver is the one to deal with them — and this is what keeps one from\n * being nobody's for ever: when this handle is let go of, they are dropped with it.\n */\n markTransient(value: unknown): void {\n for (const ref of refsInside(value)) {\n if (ref.id === this.id || ref.pvtReleased) continue;\n this.pvtDropTransient(ref);\n if (this.pvtOwnedRefs.includes(ref) || this.pvtTransientRefs.includes(ref)) continue;\n this.pvtTransientRefs.push(ref);\n }\n }\n\n /** Stop treating a reference as one that was only passing through. */\n private pvtDropTransient(ref: RemoteProcess): void {\n const at = this.pvtTransientRefs.indexOf(ref);\n if (at >= 0) this.pvtTransientRefs.splice(at, 1);\n }\n\n /**\n * Keep the references sitting in what this process holds. What it holds is here, so the\n * thing keeping those references alive is this handle, and it holds them until it is let\n * go of itself.\n */\n private pvtHoldOwned(value: unknown): void {\n for (const ref of refsInside(value)) {\n if (ref.id === this.id || ref.pvtReleased) continue;\n if (this.pvtOwnedRefs.includes(ref)) continue;\n this.pvtDropTransient(ref);\n this.pvtOwnedRefs.push(ref.holdRef());\n }\n }\n\n /** Nothing is heard about a process nothing here keeps. A subscription, a tuning and a\n * wait for the state are all ways of hearing, so they are where a reference has to have\n * been kept first — and where the mistake says what to do about it. */\n private pvtRequireHeld(what: string): void {\n if (this.pvtRefCount > 0) return;\n throw new Error(\n `${this.pname} is not held by anyone here: call holdRef() to keep this reference, ` +\n `or releaseRef() to let it go, before ${what}`,\n );\n }\n\n /**\n * Wait until what it holds is here.\n *\n * A handle starts out knowing nothing about the process: the far side says what a\n * process holds when something over here asks to hear it, so the asking and the waiting\n * are one act, and this is both. It settles with whatever has arrived when nothing more\n * can: a process that has ended has said its last, and a connection that has gone has\n * nothing left to say. Asking twice is asking about what is already here.\n */\n ready(): Promise<void> {\n if (this.state !== null || this.pvtWhyNotAskable() !== null) return Promise.resolve();\n this.pvtRequireHeld(\"waiting for what it holds\");\n this.pvtWant(\"state\");\n return new Promise<void>((resolve) => this.pvtReadyWaiters.push(resolve));\n }\n\n /** Everyone waiting for what it holds has heard it, or never will. */\n private pvtSettleReady(): void {\n const waiting = this.pvtReadyWaiters;\n this.pvtReadyWaiters = [];\n for (const resolve of waiting) resolve();\n }\n\n /**\n * Wait for the process to end. Its exit crosses back like everything else it\n * does, and what it left behind is the answer.\n *\n * A handle whose connection is gone rejects instead: what is left to wait for\n * after that is nothing, and a process that keeps running is not something this\n * side can tell from one that died with the wire.\n */\n wait(): Promise<RemoteExit> {\n if (this.pvtExit !== null) return Promise.resolve(this.pvtExit);\n const why = this.pvtWhyNotAskable();\n if (why !== null) return Promise.reject(new Error(why));\n // Waiting for it to end is a subscription to its end: nothing here hears an\n // exit that was never asked for, so asking to wait asks for it.\n this.pvtWant(\"exit\");\n this.pvtExitWaiter ??= makeWaiter<RemoteExit>();\n return this.pvtExitWaiter.promise;\n }\n\n /**\n * Ask the far side to stop it. Stops the way it always does there, and this\n * resolves when its exit has crossed back — which is all this side can know.\n * There is no deadline, so a process that refuses to stop leaves this pending.\n */\n stop(): Promise<void> {\n this.pvtRequireAskable();\n // Ask for the end before asking it to stop: whether an exit is sent is decided\n // by what the far side has been asked for when it comes, so a stop ordered ahead\n // of the asking could leave nothing to wait for.\n this.pvtWant(\"exit\");\n this.pvtSend({ $stop: {} }, this.ref.id);\n return this.wait().then(() => undefined);\n }\n\n /**\n * Let it go: the far side forgets this id and stops telling this side anything\n * about the process behind it. The process itself is untouched — it runs on, it\n * is simply nobody's here any more — and this handle is done: nothing reaches it,\n * nothing is waited for, and what arrives for it later is not news.\n */\n release(): void {\n this.pvtRequireAskable();\n this.pvtReleased = true;\n const owned = this.pvtOwnedRefs;\n this.pvtOwnedRefs = [];\n for (const ref of owned) {\n if (!ref.pvtReleased) ref.releaseRef();\n }\n const transient = this.pvtTransientRefs;\n this.pvtTransientRefs = [];\n for (const ref of transient) {\n // One that was kept by whoever received it is theirs, and one that was never kept is\n // nobody's: there is nothing else that would ever let go of it.\n if (!ref.pvtReleased && ref.pvtRefCount === 0) ref.release();\n }\n this.pvtLetGo?.(this.ref.id);\n this.pvtSend({ $release: {} }, this.ref.id);\n this.pvtSettleReady();\n }\n\n /** Stop feeding it messages. It is still there: `send` still reaches it. */\n pause(): void {\n this.pvtRequireAskable();\n this.pvtSend({ $pause: {} }, this.ref.id);\n }\n\n /** Feed it messages again. */\n resume(): void {\n this.pvtRequireAskable();\n this.pvtSend({ $resume: {} }, this.ref.id);\n }\n\n /**\n * What to be told about it from now on: any of `message`, `state` and `exit`,\n * or `\"silent\"` for none of it.\n *\n * A process that crossed is silent to begin with, so this is how a handle asks\n * to hear anything at all — and what is heard is only ever what was asked for.\n * An exit nobody asked for is not sent: silence is silence, which makes this the\n * one way to leave a handle that will not answer a `wait()`, and the far side's\n * books the one place an end can go unrecorded.\n */\n tune(kinds: StreamKind[] | \"silent\"): void {\n this.pvtRequireAskable();\n this.pvtRequireHeld(\"tuning what is heard about it\");\n this.pvtTune(kinds === \"silent\" ? [] : kinds);\n }\n\n /** Ask the far side to say exactly this much, and nothing when it is already\n * saying it. The list goes in the order the three are named in, so asking for\n * the same thing twice sends the same frame twice. */\n private pvtTune(wanted: StreamKind[]): void {\n const kinds = STREAM_KINDS.filter((kind) => wanted.includes(kind));\n if (kinds.length === this.pvtWanted.size && kinds.every((kind) => this.pvtWanted.has(kind))) {\n return;\n }\n this.pvtWanted = new Set(kinds);\n this.pvtSend({ $tune: { streams: kinds } }, this.ref.id);\n }\n\n /** Ask for one more category, because something here now wants it. A handle\n * that is gone asks nothing: there is no far side left to hear it, and nothing\n * was asked for, so what was wanted stays what it was. */\n private pvtWant(kind: StreamKind): void {\n if (this.pvtWanted.has(kind)) return;\n if (!this.pvtConnected || this.pvtReleased) return;\n this.pvtTune([...this.pvtWanted, kind]);\n }\n\n /** Hand the far process a message. */\n send(msg: InMsg): void {\n this.pvtRequireAskable();\n this.pvtSend({ $msg: { fromName: this.pvtFromName, body: msg } }, this.ref.id);\n }\n\n /** Subscribe to what it says, or to what it holds. Asking here is asking the far\n * side: a subscription is the first thing that wants the category, so it is what\n * turns it on, and unsubscribing leaves it on — the far side is not told to stop\n * saying something that another subscriber may still want. */\n subscribe(channel: \"message\", cb: RemoteMessage<OutMsg>): () => void;\n subscribe(channel: \"state\", cb: () => void): () => void;\n subscribe(channel: \"message\" | \"state\", cb: RemoteMessage<OutMsg> | (() => void)): () => void {\n this.pvtRequireHeld(`subscribing to what it ${channel === \"message\" ? \"says\" : \"holds\"}`);\n if (channel === \"message\") {\n const fn = cb as RemoteMessage<OutMsg>;\n this.pvtMessageSubs.push(fn);\n this.pvtWant(\"message\");\n return () => this.pvtUnsubscribe(this.pvtMessageSubs, fn);\n }\n const fn = cb as () => void;\n this.pvtStateSubs.push(fn);\n this.pvtWant(\"state\");\n return () => this.pvtUnsubscribe(this.pvtStateSubs, fn);\n }\n\n private pvtUnsubscribe<T>(list: Array<T>, fn: T): void {\n const idx = list.indexOf(fn);\n if (idx >= 0) list.splice(idx, 1);\n }\n\n // ── what the connection delivers ─────────────────────────────────────────\n // The handle does not read frames; the side that owns the connection hands it\n // what a frame about this process said.\n\n /** Its state, as the far side just published it. */\n receiveState(state: Record<string, unknown>): void {\n if (this.pvtReleased) return;\n this.state = Object.assign(this.state ?? {}, state);\n this.pvtHoldOwned(state);\n this.pvtStateSubs.forEach((fn) => fn());\n this.pvtSettleReady();\n }\n\n /** A message it emitted. */\n receiveMessage(msg: OutMsg, fromName: string): void {\n if (this.pvtReleased) return;\n // Anything that came along in the message came here on its way somewhere else.\n this.markTransient(msg);\n this.pvtMessageSubs.forEach((fn) => fn(msg, fromName));\n }\n\n /** It has ended, and this is what it left behind. The last thing said about a\n * process: nothing crosses about it after its exit, though the handle still\n * reaches it for what it left. */\n receiveExit(exit: RemoteExit): void {\n if (this.pvtExit !== null || this.pvtReleased) return;\n this.pvtExit = exit;\n this.pvtExitWaiter?.resolve(exit);\n // Nobody is waiting for state from a process that has ended: what it left is all\n // there is, and nothing more is coming.\n this.pvtSettleReady();\n }\n\n /** The methods it can answer, as functions that ask it for an answer. `call`\n * is the connection's own: a handle knows what to ask for, not how a call is\n * made or paired with its answer. */\n receiveMethods(names: string[], call: (name: string, args: unknown[]) => Promise<unknown>): void {\n for (const name of names) {\n this.$reflection[name] = async (...args: unknown[]) => {\n const value = await call(name, args);\n // A reference in an answer was handed to whoever asked, which makes it theirs to\n // deal with; this handle only remembers it, so that it is dropped with this one.\n this.markTransient(value);\n return value;\n };\n }\n }\n}\n","// ── What a process says once it has crossed ─────────────────────────────────\n//\n// A process that crosses the connection is numbered, and from that moment the\n// other side can be told about it: what it can answer, what it holds, and what it\n// emits. Both ends say exactly this about the processes they hold — the side that\n// hands one over, and the side that serves one — so it is written once here\n// rather than once per side.\n\nimport { isProcess, type AnyProcess } from \"../process.async.js\";\nimport { REFLECT_METHODS, STREAM_KINDS, type StreamKind } from \"./channel.js\";\n\nimport type { FrameSink } from \"./remote-process.js\";\n\n/** What a process can be asked over the wire: the functions on its reflection\n * surface, read once. On the side that serves it the list *is* the dispatch\n * table, so a name that was never on it can never be reached. */\nconst pvtReflectionNames = new WeakMap<object, string[]>();\n\nexport function reflectionNames(target: { $reflection?: unknown }): string[] {\n const known = pvtReflectionNames.get(target);\n if (known) return known;\n const surface = (target.$reflection ?? {}) as Record<string, unknown>;\n const names = Object.keys(surface).filter((name) => typeof surface[name] === \"function\");\n pvtReflectionNames.set(target, names);\n return names;\n}\n\n/**\n * The processes of one side that have crossed, and what the far side is told\n * about them.\n *\n * A stream starts once the frame that carried the reference is out: frames about\n * a process the reader cannot name yet have nowhere to land. The table numbers a\n * process while that frame is being written, so the numbering is queued here and\n * let out by `flush` right after the frame goes — which is the only thing a\n * caller has to remember.\n *\n * What a stream says is what the far side asked for. A process that crosses is silent\n * until something over there asks to hear it, and `tune` is that asking: only the\n * categories it names cross. The root of the connection is no exception. It is\n * registered here the moment the connection opens, and a side that wants to hear it\n * asks, which is what a visitor's proxy does for the state and messages it stands in\n * for.\n */\n\n/** One process that crossed, and what is said about it now. */\ninterface StreamRecord {\n target: AnyProcess;\n /** The categories that cross, out of the three. */\n kinds: Set<StreamKind>;\n /** How to stop hearing one that is armed. `exit` is not among them: a stream\n * has to hear the end to know it is over, and what it does with the news is\n * the question `kinds` answers. */\n stops: Map<StreamKind, () => void>;\n}\n\nexport class ProcessStreams {\n private pvtSink: FrameSink;\n /** The id of the connection's own end. Its end is the connection's end, so the side\n * that owns the wire says it, awaited there, instead of this watching for it as it\n * watches any other process's. */\n private pvtRootId: number;\n private pvtPending: Array<[AnyProcess, number]> = [];\n private pvtRecords = new Map<number, StreamRecord>();\n private pvtFlushing = false;\n\n constructor(sink: FrameSink, rootId: number) {\n this.pvtSink = sink;\n this.pvtRootId = rootId;\n }\n\n /** A process was numbered: it is about to cross. Anything that is not a\n * process — a handle travelling back to the side that holds it — crosses as\n * the reference it came with and is nobody's to stream. */\n crossed(proc: unknown, id: number): void {\n if (!isProcess(proc)) return;\n this.pvtPending.push([proc, id]);\n }\n\n /** Say what there is to say about whatever crossed while a frame was written. */\n flush(): void {\n if (this.pvtFlushing) return;\n this.pvtFlushing = true;\n try {\n while (this.pvtPending.length > 0) {\n const next = this.pvtPending.shift();\n if (next) this.pvtStream(next[0], next[1]);\n }\n } finally {\n this.pvtFlushing = false;\n }\n }\n\n /**\n * What to say about it from now on: the categories named, and none of the\n * others. Asking for its state says it there and then — a handle that has just\n * asked what it holds should not have to wait for it to change.\n *\n * An id with no stream here is not this side's to tune, and the frame is\n * dropped: both sides tune only what they hold, so an id names a stream on the\n * side that numbered it.\n */\n tune(id: number, kinds: StreamKind[]): void {\n const record = this.pvtRecords.get(id);\n if (!record) return;\n const wanted = new Set(kinds);\n for (const kind of STREAM_KINDS) {\n const isOn = record.kinds.has(kind);\n const want = wanted.has(kind);\n if (want === isOn) continue;\n if (want) {\n record.kinds.add(kind);\n this.pvtArm(record, id, kind);\n } else {\n record.kinds.delete(kind);\n this.pvtDisarm(record, kind);\n }\n }\n }\n\n /**\n * Say nothing more about this one. It is not that the process ended — the far\n * side asked to be left out of it, so its exit is nobody's news over here, and\n * dropping the subscription is what keeps it from being sent.\n */\n stop(id: number): void {\n const record = this.pvtRecords.get(id);\n if (!record) return;\n for (const stop of record.stops.values()) stop();\n this.pvtRecords.delete(id);\n }\n\n /** Nothing more is said about any of them: the connection is done. */\n stopAll(): void {\n for (const id of [...this.pvtRecords.keys()]) this.stop(id);\n this.pvtPending.length = 0;\n }\n\n private pvtStream(target: AnyProcess, id: number): void {\n // Nothing to begin with: what is said about a process is what the far side asks\n // for, and the root is asked for like anything else.\n const record: StreamRecord = {\n target,\n kinds: new Set(),\n stops: new Map(),\n };\n this.pvtRecords.set(id, record);\n // What it can answer comes first: a handle that hears from a process it cannot\n // name yet has nowhere to put the news. It is not one of the three categories\n // — a handle with no methods can do nothing with the process however much it\n // is told about it — so it crosses even in silence.\n this.pvtSink({ [REFLECT_METHODS]: reflectionNames(target) }, id);\n for (const kind of record.kinds) this.pvtArm(record, id, kind);\n // Its end is the last thing ever said about it, and the one thing a stream has\n // to hear to know it is over, whether or not the far side is told. A process\n // that fails to run takes the same road as one that finishes.\n //\n // Not for the root. Its end is the connection's end, and the side that owns the\n // wire says it while taking the wire down, awaiting it there because that frame has\n // to be out before the close. Both of them end up in `sayEnded`.\n if (id !== this.pvtRootId) {\n void target.wait().then(\n () => void this.sayEnded(id, 0),\n () => void this.sayEnded(id, 1),\n );\n }\n }\n\n /** Start saying this much about it, and say what there is to say now. */\n private pvtArm(record: StreamRecord, id: number, kind: StreamKind): void {\n if (kind === \"message\") {\n record.stops.set(\n \"message\",\n record.target.subscribe(\"message\", (msg, sender) => {\n this.pvtSink({ $msg: { fromName: sender.fromName, body: msg } }, id);\n }),\n );\n return;\n }\n if (kind === \"state\") {\n record.stops.set(\n \"state\",\n record.target.subscribe(\"state\", () => {\n this.pvtSink({ $state: record.target.state as Record<string, unknown> }, id);\n }),\n );\n // Asked for, so said now: in silence the far side has heard nothing about\n // its state, and this is the first word rather than a repeat.\n this.pvtSink({ $state: record.target.state as Record<string, unknown> }, id);\n }\n // `exit` needs no subscription: the end is watched from the moment the process\n // crosses, since a stream has to know when it is over. Whether it is sent is\n // read from `kinds` when it comes.\n }\n\n private pvtDisarm(record: StreamRecord, kind: StreamKind): void {\n const stop = record.stops.get(kind);\n if (!stop) return;\n stop();\n record.stops.delete(kind);\n }\n\n /**\n * It has ended: say so once, if that is among the categories asked for, and say\n * nothing more about it either way. Awaited by whoever has to have the frame out\n * before the wire closes, which is the root's end and nobody else's — no other\n * process can end after this side has stopped saying anything about it.\n */\n async sayEnded(id: number, code: number): Promise<void> {\n const record = this.pvtRecords.get(id);\n if (!record) return;\n const told = record.kinds.has(\"exit\");\n const state = record.target.state;\n this.stop(id);\n if (told) await this.pvtSink({ $exit: { code, state } }, id);\n }\n}\n","// ── Who a message that crossed the wire came from ──────────────────────────\n//\n// A frame carries its sender as a name, because a symbol cannot be written down.\n// On the other side the name is turned back into an identity a process can be\n// handed: whoever the frame names, and — when that name is the one a process was\n// told is its parent — the parent's own stable id, so a child on either side of\n// the seam recognises the same sender.\n\nimport type { SenderInfo } from \"../types.js\";\n\nexport function makeSender(\n fromName: string,\n parentName: string | null,\n parentId: symbol | null,\n): SenderInfo {\n if (parentId && fromName === parentName) {\n return { fromName, fromId: parentId };\n }\n return { fromName, fromId: Symbol() };\n}\n","// ── The call side of a connection ───────────────────────────────────────────\n//\n// Both ends of a seam make calls and answer them, and the machinery is the same\n// once the wire is: a `seq` the connection counts, the calls waiting under it, the\n// surface a handle reads to make one, and the answer that names which call it\n// settles. Only where a frame leaves differs between the two ends, which is why\n// that is the one thing handed in and the rest is written once.\n\nimport { isProcess } from \"../process.async.js\";\nimport {\n REFLECT_CALL,\n REFLECT_RESULT,\n asReflectionResult,\n encodeFrame,\n jsonProblem,\n type ReflectionCall,\n} from \"./channel.js\";\nimport {\n encodeProcessRefs,\n isRemoteProcess,\n type ProcessHandle,\n type ProcessTable,\n} from \"./process-ref.js\";\nimport { reflectionNames } from \"./process-streams.js\";\n\n/** A frame on its way out: encoded, addressed, and written to this end's wire. */\nexport type WireSink = (frame: Record<string, unknown>) => Promise<void>;\n\nexport class CallSide {\n /**\n * `seq` belongs to this connection and is never reused, so two calls to the same\n * method in flight at once stay apart; the answer names the one it belongs to,\n * whichever process it was asked of.\n */\n private pvtCalls = 0;\n private pvtWaiting = new Map<\n number,\n { name: string; resolve: (value: unknown) => void; reject: (error: Error) => void }\n >();\n private pvtWrite: WireSink;\n private pvtTable: ProcessTable<ProcessHandle>;\n\n constructor(write: WireSink, table: ProcessTable<ProcessHandle>) {\n this.pvtWrite = write;\n this.pvtTable = table;\n }\n\n /**\n * Ask a process on the far side for one of its methods. Processes among the\n * arguments become references first — this side's own, with ids from its table, or\n * the far side's coming back — and what is left has to be JSON, or nothing is sent\n * at all.\n */\n call(method: string, callArgs: unknown[], to: number): Promise<unknown> {\n return new Promise((resolve, reject) => {\n const seq = ++this.pvtCalls;\n const frame = encodeFrame(\n { [`${REFLECT_CALL}${method}`]: { seq, args: callArgs } },\n this.pvtTable,\n to,\n );\n const problem = jsonProblem(frame);\n if (problem !== null) {\n reject(new Error(`cannot send ${problem} to ${method}`));\n return;\n }\n this.pvtWaiting.set(seq, { name: method, resolve, reject });\n void this.pvtWrite(frame).catch((error: unknown) => {\n this.pvtWaiting.delete(seq);\n reject(error instanceof Error ? error : new Error(String(error)));\n });\n });\n }\n\n /**\n * One function per announced name, on the surface whoever calls reads.\n *\n * An answer that carries a reference hands it to whoever asked, which makes it theirs to\n * deal with: the handle that was asked is told about it, so that one nobody keeps is let\n * go of with that handle rather than being nobody's for ever.\n */\n install(surface: Record<string, unknown>, methods: string[], to: number): void {\n for (const method of methods) {\n surface[method] = async (...callArgs: unknown[]) => {\n const value = await this.call(method, callArgs, to);\n const owner = this.pvtTable.farHandleFor(to);\n if (isRemoteProcess(owner)) owner.markTransient(value);\n return value;\n };\n }\n }\n\n /**\n * An answer to a call this side made: the call waiting under that `seq` is settled\n * by it, and the frame says whether it was one at all. An answer is about the call\n * and not about a process, so a dispatcher reads it before it looks anything up.\n */\n settle(frame: Record<string, unknown>): boolean {\n const result = asReflectionResult(frame);\n if (!result) return false;\n const waiting = this.pvtWaiting.get(result.seq);\n if (waiting) {\n this.pvtWaiting.delete(result.seq);\n if (result.error === undefined) waiting.resolve(result.value);\n else waiting.reject(new Error(`${waiting.name}: ${result.error}`));\n }\n return true;\n }\n\n /** A call that was in flight when the wire went has no answer coming; it fails\n * here rather than hanging for ever. */\n rejectAll(): void {\n for (const waiting of this.pvtWaiting.values()) {\n waiting.reject(new Error(`connection closed before ${waiting.name} answered`));\n }\n this.pvtWaiting.clear();\n }\n}\n\n/**\n * Answer one call with what the process said, or why it could not. A method may be\n * written for a call that answers later; the wire has no opinion about that, it just\n * waits for the frame.\n */\nexport async function answerCall(\n call: ReflectionCall,\n target: ProcessHandle | undefined,\n write: WireSink,\n table: ProcessTable<ProcessHandle>,\n): Promise<void> {\n // An answer goes back to the far side's own end of the connection: a result is about\n // the call and not about a process, and the one waiting for it is out there.\n const reply = (body: Record<string, unknown>) =>\n write(encodeFrame({ [`${REFLECT_RESULT}${call.name}`]: body }, table, table.farRootId()));\n // Only a process this side holds can be asked: the id a call names is the holder's\n // own, and this side is the holder of what it holds.\n if (!isProcess(target)) {\n await reply({ seq: call.seq, error: \"no process with that id on this connection\" });\n return;\n }\n const names = reflectionNames(target);\n const surface = target.$reflection as unknown as Record<string, Function>;\n const method = names.includes(call.name) ? surface[call.name] : undefined;\n if (typeof method !== \"function\") {\n await reply({ seq: call.seq, error: `no reflection method named ${call.name}` });\n return;\n }\n try {\n // References in the arguments arrived as handles on processes of this side's own,\n // and processes in the answer become references. What is left has to be JSON, or\n // the call is refused rather than half-written.\n const value = encodeProcessRefs(await method(...call.args), table);\n const problem = jsonProblem(value);\n if (problem !== null) {\n await reply({\n seq: call.seq,\n error: `${call.name} returned ${problem}, which cannot cross a frame`,\n });\n return;\n }\n await reply({ seq: call.seq, value });\n } catch (err) {\n await reply({ seq: call.seq, error: err instanceof Error ? err.message : String(err) });\n }\n}\n","// ── Server side of the seam ────────────────────────────────────────────────\n//\n// serveRemoteActor serves a posipaki actor over a frame Channel produced by a\n// spawner. It knows only the frame vocabulary (channel.ts) — no protocol, no\n// transport, no spawner. The spawner has already done the $proto handshake.\n\nimport type { ActorDefinition, ReflectionOptions } from \"../actor-types.js\";\nimport type { Message } from \"../types.js\";\nimport { isProcess } from \"../process.async.js\";\nimport type { Channel } from \"./channel.js\";\nimport {\n ProcessTable,\n SERVED_ROOT_NAME,\n isRemoteProcess,\n type ProcessHandle,\n type ProcessRef,\n} from \"./process-ref.js\";\nimport { RemoteProcess, type FrameSink } from \"./remote-process.js\";\nimport { ProcessStreams } from \"./process-streams.js\";\nimport { makeSender } from \"./sender.js\";\nimport {\n REFLECT_METHODS,\n asReflectionCall,\n badReason,\n decodeFrame,\n encodeFrame,\n errorFrame,\n errorReason,\n frameTo,\n isExit,\n isInit,\n isMsg,\n isPause,\n isRelease,\n isResume,\n isState,\n isStop,\n isTune,\n isReflectionMethods,\n tuneFrame,\n} from \"./channel.js\";\nimport { CallSide, answerCall } from \"./call-side.js\";\n\nexport type Spawner = () => Promise<Channel>;\n\n/** The name the served actor is spawned under, and the one it answers to as a sender when\n * it talks to a process of the far side's: what the client states in `$init`, since the\n * process being served is the one its proxy was forked as over there. The fallback is for\n * a connection that states none — an older client, or a hand-written `$init` — where the\n * far side's name for its own end is all there is to go on. */\nlet rootName: string = SERVED_ROOT_NAME;\n\nexport async function serveRemoteActor<\n Args,\n State,\n InMsg extends Message,\n OutMsg extends Message,\n R extends ReflectionOptions,\n>(actor: ActorDefinition<Args, State, InMsg, OutMsg, R>, spawner: Spawner): Promise<void> {\n const channel = await spawner();\n\n // The table takes the even ids: the odd ones are the far side's, so the same\n // number can never name a process on both ends at once. A process that is\n // numbered here is one that is about to cross, and its stream follows the frame\n // that carried it.\n const table = new ProcessTable<ProcessHandle>(\"even\", (proc, id) => streams.crossed(proc, id));\n\n /** Put an encoded frame on the wire, and then say what it numbered. A frame that\n * carried a reference has to be out before anything about that process is. */\n const write = async (frame: Record<string, unknown>): Promise<void> => {\n await channel.send(frame);\n streams.flush();\n };\n\n const sendToFrame = (frame: Record<string, unknown>, to: number): Promise<void> =>\n write(encodeFrame(frame, table, to));\n\n /** Every frame leaves this way. The answer is handed back, since the one frame that\n * has to be out before the wire closes is awaited by the side that owns the wire. */\n const sendTo: FrameSink = (frame, to) =>\n sendToFrame(frame, to).catch((e: unknown) => {\n console.error(\"Error sending out the frame\", e);\n });\n\n // Everything is in place to speak: the sink writes to the wire, and what the\n // table numbers crosses through it.\n const streams = new ProcessStreams(sendTo, table.rootId());\n\n // Both ends of a connection make calls and answer them: a process the far side\n // holds is asked the same way this side is asked.\n const calls = new CallSide(write, table);\n\n /** The handle for a reference that arrived: the same one every time, and the process\n * itself when the reference names a process of this side's own. The roots are\n * numbered apart, so a reference to the far side's root is a reference to a process\n * of theirs, and a handle like any of those. */\n const handleFor = (ref: ProcessRef): ProcessHandle => {\n const held = table.processFor(ref.id);\n if (held) return held;\n const known = table.farHandleFor(ref.id);\n if (isRemoteProcess(known)) return known;\n const handle = new RemoteProcess(ref, sendTo, rootName, (id) => table.release(id));\n table.bindFar(ref.id, handle);\n return handle;\n };\n\n // await $init, keeping everything that arrives with it. The channel has one handler\n // slot, and a frame that arrives while the actor is still starting has nothing to be\n // dispatched to yet, so the frames wait here and are replayed below. The $init is the\n // first of them, that being what the connection is made by.\n const waiting: Record<string, unknown>[] = [];\n await new Promise<void>((resolve) => {\n channel.onMessage((frame) => {\n waiting.push(frame);\n resolve();\n });\n });\n channel.removeHandler();\n const firstFrame = waiting.shift() as Record<string, unknown>;\n // A first frame that could not be read is a failed start like any other: the far side is told\n // what could not be read, and this connection is refused to its caller — the spawner that opened\n // it — rather than raised into the host. Nothing is served yet, so nothing is stopped here.\n const initProblem = badReason(firstFrame) ?? errorReason(firstFrame);\n if (initProblem !== null) {\n await write(errorFrame(`expected $init: ${initProblem}`)).catch(() => undefined);\n throw new Error(`serveRemoteActor: expected $init (${initProblem})`);\n }\n const initFrame = decodeFrame(firstFrame, handleFor);\n if (!isInit(initFrame)) {\n throw new Error(\"serveRemoteActor: expected $init\");\n }\n\n const init = initFrame.$init;\n const stated = init.rootName;\n if (typeof stated === \"string\" && stated !== \"\") rootName = stated;\n const parentName = (init.parentName as string) ?? null;\n const parentIdName = (init.parentIdName as string) ?? null;\n const parentId = parentIdName ? Symbol.for(parentIdName) : null;\n const { parentName: _pn, parentIdName: _pid, ...initArgs } = init;\n\n const proc = await actor.spawn(initArgs as unknown as Args, {\n name: rootName,\n parentName,\n parentId,\n });\n\n // This side's own end of the connection is the process it just spawned: id 0\n // here, and on the other side the proxy that asked for it.\n table.bindRoot(proc);\n\n await proc.ready();\n\n // The root is a process that crossed this connection like any other, at the id this\n // side gave it. What it can be asked is announced, and what it holds and what it\n // says are said once the far side asks: the announced list is the whole surface, so a\n // name that was never on it can never be reached. A proxy on the other end asks for\n // the state and the messages it stands in for the moment it connects.\n streams.crossed(proc, table.rootId());\n streams.flush();\n\n // A wire that goes takes the reason to be served with it: nobody is left to answer, so the actor\n // is stopped — children and all, the way any other stop works. Left alone it outlives every\n // client that ever dropped, and the teardown below, which waits for exactly this end, never runs.\n channel.onClose(() => {\n void proc.stop();\n });\n\n /**\n * A frame that was not a frame is the connection's problem and not the process's: the far side is\n * told what could not be read, and then this connection ends — the actor it was serving ends with\n * it, that being what it was spawned for. The host everything else runs in is never the cost of\n * one peer that is not speaking the protocol.\n *\n * The write is awaited only so the reason is out before the wire closes. A wire that has already\n * gone ends nothing twice, and the ending is the part that matters.\n */\n const endUnreadable = async (reason: string): Promise<void> => {\n console.warn(`a frame from the far side could not be read: ${reason}`);\n try {\n await write(errorFrame(reason));\n } catch {\n // The wire went before the reason could; the ending below is the same either way.\n }\n await proc.stop();\n };\n\n // bridge channel input → actor\n function dispatch(raw: Record<string, unknown>): void {\n // A frame about the wire is settled before anything else is looked up: what a codec could not\n // read, and a far side saying the connection is over, are one piece of news here — this\n // connection cannot be spoken over any more, and nothing said after it could be trusted. The\n // connection ends; the process does not.\n const wireProblem = badReason(raw) ?? errorReason(raw);\n if (wireProblem !== null) {\n void endUnreadable(wireProblem);\n return;\n }\n const frame = decodeFrame(raw, handleFor);\n // An answer is about the call waiting for it and not about a process: it names\n // the seq, and is settled before anything is looked up.\n if (calls.settle(frame)) return;\n const to = frameTo(frame);\n if (to === null) return;\n // A frame answers one of two questions. News about a process the far side holds\n // lands on the handle for it: what it holds, that it is over, what it can answer.\n // An ask of a process this side holds goes to wherever that process lives: a\n // message, control, a call, a tune.\n const news = table.farHandleFor(to);\n const mine = table.processFor(to);\n if (isRelease(frame)) {\n // A process of this side's own, let go of over there: nothing more is said about\n // it, and the id the far side knew it by is no longer this connection's. The\n // process itself runs on, and a later crossing numbers it afresh. Neither root is\n // let go of, so the table refuses both.\n if (mine !== undefined) {\n streams.stop(to);\n table.release(to);\n }\n return;\n }\n if (isTune(frame)) {\n // How much the far side is told about a process of this side's own is that\n // side's to ask, and this is where the asking lands: what it names is what\n // crosses from now on. An id this side does not hold has nothing to tune.\n if (mine !== undefined) {\n const kinds = tuneFrame(frame);\n if (kinds !== null) streams.tune(to, kinds);\n }\n return;\n }\n if (isReflectionMethods(frame)) {\n // What a process the far side holds can answer, said the moment it crossed:\n // the handle here reads it as its own surface, so a name asked on it is asked\n // there. What a process of this side's own can answer is this side's to\n // announce, not the far side's to tell it.\n if (isRemoteProcess(news)) {\n news.receiveMethods(frame[REFLECT_METHODS], (method, args) => calls.call(method, args, to));\n }\n return;\n }\n if (isState(frame)) {\n // A process the far side holds, saying what it holds: that is news for the\n // handle on it, and lands where a subscription can see it. A state frame about\n // a process of this side's own is this side's to publish, not the far side's to\n // tell it.\n if (isRemoteProcess(news)) news.receiveState(frame.$state);\n return;\n }\n if (isExit(frame)) {\n // A process the far side holds, gone. Nothing more will be said about it, so\n // this is the last thing a handle can be told.\n if (isRemoteProcess(news)) news.receiveExit(frame.$exit);\n return;\n }\n if (isStop(frame) || isPause(frame) || isResume(frame)) {\n // Control, addressed to the process it is about: acted on by whoever holds that\n // process, which is this side. The root is one of those — stopping it stops\n // what the connection is for — and a handle has nothing here to act on.\n if (isProcess(mine)) {\n const sender = makeSender(rootName, parentName, parentId);\n if (isStop(frame)) void mine.stop({ from: sender });\n else if (isPause(frame)) mine.pause();\n else mine.resume();\n }\n return;\n }\n if (isMsg(frame)) {\n const { fromName, body } = frame.$msg;\n // A message for a process this side holds goes into it, the root included. One\n // about a process the far side holds — a handle here — is that process talking,\n // and goes to whoever subscribed to the handle.\n if (isProcess(mine)) mine.send(body as InMsg, makeSender(fromName, parentName, parentId));\n else if (isRemoteProcess(news)) news.receiveMessage(body as OutMsg, fromName);\n return;\n }\n const call = asReflectionCall(frame);\n if (call) void answerCall(call, mine, write, table);\n }\n\n channel.removeHandler();\n channel.onMessage(dispatch);\n for (const frame of waiting.splice(0)) dispatch(frame);\n\n // await actor exit, announce it, close\n let code = 0;\n try {\n await proc.wait();\n } catch (err) {\n console.error(\"server actor error:\", err);\n code = 1;\n }\n // The root is over, which is the last thing said about it. It is said and awaited\n // here, because the wire closes right after it.\n await streams.sayEnded(table.rootId(), code);\n // And nothing more about anything else of this side's: there is no one left to say\n // it to.\n streams.stopAll();\n // A call this side made and the far side has not answered is not going to be\n // answered now; it fails here rather than hanging.\n calls.rejectAll();\n await channel.close();\n}\n","// ── Client side of the seam ────────────────────────────────────────────────\n//\n// remoteClient builds a posipaki actor that talks to a remote server through a\n// frame Channel produced by a spawner. It knows only the frame vocabulary\n// (channel.ts) — no protocol, no transport, no spawner. The spawner has\n// already done the $proto handshake.\n\nimport { defineActor } from \"../define-actor.js\";\nimport { isProcess } from \"../process.async.js\";\nimport { stopPropagation } from \"../hooks.js\";\nimport type { HookResult } from \"../hooks.js\";\nimport type { ActorDefinition, HandlerOptions, MethodOptions, ReflectionOptions } from \"../actor-types.js\";\nimport type { Message } from \"../types.js\";\nimport type { Channel } from \"./channel.js\";\nimport {\n ProcessTable,\n isRemoteProcess,\n type ProcessHandle,\n type ProcessRef,\n} from \"./process-ref.js\";\nimport { ProcessStreams } from \"./process-streams.js\";\nimport { RemoteProcess, type FrameSink } from \"./remote-process.js\";\nimport { makeSender } from \"./sender.js\";\nimport {\n REFLECT_METHODS,\n asReflectionCall,\n badReason,\n decodeFrame,\n encodeFrame,\n errorReason,\n frameTo,\n isExit,\n isMsg,\n isPause,\n isRelease,\n isResume,\n isStop,\n isReflectionMethods,\n isState,\n isTune,\n tuneFrame,\n} from \"./channel.js\";\nimport { CallSide, answerCall } from \"./call-side.js\";\n\nexport type ClientSpawner<Args> = (args: Args) => Promise<Channel>;\n\n\n/**\n * Why a proxy ends when the wire under it goes.\n *\n * The far side is *unreachable*, which is not the same as ended: the handles that came across are\n * still here and still readable, and what the far process left behind is still what it left behind.\n * But nothing it says can arrive and nothing here can reach it, and that is news of its own — so the\n * proxy ends with this reason rather than sitting there silent. Whoever forked the proxy hears it\n * where it hears everything else about a child, in `onChildExit`.\n */\nexport const CHANNEL_LOST = \"channel-lost\";\n\nexport function remoteClient<\n Args,\n State,\n InMsg extends Message,\n OutMsg extends Message,\n Methods extends MethodOptions = MethodOptions,\n Handlers extends HandlerOptions<InMsg> = HandlerOptions<InMsg>,\n R extends ReflectionOptions = ReflectionOptions,\n>(\n name: string,\n spawner: ClientSpawner<Args>,\n): ActorDefinition<Args, State, InMsg, OutMsg, R> {\n const proxyDef = defineActor<\n Args,\n {\n public: State;\n private: {\n channel: Channel;\n farRoot: RemoteProcess<InMsg, OutMsg>;\n exitPromise: Promise<{ code: number | null; state: State }>;\n };\n },\n InMsg,\n OutMsg,\n Methods,\n Handlers,\n R\n >({\n name,\n handlers: {} as unknown as Handlers,\n async setup(args: Args) {\n // This side's own end of the connection is the root, and id 0 is how both\n // sides name it: the far actor on one end, this proxy on the other. The\n // table takes the odd ids for the processes this side holds — the far side\n // takes the even ones — so an id says on its own which side holds it.\n // A process this side hands over is numbered by the table, and from then on\n // the far side is told what it says: the stream follows the frame that\n // carried the reference.\n const table = new ProcessTable(\"odd\", (proc, id) => streams.crossed(proc, id));\n const root = this.ctx;\n table.bindRoot(root);\n const channel = await spawner(args);\n // What this side calls the process it serves: the full name, not the short one the\n // definition was written with. A process is called here what it is called on the side\n // that forked it, and the far side spells its own subtree off whatever it is told, so a\n // short name would be a second spelling of one process — and the tree would show both.\n const fromName = this.ctx.pname;\n // And the process above it, which is who a message to the served root comes from: the\n // far side is told the same thing a child here is told about its parent.\n const parentName = this.ctx.parentName ?? this.ctx.pname;\n // Everything is in place to speak: the sink writes to the wire, and what the\n // table numbers crosses through it. The sink is reached by a call rather\n // than handed over, because what it does is flush these streams.\n const streams = new ProcessStreams((frame, to) => sendTo(frame, to), table.rootId());\n\n /** Put an encoded frame on the wire, and then say what it numbered. A frame that\n * carried a reference has to be out first, or the far side hears about a process\n * it cannot name yet. */\n const write = (frame: Record<string, unknown>): Promise<void> =>\n Promise.resolve(channel.send(frame)).then(() => streams.flush());\n\n /** Every frame leaves this way: the processes in it become references, and\n * what the frame is addressed to becomes the id the far side knows. */\n const sendTo: FrameSink = (frame, to) => {\n void write(encodeFrame(frame, table, to)).catch((error: unknown) => {\n console.error(\"Error sending out the frame\", error);\n });\n };\n sendTo(\n {\n $init: {\n ...(args as unknown as Record<string, unknown>),\n // Under what name the far side serves is this side's to state: it is serving the\n // process this proxy stands in for, which is the one named here.\n rootName: fromName,\n parentName,\n parentIdName: parentName,\n },\n },\n table.farRootId(),\n );\n\n let currentState: Record<string, unknown> = {};\n\n // ── the call side ──────────────────────────────────────────────────\n // This side both makes calls and answers them, and so does the other end of\n // every connection: what a call is, and how an answer finds the one waiting\n // for it, is written once in call-side.ts.\n const calls = new CallSide(write, table);\n\n /**\n * The handle for a reference that arrived. A process handed over twice is one\n * process, so a reference that names one this side already knows gives back the\n * handle it gave last time, and one that names a process of this side's own —\n * handed back to its owner — gives back that process.\n *\n * The roots are numbered apart, so the numbers say what belongs to whom: 1 is this\n * side's own end, and 0 is the far side's root, which is a handle like any of the\n * processes they hold.\n */\n const handleFor = (ref: ProcessRef): ProcessHandle => {\n const held = table.processFor(ref.id);\n if (held) return held;\n const known = table.farHandleFor(ref.id);\n if (isRemoteProcess(known)) return known;\n const handle = new RemoteProcess(ref, sendTo, fromName, (id) => table.release(id));\n table.bindFar(ref.id, handle);\n return handle;\n };\n\n /**\n * The far side's root, which is what this proxy stands in for. It is bound here\n * like any other reference the far side sends: what it holds, what it says, when\n * it is over and what it can answer reach it as they reach any handle.\n */\n const farRoot = new RemoteProcess<InMsg, OutMsg>(\n { id: table.farRootId(), pname: fromName },\n sendTo,\n fromName,\n (id) => table.release(id),\n );\n table.bindFar(table.farRootId(), farRoot);\n // The proxy is this side's stand-in for that process, so it is the one thing here\n // that keeps it: the state it mirrors and the messages it passes on are heard because\n // this handle is held, and it is let go of when the connection is.\n farRoot.holdRef();\n\n // Setup is done when the far side has said what it holds; until then the\n // one handler below is what takes everything that arrives, so nothing\n // falls between two of them.\n let started: (() => void) | null = null;\n const start = new Promise<void>((resolve) => {\n started = resolve;\n });\n\n // All three in one asking, since this proxy stands in for the far root: what it\n // holds is this proxy's state, what it says is what this proxy says, and its end\n // is the end of the connection. A process says nothing until something asks, and\n // the root is no exception.\n farRoot.tune([\"message\", \"state\", \"exit\"]);\n farRoot.subscribe(\"state\", () => {\n // One object, updated the way the far side publishes it: the proxy's state is\n // the far root's, and a caller here reads it as `proc.state`.\n Object.assign(currentState, farRoot.state ?? {});\n root.notify();\n started?.();\n started = null;\n });\n farRoot.subscribe(\"message\", (msg) => {\n void this.emit(msg as OutMsg);\n });\n const exitPromise: Promise<{ code: number | null; state: State }> = farRoot.wait().then(\n (exit) => ({ code: exit.code, state: exit.state as State }),\n // The wire went before the far root did: what is known here is that it is over,\n // and the state last heard is the last word there is.\n () => ({ code: null, state: currentState as State }),\n );\n\n /**\n * The wire is over, whoever ended it: the far side stopped talking, or stopped making sense.\n * What was in flight fails, handles disconnect, nothing more is said about the processes of\n * this side's own, and the proxy ends with CHANNEL_LOST — a proxy that stayed up would be one\n * whose parent still believes the far side is listening, which is exactly the belief a display\n * panel that went dark punishes.\n *\n * Said once: a wire can go in more than one way at once, and it only goes once.\n */\n let wireEnded = false;\n const wireGone = (): void => {\n if (wireEnded) return;\n wireEnded = true;\n // A call that was in flight when the wire went away has no answer coming; it fails\n // here rather than hanging forever.\n calls.rejectAll();\n // Handles live on this connection: with it gone there is nothing to reach, and\n // nothing to wait for either.\n for (const held of table.handles()) {\n if (isRemoteProcess(held)) held.disconnect();\n }\n // And nothing more is said about the processes of this side's own that were handed\n // over: there is no one left to say it to.\n streams.stopAll();\n this.exit(CHANNEL_LOST);\n };\n\n channel.onMessage((raw) => {\n // A frame about the wire ends the wire: what the far side says it could not read, and what\n // it says when the connection is over, are the same news here. A frame that could not be\n // *read* leaves nothing after it trustworthy — a wire that has lost its framing can still\n // deliver something, and what it delivers is not the far side's meaning — so this is where\n // the connection ends. A frame that reads fine and is not understood is not this, and is\n // answered about itself rather than by breaking the connection.\n const wireProblem = badReason(raw) ?? errorReason(raw);\n if (wireProblem !== null) {\n void channel.close();\n wireGone();\n return;\n }\n const frame = decodeFrame(raw, handleFor);\n // An answer is about the call waiting for it and not about a process: it names\n // the seq, and is settled before anything is looked up.\n if (calls.settle(frame)) return;\n const to = frameTo(frame);\n if (to === null) return;\n // A frame answers one of two questions. News about a process the far side holds\n // lands on the handle for it: what it holds, what it says, that it is over, what\n // it can answer. An ask of a process this side holds goes to wherever that\n // process lives: a message, control, a call, a tune.\n const news = table.farHandleFor(to);\n const mine = table.processFor(to);\n if (isRelease(frame)) {\n // A process of this side's own, let go of over there: nothing more is said\n // about it, and the id is no longer this connection's. The process itself\n // runs on. Neither root is let go of, so the table refuses both.\n if (mine !== undefined) {\n streams.stop(to);\n table.release(to);\n }\n return;\n }\n if (isReflectionMethods(frame)) {\n // What the far side holds can answer, and how this side asks it: what was\n // announced is the whole surface, so a name never announced is never called\n // here either. The far root's names go on this proxy's own surface as well,\n // since the proxy is the process a caller here holds.\n if (isRemoteProcess(news)) {\n news.receiveMethods(frame[REFLECT_METHODS], (method, callArgs) =>\n calls.call(method, callArgs, to),\n );\n if (to === table.farRootId()) {\n calls.install(\n this.reflection as unknown as Record<string, unknown>,\n frame[REFLECT_METHODS],\n table.farRootId(),\n );\n }\n }\n return;\n }\n if (isState(frame)) {\n // A process the far side holds, saying what it holds: news for whoever\n // subscribed to the handle.\n if (isRemoteProcess(news)) news.receiveState(frame.$state);\n return;\n }\n if (isExit(frame)) {\n // A process the far side holds, gone: nothing more will be said about it.\n if (isRemoteProcess(news)) news.receiveExit(frame.$exit);\n return;\n }\n if (isMsg(frame)) {\n // A message naming a process this side holds goes into it, the proxy's own\n // root included, and the wire says who sent it by name alone. One about a\n // process the far side holds is that process talking, and goes to whoever\n // subscribed to the handle.\n if (isProcess(mine)) {\n mine.send(frame.$msg.body as InMsg, makeSender(frame.$msg.fromName, null, null));\n } else if (isRemoteProcess(news)) {\n news.receiveMessage(frame.$msg.body as OutMsg, frame.$msg.fromName);\n }\n return;\n }\n if (isTune(frame)) {\n // How much the far side hears about a process of this side's own is its to\n // ask, and this is where the asking lands.\n if (mine !== undefined) {\n const kinds = tuneFrame(frame);\n if (kinds !== null) streams.tune(to, kinds);\n }\n return;\n }\n if (isStop(frame) || isPause(frame) || isResume(frame)) {\n // Control, addressed to the process it is about, and acted on by whoever holds\n // it, which is this side. Its own root is one of those. A handle has nothing\n // here to act on.\n if (isProcess(mine)) {\n if (isStop(frame)) void mine.stop({ from: makeSender(fromName, null, null) });\n else if (isPause(frame)) mine.pause();\n else mine.resume();\n }\n return;\n }\n // A call into a process of this side's own, made from over there: the method is\n // this side's to run, and the answer goes back by name and seq.\n const call = asReflectionCall(frame);\n if (call) void answerCall(call, mine, write, table);\n });\n // A wire that goes before the far root does leaves nothing to wait for: the handles are gone,\n // and the far root's end is the connection's end, which is what `wait()` on it rejects about.\n channel.onClose(() => wireGone());\n\n await start;\n\n return {\n public: currentState as State,\n private: { channel, farRoot, exitPromise },\n };\n\n },\n async onMessage(msg: InMsg): Promise<HookResult> {\n const { farRoot } = this.state.private;\n // A message this side sends is for the root: that is the process the proxy stands\n // for, and it is sent the way any handle sends to a process of the far side's.\n if (farRoot.isConnected()) farRoot.send(msg);\n return stopPropagation();\n },\n async onStopRequested() {\n const { channel, farRoot, exitPromise } = this.state.private;\n if (channel) {\n // Asking the far root to stop is asking a process, not sending it a message:\n // the control frame its holder acts on, the one every other handle uses. Worth\n // asking only while there is something to ask of it — an end that has come, or\n // a wire that has gone, leaves nothing to ask and nothing to wait for.\n if (farRoot.isConnected() && !farRoot.hasEnded()) {\n void farRoot.stop().catch(() => undefined);\n }\n await exitPromise;\n }\n this.agreeToStop();\n },\n async afterEnd() {\n if (this.state.private.channel) {\n await this.state.private.channel.close();\n }\n },\n });\n\n return proxyDef as unknown as ActorDefinition<Args, State, InMsg, OutMsg, R>;\n}\n","// ── json1 wire protocol ────────────────────────────────────────────────────\n//\n// One JSON object per frame: `{\"$key\": value}`. encode/decode turn a decoded\n// frame object into a string and back. json1Channel wraps a StringTransport so\n// it moves frame objects instead of strings.\n//\n// This is the boundary where the wire's bytes become a frame, and it is the one\n// place a bad peer can throw into a callback that belongs to nobody but the host:\n// the handler runs where the transport called it — a socket's `message` event, a\n// line reader — so a `SyntaxError` here is an uncaught exception and takes the\n// process down. So a line that will not parse is not thrown at the caller: it\n// becomes the frame that says so (`$bad`, channel.ts) and travels inward like any\n// other, where the connection it came from can answer for it.\n//\n// One frame is one JSON *object*: a line that parses to a number, a string, an\n// array or `null` is not a frame either, and reading one as a frame (`\"$init\" in 7`)\n// throws just as surely as a line that never parsed.\n\nimport { badFrame, type Channel, type StringTransport } from \"../channel.js\";\n\nexport const VERSION = \"json.v1\";\n\nexport function encode(frame: Record<string, unknown>): string {\n return JSON.stringify(frame);\n}\n\n/** The frame a line carries, throwing on a line that is not JSON. `readFrame` is how the\n * seam reads a line; this is the primitive underneath it. */\nexport function decode(str: string): Record<string, unknown> {\n return JSON.parse(str);\n}\n\n/** A line read as a frame: the frame itself, or the frame that says this one could not be\n * read. Never throws — see the note at the top of this file. */\nexport function readFrame(str: string): Record<string, unknown> {\n let parsed: unknown;\n try {\n parsed = decode(str);\n } catch (err) {\n return badFrame(err instanceof Error ? err.message : String(err), str);\n }\n if (typeof parsed !== \"object\" || parsed === null || Array.isArray(parsed)) {\n return badFrame(`a frame is one JSON object, and this was ${kindOf(parsed)}`, str);\n }\n return parsed as Record<string, unknown>;\n}\n\nfunction kindOf(value: unknown): string {\n if (value === null) return \"null\";\n if (Array.isArray(value)) return \"an array\";\n return `a ${typeof value}`;\n}\n\nexport function json1Channel(transport: StringTransport): Channel {\n return {\n send(frame) {\n return transport.send(encode(frame));\n },\n onMessage(handler) {\n transport.onMessage((str) => handler(readFrame(str)));\n },\n removeHandler() {\n transport.removeHandler();\n },\n onClose(handler) {\n transport.onClose(handler);\n },\n close() {\n return transport.close();\n },\n };\n}\n"],"mappings":"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"}
|
|
@@ -4,9 +4,15 @@ import { tmpdir } from "node:os";
|
|
|
4
4
|
import { basename, join } from "node:path";
|
|
5
5
|
import { promisify } from "node:util";
|
|
6
6
|
import * as readline from "node:readline";
|
|
7
|
+
//#region src/remote/channel.ts
|
|
8
|
+
const ERROR_KEY = "$error";
|
|
9
|
+
/** The frame that says the wire is over: the reason, and the connection ends with it. */
|
|
10
|
+
function errorFrame$1(reason) {
|
|
11
|
+
return { [ERROR_KEY]: reason };
|
|
12
|
+
}
|
|
13
|
+
//#endregion
|
|
7
14
|
//#region src/remote/stdio.ts
|
|
8
15
|
const OUTPUT_KEY = "$fd";
|
|
9
|
-
const ERROR_KEY = "$error";
|
|
10
16
|
/** Raised when the wire itself fails: no frame, the wrong protocol, a peer that went away. */
|
|
11
17
|
var StdioWireError = class extends Error {
|
|
12
18
|
constructor(message) {
|
|
@@ -20,8 +26,11 @@ function outputFrame(fd, data) {
|
|
|
20
26
|
data
|
|
21
27
|
});
|
|
22
28
|
}
|
|
29
|
+
/** An `$error` frame as a line. The word and its shape are the shared vocabulary's
|
|
30
|
+
* (channel.ts) — one word for a wire that cannot be spoken over, whether the failure was at
|
|
31
|
+
* the start of a session or in the middle of one; what this file owns is its line form. */
|
|
23
32
|
function errorFrame(reason) {
|
|
24
|
-
return JSON.stringify(
|
|
33
|
+
return JSON.stringify(errorFrame$1(reason));
|
|
25
34
|
}
|
|
26
35
|
/** Is this write error just a peer that already left? */
|
|
27
36
|
function peerGone(code) {
|