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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/README.md +4 -3
  2. package/dist/dev.js +2956 -646
  3. package/dist/node.cjs +6396 -3974
  4. package/dist/prod/affects.js +222 -0
  5. package/dist/prod/boundaries.js +568 -0
  6. package/dist/prod/core/action.js +83 -0
  7. package/dist/prod/core/async.js +394 -0
  8. package/dist/prod/core/constants.js +78 -0
  9. package/dist/prod/core/context.js +67 -0
  10. package/dist/prod/core/core.js +772 -0
  11. package/dist/prod/core/dev.js +3 -0
  12. package/dist/prod/core/effect.js +145 -0
  13. package/dist/prod/core/error.js +59 -0
  14. package/dist/prod/core/external.js +98 -0
  15. package/dist/prod/core/graph.js +91 -0
  16. package/dist/prod/core/heap.js +132 -0
  17. package/dist/prod/core/invariants.js +42 -0
  18. package/dist/prod/core/lanes.js +130 -0
  19. package/dist/prod/core/optimistic.js +265 -0
  20. package/dist/prod/core/owner.js +293 -0
  21. package/dist/prod/core/scheduler.js +689 -0
  22. package/dist/prod/core/verdict.js +293 -0
  23. package/dist/prod/index.js +45 -0
  24. package/dist/prod/map.js +264 -0
  25. package/dist/prod/signals.js +389 -0
  26. package/dist/prod/store/optimistic.js +149 -0
  27. package/dist/prod/store/projection.js +184 -0
  28. package/dist/prod/store/reconcile.js +392 -0
  29. package/dist/prod/store/store.js +739 -0
  30. package/dist/prod/store/storePath.js +103 -0
  31. package/dist/prod/store/utils.js +297 -0
  32. package/dist/types/affects.d.ts +47 -0
  33. package/dist/types/boundaries.d.ts +8 -8
  34. package/dist/types/core/async.d.ts +5 -2
  35. package/dist/types/core/constants.d.ts +8 -0
  36. package/dist/types/core/core.d.ts +12 -69
  37. package/dist/types/core/dev.d.ts +1 -1
  38. package/dist/types/core/external.d.ts +0 -30
  39. package/dist/types/core/heap.d.ts +8 -0
  40. package/dist/types/core/index.d.ts +3 -2
  41. package/dist/types/core/invariants.d.ts +10 -0
  42. package/dist/types/core/optimistic.d.ts +6 -0
  43. package/dist/types/core/owner.d.ts +8 -0
  44. package/dist/types/core/scheduler.d.ts +53 -5
  45. package/dist/types/core/types.d.ts +22 -5
  46. package/dist/types/core/verdict.d.ts +2 -0
  47. package/dist/types/index.d.ts +1 -0
  48. package/dist/types/store/projection.d.ts +0 -1
  49. package/dist/types/store/store.d.ts +32 -14
  50. package/dist/types-cjs/affects.d.cts +47 -0
  51. package/dist/types-cjs/boundaries.d.cts +8 -8
  52. package/dist/types-cjs/core/async.d.cts +5 -2
  53. package/dist/types-cjs/core/constants.d.cts +8 -0
  54. package/dist/types-cjs/core/core.d.cts +12 -69
  55. package/dist/types-cjs/core/dev.d.cts +1 -1
  56. package/dist/types-cjs/core/external.d.cts +0 -30
  57. package/dist/types-cjs/core/heap.d.cts +8 -0
  58. package/dist/types-cjs/core/index.d.cts +3 -2
  59. package/dist/types-cjs/core/invariants.d.cts +10 -0
  60. package/dist/types-cjs/core/optimistic.d.cts +6 -0
  61. package/dist/types-cjs/core/owner.d.cts +8 -0
  62. package/dist/types-cjs/core/scheduler.d.cts +53 -5
  63. package/dist/types-cjs/core/types.d.cts +22 -5
  64. package/dist/types-cjs/core/verdict.d.cts +2 -0
  65. package/dist/types-cjs/index.d.cts +1 -0
  66. package/dist/types-cjs/store/projection.d.cts +0 -1
  67. package/dist/types-cjs/store/store.d.cts +32 -14
  68. package/package.json +8 -6
  69. package/dist/prod.js +0 -4406
