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

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/node.cjs CHANGED
@@ -675,8 +675,8 @@ class GlobalQueue extends Queue {
675
675
  static Te=null;
676
676
  static Ne=null;
677
677
  static Ae=null;
678
- static he=null;
679
678
  static Oe=null;
679
+ static he=null;
680
680
  static Ie=null;
681
681
  static Re=null;
682
682
  static Ce=null;
@@ -691,8 +691,8 @@ class GlobalQueue extends Queue {
691
691
  // entry, or a non-null `currentOptimisticLane`, so `!` invocations are safe
692
692
  // once the gate holds.
693
693
  static ye=null;
694
- static be=null;
695
694
  static ve=null;
695
+ static be=null;
696
696
  static Pe=null;
697
697
  static we=null;
698
698
  static De=null;
@@ -1007,7 +1007,7 @@ function finalizePureQueue(e = null, t = false) {
1007
1007
  const t = e ?? globalQueue.L;
1008
1008
  // Optimistic reversion: a non-empty batch means _optimisticWrite ran,
1009
1009
  // which installed the engine's hooks.
1010
- if (t.H.length) GlobalQueue.be(t.H);
1010
+ if (t.H.length) GlobalQueue.ve(t.H);
1011
1011
  // Replay entanglement: subs recorded by the read-time gate get rescheduled
1012
1012
  // so they re-run with the now-committed values visible. The ambient batch
1013
1013
  // replays too — laneReadsCommitted records readers whose committed-view
@@ -1146,7 +1146,7 @@ function transitionComplete(e) {
1146
1146
  // Override blockage lives with the engine (absent hook = "no optimistic
1147
1147
  // blockage"); the hook's loops over _optimisticNodes/_optimisticStores are
1148
1148
  // no-ops when the transition holds neither, so no pre-check is needed.
1149
- if (t && GlobalQueue.ve?.(e)) t = false;
1149
+ if (t && GlobalQueue.be?.(e)) t = false;
1150
1150
  t && (e.R = true);
1151
1151
  return t;
1152
1152
  }
@@ -1353,7 +1353,7 @@ function disposeChildren(e, t = false, n) {
1353
1353
  const t = e;
1354
1354
  if (t.i?.A || t.i?.O) GlobalQueue.Ne(t);
1355
1355
  }
1356
- if (t && e.Ke && e.i !== null) e.i.ht = null;
1356
+ if (t && e.Ke && e.i !== null) e.i.Ot = null;
1357
1357
  let r = n ? e.i?.Je ?? null : e.Nt;
1358
1358
  while (r) {
1359
1359
  const e = r.At;
@@ -1382,7 +1382,7 @@ function disposeChildren(e, t = false, n) {
1382
1382
  if (e.i !== null) e.i.Je = null;
1383
1383
  } else {
1384
1384
  e.Nt = null;
1385
- e.Ot = 0;
1385
+ e.ht = 0;
1386
1386
  }
1387
1387
  // O(1) splice out of parent's chain on individual dispose. Skipped during
1388
1388
  // batch dispose (parent already disposed) and zombie disposal (node sits on
@@ -1424,7 +1424,7 @@ function runDisposal(e, t) {
1424
1424
  function childId(e, t) {
1425
1425
  let n = e;
1426
1426
  while (n.P & CONFIG_TRANSPARENT && n.ie) n = n.ie;
1427
- if (n.id != null) return formatId(n.id, t ? n.Ot++ : n.Ot);
1427
+ if (n.id != null) return formatId(n.id, t ? n.ht++ : n.ht);
1428
1428
  throw new Error("");
1429
1429
  }
1430
1430
 
@@ -1553,7 +1553,7 @@ function disposeRootSelf(e = true) {
1553
1553
  Ct: null,
1554
1554
  ut: t?.ut ?? globalQueue,
1555
1555
  gt: t?.gt || defaultContext,
1556
- Ot: 0,
1556
+ ht: 0,
1557
1557
  i: null,
1558
1558
  ie: t,
1559
1559
  dispose: disposeRootSelf
@@ -1605,7 +1605,7 @@ function unlinkSubs(e) {
1605
1605
  const n = e.rt;
1606
1606
  const i = e.We;
1607
1607
  const r = e.yt;
1608
- if (i !== null) i.yt = r; else t.bt = r;
1608
+ if (i !== null) i.yt = r; else t.vt = r;
1609
1609
  if (r !== null) r.We = i; else {
1610
1610
  t.M = i;
1611
1611
  if (i === null) {
@@ -1663,7 +1663,7 @@ function link(e, t, n = false) {
1663
1663
  // read order within the computation.
1664
1664
  const i = t.$e;
1665
1665
  if (i !== null && i.ot === e) {
1666
- i.vt &&= n;
1666
+ i.bt &&= n;
1667
1667
  return;
1668
1668
  }
1669
1669
  let r = null;
@@ -1674,7 +1674,7 @@ function link(e, t, n = false) {
1674
1674
  r.Me = t.qe;
1675
1675
  t.$e = r;
1676
1676
  // First touch of this pass: the previous pass's label is stale.
1677
- r.vt = n;
1677
+ r.bt = n;
1678
1678
  return;
1679
1679
  }
1680
1680
  }
@@ -1683,21 +1683,21 @@ function link(e, t, n = false) {
1683
1683
  // [deps.._depsTail] prefix — the O(1) equivalent of scanning the dep list
1684
1684
  // (the old alien-signals `isValidLink` walk, O(n²) when a computation
1685
1685
  // re-reads earlier deps non-consecutively, e.g. store leaf reads).
1686
- const s = e.bt;
1686
+ const s = e.vt;
1687
1687
  if (s !== null && s.je === t && (!o || s.Me === t.qe)) {
1688
1688
  // Gen-matched during a recompute = repeat touch this pass (AND); outside
1689
1689
  // a recompute there is no pass boundary, so the latest read labels it.
1690
- if (o) s.vt &&= n; else s.vt = n;
1690
+ if (o) s.bt &&= n; else s.bt = n;
1691
1691
  return;
1692
1692
  }
1693
- const u = t.$e = e.bt = {
1693
+ const u = t.$e = e.vt = {
1694
1694
  ot: e,
1695
1695
  je: t,
1696
1696
  rt: r,
1697
1697
  yt: s,
1698
1698
  We: null,
1699
1699
  Me: t.qe,
1700
- vt: n
1700
+ bt: n
1701
1701
  };
1702
1702
  if (i !== null) i.rt = u; else t.it = u;
1703
1703
  if (s !== null) s.We = u; else e.M = u;
@@ -1886,12 +1886,12 @@ function handleAsync(e, t, n) {
1886
1886
  });
1887
1887
  }
1888
1888
  if (!r && !i) {
1889
- if (e.i !== null) e.i.ht = null;
1889
+ if (e.i !== null) e.i.Ot = null;
1890
1890
  // A sync landing is the first real answer for a loadingValue node.
1891
1891
  e.ze = false;
1892
1892
  return t;
1893
1893
  }
1894
- ext(e).ht = t;
1894
+ ext(e).Ot = t;
1895
1895
  let o;
1896
1896
  // Settle-time transition re-entry. The loading rail is invisible to
1897
1897
  // transactions (#2933): a boundary-caught first load never registers as an
@@ -1914,7 +1914,7 @@ function handleAsync(e, t, n) {
1914
1914
  globalQueue.initTransition(t);
1915
1915
  };
1916
1916
  const handleError = n => {
1917
- if (e.i?.ht !== t) return;
1917
+ if (e.i?.Ot !== t) return;
1918
1918
  // NotReadyError from rejected promises should be treated as pending, not error
1919
1919
  let i = n instanceof NotReadyError;
1920
1920
  if (i && e.ze) {
@@ -1922,7 +1922,7 @@ function handleAsync(e, t, n) {
1922
1922
  // serving commit #0 — same parking as recompute's catch for sync
1923
1923
  // dependency throws. The dead flight is released so the clock-gated
1924
1924
  // error-retry pull (updateIfNecessary) can also re-ask.
1925
- if (e.i !== null) e.i.ht = null;
1925
+ if (e.i !== null) e.i.Ot = null;
1926
1926
  parkLoadingWindow(e, n);
1927
1927
  e.B = clock;
1928
1928
  return;
@@ -1936,7 +1936,7 @@ function handleAsync(e, t, n) {
1936
1936
  if (!i) releaseSettledDependents(e);
1937
1937
  };
1938
1938
  const asyncWrite = (i, r) => {
1939
- if (e.i?.ht !== t) return;
1939
+ if (e.i?.Ot !== t) return;
1940
1940
  // If the node was dirtied by a newer write (optimistic override or regular),
1941
1941
  // skip this stale async result — the upcoming flush will recompute the node
1942
1942
  // with the new value, creating a fresh Promise that supersedes this one.
@@ -2085,7 +2085,7 @@ function handleAsync(e, t, n) {
2085
2085
  n = i;
2086
2086
  f = true;
2087
2087
  if (i.done) u = true;
2088
- } else if (e.i?.ht !== t) {
2088
+ } else if (e.i?.Ot !== t) {
2089
2089
  return;
2090
2090
  } else if (!i.done) {
2091
2091
  s = true;
@@ -2105,7 +2105,7 @@ function handleAsync(e, t, n) {
2105
2105
  if (a && l) {
2106
2106
  i = n;
2107
2107
  c = true;
2108
- } else if (e.i?.ht === t) {
2108
+ } else if (e.i?.Ot === t) {
2109
2109
  u = true;
2110
2110
  handleError(n);
2111
2111
  settleAutodispose();
@@ -2171,7 +2171,7 @@ function handleAsync(e, t, n) {
2171
2171
  if (s) {
2172
2172
  o = i;
2173
2173
  n = true;
2174
- } else if (e.i?.ht === t && !(e.U & REACTIVE_DISPOSED) && flattenIfIterable(i, registerDeferredClose)) ; else {
2174
+ } else if (e.i?.Ot === t && !(e.U & REACTIVE_DISPOSED) && flattenIfIterable(i, registerDeferredClose)) ; else {
2175
2175
  asyncWrite(i);
2176
2176
  settleAutodispose();
2177
2177
  }
@@ -2284,7 +2284,7 @@ function notifyStatus(e, t, n, i, r) {
2284
2284
  // not carry a real (non-NotReadyError) error — the synchronous `isPending`
2285
2285
  // read swallows those, and the async path must match. Re-run the observer
2286
2286
  // so `isPending` re-evaluates (to not-pending) instead of forwarding.
2287
- if (i.vt && t !== STATUS_PENDING && !(n instanceof NotReadyError)) {
2287
+ if (i.bt && t !== STATUS_PENDING && !(n instanceof NotReadyError)) {
2288
2288
  enqueueSub(e);
2289
2289
  schedule();
2290
2290
  return;
@@ -2393,7 +2393,7 @@ function recompute(e, t = false) {
2393
2393
  if (!t) {
2394
2394
  if (e.T && (!n || activeTransition) && activeTransition !== e.T) globalQueue.initTransition(e.T);
2395
2395
  deleteFromHeap(e, queueFor(e));
2396
- if (e.i !== null) e.i.ht = null;
2396
+ if (e.i !== null) e.i.Ot = null;
2397
2397
  // Tracked effects run after finalizePureQueue, so dispose immediately instead of deferring
2398
2398
  if (e.T || n === EFFECT_TRACKED) disposeChildren(e); else if (e.Nt !== null || e.Ct !== null) {
2399
2399
  markDisposal(e);
@@ -2402,7 +2402,7 @@ function recompute(e, t = false) {
2402
2402
  t.Je = e.Nt;
2403
2403
  e.Ct = null;
2404
2404
  e.Nt = null;
2405
- e.Ot = 0;
2405
+ e.ht = 0;
2406
2406
  } else ;
2407
2407
  }
2408
2408
  let i = !!(e.U & REACTIVE_OPTIMISTIC_DIRTY);
@@ -2466,7 +2466,7 @@ function recompute(e, t = false) {
2466
2466
  try {
2467
2467
  if (!false && e.P & CONFIG_SYNC) {
2468
2468
  c = e.Ke(c);
2469
- if (e.i !== null) e.i.ht = null;
2469
+ if (e.i !== null) e.i.Ot = null;
2470
2470
  e.ze = false;
2471
2471
  } else {
2472
2472
  // Snapshot `_inFlight` so we can detect whether `_fn` self-registered an async
@@ -2474,13 +2474,13 @@ function recompute(e, t = false) {
2474
2474
  // with a setter callback). In that case, the outer `handleAsync` call below would
2475
2475
  // clobber the fresh subscription, so we skip it and let the internally-registered
2476
2476
  // iteration drive updates.
2477
- const t = e.i?.ht;
2477
+ const t = e.i?.Ot;
2478
2478
  const n = e.Ke(c);
2479
2479
  const i = typeof n === "object" && n !== null;
2480
- const r = e.i?.ht !== t;
2480
+ const r = e.i?.Ot !== t;
2481
2481
  c = r || !i ? n : handleAsync(e, n);
2482
2482
  if (!r && !i) {
2483
- if (e.i !== null) e.i.ht = null;
2483
+ if (e.i !== null) e.i.Ot = null;
2484
2484
  // A sync (non-object) return is the first real answer; async-shaped
2485
2485
  // results clear inside handleAsync at their own landing points, and a
2486
2486
  // self-registered flight (inFlightChanged — projections) clears when
@@ -2646,7 +2646,7 @@ function updateIfNecessary(e) {
2646
2646
  }
2647
2647
  }
2648
2648
  }
2649
- if (e.U & (REACTIVE_DIRTY | REACTIVE_OPTIMISTIC_DIRTY) || e.i?.Le && e.B < clock && !e.i?.ht) {
2649
+ if (e.U & (REACTIVE_DIRTY | REACTIVE_OPTIMISTIC_DIRTY) || e.i?.Le && e.B < clock && !e.i?.Ot) {
2650
2650
  recompute(e);
2651
2651
  }
2652
2652
  e.U = e.U & (REACTIVE_SNAPSHOT_STALE | REACTIVE_IN_HEAP | REACTIVE_IN_HEAP_HEIGHT);
@@ -2665,7 +2665,7 @@ function computed(e, t) {
2665
2665
  Ct: null,
2666
2666
  ut: context?.ut ?? globalQueue,
2667
2667
  gt: context?.gt ?? defaultContext,
2668
- Ot: 0,
2668
+ ht: 0,
2669
2669
  Ke: e,
2670
2670
  Be: i ? t.loadingValue : undefined,
2671
2671
  ft: 0,
@@ -2675,7 +2675,7 @@ function computed(e, t) {
2675
2675
  $e: null,
2676
2676
  qe: 0,
2677
2677
  M: null,
2678
- bt: null,
2678
+ vt: null,
2679
2679
  ie: context,
2680
2680
  At: null,
2681
2681
  It: null,
@@ -2711,7 +2711,7 @@ function computed(e, t) {
2711
2711
  O: undefined,
2712
2712
  t: undefined,
2713
2713
  $: 0,
2714
- ht: null,
2714
+ Ot: null,
2715
2715
  Le: undefined,
2716
2716
  Pt: undefined,
2717
2717
  nt: undefined,
@@ -2740,7 +2740,7 @@ function computed(e, t) {
2740
2740
  Ct: null,
2741
2741
  ut: context?.ut ?? globalQueue,
2742
2742
  gt: context?.gt ?? defaultContext,
2743
- Ot: 0,
2743
+ ht: 0,
2744
2744
  Ke: e,
2745
2745
  Be: undefined,
2746
2746
  ft: 0,
@@ -2750,7 +2750,7 @@ function computed(e, t) {
2750
2750
  $e: null,
2751
2751
  qe: 0,
2752
2752
  M: null,
2753
- bt: null,
2753
+ vt: null,
2754
2754
  ie: context,
2755
2755
  At: null,
2756
2756
  It: null,
@@ -2812,7 +2812,7 @@ function signal(e, t, n = null) {
2812
2812
  P: (t?.ownedWrite ? CONFIG_OWNED_WRITE : 0) | (t?.Ft ? CONFIG_NO_SNAPSHOT : 0),
2813
2813
  Be: e,
2814
2814
  M: null,
2815
- bt: null,
2815
+ vt: null,
2816
2816
  B: clock,
2817
2817
  st: n,
2818
2818
  Tt: n?.i?._t || null,
@@ -2951,7 +2951,7 @@ function read(e) {
2951
2951
  // Probe mode is suspended while preparing the node so nested reads during a
2952
2952
  // recompute don't collect into the probe.
2953
2953
  if (pendingCheckActive) {
2954
- GlobalQueue.he(e, t, r, i);
2954
+ GlobalQueue.Oe(e, t, r, i);
2955
2955
  } else if (typeof n.Ke === "function") {
2956
2956
  prepareComputed(e, false);
2957
2957
  }
@@ -3048,7 +3048,7 @@ function read(e) {
3048
3048
  const o = !t || currentOptimisticLane !== null && GlobalQueue.me(e, r, t) || e.q === NOT_PENDING || t.P & CONFIG_CHILDREN_FORBIDDEN || stale && e.T && activeTransition !== e.T ? e.Be : e.q;
3049
3049
  // Record that this isPending() probe observed the fresh pending value, so
3050
3050
  // the probe doesn't pair "pending" with the new value (#2831).
3051
- if (pendingCheckActive) GlobalQueue.Oe(e, o);
3051
+ if (pendingCheckActive) GlobalQueue.he(e, o);
3052
3052
  if (!t && r === e && typeof n.Ke === "function" && e.P & CONFIG_AUTO_DISPOSE && !(r.Xe & STATUS_PENDING) && !e.M) {
3053
3053
  unobserved(e);
3054
3054
  }
@@ -3384,7 +3384,14 @@ function isUndefined(e) {
3384
3384
  const n = e.i?.C !== NOT_PENDING;
3385
3385
  const i = n ? unwrapOverride(e.i?.C) : e.Be;
3386
3386
  if (typeof t === "function") t = t(i);
3387
- const r = !!(e.Xe & STATUS_UNINITIALIZED) || !e.wt || !e.wt(i, t);
3387
+ const r = !!(e.Xe & STATUS_UNINITIALIZED) ||
3388
+ // A dirty node's _value is stale (its queued recompute hasn't run — e.g.
3389
+ // a latest() shadow marked by the previous landing's companion snap), so
3390
+ // equality against it must not swallow the write. Without this, a sync
3391
+ // push returning the shadow to that stale value was dropped, the snap
3392
+ // recompute then committed the parent's old value, and the banner showed
3393
+ // the previous transition's target (#3041 follow-up).
3394
+ !!((e.U ?? 0) & (REACTIVE_DIRTY | REACTIVE_CHECK)) || !e.wt || !e.wt(i, t);
3388
3395
  if (!r) {
3389
3396
  // Same-value write with an active override still entangles the current
3390
3397
  // action's transition — the hold must outlast all overlapping actions.
@@ -3523,16 +3530,31 @@ function cleanupCompletedLanes(e) {
3523
3530
  * read()'s value selection under a lane: return the committed `_value` for
3524
3531
  * optimistic/lane-assigned signals, stale-mode reads, and pending owners.
3525
3532
  */ function laneReadsCommitted(e, t, n) {
3526
- if (e.i?.C !== undefined || !!e.i?.o || !!(t.Xe & STATUS_PENDING)) return true;
3533
+ if (e.i?.C !== undefined || !!e.i?.o || !!(t.Xe & STATUS_PENDING)) {
3534
+ // The committed view hides a staged in-flight value that will promote
3535
+ // silently (commitPendingNode never re-notifies). gatedRead records plain
3536
+ // signals for replay at commit; async memos are excluded from it by the
3537
+ // `_fn` check and reach here instead — a lane-assigned source whose async
3538
+ // already settled (laneAsyncSettled keeps _optimisticLane) served its
3539
+ // committed value to a reader that never re-ran after the landing, so a
3540
+ // pending-gated branch stayed one value behind permanently (#3041
3541
+ // follow-up). Record the reader under the same replay contract.
3542
+ if (e.q !== NOT_PENDING) (activeTransition ?? globalQueue.L).te.add(n);
3543
+ return true;
3544
+ }
3527
3545
  if (t === e && stale && n.i?.t !== e) {
3528
- // The committed view can hide a same-tick ambient write (a lane member —
3529
- // even just an isPending companion flip — puts the reader "under a lane"
3530
- // against unrelated plain writes). With no transaction the write commits
3531
- // at THIS flush's end with no re-delivery, so record the reader for
3532
- // replay at commit the same contract gatedRead provides when a
3533
- // transaction is active (#2963). If a transaction forms mid-flush,
3534
- // initTransition carries the recording over to it.
3535
- if (e.q !== NOT_PENDING && activeTransition === null) globalQueue.L.te.add(n);
3546
+ // The committed view can hide a staged write (a lane member — even just
3547
+ // an isPending companion flip — puts the reader "under a lane"). The
3548
+ // staged value commits with no re-delivery (commitPendingNode never
3549
+ // re-notifies), so record the reader for replay at commit — the same
3550
+ // contract gatedRead provides (#2963). gatedRead itself only covers
3551
+ // signal reads where the reading computed differs from the source; the
3552
+ // owner === el memo/self read lands here instead. With a transaction
3553
+ // active the staged value promotes silently at ITS landing, so record
3554
+ // into the transaction (#3041 follow-up: a pending-gated branch that
3555
+ // first read its async source during the landing flush stayed one value
3556
+ // behind permanently); with none, into the ambient batch.
3557
+ if (e.q !== NOT_PENDING) (activeTransition ?? globalQueue.L).te.add(n);
3536
3558
  return true;
3537
3559
  }
3538
3560
  return false;
@@ -3606,8 +3628,8 @@ function trackOptimisticStore(e) {
3606
3628
  */ function installOptimisticEngine() {
3607
3629
  if (GlobalQueue.ye !== null) return;
3608
3630
  GlobalQueue.ye = optimisticWrite;
3609
- GlobalQueue.be = resolveOptimisticNodes;
3610
- GlobalQueue.ve = transitionBlocked;
3631
+ GlobalQueue.ve = resolveOptimisticNodes;
3632
+ GlobalQueue.be = transitionBlocked;
3611
3633
  GlobalQueue.Pe = cleanupCompletedLanes;
3612
3634
  GlobalQueue.we = runLaneEffects;
3613
3635
  GlobalQueue.De = gatedRead;
@@ -3718,7 +3740,7 @@ function collectPendingSources(e) {
3718
3740
  const r = i.U & REACTIVE_RECOMPUTING_DEPS ? i.$e : undefined;
3719
3741
  if (r !== null) {
3720
3742
  for (let e = i.it ?? null; e !== null; e = e.rt) {
3721
- if (!e.vt && markWalk(e.ot, t)) return true;
3743
+ if (!e.bt && markWalk(e.ot, t)) return true;
3722
3744
  if (e === r) break;
3723
3745
  }
3724
3746
  }
@@ -3762,7 +3784,7 @@ function computePendingState(e) {
3762
3784
  return newQuestionInFlight(n);
3763
3785
  }
3764
3786
  if (n && e.q !== NOT_PENDING && !hasActiveOverride$1(e)) {
3765
- return !!(n.U & REACTIVE_MANUAL_WRITE) || !n.i?.ht && !(n.Xe & STATUS_PENDING) || !!(n.Xe & STATUS_PENDING) && quietPending(n);
3787
+ return !!(n.U & REACTIVE_MANUAL_WRITE) || !n.i?.Ot && !(n.Xe & STATUS_PENDING) || !!(n.Xe & STATUS_PENDING) && quietPending(n);
3766
3788
  }
3767
3789
  // `!comp._loading`: a hold created while the loading window is still open is
3768
3790
  // the window's own landing in flight to its commit — verdict-quiet like the
@@ -3876,6 +3898,13 @@ function snapCompanionsToState(e) {
3876
3898
 
3877
3899
  function getLatestValueComputed(e) {
3878
3900
  let t = e.i?.O;
3901
+ // A shadow disposed while unobserved (its gated reader unmounted at a
3902
+ // landing) is a corpse: sync writes into it equality-swallow against its
3903
+ // frozen _value, and a later read revives it via recompute — clearing
3904
+ // DISPOSED and re-deriving from the committed view, so the banner showed
3905
+ // the previous transition's target (#3041 follow-up). Treat it as absent;
3906
+ // recreation backfills from the in-flight write below.
3907
+ if (t && t.U & REACTIVE_DISPOSED) t = undefined;
3879
3908
  if (!t) {
3880
3909
  const n = latestReadActive;
3881
3910
  setLatestReadActive(false);
@@ -4064,9 +4093,9 @@ GlobalQueue.Ne = snapCompanionsToState;
4064
4093
 
4065
4094
  GlobalQueue.Ae = latestRead;
4066
4095
 
4067
- GlobalQueue.he = pendingCheckRead;
4096
+ GlobalQueue.Oe = pendingCheckRead;
4068
4097
 
4069
- GlobalQueue.Oe = recordFreshRead;
4098
+ GlobalQueue.he = recordFreshRead;
4070
4099
 
4071
4100
  GlobalQueue.Ie = applyReask;
4072
4101
 
@@ -6972,68 +7001,130 @@ function descend(e, t, n, i, r = false) {
6972
7001
  * loading windows, handleAsync landings, commit-through-setter) on next
6973
7002
  * primitives; the generic draft write-traps are reused from the legacy
6974
7003
  * module unchanged.
6975
- */ function createWriteTraps(e, t) {
6976
- // Save/restore, never hard-reset: the draft can be driven from inside an
6977
- // enclosing authoritative-write scope (next-store optimistic derives), and
6978
- // a hard `false` would clobber it mid-derive.
6979
- const n = {
6980
- get(e, t) {
7004
+ */
7005
+ /**
7006
+ * Wrap a store proxy as a projection DRAFT: every operation carries the write
7007
+ * override (the derive is the author — its ops must not hit the §6c firewall
7008
+ * gate, even in a continuation after an `await`/`yield` where the sync write
7009
+ * scope has closed).
7010
+ *
7011
+ * FAKE TARGET, not the store proxy itself (#3060): after a proxy trap
7012
+ * returns, the engine runs spec invariant validation against the proxy's
7013
+ * TARGET — [[OwnPropertyKeys]] after ownKeys, [[GetOwnProperty]] after
7014
+ * set/getOwnPropertyDescriptor/defineProperty. With the store proxy as
7015
+ * target those checks re-enter the store's traps OUTSIDE the override
7016
+ * bracket (the trap's finally has already run), so `Object.keys(state)` in
7017
+ * a derive continuation fired the firewall gate and re-threw the
7018
+ * projection's own pending NotReadyError into the derive. A dummy of
7019
+ * matching kind (array/object, same trick as the store's own TargetShape)
7020
+ * keeps invariant validation away from the store entirely; the traps
7021
+ * forward to the closed-over inner proxy inside the bracket.
7022
+ *
7023
+ * Save/restore projectionWriteActive, never hard-reset: the draft can be
7024
+ * driven from inside an enclosing authoritative-write scope (next-store
7025
+ * optimistic derives), and a hard `false` would clobber it mid-derive.
7026
+ */ function wrapDraft(e, t, n) {
7027
+ const i = {
7028
+ get(i, r) {
7029
+ let o;
7030
+ const s = projectionWriteActive;
7031
+ setWriteOverride(true);
7032
+ setProjectionWriteActive(true);
7033
+ try {
7034
+ o = e[r];
7035
+ } finally {
7036
+ setWriteOverride(false);
7037
+ setProjectionWriteActive(s);
7038
+ }
7039
+ if (r === $TARGET) return o;
7040
+ return typeof o === "object" && o !== null ? wrapDraft(o, t, n) : o;
7041
+ },
7042
+ has(t, n) {
6981
7043
  let i;
6982
7044
  const r = projectionWriteActive;
6983
7045
  setWriteOverride(true);
6984
7046
  setProjectionWriteActive(true);
6985
7047
  try {
6986
- i = e[t];
7048
+ i = n in e;
6987
7049
  } finally {
6988
7050
  setWriteOverride(false);
6989
7051
  setProjectionWriteActive(r);
6990
7052
  }
6991
- if (t === $TARGET) return i;
6992
- return typeof i === "object" && i !== null ? new Proxy(i, n) : i;
7053
+ return i;
6993
7054
  },
6994
- has(e, t) {
6995
- let n;
6996
- const i = projectionWriteActive;
7055
+ set(i, r, o) {
7056
+ if (t && !t()) return true;
7057
+ const s = projectionWriteActive;
6997
7058
  setWriteOverride(true);
6998
7059
  setProjectionWriteActive(true);
6999
7060
  try {
7000
- n = t in e;
7061
+ e[r] = o;
7062
+ n?.();
7001
7063
  } finally {
7002
7064
  setWriteOverride(false);
7003
- setProjectionWriteActive(i);
7065
+ setProjectionWriteActive(s);
7004
7066
  }
7005
- return n;
7067
+ return true;
7006
7068
  },
7007
- set(n, i, r) {
7008
- if (e && !e()) return true;
7069
+ deleteProperty(i, r) {
7070
+ if (t && !t()) return true;
7009
7071
  const o = projectionWriteActive;
7010
7072
  setWriteOverride(true);
7011
7073
  setProjectionWriteActive(true);
7012
7074
  try {
7013
- n[i] = r;
7014
- t?.();
7075
+ delete e[r];
7076
+ n?.();
7015
7077
  } finally {
7016
7078
  setWriteOverride(false);
7017
7079
  setProjectionWriteActive(o);
7018
7080
  }
7019
7081
  return true;
7020
7082
  },
7021
- deleteProperty(n, i) {
7022
- if (e && !e()) return true;
7083
+ ownKeys() {
7084
+ const t = projectionWriteActive;
7085
+ setWriteOverride(true);
7086
+ setProjectionWriteActive(true);
7087
+ try {
7088
+ return Reflect.ownKeys(e);
7089
+ } finally {
7090
+ setWriteOverride(false);
7091
+ setProjectionWriteActive(t);
7092
+ }
7093
+ },
7094
+ getOwnPropertyDescriptor(t, n) {
7095
+ let i;
7023
7096
  const r = projectionWriteActive;
7024
7097
  setWriteOverride(true);
7025
7098
  setProjectionWriteActive(true);
7026
7099
  try {
7027
- delete n[i];
7028
- t?.();
7100
+ i = Reflect.getOwnPropertyDescriptor(e, n);
7029
7101
  } finally {
7030
7102
  setWriteOverride(false);
7031
7103
  setProjectionWriteActive(r);
7032
7104
  }
7105
+ // The dummy target doesn't hold the key, so a non-configurable report
7106
+ // would violate the proxy invariant. Store descriptors are already
7107
+ // normalized configurable; enforce it for raw leaves too.
7108
+ if (i) i.configurable = true;
7109
+ return i;
7110
+ },
7111
+ defineProperty(i, r, o) {
7112
+ if (t && !t()) return true;
7113
+ const s = projectionWriteActive;
7114
+ setWriteOverride(true);
7115
+ setProjectionWriteActive(true);
7116
+ try {
7117
+ Reflect.defineProperty(e, r, o);
7118
+ n?.();
7119
+ } finally {
7120
+ setWriteOverride(false);
7121
+ setProjectionWriteActive(s);
7122
+ }
7033
7123
  return true;
7034
7124
  }
7035
7125
  };
7036
- return n;
7126
+ // Matching-kind dummy so Array.isArray(draft) answers like the store.
7127
+ return new Proxy(Array.isArray(e) ? [] : {}, i);
7037
7128
  }
7038
7129
 
7039
7130
  function createProjectionNextInternal(e, t, n) {
@@ -7089,7 +7180,7 @@ function runProjectionComputedNext(e, t, n, i, r) {
7089
7180
  // seed so draft writes cannot tear through to readers (#2988). Every commit
7090
7181
  // point reconciles the shadow through the normal commit path.
7091
7182
  const l = o.ze ? JSON.parse(JSON.stringify(e[$TARGET][STORE_VALUE])) : null;
7092
- const f = new Proxy(e, createWriteTraps(() => !s || o.i?.ht === u, r));
7183
+ const f = wrapDraft(e, () => !s || o.i?.Ot === u, r);
7093
7184
  storeSetterNext(f, r => {
7094
7185
  u = t(l ?? r);
7095
7186
  s = true;
@@ -7144,8 +7235,8 @@ function installNextBlockedHalf() {
7144
7235
  e.clear();
7145
7236
  };
7146
7237
  }
7147
- const e = GlobalQueue.ve;
7148
- GlobalQueue.ve = t => {
7238
+ const e = GlobalQueue.be;
7239
+ GlobalQueue.be = t => {
7149
7240
  for (const e of t.j) {
7150
7241
  const t = e?.[$TARGET];
7151
7242
  const n = t?.fam?.node;
@@ -8162,8 +8253,8 @@ class RevealController {
8162
8253
  Ft: true
8163
8254
  });
8164
8255
  An=true;
8165
- hn=true;
8166
- On=false;
8256
+ On=true;
8257
+ hn=false;
8167
8258
  constructor(e, t) {
8168
8259
  this._n = e;
8169
8260
  this.Tn = t;
@@ -8221,10 +8312,10 @@ class RevealController {
8221
8312
  untrack(() => this.pn());
8222
8313
  }
8223
8314
  pn(e, t) {
8224
- if (this.On) return;
8225
- this.On = true;
8315
+ if (this.hn) return;
8316
+ this.hn = true;
8226
8317
  const n = this.An;
8227
- const i = this.hn;
8318
+ const i = this.On;
8228
8319
  try {
8229
8320
  const n = e ?? read(this.cn), i = untrack(this._n), r = i === "sequential" && !!untrack(this.Tn), o = t ?? r;
8230
8321
  if (n) {
@@ -8276,10 +8367,10 @@ class RevealController {
8276
8367
  }
8277
8368
  } finally {
8278
8369
  this.An = this.sn();
8279
- this.hn = this.fn();
8280
- this.On = false;
8370
+ this.On = this.fn();
8371
+ this.hn = false;
8281
8372
  }
8282
- if (this.dn && (n !== this.An || i !== this.hn)) this.dn.pn();
8373
+ if (this.dn && (n !== this.An || i !== this.On)) this.dn.pn();
8283
8374
  }
8284
8375
  }
8285
8376
 
@@ -8299,8 +8390,8 @@ class CollectionQueue extends Queue {
8299
8390
  });
8300
8391
  En;
8301
8392
  Sn=false;
8302
- bn;
8303
- vn=ON_INIT;
8393
+ vn;
8394
+ bn=ON_INIT;
8304
8395
  constructor(e) {
8305
8396
  super();
8306
8397
  this.gn = e;
@@ -8311,16 +8402,16 @@ class CollectionQueue extends Queue {
8311
8402
  }
8312
8403
  notify(e, t, n, i) {
8313
8404
  if (!(t & this.gn)) return super.notify(e, t, n, i);
8314
- if (this.Sn && this.bn) {
8405
+ if (this.Sn && this.vn) {
8315
8406
  const e = untrack(() => {
8316
8407
  try {
8317
- return this.bn();
8408
+ return this.vn();
8318
8409
  } catch {
8319
8410
  return ON_INIT;
8320
8411
  }
8321
8412
  });
8322
- if (e !== this.vn) {
8323
- this.vn = e;
8413
+ if (e !== this.bn) {
8414
+ this.bn = e;
8324
8415
  this.Sn = false;
8325
8416
  this.un.clear();
8326
8417
  }
@@ -8367,9 +8458,9 @@ class CollectionQueue extends Queue {
8367
8458
  }
8368
8459
  if (!this.ln) {
8369
8460
  setSignal(this.cn, false);
8370
- if (this.bn) {
8461
+ if (this.vn) {
8371
8462
  try {
8372
- this.vn = untrack(() => this.bn());
8463
+ this.bn = untrack(() => this.vn());
8373
8464
  } catch {
8374
8465
  /* value not yet committed — _prevOn stays stale, next notify will reset */}
8375
8466
  }
@@ -8387,7 +8478,7 @@ function createCollectionBoundary(e, t, n, i) {
8387
8478
  ownedWrite: true,
8388
8479
  Ft: true
8389
8480
  });
8390
- if (i) o.bn = i;
8481
+ if (i) o.vn = i;
8391
8482
  const s = o.yn = createBoundChildren(r, t, o, e);
8392
8483
  // Prime source tracking so reveal registration sees pending sources.
8393
8484
  untrack(() => {