@solidjs/signals 2.0.0-rc.5 → 2.0.0-rc.7

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 (66) hide show
  1. package/dist/dev.js +2467 -1322
  2. package/dist/node.cjs +2037 -2428
  3. package/dist/node.dev.cjs +13724 -0
  4. package/dist/prod/boundaries.js +3 -1
  5. package/dist/prod/core/async.js +47 -20
  6. package/dist/prod/core/attribution-hooks.js +3 -0
  7. package/dist/prod/core/constants.js +9 -1
  8. package/dist/prod/core/context.js +10 -16
  9. package/dist/prod/core/core.js +260 -188
  10. package/dist/prod/core/dev.js +2 -0
  11. package/dist/prod/core/effect.js +41 -32
  12. package/dist/prod/core/external.js +2 -2
  13. package/dist/prod/core/graph.js +35 -31
  14. package/dist/prod/core/heap.js +34 -40
  15. package/dist/prod/core/lanes.js +44 -30
  16. package/dist/prod/core/optimistic.js +55 -45
  17. package/dist/prod/core/owner.js +35 -35
  18. package/dist/prod/core/scheduler.js +176 -177
  19. package/dist/prod/core/verdict.js +53 -52
  20. package/dist/prod/index.js +0 -2
  21. package/dist/prod/map.js +104 -94
  22. package/dist/prod/signals.js +119 -35
  23. package/dist/prod/store/next/optimistic.js +217 -163
  24. package/dist/prod/store/next/projection.js +2 -2
  25. package/dist/prod/store/next/reconcile.js +140 -288
  26. package/dist/prod/store/next/store.js +338 -252
  27. package/dist/prod/store/store.js +2 -2
  28. package/dist/types/core/attribution-hooks.d.ts +75 -0
  29. package/dist/types/core/attribution.d.ts +313 -9
  30. package/dist/types/core/constants.d.ts +8 -0
  31. package/dist/types/core/core.d.ts +12 -3
  32. package/dist/types/core/dev.d.ts +56 -9
  33. package/dist/types/core/heap.d.ts +5 -3
  34. package/dist/types/core/invariants.d.ts +1 -1
  35. package/dist/types/core/lanes.d.ts +10 -0
  36. package/dist/types/core/scheduler.d.ts +14 -4
  37. package/dist/types/signals.d.ts +10 -11
  38. package/dist/types/store/index.d.ts +3 -6
  39. package/dist/types/store/next/optimistic.d.ts +4 -2
  40. package/dist/types/store/next/reconcile.d.ts +5 -12
  41. package/dist/types/store/next/store.d.ts +3 -9
  42. package/dist/types/store/next/target.d.ts +30 -46
  43. package/dist/types/store/store.d.ts +14 -9
  44. package/dist/types-cjs/core/attribution-hooks.d.cts +75 -0
  45. package/dist/types-cjs/core/attribution.d.cts +313 -9
  46. package/dist/types-cjs/core/constants.d.cts +8 -0
  47. package/dist/types-cjs/core/core.d.cts +12 -3
  48. package/dist/types-cjs/core/dev.d.cts +56 -9
  49. package/dist/types-cjs/core/heap.d.cts +5 -3
  50. package/dist/types-cjs/core/invariants.d.cts +1 -1
  51. package/dist/types-cjs/core/lanes.d.cts +10 -0
  52. package/dist/types-cjs/core/scheduler.d.cts +14 -4
  53. package/dist/types-cjs/signals.d.cts +10 -11
  54. package/dist/types-cjs/store/index.d.cts +3 -6
  55. package/dist/types-cjs/store/next/optimistic.d.cts +4 -2
  56. package/dist/types-cjs/store/next/reconcile.d.cts +5 -12
  57. package/dist/types-cjs/store/next/store.d.cts +3 -9
  58. package/dist/types-cjs/store/next/target.d.cts +30 -46
  59. package/dist/types-cjs/store/store.d.cts +14 -9
  60. package/package.json +3 -2
  61. package/dist/prod/store/next/patch-hooks.js +0 -13
  62. package/dist/prod/store/next/patch.js +0 -614
  63. package/dist/types/store/next/patch-hooks.d.ts +0 -41
  64. package/dist/types/store/next/patch.d.ts +0 -91
  65. package/dist/types-cjs/store/next/patch-hooks.d.cts +0 -41
  66. package/dist/types-cjs/store/next/patch.d.cts +0 -91
@@ -10,7 +10,7 @@ import { insertIntoHeap, queueFor, markHeap, enqueueSub } from "./heap.js";
10
10
 
11
11
  import "./invariants.js";
12
12
 
13
- import { findLane, hasActiveOverride, assignOrMergeLane } from "./lanes.js";
13
+ import { findLane, laneHeld, hasActiveOverride, assignOrMergeLane } from "./lanes.js";
14
14
 
