statewire 0.0.0-0 → 0.0.2
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 +84 -1
- package/dist/client/changes.d.ts +7 -0
- package/dist/client/changes.d.ts.map +1 -0
- package/dist/client/changes.js +25 -0
- package/dist/client/changes.js.map +1 -0
- package/dist/client/connection.d.ts +63 -0
- package/dist/client/connection.d.ts.map +1 -0
- package/dist/client/connection.js +211 -0
- package/dist/client/connection.js.map +1 -0
- package/dist/client/core.d.ts +14 -0
- package/dist/client/core.d.ts.map +1 -0
- package/dist/client/core.js +272 -0
- package/dist/client/core.js.map +1 -0
- package/dist/client/session.d.ts +71 -0
- package/dist/client/session.d.ts.map +1 -0
- package/dist/client/session.js +529 -0
- package/dist/client/session.js.map +1 -0
- package/dist/client/sessionStore.d.ts +16 -0
- package/dist/client/sessionStore.d.ts.map +1 -0
- package/dist/client/sessionStore.js +14 -0
- package/dist/client/sessionStore.js.map +1 -0
- package/dist/client/timing.d.ts +11 -0
- package/dist/client/timing.d.ts.map +1 -0
- package/dist/client/timing.js +15 -0
- package/dist/client/timing.js.map +1 -0
- 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 +28 -0
- package/dist/host/draft.d.ts.map +1 -0
- package/dist/host/draft.js +211 -0
- package/dist/host/draft.js.map +1 -0
- package/dist/host/engine.d.ts +14 -0
- package/dist/host/engine.d.ts.map +1 -0
- package/dist/host/engine.js +17 -0
- package/dist/host/engine.js.map +1 -0
- package/dist/host/host.d.ts +62 -0
- package/dist/host/host.d.ts.map +1 -0
- package/dist/host/host.js +331 -0
- package/dist/host/host.js.map +1 -0
- package/dist/host/socket.d.ts +14 -0
- package/dist/host/socket.d.ts.map +1 -0
- package/dist/host/socket.js +459 -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 +44 -0
- package/dist/host.d.ts.map +1 -0
- package/dist/host.js +4 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +5 -0
- package/dist/statewire.d.ts +104 -0
- package/dist/statewire.d.ts.map +1 -0
- package/dist/statewire.js +53 -0
- package/dist/statewire.js.map +1 -0
- 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 +12 -0
- package/dist/transports/remote.d.ts.map +1 -0
- package/dist/transports/remote.js +21 -0
- package/dist/transports/remote.js.map +1 -0
- package/dist/transports/sse-parser.d.ts +5 -0
- package/dist/transports/sse-parser.d.ts.map +1 -0
- package/dist/transports/sse-parser.js +26 -0
- package/dist/transports/sse-parser.js.map +1 -0
- package/dist/transports/sse.d.ts +64 -0
- package/dist/transports/sse.d.ts.map +1 -0
- package/dist/transports/sse.js +137 -0
- package/dist/transports/sse.js.map +1 -0
- package/dist/transports/testing.d.ts +32 -0
- package/dist/transports/testing.d.ts.map +1 -0
- package/dist/transports/testing.js +94 -0
- package/dist/transports/testing.js.map +1 -0
- package/dist/transports/ws.d.ts +9 -0
- package/dist/transports/ws.d.ts.map +1 -0
- package/dist/transports/ws.js +169 -0
- package/dist/transports/ws.js.map +1 -0
- package/dist/types.d.ts +60 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +24 -0
- package/dist/types.js.map +1 -0
- 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/util/recordMutations.d.ts +10 -0
- package/dist/util/recordMutations.d.ts.map +1 -0
- package/dist/util/recordMutations.js +109 -0
- 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 +27 -0
- package/dist/wire/meta.d.ts.map +1 -0
- package/dist/wire/meta.js +75 -0
- package/dist/wire/meta.js.map +1 -0
- package/dist/wire/ops.d.ts +19 -0
- package/dist/wire/ops.d.ts.map +1 -0
- package/dist/wire/ops.js +112 -0
- package/dist/wire/ops.js.map +1 -0
- package/package.json +52 -5
- package/src/client/changes.ts +38 -0
- package/src/client/connection.ts +301 -0
- package/src/client/core.ts +312 -0
- package/src/client/session.ts +696 -0
- package/src/client/sessionStore.ts +23 -0
- package/src/client/timing.ts +14 -0
- package/src/host/adapter.ts +33 -0
- package/src/host/draft.ts +323 -0
- package/src/host/engine.ts +13 -0
- package/src/host/host.ts +482 -0
- package/src/host/socket.ts +542 -0
- package/src/host-internal.ts +28 -0
- package/src/host.ts +61 -0
- package/src/index.ts +5 -0
- package/src/statewire.ts +200 -0
- package/src/transports/fake-sse.ts +51 -0
- package/src/transports/fixtures.ts +60 -0
- package/src/transports/remote.ts +30 -0
- package/src/transports/sse-parser.ts +24 -0
- package/src/transports/sse.ts +267 -0
- package/src/transports/testing.ts +123 -0
- package/src/transports/ws.ts +256 -0
- package/src/types.ts +88 -0
- 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/util/recordMutations.ts +0 -0
- package/src/util/statePath.ts +61 -0
- package/src/wire/meta.ts +101 -0
- package/src/wire/ops.ts +202 -0
- package/index.js +0 -1
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
import { applyOps, sanitizeValue } from "../wire/ops.js";
|
|
2
|
+
import { StatewireReject } from "./engine.js";
|
|
3
|
+
import { createStateDraft } from "./draft.js";
|
|
4
|
+
import { createMethodProxy } from "../util/methodProxy.js";
|
|
5
|
+
import { StatewireSendError } from "../types.js";
|
|
6
|
+
import { useEffect, useState } from "@assistant-ui/tap/react-shim";
|
|
7
|
+
//#region src/host/host.ts
|
|
8
|
+
const isDev = () => typeof process === "undefined" || process.env["NODE_ENV"] !== "production";
|
|
9
|
+
const stateHosts = /* @__PURE__ */ new WeakMap();
|
|
10
|
+
/** Host-side accessor for a `useStatewireState` state object's source (`snapshot()` reads the committed state). */
|
|
11
|
+
const getStateHost = (state) => stateHosts.get(state);
|
|
12
|
+
const useStatewireState = (init) => {
|
|
13
|
+
const [, setVersion] = useState(0);
|
|
14
|
+
const [cell] = useState(() => {
|
|
15
|
+
const commit = () => {
|
|
16
|
+
if (c.draft) c.current = c.draft.flush();
|
|
17
|
+
return c.current;
|
|
18
|
+
};
|
|
19
|
+
const c = {
|
|
20
|
+
current: sanitizeValue(init()),
|
|
21
|
+
draft: null,
|
|
22
|
+
changed: [[]],
|
|
23
|
+
onOp: null,
|
|
24
|
+
onChange: null,
|
|
25
|
+
bump: () => setVersion((v) => v + 1),
|
|
26
|
+
ctl: {
|
|
27
|
+
apply: (ops) => {
|
|
28
|
+
const result = applyOps(commit(), ops);
|
|
29
|
+
if (result.events.length > 0) throw new Error("statewire: event ops do not apply to state — route them to emit");
|
|
30
|
+
c.current = result.state;
|
|
31
|
+
c.draft?.invalidate();
|
|
32
|
+
c.changed.push(...result.changedPaths);
|
|
33
|
+
if (c.onOp) for (const op of ops) c.onOp(op);
|
|
34
|
+
c.bump();
|
|
35
|
+
c.onChange?.();
|
|
36
|
+
},
|
|
37
|
+
snapshot: commit
|
|
38
|
+
},
|
|
39
|
+
host: {
|
|
40
|
+
snapshot: commit,
|
|
41
|
+
setOnOp: (listener) => {
|
|
42
|
+
c.onOp = listener;
|
|
43
|
+
},
|
|
44
|
+
setOnChange: (listener_0) => {
|
|
45
|
+
c.onChange = listener_0;
|
|
46
|
+
},
|
|
47
|
+
takeChanged: () => {
|
|
48
|
+
const changed = c.changed;
|
|
49
|
+
c.changed = [];
|
|
50
|
+
return changed;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
return c;
|
|
55
|
+
});
|
|
56
|
+
let value = cell.ctl.snapshot();
|
|
57
|
+
if (typeof value === "object" && value !== null) {
|
|
58
|
+
cell.draft ??= createStateDraft({
|
|
59
|
+
snapshot: () => cell.current,
|
|
60
|
+
record: (op, changedPath) => {
|
|
61
|
+
cell.changed.push(changedPath);
|
|
62
|
+
cell.onOp?.(op);
|
|
63
|
+
cell.bump();
|
|
64
|
+
cell.onChange?.();
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
stateHosts.set(cell.draft.proxy, cell.host);
|
|
68
|
+
value = cell.draft.proxy;
|
|
69
|
+
}
|
|
70
|
+
return [value, cell.ctl];
|
|
71
|
+
};
|
|
72
|
+
const executionStates = /* @__PURE__ */ new WeakMap();
|
|
73
|
+
/**
|
|
74
|
+
* `CommandExecution(executor)` runs the (possibly async) `executor({ ack })`
|
|
75
|
+
* immediately: its return value resolves the execution, a throw/rejection
|
|
76
|
+
* rejects it; `ack()` releases the client's ack watermark before the executor
|
|
77
|
+
* finishes. `CommandExecution.withResolvers()` returns `[execution,
|
|
78
|
+
* { ack, resolve, reject }]` instead — settle them from your own spawned work.
|
|
79
|
+
*/
|
|
80
|
+
const CommandExecution = Object.assign((executor) => {
|
|
81
|
+
const state = {
|
|
82
|
+
acked: false,
|
|
83
|
+
settled: null,
|
|
84
|
+
bind: null
|
|
85
|
+
};
|
|
86
|
+
const execution = Object.freeze({});
|
|
87
|
+
executionStates.set(execution, state);
|
|
88
|
+
const settle = (settled) => {
|
|
89
|
+
if (state.settled) return;
|
|
90
|
+
state.settled = settled;
|
|
91
|
+
state.acked = true;
|
|
92
|
+
state.bind?.onSettle(settled);
|
|
93
|
+
};
|
|
94
|
+
const ack = () => {
|
|
95
|
+
if (state.acked) return;
|
|
96
|
+
state.acked = true;
|
|
97
|
+
state.bind?.onAck();
|
|
98
|
+
};
|
|
99
|
+
(async () => {
|
|
100
|
+
try {
|
|
101
|
+
settle({
|
|
102
|
+
type: "resolved",
|
|
103
|
+
value: await executor({ ack })
|
|
104
|
+
});
|
|
105
|
+
} catch (error) {
|
|
106
|
+
settle({
|
|
107
|
+
type: "rejected",
|
|
108
|
+
error
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
})();
|
|
112
|
+
return execution;
|
|
113
|
+
}, { withResolvers: () => {
|
|
114
|
+
let resolve;
|
|
115
|
+
let reject;
|
|
116
|
+
const promise = new Promise((res, rej) => {
|
|
117
|
+
resolve = res;
|
|
118
|
+
reject = rej;
|
|
119
|
+
});
|
|
120
|
+
let ack;
|
|
121
|
+
return [CommandExecution(({ ack: a }) => {
|
|
122
|
+
ack = a;
|
|
123
|
+
return promise;
|
|
124
|
+
}), {
|
|
125
|
+
ack: () => ack(),
|
|
126
|
+
resolve,
|
|
127
|
+
reject
|
|
128
|
+
}];
|
|
129
|
+
} });
|
|
130
|
+
const commandsHosts = /* @__PURE__ */ new WeakMap();
|
|
131
|
+
const getCommandsHost = (commands) => commandsHosts.get(commands);
|
|
132
|
+
const bindCommandsHost = (commands, host) => {
|
|
133
|
+
commandsHosts.set(commands, host);
|
|
134
|
+
};
|
|
135
|
+
const STALL_WARN_MS = 5e3;
|
|
136
|
+
const toSendError = (error) => error instanceof StatewireSendError ? error : new StatewireSendError({
|
|
137
|
+
fate: "rejected",
|
|
138
|
+
cause: "server",
|
|
139
|
+
message: error instanceof Error ? error.message : String(error),
|
|
140
|
+
...error instanceof StatewireReject && error.payload !== void 0 && { payload: error.payload }
|
|
141
|
+
});
|
|
142
|
+
const ackInvocation = (cell, inv) => {
|
|
143
|
+
if (inv.acked) return;
|
|
144
|
+
inv.acked = true;
|
|
145
|
+
cell.listener?.onAck(inv);
|
|
146
|
+
inv.origin?.onAck?.();
|
|
147
|
+
};
|
|
148
|
+
const settleInvocation = (cell, inv, call, settled) => {
|
|
149
|
+
ackInvocation(cell, inv);
|
|
150
|
+
if (settled.type === "resolved") {
|
|
151
|
+
const outcome = settled.value === void 0 ? { type: "accepted" } : {
|
|
152
|
+
type: "accepted",
|
|
153
|
+
payload: sanitizeValue(settled.value)
|
|
154
|
+
};
|
|
155
|
+
cell.listener?.onSettle(inv, outcome);
|
|
156
|
+
inv.origin?.onSettle?.(outcome);
|
|
157
|
+
call.resolve(outcome.payload);
|
|
158
|
+
} else {
|
|
159
|
+
const error = toSendError(settled.error);
|
|
160
|
+
const outcome = {
|
|
161
|
+
type: "rejected",
|
|
162
|
+
error
|
|
163
|
+
};
|
|
164
|
+
cell.listener?.onSettle(inv, outcome);
|
|
165
|
+
inv.origin?.onSettle?.(outcome);
|
|
166
|
+
call.reject(error);
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
const pump = (cell) => {
|
|
170
|
+
if (cell.running || !cell.handlers) {
|
|
171
|
+
watchStall(cell);
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
const call = cell.queue.shift();
|
|
175
|
+
if (!call) return;
|
|
176
|
+
const handler = cell.handlers[call.method];
|
|
177
|
+
if (handler === void 0) {
|
|
178
|
+
const error = new StatewireSendError({
|
|
179
|
+
fate: "unknown-command",
|
|
180
|
+
cause: "server"
|
|
181
|
+
});
|
|
182
|
+
call.origin?.onSettle?.({
|
|
183
|
+
type: "rejected",
|
|
184
|
+
error
|
|
185
|
+
});
|
|
186
|
+
call.reject(error);
|
|
187
|
+
pump(cell);
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
const inv = {
|
|
191
|
+
method: call.method,
|
|
192
|
+
params: call.params,
|
|
193
|
+
ts: call.ts,
|
|
194
|
+
seq: ++cell.seq,
|
|
195
|
+
acked: false,
|
|
196
|
+
...call.origin !== void 0 && { origin: call.origin },
|
|
197
|
+
...call.origin?.clientId !== void 0 && { clientId: call.origin.clientId }
|
|
198
|
+
};
|
|
199
|
+
cell.running = true;
|
|
200
|
+
cell.listener?.onStart(inv);
|
|
201
|
+
cell.listener?.onPosted?.(inv);
|
|
202
|
+
cell.listener?.onCovered?.(inv);
|
|
203
|
+
(async () => {
|
|
204
|
+
try {
|
|
205
|
+
const value = await handler(...call.params);
|
|
206
|
+
const execution = typeof value === "object" && value !== null ? executionStates.get(value) : void 0;
|
|
207
|
+
if (execution) {
|
|
208
|
+
if (execution.acked) ackInvocation(cell, inv);
|
|
209
|
+
if (execution.settled) settleInvocation(cell, inv, call, execution.settled);
|
|
210
|
+
else execution.bind = {
|
|
211
|
+
onAck: () => ackInvocation(cell, inv),
|
|
212
|
+
onSettle: (settled) => settleInvocation(cell, inv, call, settled)
|
|
213
|
+
};
|
|
214
|
+
} else settleInvocation(cell, inv, call, {
|
|
215
|
+
type: "resolved",
|
|
216
|
+
value
|
|
217
|
+
});
|
|
218
|
+
} catch (error) {
|
|
219
|
+
settleInvocation(cell, inv, call, {
|
|
220
|
+
type: "rejected",
|
|
221
|
+
error
|
|
222
|
+
});
|
|
223
|
+
} finally {
|
|
224
|
+
cell.running = false;
|
|
225
|
+
pump(cell);
|
|
226
|
+
}
|
|
227
|
+
})();
|
|
228
|
+
};
|
|
229
|
+
const watchStall = (cell) => {
|
|
230
|
+
if (!isDev() || cell.stallTimer !== null || cell.queue.length === 0) return;
|
|
231
|
+
if (cell.handlers) return;
|
|
232
|
+
cell.stallTimer = setTimeout(() => {
|
|
233
|
+
cell.stallTimer = null;
|
|
234
|
+
if (cell.handlers === null && cell.queue.length > 0 && !cell.unmounted) console.warn(`statewire: ${cell.queue.length} buffered command(s) waiting over ${STALL_WARN_MS}ms — did the host forget to arm useStatewireCommands?`);
|
|
235
|
+
}, STALL_WARN_MS);
|
|
236
|
+
};
|
|
237
|
+
const useStatewireCommands = (commands) => {
|
|
238
|
+
const [built] = useState(() => {
|
|
239
|
+
const cell = {
|
|
240
|
+
handlers: null,
|
|
241
|
+
queue: [],
|
|
242
|
+
running: false,
|
|
243
|
+
listener: null,
|
|
244
|
+
seq: 0,
|
|
245
|
+
unmounted: false,
|
|
246
|
+
stallTimer: null
|
|
247
|
+
};
|
|
248
|
+
const proxy = createMethodProxy((method, params) => new Promise((resolve, reject) => {
|
|
249
|
+
if (cell.unmounted) {
|
|
250
|
+
reject(/* @__PURE__ */ new Error("statewire: commands called after unmount"));
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
cell.queue.push({
|
|
254
|
+
method,
|
|
255
|
+
params,
|
|
256
|
+
ts: Date.now(),
|
|
257
|
+
resolve,
|
|
258
|
+
reject
|
|
259
|
+
});
|
|
260
|
+
pump(cell);
|
|
261
|
+
}));
|
|
262
|
+
commandsHosts.set(proxy, {
|
|
263
|
+
setListener: (listener) => {
|
|
264
|
+
cell.listener = listener;
|
|
265
|
+
},
|
|
266
|
+
submit: (origin) => new Promise((resolve_0, reject_0) => {
|
|
267
|
+
if (cell.unmounted) {
|
|
268
|
+
reject_0(/* @__PURE__ */ new Error("statewire: commands called after unmount"));
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
cell.queue.push({
|
|
272
|
+
method: origin.method,
|
|
273
|
+
params: origin.params,
|
|
274
|
+
ts: Date.now(),
|
|
275
|
+
resolve: resolve_0,
|
|
276
|
+
reject: reject_0,
|
|
277
|
+
origin
|
|
278
|
+
});
|
|
279
|
+
pump(cell);
|
|
280
|
+
})
|
|
281
|
+
});
|
|
282
|
+
return {
|
|
283
|
+
cell,
|
|
284
|
+
proxy
|
|
285
|
+
};
|
|
286
|
+
});
|
|
287
|
+
useEffect(() => {
|
|
288
|
+
const { cell: cell_0 } = built;
|
|
289
|
+
cell_0.unmounted = false;
|
|
290
|
+
return () => {
|
|
291
|
+
cell_0.unmounted = true;
|
|
292
|
+
cell_0.handlers = null;
|
|
293
|
+
if (cell_0.stallTimer !== null) {
|
|
294
|
+
clearTimeout(cell_0.stallTimer);
|
|
295
|
+
cell_0.stallTimer = null;
|
|
296
|
+
}
|
|
297
|
+
queueMicrotask(() => {
|
|
298
|
+
if (!cell_0.unmounted) return;
|
|
299
|
+
const queued = cell_0.queue;
|
|
300
|
+
cell_0.queue = [];
|
|
301
|
+
for (const call of queued) call.reject(/* @__PURE__ */ new Error("statewire: unmounted"));
|
|
302
|
+
});
|
|
303
|
+
};
|
|
304
|
+
}, [built]);
|
|
305
|
+
useEffect(() => {
|
|
306
|
+
built.cell.handlers = commands || null;
|
|
307
|
+
pump(built.cell);
|
|
308
|
+
});
|
|
309
|
+
return built.proxy;
|
|
310
|
+
};
|
|
311
|
+
const emitHosts = /* @__PURE__ */ new WeakMap();
|
|
312
|
+
const getEmitHost = (emit) => emit && emitHosts.get(emit);
|
|
313
|
+
const useStatewireEmit = () => {
|
|
314
|
+
const [built] = useState(_temp);
|
|
315
|
+
return built;
|
|
316
|
+
};
|
|
317
|
+
function _temp() {
|
|
318
|
+
const cell = { sink: null };
|
|
319
|
+
const emit = (event) => {
|
|
320
|
+
if (!cell.sink) throw new Error("statewire: emit before a host bound the event sink");
|
|
321
|
+
cell.sink(sanitizeValue(event));
|
|
322
|
+
};
|
|
323
|
+
emitHosts.set(emit, { setSink: (sink) => {
|
|
324
|
+
cell.sink = sink;
|
|
325
|
+
} });
|
|
326
|
+
return emit;
|
|
327
|
+
}
|
|
328
|
+
//#endregion
|
|
329
|
+
export { CommandExecution, bindCommandsHost, getCommandsHost, getEmitHost, getStateHost, useStatewireCommands, useStatewireEmit, useStatewireState };
|
|
330
|
+
|
|
331
|
+
//# sourceMappingURL=host.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"host.js","names":["useEffect","useState","applyOps","sanitizeValue","StatewirePath","StatewireReject","createStateDraft","createMethodProxy","ServerOp","StateDraft","StatewireSendError","Statewire","StatewireHost","isDev","process","env","stateHosts","WeakMap","StateHost","getStateHost","state","get","StateCell","current","draft","changed","onOp","op","onChange","ctl","StateCtl","host","bump","useStatewireState","init","TState","setVersion","cell","commit","c","flush","v","apply","ops","result","events","length","Error","invalidate","push","changedPaths","snapshot","setOnOp","listener","setOnChange","takeChanged","value","record","changedPath","set","proxy","const","ExecutionSettled","type","error","ExecutionBind","onAck","onSettle","settled","ExecutionState","acked","bind","executionStates","CommandExecution","Object","assign","executor","resolvers","ack","T","PromiseLike","Execution","execution","freeze","settle","withResolvers","ExecutionResolvers","resolve","reject","promise","Promise","res","rej","a","CommandsInvocation","method","params","ts","seq","clientId","CommandsOutcome","payload","CommandsListener","onStart","inv","onPosted","onCovered","outcome","CommandsSubmission","CommandsHost","setListener","submit","call","commandsHosts","getCommandsHost","commands","bindCommandsHost","QueuedCall","origin","ActiveInvocation","CommandsCell","handlers","Record","args","queue","running","unmounted","stallTimer","ReturnType","setTimeout","STALL_WARN_MS","toSendError","fate","cause","message","String","undefined","ackInvocation","settleInvocation","pump","watchStall","shift","handler","console","warn","useStatewireCommands","Commands","THandlers","CommandsProxy","HandledCommands","built","Date","now","clearTimeout","queueMicrotask","queued","EmitHost","setSink","sink","event","emitHosts","getEmitHost","emit","useStatewireEmit","_temp"],"sources":["../../src/host/host.ts"],"sourcesContent":["import { useEffect, useState } from \"react\";\nimport { applyOps, sanitizeValue } from \"../wire/ops\";\nimport type { StatewirePath } from \"../wire/ops\";\nimport { StatewireReject } from \"./engine\";\nimport { createStateDraft } from \"./draft\";\nimport { createMethodProxy } from \"../util/methodProxy\";\nimport type { ServerOp, StateDraft } from \"./draft\";\nimport { StatewireSendError } from \"../types\";\nimport type { Statewire } from \"../types\";\nimport type { StatewireHost } from \"../host\";\n\nconst isDev = () =>\n typeof process === \"undefined\" || process.env[\"NODE_ENV\"] !== \"production\";\n\n// ─── state ──────────────────────────────────────────────\n\nconst stateHosts = new WeakMap<object, StatewireHost.StateHost>();\n\n/** Host-side accessor for a `useStatewireState` state object's source (`snapshot()` reads the committed state). */\nexport const getStateHost = (\n state: object,\n): StatewireHost.StateHost | undefined => stateHosts.get(state);\n\ntype StateCell = {\n current: unknown;\n draft: StateDraft<object> | null;\n changed: StatewirePath[];\n onOp: ((op: ServerOp) => void) | null;\n onChange: (() => void) | null;\n ctl: StatewireHost.StateCtl;\n host: StatewireHost.StateHost;\n bump: () => void;\n};\n\nexport const useStatewireState = <TState>(\n init: () => TState,\n): readonly [TState, StatewireHost.StateCtl<TState>] => {\n const [, setVersion] = useState(0);\n const [cell] = useState((): StateCell => {\n const commit = () => {\n if (c.draft) c.current = c.draft.flush();\n return c.current;\n };\n const c: StateCell = {\n current: sanitizeValue(init()),\n draft: null,\n changed: [[]],\n onOp: null,\n onChange: null,\n bump: () => setVersion((v) => v + 1),\n ctl: {\n apply: (ops) => {\n const result = applyOps(commit(), ops);\n if (result.events.length > 0) {\n throw new Error(\n \"statewire: event ops do not apply to state — route them to emit\",\n );\n }\n c.current = result.state;\n c.draft?.invalidate();\n c.changed.push(...result.changedPaths);\n if (c.onOp) for (const op of ops) c.onOp(op as ServerOp);\n c.bump();\n c.onChange?.();\n },\n snapshot: commit,\n },\n host: {\n snapshot: commit,\n setOnOp: (listener) => {\n c.onOp = listener;\n },\n setOnChange: (listener) => {\n c.onChange = listener;\n },\n takeChanged: () => {\n const changed = c.changed;\n c.changed = [];\n return changed;\n },\n },\n };\n return c;\n });\n\n let value = cell.ctl.snapshot();\n if (typeof value === \"object\" && value !== null) {\n cell.draft ??= createStateDraft<object>({\n snapshot: () => cell.current,\n record: (op, changedPath) => {\n cell.changed.push(changedPath);\n cell.onOp?.(op);\n cell.bump();\n cell.onChange?.();\n },\n });\n stateHosts.set(cell.draft.proxy, cell.host);\n value = cell.draft.proxy;\n }\n return [value as TState, cell.ctl as StatewireHost.StateCtl<TState>] as const;\n};\n\n// ─── commands ───────────────────────────────────────────\n\ntype ExecutionSettled =\n | { type: \"resolved\"; value: unknown }\n | { type: \"rejected\"; error: unknown };\n\ntype ExecutionBind = {\n onAck: () => void;\n onSettle: (settled: ExecutionSettled) => void;\n};\n\ntype ExecutionState = {\n acked: boolean;\n settled: ExecutionSettled | null;\n bind: ExecutionBind | null;\n};\n\nconst executionStates = new WeakMap<object, ExecutionState>();\n\n/**\n * `CommandExecution(executor)` runs the (possibly async) `executor({ ack })`\n * immediately: its return value resolves the execution, a throw/rejection\n * rejects it; `ack()` releases the client's ack watermark before the executor\n * finishes. `CommandExecution.withResolvers()` returns `[execution,\n * { ack, resolve, reject }]` instead — settle them from your own spawned work.\n */\nexport const CommandExecution = Object.assign(\n <T = void>(\n executor: (resolvers: {\n ack: () => void;\n }) => T | void | PromiseLike<T | void>,\n ): StatewireHost.Execution<T> => {\n const state: ExecutionState = { acked: false, settled: null, bind: null };\n const execution = Object.freeze(\n {},\n ) as unknown as StatewireHost.Execution<T>;\n executionStates.set(execution, state);\n const settle = (settled: ExecutionSettled) => {\n if (state.settled) return;\n state.settled = settled;\n state.acked = true;\n state.bind?.onSettle(settled);\n };\n const ack = () => {\n if (state.acked) return;\n state.acked = true;\n state.bind?.onAck();\n };\n void (async () => {\n try {\n settle({ type: \"resolved\", value: await executor({ ack }) });\n } catch (error) {\n settle({ type: \"rejected\", error });\n }\n })();\n return execution;\n },\n {\n withResolvers: <T = void>(): [\n StatewireHost.Execution<T>,\n StatewireHost.ExecutionResolvers<T>,\n ] => {\n let resolve!: (value: T) => void;\n let reject!: (error: unknown) => void;\n const promise = new Promise<T>((res, rej) => {\n resolve = res;\n reject = rej;\n });\n let ack!: () => void;\n const execution = CommandExecution<T>(({ ack: a }) => {\n ack = a;\n return promise;\n });\n return [execution, { ack: () => ack(), resolve, reject }];\n },\n },\n);\n\nexport type CommandsInvocation = {\n readonly method: string;\n readonly params: readonly unknown[];\n readonly ts: number;\n readonly seq: number;\n readonly clientId?: string;\n};\n\nexport type CommandsOutcome =\n | { type: \"accepted\"; payload?: unknown }\n | { type: \"rejected\"; error: unknown };\n\nexport type CommandsListener = {\n onStart: (inv: CommandsInvocation) => void;\n onPosted?: (inv: CommandsInvocation) => void;\n onAck: (inv: CommandsInvocation) => void;\n /** Canonical state now covers the invocation's effect — drop any overlay. */\n onCovered?: (inv: CommandsInvocation) => void;\n onSettle: (inv: CommandsInvocation, outcome: CommandsOutcome) => void;\n};\n\nexport type CommandsSubmission = {\n method: string;\n params: readonly unknown[];\n clientId?: string;\n onAck?: () => void;\n onSettle?: (outcome: CommandsOutcome) => void;\n};\n\nexport type CommandsHost = {\n setListener: (listener: CommandsListener | null) => void;\n submit?: (call: CommandsSubmission) => Promise<unknown>;\n};\n\nconst commandsHosts = new WeakMap<object, CommandsHost>();\n\nexport const getCommandsHost = (commands: object): CommandsHost | undefined =>\n commandsHosts.get(commands);\n\nexport const bindCommandsHost = (commands: object, host: CommandsHost) => {\n commandsHosts.set(commands, host);\n};\n\ntype QueuedCall = {\n method: string;\n params: readonly unknown[];\n ts: number;\n resolve: (value: unknown) => void;\n reject: (error: unknown) => void;\n origin?: CommandsSubmission;\n};\n\ntype ActiveInvocation = CommandsInvocation & {\n acked: boolean;\n origin?: CommandsSubmission;\n};\n\ntype CommandsCell = {\n handlers: Record<string, (...args: never[]) => unknown> | null;\n queue: QueuedCall[];\n running: boolean;\n listener: CommandsListener | null;\n seq: number;\n unmounted: boolean;\n stallTimer: ReturnType<typeof setTimeout> | null;\n};\n\nconst STALL_WARN_MS = 5000;\n\nconst toSendError = (error: unknown): StatewireSendError =>\n error instanceof StatewireSendError\n ? error\n : new StatewireSendError({\n fate: \"rejected\",\n cause: \"server\",\n message: error instanceof Error ? error.message : String(error),\n ...(error instanceof StatewireReject &&\n error.payload !== undefined && { payload: error.payload }),\n });\n\nconst ackInvocation = (cell: CommandsCell, inv: ActiveInvocation) => {\n if (inv.acked) return;\n inv.acked = true;\n cell.listener?.onAck(inv);\n inv.origin?.onAck?.();\n};\n\nconst settleInvocation = (\n cell: CommandsCell,\n inv: ActiveInvocation,\n call: QueuedCall,\n settled: ExecutionSettled,\n) => {\n ackInvocation(cell, inv);\n if (settled.type === \"resolved\") {\n const outcome: CommandsOutcome =\n settled.value === undefined\n ? { type: \"accepted\" }\n : { type: \"accepted\", payload: sanitizeValue(settled.value) };\n cell.listener?.onSettle(inv, outcome);\n inv.origin?.onSettle?.(outcome);\n call.resolve(outcome.payload);\n } else {\n const error = toSendError(settled.error);\n const outcome: CommandsOutcome = { type: \"rejected\", error };\n cell.listener?.onSettle(inv, outcome);\n inv.origin?.onSettle?.(outcome);\n call.reject(error);\n }\n};\n\nconst pump = (cell: CommandsCell) => {\n if (cell.running || !cell.handlers) {\n watchStall(cell);\n return;\n }\n const call = cell.queue.shift();\n if (!call) return;\n const handler = cell.handlers[call.method];\n if (handler === undefined) {\n const error = new StatewireSendError({\n fate: \"unknown-command\",\n cause: \"server\",\n });\n call.origin?.onSettle?.({ type: \"rejected\", error });\n call.reject(error);\n pump(cell);\n return;\n }\n const inv: ActiveInvocation = {\n method: call.method,\n params: call.params,\n ts: call.ts,\n seq: ++cell.seq,\n acked: false,\n ...(call.origin !== undefined && { origin: call.origin }),\n ...(call.origin?.clientId !== undefined && {\n clientId: call.origin.clientId,\n }),\n };\n cell.running = true;\n cell.listener?.onStart(inv);\n cell.listener?.onPosted?.(inv);\n cell.listener?.onCovered?.(inv);\n void (async () => {\n try {\n const value = await (handler as (...args: readonly unknown[]) => unknown)(\n ...call.params,\n );\n const execution =\n typeof value === \"object\" && value !== null\n ? executionStates.get(value)\n : undefined;\n if (execution) {\n if (execution.acked) ackInvocation(cell, inv);\n if (execution.settled) {\n settleInvocation(cell, inv, call, execution.settled);\n } else {\n execution.bind = {\n onAck: () => ackInvocation(cell, inv),\n onSettle: (settled) => settleInvocation(cell, inv, call, settled),\n };\n }\n } else {\n settleInvocation(cell, inv, call, { type: \"resolved\", value });\n }\n } catch (error) {\n settleInvocation(cell, inv, call, { type: \"rejected\", error });\n } finally {\n cell.running = false;\n pump(cell);\n }\n })();\n};\n\nconst watchStall = (cell: CommandsCell) => {\n if (!isDev() || cell.stallTimer !== null || cell.queue.length === 0) return;\n if (cell.handlers) return;\n cell.stallTimer = setTimeout(() => {\n cell.stallTimer = null;\n if (cell.handlers === null && cell.queue.length > 0 && !cell.unmounted) {\n console.warn(\n `statewire: ${cell.queue.length} buffered command(s) waiting over ${STALL_WARN_MS}ms — did the host forget to arm useStatewireCommands?`,\n );\n }\n }, STALL_WARN_MS);\n};\n\nexport const useStatewireCommands = <THandlers extends Statewire.Commands>(\n commands: THandlers | undefined | null | false,\n): Statewire.CommandsProxy<StatewireHost.HandledCommands<THandlers>> => {\n const [built] = useState(() => {\n const cell: CommandsCell = {\n handlers: null,\n queue: [],\n running: false,\n listener: null,\n seq: 0,\n unmounted: false,\n stallTimer: null,\n };\n const proxy = createMethodProxy<\n Statewire.CommandsProxy<StatewireHost.HandledCommands<THandlers>>\n >(\n (method, params) =>\n new Promise((resolve, reject) => {\n if (cell.unmounted) {\n reject(new Error(\"statewire: commands called after unmount\"));\n return;\n }\n cell.queue.push({\n method,\n params,\n ts: Date.now(),\n resolve,\n reject,\n });\n pump(cell);\n }),\n );\n commandsHosts.set(proxy, {\n setListener: (listener) => {\n cell.listener = listener;\n },\n submit: (origin) =>\n new Promise((resolve, reject) => {\n if (cell.unmounted) {\n reject(new Error(\"statewire: commands called after unmount\"));\n return;\n }\n cell.queue.push({\n method: origin.method,\n params: origin.params,\n ts: Date.now(),\n resolve,\n reject,\n origin,\n });\n pump(cell);\n }),\n });\n return { cell, proxy };\n });\n\n useEffect(() => {\n const { cell } = built;\n cell.unmounted = false;\n return () => {\n cell.unmounted = true;\n cell.handlers = null;\n if (cell.stallTimer !== null) {\n clearTimeout(cell.stallTimer);\n cell.stallTimer = null;\n }\n queueMicrotask(() => {\n if (!cell.unmounted) return;\n const queued = cell.queue;\n cell.queue = [];\n for (const call of queued) {\n call.reject(new Error(\"statewire: unmounted\"));\n }\n });\n };\n }, [built]);\n\n useEffect(() => {\n built.cell.handlers = commands || null;\n pump(built.cell);\n });\n\n return built.proxy;\n};\n\n// ─── emit ───────────────────────────────────────────────\n\nexport type EmitHost = {\n setSink: (sink: ((event: unknown) => void) | null) => void;\n};\n\nconst emitHosts = new WeakMap<object, EmitHost>();\n\nexport const getEmitHost = (emit: object | undefined): EmitHost | undefined =>\n emit && emitHosts.get(emit);\n\nexport const useStatewireEmit = <TEvent>(): ((event: TEvent) => void) => {\n const [built] = useState(() => {\n const cell = { sink: null as ((event: unknown) => void) | null };\n const emit = (event: TEvent) => {\n if (!cell.sink) {\n throw new Error(\"statewire: emit before a host bound the event sink\");\n }\n cell.sink(sanitizeValue(event));\n };\n emitHosts.set(emit, {\n setSink: (sink) => {\n cell.sink = sink;\n },\n });\n return emit;\n });\n return built;\n};\n"],"mappings":";;;;;;;AAWA,MAAMa,cACJ,OAAOC,YAAY,eAAeA,QAAQC,IAAI,gBAAgB;AAIhE,MAAMC,6BAAa,IAAIC,QAAyC;;AAGhE,MAAaE,gBACXC,UACwCJ,WAAWK,IAAID,KAAK;AAa9D,MAAaa,qBACXC,SACsD;CACtD,MAAM,GAAGE,cAAcnC,SAAS,CAAC;CACjC,MAAM,CAACoC,QAAQpC,eAA0B;EACvC,MAAMqC,eAAe;GACnB,IAAIC,EAAEf,OAAOe,EAAEhB,UAAUgB,EAAEf,MAAMgB,MAAM;GACvC,OAAOD,EAAEhB;EACX;EACA,MAAMgB,IAAe;GACnBhB,SAASpB,cAAc+B,KAAK,CAAC;GAC7BV,OAAO;GACPC,SAAS,CAAC,CAAA,CAAE;GACZC,MAAM;GACNE,UAAU;GACVI,YAAYI,YAAYK,MAAMA,IAAI,CAAC;GACnCZ,KAAK;IACHa,QAAQC,QAAQ;KACd,MAAMC,SAAS1C,SAASoC,OAAO,GAAGK,GAAG;KACrC,IAAIC,OAAOC,OAAOC,SAAS,GACzB,MAAM,IAAIC,MACR,iEACF;KAEFR,EAAEhB,UAAUqB,OAAOxB;KACnBmB,EAAEf,OAAOwB,WAAW;KACpBT,EAAEd,QAAQwB,KAAK,GAAGL,OAAOM,YAAY;KACrC,IAAIX,EAAEb,MAAM,KAAK,MAAMC,MAAMgB,KAAKJ,EAAEb,KAAKC,EAAc;KACvDY,EAAEP,KAAK;KACPO,EAAEX,WAAW;IACf;IACAuB,UAAUb;GACZ;GACAP,MAAM;IACJoB,UAAUb;IACVc,UAAUC,aAAa;KACrBd,EAAEb,OAAO2B;IACX;IACAC,cAAcD,eAAa;KACzBd,EAAEX,WAAWyB;IACf;IACAE,mBAAmB;KACjB,MAAM9B,UAAUc,EAAEd;KAClBc,EAAEd,UAAU,CAAA;KACZ,OAAOA;IACT;GACF;EACF;EACA,OAAOc;CACT,CAAC;CAED,IAAIiB,QAAQnB,KAAKR,IAAIsB,SAAS;CAC9B,IAAI,OAAOK,UAAU,YAAYA,UAAU,MAAM;EAC/CnB,KAAKb,UAAUlB,iBAAyB;GACtC6C,gBAAgBd,KAAKd;GACrBkC,SAAS9B,IAAI+B,gBAAgB;IAC3BrB,KAAKZ,QAAQwB,KAAKS,WAAW;IAC7BrB,KAAKX,OAAOC,EAAE;IACdU,KAAKL,KAAK;IACVK,KAAKT,WAAW;GAClB;EACF,CAAC;EACDZ,WAAW2C,IAAItB,KAAKb,MAAMoC,OAAOvB,KAAKN,IAAI;EAC1CyB,QAAQnB,KAAKb,MAAMoC;CACrB;CACA,OAAO,CAACJ,OAAiBnB,KAAKR,GAAqC;AACrE;AAmBA,MAAM2C,kCAAkB,IAAIvD,QAAgC;;;;;;;;AAS5D,MAAawD,mBAAmBC,OAAOC,QAEnCC,aAG+B;CAC/B,MAAMxD,QAAwB;EAAEkD,OAAO;EAAOF,SAAS;EAAMG,MAAM;CAAK;CACxE,MAAMW,YAAYR,OAAOS,OACvB,CAAC,CACH;CACAX,gBAAgBb,IAAIuB,WAAW9D,KAAK;CACpC,MAAMgE,UAAUhB,YAA8B;EAC5C,IAAIhD,MAAMgD,SAAS;EACnBhD,MAAMgD,UAAUA;EAChBhD,MAAMkD,QAAQ;EACdlD,MAAMmD,MAAMJ,SAASC,OAAO;CAC9B;CACA,MAAMU,YAAY;EAChB,IAAI1D,MAAMkD,OAAO;EACjBlD,MAAMkD,QAAQ;EACdlD,MAAMmD,MAAML,MAAM;CACpB;CACA,CAAM,YAAY;EAChB,IAAI;GACFkB,OAAO;IAAErB,MAAM;IAAYP,OAAO,MAAMoB,SAAS,EAAEE,IAAI,CAAC;GAAE,CAAC;EAC7D,SAASd,OAAO;GACdoB,OAAO;IAAErB,MAAM;IAAYC;GAAM,CAAC;EACpC;CACF,EAAA,CAAG;CACH,OAAOkB;AACT,GACA,EACEG,qBAGK;CACH,IAAIE;CACJ,IAAIC;CACJ,MAAMC,UAAU,IAAIC,SAAYC,KAAKC,QAAQ;EAC3CL,UAAUI;EACVH,SAASI;CACX,CAAC;CACD,IAAId;CAKJ,OAAO,CAJWL,kBAAqB,EAAEK,KAAKe,QAAQ;EACpDf,MAAMe;EACN,OAAOJ;CACT,CACQP,GAAW;EAAEJ,WAAWA,IAAI;EAAGS;EAASC;CAAO,CAAC;AAC1D,EACF,CACF;AAoCA,MAAMyB,gCAAgB,IAAIhG,QAA8B;AAExD,MAAaiG,mBAAmBC,aAC9BF,cAAc5F,IAAI8F,QAAQ;AAE5B,MAAaC,oBAAoBD,UAAkBpF,SAAuB;CACxEkF,cAActD,IAAIwD,UAAUpF,IAAI;AAClC;AA0BA,MAAMmG,gBAAgB;AAEtB,MAAMC,eAAenE,UACnBA,iBAAiBtD,qBACbsD,QACA,IAAItD,mBAAmB;CACrB0H,MAAM;CACNC,OAAO;CACPC,SAAStE,iBAAiBjB,QAAQiB,MAAMsE,UAAUC,OAAOvE,KAAK;CAC9D,GAAIA,iBAAiB3D,mBACnB2D,MAAMqC,YAAYmC,KAAAA,KAAa,EAAEnC,SAASrC,MAAMqC,QAAQ;AAC5D,CAAC;AAEP,MAAMoC,iBAAiBpG,MAAoBmE,QAA0B;CACnE,IAAIA,IAAIlC,OAAO;CACfkC,IAAIlC,QAAQ;CACZjC,KAAKgB,UAAUa,MAAMsC,GAAG;CACxBA,IAAIc,QAAQpD,QAAQ;AACtB;AAEA,MAAMwE,oBACJrG,MACAmE,KACAQ,MACA5C,YACG;CACHqE,cAAcpG,MAAMmE,GAAG;CACvB,IAAIpC,QAAQL,SAAS,YAAY;EAC/B,MAAM4C,UACJvC,QAAQZ,UAAUgF,KAAAA,IACd,EAAEzE,MAAM,WAAW,IACnB;GAAEA,MAAM;GAAYsC,SAASlG,cAAciE,QAAQZ,KAAK;EAAE;EAChEnB,KAAKgB,UAAUc,SAASqC,KAAKG,OAAO;EACpCH,IAAIc,QAAQnD,WAAWwC,OAAO;EAC9BK,KAAKzB,QAAQoB,QAAQN,OAAO;CAC9B,OAAO;EACL,MAAMrC,QAAQmE,YAAY/D,QAAQJ,KAAK;EACvC,MAAM2C,UAA2B;GAAE5C,MAAM;GAAYC;EAAM;EAC3D3B,KAAKgB,UAAUc,SAASqC,KAAKG,OAAO;EACpCH,IAAIc,QAAQnD,WAAWwC,OAAO;EAC9BK,KAAKxB,OAAOxB,KAAK;CACnB;AACF;AAEA,MAAM2E,QAAQtG,SAAuB;CACnC,IAAIA,KAAKwF,WAAW,CAACxF,KAAKoF,UAAU;EAClCmB,WAAWvG,IAAI;EACf;CACF;CACA,MAAM2E,OAAO3E,KAAKuF,MAAMiB,MAAM;CAC9B,IAAI,CAAC7B,MAAM;CACX,MAAM8B,UAAUzG,KAAKoF,SAAST,KAAKjB;CACnC,IAAI+C,YAAYN,KAAAA,GAAW;EACzB,MAAMxE,QAAQ,IAAItD,mBAAmB;GACnC0H,MAAM;GACNC,OAAO;EACT,CAAC;EACDrB,KAAKM,QAAQnD,WAAW;GAAEJ,MAAM;GAAYC;EAAM,CAAC;EACnDgD,KAAKxB,OAAOxB,KAAK;EACjB2E,KAAKtG,IAAI;EACT;CACF;CACA,MAAMmE,MAAwB;EAC5BT,QAAQiB,KAAKjB;EACbC,QAAQgB,KAAKhB;EACbC,IAAIe,KAAKf;EACTC,KAAK,EAAE7D,KAAK6D;EACZ5B,OAAO;EACP,GAAI0C,KAAKM,WAAWkB,KAAAA,KAAa,EAAElB,QAAQN,KAAKM,OAAO;EACvD,GAAIN,KAAKM,QAAQnB,aAAaqC,KAAAA,KAAa,EACzCrC,UAAUa,KAAKM,OAAOnB,SACxB;CACF;CACA9D,KAAKwF,UAAU;CACfxF,KAAKgB,UAAUkD,QAAQC,GAAG;CAC1BnE,KAAKgB,UAAUoD,WAAWD,GAAG;CAC7BnE,KAAKgB,UAAUqD,YAAYF,GAAG;CAC9B,CAAM,YAAY;EAChB,IAAI;GACF,MAAMhD,QAAQ,MAAOsF,QACnB,GAAG9B,KAAKhB,MACV;GACA,MAAMd,YACJ,OAAO1B,UAAU,YAAYA,UAAU,OACnCgB,gBAAgBnD,IAAImC,KAAK,IACzBgF,KAAAA;GACN,IAAItD,WAAW;IACb,IAAIA,UAAUZ,OAAOmE,cAAcpG,MAAMmE,GAAG;IAC5C,IAAItB,UAAUd,SACZsE,iBAAiBrG,MAAMmE,KAAKQ,MAAM9B,UAAUd,OAAO;SAEnDc,UAAUX,OAAO;KACfL,aAAauE,cAAcpG,MAAMmE,GAAG;KACpCrC,WAAWC,YAAYsE,iBAAiBrG,MAAMmE,KAAKQ,MAAM5C,OAAO;IAClE;GAEJ,OACEsE,iBAAiBrG,MAAMmE,KAAKQ,MAAM;IAAEjD,MAAM;IAAYP;GAAM,CAAC;EAEjE,SAASQ,OAAO;GACd0E,iBAAiBrG,MAAMmE,KAAKQ,MAAM;IAAEjD,MAAM;IAAYC;GAAM,CAAC;EAC/D,UAAU;GACR3B,KAAKwF,UAAU;GACfc,KAAKtG,IAAI;EACX;CACF,EAAA,CAAG;AACL;AAEA,MAAMuG,cAAcvG,SAAuB;CACzC,IAAI,CAACxB,MAAM,KAAKwB,KAAK0F,eAAe,QAAQ1F,KAAKuF,MAAM9E,WAAW,GAAG;CACrE,IAAIT,KAAKoF,UAAU;CACnBpF,KAAK0F,aAAaE,iBAAiB;EACjC5F,KAAK0F,aAAa;EAClB,IAAI1F,KAAKoF,aAAa,QAAQpF,KAAKuF,MAAM9E,SAAS,KAAK,CAACT,KAAKyF,WAC3DiB,QAAQC,KACN,cAAc3G,KAAKuF,MAAM9E,OAAM,oCAAqCoF,cAAa,sDACnF;CAEJ,GAAGA,aAAa;AAClB;AAEA,MAAae,wBACX9B,aACsE;CACtE,MAAM,CAACmC,SAASrJ,eAAe;EAC7B,MAAMoC,OAAqB;GACzBoF,UAAU;GACVG,OAAO,CAAA;GACPC,SAAS;GACTxE,UAAU;GACV6C,KAAK;GACL4B,WAAW;GACXC,YAAY;EACd;EACA,MAAMnE,QAAQrD,mBAGXwF,QAAQC,WACP,IAAIN,SAASH,SAASC,WAAW;GAC/B,IAAInD,KAAKyF,WAAW;IAClBtC,uBAAO,IAAIzC,MAAM,0CAA0C,CAAC;IAC5D;GACF;GACAV,KAAKuF,MAAM3E,KAAK;IACd8C;IACAC;IACAC,IAAIsD,KAAKC,IAAI;IACbjE;IACAC;GACF,CAAC;GACDmD,KAAKtG,IAAI;EACX,CAAC,CACL;EACA4E,cAActD,IAAIC,OAAO;GACvBkD,cAAczD,aAAa;IACzBhB,KAAKgB,WAAWA;GAClB;GACA0D,SAASO,WACP,IAAI5B,SAASH,WAASC,aAAW;IAC/B,IAAInD,KAAKyF,WAAW;KAClBtC,yBAAO,IAAIzC,MAAM,0CAA0C,CAAC;KAC5D;IACF;IACAV,KAAKuF,MAAM3E,KAAK;KACd8C,QAAQuB,OAAOvB;KACfC,QAAQsB,OAAOtB;KACfC,IAAIsD,KAAKC,IAAI;KACbjE,SAAAA;KACAC,QAAAA;KACA8B;IACF,CAAC;IACDqB,KAAKtG,IAAI;GACX,CAAC;EACL,CAAC;EACD,OAAO;GAAEA;GAAMuB;EAAM;CACvB,CAAC;CAED5D,gBAAgB;EACd,MAAM,EAAEqC,MAAAA,WAASiH;EACjBjH,OAAKyF,YAAY;EACjB,aAAa;GACXzF,OAAKyF,YAAY;GACjBzF,OAAKoF,WAAW;GAChB,IAAIpF,OAAK0F,eAAe,MAAM;IAC5B0B,aAAapH,OAAK0F,UAAU;IAC5B1F,OAAK0F,aAAa;GACpB;GACA2B,qBAAqB;IACnB,IAAI,CAACrH,OAAKyF,WAAW;IACrB,MAAM6B,SAAStH,OAAKuF;IACpBvF,OAAKuF,QAAQ,CAAA;IACb,KAAK,MAAMZ,QAAQ2C,QACjB3C,KAAKxB,uBAAO,IAAIzC,MAAM,sBAAsB,CAAC;GAEjD,CAAC;EACH;CACF,GAAG,CAACuG,KAAK,CAAC;CAEVtJ,gBAAgB;EACdsJ,MAAMjH,KAAKoF,WAAWN,YAAY;EAClCwB,KAAKW,MAAMjH,IAAI;CACjB,CAAC;CAED,OAAOiH,MAAM1F;AACf;AAQA,MAAMoG,4BAAY,IAAI/I,QAA0B;AAEhD,MAAagJ,eAAeC,SAC1BA,QAAQF,UAAU3I,IAAI6I,IAAI;AAE5B,MAAaC,yBAAmB;CAC9B,MAAA,CAAAb,SAAgBrJ,SAASmK,KAcxB;CAAE,OACId;AAAK;AAhBkB,SAAAc,QAAA;CAE5B,MAAA/H,OAAa,EAAAyH,MAAQ,KAA0C;CAC/D,MAAAI,QAAaH,UAAA;EACX,IAAI,CAAC1H,KAAIyH,MACP,MAAM,IAAI/G,MAAM,oDAAoD;EAEtEV,KAAIyH,KAAM3J,cAAc4J,KAAK,CAAC;CAAC;CAEjCC,UAASrG,IAAKuG,MAAM,EAAAL,UACTC,SAAA;EACPzH,KAAIyH,OAAQA;CAAH,EAEb,CAAC;CAAC,OACKI;AAAI"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Statewire } from "../types.js";
|
|
2
|
+
import { StatewireHostInternal } from "../host-internal.js";
|
|
3
|
+
import { ResourceElement } from "@assistant-ui/tap";
|
|
4
|
+
//#region src/host/socket.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Transport-agnostic WS binding over a statewire/host transport:
|
|
7
|
+
* feed it sockets (anything with `send`/`close`) and raw text frames, and it
|
|
8
|
+
* speaks the Statewire envelope protocol — snapshot-first attach with `syn`,
|
|
9
|
+
* delta/ack/res envelopes, per-client-id supersede, and `fin` on finish.
|
|
10
|
+
*/
|
|
11
|
+
declare const StatewireSocketHost: (transport: ResourceElement<Statewire>, options?: StatewireHostInternal.SocketHostOptions) => StatewireHostInternal.SocketHost;
|
|
12
|
+
//#endregion
|
|
13
|
+
export { StatewireSocketHost };
|
|
14
|
+
//# sourceMappingURL=socket.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"socket.d.ts","names":[],"sources":["../../src/host/socket.ts"],"mappings":";;;;;;;;;;cA2gBa,sBACX,WAAW,gBAAgB,YAC3B,UAAU,sBAAsB,sBAC/B,sBAAsB"}
|