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

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 (98) hide show
  1. package/dist/dev-shared.js +882 -405
  2. package/dist/dev.attribution.js +172 -66
  3. package/dist/dev.js +1529 -745
  4. package/dist/observe/affects-marks.js +86 -0
  5. package/dist/observe/affects.js +32 -80
  6. package/dist/observe/boundaries.js +202 -166
  7. package/dist/observe/core/async.js +192 -141
  8. package/dist/observe/core/attribution-queries.js +1 -1
  9. package/dist/observe/core/attribution.js +315 -214
  10. package/dist/observe/core/constants.js +23 -4
  11. package/dist/observe/core/context.js +3 -3
  12. package/dist/observe/core/core.js +532 -360
  13. package/dist/observe/core/dev.js +63 -35
  14. package/dist/observe/core/effect.js +47 -47
  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 +56 -42
  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 +242 -229
  21. package/dist/observe/core/owner.js +62 -50
  22. package/dist/observe/core/scheduler.js +322 -168
  23. package/dist/observe/core/truth.js +45 -0
  24. package/dist/observe/core/verdict.js +114 -64
  25. package/dist/observe/deferred.js +184 -0
  26. package/dist/observe/index.js +7 -1
  27. package/dist/observe/map.js +339 -254
  28. package/dist/observe/reveal.js +77 -77
  29. package/dist/observe/signals.js +54 -33
  30. package/dist/observe/store/affects.js +76 -69
  31. package/dist/observe/store/edges.js +39 -0
  32. package/dist/observe/store/hooks.js +13 -0
  33. package/dist/observe/store/index.js +0 -2
  34. package/dist/observe/store/optimistic.js +82 -44
  35. package/dist/observe/store/projection.js +83 -64
  36. package/dist/observe/store/reconcile.js +32 -30
  37. package/dist/observe/store/store.js +219 -123
  38. package/dist/prod/affects-marks.js +86 -0
  39. package/dist/prod/affects.js +33 -79
  40. package/dist/prod/boundaries.js +185 -149
  41. package/dist/prod/core/async.js +176 -135
  42. package/dist/prod/core/constants.js +23 -4
  43. package/dist/prod/core/context.js +3 -3
  44. package/dist/prod/core/core.js +521 -353
  45. package/dist/prod/core/effect.js +66 -66
  46. package/dist/prod/core/error.js +5 -3
  47. package/dist/prod/core/external.js +5 -6
  48. package/dist/prod/core/graph.js +56 -42
  49. package/dist/prod/core/heap.js +38 -38
  50. package/dist/prod/core/identities.js +62 -0
  51. package/dist/prod/core/lanes.js +237 -224
  52. package/dist/prod/core/owner.js +62 -51
  53. package/dist/prod/core/scheduler.js +312 -158
  54. package/dist/prod/core/truth.js +45 -0
  55. package/dist/prod/core/verdict.js +113 -63
  56. package/dist/prod/deferred.js +182 -0
  57. package/dist/prod/index.js +7 -1
  58. package/dist/prod/map.js +366 -281
  59. package/dist/prod/reveal.js +77 -77
  60. package/dist/prod/signals.js +59 -38
  61. package/dist/prod/store/affects.js +76 -69
  62. package/dist/prod/store/edges.js +39 -0
  63. package/dist/prod/store/hooks.js +13 -0
  64. package/dist/prod/store/index.js +0 -2
  65. package/dist/prod/store/optimistic.js +121 -84
  66. package/dist/prod/store/projection.js +46 -34
  67. package/dist/prod/store/reconcile.js +32 -30
  68. package/dist/prod/store/store.js +205 -116
  69. package/dist/types/affects-marks.d.ts +14 -0
  70. package/dist/types/boundaries.d.ts +5 -1
  71. package/dist/types/core/async.d.ts +10 -0
  72. package/dist/types/core/attribution.d.ts +6 -2
  73. package/dist/types/core/constants.d.ts +18 -1
  74. package/dist/types/core/core.d.ts +77 -5
  75. package/dist/types/core/dev.d.ts +43 -13
  76. package/dist/types/core/graph.d.ts +11 -0
  77. package/dist/types/core/identities.d.ts +17 -0
  78. package/dist/types/core/index.d.ts +2 -1
  79. package/dist/types/core/lanes.d.ts +2 -4
  80. package/dist/types/core/owner.d.ts +5 -3
  81. package/dist/types/core/scheduler.d.ts +59 -34
  82. package/dist/types/core/truth.d.ts +16 -0
  83. package/dist/types/core/types.d.ts +21 -6
  84. package/dist/types/core/verdict.d.ts +32 -0
  85. package/dist/types/deferred.d.ts +28 -0
  86. package/dist/types/index.d.ts +6 -0
  87. package/dist/types/map.d.ts +2 -2
  88. package/dist/types/signals.d.ts +28 -7
  89. package/dist/types/store/affects.d.ts +11 -0
  90. package/dist/types/store/edges.d.ts +9 -0
  91. package/dist/types/store/hooks.d.ts +48 -0
  92. package/dist/types/store/index.d.ts +10 -4
  93. package/dist/types/store/optimistic.d.ts +3 -2
  94. package/dist/types/store/projection.d.ts +4 -3
  95. package/dist/types/store/store.d.ts +4 -39
  96. package/dist/types/store/target.d.ts +16 -8
  97. package/dist/types/store/types.d.ts +14 -0
  98. package/package.json +1 -1
