@solidjs/signals 2.0.0-rc.0 → 2.0.0-rc.2

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 (70) hide show
  1. package/README.md +1 -1
  2. package/dist/dev.js +4287 -2803
  3. package/dist/node.cjs +4563 -3756
  4. package/dist/prod/affects.js +16 -16
  5. package/dist/prod/boundaries.js +90 -90
  6. package/dist/prod/core/action.js +3 -3
  7. package/dist/prod/core/async.js +234 -178
  8. package/dist/prod/core/constants.js +39 -1
  9. package/dist/prod/core/core.js +362 -243
  10. package/dist/prod/core/effect.js +56 -56
  11. package/dist/prod/core/external.js +4 -4
  12. package/dist/prod/core/graph.js +65 -54
  13. package/dist/prod/core/heap.js +47 -39
  14. package/dist/prod/core/invariants.js +3 -2
  15. package/dist/prod/core/lanes.js +41 -34
  16. package/dist/prod/core/optimistic.js +78 -58
  17. package/dist/prod/core/owner.js +101 -100
  18. package/dist/prod/core/scheduler.js +249 -192
  19. package/dist/prod/core/verdict.js +185 -78
  20. package/dist/prod/index.js +7 -7
  21. package/dist/prod/map.js +108 -106
  22. package/dist/prod/signals.js +20 -1
  23. package/dist/prod/store/index.js +36 -0
  24. package/dist/prod/store/next/optimistic.js +385 -0
  25. package/dist/prod/store/next/projection.js +172 -0
  26. package/dist/prod/store/next/reconcile.js +331 -0
  27. package/dist/prod/store/next/store.js +1499 -0
  28. package/dist/prod/store/next/target.js +20 -0
  29. package/dist/prod/store/store.js +126 -882
  30. package/dist/prod/store/utils.js +59 -186
  31. package/dist/types/core/attribution-hooks.d.ts +52 -0
  32. package/dist/types/core/attribution.d.ts +186 -0
  33. package/dist/types/core/constants.d.ts +26 -0
  34. package/dist/types/core/core.d.ts +16 -1
  35. package/dist/types/core/dev.d.ts +20 -3
  36. package/dist/types/core/graph.d.ts +1 -0
  37. package/dist/types/core/lanes.d.ts +4 -16
  38. package/dist/types/core/scheduler.d.ts +12 -2
  39. package/dist/types/core/types.d.ts +85 -41
  40. package/dist/types/signals.d.ts +19 -0
  41. package/dist/types/store/index.d.ts +15 -5
  42. package/dist/types/store/next/optimistic.d.ts +20 -0
  43. package/dist/types/store/next/projection.d.ts +8 -0
  44. package/dist/types/store/next/reconcile.d.ts +3 -0
  45. package/dist/types/store/next/store.d.ts +77 -0
  46. package/dist/types/store/next/target.d.ts +117 -0
  47. package/dist/types/store/store.d.ts +26 -101
  48. package/dist/types/store/utils.d.ts +0 -40
  49. package/dist/types-cjs/core/attribution-hooks.d.cts +52 -0
  50. package/dist/types-cjs/core/attribution.d.cts +186 -0
  51. package/dist/types-cjs/core/constants.d.cts +26 -0
  52. package/dist/types-cjs/core/core.d.cts +16 -1
  53. package/dist/types-cjs/core/dev.d.cts +20 -3
  54. package/dist/types-cjs/core/graph.d.cts +1 -0
  55. package/dist/types-cjs/core/lanes.d.cts +4 -16
  56. package/dist/types-cjs/core/scheduler.d.cts +12 -2
  57. package/dist/types-cjs/core/types.d.cts +85 -41
  58. package/dist/types-cjs/signals.d.cts +19 -0
  59. package/dist/types-cjs/store/index.d.cts +15 -5
  60. package/dist/types-cjs/store/next/optimistic.d.cts +20 -0
  61. package/dist/types-cjs/store/next/projection.d.cts +8 -0
  62. package/dist/types-cjs/store/next/reconcile.d.cts +3 -0
  63. package/dist/types-cjs/store/next/store.d.cts +77 -0
  64. package/dist/types-cjs/store/next/target.d.cts +117 -0
  65. package/dist/types-cjs/store/store.d.cts +26 -101
  66. package/dist/types-cjs/store/utils.d.cts +0 -40
  67. package/package.json +2 -1
  68. package/dist/prod/store/optimistic.js +0 -217
  69. package/dist/prod/store/projection.js +0 -231
  70. package/dist/prod/store/reconcile.js +0 -707
