@solidjs/signals 2.0.0-rc.15 → 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 (90) hide show
  1. package/dist/dev-shared.js +2268 -1734
  2. package/dist/dev.attribution.js +75 -52
  3. package/dist/dev.js +1348 -658
  4. package/dist/observe/affects-marks.js +86 -0
  5. package/dist/observe/affects.js +22 -73
  6. package/dist/observe/boundaries.js +192 -190
  7. package/dist/observe/core/async.js +177 -131
  8. package/dist/observe/core/attribution-queries.js +1 -1
  9. package/dist/observe/core/attribution.js +176 -159
  10. package/dist/observe/core/constants.js +17 -3
  11. package/dist/observe/core/context.js +5 -3
  12. package/dist/observe/core/core.js +520 -364
  13. package/dist/observe/core/dev.js +66 -38
  14. package/dist/observe/core/effect.js +50 -48
  15. package/dist/observe/core/error.js +5 -3
  16. package/dist/observe/core/external.js +5 -6
  17. package/dist/observe/core/graph.js +60 -44
  18. package/dist/observe/core/heap.js +33 -33
  19. package/dist/observe/core/identities.js +62 -0
  20. package/dist/observe/core/lanes.js +238 -260
  21. package/dist/observe/core/owner.js +117 -79
  22. package/dist/observe/core/scheduler.js +381 -217
  23. package/dist/observe/core/truth.js +45 -0
  24. package/dist/observe/core/verdict.js +91 -50
  25. package/dist/observe/deferred.js +184 -0
  26. package/dist/observe/index.js +7 -1
  27. package/dist/observe/map.js +345 -260
  28. package/dist/observe/reveal.js +76 -76
  29. package/dist/observe/signals.js +47 -31
  30. package/dist/observe/store/affects.js +18 -18
  31. package/dist/observe/store/edges.js +39 -0
  32. package/dist/observe/store/optimistic.js +146 -100
  33. package/dist/observe/store/projection.js +68 -55
  34. package/dist/observe/store/store.js +180 -118
  35. package/dist/prod/affects-marks.js +86 -0
  36. package/dist/prod/affects.js +23 -72
  37. package/dist/prod/boundaries.js +156 -154
  38. package/dist/prod/core/async.js +173 -127
  39. package/dist/prod/core/constants.js +17 -3
  40. package/dist/prod/core/context.js +5 -3
  41. package/dist/prod/core/core.js +495 -343
  42. package/dist/prod/core/effect.js +70 -68
  43. package/dist/prod/core/error.js +5 -3
  44. package/dist/prod/core/external.js +5 -6
  45. package/dist/prod/core/graph.js +60 -44
  46. package/dist/prod/core/heap.js +38 -38
  47. package/dist/prod/core/identities.js +62 -0
  48. package/dist/prod/core/lanes.js +230 -252
  49. package/dist/prod/core/owner.js +114 -77
  50. package/dist/prod/core/scheduler.js +327 -163
  51. package/dist/prod/core/truth.js +45 -0
  52. package/dist/prod/core/verdict.js +90 -49
  53. package/dist/prod/deferred.js +182 -0
  54. package/dist/prod/index.js +7 -1
  55. package/dist/prod/map.js +360 -275
  56. package/dist/prod/reveal.js +76 -76
  57. package/dist/prod/signals.js +42 -26
  58. package/dist/prod/store/affects.js +6 -6
  59. package/dist/prod/store/edges.js +39 -0
  60. package/dist/prod/store/optimistic.js +143 -98
  61. package/dist/prod/store/projection.js +25 -19
  62. package/dist/prod/store/store.js +157 -100
  63. package/dist/types/affects-marks.d.ts +14 -0
  64. package/dist/types/boundaries.d.ts +1 -1
  65. package/dist/types/core/async.d.ts +10 -0
  66. package/dist/types/core/constants.d.ts +13 -1
  67. package/dist/types/core/core.d.ts +54 -5
  68. package/dist/types/core/dev.d.ts +51 -13
  69. package/dist/types/core/error.d.ts +9 -1
  70. package/dist/types/core/graph.d.ts +11 -0
  71. package/dist/types/core/identities.d.ts +17 -0
  72. package/dist/types/core/index.d.ts +2 -1
  73. package/dist/types/core/lanes.d.ts +2 -14
  74. package/dist/types/core/owner.d.ts +9 -3
  75. package/dist/types/core/scheduler.d.ts +70 -32
  76. package/dist/types/core/truth.d.ts +16 -0
  77. package/dist/types/core/types.d.ts +21 -0
  78. package/dist/types/core/verdict.d.ts +32 -0
  79. package/dist/types/deferred.d.ts +28 -0
  80. package/dist/types/index.d.ts +6 -0
  81. package/dist/types/map.d.ts +2 -2
  82. package/dist/types/signals.d.ts +28 -7
  83. package/dist/types/store/edges.d.ts +9 -0
  84. package/dist/types/store/index.d.ts +10 -3
  85. package/dist/types/store/optimistic.d.ts +3 -2
  86. package/dist/types/store/projection.d.ts +4 -3
  87. package/dist/types/store/store.d.ts +1 -1
  88. package/dist/types/store/target.d.ts +16 -8
  89. package/dist/types/store/types.d.ts +14 -0
  90. package/package.json +1 -1
