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

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 (57) hide show
  1. package/dist/dev.js +1618 -232
  2. package/dist/node.cjs +2262 -1199
  3. package/dist/prod/boundaries.js +4 -1
  4. package/dist/prod/core/async.js +152 -101
  5. package/dist/prod/core/constants.js +55 -1
  6. package/dist/prod/core/core.js +305 -234
  7. package/dist/prod/core/effect.js +28 -28
  8. package/dist/prod/core/error.js +13 -1
  9. package/dist/prod/core/external.js +2 -2
  10. package/dist/prod/core/graph.js +27 -27
  11. package/dist/prod/core/heap.js +30 -30
  12. package/dist/prod/core/lanes.js +32 -32
  13. package/dist/prod/core/optimistic.js +57 -57
  14. package/dist/prod/core/owner.js +34 -34
  15. package/dist/prod/core/scheduler.js +346 -152
  16. package/dist/prod/core/verdict.js +122 -65
  17. package/dist/prod/index.js +3 -3
  18. package/dist/prod/map.js +106 -106
  19. package/dist/prod/signals.js +321 -26
  20. package/dist/prod/store/next/optimistic.js +363 -151
  21. package/dist/prod/store/next/patch.js +6 -6
  22. package/dist/prod/store/next/projection.js +25 -21
  23. package/dist/prod/store/next/store.js +223 -113
  24. package/dist/prod/store/store.js +2 -2
  25. package/dist/types/core/async.d.ts +2 -0
  26. package/dist/types/core/attribution-hooks.d.ts +11 -0
  27. package/dist/types/core/attribution.d.ts +57 -4
  28. package/dist/types/core/constants.d.ts +54 -0
  29. package/dist/types/core/core.d.ts +19 -20
  30. package/dist/types/core/dev.d.ts +8 -2
  31. package/dist/types/core/error.d.ts +9 -0
  32. package/dist/types/core/index.d.ts +2 -2
  33. package/dist/types/core/scheduler.d.ts +39 -0
  34. package/dist/types/core/types.d.ts +12 -0
  35. package/dist/types/index.d.ts +3 -3
  36. package/dist/types/signals.d.ts +108 -11
  37. package/dist/types/store/next/optimistic.d.ts +13 -10
  38. package/dist/types/store/next/projection.d.ts +1 -1
  39. package/dist/types/store/next/store.d.ts +22 -0
  40. package/dist/types/store/next/target.d.ts +25 -0
  41. package/dist/types-cjs/core/async.d.cts +2 -0
  42. package/dist/types-cjs/core/attribution-hooks.d.cts +11 -0
  43. package/dist/types-cjs/core/attribution.d.cts +57 -4
  44. package/dist/types-cjs/core/constants.d.cts +54 -0
  45. package/dist/types-cjs/core/core.d.cts +19 -20
  46. package/dist/types-cjs/core/dev.d.cts +8 -2
  47. package/dist/types-cjs/core/error.d.cts +9 -0
  48. package/dist/types-cjs/core/index.d.cts +2 -2
  49. package/dist/types-cjs/core/scheduler.d.cts +39 -0
  50. package/dist/types-cjs/core/types.d.cts +12 -0
  51. package/dist/types-cjs/index.d.cts +3 -3
  52. package/dist/types-cjs/signals.d.cts +108 -11
  53. package/dist/types-cjs/store/next/optimistic.d.cts +13 -10
  54. package/dist/types-cjs/store/next/projection.d.cts +1 -1
  55. package/dist/types-cjs/store/next/store.d.cts +22 -0
  56. package/dist/types-cjs/store/next/target.d.cts +25 -0
  57. package/package.json +1 -1
@@ -1,6 +1,6 @@
1
- import { handleAsync, clearStatus, parkLoadingWindow, notifyStatus, settleErroredDependents } from "./async.js";
1
+ import { releaseFlightTeardown, handleAsync, clearStatus, parkLoadingWindow, notifyStatus, settlePendingSource, settleErroredDependents } from "./async.js";
2
2
 
3
- import { EFFECT_TRACKED, REACTIVE_OPTIMISTIC_DIRTY, CONFIG_OPTIMISTIC, NOT_PENDING, STATUS_UNINITIALIZED, STATUS_ERROR, REACTIVE_REASK, REACTIVE_RECOMPUTING_DEPS, CONFIG_SYNC, CONFIG_HAS_LANE, STATUS_PENDING, REACTIVE_MISSED_WAKE, REACTIVE_NONE, REACTIVE_SNAPSHOT_STALE, unwrapOverride, OVERRIDE_UNDEFINED, CONFIG_HAS_COMPANIONS, REACTIVE_LAZY, REACTIVE_DISPOSED, CONFIG_AUTO_DISPOSE, CONFIG_CHILDREN_FORBIDDEN, REACTIVE_CHECK, REACTIVE_DIRTY, REACTIVE_IN_HEAP, REACTIVE_IN_HEAP_HEIGHT, defaultContext, CONFIG_IN_SNAPSHOT_SCOPE, CONFIG_TRANSPARENT, CONFIG_OWNED_WRITE, CONFIG_NO_SNAPSHOT, $REFRESH, REACTIVE_MANUAL_WRITE, CONFIG_FW_CHILDREN, NO_SNAPSHOT, CONFIG_HAS_SNAPSHOT, STORE_SNAPSHOT_PROPS, EFFECT_USER } from "./constants.js";
3
+ import { EFFECT_TRACKED, REACTIVE_OPTIMISTIC_DIRTY, CONFIG_OPTIMISTIC, NOT_PENDING, STATUS_UNINITIALIZED, STATUS_ERROR, REACTIVE_REASK, REACTIVE_RECOMPUTING_DEPS, CONFIG_SYNC, CONFIG_HAS_LANE, STATUS_PENDING, REACTIVE_MISSED_WAKE, REACTIVE_NONE, REACTIVE_SNAPSHOT_STALE, unwrapOverride, CONFIG_DIRECT_COMMIT, OVERRIDE_UNDEFINED, CONFIG_AUTHORITATIVE_OBSERVED, CONFIG_HAS_COMPANIONS, REACTIVE_LAZY, REACTIVE_DISPOSED, CONFIG_AUTO_DISPOSE, CONFIG_CHILDREN_FORBIDDEN, CONFIG_FRESH_READ, CONFIG_AUTHORITATIVE_READ, 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, CONFIG_FW_CHILDREN, NO_SNAPSHOT, CONFIG_HAS_SNAPSHOT, REACTIVE_MANUAL_WRITE, STORE_SNAPSHOT_PROPS, EFFECT_USER } from "./constants.js";
4
4
 
5
5
  import { NotReadyError } from "./error.js";
6
6
 
@@ -8,15 +8,15 @@ import { trimStaleDeps, link, dormantNodes } from "./graph.js";
8
8
 
9
9
  import { deleteFromHeap, queueFor, insertIntoHeapHeight, enqueueSub, markNode, markHeap, insertIntoHeap } from "./heap.js";
10
10
 
11
- import { GlobalQueue, activeTransition, globalQueue, clock, insertSubs, queuePendingNode, runInTransition, schedule, notifyEpoch, dirtyQueue, bumpNotifyEpoch, projectionWriteActive, reaskArmed, armReaskClear } from "./scheduler.js";
11
+ import { GlobalQueue, bumpNotifyEpoch, activeTransition, globalQueue, clock, insertSubs, queuePendingNode, runInTransition, schedule, notifyEpoch, dirtyQueue, projectionWriteActive, reaskArmed, armReaskClear } from "./scheduler.js";
12
12
 
13
13
  import "./invariants.js";
14
14
 
15
15
  import { disposeChildren, markDisposal, inheritId } from "./owner.js";
16
16
 
17
- GlobalQueue.Ce = recompute;
17
+ GlobalQueue.Fe = recompute;
18
18
 
19
- GlobalQueue.Fe = disposeChildren;
19
+ GlobalQueue.He = disposeChildren;
20
20
 
21
21
  let tracking = false;
22
22
 
@@ -48,7 +48,7 @@ let snapshotSources = null;
48
48
 
