@solidjs/signals 2.0.0-rc.16 → 2.0.0-rc.17

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 (39) hide show
  1. package/dist/dev-shared.js +1719 -1603
  2. package/dist/dev.attribution.js +13 -13
  3. package/dist/dev.js +182 -45
  4. package/dist/observe/boundaries.js +2 -2
  5. package/dist/observe/core/async.js +3 -1
  6. package/dist/observe/core/context.js +2 -0
  7. package/dist/observe/core/core.js +26 -10
  8. package/dist/observe/core/effect.js +2 -0
  9. package/dist/observe/core/graph.js +10 -8
  10. package/dist/observe/core/lanes.js +25 -14
  11. package/dist/observe/core/owner.js +73 -47
  12. package/dist/observe/core/scheduler.js +189 -173
  13. package/dist/observe/core/verdict.js +3 -0
  14. package/dist/observe/map.js +2 -2
  15. package/dist/observe/signals.js +6 -1
  16. package/dist/observe/store/affects.js +13 -13
  17. package/dist/observe/store/optimistic.js +112 -71
  18. package/dist/observe/store/store.js +25 -16
  19. package/dist/prod/boundaries.js +2 -2
  20. package/dist/prod/core/async.js +3 -1
  21. package/dist/prod/core/context.js +2 -0
  22. package/dist/prod/core/core.js +31 -15
  23. package/dist/prod/core/effect.js +2 -0
  24. package/dist/prod/core/graph.js +10 -8
  25. package/dist/prod/core/heap.js +1 -1
  26. package/dist/prod/core/lanes.js +25 -14
  27. package/dist/prod/core/owner.js +70 -44
  28. package/dist/prod/core/scheduler.js +43 -27
  29. package/dist/prod/core/verdict.js +4 -1
  30. package/dist/prod/map.js +2 -2
  31. package/dist/prod/signals.js +18 -13
  32. package/dist/prod/store/optimistic.js +112 -71
  33. package/dist/prod/store/store.js +18 -7
  34. package/dist/types/core/core.d.ts +10 -3
  35. package/dist/types/core/dev.d.ts +9 -1
  36. package/dist/types/core/error.d.ts +9 -1
  37. package/dist/types/core/owner.d.ts +4 -0
  38. package/dist/types/core/scheduler.d.ts +23 -4
  39. package/package.json +1 -1
@@ -14,6 +14,8 @@ import { runHeap, enqueueSub, deleteFromHeap } from "./heap.js";
14
14
 
15
15
  import { devCheckQuiescent } from "./invariants.js";
16
16
 
17
+ import { rethrowCleanupError } from "./owner.js";
18
+
17
19
  // Optional-module hooks: module bindings, not `GlobalQueue` statics, so a
18
20
  // bundle that never imports the installing module never assigns them — its
19
21
  // minifier folds every guarded call site (and the branch behind it) away.
@@ -38,12 +40,12 @@ let endLanesHook = null;
38
40
 
39
41
  let lanesBlockedHook = null;
40
42
 
