@solidjs/signals 2.0.0-rc.18 → 2.0.0-rc.19

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 (65) hide show
  1. package/dist/dev-shared.js +168 -88
  2. package/dist/dev.attribution.js +16 -13
  3. package/dist/dev.js +272 -129
  4. package/dist/observe/boundaries.js +88 -67
  5. package/dist/observe/core/action.js +8 -0
  6. package/dist/observe/core/async.js +46 -34
  7. package/dist/observe/core/attribution.js +30 -28
  8. package/dist/observe/core/constants.js +21 -1
  9. package/dist/observe/core/core.js +164 -136
  10. package/dist/observe/core/effect.js +6 -6
  11. package/dist/observe/core/graph.js +3 -3
  12. package/dist/observe/core/heap.js +5 -5
  13. package/dist/observe/core/lanes.js +104 -84
  14. package/dist/observe/core/owner.js +10 -9
  15. package/dist/observe/core/scheduler.js +38 -35
  16. package/dist/observe/core/truth.js +6 -6
  17. package/dist/observe/core/verdict.js +13 -13
  18. package/dist/observe/deferred.js +39 -40
  19. package/dist/observe/index.js +2 -2
  20. package/dist/observe/map.js +22 -22
  21. package/dist/observe/reveal.js +5 -5
  22. package/dist/observe/signals.js +57 -15
  23. package/dist/observe/store/affects.js +1 -1
  24. package/dist/observe/store/hooks.js +3 -0
  25. package/dist/observe/store/optimistic.js +11 -11
  26. package/dist/observe/store/projection.js +34 -21
  27. package/dist/observe/store/reconcile.js +2 -2
  28. package/dist/observe/store/store.js +63 -53
  29. package/dist/observe/store/utils.js +7 -2
  30. package/dist/prod/boundaries.js +153 -132
  31. package/dist/prod/core/action.js +8 -0
  32. package/dist/prod/core/async.js +55 -43
  33. package/dist/prod/core/constants.js +14 -1
  34. package/dist/prod/core/core.js +162 -134
  35. package/dist/prod/core/effect.js +9 -9
  36. package/dist/prod/core/graph.js +3 -3
  37. package/dist/prod/core/heap.js +12 -12
  38. package/dist/prod/core/lanes.js +98 -78
  39. package/dist/prod/core/owner.js +15 -14
  40. package/dist/prod/core/scheduler.js +43 -40
  41. package/dist/prod/core/truth.js +6 -6
  42. package/dist/prod/core/verdict.js +17 -17
  43. package/dist/prod/deferred.js +39 -40
  44. package/dist/prod/index.js +2 -2
  45. package/dist/prod/map.js +14 -14
  46. package/dist/prod/reveal.js +8 -8
  47. package/dist/prod/signals.js +46 -4
  48. package/dist/prod/store/affects.js +1 -1
  49. package/dist/prod/store/hooks.js +3 -0
  50. package/dist/prod/store/optimistic.js +16 -16
  51. package/dist/prod/store/projection.js +22 -9
  52. package/dist/prod/store/reconcile.js +2 -2
  53. package/dist/prod/store/store.js +262 -262
  54. package/dist/prod/store/utils.js +2 -0
  55. package/dist/types/core/action.d.ts +8 -0
  56. package/dist/types/core/constants.d.ts +20 -0
  57. package/dist/types/core/core.d.ts +14 -1
  58. package/dist/types/core/dev.d.ts +1 -1
  59. package/dist/types/core/index.d.ts +1 -1
  60. package/dist/types/core/lanes.d.ts +5 -1
  61. package/dist/types/core/scheduler.d.ts +2 -0
  62. package/dist/types/index.d.ts +3 -1
  63. package/dist/types/signals.d.ts +37 -0
  64. package/dist/types/store/target.d.ts +2 -0
  65. package/package.json +1 -1