49
49
  function ownerInSnapshotScope(e) {
50
50
  while (e) {
51
- if (e.He) return true;
51
+ if (e.Ve) return true;
52
52
  e = e.ke;
53
53
  }
54
54
  return false;
@@ -60,20 +60,20 @@ function setSnapshotCapture(e) {
60
60
  }
61
61
 
62
62
  function markSnapshotScope(e) {
63
- e.He = true;
63
+ e.Ve = true;
64
64
  }
65
65
 
66
66
  function releaseSnapshotScope(e) {
67
- e.He = false;
67
+ e.Ve = false;
68
68
  releaseSubtree(e);
69
69
  schedule();
70
70
  }
71
71
 
72
72
  function releaseSubtree(e) {
73
- let t = e.ve;
73
+ let t = e.xe;
74
74
  while (t) {
75
- if (t.He) {
76
- t = t.Ve;
75
+ if (t.Ve) {
76
+ t = t.Le;
77
77
  continue;
78
78
  }
79
79
  if (t.oe) {
@@ -82,19 +82,19 @@ function releaseSubtree(e) {
82
82
  if (e.ie & REACTIVE_SNAPSHOT_STALE) {
83
83
  e.ie &= ~REACTIVE_SNAPSHOT_STALE;
84
84
  e.ie |= REACTIVE_DIRTY;
85
- if (dirtyQueue.xe > e.Le) dirtyQueue.xe = e.Le;
85
+ if (dirtyQueue.Qe > e.Me) dirtyQueue.Qe = e.Me;
86
86
  insertIntoHeap(e, dirtyQueue);
87
87
  }
88
88
  }
89
89
  releaseSubtree(t);
90
- t = t.Ve;
90
+ t = t.Le;
91
91
  }
92
92
  }
93
93
 
94
94
  function clearSnapshots() {
95
95
  if (snapshotSources) {
96
96
  for (const e of snapshotSources) {
97
- delete e.o?.Qe;
97
+ delete e.o?.We;
98
98
  // StoreNode targets share one pre-initialized hidden class (see
99
99
  // createStoreProxy) — assign undefined instead of deleting, and only
100
100
  // when present so signal-node sources don't grow the field.
@@ -108,48 +108,63 @@ function clearSnapshots() {
108
108
  function recompute(e, t = false) {
109
109
  // §12d: any recompute can clean a marked subscriber — invalidate skips.
110
110
  bumpNotifyEpoch();
111
- const n = e.Re;
111
+ const n = e.ge;
112
112
  if (!t) {
113
- if (e._e && (!n || activeTransition) && activeTransition !== e._e) globalQueue.initTransition(e._e);
113
+ if (e.Ae && (!n || activeTransition) && activeTransition !== e.Ae) globalQueue.initTransition(e.Ae);
114
114
  deleteFromHeap(e, queueFor(e));
115
- if (e.o !== null) e.o.Ee = null;
115
+ if (e.o !== null) {
116
+ e.o.Ie = null;
117
+ // Supersede is where an iterator flight dies (#3122): close it now.
118
+ // Its cleanup(close) registration may sit in a zombie-deferred
119
+ // disposal list that a held transition only drains when the
120
+ // SUPERSEDING flight settles — cancellation must not wait for the
121
+ // work that replaced it. Idempotent with the cleanup-channel close.
122
+ releaseFlightTeardown(e);
123
+ }
116
124
  // Tracked effects run after finalizePureQueue, so dispose immediately instead of deferring
117
- if (e._e || n === EFFECT_TRACKED) disposeChildren(e); else if (e.ve !== null || e.he !== null) {
125
+ if (e.Ae || n === EFFECT_TRACKED) disposeChildren(e); else if (e.xe !== null || e.Ge !== null) {
118
126
  markDisposal(e);
119
127
  const t = ext(e);
120
- t.We = e.he;
121
- t.qe = e.ve;
122
- e.he = null;
123
- e.ve = null;
124
- e.Me = 0;
128
+ t.qe = e.Ge;
129
+ t.Ye = e.xe;
130
+ e.Ge = null;
131
+ e.xe = null;
132
+ e.Ze = 0;
125
133
  } else ;
126
134
  }
127
135
  let i = !!(e.ie & REACTIVE_OPTIMISTIC_DIRTY);
128
- const u = (e.T & CONFIG_OPTIMISTIC) !== 0 && e.o?.De !== NOT_PENDING && e.o?.De !== undefined;
136
+ const u = (e.T & CONFIG_OPTIMISTIC) !== 0 && e.o?.Pe !== NOT_PENDING && e.o?.Pe !== undefined;
129
137
  const l = !!(e.S & STATUS_UNINITIALIZED);
130
138
  // Outgoing error, captured before the compute clears status: if this run
131
139
  // recovers to an unchanged value, dependents still holding this object must
132
140
  // be swept (settleErroredDependents, #2949).
133
141
  const o = e.S & STATUS_ERROR ? e.o?._ : undefined;
142
+ // Pending SOURCE-hood, captured before the compute clears status: a node
143
+ // whose own flight parked dependents self-registers in _pendingSources
144
+ // (notifyStatus, isSource). If this recompute supersedes that flight and
145
+ // settles synchronously, those dependents settle HERE — asyncWrite's
146
+ // settlePendingSource walk never runs for a landing that was preempted
147
+ // (#3181).
148
+ const s = e.o?.le?.has(e);
134
149
  // Re-ask classification lives in the verdict module; capture the flag before
135
150
  // the recompute wipes _flags below.
136
- const s = (e.ie & REACTIVE_REASK) !== 0;
151
+ const a = (e.ie & REACTIVE_REASK) !== 0;
137
152
  // Captured before the compute clears it on a sync landing: if that landing
138
153
  // is transition-held below, the window must stay open until the hold
139
154
  // commits (commitPendingNode) — a closed window plus a held value reads as
140
155
  // a pending frame to live observers of the verdict (#2990).
141
- const a = e.Ie;
142
- const r = context;
156
+ const r = e.Ne;
157
+ const c = context;
143
158
  context = e;
144
- e.Ye = null;
145
- e.Ze++;
159
+ e.je = null;
160
+ e.Ke++;
146
161
  e.ie = REACTIVE_RECOMPUTING_DEPS;
147
162
  e.Te = clock;
148
- let c = e.Pe === NOT_PENDING ? e.be : e.Pe;
149
- let _ = e.Le;
150
- let f = false;
151
- let N = tracking;
152
- let E = currentOptimisticLane;
163
+ let _ = e.Re === NOT_PENDING ? e.be : e.Re;
164
+ let f = e.Me;
165
+ let I = false;
166
+ let E = tracking;
167
+ let N = currentOptimisticLane;
153
168
  tracking = true;
154
169
  // A computed's fn establishes its OWN dependencies, so it must never run
155
170
  // inside a latest() read window: read() short-circuits through the
@@ -157,54 +172,54 @@ function recompute(e, t = false) {
157
172
  // computed) inside latest(fn) came out permanently dependency-less (#2926).
158
173
  // latestRead() already suspends the flag for its pull-recomputes; this
159
174
  // covers creation-time computes and flushes that run inside the window.
160
- const I = latestReadActive;
175
+ const T = latestReadActive;
161
176
  latestReadActive = false;
162
177
  // Lane posture lives with the engine: OPTIMISTIC_DIRTY is only ever set by
163
178
  // engine-driven paths, and _optimisticNodes is only pushed by
164
179
  // _optimisticWrite, so the hook is installed whenever either gate holds.
165
180
  if (i) {
166
- const t = GlobalQueue.je(e, true);
181
+ const t = GlobalQueue.Be(e, true);
167
182
  if (t) currentOptimisticLane = t;
168
183
  // `false` = wake-only lane demotion: recompute plain so a mid-tick
169
184
  // latest()/isPending() pull stages instead of direct-committing (#3009).
170
185
  // The predicate lives with the engine (recomputeLane).
171
186
  else if (t === false) i = false;
172
- } else if (activeTransition && !t && activeTransition.Ke.length) {
187
+ } else if (activeTransition && !t && activeTransition.ze.length) {
173
188
  // Lane adoption: parent-deeper-than-owned-child can run before its OPT-dirty
174
189
  // child propagates. Walk deps once and inherit the OPT lane so this node
175
190
  // recomputes under the right posture and propagates correctly.
176
- const t = GlobalQueue.je(e, false);
191
+ const t = GlobalQueue.Be(e, false);
177
192
  if (t) {
178
193
  i = true;
179
194
  currentOptimisticLane = t;
180
195
  }
181
196
  }
182
- const d = n && n !== EFFECT_USER;
183
- const T = stale;
184
- if (d) stale = true;
197
+ const S = n && n !== EFFECT_USER;
198
+ const d = stale;
199
+ if (S) stale = true;
185
200
  try {
186
201
  if (!false && e.T & CONFIG_SYNC) {
187
- c = e.oe(c);
188
- if (e.o !== null) e.o.Ee = null;
189
- e.Ie = false;
202
+ _ = e.oe(_);
203
+ if (e.o !== null) e.o.Ie = null;
204
+ e.Ne = false;
190
205
  } else {
191
206
  // Snapshot `_inFlight` so we can detect whether `_fn` self-registered an async
192
207
  // subscription (e.g. `createProjection` calls `handleAsync` from inside its body
193
208
  // with a setter callback). In that case, the outer `handleAsync` call below would
194
209
  // clobber the fresh subscription, so we skip it and let the internally-registered
195
210
  // iteration drive updates.
196
- const t = e.o?.Ee;
197
- const n = e.oe(c);
211
+ const t = e.o?.Ie;
212
+ const n = e.oe(_);
198
213
  const i = typeof n === "object" && n !== null;
199
- const u = e.o?.Ee !== t;
200
- c = u || !i ? n : handleAsync(e, n);
214
+ const u = e.o?.Ie !== t;
215
+ _ = u || !i ? n : handleAsync(e, n);
201
216
  if (!u && !i) {
202
- if (e.o !== null) e.o.Ee = null;
217
+ if (e.o !== null) e.o.Ie = null;
203
218
  // A sync (non-object) return is the first real answer; async-shaped
204
219
  // results clear inside handleAsync at their own landing points, and a
205
220
  // self-registered flight (inFlightChanged — projections) clears when
206
221
  // its internal handleAsync lands.
207
- e.Ie = false;
222
+ e.Ne = false;
208
223
  }
209
224
  }
210
225
  // On a status-free node clearStatus is a guaranteed no-op: every field
@@ -214,10 +229,10 @@ function recompute(e, t = false) {
214
229
  if (e.S !== 0 || e.o !== null) clearStatus(e, t);
215
230
  // _optimisticLane is only ever assigned by engine paths (CONFIG_HAS_LANE
216
231
  // is their sticky presence mark).
217
- if (e.T & CONFIG_HAS_LANE && e.o?.Be) GlobalQueue.ze(e);
232
+ if (e.T & CONFIG_HAS_LANE && e.o?.Je) GlobalQueue.Xe(e);
218
233
  } catch (t) {
219
234
  const n = t instanceof NotReadyError;
220
- if (n && e.Ie) {
235
+ if (n && e.Ne) {
221
236
  // Loading window with an unready sync dependency: register for the
222
237
  // source's settle (the settlePendingSource walk runs off
223
238
  // _pendingSources + _blocked alone) but take NO read-visible pending
@@ -233,30 +248,33 @@ function recompute(e, t = false) {
233
248
  let i = false;
234
249
  if (n) {
235
250
  ext(e).fe = true;
236
- if (GlobalQueue.Je !== null) i = GlobalQueue.Je(e, s);
251
+ if (GlobalQueue.et !== null) i = GlobalQueue.et(e, a);
237
252
  }
238
- notifyStatus(e, n ? STATUS_PENDING : STATUS_ERROR, t, undefined, n ? e.o?.Be : undefined);
253
+ notifyStatus(e, n ? STATUS_PENDING : STATUS_ERROR, t, undefined, n ? e.o?.Je : undefined);
254
+ // The replacement source is fully propagated now. If no new flight
255
+ // re-owned self, retire the superseded flight and its dependent copies.
256
+ if (n && s && !e.o?.Ie) settlePendingSource(e);
239
257
  if (i) GlobalQueue.k(e);
240
258
  }
241
259
  } finally {
242
- tracking = N;
243
- latestReadActive = I;
244
- if (d) stale = T;
260
+ tracking = E;
261
+ latestReadActive = T;
262
+ if (S) stale = d;
245
263
  // Consume the missed-wake latch (#3037, set by insertSubs): a dep write
246
264
  // landed beneath this pass on a link it had already validated. The wipe
247
265
  // below must not key off DIRTY/CHECK — the read-time pull protocol
248
266
  // (markNode(c) in read()) marks the running node as part of ordinary
249
267
  // bookkeeping, and those marks are correctly discarded here.
250
- f = (e.ie & REACTIVE_MISSED_WAKE) !== 0;
268
+ I = (e.ie & REACTIVE_MISSED_WAKE) !== 0;
251
269
  e.ie = REACTIVE_NONE | (t ? e.ie & REACTIVE_SNAPSHOT_STALE : 0);
252
- context = r;
270
+ context = c;
253
271
  }
254
272
  if (!e.o?._) {
255
273
  trimStaleDeps(e);
256
- const s = u ? unwrapOverride(e.o?.De) : e.Pe === NOT_PENDING ? e.be : e.Pe;
257
- let r = false;
274
+ const a = u ? unwrapOverride(e.o?.Pe) : e.Re === NOT_PENDING ? e.be : e.Re;
275
+ let c = false;
258
276
  try {
259
- r = !n && l || !e.Ue || !e.Ue(s, c);
277
+ c = !n && l || !e.pe || !e.pe(a, _);
260
278
  } catch (t) {
261
279
  // A throwing user comparator is an error of this node's computation.
262
280
  // Route it through the same status path as a compute-phase throw so
@@ -269,53 +287,63 @@ function recompute(e, t = false) {
269
287
  // its runner — happen here instead. `!create` matches the previous `initialized`
270
288
  // gate: the explicit recompute(node, true) inside effect() does not enqueue, so
271
289
  // effect() can call its runner synchronously for the first run.
272
- if (n && r) {
273
- e.Xe = !e.o?._;
290
+ if (n && c) {
291
+ e.tt = !e.o?._;
274
292
  // Reuse one bound runner per effect — runEffect no-ops on a stale
275
293
  // `_modified`, so re-enqueueing the same function is harmless.
276
- if (!t) e.C.enqueue(n, e.et ??= GlobalQueue.tt.bind(null, e));
294
+ if (!t) e.C.enqueue(n, e.nt ??= GlobalQueue.it.bind(null, e));
277
295
  }
278
- if (e.o?._) ; else if (r) {
279
- const l = u ? e.o?.De : undefined;
296
+ if (e.o?._) ; else if (c) {
297
+ const l = u ? e.o?.Pe : undefined;
280
298
  if (t ||
281
299
  // Plain sync flush (no transition on either side) commits effect
282
300
  // values directly — the pending round-trip (queuePendingNode +
283
301
  // commitPendingNodes) exists to sequence transition reveals, and
284
302
  // paying it per effect on the plain path is pure overhead.
285
- n && (activeTransition !== e._e || activeTransition === null) || i) {
286
- e.be = c;
303
+ // DIRECT_COMMIT effects (resolve/until) commit directly even under
304
+ // their own held transition: their applies deliver on a microtask,
305
+ // not the stashed queues, so a staged value would hand the immediate
306
+ // apply stale state — see CONFIG_DIRECT_COMMIT.
307
+ n && (activeTransition !== e.Ae || activeTransition === null || e.T & CONFIG_DIRECT_COMMIT) || i) {
308
+ e.be = _;
287
309
  // Lane-propagated correction: upstream data is fresh, correct the
288
310
  // override unconditionally. The direct _value commit is the lane's
289
311
  // own reveal schedule; drop any superseded older hold so its queued
290
312
  // commit can't clobber the fresh value.
291
313
  if (u && i) {
292
- ext(e).De = c === undefined ? OVERRIDE_UNDEFINED : c;
293
- e.Pe = NOT_PENDING;
314
+ ext(e).Pe = _ === undefined ? OVERRIDE_UNDEFINED : _;
315
+ e.Re = NOT_PENDING;
294
316
  }
295
317
  } else {
296
- e.Pe = c;
318
+ e.Re = _;
297
319
  // A window landing that gets held re-opens the window until the hold
298
320
  // commits — the verdict's held-value branch is window-gated (#2990).
299
- if (a) e.Ie = true;
321
+ if (r) e.Ne = true;
300
322
  // Transition-held sync recompute is a write path like setSignal/asyncWrite,
301
323
  // so sync derivations of held sources stay visible to isPending()/latest()
302
324
  // (#2831). Both companion writes are transition-scoped (optimistic) and
303
325
  // auto-revert/re-derive at commit. Skipped for plain flushes where the
304
326
  // pending value commits before effects run.
305
- if ((activeTransition || e._e) && GlobalQueue.Oe !== null) GlobalQueue.Oe(e, c);
327
+ if ((activeTransition || e.Ae) && GlobalQueue.Ue !== null) GlobalQueue.Ue(e, _);
306
328
  }
307
329
  // insertSubs only walks _subs (no scheduling of its own), so a
308
330
  // subscriber-less node has nothing to notify.
309
- if (e.u !== null && (!u || i || e.o?.De !== l)) insertSubs(e, i || u);
331
+ if (e.u !== null && (!u || i || e.o?.Pe !== l)) insertSubs(e, i || u);
310
332
  } else if (u) {
311
333
  // Unchanged value (equals the override) recomputed while the override
312
334
  // is active: _value may still be stale, so hold the authoritative value
313
335
  // for commit on its own transition's schedule — invisibly (A17/A18).
314
- if (e.Pe === NOT_PENDING) queuePendingNode(e);
315
- e.Pe = c;
316
- if (a) e.Ie = true;
336
+ if (e.Re === NOT_PENDING) queuePendingNode(e);
337
+ e.Re = _;
338
+ if (r) e.Ne = true;
317
339
  // see the held branch above (#2990)
318
- } else if (e.Le != _) {
340
+ // A authoritative-view reader (until()) observed this node past its
341
+ // override — and "authoritative arrival equal to the override" is
342
+ // exactly the acknowledgment it waits for. Wake those readers only;
343
+ // A17 silence holds for every ordinary subscriber. (Hook installed by
344
+ // until(), the only setter of the gating bit.)
345
+ if (e.T & CONFIG_AUTHORITATIVE_OBSERVED) GlobalQueue.he(e);
346
+ } else if (e.Me != f) {
319
347
  for (let t = e.u; t !== null; t = t.ae) {
320
348
  insertIntoHeapHeight(t.ce, queueFor(t.ce));
321
349
  }
@@ -325,23 +353,27 @@ function recompute(e, t = false) {
325
353
  // in an errored run and may sit on stale commits (#2949). Changed-value
326
354
  // recoveries ride insertSubs above; a comparator throw re-errored the node
327
355
  // (el._x?._error re-set), so this only runs on a genuinely clean recovery.
328
- if (o !== undefined && !r && !e.o?._) settleErroredDependents(e, o);
356
+ if (o !== undefined && !c && !e.o?._) settleErroredDependents(e, o);
357
+ // #3181: a synchronous settle supersedes the old landing callback, so
358
+ // recompute owns its pending-source sweep. An uninitialized node without
359
+ // a replacement source still has no truth to reveal and must stay parked.
360
+ if (s && !(e.S & (STATUS_PENDING | STATUS_UNINITIALIZED))) settlePendingSource(e);
329
361
  }
330
- currentOptimisticLane = E;
331
- const S = e.Pe !== NOT_PENDING || e.o !== null && (e.o.qe !== null || e.o.We !== null) || (e.S & (STATUS_PENDING | STATUS_UNINITIALIZED)) !== 0;
362
+ currentOptimisticLane = N;
363
+ const A = e.Re !== NOT_PENDING || e.o !== null && (e.o.Ye !== null || e.o.qe !== null) || (e.S & (STATUS_PENDING | STATUS_UNINITIALIZED)) !== 0;
332
364
  // Override-covered holds (hasOverride) always queue: their commit belongs
333
365
  // to their own transition's schedule (A18 re-rule) and is unobservable
334
366
  // under the override (A17). Revert no longer commits anything, so an
335
367
  // unqueued covered hold would leak (INV-7) once the revert clears
336
368
  // _transition.
337
- S && (!t || e.S & STATUS_PENDING) && (!e._e || u) && queuePendingNode(e);
338
- e._e && n && activeTransition !== e._e && runInTransition(e._e, () => recompute(e));
369
+ A && (!t || e.S & STATUS_PENDING) && (!e.Ae || u) && queuePendingNode(e);
370
+ e.Ae && n && activeTransition !== e.Ae && runInTransition(e.Ae, () => recompute(e));
339
371
  // Missed-wake reschedule (see the finally above): values this pass read
340
372
  // before the nested commit are stale, so run again now that the heap will
341
373
  // accept the node. Equality gates stop same-value landings from cascading,
342
374
  // and a re-run only latches again if another nested commit changes a dep
343
375
  // beneath it — convergent unless deps genuinely keep changing.
344
- if (f) {
376
+ if (I) {
345
377
  enqueueSub(e);
346
378
  schedule();
347
379
  }
@@ -352,11 +384,13 @@ function updateIfNecessary(e) {
352
384
  // (_depsTail/_depGen) is live, and a nested recompute would corrupt it.
353
385
  // A mid-pass mark stays latched for recompute's own tail to reschedule
354
386
  // (#3037); readers meanwhile serve the values the pass has so far.
355
- if (e.ie & REACTIVE_RECOMPUTING_DEPS) return;
387
+ // Never recompute a DISPOSED node either: recompute rewrites _flags and
388
+ // would resurrect it (#2983) — readers serve its last value.
389
+ if (e.ie & (REACTIVE_RECOMPUTING_DEPS | REACTIVE_DISPOSED)) return;
356
390
  if (e.ie & REACTIVE_CHECK) {
357
- for (let t = e.nt; t; t = t.it) {
358
- const n = t.ut;
359
- const i = n.lt || n;
391
+ for (let t = e.ut; t; t = t.lt) {
392
+ const n = t.ot;
393
+ const i = n.st || n;
360
394
  if (i.oe) {
361
395
  updateIfNecessary(i);
362
396
  }
@@ -365,7 +399,7 @@ function updateIfNecessary(e) {
365
399
  }
366
400
  }
367
401
  }
368
- if (e.ie & (REACTIVE_DIRTY | REACTIVE_OPTIMISTIC_DIRTY) || e.o?._ && e.Te < clock && !e.o?.Ee) {
402
+ if (e.ie & (REACTIVE_DIRTY | REACTIVE_OPTIMISTIC_DIRTY) || e.o?._ && e.Te < clock && !e.o?.Ie) {
369
403
  recompute(e);
370
404
  }
371
405
  e.ie = e.ie & (REACTIVE_SNAPSHOT_STALE | REACTIVE_IN_HEAP | REACTIVE_IN_HEAP_HEIGHT);
@@ -380,40 +414,40 @@ function computed(e, t) {
380
414
  const u = {
381
415
  id: inheritId(t, n, context),
382
416
  T: (n ? CONFIG_TRANSPARENT : 0) | (t?.ownedWrite ? CONFIG_OWNED_WRITE : 0) | (!context || t?.lazy ? CONFIG_AUTO_DISPOSE : 0) | (t?.sync ? CONFIG_SYNC : 0) | (t?.H ? CONFIG_NO_SNAPSHOT : 0) | (snapshotCaptureActive && ownerInSnapshotScope(context) ? CONFIG_IN_SNAPSHOT_SCOPE : 0),
383
- Ue: t?.equals != null ? t.equals : isEqual,
384
- he: null,
417
+ pe: t?.equals ?? isEqual,
418
+ Ge: null,
385
419
  C: context?.C ?? globalQueue,
386
420
  we: context?.we ?? defaultContext,
387
- Me: 0,
421
+ Ze: 0,
388
422
  oe: e,
389
423
  be: i ? t.loadingValue : undefined,
390
- Le: 0,
391
- ot: undefined,
392
- st: null,
393
- nt: null,
394
- Ye: null,
395
- Ze: 0,
424
+ Me: 0,
425
+ rt: undefined,
426
+ ct: null,
427
+ ut: null,
428
+ je: null,
429
+ Ke: 0,
396
430
  u: null,
397
- rt: null,
431
+ _t: null,
398
432
  ke: context,
399
- Ve: null,
400
- ct: null,
401
- ve: null,
433
+ Le: null,
434
+ ft: null,
435
+ xe: null,
402
436
  ie: t?.lazy ? REACTIVE_LAZY : REACTIVE_NONE,
403
437
  // A loadingValue node is born committed: commit #0 is already in _value.
404
438
  S: i ? 0 : STATUS_UNINITIALIZED,
405
439
  Te: clock,
406
- Pe: NOT_PENDING,
407
- _e: null,
408
- _t: -1,
409
- Ie: i,
440
+ Re: NOT_PENDING,
441
+ Ae: null,
442
+ It: -1,
443
+ Ne: i,
410
444
  // Cold machinery (async/transition/optimistic/verdict slots) lives one
411
445
  // hop away in the lazily-allocated extension — the core literal MUST
412
446
  // stay under V8's in-object boundary (§12: past ~39 fields every
413
447
  // allocation spills to a backing store and creation cost ~4x's).
414
448
  o: null
415
449
  };
416
- if (t?.unobserved) ext(u).ft = t.unobserved;
450
+ if (t?.unobserved) ext(u).Et = t.unobserved;
417
451
  setupComputedNode(u, t);
418
452
  return u;
419
453
  }
@@ -423,25 +457,26 @@ function computed(e, t) {
423
457
  * this; hot paths read `el._x?._field` gated by the _config presence bits.
424
458
  * Never call ext() just to store a field's default. */ function ext(e) {
425
459
  return e.o ??= {
426
- De: undefined,
460
+ Pe: undefined,
427
461
  Nt: undefined,
428
- Be: undefined,
429
- Ge: undefined,
430
- ge: undefined,
431
- Et: undefined,
462
+ Je: undefined,
463
+ ye: undefined,
464
+ Ce: undefined,
465
+ Tt: undefined,
432
466
  t: 0,
467
+ Ie: null,
433
468
  Ee: null,
434
469
  _: undefined,
435
470
  fe: undefined,
436
471
  le: undefined,
437
472
  h: undefined,
438
- pe: false,
473
+ De: false,
439
474
  i: null,
440
- ft: undefined,
441
- Qe: undefined,
442
- We: null,
475
+ Et: undefined,
476
+ We: undefined,
443
477
  qe: null,
444
- It: undefined
478
+ Ye: null,
479
+ St: undefined
445
480
  };
446
481
  }
447
482
 
@@ -454,39 +489,39 @@ function computed(e, t) {
454
489
  const l = u?.transparent ?? false;
455
490
  const o = {
456
491
  id: inheritId(u, l, context),
457
- T: (l ? CONFIG_TRANSPARENT : 0) | (u?.ownedWrite ? CONFIG_OWNED_WRITE : 0) | (u?.sync ? CONFIG_SYNC : 0) | (snapshotCaptureActive && ownerInSnapshotScope(context) ? CONFIG_IN_SNAPSHOT_SCOPE : 0),
458
- Ue: false,
459
- he: null,
492
+ T: (l ? CONFIG_TRANSPARENT : 0) | (u?.ownedWrite ? CONFIG_OWNED_WRITE : 0) | (u?.sync ? CONFIG_SYNC : 0) | (u?.dt ?? 0) | (snapshotCaptureActive && ownerInSnapshotScope(context) ? CONFIG_IN_SNAPSHOT_SCOPE : 0),
493
+ pe: false,
494
+ Ge: null,
460
495
  C: context?.C ?? globalQueue,
461
496
  we: context?.we ?? defaultContext,
462
- Me: 0,
497
+ Ze: 0,
463
498
  oe: e,
464
499
  be: undefined,
465
- Le: 0,
466
- ot: undefined,
467
- st: null,
468
- nt: null,
469
- Ye: null,
470
- Ze: 0,
500
+ Me: 0,
501
+ rt: undefined,
502
+ ct: null,
503
+ ut: null,
504
+ je: null,
505
+ Ke: 0,
471
506
  u: null,
472
- rt: null,
507
+ _t: null,
473
508
  ke: context,
474
- Ve: null,
475
- ct: null,
476
- ve: null,
509
+ Le: null,
510
+ ft: null,
511
+ xe: null,
477
512
  ie: REACTIVE_LAZY,
478
513
  S: STATUS_UNINITIALIZED,
479
514
  Te: clock,
480
- Pe: NOT_PENDING,
481
- _e: null,
482
- _t: -1,
483
- Ie: false,
484
- Xe: false,
485
- dt: undefined,
486
- Tt: t,
487
- St: n,
515
+ Re: NOT_PENDING,
516
+ Ae: null,
517
+ It: -1,
518
+ Ne: false,
519
+ tt: false,
488
520
  At: undefined,
489
- Re: i,
521
+ Ot: t,
522
+ Ct: n,
523
+ Rt: undefined,
524
+ ge: i,
490
525
  o: null
491
526
  };
492
527
  // Effects dispatch status through the SHARED notifier (statusNotifierOf,
@@ -494,7 +529,7 @@ function computed(e, t) {
494
529
  // allocation on EVERY effect at creation (an alloc + 19 field stores,
495
530
  // +23% effect creation, caught by the creation benches). Only genuinely
496
531
  // per-node channels (boundaries) live on _x.
497
- if (u?.unobserved) ext(o).ft = u.unobserved;
532
+ if (u?.unobserved) ext(o).Et = u.unobserved;
498
533
  setupComputedNode(o, lazyOptions);
499
534
  return o;
500
535
  }
@@ -515,10 +550,9 @@ function setEffectStatusNotify(e) {
515
550
  * the field) fall back to the shared notifier. Presence doubles as the
516
551
  * "display consumer" membership test in the status walks, exactly as the
517
552
  * per-node field did when every effect carried one. */ function statusNotifierOf(e) {
518
- const t = e.o;
519
- const n = t !== null && t !== undefined ? t.h : undefined;
520
- if (n !== undefined) return n;
521
- return e.Re ? effectStatusNotify ?? undefined : undefined;
553
+ const t = e.o?.h;
554
+ if (t !== undefined) return t;
555
+ return e.ge ? effectStatusNotify ?? undefined : undefined;
522
556
  }
523
557
 
524
558
  const lazyOptions = {
@@ -526,24 +560,24 @@ const lazyOptions = {
526
560
  };
527
561
 
528
562
  function setupComputedNode(e, t) {
529
- e.st = e;
530
- const n = context?.Ct ? context.Ot : context;
563
+ e.ct = e;
564
+ const n = context?.Gt ? context.Dt : context;
531
565
  if (context) {
532
- const t = context.ve;
566
+ const t = context.xe;
533
567
  if (t === null) {
534
- context.ve = e;
568
+ context.xe = e;
535
569
  } else {
536
- e.Ve = t;
537
- t.ct = e;
538
- context.ve = e;
570
+ e.Le = t;
571
+ t.ft = e;
572
+ context.xe = e;
539
573
  }
540
574
  }
541
- if (n) e.Le = n.Le + 1;
542
- if (GlobalQueue.Rt !== null) GlobalQueue.Rt(e);
575
+ if (n) e.Me = n.Me + 1;
576
+ if (GlobalQueue.Pt !== null) GlobalQueue.Pt(e);
543
577
  !t?.lazy && recompute(e, true);
544
578
  if (snapshotCaptureActive && !t?.lazy) {
545
579
  if (!(e.S & STATUS_PENDING) && !(e.T & CONFIG_NO_SNAPSHOT)) {
546
- ext(e).Qe = e.be === undefined ? NO_SNAPSHOT : e.be;
580
+ ext(e).We = e.be === undefined ? NO_SNAPSHOT : e.be;
547
581
  e.T |= CONFIG_HAS_SNAPSHOT;
548
582
  snapshotSources.add(e);
549
583
  }
@@ -552,31 +586,31 @@ function setupComputedNode(e, t) {
552
586
 
553
587
  function signal(e, t, n = null) {
554
588
  const i = {
555
- Ue: t?.equals != null ? t.equals : isEqual,
589
+ pe: t?.equals ?? isEqual,
556
590
  T: (t?.ownedWrite ? CONFIG_OWNED_WRITE : 0) | (t?.H ? CONFIG_NO_SNAPSHOT : 0),
557
591
  be: e,
558
592
  u: null,
559
- rt: null,
593
+ _t: null,
560
594
  Te: clock,
561
- lt: n,
595
+ st: n,
562
596
  Se: n?.o?.i || null,
563
- Pe: NOT_PENDING,
597
+ Re: NOT_PENDING,
564
598
  // Signal-literal diet (§12e): NO _time/_fn/_statusFlags slots. Stores
565
599
  // materialize one signal per touched leaf, so signal bytes are store
566
600
  // bytes. _time is write-only on signals (every read site is computed-
567
601
  // typed error-retry gating); _fn/_statusFlags read falsy-identically as
568
602
  // missing properties on the shared paths (undefined masks to 0).
569
- _e: null,
570
- _t: -1,
603
+ Ae: null,
604
+ It: -1,
571
605
  o: null
572
606
  };
573
- if (t?.unobserved) ext(i).ft = t.unobserved;
607
+ if (t?.unobserved) ext(i).Et = t.unobserved;
574
608
  if (n) {
575
609
  ext(n).i = i;
576
610
  n.T |= CONFIG_FW_CHILDREN;
577
611
  }
578
612
  if (snapshotCaptureActive && !(i.T & CONFIG_NO_SNAPSHOT) && !((n?.S ?? 0) & STATUS_PENDING)) {
579
- ext(i).Qe = e === undefined ? NO_SNAPSHOT : e;
613
+ ext(i).We = e === undefined ? NO_SNAPSHOT : e;
580
614
  i.T |= CONFIG_HAS_SNAPSHOT;
581
615
  snapshotSources.add(i);
582
616
  }
@@ -585,14 +619,14 @@ function signal(e, t, n = null) {
585
619
 
586
620
  function optimisticSignal(e, t) {
587
621
  const n = signal(e, t);
588
- ext(n).De = NOT_PENDING;
622
+ ext(n).Pe = NOT_PENDING;
589
623
  n.T |= CONFIG_OPTIMISTIC;
590
624
  return n;
591
625
  }
592
626
 
593
627
  function optimisticComputed(e, t) {
594
628
  const n = computed(e, t);
595
- ext(n).De = NOT_PENDING;
629
+ ext(n).Pe = NOT_PENDING;
596
630
  n.T |= CONFIG_OPTIMISTIC;
597
631
  return n;
598
632
  }
@@ -623,11 +657,11 @@ function isEqual(e, t) {
623
657
  * );
624
658
  * ```
625
659
  */ function untrack(e, t) {
626
- if (GlobalQueue.Gt === null && !tracking && true) return e();
660
+ if (GlobalQueue.ht === null && !tracking && true) return e();
627
661
  const n = tracking;
628
662
  tracking = false;
629
663
  try {
630
- if (GlobalQueue.Gt !== null) return GlobalQueue.Gt(e);
664
+ if (GlobalQueue.ht !== null) return GlobalQueue.ht(e);
631
665
  return e();
632
666
  } finally {
633
667
  tracking = n;
@@ -668,16 +702,44 @@ function isEqual(e, t) {
668
702
  * fast path, `_fn` nodes need prepareComputed, and firewall / override /
669
703
  * snapshot / transition / lane / dev-strictRead state all take the full
670
704
  * resolution. Anything slow returns READ_SLOW; the caller then calls read().
671
- */ function readNodeFast(e) {
672
- if (latestReadActive || pendingCheckActive || e.oe || e.lt || e.o?.De !== undefined || e.o?.Qe !== undefined || activeTransition !== null || currentOptimisticLane !== null || snapshotCaptureActive || false) return READ_SLOW;
705
+ */
706
+ /**
707
+ * Wake only authoritative-view readers (until() predicates) subscribed to `el`.
708
+ * The A17-silent ack paths — an authoritative arrival equal to the active
709
+ * override — use this so the predicate re-evaluates without re-firing
710
+ * ordinary subscribers whose visible (override) value did not change.
711
+ * Pay-for-use: reached through GlobalQueue._notifyAuthoritativeObservers,
712
+ * installed at first until() call — apps that never use until() shake it.
713
+ */ function notifyAuthoritativeObservers(e) {
714
+ for (let t = e.u; t !== null; t = t.ae) {
715
+ const e = t.ce;
716
+ if (!(e.T & CONFIG_AUTHORITATIVE_READ)) continue;
717
+ // Missed-wake latch (#3037), same contract as insertSubs: the reader may
718
+ // itself have pulled this recompute (updateIfNecessary from its own
719
+ // read), and the heap refuses RECOMPUTING nodes — latch so recompute's
720
+ // tail reschedules it with the staged value visible.
721
+ if (e.ie & REACTIVE_RECOMPUTING_DEPS && t.Ft === e.Ke && t !== e.je) e.ie |= REACTIVE_MISSED_WAKE;
722
+ enqueueSub(e);
723
+ }
724
+ schedule();
725
+ }
726
+
727
+ /** Installs the until() machinery hook. Idempotent; called by until() before
728
+ * any authoritative-view read happens (same late-binding contract as the
729
+ * optimistic engine). */ function installAuthoritativeRead() {
730
+ if (GlobalQueue.he === null) GlobalQueue.he = notifyAuthoritativeObservers;
731
+ }
732
+
733
+ function readNodeFast(e) {
734
+ if (latestReadActive || pendingCheckActive || e.oe || e.st || e.o?.Pe !== undefined || e.o?.We !== undefined || activeTransition !== null || currentOptimisticLane !== null || snapshotCaptureActive || false) return READ_SLOW;
673
735
  let t = context;
674
- if (t?.Ct) t = t.Ot;
736
+ if (t?.Gt) t = t.Dt;
675
737
  if (t && tracking) link(e, t);
676
738
  // Children-forbidden readers (createTrackedEffect / onSettled callbacks) get
677
739
  // committed visibility: like the effect half of createEffect and event
678
740
  // handlers, effect-phase code never observes its own unsettled write — the
679
741
  // write lands in the same flush's continuation (#3006).
680
- return !t || e.Pe === NOT_PENDING || t.T & CONFIG_CHILDREN_FORBIDDEN ? e.be : e.Pe;
742
+ return !t || e.Re === NOT_PENDING || t.T & CONFIG_CHILDREN_FORBIDDEN ? e.be : e.Re;
681
743
  }
682
744
 
683
745
  function read(e) {
@@ -685,47 +747,54 @@ function read(e) {
685
747
  // Checked before isPending so that isPending(() => latest(x)) checks
686
748
  // the _pendingSignal of _latestValueComputed (async in flight) rather
687
749
  // than the original node (which stays "pending" while held in a transition).
688
- if (latestReadActive) return GlobalQueue.Pt(e);
750
+ if (latestReadActive) return GlobalQueue.gt(e);
689
751
  let t = context;
690
- if (t?.Ct) t = t.Ot;
752
+ if (t?.Gt) t = t.Dt;
691
753
  const n = e;
692
- const i = e.lt;
754
+ const i = e.st;
693
755
  const u = i || e;
694
756
  // Handle isPending() mode: collect pending state while preserving normal read semantics.
695
757
  // Probe mode is suspended while preparing the node so nested reads during a
696
758
  // recompute don't collect into the probe.
697
759
  if (pendingCheckActive) {
698
- GlobalQueue.Dt(e, t, u, i);
760
+ GlobalQueue.Ht(e, t, u, i);
699
761
  } else if (typeof n.oe === "function") {
700
762
  prepareComputed(e, false);
701
763
  }
702
- if (!n.oe && u === e && e.o?.De === undefined && e.o?.Qe === undefined && activeTransition === null && currentOptimisticLane === null && !snapshotCaptureActive && true) {
764
+ if (!n.oe && u === e && e.o?.Pe === undefined && e.o?.We === undefined && activeTransition === null && currentOptimisticLane === null && !snapshotCaptureActive && true) {
703
765
  if (t && tracking) link(e, t);
704
766
  // Committed visibility for children-forbidden readers — see readNodeFast.
705
- return !t || e.Pe === NOT_PENDING || t.T & CONFIG_CHILDREN_FORBIDDEN ? e.be : e.Pe;
767
+ return !t || e.Re === NOT_PENDING || t.T & CONFIG_CHILDREN_FORBIDDEN ? e.be : e.Re;
706
768
  }
707
769
  if (t && tracking) {
708
770
  link(e, t, pendingCheckActive);
709
771
  if (u.oe) {
710
772
  const n = queueFor(e);
711
- if (u.Le >= n.xe) {
773
+ if (u.Me >= n.Qe) {
712
774
  markNode(t);
713
775
  markHeap(n);
714
776
  updateIfNecessary(u);
715
777
  }
716
- const i = u.Le;
778
+ // Fresh-pull readers (awaitable refresh's waiter) recompute a dirty
779
+ // source inline even when the height gate defers to the flush: the
780
+ // waiter must park on the re-ask's window (or serve its sync answer),
781
+ // never read the PRE-re-ask value as settled. Self-guarded: a clean
782
+ // node no-ops and updateIfNecessary refuses disposed nodes (#2983) —
783
+ // a dead target serves its last value, which is already quiescent.
784
+ else if (t.T & CONFIG_FRESH_READ) updateIfNecessary(u);
785
+ const i = u.Me;
717
786
  // parent check is shallow, might need to be recursive
718
- if (i >= t.Le && e.ke !== t) {
719
- t.Le = i + 1;
787
+ if (i >= t.Me && e.ke !== t) {
788
+ t.Me = i + 1;
720
789
  }
721
790
  }
722
791
  }
723
792
  if (u.S & STATUS_PENDING) {
724
- if (t && !(stale && u._e && activeTransition !== u._e)) {
793
+ if (t && !(stale && u.Ae && activeTransition !== u.Ae)) {
725
794
  // Per-lane suspension lives with the engine (a non-null lane implies it
726
795
  // is installed): under a lane, only same-lane pending async without an
727
796
  // active override throws.
728
- if (currentOptimisticLane === null || GlobalQueue.ht(u)) {
797
+ if (currentOptimisticLane === null || GlobalQueue.Vt(u)) {
729
798
  if (!tracking && e !== t) link(e, t);
730
799
  throw u.o?._;
731
800
  }
@@ -761,17 +830,27 @@ function read(e) {
761
830
  } else throw u.o?._;
762
831
  }
763
832
  if (snapshotCaptureActive && t && t.T & CONFIG_IN_SNAPSHOT_SCOPE) {
764
- const n = e.o?.Qe;
833
+ const n = e.o?.We;
765
834
  if (n !== undefined) {
766
835
  const i = n === NO_SNAPSHOT ? undefined : n;
767
- const u = e.Pe !== NOT_PENDING ? e.Pe : e.be;
836
+ const u = e.Re !== NOT_PENDING ? e.Re : e.be;
768
837
  if (u !== i) t.ie |= REACTIVE_SNAPSHOT_STALE;
769
838
  return i;
770
839
  }
771
840
  }
772
- if (e.o?.De !== undefined && e.o?.De !== NOT_PENDING) {
773
- // A17: the override IS the value for every reader.
774
- return unwrapOverride(e.o?.De);
841
+ if (e.o?.Pe !== undefined && e.o?.Pe !== NOT_PENDING) {
842
+ // A17: the override IS the value for every reader — except an authoritative
843
+ // reader (until()'s predicate carries CONFIG_AUTHORITATIVE_READ): it must
844
+ // observe independently-arriving truth, and serving it the caller's own
845
+ // tentative write would trivially satisfy the predicate. The bit is checked
846
+ // on the reading computation itself, so a shared computed the predicate
847
+ // pulls recomputes as ITSELF (context = the memo, no bit) under the normal
848
+ // view. Fall through to normal value selection (staged `_pendingValue` is
849
+ // authoritative — optimism never lives there); the sticky mark makes the
850
+ // A17-silent "landing equals override" paths notify this node's subs so
851
+ // the reader re-runs when truth arrives.
852
+ if (!(t && t.T & CONFIG_AUTHORITATIVE_READ)) return unwrapOverride(e.o?.Pe);
853
+ e.T |= CONFIG_AUTHORITATIVE_OBSERVED;
775
854
  }
776
855
  // Entanglement gate: a reader recomputing under an optimistic lane that reads
777
856
  // a pending mid-transition write sees the committed value. Projection-store
@@ -780,7 +859,7 @@ function read(e) {
780
859
  // _pendingValue for correct fetching. The sub is recorded for replay at commit
781
860
  // so it re-runs with the new committed view. (Gate details live with the
782
861
  // engine — a non-null lane implies it is installed.)
783
- if (currentOptimisticLane !== null && activeTransition !== null && t !== null && GlobalQueue.Ft(e, u, t)) {
862
+ if (currentOptimisticLane !== null && activeTransition !== null && t !== null && GlobalQueue.vt(e, u, t)) {
784
863
  return e.be;
785
864
  }
786
865
  // In optimistic lane context, return _value for optimistic/lane-assigned signals
@@ -789,10 +868,19 @@ function read(e) {
789
868
  // (The lane-context clause lives with the engine.) Children-forbidden readers
790
869
  // (createTrackedEffect / onSettled callbacks) get committed visibility — see
791
870
  // readNodeFast (#3006).
792
- const l = !t || currentOptimisticLane !== null && GlobalQueue.gt(e, u, t) || e.Pe === NOT_PENDING || t.T & CONFIG_CHILDREN_FORBIDDEN || stale && e._e && activeTransition !== e._e ? e.be : e.Pe;
871
+ const l = !t || currentOptimisticLane !== null && GlobalQueue.bt(e, u, t) || e.Re === NOT_PENDING || t.T & CONFIG_CHILDREN_FORBIDDEN || stale && e.Ae && activeTransition !== e.Ae ||
872
+ // A17 for HELD truth (#3164, see CONFIG_HELD_TRUTH): staged confirming
873
+ // truth — fold-staged onto an armed family, or entangle-stolen by an
874
+ // awaited until() — is masked from ordinary readers until its
875
+ // transaction's reveal; the retaining transaction's own speculative
876
+ // recomputes included (partial override coverage would otherwise
877
+ // compose override + staged truth into a state no timeline contains).
878
+ // Authoritative readers (until()'s predicate) and latest() see the
879
+ // staged truth — the tunnel that keeps the hold deadlock-free.
880
+ e.T & CONFIG_HELD_TRUTH && !latestReadActive && !(t.T & CONFIG_AUTHORITATIVE_READ) ? e.be : e.Re;
793
881
  // Record that this isPending() probe observed the fresh pending value, so
794
882
  // the probe doesn't pair "pending" with the new value (#2831).
795
- if (pendingCheckActive) GlobalQueue.Ht(e, l);
883
+ if (pendingCheckActive) GlobalQueue.kt(e, l);
796
884
  if (!t && u === e && typeof n.oe === "function" && e.T & CONFIG_AUTO_DISPOSE && !(u.S & STATUS_PENDING) && !e.u) {
797
885
  // Deferred, not inline (#3078): an inline unobserved() here made untracked
798
886
  // reads destructive — dispose on this read, full revival recompute on the
@@ -807,28 +895,28 @@ function read(e) {
807
895
  }
808
896
 
809
897
  function setSignal(e, t) {
810
- if (e._e && activeTransition !== e._e) globalQueue.initTransition(e._e);
898
+ if (e.Ae && activeTransition !== e.Ae) globalQueue.initTransition(e.Ae);
811
899
  // The optimistic write path lives with the engine: only optimisticSignal /
812
900
  // optimisticComputed callers and optimistic store nodes carry an
813
901
  // _overrideValue slot (flagged by CONFIG_OPTIMISTIC — a masked read of the
814
902
  // always-present config instead of a missing-property probe), and every
815
903
  // module that installs one installs the engine first.
816
- if (e.T & CONFIG_OPTIMISTIC && !projectionWriteActive) return GlobalQueue.kt(e, t);
817
- const n = e.Pe === NOT_PENDING ? e.be : e.Pe;
904
+ if (e.T & CONFIG_OPTIMISTIC && !projectionWriteActive) return GlobalQueue.xt(e, t);
905
+ const n = e.Re === NOT_PENDING ? e.be : e.Re;
818
906
  if (typeof t === "function") t = t(n);
819
907
  // Uninitialized check first: the first commit has no previous value, so the
820
908
  // user comparator must not run against `undefined` (matches recompute).
821
- const i = !!(e.S & STATUS_UNINITIALIZED) || !e.Ue || !e.Ue(n, t);
909
+ const i = !!(e.S & STATUS_UNINITIALIZED) || !e.pe || !e.pe(n, t);
822
910
  if (!i) return t;
823
- const u = e.Pe !== NOT_PENDING;
911
+ const u = e.Re !== NOT_PENDING;
824
912
  if (!u) queuePendingNode(e);
825
- e.Pe = t;
913
+ e.Re = t;
826
914
  // syncCompanions only pokes _pendingSignal/_latestValueComputed — with
827
915
  // neither companion present the call is a guaranteed no-op (companions are
828
916
  // only ever created, never removed, and creating one installs the hook and
829
917
  // sets CONFIG_HAS_COMPANIONS — one masked read replaces two optional-field
830
918
  // probes on every write).
831
- e.T & CONFIG_HAS_COMPANIONS && GlobalQueue.Oe !== null && GlobalQueue.Oe(e, t);
919
+ e.T & CONFIG_HAS_COMPANIONS && GlobalQueue.Ue !== null && GlobalQueue.Ue(e, t);
832
920
  // _time is a computed-only slot (§12e): writing it on a signal would fork
833
921
  // the lean shape. Every read site is computed-typed.
834
922
  if (e.oe !== undefined) e.Te = clock;
@@ -837,7 +925,7 @@ function setSignal(e, t) {
837
925
  // (epoch) — re-stages the value and stops. The walk is idempotent (subs
838
926
  // marked, heap entries flag-guarded, effects queued once); lane and reask
839
927
  // contexts change what a walk MEANS, so they always walk.
840
- if (u && e._t === notifyEpoch && currentOptimisticLane === null && !reaskArmed) return t;
928
+ if (u && e.It === notifyEpoch && currentOptimisticLane === null && !reaskArmed) return t;
841
929
  insertSubs(e);
842
930
  schedule();
843
931
  return t;
@@ -851,12 +939,12 @@ function setSignal(e, t) {
851
939
  * cleanup point.
852
940
  */ function suppressComputedRecompute(e) {
853
941
  deleteFromHeap(e, queueFor(e));
854
- if (!(e.ie & REACTIVE_MANUAL_WRITE) && e.Pe === NOT_PENDING) {
942
+ if (!(e.ie & REACTIVE_MANUAL_WRITE) && e.Re === NOT_PENDING) {
855
943
  queuePendingNode(e);
856
944
  schedule();
857
945
  }
858
946
  e.ie = e.ie & -4 | REACTIVE_MANUAL_WRITE;
859
- e.vt = clock;
947
+ e.Ut = clock;
860
948
  }
861
949
 
862
950
  /**
@@ -912,39 +1000,22 @@ function staleValues(e, t = true) {
912
1000
  }
913
1001
 
914
1002
  /**
915
- * Invalidates one reactive source, forcing it to re-execute even if its inputs
916
- * haven't changed.
917
- *
918
- * Pass either a Solid-created accessor or a projected store created from
919
- * `createStore(fn, ...)` / `createProjection(...)`. `refresh()` is a
920
- * write-like invalidation operation: it does not read the target's value, and
921
- * refreshing a plain signal accessor is a no-op.
922
- *
923
- * Use it to invalidate cached async values (e.g. force a re-fetch) without
924
- * tearing the consumer down.
925
- *
926
- * @example
927
- * ```ts
928
- * const user = createMemo(async () => fetch(`/users/${id()}`).then(r => r.json()));
929
- *
930
- * // Re-fetch on demand
931
- * <button onClick={() => refresh(user)}>Reload</button>
932
- * ```
933
- */ function refresh(e) {
934
- const t = e?.[$REFRESH];
935
- if (!t) {
936
- return;
937
- }
938
- if (typeof t.oe === "function" && !(t.ie & REACTIVE_DISPOSED)) {
939
- if (t.ie & REACTIVE_MANUAL_WRITE) {
1003
+ * Core marking half of `refresh()` (the public wrapper lives in signals.ts
1004
+ * it validates the target, marks through here, then builds the quiescence
1005
+ * promise on the resolve()/until() effect machinery). Flags the node's next
1006
+ * recompute as a quiet re-ask and schedules it; no-ops for non-derived or
1007
+ * disposed targets and for same-tick manual writes.
1008
+ */ function markRefresh(e) {
1009
+ if (typeof e.oe === "function" && !(e.ie & REACTIVE_DISPOSED)) {
1010
+ if (e.ie & REACTIVE_MANUAL_WRITE) {
940
1011
  // A manual write in the CURRENT tick wins over the refresh (#2692).
941
1012
  // A mask stamped in an earlier tick only survives because a
942
1013
  // transaction (action) is holding the pending drain open; there the
943
1014
  // refresh is a later, explicit re-ask and lifts the mask — otherwise
944
1015
  // any setStore early in an action silently swallows every refresh()
945
1016
  // for the rest of the transaction (#3026).
946
- if (t.vt === clock) return;
947
- t.ie &= ~REACTIVE_MANUAL_WRITE;
1017
+ if (e.Ut === clock) return;
1018
+ e.ie &= ~REACTIVE_MANUAL_WRITE;
948
1019
  // No REASK below: the batch carries a manual value change, so the
949
1020
  // recompute is not a quiet re-ask of an unchanged question.
950
1021
  }
@@ -955,14 +1026,14 @@ function staleValues(e, t = true) {
955
1026
  // REACTIVE_IN_HEAP counts as dirt: insertSubs schedules subscribers by
956
1027
  // heap insertion alone (no DIRTY/CHECK flag), so a same-batch value
957
1028
  // change followed by refresh() must not be laundered into a quiet re-ask.
958
- else if (!(t.ie & (REACTIVE_DIRTY | REACTIVE_CHECK | REACTIVE_IN_HEAP))) {
959
- t.ie |= REACTIVE_REASK;
1029
+ else if (!(e.ie & (REACTIVE_DIRTY | REACTIVE_CHECK | REACTIVE_IN_HEAP))) {
1030
+ e.ie |= REACTIVE_REASK;
960
1031
  armReaskClear();
961
1032
  }
962
- t.ie = t.ie & ~REACTIVE_CHECK | REACTIVE_DIRTY;
963
- insertIntoHeap(t, queueFor(t));
1033
+ e.ie = e.ie & ~REACTIVE_CHECK | REACTIVE_DIRTY;
1034
+ insertIntoHeap(e, queueFor(e));
964
1035
  schedule();
965
1036
  }
966
1037
  }
967
1038
 
968
- export { READ_SLOW, clearSnapshots, computed, context, createEffectNode, currentOptimisticLane, effectStatusNotify, ext, isEqual, latestReadActive, markSnapshotScope, optimisticComputed, optimisticSignal, pendingCheckActive, prepareComputed, read, readNodeFast, recompute, refresh, releaseSnapshotScope, runWithOwner, setContextInternal, setEffectStatusNotify, setLatestReadActive, setMemo, setPendingCheckActive, setSignal, setSnapshotCapture, signal, snapshotCaptureActive, snapshotSources, stale, staleValues, statusNotifierOf, suppressComputedRecompute, tracking, untrack };
1039
+ 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, setSnapshotCapture, signal, snapshotCaptureActive, snapshotSources, stale, staleValues, statusNotifierOf, suppressComputedRecompute, tracking, untrack };