@@ -0,0 +1,772 @@
1
+ import { handleAsync, clearStatus, notifyStatus } from "./async.js";
2
+
3
+ import { $REFRESH, REACTIVE_DISPOSED, REACTIVE_MANUAL_WRITE, REACTIVE_DIRTY, REACTIVE_CHECK, REACTIVE_IN_HEAP, REACTIVE_REASK, REACTIVE_LAZY, REACTIVE_NONE, defaultContext, CONFIG_TRANSPARENT, CONFIG_OWNED_WRITE, CONFIG_AUTO_DISPOSE, CONFIG_SYNC, CONFIG_NO_SNAPSHOT, CONFIG_IN_SNAPSHOT_SCOPE, NOT_PENDING, STATUS_UNINITIALIZED, STATUS_PENDING, NO_SNAPSHOT, REACTIVE_SNAPSHOT_STALE, EFFECT_TRACKED, REACTIVE_OPTIMISTIC_DIRTY, REACTIVE_RECOMPUTING_DEPS, STATUS_ERROR, REACTIVE_IN_HEAP_HEIGHT, STORE_SNAPSHOT_PROPS, EFFECT_USER } from "./constants.js";
4
+
5
+ import { NotReadyError } from "./error.js";
6
+
7
+ import { trimStaleDeps, link, unobserved } from "./graph.js";
8
+
9
+ import { insertIntoHeap, queueFor, deleteFromHeap, insertIntoHeapHeight, markNode, markHeap } from "./heap.js";
10
+
11
+ import { schedule, GlobalQueue, globalQueue, clock, activeTransition, queuePendingNode, insertSubs, dirtyQueue, activeAffectsMarks, runInTransition, projectionWriteActive, armReaskClear } from "./scheduler.js";
12
+
13
+ import "./invariants.js";
14
+
15
+ import { inheritId, disposeChildren, markDisposal } from "./owner.js";
16
+
17
+ GlobalQueue.Ce = recompute;
18
+
19
+ GlobalQueue.Oe = disposeChildren;
20
+
21
+ let tracking = false;
22
+
23
+ /** @internal verdict-module glue */ function setPendingCheckActive(e) {
24
+ pendingCheckActive = e;
25
+ }
26
+
27
+ /** @internal verdict-module glue */ function setLatestReadActive(e) {
28
+ latestReadActive = e;
29
+ }
30
+
31
+ /** @internal verdict-module glue */ function setContextInternal(e) {
32
+ context = e;
33
+ }
34
+
35
+ let stale = false;
36
+
37
+ let pendingCheckActive = false;
38
+
39
+ let latestReadActive = false;
40
+
41
+ let context = null;
42
+
43
+ let currentOptimisticLane = null;
44
+
45
+ /**
46
+ * Marked sources read by the recompute currently on the stack (saved/restored
47
+ * per recompute, like `context`). A computed that reads a node with a live
48
+ * `affects()` mark inherits the mark's pendingness — `recompute` applies the
49
+ * collected sources through `applyAffectsReads` after its commit, because the
50
+ * `clearStatus` at the top of the commit path wipes whatever sentinel entries
51
+ * the node held from the registration-time push. This is the pull half of
52
+ * mark propagation (real async re-establishes itself by re-throwing on read;
53
+ * marks are value-transparent, so they re-establish here instead).
54
+ */ let affectsReads = null;
55
+
56
+ let snapshotCaptureActive = false;
57
+
58
+ let snapshotSources = null;
59
+
60
+ function ownerInSnapshotScope(e) {
61
+ while (e) {
62
+ if (e.ke) return true;
63
+ e = e.He;
64
+ }
65
+ return false;
66
+ }
67
+
68
+ function setSnapshotCapture(e) {
69
+ snapshotCaptureActive = e;
70
+ if (e && !snapshotSources) snapshotSources = new Set;
71
+ }
72
+
73
+ function markSnapshotScope(e) {
74
+ e.ke = true;
75
+ }
76
+
77
+ function releaseSnapshotScope(e) {
78
+ e.ke = false;
79
+ releaseSubtree(e);
80
+ schedule();
81
+ }
82
+
83
+ function releaseSubtree(e) {
84
+ let t = e.Fe;
85
+ while (t) {
86
+ if (t.ke) {
87
+ t = t.Ve;
88
+ continue;
89
+ }
90
+ if (t.xe) {
91
+ const e = t;
92
+ e.U &= ~CONFIG_IN_SNAPSHOT_SCOPE;
93
+ if (e.u & REACTIVE_SNAPSHOT_STALE) {
94
+ e.u &= ~REACTIVE_SNAPSHOT_STALE;
95
+ e.u |= REACTIVE_DIRTY;
96
+ if (dirtyQueue.Le > e.qe) dirtyQueue.Le = e.qe;
97
+ insertIntoHeap(e, dirtyQueue);
98
+ }
99
+ }
100
+ releaseSubtree(t);
101
+ t = t.Ve;
102
+ }
103
+ }
104
+
105
+ function clearSnapshots() {
106
+ if (snapshotSources) {
107
+ for (const e of snapshotSources) {
108
+ delete e.Ye;
109
+ delete e[STORE_SNAPSHOT_PROPS];
110
+ }
111
+ snapshotSources = null;
112
+ }
113
+ snapshotCaptureActive = false;
114
+ }
115
+
116
+ function recompute(e, t = false) {
117
+ const n = e.De;
118
+ if (!t) {
119
+ if (e.ve && (!n || activeTransition) && activeTransition !== e.ve) globalQueue.initTransition(e.ve);
120
+ deleteFromHeap(e, queueFor(e));
121
+ e.Ae = null;
122
+ // Tracked effects run after finalizePureQueue, so dispose immediately instead of deferring
123
+ if (e.ve || n === EFFECT_TRACKED) disposeChildren(e); else if (e.Fe !== null || e.Me !== null) {
124
+ markDisposal(e);
125
+ e.We = e.Me;
126
+ e.Ze = e.Fe;
127
+ e.Me = null;
128
+ e.Fe = null;
129
+ e.je = 0;
130
+ } else ;
131
+ }
132
+ let i = !!(e.u & REACTIVE_OPTIMISTIC_DIRTY);
133
+ const l = e.be !== undefined && e.be !== NOT_PENDING;
134
+ const u = !!(e.i & STATUS_UNINITIALIZED);
135
+ // Re-ask classification lives in the verdict module; capture the flag before
136
+ // the recompute wipes _flags below.
137
+ const s = (e.u & REACTIVE_REASK) !== 0;
138
+ const o = context;
139
+ context = e;
140
+ e.Ke = null;
141
+ e.ze++;
142
+ e.u = REACTIVE_RECOMPUTING_DEPS;
143
+ e.Ie = clock;
144
+ let a = e.ge === NOT_PENDING ? e.Ue : e.ge;
145
+ let r = e.qe;
146
+ let c = tracking;
147
+ const _ = affectsReads;
148
+ affectsReads = null;
149
+ let f = null;
150
+ let E = currentOptimisticLane;
151
+ tracking = true;
152
+ // Lane posture lives with the engine: OPTIMISTIC_DIRTY is only ever set by
153
+ // engine-driven paths, and _optimisticNodes is only pushed by
154
+ // _optimisticWrite, so the hook is installed whenever either gate holds.
155
+ if (i) {
156
+ const t = GlobalQueue.$e(e, true);
157
+ if (t) currentOptimisticLane = t;
158
+ } else if (activeTransition && !t && activeTransition.Be.length) {
159
+ // Lane adoption: parent-deeper-than-owned-child can run before its OPT-dirty
160
+ // child propagates. Walk deps once and inherit the OPT lane so this node
161
+ // recomputes under the right posture and propagates correctly.
162
+ const t = GlobalQueue.$e(e, false);
163
+ if (t) {
164
+ i = true;
165
+ currentOptimisticLane = t;
166
+ }
167
+ }
168
+ const T = n && n !== EFFECT_USER;
169
+ const N = stale;
170
+ if (T) stale = true;
171
+ try {
172
+ if (!false && e.U & CONFIG_SYNC) {
173
+ a = e.xe(a);
174
+ e.Ae = null;
175
+ } else {
176
+ // Snapshot `_inFlight` so we can detect whether `_fn` self-registered an async
177
+ // subscription (e.g. `createProjection` calls `handleAsync` from inside its body
178
+ // with a setter callback). In that case, the outer `handleAsync` call below would
179
+ // clobber the fresh subscription, so we skip it and let the internally-registered
180
+ // iteration drive updates.
181
+ const t = e.Ae;
182
+ const n = e.xe(a);
183
+ const i = typeof n === "object" && n !== null;
184
+ const l = e.Ae !== t;
185
+ a = l || !i ? n : handleAsync(e, n);
186
+ if (!l && !i) e.Ae = null;
187
+ }
188
+ clearStatus(e, t);
189
+ // _optimisticLane is only ever assigned by engine paths.
190
+ if (e.Je) GlobalQueue.Xe(e);
191
+ } catch (t) {
192
+ // Track pending async in the lane (not the lane's source — it creates the lane
193
+ // but doesn't belong to it). Set lane BEFORE notifyStatus for downstream propagation.
194
+ if (t instanceof NotReadyError && currentOptimisticLane) GlobalQueue.et(e);
195
+ let n = false;
196
+ if (t instanceof NotReadyError) {
197
+ e.Re = true;
198
+ if (GlobalQueue.tt !== null) n = GlobalQueue.tt(e, s);
199
+ }
200
+ notifyStatus(e, t instanceof NotReadyError ? STATUS_PENDING : STATUS_ERROR, t, undefined, t instanceof NotReadyError ? e.Je : undefined);
201
+ if (n) GlobalQueue.nt(e);
202
+ } finally {
203
+ tracking = c;
204
+ if (T) stale = N;
205
+ e.u = REACTIVE_NONE | (t ? e.u & REACTIVE_SNAPSHOT_STALE : 0);
206
+ context = o;
207
+ f = affectsReads;
208
+ affectsReads = _;
209
+ }
210
+ if (!e.k) {
211
+ trimStaleDeps(e);
212
+ const s = l ? e.be : e.ge === NOT_PENDING ? e.Ue : e.ge;
213
+ let o = false;
214
+ try {
215
+ o = !n && u || !e.Ge || !e.Ge(s, a);
216
+ } catch (t) {
217
+ // A throwing user comparator is an error of this node's computation.
218
+ // Route it through the same status path as a compute-phase throw so
219
+ // error boundaries contain it; otherwise it unwinds the scheduler
220
+ // flush, bypassing every boundary and wedging the queue (#2837).
221
+ notifyStatus(e, STATUS_ERROR, t);
222
+ }
223
+ // Effects use `_equals: false` (no per-effect closure). The side effects that
224
+ // the equals closure used to perform — flagging the effect dirty and enqueueing
225
+ // its runner — happen here instead. `!create` matches the previous `initialized`
226
+ // gate: the explicit recompute(node, true) inside effect() does not enqueue, so
227
+ // effect() can call its runner synchronously for the first run.
228
+ if (n && o) {
229
+ e.it = !e.k;
230
+ // Reuse one bound runner per effect — runEffect no-ops on a stale
231
+ // `_modified`, so re-enqueueing the same function is harmless.
232
+ if (!t) e.v.enqueue(n, e.lt ??= GlobalQueue.ut.bind(null, e));
233
+ }
234
+ if (e.k) ; else if (o) {
235
+ const u = l ? e.be : undefined;
236
+ if (t || n && activeTransition !== e.ve || i) {
237
+ e.Ue = a;
238
+ // Lane-propagated correction: upstream data is fresh, correct the
239
+ // override unconditionally. The direct _value commit is the lane's
240
+ // own reveal schedule; drop any superseded older hold so its queued
241
+ // commit can't clobber the fresh value.
242
+ if (l && i) {
243
+ e.be = a;
244
+ e.ge = NOT_PENDING;
245
+ }
246
+ } else {
247
+ e.ge = a;
248
+ // Transition-held sync recompute is a write path like setSignal/asyncWrite,
249
+ // so sync derivations of held sources stay visible to isPending()/latest()
250
+ // (#2831). Both companion writes are transition-scoped (optimistic) and
251
+ // auto-revert/re-derive at commit. Skipped for plain flushes where the
252
+ // pending value commits before effects run.
253
+ if ((activeTransition || e.ve) && GlobalQueue._e !== null) GlobalQueue._e(e, a);
254
+ }
255
+ if (!l || i || e.be !== u) insertSubs(e, i || l);
256
+ } else if (l) {
257
+ // Unchanged value (equals the override) recomputed while the override
258
+ // is active: _value may still be stale, so hold the authoritative value
259
+ // for commit on its own transition's schedule — invisibly (A17/A18).
260
+ if (e.ge === NOT_PENDING) queuePendingNode(e);
261
+ e.ge = a;
262
+ } else if (e.qe != r) {
263
+ for (let t = e.p; t !== null; t = t.de) {
264
+ insertIntoHeapHeight(t.Ee, queueFor(t.Ee));
265
+ }
266
+ }
267
+ }
268
+ currentOptimisticLane = E;
269
+ // Marks read during this recompute re-attach after the commit above:
270
+ // earlier, the sentinel's NotReadyError in `_error` would have routed the
271
+ // fresh value into the error-skip branch instead of committing it. A real
272
+ // (non-NotReady) error wins over marks (#2893): applying the sentinel here
273
+ // would clobber the user's error with a NotReadyError from a node whose
274
+ // reads value-transparency promises can never throw NotReady.
275
+ // `markedReads` only collects under a live mark, so the hook is installed.
276
+ if (f && !(e.i & STATUS_ERROR)) GlobalQueue.j(e, f);
277
+ // Mark-only pending doesn't queue (#2893): the node holds no value needing
278
+ // a transition-scheduled commit, and queueing would stamp the marking
279
+ // action's transaction onto it — freezing unrelated writes that share it.
280
+ // (Single mask test up front keeps the mark-free hot path at original cost.)
281
+ const I = e.i & (STATUS_PENDING | STATUS_UNINITIALIZED);
282
+ const S = e.ge !== NOT_PENDING || e.Ze !== null || e.We !== null || I !== 0 && (I !== STATUS_PENDING || activeAffectsMarks === 0 || !GlobalQueue.$(e));
283
+ // Override-covered holds (hasOverride) always queue: their commit belongs
284
+ // to their own transition's schedule (A18 re-rule) and is unobservable
285
+ // under the override (A17). Revert no longer commits anything, so an
286
+ // unqueued covered hold would leak (INV-7) once the revert clears
287
+ // _transition.
288
+ S && (!t || e.i & STATUS_PENDING) && (!e.ve || l) && queuePendingNode(e);
289
+ e.ve && n && activeTransition !== e.ve && runInTransition(e.ve, () => recompute(e));
290
+ }
291
+
292
+ function updateIfNecessary(e) {
293
+ if (e.u & REACTIVE_CHECK) {
294
+ for (let t = e.S; t; t = t.st) {
295
+ const n = t.ot;
296
+ const i = n.rt || n;
297
+ if (i.xe) {
298
+ updateIfNecessary(i);
299
+ }
300
+ if (e.u & REACTIVE_DIRTY) {
301
+ break;
302
+ }
303
+ }
304
+ }
305
+ if (e.u & (REACTIVE_DIRTY | REACTIVE_OPTIMISTIC_DIRTY) || e.k && e.Ie < clock && !e.Ae) {
306
+ recompute(e);
307
+ }
308
+ e.u = e.u & (REACTIVE_SNAPSHOT_STALE | REACTIVE_IN_HEAP | REACTIVE_IN_HEAP_HEIGHT);
309
+ }
310
+
311
+ function computed(e, t) {
312
+ const n = t?.transparent ?? false;
313
+ const i = {
314
+ id: inheritId(t, n, context),
315
+ U: (n ? CONFIG_TRANSPARENT : 0) | (t?.ownedWrite ? CONFIG_OWNED_WRITE : 0) | (!context || t?.lazy ? CONFIG_AUTO_DISPOSE : 0) | (t?.sync ? CONFIG_SYNC : 0) | (t?.re ? CONFIG_NO_SNAPSHOT : 0) | (snapshotCaptureActive && ownerInSnapshotScope(context) ? CONFIG_IN_SNAPSHOT_SCOPE : 0),
316
+ Ge: t?.equals != null ? t.equals : isEqual,
317
+ ct: t?.unobserved,
318
+ Me: null,
319
+ v: context?.v ?? globalQueue,
320
+ we: context?.we ?? defaultContext,
321
+ je: 0,
322
+ xe: e,
323
+ Ue: undefined,
324
+ qe: 0,
325
+ G: null,
326
+ _t: undefined,
327
+ ft: null,
328
+ S: null,
329
+ Ke: null,
330
+ ze: 0,
331
+ p: null,
332
+ Et: null,
333
+ He: context,
334
+ Ve: null,
335
+ Tt: null,
336
+ Fe: null,
337
+ u: t?.lazy ? REACTIVE_LAZY : REACTIVE_NONE,
338
+ i: STATUS_UNINITIALIZED,
339
+ Ie: clock,
340
+ ge: NOT_PENDING,
341
+ We: null,
342
+ Ze: null,
343
+ Ae: null,
344
+ ve: null,
345
+ A: false
346
+ };
347
+ setupComputedNode(i, t);
348
+ return i;
349
+ }
350
+
351
+ /**
352
+ * Build an Effect node with all effect-specific fields baked into a single object literal,
353
+ * so V8 sees the full hidden class shape at construction time. Effects always run in lazy
354
+ * mode (recompute is called explicitly by `effect()`), so we hardcode the lazy bits and skip
355
+ * the auto-dispose CONFIG bit (effect() previously cleared it post-construction).
356
+ */ function createEffectNode(e, t, n, i, l, u) {
357
+ const s = u?.transparent ?? false;
358
+ const o = {
359
+ id: inheritId(u, s, context),
360
+ U: (s ? CONFIG_TRANSPARENT : 0) | (u?.ownedWrite ? CONFIG_OWNED_WRITE : 0) | (u?.sync ? CONFIG_SYNC : 0) | (snapshotCaptureActive && ownerInSnapshotScope(context) ? CONFIG_IN_SNAPSHOT_SCOPE : 0),
361
+ Ge: false,
362
+ ct: u?.unobserved,
363
+ Me: null,
364
+ v: context?.v ?? globalQueue,
365
+ we: context?.we ?? defaultContext,
366
+ je: 0,
367
+ xe: e,
368
+ Ue: undefined,
369
+ qe: 0,
370
+ G: null,
371
+ _t: undefined,
372
+ ft: null,
373
+ S: null,
374
+ Ke: null,
375
+ ze: 0,
376
+ p: null,
377
+ Et: null,
378
+ He: context,
379
+ Ve: null,
380
+ Tt: null,
381
+ Fe: null,
382
+ u: REACTIVE_LAZY,
383
+ i: STATUS_UNINITIALIZED,
384
+ Ie: clock,
385
+ ge: NOT_PENDING,
386
+ We: null,
387
+ Ze: null,
388
+ Ae: null,
389
+ ve: null,
390
+ A: false,
391
+ it: false,
392
+ Nt: undefined,
393
+ It: t,
394
+ St: n,
395
+ At: undefined,
396
+ De: i,
397
+ C: l
398
+ };
399
+ setupComputedNode(o, lazyOptions);
400
+ return o;
401
+ }
402
+
403
+ const lazyOptions = {
404
+ lazy: true
405
+ };
406
+
407
+ function setupComputedNode(e, t) {
408
+ e.ft = e;
409
+ const n = context?.dt ? context.Ct : context;
410
+ if (context) {
411
+ const t = context.Fe;
412
+ if (t === null) {
413
+ context.Fe = e;
414
+ } else {
415
+ e.Ve = t;
416
+ t.Tt = e;
417
+ context.Fe = e;
418
+ }
419
+ }
420
+ if (n) e.qe = n.qe + 1;
421
+ if (GlobalQueue.Ot !== null) GlobalQueue.Ot(e);
422
+ !t?.lazy && recompute(e, true);
423
+ if (snapshotCaptureActive && !t?.lazy) {
424
+ if (!(e.i & STATUS_PENDING) && !(e.U & CONFIG_NO_SNAPSHOT)) {
425
+ e.Ye = e.Ue === undefined ? NO_SNAPSHOT : e.Ue;
426
+ snapshotSources.add(e);
427
+ }
428
+ }
429
+ }
430
+
431
+ function signal(e, t, n = null) {
432
+ const i = {
433
+ Ge: t?.equals != null ? t.equals : isEqual,
434
+ U: (t?.ownedWrite ? CONFIG_OWNED_WRITE : 0) | (t?.re ? CONFIG_NO_SNAPSHOT : 0),
435
+ ct: t?.unobserved,
436
+ Ue: e,
437
+ p: null,
438
+ Et: null,
439
+ Ie: clock,
440
+ rt: n,
441
+ Ne: n?.G || null,
442
+ ge: NOT_PENDING
443
+ };
444
+ n && (n.G = i);
445
+ if (snapshotCaptureActive && !(i.U & CONFIG_NO_SNAPSHOT) && !((n?.i ?? 0) & STATUS_PENDING)) {
446
+ i.Ye = e === undefined ? NO_SNAPSHOT : e;
447
+ snapshotSources.add(i);
448
+ }
449
+ return i;
450
+ }
451
+
452
+ function optimisticSignal(e, t) {
453
+ const n = signal(e, t);
454
+ n.be = NOT_PENDING;
455
+ return n;
456
+ }
457
+
458
+ function optimisticComputed(e, t) {
459
+ const n = computed(e, t);
460
+ n.be = NOT_PENDING;
461
+ return n;
462
+ }
463
+
464
+ function isEqual(e, t) {
465
+ return e === t;
466
+ }
467
+
468
+ /**
469
+ * Runs `fn` outside of any reactive tracking — reads inside `fn` will not
470
+ * subscribe the current scope. Returns whatever `fn` returns.
471
+ *
472
+ * Use `untrack` inside a memo or effect when you need to read a signal once
473
+ * without making the surrounding computation depend on its future changes.
474
+ *
475
+ * Pass a `strictReadLabel` string to enable a dev-mode warning: any reactive
476
+ * read inside `fn` that isn't inside a nested tracking scope will log a
477
+ * warning naming the label.
478
+ *
479
+ * @example
480
+ * ```ts
481
+ * createEffect(
482
+ * () => trigger(), // tracks `trigger` only
483
+ * () => {
484
+ * const snapshot = untrack(() => state); // read once, untracked
485
+ * log(snapshot);
486
+ * }
487
+ * );
488
+ * ```
489
+ */ function untrack(e, t) {
490
+ if (GlobalQueue.Rt === null && !tracking && true) return e();
491
+ const n = tracking;
492
+ tracking = false;
493
+ try {
494
+ if (GlobalQueue.Rt !== null) return GlobalQueue.Rt(e);
495
+ return e();
496
+ } finally {
497
+ tracking = n;
498
+ }
499
+ }
500
+
501
+ /**
502
+ * Bring a computed to a readable state: lazy/disposed nodes are (re)computed;
503
+ * an isPending() probe (`refresh`) additionally pulls the node fully up to
504
+ * date so its status flags reflect the current graph.
505
+ */ function prepareComputed(e, t) {
506
+ if (e.u & REACTIVE_LAZY) {
507
+ e.u &= ~REACTIVE_LAZY;
508
+ recompute(e, true);
509
+ } else if (e.u & REACTIVE_DISPOSED) {
510
+ recompute(e, true);
511
+ } else if (t) {
512
+ updateIfNecessary(e);
513
+ }
514
+ }
515
+
516
+ function read(e) {
517
+ // Handle latest() mode: read from _latestValueComputed
518
+ // Checked before isPending so that isPending(() => latest(x)) checks
519
+ // the _pendingSignal of _latestValueComputed (async in flight) rather
520
+ // than the original node (which stays "pending" while held in a transition).
521
+ if (latestReadActive) return GlobalQueue.Gt(e);
522
+ let t = context;
523
+ if (t?.dt) t = t.Ct;
524
+ const n = e;
525
+ const i = e.rt;
526
+ const l = i || e;
527
+ // Handle isPending() mode: collect pending state while preserving normal read semantics.
528
+ // Probe mode is suspended while preparing the node so nested reads during a
529
+ // recompute don't collect into the probe.
530
+ if (pendingCheckActive) {
531
+ GlobalQueue.Pt(e, t, l, i);
532
+ } else if (typeof n.xe === "function") {
533
+ prepareComputed(e, false);
534
+ }
535
+ if (!n.xe && l === e && e.be === undefined && e.Ye === undefined && activeTransition === null && currentOptimisticLane === null && !snapshotCaptureActive && true) {
536
+ if (t && tracking) {
537
+ link(e, t);
538
+ // A live mark on a read source flows to the reader (probe reads are
539
+ // excluded: the probe's own collection owns that verdict, and marking
540
+ // the enclosing memo would make an `isPending` wrapper itself pending).
541
+ if (activeAffectsMarks !== 0 && e.P && !pendingCheckActive) (affectsReads ??= []).push(e);
542
+ }
543
+ return !t || e.ge === NOT_PENDING ? e.Ue : e.ge;
544
+ }
545
+ if (t && tracking) {
546
+ link(e, t, pendingCheckActive);
547
+ // Mark inheritance through derivation (see the fast path above), and its
548
+ // transitive half (#2893): a mark-pended owner's sentinel sources flow to
549
+ // the reader like a direct mark — value-transparent reads have no throw
550
+ // to re-establish through, so without this a mid-window recompute sheds
551
+ // pendingness permanently past one derivation level.
552
+ if (activeAffectsMarks !== 0 && !pendingCheckActive) {
553
+ if (e.P) (affectsReads ??= []).push(e);
554
+ if (l.i & STATUS_PENDING) GlobalQueue.I(l, affectsReads ??= []);
555
+ }
556
+ if (l.xe) {
557
+ const n = queueFor(e);
558
+ if (l.qe >= n.Le) {
559
+ markNode(t);
560
+ markHeap(n);
561
+ updateIfNecessary(l);
562
+ }
563
+ const i = l.qe;
564
+ // parent check is shallow, might need to be recursive
565
+ if (i >= t.qe && e.He !== t) {
566
+ t.qe = i + 1;
567
+ }
568
+ }
569
+ }
570
+ // Mark-only pending never suspends the reader (#2886): an affects() mark is
571
+ // a promise of change, not an absence of value, so a derived node whose only
572
+ // pending sources are mark sentinels keeps its real value readable —
573
+ // pendingness reaches readers through verdicts (isPending), not throws.
574
+ // (`activeAffectsMarks` gates the source scan off the mark-free hot path;
575
+ // sentinels can't survive in pending sources past their last release.)
576
+ if (l.i & STATUS_PENDING && !(activeAffectsMarks !== 0 && GlobalQueue.$(l))) {
577
+ if (t && !(stale && l.ve && activeTransition !== l.ve)) {
578
+ // Per-lane suspension lives with the engine (a non-null lane implies it
579
+ // is installed): under a lane, only same-lane pending async without an
580
+ // active override throws.
581
+ if (currentOptimisticLane === null || GlobalQueue.ht(l)) {
582
+ if (!tracking && e !== t) link(e, t);
583
+ throw l.k;
584
+ }
585
+ } else if (t && l !== e && l.i & STATUS_UNINITIALIZED) {
586
+ if (!tracking && e !== t) link(e, t);
587
+ throw l.k;
588
+ } else if (!t && l.i & STATUS_UNINITIALIZED) {
589
+ throw l.k;
590
+ }
591
+ }
592
+ if (e.xe && e.i & STATUS_ERROR) {
593
+ // Only a genuine reactive re-read may retry an errored async source:
594
+ // - tracking: owned/tracked scope only (never events / `untrack` / effect side-effect phase)
595
+ // - !pendingCheckActive: an `isPending` probe observes the error, never refetches
596
+ // - el._time < clock: only on a later cycle than the one the error was found
597
+ if (tracking && !pendingCheckActive && e.Ie < clock) {
598
+ recompute(e);
599
+ return read(e);
600
+ } else throw e.k;
601
+ }
602
+ if (snapshotCaptureActive && t && t.U & CONFIG_IN_SNAPSHOT_SCOPE) {
603
+ const n = e.Ye;
604
+ if (n !== undefined) {
605
+ const i = n === NO_SNAPSHOT ? undefined : n;
606
+ const l = e.ge !== NOT_PENDING ? e.ge : e.Ue;
607
+ if (l !== i) t.u |= REACTIVE_SNAPSHOT_STALE;
608
+ return i;
609
+ }
610
+ }
611
+ if (e.be !== undefined && e.be !== NOT_PENDING) {
612
+ // An active override means the engine is installed (A17: the override IS
613
+ // the value for every reader — that check itself stays right here).
614
+ if (t && stale && GlobalQueue.gt(e)) return e.Ue;
615
+ return e.be;
616
+ }
617
+ // Entanglement gate: a reader recomputing under an optimistic lane that reads
618
+ // a pending mid-transition write sees the committed value. Projection-store
619
+ // manual writes use the firewall's manual-write flag to opt into this path.
620
+ // Async drivers are not under an optimistic lane and so bypass this, reading
621
+ // _pendingValue for correct fetching. The sub is recorded for replay at commit
622
+ // so it re-runs with the new committed view. (Gate details live with the
623
+ // engine — a non-null lane implies it is installed.)
624
+ if (currentOptimisticLane !== null && activeTransition !== null && t !== null && GlobalQueue.Dt(e, l, t)) {
625
+ return e.Ue;
626
+ }
627
+ // In optimistic lane context, return _value for optimistic/lane-assigned signals
628
+ // and for regular signals in stale mode (render effects). Non-stale readers (user
629
+ // effects) see _pendingValue so that latest() and direct reads stay consistent.
630
+ // (The lane-context clause lives with the engine.)
631
+ const u = !t || currentOptimisticLane !== null && GlobalQueue.kt(e, l, t) || e.ge === NOT_PENDING || stale && e.ve && activeTransition !== e.ve ? e.Ue : e.ge;
632
+ // Record that this isPending() probe observed the fresh pending value, so
633
+ // the probe doesn't pair "pending" with the new value (#2831).
634
+ if (pendingCheckActive) GlobalQueue.vt(e, u);
635
+ if (!t && l === e && typeof n.xe === "function" && e.U & CONFIG_AUTO_DISPOSE && !(l.i & STATUS_PENDING) && !e.p) {
636
+ unobserved(e);
637
+ }
638
+ return u;
639
+ }
640
+
641
+ function setSignal(e, t) {
642
+ if (e.ve && activeTransition !== e.ve) globalQueue.initTransition(e.ve);
643
+ // The optimistic write path lives with the engine: only optimisticSignal /
644
+ // optimisticComputed callers and optimistic store nodes carry an
645
+ // _overrideValue slot, and every module that creates one installs the
646
+ // engine first.
647
+ if (e.be !== undefined && !projectionWriteActive) return GlobalQueue.bt(e, t);
648
+ const n = e.ge === NOT_PENDING ? e.Ue : e.ge;
649
+ if (typeof t === "function") t = t(n);
650
+ // Uninitialized check first: the first commit has no previous value, so the
651
+ // user comparator must not run against `undefined` (matches recompute).
652
+ const i = !!(e.i & STATUS_UNINITIALIZED) || !e.Ge || !e.Ge(n, t);
653
+ if (!i) return t;
654
+ if (e.ge === NOT_PENDING) queuePendingNode(e);
655
+ e.ge = t;
656
+ GlobalQueue._e !== null && GlobalQueue._e(e, t);
657
+ e.Ie = clock;
658
+ insertSubs(e);
659
+ schedule();
660
+ return t;
661
+ }
662
+
663
+ /**
664
+ * Suppresses automatic recomputation of `el` until the scheduler drains. Used
665
+ * when a manual write should win over dependency changes queued in the same
666
+ * tick. The MANUAL_WRITE flag is cleared by the pending-node drain; projection
667
+ * computeds don't commit values, but they still need the same end-of-tick
668
+ * cleanup point.
669
+ */ function suppressComputedRecompute(e) {
670
+ deleteFromHeap(e, queueFor(e));
671
+ if (!(e.u & REACTIVE_MANUAL_WRITE) && e.ge === NOT_PENDING) {
672
+ queuePendingNode(e);
673
+ schedule();
674
+ }
675
+ e.u = e.u & -4 | REACTIVE_MANUAL_WRITE;
676
+ }
677
+
678
+ /**
679
+ * User-facing setter for the memo form of `createSignal(fn)`. Behaves like
680
+ * `setSignal`, but also cancels any pending recompute of the memo so the
681
+ * manual value wins over a value that would otherwise be produced by an
682
+ * upstream change in the same tick.
683
+ */ function setMemo(e, t) {
684
+ const n = setSignal(e, t);
685
+ suppressComputedRecompute(e);
686
+ return n;
687
+ }
688
+
689
+ /**
690
+ * Executes `fn` with the given `owner` set as the current owner. Any reactive
691
+ * primitives (`createSignal`, `createMemo`, `createEffect`, `onCleanup`,
692
+ * `cleanup`, etc.) created inside `fn` are attached to that owner, so they
693
+ * are disposed when the owner is disposed.
694
+ *
695
+ * The classic pattern: capture the current owner with `getOwner()` inside a
696
+ * component, then re-enter it from a callback (event handler, async resolve,
697
+ * setTimeout) so disposables created in the callback get cleaned up with the
698
+ * component.
699
+ *
700
+ * @example
701
+ * ```ts
702
+ * function delayed<T>(ms: number, fn: () => T) {
703
+ * const owner = getOwner();
704
+ * setTimeout(() => runWithOwner(owner, fn), ms);
705
+ * }
706
+ * ```
707
+ */ function runWithOwner(e, t) {
708
+ const n = context;
709
+ const i = tracking;
710
+ context = e;
711
+ tracking = false;
712
+ try {
713
+ return t();
714
+ } finally {
715
+ context = n;
716
+ tracking = i;
717
+ }
718
+ }
719
+
720
+ function staleValues(e, t = true) {
721
+ const n = stale;
722
+ stale = t;
723
+ try {
724
+ return e();
725
+ } finally {
726
+ stale = n;
727
+ }
728
+ }
729
+
730
+ /**
731
+ * Invalidates one reactive source, forcing it to re-execute even if its inputs
732
+ * haven't changed.
733
+ *
734
+ * Pass either a Solid-created accessor or a projected store created from
735
+ * `createStore(fn, ...)` / `createProjection(...)`. `refresh()` is a
736
+ * write-like invalidation operation: it does not read the target's value, and
737
+ * refreshing a plain signal accessor is a no-op.
738
+ *
739
+ * Use it to invalidate cached async values (e.g. force a re-fetch) without
740
+ * tearing the consumer down.
741
+ *
742
+ * @example
743
+ * ```ts
744
+ * const user = createMemo(async () => fetch(`/users/${id()}`).then(r => r.json()));
745
+ *
746
+ * // Re-fetch on demand
747
+ * <button onClick={() => refresh(user)}>Reload</button>
748
+ * ```
749
+ */ function refresh(e) {
750
+ const t = e?.[$REFRESH];
751
+ if (!t) {
752
+ return;
753
+ }
754
+ if (typeof t.xe === "function" && !(t.u & (REACTIVE_DISPOSED | REACTIVE_MANUAL_WRITE))) {
755
+ // A refresh with no value-change dirt already queued is a re-ask of the
756
+ // same question: mark it so the recompute classifies any resulting
757
+ // pending window as quiet (not pending). If the node is already dirty
758
+ // from a real input change, the question changed — don't mark.
759
+ // REACTIVE_IN_HEAP counts as dirt: insertSubs schedules subscribers by
760
+ // heap insertion alone (no DIRTY/CHECK flag), so a same-batch value
761
+ // change followed by refresh() must not be laundered into a quiet re-ask.
762
+ if (!(t.u & (REACTIVE_DIRTY | REACTIVE_CHECK | REACTIVE_IN_HEAP))) {
763
+ t.u |= REACTIVE_REASK;
764
+ armReaskClear();
765
+ }
766
+ t.u = t.u & ~REACTIVE_CHECK | REACTIVE_DIRTY;
767
+ insertIntoHeap(t, queueFor(t));
768
+ schedule();
769
+ }
770
+ }
771
+
772
+ export { clearSnapshots, computed, context, createEffectNode, currentOptimisticLane, isEqual, latestReadActive, markSnapshotScope, optimisticComputed, optimisticSignal, pendingCheckActive, prepareComputed, read, recompute, refresh, releaseSnapshotScope, runWithOwner, setContextInternal, setLatestReadActive, setMemo, setPendingCheckActive, setSignal, setSnapshotCapture, signal, snapshotCaptureActive, snapshotSources, stale, staleValues, suppressComputedRecompute, tracking, untrack };