@solidjs/signals 2.0.0-beta.18 → 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 (68) hide show
  1. package/dist/dev.js +3276 -928
  2. package/dist/node.cjs +6646 -4189
  3. package/dist/prod/affects.js +218 -0
  4. package/dist/prod/boundaries.js +568 -0
  5. package/dist/prod/core/action.js +96 -0
  6. package/dist/prod/core/async.js +380 -0
  7. package/dist/prod/core/constants.js +92 -0
  8. package/dist/prod/core/context.js +67 -0
  9. package/dist/prod/core/core.js +772 -0
  10. package/dist/prod/core/dev.js +3 -0
  11. package/dist/prod/core/effect.js +145 -0
  12. package/dist/prod/core/error.js +59 -0
  13. package/dist/prod/core/external.js +98 -0
  14. package/dist/prod/core/graph.js +91 -0
  15. package/dist/prod/core/heap.js +132 -0
  16. package/dist/prod/core/invariants.js +42 -0
  17. package/dist/prod/core/lanes.js +140 -0
  18. package/dist/prod/core/optimistic.js +273 -0
  19. package/dist/prod/core/owner.js +293 -0
  20. package/dist/prod/core/scheduler.js +689 -0
  21. package/dist/prod/core/verdict.js +292 -0
  22. package/dist/prod/index.js +45 -0
  23. package/dist/prod/map.js +293 -0
  24. package/dist/prod/signals.js +389 -0
  25. package/dist/prod/store/optimistic.js +184 -0
  26. package/dist/prod/store/projection.js +184 -0
  27. package/dist/prod/store/reconcile.js +426 -0
  28. package/dist/prod/store/store.js +870 -0
  29. package/dist/prod/store/storePath.js +103 -0
  30. package/dist/prod/store/utils.js +316 -0
  31. package/dist/types/affects.d.ts +1 -1
  32. package/dist/types/boundaries.d.ts +6 -6
  33. package/dist/types/core/action.d.ts +19 -6
  34. package/dist/types/core/async.d.ts +4 -38
  35. package/dist/types/core/constants.d.ts +12 -0
  36. package/dist/types/core/core.d.ts +12 -78
  37. package/dist/types/core/dev.d.ts +7 -0
  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/lanes.d.ts +2 -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 +40 -39
  45. package/dist/types/core/types.d.ts +9 -1
  46. package/dist/types/core/verdict.d.ts +2 -0
  47. package/dist/types/store/projection.d.ts +0 -1
  48. package/dist/types/store/store.d.ts +8 -2
  49. package/dist/types-cjs/affects.d.cts +1 -1
  50. package/dist/types-cjs/boundaries.d.cts +6 -6
  51. package/dist/types-cjs/core/action.d.cts +19 -6
  52. package/dist/types-cjs/core/async.d.cts +4 -38
  53. package/dist/types-cjs/core/constants.d.cts +12 -0
  54. package/dist/types-cjs/core/core.d.cts +12 -78
  55. package/dist/types-cjs/core/dev.d.cts +7 -0
  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/lanes.d.cts +2 -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 +40 -39
  63. package/dist/types-cjs/core/types.d.cts +9 -1
  64. package/dist/types-cjs/core/verdict.d.cts +2 -0
  65. package/dist/types-cjs/store/projection.d.cts +0 -1
  66. package/dist/types-cjs/store/store.d.cts +8 -2
  67. package/package.json +8 -6
  68. package/dist/prod.js +0 -4637