@@ -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
- import { pendingGuessOf, laneValueOf, optimisticWrite } from "../core/lanes.js";
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
 
@@ -18,6 +18,8 @@ import { $OWNER } from "./target.js";
18
18
 
19
19
  import { $TARGET, markRawIngest, $TRACK, isWrappable } from "./types.js";
20
20
 
21
+ import { laneValueOf } from "../core/truth.js";
22
+
21
23
  /**
22
24
  * Store — optimistic stores on lanes (plan sec. 31, S4; INTERNALS §3/§7, RUL-3).
23
25
  *
@@ -81,7 +83,7 @@ function notifyOptimisticWrites(e, n) {
81
83
  // inner store's truth for its key before guessing over it.
82
84
  const o = e.ch ? e.v : null;
83
85
  const guess = (e, n, i, r) => {
84
- if (o !== null) e.Ae = i ? n in t : unwrapValue(t[n]);
86
+ if (o !== null) e.Ie = i ? n in t : unwrapValue(t[n]);
85
87
  // By value: a function leaf is a value, not an updater (#3017).
86
88
  optimisticWrite(e, () => r);
87
89
  };
@@ -91,16 +93,16 @@ function notifyOptimisticWrites(e, n) {
91
93
  // A chained draft holds the inner store's raws; a raw is the inner slot it
92
94
  // resolves to (as a read of it serves) — the row a held write staged is
93
95
  // the same row, not a guess over the slot (#3796).
94
- const a = n[t];
95
- 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);
96
98
  if (!(t in i)) {
97
99
  guess(getNode(e, t), t, false, f);
98
100
  guess(getHasNode(e, t), t, true, true);
99
101
  s = true;
100
102
  } else {
101
103
  const n = i[t];
102
- const a = unwrapValue(o && n ? resolveChainedRaw(e, t, n) : n);
103
- 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)) {
104
106
  guess(getNode(e, t), t, false, f);
105
107
  if (r) s = true;
106
108
  }
@@ -120,29 +122,31 @@ function notifyOptimisticWrites(e, n) {
120
122
  if (s) {
121
123
  const o = r ? n.map(unwrapValue) : shallowKeys(n);
122
124
  // The rows the setter removed from the view it saw, by key: a later
123
- // 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`).
124
127
  let s = null;
125
- const a = e.fam.key;
126
- if (r && a !== null && a !== undefined) {
128
+ const u = e.fam.key;
129
+ if (r && u !== null && u !== undefined) {
130
+ s = new Set;
127
131
  const e = new Set;
128
132
  for (let n = 0; n < o.length; n++) {
129
- const t = isWrappable(o[n]) ? a(o[n]) : undefined;
133
+ const t = isWrappable(o[n]) ? u(o[n]) : undefined;
130
134
  if (t !== undefined) e.add(t);
131
135
  }
132
136
  for (let n = 0; n < i.length; n++) {
133
137
  const t = unwrapValue(i[n]);
134
- const r = isWrappable(t) ? a(t) : undefined;
135
- 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);
136
140
  }
137
141
  }
138
142
  optimisticWrite(getContainerNode(e), new LaneView(o, t, s));
139
143
  }
140
144
  if (e.dk !== null) optimisticWrite(e.dk, {});
141
145
  markOverlaid(e);
142
- const a = optStaged.get(e);
143
- if (a === undefined) return null;
146
+ const u = optStaged.get(e);
147
+ if (u === undefined) return null;
144
148
  optStaged.delete(e);
145
- return a;
149
+ return u;
146
150
  }
147
151
 
148
152
  /** The container comparator's lane arm (store.ts `containerEquals`): an
@@ -185,7 +189,7 @@ function rowSame(e, n, t) {
185
189
 
186
190
  // A cycle (a row that references itself) is not plain data: no match, so
187
191
  // the landing stays a correction.
188
- GlobalQueue.tn = (e, n) => {
192
+ GlobalQueue.nn = (e, n) => {
189
193
  try {
190
194
  return echoes(e, n);
191
195
  } catch {
@@ -226,18 +230,18 @@ function arrangementEqual(e, n, t) {
226
230
  }
227
231
  }
228
232
  for (let s = 0; s < n.length; s++) {
229
- const a = n[s];
233
+ const u = n[s];
230
234
  let f;
231
- if (isWrappable(a)) {
235
+ if (isWrappable(u)) {
232
236
  if (o !== null) {
233
- const e = t(a);
237
+ const e = t(u);
234
238
  if (e !== undefined) f = o.get(e);
235
239
  } else if (s < i && isWrappable(unwrapValue(r[s]))) f = r[s];
236
240
  }
237
241
  if (f !== undefined) {
238
- if (unwrapValue(f) !== a) reconcileDraft(f, a, t);
242
+ if (unwrapValue(f) !== u) reconcileDraft(f, u, t);
239
243
  if (e[s] !== f) e[s] = f;
240
- } else if (unwrapValue(e[s]) !== a) e[s] = a;
244
+ } else if (unwrapValue(e[s]) !== u) e[s] = u;
241
245
  }
242
246
  if (e.length !== n.length) e.length = n.length;
243
247
  return;
@@ -266,66 +270,105 @@ function arrangementEqual(e, n, t) {
266
270
  * node is born for it as the lane's derivation), on `length` only when the
267
271
  * committed length differs, and as the `LaneView`'s base for structural
268
272
  * reads. Unkeyed families compose
269
- * positionally — the guess stands as written (the documented residue). */ GlobalQueue.an = (e, n) => {
270
- const t = e.lt;
271
- if (t === undefined || e.ot !== $TRACK) return;
272
- const i = e.m.B;
273
- if (!(i instanceof LaneView)) return;
274
- if (!Array.isArray(n) || !Array.isArray(i.rows)) {
275
- 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;
276
281
  return;
277
282
  }
278
- const r = t.fam?.key ?? null;
279
- if (r === null) return;
280
- const o = new Map;
283
+ const o = i.fam?.key ?? null;
284
+ if (o === null) return;
285
+ const s = new Map;
281
286
  for (let e = 0; e < n.length; e++) {
282
287
  const t = n[e];
283
- const i = isWrappable(t) ? r(t) : undefined;
284
- 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);
285
290
  }
