@solidjs/signals 2.0.0-beta.19 → 2.0.0-beta.20

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 (36) hide show
  1. package/dist/dev.js +670 -371
  2. package/dist/node.cjs +1878 -1606
  3. package/dist/prod/affects.js +17 -21
  4. package/dist/prod/core/action.js +19 -6
  5. package/dist/prod/core/async.js +57 -71
  6. package/dist/prod/core/constants.js +15 -1
  7. package/dist/prod/core/core.js +39 -39
  8. package/dist/prod/core/effect.js +14 -14
  9. package/dist/prod/core/graph.js +1 -1
  10. package/dist/prod/core/heap.js +2 -2
  11. package/dist/prod/core/lanes.js +23 -13
  12. package/dist/prod/core/optimistic.js +107 -99
  13. package/dist/prod/core/owner.js +23 -23
  14. package/dist/prod/core/scheduler.js +180 -180
  15. package/dist/prod/core/verdict.js +12 -13
  16. package/dist/prod/map.js +196 -167
  17. package/dist/prod/signals.js +1 -1
  18. package/dist/prod/store/optimistic.js +103 -68
  19. package/dist/prod/store/reconcile.js +80 -46
  20. package/dist/prod/store/store.js +204 -73
  21. package/dist/prod/store/utils.js +61 -42
  22. package/dist/types/core/action.d.ts +19 -6
  23. package/dist/types/core/constants.d.ts +12 -0
  24. package/dist/types/core/dev.d.ts +7 -0
  25. package/dist/types/core/lanes.d.ts +2 -0
  26. package/dist/types/core/scheduler.d.ts +2 -6
  27. package/dist/types/core/types.d.ts +9 -1
  28. package/dist/types/store/store.d.ts +8 -2
  29. package/dist/types-cjs/core/action.d.cts +19 -6
  30. package/dist/types-cjs/core/constants.d.cts +12 -0
  31. package/dist/types-cjs/core/dev.d.cts +7 -0
  32. package/dist/types-cjs/core/lanes.d.cts +2 -0
  33. package/dist/types-cjs/core/scheduler.d.cts +2 -6
  34. package/dist/types-cjs/core/types.d.cts +9 -1
  35. package/dist/types-cjs/store/store.d.cts +8 -2
  36. package/package.json +1 -1
@@ -1,18 +1,18 @@
1
1
  import { handleAsync, clearStatus, notifyStatus } from "./async.js";
2
2
 
3
- import { $REFRESH, REACTIVE_DISPOSED, REACTIVE_MANUAL_WRITE, REACTIVE_DIRTY, REACTIVE_CHECK, REACTIVE_IN_HEAP, REACTIVE_REASK, REACTIVE_LAZY, REACTIVE_NONE, defaultContext, CONFIG_TRANSPARENT, CONFIG_OWNED_WRITE, CONFIG_AUTO_DISPOSE, CONFIG_SYNC, CONFIG_NO_SNAPSHOT, CONFIG_IN_SNAPSHOT_SCOPE, NOT_PENDING, STATUS_UNINITIALIZED, STATUS_PENDING, NO_SNAPSHOT, REACTIVE_SNAPSHOT_STALE, EFFECT_TRACKED, REACTIVE_OPTIMISTIC_DIRTY, REACTIVE_RECOMPUTING_DEPS, STATUS_ERROR, REACTIVE_IN_HEAP_HEIGHT, STORE_SNAPSHOT_PROPS, EFFECT_USER } from "./constants.js";
3
+ import { EFFECT_TRACKED, REACTIVE_OPTIMISTIC_DIRTY, NOT_PENDING, STATUS_UNINITIALIZED, REACTIVE_REASK, REACTIVE_RECOMPUTING_DEPS, CONFIG_SYNC, STATUS_PENDING, STATUS_ERROR, REACTIVE_NONE, REACTIVE_SNAPSHOT_STALE, unwrapOverride, OVERRIDE_UNDEFINED, CONFIG_AUTO_DISPOSE, REACTIVE_LAZY, REACTIVE_DISPOSED, REACTIVE_CHECK, REACTIVE_DIRTY, REACTIVE_IN_HEAP, REACTIVE_IN_HEAP_HEIGHT, defaultContext, CONFIG_IN_SNAPSHOT_SCOPE, CONFIG_TRANSPARENT, CONFIG_OWNED_WRITE, CONFIG_NO_SNAPSHOT, $REFRESH, REACTIVE_MANUAL_WRITE, NO_SNAPSHOT, STORE_SNAPSHOT_PROPS, EFFECT_USER } from "./constants.js";
4
4
 