15
15
  import { installOptimisticEngine } from "./optimistic.js";
16
16
 
@@ -47,10 +47,10 @@ let pendingProbe = null;
47
47
  * O(all-leaves-ever-read)-per-update pathology). Entries are permanent like
48
48
  * the companions themselves; a store with no leaf-level isPending()/latest()
49
49
  * reads never allocates the set or pays the walk. */ function markFirewallChildCompanions(e) {
50
- const t = e.st;
50
+ const t = e.rt;
51
51
  if (!t) return;
52
52
  t.T |= CONFIG_CHILD_COMPANIONS;
53
- (ext(t).St ??= new Set).add(e);
53
+ (ext(t).dt ??= new Set).add(e);
54
54
  }
55
55
 
56
56
  function getPendingSignal(e) {
@@ -63,7 +63,7 @@ function getPendingSignal(e) {
63
63
  ext(e).ye = t;
64
64
  e.T |= CONFIG_HAS_COMPANIONS;
65
65
  markFirewallChildCompanions(e);
66
- ext(t).Tt = e;
66
+ ext(t).St = e;
67
67
  if (computePendingState(e)) setSignal(t, true);
68
68
  }
69
69
  return t;
@@ -72,7 +72,7 @@ function getPendingSignal(e) {
72
72
  function collectPendingSources(e) {
73
73
  if (!pendingProbe) return;
74
74
  pendingProbe.sources.add(e);
75
- const t = e.st || e;
75
+ const t = e.rt || e;
76
76
  if (t !== e) pendingProbe.sources.add(t);
77
77
  }
78
78
 
@@ -105,33 +105,29 @@ function collectPendingSources(e) {
105
105
  if (e.S & STATUS_ERROR) return false;
106
106
  if (t.has(e)) return false;
107
107
  t.add(e);
108
- const n = e.st;
108
+ const n = e.rt;
109
109
  if (n && markWalk(n, t)) return true;
110
110
  // Mid-recompute (the clearStatus companion poke runs before
111
111
  // trimStaleDeps), only the validated prefix [_deps.._depsTail] is this
112
112
  // pass's dependency set — walking past it would read dropped deps and
113
113
  // latch a stale verdict on the companion.
114
114
  const i = e;
115
- const r = i.ie & REACTIVE_RECOMPUTING_DEPS ? i.je : undefined;
115
+ const r = i.ie & REACTIVE_RECOMPUTING_DEPS ? i.Be : undefined;
116
116
  if (r !== null) {
117
- for (let e = i.ut ?? null; e !== null; e = e.lt) {
118
- if (!e.ve && markWalk(e.ot, t)) return true;
117
+ for (let e = i.lt ?? null; e !== null; e = e.ot) {
118
+ if (!e.ve && markWalk(e.st, t)) return true;
119
119
  if (e === r) break;
120
120
  }
121
121
  }
122
122
  return false;
123
123
  }
124
124
 
125
- /** Gated entry: apps with no live mark pay one integer compare. */ function markCovered(e) {
126
- return activeAffectsMarks !== 0 && markWalk(e, new Set);
127
- }
128
-
129
125
  function quietPending(e) {
130
126
  if (e.o?.le) {
131
- for (const t of e.o.le) if (!t.o?.Ge) return false;
127
+ for (const t of e.o.le) if (!t.o?.De) return false;
132
128
  return true;
133
129
  }
134
- return e.o?.Ge ?? false;
130
+ return e.o?.De ?? false;
135
131
  }
136
132
 
137
133
  // NOTE: a loadingValue node's open loading window (_loading) is verdict-quiet
@@ -151,23 +147,28 @@ function computePendingState(e) {
151
147
  // Mark coverage is transitive by dep-graph reachability: a latest() shadow
152
148
  // reaches its owner (and a store leaf its firewall) through its own deps,
153
149
  // so the one walk covers direct marks, derivation, and companion chains.
154
- if (markCovered(e)) return true;
155
- const n = e.st;
156
- if (e.o?.Tt) {
157
- const t = e.o?.Tt;
158
- const n = t.st || t;
150
+ // Gated: apps with no live mark pay one integer compare.
151
+ if (activeAffectsMarks !== 0 && markWalk(e, new Set)) return true;
152
+ const n = e.rt;
153
+ if (e.o?.St) {
154
+ const t = e.o?.St;
155
+ const n = t.rt || t;
159
156
  return newQuestionInFlight(n);
160
157
  }
161
- if (n && e.Pe !== NOT_PENDING && !hasActiveOverride(e)) {
158
+ if (n && e.Re !== NOT_PENDING && !hasActiveOverride(e)) {
162
159
  return !!(n.ie & REACTIVE_MANUAL_WRITE) || !n.o?.Ie && !(n.S & STATUS_PENDING) || !!(n.S & STATUS_PENDING) && quietPending(n);
163
160
  }
164
161
  // `!comp._loading`: a hold created while the loading window is still open is
165
162
  // the window's own landing in flight to its commit — verdict-quiet like the
166
163
  // rest of the window (the UNINITIALIZED check suppresses exactly this frame
167
164
  // for windowless first loads; born-committed nodes need their own gate, #2990).
168
- if (e.Pe !== NOT_PENDING && !(t.S & STATUS_UNINITIALIZED) && !t.Ne) {
169
- if (hasActiveOverride(e)) return !e.ge || !e.ge(e.Pe, unwrapOverride(e.o?.Oe));
170
- return true;
165
+ if (e.Re !== NOT_PENDING && !(t.S & STATUS_UNINITIALIZED) && !t.Ne) {
166
+ if (hasActiveOverride(e)) return !e.pe || !e.pe(e.Re, unwrapOverride(e.o?.Pe));
167
+ // A quiet re-ask's held landing still answers the same question: the
168
+ // classification survives the landing (asyncWrite) and dies with the
169
+ // commit (commitPendingNode) — verdict-quiet through the reveal, like
170
+ // the loading window above (#3178).
171
+ if (!t.o?.De) return true;
171
172
  }
172
173
  return newQuestionInFlight(t);
173
174
  }
@@ -185,7 +186,7 @@ function updatePendingSignal(e) {
185
186
  }
186
187
 
187
188
  function updateChildCompanions(e) {
188
- const t = e.o?.St;
189
+ const t = e.o?.dt;
189
190
  if (t === undefined) return;
190
191
  for (const e of t) updatePendingSignal(e);
191
192
  }
@@ -235,11 +236,11 @@ function updateChildCompanions(e) {
235
236
  }
236
237
  if (s !== e) continue;
237
238
  suppressedProbes.delete(n);
238
- const o = n.o?.ye?.o?.Je;
239
+ const o = n.o?.ye?.o?.$e;
239
240
  for (const e of i) {
240
241
  if (e.ie & REACTIVE_DISPOSED) continue;
241
242
  e.ie |= REACTIVE_OPTIMISTIC_DIRTY;
242
- if (o) assignOrMergeLane(e, o); else if (e.o !== null) e.o.Je = undefined;
243
+ if (o) assignOrMergeLane(e, o); else if (e.o !== null) e.o.$e = undefined;
243
244
  enqueueSub(e);
244
245
  t = true;
245
246
  }
@@ -250,18 +251,18 @@ function updateChildCompanions(e) {
250
251
  function snapCompanionsToState(e) {
251
252
  suppressedProbes.size !== 0 && suppressedProbes.delete(e);
252
253
  const t = e.o?.ye;
253
- if (t && (t.o?.Oe === undefined || t.o?.Oe === NOT_PENDING)) {
254
+ if (t && (t.o?.Pe === undefined || t.o?.Pe === NOT_PENDING)) {
254
255
  const n = computePendingState(e);
255
- if (t.be !== n || t.Pe !== NOT_PENDING) {
256
+ if (t.be !== n || t.Re !== NOT_PENDING) {
256
257
  t.be = n;
257
- t.Pe = NOT_PENDING;
258
+ t.Re = NOT_PENDING;
258
259
  insertSubs(t);
259
260
  schedule();
260
261
  }
261
262
  }
262
263
  const n = e.o?.Ce;
263
264
  if (n && !(n.ie & REACTIVE_DISPOSED)) {
264
- if ((n.o?.Oe === undefined || n.o?.Oe === NOT_PENDING) && n.Pe === NOT_PENDING && !Object.is(n.be, e.be) && !(n.ie & (REACTIVE_DIRTY | REACTIVE_CHECK))) {
265
+ if ((n.o?.Pe === undefined || n.o?.Pe === NOT_PENDING) && n.Re === NOT_PENDING && !Object.is(n.be, e.be) && !(n.ie & (REACTIVE_DIRTY | REACTIVE_CHECK))) {
265
266
  n.ie |= REACTIVE_DIRTY;
266
267
  insertIntoHeap(n, queueFor(n));
267
268
  insertSubs(n);
@@ -292,13 +293,13 @@ function getLatestValueComputed(e) {
292
293
  ext(e).Ce = t;
293
294
  e.T |= CONFIG_HAS_COMPANIONS;
294
295
  markFirewallChildCompanions(e);
295
- ext(t).Tt = e;
296
+ ext(t).St = e;
296
297
  // Parent-child lane relationship
297
298
  // Backfill an in-flight write (mirrors getPendingSignal): the companion is
298
299
  // created lazily, possibly after the write was processed — syncCompanions
299
300
  // only pushes into companions that already exist, so the first latest()
300
301
  // read inside a held transition showed the committed value (#3041).
301
- if (e.Pe !== NOT_PENDING && !hasActiveOverride(e)) setSignal(t, e.Pe);
302
+ if (e.Re !== NOT_PENDING && !hasActiveOverride(e)) setSignal(t, e.Re);
302
303
  setContextInternal(r);
303
304
  setPendingCheckActive(i);
304
305
  setLatestReadActive(n);
@@ -310,7 +311,7 @@ function getLatestValueComputed(e) {
310
311
  const t = getLatestValueComputed(e);
311
312
  const n = latestReadActive;
312
313
  setLatestReadActive(false);
313
- const i = e.o?.Oe !== undefined && e.o?.Oe !== NOT_PENDING ? unwrapOverride(e.o?.Oe) : e.be;
314
+ const i = e.o?.Pe !== undefined && e.o?.Pe !== NOT_PENDING ? unwrapOverride(e.o?.Pe) : e.be;
314
315
  let r;
315
316
  try {
316
317
  // An untracked latest() read has no reading context, so read() never
@@ -319,7 +320,7 @@ function getLatestValueComputed(e) {
319
320
  // until the flush (#2922). Mirror the tracked-read pull here: mark the
320
321
  // queued staleness through the graph, then bring the shadow up to date.
321
322
  const e = queueFor(t);
322
- if (t.Me >= e.Qe && !(t.ie & (REACTIVE_DISPOSED | REACTIVE_ZOMBIE))) {
323
+ if (t.qe >= e.Me && !(t.ie & (REACTIVE_DISPOSED | REACTIVE_ZOMBIE))) {
323
324
  markHeap(e);
324
325
  // Suspend probe collection during the pull (mirrors pendingCheckRead's
325
326
  // prepare): a probe through latest() answers for the SHADOW — the
@@ -346,10 +347,10 @@ function getLatestValueComputed(e) {
346
347
  setLatestReadActive(n);
347
348
  }
348
349
  if (t.S & STATUS_PENDING) return i;
349
- if (stale && currentOptimisticLane && t.o?.Je) {
350
- const e = findLane(t.o?.Je);
350
+ if (stale && currentOptimisticLane && t.o?.$e) {
351
+ const e = findLane(t.o?.$e);
351
352
  const n = findLane(currentOptimisticLane);
352
- if (e !== n && e.De.size > 0) {
353
+ if (e !== n && laneHeld(e)) {
353
354
  return i;
354
355
  }
355
356
  }
@@ -357,7 +358,7 @@ function getLatestValueComputed(e) {
357
358
  // speculative value in _pendingValue; a contextless read() only surfaces
358
359
  // _value. Overrides stay authoritative (A17), and stale readers keep the
359
360
  // other transition's committed view, matching read()'s own selection.
360
- if (t.Pe !== NOT_PENDING && !hasActiveOverride(t) && !(stale && t.Ae && activeTransition !== t.Ae)) return t.Pe;
361
+ if (t.Re !== NOT_PENDING && !hasActiveOverride(t) && !(stale && t.Ae && activeTransition !== t.Ae)) return t.Re;
361
362
  return r;
362
363
  }
363
364
 
@@ -371,9 +372,9 @@ function getLatestValueComputed(e) {
371
372
  * so the `_fn` check is belt-and-braces for this call site.
372
373
  */ function latestShadowWithInitializedParent(e) {
373
374
  if (typeof e.oe !== "function") return false;
374
- const t = e.o?.Tt;
375
+ const t = e.o?.St;
375
376
  if (t === undefined) return false;
376
- const n = t.st || t;
377
+ const n = t.rt || t;
377
378
  return !(n.S & STATUS_UNINITIALIZED);
378
379
  }
379
380
 
@@ -433,7 +434,7 @@ function getLatestValueComputed(e) {
433
434
  }
434
435
 
435
436
  function recordFreshRead(e, t) {
436
- if (pendingProbe !== null && e.Pe !== NOT_PENDING && t === e.Pe) {
437
+ if (pendingProbe !== null && e.Re !== NOT_PENDING && t === e.Re) {
437
438
  if (heldAwaitingAsync(e)) return;
438
439
  pendingProbe.freshReads.add(e);
439
440
  }
@@ -441,10 +442,10 @@ function recordFreshRead(e, t) {
441
442
 
442
443
  function applyReask(e, t) {
443
444
  const n = !!(e.S & STATUS_PENDING);
444
- const i = t && !(n && !e.o?.Ge);
445
- const r = n && (e.o?.Ge ?? false) !== i;
445
+ const i = t && !(n && !e.o?.De);
446
+ const r = n && (e.o?.De ?? false) !== i;
446
447
  // Allocation-free for the quiet case: false is the extension default.
447
- if (i) ext(e).Ge = true; else if (e.o !== null) e.o.Ge = false;
448
+ if (i) ext(e).De = true; else if (e.o !== null) e.o.De = false;
448
449
  return r;
449
450
  }
450
451
 
@@ -525,7 +526,7 @@ function isPending(e) {
525
526
  // Hook installation (same late-binding pattern as GlobalQueue._update /
526
527
  // _propagateAffects): core call sites fire these behind the same guards the
527
528
  // direct calls used, so behavior is identical once this module loads.
528
- GlobalQueue.Re = syncCompanions;
529
+ GlobalQueue.Ue = syncCompanions;
529
530
 
530
531
  GlobalQueue.de = updatePendingSignal;
531
532
 
@@ -533,18 +534,18 @@ GlobalQueue.me = updateChildCompanions;
533
534
 
534
535
  GlobalQueue.un = snapCompanionsToState;
535
536
 
536
- GlobalQueue.gt = latestRead;
537
+ GlobalQueue.Vt = latestRead;
537
538
 
538
- GlobalQueue.Ht = pendingCheckRead;
539
+ GlobalQueue.bt = pendingCheckRead;
539
540
 
540
- GlobalQueue.kt = recordFreshRead;
541
+ GlobalQueue.Lt = recordFreshRead;
541
542
 
542
- GlobalQueue.et = applyReask;
543
+ GlobalQueue.nt = applyReask;
543
544
 
544
545
  GlobalQueue.k = repollDownstreamVerdicts;
545
546
 
546
- GlobalQueue.Wt = witnessAffects;
547
+ GlobalQueue.zt = witnessAffects;
547
548
 
548
- GlobalQueue.zt = wakeSuppressedProbes;
549
+ GlobalQueue.Kt = wakeSuppressedProbes;
549
550
 
550
551
  export { isPending, latest };
@@ -38,8 +38,6 @@ export { createProjectionNext as createProjection } from "./store/next/projectio
38
38
 
39
39
  export { merge, omit } from "./store/utils.js";
40
40
 
41
- export { patchableRaw, registerPatch, registerRowOps, registerSlotPatchNext as registerSlotPatch } from "./store/next/patch.js";
42
-
43
41
  export { storeHasFamily, storeHasOptimisticFamily, storeIsShallow } from "./store/next/store.js";
44
42
 
45
43
  export { storePath } from "./store/storePath.js";
package/dist/prod/map.js CHANGED
@@ -6,6 +6,8 @@ import "./core/scheduler.js";
6
6
 
7
7
  import { CONFIG_AUTO_DISPOSE } from "./core/constants.js";
8
8
 
9
+ import { attrHooks } from "./core/attribution-hooks.js";
10
+
9
11
  import "./core/invariants.js";
10
12
 
11
13
  import "./core/verdict.js";
@@ -23,23 +25,23 @@ function mapArray(t, s, i) {
23
25
  const r = s.length > 1;
24
26
  const n = s;
25
27
  const h = {
26
- Kt: createOwner(),
27
- $t: 0,
28
- Jt: t,
29
- Xt: [],
30
- Yt: n,
31
- Zt: [],
28
+ $t: createOwner(),
29
+ Jt: 0,
30
+ Xt: t,
31
+ Yt: [],
32
+ Zt: n,
32
33
  ts: [],
33
- ss: e,
34
+ ss: [],
35
+ Ht: e,
34
36
  es: e || i?.keyed === false ? [] : undefined,
35
37
  rs: r && i?.keyed !== false ? [] : undefined,
36
38
  ns: i?.keyed === false,
37
39
  hs: i?.fallback
38
40
  };
39
- const o = computed(updateKeyedMap.bind(h));
41
+ const o = computed(updateKeyedMap.bind(h), undefined);
40
42
  // Untracked reads inside the internal owner resolve via _parentComputed; routing
41
43
  // them through node lets store-proxy lookups see pending writes (not stale _value).
42
- h.Kt.Dt = o;
44
+ h.$t.Pt = o;
43
45
  o.T &= ~CONFIG_AUTO_DISPOSE;
44
46
  return accessor(o);
45
47
  }
@@ -58,163 +60,171 @@ const pureOptions = {
58
60
  // strong-abort ordering: removed rows now dispose AFTER the pass's new rows
59
61
  // are created (you cannot destroy state before knowing the pass will land).
60
62
  function updateKeyedMap() {
61
- const t = this.Jt() || [], s = t.length;
63
+ const t = this.Xt() || [], s = t.length;
62
64
  t[$TRACK];
63
65
  // top level tracking
64
- runWithOwner(this.Kt, () => {
66
+ runWithOwner(this.$t, () => {
65
67
  let i, e, r, n,
66
68
  // Mappers write freshly-created row/index signals into the STAGE
67
69
  // arrays (`rows`/`indexes`), never into `this._rows`/`this._indexes`.
68
70
  h = this.es ? this.ns ? () => {
69
71
  r[e] = signal(t[e], pureOptions);
70
- return this.Yt(accessor(r[e]), e);
72
+ return this.Zt(accessor(r[e]), e);
71
73
  } : () => {
72
74
  r[e] = signal(t[e], pureOptions);
73
75
  n && (n[e] = signal(e, pureOptions));
74
- return this.Yt(accessor(r[e]), n ? accessor(n[e]) : undefined);
76
+ return this.Zt(accessor(r[e]), n ? accessor(n[e]) : undefined);
75
77
  } : this.rs ? () => {
76
78
  const s = t[e];
77
79
  n[e] = signal(e, pureOptions);
78
- return this.Yt(s, accessor(n[e]));
80
+ return this.Zt(s, accessor(n[e]));
79
81
  } : () => {
80
82
  const s = t[e];
81
- return this.Yt(s);
83
+ return this.Zt(s);
82
84
  };
83
85
  // fast path for empty arrays
84
86
  if (s === 0) {
85
- if (this.$t !== 0) {
86
- this.Kt.dispose(false);
87
+ if (this.Jt !== 0) {
88
+ this.$t.dispose(false);
89
+ this.ss = [];
90
+ this.Yt = [];
87
91
  this.ts = [];
88
- this.Xt = [];
89
- this.Zt = [];
90
- this.$t = 0;
92
+ this.Jt = 0;
91
93
  this.es && (this.es = []);
92
94
  this.rs && (this.rs = []);
93
95
  }
94
- if (this.hs && !this.Zt[0]) {
96
+ if (this.hs && !this.ts[0]) {
95
97
  // an aborted fallback attempt leaves an owner without a mapping;
96
98
  // dispose it before re-creating
97
- this.ts[0]?.dispose();
98
- this.Zt[0] = runWithOwner(this.ts[0] = createOwner(), this.hs);
99
+ this.ss[0]?.dispose();
100
+ this.ts[0] = runWithOwner(this.ss[0] = createOwner(), this.hs);
99
101
  }
100
102
  }
101
103
  // fast path for new create
102
- else if (this.$t === 0) {
104
+ else if (this.Jt === 0) {
103
105
  const o = new Array(s);
104
- const c = new Array(s);
106
+ const a = new Array(s);
105
107
  r = this.es && new Array(s);
106
108
  n = this.rs && new Array(s);
107
109
  try {
108
- for (e = 0; e < s; e++) o[e] = runWithOwner(c[e] = createOwner(), h);
110
+ for (e = 0; e < s; e++) o[e] = runWithOwner(a[e] = createOwner(), h);
109
111
  } catch (t) {
110
- for (i = 0; i <= e; i++) c[i]?.dispose();
112
+ for (i = 0; i <= e; i++) a[i]?.dispose();
111
113
  throw t;
112
114
  }
113
115
  // commit
114
- if (this.ts[0]) this.ts[0].dispose();
116
+ if (this.ss[0]) this.ss[0].dispose();
115
117
  // previous fallback
116
- this.Zt = o;
117
- this.ts = c;
118
+ this.ts = o;
119
+ this.ss = a;
118
120
  r && (this.es = r);
119
121
  n && (this.rs = n);
120
- this.Xt = t.slice(0);
121
- this.$t = s;
122
+ this.Yt = t.slice(0);
123
+ this.Jt = s;
122
124
  } else {
123
- let o, c, a, f, u, p, w, l, d;
125
+ let o, a, c, f, u, p, l, d, w,
126
+ // Dev (attribution engine installed): the items behind the exited and
127
+ // entered rows, for the list-identity census.
128
+ m, O;
124
129
  // skip common prefix
125
- for (o = 0, c = Math.min(this.$t, s); o < c && (this.Xt[o] === t[o] || this.es && compare(this.ss, this.Xt[o], t[o])); o++) {
130
+ for (o = 0, a = Math.min(this.Jt, s); o < a && (this.Yt[o] === t[o] || this.es && compare(this.Ht, this.Yt[o], t[o])); o++) {
126
131
  if (this.es) setSignal(this.es[o], t[o]);
127
132
  }
128
133
  // skip common suffix — counted only; retained entries land in one pass
129
134
  // at commit instead of being staged and copied twice
130
- for (c = this.$t - 1, a = s - 1; c >= o && a >= o && (this.Xt[c] === t[a] || this.es && compare(this.ss, this.Xt[c], t[a])); c--,
131
- a--) ;
135
+ for (a = this.Jt - 1, c = s - 1; a >= o && c >= o && (this.Yt[a] === t[c] || this.es && compare(this.Ht, this.Yt[a], t[c])); a--,
136
+ c--) ;
132
137
  // no structural change (every position matched in place at equal
133
138
  // length — the common post-reconcile shape): keep the same mapped
134
139
  // array identity so downstream consumers don't re-run at all
135
- if (o === s && this.$t === s) {
136
- this.Xt = t.slice(0);
140
+ if (o === s && this.Jt === s) {
141
+ this.Yt = t.slice(0);
137
142
  return;
138
143
  }
139
- const O = s - this.$t;
140
- const m = new Array(s);
141
- const _ = new Array(s);
144
+ const _ = s - this.Jt;
145
+ const y = new Array(s);
146
+ const A = new Array(s);
142
147
  r = this.es ? new Array(s) : undefined;
143
148
  n = this.rs ? new Array(s) : undefined;
144
149
  // 0) prepare a map of all indices in the changed window of newItems,
145
150
  // scanning backwards so we encounter them in natural order
146
151
  p = new Map;
147
- w = new Array(a + 1);
148
- for (e = a; e >= o; e--) {
152
+ l = new Array(c + 1);
153
+ for (e = c; e >= o; e--) {
149
154
  f = t[e];
150
- u = this.ss ? this.ss(f) : f;
155
+ u = this.Ht ? this.Ht(f) : f;
151
156
  i = p.get(u);
152
- w[e] = i === undefined ? -1 : i;
157
+ l[e] = i === undefined ? -1 : i;
153
158
  p.set(u, e);
154
159
  }
155
160
  // 1) step through the old changed window and see if items can be found
156
161
  // in the new set; if so, stage them at their new positions; if not,
157
162
  // queue them for disposal at commit
158
- for (i = o; i <= c; i++) {
159
- f = this.Xt[i];
160
- u = this.ss ? this.ss(f) : f;
163
+ for (i = o; i <= a; i++) {
164
+ f = this.Yt[i];
165
+ u = this.Ht ? this.Ht(f) : f;
161
166
  e = p.get(u);
162
167
  if (e !== undefined && e !== -1) {
163
- m[e] = this.Zt[i];
164
- _[e] = this.ts[i];
168
+ y[e] = this.ts[i];
169
+ A[e] = this.ss[i];
165
170
  r && (r[e] = this.es[i]);
166
171
  n && (n[e] = this.rs[i]);
167
- e = w[e];
172
+ e = l[e];
168
173
  p.set(u, e);
169
- } else (l ??= []).push(this.ts[i]);
174
+ } else {
175
+ (d ??= []).push(this.ss[i]);
176
+ if (false && attrHooks !== null) ;
177
+ }
170
178
  }
171
179
  // 2) create new rows into the temp arrays; an abort disposes only these
172
180
  try {
173
- for (e = o; e <= a; e++) {
174
- if (_[e] !== undefined) continue;
175
- (d ??= []).push(_[e] = createOwner());
176
- m[e] = runWithOwner(_[e], h);
181
+ for (e = o; e <= c; e++) {
182
+ if (A[e] !== undefined) continue;
183
+ (w ??= []).push(A[e] = createOwner());
184
+ if (false && attrHooks !== null) ;
185
+ y[e] = runWithOwner(A[e], h);
177
186
  }
178
187
  } catch (t) {
179
- if (d) for (i = 0; i < d.length; i++) d[i].dispose();
188
+ if (w) for (i = 0; i < w.length; i++) w[i].dispose();
180
189
  throw t;
181
190
  }
182
191
  // 3) commit: land the retained prefix and suffix plus the staged window
183
192
  // into the fresh arrays, swap them in (new identity for downstream
184
193
  // change propagation), then dispose exited rows
185
194
  for (i = 0; i < o; i++) {
186
- m[i] = this.Zt[i];
187
- _[i] = this.ts[i];
195
+ y[i] = this.ts[i];
196
+ A[i] = this.ss[i];
188
197
  r && (r[i] = this.es[i]);
189
198
  n && (n[i] = this.rs[i]);
190
199
  }
191
- for (e = o; e <= a; e++) {
200
+ for (e = o; e <= c; e++) {
192
201
  if (r) setSignal(r[e], t[e]);
193
202
  if (n) setSignal(n[e], e);
194
203
  }
195
- for (e = a + 1; e < s; e++) {
196
- m[e] = this.Zt[e - O];
197
- _[e] = this.ts[e - O];
204
+ for (e = c + 1; e < s; e++) {
205
+ y[e] = this.ts[e - _];
206
+ A[e] = this.ss[e - _];
198
207
  if (r) {
199
- r[e] = this.es[e - O];
208
+ r[e] = this.es[e - _];
200
209
  setSignal(r[e], t[e]);
201
210
  }
202
211
  if (n) {
203
- n[e] = this.rs[e - O];
204
- if (O !== 0) setSignal(n[e], e);
212
+ n[e] = this.rs[e - _];
213
+ if (_ !== 0) setSignal(n[e], e);
205
214
  }
206
215
  }
207
- this.Zt = m;
208
- this.ts = _;
216
+ this.ts = y;
217
+ this.ss = A;
209
218
  r && (this.es = r);
210
219
  n && (this.rs = n);
211
- this.$t = s;
220
+ this.Jt = s;
212
221
  // save a copy of the mapped items for the next update
213
- this.Xt = t.slice(0);
214
- if (l) for (i = 0; i < l.length; i++) l[i].dispose();
222
+ this.Yt = t.slice(0);
223
+ if (d) for (i = 0; i < d.length; i++) d[i].dispose();
224
+ if (false && attrHooks !== null && m !== undefined && O !== undefined) ;
215
225
  }
216
226
  });
217
- return this.Zt;
227
+ return this.ts;
218
228
  }
219
229
 
220
230
  /**
@@ -234,13 +244,13 @@ function updateKeyedMap() {
234
244
  */ function repeat(t, s, i) {
235
245
  const e = s;
236
246
  const r = {
237
- Kt: createOwner(),
238
- $t: 0,
247
+ $t: createOwner(),
248
+ Jt: 0,
239
249
  cs: 0,
240
250
  fs: t,
241
- Yt: e,
251
+ Zt: e,
252
+ ss: [],
242
253
  ts: [],
243
- Zt: [],
244
254
  us: i?.from,
245
255
  hs: i?.fallback
246
256
  };
@@ -248,7 +258,7 @@ function updateKeyedMap() {
248
258
  // Same as mapArray: untracked reads inside the internal owner resolve via
249
259
  // _parentComputed, so async reads in row callbacks register with the node
250
260
  // (pending tracking + post-settle retry) instead of vanishing.
251
- r.Kt.Dt = n;
261
+ r.$t.Pt = n;
252
262
  n.T &= ~CONFIG_AUTO_DISPOSE;
253
263
  return accessor(n);
254
264
  }
@@ -263,26 +273,26 @@ function updateKeyedMap() {
263
273
  function updateRepeat() {
264
274
  const t = this.fs();
265
275
  const s = this.us?.() || 0;
266
- runWithOwner(this.Kt, () => {
276
+ runWithOwner(this.$t, () => {
267
277
  if (t === 0) {
268
- if (this.$t !== 0) {
269
- this.Kt.dispose(false);
278
+ if (this.Jt !== 0) {
279
+ this.$t.dispose(false);
280
+ this.ss = [];
270
281
  this.ts = [];
271
- this.Zt = [];
272
- this.$t = 0;
282
+ this.Jt = 0;
273
283
  // Reset offset to match the cleared data (#2767, repro 2).
274
284
  this.cs = 0;
275
285
  }
276
- if (this.hs && !this.Zt[0]) {
286
+ if (this.hs && !this.ts[0]) {
277
287
  // an aborted fallback attempt leaves an owner without a mapping;
278
288
  // dispose it before re-creating
279
- this.ts[0]?.dispose();
280
- this.Zt[0] = runWithOwner(this.ts[0] = createOwner(), this.hs);
289
+ this.ss[0]?.dispose();
290
+ this.ts[0] = runWithOwner(this.ss[0] = createOwner(), this.hs);
281
291
  }
282
292
  return;
283
293
  }
284
294
  const i = s + t;
285
- const e = this.cs + this.$t;
295
+ const e = this.cs + this.Jt;
286
296
  // Retained overlap [keepStart, keepEnd) in global indexes; empty when the
287
297
  // windows are disjoint or when coming from empty/fallback.
288
298
  const r = Math.max(s, this.cs);
@@ -290,26 +300,26 @@ function updateRepeat() {
290
300
  const h = new Array(t);
291
301
  const o = new Array(t);
292
302
  for (let t = r; t < n; t++) {
293
- o[t - s] = this.ts[t - this.cs];
294
- h[t - s] = this.Zt[t - this.cs];
303
+ o[t - s] = this.ss[t - this.cs];
304
+ h[t - s] = this.ts[t - this.cs];
295
305
  }
296
306
  try {
297
307
  for (let t = s; t < i; t++) {
298
308
  if (t >= r && t < n) continue;
299
- h[t - s] = runWithOwner(o[t - s] = createOwner(), () => this.Yt(t));
309
+ h[t - s] = runWithOwner(o[t - s] = createOwner(), () => this.Zt(t));
300
310
  }
301
311
  } catch (t) {
302
312
  for (let t = s; t < i; t++) if ((t < r || t >= n) && o[t - s]) o[t - s].dispose();
303
313
  throw t;
304
314
  }
305
315
  // commit: dispose the previous fallback or the rows leaving the window
306
- if (this.$t === 0) this.ts[0]?.dispose(); else for (let t = this.cs; t < e; t++) if (t < s || t >= i) this.ts[t - this.cs].dispose();
307
- this.Zt = h;
308
- this.ts = o;
316
+ if (this.Jt === 0) this.ss[0]?.dispose(); else for (let t = this.cs; t < e; t++) if (t < s || t >= i) this.ss[t - this.cs].dispose();
317
+ this.ts = h;
318
+ this.ss = o;
309
319
  this.cs = s;
310
- this.$t = t;
320
+ this.Jt = t;
311
321
  });
312
- return this.Zt;
322
+ return this.ts;
313
323
  }
314
324
 
315
325
  function compare(t, s, i) {