286
- const s = new Set;
287
- const a = [];
288
- const f = i.rows;
289
- for (let e = 0; e < f.length; e++) {
290
- const n = f[e];
291
- const t = isWrappable(n) ? r(n) : undefined;
292
- 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;
293
298
  if (i !== undefined) {
294
- a.push(i);
295
- s.add(t);
296
- } else a.push(n);
299
+ f.push(i);
300
+ u.add(t);
301
+ } else f.push(n);
297
302
  }
298
- const u = i.removed;
303
+ const l = r.removed;
299
304
  for (let e = 0; e < n.length; e++) {
300
305
  const t = n[e];
301
- const i = isWrappable(t) ? r(t) : undefined;
302
- 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);
303
308
  }
304
- i.rows = a;
305
- i.base = a;
306
- const l = txOf(e);
307
- const c = committed(t);
308
- const d = t.n;
309
- for (let e = 0; e < a.length; e++) {
310
- 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];
311
316
  // A slot the lane does not own shows the committed row: it becomes the
312
317
  // lane's only where the composed row is another row (by key — the same
313
318
  // key's new object is the same row, its target adopted it).
314
319
  if (n === undefined) {
315
- if (!sameRow(c[e], a[e], r)) laneSet(getNode(t, e), a[e], l);
316
- } else if (!sameRow(n.i & CONFIG_OVERRIDE ? n.m.B : 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);
317
322
  }
