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

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 (134) hide show
  1. package/dist/dev-shared.js +6357 -0
  2. package/dist/dev.attribution.js +2485 -0
  3. package/dist/dev.js +2851 -7027
  4. package/dist/observe/affects.js +129 -0
  5. package/dist/observe/attribution.js +7 -0
  6. package/dist/observe/boundaries.js +641 -0
  7. package/dist/observe/core/action.js +177 -0
  8. package/dist/observe/core/async.js +846 -0
  9. package/dist/observe/core/attribution-costs.js +66 -0
  10. package/dist/observe/core/attribution-feedback.js +282 -0
  11. package/dist/observe/core/attribution-hooks.js +82 -0
  12. package/dist/observe/core/attribution-queries.js +28 -0
  13. package/dist/observe/core/attribution.js +2095 -0
  14. package/dist/observe/core/constants.js +248 -0
  15. package/dist/{types-cjs/core/context.d.cts → observe/core/context.js} +37 -12
  16. package/dist/observe/core/core.js +1789 -0
  17. package/dist/observe/core/dev.js +293 -0
  18. package/dist/observe/core/effect.js +195 -0
  19. package/dist/observe/core/error-hooks.js +71 -0
  20. package/dist/observe/core/error.js +80 -0
  21. package/dist/observe/core/external.js +98 -0
  22. package/dist/observe/core/graph.js +155 -0
  23. package/dist/observe/core/heap.js +147 -0
  24. package/dist/observe/core/invariants.js +45 -0
  25. package/dist/observe/core/lanes.js +205 -0
  26. package/dist/observe/core/optimistic.js +585 -0
  27. package/dist/observe/core/owner.js +322 -0
  28. package/dist/observe/core/scheduler.js +1428 -0
  29. package/dist/observe/core/verdict.js +669 -0
  30. package/dist/observe/index.js +59 -0
  31. package/dist/observe/map.js +484 -0
  32. package/dist/{types-cjs/signals.d.cts → observe/signals.js} +311 -317
  33. package/dist/observe/store/index.js +40 -0
  34. package/dist/observe/store/next/optimistic.js +660 -0
  35. package/dist/observe/store/next/projection.js +255 -0
  36. package/dist/observe/store/next/reconcile.js +375 -0
  37. package/dist/observe/store/next/store.js +2327 -0
  38. package/dist/observe/store/next/target.js +51 -0
  39. package/dist/observe/store/store.js +325 -0
  40. package/dist/observe/store/storePath.js +103 -0
  41. package/dist/observe/store/utils.js +1023 -0
  42. package/dist/prod/attribution.js +41 -0
  43. package/dist/prod/boundaries.js +128 -76
  44. package/dist/prod/core/action.js +65 -37
  45. package/dist/prod/core/async.js +324 -172
  46. package/dist/prod/core/constants.js +57 -1
  47. package/dist/prod/core/context.js +3 -3
  48. package/dist/prod/core/core.js +1003 -364
  49. package/dist/prod/core/dev.js +17 -1
  50. package/dist/prod/core/effect.js +76 -42
  51. package/dist/prod/core/error-hooks.js +71 -0
  52. package/dist/prod/core/external.js +4 -4
  53. package/dist/prod/core/graph.js +37 -37
  54. package/dist/prod/core/heap.js +61 -56
  55. package/dist/prod/core/lanes.js +107 -63
  56. package/dist/prod/core/optimistic.js +374 -93
  57. package/dist/prod/core/owner.js +62 -46
  58. package/dist/prod/core/scheduler.js +653 -286
  59. package/dist/prod/core/verdict.js +245 -127
  60. package/dist/prod/index.js +15 -5
  61. package/dist/prod/map.js +292 -141
  62. package/dist/prod/signals.js +29 -16
  63. package/dist/prod/store/next/optimistic.js +77 -55
  64. package/dist/prod/store/next/projection.js +31 -20
  65. package/dist/prod/store/next/reconcile.js +87 -84
  66. package/dist/prod/store/next/store.js +718 -401
  67. package/dist/prod/store/next/target.js +32 -10
  68. package/dist/prod/store/store.js +12 -14
  69. package/dist/prod/store/utils.js +950 -130
  70. package/dist/types/attribution.d.ts +20 -0
  71. package/dist/types/attribution.prod.d.ts +22 -0
  72. package/dist/types/boundaries.d.ts +10 -1
  73. package/dist/types/core/action.d.ts +12 -5
  74. package/dist/types/core/async.d.ts +1 -1
  75. package/dist/types/core/attribution-costs.d.ts +35 -0
  76. package/dist/types/core/attribution-feedback.d.ts +133 -0
  77. package/dist/types/core/attribution-hooks.d.ts +147 -9
  78. package/dist/types/core/attribution-queries.d.ts +10 -0
  79. package/dist/types/core/attribution.d.ts +216 -182
  80. package/dist/types/core/constants.d.ts +56 -0
  81. package/dist/types/core/core.d.ts +190 -2
  82. package/dist/types/core/dev.d.ts +246 -28
  83. package/dist/types/core/effect.d.ts +8 -1
  84. package/dist/types/core/error-hooks.d.ts +71 -0
  85. package/dist/types/core/index.d.ts +4 -1
  86. package/dist/types/core/invariants.d.ts +4 -0
  87. package/dist/types/core/lanes.d.ts +39 -5
  88. package/dist/types/core/scheduler.d.ts +153 -0
  89. package/dist/types/core/types.d.ts +32 -9
  90. package/dist/types/index.d.ts +10 -3
  91. package/dist/types/map.d.ts +2 -0
  92. package/dist/types/signals.d.ts +8 -0
  93. package/dist/types/store/index.d.ts +2 -0
  94. package/dist/types/store/next/optimistic.d.ts +1 -1
  95. package/dist/types/store/next/store.d.ts +11 -5
  96. package/dist/types/store/next/target.d.ts +37 -10
  97. package/dist/types/store/utils.d.ts +178 -0
  98. package/package.json +21 -17
  99. package/dist/node.cjs +0 -10541
  100. package/dist/node.dev.cjs +0 -13724
  101. package/dist/types-cjs/affects.d.cts +0 -47
  102. package/dist/types-cjs/boundaries.d.cts +0 -175
  103. package/dist/types-cjs/core/action.d.cts +0 -64
  104. package/dist/types-cjs/core/async.d.cts +0 -23
  105. package/dist/types-cjs/core/attribution-hooks.d.cts +0 -127
  106. package/dist/types-cjs/core/attribution.d.cts +0 -495
  107. package/dist/types-cjs/core/constants.d.cts +0 -159
  108. package/dist/types-cjs/core/core.d.cts +0 -185
  109. package/dist/types-cjs/core/dev.d.cts +0 -136
  110. package/dist/types-cjs/core/effect.d.cts +0 -30
  111. package/dist/types-cjs/core/error.d.cts +0 -56
  112. package/dist/types-cjs/core/external.d.cts +0 -15
  113. package/dist/types-cjs/core/graph.d.cts +0 -28
  114. package/dist/types-cjs/core/heap.d.cts +0 -24
  115. package/dist/types-cjs/core/index.d.cts +0 -13
  116. package/dist/types-cjs/core/invariants.d.cts +0 -59
  117. package/dist/types-cjs/core/lanes.d.cts +0 -54
  118. package/dist/types-cjs/core/optimistic.d.cts +0 -6
  119. package/dist/types-cjs/core/owner.d.cts +0 -124
  120. package/dist/types-cjs/core/scheduler.d.cts +0 -236
  121. package/dist/types-cjs/core/types.d.cts +0 -204
  122. package/dist/types-cjs/core/verdict.d.cts +0 -2
  123. package/dist/types-cjs/index.d.cts +0 -10
  124. package/dist/types-cjs/map.d.cts +0 -69
  125. package/dist/types-cjs/package.json +0 -3
  126. package/dist/types-cjs/store/index.d.cts +0 -18
  127. package/dist/types-cjs/store/next/optimistic.d.cts +0 -25
  128. package/dist/types-cjs/store/next/projection.d.cts +0 -8
  129. package/dist/types-cjs/store/next/reconcile.d.cts +0 -10
  130. package/dist/types-cjs/store/next/store.d.cts +0 -121
  131. package/dist/types-cjs/store/next/target.d.cts +0 -166
  132. package/dist/types-cjs/store/store.d.cts +0 -143
  133. package/dist/types-cjs/store/storePath.d.cts +0 -58
  134. package/dist/types-cjs/store/utils.d.cts +0 -74
