@solidjs/signals 2.0.0-beta.18 → 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 (56) hide show
  1. package/dist/dev.js +2743 -694
  2. package/dist/node.cjs +6419 -4234
  3. package/dist/prod/affects.js +222 -0
  4. package/dist/prod/boundaries.js +568 -0
  5. package/dist/prod/core/action.js +83 -0
  6. package/dist/prod/core/async.js +394 -0
  7. package/dist/prod/core/constants.js +78 -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 +130 -0
  18. package/dist/prod/core/optimistic.js +265 -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 +293 -0
  22. package/dist/prod/index.js +45 -0
  23. package/dist/prod/map.js +264 -0
  24. package/dist/prod/signals.js +389 -0
  25. package/dist/prod/store/optimistic.js +149 -0
  26. package/dist/prod/store/projection.js +184 -0
  27. package/dist/prod/store/reconcile.js +392 -0
  28. package/dist/prod/store/store.js +739 -0
  29. package/dist/prod/store/storePath.js +103 -0
  30. package/dist/prod/store/utils.js +297 -0
  31. package/dist/types/affects.d.ts +1 -1
  32. package/dist/types/boundaries.d.ts +6 -6
  33. package/dist/types/core/async.d.ts +4 -38
  34. package/dist/types/core/core.d.ts +12 -78
  35. package/dist/types/core/external.d.ts +0 -30
  36. package/dist/types/core/heap.d.ts +8 -0
  37. package/dist/types/core/index.d.ts +3 -2
  38. package/dist/types/core/optimistic.d.ts +6 -0
  39. package/dist/types/core/owner.d.ts +8 -0
  40. package/dist/types/core/scheduler.d.ts +39 -34
  41. package/dist/types/core/verdict.d.ts +2 -0
  42. package/dist/types/store/projection.d.ts +0 -1
  43. package/dist/types-cjs/affects.d.cts +1 -1
  44. package/dist/types-cjs/boundaries.d.cts +6 -6
  45. package/dist/types-cjs/core/async.d.cts +4 -38
  46. package/dist/types-cjs/core/core.d.cts +12 -78
  47. package/dist/types-cjs/core/external.d.cts +0 -30
  48. package/dist/types-cjs/core/heap.d.cts +8 -0
  49. package/dist/types-cjs/core/index.d.cts +3 -2
  50. package/dist/types-cjs/core/optimistic.d.cts +6 -0
  51. package/dist/types-cjs/core/owner.d.cts +8 -0
  52. package/dist/types-cjs/core/scheduler.d.cts +39 -34
  53. package/dist/types-cjs/core/verdict.d.cts +2 -0
  54. package/dist/types-cjs/store/projection.d.cts +0 -1
  55. package/package.json +8 -6
  56. package/dist/prod.js +0 -4637
