@solidjs/signals 2.0.0-beta.26 → 2.0.0-beta.27

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.
@@ -1,4 +1,4 @@
1
- import { globalQueue, activeTransition, currentTransition, setActiveTransition, schedule, flush } from "./scheduler.js";
1
+ import { globalQueue, activeTransition, currentTransition, schedule, flush } from "./scheduler.js";
2
2
 
3
3
  import { isThenable } from "./async.js";
4
4
 
@@ -79,13 +79,18 @@ function restoreTransition(e, r) {
79
79
  globalQueue.initTransition();
80
80
  let o = activeTransition;
81
81
  o.ie.push(i);
82
- const done = (e, r, s = false) => {
82
+ const done = (e, r, u = false) => {
83
83
  o = currentTransition(o);
84
- const u = o.ie.indexOf(i);
85
- if (u >= 0) o.ie.splice(u, 1);
86
- setActiveTransition(o);
84
+ const s = o.ie.indexOf(i);
85
+ if (s >= 0) o.ie.splice(s, 1);
86
+ // Re-adopt through initTransition like every other resumption site:
87
+ // a bare setActiveTransition leaves globalQueue._batch as a detached
88
+ // ambient batch, and anything registered before the scheduled flush
89
+ // (held writes on a merging transition, optimistic overrides,
90
+ // affects() marks) lands there with nothing to ever finalize it.
91
+ globalQueue.initTransition(o);
87
92
  schedule();
88
- s ? n(r) : t(e);
93
+ u ? n(r) : t(e);
89
94
  };
90
95
  const step = (e, r) => {
91
96
  let t;
@@ -92,6 +92,37 @@ function releaseSettledDependents(e) {
92
92
  if (n) for (const e of n) releaseIfSettledUnobserved(e);
93
93
  }
94
94
 
95
+ // Error-dimension twin of settlePendingSource's blocked re-enqueue (#2949):
96
+ // a node in STATUS_ERROR that recovers by recomputing to an UNCHANGED value
97
+ // fires no value notification — the recovery is completely silent. But a
98
+ // dependent that re-ran during the error window consumed its dirty flag and
99
+ // committed nothing (the fresh sibling values it read were absorbed into an
100
+ // errored run), so its committed value is stale. The propagated error is one
101
+ // object identity down the whole dependent tree, and holding it is exactly
102
+ // the "blocked on this error" marker — re-enqueue those holders so they
103
+ // re-run: fresh values commit and flow, and a dependent with another
104
+ // still-broken source simply re-errors. The async dimension needs no twin of
105
+ // its own: recovery there passes through a pending window whose re-runners
106
+ // set _blocked and ride settlePendingSource. Walks the full dependent graph
107
+ // (releaseSettledDependents shape): identity holders can sit below an
108
+ // intermediate whose own error state has since been scrubbed or replaced
109
+ // (e.g. an error boundary's tree node).
110
+ function settleErroredDependents(e, n) {
111
+ let t = false;
112
+ const r = new Set;
113
+ const visit = e => {
114
+ if (r.has(e)) return;
115
+ r.add(e);
116
+ if (e._ === n) {
117
+ enqueueSub(e);
118
+ t = true;
119
+ }
120
+ forEachDependent(e, visit);
121
+ };
122
+ forEachDependent(e, visit);
123
+ if (t) schedule();
124
+ }
125
+
95
126
  function settlePendingSource(e) {
96
127
  let n = false;
97
128
  let t;
@@ -206,8 +237,8 @@ function handleAsync(e, n, t) {
206
237
  // (A17 — every reader sees the override); the revert reveals whatever
207
238
  // has committed by then, so corrections reveal atomically with their
208
239
  // transition rather than escaping it.
209
- if (e._e === NOT_PENDING) queuePendingNode(e);
210
- e._e = r;
240
+ if (e.De === NOT_PENDING) queuePendingNode(e);
241
+ e.De = r;
211
242
  // The hold is a companion-visible write like any other (A13/A19): the
212
243
  // clearStatus() above computed its verdict before the hold existed, so
213
244
  // isPending must re-derive (the value is not final until commit — V1)
@@ -215,14 +246,14 @@ function handleAsync(e, n, t) {
215
246
  // only notified when the hold is visible to them: under an active
216
247
  // override every reader sees the override (A17), so waking subs would
217
248
  // re-show an unchanged view — the revert is the notification point.
218
- GlobalQueue.De !== null && GlobalQueue.De(e, r);
249
+ GlobalQueue._e !== null && GlobalQueue._e(e, r);
219
250
  if (!hasActiveOverride(e)) insertSubs(e);
220
251
  e.Se = clock;
221
252
  } else if (l) {
222
253
  // Route through lane's effect queue for independent flushing
223
254
  const n = e.Pe;
224
255
  const t = e.Ue;
225
- const o = e.Re;
256
+ const o = e.be;
226
257
  try {
227
258
  if (!n && u || !o || !o(r, t)) {
228
259
  e.Ue = r;
@@ -230,7 +261,7 @@ function handleAsync(e, n, t) {
230
261
  // The latest() shadow write gives latest() effects independent lanes; the
231
262
  // _pendingSignal update is a no-op repeat of the clearStatus() call above
232
263
  // (computePendingState doesn't read _value).
233
- GlobalQueue.De !== null && GlobalQueue.De(e, r);
264
+ GlobalQueue._e !== null && GlobalQueue._e(e, r);
234
265
  insertSubs(e, true);
235
266
  }
236
267
  } catch (n) {
@@ -383,13 +414,13 @@ function clearStatus(e, n = false) {
383
414
  // The pending window is over; its quiet classification dies with it.
384
415
  // (Unconditional: _reask is baked into the node literals, so this is a
385
416
  // plain store to an existing slot — no shape change.)
386
- e.be = false;
417
+ e.Re = false;
387
418
  e.S = n ? 0 : e.S & STATUS_UNINITIALIZED;
388
419
  if (e._) setPendingError(e);
389
420
  // Update pending signal for isPending() reactivity (companions only exist
390
421
  // once the verdict layer created them, which installs the hooks).
391
- if (e.he || e.Ge) GlobalQueue.ce(e);
392
- if (e.u && GlobalQueue.Oe !== null) GlobalQueue.Oe(e);
422
+ if (e.he || e.pe) GlobalQueue.ce(e);
423
+ if (e.u && GlobalQueue.Ge !== null) GlobalQueue.Ge(e);
393
424
  if (e.i) e.i();
394
425
  }
395
426
 
@@ -413,7 +444,7 @@ function notifyStatus(e, n, t, r, o) {
413
444
  e._ = t;
414
445
  }
415
446
  GlobalQueue.ce !== null && GlobalQueue.ce(e);
416
- if (e.u && GlobalQueue.Oe !== null) GlobalQueue.Oe(e);
447
+ if (e.u && GlobalQueue.Ge !== null) GlobalQueue.Ge(e);
417
448
  }
418
449
  if (o && !r) {
419
450
  assignOrMergeLane(e, o);
@@ -439,7 +470,7 @@ function notifyStatus(e, n, t, r, o) {
439
470
  // not carry a real (non-NotReadyError) error — the synchronous `isPending`
440
471
  // read swallows those, and the async path must match. Re-run the observer
441
472
  // so `isPending` re-evaluates (to not-pending) instead of forwarding.
442
- if (r.ge && n !== STATUS_PENDING && !(t instanceof NotReadyError)) {
473
+ if (r.Oe && n !== STATUS_PENDING && !(t instanceof NotReadyError)) {
443
474
  enqueueSub(e);
444
475
  schedule();
445
476
  return;
@@ -450,4 +481,4 @@ function notifyStatus(e, n, t, r, o) {
450
481
  });
451
482
  }
452
483
 
453
- export { addPendingSource, clearStatus, forEachDependent, handleAsync, isThenable, notifyStatus, releaseSettledDependents, setPendingError, settlePendingSource };
484
+ export { addPendingSource, clearStatus, forEachDependent, handleAsync, isThenable, notifyStatus, releaseSettledDependents, setPendingError, settleErroredDependents, settlePendingSource };
@@ -1,6 +1,6 @@
1
- import { handleAsync, clearStatus, notifyStatus } from "./async.js";
1
+ import { handleAsync, clearStatus, notifyStatus, settleErroredDependents } from "./async.js";
2
2
 
3
- import { EFFECT_TRACKED, REACTIVE_OPTIMISTIC_DIRTY, NOT_PENDING, STATUS_UNINITIALIZED, REACTIVE_REASK, REACTIVE_RECOMPUTING_DEPS, CONFIG_SYNC, STATUS_PENDING, STATUS_ERROR, REACTIVE_NONE, REACTIVE_SNAPSHOT_STALE, unwrapOverride, OVERRIDE_UNDEFINED, REACTIVE_LAZY, REACTIVE_DISPOSED, CONFIG_AUTO_DISPOSE, 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, NO_SNAPSHOT, STORE_SNAPSHOT_PROPS, EFFECT_USER } from "./constants.js";
3
+ import { EFFECT_TRACKED, REACTIVE_OPTIMISTIC_DIRTY, NOT_PENDING, STATUS_UNINITIALIZED, STATUS_ERROR, REACTIVE_REASK, REACTIVE_RECOMPUTING_DEPS, CONFIG_SYNC, STATUS_PENDING, REACTIVE_NONE, REACTIVE_SNAPSHOT_STALE, unwrapOverride, OVERRIDE_UNDEFINED, REACTIVE_LAZY, REACTIVE_DISPOSED, CONFIG_AUTO_DISPOSE, 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, NO_SNAPSHOT, STORE_SNAPSHOT_PROPS, EFFECT_USER } from "./constants.js";
4
4
 
5
5
  import { NotReadyError } from "./error.js";
6
6
 
@@ -14,9 +14,9 @@ import "./invariants.js";
14
14
 
15
15
  import { disposeChildren, markDisposal, inheritId } from "./owner.js";
16
16
 
17
- GlobalQueue.pe = recompute;
17
+ GlobalQueue.Ce = recompute;
18
18
 
19
- GlobalQueue.Ce = disposeChildren;
19
+ GlobalQueue.me = 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.me) return true;
51
+ if (e.ge) return true;
52
52
  e = e.ve;
53
53
  }
54
54
  return false;
@@ -60,11 +60,11 @@ function setSnapshotCapture(e) {
60
60
  }
61
61
 
62
62
  function markSnapshotScope(e) {
63
- e.me = true;
63
+ e.ge = true;
64
64
  }
65
65
 
66
66
  function releaseSnapshotScope(e) {
67
- e.me = false;
67
+ e.ge = false;
68
68
  releaseSubtree(e);
69
69
  schedule();
70
70
  }
@@ -72,7 +72,7 @@ function releaseSnapshotScope(e) {
72
72
  function releaseSubtree(e) {
73
73
  let t = e.ke;
74
74
  while (t) {
75
- if (t.me) {
75
+ if (t.ge) {
76
76
  t = t.Fe;
77
77
  continue;
78
78
  }
@@ -124,19 +124,23 @@ function recompute(e, t = false) {
124
124
  let i = !!(e.se & REACTIVE_OPTIMISTIC_DIRTY);
125
125
  const u = e.Ae !== undefined && e.Ae !== NOT_PENDING;
126
126
  const l = !!(e.S & STATUS_UNINITIALIZED);
127
+ // Outgoing error, captured before the compute clears status: if this run
128
+ // recovers to an unchanged value, dependents still holding this object must
129
+ // be swept (settleErroredDependents, #2949).
130
+ const o = e.S & STATUS_ERROR ? e._ : undefined;
127
131
  // Re-ask classification lives in the verdict module; capture the flag before
128
132
  // the recompute wipes _flags below.
129
- const o = (e.se & REACTIVE_REASK) !== 0;
130
- const s = context;
133
+ const s = (e.se & REACTIVE_REASK) !== 0;
134
+ const a = context;
131
135
  context = e;
132
136
  e.We = null;
133
137
  e.Ye++;
134
138
  e.se = REACTIVE_RECOMPUTING_DEPS;
135
139
  e.Se = clock;
136
- let a = e._e === NOT_PENDING ? e.Ue : e._e;
137
- let r = e.Ve;
138
- let c = tracking;
139
- let _ = currentOptimisticLane;
140
+ let r = e.De === NOT_PENDING ? e.Ue : e.De;
141
+ let c = e.Ve;
142
+ let _ = tracking;
143
+ let f = currentOptimisticLane;
140
144
  tracking = true;
141
145
  // A computed's fn establishes its OWN dependencies, so it must never run
142
146
  // inside a latest() read window: read() short-circuits through the
@@ -144,7 +148,7 @@ function recompute(e, t = false) {
144
148
  // computed) inside latest(fn) came out permanently dependency-less (#2926).
145
149
  // latestRead() already suspends the flag for its pull-recomputes; this
146
150
  // covers creation-time computes and flushes that run inside the window.
147
- const f = latestReadActive;
151
+ const E = latestReadActive;
148
152
  latestReadActive = false;
149
153
  // Lane posture lives with the engine: OPTIMISTIC_DIRTY is only ever set by
150
154
  // engine-driven paths, and _optimisticNodes is only pushed by
@@ -162,12 +166,12 @@ function recompute(e, t = false) {
162
166
  currentOptimisticLane = t;
163
167
  }
164
168
  }
165
- const E = n && n !== EFFECT_USER;
166
- const N = stale;
167
- if (E) stale = true;
169
+ const N = n && n !== EFFECT_USER;
170
+ const T = stale;
171
+ if (N) stale = true;
168
172
  try {
169
173
  if (!false && e.T & CONFIG_SYNC) {
170
- a = e.ae(a);
174
+ r = e.ae(r);
171
175
  e.Te = null;
172
176
  } else {
173
177
  // Snapshot `_inFlight` so we can detect whether `_fn` self-registered an async
@@ -176,16 +180,16 @@ function recompute(e, t = false) {
176
180
  // clobber the fresh subscription, so we skip it and let the internally-registered
177
181
  // iteration drive updates.
178
182
  const t = e.Te;
179
- const n = e.ae(a);
183
+ const n = e.ae(r);
180
184
  const i = typeof n === "object" && n !== null;
181
185
  const u = e.Te !== t;
182
- a = u || !i ? n : handleAsync(e, n);
186
+ r = u || !i ? n : handleAsync(e, n);
183
187
  if (!u && !i) e.Te = null;
184
188
  }
185
189
  // On a status-free node clearStatus is a guaranteed no-op: every branch
186
190
  // in its body is gated on one of these fields, and with _statusFlags === 0
187
191
  // the flags write (create or not) stores the 0 already there.
188
- if (e.S !== 0 || e.i !== undefined || e._ || e.be || e.de || e.oe !== undefined || e.he !== undefined || e.Ge !== undefined || e.u !== null) clearStatus(e, t);
192
+ if (e.S !== 0 || e.i !== undefined || e._ || e.Re || e.de || e.oe !== undefined || e.he !== undefined || e.pe !== undefined || e.u !== null) clearStatus(e, t);
189
193
  // _optimisticLane is only ever assigned by engine paths.
190
194
  if (e.Me) GlobalQueue.Ke(e);
191
195
  } catch (t) {
@@ -195,23 +199,23 @@ function recompute(e, t = false) {
195
199
  let n = false;
196
200
  if (t instanceof NotReadyError) {
197
201
  e.de = true;
198
- if (GlobalQueue.$e !== null) n = GlobalQueue.$e(e, o);
202
+ if (GlobalQueue.$e !== null) n = GlobalQueue.$e(e, s);
199
203
  }
200
204
  notifyStatus(e, t instanceof NotReadyError ? STATUS_PENDING : STATUS_ERROR, t, undefined, t instanceof NotReadyError ? e.Me : undefined);
201
205
  if (n) GlobalQueue.k(e);
202
206
  } finally {
203
- tracking = c;
204
- latestReadActive = f;
205
- if (E) stale = N;
207
+ tracking = _;
208
+ latestReadActive = E;
209
+ if (N) stale = T;
206
210
  e.se = REACTIVE_NONE | (t ? e.se & REACTIVE_SNAPSHOT_STALE : 0);
207
- context = s;
211
+ context = a;
208
212
  }
209
213
  if (!e._) {
210
214
  trimStaleDeps(e);
211
- const o = u ? unwrapOverride(e.Ae) : e._e === NOT_PENDING ? e.Ue : e._e;
212
- let s = false;
215
+ const s = u ? unwrapOverride(e.Ae) : e.De === NOT_PENDING ? e.Ue : e.De;
216
+ let a = false;
213
217
  try {
214
- s = !n && l || !e.Re || !e.Re(o, a);
218
+ a = !n && l || !e.be || !e.be(s, r);
215
219
  } catch (t) {
216
220
  // A throwing user comparator is an error of this node's computation.
217
221
  // Route it through the same status path as a compute-phase throw so
@@ -224,13 +228,13 @@ function recompute(e, t = false) {
224
228
  // its runner — happen here instead. `!create` matches the previous `initialized`
225
229
  // gate: the explicit recompute(node, true) inside effect() does not enqueue, so
226
230
  // effect() can call its runner synchronously for the first run.
227
- if (n && s) {
231
+ if (n && a) {
228
232
  e.Be = !e._;
229
233
  // Reuse one bound runner per effect — runEffect no-ops on a stale
230
234
  // `_modified`, so re-enqueueing the same function is harmless.
231
235
  if (!t) e.C.enqueue(n, e.Je ??= GlobalQueue.Xe.bind(null, e));
232
236
  }
233
- if (e._) ; else if (s) {
237
+ if (e._) ; else if (a) {
234
238
  const l = u ? e.Ae : undefined;
235
239
  if (t ||
236
240
  // Plain sync flush (no transition on either side) commits effect
@@ -238,23 +242,23 @@ function recompute(e, t = false) {
238
242
  // commitPendingNodes) exists to sequence transition reveals, and
239
243
  // paying it per effect on the plain path is pure overhead.
240
244
  n && (activeTransition !== e.Ie || activeTransition === null) || i) {
241
- e.Ue = a;
245
+ e.Ue = r;
242
246
  // Lane-propagated correction: upstream data is fresh, correct the
243
247
  // override unconditionally. The direct _value commit is the lane's
244
248
  // own reveal schedule; drop any superseded older hold so its queued
245
249
  // commit can't clobber the fresh value.
246
250
  if (u && i) {
247
- e.Ae = a === undefined ? OVERRIDE_UNDEFINED : a;
248
- e._e = NOT_PENDING;
251
+ e.Ae = r === undefined ? OVERRIDE_UNDEFINED : r;
252
+ e.De = NOT_PENDING;
249
253
  }
250
254
  } else {
251
- e._e = a;
255
+ e.De = r;
252
256
  // Transition-held sync recompute is a write path like setSignal/asyncWrite,
253
257
  // so sync derivations of held sources stay visible to isPending()/latest()
254
258
  // (#2831). Both companion writes are transition-scoped (optimistic) and
255
259
  // auto-revert/re-derive at commit. Skipped for plain flushes where the
256
260
  // pending value commits before effects run.
257
- if ((activeTransition || e.Ie) && GlobalQueue.De !== null) GlobalQueue.De(e, a);
261
+ if ((activeTransition || e.Ie) && GlobalQueue._e !== null) GlobalQueue._e(e, r);
258
262
  }
259
263
  // insertSubs only walks _subs (no scheduling of its own), so a
260
264
  // subscriber-less node has nothing to notify.
@@ -263,22 +267,28 @@ function recompute(e, t = false) {
263
267
  // Unchanged value (equals the override) recomputed while the override
264
268
  // is active: _value may still be stale, so hold the authoritative value
265
269
  // for commit on its own transition's schedule — invisibly (A17/A18).
266
- if (e._e === NOT_PENDING) queuePendingNode(e);
267
- e._e = a;
268
- } else if (e.Ve != r) {
270
+ if (e.De === NOT_PENDING) queuePendingNode(e);
271
+ e.De = r;
272
+ } else if (e.Ve != c) {
269
273
  for (let t = e.o; t !== null; t = t.ue) {
270
274
  insertIntoHeapHeight(t.le, queueFor(t.le));
271
275
  }
272
276
  }
277
+ // Silent recovery: errored → unchanged value fires no notification, but
278
+ // dependents still holding the propagated error consumed their dirty flag
279
+ // in an errored run and may sit on stale commits (#2949). Changed-value
280
+ // recoveries ride insertSubs above; a comparator throw re-errored the node
281
+ // (el._error re-set), so this only runs on a genuinely clean recovery.
282
+ if (o !== undefined && !a && !e._) settleErroredDependents(e, o);
273
283
  }
274
- currentOptimisticLane = _;
275
- const T = e._e !== NOT_PENDING || e.Qe !== null || e.ye !== null || (e.S & (STATUS_PENDING | STATUS_UNINITIALIZED)) !== 0;
284
+ currentOptimisticLane = f;
285
+ const d = e.De !== NOT_PENDING || e.Qe !== null || e.ye !== null || (e.S & (STATUS_PENDING | STATUS_UNINITIALIZED)) !== 0;
276
286
  // Override-covered holds (hasOverride) always queue: their commit belongs
277
287
  // to their own transition's schedule (A18 re-rule) and is unobservable
278
288
  // under the override (A17). Revert no longer commits anything, so an
279
289
  // unqueued covered hold would leak (INV-7) once the revert clears
280
290
  // _transition.
281
- T && (!t || e.S & STATUS_PENDING) && (!e.Ie || u) && queuePendingNode(e);
291
+ d && (!t || e.S & STATUS_PENDING) && (!e.Ie || u) && queuePendingNode(e);
282
292
  e.Ie && n && activeTransition !== e.Ie && runInTransition(e.Ie, () => recompute(e));
283
293
  }
284
294
 
@@ -306,7 +316,7 @@ function computed(e, t) {
306
316
  const i = {
307
317
  id: inheritId(t, n, context),
308
318
  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),
309
- Re: t?.equals != null ? t.equals : isEqual,
319
+ be: t?.equals != null ? t.equals : isEqual,
310
320
  ut: t?.unobserved,
311
321
  Le: null,
312
322
  C: context?.C ?? globalQueue,
@@ -330,12 +340,12 @@ function computed(e, t) {
330
340
  se: t?.lazy ? REACTIVE_LAZY : REACTIVE_NONE,
331
341
  S: STATUS_UNINITIALIZED,
332
342
  Se: clock,
333
- _e: NOT_PENDING,
343
+ De: NOT_PENDING,
334
344
  ye: null,
335
345
  Qe: null,
336
346
  Te: null,
337
347
  Ie: null,
338
- be: false
348
+ Re: false
339
349
  };
340
350
  setupComputedNode(i, t);
341
351
  return i;
@@ -351,7 +361,7 @@ function computed(e, t) {
351
361
  const s = {
352
362
  id: inheritId(l, o, context),
353
363
  T: (o ? CONFIG_TRANSPARENT : 0) | (l?.ownedWrite ? CONFIG_OWNED_WRITE : 0) | (l?.sync ? CONFIG_SYNC : 0) | (snapshotCaptureActive && ownerInSnapshotScope(context) ? CONFIG_IN_SNAPSHOT_SCOPE : 0),
354
- Re: false,
364
+ be: false,
355
365
  ut: l?.unobserved,
356
366
  Le: null,
357
367
  C: context?.C ?? globalQueue,
@@ -375,12 +385,12 @@ function computed(e, t) {
375
385
  se: REACTIVE_LAZY,
376
386
  S: STATUS_UNINITIALIZED,
377
387
  Se: clock,
378
- _e: NOT_PENDING,
388
+ De: NOT_PENDING,
379
389
  ye: null,
380
390
  Qe: null,
381
391
  Te: null,
382
392
  Ie: null,
383
- be: false,
393
+ Re: false,
384
394
  Be: false,
385
395
  ct: undefined,
386
396
  _t: t,
@@ -411,7 +421,7 @@ function setupComputedNode(e, t) {
411
421
  }
412
422
  }
413
423
  if (n) e.Ve = n.Ve + 1;
414
- if (GlobalQueue.It !== null) GlobalQueue.It(e);
424
+ if (GlobalQueue.dt !== null) GlobalQueue.dt(e);
415
425
  !t?.lazy && recompute(e, true);
416
426
  if (snapshotCaptureActive && !t?.lazy) {
417
427
  if (!(e.S & STATUS_PENDING) && !(e.T & CONFIG_NO_SNAPSHOT)) {
@@ -423,7 +433,7 @@ function setupComputedNode(e, t) {
423
433
 
424
434
  function signal(e, t, n = null) {
425
435
  const i = {
426
- Re: t?.equals != null ? t.equals : isEqual,
436
+ be: t?.equals != null ? t.equals : isEqual,
427
437
  T: (t?.ownedWrite ? CONFIG_OWNED_WRITE : 0) | (t?.V ? CONFIG_NO_SNAPSHOT : 0),
428
438
  ut: t?.unobserved,
429
439
  Ue: e,
@@ -432,7 +442,7 @@ function signal(e, t, n = null) {
432
442
  Se: clock,
433
443
  it: n,
434
444
  fe: n?.u || null,
435
- _e: NOT_PENDING
445
+ De: NOT_PENDING
436
446
  };
437
447
  n && (n.u = i);
438
448
  if (snapshotCaptureActive && !(i.T & CONFIG_NO_SNAPSHOT) && !((n?.S ?? 0) & STATUS_PENDING)) {
@@ -480,11 +490,11 @@ function isEqual(e, t) {
480
490
  * );
481
491
  * ```
482
492
  */ function untrack(e, t) {
483
- if (GlobalQueue.dt === null && !tracking && true) return e();
493
+ if (GlobalQueue.It === null && !tracking && true) return e();
484
494
  const n = tracking;
485
495
  tracking = false;
486
496
  try {
487
- if (GlobalQueue.dt !== null) return GlobalQueue.dt(e);
497
+ if (GlobalQueue.It !== null) return GlobalQueue.It(e);
488
498
  return e();
489
499
  } finally {
490
500
  tracking = n;
@@ -524,7 +534,7 @@ function isEqual(e, t) {
524
534
  let t = context;
525
535
  if (t?.Nt) t = t.Tt;
526
536
  if (t && tracking) link(e, t);
527
- return !t || e._e === NOT_PENDING ? e.Ue : e._e;
537
+ return !t || e.De === NOT_PENDING ? e.Ue : e.De;
528
538
  }
529
539
 
530
540
  function read(e) {
@@ -548,7 +558,7 @@ function read(e) {
548
558
  }
549
559
  if (!n.ae && u === e && e.Ae === undefined && e.xe === undefined && activeTransition === null && currentOptimisticLane === null && !snapshotCaptureActive && true) {
550
560
  if (t && tracking) link(e, t);
551
- return !t || e._e === NOT_PENDING ? e.Ue : e._e;
561
+ return !t || e.De === NOT_PENDING ? e.Ue : e.De;
552
562
  }
553
563
  if (t && tracking) {
554
564
  link(e, t, pendingCheckActive);
@@ -582,21 +592,25 @@ function read(e) {
582
592
  throw u._;
583
593
  }
584
594
  }
585
- if (e.ae && e.S & STATUS_ERROR) {
595
+ // `owner` is the computed itself, or the firewall behind a store node —
596
+ // firewall-backed reads follow the same rules (memo parity, #2897 ruling):
597
+ // an errored derive throws for every late reader instead of silently
598
+ // serving node values (the seed, or last-good data after a failed refetch).
599
+ if (u.ae && u.S & STATUS_ERROR) {
586
600
  // Only a genuine reactive re-read may retry an errored async source:
587
601
  // - tracking: owned/tracked scope only (never events / `untrack` / effect side-effect phase)
588
602
  // - !pendingCheckActive: an `isPending` probe observes the error, never refetches
589
- // - el._time < clock: only on a later cycle than the one the error was found
590
- if (tracking && !pendingCheckActive && e.Se < clock) {
591
- recompute(e);
603
+ // - owner._time < clock: only on a later cycle than the one the error was found
604
+ if (tracking && !pendingCheckActive && u.Se < clock) {
605
+ recompute(u);
592
606
  return read(e);
593
- } else throw e._;
607
+ } else throw u._;
594
608
  }
595
609
  if (snapshotCaptureActive && t && t.T & CONFIG_IN_SNAPSHOT_SCOPE) {
596
610
  const n = e.xe;
597
611
  if (n !== undefined) {
598
612
  const i = n === NO_SNAPSHOT ? undefined : n;
599
- const u = e._e !== NOT_PENDING ? e._e : e.Ue;
613
+ const u = e.De !== NOT_PENDING ? e.De : e.Ue;
600
614
  if (u !== i) t.se |= REACTIVE_SNAPSHOT_STALE;
601
615
  return i;
602
616
  }
@@ -619,7 +633,7 @@ function read(e) {
619
633
  // and for regular signals in stale mode (render effects). Non-stale readers (user
620
634
  // effects) see _pendingValue so that latest() and direct reads stay consistent.
621
635
  // (The lane-context clause lives with the engine.)
622
- const l = !t || currentOptimisticLane !== null && GlobalQueue.Rt(e, u, t) || e._e === NOT_PENDING || stale && e.Ie && activeTransition !== e.Ie ? e.Ue : e._e;
636
+ const l = !t || currentOptimisticLane !== null && GlobalQueue.Rt(e, u, t) || e.De === NOT_PENDING || stale && e.Ie && activeTransition !== e.Ie ? e.Ue : e.De;
623
637
  // Record that this isPending() probe observed the fresh pending value, so
624
638
  // the probe doesn't pair "pending" with the new value (#2831).
625
639
  if (pendingCheckActive) GlobalQueue.Pt(e, l);
@@ -636,18 +650,18 @@ function setSignal(e, t) {
636
650
  // _overrideValue slot, and every module that creates one installs the
637
651
  // engine first.
638
652
  if (e.Ae !== undefined && !projectionWriteActive) return GlobalQueue.ht(e, t);
639
- const n = e._e === NOT_PENDING ? e.Ue : e._e;
653
+ const n = e.De === NOT_PENDING ? e.Ue : e.De;
640
654
  if (typeof t === "function") t = t(n);
641
655
  // Uninitialized check first: the first commit has no previous value, so the
642
656
  // user comparator must not run against `undefined` (matches recompute).
643
- const i = !!(e.S & STATUS_UNINITIALIZED) || !e.Re || !e.Re(n, t);
657
+ const i = !!(e.S & STATUS_UNINITIALIZED) || !e.be || !e.be(n, t);
644
658
  if (!i) return t;
645
- if (e._e === NOT_PENDING) queuePendingNode(e);
646
- e._e = t;
659
+ if (e.De === NOT_PENDING) queuePendingNode(e);
660
+ e.De = t;
647
661
  // syncCompanions only pokes _pendingSignal/_latestValueComputed — with
648
662
  // neither companion present the call is a guaranteed no-op (companions are
649
663
  // only ever created, never removed, and creating one installs the hook).
650
- (e.he !== undefined || e.Ge !== undefined) && GlobalQueue.De !== null && GlobalQueue.De(e, t);
664
+ (e.he !== undefined || e.pe !== undefined) && GlobalQueue._e !== null && GlobalQueue._e(e, t);
651
665
  e.Se = clock;
652
666
  insertSubs(e);
653
667
  schedule();
@@ -662,7 +676,7 @@ function setSignal(e, t) {
662
676
  * cleanup point.
663
677
  */ function suppressComputedRecompute(e) {
664
678
  deleteFromHeap(e, queueFor(e));
665
- if (!(e.se & REACTIVE_MANUAL_WRITE) && e._e === NOT_PENDING) {
679
+ if (!(e.se & REACTIVE_MANUAL_WRITE) && e.De === NOT_PENDING) {
666
680
  queuePendingNode(e);
667
681
  schedule();
668
682
  }
@@ -64,8 +64,8 @@ function externalUntrack(e) {
64
64
  // removed on reset) so core's null checks stay equivalent to the old
65
65
  // `externalSourceConfig` truthiness checks.
66
66
  function syncExternalHooks() {
67
- GlobalQueue.It = externalSourceConfig ? wireExternalSource : null;
68
- GlobalQueue.dt = externalSourceConfig ? externalUntrack : null;
67
+ GlobalQueue.dt = externalSourceConfig ? wireExternalSource : null;
68
+ GlobalQueue.It = externalSourceConfig ? externalUntrack : null;
69
69
  }
70
70
 
71
71
  function enableExternalSource(e) {
@@ -61,7 +61,7 @@ function link(l, n, e = false) {
61
61
  // read order within the computation.
62
62
  const u = n.We;
63
63
  if (u !== null && u.nt === l) {
64
- u.ge &&= e;
64
+ u.Oe &&= e;
65
65
  return;
66
66
  }
67
67
  let s = null;
@@ -72,7 +72,7 @@ function link(l, n, e = false) {
72
72
  s.nl = n.Ye;
73
73
  n.We = s;
74
74
  // First touch of this pass: the previous pass's label is stale.
75
- s.ge = e;
75
+ s.Oe = e;
76
76
  return;
77
77
  }
78
78
  }
@@ -85,7 +85,7 @@ function link(l, n, e = false) {
85
85
  if (i !== null && i.le === n && (!t || i.nl === n.Ye)) {
86
86
  // Gen-matched during a recompute = repeat touch this pass (AND); outside
87
87
  // a recompute there is no pass boundary, so the latest read labels it.
88
- if (t) i.ge &&= e; else i.ge = e;
88
+ if (t) i.Oe &&= e; else i.Oe = e;
89
89
  return;
90
90
  }
91
91
  const o = n.We = l.st = {
@@ -95,7 +95,7 @@ function link(l, n, e = false) {
95
95
  ll: i,
96
96
  ue: null,
97
97
  nl: n.Ye,
98
- ge: e
98
+ Oe: e
99
99
  };
100
100
  if (u !== null) u.tt = o; else n.et = o;
101
101
  if (i !== null) i.ue = o; else l.o = o;
@@ -37,7 +37,7 @@ const activeLanes = new Set;
37
37
  // the owner's write merges the companion's subscribers into this lane and
38
38
  // their effects wait on its async instead of flushing immediately.
39
39
  adoptCompanionLane(n.he, e);
40
- adoptCompanionLane(n.Ge, e);
40
+ adoptCompanionLane(n.pe, e);
41
41
  return e;
42
42
  }
43
43
 
@@ -27,7 +27,7 @@ import { GlobalQueue, activeTransition, globalQueue, clock, insertSubs, schedule
27
27
  const t = e.Ae !== NOT_PENDING;
28
28
  const i = t ? unwrapOverride(e.Ae) : e.Ue;
29
29
  if (typeof n === "function") n = n(i);
30
- const u = !!(e.S & STATUS_UNINITIALIZED) || !e.Re || !e.Re(i, n);
30
+ const u = !!(e.S & STATUS_UNINITIALIZED) || !e.be || !e.be(i, n);
31
31
  if (!u) {
32
32
  // Same-value write with an active override still entangles the current
33
33
  // action's transition — the hold must outlast all overlapping actions.
@@ -54,7 +54,7 @@ import { GlobalQueue, activeTransition, globalQueue, clock, insertSubs, schedule
54
54
  e.Ae = n === undefined ? OVERRIDE_UNDEFINED : n;
55
55
  // syncCompanions only pokes _pendingSignal/_latestValueComputed — with
56
56
  // neither companion present the call is a guaranteed no-op.
57
- (e.he !== undefined || e.Ge !== undefined) && GlobalQueue.De !== null && GlobalQueue.De(e, n);
57
+ (e.he !== undefined || e.pe !== undefined) && GlobalQueue._e !== null && GlobalQueue._e(e, n);
58
58
  e.Se = clock;
59
59
  insertSubs(e, true);
60
60
  schedule();
@@ -98,9 +98,9 @@ function resolveOptimisticNodes(e) {
98
98
  // transition that produced them (A19 — pending is a property of the data).
99
99
  for (let t = 0; t < n; t++) {
100
100
  const n = e[t];
101
- if (n.he || n.Ge) GlobalQueue.un(n);
101
+ if (n.he || n.pe) GlobalQueue.un(n);
102
102
  const i = n.nn;
103
- if (i && (i.he === n || i.Ge === n)) GlobalQueue.un(i);
103
+ if (i && (i.he === n || i.pe === n)) GlobalQueue.un(i);
104
104
  }
105
105
  e.splice(0, n);
106
106
  }
@@ -153,7 +153,7 @@ function cleanupCompletedLanes(e) {
153
153
  * that reads a pending mid-transition write sees the committed value; the sub
154
154
  * is recorded for replay at commit.
155
155
  */ function gatedRead(e, n, t) {
156
- if (latestReadActive || e._e === NOT_PENDING || e.ae || n !== e && !(n.se & REACTIVE_MANUAL_WRITE)) {
156
+ if (latestReadActive || e.De === NOT_PENDING || e.ae || n !== e && !(n.se & REACTIVE_MANUAL_WRITE)) {
157
157
  return false;
158
158
  }
159
159
  activeTransition.ln.add(t);