@solidjs/signals 2.0.0-rc.6 → 2.0.0-rc.8

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 (131) hide show
  1. package/dist/dev-shared.js +5243 -0
  2. package/dist/dev.attribution.js +2333 -0
  3. package/dist/dev.js +1758 -6621
  4. package/dist/observe/affects.js +127 -0
  5. package/dist/observe/attribution.js +1 -0
  6. package/dist/observe/boundaries.js +586 -0
  7. package/dist/observe/core/action.js +167 -0
  8. package/dist/observe/core/async.js +736 -0
  9. package/dist/observe/core/attribution-hooks.js +60 -0
  10. package/dist/observe/core/attribution.js +2318 -0
  11. package/dist/{types-cjs/core/constants.d.cts → observe/core/constants.js} +135 -71
  12. package/dist/{types-cjs/core/context.d.cts → observe/core/context.js} +37 -12
  13. package/dist/observe/core/core.js +1289 -0
  14. package/dist/observe/core/dev.js +232 -0
  15. package/dist/observe/core/effect.js +179 -0
  16. package/dist/observe/core/error.js +80 -0
  17. package/dist/observe/core/external.js +98 -0
  18. package/dist/observe/core/graph.js +155 -0
  19. package/dist/observe/core/heap.js +147 -0
  20. package/dist/observe/core/invariants.js +43 -0
  21. package/dist/observe/core/lanes.js +168 -0
  22. package/dist/observe/core/optimistic.js +438 -0
  23. package/dist/observe/core/owner.js +308 -0
  24. package/dist/observe/core/scheduler.js +1190 -0
  25. package/dist/observe/core/verdict.js +551 -0
  26. package/dist/observe/index.js +55 -0
  27. package/dist/observe/map.js +482 -0
  28. package/dist/{types-cjs/signals.d.cts → observe/signals.js} +305 -317
  29. package/dist/observe/store/index.js +38 -0
  30. package/dist/observe/store/next/optimistic.js +651 -0
  31. package/dist/observe/store/next/projection.js +242 -0
  32. package/dist/observe/store/next/reconcile.js +373 -0
  33. package/dist/observe/store/next/store.js +2213 -0
  34. package/dist/observe/store/next/target.js +51 -0
  35. package/dist/observe/store/store.js +323 -0
  36. package/dist/observe/store/storePath.js +103 -0
  37. package/dist/observe/store/utils.js +210 -0
  38. package/dist/prod/attribution.js +32 -0
  39. package/dist/prod/boundaries.js +3 -1
  40. package/dist/prod/core/action.js +52 -32
  41. package/dist/prod/core/async.js +177 -128
  42. package/dist/prod/core/attribution-hooks.js +3 -0
  43. package/dist/prod/core/constants.js +32 -1
  44. package/dist/prod/core/context.js +10 -16
  45. package/dist/prod/core/core.js +505 -286
  46. package/dist/prod/core/dev.js +2 -0
  47. package/dist/prod/core/effect.js +72 -43
  48. package/dist/prod/core/external.js +2 -2
  49. package/dist/prod/core/graph.js +40 -36
  50. package/dist/prod/core/heap.js +50 -51
  51. package/dist/prod/core/lanes.js +43 -22
  52. package/dist/prod/core/optimistic.js +224 -80
  53. package/dist/prod/core/owner.js +43 -39
  54. package/dist/prod/core/scheduler.js +347 -232
  55. package/dist/prod/core/verdict.js +71 -74
  56. package/dist/prod/index.js +9 -5
  57. package/dist/prod/map.js +311 -150
  58. package/dist/prod/signals.js +52 -38
  59. package/dist/prod/store/next/optimistic.js +127 -131
  60. package/dist/prod/store/next/projection.js +3 -3
  61. package/dist/prod/store/next/reconcile.js +149 -294
  62. package/dist/prod/store/next/store.js +694 -380
  63. package/dist/prod/store/next/target.js +32 -10
  64. package/dist/prod/store/store.js +12 -14
  65. package/dist/prod/store/utils.js +36 -27
  66. package/dist/types/attribution.d.ts +15 -0
  67. package/dist/types/attribution.prod.d.ts +13 -0
  68. package/dist/types/core/async.d.ts +1 -1
  69. package/dist/types/core/attribution-hooks.d.ts +183 -6
  70. package/dist/types/core/attribution.d.ts +435 -24
  71. package/dist/types/core/constants.d.ts +31 -0
  72. package/dist/types/core/core.d.ts +19 -3
  73. package/dist/types/core/dev.d.ts +165 -26
  74. package/dist/types/core/effect.d.ts +8 -1
  75. package/dist/types/core/heap.d.ts +5 -3
  76. package/dist/types/core/index.d.ts +2 -1
  77. package/dist/types/core/invariants.d.ts +1 -1
  78. package/dist/types/core/lanes.d.ts +17 -0
  79. package/dist/types/core/scheduler.d.ts +69 -4
  80. package/dist/types/core/types.d.ts +29 -9
  81. package/dist/types/index.d.ts +9 -2
  82. package/dist/types/map.d.ts +2 -0
  83. package/dist/types/signals.d.ts +10 -0
  84. package/dist/types/store/index.d.ts +4 -6
  85. package/dist/types/store/next/optimistic.d.ts +4 -2
  86. package/dist/types/store/next/reconcile.d.ts +5 -12
  87. package/dist/types/store/next/store.d.ts +8 -9
  88. package/dist/types/store/next/target.d.ts +56 -55
  89. package/dist/types/store/store.d.ts +14 -9
  90. package/dist/types/store/utils.d.ts +7 -0
  91. package/package.json +21 -16
  92. package/dist/node.cjs +0 -11121
  93. package/dist/prod/store/next/patch-hooks.js +0 -13
  94. package/dist/prod/store/next/patch.js +0 -614
  95. package/dist/types/store/next/patch-hooks.d.ts +0 -41
  96. package/dist/types/store/next/patch.d.ts +0 -91
  97. package/dist/types-cjs/affects.d.cts +0 -47
  98. package/dist/types-cjs/boundaries.d.cts +0 -175
  99. package/dist/types-cjs/core/action.d.cts +0 -64
  100. package/dist/types-cjs/core/async.d.cts +0 -23
  101. package/dist/types-cjs/core/attribution-hooks.d.cts +0 -63
  102. package/dist/types-cjs/core/attribution.d.cts +0 -239
  103. package/dist/types-cjs/core/core.d.cts +0 -176
  104. package/dist/types-cjs/core/dev.d.cts +0 -95
  105. package/dist/types-cjs/core/effect.d.cts +0 -30
  106. package/dist/types-cjs/core/error.d.cts +0 -56
  107. package/dist/types-cjs/core/external.d.cts +0 -15
  108. package/dist/types-cjs/core/graph.d.cts +0 -28
  109. package/dist/types-cjs/core/heap.d.cts +0 -22
  110. package/dist/types-cjs/core/index.d.cts +0 -13
  111. package/dist/types-cjs/core/invariants.d.cts +0 -59
  112. package/dist/types-cjs/core/lanes.d.cts +0 -44
  113. package/dist/types-cjs/core/optimistic.d.cts +0 -6
  114. package/dist/types-cjs/core/owner.d.cts +0 -124
  115. package/dist/types-cjs/core/scheduler.d.cts +0 -231
  116. package/dist/types-cjs/core/types.d.cts +0 -204
  117. package/dist/types-cjs/core/verdict.d.cts +0 -2
  118. package/dist/types-cjs/index.d.cts +0 -10
  119. package/dist/types-cjs/map.d.cts +0 -69
  120. package/dist/types-cjs/package.json +0 -3
  121. package/dist/types-cjs/store/index.d.cts +0 -21
  122. package/dist/types-cjs/store/next/optimistic.d.cts +0 -23
  123. package/dist/types-cjs/store/next/patch-hooks.d.cts +0 -41
  124. package/dist/types-cjs/store/next/patch.d.cts +0 -91
  125. package/dist/types-cjs/store/next/projection.d.cts +0 -8
  126. package/dist/types-cjs/store/next/reconcile.d.cts +0 -17
  127. package/dist/types-cjs/store/next/store.d.cts +0 -127
  128. package/dist/types-cjs/store/next/target.d.cts +0 -192
  129. package/dist/types-cjs/store/store.d.cts +0 -138
  130. package/dist/types-cjs/store/storePath.d.cts +0 -58
  131. package/dist/types-cjs/store/utils.d.cts +0 -74