@@ -12,7 +12,9 @@ export { $REFRESH, SUPPORTS_PROXY } from "./core/constants.js";
12
12
 
13
13
  import "./core/invariants.js";
14
14
 
15
- export { enforceLoadingBoundary, flush, resetErrorHalt } from "./core/scheduler.js";
15
+ export { ownerPath } from "./core/dev.js";
16
+
17
+ export { ROOT_ERROR_HOOK, enforceLoadingBoundary, flush, resetErrorHalt } from "./core/scheduler.js";
16
18
 
17
19
  export { isPending, latest } from "./core/verdict.js";
18
20
 
@@ -20,6 +22,8 @@ import "./core/effect.js";
20
22
 
21
23
  export { action } from "./core/action.js";
22
24
 
25
+ export { configureClientErrors } from "./core/error-hooks.js";
26
+
23
27
  export { createEffect, createMemo, createOptimistic, createReaction, createRenderEffect, createSignal, createTrackedEffect, onCleanup, onSettled, refresh, resolve, until } from "./signals.js";
24
28
 
25
29
  export { affects } from "./affects.js";
@@ -32,16 +36,22 @@ export { createErrorBoundary, createLoadingBoundary, createRevealOrder, flatten
32
36
 
33
37
  export { $PROXY, $TARGET, $TRACK, isWrappable } from "./store/store.js";
34
38
 
39
+ export { MergeView, OmitView, SOURCE_MEMO, SOURCE_MERGE, SOURCE_OMIT, SOURCE_PLAIN, SOURCE_PROXY, hasStaticKeys, isStatic, merge, mergeSources, mergeView, omit, omitView, resolvedTable, sourceGet, sourceHas, sourceKeys, sourceOwners, viewOf } from "./store/utils.js";
40
+
35
41
  export { createOptimisticStoreNext as createOptimisticStore } from "./store/next/optimistic.js";
36
42
 
37
43
  export { createProjectionNext as createProjection } from "./store/next/projection.js";
38
44
 
39
- export { merge, omit } from "./store/utils.js";
40
-
41
45
  export { storeHasFamily, storeHasOptimisticFamily, storeIsShallow } from "./store/next/store.js";
42
46
 
43
47
  export { storePath } from "./store/storePath.js";
44
48
 
45
- const DEV = undefined;
49
+ /**
50
+ * Observe tier (diagnostics channel, attribution hook slot + interaction
51
+ * frame): dev and observe builds. The attribution engine itself is the
52
+ * `@solidjs/signals/attribution` entry.
53
+ */ const OBSERVE = undefined;
54
+
55
+ /** Dev tier (devtools hooks, graph traversal, console reporting): dev builds only. */ const DEV = undefined;
46
56
 
47
- export { DEV };
57
+ export { DEV, OBSERVE };
package/dist/prod/map.js CHANGED
@@ -24,165 +24,316 @@ function mapArray(t, s, i) {
24
24
  const e = typeof i?.keyed === "function" ? i.keyed : undefined;
25
25
  const r = s.length > 1;
26
26
  const n = s;
27
- const h = {
28
- $t: createOwner(),
29
- Jt: 0,
30
- Xt: t,
31
- Yt: [],
32
- Zt: n,
33
- ts: [],
34
- ss: [],
35
- Ht: e,
36
- es: e || i?.keyed === false ? [] : undefined,
37
- rs: r && i?.keyed !== false ? [] : undefined,
38
- ns: i?.keyed === false,
39
- hs: i?.fallback
27
+ const o = {
28
+ se: createOwner(),
29
+ ts: 0,
30
+ ss: t,
31
+ es: [],
32
+ rs: n,
33
+ ns: [],
34
+ hs: [],
35
+ qt: e,
36
+ fs: e || i?.keyed === false ? [] : undefined,
37
+ cs: r && i?.keyed !== false ? [] : undefined,
38
+ ls: i?.keyed === false,
39
+ us: i?.fallback
40
40
  };
41
- const o = computed(updateKeyedMap.bind(h), undefined);
41
+ const h = computed(updateKeyedMap.bind(o), undefined);
42
42
  // Untracked reads inside the internal owner resolve via _parentComputed; routing
43
43
  // them through node lets store-proxy lookups see pending writes (not stale _value).
44
- h.$t.Pt = o;
45
- o.T &= ~CONFIG_AUTO_DISPOSE;
46
- return accessor(o);
44
+ o.se.Qt = h;
45
+ h.T &= ~CONFIG_AUTO_DISPOSE;
46
+ return accessor(h);
47
47
  }
48
48
 
49
49
  const pureOptions = {
50
50
  ownedWrite: true
51
51
  };
52
52
 
53
- // Exception safety (#2903): a map callback can throw NotReadyError mid-pass
54
- // (async read), and the computed re-runs the whole pass after settle. Every
55
- // pass therefore STAGES its work — new rows are created into temp arrays and
56
- // removals are deferred — and commits to `this` only after every mapper
57
- // succeeded. An aborted pass disposes just the owners it created and leaves
58
- // `_items`/`_mappings`/`_nodes`/`_rows`/`_indexes`/`_len` exactly as they
59
- // were, so the retry diffs against uncorrupted state. Consequence of the
60
- // strong-abort ordering: removed rows now dispose AFTER the pass's new rows
61
- // are created (you cannot destroy state before knowing the pass will land).
53
+ function trySmallMove(t, s, i, e) {
54
+ const r = t.es;
55
+ const n = t.ts - 1;
56
+ const o = [];
57
+ const h = [];
58
+ const f = [];
59
+ // flat triples: oldStart, newStart, length
60
+ let c = 256;
61
+ let a = e;
62
+ let l = e;
63
+ let u = false;
64
+ while (a <= n && l <= i - 1) {
65
+ const t = r[a];
66
+ const e = s[l];
67
+ if (t === e) {
68
+ if (!u) {
69
+ f.push(a, l, 0);
70
+ u = true;
71
+ }
72
+ f[f.length - 1]++;
73
+ a++;
74
+ l++;
75
+ continue;
76
+ }
77
+ u = false;
78
+ // Bounded realignment lookahead, shorter distance wins.
79
+ let p = -1;
80
+ let d = Math.min(32 - o.length, n - a, c);
81
+ for (let t = 1; t <= d; t++) {
82
+ if (r[a + t] === e) {
83
+ p = t;
84
+ break;
85
+ }
86
+ }
87
+ c -= p === -1 ? d : p;
88
+ let w = -1;
89
+ d = Math.min(32 - h.length, i - 1 - l, c);
90
+ for (let i = 1; i <= d; i++) {
91
+ if (s[l + i] === t) {
92
+ w = i;
93
+ break;
94
+ }
95
+ }
96
+ c -= w === -1 ? d : w;
97
+ if (p !== -1 && (w === -1 || p <= w)) {
98
+ while (p-- > 0) o.push(a++);
99
+ continue;
100
+ }
101
+ if (w !== -1) {
102
+ while (w-- > 0) h.push(l++);
103
+ continue;
104
+ }
105
+ if (c <= 0 || o.length === 32 || h.length === 32) return false;
106
+ o.push(a++);
107
+ h.push(l++);
108
+ }
109
+ for (;a <= n; a++) {
110
+ if (o.length === 32) return false;
111
+ o.push(a);
112
+ }
113
+ for (;l <= i - 1; l++) {
114
+ if (h.length === 32) return false;
115
+ h.push(l);
116
+ }
117
+ return commitSmallMove(t, s, i, o, h, f);
118
+ }
119
+
120
+ /** PHASE 2 of the small-move path, in its OWN function so that a pass which
121
+ * only SCANS and bails (a full replace: the first structural pass of a page,
122
+ * typically) compiles nothing but the scan — V8 parses and compiles lazily
123
+ * per function, and cold `replace` measured +0.5 ms with both phases in one
124
+ * body. Pairs displaced sources with destinations (an unmatched destination
125
+ * is a replacement/insertion → general path), then commits: slice() the live
126
+ * arrays, copy shifted runs, patch displaced pairs, dispose leftovers. */ function commitSmallMove(t, s, i, e, r, n) {
127
+ const o = t.es;
128
+ let h;
129
+ let f;
130
+ let c;
131
+ if (r.length !== 0) {
132
+ c = new Array(e.length);
133
+ for (f = 0; f < r.length; f++) {
134
+ let t = -1;
135
+ for (h = 0; h < e.length; h++) {
136
+ if (!c[h] && o[e[h]] === s[r[f]]) {
137
+ t = h;
138
+ break;
139
+ }
140
+ }
141
+ if (t === -1) return false;
142
+ c[t] = true;
143
+ r[f] = r[f] << 6 | t;
144
+ // pack pairing (found < 32)
145
+ }
146
+ }
147
+ // DUPLICATES: the general path pairs equal identities by OCCURRENCE ORDER
148
+ // (the chained index map). Displaced↔displaced pairing above is ascending
149
+ // on both sides, so it agrees; but an aligned run was matched by POSITION,
150
+ // and if a displaced identity also occurs inside a run the two algorithms
151
+ // can hand different occurrences different owners (row-local state moves;
152
+ // a shrink could dispose the wrong one). Decline that case — general path.
153
+ if (e.length !== 0 || r.length !== 0) {
154
+ const t = new Set;
155
+ for (h = 0; h < e.length; h++) t.add(o[e[h]]);
156
+ for (f = 0; f < r.length; f++) t.add(s[r[f] >> 6]);
157
+ for (let s = 0; s < n.length; s += 3) {
158
+ const i = n[s];
159
+ for (let e = 0, r = n[s + 2]; e < r; e++) if (t.has(o[i + e])) return false;
160
+ }
161
+ }
162
+ const a = t.ns;
163
+ const l = t.hs;
164
+ const u = a.slice(0, i);
165
+ const p = l.slice(0, i);
166
+ for (let t = 0; t < n.length; t += 3) {
167
+ const s = n[t];
168
+ const i = n[t + 1];
169
+ if (s !== i) {
170
+ for (let e = 0; e < n[t + 2]; e++) {
171
+ u[i + e] = a[s + e];
172
+ p[i + e] = l[s + e];
173
+ }
174
+ }
175
+ }
176
+ for (f = 0; f < r.length; f++) {
177
+ const t = r[f] >> 6;
178
+ const s = e[r[f] & 63];
179
+ u[t] = a[s];
180
+ p[t] = l[s];
181
+ }
182
+ t.ns = u;
183
+ t.hs = p;
184
+ t.ts = i;
185
+ t.es = s.slice(0);
186
+ // Dispose unmatched sources LAST (general-path ordering).
187
+ for (h = 0; h < e.length; h++) {
188
+ if (c === undefined || !c[h]) l[e[h]].dispose();
189
+ }
190
+ return true;
191
+ }
192
+
62
193
  function updateKeyedMap() {
63
- const t = this.Xt() || [], s = t.length;
194
+ const t = this.ss() || [], s = t.length;
64
195
  t[$TRACK];
65
196
  // top level tracking
66
- runWithOwner(this.$t, () => {
197
+ runWithOwner(this.se, () => {
67
198
  let i, e, r, n,
68
199
  // Mappers write freshly-created row/index signals into the STAGE
69
200
  // arrays (`rows`/`indexes`), never into `this._rows`/`this._indexes`.
70
- h = this.es ? this.ns ? () => {
201
+ o = this.fs ? this.ls ? () => {
71
202
  r[e] = signal(t[e], pureOptions);
72
- return this.Zt(accessor(r[e]), e);
203
+ return this.rs(accessor(r[e]), e);
73
204
  } : () => {
74
205
  r[e] = signal(t[e], pureOptions);
75
206
  n && (n[e] = signal(e, pureOptions));
76
- return this.Zt(accessor(r[e]), n ? accessor(n[e]) : undefined);
77
- } : this.rs ? () => {
207
+ return this.rs(accessor(r[e]), n ? accessor(n[e]) : undefined);
208
+ } : this.cs ? () => {
78
209
  const s = t[e];
79
210
  n[e] = signal(e, pureOptions);
80
- return this.Zt(s, accessor(n[e]));
211
+ return this.rs(s, accessor(n[e]));
81
212
  } : () => {
82
213
  const s = t[e];
83
- return this.Zt(s);
214
+ return this.rs(s);
84
215
  };
85
216
  // fast path for empty arrays
86
217
  if (s === 0) {
87
- if (this.Jt !== 0) {
88
- this.$t.dispose(false);
89
- this.ss = [];
90
- this.Yt = [];
91
- this.ts = [];
92
- this.Jt = 0;
93
- this.es && (this.es = []);
94
- this.rs && (this.rs = []);
218
+ if (this.ts !== 0) {
219
+ this.se.dispose(false);
220
+ this.hs = [];
221
+ this.es = [];
222
+ this.ns = [];
223
+ this.ts = 0;
224
+ this.fs && (this.fs = []);
225
+ this.cs && (this.cs = []);
95
226
  }
96
- if (this.hs && !this.ts[0]) {
227
+ if (this.us && !this.ns[0]) {
97
228
  // an aborted fallback attempt leaves an owner without a mapping;
98
229
  // dispose it before re-creating
99
- this.ss[0]?.dispose();
100
- this.ts[0] = runWithOwner(this.ss[0] = createOwner(), this.hs);
230
+ this.hs[0]?.dispose();
231
+ this.ns[0] = runWithOwner(this.hs[0] = createOwner(), this.us);
101
232
  }
102
233
  }
103
234
  // fast path for new create
104
- else if (this.Jt === 0) {
105
- const o = new Array(s);
106
- const a = new Array(s);
107
- r = this.es && new Array(s);
108
- n = this.rs && new Array(s);
235
+ else if (this.ts === 0) {
236
+ const h = new Array(s);
237
+ const f = new Array(s);
238
+ r = this.fs && new Array(s);
239
+ n = this.cs && new Array(s);
109
240
  try {
110
- for (e = 0; e < s; e++) o[e] = runWithOwner(a[e] = createOwner(), h);
241
+ for (e = 0; e < s; e++) h[e] = runWithOwner(f[e] = createOwner(), o);
111
242
  } catch (t) {
112
- for (i = 0; i <= e; i++) a[i]?.dispose();
243
+ for (i = 0; i <= e; i++) f[i]?.dispose();
113
244
  throw t;
114
245
  }
115
246
  // commit
116
- if (this.ss[0]) this.ss[0].dispose();
247
+ if (this.hs[0]) this.hs[0].dispose();
117
248
  // previous fallback
118
- this.ts = o;
119
- this.ss = a;
120
- r && (this.es = r);
121
- n && (this.rs = n);
122
- this.Yt = t.slice(0);
123
- this.Jt = s;
249
+ this.ns = h;
250
+ this.hs = f;
251
+ r && (this.fs = r);
252
+ n && (this.cs = n);
253
+ this.es = t.slice(0);
254
+ this.ts = s;
124
255
  } else {
125
- let o, a, c, f, u, p, l, d, w,
256
+ let h, f, c, a, l, u, p, d, w,
126
257
  // Dev (attribution engine installed): the items behind the exited and
127
258
  // entered rows, for the list-identity census.
128
259
  m, O;
129
260
  // skip common prefix
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++) {
131
- if (this.es) setSignal(this.es[o], t[o]);
261
+ for (h = 0, f = Math.min(this.ts, s); h < f && (this.es[h] === t[h] || this.fs && compare(this.qt, this.es[h], t[h])); h++) {
262
+ if (this.fs) setSignal(this.fs[h], t[h]);
132
263
  }
133
264
  // skip common suffix — counted only; retained entries land in one pass
134
265
  // at commit instead of being staged and copied twice
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--,
266
+ for (f = this.ts - 1, c = s - 1; f >= h && c >= h && (this.es[f] === t[c] || this.fs && compare(this.qt, this.es[f], t[c])); f--,
136
267
  c--) ;
137
268
  // no structural change (every position matched in place at equal
138
269
  // length — the common post-reconcile shape): keep the same mapped
139
270
  // array identity so downstream consumers don't re-run at all
140
- if (o === s && this.Jt === s) {
141
- this.Yt = t.slice(0);
271
+ if (h === s && this.ts === s) {
272
+ this.es = t.slice(0);
142
273
  return;
143
274
  }
144
- const _ = s - this.Jt;
275
+ // SMALL-MOVE FAST PATH: extracted to its own function — inlining it
276
+ // here bloats updateKeyedMap past the JIT's optimization budget and
277
+ // deoptimizes the GENERAL path (measured 2x on reverse). Gated to
278
+ // LARGE trimmed windows: when the trims already shrank the window
279
+ // (plain removals, tail edits), the general path is window-
280
+ // proportional and cheap — the fast path would only re-walk what the
281
+ // trims proved.
282
+ if (s <= this.ts && f - h > 64 && this.fs === undefined && this.cs === undefined) {
283
+ // PROBE before the scan: a small move keeps a mid-window item within
284
+ // ±32 of its old position; a REPLACE (all fresh items — the shape
285
+ // every page's first structural pass usually is) has it nowhere.
286
+ // ~65 compares, no allocation, and the scan function is never
287
+ // compiled for a replace (its cold first-call compile was the cost).
288
+ const i = h + (c - h >> 1);
289
+ const e = t[i];
290
+ const r = Math.min(f, i + 32);
291
+ let n = Math.max(h, i - 32);
292
+ while (n <= r && this.es[n] !== e) n++;
293
+ if (n <= r && trySmallMove(this, t, s, h)) return;
294
+ }
295
+ const _ = s - this.ts;
145
296
  const y = new Array(s);
146
297
  const A = new Array(s);
147
- r = this.es ? new Array(s) : undefined;
148
- n = this.rs ? new Array(s) : undefined;
298
+ r = this.fs ? new Array(s) : undefined;
299
+ n = this.cs ? new Array(s) : undefined;
149
300
  // 0) prepare a map of all indices in the changed window of newItems,
150
301
  // scanning backwards so we encounter them in natural order
151
- p = new Map;
152
- l = new Array(c + 1);
153
- for (e = c; e >= o; e--) {
154
- f = t[e];
155
- u = this.Ht ? this.Ht(f) : f;
156
- i = p.get(u);
157
- l[e] = i === undefined ? -1 : i;
158
- p.set(u, e);
302
+ u = new Map;
303
+ p = new Array(c + 1);
304
+ for (e = c; e >= h; e--) {
305
+ a = t[e];
306
+ l = this.qt ? this.qt(a) : a;
307
+ i = u.get(l);
308
+ p[e] = i === undefined ? -1 : i;
309
+ u.set(l, e);
159
310
  }
160
311
  // 1) step through the old changed window and see if items can be found
161
312
  // in the new set; if so, stage them at their new positions; if not,
162
313
  // queue them for disposal at commit
163
- for (i = o; i <= a; i++) {
164
- f = this.Yt[i];
165
- u = this.Ht ? this.Ht(f) : f;
166
- e = p.get(u);
314
+ for (i = h; i <= f; i++) {
315
+ a = this.es[i];
316
+ l = this.qt ? this.qt(a) : a;
317
+ e = u.get(l);
167
318
  if (e !== undefined && e !== -1) {
168
- y[e] = this.ts[i];
169
- A[e] = this.ss[i];
170
- r && (r[e] = this.es[i]);
171
- n && (n[e] = this.rs[i]);
172
- e = l[e];
173
- p.set(u, e);
319
+ y[e] = this.ns[i];
320
+ A[e] = this.hs[i];
321
+ r && (r[e] = this.fs[i]);
322
+ n && (n[e] = this.cs[i]);
323
+ e = p[e];
324
+ u.set(l, e);
174
325
  } else {
175
- (d ??= []).push(this.ss[i]);
326
+ (d ??= []).push(this.hs[i]);
176
327
  if (false && attrHooks !== null) ;
177
328
  }
178
329
  }
179
330
  // 2) create new rows into the temp arrays; an abort disposes only these
180
331
  try {
181
- for (e = o; e <= c; e++) {
332
+ for (e = h; e <= c; e++) {
182
333
  if (A[e] !== undefined) continue;
183
334
  (w ??= []).push(A[e] = createOwner());
184
335
  if (false && attrHooks !== null) ;
185
- y[e] = runWithOwner(A[e], h);
336
+ y[e] = runWithOwner(A[e], o);
186
337
  }
187
338
  } catch (t) {
188
339
  if (w) for (i = 0; i < w.length; i++) w[i].dispose();
@@ -191,40 +342,40 @@ function updateKeyedMap() {
191
342
  // 3) commit: land the retained prefix and suffix plus the staged window
192
343
  // into the fresh arrays, swap them in (new identity for downstream
193
344
  // change propagation), then dispose exited rows
194
- for (i = 0; i < o; i++) {
195
- y[i] = this.ts[i];
196
- A[i] = this.ss[i];
197
- r && (r[i] = this.es[i]);
198
- n && (n[i] = this.rs[i]);
345
+ for (i = 0; i < h; i++) {
346
+ y[i] = this.ns[i];
347
+ A[i] = this.hs[i];
348
+ r && (r[i] = this.fs[i]);
349
+ n && (n[i] = this.cs[i]);
199
350
  }
200
- for (e = o; e <= c; e++) {
351
+ for (e = h; e <= c; e++) {
201
352
  if (r) setSignal(r[e], t[e]);
202
353
  if (n) setSignal(n[e], e);
203
354
  }
204
355
  for (e = c + 1; e < s; e++) {
205
- y[e] = this.ts[e - _];
206
- A[e] = this.ss[e - _];
356
+ y[e] = this.ns[e - _];
357
+ A[e] = this.hs[e - _];
207
358
  if (r) {
208
- r[e] = this.es[e - _];
359
+ r[e] = this.fs[e - _];
209
360
  setSignal(r[e], t[e]);
210
361
  }
211
362
  if (n) {
212
- n[e] = this.rs[e - _];
363
+ n[e] = this.cs[e - _];
213
364
  if (_ !== 0) setSignal(n[e], e);
214
365
  }
215
366
  }
216
- this.ts = y;
217
- this.ss = A;
218
- r && (this.es = r);
219
- n && (this.rs = n);
220
- this.Jt = s;
367
+ this.ns = y;
368
+ this.hs = A;
369
+ r && (this.fs = r);
370
+ n && (this.cs = n);
371
+ this.ts = s;
221
372
  // save a copy of the mapped items for the next update
222
- this.Yt = t.slice(0);
373
+ this.es = t.slice(0);
223
374
  if (d) for (i = 0; i < d.length; i++) d[i].dispose();
224
375
  if (false && attrHooks !== null && m !== undefined && O !== undefined) ;
225
376
  }
226
377
  });
227
- return this.ts;
378
+ return this.ns;
228
379
  }
229
380
 
230
381
  /**
@@ -244,21 +395,21 @@ function updateKeyedMap() {
244
395
  */ function repeat(t, s, i) {
245
396
  const e = s;
246
397
  const r = {
247
- $t: createOwner(),
248
- Jt: 0,
249
- cs: 0,
250
- fs: t,
251
- Zt: e,
252
- ss: [],
253
- ts: [],
254
- us: i?.from,
255
- hs: i?.fallback
398
+ se: createOwner(),
399
+ ts: 0,
400
+ ps: 0,
401
+ ds: t,
402
+ rs: e,
403
+ hs: [],
404
+ ns: [],
405
+ ws: i?.from,
406
+ us: i?.fallback
256
407
  };
257
408
  const n = computed(updateRepeat.bind(r));
258
409
  // Same as mapArray: untracked reads inside the internal owner resolve via
259
410
  // _parentComputed, so async reads in row callbacks register with the node
260
411
  // (pending tracking + post-settle retry) instead of vanishing.
261
- r.$t.Pt = n;
412
+ r.se.Qt = n;
262
413
  n.T &= ~CONFIG_AUTO_DISPOSE;
263
414
  return accessor(n);
264
415
  }
@@ -271,55 +422,55 @@ function updateKeyedMap() {
271
422
  // for the post-settle retry. The overlap math also subsumes the previous
272
423
  // disjoint-window/front-clear/end-clear/shift special cases.
273
424
  function updateRepeat() {
274
- const t = this.fs();
275
- const s = this.us?.() || 0;
276
- runWithOwner(this.$t, () => {
425
+ const t = this.ds();
426
+ const s = this.ws?.() || 0;
427
+ runWithOwner(this.se, () => {
277
428
  if (t === 0) {
278
- if (this.Jt !== 0) {
279
- this.$t.dispose(false);
280
- this.ss = [];
281
- this.ts = [];
282
- this.Jt = 0;
429
+ if (this.ts !== 0) {
430
+ this.se.dispose(false);
431
+ this.hs = [];
432
+ this.ns = [];
433
+ this.ts = 0;
283
434
  // Reset offset to match the cleared data (#2767, repro 2).
284
- this.cs = 0;
435
+ this.ps = 0;
285
436
  }
286
- if (this.hs && !this.ts[0]) {
437
+ if (this.us && !this.ns[0]) {
287
438
  // an aborted fallback attempt leaves an owner without a mapping;
288
439
  // dispose it before re-creating
289
- this.ss[0]?.dispose();
290
- this.ts[0] = runWithOwner(this.ss[0] = createOwner(), this.hs);
440
+ this.hs[0]?.dispose();
441
+ this.ns[0] = runWithOwner(this.hs[0] = createOwner(), this.us);
291
442
  }
292
443
  return;
293
444
  }
294
445
  const i = s + t;
295
- const e = this.cs + this.Jt;
446
+ const e = this.ps + this.ts;
296
447
  // Retained overlap [keepStart, keepEnd) in global indexes; empty when the
297
448
  // windows are disjoint or when coming from empty/fallback.
298
- const r = Math.max(s, this.cs);
449
+ const r = Math.max(s, this.ps);
299
450
  const n = Math.min(i, e);
300
- const h = new Array(t);
301
451
  const o = new Array(t);
452
+ const h = new Array(t);
302
453
  for (let t = r; t < n; t++) {
303
- o[t - s] = this.ss[t - this.cs];
304
- h[t - s] = this.ts[t - this.cs];
454
+ h[t - s] = this.hs[t - this.ps];
455
+ o[t - s] = this.ns[t - this.ps];
305
456
  }
306
457
  try {
307
458
  for (let t = s; t < i; t++) {
308
459
  if (t >= r && t < n) continue;
309
- h[t - s] = runWithOwner(o[t - s] = createOwner(), () => this.Zt(t));
460
+ o[t - s] = runWithOwner(h[t - s] = createOwner(), () => this.rs(t));
310
461
  }
311
462
  } catch (t) {
312
- for (let t = s; t < i; t++) if ((t < r || t >= n) && o[t - s]) o[t - s].dispose();
463
+ for (let t = s; t < i; t++) if ((t < r || t >= n) && h[t - s]) h[t - s].dispose();
313
464
  throw t;
314
465
  }
315
466
  // commit: dispose the previous fallback or the rows leaving the window
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;
319
- this.cs = s;
320
- this.Jt = t;
467
+ if (this.ts === 0) this.hs[0]?.dispose(); else for (let t = this.ps; t < e; t++) if (t < s || t >= i) this.hs[t - this.ps].dispose();
468
+ this.ns = o;
469
+ this.hs = h;
470
+ this.ps = s;
471
+ this.ts = t;
321
472
  });
322
- return this.ts;
473
+ return this.ns;
323
474
  }
324
475
 
325
476
  function compare(t, s, i) {