@solidjs/signals 2.0.0-rc.2 → 2.0.0-rc.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/dist/dev.js +1454 -118
  2. package/dist/node.cjs +2709 -1396
  3. package/dist/prod/affects.js +13 -12
  4. package/dist/prod/boundaries.js +39 -34
  5. package/dist/prod/core/action.js +3 -3
  6. package/dist/prod/core/async.js +48 -46
  7. package/dist/prod/core/core.js +99 -67
  8. package/dist/prod/core/effect.js +25 -28
  9. package/dist/prod/core/external.js +2 -2
  10. package/dist/prod/core/graph.js +85 -49
  11. package/dist/prod/core/heap.js +10 -10
  12. package/dist/prod/core/lanes.js +19 -19
  13. package/dist/prod/core/optimistic.js +66 -41
  14. package/dist/prod/core/owner.js +13 -13
  15. package/dist/prod/core/scheduler.js +131 -85
  16. package/dist/prod/core/verdict.js +36 -15
  17. package/dist/prod/index.js +4 -0
  18. package/dist/prod/map.js +101 -101
  19. package/dist/prod/signals.js +1 -1
  20. package/dist/prod/store/index.js +2 -0
  21. package/dist/prod/store/next/optimistic.js +65 -11
  22. package/dist/prod/store/next/patch-hooks.js +13 -0
  23. package/dist/prod/store/next/patch.js +614 -0
  24. package/dist/prod/store/next/projection.js +107 -45
  25. package/dist/prod/store/next/reconcile.js +307 -120
  26. package/dist/prod/store/next/store.js +321 -92
  27. package/dist/prod/store/next/target.js +13 -4
  28. package/dist/prod/store/store.js +5 -5
  29. package/dist/types/core/core.d.ts +15 -1
  30. package/dist/types/core/dev.d.ts +8 -0
  31. package/dist/types/core/graph.d.ts +22 -0
  32. package/dist/types/core/invariants.d.ts +1 -1
  33. package/dist/types/core/scheduler.d.ts +12 -0
  34. package/dist/types/store/index.d.ts +2 -0
  35. package/dist/types/store/next/patch-hooks.d.ts +41 -0
  36. package/dist/types/store/next/patch.d.ts +91 -0
  37. package/dist/types/store/next/reconcile.d.ts +14 -0
  38. package/dist/types/store/next/store.d.ts +30 -2
  39. package/dist/types/store/next/target.d.ts +58 -8
  40. package/dist/types-cjs/core/core.d.cts +15 -1
  41. package/dist/types-cjs/core/dev.d.cts +8 -0
  42. package/dist/types-cjs/core/graph.d.cts +22 -0
  43. package/dist/types-cjs/core/invariants.d.cts +1 -1
  44. package/dist/types-cjs/core/scheduler.d.cts +12 -0
  45. package/dist/types-cjs/store/index.d.cts +2 -0
  46. package/dist/types-cjs/store/next/patch-hooks.d.cts +41 -0
  47. package/dist/types-cjs/store/next/patch.d.cts +91 -0
  48. package/dist/types-cjs/store/next/reconcile.d.cts +14 -0
  49. package/dist/types-cjs/store/next/store.d.cts +30 -2
  50. package/dist/types-cjs/store/next/target.d.cts +58 -8
  51. package/package.json +14 -14
  52. package/dist/types/store/optimistic.d.ts +0 -45
  53. package/dist/types/store/projection.d.ts +0 -70
  54. package/dist/types/store/reconcile.d.ts +0 -46
  55. package/dist/types-cjs/store/optimistic.d.cts +0 -45
  56. package/dist/types-cjs/store/projection.d.cts +0 -70
  57. package/dist/types-cjs/store/reconcile.d.cts +0 -46
