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

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 (74) hide show
  1. package/dist/dev-shared.js +553 -264
  2. package/dist/dev.attribution.js +18 -18
  3. package/dist/dev.js +1030 -439
  4. package/dist/observe/affects.js +12 -2
  5. package/dist/observe/boundaries.js +168 -115
  6. package/dist/observe/core/async.js +57 -37
  7. package/dist/observe/core/attribution.js +6 -6
  8. package/dist/observe/core/constants.js +9 -1
  9. package/dist/observe/core/copies.js +10 -0
  10. package/dist/observe/core/core.js +261 -181
  11. package/dist/observe/core/effect.js +32 -27
  12. package/dist/observe/core/graph.js +7 -7
  13. package/dist/observe/core/heap.js +29 -29
  14. package/dist/observe/core/lanes.js +301 -101
  15. package/dist/observe/core/owner.js +13 -13
  16. package/dist/observe/core/scheduler.js +124 -69
  17. package/dist/observe/core/truth.js +9 -7
  18. package/dist/observe/core/verdict.js +160 -98
  19. package/dist/observe/deferred.js +1 -1
  20. package/dist/observe/index.js +2 -0
  21. package/dist/observe/map.js +120 -116
  22. package/dist/observe/reveal.js +48 -48
  23. package/dist/observe/signals.js +5 -5
  24. package/dist/observe/store/affects.js +2 -2
  25. package/dist/observe/store/optimistic.js +272 -176
  26. package/dist/observe/store/projection.js +21 -10
  27. package/dist/observe/store/reconcile.js +8 -2
  28. package/dist/observe/store/store.js +91 -55
  29. package/dist/observe/store/types.js +11 -1
  30. package/dist/observe/store/utils.js +1 -1
  31. package/dist/prod/affects.js +12 -2
  32. package/dist/prod/boundaries.js +164 -109
  33. package/dist/prod/core/async.js +201 -181
  34. package/dist/prod/core/constants.js +9 -1
  35. package/dist/prod/core/copies.js +10 -0
  36. package/dist/prod/core/core.js +244 -164
  37. package/dist/prod/core/dev.js +108 -3
  38. package/dist/prod/core/effect.js +28 -23
  39. package/dist/prod/core/graph.js +9 -9
  40. package/dist/prod/core/heap.js +16 -16
  41. package/dist/prod/core/identities.js +1 -1
  42. package/dist/prod/core/lanes.js +307 -95
  43. package/dist/prod/core/owner.js +22 -22
  44. package/dist/prod/core/scheduler.js +266 -211
  45. package/dist/prod/core/truth.js +9 -7
  46. package/dist/prod/core/verdict.js +161 -99
  47. package/dist/prod/deferred.js +1 -1
  48. package/dist/prod/index.js +2 -0
  49. package/dist/prod/map.js +78 -74
  50. package/dist/prod/reveal.js +34 -34
  51. package/dist/prod/signals.js +3 -3
  52. package/dist/prod/store/affects.js +15 -15
  53. package/dist/prod/store/optimistic.js +185 -89
  54. package/dist/prod/store/projection.js +49 -38
  55. package/dist/prod/store/reconcile.js +8 -2
  56. package/dist/prod/store/store.js +99 -63
  57. package/dist/prod/store/types.js +11 -1
  58. package/dist/types/affects.d.ts +3 -2
  59. package/dist/types/boundaries.d.ts +14 -2
  60. package/dist/types/core/async.d.ts +2 -1
  61. package/dist/types/core/constants.d.ts +8 -0
  62. package/dist/types/core/copies.d.ts +54 -0
  63. package/dist/types/core/core.d.ts +15 -0
  64. package/dist/types/core/dev.d.ts +1 -1
  65. package/dist/types/core/lanes.d.ts +8 -1
  66. package/dist/types/core/scheduler.d.ts +36 -4
  67. package/dist/types/core/truth.d.ts +3 -1
  68. package/dist/types/core/types.d.ts +6 -0
  69. package/dist/types/index.d.ts +2 -0
  70. package/dist/types/store/hooks.d.ts +15 -1
  71. package/dist/types/store/store.d.ts +2 -1
  72. package/dist/types/store/target.d.ts +5 -0
  73. package/dist/types/store/types.d.ts +7 -0
  74. package/package.json +1 -1
