@solidjs/signals 2.0.0-rc.17 → 2.0.0-rc.18

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 (40) hide show
  1. package/dist/dev-shared.js +296 -191
  2. package/dist/dev.attribution.js +16 -16
  3. package/dist/dev.js +527 -311
  4. package/dist/observe/core/async.js +148 -115
  5. package/dist/observe/core/constants.js +3 -1
  6. package/dist/observe/core/core.js +27 -27
  7. package/dist/observe/core/effect.js +29 -32
  8. package/dist/observe/core/graph.js +5 -5
  9. package/dist/observe/core/owner.js +7 -7
  10. package/dist/observe/core/scheduler.js +23 -12
  11. package/dist/observe/core/verdict.js +2 -2
  12. package/dist/observe/deferred.js +16 -13
  13. package/dist/observe/from.js +248 -0
  14. package/dist/observe/index.js +2 -0
  15. package/dist/observe/store/reconcile.js +137 -121
  16. package/dist/observe/store/store.js +595 -618
  17. package/dist/observe/store/target.js +1 -5
  18. package/dist/prod/core/async.js +209 -176
  19. package/dist/prod/core/constants.js +3 -1
  20. package/dist/prod/core/core.js +33 -33
  21. package/dist/prod/core/effect.js +24 -27
  22. package/dist/prod/core/graph.js +2 -2
  23. package/dist/prod/core/lanes.js +14 -14
  24. package/dist/prod/core/scheduler.js +35 -24
  25. package/dist/prod/core/truth.js +4 -4
  26. package/dist/prod/core/verdict.js +7 -7
  27. package/dist/prod/deferred.js +17 -14
  28. package/dist/prod/from.js +248 -0
  29. package/dist/prod/index.js +2 -0
  30. package/dist/prod/store/optimistic.js +1 -1
  31. package/dist/prod/store/reconcile.js +137 -121
  32. package/dist/prod/store/store.js +94 -117
  33. package/dist/prod/store/target.js +13 -17
  34. package/dist/types/core/async.d.ts +12 -2
  35. package/dist/types/core/constants.d.ts +5 -0
  36. package/dist/types/core/core.d.ts +19 -3
  37. package/dist/types/core/scheduler.d.ts +15 -3
  38. package/dist/types/from.d.ts +47 -0
  39. package/dist/types/index.d.ts +1 -0
  40. package/package.json +1 -1
@@ -1,8 +1,8 @@
1
- import { STATUS_ERROR, STATUS_PENDING, STATUS_UNINITIALIZED, CONFIG_GUESS, CONFIG_HELD, REACTIVE_STAGED_READ, CONFIG_STAGED, CONFIG_STAGED_ERROR, CONFIG_AUTO_DISPOSE, REACTIVE_ZOMBIE, REACTIVE_DIRTY, NOT_PENDING, REACTIVE_DISPOSED, CONFIG_REDERIVE, CONFIG_VERDICT, CONFIG_OVERRIDE } from "./constants.js";
1
+ import { STATUS_ERROR, STATUS_PENDING, STATUS_UNINITIALIZED, CONFIG_GUESS, REACTIVE_RECOMPUTING_DEPS, CONFIG_HELD, REACTIVE_STAGED_READ, CONFIG_STAGED, CONFIG_STAGED_ERROR, CONFIG_AUTO_DISPOSE, REACTIVE_ZOMBIE, NewSet, REACTIVE_DIRTY, NOT_PENDING, REACTIVE_DISPOSED, CONFIG_REDERIVE, CONFIG_VERDICT, CONFIG_OVERRIDE } from "./constants.js";
2
2
 
3
3
  import { attrHooks } from "./attribution-hooks.js";
4
4
 
5
- import { ext, statusNotifierOf, untrack, context, setSignal } from "./core.js";
5
+ import { ext, statusNotifierOf, context, untrack, setSignal } from "./core.js";
6
6
 
7
7
  import "./dev.js";
8
8
 
@@ -12,7 +12,7 @@ import { unobserved, trimStaleDeps } from "./graph.js";
12
12
 
13
13
  import { enqueueSub } from "./heap.js";
14
14
 
15
- import { cleanup } from "./owner.js";
15
+ import { disposeChildren, cleanup } from "./owner.js";
16
16
 
17
17
  import { passLane, joinFuture, question, MAINLINE_QUESTION, globalQueue, schedule, clock, flush, freshHook, txOf, laneStageHook, queuePendingNode } from "./scheduler.js";
18
18
 