@@ -4,7 +4,7 @@ import { EFFECT_TRACKED, REACTIVE_OPTIMISTIC_DIRTY, CONFIG_OPTIMISTIC, NOT_PENDI
4
4
 
5
5
  import { NotReadyError } from "./error.js";
6
6
 
7
- import { trimStaleDeps, link, unobserved } from "./graph.js";
7
+ import { trimStaleDeps, link, dormantNodes } from "./graph.js";
8
8
 
9
9
  import { deleteFromHeap, queueFor, insertIntoHeapHeight, enqueueSub, markNode, markHeap, insertIntoHeap } from "./heap.js";
10
10
 
@@ -49,7 +49,7 @@ let snapshotSources = null;
49
49
  function ownerInSnapshotScope(e) {
50
50
  while (e) {
51
51
  if (e.He) return true;
52
- e = e.ve;
52
+ e = e.ke;
53
53
  }
54
54
  return false;
55
55
  }
@@ -70,13 +70,13 @@ function releaseSnapshotScope(e) {
70
70
  }
71
71
 
72
72
  function releaseSubtree(e) {
73
- let t = e.ke;
73
+ let t = e.ve;
74
74
  while (t) {
75
75
  if (t.He) {
76
76
  t = t.Ve;
77
77
  continue;
78
78
  }
79
- if (t.Se) {
79
+ if (t.oe) {
80
80
  const e = t;
81
81
  e.T &= ~CONFIG_IN_SNAPSHOT_SCOPE;
82
82
  if (e.ie & REACTIVE_SNAPSHOT_STALE) {
@@ -114,13 +114,13 @@ function recompute(e, t = false) {
114
114
  deleteFromHeap(e, queueFor(e));
115
115
  if (e.o !== null) e.o.Ee = null;
116
116
  // Tracked effects run after finalizePureQueue, so dispose immediately instead of deferring
117
- if (e._e || n === EFFECT_TRACKED) disposeChildren(e); else if (e.ke !== null || e.he !== null) {
117
+ if (e._e || n === EFFECT_TRACKED) disposeChildren(e); else if (e.ve !== null || e.he !== null) {
118
118
  markDisposal(e);
119
119
  const t = ext(e);
120
120
  t.We = e.he;
121
- t.qe = e.ke;
121
+ t.qe = e.ve;
122
122
  e.he = null;
123
- e.ke = null;
123
+ e.ve = null;
124
124
  e.Me = 0;
125
125
  } else ;
126
126
  }
@@ -148,8 +148,8 @@ function recompute(e, t = false) {
148
148
  let c = e.Pe === NOT_PENDING ? e.be : e.Pe;
149
149
  let _ = e.Le;
150
150
  let f = false;
151
- let E = tracking;
152
- let I = currentOptimisticLane;
151
+ let N = tracking;
152
+ let E = currentOptimisticLane;
153
153
  tracking = true;
154
154
  // A computed's fn establishes its OWN dependencies, so it must never run
155
155
  // inside a latest() read window: read() short-circuits through the
@@ -157,7 +157,7 @@ function recompute(e, t = false) {
157
157
  // computed) inside latest(fn) came out permanently dependency-less (#2926).
158
158
  // latestRead() already suspends the flag for its pull-recomputes; this
159
159
  // covers creation-time computes and flushes that run inside the window.
160
- const N = latestReadActive;
160
+ const I = latestReadActive;
161
161
  latestReadActive = false;
162
162
  // Lane posture lives with the engine: OPTIMISTIC_DIRTY is only ever set by
163
163
  // engine-driven paths, and _optimisticNodes is only pushed by
@@ -179,12 +179,12 @@ function recompute(e, t = false) {
179
179
  currentOptimisticLane = t;
180
180
  }
181
181
  }
182
- const T = n && n !== EFFECT_USER;
183
- const d = stale;
184
- if (T) stale = true;
182
+ const d = n && n !== EFFECT_USER;
183
+ const T = stale;
184
+ if (d) stale = true;
185
185
  try {
186
186
  if (!false && e.T & CONFIG_SYNC) {
187
- c = e.Se(c);
187
+ c = e.oe(c);
188
188
  if (e.o !== null) e.o.Ee = null;
189
189
  e.Ie = false;
190
190
  } else {
@@ -194,7 +194,7 @@ function recompute(e, t = false) {
194
194
  // clobber the fresh subscription, so we skip it and let the internally-registered
195
195
  // iteration drive updates.
196
196
  const t = e.o?.Ee;
197
- const n = e.Se(c);
197
+ const n = e.oe(c);
198
198
  const i = typeof n === "object" && n !== null;
199
199
  const u = e.o?.Ee !== t;
200
200
  c = u || !i ? n : handleAsync(e, n);
@@ -232,16 +232,16 @@ function recompute(e, t = false) {
232
232
  if (n && currentOptimisticLane) GlobalQueue.$e(e);
233
233
  let i = false;
234
234
  if (n) {
235
- ext(e).ue = true;
235
+ ext(e).fe = true;
236
236
  if (GlobalQueue.Je !== null) i = GlobalQueue.Je(e, s);
237
237
  }
238
238
  notifyStatus(e, n ? STATUS_PENDING : STATUS_ERROR, t, undefined, n ? e.o?.Be : undefined);
239
- if (i) GlobalQueue.p(e);
239
+ if (i) GlobalQueue.k(e);
240
240
  }
241
241
  } finally {
242
- tracking = E;
243
- latestReadActive = N;
244
- if (T) stale = d;
242
+ tracking = N;
243
+ latestReadActive = I;
244
+ if (d) stale = T;
245
245
  // Consume the missed-wake latch (#3037, set by insertSubs): a dep write
246
246
  // landed beneath this pass on a link it had already validated. The wipe
247
247
  // below must not key off DIRTY/CHECK — the read-time pull protocol
@@ -316,8 +316,8 @@ function recompute(e, t = false) {
316
316
  if (a) e.Ie = true;
317
317
  // see the held branch above (#2990)
318
318
  } else if (e.Le != _) {
319
- for (let t = e.u; t !== null; t = t.fe) {
320
- insertIntoHeapHeight(t.ae, queueFor(t.ae));
319
+ for (let t = e.u; t !== null; t = t.ae) {
320
+ insertIntoHeapHeight(t.ce, queueFor(t.ce));
321
321
  }
322
322
  }
323
323
  // Silent recovery: errored → unchanged value fires no notification, but
@@ -327,7 +327,7 @@ function recompute(e, t = false) {
327
327
  // (el._x?._error re-set), so this only runs on a genuinely clean recovery.
328
328
  if (o !== undefined && !r && !e.o?._) settleErroredDependents(e, o);
329
329
  }
330
- currentOptimisticLane = I;
330
+ currentOptimisticLane = E;
331
331
  const S = e.Pe !== NOT_PENDING || e.o !== null && (e.o.qe !== null || e.o.We !== null) || (e.S & (STATUS_PENDING | STATUS_UNINITIALIZED)) !== 0;
332
332
  // Override-covered holds (hasOverride) always queue: their commit belongs
333
333
  // to their own transition's schedule (A18 re-rule) and is unobservable
@@ -357,7 +357,7 @@ function updateIfNecessary(e) {
357
357
  for (let t = e.nt; t; t = t.it) {
358
358
  const n = t.ut;
359
359
  const i = n.lt || n;
360
- if (i.Se) {
360
+ if (i.oe) {
361
361
  updateIfNecessary(i);
362
362
  }
363
363
  if (e.ie & REACTIVE_DIRTY) {
@@ -385,7 +385,7 @@ function computed(e, t) {
385
385
  C: context?.C ?? globalQueue,
386
386
  we: context?.we ?? defaultContext,
387
387
  Me: 0,
388
- Se: e,
388
+ oe: e,
389
389
  be: i ? t.loadingValue : undefined,
390
390
  Le: 0,
391
391
  ot: undefined,
@@ -395,10 +395,10 @@ function computed(e, t) {
395
395
  Ze: 0,
396
396
  u: null,
397
397
  rt: null,
398
- ve: context,
398
+ ke: context,
399
399
  Ve: null,
400
400
  ct: null,
401
- ke: null,
401
+ ve: null,
402
402
  ie: t?.lazy ? REACTIVE_LAZY : REACTIVE_NONE,
403
403
  // A loadingValue node is born committed: commit #0 is already in _value.
404
404
  S: i ? 0 : STATUS_UNINITIALIZED,
@@ -424,24 +424,24 @@ function computed(e, t) {
424
424
  * Never call ext() just to store a field's default. */ function ext(e) {
425
425
  return e.o ??= {
426
426
  De: undefined,
427
- Et: undefined,
427
+ Nt: undefined,
428
428
  Be: undefined,
429
429
  Ge: undefined,
430
430
  ge: undefined,
431
- It: undefined,
431
+ Et: undefined,
432
432
  t: 0,
433
433
  Ee: null,
434
434
  _: undefined,
435
- ue: undefined,
435
+ fe: undefined,
436
436
  le: undefined,
437
- A: undefined,
437
+ h: undefined,
438
438
  pe: false,
439
- l: null,
439
+ i: null,
440
440
  ft: undefined,
441
441
  Qe: undefined,
442
442
  We: null,
443
443
  qe: null,
444
- Nt: undefined
444
+ It: undefined
445
445
  };
446
446
  }
447
447
 
@@ -450,17 +450,17 @@ function computed(e, t) {
450
450
  * so V8 sees the full hidden class shape at construction time. Effects always run in lazy
451
451
  * mode (recompute is called explicitly by `effect()`), so we hardcode the lazy bits and skip
452
452
  * the auto-dispose CONFIG bit (effect() previously cleared it post-construction).
453
- */ function createEffectNode(e, t, n, i, u, l) {
454
- const o = l?.transparent ?? false;
455
- const s = {
456
- id: inheritId(l, o, context),
457
- T: (o ? CONFIG_TRANSPARENT : 0) | (l?.ownedWrite ? CONFIG_OWNED_WRITE : 0) | (l?.sync ? CONFIG_SYNC : 0) | (snapshotCaptureActive && ownerInSnapshotScope(context) ? CONFIG_IN_SNAPSHOT_SCOPE : 0),
453
+ */ function createEffectNode(e, t, n, i, u) {
454
+ const l = u?.transparent ?? false;
455
+ const o = {
456
+ id: inheritId(u, l, context),
457
+ T: (l ? CONFIG_TRANSPARENT : 0) | (u?.ownedWrite ? CONFIG_OWNED_WRITE : 0) | (u?.sync ? CONFIG_SYNC : 0) | (snapshotCaptureActive && ownerInSnapshotScope(context) ? CONFIG_IN_SNAPSHOT_SCOPE : 0),
458
458
  Ue: false,
459
459
  he: null,
460
460
  C: context?.C ?? globalQueue,
461
461
  we: context?.we ?? defaultContext,
462
462
  Me: 0,
463
- Se: e,
463
+ oe: e,
464
464
  be: undefined,
465
465
  Le: 0,
466
466
  ot: undefined,
@@ -470,10 +470,10 @@ function computed(e, t) {
470
470
  Ze: 0,
471
471
  u: null,
472
472
  rt: null,
473
- ve: context,
473
+ ke: context,
474
474
  Ve: null,
475
475
  ct: null,
476
- ke: null,
476
+ ve: null,
477
477
  ie: REACTIVE_LAZY,
478
478
  S: STATUS_UNINITIALIZED,
479
479
  Te: clock,
@@ -482,18 +482,43 @@ function computed(e, t) {
482
482
  _t: -1,
483
483
  Ie: false,
484
484
  Xe: false,
485
- Tt: undefined,
486
- dt: t,
485
+ dt: undefined,
486
+ Tt: t,
487
487
  St: n,
488
488
  At: undefined,
489
489
  Re: i,
490
490
  o: null
491
491
  };
492
- // Boundary effects carry a status channel; most effects never touch _x.
493
- if (u !== undefined) ext(s).A = u;
494
- if (l?.unobserved) ext(s).ft = l.unobserved;
495
- setupComputedNode(s, lazyOptions);
496
- return s;
492
+ // Effects dispatch status through the SHARED notifier (statusNotifierOf,
493
+ // keyed off _type) storing it per node forced a full NodeExtension
494
+ // allocation on EVERY effect at creation (an alloc + 19 field stores,
495
+ // +23% effect creation, caught by the creation benches). Only genuinely
496
+ // per-node channels (boundaries) live on _x.
497
+ if (u?.unobserved) ext(o).ft = u.unobserved;
498
+ setupComputedNode(o, lazyOptions);
499
+ return o;
500
+ }
501
+
502
+ /**
503
+ * The shared status notifier for effect nodes, installed once by effect.ts
504
+ * at module evaluation (`this`-dispatched — one function serves every
505
+ * effect, so nodes never store it). Boundary computeds keep their own
506
+ * per-node channel on `_x._notifyStatus`, which takes precedence.
507
+ */ let effectStatusNotify = null;
508
+
509
+ function setEffectStatusNotify(e) {
510
+ effectStatusNotify = e;
511
+ }
512
+
513
+ /** Resolve a node's status notifier: an own `_x` channel (boundaries) wins;
514
+ * effect nodes (`_type` — EFFECT_PURE is 0, and only effect literals carry
515
+ * the field) fall back to the shared notifier. Presence doubles as the
516
+ * "display consumer" membership test in the status walks, exactly as the
517
+ * per-node field did when every effect carried one. */ function statusNotifierOf(e) {
518
+ const t = e.o;
519
+ const n = t !== null && t !== undefined ? t.h : undefined;
520
+ if (n !== undefined) return n;
521
+ return e.Re ? effectStatusNotify ?? undefined : undefined;
497
522
  }
498
523
 
499
524
  const lazyOptions = {
@@ -504,13 +529,13 @@ function setupComputedNode(e, t) {
504
529
  e.st = e;
505
530
  const n = context?.Ct ? context.Ot : context;
506
531
  if (context) {
507
- const t = context.ke;
532
+ const t = context.ve;
508
533
  if (t === null) {
509
- context.ke = e;
534
+ context.ve = e;
510
535
  } else {
511
536
  e.Ve = t;
512
537
  t.ct = e;
513
- context.ke = e;
538
+ context.ve = e;
514
539
  }
515
540
  }
516
541
  if (n) e.Le = n.Le + 1;
@@ -534,7 +559,7 @@ function signal(e, t, n = null) {
534
559
  rt: null,
535
560
  Te: clock,
536
561
  lt: n,
537
- ce: n?.o?.l || null,
562
+ Se: n?.o?.i || null,
538
563
  Pe: NOT_PENDING,
539
564
  // Signal-literal diet (§12e): NO _time/_fn/_statusFlags slots. Stores
540
565
  // materialize one signal per touched leaf, so signal bytes are store
@@ -547,7 +572,7 @@ function signal(e, t, n = null) {
547
572
  };
548
573
  if (t?.unobserved) ext(i).ft = t.unobserved;
549
574
  if (n) {
550
- ext(n).l = i;
575
+ ext(n).i = i;
551
576
  n.T |= CONFIG_FW_CHILDREN;
552
577
  }
553
578
  if (snapshotCaptureActive && !(i.T & CONFIG_NO_SNAPSHOT) && !((n?.S ?? 0) & STATUS_PENDING)) {
@@ -644,7 +669,7 @@ function isEqual(e, t) {
644
669
  * snapshot / transition / lane / dev-strictRead state all take the full
645
670
  * resolution. Anything slow returns READ_SLOW; the caller then calls read().
646
671
  */ function readNodeFast(e) {
647
- if (latestReadActive || pendingCheckActive || e.Se || e.lt || e.o?.De !== undefined || e.o?.Qe !== undefined || activeTransition !== null || currentOptimisticLane !== null || snapshotCaptureActive || false) return READ_SLOW;
672
+ if (latestReadActive || pendingCheckActive || e.oe || e.lt || e.o?.De !== undefined || e.o?.Qe !== undefined || activeTransition !== null || currentOptimisticLane !== null || snapshotCaptureActive || false) return READ_SLOW;
648
673
  let t = context;
649
674
  if (t?.Ct) t = t.Ot;
650
675
  if (t && tracking) link(e, t);
@@ -671,17 +696,17 @@ function read(e) {
671
696
  // recompute don't collect into the probe.
672
697
  if (pendingCheckActive) {
673
698
  GlobalQueue.Dt(e, t, u, i);
674
- } else if (typeof n.Se === "function") {
699
+ } else if (typeof n.oe === "function") {
675
700
  prepareComputed(e, false);
676
701
  }
677
- if (!n.Se && u === e && e.o?.De === undefined && e.o?.Qe === undefined && activeTransition === null && currentOptimisticLane === null && !snapshotCaptureActive && true) {
702
+ if (!n.oe && u === e && e.o?.De === undefined && e.o?.Qe === undefined && activeTransition === null && currentOptimisticLane === null && !snapshotCaptureActive && true) {
678
703
  if (t && tracking) link(e, t);
679
704
  // Committed visibility for children-forbidden readers — see readNodeFast.
680
705
  return !t || e.Pe === NOT_PENDING || t.T & CONFIG_CHILDREN_FORBIDDEN ? e.be : e.Pe;
681
706
  }
682
707
  if (t && tracking) {
683
708
  link(e, t, pendingCheckActive);
684
- if (u.Se) {
709
+ if (u.oe) {
685
710
  const n = queueFor(e);
686
711
  if (u.Le >= n.xe) {
687
712
  markNode(t);
@@ -690,7 +715,7 @@ function read(e) {
690
715
  }
691
716
  const i = u.Le;
692
717
  // parent check is shallow, might need to be recursive
693
- if (i >= t.Le && e.ve !== t) {
718
+ if (i >= t.Le && e.ke !== t) {
694
719
  t.Le = i + 1;
695
720
  }
696
721
  }
@@ -725,7 +750,7 @@ function read(e) {
725
750
  // firewall-backed reads follow the same rules (memo parity, #2897 ruling):
726
751
  // an errored derive throws for every late reader instead of silently
727
752
  // serving node values (the seed, or last-good data after a failed refetch).
728
- if (u.Se && u.S & STATUS_ERROR) {
753
+ if (u.oe && u.S & STATUS_ERROR) {
729
754
  // Only a genuine reactive re-read may retry an errored async source:
730
755
  // - tracking: owned/tracked scope only (never events / `untrack` / effect side-effect phase)
731
756
  // - !pendingCheckActive: an `isPending` probe observes the error, never refetches
@@ -768,8 +793,15 @@ function read(e) {
768
793
  // Record that this isPending() probe observed the fresh pending value, so
769
794
  // the probe doesn't pair "pending" with the new value (#2831).
770
795
  if (pendingCheckActive) GlobalQueue.Ht(e, l);
771
- if (!t && u === e && typeof n.Se === "function" && e.T & CONFIG_AUTO_DISPOSE && !(u.S & STATUS_PENDING) && !e.u) {
772
- unobserved(e);
796
+ if (!t && u === e && typeof n.oe === "function" && e.T & CONFIG_AUTO_DISPOSE && !(u.S & STATUS_PENDING) && !e.u) {
797
+ // Deferred, not inline (#3078): an inline unobserved() here made untracked
798
+ // reads destructive — dispose on this read, full revival recompute on the
799
+ // next — so consecutive reads could answer differently with no write in
800
+ // between (the revival samples the ambient transition/lane context).
801
+ // The sweep at flush finalization re-validates and reclaims; schedule()
802
+ // guarantees that flush happens even if nothing else is queued.
803
+ dormantNodes.add(e);
804
+ schedule();
773
805
  }
774
806
  return l;
775
807
  }
@@ -781,7 +813,7 @@ function setSignal(e, t) {
781
813
  // _overrideValue slot (flagged by CONFIG_OPTIMISTIC — a masked read of the
782
814
  // always-present config instead of a missing-property probe), and every
783
815
  // module that installs one installs the engine first.
784
- if (e.T & CONFIG_OPTIMISTIC && !projectionWriteActive) return GlobalQueue.vt(e, t);
816
+ if (e.T & CONFIG_OPTIMISTIC && !projectionWriteActive) return GlobalQueue.kt(e, t);
785
817
  const n = e.Pe === NOT_PENDING ? e.be : e.Pe;
786
818
  if (typeof t === "function") t = t(n);
787
819
  // Uninitialized check first: the first commit has no previous value, so the
@@ -799,7 +831,7 @@ function setSignal(e, t) {
799
831
  e.T & CONFIG_HAS_COMPANIONS && GlobalQueue.Oe !== null && GlobalQueue.Oe(e, t);
800
832
  // _time is a computed-only slot (§12e): writing it on a signal would fork
801
833
  // the lean shape. Every read site is computed-typed.
802
- if (e.Se !== undefined) e.Te = clock;
834
+ if (e.oe !== undefined) e.Te = clock;
803
835
  // Staged-rewrite fast path (§12d): a re-write to a node whose subscribers
804
836
  // were already walked — and where nothing has recomputed or linked since
805
837
  // (epoch) — re-stages the value and stops. The walk is idempotent (subs
@@ -824,7 +856,7 @@ function setSignal(e, t) {
824
856
  schedule();
825
857
  }
826
858
  e.ie = e.ie & -4 | REACTIVE_MANUAL_WRITE;
827
- e.kt = clock;
859
+ e.vt = clock;
828
860
  }
829
861
 
830
862
  /**
@@ -903,7 +935,7 @@ function staleValues(e, t = true) {
903
935
  if (!t) {
904
936
  return;
905
937
  }
906
- if (typeof t.Se === "function" && !(t.ie & REACTIVE_DISPOSED)) {
938
+ if (typeof t.oe === "function" && !(t.ie & REACTIVE_DISPOSED)) {
907
939
  if (t.ie & REACTIVE_MANUAL_WRITE) {
908
940
  // A manual write in the CURRENT tick wins over the refresh (#2692).
909
941
  // A mask stamped in an earlier tick only survives because a
@@ -911,7 +943,7 @@ function staleValues(e, t = true) {
911
943
  // refresh is a later, explicit re-ask and lifts the mask — otherwise
912
944
  // any setStore early in an action silently swallows every refresh()
913
945
  // for the rest of the transaction (#3026).
914
- if (t.kt === clock) return;
946
+ if (t.vt === clock) return;
915
947
  t.ie &= ~REACTIVE_MANUAL_WRITE;
916
948
  // No REASK below: the batch carries a manual value change, so the
917
949
  // recompute is not a quiet re-ask of an unchanged question.
@@ -933,4 +965,4 @@ function staleValues(e, t = true) {
933
965
  }
934
966
  }
935
967
 
936
- export { READ_SLOW, clearSnapshots, computed, context, createEffectNode, currentOptimisticLane, ext, isEqual, latestReadActive, markSnapshotScope, optimisticComputed, optimisticSignal, pendingCheckActive, prepareComputed, read, readNodeFast, recompute, refresh, releaseSnapshotScope, runWithOwner, setContextInternal, setLatestReadActive, setMemo, setPendingCheckActive, setSignal, setSnapshotCapture, signal, snapshotCaptureActive, snapshotSources, stale, staleValues, suppressComputedRecompute, tracking, untrack };
968
+ export { READ_SLOW, clearSnapshots, computed, context, createEffectNode, currentOptimisticLane, effectStatusNotify, ext, isEqual, latestReadActive, markSnapshotScope, optimisticComputed, optimisticSignal, pendingCheckActive, prepareComputed, read, readNodeFast, recompute, refresh, releaseSnapshotScope, runWithOwner, setContextInternal, setEffectStatusNotify, setLatestReadActive, setMemo, setPendingCheckActive, setSignal, setSnapshotCapture, signal, snapshotCaptureActive, snapshotSources, stale, staleValues, statusNotifierOf, suppressComputedRecompute, tracking, untrack };
@@ -1,6 +1,6 @@
1
- import { REACTIVE_DISPOSED, STATUS_ERROR, EFFECT_USER, CONFIG_AUTO_DISPOSE, CONFIG_CHILDREN_FORBIDDEN, EFFECT_TRACKED, STATUS_PENDING, EFFECT_RENDER } from "./constants.js";
1
+ import { REACTIVE_DISPOSED, STATUS_ERROR, EFFECT_USER, CONFIG_AUTO_DISPOSE, CONFIG_CHILDREN_FORBIDDEN, EFFECT_TRACKED, EFFECT_RENDER, STATUS_PENDING } from "./constants.js";
2
2
 
3
- import { ext, createEffectNode, recompute, computed, staleValues } from "./core.js";
3
+ import { setEffectStatusNotify, ext, createEffectNode, recompute, computed, staleValues } from "./core.js";
4
4
 
5
5
  import { unwrapStatusError, StatusError } from "./error.js";
6
6
 
@@ -10,17 +10,17 @@ import { GlobalQueue, haltReactivity } from "./scheduler.js";
10
10
  * Effects are the leaf nodes of our reactive graph. When their sources change, they are
11
11
  * automatically added to the queue of effects to re-execute, which will cause them to fetch their
12
12
  * sources and recompute
13
- */ function effect(t, e, E, R) {
14
- const r = !!R?.user;
15
- const f = createEffectNode(t, e, E, r ? EFFECT_USER : EFFECT_RENDER, notifyEffectStatus, R);
16
- recompute(f, true);
17
- !R?.defer && (f.Re === EFFECT_USER || R?.schedule ? f.C.enqueue(f.Re, runEffect.bind(null, f)) : runEffect(f));
13
+ */ function effect(t, e, E, f) {
14
+ const r = !!f?.user;
15
+ const R = createEffectNode(t, e, E, r ? EFFECT_USER : EFFECT_RENDER, f);
16
+ recompute(R, true);
17
+ !f?.defer && (R.Re === EFFECT_USER || f?.schedule ? R.C.enqueue(R.Re, runEffect.bind(null, R)) : runEffect(R));
18
18
  }
19
19
 
20
20
  function notifyEffectStatus(t, e) {
21
21
  // Use passed values if provided, otherwise read from node
22
22
  const E = t !== undefined ? t : this.S;
23
- const R = e !== undefined ? e : this.o?._;
23
+ const f = e !== undefined ? e : this.o?._;
24
24
  if (E & STATUS_ERROR) {
25
25
  this.C.notify(this, STATUS_PENDING, 0);
26
26
  if (this.Re === EFFECT_USER) {
@@ -40,11 +40,11 @@ function notifyEffectStatus(t, e) {
40
40
  return;
41
41
  }
42
42
  if (!this.C.notify(this, STATUS_ERROR, STATUS_ERROR)) {
43
- haltReactivity(unwrapStatusError(R));
44
- throw R;
43
+ haltReactivity(unwrapStatusError(f));
44
+ throw f;
45
45
  }
46
46
  } else if (this.Re === EFFECT_RENDER) {
47
- this.C.notify(this, STATUS_PENDING | STATUS_ERROR, E, R);
47
+ this.C.notify(this, STATUS_PENDING | STATUS_ERROR, E, f);
48
48
  }
49
49
  }
50
50
 
@@ -62,7 +62,7 @@ function runEffect(t) {
62
62
  // same flush must not be hijacked by a later-arriving error status.
63
63
  if (t.S & STATUS_ERROR && t.Re === EFFECT_USER) {
64
64
  const e = unwrapStatusError(t.o?._);
65
- t.Tt = t.be;
65
+ t.dt = t.be;
66
66
  t.Xe = false;
67
67
  try {
68
68
  t.St ? t.St(e, () => {
@@ -82,7 +82,7 @@ function runEffect(t) {
82
82
  t.At = undefined;
83
83
  try {
84
84
  e?.();
85
- const E = t.dt(t.be, t.Tt);
85
+ const E = t.Tt(t.be, t.dt);
86
86
  if (false && E !== undefined && typeof E !== "function") ;
87
87
  // The final cleanup is invoked by disposeChildren at true disposal.
88
88
  t.At = E;
@@ -94,7 +94,7 @@ function runEffect(t) {
94
94
  throw e;
95
95
  }
96
96
  } finally {
97
- t.Tt = t.be;
97
+ t.dt = t.be;
98
98
  t.Xe = false;
99
99
  }
100
100
  }
@@ -117,8 +117,8 @@ GlobalQueue.tt = runEffect;
117
117
  const e = E.At;
118
118
  E.At = undefined;
119
119
  e?.();
120
- const R = staleValues(t);
121
- E.At = R;
120
+ const f = staleValues(t);
121
+ E.At = f;
122
122
  }, {
123
123
  ...e,
124
124
  lazy: true
@@ -127,19 +127,16 @@ GlobalQueue.tt = runEffect;
127
127
  E.T = E.T & ~CONFIG_AUTO_DISPOSE | CONFIG_CHILDREN_FORBIDDEN;
128
128
  E.Xe = true;
129
129
  E.Re = EFFECT_TRACKED;
130
- ext(E).A = (t, e) => {
131
- const R = t !== undefined ? t : E.S;
132
- if (R & STATUS_ERROR) {
133
- E.C.notify(E, STATUS_PENDING, 0);
134
- const t = e !== undefined ? e : E.o?._;
135
- if (!E.C.notify(E, STATUS_ERROR, STATUS_ERROR)) {
136
- haltReactivity(unwrapStatusError(t));
137
- throw t;
138
- }
139
- }
140
- };
141
- E.Ut = run;
130
+ // Status dispatch rides the SHARED notifier (statusNotifierOf keys off
131
+ // _type): its error arm is behavior-identical to the closure that used to
132
+ // live here, without the per-node NodeExtension allocation.
133
+ E.Ut = run;
142
134
  E.C.enqueue(EFFECT_USER, run);
143
135
  }
144
136
 
137
+ // Install the shared effect status notifier (statusNotifierOf serves it to
138
+ // every effect node) — module-scope: any bundle that creates effects
139
+ // evaluates this module.
140
+ setEffectStatusNotify(notifyEffectStatus);
141
+
145
142
  export { effect, trackedEffect };
@@ -46,11 +46,11 @@ function wireExternalSource(e) {
46
46
  equals: false,
47
47
  ownedWrite: true
48
48
  });
49
- const r = externalSourceConfig.factory(e.Se, () => {
49
+ const r = externalSourceConfig.factory(e.oe, () => {
50
50
  setSignal(n, undefined);
51
51
  });
52
52
  cleanup(() => r.dispose());
53
- e.Se = e => {
53
+ e.oe = e => {
54
54
  read(n);
55
55
  return r.track(e);
56
56
  };