318
- if (d !== null) {
319
- for (let e = a.length; ;e++) {
320
- const n = d[e];
323
+ if (p !== null) {
324
+ for (let e = f.length; ;e++) {
325
+ const n = p[e];
321
326
  if (n === undefined) break;
322
- laneSet(n, undefined, l);
327
+ laneSet(n, undefined, c);
323
328
  }
324
- const e = d.length;
325
- if (e !== undefined && (e.i & 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);
326
331
  }
327
332
  };
328
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
+
329
372
  function sameRow(e, n, t) {
330
373
  if (e === n) return true;
331
374
  if (!isWrappable(e) || !isWrappable(n)) return false;
@@ -337,12 +380,12 @@ function sameRow(e, n, t) {
337
380
  * node that was not the lane's becomes its derivation (its committed value
338
381
  * untouched beneath; the lane's end commits the latest). */ function laneSet(e, n, t) {
339
382
  const i = ext(e);
340
- if (!(e.i & CONFIG_OVERRIDE)) {
341
- e.i |= CONFIG_OVERRIDE;
383
+ if (!(e.l & CONFIG_OVERRIDE)) {
384
+ e.l |= CONFIG_OVERRIDE;
342
385
  list(e, t);
343
- } else if (i.B === n) return;
344
- i.B = n;
345
- if (e.t !== null) {
386
+ } else if (i.v === n) return;
387
+ i.v = n;
388
+ if (e.o !== null) {
346
389
  insertSubs(e);
347
390
  laneDirty(e, t);
348
391
  }
@@ -387,7 +430,7 @@ function sweepOverlaid() {
387
430
  // The container shows its backing again (a shown arrangement guess
388
431
  // that ended without a landing left its `LaneView` as the value).
389
432
  const t = e.k;
390
- if (t !== null && t.Ae instanceof LaneView) t.Ae = t.Ae.base;
433
+ if (t !== null && t.Ie instanceof LaneView) t.Ie = t.Ie.base;
391
434
  }
392
435
  if (n.size === 0) overlaidFamilies.delete(e);
393
436
  }
@@ -404,11 +447,11 @@ function sweepOverlaid() {
404
447
  if (i !== null) for (const e of Reflect.ownKeys(i)) {
405
448
  const r = i[e];
406
449
  const o = untrack(() => unwrapValue(n[e]));
407
- if (r.ye && r.ye(r.Ae, o)) continue;
408
- r.Ae = o;
450
+ if (r.xe && r.xe(r.Ie, o)) continue;
451
+ r.Ie = o;
409
452
  // (The lane's end notified it this epoch when the shown value and the
410
453
  // covered one differed — its readers re-derive already.)
411
- if (r.t !== null && r.qe !== notifyEpoch) {
454
+ if (r.o !== null && r.Me !== notifyEpoch) {
412
455
  insertSubs(r);
413
456
  t = true;
414
457
  }
@@ -417,9 +460,9 @@ function sweepOverlaid() {
417
460
  if (r !== null) for (const e of Reflect.ownKeys(r)) {
418
461
  const i = r[e];
419
462
  const o = untrack(() => e in n);
420
- if (i.Ae === o) continue;
421
- i.Ae = o;
422
- if (i.t !== null && i.qe !== notifyEpoch) {
463
+ if (i.Ie === o) continue;
464
+ i.Ie = o;
465
+ if (i.o !== null && i.Me !== notifyEpoch) {
423
466
  insertSubs(i);
424
467
  t = true;
425
468
  }
@@ -427,9 +470,9 @@ function sweepOverlaid() {
427
470
  // The arrangement the readers saw (the shown guess) against the inner's
428
471
  // now: a structural reader re-derives when they differ.
429
472
  const o = e.k;
430
- if (o !== null && o.t !== null && o.Ae instanceof LaneView && o.qe !== notifyEpoch) {
473
+ if (o !== null && o.o !== null && o.Ie instanceof LaneView && o.Me !== notifyEpoch) {
431
474
  const i = Array.isArray(n) ? untrack(() => n.map(unwrapValue)) : n;
432
- if (!arrangementEqual(o.Ae.rows, i, e.fam?.key ?? null)) {
475
+ if (!arrangementEqual(o.Ie.rows, i, e.fam?.key ?? null)) {
433
476
  insertSubs(o);
434
477
  t = true;
435
478
  }
@@ -438,12 +481,12 @@ function sweepOverlaid() {
438
481
  }
439
482
 
440
483
  function carriesLane(e) {
441
- if (e.k !== null && e.k.i & CONFIG_OVERRIDE) return true;
442
- if (e.dk !== null && e.dk.i & CONFIG_OVERRIDE) return true;
484
+ if (e.k !== null && e.k.l & CONFIG_OVERRIDE) return true;
485
+ if (e.dk !== null && e.dk.l & CONFIG_OVERRIDE) return true;
443
486
  const n = e.n;
444
- if (n !== null) for (const e of Reflect.ownKeys(n)) if (n[e].i & CONFIG_OVERRIDE) return true;
487
+ if (n !== null) for (const e of Reflect.ownKeys(n)) if (n[e].l & CONFIG_OVERRIDE) return true;
445
488
  const t = e.h;
446
- if (t !== null) for (const e of Reflect.ownKeys(t)) if (t[e].i & CONFIG_OVERRIDE) return true;
489
+ if (t !== null) for (const e of Reflect.ownKeys(t)) if (t[e].l & CONFIG_OVERRIDE) return true;
447
490
  return false;
448
491
  }
449
492
 
@@ -461,9 +504,9 @@ function overlaid(e) {
461
504
  * the backing answers. */ function optimisticHas(e, n) {
462
505
  if (!overlaid(e)) return undefined;
463
506
  const t = e.h?.[n];
464
- if (t !== undefined && t.i & CONFIG_OVERRIDE) return !!shown(t);
507
+ if (t !== undefined && t.l & CONFIG_OVERRIDE) return !!shown(t);
465
508
  const i = e.n?.[n];
466
- if (i !== undefined && i.i & CONFIG_OVERRIDE) return shown(i) !== undefined;
509
+ if (i !== undefined && i.l & CONFIG_OVERRIDE) return shown(i) !== undefined;
467
510
  return undefined;
468
511
  }
469
512
 
@@ -474,7 +517,7 @@ function overlaid(e) {
474
517
  if (t === undefined) return undefined;
475
518
  if (!t) return null;
476
519
  const i = e.n?.[n];
477
- const r = i !== undefined && i.i & CONFIG_OVERRIDE ? shown(i) : e.v[n];
520
+ const r = i !== undefined && i.l & CONFIG_OVERRIDE ? shown(i) : e.v[n];
478
521
  // An array's `length` is reported as the array has it (non-configurable).
479
522
  if (n === "length" && Array.isArray(e.v)) return {
480
523
  value: r,
@@ -507,7 +550,7 @@ i = false) {
507
550
  for (const e of Reflect.ownKeys(o)) {
508
551
  const r = o[e];
509
552
  let s;
510
- if (r.i & CONFIG_OVERRIDE) s = t(r); else if (!i || (s = pendingGuessOf(r)) === NOT_PENDING) continue;
553
+ if (r.l & CONFIG_OVERRIDE) s = t(r); else if (!i || (s = pendingGuessOf(r)) === NOT_PENDING) continue;
511
554
  if (e === "length" && Array.isArray(n)) {
512
555
  if (n.length !== s) ensure().length = s;
513
556
  } else if (!isEqual(n[e], s) || !hasOwn.call(n, e)) {
@@ -519,11 +562,11 @@ i = false) {
519
562
  if (s !== null) {
520
563
  for (const e of Reflect.ownKeys(s)) {
521
564
  const o = s[e];
522
- let a;
523
- if (o.i & CONFIG_OVERRIDE) a = t(o); else if (!i || (a = pendingGuessOf(o)) === NOT_PENDING) continue;
524
- const f = !!a;
525
- const u = r ?? n;
526
- 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];
527
570
  }
528
571
  }
529
572
  return r ?? n;
@@ -532,9 +575,11 @@ i = false) {
532
575
  function createOptimisticStore(e, n, t) {
533
576
  const i = typeof e === "function";
534
577
  const r = i ? t : n;
535
- const o = i ? n : e;
578
+ // Seedless derived form: the root starts as an empty record (see
579
+ // createProjectionInternal).
580
+ const o = i ? n || {} : e;
536
581
  const s = r?.key === undefined ? "id" : r.key;
537
- const a = {
582
+ const u = {
538
583
  map: new WeakMap,
539
584
  node: null,
540
585
  live: new Set,
@@ -542,8 +587,8 @@ function createOptimisticStore(e, n, t) {
542
587
  opt: true,
543
588
  key: typeof s === "function" ? s : s === null ? null : e => isWrappable(e) ? e[s] : undefined
544
589
  };
545
- const f = wrap(o, null, null, a);
546
- if (a.shallow) {
590
+ const f = wrap(o, null, null, u);
591
+ if (u.shallow) {
547
592
  f[$TARGET].s = true;
548
593
  markRawIngest(o);
549
594
  }
@@ -554,11 +599,11 @@ function createOptimisticStore(e, n, t) {
554
599
  loadingValue: undefined
555
600
  };
556
601
  const i = computed(() => {
557
- if (!a.node) a.node = getOwner();
602
+ if (!u.node) u.node = getOwner();
558
603
  runProjectionComputed(f, n, s);
559
604
  }, t);
560
- i.i &= ~CONFIG_AUTO_DISPOSE;
561
- a.node = i;
605
+ i.l &= ~CONFIG_AUTO_DISPOSE;
606
+ u.node = i;
562
607
  }
563
608
  return [ f, e => storeSetter(f, e) ];
564
609
  }
@@ -10,7 +10,7 @@ import { enqueueSub } from "../core/heap.js";
10
10
 
11
11
  import { getOwner, isDisposed } from "../core/owner.js";
12
12
 
13
- import { question, setQuestion, schedule } from "../core/scheduler.js";
13
+ import { question, setQuestion, insertSubs, schedule } from "../core/scheduler.js";
14
14
 
15
15
  import { reconcileState } from "./reconcile.js";
16
16
 
@@ -18,7 +18,7 @@ import { wrap, storeSetter, runDirect } from "./store.js";
18
18
 
19
19
  import { setLookup } from "./target.js";
20
20
 
21
- import { $TARGET, markRawIngest, setWriteOverride, isWrappable } from "./types.js";
21
+ import { $TARGET, markRawIngest, isWrappable, setWriteOverride } from "./types.js";
22
22
 
23
23
  /**
24
24
  * Store — projections (plan sec. 31, S3; INTERNALS §7/§7b).
@@ -122,7 +122,7 @@ function cloneState(e, t) {
122
122
  const r = e.node;
123
123
  e.woke = true;
124
124
  forEachFamilyNode(e, e => {
125
- if (e.t === null) return;
125
+ if (e.o === null) return;
126
126
  // The leaf carries the derive's pending as a propagated copy, as a memo
127
127
  // between them would: a dependent recovering one branch stays pending
128
128
  // through a leaf it still reads (core `retryReaches`), and the landing's
@@ -139,7 +139,7 @@ function cloneState(e, t) {
139
139
  /** The derive's flight rejected: every live reader of the family
140
140
  * re-derives (its pull throws the derive's error). */ function errorFamily(e) {
141
141
  forEachFamilyNode(e, e => {
142
- if (e.t === null) return;
142
+ if (e.o === null) return;
143
143
  forEachDependent(e, e => {
144
144
  enqueueSub(e);
145
145
  });
@@ -154,7 +154,7 @@ function cloneState(e, t) {
154
154
  e.woke = false;
155
155
  const t = e.node;
156
156
  forEachFamilyNode(e, e => {
157
- if (e.t !== null) settlePendingSource(e, t);
157
+ if (e.o !== null) settlePendingSource(e, t);
158
158
  });
159
159
  }
160
160
 
@@ -183,16 +183,16 @@ function forEachFamilyNode(e, t) {
183
183
  // for the whole first flight — the derive works a detached shadow of the
184
184
  // seed so draft writes cannot tear through to readers (#2988). Every
185
185
  // commit point reconciles the shadow through the normal commit path.
186
- const a = i.De ? cloneState(s.v, s.s) : null;
186
+ const a = i.ce ? cloneState(s.v, s.s) : null;
187
187
  // The question a write of this run answers: inside a slice, the slice's
188
188
  // (the sync pass); in a continuation — the flight still registered — the
189
189
  // flight's (`handleAsync` stamped it with the action that asked).
190
- const asking = () => question || (i.m !== null && i.m.Te !== null ? i.m._e : 0);
190
+ const asking = () => question || (i.T !== null && i.T.Se !== null ? i.T.Ee : 0);
191
191
  const f = wrapDraft(e, () => c.run === u && !isDisposed(i), o, s.s,
192
192
  // A write after the run returned (a continuation, a callback) arms the
193
193
  // drain itself when no landing will.
194
194
  () => {
195
- if (!(i.S & STATUS_PENDING) && !i.De) schedule();
195
+ if (!(i.m & STATUS_PENDING) && !i.ce) schedule();
196
196
  }, asking);
197
197
  // The creation run commits directly (a memo's first value is its
198
198
  // `_value`); every later run — a re-derive in a flush, an async landing
@@ -219,7 +219,12 @@ function forEachFamilyNode(e, t) {
219
219
  }
220
220
  // A landing (not the sync pass's own commit): the readers held
221
221
  // pending on the derive settle.
222
- if (!d || !(i.S & STATUS_UNINITIALIZED)) settleFamily(c);
222
+ if (!d || !(i.m & STATUS_UNINITIALIZED)) settleFamily(c);
223
+ // A commit is the derive's change for the readers that observed its
224
+ // flight (linked by `pullFamily`; a settled pull does not link), as
225
+ // a memo's landing is for its readers: one that caught the NotReady
226
+ // (a fallback value, not pending) re-runs too (#4070).
227
+ insertSubs(i);
223
228
  };
224
229
  const u = handleAsync(i, l, commit, (e, t) => {
225
230
  // The flight rejected: the leaves' readers learn it from here —
@@ -228,10 +233,10 @@ function forEachFamilyNode(e, t) {
228
233
  // reader re-derives and meets the error at its pull (memo parity,
229
234
  // #2897) — and the flush that runs them advances the clock, so a
230
235
  // later tracked re-read may retry (core `read`).
231
- if (d && i.S & STATUS_UNINITIALIZED) return;
236
+ if (d && i.m & STATUS_UNINITIALIZED) return;
232
237
  if (t) wakeFamily(c, e); else errorFamily(c);
233
238
  });
234
- if (!i.De) commit(u);
239
+ if (!i.ce) commit(u);
235
240
  }, false);
236
241
  try {
237
242
  d ? runDirect(pass) : pass();
@@ -248,11 +253,14 @@ function forEachFamilyNode(e, t) {
248
253
  // the wake, as for the throw. Not a sync pass that superseded one — the
249
254
  // status it reads is the dead flight's, cleared when this pass settles
250
255
  // (#3181: a reader the settle walk had just released, re-parked for good).
251
- if (i.S & STATUS_PENDING && i.m.Te !== null && !i.De && !d) wakeFamily(c, i.m?.F);
256
+ if (i.m & STATUS_PENDING && i.T.Se !== null && !i.ce && !d) wakeFamily(c, i.T?.F);
252
257
  return i;
253
258
  }
254
259
 
255
260
  function createProjectionInternal(e, t, r) {
261
+ // Seedless (`fn` takes no draft): the root starts as an empty record. It is
262
+ // a draft like any seed, never observable before the first landing (A25).
263
+ t ||= {};
256
264
  const n = r?.key === undefined ? "id" : r.key;
257
265
  const o = {
258
266
  map: new WeakMap,
@@ -276,20 +284,18 @@ function createProjectionInternal(e, t, r) {
276
284
  if (!o.node) o.node = getOwner();
277
285
  runProjectionComputed(i, e, n);
278
286
  }, s);
279
- c.i &= ~CONFIG_AUTO_DISPOSE;
287
+ c.l &= ~CONFIG_AUTO_DISPOSE;
280
288
  o.node = c;
289
+ // The derive's leaves are not its dependents: a mark's repoll
290
+ // (affects-marks.ts) reaches their readers through this.
291
+ c.fam = o;
281
292
  return {
282
293
  store: i,
283
294
  node: c
284
295
  };
285
296
  }
286
297
 
287
- /**
288
- * A derived store: `fn` runs in a computed and writes its draft; readers of
289
- * the store's keys re-run only when the keys they read change (the
290
- * firewall). `fn` may be async or an async iterator; the seed is a draft,
291
- * never an observable value, until the first landing (A25).
292
- */ function createProjection(e, t, r) {
298
+ function createProjection(e, t, r) {
293
299
  return createProjectionInternal(e, t, r).store;
294
300
  }
295
301