@@ -1,20 +1,22 @@
1
- import { CONFIG_OVERRIDE, CONFIG_GUESS, EFFECT_RENDER, CONFIG_CHILDREN_FORBIDDEN, NOT_PENDING, CONFIG_SLOT_NODE, CONFIG_AUTO_DISPOSE } from "../core/constants.js";
1
+ import { CONFIG_GUESS, CONFIG_OVERRIDE, EFFECT_RENDER, CONFIG_CHILDREN_FORBIDDEN, NOT_PENDING, CONFIG_SLOT_NODE, CONFIG_AUTO_DISPOSE, REACTIVE_REASK } from "../core/constants.js";
2
2
 
3
- import { computed, joinPassAt, ext, untrack, read, isEqual } from "../core/core.js";
3
+ import { computed, isEqual, joinPassAt, ext, untrack, read } from "../core/core.js";
4
4
 
5
- import { pendingGuessOf, optimisticWrite } from "../core/lanes.js";
5
+ import { take, pendingGuessOf, optimisticWrite } from "../core/lanes.js";
6
6
 
7
7
  import { getOwner } from "../core/owner.js";
8
8
 
9
- import { GlobalQueue, txOf, insertSubs, joinFuture, resolveTx, passLane, list, laneDirty, notifyEpoch, schedule } from "../core/scheduler.js";
9
+ import { GlobalQueue, txOf, insertSubs, joinFuture, resolveTx, passLane, list, laneDirty, clock, merge, notifyEpoch, schedule } from "../core/scheduler.js";
10
10
 
11
11
  import { runProjectionComputed } from "./projection.js";
12
12
 
13
- import { wrap, storeSetter, LaneView, committed, getNode, unwrapValue, sameKey, resolveChainedRaw, getHasNode, targetsEqual, getContainerNode, cloneRaw } from "./store.js";
13
+ import { reconcileState } from "./reconcile.js";
14
+
15
+ import { wrap, storeSetter, getContainerNode, getHasNode, getNode, LaneView, committed, unwrapValue, sameKey, resolveChainedRaw, targetsEqual, cloneRaw } from "./store.js";
14
16
 
15
17
  import { installOptHooks } from "./hooks.js";
16
18
 
17
- import { $OWNER } from "./target.js";
19
+ import { $OWNER, lookupTarget } from "./target.js";
18
20
 
19
21
  import { $TARGET, markRawIngest, $TRACK, isWrappable } from "./types.js";
20
22
 
