statewire 0.13.0 → 0.14.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/README.md +2 -0
- package/dist/client/connection.d.ts +5 -2
- package/dist/client/connection.d.ts.map +1 -1
- package/dist/client/connection.js +54 -19
- package/dist/client/connection.js.map +1 -1
- package/dist/client/core.d.ts +2 -2
- package/dist/client/core.d.ts.map +1 -1
- package/dist/client/core.js +5 -4
- package/dist/client/core.js.map +1 -1
- package/dist/client/session.d.ts.map +1 -1
- package/dist/client/session.js +6 -2
- package/dist/client/session.js.map +1 -1
- package/dist/host/http.d.ts +2 -1
- package/dist/host/http.d.ts.map +1 -1
- package/dist/host/http.js +36 -3
- package/dist/host/http.js.map +1 -1
- package/dist/host/socket.d.ts +11 -2
- package/dist/host/socket.d.ts.map +1 -1
- package/dist/host/socket.js +135 -6
- package/dist/host/socket.js.map +1 -1
- package/dist/host-internal.d.ts +9 -1
- package/dist/host-internal.d.ts.map +1 -1
- package/dist/statewire.d.ts +16 -11
- package/dist/statewire.d.ts.map +1 -1
- package/dist/statewire.js +2 -2
- package/dist/statewire.js.map +1 -1
- package/dist/transports/sse.d.ts +2 -0
- package/dist/transports/sse.d.ts.map +1 -1
- package/dist/transports/sse.js +4 -0
- package/dist/transports/sse.js.map +1 -1
- package/dist/transports/ws.d.ts.map +1 -1
- package/dist/transports/ws.js +4 -0
- package/dist/transports/ws.js.map +1 -1
- package/package.json +1 -1
- package/src/client/connection.ts +67 -20
- package/src/client/core.ts +4 -3
- package/src/client/session.ts +10 -2
- package/src/host/http.ts +40 -2
- package/src/host/socket.ts +220 -6
- package/src/host-internal.ts +14 -1
- package/src/statewire.ts +23 -10
- package/src/transports/sse.ts +6 -0
- package/src/transports/ws.ts +4 -0
package/dist/host/socket.js
CHANGED
|
@@ -407,6 +407,128 @@ const message = (h, conn, data) => {
|
|
|
407
407
|
const admission = admitFrame(h, rec, frame);
|
|
408
408
|
if (admission.type === "refused") sendTo(h, conn, JSON.stringify(admission.syn));
|
|
409
409
|
};
|
|
410
|
+
const closePending = (h, pending, code, reason) => {
|
|
411
|
+
if (!pending.open) return;
|
|
412
|
+
pending.open = false;
|
|
413
|
+
h.pendingConns.delete(pending);
|
|
414
|
+
if (pending.timer !== null) clearTimeout(pending.timer);
|
|
415
|
+
try {
|
|
416
|
+
pending.socket.close(code, reason);
|
|
417
|
+
} catch {}
|
|
418
|
+
};
|
|
419
|
+
const sendPending = (pending, data) => {
|
|
420
|
+
if (!pending.open) return false;
|
|
421
|
+
try {
|
|
422
|
+
pending.socket.send(data);
|
|
423
|
+
return true;
|
|
424
|
+
} catch {
|
|
425
|
+
return false;
|
|
426
|
+
}
|
|
427
|
+
};
|
|
428
|
+
const rejectPendingAuthorization = (h, pending, error) => {
|
|
429
|
+
const response = error instanceof Response ? error : null;
|
|
430
|
+
const unauthorized = response?.status === 401 || response?.status === 403;
|
|
431
|
+
const status = response?.status;
|
|
432
|
+
const message = unauthorized ? "unauthorized" : response?.statusText || (status === void 0 ? "authorization failed" : `HTTP ${status}`);
|
|
433
|
+
sendPending(pending, JSON.stringify({ fin: {
|
|
434
|
+
reason: unauthorized ? "unauthorized" : "error",
|
|
435
|
+
message,
|
|
436
|
+
...status !== void 0 && { status }
|
|
437
|
+
} }));
|
|
438
|
+
closePending(h, pending, unauthorized ? 1008 : 1011, message);
|
|
439
|
+
};
|
|
440
|
+
const normalizedHeaders = (headers) => Object.fromEntries(new Headers(headers));
|
|
441
|
+
const connectAuthorized = (h, clientId, socket, options) => {
|
|
442
|
+
const authorize = h.authorize;
|
|
443
|
+
if (authorize === void 0 || options.authorized === true) return register(h, clientId, socket, options.authorized === true)?.connection ?? null;
|
|
444
|
+
const refuse = (code, reason) => {
|
|
445
|
+
try {
|
|
446
|
+
socket.close(code, reason);
|
|
447
|
+
} catch {}
|
|
448
|
+
return null;
|
|
449
|
+
};
|
|
450
|
+
if (h.disposed) return refuse(1001, "disposed");
|
|
451
|
+
if (!CLIENT_ID_RE.test(clientId)) return refuse(1008, "invalid client id");
|
|
452
|
+
flush(h);
|
|
453
|
+
if (h.finished !== null) {
|
|
454
|
+
try {
|
|
455
|
+
socket.send(JSON.stringify({ fin: h.finished }));
|
|
456
|
+
} catch {}
|
|
457
|
+
return refuse(1e3, "finished");
|
|
458
|
+
}
|
|
459
|
+
const pending = {
|
|
460
|
+
socket,
|
|
461
|
+
open: true,
|
|
462
|
+
authorizing: false,
|
|
463
|
+
timer: null,
|
|
464
|
+
connection: null
|
|
465
|
+
};
|
|
466
|
+
h.pendingConns.add(pending);
|
|
467
|
+
pending.timer = setTimeout(() => rejectPendingAuthorization(h, pending, new Response(null, { status: 401 })), h.wsInitTimeoutMs);
|
|
468
|
+
pending.timer.unref?.();
|
|
469
|
+
return {
|
|
470
|
+
clientId,
|
|
471
|
+
message: (data) => {
|
|
472
|
+
if (pending.connection !== null) {
|
|
473
|
+
pending.connection.message(data);
|
|
474
|
+
return;
|
|
475
|
+
}
|
|
476
|
+
if (!pending.open || h.disposed || h.finished !== null) return;
|
|
477
|
+
if (pending.authorizing) {
|
|
478
|
+
closePending(h, pending, 1008, "authorization pending");
|
|
479
|
+
return;
|
|
480
|
+
}
|
|
481
|
+
let frame;
|
|
482
|
+
try {
|
|
483
|
+
frame = parseFrame(data, true);
|
|
484
|
+
} catch (error) {
|
|
485
|
+
const reason = violationReason(error);
|
|
486
|
+
if (reason === null) throw error;
|
|
487
|
+
sendPending(pending, JSON.stringify({ fin: {
|
|
488
|
+
reason: "error",
|
|
489
|
+
message: `protocol violation: ${reason}`
|
|
490
|
+
} }));
|
|
491
|
+
closePending(h, pending, 1008, reason);
|
|
492
|
+
return;
|
|
493
|
+
}
|
|
494
|
+
if (frame.headers === null) {
|
|
495
|
+
rejectPendingAuthorization(h, pending, new Response(null, { status: 401 }));
|
|
496
|
+
return;
|
|
497
|
+
}
|
|
498
|
+
let headers;
|
|
499
|
+
try {
|
|
500
|
+
headers = normalizedHeaders(frame.headers);
|
|
501
|
+
} catch {
|
|
502
|
+
sendPending(pending, JSON.stringify({ fin: {
|
|
503
|
+
reason: "error",
|
|
504
|
+
message: "protocol violation: malformed headers"
|
|
505
|
+
} }));
|
|
506
|
+
closePending(h, pending, 1008, "malformed headers");
|
|
507
|
+
return;
|
|
508
|
+
}
|
|
509
|
+
pending.authorizing = true;
|
|
510
|
+
Promise.resolve().then(() => authorize({ headers })).then(() => {
|
|
511
|
+
if (!pending.open || h.disposed || h.finished !== null) return;
|
|
512
|
+
options.onAuthorized?.();
|
|
513
|
+
pending.open = false;
|
|
514
|
+
h.pendingConns.delete(pending);
|
|
515
|
+
if (pending.timer !== null) clearTimeout(pending.timer);
|
|
516
|
+
const registration = register(h, clientId, socket, true);
|
|
517
|
+
if (registration === null) return;
|
|
518
|
+
pending.connection = registration.connection;
|
|
519
|
+
if (frame.ctx.length === 0 && frame.cmd.length === 0) return;
|
|
520
|
+
const admission = admitFrame(h, registration.rec, frame);
|
|
521
|
+
if (admission.type === "refused") sendTo(h, registration.conn, JSON.stringify(admission.syn));
|
|
522
|
+
}).catch((error) => {
|
|
523
|
+
if (pending.open) rejectPendingAuthorization(h, pending, error);
|
|
524
|
+
});
|
|
525
|
+
},
|
|
526
|
+
close: () => {
|
|
527
|
+
if (pending.connection !== null) pending.connection.close();
|
|
528
|
+
else closePending(h, pending);
|
|
529
|
+
}
|
|
530
|
+
};
|
|
531
|
+
};
|
|
410
532
|
const gcClients = (h) => {
|
|
411
533
|
let excess = h.clients.size - h.clientRecordLimit;
|
|
412
534
|
if (excess <= 0) return;
|
|
@@ -419,7 +541,7 @@ const gcClients = (h) => {
|
|
|
419
541
|
excess -= 1;
|
|
420
542
|
}
|
|
421
543
|
};
|
|
422
|
-
const register = (h, clientId, socket) => {
|
|
544
|
+
const register = (h, clientId, socket, sawFrame = false) => {
|
|
423
545
|
const refuse = (code, reason) => {
|
|
424
546
|
try {
|
|
425
547
|
socket.close(code, reason);
|
|
@@ -454,7 +576,7 @@ const register = (h, clientId, socket) => {
|
|
|
454
576
|
clientId,
|
|
455
577
|
socket,
|
|
456
578
|
open: true,
|
|
457
|
-
sawFrame
|
|
579
|
+
sawFrame,
|
|
458
580
|
lastSentAt: 0,
|
|
459
581
|
lease: null
|
|
460
582
|
};
|
|
@@ -486,12 +608,16 @@ const register = (h, clientId, socket) => {
|
|
|
486
608
|
}
|
|
487
609
|
};
|
|
488
610
|
};
|
|
489
|
-
const connect = (h, clientId, socket) => {
|
|
490
|
-
return
|
|
611
|
+
const connect = (h, clientId, socket, options = {}) => {
|
|
612
|
+
return connectAuthorized(h, clientId, socket, options);
|
|
491
613
|
};
|
|
492
614
|
const finish = (h, fin) => {
|
|
493
615
|
if (h.finished !== null || h.disposed) return;
|
|
494
616
|
h.finished = fin;
|
|
617
|
+
for (const pending of [...h.pendingConns]) {
|
|
618
|
+
sendPending(pending, JSON.stringify({ fin }));
|
|
619
|
+
closePending(h, pending, 1e3, fin.reason);
|
|
620
|
+
}
|
|
495
621
|
flush(h, fin);
|
|
496
622
|
};
|
|
497
623
|
const resume = (h) => {
|
|
@@ -510,11 +636,13 @@ const useSocketHost = (transport, options) => {
|
|
|
510
636
|
const [h] = useState(() => {
|
|
511
637
|
const host = {
|
|
512
638
|
heartbeatMs: 15e3,
|
|
639
|
+
wsInitTimeoutMs: 5e3,
|
|
513
640
|
clientRecordLimit: CLIENT_RECORD_LIMIT,
|
|
514
641
|
finOnIdle: false,
|
|
515
642
|
authorize: void 0,
|
|
516
643
|
clients: /* @__PURE__ */ new Map(),
|
|
517
644
|
conns: /* @__PURE__ */ new Set(),
|
|
645
|
+
pendingConns: /* @__PURE__ */ new Set(),
|
|
518
646
|
pendingOps: [],
|
|
519
647
|
pendingApplied: /* @__PURE__ */ new Map(),
|
|
520
648
|
pendingCmds: /* @__PURE__ */ new Map(),
|
|
@@ -530,7 +658,7 @@ const useSocketHost = (transport, options) => {
|
|
|
530
658
|
host.flushScheduled = false;
|
|
531
659
|
flush(host);
|
|
532
660
|
}),
|
|
533
|
-
connect: (clientId, socket) => connect(host, clientId, socket),
|
|
661
|
+
connect: (clientId, socket, connectOptions) => connect(host, clientId, socket, connectOptions),
|
|
534
662
|
finish: (fin) => finish(host, fin),
|
|
535
663
|
stream: (request) => stream(host, request),
|
|
536
664
|
frames: (request_0) => frames(host, request_0)
|
|
@@ -538,6 +666,7 @@ const useSocketHost = (transport, options) => {
|
|
|
538
666
|
return host;
|
|
539
667
|
});
|
|
540
668
|
setHeartbeatMs(h, options?.heartbeatIntervalMs ?? 15e3);
|
|
669
|
+
h.wsInitTimeoutMs = options?.wsInitTimeoutMs ?? 5e3;
|
|
541
670
|
h.clientRecordLimit = options?.clientRecordLimit ?? CLIENT_RECORD_LIMIT;
|
|
542
671
|
h.finOnIdle = options?.finOnIdle ?? false;
|
|
543
672
|
h.authorize = options?.authorize;
|
|
@@ -567,7 +696,7 @@ const StatewireSocketHost = (transport, options) => {
|
|
|
567
696
|
const root = createTapRoot(SocketHostRoot);
|
|
568
697
|
let disposed = false;
|
|
569
698
|
return {
|
|
570
|
-
connect: (clientId, socket) => flushTapSync(() => root.getValue().connect(clientId, socket)),
|
|
699
|
+
connect: (clientId, socket, connectOptions) => flushTapSync(() => root.getValue().connect(clientId, socket, connectOptions)),
|
|
571
700
|
stream: (request) => flushTapSync(() => root.getValue().stream(request)),
|
|
572
701
|
frames: (request) => flushTapSync(() => root.getValue().frames(request)),
|
|
573
702
|
finish: (fin) => flushTapSync(() => root.getValue().finish(fin)),
|
package/dist/host/socket.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"socket.js","names":["useEffect","useState","createTapRoot","flushTapSync","useResource","ResourceElement","getCommandsHost","getStateHost","CommandsHost","CommandsOutcome","StatewireSendError","Statewire","StatewireHost","StatewireHostInternal","encodeValue","reviveValue","createMacrotaskPoster","StatewireMetaEntry","StatewirePath","StatewireCmd","StatewireEnvelope","frames","serveFrames","stream","serveStream","CLIENT_ID_RE","RESULT_TTL_MS","RESULT_LIMIT","CLIENT_RECORD_LIMIT","WireOp","op","path","value","meta","Admission","seq","method","applied","appliedSent","settled","ClientRec","id","lastSeq","ctxSeq","touched","context","Record","results","Map","ts","cmd","inflight","Conn","clientId","socket","Socket","open","sawFrame","lastSentAt","lease","violation","reason","Object","assign","Error","name","violationReason","error","message","CtxStatement","CmdStatement","params","ParsedFrame","headers","ctx","isPlainObject","Array","isArray","parseLane","length","statements","prev","statement","Number","isInteger","push","contextValue","ops","undefined","rejectUnknown","parseFrameValue","frame","first","keys","unknown","filter","key","sort","raw","values","some","parseFrame","JSON","parse","encodePayload","payload","cmdOf","adm","outcome","type","failure","fate","code","String","SocketHostState","heartbeatMs","clientRecordLimit","finOnIdle","authorize","SocketHostOptions","clients","conns","Set","pendingOps","pendingApplied","pendingCmds","idleWire","finished","Fin","disposed","flushScheduled","heartbeatTimer","ReturnType","setInterval","stateHost","StateHost","commandsHost","current","post","connect","SocketConnection","finish","fin","request","Request","Promise","Response","scheduleFlush","h","recordOp","attach","next","nextState","state","nextCommands","commands","submit","setOnOp","closeConn","conn","delete","close","size","clearInterval","sendTo","data","Date","now","send","ensureHeartbeat","unref","setHeartbeatMs","ms","idleLevel","rec","flush","takeChanged","queueApplied","level","edge","cmds","appliedEntries","get","map","packet","idle","stringify","verdicts","list","set","queueCmd","retain","newest","Math","max","entry","min","admittedThrough","reemit","cached","settleCmd","settleWire","callerOf","Caller","isConnected","rejectStatement","admitCmd","names","methods","caller","onApplied","onSettle","catch","FrameAdmission","syn","admitFrame","through","ctxNew","s","cmdNew","at","dur","admission","gcClients","excess","live","oldest","a","b","has","Registration","connection","register","refuse","test","known","created","add","snapshot","hello","registration","resume","suspend","useSocketHost","transport","options","Pick","SocketHost","host","heartbeatIntervalMs","StatewireSocketHost","SocketHostRoot","root","getValue","dispose","unmount"],"sources":["../../src/host/socket.ts"],"sourcesContent":["import { useEffect, useState } from \"react\";\nimport { createTapRoot, flushTapSync, useResource } from \"@assistant-ui/tap\";\nimport type { ResourceElement } from \"@assistant-ui/tap\";\nimport { getCommandsHost, getStateHost } from \"./host\";\nimport type { CommandsHost, CommandsOutcome } from \"./host\";\nimport { StatewireSendError } from \"../types\";\nimport type { Statewire } from \"../types\";\nimport type { StatewireHost } from \"../host\";\nimport type { StatewireHostInternal } from \"../host-internal\";\nimport { encodeValue, reviveValue } from \"../wire/meta\";\nimport { createMacrotaskPoster } from \"../util/macrotask\";\nimport type { StatewireMetaEntry } from \"../wire/meta\";\nimport type { StatewirePath } from \"../wire/ops\";\nimport type { StatewireCmd, StatewireEnvelope } from \"../client/connection\";\nimport { frames as serveFrames, stream as serveStream } from \"./http\";\n\nexport const CLIENT_ID_RE = /^[A-Za-z0-9._~-]{1,256}$/;\nconst RESULT_TTL_MS = 30_000;\nconst RESULT_LIMIT = 256;\nconst CLIENT_RECORD_LIMIT = 1024;\n\ntype WireOp = {\n op: string;\n path?: StatewirePath;\n value?: unknown;\n meta?: StatewireMetaEntry[];\n};\n\ntype Admission = {\n seq: number;\n method: string;\n applied: boolean;\n appliedSent: boolean;\n settled: boolean;\n};\n\nexport type ClientRec = {\n id: string;\n lastSeq: number;\n ctxSeq: number;\n touched: number;\n context: Record<string, unknown> | null;\n results: Map<number, { ts: number; cmd: StatewireCmd }>;\n inflight: Map<number, Admission>;\n};\n\nexport type Conn = {\n clientId: string;\n socket: StatewireHostInternal.Socket;\n open: boolean;\n sawFrame: boolean;\n lastSentAt: number;\n lease: string | null;\n};\n\n// ─── frame parsing ──────────────────────────────────────\n\nconst violation = (reason: string): never => {\n throw Object.assign(new Error(reason), { name: \"StatewireViolation\" });\n};\n\nconst violationReason = (error: unknown): string | null =>\n error instanceof Error && error.name === \"StatewireViolation\"\n ? error.message\n : null;\n\ntype CtxStatement = { seq: number; value: Record<string, unknown> };\ntype CmdStatement = {\n seq: number;\n method: string;\n params: unknown;\n meta?: unknown;\n};\n\nexport type ParsedFrame = {\n headers: Record<string, string> | null;\n ctx: CtxStatement[];\n cmd: CmdStatement[];\n};\n\nconst isPlainObject = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null && !Array.isArray(value);\n\nconst parseLane = (value: unknown): Record<string, unknown>[] => {\n if (!Array.isArray(value)) return violation(\"malformed frame\");\n if (value.length === 0) return violation(\"empty lane\");\n const statements: Record<string, unknown>[] = [];\n let prev: number | null = null;\n for (const statement of value) {\n if (!isPlainObject(statement)) return violation(\"malformed statement\");\n const seq = statement[\"seq\"];\n if (typeof seq !== \"number\" || !Number.isInteger(seq) || seq < 1) {\n return violation(\"malformed statement\");\n }\n if (prev !== null && seq !== prev + 1) return violation(\"malformed frame\");\n prev = seq;\n statements.push(statement);\n }\n return statements;\n};\n\n/** v1 ctx statements state the context whole: one root replace with an object value. */\nconst contextValue = (ops: unknown): Record<string, unknown> => {\n if (!Array.isArray(ops) || ops.length !== 1) {\n throw new Error(\"context must be a single-op array\");\n }\n const op = ops[0] as Record<string, unknown> | null;\n if (\n !isPlainObject(op) ||\n op[\"op\"] !== \"replace\" ||\n !Array.isArray(op[\"path\"]) ||\n op[\"path\"].length !== 0\n ) {\n throw new Error(\"context op must be a root replace\");\n }\n const value =\n op[\"meta\"] !== undefined\n ? reviveValue(op[\"value\"], op[\"meta\"], { rejectUnknown: true })\n : op[\"value\"];\n if (!isPlainObject(value)) {\n throw new Error(\"context value must be an object\");\n }\n return value;\n};\n\nexport const parseFrameValue = (\n frame: unknown,\n first: boolean,\n): ParsedFrame => {\n if (!isPlainObject(frame)) return violation(\"malformed frame\");\n const keys = Object.keys(frame);\n if (keys.length === 0) return violation(\"malformed frame\");\n const unknown = keys\n .filter((key) => key !== \"headers\" && key !== \"ctx\" && key !== \"cmd\")\n .sort();\n if (unknown.length > 0)\n return violation(`unknown frame key: '${unknown[0]}'`);\n let headers: Record<string, string> | null = null;\n if (frame[\"headers\"] !== undefined) {\n if (!first) return violation(\"mid-session headers\");\n const raw = frame[\"headers\"];\n if (\n !isPlainObject(raw) ||\n Object.values(raw).some((value) => typeof value !== \"string\")\n ) {\n return violation(\"malformed headers\");\n }\n headers = raw as Record<string, string>;\n }\n const ctx: CtxStatement[] = [];\n if (frame[\"ctx\"] !== undefined) {\n for (const statement of parseLane(frame[\"ctx\"])) {\n try {\n ctx.push({\n seq: statement[\"seq\"] as number,\n value: contextValue(statement[\"ops\"]),\n });\n } catch {\n return violation(\"invalid-context\");\n }\n }\n }\n const cmd: CmdStatement[] = [];\n if (frame[\"cmd\"] !== undefined) {\n for (const statement of parseLane(frame[\"cmd\"])) {\n const method = statement[\"method\"];\n if (typeof method !== \"string\" || !(\"params\" in statement)) {\n return violation(\"malformed statement\");\n }\n cmd.push({\n seq: statement[\"seq\"] as number,\n method,\n params: statement[\"params\"],\n ...(statement[\"meta\"] !== undefined && { meta: statement[\"meta\"] }),\n });\n }\n }\n return { headers, ctx, cmd };\n};\n\nexport const parseFrame = (raw: string, first: boolean): ParsedFrame => {\n let frame: unknown;\n try {\n frame = JSON.parse(raw);\n } catch {\n return violation(\"malformed frame\");\n }\n return parseFrameValue(frame, first);\n};\n\n// ─── verdict encoding ───────────────────────────────────\n\nconst encodePayload = (\n payload: unknown,\n): { payload?: unknown; meta?: StatewireMetaEntry[] } => {\n if (payload === undefined) return {};\n const { value, meta } = encodeValue(payload);\n return { payload: value, ...(meta !== undefined && { meta }) };\n};\n\nconst cmdOf = (adm: Admission, outcome: CommandsOutcome): StatewireCmd => {\n if (outcome.type === \"accepted\") {\n return { seq: adm.seq, type: \"result\", ...encodePayload(outcome.payload) };\n }\n const failure =\n outcome.error instanceof StatewireSendError ? outcome.error.failure : null;\n switch (failure?.fate) {\n case \"failed\":\n return {\n seq: adm.seq,\n type: \"failed\",\n ...(failure.message !== undefined && { message: failure.message }),\n };\n case \"rejected\": {\n if (failure.code !== undefined) {\n const message =\n failure.code === \"unknown-command\"\n ? `unknown method: '${adm.method}'`\n : failure.message;\n return {\n seq: adm.seq,\n type: \"rejected\",\n code: failure.code,\n ...(message !== undefined && { message }),\n };\n }\n return {\n seq: adm.seq,\n type: \"rejected\",\n ...(failure.message !== undefined && { message: failure.message }),\n ...encodePayload(failure.payload),\n };\n }\n default:\n return {\n seq: adm.seq,\n type: \"failed\",\n message:\n outcome.error instanceof Error\n ? outcome.error.message\n : String(outcome.error),\n };\n }\n};\n\n// ─── host ───────────────────────────────────────────────\n\nexport type SocketHostState = {\n heartbeatMs: number;\n clientRecordLimit: number;\n finOnIdle: boolean;\n authorize: StatewireHostInternal.SocketHostOptions[\"authorize\"];\n clients: Map<string, ClientRec>;\n conns: Set<Conn>;\n pendingOps: WireOp[];\n pendingApplied: Map<string, number[]>;\n pendingCmds: Map<string, StatewireCmd[]>;\n idleWire: boolean;\n finished: StatewireHost.Fin | null;\n disposed: boolean;\n flushScheduled: boolean;\n heartbeatTimer: ReturnType<typeof setInterval> | null;\n stateHost: StatewireHost.StateHost | null;\n commandsHost: CommandsHost | null;\n current: Statewire<unknown> | null;\n post: () => void;\n connect: (\n clientId: string,\n socket: StatewireHostInternal.Socket,\n ) => StatewireHostInternal.SocketConnection | null;\n finish: (fin: StatewireHost.Fin) => void;\n stream: (request: Request) => Promise<Response>;\n frames: (request: Request) => Promise<Response>;\n};\n\nconst scheduleFlush = (h: SocketHostState) => {\n if (h.flushScheduled || h.disposed) return;\n h.flushScheduled = true;\n h.post();\n};\n\nconst recordOp = (\n h: SocketHostState,\n op: {\n op: string;\n path?: StatewirePath;\n value?: unknown;\n },\n) => {\n if (op.op === \"replace\" || op.op === \"add\") {\n const { value, meta } = encodeValue(op.value);\n h.pendingOps.push({ ...op, value, ...(meta !== undefined && { meta }) });\n } else {\n h.pendingOps.push(op);\n }\n scheduleFlush(h);\n};\n\nconst attach = (h: SocketHostState, next: Statewire<unknown>) => {\n if (next === h.current) return;\n h.current = next;\n const nextState =\n typeof next.state === \"object\" && next.state !== null\n ? getStateHost(next.state)\n : undefined;\n const nextCommands = getCommandsHost(next.commands);\n if (!nextState || !nextCommands?.submit) {\n throw new Error(\n \"StatewireSocketHost requires a statewire/host transport (useStatewireState with object state, useStatewireCommands)\",\n );\n }\n if (nextState !== h.stateHost) {\n h.stateHost?.setOnOp(null);\n h.stateHost = nextState;\n h.stateHost.setOnOp((op) => recordOp(h, op));\n }\n h.commandsHost = nextCommands;\n};\n\nexport const closeConn = (\n h: SocketHostState,\n conn: Conn,\n code?: number,\n reason?: string,\n) => {\n if (!conn.open) return;\n conn.open = false;\n h.conns.delete(conn);\n try {\n conn.socket.close(code, reason);\n } catch {\n /* peer already gone */\n }\n if (h.conns.size === 0 && h.heartbeatTimer !== null) {\n clearInterval(h.heartbeatTimer);\n h.heartbeatTimer = null;\n }\n};\n\nexport const sendTo = (h: SocketHostState, conn: Conn, data: string) => {\n if (!conn.open) return;\n conn.lastSentAt = Date.now();\n try {\n conn.socket.send(data);\n } catch {\n closeConn(h, conn);\n }\n};\n\nconst ensureHeartbeat = (h: SocketHostState) => {\n if (h.heartbeatTimer !== null || h.heartbeatMs <= 0) return;\n h.heartbeatTimer = setInterval(() => {\n const now = Date.now();\n for (const conn of [...h.conns]) {\n if (now - conn.lastSentAt >= h.heartbeatMs) sendTo(h, conn, \"{}\");\n }\n }, h.heartbeatMs);\n (h.heartbeatTimer as unknown as { unref?: () => void }).unref?.();\n};\n\nconst setHeartbeatMs = (h: SocketHostState, ms: number) => {\n if (ms === h.heartbeatMs) return;\n h.heartbeatMs = ms;\n if (h.heartbeatTimer !== null) {\n clearInterval(h.heartbeatTimer);\n h.heartbeatTimer = null;\n ensureHeartbeat(h);\n }\n};\n\nconst idleLevel = (h: SocketHostState): boolean => {\n for (const rec of h.clients.values()) {\n if (rec.inflight.size > 0) return false;\n }\n return true;\n};\n\nexport const flush = (h: SocketHostState, fin?: StatewireHost.Fin) => {\n flushTapSync(() => {});\n h.stateHost?.takeChanged();\n for (const rec of h.clients.values()) {\n for (const adm of rec.inflight.values()) {\n if (adm.applied && !adm.settled && !adm.appliedSent) {\n adm.appliedSent = true;\n queueApplied(h, rec.id, adm.seq);\n }\n }\n }\n const level = idleLevel(h);\n const edge = level !== h.idleWire;\n if (\n h.pendingOps.length === 0 &&\n h.pendingApplied.size === 0 &&\n h.pendingCmds.size === 0 &&\n fin === undefined &&\n !edge\n ) {\n return;\n }\n h.idleWire = level;\n if (fin === undefined && edge && level && h.finOnIdle) {\n fin = { reason: \"idle\" };\n }\n const ops = h.pendingOps;\n const applied = h.pendingApplied;\n const cmds = h.pendingCmds;\n h.pendingOps = [];\n h.pendingApplied = new Map();\n h.pendingCmds = new Map();\n // Applied entries anchor to their effects: piggybacked on the ops packet\n // when one is flushing, standalone otherwise. Terminal verdicts ride their\n // own packet.\n for (const conn of [...h.conns]) {\n const appliedEntries: StatewireCmd[] = (\n applied.get(conn.clientId) ?? []\n ).map((seq) => ({ seq, type: \"applied\" }));\n if (ops.length > 0) {\n const packet: StatewireEnvelope = {\n ops,\n ...(appliedEntries.length > 0 && { cmd: appliedEntries }),\n ...(edge && { idle: level }),\n };\n sendTo(h, conn, JSON.stringify(packet));\n } else if (appliedEntries.length > 0) {\n sendTo(h, conn, JSON.stringify({ cmd: appliedEntries }));\n }\n const verdicts = cmds.get(conn.clientId) ?? [];\n if (verdicts.length > 0) {\n sendTo(h, conn, JSON.stringify({ cmd: verdicts }));\n }\n if (edge && ops.length === 0) {\n sendTo(h, conn, JSON.stringify({ idle: level }));\n }\n if (fin !== undefined) {\n sendTo(h, conn, JSON.stringify({ fin }));\n closeConn(h, conn);\n }\n }\n};\n\nconst queueApplied = (h: SocketHostState, clientId: string, seq: number) => {\n const list = h.pendingApplied.get(clientId);\n if (list) list.push(seq);\n else h.pendingApplied.set(clientId, [seq]);\n scheduleFlush(h);\n};\n\nconst queueCmd = (h: SocketHostState, clientId: string, cmd: StatewireCmd) => {\n const list = h.pendingCmds.get(clientId);\n if (list) list.push(cmd);\n else h.pendingCmds.set(clientId, [cmd]);\n scheduleFlush(h);\n};\n\nconst retain = (rec: ClientRec, cmd: StatewireCmd) => {\n const now = Date.now();\n rec.results.set(cmd.seq, { ts: now, cmd });\n const newest = Math.max(...rec.results.keys());\n for (const [seq, entry] of rec.results) {\n if (seq !== newest && now - entry.ts > RESULT_TTL_MS) {\n rec.results.delete(seq);\n }\n }\n while (rec.results.size > RESULT_LIMIT) {\n rec.results.delete(Math.min(...rec.results.keys()));\n }\n};\n\n/** Cmd-lane watermark: the last statement admitted, settled or not. */\nconst admittedThrough = (rec: ClientRec): number =>\n Math.max(rec.lastSeq, ...rec.inflight.keys());\n\n// A re-asked seq never re-runs: the stored verdict re-emits, an applied\n// inflight run re-answers applied; one not yet applied answers nothing (its\n// answers ride the stream when ready), an evicted verdict answers expired.\nconst reemit = (h: SocketHostState, rec: ClientRec, seq: number) => {\n const cached = rec.results.get(seq);\n if (cached) {\n const newest = Math.max(...rec.results.keys());\n if (seq === newest || Date.now() - cached.ts <= RESULT_TTL_MS) {\n queueCmd(h, rec.id, cached.cmd);\n return;\n }\n rec.results.delete(seq);\n }\n const adm = rec.inflight.get(seq);\n if (adm) {\n if (adm.applied) queueApplied(h, rec.id, seq);\n return;\n }\n queueCmd(h, rec.id, { seq, type: \"expired\" });\n};\n\nconst settleCmd = (\n h: SocketHostState,\n rec: ClientRec,\n adm: Admission,\n cmd: StatewireCmd,\n) => {\n if (adm.settled) return;\n adm.settled = true;\n rec.inflight.delete(adm.seq);\n retain(rec, cmd);\n rec.lastSeq = Math.max(rec.lastSeq, adm.seq);\n adm.applied = true;\n queueCmd(h, rec.id, cmd);\n};\n\nconst settleWire = (\n h: SocketHostState,\n rec: ClientRec,\n adm: Admission,\n outcome: CommandsOutcome,\n) => settleCmd(h, rec, adm, cmdOf(adm, outcome));\n\nconst callerOf = (\n h: SocketHostState,\n rec: ClientRec,\n): StatewireHost.Caller => ({\n clientId: rec.id,\n get context() {\n return rec.context;\n },\n get isConnected() {\n if (h.clients.get(rec.id) !== rec) return false;\n for (const conn of h.conns) {\n if (conn.clientId === rec.id && conn.open) return true;\n }\n return false;\n },\n});\n\nconst rejectStatement = (\n h: SocketHostState,\n rec: ClientRec,\n adm: Admission,\n message: string,\n) =>\n settleCmd(h, rec, adm, {\n seq: adm.seq,\n type: \"rejected\",\n code: \"invalid-params\",\n message,\n });\n\nconst admitCmd = (\n h: SocketHostState,\n rec: ClientRec,\n statement: CmdStatement,\n) => {\n const adm: Admission = {\n seq: statement.seq,\n method: statement.method,\n applied: false,\n appliedSent: false,\n settled: false,\n };\n rec.inflight.set(statement.seq, adm);\n if (!Array.isArray(statement.params)) {\n rejectStatement(h, rec, adm, \"params must be an array\");\n return;\n }\n let params = statement.params;\n if (statement.meta !== undefined) {\n try {\n params = reviveValue(params, statement.meta, {\n rejectUnknown: true,\n }) as unknown[];\n } catch (error) {\n rejectStatement(\n h,\n rec,\n adm,\n `invalid params: ${(error as Error).message}`,\n );\n return;\n }\n }\n if (statement.method === \"statewire/commands\") {\n if (params.length > 0) {\n rejectStatement(h, rec, adm, \"statewire/commands takes no params\");\n return;\n }\n const names = [\n ...(h.commandsHost?.methods?.() ?? []),\n \"statewire/commands\",\n ].sort();\n settleCmd(h, rec, adm, { seq: adm.seq, type: \"result\", payload: names });\n return;\n }\n h.commandsHost!.submit!({\n method: statement.method,\n params,\n clientId: rec.id,\n caller: callerOf(h, rec),\n onApplied: () => {\n if (adm.settled || adm.applied) return;\n adm.applied = true;\n rec.lastSeq = Math.max(rec.lastSeq, adm.seq);\n scheduleFlush(h);\n },\n onSettle: (outcome) => settleWire(h, rec, adm, outcome),\n }).catch((error: unknown) => {\n if (!adm.settled) settleWire(h, rec, adm, { type: \"rejected\", error });\n });\n};\n\n// One admission law, both lanes: absorbed statements answer from the record,\n// then the new suffix is admitted whole or the frame is refused whole via a\n// {syn} stating both watermarks, nothing consumed. A gap is never a close.\nexport type FrameAdmission =\n | { type: \"ok\" }\n | { type: \"refused\"; syn: { syn: { seq: number; ctxSeq: number } } };\n\nexport const admitFrame = (\n h: SocketHostState,\n rec: ClientRec,\n frame: ParsedFrame,\n): FrameAdmission => {\n rec.touched = Date.now();\n const through = admittedThrough(rec);\n for (const statement of frame.cmd) {\n if (statement.seq <= through) reemit(h, rec, statement.seq);\n }\n const ctxNew = frame.ctx.filter((s) => s.seq > rec.ctxSeq);\n const cmdNew = frame.cmd.filter((s) => s.seq > through);\n if (\n (ctxNew.length > 0 && ctxNew[0]!.seq !== rec.ctxSeq + 1) ||\n (cmdNew.length > 0 && cmdNew[0]!.seq !== through + 1)\n ) {\n return {\n type: \"refused\",\n syn: { syn: { seq: through, ctxSeq: rec.ctxSeq } },\n };\n }\n for (const statement of ctxNew) {\n rec.context = statement.value;\n rec.ctxSeq = statement.seq;\n }\n for (const statement of cmdNew) admitCmd(h, rec, statement);\n if (cmdNew.length > 0) {\n // Memory host: admitted means retained — dur rides the admitting flush.\n queueCmd(h, rec.id, { seq: cmdNew.at(-1)!.seq, dur: true });\n }\n scheduleFlush(h);\n return { type: \"ok\" };\n};\n\nconst message = (h: SocketHostState, conn: Conn, data: string) => {\n if (!conn.open || h.disposed || h.finished !== null) return;\n const first = !conn.sawFrame;\n conn.sawFrame = true;\n let frame: ParsedFrame;\n try {\n frame = parseFrame(data, first);\n } catch (error) {\n const reason = violationReason(error);\n if (reason === null) throw error;\n closeConn(h, conn, 1008, reason);\n return;\n }\n if (frame.ctx.length === 0 && frame.cmd.length === 0) return;\n const rec = h.clients.get(conn.clientId)!;\n const admission = admitFrame(h, rec, frame);\n if (admission.type === \"refused\") {\n sendTo(h, conn, JSON.stringify(admission.syn));\n }\n};\n\nconst gcClients = (h: SocketHostState) => {\n let excess = h.clients.size - h.clientRecordLimit;\n if (excess <= 0) return;\n const live = new Set([...h.conns].map((conn) => conn.clientId));\n const oldest = [...h.clients.values()].sort((a, b) => a.touched - b.touched);\n for (const rec of oldest) {\n if (excess <= 0) return;\n if (live.has(rec.id) || rec.inflight.size > 0) continue;\n h.clients.delete(rec.id);\n excess -= 1;\n }\n};\n\nexport type Registration = {\n rec: ClientRec;\n conn: Conn;\n connection: StatewireHostInternal.SocketConnection;\n};\n\nexport const register = (\n h: SocketHostState,\n clientId: string,\n socket: StatewireHostInternal.Socket,\n): Registration | null => {\n const refuse = (code: number, reason: string) => {\n try {\n socket.close(code, reason);\n } catch {\n /* peer already gone */\n }\n return null;\n };\n if (h.disposed) return refuse(1001, \"disposed\");\n if (!CLIENT_ID_RE.test(clientId)) return refuse(1008, \"invalid client id\");\n flush(h);\n if (h.finished !== null) {\n try {\n socket.send(JSON.stringify({ fin: h.finished }));\n } catch {\n /* peer already gone */\n }\n refuse(1000, \"finished\");\n return null;\n }\n const known = h.clients.has(clientId);\n const rec = known\n ? h.clients.get(clientId)!\n : (() => {\n const created: ClientRec = {\n id: clientId,\n lastSeq: 0,\n ctxSeq: 0,\n touched: Date.now(),\n context: null,\n results: new Map(),\n inflight: new Map(),\n };\n h.clients.set(clientId, created);\n return created;\n })();\n rec.touched = Date.now();\n const conn: Conn = {\n clientId,\n socket,\n open: true,\n sawFrame: false,\n lastSentAt: 0,\n lease: null,\n };\n h.conns.add(conn);\n gcClients(h);\n ensureHeartbeat(h);\n const { value, meta } = encodeValue(h.stateHost!.snapshot());\n const hello: StatewireEnvelope = {\n ops: [\n {\n op: \"replace\",\n path: [],\n value,\n ...(meta !== undefined && { meta }),\n },\n ],\n syn: {\n seq: admittedThrough(rec),\n ctxSeq: rec.ctxSeq,\n ...(h.idleWire && { idle: true }),\n },\n };\n sendTo(h, conn, JSON.stringify(hello));\n const connection: StatewireHostInternal.SocketConnection = {\n clientId,\n message: (data) => message(h, conn, data),\n close: () => closeConn(h, conn),\n };\n return { rec, conn, connection };\n};\n\nconst connect = (\n h: SocketHostState,\n clientId: string,\n socket: StatewireHostInternal.Socket,\n): StatewireHostInternal.SocketConnection | null => {\n const registration = register(h, clientId, socket);\n return registration?.connection ?? null;\n};\n\nconst finish = (h: SocketHostState, fin: StatewireHost.Fin) => {\n if (h.finished !== null || h.disposed) return;\n h.finished = fin;\n flush(h, fin);\n};\n\nconst resume = (h: SocketHostState) => {\n h.disposed = false;\n h.stateHost?.setOnOp((op) => recordOp(h, op));\n};\n\nconst suspend = (h: SocketHostState) => {\n h.disposed = true;\n if (h.heartbeatTimer !== null) {\n clearInterval(h.heartbeatTimer);\n h.heartbeatTimer = null;\n }\n h.stateHost?.setOnOp(null);\n};\n\nconst useSocketHost = (\n transport: ResourceElement<Statewire>,\n options?: StatewireHostInternal.SocketHostOptions,\n): Pick<\n StatewireHostInternal.SocketHost,\n \"connect\" | \"finish\" | \"stream\" | \"frames\"\n> => {\n const [h] = useState((): SocketHostState => {\n const host: SocketHostState = {\n heartbeatMs: 15_000,\n clientRecordLimit: CLIENT_RECORD_LIMIT,\n finOnIdle: false,\n authorize: undefined,\n clients: new Map(),\n conns: new Set(),\n pendingOps: [],\n pendingApplied: new Map(),\n pendingCmds: new Map(),\n idleWire: true,\n finished: null,\n disposed: false,\n flushScheduled: false,\n heartbeatTimer: null,\n stateHost: null,\n commandsHost: null,\n current: null,\n post: createMacrotaskPoster(() => {\n host.flushScheduled = false;\n flush(host);\n }),\n connect: (clientId, socket) => connect(host, clientId, socket),\n finish: (fin) => finish(host, fin),\n stream: (request) => serveStream(host, request),\n frames: (request) => serveFrames(host, request),\n };\n return host;\n });\n setHeartbeatMs(h, options?.heartbeatIntervalMs ?? 15_000);\n h.clientRecordLimit = options?.clientRecordLimit ?? CLIENT_RECORD_LIMIT;\n h.finOnIdle = options?.finOnIdle ?? false;\n h.authorize = options?.authorize;\n const value = useResource(transport) as Statewire<unknown>;\n attach(h, value);\n useEffect(() => {\n attach(h, value);\n });\n useEffect(() => {\n resume(h);\n return () => suspend(h);\n }, [h]);\n return h;\n};\n\n/**\n * Transport-agnostic WS binding over a statewire/host transport:\n * feed it sockets (anything with `send`/`close`) and raw text frames, and it\n * speaks the Statewire packet protocol — snapshot-first hello with `syn`,\n * statement-lane client frames under one admission law, `{cmd}` answer\n * arrays fanned out to every attach of a client id, idle edges, and `fin` on\n * finish.\n */\nexport const StatewireSocketHost = (\n transport: ResourceElement<Statewire>,\n options?: StatewireHostInternal.SocketHostOptions,\n): StatewireHostInternal.SocketHost => {\n const SocketHostRoot = () => useSocketHost(transport, options);\n const root = createTapRoot(SocketHostRoot);\n let disposed = false;\n return {\n connect: (clientId, socket) =>\n flushTapSync(() => root.getValue().connect(clientId, socket)),\n stream: (request) => flushTapSync(() => root.getValue().stream(request)),\n frames: (request) => flushTapSync(() => root.getValue().frames(request)),\n finish: (fin) => flushTapSync(() => root.getValue().finish(fin)),\n dispose: () => {\n if (disposed) return;\n disposed = true;\n flushTapSync(() => root.getValue().finish({ reason: \"evicted\" }));\n root.unmount();\n },\n };\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"socket.js","names":["useEffect","useState","createTapRoot","flushTapSync","useResource","ResourceElement","getCommandsHost","getStateHost","CommandsHost","CommandsOutcome","StatewireSendError","Statewire","StatewireHost","StatewireHostInternal","encodeValue","reviveValue","createMacrotaskPoster","StatewireMetaEntry","StatewirePath","StatewireCmd","StatewireEnvelope","frames","serveFrames","stream","serveStream","CLIENT_ID_RE","RESULT_TTL_MS","RESULT_LIMIT","CLIENT_RECORD_LIMIT","WireOp","op","path","value","meta","Admission","seq","method","applied","appliedSent","settled","ClientRec","id","lastSeq","ctxSeq","touched","context","Record","results","Map","ts","cmd","inflight","Conn","clientId","socket","Socket","open","sawFrame","lastSentAt","lease","PendingConn","authorizing","timer","ReturnType","setTimeout","connection","SocketConnection","violation","reason","Object","assign","Error","name","violationReason","error","message","CtxStatement","CmdStatement","params","ParsedFrame","headers","ctx","isPlainObject","Array","isArray","parseLane","length","statements","prev","statement","Number","isInteger","push","contextValue","ops","undefined","rejectUnknown","parseFrameValue","frame","first","keys","unknown","filter","key","sort","raw","values","some","parseFrame","JSON","parse","encodePayload","payload","cmdOf","adm","outcome","type","failure","fate","code","String","SocketHostState","heartbeatMs","wsInitTimeoutMs","clientRecordLimit","finOnIdle","authorize","SocketHostOptions","clients","conns","Set","pendingConns","pendingOps","pendingApplied","pendingCmds","idleWire","finished","Fin","disposed","flushScheduled","heartbeatTimer","setInterval","stateHost","StateHost","commandsHost","current","post","connect","options","SocketConnectOptions","finish","fin","request","Request","Promise","Response","scheduleFlush","h","recordOp","attach","next","nextState","state","nextCommands","commands","submit","setOnOp","closeConn","conn","delete","close","size","clearInterval","sendTo","data","Date","now","send","ensureHeartbeat","unref","setHeartbeatMs","ms","idleLevel","rec","flush","takeChanged","queueApplied","level","edge","cmds","appliedEntries","get","map","packet","idle","stringify","verdicts","list","set","queueCmd","retain","newest","Math","max","entry","min","admittedThrough","reemit","cached","settleCmd","settleWire","callerOf","Caller","isConnected","rejectStatement","admitCmd","names","methods","caller","onApplied","onSettle","catch","FrameAdmission","syn","admitFrame","through","ctxNew","s","cmdNew","at","dur","admission","closePending","pending","clearTimeout","sendPending","rejectPendingAuthorization","response","unauthorized","status","statusText","normalizedHeaders","fromEntries","Headers","connectAuthorized","authorized","registration","register","refuse","test","add","resolve","then","onAuthorized","gcClients","excess","live","oldest","a","b","has","Registration","known","created","snapshot","hello","resume","suspend","useSocketHost","transport","Pick","SocketHost","host","connectOptions","heartbeatIntervalMs","StatewireSocketHost","SocketHostRoot","root","getValue","dispose","unmount"],"sources":["../../src/host/socket.ts"],"sourcesContent":["import { useEffect, useState } from \"react\";\nimport { createTapRoot, flushTapSync, useResource } from \"@assistant-ui/tap\";\nimport type { ResourceElement } from \"@assistant-ui/tap\";\nimport { getCommandsHost, getStateHost } from \"./host\";\nimport type { CommandsHost, CommandsOutcome } from \"./host\";\nimport { StatewireSendError } from \"../types\";\nimport type { Statewire } from \"../types\";\nimport type { StatewireHost } from \"../host\";\nimport type { StatewireHostInternal } from \"../host-internal\";\nimport { encodeValue, reviveValue } from \"../wire/meta\";\nimport { createMacrotaskPoster } from \"../util/macrotask\";\nimport type { StatewireMetaEntry } from \"../wire/meta\";\nimport type { StatewirePath } from \"../wire/ops\";\nimport type { StatewireCmd, StatewireEnvelope } from \"../client/connection\";\nimport { frames as serveFrames, stream as serveStream } from \"./http\";\n\nexport const CLIENT_ID_RE = /^[A-Za-z0-9._~-]{1,256}$/;\nconst RESULT_TTL_MS = 30_000;\nconst RESULT_LIMIT = 256;\nconst CLIENT_RECORD_LIMIT = 1024;\n\ntype WireOp = {\n op: string;\n path?: StatewirePath;\n value?: unknown;\n meta?: StatewireMetaEntry[];\n};\n\ntype Admission = {\n seq: number;\n method: string;\n applied: boolean;\n appliedSent: boolean;\n settled: boolean;\n};\n\nexport type ClientRec = {\n id: string;\n lastSeq: number;\n ctxSeq: number;\n touched: number;\n context: Record<string, unknown> | null;\n results: Map<number, { ts: number; cmd: StatewireCmd }>;\n inflight: Map<number, Admission>;\n};\n\nexport type Conn = {\n clientId: string;\n socket: StatewireHostInternal.Socket;\n open: boolean;\n sawFrame: boolean;\n lastSentAt: number;\n lease: string | null;\n};\n\ntype PendingConn = {\n socket: StatewireHostInternal.Socket;\n open: boolean;\n authorizing: boolean;\n timer: ReturnType<typeof setTimeout> | null;\n connection: StatewireHostInternal.SocketConnection | null;\n};\n\n// ─── frame parsing ──────────────────────────────────────\n\nconst violation = (reason: string): never => {\n throw Object.assign(new Error(reason), { name: \"StatewireViolation\" });\n};\n\nconst violationReason = (error: unknown): string | null =>\n error instanceof Error && error.name === \"StatewireViolation\"\n ? error.message\n : null;\n\ntype CtxStatement = { seq: number; value: Record<string, unknown> };\ntype CmdStatement = {\n seq: number;\n method: string;\n params: unknown;\n meta?: unknown;\n};\n\nexport type ParsedFrame = {\n headers: Record<string, string> | null;\n ctx: CtxStatement[];\n cmd: CmdStatement[];\n};\n\nconst isPlainObject = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null && !Array.isArray(value);\n\nconst parseLane = (value: unknown): Record<string, unknown>[] => {\n if (!Array.isArray(value)) return violation(\"malformed frame\");\n if (value.length === 0) return violation(\"empty lane\");\n const statements: Record<string, unknown>[] = [];\n let prev: number | null = null;\n for (const statement of value) {\n if (!isPlainObject(statement)) return violation(\"malformed statement\");\n const seq = statement[\"seq\"];\n if (typeof seq !== \"number\" || !Number.isInteger(seq) || seq < 1) {\n return violation(\"malformed statement\");\n }\n if (prev !== null && seq !== prev + 1) return violation(\"malformed frame\");\n prev = seq;\n statements.push(statement);\n }\n return statements;\n};\n\n/** v1 ctx statements state the context whole: one root replace with an object value. */\nconst contextValue = (ops: unknown): Record<string, unknown> => {\n if (!Array.isArray(ops) || ops.length !== 1) {\n throw new Error(\"context must be a single-op array\");\n }\n const op = ops[0] as Record<string, unknown> | null;\n if (\n !isPlainObject(op) ||\n op[\"op\"] !== \"replace\" ||\n !Array.isArray(op[\"path\"]) ||\n op[\"path\"].length !== 0\n ) {\n throw new Error(\"context op must be a root replace\");\n }\n const value =\n op[\"meta\"] !== undefined\n ? reviveValue(op[\"value\"], op[\"meta\"], { rejectUnknown: true })\n : op[\"value\"];\n if (!isPlainObject(value)) {\n throw new Error(\"context value must be an object\");\n }\n return value;\n};\n\nexport const parseFrameValue = (\n frame: unknown,\n first: boolean,\n): ParsedFrame => {\n if (!isPlainObject(frame)) return violation(\"malformed frame\");\n const keys = Object.keys(frame);\n if (keys.length === 0) return violation(\"malformed frame\");\n const unknown = keys\n .filter((key) => key !== \"headers\" && key !== \"ctx\" && key !== \"cmd\")\n .sort();\n if (unknown.length > 0)\n return violation(`unknown frame key: '${unknown[0]}'`);\n let headers: Record<string, string> | null = null;\n if (frame[\"headers\"] !== undefined) {\n if (!first) return violation(\"mid-session headers\");\n const raw = frame[\"headers\"];\n if (\n !isPlainObject(raw) ||\n Object.values(raw).some((value) => typeof value !== \"string\")\n ) {\n return violation(\"malformed headers\");\n }\n headers = raw as Record<string, string>;\n }\n const ctx: CtxStatement[] = [];\n if (frame[\"ctx\"] !== undefined) {\n for (const statement of parseLane(frame[\"ctx\"])) {\n try {\n ctx.push({\n seq: statement[\"seq\"] as number,\n value: contextValue(statement[\"ops\"]),\n });\n } catch {\n return violation(\"invalid-context\");\n }\n }\n }\n const cmd: CmdStatement[] = [];\n if (frame[\"cmd\"] !== undefined) {\n for (const statement of parseLane(frame[\"cmd\"])) {\n const method = statement[\"method\"];\n if (typeof method !== \"string\" || !(\"params\" in statement)) {\n return violation(\"malformed statement\");\n }\n cmd.push({\n seq: statement[\"seq\"] as number,\n method,\n params: statement[\"params\"],\n ...(statement[\"meta\"] !== undefined && { meta: statement[\"meta\"] }),\n });\n }\n }\n return { headers, ctx, cmd };\n};\n\nexport const parseFrame = (raw: string, first: boolean): ParsedFrame => {\n let frame: unknown;\n try {\n frame = JSON.parse(raw);\n } catch {\n return violation(\"malformed frame\");\n }\n return parseFrameValue(frame, first);\n};\n\n// ─── verdict encoding ───────────────────────────────────\n\nconst encodePayload = (\n payload: unknown,\n): { payload?: unknown; meta?: StatewireMetaEntry[] } => {\n if (payload === undefined) return {};\n const { value, meta } = encodeValue(payload);\n return { payload: value, ...(meta !== undefined && { meta }) };\n};\n\nconst cmdOf = (adm: Admission, outcome: CommandsOutcome): StatewireCmd => {\n if (outcome.type === \"accepted\") {\n return { seq: adm.seq, type: \"result\", ...encodePayload(outcome.payload) };\n }\n const failure =\n outcome.error instanceof StatewireSendError ? outcome.error.failure : null;\n switch (failure?.fate) {\n case \"failed\":\n return {\n seq: adm.seq,\n type: \"failed\",\n ...(failure.message !== undefined && { message: failure.message }),\n };\n case \"rejected\": {\n if (failure.code !== undefined) {\n const message =\n failure.code === \"unknown-command\"\n ? `unknown method: '${adm.method}'`\n : failure.message;\n return {\n seq: adm.seq,\n type: \"rejected\",\n code: failure.code,\n ...(message !== undefined && { message }),\n };\n }\n return {\n seq: adm.seq,\n type: \"rejected\",\n ...(failure.message !== undefined && { message: failure.message }),\n ...encodePayload(failure.payload),\n };\n }\n default:\n return {\n seq: adm.seq,\n type: \"failed\",\n message:\n outcome.error instanceof Error\n ? outcome.error.message\n : String(outcome.error),\n };\n }\n};\n\n// ─── host ───────────────────────────────────────────────\n\nexport type SocketHostState = {\n heartbeatMs: number;\n wsInitTimeoutMs: number;\n clientRecordLimit: number;\n finOnIdle: boolean;\n authorize: StatewireHostInternal.SocketHostOptions[\"authorize\"];\n clients: Map<string, ClientRec>;\n conns: Set<Conn>;\n pendingConns: Set<PendingConn>;\n pendingOps: WireOp[];\n pendingApplied: Map<string, number[]>;\n pendingCmds: Map<string, StatewireCmd[]>;\n idleWire: boolean;\n finished: StatewireHost.Fin | null;\n disposed: boolean;\n flushScheduled: boolean;\n heartbeatTimer: ReturnType<typeof setInterval> | null;\n stateHost: StatewireHost.StateHost | null;\n commandsHost: CommandsHost | null;\n current: Statewire<unknown> | null;\n post: () => void;\n connect: (\n clientId: string,\n socket: StatewireHostInternal.Socket,\n options?: StatewireHostInternal.SocketConnectOptions,\n ) => StatewireHostInternal.SocketConnection | null;\n finish: (fin: StatewireHost.Fin) => void;\n stream: (request: Request) => Promise<Response>;\n frames: (request: Request) => Promise<Response>;\n};\n\nconst scheduleFlush = (h: SocketHostState) => {\n if (h.flushScheduled || h.disposed) return;\n h.flushScheduled = true;\n h.post();\n};\n\nconst recordOp = (\n h: SocketHostState,\n op: {\n op: string;\n path?: StatewirePath;\n value?: unknown;\n },\n) => {\n if (op.op === \"replace\" || op.op === \"add\") {\n const { value, meta } = encodeValue(op.value);\n h.pendingOps.push({ ...op, value, ...(meta !== undefined && { meta }) });\n } else {\n h.pendingOps.push(op);\n }\n scheduleFlush(h);\n};\n\nconst attach = (h: SocketHostState, next: Statewire<unknown>) => {\n if (next === h.current) return;\n h.current = next;\n const nextState =\n typeof next.state === \"object\" && next.state !== null\n ? getStateHost(next.state)\n : undefined;\n const nextCommands = getCommandsHost(next.commands);\n if (!nextState || !nextCommands?.submit) {\n throw new Error(\n \"StatewireSocketHost requires a statewire/host transport (useStatewireState with object state, useStatewireCommands)\",\n );\n }\n if (nextState !== h.stateHost) {\n h.stateHost?.setOnOp(null);\n h.stateHost = nextState;\n h.stateHost.setOnOp((op) => recordOp(h, op));\n }\n h.commandsHost = nextCommands;\n};\n\nexport const closeConn = (\n h: SocketHostState,\n conn: Conn,\n code?: number,\n reason?: string,\n) => {\n if (!conn.open) return;\n conn.open = false;\n h.conns.delete(conn);\n try {\n conn.socket.close(code, reason);\n } catch {\n /* peer already gone */\n }\n if (h.conns.size === 0 && h.heartbeatTimer !== null) {\n clearInterval(h.heartbeatTimer);\n h.heartbeatTimer = null;\n }\n};\n\nexport const sendTo = (h: SocketHostState, conn: Conn, data: string) => {\n if (!conn.open) return;\n conn.lastSentAt = Date.now();\n try {\n conn.socket.send(data);\n } catch {\n closeConn(h, conn);\n }\n};\n\nconst ensureHeartbeat = (h: SocketHostState) => {\n if (h.heartbeatTimer !== null || h.heartbeatMs <= 0) return;\n h.heartbeatTimer = setInterval(() => {\n const now = Date.now();\n for (const conn of [...h.conns]) {\n if (now - conn.lastSentAt >= h.heartbeatMs) sendTo(h, conn, \"{}\");\n }\n }, h.heartbeatMs);\n (h.heartbeatTimer as unknown as { unref?: () => void }).unref?.();\n};\n\nconst setHeartbeatMs = (h: SocketHostState, ms: number) => {\n if (ms === h.heartbeatMs) return;\n h.heartbeatMs = ms;\n if (h.heartbeatTimer !== null) {\n clearInterval(h.heartbeatTimer);\n h.heartbeatTimer = null;\n ensureHeartbeat(h);\n }\n};\n\nconst idleLevel = (h: SocketHostState): boolean => {\n for (const rec of h.clients.values()) {\n if (rec.inflight.size > 0) return false;\n }\n return true;\n};\n\nexport const flush = (h: SocketHostState, fin?: StatewireHost.Fin) => {\n flushTapSync(() => {});\n h.stateHost?.takeChanged();\n for (const rec of h.clients.values()) {\n for (const adm of rec.inflight.values()) {\n if (adm.applied && !adm.settled && !adm.appliedSent) {\n adm.appliedSent = true;\n queueApplied(h, rec.id, adm.seq);\n }\n }\n }\n const level = idleLevel(h);\n const edge = level !== h.idleWire;\n if (\n h.pendingOps.length === 0 &&\n h.pendingApplied.size === 0 &&\n h.pendingCmds.size === 0 &&\n fin === undefined &&\n !edge\n ) {\n return;\n }\n h.idleWire = level;\n if (fin === undefined && edge && level && h.finOnIdle) {\n fin = { reason: \"idle\" };\n }\n const ops = h.pendingOps;\n const applied = h.pendingApplied;\n const cmds = h.pendingCmds;\n h.pendingOps = [];\n h.pendingApplied = new Map();\n h.pendingCmds = new Map();\n // Applied entries anchor to their effects: piggybacked on the ops packet\n // when one is flushing, standalone otherwise. Terminal verdicts ride their\n // own packet.\n for (const conn of [...h.conns]) {\n const appliedEntries: StatewireCmd[] = (\n applied.get(conn.clientId) ?? []\n ).map((seq) => ({ seq, type: \"applied\" }));\n if (ops.length > 0) {\n const packet: StatewireEnvelope = {\n ops,\n ...(appliedEntries.length > 0 && { cmd: appliedEntries }),\n ...(edge && { idle: level }),\n };\n sendTo(h, conn, JSON.stringify(packet));\n } else if (appliedEntries.length > 0) {\n sendTo(h, conn, JSON.stringify({ cmd: appliedEntries }));\n }\n const verdicts = cmds.get(conn.clientId) ?? [];\n if (verdicts.length > 0) {\n sendTo(h, conn, JSON.stringify({ cmd: verdicts }));\n }\n if (edge && ops.length === 0) {\n sendTo(h, conn, JSON.stringify({ idle: level }));\n }\n if (fin !== undefined) {\n sendTo(h, conn, JSON.stringify({ fin }));\n closeConn(h, conn);\n }\n }\n};\n\nconst queueApplied = (h: SocketHostState, clientId: string, seq: number) => {\n const list = h.pendingApplied.get(clientId);\n if (list) list.push(seq);\n else h.pendingApplied.set(clientId, [seq]);\n scheduleFlush(h);\n};\n\nconst queueCmd = (h: SocketHostState, clientId: string, cmd: StatewireCmd) => {\n const list = h.pendingCmds.get(clientId);\n if (list) list.push(cmd);\n else h.pendingCmds.set(clientId, [cmd]);\n scheduleFlush(h);\n};\n\nconst retain = (rec: ClientRec, cmd: StatewireCmd) => {\n const now = Date.now();\n rec.results.set(cmd.seq, { ts: now, cmd });\n const newest = Math.max(...rec.results.keys());\n for (const [seq, entry] of rec.results) {\n if (seq !== newest && now - entry.ts > RESULT_TTL_MS) {\n rec.results.delete(seq);\n }\n }\n while (rec.results.size > RESULT_LIMIT) {\n rec.results.delete(Math.min(...rec.results.keys()));\n }\n};\n\n/** Cmd-lane watermark: the last statement admitted, settled or not. */\nconst admittedThrough = (rec: ClientRec): number =>\n Math.max(rec.lastSeq, ...rec.inflight.keys());\n\n// A re-asked seq never re-runs: the stored verdict re-emits, an applied\n// inflight run re-answers applied; one not yet applied answers nothing (its\n// answers ride the stream when ready), an evicted verdict answers expired.\nconst reemit = (h: SocketHostState, rec: ClientRec, seq: number) => {\n const cached = rec.results.get(seq);\n if (cached) {\n const newest = Math.max(...rec.results.keys());\n if (seq === newest || Date.now() - cached.ts <= RESULT_TTL_MS) {\n queueCmd(h, rec.id, cached.cmd);\n return;\n }\n rec.results.delete(seq);\n }\n const adm = rec.inflight.get(seq);\n if (adm) {\n if (adm.applied) queueApplied(h, rec.id, seq);\n return;\n }\n queueCmd(h, rec.id, { seq, type: \"expired\" });\n};\n\nconst settleCmd = (\n h: SocketHostState,\n rec: ClientRec,\n adm: Admission,\n cmd: StatewireCmd,\n) => {\n if (adm.settled) return;\n adm.settled = true;\n rec.inflight.delete(adm.seq);\n retain(rec, cmd);\n rec.lastSeq = Math.max(rec.lastSeq, adm.seq);\n adm.applied = true;\n queueCmd(h, rec.id, cmd);\n};\n\nconst settleWire = (\n h: SocketHostState,\n rec: ClientRec,\n adm: Admission,\n outcome: CommandsOutcome,\n) => settleCmd(h, rec, adm, cmdOf(adm, outcome));\n\nconst callerOf = (\n h: SocketHostState,\n rec: ClientRec,\n): StatewireHost.Caller => ({\n clientId: rec.id,\n get context() {\n return rec.context;\n },\n get isConnected() {\n if (h.clients.get(rec.id) !== rec) return false;\n for (const conn of h.conns) {\n if (conn.clientId === rec.id && conn.open) return true;\n }\n return false;\n },\n});\n\nconst rejectStatement = (\n h: SocketHostState,\n rec: ClientRec,\n adm: Admission,\n message: string,\n) =>\n settleCmd(h, rec, adm, {\n seq: adm.seq,\n type: \"rejected\",\n code: \"invalid-params\",\n message,\n });\n\nconst admitCmd = (\n h: SocketHostState,\n rec: ClientRec,\n statement: CmdStatement,\n) => {\n const adm: Admission = {\n seq: statement.seq,\n method: statement.method,\n applied: false,\n appliedSent: false,\n settled: false,\n };\n rec.inflight.set(statement.seq, adm);\n if (!Array.isArray(statement.params)) {\n rejectStatement(h, rec, adm, \"params must be an array\");\n return;\n }\n let params = statement.params;\n if (statement.meta !== undefined) {\n try {\n params = reviveValue(params, statement.meta, {\n rejectUnknown: true,\n }) as unknown[];\n } catch (error) {\n rejectStatement(\n h,\n rec,\n adm,\n `invalid params: ${(error as Error).message}`,\n );\n return;\n }\n }\n if (statement.method === \"statewire/commands\") {\n if (params.length > 0) {\n rejectStatement(h, rec, adm, \"statewire/commands takes no params\");\n return;\n }\n const names = [\n ...(h.commandsHost?.methods?.() ?? []),\n \"statewire/commands\",\n ].sort();\n settleCmd(h, rec, adm, { seq: adm.seq, type: \"result\", payload: names });\n return;\n }\n h.commandsHost!.submit!({\n method: statement.method,\n params,\n clientId: rec.id,\n caller: callerOf(h, rec),\n onApplied: () => {\n if (adm.settled || adm.applied) return;\n adm.applied = true;\n rec.lastSeq = Math.max(rec.lastSeq, adm.seq);\n scheduleFlush(h);\n },\n onSettle: (outcome) => settleWire(h, rec, adm, outcome),\n }).catch((error: unknown) => {\n if (!adm.settled) settleWire(h, rec, adm, { type: \"rejected\", error });\n });\n};\n\n// One admission law, both lanes: absorbed statements answer from the record,\n// then the new suffix is admitted whole or the frame is refused whole via a\n// {syn} stating both watermarks, nothing consumed. A gap is never a close.\nexport type FrameAdmission =\n | { type: \"ok\" }\n | { type: \"refused\"; syn: { syn: { seq: number; ctxSeq: number } } };\n\nexport const admitFrame = (\n h: SocketHostState,\n rec: ClientRec,\n frame: ParsedFrame,\n): FrameAdmission => {\n rec.touched = Date.now();\n const through = admittedThrough(rec);\n for (const statement of frame.cmd) {\n if (statement.seq <= through) reemit(h, rec, statement.seq);\n }\n const ctxNew = frame.ctx.filter((s) => s.seq > rec.ctxSeq);\n const cmdNew = frame.cmd.filter((s) => s.seq > through);\n if (\n (ctxNew.length > 0 && ctxNew[0]!.seq !== rec.ctxSeq + 1) ||\n (cmdNew.length > 0 && cmdNew[0]!.seq !== through + 1)\n ) {\n return {\n type: \"refused\",\n syn: { syn: { seq: through, ctxSeq: rec.ctxSeq } },\n };\n }\n for (const statement of ctxNew) {\n rec.context = statement.value;\n rec.ctxSeq = statement.seq;\n }\n for (const statement of cmdNew) admitCmd(h, rec, statement);\n if (cmdNew.length > 0) {\n // Memory host: admitted means retained — dur rides the admitting flush.\n queueCmd(h, rec.id, { seq: cmdNew.at(-1)!.seq, dur: true });\n }\n scheduleFlush(h);\n return { type: \"ok\" };\n};\n\nconst message = (h: SocketHostState, conn: Conn, data: string) => {\n if (!conn.open || h.disposed || h.finished !== null) return;\n const first = !conn.sawFrame;\n conn.sawFrame = true;\n let frame: ParsedFrame;\n try {\n frame = parseFrame(data, first);\n } catch (error) {\n const reason = violationReason(error);\n if (reason === null) throw error;\n closeConn(h, conn, 1008, reason);\n return;\n }\n if (frame.ctx.length === 0 && frame.cmd.length === 0) return;\n const rec = h.clients.get(conn.clientId)!;\n const admission = admitFrame(h, rec, frame);\n if (admission.type === \"refused\") {\n sendTo(h, conn, JSON.stringify(admission.syn));\n }\n};\n\nconst closePending = (\n h: SocketHostState,\n pending: PendingConn,\n code?: number,\n reason?: string,\n) => {\n if (!pending.open) return;\n pending.open = false;\n h.pendingConns.delete(pending);\n if (pending.timer !== null) clearTimeout(pending.timer);\n try {\n pending.socket.close(code, reason);\n } catch {\n /* peer already gone */\n }\n};\n\nconst sendPending = (pending: PendingConn, data: string): boolean => {\n if (!pending.open) return false;\n try {\n pending.socket.send(data);\n return true;\n } catch {\n return false;\n }\n};\n\nconst rejectPendingAuthorization = (\n h: SocketHostState,\n pending: PendingConn,\n error: unknown,\n) => {\n const response = error instanceof Response ? error : null;\n const unauthorized = response?.status === 401 || response?.status === 403;\n const status = response?.status;\n const message = unauthorized\n ? \"unauthorized\"\n : response?.statusText ||\n (status === undefined ? \"authorization failed\" : `HTTP ${status}`);\n sendPending(\n pending,\n JSON.stringify({\n fin: {\n reason: unauthorized ? \"unauthorized\" : \"error\",\n message,\n ...(status !== undefined && { status }),\n },\n }),\n );\n closePending(h, pending, unauthorized ? 1008 : 1011, message);\n};\n\nconst normalizedHeaders = (\n headers: Record<string, string>,\n): Record<string, string> => Object.fromEntries(new Headers(headers));\n\nconst connectAuthorized = (\n h: SocketHostState,\n clientId: string,\n socket: StatewireHostInternal.Socket,\n options: StatewireHostInternal.SocketConnectOptions,\n): StatewireHostInternal.SocketConnection | null => {\n const authorize = h.authorize;\n if (authorize === undefined || options.authorized === true) {\n const registration = register(\n h,\n clientId,\n socket,\n options.authorized === true,\n );\n return registration?.connection ?? null;\n }\n const refuse = (code: number, reason: string) => {\n try {\n socket.close(code, reason);\n } catch {\n /* peer already gone */\n }\n return null;\n };\n if (h.disposed) return refuse(1001, \"disposed\");\n if (!CLIENT_ID_RE.test(clientId)) return refuse(1008, \"invalid client id\");\n flush(h);\n if (h.finished !== null) {\n try {\n socket.send(JSON.stringify({ fin: h.finished }));\n } catch {\n /* peer already gone */\n }\n return refuse(1000, \"finished\");\n }\n const pending: PendingConn = {\n socket,\n open: true,\n authorizing: false,\n timer: null,\n connection: null,\n };\n h.pendingConns.add(pending);\n pending.timer = setTimeout(\n () =>\n rejectPendingAuthorization(\n h,\n pending,\n new Response(null, { status: 401 }),\n ),\n h.wsInitTimeoutMs,\n );\n (pending.timer as unknown as { unref?: () => void }).unref?.();\n return {\n clientId,\n message: (data) => {\n if (pending.connection !== null) {\n pending.connection.message(data);\n return;\n }\n if (!pending.open || h.disposed || h.finished !== null) return;\n if (pending.authorizing) {\n closePending(h, pending, 1008, \"authorization pending\");\n return;\n }\n let frame: ParsedFrame;\n try {\n frame = parseFrame(data, true);\n } catch (error) {\n const reason = violationReason(error);\n if (reason === null) throw error;\n sendPending(\n pending,\n JSON.stringify({\n fin: {\n reason: \"error\",\n message: `protocol violation: ${reason}`,\n },\n }),\n );\n closePending(h, pending, 1008, reason);\n return;\n }\n if (frame.headers === null) {\n rejectPendingAuthorization(\n h,\n pending,\n new Response(null, { status: 401 }),\n );\n return;\n }\n let headers: Record<string, string>;\n try {\n headers = normalizedHeaders(frame.headers);\n } catch {\n sendPending(\n pending,\n JSON.stringify({\n fin: {\n reason: \"error\",\n message: \"protocol violation: malformed headers\",\n },\n }),\n );\n closePending(h, pending, 1008, \"malformed headers\");\n return;\n }\n pending.authorizing = true;\n Promise.resolve()\n .then(() => authorize({ headers }))\n .then(() => {\n if (!pending.open || h.disposed || h.finished !== null) return;\n options.onAuthorized?.();\n pending.open = false;\n h.pendingConns.delete(pending);\n if (pending.timer !== null) clearTimeout(pending.timer);\n const registration = register(h, clientId, socket, true);\n if (registration === null) return;\n pending.connection = registration.connection;\n if (frame.ctx.length === 0 && frame.cmd.length === 0) return;\n const admission = admitFrame(h, registration.rec, frame);\n if (admission.type === \"refused\") {\n sendTo(h, registration.conn, JSON.stringify(admission.syn));\n }\n })\n .catch((error: unknown) => {\n if (pending.open) rejectPendingAuthorization(h, pending, error);\n });\n },\n close: () => {\n if (pending.connection !== null) pending.connection.close();\n else closePending(h, pending);\n },\n };\n};\n\nconst gcClients = (h: SocketHostState) => {\n let excess = h.clients.size - h.clientRecordLimit;\n if (excess <= 0) return;\n const live = new Set([...h.conns].map((conn) => conn.clientId));\n const oldest = [...h.clients.values()].sort((a, b) => a.touched - b.touched);\n for (const rec of oldest) {\n if (excess <= 0) return;\n if (live.has(rec.id) || rec.inflight.size > 0) continue;\n h.clients.delete(rec.id);\n excess -= 1;\n }\n};\n\nexport type Registration = {\n rec: ClientRec;\n conn: Conn;\n connection: StatewireHostInternal.SocketConnection;\n};\n\nexport const register = (\n h: SocketHostState,\n clientId: string,\n socket: StatewireHostInternal.Socket,\n sawFrame = false,\n): Registration | null => {\n const refuse = (code: number, reason: string) => {\n try {\n socket.close(code, reason);\n } catch {\n /* peer already gone */\n }\n return null;\n };\n if (h.disposed) return refuse(1001, \"disposed\");\n if (!CLIENT_ID_RE.test(clientId)) return refuse(1008, \"invalid client id\");\n flush(h);\n if (h.finished !== null) {\n try {\n socket.send(JSON.stringify({ fin: h.finished }));\n } catch {\n /* peer already gone */\n }\n refuse(1000, \"finished\");\n return null;\n }\n const known = h.clients.has(clientId);\n const rec = known\n ? h.clients.get(clientId)!\n : (() => {\n const created: ClientRec = {\n id: clientId,\n lastSeq: 0,\n ctxSeq: 0,\n touched: Date.now(),\n context: null,\n results: new Map(),\n inflight: new Map(),\n };\n h.clients.set(clientId, created);\n return created;\n })();\n rec.touched = Date.now();\n const conn: Conn = {\n clientId,\n socket,\n open: true,\n sawFrame,\n lastSentAt: 0,\n lease: null,\n };\n h.conns.add(conn);\n gcClients(h);\n ensureHeartbeat(h);\n const { value, meta } = encodeValue(h.stateHost!.snapshot());\n const hello: StatewireEnvelope = {\n ops: [\n {\n op: \"replace\",\n path: [],\n value,\n ...(meta !== undefined && { meta }),\n },\n ],\n syn: {\n seq: admittedThrough(rec),\n ctxSeq: rec.ctxSeq,\n ...(h.idleWire && { idle: true }),\n },\n };\n sendTo(h, conn, JSON.stringify(hello));\n const connection: StatewireHostInternal.SocketConnection = {\n clientId,\n message: (data) => message(h, conn, data),\n close: () => closeConn(h, conn),\n };\n return { rec, conn, connection };\n};\n\nconst connect = (\n h: SocketHostState,\n clientId: string,\n socket: StatewireHostInternal.Socket,\n options: StatewireHostInternal.SocketConnectOptions = {},\n): StatewireHostInternal.SocketConnection | null => {\n return connectAuthorized(h, clientId, socket, options);\n};\n\nconst finish = (h: SocketHostState, fin: StatewireHost.Fin) => {\n if (h.finished !== null || h.disposed) return;\n h.finished = fin;\n for (const pending of [...h.pendingConns]) {\n sendPending(pending, JSON.stringify({ fin }));\n closePending(h, pending, 1000, fin.reason);\n }\n flush(h, fin);\n};\n\nconst resume = (h: SocketHostState) => {\n h.disposed = false;\n h.stateHost?.setOnOp((op) => recordOp(h, op));\n};\n\nconst suspend = (h: SocketHostState) => {\n h.disposed = true;\n if (h.heartbeatTimer !== null) {\n clearInterval(h.heartbeatTimer);\n h.heartbeatTimer = null;\n }\n h.stateHost?.setOnOp(null);\n};\n\nconst useSocketHost = (\n transport: ResourceElement<Statewire>,\n options?: StatewireHostInternal.SocketHostOptions,\n): Pick<\n StatewireHostInternal.SocketHost,\n \"connect\" | \"finish\" | \"stream\" | \"frames\"\n> => {\n const [h] = useState((): SocketHostState => {\n const host: SocketHostState = {\n heartbeatMs: 15_000,\n wsInitTimeoutMs: 5_000,\n clientRecordLimit: CLIENT_RECORD_LIMIT,\n finOnIdle: false,\n authorize: undefined,\n clients: new Map(),\n conns: new Set(),\n pendingConns: new Set(),\n pendingOps: [],\n pendingApplied: new Map(),\n pendingCmds: new Map(),\n idleWire: true,\n finished: null,\n disposed: false,\n flushScheduled: false,\n heartbeatTimer: null,\n stateHost: null,\n commandsHost: null,\n current: null,\n post: createMacrotaskPoster(() => {\n host.flushScheduled = false;\n flush(host);\n }),\n connect: (clientId, socket, connectOptions) =>\n connect(host, clientId, socket, connectOptions),\n finish: (fin) => finish(host, fin),\n stream: (request) => serveStream(host, request),\n frames: (request) => serveFrames(host, request),\n };\n return host;\n });\n setHeartbeatMs(h, options?.heartbeatIntervalMs ?? 15_000);\n h.wsInitTimeoutMs = options?.wsInitTimeoutMs ?? 5_000;\n h.clientRecordLimit = options?.clientRecordLimit ?? CLIENT_RECORD_LIMIT;\n h.finOnIdle = options?.finOnIdle ?? false;\n h.authorize = options?.authorize;\n const value = useResource(transport) as Statewire<unknown>;\n attach(h, value);\n useEffect(() => {\n attach(h, value);\n });\n useEffect(() => {\n resume(h);\n return () => suspend(h);\n }, [h]);\n return h;\n};\n\n/**\n * Transport-agnostic WS binding over a statewire/host transport:\n * feed it sockets (anything with `send`/`close`) and raw text frames, and it\n * speaks the Statewire packet protocol — snapshot-first hello with `syn`,\n * statement-lane client frames under one admission law, `{cmd}` answer\n * arrays fanned out to every attach of a client id, idle edges, and `fin` on\n * finish.\n */\nexport const StatewireSocketHost = (\n transport: ResourceElement<Statewire>,\n options?: StatewireHostInternal.SocketHostOptions,\n): StatewireHostInternal.SocketHost => {\n const SocketHostRoot = () => useSocketHost(transport, options);\n const root = createTapRoot(SocketHostRoot);\n let disposed = false;\n return {\n connect: (clientId, socket, connectOptions) =>\n flushTapSync(() =>\n root.getValue().connect(clientId, socket, connectOptions),\n ),\n stream: (request) => flushTapSync(() => root.getValue().stream(request)),\n frames: (request) => flushTapSync(() => root.getValue().frames(request)),\n finish: (fin) => flushTapSync(() => root.getValue().finish(fin)),\n dispose: () => {\n if (disposed) return;\n disposed = true;\n flushTapSync(() => root.getValue().finish({ reason: \"evicted\" }));\n root.unmount();\n },\n };\n};\n"],"mappings":"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"}
|
package/dist/host-internal.d.ts
CHANGED
|
@@ -12,9 +12,15 @@ declare namespace StatewireHostInternal {
|
|
|
12
12
|
message: (data: string) => void;
|
|
13
13
|
close: () => void;
|
|
14
14
|
};
|
|
15
|
+
type SocketConnectOptions = {
|
|
16
|
+
/** The adapter restored this socket from an already-authorized session. */
|
|
17
|
+
authorized?: boolean;
|
|
18
|
+
/** Persist authorization before the first snapshot is released. */
|
|
19
|
+
onAuthorized?: () => void;
|
|
20
|
+
};
|
|
15
21
|
type SocketHost = {
|
|
16
22
|
/** Null means refused: the socket was told (fin and/or close) and is dead. */
|
|
17
|
-
connect: (clientId: string, socket: Socket) => SocketConnection | null;
|
|
23
|
+
connect: (clientId: string, socket: Socket, options?: SocketConnectOptions) => SocketConnection | null;
|
|
18
24
|
stream: (request: Request) => Promise<Response>;
|
|
19
25
|
frames: (request: Request) => Promise<Response>;
|
|
20
26
|
finish: (fin: StatewireHost.Fin) => void;
|
|
@@ -24,6 +30,8 @@ declare namespace StatewireHostInternal {
|
|
|
24
30
|
authorize?: (ctx: {
|
|
25
31
|
headers: Record<string, string>;
|
|
26
32
|
}) => void | Promise<void>;
|
|
33
|
+
/** Time allowed to complete WebSocket initialization and authorization. */
|
|
34
|
+
wsInitTimeoutMs?: number;
|
|
27
35
|
heartbeatIntervalMs?: number;
|
|
28
36
|
/** LRU cap on stored client records; live or in-flight records are exempt. */
|
|
29
37
|
clientRecordLimit?: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"host-internal.d.ts","names":[],"sources":["../src/host-internal.ts"],"mappings":";;;;kBAIiB;OACH;IACV,OAAO;IACP,QAAQ,eAAe;;OAGb;aACD;IACT,UAAU;IACV;;OAGU;;IAEV,
|
|
1
|
+
{"version":3,"file":"host-internal.d.ts","names":[],"sources":["../src/host-internal.ts"],"mappings":";;;;kBAIiB;OACH;IACV,OAAO;IACP,QAAQ,eAAe;;OAGb;aACD;IACT,UAAU;IACV;;OAGU;;IAEV;;IAEA;;OAGU;;IAEV,UACE,kBACA,QAAQ,QACR,UAAU,yBACP;IACL,SAAS,SAAS,YAAY,QAAQ;IACtC,SAAS,SAAS,YAAY,QAAQ;IACtC,SAAS,KAAK,cAAc;IAC5B;;OAGU;IACV,aAAa;MACX,SAAS;iBACE;;IAEb;IACA;;IAEA;;IAEA;;OAGU,MAAM,cAAc"}
|
package/dist/statewire.d.ts
CHANGED
|
@@ -58,26 +58,27 @@ declare namespace StatewireClient {
|
|
|
58
58
|
/** Removes the entry. */
|
|
59
59
|
discardFailed: (entry: FailedCommand) => void;
|
|
60
60
|
};
|
|
61
|
+
/** `cause`/`nextRetryAt`/`lastError` are present only while waiting out the backoff timer; a dial in flight carries `attempt` alone. */
|
|
61
62
|
type ConnectionState = {
|
|
62
|
-
status: "
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
status: "idle";
|
|
63
|
+
status: "disconnected";
|
|
64
|
+
reason: "deferred" | "idle" | "gone";
|
|
65
|
+
message?: string;
|
|
66
|
+
payload?: unknown;
|
|
67
67
|
} | {
|
|
68
|
-
status: "
|
|
69
|
-
|
|
68
|
+
status: "connecting";
|
|
69
|
+
/** 0 = the episode's first dial, >0 = retry. */
|
|
70
70
|
attempt: number;
|
|
71
|
-
|
|
71
|
+
cause?: "dropped" | "evicted" | "error" | "unauthorized";
|
|
72
|
+
nextRetryAt?: number;
|
|
72
73
|
lastError?: string;
|
|
73
74
|
message?: string;
|
|
74
75
|
} | {
|
|
75
|
-
status: "
|
|
76
|
-
message?: string;
|
|
77
|
-
payload?: unknown;
|
|
76
|
+
status: "connected";
|
|
78
77
|
};
|
|
79
78
|
type Connection = ConnectionState & {
|
|
80
79
|
reconnect: () => void;
|
|
80
|
+
/** True while retrying (`connecting` with `attempt > 0`) or parked `gone`. */
|
|
81
|
+
degraded: boolean;
|
|
81
82
|
};
|
|
82
83
|
type ConnectionStatus = Connection["status"];
|
|
83
84
|
/**
|
|
@@ -192,6 +193,8 @@ declare namespace StatewireClient {
|
|
|
192
193
|
type SSEOptions = {
|
|
193
194
|
sessionStore?: SessionStorage | undefined;
|
|
194
195
|
url: string;
|
|
196
|
+
/** The session does not exist on the server yet: the first attach waits for the first command send (or an explicit `reconnect()`). */
|
|
197
|
+
isNew?: boolean;
|
|
195
198
|
headers?: HeadersOption;
|
|
196
199
|
fetch?: typeof globalThis.fetch;
|
|
197
200
|
onSessionLost?: OnSessionLost;
|
|
@@ -202,6 +205,8 @@ declare namespace StatewireClient {
|
|
|
202
205
|
type WSOptions = {
|
|
203
206
|
sessionStore?: SessionStorage | undefined;
|
|
204
207
|
url: string;
|
|
208
|
+
/** The session does not exist on the server yet: the first attach waits for the first command send (or an explicit `reconnect()`). */
|
|
209
|
+
isNew?: boolean;
|
|
205
210
|
headers?: HeadersOption;
|
|
206
211
|
protocols?: string | string[];
|
|
207
212
|
query?: Record<string, string> | (() => Record<string, string> | Promise<Record<string, string>>);
|
package/dist/statewire.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"statewire.d.ts","names":[],"sources":["../src/statewire.ts"],"mappings":";;;;cAgCa,eACX,QACA,kBAAkB,UAAU,WAAW,UAAU,UAEjD,SAAS,gBAAgB,QAAQ,QAAQ,eACxC,gBAAgB,QAAQ,QAAQ;cA6DtB,oBACX,QACA,kBAAkB,UAAU,WAAW,UAAU,UAEjD,SAAS,gBAAgB,QAAQ,QAAQ,eACxC,gBAAgB,gBAAgB,QAAQ,QAAQ;cAGtC,gBACX,QACA,kBAAkB,UAAU,WAAW,UAAU;mBAEhC;UACT;EAEI,YAAA,SAAS,gBAAgB,QAAQ,QAAQ;MAKjD,SAAS;MAIT,cAAc,gBAAgB;MAI9B,YAAY,UAAU,cAAc;MAIpC;EAIJ,WAAW,OAAO;MAId,mBAAmB,gBAAgB;EAIvC,YAAY,OAAO,gBAAgB,gBAAgB;EAInD,cAAc,OAAO,gBAAgB;EAIrC,UAAU;EAIV;;kBAOe;OACH,QACV,QACA,kBAAkB,UAAU,WAAW,UAAU;IAEjD,WAAW,gBAAgB,UAAU,QAAQ;;IAE7C;MACM,UAAU,gBAAgB;;;IAGhC,eAAe;IACf,aAAa,WAAW,YAAY,SAAS;IAC7C,cAAc,YAAY,YAAY;IACtC,iBACE,OAAO,YAAY,SACnB;MAAO,SAAS,UAAU;;IAE5B,mBACE,QAAQ,UAAU,cAAc,YAChC;MAAO,OAAO,YAAY;;IAE5B,sBAAsB,YAAY;;IAElC,kBACE,OAAO,YAAY,SACnB,OAAO;;OAIC,QACV,QACA,kBAAkB,UAAU,WAAW,UAAU;;IAGjD,OAAO;;IAEP,gBAAgB;IAChB,YAAY;IACZ,UAAU,UAAU,cAAc;;IAElC;;IAEA,aAAa,OAAO;;IAEpB,iBAAiB;;IAEjB,cAAc,OAAO,kBAAkB;;IAEvC,gBAAgB,OAAO
|
|
1
|
+
{"version":3,"file":"statewire.d.ts","names":[],"sources":["../src/statewire.ts"],"mappings":";;;;cAgCa,eACX,QACA,kBAAkB,UAAU,WAAW,UAAU,UAEjD,SAAS,gBAAgB,QAAQ,QAAQ,eACxC,gBAAgB,QAAQ,QAAQ;cA6DtB,oBACX,QACA,kBAAkB,UAAU,WAAW,UAAU,UAEjD,SAAS,gBAAgB,QAAQ,QAAQ,eACxC,gBAAgB,gBAAgB,QAAQ,QAAQ;cAGtC,gBACX,QACA,kBAAkB,UAAU,WAAW,UAAU;mBAEhC;UACT;EAEI,YAAA,SAAS,gBAAgB,QAAQ,QAAQ;MAKjD,SAAS;MAIT,cAAc,gBAAgB;MAI9B,YAAY,UAAU,cAAc;MAIpC;EAIJ,WAAW,OAAO;MAId,mBAAmB,gBAAgB;EAIvC,YAAY,OAAO,gBAAgB,gBAAgB;EAInD,cAAc,OAAO,gBAAgB;EAIrC,UAAU;EAIV;;kBAOe;OACH,QACV,QACA,kBAAkB,UAAU,WAAW,UAAU;IAEjD,WAAW,gBAAgB,UAAU,QAAQ;;IAE7C;MACM,UAAU,gBAAgB;;;IAGhC,eAAe;IACf,aAAa,WAAW,YAAY,SAAS;IAC7C,cAAc,YAAY,YAAY;IACtC,iBACE,OAAO,YAAY,SACnB;MAAO,SAAS,UAAU;;IAE5B,mBACE,QAAQ,UAAU,cAAc,YAChC;MAAO,OAAO,YAAY;;IAE5B,sBAAsB,YAAY;;IAElC,kBACE,OAAO,YAAY,SACnB,OAAO;;OAIC,QACV,QACA,kBAAkB,UAAU,WAAW,UAAU;;IAGjD,OAAO;;IAEP,gBAAgB;IAChB,YAAY;IACZ,UAAU,UAAU,cAAc;;IAElC;;IAEA,aAAa,OAAO;;IAEpB,iBAAiB;;IAEjB,cAAc,OAAO,kBAAkB;;IAEvC,gBAAgB,OAAO;;;OAIb;IAEN;IACA;IACA;IACA;;IAGA;;IAEA;IACA;IACA;IACA;IACA;;IAEA;;OACM,aAAa;IACvB;;IAEA;;OAEU,mBAAmB;;;;;OAMnB,WACV,QACA,kBAAkB,UAAU,WAAW,UAAU,aAEjD,OAAO,QACP,SAAS,UAAU,QAAQ,YAC3B,KAAK;OAGK;IACV;IACA;IACA;;;;;;;OAQU,YAAY,WAAW,OAAO;;;;;;;;;;;;;OAc9B;IAEN;IACA;IACA;IACA;IACA;;IAEA;IAAgB;IAAiB;;IACjC;IAAiB;;IACjB;IAAiB;;IAEjB;IACA;IACA;;IAGA;IACA;;;OAIM,iBACV,SAAS;IACP;IACA;IACA;IACA;IACA;;;OAKQ;aACD;aACA;aACA;aACA,SAAS;aACT;aACA;;;OAIC;IACV;IACA;IACA;IACA;;;OAIU;IACV;IACA;IACA;IACA,mBAAmB;;IAEnB,oBAAoB;;IAEpB,kBAAkB;;;OAIR;IACV;IACA,cAAc;IACd;IACA;IACA;IACA;;;OAIU;IACV,YAAY;IACZ,OAAO,QAAQ;;IAEf,QAAQ,GAAG,UAAU,IAAI,QAAQ,OAAO,QAAQ;;IAEhD,aAAa;;;OAIH,gBACR,gBACE;IAAO;QAAyB,cAAc,QAAQ;OAEhD;IACV,eAAe;IACf;;IAEA;IACA,UAAU;IACV,eAAe,WAAW;IAC1B,gBAAgB;IAChB,YAAY,YAAY;;IAExB;;OAGU;IACV,eAAe;IACf;;IAEA;IACA,UAAU;IACV;IACA,QACI,gCACO,yBAAyB,QAAQ;IAC5C,iBAAiB,aAAa,kCAAkC;IAChE,gBAAgB;IAChB,YAAY,YAAY;;IAExB"}
|
package/dist/statewire.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { CONNECTED_CONNECTION, useStatewireCore } from "./client/core.js";
|
|
2
2
|
import { SessionStorageContext } from "./client/sessionStore.js";
|
|
3
3
|
import { useMemo, useRef, useState, useSyncExternalStore } from "@assistant-ui/tap/react-shim";
|
|
4
4
|
import { createTapRoot, flushTapSync, resource, useContextProvider, useResource, useResources, withKey } from "@assistant-ui/tap";
|
|
@@ -18,7 +18,7 @@ const useStatewire = (options) => {
|
|
|
18
18
|
const state = useSyncExternalStore(subscribe, core.getState, core.getState);
|
|
19
19
|
const isBusy = useSyncExternalStore(subscribe, core.getBusy, core.getBusy);
|
|
20
20
|
const failed = useSyncExternalStore(subscribe, core.getFailed, core.getFailed);
|
|
21
|
-
const connection = value.connection ??
|
|
21
|
+
const connection = value.connection ?? CONNECTED_CONNECTION;
|
|
22
22
|
return useMemo(() => {
|
|
23
23
|
const failures = () => {
|
|
24
24
|
if (!value.failures) throw new Error("statewire: this transport has no failed-send lane");
|