@yoltra/core 0.7.0 → 0.8.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 +127 -11
- package/README.md +126 -12
- package/dist/types/index.d.ts +2 -1
- package/dist/types/persistence/persist.d.ts +2 -2
- package/dist/types/store/Store.d.ts +368 -14
- package/dist/types/store/fingerprint.d.ts +62 -0
- package/dist/types/types.d.ts +524 -14
- package/dist/yoltra.cjs +2 -2
- package/dist/yoltra.cjs.map +1 -1
- package/dist/yoltra.mjs +1668 -880
- package/dist/yoltra.mjs.map +1 -1
- package/dist/yoltra.umd.js +2 -2
- package/dist/yoltra.umd.js.map +1 -1
- package/package.json +3 -2
package/dist/yoltra.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* @yoltra/core v0.
|
|
2
|
+
* @yoltra/core v0.8.0
|
|
3
3
|
* (c) 2026 Manu Ramirez <@pixerael>
|
|
4
4
|
* License: MIT */
|
|
5
|
-
class
|
|
5
|
+
class G {
|
|
6
6
|
/**
|
|
7
7
|
* Internal registry: `channel → type → Set<handler>`.
|
|
8
8
|
* @internal
|
|
@@ -40,11 +40,11 @@ class W {
|
|
|
40
40
|
*
|
|
41
41
|
* @public
|
|
42
42
|
*/
|
|
43
|
-
on(e, t,
|
|
44
|
-
let
|
|
45
|
-
|
|
46
|
-
let
|
|
47
|
-
return
|
|
43
|
+
on(e, t, n) {
|
|
44
|
+
let r = this.handlers.get(e);
|
|
45
|
+
r || (r = /* @__PURE__ */ new Map(), this.handlers.set(e, r));
|
|
46
|
+
let i = r.get(t);
|
|
47
|
+
return i || (i = /* @__PURE__ */ new Set(), r.set(t, i)), i.add(n), () => this.off(e, t, n);
|
|
48
48
|
}
|
|
49
49
|
/**
|
|
50
50
|
* Removes a specific handler previously added with {@link EventBus.on | `on`}.
|
|
@@ -66,11 +66,11 @@ class W {
|
|
|
66
66
|
*
|
|
67
67
|
* @public
|
|
68
68
|
*/
|
|
69
|
-
off(e, t,
|
|
70
|
-
const
|
|
71
|
-
if (!
|
|
72
|
-
const
|
|
73
|
-
|
|
69
|
+
off(e, t, n) {
|
|
70
|
+
const r = this.handlers.get(e);
|
|
71
|
+
if (!r) return;
|
|
72
|
+
const i = r.get(t);
|
|
73
|
+
i && (i.delete(n), i.size === 0 && r.delete(t), r.size === 0 && this.handlers.delete(e));
|
|
74
74
|
}
|
|
75
75
|
/**
|
|
76
76
|
* Emits an event to all subscribers of the exact `(channel, type)`.
|
|
@@ -94,16 +94,16 @@ class W {
|
|
|
94
94
|
*
|
|
95
95
|
* @public
|
|
96
96
|
*/
|
|
97
|
-
emit(e, t,
|
|
98
|
-
const
|
|
99
|
-
if (!
|
|
100
|
-
const
|
|
101
|
-
if (!(!
|
|
102
|
-
for (const l of [...
|
|
97
|
+
emit(e, t, n, r) {
|
|
98
|
+
const i = this.handlers.get(e);
|
|
99
|
+
if (!i) return;
|
|
100
|
+
const s = i.get(t);
|
|
101
|
+
if (!(!s || s.size === 0))
|
|
102
|
+
for (const l of [...s])
|
|
103
103
|
try {
|
|
104
|
-
l(
|
|
105
|
-
} catch (
|
|
106
|
-
console.error("EventBus handler error:",
|
|
104
|
+
l(n, r);
|
|
105
|
+
} catch (c) {
|
|
106
|
+
console.error("EventBus handler error:", c);
|
|
107
107
|
}
|
|
108
108
|
}
|
|
109
109
|
/**
|
|
@@ -123,7 +123,7 @@ class W {
|
|
|
123
123
|
this.handlers.clear();
|
|
124
124
|
}
|
|
125
125
|
}
|
|
126
|
-
class
|
|
126
|
+
class J {
|
|
127
127
|
/**
|
|
128
128
|
* Exact handlers: `channel → type → [handlers]`.
|
|
129
129
|
* @internal
|
|
@@ -184,18 +184,18 @@ class U {
|
|
|
184
184
|
*
|
|
185
185
|
* @public
|
|
186
186
|
*/
|
|
187
|
-
on(e, t,
|
|
188
|
-
const
|
|
189
|
-
if (this.isPattern(
|
|
190
|
-
const
|
|
187
|
+
on(e, t, n) {
|
|
188
|
+
const r = String(t);
|
|
189
|
+
if (this.isPattern(r)) {
|
|
190
|
+
const i = r;
|
|
191
191
|
this.patternHandlers.has(e) || this.patternHandlers.set(e, /* @__PURE__ */ new Map());
|
|
192
|
-
const
|
|
193
|
-
return
|
|
192
|
+
const s = this.patternHandlers.get(e);
|
|
193
|
+
return s.has(i) || (s.set(i, []), this.indexPattern(e, i)), s.get(i).push(n), () => this.offPattern(e, i, n);
|
|
194
194
|
} else {
|
|
195
|
-
const
|
|
195
|
+
const i = this.normalizeTypeKey(r);
|
|
196
196
|
this.handlers.has(e) || this.handlers.set(e, /* @__PURE__ */ new Map());
|
|
197
|
-
const
|
|
198
|
-
return
|
|
197
|
+
const s = this.handlers.get(e);
|
|
198
|
+
return s.has(i) || s.set(i, []), s.get(i).push(n), () => this.offExactNormalized(e, i, n);
|
|
199
199
|
}
|
|
200
200
|
}
|
|
201
201
|
/**
|
|
@@ -216,9 +216,9 @@ class U {
|
|
|
216
216
|
*
|
|
217
217
|
* @public
|
|
218
218
|
*/
|
|
219
|
-
off(e, t,
|
|
220
|
-
const
|
|
221
|
-
this.offExactNormalized(e,
|
|
219
|
+
off(e, t, n) {
|
|
220
|
+
const r = this.normalizeTypeKey(String(t));
|
|
221
|
+
this.offExactNormalized(e, r, n);
|
|
222
222
|
}
|
|
223
223
|
/**
|
|
224
224
|
* Internal exact unsubscription using an already **normalized** type key.
|
|
@@ -228,13 +228,13 @@ class U {
|
|
|
228
228
|
* @param handler - Handler to remove.
|
|
229
229
|
* @internal
|
|
230
230
|
*/
|
|
231
|
-
offExactNormalized(e, t,
|
|
232
|
-
const
|
|
233
|
-
if (!n) return;
|
|
234
|
-
const r = n.get(t);
|
|
231
|
+
offExactNormalized(e, t, n) {
|
|
232
|
+
const r = this.handlers.get(e);
|
|
235
233
|
if (!r) return;
|
|
236
|
-
const
|
|
237
|
-
|
|
234
|
+
const i = r.get(t);
|
|
235
|
+
if (!i) return;
|
|
236
|
+
const s = i.indexOf(n);
|
|
237
|
+
s !== -1 && i.splice(s, 1), i.length === 0 && r.delete(t), r.size === 0 && this.handlers.delete(e);
|
|
238
238
|
}
|
|
239
239
|
/**
|
|
240
240
|
* Internal removal for a **pattern** subscription. No-ops if missing.
|
|
@@ -244,13 +244,13 @@ class U {
|
|
|
244
244
|
* @param handler - Handler to remove.
|
|
245
245
|
* @internal
|
|
246
246
|
*/
|
|
247
|
-
offPattern(e, t,
|
|
248
|
-
const
|
|
249
|
-
if (!n) return;
|
|
250
|
-
const r = n.get(t);
|
|
247
|
+
offPattern(e, t, n) {
|
|
248
|
+
const r = this.patternHandlers.get(e);
|
|
251
249
|
if (!r) return;
|
|
252
|
-
const
|
|
253
|
-
|
|
250
|
+
const i = r.get(t);
|
|
251
|
+
if (!i) return;
|
|
252
|
+
const s = i.indexOf(n);
|
|
253
|
+
s !== -1 && i.splice(s, 1), i.length === 0 && (r.delete(t), this.unindexPattern(e, t)), r.size === 0 && (this.patternHandlers.delete(e), this.patternIndex.delete(e));
|
|
254
254
|
}
|
|
255
255
|
/**
|
|
256
256
|
* Emits an event to all exact subscribers first, then to **matching pattern** subscribers.
|
|
@@ -272,21 +272,21 @@ class U {
|
|
|
272
272
|
*
|
|
273
273
|
* @public
|
|
274
274
|
*/
|
|
275
|
-
emit(e, t,
|
|
276
|
-
const
|
|
277
|
-
for (const
|
|
278
|
-
if (!
|
|
279
|
-
|
|
275
|
+
emit(e, t, n) {
|
|
276
|
+
const r = String(t), i = this.normalizeTypeKey(r), s = this.handlers.get(e)?.get(i) ?? [], l = this.matchingPatternHandlers(e, r), c = /* @__PURE__ */ new Set(), a = (d) => {
|
|
277
|
+
for (const f of [...d])
|
|
278
|
+
if (!c.has(f)) {
|
|
279
|
+
c.add(f);
|
|
280
280
|
try {
|
|
281
|
-
|
|
282
|
-
} catch (
|
|
283
|
-
console.error(
|
|
281
|
+
f(n);
|
|
282
|
+
} catch (u) {
|
|
283
|
+
console.error(u);
|
|
284
284
|
continue;
|
|
285
285
|
}
|
|
286
286
|
}
|
|
287
287
|
};
|
|
288
|
-
a(
|
|
289
|
-
for (const
|
|
288
|
+
a(s);
|
|
289
|
+
for (const d of l) a(d);
|
|
290
290
|
}
|
|
291
291
|
/**
|
|
292
292
|
* Emits a payload that is only built if somebody is listening.
|
|
@@ -304,23 +304,23 @@ class U {
|
|
|
304
304
|
*
|
|
305
305
|
* @public
|
|
306
306
|
*/
|
|
307
|
-
emitWith(e, t,
|
|
308
|
-
const
|
|
309
|
-
if (
|
|
310
|
-
const
|
|
311
|
-
for (const
|
|
312
|
-
if (!a.has(
|
|
313
|
-
a.add(
|
|
307
|
+
emitWith(e, t, n) {
|
|
308
|
+
const r = String(t), i = this.normalizeTypeKey(r), s = this.handlers.get(e)?.get(i) ?? [], l = this.matchingPatternHandlers(e, r);
|
|
309
|
+
if (s.length === 0 && l.length === 0) return;
|
|
310
|
+
const c = n(), a = /* @__PURE__ */ new Set(), d = (f) => {
|
|
311
|
+
for (const u of [...f])
|
|
312
|
+
if (!a.has(u)) {
|
|
313
|
+
a.add(u);
|
|
314
314
|
try {
|
|
315
|
-
|
|
315
|
+
u(c);
|
|
316
316
|
} catch (p) {
|
|
317
317
|
console.error(p);
|
|
318
318
|
continue;
|
|
319
319
|
}
|
|
320
320
|
}
|
|
321
321
|
};
|
|
322
|
-
|
|
323
|
-
for (const
|
|
322
|
+
d(s);
|
|
323
|
+
for (const f of l) d(f);
|
|
324
324
|
}
|
|
325
325
|
/**
|
|
326
326
|
* Determines if a string is a **pattern** (contains `*`).
|
|
@@ -359,27 +359,27 @@ class U {
|
|
|
359
359
|
* @internal
|
|
360
360
|
*/
|
|
361
361
|
indexPattern(e, t) {
|
|
362
|
-
let
|
|
363
|
-
|
|
364
|
-
const
|
|
365
|
-
if (
|
|
366
|
-
|
|
362
|
+
let n = this.patternIndex.get(e);
|
|
363
|
+
n === void 0 && (n = { byHead: /* @__PURE__ */ new Map(), anyHead: [] }, this.patternIndex.set(e, n));
|
|
364
|
+
const r = this.splitPath(t), i = { pattern: t, segments: r }, s = r[0];
|
|
365
|
+
if (s === void 0 || s === "*" || s === "**") {
|
|
366
|
+
n.anyHead.push(i);
|
|
367
367
|
return;
|
|
368
368
|
}
|
|
369
|
-
const l =
|
|
370
|
-
l === void 0 ?
|
|
369
|
+
const l = n.byHead.get(s);
|
|
370
|
+
l === void 0 ? n.byHead.set(s, [i]) : l.push(i);
|
|
371
371
|
}
|
|
372
372
|
/**
|
|
373
373
|
* Removes a pattern from the index. Paired with {@link LooseEventBus.offPattern}.
|
|
374
374
|
* @internal
|
|
375
375
|
*/
|
|
376
376
|
unindexPattern(e, t) {
|
|
377
|
-
const
|
|
378
|
-
if (
|
|
379
|
-
const
|
|
380
|
-
if (
|
|
381
|
-
const
|
|
382
|
-
|
|
377
|
+
const n = this.patternIndex.get(e);
|
|
378
|
+
if (n === void 0) return;
|
|
379
|
+
const r = this.splitPath(t)[0], i = r === void 0 || r === "*" || r === "**" ? n.anyHead : n.byHead.get(r);
|
|
380
|
+
if (i === void 0) return;
|
|
381
|
+
const s = i.findIndex((l) => l.pattern === t);
|
|
382
|
+
s !== -1 && i.splice(s, 1), i.length === 0 && i !== n.anyHead && r !== void 0 && n.byHead.delete(r);
|
|
383
383
|
}
|
|
384
384
|
/**
|
|
385
385
|
* The handler lists of every pattern matching this subject.
|
|
@@ -393,20 +393,20 @@ class U {
|
|
|
393
393
|
* @internal
|
|
394
394
|
*/
|
|
395
395
|
matchingPatternHandlers(e, t) {
|
|
396
|
-
const
|
|
397
|
-
if (
|
|
398
|
-
const
|
|
399
|
-
for (const
|
|
400
|
-
if (!this.matchSegments(
|
|
401
|
-
const
|
|
402
|
-
|
|
396
|
+
const n = this.patternHandlers.get(e), r = this.patternIndex.get(e);
|
|
397
|
+
if (n === void 0 || n.size === 0 || r === void 0) return [];
|
|
398
|
+
const i = this.splitPath(t), s = [], l = (a) => {
|
|
399
|
+
for (const d of a) {
|
|
400
|
+
if (!this.matchSegments(d.segments, i)) continue;
|
|
401
|
+
const f = n.get(d.pattern);
|
|
402
|
+
f !== void 0 && s.push(f);
|
|
403
403
|
}
|
|
404
|
-
},
|
|
405
|
-
if (
|
|
406
|
-
const a =
|
|
404
|
+
}, c = i[0];
|
|
405
|
+
if (c !== void 0) {
|
|
406
|
+
const a = r.byHead.get(c);
|
|
407
407
|
a !== void 0 && l(a);
|
|
408
408
|
}
|
|
409
|
-
return l(
|
|
409
|
+
return l(r.anyHead), s;
|
|
410
410
|
}
|
|
411
411
|
/**
|
|
412
412
|
* Pattern matcher over dot-separated segments, which arrive already split.
|
|
@@ -437,18 +437,18 @@ class U {
|
|
|
437
437
|
* @internal
|
|
438
438
|
*/
|
|
439
439
|
matchSegments(e, t) {
|
|
440
|
-
let
|
|
441
|
-
for (;
|
|
442
|
-
if (
|
|
443
|
-
|
|
444
|
-
else if (
|
|
445
|
-
|
|
446
|
-
else if (
|
|
447
|
-
|
|
440
|
+
let n = 0, r = 0, i = -1, s = 0;
|
|
441
|
+
for (; r < t.length; )
|
|
442
|
+
if (n < e.length && (e[n] === "*" || e[n] === t[r]))
|
|
443
|
+
n++, r++;
|
|
444
|
+
else if (n < e.length && e[n] === "**")
|
|
445
|
+
i = n, s = r, n++;
|
|
446
|
+
else if (i !== -1)
|
|
447
|
+
n = i + 1, r = ++s;
|
|
448
448
|
else
|
|
449
449
|
return !1;
|
|
450
|
-
for (;
|
|
451
|
-
return
|
|
450
|
+
for (; n < e.length && e[n] === "**"; ) n++;
|
|
451
|
+
return n === e.length;
|
|
452
452
|
}
|
|
453
453
|
/**
|
|
454
454
|
* Removes **all** listeners (exact and pattern). Useful for tests/HMR teardown.
|
|
@@ -473,16 +473,16 @@ class U {
|
|
|
473
473
|
*/
|
|
474
474
|
__introspect() {
|
|
475
475
|
const e = [];
|
|
476
|
-
for (const [t,
|
|
477
|
-
for (const [
|
|
478
|
-
|
|
479
|
-
for (const [t,
|
|
480
|
-
for (const [
|
|
481
|
-
|
|
476
|
+
for (const [t, n] of this.handlers)
|
|
477
|
+
for (const [r, i] of n)
|
|
478
|
+
i.length > 0 && e.push({ channel: t, type: r, count: i.length });
|
|
479
|
+
for (const [t, n] of this.patternHandlers)
|
|
480
|
+
for (const [r, i] of n)
|
|
481
|
+
i.length > 0 && e.push({ channel: t, type: r, count: i.length });
|
|
482
482
|
return e;
|
|
483
483
|
}
|
|
484
484
|
}
|
|
485
|
-
class
|
|
485
|
+
class X {
|
|
486
486
|
/**
|
|
487
487
|
* The underlying pure reducer function.
|
|
488
488
|
* @internal
|
|
@@ -524,147 +524,147 @@ class L {
|
|
|
524
524
|
return this._reduce(e, t);
|
|
525
525
|
}
|
|
526
526
|
}
|
|
527
|
-
const
|
|
528
|
-
function
|
|
527
|
+
const _ = /* @__PURE__ */ new Set();
|
|
528
|
+
function P(o, e) {
|
|
529
529
|
const t = o ? `${o}.${e}` : e;
|
|
530
|
-
|
|
530
|
+
_.has(t) || (_.add(t), console.warn(
|
|
531
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.`
|
|
532
532
|
));
|
|
533
533
|
}
|
|
534
|
-
function I(o, e, t = "",
|
|
535
|
-
const
|
|
536
|
-
return
|
|
534
|
+
function I(o, e, t = "", n = /* @__PURE__ */ new Map()) {
|
|
535
|
+
const r = [];
|
|
536
|
+
return M(o, e, t, n, r), r;
|
|
537
537
|
}
|
|
538
|
-
function
|
|
538
|
+
function M(o, e, t, n, r) {
|
|
539
539
|
if (o === e) return;
|
|
540
540
|
if (typeof o != "object" || typeof e != "object" || o === null || e === null) {
|
|
541
541
|
if (typeof o == "number" && Number.isNaN(o) && Number.isNaN(e))
|
|
542
542
|
return;
|
|
543
|
-
|
|
543
|
+
r.push(t);
|
|
544
544
|
return;
|
|
545
545
|
}
|
|
546
546
|
if (o instanceof Date && e instanceof Date) {
|
|
547
|
-
o.getTime() !== e.getTime() &&
|
|
547
|
+
o.getTime() !== e.getTime() && r.push(t);
|
|
548
548
|
return;
|
|
549
549
|
}
|
|
550
550
|
if (o instanceof RegExp && e instanceof RegExp) {
|
|
551
|
-
(o.source !== e.source || e.flags !== o.flags) &&
|
|
551
|
+
(o.source !== e.source || e.flags !== o.flags) && r.push(t);
|
|
552
552
|
return;
|
|
553
553
|
}
|
|
554
554
|
if (o instanceof Map || e instanceof Map) {
|
|
555
|
-
|
|
555
|
+
r.push(t);
|
|
556
556
|
return;
|
|
557
557
|
}
|
|
558
558
|
if (o instanceof Set || e instanceof Set) {
|
|
559
|
-
|
|
559
|
+
r.push(t);
|
|
560
560
|
return;
|
|
561
561
|
}
|
|
562
|
-
const
|
|
563
|
-
if (l?.has(
|
|
564
|
-
const
|
|
565
|
-
|
|
562
|
+
const i = o, s = e, l = n.get(i);
|
|
563
|
+
if (l?.has(s)) return;
|
|
564
|
+
const c = l ?? /* @__PURE__ */ new Set();
|
|
565
|
+
c.add(s), l || n.set(i, c);
|
|
566
566
|
try {
|
|
567
|
-
const a = Array.isArray(o),
|
|
568
|
-
if (a !==
|
|
569
|
-
|
|
567
|
+
const a = Array.isArray(o), d = Array.isArray(e);
|
|
568
|
+
if (a !== d) {
|
|
569
|
+
r.push(t);
|
|
570
570
|
return;
|
|
571
571
|
}
|
|
572
572
|
if (a) {
|
|
573
|
-
const
|
|
574
|
-
|
|
575
|
-
const
|
|
576
|
-
for (let g = 0; g <
|
|
577
|
-
|
|
578
|
-
for (let g =
|
|
579
|
-
|
|
573
|
+
const h = o, y = e;
|
|
574
|
+
h.length !== y.length && t && r.push(t);
|
|
575
|
+
const w = Math.min(h.length, y.length);
|
|
576
|
+
for (let g = 0; g < w; g++)
|
|
577
|
+
h[g] !== y[g] && M(h[g], y[g], t ? `${t}.${g}` : `${g}`, n, r);
|
|
578
|
+
for (let g = w; g < Math.max(h.length, y.length); g++)
|
|
579
|
+
r.push(t ? `${t}.${g}` : `${g}`);
|
|
580
580
|
return;
|
|
581
581
|
}
|
|
582
|
-
const
|
|
583
|
-
if (
|
|
584
|
-
|
|
582
|
+
const f = Object.keys(o), u = Object.keys(e);
|
|
583
|
+
if (f.length === 0 && u.length === 0) {
|
|
584
|
+
r.push(t);
|
|
585
585
|
return;
|
|
586
586
|
}
|
|
587
|
-
let p =
|
|
587
|
+
let p = f.length === u.length;
|
|
588
588
|
if (p) {
|
|
589
|
-
for (let
|
|
590
|
-
if (!Object.prototype.hasOwnProperty.call(o, h
|
|
589
|
+
for (let h = 0; h < u.length; h++)
|
|
590
|
+
if (!Object.prototype.hasOwnProperty.call(o, u[h])) {
|
|
591
591
|
p = !1;
|
|
592
592
|
break;
|
|
593
593
|
}
|
|
594
594
|
}
|
|
595
595
|
if (p) {
|
|
596
|
-
for (const
|
|
597
|
-
o[
|
|
596
|
+
for (const h of u)
|
|
597
|
+
o[h] !== e[h] && (process.env.NODE_ENV !== "production" && h.includes(".") && P(t, h), M(o[h], e[h], t ? `${t}.${h}` : h, n, r));
|
|
598
598
|
return;
|
|
599
599
|
}
|
|
600
|
-
for (const
|
|
601
|
-
const
|
|
602
|
-
if (
|
|
603
|
-
process.env.NODE_ENV !== "production" &&
|
|
604
|
-
const
|
|
605
|
-
if (!
|
|
606
|
-
|
|
600
|
+
for (const h of u) {
|
|
601
|
+
const y = Object.prototype.hasOwnProperty.call(o, h);
|
|
602
|
+
if (y && o[h] === e[h]) continue;
|
|
603
|
+
process.env.NODE_ENV !== "production" && h.includes(".") && P(t, h);
|
|
604
|
+
const w = t ? `${t}.${h}` : h;
|
|
605
|
+
if (!y) {
|
|
606
|
+
r.push(w);
|
|
607
607
|
continue;
|
|
608
608
|
}
|
|
609
|
-
|
|
609
|
+
M(o[h], e[h], w, n, r);
|
|
610
610
|
}
|
|
611
|
-
for (const
|
|
612
|
-
Object.prototype.hasOwnProperty.call(e,
|
|
611
|
+
for (const h of f)
|
|
612
|
+
Object.prototype.hasOwnProperty.call(e, h) || (process.env.NODE_ENV !== "production" && h.includes(".") && P(t, h), r.push(t ? `${t}.${h}` : h));
|
|
613
613
|
} finally {
|
|
614
|
-
|
|
614
|
+
c.delete(s), c.size === 0 && n.delete(i);
|
|
615
615
|
}
|
|
616
616
|
}
|
|
617
|
-
function
|
|
618
|
-
if (o === null || typeof o != "object" || e.has(o) || (t !== void 0 && o === t.watch && t.onFound(), Object.isFrozen(o))) return o;
|
|
619
|
-
if (
|
|
620
|
-
const
|
|
621
|
-
for (let
|
|
622
|
-
|
|
623
|
-
return Object.freeze(
|
|
624
|
-
}
|
|
625
|
-
for (const
|
|
626
|
-
const
|
|
627
|
-
!
|
|
628
|
-
}
|
|
629
|
-
for (const
|
|
630
|
-
const
|
|
631
|
-
!
|
|
617
|
+
function C(o, e = /* @__PURE__ */ new WeakSet(), t) {
|
|
618
|
+
if (o === null || typeof o != "object" || e.has(o) || (t !== void 0 && o === t.watch && t.onFound(), Object.isFrozen(o)) || (e.add(o), ArrayBuffer.isView(o))) return o;
|
|
619
|
+
if (Array.isArray(o)) {
|
|
620
|
+
const n = o;
|
|
621
|
+
for (let r = 0; r < n.length; r++)
|
|
622
|
+
n[r] = C(n[r], e, t);
|
|
623
|
+
return Object.freeze(n);
|
|
624
|
+
}
|
|
625
|
+
for (const n of Object.getOwnPropertyNames(o)) {
|
|
626
|
+
const r = Object.getOwnPropertyDescriptor(o, n);
|
|
627
|
+
!r || !("value" in r) || (o[n] = C(o[n], e, t));
|
|
628
|
+
}
|
|
629
|
+
for (const n of Object.getOwnPropertySymbols(o)) {
|
|
630
|
+
const r = Object.getOwnPropertyDescriptor(o, n);
|
|
631
|
+
!r || !("value" in r) || (o[n] = C(o[n], e, t));
|
|
632
632
|
}
|
|
633
633
|
return Object.freeze(o);
|
|
634
634
|
}
|
|
635
|
-
const
|
|
636
|
-
function
|
|
637
|
-
return { [
|
|
635
|
+
const q = /* @__PURE__ */ Symbol.for("yoltra.rejected");
|
|
636
|
+
function Re(o) {
|
|
637
|
+
return { [q]: !0, reason: o };
|
|
638
638
|
}
|
|
639
|
-
function
|
|
640
|
-
return typeof o == "object" && o !== null && o[
|
|
639
|
+
function Y(o) {
|
|
640
|
+
return typeof o == "object" && o !== null && o[q] === !0;
|
|
641
641
|
}
|
|
642
|
-
class
|
|
642
|
+
class Z extends Error {
|
|
643
643
|
channel;
|
|
644
644
|
type;
|
|
645
645
|
idleMs;
|
|
646
|
-
constructor(e, t,
|
|
646
|
+
constructor(e, t, n) {
|
|
647
647
|
super(
|
|
648
|
-
`[yoltra] call to "${e}/${t}" saw no correlated reply for ${
|
|
649
|
-
), this.name = "CallTimeoutError", this.channel = e, this.type = t, this.idleMs =
|
|
648
|
+
`[yoltra] call to "${e}/${t}" saw no correlated reply for ${n}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 = n;
|
|
650
650
|
}
|
|
651
651
|
}
|
|
652
|
-
class
|
|
652
|
+
class B extends Error {
|
|
653
653
|
constructor(e) {
|
|
654
654
|
super(`[yoltra] call aborted: ${e}`), this.name = "CallAbortedError";
|
|
655
655
|
}
|
|
656
656
|
}
|
|
657
|
-
function
|
|
657
|
+
function ee(o) {
|
|
658
658
|
const [e, t] = o;
|
|
659
659
|
if (t === void 0) return { channel: e, isTerminal: () => !0 };
|
|
660
|
-
if (typeof t == "string") return { channel: e, isTerminal: (
|
|
661
|
-
const
|
|
662
|
-
return { channel: e, isTerminal: (
|
|
660
|
+
if (typeof t == "string") return { channel: e, isTerminal: (r) => r === t };
|
|
661
|
+
const n = new Set(t);
|
|
662
|
+
return { channel: e, isTerminal: (r) => n.has(r) };
|
|
663
663
|
}
|
|
664
|
-
function
|
|
664
|
+
function te(o, e, t) {
|
|
665
665
|
return o.parentId === e ? !0 : t === void 0 ? !1 : o.meta?.correlationId === t;
|
|
666
666
|
}
|
|
667
|
-
class
|
|
667
|
+
class ne {
|
|
668
668
|
constructor(e) {
|
|
669
669
|
this.highWaterMark = e;
|
|
670
670
|
}
|
|
@@ -699,8 +699,8 @@ class q {
|
|
|
699
699
|
put(e) {
|
|
700
700
|
if (this.closed || this.ended) return Promise.resolve();
|
|
701
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((
|
|
703
|
-
this.putters.push({ item: e, release:
|
|
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((n) => {
|
|
703
|
+
this.putters.push({ item: e, release: n });
|
|
704
704
|
}) : (this.dropped++, Promise.resolve());
|
|
705
705
|
}
|
|
706
706
|
/** Takes the next item, waiting if none is available. Resolves `done` once closed and drained. */
|
|
@@ -708,12 +708,12 @@ class q {
|
|
|
708
708
|
this.consuming = !0;
|
|
709
709
|
const e = this.buffer.shift();
|
|
710
710
|
if (e !== void 0) {
|
|
711
|
-
const
|
|
712
|
-
return
|
|
711
|
+
const n = this.putters.shift();
|
|
712
|
+
return n !== void 0 && (this.buffer.push(n.item), n.release()), Promise.resolve({ value: e, done: !1 });
|
|
713
713
|
}
|
|
714
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((
|
|
716
|
-
this.takers.push(
|
|
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((n) => {
|
|
716
|
+
this.takers.push(n);
|
|
717
717
|
});
|
|
718
718
|
}
|
|
719
719
|
/**
|
|
@@ -734,9 +734,9 @@ class q {
|
|
|
734
734
|
this.buffer.push(e.item), e.release(), e = this.putters.shift();
|
|
735
735
|
let t = this.takers.shift();
|
|
736
736
|
for (; t !== void 0; ) {
|
|
737
|
-
const
|
|
737
|
+
const n = this.buffer.shift();
|
|
738
738
|
t(
|
|
739
|
-
|
|
739
|
+
n !== void 0 ? { value: n, done: !1 } : { value: void 0, done: !0 }
|
|
740
740
|
), t = this.takers.shift();
|
|
741
741
|
}
|
|
742
742
|
}
|
|
@@ -761,91 +761,356 @@ class q {
|
|
|
761
761
|
t.release(), t = this.putters.shift();
|
|
762
762
|
}
|
|
763
763
|
}
|
|
764
|
-
const
|
|
765
|
-
function
|
|
766
|
-
const { channel:
|
|
767
|
-
let
|
|
768
|
-
const p = new Promise((E,
|
|
769
|
-
|
|
764
|
+
const re = 3e4, ie = 16;
|
|
765
|
+
function se(o, e, t, n, r) {
|
|
766
|
+
const { channel: i, isTerminal: s } = ee(r.reply), l = r.timeoutMs ?? re, c = new ne(r.highWaterMark ?? ie), a = o.idFactory();
|
|
767
|
+
let d, f, u = !1;
|
|
768
|
+
const p = new Promise((E, R) => {
|
|
769
|
+
d = E, f = R;
|
|
770
770
|
});
|
|
771
771
|
p.catch(() => {
|
|
772
772
|
});
|
|
773
|
-
let
|
|
774
|
-
const
|
|
775
|
-
|
|
773
|
+
let h = null, y = null;
|
|
774
|
+
const w = (E, R = !1) => {
|
|
775
|
+
u || (u = !0, h !== null && clearTimeout(h), h = null, y?.(), y = null, R ? c.end() : c.close(), r.signal?.removeEventListener("abort", g), E());
|
|
776
776
|
};
|
|
777
777
|
function g() {
|
|
778
|
-
|
|
778
|
+
w(() => f(new B(String(r.signal?.reason ?? "signal aborted"))));
|
|
779
779
|
}
|
|
780
|
-
const
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
}, l),
|
|
780
|
+
const b = () => {
|
|
781
|
+
h !== null && clearTimeout(h), h = setTimeout(() => {
|
|
782
|
+
w(() => f(new Z(e, t, l)));
|
|
783
|
+
}, l), h.unref?.();
|
|
784
784
|
};
|
|
785
|
-
return
|
|
785
|
+
return y = o.registerEffect({
|
|
786
786
|
// A pattern effect on the reply channel: which types are terminal is known, which are
|
|
787
787
|
// progress is not, so the filter cannot be a key list.
|
|
788
|
-
when: { channel:
|
|
788
|
+
when: { channel: i },
|
|
789
789
|
effect: async (E) => {
|
|
790
|
-
if (!
|
|
791
|
-
if (
|
|
792
|
-
|
|
790
|
+
if (!u && te(E, a, r.correlationId)) {
|
|
791
|
+
if (b(), s(String(E.type))) {
|
|
792
|
+
w(() => d(E), !0);
|
|
793
793
|
return;
|
|
794
794
|
}
|
|
795
|
-
await
|
|
795
|
+
await c.put(E);
|
|
796
796
|
}
|
|
797
797
|
}
|
|
798
|
-
}),
|
|
798
|
+
}), r.signal !== void 0 && (r.signal.aborted ? g() : r.signal.addEventListener("abort", g, { once: !0 })), b(), o.emit(e, t, n, {
|
|
799
799
|
id: a,
|
|
800
|
-
...
|
|
800
|
+
...r.correlationId !== void 0 ? { meta: { correlationId: r.correlationId } } : {}
|
|
801
801
|
}), {
|
|
802
|
-
then: (E,
|
|
802
|
+
then: (E, R) => p.then(E, R),
|
|
803
803
|
catch: (E) => p.catch(E),
|
|
804
804
|
finally: (E) => p.finally(E),
|
|
805
805
|
get dropped() {
|
|
806
|
-
return
|
|
806
|
+
return c.droppedCount;
|
|
807
807
|
},
|
|
808
808
|
cancel: (E = "cancelled") => {
|
|
809
|
-
|
|
809
|
+
w(() => f(new B(E)));
|
|
810
810
|
},
|
|
811
|
-
[Symbol.asyncIterator]: () => (
|
|
812
|
-
next: () =>
|
|
811
|
+
[Symbol.asyncIterator]: () => (c.beginConsuming(), {
|
|
812
|
+
next: () => c.take(),
|
|
813
813
|
// Called by `for await` on `break`, `return` or a throw. Without it, abandoning the
|
|
814
814
|
// loop would leave the effect registered and the producer parked for good.
|
|
815
|
-
return: async () => (
|
|
815
|
+
return: async () => (c.close(), { value: void 0, done: !0 })
|
|
816
816
|
})
|
|
817
817
|
};
|
|
818
818
|
}
|
|
819
|
-
function
|
|
819
|
+
function oe(o, e) {
|
|
820
820
|
if (!e) return o;
|
|
821
|
-
const
|
|
822
|
-
let
|
|
823
|
-
for (const
|
|
824
|
-
if (
|
|
825
|
-
|
|
821
|
+
const n = (e[0] === "." ? e.slice(1) : e).split(".");
|
|
822
|
+
let r = o;
|
|
823
|
+
for (const i of n) {
|
|
824
|
+
if (r == null) return;
|
|
825
|
+
r = r[i];
|
|
826
826
|
}
|
|
827
|
-
return
|
|
827
|
+
return r;
|
|
828
828
|
}
|
|
829
|
-
function
|
|
829
|
+
function ce(o) {
|
|
830
830
|
if (!o) return [];
|
|
831
|
-
const t = (o[0] === "." ? o.slice(1) : o).split("."),
|
|
832
|
-
for (let
|
|
833
|
-
|
|
834
|
-
return
|
|
831
|
+
const t = (o[0] === "." ? o.slice(1) : o).split("."), n = [];
|
|
832
|
+
for (let r = 0; r < t.length; r++)
|
|
833
|
+
n.push(t.slice(0, r + 1).join("."));
|
|
834
|
+
return n;
|
|
835
|
+
}
|
|
836
|
+
const m = "$yoltra", O = Object.freeze(
|
|
837
|
+
Object.assign(/* @__PURE__ */ Object.create(null), {
|
|
838
|
+
Int8Array,
|
|
839
|
+
Uint8Array,
|
|
840
|
+
Uint8ClampedArray,
|
|
841
|
+
Int16Array,
|
|
842
|
+
Uint16Array,
|
|
843
|
+
Int32Array,
|
|
844
|
+
Uint32Array,
|
|
845
|
+
Float32Array,
|
|
846
|
+
Float64Array,
|
|
847
|
+
BigInt64Array,
|
|
848
|
+
BigUint64Array
|
|
849
|
+
})
|
|
850
|
+
);
|
|
851
|
+
function ae(o) {
|
|
852
|
+
const e = o.constructor?.name;
|
|
853
|
+
if (e !== void 0 && Object.prototype.hasOwnProperty.call(O, e))
|
|
854
|
+
return e;
|
|
855
|
+
if (o instanceof DataView) return "DataView";
|
|
856
|
+
for (const t of Object.keys(O)) {
|
|
857
|
+
const n = O[t];
|
|
858
|
+
if (n !== void 0 && o instanceof n) return t;
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
function N(o) {
|
|
862
|
+
const e = globalThis.Buffer;
|
|
863
|
+
if (e !== void 0) return e.from(o).toString("base64");
|
|
864
|
+
const t = 8192;
|
|
865
|
+
let n = "";
|
|
866
|
+
for (let r = 0; r < o.length; r += t)
|
|
867
|
+
n += String.fromCharCode(...o.subarray(r, r + t));
|
|
868
|
+
return btoa(n);
|
|
869
|
+
}
|
|
870
|
+
function de(o) {
|
|
871
|
+
const e = globalThis.Buffer;
|
|
872
|
+
if (e !== void 0) {
|
|
873
|
+
const r = e.from(o, "base64");
|
|
874
|
+
return new Uint8Array(r.subarray(0, r.length));
|
|
875
|
+
}
|
|
876
|
+
const t = atob(o), n = new Uint8Array(t.length);
|
|
877
|
+
for (let r = 0; r < t.length; r += 1) n[r] = t.charCodeAt(r);
|
|
878
|
+
return n;
|
|
879
|
+
}
|
|
880
|
+
function j(o, e = {}) {
|
|
881
|
+
const t = e.maxNodes ?? 1e5, n = e.sanitize, r = [], i = /* @__PURE__ */ new Map();
|
|
882
|
+
let s = 0, l = !1;
|
|
883
|
+
function c(d, f) {
|
|
884
|
+
if (n !== void 0 && (d = n(f, d)), s += 1, s > t)
|
|
885
|
+
return l = !0, { [m]: "unsupported", kind: "truncated" };
|
|
886
|
+
switch (typeof d) {
|
|
887
|
+
case "undefined":
|
|
888
|
+
return { [m]: "undefined" };
|
|
889
|
+
case "bigint":
|
|
890
|
+
return { [m]: "bigint", value: d.toString() };
|
|
891
|
+
case "number":
|
|
892
|
+
return Number.isNaN(d) ? { [m]: "nan" } : d === 1 / 0 ? { [m]: "infinity", sign: 1 } : d === -1 / 0 ? { [m]: "infinity", sign: -1 } : d;
|
|
893
|
+
case "function":
|
|
894
|
+
case "symbol":
|
|
895
|
+
return r.push(f), { [m]: "unsupported", kind: typeof d };
|
|
896
|
+
case "string":
|
|
897
|
+
case "boolean":
|
|
898
|
+
return d;
|
|
899
|
+
}
|
|
900
|
+
if (d === null) return null;
|
|
901
|
+
const u = d, p = i.get(u);
|
|
902
|
+
if (p !== void 0) return { [m]: "ref", path: p };
|
|
903
|
+
if (i.set(u, f), d instanceof Date)
|
|
904
|
+
return { [m]: "date", iso: d.toISOString() };
|
|
905
|
+
if (d instanceof RegExp)
|
|
906
|
+
return { [m]: "regexp", source: d.source, flags: d.flags };
|
|
907
|
+
if (d instanceof Error)
|
|
908
|
+
return { [m]: "error", name: d.name, message: d.message };
|
|
909
|
+
if (d instanceof Map) {
|
|
910
|
+
const g = [];
|
|
911
|
+
let b = 0;
|
|
912
|
+
for (const [v, E] of d)
|
|
913
|
+
g.push([c(v, `${f}/@k${b}`), c(E, `${f}/${b}`)]), b += 1;
|
|
914
|
+
return { [m]: "map", entries: g };
|
|
915
|
+
}
|
|
916
|
+
if (d instanceof Set) {
|
|
917
|
+
const g = [];
|
|
918
|
+
let b = 0;
|
|
919
|
+
for (const v of d)
|
|
920
|
+
g.push(c(v, `${f}/${b}`)), b += 1;
|
|
921
|
+
return { [m]: "set", values: g };
|
|
922
|
+
}
|
|
923
|
+
if (Array.isArray(d))
|
|
924
|
+
return d.map((g, b) => c(g, `${f}/${b}`));
|
|
925
|
+
if (d instanceof ArrayBuffer)
|
|
926
|
+
return s += Math.ceil(d.byteLength / 64), s > t ? (l = !0, { [m]: "unsupported", kind: "truncated" }) : {
|
|
927
|
+
[m]: "binary",
|
|
928
|
+
kind: "ArrayBuffer",
|
|
929
|
+
b64: N(new Uint8Array(d))
|
|
930
|
+
};
|
|
931
|
+
if (ArrayBuffer.isView(d)) {
|
|
932
|
+
const g = d;
|
|
933
|
+
s += Math.ceil(g.byteLength / 64);
|
|
934
|
+
const b = ae(g);
|
|
935
|
+
if (b === void 0)
|
|
936
|
+
return r.push(f), {
|
|
937
|
+
[m]: "unsupported",
|
|
938
|
+
kind: g.constructor?.name ?? "ArrayBufferView"
|
|
939
|
+
};
|
|
940
|
+
const v = new Uint8Array(g.buffer, g.byteOffset, g.byteLength), E = { [m]: "binary", kind: b, b64: N(v) };
|
|
941
|
+
return g.constructor?.name !== b && r.push(f), E;
|
|
942
|
+
}
|
|
943
|
+
const h = Object.getPrototypeOf(d), y = d.constructor?.name;
|
|
944
|
+
if (h !== null && h !== Object.prototype && y !== "Object") {
|
|
945
|
+
r.push(f);
|
|
946
|
+
const g = {};
|
|
947
|
+
for (const [b, v] of Object.entries(d))
|
|
948
|
+
g[b] = c(v, `${f}/${D(b)}`);
|
|
949
|
+
return {
|
|
950
|
+
[m]: "unsupported",
|
|
951
|
+
kind: y ?? "unknown",
|
|
952
|
+
value: g
|
|
953
|
+
};
|
|
954
|
+
}
|
|
955
|
+
const w = {};
|
|
956
|
+
for (const [g, b] of Object.entries(d))
|
|
957
|
+
w[g] = c(b, `${f}/${D(g)}`);
|
|
958
|
+
return m in w ? { [m]: "escaped", value: w } : w;
|
|
959
|
+
}
|
|
960
|
+
return { value: c(o, ""), report: { truncated: l, unsupported: r } };
|
|
961
|
+
}
|
|
962
|
+
function le(o) {
|
|
963
|
+
const e = /* @__PURE__ */ new Map(), t = [];
|
|
964
|
+
function n(s, l) {
|
|
965
|
+
if (s === null || typeof s != "object") return s;
|
|
966
|
+
if (Array.isArray(s)) {
|
|
967
|
+
const a = [];
|
|
968
|
+
return e.set(l, a), s.forEach((d, f) => {
|
|
969
|
+
if (z(d)) {
|
|
970
|
+
t.push({ target: a, key: f, path: d.path }), a[f] = void 0;
|
|
971
|
+
return;
|
|
972
|
+
}
|
|
973
|
+
a[f] = n(d, `${l}/${f}`);
|
|
974
|
+
}), a;
|
|
975
|
+
}
|
|
976
|
+
if (typeof s[m] == "string") {
|
|
977
|
+
const a = s;
|
|
978
|
+
switch (a[m]) {
|
|
979
|
+
case "undefined":
|
|
980
|
+
return;
|
|
981
|
+
case "nan":
|
|
982
|
+
return Number.NaN;
|
|
983
|
+
case "infinity":
|
|
984
|
+
return a.sign === 1 ? 1 / 0 : -1 / 0;
|
|
985
|
+
case "bigint":
|
|
986
|
+
return BigInt(a.value);
|
|
987
|
+
case "date":
|
|
988
|
+
return new Date(a.iso);
|
|
989
|
+
case "regexp":
|
|
990
|
+
return new RegExp(a.source, a.flags);
|
|
991
|
+
case "error": {
|
|
992
|
+
const d = new Error(a.message);
|
|
993
|
+
return d.name = a.name, d;
|
|
994
|
+
}
|
|
995
|
+
case "binary": {
|
|
996
|
+
const d = de(a.b64);
|
|
997
|
+
if (a.kind === "ArrayBuffer") {
|
|
998
|
+
const p = d.slice();
|
|
999
|
+
return e.set(l, p.buffer), p.buffer;
|
|
1000
|
+
}
|
|
1001
|
+
if (a.kind === "DataView") {
|
|
1002
|
+
const p = d.slice(), h = new DataView(p.buffer);
|
|
1003
|
+
return e.set(l, h), h;
|
|
1004
|
+
}
|
|
1005
|
+
const f = Object.prototype.hasOwnProperty.call(O, a.kind) ? O[a.kind] : void 0;
|
|
1006
|
+
if (f === void 0) return;
|
|
1007
|
+
const u = new f(d.slice().buffer);
|
|
1008
|
+
return e.set(l, u), u;
|
|
1009
|
+
}
|
|
1010
|
+
case "unsupported":
|
|
1011
|
+
return a.value !== void 0 ? r(a.value, l) : void 0;
|
|
1012
|
+
case "ref":
|
|
1013
|
+
return;
|
|
1014
|
+
case "map": {
|
|
1015
|
+
const d = /* @__PURE__ */ new Map();
|
|
1016
|
+
return e.set(l, d), a.entries.forEach(([f, u], p) => {
|
|
1017
|
+
d.set(n(f, `${l}/@k${p}`), n(u, `${l}/${p}`));
|
|
1018
|
+
}), d;
|
|
1019
|
+
}
|
|
1020
|
+
case "set": {
|
|
1021
|
+
const d = /* @__PURE__ */ new Set();
|
|
1022
|
+
return e.set(l, d), a.values.forEach((f, u) => d.add(n(f, `${l}/${u}`))), d;
|
|
1023
|
+
}
|
|
1024
|
+
case "escaped":
|
|
1025
|
+
return r(a.value, l);
|
|
1026
|
+
default:
|
|
1027
|
+
return;
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
return r(s, l);
|
|
1031
|
+
}
|
|
1032
|
+
function r(s, l) {
|
|
1033
|
+
const c = {};
|
|
1034
|
+
e.set(l, c);
|
|
1035
|
+
for (const [a, d] of Object.entries(s)) {
|
|
1036
|
+
const f = `${l}/${D(a)}`;
|
|
1037
|
+
if (z(d)) {
|
|
1038
|
+
t.push({ target: c, key: a, path: d.path }), c[a] = void 0;
|
|
1039
|
+
continue;
|
|
1040
|
+
}
|
|
1041
|
+
c[a] = n(d, f);
|
|
1042
|
+
}
|
|
1043
|
+
return c;
|
|
1044
|
+
}
|
|
1045
|
+
const i = n(o, "");
|
|
1046
|
+
e.set("", i);
|
|
1047
|
+
for (const { target: s, key: l, path: c } of t)
|
|
1048
|
+
s[l] = e.get(c);
|
|
1049
|
+
return i;
|
|
835
1050
|
}
|
|
836
|
-
function
|
|
1051
|
+
function z(o) {
|
|
1052
|
+
return o !== null && typeof o == "object" && o[m] === "ref" && typeof o.path == "string";
|
|
1053
|
+
}
|
|
1054
|
+
function D(o) {
|
|
1055
|
+
return o.replace(/~/g, "~0").replace(/\//g, "~1");
|
|
1056
|
+
}
|
|
1057
|
+
function Oe(o, e, t = {}) {
|
|
1058
|
+
let n = t.maxNodes ?? 1e5;
|
|
1059
|
+
for (let r = 0; r < 8; r += 1) {
|
|
1060
|
+
const { value: i, report: s } = j(o, { ...t, maxNodes: n });
|
|
1061
|
+
let l;
|
|
1062
|
+
try {
|
|
1063
|
+
l = JSON.stringify(i)?.length ?? 0;
|
|
1064
|
+
} catch {
|
|
1065
|
+
l = Number.POSITIVE_INFINITY;
|
|
1066
|
+
}
|
|
1067
|
+
if (l <= e)
|
|
1068
|
+
return s.truncated ? {
|
|
1069
|
+
value: i,
|
|
1070
|
+
truncated: !0,
|
|
1071
|
+
note: `State was too large to send in full; parts beyond ${n} nodes are omitted.`
|
|
1072
|
+
} : { value: i, truncated: !1 };
|
|
1073
|
+
const c = Math.floor(n * e * 0.8 / l);
|
|
1074
|
+
if (n = Math.max(1, Math.min(c, n - 1)), n <= 1 && r > 0)
|
|
1075
|
+
break;
|
|
1076
|
+
}
|
|
1077
|
+
return {
|
|
1078
|
+
value: { [m]: "unsupported", kind: "truncated" },
|
|
1079
|
+
truncated: !0,
|
|
1080
|
+
note: `State exceeds the ${e}-byte transport limit and could not be reduced to fit.`
|
|
1081
|
+
};
|
|
1082
|
+
}
|
|
1083
|
+
const fe = 1e4;
|
|
1084
|
+
function x(o) {
|
|
1085
|
+
return o === null || typeof o != "object" ? JSON.stringify(o) ?? "null" : Array.isArray(o) ? `[${o.map(x).join(",")}]` : `{${Object.entries(o).sort(
|
|
1086
|
+
([t], [n]) => t < n ? -1 : t > n ? 1 : 0
|
|
1087
|
+
).map(([t, n]) => `${JSON.stringify(t)}:${x(n)}`).join(",")}}`;
|
|
1088
|
+
}
|
|
1089
|
+
function ue(o, e, t) {
|
|
1090
|
+
const n = `${o}::${e}`;
|
|
1091
|
+
if (t === null) return `${n}::null`;
|
|
1092
|
+
if (t === void 0) return `${n}::undefined`;
|
|
1093
|
+
if (typeof t != "object") return `${n}::${typeof t}:${String(t)}`;
|
|
1094
|
+
try {
|
|
1095
|
+
const { value: r, report: i } = j(t, { maxNodes: fe });
|
|
1096
|
+
return i.truncated ? `${n}::${Date.now()}::${Math.random()}` : `${n}::${x(r)}`;
|
|
1097
|
+
} catch {
|
|
1098
|
+
return `${n}::${Date.now()}::${Math.random()}`;
|
|
1099
|
+
}
|
|
1100
|
+
}
|
|
1101
|
+
function $(o, e) {
|
|
837
1102
|
return !o || "any" in o && o.any === !0 ? !0 : "keys" in o ? o.keys.some(
|
|
838
|
-
([t,
|
|
1103
|
+
([t, n]) => e.channel === t && e.type === n
|
|
839
1104
|
) : "channel" in o ? e.channel === o.channel : "channels" in o ? o.channels.includes(e.channel) : !1;
|
|
840
1105
|
}
|
|
841
|
-
function
|
|
1106
|
+
function he(o) {
|
|
842
1107
|
return typeof o == "function" ? o : o.middleware;
|
|
843
1108
|
}
|
|
844
|
-
function
|
|
1109
|
+
function A(o) {
|
|
845
1110
|
if (typeof o != "function")
|
|
846
1111
|
return o.when;
|
|
847
1112
|
}
|
|
848
|
-
function
|
|
1113
|
+
function U(o) {
|
|
849
1114
|
if (o.when) {
|
|
850
1115
|
const e = o.when;
|
|
851
1116
|
if ("keys" in e)
|
|
@@ -853,7 +1118,7 @@ function D(o) {
|
|
|
853
1118
|
}
|
|
854
1119
|
return [];
|
|
855
1120
|
}
|
|
856
|
-
function
|
|
1121
|
+
function pe(o, e) {
|
|
857
1122
|
try {
|
|
858
1123
|
return structuredClone(e);
|
|
859
1124
|
} catch (t) {
|
|
@@ -862,11 +1127,19 @@ function re(o, e) {
|
|
|
862
1127
|
);
|
|
863
1128
|
}
|
|
864
1129
|
}
|
|
865
|
-
function
|
|
866
|
-
return process.env.NODE_ENV === "production" ? o :
|
|
1130
|
+
function T(o, e) {
|
|
1131
|
+
return process.env.NODE_ENV === "production" ? o : C(o, /* @__PURE__ */ new WeakSet(), e);
|
|
867
1132
|
}
|
|
868
|
-
const
|
|
869
|
-
|
|
1133
|
+
const H = 100, V = 64, ge = 64, ye = 64, W = 16, me = Object.freeze({ committed: !1, written: !1 }), we = Object.freeze({
|
|
1134
|
+
committed: !1,
|
|
1135
|
+
written: !1,
|
|
1136
|
+
reason: "deduped"
|
|
1137
|
+
}), F = Object.freeze({
|
|
1138
|
+
committed: !1,
|
|
1139
|
+
written: !1,
|
|
1140
|
+
reason: "cascade"
|
|
1141
|
+
}), be = Object.freeze({ committed: !0, written: !1 }), Ee = Object.freeze({ committed: !0, written: !0 }), K = () => typeof performance < "u" && typeof performance.now == "function" ? performance.now() : Date.now();
|
|
1142
|
+
class k {
|
|
870
1143
|
/**
|
|
871
1144
|
* Store name (used by DevTools & diagnostics).
|
|
872
1145
|
*
|
|
@@ -876,7 +1149,9 @@ class x {
|
|
|
876
1149
|
/**
|
|
877
1150
|
* Registered middleware pipeline (run **before** reducers).
|
|
878
1151
|
* Stores either raw functions (legacy) or MiddlewareSpec objects.
|
|
879
|
-
*
|
|
1152
|
+
*
|
|
1153
|
+
* Only an explicit `false` stops propagation. Returning nothing allows the event, so
|
|
1154
|
+
* middleware that only logs or measures needs no `return` at all.
|
|
880
1155
|
*
|
|
881
1156
|
* @internal
|
|
882
1157
|
*/
|
|
@@ -960,6 +1235,17 @@ class x {
|
|
|
960
1235
|
*/
|
|
961
1236
|
writtenEventSubscribers = /* @__PURE__ */ new Map();
|
|
962
1237
|
allEventSubscribers = /* @__PURE__ */ new Map();
|
|
1238
|
+
/**
|
|
1239
|
+
* True while a devtools time-travel is applying a snapshot or replaying events.
|
|
1240
|
+
*
|
|
1241
|
+
* @remarks
|
|
1242
|
+
* Saved and restored rather than set and cleared to `false`: `__replayEvents` calls
|
|
1243
|
+
* `__applyExternalState` as its first step, so clearing on the inner call's way out would
|
|
1244
|
+
* unset the flag for the entire event loop that follows it.
|
|
1245
|
+
*
|
|
1246
|
+
* @internal
|
|
1247
|
+
*/
|
|
1248
|
+
replaying = !1;
|
|
963
1249
|
/**
|
|
964
1250
|
* Track reducerBus unsubs per slice for HMR/register/unregister.
|
|
965
1251
|
*
|
|
@@ -974,6 +1260,70 @@ class x {
|
|
|
974
1260
|
* @internal
|
|
975
1261
|
*/
|
|
976
1262
|
patternReducers = /* @__PURE__ */ new Map();
|
|
1263
|
+
/**
|
|
1264
|
+
* Where each mounted slice came from. See {@link Origin}.
|
|
1265
|
+
*
|
|
1266
|
+
* @remarks
|
|
1267
|
+
* This is what makes `replace*` mean "replace mine" rather than "replace everything". It
|
|
1268
|
+
* is written by `mountSlice` and never by a caller.
|
|
1269
|
+
*
|
|
1270
|
+
* @internal
|
|
1271
|
+
*/
|
|
1272
|
+
sliceOrigin = /* @__PURE__ */ new Map();
|
|
1273
|
+
/**
|
|
1274
|
+
* Who claims each dynamically mounted slice, for introspection only.
|
|
1275
|
+
*
|
|
1276
|
+
* @remarks
|
|
1277
|
+
* Surfaced in `__devtoolsIntrospect()` and named in the collision error. **Never read by
|
|
1278
|
+
* `replace*`.** Correctness comes from {@link Origin}, which nobody has to remember to
|
|
1279
|
+
* pass; if preservation depended on this string, forgetting it would silently delete a
|
|
1280
|
+
* library's state.
|
|
1281
|
+
*
|
|
1282
|
+
* @internal
|
|
1283
|
+
*/
|
|
1284
|
+
sliceOwner = /* @__PURE__ */ new Map();
|
|
1285
|
+
/**
|
|
1286
|
+
* Slices unmounted by their owner, for a development-time diagnostic.
|
|
1287
|
+
*
|
|
1288
|
+
* @remarks
|
|
1289
|
+
* Decoration re-types the store, and after a disposer runs the widened type still claims
|
|
1290
|
+
* a slice that is gone. Reading it would hand a component `undefined` from a type that
|
|
1291
|
+
* promised a value, which is the silent failure this whole feature exists to remove.
|
|
1292
|
+
* Populated only for `dynamic` and `internal` slices: a `spec` slice removed by a
|
|
1293
|
+
* `replace*` was not promised by anyone's widened type.
|
|
1294
|
+
*
|
|
1295
|
+
* Bounded, because a long development session that mounts and disposes repeatedly would
|
|
1296
|
+
* otherwise accumulate an entry per cycle forever. The oldest is dropped: the diagnostic
|
|
1297
|
+
* exists for a slice someone has just stopped using, and a name disposed hundreds of
|
|
1298
|
+
* mounts ago is not the one being read by mistake. Maps to the owner, or `undefined`
|
|
1299
|
+
* when the library did not name itself.
|
|
1300
|
+
*
|
|
1301
|
+
* @internal
|
|
1302
|
+
*/
|
|
1303
|
+
disposedSlices = /* @__PURE__ */ new Map();
|
|
1304
|
+
/** @internal */
|
|
1305
|
+
registrationObservers = /* @__PURE__ */ new Set();
|
|
1306
|
+
/**
|
|
1307
|
+
* Changes accumulated inside the current public call, flushed once at its end.
|
|
1308
|
+
*
|
|
1309
|
+
* @internal
|
|
1310
|
+
*/
|
|
1311
|
+
pendingRegistrationChanges = null;
|
|
1312
|
+
/**
|
|
1313
|
+
* Depth of nested registration transactions.
|
|
1314
|
+
*
|
|
1315
|
+
* @remarks
|
|
1316
|
+
* `hotReplace` calls three `replace*` methods, and each of those registers repeatedly.
|
|
1317
|
+
* Only the outermost public entry point flushes, so one `hotReplace` produces one batch
|
|
1318
|
+
* spanning all three kinds rather than three batches of intermediate topology.
|
|
1319
|
+
*
|
|
1320
|
+
* @internal
|
|
1321
|
+
*/
|
|
1322
|
+
registrationDepth = 0;
|
|
1323
|
+
/** True while observers are being notified, so a re-entrant change is queued. @internal */
|
|
1324
|
+
notifyingRegistrations = !1;
|
|
1325
|
+
/** Batches produced by an observer's own registrations, drained after the current one. @internal */
|
|
1326
|
+
queuedRegistrationBatches = [];
|
|
977
1327
|
/**
|
|
978
1328
|
* Whether `__replayEvents()` is allowed.
|
|
979
1329
|
* Set from `spec.devtools.allowReplay`.
|
|
@@ -1000,6 +1350,8 @@ class x {
|
|
|
1000
1350
|
* signal that a reducer misbehaved.
|
|
1001
1351
|
*/
|
|
1002
1352
|
onReducerError;
|
|
1353
|
+
/** @internal */
|
|
1354
|
+
onSubscriberError;
|
|
1003
1355
|
/**
|
|
1004
1356
|
* `slice:channel:type` combinations already warned about for payload aliasing.
|
|
1005
1357
|
*
|
|
@@ -1089,13 +1441,15 @@ class x {
|
|
|
1089
1441
|
* Tracks processed events by fingerprint with timestamps for TTL-based deduplication.
|
|
1090
1442
|
*
|
|
1091
1443
|
* **Deduplication Behavior:**
|
|
1092
|
-
* - Events are fingerprinted
|
|
1444
|
+
* - Events are fingerprinted through the codec, so `Map`, `Set`, `Date`, `BigInt`, binary
|
|
1445
|
+
* and cyclic payloads all compare by content rather than collapsing to `{}`
|
|
1446
|
+
* - Plain-object keys are sorted, so key order is not content; array and `Map` order is
|
|
1093
1447
|
* - If an identical fingerprint is seen within the dedup window, it's skipped
|
|
1094
|
-
* - The window is
|
|
1448
|
+
* - The window is `dedupWindowMs`, which defaults to `0` (dedup off)
|
|
1095
1449
|
*
|
|
1096
1450
|
* **Limitations:**
|
|
1097
|
-
* -
|
|
1098
|
-
*
|
|
1451
|
+
* - A payload larger than the fingerprint node budget is never deduplicated, which is the
|
|
1452
|
+
* safe direction: a missed dedup costs a duplicate, a false one drops a real event
|
|
1099
1453
|
* - Legitimate rapid-fire identical events may be incorrectly deduplicated
|
|
1100
1454
|
* - The cache is bounded to 1000 entries with lazy pruning
|
|
1101
1455
|
*
|
|
@@ -1138,14 +1492,17 @@ class x {
|
|
|
1138
1492
|
* @public
|
|
1139
1493
|
*/
|
|
1140
1494
|
constructor(e) {
|
|
1141
|
-
if (this.name = e.name ?? "yoltra Store", this.reducerBus = new
|
|
1495
|
+
if (this.name = e.name ?? "yoltra Store", this.reducerBus = new G(), this.connectorBus = new J(), this.middleware = (e.middleware ?? []).map((t) => ({
|
|
1496
|
+
input: t,
|
|
1497
|
+
origin: "spec"
|
|
1498
|
+
})), 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.onSubscriberError = e.onSubscriberError, this.maxReduceDepth = e.maxReduceDepth ?? ye, this.maxTransitionsPerDrain = e.maxTransitionsPerDrain ?? 1 / 0, this.onCascade = e.onCascade, this.onRejected = e.onRejected, this.dedupConfig = {
|
|
1142
1499
|
windowMs: e.dedupWindowMs ?? 0,
|
|
1143
1500
|
maxCacheSize: 1e3
|
|
1144
|
-
}, Object.entries(e.reducer).forEach(([t,
|
|
1145
|
-
this.mountSlice(t,
|
|
1501
|
+
}, Object.entries(e.reducer).forEach(([t, n]) => {
|
|
1502
|
+
this.mountSlice(t, n, { preserveState: !1 });
|
|
1146
1503
|
}), e.effects?.length)
|
|
1147
1504
|
for (const t of e.effects)
|
|
1148
|
-
this.
|
|
1505
|
+
this.registerEffectWithOrigin(t, "spec");
|
|
1149
1506
|
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);
|
|
1150
1507
|
}
|
|
1151
1508
|
/**
|
|
@@ -1162,7 +1519,7 @@ class x {
|
|
|
1162
1519
|
* @public
|
|
1163
1520
|
*/
|
|
1164
1521
|
dispose() {
|
|
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;
|
|
1522
|
+
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.sliceOrigin.clear(), this.sliceOwner.clear(), this.disposedSlices.clear(), this.registrationObservers.clear(), this.pendingRegistrationChanges = null, this.queuedRegistrationBatches.length = 0, this.middleware.length = 0, this.changedPathSink = null;
|
|
1166
1523
|
}
|
|
1167
1524
|
/**
|
|
1168
1525
|
* Generates a fingerprint for an event for deduplication purposes.
|
|
@@ -1175,18 +1532,8 @@ class x {
|
|
|
1175
1532
|
*
|
|
1176
1533
|
* @internal
|
|
1177
1534
|
*/
|
|
1178
|
-
fingerprint(e, t,
|
|
1179
|
-
|
|
1180
|
-
try {
|
|
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}`;
|
|
1187
|
-
} catch {
|
|
1188
|
-
return `${n}::${Date.now()}::${Math.random()}`;
|
|
1189
|
-
}
|
|
1535
|
+
fingerprint(e, t, n) {
|
|
1536
|
+
return ue(e, t, n);
|
|
1190
1537
|
}
|
|
1191
1538
|
/**
|
|
1192
1539
|
* Checks if an event should be deduplicated.
|
|
@@ -1198,8 +1545,8 @@ class x {
|
|
|
1198
1545
|
* @internal
|
|
1199
1546
|
*/
|
|
1200
1547
|
shouldDedupe(e, t) {
|
|
1201
|
-
const
|
|
1202
|
-
return
|
|
1548
|
+
const n = Date.now(), r = this.processedEvents.get(e);
|
|
1549
|
+
return r !== void 0 && n - r < t ? (this.dedupCount++, !0) : (this.processedEvents.set(e, n), this.ensureCleanupTimer(), this.processedEvents.size > this.dedupConfig.maxCacheSize && this.pruneProcessedEvents(n), !1);
|
|
1203
1550
|
}
|
|
1204
1551
|
/**
|
|
1205
1552
|
* Starts the periodic prune interval if it isn't already running. Called when
|
|
@@ -1221,9 +1568,9 @@ class x {
|
|
|
1221
1568
|
* @internal
|
|
1222
1569
|
*/
|
|
1223
1570
|
pruneProcessedEvents(e) {
|
|
1224
|
-
const t = Math.max(this.dedupConfig.windowMs,
|
|
1225
|
-
for (const [
|
|
1226
|
-
|
|
1571
|
+
const t = Math.max(this.dedupConfig.windowMs, H), n = e - t * 2;
|
|
1572
|
+
for (const [r, i] of this.processedEvents)
|
|
1573
|
+
i < n && this.processedEvents.delete(r);
|
|
1227
1574
|
this.processedEvents.size === 0 && this.eventCleanupTimer !== null && (clearInterval(this.eventCleanupTimer), this.eventCleanupTimer = null);
|
|
1228
1575
|
}
|
|
1229
1576
|
/**
|
|
@@ -1237,14 +1584,14 @@ class x {
|
|
|
1237
1584
|
*
|
|
1238
1585
|
* @internal
|
|
1239
1586
|
*/
|
|
1240
|
-
reportCascade(e, t,
|
|
1587
|
+
reportCascade(e, t, n, r, i) {
|
|
1241
1588
|
console.error(
|
|
1242
|
-
`[yoltra] Cascade stopped: "${
|
|
1589
|
+
`[yoltra] Cascade stopped: "${n.channel}/${n.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 "${n.channel}/${n.type}" and what that emits in turn.` + (i.length > 0 ? ` Recent causal chain: ${i.join(" → ")} → (refused).` : "")
|
|
1243
1590
|
);
|
|
1244
1591
|
try {
|
|
1245
|
-
this.onCascade?.({ limit: e, limitValue: t, event:
|
|
1246
|
-
} catch (
|
|
1247
|
-
console.error("onCascade handler error:",
|
|
1592
|
+
this.onCascade?.({ limit: e, limitValue: t, event: n, depth: r, chain: i });
|
|
1593
|
+
} catch (s) {
|
|
1594
|
+
console.error("onCascade handler error:", s);
|
|
1248
1595
|
}
|
|
1249
1596
|
}
|
|
1250
1597
|
/**
|
|
@@ -1256,18 +1603,18 @@ class x {
|
|
|
1256
1603
|
* @internal
|
|
1257
1604
|
*/
|
|
1258
1605
|
async notifyEffects(e) {
|
|
1259
|
-
const t = this.scopedEmit(e),
|
|
1260
|
-
if (
|
|
1261
|
-
for (const
|
|
1606
|
+
const t = this.scopedEmit(e), n = `${String(e.channel)}::${String(e.type)}`, r = this.effects.get(n);
|
|
1607
|
+
if (r && r.size > 0)
|
|
1608
|
+
for (const i of [...r])
|
|
1262
1609
|
try {
|
|
1263
|
-
await
|
|
1264
|
-
} catch (
|
|
1265
|
-
console.error("Effect error:",
|
|
1610
|
+
await i.effect(e, this.getState, t);
|
|
1611
|
+
} catch (s) {
|
|
1612
|
+
console.error("Effect error:", s), this.onEffectError?.(s, e);
|
|
1266
1613
|
}
|
|
1267
|
-
for (const { effect:
|
|
1268
|
-
if (
|
|
1614
|
+
for (const { effect: i, when: s } of this.patternEffects)
|
|
1615
|
+
if ($(s, e))
|
|
1269
1616
|
try {
|
|
1270
|
-
await
|
|
1617
|
+
await i(e, this.getState, t);
|
|
1271
1618
|
} catch (l) {
|
|
1272
1619
|
console.error("Effect error:", l), this.onEffectError?.(l, e);
|
|
1273
1620
|
}
|
|
@@ -1286,9 +1633,9 @@ class x {
|
|
|
1286
1633
|
const t = {
|
|
1287
1634
|
id: e.id,
|
|
1288
1635
|
depth: e.depth ?? 0,
|
|
1289
|
-
chain: [...this.currentEvent?.chain ?? [], e.id].slice(-
|
|
1636
|
+
chain: [...this.currentEvent?.chain ?? [], e.id].slice(-W)
|
|
1290
1637
|
};
|
|
1291
|
-
return ((
|
|
1638
|
+
return ((n, r, i, s) => this.emitCaused(t, n, r, i, s));
|
|
1292
1639
|
}
|
|
1293
1640
|
/**
|
|
1294
1641
|
* Notifies event subscribers for a specific phase.
|
|
@@ -1301,13 +1648,15 @@ class x {
|
|
|
1301
1648
|
* @internal
|
|
1302
1649
|
*/
|
|
1303
1650
|
notifyEventSubscribers(e, t) {
|
|
1304
|
-
const
|
|
1305
|
-
if (
|
|
1306
|
-
for (const l of [...
|
|
1651
|
+
const n = `${String(e.channel)}::${String(e.type)}`, i = (t === "committed" ? this.committedEventSubscribers : t === "written" ? this.writtenEventSubscribers : this.uncommittedEventSubscribers).get(n);
|
|
1652
|
+
if (i?.size)
|
|
1653
|
+
for (const l of [...i])
|
|
1654
|
+
this.replaying && !l.duringReplay || this.invokeEventSubscriber(l.handler, e, t);
|
|
1307
1655
|
if (t === "written") return;
|
|
1308
|
-
const
|
|
1309
|
-
if (
|
|
1310
|
-
for (const l of [...
|
|
1656
|
+
const s = this.allEventSubscribers.get(n);
|
|
1657
|
+
if (s?.size)
|
|
1658
|
+
for (const l of [...s])
|
|
1659
|
+
this.replaying && !l.duringReplay || this.invokeEventSubscriber(l.handler, e, t);
|
|
1311
1660
|
}
|
|
1312
1661
|
/**
|
|
1313
1662
|
* Invokes a single event-subscription handler **fire-and-forget**: synchronous
|
|
@@ -1316,12 +1665,15 @@ class x {
|
|
|
1316
1665
|
*
|
|
1317
1666
|
* @internal
|
|
1318
1667
|
*/
|
|
1319
|
-
invokeEventSubscriber(e, t,
|
|
1668
|
+
invokeEventSubscriber(e, t, n) {
|
|
1669
|
+
const r = (i) => {
|
|
1670
|
+
console.error("Event subscription error:", i), this.onSubscriberError?.(i, t, n);
|
|
1671
|
+
};
|
|
1320
1672
|
try {
|
|
1321
|
-
const
|
|
1322
|
-
|
|
1323
|
-
} catch (
|
|
1324
|
-
|
|
1673
|
+
const i = e(t, this.getState, this.emit, n);
|
|
1674
|
+
i && typeof i.then == "function" && i.catch(r);
|
|
1675
|
+
} catch (i) {
|
|
1676
|
+
r(i);
|
|
1325
1677
|
}
|
|
1326
1678
|
}
|
|
1327
1679
|
/**
|
|
@@ -1375,11 +1727,11 @@ class x {
|
|
|
1375
1727
|
*
|
|
1376
1728
|
* @internal
|
|
1377
1729
|
*/
|
|
1378
|
-
stageSliceGuarded(e, t,
|
|
1730
|
+
stageSliceGuarded(e, t, n) {
|
|
1379
1731
|
try {
|
|
1380
|
-
return this.stageSlice(e, t,
|
|
1381
|
-
} catch (
|
|
1382
|
-
return console.error(`Reducer error in slice "${e}":`,
|
|
1732
|
+
return this.stageSlice(e, t, n);
|
|
1733
|
+
} catch (r) {
|
|
1734
|
+
return console.error(`Reducer error in slice "${e}":`, r), this.onReducerError?.(r, t, e), null;
|
|
1383
1735
|
}
|
|
1384
1736
|
}
|
|
1385
1737
|
/**
|
|
@@ -1398,13 +1750,13 @@ class x {
|
|
|
1398
1750
|
*
|
|
1399
1751
|
* @internal
|
|
1400
1752
|
*/
|
|
1401
|
-
stageSlice(e, t,
|
|
1402
|
-
const
|
|
1403
|
-
if (
|
|
1404
|
-
if (
|
|
1405
|
-
const
|
|
1406
|
-
if (
|
|
1407
|
-
const l = t.payload,
|
|
1753
|
+
stageSlice(e, t, n) {
|
|
1754
|
+
const r = this.state[e], i = this.reducers[e].reduce(r, t);
|
|
1755
|
+
if (Y(i)) return i;
|
|
1756
|
+
if (r === i) return null;
|
|
1757
|
+
const s = I(r, i);
|
|
1758
|
+
if (s.length === 0) return null;
|
|
1759
|
+
const l = t.payload, c = process.env.NODE_ENV !== "production" && l !== null && typeof l == "object" ? {
|
|
1408
1760
|
watch: l,
|
|
1409
1761
|
onFound: () => {
|
|
1410
1762
|
const a = `${e}:${t.channel}:${t.type}`;
|
|
@@ -1413,11 +1765,11 @@ class x {
|
|
|
1413
1765
|
));
|
|
1414
1766
|
}
|
|
1415
1767
|
} : void 0;
|
|
1416
|
-
return
|
|
1768
|
+
return n.push({
|
|
1417
1769
|
name: e,
|
|
1418
|
-
prev:
|
|
1419
|
-
frozen:
|
|
1420
|
-
leafPaths:
|
|
1770
|
+
prev: r,
|
|
1771
|
+
frozen: T(i, c),
|
|
1772
|
+
leafPaths: s
|
|
1421
1773
|
}), null;
|
|
1422
1774
|
}
|
|
1423
1775
|
/**
|
|
@@ -1441,26 +1793,26 @@ class x {
|
|
|
1441
1793
|
*/
|
|
1442
1794
|
commitStaged(e, t) {
|
|
1443
1795
|
if (e.length === 0) return !1;
|
|
1444
|
-
const
|
|
1445
|
-
for (const
|
|
1446
|
-
if (this.state =
|
|
1447
|
-
for (const
|
|
1448
|
-
for (const
|
|
1449
|
-
this.changedPathSink.push(
|
|
1450
|
-
for (const
|
|
1451
|
-
const
|
|
1452
|
-
for (const
|
|
1453
|
-
if (
|
|
1454
|
-
|
|
1796
|
+
const n = { ...this.state };
|
|
1797
|
+
for (const r of e) n[r.name] = r.frozen;
|
|
1798
|
+
if (this.state = n, this.changedPathSink)
|
|
1799
|
+
for (const r of e)
|
|
1800
|
+
for (const i of r.leafPaths)
|
|
1801
|
+
this.changedPathSink.push(i ? `${r.name}.${i}` : r.name);
|
|
1802
|
+
for (const r of e) {
|
|
1803
|
+
const i = /* @__PURE__ */ new Set();
|
|
1804
|
+
for (const s of r.leafPaths) {
|
|
1805
|
+
if (s === "") {
|
|
1806
|
+
i.add("");
|
|
1455
1807
|
continue;
|
|
1456
1808
|
}
|
|
1457
|
-
for (const l of
|
|
1809
|
+
for (const l of k.buildAncestorPaths(s)) i.add(l);
|
|
1458
1810
|
}
|
|
1459
|
-
for (const
|
|
1460
|
-
this.connectorBus.emitWith(
|
|
1461
|
-
oldValue: this.getAtPath(
|
|
1462
|
-
newValue: this.getAtPath(
|
|
1463
|
-
path:
|
|
1811
|
+
for (const s of i)
|
|
1812
|
+
this.connectorBus.emitWith(r.name, s, () => ({
|
|
1813
|
+
oldValue: this.getAtPath(r.prev, s),
|
|
1814
|
+
newValue: this.getAtPath(r.frozen, s),
|
|
1815
|
+
path: s,
|
|
1464
1816
|
// Provenance, built inside the same lazy factory as the values: a subscriber that
|
|
1465
1817
|
// needs to know why a value moved no longer has to mirror the cause into state and
|
|
1466
1818
|
// keep it there twice.
|
|
@@ -1482,65 +1834,68 @@ class x {
|
|
|
1482
1834
|
* @public
|
|
1483
1835
|
*/
|
|
1484
1836
|
__devtoolsIntrospect() {
|
|
1485
|
-
const e = Object.keys(this.reducers).map((
|
|
1486
|
-
const
|
|
1487
|
-
return {
|
|
1837
|
+
const e = Object.keys(this.reducers).map((c) => {
|
|
1838
|
+
const a = this.patternReducers.get(c);
|
|
1839
|
+
return {
|
|
1840
|
+
name: c,
|
|
1841
|
+
when: a,
|
|
1842
|
+
origin: this.sliceOrigin.get(c) ?? "spec",
|
|
1843
|
+
owner: this.sliceOwner.get(c)
|
|
1844
|
+
};
|
|
1488
1845
|
}), t = [];
|
|
1489
|
-
for (const [
|
|
1490
|
-
if (
|
|
1491
|
-
const [
|
|
1492
|
-
for (const
|
|
1493
|
-
const
|
|
1494
|
-
t.push({
|
|
1846
|
+
for (const [c, a] of this.effects) {
|
|
1847
|
+
if (a.size === 0) continue;
|
|
1848
|
+
const [d, f] = c.split("::");
|
|
1849
|
+
for (const u of a) {
|
|
1850
|
+
const p = this.effectMeta.get(u.effect);
|
|
1851
|
+
t.push({
|
|
1852
|
+
channel: d,
|
|
1853
|
+
type: f,
|
|
1854
|
+
name: p?.name,
|
|
1855
|
+
description: p?.description,
|
|
1856
|
+
origin: u.origin
|
|
1857
|
+
});
|
|
1495
1858
|
}
|
|
1496
1859
|
}
|
|
1497
|
-
for (const
|
|
1498
|
-
const
|
|
1860
|
+
for (const c of this.patternEffects) {
|
|
1861
|
+
const a = this.effectMeta.get(c.effect);
|
|
1499
1862
|
t.push({
|
|
1500
1863
|
channel: "*",
|
|
1501
1864
|
type: "*",
|
|
1502
|
-
name:
|
|
1503
|
-
description:
|
|
1865
|
+
name: a?.name,
|
|
1866
|
+
description: a?.description,
|
|
1867
|
+
origin: c.origin
|
|
1504
1868
|
});
|
|
1505
1869
|
}
|
|
1506
|
-
const s = [];
|
|
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
1870
|
const n = [];
|
|
1514
|
-
for (const
|
|
1515
|
-
|
|
1516
|
-
|
|
1871
|
+
for (const { input: c, origin: a } of this.middleware)
|
|
1872
|
+
typeof c == "function" ? n.push({ name: c.name || void 0, origin: a }) : n.push({
|
|
1873
|
+
name: c.meta?.name,
|
|
1874
|
+
description: c.meta?.description,
|
|
1875
|
+
when: c.when,
|
|
1876
|
+
origin: a
|
|
1877
|
+
});
|
|
1517
1878
|
const r = [];
|
|
1518
|
-
for (const
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
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" });
|
|
1535
|
-
}
|
|
1536
|
-
const c = this.listeners.size;
|
|
1879
|
+
for (const c of this.connectorBus.__introspect())
|
|
1880
|
+
for (let a = 0; a < c.count; a++)
|
|
1881
|
+
r.push({ reducer: c.channel, property: c.type });
|
|
1882
|
+
const i = [], s = (c, a) => {
|
|
1883
|
+
for (const [d, f] of c) {
|
|
1884
|
+
if (f.size === 0) continue;
|
|
1885
|
+
const [u, p] = d.split("::");
|
|
1886
|
+
for (const h of f)
|
|
1887
|
+
i.push({ channel: u, type: p, phase: a, duringReplay: h.duringReplay });
|
|
1888
|
+
}
|
|
1889
|
+
};
|
|
1890
|
+
s(this.committedEventSubscribers, "committed"), s(this.uncommittedEventSubscribers, "uncommitted"), s(this.writtenEventSubscribers, "written"), s(this.allEventSubscribers, "all");
|
|
1891
|
+
const l = this.listeners.size;
|
|
1537
1892
|
return {
|
|
1538
1893
|
reducers: e,
|
|
1539
1894
|
effects: t,
|
|
1540
|
-
middleware:
|
|
1541
|
-
atomic:
|
|
1542
|
-
event:
|
|
1543
|
-
coarse:
|
|
1895
|
+
middleware: n,
|
|
1896
|
+
atomic: r,
|
|
1897
|
+
event: i,
|
|
1898
|
+
coarse: l,
|
|
1544
1899
|
dedupHits: this.dedupCount,
|
|
1545
1900
|
queueDepth: this.reduceQueue.length + this.inFlightEffects
|
|
1546
1901
|
};
|
|
@@ -1565,36 +1920,50 @@ class x {
|
|
|
1565
1920
|
throw new Error(
|
|
1566
1921
|
"[yoltra] External state apply (time-travel) is disabled. Enable it with createStore({ devtools: { allowReplay: true } })"
|
|
1567
1922
|
);
|
|
1568
|
-
const t = this.
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1923
|
+
const t = this.replaying;
|
|
1924
|
+
this.replaying = !0;
|
|
1925
|
+
try {
|
|
1926
|
+
return this.applyExternalStateInner(e);
|
|
1927
|
+
} finally {
|
|
1928
|
+
this.replaying = t;
|
|
1929
|
+
}
|
|
1930
|
+
}
|
|
1931
|
+
/**
|
|
1932
|
+
* The body of {@link __applyExternalState}, with the replay flag already set.
|
|
1933
|
+
*
|
|
1934
|
+
* @internal
|
|
1935
|
+
*/
|
|
1936
|
+
applyExternalStateInner(e) {
|
|
1937
|
+
const t = this.state, n = e, r = { ...this.state };
|
|
1938
|
+
let i = !1;
|
|
1939
|
+
Object.keys(this.reducers).forEach((s) => {
|
|
1940
|
+
const l = t?.[s], c = n?.[s];
|
|
1941
|
+
if (c === void 0) {
|
|
1942
|
+
process.env.NODE_ENV !== "production" && (this.sliceOrigin.get(s) ?? "spec") === "spec" && console.warn(
|
|
1574
1943
|
`[yoltra] External state is missing slice "${String(
|
|
1575
|
-
|
|
1944
|
+
s
|
|
1576
1945
|
)}"; retaining its current value. Time-travel snapshots should contain all slices.`
|
|
1577
1946
|
);
|
|
1578
1947
|
return;
|
|
1579
1948
|
}
|
|
1580
|
-
if (l ===
|
|
1581
|
-
const a =
|
|
1582
|
-
|
|
1583
|
-
const
|
|
1584
|
-
if (
|
|
1585
|
-
const
|
|
1586
|
-
for (const
|
|
1587
|
-
if (
|
|
1588
|
-
|
|
1949
|
+
if (l === c) return;
|
|
1950
|
+
const a = T(c);
|
|
1951
|
+
r[s] = a, i = !0;
|
|
1952
|
+
const d = I(l, c);
|
|
1953
|
+
if (d.length === 0) return;
|
|
1954
|
+
const f = /* @__PURE__ */ new Set();
|
|
1955
|
+
for (const u of d) {
|
|
1956
|
+
if (u === "") {
|
|
1957
|
+
f.add("");
|
|
1589
1958
|
continue;
|
|
1590
1959
|
}
|
|
1591
|
-
for (const p of
|
|
1960
|
+
for (const p of k.buildAncestorPaths(u)) f.add(p);
|
|
1592
1961
|
}
|
|
1593
|
-
for (const
|
|
1594
|
-
const p = this.getAtPath(l,
|
|
1595
|
-
this.connectorBus.emit(
|
|
1962
|
+
for (const u of f) {
|
|
1963
|
+
const p = this.getAtPath(l, u), h = this.getAtPath(a, u);
|
|
1964
|
+
this.connectorBus.emit(s, u, { oldValue: p, newValue: h, path: u });
|
|
1596
1965
|
}
|
|
1597
|
-
}),
|
|
1966
|
+
}), i && (this.state = r), i && this.listeners.forEach((s) => s());
|
|
1598
1967
|
}
|
|
1599
1968
|
/**
|
|
1600
1969
|
* Replays a sequence of events from a snapshot through reducers and event
|
|
@@ -1613,25 +1982,39 @@ class x {
|
|
|
1613
1982
|
throw new Error(
|
|
1614
1983
|
"[yoltra] Event replay is disabled. Enable it with createStore({ devtools: { allowReplay: true } })"
|
|
1615
1984
|
);
|
|
1985
|
+
const n = this.replaying;
|
|
1986
|
+
this.replaying = !0;
|
|
1987
|
+
try {
|
|
1988
|
+
this.replayEventsInner(e, t);
|
|
1989
|
+
} finally {
|
|
1990
|
+
this.replaying = n;
|
|
1991
|
+
}
|
|
1992
|
+
}
|
|
1993
|
+
/**
|
|
1994
|
+
* The body of {@link __replayEvents}, with the replay flag already set.
|
|
1995
|
+
*
|
|
1996
|
+
* @internal
|
|
1997
|
+
*/
|
|
1998
|
+
replayEventsInner(e, t) {
|
|
1616
1999
|
this.__applyExternalState(e);
|
|
1617
|
-
for (const
|
|
1618
|
-
const
|
|
1619
|
-
this.stagingSink =
|
|
1620
|
-
let
|
|
2000
|
+
for (const n of t) {
|
|
2001
|
+
const r = n, i = [];
|
|
2002
|
+
this.stagingSink = i;
|
|
2003
|
+
let s = null;
|
|
1621
2004
|
try {
|
|
1622
|
-
this.reducerBus.emit(
|
|
1623
|
-
for (const [
|
|
1624
|
-
if (
|
|
1625
|
-
if (
|
|
1626
|
-
const
|
|
1627
|
-
|
|
2005
|
+
this.reducerBus.emit(r.channel, r.type, r.payload, r), s = this.stagedRejection;
|
|
2006
|
+
for (const [c, a] of this.patternReducers) {
|
|
2007
|
+
if (s !== null) break;
|
|
2008
|
+
if ($(a, r)) {
|
|
2009
|
+
const d = this.stageSliceGuarded(c, r, i);
|
|
2010
|
+
d !== null && (s = d);
|
|
1628
2011
|
}
|
|
1629
2012
|
}
|
|
1630
2013
|
} finally {
|
|
1631
2014
|
this.stagingSink = null, this.stagedRejection = null, this.stagedRejectedBy = "";
|
|
1632
2015
|
}
|
|
1633
|
-
const l =
|
|
1634
|
-
this.notifyEventSubscribers(
|
|
2016
|
+
const l = s === null && this.commitStaged(i, r);
|
|
2017
|
+
this.notifyEventSubscribers(r, "committed"), l && (this.notifyEventSubscribers(r, "written"), this.listeners.forEach((c) => c()));
|
|
1635
2018
|
}
|
|
1636
2019
|
}
|
|
1637
2020
|
/**
|
|
@@ -1677,8 +2060,8 @@ class x {
|
|
|
1677
2060
|
*
|
|
1678
2061
|
* @public
|
|
1679
2062
|
*/
|
|
1680
|
-
async emit(e, t,
|
|
1681
|
-
return this.emitCaused(null, e, t,
|
|
2063
|
+
async emit(e, t, n, r) {
|
|
2064
|
+
return this.emitCaused(null, e, t, n, r);
|
|
1682
2065
|
}
|
|
1683
2066
|
/**
|
|
1684
2067
|
* The real emit, with an explicitly supplied cause.
|
|
@@ -1692,45 +2075,45 @@ class x {
|
|
|
1692
2075
|
*
|
|
1693
2076
|
* @internal
|
|
1694
2077
|
*/
|
|
1695
|
-
async emitCaused(e, t,
|
|
1696
|
-
const
|
|
1697
|
-
if (
|
|
1698
|
-
const p =
|
|
1699
|
-
if (this.shouldDedupe(
|
|
1700
|
-
return
|
|
2078
|
+
async emitCaused(e, t, n, r, i) {
|
|
2079
|
+
const s = i?.dedupKey, l = this.dedupConfig.windowMs;
|
|
2080
|
+
if (i?.skipDedup !== !0 && (l > 0 || s !== void 0)) {
|
|
2081
|
+
const p = s !== void 0 && l <= 0 ? H : l, h = s !== void 0 ? `${t}::${n}::#${s}` : this.fingerprint(t, n, r);
|
|
2082
|
+
if (this.shouldDedupe(h, p))
|
|
2083
|
+
return we;
|
|
1701
2084
|
}
|
|
1702
|
-
const
|
|
1703
|
-
if (a !== null &&
|
|
2085
|
+
const c = i?.id ?? this.idFactory(), a = this.currentEvent ?? e, d = a === null ? 0 : a.depth + 1;
|
|
2086
|
+
if (a !== null && d > this.maxReduceDepth)
|
|
1704
2087
|
return this.reportCascade(
|
|
1705
2088
|
"maxReduceDepth",
|
|
1706
2089
|
this.maxReduceDepth,
|
|
1707
2090
|
{
|
|
1708
2091
|
channel: t,
|
|
1709
|
-
type:
|
|
1710
|
-
payload:
|
|
1711
|
-
id:
|
|
1712
|
-
...
|
|
2092
|
+
type: n,
|
|
2093
|
+
payload: r,
|
|
2094
|
+
id: c,
|
|
2095
|
+
...i?.meta !== void 0 ? { meta: i.meta } : {},
|
|
1713
2096
|
parentId: a.id,
|
|
1714
|
-
depth:
|
|
2097
|
+
depth: d
|
|
1715
2098
|
},
|
|
1716
|
-
|
|
2099
|
+
d,
|
|
1717
2100
|
a.chain
|
|
1718
|
-
),
|
|
1719
|
-
let
|
|
1720
|
-
const
|
|
1721
|
-
|
|
2101
|
+
), F;
|
|
2102
|
+
let f;
|
|
2103
|
+
const u = new Promise((p) => {
|
|
2104
|
+
f = p;
|
|
1722
2105
|
});
|
|
1723
2106
|
return this.reduceQueue.push({
|
|
1724
2107
|
channel: t,
|
|
1725
|
-
type:
|
|
1726
|
-
payload:
|
|
1727
|
-
id:
|
|
1728
|
-
meta:
|
|
1729
|
-
resolve:
|
|
2108
|
+
type: n,
|
|
2109
|
+
payload: r,
|
|
2110
|
+
id: c,
|
|
2111
|
+
meta: i?.meta,
|
|
2112
|
+
resolve: f,
|
|
1730
2113
|
// Only carried for caused events, so a root event's object stays byte-identical to one
|
|
1731
2114
|
// built before causality existed — the same rule `meta` follows.
|
|
1732
|
-
...a !== null ? { parentId: a.id, depth:
|
|
1733
|
-
}), this.drainReduce(),
|
|
2115
|
+
...a !== null ? { parentId: a.id, depth: d, chain: a.chain } : {}
|
|
2116
|
+
}), this.drainReduce(), u;
|
|
1734
2117
|
}
|
|
1735
2118
|
/**
|
|
1736
2119
|
* Drains the reduce queue **synchronously**. For each event it runs middleware,
|
|
@@ -1747,47 +2130,47 @@ class x {
|
|
|
1747
2130
|
this.isReducing = !0, this.transitionsThisDrain = 0;
|
|
1748
2131
|
try {
|
|
1749
2132
|
for (; this.reduceQueue.length > 0; ) {
|
|
1750
|
-
const e = this.reduceQueue.shift(), { channel: t, type:
|
|
2133
|
+
const e = this.reduceQueue.shift(), { channel: t, type: n, payload: r, id: i, meta: s, resolve: l, parentId: c, depth: a, chain: d } = e, f = {
|
|
1751
2134
|
channel: t,
|
|
1752
|
-
type:
|
|
1753
|
-
payload:
|
|
1754
|
-
id:
|
|
1755
|
-
...
|
|
1756
|
-
...
|
|
2135
|
+
type: n,
|
|
2136
|
+
payload: r,
|
|
2137
|
+
id: i,
|
|
2138
|
+
...s !== void 0 ? { meta: s } : {},
|
|
2139
|
+
...c !== void 0 ? { parentId: c, depth: a } : {}
|
|
1757
2140
|
};
|
|
1758
|
-
if (
|
|
2141
|
+
if (c !== void 0 && ++this.transitionsThisDrain > this.maxTransitionsPerDrain) {
|
|
1759
2142
|
this.reportCascade(
|
|
1760
2143
|
"maxTransitionsPerDrain",
|
|
1761
2144
|
this.maxTransitionsPerDrain,
|
|
1762
|
-
|
|
2145
|
+
f,
|
|
1763
2146
|
a,
|
|
1764
|
-
|
|
1765
|
-
), l(
|
|
2147
|
+
d
|
|
2148
|
+
), l(F);
|
|
1766
2149
|
continue;
|
|
1767
2150
|
}
|
|
1768
2151
|
this.currentEvent = {
|
|
1769
|
-
id:
|
|
2152
|
+
id: i,
|
|
1770
2153
|
depth: a ?? 0,
|
|
1771
|
-
chain: [...
|
|
2154
|
+
chain: [...d ?? [], i].slice(-W)
|
|
1772
2155
|
};
|
|
1773
|
-
const
|
|
1774
|
-
|
|
1775
|
-
const
|
|
1776
|
-
let
|
|
2156
|
+
const u = this.instrumentObservers.size > 0, p = u ? this.state : void 0, h = u ? [] : void 0;
|
|
2157
|
+
h !== void 0 && (this.changedPathSink = h);
|
|
2158
|
+
const y = u ? K() : 0;
|
|
2159
|
+
let w = me;
|
|
1777
2160
|
try {
|
|
1778
|
-
|
|
2161
|
+
w = this.applyEventSync(f);
|
|
1779
2162
|
} catch (g) {
|
|
1780
2163
|
console.error("Emit reduce error:", g);
|
|
1781
2164
|
} finally {
|
|
1782
|
-
|
|
2165
|
+
u && (this.changedPathSink = null), this.currentEvent = null;
|
|
1783
2166
|
}
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
2167
|
+
u && this.emitInstrumentation(
|
|
2168
|
+
f,
|
|
2169
|
+
w,
|
|
2170
|
+
h ?? [],
|
|
1788
2171
|
p,
|
|
1789
|
-
|
|
1790
|
-
), this.runEventEffects(
|
|
2172
|
+
K() - y
|
|
2173
|
+
), this.runEventEffects(f, w, l);
|
|
1791
2174
|
}
|
|
1792
2175
|
} finally {
|
|
1793
2176
|
this.isReducing = !1;
|
|
@@ -1805,45 +2188,56 @@ class x {
|
|
|
1805
2188
|
* @internal
|
|
1806
2189
|
*/
|
|
1807
2190
|
applyEventSync(e) {
|
|
1808
|
-
for (const
|
|
1809
|
-
const l =
|
|
1810
|
-
if (
|
|
1811
|
-
const
|
|
2191
|
+
for (const { input: s } of this.middleware) {
|
|
2192
|
+
const l = A(s);
|
|
2193
|
+
if (!$(l, e)) continue;
|
|
2194
|
+
const c = he(s);
|
|
1812
2195
|
let a;
|
|
1813
2196
|
try {
|
|
1814
|
-
a =
|
|
2197
|
+
a = c(this.state, e, this.emit), process.env.NODE_ENV !== "production" && typeof a?.then == "function" && console.error(
|
|
1815
2198
|
`[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.`
|
|
1816
2199
|
);
|
|
1817
|
-
} catch (
|
|
1818
|
-
console.error(
|
|
2200
|
+
} catch (d) {
|
|
2201
|
+
console.error(
|
|
2202
|
+
`[yoltra] Middleware threw for "${e.channel}/${e.type}"; the event was vetoed and did not reach any reducer.`,
|
|
2203
|
+
d
|
|
2204
|
+
), a = !1;
|
|
2205
|
+
}
|
|
2206
|
+
if (a === !1) {
|
|
2207
|
+
this.notifyEventSubscribers(e, "uncommitted");
|
|
2208
|
+
const d = typeof s == "function" ? s.name || void 0 : s.meta?.name;
|
|
2209
|
+
return Object.freeze({
|
|
2210
|
+
committed: !1,
|
|
2211
|
+
written: !1,
|
|
2212
|
+
reason: "vetoed",
|
|
2213
|
+
...d !== void 0 && d !== "" ? { vetoedBy: d } : {}
|
|
2214
|
+
});
|
|
1819
2215
|
}
|
|
1820
|
-
if (!a)
|
|
1821
|
-
return this.notifyEventSubscribers(e, "uncommitted"), S;
|
|
1822
2216
|
}
|
|
1823
2217
|
const t = [];
|
|
1824
2218
|
this.stagingSink = t;
|
|
1825
|
-
let
|
|
2219
|
+
let n = null, r = "";
|
|
1826
2220
|
try {
|
|
1827
2221
|
this.reducerBus.emit(
|
|
1828
2222
|
e.channel,
|
|
1829
2223
|
e.type,
|
|
1830
2224
|
e.payload,
|
|
1831
2225
|
e
|
|
1832
|
-
),
|
|
1833
|
-
for (const [
|
|
1834
|
-
if (
|
|
1835
|
-
if (
|
|
1836
|
-
const
|
|
1837
|
-
|
|
2226
|
+
), n = this.stagedRejection, r = this.stagedRejectedBy;
|
|
2227
|
+
for (const [s, l] of this.patternReducers) {
|
|
2228
|
+
if (n !== null) break;
|
|
2229
|
+
if ($(l, e)) {
|
|
2230
|
+
const c = this.stageSliceGuarded(s, e, t);
|
|
2231
|
+
c !== null && (n = c, r = s);
|
|
1838
2232
|
}
|
|
1839
2233
|
}
|
|
1840
2234
|
} finally {
|
|
1841
2235
|
this.stagingSink = null, this.stagedRejection = null, this.stagedRejectedBy = "";
|
|
1842
2236
|
}
|
|
1843
|
-
if (
|
|
1844
|
-
return this.onRejected?.(
|
|
1845
|
-
const
|
|
1846
|
-
return this.notifyEventSubscribers(e, "committed"),
|
|
2237
|
+
if (n !== null)
|
|
2238
|
+
return this.onRejected?.(n, e, r), this.notifyEventSubscribers(e, "committed"), { committed: !0, written: !1, rejected: n };
|
|
2239
|
+
const i = this.commitStaged(t, e);
|
|
2240
|
+
return this.notifyEventSubscribers(e, "committed"), i && (this.notifyEventSubscribers(e, "written"), this.listeners.forEach((s) => s())), i ? Ee : be;
|
|
1847
2241
|
}
|
|
1848
2242
|
/**
|
|
1849
2243
|
* Runs a single committed event's effects as an **independent async task**,
|
|
@@ -1853,14 +2247,14 @@ class x {
|
|
|
1853
2247
|
*
|
|
1854
2248
|
* @internal
|
|
1855
2249
|
*/
|
|
1856
|
-
async runEventEffects(e, t,
|
|
2250
|
+
async runEventEffects(e, t, n) {
|
|
1857
2251
|
this.inFlightEffects++;
|
|
1858
2252
|
try {
|
|
1859
2253
|
t.committed && await this.notifyEffects(e);
|
|
1860
|
-
} catch (
|
|
1861
|
-
console.error("Effect error:",
|
|
2254
|
+
} catch (r) {
|
|
2255
|
+
console.error("Effect error:", r);
|
|
1862
2256
|
} finally {
|
|
1863
|
-
this.inFlightEffects--,
|
|
2257
|
+
this.inFlightEffects--, n(t);
|
|
1864
2258
|
}
|
|
1865
2259
|
}
|
|
1866
2260
|
/**
|
|
@@ -1881,11 +2275,11 @@ class x {
|
|
|
1881
2275
|
*
|
|
1882
2276
|
* @internal
|
|
1883
2277
|
*/
|
|
1884
|
-
emitInstrumentation(e, t,
|
|
1885
|
-
const
|
|
1886
|
-
for (const a of
|
|
1887
|
-
|
|
1888
|
-
const
|
|
2278
|
+
emitInstrumentation(e, t, n, r, i) {
|
|
2279
|
+
const s = {}, l = {};
|
|
2280
|
+
for (const a of n)
|
|
2281
|
+
s[a] = this.getAtPath(r, a), l[a] = this.getAtPath(this.state, a);
|
|
2282
|
+
const c = {
|
|
1889
2283
|
event: {
|
|
1890
2284
|
id: e.id,
|
|
1891
2285
|
channel: e.channel,
|
|
@@ -1896,19 +2290,19 @@ class x {
|
|
|
1896
2290
|
...e.meta !== void 0 ? { meta: e.meta } : {}
|
|
1897
2291
|
},
|
|
1898
2292
|
committed: t.committed,
|
|
1899
|
-
changedPaths:
|
|
1900
|
-
prevValues:
|
|
2293
|
+
changedPaths: n,
|
|
2294
|
+
prevValues: s,
|
|
1901
2295
|
nextValues: l,
|
|
1902
|
-
reduceTimeMs:
|
|
2296
|
+
reduceTimeMs: i,
|
|
1903
2297
|
// Present only when a reducer refused, so an observer can tell a refusal from a veto —
|
|
1904
2298
|
// identical in state, entirely different in cause.
|
|
1905
2299
|
...t.rejected !== void 0 ? { rejected: t.rejected } : {}
|
|
1906
2300
|
};
|
|
1907
2301
|
for (const a of [...this.instrumentObservers])
|
|
1908
2302
|
try {
|
|
1909
|
-
a(
|
|
1910
|
-
} catch (
|
|
1911
|
-
console.error("Instrumentation observer error:",
|
|
2303
|
+
a(c);
|
|
2304
|
+
} catch (d) {
|
|
2305
|
+
console.error("Instrumentation observer error:", d);
|
|
1912
2306
|
}
|
|
1913
2307
|
}
|
|
1914
2308
|
/**
|
|
@@ -1939,13 +2333,209 @@ class x {
|
|
|
1939
2333
|
*
|
|
1940
2334
|
* @public
|
|
1941
2335
|
*/
|
|
1942
|
-
connect(e, t,
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
2336
|
+
connect(e, t, n) {
|
|
2337
|
+
if (process.env.NODE_ENV !== "production" && this.disposedSlices.has(e.reducer)) {
|
|
2338
|
+
const i = this.disposedSlices.get(e.reducer);
|
|
2339
|
+
throw new Error(
|
|
2340
|
+
`[yoltra] Slice "${String(e.reducer)}" was unmounted by its owner${i === void 0 ? "" : ` (${i})`}. Hooks and subscriptions widened for it are no longer valid.`
|
|
2341
|
+
);
|
|
2342
|
+
}
|
|
2343
|
+
const r = this.connectorBus.on(e.reducer, e.property, t);
|
|
2344
|
+
if (n?.immediate === !0) {
|
|
2345
|
+
const i = this.state[e.reducer], s = e.property.includes("*") ? "" : e.property;
|
|
2346
|
+
t({ oldValue: void 0, newValue: this.getAtPath(i, s), path: s });
|
|
2347
|
+
}
|
|
2348
|
+
return r;
|
|
2349
|
+
}
|
|
2350
|
+
/**
|
|
2351
|
+
* Subscribe to reducer, middleware and effect registrations.
|
|
2352
|
+
*
|
|
2353
|
+
* Delivered as an array, one batch per public call: `replaceReducers` unmounts and then
|
|
2354
|
+
* remounts, and a per-change observer would see a spurious unmount of a slice that is only
|
|
2355
|
+
* being updated. Observers run after the state broadcast, and a registration made by an
|
|
2356
|
+
* observer is queued rather than delivered re-entrantly.
|
|
2357
|
+
*
|
|
2358
|
+
* Replay never produces a change, so there is no `duringReplay` option here. `dispose()`
|
|
2359
|
+
* fires nothing.
|
|
2360
|
+
*
|
|
2361
|
+
* @param observer - Receives one batch per registration change.
|
|
2362
|
+
* @param options - `emitCurrent` synthesizes a `'mounted'` batch for everything already
|
|
2363
|
+
* installed, delivered synchronously before this call returns, carrying each registration's
|
|
2364
|
+
* real origin rather than a synthetic marker.
|
|
2365
|
+
* @returns Unsubscribe function.
|
|
2366
|
+
*
|
|
2367
|
+
* @example
|
|
2368
|
+
* ```ts
|
|
2369
|
+
* const off = store.onRegistrationChange((changes) => {
|
|
2370
|
+
* for (const c of changes) {
|
|
2371
|
+
* console.log(c.op, c.kind, c.name, c.origin);
|
|
2372
|
+
* }
|
|
2373
|
+
* }, { emitCurrent: true });
|
|
2374
|
+
* off();
|
|
2375
|
+
* ```
|
|
2376
|
+
*
|
|
2377
|
+
* @public
|
|
2378
|
+
*/
|
|
2379
|
+
onRegistrationChange(e, t) {
|
|
2380
|
+
if (this.registrationObservers.add(e), t?.emitCurrent === !0) {
|
|
2381
|
+
const n = this.describeCurrentRegistrations();
|
|
2382
|
+
if (n.length > 0) {
|
|
2383
|
+
const r = this.notifyingRegistrations;
|
|
2384
|
+
this.notifyingRegistrations = !0;
|
|
2385
|
+
try {
|
|
2386
|
+
this.invokeRegistrationObserver(e, n);
|
|
2387
|
+
} finally {
|
|
2388
|
+
this.notifyingRegistrations = r;
|
|
2389
|
+
}
|
|
2390
|
+
r || this.drainQueuedRegistrationBatches();
|
|
2391
|
+
}
|
|
2392
|
+
}
|
|
2393
|
+
return () => {
|
|
2394
|
+
this.registrationObservers.delete(e);
|
|
2395
|
+
};
|
|
2396
|
+
}
|
|
2397
|
+
/**
|
|
2398
|
+
* Everything currently installed, as `"mounted"` changes.
|
|
2399
|
+
*
|
|
2400
|
+
* @internal
|
|
2401
|
+
*/
|
|
2402
|
+
describeCurrentRegistrations() {
|
|
2403
|
+
const e = [];
|
|
2404
|
+
for (const t of Object.keys(this.reducers))
|
|
2405
|
+
e.push({
|
|
2406
|
+
kind: "reducer",
|
|
2407
|
+
op: "mounted",
|
|
2408
|
+
name: t,
|
|
2409
|
+
// The real origin, never a synthetic "existing" marker. Filtering on provenance is
|
|
2410
|
+
// the main thing an observer does, and a snapshot that lied about it would break
|
|
2411
|
+
// exactly the registrations that were already there.
|
|
2412
|
+
origin: this.sliceOrigin.get(t) ?? "spec",
|
|
2413
|
+
owner: this.sliceOwner.get(t),
|
|
2414
|
+
when: this.patternReducers.get(t),
|
|
2415
|
+
// From this observer's point of view the state exists; it never saw a prior value.
|
|
2416
|
+
state: "initialized",
|
|
2417
|
+
dispatch: this.patternReducers.has(t) ? "pattern" : "keyed"
|
|
2418
|
+
});
|
|
2419
|
+
for (const t of this.middleware) {
|
|
2420
|
+
const n = typeof t.input == "function" ? void 0 : t.input.meta;
|
|
2421
|
+
e.push({
|
|
2422
|
+
kind: "middleware",
|
|
2423
|
+
op: "mounted",
|
|
2424
|
+
name: n?.name ?? (typeof t.input == "function" ? t.input.name : void 0),
|
|
2425
|
+
description: n?.description,
|
|
2426
|
+
origin: t.origin,
|
|
2427
|
+
when: A(t.input),
|
|
2428
|
+
dispatch: "pattern"
|
|
2429
|
+
});
|
|
2430
|
+
}
|
|
2431
|
+
for (const [t, n] of this.effects) {
|
|
2432
|
+
const [r, i] = t.split("::");
|
|
2433
|
+
for (const s of n)
|
|
2434
|
+
e.push({
|
|
2435
|
+
kind: "effect",
|
|
2436
|
+
op: "mounted",
|
|
2437
|
+
name: this.effectMeta.get(s.effect)?.name,
|
|
2438
|
+
description: this.effectMeta.get(s.effect)?.description,
|
|
2439
|
+
origin: s.origin,
|
|
2440
|
+
when: { keys: [[r, i]] },
|
|
2441
|
+
dispatch: "keyed"
|
|
2442
|
+
});
|
|
1947
2443
|
}
|
|
1948
|
-
|
|
2444
|
+
for (const t of this.patternEffects)
|
|
2445
|
+
e.push({
|
|
2446
|
+
kind: "effect",
|
|
2447
|
+
op: "mounted",
|
|
2448
|
+
name: this.effectMeta.get(t.effect)?.name,
|
|
2449
|
+
description: this.effectMeta.get(t.effect)?.description,
|
|
2450
|
+
origin: t.origin,
|
|
2451
|
+
when: t.when,
|
|
2452
|
+
dispatch: "pattern"
|
|
2453
|
+
});
|
|
2454
|
+
return e;
|
|
2455
|
+
}
|
|
2456
|
+
/**
|
|
2457
|
+
* Runs `fn` as one registration transaction, flushing a single batch at the outermost end.
|
|
2458
|
+
*
|
|
2459
|
+
* @internal
|
|
2460
|
+
*/
|
|
2461
|
+
inRegistrationTransaction(e) {
|
|
2462
|
+
this.registrationDepth += 1;
|
|
2463
|
+
try {
|
|
2464
|
+
return e();
|
|
2465
|
+
} finally {
|
|
2466
|
+
this.registrationDepth -= 1, this.registrationDepth === 0 && this.flushRegistrationChanges();
|
|
2467
|
+
}
|
|
2468
|
+
}
|
|
2469
|
+
/**
|
|
2470
|
+
* Records a change, to be delivered when the current transaction ends.
|
|
2471
|
+
*
|
|
2472
|
+
* @remarks
|
|
2473
|
+
* Guarded on observer count **before** anything is allocated. These call sites run inside
|
|
2474
|
+
* `createStore`, so a twenty-slice store with nobody listening must build no objects and
|
|
2475
|
+
* no arrays at all - the same discipline `emitInstrumentation` already follows.
|
|
2476
|
+
*
|
|
2477
|
+
* @internal
|
|
2478
|
+
*/
|
|
2479
|
+
recordRegistrationChange(e) {
|
|
2480
|
+
this.registrationObservers.size !== 0 && ((this.pendingRegistrationChanges ??= []).push(e()), this.registrationDepth === 0 && this.flushRegistrationChanges());
|
|
2481
|
+
}
|
|
2482
|
+
/** @internal */
|
|
2483
|
+
flushRegistrationChanges() {
|
|
2484
|
+
const e = this.pendingRegistrationChanges;
|
|
2485
|
+
if (this.pendingRegistrationChanges = null, !(e === null || e.length === 0)) {
|
|
2486
|
+
if (this.notifyingRegistrations) {
|
|
2487
|
+
this.queuedRegistrationBatches.push(e);
|
|
2488
|
+
return;
|
|
2489
|
+
}
|
|
2490
|
+
this.notifyingRegistrations = !0;
|
|
2491
|
+
try {
|
|
2492
|
+
this.deliverRegistrationBatch(e), this.drainQueuedRegistrationBatches();
|
|
2493
|
+
} finally {
|
|
2494
|
+
this.notifyingRegistrations = !1;
|
|
2495
|
+
}
|
|
2496
|
+
}
|
|
2497
|
+
}
|
|
2498
|
+
/**
|
|
2499
|
+
* Delivers batches an observer produced while being notified.
|
|
2500
|
+
*
|
|
2501
|
+
* @remarks
|
|
2502
|
+
* Bounded like the reduce depth, and for the same reason: two observers registering in
|
|
2503
|
+
* response to each other would otherwise loop forever. Logged rather than thrown - the
|
|
2504
|
+
* topology is correct at that point, and throwing would truncate the stream *and* unwind a
|
|
2505
|
+
* caller that did nothing wrong.
|
|
2506
|
+
*
|
|
2507
|
+
* @internal
|
|
2508
|
+
*/
|
|
2509
|
+
drainQueuedRegistrationBatches() {
|
|
2510
|
+
let e = 0;
|
|
2511
|
+
for (; this.queuedRegistrationBatches.length > 0; ) {
|
|
2512
|
+
if (e >= V) {
|
|
2513
|
+
console.error(
|
|
2514
|
+
`[yoltra] Registration notifications exceeded ${V} rounds; dropping the rest. Two observers are most likely registering in response to each other.`
|
|
2515
|
+
), this.queuedRegistrationBatches.length = 0;
|
|
2516
|
+
break;
|
|
2517
|
+
}
|
|
2518
|
+
e += 1, this.deliverRegistrationBatch(this.queuedRegistrationBatches.shift());
|
|
2519
|
+
}
|
|
2520
|
+
}
|
|
2521
|
+
/** @internal */
|
|
2522
|
+
deliverRegistrationBatch(e) {
|
|
2523
|
+
for (const t of [...this.registrationObservers])
|
|
2524
|
+
this.invokeRegistrationObserver(t, e);
|
|
2525
|
+
}
|
|
2526
|
+
/** @internal */
|
|
2527
|
+
invokeRegistrationObserver(e, t) {
|
|
2528
|
+
try {
|
|
2529
|
+
const n = e(t);
|
|
2530
|
+
process.env.NODE_ENV !== "production" && typeof n?.then == "function" && console.error(
|
|
2531
|
+
"[yoltra] A registration observer returned a Promise. Registration notifications are synchronous: the store has already moved on by the time it resolves. Do the work synchronously, or schedule it yourself and accept that the topology may have changed again."
|
|
2532
|
+
);
|
|
2533
|
+
} catch (n) {
|
|
2534
|
+
console.error("Registration observer error:", n);
|
|
2535
|
+
}
|
|
2536
|
+
}
|
|
2537
|
+
get isReplaying() {
|
|
2538
|
+
return this.replaying;
|
|
1949
2539
|
}
|
|
1950
2540
|
/**
|
|
1951
2541
|
* Subscribe to events by channel and type.
|
|
@@ -1958,8 +2548,15 @@ class x {
|
|
|
1958
2548
|
* - `'committed'` (default): Events that passed middleware and reached reducers.
|
|
1959
2549
|
* Notified after reducers, before effects.
|
|
1960
2550
|
* - `'uncommitted'`: Events rejected by middleware. Notified immediately after rejection.
|
|
2551
|
+
* - `'written'`: Events that actually changed state. Stricter than `committed`, which
|
|
2552
|
+
* fires for every event a store accepts including one with no reducers at all.
|
|
1961
2553
|
* - `'all'`: Both committed and uncommitted events. Handler receives the phase parameter
|
|
1962
|
-
* to distinguish between the two.
|
|
2554
|
+
* to distinguish between the two. Deliberately not `written` as well: an event that
|
|
2555
|
+
* writes is also committed, so folding it in would notify every existing `all`
|
|
2556
|
+
* subscriber twice for one event.
|
|
2557
|
+
*
|
|
2558
|
+
* **Replay:** a handler is not called while devtools is replaying, unless it opted in with
|
|
2559
|
+
* `{ duringReplay: true }`.
|
|
1963
2560
|
*
|
|
1964
2561
|
* @typeParam C - Channel key within `EM`.
|
|
1965
2562
|
* @typeParam T - Event type key within channel `C`.
|
|
@@ -1993,11 +2590,16 @@ class x {
|
|
|
1993
2590
|
*
|
|
1994
2591
|
* @public
|
|
1995
2592
|
*/
|
|
1996
|
-
onEvent(e, t,
|
|
1997
|
-
const
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2593
|
+
onEvent(e, t, n, r = "committed", i) {
|
|
2594
|
+
const s = `${e}::${String(t)}`, l = r === "committed" ? this.committedEventSubscribers : r === "uncommitted" ? this.uncommittedEventSubscribers : r === "written" ? this.writtenEventSubscribers : this.allEventSubscribers;
|
|
2595
|
+
l.has(s) || l.set(s, /* @__PURE__ */ new Set());
|
|
2596
|
+
const c = {
|
|
2597
|
+
handler: n,
|
|
2598
|
+
duringReplay: i?.duringReplay === !0
|
|
2599
|
+
};
|
|
2600
|
+
return l.get(s).add(c), () => {
|
|
2601
|
+
const a = l.get(s);
|
|
2602
|
+
a && (a.delete(c), a.size === 0 && l.delete(s));
|
|
2001
2603
|
};
|
|
2002
2604
|
}
|
|
2003
2605
|
/**
|
|
@@ -2071,10 +2673,86 @@ class x {
|
|
|
2071
2673
|
* @public
|
|
2072
2674
|
*/
|
|
2073
2675
|
registerMiddleware(e) {
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2676
|
+
const t = { input: e, origin: "dynamic" };
|
|
2677
|
+
return this.middleware.push(t), this.recordMiddlewareChange(t, "mounted"), this.asRegistration(() => {
|
|
2678
|
+
const n = this.middleware.indexOf(t);
|
|
2679
|
+
n !== -1 && (this.middleware.splice(n, 1), this.recordMiddlewareChange(t, "unmounted"));
|
|
2680
|
+
});
|
|
2681
|
+
}
|
|
2682
|
+
/**
|
|
2683
|
+
* Turns a disposer into the callable object `register*` returns.
|
|
2684
|
+
*
|
|
2685
|
+
* @remarks
|
|
2686
|
+
* `Object.assign` onto the function rather than a new object, so every existing call site
|
|
2687
|
+
* keeps working verbatim: `const off = store.registerEffect(spec); off();` compiles and
|
|
2688
|
+
* runs exactly as before, while `.store` and `.dispose` become available to a library that
|
|
2689
|
+
* wants the widened type.
|
|
2690
|
+
*
|
|
2691
|
+
* A callable object rather than an overload or a second method: an overload cannot change
|
|
2692
|
+
* the return shape based on nothing, and a parallel `registerSliceX` family would leave
|
|
2693
|
+
* the originals permanently second class and force libraries to branch on the core version.
|
|
2694
|
+
*
|
|
2695
|
+
* @internal
|
|
2696
|
+
*/
|
|
2697
|
+
recordMiddlewareChange(e, t) {
|
|
2698
|
+
this.recordRegistrationChange(() => {
|
|
2699
|
+
const n = typeof e.input == "function" ? void 0 : e.input.meta;
|
|
2700
|
+
return {
|
|
2701
|
+
kind: "middleware",
|
|
2702
|
+
op: t,
|
|
2703
|
+
name: n?.name ?? (typeof e.input == "function" ? e.input.name : void 0),
|
|
2704
|
+
description: n?.description,
|
|
2705
|
+
origin: e.origin,
|
|
2706
|
+
when: A(e.input),
|
|
2707
|
+
dispatch: "pattern"
|
|
2708
|
+
};
|
|
2709
|
+
});
|
|
2710
|
+
}
|
|
2711
|
+
/**
|
|
2712
|
+
* Drops an effect's metadata only once nothing is still registered with it.
|
|
2713
|
+
*
|
|
2714
|
+
* @remarks
|
|
2715
|
+
* `effectMeta` is keyed by the effect *function*, and the same function can legitimately
|
|
2716
|
+
* back several registrations. Deleting on the first disposal stripped the name and
|
|
2717
|
+
* description of the ones still live, which a devtools panel then showed as unnamed.
|
|
2718
|
+
*
|
|
2719
|
+
* @internal
|
|
2720
|
+
*/
|
|
2721
|
+
releaseEffectMeta(e) {
|
|
2722
|
+
for (const t of this.effects.values())
|
|
2723
|
+
for (const n of t) if (n.effect === e) return;
|
|
2724
|
+
for (const t of this.patternEffects) if (t.effect === e) return;
|
|
2725
|
+
this.effectMeta.delete(e);
|
|
2726
|
+
}
|
|
2727
|
+
/** @internal */
|
|
2728
|
+
recordEffectChange(e, t, n, r, i) {
|
|
2729
|
+
this.recordRegistrationChange(() => ({
|
|
2730
|
+
kind: "effect",
|
|
2731
|
+
op: r,
|
|
2732
|
+
name: this.effectMeta.get(e)?.name,
|
|
2733
|
+
description: this.effectMeta.get(e)?.description,
|
|
2734
|
+
origin: n,
|
|
2735
|
+
when: t,
|
|
2736
|
+
dispatch: i
|
|
2737
|
+
}));
|
|
2738
|
+
}
|
|
2739
|
+
/** @internal */
|
|
2740
|
+
asRegistration(e) {
|
|
2741
|
+
return Object.assign(e, { store: this, dispose: e });
|
|
2742
|
+
}
|
|
2743
|
+
/**
|
|
2744
|
+
* The one place the widening cast lives.
|
|
2745
|
+
*
|
|
2746
|
+
* @remarks
|
|
2747
|
+
* Decoration is type-level only. This returns the **same runtime object**: subscriptions,
|
|
2748
|
+
* effects, middleware, the dedup cache, both buses and any in-flight `call()` are
|
|
2749
|
+
* untouched, and nothing re-subscribes. Keeping the cast here means no call site needs one,
|
|
2750
|
+
* which is the entire point of the feature.
|
|
2751
|
+
*
|
|
2752
|
+
* @internal
|
|
2753
|
+
*/
|
|
2754
|
+
widened() {
|
|
2755
|
+
return this;
|
|
2078
2756
|
}
|
|
2079
2757
|
/**
|
|
2080
2758
|
* Dynamically **adds** a named slice reducer at runtime.
|
|
@@ -2098,14 +2776,65 @@ class x {
|
|
|
2098
2776
|
*
|
|
2099
2777
|
* @public
|
|
2100
2778
|
*/
|
|
2101
|
-
registerReducer(e, t) {
|
|
2779
|
+
registerReducer(e, t, n) {
|
|
2780
|
+
return this.registerSlice(e, t, n);
|
|
2781
|
+
}
|
|
2782
|
+
/**
|
|
2783
|
+
* Mounts a slice and hands back the widened store alongside a disposer.
|
|
2784
|
+
*
|
|
2785
|
+
* @remarks
|
|
2786
|
+
* The name `registerSlice` is what the guide uses; `registerReducer` keeps its broader
|
|
2787
|
+
* `name: string` signature and delegates here, so existing call sites are untouched.
|
|
2788
|
+
*
|
|
2789
|
+
* @public
|
|
2790
|
+
*/
|
|
2791
|
+
registerSlice(e, t, n) {
|
|
2792
|
+
return this.inRegistrationTransaction(() => this.registerSliceInner(e, t, n));
|
|
2793
|
+
}
|
|
2794
|
+
/** @internal */
|
|
2795
|
+
registerSliceInner(e, t, n) {
|
|
2102
2796
|
if (Object.prototype.hasOwnProperty.call(this.reducers, e))
|
|
2103
2797
|
throw new Error(`Reducer ${e} already exists`);
|
|
2104
2798
|
return this.mountSlice(e, t, {
|
|
2105
|
-
preserveState: !1
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
}
|
|
2799
|
+
preserveState: !1,
|
|
2800
|
+
origin: "dynamic",
|
|
2801
|
+
owner: n?.owner
|
|
2802
|
+
}), this.listeners.forEach((r) => r()), this.announceMountedSlice(e, this.state[e]), this.asRegistration(() => {
|
|
2803
|
+
Object.prototype.hasOwnProperty.call(this.reducers, e) && this.inRegistrationTransaction(() => {
|
|
2804
|
+
this.unmountSlice(e, { deleteState: !0 }), this.listeners.forEach((r) => r());
|
|
2805
|
+
});
|
|
2806
|
+
});
|
|
2807
|
+
}
|
|
2808
|
+
/**
|
|
2809
|
+
* Mounts a slice and returns the widened store, for chaining.
|
|
2810
|
+
*
|
|
2811
|
+
* @remarks
|
|
2812
|
+
* No disposer, deliberately. After a disposer runs, the widened type still promises a
|
|
2813
|
+
* slice that is gone, and TypeScript cannot express "valid until that call". The chaining
|
|
2814
|
+
* API therefore does not hand one out, so the footgun does not exist on the path most
|
|
2815
|
+
* people take; {@link registerSlice} carries one for the library that owns the slice, and
|
|
2816
|
+
* the documented rule is that a disposer stays library-private.
|
|
2817
|
+
*
|
|
2818
|
+
* @public
|
|
2819
|
+
*/
|
|
2820
|
+
withSlice(e, t, n) {
|
|
2821
|
+
return this.registerSlice(e, t, n), this.widened();
|
|
2822
|
+
}
|
|
2823
|
+
/**
|
|
2824
|
+
* Registers middleware and returns the widened store, for chaining.
|
|
2825
|
+
*
|
|
2826
|
+
* @public
|
|
2827
|
+
*/
|
|
2828
|
+
withMiddleware(e) {
|
|
2829
|
+
return this.registerMiddleware(e), this.widened();
|
|
2830
|
+
}
|
|
2831
|
+
/**
|
|
2832
|
+
* Registers an effect and returns the widened store, for chaining.
|
|
2833
|
+
*
|
|
2834
|
+
* @public
|
|
2835
|
+
*/
|
|
2836
|
+
withEffect(e) {
|
|
2837
|
+
return this.registerEffect(e), this.widened();
|
|
2109
2838
|
}
|
|
2110
2839
|
/**
|
|
2111
2840
|
* Registers an **effect** (stateless async event consumer) that runs after reducers.
|
|
@@ -2218,39 +2947,65 @@ class x {
|
|
|
2218
2947
|
*
|
|
2219
2948
|
* @public
|
|
2220
2949
|
*/
|
|
2221
|
-
call(e, t,
|
|
2222
|
-
return
|
|
2223
|
-
{
|
|
2950
|
+
call(e, t, n, r) {
|
|
2951
|
+
return se(
|
|
2952
|
+
{
|
|
2953
|
+
idFactory: this.idFactory,
|
|
2954
|
+
// `internal`, so an in-flight call survives even `replaceEffects(next, { scope: "all" })`.
|
|
2955
|
+
// A test harness resetting a store between cases never means "and abandon the call
|
|
2956
|
+
// that is currently awaiting a reply", and the symptom would be a hang to the idle
|
|
2957
|
+
// timeout with nothing pointing at the reset.
|
|
2958
|
+
registerEffect: (i) => this.registerEffectWithOrigin(i, "internal"),
|
|
2959
|
+
emit: this.emit
|
|
2960
|
+
},
|
|
2224
2961
|
e,
|
|
2225
2962
|
t,
|
|
2226
|
-
|
|
2227
|
-
|
|
2963
|
+
n,
|
|
2964
|
+
r
|
|
2228
2965
|
);
|
|
2229
2966
|
}
|
|
2230
2967
|
registerEffect(e) {
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2968
|
+
return this.asRegistration(this.registerEffectWithOrigin(e, "dynamic"));
|
|
2969
|
+
}
|
|
2970
|
+
/**
|
|
2971
|
+
* {@link registerEffect}, with the provenance the caller cannot set.
|
|
2972
|
+
*
|
|
2973
|
+
* @remarks
|
|
2974
|
+
* Kept private so no origin parameter leaks into `StoreInstance`. Three callers: the
|
|
2975
|
+
* constructor (`spec`), the public method (`dynamic`), and `store.call()` (`internal`).
|
|
2976
|
+
*
|
|
2977
|
+
* @internal
|
|
2978
|
+
*/
|
|
2979
|
+
registerEffectWithOrigin(e, t) {
|
|
2980
|
+
const { effect: n, meta: r, when: i } = e, s = [];
|
|
2981
|
+
if (r && this.effectMeta.set(n, r), i && ("any" in i && i.any === !0 || "channel" in i || "channels" in i)) {
|
|
2982
|
+
const a = { effect: n, when: i, origin: t };
|
|
2983
|
+
return this.patternEffects.add(a), this.recordEffectChange(n, i, t, "mounted", "pattern"), () => {
|
|
2984
|
+
this.recordEffectChange(n, i, t, "unmounted", "pattern"), this.patternEffects.delete(a), this.releaseEffectMeta(n);
|
|
2236
2985
|
};
|
|
2237
2986
|
}
|
|
2238
|
-
const
|
|
2239
|
-
if (
|
|
2240
|
-
const
|
|
2241
|
-
return this.patternEffects.add(
|
|
2242
|
-
this.patternEffects.delete(
|
|
2987
|
+
const c = U(e);
|
|
2988
|
+
if (c.length === 0 && !i) {
|
|
2989
|
+
const a = { any: !0 }, d = { effect: n, when: a, origin: t };
|
|
2990
|
+
return this.patternEffects.add(d), this.recordEffectChange(n, a, t, "mounted", "pattern"), () => {
|
|
2991
|
+
this.recordEffectChange(n, a, t, "unmounted", "pattern"), this.patternEffects.delete(d), this.releaseEffectMeta(n);
|
|
2243
2992
|
};
|
|
2244
2993
|
}
|
|
2245
|
-
for (const [
|
|
2246
|
-
const
|
|
2247
|
-
this.effects.has(
|
|
2248
|
-
|
|
2249
|
-
|
|
2994
|
+
for (const [a, d] of c) {
|
|
2995
|
+
const f = `${String(a)}::${String(d)}`;
|
|
2996
|
+
this.effects.has(f) || this.effects.set(f, /* @__PURE__ */ new Set());
|
|
2997
|
+
const u = { effect: n, origin: t };
|
|
2998
|
+
this.effects.get(f).add(u);
|
|
2999
|
+
const p = { keys: [[a, d]] };
|
|
3000
|
+
this.recordEffectChange(n, p, t, "mounted", "keyed"), s.push(() => {
|
|
3001
|
+
this.recordEffectChange(n, p, t, "unmounted", "keyed");
|
|
3002
|
+
const h = this.effects.get(f);
|
|
3003
|
+
h && (h.delete(u), h.size === 0 && this.effects.delete(f));
|
|
2250
3004
|
});
|
|
2251
3005
|
}
|
|
2252
3006
|
return () => {
|
|
2253
|
-
for (const
|
|
3007
|
+
for (const a of s) a();
|
|
3008
|
+
this.releaseEffectMeta(n);
|
|
2254
3009
|
};
|
|
2255
3010
|
}
|
|
2256
3011
|
/**
|
|
@@ -2274,15 +3029,15 @@ class x {
|
|
|
2274
3029
|
*
|
|
2275
3030
|
* @public
|
|
2276
3031
|
*/
|
|
2277
|
-
onEffect(e, t,
|
|
2278
|
-
const
|
|
2279
|
-
if (
|
|
2280
|
-
const
|
|
2281
|
-
return
|
|
3032
|
+
onEffect(e, t, n) {
|
|
3033
|
+
const r = async (i, s, l) => {
|
|
3034
|
+
if (i.channel !== e || i.type !== t) return;
|
|
3035
|
+
const c = i;
|
|
3036
|
+
return n(c.payload, s, l, c);
|
|
2282
3037
|
};
|
|
2283
3038
|
return this.registerEffect({
|
|
2284
3039
|
when: { keys: [[e, t]] },
|
|
2285
|
-
effect:
|
|
3040
|
+
effect: r
|
|
2286
3041
|
});
|
|
2287
3042
|
}
|
|
2288
3043
|
/**
|
|
@@ -2301,9 +3056,23 @@ class x {
|
|
|
2301
3056
|
*
|
|
2302
3057
|
* @public
|
|
2303
3058
|
*/
|
|
2304
|
-
replaceMiddleware(e) {
|
|
3059
|
+
replaceMiddleware(e, t = {}) {
|
|
3060
|
+
this.inRegistrationTransaction(() => this.replaceMiddlewareInner(e, t));
|
|
3061
|
+
}
|
|
3062
|
+
/** @internal */
|
|
3063
|
+
replaceMiddlewareInner(e, t = {}) {
|
|
3064
|
+
const n = t.scope ?? "spec", r = this.middleware.filter(
|
|
3065
|
+
(i) => n === "all" ? i.origin === "internal" : i.origin !== "spec"
|
|
3066
|
+
);
|
|
3067
|
+
for (const i of this.middleware)
|
|
3068
|
+
r.includes(i) || this.recordMiddlewareChange(i, "unmounted");
|
|
2305
3069
|
this.middleware.length = 0;
|
|
2306
|
-
for (const
|
|
3070
|
+
for (const i of e) {
|
|
3071
|
+
const s = { input: i, origin: "spec" };
|
|
3072
|
+
this.middleware.push(s), this.recordMiddlewareChange(s, "mounted");
|
|
3073
|
+
}
|
|
3074
|
+
for (const i of r) this.middleware.push(i);
|
|
3075
|
+
this.reportPreserved("replaceMiddleware", r.length, n);
|
|
2307
3076
|
}
|
|
2308
3077
|
/**
|
|
2309
3078
|
* Replaces all registered **effects** (HMR-friendly).
|
|
@@ -2321,16 +3090,53 @@ class x {
|
|
|
2321
3090
|
*
|
|
2322
3091
|
* @public
|
|
2323
3092
|
*/
|
|
2324
|
-
replaceEffects(e) {
|
|
2325
|
-
this.
|
|
2326
|
-
|
|
2327
|
-
|
|
3093
|
+
replaceEffects(e, t = {}) {
|
|
3094
|
+
this.inRegistrationTransaction(() => this.replaceEffectsInner(e, t));
|
|
3095
|
+
}
|
|
3096
|
+
/** @internal */
|
|
3097
|
+
replaceEffectsInner(e, t = {}) {
|
|
3098
|
+
const n = t.scope ?? "spec", r = (s) => n === "all" ? s === "internal" : s !== "spec";
|
|
3099
|
+
let i = 0;
|
|
3100
|
+
for (const [s, l] of this.effects) {
|
|
3101
|
+
for (const c of [...l]) {
|
|
3102
|
+
if (r(c.origin)) {
|
|
3103
|
+
i += 1;
|
|
3104
|
+
continue;
|
|
3105
|
+
}
|
|
3106
|
+
this.recordEffectChange(
|
|
3107
|
+
c.effect,
|
|
3108
|
+
{ keys: [s.split("::")] },
|
|
3109
|
+
c.origin,
|
|
3110
|
+
"unmounted",
|
|
3111
|
+
"keyed"
|
|
3112
|
+
), l.delete(c), this.releaseEffectMeta(c.effect);
|
|
3113
|
+
}
|
|
3114
|
+
l.size === 0 && this.effects.delete(s);
|
|
3115
|
+
}
|
|
3116
|
+
for (const s of [...this.patternEffects]) {
|
|
3117
|
+
if (r(s.origin)) {
|
|
3118
|
+
i += 1;
|
|
3119
|
+
continue;
|
|
3120
|
+
}
|
|
3121
|
+
this.recordEffectChange(s.effect, s.when, s.origin, "unmounted", "pattern"), this.patternEffects.delete(s), this.releaseEffectMeta(s.effect);
|
|
3122
|
+
}
|
|
3123
|
+
for (const s of e)
|
|
3124
|
+
this.registerEffectWithOrigin(s, "spec");
|
|
3125
|
+
this.reportPreserved("replaceEffects", i, n);
|
|
2328
3126
|
}
|
|
2329
3127
|
/**
|
|
2330
3128
|
* Replaces the entire **reducer set** (HMR-friendly).
|
|
2331
3129
|
*
|
|
2332
3130
|
* @param next - Map of slice specs keyed by slice name.
|
|
2333
|
-
* @param opts - `{ preserveState?: boolean }` (default `true`)
|
|
3131
|
+
* @param opts - `{ preserveState?: boolean }` (default `true`) and
|
|
3132
|
+
* `{ scope?: "spec" | "all" }` (default `"spec"`).
|
|
3133
|
+
*
|
|
3134
|
+
* @remarks
|
|
3135
|
+
* Replaces **spec-provenance slices only**. A slice mounted after construction with
|
|
3136
|
+
* `registerSlice` survives, along with its state: it was never part of the set this call
|
|
3137
|
+
* is replacing. Pass `{ scope: "all" }` for the pre-0.8.0 wholesale behaviour.
|
|
3138
|
+
*
|
|
3139
|
+
* Throws, before mutating anything, if `next` names a slice a library mounted at runtime.
|
|
2334
3140
|
*
|
|
2335
3141
|
* @example Hot module replacement
|
|
2336
3142
|
* ```ts
|
|
@@ -2344,11 +3150,67 @@ class x {
|
|
|
2344
3150
|
* @public
|
|
2345
3151
|
*/
|
|
2346
3152
|
replaceReducers(e, t = {}) {
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
3153
|
+
this.inRegistrationTransaction(() => this.replaceReducersInner(e, t));
|
|
3154
|
+
}
|
|
3155
|
+
/** @internal */
|
|
3156
|
+
replaceReducersInner(e, t = {}) {
|
|
3157
|
+
const n = t.preserveState !== !1, r = t.scope ?? "spec", i = new Set(Object.keys(this.reducers)), s = Object.entries(e), l = new Set(s.map(([d]) => d));
|
|
3158
|
+
this.assertNoSliceCollision(e, r);
|
|
3159
|
+
const c = this.state;
|
|
3160
|
+
let a = 0;
|
|
3161
|
+
for (const d of i) {
|
|
3162
|
+
if (l.has(d)) continue;
|
|
3163
|
+
const f = this.sliceOrigin.get(d) ?? "spec";
|
|
3164
|
+
if (!(r === "all" ? f !== "internal" : f === "spec")) {
|
|
3165
|
+
a += 1;
|
|
3166
|
+
continue;
|
|
3167
|
+
}
|
|
3168
|
+
this.unmountSlice(d, { deleteState: !0 });
|
|
3169
|
+
}
|
|
3170
|
+
for (const [d, f] of s)
|
|
3171
|
+
i.has(d) ? (this.unmountSlice(d, { deleteState: !1 }), this.mountSlice(d, f, { preserveState: n, origin: "spec" })) : this.mountSlice(d, f, { preserveState: !1, origin: "spec" });
|
|
3172
|
+
this.state !== c && this.listeners.forEach((d) => d()), this.reportPreserved("replaceReducers", a, r);
|
|
3173
|
+
}
|
|
3174
|
+
/**
|
|
3175
|
+
* Refuses, before anything is mutated, to take over a slice mounted at runtime.
|
|
3176
|
+
*
|
|
3177
|
+
* @remarks
|
|
3178
|
+
* An application authoring a slice a library owns is a real mistake, and a silent takeover
|
|
3179
|
+
* is the worst available outcome: the library keeps a disposer for a slice that is no
|
|
3180
|
+
* longer its own. Throwing part-way through would be worse still, which is why this runs
|
|
3181
|
+
* as a pre-flight and why `hotReplace` calls it before swapping anything at all.
|
|
3182
|
+
*
|
|
3183
|
+
* @internal
|
|
3184
|
+
*/
|
|
3185
|
+
assertNoSliceCollision(e, t) {
|
|
3186
|
+
if (t !== "spec") return;
|
|
3187
|
+
const n = Object.keys(e).filter(
|
|
3188
|
+
(i) => this.sliceOrigin.get(i) === "dynamic"
|
|
3189
|
+
);
|
|
3190
|
+
if (n.length === 0) return;
|
|
3191
|
+
const r = n.map((i) => {
|
|
3192
|
+
const s = this.sliceOwner.get(i);
|
|
3193
|
+
return s === void 0 ? `"${i}"` : `"${i}" (owner: ${s})`;
|
|
3194
|
+
}).join(", ");
|
|
3195
|
+
throw new Error(
|
|
3196
|
+
`[yoltra] replaceReducers would take over ${n.length === 1 ? "a slice" : "slices"} mounted at runtime: ${r}. Rename the slice, or pass { scope: "all" } to replace it deliberately.`
|
|
3197
|
+
);
|
|
3198
|
+
}
|
|
3199
|
+
/**
|
|
3200
|
+
* Says what a `replace*` call left alone, when it left anything alone.
|
|
3201
|
+
*
|
|
3202
|
+
* @remarks
|
|
3203
|
+
* Development only, and silent unless something was actually preserved, so the normal HMR
|
|
3204
|
+
* path stays quiet. `console.debug` rather than `warn`: this is correct operation, and
|
|
3205
|
+
* every existing `warn` in this file marks a genuine problem. It exists so "why is that
|
|
3206
|
+
* effect still firing after a reload" has an answer that does not require reading core.
|
|
3207
|
+
*
|
|
3208
|
+
* @internal
|
|
3209
|
+
*/
|
|
3210
|
+
reportPreserved(e, t, n) {
|
|
3211
|
+
t !== 0 && process.env.NODE_ENV !== "production" && console.debug(
|
|
3212
|
+
`[yoltra] ${e} preserved ${t} registration${t === 1 ? "" : "s"} made after construction.${n === "spec" ? ' Pass { scope: "all" } to replace them too.' : ""}`
|
|
3213
|
+
);
|
|
2352
3214
|
}
|
|
2353
3215
|
/**
|
|
2354
3216
|
* Convenience API to replace **any subset** of store parts (HMR patterns).
|
|
@@ -2368,7 +3230,10 @@ class x {
|
|
|
2368
3230
|
* @public
|
|
2369
3231
|
*/
|
|
2370
3232
|
hotReplace(e) {
|
|
2371
|
-
|
|
3233
|
+
const t = e.scope;
|
|
3234
|
+
e.reducer && this.assertNoSliceCollision(e.reducer, t ?? "spec"), this.inRegistrationTransaction(() => {
|
|
3235
|
+
e.middleware && this.replaceMiddleware(e.middleware, { scope: t }), e.effects && this.replaceEffects(e.effects, { scope: t }), e.reducer && this.replaceReducers(e.reducer, { preserveState: e.preserveState, scope: t });
|
|
3236
|
+
});
|
|
2372
3237
|
}
|
|
2373
3238
|
/**
|
|
2374
3239
|
* Mounts a slice: installs reducer, initializes state (unless preserved),
|
|
@@ -2380,36 +3245,99 @@ class x {
|
|
|
2380
3245
|
*
|
|
2381
3246
|
* @internal
|
|
2382
3247
|
*/
|
|
2383
|
-
mountSlice(e, t,
|
|
2384
|
-
|
|
2385
|
-
|
|
3248
|
+
mountSlice(e, t, n) {
|
|
3249
|
+
this.mountSliceInner(e, t, n), this.recordSliceChange(
|
|
3250
|
+
e,
|
|
3251
|
+
"mounted",
|
|
3252
|
+
n.preserveState ? "preserved" : "initialized"
|
|
3253
|
+
);
|
|
3254
|
+
}
|
|
3255
|
+
/** @internal */
|
|
3256
|
+
mountSliceInner(e, t, n) {
|
|
3257
|
+
const r = e;
|
|
3258
|
+
this.sliceOrigin.set(r, n.origin ?? "spec"), n.owner !== void 0 && this.sliceOwner.set(r, n.owner), this.disposedSlices.delete(r);
|
|
3259
|
+
const { reducer: i, state: s, when: l } = t;
|
|
3260
|
+
if (this.reducers[e] = new X(i), (!n.preserveState || this.state[r] === void 0) && (this.state = {
|
|
2386
3261
|
...this.state,
|
|
2387
|
-
[
|
|
3262
|
+
[r]: T(pe(r, s))
|
|
2388
3263
|
}), l && ("any" in l && l.any === !0 || "channel" in l || "channels" in l)) {
|
|
2389
|
-
this.patternReducers.set(e, l), this.sliceUnsubs.set(
|
|
3264
|
+
this.patternReducers.set(e, l), this.sliceUnsubs.set(r, []);
|
|
2390
3265
|
return;
|
|
2391
3266
|
}
|
|
2392
|
-
const a =
|
|
3267
|
+
const a = U(t);
|
|
2393
3268
|
if (a.length === 0 && !l) {
|
|
2394
|
-
this.patternReducers.set(e, { any: !0 }), this.sliceUnsubs.set(
|
|
3269
|
+
this.patternReducers.set(e, { any: !0 }), this.sliceUnsubs.set(r, []);
|
|
2395
3270
|
return;
|
|
2396
3271
|
}
|
|
2397
|
-
const
|
|
2398
|
-
for (const [
|
|
2399
|
-
const p = this.reducerBus.on(
|
|
2400
|
-
const
|
|
2401
|
-
channel:
|
|
2402
|
-
type:
|
|
2403
|
-
payload:
|
|
3272
|
+
const d = [];
|
|
3273
|
+
for (const [f, u] of a) {
|
|
3274
|
+
const p = this.reducerBus.on(f, u, (h, y) => {
|
|
3275
|
+
const w = y ?? {
|
|
3276
|
+
channel: f,
|
|
3277
|
+
type: u,
|
|
3278
|
+
payload: h,
|
|
2404
3279
|
id: this.idFactory()
|
|
2405
3280
|
};
|
|
2406
3281
|
if (this.stagingSink === null) return;
|
|
2407
|
-
const g = this.stageSliceGuarded(e,
|
|
3282
|
+
const g = this.stageSliceGuarded(e, w, this.stagingSink);
|
|
2408
3283
|
g !== null && this.stagedRejection === null && (this.stagedRejection = g, this.stagedRejectedBy = e);
|
|
2409
3284
|
});
|
|
2410
|
-
|
|
3285
|
+
d.push(p);
|
|
3286
|
+
}
|
|
3287
|
+
this.sliceUnsubs.set(r, d);
|
|
3288
|
+
}
|
|
3289
|
+
/**
|
|
3290
|
+
* Records a slice mount or unmount for {@link onRegistrationChange}.
|
|
3291
|
+
*
|
|
3292
|
+
* @internal
|
|
3293
|
+
*/
|
|
3294
|
+
recordSliceChange(e, t, n) {
|
|
3295
|
+
this.recordRegistrationChange(() => ({
|
|
3296
|
+
kind: "reducer",
|
|
3297
|
+
op: t,
|
|
3298
|
+
name: e,
|
|
3299
|
+
origin: this.sliceOrigin.get(e) ?? "spec",
|
|
3300
|
+
owner: this.sliceOwner.get(e),
|
|
3301
|
+
when: this.patternReducers.get(e),
|
|
3302
|
+
state: n,
|
|
3303
|
+
dispatch: this.patternReducers.has(e) ? "pattern" : "keyed"
|
|
3304
|
+
}));
|
|
3305
|
+
}
|
|
3306
|
+
/**
|
|
3307
|
+
* Announces a newly mounted slice on the connector bus.
|
|
3308
|
+
*
|
|
3309
|
+
* @remarks
|
|
3310
|
+
* `registerReducer` has always broadcast to `listeners`, which wakes `subscribe` and so
|
|
3311
|
+
* `useSelector`. It emitted **nothing** on `connectorBus`, which is what `connect` rides,
|
|
3312
|
+
* so `useAtomicProp`, `useAtomicProps` and the Suspense hooks never woke for a slice
|
|
3313
|
+
* mounted after creation: a component subscribed to a path inside it simply never
|
|
3314
|
+
* re-rendered. That makes the decoration story ship a documented-as-working path that does
|
|
3315
|
+
* not work, which is why this is here rather than filed as a follow-up.
|
|
3316
|
+
*
|
|
3317
|
+
* Scope, stated precisely because it is narrower than it looks: this emits the slice root
|
|
3318
|
+
* and its **top-level** keys, which is exactly what an ordinary commit emits when a
|
|
3319
|
+
* subtree first appears - `detectChangedProps` reports a newly-appearing branch at its
|
|
3320
|
+
* root, not leaf by leaf. So a `connect` on `"deep.n"` does not fire here, and does not
|
|
3321
|
+
* fire on a normal commit that first creates `deep` either. Consistent, not complete.
|
|
3322
|
+
*
|
|
3323
|
+
* Skipped when nothing is subscribed, and skipped entirely during construction, where no
|
|
3324
|
+
* subscriber can exist yet.
|
|
3325
|
+
*
|
|
3326
|
+
* @internal
|
|
3327
|
+
*/
|
|
3328
|
+
announceMountedSlice(e, t) {
|
|
3329
|
+
const r = I(typeof t == "object" && t !== null ? {} : void 0, t), i = /* @__PURE__ */ new Set([""]);
|
|
3330
|
+
for (const s of r)
|
|
3331
|
+
if (s !== "")
|
|
3332
|
+
for (const l of k.buildAncestorPaths(s)) i.add(l);
|
|
3333
|
+
for (const s of i) {
|
|
3334
|
+
const l = this.getAtPath(this.state[e], s);
|
|
3335
|
+
this.connectorBus.emit(e, s, {
|
|
3336
|
+
oldValue: void 0,
|
|
3337
|
+
newValue: l,
|
|
3338
|
+
path: s
|
|
3339
|
+
});
|
|
2411
3340
|
}
|
|
2412
|
-
this.sliceUnsubs.set(n, u);
|
|
2413
3341
|
}
|
|
2414
3342
|
/**
|
|
2415
3343
|
* Unmounts a slice: disposes reducer-bus listeners, removes reducer,
|
|
@@ -2421,21 +3349,27 @@ class x {
|
|
|
2421
3349
|
* @internal
|
|
2422
3350
|
*/
|
|
2423
3351
|
unmountSlice(e, t) {
|
|
2424
|
-
const
|
|
2425
|
-
this.patternReducers.delete(e)
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
3352
|
+
const n = e;
|
|
3353
|
+
if (this.recordSliceChange(n, "unmounted", t.deleteState ? "deleted" : "retained"), this.patternReducers.delete(e), process.env.NODE_ENV !== "production") {
|
|
3354
|
+
const i = this.sliceOrigin.get(n);
|
|
3355
|
+
if (i === "dynamic" || i === "internal")
|
|
3356
|
+
for (this.disposedSlices.set(n, this.sliceOwner.get(n)); this.disposedSlices.size > ge; )
|
|
3357
|
+
this.disposedSlices.delete(this.disposedSlices.keys().next().value);
|
|
3358
|
+
}
|
|
3359
|
+
this.sliceOrigin.delete(n), this.sliceOwner.delete(n);
|
|
3360
|
+
const r = this.sliceUnsubs.get(n);
|
|
3361
|
+
if (r) {
|
|
3362
|
+
for (const i of r)
|
|
2429
3363
|
try {
|
|
2430
|
-
|
|
2431
|
-
} catch (
|
|
2432
|
-
console.error(`[Store error]: ${
|
|
3364
|
+
i();
|
|
3365
|
+
} catch (s) {
|
|
3366
|
+
console.error(`[Store error]: ${s}`);
|
|
2433
3367
|
}
|
|
2434
|
-
this.sliceUnsubs.delete(
|
|
3368
|
+
this.sliceUnsubs.delete(n);
|
|
2435
3369
|
}
|
|
2436
3370
|
if (delete this.reducers[e], t.deleteState) {
|
|
2437
|
-
const { [
|
|
2438
|
-
this.state =
|
|
3371
|
+
const { [n]: i, ...s } = this.state;
|
|
3372
|
+
this.state = s;
|
|
2439
3373
|
}
|
|
2440
3374
|
}
|
|
2441
3375
|
/**
|
|
@@ -2452,7 +3386,7 @@ class x {
|
|
|
2452
3386
|
* @internal
|
|
2453
3387
|
*/
|
|
2454
3388
|
getAtPath(e, t) {
|
|
2455
|
-
return
|
|
3389
|
+
return oe(e, t);
|
|
2456
3390
|
}
|
|
2457
3391
|
/**
|
|
2458
3392
|
* Builds ancestor paths for a dotted path.
|
|
@@ -2470,364 +3404,215 @@ class x {
|
|
|
2470
3404
|
* @public
|
|
2471
3405
|
*/
|
|
2472
3406
|
static buildAncestorPaths(e) {
|
|
2473
|
-
return
|
|
3407
|
+
return ce(e);
|
|
2474
3408
|
}
|
|
2475
3409
|
}
|
|
2476
|
-
function
|
|
2477
|
-
return new
|
|
3410
|
+
function ke(o) {
|
|
3411
|
+
return new k({
|
|
2478
3412
|
...o,
|
|
2479
3413
|
reducer: o.reducer ?? {},
|
|
2480
3414
|
middleware: o.middleware ?? [],
|
|
2481
3415
|
effects: o.effects ?? []
|
|
2482
3416
|
});
|
|
2483
3417
|
}
|
|
2484
|
-
const
|
|
2485
|
-
function
|
|
3418
|
+
const $e = (o) => (e, t) => t.map((n) => [e, n]), Me = () => (o) => o, Ce = () => (o) => o, Pe = () => (o) => o, Ie = () => (o) => o, L = /* @__PURE__ */ new Set();
|
|
3419
|
+
function ve(o) {
|
|
2486
3420
|
const e = String(o);
|
|
2487
|
-
|
|
3421
|
+
L.has(e) || (L.add(e), console.warn(
|
|
2488
3422
|
`[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.`
|
|
2489
3423
|
));
|
|
2490
3424
|
}
|
|
2491
|
-
function
|
|
3425
|
+
function Se(o, e) {
|
|
2492
3426
|
if (o.length !== e.length) return e;
|
|
2493
3427
|
for (let t = 0; t < o.length; t++)
|
|
2494
3428
|
if (o[t] !== e[t]) return e;
|
|
2495
3429
|
return o;
|
|
2496
3430
|
}
|
|
2497
|
-
function
|
|
2498
|
-
const e = o.selectId ?? ((
|
|
3431
|
+
function Ae(o = {}) {
|
|
3432
|
+
const e = o.selectId ?? ((c) => c.id), { sortComparer: t } = o, n = (c, a) => {
|
|
2499
3433
|
if (t === void 0) return a;
|
|
2500
|
-
const
|
|
2501
|
-
const p =
|
|
2502
|
-
return p === void 0 ||
|
|
3434
|
+
const d = [...a].sort((f, u) => {
|
|
3435
|
+
const p = c.entities[f], h = c.entities[u];
|
|
3436
|
+
return p === void 0 || h === void 0 ? 0 : t(p, h);
|
|
2503
3437
|
});
|
|
2504
|
-
return
|
|
2505
|
-
},
|
|
2506
|
-
const
|
|
2507
|
-
return { ...
|
|
2508
|
-
},
|
|
2509
|
-
let
|
|
3438
|
+
return Se(a, d);
|
|
3439
|
+
}, r = (c, a, d) => {
|
|
3440
|
+
const f = { ...c, entities: a, ids: d };
|
|
3441
|
+
return { ...f, ids: n(f, d) };
|
|
3442
|
+
}, i = (c, a, d) => {
|
|
3443
|
+
let f = null, u = null;
|
|
2510
3444
|
for (const p of a) {
|
|
2511
|
-
const
|
|
2512
|
-
process.env.NODE_ENV !== "production" && String(
|
|
2513
|
-
const
|
|
2514
|
-
if (
|
|
2515
|
-
const
|
|
2516
|
-
|
|
2517
|
-
}
|
|
2518
|
-
return
|
|
2519
|
-
},
|
|
2520
|
-
let
|
|
2521
|
-
for (const { id:
|
|
2522
|
-
const p = (
|
|
2523
|
-
p !== void 0 && (
|
|
2524
|
-
}
|
|
2525
|
-
return
|
|
2526
|
-
}, l = (
|
|
2527
|
-
const
|
|
2528
|
-
if (
|
|
2529
|
-
const
|
|
2530
|
-
for (const
|
|
2531
|
-
return
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
3445
|
+
const h = e(p);
|
|
3446
|
+
process.env.NODE_ENV !== "production" && String(h).includes(".") && ve(h);
|
|
3447
|
+
const y = (f ?? c.entities)[h];
|
|
3448
|
+
if (y !== void 0 && d === "add") continue;
|
|
3449
|
+
const w = y !== void 0 && d === "upsert" ? { ...y, ...p } : p;
|
|
3450
|
+
f ??= { ...c.entities }, f[h] = w, y === void 0 && (u ??= [...c.ids], u.push(h));
|
|
3451
|
+
}
|
|
3452
|
+
return f === null ? c : r(c, f, u ?? c.ids);
|
|
3453
|
+
}, s = (c, a) => {
|
|
3454
|
+
let d = null;
|
|
3455
|
+
for (const { id: f, changes: u } of a) {
|
|
3456
|
+
const p = (d ?? c.entities)[f];
|
|
3457
|
+
p !== void 0 && (d ??= { ...c.entities }, d[f] = { ...p, ...u });
|
|
3458
|
+
}
|
|
3459
|
+
return d === null ? c : r(c, d, c.ids);
|
|
3460
|
+
}, l = (c, a) => {
|
|
3461
|
+
const d = new Set(a.filter((u) => c.entities[u] !== void 0));
|
|
3462
|
+
if (d.size === 0) return c;
|
|
3463
|
+
const f = { ...c.entities };
|
|
3464
|
+
for (const u of d) delete f[u];
|
|
3465
|
+
return r(
|
|
3466
|
+
c,
|
|
3467
|
+
f,
|
|
3468
|
+
c.ids.filter((u) => !d.has(u))
|
|
2535
3469
|
);
|
|
2536
3470
|
};
|
|
2537
3471
|
return {
|
|
2538
|
-
getInitialState(
|
|
3472
|
+
getInitialState(c) {
|
|
2539
3473
|
const a = { ids: [], entities: {} };
|
|
2540
|
-
return
|
|
3474
|
+
return c === void 0 ? a : { ...a, ...c };
|
|
2541
3475
|
},
|
|
2542
|
-
addOne: (
|
|
2543
|
-
addMany: (
|
|
2544
|
-
setOne: (
|
|
2545
|
-
setMany: (
|
|
2546
|
-
setAll: (
|
|
2547
|
-
const
|
|
2548
|
-
for (const
|
|
2549
|
-
const p = e(
|
|
2550
|
-
|
|
3476
|
+
addOne: (c, a) => i(c, [a], "add"),
|
|
3477
|
+
addMany: (c, a) => i(c, a, "add"),
|
|
3478
|
+
setOne: (c, a) => i(c, [a], "set"),
|
|
3479
|
+
setMany: (c, a) => i(c, a, "set"),
|
|
3480
|
+
setAll: (c, a) => {
|
|
3481
|
+
const d = {}, f = [];
|
|
3482
|
+
for (const u of a) {
|
|
3483
|
+
const p = e(u);
|
|
3484
|
+
d[p] === void 0 && f.push(p), d[p] = u;
|
|
2551
3485
|
}
|
|
2552
|
-
return
|
|
3486
|
+
return r(c, d, f);
|
|
2553
3487
|
},
|
|
2554
|
-
updateOne: (
|
|
2555
|
-
updateMany: (
|
|
2556
|
-
upsertOne: (
|
|
2557
|
-
upsertMany: (
|
|
2558
|
-
removeOne: (
|
|
2559
|
-
removeMany: (
|
|
2560
|
-
removeAll: (
|
|
2561
|
-
selectIds: (
|
|
2562
|
-
selectEntities: (
|
|
2563
|
-
selectAll: (
|
|
2564
|
-
selectById: (
|
|
2565
|
-
selectTotal: (
|
|
3488
|
+
updateOne: (c, a) => s(c, [a]),
|
|
3489
|
+
updateMany: (c, a) => s(c, a),
|
|
3490
|
+
upsertOne: (c, a) => i(c, [a], "upsert"),
|
|
3491
|
+
upsertMany: (c, a) => i(c, a, "upsert"),
|
|
3492
|
+
removeOne: (c, a) => l(c, [a]),
|
|
3493
|
+
removeMany: (c, a) => l(c, a),
|
|
3494
|
+
removeAll: (c) => c.ids.length === 0 ? c : r(c, {}, []),
|
|
3495
|
+
selectIds: (c) => c.ids,
|
|
3496
|
+
selectEntities: (c) => c.entities,
|
|
3497
|
+
selectAll: (c) => c.ids.map((a) => c.entities[a]),
|
|
3498
|
+
selectById: (c, a) => c.entities[a],
|
|
3499
|
+
selectTotal: (c) => c.ids.length,
|
|
2566
3500
|
idsPath: "ids",
|
|
2567
|
-
pathTo: (
|
|
2568
|
-
anyField: (
|
|
3501
|
+
pathTo: (c, a) => a === void 0 ? `entities.${c}` : `entities.${c}.${a}`,
|
|
3502
|
+
anyField: (c) => `entities.*.${c}`
|
|
2569
3503
|
};
|
|
2570
3504
|
}
|
|
2571
|
-
|
|
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) {
|
|
2579
|
-
case "undefined":
|
|
2580
|
-
return { [w]: "undefined" };
|
|
2581
|
-
case "bigint":
|
|
2582
|
-
return { [w]: "bigint", value: u.toString() };
|
|
2583
|
-
case "number":
|
|
2584
|
-
return Number.isNaN(u) ? { [w]: "nan" } : u === 1 / 0 ? { [w]: "infinity", sign: 1 } : u === -1 / 0 ? { [w]: "infinity", sign: -1 } : u;
|
|
2585
|
-
case "function":
|
|
2586
|
-
case "symbol":
|
|
2587
|
-
return n.push(d), { [w]: "unsupported", kind: typeof u };
|
|
2588
|
-
case "string":
|
|
2589
|
-
case "boolean":
|
|
2590
|
-
return u;
|
|
2591
|
-
}
|
|
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) {
|
|
2602
|
-
const m = [];
|
|
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 };
|
|
2607
|
-
}
|
|
2608
|
-
if (u instanceof Set) {
|
|
2609
|
-
const m = [];
|
|
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 };
|
|
2614
|
-
}
|
|
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 } };
|
|
2623
|
-
}
|
|
2624
|
-
function ue(o) {
|
|
2625
|
-
const e = /* @__PURE__ */ new Map(), t = [];
|
|
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;
|
|
2633
|
-
return;
|
|
2634
|
-
}
|
|
2635
|
-
a[d] = s(u, `${l}/${d}`);
|
|
2636
|
-
}), a;
|
|
2637
|
-
}
|
|
2638
|
-
if (typeof c[w] == "string") {
|
|
2639
|
-
const a = c;
|
|
2640
|
-
switch (a[w]) {
|
|
2641
|
-
case "undefined":
|
|
2642
|
-
return;
|
|
2643
|
-
case "nan":
|
|
2644
|
-
return Number.NaN;
|
|
2645
|
-
case "infinity":
|
|
2646
|
-
return a.sign === 1 ? 1 / 0 : -1 / 0;
|
|
2647
|
-
case "bigint":
|
|
2648
|
-
return BigInt(a.value);
|
|
2649
|
-
case "date":
|
|
2650
|
-
return new Date(a.iso);
|
|
2651
|
-
case "regexp":
|
|
2652
|
-
return new RegExp(a.source, a.flags);
|
|
2653
|
-
case "error": {
|
|
2654
|
-
const u = new Error(a.message);
|
|
2655
|
-
return u.name = a.name, u;
|
|
2656
|
-
}
|
|
2657
|
-
case "unsupported":
|
|
2658
|
-
return;
|
|
2659
|
-
case "ref":
|
|
2660
|
-
return;
|
|
2661
|
-
case "map": {
|
|
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;
|
|
2666
|
-
}
|
|
2667
|
-
case "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;
|
|
2670
|
-
}
|
|
2671
|
-
case "escaped":
|
|
2672
|
-
return n(a.value, l);
|
|
2673
|
-
default:
|
|
2674
|
-
return;
|
|
2675
|
-
}
|
|
2676
|
-
}
|
|
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;
|
|
2686
|
-
continue;
|
|
2687
|
-
}
|
|
2688
|
-
i[a] = s(u, d);
|
|
2689
|
-
}
|
|
2690
|
-
return i;
|
|
2691
|
-
}
|
|
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;
|
|
2697
|
-
}
|
|
2698
|
-
function N(o) {
|
|
2699
|
-
return o !== null && typeof o == "object" && o[w] === "ref" && typeof o.path == "string";
|
|
2700
|
-
}
|
|
2701
|
-
function F(o) {
|
|
2702
|
-
return o.replace(/~/g, "~0").replace(/\//g, "~1");
|
|
2703
|
-
}
|
|
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;
|
|
2709
|
-
try {
|
|
2710
|
-
l = JSON.stringify(r)?.length ?? 0;
|
|
2711
|
-
} catch {
|
|
2712
|
-
l = Number.POSITIVE_INFINITY;
|
|
2713
|
-
}
|
|
2714
|
-
if (l <= e)
|
|
2715
|
-
return c.truncated ? {
|
|
2716
|
-
value: r,
|
|
2717
|
-
truncated: !0,
|
|
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)
|
|
2722
|
-
break;
|
|
2723
|
-
}
|
|
2724
|
-
return {
|
|
2725
|
-
value: { [w]: "unsupported", kind: "truncated" },
|
|
2726
|
-
truncated: !0,
|
|
2727
|
-
note: `State exceeds the ${e}-byte transport limit and could not be reduced to fit.`
|
|
2728
|
-
};
|
|
2729
|
-
}
|
|
2730
|
-
function b(o, e, t) {
|
|
3505
|
+
function S(o, e, t) {
|
|
2731
3506
|
o.onError?.(e, t);
|
|
2732
3507
|
}
|
|
2733
|
-
async function
|
|
3508
|
+
async function Te(o) {
|
|
2734
3509
|
const e = { slices: {}, restored: !1 };
|
|
2735
3510
|
let t;
|
|
2736
3511
|
try {
|
|
2737
3512
|
t = o.source ?? await o.adapter.read(o.key);
|
|
2738
|
-
} catch (
|
|
2739
|
-
return
|
|
3513
|
+
} catch (r) {
|
|
3514
|
+
return S(o, r, "read"), e;
|
|
2740
3515
|
}
|
|
2741
3516
|
if (t == null || t === "") return e;
|
|
2742
|
-
let
|
|
3517
|
+
let n;
|
|
2743
3518
|
try {
|
|
2744
|
-
|
|
2745
|
-
} catch (
|
|
2746
|
-
return
|
|
3519
|
+
n = le(JSON.parse(t));
|
|
3520
|
+
} catch (r) {
|
|
3521
|
+
return S(o, r, "decode"), e;
|
|
2747
3522
|
}
|
|
2748
|
-
if (
|
|
2749
|
-
return
|
|
2750
|
-
if (
|
|
3523
|
+
if (n === null || typeof n != "object" || typeof n.version != "number")
|
|
3524
|
+
return S(o, new Error("persisted payload is not a recognisable envelope"), "decode"), e;
|
|
3525
|
+
if (n.version !== o.version) {
|
|
2751
3526
|
if (o.migrate === void 0)
|
|
2752
|
-
return
|
|
3527
|
+
return S(
|
|
2753
3528
|
o,
|
|
2754
3529
|
new Error(
|
|
2755
|
-
`persisted state is version ${
|
|
3530
|
+
`persisted state is version ${n.version}, this build expects ${o.version}, and no migrate was supplied`
|
|
2756
3531
|
),
|
|
2757
3532
|
"migrate"
|
|
2758
3533
|
), e;
|
|
2759
3534
|
try {
|
|
2760
|
-
const
|
|
2761
|
-
return
|
|
2762
|
-
} catch (
|
|
2763
|
-
return
|
|
3535
|
+
const r = o.migrate(n.slices, n.version);
|
|
3536
|
+
return r === null ? e : { slices: r, restored: !0 };
|
|
3537
|
+
} catch (r) {
|
|
3538
|
+
return S(o, r, "migrate"), e;
|
|
2764
3539
|
}
|
|
2765
3540
|
}
|
|
2766
|
-
return { slices:
|
|
3541
|
+
return { slices: n.slices ?? {}, restored: !0 };
|
|
2767
3542
|
}
|
|
2768
|
-
function
|
|
3543
|
+
function De(o, e) {
|
|
2769
3544
|
if (!e.restored) return o;
|
|
2770
3545
|
const t = {};
|
|
2771
|
-
for (const [
|
|
2772
|
-
const
|
|
2773
|
-
t[
|
|
3546
|
+
for (const [n, r] of Object.entries(o)) {
|
|
3547
|
+
const i = e.slices[n];
|
|
3548
|
+
t[n] = i === void 0 ? r : { ...r, state: i };
|
|
2774
3549
|
}
|
|
2775
3550
|
return t;
|
|
2776
3551
|
}
|
|
2777
|
-
function
|
|
2778
|
-
const t = o ?? {},
|
|
2779
|
-
|
|
3552
|
+
function Q(o, e) {
|
|
3553
|
+
const t = o ?? {}, n = e.slices === void 0 ? t : Object.fromEntries(e.slices.filter((s) => s in t).map((s) => [s, t[s]])), { value: r, report: i } = j({ version: e.version, slices: n });
|
|
3554
|
+
if (i.truncated || i.unsupported.length > 0) {
|
|
3555
|
+
const s = [];
|
|
3556
|
+
i.truncated && s.push("state was too large to encode in full"), i.unsupported.length > 0 && s.push(`values with no faithful representation at: ${i.unsupported.join(", ")}`);
|
|
3557
|
+
const l = s.join("; ");
|
|
3558
|
+
S(
|
|
3559
|
+
e,
|
|
3560
|
+
new Error(`[yoltra] Persisted state is incomplete - ${l}.`),
|
|
3561
|
+
"encode"
|
|
3562
|
+
);
|
|
3563
|
+
}
|
|
3564
|
+
return JSON.stringify(r);
|
|
2780
3565
|
}
|
|
2781
|
-
function
|
|
2782
|
-
const t = e.throttleMs ?? 250,
|
|
2783
|
-
let
|
|
2784
|
-
const
|
|
2785
|
-
if (
|
|
2786
|
-
|
|
3566
|
+
function xe(o, e) {
|
|
3567
|
+
const t = e.throttleMs ?? 250, n = e.slices;
|
|
3568
|
+
let r = null, i = !1;
|
|
3569
|
+
const s = () => {
|
|
3570
|
+
if (i) {
|
|
3571
|
+
i = !1;
|
|
2787
3572
|
try {
|
|
2788
|
-
const a = e.adapter.write(e.key,
|
|
2789
|
-
a instanceof Promise && a.catch((
|
|
3573
|
+
const a = e.adapter.write(e.key, Q(o.getState(), e));
|
|
3574
|
+
a instanceof Promise && a.catch((d) => S(e, d, "write"));
|
|
2790
3575
|
} catch (a) {
|
|
2791
|
-
|
|
3576
|
+
S(e, a, "write");
|
|
2792
3577
|
}
|
|
2793
3578
|
}
|
|
2794
3579
|
}, l = () => {
|
|
2795
|
-
if (
|
|
2796
|
-
|
|
3580
|
+
if (i = !0, t <= 0) {
|
|
3581
|
+
s();
|
|
2797
3582
|
return;
|
|
2798
3583
|
}
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
}, t),
|
|
2802
|
-
},
|
|
2803
|
-
if (
|
|
3584
|
+
r === null && (r = setTimeout(() => {
|
|
3585
|
+
r = null, s();
|
|
3586
|
+
}, t), r.unref?.());
|
|
3587
|
+
}, c = o.instrument((a) => {
|
|
3588
|
+
if (n === void 0) {
|
|
2804
3589
|
l();
|
|
2805
3590
|
return;
|
|
2806
3591
|
}
|
|
2807
3592
|
(a.changedPaths ?? []).some(
|
|
2808
|
-
(
|
|
3593
|
+
(f) => n.some((u) => f === u || f.startsWith(`${u}.`))
|
|
2809
3594
|
) && l();
|
|
2810
3595
|
});
|
|
2811
3596
|
return () => {
|
|
2812
|
-
|
|
3597
|
+
c(), r !== null && (clearTimeout(r), r = null), s();
|
|
2813
3598
|
};
|
|
2814
3599
|
}
|
|
2815
|
-
function
|
|
2816
|
-
return
|
|
3600
|
+
function je(o, e) {
|
|
3601
|
+
return Q(o.getState(), e);
|
|
2817
3602
|
}
|
|
2818
|
-
function
|
|
3603
|
+
function _e(o) {
|
|
2819
3604
|
return {
|
|
2820
3605
|
read: (e) => o.getItem(e),
|
|
2821
3606
|
write: (e, t) => o.setItem(e, t),
|
|
2822
3607
|
remove: (e) => o.removeItem(e)
|
|
2823
3608
|
};
|
|
2824
3609
|
}
|
|
2825
|
-
function
|
|
3610
|
+
function Be(o) {
|
|
2826
3611
|
const e = new Map(Object.entries(o ?? {}));
|
|
2827
3612
|
return {
|
|
2828
3613
|
read: (t) => e.get(t) ?? null,
|
|
2829
|
-
write: (t,
|
|
2830
|
-
e.set(t,
|
|
3614
|
+
write: (t, n) => {
|
|
3615
|
+
e.set(t, n);
|
|
2831
3616
|
},
|
|
2832
3617
|
remove: (t) => {
|
|
2833
3618
|
e.delete(t);
|
|
@@ -2835,28 +3620,31 @@ function $e(o) {
|
|
|
2835
3620
|
};
|
|
2836
3621
|
}
|
|
2837
3622
|
export {
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
3623
|
+
B as CallAbortedError,
|
|
3624
|
+
Z as CallTimeoutError,
|
|
3625
|
+
G as EventBus,
|
|
3626
|
+
J as LooseEventBus,
|
|
3627
|
+
X as Reducer,
|
|
3628
|
+
Re as Rejected,
|
|
3629
|
+
k as Store,
|
|
3630
|
+
Ae as createEntityAdapter,
|
|
3631
|
+
Be as createMemoryAdapter,
|
|
3632
|
+
ke as createStore,
|
|
3633
|
+
_e as createWebStorageAdapter,
|
|
3634
|
+
le as decodeState,
|
|
3635
|
+
Ie as defineEffect,
|
|
3636
|
+
Pe as defineMiddleware,
|
|
3637
|
+
Ce as defineSlice,
|
|
3638
|
+
je as dehydrate,
|
|
2851
3639
|
I as detectChangedProps,
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
3640
|
+
j as encodeState,
|
|
3641
|
+
Oe as encodeStateBounded,
|
|
3642
|
+
Me as eventKeys,
|
|
3643
|
+
C as freezeState,
|
|
3644
|
+
Te as hydrate,
|
|
3645
|
+
Y as isRejected,
|
|
3646
|
+
xe as persist,
|
|
3647
|
+
$e as typedEvents,
|
|
3648
|
+
De as withHydration
|
|
2861
3649
|
};
|
|
2862
3650
|
//# sourceMappingURL=yoltra.mjs.map
|