@solidjs/signals 2.0.0-beta.17 → 2.0.0-beta.19

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 (69) hide show
  1. package/README.md +4 -3
  2. package/dist/dev.js +2956 -646
  3. package/dist/node.cjs +6396 -3974
  4. package/dist/prod/affects.js +222 -0
  5. package/dist/prod/boundaries.js +568 -0
  6. package/dist/prod/core/action.js +83 -0
  7. package/dist/prod/core/async.js +394 -0
  8. package/dist/prod/core/constants.js +78 -0
  9. package/dist/prod/core/context.js +67 -0
  10. package/dist/prod/core/core.js +772 -0
  11. package/dist/prod/core/dev.js +3 -0
  12. package/dist/prod/core/effect.js +145 -0
  13. package/dist/prod/core/error.js +59 -0
  14. package/dist/prod/core/external.js +98 -0
  15. package/dist/prod/core/graph.js +91 -0
  16. package/dist/prod/core/heap.js +132 -0
  17. package/dist/prod/core/invariants.js +42 -0
  18. package/dist/prod/core/lanes.js +130 -0
  19. package/dist/prod/core/optimistic.js +265 -0
  20. package/dist/prod/core/owner.js +293 -0
  21. package/dist/prod/core/scheduler.js +689 -0
  22. package/dist/prod/core/verdict.js +293 -0
  23. package/dist/prod/index.js +45 -0
  24. package/dist/prod/map.js +264 -0
  25. package/dist/prod/signals.js +389 -0
  26. package/dist/prod/store/optimistic.js +149 -0
  27. package/dist/prod/store/projection.js +184 -0
  28. package/dist/prod/store/reconcile.js +392 -0
  29. package/dist/prod/store/store.js +739 -0
  30. package/dist/prod/store/storePath.js +103 -0
  31. package/dist/prod/store/utils.js +297 -0
  32. package/dist/types/affects.d.ts +47 -0
  33. package/dist/types/boundaries.d.ts +8 -8
  34. package/dist/types/core/async.d.ts +5 -2
  35. package/dist/types/core/constants.d.ts +8 -0
  36. package/dist/types/core/core.d.ts +12 -69
  37. package/dist/types/core/dev.d.ts +1 -1
  38. package/dist/types/core/external.d.ts +0 -30
  39. package/dist/types/core/heap.d.ts +8 -0
  40. package/dist/types/core/index.d.ts +3 -2
  41. package/dist/types/core/invariants.d.ts +10 -0
  42. package/dist/types/core/optimistic.d.ts +6 -0
  43. package/dist/types/core/owner.d.ts +8 -0
  44. package/dist/types/core/scheduler.d.ts +53 -5
  45. package/dist/types/core/types.d.ts +22 -5
  46. package/dist/types/core/verdict.d.ts +2 -0
  47. package/dist/types/index.d.ts +1 -0
  48. package/dist/types/store/projection.d.ts +0 -1
  49. package/dist/types/store/store.d.ts +32 -14
  50. package/dist/types-cjs/affects.d.cts +47 -0
  51. package/dist/types-cjs/boundaries.d.cts +8 -8
  52. package/dist/types-cjs/core/async.d.cts +5 -2
  53. package/dist/types-cjs/core/constants.d.cts +8 -0
  54. package/dist/types-cjs/core/core.d.cts +12 -69
  55. package/dist/types-cjs/core/dev.d.cts +1 -1
  56. package/dist/types-cjs/core/external.d.cts +0 -30
  57. package/dist/types-cjs/core/heap.d.cts +8 -0
  58. package/dist/types-cjs/core/index.d.cts +3 -2
  59. package/dist/types-cjs/core/invariants.d.cts +10 -0
  60. package/dist/types-cjs/core/optimistic.d.cts +6 -0
  61. package/dist/types-cjs/core/owner.d.cts +8 -0
  62. package/dist/types-cjs/core/scheduler.d.cts +53 -5
  63. package/dist/types-cjs/core/types.d.cts +22 -5
  64. package/dist/types-cjs/core/verdict.d.cts +2 -0
  65. package/dist/types-cjs/index.d.cts +1 -0
  66. package/dist/types-cjs/store/projection.d.cts +0 -1
  67. package/dist/types-cjs/store/store.d.cts +32 -14
  68. package/package.json +8 -6
  69. package/dist/prod.js +0 -4406