@@ -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,426 @@
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_DESC, STORE_HAS, getKeys, $DELETED, symbolKeyedRecords, getStoreSymbols } 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
+ // Symbols are merged explicitly below; keep the common string-key path on
49
+ // Object.keys() and avoid reflecting the base symbols twice.
50
+ const n = getKeys(e, t);
51
+ const a = Object.keys(r);
52
+ // `value` can be a wrapped store (store-in-store) whose ownKeys trap tracks;
53
+ // mirror `getKeys` and enumerate its symbols untracked in that case.
54
+ const i = e[$TARGET] ? untrack(() => Object.getOwnPropertySymbols(e)) : Object.getOwnPropertySymbols(e);
55
+ const o = Object.getOwnPropertySymbols(r);
56
+ // Symbol-free diff (the overwhelmingly common case) stays on the exact
57
+ // pre-#2851 path, including the identical-key-sets fast path from #2756.
58
+ if (i.length === 0 && o.length === 0) {
59
+ if (n.length === a.length) {
60
+ let e = true;
61
+ for (let t = 0; t < n.length; t++) {
62
+ if (n[t] !== a[t]) {
63
+ e = false;
64
+ break;
65
+ }
66
+ }
67
+ if (e) return n;
68
+ }
69
+ const e = new Set(n);
70
+ for (let t = 0; t < a.length; t++) e.add(a[t]);
71
+ return Array.from(e);
72
+ }
73
+ // Symbol-aware diff (#2851): base symbols join the set, then override
74
+ // adds/deletes are re-applied so a `$DELETED` symbol stays deleted, then
75
+ // `next`'s keys (a key present in next is never deleted by the diff).
76
+ const l = new Set(n);
77
+ addEnumSymbols(e, i, l);
78
+ if (t) {
79
+ for (const e of Reflect.ownKeys(t)) {
80
+ t[e] === $DELETED ? l.delete(e) : l.add(e);
81
+ }
82
+ }
83
+ for (let e = 0; e < a.length; e++) l.add(a[e]);
84
+ addEnumSymbols(r, o, l);
85
+ return Array.from(l);
86
+ }
87
+
88
+ // Array entries can be `null`/`undefined`/primitives, not just keyed objects.
89
+ // These helpers keep the keyed paths from passing a non-object to `keyFn` (which
90
+ // assumes an object) or to `wrap()` (which assumes a wrappable value).
91
+ function wrapValue(e, t) {
92
+ return isWrappable(e) ? wrap(e, t) : e;
93
+ }
94
+
95
+ function itemKey(e, t) {
96
+ return isWrappable(e) ? t(e) : e;
97
+ }
98
+
99
+ function keyedMatch(e, t, r) {
100
+ return e === t || isWrappable(e) && isWrappable(t) && r(e) === r(t);
101
+ }
102
+
103
+ // Array reconciliation updates the slots it visits, then swaps STORE_VALUE.
104
+ // Previously tracked keys that are absent from `next` still need invalidating,
105
+ // and `in` dependencies should follow the new value's membership. Use
106
+ // membership rather than length arithmetic so sparse arrays and named array
107
+ // props behave like normal property reads.
108
+ function syncArrayNodeMembership(e, t) {
109
+ let r = e[STORE_NODE];
110
+ if (r) {
111
+ const e = nodeKeys(r);
112
+ for (let n = 0, a = e.length; n < a; n++) {
113
+ const a = e[n];
114
+ a in t || setSignal(r[a], undefined);
115
+ }
116
+ }
117
+ if (r = e[STORE_HAS]) {
118
+ const e = nodeKeys(r);
119
+ for (let n = 0, a = e.length; n < a; n++) {
120
+ const a = e[n];
121
+ setSignal(r[a], a in t);
122
+ }
123
+ }
124
+ }
125
+
126
+ // Reconcile a single array slot: recurse into a wrappable pair, otherwise replace
127
+ // the node's value outright (covers object→primitive and primitive→object).
128
+ function applyArrayItem(e, t, r, n, a) {
129
+ if (isWrappable(e) && isWrappable(t)) {
130
+ const i = wrap(t, r);
131
+ n && setSignal(n, i);
132
+ applyState(e, i, a);
133
+ } else n && setSignal(n, wrapValue(e, r));
134
+ }
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
+
164
+ // Dispatcher: every applyState call (including recursion) checks for the
165
+ // presence of override / optimistic-override slots once and routes to the
166
+ // appropriate body. The fast body never calls `getOverrideValue` and never
167
+ // branches on a `fastPath` boolean, so V8 sees a tighter, more inlinable
168
+ // shape for the overwhelmingly common case of plain stores.
169
+ function applyState(e, t, r) {
170
+ // Array items and root calls can pass a store proxy as `next`; normalize to
171
+ // its raw value or the swap would set a store's STORE_VALUE to its own proxy.
172
+ e = unwrap(e);
173
+ const n = t?.[$TARGET];
174
+ if (!n) return;
175
+ if (n[STORE_OVERRIDE] || n[STORE_OPTIMISTIC_OVERRIDE]) {
176
+ applyStateSlow(e, n, r);
177
+ } else {
178
+ applyStateFast(e, n, r);
179
+ }
180
+ }
181
+
182
+ function applyStateFast(e, t, r) {
183
+ const n = t[STORE_VALUE];
184
+ if (e === n) return;
185
+ const a = t[STORE_NODE];
186
+ // swap
187
+ (t[STORE_LOOKUP] || storeLookup).set(e, t[$PROXY]);
188
+ t[STORE_VALUE] = e;
189
+ // merge
190
+ if (Array.isArray(n)) {
191
+ let i = false;
192
+ const o = n.length;
193
+ if (e.length && o && isWrappable(e[0]) && r(e[0]) != null) {
194
+ let l, s, p, f, c, u, S, y;
195
+ for (p = 0, f = Math.min(o, e.length); p < f && keyedMatch(u = n[p], e[p], r); p++) {
196
+ isWrappable(u) && isWrappable(e[p]) && applyState(e[p], wrap(u, t), r);
197
+ }
198
+ const E = new Array(e.length), O = new Map;
199
+ for (f = o - 1, c = e.length - 1; f >= p && c >= p && keyedMatch(u = n[f], e[c], r); f--,
200
+ c--) {
201
+ E[c] = u;
202
+ }
203
+ if (p > c || p > f) {
204
+ for (s = p; s <= c; s++) {
205
+ i = true;
206
+ a?.[s] && setSignal(a[s], wrapValue(e[s], t));
207
+ }
208
+ for (;s < e.length; s++) {
209
+ i = true;
210
+ applyArrayItem(e[s], E[s], t, a?.[s], r);
211
+ }
212
+ syncArrayNodeMembership(t, e);
213
+ (i || o !== e.length) && notifySelf(t);
214
+ o !== e.length && a?.length && setSignal(a.length, e.length);
215
+ return;
216
+ }
217
+ S = new Array(c + 1);
218
+ for (s = c; s >= p; s--) {
219
+ u = e[s];
220
+ y = itemKey(u, r);
221
+ l = O.get(y);
222
+ S[s] = l === undefined ? -1 : l;
223
+ O.set(y, s);
224
+ }
225
+ for (l = p; l <= f; l++) {
226
+ u = n[l];
227
+ y = itemKey(u, r);
228
+ s = O.get(y);
229
+ if (s !== undefined && s !== -1) {
230
+ E[s] = u;
231
+ s = S[s];
232
+ O.set(y, s);
233
+ }
234
+ }
235
+ for (s = p; s < e.length; s++) {
236
+ if (s in E) {
237
+ applyArrayItem(e[s], E[s], t, a?.[s], r);
238
+ } else a?.[s] && setSignal(a[s], wrapValue(e[s], t));
239
+ }
240
+ if (p < e.length) i = true;
241
+ } else if (e.length) {
242
+ for (let o = 0, l = e.length; o < l; o++) {
243
+ const l = n[o];
244
+ if (isWrappable(l) && isWrappable(e[o])) applyState(e[o], wrap(l, t), r); else {
245
+ if (l !== e[o]) i = true;
246
+ a?.[o] && setSignal(a[o], wrapValue(e[o], t));
247
+ }
248
+ }
249
+ }
250
+ syncArrayNodeMembership(t, e);
251
+ if (o !== e.length) {
252
+ i = true;
253
+ a?.length && setSignal(a.length, e.length);
254
+ }
255
+ i && notifySelf(t);
256
+ return;
257
+ }
258
+ // values
259
+ let i = t[STORE_NODE];
260
+ let o;
261
+ if (i) {
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];
266
+ const p = i[s];
267
+ const f = unwrap(n[s]);
268
+ let c = unwrap(e[s]);
269
+ if (f === c) continue;
270
+ if (!f || !isWrappable(f) || !isWrappable(c) || Array.isArray(f) !== Array.isArray(c) || r(f) != null && r(f) !== r(c)) {
271
+ o && setSignal(o, void 0);
272
+ p && setSignal(p, isWrappable(c) ? wrap(c, t) : c);
273
+ } else applyState(c, wrap(f, t), r);
274
+ }
275
+ }
276
+ if (!o && t[STORE_DESC]) applyDescendants(n, e, t, i, r);
277
+ // has
278
+ if (i = t[STORE_HAS]) {
279
+ const t = nodeKeys(i);
280
+ for (let r = 0, n = t.length; r < n; r++) {
281
+ const n = t[r];
282
+ setSignal(i[n], n in e);
283
+ }
284
+ }
285
+ }
286
+
287
+ function applyStateSlow(e, t, r) {
288
+ const n = t[STORE_VALUE];
289
+ const a = t[STORE_OVERRIDE];
290
+ const i = t[STORE_OPTIMISTIC_OVERRIDE];
291
+ let o = t[STORE_NODE];
292
+ // swap
293
+ (t[STORE_LOOKUP] || storeLookup).set(e, t[$PROXY]);
294
+ t[STORE_VALUE] = e;
295
+ t[STORE_OVERRIDE] = undefined;
296
+ // merge
297
+ if (Array.isArray(n)) {
298
+ let l = false;
299
+ const s = getOverrideValue(n, a, "length", i);
300
+ if (e.length && s && isWrappable(e[0]) && r(e[0]) != null) {
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);
304
+ }
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;
309
+ }
310
+ if (c > S || c > u) {
311
+ for (f = c; f <= S; f++) {
312
+ l = true;
313
+ o?.[f] && setSignal(o[f], wrapValue(e[f], t));
314
+ }
315
+ for (;f < e.length; f++) {
316
+ l = true;
317
+ applyArrayItem(e[f], R[f], t, o?.[f], r);
318
+ }
319
+ const n = e.length;
320
+ syncArrayNodeMembership(t, e);
321
+ (l || s !== n) && notifySelf(t);
322
+ s !== n && o?.length && setSignal(o.length, n);
323
+ return;
324
+ }
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);
330
+ E[f] = p === undefined ? -1 : p;
331
+ d.set(O, f);
332
+ }
333
+ for (p = c; p <= u; p++) {
334
+ y = getOverrideValue(n, a, p, i);
335
+ O = itemKey(y, r);
336
+ f = d.get(O);
337
+ if (f !== undefined && f !== -1) {
338
+ R[f] = y;
339
+ f = E[f];
340
+ d.set(O, f);
341
+ }
342
+ }
343
+ for (f = c; f < e.length; f++) {
344
+ if (f in R) {
345
+ applyArrayItem(e[f], R[f], t, o?.[f], r);
346
+ } else o?.[f] && setSignal(o[f], wrapValue(e[f], t));
347
+ }
348
+ if (c < e.length) l = true;
349
+ } else if (e.length) {
350
+ for (let s = 0, p = e.length; s < p; s++) {
351
+ const p = getOverrideValue(n, a, s, i);
352
+ if (isWrappable(p) && isWrappable(e[s])) applyState(e[s], wrap(p, t), r); else {
353
+ if (p !== e[s]) l = true;
354
+ o?.[s] && setSignal(o[s], wrapValue(e[s], t));
355
+ }
356
+ }
357
+ }
358
+ const p = e.length;
359
+ syncArrayNodeMembership(t, e);
360
+ if (s !== p) {
361
+ l = true;
362
+ o?.length && setSignal(o.length, p);
363
+ }
364
+ l && notifySelf(t);
365
+ return;
366
+ }
367
+ // values
368
+ let l;
369
+ if (o) {
370
+ l = o[$TRACK];
371
+ const s = l ? getAllKeys(n, a, e) : nodeKeys(o);
372
+ for (let p = 0, f = s.length; p < f; p++) {
373
+ const f = s[p];
374
+ const c = o[f];
375
+ const u = unwrap(getOverrideValue(n, a, f, i));
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)) {
379
+ l && setSignal(l, void 0);
380
+ c && setSignal(c, isWrappable(S) ? wrap(S, t) : S);
381
+ } else applyState(S, wrap(u, t), r);
382
+ }
383
+ }
384
+ if (!l && t[STORE_DESC]) applyDescendants(n, e, t, o, r, a, i);
385
+ // has
386
+ if (o = t[STORE_HAS]) {
387
+ const t = nodeKeys(o);
388
+ for (let r = 0, n = t.length; r < n; r++) {
389
+ const n = t[r];
390
+ setSignal(o[n], n in e);
391
+ }
392
+ }
393
+ }
394
+
395
+ /**
396
+ * Returns a draft-mutating function that smart-merges `value` into a store,
397
+ * preserving the identity of items whose `key` field matches between old and
398
+ * new states. Useful when applying server payloads or full-replacement data
399
+ * onto an existing store without losing fine-grained reactivity.
400
+ *
401
+ * Items with the same key are updated in place (only changed properties
402
+ * trigger updates). Items added or removed update the corresponding signals.
403
+ *
404
+ * @param value the next state to merge in
405
+ * @param key property name (string) or extractor function for stable identity
406
+ *
407
+ * @example
408
+ * ```ts
409
+ * const [todos, setTodos] = createStore<Todo[]>([]);
410
+ *
411
+ * async function refresh() {
412
+ * const fresh = await api.getTodos();
413
+ * setTodos(reconcile(fresh, "id")); // diff-merge by `id`
414
+ * }
415
+ * ```
416
+ */ function reconcile(e, t) {
417
+ return r => {
418
+ if (r == null) throw new Error("");
419
+ const n = typeof t === "string" ? e => e[t] : t;
420
+ const a = n(r);
421
+ if (a !== undefined && n(e) !== a) throw new Error("");
422
+ applyState(e, r, n);
423
+ };
424
+ }
425
+
426
+ export { reconcile };