@@ -0,0 +1,739 @@
1
+ import { $REFRESH, STORE_SNAPSHOT_PROPS, NOT_PENDING, STATUS_PENDING, NO_SNAPSHOT } from "../core/constants.js";
2
+
3
+ import { suppressComputedRecompute, isEqual, signal, pendingCheckActive, untrack, setSignal, read, snapshotCaptureActive, snapshotSources } from "../core/core.js";
4
+
5
+ import { DEV } from "../core/dev.js";
6
+
7
+ import { getObserver } from "../core/owner.js";
8
+
9
+ import { GlobalQueue, registerTransientStoreNode, projectionWriteActive, globalQueue } from "../core/scheduler.js";
10
+
11
+ import "../core/invariants.js";
12
+
13
+ import "../core/verdict.js";
14
+
15
+ import "../core/effect.js";
16
+
17
+ import { createProjectionInternal } from "./projection.js";
18
+
19
+ /**
20
+ * Brand symbols used internally by the store proxy / projection plumbing.
21
+ * Cross-package wiring; not part of the user-facing API.
22
+ *
23
+ * @internal
24
+ */ const $TRACK = Symbol(0), $TARGET = Symbol(0), $PROXY = Symbol(0), $DELETED = Symbol(0),
25
+ // Node-map slot carrying a record-level `affects()` mark: any read through
26
+ // the record witnesses it into the active isPending() probe.
27
+ $AFFECTS = Symbol(0);
28
+
29
+ const STORE_VALUE = "v", STORE_OVERRIDE = "o", STORE_OPTIMISTIC_OVERRIDE = "x", STORE_NODE = "n", STORE_HAS = "h", STORE_CUSTOM_PROTO = "c", STORE_WRAP = "w", STORE_LOOKUP = "l", STORE_FIREWALL = "f", STORE_OPTIMISTIC = "p";
30
+
31
+ const STORE_SELF_PENDING = Symbol(0);
32
+
33
+ function createStoreProxy(e, t = storeTraps, r) {
34
+ let n;
35
+ if (Array.isArray(e)) {
36
+ n = [];
37
+ n.v = e;
38
+ } else {
39
+ n = {
40
+ v: e
41
+ };
42
+ const t = e?.[$TARGET]?.[STORE_VALUE] ?? e;
43
+ const r = Object.getPrototypeOf(t);
44
+ if (r !== null && r !== Object.prototype) {
45
+ n[STORE_CUSTOM_PROTO] = true;
46
+ }
47
+ }
48
+ r && r(n);
49
+ return n[$PROXY] = new Proxy(n, t);
50
+ }
51
+
52
+ const storeLookup = new WeakMap;
53
+
54
+ // Node records that hold at least one user (non-`$TRACK`) symbol-keyed node.
55
+ // Lets reconcile enumerate symbols only for records that need it (#2851).
56
+ const symbolKeyedRecords = new WeakSet;
57
+
58
+ function wrap(e, t) {
59
+ if (t?.[STORE_WRAP]) return t[STORE_WRAP](e, t);
60
+ let r = e[$PROXY] || storeLookup.get(e);
61
+ if (!r) storeLookup.set(e, r = createStoreProxy(e));
62
+ return r;
63
+ }
64
+
65
+ function isWrappable(e) {
66
+ if (e == null || typeof e !== "object" || Object.isFrozen(e)) return false;
67
+ // Dynamic Node check (kept dynamic so test/SSR overrides of `globalThis.Node`
68
+ // are observed at call time).
69
+ return typeof Node === "undefined" || !(e instanceof Node);
70
+ }
71
+
72
+ let writeOverride = false;
73
+
74
+ function setWriteOverride(e) {
75
+ writeOverride = e;
76
+ }
77
+
78
+ function writeOnly(e) {
79
+ return writeOverride || !!Writing?.has(e);
80
+ }
81
+
82
+ function unwrapStoreValue(e, t, r) {
83
+ const n = e?.[$TARGET] || r?.get(e)?.[$TARGET];
84
+ if (!n) return e;
85
+ const o = n[STORE_OVERRIDE];
86
+ if (!o) return n[STORE_VALUE];
87
+ if (!t) t = new Map;
88
+ if (t.has(e)) return t.get(e);
89
+ const i = n[STORE_VALUE];
90
+ const s = Array.isArray(i);
91
+ const E = s ? [] : Object.create(Object.getPrototypeOf(i));
92
+ t.set(e, E);
93
+ r = n[STORE_LOOKUP] ?? storeLookup;
94
+ for (const e of getKeys(i, o)) {
95
+ if (s && e === "length") continue;
96
+ const n = e in o ? o[e] : i[e];
97
+ if (n !== $DELETED) E[e] = unwrapStoreValue(n, t, r);
98
+ }
99
+ if (s) E.length = o.length ?? i.length;
100
+ return E;
101
+ }
102
+
103
+ function isPrototypePollutionKey(e) {
104
+ return e === "__proto__" || e === "constructor" || e === "prototype";
105
+ }
106
+
107
+ // Own enumerable keys including symbols (`Object.keys` drops symbol-keyed props). #2769
108
+ function ownEnumerableKeys(e) {
109
+ return Reflect.ownKeys(e).filter(t => Object.prototype.propertyIsEnumerable.call(e, t));
110
+ }
111
+
112
+ /**
113
+ * Single chokepoint for the store's layered value resolution: returns the
114
+ * override layer (optimistic first, then regular) that shadows `property`, or
115
+ * `undefined` when the base `STORE_VALUE` is authoritative. Every trap must
116
+ * resolve through this — hand-inlining the layer order is how the optimistic
117
+ * layer gets missed (#2850).
118
+ */ function getOverlayLayer(e, t) {
119
+ const r = e[STORE_OPTIMISTIC_OVERRIDE];
120
+ if (r && t in r) return r;
121
+ const n = e[STORE_OVERRIDE];
122
+ if (n && t in n) return n;
123
+ return undefined;
124
+ }
125
+
126
+ /**
127
+ * The value a store leaf's backing signal currently shows to readers: active
128
+ * override, else held pending value, else committed value.
129
+ */ function visibleNodeValue(e) {
130
+ return e.be !== undefined && e.be !== NOT_PENDING ? e.be : e.ge !== NOT_PENDING ? e.ge : e.Ue;
131
+ }
132
+
133
+ function hasOwnStoreProperty(e, t) {
134
+ // Override layers are null-prototype objects, so `in` is an own check.
135
+ const r = getOverlayLayer(e, t);
136
+ if (r) return r[t] !== $DELETED;
137
+ return Object.prototype.hasOwnProperty.call(unwrapStoreValue(e[STORE_VALUE]), t);
138
+ }
139
+
140
+ function hasInheritedAccessor(e, t) {
141
+ let r = Object.getPrototypeOf(e);
142
+ while (r && r !== Object.prototype) {
143
+ const e = Reflect.getOwnPropertyDescriptor(r, t);
144
+ if (e) return !!e.get;
145
+ r = Object.getPrototypeOf(r);
146
+ }
147
+ return false;
148
+ }
149
+
150
+ function getNodes(e, t) {
151
+ let r = e[t];
152
+ if (!r) e[t] = r = Object.create(null);
153
+ return r;
154
+ }
155
+
156
+ function getNode(e, t, r, n, o = isEqual, i) {
157
+ if (t[r]) return t[r];
158
+ const s = signal(n, {
159
+ equals: o,
160
+ unobserved() {
161
+ if (t[r] === s) {
162
+ delete t[r];
163
+ // Drop the symbol-record mark once the last user symbol node is
164
+ // gone, so reconcile's fast path stops probing a now string-only
165
+ // record. Runs only on symbol-node cleanup (cold), never on reconcile.
166
+ if (typeof r === "symbol" && r !== $TRACK && r !== $AFFECTS && symbolKeyedRecords.has(t)) {
167
+ const e = Object.getOwnPropertySymbols(t);
168
+ let r = false;
169
+ for (let t = 0, n = e.length; t < n; t++) {
170
+ if (e[t] !== $TRACK && e[t] !== $AFFECTS) {
171
+ r = true;
172
+ break;
173
+ }
174
+ }
175
+ if (!r) symbolKeyedRecords.delete(t);
176
+ }
177
+ }
178
+ }
179
+ }, e[STORE_FIREWALL]);
180
+ if (e[STORE_OPTIMISTIC]) {
181
+ s.be = NOT_PENDING;
182
+ }
183
+ if (i && r in i) {
184
+ const e = i[r];
185
+ s.Ye = e === undefined ? NO_SNAPSHOT : e;
186
+ snapshotSources?.add(s);
187
+ }
188
+ if (typeof r === "symbol" && r !== $TRACK && r !== $AFFECTS) symbolKeyedRecords.add(t);
189
+ // A node born inside a live keyless mark's identity scope inherits the mark
190
+ // (the declaration walk could only cover nodes that existed then). The
191
+ // record's own $AFFECTS carrier is the mark's channel, never a member.
192
+ if (r !== $AFFECTS && affectsScopes.size) inheritAffectsMarks(s, e[STORE_VALUE]);
193
+ return t[r] = s;
194
+ }
195
+
196
+ /**
197
+ * Scope inheritance for late-created nodes: every live keyless mark whose
198
+ * identity scope contains the owning record's raw gets counted on the new
199
+ * node. Inherited marks live exactly as long as the scope's carrier — the
200
+ * release hook below drops them with the entry.
201
+ */ function inheritAffectsMarks(e, t) {
202
+ // A live scope exists, so affects.ts already installed the mark engine.
203
+ for (const [r, n] of affectsScopes) {
204
+ if (r.P && n.scope.has(t)) {
205
+ GlobalQueue.D(e);
206
+ n.inherited.push(e);
207
+ }
208
+ }
209
+ }
210
+
211
+ const affectsScopes = new Map;
212
+
213
+ /**
214
+ * Snapshots the identities reachable from `value` into `scope`, reading
215
+ * through write overlays (an optimistic row pushed before the declaration is
216
+ * in motion too). Untracked by construction: walks raw values, never traps.
217
+ * Every LIVE node under each reachable record — property leaves, `$TRACK`,
218
+ * and has-nodes — collects into `found`: those are the graph edges existing
219
+ * readers subscribed through, so the mark registers on them directly and
220
+ * rides the status rails to everything derived. (Nodes born later inherit
221
+ * from the scope in `getNode`.)
222
+ */ function walkAffectsScope(e, t, r, n,
223
+ // Cycle guard, fresh per declaration: the scope itself can't serve — a
224
+ // re-declaration on the same carrier unions into a scope that already
225
+ // holds the root, and must still descend to pick up records added since.
226
+ o) {
227
+ if (!isWrappable(e)) return;
228
+ const i = e[$TARGET] || (n ?? storeLookup).get(e)?.[$TARGET];
229
+ const s = i ? i[STORE_VALUE] : e;
230
+ if (o.has(s)) return;
231
+ o.add(s);
232
+ t.scope.add(s);
233
+ let E;
234
+ if (i) {
235
+ collectRecordNodes(i[STORE_NODE], r);
236
+ collectRecordNodes(i[STORE_HAS], r);
237
+ E = mergedOverlay(i);
238
+ n = i[STORE_LOOKUP] ?? n;
239
+ }
240
+ if (Array.isArray(s)) {
241
+ const e = E?.length ?? s.length;
242
+ for (let i = 0; i < e; i++) {
243
+ const e = E && i in E ? E[i] : s[i];
244
+ if (e !== $DELETED) walkAffectsScope(e, t, r, n, o);
245
+ }
246
+ } else {
247
+ const e = getKeys(s, E);
248
+ for (let i = 0, O = e.length; i < O; i++) {
249
+ const O = getPropertyDescriptor(s, E, e[i]);
250
+ if (!O || O.get) continue;
251
+ walkAffectsScope(O.value, t, r, n, o);
252
+ }
253
+ }
254
+ }
255
+
256
+ /** All live signal nodes of one record's node map (string + symbol keyed). */ function collectRecordNodes(e, t) {
257
+ if (!e) return;
258
+ for (const r of Object.keys(e)) t.push(e[r]);
259
+ const r = Object.getOwnPropertySymbols(e);
260
+ for (let n = 0, o = r.length; n < o; n++) {
261
+ // Another mark's carrier is its own channel — counting it here would
262
+ // extend that sibling scope's lifetime to this declaration's.
263
+ if (r[n] !== $AFFECTS) t.push(e[r[n]]);
264
+ }
265
+ }
266
+
267
+ /**
268
+ * Witness live mark coverage of a record into the active isPending() probe.
269
+ * Tracked reads don't need this — they go through real signal nodes, which
270
+ * carry marks directly (declaration walk or birth inheritance). This covers
271
+ * UNTRACKED probes reading through records whose nodes never materialized
272
+ * (no observer ever subscribed, so no node exists to carry the mark).
273
+ * Callers guard on `pendingCheckActive`, so plain reads never pay for this.
274
+ *
275
+ * @internal
276
+ */ function witnessAffectsMark(e) {
277
+ // Callers guard on `pendingCheckActive`, which only flips inside
278
+ // isPending() — the verdict layer is loaded and its hook installed.
279
+ const t = e[STORE_NODE]?.[$AFFECTS];
280
+ if (t?.P) GlobalQueue.Zt(t);
281
+ if (affectsScopes.size) {
282
+ const r = e[STORE_VALUE];
283
+ for (const [e, n] of affectsScopes) {
284
+ if (e !== t && e.P && n.scope.has(r)) GlobalQueue.Zt(e);
285
+ }
286
+ }
287
+ }
288
+
289
+ /**
290
+ * Resolves the store nodes an `affects()` declaration marks: with a `key`,
291
+ * the named slot's leaf node (upserted so the mark has an addressable
292
+ * carrier); without, the record's $AFFECTS carrier plus every LIVE node in
293
+ * its subtree (the edges existing readers subscribed through), with the
294
+ * subtree's identities snapshotted into the mark's scope so nodes created
295
+ * during the window — and untracked probes over captured proxies — resolve
296
+ * against it (#2882).
297
+ *
298
+ * @internal
299
+ */ function getStoreAffectsNodes(e, t) {
300
+ const r = getNodes(e, STORE_NODE);
301
+ if (t === undefined) {
302
+ const t = getNode(e, r, $AFFECTS, undefined, false);
303
+ GlobalQueue.T ||= e => {
304
+ const t = affectsScopes.get(e);
305
+ if (!t) return;
306
+ affectsScopes.delete(e);
307
+ for (let e = 0; e < t.inherited.length; e++) GlobalQueue.F(t.inherited[e]);
308
+ };
309
+ let n = affectsScopes.get(t);
310
+ if (!n) affectsScopes.set(t, n = {
311
+ scope: new Set,
312
+ inherited: []
313
+ });
314
+ const o = [ t ];
315
+ walkAffectsScope(e[$PROXY], n, o, e[STORE_LOOKUP], new Set);
316
+ return o;
317
+ }
318
+ if (r[t]) return [ r[t] ];
319
+ const n = getOverlayLayer(e, t);
320
+ const o = n ? n[t] : e[STORE_VALUE][t];
321
+ const i = o === $DELETED ? undefined : o;
322
+ return [ upsertStoreNode(e, r, t, i, e[STORE_SNAPSHOT_PROPS]) ];
323
+ }
324
+
325
+ function trackSelf(e, t = $TRACK) {
326
+ if (!getObserver()) return;
327
+ read(getNode(e, getNodes(e, STORE_NODE), t, undefined, false));
328
+ // Store-in-store: structural notifications (reconcile, notifySelf) land on
329
+ // the wrapped source's own self-node, never on this wrapper view's. Chain
330
+ // the read through so enumeration/$TRACK on the wrapper observes them
331
+ // (#2864). Property reads already chain naturally via the inner get trap.
332
+ // An override layer on the view is a hold (A17) — the shown structure is
333
+ // the overlay's, so don't subscribe through it; clearing the layer notifies
334
+ // this view's own self-node and the re-run re-establishes the chain.
335
+ if (t === $TRACK && !e[STORE_OVERRIDE] && !e[STORE_OPTIMISTIC_OVERRIDE] && e[STORE_VALUE][$TARGET]) e[STORE_VALUE][$TRACK];
336
+ }
337
+
338
+ function notifySelf(e) {
339
+ const t = e[STORE_NODE]?.[$TRACK];
340
+ t && setSignal(t, e[STORE_OPTIMISTIC] && !projectionWriteActive ? STORE_SELF_PENDING : undefined);
341
+ }
342
+
343
+ /**
344
+ * The write overlay a walk must read through: optimistic writes shadow
345
+ * regular pending writes, the same resolution order as every proxy trap and
346
+ * `reconcile` (#2850). Merging allocates only in the rare both-present case
347
+ * (a derived optimistic store with an in-flight projection commit).
348
+ */ function mergedOverlay(e) {
349
+ const t = e[STORE_OVERRIDE];
350
+ const r = e[STORE_OPTIMISTIC_OVERRIDE];
351
+ return t && r ? {
352
+ ...t,
353
+ ...r
354
+ } : r ?? t;
355
+ }
356
+
357
+ function getKeys(e, t, r = true) {
358
+ // Plain objects can't trigger proxy traps — only pay for the untrack
359
+ // closure when the source is itself a wrapped store (store-in-store).
360
+ const n = e[$TARGET] ? untrack(() => r ? Object.keys(e) : Reflect.ownKeys(e)) : r ? Object.keys(e) : Reflect.ownKeys(e);
361
+ if (!t) return n;
362
+ const o = new Set(n);
363
+ const i = Reflect.ownKeys(t);
364
+ for (const e of i) {
365
+ if (t[e] !== $DELETED) o.add(e); else o.delete(e);
366
+ }
367
+ return Array.from(o);
368
+ }
369
+
370
+ function getPropertyDescriptor(e, t, r) {
371
+ if (t && r in t) {
372
+ if (t[r] === $DELETED) return void 0;
373
+ const n = Reflect.getOwnPropertyDescriptor(t, r);
374
+ if (n?.get || n?.set) return n;
375
+ // Plain writes live in the override while the source keeps its old value.
376
+ // Preserve the source descriptor flags, but report the current override
377
+ // value. Source accessors cannot be patched with a value, and inherited
378
+ // properties have no source own descriptor, so those keep their descriptor.
379
+ const o = Reflect.getOwnPropertyDescriptor(e, r);
380
+ if (!o) return n;
381
+ if (o.get || o.set) return o;
382
+ // Reflect returns a fresh descriptor, so patching in place is safe and
383
+ // avoids an allocation on Object.keys/spread over written stores.
384
+ o.value = t[r];
385
+ return o;
386
+ }
387
+ return Reflect.getOwnPropertyDescriptor(e, r);
388
+ }
389
+
390
+ function prepareStoreWrite(e, t, r) {
391
+ if (e[STORE_OPTIMISTIC]) {
392
+ const t = e[STORE_FIREWALL];
393
+ if (t?.ve) {
394
+ globalQueue.initTransition(t.ve);
395
+ }
396
+ }
397
+ const n = e[STORE_VALUE];
398
+ const o = n[r];
399
+ if (snapshotCaptureActive && typeof r !== "symbol" && !((e[STORE_FIREWALL]?.i ?? 0) & STATUS_PENDING)) {
400
+ if (!e[STORE_SNAPSHOT_PROPS]) {
401
+ e[STORE_SNAPSHOT_PROPS] = Object.create(null);
402
+ snapshotSources?.add(e);
403
+ }
404
+ if (!(r in e[STORE_SNAPSHOT_PROPS])) {
405
+ e[STORE_SNAPSHOT_PROPS][r] = o;
406
+ }
407
+ }
408
+ const i = e[STORE_OPTIMISTIC] && !projectionWriteActive;
409
+ const s = i ? STORE_OPTIMISTIC_OVERRIDE : STORE_OVERRIDE;
410
+ return {
411
+ base: o,
412
+ overrideKey: s,
413
+ state: n
414
+ };
415
+ }
416
+
417
+ /**
418
+ * Registers the store for transition reversion. Called only once a write is
419
+ * known to be effective — ineffective writes (same value, delete of an absent
420
+ * property) are no-ops and must not entangle the store. Optimistic writes are
421
+ * verdict-inert (question-scoped pending model): no mask is armed — the write
422
+ * neither pends its own slot nor silences anyone else's.
423
+ */ function armOptimisticStoreWrite(e, t) {
424
+ // STORE_OPTIMISTIC is only set by createOptimisticStore, which installs the
425
+ // optimistic engine before wrapping.
426
+ if (e[STORE_OPTIMISTIC] && !projectionWriteActive) {
427
+ GlobalQueue.Vt(t);
428
+ }
429
+ }
430
+
431
+ function upsertStoreNode(e, t, r, n, o) {
432
+ if (t[r]) return t[r];
433
+ const i = isWrappable(n) ? wrap(n, e) : n;
434
+ const s = getNode(e, t, r, i, isEqual, o);
435
+ registerTransientStoreNode(s);
436
+ return s;
437
+ }
438
+
439
+ function notifyStoreProperty(e, t, r, n, o, i) {
440
+ // Cold writes upsert a transient pending node so untracked reads batch like signals.
441
+ // Skip for projection writes (different commit semantics) and for optimistic stores
442
+ // (whose whole purpose is immediate visibility via STORE_OPTIMISTIC_OVERRIDE).
443
+ const s = projectionWriteActive || e[STORE_OPTIMISTIC];
444
+ const E = r !== "delete";
445
+ const O = e[STORE_HAS]?.[t];
446
+ if (O) {
447
+ setSignal(O, E);
448
+ } else if (!s && r !== "invalidate" && i !== E) {
449
+ const r = upsertStoreNode(e, getNodes(e, STORE_HAS), t, i);
450
+ setSignal(r, E);
451
+ }
452
+ const c = getNodes(e, STORE_NODE);
453
+ if (r === "set") {
454
+ if (c[t]) {
455
+ setSignal(c[t], () => isWrappable(n) ? wrap(n, e) : n);
456
+ } else if (!s) {
457
+ const r = upsertStoreNode(e, c, t, o, e[STORE_SNAPSHOT_PROPS]);
458
+ setSignal(r, () => isWrappable(n) ? wrap(n, e) : n);
459
+ }
460
+ } else if (r === "invalidate") {
461
+ if (c[t]) {
462
+ setSignal(c[t], {});
463
+ delete c[t];
464
+ }
465
+ } else {
466
+ if (c[t]) {
467
+ setSignal(c[t], undefined);
468
+ } else if (!s) {
469
+ const r = upsertStoreNode(e, c, t, o, e[STORE_SNAPSHOT_PROPS]);
470
+ setSignal(r, undefined);
471
+ }
472
+ }
473
+ notifySelf(e);
474
+ }
475
+
476
+ let Writing = null;
477
+
478
+ const storeTraps = {
479
+ get(e, t, r) {
480
+ if (t === $TARGET) return e;
481
+ if (t === $PROXY) return r;
482
+ if (t === $REFRESH) return e[STORE_FIREWALL];
483
+ if (pendingCheckActive) witnessAffectsMark(e);
484
+ if (t === $TRACK) {
485
+ trackSelf(e);
486
+ return r;
487
+ }
488
+ const n = getObserver() === e[STORE_FIREWALL];
489
+ const o = getNodes(e, STORE_NODE);
490
+ const i = n ? undefined : o[t];
491
+ const s = e[STORE_VALUE];
492
+ if (!i && !e[STORE_OVERRIDE] && !e[STORE_OPTIMISTIC_OVERRIDE] && !e[STORE_CUSTOM_PROTO] && !e[STORE_OPTIMISTIC] && !e[STORE_SNAPSHOT_PROPS] && !s[$TARGET] && !(t in s) && getObserver() && !n && !writeOnly(r)) {
493
+ return read(getNode(e, o, t, undefined));
494
+ }
495
+ const E = getOverlayLayer(e, t);
496
+ const O = !!E;
497
+ const c = !!e[STORE_VALUE][$TARGET];
498
+ const f = E ?? e[STORE_VALUE];
499
+ if (!i) {
500
+ const n = Object.getOwnPropertyDescriptor(f, t);
501
+ if (n && n.get) return n.get.call(r);
502
+ if (!n && !O && e[STORE_CUSTOM_PROTO]) {
503
+ const e = unwrapStoreValue(f);
504
+ if (hasInheritedAccessor(e, t)) {
505
+ return Reflect.get(f, t, r);
506
+ }
507
+ }
508
+ }
509
+ if (writeOnly(r)) {
510
+ if (isPrototypePollutionKey(t) && !hasOwnStoreProperty(e, t)) return undefined;
511
+ let r = i && (O || !c) ? visibleNodeValue(i) : f[t];
512
+ r === $DELETED && (r = undefined);
513
+ if (!isWrappable(r)) return r;
514
+ const n = wrap(r, e);
515
+ Writing?.add(n);
516
+ return n;
517
+ }
518
+ let S = i ? O || !c ? read(o[t]) : (read(o[t]), f[t]) : f[t];
519
+ S === $DELETED && (S = undefined);
520
+ if (!i) {
521
+ if (!O && typeof S === "function" && !Object.prototype.hasOwnProperty.call(f, t)) {
522
+ let t;
523
+ return !Array.isArray(e[STORE_VALUE]) && (t = Object.getPrototypeOf(e[STORE_VALUE])) && t !== Object.prototype ? S.bind(f) : S;
524
+ } else if (getObserver() && !n) {
525
+ return read(getNode(e, o, t, isWrappable(S) ? wrap(S, e) : S, isEqual, e[STORE_SNAPSHOT_PROPS]));
526
+ }
527
+ }
528
+ return isWrappable(S) ? wrap(S, e) : S;
529
+ },
530
+ has(e, t) {
531
+ if (t === $PROXY || t === $TRACK || t === "__proto__") return true;
532
+ if (pendingCheckActive) witnessAffectsMark(e);
533
+ const r = getOverlayLayer(e, t);
534
+ const n = r ? r[t] !== $DELETED : t in e[STORE_VALUE];
535
+ if (writeOnly(e[$PROXY]) || getObserver() === e[STORE_FIREWALL]) return n;
536
+ const o = getNodes(e, STORE_HAS);
537
+ // If a has-node already exists, it carries the batched presence — `read()`
538
+ // returns `_value` (committed) for untracked reads and the pending value for
539
+ // downstream computes. This keeps `in` consistent with value reads.
540
+ if (o[t]) return read(o[t]);
541
+ // No node yet: `has` reflects committed presence (no pending write could change
542
+ // it without first upserting a has-node at the write site). Create + read only
543
+ // when tracking; leave untracked reads node-free.
544
+ if (getObserver()) {
545
+ return read(getNode(e, o, t, n));
546
+ }
547
+ return n;
548
+ },
549
+ set(e, t, r) {
550
+ if (t === "__proto__") return true;
551
+ const n = e[$PROXY];
552
+ if (writeOnly(n)) {
553
+ untrack(() => {
554
+ const {base: o, overrideKey: i, state: s} = prepareStoreWrite(e, n, t);
555
+ const E = getOverlayLayer(e, t);
556
+ const O = E ? E[t] : o;
557
+ const c = E ? E[t] !== $DELETED : t in e[STORE_VALUE];
558
+ const f = unwrapStoreValue(r);
559
+ // Symbol-keyed writes on arrays are metadata, not index writes — never run
560
+ // them through the numeric index/length machinery (`parseInt` on a symbol
561
+ // throws). #2769
562
+ const S = typeof t === "string" ? Number(t) : -1;
563
+ const R = Array.isArray(s) && Number.isInteger(S) && S >= 0 && S < 4294967295 && String(S) === t;
564
+ const T = R ? S + 1 : 0;
565
+ const u = R && (getOverlayLayer(e, "length") ?? s).length;
566
+ const l = R && T > u ? T : undefined;
567
+ if (O === f && l === undefined) return true;
568
+ armOptimisticStoreWrite(e, n);
569
+ if (f !== undefined && f === o && l === undefined) delete e[i]?.[t]; else {
570
+ const r = e[i] || (e[i] = Object.create(null));
571
+ r[t] = f;
572
+ if (l !== undefined) r.length = l;
573
+ }
574
+ notifyStoreProperty(e, t, "set", f, O, c);
575
+ // Shrinking an array's length must remove the truncated indices, otherwise
576
+ // they leak through `has`, `ownKeys`, and (tracked) index reads from the
577
+ // underlying value. Mark each as deleted and notify so reactive reads update. #2768
578
+ if (Array.isArray(s) && t === "length" && typeof f === "number" && typeof O === "number" && f < O) {
579
+ const t = e[i] || (e[i] = Object.create(null));
580
+ for (let r = f; r < O; r++) {
581
+ if (t[r] === $DELETED) continue;
582
+ const n = r in t ? t[r] : s[r];
583
+ if (!(r in t) && !(r in s)) continue;
584
+ t[r] = $DELETED;
585
+ notifyStoreProperty(e, r, "delete", undefined, n, true);
586
+ }
587
+ }
588
+ // notify length change
589
+ if (Array.isArray(s) && t !== "length" && l !== undefined) {
590
+ const t = getNodes(e, STORE_NODE);
591
+ if (t.length) {
592
+ setSignal(t.length, l);
593
+ } else if (!projectionWriteActive && !e[STORE_OPTIMISTIC]) {
594
+ const r = upsertStoreNode(e, t, "length", u, e[STORE_SNAPSHOT_PROPS]);
595
+ setSignal(r, l);
596
+ }
597
+ }
598
+ if (false) ;
599
+ });
600
+ }
601
+ return true;
602
+ },
603
+ defineProperty(e, t, r) {
604
+ if (t === "__proto__") return true;
605
+ const n = e[$PROXY];
606
+ if (writeOnly(n)) {
607
+ untrack(() => {
608
+ const {base: o, overrideKey: i} = prepareStoreWrite(e, n, t);
609
+ armOptimisticStoreWrite(e, n);
610
+ const s = "value" in r ? {
611
+ ...r,
612
+ value: unwrapStoreValue(r.value)
613
+ } : r;
614
+ Object.defineProperty(e[i] || (e[i] = Object.create(null)), t, s);
615
+ notifyStoreProperty(e, t, "invalidate");
616
+ if (false) ;
617
+ });
618
+ }
619
+ return true;
620
+ },
621
+ deleteProperty(e, t) {
622
+ if (t === "__proto__") return true;
623
+ // Check both optimistic and regular override for existing $DELETED
624
+ const r = e[STORE_OPTIMISTIC_OVERRIDE]?.[t] === $DELETED;
625
+ const n = e[STORE_OVERRIDE]?.[t] === $DELETED;
626
+ if (writeOnly(e[$PROXY]) && !r && !n) {
627
+ untrack(() => {
628
+ const r = e[STORE_OPTIMISTIC] && !projectionWriteActive;
629
+ const n = r ? STORE_OPTIMISTIC_OVERRIDE : STORE_OVERRIDE;
630
+ const o = getOverlayLayer(e, t);
631
+ const i = o ? o[t] : e[STORE_VALUE][t];
632
+ if (t in e[STORE_VALUE] || e[STORE_OVERRIDE] && t in e[STORE_OVERRIDE]) {
633
+ armOptimisticStoreWrite(e, e[$PROXY]);
634
+ (e[n] || (e[n] = Object.create(null)))[t] = $DELETED;
635
+ } else if (e[n] && t in e[n]) {
636
+ armOptimisticStoreWrite(e, e[$PROXY]);
637
+ delete e[n][t];
638
+ } else return true;
639
+ notifyStoreProperty(e, t, "delete", undefined, i, true);
640
+ });
641
+ }
642
+ return true;
643
+ },
644
+ ownKeys(e) {
645
+ if (pendingCheckActive) witnessAffectsMark(e);
646
+ if (getObserver() !== e[STORE_FIREWALL]) trackSelf(e);
647
+ // Merge optimistic override with regular override for key enumeration
648
+ let t = getKeys(e[STORE_VALUE], e[STORE_OVERRIDE], false);
649
+ if (e[STORE_OPTIMISTIC_OVERRIDE]) {
650
+ const r = new Set(t);
651
+ for (const t of Reflect.ownKeys(e[STORE_OPTIMISTIC_OVERRIDE])) {
652
+ if (e[STORE_OPTIMISTIC_OVERRIDE][t] !== $DELETED) r.add(t); else r.delete(t);
653
+ }
654
+ t = Array.from(r);
655
+ }
656
+ return t;
657
+ },
658
+ getOwnPropertyDescriptor(e, t) {
659
+ if (t === $PROXY) return {
660
+ value: e[$PROXY],
661
+ writable: true,
662
+ configurable: true
663
+ };
664
+ // Check optimistic override first, but use base descriptor structure for compatibility
665
+ if (e[STORE_OPTIMISTIC_OVERRIDE] && t in e[STORE_OPTIMISTIC_OVERRIDE]) {
666
+ if (e[STORE_OPTIMISTIC_OVERRIDE][t] === $DELETED) return undefined;
667
+ const r = Reflect.getOwnPropertyDescriptor(e[STORE_OPTIMISTIC_OVERRIDE], t);
668
+ if (r?.get || r?.set || !(t in e[STORE_VALUE])) return r;
669
+ // Get base descriptor structure, override just the value
670
+ const n = getPropertyDescriptor(e[STORE_VALUE], e[STORE_OVERRIDE], t);
671
+ if (n) {
672
+ const r = Reflect.getOwnPropertyDescriptor(e, t);
673
+ const o = !r || r.configurable ? true : n.configurable;
674
+ return {
675
+ ...n,
676
+ configurable: o,
677
+ value: e[STORE_OPTIMISTIC_OVERRIDE][t]
678
+ };
679
+ }
680
+ return {
681
+ value: e[STORE_OPTIMISTIC_OVERRIDE][t],
682
+ writable: true,
683
+ enumerable: true,
684
+ configurable: true
685
+ };
686
+ }
687
+ const r = getPropertyDescriptor(e[STORE_VALUE], e[STORE_OVERRIDE], t);
688
+ // The proxy target is an internal node object, not the original source. When the
689
+ // source has a non-configurable property that does not also exist as non-configurable
690
+ // on the proxy target, the proxy invariant is violated: the engine requires that a
691
+ // property reported as non-configurable must actually be non-configurable on the
692
+ // target object. Override configurable to true only in that case.
693
+ if (r && !r.configurable) {
694
+ const n = Reflect.getOwnPropertyDescriptor(e, t);
695
+ if (!n || n.configurable) return {
696
+ ...r,
697
+ configurable: true
698
+ };
699
+ }
700
+ return r;
701
+ },
702
+ getPrototypeOf(e) {
703
+ return Object.getPrototypeOf(e[STORE_VALUE]);
704
+ }
705
+ };
706
+
707
+ function storeSetter(e, t) {
708
+ const r = Writing;
709
+ Writing = new Set;
710
+ Writing.add(e);
711
+ try {
712
+ const r = t(e);
713
+ if (r !== e && r !== undefined) {
714
+ if (Array.isArray(r)) {
715
+ for (let t = 0, n = r.length; t < n; t++) e[t] = r[t];
716
+ e.length = r.length;
717
+ } else {
718
+ const t = new Set([ ...ownEnumerableKeys(e), ...ownEnumerableKeys(r) ]);
719
+ t.forEach(t => {
720
+ if (t in r) e[t] = r[t]; else delete e[t];
721
+ });
722
+ }
723
+ }
724
+ } finally {
725
+ Writing.clear();
726
+ Writing = r;
727
+ }
728
+ }
729
+
730
+ function createStore(e, t, r) {
731
+ const n = typeof e === "function", o = n ? createProjectionInternal(e, t, r).store : wrap(e);
732
+ return [ o, n ? e => {
733
+ // Mark the projection as manually written before notifying property nodes.
734
+ suppressComputedRecompute(o[$REFRESH]);
735
+ storeSetter(o, e);
736
+ } : e => storeSetter(o, e) ];
737
+ }
738
+
739
+ export { $AFFECTS, $DELETED, $PROXY, $TARGET, $TRACK, STORE_CUSTOM_PROTO, STORE_FIREWALL, STORE_HAS, STORE_LOOKUP, STORE_NODE, STORE_OPTIMISTIC, STORE_OPTIMISTIC_OVERRIDE, STORE_OVERRIDE, STORE_VALUE, STORE_WRAP, createStore, createStoreProxy, getKeys, getOverlayLayer, getPropertyDescriptor, getStoreAffectsNodes, isWrappable, mergedOverlay, notifySelf, ownEnumerableKeys, setWriteOverride, storeLookup, storeSetter, storeTraps, symbolKeyedRecords, trackSelf, visibleNodeValue, witnessAffectsMark, wrap };