@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,6 +1,6 @@
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
- import { ext, statusNotifierOf, untrack, context, setSignal } from "./core.js";
3
+ import { ext, statusNotifierOf, context, untrack, setSignal } from "./core.js";
4
4
 
5
5
  import { StatusError, NotReadyError } from "./error.js";
6
6
 
@@ -8,7 +8,7 @@ import { unobserved, trimStaleDeps } from "./graph.js";
8
8
 
9
9
  import { enqueueSub } from "./heap.js";
10
10
 
11
- import { cleanup } from "./owner.js";
11
+ import { disposeChildren, cleanup } from "./owner.js";
12
12
 
13
13
  import { passLane, joinFuture, question, MAINLINE_QUESTION, globalQueue, schedule, clock, flush, freshHook, txOf, laneStageHook, queuePendingNode } from "./scheduler.js";
14
14
 
@@ -17,16 +17,16 @@ import { passLane, joinFuture, question, MAINLINE_QUESTION, globalQueue, schedul
17
17
  // created dual state whose migration invariant was easy to break: a third
18
18
  // overlapping source landed beside the Set and removePendingSource refused
19
19
  // to clear it, stranding the Set members' pending forever (#2893).
20
- function addPendingSource(e, t) {
21
- if (e.T?.fe?.has(t)) return false;
22
- (ext(e).fe ??= new Set).add(t);
20
+ function addPendingSource(e, n) {
21
+ if (e.T?.fe?.has(n)) return false;
22
+ (ext(e).fe ??= new NewSet).add(n);
23
23
  return true;
24
24
  }
25
25
 
26
- function removePendingSource(e, t) {
27
- const n = e.T?.fe;
28
- if (!n?.delete(t)) return false;
29
- if (!n.size) e.T.fe = undefined;
26
+ function removePendingSource(e, n) {
27
+ const t = e.T?.fe;
28
+ if (!t?.delete(n)) return false;
29
+ if (!t.size) e.T.fe = undefined;
30
30
  return true;
31
31
  }
32
32
 
@@ -41,10 +41,10 @@ function clearPendingSources(e) {
41
41
  // edge: a dep that IS the source, or one whose own pending chain carries it
42
42
  // (pending sources propagate the origin node, so this covers any depth).
43
43
  // Also guards branch-local recovery: another dependency may still need the source.
44
- function retryReaches(e, t) {
45
- for (let n = e.C; n; n = n.G) {
46
- const e = n.S;
47
- if (e === t || e.T?.fe?.has(t)) return true;
44
+ function retryReaches(e, n) {
45
+ for (let t = e.C; t; t = t.G) {
46
+ const e = t.S;
47
+ if (e === n || e.T?.fe?.has(n)) return true;
48
48
  }
49
49
  return false;
50
50
  }
@@ -55,33 +55,33 @@ function retryReaches(e, t) {
55
55
  * settlePendingSource walk runs off `_pendingSources` + `_blocked` alone —
56
56
  * with NO read-visible pending status and no downstream propagation. Commit
57
57
  * #0 keeps serving.
58
- */ function parkLoadingWindow(e, t) {
59
- ext(e).ue = true;
60
- if (t.source) addPendingSource(e, t.source);
58
+ */ function parkLoadingWindow(e, n) {
59
+ ext(e).se = true;
60
+ if (n.source) addPendingSource(e, n.source);
61
61
  // A settled error is the node's answer ("the error stays the answer until
62
62
  // this retry can actually run") — the park must not replace it: reads
63
63
  // throw `_error` while STATUS_ERROR is set, and overwriting it here leaks
64
64
  // a pending-class NotReadyError from a read-invisible park (#2989).
65
- if (!(e.m & STATUS_ERROR)) setPendingError(e, t.source, t);
65
+ if (!(e.m & STATUS_ERROR)) setPendingError(e, n.source, n);
66
66
  }
67
67
 
68
- function setPendingError(e, t, n) {
69
- if (!t) {
68
+ function setPendingError(e, n, t) {
69
+ if (!n) {
70
70
  if (e.T !== null) e.T.F = null;
71
71
  return;
72
72
  }
73
- if (n instanceof NotReadyError && n.source === t) {
74
- ext(e).F = n;
73
+ if (t instanceof NotReadyError && t.source === n) {
74
+ ext(e).F = t;
75
75
  return;
76
76
  }
77
77
  const r = e.T?.F;
78
- if (!(r instanceof NotReadyError) || r.source !== t) {
79
- ext(e).F = new NotReadyError(t);
78
+ if (!(r instanceof NotReadyError) || r.source !== n) {
79
+ ext(e).F = new NotReadyError(n);
80
80
  }
81
81
  }
82
82
 
83
- function forEachDependent(e, t) {
84
- for (let n = e.o; n !== null; n = n.t) t(n.u, n);
83
+ function forEachDependent(e, n) {
84
+ for (let t = e.o; t !== null; t = t.t) n(t.u, t);
85
85
  }
86
86
 
87
87
  // Queue a node to re-run on the next flush (used both when a pending source
@@ -103,16 +103,16 @@ function releaseIfSettledUnobserved(e) {
103
103
  // the propagation completes, walk the same graph for stranded lazy nodes.
104
104
  // Collect-then-release so unobserved() never unlinks under the walk.
105
105
  function releaseSettledDependents(e) {
106
- let t;
107
- const n = new Set;
106
+ let n;
107
+ const t = new NewSet;
108
108
  const visit = e => {
109
- if (n.has(e)) return;
110
- n.add(e);
111
- if (!e.o && e.l & CONFIG_AUTO_DISPOSE) (t ??= []).push(e);
109
+ if (t.has(e)) return;
110
+ t.add(e);
111
+ if (!e.o && e.l & CONFIG_AUTO_DISPOSE) (n ??= []).push(e);
112
112
  forEachDependent(e, visit);
113
113
  };
114
114
  forEachDependent(e, visit);
115
- if (t) for (const e of t) releaseIfSettledUnobserved(e);
115
+ if (n) for (const e of n) releaseIfSettledUnobserved(e);
116
116
  }
117
117
 
118
118
  // Error-dimension twin of settlePendingSource's blocked re-enqueue (#2949):
@@ -137,7 +137,7 @@ function releaseSettledDependents(e) {
137
137
  * it through the ordinary error path (`commitPendingNode` → `notifyStatus`),
138
138
  * dependents included. Not for a lane pass, nor a node with no shown value
139
139
  * (born held — its error has no frame to wait behind): those publish now,
140
- * as before. Returns whether the error was staged. */ function stageError(e, t, n) {
140
+ * as before. Returns whether the error was staged. */ function stageError(e, n, t) {
141
141
  // Held, or — for a pass's own throw — derived from a staging of a flush
142
142
  // (REACTIVE_STAGED_READ is this pass's; a landing after the pass cannot
143
143
  // read it, the flush it read a staging of has committed or parked since).
@@ -146,13 +146,13 @@ function releaseSettledDependents(e) {
146
146
  // (#4109). A flush that parks nothing publishes it at its commit (S-38).
147
147
  // Not a projection's derive: its readers learn its error through the
148
148
  // family, which the commit's publish never reaches (#4189).
149
- if (!(e.l & CONFIG_HELD || n && e.R & REACTIVE_STAGED_READ && globalQueue.q && !e.fam) || passLane) return false;
149
+ if (!(e.l & CONFIG_HELD || t && e.R & REACTIVE_STAGED_READ && globalQueue.q && !e.fam) || passLane) return false;
150
150
  // The node answered (an error ends the wait — no longer pending, nor
151
151
  // blocked); a shown error stays its display until the commit.
152
152
  clearPendingSources(e);
153
- if (e.T) e.T.ue = false;
153
+ if (e.T) e.T.se = false;
154
154
  if (!((e.m &= STATUS_ERROR | STATUS_UNINITIALIZED) & STATUS_ERROR)) setPendingError(e);
155
- e.se = t instanceof StatusError ? t : new StatusError(e, t);
155
+ e.ue = n instanceof StatusError ? n : new StatusError(e, n);
156
156
  e.l |= CONFIG_STAGED | CONFIG_STAGED_ERROR;
157
157
  // Readers parked on the flight re-run and derive from the staging; the
158
158
  // verdict readers the walk wakes need a flush (#4106).
@@ -161,34 +161,34 @@ function releaseSettledDependents(e) {
161
161
  return true;
162
162
  }
163
163
 
164
- function settleErroredDependents(e, t) {
165
- let n = false;
166
- const r = new Set;
164
+ function settleErroredDependents(e, n) {
165
+ let t = false;
166
+ const r = new NewSet;
167
167
  const visit = e => {
168
168
  if (r.has(e)) return;
169
169
  r.add(e);
170
- if (e.T?.F === t) {
170
+ if (e.T?.F === n) {
171
171
  enqueueSub(e);
172
- n = true;
172
+ t = true;
173
173
  }
174
174
  forEachDependent(e, visit);
175
175
  };
176
176
  forEachDependent(e, visit);
177
- if (n) schedule();
177
+ if (t) schedule();
178
178
  }
179
179
 
180
180
  // Retire `source` from pending state along the dependent graph rooted at `el`.
181
181
  // By default, `el` is the source whose flight settled or was superseded.
182
182
  // With a distinct `source`, `el` is a recovered computation that dropped it:
183
183
  // the source may still be pending, so dependents with another path to it stay pending.
184
- function settlePendingSource(e, t = e) {
184
+ function settlePendingSource(e, n = e) {
185
185
  // Landing and branch recovery already cleared el's own set. Superseded
186
186
  // re-parks can retain an abandoned self entry (source === el), which must
187
187
  // retire in the same walk as its propagated copies.
188
- removePendingSource(e, t);
189
- let n = false;
188
+ removePendingSource(e, n);
189
+ let t = false;
190
190
  let r;
191
- const o = new Set;
191
+ const o = new NewSet;
192
192
  const settle = f => {
193
193
  if (o.has(f) ||
194
194
  // A conditional dropped this source, but another dependency can still
@@ -197,7 +197,7 @@ function settlePendingSource(e, t = e) {
197
197
  // carrying dependency may itself be a later branch of this same walk
198
198
  // (two unchanged memos converging), and its visit must be free to
199
199
  // re-examine this node once that branch has retired the source.
200
- t !== e && retryReaches(f, t) || !removePendingSource(f, t))
200
+ n !== e && retryReaches(f, n) || !removePendingSource(f, n))
201
201
  // A19: a verdict reader holds no pending of its own (it was re-derived
202
202
  // when the source went pending, `propagateStatus`), and a landing
203
203
  // equal to the committed value notifies nobody — the source settling
@@ -205,28 +205,28 @@ function settlePendingSource(e, t = e) {
205
205
  return f.l & CONFIG_VERDICT && enqueueSub(f);
206
206
  o.add(f);
207
207
  f.ie = clock;
208
- const u = f.T?.fe?.values().next().value;
208
+ const s = f.T?.fe?.values().next().value;
209
209
  // STATUS_ERROR + pending sources only coexist via an errored loading
210
210
  // window's park (notifyStatus(STATUS_ERROR) clears pending sources
211
211
  // otherwise): the settled error stays the answer through the settle —
212
212
  // nulling it here would have reads throw `null` until the re-enqueued
213
213
  // retry lands, or lose it entirely if that retry parks again (#2989).
214
- const s = f.m & STATUS_ERROR;
215
- if (u) {
216
- if (!s) setPendingError(f, u);
214
+ const u = f.m & STATUS_ERROR;
215
+ if (s) {
216
+ if (!u) setPendingError(f, s);
217
217
  } else {
218
218
  f.m &= ~STATUS_PENDING;
219
- if (!s) setPendingError(f);
219
+ if (!u) setPendingError(f);
220
220
  // L2: a landing resumes the transaction waiting on it (maintainer: "it
221
221
  // resumes the sync frame") — a held reader's re-pass over the landed
222
222
  // value is that transaction's work, and the flush that carries it
223
223
  // parks into it.
224
224
  if (f.l & CONFIG_HELD) joinFuture(txOf(f));
225
- if (f.T?.ue) {
225
+ if (f.T?.se) {
226
226
  enqueueSub(f);
227
- n = true;
227
+ t = true;
228
228
  }
229
- if (f.T !== null) f.T.ue = false;
229
+ if (f.T !== null) f.T.se = false;
230
230
  // Fully settled with nobody watching: release candidate (#2934). Checked
231
231
  // again at release time — deferred so unobserved() can't unlink subs
232
232
  // lists this walk is still iterating.
@@ -238,7 +238,7 @@ function settlePendingSource(e, t = e) {
238
238
  // Release before the flush schedule below: unobserved() pulls the node back
239
239
  // out of the heap, so the enqueueSub above never recomputes a released node.
240
240
  if (r) for (const e of r) releaseIfSettledUnobserved(e);
241
- if (n) schedule();
241
+ if (t) schedule();
242
242
  }
243
243
 
244
244
  // Object-thenable detection (Promises/A+ shape).
@@ -247,14 +247,42 @@ function isThenable(e) {
247
247
  }
248
248
 
249
249
  /** Fire and clear a node's iterator-flight cancellation hook (#3122). */ function releaseFlightTeardown(e) {
250
- const t = e.T?.ae;
251
- if (t != null) {
250
+ const n = e.T?.ae;
251
+ if (n != null) {
252
252
  e.T.ae = null;
253
- t();
253
+ n();
254
254
  }
255
255
  }
256
256
 
257
- function handleAsync(e, t, n,
257
+ /**
258
+ * Internal (not a package export): run `fn` when the current pass's flight
259
+ * is superseded, at the same instant as the iterator close above, instead of
260
+ * when the replacing pass commits (owner cleanups wait for that). Chains onto
261
+ * the node's teardown slot; fires once with it. A no-op unless the ambient
262
+ * owner is a computed in its own pass. `consumeIterator` fills the slot
263
+ * before its first pull, so a source opened in an async generator's body
264
+ * (`for await`) composes after the generator's close.
265
+ */ function onSupersede(e) {
266
+ const n = context;
267
+ if (n === null || n.X === undefined || !(n.R & REACTIVE_RECOMPUTING_DEPS)) return;
268
+ const t = n.T === null;
269
+ const r = ext(n);
270
+ // Allocating the extension mid-run turns `_x?._inFlight` from undefined into
271
+ // null, which recompute would read as a flight this body registered itself.
272
+ // Restore undefined here, so the fix costs nothing for code that never
273
+ // calls onSupersede.
274
+ if (t) r.Se = undefined;
275
+ const o = r.ae;
276
+ r.ae = o === null ? e : () => {
277
+ try {
278
+ o();
279
+ } finally {
280
+ e();
281
+ }
282
+ };
283
+ }
284
+
285
+ function handleAsync(e, n, t,
258
286
  // The flight rejected (after the node's status is set): a projection
259
287
  // tells its leaves' readers, who are not the node's dependents
260
288
  // (store/projection.ts). `pending`: a NotReady rejection — the node is
@@ -262,24 +290,24 @@ function handleAsync(e, t, n,
262
290
  r) {
263
291
  let o = false;
264
292
  let f = false;
265
- if (typeof t === "object" && t !== null) {
293
+ if (typeof n === "object" && n !== null) {
266
294
  untrack(() => {
267
- o = t[Symbol.asyncIterator];
268
- f = !o && isThenable(t);
295
+ o = n[Symbol.asyncIterator];
296
+ f = !o && isThenable(n);
269
297
  });
270
298
  }
271
299
  if (!f && !o) {
272
300
  if (e.T !== null) e.T.Se = null;
273
301
  // A sync landing is the first real answer for a loadingValue node.
274
302
  e.ce = false;
275
- return t;
303
+ return n;
276
304
  }
277
305
  // Flight replacement relies on recompute's supersede release for iterator
278
306
  // teardown (#3122): every handleAsync call — including the projection
279
307
  // self-registration — runs during a recompute of `el`, which has already
280
308
  // fired _flightTeardown. A future non-recompute registration path must
281
309
  // release it here before overwriting _inFlight.
282
- ext(e).Se = t;
310
+ ext(e).Se = n;
283
311
  // The question this flight answers (A18 provenance, lanes.ts): the action
284
312
  // whose slice asked it; mainline is always the current question.
285
313
  e.T.Ee = question || MAINLINE_QUESTION;
@@ -290,9 +318,9 @@ r) {
290
318
  // The landing retires only the flight's own entry (landStatus, #3373), so
291
319
  // an entry that survived here would hold the node past its own answer.
292
320
  e.T.fe = undefined;
293
- let u;
321
+ let s;
294
322
  const handleError = o => {
295
- if (e.T?.Se !== t) return;
323
+ if (e.T?.Se !== n) return;
296
324
  // NotReadyError from rejected promises should be treated as pending, not error
297
325
  let f = o instanceof NotReadyError;
298
326
  if (f && e.ce) {
@@ -308,7 +336,14 @@ r) {
308
336
  // D-41: a held node's error is staged (`stageError`). A derived store's
309
337
  // readers learn its error through the family, not the derive's
310
338
  // dependents: it publishes now.
311
- if (f || n || !stageError(e, o)) notifyStatus(e, f ? STATUS_PENDING : STATUS_ERROR, o);
339
+ if (f || t || !stageError(e, o)) {
340
+ notifyStatus(e, f ? STATUS_PENDING : STATUS_ERROR, o);
341
+ // The error is this pass's answer, published now: it replaces the shown
342
+ // frame as a value's commit would (`commitPendingNode`), so the frame
343
+ // the pass parked goes instead of waiting for a later success. A no-op
344
+ // when nothing is parked.
345
+ if (!f) disposeChildren(e, false, true);
346
+ }
312
347
  // A NotReady rejection is a landing into another pending source. The
313
348
  // rejected flight will never settle its self entry, so transfer ownership
314
349
  // after notifyStatus has propagated the replacement source.
@@ -321,16 +356,16 @@ r) {
321
356
  r?.(o, f);
322
357
  };
323
358
  const asyncWrite = (r, o) => {
324
- if (e.T?.Se !== t) return;
359
+ if (e.T?.Se !== n) return;
325
360
  // If the node was dirtied by a newer write (optimistic override or regular),
326
361
  // skip this stale async result — the upcoming flush will recompute the node
327
362
  // with the new value, creating a fresh Promise that supersedes this one.
328
363
  if (e.R & REACTIVE_DIRTY) return;
329
364
  const f = e.m & STATUS_UNINITIALIZED;
330
365
  landStatus(e);
331
- if (n) {
366
+ if (t) {
332
367
  try {
333
- n(r);
368
+ t(r);
334
369
  } catch (e) {
335
370
  handleError(e);
336
371
  return;
@@ -352,7 +387,7 @@ r) {
352
387
  // (`_pendingValue` set inside setSignal) is not — commitPendingNode closes
353
388
  // the window when the flush commits it, so no one-frame pulse can leak to
354
389
  // observers between the landing and its commit (#2990).
355
- if (e.se === NOT_PENDING) {
390
+ if (e.ue === NOT_PENDING) {
356
391
  e.ce = false;
357
392
  // The landing published: the dependency tail the flight's pass left
358
393
  // linked goes now (A30, #3410). A staged landing has not replaced the
@@ -388,14 +423,14 @@ r) {
388
423
  // write through asyncWrite, and close registration targets `owner` (el
389
424
  // itself) directly. Returns whether a sync answer landed (first yield or
390
425
  // empty completion) — meaningful only in the live posture.
391
- const consumeIterator = (n, r) => {
392
- const o = n[Symbol.asyncIterator]();
426
+ const consumeIterator = (t, r) => {
427
+ const o = t[Symbol.asyncIterator]();
393
428
  let f = false;
394
- let s = false;
429
+ let u = false;
395
430
  let i = !r;
396
431
  const close = () => {
397
- if (s) return;
398
- s = true;
432
+ if (u) return;
433
+ u = true;
399
434
  try {
400
435
  const e = o.return?.();
401
436
  if (isThenable(e)) e.then(undefined, () => {});
@@ -404,7 +439,11 @@ r) {
404
439
  cleanup(close, r);
405
440
  // Flight-identity cancellation (#3122): the registration above is the
406
441
  // owner-death backstop; the teardown slot fires at the _inFlight release
407
- // sites so supersede stops this stream immediately.
442
+ // sites so supersede stops this stream immediately. Assigned, not
443
+ // chained (chaining here costs every app bytes): it replaces any
444
+ // `onSupersede` teardown this run registered earlier, which then falls
445
+ // back to the owner-cleanup channel. A returned `from()` is unaffected:
446
+ // `close` calls its `return()`, which runs its own teardown.
408
447
  ext(e).ae = close;
409
448
  // Release check before each next pull: an unobserved lazy node must tear
410
449
  // down (its close above runs via disposal, closing the iterator) instead
@@ -420,7 +459,7 @@ r) {
420
459
  }
421
460
  };
422
461
  const iterate = () => {
423
- let n, r, l = false, a = false, S = true;
462
+ let t, r, l = false, a = false, S = true;
424
463
  // Protocol tolerance, matching `for await`: `await` unwraps whatever
425
464
  // next() returns — a thenable OR a bare IteratorResult. Real producers
426
465
  // use the bare form as a promise-free fast path when a value is already
@@ -439,16 +478,16 @@ r) {
439
478
  // silently dropped. (The deferred posture never has a caller, so
440
479
  // initialRead starts false there and everything writes through.)
441
480
  if (S && i) {
442
- n = r;
481
+ t = r;
443
482
  l = true;
444
- if (r.done) s = true;
445
- } else if (e.T?.Se !== t) {
483
+ if (r.done) u = true;
484
+ } else if (e.T?.Se !== n) {
446
485
  return;
447
486
  } else if (!r.done) {
448
487
  f = true;
449
488
  asyncWrite(r.value, iterateOrRelease);
450
489
  } else {
451
- s = true;
490
+ u = true;
452
491
  if (f) {
453
492
  schedule();
454
493
  flush();
@@ -458,30 +497,30 @@ r) {
458
497
  }
459
498
  settleAutodispose();
460
499
  }
461
- }, n => {
500
+ }, t => {
462
501
  if (S && i) {
463
- r = n;
502
+ r = t;
464
503
  a = true;
465
- } else if (e.T?.Se === t) {
466
- s = true;
467
- handleError(n);
504
+ } else if (e.T?.Se === n) {
505
+ u = true;
506
+ handleError(t);
468
507
  settleAutodispose();
469
508
  }
470
509
  });
471
510
  S = false;
472
511
  if (a) {
473
512
  // Match the promise branch, but only rethrow during the initial read.
474
- s = true;
513
+ u = true;
475
514
  handleError(r);
476
515
  if (i) throw r;
477
516
  return true;
478
517
  }
479
- if (l && !n.done) {
480
- u = n.value;
518
+ if (l && !t.done) {
519
+ s = t.value;
481
520
  f = true;
482
521
  return iterate();
483
522
  }
484
- return l && n.done;
523
+ return l && t.done;
485
524
  };
486
525
  const l = iterate();
487
526
  // Later iterate() calls run from asyncWrite, where rethrowing would be unhandled.
@@ -491,31 +530,31 @@ r) {
491
530
  // Landed-synchronously verdict for a LIVE iterator drain; null when no live
492
531
  // drain ran (plain promise flight, or a deferred flatten). Drives the
493
532
  // shared NotReady/loading tail below.
494
- let s = null;
533
+ let u = null;
495
534
  // Flatten one async level: a thenable that RESOLVES to an AsyncIterable —
496
535
  // the shape every async stub returning a stream produces — consumes as the
497
536
  // stream itself rather than settling on the iterable object. One level
498
537
  // only: A+ `then` already collapses nested thenables, so the resolved
499
538
  // value is never itself a thenable.
500
- const flattenIfIterable = (e, t) => {
501
- let n = false;
539
+ const flattenIfIterable = (e, n) => {
540
+ let t = false;
502
541
  if (typeof e === "object" && e !== null) {
503
542
  untrack(() => {
504
- n = e[Symbol.asyncIterator];
543
+ t = e[Symbol.asyncIterator];
505
544
  });
506
545
  }
507
- if (!n) return false;
508
- u = undefined;
509
- const r = consumeIterator(e, t);
510
- if (!t) s = r;
546
+ if (!t) return false;
547
+ s = undefined;
548
+ const r = consumeIterator(e, n);
549
+ if (!n) u = r;
511
550
  return true;
512
551
  };
513
552
  if (f) {
514
- let n = false, r = false, o, f = true;
515
- t.then(r => {
553
+ let t = false, r = false, o, f = true;
554
+ n.then(r => {
516
555
  if (f) {
517
- u = r;
518
- n = true;
556
+ s = r;
557
+ t = true;
519
558
  } else {
520
559
  // Flattening consumes the stream as the value: each yield lands
521
560
  // through asyncWrite under this flight's identity; the first one
@@ -527,7 +566,7 @@ r) {
527
566
  // compute catch above it: a protocol throw settles as this
528
567
  // flight's error (#4112).
529
568
  try {
530
- if (e.T?.Se === t && !(e.R & REACTIVE_DISPOSED) && flattenIfIterable(r, e)) return;
569
+ if (e.T?.Se === n && !(e.R & REACTIVE_DISPOSED) && flattenIfIterable(r, e)) return;
531
570
  asyncWrite(r);
532
571
  } catch (e) {
533
572
  handleError(e);
@@ -550,14 +589,14 @@ r) {
550
589
  // momentarily read as `undefined`.
551
590
  handleError(o);
552
591
  throw o;
553
- } else if (!n) {
554
- // Loading window: serve commit #0 instead of suspending — first-flight
555
- // work on a loadingValue node is loading-class (invisible to
556
- // boundaries); the flight itself is already registered in _inFlight and
557
- // lands through asyncWrite.
558
- if (e.ce) return e.Ie;
559
- throw new NotReadyError(context);
560
- } else if (!flattenIfIterable(u)) {
592
+ } else if (!t) {
593
+ // Not landed: the shared tail below suspends, or — loading window —
594
+ // serves commit #0 (first-flight work on a loadingValue node is
595
+ // loading-class, invisible to boundaries; the flight itself is already
596
+ // registered in _inFlight and lands through asyncWrite). A promise is
597
+ // never an iterator, so nothing between here and there runs.
598
+ u = false;
599
+ } else if (!flattenIfIterable(s)) {
561
600
  // Synchronously-resolved promise: the first real answer landed.
562
601
  e.ce = false;
563
602
  }
@@ -565,10 +604,10 @@ r) {
565
604
  // are still inside the synchronous read): full initial-drain semantics
566
605
  // apply and the shared tail below settles the verdict.
567
606
  }
568
- if (o) flattenIfIterable(t);
569
- if (s !== null) {
570
- if (!s) {
571
- // Loading window: serve commit #0 (see the promise branch above).
607
+ if (o) flattenIfIterable(n);
608
+ if (u !== null) {
609
+ if (!u) {
610
+ // Loading window: serve commit #0 instead of suspending.
572
611
  if (e.ce) return e.Ie;
573
612
  throw new NotReadyError(context);
574
613
  }
@@ -576,16 +615,16 @@ r) {
576
615
  // answer; async yields clear inside asyncWrite.
577
616
  e.ce = false;
578
617
  }
579
- return u;
618
+ return s;
580
619
  }
581
620
 
582
- function clearStatus(e, t = false) {
621
+ function clearStatus(e, n = false) {
583
622
  if (e.T?.fe) clearPendingSources(e);
584
- if (e.T?.ue) if (e.T !== null) e.T.ue = false;
585
- e.m = t ? 0 : e.m & STATUS_UNINITIALIZED;
623
+ if (e.T?.se) e.T.se = false;
624
+ e.m = n ? 0 : e.m & STATUS_UNINITIALIZED;
586
625
  if (e.T?.F) setPendingError(e);
587
- const n = statusNotifierOf(e);
588
- if (n) n.call(e);
626
+ const t = statusNotifierOf(e);
627
+ if (t) t.call(e);
589
628
  }
590
629
 
591
630
  /**
@@ -612,35 +651,33 @@ function clearStatus(e, t = false) {
612
651
  * the first landing retires UNINITIALIZED. `_error` must move off self: a
613
652
  * reader thrown NotReady(self) would park on a retired entry. Companions
614
653
  * keep their verdict (pending before and after; the write re-syncs them).
615
- */ function landStatus(e, t = false) {
616
- const n = e.T?.fe;
654
+ */ function landStatus(e, n = false) {
655
+ const t = e.T?.fe;
617
656
  // (The full clear below drops the set whether or not self was retired first.)
618
- if (n && (n.delete(e), n.size)) {
619
- e.T.ue = false;
620
- if (t) e.m = STATUS_PENDING;
621
- setPendingError(e, n.values().next().value);
622
- } else clearStatus(e, t);
657
+ if (t && (t.delete(e), t.size)) {
658
+ e.T.se = false;
659
+ if (n) e.m = STATUS_PENDING;
660
+ setPendingError(e, t.values().next().value);
661
+ } else clearStatus(e, n);
623
662
  }
624
663
 
625
- function notifyStatus(e, t, n, r) {
664
+ function notifyStatus(e, n, t) {
626
665
  // Wrap regular errors to track source node
627
- if (t === STATUS_ERROR && !(n instanceof StatusError) && !(n instanceof NotReadyError)) n = new StatusError(e, n);
628
- const o = t === STATUS_PENDING && n instanceof NotReadyError ? n.source : undefined;
666
+ if (n === STATUS_ERROR && !(t instanceof StatusError) && !(t instanceof NotReadyError)) t = new StatusError(e, t);
667
+ const r = n === STATUS_PENDING && t instanceof NotReadyError ? t.source : undefined;
629
668
  // (CARVE 2: the lane assignment went with the engine.)
630
- {
631
- if (t === STATUS_PENDING && o) {
632
- // D-41: a re-ask of a shown error keeps it the display (`_shownError`).
633
- if (e.m & STATUS_ERROR) e.T.de = e.T.F;
634
- addPendingSource(e, o);
635
- e.m = STATUS_PENDING | e.m & STATUS_UNINITIALIZED;
636
- // Preserve the current source on this propagation so readers park on
637
- // the distinct pending source.
638
- setPendingError(e, o, n);
639
- } else {
640
- clearPendingSources(e);
641
- e.m = t | (t !== STATUS_ERROR ? e.m & STATUS_UNINITIALIZED : 0);
642
- ext(e).F = n;
643
- }
669
+ if (n === STATUS_PENDING && r) {
670
+ // D-41: a re-ask of a shown error keeps it the display (`_shownError`).
671
+ if (e.m & STATUS_ERROR) e.T.de = e.T.F;
672
+ addPendingSource(e, r);
673
+ e.m = STATUS_PENDING | e.m & STATUS_UNINITIALIZED;
674
+ // Preserve the current source on this propagation so readers park on
675
+ // the distinct pending source.
676
+ setPendingError(e, r, t);
677
+ } else {
678
+ clearPendingSources(e);
679
+ e.m = n | (n !== STATUS_ERROR ? e.m & STATUS_UNINITIALIZED : 0);
680
+ ext(e).F = t;
644
681
  }
645
682
  // Lanes: a written guess is an optimistic boundary (A17 — "the optimistic
646
683
  // future value until we know otherwise"). Its own source in flight is its
@@ -648,28 +685,26 @@ function notifyStatus(e, t, n, r) {
648
685
  // transition's to wait on — the frame it was asked in holds (A17: "a
649
686
  // transition whose optimistic node is still pending on its own fetch is
650
687
  // not complete"), through the node itself (`blocked`).
651
- if (t === STATUS_PENDING && e.l & CONFIG_GUESS) {
688
+ if (n === STATUS_PENDING && e.l & CONFIG_GUESS) {
652
689
  if (passLane === null) joinFuture(null);
653
690
  return;
654
691
  }
655
- const f = statusNotifierOf(e);
656
- if (f) {
657
- {
658
- f.call(e);
659
- }
692
+ const o = statusNotifierOf(e);
693
+ if (o) {
694
+ o.call(e);
660
695
  return;
661
696
  }
662
- propagateStatus(e, t, n);
697
+ propagateStatus(e, n, t);
663
698
  }
664
699
 
665
700
  /** The dependents' half of `notifyStatus`: `el`'s status reaches each
666
701
  * subscriber as a propagated mark (or a re-derive). On its own for a store
667
702
  * family's leaves, which are not the derive's dependents — the family
668
703
  * propagates the derive's status from each leaf to the leaf's readers
669
- * (store/projection.ts `wakeFamily`), exactly as a memo's would reach its. */ function propagateStatus(e, t, n, r) {
670
- const o = t === STATUS_PENDING && n instanceof NotReadyError ? n.source : undefined;
671
- forEachDependent(e, (r, f) => {
672
- r.ie = clock;
704
+ * (store/projection.ts `wakeFamily`), exactly as a memo's would reach its. */ function propagateStatus(e, n, t) {
705
+ const r = n === STATUS_PENDING && t instanceof NotReadyError ? t.source : undefined;
706
+ forEachDependent(e, (o, f) => {
707
+ o.ie = clock;
673
708
  // A pending mark on a kept-tail link re-derives the subscriber instead of
674
709
  // marking it (A30, #3494 review; fuzzer latest-1 #2141; #3519 review).
675
710
  // Past `_depsTail` lie the committed frame's deps, kept by A30 because
@@ -689,8 +724,8 @@ function notifyStatus(e, t, n, r) {
689
724
  // Inheriting the error would make a probe's reader errored. A boundary's
690
725
  // output (CONFIG_REDERIVE, boundaries.ts) the same: content or fallback
691
726
  // is its pass's call.
692
- if (r.l & (CONFIG_REDERIVE | CONFIG_VERDICT) || t === STATUS_PENDING && f.Te !== r.Ne) {
693
- enqueueSub(r);
727
+ if (o.l & (CONFIG_REDERIVE | CONFIG_VERDICT) || n === STATUS_PENDING && f.Te !== o.Ne) {
728
+ enqueueSub(o);
694
729
  schedule();
695
730
  return;
696
731
  }
@@ -701,30 +736,28 @@ function notifyStatus(e, t, n, r) {
701
736
  // frame still passes through — its pass is the frame's (#3372, compiled
702
737
  // shape: the unmount it stages makes the observer a zombie whose say is
703
738
  // moot for this transaction, A15 #3463).
704
- if (t === STATUS_PENDING && o && r.T?.fe?.has(o)) {
705
- if (passLane === null && (r.l & (CONFIG_HELD | CONFIG_OVERRIDE)) === CONFIG_HELD && globalQueue.q && !freshHook?.(r, o.ie === clock)) joinFuture(txOf(r));
739
+ if (n === STATUS_PENDING && r && o.T?.fe?.has(r)) {
740
+ if (passLane === null && (o.l & (CONFIG_HELD | CONFIG_OVERRIDE)) === CONFIG_HELD && globalQueue.q && !freshHook?.(o, r.ie === clock)) joinFuture(txOf(o));
706
741
  return;
707
742
  }
708
- if (t === STATUS_PENDING && o || t !== STATUS_PENDING && (r.T?.F !== n || r.T?.fe)) {
743
+ if (n === STATUS_PENDING && r || n !== STATUS_PENDING && (o.T?.F !== t || o.T?.fe)) {
709
744
  // The marked subscriber is queued for the commit sweep so its status
710
745
  // bookkeeping (loading window, uninitialized clear) runs with the flush
711
746
  // — with the lane, when the pass propagating is the lane's work and
712
747
  // the dependent's pending is the lane's own flight (`laneStage`).
713
- {
714
- // (No answer: a pending propagation leaves a written guess a guess.)
715
- if (laneStageHook && passLane !== null) laneStageHook(r, passLane, true, e); else {
716
- queuePendingNode(r);
717
- // A15 (#3443): pending propagates onto a held memo without
718
- // recomputing it, and the propagation itself enters the memo's
719
- // transaction — the flight flows into a memo that transaction
720
- // holds, so the write that started it is held with it. A render
721
- // effect's membership is its pass's (`notify`), never sticky.
722
- if (t === STATUS_PENDING && (r.l & (CONFIG_HELD | CONFIG_OVERRIDE)) === CONFIG_HELD && !r.i) joinFuture(txOf(r));
723
- }
748
+ // (No answer: a pending propagation leaves a written guess a guess.)
749
+ if (laneStageHook && passLane !== null) laneStageHook(o, passLane, true, e); else {
750
+ queuePendingNode(o);
751
+ // A15 (#3443): pending propagates onto a held memo without
752
+ // recomputing it, and the propagation itself enters the memo's
753
+ // transaction — the flight flows into a memo that transaction
754
+ // holds, so the write that started it is held with it. A render
755
+ // effect's membership is its pass's (`notify`), never sticky.
756
+ if (n === STATUS_PENDING && (o.l & (CONFIG_HELD | CONFIG_OVERRIDE)) === CONFIG_HELD && !o.i) joinFuture(txOf(o));
724
757
  }
725
- notifyStatus(r, t, n);
758
+ notifyStatus(o, n, t);
726
759
  }
727
760
  });
728
761
  }
729
762
 
730
- export { addPendingSource, clearStatus, forEachDependent, handleAsync, isThenable, notifyStatus, parkLoadingWindow, propagateStatus, releaseFlightTeardown, releaseIfSettledUnobserved, releaseSettledDependents, setPendingError, settleErroredDependents, settlePendingSource, stageError };
763
+ export { addPendingSource, clearStatus, forEachDependent, handleAsync, isThenable, notifyStatus, onSupersede, parkLoadingWindow, propagateStatus, releaseFlightTeardown, releaseIfSettledUnobserved, releaseSettledDependents, setPendingError, settleErroredDependents, settlePendingSource, stageError };