41
- function installLaneHooks(e, n, o, l, t, s, u, i, r) {
43
+ function installLaneHooks(e, n, o, t, l, s, u, i, r) {
42
44
  laneReadHook = e;
43
45
  laneStageHook = n;
44
46
  laneOutcomeHook = o;
45
- laneWriteHook = l;
46
- applyGuessesHook = t;
47
+ laneWriteHook = t;
48
+ applyGuessesHook = l;
47
49
  laneSeamsHook = s;
48
50
  laneCorrectionsHook = u;
49
51
  endLanesHook = i;
@@ -73,12 +75,12 @@ let boundarySeamHook = null;
73
75
 
74
76
  let heldRunHook = null;
75
77
 
76
- function installBoundaryHooks(e, n, o, l, t) {
78
+ function installBoundaryHooks(e, n, o, t, l) {
77
79
  catchHook = e;
78
80
  freshHook = n;
79
81
  hiddenHook = o;
80
- boundarySeamHook = l;
81
- heldRunHook = t;
82
+ boundarySeamHook = t;
83
+ heldRunHook = l;
82
84
  }
83
85
 
84
86
  /** Store (store/store.ts): `park` — the flush parked into `t`: the store
@@ -287,16 +289,16 @@ let judge = null;
287
289
  }
288
290
 
289
291
  function blockedBy(e, n, o = false) {
290
- for (let l = 0; l < e.length; l++) {
291
- const t = e[l];
292
- if (!(t.m & STATUS_PENDING) || t.R & REACTIVE_DISPOSED || t.l & CONFIG_GUESS || t.T.Re !== null && txOf(t) !== n || o && !ownSource(t, n)) continue;
292
+ for (let t = 0; t < e.length; t++) {
293
+ const l = e[t];
294
+ if (!(l.m & STATUS_PENDING) || l.R & REACTIVE_DISPOSED || l.l & CONFIG_GUESS || l.T.Re !== null && txOf(l) !== n || o && !ownSource(l, n)) continue;
293
295
  // The frame's own pending observer (off screen: this one holds nothing;
294
296
  // the next listed node may).
295
- if (t.i === EFFECT_RENDER) {
296
- if (onScreen(t, judge ?? n)) return true;
297
+ if (l.i === EFFECT_RENDER) {
298
+ if (onScreen(l, judge ?? n)) return true;
297
299
  continue;
298
300
  }
299
- for (let e = t.o; e !== null; e = e.t) {
301
+ for (let e = l.o; e !== null; e = e.t) {
300
302
  const o = e.u;
301
303
  // A frame reader: a render effect, or a stale reader of the flight
302
304
  // (REACTIVE_FRAME_READ — a verdict reader, `observeFlight`; lane work,
@@ -399,9 +401,9 @@ function deferZombie(e) {
399
401
 
400
402
  /** The nodes under `owner` a transaction other than `t` holds (boundaries.ts:
401
403
  * what an earlier hold staged under a re-armed boundary). */ function heldUnder(e, n, o) {
402
- for (let l = e.De; l !== null; l = l.pe) {
403
- if ((l.l & (CONFIG_HELD | CONFIG_OVERRIDE)) === CONFIG_HELD && txOf(l) !== n) o(l);
404
- heldUnder(l, n, o);
404
+ for (let t = e.De; t !== null; t = t.pe) {
405
+ if ((t.l & (CONFIG_HELD | CONFIG_OVERRIDE)) === CONFIG_HELD && txOf(t) !== n) o(t);
406
+ heldUnder(t, n, o);
405
407
  }
406
408
  }
407
409
 
@@ -498,6 +500,8 @@ function schedule() {
498
500
  function haltReactivity(e) {
499
501
  if (halted) return;
500
502
  halted = true;
503
+ // A cleanup error collected before the halt is dropped (owner.ts).
504
+ rethrowCleanupError(true);
501
505
  let n = "[REACTIVITY_HALTED]";
502
506
  // Surface the cause here too: callers rethrow it, but a creation-time throw
503
507
  // unwinds through ancestor recomputes that convert it to status instead of
@@ -513,6 +517,15 @@ function haltReactivity(e) {
513
517
  o && o(e);
514
518
  }
515
519
 
520
+ /**
521
+ * Dev: `haltReactivity`, located at `subject` — the computation the uncaught
522
+ * error escaped from — for the REACTIVITY_HALTED message's owner path. Call
523
+ * sites pick it in dev builds only (`haltReactivity(e)` in production), so
524
+ * production keeps the one-argument halt and its bytes unchanged.
525
+ */ function haltReactivityAt(e, n) {
526
+ haltReactivity(e);
527
+ }
528
+
516
529
  // Logs on the first write after a halt so a frozen interaction is traceable.
517
530
  function notifyHalted() {
518
531
  if (haltNotified) return;
@@ -664,7 +677,7 @@ class GlobalQueue {
664
677
  // This flush's own runs, the lanes' reveals, and the landings' held runs
665
678
  // are collected apart and ordered below.
666
679
  const o = this.un;
667
- const l = this.un = [ [], [] ];
680
+ const t = this.un = [ [], [] ];
668
681
  // The passes that read this frame's stagings as the screen read held
669
682
  // writes if it parked: the lane seam re-derives them on the committed
670
683
  // world (a lane's runs wait this round).
@@ -691,8 +704,8 @@ class GlobalQueue {
691
704
  // parked (something async below) — the window is the frame's, the marks
692
705
  // are its transaction's; else they release at the seam, verdict-only,
693
706
  // nothing to show (affects.ts).
694
- const t = n && liveTx(n);
695
- releaseAmbientMarksHook?.(t);
707
+ const l = n && liveTx(n);
708
+ releaseAmbientMarksHook?.(l);
696
709
  // The effect phase: lane work first (displayed ahead of the frame), then
697
710
  // this flush's runs, then the runs the landings held from earlier
698
711
  // flushes — as one pass would have queued them (#3540: a shell
@@ -700,14 +713,14 @@ class GlobalQueue {
700
713
  // write; #3528: a display-ahead swap before the count it is shown
701
714
  // beside). A parked frame's runs wait with its transaction instead: the
702
715
  // effect phase applies a committed frame.
703
- const s = t !== null;
716
+ const s = l !== null;
704
717
  for (let e = 0; e < 2; e++) {
705
- if (s) append(t.un[e], o[e]);
718
+ if (s) append(l.un[e], o[e]);
706
719
  // The plain flush — no reveal, no landing, not parked — has nothing to
707
720
  // order around its own runs: they are the queue as they stand (the
708
721
  // same array, not a copy; `run` takes it whole). Every other seam
709
722
  // builds the ordered queue above.
710
- this.un[e] = s || l[e].length || this.un[e].length ? l[e].concat(s ? [] : o[e], this.un[e]) : o[e];
723
+ this.un[e] = s || t[e].length || this.un[e].length ? t[e].concat(s ? [] : o[e], this.un[e]) : o[e];
711
724
  }
712
725
  if (deferredZombies.length !== 0) {
713
726
  // Survivors are the displayed frame of a held pass: they rerun for the
@@ -749,8 +762,8 @@ class GlobalQueue {
749
762
  *
750
763
  * A boundary between the observer and the root (boundaries.ts) is asked
751
764
  * first: a fallback catches what is not ready under it, and the root
752
- * never hears of it. */ notify(e, n, o, l) {
753
- if (catchHook?.(e, o & n, l)) return true;
765
+ * never hears of it. */ notify(e, n, o, t) {
766
+ if (catchHook?.(e, o & n, t)) return true;
754
767
  if (n & STATUS_PENDING) {
755
768
  if (o & STATUS_PENDING) {
756
769
  // A pass that went pending holds its frame: the async's own
@@ -932,7 +945,7 @@ function commitPendingNode(e) {
932
945
  // commit beneath a flight publishes its inputs (A15 reveal corollary,
933
946
  // #3305): a reveal of it must observe, not show the pre-flight value.
934
947
  const o = e.se === NOT_PENDING && (n.m & STATUS_PENDING) !== 0;
935
- const l = e.l & CONFIG_STAGED_ERROR;
948
+ const t = e.l & CONFIG_STAGED_ERROR;
936
949
  // An answer commits: the error it replaces leaves the display (D-41).
937
950
  if (!o && n.T) n.T.de = undefined;
938
951
  e.l = o ? e.l & -1048833 | CONFIG_INPUTS_PUBLISHED : e.l & -3147137;
@@ -940,7 +953,7 @@ function commitPendingNode(e) {
940
953
  // show, through the ordinary error path (`stageError`). Its readers first
941
954
  // see it in the cycle after this seam: a tracked re-read there is not a
942
955
  // retry (`read`), or a boundary re-derived by it would retry it forever.
943
- if (l) {
956
+ if (t) {
944
957
  const o = e.se;
945
958
  e.se = NOT_PENDING;
946
959
  e.ie = clock + 1;
@@ -954,7 +967,7 @@ function commitPendingNode(e) {
954
967
  // the landed value's commit (A19 exc. 2, #3178): verdict-quiet through
955
968
  // the reveal. (The sweep of a node still in flight is not a landing.)
956
969
  // The A28 stash goes with it.
957
- if (n.T != null) n.T.Ve = false, n.T.Be = NOT_PENDING;
970
+ if (n.T != null) n.T.Ve = false, n.T.je = NOT_PENDING;
958
971
  // An effect with a staged value was born held (L2): its first run is
959
972
  // this commit's, not its creation's (A29) — queue it now.
960
973
  if (e.i && e.i !== EFFECT_TRACKED) {
@@ -1018,10 +1031,13 @@ function flush(e) {
1018
1031
  while (scheduled) {
1019
1032
  globalQueue.flush();
1020
1033
  }
1034
+ // A cleanup that threw during the drain, now that the drain is complete
1035
+ // (owner.ts).
1036
+ rethrowCleanupError();
1021
1037
  }
1022
1038
 
1023
1039
  function runQueue(e, n) {
1024
1040
  for (let o = 0; o < e.length; o++) e[o](n);
1025
1041
  }
1026
1042
 
1027
- export { GlobalQueue, MAINLINE_QUESTION, ROOT_ERROR_HOOK, actionDepth, applyGuessesHook, blocked, boundarySeamHook, bumpNotifyEpoch, catchHook, clock, commitPendingNode, deferZombie, dirtyQueue, endLanesHook, enforceLoadingBoundary, enterAction, exitAction, externalUntrackHook, flush, flushTransaction, freshHook, globalQueue, haltReactivity, heldRunHook, heldTrim, heldUnder, hiddenHook, holdNode, insertSubs, installBoundaryHooks, installLaneHooks, installMarkHooks, installStoreHooks, installVerdictHooks, joinFuture, joinPassTx, laneCorrectionsHook, laneDirty, laneOutcomeHook, laneReadHook, laneSeamsHook, laneStageHook, laneWriteHook, lanesBlockedHook, list, liveTx, merge, newTransaction, nextQuestion, notifyEpoch, observeFlightHook, ownFlights, passLane, passTx, question, queuePendingNode, releaseAmbientMarksHook, releaseMarksHook, releaseQueues, reruns, resetErrorHalt, resolveTx, sameLane, schedule, setExternalHooks, setPassLane, setQuestion, stagedReaders, staleReader, storeCommitHook, storeParkHook, txOf, unhold, wireExternalSourceHook };
1043
+ export { GlobalQueue, MAINLINE_QUESTION, ROOT_ERROR_HOOK, actionDepth, applyGuessesHook, blocked, boundarySeamHook, bumpNotifyEpoch, catchHook, clock, commitPendingNode, deferZombie, dirtyQueue, endLanesHook, enforceLoadingBoundary, enterAction, exitAction, externalUntrackHook, flush, flushTransaction, freshHook, globalQueue, haltReactivity, haltReactivityAt, heldRunHook, heldTrim, heldUnder, hiddenHook, holdNode, insertSubs, installBoundaryHooks, installLaneHooks, installMarkHooks, installStoreHooks, installVerdictHooks, joinFuture, joinPassTx, laneCorrectionsHook, laneDirty, laneOutcomeHook, laneReadHook, laneSeamsHook, laneStageHook, laneWriteHook, lanesBlockedHook, list, liveTx, merge, newTransaction, nextQuestion, notifyEpoch, observeFlightHook, ownFlights, passLane, passTx, question, queuePendingNode, releaseAmbientMarksHook, releaseMarksHook, releaseQueues, reruns, resetErrorHalt, resolveTx, sameLane, schedule, setExternalHooks, setPassLane, setQuestion, stagedReaders, staleReader, storeCommitHook, storeParkHook, txOf, unhold, wireExternalSourceHook };
@@ -175,7 +175,7 @@ let probeFound = false;
175
175
  * a router's link claim probing inside the computation that creates the
176
176
  * anchor). A throw still reaches the pass through `untrack`. */ function markVerdictReader(e) {
177
177
  let t = context;
178
- if (t?.je) t = t.Ye;
178
+ if (t?.Qe) t = t.Ye;
179
179
  if (t !== null && tracking) {
180
180
  t.l |= CONFIG_VERDICT;
181
181
  t.R |= REACTIVE_PROBED;
@@ -318,6 +318,9 @@ let probeFound = false;
318
318
  const u = (n.m & STATUS_PENDING) !== 0 && !quietPending(n);
319
319
  if (e.l & CONFIG_GUESS) {
320
320
  if (probing && (u || e.se !== NOT_PENDING && (!e.xe || !e.xe(e.T.v, e.se)))) probeFound = true;
321
+ // A lane a correction folded under (D-34): `latest()` shows the hold's
322
+ // world whole — the truth beneath each guess, else what it covered.
323
+ if (latestActive && r.folded) return r.folded(null, e);
321
324
  return e.T.v;
322
325
  }
323
326
  if (probing && u) probeFound = true;
package/dist/prod/map.js CHANGED
@@ -301,7 +301,7 @@ function updateKeyedMap() {
301
301
  this.ct && (this.ct = []);
302
302
  this.lt && (this.lt = []);
303
303
  }
304
- if (this.H && !this.ht[0]) {
304
+ if (this.H && !this.ht.length) {
305
305
  // an aborted fallback attempt leaves an owner without a mapping;
306
306
  // dispose it before re-creating
307
307
  this.tn[0]?.dispose();
@@ -539,7 +539,7 @@ function updateRepeat() {
539
539
  // Reset offset to match the cleared data (#2767, repro 2).
540
540
  this.dt = 0;
541
541
  }
542
- if (this.H && !this.ht[0]) {
542
+ if (this.H && !this.ht.length) {
543
543
  // an aborted fallback attempt leaves an owner without a mapping;
544
544
  // dispose it before re-creating
545
545
  this.tn[0]?.dispose();
@@ -292,7 +292,12 @@ function createMemo(e, t) {
292
292
  o = undefined;
293
293
  }
294
294
  runWithOwner(n, () => {
295
- effect(() => (c(), o = getOwner()), t => {
295
+ effect(() => {
296
+ const e = getOwner();
297
+ o = e;
298
+ c();
299
+ return e;
300
+ }, t => {
296
301
  o = undefined;
297
302
  r?.();
298
303
  const n = (e.effect || e)?.();
@@ -334,14 +339,14 @@ function createMemo(e, t) {
334
339
  // or an already-displayed guess would satisfy it in a later slice. (REDERIVE
335
340
  // after: the first pass's own error is the promise's rejection.)
336
341
  computed(() => {
337
- let i, u = false;
342
+ let u, i = false;
338
343
  try {
339
- i = e();
344
+ u = e();
340
345
  } catch (e) {
341
346
  if (e instanceof NotReadyError) throw e;
342
347
  // An error is an answer (D-41): delivered by the same frame rule.
343
- i = unwrapStatusError(e);
344
- u = true;
348
+ u = unwrapStatusError(e);
349
+ i = true;
345
350
  }
346
351
  const s = getOwner();
347
352
  // A truth reader waits out a `createDeferred` flight its value derives
@@ -354,9 +359,9 @@ function createMemo(e, t) {
354
359
  staleReader(s, resolveTx(a));
355
360
  return;
356
361
  }
357
- if (u) return void queueMicrotask(() => r(i));
358
- o?.(i);
359
- queueMicrotask(() => t(i));
362
+ if (i) return void queueMicrotask(() => r(u));
363
+ o?.(u);
364
+ queueMicrotask(() => t(u));
360
365
  }, {
361
366
  Le: n
362
367
  }).l |= CONFIG_REDERIVE;
@@ -516,14 +521,14 @@ function createMemo(e, t) {
516
521
  // (`saving=true` beside the confirmed `version=1` is a tear no timeline
517
522
  // contains). Updates that do not flip the predicate reveal freely.
518
523
  const c = flushTransaction;
519
- createRoot(i => {
520
- let u;
524
+ createRoot(u => {
525
+ let i;
521
526
  let s;
522
527
  const settle = e => {
523
- if (u !== undefined) clearTimeout(u);
528
+ if (i !== undefined) clearTimeout(i);
524
529
  if (s !== undefined) o.removeEventListener("abort", s);
525
530
  e();
526
- i();
531
+ u();
527
532
  };
528
533
  // Authoritative: the predicate sees the truth, never the action's own
529
534
  // optimistic guess — a guess cannot satisfy the wait for its own
@@ -538,7 +543,7 @@ function createMemo(e, t) {
538
543
  // revealed with the action.
539
544
  if (e && c !== null && globalQueue.q && resolveTx(c).tt !== 0) joinFuture(c);
540
545
  });
541
- if (t?.timeout !== undefined) u = setTimeout(() => settle(() => n(new TimeoutError)), t.timeout);
546
+ if (t?.timeout !== undefined) i = setTimeout(() => settle(() => n(new TimeoutError)), t.timeout);
542
547
  if (o !== undefined) {
543
548
  s = () => settle(() => n(o.reason));
544
549
  o.addEventListener("abort", s, {
@@ -1,12 +1,12 @@
1
- import { CONFIG_OVERRIDE, CONFIG_AUTO_DISPOSE, NOT_PENDING } from "../core/constants.js";
1
+ import { CONFIG_OVERRIDE, CONFIG_GUESS, EFFECT_RENDER, CONFIG_CHILDREN_FORBIDDEN, NOT_PENDING, CONFIG_SLOT_NODE, CONFIG_AUTO_DISPOSE } from "../core/constants.js";
2
2
 
3
- import { computed, ext, untrack, read, isEqual } from "../core/core.js";
3
+ import { computed, joinPassAt, ext, untrack, read, isEqual } from "../core/core.js";
4
4
 
5
5
  import { pendingGuessOf, optimisticWrite } from "../core/lanes.js";
6
6
 
7
7
  import { getOwner } from "../core/owner.js";
8
8
 
9
- import { GlobalQueue, txOf, list, insertSubs, laneDirty, notifyEpoch, schedule } from "../core/scheduler.js";
9
+ import { GlobalQueue, txOf, insertSubs, joinFuture, resolveTx, passLane, list, laneDirty, notifyEpoch, schedule } from "../core/scheduler.js";
10
10
 
11
11
  import { runProjectionComputed } from "./projection.js";
12
12
 
@@ -93,16 +93,16 @@ function notifyOptimisticWrites(e, n) {
93
93
  // A chained draft holds the inner store's raws; a raw is the inner slot it
94
94
  // resolves to (as a read of it serves) — the row a held write staged is
95
95
  // the same row, not a guess over the slot (#3796).
96
- const a = n[t];
97
- const f = unwrapValue(o && a ? resolveChainedRaw(e, t, a) : a);
96
+ const u = n[t];
97
+ const f = unwrapValue(o && u ? resolveChainedRaw(e, t, u) : u);
98
98
  if (!(t in i)) {
99
99
  guess(getNode(e, t), t, false, f);
100
100
  guess(getHasNode(e, t), t, true, true);
101
101
  s = true;
102
102
  } else {
103
103
  const n = i[t];
104
- const a = unwrapValue(o && n ? resolveChainedRaw(e, t, n) : n);
105
- if (!isEqual(a, f) && !targetsEqual(a, f)) {
104
+ const u = unwrapValue(o && n ? resolveChainedRaw(e, t, n) : n);
105
+ if (!isEqual(u, f) && !targetsEqual(u, f)) {
106
106
  guess(getNode(e, t), t, false, f);
107
107
  if (r) s = true;
108
108
  }
@@ -122,29 +122,31 @@ function notifyOptimisticWrites(e, n) {
122
122
  if (s) {
123
123
  const o = r ? n.map(unwrapValue) : shallowKeys(n);
124
124
  // The rows the setter removed from the view it saw, by key: a later
125
- // re-base over another action's truth must not bring them back.
125
+ // re-base over another action's truth must not bring them back. A set
126
+ // (empty or not) marks a keyed arrangement guess (`fold`).
126
127
  let s = null;
127
- const a = e.fam.key;
128
- if (r && a !== null && a !== undefined) {
128
+ const u = e.fam.key;
129
+ if (r && u !== null && u !== undefined) {
130
+ s = new Set;
129
131
  const e = new Set;
130
132
  for (let n = 0; n < o.length; n++) {
131
- const t = isWrappable(o[n]) ? a(o[n]) : undefined;
133
+ const t = isWrappable(o[n]) ? u(o[n]) : undefined;
132
134
  if (t !== undefined) e.add(t);
133
135
  }
134
136
  for (let n = 0; n < i.length; n++) {
135
137
  const t = unwrapValue(i[n]);
136
- const r = isWrappable(t) ? a(t) : undefined;
137
- if (r !== undefined && !e.has(r)) (s ??= new Set).add(r);
138
+ const r = isWrappable(t) ? u(t) : undefined;
139
+ if (r !== undefined && !e.has(r)) s.add(r);
138
140
  }
139
141
  }
140
142
  optimisticWrite(getContainerNode(e), new LaneView(o, t, s));
141
143
  }
142
144
  if (e.dk !== null) optimisticWrite(e.dk, {});
143
145
  markOverlaid(e);
144
- const a = optStaged.get(e);
145
- if (a === undefined) return null;
146
+ const u = optStaged.get(e);
147
+ if (u === undefined) return null;
146
148
  optStaged.delete(e);
147
- return a;
149
+ return u;
148
150
  }
149
151
 
150
152
  /** The container comparator's lane arm (store.ts `containerEquals`): an
@@ -228,18 +230,18 @@ function arrangementEqual(e, n, t) {
228
230
  }
229
231
  }
230
232
  for (let s = 0; s < n.length; s++) {
231
- const a = n[s];
233
+ const u = n[s];
232
234
  let f;
233
- if (isWrappable(a)) {
235
+ if (isWrappable(u)) {
234
236
  if (o !== null) {
235
- const e = t(a);
237
+ const e = t(u);
236
238
  if (e !== undefined) f = o.get(e);
237
239
  } else if (s < i && isWrappable(unwrapValue(r[s]))) f = r[s];
238
240
  }
239
241
  if (f !== undefined) {
240
- if (unwrapValue(f) !== a) reconcileDraft(f, a, t);
242
+ if (unwrapValue(f) !== u) reconcileDraft(f, u, t);
241
243
  if (e[s] !== f) e[s] = f;
242
- } else if (unwrapValue(e[s]) !== a) e[s] = a;
244
+ } else if (unwrapValue(e[s]) !== u) e[s] = u;
243
245
  }
244
246
  if (e.length !== n.length) e.length = n.length;
245
247
  return;
@@ -268,66 +270,105 @@ function arrangementEqual(e, n, t) {
268
270
  * node is born for it as the lane's derivation), on `length` only when the
269
271
  * committed length differs, and as the `LaneView`'s base for structural
270
272
  * reads. Unkeyed families compose
271
- * positionally — the guess stands as written (the documented residue). */ GlobalQueue.an = (e, n) => {
272
- const t = e.O;
273
- if (t === undefined || e.ze !== $TRACK) return;
274
- const i = e.T.v;
275
- if (!(i instanceof LaneView)) return;
276
- if (!Array.isArray(n) || !Array.isArray(i.rows)) {
277
- i.base = n;
273
+ * positionally — the guess stands as written (the documented residue). */ GlobalQueue.an = (e, n, t) => {
274
+ if (!t) return fold(e, n);
275
+ const i = e.O;
276
+ if (i === undefined || e.ze !== $TRACK) return;
277
+ const r = e.T.v;
278
+ if (!(r instanceof LaneView)) return;
279
+ if (!Array.isArray(n) || !Array.isArray(r.rows)) {
280
+ r.base = n;
278
281
  return;
279
282
  }
280
- const r = t.fam?.key ?? null;
281
- if (r === null) return;
282
- const o = new Map;
283
+ const o = i.fam?.key ?? null;
284
+ if (o === null) return;
285
+ const s = new Map;
283
286
  for (let e = 0; e < n.length; e++) {
284
287
  const t = n[e];
285
- const i = isWrappable(t) ? r(t) : undefined;
286
- if (i !== undefined && !o.has(i)) o.set(i, t);
288
+ const i = isWrappable(t) ? o(t) : undefined;
289
+ if (i !== undefined && !s.has(i)) s.set(i, t);
287
290
  }
288
- const s = new Set;
289
- const a = [];
290
- const f = i.rows;
291
- for (let e = 0; e < f.length; e++) {
292
- const n = f[e];
293
- const t = isWrappable(n) ? r(n) : undefined;
294
- const i = t !== undefined ? o.get(t) : undefined;
291
+ const u = new Set;
292
+ const f = [];
293
+ const a = r.rows;
294
+ for (let e = 0; e < a.length; e++) {
295
+ const n = a[e];
296
+ const t = isWrappable(n) ? o(n) : undefined;
297
+ const i = t !== undefined ? s.get(t) : undefined;
295
298
  if (i !== undefined) {
296
- a.push(i);
297
- s.add(t);
298
- } else a.push(n);
299
+ f.push(i);
300
+ u.add(t);
301
+ } else f.push(n);
299
302
  }
300
- const u = i.removed;
303
+ const l = r.removed;
301
304
  for (let e = 0; e < n.length; e++) {
302
305
  const t = n[e];
303
- const i = isWrappable(t) ? r(t) : undefined;
304
- if (i !== undefined && !s.has(i) && (u === null || !u.has(i))) a.push(t);
306
+ const i = isWrappable(t) ? o(t) : undefined;
307
+ if (i !== undefined && !u.has(i) && (l === null || !l.has(i))) f.push(t);
305
308
  }
306
- i.rows = a;
307
- i.base = a;
308
- const l = txOf(e);
309
- const c = committed(t);
310
- const d = t.n;
311
- for (let e = 0; e < a.length; e++) {
312
- const n = d?.[e];
309
+ r.rows = f;
310
+ r.base = f;
311
+ const c = txOf(e);
312
+ const d = committed(i);
313
+ const p = i.n;
314
+ for (let e = 0; e < f.length; e++) {
315
+ const n = p?.[e];
313
316
  // A slot the lane does not own shows the committed row: it becomes the
314
317
  // lane's only where the composed row is another row (by key — the same
315
318
  // key's new object is the same row, its target adopted it).
316
319
  if (n === undefined) {
317
- if (!sameRow(c[e], a[e], r)) laneSet(getNode(t, e), a[e], l);
318
- } else if (!sameRow(n.l & CONFIG_OVERRIDE ? n.T.v : c[e], a[e], r)) laneSet(n, a[e], l);
320
+ if (!sameRow(d[e], f[e], o)) laneSet(getNode(i, e), f[e], c);
321
+ } else if (!sameRow(n.l & CONFIG_OVERRIDE ? n.T.v : d[e], f[e], o)) laneSet(n, f[e], c);
319
322
  }
320
- if (d !== null) {
321
- for (let e = a.length; ;e++) {
322
- const n = d[e];
323
+ if (p !== null) {
324
+ for (let e = f.length; ;e++) {
325
+ const n = p[e];
323
326
  if (n === undefined) break;
324
- laneSet(n, undefined, l);
327
+ laneSet(n, undefined, c);
325
328
  }
326
- const e = d.length;
327
- if (e !== undefined && (e.l & CONFIG_OVERRIDE || c.length !== a.length)) laneSet(e, a.length, l);
329
+ const e = p.length;
330
+ if (e !== undefined && (e.l & CONFIG_OVERRIDE || d.length !== f.length)) laneSet(e, f.length, c);
328
331
  }
329
332
  };
330
333
 
334
+ /** D-34 for a keyed arrangement guess: rows by key, not positions. A
335
+ * current truth that differs folds into the hold beneath it instead of
336
+ * voiding the lane: the guess stays the lane's value and the screen's until
337
+ * the hold commits, where rows match by key, and the graph outside the lane
338
+ * re-derives from the truth now (`foldedRead`). A confirmation is silent
339
+ * (A17): only truth readers are told. True: the lane stages the truth
340
+ * beneath (`laneWrite`). */ function fold(e, n) {
341
+ const t = e.O?.k;
342
+ const i = txOf(e);
343
+ // A guess the screen never showed is void at the correction (D-34); a
344
+ // keyed arrangement guess's view carries its removed-keys set.
345
+ if (!i.ke || !(t?.l & CONFIG_OVERRIDE) || !t.T.v?.removed) return false;
346
+ const r = e.T.v;
347
+ if ((!e.xe || !e.xe(r, n)) && !GlobalQueue.nn(r, n)) {
348
+ i.folded = foldedRead;
349
+ insertSubs(e);
350
+ } else GlobalQueue.sn?.(i);
351
+ joinFuture(resolveTx(i._parent ?? i));
352
+ return true;
353
+ }
354
+
355
+ /** A folded lane's guess read by a deriving pass outside the lane, tracked
356
+ * or not (`untrack` is about dependencies, not about which world a pass
357
+ * derives from), or by `latest()` (`c` null): the hold's world — the truth
358
+ * staged beneath the guess, else the value it covered — and the pass joins
359
+ * the hold. Lane passes and the screen keep the guess: held truth is masked
360
+ * from lane passes only (#3164). The store's own derive reconciles its
361
+ * landings against the arrangement the guesses made: it is the author, not
362
+ * a reader. */ function foldedRead(e, n) {
363
+ if (e !== null) {
364
+ if (!(n.l & CONFIG_GUESS) || passLane !== null || e.i === EFFECT_RENDER || e.l & CONFIG_CHILDREN_FORBIDDEN || n.O?.fam?.node === e) return NOT_PENDING;
365
+ const t = txOf(n);
366
+ joinPassAt(e, resolveTx(t._parent ?? t));
367
+ }
368
+ if (n.se !== NOT_PENDING) return n.se;
369
+ return n.l & CONFIG_SLOT_NODE ? GlobalQueue.fn(n) : n.Ie;
370
+ }
371
+
331
372
  function sameRow(e, n, t) {
332
373
  if (e === n) return true;
333
374
  if (!isWrappable(e) || !isWrappable(n)) return false;
@@ -521,11 +562,11 @@ i = false) {
521
562
  if (s !== null) {
522
563
  for (const e of Reflect.ownKeys(s)) {
523
564
  const o = s[e];
524
- let a;
525
- if (o.l & CONFIG_OVERRIDE) a = t(o); else if (!i || (a = pendingGuessOf(o)) === NOT_PENDING) continue;
526
- const f = !!a;
527
- const u = r ?? n;
528
- if (!f && e in u) delete ensure()[e];
565
+ let u;
566
+ if (o.l & CONFIG_OVERRIDE) u = t(o); else if (!i || (u = pendingGuessOf(o)) === NOT_PENDING) continue;
567
+ const f = !!u;
568
+ const a = r ?? n;
569
+ if (!f && e in a) delete ensure()[e];
529
570
  }
530
571
  }
531
572
  return r ?? n;
@@ -538,7 +579,7 @@ function createOptimisticStore(e, n, t) {
538
579
  // createProjectionInternal).
539
580
  const o = i ? n || {} : e;
540
581
  const s = r?.key === undefined ? "id" : r.key;
541
- const a = {
582
+ const u = {
542
583
  map: new WeakMap,
543
584
  node: null,
544
585
  live: new Set,
@@ -546,8 +587,8 @@ function createOptimisticStore(e, n, t) {
546
587
  opt: true,
547
588
  key: typeof s === "function" ? s : s === null ? null : e => isWrappable(e) ? e[s] : undefined
548
589
  };
549
- const f = wrap(o, null, null, a);
550
- if (a.shallow) {
590
+ const f = wrap(o, null, null, u);
591
+ if (u.shallow) {
551
592
  f[$TARGET].s = true;
552
593
  markRawIngest(o);
553
594
  }
@@ -558,11 +599,11 @@ function createOptimisticStore(e, n, t) {
558
599
  loadingValue: undefined
559
600
  };
560
601
  const i = computed(() => {
561
- if (!a.node) a.node = getOwner();
602
+ if (!u.node) u.node = getOwner();
562
603
  runProjectionComputed(f, n, s);
563
604
  }, t);
564
605
  i.l &= ~CONFIG_AUTO_DISPOSE;
565
- a.node = i;
606
+ u.node = i;
566
607
  }
567
608
  return [ f, e => storeSetter(f, e) ];
568
609
  }