@yoltra/core 0.5.0 → 0.7.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.es.md +462 -76
- package/README.md +317 -63
- package/dist/types/index.d.ts +6 -1
- package/dist/types/persistence/persist.d.ts +3 -6
- package/dist/types/reducer/Reducer.d.ts +3 -2
- package/dist/types/store/Store.d.ts +239 -56
- package/dist/types/store/call.d.ts +149 -0
- package/dist/types/store/callQueue.d.ts +79 -0
- package/dist/types/store/matching.d.ts +49 -0
- package/dist/types/store/paths.d.ts +39 -0
- package/dist/types/store/performCall.d.ts +15 -0
- package/dist/types/store/rejection.d.ts +58 -0
- package/dist/types/types.d.ts +246 -13
- package/dist/yoltra.cjs +3 -8
- package/dist/yoltra.cjs.map +1 -1
- package/dist/yoltra.mjs +1509 -1038
- package/dist/yoltra.mjs.map +1 -1
- package/dist/yoltra.umd.js +3 -8
- package/dist/yoltra.umd.js.map +1 -1
- package/package.json +12 -11
package/dist/yoltra.mjs
CHANGED
|
@@ -1,23 +1,13 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* @yoltra/core v0.
|
|
2
|
+
* @yoltra/core v0.7.0
|
|
3
3
|
* (c) 2026 Manu Ramirez <@pixerael>
|
|
4
|
-
* License: MIT
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
var C = (o, e, t) => e in o ? T(o, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : o[e] = t;
|
|
12
|
-
var p = (o, e, t) => C(o, typeof e != "symbol" ? e + "" : e, t);
|
|
13
|
-
class B {
|
|
14
|
-
constructor() {
|
|
15
|
-
/**
|
|
16
|
-
* Internal registry: `channel → type → Set<handler>`.
|
|
17
|
-
* @internal
|
|
18
|
-
*/
|
|
19
|
-
p(this, "handlers", /* @__PURE__ */ new Map());
|
|
20
|
-
}
|
|
4
|
+
* License: MIT */
|
|
5
|
+
class W {
|
|
6
|
+
/**
|
|
7
|
+
* Internal registry: `channel → type → Set<handler>`.
|
|
8
|
+
* @internal
|
|
9
|
+
*/
|
|
10
|
+
handlers = /* @__PURE__ */ new Map();
|
|
21
11
|
/**
|
|
22
12
|
* Subscribes a handler to an exact `(channel, type)`.
|
|
23
13
|
*
|
|
@@ -50,11 +40,11 @@ class B {
|
|
|
50
40
|
*
|
|
51
41
|
* @public
|
|
52
42
|
*/
|
|
53
|
-
on(e, t,
|
|
54
|
-
let
|
|
55
|
-
|
|
56
|
-
let
|
|
57
|
-
return
|
|
43
|
+
on(e, t, s) {
|
|
44
|
+
let n = this.handlers.get(e);
|
|
45
|
+
n || (n = /* @__PURE__ */ new Map(), this.handlers.set(e, n));
|
|
46
|
+
let r = n.get(t);
|
|
47
|
+
return r || (r = /* @__PURE__ */ new Set(), n.set(t, r)), r.add(s), () => this.off(e, t, s);
|
|
58
48
|
}
|
|
59
49
|
/**
|
|
60
50
|
* Removes a specific handler previously added with {@link EventBus.on | `on`}.
|
|
@@ -76,11 +66,11 @@ class B {
|
|
|
76
66
|
*
|
|
77
67
|
* @public
|
|
78
68
|
*/
|
|
79
|
-
off(e, t,
|
|
80
|
-
const
|
|
81
|
-
if (!
|
|
82
|
-
const
|
|
83
|
-
|
|
69
|
+
off(e, t, s) {
|
|
70
|
+
const n = this.handlers.get(e);
|
|
71
|
+
if (!n) return;
|
|
72
|
+
const r = n.get(t);
|
|
73
|
+
r && (r.delete(s), r.size === 0 && n.delete(t), n.size === 0 && this.handlers.delete(e));
|
|
84
74
|
}
|
|
85
75
|
/**
|
|
86
76
|
* Emits an event to all subscribers of the exact `(channel, type)`.
|
|
@@ -104,16 +94,16 @@ class B {
|
|
|
104
94
|
*
|
|
105
95
|
* @public
|
|
106
96
|
*/
|
|
107
|
-
emit(e, t,
|
|
108
|
-
const
|
|
109
|
-
if (!
|
|
110
|
-
const
|
|
111
|
-
if (!(!
|
|
112
|
-
for (const
|
|
97
|
+
emit(e, t, s, n) {
|
|
98
|
+
const r = this.handlers.get(e);
|
|
99
|
+
if (!r) return;
|
|
100
|
+
const c = r.get(t);
|
|
101
|
+
if (!(!c || c.size === 0))
|
|
102
|
+
for (const l of [...c])
|
|
113
103
|
try {
|
|
114
|
-
|
|
115
|
-
} catch (
|
|
116
|
-
console.error("EventBus handler error:",
|
|
104
|
+
l(s, n);
|
|
105
|
+
} catch (i) {
|
|
106
|
+
console.error("EventBus handler error:", i);
|
|
117
107
|
}
|
|
118
108
|
}
|
|
119
109
|
/**
|
|
@@ -133,37 +123,35 @@ class B {
|
|
|
133
123
|
this.handlers.clear();
|
|
134
124
|
}
|
|
135
125
|
}
|
|
136
|
-
class
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
p(this, "patternIndex", /* @__PURE__ */ new Map());
|
|
166
|
-
}
|
|
126
|
+
class U {
|
|
127
|
+
/**
|
|
128
|
+
* Exact handlers: `channel → type → [handlers]`.
|
|
129
|
+
* @internal
|
|
130
|
+
*/
|
|
131
|
+
handlers = /* @__PURE__ */ new Map();
|
|
132
|
+
/**
|
|
133
|
+
* Pattern handlers with `*` and `**`: `channel → pattern(string) → [handlers]`.
|
|
134
|
+
* @internal
|
|
135
|
+
*/
|
|
136
|
+
patternHandlers = /* @__PURE__ */ new Map();
|
|
137
|
+
/**
|
|
138
|
+
* Patterns bucketed by their first segment, so an emit tests only what could match.
|
|
139
|
+
*
|
|
140
|
+
* @remarks
|
|
141
|
+
* Delivery used to walk every pattern registered on the channel and run the full segment
|
|
142
|
+
* matcher against each. That is linear in the number of patterns rather than in the number
|
|
143
|
+
* that match, and it re-split both the pattern and the subject on every test — for a thousand
|
|
144
|
+
* patterns, two thousand string splits to deliver one event.
|
|
145
|
+
*
|
|
146
|
+
* A subject's first segment can only be matched by a pattern whose first segment is that same
|
|
147
|
+
* literal, or is `*` or `**`. Bucketing on that turns the common shape — distinct event
|
|
148
|
+
* families like `panel.*` and `order.**` — from a scan of everything into a map lookup plus
|
|
149
|
+
* the handful that begin with a wildcard.
|
|
150
|
+
*
|
|
151
|
+
* It buys nothing for a channel where every pattern starts with `**`, since all of those must
|
|
152
|
+
* still be tested. That is the honest worst case, and it is unchanged rather than worsened.
|
|
153
|
+
*/
|
|
154
|
+
patternIndex = /* @__PURE__ */ new Map();
|
|
167
155
|
/**
|
|
168
156
|
* Subscribes a handler to either an **exact** type or a **pattern**.
|
|
169
157
|
*
|
|
@@ -196,18 +184,18 @@ class H {
|
|
|
196
184
|
*
|
|
197
185
|
* @public
|
|
198
186
|
*/
|
|
199
|
-
on(e, t,
|
|
200
|
-
const
|
|
201
|
-
if (this.isPattern(
|
|
202
|
-
const
|
|
187
|
+
on(e, t, s) {
|
|
188
|
+
const n = String(t);
|
|
189
|
+
if (this.isPattern(n)) {
|
|
190
|
+
const r = n;
|
|
203
191
|
this.patternHandlers.has(e) || this.patternHandlers.set(e, /* @__PURE__ */ new Map());
|
|
204
|
-
const
|
|
205
|
-
return
|
|
192
|
+
const c = this.patternHandlers.get(e);
|
|
193
|
+
return c.has(r) || (c.set(r, []), this.indexPattern(e, r)), c.get(r).push(s), () => this.offPattern(e, r, s);
|
|
206
194
|
} else {
|
|
207
|
-
const
|
|
195
|
+
const r = this.normalizeTypeKey(n);
|
|
208
196
|
this.handlers.has(e) || this.handlers.set(e, /* @__PURE__ */ new Map());
|
|
209
|
-
const
|
|
210
|
-
return
|
|
197
|
+
const c = this.handlers.get(e);
|
|
198
|
+
return c.has(r) || c.set(r, []), c.get(r).push(s), () => this.offExactNormalized(e, r, s);
|
|
211
199
|
}
|
|
212
200
|
}
|
|
213
201
|
/**
|
|
@@ -228,9 +216,9 @@ class H {
|
|
|
228
216
|
*
|
|
229
217
|
* @public
|
|
230
218
|
*/
|
|
231
|
-
off(e, t,
|
|
232
|
-
const
|
|
233
|
-
this.offExactNormalized(e,
|
|
219
|
+
off(e, t, s) {
|
|
220
|
+
const n = this.normalizeTypeKey(String(t));
|
|
221
|
+
this.offExactNormalized(e, n, s);
|
|
234
222
|
}
|
|
235
223
|
/**
|
|
236
224
|
* Internal exact unsubscription using an already **normalized** type key.
|
|
@@ -240,13 +228,13 @@ class H {
|
|
|
240
228
|
* @param handler - Handler to remove.
|
|
241
229
|
* @internal
|
|
242
230
|
*/
|
|
243
|
-
offExactNormalized(e, t,
|
|
244
|
-
const
|
|
245
|
-
if (!
|
|
246
|
-
const
|
|
247
|
-
if (!
|
|
248
|
-
const
|
|
249
|
-
|
|
231
|
+
offExactNormalized(e, t, s) {
|
|
232
|
+
const n = this.handlers.get(e);
|
|
233
|
+
if (!n) return;
|
|
234
|
+
const r = n.get(t);
|
|
235
|
+
if (!r) return;
|
|
236
|
+
const c = r.indexOf(s);
|
|
237
|
+
c !== -1 && r.splice(c, 1), r.length === 0 && n.delete(t), n.size === 0 && this.handlers.delete(e);
|
|
250
238
|
}
|
|
251
239
|
/**
|
|
252
240
|
* Internal removal for a **pattern** subscription. No-ops if missing.
|
|
@@ -256,13 +244,13 @@ class H {
|
|
|
256
244
|
* @param handler - Handler to remove.
|
|
257
245
|
* @internal
|
|
258
246
|
*/
|
|
259
|
-
offPattern(e, t,
|
|
260
|
-
const
|
|
261
|
-
if (!
|
|
262
|
-
const
|
|
263
|
-
if (!
|
|
264
|
-
const
|
|
265
|
-
|
|
247
|
+
offPattern(e, t, s) {
|
|
248
|
+
const n = this.patternHandlers.get(e);
|
|
249
|
+
if (!n) return;
|
|
250
|
+
const r = n.get(t);
|
|
251
|
+
if (!r) return;
|
|
252
|
+
const c = r.indexOf(s);
|
|
253
|
+
c !== -1 && r.splice(c, 1), r.length === 0 && (n.delete(t), this.unindexPattern(e, t)), n.size === 0 && (this.patternHandlers.delete(e), this.patternIndex.delete(e));
|
|
266
254
|
}
|
|
267
255
|
/**
|
|
268
256
|
* Emits an event to all exact subscribers first, then to **matching pattern** subscribers.
|
|
@@ -284,21 +272,21 @@ class H {
|
|
|
284
272
|
*
|
|
285
273
|
* @public
|
|
286
274
|
*/
|
|
287
|
-
emit(e, t,
|
|
288
|
-
const
|
|
289
|
-
for (const
|
|
290
|
-
if (!
|
|
291
|
-
|
|
275
|
+
emit(e, t, s) {
|
|
276
|
+
const n = String(t), r = this.normalizeTypeKey(n), c = this.handlers.get(e)?.get(r) ?? [], l = this.matchingPatternHandlers(e, n), i = /* @__PURE__ */ new Set(), a = (u) => {
|
|
277
|
+
for (const d of [...u])
|
|
278
|
+
if (!i.has(d)) {
|
|
279
|
+
i.add(d);
|
|
292
280
|
try {
|
|
293
|
-
|
|
294
|
-
} catch (
|
|
295
|
-
console.error(
|
|
281
|
+
d(s);
|
|
282
|
+
} catch (h) {
|
|
283
|
+
console.error(h);
|
|
296
284
|
continue;
|
|
297
285
|
}
|
|
298
286
|
}
|
|
299
287
|
};
|
|
300
|
-
|
|
301
|
-
for (const
|
|
288
|
+
a(c);
|
|
289
|
+
for (const u of l) a(u);
|
|
302
290
|
}
|
|
303
291
|
/**
|
|
304
292
|
* Emits a payload that is only built if somebody is listening.
|
|
@@ -316,23 +304,23 @@ class H {
|
|
|
316
304
|
*
|
|
317
305
|
* @public
|
|
318
306
|
*/
|
|
319
|
-
emitWith(e, t,
|
|
320
|
-
const
|
|
321
|
-
if (
|
|
322
|
-
const
|
|
323
|
-
for (const
|
|
324
|
-
if (!
|
|
325
|
-
|
|
307
|
+
emitWith(e, t, s) {
|
|
308
|
+
const n = String(t), r = this.normalizeTypeKey(n), c = this.handlers.get(e)?.get(r) ?? [], l = this.matchingPatternHandlers(e, n);
|
|
309
|
+
if (c.length === 0 && l.length === 0) return;
|
|
310
|
+
const i = s(), a = /* @__PURE__ */ new Set(), u = (d) => {
|
|
311
|
+
for (const h of [...d])
|
|
312
|
+
if (!a.has(h)) {
|
|
313
|
+
a.add(h);
|
|
326
314
|
try {
|
|
327
|
-
|
|
328
|
-
} catch (
|
|
329
|
-
console.error(
|
|
315
|
+
h(i);
|
|
316
|
+
} catch (p) {
|
|
317
|
+
console.error(p);
|
|
330
318
|
continue;
|
|
331
319
|
}
|
|
332
320
|
}
|
|
333
321
|
};
|
|
334
|
-
c
|
|
335
|
-
for (const
|
|
322
|
+
u(c);
|
|
323
|
+
for (const d of l) u(d);
|
|
336
324
|
}
|
|
337
325
|
/**
|
|
338
326
|
* Determines if a string is a **pattern** (contains `*`).
|
|
@@ -371,27 +359,27 @@ class H {
|
|
|
371
359
|
* @internal
|
|
372
360
|
*/
|
|
373
361
|
indexPattern(e, t) {
|
|
374
|
-
let
|
|
375
|
-
|
|
376
|
-
const
|
|
377
|
-
if (
|
|
378
|
-
|
|
362
|
+
let s = this.patternIndex.get(e);
|
|
363
|
+
s === void 0 && (s = { byHead: /* @__PURE__ */ new Map(), anyHead: [] }, this.patternIndex.set(e, s));
|
|
364
|
+
const n = this.splitPath(t), r = { pattern: t, segments: n }, c = n[0];
|
|
365
|
+
if (c === void 0 || c === "*" || c === "**") {
|
|
366
|
+
s.anyHead.push(r);
|
|
379
367
|
return;
|
|
380
368
|
}
|
|
381
|
-
const
|
|
382
|
-
|
|
369
|
+
const l = s.byHead.get(c);
|
|
370
|
+
l === void 0 ? s.byHead.set(c, [r]) : l.push(r);
|
|
383
371
|
}
|
|
384
372
|
/**
|
|
385
373
|
* Removes a pattern from the index. Paired with {@link LooseEventBus.offPattern}.
|
|
386
374
|
* @internal
|
|
387
375
|
*/
|
|
388
376
|
unindexPattern(e, t) {
|
|
389
|
-
const
|
|
390
|
-
if (
|
|
391
|
-
const
|
|
392
|
-
if (
|
|
393
|
-
const
|
|
394
|
-
|
|
377
|
+
const s = this.patternIndex.get(e);
|
|
378
|
+
if (s === void 0) return;
|
|
379
|
+
const n = this.splitPath(t)[0], r = n === void 0 || n === "*" || n === "**" ? s.anyHead : s.byHead.get(n);
|
|
380
|
+
if (r === void 0) return;
|
|
381
|
+
const c = r.findIndex((l) => l.pattern === t);
|
|
382
|
+
c !== -1 && r.splice(c, 1), r.length === 0 && r !== s.anyHead && n !== void 0 && s.byHead.delete(n);
|
|
395
383
|
}
|
|
396
384
|
/**
|
|
397
385
|
* The handler lists of every pattern matching this subject.
|
|
@@ -405,20 +393,20 @@ class H {
|
|
|
405
393
|
* @internal
|
|
406
394
|
*/
|
|
407
395
|
matchingPatternHandlers(e, t) {
|
|
408
|
-
const
|
|
409
|
-
if (
|
|
410
|
-
const
|
|
411
|
-
for (const
|
|
412
|
-
if (!this.matchSegments(
|
|
413
|
-
const
|
|
414
|
-
|
|
396
|
+
const s = this.patternHandlers.get(e), n = this.patternIndex.get(e);
|
|
397
|
+
if (s === void 0 || s.size === 0 || n === void 0) return [];
|
|
398
|
+
const r = this.splitPath(t), c = [], l = (a) => {
|
|
399
|
+
for (const u of a) {
|
|
400
|
+
if (!this.matchSegments(u.segments, r)) continue;
|
|
401
|
+
const d = s.get(u.pattern);
|
|
402
|
+
d !== void 0 && c.push(d);
|
|
415
403
|
}
|
|
416
|
-
},
|
|
417
|
-
if (
|
|
418
|
-
const
|
|
419
|
-
|
|
404
|
+
}, i = r[0];
|
|
405
|
+
if (i !== void 0) {
|
|
406
|
+
const a = n.byHead.get(i);
|
|
407
|
+
a !== void 0 && l(a);
|
|
420
408
|
}
|
|
421
|
-
return
|
|
409
|
+
return l(n.anyHead), c;
|
|
422
410
|
}
|
|
423
411
|
/**
|
|
424
412
|
* Pattern matcher over dot-separated segments, which arrive already split.
|
|
@@ -449,18 +437,18 @@ class H {
|
|
|
449
437
|
* @internal
|
|
450
438
|
*/
|
|
451
439
|
matchSegments(e, t) {
|
|
452
|
-
let
|
|
453
|
-
for (;
|
|
454
|
-
if (
|
|
455
|
-
|
|
456
|
-
else if (
|
|
457
|
-
|
|
458
|
-
else if (
|
|
459
|
-
|
|
440
|
+
let s = 0, n = 0, r = -1, c = 0;
|
|
441
|
+
for (; n < t.length; )
|
|
442
|
+
if (s < e.length && (e[s] === "*" || e[s] === t[n]))
|
|
443
|
+
s++, n++;
|
|
444
|
+
else if (s < e.length && e[s] === "**")
|
|
445
|
+
r = s, c = n, s++;
|
|
446
|
+
else if (r !== -1)
|
|
447
|
+
s = r + 1, n = ++c;
|
|
460
448
|
else
|
|
461
449
|
return !1;
|
|
462
|
-
for (;
|
|
463
|
-
return
|
|
450
|
+
for (; s < e.length && e[s] === "**"; ) s++;
|
|
451
|
+
return s === e.length;
|
|
464
452
|
}
|
|
465
453
|
/**
|
|
466
454
|
* Removes **all** listeners (exact and pattern). Useful for tests/HMR teardown.
|
|
@@ -485,16 +473,21 @@ class H {
|
|
|
485
473
|
*/
|
|
486
474
|
__introspect() {
|
|
487
475
|
const e = [];
|
|
488
|
-
for (const [t,
|
|
489
|
-
for (const [
|
|
490
|
-
|
|
491
|
-
for (const [t,
|
|
492
|
-
for (const [
|
|
493
|
-
|
|
476
|
+
for (const [t, s] of this.handlers)
|
|
477
|
+
for (const [n, r] of s)
|
|
478
|
+
r.length > 0 && e.push({ channel: t, type: n, count: r.length });
|
|
479
|
+
for (const [t, s] of this.patternHandlers)
|
|
480
|
+
for (const [n, r] of s)
|
|
481
|
+
r.length > 0 && e.push({ channel: t, type: n, count: r.length });
|
|
494
482
|
return e;
|
|
495
483
|
}
|
|
496
484
|
}
|
|
497
|
-
class
|
|
485
|
+
class L {
|
|
486
|
+
/**
|
|
487
|
+
* The underlying pure reducer function.
|
|
488
|
+
* @internal
|
|
489
|
+
*/
|
|
490
|
+
_reduce;
|
|
498
491
|
/**
|
|
499
492
|
* Creates a new {@link Reducer} from a pure reducer function.
|
|
500
493
|
*
|
|
@@ -511,11 +504,6 @@ class K {
|
|
|
511
504
|
* @public
|
|
512
505
|
*/
|
|
513
506
|
constructor(e) {
|
|
514
|
-
/**
|
|
515
|
-
* The underlying pure reducer function.
|
|
516
|
-
* @internal
|
|
517
|
-
*/
|
|
518
|
-
p(this, "_reduce");
|
|
519
507
|
this._reduce = e;
|
|
520
508
|
}
|
|
521
509
|
/**
|
|
@@ -523,7 +511,7 @@ class K {
|
|
|
523
511
|
*
|
|
524
512
|
* @param state - Current state.
|
|
525
513
|
* @param event - An event drawn from {@link EventUnion | `EventUnion<EM>`}.
|
|
526
|
-
* @returns The next state
|
|
514
|
+
* @returns The next state, or a {@link Rejection} if the reducer refused the write.
|
|
527
515
|
*
|
|
528
516
|
* @example
|
|
529
517
|
* ```ts
|
|
@@ -536,115 +524,336 @@ class K {
|
|
|
536
524
|
return this._reduce(e, t);
|
|
537
525
|
}
|
|
538
526
|
}
|
|
539
|
-
const
|
|
540
|
-
function
|
|
527
|
+
const T = /* @__PURE__ */ new Set();
|
|
528
|
+
function O(o, e) {
|
|
541
529
|
const t = o ? `${o}.${e}` : e;
|
|
542
|
-
|
|
530
|
+
T.has(t) || (T.add(t), console.warn(
|
|
543
531
|
`[yoltra] State key "${e}"${o ? ` under "${o}"` : ""} contains a dot. Paths are dotted, so this key is indistinguishable from nested objects of the same name: a subscription to "${t}" may match the wrong value, and DevTools patches for it will address the wrong node. Rename the key, or nest it.`
|
|
544
532
|
));
|
|
545
533
|
}
|
|
546
|
-
function
|
|
547
|
-
const
|
|
548
|
-
return
|
|
534
|
+
function I(o, e, t = "", s = /* @__PURE__ */ new Map()) {
|
|
535
|
+
const n = [];
|
|
536
|
+
return P(o, e, t, s, n), n;
|
|
549
537
|
}
|
|
550
|
-
function
|
|
538
|
+
function P(o, e, t, s, n) {
|
|
551
539
|
if (o === e) return;
|
|
552
540
|
if (typeof o != "object" || typeof e != "object" || o === null || e === null) {
|
|
553
541
|
if (typeof o == "number" && Number.isNaN(o) && Number.isNaN(e))
|
|
554
542
|
return;
|
|
555
|
-
|
|
543
|
+
n.push(t);
|
|
556
544
|
return;
|
|
557
545
|
}
|
|
558
546
|
if (o instanceof Date && e instanceof Date) {
|
|
559
|
-
o.getTime() !== e.getTime() &&
|
|
547
|
+
o.getTime() !== e.getTime() && n.push(t);
|
|
560
548
|
return;
|
|
561
549
|
}
|
|
562
550
|
if (o instanceof RegExp && e instanceof RegExp) {
|
|
563
|
-
(o.source !== e.source || e.flags !== o.flags) &&
|
|
551
|
+
(o.source !== e.source || e.flags !== o.flags) && n.push(t);
|
|
564
552
|
return;
|
|
565
553
|
}
|
|
566
554
|
if (o instanceof Map || e instanceof Map) {
|
|
567
|
-
|
|
555
|
+
n.push(t);
|
|
568
556
|
return;
|
|
569
557
|
}
|
|
570
558
|
if (o instanceof Set || e instanceof Set) {
|
|
571
|
-
|
|
559
|
+
n.push(t);
|
|
572
560
|
return;
|
|
573
561
|
}
|
|
574
|
-
const
|
|
575
|
-
if (
|
|
576
|
-
const
|
|
577
|
-
|
|
562
|
+
const r = o, c = e, l = s.get(r);
|
|
563
|
+
if (l?.has(c)) return;
|
|
564
|
+
const i = l ?? /* @__PURE__ */ new Set();
|
|
565
|
+
i.add(c), l || s.set(r, i);
|
|
578
566
|
try {
|
|
579
|
-
const
|
|
580
|
-
if (
|
|
581
|
-
|
|
567
|
+
const a = Array.isArray(o), u = Array.isArray(e);
|
|
568
|
+
if (a !== u) {
|
|
569
|
+
n.push(t);
|
|
582
570
|
return;
|
|
583
571
|
}
|
|
584
|
-
if (
|
|
585
|
-
const
|
|
586
|
-
|
|
587
|
-
const
|
|
588
|
-
for (let
|
|
589
|
-
|
|
590
|
-
for (let
|
|
591
|
-
|
|
572
|
+
if (a) {
|
|
573
|
+
const f = o, m = e;
|
|
574
|
+
f.length !== m.length && t && n.push(t);
|
|
575
|
+
const y = Math.min(f.length, m.length);
|
|
576
|
+
for (let g = 0; g < y; g++)
|
|
577
|
+
f[g] !== m[g] && P(f[g], m[g], t ? `${t}.${g}` : `${g}`, s, n);
|
|
578
|
+
for (let g = y; g < Math.max(f.length, m.length); g++)
|
|
579
|
+
n.push(t ? `${t}.${g}` : `${g}`);
|
|
592
580
|
return;
|
|
593
581
|
}
|
|
594
|
-
const
|
|
595
|
-
if (
|
|
596
|
-
|
|
582
|
+
const d = Object.keys(o), h = Object.keys(e);
|
|
583
|
+
if (d.length === 0 && h.length === 0) {
|
|
584
|
+
n.push(t);
|
|
597
585
|
return;
|
|
598
586
|
}
|
|
599
|
-
let
|
|
600
|
-
if (
|
|
601
|
-
for (let
|
|
602
|
-
if (!Object.prototype.hasOwnProperty.call(o,
|
|
603
|
-
|
|
587
|
+
let p = d.length === h.length;
|
|
588
|
+
if (p) {
|
|
589
|
+
for (let f = 0; f < h.length; f++)
|
|
590
|
+
if (!Object.prototype.hasOwnProperty.call(o, h[f])) {
|
|
591
|
+
p = !1;
|
|
604
592
|
break;
|
|
605
593
|
}
|
|
606
594
|
}
|
|
607
|
-
if (
|
|
608
|
-
for (const
|
|
609
|
-
o[
|
|
595
|
+
if (p) {
|
|
596
|
+
for (const f of h)
|
|
597
|
+
o[f] !== e[f] && (process.env.NODE_ENV !== "production" && f.includes(".") && O(t, f), P(o[f], e[f], t ? `${t}.${f}` : f, s, n));
|
|
610
598
|
return;
|
|
611
599
|
}
|
|
612
|
-
for (const
|
|
613
|
-
const m = Object.prototype.hasOwnProperty.call(o,
|
|
614
|
-
if (m && o[
|
|
615
|
-
process.env.NODE_ENV !== "production" &&
|
|
616
|
-
const
|
|
600
|
+
for (const f of h) {
|
|
601
|
+
const m = Object.prototype.hasOwnProperty.call(o, f);
|
|
602
|
+
if (m && o[f] === e[f]) continue;
|
|
603
|
+
process.env.NODE_ENV !== "production" && f.includes(".") && O(t, f);
|
|
604
|
+
const y = t ? `${t}.${f}` : f;
|
|
617
605
|
if (!m) {
|
|
618
|
-
|
|
606
|
+
n.push(y);
|
|
619
607
|
continue;
|
|
620
608
|
}
|
|
621
|
-
|
|
609
|
+
P(o[f], e[f], y, s, n);
|
|
622
610
|
}
|
|
623
|
-
for (const
|
|
624
|
-
Object.prototype.hasOwnProperty.call(e,
|
|
611
|
+
for (const f of d)
|
|
612
|
+
Object.prototype.hasOwnProperty.call(e, f) || (process.env.NODE_ENV !== "production" && f.includes(".") && O(t, f), n.push(t ? `${t}.${f}` : f));
|
|
625
613
|
} finally {
|
|
626
|
-
|
|
614
|
+
i.delete(c), i.size === 0 && s.delete(r);
|
|
627
615
|
}
|
|
628
616
|
}
|
|
629
|
-
function
|
|
617
|
+
function M(o, e = /* @__PURE__ */ new WeakSet(), t) {
|
|
630
618
|
if (o === null || typeof o != "object" || e.has(o) || (t !== void 0 && o === t.watch && t.onFound(), Object.isFrozen(o))) return o;
|
|
631
619
|
if (e.add(o), Array.isArray(o)) {
|
|
632
|
-
const
|
|
633
|
-
for (let
|
|
634
|
-
n
|
|
635
|
-
return Object.freeze(
|
|
620
|
+
const s = o;
|
|
621
|
+
for (let n = 0; n < s.length; n++)
|
|
622
|
+
s[n] = M(s[n], e, t);
|
|
623
|
+
return Object.freeze(s);
|
|
636
624
|
}
|
|
637
|
-
for (const
|
|
638
|
-
const
|
|
639
|
-
!
|
|
625
|
+
for (const s of Object.getOwnPropertyNames(o)) {
|
|
626
|
+
const n = Object.getOwnPropertyDescriptor(o, s);
|
|
627
|
+
!n || !("value" in n) || (o[s] = M(o[s], e, t));
|
|
640
628
|
}
|
|
641
|
-
for (const
|
|
642
|
-
const
|
|
643
|
-
!
|
|
629
|
+
for (const s of Object.getOwnPropertySymbols(o)) {
|
|
630
|
+
const n = Object.getOwnPropertyDescriptor(o, s);
|
|
631
|
+
!n || !("value" in n) || (o[s] = M(o[s], e, t));
|
|
644
632
|
}
|
|
645
633
|
return Object.freeze(o);
|
|
646
634
|
}
|
|
647
|
-
|
|
635
|
+
const B = /* @__PURE__ */ Symbol.for("yoltra.rejected");
|
|
636
|
+
function fe(o) {
|
|
637
|
+
return { [B]: !0, reason: o };
|
|
638
|
+
}
|
|
639
|
+
function V(o) {
|
|
640
|
+
return typeof o == "object" && o !== null && o[B] === !0;
|
|
641
|
+
}
|
|
642
|
+
class Q extends Error {
|
|
643
|
+
channel;
|
|
644
|
+
type;
|
|
645
|
+
idleMs;
|
|
646
|
+
constructor(e, t, s) {
|
|
647
|
+
super(
|
|
648
|
+
`[yoltra] call to "${e}/${t}" saw no correlated reply for ${s}ms. The timeout is idle rather than total, so this means the responder went quiet, not that it was slow. Check that something handles "${e}/${t}" and that its reply is emitted through the \`emit\` it was handed — a reply emitted from an unrelated context carries no causal link, and needs an explicit correlationId instead.`
|
|
649
|
+
), this.name = "CallTimeoutError", this.channel = e, this.type = t, this.idleMs = s;
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
class C extends Error {
|
|
653
|
+
constructor(e) {
|
|
654
|
+
super(`[yoltra] call aborted: ${e}`), this.name = "CallAbortedError";
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
function G(o) {
|
|
658
|
+
const [e, t] = o;
|
|
659
|
+
if (t === void 0) return { channel: e, isTerminal: () => !0 };
|
|
660
|
+
if (typeof t == "string") return { channel: e, isTerminal: (n) => n === t };
|
|
661
|
+
const s = new Set(t);
|
|
662
|
+
return { channel: e, isTerminal: (n) => s.has(n) };
|
|
663
|
+
}
|
|
664
|
+
function J(o, e, t) {
|
|
665
|
+
return o.parentId === e ? !0 : t === void 0 ? !1 : o.meta?.correlationId === t;
|
|
666
|
+
}
|
|
667
|
+
class q {
|
|
668
|
+
constructor(e) {
|
|
669
|
+
this.highWaterMark = e;
|
|
670
|
+
}
|
|
671
|
+
highWaterMark;
|
|
672
|
+
buffer = [];
|
|
673
|
+
/** Consumers parked in `take`, oldest first. */
|
|
674
|
+
takers = [];
|
|
675
|
+
/** Producers parked in `put`, each with the item they are waiting to hand over. */
|
|
676
|
+
putters = [];
|
|
677
|
+
consuming = !1;
|
|
678
|
+
/** No more items will be accepted, but what is already here is still owed to the consumer. */
|
|
679
|
+
ended = !1;
|
|
680
|
+
/** Abandoned: nothing further is owed to anybody. */
|
|
681
|
+
closed = !1;
|
|
682
|
+
/** Items discarded because nobody was iterating and the buffer was full. */
|
|
683
|
+
dropped = 0;
|
|
684
|
+
/** How many items were discarded for want of a consumer. */
|
|
685
|
+
get droppedCount() {
|
|
686
|
+
return this.dropped;
|
|
687
|
+
}
|
|
688
|
+
/**
|
|
689
|
+
* Marks that a consumer has started pulling. From here on, a full buffer parks the producer
|
|
690
|
+
* rather than dropping.
|
|
691
|
+
*/
|
|
692
|
+
beginConsuming() {
|
|
693
|
+
this.consuming = !0;
|
|
694
|
+
}
|
|
695
|
+
/**
|
|
696
|
+
* Offers an item. The returned promise settles when the item has been taken — or immediately,
|
|
697
|
+
* if it fit in the buffer or was dropped.
|
|
698
|
+
*/
|
|
699
|
+
put(e) {
|
|
700
|
+
if (this.closed || this.ended) return Promise.resolve();
|
|
701
|
+
const t = this.takers.shift();
|
|
702
|
+
return t !== void 0 ? (t({ value: e, done: !1 }), Promise.resolve()) : this.buffer.length < this.highWaterMark ? (this.buffer.push(e), Promise.resolve()) : this.consuming ? new Promise((s) => {
|
|
703
|
+
this.putters.push({ item: e, release: s });
|
|
704
|
+
}) : (this.dropped++, Promise.resolve());
|
|
705
|
+
}
|
|
706
|
+
/** Takes the next item, waiting if none is available. Resolves `done` once closed and drained. */
|
|
707
|
+
take() {
|
|
708
|
+
this.consuming = !0;
|
|
709
|
+
const e = this.buffer.shift();
|
|
710
|
+
if (e !== void 0) {
|
|
711
|
+
const s = this.putters.shift();
|
|
712
|
+
return s !== void 0 && (this.buffer.push(s.item), s.release()), Promise.resolve({ value: e, done: !1 });
|
|
713
|
+
}
|
|
714
|
+
const t = this.putters.shift();
|
|
715
|
+
return t !== void 0 ? (t.release(), Promise.resolve({ value: t.item, done: !1 })) : this.closed || this.ended ? Promise.resolve({ value: void 0, done: !0 }) : new Promise((s) => {
|
|
716
|
+
this.takers.push(s);
|
|
717
|
+
});
|
|
718
|
+
}
|
|
719
|
+
/**
|
|
720
|
+
* Stops accepting items, but keeps owing the consumer everything already queued.
|
|
721
|
+
*
|
|
722
|
+
* @remarks
|
|
723
|
+
* What the terminal reply does. Closing outright at that moment would throw away progress the
|
|
724
|
+
* responder had already handed over and the consumer had not yet read — which is exactly what
|
|
725
|
+
* happened before this existed: a six-step job delivered five steps, because the sixth was in
|
|
726
|
+
* the buffer when `done` arrived and the buffer was cleared. The terminal event says "no more
|
|
727
|
+
* is coming", not "forget what you were given".
|
|
728
|
+
*/
|
|
729
|
+
end() {
|
|
730
|
+
if (this.ended || this.closed) return;
|
|
731
|
+
this.ended = !0;
|
|
732
|
+
let e = this.putters.shift();
|
|
733
|
+
for (; e !== void 0; )
|
|
734
|
+
this.buffer.push(e.item), e.release(), e = this.putters.shift();
|
|
735
|
+
let t = this.takers.shift();
|
|
736
|
+
for (; t !== void 0; ) {
|
|
737
|
+
const s = this.buffer.shift();
|
|
738
|
+
t(
|
|
739
|
+
s !== void 0 ? { value: s, done: !1 } : { value: void 0, done: !0 }
|
|
740
|
+
), t = this.takers.shift();
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
/**
|
|
744
|
+
* Closes the queue: waiting consumers are told `done`, and **every parked producer is
|
|
745
|
+
* released**.
|
|
746
|
+
*
|
|
747
|
+
* @remarks
|
|
748
|
+
* Releasing producers is not tidying up. A producer parked on `put` is a pending `await emit`
|
|
749
|
+
* somewhere; leaving it parked when the call has already settled would hang the responder for
|
|
750
|
+
* good — turning a timed-out call into a wedged process, which is worse than the problem
|
|
751
|
+
* backpressure was added to solve.
|
|
752
|
+
*/
|
|
753
|
+
close() {
|
|
754
|
+
if (this.closed) return;
|
|
755
|
+
this.closed = !0, this.buffer.length = 0;
|
|
756
|
+
let e = this.takers.shift();
|
|
757
|
+
for (; e !== void 0; )
|
|
758
|
+
e({ value: void 0, done: !0 }), e = this.takers.shift();
|
|
759
|
+
let t = this.putters.shift();
|
|
760
|
+
for (; t !== void 0; )
|
|
761
|
+
t.release(), t = this.putters.shift();
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
const Y = 3e4, X = 16;
|
|
765
|
+
function Z(o, e, t, s, n) {
|
|
766
|
+
const { channel: r, isTerminal: c } = G(n.reply), l = n.timeoutMs ?? Y, i = new q(n.highWaterMark ?? X), a = o.idFactory();
|
|
767
|
+
let u, d, h = !1;
|
|
768
|
+
const p = new Promise((E, v) => {
|
|
769
|
+
u = E, d = v;
|
|
770
|
+
});
|
|
771
|
+
p.catch(() => {
|
|
772
|
+
});
|
|
773
|
+
let f = null, m = null;
|
|
774
|
+
const y = (E, v = !1) => {
|
|
775
|
+
h || (h = !0, f !== null && clearTimeout(f), f = null, m?.(), m = null, v ? i.end() : i.close(), n.signal?.removeEventListener("abort", g), E());
|
|
776
|
+
};
|
|
777
|
+
function g() {
|
|
778
|
+
y(() => d(new C(String(n.signal?.reason ?? "signal aborted"))));
|
|
779
|
+
}
|
|
780
|
+
const $ = () => {
|
|
781
|
+
f !== null && clearTimeout(f), f = setTimeout(() => {
|
|
782
|
+
y(() => d(new Q(e, t, l)));
|
|
783
|
+
}, l), f.unref?.();
|
|
784
|
+
};
|
|
785
|
+
return m = o.registerEffect({
|
|
786
|
+
// A pattern effect on the reply channel: which types are terminal is known, which are
|
|
787
|
+
// progress is not, so the filter cannot be a key list.
|
|
788
|
+
when: { channel: r },
|
|
789
|
+
effect: async (E) => {
|
|
790
|
+
if (!h && J(E, a, n.correlationId)) {
|
|
791
|
+
if ($(), c(String(E.type))) {
|
|
792
|
+
y(() => u(E), !0);
|
|
793
|
+
return;
|
|
794
|
+
}
|
|
795
|
+
await i.put(E);
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
}), n.signal !== void 0 && (n.signal.aborted ? g() : n.signal.addEventListener("abort", g, { once: !0 })), $(), o.emit(e, t, s, {
|
|
799
|
+
id: a,
|
|
800
|
+
...n.correlationId !== void 0 ? { meta: { correlationId: n.correlationId } } : {}
|
|
801
|
+
}), {
|
|
802
|
+
then: (E, v) => p.then(E, v),
|
|
803
|
+
catch: (E) => p.catch(E),
|
|
804
|
+
finally: (E) => p.finally(E),
|
|
805
|
+
get dropped() {
|
|
806
|
+
return i.droppedCount;
|
|
807
|
+
},
|
|
808
|
+
cancel: (E = "cancelled") => {
|
|
809
|
+
y(() => d(new C(E)));
|
|
810
|
+
},
|
|
811
|
+
[Symbol.asyncIterator]: () => (i.beginConsuming(), {
|
|
812
|
+
next: () => i.take(),
|
|
813
|
+
// Called by `for await` on `break`, `return` or a throw. Without it, abandoning the
|
|
814
|
+
// loop would leave the effect registered and the producer parked for good.
|
|
815
|
+
return: async () => (i.close(), { value: void 0, done: !0 })
|
|
816
|
+
})
|
|
817
|
+
};
|
|
818
|
+
}
|
|
819
|
+
function ee(o, e) {
|
|
820
|
+
if (!e) return o;
|
|
821
|
+
const s = (e[0] === "." ? e.slice(1) : e).split(".");
|
|
822
|
+
let n = o;
|
|
823
|
+
for (const r of s) {
|
|
824
|
+
if (n == null) return;
|
|
825
|
+
n = n[r];
|
|
826
|
+
}
|
|
827
|
+
return n;
|
|
828
|
+
}
|
|
829
|
+
function te(o) {
|
|
830
|
+
if (!o) return [];
|
|
831
|
+
const t = (o[0] === "." ? o.slice(1) : o).split("."), s = [];
|
|
832
|
+
for (let n = 0; n < t.length; n++)
|
|
833
|
+
s.push(t.slice(0, n + 1).join("."));
|
|
834
|
+
return s;
|
|
835
|
+
}
|
|
836
|
+
function k(o, e) {
|
|
837
|
+
return !o || "any" in o && o.any === !0 ? !0 : "keys" in o ? o.keys.some(
|
|
838
|
+
([t, s]) => e.channel === t && e.type === s
|
|
839
|
+
) : "channel" in o ? e.channel === o.channel : "channels" in o ? o.channels.includes(e.channel) : !1;
|
|
840
|
+
}
|
|
841
|
+
function ne(o) {
|
|
842
|
+
return typeof o == "function" ? o : o.middleware;
|
|
843
|
+
}
|
|
844
|
+
function se(o) {
|
|
845
|
+
if (typeof o != "function")
|
|
846
|
+
return o.when;
|
|
847
|
+
}
|
|
848
|
+
function D(o) {
|
|
849
|
+
if (o.when) {
|
|
850
|
+
const e = o.when;
|
|
851
|
+
if ("keys" in e)
|
|
852
|
+
return e.keys;
|
|
853
|
+
}
|
|
854
|
+
return [];
|
|
855
|
+
}
|
|
856
|
+
function re(o, e) {
|
|
648
857
|
try {
|
|
649
858
|
return structuredClone(e);
|
|
650
859
|
} catch (t) {
|
|
@@ -653,11 +862,274 @@ function W(o, e) {
|
|
|
653
862
|
);
|
|
654
863
|
}
|
|
655
864
|
}
|
|
656
|
-
function
|
|
657
|
-
return process.env.NODE_ENV === "production" ? o :
|
|
865
|
+
function R(o, e) {
|
|
866
|
+
return process.env.NODE_ENV === "production" ? o : M(o, /* @__PURE__ */ new WeakSet(), e);
|
|
658
867
|
}
|
|
659
|
-
const
|
|
660
|
-
class
|
|
868
|
+
const A = 100, ie = 64, z = 16, S = Object.freeze({ committed: !1, written: !1 }), oe = Object.freeze({ committed: !0, written: !1 }), ce = Object.freeze({ committed: !0, written: !0 }), _ = () => typeof performance < "u" && typeof performance.now == "function" ? performance.now() : Date.now();
|
|
869
|
+
class x {
|
|
870
|
+
/**
|
|
871
|
+
* Store name (used by DevTools & diagnostics).
|
|
872
|
+
*
|
|
873
|
+
* @public
|
|
874
|
+
*/
|
|
875
|
+
name;
|
|
876
|
+
/**
|
|
877
|
+
* Registered middleware pipeline (run **before** reducers).
|
|
878
|
+
* Stores either raw functions (legacy) or MiddlewareSpec objects.
|
|
879
|
+
* Return `false` from the middleware function to stop propagation.
|
|
880
|
+
*
|
|
881
|
+
* @internal
|
|
882
|
+
*/
|
|
883
|
+
middleware;
|
|
884
|
+
/**
|
|
885
|
+
* Installed slice reducers keyed by slice name.
|
|
886
|
+
*
|
|
887
|
+
* @internal
|
|
888
|
+
*/
|
|
889
|
+
reducers;
|
|
890
|
+
/**
|
|
891
|
+
* Current immutable snapshot of the store state.
|
|
892
|
+
* This reference changes whenever any slice changes (shallow immutability).
|
|
893
|
+
*
|
|
894
|
+
* @internal
|
|
895
|
+
*/
|
|
896
|
+
state;
|
|
897
|
+
/**
|
|
898
|
+
* Bus for reducer wiring (emit by `(channel, type)`).
|
|
899
|
+
*
|
|
900
|
+
* @internal
|
|
901
|
+
*/
|
|
902
|
+
reducerBus;
|
|
903
|
+
/**
|
|
904
|
+
* Bus for **granular** connector events (emit by **dotted path** inside a slice).
|
|
905
|
+
*
|
|
906
|
+
* @internal
|
|
907
|
+
*/
|
|
908
|
+
connectorBus;
|
|
909
|
+
/**
|
|
910
|
+
* Coarse-grained listeners (called once per committed event, only if state changed).
|
|
911
|
+
*
|
|
912
|
+
* @internal
|
|
913
|
+
*/
|
|
914
|
+
listeners = /* @__PURE__ */ new Set();
|
|
915
|
+
/**
|
|
916
|
+
* Registered effect handlers keyed by `"channel::type"` for O(1) lookup.
|
|
917
|
+
* Used for effects with explicit `keys` targeting.
|
|
918
|
+
*
|
|
919
|
+
* @internal
|
|
920
|
+
*/
|
|
921
|
+
effects = /* @__PURE__ */ new Map();
|
|
922
|
+
/**
|
|
923
|
+
* Pattern-based effects that need runtime matching.
|
|
924
|
+
* Used for effects with `when: { any }`, `{ channel }`, or `{ channels }`.
|
|
925
|
+
* Stores tuples of [effect function, when matcher].
|
|
926
|
+
*
|
|
927
|
+
* @internal
|
|
928
|
+
*/
|
|
929
|
+
patternEffects = /* @__PURE__ */ new Set();
|
|
930
|
+
/**
|
|
931
|
+
* Committed event subscribers keyed by `"channel::type"` for O(1) lookup.
|
|
932
|
+
* Notified after reducers, before effects, for events that passed middleware.
|
|
933
|
+
*
|
|
934
|
+
* @internal
|
|
935
|
+
*/
|
|
936
|
+
committedEventSubscribers = /* @__PURE__ */ new Map();
|
|
937
|
+
/**
|
|
938
|
+
* Uncommitted event subscribers keyed by `"channel::type"` for O(1) lookup.
|
|
939
|
+
* Notified when middleware rejects an event.
|
|
940
|
+
*
|
|
941
|
+
* @internal
|
|
942
|
+
*/
|
|
943
|
+
uncommittedEventSubscribers = /* @__PURE__ */ new Map();
|
|
944
|
+
/**
|
|
945
|
+
* All-events subscribers keyed by `"channel::type"` for O(1) lookup.
|
|
946
|
+
* Notified for both committed and uncommitted events with phase parameter.
|
|
947
|
+
*
|
|
948
|
+
* @internal
|
|
949
|
+
*/
|
|
950
|
+
/**
|
|
951
|
+
* Subscribers to events that actually changed state, notified after the commit.
|
|
952
|
+
*
|
|
953
|
+
* @remarks
|
|
954
|
+
* Separate from `committedEventSubscribers` rather than a filter over it, because the two
|
|
955
|
+
* answer different questions and one of them is load bearing: `committed` means "not vetoed"
|
|
956
|
+
* and fires for every event a store accepts, including every event in a store with no
|
|
957
|
+
* reducers. Narrowing it would have silently stopped toasts and analytics firing.
|
|
958
|
+
*
|
|
959
|
+
* @internal
|
|
960
|
+
*/
|
|
961
|
+
writtenEventSubscribers = /* @__PURE__ */ new Map();
|
|
962
|
+
allEventSubscribers = /* @__PURE__ */ new Map();
|
|
963
|
+
/**
|
|
964
|
+
* Track reducerBus unsubs per slice for HMR/register/unregister.
|
|
965
|
+
*
|
|
966
|
+
* @internal
|
|
967
|
+
*/
|
|
968
|
+
sliceUnsubs = /* @__PURE__ */ new Map();
|
|
969
|
+
/**
|
|
970
|
+
* Pattern-based reducers that need runtime matching.
|
|
971
|
+
* Used for reducers with `when: { any }`, `{ channel }`, or `{ channels }`.
|
|
972
|
+
* Maps slice name to the `when` matcher.
|
|
973
|
+
*
|
|
974
|
+
* @internal
|
|
975
|
+
*/
|
|
976
|
+
patternReducers = /* @__PURE__ */ new Map();
|
|
977
|
+
/**
|
|
978
|
+
* Whether `__replayEvents()` is allowed.
|
|
979
|
+
* Set from `spec.devtools.allowReplay`.
|
|
980
|
+
*
|
|
981
|
+
* @internal
|
|
982
|
+
*/
|
|
983
|
+
replayEnabled;
|
|
984
|
+
/**
|
|
985
|
+
* Produces the `id` for each emitted event. Defaults to `crypto.randomUUID()`; overridable
|
|
986
|
+
* via {@link StoreSpec.idFactory} for runtimes lacking it or for deterministic tests.
|
|
987
|
+
*
|
|
988
|
+
* @internal
|
|
989
|
+
*/
|
|
990
|
+
idFactory;
|
|
991
|
+
/**
|
|
992
|
+
* Optional hook invoked when an effect throws/rejects. See
|
|
993
|
+
* {@link StoreSpec.onEffectError}. `await emit()` never rejects on effect
|
|
994
|
+
* failure — this is how callers observe effect errors.
|
|
995
|
+
*/
|
|
996
|
+
onEffectError;
|
|
997
|
+
/**
|
|
998
|
+
* Optional hook invoked when a reducer throws. See {@link StoreSpec.onReducerError}. The
|
|
999
|
+
* failing slice is isolated rather than the event being rolled back, so this is the only
|
|
1000
|
+
* signal that a reducer misbehaved.
|
|
1001
|
+
*/
|
|
1002
|
+
onReducerError;
|
|
1003
|
+
/**
|
|
1004
|
+
* `slice:channel:type` combinations already warned about for payload aliasing.
|
|
1005
|
+
*
|
|
1006
|
+
* @remarks
|
|
1007
|
+
* Development-only diagnostics have to stay quiet enough to be read. One warning names the
|
|
1008
|
+
* pattern; repeating it once per event would bury it.
|
|
1009
|
+
*/
|
|
1010
|
+
warnedPayloadAliases = /* @__PURE__ */ new Set();
|
|
1011
|
+
/**
|
|
1012
|
+
* Pending events awaiting the **synchronous** reduce phase (middleware +
|
|
1013
|
+
* reducers + subscribers + coarse listeners). Drained by {@link drainReduce}.
|
|
1014
|
+
*
|
|
1015
|
+
* @internal
|
|
1016
|
+
*/
|
|
1017
|
+
reduceQueue = [];
|
|
1018
|
+
/**
|
|
1019
|
+
* Re-entrancy guard for the synchronous reduce phase.
|
|
1020
|
+
*
|
|
1021
|
+
* @internal
|
|
1022
|
+
*/
|
|
1023
|
+
isReducing = !1;
|
|
1024
|
+
/**
|
|
1025
|
+
* The event currently being reduced, or `null` outside the drain.
|
|
1026
|
+
*
|
|
1027
|
+
* @remarks
|
|
1028
|
+
* This is what makes causality exact rather than best-effort. The drain is synchronous — no
|
|
1029
|
+
* `await` can interleave — so any `emit` that arrives while it is set is, without ambiguity, a
|
|
1030
|
+
* consequence of this event. That catches the case a scoped `emit` closure cannot: a
|
|
1031
|
+
* middleware or subscriber that captured the store and calls `store.emit` directly instead of
|
|
1032
|
+
* using the injected one. Attribution should not depend on which reference a consumer reached
|
|
1033
|
+
* for.
|
|
1034
|
+
*
|
|
1035
|
+
* @internal
|
|
1036
|
+
*/
|
|
1037
|
+
currentEvent = null;
|
|
1038
|
+
/**
|
|
1039
|
+
* Events processed by the drain currently in progress. Compared against
|
|
1040
|
+
* `maxTransitionsPerDrain`, which is off unless configured.
|
|
1041
|
+
*
|
|
1042
|
+
* @internal
|
|
1043
|
+
*/
|
|
1044
|
+
transitionsThisDrain = 0;
|
|
1045
|
+
/**
|
|
1046
|
+
* Ceilings that stop a cascade from becoming a hung process. See {@link StoreSpec.maxReduceDepth}.
|
|
1047
|
+
*
|
|
1048
|
+
* @internal
|
|
1049
|
+
*/
|
|
1050
|
+
maxReduceDepth;
|
|
1051
|
+
maxTransitionsPerDrain;
|
|
1052
|
+
onCascade;
|
|
1053
|
+
onRejected;
|
|
1054
|
+
/**
|
|
1055
|
+
* Registered instrumentation observers (DevTools seam). See {@link instrument}.
|
|
1056
|
+
*
|
|
1057
|
+
* @internal
|
|
1058
|
+
*/
|
|
1059
|
+
instrumentObservers = /* @__PURE__ */ new Set();
|
|
1060
|
+
/**
|
|
1061
|
+
* Scratch array collecting slice-prefixed changed leaf paths during an
|
|
1062
|
+
* instrumented reduce. Set by {@link drainReduce} while observers are active;
|
|
1063
|
+
* appended to by {@link commitStaged}. `null` when not instrumenting.
|
|
1064
|
+
*
|
|
1065
|
+
* @internal
|
|
1066
|
+
*/
|
|
1067
|
+
changedPathSink = null;
|
|
1068
|
+
/**
|
|
1069
|
+
* Where keyed reducers put their pending writes during a reduce, and the refusal one of them
|
|
1070
|
+
* returned.
|
|
1071
|
+
*
|
|
1072
|
+
* @remarks
|
|
1073
|
+
* Keyed reducers are invoked through `reducerBus`, which delivers to handlers and has no way
|
|
1074
|
+
* to hand a value back — the same reason `changedPathSink` exists. `null` outside a reduce.
|
|
1075
|
+
*
|
|
1076
|
+
* @internal
|
|
1077
|
+
*/
|
|
1078
|
+
stagingSink = null;
|
|
1079
|
+
stagedRejection = null;
|
|
1080
|
+
stagedRejectedBy = "";
|
|
1081
|
+
/**
|
|
1082
|
+
* Count of effect tasks currently in flight; surfaced as queue depth by
|
|
1083
|
+
* {@link __devtoolsIntrospect}.
|
|
1084
|
+
*
|
|
1085
|
+
* @internal
|
|
1086
|
+
*/
|
|
1087
|
+
inFlightEffects = 0;
|
|
1088
|
+
/**
|
|
1089
|
+
* Tracks processed events by fingerprint with timestamps for TTL-based deduplication.
|
|
1090
|
+
*
|
|
1091
|
+
* **Deduplication Behavior:**
|
|
1092
|
+
* - Events are fingerprinted using `channel::type::JSON(payload)`
|
|
1093
|
+
* - If an identical fingerprint is seen within the dedup window, it's skipped
|
|
1094
|
+
* - The window is 50ms in development, 100ms in production
|
|
1095
|
+
*
|
|
1096
|
+
* **Limitations:**
|
|
1097
|
+
* - Non-serializable payloads (functions, symbols, circular refs) get unique
|
|
1098
|
+
* fingerprints and won't be deduplicated
|
|
1099
|
+
* - Legitimate rapid-fire identical events may be incorrectly deduplicated
|
|
1100
|
+
* - The cache is bounded to 1000 entries with lazy pruning
|
|
1101
|
+
*
|
|
1102
|
+
* @internal
|
|
1103
|
+
*/
|
|
1104
|
+
processedEvents = /* @__PURE__ */ new Map();
|
|
1105
|
+
/**
|
|
1106
|
+
* Lifetime count of events suppressed by the deduplication cache.
|
|
1107
|
+
* Exposed via {@link __devtoolsIntrospect} so the DevTools agent can
|
|
1108
|
+
* surface it in the STORE_METRICS response without further core changes.
|
|
1109
|
+
*
|
|
1110
|
+
* @internal
|
|
1111
|
+
*/
|
|
1112
|
+
dedupCount = 0;
|
|
1113
|
+
/**
|
|
1114
|
+
* Store-owned metadata for registered effects, keyed by the effect function.
|
|
1115
|
+
* Kept **off** the caller's function object: mutating a user-owned function
|
|
1116
|
+
* (the old `fn.__quoMeta`) bled metadata across stores that share a handler
|
|
1117
|
+
* and left it attached after unregister. Cleared on {@link dispose}.
|
|
1118
|
+
*
|
|
1119
|
+
* @internal
|
|
1120
|
+
*/
|
|
1121
|
+
effectMeta = /* @__PURE__ */ new WeakMap();
|
|
1122
|
+
/**
|
|
1123
|
+
* Configuration for event deduplication.
|
|
1124
|
+
* @internal
|
|
1125
|
+
*/
|
|
1126
|
+
dedupConfig;
|
|
1127
|
+
/**
|
|
1128
|
+
* Timer for periodic cleanup of processed events.
|
|
1129
|
+
*
|
|
1130
|
+
* @internal
|
|
1131
|
+
*/
|
|
1132
|
+
eventCleanupTimer = null;
|
|
661
1133
|
/**
|
|
662
1134
|
* Creates a store from a {@link StoreSpec}.
|
|
663
1135
|
*
|
|
@@ -666,223 +1138,15 @@ class $ {
|
|
|
666
1138
|
* @public
|
|
667
1139
|
*/
|
|
668
1140
|
constructor(e) {
|
|
669
|
-
|
|
670
|
-
* Store name (used by DevTools & diagnostics).
|
|
671
|
-
*
|
|
672
|
-
* @public
|
|
673
|
-
*/
|
|
674
|
-
p(this, "name");
|
|
675
|
-
/**
|
|
676
|
-
* Registered middleware pipeline (run **before** reducers).
|
|
677
|
-
* Stores either raw functions (legacy) or MiddlewareSpec objects.
|
|
678
|
-
* Return `false` from the middleware function to stop propagation.
|
|
679
|
-
*
|
|
680
|
-
* @internal
|
|
681
|
-
*/
|
|
682
|
-
p(this, "middleware");
|
|
683
|
-
/**
|
|
684
|
-
* Installed slice reducers keyed by slice name.
|
|
685
|
-
*
|
|
686
|
-
* @internal
|
|
687
|
-
*/
|
|
688
|
-
p(this, "reducers");
|
|
689
|
-
/**
|
|
690
|
-
* Current immutable snapshot of the store state.
|
|
691
|
-
* This reference changes whenever any slice changes (shallow immutability).
|
|
692
|
-
*
|
|
693
|
-
* @internal
|
|
694
|
-
*/
|
|
695
|
-
p(this, "state");
|
|
696
|
-
/**
|
|
697
|
-
* Bus for reducer wiring (emit by `(channel, type)`).
|
|
698
|
-
*
|
|
699
|
-
* @internal
|
|
700
|
-
*/
|
|
701
|
-
p(this, "reducerBus");
|
|
702
|
-
/**
|
|
703
|
-
* Bus for **granular** connector events (emit by **dotted path** inside a slice).
|
|
704
|
-
*
|
|
705
|
-
* @internal
|
|
706
|
-
*/
|
|
707
|
-
p(this, "connectorBus");
|
|
708
|
-
/**
|
|
709
|
-
* Coarse-grained listeners (called once per committed event, only if state changed).
|
|
710
|
-
*
|
|
711
|
-
* @internal
|
|
712
|
-
*/
|
|
713
|
-
p(this, "listeners", /* @__PURE__ */ new Set());
|
|
714
|
-
/**
|
|
715
|
-
* Registered effect handlers keyed by `"channel::type"` for O(1) lookup.
|
|
716
|
-
* Used for effects with explicit `keys` targeting.
|
|
717
|
-
*
|
|
718
|
-
* @internal
|
|
719
|
-
*/
|
|
720
|
-
p(this, "effects", /* @__PURE__ */ new Map());
|
|
721
|
-
/**
|
|
722
|
-
* Pattern-based effects that need runtime matching.
|
|
723
|
-
* Used for effects with `when: { any }`, `{ channel }`, or `{ channels }`.
|
|
724
|
-
* Stores tuples of [effect function, when matcher].
|
|
725
|
-
*
|
|
726
|
-
* @internal
|
|
727
|
-
*/
|
|
728
|
-
p(this, "patternEffects", /* @__PURE__ */ new Set());
|
|
729
|
-
/**
|
|
730
|
-
* Committed event subscribers keyed by `"channel::type"` for O(1) lookup.
|
|
731
|
-
* Notified after reducers, before effects, for events that passed middleware.
|
|
732
|
-
*
|
|
733
|
-
* @internal
|
|
734
|
-
*/
|
|
735
|
-
p(this, "committedEventSubscribers", /* @__PURE__ */ new Map());
|
|
736
|
-
/**
|
|
737
|
-
* Uncommitted event subscribers keyed by `"channel::type"` for O(1) lookup.
|
|
738
|
-
* Notified when middleware rejects an event.
|
|
739
|
-
*
|
|
740
|
-
* @internal
|
|
741
|
-
*/
|
|
742
|
-
p(this, "uncommittedEventSubscribers", /* @__PURE__ */ new Map());
|
|
743
|
-
/**
|
|
744
|
-
* All-events subscribers keyed by `"channel::type"` for O(1) lookup.
|
|
745
|
-
* Notified for both committed and uncommitted events with phase parameter.
|
|
746
|
-
*
|
|
747
|
-
* @internal
|
|
748
|
-
*/
|
|
749
|
-
p(this, "allEventSubscribers", /* @__PURE__ */ new Map());
|
|
750
|
-
/**
|
|
751
|
-
* Track reducerBus unsubs per slice for HMR/register/unregister.
|
|
752
|
-
*
|
|
753
|
-
* @internal
|
|
754
|
-
*/
|
|
755
|
-
p(this, "sliceUnsubs", /* @__PURE__ */ new Map());
|
|
756
|
-
/**
|
|
757
|
-
* Pattern-based reducers that need runtime matching.
|
|
758
|
-
* Used for reducers with `when: { any }`, `{ channel }`, or `{ channels }`.
|
|
759
|
-
* Maps slice name to the `when` matcher.
|
|
760
|
-
*
|
|
761
|
-
* @internal
|
|
762
|
-
*/
|
|
763
|
-
p(this, "patternReducers", /* @__PURE__ */ new Map());
|
|
764
|
-
/**
|
|
765
|
-
* Whether `__replayEvents()` is allowed.
|
|
766
|
-
* Set from `spec.devtools.allowReplay`.
|
|
767
|
-
*
|
|
768
|
-
* @internal
|
|
769
|
-
*/
|
|
770
|
-
p(this, "replayEnabled");
|
|
771
|
-
/**
|
|
772
|
-
* Produces the `id` for each emitted event. Defaults to `crypto.randomUUID()`; overridable
|
|
773
|
-
* via {@link StoreSpec.idFactory} for runtimes lacking it or for deterministic tests.
|
|
774
|
-
*
|
|
775
|
-
* @internal
|
|
776
|
-
*/
|
|
777
|
-
p(this, "idFactory");
|
|
778
|
-
/**
|
|
779
|
-
* Optional hook invoked when an effect throws/rejects. See
|
|
780
|
-
* {@link StoreSpec.onEffectError}. `await emit()` never rejects on effect
|
|
781
|
-
* failure — this is how callers observe effect errors.
|
|
782
|
-
*/
|
|
783
|
-
p(this, "onEffectError");
|
|
784
|
-
/**
|
|
785
|
-
* Optional hook invoked when a reducer throws. See {@link StoreSpec.onReducerError}. The
|
|
786
|
-
* failing slice is isolated rather than the event being rolled back, so this is the only
|
|
787
|
-
* signal that a reducer misbehaved.
|
|
788
|
-
*/
|
|
789
|
-
p(this, "onReducerError");
|
|
790
|
-
/**
|
|
791
|
-
* `slice:channel:type` combinations already warned about for payload aliasing.
|
|
792
|
-
*
|
|
793
|
-
* @remarks
|
|
794
|
-
* Development-only diagnostics have to stay quiet enough to be read. One warning names the
|
|
795
|
-
* pattern; repeating it once per event would bury it.
|
|
796
|
-
*/
|
|
797
|
-
p(this, "warnedPayloadAliases", /* @__PURE__ */ new Set());
|
|
798
|
-
/**
|
|
799
|
-
* Pending events awaiting the **synchronous** reduce phase (middleware +
|
|
800
|
-
* reducers + subscribers + coarse listeners). Drained by {@link drainReduce}.
|
|
801
|
-
*
|
|
802
|
-
* @internal
|
|
803
|
-
*/
|
|
804
|
-
p(this, "reduceQueue", []);
|
|
805
|
-
/**
|
|
806
|
-
* Re-entrancy guard for the synchronous reduce phase.
|
|
807
|
-
*
|
|
808
|
-
* @internal
|
|
809
|
-
*/
|
|
810
|
-
p(this, "isReducing", !1);
|
|
811
|
-
/**
|
|
812
|
-
* Registered instrumentation observers (DevTools seam). See {@link instrument}.
|
|
813
|
-
*
|
|
814
|
-
* @internal
|
|
815
|
-
*/
|
|
816
|
-
p(this, "instrumentObservers", /* @__PURE__ */ new Set());
|
|
817
|
-
/**
|
|
818
|
-
* Scratch array collecting slice-prefixed changed leaf paths during an
|
|
819
|
-
* instrumented reduce. Set by {@link drainReduce} while observers are active;
|
|
820
|
-
* appended to by {@link forwardEvent}. `null` when not instrumenting.
|
|
821
|
-
*
|
|
822
|
-
* @internal
|
|
823
|
-
*/
|
|
824
|
-
p(this, "changedPathSink", null);
|
|
825
|
-
/**
|
|
826
|
-
* Count of effect tasks currently in flight; surfaced as queue depth by
|
|
827
|
-
* {@link __devtoolsIntrospect}.
|
|
828
|
-
*
|
|
829
|
-
* @internal
|
|
830
|
-
*/
|
|
831
|
-
p(this, "inFlightEffects", 0);
|
|
832
|
-
/**
|
|
833
|
-
* Tracks processed events by fingerprint with timestamps for TTL-based deduplication.
|
|
834
|
-
*
|
|
835
|
-
* **Deduplication Behavior:**
|
|
836
|
-
* - Events are fingerprinted using `channel::type::JSON(payload)`
|
|
837
|
-
* - If an identical fingerprint is seen within the dedup window, it's skipped
|
|
838
|
-
* - The window is 50ms in development, 100ms in production
|
|
839
|
-
*
|
|
840
|
-
* **Limitations:**
|
|
841
|
-
* - Non-serializable payloads (functions, symbols, circular refs) get unique
|
|
842
|
-
* fingerprints and won't be deduplicated
|
|
843
|
-
* - Legitimate rapid-fire identical events may be incorrectly deduplicated
|
|
844
|
-
* - The cache is bounded to 1000 entries with lazy pruning
|
|
845
|
-
*
|
|
846
|
-
* @internal
|
|
847
|
-
*/
|
|
848
|
-
p(this, "processedEvents", /* @__PURE__ */ new Map());
|
|
849
|
-
/**
|
|
850
|
-
* Lifetime count of events suppressed by the deduplication cache.
|
|
851
|
-
* Exposed via {@link __devtoolsIntrospect} so the DevTools agent can
|
|
852
|
-
* surface it in the STORE_METRICS response without further core changes.
|
|
853
|
-
*
|
|
854
|
-
* @internal
|
|
855
|
-
*/
|
|
856
|
-
p(this, "dedupCount", 0);
|
|
857
|
-
/**
|
|
858
|
-
* Store-owned metadata for registered effects, keyed by the effect function.
|
|
859
|
-
* Kept **off** the caller's function object: mutating a user-owned function
|
|
860
|
-
* (the old `fn.__quoMeta`) bled metadata across stores that share a handler
|
|
861
|
-
* and left it attached after unregister. Cleared on {@link dispose}.
|
|
862
|
-
*
|
|
863
|
-
* @internal
|
|
864
|
-
*/
|
|
865
|
-
p(this, "effectMeta", /* @__PURE__ */ new WeakMap());
|
|
866
|
-
/**
|
|
867
|
-
* Configuration for event deduplication.
|
|
868
|
-
* @internal
|
|
869
|
-
*/
|
|
870
|
-
p(this, "dedupConfig");
|
|
871
|
-
/**
|
|
872
|
-
* Timer for periodic cleanup of processed events.
|
|
873
|
-
*
|
|
874
|
-
* @internal
|
|
875
|
-
*/
|
|
876
|
-
p(this, "eventCleanupTimer", null);
|
|
877
|
-
if (this.name = e.name ?? "yoltra Store", this.reducerBus = new B(), this.connectorBus = new H(), this.middleware = [...e.middleware ?? []], this.reducers = {}, this.state = {}, this.replayEnabled = e.devtools?.allowReplay ?? !1, this.idFactory = e.idFactory ?? (() => crypto.randomUUID()), this.onEffectError = e.onEffectError, this.onReducerError = e.onReducerError, this.dedupConfig = {
|
|
1141
|
+
if (this.name = e.name ?? "yoltra Store", this.reducerBus = new W(), this.connectorBus = new U(), this.middleware = [...e.middleware ?? []], this.reducers = {}, this.state = {}, this.replayEnabled = e.devtools?.allowReplay ?? !1, this.idFactory = e.idFactory ?? (() => crypto.randomUUID()), this.onEffectError = e.onEffectError, this.onReducerError = e.onReducerError, this.maxReduceDepth = e.maxReduceDepth ?? ie, this.maxTransitionsPerDrain = e.maxTransitionsPerDrain ?? 1 / 0, this.onCascade = e.onCascade, this.onRejected = e.onRejected, this.dedupConfig = {
|
|
878
1142
|
windowMs: e.dedupWindowMs ?? 0,
|
|
879
1143
|
maxCacheSize: 1e3
|
|
880
|
-
}, Object.entries(e.reducer).forEach(([t,
|
|
881
|
-
this.mountSlice(t,
|
|
1144
|
+
}, Object.entries(e.reducer).forEach(([t, s]) => {
|
|
1145
|
+
this.mountSlice(t, s, { preserveState: !1 });
|
|
882
1146
|
}), e.effects?.length)
|
|
883
1147
|
for (const t of e.effects)
|
|
884
1148
|
this.registerEffect(t);
|
|
885
|
-
this.dispose = this.dispose.bind(this), this.notifyEffects = this.notifyEffects.bind(this), this.
|
|
1149
|
+
this.dispose = this.dispose.bind(this), this.notifyEffects = this.notifyEffects.bind(this), this.__applyExternalState = this.__applyExternalState.bind(this), this.__replayEvents = this.__replayEvents.bind(this), this.__devtoolsIntrospect = this.__devtoolsIntrospect.bind(this), this.mountSlice = this.mountSlice.bind(this), this.unmountSlice = this.unmountSlice.bind(this), this.getAtPath = this.getAtPath.bind(this), this.emit = this.emit.bind(this), this.subscribe = this.subscribe.bind(this), this.connect = this.connect.bind(this), this.onEffect = this.onEffect.bind(this), this.onEvent = this.onEvent.bind(this), this.getState = this.getState.bind(this), this.registerEffect = this.registerEffect.bind(this), this.registerMiddleware = this.registerMiddleware.bind(this), this.registerReducer = this.registerReducer.bind(this), this.replaceMiddleware = this.replaceMiddleware.bind(this), this.replaceEffects = this.replaceEffects.bind(this), this.replaceReducers = this.replaceReducers.bind(this), this.hotReplace = this.hotReplace.bind(this);
|
|
886
1150
|
}
|
|
887
1151
|
/**
|
|
888
1152
|
* Cleanup resources (timers, etc.) when disposing the store.
|
|
@@ -898,7 +1162,7 @@ class $ {
|
|
|
898
1162
|
* @public
|
|
899
1163
|
*/
|
|
900
1164
|
dispose() {
|
|
901
|
-
this.eventCleanupTimer && (clearInterval(this.eventCleanupTimer), this.eventCleanupTimer = null), this.processedEvents.clear(), this.effects.clear(), this.patternEffects.clear(), this.effectMeta = /* @__PURE__ */ new WeakMap(), this.warnedPayloadAliases.clear(), this.listeners.clear(), this.committedEventSubscribers.clear(), this.uncommittedEventSubscribers.clear(), this.allEventSubscribers.clear(), this.instrumentObservers.clear(), this.connectorBus.clear(), this.reducerBus.clear(), this.patternReducers.clear(), this.sliceUnsubs.clear(), this.changedPathSink = null;
|
|
1165
|
+
this.eventCleanupTimer && (clearInterval(this.eventCleanupTimer), this.eventCleanupTimer = null), this.processedEvents.clear(), this.effects.clear(), this.patternEffects.clear(), this.effectMeta = /* @__PURE__ */ new WeakMap(), this.warnedPayloadAliases.clear(), this.listeners.clear(), this.committedEventSubscribers.clear(), this.uncommittedEventSubscribers.clear(), this.writtenEventSubscribers.clear(), this.allEventSubscribers.clear(), this.instrumentObservers.clear(), this.connectorBus.clear(), this.reducerBus.clear(), this.patternReducers.clear(), this.sliceUnsubs.clear(), this.changedPathSink = null;
|
|
902
1166
|
}
|
|
903
1167
|
/**
|
|
904
1168
|
* Generates a fingerprint for an event for deduplication purposes.
|
|
@@ -911,17 +1175,17 @@ class $ {
|
|
|
911
1175
|
*
|
|
912
1176
|
* @internal
|
|
913
1177
|
*/
|
|
914
|
-
fingerprint(e, t,
|
|
915
|
-
const
|
|
1178
|
+
fingerprint(e, t, s) {
|
|
1179
|
+
const n = `${e}::${t}`;
|
|
916
1180
|
try {
|
|
917
|
-
if (
|
|
918
|
-
return `${
|
|
919
|
-
if (typeof
|
|
920
|
-
return `${
|
|
921
|
-
const
|
|
922
|
-
return `${
|
|
1181
|
+
if (s == null)
|
|
1182
|
+
return `${n}::null`;
|
|
1183
|
+
if (typeof s != "object")
|
|
1184
|
+
return `${n}::${String(s)}`;
|
|
1185
|
+
const r = JSON.stringify(s);
|
|
1186
|
+
return `${n}::${r}`;
|
|
923
1187
|
} catch {
|
|
924
|
-
return `${
|
|
1188
|
+
return `${n}::${Date.now()}::${Math.random()}`;
|
|
925
1189
|
}
|
|
926
1190
|
}
|
|
927
1191
|
/**
|
|
@@ -934,8 +1198,8 @@ class $ {
|
|
|
934
1198
|
* @internal
|
|
935
1199
|
*/
|
|
936
1200
|
shouldDedupe(e, t) {
|
|
937
|
-
const
|
|
938
|
-
return
|
|
1201
|
+
const s = Date.now(), n = this.processedEvents.get(e);
|
|
1202
|
+
return n !== void 0 && s - n < t ? (this.dedupCount++, !0) : (this.processedEvents.set(e, s), this.ensureCleanupTimer(), this.processedEvents.size > this.dedupConfig.maxCacheSize && this.pruneProcessedEvents(s), !1);
|
|
939
1203
|
}
|
|
940
1204
|
/**
|
|
941
1205
|
* Starts the periodic prune interval if it isn't already running. Called when
|
|
@@ -957,55 +1221,31 @@ class $ {
|
|
|
957
1221
|
* @internal
|
|
958
1222
|
*/
|
|
959
1223
|
pruneProcessedEvents(e) {
|
|
960
|
-
const t = Math.max(this.dedupConfig.windowMs,
|
|
961
|
-
for (const [
|
|
962
|
-
|
|
1224
|
+
const t = Math.max(this.dedupConfig.windowMs, A), s = e - t * 2;
|
|
1225
|
+
for (const [n, r] of this.processedEvents)
|
|
1226
|
+
r < s && this.processedEvents.delete(n);
|
|
963
1227
|
this.processedEvents.size === 0 && this.eventCleanupTimer !== null && (clearInterval(this.eventCleanupTimer), this.eventCleanupTimer = null);
|
|
964
1228
|
}
|
|
965
1229
|
/**
|
|
966
|
-
*
|
|
967
|
-
*
|
|
968
|
-
* @param when - The When matcher (or undefined for "all events").
|
|
969
|
-
* @param event - The event to check.
|
|
970
|
-
* @returns `true` if the event matches, `false` otherwise.
|
|
1230
|
+
* Reports a breached ceiling and refuses the emit.
|
|
971
1231
|
*
|
|
972
1232
|
* @remarks
|
|
973
|
-
*
|
|
974
|
-
*
|
|
975
|
-
*
|
|
976
|
-
*
|
|
977
|
-
* - `{ channels: ['x', 'y'] }` matches if event's channel is in the array.
|
|
1233
|
+
* Console *and* hook, matching how reducer and effect errors are reported: a cascade is a
|
|
1234
|
+
* wiring bug, and the console line is what a developer who has not registered a hook will
|
|
1235
|
+
* actually see. Without one, refusing the emit would look exactly like the event never having
|
|
1236
|
+
* been emitted at all — which is the invisibility this whole guard exists to end.
|
|
978
1237
|
*
|
|
979
1238
|
* @internal
|
|
980
1239
|
*/
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
)
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
* @param input - MiddlewareInput (function or spec).
|
|
991
|
-
* @returns The middleware function.
|
|
992
|
-
*
|
|
993
|
-
* @internal
|
|
994
|
-
*/
|
|
995
|
-
getMiddlewareFunction(e) {
|
|
996
|
-
return typeof e == "function" ? e : e.middleware;
|
|
997
|
-
}
|
|
998
|
-
/**
|
|
999
|
-
* Gets the `when` matcher from a MiddlewareInput.
|
|
1000
|
-
*
|
|
1001
|
-
* @param input - MiddlewareInput (function or spec).
|
|
1002
|
-
* @returns The `when` matcher, or `undefined` for raw functions (match all).
|
|
1003
|
-
*
|
|
1004
|
-
* @internal
|
|
1005
|
-
*/
|
|
1006
|
-
getMiddlewareWhen(e) {
|
|
1007
|
-
if (typeof e != "function")
|
|
1008
|
-
return e.when;
|
|
1240
|
+
reportCascade(e, t, s, n, r) {
|
|
1241
|
+
console.error(
|
|
1242
|
+
`[yoltra] Cascade stopped: "${s.channel}/${s.type}" would exceed ${e} (${t}). This event was refused and the chain ends here. A chain this long is almost always two consumers emitting into each other — check what reacts to "${s.channel}/${s.type}" and what that emits in turn.` + (r.length > 0 ? ` Recent causal chain: ${r.join(" → ")} → (refused).` : "")
|
|
1243
|
+
);
|
|
1244
|
+
try {
|
|
1245
|
+
this.onCascade?.({ limit: e, limitValue: t, event: s, depth: n, chain: r });
|
|
1246
|
+
} catch (c) {
|
|
1247
|
+
console.error("onCascade handler error:", c);
|
|
1248
|
+
}
|
|
1009
1249
|
}
|
|
1010
1250
|
/**
|
|
1011
1251
|
* Invokes all registered **effects** for a given event.
|
|
@@ -1016,22 +1256,40 @@ class $ {
|
|
|
1016
1256
|
* @internal
|
|
1017
1257
|
*/
|
|
1018
1258
|
async notifyEffects(e) {
|
|
1019
|
-
const t = `${String(e.channel)}::${String(e.type)}`, n = this.effects.get(
|
|
1259
|
+
const t = this.scopedEmit(e), s = `${String(e.channel)}::${String(e.type)}`, n = this.effects.get(s);
|
|
1020
1260
|
if (n && n.size > 0)
|
|
1021
|
-
for (const
|
|
1261
|
+
for (const r of [...n])
|
|
1022
1262
|
try {
|
|
1023
|
-
await
|
|
1024
|
-
} catch (
|
|
1025
|
-
console.error("Effect error:",
|
|
1263
|
+
await r(e, this.getState, t);
|
|
1264
|
+
} catch (c) {
|
|
1265
|
+
console.error("Effect error:", c), this.onEffectError?.(c, e);
|
|
1026
1266
|
}
|
|
1027
|
-
for (const { effect:
|
|
1028
|
-
if (
|
|
1267
|
+
for (const { effect: r, when: c } of this.patternEffects)
|
|
1268
|
+
if (k(c, e))
|
|
1029
1269
|
try {
|
|
1030
|
-
await
|
|
1031
|
-
} catch (
|
|
1032
|
-
console.error("Effect error:",
|
|
1270
|
+
await r(e, this.getState, t);
|
|
1271
|
+
} catch (l) {
|
|
1272
|
+
console.error("Effect error:", l), this.onEffectError?.(l, e);
|
|
1033
1273
|
}
|
|
1034
1274
|
}
|
|
1275
|
+
/**
|
|
1276
|
+
* An `emit` that attributes whatever it sends to `cause`.
|
|
1277
|
+
*
|
|
1278
|
+
* @remarks
|
|
1279
|
+
* Built per event rather than per effect: every effect reacting to one event shares a cause,
|
|
1280
|
+
* and one closure is cheaper than one per handler on a path that runs for every committed
|
|
1281
|
+
* event.
|
|
1282
|
+
*
|
|
1283
|
+
* @internal
|
|
1284
|
+
*/
|
|
1285
|
+
scopedEmit(e) {
|
|
1286
|
+
const t = {
|
|
1287
|
+
id: e.id,
|
|
1288
|
+
depth: e.depth ?? 0,
|
|
1289
|
+
chain: [...this.currentEvent?.chain ?? [], e.id].slice(-z)
|
|
1290
|
+
};
|
|
1291
|
+
return ((s, n, r, c) => this.emitCaused(t, s, n, r, c));
|
|
1292
|
+
}
|
|
1035
1293
|
/**
|
|
1036
1294
|
* Notifies event subscribers for a specific phase.
|
|
1037
1295
|
*
|
|
@@ -1043,12 +1301,13 @@ class $ {
|
|
|
1043
1301
|
* @internal
|
|
1044
1302
|
*/
|
|
1045
1303
|
notifyEventSubscribers(e, t) {
|
|
1046
|
-
const
|
|
1047
|
-
if (
|
|
1048
|
-
for (const
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1304
|
+
const s = `${String(e.channel)}::${String(e.type)}`, r = (t === "committed" ? this.committedEventSubscribers : t === "written" ? this.writtenEventSubscribers : this.uncommittedEventSubscribers).get(s);
|
|
1305
|
+
if (r?.size)
|
|
1306
|
+
for (const l of [...r]) this.invokeEventSubscriber(l, e, t);
|
|
1307
|
+
if (t === "written") return;
|
|
1308
|
+
const c = this.allEventSubscribers.get(s);
|
|
1309
|
+
if (c?.size)
|
|
1310
|
+
for (const l of [...c]) this.invokeEventSubscriber(l, e, t);
|
|
1052
1311
|
}
|
|
1053
1312
|
/**
|
|
1054
1313
|
* Invokes a single event-subscription handler **fire-and-forget**: synchronous
|
|
@@ -1057,12 +1316,12 @@ class $ {
|
|
|
1057
1316
|
*
|
|
1058
1317
|
* @internal
|
|
1059
1318
|
*/
|
|
1060
|
-
invokeEventSubscriber(e, t,
|
|
1319
|
+
invokeEventSubscriber(e, t, s) {
|
|
1061
1320
|
try {
|
|
1062
|
-
const
|
|
1063
|
-
|
|
1064
|
-
} catch (
|
|
1065
|
-
console.error("Event subscription error:",
|
|
1321
|
+
const n = e(t, this.getState, this.emit, s);
|
|
1322
|
+
n && typeof n.then == "function" && n.catch((r) => console.error("Event subscription error:", r));
|
|
1323
|
+
} catch (n) {
|
|
1324
|
+
console.error("Event subscription error:", n);
|
|
1066
1325
|
}
|
|
1067
1326
|
}
|
|
1068
1327
|
/**
|
|
@@ -1100,53 +1359,116 @@ class $ {
|
|
|
1100
1359
|
* pattern reducer's throw aborted the commit and notified nobody, not even the uncommitted
|
|
1101
1360
|
* subscribers a veto would have reached.
|
|
1102
1361
|
*
|
|
1103
|
-
* The semantics are
|
|
1362
|
+
* The semantics are the same either way: **the failing slice is isolated.** Its state is
|
|
1104
1363
|
* unchanged, every other slice still reduces, and the event still commits if anything else
|
|
1105
|
-
* changed.
|
|
1106
|
-
*
|
|
1107
|
-
*
|
|
1108
|
-
*
|
|
1364
|
+
* changed.
|
|
1365
|
+
*
|
|
1366
|
+
* That is deliberately *not* what a {@link Rejected} refusal does, which discards the whole
|
|
1367
|
+
* event. A crash and a refusal are different acts: a reducer that throws has a bug and should
|
|
1368
|
+
* not be able to veto its neighbours' work, while a reducer that refuses has made a decision
|
|
1369
|
+
* and must be able to.
|
|
1370
|
+
*
|
|
1371
|
+
* This once argued that rolling back was untenable, because subscribers were notified as each
|
|
1372
|
+
* slice committed and a later revert would have told them about a value that no longer
|
|
1373
|
+
* existed. Staging removed that obstacle — nothing is notified until every slice is written —
|
|
1374
|
+
* which is what made refusal possible at all.
|
|
1109
1375
|
*
|
|
1110
1376
|
* @internal
|
|
1111
1377
|
*/
|
|
1112
|
-
|
|
1378
|
+
stageSliceGuarded(e, t, s) {
|
|
1113
1379
|
try {
|
|
1114
|
-
return this.
|
|
1380
|
+
return this.stageSlice(e, t, s);
|
|
1115
1381
|
} catch (n) {
|
|
1116
|
-
return console.error(`Reducer error in slice "${e}":`, n), this.onReducerError?.(n, t, e),
|
|
1382
|
+
return console.error(`Reducer error in slice "${e}":`, n), this.onReducerError?.(n, t, e), null;
|
|
1117
1383
|
}
|
|
1118
1384
|
}
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1385
|
+
/**
|
|
1386
|
+
* Runs one slice's reducer and records what it *would* write. Writes nothing.
|
|
1387
|
+
*
|
|
1388
|
+
* @returns The reducer's {@link Rejection} if it refused, otherwise `null`.
|
|
1389
|
+
*
|
|
1390
|
+
* @remarks
|
|
1391
|
+
* The staging half of the write path. Nothing here touches `this.state` or notifies anybody,
|
|
1392
|
+
* which is what lets the event be refused after every reducer has had its say — a decision
|
|
1393
|
+
* that has to see the whole diff cannot be made one slice at a time.
|
|
1394
|
+
*
|
|
1395
|
+
* Freezing happens here rather than at commit because it is where the new value is built, and
|
|
1396
|
+
* the freeze is a no-op on anything already frozen; a staged slice that never commits is
|
|
1397
|
+
* discarded frozen, which costs nothing and keeps the committed path free of a second walk.
|
|
1398
|
+
*
|
|
1399
|
+
* @internal
|
|
1400
|
+
*/
|
|
1401
|
+
stageSlice(e, t, s) {
|
|
1402
|
+
const n = this.state[e], r = this.reducers[e].reduce(n, t);
|
|
1403
|
+
if (V(r)) return r;
|
|
1404
|
+
if (n === r) return null;
|
|
1405
|
+
const c = I(n, r);
|
|
1406
|
+
if (c.length === 0) return null;
|
|
1407
|
+
const l = t.payload, i = process.env.NODE_ENV !== "production" && l !== null && typeof l == "object" ? {
|
|
1408
|
+
watch: l,
|
|
1126
1409
|
onFound: () => {
|
|
1127
|
-
const
|
|
1128
|
-
this.warnedPayloadAliases.has(
|
|
1410
|
+
const a = `${e}:${t.channel}:${t.type}`;
|
|
1411
|
+
this.warnedPayloadAliases.has(a) || (this.warnedPayloadAliases.add(a), console.warn(
|
|
1129
1412
|
`[yoltra] Slice "${e}" stored the payload of "${t.channel}/${t.type}" by reference. It is now frozen along with the rest of the state, so the emitter mutating it later will throw in development and silently corrupt state in production. Copy the payload in the reducer instead.`
|
|
1130
1413
|
));
|
|
1131
1414
|
}
|
|
1132
|
-
} : void 0
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1415
|
+
} : void 0;
|
|
1416
|
+
return s.push({
|
|
1417
|
+
name: e,
|
|
1418
|
+
prev: n,
|
|
1419
|
+
frozen: R(r, i),
|
|
1420
|
+
leafPaths: c
|
|
1421
|
+
}), null;
|
|
1422
|
+
}
|
|
1423
|
+
/**
|
|
1424
|
+
* Writes every staged slice, then tells the world — in that order.
|
|
1425
|
+
*
|
|
1426
|
+
* @remarks
|
|
1427
|
+
* The commit half. Assigning all slices under a single new root before any notification goes
|
|
1428
|
+
* out is what closes the window this used to leave open: notifications fired per slice as each
|
|
1429
|
+
* committed, so a subscriber to slice A that read `getState()` could observe slice B of the
|
|
1430
|
+
* *same event* not yet applied. In React that window is real, because the atomic hooks use a
|
|
1431
|
+
* change as a bare signal and then re-read the whole store.
|
|
1432
|
+
*
|
|
1433
|
+
* It is also what makes refusal possible at all. The previous code documented rollback as
|
|
1434
|
+
* untenable precisely because "an event that reverted afterwards would have already told
|
|
1435
|
+
* components about a value that no longer exists" — true when notification and commit were the
|
|
1436
|
+
* same step, and no longer true now that they are not.
|
|
1437
|
+
*
|
|
1438
|
+
* @returns `true` if anything was written.
|
|
1439
|
+
*
|
|
1440
|
+
* @internal
|
|
1441
|
+
*/
|
|
1442
|
+
commitStaged(e, t) {
|
|
1443
|
+
if (e.length === 0) return !1;
|
|
1444
|
+
const s = { ...this.state };
|
|
1445
|
+
for (const n of e) s[n.name] = n.frozen;
|
|
1446
|
+
if (this.state = s, this.changedPathSink)
|
|
1447
|
+
for (const n of e)
|
|
1448
|
+
for (const r of n.leafPaths)
|
|
1449
|
+
this.changedPathSink.push(r ? `${n.name}.${r}` : n.name);
|
|
1450
|
+
for (const n of e) {
|
|
1451
|
+
const r = /* @__PURE__ */ new Set();
|
|
1452
|
+
for (const c of n.leafPaths) {
|
|
1453
|
+
if (c === "") {
|
|
1454
|
+
r.add("");
|
|
1455
|
+
continue;
|
|
1456
|
+
}
|
|
1457
|
+
for (const l of x.buildAncestorPaths(c)) r.add(l);
|
|
1141
1458
|
}
|
|
1142
|
-
for (const
|
|
1459
|
+
for (const c of r)
|
|
1460
|
+
this.connectorBus.emitWith(n.name, c, () => ({
|
|
1461
|
+
oldValue: this.getAtPath(n.prev, c),
|
|
1462
|
+
newValue: this.getAtPath(n.frozen, c),
|
|
1463
|
+
path: c,
|
|
1464
|
+
// Provenance, built inside the same lazy factory as the values: a subscriber that
|
|
1465
|
+
// needs to know why a value moved no longer has to mirror the cause into state and
|
|
1466
|
+
// keep it there twice.
|
|
1467
|
+
eventId: t.id,
|
|
1468
|
+
channel: t.channel,
|
|
1469
|
+
type: t.type
|
|
1470
|
+
}));
|
|
1143
1471
|
}
|
|
1144
|
-
for (const c of f)
|
|
1145
|
-
this.connectorBus.emitWith(e, c, () => ({
|
|
1146
|
-
oldValue: this.getAtPath(n, c),
|
|
1147
|
-
newValue: this.getAtPath(r, c),
|
|
1148
|
-
path: c
|
|
1149
|
-
}));
|
|
1150
1472
|
return !0;
|
|
1151
1473
|
}
|
|
1152
1474
|
/**
|
|
@@ -1160,65 +1482,65 @@ class $ {
|
|
|
1160
1482
|
* @public
|
|
1161
1483
|
*/
|
|
1162
1484
|
__devtoolsIntrospect() {
|
|
1163
|
-
const e = Object.keys(this.reducers).map((
|
|
1164
|
-
const
|
|
1165
|
-
return { name:
|
|
1485
|
+
const e = Object.keys(this.reducers).map((l) => {
|
|
1486
|
+
const i = this.patternReducers.get(l);
|
|
1487
|
+
return { name: l, when: i };
|
|
1166
1488
|
}), t = [];
|
|
1167
|
-
for (const [
|
|
1168
|
-
if (
|
|
1169
|
-
const [
|
|
1170
|
-
for (const
|
|
1171
|
-
const
|
|
1172
|
-
t.push({ channel:
|
|
1489
|
+
for (const [l, i] of this.effects) {
|
|
1490
|
+
if (i.size === 0) continue;
|
|
1491
|
+
const [a, u] = l.split("::");
|
|
1492
|
+
for (const d of i) {
|
|
1493
|
+
const h = this.effectMeta.get(d);
|
|
1494
|
+
t.push({ channel: a, type: u, name: h?.name, description: h?.description });
|
|
1173
1495
|
}
|
|
1174
1496
|
}
|
|
1175
|
-
for (const
|
|
1176
|
-
const
|
|
1497
|
+
for (const l of this.patternEffects) {
|
|
1498
|
+
const i = this.effectMeta.get(l.effect);
|
|
1177
1499
|
t.push({
|
|
1178
1500
|
channel: "*",
|
|
1179
1501
|
type: "*",
|
|
1180
|
-
name:
|
|
1181
|
-
description:
|
|
1502
|
+
name: i?.name,
|
|
1503
|
+
description: i?.description
|
|
1182
1504
|
});
|
|
1183
1505
|
}
|
|
1184
|
-
const n = [];
|
|
1185
|
-
for (const a of this.middleware)
|
|
1186
|
-
typeof a == "function" ? n.push({ name: a.name || void 0 }) : n.push({
|
|
1187
|
-
name: a.meta?.name,
|
|
1188
|
-
description: a.meta?.description,
|
|
1189
|
-
when: a.when
|
|
1190
|
-
});
|
|
1191
1506
|
const s = [];
|
|
1192
|
-
for (const
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1507
|
+
for (const l of this.middleware)
|
|
1508
|
+
typeof l == "function" ? s.push({ name: l.name || void 0 }) : s.push({
|
|
1509
|
+
name: l.meta?.name,
|
|
1510
|
+
description: l.meta?.description,
|
|
1511
|
+
when: l.when
|
|
1512
|
+
});
|
|
1513
|
+
const n = [];
|
|
1514
|
+
for (const l of this.connectorBus.__introspect())
|
|
1515
|
+
for (let i = 0; i < l.count; i++)
|
|
1516
|
+
n.push({ reducer: l.channel, property: l.type });
|
|
1517
|
+
const r = [];
|
|
1518
|
+
for (const [l, i] of this.committedEventSubscribers) {
|
|
1519
|
+
if (i.size === 0) continue;
|
|
1520
|
+
const [a, u] = l.split("::");
|
|
1521
|
+
for (let d = 0; d < i.size; d++)
|
|
1522
|
+
r.push({ channel: a, type: u, phase: "committed" });
|
|
1201
1523
|
}
|
|
1202
|
-
for (const [
|
|
1203
|
-
if (
|
|
1204
|
-
const [
|
|
1205
|
-
for (let
|
|
1206
|
-
|
|
1524
|
+
for (const [l, i] of this.uncommittedEventSubscribers) {
|
|
1525
|
+
if (i.size === 0) continue;
|
|
1526
|
+
const [a, u] = l.split("::");
|
|
1527
|
+
for (let d = 0; d < i.size; d++)
|
|
1528
|
+
r.push({ channel: a, type: u, phase: "uncommitted" });
|
|
1207
1529
|
}
|
|
1208
|
-
for (const [
|
|
1209
|
-
if (
|
|
1210
|
-
const [
|
|
1211
|
-
for (let
|
|
1212
|
-
|
|
1530
|
+
for (const [l, i] of this.allEventSubscribers) {
|
|
1531
|
+
if (i.size === 0) continue;
|
|
1532
|
+
const [a, u] = l.split("::");
|
|
1533
|
+
for (let d = 0; d < i.size; d++)
|
|
1534
|
+
r.push({ channel: a, type: u, phase: "all" });
|
|
1213
1535
|
}
|
|
1214
|
-
const
|
|
1536
|
+
const c = this.listeners.size;
|
|
1215
1537
|
return {
|
|
1216
1538
|
reducers: e,
|
|
1217
1539
|
effects: t,
|
|
1218
|
-
middleware:
|
|
1219
|
-
atomic:
|
|
1220
|
-
event:
|
|
1221
|
-
coarse:
|
|
1540
|
+
middleware: s,
|
|
1541
|
+
atomic: n,
|
|
1542
|
+
event: r,
|
|
1543
|
+
coarse: c,
|
|
1222
1544
|
dedupHits: this.dedupCount,
|
|
1223
1545
|
queueDepth: this.reduceQueue.length + this.inFlightEffects
|
|
1224
1546
|
};
|
|
@@ -1228,7 +1550,7 @@ class $ {
|
|
|
1228
1550
|
* fine-grained path changes for each slice.
|
|
1229
1551
|
*
|
|
1230
1552
|
* **State Immutability**: If any slices change, a new state object is created via
|
|
1231
|
-
* shallow spread. This ensures consistent immutability with {@link
|
|
1553
|
+
* shallow spread. This ensures consistent immutability with {@link commitStaged}.
|
|
1232
1554
|
*
|
|
1233
1555
|
* **Missing slices**: the snapshot should contain every slice. A slice absent
|
|
1234
1556
|
* from `nextPlain` is **retained at its current value** (not blanked to
|
|
@@ -1243,36 +1565,36 @@ class $ {
|
|
|
1243
1565
|
throw new Error(
|
|
1244
1566
|
"[yoltra] External state apply (time-travel) is disabled. Enable it with createStore({ devtools: { allowReplay: true } })"
|
|
1245
1567
|
);
|
|
1246
|
-
const t = this.state,
|
|
1247
|
-
let
|
|
1248
|
-
Object.keys(this.reducers).forEach((
|
|
1249
|
-
const
|
|
1250
|
-
if (
|
|
1568
|
+
const t = this.state, s = e, n = { ...this.state };
|
|
1569
|
+
let r = !1;
|
|
1570
|
+
Object.keys(this.reducers).forEach((c) => {
|
|
1571
|
+
const l = t?.[c], i = s?.[c];
|
|
1572
|
+
if (i === void 0) {
|
|
1251
1573
|
process.env.NODE_ENV !== "production" && console.warn(
|
|
1252
1574
|
`[yoltra] External state is missing slice "${String(
|
|
1253
|
-
|
|
1575
|
+
c
|
|
1254
1576
|
)}"; retaining its current value. Time-travel snapshots should contain all slices.`
|
|
1255
1577
|
);
|
|
1256
1578
|
return;
|
|
1257
1579
|
}
|
|
1258
|
-
if (
|
|
1259
|
-
const
|
|
1260
|
-
|
|
1261
|
-
const
|
|
1262
|
-
if (
|
|
1263
|
-
const
|
|
1264
|
-
for (const
|
|
1265
|
-
if (
|
|
1266
|
-
|
|
1580
|
+
if (l === i) return;
|
|
1581
|
+
const a = R(i);
|
|
1582
|
+
n[c] = a, r = !0;
|
|
1583
|
+
const u = I(l, i);
|
|
1584
|
+
if (u.length === 0) return;
|
|
1585
|
+
const d = /* @__PURE__ */ new Set();
|
|
1586
|
+
for (const h of u) {
|
|
1587
|
+
if (h === "") {
|
|
1588
|
+
d.add("");
|
|
1267
1589
|
continue;
|
|
1268
1590
|
}
|
|
1269
|
-
for (const
|
|
1591
|
+
for (const p of x.buildAncestorPaths(h)) d.add(p);
|
|
1270
1592
|
}
|
|
1271
|
-
for (const
|
|
1272
|
-
const
|
|
1273
|
-
this.connectorBus.emit(
|
|
1593
|
+
for (const h of d) {
|
|
1594
|
+
const p = this.getAtPath(l, h), f = this.getAtPath(a, h);
|
|
1595
|
+
this.connectorBus.emit(c, h, { oldValue: p, newValue: f, path: h });
|
|
1274
1596
|
}
|
|
1275
|
-
}),
|
|
1597
|
+
}), r && (this.state = n), r && this.listeners.forEach((c) => c());
|
|
1276
1598
|
}
|
|
1277
1599
|
/**
|
|
1278
1600
|
* Replays a sequence of events from a snapshot through reducers and event
|
|
@@ -1292,13 +1614,24 @@ class $ {
|
|
|
1292
1614
|
"[yoltra] Event replay is disabled. Enable it with createStore({ devtools: { allowReplay: true } })"
|
|
1293
1615
|
);
|
|
1294
1616
|
this.__applyExternalState(e);
|
|
1295
|
-
for (const
|
|
1296
|
-
const
|
|
1297
|
-
this.
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1617
|
+
for (const s of t) {
|
|
1618
|
+
const n = s, r = [];
|
|
1619
|
+
this.stagingSink = r;
|
|
1620
|
+
let c = null;
|
|
1621
|
+
try {
|
|
1622
|
+
this.reducerBus.emit(n.channel, n.type, n.payload, n), c = this.stagedRejection;
|
|
1623
|
+
for (const [i, a] of this.patternReducers) {
|
|
1624
|
+
if (c !== null) break;
|
|
1625
|
+
if (k(a, n)) {
|
|
1626
|
+
const u = this.stageSliceGuarded(i, n, r);
|
|
1627
|
+
u !== null && (c = u);
|
|
1628
|
+
}
|
|
1629
|
+
}
|
|
1630
|
+
} finally {
|
|
1631
|
+
this.stagingSink = null, this.stagedRejection = null, this.stagedRejectedBy = "";
|
|
1632
|
+
}
|
|
1633
|
+
const l = c === null && this.commitStaged(r, n);
|
|
1634
|
+
this.notifyEventSubscribers(n, "committed"), l && (this.notifyEventSubscribers(n, "written"), this.listeners.forEach((i) => i()));
|
|
1302
1635
|
}
|
|
1303
1636
|
}
|
|
1304
1637
|
/**
|
|
@@ -1310,13 +1643,13 @@ class $ {
|
|
|
1310
1643
|
* phase* (step 5) runs afterwards, asynchronously.
|
|
1311
1644
|
* 1. **Deduplication** (opt-in) - Skip when content-dedup is enabled (`dedupWindowMs > 0`) or a matching `dedupKey` recurs; off by default
|
|
1312
1645
|
* 2. **Middleware** (sync) - Pre-reducer hooks; may cancel by returning `false`
|
|
1313
|
-
* 3. **Reducers** (sync) -
|
|
1314
|
-
* 4. **
|
|
1646
|
+
* 3. **Reducers** (sync) - every matching slice is *staged*; nothing is written yet, so a refusal from the last reducer still stops the first one's write
|
|
1647
|
+
* 4. **Commit + subscribers** (sync) - all staged slices are assigned under one new root, then event subscribers (`committed`, then `written` when state actually changed), then coarse listeners
|
|
1315
1648
|
* 5. **Effects** (async) - side-effects keyed by `(channel, type)`; the returned promise resolves once they complete
|
|
1316
1649
|
*
|
|
1317
1650
|
* **Change Detection**: Uses reference equality (`===`) on `this.state` to determine
|
|
1318
|
-
* if any slice changed. Works because
|
|
1319
|
-
*
|
|
1651
|
+
* if any slice changed. Works because the commit builds a new state reference via
|
|
1652
|
+
* shallow spread when any slice changes.
|
|
1320
1653
|
*
|
|
1321
1654
|
* @typeParam C - Channel key in `EM`.
|
|
1322
1655
|
* @typeParam T - Type key within channel `C`.
|
|
@@ -1344,26 +1677,60 @@ class $ {
|
|
|
1344
1677
|
*
|
|
1345
1678
|
* @public
|
|
1346
1679
|
*/
|
|
1347
|
-
async emit(e, t,
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1680
|
+
async emit(e, t, s, n) {
|
|
1681
|
+
return this.emitCaused(null, e, t, s, n);
|
|
1682
|
+
}
|
|
1683
|
+
/**
|
|
1684
|
+
* The real emit, with an explicitly supplied cause.
|
|
1685
|
+
*
|
|
1686
|
+
* @remarks
|
|
1687
|
+
* Exists so the parent can be passed without a pseudo-private field on the public
|
|
1688
|
+
* {@link EmitOptions}. Two callers supply one: the public {@link emit} passes `null` and lets
|
|
1689
|
+
* `currentEvent` speak for the synchronous case, and the scoped `emit` handed to effects passes
|
|
1690
|
+
* the event that triggered them — effects resume after the drain has ended, so nothing else
|
|
1691
|
+
* could still know what caused them.
|
|
1692
|
+
*
|
|
1693
|
+
* @internal
|
|
1694
|
+
*/
|
|
1695
|
+
async emitCaused(e, t, s, n, r) {
|
|
1696
|
+
const c = r?.dedupKey, l = this.dedupConfig.windowMs;
|
|
1697
|
+
if (r?.skipDedup !== !0 && (l > 0 || c !== void 0)) {
|
|
1698
|
+
const p = c !== void 0 && l <= 0 ? A : l, f = c !== void 0 ? `${t}::${s}::#${c}` : this.fingerprint(t, s, n);
|
|
1699
|
+
if (this.shouldDedupe(f, p))
|
|
1700
|
+
return S;
|
|
1353
1701
|
}
|
|
1354
|
-
const
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1702
|
+
const i = r?.id ?? this.idFactory(), a = this.currentEvent ?? e, u = a === null ? 0 : a.depth + 1;
|
|
1703
|
+
if (a !== null && u > this.maxReduceDepth)
|
|
1704
|
+
return this.reportCascade(
|
|
1705
|
+
"maxReduceDepth",
|
|
1706
|
+
this.maxReduceDepth,
|
|
1707
|
+
{
|
|
1708
|
+
channel: t,
|
|
1709
|
+
type: s,
|
|
1710
|
+
payload: n,
|
|
1711
|
+
id: i,
|
|
1712
|
+
...r?.meta !== void 0 ? { meta: r.meta } : {},
|
|
1713
|
+
parentId: a.id,
|
|
1714
|
+
depth: u
|
|
1715
|
+
},
|
|
1716
|
+
u,
|
|
1717
|
+
a.chain
|
|
1718
|
+
), S;
|
|
1719
|
+
let d;
|
|
1720
|
+
const h = new Promise((p) => {
|
|
1721
|
+
d = p;
|
|
1358
1722
|
});
|
|
1359
1723
|
return this.reduceQueue.push({
|
|
1360
|
-
channel:
|
|
1361
|
-
type:
|
|
1724
|
+
channel: t,
|
|
1725
|
+
type: s,
|
|
1362
1726
|
payload: n,
|
|
1363
|
-
id:
|
|
1364
|
-
meta:
|
|
1365
|
-
resolve:
|
|
1366
|
-
|
|
1727
|
+
id: i,
|
|
1728
|
+
meta: r?.meta,
|
|
1729
|
+
resolve: d,
|
|
1730
|
+
// Only carried for caused events, so a root event's object stays byte-identical to one
|
|
1731
|
+
// built before causality existed — the same rule `meta` follows.
|
|
1732
|
+
...a !== null ? { parentId: a.id, depth: u, chain: a.chain } : {}
|
|
1733
|
+
}), this.drainReduce(), h;
|
|
1367
1734
|
}
|
|
1368
1735
|
/**
|
|
1369
1736
|
* Drains the reduce queue **synchronously**. For each event it runs middleware,
|
|
@@ -1377,33 +1744,50 @@ class $ {
|
|
|
1377
1744
|
*/
|
|
1378
1745
|
drainReduce() {
|
|
1379
1746
|
if (!this.isReducing) {
|
|
1380
|
-
this.isReducing = !0;
|
|
1747
|
+
this.isReducing = !0, this.transitionsThisDrain = 0;
|
|
1381
1748
|
try {
|
|
1382
1749
|
for (; this.reduceQueue.length > 0; ) {
|
|
1383
|
-
const { channel:
|
|
1384
|
-
channel:
|
|
1385
|
-
type:
|
|
1750
|
+
const e = this.reduceQueue.shift(), { channel: t, type: s, payload: n, id: r, meta: c, resolve: l, parentId: i, depth: a, chain: u } = e, d = {
|
|
1751
|
+
channel: t,
|
|
1752
|
+
type: s,
|
|
1386
1753
|
payload: n,
|
|
1387
|
-
id:
|
|
1388
|
-
...
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1754
|
+
id: r,
|
|
1755
|
+
...c !== void 0 ? { meta: c } : {},
|
|
1756
|
+
...i !== void 0 ? { parentId: i, depth: a } : {}
|
|
1757
|
+
};
|
|
1758
|
+
if (i !== void 0 && ++this.transitionsThisDrain > this.maxTransitionsPerDrain) {
|
|
1759
|
+
this.reportCascade(
|
|
1760
|
+
"maxTransitionsPerDrain",
|
|
1761
|
+
this.maxTransitionsPerDrain,
|
|
1762
|
+
d,
|
|
1763
|
+
a,
|
|
1764
|
+
u
|
|
1765
|
+
), l(S);
|
|
1766
|
+
continue;
|
|
1767
|
+
}
|
|
1768
|
+
this.currentEvent = {
|
|
1769
|
+
id: r,
|
|
1770
|
+
depth: a ?? 0,
|
|
1771
|
+
chain: [...u ?? [], r].slice(-z)
|
|
1772
|
+
};
|
|
1773
|
+
const h = this.instrumentObservers.size > 0, p = h ? this.state : void 0, f = h ? [] : void 0;
|
|
1774
|
+
f !== void 0 && (this.changedPathSink = f);
|
|
1775
|
+
const m = h ? _() : 0;
|
|
1776
|
+
let y = S;
|
|
1393
1777
|
try {
|
|
1394
|
-
|
|
1395
|
-
} catch (
|
|
1396
|
-
console.error("Emit reduce error:",
|
|
1778
|
+
y = this.applyEventSync(d);
|
|
1779
|
+
} catch (g) {
|
|
1780
|
+
console.error("Emit reduce error:", g);
|
|
1397
1781
|
} finally {
|
|
1398
|
-
|
|
1782
|
+
h && (this.changedPathSink = null), this.currentEvent = null;
|
|
1399
1783
|
}
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
), this.runEventEffects(
|
|
1784
|
+
h && this.emitInstrumentation(
|
|
1785
|
+
d,
|
|
1786
|
+
y,
|
|
1787
|
+
f ?? [],
|
|
1788
|
+
p,
|
|
1789
|
+
_() - m
|
|
1790
|
+
), this.runEventEffects(d, y, l);
|
|
1407
1791
|
}
|
|
1408
1792
|
} finally {
|
|
1409
1793
|
this.isReducing = !1;
|
|
@@ -1421,32 +1805,45 @@ class $ {
|
|
|
1421
1805
|
* @internal
|
|
1422
1806
|
*/
|
|
1423
1807
|
applyEventSync(e) {
|
|
1424
|
-
for (const
|
|
1425
|
-
const
|
|
1426
|
-
if (!
|
|
1427
|
-
const
|
|
1808
|
+
for (const c of this.middleware) {
|
|
1809
|
+
const l = se(c);
|
|
1810
|
+
if (!k(l, e)) continue;
|
|
1811
|
+
const i = ne(c);
|
|
1428
1812
|
let a;
|
|
1429
1813
|
try {
|
|
1430
|
-
a =
|
|
1814
|
+
a = i(this.state, e, this.emit), process.env.NODE_ENV !== "production" && typeof a?.then == "function" && console.error(
|
|
1431
1815
|
`[yoltra] Middleware for "${e.channel}/${e.type}" returned a Promise. Middleware is synchronous: a Promise is truthy, so this event was allowed without waiting and a "return false" inside it can never veto. Do the check synchronously, and put anything that must await in an effect.`
|
|
1432
1816
|
);
|
|
1433
|
-
} catch (
|
|
1434
|
-
console.error("Middleware error:",
|
|
1817
|
+
} catch (u) {
|
|
1818
|
+
console.error("Middleware error:", u), a = !1;
|
|
1435
1819
|
}
|
|
1436
1820
|
if (!a)
|
|
1437
|
-
return this.notifyEventSubscribers(e, "uncommitted"),
|
|
1821
|
+
return this.notifyEventSubscribers(e, "uncommitted"), S;
|
|
1438
1822
|
}
|
|
1439
|
-
const t =
|
|
1440
|
-
this.
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1823
|
+
const t = [];
|
|
1824
|
+
this.stagingSink = t;
|
|
1825
|
+
let s = null, n = "";
|
|
1826
|
+
try {
|
|
1827
|
+
this.reducerBus.emit(
|
|
1828
|
+
e.channel,
|
|
1829
|
+
e.type,
|
|
1830
|
+
e.payload,
|
|
1831
|
+
e
|
|
1832
|
+
), s = this.stagedRejection, n = this.stagedRejectedBy;
|
|
1833
|
+
for (const [c, l] of this.patternReducers) {
|
|
1834
|
+
if (s !== null) break;
|
|
1835
|
+
if (k(l, e)) {
|
|
1836
|
+
const i = this.stageSliceGuarded(c, e, t);
|
|
1837
|
+
i !== null && (s = i, n = c);
|
|
1838
|
+
}
|
|
1839
|
+
}
|
|
1840
|
+
} finally {
|
|
1841
|
+
this.stagingSink = null, this.stagedRejection = null, this.stagedRejectedBy = "";
|
|
1842
|
+
}
|
|
1843
|
+
if (s !== null)
|
|
1844
|
+
return this.onRejected?.(s, e, n), this.notifyEventSubscribers(e, "committed"), { committed: !0, written: !1, rejected: s };
|
|
1845
|
+
const r = this.commitStaged(t, e);
|
|
1846
|
+
return this.notifyEventSubscribers(e, "committed"), r && (this.notifyEventSubscribers(e, "written"), this.listeners.forEach((c) => c())), r ? ce : oe;
|
|
1450
1847
|
}
|
|
1451
1848
|
/**
|
|
1452
1849
|
* Runs a single committed event's effects as an **independent async task**,
|
|
@@ -1456,14 +1853,14 @@ class $ {
|
|
|
1456
1853
|
*
|
|
1457
1854
|
* @internal
|
|
1458
1855
|
*/
|
|
1459
|
-
async runEventEffects(e, t,
|
|
1856
|
+
async runEventEffects(e, t, s) {
|
|
1460
1857
|
this.inFlightEffects++;
|
|
1461
1858
|
try {
|
|
1462
|
-
t && await this.notifyEffects(e);
|
|
1463
|
-
} catch (
|
|
1464
|
-
console.error("Effect error:",
|
|
1859
|
+
t.committed && await this.notifyEffects(e);
|
|
1860
|
+
} catch (n) {
|
|
1861
|
+
console.error("Effect error:", n);
|
|
1465
1862
|
} finally {
|
|
1466
|
-
this.inFlightEffects--,
|
|
1863
|
+
this.inFlightEffects--, s(t);
|
|
1467
1864
|
}
|
|
1468
1865
|
}
|
|
1469
1866
|
/**
|
|
@@ -1479,16 +1876,16 @@ class $ {
|
|
|
1479
1876
|
/**
|
|
1480
1877
|
* Builds an {@link InstrumentedEvent} from the reduce result and notifies
|
|
1481
1878
|
* observers. `changedPaths` are the exact slice-prefixed leaf paths recorded
|
|
1482
|
-
* by {@link
|
|
1879
|
+
* by {@link commitStaged} during this reduce, so DevTools patches need no
|
|
1483
1880
|
* re-diff.
|
|
1484
1881
|
*
|
|
1485
1882
|
* @internal
|
|
1486
1883
|
*/
|
|
1487
|
-
emitInstrumentation(e, t,
|
|
1488
|
-
const
|
|
1489
|
-
for (const
|
|
1490
|
-
|
|
1491
|
-
const
|
|
1884
|
+
emitInstrumentation(e, t, s, n, r) {
|
|
1885
|
+
const c = {}, l = {};
|
|
1886
|
+
for (const a of s)
|
|
1887
|
+
c[a] = this.getAtPath(n, a), l[a] = this.getAtPath(this.state, a);
|
|
1888
|
+
const i = {
|
|
1492
1889
|
event: {
|
|
1493
1890
|
id: e.id,
|
|
1494
1891
|
channel: e.channel,
|
|
@@ -1498,17 +1895,20 @@ class $ {
|
|
|
1498
1895
|
// byte-identical to the pre-`meta` shape.
|
|
1499
1896
|
...e.meta !== void 0 ? { meta: e.meta } : {}
|
|
1500
1897
|
},
|
|
1501
|
-
committed: t,
|
|
1502
|
-
changedPaths:
|
|
1503
|
-
prevValues:
|
|
1504
|
-
nextValues:
|
|
1505
|
-
reduceTimeMs:
|
|
1898
|
+
committed: t.committed,
|
|
1899
|
+
changedPaths: s,
|
|
1900
|
+
prevValues: c,
|
|
1901
|
+
nextValues: l,
|
|
1902
|
+
reduceTimeMs: r,
|
|
1903
|
+
// Present only when a reducer refused, so an observer can tell a refusal from a veto —
|
|
1904
|
+
// identical in state, entirely different in cause.
|
|
1905
|
+
...t.rejected !== void 0 ? { rejected: t.rejected } : {}
|
|
1506
1906
|
};
|
|
1507
|
-
for (const
|
|
1907
|
+
for (const a of [...this.instrumentObservers])
|
|
1508
1908
|
try {
|
|
1509
|
-
|
|
1510
|
-
} catch (
|
|
1511
|
-
console.error("Instrumentation observer error:",
|
|
1909
|
+
a(i);
|
|
1910
|
+
} catch (u) {
|
|
1911
|
+
console.error("Instrumentation observer error:", u);
|
|
1512
1912
|
}
|
|
1513
1913
|
}
|
|
1514
1914
|
/**
|
|
@@ -1539,8 +1939,13 @@ class $ {
|
|
|
1539
1939
|
*
|
|
1540
1940
|
* @public
|
|
1541
1941
|
*/
|
|
1542
|
-
connect(e, t) {
|
|
1543
|
-
|
|
1942
|
+
connect(e, t, s) {
|
|
1943
|
+
const n = this.connectorBus.on(e.reducer, e.property, t);
|
|
1944
|
+
if (s?.immediate === !0) {
|
|
1945
|
+
const r = this.state[e.reducer], c = e.property.includes("*") ? "" : e.property;
|
|
1946
|
+
t({ oldValue: void 0, newValue: this.getAtPath(r, c), path: c });
|
|
1947
|
+
}
|
|
1948
|
+
return n;
|
|
1544
1949
|
}
|
|
1545
1950
|
/**
|
|
1546
1951
|
* Subscribe to events by channel and type.
|
|
@@ -1588,11 +1993,11 @@ class $ {
|
|
|
1588
1993
|
*
|
|
1589
1994
|
* @public
|
|
1590
1995
|
*/
|
|
1591
|
-
onEvent(e, t,
|
|
1592
|
-
const
|
|
1593
|
-
return
|
|
1594
|
-
const
|
|
1595
|
-
|
|
1996
|
+
onEvent(e, t, s, n = "committed") {
|
|
1997
|
+
const r = `${e}::${String(t)}`, c = n === "committed" ? this.committedEventSubscribers : n === "uncommitted" ? this.uncommittedEventSubscribers : n === "written" ? this.writtenEventSubscribers : this.allEventSubscribers;
|
|
1998
|
+
return c.has(r) || c.set(r, /* @__PURE__ */ new Set()), c.get(r).add(s), () => {
|
|
1999
|
+
const l = c.get(r);
|
|
2000
|
+
l && (l.delete(s), l.size === 0 && c.delete(r));
|
|
1596
2001
|
};
|
|
1597
2002
|
}
|
|
1598
2003
|
/**
|
|
@@ -1698,8 +2103,8 @@ class $ {
|
|
|
1698
2103
|
throw new Error(`Reducer ${e} already exists`);
|
|
1699
2104
|
return this.mountSlice(e, t, {
|
|
1700
2105
|
preserveState: !1
|
|
1701
|
-
}), this.listeners.forEach((
|
|
1702
|
-
this.unmountSlice(e, { deleteState: !0 }), this.listeners.forEach((
|
|
2106
|
+
}), this.listeners.forEach((s) => s()), () => {
|
|
2107
|
+
this.unmountSlice(e, { deleteState: !0 }), this.listeners.forEach((s) => s());
|
|
1703
2108
|
};
|
|
1704
2109
|
}
|
|
1705
2110
|
/**
|
|
@@ -1734,30 +2139,118 @@ class $ {
|
|
|
1734
2139
|
*
|
|
1735
2140
|
* @public
|
|
1736
2141
|
*/
|
|
2142
|
+
/**
|
|
2143
|
+
* Sends a request and waits for the reply, correlating the two automatically.
|
|
2144
|
+
*
|
|
2145
|
+
* @typeParam C - Request channel.
|
|
2146
|
+
* @typeParam T - Request type within `C`.
|
|
2147
|
+
* @param channel - Channel to send on.
|
|
2148
|
+
* @param type - Event type to send.
|
|
2149
|
+
* @param payload - The **request** payload. This is what you are sending; what comes back is
|
|
2150
|
+
* described by {@link CallOptions.reply}, not by this.
|
|
2151
|
+
* @param opts - Which replies end the call, and how long to wait. See {@link CallOptions}.
|
|
2152
|
+
* @returns A {@link CallHandle}: `await` it for the terminal reply, or `for await` it for
|
|
2153
|
+
* progress events as they arrive.
|
|
2154
|
+
*
|
|
2155
|
+
* @remarks
|
|
2156
|
+
* Every consumer of an event bus eventually writes request/reply by hand — mint an id,
|
|
2157
|
+
* subscribe, match, time out, unsubscribe — and every one of them writes the same eighty lines
|
|
2158
|
+
* with the same two bugs: the subscription outlives the call, and a responder that forgets to
|
|
2159
|
+
* echo the id produces a timeout with nothing to point at. This is that, once.
|
|
2160
|
+
*
|
|
2161
|
+
* **Correlation is causal.** The store stamps `parentId` on anything emitted while an event is
|
|
2162
|
+
* being handled, so a responder that replies through the `emit` it was handed is already
|
|
2163
|
+
* correlated. There is no id to mint, echo, or forget:
|
|
2164
|
+
*
|
|
2165
|
+
* ```ts
|
|
2166
|
+
* store.registerEffect({
|
|
2167
|
+
* when: { keys: [["rpc", "ask"]] },
|
|
2168
|
+
* effect: async (event, _get, emit) => {
|
|
2169
|
+
* await emit("rpc", "answer", await lookup(event.payload.q));
|
|
2170
|
+
* },
|
|
2171
|
+
* });
|
|
2172
|
+
* ```
|
|
2173
|
+
*
|
|
2174
|
+
* **The reply carries its own discriminant.** A call resolves to the *event*, not the payload,
|
|
2175
|
+
* because a caller often cannot know which kind of reply it will get:
|
|
2176
|
+
*
|
|
2177
|
+
* ```ts
|
|
2178
|
+
* const res = await store.call("rpc", "ask", { q }, { reply: ["rpc", ["answer", "error"]] });
|
|
2179
|
+
* switch (res.type) {
|
|
2180
|
+
* case "answer": return res.payload;
|
|
2181
|
+
* case "error": throw new Error(res.payload.reason);
|
|
2182
|
+
* }
|
|
2183
|
+
* ```
|
|
2184
|
+
*
|
|
2185
|
+
* **Progress streams, with backpressure.** Any correlated event that is not terminal is
|
|
2186
|
+
* progress, and iterating the call consumes it. The producer genuinely waits: `emit` resolves
|
|
2187
|
+
* only once its effects have run, and the collector is an effect that does not return until the
|
|
2188
|
+
* consumer has taken the item. A responder writing `await emit("rpc", "progress", chunk)` is
|
|
2189
|
+
* therefore paced by the reader, with nothing buffering without bound.
|
|
2190
|
+
*
|
|
2191
|
+
* ```ts
|
|
2192
|
+
* const call = store.call("job", "start", { id }, {
|
|
2193
|
+
* reply: ["job", "done"],
|
|
2194
|
+
* highWaterMark: 4,
|
|
2195
|
+
* });
|
|
2196
|
+
* for await (const step of call) await render(step.payload); // producer waits on this
|
|
2197
|
+
* const { payload } = await call;
|
|
2198
|
+
* ```
|
|
2199
|
+
*
|
|
2200
|
+
* Backpressure engages **once you begin iterating**. A call that is only awaited never pulls,
|
|
2201
|
+
* so blocking its producer would deadlock the call itself — progress nobody reads would stop
|
|
2202
|
+
* the terminal event from ever being sent. Un-iterated progress therefore buffers to
|
|
2203
|
+
* `highWaterMark` and is then counted on {@link CallHandle.dropped} rather than blocking.
|
|
2204
|
+
*
|
|
2205
|
+
* **This is a local primitive.**
|
|
2206
|
+
*
|
|
2207
|
+
* @example Timeout is idle, not total
|
|
2208
|
+
* ```ts
|
|
2209
|
+
* // Survives a job that streams for minutes; fails a responder that goes quiet for 5s.
|
|
2210
|
+
* await store.call("job", "start", { id }, { reply: ["job", "done"], timeoutMs: 5_000 });
|
|
2211
|
+
* ```
|
|
2212
|
+
*
|
|
2213
|
+
* @example Cancelling
|
|
2214
|
+
* ```ts
|
|
2215
|
+
* const call = store.call("rpc", "ask", { q }, { reply: ["rpc", "answer"] });
|
|
2216
|
+
* useEffect(() => () => call.cancel("unmounted"), [call]);
|
|
2217
|
+
* ```
|
|
2218
|
+
*
|
|
2219
|
+
* @public
|
|
2220
|
+
*/
|
|
2221
|
+
call(e, t, s, n) {
|
|
2222
|
+
return Z(
|
|
2223
|
+
{ idFactory: this.idFactory, registerEffect: this.registerEffect, emit: this.emit },
|
|
2224
|
+
e,
|
|
2225
|
+
t,
|
|
2226
|
+
s,
|
|
2227
|
+
n
|
|
2228
|
+
);
|
|
2229
|
+
}
|
|
1737
2230
|
registerEffect(e) {
|
|
1738
|
-
const { effect: t, meta:
|
|
1739
|
-
if (
|
|
1740
|
-
const
|
|
1741
|
-
return this.patternEffects.add(
|
|
1742
|
-
this.patternEffects.delete(
|
|
2231
|
+
const { effect: t, meta: s, when: n } = e, r = [];
|
|
2232
|
+
if (s && this.effectMeta.set(t, s), n && ("any" in n && n.any === !0 || "channel" in n || "channels" in n)) {
|
|
2233
|
+
const i = { effect: t, when: n };
|
|
2234
|
+
return this.patternEffects.add(i), () => {
|
|
2235
|
+
this.patternEffects.delete(i);
|
|
1743
2236
|
};
|
|
1744
2237
|
}
|
|
1745
|
-
const
|
|
1746
|
-
if (
|
|
1747
|
-
const
|
|
1748
|
-
return this.patternEffects.add(
|
|
1749
|
-
this.patternEffects.delete(
|
|
2238
|
+
const l = D(e);
|
|
2239
|
+
if (l.length === 0 && !n) {
|
|
2240
|
+
const i = { effect: t, when: { any: !0 } };
|
|
2241
|
+
return this.patternEffects.add(i), () => {
|
|
2242
|
+
this.patternEffects.delete(i);
|
|
1750
2243
|
};
|
|
1751
2244
|
}
|
|
1752
|
-
for (const [
|
|
1753
|
-
const
|
|
1754
|
-
this.effects.has(
|
|
1755
|
-
const
|
|
1756
|
-
|
|
2245
|
+
for (const [i, a] of l) {
|
|
2246
|
+
const u = `${String(i)}::${String(a)}`;
|
|
2247
|
+
this.effects.has(u) || this.effects.set(u, /* @__PURE__ */ new Set()), this.effects.get(u).add(t), r.push(() => {
|
|
2248
|
+
const d = this.effects.get(u);
|
|
2249
|
+
d && (d.delete(t), d.size === 0 && this.effects.delete(u));
|
|
1757
2250
|
});
|
|
1758
2251
|
}
|
|
1759
2252
|
return () => {
|
|
1760
|
-
for (const
|
|
2253
|
+
for (const i of r) i();
|
|
1761
2254
|
};
|
|
1762
2255
|
}
|
|
1763
2256
|
/**
|
|
@@ -1781,15 +2274,15 @@ class $ {
|
|
|
1781
2274
|
*
|
|
1782
2275
|
* @public
|
|
1783
2276
|
*/
|
|
1784
|
-
onEffect(e, t,
|
|
1785
|
-
const
|
|
1786
|
-
if (
|
|
1787
|
-
const
|
|
1788
|
-
return
|
|
2277
|
+
onEffect(e, t, s) {
|
|
2278
|
+
const n = async (r, c, l) => {
|
|
2279
|
+
if (r.channel !== e || r.type !== t) return;
|
|
2280
|
+
const i = r;
|
|
2281
|
+
return s(i.payload, c, l, i);
|
|
1789
2282
|
};
|
|
1790
2283
|
return this.registerEffect({
|
|
1791
2284
|
when: { keys: [[e, t]] },
|
|
1792
|
-
effect:
|
|
2285
|
+
effect: n
|
|
1793
2286
|
});
|
|
1794
2287
|
}
|
|
1795
2288
|
/**
|
|
@@ -1851,11 +2344,11 @@ class $ {
|
|
|
1851
2344
|
* @public
|
|
1852
2345
|
*/
|
|
1853
2346
|
replaceReducers(e, t = {}) {
|
|
1854
|
-
const
|
|
1855
|
-
for (const
|
|
1856
|
-
|
|
1857
|
-
for (const [
|
|
1858
|
-
|
|
2347
|
+
const s = t.preserveState !== !1, n = new Set(Object.keys(this.reducers)), r = Object.entries(e), c = new Set(r.map(([l]) => l));
|
|
2348
|
+
for (const l of n)
|
|
2349
|
+
c.has(l) || this.unmountSlice(l, { deleteState: !0 });
|
|
2350
|
+
for (const [l, i] of r)
|
|
2351
|
+
n.has(l) ? (this.unmountSlice(l, { deleteState: !1 }), this.mountSlice(l, i, { preserveState: s })) : this.mountSlice(l, i, { preserveState: !1 });
|
|
1859
2352
|
}
|
|
1860
2353
|
/**
|
|
1861
2354
|
* Convenience API to replace **any subset** of store parts (HMR patterns).
|
|
@@ -1887,34 +2380,36 @@ class $ {
|
|
|
1887
2380
|
*
|
|
1888
2381
|
* @internal
|
|
1889
2382
|
*/
|
|
1890
|
-
mountSlice(e, t,
|
|
1891
|
-
const
|
|
1892
|
-
if (this.reducers[e] = new
|
|
2383
|
+
mountSlice(e, t, s) {
|
|
2384
|
+
const n = e, { reducer: r, state: c, when: l } = t;
|
|
2385
|
+
if (this.reducers[e] = new L(r), (!s.preserveState || this.state[n] === void 0) && (this.state = {
|
|
1893
2386
|
...this.state,
|
|
1894
|
-
[
|
|
1895
|
-
}),
|
|
1896
|
-
this.patternReducers.set(e,
|
|
2387
|
+
[n]: R(re(n, c))
|
|
2388
|
+
}), l && ("any" in l && l.any === !0 || "channel" in l || "channels" in l)) {
|
|
2389
|
+
this.patternReducers.set(e, l), this.sliceUnsubs.set(n, []);
|
|
1897
2390
|
return;
|
|
1898
2391
|
}
|
|
1899
|
-
const
|
|
1900
|
-
if (
|
|
1901
|
-
this.patternReducers.set(e, { any: !0 }), this.sliceUnsubs.set(
|
|
2392
|
+
const a = D(t);
|
|
2393
|
+
if (a.length === 0 && !l) {
|
|
2394
|
+
this.patternReducers.set(e, { any: !0 }), this.sliceUnsubs.set(n, []);
|
|
1902
2395
|
return;
|
|
1903
2396
|
}
|
|
1904
|
-
const
|
|
1905
|
-
for (const [
|
|
1906
|
-
const
|
|
1907
|
-
const
|
|
1908
|
-
channel:
|
|
1909
|
-
type:
|
|
1910
|
-
payload:
|
|
2397
|
+
const u = [];
|
|
2398
|
+
for (const [d, h] of a) {
|
|
2399
|
+
const p = this.reducerBus.on(d, h, (f, m) => {
|
|
2400
|
+
const y = m ?? {
|
|
2401
|
+
channel: d,
|
|
2402
|
+
type: h,
|
|
2403
|
+
payload: f,
|
|
1911
2404
|
id: this.idFactory()
|
|
1912
2405
|
};
|
|
1913
|
-
this.
|
|
2406
|
+
if (this.stagingSink === null) return;
|
|
2407
|
+
const g = this.stageSliceGuarded(e, y, this.stagingSink);
|
|
2408
|
+
g !== null && this.stagedRejection === null && (this.stagedRejection = g, this.stagedRejectedBy = e);
|
|
1914
2409
|
});
|
|
1915
|
-
|
|
2410
|
+
u.push(p);
|
|
1916
2411
|
}
|
|
1917
|
-
this.sliceUnsubs.set(
|
|
2412
|
+
this.sliceUnsubs.set(n, u);
|
|
1918
2413
|
}
|
|
1919
2414
|
/**
|
|
1920
2415
|
* Unmounts a slice: disposes reducer-bus listeners, removes reducer,
|
|
@@ -1926,38 +2421,22 @@ class $ {
|
|
|
1926
2421
|
* @internal
|
|
1927
2422
|
*/
|
|
1928
2423
|
unmountSlice(e, t) {
|
|
1929
|
-
const
|
|
2424
|
+
const s = e;
|
|
1930
2425
|
this.patternReducers.delete(e);
|
|
1931
|
-
const
|
|
1932
|
-
if (
|
|
1933
|
-
for (const
|
|
2426
|
+
const n = this.sliceUnsubs.get(s);
|
|
2427
|
+
if (n) {
|
|
2428
|
+
for (const r of n)
|
|
1934
2429
|
try {
|
|
1935
|
-
|
|
1936
|
-
} catch (
|
|
1937
|
-
console.error(`[Store error]: ${
|
|
2430
|
+
r();
|
|
2431
|
+
} catch (c) {
|
|
2432
|
+
console.error(`[Store error]: ${c}`);
|
|
1938
2433
|
}
|
|
1939
|
-
this.sliceUnsubs.delete(
|
|
2434
|
+
this.sliceUnsubs.delete(s);
|
|
1940
2435
|
}
|
|
1941
2436
|
if (delete this.reducers[e], t.deleteState) {
|
|
1942
|
-
const { [
|
|
1943
|
-
this.state =
|
|
1944
|
-
}
|
|
1945
|
-
}
|
|
1946
|
-
/**
|
|
1947
|
-
* Normalizes event targeting from `when` to an array of EventKeys.
|
|
1948
|
-
*
|
|
1949
|
-
* @param spec - Object with an optional `when` matcher.
|
|
1950
|
-
* @returns Array of `[channel, type]` pairs.
|
|
1951
|
-
*
|
|
1952
|
-
* @internal
|
|
1953
|
-
*/
|
|
1954
|
-
normalizeEventKeys(e) {
|
|
1955
|
-
if (e.when) {
|
|
1956
|
-
const t = e.when;
|
|
1957
|
-
if ("keys" in t)
|
|
1958
|
-
return t.keys;
|
|
2437
|
+
const { [s]: r, ...c } = this.state;
|
|
2438
|
+
this.state = c;
|
|
1959
2439
|
}
|
|
1960
|
-
return [];
|
|
1961
2440
|
}
|
|
1962
2441
|
/**
|
|
1963
2442
|
* Reads a dotted path from an object (supports numeric array indices via string keys).
|
|
@@ -1966,17 +2445,14 @@ class $ {
|
|
|
1966
2445
|
* @param path - Dotted path; leading dot is ignored.
|
|
1967
2446
|
* @returns The value at the path, or `undefined`.
|
|
1968
2447
|
*
|
|
2448
|
+
* @remarks
|
|
2449
|
+
* A member rather than a bare import: a test replaces this on the instance to count how many
|
|
2450
|
+
* walks describing a change costs, which only works while the callers go through `this`.
|
|
2451
|
+
*
|
|
1969
2452
|
* @internal
|
|
1970
2453
|
*/
|
|
1971
2454
|
getAtPath(e, t) {
|
|
1972
|
-
|
|
1973
|
-
const s = (t[0] === "." ? t.slice(1) : t).split(".");
|
|
1974
|
-
let i = e;
|
|
1975
|
-
for (const d of s) {
|
|
1976
|
-
if (i == null) return;
|
|
1977
|
-
i = i[d];
|
|
1978
|
-
}
|
|
1979
|
-
return i;
|
|
2455
|
+
return ee(e, t);
|
|
1980
2456
|
}
|
|
1981
2457
|
/**
|
|
1982
2458
|
* Builds ancestor paths for a dotted path.
|
|
@@ -1994,268 +2470,259 @@ class $ {
|
|
|
1994
2470
|
* @public
|
|
1995
2471
|
*/
|
|
1996
2472
|
static buildAncestorPaths(e) {
|
|
1997
|
-
|
|
1998
|
-
const n = (e[0] === "." ? e.slice(1) : e).split("."), s = [];
|
|
1999
|
-
for (let i = 0; i < n.length; i++)
|
|
2000
|
-
s.push(n.slice(0, i + 1).join("."));
|
|
2001
|
-
return s;
|
|
2473
|
+
return te(e);
|
|
2002
2474
|
}
|
|
2003
2475
|
}
|
|
2004
|
-
function
|
|
2005
|
-
return new
|
|
2006
|
-
|
|
2476
|
+
function he(o) {
|
|
2477
|
+
return new x({
|
|
2478
|
+
...o,
|
|
2007
2479
|
reducer: o.reducer ?? {},
|
|
2008
2480
|
middleware: o.middleware ?? [],
|
|
2009
|
-
effects: o.effects ?? []
|
|
2010
|
-
dedupWindowMs: o.dedupWindowMs,
|
|
2011
|
-
idFactory: o.idFactory,
|
|
2012
|
-
devtools: o.devtools,
|
|
2013
|
-
onEffectError: o.onEffectError,
|
|
2014
|
-
onReducerError: o.onReducerError
|
|
2481
|
+
effects: o.effects ?? []
|
|
2015
2482
|
});
|
|
2016
2483
|
}
|
|
2017
|
-
const
|
|
2018
|
-
function
|
|
2484
|
+
const pe = (o) => (e, t) => t.map((s) => [e, s]), me = () => (o) => o, j = /* @__PURE__ */ new Set();
|
|
2485
|
+
function ae(o) {
|
|
2019
2486
|
const e = String(o);
|
|
2020
|
-
|
|
2487
|
+
j.has(e) || (j.add(e), console.warn(
|
|
2021
2488
|
`[yoltra] Entity id "${e}" contains a dot. Paths are dotted, so a subscription to "entities.${e}" is indistinguishable from one to a nested object of the same name. Use ids without dots.`
|
|
2022
2489
|
));
|
|
2023
2490
|
}
|
|
2024
|
-
function
|
|
2491
|
+
function le(o, e) {
|
|
2025
2492
|
if (o.length !== e.length) return e;
|
|
2026
2493
|
for (let t = 0; t < o.length; t++)
|
|
2027
2494
|
if (o[t] !== e[t]) return e;
|
|
2028
2495
|
return o;
|
|
2029
2496
|
}
|
|
2030
|
-
function
|
|
2031
|
-
const e = o.selectId ?? ((
|
|
2032
|
-
if (t === void 0) return
|
|
2033
|
-
const
|
|
2034
|
-
const
|
|
2035
|
-
return
|
|
2497
|
+
function ye(o = {}) {
|
|
2498
|
+
const e = o.selectId ?? ((i) => i.id), { sortComparer: t } = o, s = (i, a) => {
|
|
2499
|
+
if (t === void 0) return a;
|
|
2500
|
+
const u = [...a].sort((d, h) => {
|
|
2501
|
+
const p = i.entities[d], f = i.entities[h];
|
|
2502
|
+
return p === void 0 || f === void 0 ? 0 : t(p, f);
|
|
2036
2503
|
});
|
|
2037
|
-
return
|
|
2038
|
-
},
|
|
2039
|
-
const
|
|
2040
|
-
return { ...
|
|
2041
|
-
},
|
|
2042
|
-
let
|
|
2043
|
-
for (const
|
|
2044
|
-
const
|
|
2045
|
-
process.env.NODE_ENV !== "production" && String(
|
|
2046
|
-
const m = (
|
|
2047
|
-
if (m !== void 0 &&
|
|
2048
|
-
const
|
|
2049
|
-
|
|
2504
|
+
return le(a, u);
|
|
2505
|
+
}, n = (i, a, u) => {
|
|
2506
|
+
const d = { ...i, entities: a, ids: u };
|
|
2507
|
+
return { ...d, ids: s(d, u) };
|
|
2508
|
+
}, r = (i, a, u) => {
|
|
2509
|
+
let d = null, h = null;
|
|
2510
|
+
for (const p of a) {
|
|
2511
|
+
const f = e(p);
|
|
2512
|
+
process.env.NODE_ENV !== "production" && String(f).includes(".") && ae(f);
|
|
2513
|
+
const m = (d ?? i.entities)[f];
|
|
2514
|
+
if (m !== void 0 && u === "add") continue;
|
|
2515
|
+
const y = m !== void 0 && u === "upsert" ? { ...m, ...p } : p;
|
|
2516
|
+
d ??= { ...i.entities }, d[f] = y, m === void 0 && (h ??= [...i.ids], h.push(f));
|
|
2050
2517
|
}
|
|
2051
|
-
return
|
|
2052
|
-
},
|
|
2053
|
-
let
|
|
2054
|
-
for (const { id:
|
|
2055
|
-
const
|
|
2056
|
-
|
|
2518
|
+
return d === null ? i : n(i, d, h ?? i.ids);
|
|
2519
|
+
}, c = (i, a) => {
|
|
2520
|
+
let u = null;
|
|
2521
|
+
for (const { id: d, changes: h } of a) {
|
|
2522
|
+
const p = (u ?? i.entities)[d];
|
|
2523
|
+
p !== void 0 && (u ??= { ...i.entities }, u[d] = { ...p, ...h });
|
|
2057
2524
|
}
|
|
2058
|
-
return
|
|
2059
|
-
},
|
|
2060
|
-
const
|
|
2061
|
-
if (
|
|
2062
|
-
const
|
|
2063
|
-
for (const
|
|
2064
|
-
return
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2525
|
+
return u === null ? i : n(i, u, i.ids);
|
|
2526
|
+
}, l = (i, a) => {
|
|
2527
|
+
const u = new Set(a.filter((h) => i.entities[h] !== void 0));
|
|
2528
|
+
if (u.size === 0) return i;
|
|
2529
|
+
const d = { ...i.entities };
|
|
2530
|
+
for (const h of u) delete d[h];
|
|
2531
|
+
return n(
|
|
2532
|
+
i,
|
|
2533
|
+
d,
|
|
2534
|
+
i.ids.filter((h) => !u.has(h))
|
|
2068
2535
|
);
|
|
2069
2536
|
};
|
|
2070
2537
|
return {
|
|
2071
|
-
getInitialState(
|
|
2072
|
-
const
|
|
2073
|
-
return
|
|
2538
|
+
getInitialState(i) {
|
|
2539
|
+
const a = { ids: [], entities: {} };
|
|
2540
|
+
return i === void 0 ? a : { ...a, ...i };
|
|
2074
2541
|
},
|
|
2075
|
-
addOne: (
|
|
2076
|
-
addMany: (
|
|
2077
|
-
setOne: (
|
|
2078
|
-
setMany: (
|
|
2079
|
-
setAll: (
|
|
2080
|
-
const
|
|
2081
|
-
for (const
|
|
2082
|
-
const
|
|
2083
|
-
|
|
2542
|
+
addOne: (i, a) => r(i, [a], "add"),
|
|
2543
|
+
addMany: (i, a) => r(i, a, "add"),
|
|
2544
|
+
setOne: (i, a) => r(i, [a], "set"),
|
|
2545
|
+
setMany: (i, a) => r(i, a, "set"),
|
|
2546
|
+
setAll: (i, a) => {
|
|
2547
|
+
const u = {}, d = [];
|
|
2548
|
+
for (const h of a) {
|
|
2549
|
+
const p = e(h);
|
|
2550
|
+
u[p] === void 0 && d.push(p), u[p] = h;
|
|
2084
2551
|
}
|
|
2085
|
-
return
|
|
2552
|
+
return n(i, u, d);
|
|
2086
2553
|
},
|
|
2087
|
-
updateOne: (
|
|
2088
|
-
updateMany: (
|
|
2089
|
-
upsertOne: (
|
|
2090
|
-
upsertMany: (
|
|
2091
|
-
removeOne: (
|
|
2092
|
-
removeMany: (
|
|
2093
|
-
removeAll: (
|
|
2094
|
-
selectIds: (
|
|
2095
|
-
selectEntities: (
|
|
2096
|
-
selectAll: (
|
|
2097
|
-
selectById: (
|
|
2098
|
-
selectTotal: (
|
|
2554
|
+
updateOne: (i, a) => c(i, [a]),
|
|
2555
|
+
updateMany: (i, a) => c(i, a),
|
|
2556
|
+
upsertOne: (i, a) => r(i, [a], "upsert"),
|
|
2557
|
+
upsertMany: (i, a) => r(i, a, "upsert"),
|
|
2558
|
+
removeOne: (i, a) => l(i, [a]),
|
|
2559
|
+
removeMany: (i, a) => l(i, a),
|
|
2560
|
+
removeAll: (i) => i.ids.length === 0 ? i : n(i, {}, []),
|
|
2561
|
+
selectIds: (i) => i.ids,
|
|
2562
|
+
selectEntities: (i) => i.entities,
|
|
2563
|
+
selectAll: (i) => i.ids.map((a) => i.entities[a]),
|
|
2564
|
+
selectById: (i, a) => i.entities[a],
|
|
2565
|
+
selectTotal: (i) => i.ids.length,
|
|
2099
2566
|
idsPath: "ids",
|
|
2100
|
-
pathTo: (
|
|
2101
|
-
anyField: (
|
|
2567
|
+
pathTo: (i, a) => a === void 0 ? `entities.${i}` : `entities.${i}.${a}`,
|
|
2568
|
+
anyField: (i) => `entities.*.${i}`
|
|
2102
2569
|
};
|
|
2103
2570
|
}
|
|
2104
|
-
const
|
|
2105
|
-
function
|
|
2106
|
-
const t = e.maxNodes ?? 1e5,
|
|
2107
|
-
let
|
|
2108
|
-
function
|
|
2109
|
-
if (
|
|
2110
|
-
return
|
|
2111
|
-
switch (typeof
|
|
2571
|
+
const w = "$yoltra";
|
|
2572
|
+
function H(o, e = {}) {
|
|
2573
|
+
const t = e.maxNodes ?? 1e5, s = e.sanitize, n = [], r = /* @__PURE__ */ new Map();
|
|
2574
|
+
let c = 0, l = !1;
|
|
2575
|
+
function i(u, d) {
|
|
2576
|
+
if (s !== void 0 && (u = s(d, u)), c += 1, c > t)
|
|
2577
|
+
return l = !0, { [w]: "unsupported", kind: "truncated" };
|
|
2578
|
+
switch (typeof u) {
|
|
2112
2579
|
case "undefined":
|
|
2113
|
-
return { [
|
|
2580
|
+
return { [w]: "undefined" };
|
|
2114
2581
|
case "bigint":
|
|
2115
|
-
return { [
|
|
2582
|
+
return { [w]: "bigint", value: u.toString() };
|
|
2116
2583
|
case "number":
|
|
2117
|
-
return Number.isNaN(
|
|
2584
|
+
return Number.isNaN(u) ? { [w]: "nan" } : u === 1 / 0 ? { [w]: "infinity", sign: 1 } : u === -1 / 0 ? { [w]: "infinity", sign: -1 } : u;
|
|
2118
2585
|
case "function":
|
|
2119
2586
|
case "symbol":
|
|
2120
|
-
return
|
|
2587
|
+
return n.push(d), { [w]: "unsupported", kind: typeof u };
|
|
2121
2588
|
case "string":
|
|
2122
2589
|
case "boolean":
|
|
2123
|
-
return
|
|
2590
|
+
return u;
|
|
2124
2591
|
}
|
|
2125
|
-
if (
|
|
2126
|
-
const
|
|
2127
|
-
if (
|
|
2128
|
-
if (
|
|
2129
|
-
return { [
|
|
2130
|
-
if (
|
|
2131
|
-
return { [
|
|
2132
|
-
if (
|
|
2133
|
-
return { [
|
|
2134
|
-
if (
|
|
2592
|
+
if (u === null) return null;
|
|
2593
|
+
const h = u, p = r.get(h);
|
|
2594
|
+
if (p !== void 0) return { [w]: "ref", path: p };
|
|
2595
|
+
if (r.set(h, d), u instanceof Date)
|
|
2596
|
+
return { [w]: "date", iso: u.toISOString() };
|
|
2597
|
+
if (u instanceof RegExp)
|
|
2598
|
+
return { [w]: "regexp", source: u.source, flags: u.flags };
|
|
2599
|
+
if (u instanceof Error)
|
|
2600
|
+
return { [w]: "error", name: u.name, message: u.message };
|
|
2601
|
+
if (u instanceof Map) {
|
|
2135
2602
|
const m = [];
|
|
2136
|
-
let
|
|
2137
|
-
for (const [
|
|
2138
|
-
m.push([
|
|
2139
|
-
return { [
|
|
2603
|
+
let y = 0;
|
|
2604
|
+
for (const [g, $] of u)
|
|
2605
|
+
m.push([i(g, `${d}/@k${y}`), i($, `${d}/${y}`)]), y += 1;
|
|
2606
|
+
return { [w]: "map", entries: m };
|
|
2140
2607
|
}
|
|
2141
|
-
if (
|
|
2608
|
+
if (u instanceof Set) {
|
|
2142
2609
|
const m = [];
|
|
2143
|
-
let
|
|
2144
|
-
for (const
|
|
2145
|
-
m.push(
|
|
2146
|
-
return { [
|
|
2610
|
+
let y = 0;
|
|
2611
|
+
for (const g of u)
|
|
2612
|
+
m.push(i(g, `${d}/${y}`)), y += 1;
|
|
2613
|
+
return { [w]: "set", values: m };
|
|
2147
2614
|
}
|
|
2148
|
-
if (Array.isArray(
|
|
2149
|
-
return
|
|
2150
|
-
const
|
|
2151
|
-
for (const [m,
|
|
2152
|
-
|
|
2153
|
-
return
|
|
2154
|
-
}
|
|
2155
|
-
return { value:
|
|
2615
|
+
if (Array.isArray(u))
|
|
2616
|
+
return u.map((m, y) => i(m, `${d}/${y}`));
|
|
2617
|
+
const f = {};
|
|
2618
|
+
for (const [m, y] of Object.entries(u))
|
|
2619
|
+
f[m] = i(y, `${d}/${F(m)}`);
|
|
2620
|
+
return w in f ? { [w]: "escaped", value: f } : f;
|
|
2621
|
+
}
|
|
2622
|
+
return { value: i(o, ""), report: { truncated: l, unsupported: n } };
|
|
2156
2623
|
}
|
|
2157
|
-
function
|
|
2624
|
+
function ue(o) {
|
|
2158
2625
|
const e = /* @__PURE__ */ new Map(), t = [];
|
|
2159
|
-
function
|
|
2160
|
-
if (
|
|
2161
|
-
if (Array.isArray(
|
|
2162
|
-
const
|
|
2163
|
-
return e.set(
|
|
2164
|
-
if (
|
|
2165
|
-
t.push({ target:
|
|
2626
|
+
function s(c, l) {
|
|
2627
|
+
if (c === null || typeof c != "object") return c;
|
|
2628
|
+
if (Array.isArray(c)) {
|
|
2629
|
+
const a = [];
|
|
2630
|
+
return e.set(l, a), c.forEach((u, d) => {
|
|
2631
|
+
if (N(u)) {
|
|
2632
|
+
t.push({ target: a, key: d, path: u.path }), a[d] = void 0;
|
|
2166
2633
|
return;
|
|
2167
2634
|
}
|
|
2168
|
-
|
|
2169
|
-
}),
|
|
2635
|
+
a[d] = s(u, `${l}/${d}`);
|
|
2636
|
+
}), a;
|
|
2170
2637
|
}
|
|
2171
|
-
if (typeof
|
|
2172
|
-
const
|
|
2173
|
-
switch (
|
|
2638
|
+
if (typeof c[w] == "string") {
|
|
2639
|
+
const a = c;
|
|
2640
|
+
switch (a[w]) {
|
|
2174
2641
|
case "undefined":
|
|
2175
2642
|
return;
|
|
2176
2643
|
case "nan":
|
|
2177
2644
|
return Number.NaN;
|
|
2178
2645
|
case "infinity":
|
|
2179
|
-
return
|
|
2646
|
+
return a.sign === 1 ? 1 / 0 : -1 / 0;
|
|
2180
2647
|
case "bigint":
|
|
2181
|
-
return BigInt(
|
|
2648
|
+
return BigInt(a.value);
|
|
2182
2649
|
case "date":
|
|
2183
|
-
return new Date(
|
|
2650
|
+
return new Date(a.iso);
|
|
2184
2651
|
case "regexp":
|
|
2185
|
-
return new RegExp(
|
|
2652
|
+
return new RegExp(a.source, a.flags);
|
|
2186
2653
|
case "error": {
|
|
2187
|
-
const
|
|
2188
|
-
return
|
|
2654
|
+
const u = new Error(a.message);
|
|
2655
|
+
return u.name = a.name, u;
|
|
2189
2656
|
}
|
|
2190
2657
|
case "unsupported":
|
|
2191
2658
|
return;
|
|
2192
2659
|
case "ref":
|
|
2193
2660
|
return;
|
|
2194
2661
|
case "map": {
|
|
2195
|
-
const
|
|
2196
|
-
return e.set(
|
|
2197
|
-
|
|
2198
|
-
}),
|
|
2662
|
+
const u = /* @__PURE__ */ new Map();
|
|
2663
|
+
return e.set(l, u), a.entries.forEach(([d, h], p) => {
|
|
2664
|
+
u.set(s(d, `${l}/@k${p}`), s(h, `${l}/${p}`));
|
|
2665
|
+
}), u;
|
|
2199
2666
|
}
|
|
2200
2667
|
case "set": {
|
|
2201
|
-
const
|
|
2202
|
-
return e.set(
|
|
2668
|
+
const u = /* @__PURE__ */ new Set();
|
|
2669
|
+
return e.set(l, u), a.values.forEach((d, h) => u.add(s(d, `${l}/${h}`))), u;
|
|
2203
2670
|
}
|
|
2204
2671
|
case "escaped":
|
|
2205
|
-
return
|
|
2672
|
+
return n(a.value, l);
|
|
2206
2673
|
default:
|
|
2207
2674
|
return;
|
|
2208
2675
|
}
|
|
2209
2676
|
}
|
|
2210
|
-
return
|
|
2211
|
-
}
|
|
2212
|
-
function
|
|
2213
|
-
const
|
|
2214
|
-
e.set(
|
|
2215
|
-
for (const [
|
|
2216
|
-
const
|
|
2217
|
-
if (
|
|
2218
|
-
t.push({ target:
|
|
2677
|
+
return n(c, l);
|
|
2678
|
+
}
|
|
2679
|
+
function n(c, l) {
|
|
2680
|
+
const i = {};
|
|
2681
|
+
e.set(l, i);
|
|
2682
|
+
for (const [a, u] of Object.entries(c)) {
|
|
2683
|
+
const d = `${l}/${F(a)}`;
|
|
2684
|
+
if (N(u)) {
|
|
2685
|
+
t.push({ target: i, key: a, path: u.path }), i[a] = void 0;
|
|
2219
2686
|
continue;
|
|
2220
2687
|
}
|
|
2221
|
-
|
|
2688
|
+
i[a] = s(u, d);
|
|
2222
2689
|
}
|
|
2223
|
-
return
|
|
2690
|
+
return i;
|
|
2224
2691
|
}
|
|
2225
|
-
const
|
|
2226
|
-
e.set("",
|
|
2227
|
-
for (const { target:
|
|
2228
|
-
|
|
2229
|
-
return
|
|
2692
|
+
const r = s(o, "");
|
|
2693
|
+
e.set("", r);
|
|
2694
|
+
for (const { target: c, key: l, path: i } of t)
|
|
2695
|
+
c[l] = e.get(i);
|
|
2696
|
+
return r;
|
|
2230
2697
|
}
|
|
2231
|
-
function
|
|
2232
|
-
return o !== null && typeof o == "object" && o[
|
|
2698
|
+
function N(o) {
|
|
2699
|
+
return o !== null && typeof o == "object" && o[w] === "ref" && typeof o.path == "string";
|
|
2233
2700
|
}
|
|
2234
|
-
function
|
|
2701
|
+
function F(o) {
|
|
2235
2702
|
return o.replace(/~/g, "~0").replace(/\//g, "~1");
|
|
2236
2703
|
}
|
|
2237
|
-
function
|
|
2238
|
-
let
|
|
2239
|
-
for (let
|
|
2240
|
-
const { value:
|
|
2241
|
-
let
|
|
2704
|
+
function ge(o, e, t = {}) {
|
|
2705
|
+
let s = t.maxNodes ?? 1e5;
|
|
2706
|
+
for (let n = 0; n < 8; n += 1) {
|
|
2707
|
+
const { value: r, report: c } = H(o, { ...t, maxNodes: s });
|
|
2708
|
+
let l;
|
|
2242
2709
|
try {
|
|
2243
|
-
|
|
2710
|
+
l = JSON.stringify(r)?.length ?? 0;
|
|
2244
2711
|
} catch {
|
|
2245
|
-
|
|
2712
|
+
l = Number.POSITIVE_INFINITY;
|
|
2246
2713
|
}
|
|
2247
|
-
if (
|
|
2248
|
-
return
|
|
2249
|
-
value:
|
|
2714
|
+
if (l <= e)
|
|
2715
|
+
return c.truncated ? {
|
|
2716
|
+
value: r,
|
|
2250
2717
|
truncated: !0,
|
|
2251
|
-
note: `State was too large to send in full; parts beyond ${
|
|
2252
|
-
} : { value:
|
|
2253
|
-
const
|
|
2254
|
-
if (
|
|
2718
|
+
note: `State was too large to send in full; parts beyond ${s} nodes are omitted.`
|
|
2719
|
+
} : { value: r, truncated: !1 };
|
|
2720
|
+
const i = Math.floor(s * e * 0.8 / l);
|
|
2721
|
+
if (s = Math.max(1, Math.min(i, s - 1)), s <= 1 && n > 0)
|
|
2255
2722
|
break;
|
|
2256
2723
|
}
|
|
2257
2724
|
return {
|
|
2258
|
-
value: { [
|
|
2725
|
+
value: { [w]: "unsupported", kind: "truncated" },
|
|
2259
2726
|
truncated: !0,
|
|
2260
2727
|
note: `State exceeds the ${e}-byte transport limit and could not be reduced to fit.`
|
|
2261
2728
|
};
|
|
@@ -2263,104 +2730,104 @@ function Y(o, e, t = {}) {
|
|
|
2263
2730
|
function b(o, e, t) {
|
|
2264
2731
|
o.onError?.(e, t);
|
|
2265
2732
|
}
|
|
2266
|
-
async function
|
|
2733
|
+
async function we(o) {
|
|
2267
2734
|
const e = { slices: {}, restored: !1 };
|
|
2268
2735
|
let t;
|
|
2269
2736
|
try {
|
|
2270
2737
|
t = o.source ?? await o.adapter.read(o.key);
|
|
2271
|
-
} catch (
|
|
2272
|
-
return b(o,
|
|
2738
|
+
} catch (n) {
|
|
2739
|
+
return b(o, n, "read"), e;
|
|
2273
2740
|
}
|
|
2274
2741
|
if (t == null || t === "") return e;
|
|
2275
|
-
let
|
|
2742
|
+
let s;
|
|
2276
2743
|
try {
|
|
2277
|
-
|
|
2278
|
-
} catch (
|
|
2279
|
-
return b(o,
|
|
2744
|
+
s = ue(JSON.parse(t));
|
|
2745
|
+
} catch (n) {
|
|
2746
|
+
return b(o, n, "decode"), e;
|
|
2280
2747
|
}
|
|
2281
|
-
if (
|
|
2748
|
+
if (s === null || typeof s != "object" || typeof s.version != "number")
|
|
2282
2749
|
return b(o, new Error("persisted payload is not a recognisable envelope"), "decode"), e;
|
|
2283
|
-
if (
|
|
2750
|
+
if (s.version !== o.version) {
|
|
2284
2751
|
if (o.migrate === void 0)
|
|
2285
2752
|
return b(
|
|
2286
2753
|
o,
|
|
2287
2754
|
new Error(
|
|
2288
|
-
`persisted state is version ${
|
|
2755
|
+
`persisted state is version ${s.version}, this build expects ${o.version}, and no migrate was supplied`
|
|
2289
2756
|
),
|
|
2290
2757
|
"migrate"
|
|
2291
2758
|
), e;
|
|
2292
2759
|
try {
|
|
2293
|
-
const
|
|
2294
|
-
return
|
|
2295
|
-
} catch (
|
|
2296
|
-
return b(o,
|
|
2760
|
+
const n = o.migrate(s.slices, s.version);
|
|
2761
|
+
return n === null ? e : { slices: n, restored: !0 };
|
|
2762
|
+
} catch (n) {
|
|
2763
|
+
return b(o, n, "migrate"), e;
|
|
2297
2764
|
}
|
|
2298
2765
|
}
|
|
2299
|
-
return { slices:
|
|
2766
|
+
return { slices: s.slices ?? {}, restored: !0 };
|
|
2300
2767
|
}
|
|
2301
|
-
function
|
|
2768
|
+
function Ee(o, e) {
|
|
2302
2769
|
if (!e.restored) return o;
|
|
2303
2770
|
const t = {};
|
|
2304
|
-
for (const [
|
|
2305
|
-
const
|
|
2306
|
-
t[
|
|
2771
|
+
for (const [s, n] of Object.entries(o)) {
|
|
2772
|
+
const r = e.slices[s];
|
|
2773
|
+
t[s] = r === void 0 ? n : { ...n, state: r };
|
|
2307
2774
|
}
|
|
2308
2775
|
return t;
|
|
2309
2776
|
}
|
|
2310
|
-
function
|
|
2311
|
-
const t = o ?? {},
|
|
2312
|
-
return JSON.stringify(
|
|
2777
|
+
function K(o, e) {
|
|
2778
|
+
const t = o ?? {}, s = e.slices === void 0 ? t : Object.fromEntries(e.slices.filter((n) => n in t).map((n) => [n, t[n]]));
|
|
2779
|
+
return JSON.stringify(H({ version: e.version, slices: s }).value);
|
|
2313
2780
|
}
|
|
2314
|
-
function
|
|
2315
|
-
const t = e.throttleMs ?? 250,
|
|
2316
|
-
let
|
|
2317
|
-
const
|
|
2318
|
-
if (
|
|
2319
|
-
|
|
2781
|
+
function be(o, e) {
|
|
2782
|
+
const t = e.throttleMs ?? 250, s = e.slices;
|
|
2783
|
+
let n = null, r = !1;
|
|
2784
|
+
const c = () => {
|
|
2785
|
+
if (r) {
|
|
2786
|
+
r = !1;
|
|
2320
2787
|
try {
|
|
2321
|
-
const
|
|
2322
|
-
|
|
2323
|
-
} catch (
|
|
2324
|
-
b(e,
|
|
2788
|
+
const a = e.adapter.write(e.key, K(o.getState(), e));
|
|
2789
|
+
a instanceof Promise && a.catch((u) => b(e, u, "write"));
|
|
2790
|
+
} catch (a) {
|
|
2791
|
+
b(e, a, "write");
|
|
2325
2792
|
}
|
|
2326
2793
|
}
|
|
2327
|
-
},
|
|
2328
|
-
if (
|
|
2329
|
-
|
|
2794
|
+
}, l = () => {
|
|
2795
|
+
if (r = !0, t <= 0) {
|
|
2796
|
+
c();
|
|
2330
2797
|
return;
|
|
2331
2798
|
}
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
}, t),
|
|
2335
|
-
},
|
|
2336
|
-
if (
|
|
2337
|
-
|
|
2799
|
+
n === null && (n = setTimeout(() => {
|
|
2800
|
+
n = null, c();
|
|
2801
|
+
}, t), n.unref?.());
|
|
2802
|
+
}, i = o.instrument((a) => {
|
|
2803
|
+
if (s === void 0) {
|
|
2804
|
+
l();
|
|
2338
2805
|
return;
|
|
2339
2806
|
}
|
|
2340
|
-
(
|
|
2341
|
-
(
|
|
2342
|
-
) &&
|
|
2807
|
+
(a.changedPaths ?? []).some(
|
|
2808
|
+
(d) => s.some((h) => d === h || d.startsWith(`${h}.`))
|
|
2809
|
+
) && l();
|
|
2343
2810
|
});
|
|
2344
2811
|
return () => {
|
|
2345
|
-
|
|
2812
|
+
i(), n !== null && (clearTimeout(n), n = null), c();
|
|
2346
2813
|
};
|
|
2347
2814
|
}
|
|
2348
|
-
function
|
|
2349
|
-
return
|
|
2815
|
+
function ve(o, e) {
|
|
2816
|
+
return K(o.getState(), e);
|
|
2350
2817
|
}
|
|
2351
|
-
function
|
|
2818
|
+
function Se(o) {
|
|
2352
2819
|
return {
|
|
2353
2820
|
read: (e) => o.getItem(e),
|
|
2354
2821
|
write: (e, t) => o.setItem(e, t),
|
|
2355
2822
|
remove: (e) => o.removeItem(e)
|
|
2356
2823
|
};
|
|
2357
2824
|
}
|
|
2358
|
-
function
|
|
2825
|
+
function $e(o) {
|
|
2359
2826
|
const e = new Map(Object.entries(o ?? {}));
|
|
2360
2827
|
return {
|
|
2361
2828
|
read: (t) => e.get(t) ?? null,
|
|
2362
|
-
write: (t,
|
|
2363
|
-
e.set(t,
|
|
2829
|
+
write: (t, s) => {
|
|
2830
|
+
e.set(t, s);
|
|
2364
2831
|
},
|
|
2365
2832
|
remove: (t) => {
|
|
2366
2833
|
e.delete(t);
|
|
@@ -2368,24 +2835,28 @@ function se(o) {
|
|
|
2368
2835
|
};
|
|
2369
2836
|
}
|
|
2370
2837
|
export {
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2838
|
+
C as CallAbortedError,
|
|
2839
|
+
Q as CallTimeoutError,
|
|
2840
|
+
W as EventBus,
|
|
2841
|
+
U as LooseEventBus,
|
|
2842
|
+
L as Reducer,
|
|
2843
|
+
fe as Rejected,
|
|
2844
|
+
x as Store,
|
|
2845
|
+
ye as createEntityAdapter,
|
|
2846
|
+
$e as createMemoryAdapter,
|
|
2847
|
+
he as createStore,
|
|
2848
|
+
Se as createWebStorageAdapter,
|
|
2849
|
+
ue as decodeState,
|
|
2850
|
+
ve as dehydrate,
|
|
2851
|
+
I as detectChangedProps,
|
|
2852
|
+
H as encodeState,
|
|
2853
|
+
ge as encodeStateBounded,
|
|
2854
|
+
me as eventKeys,
|
|
2855
|
+
M as freezeState,
|
|
2856
|
+
we as hydrate,
|
|
2857
|
+
V as isRejected,
|
|
2858
|
+
be as persist,
|
|
2859
|
+
pe as typedEvents,
|
|
2860
|
+
Ee as withHydration
|
|
2390
2861
|
};
|
|
2391
2862
|
//# sourceMappingURL=yoltra.mjs.map
|