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

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 (53) hide show
  1. package/README.md +1 -1
  2. package/dist/dev.js +2622 -2438
  3. package/dist/node.cjs +3770 -3571
  4. package/dist/prod/core/async.js +186 -132
  5. package/dist/prod/core/core.js +118 -107
  6. package/dist/prod/core/effect.js +13 -13
  7. package/dist/prod/core/external.js +1 -1
  8. package/dist/prod/core/graph.js +8 -8
  9. package/dist/prod/core/heap.js +24 -24
  10. package/dist/prod/core/lanes.js +3 -3
  11. package/dist/prod/core/optimistic.js +38 -21
  12. package/dist/prod/core/owner.js +21 -21
  13. package/dist/prod/core/scheduler.js +55 -47
  14. package/dist/prod/core/verdict.js +40 -40
  15. package/dist/prod/index.js +7 -7
  16. package/dist/prod/map.js +81 -79
  17. package/dist/prod/signals.js +20 -1
  18. package/dist/prod/store/index.js +36 -0
  19. package/dist/prod/store/next/optimistic.js +377 -0
  20. package/dist/prod/store/next/projection.js +172 -0
  21. package/dist/prod/store/next/reconcile.js +327 -0
  22. package/dist/prod/store/next/store.js +1232 -0
  23. package/dist/prod/store/next/target.js +20 -0
  24. package/dist/prod/store/store.js +123 -879
  25. package/dist/prod/store/utils.js +59 -186
  26. package/dist/types/core/core.d.ts +8 -0
  27. package/dist/types/core/dev.d.ts +1 -1
  28. package/dist/types/core/scheduler.d.ts +4 -2
  29. package/dist/types/signals.d.ts +19 -0
  30. package/dist/types/store/index.d.ts +15 -5
  31. package/dist/types/store/next/optimistic.d.ts +20 -0
  32. package/dist/types/store/next/projection.d.ts +24 -0
  33. package/dist/types/store/next/reconcile.d.ts +3 -0
  34. package/dist/types/store/next/store.d.ts +71 -0
  35. package/dist/types/store/next/target.d.ts +99 -0
  36. package/dist/types/store/store.d.ts +26 -101
  37. package/dist/types/store/utils.d.ts +0 -40
  38. package/dist/types-cjs/core/core.d.cts +8 -0
  39. package/dist/types-cjs/core/dev.d.cts +1 -1
  40. package/dist/types-cjs/core/scheduler.d.cts +4 -2
  41. package/dist/types-cjs/signals.d.cts +19 -0
  42. package/dist/types-cjs/store/index.d.cts +15 -5
  43. package/dist/types-cjs/store/next/optimistic.d.cts +20 -0
  44. package/dist/types-cjs/store/next/projection.d.cts +24 -0
  45. package/dist/types-cjs/store/next/reconcile.d.cts +3 -0
  46. package/dist/types-cjs/store/next/store.d.cts +71 -0
  47. package/dist/types-cjs/store/next/target.d.cts +99 -0
  48. package/dist/types-cjs/store/store.d.cts +26 -101
  49. package/dist/types-cjs/store/utils.d.cts +0 -40
  50. package/package.json +2 -1
  51. package/dist/prod/store/optimistic.js +0 -217
  52. package/dist/prod/store/projection.js +0 -231
  53. package/dist/prod/store/reconcile.js +0 -707
@@ -1,20 +1,20 @@
1
- import { STATUS_UNINITIALIZED, STATUS_ERROR, STATUS_PENDING, REACTIVE_DIRTY, REACTIVE_OPTIMISTIC_DIRTY, NOT_PENDING, CONFIG_AUTO_DISPOSE, REACTIVE_ZOMBIE } from "./constants.js";
1
+ import { STATUS_UNINITIALIZED, STATUS_ERROR, STATUS_PENDING, REACTIVE_DIRTY, REACTIVE_OPTIMISTIC_DIRTY, NOT_PENDING, CONFIG_AUTO_DISPOSE, REACTIVE_ZOMBIE, REACTIVE_DISPOSED } from "./constants.js";
2
2
 
