@solidjs/signals 2.0.0-beta.19 → 2.0.0-beta.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 (36) hide show
  1. package/dist/dev.js +670 -371
  2. package/dist/node.cjs +1878 -1606
  3. package/dist/prod/affects.js +17 -21
  4. package/dist/prod/core/action.js +19 -6
  5. package/dist/prod/core/async.js +57 -71
  6. package/dist/prod/core/constants.js +15 -1
  7. package/dist/prod/core/core.js +39 -39
  8. package/dist/prod/core/effect.js +14 -14
  9. package/dist/prod/core/graph.js +1 -1
  10. package/dist/prod/core/heap.js +2 -2
  11. package/dist/prod/core/lanes.js +23 -13
  12. package/dist/prod/core/optimistic.js +107 -99
  13. package/dist/prod/core/owner.js +23 -23
  14. package/dist/prod/core/scheduler.js +180 -180
  15. package/dist/prod/core/verdict.js +12 -13
  16. package/dist/prod/map.js +196 -167
  17. package/dist/prod/signals.js +1 -1
  18. package/dist/prod/store/optimistic.js +103 -68
  19. package/dist/prod/store/reconcile.js +80 -46
  20. package/dist/prod/store/store.js +204 -73
  21. package/dist/prod/store/utils.js +61 -42
  22. package/dist/types/core/action.d.ts +19 -6
  23. package/dist/types/core/constants.d.ts +12 -0
  24. package/dist/types/core/dev.d.ts +7 -0
  25. package/dist/types/core/lanes.d.ts +2 -0
  26. package/dist/types/core/scheduler.d.ts +2 -6
  27. package/dist/types/core/types.d.ts +9 -1
  28. package/dist/types/store/store.d.ts +8 -2
  29. package/dist/types-cjs/core/action.d.cts +19 -6
  30. package/dist/types-cjs/core/constants.d.cts +12 -0
  31. package/dist/types-cjs/core/dev.d.cts +7 -0
  32. package/dist/types-cjs/core/lanes.d.cts +2 -0
  33. package/dist/types-cjs/core/scheduler.d.cts +2 -6
  34. package/dist/types-cjs/core/types.d.cts +9 -1
  35. package/dist/types-cjs/store/store.d.cts +8 -2
  36. package/package.json +1 -1
@@ -2,7 +2,7 @@ import { computed } from "../core/core.js";
2
2
 
3
3
  import { CONFIG_AUTO_DISPOSE, NOT_PENDING } from "../core/constants.js";
4
4
 
5
- import { GlobalQueue, schedule, setProjectionWriteActive, insertSubs, projectionWriteActive } from "../core/scheduler.js";
5
+ import { GlobalQueue, schedule, currentTransition, insertSubs, setProjectionWriteActive, projectionWriteActive } from "../core/scheduler.js";
6
6
 
7
7
  import "../core/invariants.js";
8
8
 
@@ -14,126 +14,161 @@ import { installOptimisticEngine } from "../core/optimistic.js";
14
14
 
15
15
  import { runProjectionComputed } from "./projection.js";
16
16
 
17
- import { storeSetter, $TARGET, STORE_OPTIMISTIC_OVERRIDE, STORE_NODE, getOverlayLayer, STORE_VALUE, $DELETED, isWrappable, wrap, visibleNodeValue, $TRACK, notifySelf, STORE_WRAP, createStoreProxy, storeTraps, STORE_LOOKUP, STORE_OPTIMISTIC, STORE_FIREWALL } from "./store.js";
17
+ import { storeSetter, $TARGET, STORE_OPTIMISTIC_OVERRIDE, STORE_NODE, STORE_OPTIMISTIC_OWNERS, getOverlayLayer, STORE_VALUE, $DELETED, isWrappable, wrap, visibleNodeValue, $TRACK, notifySelf, STORE_WRAP, createStoreProxy, storeTraps, STORE_LOOKUP, STORE_OPTIMISTIC, STORE_FIREWALL } from "./store.js";
18
18
 
