statewire 0.8.1 → 0.9.1

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.
Files changed (95) hide show
  1. package/README.md +2 -2
  2. package/dist/client/connection.d.ts +23 -19
  3. package/dist/client/connection.d.ts.map +1 -1
  4. package/dist/client/connection.js +143 -103
  5. package/dist/client/connection.js.map +1 -1
  6. package/dist/client/core.d.ts +30 -3
  7. package/dist/client/core.d.ts.map +1 -1
  8. package/dist/client/core.js +222 -260
  9. package/dist/client/core.js.map +1 -1
  10. package/dist/client/session.d.ts +34 -39
  11. package/dist/client/session.d.ts.map +1 -1
  12. package/dist/client/session.js +380 -373
  13. package/dist/client/session.js.map +1 -1
  14. package/dist/client/sessionStore.d.ts +1 -0
  15. package/dist/client/sessionStore.d.ts.map +1 -1
  16. package/dist/client/sessionStore.js.map +1 -1
  17. package/dist/client/timing.d.ts +1 -2
  18. package/dist/client/timing.d.ts.map +1 -1
  19. package/dist/client/timing.js +1 -5
  20. package/dist/client/timing.js.map +1 -1
  21. package/dist/host/draft.d.ts +2 -5
  22. package/dist/host/draft.d.ts.map +1 -1
  23. package/dist/host/draft.js.map +1 -1
  24. package/dist/host/host.d.ts +5 -8
  25. package/dist/host/host.d.ts.map +1 -1
  26. package/dist/host/host.js +23 -32
  27. package/dist/host/host.js.map +1 -1
  28. package/dist/host/socket.d.ts +3 -2
  29. package/dist/host/socket.d.ts.map +1 -1
  30. package/dist/host/socket.js +484 -424
  31. package/dist/host/socket.js.map +1 -1
  32. package/dist/host-internal.d.ts +4 -0
  33. package/dist/host-internal.d.ts.map +1 -1
  34. package/dist/host.d.ts +10 -10
  35. package/dist/host.d.ts.map +1 -1
  36. package/dist/host.js +2 -2
  37. package/dist/index.d.ts +1 -2
  38. package/dist/index.js +1 -2
  39. package/dist/statewire.d.ts +29 -24
  40. package/dist/statewire.d.ts.map +1 -1
  41. package/dist/statewire.js +8 -2
  42. package/dist/statewire.js.map +1 -1
  43. package/dist/transports/fake-sse.d.ts +1 -1
  44. package/dist/transports/fake-sse.d.ts.map +1 -1
  45. package/dist/transports/fake-sse.js +5 -2
  46. package/dist/transports/fake-sse.js.map +1 -1
  47. package/dist/transports/fixtures.d.ts +1 -2
  48. package/dist/transports/fixtures.d.ts.map +1 -1
  49. package/dist/transports/fixtures.js +5 -7
  50. package/dist/transports/fixtures.js.map +1 -1
  51. package/dist/transports/remote.d.ts +2 -1
  52. package/dist/transports/remote.d.ts.map +1 -1
  53. package/dist/transports/remote.js +10 -4
  54. package/dist/transports/remote.js.map +1 -1
  55. package/dist/transports/sse.d.ts +32 -46
  56. package/dist/transports/sse.d.ts.map +1 -1
  57. package/dist/transports/sse.js +56 -59
  58. package/dist/transports/sse.js.map +1 -1
  59. package/dist/transports/testing.d.ts +7 -5
  60. package/dist/transports/testing.d.ts.map +1 -1
  61. package/dist/transports/testing.js +41 -14
  62. package/dist/transports/testing.js.map +1 -1
  63. package/dist/transports/ws.d.ts +2 -3
  64. package/dist/transports/ws.d.ts.map +1 -1
  65. package/dist/transports/ws.js +25 -80
  66. package/dist/transports/ws.js.map +1 -1
  67. package/dist/types.d.ts +8 -8
  68. package/dist/types.d.ts.map +1 -1
  69. package/dist/types.js +3 -4
  70. package/dist/types.js.map +1 -1
  71. package/dist/wire/ops.d.ts +1 -5
  72. package/dist/wire/ops.d.ts.map +1 -1
  73. package/dist/wire/ops.js +6 -5
  74. package/dist/wire/ops.js.map +1 -1
  75. package/package.json +1 -1
  76. package/src/client/connection.ts +175 -128
  77. package/src/client/core.ts +287 -278
  78. package/src/client/session.ts +474 -480
  79. package/src/client/sessionStore.ts +1 -0
  80. package/src/client/timing.ts +0 -6
  81. package/src/host/draft.ts +1 -3
  82. package/src/host/host.ts +41 -58
  83. package/src/host/socket.ts +653 -448
  84. package/src/host-internal.ts +4 -0
  85. package/src/host.ts +13 -10
  86. package/src/index.ts +0 -1
  87. package/src/statewire.ts +38 -32
  88. package/src/transports/fake-sse.ts +2 -1
  89. package/src/transports/fixtures.ts +4 -9
  90. package/src/transports/remote.ts +12 -5
  91. package/src/transports/sse.ts +99 -115
  92. package/src/transports/testing.ts +47 -19
  93. package/src/transports/ws.ts +44 -115
  94. package/src/types.ts +15 -14
  95. package/src/wire/ops.ts +13 -16