3
- import { untrack, context, setSignal } from "./core.js";
3
+ import { untrack, setSignal, context } from "./core.js";
4
4
 
5
5
  import "./invariants.js";
6
6
 
7
- import { NotReadyError, StatusError } from "./error.js";
7
+ import { StatusError, NotReadyError } from "./error.js";
8
8
 
9
9
  import { trimStaleDeps, unobserved } from "./graph.js";
10
10
 
11
11
  import { enqueueSub } from "./heap.js";
12
12
 
13
- import { resolveTransition, hasActiveOverride, assignOrMergeLane, resolveLane } from "./lanes.js";
13
+ import { hasActiveOverride, assignOrMergeLane, resolveLane, resolveTransition } from "./lanes.js";
14
14
 
15
15
  import { cleanup } from "./owner.js";
16
16
 
17
- import { globalQueue, GlobalQueue, schedule, flush, queuePendingNode, insertSubs, clock, currentTransition } from "./scheduler.js";
17
+ import { GlobalQueue, schedule, flush, queuePendingNode, insertSubs, clock, currentTransition, globalQueue } from "./scheduler.js";
18
18
 
19
19
  // The lazily-created Set is the ONE container for pending sources. Its
20
20
  // predecessor — a singular slot promoted to a Set on the second source —
@@ -45,7 +45,7 @@ function clearPendingSources(e) {
45
45
  * with NO read-visible pending status, no downstream propagation, no
46
46
  * transition, no lane registration. Commit #0 keeps serving.
47
47
  */ function parkLoadingWindow(e, n) {
48
- e.ue = true;
48
+ e.le = true;
49
49
  if (n.source) addPendingSource(e, n.source);
50
50
  // A settled error is the node's answer ("the error stays the answer until
51
51
  // this retry can actually run") — the park must not replace it: reads
@@ -70,10 +70,10 @@ function setPendingError(e, n, t) {
70
70
  }
71
71
 
72
72
  function forEachDependent(e, n) {
73
- for (let t = e.o; t !== null; t = t.le) n(t.fe, t);
73
+ for (let t = e.o; t !== null; t = t.ue) n(t.fe, t);
74
74
  // `?? null`: affects() marks route plain signals (no `_child` slot) through here.
75
75
  for (let t = e.u ?? null; t !== null; t = t.ae) {
76
- for (let e = t.o; e !== null; e = e.le) n(e.fe, e);
76
+ for (let e = t.o; e !== null; e = e.ue) n(e.fe, e);
77
77
  }
78
78
  }
79
79
 
@@ -145,35 +145,35 @@ function settlePendingSource(e) {
145
145
  const r = new Set;
146
146
  // Companion updates no-op without the verdict layer (null hook).
147
147
  const o = GlobalQueue.Se;
148
- const settle = u => {
149
- if (r.has(u) || !removePendingSource(u, e)) return;
150
- r.add(u);
151
- u.de = clock;
152
- const i = u.oe?.values().next().value;
148
+ const settle = l => {
149
+ if (r.has(l) || !removePendingSource(l, e)) return;
150
+ r.add(l);
151
+ l.de = clock;
152
+ const u = l.oe?.values().next().value;
153
153
  // STATUS_ERROR + pending sources only coexist via an errored loading
154
154
  // window's park (notifyStatus(STATUS_ERROR) clears pending sources
155
155
  // otherwise): the settled error stays the answer through the settle —
156
156
  // nulling it here would have reads throw `null` until the re-enqueued
157
157
  // retry lands, or lose it entirely if that retry parks again (#2989).
158
- const l = u.S & STATUS_ERROR;
159
- if (i) {
160
- if (!l) setPendingError(u, i);
161
- o !== null && o(u);
158
+ const i = l.S & STATUS_ERROR;
159
+ if (u) {
160
+ if (!i) setPendingError(l, u);
161
+ o !== null && o(l);
162
162
  } else {
163
- u.S &= ~STATUS_PENDING;
164
- if (!l) setPendingError(u);
165
- o !== null && o(u);
166
- if (u.ue) {
167
- enqueueSub(u);
163
+ l.S &= ~STATUS_PENDING;
164
+ if (!i) setPendingError(l);
165
+ o !== null && o(l);
166
+ if (l.le) {
167
+ enqueueSub(l);
168
168
  n = true;
169
169
  }
170
- u.ue = false;
170
+ l.le = false;
171
171
  // Fully settled with nobody watching: release candidate (#2934). Checked
172
172
  // again at release time — deferred so unobserved() can't unlink subs
173
173
  // lists this walk is still iterating.
174
- if (!u.o && u.T & CONFIG_AUTO_DISPOSE) (t ??= []).push(u);
174
+ if (!l.o && l.T & CONFIG_AUTO_DISPOSE) (t ??= []).push(l);
175
175
  }
176
- forEachDependent(u, settle);
176
+ forEachDependent(l, settle);
177
177
  };
178
178
  forEachDependent(e, settle);
179
179
  // Release before the flush schedule below: unobserved() pulls the node back
@@ -203,7 +203,7 @@ function handleAsync(e, n, t) {
203
203
  return n;
204
204
  }
205
205
  e.Te = n;
206
- let u;
206
+ let l;
207
207
  // Settle-time transition re-entry. The loading rail is invisible to
208
208
  // transactions (#2933): a boundary-caught first load never registers as an
209
209
  // async reporter, so its settle — the boundary's fallback -> content
@@ -253,15 +253,15 @@ function handleAsync(e, n, t) {
253
253
  // with the new value, creating a fresh Promise that supersedes this one.
254
254
  if (e.se & (REACTIVE_DIRTY | REACTIVE_OPTIMISTIC_DIRTY)) return;
255
255
  settleTransition();
256
- const u = !!(e.S & STATUS_UNINITIALIZED);
256
+ const l = !!(e.S & STATUS_UNINITIALIZED);
257
257
  trimStaleDeps(e);
258
258
  clearStatus(e);
259
- const i = resolveLane(e);
260
- if (i) i.Ae.delete(e);
259
+ const u = resolveLane(e);
260
+ if (u) u.Ae.delete(e);
261
261
  if (t) {
262
262
  t(r);
263
- if (u) clearStatus(e, true);
264
- } else if (e._e !== undefined) {
263
+ if (l) clearStatus(e, true);
264
+ } else if (e.De !== undefined) {
265
265
  // Optimistic node — resting OR covered by an active override — holds
266
266
  // through the shared pending-node path, exactly like a plain async memo,
267
267
  // so the commit clears STATUS_UNINITIALIZED (#2806) and elevation to
@@ -271,8 +271,8 @@ function handleAsync(e, n, t) {
271
271
  // (A17 — every reader sees the override); the revert reveals whatever
272
272
  // has committed by then, so corrections reveal atomically with their
273
273
  // transition rather than escaping it.
274
- if (e.De === NOT_PENDING) queuePendingNode(e);
275
- e.De = r;
274
+ if (e._e === NOT_PENDING) queuePendingNode(e);
275
+ e._e = r;
276
276
  // The hold is a companion-visible write like any other (A13/A19): the
277
277
  // clearStatus() above computed its verdict before the hold existed, so
278
278
  // isPending must re-derive (the value is not final until commit — V1)
@@ -283,14 +283,14 @@ function handleAsync(e, n, t) {
283
283
  GlobalQueue.Pe !== null && GlobalQueue.Pe(e, r);
284
284
  if (!hasActiveOverride(e)) insertSubs(e);
285
285
  e.de = clock;
286
- } else if (i) {
286
+ } else if (u) {
287
287
  // Route through lane's effect queue for independent flushing
288
288
  const n = e.Re;
289
- const t = e.Ue;
290
- const o = e.be;
289
+ const t = e.be;
290
+ const o = e.Ue;
291
291
  try {
292
- if (!n && u || !o || !o(r, t)) {
293
- e.Ue = r;
292
+ if (!n && l || !o || !o(r, t)) {
293
+ e.be = r;
294
294
  e.de = clock;
295
295
  // The latest() shadow write gives latest() effects independent lanes; the
296
296
  // _pendingSignal update is a no-op repeat of the clearStatus() call above
@@ -320,7 +320,7 @@ function handleAsync(e, n, t) {
320
320
  // held-value branch is window-gated, and commitPendingNode closes the
321
321
  // window when the hold commits, so no one-frame isPending pulse can leak
322
322
  // to live observers between the landing and its commit (#2990).
323
- if (e.De === NOT_PENDING) e.Ee = false;
323
+ if (e._e === NOT_PENDING) e.Ee = false;
324
324
  settlePendingSource(e);
325
325
  schedule();
326
326
  flush();
@@ -340,94 +340,68 @@ function handleAsync(e, n, t) {
340
340
  }
341
341
  return false;
342
342
  };
343
- if (o) {
344
- let t = false, r = false, o, i = true;
345
- n.then(e => {
346
- if (i) {
347
- u = e;
348
- t = true;
349
- } else {
350
- asyncWrite(e);
351
- settleAutodispose();
352
- }
353
- }, e => {
354
- if (i) {
355
- o = e;
356
- r = true;
357
- } else {
358
- handleError(e);
359
- settleAutodispose();
360
- }
361
- });
362
- i = false;
363
- if (r) {
364
- // Settle through the same status path an async rejection uses, then
365
- // unwind the in-progress synchronous read so the errored node isn't
366
- // momentarily read as `undefined`.
367
- handleError(o);
368
- throw o;
369
- } else if (!t) {
370
- // Loading window: serve commit #0 instead of suspending. No transition
371
- // is opened — first-flight work on a loadingValue node is loading-class
372
- // (invisible to boundaries and transitions); the flight itself is
373
- // already registered in _inFlight and lands through asyncWrite.
374
- if (e.Ee) return e.Ue;
375
- globalQueue.initTransition(resolveTransition(e));
376
- throw new NotReadyError(context);
377
- } else {
378
- // Synchronously-resolved promise: the first real answer landed.
379
- e.Ee = false;
380
- }
381
- }
382
- if (r) {
383
- const t = n[Symbol.asyncIterator]();
384
- let r = false;
385
- let o = false;
386
- let i = true;
387
- cleanup(() => {
388
- if (o) return;
389
- o = true;
343
+ // Consumes an AsyncIterable as this flight's value stream. Two postures:
344
+ // LIVE (called synchronously from this read the compute returned an
345
+ // iterable directly, or a sync-settled thenable held one), where the
346
+ // initial drain may stash a sync first yield for the caller to return and
347
+ // close registration uses the ambient owner; and DEFERRED (the flattening
348
+ // path — a thenable resolved to an iterable in a later microtask), where
349
+ // there is no caller to serve and no ambient owner: sync-settled steps
350
+ // write through asyncWrite, and close registration goes through the slot
351
+ // the thenable branch pre-registered while it still owned the context.
352
+ // Returns whether a sync answer landed (first yield or empty completion) —
353
+ // meaningful only in the live posture.
354
+ const consumeIterator = (t, r) => {
355
+ const o = t[Symbol.asyncIterator]();
356
+ let u = false;
357
+ let i = false;
358
+ let s = !r;
359
+ const close = () => {
360
+ if (i) return;
361
+ i = true;
390
362
  try {
391
- const e = t.return?.();
363
+ const e = o.return?.();
392
364
  if (isThenable(e)) e.then(undefined, () => {});
393
365
  } catch {}
394
- });
366
+ };
367
+ r ? r(close) : cleanup(close);
395
368
  // Release check before each next pull: an unobserved lazy node must tear
396
- // down (its cleanup above closes the iterator) instead of pumping the
397
- // stream forever with zero subscribers (#2935).
369
+ // down (its close above runs via disposal, closing the iterator) instead
370
+ // of pumping the stream forever with zero subscribers (#2935).
398
371
  const iterateOrRelease = () => {
399
372
  if (!settleAutodispose()) iterate();
400
373
  };
401
374
  const iterate = () => {
402
- let l, s, f = false, a = false, c = true;
375
+ let t, r, f = false, a = false, c = true;
403
376
  // Protocol tolerance, matching `for await`: `await` unwraps whatever
404
377
  // next() returns — a thenable OR a bare IteratorResult. Real producers
405
378
  // use the bare form as a promise-free fast path when a value is already
406
379
  // buffered (seroval's deserialized streams do), so a bare result is
407
380
  // assimilated as an already-settled step instead of crashing on `.then`.
408
- const S = t.next();
381
+ const S = o.next();
409
382
  const d = isThenable(S) ? S : {
410
383
  then: e => void e(S)
411
384
  };
412
- d.then(t => {
385
+ d.then(r => {
413
386
  // The sync stash only serves the INITIAL drain (handleAsync's caller
414
387
  // consumes syncValue / throws NotReady from it). A sync-settled step
415
388
  // after an async gap — seroval buffering values between pulls, a
416
389
  // sync-thenable producer mid-stream — has no caller reading the
417
390
  // stash: it must write through the async path or the value is
418
- // silently dropped.
419
- if (c && i) {
420
- l = t;
391
+ // silently dropped. (The deferred posture never has a caller, so
392
+ // initialRead starts false there and everything writes through.)
393
+ if (c && s) {
394
+ t = r;
421
395
  f = true;
422
- if (t.done) o = true;
396
+ if (r.done) i = true;
423
397
  } else if (e.Te !== n) {
424
398
  return;
425
- } else if (!t.done) {
426
- r = true;
427
- asyncWrite(t.value, iterateOrRelease);
399
+ } else if (!r.done) {
400
+ u = true;
401
+ asyncWrite(r.value, iterateOrRelease);
428
402
  } else {
429
- o = true;
430
- if (r) {
403
+ i = true;
404
+ if (u) {
431
405
  schedule();
432
406
  flush();
433
407
  } else {
@@ -437,11 +411,11 @@ function handleAsync(e, n, t) {
437
411
  settleAutodispose();
438
412
  }
439
413
  }, t => {
440
- if (c) {
441
- s = t;
414
+ if (c && s) {
415
+ r = t;
442
416
  a = true;
443
417
  } else if (e.Te === n) {
444
- o = true;
418
+ i = true;
445
419
  handleError(t);
446
420
  settleAutodispose();
447
421
  }
@@ -449,24 +423,104 @@ function handleAsync(e, n, t) {
449
423
  c = false;
450
424
  if (a) {
451
425
  // Match the promise branch, but only rethrow during the initial read.
452
- o = true;
453
- handleError(s);
454
- if (i) throw s;
426
+ i = true;
427
+ handleError(r);
428
+ if (s) throw r;
455
429
  return true;
456
430
  }
457
- if (f && !l.done) {
458
- u = l.value;
459
- r = true;
431
+ if (f && !t.done) {
432
+ l = t.value;
433
+ u = true;
460
434
  return iterate();
461
435
  }
462
- return f && l.done;
436
+ return f && t.done;
463
437
  };
464
- const l = iterate();
438
+ const f = iterate();
465
439
  // Later iterate() calls run from asyncWrite, where rethrowing would be unhandled.
466
- i = false;
467
- if (!r && !l) {
440
+ s = false;
441
+ return u || f;
442
+ };
443
+ // Landed-synchronously verdict for a LIVE iterator drain; null when no live
444
+ // drain ran (plain promise flight, or a deferred flatten). Drives the
445
+ // shared NotReady/loading tail below.
446
+ let u = null;
447
+ // Flatten one async level: a thenable that RESOLVES to an AsyncIterable —
448
+ // the shape every async stub returning a stream produces — consumes as the
449
+ // stream itself rather than settling on the iterable object. One level
450
+ // only: A+ `then` already collapses nested thenables, so the resolved
451
+ // value is never itself a thenable.
452
+ const flattenIfIterable = (e, n) => {
453
+ let t = false;
454
+ if (typeof e === "object" && e !== null) {
455
+ untrack(() => {
456
+ t = e[Symbol.asyncIterator];
457
+ });
458
+ }
459
+ if (!t) return false;
460
+ const r = consumeIterator(e, n);
461
+ if (!n) u = r;
462
+ return true;
463
+ };
464
+ if (o) {
465
+ let t = false, r = false, o, u = true;
466
+ // Close registration for the flattening path. Consumption starts in a
467
+ // microtask where the ambient owner is gone (or worse, someone else's),
468
+ // so `cleanup()` can't be used — the close targets el's disposal list
469
+ // directly, exactly where a live cleanup() during this recompute would
470
+ // have put it. Deliberately NOT pre-registered at flight start: a
471
+ // non-null `_disposal` reclassifies the node into recompute's deferred
472
+ // (zombie) disposal path, and plain promise flights — the overwhelming
473
+ // majority — must not pay that. Only a flight that actually flattens
474
+ // becomes disposal-bearing, which is exactly the class a directly
475
+ // returned iterable already occupies.
476
+ const registerDeferredClose = n => {
477
+ if (!e.he) e.he = n; else if (Array.isArray(e.he)) e.he.push(n); else e.he = [ e.he, n ];
478
+ };
479
+ n.then(r => {
480
+ if (u) {
481
+ l = r;
482
+ t = true;
483
+ } else if (e.Te === n && !(e.se & REACTIVE_DISPOSED) && flattenIfIterable(r, registerDeferredClose)) ; else {
484
+ asyncWrite(r);
485
+ settleAutodispose();
486
+ }
487
+ }, e => {
488
+ if (u) {
489
+ o = e;
490
+ r = true;
491
+ } else {
492
+ handleError(e);
493
+ settleAutodispose();
494
+ }
495
+ });
496
+ u = false;
497
+ if (r) {
498
+ // Settle through the same status path an async rejection uses, then
499
+ // unwind the in-progress synchronous read so the errored node isn't
500
+ // momentarily read as `undefined`.
501
+ handleError(o);
502
+ throw o;
503
+ } else if (!t) {
504
+ // Loading window: serve commit #0 instead of suspending. No transition
505
+ // is opened — first-flight work on a loadingValue node is loading-class
506
+ // (invisible to boundaries and transitions); the flight itself is
507
+ // already registered in _inFlight and lands through asyncWrite.
508
+ if (e.Ee) return e.be;
509
+ globalQueue.initTransition(resolveTransition(e));
510
+ throw new NotReadyError(context);
511
+ } else if (!flattenIfIterable(l)) {
512
+ // Synchronously-resolved promise: the first real answer landed.
513
+ e.Ee = false;
514
+ }
515
+ // A sync-resolved promise holding an AsyncIterable flattened LIVE (we
516
+ // are still inside the synchronous read): full initial-drain semantics
517
+ // apply and the shared tail below settles the verdict.
518
+ }
519
+ if (r) flattenIfIterable(n);
520
+ if (u !== null) {
521
+ if (!u) {
468
522
  // Loading window: serve commit #0 (see the promise branch above).
469
- if (e.Ee) return e.Ue;
523
+ if (e.Ee) return e.be;
470
524
  globalQueue.initTransition(resolveTransition(e));
471
525
  throw new NotReadyError(context);
472
526
  }
@@ -474,52 +528,52 @@ function handleAsync(e, n, t) {
474
528
  // answer; async yields clear inside asyncWrite.
475
529
  e.Ee = false;
476
530
  }
477
- return u;
531
+ return l;
478
532
  }
479
533
 
480
534
  function clearStatus(e, n = false) {
481
535
  if (e.oe) clearPendingSources(e);
482
- if (e.ue) e.ue = false;
536
+ if (e.le) e.le = false;
483
537
  // The pending window is over; its quiet classification dies with it.
484
538
  // (Unconditional: _reask is baked into the node literals, so this is a
485
539
  // plain store to an existing slot — no shape change.)
486
- e.he = false;
540
+ e.pe = false;
487
541
  e.S = n ? 0 : e.S & STATUS_UNINITIALIZED;
488
542
  if (e._) setPendingError(e);
489
543
  // Update pending signal for isPending() reactivity (companions only exist
490
544
  // once the verdict layer created them, which installs the hooks).
491
- if (e.ge || e.pe) GlobalQueue.Se(e);
492
- if (e.u && GlobalQueue.Oe !== null) GlobalQueue.Oe(e);
545
+ if (e.Oe || e.ge) GlobalQueue.Se(e);
546
+ if (e.u && GlobalQueue.Ge !== null) GlobalQueue.Ge(e);
493
547
  if (e.i) e.i();
494
548
  }
495
549
 
496
550
  function notifyStatus(e, n, t, r, o) {
497
551
  // Wrap regular errors to track source node
498
552
  if (n === STATUS_ERROR && !(t instanceof StatusError) && !(t instanceof NotReadyError)) t = new StatusError(e, t);
499
- const u = n === STATUS_PENDING && t instanceof NotReadyError ? t.source : undefined;
500
- const i = u === e;
501
- const l = n === STATUS_PENDING && e._e !== undefined && !i;
502
- const s = l && hasActiveOverride(e);
553
+ const l = n === STATUS_PENDING && t instanceof NotReadyError ? t.source : undefined;
554
+ const u = l === e;
555
+ const i = n === STATUS_PENDING && e.De !== undefined && !u;
556
+ const s = i && hasActiveOverride(e);
503
557
  if (!r) {
504
- if (n === STATUS_PENDING && u) {
505
- addPendingSource(e, u);
558
+ if (n === STATUS_PENDING && l) {
559
+ addPendingSource(e, l);
506
560
  e.S = STATUS_PENDING | e.S & STATUS_UNINITIALIZED;
507
561
  // Preserve the current source on this propagation so render-effect notification
508
562
  // can register every distinct pending source with the transition.
509
- setPendingError(e, u, t);
563
+ setPendingError(e, l, t);
510
564
  } else {
511
565
  clearPendingSources(e);
512
566
  e.S = n | (n !== STATUS_ERROR ? e.S & STATUS_UNINITIALIZED : 0);
513
567
  e._ = t;
514
568
  }
515
569
  GlobalQueue.Se !== null && GlobalQueue.Se(e);
516
- if (e.u && GlobalQueue.Oe !== null) GlobalQueue.Oe(e);
570
+ if (e.u && GlobalQueue.Ge !== null) GlobalQueue.Ge(e);
517
571
  }
518
572
  if (o && !r) {
519
573
  assignOrMergeLane(e, o);
520
574
  }
521
575
  const f = r || s;
522
- const a = r || l ? undefined : o;
576
+ const a = r || i ? undefined : o;
523
577
  if (e.i) {
524
578
  if (r && n === STATUS_PENDING) {
525
579
  return;
@@ -533,13 +587,13 @@ function notifyStatus(e, n, t, r, o) {
533
587
  }
534
588
  forEachDependent(e, (e, r) => {
535
589
  e.de = clock;
536
- if (n === STATUS_PENDING && u && !e.oe?.has(u) || n !== STATUS_PENDING && (e._ !== t || e.oe)) {
590
+ if (n === STATUS_PENDING && l && !e.oe?.has(l) || n !== STATUS_PENDING && (e._ !== t || e.oe)) {
537
591
  // A pending-observer link is the subscription an `isPending` read created.
538
592
  // It exists so the observer re-runs when the source settles, but it must
539
593
  // not carry a real (non-NotReadyError) error — the synchronous `isPending`
540
594
  // read swallows those, and the async path must match. Re-run the observer
541
595
  // so `isPending` re-evaluates (to not-pending) instead of forwarding.
542
- if (r.Ge && n !== STATUS_PENDING && !(t instanceof NotReadyError)) {
596
+ if (r.ye && n !== STATUS_PENDING && !(t instanceof NotReadyError)) {
543
597
  enqueueSub(e);
544
598
  schedule();
545
599
  return;