@@ -22,22 +22,22 @@ import { passLane, joinFuture, question, MAINLINE_QUESTION, globalQueue, schedul
22
22
  // overlapping source landed beside the Set and removePendingSource refused
23
23
  // to clear it, stranding the Set members' pending forever (#2893).
24
24
  function addPendingSource(e, t) {
25
- if (e.T?.fe?.has(t)) return false;
26
- (ext(e).fe ??= new Set).add(t);
25
+ if (e.T?.se?.has(t)) return false;
26
+ (ext(e).se ??= new NewSet).add(t);
27
27
  return true;
28
28
  }
29
29
 
30
30
  function removePendingSource(e, t) {
31
- const n = e.T?.fe;
31
+ const n = e.T?.se;
32
32
  if (!n?.delete(t)) return false;
33
- if (!n.size) e.T.fe = undefined;
33
+ if (!n.size) e.T.se = undefined;
34
34
  return true;
35
35
  }
36
36
 
37
37
  function clearPendingSources(e) {
38
38
  // This set is node-owned and never shared; dropping the sole reference
39
39
  // releases the set and every entry without a redundant clear() walk.
40
- if (e.T !== null) e.T.fe = undefined;
40
+ if (e.T !== null) e.T.se = undefined;
41
41
  }
42
42
 
43
43
  // A rejection-pending only resolves through the settle sweep over the
@@ -48,7 +48,7 @@ function clearPendingSources(e) {
48
48
  function retryReaches(e, t) {
49
49
  for (let n = e.C; n; n = n.G) {
50
50
  const e = n.S;
51
- if (e === t || e.T?.fe?.has(t)) return true;
51
+ if (e === t || e.T?.se?.has(t)) return true;
52
52
  }
53
53
  return false;
54
54
  }
@@ -60,7 +60,7 @@ function retryReaches(e, t) {
60
60
  * with NO read-visible pending status and no downstream propagation. Commit
61
61
  * #0 keeps serving.
62
62
  */ function parkLoadingWindow(e, t) {
63
- ext(e).se = true;
63
+ ext(e).fe = true;
64
64
  if (t.source) addPendingSource(e, t.source);
65
65
  // A settled error is the node's answer ("the error stays the answer until
66
66
  // this retry can actually run") — the park must not replace it: reads
@@ -108,7 +108,7 @@ function releaseIfSettledUnobserved(e) {
108
108
  // Collect-then-release so unobserved() never unlinks under the walk.
109
109
  function releaseSettledDependents(e) {
110
110
  let t;
111
- const n = new Set;
111
+ const n = new NewSet;
112
112
  const visit = e => {
113
113
  if (n.has(e)) return;
114
114
  n.add(e);
@@ -154,7 +154,7 @@ function releaseSettledDependents(e) {
154
154
  // The node answered (an error ends the wait — no longer pending, nor
155
155
  // blocked); a shown error stays its display until the commit.
156
156
  clearPendingSources(e);
157
- if (e.T) e.T.se = false;
157
+ if (e.T) e.T.fe = false;
158
158
  if (!((e.m &= STATUS_ERROR | STATUS_UNINITIALIZED) & STATUS_ERROR)) setPendingError(e);
159
159
  e.ue = t instanceof StatusError ? t : new StatusError(e, t);
160
160
  e.l |= CONFIG_STAGED | CONFIG_STAGED_ERROR;
@@ -167,7 +167,7 @@ function releaseSettledDependents(e) {
167
167
 
168
168
  function settleErroredDependents(e, t) {
169
169
  let n = false;
170
- const r = new Set;
170
+ const r = new NewSet;
171
171
  const visit = e => {
172
172
  if (r.has(e)) return;
173
173
  r.add(e);
@@ -192,51 +192,51 @@ function settlePendingSource(e, t = e) {
192
192
  removePendingSource(e, t);
193
193
  let n = false;
194
194
  let r;
195
- const o = new Set;
196
- const settle = f => {
197
- if (o.has(f) ||
195
+ const o = new NewSet;
196
+ const settle = s => {
197
+ if (o.has(s) ||
198
198
  // A conditional dropped this source, but another dependency can still
199
199
  // carry it. Only retire pending state inherited through the recovered
200
200
  // branch. Deliberately NOT marked visited on this early return: the
201
201
  // carrying dependency may itself be a later branch of this same walk
202
202
  // (two unchanged memos converging), and its visit must be free to
203
203
  // re-examine this node once that branch has retired the source.
204
- t !== e && retryReaches(f, t) || !removePendingSource(f, t))
204
+ t !== e && retryReaches(s, t) || !removePendingSource(s, t))
205
205
  // A19: a verdict reader holds no pending of its own (it was re-derived
206
206
  // when the source went pending, `propagateStatus`), and a landing
207
207
  // equal to the committed value notifies nobody — the source settling
208
208
  // is its verdict changing: it runs again.
209
- return f.l & CONFIG_VERDICT && enqueueSub(f);
210
- o.add(f);
211
- f.ie = clock;
212
- const s = f.T?.fe?.values().next().value;
209
+ return s.l & CONFIG_VERDICT && enqueueSub(s);
210
+ o.add(s);
211
+ s.ie = clock;
212
+ const f = s.T?.se?.values().next().value;
213
213
  // STATUS_ERROR + pending sources only coexist via an errored loading
214
214
  // window's park (notifyStatus(STATUS_ERROR) clears pending sources
215
215
  // otherwise): the settled error stays the answer through the settle —
216
216
  // nulling it here would have reads throw `null` until the re-enqueued
217
217
  // retry lands, or lose it entirely if that retry parks again (#2989).
218
- const u = f.m & STATUS_ERROR;
219
- if (s) {
220
- if (!u) setPendingError(f, s);
218
+ const u = s.m & STATUS_ERROR;
219
+ if (f) {
220
+ if (!u) setPendingError(s, f);
221
221
  } else {
222
- f.m &= ~STATUS_PENDING;
223
- if (!u) setPendingError(f);
222
+ s.m &= ~STATUS_PENDING;
223
+ if (!u) setPendingError(s);
224
224
  // L2: a landing resumes the transaction waiting on it (maintainer: "it
225
225
  // resumes the sync frame") — a held reader's re-pass over the landed
226
226
  // value is that transaction's work, and the flush that carries it
227
227
  // parks into it.
228
- if (f.l & CONFIG_HELD) joinFuture(txOf(f));
229
- if (f.T?.se) {
230
- enqueueSub(f);
228
+ if (s.l & CONFIG_HELD) joinFuture(txOf(s));
229
+ if (s.T?.fe) {
230
+ enqueueSub(s);
231
231
  n = true;
232
232
  }
233
- if (f.T !== null) f.T.se = false;
233
+ if (s.T !== null) s.T.fe = false;
234
234
  // Fully settled with nobody watching: release candidate (#2934). Checked
235
235
  // again at release time — deferred so unobserved() can't unlink subs
236
236
  // lists this walk is still iterating.
237
- if (!f.o && f.l & CONFIG_AUTO_DISPOSE) (r ??= []).push(f);
237
+ if (!s.o && s.l & CONFIG_AUTO_DISPOSE) (r ??= []).push(s);
238
238
  }
239
- forEachDependent(f, settle);
239
+ forEachDependent(s, settle);
240
240
  };
241
241
  forEachDependent(e, settle);
242
242
  // Release before the flush schedule below: unobserved() pulls the node back
@@ -258,6 +258,34 @@ function isThenable(e) {
258
258
  }
259
259
  }
260
260
 
261
+ /**
262
+ * Internal (not a package export): run `fn` when the current pass's flight
263
+ * is superseded, at the same instant as the iterator close above, instead of
264
+ * when the replacing pass commits (owner cleanups wait for that). Chains onto
265
+ * the node's teardown slot; fires once with it. A no-op unless the ambient
266
+ * owner is a computed in its own pass. `consumeIterator` fills the slot
267
+ * before its first pull, so a source opened in an async generator's body
268
+ * (`for await`) composes after the generator's close.
269
+ */ function onSupersede(e) {
270
+ const t = context;
271
+ if (t === null || t.X === undefined || !(t.R & REACTIVE_RECOMPUTING_DEPS)) return;
272
+ const n = t.T === null;
273
+ const r = ext(t);
274
+ // Allocating the extension mid-run turns `_x?._inFlight` from undefined into
275
+ // null, which recompute would read as a flight this body registered itself.
276
+ // Restore undefined here, so the fix costs nothing for code that never
277
+ // calls onSupersede.
278
+ if (n) r.Se = undefined;
279
+ const o = r.ae;
280
+ r.ae = o === null ? e : () => {
281
+ try {
282
+ o();
283
+ } finally {
284
+ e();
285
+ }
286
+ };
287
+ }
288
+
261
289
  function handleAsync(e, t, n,
262
290
  // The flight rejected (after the node's status is set): a projection
263
291
  // tells its leaves' readers, who are not the node's dependents
@@ -265,14 +293,14 @@ function handleAsync(e, t, n,
265
293
  // pending on another source, not errored.
266
294
  r) {
267
295
  let o = false;
268
- let f = false;
296
+ let s = false;
269
297
  if (typeof t === "object" && t !== null) {
270
298
  untrack(() => {
271
299
  o = t[Symbol.asyncIterator];
272
- f = !o && isThenable(t);
300
+ s = !o && isThenable(t);
273
301
  });
274
302
  }
275
- if (!f && !o) {
303
+ if (!s && !o) {
276
304
  if (e.T !== null) e.T.Se = null;
277
305
  // A sync landing is the first real answer for a loadingValue node.
278
306
  e.ce = false;
@@ -293,19 +321,19 @@ r) {
293
321
  // describe this answer. Drop it — the flight is the node's pending now.
294
322
  // The landing retires only the flight's own entry (landStatus, #3373), so
295
323
  // an entry that survived here would hold the node past its own answer.
296
- e.T.fe = undefined;
324
+ e.T.se = undefined;
297
325
  // Attribution hook: a new flight is registered. Fired here (not in the
298
326
  // branches below) so every flight shape — plain thenable, iterator, the
299
327
  // flattened combinations — is announced exactly once, while the recompute
300
328
  // frame that caused it is still on the engine's stack. Not inside a try
301
329
  // (#2883 — see attribution-hooks.ts).
302
330
  if (attrHooks !== null) attrHooks.flightStart(e, t);
303
- let s;
331
+ let f;
304
332
  const handleError = o => {
305
333
  if (e.T?.Se !== t) return;
306
334
  // NotReadyError from rejected promises should be treated as pending, not error
307
- let f = o instanceof NotReadyError;
308
- if (f && e.ce) {
335
+ let s = o instanceof NotReadyError;
336
+ if (s && e.ce) {
309
337
  // Loading window: the flight died waiting on an unready source. Keep
310
338
  // serving commit #0 — same parking as recompute's catch for sync
311
339
  // dependency throws. The dead flight is released so the clock-gated
@@ -318,17 +346,24 @@ r) {
318
346
  // D-41: a held node's error is staged (`stageError`). A derived store's
319
347
  // readers learn its error through the family, not the derive's
320
348
  // dependents: it publishes now.
321
- if (f || n || !stageError(e, o)) notifyStatus(e, f ? STATUS_PENDING : STATUS_ERROR, o);
349
+ if (s || n || !stageError(e, o)) {
350
+ notifyStatus(e, s ? STATUS_PENDING : STATUS_ERROR, o);
351
+ // The error is this pass's answer, published now: it replaces the shown
352
+ // frame as a value's commit would (`commitPendingNode`), so the frame
353
+ // the pass parked goes instead of waiting for a later success. A no-op
354
+ // when nothing is parked.
355
+ if (!s) disposeChildren(e, false, true);
356
+ }
322
357
  // A NotReady rejection is a landing into another pending source. The
323
358
  // rejected flight will never settle its self entry, so transfer ownership
324
359
  // after notifyStatus has propagated the replacement source.
325
- if (f) settlePendingSource(e);
360
+ if (s) settlePendingSource(e);
326
361
  e.ie = clock;
327
362
  // A real error settles derivatively-pending dependents (notifyStatus
328
363
  // cleared their pending sources), so stranded lazy ones release here —
329
364
  // the error twin of settlePendingSource's release (#2934).
330
- if (!f) releaseSettledDependents(e);
331
- r?.(o, f);
365
+ if (!s) releaseSettledDependents(e);
366
+ r?.(o, s);
332
367
  };
333
368
  const asyncWrite = (r, o) => {
334
369
  if (e.T?.Se !== t) return;
@@ -336,7 +371,7 @@ r) {
336
371
  // skip this stale async result — the upcoming flush will recompute the node
337
372
  // with the new value, creating a fresh Promise that supersedes this one.
338
373
  if (e.R & REACTIVE_DIRTY) return;
339
- const f = e.m & STATUS_UNINITIALIZED;
374
+ const s = e.m & STATUS_UNINITIALIZED;
340
375
  landStatus(e);
341
376
  // Attribution hook: lets the engine snapshot state before the landing
342
377
  // branches, so it can tell whether the plain path's setSignal committed a
@@ -352,7 +387,7 @@ r) {
352
387
  // A store derive's landing commits through its setter: unheld, the
353
388
  // shown error leaves now; held, at the derive's commit.
354
389
  if (!(e.l & CONFIG_HELD)) e.T.de = undefined;
355
- if (f) landStatus(e, true);
390
+ if (s) landStatus(e, true);
356
391
  // Attribution hook: this path landed through the setter (derived
357
392
  // stores, projections), which does not go through setSignal, so the
358
393
  // plain branch's asyncEnd never ran and the flight stayed open — the
@@ -419,7 +454,7 @@ r) {
419
454
  // empty completion) — meaningful only in the live posture.
420
455
  const consumeIterator = (n, r) => {
421
456
  const o = n[Symbol.asyncIterator]();
422
- let f = false;
457
+ let s = false;
423
458
  let u = false;
424
459
  let i = !r;
425
460
  const close = () => {
@@ -433,7 +468,11 @@ r) {
433
468
  cleanup(close, r);
434
469
  // Flight-identity cancellation (#3122): the registration above is the
435
470
  // owner-death backstop; the teardown slot fires at the _inFlight release
436
- // sites so supersede stops this stream immediately.
471
+ // sites so supersede stops this stream immediately. Assigned, not
472
+ // chained (chaining here costs every app bytes): it replaces any
473
+ // `onSupersede` teardown this run registered earlier, which then falls
474
+ // back to the owner-cleanup channel. A returned `from()` is unaffected:
475
+ // `close` calls its `return()`, which runs its own teardown.
437
476
  ext(e).ae = close;
438
477
  // Release check before each next pull: an unobserved lazy node must tear
439
478
  // down (its close above runs via disposal, closing the iterator) instead
@@ -474,11 +513,11 @@ r) {
474
513
  } else if (e.T?.Se !== t) {
475
514
  return;
476
515
  } else if (!r.done) {
477
- f = true;
516
+ s = true;
478
517
  asyncWrite(r.value, iterateOrRelease);
479
518
  } else {
480
519
  u = true;
481
- if (f) {
520
+ if (s) {
482
521
  schedule();
483
522
  flush();
484
523
  } else {
@@ -506,8 +545,8 @@ r) {
506
545
  return true;
507
546
  }
508
547
  if (l && !n.done) {
509
- s = n.value;
510
- f = true;
548
+ f = n.value;
549
+ s = true;
511
550
  return iterate();
512
551
  }
513
552
  return l && n.done;
@@ -515,7 +554,7 @@ r) {
515
554
  const l = iterate();
516
555
  // Later iterate() calls run from asyncWrite, where rethrowing would be unhandled.
517
556
  i = false;
518
- return f || l;
557
+ return s || l;
519
558
  };
520
559
  // Landed-synchronously verdict for a LIVE iterator drain; null when no live
521
560
  // drain ran (plain promise flight, or a deferred flatten). Drives the
@@ -534,16 +573,16 @@ r) {
534
573
  });
535
574
  }
536
575
  if (!n) return false;
537
- s = undefined;
576
+ f = undefined;
538
577
  const r = consumeIterator(e, t);
539
578
  if (!t) u = r;
540
579
  return true;
541
580
  };
542
- if (f) {
543
- let n = false, r = false, o, f = true;
581
+ if (s) {
582
+ let n = false, r = false, o, s = true;
544
583
  t.then(r => {
545
- if (f) {
546
- s = r;
584
+ if (s) {
585
+ f = r;
547
586
  n = true;
548
587
  } else {
549
588
  // Flattening consumes the stream as the value: each yield lands
@@ -564,7 +603,7 @@ r) {
564
603
  settleAutodispose();
565
604
  }
566
605
  }, e => {
567
- if (f) {
606
+ if (s) {
568
607
  o = e;
569
608
  r = true;
570
609
  } else {
@@ -572,7 +611,7 @@ r) {
572
611
  settleAutodispose();
573
612
  }
574
613
  });
575
- f = false;
614
+ s = false;
576
615
  if (r) {
577
616
  // Settle through the same status path an async rejection uses, then
578
617
  // unwind the in-progress synchronous read so the errored node isn't
@@ -580,13 +619,13 @@ r) {
580
619
  handleError(o);
581
620
  throw o;
582
621
  } else if (!n) {
583
- // Loading window: serve commit #0 instead of suspending — first-flight
584
- // work on a loadingValue node is loading-class (invisible to
585
- // boundaries); the flight itself is already registered in _inFlight and
586
- // lands through asyncWrite.
587
- if (e.ce) return e.Ie;
588
- throw new NotReadyError(context);
589
- } else if (!flattenIfIterable(s)) {
622
+ // Not landed: the shared tail below suspends, or — loading window —
623
+ // serves commit #0 (first-flight work on a loadingValue node is
624
+ // loading-class, invisible to boundaries; the flight itself is already
625
+ // registered in _inFlight and lands through asyncWrite). A promise is
626
+ // never an iterator, so nothing between here and there runs.
627
+ u = false;
628
+ } else if (!flattenIfIterable(f)) {
590
629
  // Synchronously-resolved promise: the first real answer landed.
591
630
  e.ce = false;
592
631
  }
@@ -597,7 +636,7 @@ r) {
597
636
  if (o) flattenIfIterable(t);
598
637
  if (u !== null) {
599
638
  if (!u) {
600
- // Loading window: serve commit #0 (see the promise branch above).
639
+ // Loading window: serve commit #0 instead of suspending.
601
640
  if (e.ce) return e.Ie;
602
641
  throw new NotReadyError(context);
603
642
  }
@@ -605,12 +644,12 @@ r) {
605
644
  // answer; async yields clear inside asyncWrite.
606
645
  e.ce = false;
607
646
  }
608
- return s;
647
+ return f;
609
648
  }
610
649
 
611
650
  function clearStatus(e, t = false) {
612
- if (e.T?.fe) clearPendingSources(e);
613
- if (e.T?.se) if (e.T !== null) e.T.se = false;
651
+ if (e.T?.se) clearPendingSources(e);
652
+ if (e.T?.fe) e.T.fe = false;
614
653
  e.m = t ? 0 : e.m & STATUS_UNINITIALIZED;
615
654
  if (e.T?.F) setPendingError(e);
616
655
  const n = statusNotifierOf(e);
@@ -642,34 +681,32 @@ function clearStatus(e, t = false) {
642
681
  * reader thrown NotReady(self) would park on a retired entry. Companions
643
682
  * keep their verdict (pending before and after; the write re-syncs them).
644
683
  */ function landStatus(e, t = false) {
645
- const n = e.T?.fe;
684
+ const n = e.T?.se;
646
685
  // (The full clear below drops the set whether or not self was retired first.)
647
686
  if (n && (n.delete(e), n.size)) {
648
- e.T.se = false;
687
+ e.T.fe = false;
649
688
  if (t) e.m = STATUS_PENDING;
650
689
  setPendingError(e, n.values().next().value);
651
690
  } else clearStatus(e, t);
652
691
  }
653
692
 
654
- function notifyStatus(e, t, n, r) {
693
+ function notifyStatus(e, t, n) {
655
694
  // Wrap regular errors to track source node
656
695
  if (t === STATUS_ERROR && !(n instanceof StatusError) && !(n instanceof NotReadyError)) n = new StatusError(e, n);
657
- const o = t === STATUS_PENDING && n instanceof NotReadyError ? n.source : undefined;
696
+ const r = t === STATUS_PENDING && n instanceof NotReadyError ? n.source : undefined;
658
697
  // (CARVE 2: the lane assignment went with the engine.)
659
- {
660
- if (t === STATUS_PENDING && o) {
661
- // D-41: a re-ask of a shown error keeps it the display (`_shownError`).
662
- if (e.m & STATUS_ERROR) e.T.de = e.T.F;
663
- addPendingSource(e, o);
664
- e.m = STATUS_PENDING | e.m & STATUS_UNINITIALIZED;
665
- // Preserve the current source on this propagation so readers park on
666
- // the distinct pending source.
667
- setPendingError(e, o, n);
668
- } else {
669
- clearPendingSources(e);
670
- e.m = t | (t !== STATUS_ERROR ? e.m & STATUS_UNINITIALIZED : 0);
671
- ext(e).F = n;
672
- }
698
+ if (t === STATUS_PENDING && r) {
699
+ // D-41: a re-ask of a shown error keeps it the display (`_shownError`).
700
+ if (e.m & STATUS_ERROR) e.T.de = e.T.F;
701
+ addPendingSource(e, r);
702
+ e.m = STATUS_PENDING | e.m & STATUS_UNINITIALIZED;
703
+ // Preserve the current source on this propagation so readers park on
704
+ // the distinct pending source.
705
+ setPendingError(e, r, n);
706
+ } else {
707
+ clearPendingSources(e);
708
+ e.m = t | (t !== STATUS_ERROR ? e.m & STATUS_UNINITIALIZED : 0);
709
+ ext(e).F = n;
673
710
  }
674
711
  // Lanes: a written guess is an optimistic boundary (A17 — "the optimistic
675
712
  // future value until we know otherwise"). Its own source in flight is its
@@ -681,11 +718,9 @@ function notifyStatus(e, t, n, r) {
681
718
  if (passLane === null) joinFuture(null);
682
719
  return;
683
720
  }
684
- const f = statusNotifierOf(e);
685
- if (f) {
686
- {
687
- f.call(e);
688
- }
721
+ const o = statusNotifierOf(e);
722
+ if (o) {
723
+ o.call(e);
689
724
  return;
690
725
  }
691
726
  propagateStatus(e, t, n);
@@ -695,10 +730,10 @@ function notifyStatus(e, t, n, r) {
695
730
  * subscriber as a propagated mark (or a re-derive). On its own for a store
696
731
  * family's leaves, which are not the derive's dependents — the family
697
732
  * propagates the derive's status from each leaf to the leaf's readers
698
- * (store/projection.ts `wakeFamily`), exactly as a memo's would reach its. */ function propagateStatus(e, t, n, r) {
699
- const o = t === STATUS_PENDING && n instanceof NotReadyError ? n.source : undefined;
700
- forEachDependent(e, (r, f) => {
701
- r.ie = clock;
733
+ * (store/projection.ts `wakeFamily`), exactly as a memo's would reach its. */ function propagateStatus(e, t, n) {
734
+ const r = t === STATUS_PENDING && n instanceof NotReadyError ? n.source : undefined;
735
+ forEachDependent(e, (o, s) => {
736
+ o.ie = clock;
702
737
  // A pending mark on a kept-tail link re-derives the subscriber instead of
703
738
  // marking it (A30, #3494 review; fuzzer latest-1 #2141; #3519 review).
704
739
  // Past `_depsTail` lie the committed frame's deps, kept by A30 because
@@ -718,8 +753,8 @@ function notifyStatus(e, t, n, r) {
718
753
  // Inheriting the error would make a probe's reader errored. A boundary's
719
754
  // output (CONFIG_REDERIVE, boundaries.ts) the same: content or fallback
720
755
  // is its pass's call.
721
- if (r.l & (CONFIG_REDERIVE | CONFIG_VERDICT) || t === STATUS_PENDING && f.Te !== r.Ne) {
722
- enqueueSub(r);
756
+ if (o.l & (CONFIG_REDERIVE | CONFIG_VERDICT) || t === STATUS_PENDING && s.Te !== o.Ne) {
757
+ enqueueSub(o);
723
758
  schedule();
724
759
  return;
725
760
  }
@@ -730,30 +765,28 @@ function notifyStatus(e, t, n, r) {
730
765
  // frame still passes through — its pass is the frame's (#3372, compiled
731
766
  // shape: the unmount it stages makes the observer a zombie whose say is
732
767
  // moot for this transaction, A15 #3463).
733
- if (t === STATUS_PENDING && o && r.T?.fe?.has(o)) {
734
- if (passLane === null && (r.l & (CONFIG_HELD | CONFIG_OVERRIDE)) === CONFIG_HELD && globalQueue.q && !freshHook?.(r, o.ie === clock)) joinFuture(txOf(r));
768
+ if (t === STATUS_PENDING && r && o.T?.se?.has(r)) {
769
+ if (passLane === null && (o.l & (CONFIG_HELD | CONFIG_OVERRIDE)) === CONFIG_HELD && globalQueue.q && !freshHook?.(o, r.ie === clock)) joinFuture(txOf(o));
735
770
  return;
736
771
  }
737
- if (t === STATUS_PENDING && o || t !== STATUS_PENDING && (r.T?.F !== n || r.T?.fe)) {
772
+ if (t === STATUS_PENDING && r || t !== STATUS_PENDING && (o.T?.F !== n || o.T?.se)) {
738
773
  // The marked subscriber is queued for the commit sweep so its status
739
774
  // bookkeeping (loading window, uninitialized clear) runs with the flush
740
775
  // — with the lane, when the pass propagating is the lane's work and
741
776
  // the dependent's pending is the lane's own flight (`laneStage`).
742
- {
743
- // (No answer: a pending propagation leaves a written guess a guess.)
744
- if (laneStageHook && passLane !== null) laneStageHook(r, passLane, true, e); else {
745
- queuePendingNode(r);
746
- // A15 (#3443): pending propagates onto a held memo without
747
- // recomputing it, and the propagation itself enters the memo's
748
- // transaction — the flight flows into a memo that transaction
749
- // holds, so the write that started it is held with it. A render
750
- // effect's membership is its pass's (`notify`), never sticky.
751
- if (t === STATUS_PENDING && (r.l & (CONFIG_HELD | CONFIG_OVERRIDE)) === CONFIG_HELD && !r.i) joinFuture(txOf(r));
752
- }
777
+ // (No answer: a pending propagation leaves a written guess a guess.)
778
+ if (laneStageHook && passLane !== null) laneStageHook(o, passLane, true, e); else {
779
+ queuePendingNode(o);
780
+ // A15 (#3443): pending propagates onto a held memo without
781
+ // recomputing it, and the propagation itself enters the memo's
782
+ // transaction — the flight flows into a memo that transaction
783
+ // holds, so the write that started it is held with it. A render
784
+ // effect's membership is its pass's (`notify`), never sticky.
785
+ if (t === STATUS_PENDING && (o.l & (CONFIG_HELD | CONFIG_OVERRIDE)) === CONFIG_HELD && !o.i) joinFuture(txOf(o));
753
786
  }
754
- notifyStatus(r, t, n);
787
+ notifyStatus(o, t, n);
755
788
  }
756
789
  });
757
790
  }
758
791
 
759
- export { addPendingSource, clearStatus, forEachDependent, handleAsync, isThenable, notifyStatus, parkLoadingWindow, propagateStatus, releaseFlightTeardown, releaseIfSettledUnobserved, releaseSettledDependents, setPendingError, settleErroredDependents, settlePendingSource, stageError };
792
+ export { addPendingSource, clearStatus, forEachDependent, handleAsync, isThenable, notifyStatus, onSupersede, parkLoadingWindow, propagateStatus, releaseFlightTeardown, releaseIfSettledUnobserved, releaseSettledDependents, setPendingError, settleErroredDependents, settlePendingSource, stageError };
@@ -236,4 +236,6 @@ const defaultContext = {};
236
236
  * @internal
237
237
  */ const $REFRESH = Symbol("refresh");
238
238
 
239
- export { $REFRESH, CAUGHT_REARMED, CONFIG_AUTHORITATIVE, CONFIG_AUTO_DISPOSE, CONFIG_CHILDREN_FORBIDDEN, CONFIG_FRESH_READ, CONFIG_GUESS, CONFIG_HAS_SNAPSHOT, CONFIG_HELD, CONFIG_HELD_FRAME, CONFIG_INPUTS_PUBLISHED, CONFIG_IN_SNAPSHOT_SCOPE, CONFIG_LAGS, CONFIG_MANUAL_WRITE, CONFIG_NO_SNAPSHOT, CONFIG_OVERRIDE, CONFIG_OWNED_WRITE, CONFIG_PLUMBING, CONFIG_PROMOTED, CONFIG_REDERIVE, CONFIG_SLOT_NODE, CONFIG_STAGED, CONFIG_STAGED_ERROR, CONFIG_SYNC, CONFIG_TRANSPARENT, CONFIG_VERDICT, EFFECT_RENDER, EFFECT_TRACKED, EFFECT_USER, NOT_PENDING, NO_SNAPSHOT, REACTIVE_CHECK, REACTIVE_DIRTY, REACTIVE_DISPOSED, REACTIVE_FRAME_READ, REACTIVE_IN_HEAP, REACTIVE_IN_HEAP_HEIGHT, REACTIVE_JOINED, REACTIVE_LANE_DIRTY, REACTIVE_LANE_READ, REACTIVE_LAZY, REACTIVE_MANUAL_WRITE, REACTIVE_MISSED_WAKE, REACTIVE_NONE, REACTIVE_PROBED, REACTIVE_PROBE_UNANSWERED, REACTIVE_REASK, REACTIVE_RECOMPUTING_DEPS, REACTIVE_SCREEN_READ, REACTIVE_SNAPSHOT_STALE, REACTIVE_STAGED_READ, REACTIVE_ZOMBIE, STATUS_ERROR, STATUS_NONE, STATUS_PENDING, STATUS_UNINITIALIZED, SUPPORTS_PROXY, defaultContext };
239
+ const NewSet = Set;
240
+
241
+ export { $REFRESH, CAUGHT_REARMED, CONFIG_AUTHORITATIVE, CONFIG_AUTO_DISPOSE, CONFIG_CHILDREN_FORBIDDEN, CONFIG_FRESH_READ, CONFIG_GUESS, CONFIG_HAS_SNAPSHOT, CONFIG_HELD, CONFIG_HELD_FRAME, CONFIG_INPUTS_PUBLISHED, CONFIG_IN_SNAPSHOT_SCOPE, CONFIG_LAGS, CONFIG_MANUAL_WRITE, CONFIG_NO_SNAPSHOT, CONFIG_OVERRIDE, CONFIG_OWNED_WRITE, CONFIG_PLUMBING, CONFIG_PROMOTED, CONFIG_REDERIVE, CONFIG_SLOT_NODE, CONFIG_STAGED, CONFIG_STAGED_ERROR, CONFIG_SYNC, CONFIG_TRANSPARENT, CONFIG_VERDICT, EFFECT_RENDER, EFFECT_TRACKED, EFFECT_USER, NOT_PENDING, NO_SNAPSHOT, NewSet, REACTIVE_CHECK, REACTIVE_DIRTY, REACTIVE_DISPOSED, REACTIVE_FRAME_READ, REACTIVE_IN_HEAP, REACTIVE_IN_HEAP_HEIGHT, REACTIVE_JOINED, REACTIVE_LANE_DIRTY, REACTIVE_LANE_READ, REACTIVE_LAZY, REACTIVE_MANUAL_WRITE, REACTIVE_MISSED_WAKE, REACTIVE_NONE, REACTIVE_PROBED, REACTIVE_PROBE_UNANSWERED, REACTIVE_REASK, REACTIVE_RECOMPUTING_DEPS, REACTIVE_SCREEN_READ, REACTIVE_SNAPSHOT_STALE, REACTIVE_STAGED_READ, REACTIVE_ZOMBIE, STATUS_ERROR, STATUS_NONE, STATUS_PENDING, STATUS_UNINITIALIZED, SUPPORTS_PROXY, defaultContext };