@@ -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, getEmitHost, getStateHost } from "../host/host.js";
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 createCore = (getOptions) => {
20
- let value = null;
21
- let source = null;
22
- let overlays = [];
23
- let updates = [];
24
- let events = [];
25
- let pendingChanged = [];
26
- let canonical;
27
- let published;
28
- let overlayPaths = [];
29
- let notifiedPublished;
30
- let notifiedOverlayPaths = [];
31
- let notifiedConnection = null;
32
- let stale = false;
33
- let everAttached = false;
34
- let overlaysDirty = false;
35
- let flushing = false;
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
- const recompute = () => {
73
- if (!stale || !value) return;
74
- stale = false;
75
- const prevCanonical = canonical;
76
- drainCanonical();
77
- if (canonical === prevCanonical && !overlaysDirty) return;
78
- overlaysDirty = false;
79
- const { optimistic, materialize } = getOptions();
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
- if (materialize && next !== void 0) try {
103
- const recorded = recordMutations(next, (draft) => materialize(draft));
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
- console.error("statewire: materialize threw; publishing without its update", error);
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
- if (next.commands !== prev?.commands) {
207
- if (prev) getCommandsHost(prev.commands)?.setListener(null);
208
- getCommandsHost(next.commands)?.setListener(commandsListener);
209
- if (overlays.length > 0) {
210
- overlays = [];
211
- overlaysDirty = true;
212
- }
213
- markStale();
214
- }
215
- if (next.emit !== prev?.emit) {
216
- if (prev) getEmitHost(prev.emit)?.setSink(null);
217
- getEmitHost(next.emit)?.setSink(eventSink);
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 (!source) markStale();
220
- schedule();
221
- };
222
- const detach = () => {
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
- return {
232
- attach,
233
- detach,
234
- getState: () => {
235
- recompute();
236
- return published;
237
- },
238
- commands: createMethodProxy((method, params) => {
239
- if (!value) return Promise.reject(new StatewireSendError({
240
- fate: "aborted",
241
- cause: "unmount"
242
- }));
243
- const send = value.commands[method];
244
- const promise = send(...params);
245
- flush();
246
- return promise;
247
- }),
248
- subscribe: (listener) => {
249
- listeners.add(listener);
250
- return () => {
251
- listeners.delete(listener);
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 $ = c(8);
258
- let t0;
259
- if ($[0] !== getOptions) {
260
- t0 = () => createCore(getOptions);
261
- $[0] = getOptions;
262
- $[1] = t0;
263
- } else t0 = $[1];
264
- const [core] = useState(t0);
265
- core.attach(value);
266
- let t1;
267
- if ($[2] !== core || $[3] !== value) {
268
- t1 = () => {
269
- core.attach(value);
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
- $[2] = core;
272
- $[3] = value;
273
- $[4] = t1;
274
- } else t1 = $[4];
275
- useEffect(t1);
276
- let t2;
277
- let t3;
278
- if ($[5] !== core) {
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
@@ -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":";;;;;;;;AAYA,MAAac,kBAA8C;CACzDE,QAAQ;CACRC,iBAAiB,CAAC;AACpB;AAEA,MAAMC,aAAaC,UACjBA,iBAAiBR,qBACbQ,MAAME,UACN;CACEC,MAAM;CACNC,OAAO;CACPC,SAASL,iBAAiBM,QAAQN,MAAMK,UAAUE,OAAOP,KAAK;AAChE;AAgCN,MAAM2C,YAAYC,MAAY;CAC5B,IAAIA,EAAEZ,WAAW;CACjBY,EAAEZ,YAAY;CACdY,EAAET,KAAK;AACT;AAEA,MAAMU,aAAaD,MAAY;CAC7BA,EAAEhB,QAAQ;CACVe,SAASC,CAAC;AACZ;AAIA,MAAME,kBAAkBF,MAAY;CAClC,IAAIA,EAAE7B,QAAQ;EACZ6B,EAAExB,eAAe2B,KAAK,GAAGH,EAAE7B,OAAOiC,YAAY,CAAC;EAC/C,MAAMC,WAAWL,EAAE7B,OAAOkC,SAAS;EACnC,IAAIA,aAAaC,KAAAA,GAAW;GAC1BN,EAAEf,eAAe;GACjBe,EAAEvB,YAAY4B;GACd;EACF;EACA,MAAME,OAAOP,EAAEf,eAAeqB,KAAAA,IAAYN,EAAEhC,WAAW,CAAC,CAACwC;EACzD,IAAID,SAASP,EAAEvB,WAAWuB,EAAExB,eAAe2B,KAAK,CAAA,CAAE;EAClDH,EAAEvB,YAAY8B;CAChB,OAAO,IAAIP,EAAE9B,OAAO;EAClB,IAAI8B,EAAE9B,MAAMuC,UAAUH,KAAAA,GAAWN,EAAEf,eAAe;EAClD,MAAMsB,OAAOP,EAAEf,eAAee,EAAE9B,MAAMuC,QAAQT,EAAEhC,WAAW,CAAC,CAACwC;EAC7D,IAAID,SAASP,EAAEvB,WAAW;GACxBuB,EAAExB,eAAe2B,KAAK,CAAA,CAAE;GACxBH,EAAEvB,YAAY8B;EAChB;CACF;AACF;AAEA,MAAMG,aAAaV,MAAY;CAC7B,IAAI,CAACA,EAAEhB,SAAS,CAACgB,EAAE9B,OAAO;CAC1B8B,EAAEhB,QAAQ;CACV,MAAM2B,gBAAgBX,EAAEvB;CACxByB,eAAeF,CAAC;CAChB,IAAIA,EAAEvB,cAAckC,iBAAiB,CAACX,EAAEd,eAAe;CACvDc,EAAEd,gBAAgB;CAClB,MAAM,EAAE0B,YAAYC,gBAAgBb,EAAEhC,WAAW;CACjD,IAAIuC,OAAOP,EAAEvB;CACb,IAAIqC,QAAkC,CAAA;CACtC,IAAIF,cAAcZ,EAAEvB,cAAc6B,KAAAA,GAChC,KAAK,MAAMS,WAAWf,EAAE3B,UAAU;EAChC,IAAI0C,QAAQjD,SAAS;EACrB,MAAM,EAAED,QAAQkD;EAChB,MAAMC,MAAyC;GAC7CE,IAAIrD,IAAIqD;GACRC,KAAKtD,IAAIsD;GACT,GAAItD,IAAIuD,aAAad,KAAAA,KAAa,EAAEc,UAAUvD,IAAIuD,SAAS;EAC7D;EACA,IAAI;GACF,MAAMC,WAAW7E,gBAAgB+D,OAAOe,UACtCV,WACEU,OACA;IAAEC,QAAQ1D,IAAI0D;IAAQC,QAAQ3D,IAAI2D;GAAO,GACzCR,GACF,CACF;GACAT,OAAOc,SAASZ;GAChBK,QAAQ,CAAC,GAAGA,OAAO,GAAGO,SAASK,YAAY;EAC7C,SAAStE,OAAO;GACd2D,QAAQjD,UAAU;GAClB6D,QAAQvE,MACN,4CAA4CS,IAAI0D,OAAM,oCACtDnE,KACF;EACF;CACF;CAEF,IAAIyD,eAAeN,SAASD,KAAAA,GAC1B,IAAI;EACF,MAAMe,WAAW7E,gBAAgB+D,OAAOe,UACtCT,YAAYS,KAAc,CAC5B;EACAf,OAAOc,SAASZ;EAChBK,QAAQ,CAAC,GAAGA,OAAO,GAAGO,SAASK,YAAY;CAC7C,SAAStE,OAAO;EACduE,QAAQvE,MACN,+DACAA,KACF;CACF;CAEF4C,EAAEtB,YAAY6B;CACdP,EAAErB,eAAemC;AACnB;AAEA,MAAMc,iBAAiB5B,MACrBA,EAAE9B,OAAO2D,cAAc9E;AAEzB,MAAM+E,SAAS9B,MAAY;CACzB,IAAI,CAACA,EAAE9B,OAAO;CACd,IAAI8B,EAAEb,UAAU;EACdY,SAASC,CAAC;EACV;CACF;CACAA,EAAEb,WAAW;CACb,IAAI;EACFuB,UAAUV,CAAC;EACX,MAAM+B,UAAU/B,EAAEhC,WAAW;EAC7B,MAAMgE,eAAehC,EAAEtB,cAAcsB,EAAEpB;EACvC,IAAIoD,cAAc;GAChB,MAAMC,OAAOjC,EAAEpB;GACf,MAAMsD,UAAU;IACd,GAAGlC,EAAExB;IACL,GAAGwB,EAAEnB;IACL,GAAGmB,EAAErB;GAAY;GAEnBqB,EAAExB,iBAAiB,CAAA;GACnBwB,EAAEpB,oBAAoBoB,EAAEtB;GACxBsB,EAAEnB,uBAAuBmB,EAAErB;GAC3BoD,QAAQI,gBAAgBnC,EAAEtB,WAAoB,EAC5C0D,SAASjG,cAAc8F,MAAMjC,EAAEtB,WAAWwD,OAAO,EACnD,CAAC;EACH;EACA,IAAIlC,EAAE1B,QAAQ+D,SAAS,KAAKrC,EAAEtB,cAAc4B,KAAAA,GAAW;GACrD,MAAMgC,QAAQtC,EAAE1B;GAChB0B,EAAE1B,UAAU,CAAA;GACZ,KAAK,MAAMiE,UAAUD,OACnBP,QAAQS,kBAAkBD,QAAQ,EAAE9B,OAAOT,EAAEtB,UAAmB,CAAC;EAErE;EACA,MAAMmD,aAAaD,cAAc5B,CAAC;EAClC,MAAMyC,oBAAoBZ,eAAe7B,EAAElB;EAC3CkB,EAAElB,qBAAqB+C;EACvB,IAAIY,mBAAmBV,QAAQW,qBAAqBb,UAAU;EAC9D,MAAMc,OAAO3C,EAAEN,QAAQ;EACvB,MAAMkD,cAAcD,SAAS3C,EAAEjB;EAC/BiB,EAAEjB,eAAe4D;EACjB,IAAIX,gBAAgBS,qBAAqBG,aACvC,KAAK,MAAM9C,YAAY,CAAC,GAAGE,EAAEX,SAAS,GAAGS,SAAS;CAEtD,UAAU;EACRE,EAAEb,WAAW;CACf;AACF;AAEA,MAAM0D,QACJ7C,GACAnC,KACAZ,QACA6F,UACG;CACH,IAAI,CAAC9C,EAAEhC,WAAW,CAAC,CAACwE,iBAAiB;CACrCxC,EAAE1B,QAAQ6B,KAAK;EACboB,QAAQ1D,IAAI0D;EACZC,QAAQ3D,IAAI2D;EACZL,KAAKtD,IAAIsD;EACTlE;EACA,GAAG6F;CACL,CAAC;CACD/C,SAASC,CAAC;AACZ;AAEA,MAAMgD,UAAUhD,GAASO,SAA6B;CACpD,IAAIA,SAASP,EAAE9B,OAAO;CACtB,MAAM+D,OAAOjC,EAAE9B;CACf8B,EAAE9B,QAAQqC;CACV,MAAM0C,aACJ1C,KAAKpC,WACJ,OAAOoC,KAAKE,UAAU,YAAYF,KAAKE,UAAU,OAC9CpE,aAAakE,KAAKE,KAAK,IACvBH,KAAAA,MACJ;CACF,IAAI2C,eAAejD,EAAE7B,QAAQ;EAC3B6B,EAAE7B,QAAQ+E,YAAY,IAAI;EAC1BlD,EAAE7B,SAAS8E;EACXjD,EAAE7B,QAAQ+E,kBAAkBjD,UAAUD,CAAC,CAAC;EAExCA,EAAEf,eAAe;EACjBgB,UAAUD,CAAC;CACb;CACA,IAAIO,KAAKZ,aAAasC,MAAMtC,UAAU;EACpC,IAAIsC,MAAM7F,gBAAgB6F,KAAKtC,QAAQ,CAAC,EAAEwD,YAAY,IAAI;EAC1D/G,gBAAgBmE,KAAKZ,QAAQ,CAAC,EAAEwD,YAAYnD,EAAER,gBAAgB;EAC9D,IAAIQ,EAAE3B,SAASgE,SAAS,GAAG;GACzBrC,EAAE3B,WAAW,CAAA;GACb2B,EAAEd,gBAAgB;EACpB;EACAe,UAAUD,CAAC;CACb;CACA,IAAI,CAACA,EAAE7B,QAAQ8B,UAAUD,CAAC;CAC1BD,SAASC,CAAC;AACZ;AAEA,MAAMoD,UAAUpD,MAAY;CAC1BA,EAAE7B,QAAQ+E,YAAY,IAAI;CAC1BlD,EAAE7B,SAAS;CACX,IAAI6B,EAAE9B,OAAO;EACX9B,gBAAgB4D,EAAE9B,MAAMyB,QAAQ,CAAC,EAAEwD,YAAY,IAAI;EACnDnD,EAAE9B,QAAQ;CACZ;AACF;AAEA,MAAamF,oBACXrF,YACAE,UACG;CACH,MAAM,CAACoF,QAAQpH,eAAqB;EAClC,MAAM8D,IAAU;GACdhC;GACAE,OAAO;GACPC,QAAQ;GACRE,UAAU,CAAA;GACVC,SAAS,CAAA;GACTE,gBAAgB,CAAA;GAChBC,WAAW6B,KAAAA;GACX5B,WAAW4B,KAAAA;GACX3B,cAAc,CAAA;GACdC,mBAAmB0B,KAAAA;GACnBzB,sBAAsB,CAAA;GACtBC,oBAAoB;GACpBC,cAAc;GACdC,OAAO;GACPC,cAAc;GACdC,eAAe;GACfC,UAAU;GACVC,WAAW;GACXC,2BAAW,IAAIC,IAAI;GACnBC,MAAM9C,4BAA4B;IAChCuD,EAAEZ,YAAY;IACd0C,MAAM9B,CAAC;GACT,CAAC;GACDR,kBAAkB;IAChB+D,UAAU1F,QAAQ;KAChBmC,EAAE3B,SAAS8B,KAAK;MAAEtC;MAAKC,SAAS;KAAM,CAAC;KACvCkC,EAAEd,gBAAgB;KAClBe,UAAUD,CAAC;KACX6C,KAAK7C,GAAGnC,KAAK,QAAQ;IACvB;IACA2F,WAAW3F,UAAQgF,KAAK7C,GAAGnC,OAAK,QAAQ;IACxC4F,YAAY5F,UAAQgF,KAAK7C,GAAGnC,OAAK,SAAS;IAC1C6F,YAAY7F,UAAQ;KAClB,IAAI,CAACmC,EAAE3B,SAASsF,MAAMC,MAAMA,EAAE/F,QAAQA,KAAG,GAAG;KAC5CmC,EAAE3B,WAAW2B,EAAE3B,SAASwF,QAAQD,QAAMA,IAAE/F,QAAQA,KAAG;KACnDmC,EAAEd,gBAAgB;KAClBe,UAAUD,CAAC;IACb;IACA8D,WAAWjG,OAAKkG,YAAY;KAC1BlB,KACE7C,GACAnC,OACA,WACAkG,QAAQC,SAAS,aACb,EAAEjB,QAAQgB,QAAQE,QAAQ,IAC1B,EAAE3G,SAASH,UAAU4G,QAAQ3G,KAAK,EAAE,CAC1C;KACA0E,MAAM9B,CAAC;IACT;GACF;GACAP,gBAAgB;IACdiB,UAAUV,CAAC;IACX,OAAOA,EAAEtB;GACX;GACAgB,eAAeM,EAAE9B,OAAOgG,UAAU;GAClCvE,UAAUjD,mBACP6E,QAAQC,WAAW;IAClB,IAAI,CAACxB,EAAE9B,OACL,OAAOiG,QAAQC,OACb,IAAIxH,mBAAmB;KAAEW,MAAM;KAAWC,OAAO;IAAU,CAAC,CAC9D;IAEF,MAAM6G,OACJrE,EAAE9B,MAAMyB,SAIR4B;IACF,MAAMiD,UAAUH,KAAK,GAAG7C,MAAM;IAC9BM,MAAM9B,CAAC;IACP,OAAOwE;GACT,CACF;GACA3E,YAAYC,aAAa;IACvBE,EAAEX,UAAUoF,IAAI3E,QAAQ;IACxB,aAAa;KACXE,EAAEX,UAAUqF,OAAO5E,QAAQ;IAC7B;GACF;EACF;EACA,OAAOE;CACT,CAAC;CACDsD,KAAKtF,aAAaA;CAIlBgF,OAAOM,MAAMpF,KAAK;CAClBjC,gBAAgB;EACd+G,OAAOM,MAAMpF,KAAK;CACpB,CAAC;CACDjC,sBAAsBmH,OAAOE,IAAI,GAAG,CAACA,IAAI,CAAC;CAC1C,OAAOA;AACT"}