@@ -0,0 +1,1289 @@
1
+ import { releaseFlightTeardown, handleAsync, clearStatus, parkLoadingWindow, notifyStatus, settlePendingSource, settleErroredDependents } from "./async.js";
2
+
3
+ import { EFFECT_TRACKED, EFFECT_USER, REACTIVE_OPTIMISTIC_DIRTY, CONFIG_OPTIMISTIC, NOT_PENDING, STATUS_UNINITIALIZED, STATUS_ERROR, STATUS_PENDING, REACTIVE_REASK, REACTIVE_RECOMPUTING_DEPS, CONFIG_SYNC, CONFIG_HAS_LANE, REACTIVE_MISSED_WAKE, REACTIVE_NONE, REACTIVE_SNAPSHOT_STALE, unwrapOverride, CONFIG_DIRECT_COMMIT, OVERRIDE_UNDEFINED, CONFIG_HAS_COMPANIONS, REACTIVE_LAZY, REACTIVE_DISPOSED, CONFIG_AUTO_DISPOSE, CONFIG_CHILDREN_FORBIDDEN, CONFIG_FRESH_READ, CONFIG_INPUTS_PUBLISHED, CONFIG_AUTHORITATIVE_READ, CONFIG_OVERRIDE_SUPERSEDED, CONFIG_AUTHORITATIVE_OBSERVED, CONFIG_HELD_TRUTH, REACTIVE_CHECK, REACTIVE_DIRTY, REACTIVE_IN_HEAP, REACTIVE_IN_HEAP_HEIGHT, defaultContext, CONFIG_IN_SNAPSHOT_SCOPE, CONFIG_TRANSPARENT, CONFIG_OWNED_WRITE, CONFIG_NO_SNAPSHOT, NO_SNAPSHOT, CONFIG_HAS_SNAPSHOT, REACTIVE_MANUAL_WRITE, CONFIG_FW_CHILDREN, CONFIG_SLOT_NODE, STORE_SNAPSHOT_PROPS } from "./constants.js";
4
+
5
+ import { NotReadyError } from "./error.js";
6
+
7
+ import { trimStaleDeps, link, dormantNodes } from "./graph.js";
8
+
9
+ import { deleteFromHeap, queueFor, insertIntoHeapHeight, enqueueSub, markNode, markHeap, insertIntoHeap } from "./heap.js";
10
+
11
+ import { GlobalQueue, bumpNotifyEpoch, activeTransition, globalQueue, clock, currentTransition, insertSubs, queuePendingNode, runInTransition, schedule, notifyEpoch, dirtyQueue, projectionWriteActive, reaskArmed, armReaskClear } from "./scheduler.js";
12
+
13
+ import { GRAPH_SIZE_WARN_AT, noteFanIn } from "./dev.js";
14
+
15
+ import { attrHooks } from "./attribution-hooks.js";
16
+
17
+ import "./invariants.js";
18
+
19
+ import { disposeChildren, markDisposal, inheritId } from "./owner.js";
20
+
21
+ // The heap's per-node step. A tracked effect's heap visit is its compute
22
+ // phase — empty, like a user effect whose compute reads nothing — and hands
23
+ // the callback to the user queue. Routing the wake through the heap, rather
24
+ // than straight into the queue at notify time, is what orders the run after
25
+ // the commit regardless of which phase the write came from: a write in a
26
+ // render-effect callback stages its value for the next pass, but a wake pushed
27
+ // directly into the user queue ran in the SAME pass, read the old value, and
28
+ // nothing re-notified it when the value landed (#3291).
29
+ GlobalQueue.lt = e => {
30
+ if (e.Re === EFFECT_TRACKED) {
31
+ deleteFromHeap(e, queueFor(e));
32
+ e._t = true;
33
+ e.C.enqueue(EFFECT_USER, e.ct);
34
+ } else recompute(e);
35
+ };
36
+
37
+ GlobalQueue.Et = disposeChildren;
38
+
39
+ let tracking = false;
40
+
41
+ /** @internal verdict-module glue */ function setPendingCheckActive(e) {
42
+ pendingCheckActive = e;
43
+ }
44
+
45
+ /** @internal verdict-module glue */ function setLatestReadActive(e) {
46
+ latestReadActive = e;
47
+ }
48
+
49
+ /** @internal verdict-module glue */ function setContextInternal(e) {
50
+ context = e;
51
+ }
52
+
53
+ let stale = false;
54
+
55
+ let pendingCheckActive = false;
56
+
57
+ let latestReadActive = false;
58
+
59
+ let context = null;
60
+
61
+ let currentOptimisticLane = null;
62
+
63
+ let snapshotCaptureActive = false;
64
+
65
+ let snapshotSources = null;
66
+
67
+ function ownerInSnapshotScope(e) {
68
+ while (e) {
69
+ if (e.It) return true;
70
+ e = e.Nt;
71
+ }
72
+ return false;
73
+ }
74
+
75
+ function setSnapshotCapture(e) {
76
+ snapshotCaptureActive = e;
77
+ if (e && !snapshotSources) snapshotSources = new Set;
78
+ }
79
+
80
+ function markSnapshotScope(e) {
81
+ e.It = true;
82
+ }
83
+
84
+ function releaseSnapshotScope(e) {
85
+ e.It = false;
86
+ releaseSubtree(e);
87
+ schedule();
88
+ }
89
+
90
+ function releaseSubtree(e) {
91
+ let t = e.Tt;
92
+ while (t) {
93
+ if (t.It) {
94
+ t = t.dt;
95
+ continue;
96
+ }
97
+ if (t.ot) {
98
+ const e = t;
99
+ e.T &= ~CONFIG_IN_SNAPSHOT_SCOPE;
100
+ if (e.it & REACTIVE_SNAPSHOT_STALE) {
101
+ e.it &= ~REACTIVE_SNAPSHOT_STALE;
102
+ e.it |= REACTIVE_DIRTY;
103
+ if (dirtyQueue.St > e.At) dirtyQueue.St = e.At;
104
+ insertIntoHeap(e, dirtyQueue);
105
+ }
106
+ }
107
+ releaseSubtree(t);
108
+ t = t.dt;
109
+ }
110
+ }
111
+
112
+ function clearSnapshots() {
113
+ if (snapshotSources) {
114
+ for (const e of snapshotSources) {
115
+ delete e.o?.Ot;
116
+ // StoreNode targets share one pre-initialized hidden class (see
117
+ // createStoreProxy) — assign undefined instead of deleting, and only
118
+ // when present so signal-node sources don't grow the field.
119
+ if (e[STORE_SNAPSHOT_PROPS] !== undefined) e[STORE_SNAPSHOT_PROPS] = undefined;
120
+ }
121
+ snapshotSources = null;
122
+ }
123
+ snapshotCaptureActive = false;
124
+ }
125
+
126
+ function recompute(e, t = false) {
127
+ // §12d: any recompute can clean a marked subscriber — invalidate skips.
128
+ bumpNotifyEpoch();
129
+ const n = e.Re;
130
+ // Attribution hook: fired before this run touches the dep list — `_deps`
131
+ // still holds the previous run's links (the subscriptions that could have
132
+ // triggered this run, and the baseline for the engine's subscription diff).
133
+ let i = false;
134
+ if (attrHooks !== null) attrHooks.recomputeStart(e, t);
135
+ if (!t) {
136
+ if (e.Ee && (!n || activeTransition) && activeTransition !== e.Ee) globalQueue.initTransition(e.Ee);
137
+ deleteFromHeap(e, queueFor(e));
138
+ if (e.o !== null) {
139
+ e.o.Se = null;
140
+ // Supersede is where an iterator flight dies (#3122): close it now.
141
+ // Its cleanup(close) registration may sit in a zombie-deferred
142
+ // disposal list that a held transition only drains when the
143
+ // SUPERSEDING flight settles — cancellation must not wait for the
144
+ // work that replaced it. Idempotent with the cleanup-channel close.
145
+ releaseFlightTeardown(e);
146
+ }
147
+ // Tracked effects run after finalizePureQueue, so dispose immediately instead of deferring
148
+ if (e.Ee || n === EFFECT_TRACKED) disposeChildren(e); else if (e.Tt !== null || e.he !== null) {
149
+ markDisposal(e);
150
+ const t = ext(e);
151
+ t.Ct = e.he;
152
+ t.Rt = e.Tt;
153
+ e.he = null;
154
+ e.Tt = null;
155
+ e.Gt = 0;
156
+ } else ;
157
+ }
158
+ let l = !!(e.it & REACTIVE_OPTIMISTIC_DIRTY);
159
+ const u = (e.T & CONFIG_OPTIMISTIC) !== 0 && e.o?.De !== NOT_PENDING && e.o?.De !== undefined;
160
+ const o = !!(e.S & STATUS_UNINITIALIZED);
161
+ // Capture both error and pending status before the compute clears them.
162
+ // A conditional can drop its pending source and recover to an unchanged
163
+ // value, leaving blocked dependents outside that source’s settle walk.
164
+ const s = e.S & STATUS_ERROR ? e.o?._ : undefined;
165
+ const a = e.S & STATUS_PENDING ? e.o?.ee : undefined;
166
+ // Pending SOURCE-hood, captured before the compute clears status: a node
167
+ // whose own flight parked dependents self-registers in _pendingSources
168
+ // (notifyStatus, isSource). If this recompute supersedes that flight and
169
+ // settles synchronously, those dependents settle HERE — asyncWrite's
170
+ // settlePendingSource walk never runs for a landing that was preempted
171
+ // (#3181).
172
+ const r = e.o?.ee?.has(e);
173
+ // Re-ask classification lives in the verdict module; capture the flag before
174
+ // the recompute wipes _flags below.
175
+ const _ = (e.it & REACTIVE_REASK) !== 0;
176
+ // Captured before the compute clears it on a sync landing: if that landing
177
+ // is transition-held below, the window must stay open until the hold
178
+ // commits (commitPendingNode) — a closed window plus a held value reads as
179
+ // a pending frame to live observers of the verdict (#2990).
180
+ const c = e.de;
181
+ const f = context;
182
+ context = e;
183
+ e.Dt = null;
184
+ e.Pt++;
185
+ e.it = REACTIVE_RECOMPUTING_DEPS;
186
+ e.ae = clock;
187
+ let E = e.Pe === NOT_PENDING ? e.ge : e.Pe;
188
+ let I = e.At;
189
+ let N = false;
190
+ let T = tracking;
191
+ let d = currentOptimisticLane;
192
+ tracking = true;
193
+ // A computed's fn establishes its OWN dependencies, so it must never run
194
+ // inside a latest() read window: read() short-circuits through the
195
+ // companion path before dependency linking, so a memo created (eagerly
196
+ // computed) inside latest(fn) came out permanently dependency-less (#2926).
197
+ // latestRead() already suspends the flag for its pull-recomputes; this
198
+ // covers creation-time computes and flushes that run inside the window.
199
+ const S = latestReadActive;
200
+ latestReadActive = false;
201
+ // Lane posture lives with the engine: OPTIMISTIC_DIRTY is only ever set by
202
+ // engine-driven paths, and _optimisticNodes is only pushed by
203
+ // _optimisticWrite, so the hook is installed whenever either gate holds.
204
+ if (l) {
205
+ const t = GlobalQueue.Ft(e, true);
206
+ if (t) currentOptimisticLane = t;
207
+ // `false` = wake-only lane demotion: recompute plain so a mid-tick
208
+ // latest()/isPending() pull stages instead of direct-committing (#3009).
209
+ // The predicate lives with the engine (recomputeLane).
210
+ else if (t === false) l = false;
211
+ } else if (activeTransition && !t && activeTransition.en.length) {
212
+ // Lane adoption: parent-deeper-than-owned-child can run before its OPT-dirty
213
+ // child propagates. Walk deps once and inherit the OPT lane so this node
214
+ // recomputes under the right posture and propagates correctly.
215
+ const t = GlobalQueue.Ft(e, false);
216
+ if (t) {
217
+ l = true;
218
+ currentOptimisticLane = t;
219
+ }
220
+ }
221
+ const A = n && n !== EFFECT_USER;
222
+ const O = stale;
223
+ if (A) stale = true;
224
+ // An effect recorded for this transaction's commit replay (it once read a
225
+ // node the transaction held and showed the committed value) and now
226
+ // recomputing UNDER the transaction sees its staged view: the value this
227
+ // run produces is applied by the commit itself, and the stale recording
228
+ // would publish the frame a second time. Drop it; the reads below re-record
229
+ // if they are served the committed view again (a lane's committed read).
230
+ if (n && activeTransition !== null && activeTransition.ht.size) activeTransition.ht.delete(e);
231
+ try {
232
+ if (!false && e.T & CONFIG_SYNC) {
233
+ E = e.ot(E);
234
+ if (e.o !== null) e.o.Se = null;
235
+ e.de = false;
236
+ } else {
237
+ // Snapshot `_inFlight` so we can detect whether `_fn` self-registered an async
238
+ // subscription (e.g. `createProjection` calls `handleAsync` from inside its body
239
+ // with a setter callback). In that case, the outer `handleAsync` call below would
240
+ // clobber the fresh subscription, so we skip it and let the internally-registered
241
+ // iteration drive updates.
242
+ const t = e.o?.Se;
243
+ const n = e.ot(E);
244
+ const i = typeof n === "object" && n !== null;
245
+ const l = e.o?.Se !== t;
246
+ E = l || !i ? n : handleAsync(e, n);
247
+ if (!l && !i) {
248
+ if (e.o !== null) e.o.Se = null;
249
+ // A sync (non-object) return is the first real answer; async-shaped
250
+ // results clear inside handleAsync at their own landing points, and a
251
+ // self-registered flight (inFlightChanged — projections) clears when
252
+ // its internal handleAsync lands.
253
+ e.de = false;
254
+ }
255
+ }
256
+ // On a status-free node clearStatus is a guaranteed no-op: every field
257
+ // its body gates on is either _statusFlags or lives in the cold
258
+ // extension — no extension, no status to clear. (_x from an unrelated
259
+ // installer just makes clearStatus a cheap re-verified no-op.)
260
+ if (e.S !== 0 || e.o !== null) clearStatus(e, t);
261
+ // _optimisticLane is only ever assigned by engine paths (CONFIG_HAS_LANE
262
+ // is their sticky presence mark).
263
+ if (e.T & CONFIG_HAS_LANE && e.o?.Te) GlobalQueue.Ht(e);
264
+ } catch (t) {
265
+ const n = t instanceof NotReadyError;
266
+ if (n && e.de) {
267
+ // Loading window with an unready sync dependency: register for the
268
+ // source's settle (the settlePendingSource walk runs off
269
+ // _pendingSources + _blocked alone) but take NO read-visible pending
270
+ // status, no downstream propagation, no transition, no lane
271
+ // registration — the committed loading value keeps serving. If the
272
+ // node is currently errored the error stays the answer until this
273
+ // retry can actually run.
274
+ parkLoadingWindow(e, t);
275
+ } else {
276
+ // Track pending async in the lane (not the lane's source — it creates the lane
277
+ // but doesn't belong to it). Set lane BEFORE notifyStatus for downstream propagation.
278
+ if (n && currentOptimisticLane) GlobalQueue.vt(e);
279
+ let i = false;
280
+ if (n) {
281
+ ext(e).ie = true;
282
+ if (GlobalQueue.gt !== null) i = GlobalQueue.gt(e, _);
283
+ }
284
+ notifyStatus(e, n ? STATUS_PENDING : STATUS_ERROR, t, undefined, n ? e.o?.Te : undefined);
285
+ // The replacement source is fully propagated now. If no new flight
286
+ // re-owned self, retire the superseded flight and its dependent copies.
287
+ if (n && r && !e.o?.Se) settlePendingSource(e);
288
+ if (i) GlobalQueue.k(e);
289
+ }
290
+ } finally {
291
+ tracking = T;
292
+ latestReadActive = S;
293
+ if (A) stale = O;
294
+ // Consume the missed-wake latch (#3037, set by insertSubs): a dep write
295
+ // landed beneath this pass on a link it had already validated. The wipe
296
+ // below must not key off DIRTY/CHECK — the read-time pull protocol
297
+ // (markNode(c) in read()) marks the running node as part of ordinary
298
+ // bookkeeping, and those marks are correctly discarded here.
299
+ N = (e.it & REACTIVE_MISSED_WAKE) !== 0;
300
+ e.it = REACTIVE_NONE | (t ? e.it & REACTIVE_SNAPSHOT_STALE : 0);
301
+ context = f;
302
+ }
303
+ if (!e.o?._) {
304
+ trimStaleDeps(e);
305
+ // Observe-tier fan-in (HUGE_FAN_IN): with the stale tail trimmed, the dep
306
+ // list IS this pass's distinct sources — count it here rather than per
307
+ // link. A begin/end bracket around the pass plus a per-link increment
308
+ // measured -5.8% on createRenderEffects:create1to1 (CodSpeed, dev tier)
309
+ // and cost several points of the shape wins elsewhere; this walk is a
310
+ // fraction of the reads that built the list and keeps no module state,
311
+ // so nested pulls need no save/restore.
312
+ {
313
+ let t = 0;
314
+ for (let n = e.te; n !== null; n = n.ne) t++;
315
+ if (t >= GRAPH_SIZE_WARN_AT) noteFanIn(e, t);
316
+ }
317
+ // INV-11 (#3330): the equality gate compares against the slot this run
318
+ // publishes to. An override-covered node publishes the override; a lane
319
+ // recompute (OPT-dirty) direct-commits `_value` — the lane's own reveal
320
+ // schedule — so a transaction-held `_pendingValue` that already equals
321
+ // the new result is not "unchanged": the screen still shows `_value`.
322
+ // Only a transaction-staged run compares against `_pendingValue`.
323
+ const _ = u ? unwrapOverride(e.o?.De) : l || e.Pe === NOT_PENDING ? e.ge : e.Pe;
324
+ let f = false;
325
+ try {
326
+ f = !n && o || !e.Ue || !e.Ue(_, E);
327
+ } catch (t) {
328
+ // A throwing user comparator is an error of this node's computation.
329
+ // Route it through the same status path as a compute-phase throw so
330
+ // error boundaries contain it; otherwise it unwinds the scheduler
331
+ // flush, bypassing every boundary and wedging the queue (#2837).
332
+ notifyStatus(e, STATUS_ERROR, t);
333
+ }
334
+ // A committed derived change becomes a cause for this node's subscribers,
335
+ // chaining their attribution through this node to the root write.
336
+ if (attrHooks !== null) {
337
+ i = f && !e.o?._;
338
+ if (i && !n && !t) attrHooks.derivedChanged(e);
339
+ }
340
+ // Effects use `_equals: false` (no per-effect closure). The side effects that
341
+ // the equals closure used to perform — flagging the effect dirty and enqueueing
342
+ // its runner — happen here instead. `!create` matches the previous `initialized`
343
+ // gate: the explicit recompute(node, true) inside effect() does not enqueue, so
344
+ // effect() can call its runner synchronously for the first run.
345
+ if (n && f) {
346
+ e._t = !e.o?._;
347
+ // Reuse one bound runner per effect — runEffect no-ops on a stale
348
+ // `_modified`, so re-enqueueing the same function is harmless.
349
+ if (!t) {
350
+ e.C.enqueue(n, e.kt ??= GlobalQueue.bt.bind(null, e));
351
+ // Contested effect (#3322). Effects don't entangle transactions (a
352
+ // shared effect is not shared state), yet they have one value slot:
353
+ // when this write commits under a different transaction
354
+ // (`activeTransition`, null = mainline) than the one that produced the
355
+ // previous value (`_valueTransition`), that view is gone. Rather than
356
+ // merge the two, each commit re-derives the effect against its own
357
+ // committed world (Transition._contested, re-dirtied by
358
+ // finalizePureQueue ahead of the heap run). The previous owner always
359
+ // needs it if still live: its commit is silent (staging already
360
+ // notified) and the value it computed is gone. The new owner needs it
361
+ // too, for the same reason, unless it is mainline — mainline publishes
362
+ // what it computes. A previous owner that was mainline, or already
363
+ // committed, left nothing to protect.
364
+ let t = e.Vt;
365
+ if (t !== activeTransition) {
366
+ e.Vt = activeTransition;
367
+ if (t !== null && (t = currentTransition(t)) !== activeTransition && !t.Ut) {
368
+ (t.xt ??= []).push(e);
369
+ if (activeTransition !== null) (activeTransition.xt ??= []).push(e);
370
+ }
371
+ }
372
+ }
373
+ }
374
+ if (e.o?._) ; else if (f) {
375
+ const i = u ? e.o?.De : undefined;
376
+ if (t ||
377
+ // Plain sync flush (no transition on either side) commits effect
378
+ // values directly — the pending round-trip (queuePendingNode +
379
+ // commitPendingNodes) exists to sequence transition reveals, and
380
+ // paying it per effect on the plain path is pure overhead.
381
+ // DIRECT_COMMIT effects (resolve/until) commit directly even under
382
+ // their own held transition: their applies deliver on a microtask,
383
+ // not the stashed queues, so a staged value would hand the immediate
384
+ // apply stale state — see CONFIG_DIRECT_COMMIT.
385
+ n && (activeTransition !== e.Ee || activeTransition === null || e.T & CONFIG_DIRECT_COMMIT) || l) {
386
+ e.ge = E;
387
+ // Lane-propagated correction: upstream data is fresh, correct the
388
+ // override unconditionally. The direct _value commit is the lane's
389
+ // own reveal schedule; drop any superseded older hold so its queued
390
+ // commit can't clobber the fresh value.
391
+ if (u && l) {
392
+ ext(e).De = E === undefined ? OVERRIDE_UNDEFINED : E;
393
+ e.Pe = NOT_PENDING;
394
+ }
395
+ } else {
396
+ e.Pe = E;
397
+ // A window landing that gets held re-opens the window until the hold
398
+ // commits — the verdict's held-value branch is window-gated (#2990).
399
+ if (c) e.de = true;
400
+ // Transition-held sync recompute is a write path like setSignal/asyncWrite,
401
+ // so sync derivations of held sources stay visible to isPending()/latest()
402
+ // (#2831). Both companion writes are transition-scoped (optimistic) and
403
+ // auto-revert/re-derive at commit. Skipped for plain flushes where the
404
+ // pending value commits before effects run.
405
+ if ((activeTransition || e.Ee) && GlobalQueue.Ae !== null) GlobalQueue.Ae(e, E);
406
+ }
407
+ // insertSubs only walks _subs (no scheduling of its own), so a
408
+ // subscriber-less node has nothing to notify.
409
+ if (e.u !== null && (!u || l || e.o?.De !== i)) insertSubs(e, l || u);
410
+ // A18 supersession, sync twin of asyncWrite's override branch (#3331):
411
+ // this pass published truth that differs from the override (the gate
412
+ // compared against it) into the transaction-held slot. Whether the
413
+ // source is this node's own async or an upstream node it derives from
414
+ // synchronously makes no difference — "the source recomputed". The
415
+ // override stays displayed until the commit; the graph moves to the
416
+ // staged truth now (plain channel, lane demoted). Ordering: "a new
417
+ // value from the source" postdates the override — an override written
418
+ // in this same tick (optimisticWrite stamps `_overrideTime`) is the
419
+ // newer intent over whatever this pass derives from the batch's staged
420
+ // inputs, and is not superseded by it.
421
+ else if (u && !l && e.o.Lt !== clock) GlobalQueue.Oe(e, E);
422
+ } else if (u) {
423
+ // Unchanged value (equals the override) recomputed while the override
424
+ // is active: _value may still be stale, so hold the authoritative value
425
+ // for commit on its own transition's schedule — invisibly (A17/A18).
426
+ if (e.Pe === NOT_PENDING) queuePendingNode(e);
427
+ e.Pe = E;
428
+ if (c) e.de = true;
429
+ // see the held branch above (#2990)
430
+ // A confirmation after a supersession restores the override as the
431
+ // graph's value and notifies; a plain confirmation wakes only an
432
+ // authoritative-view reader (until()'s predicate, refresh()'s waiter)
433
+ // that observed this node past its override — "authoritative arrival
434
+ // equal to the override" is exactly the acknowledgment it waits for;
435
+ // A17 silence holds for every ordinary subscriber. Both live in the
436
+ // engine's supersedeOverride.
437
+ GlobalQueue.Oe(e, E);
438
+ } else if (e.At != I) {
439
+ for (let t = e.u; t !== null; t = t.se) {
440
+ insertIntoHeapHeight(t.le, queueFor(t.le));
441
+ }
442
+ }
443
+ // Silent recovery: errored → unchanged value fires no notification, but
444
+ // dependents still holding the propagated error consumed their dirty flag
445
+ // in an errored run and may sit on stale commits (#2949). Changed-value
446
+ // recoveries ride insertSubs above; a comparator throw re-errored the node
447
+ // (el._x?._error re-set), so this only runs on a genuinely clean recovery.
448
+ if (!f && !e.o?._) {
449
+ if (s !== undefined) settleErroredDependents(e, s);
450
+ // Self-registration (this node's own superseded flight) is the #3181
451
+ // sweep's business below — retiring it here too would walk twice.
452
+ if (a) for (const t of a) if (t !== e) settlePendingSource(e, t);
453
+ }
454
+ // #3181: a synchronous settle supersedes the old landing callback, so
455
+ // recompute owns its pending-source sweep. An uninitialized node without
456
+ // a replacement source still has no truth to reveal and must stay parked.
457
+ if (r && !(e.S & (STATUS_PENDING | STATUS_UNINITIALIZED))) settlePendingSource(e);
458
+ }
459
+ // Attribution hook: fired before the lane restore so `currentOptimisticLane`
460
+ // still reflects THIS run's posture. The facts distinguish an overlay
461
+ // recompute (optimistic lane, transition replay, transition-held commit)
462
+ // from a plain committed one — the engine must not blame overlay runs as
463
+ // waste or double-count them against plain aggregates.
464
+ if (attrHooks !== null) attrHooks.recomputeEnd(e, t, i, l || currentOptimisticLane !== null, activeTransition !== null || e.Ee !== null, e.Pe !== NOT_PENDING);
465
+ currentOptimisticLane = d;
466
+ const C = e.Pe !== NOT_PENDING || e.o !== null && (e.o.Rt !== null || e.o.Ct !== null) || (e.S & (STATUS_PENDING | STATUS_UNINITIALIZED)) !== 0;
467
+ // Override-covered holds (hasOverride) always queue: their commit belongs
468
+ // to their own transition's schedule (A18 re-rule) and is unobservable
469
+ // under the override (A17). Revert no longer commits anything, so an
470
+ // unqueued covered hold would leak (INV-7) once the revert clears
471
+ // _transition.
472
+ C && (!t || e.S & STATUS_PENDING) && (!e.Ee || u) && queuePendingNode(e);
473
+ e.Ee && n && activeTransition !== e.Ee && runInTransition(e.Ee, () => recompute(e));
474
+ // Missed-wake reschedule (see the finally above): values this pass read
475
+ // before the nested commit are stale, so run again now that the heap will
476
+ // accept the node. Equality gates stop same-value landings from cascading,
477
+ // and a re-run only latches again if another nested commit changes a dep
478
+ // beneath it — convergent unless deps genuinely keep changing.
479
+ if (N) {
480
+ enqueueSub(e);
481
+ schedule();
482
+ }
483
+ }
484
+
485
+ function updateIfNecessary(e) {
486
+ // Never re-enter a node that is currently computing: its dep bookkeeping
487
+ // (_depsTail/_depGen) is live, and a nested recompute would corrupt it.
488
+ // A mid-pass mark stays latched for recompute's own tail to reschedule
489
+ // (#3037); readers meanwhile serve the values the pass has so far.
490
+ // Never recompute a DISPOSED node either: recompute rewrites _flags and
491
+ // would resurrect it (#2983) — readers serve its last value.
492
+ if (e.it & (REACTIVE_RECOMPUTING_DEPS | REACTIVE_DISPOSED)) return;
493
+ if (e.it & REACTIVE_CHECK) {
494
+ for (let t = e.te; t; t = t.ne) {
495
+ const n = t.oe;
496
+ const i = n.re || n;
497
+ if (i.ot) {
498
+ updateIfNecessary(i);
499
+ }
500
+ if (e.it & REACTIVE_DIRTY) {
501
+ break;
502
+ }
503
+ }
504
+ }
505
+ if (e.it & (REACTIVE_DIRTY | REACTIVE_OPTIMISTIC_DIRTY) || e.o?._ && e.ae < clock && !e.o?.Se) {
506
+ recompute(e);
507
+ }
508
+ e.it = e.it & (REACTIVE_SNAPSHOT_STALE | REACTIVE_IN_HEAP | REACTIVE_IN_HEAP_HEIGHT);
509
+ }
510
+
511
+ function computed(e, t) {
512
+ const n = t?.transparent ?? false;
513
+ // `in` (not `!== undefined`): an explicit `loadingValue: undefined` on a
514
+ // `T | undefined` node is a real commit #0. The typeof guard tolerates
515
+ // non-object option values that older call shapes force through `as any`.
516
+ const i = t !== null && typeof t === "object" && "loadingValue" in t;
517
+ // Two literals, one per tier, selected at build time (the observe flag is
518
+ // a literal after replacement; the untaken branch is dead code). The observe
519
+ // literal is the prod literal plus its `_name` slot — a slot in the
520
+ // boilerplate, because a post-construction `self._name = …` forces a
521
+ // hidden-class transition and an out-of-object property store on EVERY node
522
+ // (measured: the whole of the observe tier's creation overhead). Keep the
523
+ // two in sync — the dist artifact test pins observe's key set to prod's
524
+ // plus `_name`.
525
+ const l = {
526
+ id: inheritId(t, n, context),
527
+ T: (n ? CONFIG_TRANSPARENT : 0) | (t?.ownedWrite ? CONFIG_OWNED_WRITE : 0) | (!context || t?.lazy ? CONFIG_AUTO_DISPOSE : 0) | (t?.sync ? CONFIG_SYNC : 0) | (t?.V ? CONFIG_NO_SNAPSHOT : 0) | (snapshotCaptureActive && ownerInSnapshotScope(context) ? CONFIG_IN_SNAPSHOT_SCOPE : 0),
528
+ Ue: t?.equals ?? isEqual,
529
+ he: null,
530
+ C: context?.C ?? globalQueue,
531
+ ft: context?.ft ?? defaultContext,
532
+ Gt: 0,
533
+ ot: e,
534
+ ge: i ? t.loadingValue : undefined,
535
+ At: 0,
536
+ yt: undefined,
537
+ Qt: null,
538
+ te: null,
539
+ Dt: null,
540
+ Pt: 0,
541
+ u: null,
542
+ Wt: null,
543
+ Nt: context,
544
+ dt: null,
545
+ wt: null,
546
+ Tt: null,
547
+ it: t?.lazy ? REACTIVE_LAZY : REACTIVE_NONE,
548
+ S: i ? 0 : STATUS_UNINITIALIZED,
549
+ ae: clock,
550
+ Pe: NOT_PENDING,
551
+ Ee: null,
552
+ Mt: -1,
553
+ de: i,
554
+ o: null,
555
+ _name: t?.name ?? "computed"
556
+ };
557
+ if (t?.unobserved) ext(l).qt = t.unobserved;
558
+ setupComputedNode(l, t);
559
+ return l;
560
+ }
561
+
562
+ /** Lazily allocate a node's cold extension (ONE shape for signals and
563
+ * computeds — `_x` access stays monomorphic). Installers write through
564
+ * this; hot paths read `el._x?._field` gated by the _config presence bits.
565
+ * Never call ext() just to store a field's default. */ function ext(e) {
566
+ return e.o ??= {
567
+ De: undefined,
568
+ Yt: undefined,
569
+ Lt: 0,
570
+ Zt: 0,
571
+ Te: undefined,
572
+ be: undefined,
573
+ pe: undefined,
574
+ Qe: undefined,
575
+ t: 0,
576
+ Se: null,
577
+ ce: null,
578
+ _: undefined,
579
+ ie: undefined,
580
+ ee: undefined,
581
+ h: undefined,
582
+ Ne: false,
583
+ i: null,
584
+ qt: undefined,
585
+ Ot: undefined,
586
+ Ct: null,
587
+ Rt: null,
588
+ jt: undefined
589
+ };
590
+ }
591
+
592
+ /**
593
+ * Build an Effect node with all effect-specific fields baked into a single object literal,
594
+ * so V8 sees the full hidden class shape at construction time. Effects always run in lazy
595
+ * mode (recompute is called explicitly by `effect()`), so we hardcode the lazy bits and skip
596
+ * the auto-dispose CONFIG bit (effect() previously cleared it post-construction).
597
+ */ function createEffectNode(e, t, n, i, l) {
598
+ const u = l?.transparent ?? false;
599
+ // Prod and observe boilerplates — see computed() for why the observe tier
600
+ // gets its `_name` as a literal slot rather than a write after the fact.
601
+ // The default label is the node kind (tracked effects relabel their computed
602
+ // in trackedEffect); the wrappers in signals.ts no longer spread a name into
603
+ // the options to get it.
604
+ const o = {
605
+ id: inheritId(l, u, context),
606
+ T: (u ? CONFIG_TRANSPARENT : 0) | (l?.ownedWrite ? CONFIG_OWNED_WRITE : 0) | (l?.sync ? CONFIG_SYNC : 0) | (l?.Kt ?? 0) | (snapshotCaptureActive && ownerInSnapshotScope(context) ? CONFIG_IN_SNAPSHOT_SCOPE : 0),
607
+ Ue: false,
608
+ he: null,
609
+ C: context?.C ?? globalQueue,
610
+ ft: context?.ft ?? defaultContext,
611
+ Gt: 0,
612
+ ot: e,
613
+ ge: undefined,
614
+ At: 0,
615
+ yt: undefined,
616
+ Qt: null,
617
+ te: null,
618
+ Dt: null,
619
+ Pt: 0,
620
+ u: null,
621
+ Wt: null,
622
+ Nt: context,
623
+ dt: null,
624
+ wt: null,
625
+ Tt: null,
626
+ it: REACTIVE_LAZY,
627
+ S: STATUS_UNINITIALIZED,
628
+ ae: clock,
629
+ Pe: NOT_PENDING,
630
+ Ee: null,
631
+ Mt: -1,
632
+ de: false,
633
+ _t: false,
634
+ Bt: undefined,
635
+ zt: t,
636
+ Jt: n,
637
+ Xt: undefined,
638
+ Re: i,
639
+ Vt: null,
640
+ o: null,
641
+ _name: l?.name ?? "effect"
642
+ };
643
+ // Effects dispatch status through the SHARED notifier (statusNotifierOf,
644
+ // keyed off _type) — storing it per node forced a full NodeExtension
645
+ // allocation on EVERY effect at creation (an alloc + 19 field stores,
646
+ // +23% effect creation, caught by the creation benches). Only genuinely
647
+ // per-node channels (boundaries) live on _x.
648
+ if (l?.unobserved) ext(o).qt = l.unobserved;
649
+ setupComputedNode(o, lazyOptions);
650
+ return o;
651
+ }
652
+
653
+ /**
654
+ * The shared status notifier for effect nodes, installed once by effect.ts
655
+ * at module evaluation (`this`-dispatched — one function serves every
656
+ * effect, so nodes never store it). Boundary computeds keep their own
657
+ * per-node channel on `_x._notifyStatus`, which takes precedence.
658
+ */ let effectStatusNotify = null;
659
+
660
+ function setEffectStatusNotify(e) {
661
+ effectStatusNotify = e;
662
+ }
663
+
664
+ /** Resolve a node's status notifier: an own `_x` channel (boundaries) wins;
665
+ * effect nodes (`_type` — EFFECT_PURE is 0, and only effect literals carry
666
+ * the field) fall back to the shared notifier. Presence doubles as the
667
+ * "display consumer" membership test in the status walks, exactly as the
668
+ * per-node field did when every effect carried one. */ function statusNotifierOf(e) {
669
+ const t = e.o?.h;
670
+ if (t !== undefined) return t;
671
+ return e.Re ? effectStatusNotify ?? undefined : undefined;
672
+ }
673
+
674
+ const lazyOptions = {
675
+ lazy: true
676
+ };
677
+
678
+ function setupComputedNode(e, t) {
679
+ e.Qt = e;
680
+ const n = context?.$t ? context.ln : context;
681
+ if (context) {
682
+ const t = context.Tt;
683
+ if (t === null) {
684
+ context.Tt = e;
685
+ } else {
686
+ e.dt = t;
687
+ t.wt = e;
688
+ context.Tt = e;
689
+ }
690
+ }
691
+ if (n) e.At = n.At + 1;
692
+ if (GlobalQueue.un !== null) GlobalQueue.un(e);
693
+ !t?.lazy && recompute(e, true);
694
+ if (snapshotCaptureActive && !t?.lazy) {
695
+ if (!(e.S & STATUS_PENDING) && !(e.T & CONFIG_NO_SNAPSHOT)) {
696
+ ext(e).Ot = e.ge === undefined ? NO_SNAPSHOT : e.ge;
697
+ e.T |= CONFIG_HAS_SNAPSHOT;
698
+ snapshotSources.add(e);
699
+ }
700
+ }
701
+ }
702
+
703
+ function signal(e, t, n = null) {
704
+ // Prod and observe boilerplates — see computed(). The observe literal adds
705
+ // `_name` and `_owner` (the creating owner, stamped by registerGraph for
706
+ // createSignal nodes so ownerPath can locate signal subjects; null here,
707
+ // and staying null on internal signals — one shape either way).
708
+ const i = {
709
+ Ue: t?.equals ?? isEqual,
710
+ T: (t?.ownedWrite ? CONFIG_OWNED_WRITE : 0) | (t?.V ? CONFIG_NO_SNAPSHOT : 0),
711
+ ge: e,
712
+ u: null,
713
+ Wt: null,
714
+ ae: clock,
715
+ re: n,
716
+ ue: n?.o?.i || null,
717
+ sn: null,
718
+ Pe: NOT_PENDING,
719
+ Ee: null,
720
+ Mt: -1,
721
+ o: null,
722
+ _name: t?.name ?? "signal",
723
+ an: null
724
+ };
725
+ if (t?.unobserved) ext(i).qt = t.unobserved;
726
+ if (n) linkFirewallChild(n, i);
727
+ if (snapshotCaptureActive && !(i.T & CONFIG_NO_SNAPSHOT) && !((n?.S ?? 0) & STATUS_PENDING)) {
728
+ ext(i).Ot = e === undefined ? NO_SNAPSHOT : e;
729
+ i.T |= CONFIG_HAS_SNAPSHOT;
730
+ snapshotSources.add(i);
731
+ }
732
+ return i;
733
+ }
734
+
735
+ // ---------------------------------------------------------------------------
736
+ // SLOT SIGNALS (store leaves) — the create-floor diet. Store mounts
737
+ // materialize one signal per touched leaf (~13 × rows on dbmon), so per-node
738
+ // allocations are mount bytes: the generic path costs an options object, an
739
+ // equals closure, an unobserved closure, a NodeExtension to hold it, and
740
+ // three post-construction expandos (acc/px/pxv → hidden-class transitions).
741
+ // slotSignal bakes everything into ONE literal: `_host`/`_key` backrefs
742
+ // replace the closures (equals is a method call — `this` is the node; the
743
+ // unobserved sweep dispatches CONFIG_SLOT_NODE to one shared hook), and the
744
+ // store's wrap-cache fields are pre-shaped.
745
+ /** The shared slot-node unobserved handler — a live binding read directly by
746
+ * the sweep sites (no wrapper frame, no null check: a CONFIG_SLOT_NODE node
747
+ * existing implies the store module loaded and registered the hook). */ let slotUnobservedHook;
748
+
749
+ /** Install the shared slot-node unobserved handler (store module, once). */ function setSlotUnobserved(e) {
750
+ slotUnobservedHook = e;
751
+ }
752
+
753
+ /** Push a new node onto its firewall's child chain (the literal already
754
+ * points `_nextChild` at the old head). Doubly linked so a released leaf
755
+ * unlinks in O(1) — the chain is walked per mark of the projection and
756
+ * would otherwise grow by one node per leaf ever read (#3351). */ function linkFirewallChild(e, t) {
757
+ const n = t.ue;
758
+ if (n !== null) n.sn = t;
759
+ ext(e).i = t;
760
+ e.T |= CONFIG_FW_CHILDREN;
761
+ }
762
+
763
+ /** Release a firewall child the store no longer addresses (unobserved sweep
764
+ * dropped it from its target's cache): unlink it from the chain so the
765
+ * projection stops retaining it and its last value. The node keeps its own
766
+ * `_nextChild` so a walk that is mid-chain on it still terminates. Nodes in
767
+ * `_companionChildren` stay there — companions are permanent by contract
768
+ * and snap through that set, not the chain. */ function unlinkFirewallChild(e) {
769
+ const t = e;
770
+ const n = t.re;
771
+ if (!n) return;
772
+ const i = t.sn;
773
+ const l = t.ue;
774
+ if (i !== null) i.ue = l; else if (n.o.i === t) n.o.i = l;
775
+ if (l !== null) l.sn = i;
776
+ t.sn = null;
777
+ }
778
+
779
+ function slotSignal(e, t, n, i, l, u = null) {
780
+ // Prod and observe boilerplates — see computed(). The store relabels the
781
+ // observe slot (`store.<key>`) when the attribution engine is installed.
782
+ const o = {
783
+ Ue: t,
784
+ T: CONFIG_OWNED_WRITE | CONFIG_SLOT_NODE,
785
+ ge: e,
786
+ u: null,
787
+ Wt: null,
788
+ ae: clock,
789
+ re: u,
790
+ ue: u?.o?.i || null,
791
+ sn: null,
792
+ Pe: NOT_PENDING,
793
+ Ee: null,
794
+ Mt: -1,
795
+ o: null,
796
+ rn: n,
797
+ _n: i,
798
+ acc: l,
799
+ px: undefined,
800
+ pxv: undefined,
801
+ _name: "signal"
802
+ };
803
+ if (u) linkFirewallChild(u, o);
804
+ if (snapshotCaptureActive && !((u?.S ?? 0) & STATUS_PENDING)) {
805
+ ext(o).Ot = e === undefined ? NO_SNAPSHOT : e;
806
+ o.T |= CONFIG_HAS_SNAPSHOT;
807
+ snapshotSources.add(o);
808
+ }
809
+ return o;
810
+ }
811
+
812
+ function optimisticSignal(e, t) {
813
+ const n = signal(e, t);
814
+ ext(n).De = NOT_PENDING;
815
+ n.T |= CONFIG_OPTIMISTIC;
816
+ return n;
817
+ }
818
+
819
+ function optimisticComputed(e, t) {
820
+ const n = computed(e, t);
821
+ ext(n).De = NOT_PENDING;
822
+ n.T |= CONFIG_OPTIMISTIC;
823
+ return n;
824
+ }
825
+
826
+ function isEqual(e, t) {
827
+ return e === t;
828
+ }
829
+
830
+ /**
831
+ * Runs `fn` outside of any reactive tracking — reads inside `fn` will not
832
+ * subscribe the current scope. Returns whatever `fn` returns.
833
+ *
834
+ * Use `untrack` inside a memo or effect when you need to read a signal once
835
+ * without making the surrounding computation depend on its future changes.
836
+ *
837
+ * Pass a `strictReadLabel` string to enable a dev-mode warning: any reactive
838
+ * read inside `fn` that isn't inside a nested tracking scope will log a
839
+ * warning naming the label.
840
+ *
841
+ * @example
842
+ * ```ts
843
+ * createEffect(
844
+ * () => trigger(), // tracks `trigger` only
845
+ * () => {
846
+ * const snapshot = untrack(() => state); // read once, untracked
847
+ * log(snapshot);
848
+ * }
849
+ * );
850
+ * ```
851
+ */ function untrack(e, t) {
852
+ if (GlobalQueue.cn === null && !tracking && true) return e();
853
+ const n = tracking;
854
+ tracking = false;
855
+ try {
856
+ if (GlobalQueue.cn !== null) return GlobalQueue.cn(e);
857
+ return e();
858
+ } finally {
859
+ tracking = n;
860
+ }
861
+ }
862
+
863
+ /**
864
+ * Bring a computed to a readable state: lazy/disposed nodes are (re)computed;
865
+ * an isPending() probe (`refresh`) additionally pulls the node fully up to
866
+ * date so its status flags reflect the current graph.
867
+ */ function prepareComputed(e, t) {
868
+ if (e.it & REACTIVE_LAZY) {
869
+ e.it &= ~REACTIVE_LAZY;
870
+ recompute(e, true);
871
+ } else if (e.it & REACTIVE_DISPOSED) {
872
+ // Two disposal lifecycles share the flag (#3024). Observation-lifecycle
873
+ // nodes (CONFIG_AUTO_DISPOSE) are dormant — torn down by unobserved()
874
+ // when the last subscriber left — and reads reawaken them; that is the
875
+ // pay-for-use contract. Owner-lifecycle nodes are dead: recomputing would
876
+ // re-run user code in a torn-down tree (and discard manual writes on
877
+ // derived-writable signals), so reads return the last committed value.
878
+ if (e.T & CONFIG_AUTO_DISPOSE) recompute(e, true);
879
+ } else if (t) {
880
+ updateIfNecessary(e);
881
+ }
882
+ }
883
+
884
+ /**
885
+ * Sentinel returned by readNodeFast when the plain-signal fast path does not
886
+ * apply and the caller must fall back to the full read().
887
+ */ const READ_SLOW = Symbol("read-slow");
888
+
889
+ /**
890
+ * read()'s plain-signal fast path as a standalone entry for hot callers
891
+ * (store traps). Safe to substitute for read() only because the bail
892
+ * conditions mirror read()'s prelude and fast-path guard exactly: the
893
+ * latestRead and pendingCheck windows run side-effectful hooks before the
894
+ * fast path, `_fn` nodes need prepareComputed, and firewall / override /
895
+ * snapshot / transition / lane / dev-strictRead state all take the full
896
+ * resolution. Anything slow returns READ_SLOW; the caller then calls read().
897
+ */
898
+ /**
899
+ * Wake only authoritative-view readers (until() predicates) subscribed to `el`.
900
+ * The A17-silent ack paths — an authoritative arrival equal to the active
901
+ * override — use this so the predicate re-evaluates without re-firing
902
+ * ordinary subscribers whose visible (override) value did not change.
903
+ * Pay-for-use: reached through GlobalQueue._notifyAuthoritativeObservers,
904
+ * installed at first until() call — apps that never use until() shake it.
905
+ */ function notifyAuthoritativeObservers(e) {
906
+ for (let t = e.u; t !== null; t = t.se) {
907
+ const e = t.le;
908
+ if (!(e.T & CONFIG_AUTHORITATIVE_READ)) continue;
909
+ // Missed-wake latch (#3037), same contract as insertSubs: the reader may
910
+ // itself have pulled this recompute (updateIfNecessary from its own
911
+ // read), and the heap refuses RECOMPUTING nodes — latch so recompute's
912
+ // tail reschedules it with the staged value visible.
913
+ if (e.it & REACTIVE_RECOMPUTING_DEPS && t.fn === e.Pt && t !== e.Dt) e.it |= REACTIVE_MISSED_WAKE;
914
+ enqueueSub(e);
915
+ }
916
+ schedule();
917
+ }
918
+
919
+ /** Installs the authoritative-reader wakeup hook. Idempotent; called by every
920
+ * creator of a CONFIG_AUTHORITATIVE_READ computation — until() and refresh() —
921
+ * before its first read (same late-binding contract as the optimistic engine;
922
+ * the gating bit is only ever set by such a read, so the `!` call sites are
923
+ * safe once every setter installs, #3303). */ function installAuthoritativeRead() {
924
+ if (GlobalQueue.En === null) GlobalQueue.En = notifyAuthoritativeObservers;
925
+ }
926
+
927
+ /**
928
+ * Stale-reader term of the value selections below: a render effect reading a
929
+ * node some OTHER live transaction has staged sees the committed value. The
930
+ * commit is silent — the staging walk was the notification — so a reader
931
+ * that linked AFTER that walk (an effect created during the hold, a store
932
+ * key first read under it) would show the old value past the reveal: record
933
+ * it for the transaction's commit replay (the `_gatedSubs` contract lanes
934
+ * already use). An effect the transaction itself computed re-derives at its
935
+ * commit on its own (parked run, or the contested re-derive, #3322) and is
936
+ * not recorded — replaying it too would publish the frame twice.
937
+ */ function heldFromStale(e, t) {
938
+ const n = e.Ee;
939
+ if (n === null || n === activeTransition) return false;
940
+ const i = currentTransition(n);
941
+ const l = t.Vt;
942
+ if (l == null || currentTransition(l) !== i) i.ht.add(t);
943
+ return true;
944
+ }
945
+
946
+ function readNodeFast(e) {
947
+ if (latestReadActive || pendingCheckActive || e.ot || e.re || e.o?.De !== undefined || e.o?.Ot !== undefined || activeTransition !== null || currentOptimisticLane !== null || snapshotCaptureActive || false) return READ_SLOW;
948
+ let t = context;
949
+ if (t?.$t) t = t.ln;
950
+ if (t && tracking) link(e, t);
951
+ // Children-forbidden readers (createTrackedEffect / onSettled callbacks) get
952
+ // committed visibility: like the effect half of createEffect and event
953
+ // handlers, effect-phase code never observes its own unsettled write — the
954
+ // write lands in the same flush's continuation (#3006).
955
+ // A stale reader (render effect) recomputing with no transaction active is
956
+ // mainline: a write staged by a live transaction (`_transition` stamped —
957
+ // ambient staging never is) stays masked until that transaction's reveal,
958
+ // the same rule the slow path applies (#3322). Without it a zombie
959
+ // recompute, or a commit-time re-derive of a contested effect, published
960
+ // another transaction's uncommitted value.
961
+ return !t || e.Pe === NOT_PENDING || t.T & CONFIG_CHILDREN_FORBIDDEN || stale && heldFromStale(e, t) ? e.ge : e.Pe;
962
+ }
963
+
964
+ function read(e) {
965
+ // Handle latest() mode: read from _latestValueComputed
966
+ // Checked before isPending so that isPending(() => latest(x)) checks
967
+ // the _pendingSignal of _latestValueComputed (async in flight) rather
968
+ // than the original node (which stays "pending" while held in a transition).
969
+ if (latestReadActive) return GlobalQueue.In(e);
970
+ let t = context;
971
+ if (t?.$t) t = t.ln;
972
+ const n = e;
973
+ const i = e.re;
974
+ const l = i || e;
975
+ // Handle isPending() mode: collect pending state while preserving normal read semantics.
976
+ // Probe mode is suspended while preparing the node so nested reads during a
977
+ // recompute don't collect into the probe.
978
+ if (pendingCheckActive) {
979
+ GlobalQueue.Nn(e, t, l, i);
980
+ } else if (typeof n.ot === "function") {
981
+ prepareComputed(e, false);
982
+ }
983
+ if (!n.ot && l === e && e.o?.De === undefined && e.o?.Ot === undefined && activeTransition === null && currentOptimisticLane === null && !snapshotCaptureActive && true) {
984
+ if (t && tracking) link(e, t);
985
+ // Committed visibility for children-forbidden readers and for stale
986
+ // readers of a foreign transaction's staged write — see readNodeFast.
987
+ return !t || e.Pe === NOT_PENDING || t.T & CONFIG_CHILDREN_FORBIDDEN || stale && heldFromStale(e, t) ? e.ge : e.Pe;
988
+ }
989
+ if (t && tracking) {
990
+ link(e, t, pendingCheckActive);
991
+ if (l.ot) {
992
+ const n = queueFor(e);
993
+ if (l.At >= n.St) {
994
+ markNode(t);
995
+ markHeap(n);
996
+ updateIfNecessary(l);
997
+ }
998
+ // Fresh-pull readers (awaitable refresh's waiter) recompute a dirty
999
+ // source inline even when the height gate defers to the flush: the
1000
+ // waiter must park on the re-ask's window (or serve its sync answer),
1001
+ // never read the PRE-re-ask value as settled. Self-guarded: a clean
1002
+ // node no-ops and updateIfNecessary refuses disposed nodes (#2983) —
1003
+ // a dead target serves its last value, which is already quiescent.
1004
+ else if (t.T & CONFIG_FRESH_READ) updateIfNecessary(l);
1005
+ const i = l.At;
1006
+ // parent check is shallow, might need to be recursive
1007
+ if (i >= t.At && e.Nt !== t) {
1008
+ t.At = i + 1;
1009
+ }
1010
+ }
1011
+ }
1012
+ if (l.S & STATUS_PENDING) {
1013
+ // A reader landing on a pending node throws — the reveal that discovered
1014
+ // the flight holds on it (A15: observed async settles as one unit) — with
1015
+ // one carve-out: a stale (render) reader of a node pending in some OTHER
1016
+ // transaction keeps showing the node's committed value, no entanglement
1017
+ // (parallel transactions; the reader is recorded for that transaction's
1018
+ // commit replay, `heldFromStale`). The carve-out is sound only while the
1019
+ // committed value is coherent with the visible frame, i.e. while the
1020
+ // flight's inputs are themselves unpublished: the stamp alone does not
1021
+ // say so (it is pending-node bookkeeping), so it is refused when the
1022
+ // inputs are on screen — committed by a batch that left the flight in
1023
+ // the air (CONFIG_INPUTS_PUBLISHED, #3305) or revealed through a lane
1024
+ // (optimistic / latest, #3334) — and the reader holds instead. An
1025
+ // UNINITIALIZED node has no committed value to show and holds too
1026
+ // (firewall-backed store reads always did; plain memos since the #3043
1027
+ // port): falling through served `undefined` as if settled and stranded
1028
+ // the reader outside both transactions, so it never re-ran.
1029
+ if (t && !(stale && !(l.S & STATUS_UNINITIALIZED) && !(l.T & CONFIG_INPUTS_PUBLISHED) && !(l.T & CONFIG_HAS_LANE && GlobalQueue.Tn(l)) && heldFromStale(l, t))) {
1030
+ // Per-lane suspension lives with the engine (a non-null lane implies it
1031
+ // is installed): under a lane, only same-lane pending async without an
1032
+ // active override throws — plus uninitialized sources regardless of
1033
+ // lane (#3276); that check rides laneSuspends so floor bundles don't
1034
+ // pay for it.
1035
+ if (currentOptimisticLane === null || GlobalQueue.dn(l)) {
1036
+ if (!tracking && e !== t) link(e, t);
1037
+ throw l.o?._;
1038
+ }
1039
+ } else if (!t && l.S & STATUS_UNINITIALIZED) {
1040
+ throw l.o?._;
1041
+ }
1042
+ }
1043
+ // `owner` is the computed itself, or the firewall behind a store node —
1044
+ // firewall-backed reads follow the same rules (memo parity, #2897 ruling):
1045
+ // an errored derive throws for every late reader instead of silently
1046
+ // serving node values (the seed, or last-good data after a failed refetch).
1047
+ if (l.ot && l.S & STATUS_ERROR) {
1048
+ // Only a genuine reactive re-read may retry an errored async source:
1049
+ // - tracking: owned/tracked scope only (never events / `untrack` / effect side-effect phase)
1050
+ // - !pendingCheckActive: an `isPending` probe observes the error, never refetches
1051
+ // - owner._time < clock: only on a later cycle than the one the error was found
1052
+ if (tracking && !pendingCheckActive && l.ae < clock) {
1053
+ recompute(l);
1054
+ return read(e);
1055
+ } else throw l.o?._;
1056
+ }
1057
+ if (snapshotCaptureActive && t && t.T & CONFIG_IN_SNAPSHOT_SCOPE) {
1058
+ const n = e.o?.Ot;
1059
+ if (n !== undefined) {
1060
+ const i = n === NO_SNAPSHOT ? undefined : n;
1061
+ const l = e.Pe !== NOT_PENDING ? e.Pe : e.ge;
1062
+ if (l !== i) t.it |= REACTIVE_SNAPSHOT_STALE;
1063
+ return i;
1064
+ }
1065
+ }
1066
+ if (e.o?.De !== undefined && e.o?.De !== NOT_PENDING) {
1067
+ // A17: the override IS the value for every reader — except an authoritative
1068
+ // reader (until()'s predicate carries CONFIG_AUTHORITATIVE_READ): it must
1069
+ // observe independently-arriving truth, and serving it the caller's own
1070
+ // tentative write would trivially satisfy the predicate. The bit is checked
1071
+ // on the reading computation itself, so a shared computed the predicate
1072
+ // pulls recomputes as ITSELF (context = the memo, no bit) under the normal
1073
+ // view. Fall through to normal value selection (staged `_pendingValue` is
1074
+ // authoritative — optimism never lives there); the sticky mark makes the
1075
+ // A17-silent "landing equals override" paths notify this node's subs so
1076
+ // the reader re-runs when truth arrives.
1077
+ if (!(t && t.T & CONFIG_AUTHORITATIVE_READ)) {
1078
+ // A18 supersession (#3331): the node's own source answered with a
1079
+ // DIFFERENT value. The optimism is over for the graph — a tracked
1080
+ // reader sees the staged truth — while the override remains the
1081
+ // DISPLAYED value for untracked reads (and for a stale reader of some
1082
+ // other transaction). The selection lives with the engine.
1083
+ if (t && e.T & CONFIG_OVERRIDE_SUPERSEDED) return GlobalQueue.Sn(e);
1084
+ return unwrapOverride(e.o?.De);
1085
+ }
1086
+ e.T |= CONFIG_AUTHORITATIVE_OBSERVED;
1087
+ }
1088
+ // Entanglement gate: a reader recomputing under an optimistic lane that reads
1089
+ // a pending mid-transition write sees the committed value. Projection-store
1090
+ // manual writes use the firewall's manual-write flag to opt into this path.
1091
+ // Async drivers are not under an optimistic lane and so bypass this, reading
1092
+ // _pendingValue for correct fetching. The sub is recorded for replay at commit
1093
+ // so it re-runs with the new committed view. (Gate details live with the
1094
+ // engine — a non-null lane implies it is installed.)
1095
+ if (currentOptimisticLane !== null && activeTransition !== null && t !== null && GlobalQueue.An(e, l, t)) {
1096
+ return e.ge;
1097
+ }
1098
+ // In optimistic lane context, return _value for optimistic/lane-assigned signals
1099
+ // and for regular signals in stale mode (render effects). Non-stale readers (user
1100
+ // effects) see _pendingValue so that latest() and direct reads stay consistent.
1101
+ // (The lane-context clause lives with the engine.) Children-forbidden readers
1102
+ // (createTrackedEffect / onSettled callbacks) get committed visibility — see
1103
+ // readNodeFast (#3006).
1104
+ const u = !t || currentOptimisticLane !== null && GlobalQueue.On(e, l, t) || e.Pe === NOT_PENDING || t.T & CONFIG_CHILDREN_FORBIDDEN || stale && heldFromStale(e, t) ||
1105
+ // A17 for HELD truth (#3164, see CONFIG_HELD_TRUTH): staged confirming
1106
+ // truth — fold-staged onto an armed family, or entangle-stolen by an
1107
+ // awaited until() — is masked from ordinary readers until its
1108
+ // transaction's reveal; the retaining transaction's own speculative
1109
+ // recomputes included (partial override coverage would otherwise
1110
+ // compose override + staged truth into a state no timeline contains).
1111
+ // Authoritative readers (until()'s predicate) and latest() see the
1112
+ // staged truth — the tunnel that keeps the hold deadlock-free.
1113
+ e.T & CONFIG_HELD_TRUTH && !latestReadActive && !(t.T & CONFIG_AUTHORITATIVE_READ) ? e.ge : e.Pe;
1114
+ // Record that this isPending() probe observed the fresh pending value, so
1115
+ // the probe doesn't pair "pending" with the new value (#2831).
1116
+ if (pendingCheckActive) GlobalQueue.Cn(e, u);
1117
+ if (!t && l === e && typeof n.ot === "function" && e.T & CONFIG_AUTO_DISPOSE && !(l.S & STATUS_PENDING) && !e.u) {
1118
+ // Deferred, not inline (#3078): an inline unobserved() here made untracked
1119
+ // reads destructive — dispose on this read, full revival recompute on the
1120
+ // next — so consecutive reads could answer differently with no write in
1121
+ // between (the revival samples the ambient transition/lane context).
1122
+ // The sweep at flush finalization re-validates and reclaims; schedule()
1123
+ // guarantees that flush happens even if nothing else is queued.
1124
+ dormantNodes.add(e);
1125
+ schedule();
1126
+ }
1127
+ return u;
1128
+ }
1129
+
1130
+ function setSignal(e, t) {
1131
+ if (e.Ee && activeTransition !== e.Ee) globalQueue.initTransition(e.Ee);
1132
+ // The optimistic write path lives with the engine: only optimisticSignal /
1133
+ // optimisticComputed callers and optimistic store nodes carry an
1134
+ // _overrideValue slot (flagged by CONFIG_OPTIMISTIC — a masked read of the
1135
+ // always-present config instead of a missing-property probe), and every
1136
+ // module that installs one installs the engine first.
1137
+ if (e.T & CONFIG_OPTIMISTIC) {
1138
+ if (!projectionWriteActive) return GlobalQueue.pn(e, t);
1139
+ // An authoritative store landing on an override-covered node: the store
1140
+ // twin of asyncWrite's override branch, decided by the engine (#3331).
1141
+ const n = e.o?.De;
1142
+ if (n !== undefined && n !== NOT_PENDING) return GlobalQueue.Rn(e, t);
1143
+ }
1144
+ const n = e.Pe === NOT_PENDING ? e.ge : e.Pe;
1145
+ if (typeof t === "function") t = t(n);
1146
+ // Uninitialized check first: the first commit has no previous value, so the
1147
+ // user comparator must not run against `undefined` (matches recompute).
1148
+ const i = !!(e.S & STATUS_UNINITIALIZED) || !e.Ue || !e.Ue(n, t);
1149
+ if (!i) return t;
1150
+ // Attribution hook: this committed write is where a re-run chain begins.
1151
+ if (attrHooks !== null) attrHooks.write(e, n, t);
1152
+ const l = e.Pe !== NOT_PENDING;
1153
+ if (!l) queuePendingNode(e);
1154
+ e.Pe = t;
1155
+ // syncCompanions only pokes _pendingSignal/_latestValueComputed — with
1156
+ // neither companion present the call is a guaranteed no-op (companions are
1157
+ // only ever created, never removed, and creating one installs the hook and
1158
+ // sets CONFIG_HAS_COMPANIONS — one masked read replaces two optional-field
1159
+ // probes on every write).
1160
+ e.T & CONFIG_HAS_COMPANIONS && GlobalQueue.Ae !== null && GlobalQueue.Ae(e, t);
1161
+ // _time is a computed-only slot (§12e): writing it on a signal would fork
1162
+ // the lean shape. Every read site is computed-typed.
1163
+ if (e.ot !== undefined) e.ae = clock;
1164
+ // Staged-rewrite fast path (§12d): a re-write to a node whose subscribers
1165
+ // were already walked — and where nothing has recomputed or linked since
1166
+ // (epoch) — re-stages the value and stops. The walk is idempotent (subs
1167
+ // marked, heap entries flag-guarded, effects queued once); lane and reask
1168
+ // contexts change what a walk MEANS, so they always walk.
1169
+ if (l && e.Mt === notifyEpoch && currentOptimisticLane === null && !reaskArmed) return t;
1170
+ insertSubs(e);
1171
+ schedule();
1172
+ return t;
1173
+ }
1174
+
1175
+ /**
1176
+ * Suppresses automatic recomputation of `el` until the scheduler drains. Used
1177
+ * when a manual write should win over dependency changes queued in the same
1178
+ * tick. The MANUAL_WRITE flag is cleared by the pending-node drain; projection
1179
+ * computeds don't commit values, but they still need the same end-of-tick
1180
+ * cleanup point.
1181
+ */ function suppressComputedRecompute(e) {
1182
+ deleteFromHeap(e, queueFor(e));
1183
+ if (!(e.it & REACTIVE_MANUAL_WRITE) && e.Pe === NOT_PENDING) {
1184
+ queuePendingNode(e);
1185
+ schedule();
1186
+ }
1187
+ e.it = e.it & -4 | REACTIVE_MANUAL_WRITE;
1188
+ e.Gn = clock;
1189
+ }
1190
+
1191
+ /**
1192
+ * User-facing setter for the memo form of `createSignal(fn)`. Behaves like
1193
+ * `setSignal`, but also cancels any pending recompute of the memo so the
1194
+ * manual value wins over a value that would otherwise be produced by an
1195
+ * upstream change in the same tick.
1196
+ */ function setMemo(e, t) {
1197
+ const n = setSignal(e, t);
1198
+ suppressComputedRecompute(e);
1199
+ return n;
1200
+ }
1201
+
1202
+ /**
1203
+ * Executes `fn` with the given `owner` set as the current owner. Any reactive
1204
+ * primitives (`createSignal`, `createMemo`, `createEffect`, `onCleanup`,
1205
+ * `cleanup`, etc.) created inside `fn` are attached to that owner, so they
1206
+ * are disposed when the owner is disposed.
1207
+ *
1208
+ * The classic pattern: capture the current owner with `getOwner()` inside a
1209
+ * component, then re-enter it from a callback (event handler, async resolve,
1210
+ * setTimeout) so disposables created in the callback get cleaned up with the
1211
+ * component.
1212
+ *
1213
+ * @example
1214
+ * ```ts
1215
+ * function delayed<T>(ms: number, fn: () => T) {
1216
+ * const owner = getOwner();
1217
+ * setTimeout(() => runWithOwner(owner, fn), ms);
1218
+ * }
1219
+ * ```
1220
+ */ function runWithOwner(e, t) {
1221
+ const n = context;
1222
+ const i = tracking;
1223
+ context = e;
1224
+ tracking = false;
1225
+ try {
1226
+ return t();
1227
+ } finally {
1228
+ context = n;
1229
+ tracking = i;
1230
+ }
1231
+ }
1232
+
1233
+ function staleValues(e, t = true) {
1234
+ const n = stale;
1235
+ stale = t;
1236
+ try {
1237
+ return e();
1238
+ } finally {
1239
+ stale = n;
1240
+ }
1241
+ }
1242
+
1243
+ /**
1244
+ * Core marking half of `refresh()` (the public wrapper lives in signals.ts —
1245
+ * it validates the target, marks through here, then builds the quiescence
1246
+ * promise on the resolve()/until() effect machinery). Flags the node's next
1247
+ * recompute as a quiet re-ask and schedules it; no-ops for non-derived or
1248
+ * disposed targets and for same-tick manual writes.
1249
+ */ function markRefresh(e) {
1250
+ if (typeof e.ot === "function" && !(e.it & REACTIVE_DISPOSED)) {
1251
+ if (e.it & REACTIVE_MANUAL_WRITE) {
1252
+ // A manual write in the CURRENT tick wins over the refresh (#2692).
1253
+ // A mask stamped in an earlier tick only survives because a
1254
+ // transaction (action) is holding the pending drain open; there the
1255
+ // refresh is a later, explicit re-ask and lifts the mask — otherwise
1256
+ // any setStore early in an action silently swallows every refresh()
1257
+ // for the rest of the transaction (#3026).
1258
+ if (e.Gn === clock) return;
1259
+ e.it &= ~REACTIVE_MANUAL_WRITE;
1260
+ // The lift falls through to the re-ask classification below. The held
1261
+ // write's value change already rides the transaction; the refetch it
1262
+ // asks for is the same question with unchanged inputs. Skipping the
1263
+ // mark here classified that refetch as a NEW question, which pends
1264
+ // every leaf (3.1) — an action doing setStore + yield + refresh(store)
1265
+ // lit up every sibling row, and affects() could not narrow it (a mark
1266
+ // only turns pending on). Same-question motion stays silent (3.4);
1267
+ // the written slot and any declared mark carry the pending instead.
1268
+ }
1269
+ // A refresh with no value-change dirt already queued is a re-ask of the
1270
+ // same question: mark it so the recompute classifies any resulting
1271
+ // pending window as quiet (not pending). If the node is already dirty
1272
+ // from a real input change, the question changed — don't mark.
1273
+ // REACTIVE_IN_HEAP counts as dirt: insertSubs schedules subscribers by
1274
+ // heap insertion alone (no DIRTY/CHECK flag), so a same-batch value
1275
+ // change followed by refresh() must not be laundered into a quiet re-ask.
1276
+ if (!(e.it & (REACTIVE_DIRTY | REACTIVE_CHECK | REACTIVE_IN_HEAP))) {
1277
+ e.it |= REACTIVE_REASK;
1278
+ armReaskClear();
1279
+ }
1280
+ e.it = e.it & ~REACTIVE_CHECK | REACTIVE_DIRTY;
1281
+ // A refresh() self-invalidation is a root cause too — the target's next
1282
+ // run has no changed dep to point at, so it points here instead.
1283
+ if (attrHooks !== null) attrHooks.refreshed(e);
1284
+ insertIntoHeap(e, queueFor(e));
1285
+ schedule();
1286
+ }
1287
+ }
1288
+
1289
+ export { READ_SLOW, clearSnapshots, computed, context, createEffectNode, currentOptimisticLane, effectStatusNotify, ext, installAuthoritativeRead, isEqual, latestReadActive, markRefresh, markSnapshotScope, notifyAuthoritativeObservers, optimisticComputed, optimisticSignal, pendingCheckActive, prepareComputed, read, readNodeFast, recompute, releaseSnapshotScope, runWithOwner, setContextInternal, setEffectStatusNotify, setLatestReadActive, setMemo, setPendingCheckActive, setSignal, setSlotUnobserved, setSnapshotCapture, signal, slotSignal, slotUnobservedHook, snapshotCaptureActive, snapshotSources, stale, staleValues, statusNotifierOf, suppressComputedRecompute, tracking, unlinkFirewallChild, untrack };