5
5
  import { NotReadyError } from "./error.js";
6
6
 
7
7
  import { trimStaleDeps, link, unobserved } from "./graph.js";
8
8
 
9
- import { insertIntoHeap, queueFor, deleteFromHeap, insertIntoHeapHeight, markNode, markHeap } from "./heap.js";
9
+ import { deleteFromHeap, queueFor, insertIntoHeapHeight, markNode, markHeap, insertIntoHeap } from "./heap.js";
10
10
 
11
- import { schedule, GlobalQueue, globalQueue, clock, activeTransition, queuePendingNode, insertSubs, dirtyQueue, activeAffectsMarks, runInTransition, projectionWriteActive, armReaskClear } from "./scheduler.js";
11
+ import { GlobalQueue, activeTransition, globalQueue, clock, insertSubs, queuePendingNode, activeAffectsMarks, runInTransition, schedule, dirtyQueue, projectionWriteActive, armReaskClear } from "./scheduler.js";
12
12
 
13
13
  import "./invariants.js";
14
14
 
15
- import { inheritId, disposeChildren, markDisposal } from "./owner.js";
15
+ import { disposeChildren, markDisposal, inheritId } from "./owner.js";
16
16
 
17
17
  GlobalQueue.Ce = recompute;
18
18
 
@@ -60,7 +60,7 @@ let snapshotSources = null;
60
60
  function ownerInSnapshotScope(e) {
61
61
  while (e) {
62
62
  if (e.ke) return true;
63
- e = e.He;
63
+ e = e.Fe;
64
64
  }
65
65
  return false;
66
66
  }
@@ -81,7 +81,7 @@ function releaseSnapshotScope(e) {
81
81
  }
82
82
 
