statewire 0.8.1 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/client/connection.d.ts +23 -19
- package/dist/client/connection.d.ts.map +1 -1
- package/dist/client/connection.js +143 -103
- package/dist/client/connection.js.map +1 -1
- package/dist/client/core.d.ts +30 -3
- package/dist/client/core.d.ts.map +1 -1
- package/dist/client/core.js +222 -260
- package/dist/client/core.js.map +1 -1
- package/dist/client/session.d.ts +34 -39
- package/dist/client/session.d.ts.map +1 -1
- package/dist/client/session.js +380 -373
- package/dist/client/session.js.map +1 -1
- package/dist/client/sessionStore.d.ts +1 -0
- package/dist/client/sessionStore.d.ts.map +1 -1
- package/dist/client/sessionStore.js.map +1 -1
- package/dist/client/timing.d.ts +1 -2
- package/dist/client/timing.d.ts.map +1 -1
- package/dist/client/timing.js +1 -5
- package/dist/client/timing.js.map +1 -1
- package/dist/host/draft.d.ts +2 -5
- package/dist/host/draft.d.ts.map +1 -1
- package/dist/host/draft.js.map +1 -1
- package/dist/host/host.d.ts +5 -8
- package/dist/host/host.d.ts.map +1 -1
- package/dist/host/host.js +23 -32
- package/dist/host/host.js.map +1 -1
- package/dist/host/socket.d.ts +3 -2
- package/dist/host/socket.d.ts.map +1 -1
- package/dist/host/socket.js +484 -424
- package/dist/host/socket.js.map +1 -1
- package/dist/host-internal.d.ts +4 -0
- package/dist/host-internal.d.ts.map +1 -1
- package/dist/host.d.ts +10 -10
- package/dist/host.d.ts.map +1 -1
- package/dist/host.js +2 -2
- package/dist/index.d.ts +1 -2
- package/dist/index.js +1 -2
- package/dist/statewire.d.ts +29 -24
- package/dist/statewire.d.ts.map +1 -1
- package/dist/statewire.js +8 -2
- package/dist/statewire.js.map +1 -1
- package/dist/transports/fake-sse.d.ts +1 -1
- package/dist/transports/fake-sse.d.ts.map +1 -1
- package/dist/transports/fake-sse.js +5 -2
- package/dist/transports/fake-sse.js.map +1 -1
- package/dist/transports/fixtures.d.ts +1 -2
- package/dist/transports/fixtures.d.ts.map +1 -1
- package/dist/transports/fixtures.js +5 -7
- package/dist/transports/fixtures.js.map +1 -1
- package/dist/transports/remote.d.ts +2 -1
- package/dist/transports/remote.d.ts.map +1 -1
- package/dist/transports/remote.js +10 -4
- package/dist/transports/remote.js.map +1 -1
- package/dist/transports/sse.d.ts +32 -46
- package/dist/transports/sse.d.ts.map +1 -1
- package/dist/transports/sse.js +56 -59
- package/dist/transports/sse.js.map +1 -1
- package/dist/transports/testing.d.ts +7 -5
- package/dist/transports/testing.d.ts.map +1 -1
- package/dist/transports/testing.js +41 -14
- package/dist/transports/testing.js.map +1 -1
- package/dist/transports/ws.d.ts +2 -3
- package/dist/transports/ws.d.ts.map +1 -1
- package/dist/transports/ws.js +25 -80
- package/dist/transports/ws.js.map +1 -1
- package/dist/types.d.ts +8 -8
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +3 -4
- package/dist/types.js.map +1 -1
- package/dist/wire/ops.d.ts +1 -5
- package/dist/wire/ops.d.ts.map +1 -1
- package/dist/wire/ops.js +1 -4
- package/dist/wire/ops.js.map +1 -1
- package/package.json +1 -1
- package/src/client/connection.ts +175 -128
- package/src/client/core.ts +287 -278
- package/src/client/session.ts +474 -480
- package/src/client/sessionStore.ts +1 -0
- package/src/client/timing.ts +0 -6
- package/src/host/draft.ts +1 -3
- package/src/host/host.ts +41 -58
- package/src/host/socket.ts +653 -448
- package/src/host-internal.ts +4 -0
- package/src/host.ts +13 -10
- package/src/index.ts +0 -1
- package/src/statewire.ts +38 -32
- package/src/transports/fake-sse.ts +2 -1
- package/src/transports/fixtures.ts +4 -9
- package/src/transports/remote.ts +12 -5
- package/src/transports/sse.ts +99 -115
- package/src/transports/testing.ts +47 -19
- package/src/transports/ws.ts +44 -115
- package/src/types.ts +15 -14
- package/src/wire/ops.ts +9 -16
package/dist/client/core.js
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { recordMutations } from "../util/recordMutations.js";
|
|
2
2
|
import { createMethodProxy } from "../util/methodProxy.js";
|
|
3
3
|
import { StatewireSendError } from "../types.js";
|
|
4
|
-
import { getCommandsHost,
|
|
4
|
+
import { getCommandsHost, getStateHost } from "../host/host.js";
|
|
5
5
|
import { createMacrotaskPoster } from "../util/macrotask.js";
|
|
6
6
|
import { createChanges } from "./changes.js";
|
|
7
|
-
import { c } from "@assistant-ui/tap/react-shim/compiler-runtime";
|
|
8
7
|
import { useEffect, useState } from "@assistant-ui/tap/react-shim";
|
|
9
8
|
//#region src/client/core.ts
|
|
10
9
|
const LIVE_CONNECTION = {
|
|
@@ -16,276 +15,239 @@ const failureOf = (error) => error instanceof StatewireSendError ? error.failure
|
|
|
16
15
|
cause: "server",
|
|
17
16
|
message: error instanceof Error ? error.message : String(error)
|
|
18
17
|
};
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
const listeners = /* @__PURE__ */ new Set();
|
|
37
|
-
const post = createMacrotaskPoster(() => {
|
|
38
|
-
scheduled = false;
|
|
39
|
-
flush();
|
|
40
|
-
});
|
|
41
|
-
let scheduled = false;
|
|
42
|
-
const schedule = () => {
|
|
43
|
-
if (scheduled) return;
|
|
44
|
-
scheduled = true;
|
|
45
|
-
post();
|
|
46
|
-
};
|
|
47
|
-
const markStale = () => {
|
|
48
|
-
stale = true;
|
|
49
|
-
schedule();
|
|
50
|
-
};
|
|
51
|
-
const drainCanonical = () => {
|
|
52
|
-
if (source) {
|
|
53
|
-
pendingChanged.push(...source.takeChanged());
|
|
54
|
-
const snapshot = source.snapshot();
|
|
55
|
-
if (snapshot !== void 0) {
|
|
56
|
-
everAttached = true;
|
|
57
|
-
canonical = snapshot;
|
|
58
|
-
return;
|
|
59
|
-
}
|
|
60
|
-
const next = everAttached ? void 0 : getOptions().initialState;
|
|
61
|
-
if (next !== canonical) pendingChanged.push([]);
|
|
62
|
-
canonical = next;
|
|
63
|
-
} else if (value) {
|
|
64
|
-
if (value.state !== void 0) everAttached = true;
|
|
65
|
-
const next = everAttached ? value.state : getOptions().initialState;
|
|
66
|
-
if (next !== canonical) {
|
|
67
|
-
pendingChanged.push([]);
|
|
68
|
-
canonical = next;
|
|
69
|
-
}
|
|
18
|
+
const schedule = (c) => {
|
|
19
|
+
if (c.scheduled) return;
|
|
20
|
+
c.scheduled = true;
|
|
21
|
+
c.post();
|
|
22
|
+
};
|
|
23
|
+
const markStale = (c) => {
|
|
24
|
+
c.stale = true;
|
|
25
|
+
schedule(c);
|
|
26
|
+
};
|
|
27
|
+
const drainCanonical = (c) => {
|
|
28
|
+
if (c.source) {
|
|
29
|
+
c.pendingChanged.push(...c.source.takeChanged());
|
|
30
|
+
const snapshot = c.source.snapshot();
|
|
31
|
+
if (snapshot !== void 0) {
|
|
32
|
+
c.everAttached = true;
|
|
33
|
+
c.canonical = snapshot;
|
|
34
|
+
return;
|
|
70
35
|
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
if (
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
let next = canonical;
|
|
81
|
-
let paths = [];
|
|
82
|
-
if (optimistic && canonical !== void 0) for (const overlay of overlays) {
|
|
83
|
-
if (overlay.dropped) continue;
|
|
84
|
-
const { inv } = overlay;
|
|
85
|
-
const ctx = {
|
|
86
|
-
ts: inv.ts,
|
|
87
|
-
seq: inv.seq,
|
|
88
|
-
...inv.clientId !== void 0 && { clientId: inv.clientId }
|
|
89
|
-
};
|
|
90
|
-
try {
|
|
91
|
-
const recorded = recordMutations(next, (draft) => optimistic(draft, {
|
|
92
|
-
method: inv.method,
|
|
93
|
-
params: inv.params
|
|
94
|
-
}, ctx));
|
|
95
|
-
next = recorded.state;
|
|
96
|
-
paths = [...paths, ...recorded.changedPaths];
|
|
97
|
-
} catch (error) {
|
|
98
|
-
overlay.dropped = true;
|
|
99
|
-
console.error(`statewire: optimistic reducer threw for "${inv.method}"; dropping its optimistic update`, error);
|
|
100
|
-
}
|
|
36
|
+
const next = c.everAttached ? void 0 : c.getOptions().initialState;
|
|
37
|
+
if (next !== c.canonical) c.pendingChanged.push([]);
|
|
38
|
+
c.canonical = next;
|
|
39
|
+
} else if (c.value) {
|
|
40
|
+
if (c.value.state !== void 0) c.everAttached = true;
|
|
41
|
+
const next = c.everAttached ? c.value.state : c.getOptions().initialState;
|
|
42
|
+
if (next !== c.canonical) {
|
|
43
|
+
c.pendingChanged.push([]);
|
|
44
|
+
c.canonical = next;
|
|
101
45
|
}
|
|
102
|
-
|
|
103
|
-
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
const recompute = (c) => {
|
|
49
|
+
if (!c.stale || !c.value) return;
|
|
50
|
+
c.stale = false;
|
|
51
|
+
const prevCanonical = c.canonical;
|
|
52
|
+
drainCanonical(c);
|
|
53
|
+
if (c.canonical === prevCanonical && !c.overlaysDirty) return;
|
|
54
|
+
c.overlaysDirty = false;
|
|
55
|
+
const { optimistic, materialize } = c.getOptions();
|
|
56
|
+
let next = c.canonical;
|
|
57
|
+
let paths = [];
|
|
58
|
+
if (optimistic && c.canonical !== void 0) for (const overlay of c.overlays) {
|
|
59
|
+
if (overlay.dropped) continue;
|
|
60
|
+
const { inv } = overlay;
|
|
61
|
+
const ctx = {
|
|
62
|
+
ts: inv.ts,
|
|
63
|
+
seq: inv.seq,
|
|
64
|
+
...inv.clientId !== void 0 && { clientId: inv.clientId }
|
|
65
|
+
};
|
|
66
|
+
try {
|
|
67
|
+
const recorded = recordMutations(next, (draft) => optimistic(draft, {
|
|
68
|
+
method: inv.method,
|
|
69
|
+
params: inv.params
|
|
70
|
+
}, ctx));
|
|
104
71
|
next = recorded.state;
|
|
105
72
|
paths = [...paths, ...recorded.changedPaths];
|
|
106
73
|
} catch (error) {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
published = next;
|
|
110
|
-
overlayPaths = paths;
|
|
111
|
-
};
|
|
112
|
-
const getConnection = () => value?.connection ?? LIVE_CONNECTION;
|
|
113
|
-
const flush = () => {
|
|
114
|
-
if (!value) return;
|
|
115
|
-
if (flushing) {
|
|
116
|
-
schedule();
|
|
117
|
-
return;
|
|
118
|
-
}
|
|
119
|
-
flushing = true;
|
|
120
|
-
try {
|
|
121
|
-
recompute();
|
|
122
|
-
const options = getOptions();
|
|
123
|
-
const stateChanged = published !== notifiedPublished;
|
|
124
|
-
if (stateChanged) {
|
|
125
|
-
const prev = notifiedPublished;
|
|
126
|
-
const changed = [
|
|
127
|
-
...pendingChanged,
|
|
128
|
-
...notifiedOverlayPaths,
|
|
129
|
-
...overlayPaths
|
|
130
|
-
];
|
|
131
|
-
pendingChanged = [];
|
|
132
|
-
notifiedPublished = published;
|
|
133
|
-
notifiedOverlayPaths = overlayPaths;
|
|
134
|
-
options.onStateChange?.(published, { changes: createChanges(prev, published, changed) });
|
|
135
|
-
}
|
|
136
|
-
if (updates.length > 0 && published !== void 0) {
|
|
137
|
-
const batch = updates;
|
|
138
|
-
updates = [];
|
|
139
|
-
for (const update of batch) options.onCommandChange?.(update, { state: published });
|
|
140
|
-
}
|
|
141
|
-
if (events.length > 0 && published !== void 0) {
|
|
142
|
-
const batch = events;
|
|
143
|
-
events = [];
|
|
144
|
-
for (const event of batch) options.onEvent?.(event, { state: published });
|
|
145
|
-
}
|
|
146
|
-
const connection = getConnection();
|
|
147
|
-
const connectionChanged = connection !== notifiedConnection;
|
|
148
|
-
notifiedConnection = connection;
|
|
149
|
-
if (connectionChanged) options.onConnectionChange?.(connection);
|
|
150
|
-
if (stateChanged || connectionChanged) for (const listener of [...listeners]) listener();
|
|
151
|
-
} finally {
|
|
152
|
-
flushing = false;
|
|
153
|
-
}
|
|
154
|
-
};
|
|
155
|
-
const note = (inv, status, extra) => {
|
|
156
|
-
if (!getOptions().onCommandChange) return;
|
|
157
|
-
updates.push({
|
|
158
|
-
method: inv.method,
|
|
159
|
-
params: inv.params,
|
|
160
|
-
seq: inv.seq,
|
|
161
|
-
status,
|
|
162
|
-
...extra
|
|
163
|
-
});
|
|
164
|
-
schedule();
|
|
165
|
-
};
|
|
166
|
-
const commandsListener = {
|
|
167
|
-
onStart: (inv) => {
|
|
168
|
-
overlays.push({
|
|
169
|
-
inv,
|
|
170
|
-
dropped: false
|
|
171
|
-
});
|
|
172
|
-
overlaysDirty = true;
|
|
173
|
-
markStale();
|
|
174
|
-
note(inv, "queued");
|
|
175
|
-
},
|
|
176
|
-
onPosted: (inv) => note(inv, "posted"),
|
|
177
|
-
onAck: (inv) => note(inv, "acked"),
|
|
178
|
-
onCovered: (inv) => {
|
|
179
|
-
if (!overlays.some((o) => o.inv === inv)) return;
|
|
180
|
-
overlays = overlays.filter((o) => o.inv !== inv);
|
|
181
|
-
overlaysDirty = true;
|
|
182
|
-
markStale();
|
|
183
|
-
},
|
|
184
|
-
onSettle: (inv, outcome) => {
|
|
185
|
-
note(inv, "settled", outcome.type === "accepted" ? { result: outcome.payload } : { failure: failureOf(outcome.error) });
|
|
186
|
-
flush();
|
|
187
|
-
}
|
|
188
|
-
};
|
|
189
|
-
const eventSink = (event) => {
|
|
190
|
-
if (!getOptions().onEvent) return;
|
|
191
|
-
events.push(event);
|
|
192
|
-
schedule();
|
|
193
|
-
};
|
|
194
|
-
const attach = (next) => {
|
|
195
|
-
if (next === value) return;
|
|
196
|
-
const prev = value;
|
|
197
|
-
value = next;
|
|
198
|
-
const nextSource = next.source ?? (typeof next.state === "object" && next.state !== null ? getStateHost(next.state) : void 0) ?? null;
|
|
199
|
-
if (nextSource !== source) {
|
|
200
|
-
source?.setOnChange(null);
|
|
201
|
-
source = nextSource;
|
|
202
|
-
source?.setOnChange(markStale);
|
|
203
|
-
everAttached = false;
|
|
204
|
-
markStale();
|
|
74
|
+
overlay.dropped = true;
|
|
75
|
+
console.error(`statewire: optimistic reducer threw for "${inv.method}"; dropping its optimistic update`, error);
|
|
205
76
|
}
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
77
|
+
}
|
|
78
|
+
if (materialize && next !== void 0) try {
|
|
79
|
+
const recorded = recordMutations(next, (draft) => materialize(draft));
|
|
80
|
+
next = recorded.state;
|
|
81
|
+
paths = [...paths, ...recorded.changedPaths];
|
|
82
|
+
} catch (error) {
|
|
83
|
+
console.error("statewire: materialize threw; publishing without its update", error);
|
|
84
|
+
}
|
|
85
|
+
c.published = next;
|
|
86
|
+
c.overlayPaths = paths;
|
|
87
|
+
};
|
|
88
|
+
const getConnection = (c) => c.value?.connection ?? LIVE_CONNECTION;
|
|
89
|
+
const flush = (c) => {
|
|
90
|
+
if (!c.value) return;
|
|
91
|
+
if (c.flushing) {
|
|
92
|
+
schedule(c);
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
c.flushing = true;
|
|
96
|
+
try {
|
|
97
|
+
recompute(c);
|
|
98
|
+
const options = c.getOptions();
|
|
99
|
+
const stateChanged = c.published !== c.notifiedPublished;
|
|
100
|
+
if (stateChanged) {
|
|
101
|
+
const prev = c.notifiedPublished;
|
|
102
|
+
const changed = [
|
|
103
|
+
...c.pendingChanged,
|
|
104
|
+
...c.notifiedOverlayPaths,
|
|
105
|
+
...c.overlayPaths
|
|
106
|
+
];
|
|
107
|
+
c.pendingChanged = [];
|
|
108
|
+
c.notifiedPublished = c.published;
|
|
109
|
+
c.notifiedOverlayPaths = c.overlayPaths;
|
|
110
|
+
options.onStateChange?.(c.published, { changes: createChanges(prev, c.published, changed) });
|
|
218
111
|
}
|
|
219
|
-
if (
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
source?.setOnChange(null);
|
|
224
|
-
source = null;
|
|
225
|
-
if (value) {
|
|
226
|
-
getCommandsHost(value.commands)?.setListener(null);
|
|
227
|
-
getEmitHost(value.emit)?.setSink(null);
|
|
228
|
-
value = null;
|
|
112
|
+
if (c.updates.length > 0 && c.published !== void 0) {
|
|
113
|
+
const batch = c.updates;
|
|
114
|
+
c.updates = [];
|
|
115
|
+
for (const update of batch) options.onCommandChange?.(update, { state: c.published });
|
|
229
116
|
}
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
117
|
+
const connection = getConnection(c);
|
|
118
|
+
const connectionChanged = connection !== c.notifiedConnection;
|
|
119
|
+
c.notifiedConnection = connection;
|
|
120
|
+
if (connectionChanged) options.onConnectionChange?.(connection);
|
|
121
|
+
const busy = c.getBusy();
|
|
122
|
+
const busyChanged = busy !== c.notifiedBusy;
|
|
123
|
+
c.notifiedBusy = busy;
|
|
124
|
+
if (stateChanged || connectionChanged || busyChanged) for (const listener of [...c.listeners]) listener();
|
|
125
|
+
} finally {
|
|
126
|
+
c.flushing = false;
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
const note = (c, inv, status, extra) => {
|
|
130
|
+
if (!c.getOptions().onCommandChange) return;
|
|
131
|
+
c.updates.push({
|
|
132
|
+
method: inv.method,
|
|
133
|
+
params: inv.params,
|
|
134
|
+
seq: inv.seq,
|
|
135
|
+
status,
|
|
136
|
+
...extra
|
|
137
|
+
});
|
|
138
|
+
schedule(c);
|
|
139
|
+
};
|
|
140
|
+
const attach = (c, next) => {
|
|
141
|
+
if (next === c.value) return;
|
|
142
|
+
const prev = c.value;
|
|
143
|
+
c.value = next;
|
|
144
|
+
const nextSource = next.source ?? (typeof next.state === "object" && next.state !== null ? getStateHost(next.state) : void 0) ?? null;
|
|
145
|
+
if (nextSource !== c.source) {
|
|
146
|
+
c.source?.setOnChange(null);
|
|
147
|
+
c.source = nextSource;
|
|
148
|
+
c.source?.setOnChange(() => markStale(c));
|
|
149
|
+
c.everAttached = false;
|
|
150
|
+
markStale(c);
|
|
151
|
+
}
|
|
152
|
+
if (next.commands !== prev?.commands) {
|
|
153
|
+
if (prev) getCommandsHost(prev.commands)?.setListener(null);
|
|
154
|
+
getCommandsHost(next.commands)?.setListener(c.commandsListener);
|
|
155
|
+
if (c.overlays.length > 0) {
|
|
156
|
+
c.overlays = [];
|
|
157
|
+
c.overlaysDirty = true;
|
|
253
158
|
}
|
|
254
|
-
|
|
159
|
+
markStale(c);
|
|
160
|
+
}
|
|
161
|
+
if (!c.source) markStale(c);
|
|
162
|
+
schedule(c);
|
|
163
|
+
};
|
|
164
|
+
const detach = (c) => {
|
|
165
|
+
c.source?.setOnChange(null);
|
|
166
|
+
c.source = null;
|
|
167
|
+
if (c.value) {
|
|
168
|
+
getCommandsHost(c.value.commands)?.setListener(null);
|
|
169
|
+
c.value = null;
|
|
170
|
+
}
|
|
255
171
|
};
|
|
256
172
|
const useStatewireCore = (getOptions, value) => {
|
|
257
|
-
const
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
173
|
+
const [core] = useState(() => {
|
|
174
|
+
const c = {
|
|
175
|
+
getOptions,
|
|
176
|
+
value: null,
|
|
177
|
+
source: null,
|
|
178
|
+
overlays: [],
|
|
179
|
+
updates: [],
|
|
180
|
+
pendingChanged: [],
|
|
181
|
+
canonical: void 0,
|
|
182
|
+
published: void 0,
|
|
183
|
+
overlayPaths: [],
|
|
184
|
+
notifiedPublished: void 0,
|
|
185
|
+
notifiedOverlayPaths: [],
|
|
186
|
+
notifiedConnection: null,
|
|
187
|
+
notifiedBusy: true,
|
|
188
|
+
stale: false,
|
|
189
|
+
everAttached: false,
|
|
190
|
+
overlaysDirty: false,
|
|
191
|
+
flushing: false,
|
|
192
|
+
scheduled: false,
|
|
193
|
+
listeners: /* @__PURE__ */ new Set(),
|
|
194
|
+
post: createMacrotaskPoster(() => {
|
|
195
|
+
c.scheduled = false;
|
|
196
|
+
flush(c);
|
|
197
|
+
}),
|
|
198
|
+
commandsListener: {
|
|
199
|
+
onStart: (inv) => {
|
|
200
|
+
c.overlays.push({
|
|
201
|
+
inv,
|
|
202
|
+
dropped: false
|
|
203
|
+
});
|
|
204
|
+
c.overlaysDirty = true;
|
|
205
|
+
markStale(c);
|
|
206
|
+
note(c, inv, "queued");
|
|
207
|
+
},
|
|
208
|
+
onPosted: (inv_0) => note(c, inv_0, "posted"),
|
|
209
|
+
onApplied: (inv_1) => note(c, inv_1, "applied"),
|
|
210
|
+
onCovered: (inv_2) => {
|
|
211
|
+
if (!c.overlays.some((o) => o.inv === inv_2)) return;
|
|
212
|
+
c.overlays = c.overlays.filter((o_0) => o_0.inv !== inv_2);
|
|
213
|
+
c.overlaysDirty = true;
|
|
214
|
+
markStale(c);
|
|
215
|
+
},
|
|
216
|
+
onSettle: (inv_3, outcome) => {
|
|
217
|
+
note(c, inv_3, "settled", outcome.type === "accepted" ? { result: outcome.payload } : { failure: failureOf(outcome.error) });
|
|
218
|
+
flush(c);
|
|
219
|
+
}
|
|
220
|
+
},
|
|
221
|
+
getState: () => {
|
|
222
|
+
recompute(c);
|
|
223
|
+
return c.published;
|
|
224
|
+
},
|
|
225
|
+
getBusy: () => c.value?.isBusy ?? true,
|
|
226
|
+
commands: createMethodProxy((method, params) => {
|
|
227
|
+
if (!c.value) return Promise.reject(new StatewireSendError({
|
|
228
|
+
fate: "aborted",
|
|
229
|
+
cause: "unmount"
|
|
230
|
+
}));
|
|
231
|
+
const send = c.value.commands[method];
|
|
232
|
+
const promise = send(...params);
|
|
233
|
+
flush(c);
|
|
234
|
+
return promise;
|
|
235
|
+
}),
|
|
236
|
+
subscribe: (listener) => {
|
|
237
|
+
c.listeners.add(listener);
|
|
238
|
+
return () => {
|
|
239
|
+
c.listeners.delete(listener);
|
|
240
|
+
};
|
|
241
|
+
}
|
|
270
242
|
};
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
useEffect(
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
t2 = () => () => core.detach();
|
|
280
|
-
t3 = [core];
|
|
281
|
-
$[5] = core;
|
|
282
|
-
$[6] = t2;
|
|
283
|
-
$[7] = t3;
|
|
284
|
-
} else {
|
|
285
|
-
t2 = $[6];
|
|
286
|
-
t3 = $[7];
|
|
287
|
-
}
|
|
288
|
-
useEffect(t2, t3);
|
|
243
|
+
return c;
|
|
244
|
+
});
|
|
245
|
+
core.getOptions = getOptions;
|
|
246
|
+
attach(core, value);
|
|
247
|
+
useEffect(() => {
|
|
248
|
+
attach(core, value);
|
|
249
|
+
});
|
|
250
|
+
useEffect(() => () => detach(core), [core]);
|
|
289
251
|
return core;
|
|
290
252
|
};
|
|
291
253
|
//#endregion
|
package/dist/client/core.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core.js","names":["useEffect","useState","createChanges","getCommandsHost","getEmitHost","getStateHost","CommandsInvocation","CommandsListener","recordMutations","createMacrotaskPoster","createMethodProxy","StatewirePath","StatewireSendError","Statewire","StatewireClient","LIVE_CONNECTION","Connection","status","reconnect","failureOf","error","SendFailure","failure","fate","cause","message","Error","String","Overlay","inv","dropped","createCore","getOptions","Options","value","source","StateSource","overlays","updates","CommandUpdate","events","pendingChanged","canonical","published","overlayPaths","notifiedPublished","notifiedOverlayPaths","notifiedConnection","stale","everAttached","overlaysDirty","flushing","listeners","Set","post","scheduled","flush","schedule","markStale","drainCanonical","push","takeChanged","snapshot","undefined","next","initialState","state","recompute","prevCanonical","optimistic","materialize","paths","overlay","ctx","OptimisticContext","ts","seq","clientId","recorded","draft","method","params","Command","changedPaths","console","getConnection","connection","options","stateChanged","prev","changed","onStateChange","changes","length","batch","update","onCommandChange","event","onEvent","connectionChanged","onConnectionChange","listener","note","extra","result","commandsListener","onStart","onPosted","onAck","onCovered","some","o","filter","onSettle","outcome","type","payload","eventSink","attach","nextSource","setOnChange","commands","setListener","emit","setSink","detach","CommandsProxy","Promise","reject","send","Record","args","promise","getState","subscribe","add","delete","useStatewireCore","$","_c","t0","core","t1","t2","t3"],"sources":["../../src/client/core.ts"],"sourcesContent":["import { useEffect, useState } from \"react\";\nimport { createChanges } from \"./changes\";\nimport { getCommandsHost, getEmitHost, getStateHost } from \"../host/host\";\nimport type { CommandsInvocation, CommandsListener } from \"../host/host\";\nimport { recordMutations } from \"../util/recordMutations\";\nimport { createMacrotaskPoster } from \"../util/macrotask\";\nimport { createMethodProxy } from \"../util/methodProxy\";\nimport type { StatewirePath } from \"../wire/ops\";\nimport { StatewireSendError } from \"../types\";\nimport type { Statewire } from \"../types\";\nimport type { StatewireClient } from \"../statewire\";\n\nexport const LIVE_CONNECTION: StatewireClient.Connection = {\n status: \"live\",\n reconnect: () => {},\n};\n\nconst failureOf = (error: unknown): StatewireClient.SendFailure =>\n error instanceof StatewireSendError\n ? error.failure\n : {\n fate: \"rejected\",\n cause: \"server\",\n message: error instanceof Error ? error.message : String(error),\n };\n\ntype Overlay = { inv: CommandsInvocation; dropped: boolean };\n\nconst createCore = (\n getOptions: () => StatewireClient.Options<any, any, any>,\n) => {\n let value: Statewire<unknown> | null = null;\n let source: Statewire.StateSource | null = null;\n let overlays: Overlay[] = [];\n let updates: Statewire.CommandUpdate[] = [];\n let events: unknown[] = [];\n let pendingChanged: StatewirePath[] = [];\n let canonical: unknown;\n let published: unknown;\n let overlayPaths: readonly StatewirePath[] = [];\n let notifiedPublished: unknown;\n let notifiedOverlayPaths: readonly StatewirePath[] = [];\n let notifiedConnection: StatewireClient.Connection | null = null;\n let stale = false;\n let everAttached = false;\n let overlaysDirty = false;\n let flushing = false;\n const listeners = new Set<() => void>();\n\n const post = createMacrotaskPoster(() => {\n scheduled = false;\n flush();\n });\n let scheduled = false;\n const schedule = () => {\n if (scheduled) return;\n scheduled = true;\n post();\n };\n\n const markStale = () => {\n stale = true;\n schedule();\n };\n\n // initialState stands in for the canonical state only before the first\n // attach snapshot; replay boundaries after that read as loading, not preload.\n const drainCanonical = () => {\n if (source) {\n pendingChanged.push(...source.takeChanged());\n const snapshot = source.snapshot();\n if (snapshot !== undefined) {\n everAttached = true;\n canonical = snapshot;\n return;\n }\n const next = everAttached ? undefined : getOptions().initialState;\n if (next !== canonical) pendingChanged.push([]);\n canonical = next;\n } else if (value) {\n if (value.state !== undefined) everAttached = true;\n const next = everAttached ? value.state : getOptions().initialState;\n if (next !== canonical) {\n pendingChanged.push([]);\n canonical = next;\n }\n }\n };\n\n const recompute = () => {\n if (!stale || !value) return;\n stale = false;\n const prevCanonical = canonical;\n drainCanonical();\n if (canonical === prevCanonical && !overlaysDirty) return;\n overlaysDirty = false;\n const { optimistic, materialize } = getOptions();\n let next = canonical;\n let paths: readonly StatewirePath[] = [];\n if (optimistic && canonical !== undefined) {\n for (const overlay of overlays) {\n if (overlay.dropped) continue;\n const { inv } = overlay;\n const ctx: StatewireClient.OptimisticContext = {\n ts: inv.ts,\n seq: inv.seq,\n ...(inv.clientId !== undefined && { clientId: inv.clientId }),\n };\n try {\n const recorded = recordMutations(next, (draft) =>\n optimistic(\n draft as never,\n { method: inv.method, params: inv.params } as Statewire.Command,\n ctx,\n ),\n );\n next = recorded.state;\n paths = [...paths, ...recorded.changedPaths];\n } catch (error) {\n overlay.dropped = true;\n console.error(\n `statewire: optimistic reducer threw for \"${inv.method}\"; dropping its optimistic update`,\n error,\n );\n }\n }\n }\n if (materialize && next !== undefined) {\n try {\n const recorded = recordMutations(next, (draft) =>\n materialize(draft as never),\n );\n next = recorded.state;\n paths = [...paths, ...recorded.changedPaths];\n } catch (error) {\n console.error(\n \"statewire: materialize threw; publishing without its update\",\n error,\n );\n }\n }\n published = next;\n overlayPaths = paths;\n };\n\n const getConnection = (): StatewireClient.Connection =>\n value?.connection ?? LIVE_CONNECTION;\n\n const flush = () => {\n if (!value) return;\n if (flushing) {\n schedule();\n return;\n }\n flushing = true;\n try {\n recompute();\n const options = getOptions();\n const stateChanged = published !== notifiedPublished;\n if (stateChanged) {\n const prev = notifiedPublished;\n const changed = [\n ...pendingChanged,\n ...notifiedOverlayPaths,\n ...overlayPaths,\n ];\n pendingChanged = [];\n notifiedPublished = published;\n notifiedOverlayPaths = overlayPaths;\n options.onStateChange?.(published as never, {\n changes: createChanges(prev, published, changed),\n });\n }\n if (updates.length > 0 && published !== undefined) {\n const batch = updates;\n updates = [];\n for (const update of batch) {\n options.onCommandChange?.(update, { state: published as never });\n }\n }\n if (events.length > 0 && published !== undefined) {\n const batch = events;\n events = [];\n for (const event of batch) {\n options.onEvent?.(event, { state: published as never });\n }\n }\n const connection = getConnection();\n const connectionChanged = connection !== notifiedConnection;\n notifiedConnection = connection;\n if (connectionChanged) options.onConnectionChange?.(connection);\n if (stateChanged || connectionChanged) {\n for (const listener of [...listeners]) listener();\n }\n } finally {\n flushing = false;\n }\n };\n\n const note = (\n inv: CommandsInvocation,\n status: Statewire.CommandUpdate[\"status\"],\n extra?: { result?: unknown; failure?: StatewireClient.SendFailure },\n ) => {\n if (!getOptions().onCommandChange) return;\n updates.push({\n method: inv.method,\n params: inv.params as never[],\n seq: inv.seq,\n status,\n ...extra,\n });\n schedule();\n };\n\n const commandsListener: CommandsListener = {\n onStart: (inv) => {\n overlays.push({ inv, dropped: false });\n overlaysDirty = true;\n markStale();\n note(inv, \"queued\");\n },\n onPosted: (inv) => note(inv, \"posted\"),\n onAck: (inv) => note(inv, \"acked\"),\n onCovered: (inv) => {\n if (!overlays.some((o) => o.inv === inv)) return;\n overlays = overlays.filter((o) => o.inv !== inv);\n overlaysDirty = true;\n markStale();\n },\n onSettle: (inv, outcome) => {\n note(\n inv,\n \"settled\",\n outcome.type === \"accepted\"\n ? { result: outcome.payload }\n : { failure: failureOf(outcome.error) },\n );\n flush();\n },\n };\n\n const eventSink = (event: unknown) => {\n if (!getOptions().onEvent) return;\n events.push(event);\n schedule();\n };\n\n const attach = (next: Statewire<unknown>) => {\n if (next === value) return;\n const prev = value;\n value = next;\n const nextSource =\n next.source ??\n (typeof next.state === \"object\" && next.state !== null\n ? getStateHost(next.state)\n : undefined) ??\n null;\n if (nextSource !== source) {\n source?.setOnChange(null);\n source = nextSource;\n source?.setOnChange(markStale);\n // A new source is a new attach lifecycle: initialState preloads again.\n everAttached = false;\n markStale();\n }\n if (next.commands !== prev?.commands) {\n if (prev) getCommandsHost(prev.commands)?.setListener(null);\n getCommandsHost(next.commands)?.setListener(commandsListener);\n if (overlays.length > 0) {\n overlays = [];\n overlaysDirty = true;\n }\n markStale();\n }\n if (next.emit !== prev?.emit) {\n if (prev) getEmitHost(prev.emit)?.setSink(null);\n getEmitHost(next.emit)?.setSink(eventSink);\n }\n if (!source) markStale();\n schedule();\n };\n\n const detach = () => {\n source?.setOnChange(null);\n source = null;\n if (value) {\n getCommandsHost(value.commands)?.setListener(null);\n getEmitHost(value.emit)?.setSink(null);\n value = null;\n }\n };\n\n const commands = createMethodProxy<Statewire.CommandsProxy<any>>(\n (method, params) => {\n if (!value) {\n return Promise.reject(\n new StatewireSendError({ fate: \"aborted\", cause: \"unmount\" }),\n );\n }\n const send = (\n value.commands as Record<\n string,\n (...args: unknown[]) => Promise<unknown>\n >\n )[method]!;\n const promise = send(...params);\n flush();\n return promise;\n },\n );\n\n return {\n attach,\n detach,\n getState: () => {\n recompute();\n return published;\n },\n commands,\n subscribe: (listener: () => void) => {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n };\n};\n\nexport const useStatewireCore = (\n getOptions: () => StatewireClient.Options<any, any, any>,\n value: Statewire<unknown>,\n) => {\n const [core] = useState(() => createCore(getOptions));\n // Attach during render so the first snapshot reads the transport's state;\n // re-attaching the same transport is a no-op and the single-slot host\n // listeners make a swap land on the last writer.\n core.attach(value);\n useEffect(() => {\n core.attach(value);\n });\n useEffect(() => () => core.detach(), [core]);\n return core;\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"core.js","names":["useEffect","useState","createChanges","getCommandsHost","getStateHost","CommandsInvocation","CommandsListener","recordMutations","createMacrotaskPoster","createMethodProxy","StatewirePath","StatewireSendError","Statewire","StatewireClient","LIVE_CONNECTION","Connection","status","reconnect","failureOf","error","SendFailure","failure","fate","cause","message","Error","String","Overlay","inv","dropped","Core","getOptions","Options","value","source","StateSource","overlays","updates","CommandUpdate","pendingChanged","canonical","published","overlayPaths","notifiedPublished","notifiedOverlayPaths","notifiedConnection","notifiedBusy","stale","everAttached","overlaysDirty","flushing","scheduled","listeners","Set","post","commandsListener","getState","getBusy","commands","CommandsProxy","subscribe","listener","schedule","c","markStale","drainCanonical","push","takeChanged","snapshot","undefined","next","initialState","state","recompute","prevCanonical","optimistic","materialize","paths","overlay","ctx","OptimisticContext","ts","seq","clientId","recorded","draft","method","params","Command","changedPaths","console","getConnection","connection","flush","options","stateChanged","prev","changed","onStateChange","changes","length","batch","update","onCommandChange","connectionChanged","onConnectionChange","busy","busyChanged","note","extra","result","attach","nextSource","setOnChange","setListener","detach","useStatewireCore","core","onStart","onPosted","onApplied","onCovered","some","o","filter","onSettle","outcome","type","payload","isBusy","Promise","reject","send","Record","args","promise","add","delete"],"sources":["../../src/client/core.ts"],"sourcesContent":["import { useEffect, useState } from \"react\";\nimport { createChanges } from \"./changes\";\nimport { getCommandsHost, getStateHost } from \"../host/host\";\nimport type { CommandsInvocation, CommandsListener } from \"../host/host\";\nimport { recordMutations } from \"../util/recordMutations\";\nimport { createMacrotaskPoster } from \"../util/macrotask\";\nimport { createMethodProxy } from \"../util/methodProxy\";\nimport type { StatewirePath } from \"../wire/ops\";\nimport { StatewireSendError } from \"../types\";\nimport type { Statewire } from \"../types\";\nimport type { StatewireClient } from \"../statewire\";\n\nexport const LIVE_CONNECTION: StatewireClient.Connection = {\n status: \"live\",\n reconnect: () => {},\n};\n\nconst failureOf = (error: unknown): StatewireClient.SendFailure =>\n error instanceof StatewireSendError\n ? error.failure\n : {\n fate: \"rejected\",\n cause: \"server\",\n message: error instanceof Error ? error.message : String(error),\n };\n\ntype Overlay = { inv: CommandsInvocation; dropped: boolean };\n\ntype Core = {\n getOptions: () => StatewireClient.Options<any, any>;\n value: Statewire<unknown> | null;\n source: Statewire.StateSource | null;\n overlays: Overlay[];\n updates: Statewire.CommandUpdate[];\n pendingChanged: StatewirePath[];\n canonical: unknown;\n published: unknown;\n overlayPaths: readonly StatewirePath[];\n notifiedPublished: unknown;\n notifiedOverlayPaths: readonly StatewirePath[];\n notifiedConnection: StatewireClient.Connection | null;\n notifiedBusy: boolean;\n stale: boolean;\n everAttached: boolean;\n overlaysDirty: boolean;\n flushing: boolean;\n scheduled: boolean;\n listeners: Set<() => void>;\n post: () => void;\n commandsListener: CommandsListener;\n getState: () => unknown;\n getBusy: () => boolean;\n commands: Statewire.CommandsProxy<any>;\n subscribe: (listener: () => void) => () => void;\n};\n\nconst schedule = (c: Core) => {\n if (c.scheduled) return;\n c.scheduled = true;\n c.post();\n};\n\nconst markStale = (c: Core) => {\n c.stale = true;\n schedule(c);\n};\n\n// initialState stands in for the canonical state only before the first\n// attach snapshot; replay boundaries after that read as loading, not preload.\nconst drainCanonical = (c: Core) => {\n if (c.source) {\n c.pendingChanged.push(...c.source.takeChanged());\n const snapshot = c.source.snapshot();\n if (snapshot !== undefined) {\n c.everAttached = true;\n c.canonical = snapshot;\n return;\n }\n const next = c.everAttached ? undefined : c.getOptions().initialState;\n if (next !== c.canonical) c.pendingChanged.push([]);\n c.canonical = next;\n } else if (c.value) {\n if (c.value.state !== undefined) c.everAttached = true;\n const next = c.everAttached ? c.value.state : c.getOptions().initialState;\n if (next !== c.canonical) {\n c.pendingChanged.push([]);\n c.canonical = next;\n }\n }\n};\n\nconst recompute = (c: Core) => {\n if (!c.stale || !c.value) return;\n c.stale = false;\n const prevCanonical = c.canonical;\n drainCanonical(c);\n if (c.canonical === prevCanonical && !c.overlaysDirty) return;\n c.overlaysDirty = false;\n const { optimistic, materialize } = c.getOptions();\n let next = c.canonical;\n let paths: readonly StatewirePath[] = [];\n if (optimistic && c.canonical !== undefined) {\n for (const overlay of c.overlays) {\n if (overlay.dropped) continue;\n const { inv } = overlay;\n const ctx: StatewireClient.OptimisticContext = {\n ts: inv.ts,\n seq: inv.seq,\n ...(inv.clientId !== undefined && { clientId: inv.clientId }),\n };\n try {\n const recorded = recordMutations(next, (draft) =>\n optimistic(\n draft as never,\n { method: inv.method, params: inv.params } as Statewire.Command,\n ctx,\n ),\n );\n next = recorded.state;\n paths = [...paths, ...recorded.changedPaths];\n } catch (error) {\n overlay.dropped = true;\n console.error(\n `statewire: optimistic reducer threw for \"${inv.method}\"; dropping its optimistic update`,\n error,\n );\n }\n }\n }\n if (materialize && next !== undefined) {\n try {\n const recorded = recordMutations(next, (draft) =>\n materialize(draft as never),\n );\n next = recorded.state;\n paths = [...paths, ...recorded.changedPaths];\n } catch (error) {\n console.error(\n \"statewire: materialize threw; publishing without its update\",\n error,\n );\n }\n }\n c.published = next;\n c.overlayPaths = paths;\n};\n\nconst getConnection = (c: Core): StatewireClient.Connection =>\n c.value?.connection ?? LIVE_CONNECTION;\n\nconst flush = (c: Core) => {\n if (!c.value) return;\n if (c.flushing) {\n schedule(c);\n return;\n }\n c.flushing = true;\n try {\n recompute(c);\n const options = c.getOptions();\n const stateChanged = c.published !== c.notifiedPublished;\n if (stateChanged) {\n const prev = c.notifiedPublished;\n const changed = [\n ...c.pendingChanged,\n ...c.notifiedOverlayPaths,\n ...c.overlayPaths,\n ];\n c.pendingChanged = [];\n c.notifiedPublished = c.published;\n c.notifiedOverlayPaths = c.overlayPaths;\n options.onStateChange?.(c.published as never, {\n changes: createChanges(prev, c.published, changed),\n });\n }\n if (c.updates.length > 0 && c.published !== undefined) {\n const batch = c.updates;\n c.updates = [];\n for (const update of batch) {\n options.onCommandChange?.(update, { state: c.published as never });\n }\n }\n const connection = getConnection(c);\n const connectionChanged = connection !== c.notifiedConnection;\n c.notifiedConnection = connection;\n if (connectionChanged) options.onConnectionChange?.(connection);\n const busy = c.getBusy();\n const busyChanged = busy !== c.notifiedBusy;\n c.notifiedBusy = busy;\n if (stateChanged || connectionChanged || busyChanged) {\n for (const listener of [...c.listeners]) listener();\n }\n } finally {\n c.flushing = false;\n }\n};\n\nconst note = (\n c: Core,\n inv: CommandsInvocation,\n status: Statewire.CommandUpdate[\"status\"],\n extra?: { result?: unknown; failure?: StatewireClient.SendFailure },\n) => {\n if (!c.getOptions().onCommandChange) return;\n c.updates.push({\n method: inv.method,\n params: inv.params as never[],\n seq: inv.seq,\n status,\n ...extra,\n });\n schedule(c);\n};\n\nconst attach = (c: Core, next: Statewire<unknown>) => {\n if (next === c.value) return;\n const prev = c.value;\n c.value = next;\n const nextSource =\n next.source ??\n (typeof next.state === \"object\" && next.state !== null\n ? getStateHost(next.state)\n : undefined) ??\n null;\n if (nextSource !== c.source) {\n c.source?.setOnChange(null);\n c.source = nextSource;\n c.source?.setOnChange(() => markStale(c));\n // A new source is a new attach lifecycle: initialState preloads again.\n c.everAttached = false;\n markStale(c);\n }\n if (next.commands !== prev?.commands) {\n if (prev) getCommandsHost(prev.commands)?.setListener(null);\n getCommandsHost(next.commands)?.setListener(c.commandsListener);\n if (c.overlays.length > 0) {\n c.overlays = [];\n c.overlaysDirty = true;\n }\n markStale(c);\n }\n if (!c.source) markStale(c);\n schedule(c);\n};\n\nconst detach = (c: Core) => {\n c.source?.setOnChange(null);\n c.source = null;\n if (c.value) {\n getCommandsHost(c.value.commands)?.setListener(null);\n c.value = null;\n }\n};\n\nexport const useStatewireCore = (\n getOptions: () => StatewireClient.Options<any, any>,\n value: Statewire<unknown>,\n) => {\n const [core] = useState((): Core => {\n const c: Core = {\n getOptions,\n value: null,\n source: null,\n overlays: [],\n updates: [],\n pendingChanged: [],\n canonical: undefined,\n published: undefined,\n overlayPaths: [],\n notifiedPublished: undefined,\n notifiedOverlayPaths: [],\n notifiedConnection: null,\n notifiedBusy: true,\n stale: false,\n everAttached: false,\n overlaysDirty: false,\n flushing: false,\n scheduled: false,\n listeners: new Set(),\n post: createMacrotaskPoster(() => {\n c.scheduled = false;\n flush(c);\n }),\n commandsListener: {\n onStart: (inv) => {\n c.overlays.push({ inv, dropped: false });\n c.overlaysDirty = true;\n markStale(c);\n note(c, inv, \"queued\");\n },\n onPosted: (inv) => note(c, inv, \"posted\"),\n onApplied: (inv) => note(c, inv, \"applied\"),\n onCovered: (inv) => {\n if (!c.overlays.some((o) => o.inv === inv)) return;\n c.overlays = c.overlays.filter((o) => o.inv !== inv);\n c.overlaysDirty = true;\n markStale(c);\n },\n onSettle: (inv, outcome) => {\n note(\n c,\n inv,\n \"settled\",\n outcome.type === \"accepted\"\n ? { result: outcome.payload }\n : { failure: failureOf(outcome.error) },\n );\n flush(c);\n },\n },\n getState: () => {\n recompute(c);\n return c.published;\n },\n getBusy: () => c.value?.isBusy ?? true,\n commands: createMethodProxy<Statewire.CommandsProxy<any>>(\n (method, params) => {\n if (!c.value) {\n return Promise.reject(\n new StatewireSendError({ fate: \"aborted\", cause: \"unmount\" }),\n );\n }\n const send = (\n c.value.commands as Record<\n string,\n (...args: unknown[]) => Promise<unknown>\n >\n )[method]!;\n const promise = send(...params);\n flush(c);\n return promise;\n },\n ),\n subscribe: (listener) => {\n c.listeners.add(listener);\n return () => {\n c.listeners.delete(listener);\n };\n },\n };\n return c;\n });\n core.getOptions = getOptions;\n // Attach during render so the first snapshot reads the transport's state;\n // re-attaching the same transport is a no-op and the single-slot host\n // listeners make a swap land on the last writer.\n attach(core, value);\n useEffect(() => {\n attach(core, value);\n });\n useEffect(() => () => detach(core), [core]);\n return core;\n};\n"],"mappings":"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"}
|