@yoltra/core 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.es.md +322 -143
- package/README.md +85 -76
- package/dist/types/store/Store.d.ts +5 -52
- package/dist/types/store/matching.d.ts +49 -0
- package/dist/types/store/paths.d.ts +39 -0
- package/dist/types/store/performCall.d.ts +15 -0
- package/dist/types/store/rejection.d.ts +2 -2
- package/dist/types/types.d.ts +4 -4
- package/dist/yoltra.cjs +3 -8
- package/dist/yoltra.cjs.map +1 -1
- package/dist/yoltra.mjs +898 -938
- package/dist/yoltra.mjs.map +1 -1
- package/dist/yoltra.umd.js +3 -8
- package/dist/yoltra.umd.js.map +1 -1
- package/package.json +4 -3
package/dist/yoltra.mjs
CHANGED
|
@@ -1,23 +1,13 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* @yoltra/core v0.
|
|
2
|
+
* @yoltra/core v0.7.0
|
|
3
3
|
* (c) 2026 Manu Ramirez <@pixerael>
|
|
4
|
-
* License: MIT
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
var F = (c, e, t) => e in c ? K(c, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : c[e] = t;
|
|
12
|
-
var p = (c, e, t) => F(c, typeof e != "symbol" ? e + "" : e, t);
|
|
13
|
-
class U {
|
|
14
|
-
constructor() {
|
|
15
|
-
/**
|
|
16
|
-
* Internal registry: `channel → type → Set<handler>`.
|
|
17
|
-
* @internal
|
|
18
|
-
*/
|
|
19
|
-
p(this, "handlers", /* @__PURE__ */ new Map());
|
|
20
|
-
}
|
|
4
|
+
* License: MIT */
|
|
5
|
+
class W {
|
|
6
|
+
/**
|
|
7
|
+
* Internal registry: `channel → type → Set<handler>`.
|
|
8
|
+
* @internal
|
|
9
|
+
*/
|
|
10
|
+
handlers = /* @__PURE__ */ new Map();
|
|
21
11
|
/**
|
|
22
12
|
* Subscribes a handler to an exact `(channel, type)`.
|
|
23
13
|
*
|
|
@@ -107,9 +97,9 @@ class U {
|
|
|
107
97
|
emit(e, t, s, n) {
|
|
108
98
|
const r = this.handlers.get(e);
|
|
109
99
|
if (!r) return;
|
|
110
|
-
const
|
|
111
|
-
if (!(!
|
|
112
|
-
for (const l of [...
|
|
100
|
+
const c = r.get(t);
|
|
101
|
+
if (!(!c || c.size === 0))
|
|
102
|
+
for (const l of [...c])
|
|
113
103
|
try {
|
|
114
104
|
l(s, n);
|
|
115
105
|
} catch (i) {
|
|
@@ -133,37 +123,35 @@ class U {
|
|
|
133
123
|
this.handlers.clear();
|
|
134
124
|
}
|
|
135
125
|
}
|
|
136
|
-
class
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
p(this, "patternIndex", /* @__PURE__ */ new Map());
|
|
166
|
-
}
|
|
126
|
+
class U {
|
|
127
|
+
/**
|
|
128
|
+
* Exact handlers: `channel → type → [handlers]`.
|
|
129
|
+
* @internal
|
|
130
|
+
*/
|
|
131
|
+
handlers = /* @__PURE__ */ new Map();
|
|
132
|
+
/**
|
|
133
|
+
* Pattern handlers with `*` and `**`: `channel → pattern(string) → [handlers]`.
|
|
134
|
+
* @internal
|
|
135
|
+
*/
|
|
136
|
+
patternHandlers = /* @__PURE__ */ new Map();
|
|
137
|
+
/**
|
|
138
|
+
* Patterns bucketed by their first segment, so an emit tests only what could match.
|
|
139
|
+
*
|
|
140
|
+
* @remarks
|
|
141
|
+
* Delivery used to walk every pattern registered on the channel and run the full segment
|
|
142
|
+
* matcher against each. That is linear in the number of patterns rather than in the number
|
|
143
|
+
* that match, and it re-split both the pattern and the subject on every test — for a thousand
|
|
144
|
+
* patterns, two thousand string splits to deliver one event.
|
|
145
|
+
*
|
|
146
|
+
* A subject's first segment can only be matched by a pattern whose first segment is that same
|
|
147
|
+
* literal, or is `*` or `**`. Bucketing on that turns the common shape — distinct event
|
|
148
|
+
* families like `panel.*` and `order.**` — from a scan of everything into a map lookup plus
|
|
149
|
+
* the handful that begin with a wildcard.
|
|
150
|
+
*
|
|
151
|
+
* It buys nothing for a channel where every pattern starts with `**`, since all of those must
|
|
152
|
+
* still be tested. That is the honest worst case, and it is unchanged rather than worsened.
|
|
153
|
+
*/
|
|
154
|
+
patternIndex = /* @__PURE__ */ new Map();
|
|
167
155
|
/**
|
|
168
156
|
* Subscribes a handler to either an **exact** type or a **pattern**.
|
|
169
157
|
*
|
|
@@ -201,13 +189,13 @@ class L {
|
|
|
201
189
|
if (this.isPattern(n)) {
|
|
202
190
|
const r = n;
|
|
203
191
|
this.patternHandlers.has(e) || this.patternHandlers.set(e, /* @__PURE__ */ new Map());
|
|
204
|
-
const
|
|
205
|
-
return
|
|
192
|
+
const c = this.patternHandlers.get(e);
|
|
193
|
+
return c.has(r) || (c.set(r, []), this.indexPattern(e, r)), c.get(r).push(s), () => this.offPattern(e, r, s);
|
|
206
194
|
} else {
|
|
207
195
|
const r = this.normalizeTypeKey(n);
|
|
208
196
|
this.handlers.has(e) || this.handlers.set(e, /* @__PURE__ */ new Map());
|
|
209
|
-
const
|
|
210
|
-
return
|
|
197
|
+
const c = this.handlers.get(e);
|
|
198
|
+
return c.has(r) || c.set(r, []), c.get(r).push(s), () => this.offExactNormalized(e, r, s);
|
|
211
199
|
}
|
|
212
200
|
}
|
|
213
201
|
/**
|
|
@@ -245,8 +233,8 @@ class L {
|
|
|
245
233
|
if (!n) return;
|
|
246
234
|
const r = n.get(t);
|
|
247
235
|
if (!r) return;
|
|
248
|
-
const
|
|
249
|
-
|
|
236
|
+
const c = r.indexOf(s);
|
|
237
|
+
c !== -1 && r.splice(c, 1), r.length === 0 && n.delete(t), n.size === 0 && this.handlers.delete(e);
|
|
250
238
|
}
|
|
251
239
|
/**
|
|
252
240
|
* Internal removal for a **pattern** subscription. No-ops if missing.
|
|
@@ -261,8 +249,8 @@ class L {
|
|
|
261
249
|
if (!n) return;
|
|
262
250
|
const r = n.get(t);
|
|
263
251
|
if (!r) return;
|
|
264
|
-
const
|
|
265
|
-
|
|
252
|
+
const c = r.indexOf(s);
|
|
253
|
+
c !== -1 && r.splice(c, 1), r.length === 0 && (n.delete(t), this.unindexPattern(e, t)), n.size === 0 && (this.patternHandlers.delete(e), this.patternIndex.delete(e));
|
|
266
254
|
}
|
|
267
255
|
/**
|
|
268
256
|
* Emits an event to all exact subscribers first, then to **matching pattern** subscribers.
|
|
@@ -285,20 +273,20 @@ class L {
|
|
|
285
273
|
* @public
|
|
286
274
|
*/
|
|
287
275
|
emit(e, t, s) {
|
|
288
|
-
const n = String(t), r = this.normalizeTypeKey(n),
|
|
289
|
-
for (const
|
|
290
|
-
if (!i.has(
|
|
291
|
-
i.add(
|
|
276
|
+
const n = String(t), r = this.normalizeTypeKey(n), c = this.handlers.get(e)?.get(r) ?? [], l = this.matchingPatternHandlers(e, n), i = /* @__PURE__ */ new Set(), a = (u) => {
|
|
277
|
+
for (const d of [...u])
|
|
278
|
+
if (!i.has(d)) {
|
|
279
|
+
i.add(d);
|
|
292
280
|
try {
|
|
293
|
-
|
|
294
|
-
} catch (
|
|
295
|
-
console.error(
|
|
281
|
+
d(s);
|
|
282
|
+
} catch (h) {
|
|
283
|
+
console.error(h);
|
|
296
284
|
continue;
|
|
297
285
|
}
|
|
298
286
|
}
|
|
299
287
|
};
|
|
300
|
-
a(
|
|
301
|
-
for (const
|
|
288
|
+
a(c);
|
|
289
|
+
for (const u of l) a(u);
|
|
302
290
|
}
|
|
303
291
|
/**
|
|
304
292
|
* Emits a payload that is only built if somebody is listening.
|
|
@@ -317,22 +305,22 @@ class L {
|
|
|
317
305
|
* @public
|
|
318
306
|
*/
|
|
319
307
|
emitWith(e, t, s) {
|
|
320
|
-
const n = String(t), r = this.normalizeTypeKey(n),
|
|
321
|
-
if (
|
|
322
|
-
const i = s(), a = /* @__PURE__ */ new Set(),
|
|
323
|
-
for (const
|
|
324
|
-
if (!a.has(
|
|
325
|
-
a.add(
|
|
308
|
+
const n = String(t), r = this.normalizeTypeKey(n), c = this.handlers.get(e)?.get(r) ?? [], l = this.matchingPatternHandlers(e, n);
|
|
309
|
+
if (c.length === 0 && l.length === 0) return;
|
|
310
|
+
const i = s(), a = /* @__PURE__ */ new Set(), u = (d) => {
|
|
311
|
+
for (const h of [...d])
|
|
312
|
+
if (!a.has(h)) {
|
|
313
|
+
a.add(h);
|
|
326
314
|
try {
|
|
327
|
-
|
|
328
|
-
} catch (
|
|
329
|
-
console.error(
|
|
315
|
+
h(i);
|
|
316
|
+
} catch (p) {
|
|
317
|
+
console.error(p);
|
|
330
318
|
continue;
|
|
331
319
|
}
|
|
332
320
|
}
|
|
333
321
|
};
|
|
334
|
-
|
|
335
|
-
for (const
|
|
322
|
+
u(c);
|
|
323
|
+
for (const d of l) u(d);
|
|
336
324
|
}
|
|
337
325
|
/**
|
|
338
326
|
* Determines if a string is a **pattern** (contains `*`).
|
|
@@ -373,13 +361,13 @@ class L {
|
|
|
373
361
|
indexPattern(e, t) {
|
|
374
362
|
let s = this.patternIndex.get(e);
|
|
375
363
|
s === void 0 && (s = { byHead: /* @__PURE__ */ new Map(), anyHead: [] }, this.patternIndex.set(e, s));
|
|
376
|
-
const n = this.splitPath(t), r = { pattern: t, segments: n },
|
|
377
|
-
if (
|
|
364
|
+
const n = this.splitPath(t), r = { pattern: t, segments: n }, c = n[0];
|
|
365
|
+
if (c === void 0 || c === "*" || c === "**") {
|
|
378
366
|
s.anyHead.push(r);
|
|
379
367
|
return;
|
|
380
368
|
}
|
|
381
|
-
const l = s.byHead.get(
|
|
382
|
-
l === void 0 ? s.byHead.set(
|
|
369
|
+
const l = s.byHead.get(c);
|
|
370
|
+
l === void 0 ? s.byHead.set(c, [r]) : l.push(r);
|
|
383
371
|
}
|
|
384
372
|
/**
|
|
385
373
|
* Removes a pattern from the index. Paired with {@link LooseEventBus.offPattern}.
|
|
@@ -390,8 +378,8 @@ class L {
|
|
|
390
378
|
if (s === void 0) return;
|
|
391
379
|
const n = this.splitPath(t)[0], r = n === void 0 || n === "*" || n === "**" ? s.anyHead : s.byHead.get(n);
|
|
392
380
|
if (r === void 0) return;
|
|
393
|
-
const
|
|
394
|
-
|
|
381
|
+
const c = r.findIndex((l) => l.pattern === t);
|
|
382
|
+
c !== -1 && r.splice(c, 1), r.length === 0 && r !== s.anyHead && n !== void 0 && s.byHead.delete(n);
|
|
395
383
|
}
|
|
396
384
|
/**
|
|
397
385
|
* The handler lists of every pattern matching this subject.
|
|
@@ -407,18 +395,18 @@ class L {
|
|
|
407
395
|
matchingPatternHandlers(e, t) {
|
|
408
396
|
const s = this.patternHandlers.get(e), n = this.patternIndex.get(e);
|
|
409
397
|
if (s === void 0 || s.size === 0 || n === void 0) return [];
|
|
410
|
-
const r = this.splitPath(t),
|
|
411
|
-
for (const
|
|
412
|
-
if (!this.matchSegments(
|
|
413
|
-
const
|
|
414
|
-
|
|
398
|
+
const r = this.splitPath(t), c = [], l = (a) => {
|
|
399
|
+
for (const u of a) {
|
|
400
|
+
if (!this.matchSegments(u.segments, r)) continue;
|
|
401
|
+
const d = s.get(u.pattern);
|
|
402
|
+
d !== void 0 && c.push(d);
|
|
415
403
|
}
|
|
416
404
|
}, i = r[0];
|
|
417
405
|
if (i !== void 0) {
|
|
418
406
|
const a = n.byHead.get(i);
|
|
419
407
|
a !== void 0 && l(a);
|
|
420
408
|
}
|
|
421
|
-
return l(n.anyHead),
|
|
409
|
+
return l(n.anyHead), c;
|
|
422
410
|
}
|
|
423
411
|
/**
|
|
424
412
|
* Pattern matcher over dot-separated segments, which arrive already split.
|
|
@@ -449,14 +437,14 @@ class L {
|
|
|
449
437
|
* @internal
|
|
450
438
|
*/
|
|
451
439
|
matchSegments(e, t) {
|
|
452
|
-
let s = 0, n = 0, r = -1,
|
|
440
|
+
let s = 0, n = 0, r = -1, c = 0;
|
|
453
441
|
for (; n < t.length; )
|
|
454
442
|
if (s < e.length && (e[s] === "*" || e[s] === t[n]))
|
|
455
443
|
s++, n++;
|
|
456
444
|
else if (s < e.length && e[s] === "**")
|
|
457
|
-
r = s,
|
|
445
|
+
r = s, c = n, s++;
|
|
458
446
|
else if (r !== -1)
|
|
459
|
-
s = r + 1, n = ++
|
|
447
|
+
s = r + 1, n = ++c;
|
|
460
448
|
else
|
|
461
449
|
return !1;
|
|
462
450
|
for (; s < e.length && e[s] === "**"; ) s++;
|
|
@@ -494,7 +482,12 @@ class L {
|
|
|
494
482
|
return e;
|
|
495
483
|
}
|
|
496
484
|
}
|
|
497
|
-
class
|
|
485
|
+
class L {
|
|
486
|
+
/**
|
|
487
|
+
* The underlying pure reducer function.
|
|
488
|
+
* @internal
|
|
489
|
+
*/
|
|
490
|
+
_reduce;
|
|
498
491
|
/**
|
|
499
492
|
* Creates a new {@link Reducer} from a pure reducer function.
|
|
500
493
|
*
|
|
@@ -511,11 +504,6 @@ class V {
|
|
|
511
504
|
* @public
|
|
512
505
|
*/
|
|
513
506
|
constructor(e) {
|
|
514
|
-
/**
|
|
515
|
-
* The underlying pure reducer function.
|
|
516
|
-
* @internal
|
|
517
|
-
*/
|
|
518
|
-
p(this, "_reduce");
|
|
519
507
|
this._reduce = e;
|
|
520
508
|
}
|
|
521
509
|
/**
|
|
@@ -537,137 +525,162 @@ class V {
|
|
|
537
525
|
}
|
|
538
526
|
}
|
|
539
527
|
const T = /* @__PURE__ */ new Set();
|
|
540
|
-
function O(
|
|
541
|
-
const t =
|
|
528
|
+
function O(o, e) {
|
|
529
|
+
const t = o ? `${o}.${e}` : e;
|
|
542
530
|
T.has(t) || (T.add(t), console.warn(
|
|
543
|
-
`[yoltra] State key "${e}"${
|
|
531
|
+
`[yoltra] State key "${e}"${o ? ` under "${o}"` : ""} contains a dot. Paths are dotted, so this key is indistinguishable from nested objects of the same name: a subscription to "${t}" may match the wrong value, and DevTools patches for it will address the wrong node. Rename the key, or nest it.`
|
|
544
532
|
));
|
|
545
533
|
}
|
|
546
|
-
function I(
|
|
534
|
+
function I(o, e, t = "", s = /* @__PURE__ */ new Map()) {
|
|
547
535
|
const n = [];
|
|
548
|
-
return P(
|
|
536
|
+
return P(o, e, t, s, n), n;
|
|
549
537
|
}
|
|
550
|
-
function P(
|
|
551
|
-
if (
|
|
552
|
-
if (typeof
|
|
553
|
-
if (typeof
|
|
538
|
+
function P(o, e, t, s, n) {
|
|
539
|
+
if (o === e) return;
|
|
540
|
+
if (typeof o != "object" || typeof e != "object" || o === null || e === null) {
|
|
541
|
+
if (typeof o == "number" && Number.isNaN(o) && Number.isNaN(e))
|
|
554
542
|
return;
|
|
555
543
|
n.push(t);
|
|
556
544
|
return;
|
|
557
545
|
}
|
|
558
|
-
if (
|
|
559
|
-
|
|
546
|
+
if (o instanceof Date && e instanceof Date) {
|
|
547
|
+
o.getTime() !== e.getTime() && n.push(t);
|
|
560
548
|
return;
|
|
561
549
|
}
|
|
562
|
-
if (
|
|
563
|
-
(
|
|
550
|
+
if (o instanceof RegExp && e instanceof RegExp) {
|
|
551
|
+
(o.source !== e.source || e.flags !== o.flags) && n.push(t);
|
|
564
552
|
return;
|
|
565
553
|
}
|
|
566
|
-
if (
|
|
554
|
+
if (o instanceof Map || e instanceof Map) {
|
|
567
555
|
n.push(t);
|
|
568
556
|
return;
|
|
569
557
|
}
|
|
570
|
-
if (
|
|
558
|
+
if (o instanceof Set || e instanceof Set) {
|
|
571
559
|
n.push(t);
|
|
572
560
|
return;
|
|
573
561
|
}
|
|
574
|
-
const r =
|
|
575
|
-
if (l?.has(
|
|
562
|
+
const r = o, c = e, l = s.get(r);
|
|
563
|
+
if (l?.has(c)) return;
|
|
576
564
|
const i = l ?? /* @__PURE__ */ new Set();
|
|
577
|
-
i.add(
|
|
565
|
+
i.add(c), l || s.set(r, i);
|
|
578
566
|
try {
|
|
579
|
-
const a = Array.isArray(
|
|
580
|
-
if (a !==
|
|
567
|
+
const a = Array.isArray(o), u = Array.isArray(e);
|
|
568
|
+
if (a !== u) {
|
|
581
569
|
n.push(t);
|
|
582
570
|
return;
|
|
583
571
|
}
|
|
584
572
|
if (a) {
|
|
585
|
-
const
|
|
586
|
-
|
|
587
|
-
const
|
|
588
|
-
for (let
|
|
589
|
-
|
|
590
|
-
for (let
|
|
591
|
-
n.push(t ? `${t}.${
|
|
573
|
+
const f = o, m = e;
|
|
574
|
+
f.length !== m.length && t && n.push(t);
|
|
575
|
+
const y = Math.min(f.length, m.length);
|
|
576
|
+
for (let g = 0; g < y; g++)
|
|
577
|
+
f[g] !== m[g] && P(f[g], m[g], t ? `${t}.${g}` : `${g}`, s, n);
|
|
578
|
+
for (let g = y; g < Math.max(f.length, m.length); g++)
|
|
579
|
+
n.push(t ? `${t}.${g}` : `${g}`);
|
|
592
580
|
return;
|
|
593
581
|
}
|
|
594
|
-
const
|
|
595
|
-
if (
|
|
582
|
+
const d = Object.keys(o), h = Object.keys(e);
|
|
583
|
+
if (d.length === 0 && h.length === 0) {
|
|
596
584
|
n.push(t);
|
|
597
585
|
return;
|
|
598
586
|
}
|
|
599
|
-
let
|
|
600
|
-
if (
|
|
601
|
-
for (let
|
|
602
|
-
if (!Object.prototype.hasOwnProperty.call(
|
|
603
|
-
|
|
587
|
+
let p = d.length === h.length;
|
|
588
|
+
if (p) {
|
|
589
|
+
for (let f = 0; f < h.length; f++)
|
|
590
|
+
if (!Object.prototype.hasOwnProperty.call(o, h[f])) {
|
|
591
|
+
p = !1;
|
|
604
592
|
break;
|
|
605
593
|
}
|
|
606
594
|
}
|
|
607
|
-
if (
|
|
608
|
-
for (const
|
|
609
|
-
|
|
595
|
+
if (p) {
|
|
596
|
+
for (const f of h)
|
|
597
|
+
o[f] !== e[f] && (process.env.NODE_ENV !== "production" && f.includes(".") && O(t, f), P(o[f], e[f], t ? `${t}.${f}` : f, s, n));
|
|
610
598
|
return;
|
|
611
599
|
}
|
|
612
|
-
for (const
|
|
613
|
-
const
|
|
614
|
-
if (
|
|
615
|
-
process.env.NODE_ENV !== "production" &&
|
|
616
|
-
const
|
|
617
|
-
if (!
|
|
618
|
-
n.push(
|
|
600
|
+
for (const f of h) {
|
|
601
|
+
const m = Object.prototype.hasOwnProperty.call(o, f);
|
|
602
|
+
if (m && o[f] === e[f]) continue;
|
|
603
|
+
process.env.NODE_ENV !== "production" && f.includes(".") && O(t, f);
|
|
604
|
+
const y = t ? `${t}.${f}` : f;
|
|
605
|
+
if (!m) {
|
|
606
|
+
n.push(y);
|
|
619
607
|
continue;
|
|
620
608
|
}
|
|
621
|
-
P(
|
|
609
|
+
P(o[f], e[f], y, s, n);
|
|
622
610
|
}
|
|
623
|
-
for (const
|
|
624
|
-
Object.prototype.hasOwnProperty.call(e,
|
|
611
|
+
for (const f of d)
|
|
612
|
+
Object.prototype.hasOwnProperty.call(e, f) || (process.env.NODE_ENV !== "production" && f.includes(".") && O(t, f), n.push(t ? `${t}.${f}` : f));
|
|
625
613
|
} finally {
|
|
626
|
-
i.delete(
|
|
614
|
+
i.delete(c), i.size === 0 && s.delete(r);
|
|
627
615
|
}
|
|
628
616
|
}
|
|
629
|
-
function M(
|
|
630
|
-
if (
|
|
631
|
-
if (e.add(
|
|
632
|
-
const s =
|
|
617
|
+
function M(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))) return o;
|
|
619
|
+
if (e.add(o), Array.isArray(o)) {
|
|
620
|
+
const s = o;
|
|
633
621
|
for (let n = 0; n < s.length; n++)
|
|
634
622
|
s[n] = M(s[n], e, t);
|
|
635
623
|
return Object.freeze(s);
|
|
636
624
|
}
|
|
637
|
-
for (const s of Object.getOwnPropertyNames(
|
|
638
|
-
const n = Object.getOwnPropertyDescriptor(
|
|
639
|
-
!n || !("value" in n) || (
|
|
625
|
+
for (const s of Object.getOwnPropertyNames(o)) {
|
|
626
|
+
const n = Object.getOwnPropertyDescriptor(o, s);
|
|
627
|
+
!n || !("value" in n) || (o[s] = M(o[s], e, t));
|
|
640
628
|
}
|
|
641
|
-
for (const s of Object.getOwnPropertySymbols(
|
|
642
|
-
const n = Object.getOwnPropertyDescriptor(
|
|
643
|
-
!n || !("value" in n) || (
|
|
629
|
+
for (const s of Object.getOwnPropertySymbols(o)) {
|
|
630
|
+
const n = Object.getOwnPropertyDescriptor(o, s);
|
|
631
|
+
!n || !("value" in n) || (o[s] = M(o[s], e, t));
|
|
632
|
+
}
|
|
633
|
+
return Object.freeze(o);
|
|
634
|
+
}
|
|
635
|
+
const B = /* @__PURE__ */ Symbol.for("yoltra.rejected");
|
|
636
|
+
function fe(o) {
|
|
637
|
+
return { [B]: !0, reason: o };
|
|
638
|
+
}
|
|
639
|
+
function V(o) {
|
|
640
|
+
return typeof o == "object" && o !== null && o[B] === !0;
|
|
641
|
+
}
|
|
642
|
+
class Q extends Error {
|
|
643
|
+
channel;
|
|
644
|
+
type;
|
|
645
|
+
idleMs;
|
|
646
|
+
constructor(e, t, s) {
|
|
647
|
+
super(
|
|
648
|
+
`[yoltra] call to "${e}/${t}" saw no correlated reply for ${s}ms. The timeout is idle rather than total, so this means the responder went quiet, not that it was slow. Check that something handles "${e}/${t}" and that its reply is emitted through the \`emit\` it was handed — a reply emitted from an unrelated context carries no causal link, and needs an explicit correlationId instead.`
|
|
649
|
+
), this.name = "CallTimeoutError", this.channel = e, this.type = t, this.idleMs = s;
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
class C extends Error {
|
|
653
|
+
constructor(e) {
|
|
654
|
+
super(`[yoltra] call aborted: ${e}`), this.name = "CallAbortedError";
|
|
644
655
|
}
|
|
645
|
-
return Object.freeze(c);
|
|
646
656
|
}
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
return {
|
|
657
|
+
function G(o) {
|
|
658
|
+
const [e, t] = o;
|
|
659
|
+
if (t === void 0) return { channel: e, isTerminal: () => !0 };
|
|
660
|
+
if (typeof t == "string") return { channel: e, isTerminal: (n) => n === t };
|
|
661
|
+
const s = new Set(t);
|
|
662
|
+
return { channel: e, isTerminal: (n) => s.has(n) };
|
|
650
663
|
}
|
|
651
|
-
function
|
|
652
|
-
return
|
|
664
|
+
function J(o, e, t) {
|
|
665
|
+
return o.parentId === e ? !0 : t === void 0 ? !1 : o.meta?.correlationId === t;
|
|
653
666
|
}
|
|
654
|
-
class
|
|
667
|
+
class q {
|
|
655
668
|
constructor(e) {
|
|
656
|
-
p(this, "highWaterMark");
|
|
657
|
-
p(this, "buffer", []);
|
|
658
|
-
/** Consumers parked in `take`, oldest first. */
|
|
659
|
-
p(this, "takers", []);
|
|
660
|
-
/** Producers parked in `put`, each with the item they are waiting to hand over. */
|
|
661
|
-
p(this, "putters", []);
|
|
662
|
-
p(this, "consuming", !1);
|
|
663
|
-
/** No more items will be accepted, but what is already here is still owed to the consumer. */
|
|
664
|
-
p(this, "ended", !1);
|
|
665
|
-
/** Abandoned: nothing further is owed to anybody. */
|
|
666
|
-
p(this, "closed", !1);
|
|
667
|
-
/** Items discarded because nobody was iterating and the buffer was full. */
|
|
668
|
-
p(this, "dropped", 0);
|
|
669
669
|
this.highWaterMark = e;
|
|
670
670
|
}
|
|
671
|
+
highWaterMark;
|
|
672
|
+
buffer = [];
|
|
673
|
+
/** Consumers parked in `take`, oldest first. */
|
|
674
|
+
takers = [];
|
|
675
|
+
/** Producers parked in `put`, each with the item they are waiting to hand over. */
|
|
676
|
+
putters = [];
|
|
677
|
+
consuming = !1;
|
|
678
|
+
/** No more items will be accepted, but what is already here is still owed to the consumer. */
|
|
679
|
+
ended = !1;
|
|
680
|
+
/** Abandoned: nothing further is owed to anybody. */
|
|
681
|
+
closed = !1;
|
|
682
|
+
/** Items discarded because nobody was iterating and the buffer was full. */
|
|
683
|
+
dropped = 0;
|
|
671
684
|
/** How many items were discarded for want of a consumer. */
|
|
672
685
|
get droppedCount() {
|
|
673
686
|
return this.dropped;
|
|
@@ -748,46 +761,375 @@ class G {
|
|
|
748
761
|
t.release(), t = this.putters.shift();
|
|
749
762
|
}
|
|
750
763
|
}
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
764
|
+
const Y = 3e4, X = 16;
|
|
765
|
+
function Z(o, e, t, s, n) {
|
|
766
|
+
const { channel: r, isTerminal: c } = G(n.reply), l = n.timeoutMs ?? Y, i = new q(n.highWaterMark ?? X), a = o.idFactory();
|
|
767
|
+
let u, d, h = !1;
|
|
768
|
+
const p = new Promise((E, v) => {
|
|
769
|
+
u = E, d = v;
|
|
770
|
+
});
|
|
771
|
+
p.catch(() => {
|
|
772
|
+
});
|
|
773
|
+
let f = null, m = null;
|
|
774
|
+
const y = (E, v = !1) => {
|
|
775
|
+
h || (h = !0, f !== null && clearTimeout(f), f = null, m?.(), m = null, v ? i.end() : i.close(), n.signal?.removeEventListener("abort", g), E());
|
|
776
|
+
};
|
|
777
|
+
function g() {
|
|
778
|
+
y(() => d(new C(String(n.signal?.reason ?? "signal aborted"))));
|
|
760
779
|
}
|
|
780
|
+
const $ = () => {
|
|
781
|
+
f !== null && clearTimeout(f), f = setTimeout(() => {
|
|
782
|
+
y(() => d(new Q(e, t, l)));
|
|
783
|
+
}, l), f.unref?.();
|
|
784
|
+
};
|
|
785
|
+
return m = o.registerEffect({
|
|
786
|
+
// A pattern effect on the reply channel: which types are terminal is known, which are
|
|
787
|
+
// progress is not, so the filter cannot be a key list.
|
|
788
|
+
when: { channel: r },
|
|
789
|
+
effect: async (E) => {
|
|
790
|
+
if (!h && J(E, a, n.correlationId)) {
|
|
791
|
+
if ($(), c(String(E.type))) {
|
|
792
|
+
y(() => u(E), !0);
|
|
793
|
+
return;
|
|
794
|
+
}
|
|
795
|
+
await i.put(E);
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
}), n.signal !== void 0 && (n.signal.aborted ? g() : n.signal.addEventListener("abort", g, { once: !0 })), $(), o.emit(e, t, s, {
|
|
799
|
+
id: a,
|
|
800
|
+
...n.correlationId !== void 0 ? { meta: { correlationId: n.correlationId } } : {}
|
|
801
|
+
}), {
|
|
802
|
+
then: (E, v) => p.then(E, v),
|
|
803
|
+
catch: (E) => p.catch(E),
|
|
804
|
+
finally: (E) => p.finally(E),
|
|
805
|
+
get dropped() {
|
|
806
|
+
return i.droppedCount;
|
|
807
|
+
},
|
|
808
|
+
cancel: (E = "cancelled") => {
|
|
809
|
+
y(() => d(new C(E)));
|
|
810
|
+
},
|
|
811
|
+
[Symbol.asyncIterator]: () => (i.beginConsuming(), {
|
|
812
|
+
next: () => i.take(),
|
|
813
|
+
// Called by `for await` on `break`, `return` or a throw. Without it, abandoning the
|
|
814
|
+
// loop would leave the effect registered and the producer parked for good.
|
|
815
|
+
return: async () => (i.close(), { value: void 0, done: !0 })
|
|
816
|
+
})
|
|
817
|
+
};
|
|
761
818
|
}
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
819
|
+
function ee(o, e) {
|
|
820
|
+
if (!e) return o;
|
|
821
|
+
const s = (e[0] === "." ? e.slice(1) : e).split(".");
|
|
822
|
+
let n = o;
|
|
823
|
+
for (const r of s) {
|
|
824
|
+
if (n == null) return;
|
|
825
|
+
n = n[r];
|
|
826
|
+
}
|
|
827
|
+
return n;
|
|
766
828
|
}
|
|
767
|
-
function
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
return
|
|
829
|
+
function te(o) {
|
|
830
|
+
if (!o) return [];
|
|
831
|
+
const t = (o[0] === "." ? o.slice(1) : o).split("."), s = [];
|
|
832
|
+
for (let n = 0; n < t.length; n++)
|
|
833
|
+
s.push(t.slice(0, n + 1).join("."));
|
|
834
|
+
return s;
|
|
773
835
|
}
|
|
774
|
-
function
|
|
775
|
-
return
|
|
836
|
+
function k(o, e) {
|
|
837
|
+
return !o || "any" in o && o.any === !0 ? !0 : "keys" in o ? o.keys.some(
|
|
838
|
+
([t, s]) => e.channel === t && e.type === s
|
|
839
|
+
) : "channel" in o ? e.channel === o.channel : "channels" in o ? o.channels.includes(e.channel) : !1;
|
|
776
840
|
}
|
|
777
|
-
function
|
|
841
|
+
function ne(o) {
|
|
842
|
+
return typeof o == "function" ? o : o.middleware;
|
|
843
|
+
}
|
|
844
|
+
function se(o) {
|
|
845
|
+
if (typeof o != "function")
|
|
846
|
+
return o.when;
|
|
847
|
+
}
|
|
848
|
+
function D(o) {
|
|
849
|
+
if (o.when) {
|
|
850
|
+
const e = o.when;
|
|
851
|
+
if ("keys" in e)
|
|
852
|
+
return e.keys;
|
|
853
|
+
}
|
|
854
|
+
return [];
|
|
855
|
+
}
|
|
856
|
+
function re(o, e) {
|
|
778
857
|
try {
|
|
779
858
|
return structuredClone(e);
|
|
780
859
|
} catch (t) {
|
|
781
860
|
throw new Error(
|
|
782
|
-
`[yoltra] Initial state for slice "${String(
|
|
861
|
+
`[yoltra] Initial state for slice "${String(o)}" could not be copied: ${t instanceof Error ? t.message : String(t)}. State must be structured-cloneable — functions, class instances and DOM nodes are not. Keep behaviour out of state and store plain data.`
|
|
783
862
|
);
|
|
784
863
|
}
|
|
785
864
|
}
|
|
786
|
-
function R(
|
|
787
|
-
return process.env.NODE_ENV === "production" ?
|
|
865
|
+
function R(o, e) {
|
|
866
|
+
return process.env.NODE_ENV === "production" ? o : M(o, /* @__PURE__ */ new WeakSet(), e);
|
|
788
867
|
}
|
|
789
|
-
const
|
|
868
|
+
const A = 100, ie = 64, z = 16, S = Object.freeze({ committed: !1, written: !1 }), oe = Object.freeze({ committed: !0, written: !1 }), ce = Object.freeze({ committed: !0, written: !0 }), _ = () => typeof performance < "u" && typeof performance.now == "function" ? performance.now() : Date.now();
|
|
790
869
|
class x {
|
|
870
|
+
/**
|
|
871
|
+
* Store name (used by DevTools & diagnostics).
|
|
872
|
+
*
|
|
873
|
+
* @public
|
|
874
|
+
*/
|
|
875
|
+
name;
|
|
876
|
+
/**
|
|
877
|
+
* Registered middleware pipeline (run **before** reducers).
|
|
878
|
+
* Stores either raw functions (legacy) or MiddlewareSpec objects.
|
|
879
|
+
* Return `false` from the middleware function to stop propagation.
|
|
880
|
+
*
|
|
881
|
+
* @internal
|
|
882
|
+
*/
|
|
883
|
+
middleware;
|
|
884
|
+
/**
|
|
885
|
+
* Installed slice reducers keyed by slice name.
|
|
886
|
+
*
|
|
887
|
+
* @internal
|
|
888
|
+
*/
|
|
889
|
+
reducers;
|
|
890
|
+
/**
|
|
891
|
+
* Current immutable snapshot of the store state.
|
|
892
|
+
* This reference changes whenever any slice changes (shallow immutability).
|
|
893
|
+
*
|
|
894
|
+
* @internal
|
|
895
|
+
*/
|
|
896
|
+
state;
|
|
897
|
+
/**
|
|
898
|
+
* Bus for reducer wiring (emit by `(channel, type)`).
|
|
899
|
+
*
|
|
900
|
+
* @internal
|
|
901
|
+
*/
|
|
902
|
+
reducerBus;
|
|
903
|
+
/**
|
|
904
|
+
* Bus for **granular** connector events (emit by **dotted path** inside a slice).
|
|
905
|
+
*
|
|
906
|
+
* @internal
|
|
907
|
+
*/
|
|
908
|
+
connectorBus;
|
|
909
|
+
/**
|
|
910
|
+
* Coarse-grained listeners (called once per committed event, only if state changed).
|
|
911
|
+
*
|
|
912
|
+
* @internal
|
|
913
|
+
*/
|
|
914
|
+
listeners = /* @__PURE__ */ new Set();
|
|
915
|
+
/**
|
|
916
|
+
* Registered effect handlers keyed by `"channel::type"` for O(1) lookup.
|
|
917
|
+
* Used for effects with explicit `keys` targeting.
|
|
918
|
+
*
|
|
919
|
+
* @internal
|
|
920
|
+
*/
|
|
921
|
+
effects = /* @__PURE__ */ new Map();
|
|
922
|
+
/**
|
|
923
|
+
* Pattern-based effects that need runtime matching.
|
|
924
|
+
* Used for effects with `when: { any }`, `{ channel }`, or `{ channels }`.
|
|
925
|
+
* Stores tuples of [effect function, when matcher].
|
|
926
|
+
*
|
|
927
|
+
* @internal
|
|
928
|
+
*/
|
|
929
|
+
patternEffects = /* @__PURE__ */ new Set();
|
|
930
|
+
/**
|
|
931
|
+
* Committed event subscribers keyed by `"channel::type"` for O(1) lookup.
|
|
932
|
+
* Notified after reducers, before effects, for events that passed middleware.
|
|
933
|
+
*
|
|
934
|
+
* @internal
|
|
935
|
+
*/
|
|
936
|
+
committedEventSubscribers = /* @__PURE__ */ new Map();
|
|
937
|
+
/**
|
|
938
|
+
* Uncommitted event subscribers keyed by `"channel::type"` for O(1) lookup.
|
|
939
|
+
* Notified when middleware rejects an event.
|
|
940
|
+
*
|
|
941
|
+
* @internal
|
|
942
|
+
*/
|
|
943
|
+
uncommittedEventSubscribers = /* @__PURE__ */ new Map();
|
|
944
|
+
/**
|
|
945
|
+
* All-events subscribers keyed by `"channel::type"` for O(1) lookup.
|
|
946
|
+
* Notified for both committed and uncommitted events with phase parameter.
|
|
947
|
+
*
|
|
948
|
+
* @internal
|
|
949
|
+
*/
|
|
950
|
+
/**
|
|
951
|
+
* Subscribers to events that actually changed state, notified after the commit.
|
|
952
|
+
*
|
|
953
|
+
* @remarks
|
|
954
|
+
* Separate from `committedEventSubscribers` rather than a filter over it, because the two
|
|
955
|
+
* answer different questions and one of them is load bearing: `committed` means "not vetoed"
|
|
956
|
+
* and fires for every event a store accepts, including every event in a store with no
|
|
957
|
+
* reducers. Narrowing it would have silently stopped toasts and analytics firing.
|
|
958
|
+
*
|
|
959
|
+
* @internal
|
|
960
|
+
*/
|
|
961
|
+
writtenEventSubscribers = /* @__PURE__ */ new Map();
|
|
962
|
+
allEventSubscribers = /* @__PURE__ */ new Map();
|
|
963
|
+
/**
|
|
964
|
+
* Track reducerBus unsubs per slice for HMR/register/unregister.
|
|
965
|
+
*
|
|
966
|
+
* @internal
|
|
967
|
+
*/
|
|
968
|
+
sliceUnsubs = /* @__PURE__ */ new Map();
|
|
969
|
+
/**
|
|
970
|
+
* Pattern-based reducers that need runtime matching.
|
|
971
|
+
* Used for reducers with `when: { any }`, `{ channel }`, or `{ channels }`.
|
|
972
|
+
* Maps slice name to the `when` matcher.
|
|
973
|
+
*
|
|
974
|
+
* @internal
|
|
975
|
+
*/
|
|
976
|
+
patternReducers = /* @__PURE__ */ new Map();
|
|
977
|
+
/**
|
|
978
|
+
* Whether `__replayEvents()` is allowed.
|
|
979
|
+
* Set from `spec.devtools.allowReplay`.
|
|
980
|
+
*
|
|
981
|
+
* @internal
|
|
982
|
+
*/
|
|
983
|
+
replayEnabled;
|
|
984
|
+
/**
|
|
985
|
+
* Produces the `id` for each emitted event. Defaults to `crypto.randomUUID()`; overridable
|
|
986
|
+
* via {@link StoreSpec.idFactory} for runtimes lacking it or for deterministic tests.
|
|
987
|
+
*
|
|
988
|
+
* @internal
|
|
989
|
+
*/
|
|
990
|
+
idFactory;
|
|
991
|
+
/**
|
|
992
|
+
* Optional hook invoked when an effect throws/rejects. See
|
|
993
|
+
* {@link StoreSpec.onEffectError}. `await emit()` never rejects on effect
|
|
994
|
+
* failure — this is how callers observe effect errors.
|
|
995
|
+
*/
|
|
996
|
+
onEffectError;
|
|
997
|
+
/**
|
|
998
|
+
* Optional hook invoked when a reducer throws. See {@link StoreSpec.onReducerError}. The
|
|
999
|
+
* failing slice is isolated rather than the event being rolled back, so this is the only
|
|
1000
|
+
* signal that a reducer misbehaved.
|
|
1001
|
+
*/
|
|
1002
|
+
onReducerError;
|
|
1003
|
+
/**
|
|
1004
|
+
* `slice:channel:type` combinations already warned about for payload aliasing.
|
|
1005
|
+
*
|
|
1006
|
+
* @remarks
|
|
1007
|
+
* Development-only diagnostics have to stay quiet enough to be read. One warning names the
|
|
1008
|
+
* pattern; repeating it once per event would bury it.
|
|
1009
|
+
*/
|
|
1010
|
+
warnedPayloadAliases = /* @__PURE__ */ new Set();
|
|
1011
|
+
/**
|
|
1012
|
+
* Pending events awaiting the **synchronous** reduce phase (middleware +
|
|
1013
|
+
* reducers + subscribers + coarse listeners). Drained by {@link drainReduce}.
|
|
1014
|
+
*
|
|
1015
|
+
* @internal
|
|
1016
|
+
*/
|
|
1017
|
+
reduceQueue = [];
|
|
1018
|
+
/**
|
|
1019
|
+
* Re-entrancy guard for the synchronous reduce phase.
|
|
1020
|
+
*
|
|
1021
|
+
* @internal
|
|
1022
|
+
*/
|
|
1023
|
+
isReducing = !1;
|
|
1024
|
+
/**
|
|
1025
|
+
* The event currently being reduced, or `null` outside the drain.
|
|
1026
|
+
*
|
|
1027
|
+
* @remarks
|
|
1028
|
+
* This is what makes causality exact rather than best-effort. The drain is synchronous — no
|
|
1029
|
+
* `await` can interleave — so any `emit` that arrives while it is set is, without ambiguity, a
|
|
1030
|
+
* consequence of this event. That catches the case a scoped `emit` closure cannot: a
|
|
1031
|
+
* middleware or subscriber that captured the store and calls `store.emit` directly instead of
|
|
1032
|
+
* using the injected one. Attribution should not depend on which reference a consumer reached
|
|
1033
|
+
* for.
|
|
1034
|
+
*
|
|
1035
|
+
* @internal
|
|
1036
|
+
*/
|
|
1037
|
+
currentEvent = null;
|
|
1038
|
+
/**
|
|
1039
|
+
* Events processed by the drain currently in progress. Compared against
|
|
1040
|
+
* `maxTransitionsPerDrain`, which is off unless configured.
|
|
1041
|
+
*
|
|
1042
|
+
* @internal
|
|
1043
|
+
*/
|
|
1044
|
+
transitionsThisDrain = 0;
|
|
1045
|
+
/**
|
|
1046
|
+
* Ceilings that stop a cascade from becoming a hung process. See {@link StoreSpec.maxReduceDepth}.
|
|
1047
|
+
*
|
|
1048
|
+
* @internal
|
|
1049
|
+
*/
|
|
1050
|
+
maxReduceDepth;
|
|
1051
|
+
maxTransitionsPerDrain;
|
|
1052
|
+
onCascade;
|
|
1053
|
+
onRejected;
|
|
1054
|
+
/**
|
|
1055
|
+
* Registered instrumentation observers (DevTools seam). See {@link instrument}.
|
|
1056
|
+
*
|
|
1057
|
+
* @internal
|
|
1058
|
+
*/
|
|
1059
|
+
instrumentObservers = /* @__PURE__ */ new Set();
|
|
1060
|
+
/**
|
|
1061
|
+
* Scratch array collecting slice-prefixed changed leaf paths during an
|
|
1062
|
+
* instrumented reduce. Set by {@link drainReduce} while observers are active;
|
|
1063
|
+
* appended to by {@link commitStaged}. `null` when not instrumenting.
|
|
1064
|
+
*
|
|
1065
|
+
* @internal
|
|
1066
|
+
*/
|
|
1067
|
+
changedPathSink = null;
|
|
1068
|
+
/**
|
|
1069
|
+
* Where keyed reducers put their pending writes during a reduce, and the refusal one of them
|
|
1070
|
+
* returned.
|
|
1071
|
+
*
|
|
1072
|
+
* @remarks
|
|
1073
|
+
* Keyed reducers are invoked through `reducerBus`, which delivers to handlers and has no way
|
|
1074
|
+
* to hand a value back — the same reason `changedPathSink` exists. `null` outside a reduce.
|
|
1075
|
+
*
|
|
1076
|
+
* @internal
|
|
1077
|
+
*/
|
|
1078
|
+
stagingSink = null;
|
|
1079
|
+
stagedRejection = null;
|
|
1080
|
+
stagedRejectedBy = "";
|
|
1081
|
+
/**
|
|
1082
|
+
* Count of effect tasks currently in flight; surfaced as queue depth by
|
|
1083
|
+
* {@link __devtoolsIntrospect}.
|
|
1084
|
+
*
|
|
1085
|
+
* @internal
|
|
1086
|
+
*/
|
|
1087
|
+
inFlightEffects = 0;
|
|
1088
|
+
/**
|
|
1089
|
+
* Tracks processed events by fingerprint with timestamps for TTL-based deduplication.
|
|
1090
|
+
*
|
|
1091
|
+
* **Deduplication Behavior:**
|
|
1092
|
+
* - Events are fingerprinted using `channel::type::JSON(payload)`
|
|
1093
|
+
* - If an identical fingerprint is seen within the dedup window, it's skipped
|
|
1094
|
+
* - The window is 50ms in development, 100ms in production
|
|
1095
|
+
*
|
|
1096
|
+
* **Limitations:**
|
|
1097
|
+
* - Non-serializable payloads (functions, symbols, circular refs) get unique
|
|
1098
|
+
* fingerprints and won't be deduplicated
|
|
1099
|
+
* - Legitimate rapid-fire identical events may be incorrectly deduplicated
|
|
1100
|
+
* - The cache is bounded to 1000 entries with lazy pruning
|
|
1101
|
+
*
|
|
1102
|
+
* @internal
|
|
1103
|
+
*/
|
|
1104
|
+
processedEvents = /* @__PURE__ */ new Map();
|
|
1105
|
+
/**
|
|
1106
|
+
* Lifetime count of events suppressed by the deduplication cache.
|
|
1107
|
+
* Exposed via {@link __devtoolsIntrospect} so the DevTools agent can
|
|
1108
|
+
* surface it in the STORE_METRICS response without further core changes.
|
|
1109
|
+
*
|
|
1110
|
+
* @internal
|
|
1111
|
+
*/
|
|
1112
|
+
dedupCount = 0;
|
|
1113
|
+
/**
|
|
1114
|
+
* Store-owned metadata for registered effects, keyed by the effect function.
|
|
1115
|
+
* Kept **off** the caller's function object: mutating a user-owned function
|
|
1116
|
+
* (the old `fn.__quoMeta`) bled metadata across stores that share a handler
|
|
1117
|
+
* and left it attached after unregister. Cleared on {@link dispose}.
|
|
1118
|
+
*
|
|
1119
|
+
* @internal
|
|
1120
|
+
*/
|
|
1121
|
+
effectMeta = /* @__PURE__ */ new WeakMap();
|
|
1122
|
+
/**
|
|
1123
|
+
* Configuration for event deduplication.
|
|
1124
|
+
* @internal
|
|
1125
|
+
*/
|
|
1126
|
+
dedupConfig;
|
|
1127
|
+
/**
|
|
1128
|
+
* Timer for periodic cleanup of processed events.
|
|
1129
|
+
*
|
|
1130
|
+
* @internal
|
|
1131
|
+
*/
|
|
1132
|
+
eventCleanupTimer = null;
|
|
791
1133
|
/**
|
|
792
1134
|
* Creates a store from a {@link StoreSpec}.
|
|
793
1135
|
*
|
|
@@ -796,270 +1138,7 @@ class x {
|
|
|
796
1138
|
* @public
|
|
797
1139
|
*/
|
|
798
1140
|
constructor(e) {
|
|
799
|
-
|
|
800
|
-
* Store name (used by DevTools & diagnostics).
|
|
801
|
-
*
|
|
802
|
-
* @public
|
|
803
|
-
*/
|
|
804
|
-
p(this, "name");
|
|
805
|
-
/**
|
|
806
|
-
* Registered middleware pipeline (run **before** reducers).
|
|
807
|
-
* Stores either raw functions (legacy) or MiddlewareSpec objects.
|
|
808
|
-
* Return `false` from the middleware function to stop propagation.
|
|
809
|
-
*
|
|
810
|
-
* @internal
|
|
811
|
-
*/
|
|
812
|
-
p(this, "middleware");
|
|
813
|
-
/**
|
|
814
|
-
* Installed slice reducers keyed by slice name.
|
|
815
|
-
*
|
|
816
|
-
* @internal
|
|
817
|
-
*/
|
|
818
|
-
p(this, "reducers");
|
|
819
|
-
/**
|
|
820
|
-
* Current immutable snapshot of the store state.
|
|
821
|
-
* This reference changes whenever any slice changes (shallow immutability).
|
|
822
|
-
*
|
|
823
|
-
* @internal
|
|
824
|
-
*/
|
|
825
|
-
p(this, "state");
|
|
826
|
-
/**
|
|
827
|
-
* Bus for reducer wiring (emit by `(channel, type)`).
|
|
828
|
-
*
|
|
829
|
-
* @internal
|
|
830
|
-
*/
|
|
831
|
-
p(this, "reducerBus");
|
|
832
|
-
/**
|
|
833
|
-
* Bus for **granular** connector events (emit by **dotted path** inside a slice).
|
|
834
|
-
*
|
|
835
|
-
* @internal
|
|
836
|
-
*/
|
|
837
|
-
p(this, "connectorBus");
|
|
838
|
-
/**
|
|
839
|
-
* Coarse-grained listeners (called once per committed event, only if state changed).
|
|
840
|
-
*
|
|
841
|
-
* @internal
|
|
842
|
-
*/
|
|
843
|
-
p(this, "listeners", /* @__PURE__ */ new Set());
|
|
844
|
-
/**
|
|
845
|
-
* Registered effect handlers keyed by `"channel::type"` for O(1) lookup.
|
|
846
|
-
* Used for effects with explicit `keys` targeting.
|
|
847
|
-
*
|
|
848
|
-
* @internal
|
|
849
|
-
*/
|
|
850
|
-
p(this, "effects", /* @__PURE__ */ new Map());
|
|
851
|
-
/**
|
|
852
|
-
* Pattern-based effects that need runtime matching.
|
|
853
|
-
* Used for effects with `when: { any }`, `{ channel }`, or `{ channels }`.
|
|
854
|
-
* Stores tuples of [effect function, when matcher].
|
|
855
|
-
*
|
|
856
|
-
* @internal
|
|
857
|
-
*/
|
|
858
|
-
p(this, "patternEffects", /* @__PURE__ */ new Set());
|
|
859
|
-
/**
|
|
860
|
-
* Committed event subscribers keyed by `"channel::type"` for O(1) lookup.
|
|
861
|
-
* Notified after reducers, before effects, for events that passed middleware.
|
|
862
|
-
*
|
|
863
|
-
* @internal
|
|
864
|
-
*/
|
|
865
|
-
p(this, "committedEventSubscribers", /* @__PURE__ */ new Map());
|
|
866
|
-
/**
|
|
867
|
-
* Uncommitted event subscribers keyed by `"channel::type"` for O(1) lookup.
|
|
868
|
-
* Notified when middleware rejects an event.
|
|
869
|
-
*
|
|
870
|
-
* @internal
|
|
871
|
-
*/
|
|
872
|
-
p(this, "uncommittedEventSubscribers", /* @__PURE__ */ new Map());
|
|
873
|
-
/**
|
|
874
|
-
* All-events subscribers keyed by `"channel::type"` for O(1) lookup.
|
|
875
|
-
* Notified for both committed and uncommitted events with phase parameter.
|
|
876
|
-
*
|
|
877
|
-
* @internal
|
|
878
|
-
*/
|
|
879
|
-
/**
|
|
880
|
-
* Subscribers to events that actually changed state, notified after the commit.
|
|
881
|
-
*
|
|
882
|
-
* @remarks
|
|
883
|
-
* Separate from `committedEventSubscribers` rather than a filter over it, because the two
|
|
884
|
-
* answer different questions and one of them is load bearing: `committed` means "not vetoed"
|
|
885
|
-
* and fires for every event a store accepts, including every event in a store with no
|
|
886
|
-
* reducers. Narrowing it would have silently stopped toasts and analytics firing.
|
|
887
|
-
*
|
|
888
|
-
* @internal
|
|
889
|
-
*/
|
|
890
|
-
p(this, "writtenEventSubscribers", /* @__PURE__ */ new Map());
|
|
891
|
-
p(this, "allEventSubscribers", /* @__PURE__ */ new Map());
|
|
892
|
-
/**
|
|
893
|
-
* Track reducerBus unsubs per slice for HMR/register/unregister.
|
|
894
|
-
*
|
|
895
|
-
* @internal
|
|
896
|
-
*/
|
|
897
|
-
p(this, "sliceUnsubs", /* @__PURE__ */ new Map());
|
|
898
|
-
/**
|
|
899
|
-
* Pattern-based reducers that need runtime matching.
|
|
900
|
-
* Used for reducers with `when: { any }`, `{ channel }`, or `{ channels }`.
|
|
901
|
-
* Maps slice name to the `when` matcher.
|
|
902
|
-
*
|
|
903
|
-
* @internal
|
|
904
|
-
*/
|
|
905
|
-
p(this, "patternReducers", /* @__PURE__ */ new Map());
|
|
906
|
-
/**
|
|
907
|
-
* Whether `__replayEvents()` is allowed.
|
|
908
|
-
* Set from `spec.devtools.allowReplay`.
|
|
909
|
-
*
|
|
910
|
-
* @internal
|
|
911
|
-
*/
|
|
912
|
-
p(this, "replayEnabled");
|
|
913
|
-
/**
|
|
914
|
-
* Produces the `id` for each emitted event. Defaults to `crypto.randomUUID()`; overridable
|
|
915
|
-
* via {@link StoreSpec.idFactory} for runtimes lacking it or for deterministic tests.
|
|
916
|
-
*
|
|
917
|
-
* @internal
|
|
918
|
-
*/
|
|
919
|
-
p(this, "idFactory");
|
|
920
|
-
/**
|
|
921
|
-
* Optional hook invoked when an effect throws/rejects. See
|
|
922
|
-
* {@link StoreSpec.onEffectError}. `await emit()` never rejects on effect
|
|
923
|
-
* failure — this is how callers observe effect errors.
|
|
924
|
-
*/
|
|
925
|
-
p(this, "onEffectError");
|
|
926
|
-
/**
|
|
927
|
-
* Optional hook invoked when a reducer throws. See {@link StoreSpec.onReducerError}. The
|
|
928
|
-
* failing slice is isolated rather than the event being rolled back, so this is the only
|
|
929
|
-
* signal that a reducer misbehaved.
|
|
930
|
-
*/
|
|
931
|
-
p(this, "onReducerError");
|
|
932
|
-
/**
|
|
933
|
-
* `slice:channel:type` combinations already warned about for payload aliasing.
|
|
934
|
-
*
|
|
935
|
-
* @remarks
|
|
936
|
-
* Development-only diagnostics have to stay quiet enough to be read. One warning names the
|
|
937
|
-
* pattern; repeating it once per event would bury it.
|
|
938
|
-
*/
|
|
939
|
-
p(this, "warnedPayloadAliases", /* @__PURE__ */ new Set());
|
|
940
|
-
/**
|
|
941
|
-
* Pending events awaiting the **synchronous** reduce phase (middleware +
|
|
942
|
-
* reducers + subscribers + coarse listeners). Drained by {@link drainReduce}.
|
|
943
|
-
*
|
|
944
|
-
* @internal
|
|
945
|
-
*/
|
|
946
|
-
p(this, "reduceQueue", []);
|
|
947
|
-
/**
|
|
948
|
-
* Re-entrancy guard for the synchronous reduce phase.
|
|
949
|
-
*
|
|
950
|
-
* @internal
|
|
951
|
-
*/
|
|
952
|
-
p(this, "isReducing", !1);
|
|
953
|
-
/**
|
|
954
|
-
* The event currently being reduced, or `null` outside the drain.
|
|
955
|
-
*
|
|
956
|
-
* @remarks
|
|
957
|
-
* This is what makes causality exact rather than best-effort. The drain is synchronous — no
|
|
958
|
-
* `await` can interleave — so any `emit` that arrives while it is set is, without ambiguity, a
|
|
959
|
-
* consequence of this event. That catches the case a scoped `emit` closure cannot: a
|
|
960
|
-
* middleware or subscriber that captured the store and calls `store.emit` directly instead of
|
|
961
|
-
* using the injected one. Attribution should not depend on which reference a consumer reached
|
|
962
|
-
* for.
|
|
963
|
-
*
|
|
964
|
-
* @internal
|
|
965
|
-
*/
|
|
966
|
-
p(this, "currentEvent", null);
|
|
967
|
-
/**
|
|
968
|
-
* Events processed by the drain currently in progress. Compared against
|
|
969
|
-
* `maxTransitionsPerDrain`, which is off unless configured.
|
|
970
|
-
*
|
|
971
|
-
* @internal
|
|
972
|
-
*/
|
|
973
|
-
p(this, "transitionsThisDrain", 0);
|
|
974
|
-
/**
|
|
975
|
-
* Ceilings that stop a cascade from becoming a hung process. See {@link StoreSpec.maxReduceDepth}.
|
|
976
|
-
*
|
|
977
|
-
* @internal
|
|
978
|
-
*/
|
|
979
|
-
p(this, "maxReduceDepth");
|
|
980
|
-
p(this, "maxTransitionsPerDrain");
|
|
981
|
-
p(this, "onCascade");
|
|
982
|
-
p(this, "onRejected");
|
|
983
|
-
/**
|
|
984
|
-
* Registered instrumentation observers (DevTools seam). See {@link instrument}.
|
|
985
|
-
*
|
|
986
|
-
* @internal
|
|
987
|
-
*/
|
|
988
|
-
p(this, "instrumentObservers", /* @__PURE__ */ new Set());
|
|
989
|
-
/**
|
|
990
|
-
* Scratch array collecting slice-prefixed changed leaf paths during an
|
|
991
|
-
* instrumented reduce. Set by {@link drainReduce} while observers are active;
|
|
992
|
-
* appended to by {@link commitStaged}. `null` when not instrumenting.
|
|
993
|
-
*
|
|
994
|
-
* @internal
|
|
995
|
-
*/
|
|
996
|
-
p(this, "changedPathSink", null);
|
|
997
|
-
/**
|
|
998
|
-
* Where keyed reducers put their pending writes during a reduce, and the refusal one of them
|
|
999
|
-
* returned.
|
|
1000
|
-
*
|
|
1001
|
-
* @remarks
|
|
1002
|
-
* Keyed reducers are invoked through `reducerBus`, which delivers to handlers and has no way
|
|
1003
|
-
* to hand a value back — the same reason `changedPathSink` exists. `null` outside a reduce.
|
|
1004
|
-
*
|
|
1005
|
-
* @internal
|
|
1006
|
-
*/
|
|
1007
|
-
p(this, "stagingSink", null);
|
|
1008
|
-
p(this, "stagedRejection", null);
|
|
1009
|
-
p(this, "stagedRejectedBy", "");
|
|
1010
|
-
/**
|
|
1011
|
-
* Count of effect tasks currently in flight; surfaced as queue depth by
|
|
1012
|
-
* {@link __devtoolsIntrospect}.
|
|
1013
|
-
*
|
|
1014
|
-
* @internal
|
|
1015
|
-
*/
|
|
1016
|
-
p(this, "inFlightEffects", 0);
|
|
1017
|
-
/**
|
|
1018
|
-
* Tracks processed events by fingerprint with timestamps for TTL-based deduplication.
|
|
1019
|
-
*
|
|
1020
|
-
* **Deduplication Behavior:**
|
|
1021
|
-
* - Events are fingerprinted using `channel::type::JSON(payload)`
|
|
1022
|
-
* - If an identical fingerprint is seen within the dedup window, it's skipped
|
|
1023
|
-
* - The window is 50ms in development, 100ms in production
|
|
1024
|
-
*
|
|
1025
|
-
* **Limitations:**
|
|
1026
|
-
* - Non-serializable payloads (functions, symbols, circular refs) get unique
|
|
1027
|
-
* fingerprints and won't be deduplicated
|
|
1028
|
-
* - Legitimate rapid-fire identical events may be incorrectly deduplicated
|
|
1029
|
-
* - The cache is bounded to 1000 entries with lazy pruning
|
|
1030
|
-
*
|
|
1031
|
-
* @internal
|
|
1032
|
-
*/
|
|
1033
|
-
p(this, "processedEvents", /* @__PURE__ */ new Map());
|
|
1034
|
-
/**
|
|
1035
|
-
* Lifetime count of events suppressed by the deduplication cache.
|
|
1036
|
-
* Exposed via {@link __devtoolsIntrospect} so the DevTools agent can
|
|
1037
|
-
* surface it in the STORE_METRICS response without further core changes.
|
|
1038
|
-
*
|
|
1039
|
-
* @internal
|
|
1040
|
-
*/
|
|
1041
|
-
p(this, "dedupCount", 0);
|
|
1042
|
-
/**
|
|
1043
|
-
* Store-owned metadata for registered effects, keyed by the effect function.
|
|
1044
|
-
* Kept **off** the caller's function object: mutating a user-owned function
|
|
1045
|
-
* (the old `fn.__quoMeta`) bled metadata across stores that share a handler
|
|
1046
|
-
* and left it attached after unregister. Cleared on {@link dispose}.
|
|
1047
|
-
*
|
|
1048
|
-
* @internal
|
|
1049
|
-
*/
|
|
1050
|
-
p(this, "effectMeta", /* @__PURE__ */ new WeakMap());
|
|
1051
|
-
/**
|
|
1052
|
-
* Configuration for event deduplication.
|
|
1053
|
-
* @internal
|
|
1054
|
-
*/
|
|
1055
|
-
p(this, "dedupConfig");
|
|
1056
|
-
/**
|
|
1057
|
-
* Timer for periodic cleanup of processed events.
|
|
1058
|
-
*
|
|
1059
|
-
* @internal
|
|
1060
|
-
*/
|
|
1061
|
-
p(this, "eventCleanupTimer", null);
|
|
1062
|
-
if (this.name = e.name ?? "yoltra Store", this.reducerBus = new U(), this.connectorBus = new L(), this.middleware = [...e.middleware ?? []], this.reducers = {}, this.state = {}, this.replayEnabled = e.devtools?.allowReplay ?? !1, this.idFactory = e.idFactory ?? (() => crypto.randomUUID()), this.onEffectError = e.onEffectError, this.onReducerError = e.onReducerError, this.maxReduceDepth = e.maxReduceDepth ?? Z, this.maxTransitionsPerDrain = e.maxTransitionsPerDrain ?? 1 / 0, this.onCascade = e.onCascade, this.onRejected = e.onRejected, this.dedupConfig = {
|
|
1141
|
+
if (this.name = e.name ?? "yoltra Store", this.reducerBus = new W(), this.connectorBus = new U(), this.middleware = [...e.middleware ?? []], this.reducers = {}, this.state = {}, this.replayEnabled = e.devtools?.allowReplay ?? !1, this.idFactory = e.idFactory ?? (() => crypto.randomUUID()), this.onEffectError = e.onEffectError, this.onReducerError = e.onReducerError, this.maxReduceDepth = e.maxReduceDepth ?? ie, this.maxTransitionsPerDrain = e.maxTransitionsPerDrain ?? 1 / 0, this.onCascade = e.onCascade, this.onRejected = e.onRejected, this.dedupConfig = {
|
|
1063
1142
|
windowMs: e.dedupWindowMs ?? 0,
|
|
1064
1143
|
maxCacheSize: 1e3
|
|
1065
1144
|
}, Object.entries(e.reducer).forEach(([t, s]) => {
|
|
@@ -1142,7 +1221,7 @@ class x {
|
|
|
1142
1221
|
* @internal
|
|
1143
1222
|
*/
|
|
1144
1223
|
pruneProcessedEvents(e) {
|
|
1145
|
-
const t = Math.max(this.dedupConfig.windowMs,
|
|
1224
|
+
const t = Math.max(this.dedupConfig.windowMs, A), s = e - t * 2;
|
|
1146
1225
|
for (const [n, r] of this.processedEvents)
|
|
1147
1226
|
r < s && this.processedEvents.delete(n);
|
|
1148
1227
|
this.processedEvents.size === 0 && this.eventCleanupTimer !== null && (clearInterval(this.eventCleanupTimer), this.eventCleanupTimer = null);
|
|
@@ -1164,55 +1243,10 @@ class x {
|
|
|
1164
1243
|
);
|
|
1165
1244
|
try {
|
|
1166
1245
|
this.onCascade?.({ limit: e, limitValue: t, event: s, depth: n, chain: r });
|
|
1167
|
-
} catch (
|
|
1168
|
-
console.error("onCascade handler error:",
|
|
1246
|
+
} catch (c) {
|
|
1247
|
+
console.error("onCascade handler error:", c);
|
|
1169
1248
|
}
|
|
1170
1249
|
}
|
|
1171
|
-
/**
|
|
1172
|
-
* Checks if an event matches a `When` matcher.
|
|
1173
|
-
*
|
|
1174
|
-
* @param when - The When matcher (or undefined for "all events").
|
|
1175
|
-
* @param event - The event to check.
|
|
1176
|
-
* @returns `true` if the event matches, `false` otherwise.
|
|
1177
|
-
*
|
|
1178
|
-
* @remarks
|
|
1179
|
-
* - `undefined` or missing `when` matches ALL events.
|
|
1180
|
-
* - `{ any: true }` matches ALL events.
|
|
1181
|
-
* - `{ keys: [...] }` matches if event's `[channel, type]` is in the array.
|
|
1182
|
-
* - `{ channel: 'x' }` matches if event's channel equals 'x'.
|
|
1183
|
-
* - `{ channels: ['x', 'y'] }` matches if event's channel is in the array.
|
|
1184
|
-
*
|
|
1185
|
-
* @internal
|
|
1186
|
-
*/
|
|
1187
|
-
matchesWhen(e, t) {
|
|
1188
|
-
return !e || "any" in e && e.any === !0 ? !0 : "keys" in e ? e.keys.some(
|
|
1189
|
-
([s, n]) => t.channel === s && t.type === n
|
|
1190
|
-
) : "channel" in e ? t.channel === e.channel : "channels" in e ? e.channels.includes(t.channel) : !1;
|
|
1191
|
-
}
|
|
1192
|
-
/**
|
|
1193
|
-
* Extracts the middleware function from a MiddlewareInput.
|
|
1194
|
-
* Handles both raw functions (legacy) and MiddlewareSpec objects.
|
|
1195
|
-
*
|
|
1196
|
-
* @param input - MiddlewareInput (function or spec).
|
|
1197
|
-
* @returns The middleware function.
|
|
1198
|
-
*
|
|
1199
|
-
* @internal
|
|
1200
|
-
*/
|
|
1201
|
-
getMiddlewareFunction(e) {
|
|
1202
|
-
return typeof e == "function" ? e : e.middleware;
|
|
1203
|
-
}
|
|
1204
|
-
/**
|
|
1205
|
-
* Gets the `when` matcher from a MiddlewareInput.
|
|
1206
|
-
*
|
|
1207
|
-
* @param input - MiddlewareInput (function or spec).
|
|
1208
|
-
* @returns The `when` matcher, or `undefined` for raw functions (match all).
|
|
1209
|
-
*
|
|
1210
|
-
* @internal
|
|
1211
|
-
*/
|
|
1212
|
-
getMiddlewareWhen(e) {
|
|
1213
|
-
if (typeof e != "function")
|
|
1214
|
-
return e.when;
|
|
1215
|
-
}
|
|
1216
1250
|
/**
|
|
1217
1251
|
* Invokes all registered **effects** for a given event.
|
|
1218
1252
|
* Handles both key-based effects (O(1) lookup) and pattern-based effects (runtime matching).
|
|
@@ -1227,11 +1261,11 @@ class x {
|
|
|
1227
1261
|
for (const r of [...n])
|
|
1228
1262
|
try {
|
|
1229
1263
|
await r(e, this.getState, t);
|
|
1230
|
-
} catch (
|
|
1231
|
-
console.error("Effect error:",
|
|
1264
|
+
} catch (c) {
|
|
1265
|
+
console.error("Effect error:", c), this.onEffectError?.(c, e);
|
|
1232
1266
|
}
|
|
1233
|
-
for (const { effect: r, when:
|
|
1234
|
-
if (
|
|
1267
|
+
for (const { effect: r, when: c } of this.patternEffects)
|
|
1268
|
+
if (k(c, e))
|
|
1235
1269
|
try {
|
|
1236
1270
|
await r(e, this.getState, t);
|
|
1237
1271
|
} catch (l) {
|
|
@@ -1254,7 +1288,7 @@ class x {
|
|
|
1254
1288
|
depth: e.depth ?? 0,
|
|
1255
1289
|
chain: [...this.currentEvent?.chain ?? [], e.id].slice(-z)
|
|
1256
1290
|
};
|
|
1257
|
-
return ((s, n, r,
|
|
1291
|
+
return ((s, n, r, c) => this.emitCaused(t, s, n, r, c));
|
|
1258
1292
|
}
|
|
1259
1293
|
/**
|
|
1260
1294
|
* Notifies event subscribers for a specific phase.
|
|
@@ -1271,9 +1305,9 @@ class x {
|
|
|
1271
1305
|
if (r?.size)
|
|
1272
1306
|
for (const l of [...r]) this.invokeEventSubscriber(l, e, t);
|
|
1273
1307
|
if (t === "written") return;
|
|
1274
|
-
const
|
|
1275
|
-
if (
|
|
1276
|
-
for (const l of [...
|
|
1308
|
+
const c = this.allEventSubscribers.get(s);
|
|
1309
|
+
if (c?.size)
|
|
1310
|
+
for (const l of [...c]) this.invokeEventSubscriber(l, e, t);
|
|
1277
1311
|
}
|
|
1278
1312
|
/**
|
|
1279
1313
|
* Invokes a single event-subscription handler **fire-and-forget**: synchronous
|
|
@@ -1366,10 +1400,10 @@ class x {
|
|
|
1366
1400
|
*/
|
|
1367
1401
|
stageSlice(e, t, s) {
|
|
1368
1402
|
const n = this.state[e], r = this.reducers[e].reduce(n, t);
|
|
1369
|
-
if (
|
|
1403
|
+
if (V(r)) return r;
|
|
1370
1404
|
if (n === r) return null;
|
|
1371
|
-
const
|
|
1372
|
-
if (
|
|
1405
|
+
const c = I(n, r);
|
|
1406
|
+
if (c.length === 0) return null;
|
|
1373
1407
|
const l = t.payload, i = process.env.NODE_ENV !== "production" && l !== null && typeof l == "object" ? {
|
|
1374
1408
|
watch: l,
|
|
1375
1409
|
onFound: () => {
|
|
@@ -1383,7 +1417,7 @@ class x {
|
|
|
1383
1417
|
name: e,
|
|
1384
1418
|
prev: n,
|
|
1385
1419
|
frozen: R(r, i),
|
|
1386
|
-
leafPaths:
|
|
1420
|
+
leafPaths: c
|
|
1387
1421
|
}), null;
|
|
1388
1422
|
}
|
|
1389
1423
|
/**
|
|
@@ -1415,18 +1449,18 @@ class x {
|
|
|
1415
1449
|
this.changedPathSink.push(r ? `${n.name}.${r}` : n.name);
|
|
1416
1450
|
for (const n of e) {
|
|
1417
1451
|
const r = /* @__PURE__ */ new Set();
|
|
1418
|
-
for (const
|
|
1419
|
-
if (
|
|
1452
|
+
for (const c of n.leafPaths) {
|
|
1453
|
+
if (c === "") {
|
|
1420
1454
|
r.add("");
|
|
1421
1455
|
continue;
|
|
1422
1456
|
}
|
|
1423
|
-
for (const l of x.buildAncestorPaths(
|
|
1457
|
+
for (const l of x.buildAncestorPaths(c)) r.add(l);
|
|
1424
1458
|
}
|
|
1425
|
-
for (const
|
|
1426
|
-
this.connectorBus.emitWith(n.name,
|
|
1427
|
-
oldValue: this.getAtPath(n.prev,
|
|
1428
|
-
newValue: this.getAtPath(n.frozen,
|
|
1429
|
-
path:
|
|
1459
|
+
for (const c of r)
|
|
1460
|
+
this.connectorBus.emitWith(n.name, c, () => ({
|
|
1461
|
+
oldValue: this.getAtPath(n.prev, c),
|
|
1462
|
+
newValue: this.getAtPath(n.frozen, c),
|
|
1463
|
+
path: c,
|
|
1430
1464
|
// Provenance, built inside the same lazy factory as the values: a subscriber that
|
|
1431
1465
|
// needs to know why a value moved no longer has to mirror the cause into state and
|
|
1432
1466
|
// keep it there twice.
|
|
@@ -1454,10 +1488,10 @@ class x {
|
|
|
1454
1488
|
}), t = [];
|
|
1455
1489
|
for (const [l, i] of this.effects) {
|
|
1456
1490
|
if (i.size === 0) continue;
|
|
1457
|
-
const [a,
|
|
1458
|
-
for (const
|
|
1459
|
-
const
|
|
1460
|
-
t.push({ channel: a, type:
|
|
1491
|
+
const [a, u] = l.split("::");
|
|
1492
|
+
for (const d of i) {
|
|
1493
|
+
const h = this.effectMeta.get(d);
|
|
1494
|
+
t.push({ channel: a, type: u, name: h?.name, description: h?.description });
|
|
1461
1495
|
}
|
|
1462
1496
|
}
|
|
1463
1497
|
for (const l of this.patternEffects) {
|
|
@@ -1483,30 +1517,30 @@ class x {
|
|
|
1483
1517
|
const r = [];
|
|
1484
1518
|
for (const [l, i] of this.committedEventSubscribers) {
|
|
1485
1519
|
if (i.size === 0) continue;
|
|
1486
|
-
const [a,
|
|
1487
|
-
for (let
|
|
1488
|
-
r.push({ channel: a, type:
|
|
1520
|
+
const [a, u] = l.split("::");
|
|
1521
|
+
for (let d = 0; d < i.size; d++)
|
|
1522
|
+
r.push({ channel: a, type: u, phase: "committed" });
|
|
1489
1523
|
}
|
|
1490
1524
|
for (const [l, i] of this.uncommittedEventSubscribers) {
|
|
1491
1525
|
if (i.size === 0) continue;
|
|
1492
|
-
const [a,
|
|
1493
|
-
for (let
|
|
1494
|
-
r.push({ channel: a, type:
|
|
1526
|
+
const [a, u] = l.split("::");
|
|
1527
|
+
for (let d = 0; d < i.size; d++)
|
|
1528
|
+
r.push({ channel: a, type: u, phase: "uncommitted" });
|
|
1495
1529
|
}
|
|
1496
1530
|
for (const [l, i] of this.allEventSubscribers) {
|
|
1497
1531
|
if (i.size === 0) continue;
|
|
1498
|
-
const [a,
|
|
1499
|
-
for (let
|
|
1500
|
-
r.push({ channel: a, type:
|
|
1532
|
+
const [a, u] = l.split("::");
|
|
1533
|
+
for (let d = 0; d < i.size; d++)
|
|
1534
|
+
r.push({ channel: a, type: u, phase: "all" });
|
|
1501
1535
|
}
|
|
1502
|
-
const
|
|
1536
|
+
const c = this.listeners.size;
|
|
1503
1537
|
return {
|
|
1504
1538
|
reducers: e,
|
|
1505
1539
|
effects: t,
|
|
1506
1540
|
middleware: s,
|
|
1507
1541
|
atomic: n,
|
|
1508
1542
|
event: r,
|
|
1509
|
-
coarse:
|
|
1543
|
+
coarse: c,
|
|
1510
1544
|
dedupHits: this.dedupCount,
|
|
1511
1545
|
queueDepth: this.reduceQueue.length + this.inFlightEffects
|
|
1512
1546
|
};
|
|
@@ -1533,34 +1567,34 @@ class x {
|
|
|
1533
1567
|
);
|
|
1534
1568
|
const t = this.state, s = e, n = { ...this.state };
|
|
1535
1569
|
let r = !1;
|
|
1536
|
-
Object.keys(this.reducers).forEach((
|
|
1537
|
-
const l = t?.[
|
|
1570
|
+
Object.keys(this.reducers).forEach((c) => {
|
|
1571
|
+
const l = t?.[c], i = s?.[c];
|
|
1538
1572
|
if (i === void 0) {
|
|
1539
1573
|
process.env.NODE_ENV !== "production" && console.warn(
|
|
1540
1574
|
`[yoltra] External state is missing slice "${String(
|
|
1541
|
-
|
|
1575
|
+
c
|
|
1542
1576
|
)}"; retaining its current value. Time-travel snapshots should contain all slices.`
|
|
1543
1577
|
);
|
|
1544
1578
|
return;
|
|
1545
1579
|
}
|
|
1546
1580
|
if (l === i) return;
|
|
1547
1581
|
const a = R(i);
|
|
1548
|
-
n[
|
|
1549
|
-
const
|
|
1550
|
-
if (
|
|
1551
|
-
const
|
|
1552
|
-
for (const
|
|
1553
|
-
if (
|
|
1554
|
-
|
|
1582
|
+
n[c] = a, r = !0;
|
|
1583
|
+
const u = I(l, i);
|
|
1584
|
+
if (u.length === 0) return;
|
|
1585
|
+
const d = /* @__PURE__ */ new Set();
|
|
1586
|
+
for (const h of u) {
|
|
1587
|
+
if (h === "") {
|
|
1588
|
+
d.add("");
|
|
1555
1589
|
continue;
|
|
1556
1590
|
}
|
|
1557
|
-
for (const
|
|
1591
|
+
for (const p of x.buildAncestorPaths(h)) d.add(p);
|
|
1558
1592
|
}
|
|
1559
|
-
for (const
|
|
1560
|
-
const
|
|
1561
|
-
this.connectorBus.emit(
|
|
1593
|
+
for (const h of d) {
|
|
1594
|
+
const p = this.getAtPath(l, h), f = this.getAtPath(a, h);
|
|
1595
|
+
this.connectorBus.emit(c, h, { oldValue: p, newValue: f, path: h });
|
|
1562
1596
|
}
|
|
1563
|
-
}), r && (this.state = n), r && this.listeners.forEach((
|
|
1597
|
+
}), r && (this.state = n), r && this.listeners.forEach((c) => c());
|
|
1564
1598
|
}
|
|
1565
1599
|
/**
|
|
1566
1600
|
* Replays a sequence of events from a snapshot through reducers and event
|
|
@@ -1583,20 +1617,20 @@ class x {
|
|
|
1583
1617
|
for (const s of t) {
|
|
1584
1618
|
const n = s, r = [];
|
|
1585
1619
|
this.stagingSink = r;
|
|
1586
|
-
let
|
|
1620
|
+
let c = null;
|
|
1587
1621
|
try {
|
|
1588
|
-
this.reducerBus.emit(n.channel, n.type, n.payload, n),
|
|
1622
|
+
this.reducerBus.emit(n.channel, n.type, n.payload, n), c = this.stagedRejection;
|
|
1589
1623
|
for (const [i, a] of this.patternReducers) {
|
|
1590
|
-
if (
|
|
1591
|
-
if (
|
|
1592
|
-
const
|
|
1593
|
-
|
|
1624
|
+
if (c !== null) break;
|
|
1625
|
+
if (k(a, n)) {
|
|
1626
|
+
const u = this.stageSliceGuarded(i, n, r);
|
|
1627
|
+
u !== null && (c = u);
|
|
1594
1628
|
}
|
|
1595
1629
|
}
|
|
1596
1630
|
} finally {
|
|
1597
1631
|
this.stagingSink = null, this.stagedRejection = null, this.stagedRejectedBy = "";
|
|
1598
1632
|
}
|
|
1599
|
-
const l =
|
|
1633
|
+
const l = c === null && this.commitStaged(r, n);
|
|
1600
1634
|
this.notifyEventSubscribers(n, "committed"), l && (this.notifyEventSubscribers(n, "written"), this.listeners.forEach((i) => i()));
|
|
1601
1635
|
}
|
|
1602
1636
|
}
|
|
@@ -1659,14 +1693,14 @@ class x {
|
|
|
1659
1693
|
* @internal
|
|
1660
1694
|
*/
|
|
1661
1695
|
async emitCaused(e, t, s, n, r) {
|
|
1662
|
-
const
|
|
1663
|
-
if (r?.skipDedup !== !0 && (l > 0 ||
|
|
1664
|
-
const
|
|
1665
|
-
if (this.shouldDedupe(
|
|
1666
|
-
return
|
|
1696
|
+
const c = r?.dedupKey, l = this.dedupConfig.windowMs;
|
|
1697
|
+
if (r?.skipDedup !== !0 && (l > 0 || c !== void 0)) {
|
|
1698
|
+
const p = c !== void 0 && l <= 0 ? A : l, f = c !== void 0 ? `${t}::${s}::#${c}` : this.fingerprint(t, s, n);
|
|
1699
|
+
if (this.shouldDedupe(f, p))
|
|
1700
|
+
return S;
|
|
1667
1701
|
}
|
|
1668
|
-
const i = r?.id ?? this.idFactory(), a = this.currentEvent ?? e,
|
|
1669
|
-
if (a !== null &&
|
|
1702
|
+
const i = r?.id ?? this.idFactory(), a = this.currentEvent ?? e, u = a === null ? 0 : a.depth + 1;
|
|
1703
|
+
if (a !== null && u > this.maxReduceDepth)
|
|
1670
1704
|
return this.reportCascade(
|
|
1671
1705
|
"maxReduceDepth",
|
|
1672
1706
|
this.maxReduceDepth,
|
|
@@ -1677,14 +1711,14 @@ class x {
|
|
|
1677
1711
|
id: i,
|
|
1678
1712
|
...r?.meta !== void 0 ? { meta: r.meta } : {},
|
|
1679
1713
|
parentId: a.id,
|
|
1680
|
-
depth:
|
|
1714
|
+
depth: u
|
|
1681
1715
|
},
|
|
1682
|
-
|
|
1716
|
+
u,
|
|
1683
1717
|
a.chain
|
|
1684
|
-
),
|
|
1685
|
-
let
|
|
1686
|
-
const
|
|
1687
|
-
|
|
1718
|
+
), S;
|
|
1719
|
+
let d;
|
|
1720
|
+
const h = new Promise((p) => {
|
|
1721
|
+
d = p;
|
|
1688
1722
|
});
|
|
1689
1723
|
return this.reduceQueue.push({
|
|
1690
1724
|
channel: t,
|
|
@@ -1692,11 +1726,11 @@ class x {
|
|
|
1692
1726
|
payload: n,
|
|
1693
1727
|
id: i,
|
|
1694
1728
|
meta: r?.meta,
|
|
1695
|
-
resolve:
|
|
1729
|
+
resolve: d,
|
|
1696
1730
|
// Only carried for caused events, so a root event's object stays byte-identical to one
|
|
1697
1731
|
// built before causality existed — the same rule `meta` follows.
|
|
1698
|
-
...a !== null ? { parentId: a.id, depth:
|
|
1699
|
-
}), this.drainReduce(),
|
|
1732
|
+
...a !== null ? { parentId: a.id, depth: u, chain: a.chain } : {}
|
|
1733
|
+
}), this.drainReduce(), h;
|
|
1700
1734
|
}
|
|
1701
1735
|
/**
|
|
1702
1736
|
* Drains the reduce queue **synchronously**. For each event it runs middleware,
|
|
@@ -1713,47 +1747,47 @@ class x {
|
|
|
1713
1747
|
this.isReducing = !0, this.transitionsThisDrain = 0;
|
|
1714
1748
|
try {
|
|
1715
1749
|
for (; this.reduceQueue.length > 0; ) {
|
|
1716
|
-
const e = this.reduceQueue.shift(), { channel: t, type: s, payload: n, id: r, meta:
|
|
1750
|
+
const e = this.reduceQueue.shift(), { channel: t, type: s, payload: n, id: r, meta: c, resolve: l, parentId: i, depth: a, chain: u } = e, d = {
|
|
1717
1751
|
channel: t,
|
|
1718
1752
|
type: s,
|
|
1719
1753
|
payload: n,
|
|
1720
1754
|
id: r,
|
|
1721
|
-
...
|
|
1755
|
+
...c !== void 0 ? { meta: c } : {},
|
|
1722
1756
|
...i !== void 0 ? { parentId: i, depth: a } : {}
|
|
1723
1757
|
};
|
|
1724
1758
|
if (i !== void 0 && ++this.transitionsThisDrain > this.maxTransitionsPerDrain) {
|
|
1725
1759
|
this.reportCascade(
|
|
1726
1760
|
"maxTransitionsPerDrain",
|
|
1727
1761
|
this.maxTransitionsPerDrain,
|
|
1728
|
-
|
|
1762
|
+
d,
|
|
1729
1763
|
a,
|
|
1730
|
-
|
|
1731
|
-
), l(
|
|
1764
|
+
u
|
|
1765
|
+
), l(S);
|
|
1732
1766
|
continue;
|
|
1733
1767
|
}
|
|
1734
1768
|
this.currentEvent = {
|
|
1735
1769
|
id: r,
|
|
1736
1770
|
depth: a ?? 0,
|
|
1737
|
-
chain: [...
|
|
1771
|
+
chain: [...u ?? [], r].slice(-z)
|
|
1738
1772
|
};
|
|
1739
|
-
const
|
|
1740
|
-
|
|
1741
|
-
const
|
|
1742
|
-
let
|
|
1773
|
+
const h = this.instrumentObservers.size > 0, p = h ? this.state : void 0, f = h ? [] : void 0;
|
|
1774
|
+
f !== void 0 && (this.changedPathSink = f);
|
|
1775
|
+
const m = h ? _() : 0;
|
|
1776
|
+
let y = S;
|
|
1743
1777
|
try {
|
|
1744
|
-
|
|
1745
|
-
} catch (
|
|
1746
|
-
console.error("Emit reduce error:",
|
|
1778
|
+
y = this.applyEventSync(d);
|
|
1779
|
+
} catch (g) {
|
|
1780
|
+
console.error("Emit reduce error:", g);
|
|
1747
1781
|
} finally {
|
|
1748
|
-
|
|
1782
|
+
h && (this.changedPathSink = null), this.currentEvent = null;
|
|
1749
1783
|
}
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
), this.runEventEffects(
|
|
1784
|
+
h && this.emitInstrumentation(
|
|
1785
|
+
d,
|
|
1786
|
+
y,
|
|
1787
|
+
f ?? [],
|
|
1788
|
+
p,
|
|
1789
|
+
_() - m
|
|
1790
|
+
), this.runEventEffects(d, y, l);
|
|
1757
1791
|
}
|
|
1758
1792
|
} finally {
|
|
1759
1793
|
this.isReducing = !1;
|
|
@@ -1771,20 +1805,20 @@ class x {
|
|
|
1771
1805
|
* @internal
|
|
1772
1806
|
*/
|
|
1773
1807
|
applyEventSync(e) {
|
|
1774
|
-
for (const
|
|
1775
|
-
const l =
|
|
1776
|
-
if (!
|
|
1777
|
-
const i =
|
|
1808
|
+
for (const c of this.middleware) {
|
|
1809
|
+
const l = se(c);
|
|
1810
|
+
if (!k(l, e)) continue;
|
|
1811
|
+
const i = ne(c);
|
|
1778
1812
|
let a;
|
|
1779
1813
|
try {
|
|
1780
1814
|
a = i(this.state, e, this.emit), process.env.NODE_ENV !== "production" && typeof a?.then == "function" && console.error(
|
|
1781
1815
|
`[yoltra] Middleware for "${e.channel}/${e.type}" returned a Promise. Middleware is synchronous: a Promise is truthy, so this event was allowed without waiting and a "return false" inside it can never veto. Do the check synchronously, and put anything that must await in an effect.`
|
|
1782
1816
|
);
|
|
1783
|
-
} catch (
|
|
1784
|
-
console.error("Middleware error:",
|
|
1817
|
+
} catch (u) {
|
|
1818
|
+
console.error("Middleware error:", u), a = !1;
|
|
1785
1819
|
}
|
|
1786
1820
|
if (!a)
|
|
1787
|
-
return this.notifyEventSubscribers(e, "uncommitted"),
|
|
1821
|
+
return this.notifyEventSubscribers(e, "uncommitted"), S;
|
|
1788
1822
|
}
|
|
1789
1823
|
const t = [];
|
|
1790
1824
|
this.stagingSink = t;
|
|
@@ -1796,11 +1830,11 @@ class x {
|
|
|
1796
1830
|
e.payload,
|
|
1797
1831
|
e
|
|
1798
1832
|
), s = this.stagedRejection, n = this.stagedRejectedBy;
|
|
1799
|
-
for (const [
|
|
1833
|
+
for (const [c, l] of this.patternReducers) {
|
|
1800
1834
|
if (s !== null) break;
|
|
1801
|
-
if (
|
|
1802
|
-
const i = this.stageSliceGuarded(
|
|
1803
|
-
i !== null && (s = i, n =
|
|
1835
|
+
if (k(l, e)) {
|
|
1836
|
+
const i = this.stageSliceGuarded(c, e, t);
|
|
1837
|
+
i !== null && (s = i, n = c);
|
|
1804
1838
|
}
|
|
1805
1839
|
}
|
|
1806
1840
|
} finally {
|
|
@@ -1809,7 +1843,7 @@ class x {
|
|
|
1809
1843
|
if (s !== null)
|
|
1810
1844
|
return this.onRejected?.(s, e, n), this.notifyEventSubscribers(e, "committed"), { committed: !0, written: !1, rejected: s };
|
|
1811
1845
|
const r = this.commitStaged(t, e);
|
|
1812
|
-
return this.notifyEventSubscribers(e, "committed"), r && (this.notifyEventSubscribers(e, "written"), this.listeners.forEach((
|
|
1846
|
+
return this.notifyEventSubscribers(e, "committed"), r && (this.notifyEventSubscribers(e, "written"), this.listeners.forEach((c) => c())), r ? ce : oe;
|
|
1813
1847
|
}
|
|
1814
1848
|
/**
|
|
1815
1849
|
* Runs a single committed event's effects as an **independent async task**,
|
|
@@ -1848,9 +1882,9 @@ class x {
|
|
|
1848
1882
|
* @internal
|
|
1849
1883
|
*/
|
|
1850
1884
|
emitInstrumentation(e, t, s, n, r) {
|
|
1851
|
-
const
|
|
1885
|
+
const c = {}, l = {};
|
|
1852
1886
|
for (const a of s)
|
|
1853
|
-
|
|
1887
|
+
c[a] = this.getAtPath(n, a), l[a] = this.getAtPath(this.state, a);
|
|
1854
1888
|
const i = {
|
|
1855
1889
|
event: {
|
|
1856
1890
|
id: e.id,
|
|
@@ -1863,7 +1897,7 @@ class x {
|
|
|
1863
1897
|
},
|
|
1864
1898
|
committed: t.committed,
|
|
1865
1899
|
changedPaths: s,
|
|
1866
|
-
prevValues:
|
|
1900
|
+
prevValues: c,
|
|
1867
1901
|
nextValues: l,
|
|
1868
1902
|
reduceTimeMs: r,
|
|
1869
1903
|
// Present only when a reducer refused, so an observer can tell a refusal from a veto —
|
|
@@ -1873,8 +1907,8 @@ class x {
|
|
|
1873
1907
|
for (const a of [...this.instrumentObservers])
|
|
1874
1908
|
try {
|
|
1875
1909
|
a(i);
|
|
1876
|
-
} catch (
|
|
1877
|
-
console.error("Instrumentation observer error:",
|
|
1910
|
+
} catch (u) {
|
|
1911
|
+
console.error("Instrumentation observer error:", u);
|
|
1878
1912
|
}
|
|
1879
1913
|
}
|
|
1880
1914
|
/**
|
|
@@ -1908,8 +1942,8 @@ class x {
|
|
|
1908
1942
|
connect(e, t, s) {
|
|
1909
1943
|
const n = this.connectorBus.on(e.reducer, e.property, t);
|
|
1910
1944
|
if (s?.immediate === !0) {
|
|
1911
|
-
const r = this.state[e.reducer],
|
|
1912
|
-
t({ oldValue: void 0, newValue: this.getAtPath(r,
|
|
1945
|
+
const r = this.state[e.reducer], c = e.property.includes("*") ? "" : e.property;
|
|
1946
|
+
t({ oldValue: void 0, newValue: this.getAtPath(r, c), path: c });
|
|
1913
1947
|
}
|
|
1914
1948
|
return n;
|
|
1915
1949
|
}
|
|
@@ -1960,10 +1994,10 @@ class x {
|
|
|
1960
1994
|
* @public
|
|
1961
1995
|
*/
|
|
1962
1996
|
onEvent(e, t, s, n = "committed") {
|
|
1963
|
-
const r = `${e}::${String(t)}`,
|
|
1964
|
-
return
|
|
1965
|
-
const l =
|
|
1966
|
-
l && (l.delete(s), l.size === 0 &&
|
|
1997
|
+
const r = `${e}::${String(t)}`, c = n === "committed" ? this.committedEventSubscribers : n === "uncommitted" ? this.uncommittedEventSubscribers : n === "written" ? this.writtenEventSubscribers : this.allEventSubscribers;
|
|
1998
|
+
return c.has(r) || c.set(r, /* @__PURE__ */ new Set()), c.get(r).add(s), () => {
|
|
1999
|
+
const l = c.get(r);
|
|
2000
|
+
l && (l.delete(s), l.size === 0 && c.delete(r));
|
|
1967
2001
|
};
|
|
1968
2002
|
}
|
|
1969
2003
|
/**
|
|
@@ -2168,13 +2202,7 @@ class x {
|
|
|
2168
2202
|
* the terminal event from ever being sent. Un-iterated progress therefore buffers to
|
|
2169
2203
|
* `highWaterMark` and is then counted on {@link CallHandle.dropped} rather than blocking.
|
|
2170
2204
|
*
|
|
2171
|
-
* **This is a local primitive.**
|
|
2172
|
-
* envelope carries neither `meta` nor `parentId`, and ingress namespaces the channel, so
|
|
2173
|
-
* neither correlation nor the reply route survives the hop. That is not an oversight to route
|
|
2174
|
-
* around — federation answers cross-node request/reply with typed peer *queries*, which are
|
|
2175
|
-
* gated by a responder policy that may concede or deny. A call that federated silently would
|
|
2176
|
-
* turn that access decision into an accident of which channel someone named. Ask a peer with a
|
|
2177
|
-
* query; use `call` within a process.
|
|
2205
|
+
* **This is a local primitive.**
|
|
2178
2206
|
*
|
|
2179
2207
|
* @example Timeout is idle, not total
|
|
2180
2208
|
* ```ts
|
|
@@ -2191,58 +2219,13 @@ class x {
|
|
|
2191
2219
|
* @public
|
|
2192
2220
|
*/
|
|
2193
2221
|
call(e, t, s, n) {
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
let h = null, y = null;
|
|
2202
|
-
const g = (b, S = !1) => {
|
|
2203
|
-
f || (f = !0, h !== null && clearTimeout(h), h = null, y?.(), y = null, S ? i.end() : i.close(), n.signal?.removeEventListener("abort", w), b());
|
|
2204
|
-
};
|
|
2205
|
-
function w() {
|
|
2206
|
-
g(() => u(new C(String(n.signal?.reason ?? "signal aborted"))));
|
|
2207
|
-
}
|
|
2208
|
-
const k = () => {
|
|
2209
|
-
h !== null && clearTimeout(h), h = setTimeout(() => {
|
|
2210
|
-
g(() => u(new J(e, t, l)));
|
|
2211
|
-
}, l), h.unref?.();
|
|
2212
|
-
};
|
|
2213
|
-
return y = this.registerEffect({
|
|
2214
|
-
// A pattern effect on the reply channel: which types are terminal is known, which are
|
|
2215
|
-
// progress is not, so the filter cannot be a key list.
|
|
2216
|
-
when: { channel: r },
|
|
2217
|
-
effect: async (b) => {
|
|
2218
|
-
if (!f && Y(b, a, n.correlationId)) {
|
|
2219
|
-
if (k(), o(String(b.type))) {
|
|
2220
|
-
g(() => d(b), !0);
|
|
2221
|
-
return;
|
|
2222
|
-
}
|
|
2223
|
-
await i.put(b);
|
|
2224
|
-
}
|
|
2225
|
-
}
|
|
2226
|
-
}), n.signal !== void 0 && (n.signal.aborted ? w() : n.signal.addEventListener("abort", w, { once: !0 })), k(), this.emit(e, t, s, {
|
|
2227
|
-
id: a,
|
|
2228
|
-
...n.correlationId !== void 0 ? { meta: { correlationId: n.correlationId } } : {}
|
|
2229
|
-
}), {
|
|
2230
|
-
then: (b, S) => m.then(b, S),
|
|
2231
|
-
catch: (b) => m.catch(b),
|
|
2232
|
-
finally: (b) => m.finally(b),
|
|
2233
|
-
get dropped() {
|
|
2234
|
-
return i.droppedCount;
|
|
2235
|
-
},
|
|
2236
|
-
cancel: (b = "cancelled") => {
|
|
2237
|
-
g(() => u(new C(b)));
|
|
2238
|
-
},
|
|
2239
|
-
[Symbol.asyncIterator]: () => (i.beginConsuming(), {
|
|
2240
|
-
next: () => i.take(),
|
|
2241
|
-
// Called by `for await` on `break`, `return` or a throw. Without it, abandoning the
|
|
2242
|
-
// loop would leave the effect registered and the producer parked for good.
|
|
2243
|
-
return: async () => (i.close(), { value: void 0, done: !0 })
|
|
2244
|
-
})
|
|
2245
|
-
};
|
|
2222
|
+
return Z(
|
|
2223
|
+
{ idFactory: this.idFactory, registerEffect: this.registerEffect, emit: this.emit },
|
|
2224
|
+
e,
|
|
2225
|
+
t,
|
|
2226
|
+
s,
|
|
2227
|
+
n
|
|
2228
|
+
);
|
|
2246
2229
|
}
|
|
2247
2230
|
registerEffect(e) {
|
|
2248
2231
|
const { effect: t, meta: s, when: n } = e, r = [];
|
|
@@ -2252,7 +2235,7 @@ class x {
|
|
|
2252
2235
|
this.patternEffects.delete(i);
|
|
2253
2236
|
};
|
|
2254
2237
|
}
|
|
2255
|
-
const l =
|
|
2238
|
+
const l = D(e);
|
|
2256
2239
|
if (l.length === 0 && !n) {
|
|
2257
2240
|
const i = { effect: t, when: { any: !0 } };
|
|
2258
2241
|
return this.patternEffects.add(i), () => {
|
|
@@ -2260,10 +2243,10 @@ class x {
|
|
|
2260
2243
|
};
|
|
2261
2244
|
}
|
|
2262
2245
|
for (const [i, a] of l) {
|
|
2263
|
-
const
|
|
2264
|
-
this.effects.has(
|
|
2265
|
-
const
|
|
2266
|
-
|
|
2246
|
+
const u = `${String(i)}::${String(a)}`;
|
|
2247
|
+
this.effects.has(u) || this.effects.set(u, /* @__PURE__ */ new Set()), this.effects.get(u).add(t), r.push(() => {
|
|
2248
|
+
const d = this.effects.get(u);
|
|
2249
|
+
d && (d.delete(t), d.size === 0 && this.effects.delete(u));
|
|
2267
2250
|
});
|
|
2268
2251
|
}
|
|
2269
2252
|
return () => {
|
|
@@ -2292,10 +2275,10 @@ class x {
|
|
|
2292
2275
|
* @public
|
|
2293
2276
|
*/
|
|
2294
2277
|
onEffect(e, t, s) {
|
|
2295
|
-
const n = async (r,
|
|
2278
|
+
const n = async (r, c, l) => {
|
|
2296
2279
|
if (r.channel !== e || r.type !== t) return;
|
|
2297
2280
|
const i = r;
|
|
2298
|
-
return s(i.payload,
|
|
2281
|
+
return s(i.payload, c, l, i);
|
|
2299
2282
|
};
|
|
2300
2283
|
return this.registerEffect({
|
|
2301
2284
|
when: { keys: [[e, t]] },
|
|
@@ -2361,9 +2344,9 @@ class x {
|
|
|
2361
2344
|
* @public
|
|
2362
2345
|
*/
|
|
2363
2346
|
replaceReducers(e, t = {}) {
|
|
2364
|
-
const s = t.preserveState !== !1, n = new Set(Object.keys(this.reducers)), r = Object.entries(e),
|
|
2347
|
+
const s = t.preserveState !== !1, n = new Set(Object.keys(this.reducers)), r = Object.entries(e), c = new Set(r.map(([l]) => l));
|
|
2365
2348
|
for (const l of n)
|
|
2366
|
-
|
|
2349
|
+
c.has(l) || this.unmountSlice(l, { deleteState: !0 });
|
|
2367
2350
|
for (const [l, i] of r)
|
|
2368
2351
|
n.has(l) ? (this.unmountSlice(l, { deleteState: !1 }), this.mountSlice(l, i, { preserveState: s })) : this.mountSlice(l, i, { preserveState: !1 });
|
|
2369
2352
|
}
|
|
@@ -2398,35 +2381,35 @@ class x {
|
|
|
2398
2381
|
* @internal
|
|
2399
2382
|
*/
|
|
2400
2383
|
mountSlice(e, t, s) {
|
|
2401
|
-
const n = e, { reducer: r, state:
|
|
2402
|
-
if (this.reducers[e] = new
|
|
2384
|
+
const n = e, { reducer: r, state: c, when: l } = t;
|
|
2385
|
+
if (this.reducers[e] = new L(r), (!s.preserveState || this.state[n] === void 0) && (this.state = {
|
|
2403
2386
|
...this.state,
|
|
2404
|
-
[n]: R(
|
|
2387
|
+
[n]: R(re(n, c))
|
|
2405
2388
|
}), l && ("any" in l && l.any === !0 || "channel" in l || "channels" in l)) {
|
|
2406
2389
|
this.patternReducers.set(e, l), this.sliceUnsubs.set(n, []);
|
|
2407
2390
|
return;
|
|
2408
2391
|
}
|
|
2409
|
-
const a =
|
|
2392
|
+
const a = D(t);
|
|
2410
2393
|
if (a.length === 0 && !l) {
|
|
2411
2394
|
this.patternReducers.set(e, { any: !0 }), this.sliceUnsubs.set(n, []);
|
|
2412
2395
|
return;
|
|
2413
2396
|
}
|
|
2414
|
-
const
|
|
2415
|
-
for (const [
|
|
2416
|
-
const
|
|
2417
|
-
const
|
|
2418
|
-
channel:
|
|
2419
|
-
type:
|
|
2420
|
-
payload:
|
|
2397
|
+
const u = [];
|
|
2398
|
+
for (const [d, h] of a) {
|
|
2399
|
+
const p = this.reducerBus.on(d, h, (f, m) => {
|
|
2400
|
+
const y = m ?? {
|
|
2401
|
+
channel: d,
|
|
2402
|
+
type: h,
|
|
2403
|
+
payload: f,
|
|
2421
2404
|
id: this.idFactory()
|
|
2422
2405
|
};
|
|
2423
2406
|
if (this.stagingSink === null) return;
|
|
2424
|
-
const
|
|
2425
|
-
|
|
2407
|
+
const g = this.stageSliceGuarded(e, y, this.stagingSink);
|
|
2408
|
+
g !== null && this.stagedRejection === null && (this.stagedRejection = g, this.stagedRejectedBy = e);
|
|
2426
2409
|
});
|
|
2427
|
-
|
|
2410
|
+
u.push(p);
|
|
2428
2411
|
}
|
|
2429
|
-
this.sliceUnsubs.set(n,
|
|
2412
|
+
this.sliceUnsubs.set(n, u);
|
|
2430
2413
|
}
|
|
2431
2414
|
/**
|
|
2432
2415
|
* Unmounts a slice: disposes reducer-bus listeners, removes reducer,
|
|
@@ -2445,32 +2428,16 @@ class x {
|
|
|
2445
2428
|
for (const r of n)
|
|
2446
2429
|
try {
|
|
2447
2430
|
r();
|
|
2448
|
-
} catch (
|
|
2449
|
-
console.error(`[Store error]: ${
|
|
2431
|
+
} catch (c) {
|
|
2432
|
+
console.error(`[Store error]: ${c}`);
|
|
2450
2433
|
}
|
|
2451
2434
|
this.sliceUnsubs.delete(s);
|
|
2452
2435
|
}
|
|
2453
2436
|
if (delete this.reducers[e], t.deleteState) {
|
|
2454
|
-
const { [s]: r, ...
|
|
2455
|
-
this.state =
|
|
2437
|
+
const { [s]: r, ...c } = this.state;
|
|
2438
|
+
this.state = c;
|
|
2456
2439
|
}
|
|
2457
2440
|
}
|
|
2458
|
-
/**
|
|
2459
|
-
* Normalizes event targeting from `when` to an array of EventKeys.
|
|
2460
|
-
*
|
|
2461
|
-
* @param spec - Object with an optional `when` matcher.
|
|
2462
|
-
* @returns Array of `[channel, type]` pairs.
|
|
2463
|
-
*
|
|
2464
|
-
* @internal
|
|
2465
|
-
*/
|
|
2466
|
-
normalizeEventKeys(e) {
|
|
2467
|
-
if (e.when) {
|
|
2468
|
-
const t = e.when;
|
|
2469
|
-
if ("keys" in t)
|
|
2470
|
-
return t.keys;
|
|
2471
|
-
}
|
|
2472
|
-
return [];
|
|
2473
|
-
}
|
|
2474
2441
|
/**
|
|
2475
2442
|
* Reads a dotted path from an object (supports numeric array indices via string keys).
|
|
2476
2443
|
*
|
|
@@ -2478,17 +2445,14 @@ class x {
|
|
|
2478
2445
|
* @param path - Dotted path; leading dot is ignored.
|
|
2479
2446
|
* @returns The value at the path, or `undefined`.
|
|
2480
2447
|
*
|
|
2448
|
+
* @remarks
|
|
2449
|
+
* A member rather than a bare import: a test replaces this on the instance to count how many
|
|
2450
|
+
* walks describing a change costs, which only works while the callers go through `this`.
|
|
2451
|
+
*
|
|
2481
2452
|
* @internal
|
|
2482
2453
|
*/
|
|
2483
2454
|
getAtPath(e, t) {
|
|
2484
|
-
|
|
2485
|
-
const n = (t[0] === "." ? t.slice(1) : t).split(".");
|
|
2486
|
-
let r = e;
|
|
2487
|
-
for (const o of n) {
|
|
2488
|
-
if (r == null) return;
|
|
2489
|
-
r = r[o];
|
|
2490
|
-
}
|
|
2491
|
-
return r;
|
|
2455
|
+
return ee(e, t);
|
|
2492
2456
|
}
|
|
2493
2457
|
/**
|
|
2494
2458
|
* Builds ancestor paths for a dotted path.
|
|
@@ -2506,72 +2470,68 @@ class x {
|
|
|
2506
2470
|
* @public
|
|
2507
2471
|
*/
|
|
2508
2472
|
static buildAncestorPaths(e) {
|
|
2509
|
-
|
|
2510
|
-
const s = (e[0] === "." ? e.slice(1) : e).split("."), n = [];
|
|
2511
|
-
for (let r = 0; r < s.length; r++)
|
|
2512
|
-
n.push(s.slice(0, r + 1).join("."));
|
|
2513
|
-
return n;
|
|
2473
|
+
return te(e);
|
|
2514
2474
|
}
|
|
2515
2475
|
}
|
|
2516
|
-
function
|
|
2476
|
+
function he(o) {
|
|
2517
2477
|
return new x({
|
|
2518
|
-
...
|
|
2519
|
-
reducer:
|
|
2520
|
-
middleware:
|
|
2521
|
-
effects:
|
|
2478
|
+
...o,
|
|
2479
|
+
reducer: o.reducer ?? {},
|
|
2480
|
+
middleware: o.middleware ?? [],
|
|
2481
|
+
effects: o.effects ?? []
|
|
2522
2482
|
});
|
|
2523
2483
|
}
|
|
2524
|
-
const
|
|
2525
|
-
function
|
|
2526
|
-
const e = String(
|
|
2527
|
-
|
|
2484
|
+
const pe = (o) => (e, t) => t.map((s) => [e, s]), me = () => (o) => o, j = /* @__PURE__ */ new Set();
|
|
2485
|
+
function ae(o) {
|
|
2486
|
+
const e = String(o);
|
|
2487
|
+
j.has(e) || (j.add(e), console.warn(
|
|
2528
2488
|
`[yoltra] Entity id "${e}" contains a dot. Paths are dotted, so a subscription to "entities.${e}" is indistinguishable from one to a nested object of the same name. Use ids without dots.`
|
|
2529
2489
|
));
|
|
2530
2490
|
}
|
|
2531
|
-
function
|
|
2532
|
-
if (
|
|
2533
|
-
for (let t = 0; t <
|
|
2534
|
-
if (
|
|
2535
|
-
return
|
|
2491
|
+
function le(o, e) {
|
|
2492
|
+
if (o.length !== e.length) return e;
|
|
2493
|
+
for (let t = 0; t < o.length; t++)
|
|
2494
|
+
if (o[t] !== e[t]) return e;
|
|
2495
|
+
return o;
|
|
2536
2496
|
}
|
|
2537
|
-
function
|
|
2538
|
-
const e =
|
|
2497
|
+
function ye(o = {}) {
|
|
2498
|
+
const e = o.selectId ?? ((i) => i.id), { sortComparer: t } = o, s = (i, a) => {
|
|
2539
2499
|
if (t === void 0) return a;
|
|
2540
|
-
const
|
|
2541
|
-
const
|
|
2542
|
-
return
|
|
2500
|
+
const u = [...a].sort((d, h) => {
|
|
2501
|
+
const p = i.entities[d], f = i.entities[h];
|
|
2502
|
+
return p === void 0 || f === void 0 ? 0 : t(p, f);
|
|
2543
2503
|
});
|
|
2544
|
-
return
|
|
2545
|
-
}, n = (i, a,
|
|
2546
|
-
const
|
|
2547
|
-
return { ...
|
|
2548
|
-
}, r = (i, a,
|
|
2549
|
-
let
|
|
2550
|
-
for (const
|
|
2551
|
-
const
|
|
2552
|
-
process.env.NODE_ENV !== "production" && String(
|
|
2553
|
-
const
|
|
2554
|
-
if (
|
|
2555
|
-
const
|
|
2556
|
-
|
|
2504
|
+
return le(a, u);
|
|
2505
|
+
}, n = (i, a, u) => {
|
|
2506
|
+
const d = { ...i, entities: a, ids: u };
|
|
2507
|
+
return { ...d, ids: s(d, u) };
|
|
2508
|
+
}, r = (i, a, u) => {
|
|
2509
|
+
let d = null, h = null;
|
|
2510
|
+
for (const p of a) {
|
|
2511
|
+
const f = e(p);
|
|
2512
|
+
process.env.NODE_ENV !== "production" && String(f).includes(".") && ae(f);
|
|
2513
|
+
const m = (d ?? i.entities)[f];
|
|
2514
|
+
if (m !== void 0 && u === "add") continue;
|
|
2515
|
+
const y = m !== void 0 && u === "upsert" ? { ...m, ...p } : p;
|
|
2516
|
+
d ??= { ...i.entities }, d[f] = y, m === void 0 && (h ??= [...i.ids], h.push(f));
|
|
2557
2517
|
}
|
|
2558
|
-
return
|
|
2559
|
-
},
|
|
2560
|
-
let
|
|
2561
|
-
for (const { id:
|
|
2562
|
-
const
|
|
2563
|
-
|
|
2518
|
+
return d === null ? i : n(i, d, h ?? i.ids);
|
|
2519
|
+
}, c = (i, a) => {
|
|
2520
|
+
let u = null;
|
|
2521
|
+
for (const { id: d, changes: h } of a) {
|
|
2522
|
+
const p = (u ?? i.entities)[d];
|
|
2523
|
+
p !== void 0 && (u ??= { ...i.entities }, u[d] = { ...p, ...h });
|
|
2564
2524
|
}
|
|
2565
|
-
return
|
|
2525
|
+
return u === null ? i : n(i, u, i.ids);
|
|
2566
2526
|
}, l = (i, a) => {
|
|
2567
|
-
const
|
|
2568
|
-
if (
|
|
2569
|
-
const
|
|
2570
|
-
for (const
|
|
2527
|
+
const u = new Set(a.filter((h) => i.entities[h] !== void 0));
|
|
2528
|
+
if (u.size === 0) return i;
|
|
2529
|
+
const d = { ...i.entities };
|
|
2530
|
+
for (const h of u) delete d[h];
|
|
2571
2531
|
return n(
|
|
2572
2532
|
i,
|
|
2573
|
-
|
|
2574
|
-
i.ids.filter((
|
|
2533
|
+
d,
|
|
2534
|
+
i.ids.filter((h) => !u.has(h))
|
|
2575
2535
|
);
|
|
2576
2536
|
};
|
|
2577
2537
|
return {
|
|
@@ -2584,15 +2544,15 @@ function he(c = {}) {
|
|
|
2584
2544
|
setOne: (i, a) => r(i, [a], "set"),
|
|
2585
2545
|
setMany: (i, a) => r(i, a, "set"),
|
|
2586
2546
|
setAll: (i, a) => {
|
|
2587
|
-
const
|
|
2588
|
-
for (const
|
|
2589
|
-
const
|
|
2590
|
-
|
|
2547
|
+
const u = {}, d = [];
|
|
2548
|
+
for (const h of a) {
|
|
2549
|
+
const p = e(h);
|
|
2550
|
+
u[p] === void 0 && d.push(p), u[p] = h;
|
|
2591
2551
|
}
|
|
2592
|
-
return n(i,
|
|
2552
|
+
return n(i, u, d);
|
|
2593
2553
|
},
|
|
2594
|
-
updateOne: (i, a) =>
|
|
2595
|
-
updateMany: (i, a) =>
|
|
2554
|
+
updateOne: (i, a) => c(i, [a]),
|
|
2555
|
+
updateMany: (i, a) => c(i, a),
|
|
2596
2556
|
upsertOne: (i, a) => r(i, [a], "upsert"),
|
|
2597
2557
|
upsertMany: (i, a) => r(i, a, "upsert"),
|
|
2598
2558
|
removeOne: (i, a) => l(i, [a]),
|
|
@@ -2608,76 +2568,76 @@ function he(c = {}) {
|
|
|
2608
2568
|
anyField: (i) => `entities.*.${i}`
|
|
2609
2569
|
};
|
|
2610
2570
|
}
|
|
2611
|
-
const
|
|
2612
|
-
function
|
|
2571
|
+
const w = "$yoltra";
|
|
2572
|
+
function H(o, e = {}) {
|
|
2613
2573
|
const t = e.maxNodes ?? 1e5, s = e.sanitize, n = [], r = /* @__PURE__ */ new Map();
|
|
2614
|
-
let
|
|
2615
|
-
function i(
|
|
2616
|
-
if (s !== void 0 && (
|
|
2617
|
-
return l = !0, { [
|
|
2618
|
-
switch (typeof
|
|
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) {
|
|
2619
2579
|
case "undefined":
|
|
2620
|
-
return { [
|
|
2580
|
+
return { [w]: "undefined" };
|
|
2621
2581
|
case "bigint":
|
|
2622
|
-
return { [
|
|
2582
|
+
return { [w]: "bigint", value: u.toString() };
|
|
2623
2583
|
case "number":
|
|
2624
|
-
return Number.isNaN(
|
|
2584
|
+
return Number.isNaN(u) ? { [w]: "nan" } : u === 1 / 0 ? { [w]: "infinity", sign: 1 } : u === -1 / 0 ? { [w]: "infinity", sign: -1 } : u;
|
|
2625
2585
|
case "function":
|
|
2626
2586
|
case "symbol":
|
|
2627
|
-
return n.push(
|
|
2587
|
+
return n.push(d), { [w]: "unsupported", kind: typeof u };
|
|
2628
2588
|
case "string":
|
|
2629
2589
|
case "boolean":
|
|
2630
|
-
return
|
|
2590
|
+
return u;
|
|
2631
2591
|
}
|
|
2632
|
-
if (
|
|
2633
|
-
const
|
|
2634
|
-
if (
|
|
2635
|
-
if (r.set(
|
|
2636
|
-
return { [
|
|
2637
|
-
if (
|
|
2638
|
-
return { [
|
|
2639
|
-
if (
|
|
2640
|
-
return { [
|
|
2641
|
-
if (
|
|
2642
|
-
const
|
|
2643
|
-
let
|
|
2644
|
-
for (const [
|
|
2645
|
-
|
|
2646
|
-
return { [
|
|
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 };
|
|
2647
2607
|
}
|
|
2648
|
-
if (
|
|
2649
|
-
const
|
|
2650
|
-
let
|
|
2651
|
-
for (const
|
|
2652
|
-
|
|
2653
|
-
return { [
|
|
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 };
|
|
2654
2614
|
}
|
|
2655
|
-
if (Array.isArray(
|
|
2656
|
-
return
|
|
2657
|
-
const
|
|
2658
|
-
for (const [
|
|
2659
|
-
|
|
2660
|
-
return
|
|
2661
|
-
}
|
|
2662
|
-
return { value: i(
|
|
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 } };
|
|
2663
2623
|
}
|
|
2664
|
-
function
|
|
2624
|
+
function ue(o) {
|
|
2665
2625
|
const e = /* @__PURE__ */ new Map(), t = [];
|
|
2666
|
-
function s(
|
|
2667
|
-
if (
|
|
2668
|
-
if (Array.isArray(
|
|
2626
|
+
function s(c, l) {
|
|
2627
|
+
if (c === null || typeof c != "object") return c;
|
|
2628
|
+
if (Array.isArray(c)) {
|
|
2669
2629
|
const a = [];
|
|
2670
|
-
return e.set(l, a),
|
|
2671
|
-
if (
|
|
2672
|
-
t.push({ target: a, key:
|
|
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;
|
|
2673
2633
|
return;
|
|
2674
2634
|
}
|
|
2675
|
-
a[
|
|
2635
|
+
a[d] = s(u, `${l}/${d}`);
|
|
2676
2636
|
}), a;
|
|
2677
2637
|
}
|
|
2678
|
-
if (typeof
|
|
2679
|
-
const a =
|
|
2680
|
-
switch (a[
|
|
2638
|
+
if (typeof c[w] == "string") {
|
|
2639
|
+
const a = c;
|
|
2640
|
+
switch (a[w]) {
|
|
2681
2641
|
case "undefined":
|
|
2682
2642
|
return;
|
|
2683
2643
|
case "nan":
|
|
@@ -2691,22 +2651,22 @@ function oe(c) {
|
|
|
2691
2651
|
case "regexp":
|
|
2692
2652
|
return new RegExp(a.source, a.flags);
|
|
2693
2653
|
case "error": {
|
|
2694
|
-
const
|
|
2695
|
-
return
|
|
2654
|
+
const u = new Error(a.message);
|
|
2655
|
+
return u.name = a.name, u;
|
|
2696
2656
|
}
|
|
2697
2657
|
case "unsupported":
|
|
2698
2658
|
return;
|
|
2699
2659
|
case "ref":
|
|
2700
2660
|
return;
|
|
2701
2661
|
case "map": {
|
|
2702
|
-
const
|
|
2703
|
-
return e.set(l,
|
|
2704
|
-
|
|
2705
|
-
}),
|
|
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;
|
|
2706
2666
|
}
|
|
2707
2667
|
case "set": {
|
|
2708
|
-
const
|
|
2709
|
-
return e.set(l,
|
|
2668
|
+
const u = /* @__PURE__ */ new Set();
|
|
2669
|
+
return e.set(l, u), a.values.forEach((d, h) => u.add(s(d, `${l}/${h}`))), u;
|
|
2710
2670
|
}
|
|
2711
2671
|
case "escaped":
|
|
2712
2672
|
return n(a.value, l);
|
|
@@ -2714,37 +2674,37 @@ function oe(c) {
|
|
|
2714
2674
|
return;
|
|
2715
2675
|
}
|
|
2716
2676
|
}
|
|
2717
|
-
return n(
|
|
2677
|
+
return n(c, l);
|
|
2718
2678
|
}
|
|
2719
|
-
function n(
|
|
2679
|
+
function n(c, l) {
|
|
2720
2680
|
const i = {};
|
|
2721
2681
|
e.set(l, i);
|
|
2722
|
-
for (const [a,
|
|
2723
|
-
const
|
|
2724
|
-
if (
|
|
2725
|
-
t.push({ target: i, key: a, path:
|
|
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;
|
|
2726
2686
|
continue;
|
|
2727
2687
|
}
|
|
2728
|
-
i[a] = s(
|
|
2688
|
+
i[a] = s(u, d);
|
|
2729
2689
|
}
|
|
2730
2690
|
return i;
|
|
2731
2691
|
}
|
|
2732
|
-
const r = s(
|
|
2692
|
+
const r = s(o, "");
|
|
2733
2693
|
e.set("", r);
|
|
2734
|
-
for (const { target:
|
|
2735
|
-
|
|
2694
|
+
for (const { target: c, key: l, path: i } of t)
|
|
2695
|
+
c[l] = e.get(i);
|
|
2736
2696
|
return r;
|
|
2737
2697
|
}
|
|
2738
|
-
function
|
|
2739
|
-
return
|
|
2698
|
+
function N(o) {
|
|
2699
|
+
return o !== null && typeof o == "object" && o[w] === "ref" && typeof o.path == "string";
|
|
2740
2700
|
}
|
|
2741
|
-
function
|
|
2742
|
-
return
|
|
2701
|
+
function F(o) {
|
|
2702
|
+
return o.replace(/~/g, "~0").replace(/\//g, "~1");
|
|
2743
2703
|
}
|
|
2744
|
-
function
|
|
2704
|
+
function ge(o, e, t = {}) {
|
|
2745
2705
|
let s = t.maxNodes ?? 1e5;
|
|
2746
2706
|
for (let n = 0; n < 8; n += 1) {
|
|
2747
|
-
const { value: r, report:
|
|
2707
|
+
const { value: r, report: c } = H(o, { ...t, maxNodes: s });
|
|
2748
2708
|
let l;
|
|
2749
2709
|
try {
|
|
2750
2710
|
l = JSON.stringify(r)?.length ?? 0;
|
|
@@ -2752,7 +2712,7 @@ function pe(c, e, t = {}) {
|
|
|
2752
2712
|
l = Number.POSITIVE_INFINITY;
|
|
2753
2713
|
}
|
|
2754
2714
|
if (l <= e)
|
|
2755
|
-
return
|
|
2715
|
+
return c.truncated ? {
|
|
2756
2716
|
value: r,
|
|
2757
2717
|
truncated: !0,
|
|
2758
2718
|
note: `State was too large to send in full; parts beyond ${s} nodes are omitted.`
|
|
@@ -2762,108 +2722,108 @@ function pe(c, e, t = {}) {
|
|
|
2762
2722
|
break;
|
|
2763
2723
|
}
|
|
2764
2724
|
return {
|
|
2765
|
-
value: { [
|
|
2725
|
+
value: { [w]: "unsupported", kind: "truncated" },
|
|
2766
2726
|
truncated: !0,
|
|
2767
2727
|
note: `State exceeds the ${e}-byte transport limit and could not be reduced to fit.`
|
|
2768
2728
|
};
|
|
2769
2729
|
}
|
|
2770
|
-
function
|
|
2771
|
-
|
|
2730
|
+
function b(o, e, t) {
|
|
2731
|
+
o.onError?.(e, t);
|
|
2772
2732
|
}
|
|
2773
|
-
async function
|
|
2733
|
+
async function we(o) {
|
|
2774
2734
|
const e = { slices: {}, restored: !1 };
|
|
2775
2735
|
let t;
|
|
2776
2736
|
try {
|
|
2777
|
-
t =
|
|
2737
|
+
t = o.source ?? await o.adapter.read(o.key);
|
|
2778
2738
|
} catch (n) {
|
|
2779
|
-
return
|
|
2739
|
+
return b(o, n, "read"), e;
|
|
2780
2740
|
}
|
|
2781
2741
|
if (t == null || t === "") return e;
|
|
2782
2742
|
let s;
|
|
2783
2743
|
try {
|
|
2784
|
-
s =
|
|
2744
|
+
s = ue(JSON.parse(t));
|
|
2785
2745
|
} catch (n) {
|
|
2786
|
-
return
|
|
2746
|
+
return b(o, n, "decode"), e;
|
|
2787
2747
|
}
|
|
2788
2748
|
if (s === null || typeof s != "object" || typeof s.version != "number")
|
|
2789
|
-
return
|
|
2790
|
-
if (s.version !==
|
|
2791
|
-
if (
|
|
2792
|
-
return
|
|
2793
|
-
|
|
2749
|
+
return b(o, new Error("persisted payload is not a recognisable envelope"), "decode"), e;
|
|
2750
|
+
if (s.version !== o.version) {
|
|
2751
|
+
if (o.migrate === void 0)
|
|
2752
|
+
return b(
|
|
2753
|
+
o,
|
|
2794
2754
|
new Error(
|
|
2795
|
-
`persisted state is version ${s.version}, this build expects ${
|
|
2755
|
+
`persisted state is version ${s.version}, this build expects ${o.version}, and no migrate was supplied`
|
|
2796
2756
|
),
|
|
2797
2757
|
"migrate"
|
|
2798
2758
|
), e;
|
|
2799
2759
|
try {
|
|
2800
|
-
const n =
|
|
2760
|
+
const n = o.migrate(s.slices, s.version);
|
|
2801
2761
|
return n === null ? e : { slices: n, restored: !0 };
|
|
2802
2762
|
} catch (n) {
|
|
2803
|
-
return
|
|
2763
|
+
return b(o, n, "migrate"), e;
|
|
2804
2764
|
}
|
|
2805
2765
|
}
|
|
2806
2766
|
return { slices: s.slices ?? {}, restored: !0 };
|
|
2807
2767
|
}
|
|
2808
|
-
function
|
|
2809
|
-
if (!e.restored) return
|
|
2768
|
+
function Ee(o, e) {
|
|
2769
|
+
if (!e.restored) return o;
|
|
2810
2770
|
const t = {};
|
|
2811
|
-
for (const [s, n] of Object.entries(
|
|
2771
|
+
for (const [s, n] of Object.entries(o)) {
|
|
2812
2772
|
const r = e.slices[s];
|
|
2813
2773
|
t[s] = r === void 0 ? n : { ...n, state: r };
|
|
2814
2774
|
}
|
|
2815
2775
|
return t;
|
|
2816
2776
|
}
|
|
2817
|
-
function
|
|
2818
|
-
const t =
|
|
2819
|
-
return JSON.stringify(
|
|
2777
|
+
function K(o, e) {
|
|
2778
|
+
const t = o ?? {}, s = e.slices === void 0 ? t : Object.fromEntries(e.slices.filter((n) => n in t).map((n) => [n, t[n]]));
|
|
2779
|
+
return JSON.stringify(H({ version: e.version, slices: s }).value);
|
|
2820
2780
|
}
|
|
2821
|
-
function
|
|
2781
|
+
function be(o, e) {
|
|
2822
2782
|
const t = e.throttleMs ?? 250, s = e.slices;
|
|
2823
2783
|
let n = null, r = !1;
|
|
2824
|
-
const
|
|
2784
|
+
const c = () => {
|
|
2825
2785
|
if (r) {
|
|
2826
2786
|
r = !1;
|
|
2827
2787
|
try {
|
|
2828
|
-
const a = e.adapter.write(e.key,
|
|
2829
|
-
a instanceof Promise && a.catch((
|
|
2788
|
+
const a = e.adapter.write(e.key, K(o.getState(), e));
|
|
2789
|
+
a instanceof Promise && a.catch((u) => b(e, u, "write"));
|
|
2830
2790
|
} catch (a) {
|
|
2831
|
-
|
|
2791
|
+
b(e, a, "write");
|
|
2832
2792
|
}
|
|
2833
2793
|
}
|
|
2834
2794
|
}, l = () => {
|
|
2835
2795
|
if (r = !0, t <= 0) {
|
|
2836
|
-
|
|
2796
|
+
c();
|
|
2837
2797
|
return;
|
|
2838
2798
|
}
|
|
2839
2799
|
n === null && (n = setTimeout(() => {
|
|
2840
|
-
n = null,
|
|
2800
|
+
n = null, c();
|
|
2841
2801
|
}, t), n.unref?.());
|
|
2842
|
-
}, i =
|
|
2802
|
+
}, i = o.instrument((a) => {
|
|
2843
2803
|
if (s === void 0) {
|
|
2844
2804
|
l();
|
|
2845
2805
|
return;
|
|
2846
2806
|
}
|
|
2847
2807
|
(a.changedPaths ?? []).some(
|
|
2848
|
-
(
|
|
2808
|
+
(d) => s.some((h) => d === h || d.startsWith(`${h}.`))
|
|
2849
2809
|
) && l();
|
|
2850
2810
|
});
|
|
2851
2811
|
return () => {
|
|
2852
|
-
i(), n !== null && (clearTimeout(n), n = null),
|
|
2812
|
+
i(), n !== null && (clearTimeout(n), n = null), c();
|
|
2853
2813
|
};
|
|
2854
2814
|
}
|
|
2855
|
-
function
|
|
2856
|
-
return
|
|
2815
|
+
function ve(o, e) {
|
|
2816
|
+
return K(o.getState(), e);
|
|
2857
2817
|
}
|
|
2858
|
-
function
|
|
2818
|
+
function Se(o) {
|
|
2859
2819
|
return {
|
|
2860
|
-
read: (e) =>
|
|
2861
|
-
write: (e, t) =>
|
|
2862
|
-
remove: (e) =>
|
|
2820
|
+
read: (e) => o.getItem(e),
|
|
2821
|
+
write: (e, t) => o.setItem(e, t),
|
|
2822
|
+
remove: (e) => o.removeItem(e)
|
|
2863
2823
|
};
|
|
2864
2824
|
}
|
|
2865
|
-
function
|
|
2866
|
-
const e = new Map(Object.entries(
|
|
2825
|
+
function $e(o) {
|
|
2826
|
+
const e = new Map(Object.entries(o ?? {}));
|
|
2867
2827
|
return {
|
|
2868
2828
|
read: (t) => e.get(t) ?? null,
|
|
2869
2829
|
write: (t, s) => {
|
|
@@ -2876,27 +2836,27 @@ function be(c) {
|
|
|
2876
2836
|
}
|
|
2877
2837
|
export {
|
|
2878
2838
|
C as CallAbortedError,
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
2839
|
+
Q as CallTimeoutError,
|
|
2840
|
+
W as EventBus,
|
|
2841
|
+
U as LooseEventBus,
|
|
2842
|
+
L as Reducer,
|
|
2843
|
+
fe as Rejected,
|
|
2884
2844
|
x as Store,
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2845
|
+
ye as createEntityAdapter,
|
|
2846
|
+
$e as createMemoryAdapter,
|
|
2847
|
+
he as createStore,
|
|
2848
|
+
Se as createWebStorageAdapter,
|
|
2849
|
+
ue as decodeState,
|
|
2850
|
+
ve as dehydrate,
|
|
2891
2851
|
I as detectChangedProps,
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
|
|
2852
|
+
H as encodeState,
|
|
2853
|
+
ge as encodeStateBounded,
|
|
2854
|
+
me as eventKeys,
|
|
2895
2855
|
M as freezeState,
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2856
|
+
we as hydrate,
|
|
2857
|
+
V as isRejected,
|
|
2858
|
+
be as persist,
|
|
2859
|
+
pe as typedEvents,
|
|
2860
|
+
Ee as withHydration
|
|
2901
2861
|
};
|
|
2902
2862
|
//# sourceMappingURL=yoltra.mjs.map
|