@@ -0,0 +1,184 @@
1
+ import { computed } from "../core/core.js";
2
+
3
+ import { getOwner } from "../core/owner.js";
4
+
5
+ import { setProjectionWriteActive } from "../core/scheduler.js";
6
+
7
+ import { handleAsync } from "../core/async.js";
8
+
9
+ import "../core/verdict.js";
10
+
11
+ import "../core/effect.js";
12
+
13
+ import { CONFIG_AUTO_DISPOSE } from "../core/constants.js";
14
+
15
+ import { reconcile } from "./reconcile.js";
16
+
17
+ import { storeSetter, $TARGET, STORE_WRAP, createStoreProxy, storeTraps, setWriteOverride, STORE_LOOKUP, STORE_FIREWALL } from "./store.js";
18
+
19
+ function createProjectionInternal(e, r, t) {
20
+ let o;
21
+ const i = new WeakMap;
22
+ const wrapper = e => {
23
+ e[STORE_WRAP] = wrapProjection;
24
+ e[STORE_LOOKUP] = i;
25
+ Object.defineProperty(e, STORE_FIREWALL, {
26
+ get() {
27
+ return o;
28
+ },
29
+ configurable: true
30
+ });
31
+ };
32
+ const wrapProjection = e => {
33
+ if (i.has(e)) return i.get(e);
34
+ if (e[$TARGET]?.[STORE_WRAP] === wrapProjection) return e;
35
+ const r = createStoreProxy(e, storeTraps, wrapper);
36
+ i.set(e, r);
37
+ return r;
38
+ };
39
+ const n = wrapProjection(r);
40
+ o = computed(() => {
41
+ if (!o) o = getOwner();
42
+ runProjectionComputed(n, e, t?.key || "id");
43
+ }, undefined);
44
+ o.U &= ~CONFIG_AUTO_DISPOSE;
45
+ return {
46
+ store: n,
47
+ node: o
48
+ };
49
+ }
50
+
51
+ /**
52
+ * Creates a derived (projected) store. Like `createMemo` but for stores: the
53
+ * derive function receives a mutable draft and either mutates it in place
54
+ * (canonical) or returns a new value. Either way the result is reconciled
55
+ * against the previous draft by `options.key` (default `"id"`), so surviving
56
+ * items keep their proxy identity — only added/removed items are
57
+ * created/disposed.
58
+ *
59
+ * Returns the projected store directly (no setter — reads only).
60
+ *
61
+ * Use this when you want the structural-sharing / per-property tracking
62
+ * behaviour of a store on top of a derived computation. For simple read-only
63
+ * derivations, `createMemo` is lighter.
64
+ *
65
+ * @param fn receives the current draft; mutate it in place or return new
66
+ * data. Return is convenient for filter/derive shapes where mutation is
67
+ * awkward.
68
+ * @param seed the backing store value to wrap and reconcile into
69
+ * @param options `ProjectionOptions` — `name`, `key`. `key` defaults to
70
+ * `"id"`; specify it only when your data uses a different identity field
71
+ * (e.g. `{ key: "uuid" }` or `{ key: u => u.slug }`).
72
+ *
73
+ * @example
74
+ * ```ts
75
+ * // Mutation form — update individual fields on the draft.
76
+ * const summary = createProjection<{ total: number; active: number }>(
77
+ * draft => {
78
+ * draft.total = users().length;
79
+ * draft.active = users().filter(u => u.active).length;
80
+ * },
81
+ * { total: 0, active: 0 }
82
+ * );
83
+ *
84
+ * // Return form — produce a derived collection. Reconciled by `id` so each
85
+ * // surviving user keeps the same store identity across recomputes.
86
+ * const activeUsers = createProjection<User[]>(
87
+ * () => allUsers().filter(u => u.active),
88
+ * []
89
+ * );
90
+ * ```
91
+ *
92
+ * @see {@link https://github.com/solidjs/x-reactivity#createprojection}
93
+ */ function createProjection(e, r, t) {
94
+ return createProjectionInternal(e, r, t).store;
95
+ }
96
+
97
+ /**
98
+ * Shared projection computed body used by both `createProjection` and the derived
99
+ * form of `createOptimisticStore`. Encapsulates the write-trap draft, `storeSetter`
100
+ * wrapping, the `handleAsync` subscription with a setter callback, and the commit
101
+ * path (which must always go through `storeSetter` so the `writeOnly` guard is
102
+ * engaged during `reconcile`'s property reads).
103
+ *
104
+ * `wrapCommit` is invoked for every commit (sync return and each async yield) and
105
+ * lets callers layer extra context around the write — e.g. the optimistic store
106
+ * re-enters `setProjectionWriteActive` so reconciles target `STORE_OVERRIDE`
107
+ * instead of `STORE_OPTIMISTIC_OVERRIDE` even when an async yield fires outside
108
+ * the outer `setProjectionWriteActive` scope.
109
+ */ function runProjectionComputed(e, r, t, o, i) {
110
+ const n = getOwner();
111
+ let c = false;
112
+ let s;
113
+ const u = new Proxy(e, createWriteTraps(() => !c || n.Ae === s, i));
114
+ storeSetter(u, i => {
115
+ s = r(i);
116
+ c = true;
117
+ const commit = r => {
118
+ if (r === i || r === undefined) return;
119
+ const write = () => storeSetter(e, reconcile(r, t));
120
+ o ? o(write) : write();
121
+ };
122
+ commit(handleAsync(n, s, commit));
123
+ });
124
+ return n;
125
+ }
126
+
127
+ function createWriteTraps(e, r) {
128
+ const t = {
129
+ get(e, r) {
130
+ let o;
131
+ setWriteOverride(true);
132
+ setProjectionWriteActive(true);
133
+ try {
134
+ o = e[r];
135
+ } finally {
136
+ setWriteOverride(false);
137
+ setProjectionWriteActive(false);
138
+ }
139
+ if (r === $TARGET) return o;
140
+ return typeof o === "object" && o !== null ? new Proxy(o, t) : o;
141
+ },
142
+ has(e, r) {
143
+ let t;
144
+ setWriteOverride(true);
145
+ setProjectionWriteActive(true);
146
+ try {
147
+ t = r in e;
148
+ } finally {
149
+ setWriteOverride(false);
150
+ setProjectionWriteActive(false);
151
+ }
152
+ return t;
153
+ },
154
+ set(t, o, i) {
155
+ if (e && !e()) return true;
156
+ setWriteOverride(true);
157
+ setProjectionWriteActive(true);
158
+ try {
159
+ t[o] = i;
160
+ r?.();
161
+ } finally {
162
+ setWriteOverride(false);
163
+ setProjectionWriteActive(false);
164
+ }
165
+ return true;
166
+ },
167
+ deleteProperty(t, o) {
168
+ if (e && !e()) return true;
169
+ setWriteOverride(true);
170
+ setProjectionWriteActive(true);
171
+ try {
172
+ delete t[o];
173
+ r?.();
174
+ } finally {
175
+ setWriteOverride(false);
176
+ setProjectionWriteActive(false);
177
+ }
178
+ return true;
179
+ }
180
+ };
181
+ return t;
182
+ }
183
+
184
+ export { createProjection, createProjectionInternal, createWriteTraps, runProjectionComputed };
@@ -0,0 +1,392 @@
1
+ import { setSignal, untrack } from "../core/core.js";
2
+
3
+ import "../core/scheduler.js";
4
+
5
+ import "../core/invariants.js";
6
+
7
+ import "../core/verdict.js";
8
+
9
+ import "../core/effect.js";
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";
12
+
13
+ // Enumerate a node record's keys. Keeps the common string-key path on the
14
+ // `Object.keys` fast path; only records currently holding a user symbol node
15
+ // (marked by `getNode`) pay for symbol enumeration. `$TRACK` is the only
16
+ // internal symbol a node record can hold and callers handle it separately.
17
+ function nodeKeys(e) {
18
+ const t = Object.keys(e);
19
+ if (symbolKeyedRecords.has(e)) {
20
+ const r = Object.getOwnPropertySymbols(e);
21
+ for (let e = 0, n = r.length; e < n; e++) {
22
+ if (r[e] !== $TRACK) t.push(r[e]);
23
+ }
24
+ }
25
+ return t;
26
+ }
27
+
28
+ function unwrap(e) {
29
+ // Primitives can't be store proxies; skip the symbol lookups (which box the
30
+ // primitive) for the common leaf case.
31
+ if (e === null || typeof e !== "object") return e;
32
+ return e[$TARGET]?.[STORE_VALUE] ?? e;
33
+ }
34
+
35
+ function getOverrideValue(e, t, r, n) {
36
+ if (n && r in n) return n[r];
37
+ return t && r in t ? t[r] : e[r];
38
+ }
39
+
40
+ // Append `o`'s *enumerable* own symbol keys from a pre-fetched symbol list.
41
+ function addEnumSymbols(e, t, r) {
42
+ for (let n = 0, a = t.length; n < a; n++) {
43
+ if (Object.prototype.propertyIsEnumerable.call(e, t[n])) r.add(t[n]);
44
+ }
45
+ }
46
+
47
+ function getAllKeys(e, t, r) {
48
+ const n = getKeys(e, t);
49
+ const a = Object.keys(r);
50
+ // `value` can be a wrapped store (store-in-store) whose ownKeys trap tracks;
51
+ // mirror `getKeys` and enumerate its symbols untracked in that case.
52
+ const i = e[$TARGET] ? untrack(() => Object.getOwnPropertySymbols(e)) : Object.getOwnPropertySymbols(e);
53
+ const o = Object.getOwnPropertySymbols(r);
54
+ // Symbol-free diff (the overwhelmingly common case) stays on the exact
55
+ // pre-#2851 path, including the identical-key-sets fast path from #2756.
56
+ if (i.length === 0 && o.length === 0) {
57
+ if (n.length === a.length) {
58
+ let e = true;
59
+ for (let t = 0; t < n.length; t++) {
60
+ if (n[t] !== a[t]) {
61
+ e = false;
62
+ break;
63
+ }
64
+ }
65
+ if (e) return n;
66
+ }
67
+ const e = new Set(n);
68
+ for (let t = 0; t < a.length; t++) e.add(a[t]);
69
+ return Array.from(e);
70
+ }
71
+ // Symbol-aware diff (#2851): base symbols join the set, then override
72
+ // adds/deletes are re-applied so a `$DELETED` symbol stays deleted, then
73
+ // `next`'s keys (a key present in next is never deleted by the diff).
74
+ const l = new Set(n);
75
+ addEnumSymbols(e, i, l);
76
+ if (t) {
77
+ for (const e of Reflect.ownKeys(t)) {
78
+ t[e] === $DELETED ? l.delete(e) : l.add(e);
79
+ }
80
+ }
81
+ for (let e = 0; e < a.length; e++) l.add(a[e]);
82
+ addEnumSymbols(r, o, l);
83
+ return Array.from(l);
84
+ }
85
+
86
+ // Array entries can be `null`/`undefined`/primitives, not just keyed objects.
87
+ // These helpers keep the keyed paths from passing a non-object to `keyFn` (which
88
+ // assumes an object) or to `wrap()` (which assumes a wrappable value).
89
+ function wrapValue(e, t) {
90
+ return isWrappable(e) ? wrap(e, t) : e;
91
+ }
92
+
93
+ function itemKey(e, t) {
94
+ return isWrappable(e) ? t(e) : e;
95
+ }
96
+
97
+ function keyedMatch(e, t, r) {
98
+ return e === t || isWrappable(e) && isWrappable(t) && r(e) === r(t);
99
+ }
100
+
101
+ // Array reconciliation updates the slots it visits, then swaps STORE_VALUE.
102
+ // Previously tracked keys that are absent from `next` still need invalidating,
103
+ // and `in` dependencies should follow the new value's membership. Use
104
+ // membership rather than length arithmetic so sparse arrays and named array
105
+ // props behave like normal property reads.
106
+ function syncArrayNodeMembership(e, t) {
107
+ let r = e[STORE_NODE];
108
+ if (r) {
109
+ const e = nodeKeys(r);
110
+ for (let n = 0, a = e.length; n < a; n++) {
111
+ const a = e[n];
112
+ a in t || setSignal(r[a], undefined);
113
+ }
114
+ }
115
+ if (r = e[STORE_HAS]) {
116
+ const e = nodeKeys(r);
117
+ for (let n = 0, a = e.length; n < a; n++) {
118
+ const a = e[n];
119
+ setSignal(r[a], a in t);
120
+ }
121
+ }
122
+ }
123
+
124
+ // Reconcile a single array slot: recurse into a wrappable pair, otherwise replace
125
+ // the node's value outright (covers object→primitive and primitive→object).
126
+ function applyArrayItem(e, t, r, n, a) {
127
+ if (isWrappable(e) && isWrappable(t)) {
128
+ const i = wrap(t, r);
129
+ n && setSignal(n, i);
130
+ applyState(e, i, a);
131
+ } else n && setSignal(n, wrapValue(e, r));
132
+ }
133
+
134
+ // Dispatcher: every applyState call (including recursion) checks for the
135
+ // presence of override / optimistic-override slots once and routes to the
136
+ // appropriate body. The fast body never calls `getOverrideValue` and never
137
+ // branches on a `fastPath` boolean, so V8 sees a tighter, more inlinable
138
+ // shape for the overwhelmingly common case of plain stores.
139
+ function applyState(e, t, r) {
140
+ // Array items and root calls can pass a store proxy as `next`; normalize to
141
+ // its raw value or the swap would set a store's STORE_VALUE to its own proxy.
142
+ e = unwrap(e);
143
+ const n = t?.[$TARGET];
144
+ if (!n) return;
145
+ if (n[STORE_OVERRIDE] || n[STORE_OPTIMISTIC_OVERRIDE]) {
146
+ applyStateSlow(e, n, r);
147
+ } else {
148
+ applyStateFast(e, n, r);
149
+ }
150
+ }
151
+
152
+ function applyStateFast(e, t, r) {
153
+ const n = t[STORE_VALUE];
154
+ if (e === n) return;
155
+ const a = t[STORE_NODE];
156
+ // swap
157
+ (t[STORE_LOOKUP] || storeLookup).set(e, t[$PROXY]);
158
+ t[STORE_VALUE] = e;
159
+ // merge
160
+ if (Array.isArray(n)) {
161
+ let i = false;
162
+ const o = n.length;
163
+ if (e.length && o && isWrappable(e[0]) && r(e[0]) != null) {
164
+ let l, s, p, f, c, u, y, S;
165
+ for (p = 0, f = Math.min(o, e.length); p < f && keyedMatch(u = n[p], e[p], r); p++) {
166
+ isWrappable(u) && isWrappable(e[p]) && applyState(e[p], wrap(u, t), r);
167
+ }
168
+ const E = new Array(e.length), O = new Map;
169
+ for (f = o - 1, c = e.length - 1; f >= p && c >= p && keyedMatch(u = n[f], e[c], r); f--,
170
+ c--) {
171
+ E[c] = u;
172
+ }
173
+ if (p > c || p > f) {
174
+ for (s = p; s <= c; s++) {
175
+ i = true;
176
+ a?.[s] && setSignal(a[s], wrapValue(e[s], t));
177
+ }
178
+ for (;s < e.length; s++) {
179
+ i = true;
180
+ applyArrayItem(e[s], E[s], t, a?.[s], r);
181
+ }
182
+ syncArrayNodeMembership(t, e);
183
+ (i || o !== e.length) && notifySelf(t);
184
+ o !== e.length && a?.length && setSignal(a.length, e.length);
185
+ return;
186
+ }
187
+ y = new Array(c + 1);
188
+ for (s = c; s >= p; s--) {
189
+ 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);
194
+ }
195
+ for (l = p; l <= f; l++) {
196
+ u = n[l];
197
+ S = itemKey(u, r);
198
+ s = O.get(S);
199
+ if (s !== undefined && s !== -1) {
200
+ E[s] = u;
201
+ s = y[s];
202
+ O.set(S, s);
203
+ }
204
+ }
205
+ for (s = p; s < e.length; s++) {
206
+ if (s in E) {
207
+ applyArrayItem(e[s], E[s], t, a?.[s], r);
208
+ } else a?.[s] && setSignal(a[s], wrapValue(e[s], t));
209
+ }
210
+ if (p < e.length) i = true;
211
+ } else if (e.length) {
212
+ for (let o = 0, l = e.length; o < l; o++) {
213
+ const l = n[o];
214
+ if (isWrappable(l) && isWrappable(e[o])) applyState(e[o], wrap(l, t), r); else {
215
+ if (l !== e[o]) i = true;
216
+ a?.[o] && setSignal(a[o], wrapValue(e[o], t));
217
+ }
218
+ }
219
+ }
220
+ syncArrayNodeMembership(t, e);
221
+ if (o !== e.length) {
222
+ i = true;
223
+ a?.length && setSignal(a.length, e.length);
224
+ }
225
+ i && notifySelf(t);
226
+ return;
227
+ }
228
+ // values
229
+ let i = t[STORE_NODE];
230
+ 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];
235
+ const p = i[s];
236
+ const f = unwrap(n[s]);
237
+ let c = unwrap(e[s]);
238
+ if (f === c) continue;
239
+ 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);
241
+ p && setSignal(p, isWrappable(c) ? wrap(c, t) : c);
242
+ } else applyState(c, wrap(f, t), r);
243
+ }
244
+ }
245
+ // has
246
+ if (i = t[STORE_HAS]) {
247
+ const t = nodeKeys(i);
248
+ for (let r = 0, n = t.length; r < n; r++) {
249
+ const n = t[r];
250
+ setSignal(i[n], n in e);
251
+ }
252
+ }
253
+ }
254
+
255
+ function applyStateSlow(e, t, r) {
256
+ const n = t[STORE_VALUE];
257
+ const a = t[STORE_OVERRIDE];
258
+ const i = t[STORE_OPTIMISTIC_OVERRIDE];
259
+ let o = t[STORE_NODE];
260
+ // swap
261
+ (t[STORE_LOOKUP] || storeLookup).set(e, t[$PROXY]);
262
+ t[STORE_VALUE] = e;
263
+ t[STORE_OVERRIDE] = undefined;
264
+ // merge
265
+ if (Array.isArray(n)) {
266
+ let l = false;
267
+ const s = getOverrideValue(n, a, "length", i);
268
+ 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);
272
+ }
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;
277
+ }
278
+ if (c > y || c > u) {
279
+ for (f = c; f <= y; f++) {
280
+ l = true;
281
+ o?.[f] && setSignal(o[f], wrapValue(e[f], t));
282
+ }
283
+ for (;f < e.length; f++) {
284
+ l = true;
285
+ applyArrayItem(e[f], d[f], t, o?.[f], r);
286
+ }
287
+ const n = e.length;
288
+ syncArrayNodeMembership(t, e);
289
+ (l || s !== n) && notifySelf(t);
290
+ s !== n && o?.length && setSignal(o.length, n);
291
+ return;
292
+ }
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);
298
+ E[f] = p === undefined ? -1 : p;
299
+ R.set(O, f);
300
+ }
301
+ for (p = c; p <= u; p++) {
302
+ S = getOverrideValue(n, a, p, i);
303
+ O = itemKey(S, r);
304
+ f = R.get(O);
305
+ if (f !== undefined && f !== -1) {
306
+ d[f] = S;
307
+ f = E[f];
308
+ R.set(O, f);
309
+ }
310
+ }
311
+ for (f = c; f < e.length; f++) {
312
+ if (f in d) {
313
+ applyArrayItem(e[f], d[f], t, o?.[f], r);
314
+ } else o?.[f] && setSignal(o[f], wrapValue(e[f], t));
315
+ }
316
+ if (c < e.length) l = true;
317
+ } else if (e.length) {
318
+ for (let s = 0, p = e.length; s < p; s++) {
319
+ const p = getOverrideValue(n, a, s, i);
320
+ if (isWrappable(p) && isWrappable(e[s])) applyState(e[s], wrap(p, t), r); else {
321
+ if (p !== e[s]) l = true;
322
+ o?.[s] && setSignal(o[s], wrapValue(e[s], t));
323
+ }
324
+ }
325
+ }
326
+ const p = e.length;
327
+ syncArrayNodeMembership(t, e);
328
+ if (s !== p) {
329
+ l = true;
330
+ o?.length && setSignal(o.length, p);
331
+ }
332
+ l && notifySelf(t);
333
+ return;
334
+ }
335
+ // values
336
+ if (o) {
337
+ const l = o[$TRACK];
338
+ const s = l ? getAllKeys(n, a, e) : nodeKeys(o);
339
+ for (let p = 0, f = s.length; p < f; p++) {
340
+ const f = s[p];
341
+ const c = o[f];
342
+ 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)) {
346
+ l && setSignal(l, void 0);
347
+ c && setSignal(c, isWrappable(y) ? wrap(y, t) : y);
348
+ } else applyState(y, wrap(u, t), r);
349
+ }
350
+ }
351
+ // has
352
+ if (o = t[STORE_HAS]) {
353
+ const t = nodeKeys(o);
354
+ for (let r = 0, n = t.length; r < n; r++) {
355
+ const n = t[r];
356
+ setSignal(o[n], n in e);
357
+ }
358
+ }
359
+ }
360
+
361
+ /**
362
+ * Returns a draft-mutating function that smart-merges `value` into a store,
363
+ * preserving the identity of items whose `key` field matches between old and
364
+ * new states. Useful when applying server payloads or full-replacement data
365
+ * onto an existing store without losing fine-grained reactivity.
366
+ *
367
+ * Items with the same key are updated in place (only changed properties
368
+ * trigger updates). Items added or removed update the corresponding signals.
369
+ *
370
+ * @param value the next state to merge in
371
+ * @param key property name (string) or extractor function for stable identity
372
+ *
373
+ * @example
374
+ * ```ts
375
+ * const [todos, setTodos] = createStore<Todo[]>([]);
376
+ *
377
+ * async function refresh() {
378
+ * const fresh = await api.getTodos();
379
+ * setTodos(reconcile(fresh, "id")); // diff-merge by `id`
380
+ * }
381
+ * ```
382
+ */ function reconcile(e, t) {
383
+ return r => {
384
+ if (r == null) throw new Error("");
385
+ const n = typeof t === "string" ? e => e[t] : t;
386
+ const a = n(r);
387
+ if (a !== undefined && n(e) !== a) throw new Error("");
388
+ applyState(e, r, n);
389
+ };
390
+ }
391
+
392
+ export { reconcile };