@@ -0,0 +1,385 @@
1
+ import { computed, ext, setSignal, isEqual } from "../../core/core.js";
2
+
3
+ import { CONFIG_AUTO_DISPOSE, STATUS_PENDING, NOT_PENDING, unwrapOverride, CONFIG_OPTIMISTIC } from "../../core/constants.js";
4
+
5
+ import { GlobalQueue, insertSubs, schedule, globalQueue } from "../../core/scheduler.js";
6
+
7
+ import "../../core/invariants.js";
8
+
9
+ import "../../core/verdict.js";
10
+
11
+ import "../../core/effect.js";
12
+
13
+ import { installOptimisticEngine } from "../../core/optimistic.js";
14
+
15
+ import { $TARGET, markRawIngest, setNextOptimisticViewResolver, isWrappable, rawValuesUsed, isRawValue } from "../store.js";
16
+
17
+ import { runProjectionComputedNext } from "./projection.js";
18
+
19
+ import { wrapNext, runAuthoritative, storeSetterNext, hasActiveOverride, unwrapValue, getNode, getHasNode, targetsEqual, getKeySetNode, bumpDeep } from "./store.js";
20
+
21
+ import { setOptHooks } from "./target.js";
22
+
23
+ /**
24
+ * Store rewrite — optimistic stores (§3/§7, RUL-3): no store-side layer, no
25
+ * backup snapshots. Nodes in an optimistic family are ARMED core signals
26
+ * (`_overrideValue` slot), so every user write rides the engine's
27
+ * optimisticWrite — per-transaction ownership, entanglement, reverts, and
28
+ * flash-at-flush are inherited, not reimplemented. Membership edits live on
29
+ * armed presence nodes (the §6 overlay), so structural optimism reverts with
30
+ * the same per-transaction granularity (FINDING-2's fix by construction).
31
+ *
32
+ * Derived form = an optimistic projection: the derive's recompute and its
33
+ * async commits run under projectionWriteActive (authoritative landings
34
+ * commit silently beneath any active overrides). The transitionBlocked
35
+ * store-half (#2951) is installed here for next-shaped targets, chaining the
36
+ * legacy/engine checks.
37
+ */ let blockedInstalled = false;
38
+
39
+ function installNextBlockedHalf() {
40
+ if (blockedInstalled) return;
41
+ blockedInstalled = true;
42
+ // Late-bind the optimistic machinery into the plain store/reconcile paths
43
+ // (all call sites are fam?.opt-gated, so this always runs first) and the
44
+ // affects witness's view resolver.
45
+ setOptHooks({
46
+ notifyOptimisticWrites: notifyOptimisticWrites,
47
+ optimisticView: optimisticView,
48
+ applyTentative: applyTentative
49
+ });
50
+ setNextOptimisticViewResolver((e, t) => optimisticView(e, t));
51
+ // Scheduler flush tails call _clearOptimisticStores whenever tracked
52
+ // stores exist; next has no layer to clear — reverts are engine-native —
53
+ // so the hook only empties the batch set.
54
+ if (!GlobalQueue.Vt) {
55
+ GlobalQueue.Vt = e => {
56
+ e.clear();
57
+ };
58
+ }
59
+ const e = GlobalQueue.dn;
60
+ GlobalQueue.dn = t => {
61
+ for (const e of t.cn) {
62
+ const t = e?.[$TARGET];
63
+ const n = t?.fam?.node;
64
+ // The hold exists to keep optimistic state alive until the store's own
65
+ // truth lands (#2951). Once the family carries NO live overrides (a
66
+ // landing consumed them, or they never existed), a pending firewall is
67
+ // no reason to park the transaction — blocking then leaks it forever
68
+ // when the in-flight question is never answered (undisposed fixtures).
69
+ if (n != null && n.S & STATUS_PENDING && familyHasLiveOverrides(t.fam)) return true;
70
+ }
71
+ return e(t);
72
+ };
73
+ }
74
+
75
+ function familyHasLiveOverrides(e) {
76
+ const t = e.overlaid;
77
+ if (t === undefined || t.size === 0) return false;
78
+ for (const e of t) {
79
+ for (const t of [ e.n, e.h ]) {
80
+ if (t === null) continue;
81
+ for (const e of Reflect.ownKeys(t)) {
82
+ const n = t[e];
83
+ if (n.o?.De !== undefined && n.o?.De !== NOT_PENDING) return true;
84
+ }
85
+ }
86
+ if (e.k !== null && e.k.o?.De !== undefined && e.k.o?.De !== NOT_PENDING) return true;
87
+ }
88
+ t.clear();
89
+ // nothing live — drop the bookkeeping
90
+ return false;
91
+ }
92
+
93
+ function createOptimisticStoreNext(e, t, n) {
94
+ // Engine first (armed nodes need optimisticWrite installed before any
95
+ // node exists), then the next-shape hooks.
96
+ installOptimisticEngine();
97
+ installNextBlockedHalf();
98
+ const i = typeof e === "function";
99
+ if (!i && n === undefined) n = t;
100
+ const o = i ? t : e;
101
+ const r = {
102
+ map: new WeakMap,
103
+ node: null,
104
+ shallow: !!n?.shallow,
105
+ opt: true
106
+ };
107
+ const s = wrapNext(o, null, null, r);
108
+ r.px = s;
109
+ if (r.shallow) {
110
+ s[$TARGET].s = true;
111
+ markRawIngest(o);
112
+ }
113
+ if (i) {
114
+ const t = e;
115
+ // Async commits land outside the computed's sync body — re-apply the
116
+ // authoritative-write posture there too. Landings consume the family's
117
+ // tentative overrides (RUL-2: visible landed truth replaces optimism) —
118
+ // both the reconcile-channel commit and per-op post-await draft writes.
119
+ const consume = () => consumeOverridesNext(r);
120
+ const wrapCommit = e => {
121
+ runAuthoritative(e);
122
+ consume();
123
+ };
124
+ let i;
125
+ if (n?.seedLoadingValue) i = {
126
+ loadingValue: undefined
127
+ };
128
+ const o = computed(() => {
129
+ runAuthoritative(() => runProjectionComputedNext(s, t, n?.key === undefined ? "id" : n.key, wrapCommit, consume));
130
+ }, i);
131
+ o.T &= ~CONFIG_AUTO_DISPOSE;
132
+ r.node = o;
133
+ }
134
+ return [ s, e => storeSetterNext(s, e) ];
135
+ }
136
+
137
+ // ---- optimistic-only store machinery (moved from next/store.ts /
138
+ // next/reconcile.ts so plain-store bundles tree-shake it) ----
139
+ /** Diff the draft against the current OPTIMISTIC VIEW (committed + active
140
+ * overrides — the same view the draft was seeded from) and emit engine writes
141
+ * for exactly the changed keys. Visible-view diffing keeps no-op writes from
142
+ * entangling lanes (RUL-10 / opt R38). */ function notifyOptimisticWrites(e, t) {
143
+ // A bare write while the store's own truth is in flight rides THAT
144
+ // transaction (#2951, legacy parity): entangle the firewall's transition so
145
+ // the override survives until the refetch settles instead of flash-reverting
146
+ // at plain flush end. The blocked-check store-half keeps that transaction
147
+ // from settling while the firewall is pending.
148
+ const n = e.fam?.node;
149
+ if (n?._e) globalQueue.initTransition(n._e);
150
+ const i = e.v;
151
+ const visible = (t, n) => {
152
+ const i = e.n?.[t];
153
+ return i !== undefined && hasActiveOverride(i) ? unwrapOverride(i.o?.De) : n;
154
+ };
155
+ const visiblePresent = t => {
156
+ const n = e.h?.[t];
157
+ return n !== undefined && hasActiveOverride(n) ? !!unwrapOverride(n.o?.De) : t in i;
158
+ };
159
+ let o = false;
160
+ const r = Array.isArray(t);
161
+ for (const n of Reflect.ownKeys(t)) {
162
+ if (r && n === "length") continue;
163
+ const s = unwrapValue(t[n]);
164
+ if (!visiblePresent(n)) {
165
+ // Optimistic add: value node + presence node + membership bump.
166
+ setSignal(getNode(e, n, i[n]), () => s);
167
+ setSignal(getHasNode(e, n, n in i), true);
168
+ o = true;
169
+ } else {
170
+ const t = visible(n, i[n]);
171
+ if (!isEqual(t, s) && !targetsEqual(t, s)) {
172
+ setSignal(getNode(e, n, t), () => s);
173
+ if (r) o = true;
174
+ }
175
+ }
176
+ }
177
+ for (const n of Reflect.ownKeys(i)) {
178
+ if (r && n === "length") continue;
179
+ if (n in t || !visiblePresent(n)) continue;
180
+ // Optimistic delete: node reads undefined, presence flips, membership bumps.
181
+ setSignal(getNode(e, n, i[n]), () => undefined);
182
+ setSignal(getHasNode(e, n, true), false);
183
+ o = true;
184
+ }
185
+ if (r) {
186
+ const n = visible("length", i.length);
187
+ if (n !== t.length) {
188
+ setSignal(getNode(e, "length", n), () => t.length);
189
+ o = true;
190
+ }
191
+ }
192
+ if (o) setSignal(getKeySetNode(e), e => e + 1);
193
+ // Deep-witness: optimistic value writes notify deep() subscribers too
194
+ // (structural ones already ride the key-set bump above).
195
+ bumpDeep(e);
196
+ // Discard the draft — committed raw is untouched (revert target by
197
+ // construction). Register the root store for the scheduler's settle hooks
198
+ // and the target for landing consumption (RUL-2).
199
+ e.pb = null;
200
+ (e.fam.overlaid ??= new Set).add(e);
201
+ GlobalQueue.Nn?.(e.fam.px ?? e.px);
202
+ }
203
+
204
+ /**
205
+ * Landing consumption (RUL-2): fresh authoritative data supersedes every
206
+ * tentative override in the family. Mirrors legacy clearProjectionOverride —
207
+ * drop the override, clear lane/ownership, notify subscribers whose visible
208
+ * value changes (reversion effects go to regular queues via the projection
209
+ * write posture the caller holds).
210
+ */ function consumeOverridesNext(e) {
211
+ const t = e.overlaid;
212
+ if (t === undefined || t.size === 0) return;
213
+ runAuthoritative(() => {
214
+ for (const e of t) {
215
+ const drop = (e, t) => {
216
+ if (!hasActiveOverride(e)) return;
217
+ const n = unwrapOverride(e.o?.De);
218
+ // Full legacy reset (clearOptimisticOverride parity): the landing is
219
+ // authoritative NOW — fold committed into the node directly instead
220
+ // of riding a transaction's commit (whose queues may be stashed with
221
+ // the transaction parked; the wake would strand until it settles).
222
+ ext(e).De = NOT_PENDING;
223
+ e.T |= CONFIG_OPTIMISTIC;
224
+ const i = e.o;
225
+ if (i) {
226
+ i.Et = null;
227
+ i.Be = undefined;
228
+ }
229
+ e.Pe = NOT_PENDING;
230
+ e.be = t;
231
+ if (!e.Ue || !e.Ue(n, t)) {
232
+ insertSubs(e, true);
233
+ schedule();
234
+ }
235
+ };
236
+ // Landing consumes STRUCTURAL optimism only (legacy layer parity):
237
+ // membership edits, array length, and the value overrides written WITH
238
+ // them (a key carrying an active presence override is an add/delete —
239
+ // classified BEFORE the adoption may have made the key exist in landed
240
+ // data). A pure value override on a key the landing carries stays with
241
+ // its owning transaction (rapid-toggle contract: a live action's edit
242
+ // of an existing entity rides on top of landed truth).
243
+ const t = Array.isArray(e.v);
244
+ const n = e.h;
245
+ let i = null;
246
+ if (n !== null) {
247
+ for (const e of Reflect.ownKeys(n)) {
248
+ if (hasActiveOverride(n[e])) (i ??= new Set).add(e);
249
+ }
250
+ }
251
+ const o = e.n;
252
+ if (o !== null) {
253
+ for (const n of Reflect.ownKeys(o)) {
254
+ const r = i?.has(n) || !(n in e.v) || t && n === "length";
255
+ if (!r) continue;
256
+ drop(o[n], t && n === "length" ? e.v.length : e.v[n]);
257
+ }
258
+ }
259
+ if (n !== null) {
260
+ for (const t of Reflect.ownKeys(n)) drop(n[t], t in e.v);
261
+ }
262
+ if (e.k !== null && hasActiveOverride(e.k)) {
263
+ ext(e.k).De = NOT_PENDING;
264
+ e.k.T |= CONFIG_OPTIMISTIC;
265
+ const t = e.k.o;
266
+ if (t) {
267
+ t.Et = null;
268
+ t.Be = undefined;
269
+ }
270
+ insertSubs(e.k, true);
271
+ schedule();
272
+ }
273
+ }
274
+ t.clear();
275
+ });
276
+ }
277
+
278
+ /** Optimistic-view composition for snapshot/deep (O1: snapshot is the CURRENT
279
+ * view, lane values included; a fresh copy per call during pending windows —
280
+ * RUL-12). Returns `src` untouched when no override is active on `t`. */ function optimisticView(e, t) {
281
+ if (e.fam?.opt !== true) return t;
282
+ let n = null;
283
+ const ensure = () => n ??= Array.isArray(t) ? [ ...t ] : {
284
+ ...t
285
+ };
286
+ const i = e.n;
287
+ if (i !== null) {
288
+ for (const e of Reflect.ownKeys(i)) {
289
+ const n = i[e];
290
+ if (!hasActiveOverride(n)) continue;
291
+ const o = unwrapOverride(n.o?.De);
292
+ if (e === "length" && Array.isArray(t)) {
293
+ if (t.length !== o) ensure().length = o;
294
+ } else if (!isEqual(t[e], o)) ensure()[e] = o;
295
+ }
296
+ }
297
+ const o = e.h;
298
+ if (o !== null) {
299
+ for (const e of Reflect.ownKeys(o)) {
300
+ const i = o[e];
301
+ if (!hasActiveOverride(i)) continue;
302
+ const r = !!unwrapOverride(i.o?.De);
303
+ if (!r && e in (n ?? t)) delete ensure()[e];
304
+ }
305
+ }
306
+ return n ?? t;
307
+ }
308
+
309
+ function applyTentative(e, t, n) {
310
+ const i = e.pb ?? e.v;
311
+ const o = optimisticView(e, i);
312
+ const r = e.fam.map;
313
+ const s = Array.isArray(t);
314
+ if (Array.isArray(o) !== s) return;
315
+ // kind change at root: flat overrides below
316
+ const l = [];
317
+ const u = s ? [ ...t ] : shallowWithSymbols(t);
318
+ const match = (e, t) => {
319
+ if (!isWrappable(e) || !isWrappable(t)) return null;
320
+ if (rawValuesUsed && (isRawValue(e) || isRawValue(t))) return null;
321
+ if (Array.isArray(e) !== Array.isArray(t)) return null;
322
+ if (n) {
323
+ const i = n(e);
324
+ const o = n(t);
325
+ if (i !== undefined && o !== undefined && i !== o) return null;
326
+ }
327
+ return r.get(unwrapValue(e)) ?? null;
328
+ };
329
+ if (s) {
330
+ const e = o;
331
+ let i = null;
332
+ for (let o = 0; o < t.length; o++) {
333
+ const r = t[o];
334
+ if (!isWrappable(r)) continue;
335
+ let s;
336
+ if (n) {
337
+ const t = n(r);
338
+ if (t !== undefined) {
339
+ if (i === null) {
340
+ i = new Map;
341
+ for (let t = 0; t < e.length; t++) {
342
+ const o = unwrapValue(e[t]);
343
+ if (isWrappable(o)) {
344
+ const e = n(o);
345
+ if (e !== undefined && !i.has(e)) i.set(e, o);
346
+ }
347
+ }
348
+ }
349
+ s = i.get(t);
350
+ } else s = unwrapValue(e[o]);
351
+ } else s = unwrapValue(e[o]);
352
+ const c = match(s, r);
353
+ if (c !== null) {
354
+ // Keep the existing row in the slot (identity preserved); recurse.
355
+ u[o] = unwrapValue(s);
356
+ l.push([ c, r ]);
357
+ }
358
+ }
359
+ } else {
360
+ for (const e of Reflect.ownKeys(t)) {
361
+ const n = unwrapValue(o[e]);
362
+ const i = t[e];
363
+ const r = match(n, i);
364
+ if (r !== null) {
365
+ u[e] = n;
366
+ l.push([ r, i ]);
367
+ }
368
+ }
369
+ }
370
+ // Flat overrides for this level (adds, removals, moved slots, length, leaf
371
+ // values) — preserve any live user draft backing across the call.
372
+ const c = e.pb;
373
+ e.pb = null;
374
+ notifyOptimisticWrites(e, u);
375
+ e.pb = c;
376
+ for (let e = 0; e < l.length; e++) applyTentative(l[e][0], unwrapValue(l[e][1]), n);
377
+ }
378
+
379
+ function shallowWithSymbols(e) {
380
+ const t = {};
381
+ for (const n of Reflect.ownKeys(e)) t[n] = e[n];
382
+ return t;
383
+ }
384
+
385
+ export { consumeOverridesNext, createOptimisticStoreNext, notifyOptimisticWrites, optimisticView };
@@ -0,0 +1,172 @@
1
+ import { computed, suppressComputedRecompute } from "../../core/core.js";
2
+
3
+ import { getOwner } from "../../core/owner.js";
4
+
5
+ import { setProjectionWriteActive, projectionWriteActive } 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 { $TARGET, markRawIngest, STORE_VALUE, setWriteOverride } from "../store.js";
16
+
17
+ import { reconcileNextState } from "./reconcile.js";
18
+
19
+ import { wrapNext, storeSetterNext } from "./store.js";
20
+
21
+ /**
22
+ * Store rewrite — projections (§7/§7b): a projection is a computed store.
23
+ * The derive runs inside a computed whose recompute merges its output into
24
+ * the projection's backing through the adoption channel (replace-mode root:
25
+ * entity changes merge in place, the root proxy is stable for life). Children
26
+ * wrap into the projection's own FAMILY (writes land here, never in a source
27
+ * family), and every family node carries the projection computed as its
28
+ * firewall — reads link the derive's status and lifecycle natively. The §6c
29
+ * status gate in the traps makes an uninitialized async derive's seed
30
+ * unobservable through every read surface.
31
+ *
32
+ * Mirrors the legacy runProjectionComputed shape (shadow runs for open
33
+ * loading windows, handleAsync landings, commit-through-setter) on next
34
+ * primitives; the generic draft write-traps are reused from the legacy
35
+ * module unchanged.
36
+ */ function createWriteTraps(e, t) {
37
+ // Save/restore, never hard-reset: the draft can be driven from inside an
38
+ // enclosing authoritative-write scope (next-store optimistic derives), and
39
+ // a hard `false` would clobber it mid-derive.
40
+ const r = {
41
+ get(e, t) {
42
+ let o;
43
+ const i = projectionWriteActive;
44
+ setWriteOverride(true);
45
+ setProjectionWriteActive(true);
46
+ try {
47
+ o = e[t];
48
+ } finally {
49
+ setWriteOverride(false);
50
+ setProjectionWriteActive(i);
51
+ }
52
+ if (t === $TARGET) return o;
53
+ return typeof o === "object" && o !== null ? new Proxy(o, r) : o;
54
+ },
55
+ has(e, t) {
56
+ let r;
57
+ const o = projectionWriteActive;
58
+ setWriteOverride(true);
59
+ setProjectionWriteActive(true);
60
+ try {
61
+ r = t in e;
62
+ } finally {
63
+ setWriteOverride(false);
64
+ setProjectionWriteActive(o);
65
+ }
66
+ return r;
67
+ },
68
+ set(r, o, i) {
69
+ if (e && !e()) return true;
70
+ const n = projectionWriteActive;
71
+ setWriteOverride(true);
72
+ setProjectionWriteActive(true);
73
+ try {
74
+ r[o] = i;
75
+ t?.();
76
+ } finally {
77
+ setWriteOverride(false);
78
+ setProjectionWriteActive(n);
79
+ }
80
+ return true;
81
+ },
82
+ deleteProperty(r, o) {
83
+ if (e && !e()) return true;
84
+ const i = projectionWriteActive;
85
+ setWriteOverride(true);
86
+ setProjectionWriteActive(true);
87
+ try {
88
+ delete r[o];
89
+ t?.();
90
+ } finally {
91
+ setWriteOverride(false);
92
+ setProjectionWriteActive(i);
93
+ }
94
+ return true;
95
+ }
96
+ };
97
+ return r;
98
+ }
99
+
100
+ function createProjectionNextInternal(e, t, r) {
101
+ const o = {
102
+ map: new WeakMap,
103
+ node: null,
104
+ shallow: !!r?.shallow
105
+ };
106
+ const i = wrapNext(t, null, null, o);
107
+ if (o.shallow) {
108
+ // Shallow projection: the root is the only wrapped level — slot values
109
+ // serve raw, ingests sticky raw-mark (same t.s machinery as plain).
110
+ i[$TARGET].s = true;
111
+ markRawIngest(t);
112
+ }
113
+ let n;
114
+ if (r?.seedLoadingValue) n = {
115
+ loadingValue: undefined
116
+ };
117
+ const c = computed(() => {
118
+ if (!o.node) o.node = getOwner();
119
+ runProjectionComputedNext(i, e, r?.key === undefined ? "id" : r.key);
120
+ }, n);
121
+ c.T &= ~CONFIG_AUTO_DISPOSE;
122
+ o.node = c;
123
+ return {
124
+ store: i,
125
+ node: c
126
+ };
127
+ }
128
+
129
+ function createProjectionNext(e, t, r) {
130
+ return createProjectionNextInternal(e, t, r).store;
131
+ }
132
+
133
+ /** Derived writable store (legacy parity): a projection whose public setter
134
+ * masks the recompute for the tick (core R31 — the manual write wins over a
135
+ * same-flush dependency change). */ function createStoreDerivedNext(e, t, r) {
136
+ const {store: o, node: i} = createProjectionNextInternal(e, t, r);
137
+ return [ o, e => {
138
+ // Mark the projection as manually written before notifying nodes.
139
+ suppressComputedRecompute(i);
140
+ storeSetterNext(o, e);
141
+ } ];
142
+ }
143
+
144
+ function runProjectionComputedNext(e, t, r, o, i) {
145
+ const n = getOwner();
146
+ let c = false;
147
+ let s;
148
+ // Open loading window (seedLoadingValue): the observable store IS commit #0
149
+ // for the whole first flight — the derive works a detached shadow of the
150
+ // seed so draft writes cannot tear through to readers (#2988). Every commit
151
+ // point reconciles the shadow through the normal commit path.
152
+ const u = n.Ie ? JSON.parse(JSON.stringify(e[$TARGET][STORE_VALUE])) : null;
153
+ const l = new Proxy(e, createWriteTraps(() => !c || n.o?.Ee === s, i));
154
+ storeSetterNext(l, i => {
155
+ s = t(u ?? i);
156
+ c = true;
157
+ const commit = t => {
158
+ // Shadow run: commit a detached snapshot, never the shadow itself
159
+ // (adoption takes the value by identity — handing it the live shadow
160
+ // would fuse the draft to the observable store).
161
+ if (u && (t === undefined || t === u)) t = JSON.parse(JSON.stringify(u));
162
+ if (t === i || t === undefined) return;
163
+ const write = () => storeSetterNext(e, e => reconcileNextState(t, e, r, true), false);
164
+ o ? o(write) : write();
165
+ };
166
+ const l = handleAsync(n, s, commit);
167
+ if (!n.Ie) commit(l);
168
+ }, false);
169
+ return n;
170
+ }
171
+
172
+ export { createProjectionNext, createStoreDerivedNext, runProjectionComputedNext };