@@ -2,7 +2,7 @@ import { CONFIG_OVERRIDE, CONFIG_AUTO_DISPOSE, NOT_PENDING } from "../core/const
2
2
 
3
3
  import { computed, 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
 
@@ -10,12 +10,16 @@ import { GlobalQueue, txOf, list, insertSubs, laneDirty, notifyEpoch, schedule }
10
10
 
11
11
  import { runProjectionComputed } from "./projection.js";
12
12
 
13
- import { wrap, storeSetter, LaneView, committed, getNode, unwrapValue, sameKey, installOptHooks, resolveChainedRaw, getHasNode, targetsEqual, getContainerNode, cloneRaw } from "./store.js";
13
+ import { wrap, storeSetter, LaneView, committed, getNode, unwrapValue, sameKey, resolveChainedRaw, getHasNode, targetsEqual, getContainerNode, cloneRaw } from "./store.js";
14
+
15
+ import { installOptHooks } from "./hooks.js";
14
16
 
15
17
  import { $OWNER } from "./target.js";
16
18
 
17
19
  import { $TARGET, markRawIngest, $TRACK, isWrappable } from "./types.js";
18
20
 
21
+ import { laneValueOf } from "../core/truth.js";
22
+
19
23
  /**
20
24
  * Store — optimistic stores on lanes (plan sec. 31, S4; INTERNALS §3/§7, RUL-3).
21
25
  *
@@ -79,7 +83,7 @@ function notifyOptimisticWrites(e, n) {
79
83
  // inner store's truth for its key before guessing over it.
80
84
  const o = e.ch ? e.v : null;
81
85
  const guess = (e, n, i, r) => {
82
- if (o !== null) e.pe = i ? n in t : unwrapValue(t[n]);
86
+ if (o !== null) e.Ie = i ? n in t : unwrapValue(t[n]);
83
87
  // By value: a function leaf is a value, not an updater (#3017).
84
88
  optimisticWrite(e, () => r);
85
89
  };
@@ -89,17 +93,17 @@ function notifyOptimisticWrites(e, n) {
89
93
  // A chained draft holds the inner store's raws; a raw is the inner slot it
90
94
  // resolves to (as a read of it serves) — the row a held write staged is
91
95
  // the same row, not a guess over the slot (#3796).
92
- const f = n[t];
93
- const a = unwrapValue(o && f ? resolveChainedRaw(e, t, f) : f);
96
+ const a = n[t];
97
+ const f = unwrapValue(o && a ? resolveChainedRaw(e, t, a) : a);
94
98
  if (!(t in i)) {
95
- guess(getNode(e, t), t, false, a);
99
+ guess(getNode(e, t), t, false, f);
96
100
  guess(getHasNode(e, t), t, true, true);
97
101
  s = true;
98
102
  } else {
99
103
  const n = i[t];
100
- const f = unwrapValue(o && n ? resolveChainedRaw(e, t, n) : n);
101
- if (!isEqual(f, a) && !targetsEqual(f, a)) {
102
- guess(getNode(e, t), t, false, a);
104
+ const a = unwrapValue(o && n ? resolveChainedRaw(e, t, n) : n);
105
+ if (!isEqual(a, f) && !targetsEqual(a, f)) {
106
+ guess(getNode(e, t), t, false, f);
103
107
  if (r) s = true;
104
108
  }
105
109
  }
@@ -120,16 +124,16 @@ function notifyOptimisticWrites(e, n) {
120
124
  // The rows the setter removed from the view it saw, by key: a later
121
125
  // re-base over another action's truth must not bring them back.
122
126
  let s = null;
123
- const f = e.fam.key;
124
- if (r && f !== null && f !== undefined) {
127
+ const a = e.fam.key;
128
+ if (r && a !== null && a !== undefined) {
125
129
  const e = new Set;
126
130
  for (let n = 0; n < o.length; n++) {
127
- const t = isWrappable(o[n]) ? f(o[n]) : undefined;
131
+ const t = isWrappable(o[n]) ? a(o[n]) : undefined;
128
132
  if (t !== undefined) e.add(t);
129
133
  }
130
134
  for (let n = 0; n < i.length; n++) {
131
135
  const t = unwrapValue(i[n]);
132
- const r = isWrappable(t) ? f(t) : undefined;
136
+ const r = isWrappable(t) ? a(t) : undefined;
133
137
  if (r !== undefined && !e.has(r)) (s ??= new Set).add(r);
134
138
  }
135
139
  }
@@ -137,10 +141,10 @@ function notifyOptimisticWrites(e, n) {
137
141
  }
138
142
  if (e.dk !== null) optimisticWrite(e.dk, {});
139
143
  markOverlaid(e);
140
- const f = optStaged.get(e);
141
- if (f === undefined) return null;
144
+ const a = optStaged.get(e);
145
+ if (a === undefined) return null;
142
146
  optStaged.delete(e);
143
- return f;
147
+ return a;
144
148
  }
145
149
 
146
150
  /** The container comparator's lane arm (store.ts `containerEquals`): an
@@ -157,9 +161,40 @@ function rowSame(e, n, t) {
157
161
  if (t === null || !isWrappable(e) || !isWrappable(n)) return false;
158
162
  const i = t(unwrapValue(e));
159
163
  const r = t(unwrapValue(n));
164
+ // Keyless rows are identified by position — reconcile's fallback when the
165
+ // key is missing. The caller already paired these by index, so two keyless
166
+ // rows are the same row and the landing confirms the arrangement instead of
167
+ // dissolving it. Dissolving held an external echo under the action, and a
168
+ // mainline `until` then timed out on a source that already contained it
169
+ // (#3898). Keyed rows still match only on the key.
170
+ if (i === undefined && r === undefined) return true;
160
171
  return i !== undefined && sameKey(i, r);
161
172
  }
162
173
 
174
+ /** Whether reconcile would write anything into `a` from `b`: wrappable
175
+ * pairs descend, leaves compare as its writes do. A key mismatch is a
176
+ * replacement, which a content difference already says. Plain data — the
177
+ * server's echo of a guessed row is a new object with the same contents. */ function echoes(e, n) {
178
+ if (e === n) return true;
179
+ if (!isWrappable(e) || !isWrappable(n)) return false;
180
+ e = unwrapValue(e);
181
+ n = unwrapValue(n);
182
+ const t = Object.keys(e);
183
+ if (Array.isArray(e) !== Array.isArray(n) || t.length !== Object.keys(n).length) return false;
184
+ for (const i of t) if (!hasOwn.call(n, i) || !echoes(e[i], n[i])) return false;
185
+ return true;
186
+ }
187
+
188
+ // A cycle (a row that references itself) is not plain data: no match, so
189
+ // the landing stays a correction.
190
+ GlobalQueue.nn = (e, n) => {
191
+ try {
192
+ return echoes(e, n);
193
+ } catch {
194
+ return false;
195
+ }
196
+ };
197
+
163
198
  function arrangementEqual(e, n, t) {
164
199
  if (Array.isArray(e) !== Array.isArray(n)) return false;
165
200
  if (Array.isArray(e)) {
@@ -193,18 +228,18 @@ function arrangementEqual(e, n, t) {
193
228
  }
194
229
  }
195
230
  for (let s = 0; s < n.length; s++) {
196
- const f = n[s];
197
- let a;
198
- if (isWrappable(f)) {
231
+ const a = n[s];
232
+ let f;
233
+ if (isWrappable(a)) {
199
234
  if (o !== null) {
200
- const e = t(f);
201
- if (e !== undefined) a = o.get(e);
202
- } else if (s < i && isWrappable(unwrapValue(r[s]))) a = r[s];
235
+ const e = t(a);
236
+ if (e !== undefined) f = o.get(e);
237
+ } else if (s < i && isWrappable(unwrapValue(r[s]))) f = r[s];
203
238
  }
204
- if (a !== undefined) {
205
- if (unwrapValue(a) !== f) reconcileDraft(a, f, t);
206
- if (e[s] !== a) e[s] = a;
207
- } else if (unwrapValue(e[s]) !== f) e[s] = f;
239
+ if (f !== undefined) {
240
+ if (unwrapValue(f) !== a) reconcileDraft(f, a, t);
241
+ if (e[s] !== f) e[s] = f;
242
+ } else if (unwrapValue(e[s]) !== a) e[s] = a;
208
243
  }
209
244
  if (e.length !== n.length) e.length = n.length;
210
245
  return;
@@ -233,10 +268,10 @@ function arrangementEqual(e, n, t) {
233
268
  * node is born for it as the lane's derivation), on `length` only when the
234
269
  * committed length differs, and as the `LaneView`'s base for structural
235
270
  * reads. Unkeyed families compose
236
- * positionally — the guess stands as written (the documented residue). */ GlobalQueue.En = (e, n) => {
237
- const t = e.ot;
238
- if (t === undefined || e.rt !== $TRACK) return;
239
- const i = e.m.Z;
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;
240
275
  if (!(i instanceof LaneView)) return;
241
276
  if (!Array.isArray(n) || !Array.isArray(i.rows)) {
242
277
  i.base = n;
@@ -251,45 +286,45 @@ function arrangementEqual(e, n, t) {
251
286
  if (i !== undefined && !o.has(i)) o.set(i, t);
252
287
  }
253
288
  const s = new Set;
254
- const f = [];
255
- const a = i.rows;
256
- for (let e = 0; e < a.length; e++) {
257
- const n = a[e];
289
+ const a = [];
290
+ const f = i.rows;
291
+ for (let e = 0; e < f.length; e++) {
292
+ const n = f[e];
258
293
  const t = isWrappable(n) ? r(n) : undefined;
259
294
  const i = t !== undefined ? o.get(t) : undefined;
260
295
  if (i !== undefined) {
261
- f.push(i);
296
+ a.push(i);
262
297
  s.add(t);
263
- } else f.push(n);
298
+ } else a.push(n);
264
299
  }
265
- const l = i.removed;
300
+ const u = i.removed;
266
301
  for (let e = 0; e < n.length; e++) {
267
302
  const t = n[e];
268
303
  const i = isWrappable(t) ? r(t) : undefined;
269
- if (i !== undefined && !s.has(i) && (l === null || !l.has(i))) f.push(t);
304
+ if (i !== undefined && !s.has(i) && (u === null || !u.has(i))) a.push(t);
270
305
  }
271
- i.rows = f;
272
- i.base = f;
273
- const u = txOf(e);
306
+ i.rows = a;
307
+ i.base = a;
308
+ const l = txOf(e);
274
309
  const c = committed(t);
275
310
  const d = t.n;
276
- for (let e = 0; e < f.length; e++) {
311
+ for (let e = 0; e < a.length; e++) {
277
312
  const n = d?.[e];
278
313
  // A slot the lane does not own shows the committed row: it becomes the
279
314
  // lane's only where the composed row is another row (by key — the same
280
315
  // key's new object is the same row, its target adopted it).
281
316
  if (n === undefined) {
282
- if (!sameRow(c[e], f[e], r)) laneSet(getNode(t, e), f[e], u);
283
- } else if (!sameRow(n.u & CONFIG_OVERRIDE ? n.m.Z : c[e], f[e], r)) laneSet(n, f[e], u);
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);
284
319
  }
285
320
  if (d !== null) {
286
- for (let e = f.length; ;e++) {
321
+ for (let e = a.length; ;e++) {
287
322
  const n = d[e];
288
323
  if (n === undefined) break;
289
- laneSet(n, undefined, u);
324
+ laneSet(n, undefined, l);
290
325
  }
291
326
  const e = d.length;
292
- if (e !== undefined && (e.u & CONFIG_OVERRIDE || c.length !== f.length)) laneSet(e, f.length, u);
327
+ if (e !== undefined && (e.l & CONFIG_OVERRIDE || c.length !== a.length)) laneSet(e, a.length, l);
293
328
  }
294
329
  };
295
330
 
@@ -304,12 +339,12 @@ function sameRow(e, n, t) {
304
339
  * node that was not the lane's becomes its derivation (its committed value
305
340
  * untouched beneath; the lane's end commits the latest). */ function laneSet(e, n, t) {
306
341
  const i = ext(e);
307
- if (!(e.u & CONFIG_OVERRIDE)) {
308
- e.u |= CONFIG_OVERRIDE;
342
+ if (!(e.l & CONFIG_OVERRIDE)) {
343
+ e.l |= CONFIG_OVERRIDE;
309
344
  list(e, t);
310
- } else if (i.Z === n) return;
311
- i.Z = n;
312
- if (e.t !== null) {
345
+ } else if (i.v === n) return;
346
+ i.v = n;
347
+ if (e.o !== null) {
313
348
  insertSubs(e);
314
349
  laneDirty(e, t);
315
350
  }
@@ -354,7 +389,7 @@ function sweepOverlaid() {
354
389
  // The container shows its backing again (a shown arrangement guess
355
390
  // that ended without a landing left its `LaneView` as the value).
356
391
  const t = e.k;
357
- if (t !== null && t.pe instanceof LaneView) t.pe = t.pe.base;
392
+ if (t !== null && t.Ie instanceof LaneView) t.Ie = t.Ie.base;
358
393
  }
359
394
  if (n.size === 0) overlaidFamilies.delete(e);
360
395
  }
@@ -371,11 +406,11 @@ function sweepOverlaid() {
371
406
  if (i !== null) for (const e of Reflect.ownKeys(i)) {
372
407
  const r = i[e];
373
408
  const o = untrack(() => unwrapValue(n[e]));
374
- if (r.We && r.We(r.pe, o)) continue;
375
- r.pe = o;
409
+ if (r.xe && r.xe(r.Ie, o)) continue;
410
+ r.Ie = o;
376
411
  // (The lane's end notified it this epoch when the shown value and the
377
412
  // covered one differed — its readers re-derive already.)
378
- if (r.t !== null && r.ze !== notifyEpoch) {
413
+ if (r.o !== null && r.Me !== notifyEpoch) {
379
414
  insertSubs(r);
380
415
  t = true;
381
416
  }
@@ -384,9 +419,9 @@ function sweepOverlaid() {
384
419
  if (r !== null) for (const e of Reflect.ownKeys(r)) {
385
420
  const i = r[e];
386
421
  const o = untrack(() => e in n);
387
- if (i.pe === o) continue;
388
- i.pe = o;
389
- if (i.t !== null && i.ze !== notifyEpoch) {
422
+ if (i.Ie === o) continue;
423
+ i.Ie = o;
424
+ if (i.o !== null && i.Me !== notifyEpoch) {
390
425
  insertSubs(i);
391
426
  t = true;
392
427
  }
@@ -394,9 +429,9 @@ function sweepOverlaid() {
394
429
  // The arrangement the readers saw (the shown guess) against the inner's
395
430
  // now: a structural reader re-derives when they differ.
396
431
  const o = e.k;
397
- if (o !== null && o.t !== null && o.pe instanceof LaneView && o.ze !== notifyEpoch) {
432
+ if (o !== null && o.o !== null && o.Ie instanceof LaneView && o.Me !== notifyEpoch) {
398
433
  const i = Array.isArray(n) ? untrack(() => n.map(unwrapValue)) : n;
399
- if (!arrangementEqual(o.pe.rows, i, e.fam?.key ?? null)) {
434
+ if (!arrangementEqual(o.Ie.rows, i, e.fam?.key ?? null)) {
400
435
  insertSubs(o);
401
436
  t = true;
402
437
  }
@@ -405,12 +440,12 @@ function sweepOverlaid() {
405
440
  }
406
441
 
407
442
  function carriesLane(e) {
408
- if (e.k !== null && e.k.u & CONFIG_OVERRIDE) return true;
409
- if (e.dk !== null && e.dk.u & CONFIG_OVERRIDE) return true;
443
+ if (e.k !== null && e.k.l & CONFIG_OVERRIDE) return true;
444
+ if (e.dk !== null && e.dk.l & CONFIG_OVERRIDE) return true;
410
445
  const n = e.n;
411
- if (n !== null) for (const e of Reflect.ownKeys(n)) if (n[e].u & CONFIG_OVERRIDE) return true;
446
+ if (n !== null) for (const e of Reflect.ownKeys(n)) if (n[e].l & CONFIG_OVERRIDE) return true;
412
447
  const t = e.h;
413
- if (t !== null) for (const e of Reflect.ownKeys(t)) if (t[e].u & CONFIG_OVERRIDE) return true;
448
+ if (t !== null) for (const e of Reflect.ownKeys(t)) if (t[e].l & CONFIG_OVERRIDE) return true;
414
449
  return false;
415
450
  }
416
451
 
@@ -428,9 +463,9 @@ function overlaid(e) {
428
463
  * the backing answers. */ function optimisticHas(e, n) {
429
464
  if (!overlaid(e)) return undefined;
430
465
  const t = e.h?.[n];
431
- if (t !== undefined && t.u & CONFIG_OVERRIDE) return !!shown(t);
466
+ if (t !== undefined && t.l & CONFIG_OVERRIDE) return !!shown(t);
432
467
  const i = e.n?.[n];
433
- if (i !== undefined && i.u & CONFIG_OVERRIDE) return shown(i) !== undefined;
468
+ if (i !== undefined && i.l & CONFIG_OVERRIDE) return shown(i) !== undefined;
434
469
  return undefined;
435
470
  }
436
471
 
@@ -441,7 +476,7 @@ function overlaid(e) {
441
476
  if (t === undefined) return undefined;
442
477
  if (!t) return null;
443
478
  const i = e.n?.[n];
444
- const r = i !== undefined && i.u & CONFIG_OVERRIDE ? shown(i) : e.v[n];
479
+ const r = i !== undefined && i.l & CONFIG_OVERRIDE ? shown(i) : e.v[n];
445
480
  // An array's `length` is reported as the array has it (non-configurable).
446
481
  if (n === "length" && Array.isArray(e.v)) return {
447
482
  value: r,
@@ -474,7 +509,7 @@ i = false) {
474
509
  for (const e of Reflect.ownKeys(o)) {
475
510
  const r = o[e];
476
511
  let s;
477
- if (r.u & CONFIG_OVERRIDE) s = t(r); else if (!i || (s = pendingGuessOf(r)) === NOT_PENDING) continue;
512
+ if (r.l & CONFIG_OVERRIDE) s = t(r); else if (!i || (s = pendingGuessOf(r)) === NOT_PENDING) continue;
478
513
  if (e === "length" && Array.isArray(n)) {
479
514
  if (n.length !== s) ensure().length = s;
480
515
  } else if (!isEqual(n[e], s) || !hasOwn.call(n, e)) {
@@ -486,11 +521,11 @@ i = false) {
486
521
  if (s !== null) {
487
522
  for (const e of Reflect.ownKeys(s)) {
488
523
  const o = s[e];
489
- let f;
490
- if (o.u & CONFIG_OVERRIDE) f = t(o); else if (!i || (f = pendingGuessOf(o)) === NOT_PENDING) continue;
491
- const a = !!f;
492
- const l = r ?? n;
493
- if (!a && e in l) delete ensure()[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];
494
529
  }
495
530
  }
496
531
  return r ?? n;
@@ -499,9 +534,11 @@ i = false) {
499
534
  function createOptimisticStore(e, n, t) {
500
535
  const i = typeof e === "function";
501
536
  const r = i ? t : n;
502
- const o = i ? n : e;
537
+ // Seedless derived form: the root starts as an empty record (see
538
+ // createProjectionInternal).
539
+ const o = i ? n || {} : e;
503
540
  const s = r?.key === undefined ? "id" : r.key;
504
- const f = {
541
+ const a = {
505
542
  map: new WeakMap,
506
543
  node: null,
507
544
  live: new Set,
@@ -509,9 +546,9 @@ function createOptimisticStore(e, n, t) {
509
546
  opt: true,
510
547
  key: typeof s === "function" ? s : s === null ? null : e => isWrappable(e) ? e[s] : undefined
511
548
  };
512
- const a = wrap(o, null, null, f);
513
- if (f.shallow) {
514
- a[$TARGET].s = true;
549
+ const f = wrap(o, null, null, a);
550
+ if (a.shallow) {
551
+ f[$TARGET].s = true;
515
552
  markRawIngest(o);
516
553
  }
517
554
  if (i) {
@@ -521,13 +558,13 @@ function createOptimisticStore(e, n, t) {
521
558
  loadingValue: undefined
522
559
  };
523
560
  const i = computed(() => {
524
- if (!f.node) f.node = getOwner();
525
- runProjectionComputed(a, n, s);
561
+ if (!a.node) a.node = getOwner();
562
+ runProjectionComputed(f, n, s);
526
563
  }, t);
527
- i.u &= ~CONFIG_AUTO_DISPOSE;
528
- f.node = i;
564
+ i.l &= ~CONFIG_AUTO_DISPOSE;
565
+ a.node = i;
529
566
  }
530
- return [ a, e => storeSetter(a, e) ];
567
+ return [ f, e => storeSetter(f, e) ];
531
568
  }
532
569
 
533
570
  export { createOptimisticStore, notifyOptimisticWrites, optimisticHas, optimisticOwnDescriptor, optimisticView, sweepOverlaid };
@@ -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 } 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._e ? 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.De !== null ? i.m.Oe : 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.G & STATUS_PENDING) && !i._e) 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.G & 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.G & 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._e) commit(u);
239
+ if (!i.ce) commit(u);
235
240
  }, false);
236
241
  try {
237
242
  d ? runDirect(pass) : pass();
@@ -239,51 +244,58 @@ function forEachFamilyNode(e, t) {
239
244
  // A flight went up (NotReady out of the pass — the derive's own, with
240
245
  // the derive as its source): the leaves' readers learn it from here —
241
246
  // they do not subscribe to the derive.
242
- if (e instanceof NotReadyError && !d) wakeFamily(c, e);
247
+ // A synchronous error the same way (#3956: a rerun that finds the
248
+ // entry failed throws): every live reader re-derives and meets it.
249
+ if (!d) e instanceof NotReadyError ? wakeFamily(c, e) : errorFamily(c);
243
250
  throw e;
244
251
  }
245
252
  // A pass that returned with a flight up (an iterator's sync first yield):
246
253
  // the wake, as for the throw. Not a sync pass that superseded one — the
247
254
  // status it reads is the dead flight's, cleared when this pass settles
248
255
  // (#3181: a reader the settle walk had just released, re-parked for good).
249
- if (i.G & STATUS_PENDING && i.m.De !== null && !i._e && !d) wakeFamily(c, i.m?.V);
256
+ if (i.m & STATUS_PENDING && i.T.Se !== null && !i.ce && !d) wakeFamily(c, i.T?.F);
250
257
  return i;
251
258
  }
252
259
 
253
260
  function createProjectionInternal(e, t, r) {
254
- const n = {
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 ||= {};
264
+ const n = r?.key === undefined ? "id" : r.key;
265
+ const o = {
255
266
  map: new WeakMap,
256
267
  node: null,
257
268
  live: new Set,
258
- shallow: !!r?.shallow
269
+ shallow: !!r?.shallow,
270
+ // The row key, for a child paired after the adoption (store.ts
271
+ // `adoptChild`, #3712) as the adoption pairs them.
272
+ key: typeof n === "function" ? n : n === null ? null : e => isWrappable(e) ? e[n] : undefined
259
273
  };
260
- const o = wrap(t, null, null, n);
261
- if (n.shallow) {
262
- o[$TARGET].s = true;
274
+ const i = wrap(t, null, null, o);
275
+ if (o.shallow) {
276
+ i[$TARGET].s = true;
263
277
  markRawIngest(t);
264
278
  }
265
- let i;
266
- if (r?.seedLoadingValue) i = {
279
+ let s;
280
+ if (r?.seedLoadingValue) s = {
267
281
  loadingValue: undefined
268
282
  };
269
- const s = computed(() => {
270
- if (!n.node) n.node = getOwner();
271
- runProjectionComputed(o, e, r?.key === undefined ? "id" : r.key);
272
- }, i);
273
- s.u &= ~CONFIG_AUTO_DISPOSE;
274
- n.node = s;
283
+ const c = computed(() => {
284
+ if (!o.node) o.node = getOwner();
285
+ runProjectionComputed(i, e, n);
286
+ }, s);
287
+ c.l &= ~CONFIG_AUTO_DISPOSE;
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;
275
292
  return {
276
- store: o,
277
- node: s
293
+ store: i,
294
+ node: c
278
295
  };
279
296
  }
280
297
 
281
- /**
282
- * A derived store: `fn` runs in a computed and writes its draft; readers of
283
- * the store's keys re-run only when the keys they read change (the
284
- * firewall). `fn` may be async or an async iterator; the seed is a draft,
285
- * never an observable value, until the first landing (A25).
286
- */ function createProjection(e, t, r) {
298
+ function createProjection(e, t, r) {
287
299
  return createProjectionInternal(e, t, r).store;
288
300
  }
289
301