@@ -93,17 +95,17 @@ function notifyOptimisticWrites(e, n) {
93
95
  // A chained draft holds the inner store's raws; a raw is the inner slot it
94
96
  // resolves to (as a read of it serves) — the row a held write staged is
95
97
  // the same row, not a guess over the slot (#3796).
96
- const u = n[t];
97
- const f = unwrapValue(o && u ? resolveChainedRaw(e, t, u) : u);
98
+ const f = n[t];
99
+ const a = unwrapValue(o && f ? resolveChainedRaw(e, t, f) : f);
98
100
  if (!(t in i)) {
99
- guess(getNode(e, t), t, false, f);
101
+ guess(getNode(e, t), t, false, a);
100
102
  guess(getHasNode(e, t), t, true, true);
101
103
  s = true;
102
104
  } else {
103
105
  const n = i[t];
104
- const u = unwrapValue(o && n ? resolveChainedRaw(e, t, n) : n);
105
- if (!isEqual(u, f) && !targetsEqual(u, f)) {
106
- guess(getNode(e, t), t, false, f);
106
+ const f = unwrapValue(o && n ? resolveChainedRaw(e, t, n) : n);
107
+ if (!isEqual(f, a) && !targetsEqual(f, a)) {
108
+ guess(getNode(e, t), t, false, a);
107
109
  if (r) s = true;
108
110
  }
109
111
  }
@@ -125,17 +127,17 @@ function notifyOptimisticWrites(e, n) {
125
127
  // re-base over another action's truth must not bring them back. A set
126
128
  // (empty or not) marks a keyed arrangement guess (`fold`).
127
129
  let s = null;
128
- const u = e.fam.key;
129
- if (r && u !== null && u !== undefined) {
130
+ const f = e.fam.key;
131
+ if (r && f !== null && f !== undefined) {
130
132
  s = new Set;
131
133
  const e = new Set;
132
134
  for (let n = 0; n < o.length; n++) {
133
- const t = isWrappable(o[n]) ? u(o[n]) : undefined;
135
+ const t = isWrappable(o[n]) ? f(o[n]) : undefined;
134
136
  if (t !== undefined) e.add(t);
135
137
  }
136
138
  for (let n = 0; n < i.length; n++) {
137
139
  const t = unwrapValue(i[n]);
138
- const r = isWrappable(t) ? u(t) : undefined;
140
+ const r = isWrappable(t) ? f(t) : undefined;
139
141
  if (r !== undefined && !e.has(r)) s.add(r);
140
142
  }
141
143
  }
@@ -143,10 +145,10 @@ function notifyOptimisticWrites(e, n) {
143
145
  }
144
146
  if (e.dk !== null) optimisticWrite(e.dk, {});
145
147
  markOverlaid(e);
146
- const u = optStaged.get(e);
147
- if (u === undefined) return null;
148
+ const f = optStaged.get(e);
149
+ if (f === undefined) return null;
148
150
  optStaged.delete(e);
149
- return u;
151
+ return f;
150
152
  }
151
153
 
152
154
  /** The container comparator's lane arm (store.ts `containerEquals`): an
@@ -155,22 +157,24 @@ function notifyOptimisticWrites(e, n) {
155
157
  const i = n instanceof LaneView;
156
158
  const r = t instanceof LaneView;
157
159
  if (!i && !r) return false;
158
- return arrangementEqual(i ? n.rows : n, r ? t.rows : t, e.fam?.key ?? null);
160
+ return arrangementEqual(i ? n.rows : n, r ? t.rows : t, e.fam);
159
161
  }
160
162
 
161
163
  function rowSame(e, n, t) {
162
164
  if (isEqual(e, n) || targetsEqual(e, n)) return true;
163
- if (t === null || !isWrappable(e) || !isWrappable(n)) return false;
164
- const i = t(unwrapValue(e));
165
- const r = t(unwrapValue(n));
166
- // Keyless rows are identified by position — reconcile's fallback when the
167
- // key is missing. The caller already paired these by index, so two keyless
168
- // rows are the same row and the landing confirms the arrangement instead of
169
- // dissolving it. Dissolving held an external echo under the action, and a
170
- // mainline `until` then timed out on a source that already contained it
171
- // (#3898). Keyed rows still match only on the key.
172
- if (i === undefined && r === undefined) return true;
173
- return i !== undefined && sameKey(i, r);
165
+ const i = t.key;
166
+ if (!i || !isWrappable(e) || !isWrappable(n)) return false;
167
+ // A row the store already serves is its proxy's row: a reader (a list)
168
+ // holds that proxy, so another object at the index is another row, by key
169
+ // or contents alike — a guess's fresh object wraps a new proxy. A landing's
170
+ // object has been adopted by the row it pairs with, so it serves that
171
+ // row's proxy. Only rows no proxy serves yet pair by key, keyless rows by
172
+ // position — reconcile's fallback (#3898).
173
+ const r = lookupTarget(e = unwrapValue(e), t);
174
+ const o = lookupTarget(n = unwrapValue(n), t);
175
+ if (r || o) return r === o;
176
+ // (Two keyless rows: `undefined` is the same key.)
177
+ return sameKey(i(e), i(n));
174
178
  }
175
179
 
176
180
  /** Whether reconcile would write anything into `a` from `b`: wrappable
@@ -230,18 +234,18 @@ function arrangementEqual(e, n, t) {
230
234
  }
231
235
  }
232
236
  for (let s = 0; s < n.length; s++) {
233
- const u = n[s];
234
- let f;
235
- if (isWrappable(u)) {
237
+ const f = n[s];
238
+ let a;
239
+ if (isWrappable(f)) {
236
240
  if (o !== null) {
237
- const e = t(u);
238
- if (e !== undefined) f = o.get(e);
239
- } else if (s < i && isWrappable(unwrapValue(r[s]))) f = r[s];
241
+ const e = t(f);
242
+ if (e !== undefined) a = o.get(e);
243
+ } else if (s < i && isWrappable(unwrapValue(r[s]))) a = r[s];
240
244
  }
241
- if (f !== undefined) {
242
- if (unwrapValue(f) !== u) reconcileDraft(f, u, t);
243
- if (e[s] !== f) e[s] = f;
244
- } else if (unwrapValue(e[s]) !== u) e[s] = u;
245
+ if (a !== undefined) {
246
+ if (unwrapValue(a) !== f) reconcileDraft(a, f, t);
247
+ if (e[s] !== a) e[s] = a;
248
+ } else if (unwrapValue(e[s]) !== f) e[s] = f;
245
249
  }
246
250
  if (e.length !== n.length) e.length = n.length;
247
251
  return;
@@ -257,6 +261,29 @@ function arrangementEqual(e, n, t) {
257
261
  for (const t of Object.keys(e)) if (!(t in n)) delete e[t];
258
262
  }
259
263
 
264
+ /** Core asks (lanes `laneWrite`): the family's derive, re-asking in a lane of
265
+ * another action than the one that guessed this slot, writes it — that
266
+ * lane's new question, which the guess (over the old one) does not answer:
267
+ * the slot is the lane's derivation from here (F-6, #4336; lanes
268
+ * `laneStage` for a node's own pass). */ GlobalQueue.fn = (e, n) => {
269
+ const t = e.O;
270
+ if (n) {
271
+ // The guess comes back (lanes `endLanes`): on the slot's node now — the
272
+ // node itself, or the one a read made after it was released.
273
+ const n = e.Xe;
274
+ markOverlaid(t);
275
+ return n === $TRACK ? getContainerNode(t) : e.ye === isEqual ? getHasNode(t, n) : getNode(t, n);
276
+ }
277
+ const i = t?.fam?.node?.T?.Re;
278
+ const r = txOf(e);
279
+ if (!i?.P || sameAction(i, r)) return false;
280
+ // The re-ask takes the target's guess whole: the slot is the lane's
281
+ // derivation; its other guessed slots show their truth in the lane's
282
+ // world (lanes `take`).
283
+ for (const n of nodesOf(t)) if (n?.l & CONFIG_GUESS && txOf(n) === r) take(n, i, n !== e);
284
+ return true;
285
+ };
286
+
260
287
  /** Q-D (plan sec. 39): an OLDER question's truth landed beneath an arrangement
261
288
  * guess (`laneWrite` held it — another action's landing is not this guess's
262
289
  * answer). The guess is re-based over it: order from the guess, rows from
@@ -270,10 +297,10 @@ function arrangementEqual(e, n, t) {
270
297
  * node is born for it as the lane's derivation), on `length` only when the
271
298
  * committed length differs, and as the `LaneView`'s base for structural
272
299
  * reads. Unkeyed families compose
273
- * positionally — the guess stands as written (the documented residue). */ GlobalQueue.an = (e, n, t) => {
300
+ * positionally — the guess stands as written (the documented residue). */ GlobalQueue.Nn = (e, n, t) => {
274
301
  if (!t) return fold(e, n);
275
302
  const i = e.O;
276
- if (i === undefined || e.ze !== $TRACK) return;
303
+ if (i === undefined || e.Xe !== $TRACK) return;
277
304
  const r = e.T.P;
278
305
  if (!(r instanceof LaneView)) return;
279
306
  if (!Array.isArray(n) || !Array.isArray(r.rows)) {
@@ -288,46 +315,46 @@ function arrangementEqual(e, n, t) {
288
315
  const i = isWrappable(t) ? o(t) : undefined;
289
316
  if (i !== undefined && !s.has(i)) s.set(i, t);
290
317
  }
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];
318
+ const f = new Set;
319
+ const a = [];
320
+ const l = r.rows;
321
+ for (let e = 0; e < l.length; e++) {
322
+ const n = l[e];
296
323
  const t = isWrappable(n) ? o(n) : undefined;
297
324
  const i = t !== undefined ? s.get(t) : undefined;
298
325
  if (i !== undefined) {
299
- f.push(i);
300
- u.add(t);
301
- } else f.push(n);
326
+ a.push(i);
327
+ f.add(t);
328
+ } else a.push(n);
302
329
  }
303
- const l = r.removed;
330
+ const u = r.removed;
304
331
  for (let e = 0; e < n.length; e++) {
305
332
  const t = n[e];
306
333
  const i = isWrappable(t) ? o(t) : undefined;
307
- if (i !== undefined && !u.has(i) && (l === null || !l.has(i))) f.push(t);
334
+ if (i !== undefined && !f.has(i) && (u === null || !u.has(i))) a.push(t);
308
335
  }
309
- r.rows = f;
310
- r.base = f;
336
+ r.rows = a;
337
+ r.base = a;
311
338
  const c = txOf(e);
312
339
  const d = committed(i);
313
340
  const p = i.n;
314
- for (let e = 0; e < f.length; e++) {
341
+ for (let e = 0; e < a.length; e++) {
315
342
  const n = p?.[e];
316
343
  // A slot the lane does not own shows the committed row: it becomes the
317
344
  // lane's only where the composed row is another row (by key — the same
318
345
  // key's new object is the same row, its target adopted it).
319
346
  if (n === undefined) {
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.P : d[e], f[e], o)) laneSet(n, f[e], c);
347
+ if (!sameRow(d[e], a[e], o)) laneSet(getNode(i, e), a[e], c);
348
+ } else if (!sameRow(n.l & CONFIG_OVERRIDE ? n.T.P : d[e], a[e], o)) laneSet(n, a[e], c);
322
349
  }
323
350
  if (p !== null) {
324
- for (let e = f.length; ;e++) {
351
+ for (let e = a.length; ;e++) {
325
352
  const n = p[e];
326
353
  if (n === undefined) break;
327
354
  laneSet(n, undefined, c);
328
355
  }
329
356
  const e = p.length;
330
- if (e !== undefined && (e.l & CONFIG_OVERRIDE || d.length !== f.length)) laneSet(e, f.length, c);
357
+ if (e !== undefined && (e.l & CONFIG_OVERRIDE || d.length !== a.length)) laneSet(e, a.length, c);
331
358
  }
332
359
  };
333
360
 
@@ -342,9 +369,9 @@ function arrangementEqual(e, n, t) {
342
369
  const i = txOf(e);
343
370
  // A guess the screen never showed is void at the correction (D-34); a
344
371
  // keyed arrangement guess's view carries its removed-keys set.
345
- if (!i.ge || !(t?.l & CONFIG_OVERRIDE) || !t.T.P?.removed) return false;
372
+ if (!i.Ue || !(t?.l & CONFIG_OVERRIDE) || !t.T.P?.removed) return false;
346
373
  const r = e.T.P;
347
- if ((!e.xe || !e.xe(r, n)) && !GlobalQueue.nn(r, n)) {
374
+ if ((!e.ye || !e.ye(r, n)) && !GlobalQueue.nn(r, n)) {
348
375
  i.folded = foldedRead;
349
376
  insertSubs(e);
350
377
  } else GlobalQueue.sn?.(i);
@@ -365,8 +392,8 @@ function arrangementEqual(e, n, t) {
365
392
  const t = txOf(n);
366
393
  joinPassAt(e, resolveTx(t._parent ?? t));
367
394
  }
368
- if (n.ie !== NOT_PENDING) return n.ie;
369
- return n.l & CONFIG_SLOT_NODE ? GlobalQueue.fn(n) : n.le;
395
+ if (n.ue !== NOT_PENDING) return n.ue;
396
+ return n.l & CONFIG_SLOT_NODE ? GlobalQueue.an(n) : n.le;
370
397
  }
371
398
 
372
399
  function sameRow(e, n, t) {
@@ -391,7 +418,28 @@ function sameRow(e, n, t) {
391
418
  }
392
419
  }
393
420
 
421
+ /** D-34 for a per-key guess (#4329): the derive's draft wrote new objects
422
+ * over a target holding guessed rows (`d.length = 0; d.push(...rows)`, or
423
+ * `d.issues = rows`). The container on the way down to each guessed row
424
+ * reconciles the new object at its slot — in a keyed list, the one with
425
+ * the row's key — exactly as a returned landing would: rows match by key,
426
+ * a guessed row keeps its target, and its leaves are judged against their
427
+ * guesses. Rows nothing guessed are left as the draft wrote them. */ function pairRows(e, n) {
428
+ const t = e.fam.key;
429
+ for (let i of e.fam.overlaid ?? []) {
430
+ // The guessed row, or its ancestor directly under `t` (none: skip).
431
+ while (i.u !== e) if ((i = i.u) === null) break;
432
+ if (i === null) continue;
433
+ const r = t?.(i.v);
434
+ const o = Array.isArray(n) ? r !== undefined && n.find(e => isWrappable(e) && sameKey(t(e), r)) : n[i.pk];
435
+ // A new object only: not `c`'s own, nor one another row serves
436
+ // (pairing it would alias the two).
437
+ if (isWrappable(o) && !lookupTarget(o, e.fam)) reconcileState(o, i.px, t, true);
438
+ }
439
+ }
440
+
394
441
  installOptHooks({
442
+ pair: pairRows,
395
443
  draft: optimisticDraft,
396
444
  writes: notifyOptimisticWrites,
397
445
  arrangement: arrangement,
@@ -399,9 +447,53 @@ installOptHooks({
399
447
  view: (e, n, t = false) => t ? optimisticView(e, n, laneValueOf, true) : optimisticView(e, n),
400
448
  has: optimisticHas,
401
449
  descriptor: optimisticOwnDescriptor,
402
- sweep: sweepOverlaid
450
+ sweep: sweepOverlaid,
451
+ // A new question (not a `refresh()`) asked over guesses an earlier frame
452
+ // opened, which answer the old one (D-34, #4336). Stamped on `fam.asked`
453
+ // with this flush's `clock`, so it lapses when the flush ends: `clock + 1`
454
+ // from mainline over a live guess — a frame still reading a guess at the
455
+ // seam shows it beside the new input, so the flush holds with the guess's
456
+ // action (`park`); `~clock` from a lane with no guess of its own, or with
457
+ // no live guess left — the lane waits for its answer (F-6), as for a
458
+ // guessed `createOptimistic` (lanes `laneStage`). The guess's own lane
459
+ // asks nothing new and stamps nothing.
460
+ ask: e => {
461
+ if (e.node.R & REACTIVE_REASK || !e.overlaid?.size) return;
462
+ // Stamped with the flush (`clock`): it lapses when the flush ends.
463
+ let n = ~clock;
464
+ for (const t of e.overlaid) {
465
+ const e = laneNodeOf(t);
466
+ if (e) {
467
+ if (passLane === null) n = clock + 1; else if (sameAction(txOf(e), passLane)) return;
468
+ }
469
+ }
470
+ if ((e.asked = n) > 0) joinFuture(null);
471
+ },
472
+ // Over a new question the guesses do not answer (`asked`): from mainline
473
+ // only a target carrying a guess stands in — a read of one with none is an
474
+ // ordinary pending read (F-2), so a keyed store's other keys wait for their
475
+ // answer, not for the guess's action; in a lane with no guess of its own,
476
+ // or with no live guess left, none does (F-6).
477
+ stands: e => {
478
+ const n = e.fam.overlaid;
479
+ const t = e.fam.asked;
480
+ return !!n?.size && (t !== clock + 1 || passLane !== null || n.has(e)) && t !== ~clock;
481
+ },
482
+ // Mainline hold (`clock + 1`): the flush joins the action of each guess a
483
+ // reader still reads at the seam; a reader that moved off it (a keyed
484
+ // store's other key) holds nothing.
485
+ park: e => {
486
+ for (const n of overlaidFamilies) if (n.asked === clock + 1) for (const t of n.overlaid) {
487
+ const n = laneNodeOf(t, true);
488
+ if (n) merge(txOf(n)._parent, e);
489
+ }
490
+ }
403
491
  });
404
492
 
493
+ /** Two lanes of one action (their parents resolved through merges). */ function sameAction(e, n) {
494
+ return resolveTx(e._parent) === resolveTx(n._parent);
495
+ }
496
+
405
497
  function shallowKeys(e) {
406
498
  const n = {};
407
499
  for (const t of Reflect.ownKeys(e)) if (t !== $OWNER) n[t] = unwrapValue(e[t]);
@@ -424,7 +516,7 @@ function sweepOverlaid() {
424
516
  if (overlaidFamilies.size === 0) return;
425
517
  for (const e of overlaidFamilies) {
426
518
  const n = e.overlaid;
427
- for (const e of n) if (!carriesLane(e)) {
519
+ for (const e of n) if (!laneNodeOf(e)) {
428
520
  n.delete(e);
429
521
  if (e.ch) rebaseChained(e);
430
522
  // The container shows its backing again (a shown arrangement guess
@@ -447,7 +539,7 @@ function sweepOverlaid() {
447
539
  if (i !== null) for (const e of Reflect.ownKeys(i)) {
448
540
  const r = i[e];
449
541
  const o = untrack(() => unwrapValue(n[e]));
450
- if (r.xe && r.xe(r.le, o)) continue;
542
+ if (r.ye && r.ye(r.le, o)) continue;
451
543
  r.le = o;
452
544
  // (The lane's end notified it this epoch when the shown value and the
453
545
  // covered one differed — its readers re-derive already.)
@@ -472,7 +564,7 @@ function sweepOverlaid() {
472
564
  const o = e.k;
473
565
  if (o !== null && o.o !== null && o.le instanceof LaneView && o.Me !== notifyEpoch) {
474
566
  const i = Array.isArray(n) ? untrack(() => n.map(unwrapValue)) : n;
475
- if (!arrangementEqual(o.le.rows, i, e.fam?.key ?? null)) {
567
+ if (!arrangementEqual(o.le.rows, i, e.fam)) {
476
568
  insertSubs(o);
477
569
  t = true;
478
570
  }
@@ -480,14 +572,18 @@ function sweepOverlaid() {
480
572
  if (t) schedule();
481
573
  }
482
574
 
483
- function carriesLane(e) {
484
- if (e.k !== null && e.k.l & CONFIG_OVERRIDE) return true;
485
- if (e.dk !== null && e.dk.l & CONFIG_OVERRIDE) return true;
486
- const n = e.n;
487
- if (n !== null) for (const e of Reflect.ownKeys(n)) if (n[e].l & CONFIG_OVERRIDE) return true;
488
- const t = e.h;
489
- if (t !== null) for (const e of Reflect.ownKeys(t)) if (t[e].l & CONFIG_OVERRIDE) return true;
490
- return false;
575
+ /** `t`'s nodes (a missing container or deep node: null). */ function nodesOf(e) {
576
+ const n = [ e.k, e.dk ];
577
+ for (const t of [ e.n, e.h ]) if (t !== null) for (const e of Reflect.ownKeys(t)) n.push(t[e]);
578
+ return n;
579
+ }
580
+
581
+ /** A node of `t` carrying a lane value, if any (`read`: one a reader's
582
+ * last pass read). */ function laneNodeOf(e, n) {
583
+ for (const t of nodesOf(e)) if (t?.l & CONFIG_OVERRIDE) {
584
+ if (!n) return t;
585
+ for (let e = t.o; e !== null; e = e.t) if (e.Ne === e.u.de) return t;
586
+ }
491
587
  }
492
588
 
493
589
  function overlaid(e) {
@@ -562,11 +658,11 @@ i = false) {
562
658
  if (s !== null) {
563
659
  for (const e of Reflect.ownKeys(s)) {
564
660
  const o = s[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];
661
+ let f;
662
+ if (o.l & CONFIG_OVERRIDE) f = t(o); else if (!i || (f = pendingGuessOf(o)) === NOT_PENDING) continue;
663
+ const a = !!f;
664
+ const l = r ?? n;
665
+ if (!a && e in l) delete ensure()[e];
570
666
  }
571
667
  }
572
668
  return r ?? n;
@@ -579,7 +675,7 @@ function createOptimisticStore(e, n, t) {
579
675
  // createProjectionInternal).
580
676
  const o = i ? n || {} : e;
581
677
  const s = r?.key === undefined ? "id" : r.key;
582
- const u = {
678
+ const f = {
583
679
  map: new WeakMap,
584
680
  node: null,
585
681
  live: new Set,
@@ -587,9 +683,9 @@ function createOptimisticStore(e, n, t) {
587
683
  opt: true,
588
684
  key: typeof s === "function" ? s : s === null ? null : e => isWrappable(e) ? e[s] : undefined
589
685
  };
590
- const f = wrap(o, null, null, u);
591
- if (u.shallow) {
592
- f[$TARGET].s = true;
686
+ const a = wrap(o, null, null, f);
687
+ if (f.shallow) {
688
+ a[$TARGET].s = true;
593
689
  markRawIngest(o);
594
690
  }
595
691
  if (i) {
@@ -599,13 +695,13 @@ function createOptimisticStore(e, n, t) {
599
695
  loadingValue: undefined
600
696
  };
601
697
  const i = computed(() => {
602
- if (!u.node) u.node = getOwner();
603
- runProjectionComputed(f, n, s);
698
+ if (!f.node) f.node = getOwner();
699
+ runProjectionComputed(a, n, s);
604
700
  }, t);
605
701
  i.l &= ~CONFIG_AUTO_DISPOSE;
606
- u.node = i;
702
+ f.node = i;
607
703
  }
608
- return [ f, e => storeSetter(f, e) ];
704
+ return [ a, e => storeSetter(a, e) ];
609
705
  }
610
706
 
611
707
  export { createOptimisticStore, notifyOptimisticWrites, optimisticHas, optimisticOwnDescriptor, optimisticView, sweepOverlaid };