@yoltra/core 0.7.0 → 0.8.0

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