19
- function createOptimisticStore(t, e, r) {
19
+ function createOptimisticStore(e, t, r) {
20
20
  // Register clear function with scheduler; store nodes marked
21
21
  // STORE_OPTIMISTIC take the engine's write path, so install it before any
22
22
  // node can be created.
23
23
  installOptimisticEngine();
24
- GlobalQueue.Kt ||= clearOptimisticStores;
25
- const i = typeof t === "function";
26
- const o = i ? e : t;
27
- const c = i ? t : undefined;
24
+ GlobalQueue.Vt ||= clearOptimisticStores;
25
+ const i = typeof e === "function";
26
+ const o = i ? t : e;
27
+ const n = i ? e : undefined;
28
28
  // Create optimistic projection store
29
- const {store: n} = createOptimisticProjectionInternal(c, o, r);
30
- return [ n, t => storeSetter(n, t) ];
29
+ const {store: c} = createOptimisticProjectionInternal(n, o, r);
30
+ return [ c, e => storeSetter(c, e) ];
31
31
  }
32
32
 
33
33
  // Clear the optimistic overrides of a settling batch of stores and notify
34
34
  // signals. Owns the whole batch (iterate + clear + reschedule) so the
35
- // scheduler's flush tail carries only a size-guarded hook call.
36
- function clearOptimisticStores(t) {
37
- for (const e of t) {
38
- const t = e[$TARGET];
39
- if (t?.[STORE_OPTIMISTIC_OVERRIDE]) clearOptimisticOverride(t);
35
+ // scheduler's flush tail carries only a size-guarded hook call. The
36
+ // completing transition scopes each clear to its own layer keys (#2899).
37
+ function clearOptimisticStores(e, t) {
38
+ for (const r of e) {
39
+ const e = r[$TARGET];
40
+ if (e?.[STORE_OPTIMISTIC_OVERRIDE]) clearOptimisticOverride(e, t);
40
41
  }
41
- t.clear();
42
+ e.clear();
42
43
  schedule();
43
44
  }
44
45
 
45
- function clearOptimisticOverride(t) {
46
- const e = t[STORE_OPTIMISTIC_OVERRIDE];
47
- if (!e) return;
48
- const r = t[STORE_NODE];
49
- delete t[STORE_OPTIMISTIC_OVERRIDE];
50
- // Notify signals for all overridden properties
46
+ /**
47
+ * Consume optimistic layer entries and reset their backing nodes to base.
48
+ * With `completing` (settle path, #2899) only entries the settling
49
+ * transaction owns are consumed — the layer is store-wide but concurrent
50
+ * actions revert independently, so keys stamped by a still-in-flight
51
+ * transition survive (node-level overrides already have this granularity via
52
+ * _optimisticNodes; this is the layer's half). `null` consumes ambient
53
+ * (transaction-less) entries at plain flush end. Omitted (projection landing:
54
+ * fresh authoritative data) consumes everything — the correction supersedes
55
+ * every tentative layer.
56
+ */ function clearOptimisticOverride(e, t) {
57
+ const r = e[STORE_OPTIMISTIC_OVERRIDE];
58
+ if (!r) return;
59
+ const i = e[STORE_NODE];
60
+ const o = e[STORE_OPTIMISTIC_OWNERS];
61
+ const n = t !== undefined;
62
+ let c = false;
63
+ let s = false;
51
64
  // Use projectionWriteActive to bypass optimistic signal behavior (no lane creation)
52
65
  // This ensures reversion effects go to regular queues, not lane queues
53
- const i = projectionWriteActive;
66
+ const O = projectionWriteActive;
54
67
  setProjectionWriteActive(true);
55
68
  try {
56
- if (r) {
57
- for (const i of Reflect.ownKeys(e)) {
58
- if (r[i]) {
59
- const e = r[i];
60
- // Clear lane association so effects go to regular queue
61
- e.Je = undefined;
62
- // Re-read from base the optimistic layer was deleted above, so the
63
- // overlay resolves to STORE_OVERRIDE or STORE_VALUE.
64
- const o = getOverlayLayer(t, i);
65
- const c = o ? o[i] : t[STORE_VALUE][i];
66
- const n = c === $DELETED ? undefined : c;
67
- const s = isWrappable(n) ? wrap(n, t) : n;
68
- const O = visibleNodeValue(e);
69
- e.be = NOT_PENDING;
70
- e.ge = NOT_PENDING;
71
- e.Ue = s;
72
- if (!e.Ge || !e.Ge(O, s)) {
73
- insertSubs(e, true);
74
- schedule();
69
+ for (const O of Reflect.ownKeys(r)) {
70
+ if (n) {
71
+ let e = o?.[O] ?? null;
72
+ // Resolve merge chains (entangled actions settle as one); path-compress
73
+ // so later keys skip the walk. A dead owner (`_done === true`) settled
74
+ // through some other path — never strand its entry. A null owner is an
75
+ // ambient write: its batch belongs to whichever transaction adopted it
76
+ // (initTransition mid-batch) or to the plain flush, so it clears on
77
+ // whichever clear call reaches this store first.
78
+ if (e) {
79
+ if (typeof e.cn === "object") e = o[O] = currentTransition(e);
80
+ if (e !== t && e.cn !== true) {
81
+ s = true;
82
+ continue;
75
83
  }
76
84
  }
77
85
  }
78
- // Notify $TRACK
79
- if (r[$TRACK]) {
80
- r[$TRACK].Je = undefined;
81
- notifySelf(t);
86
+ delete r[O];
87
+ if (o) delete o[O];
88
+ c = true;
89
+ const T = i?.[O];
90
+ if (T) {
91
+ // Clear lane association so effects go to regular queue
92
+ T.Je = undefined;
93
+ // Re-read from base — this key left the optimistic layer above, so the
94
+ // overlay resolves to STORE_OVERRIDE or STORE_VALUE.
95
+ const t = getOverlayLayer(e, O);
96
+ const r = t ? t[O] : e[STORE_VALUE][O];
97
+ const i = r === $DELETED ? undefined : r;
98
+ const o = isWrappable(i) ? wrap(i, e) : i;
99
+ const n = visibleNodeValue(T);
100
+ T.be = NOT_PENDING;
101
+ T.fn = null;
102
+ T.ge = NOT_PENDING;
103
+ T.Ue = o;
104
+ if (!T.Ge || !T.Ge(n, o)) {
105
+ insertSubs(T, true);
106
+ schedule();
107
+ }
82
108
  }
83
109
  }
110
+ if (!s) {
111
+ delete e[STORE_OPTIMISTIC_OVERRIDE];
112
+ delete e[STORE_OPTIMISTIC_OWNERS];
113
+ }
114
+ // Notify $TRACK
115
+ if (c && i?.[$TRACK]) {
116
+ i[$TRACK].Je = undefined;
117
+ notifySelf(e);
118
+ }
84
119
  } finally {
85
- setProjectionWriteActive(i);
120
+ setProjectionWriteActive(O);
86
121
  }
87
122
  }
88
123
 
89
- function createOptimisticProjectionInternal(t, e, r) {
124
+ function createOptimisticProjectionInternal(e, t, r) {
90
125
  let i;
91
126
  const o = new WeakMap;
92
- const wrapper = t => {
93
- t[STORE_WRAP] = wrapProjection;
94
- t[STORE_LOOKUP] = o;
95
- t[STORE_OPTIMISTIC] = true;
127
+ const wrapper = e => {
128
+ e[STORE_WRAP] = wrapProjection;
129
+ e[STORE_LOOKUP] = o;
130
+ e[STORE_OPTIMISTIC] = true;
96
131
  // Mark as optimistic store
97
- Object.defineProperty(t, STORE_FIREWALL, {
132
+ Object.defineProperty(e, STORE_FIREWALL, {
98
133
  get() {
99
134
  return i;
100
135
  },
101
136
  configurable: true
102
137
  });
103
138
  };
104
- const wrapProjection = t => {
105
- if (o.has(t)) return o.get(t);
106
- if (t[$TARGET]?.[STORE_WRAP] === wrapProjection) return t;
107
- const e = createStoreProxy(t, storeTraps, wrapper);
108
- o.set(t, e);
109
- return e;
139
+ const wrapProjection = e => {
140
+ if (o.has(e)) return o.get(e);
141
+ if (e[$TARGET]?.[STORE_WRAP] === wrapProjection) return e;
142
+ const t = createStoreProxy(e, storeTraps, wrapper);
143
+ o.set(e, t);
144
+ return t;
110
145
  };
111
- const c = wrapProjection(e);
146
+ const n = wrapProjection(t);
112
147
  // If there's a projection function, create a computed to drive it
113
- if (t) {
148
+ if (e) {
114
149
  // All writes inside firewall recompute must go to STORE_OVERRIDE (base), not
115
150
  // STORE_OPTIMISTIC_OVERRIDE. The outer wrap covers the sync body (including
116
151
  // `fn(draft)` and the initial commit); `wrapCommit` re-applies the flag for
117
152
  // async yields because they fire outside any enclosing try/finally. It also
118
153
  // consumes stale optimistic overlays once fresh projected data lands.
119
154
  const clearProjectionOverride = () => {
120
- const t = c[$TARGET];
121
- if (t?.[STORE_OPTIMISTIC_OVERRIDE]) clearOptimisticOverride(t);
155
+ const e = n[$TARGET];
156
+ if (e?.[STORE_OPTIMISTIC_OVERRIDE]) clearOptimisticOverride(e);
122
157
  };
123
- const wrapCommit = t => {
124
- const e = projectionWriteActive;
158
+ const wrapCommit = e => {
159
+ const t = projectionWriteActive;
125
160
  setProjectionWriteActive(true);
126
161
  try {
127
- t();
162
+ e();
128
163
  clearProjectionOverride();
129
164
  } finally {
130
- setProjectionWriteActive(e);
165
+ setProjectionWriteActive(t);
131
166
  }
132
167
  };
133
168
  i = computed(() => {
134
169
  setProjectionWriteActive(true);
135
170
  try {
136
- runProjectionComputed(c, t, r?.key || "id", wrapCommit, clearProjectionOverride);
171
+ runProjectionComputed(n, e, r?.key || "id", wrapCommit, clearProjectionOverride);
137
172
  } finally {
138
173
  setProjectionWriteActive(false);
139
174
  }
@@ -141,7 +176,7 @@ function createOptimisticProjectionInternal(t, e, r) {
141
176
  i.U &= ~CONFIG_AUTO_DISPOSE;
142
177
  }
143
178
  return {
144
- store: c,
179
+ store: n,
145
180
  node: i
146
181
  };
147
182
  }
@@ -8,7 +8,7 @@ import "../core/verdict.js";
8
8
 
9
9
  import "../core/effect.js";
10
10
 
11
- import { $TARGET, STORE_OVERRIDE, STORE_OPTIMISTIC_OVERRIDE, STORE_VALUE, STORE_NODE, storeLookup, STORE_LOOKUP, $PROXY, isWrappable, wrap, notifySelf, $TRACK, STORE_HAS, getKeys, $DELETED, symbolKeyedRecords } from "./store.js";
11
+ import { $TARGET, STORE_OVERRIDE, STORE_OPTIMISTIC_OVERRIDE, STORE_VALUE, STORE_NODE, storeLookup, STORE_LOOKUP, $PROXY, isWrappable, wrap, notifySelf, $TRACK, STORE_DESC, STORE_HAS, getKeys, $DELETED, symbolKeyedRecords, getStoreSymbols } from "./store.js";
12
12
 
13
13
  // Enumerate a node record's keys. Keeps the common string-key path on the
14
14
  // `Object.keys` fast path; only records currently holding a user symbol node
@@ -45,6 +45,8 @@ function addEnumSymbols(e, t, r) {
45
45
  }
46
46
 
47
47
  function getAllKeys(e, t, r) {
48
+ // Symbols are merged explicitly below; keep the common string-key path on
49
+ // Object.keys() and avoid reflecting the base symbols twice.
48
50
  const n = getKeys(e, t);
49
51
  const a = Object.keys(r);
50
52
  // `value` can be a wrapped store (store-in-store) whose ownKeys trap tracks;
@@ -131,6 +133,34 @@ function applyArrayItem(e, t, r, n, a) {
131
133
  } else n && setSignal(n, wrapValue(e, r));
132
134
  }
133
135
 
136
+ /**
137
+ * The captured-proxy half of the object diff (#2902): descend into keyed-
138
+ * matching children that have NO node at this level but shelter subscribers
139
+ * somewhere below (their target's sticky `STORE_DESC` flag, bubbled up by
140
+ * `getNode`). Without this, a proxy captured through untracked reads — a
141
+ * `<For>` row handed to a child component — detaches from the diff the
142
+ * moment no intermediate level happens to be tracked, and its live
143
+ * subscribers go permanently stale. Never-subscribed branches have no flag
144
+ * and stay pruned exactly as before; keys the main loop already visited
145
+ * (node present) are skipped. Callers gate on the parent's own flag and on
146
+ * `$TRACK` absence (an enumeration-tracked record already diffs every key).
147
+ */ function applyDescendants(e, t, r, n, a, i, o) {
148
+ const l = r[STORE_LOOKUP] || storeLookup;
149
+ const s = (i ? getKeys(e, i) : Object.keys(e)).concat(getStoreSymbols(e, i));
150
+ for (let p = 0, f = s.length; p < f; p++) {
151
+ const f = s[p];
152
+ if (n?.[f]) continue;
153
+ // main loop already diffed this slot
154
+ const c = unwrap(i ? getOverrideValue(e, i, f, o) : e[f]);
155
+ if (!isWrappable(c)) continue;
156
+ const u = (l.get(c) ?? storeLookup.get(c))?.[$TARGET];
157
+ if (!u?.[STORE_DESC]) continue;
158
+ const S = unwrap(t[f]);
159
+ if (c === S || !isWrappable(S) || Array.isArray(c) !== Array.isArray(S) || a(c) != null && a(c) !== a(S)) continue;
160
+ applyState(S, wrap(c, r), a);
161
+ }
162
+ }
163
+
134
164
  // Dispatcher: every applyState call (including recursion) checks for the
135
165
  // presence of override / optimistic-override slots once and routes to the
136
166
  // appropriate body. The fast body never calls `getOverrideValue` and never
@@ -161,7 +191,7 @@ function applyStateFast(e, t, r) {
161
191
  let i = false;
162
192
  const o = n.length;
163
193
  if (e.length && o && isWrappable(e[0]) && r(e[0]) != null) {
164
- let l, s, p, f, c, u, y, S;
194
+ let l, s, p, f, c, u, S, y;
165
195
  for (p = 0, f = Math.min(o, e.length); p < f && keyedMatch(u = n[p], e[p], r); p++) {
166
196
  isWrappable(u) && isWrappable(e[p]) && applyState(e[p], wrap(u, t), r);
167
197
  }
@@ -184,22 +214,22 @@ function applyStateFast(e, t, r) {
184
214
  o !== e.length && a?.length && setSignal(a.length, e.length);
185
215
  return;
186
216
  }
187
- y = new Array(c + 1);
217
+ S = new Array(c + 1);
188
218
  for (s = c; s >= p; s--) {
189
219
  u = e[s];
190
- S = itemKey(u, r);
191
- l = O.get(S);
192
- y[s] = l === undefined ? -1 : l;
193
- O.set(S, s);
220
+ y = itemKey(u, r);
221
+ l = O.get(y);
222
+ S[s] = l === undefined ? -1 : l;
223
+ O.set(y, s);
194
224
  }
195
225
  for (l = p; l <= f; l++) {
196
226
  u = n[l];
197
- S = itemKey(u, r);
198
- s = O.get(S);
227
+ y = itemKey(u, r);
228
+ s = O.get(y);
199
229
  if (s !== undefined && s !== -1) {
200
230
  E[s] = u;
201
- s = y[s];
202
- O.set(S, s);
231
+ s = S[s];
232
+ O.set(y, s);
203
233
  }
204
234
  }
205
235
  for (s = p; s < e.length; s++) {
@@ -227,21 +257,23 @@ function applyStateFast(e, t, r) {
227
257
  }
228
258
  // values
229
259
  let i = t[STORE_NODE];
260
+ let o;
230
261
  if (i) {
231
- const a = i[$TRACK];
232
- const o = a ? getAllKeys(n, undefined, e) : nodeKeys(i);
233
- for (let l = 0, s = o.length; l < s; l++) {
234
- const s = o[l];
262
+ o = i[$TRACK];
263
+ const a = o ? getAllKeys(n, undefined, e) : nodeKeys(i);
264
+ for (let l = 0, s = a.length; l < s; l++) {
265
+ const s = a[l];
235
266
  const p = i[s];
236
267
  const f = unwrap(n[s]);
237
268
  let c = unwrap(e[s]);
238
269
  if (f === c) continue;
239
270
  if (!f || !isWrappable(f) || !isWrappable(c) || Array.isArray(f) !== Array.isArray(c) || r(f) != null && r(f) !== r(c)) {
240
- a && setSignal(a, void 0);
271
+ o && setSignal(o, void 0);
241
272
  p && setSignal(p, isWrappable(c) ? wrap(c, t) : c);
242
273
  } else applyState(c, wrap(f, t), r);
243
274
  }
244
275
  }
276
+ if (!o && t[STORE_DESC]) applyDescendants(n, e, t, i, r);
245
277
  // has
246
278
  if (i = t[STORE_HAS]) {
247
279
  const t = nodeKeys(i);
@@ -266,23 +298,23 @@ function applyStateSlow(e, t, r) {
266
298
  let l = false;
267
299
  const s = getOverrideValue(n, a, "length", i);
268
300
  if (e.length && s && isWrappable(e[0]) && r(e[0]) != null) {
269
- let p, f, c, u, y, S, E, O;
270
- for (c = 0, u = Math.min(s, e.length); c < u && keyedMatch(S = getOverrideValue(n, a, c, i), e[c], r); c++) {
271
- isWrappable(S) && isWrappable(e[c]) && applyState(e[c], wrap(S, t), r);
301
+ let p, f, c, u, S, y, E, O;
302
+ for (c = 0, u = Math.min(s, e.length); c < u && keyedMatch(y = getOverrideValue(n, a, c, i), e[c], r); c++) {
303
+ isWrappable(y) && isWrappable(e[c]) && applyState(e[c], wrap(y, t), r);
272
304
  }
273
- const d = new Array(e.length), R = new Map;
274
- for (u = s - 1, y = e.length - 1; u >= c && y >= c && keyedMatch(S = getOverrideValue(n, a, u, i), e[y], r); u--,
275
- y--) {
276
- d[y] = S;
305
+ const R = new Array(e.length), d = new Map;
306
+ for (u = s - 1, S = e.length - 1; u >= c && S >= c && keyedMatch(y = getOverrideValue(n, a, u, i), e[S], r); u--,
307
+ S--) {
308
+ R[S] = y;
277
309
  }
278
- if (c > y || c > u) {
279
- for (f = c; f <= y; f++) {
310
+ if (c > S || c > u) {
311
+ for (f = c; f <= S; f++) {
280
312
  l = true;
281
313
  o?.[f] && setSignal(o[f], wrapValue(e[f], t));
282
314
  }
283
315
  for (;f < e.length; f++) {
284
316
  l = true;
285
- applyArrayItem(e[f], d[f], t, o?.[f], r);
317
+ applyArrayItem(e[f], R[f], t, o?.[f], r);
286
318
  }
287
319
  const n = e.length;
288
320
  syncArrayNodeMembership(t, e);
@@ -290,27 +322,27 @@ function applyStateSlow(e, t, r) {
290
322
  s !== n && o?.length && setSignal(o.length, n);
291
323
  return;
292
324
  }
293
- E = new Array(y + 1);
294
- for (f = y; f >= c; f--) {
295
- S = e[f];
296
- O = itemKey(S, r);
297
- p = R.get(O);
325
+ E = new Array(S + 1);
326
+ for (f = S; f >= c; f--) {
327
+ y = e[f];
328
+ O = itemKey(y, r);
329
+ p = d.get(O);
298
330
  E[f] = p === undefined ? -1 : p;
299
- R.set(O, f);
331
+ d.set(O, f);
300
332
  }
301
333
  for (p = c; p <= u; p++) {
302
- S = getOverrideValue(n, a, p, i);
303
- O = itemKey(S, r);
304
- f = R.get(O);
334
+ y = getOverrideValue(n, a, p, i);
335
+ O = itemKey(y, r);
336
+ f = d.get(O);
305
337
  if (f !== undefined && f !== -1) {
306
- d[f] = S;
338
+ R[f] = y;
307
339
  f = E[f];
308
- R.set(O, f);
340
+ d.set(O, f);
309
341
  }
310
342
  }
311
343
  for (f = c; f < e.length; f++) {
312
- if (f in d) {
313
- applyArrayItem(e[f], d[f], t, o?.[f], r);
344
+ if (f in R) {
345
+ applyArrayItem(e[f], R[f], t, o?.[f], r);
314
346
  } else o?.[f] && setSignal(o[f], wrapValue(e[f], t));
315
347
  }
316
348
  if (c < e.length) l = true;
@@ -333,21 +365,23 @@ function applyStateSlow(e, t, r) {
333
365
  return;
334
366
  }
335
367
  // values
336
- if (o) {
337
- const l = o[$TRACK];
368
+ let l;
369
+ if (o) {
370
+ l = o[$TRACK];
338
371
  const s = l ? getAllKeys(n, a, e) : nodeKeys(o);
339
372
  for (let p = 0, f = s.length; p < f; p++) {
340
373
  const f = s[p];
341
374
  const c = o[f];
342
375
  const u = unwrap(getOverrideValue(n, a, f, i));
343
- let y = unwrap(e[f]);
344
- if (u === y) continue;
345
- if (!u || !isWrappable(u) || !isWrappable(y) || Array.isArray(u) !== Array.isArray(y) || r(u) != null && r(u) !== r(y)) {
376
+ let S = unwrap(e[f]);
377
+ if (u === S) continue;
378
+ if (!u || !isWrappable(u) || !isWrappable(S) || Array.isArray(u) !== Array.isArray(S) || r(u) != null && r(u) !== r(S)) {
346
379
  l && setSignal(l, void 0);
347
- c && setSignal(c, isWrappable(y) ? wrap(y, t) : y);
348
- } else applyState(y, wrap(u, t), r);
380
+ c && setSignal(c, isWrappable(S) ? wrap(S, t) : S);
381
+ } else applyState(S, wrap(u, t), r);
349
382
  }
350
383
  }
384
+ if (!l && t[STORE_DESC]) applyDescendants(n, e, t, o, r, a, i);
351
385
  // has
352
386
  if (o = t[STORE_HAS]) {
353
387
  const t = nodeKeys(o);