83
83
  function releaseSubtree(e) {
84
- let t = e.Fe;
84
+ let t = e.He;
85
85
  while (t) {
86
86
  if (t.ke) {
87
87
  t = t.Ve;
@@ -120,12 +120,12 @@ function recompute(e, t = false) {
120
120
  deleteFromHeap(e, queueFor(e));
121
121
  e.Ae = null;
122
122
  // Tracked effects run after finalizePureQueue, so dispose immediately instead of deferring
123
- if (e.ve || n === EFFECT_TRACKED) disposeChildren(e); else if (e.Fe !== null || e.Me !== null) {
123
+ if (e.ve || n === EFFECT_TRACKED) disposeChildren(e); else if (e.He !== null || e.Me !== null) {
124
124
  markDisposal(e);
125
125
  e.We = e.Me;
126
- e.Ze = e.Fe;
126
+ e.Ze = e.He;
127
127
  e.Me = null;
128
- e.Fe = null;
128
+ e.He = null;
129
129
  e.je = 0;
130
130
  } else ;
131
131
  }
@@ -165,9 +165,9 @@ function recompute(e, t = false) {
165
165
  currentOptimisticLane = t;
166
166
  }
167
167
  }
168
- const T = n && n !== EFFECT_USER;
169
- const N = stale;
170
- if (T) stale = true;
168
+ const N = n && n !== EFFECT_USER;
169
+ const T = stale;
170
+ if (N) stale = true;
171
171
  try {
172
172
  if (!false && e.U & CONFIG_SYNC) {
173
173
  a = e.xe(a);
@@ -201,7 +201,7 @@ function recompute(e, t = false) {
201
201
  if (n) GlobalQueue.nt(e);
202
202
  } finally {
203
203
  tracking = c;
204
- if (T) stale = N;
204
+ if (N) stale = T;
205
205
  e.u = REACTIVE_NONE | (t ? e.u & REACTIVE_SNAPSHOT_STALE : 0);
206
206
  context = o;
207
207
  f = affectsReads;
@@ -209,7 +209,7 @@ function recompute(e, t = false) {
209
209
  }
210
210
  if (!e.k) {
211
211
  trimStaleDeps(e);
212
- const s = l ? e.be : e.ge === NOT_PENDING ? e.Ue : e.ge;
212
+ const s = l ? unwrapOverride(e.be) : e.ge === NOT_PENDING ? e.Ue : e.ge;
213
213
  let o = false;
214
214
  try {
215
215
  o = !n && u || !e.Ge || !e.Ge(s, a);
@@ -240,7 +240,7 @@ function recompute(e, t = false) {
240
240
  // own reveal schedule; drop any superseded older hold so its queued
241
241
  // commit can't clobber the fresh value.
242
242
  if (l && i) {
243
- e.be = a;
243
+ e.be = a === undefined ? OVERRIDE_UNDEFINED : a;
244
244
  e.ge = NOT_PENDING;
245
245
  }
246
246
  } else {
@@ -279,13 +279,13 @@ function recompute(e, t = false) {
279
279
  // action's transaction onto it — freezing unrelated writes that share it.
280
280
  // (Single mask test up front keeps the mark-free hot path at original cost.)
281
281
  const I = e.i & (STATUS_PENDING | STATUS_UNINITIALIZED);
282
- const S = e.ge !== NOT_PENDING || e.Ze !== null || e.We !== null || I !== 0 && (I !== STATUS_PENDING || activeAffectsMarks === 0 || !GlobalQueue.$(e));
282
+ const p = e.ge !== NOT_PENDING || e.Ze !== null || e.We !== null || I !== 0 && (I !== STATUS_PENDING || activeAffectsMarks === 0 || !GlobalQueue.$(e));
283
283
  // Override-covered holds (hasOverride) always queue: their commit belongs
284
284
  // to their own transition's schedule (A18 re-rule) and is unobservable
285
285
  // under the override (A17). Revert no longer commits anything, so an
286
286
  // unqueued covered hold would leak (INV-7) once the revert clears
287
287
  // _transition.
288
- S && (!t || e.i & STATUS_PENDING) && (!e.ve || l) && queuePendingNode(e);
288
+ p && (!t || e.i & STATUS_PENDING) && (!e.ve || l) && queuePendingNode(e);
289
289
  e.ve && n && activeTransition !== e.ve && runInTransition(e.ve, () => recompute(e));
290
290
  }
291
291
 
@@ -330,10 +330,10 @@ function computed(e, t) {
330
330
  ze: 0,
331
331
  p: null,
332
332
  Et: null,
333
- He: context,
333
+ Fe: context,
334
334
  Ve: null,
335
- Tt: null,
336
- Fe: null,
335
+ Nt: null,
336
+ He: null,
337
337
  u: t?.lazy ? REACTIVE_LAZY : REACTIVE_NONE,
338
338
  i: STATUS_UNINITIALIZED,
339
339
  Ie: clock,
@@ -375,10 +375,10 @@ function computed(e, t) {
375
375
  ze: 0,
376
376
  p: null,
377
377
  Et: null,
378
- He: context,
378
+ Fe: context,
379
379
  Ve: null,
380
- Tt: null,
381
- Fe: null,
380
+ Nt: null,
381
+ He: null,
382
382
  u: REACTIVE_LAZY,
383
383
  i: STATUS_UNINITIALIZED,
384
384
  Ie: clock,
@@ -389,10 +389,10 @@ function computed(e, t) {
389
389
  ve: null,
390
390
  A: false,
391
391
  it: false,
392
- Nt: undefined,
392
+ Tt: undefined,
393
393
  It: t,
394
394
  St: n,
395
- At: undefined,
395
+ dt: undefined,
396
396
  De: i,
397
397
  C: l
398
398
  };
@@ -406,15 +406,15 @@ const lazyOptions = {
406
406
 
407
407
  function setupComputedNode(e, t) {
408
408
  e.ft = e;
409
- const n = context?.dt ? context.Ct : context;
409
+ const n = context?.At ? context.Ct : context;
410
410
  if (context) {
411
- const t = context.Fe;
411
+ const t = context.He;
412
412
  if (t === null) {
413
- context.Fe = e;
413
+ context.He = e;
414
414
  } else {
415
415
  e.Ve = t;
416
- t.Tt = e;
417
- context.Fe = e;
416
+ t.Nt = e;
417
+ context.He = e;
418
418
  }
419
419
  }
420
420
  if (n) e.qe = n.qe + 1;
@@ -520,7 +520,7 @@ function read(e) {
520
520
  // than the original node (which stays "pending" while held in a transition).
521
521
  if (latestReadActive) return GlobalQueue.Gt(e);
522
522
  let t = context;
523
- if (t?.dt) t = t.Ct;
523
+ if (t?.At) t = t.Ct;
524
524
  const n = e;
525
525
  const i = e.rt;
526
526
  const l = i || e;
@@ -538,7 +538,7 @@ function read(e) {
538
538
  // A live mark on a read source flows to the reader (probe reads are
539
539
  // excluded: the probe's own collection owns that verdict, and marking
540
540
  // the enclosing memo would make an `isPending` wrapper itself pending).
541
- if (activeAffectsMarks !== 0 && e.P && !pendingCheckActive) (affectsReads ??= []).push(e);
541
+ if (activeAffectsMarks !== 0 && e.M && !pendingCheckActive) (affectsReads ??= []).push(e);
542
542
  }
543
543
  return !t || e.ge === NOT_PENDING ? e.Ue : e.ge;
544
544
  }
@@ -550,7 +550,7 @@ function read(e) {
550
550
  // to re-establish through, so without this a mid-window recompute sheds
551
551
  // pendingness permanently past one derivation level.
552
552
  if (activeAffectsMarks !== 0 && !pendingCheckActive) {
553
- if (e.P) (affectsReads ??= []).push(e);
553
+ if (e.M) (affectsReads ??= []).push(e);
554
554
  if (l.i & STATUS_PENDING) GlobalQueue.I(l, affectsReads ??= []);
555
555
  }
556
556
  if (l.xe) {
@@ -562,7 +562,7 @@ function read(e) {
562
562
  }
563
563
  const i = l.qe;
564
564
  // parent check is shallow, might need to be recursive
565
- if (i >= t.qe && e.He !== t) {
565
+ if (i >= t.qe && e.Fe !== t) {
566
566
  t.qe = i + 1;
567
567
  }
568
568
  }
@@ -611,8 +611,8 @@ function read(e) {
611
611
  if (e.be !== undefined && e.be !== NOT_PENDING) {
612
612
  // An active override means the engine is installed (A17: the override IS
613
613
  // the value for every reader — that check itself stays right here).
614
- if (t && stale && GlobalQueue.gt(e)) return e.Ue;
615
- return e.be;
614
+ if (t && stale && GlobalQueue.Dt(e)) return e.Ue;
615
+ return unwrapOverride(e.be);
616
616
  }
617
617
  // Entanglement gate: a reader recomputing under an optimistic lane that reads
618
618
  // a pending mid-transition write sees the committed value. Projection-store
@@ -621,17 +621,17 @@ function read(e) {
621
621
  // _pendingValue for correct fetching. The sub is recorded for replay at commit
622
622
  // so it re-runs with the new committed view. (Gate details live with the
623
623
  // engine — a non-null lane implies it is installed.)
624
- if (currentOptimisticLane !== null && activeTransition !== null && t !== null && GlobalQueue.Dt(e, l, t)) {
624
+ if (currentOptimisticLane !== null && activeTransition !== null && t !== null && GlobalQueue.gt(e, l, t)) {
625
625
  return e.Ue;
626
626
  }
627
627
  // In optimistic lane context, return _value for optimistic/lane-assigned signals
628
628
  // and for regular signals in stale mode (render effects). Non-stale readers (user
629
629
  // effects) see _pendingValue so that latest() and direct reads stay consistent.
630
630
  // (The lane-context clause lives with the engine.)
631
- const u = !t || currentOptimisticLane !== null && GlobalQueue.kt(e, l, t) || e.ge === NOT_PENDING || stale && e.ve && activeTransition !== e.ve ? e.Ue : e.ge;
631
+ const u = !t || currentOptimisticLane !== null && GlobalQueue.vt(e, l, t) || e.ge === NOT_PENDING || stale && e.ve && activeTransition !== e.ve ? e.Ue : e.ge;
632
632
  // Record that this isPending() probe observed the fresh pending value, so
633
633
  // the probe doesn't pair "pending" with the new value (#2831).
634
- if (pendingCheckActive) GlobalQueue.vt(e, u);
634
+ if (pendingCheckActive) GlobalQueue.kt(e, u);
635
635
  if (!t && l === e && typeof n.xe === "function" && e.U & CONFIG_AUTO_DISPOSE && !(l.i & STATUS_PENDING) && !e.p) {
636
636
  unobserved(e);
637
637
  }
@@ -1,10 +1,10 @@
1
- import { EFFECT_USER, CONFIG_AUTO_DISPOSE, CONFIG_CHILDREN_FORBIDDEN, EFFECT_TRACKED, STATUS_ERROR, STATUS_PENDING, EFFECT_RENDER, REACTIVE_DISPOSED } from "./constants.js";
1
+ import { REACTIVE_DISPOSED, STATUS_ERROR, EFFECT_USER, CONFIG_AUTO_DISPOSE, CONFIG_CHILDREN_FORBIDDEN, EFFECT_TRACKED, STATUS_PENDING, EFFECT_RENDER } from "./constants.js";
2
2
 
3
3
  import { createEffectNode, recompute, computed, staleValues } from "./core.js";
4
4
 
5
5
  import { unwrapStatusError, StatusError } from "./error.js";
6
6
 
7
- import { haltReactivity, GlobalQueue } from "./scheduler.js";
7
+ import { GlobalQueue, haltReactivity } from "./scheduler.js";
8
8
 
9
9
  /**
10
10
  * Effects are the leaf nodes of our reactive graph. When their sources change, they are
@@ -62,12 +62,12 @@ function runEffect(t) {
62
62
  // same flush must not be hijacked by a later-arriving error status.
63
63
  if (t.i & STATUS_ERROR && t.De === EFFECT_USER) {
64
64
  const E = unwrapStatusError(t.k);
65
- t.Nt = t.Ue;
65
+ t.Tt = t.Ue;
66
66
  t.it = false;
67
67
  try {
68
68
  t.St ? t.St(E, () => {
69
- const E = t.At;
70
- t.At = undefined;
69
+ const E = t.dt;
70
+ t.dt = undefined;
71
71
  E?.();
72
72
  }) : console.error(E);
73
73
  } catch (E) {
@@ -78,14 +78,14 @@ function runEffect(t) {
78
78
  }
79
79
  return;
80
80
  }
81
- const E = t.At;
82
- t.At = undefined;
81
+ const E = t.dt;
82
+ t.dt = undefined;
83
83
  try {
84
84
  E?.();
85
- const e = t.It(t.Ue, t.Nt);
85
+ const e = t.It(t.Ue, t.Tt);
86
86
  if (false && e !== undefined && typeof e !== "function") ;
87
87
  // The final cleanup is invoked by disposeChildren at true disposal.
88
- t.At = e;
88
+ t.dt = e;
89
89
  } catch (E) {
90
90
  t.k = new StatusError(t, E);
91
91
  t.i |= STATUS_ERROR;
@@ -94,7 +94,7 @@ function runEffect(t) {
94
94
  throw E;
95
95
  }
96
96
  } finally {
97
- t.Nt = t.Ue;
97
+ t.Tt = t.Ue;
98
98
  t.it = false;
99
99
  }
100
100
  }
@@ -114,16 +114,16 @@ GlobalQueue.ut = runEffect;
114
114
  } finally {}
115
115
  };
116
116
  const e = computed(() => {
117
- const E = e.At;
118
- e.At = undefined;
117
+ const E = e.dt;
118
+ e.dt = undefined;
119
119
  E?.();
120
120
  const R = staleValues(t);
121
- e.At = R;
121
+ e.dt = R;
122
122
  }, {
123
123
  ...E,
124
124
  lazy: true
125
125
  });
126
- e.At = undefined;
126
+ e.dt = undefined;
127
127
  e.U = e.U & ~CONFIG_AUTO_DISPOSE | CONFIG_CHILDREN_FORBIDDEN;
128
128
  e.it = true;
129
129
  e.De = EFFECT_TRACKED;
@@ -1,4 +1,4 @@
1
- import { REACTIVE_RECOMPUTING_DEPS, CONFIG_AUTO_DISPOSE, REACTIVE_ZOMBIE } from "./constants.js";
1
+ import { CONFIG_AUTO_DISPOSE, REACTIVE_ZOMBIE, REACTIVE_RECOMPUTING_DEPS } from "./constants.js";
2
2
 
3
3
  import { deleteFromHeap, queueFor } from "./heap.js";
4
4
 
@@ -1,4 +1,4 @@
1
- import { REACTIVE_IN_HEAP, REACTIVE_RECOMPUTING_DEPS, REACTIVE_MANUAL_WRITE, REACTIVE_CHECK, REACTIVE_DIRTY, REACTIVE_IN_HEAP_HEIGHT, REACTIVE_ZOMBIE, EFFECT_TRACKED, EFFECT_USER } from "./constants.js";
1
+ import { REACTIVE_IN_HEAP, EFFECT_TRACKED, EFFECT_USER, REACTIVE_IN_HEAP_HEIGHT, REACTIVE_RECOMPUTING_DEPS, REACTIVE_MANUAL_WRITE, REACTIVE_ZOMBIE, REACTIVE_CHECK, REACTIVE_DIRTY } from "./constants.js";
2
2
 
3
3
  import { zombieQueue, dirtyQueue } from "./scheduler.js";
4
4
 
@@ -25,7 +25,7 @@ import { zombieQueue, dirtyQueue } from "./scheduler.js";
25
25
  }
26
26
 
27
27
  function actualInsertIntoHeap(e, E) {
28
- const t = (e.He?.dt ? e.He.Ct?.qe : e.He?.qe) ?? -1;
28
+ const t = (e.Fe?.At ? e.Fe.Ct?.qe : e.Fe?.qe) ?? -1;
29
29
  if (t >= e.qe) e.qe = t + 1;
30
30
  const n = e.qe;
31
31
  const I = E.eE[n];
@@ -1,6 +1,6 @@
1
1
  import { NOT_PENDING } from "./constants.js";
2
2
 
3
- import { activeTransition } from "./scheduler.js";
3
+ import { currentTransition, activeTransition } from "./scheduler.js";
4
4
 
5
5
  // Map from optimistic signal to its lane (reused for multiple writes to same signal)
6
6
  const signalLanes = new WeakMap;
@@ -19,14 +19,14 @@ const activeLanes = new Set;
19
19
  // Detect parent lane: _parentSource chains from pendingSignal → pendingValueComputed → original.
20
20
  // The child lane should not merge with the parent lane.
21
21
  const i = n.en;
22
- const a = i?.Je ? findLane(i.Je) : null;
22
+ const r = i?.Je ? findLane(i.Je) : null;
23
23
  e = {
24
- an: n,
24
+ rn: n,
25
25
  Pe: new Set,
26
26
  tn: [ [], [] ],
27
- rn: null,
27
+ an: null,
28
28
  ve: activeTransition,
29
- sn: a
29
+ sn: r
30
30
  };
31
31
  signalLanes.set(n, e);
32
32
  activeLanes.add(e);
@@ -45,16 +45,16 @@ function adoptCompanionLane(n, e) {
45
45
  if (!n) return;
46
46
  const i = signalLanes.get(n);
47
47
  if (!i) return;
48
- const a = findLane(i);
48
+ const r = findLane(i);
49
49
  // Only the companion's own unmerged root is safely re-parentable: a root
50
50
  // that absorbed other lanes carries work that is not a child of this owner.
51
- if (a !== e && a.an === n && !a.sn) a.sn = e;
51
+ if (r !== e && r.rn === n && !r.sn) r.sn = e;
52
52
  }
53
53
 
54
54
  /**
55
55
  * Union-find: find the root lane.
56
56
  */ function findLane(n) {
57
- while (n.rn) n = n.rn;
57
+ while (n.an) n = n.an;
58
58
  return n;
59
59
  }
60
60
 
@@ -64,7 +64,7 @@ function adoptCompanionLane(n, e) {
64
64
  n = findLane(n);
65
65
  e = findLane(e);
66
66
  if (n === e) return n;
67
- e.rn = n;
67
+ e.an = n;
68
68
  // Move (not copy) the merged lane's work: after the merge all routing goes
69
69
  // through findLane() to the root, so anything left behind here is dead —
70
70
  // and anything *added* here later is a routing bug (INV-5).
@@ -89,6 +89,16 @@ function adoptCompanionLane(n, e) {
89
89
  }
90
90
 
91
91
  function resolveTransition(n) {
92
+ // An active override answers with its owner, not its lane: lanes are
93
+ // scheduling affinity and a shared subscriber merges them across
94
+ // transactions (#2912) — the merged root's _transition would hand this
95
+ // node's override to whichever action wrote last through the shared
96
+ // reader. Chase merge chains; a dead owner settled through another path.
97
+ if (hasActiveOverride(n) && n.fn) {
98
+ const e = n.fn = currentTransition(n.fn);
99
+ if (e.cn !== true) return e;
100
+ n.fn = null;
101
+ }
92
102
  return resolveLane(n)?.ve ?? n.ve;
93
103
  }
94
104
 
@@ -103,16 +113,16 @@ function resolveTransition(n) {
103
113
  * a different active lane), merge unless the node has an active override.
104
114
  */ function assignOrMergeLane(n, e) {
105
115
  const i = findLane(e);
106
- const a = n.Je;
107
- if (a) {
116
+ const r = n.Je;
117
+ if (r) {
108
118
  // If the subscriber's lane was merged into another lane, it's stale —
109
119
  // replace it with the new source lane instead of following the merge chain
110
120
  // (which would incorrectly merge the new lane into the old group)
111
- if (a.rn) {
121
+ if (r.an) {
112
122
  n.Je = e;
113
123
  return;
114
124
  }
115
- const t = findLane(a);
125
+ const t = findLane(r);
116
126
  if (activeLanes.has(t)) {
117
127
  if (t !== i && !hasActiveOverride(n)) {
118
128
  // Parent-child lanes stay independent so isPending resolves without