package/dist/prod/map.js CHANGED
@@ -21,7 +21,7 @@ function mapArray(t, e, i) {
21
21
  const n = e.length > 1;
22
22
  const r = e;
23
23
  const o = {
24
- L: createOwner(),
24
+ H: createOwner(),
25
25
  it: 0,
26
26
  st: t,
27
27
  ot: [],
@@ -32,7 +32,7 @@ function mapArray(t, e, i) {
32
32
  ct: s || i?.keyed === false ? [] : undefined,
33
33
  lt: n && i?.keyed !== false ? [] : undefined,
34
34
  ut: i?.keyed === false,
35
- H: i?.fallback
35
+ L: i?.fallback
36
36
  };
37
37
  const f = computed(updateKeyedMap.bind(o), undefined);
38
38
  f.l &= ~CONFIG_AUTO_DISPOSE;
@@ -263,11 +263,11 @@ function updateKeyedMap() {
263
263
  // the flight's reader (pending tracking + post-settle retry) instead of
264
264
  // vanishing. Set per pass: the first pass runs inside `computed()`, before
265
265
  // the node exists to the caller.
266
- this.L.Ye = getOwner();
266
+ this.H.Ye = getOwner();
267
267
  const t = this.st() || [], e = t.length;
268
268
  t[$TRACK];
269
269
  // top level tracking (a store array's container node)
270
- runWithOwner(this.L, () => {
270
+ runWithOwner(this.H, () => {
271
271
  let i, s,
272
272
  // The stage slot a mapper writes its row/index signal into: `j` on the
273
273
  // create-all path, `j - start` on the general path, whose stage arrays
@@ -293,7 +293,7 @@ function updateKeyedMap() {
293
293
  // fast path for empty arrays
294
294
  if (e === 0) {
295
295
  if (this.it !== 0) {
296
- this.L.dispose(false);
296
+ this.H.dispose(false);
297
297
  this.tn = [];
298
298
  this.ot = [];
299
299
  this.ht = [];
@@ -301,11 +301,11 @@ function updateKeyedMap() {
301
301
  this.ct && (this.ct = []);
302
302
  this.lt && (this.lt = []);
303
303
  }
304
- if (this.H && !this.ht.length) {
304
+ if (this.L && !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();
308
- this.ht[0] = runWithOwner(this.tn[0] = createOwner(), this.H);
308
+ this.ht[0] = runWithOwner(this.tn[0] = createOwner(), this.L);
309
309
  }
310
310
  }
311
311
  // fast path for new create
@@ -502,7 +502,7 @@ function updateKeyedMap() {
502
502
  */ function repeat(t, e, i) {
503
503
  const s = e;
504
504
  const n = {
505
- L: createOwner(),
505
+ H: createOwner(),
506
506
  it: 0,
507
507
  dt: 0,
508
508
  wt: t,
@@ -510,7 +510,7 @@ function updateKeyedMap() {
510
510
  tn: [],
511
511
  ht: [],
512
512
  Ot: i?.from,
513
- H: i?.fallback
513
+ L: i?.fallback
514
514
  };
515
515
  const r = computed(updateRepeat.bind(n));
516
516
  r.l &= ~CONFIG_AUTO_DISPOSE;
@@ -526,24 +526,24 @@ function updateKeyedMap() {
526
526
  // disjoint-window/front-clear/end-clear/shift special cases.
527
527
  function updateRepeat() {
528
528
  // As in updateKeyedMap: the node is the row callbacks' reader, per pass.
529
- this.L.Ye = getOwner();
529
+ this.H.Ye = getOwner();
530
530
  const t = this.wt();
531
531
  const e = this.Ot?.() || 0;
532
- runWithOwner(this.L, () => {
532
+ runWithOwner(this.H, () => {
533
533
  if (t === 0) {
534
534
  if (this.it !== 0) {
535
- this.L.dispose(false);
535
+ this.H.dispose(false);
536
536
  this.tn = [];
537
537
  this.ht = [];
538
538
  this.it = 0;
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.length) {
542
+ if (this.L && !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();
546
- this.ht[0] = runWithOwner(this.tn[0] = createOwner(), this.H);
546
+ this.ht[0] = runWithOwner(this.tn[0] = createOwner(), this.L);
547
547
  }
548
548
  return;
549
549
  }
@@ -76,7 +76,7 @@ class RevealController {
76
76
  /** A slot that has left this controller's ownership: a boundary that has
77
77
  * shown content, a nested group that is ready. Shown is shown — it counts
78
78
  * as ready whatever happens to it later (a re-arm gates nobody else). */ gt(t) {
79
- return (isController(t) ? t._parent : t.V) !== this;
79
+ return (isController(t) ? t._parent : t.v) !== this;
80
80
  }
81
81
  /** The slots this controller still owns, in registration order — the
82
82
  * ones the order's state is forced on. */ Lt(t) {
@@ -106,7 +106,7 @@ class RevealController {
106
106
  }
107
107
  return t !== "natural";
108
108
  }
109
- oe(t) {
109
+ te(t) {
110
110
  if (this.At.includes(t)) return;
111
111
  this.At.push(t);
112
112
  // Gated from the start (collapsed in a collapsed sequential tail); the
@@ -118,13 +118,13 @@ class RevealController {
118
118
  t.ee = e;
119
119
  t._t();
120
120
  } else {
121
- t.V = this;
121
+ t.v = this;
122
122
  t.$ = true;
123
123
  t.ee = e;
124
124
  }
125
125
  untrack(() => this._t());
126
126
  }
127
- te(t) {
127
+ oe(t) {
128
128
  const e = this.At.indexOf(t);
129
129
  if (e >= 0) this.At.splice(e, 1);
130
130
  untrack(() => this._t());
@@ -194,8 +194,8 @@ class RevealController {
194
194
  });
195
195
  if (false) ;
196
196
  if (r) {
197
- r.oe(i);
198
- cleanup(() => r.te(i));
197
+ r.te(i);
198
+ cleanup(() => r.oe(i));
199
199
  }
200
200
  return e;
201
201
  });
@@ -204,9 +204,9 @@ class RevealController {
204
204
  // Installed at module evaluation — present exactly when something imports
205
205
  // `createRevealOrder`; a Loading boundary without one pays a null check.
206
206
  setRevealHooks({
207
- oe: (t, e) => t.oe(e),
208
207
  te: (t, e) => t.te(e),
209
- P: t => t._t()
208
+ oe: (t, e) => t.oe(e),
209
+ V: t => t._t()
210
210
  });
211
211
 
212
212
  export { createRevealOrder };
@@ -6,7 +6,7 @@ import { CONFIG_CHILDREN_FORBIDDEN, EFFECT_USER, $REFRESH, CONFIG_AUTO_DISPOSE,
6
6
 
7
7
  import { computed, signal, runWithOwner, setMemo, setSignal, markRefresh, read, untrack } from "./core/core.js";
8
8
 
9
- import { globalQueue, flushTransaction, dirtyQueue, GlobalQueue, resolveTx, passTx, staleReader, joinFuture } from "./core/scheduler.js";
9
+ import { schedule, globalQueue, flushTransaction, dirtyQueue, GlobalQueue, resolveTx, passTx, staleReader, joinFuture } from "./core/scheduler.js";
10
10
 
11
11
  import { cleanup, createRoot, getOwner, dispose } from "./core/owner.js";
12
12
 
@@ -463,7 +463,7 @@ function createMemo(e, t) {
463
463
  // guessed node's own re-ask is not answered by it (#3895): park
464
464
  // on that flight, or reject with its error.
465
465
  const e = read(t);
466
- if (t.l & CONFIG_GUESS && t.m & (STATUS_PENDING | STATUS_ERROR)) throw t.T?.F;
466
+ if (t.l & CONFIG_GUESS && t.m & (STATUS_PENDING | STATUS_ERROR)) throw t.T?.U;
467
467
  return e;
468
468
  }, t => {
469
469
  n(typeof e === "function" ? t : e);
@@ -657,7 +657,7 @@ function createMemo(e, t) {
657
657
  // still holding the optimistic value — reads do not pull (#3411). Fall
658
658
  // to the next pass while the heap has work; `run` swapped the queue,
659
659
  // so this lands there, and `enqueue` keeps the drain alive.
660
- if (dirtyQueue.et >= dirtyQueue.Ge) return globalQueue.enqueue(EFFECT_USER, fire);
660
+ if (dirtyQueue.et >= dirtyQueue.Fe) return globalQueue.enqueue(EFFECT_USER, fire);
661
661
  // Unowned, out-of-band fire (no owner, or a children-forbidden one this
662
662
  // one-shot must not bind to): a returned cleanup has no lifecycle to
663
663
  // attach to. Reject it in dev; in production the return is simply
@@ -666,4 +666,46 @@ function createMemo(e, t) {
666
666
  });
667
667
  }
668
668
 
669
- export { accessor, createEffect, createMemo, createOptimistic, createReaction, createRenderEffect, createSignal, createTrackedEffect, onCleanup, onSettled, refresh, resolve, until };
669
+ /**
670
+ * Schedules `callback` to run **once**, right after the pending flush
671
+ * finishes, in the same microtask checkpoint (before the browser paints).
672
+ * Unlike `onSettled`, it never waits on async work: if that flush is held by
673
+ * a pending transition, the callback still runs.
674
+ *
675
+ * Its main use is keeping a write out of another update's hold. Writes made
676
+ * in the same synchronous frame are applied together, so when one of them
677
+ * starts async work (a route change, a fetch), the others are held with it
678
+ * until it resolves. A write made in `onFlush` happens after that flush, so
679
+ * it is its own update: it commits on its own unless something it changes
680
+ * also derives from the held work (a memo or `createEffect` reading both),
681
+ * in which case it joins that hold as any later write would.
682
+ *
683
+ * Call it from event handlers and effect callbacks (including
684
+ * `createTrackedEffect` and `onSettled` bodies). In an owned scope such as a
685
+ * component body or a computation it warns in dev: use `onSettled` there.
686
+ *
687
+ * - A write in the callback lands after any write made inline in the same
688
+ * frame. Don't write the same signal both inside and outside it; use a
689
+ * functional setter if the order matters.
690
+ * - Several `onFlush` callbacks run in call order and batch into one flush.
691
+ * - `queueMicrotask` is not a substitute: called before the frame's first
692
+ * write, it runs before that flush and its write joins it.
693
+ *
694
+ * @example
695
+ * ```tsx
696
+ * // A menu closes now even when the consumer's onSelect starts async work.
697
+ * const select = (id: string) => {
698
+ * onFlush(() => setOpen(false));
699
+ * props.onSelect?.(id);
700
+ * };
701
+ * ```
702
+ *
703
+ * @param callback Function to run once after the pending flush
704
+ */ function onFlush(e) {
705
+ // The frame's flush is queued (or already draining) ahead of this
706
+ // microtask, so the callback's writes start a flush of their own.
707
+ schedule();
708
+ queueMicrotask(e);
709
+ }
710
+
711
+ export { accessor, createEffect, createMemo, createOptimistic, createReaction, createRenderEffect, createSignal, createTrackedEffect, onCleanup, onFlush, onSettled, refresh, resolve, until };
@@ -72,7 +72,7 @@ function scopeOf(e, o) {
72
72
  if (f !== undefined) {
73
73
  if (f.pb !== null) o.eo.add(f.v);
74
74
  // The writer's view: the tick's own unflushed guesses are in motion too.
75
- if (f.fam?.opt === true) r = optHooks.view(f, r, true);
75
+ if (optHooks && f.fam?.opt === true) r = optHooks.view(f, r, true);
76
76
  const e = f.n;
77
77
  if (e !== null) for (const o of Reflect.ownKeys(e))
78
78
  // Another mark's carrier is its own channel: counting it here would
@@ -1,3 +1,6 @@
1
+ // Set before any family is optimistic (`fam.opt`): a call site checks the
2
+ // hooks first, so a build that does not import optimistic.ts folds the arm
3
+ // away.
1
4
  let optHooks = null;
2
5
 
3
6
  function installOptHooks(o) {
@@ -83,7 +83,7 @@ function notifyOptimisticWrites(e, n) {
83
83
  // inner store's truth for its key before guessing over it.
84
84
  const o = e.ch ? e.v : null;
85
85
  const guess = (e, n, i, r) => {
86
- if (o !== null) e.Ie = i ? n in t : unwrapValue(t[n]);
86
+ if (o !== null) e.le = i ? n in t : unwrapValue(t[n]);
87
87
  // By value: a function leaf is a value, not an updater (#3017).
88
88
  optimisticWrite(e, () => r);
89
89
  };
@@ -274,7 +274,7 @@ function arrangementEqual(e, n, t) {
274
274
  if (!t) return fold(e, n);
275
275
  const i = e.O;
276
276
  if (i === undefined || e.ze !== $TRACK) return;
277
- const r = e.T.v;
277
+ const r = e.T.P;
278
278
  if (!(r instanceof LaneView)) return;
279
279
  if (!Array.isArray(n) || !Array.isArray(r.rows)) {
280
280
  r.base = n;
@@ -318,7 +318,7 @@ function arrangementEqual(e, n, t) {
318
318
  // key's new object is the same row, its target adopted it).
319
319
  if (n === undefined) {
320
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);
321
+ } else if (!sameRow(n.l & CONFIG_OVERRIDE ? n.T.P : d[e], f[e], o)) laneSet(n, f[e], c);
322
322
  }
323
323
  if (p !== null) {
324
324
  for (let e = f.length; ;e++) {
@@ -342,8 +342,8 @@ function arrangementEqual(e, n, t) {
342
342
  const i = txOf(e);
343
343
  // A guess the screen never showed is void at the correction (D-34); a
344
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;
345
+ if (!i.ge || !(t?.l & CONFIG_OVERRIDE) || !t.T.P?.removed) return false;
346
+ const r = e.T.P;
347
347
  if ((!e.xe || !e.xe(r, n)) && !GlobalQueue.nn(r, n)) {
348
348
  i.folded = foldedRead;
349
349
  insertSubs(e);
@@ -365,8 +365,8 @@ function arrangementEqual(e, n, t) {
365
365
  const t = txOf(n);
366
366
  joinPassAt(e, resolveTx(t._parent ?? t));
367
367
  }
368
- if (n.ue !== NOT_PENDING) return n.ue;
369
- return n.l & CONFIG_SLOT_NODE ? GlobalQueue.fn(n) : n.Ie;
368
+ if (n.ie !== NOT_PENDING) return n.ie;
369
+ return n.l & CONFIG_SLOT_NODE ? GlobalQueue.fn(n) : n.le;
370
370
  }
371
371
 
372
372
  function sameRow(e, n, t) {
@@ -383,8 +383,8 @@ function sameRow(e, n, t) {
383
383
  if (!(e.l & CONFIG_OVERRIDE)) {
384
384
  e.l |= CONFIG_OVERRIDE;
385
385
  list(e, t);
386
- } else if (i.v === n) return;
387
- i.v = n;
386
+ } else if (i.P === n) return;
387
+ i.P = n;
388
388
  if (e.o !== null) {
389
389
  insertSubs(e);
390
390
  laneDirty(e, t);
@@ -430,7 +430,7 @@ function sweepOverlaid() {
430
430
  // The container shows its backing again (a shown arrangement guess
431
431
  // that ended without a landing left its `LaneView` as the value).
432
432
  const t = e.k;
433
- if (t !== null && t.Ie instanceof LaneView) t.Ie = t.Ie.base;
433
+ if (t !== null && t.le instanceof LaneView) t.le = t.le.base;
434
434
  }
435
435
  if (n.size === 0) overlaidFamilies.delete(e);
436
436
  }
@@ -447,8 +447,8 @@ function sweepOverlaid() {
447
447
  if (i !== null) for (const e of Reflect.ownKeys(i)) {
448
448
  const r = i[e];
449
449
  const o = untrack(() => unwrapValue(n[e]));
450
- if (r.xe && r.xe(r.Ie, o)) continue;
451
- r.Ie = o;
450
+ if (r.xe && r.xe(r.le, o)) continue;
451
+ r.le = o;
452
452
  // (The lane's end notified it this epoch when the shown value and the
453
453
  // covered one differed — its readers re-derive already.)
454
454
  if (r.o !== null && r.Me !== notifyEpoch) {
@@ -460,8 +460,8 @@ function sweepOverlaid() {
460
460
  if (r !== null) for (const e of Reflect.ownKeys(r)) {
461
461
  const i = r[e];
462
462
  const o = untrack(() => e in n);
463
- if (i.Ie === o) continue;
464
- i.Ie = o;
463
+ if (i.le === o) continue;
464
+ i.le = o;
465
465
  if (i.o !== null && i.Me !== notifyEpoch) {
466
466
  insertSubs(i);
467
467
  t = true;
@@ -470,9 +470,9 @@ function sweepOverlaid() {
470
470
  // The arrangement the readers saw (the shown guess) against the inner's
471
471
  // now: a structural reader re-derives when they differ.
472
472
  const o = e.k;
473
- if (o !== null && o.o !== null && o.Ie instanceof LaneView && o.Me !== notifyEpoch) {
473
+ if (o !== null && o.o !== null && o.le instanceof LaneView && o.Me !== notifyEpoch) {
474
474
  const i = Array.isArray(n) ? untrack(() => n.map(unwrapValue)) : n;
475
- if (!arrangementEqual(o.Ie.rows, i, e.fam?.key ?? null)) {
475
+ if (!arrangementEqual(o.le.rows, i, e.fam?.key ?? null)) {
476
476
  insertSubs(o);
477
477
  t = true;
478
478
  }
@@ -1,4 +1,4 @@
1
- import { CONFIG_AUTO_DISPOSE, STATUS_PENDING, STATUS_UNINITIALIZED } from "../core/constants.js";
1
+ import { CONFIG_AUTO_DISPOSE, STATUS_PENDING, STATUS_ERROR, STATUS_UNINITIALIZED } from "../core/constants.js";
2
2
 
3
3
  import { computed } from "../core/core.js";
4
4
 
@@ -118,8 +118,14 @@ function cloneState(e, t) {
118
118
  * (`notifyStatus`): a verdict or re-derive reader re-runs, any other is
119
119
  * pending derivatively on the derive (its readers hold; it re-runs at the
120
120
  * landing). The leaves do not subscribe to the derive, so the family does
121
- * the walk. */ function wakeFamily(e, t) {
122
- const r = e.node;
121
+ * the walk. */ function wakeFamily(e) {
122
+ const t = e.node;
123
+ // Pending on the derive itself, whatever source took it there (an upstream
124
+ // memo's flight reaches it as a NotReady of that memo, #4271): the leaves
125
+ // are not that source's dependents, so only the family's settle — which
126
+ // retires the derive (`settleFamily`) — reaches the readers parked here. A
127
+ // reader the landing leaves unchanged does not re-run to clear it (#4305).
128
+ const r = new NotReadyError(t);
123
129
  e.woke = true;
124
130
  forEachFamilyNode(e, e => {
125
131
  if (e.o === null) return;
@@ -127,12 +133,12 @@ function cloneState(e, t) {
127
133
  // between them would: a dependent recovering one branch stays pending
128
134
  // through a leaf it still reads (core `retryReaches`), and the landing's
129
135
  // walk retires the copy first (`settleFamily` → `settlePendingSource`).
130
- addPendingSource(e, r);
136
+ addPendingSource(e, t);
131
137
  // Its readers: core's propagation from the leaf — a verdict or re-derive
132
138
  // reader re-runs, any other is pending derivatively on the derive and
133
139
  // queued for the frame (held with it: the frame waits on the flight
134
140
  // through them, `blocked`).
135
- propagateStatus(e, STATUS_PENDING, t);
141
+ propagateStatus(e, STATUS_PENDING, r);
136
142
  });
137
143
  }
138
144
 
@@ -158,6 +164,12 @@ function cloneState(e, t) {
158
164
  });
159
165
  }
160
166
 
167
+ /** A source's status reached the derive by propagation (core
168
+ * `propagateStatus`), its pass not re-run: the family learns it as from the
169
+ * pass's own throw. */ function familyStatus(e) {
170
+ if (e & STATUS_PENDING) wakeFamily(this); else if (e & STATUS_ERROR) errorFamily(this);
171
+ }
172
+
161
173
  function forEachFamilyNode(e, t) {
162
174
  for (const r of e.live) {
163
175
  const e = r.n;
@@ -187,7 +199,7 @@ function forEachFamilyNode(e, t) {
187
199
  // The question a write of this run answers: inside a slice, the slice's
188
200
  // (the sync pass); in a continuation — the flight still registered — the
189
201
  // flight's (`handleAsync` stamped it with the action that asked).
190
- const asking = () => question || (i.T !== null && i.T.Se !== null ? i.T.Ee : 0);
202
+ const asking = () => question || (i.T !== null && i.T.Ee !== null ? i.T.Te : 0);
191
203
  const f = wrapDraft(e, () => c.run === u && !isDisposed(i), o, s.s,
192
204
  // A write after the run returned (a continuation, a callback) arms the
193
205
  // drain itself when no landing will.
@@ -234,7 +246,7 @@ function forEachFamilyNode(e, t) {
234
246
  // #2897) — and the flush that runs them advances the clock, so a
235
247
  // later tracked re-read may retry (core `read`).
236
248
  if (d && i.m & STATUS_UNINITIALIZED) return;
237
- if (t) wakeFamily(c, e); else errorFamily(c);
249
+ if (t) wakeFamily(c); else errorFamily(c);
238
250
  });
239
251
  if (!i.ce) commit(u);
240
252
  }, false);
@@ -246,14 +258,14 @@ function forEachFamilyNode(e, t) {
246
258
  // they do not subscribe to the derive.
247
259
  // A synchronous error the same way (#3956: a rerun that finds the
248
260
  // entry failed throws): every live reader re-derives and meets it.
249
- if (!d) e instanceof NotReadyError ? wakeFamily(c, e) : errorFamily(c);
261
+ if (!d) e instanceof NotReadyError ? wakeFamily(c) : errorFamily(c);
250
262
  throw e;
251
263
  }
252
264
  // A pass that returned with a flight up (an iterator's sync first yield):
253
265
  // the wake, as for the throw. Not a sync pass that superseded one — the
254
266
  // status it reads is the dead flight's, cleared when this pass settles
255
267
  // (#3181: a reader the settle walk had just released, re-parked for good).
256
- if (i.m & STATUS_PENDING && i.T.Se !== null && !i.ce && !d) wakeFamily(c, i.T?.F);
268
+ if (i.m & STATUS_PENDING && i.T.Ee !== null && !i.ce && !d) wakeFamily(c);
257
269
  return i;
258
270
  }
259
271
 
@@ -266,6 +278,7 @@ function createProjectionInternal(e, t, r) {
266
278
  map: new WeakMap,
267
279
  node: null,
268
280
  live: new Set,
281
+ st: familyStatus,
269
282
  shallow: !!r?.shallow,
270
283
  // The row key, for a child paired after the adoption (store.ts
271
284
  // `adoptChild`, #3712) as the adoption pairs them.
@@ -31,7 +31,7 @@ import { $TARGET, markRawIngest, isWrappable, rawValuesUsed, isRawValue } from "
31
31
  // truth but an optimistic edit — the keyed diff is written into the draft
32
32
  // (a matched row keeps its proxy, its changed leaves become its guesses),
33
33
  // and the setter's exit turns the draft into guesses like any.
34
- if (userWriting() && f.fam?.opt === true) {
34
+ if (optHooks && userWriting() && f.fam?.opt === true) {
35
35
  optHooks.reconcile(n, unwrapValue(e), i);
36
36
  return;
37
37
  }
@@ -72,7 +72,7 @@ import { $TARGET, markRawIngest, isWrappable, rawValuesUsed, isRawValue } from "
72
72
  // Q-D: a landing on an optimistic family is reconciled against the VIEW
73
73
  // — key matching from the arrangement the guesses made (R28), so a row
74
74
  // the guess added keeps its proxy when the server returns it.
75
- const i = e.fam?.opt === true ? optHooks.view(e, f) : f;
75
+ const i = optHooks && e.fam?.opt === true ? optHooks.view(e, f) : f;
76
76
  const l = Array.isArray(n);
77
77
  const r = e.s === true;
78
78
  adoptPB(e, n, false);