statewire 0.0.1 → 0.0.3
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 +14 -13
- package/dist/client/changes.d.ts +2 -2
- package/dist/client/changes.d.ts.map +1 -1
- package/dist/client/changes.js +3 -10
- package/dist/client/changes.js.map +1 -1
- package/dist/client/connection.d.ts +18 -39
- package/dist/client/connection.d.ts.map +1 -1
- package/dist/client/connection.js +61 -54
- package/dist/client/connection.js.map +1 -1
- package/dist/client/core.d.ts +7 -11
- package/dist/client/core.d.ts.map +1 -1
- package/dist/client/core.js +58 -55
- package/dist/client/core.js.map +1 -1
- package/dist/client/session.d.ts +12 -26
- package/dist/client/session.d.ts.map +1 -1
- package/dist/client/session.js +70 -43
- package/dist/client/session.js.map +1 -1
- package/dist/client/sessionStore.d.ts +1 -1
- package/dist/client/sessionStore.js.map +1 -1
- package/dist/client/timing.d.ts +2 -1
- package/dist/client/timing.d.ts.map +1 -1
- package/dist/client/timing.js +5 -1
- package/dist/client/timing.js.map +1 -1
- package/dist/host/adapter.d.ts +8 -0
- package/dist/host/adapter.d.ts.map +1 -0
- package/dist/host/adapter.js +23 -0
- package/dist/host/adapter.js.map +1 -0
- package/dist/host/draft.d.ts +21 -7
- package/dist/host/draft.d.ts.map +1 -1
- package/dist/host/draft.js +190 -103
- package/dist/host/draft.js.map +1 -1
- package/dist/host/host.d.ts +19 -35
- package/dist/host/host.d.ts.map +1 -1
- package/dist/host/host.js +86 -54
- package/dist/host/host.js.map +1 -1
- package/dist/host/socket.d.ts +14 -0
- package/dist/host/socket.d.ts.map +1 -0
- package/dist/host/socket.js +511 -0
- package/dist/host/socket.js.map +1 -0
- package/dist/host-internal.d.ts +27 -0
- package/dist/host-internal.d.ts.map +1 -0
- package/dist/host-internal.js +3 -0
- package/dist/host.d.ts +54 -0
- package/dist/host.d.ts.map +1 -0
- package/dist/host.js +4 -0
- package/dist/index.d.ts +5 -28
- package/dist/index.js +2 -3
- package/dist/statewire.d.ts +97 -10
- package/dist/statewire.d.ts.map +1 -1
- package/dist/statewire.js +32 -36
- package/dist/statewire.js.map +1 -1
- package/dist/transports/fake-sse.d.ts +12 -0
- package/dist/transports/fake-sse.d.ts.map +1 -0
- package/dist/transports/fake-sse.js +39 -0
- package/dist/transports/fake-sse.js.map +1 -0
- package/dist/transports/fixtures.d.ts +33 -0
- package/dist/transports/fixtures.d.ts.map +1 -0
- package/dist/transports/fixtures.js +50 -0
- package/dist/transports/fixtures.js.map +1 -0
- package/dist/transports/remote.d.ts +6 -13
- package/dist/transports/remote.d.ts.map +1 -1
- package/dist/transports/remote.js +7 -25
- package/dist/transports/remote.js.map +1 -1
- package/dist/transports/sse.d.ts +32 -20
- package/dist/transports/sse.d.ts.map +1 -1
- package/dist/transports/sse.js +57 -46
- package/dist/transports/sse.js.map +1 -1
- package/dist/transports/testing.d.ts +8 -6
- package/dist/transports/testing.d.ts.map +1 -1
- package/dist/transports/testing.js +19 -46
- package/dist/transports/testing.js.map +1 -1
- package/dist/transports/ws.d.ts +4 -13
- package/dist/transports/ws.d.ts.map +1 -1
- package/dist/transports/ws.js +59 -63
- package/dist/transports/ws.js.map +1 -1
- package/dist/types.d.ts +55 -100
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/util/draftTraps.d.ts +6 -0
- package/dist/util/draftTraps.d.ts.map +1 -0
- package/dist/util/draftTraps.js +25 -0
- package/dist/util/draftTraps.js.map +1 -0
- package/dist/util/macrotask.d.ts +5 -0
- package/dist/util/macrotask.d.ts.map +1 -0
- package/dist/util/macrotask.js +25 -0
- package/dist/util/macrotask.js.map +1 -0
- package/dist/util/methodProxy.d.ts +5 -0
- package/dist/util/methodProxy.d.ts.map +1 -0
- package/dist/util/methodProxy.js +17 -0
- package/dist/util/methodProxy.js.map +1 -0
- package/dist/util/randomId.d.ts +5 -0
- package/dist/util/randomId.d.ts.map +1 -0
- package/dist/util/randomId.js +6 -0
- package/dist/util/randomId.js.map +1 -0
- package/dist/{client/optimistic.d.ts → util/recordMutations.d.ts} +2 -2
- package/dist/util/recordMutations.d.ts.map +1 -0
- package/dist/{client/optimistic.js → util/recordMutations.js} +5 -24
- package/dist/util/recordMutations.js.map +1 -0
- package/dist/util/statePath.d.ts +14 -0
- package/dist/util/statePath.d.ts.map +1 -0
- package/dist/util/statePath.js +31 -0
- package/dist/util/statePath.js.map +1 -0
- package/dist/wire/meta.d.ts +6 -1
- package/dist/wire/meta.d.ts.map +1 -1
- package/dist/wire/meta.js +30 -28
- package/dist/wire/meta.js.map +1 -1
- package/dist/wire/ops.d.ts +5 -26
- package/dist/wire/ops.d.ts.map +1 -1
- package/dist/wire/ops.js +67 -80
- package/dist/wire/ops.js.map +1 -1
- package/package.json +15 -11
- package/src/client/changes.ts +5 -15
- package/src/client/connection.ts +87 -113
- package/src/client/core.ts +57 -91
- package/src/client/session.ts +129 -90
- package/src/client/sessionStore.ts +1 -1
- package/src/client/timing.ts +6 -0
- package/src/host/adapter.ts +33 -0
- package/src/host/draft.ts +293 -125
- package/src/host/host.ts +122 -110
- package/src/host/socket.ts +618 -0
- package/src/host-internal.ts +28 -0
- package/src/host.ts +72 -0
- package/src/index.ts +2 -62
- package/src/statewire.ts +168 -61
- package/src/transports/fake-sse.ts +51 -0
- package/src/transports/fixtures.ts +60 -0
- package/src/transports/remote.ts +14 -51
- package/src/transports/sse.ts +87 -89
- package/src/transports/testing.ts +33 -63
- package/src/transports/ws.ts +78 -100
- package/src/types.ts +52 -131
- package/src/util/draftTraps.ts +32 -0
- package/src/util/macrotask.ts +25 -0
- package/src/util/methodProxy.ts +16 -0
- package/src/util/randomId.ts +4 -0
- package/src/{client/optimistic.ts → util/recordMutations.ts} +0 -0
- package/src/util/statePath.ts +61 -0
- package/src/wire/meta.ts +42 -47
- package/src/wire/ops.ts +107 -106
- package/LICENSE +0 -21
- package/dist/client/optimistic.d.ts.map +0 -1
- package/dist/client/optimistic.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/server.d.ts +0 -15
- package/dist/server.d.ts.map +0 -1
- package/dist/server.js +0 -3
- package/src/server.ts +0 -32
package/dist/transports/ws.js
CHANGED
|
@@ -1,67 +1,42 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { CLIENT_QUERY_PARAM } from "../host/adapter.js";
|
|
2
2
|
import { timing } from "../client/timing.js";
|
|
3
|
-
import {
|
|
3
|
+
import { handleEnvelope, overloadedError, useStatewireConn } from "../client/connection.js";
|
|
4
4
|
import { useStatewireRemote } from "./remote.js";
|
|
5
|
+
import { encodeWireCommand } from "./sse.js";
|
|
6
|
+
import { useState } from "@assistant-ui/tap/react-shim";
|
|
5
7
|
import { flushTapSync, resource } from "@assistant-ui/tap";
|
|
6
8
|
//#region src/transports/ws.ts
|
|
7
9
|
const OPEN = 1;
|
|
8
10
|
const WS_SUBPROTOCOL = "statewire.v1";
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
hasSnapshot: false,
|
|
12
|
-
lease: null,
|
|
13
|
-
attempt: 0,
|
|
14
|
-
episode: null,
|
|
15
|
-
abort: null,
|
|
16
|
-
socket: null,
|
|
17
|
-
pending: [],
|
|
18
|
-
gate: createGate(),
|
|
19
|
-
lifetime: null,
|
|
20
|
-
latest,
|
|
21
|
-
notify,
|
|
22
|
-
reconnect: () => reconnectConn(c),
|
|
23
|
-
attemptOnce: (abort) => attemptSocket(c, abort),
|
|
24
|
-
send: (args) => sendCommand(c, args),
|
|
25
|
-
connection: {
|
|
26
|
-
status: "connecting",
|
|
27
|
-
reconnect: () => c.reconnect()
|
|
28
|
-
}
|
|
29
|
-
};
|
|
30
|
-
return c;
|
|
31
|
-
};
|
|
32
|
-
const socketUrl = async (c) => {
|
|
33
|
-
const { url, query } = c.latest.current.options;
|
|
11
|
+
const socketUrl = async (options, clientId) => {
|
|
12
|
+
const { url, query } = options;
|
|
34
13
|
const params = new URLSearchParams(typeof query === "function" ? await query() : query);
|
|
35
|
-
params.set(
|
|
14
|
+
params.set(CLIENT_QUERY_PARAM, clientId);
|
|
36
15
|
return `${url.replace(/\/$/, "").replace(/^http/, "ws")}/ws?${params.toString()}`;
|
|
37
16
|
};
|
|
38
|
-
const settleOverloaded = (
|
|
17
|
+
const settleOverloaded = (w, { seq, retryAfterMs }) => {
|
|
39
18
|
if (seq === void 0) throw overloadedError(retryAfterMs);
|
|
40
|
-
const entry =
|
|
19
|
+
const entry = w.pending.find((p) => p.seq === seq);
|
|
41
20
|
if (!entry) return;
|
|
42
|
-
|
|
21
|
+
w.pending = w.pending.filter((p) => p !== entry);
|
|
43
22
|
entry.reject(overloadedError(retryAfterMs));
|
|
44
23
|
};
|
|
45
|
-
const
|
|
46
|
-
while (c.pending[0] && c.pending[0].seq <= ack) c.pending.shift().resolve({ type: "receipt" });
|
|
47
|
-
};
|
|
48
|
-
const resolveResponded = (c, seqs) => {
|
|
24
|
+
const resolvePending = (w, matches) => {
|
|
49
25
|
const remaining = [];
|
|
50
|
-
for (const entry of
|
|
26
|
+
for (const entry of w.pending) if (matches(entry)) entry.resolve({ type: "receipt" });
|
|
51
27
|
else remaining.push(entry);
|
|
52
|
-
|
|
28
|
+
w.pending = remaining;
|
|
53
29
|
};
|
|
54
|
-
const failPending = (
|
|
55
|
-
const pending =
|
|
56
|
-
|
|
30
|
+
const failPending = (w, error) => {
|
|
31
|
+
const pending = w.pending;
|
|
32
|
+
w.pending = [];
|
|
57
33
|
for (const entry of pending) entry.reject(error);
|
|
58
34
|
};
|
|
59
|
-
const runSocket = (c, ws, abort) => new Promise((resolve, reject) => {
|
|
35
|
+
const runSocket = (c, w, ws, abort) => new Promise((resolve, reject) => {
|
|
60
36
|
let timer;
|
|
61
37
|
let timedOut = false;
|
|
62
38
|
let outcome = null;
|
|
63
39
|
let closed = false;
|
|
64
|
-
let attached = false;
|
|
65
40
|
const arm = () => {
|
|
66
41
|
clearTimeout(timer);
|
|
67
42
|
timer = setTimeout(() => {
|
|
@@ -79,10 +54,15 @@ const runSocket = (c, ws, abort) => new Promise((resolve, reject) => {
|
|
|
79
54
|
ws.close();
|
|
80
55
|
};
|
|
81
56
|
const processEnv = (env) => {
|
|
82
|
-
const done = flushTapSync(() => handleEnvelope(c, env
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
57
|
+
const done = flushTapSync(() => handleEnvelope(c, env));
|
|
58
|
+
if (env.ack !== void 0) {
|
|
59
|
+
const ack = env.ack;
|
|
60
|
+
resolvePending(w, (entry) => entry.seq <= ack);
|
|
61
|
+
}
|
|
62
|
+
if (env.res !== void 0) {
|
|
63
|
+
const seqs = new Set(env.res.map((r) => r.seq));
|
|
64
|
+
resolvePending(w, (entry) => seqs.has(entry.seq));
|
|
65
|
+
}
|
|
86
66
|
if (done) {
|
|
87
67
|
outcome = done;
|
|
88
68
|
ws.close();
|
|
@@ -99,7 +79,7 @@ const runSocket = (c, ws, abort) => new Promise((resolve, reject) => {
|
|
|
99
79
|
return;
|
|
100
80
|
}
|
|
101
81
|
try {
|
|
102
|
-
if (frame.overloaded !== void 0) settleOverloaded(
|
|
82
|
+
if (frame.overloaded !== void 0) settleOverloaded(w, frame.overloaded);
|
|
103
83
|
else processEnv(frame);
|
|
104
84
|
} catch (error) {
|
|
105
85
|
fail(error);
|
|
@@ -108,28 +88,28 @@ const runSocket = (c, ws, abort) => new Promise((resolve, reject) => {
|
|
|
108
88
|
ws.onclose = () => {
|
|
109
89
|
closed = true;
|
|
110
90
|
clearTimeout(timer);
|
|
111
|
-
if (
|
|
91
|
+
if (w.socket === ws) failPending(w, /* @__PURE__ */ new Error("network"));
|
|
112
92
|
if (outcome) resolve(outcome);
|
|
113
93
|
else reject(/* @__PURE__ */ new Error(timedOut ? "timeout" : "network"));
|
|
114
94
|
};
|
|
115
95
|
});
|
|
116
|
-
const attemptSocket = async (c, abort) => {
|
|
96
|
+
const attemptSocket = async (c, w, options, abort) => {
|
|
117
97
|
let ws = null;
|
|
118
98
|
try {
|
|
119
|
-
const url = await socketUrl(c);
|
|
99
|
+
const url = await socketUrl(options, c.ctx.clientId);
|
|
120
100
|
abort.signal.throwIfAborted();
|
|
121
|
-
const { protocols, webSocket } =
|
|
101
|
+
const { protocols, webSocket } = options;
|
|
122
102
|
const WS = webSocket ?? globalThis.WebSocket;
|
|
123
103
|
if (!WS) throw new Error("no WebSocket implementation");
|
|
124
104
|
ws = new WS(url, [WS_SUBPROTOCOL, ...protocols === void 0 ? [] : typeof protocols === "string" ? [protocols] : protocols]);
|
|
125
|
-
|
|
126
|
-
return await runSocket(c, ws, abort);
|
|
105
|
+
w.socket = ws;
|
|
106
|
+
return await runSocket(c, w, ws, abort);
|
|
127
107
|
} finally {
|
|
128
|
-
if (
|
|
108
|
+
if (w.socket === ws) w.socket = null;
|
|
129
109
|
}
|
|
130
110
|
};
|
|
131
|
-
const sendCommand = (
|
|
132
|
-
const ws =
|
|
111
|
+
const sendCommand = (w, { seq, command }) => {
|
|
112
|
+
const ws = w.socket;
|
|
133
113
|
if (!ws || ws.readyState !== OPEN) return Promise.reject(/* @__PURE__ */ new Error("network"));
|
|
134
114
|
return new Promise((resolve, reject) => {
|
|
135
115
|
const entry = {
|
|
@@ -144,27 +124,43 @@ const sendCommand = (c, { seq, command }) => {
|
|
|
144
124
|
}
|
|
145
125
|
};
|
|
146
126
|
const timer = setTimeout(() => {
|
|
147
|
-
|
|
127
|
+
w.pending = w.pending.filter((p) => p !== entry);
|
|
148
128
|
reject(/* @__PURE__ */ new Error("timeout"));
|
|
149
129
|
ws.close();
|
|
150
130
|
}, timing.heartbeatTimeoutMs);
|
|
151
|
-
|
|
131
|
+
w.pending.push(entry);
|
|
152
132
|
try {
|
|
153
133
|
ws.send(JSON.stringify({
|
|
154
|
-
|
|
155
|
-
...encodeParams(command.params),
|
|
134
|
+
...encodeWireCommand(command),
|
|
156
135
|
seq
|
|
157
136
|
}));
|
|
158
137
|
} catch {
|
|
159
138
|
clearTimeout(timer);
|
|
160
|
-
|
|
139
|
+
w.pending = w.pending.filter((p) => p !== entry);
|
|
161
140
|
reject(/* @__PURE__ */ new Error("network"));
|
|
162
141
|
}
|
|
163
142
|
});
|
|
164
143
|
};
|
|
165
|
-
const
|
|
166
|
-
|
|
144
|
+
const useWsLink = (options, ctx) => {
|
|
145
|
+
const [w] = useState(() => ({
|
|
146
|
+
socket: null,
|
|
147
|
+
pending: []
|
|
148
|
+
}));
|
|
149
|
+
const c_0 = useStatewireConn({
|
|
150
|
+
url: options.url,
|
|
151
|
+
onChange: options.onChange,
|
|
152
|
+
ctx,
|
|
153
|
+
attemptOnce: (c, abort) => attemptSocket(c, w, options, abort)
|
|
154
|
+
});
|
|
155
|
+
const [link] = useState(() => ({
|
|
156
|
+
get connection() {
|
|
157
|
+
return c_0.connection;
|
|
158
|
+
},
|
|
159
|
+
send: (args) => sendCommand(w, args)
|
|
160
|
+
}));
|
|
161
|
+
return link;
|
|
167
162
|
};
|
|
163
|
+
const useStatewireWS = (options) => useStatewireRemote(options, useWsLink);
|
|
168
164
|
const StatewireWS = resource(useStatewireWS);
|
|
169
165
|
//#endregion
|
|
170
166
|
export { StatewireWS, WS_SUBPROTOCOL };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ws.js","names":["flushTapSync","resource","ResourceElement","encodeParams","timing","createGate","handleEnvelope","overloadedError","reconnectConn","ConnBase","StatewireEnvelope","StatewireTransport","useStatewireRemote","StatewireSessionStore","StatewireCommands","RemoteLink","StatewireSubmitResult","StatewireConnection","StatewireTransportProps","StatewireWireCommand","StatewireWSOptions","url","protocols","query","Record","Promise","webSocket","WebSocket","onChange","connection","sessionStore","Latest","options","ctx","PendingCommand","seq","resolve","result","reject","error","Error","Conn","socket","pending","latest","current","send","OPEN","WS_SUBPROTOCOL","createConn","notify","c","hasSnapshot","lease","attempt","episode","abort","gate","lifetime","reconnect","attemptOnce","attemptSocket","args","sendCommand","status","socketUrl","params","URLSearchParams","set","clientId","base","replace","toString","settleOverloaded","retryAfterMs","undefined","entry","find","p","filter","resolveReceipts","ack","shift","type","resolveResponded","seqs","Set","remaining","has","push","failPending","runSocket","ws","AbortController","timer","ReturnType","setTimeout","timedOut","outcome","closed","attached","arm","clearTimeout","close","heartbeatTimeoutMs","signal","addEventListener","onerror","stale","Boolean","aborted","fail","processEnv","env","done","res","map","r","onmessage","event","frame","overloaded","JSON","parse","String","data","onclose","throwIfAborted","WS","globalThis","extra","command","readyState","stringify","method","useStatewireWS","StatewireWS","TState","TCommands","TEvent"],"sources":["../../src/transports/ws.ts"],"sourcesContent":["import { flushTapSync, resource } from \"@assistant-ui/tap\";\nimport type { ResourceElement } from \"@assistant-ui/tap\";\nimport { encodeParams } from \"../wire/meta\";\nimport { timing } from \"../client/timing\";\nimport {\n createGate,\n handleEnvelope,\n overloadedError,\n reconnectConn,\n} from \"../client/connection\";\nimport type { ConnBase, StatewireEnvelope } from \"../client/connection\";\nimport type { StatewireTransport } from \"../types\";\nimport { useStatewireRemote } from \"./remote\";\nimport type { StatewireSessionStore } from \"../client/sessionStore\";\nimport type { StatewireCommands } from \"../types\";\nimport type {\n RemoteLink,\n StatewireSubmitResult,\n StatewireConnection,\n StatewireTransportProps,\n StatewireWireCommand,\n} from \"./sse\";\n\nexport type StatewireWSOptions = {\n url: string;\n protocols?: string | string[];\n query?:\n | Record<string, string>\n | (() => Record<string, string> | Promise<Record<string, string>>);\n webSocket?: new (url: string, protocols?: string | string[]) => WebSocket;\n onChange?: (connection: StatewireConnection) => void;\n sessionStore?: StatewireSessionStore;\n};\n\ntype Latest = {\n options: StatewireWSOptions;\n ctx: StatewireTransportProps;\n};\n\ntype PendingCommand = {\n seq: number;\n resolve: (result: StatewireSubmitResult) => void;\n reject: (error: Error) => void;\n};\n\ntype Conn = ConnBase & {\n socket: WebSocket | null;\n pending: PendingCommand[];\n latest: { readonly current: Latest };\n send: RemoteLink[\"send\"];\n};\n\nconst OPEN = 1;\n\nexport const WS_SUBPROTOCOL = \"statewire.v1\";\n\nconst createConn = (\n latest: { readonly current: Latest },\n notify: (connection: StatewireConnection) => void,\n): Conn => {\n const c: Conn = {\n hasSnapshot: false,\n lease: null,\n attempt: 0,\n episode: null,\n abort: null,\n socket: null,\n pending: [],\n gate: createGate(),\n lifetime: null,\n latest,\n notify,\n reconnect: () => reconnectConn(c),\n attemptOnce: (abort) => attemptSocket(c, abort),\n send: (args) => sendCommand(c, args),\n connection: { status: \"connecting\", reconnect: () => c.reconnect() },\n };\n return c;\n};\n\nconst socketUrl = async (c: Conn) => {\n const { url, query } = c.latest.current.options;\n const params = new URLSearchParams(\n typeof query === \"function\" ? await query() : query,\n );\n params.set(\"client\", c.latest.current.ctx.clientId);\n const base = url.replace(/\\/$/, \"\").replace(/^http/, \"ws\");\n return `${base}/ws?${params.toString()}`;\n};\n\nconst settleOverloaded = (\n c: Conn,\n { seq, retryAfterMs }: { seq?: number; retryAfterMs?: number },\n) => {\n if (seq === undefined) throw overloadedError(retryAfterMs);\n const entry = c.pending.find((p) => p.seq === seq);\n if (!entry) return;\n c.pending = c.pending.filter((p) => p !== entry);\n entry.reject(overloadedError(retryAfterMs));\n};\n\nconst resolveReceipts = (c: Conn, ack: number) => {\n while (c.pending[0] && c.pending[0].seq <= ack) {\n c.pending.shift()!.resolve({ type: \"receipt\" });\n }\n};\n\nconst resolveResponded = (c: Conn, seqs: Set<number>) => {\n const remaining: PendingCommand[] = [];\n for (const entry of c.pending) {\n if (seqs.has(entry.seq)) entry.resolve({ type: \"receipt\" });\n else remaining.push(entry);\n }\n c.pending = remaining;\n};\n\nconst failPending = (c: Conn, error: Error) => {\n const pending = c.pending;\n c.pending = [];\n for (const entry of pending) entry.reject(error);\n};\n\nconst runSocket = (\n c: Conn,\n ws: WebSocket,\n abort: AbortController,\n): Promise<\"stop\" | \"reattach\"> =>\n new Promise((resolve, reject) => {\n let timer: ReturnType<typeof setTimeout> | undefined;\n let timedOut = false;\n let outcome: \"stop\" | \"reattach\" | null = null;\n let closed = false;\n let attached = false;\n const arm = () => {\n clearTimeout(timer);\n timer = setTimeout(() => {\n timedOut = true;\n ws.close();\n }, timing.heartbeatTimeoutMs);\n };\n arm();\n abort.signal.addEventListener(\"abort\", () => ws.close());\n ws.onerror = () => {};\n const stale = () => Boolean(outcome) || closed || abort.signal.aborted;\n const fail = (error: unknown) => {\n clearTimeout(timer);\n reject(error instanceof Error ? error : new Error(\"protocol\"));\n ws.close();\n };\n const processEnv = (env: StatewireEnvelope) => {\n const done = flushTapSync(() => handleEnvelope(c, env, attached));\n attached = true;\n if (env.ack !== undefined) resolveReceipts(c, env.ack);\n if (env.res !== undefined) {\n resolveResponded(c, new Set(env.res.map((r) => r.seq)));\n }\n if (done) {\n outcome = done;\n ws.close();\n }\n };\n ws.onmessage = (event) => {\n if (stale()) return;\n arm();\n let frame: StatewireEnvelope & {\n overloaded?: { seq?: number; retryAfterMs?: number };\n };\n try {\n frame = JSON.parse(String(event.data)) as typeof frame;\n } catch {\n fail(new Error(\"protocol\"));\n return;\n }\n try {\n if (frame.overloaded !== undefined) {\n settleOverloaded(c, frame.overloaded);\n } else {\n processEnv(frame);\n }\n } catch (error) {\n fail(error);\n }\n };\n ws.onclose = () => {\n closed = true;\n clearTimeout(timer);\n if (c.socket === ws) failPending(c, new Error(\"network\"));\n if (outcome) resolve(outcome);\n else reject(new Error(timedOut ? \"timeout\" : \"network\"));\n };\n });\n\nconst attemptSocket = async (\n c: Conn,\n abort: AbortController,\n): Promise<\"stop\" | \"reattach\"> => {\n let ws: WebSocket | null = null;\n try {\n const url = await socketUrl(c);\n abort.signal.throwIfAborted();\n const { protocols, webSocket } = c.latest.current.options;\n const WS = webSocket ?? globalThis.WebSocket;\n if (!WS) throw new Error(\"no WebSocket implementation\");\n const extra =\n protocols === undefined\n ? []\n : typeof protocols === \"string\"\n ? [protocols]\n : protocols;\n ws = new WS(url, [WS_SUBPROTOCOL, ...extra]);\n c.socket = ws;\n return await runSocket(c, ws, abort);\n } finally {\n if (c.socket === ws) c.socket = null;\n }\n};\n\nconst sendCommand = (\n c: Conn,\n { seq, command }: { seq: number; command: StatewireWireCommand },\n): Promise<StatewireSubmitResult> => {\n const ws = c.socket;\n if (!ws || ws.readyState !== OPEN) {\n return Promise.reject(new Error(\"network\"));\n }\n return new Promise((resolve, reject) => {\n const entry: PendingCommand = {\n seq,\n resolve: (result) => {\n clearTimeout(timer);\n resolve(result);\n },\n reject: (error) => {\n clearTimeout(timer);\n reject(error);\n },\n };\n // A timed-out command fails the socket: the retry then rides reconnect +\n // attach-seq arbitration.\n const timer = setTimeout(() => {\n c.pending = c.pending.filter((p) => p !== entry);\n reject(new Error(\"timeout\"));\n ws.close();\n }, timing.heartbeatTimeoutMs);\n c.pending.push(entry);\n try {\n ws.send(\n JSON.stringify({\n method: command.method,\n ...encodeParams(command.params),\n seq,\n }),\n );\n } catch {\n clearTimeout(timer);\n c.pending = c.pending.filter((p) => p !== entry);\n reject(new Error(\"network\"));\n }\n });\n};\n\nconst useStatewireWS = (\n options: StatewireWSOptions,\n): StatewireTransport<any, any, any> => useStatewireRemote(options, createConn);\n\nexport const StatewireWS = resource(useStatewireWS) as <\n TState = any,\n TCommands extends StatewireCommands = StatewireCommands,\n TEvent = any,\n>(\n options: StatewireWSOptions,\n) => ResourceElement<StatewireTransport<TState | undefined, TCommands, TEvent>>;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ws.js","names":["useState","flushTapSync","resource","ResourceElement","timing","handleEnvelope","overloadedError","useStatewireConn","Conn","StatewireEnvelope","Statewire","StatewireClient","useStatewireRemote","CLIENT_QUERY_PARAM","encodeWireCommand","RemoteLink","StatewireSubmitResult","StatewireRemoteProps","StatewireWireCommand","PendingCommand","seq","resolve","result","reject","error","Error","WsChannel","socket","WebSocket","pending","OPEN","WS_SUBPROTOCOL","socketUrl","options","WSOptions","clientId","url","query","params","URLSearchParams","set","base","replace","toString","settleOverloaded","w","retryAfterMs","undefined","entry","find","p","filter","resolvePending","matches","remaining","type","push","failPending","runSocket","c","ws","abort","AbortController","Promise","timer","ReturnType","setTimeout","timedOut","outcome","closed","arm","clearTimeout","close","heartbeatTimeoutMs","signal","addEventListener","onerror","stale","Boolean","aborted","fail","processEnv","env","done","ack","res","seqs","Set","map","r","has","onmessage","event","frame","overloaded","JSON","parse","String","data","onclose","attemptSocket","ctx","throwIfAborted","protocols","webSocket","WS","globalThis","extra","sendCommand","command","readyState","send","stringify","useWsLink","onChange","attemptOnce","link","connection","args","useStatewireWS","StatewireWS","Commands","TState","TCommands","TEvent"],"sources":["../../src/transports/ws.ts"],"sourcesContent":["import { useState } from \"react\";\nimport { flushTapSync, resource } from \"@assistant-ui/tap\";\nimport type { ResourceElement } from \"@assistant-ui/tap\";\nimport { timing } from \"../client/timing\";\nimport {\n handleEnvelope,\n overloadedError,\n useStatewireConn,\n} from \"../client/connection\";\nimport type { Conn, StatewireEnvelope } from \"../client/connection\";\nimport type { Statewire } from \"../types\";\nimport type { StatewireClient } from \"../statewire\";\nimport { useStatewireRemote } from \"./remote\";\nimport { CLIENT_QUERY_PARAM } from \"../host/adapter\";\nimport { encodeWireCommand } from \"./sse\";\nimport type {\n RemoteLink,\n StatewireSubmitResult,\n StatewireRemoteProps,\n StatewireWireCommand,\n} from \"./sse\";\n\ntype PendingCommand = {\n seq: number;\n resolve: (result: StatewireSubmitResult) => void;\n reject: (error: Error) => void;\n};\n\ntype WsChannel = {\n socket: WebSocket | null;\n pending: PendingCommand[];\n};\n\nconst OPEN = 1;\n\nexport const WS_SUBPROTOCOL = \"statewire.v1\";\n\nconst socketUrl = async (\n options: StatewireClient.WSOptions,\n clientId: string,\n) => {\n const { url, query } = options;\n const params = new URLSearchParams(\n typeof query === \"function\" ? await query() : query,\n );\n params.set(CLIENT_QUERY_PARAM, clientId);\n const base = url.replace(/\\/$/, \"\").replace(/^http/, \"ws\");\n return `${base}/ws?${params.toString()}`;\n};\n\nconst settleOverloaded = (\n w: WsChannel,\n { seq, retryAfterMs }: { seq?: number; retryAfterMs?: number },\n) => {\n if (seq === undefined) throw overloadedError(retryAfterMs);\n const entry = w.pending.find((p) => p.seq === seq);\n if (!entry) return;\n w.pending = w.pending.filter((p) => p !== entry);\n entry.reject(overloadedError(retryAfterMs));\n};\n\nconst resolvePending = (\n w: WsChannel,\n matches: (entry: PendingCommand) => boolean,\n) => {\n const remaining: PendingCommand[] = [];\n for (const entry of w.pending) {\n if (matches(entry)) entry.resolve({ type: \"receipt\" });\n else remaining.push(entry);\n }\n w.pending = remaining;\n};\n\nconst failPending = (w: WsChannel, error: Error) => {\n const pending = w.pending;\n w.pending = [];\n for (const entry of pending) entry.reject(error);\n};\n\nconst runSocket = (\n c: Conn,\n w: WsChannel,\n ws: WebSocket,\n abort: AbortController,\n): Promise<\"stop\" | \"reattach\"> =>\n new Promise((resolve, reject) => {\n let timer: ReturnType<typeof setTimeout> | undefined;\n let timedOut = false;\n let outcome: \"stop\" | \"reattach\" | null = null;\n let closed = false;\n const arm = () => {\n clearTimeout(timer);\n timer = setTimeout(() => {\n timedOut = true;\n ws.close();\n }, timing.heartbeatTimeoutMs);\n };\n arm();\n abort.signal.addEventListener(\"abort\", () => ws.close());\n ws.onerror = () => {};\n const stale = () => Boolean(outcome) || closed || abort.signal.aborted;\n const fail = (error: unknown) => {\n clearTimeout(timer);\n reject(error instanceof Error ? error : new Error(\"protocol\"));\n ws.close();\n };\n const processEnv = (env: StatewireEnvelope) => {\n const done = flushTapSync(() => handleEnvelope(c, env));\n if (env.ack !== undefined) {\n const ack = env.ack;\n resolvePending(w, (entry) => entry.seq <= ack);\n }\n if (env.res !== undefined) {\n const seqs = new Set(env.res.map((r) => r.seq));\n resolvePending(w, (entry) => seqs.has(entry.seq));\n }\n if (done) {\n outcome = done;\n ws.close();\n }\n };\n ws.onmessage = (event) => {\n if (stale()) return;\n arm();\n let frame: StatewireEnvelope & {\n overloaded?: { seq?: number; retryAfterMs?: number };\n };\n try {\n frame = JSON.parse(String(event.data)) as typeof frame;\n } catch {\n fail(new Error(\"protocol\"));\n return;\n }\n try {\n if (frame.overloaded !== undefined) {\n settleOverloaded(w, frame.overloaded);\n } else {\n processEnv(frame);\n }\n } catch (error) {\n fail(error);\n }\n };\n ws.onclose = () => {\n closed = true;\n clearTimeout(timer);\n if (w.socket === ws) failPending(w, new Error(\"network\"));\n if (outcome) resolve(outcome);\n else reject(new Error(timedOut ? \"timeout\" : \"network\"));\n };\n });\n\nconst attemptSocket = async (\n c: Conn,\n w: WsChannel,\n options: StatewireClient.WSOptions,\n abort: AbortController,\n): Promise<\"stop\" | \"reattach\"> => {\n let ws: WebSocket | null = null;\n try {\n const url = await socketUrl(options, c.ctx.clientId);\n abort.signal.throwIfAborted();\n const { protocols, webSocket } = options;\n const WS = webSocket ?? globalThis.WebSocket;\n if (!WS) throw new Error(\"no WebSocket implementation\");\n const extra =\n protocols === undefined\n ? []\n : typeof protocols === \"string\"\n ? [protocols]\n : protocols;\n ws = new WS(url, [WS_SUBPROTOCOL, ...extra]);\n w.socket = ws;\n return await runSocket(c, w, ws, abort);\n } finally {\n if (w.socket === ws) w.socket = null;\n }\n};\n\nconst sendCommand = (\n w: WsChannel,\n { seq, command }: { seq: number; command: StatewireWireCommand },\n): Promise<StatewireSubmitResult> => {\n const ws = w.socket;\n if (!ws || ws.readyState !== OPEN) {\n return Promise.reject(new Error(\"network\"));\n }\n return new Promise((resolve, reject) => {\n const entry: PendingCommand = {\n seq,\n resolve: (result) => {\n clearTimeout(timer);\n resolve(result);\n },\n reject: (error) => {\n clearTimeout(timer);\n reject(error);\n },\n };\n // A timed-out command fails the socket: the retry then rides reconnect +\n // attach-seq arbitration.\n const timer = setTimeout(() => {\n w.pending = w.pending.filter((p) => p !== entry);\n reject(new Error(\"timeout\"));\n ws.close();\n }, timing.heartbeatTimeoutMs);\n w.pending.push(entry);\n try {\n ws.send(JSON.stringify({ ...encodeWireCommand(command), seq }));\n } catch {\n clearTimeout(timer);\n w.pending = w.pending.filter((p) => p !== entry);\n reject(new Error(\"network\"));\n }\n });\n};\n\nconst useWsLink = (\n options: StatewireClient.WSOptions,\n ctx: StatewireRemoteProps,\n): RemoteLink => {\n const [w] = useState((): WsChannel => ({ socket: null, pending: [] }));\n const c = useStatewireConn({\n url: options.url,\n onChange: options.onChange,\n ctx,\n attemptOnce: (c, abort) => attemptSocket(c, w, options, abort),\n });\n const [link] = useState(\n (): RemoteLink => ({\n get connection() {\n return c.connection;\n },\n send: (args) => sendCommand(w, args),\n }),\n );\n return link;\n};\n\nconst useStatewireWS = (\n options: StatewireClient.WSOptions,\n): Statewire<any, any, any> => useStatewireRemote(options, useWsLink);\n\nexport const StatewireWS = resource(useStatewireWS) as <\n TState = any,\n TCommands extends Statewire.Commands = Statewire.Commands,\n TEvent = any,\n>(\n options: StatewireClient.WSOptions,\n) => ResourceElement<Statewire<TState | undefined, TCommands, TEvent>>;\n"],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,107 +1,62 @@
|
|
|
1
|
+
import { StatewireClient } from "./statewire.js";
|
|
1
2
|
import { StatewirePath } from "./wire/ops.js";
|
|
2
|
-
import { StatewireConnection } from "./transports/sse.js";
|
|
3
|
-
import { ResourceElement } from "@assistant-ui/tap";
|
|
4
3
|
//#region src/types.d.ts
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
type
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
type
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
type
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
transport: ResourceElement<StatewireTransport<TState, TCommands, TEvent>>;
|
|
50
|
-
optimistic?: StatewireOptimistic<NonNullable<TState>, TCommands>;
|
|
51
|
-
onEvent?: (event: TEvent, ctx: {
|
|
52
|
-
state: NonNullable<TState>;
|
|
53
|
-
}) => void;
|
|
54
|
-
onStateChange?: (state: NonNullable<TState>, ctx: {
|
|
55
|
-
changes: StatewireChanges;
|
|
56
|
-
}) => void;
|
|
57
|
-
onCommandChange?: (update: StatewireCommandUpdate<TCommands>, ctx: {
|
|
58
|
-
state: NonNullable<TState>;
|
|
59
|
-
}) => void;
|
|
60
|
-
};
|
|
61
|
-
type StatewireHelpers<TState, TCommands extends StatewireCommands = StatewireCommands> = {
|
|
62
|
-
/** The transport's state type — remote transports include `undefined` until the first attach snapshot applies. */
|
|
4
|
+
declare namespace Statewire {
|
|
5
|
+
type Commands = Record<string, (...args: never[]) => unknown>;
|
|
6
|
+
type Command<TCommands extends Commands = Commands> = { [K in keyof TCommands]: {
|
|
7
|
+
method: K;
|
|
8
|
+
params: Parameters<TCommands[K]>;
|
|
9
|
+
}; }[keyof TCommands];
|
|
10
|
+
type CommandsProxy<TCommands extends Commands> = { [K in keyof TCommands]: (...args: Parameters<TCommands[K]>) => Promise<Awaited<ReturnType<TCommands[K]>>>; };
|
|
11
|
+
type CommandUpdate<TCommands extends Commands = Commands> = { [K in keyof TCommands]: {
|
|
12
|
+
method: K;
|
|
13
|
+
params: Parameters<TCommands[K]>;
|
|
14
|
+
seq: number;
|
|
15
|
+
status: "queued" | "posted" | "acked" | "settled";
|
|
16
|
+
result?: unknown;
|
|
17
|
+
failure?: StatewireClient.SendFailure;
|
|
18
|
+
}; }[keyof TCommands];
|
|
19
|
+
/** Push-based canonical state feed a statewire hands to the client core. */
|
|
20
|
+
type StateSource = {
|
|
21
|
+
snapshot: () => unknown;
|
|
22
|
+
/** Drain the paths changed since the last take (`[]` entry = whole state). */
|
|
23
|
+
takeChanged: () => StatewirePath[];
|
|
24
|
+
/** Synchronous, per change; the consumer owns coalescing. */
|
|
25
|
+
setOnChange: (listener: (() => void) | null) => void;
|
|
26
|
+
};
|
|
27
|
+
type Op = {
|
|
28
|
+
op: "replace";
|
|
29
|
+
path: StatewirePath;
|
|
30
|
+
value: unknown;
|
|
31
|
+
} | {
|
|
32
|
+
op: "add";
|
|
33
|
+
path: StatewirePath;
|
|
34
|
+
value: unknown;
|
|
35
|
+
} | {
|
|
36
|
+
op: "remove";
|
|
37
|
+
path: StatewirePath;
|
|
38
|
+
} | {
|
|
39
|
+
op: "event";
|
|
40
|
+
value: object;
|
|
41
|
+
};
|
|
42
|
+
type Changes = {
|
|
43
|
+
isChangedAt(path: readonly (string | number)[]): boolean;
|
|
44
|
+
getChangedKeys(path: readonly (string | number)[]): string[];
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
interface Statewire<TState = any, TCommands extends Statewire.Commands = Statewire.Commands, TEvent = any> {
|
|
63
48
|
state: TState;
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
* "crashed" = acked but the processing died, "result-unavailable" = acked
|
|
72
|
-
* but the result is gone.
|
|
73
|
-
* cause is which channel settled it: "server" = the server's answer;
|
|
74
|
-
* the rest are channel deaths the client settled locally.
|
|
75
|
-
*/
|
|
76
|
-
type SendFailure = {
|
|
77
|
-
fate: "rejected";
|
|
78
|
-
cause: "server";
|
|
79
|
-
message: string;
|
|
80
|
-
payload?: unknown;
|
|
81
|
-
} | {
|
|
82
|
-
fate: "unknown-command";
|
|
83
|
-
cause: "server";
|
|
84
|
-
} | {
|
|
85
|
-
fate: "invalid-params";
|
|
86
|
-
cause: "server";
|
|
87
|
-
message: string;
|
|
88
|
-
} | {
|
|
89
|
-
fate: "crashed";
|
|
90
|
-
cause: "server";
|
|
91
|
-
} | {
|
|
92
|
-
fate: "result-unavailable";
|
|
93
|
-
cause: "server" | "unmount" | "stream-gone" | "session-lost" | "superseded";
|
|
94
|
-
} | {
|
|
95
|
-
fate: "aborted";
|
|
96
|
-
cause: "cascade" | "unmount" | "stream-gone" | "session-lost" | "superseded";
|
|
97
|
-
} | {
|
|
98
|
-
fate: "lost";
|
|
99
|
-
cause: "unmount" | "stream-gone" | "session-lost" | "superseded";
|
|
100
|
-
};
|
|
49
|
+
commands: Statewire.CommandsProxy<TCommands>;
|
|
50
|
+
emit?: (event: TEvent) => void;
|
|
51
|
+
connection?: StatewireClient.Connection;
|
|
52
|
+
source?: Statewire.StateSource;
|
|
53
|
+
/** Replace this client's ambient context on the server; absent on transports without a client context channel. */
|
|
54
|
+
setContext?: (value: Record<string, unknown>) => Promise<unknown>;
|
|
55
|
+
}
|
|
101
56
|
declare class StatewireSendError extends Error {
|
|
102
|
-
readonly failure: SendFailure;
|
|
103
|
-
constructor(failure: SendFailure);
|
|
57
|
+
readonly failure: StatewireClient.SendFailure;
|
|
58
|
+
constructor(failure: StatewireClient.SendFailure);
|
|
104
59
|
}
|
|
105
60
|
//#endregion
|
|
106
|
-
export {
|
|
61
|
+
export { Statewire, StatewireSendError };
|
|
107
62
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","names":[],"sources":["../src/types.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"types.d.ts","names":[],"sources":["../src/types.ts"],"mappings":";;;kBAGiB;OACH,WAAW,mBAAmB;OAE9B,QAAQ,kBAAkB,WAAW,eAC9C,WAAW;IAAc,QAAQ;IAAG,QAAQ,WAAW,UAAU;aAC5D;OAEI,cAAc,kBAAkB,eACzC,WAAW,gBACP,MAAM,WAAW,UAAU,QAC3B,QAAQ,QAAQ,WAAW,UAAU;OAGhC,cAAc,kBAAkB,WAAW,eACpD,WAAW;IACV,QAAQ;IACR,QAAQ,WAAW,UAAU;IAC7B;IACA;IACA;IACA,UAAU,gBAAgB;aAEtB;;OAGI;IACV;;IAEA,mBAAmB;;IAEnB,cAAc;;OAGJ;IACN;IAAe,MAAM;IAAe;;IACpC;IAAW,MAAM;IAAe;;IAChC;IAAc,MAAM;;IACpB;IAAa;;OAEP;IACV,YAAY;IACZ,eAAe;;;UAIF,UACf,cACA,kBAAkB,UAAU,WAAW,UAAU,UACjD;EAEA,OAAO;EACP,UAAU,UAAU,cAAc;EAClC,QAAQ,OAAO;EACf,aAAa,gBAAgB;EAC7B,SAAS,UAAU;;EAEnB,cAAc,OAAO,4BAA4B;;cAsBtC,2BAA2B;WAC7B,SAAS,gBAAgB;EAEtB,YAAA,SAAS,gBAAgB"}
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","names":["
|
|
1
|
+
{"version":3,"file":"types.js","names":["StatewireClient","StatewirePath","Statewire","Commands","Record","args","Command","TCommands","method","K","params","Parameters","CommandsProxy","Promise","Awaited","ReturnType","CommandUpdate","seq","status","result","failure","SendFailure","StateSource","snapshot","takeChanged","setOnChange","listener","Op","op","path","value","Changes","isChangedAt","getChangedKeys","state","TState","commands","emit","event","TEvent","connection","Connection","source","setContext","describe","fate","message","cause","StatewireSendError","Error","constructor","name"],"sources":["../src/types.ts"],"sourcesContent":["import type { StatewireClient } from \"./statewire\";\nimport type { StatewirePath } from \"./wire/ops\";\n\nexport namespace Statewire {\n export type Commands = Record<string, (...args: never[]) => unknown>;\n\n export type Command<TCommands extends Commands = Commands> = {\n [K in keyof TCommands]: { method: K; params: Parameters<TCommands[K]> };\n }[keyof TCommands];\n\n export type CommandsProxy<TCommands extends Commands> = {\n [K in keyof TCommands]: (\n ...args: Parameters<TCommands[K]>\n ) => Promise<Awaited<ReturnType<TCommands[K]>>>;\n };\n\n export type CommandUpdate<TCommands extends Commands = Commands> = {\n [K in keyof TCommands]: {\n method: K;\n params: Parameters<TCommands[K]>;\n seq: number;\n status: \"queued\" | \"posted\" | \"acked\" | \"settled\";\n result?: unknown;\n failure?: StatewireClient.SendFailure;\n };\n }[keyof TCommands];\n\n /** Push-based canonical state feed a statewire hands to the client core. */\n export type StateSource = {\n snapshot: () => unknown;\n /** Drain the paths changed since the last take (`[]` entry = whole state). */\n takeChanged: () => StatewirePath[];\n /** Synchronous, per change; the consumer owns coalescing. */\n setOnChange: (listener: (() => void) | null) => void;\n };\n\n export type Op =\n | { op: \"replace\"; path: StatewirePath; value: unknown }\n | { op: \"add\"; path: StatewirePath; value: unknown }\n | { op: \"remove\"; path: StatewirePath }\n | { op: \"event\"; value: object };\n\n export type Changes = {\n isChangedAt(path: readonly (string | number)[]): boolean;\n getChangedKeys(path: readonly (string | number)[]): string[];\n };\n}\n\nexport interface Statewire<\n TState = any,\n TCommands extends Statewire.Commands = Statewire.Commands,\n TEvent = any,\n> {\n state: TState;\n commands: Statewire.CommandsProxy<TCommands>;\n emit?: (event: TEvent) => void;\n connection?: StatewireClient.Connection;\n source?: Statewire.StateSource;\n /** Replace this client's ambient context on the server; absent on transports without a client context channel. */\n setContext?: (value: Record<string, unknown>) => Promise<unknown>;\n}\n\nconst describe = (failure: StatewireClient.SendFailure): string => {\n switch (failure.fate) {\n case \"rejected\":\n return `statewire: command rejected: ${failure.message}`;\n case \"unknown-command\":\n return \"statewire: unknown command\";\n case \"invalid-params\":\n return `statewire: invalid params: ${failure.message}`;\n case \"aborted\":\n return `statewire: command aborted (${failure.cause})`;\n case \"lost\":\n return `statewire: command lost (${failure.cause})`;\n case \"crashed\":\n return \"statewire: command crashed\";\n case \"result-unavailable\":\n return `statewire: command result unavailable (${failure.cause})`;\n }\n};\n\nexport class StatewireSendError extends Error {\n readonly failure: StatewireClient.SendFailure;\n\n constructor(failure: StatewireClient.SendFailure) {\n super(describe(failure));\n this.name = \"StatewireSendError\";\n this.failure = failure;\n }\n}\n"],"mappings":";AA8DA,MAAM4C,YAAYxB,YAAiD;CACjE,QAAQA,QAAQyB,MAAhB;EACE,KAAK,YACH,OAAO,gCAAgCzB,QAAQ0B;EACjD,KAAK,mBACH,OAAO;EACT,KAAK,kBACH,OAAO,8BAA8B1B,QAAQ0B;EAC/C,KAAK,WACH,OAAO,+BAA+B1B,QAAQ2B,MAAK;EACrD,KAAK,QACH,OAAO,4BAA4B3B,QAAQ2B,MAAK;EAClD,KAAK,WACH,OAAO;EACT,KAAK,sBACH,OAAO,0CAA0C3B,QAAQ2B,MAAK;CAClE;AACF;AAEA,IAAaC,qBAAb,cAAwCC,MAAM;CAC5C;CAEAC,YAAY9B,SAAsC;EAChD,MAAMwB,SAASxB,OAAO,CAAC;EACvB,KAAK+B,OAAO;EACZ,KAAK/B,UAAUA;CACjB;AACF"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
//#region src/util/draftTraps.d.ts
|
|
2
|
+
type SharedTraps = Pick<ProxyHandler<object>, "defineProperty" | "setPrototypeOf" | "preventExtensions" | "ownKeys" | "getOwnPropertyDescriptor">;
|
|
3
|
+
declare const sharedDraftTraps: (current: () => object, context: string) => SharedTraps;
|
|
4
|
+
//#endregion
|
|
5
|
+
export { sharedDraftTraps };
|
|
6
|
+
//# sourceMappingURL=draftTraps.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"draftTraps.d.ts","names":[],"sources":["../../src/util/draftTraps.ts"],"mappings":";KAAK,cAAc,KACjB;cAQW,mBACX,uBACA,oBACC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
//#region src/util/draftTraps.ts
|
|
2
|
+
const sharedDraftTraps = (current, context) => {
|
|
3
|
+
const unsupported = (op) => {
|
|
4
|
+
throw new Error(`statewire: ${op} is not supported ${context}`);
|
|
5
|
+
};
|
|
6
|
+
return {
|
|
7
|
+
defineProperty: () => unsupported("defineProperty"),
|
|
8
|
+
setPrototypeOf: () => unsupported("setPrototypeOf"),
|
|
9
|
+
preventExtensions: () => unsupported("preventExtensions"),
|
|
10
|
+
ownKeys: () => Reflect.ownKeys(current()),
|
|
11
|
+
getOwnPropertyDescriptor: (_target, prop) => {
|
|
12
|
+
const node = current();
|
|
13
|
+
const desc = Reflect.getOwnPropertyDescriptor(node, prop);
|
|
14
|
+
if (!desc) return void 0;
|
|
15
|
+
return {
|
|
16
|
+
...desc,
|
|
17
|
+
configurable: !Array.isArray(node) || prop !== "length"
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
//#endregion
|
|
23
|
+
export { sharedDraftTraps };
|
|
24
|
+
|
|
25
|
+
//# sourceMappingURL=draftTraps.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"draftTraps.js","names":["SharedTraps","Pick","ProxyHandler","sharedDraftTraps","current","context","unsupported","op","Error","defineProperty","setPrototypeOf","preventExtensions","ownKeys","Reflect","getOwnPropertyDescriptor","_target","prop","node","desc","undefined","configurable","Array","isArray"],"sources":["../../src/util/draftTraps.ts"],"sourcesContent":["type SharedTraps = Pick<\n ProxyHandler<object>,\n | \"defineProperty\"\n | \"setPrototypeOf\"\n | \"preventExtensions\"\n | \"ownKeys\"\n | \"getOwnPropertyDescriptor\"\n>;\n\nexport const sharedDraftTraps = (\n current: () => object,\n context: string,\n): SharedTraps => {\n const unsupported = (op: string): never => {\n throw new Error(`statewire: ${op} is not supported ${context}`);\n };\n return {\n defineProperty: () => unsupported(\"defineProperty\"),\n setPrototypeOf: () => unsupported(\"setPrototypeOf\"),\n preventExtensions: () => unsupported(\"preventExtensions\"),\n ownKeys: () => Reflect.ownKeys(current()),\n getOwnPropertyDescriptor: (_target, prop) => {\n const node = current();\n const desc = Reflect.getOwnPropertyDescriptor(node, prop);\n if (!desc) return undefined;\n return {\n ...desc,\n configurable: !Array.isArray(node) || prop !== \"length\",\n };\n },\n };\n};\n"],"mappings":";AASA,MAAaG,oBACXC,SACAC,YACgB;CAChB,MAAMC,eAAeC,OAAsB;EACzC,MAAM,IAAIC,MAAM,cAAcD,GAAE,oBAAqBF,SAAS;CAChE;CACA,OAAO;EACLI,sBAAsBH,YAAY,gBAAgB;EAClDI,sBAAsBJ,YAAY,gBAAgB;EAClDK,yBAAyBL,YAAY,mBAAmB;EACxDM,eAAeC,QAAQD,QAAQR,QAAQ,CAAC;EACxCU,2BAA2BC,SAASC,SAAS;GAC3C,MAAMC,OAAOb,QAAQ;GACrB,MAAMc,OAAOL,QAAQC,yBAAyBG,MAAMD,IAAI;GACxD,IAAI,CAACE,MAAM,OAAOC,KAAAA;GAClB,OAAO;IACL,GAAGD;IACHE,cAAc,CAACC,MAAMC,QAAQL,IAAI,KAAKD,SAAS;GACjD;EACF;CACF;AACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"macrotask.d.ts","names":[],"sources":["../../src/util/macrotask.ts"],"mappings":";cAIa,wBAAyB"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
//#region src/util/macrotask.ts
|
|
2
|
+
const createMacrotaskPoster = (callback) => {
|
|
3
|
+
if (typeof MessageChannel !== "undefined") {
|
|
4
|
+
let port1 = null;
|
|
5
|
+
let port2;
|
|
6
|
+
return () => {
|
|
7
|
+
if (!port1) {
|
|
8
|
+
const channel = new MessageChannel();
|
|
9
|
+
channel.port1.onmessage = () => {
|
|
10
|
+
port1?.unref?.();
|
|
11
|
+
callback();
|
|
12
|
+
};
|
|
13
|
+
port1 = channel.port1;
|
|
14
|
+
port2 = channel.port2;
|
|
15
|
+
}
|
|
16
|
+
port1.ref?.();
|
|
17
|
+
port2.postMessage(null);
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
return () => setTimeout(callback, 0);
|
|
21
|
+
};
|
|
22
|
+
//#endregion
|
|
23
|
+
export { createMacrotaskPoster };
|
|
24
|
+
|
|
25
|
+
//# sourceMappingURL=macrotask.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"macrotask.js","names":["createMacrotaskPoster","callback","MessageChannel","port1","MessagePort","ref","unref","port2","channel","onmessage","postMessage","setTimeout"],"sources":["../../src/util/macrotask.ts"],"sourcesContent":["// MessageChannel schedules the flush as a macrotask (tap's pattern): it runs\n// after the whole microtask drain, so every producer in the current turn\n// coalesces. The port is ref'd only while a flush is pending — an active\n// MessagePort holds the Node event loop open. ref/unref are Node-only.\nexport const createMacrotaskPoster = (callback: () => void): (() => void) => {\n if (typeof MessageChannel !== \"undefined\") {\n let port1: (MessagePort & { ref?: () => void; unref?: () => void }) | null =\n null;\n let port2: MessagePort;\n return () => {\n if (!port1) {\n const channel = new MessageChannel();\n channel.port1.onmessage = () => {\n port1?.unref?.();\n callback();\n };\n port1 = channel.port1;\n port2 = channel.port2;\n }\n port1.ref?.();\n port2!.postMessage(null);\n };\n }\n return () => setTimeout(callback, 0);\n};\n"],"mappings":";AAIA,MAAaA,yBAAyBC,aAAuC;CAC3E,IAAI,OAAOC,mBAAmB,aAAa;EACzC,IAAIC,QACF;EACF,IAAII;EACJ,aAAa;GACX,IAAI,CAACJ,OAAO;IACV,MAAMK,UAAU,IAAIN,eAAe;IACnCM,QAAQL,MAAMM,kBAAkB;KAC9BN,OAAOG,QAAQ;KACfL,SAAS;IACX;IACAE,QAAQK,QAAQL;IAChBI,QAAQC,QAAQD;GAClB;GACAJ,MAAME,MAAM;GACZE,MAAOG,YAAY,IAAI;EACzB;CACF;CACA,aAAaC,WAAWV,UAAU,CAAC;AACrC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"methodProxy.d.ts","names":[],"sources":["../../src/util/methodProxy.ts"],"mappings":";cAAa,oBAAqB,kBAChC,WAAW,gBAAgB,sBAAsB,qBAChD"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
//#region src/util/methodProxy.ts
|
|
2
|
+
const createMethodProxy = (dispatch) => {
|
|
3
|
+
const memo = /* @__PURE__ */ new Map();
|
|
4
|
+
return new Proxy({}, { get: (_target, method) => {
|
|
5
|
+
if (typeof method !== "string") return void 0;
|
|
6
|
+
let fn = memo.get(method);
|
|
7
|
+
if (fn === void 0) {
|
|
8
|
+
fn = (...params) => dispatch(method, params);
|
|
9
|
+
memo.set(method, fn);
|
|
10
|
+
}
|
|
11
|
+
return fn;
|
|
12
|
+
} });
|
|
13
|
+
};
|
|
14
|
+
//#endregion
|
|
15
|
+
export { createMethodProxy };
|
|
16
|
+
|
|
17
|
+
//# sourceMappingURL=methodProxy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"methodProxy.js","names":["createMethodProxy","dispatch","method","params","Promise","T","memo","Map","Proxy","get","_target","undefined","fn","set"],"sources":["../../src/util/methodProxy.ts"],"sourcesContent":["export const createMethodProxy = <T extends object>(\n dispatch: (method: string, params: unknown[]) => Promise<unknown>,\n): T => {\n const memo = new Map<string, (...params: unknown[]) => Promise<unknown>>();\n return new Proxy({} as T, {\n get: (_target, method) => {\n if (typeof method !== \"string\") return undefined;\n let fn = memo.get(method);\n if (fn === undefined) {\n fn = (...params: unknown[]) => dispatch(method, params);\n memo.set(method, fn);\n }\n return fn;\n },\n });\n};\n"],"mappings":";AAAA,MAAaA,qBACXC,aACM;CACN,MAAMK,uBAAO,IAAIC,IAAwD;CACzE,OAAO,IAAIC,MAAM,CAAC,GAAQ,EACxBC,MAAMC,SAASR,WAAW;EACxB,IAAI,OAAOA,WAAW,UAAU,OAAOS,KAAAA;EACvC,IAAIC,KAAKN,KAAKG,IAAIP,MAAM;EACxB,IAAIU,OAAOD,KAAAA,GAAW;GACpBC,MAAM,GAAGT,WAAsBF,SAASC,QAAQC,MAAM;GACtDG,KAAKO,IAAIX,QAAQU,EAAE;EACrB;EACA,OAAOA;CACT,EACF,CAAC;AACH"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"randomId.d.ts","names":[],"sources":["../../src/util/randomId.ts"],"mappings":";cAAa"}
|