@solidjs/signals 2.0.0-rc.14 → 2.0.0-rc.15

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 (66) hide show
  1. package/dist/dev-shared.js +248 -189
  2. package/dist/dev.attribution.js +124 -41
  3. package/dist/dev.js +553 -322
  4. package/dist/observe/affects.js +34 -31
  5. package/dist/observe/boundaries.js +166 -132
  6. package/dist/observe/core/async.js +90 -83
  7. package/dist/observe/core/attribution-queries.js +1 -1
  8. package/dist/observe/core/attribution.js +281 -197
  9. package/dist/observe/core/constants.js +7 -2
  10. package/dist/observe/core/context.js +3 -3
  11. package/dist/observe/core/core.js +277 -245
  12. package/dist/observe/core/dev.js +3 -3
  13. package/dist/observe/core/effect.js +21 -21
  14. package/dist/observe/core/external.js +2 -2
  15. package/dist/observe/core/graph.js +25 -25
  16. package/dist/observe/core/heap.js +9 -9
  17. package/dist/observe/core/lanes.js +206 -160
  18. package/dist/observe/core/owner.js +27 -27
  19. package/dist/observe/core/scheduler.js +92 -86
  20. package/dist/observe/core/verdict.js +66 -54
  21. package/dist/observe/map.js +35 -35
  22. package/dist/observe/reveal.js +24 -24
  23. package/dist/observe/signals.js +38 -28
  24. package/dist/observe/store/affects.js +75 -68
  25. package/dist/observe/store/hooks.js +13 -0
  26. package/dist/observe/store/index.js +0 -2
  27. package/dist/observe/store/optimistic.js +67 -34
  28. package/dist/observe/store/projection.js +37 -31
  29. package/dist/observe/store/reconcile.js +32 -30
  30. package/dist/observe/store/store.js +128 -85
  31. package/dist/prod/affects.js +34 -31
  32. package/dist/prod/boundaries.js +143 -109
  33. package/dist/prod/core/async.js +64 -67
  34. package/dist/prod/core/constants.js +7 -2
  35. package/dist/prod/core/context.js +3 -3
  36. package/dist/prod/core/core.js +302 -270
  37. package/dist/prod/core/effect.js +38 -38
  38. package/dist/prod/core/external.js +4 -4
  39. package/dist/prod/core/graph.js +27 -27
  40. package/dist/prod/core/heap.js +30 -30
  41. package/dist/prod/core/lanes.js +257 -211
  42. package/dist/prod/core/owner.js +39 -39
  43. package/dist/prod/core/scheduler.js +125 -119
  44. package/dist/prod/core/verdict.js +70 -58
  45. package/dist/prod/map.js +73 -73
  46. package/dist/prod/reveal.js +38 -38
  47. package/dist/prod/signals.js +30 -20
  48. package/dist/prod/store/affects.js +75 -68
  49. package/dist/prod/store/hooks.js +13 -0
  50. package/dist/prod/store/index.js +0 -2
  51. package/dist/prod/store/optimistic.js +114 -81
  52. package/dist/prod/store/projection.js +30 -24
  53. package/dist/prod/store/reconcile.js +32 -30
  54. package/dist/prod/store/store.js +136 -93
  55. package/dist/types/boundaries.d.ts +4 -0
  56. package/dist/types/core/attribution.d.ts +6 -2
  57. package/dist/types/core/constants.d.ts +5 -0
  58. package/dist/types/core/core.d.ts +33 -3
  59. package/dist/types/core/lanes.d.ts +10 -0
  60. package/dist/types/core/scheduler.d.ts +12 -6
  61. package/dist/types/core/types.d.ts +0 -6
  62. package/dist/types/store/affects.d.ts +11 -0
  63. package/dist/types/store/hooks.d.ts +48 -0
  64. package/dist/types/store/index.d.ts +0 -1
  65. package/dist/types/store/store.d.ts +3 -38
  66. package/package.json +1 -1
@@ -1,4 +1,4 @@
1
- import { STATUS_PENDING, STATUS_ERROR, CONFIG_REDERIVE, REACTIVE_DISPOSED, STATUS_UNINITIALIZED, CONFIG_HELD, REACTIVE_ZOMBIE, CONFIG_VERDICT, REACTIVE_LANE_READ, CONFIG_OVERRIDE, EFFECT_USER, EFFECT_TRACKED } from "./core/constants.js";
1
+ import { STATUS_PENDING, STATUS_ERROR, CONFIG_REDERIVE, REACTIVE_DISPOSED, STATUS_UNINITIALIZED, CONFIG_HELD, EFFECT_RENDER, REACTIVE_ZOMBIE, CONFIG_VERDICT, REACTIVE_LANE_READ, CONFIG_OVERRIDE, EFFECT_USER, EFFECT_TRACKED } from "./core/constants.js";
2
2
 
3
3
  import { signal, runWithOwner, computed, read, setSignal, recompute } from "./core/core.js";
4
4
 
@@ -12,7 +12,7 @@ import { link } from "./core/graph.js";
12
12
 
13
13
  import { enqueueSub } from "./core/heap.js";
14
14
 
15
- import { createOwner, getOwner, cleanup } from "./core/owner.js";
15
+ import { createOwner, getOwner, cleanup, dispose } from "./core/owner.js";
16
16
 
17
17
  import { globalQueue, haltReactivity, passLane, joinFuture, GlobalQueue, flushTransaction, schedule, setPassLane, passTx, resolveTx, txOf } from "./core/scheduler.js";
18
18
 
@@ -77,34 +77,34 @@ function setRevealHooks(e) {
77
77
 
78
78
  /** Boundaries with readers to sweep (or an arm to resolve) at the seam. */ const collecting = new Set;
79
79
 
80
- const boundaryOf = e => e.U[BOUNDARY];
80
+ const boundaryOf = e => e.D[BOUNDARY];
81
81
 
82
82
  /** Catches what reaches it: an error boundary always; a loading one until it
83
- * has shown content, or while re-armed. */ const isCollecting = e => e.i === STATUS_ERROR || !e.k || e.L;
83
+ * has shown content, or while re-armed. */ const isCollecting = e => e.u === STATUS_ERROR || !e.h || e.U;
84
84
 
85
85
  /** The reader goes to the fallback: recorded, and the output re-derives
86
86
  * (a no-op while the output's own pass is running — its post-check
87
87
  * decides). */ function caught(e, n, r) {
88
- if (e.i === STATUS_ERROR) {
88
+ if (e.u === STATUS_ERROR) {
89
89
  // An error boundary waits on what THREW (`StatusError.source`), not on
90
90
  // the reader that saw it: the reader recovers the moment a refetch
91
91
  // starts (its boundary catches the pending), while the error is settled
92
92
  // only when its source is neither errored nor in flight. `reset` re-runs
93
93
  // the same node.
94
- r ??= n.m?.v;
94
+ r ??= n.m?.F;
95
95
  n = r?.source ?? n;
96
96
  const t = unwrapStatusError(r);
97
- setSignal(e.v, t);
98
- reportClientError(t, e.H, n);
97
+ setSignal(e.F, t);
98
+ reportClientError(t, e.L, n);
99
99
  }
100
- e.V.add(n);
100
+ e.v.add(n);
101
101
  collecting.add(e);
102
- if (e.L) flip(e);
102
+ if (e.U) flip(e);
103
103
  // Already showing the fallback: one more reader to wait on changes
104
104
  // nothing on screen. The fallback is instantiated once per show — a later
105
105
  // error reaches it through the `error` accessor, which is why it is one.
106
- if (!e.P) redraw(e);
107
- if (e.B !== null) revealHooks.j(e.B);
106
+ if (!e.H) redraw(e);
107
+ if (e.V !== null) revealHooks.P(e.V);
108
108
  }
109
109
 
110
110
  /** A re-armed boundary found something pending: fresh again, and the swap
@@ -112,14 +112,14 @@ const boundaryOf = e => e.U[BOUNDARY];
112
112
  * the lane's work from its next pass's head — not a re-pass of the
113
113
  * transaction holding its pending content, which would entangle that
114
114
  * transaction with the arming frame's (#3540 `on: () => latest(dep)`). */ function flip(e) {
115
- e.k = false;
116
- e.Z = e.W;
117
- if (e.Z !== null && e.K !== null) GlobalQueue.M(e.K, e.Z, true, false);
115
+ e.h = false;
116
+ e.B = e.j;
117
+ if (e.B !== null && e.Z !== null) GlobalQueue.W(e.Z, e.B, true, false);
118
118
  }
119
119
 
120
120
  function redraw(e) {
121
- if (e.K !== null && !(e.K.R & (REACTIVE_DISPOSED | REACTIVE_ZOMBIE))) {
122
- enqueueSub(e.K);
121
+ if (e.Z !== null && !(e.Z.R & (REACTIVE_DISPOSED | REACTIVE_ZOMBIE))) {
122
+ enqueueSub(e.Z);
123
123
  schedule();
124
124
  }
125
125
  }
@@ -135,26 +135,26 @@ function redraw(e) {
135
135
  // held reader's landing has joined its transaction, so the content
136
136
  // lands with its run, not a round after). Others still waiting: nothing
137
137
  // on screen changes, the fallback stays as it is.
138
- if (collecting.size !== 0) for (let n = boundaryOf(e); n !== undefined; n = n._parent ?? undefined) if (!(e.G & unsettled(n)) && n.V.delete(e) && n.V.size === 0) {
139
- if (n.P) redraw(n);
140
- if (n.B !== null) revealHooks.j(n.B);
138
+ if (collecting.size !== 0) for (let n = boundaryOf(e); n !== undefined; n = n._parent ?? undefined) if (!(e.S & unsettled(n)) && n.v.delete(e) && n.v.size === 0) {
139
+ if (n.H) redraw(n);
140
+ if (n.V !== null) revealHooks.P(n.V);
141
141
  }
142
142
  return false;
143
143
  }
144
144
  for (let t = boundaryOf(e); t !== undefined; t = t._parent ?? undefined) {
145
- if (!(t.i & n)) continue;
145
+ if (!(t.u & n)) continue;
146
146
  if (isCollecting(t)) {
147
147
  caught(t, e, r);
148
148
  return true;
149
149
  }
150
- t.V.add(e);
150
+ t.v.add(e);
151
151
  collecting.add(t);
152
152
  }
153
153
  return false;
154
154
  }
155
155
 
156
156
  /** The nearest boundary on `r`'s chain showing its fallback, if any. */ function hiddenBy(e) {
157
- for (let n = boundaryOf(e); n !== undefined; n = n._parent ?? undefined) if (n.P) return n;
157
+ for (let n = boundaryOf(e); n !== undefined; n = n._parent ?? undefined) if (n.H) return n;
158
158
  return undefined;
159
159
  }
160
160
 
@@ -175,19 +175,19 @@ function redraw(e) {
175
175
  * still showing its fallback holds it again then. */ function heldRun(e) {
176
176
  const n = hiddenBy(e);
177
177
  if (n === undefined) return false;
178
- (n.Y ??= new Set).add(e);
178
+ (n.K ??= new Set).add(e);
179
179
  return true;
180
180
  }
181
181
 
182
182
  /** The reveal: the runs held behind the fallback are this flush's, each in
183
183
  * its own phase — render updates with the frame that attaches the content,
184
184
  * user effects after it. */ function release(e) {
185
- if (e.Y === null) return;
186
- for (const n of e.Y) {
187
- const e = n.i;
188
- globalQueue.enqueue(e === EFFECT_TRACKED ? EFFECT_USER : e, e === EFFECT_TRACKED ? n.q : n.J ??= GlobalQueue.X.bind(null, n));
185
+ if (e.K === null) return;
186
+ for (const n of e.K) {
187
+ const e = n.u;
188
+ globalQueue.enqueue(e === EFFECT_TRACKED ? EFFECT_USER : e, e === EFFECT_TRACKED ? n.M : n.Y ??= GlobalQueue.q.bind(null, n));
189
189
  }
190
- e.Y = null;
190
+ e.K = null;
191
191
  }
192
192
 
193
193
  /** Drop the readers that settled or died. Settled: a loading reader no
@@ -195,37 +195,40 @@ function redraw(e) {
195
195
  * that landed but is held (its value staged in a transaction) is not: the
196
196
  * content reveals at the commit, with its run. The tree is: the output reads
197
197
  * it and enters the transaction itself (its committed value shows until the
198
- * landing). */ const unsettled = e => e.i === STATUS_ERROR ? STATUS_ERROR | STATUS_PENDING : STATUS_PENDING;
198
+ * landing). */ const unsettled = e => e.u === STATUS_ERROR ? STATUS_ERROR | STATUS_PENDING : STATUS_PENDING;
199
199
 
200
200
  function prune(e, n) {
201
201
  const r = unsettled(e);
202
- for (const t of e.V) {
203
- if (t.R & REACTIVE_DISPOSED) e.V.delete(t); else if (!(t.G & r)) {
204
- if (t !== e.$ && (t.u & (CONFIG_HELD | CONFIG_OVERRIDE)) === CONFIG_HELD) {
202
+ for (const t of e.v) {
203
+ if (t.R & REACTIVE_DISPOSED) e.v.delete(t); else if (!(t.S & r)) {
204
+ if (t !== e.J && (t.i & (CONFIG_HELD | CONFIG_OVERRIDE)) === CONFIG_HELD) {
205
205
  // Landed, held: the content is that transaction's — the output's
206
206
  // pass enters it and the reveal lands with the reader's run. The
207
207
  // seam, past its park decision, waits for the commit instead. (A
208
- // lane's reader reveals with the lane, this round.)
209
- if (!n) continue;
208
+ // lane's reader reveals with the lane, this round.) A boundary that
209
+ // has not shown content catches it instead: the fallback stays until
210
+ // the reader is committed (#3540: what a fresh boundary catches holds
211
+ // nothing outside it).
212
+ if (!n || !e.h) continue;
210
213
  joinFuture(txOf(t));
211
214
  }
212
- e.V.delete(t);
215
+ e.v.delete(t);
213
216
  }
214
217
  }
215
- return e.V.size;
218
+ return e.v.size;
216
219
  }
217
220
 
218
221
  /** Reveal order: a slot is ready when its content can show — it has shown
219
222
  * content, or nothing under it is unready (the tree neither pending nor
220
223
  * born held, no reader waited on). */ function ready(e) {
221
- return e.k || !(e.$.G & STATUS_PENDING) && !(e.$.u & CONFIG_HELD && (e.K === null || e.K.G & STATUS_UNINITIALIZED)) && prune(e, false) === 0;
224
+ return e.h || !(e.J.S & STATUS_PENDING) && !(e.J.i & CONFIG_HELD && (e.Z === null || e.Z.S & STATUS_UNINITIALIZED)) && prune(e, false) === 0;
222
225
  }
223
226
 
224
227
  /** GlobalQueue._boundarySeam, end of the seam: readers that settled, died,
225
228
  * or landed and committed are dropped; a fallback with none left reveals
226
229
  * next round. An arm resolves: nothing collected, nothing happened. */ function boundarySeam() {
227
230
  for (const e of collecting) {
228
- const n = e.K.R;
231
+ const n = e.Z.R;
229
232
  if (n & REACTIVE_DISPOSED) {
230
233
  collecting.delete(e);
231
234
  continue;
@@ -233,11 +236,11 @@ function prune(e, n) {
233
236
  // A parked frame's boundary (zombie) keeps its state for its revival.
234
237
  if (n & REACTIVE_ZOMBIE) continue;
235
238
  prune(e, false);
236
- e.L = false;
237
- if (e.V.size === 0) {
239
+ e.U = false;
240
+ if (e.v.size === 0) {
238
241
  collecting.delete(e);
239
- if (e.P) redraw(e);
240
- if (e.B !== null) revealHooks.j(e.B);
242
+ if (e.H) redraw(e);
243
+ if (e.V !== null) revealHooks.P(e.V);
241
244
  }
242
245
  }
243
246
  }
@@ -245,22 +248,22 @@ function prune(e, n) {
245
248
  /** The `on` pass is a verdict's: it probed itself (CONFIG_VERDICT), or it
246
249
  * read a memo that did (#3528's `createMemo(() => isPending(m2))`) — its
247
250
  * swap is display-ahead either way. */ function verdictDerived(e) {
248
- if (e.u & CONFIG_VERDICT) return true;
249
- for (let n = e._; n !== null; n = n.p) if (n.I.u & CONFIG_VERDICT) return true;
251
+ if (e.i & CONFIG_VERDICT) return true;
252
+ for (let n = e.G; n !== null; n = n._) if (n.I.i & CONFIG_VERDICT) return true;
250
253
  return false;
251
254
  }
252
255
 
253
256
  /** `on` changed after the mount: fresh again if anything under it is
254
257
  * pending now; collecting for the rest of the flush either way. */ function arm(e) {
255
- if (!e.k) {
258
+ if (!e.h) {
256
259
  // Already re-armed and on its fallback, as the frame's work — and the
257
260
  // `on` pass arms again as lane work: its verdict was provisional (a
258
261
  // memo of `isPending(m2)` is a watcher until the flush parks, then the
259
262
  // holder's verdict lane's — verdict.ts), and the swap it asked for is
260
263
  // display-ahead after all (#3528). Re-home the swap: the output re-runs
261
264
  // as the lane's, shown now beside the held frame.
262
- if (e.P && e.Z === null && e.W === null && passLane !== null) {
263
- e.W = passLane;
265
+ if (e.H && e.B === null && e.j === null && passLane !== null) {
266
+ e.j = passLane;
264
267
  // The swap the frame's pass staged (held with the frame) is void: the
265
268
  // lane's pass stages it anew (`flip` lists the output in the lane,
266
269
  // which voids its staging), as a watcher's provisional value is
@@ -270,20 +273,20 @@ function prune(e, n) {
270
273
  }
271
274
  return;
272
275
  }
273
- e.L = true;
276
+ e.U = true;
274
277
  // A verdict read in `on` (`isPending`) whose frame has no transaction
275
278
  // yet: the swap is still display-ahead — the frame gets one now (it lands
276
279
  // at this very seam if nothing holds it), and the swap is its verdict
277
280
  // lane's work, shown ahead of the frame's own runs (#3528).
278
281
  let n = passLane;
279
- if (n === null && globalQueue.ee && verdictDerived(getOwner())) {
282
+ if (n === null && globalQueue.X && verdictDerived(getOwner())) {
280
283
  joinFuture(null);
281
- n = GlobalQueue.ne(flushTransaction);
284
+ n = GlobalQueue.$(flushTransaction);
282
285
  }
283
- e.W = n;
286
+ e.j = n;
284
287
  collecting.add(e);
285
- for (const n of e.V) {
286
- if (n.G & STATUS_PENDING && !(n.R & REACTIVE_DISPOSED)) {
288
+ for (const n of e.v) {
289
+ if (n.S & STATUS_PENDING && !(n.R & REACTIVE_DISPOSED)) {
287
290
  flip(e);
288
291
  redraw(e);
289
292
  return;
@@ -294,35 +297,36 @@ function prune(e, n) {
294
297
  /** The error boundary's `reset`: re-run what threw (a comparator throw
295
298
  * names a signal — nothing to re-run). */ function reset(e) {
296
299
  // A snapshot: a source failing again is caught — and re-added — mid-walk.
297
- for (const n of [ ...e.V ]) if (n.re !== undefined && !(n.R & REACTIVE_DISPOSED)) recompute(n);
300
+ for (const n of [ ...e.v ]) if (n.ee !== undefined && !(n.R & REACTIVE_DISPOSED)) recompute(n);
298
301
  schedule();
299
302
  }
300
303
 
301
304
  function createBoundary(e, n, r, t) {
302
- const o = createOwner();
303
- const l = {
304
- i: e,
305
- _parent: boundaryOf(o) ?? null,
306
- H: o,
307
- $: null,
308
- K: null,
309
- V: new Set,
310
- k: false,
311
- L: false,
312
- W: null,
305
+ const l = createOwner();
306
+ const o = {
307
+ u: e,
308
+ _parent: boundaryOf(l) ?? null,
309
+ L: l,
310
+ J: null,
313
311
  Z: null,
314
- P: false,
315
- Y: null,
312
+ v: new Set,
313
+ h: false,
314
+ U: false,
315
+ j: null,
316
316
  B: null,
317
- te: false,
318
- oe: false,
319
- v: e === STATUS_ERROR ? signal(undefined, ERROR_SIGNAL) : null,
320
- le: r
317
+ H: false,
318
+ K: null,
319
+ V: null,
320
+ ne: false,
321
+ re: false,
322
+ F: e === STATUS_ERROR ? signal(undefined, ERROR_SIGNAL) : null,
323
+ te: r,
324
+ le: null
321
325
  };
322
- const u = e === STATUS_PENDING ? o.U[REVEAL] : null;
326
+ const u = e === STATUS_PENDING ? l.D[REVEAL] : null;
323
327
  if (getOwner()) cleanup(() => {
324
- collecting.delete(l);
325
- if (u) revealHooks.ue(u, l);
328
+ collecting.delete(o);
329
+ if (u) revealHooks.oe(u, o);
326
330
  });
327
331
  // The `on` dependencies live OUTSIDE the boundary, as the condition of a
328
332
  // `<Show>` wrapping it would: created before the owner's context names it.
@@ -331,7 +335,7 @@ function createBoundary(e, n, r, t) {
331
335
  // does not suspend the parent — and re-arms.
332
336
  if (t) {
333
337
  let e = false;
334
- runWithOwner(o, () => computed(() => {
338
+ runWithOwner(l, () => computed(() => {
335
339
  try {
336
340
  t();
337
341
  } catch (e) {
@@ -343,16 +347,16 @@ function createBoundary(e, n, r, t) {
343
347
  return;
344
348
  }
345
349
  }
346
- if (e) arm(l); else e = true;
347
- })).u |= CONFIG_REDERIVE;
350
+ if (e) arm(o); else e = true;
351
+ })).i |= CONFIG_REDERIVE;
348
352
  }
349
353
  const a = {
350
- ...o.U,
351
- [BOUNDARY]: l
354
+ ...l.D,
355
+ [BOUNDARY]: o
352
356
  };
353
357
  if (revealHooks !== null) a[REVEAL] = null;
354
- o.U = a;
355
- const i = runWithOwner(o, () => {
358
+ l.D = a;
359
+ const i = runWithOwner(l, () => {
356
360
  const e = true ? computed(n, {
357
361
  name: "children"
358
362
  }) : computed(n);
@@ -360,29 +364,29 @@ function createBoundary(e, n, r, t) {
360
364
  name: "boundary"
361
365
  }) : computed(() => flatten(read(e)));
362
366
  });
363
- l.$ = i;
367
+ o.J = i;
364
368
  // A slot of the reveal order in its context (reveal.ts): gated until the
365
369
  // controller releases it — before the output's first pass.
366
- if (u) revealHooks.ae(u, l);
370
+ if (u) revealHooks.ue(u, o);
367
371
  const f = computed(() => {
368
372
  // Reveal order (reveal.ts): a gated slot shows its fallback — or, in a
369
373
  // collapsed tail, nothing — whatever its content's state; the
370
374
  // controller is told the pass ran (its readiness may have changed) and
371
375
  // releases it in turn.
372
- if (l.te) {
376
+ if (o.ne) {
373
377
  // Linked without being read: the tree settling (or changing)
374
378
  // re-derives this pass, which is how the controller hears of it.
375
379
  // It may release this very slot (the frontier whose content just
376
380
  // settled): the pass goes on to show it — the redraw it asks for is
377
381
  // refused mid-pass and not needed.
378
382
  link(i, getOwner());
379
- if (l.B !== null) revealHooks.j(l.B);
380
- if (l.te) {
381
- if (l.oe) {
382
- l.P = true;
383
+ if (o.V !== null) revealHooks.P(o.V);
384
+ if (o.ne) {
385
+ if (o.re) {
386
+ o.H = true;
383
387
  return undefined;
384
388
  }
385
- return fallback(l);
389
+ return fallback(o);
386
390
  }
387
391
  }
388
392
  // A tree carrying a status is not read: an errored memo's reactive
@@ -392,24 +396,24 @@ function createBoundary(e, n, r, t) {
392
396
  // display-ahead `on` causes is the lane's, and must still be the
393
397
  // fallback. Linked, so its recovery re-derives this pass; read again
394
398
  // once clean.
395
- const n = i.G & (STATUS_PENDING | STATUS_ERROR);
399
+ const n = i.S & (STATUS_PENDING | STATUS_ERROR);
396
400
  if (n !== 0) {
397
401
  link(i, getOwner());
398
402
  if (n & e) {
399
- if (isCollecting(l)) {
400
- caught(l, i, undefined);
401
- return fallback(l);
403
+ if (isCollecting(o)) {
404
+ caught(o, i, undefined);
405
+ return fallback(o);
402
406
  }
403
407
  // Forwarded: a loading boundary showing content keeps it and
404
408
  // holds the frame like any reader (recorded for its `on`).
405
- l.V.add(i);
406
- collecting.add(l);
409
+ o.v.add(i);
410
+ collecting.add(o);
407
411
  }
408
412
  // A pending passes an error boundary by (A6); an error, a loading
409
413
  // one; a loading boundary showing content forwards its pending.
410
- throw i.m.v;
414
+ throw i.m.F;
411
415
  }
412
- if (isCollecting(l)) {
416
+ if (isCollecting(o)) {
413
417
  // A29's boundary exemption (#3540): a boundary MOUNTED over a held
414
418
  // value (its first pass; a first pass under it that read a hold was
415
419
  // collected, `joinPass` — the tree's own, or a render effect's that
@@ -422,43 +426,56 @@ function createBoundary(e, n, r, t) {
422
426
  // which reveals the content — a fallback staged earlier is replaced
423
427
  // ahead of the commit and never shown.
424
428
  const e = getOwner();
425
- if (l.V.size !== 0 && e.G & STATUS_UNINITIALIZED && !(e.u & CONFIG_HELD)) return fallback(l);
429
+ if (o.v.size !== 0 && e.S & STATUS_UNINITIALIZED && !(e.i & CONFIG_HELD)) return fallback(o);
426
430
  // Readers under it still unready: the fallback, the tree untouched.
427
431
  // The seam re-derives this pass when they settle.
428
- if (prune(l, true) !== 0) return fallback(l);
432
+ if (prune(o, true) !== 0) return fallback(o);
429
433
  }
430
434
  let r;
431
435
  try {
432
436
  r = read(i);
433
437
  } catch (n) {
434
438
  if (n instanceof NotReadyError ? e === STATUS_PENDING : e === STATUS_ERROR) {
435
- if (isCollecting(l)) {
436
- caught(l, i, n);
437
- return fallback(l);
439
+ if (isCollecting(o)) {
440
+ caught(o, i, n);
441
+ return fallback(o);
438
442
  }
439
443
  // Forwarded: a loading boundary showing content keeps it and
440
444
  // holds the frame like any reader (recorded for its `on`).
441
- l.V.add(i);
442
- collecting.add(l);
445
+ o.v.add(i);
446
+ collecting.add(o);
443
447
  }
444
448
  // A pending passes an error boundary by (A6).
445
449
  throw n;
446
450
  }
447
451
  // Readers under it still unready (caught before, or while the read
448
452
  // ran the content at a mount): the fallback.
449
- if (isCollecting(l) && l.V.size !== 0) return fallback(l);
450
- l.k = true;
453
+ if (isCollecting(o) && o.v.size !== 0) return fallback(o);
454
+ o.h = true;
451
455
  // Observe: the fallback stops showing (a hide before its commit means
452
456
  // it never displayed — the engine knows the swap it was staged with).
453
- if (l.P && l.i & STATUS_PENDING && attrHooks !== null) attrHooks.boundaryFallback(l, l.$, false);
454
- l.P = false;
455
- release(l);
457
+ if (o.H && o.u & STATUS_PENDING && attrHooks !== null) attrHooks.boundaryFallback(o, o.J, false);
458
+ o.H = false;
459
+ // The fallback dies when the content that replaces it is on screen —
460
+ // with this flush's commits when the pass is the frame's, at the
461
+ // landing when the frame parks (the run is held with it, as the old
462
+ // children of a held pass are) — not now: a held swap keeps the
463
+ // fallback on screen, live, until it commits. A pass back to the
464
+ // fallback before then finds it still built and keeps it.
465
+ const t = o.le;
466
+ if (t !== null) globalQueue.enqueue(EFFECT_RENDER, () => {
467
+ if (!o.H && o.le === t) {
468
+ dispose(t);
469
+ o.le = null;
470
+ }
471
+ });
472
+ release(o);
456
473
  // Shown: the slot leaves its reveal order (a later re-arm gates nobody
457
474
  // else; the frontier moves on).
458
- if (l.B !== null) {
459
- const e = l.B;
460
- l.B = null;
461
- revealHooks.j(e);
475
+ if (o.V !== null) {
476
+ const e = o.V;
477
+ o.V = null;
478
+ revealHooks.P(e);
462
479
  }
463
480
  return r;
464
481
  },
@@ -467,10 +484,10 @@ function createBoundary(e, n, r, t) {
467
484
  // frozen by snapshot capture.
468
485
  {
469
486
  name: "value",
470
- ie: true
487
+ ae: true
471
488
  });
472
- f.u |= CONFIG_REDERIVE;
473
- l.K = f;
489
+ f.i |= CONFIG_REDERIVE;
490
+ o.Z = f;
474
491
  return accessor(f);
475
492
  }
476
493
 
@@ -478,26 +495,43 @@ function fallback(e) {
478
495
  // The swap a display-ahead re-arm asked for: this pass is the lane's — a
479
496
  // lane read by construction (REACTIVE_LANE_READ: `recompute`'s tail keeps
480
497
  // the pass in the lane).
481
- if (e.Z !== null) {
482
- setPassLane(e.Z);
483
- e.K.R |= REACTIVE_LANE_READ;
484
- e.Z = null;
498
+ if (e.B !== null) {
499
+ setPassLane(e.B);
500
+ e.Z.R |= REACTIVE_LANE_READ;
501
+ e.B = null;
485
502
  }
486
503
  // Observe: a loading boundary starts showing its fallback — the swap lands
487
504
  // with the frame's transaction, or this drain commits it (lane work, or no
488
505
  // transaction). A mount's synchronous first show has no drain of its own:
489
506
  // one is scheduled so the engine's display instant (`flushEnd`) comes.
490
- if (!e.P && e.i & STATUS_PENDING && attrHooks !== null) {
491
- attrHooks.boundaryFallback(e, e.$, true, passLane !== null ? null : flushTransaction !== null ? resolveTx(flushTransaction) : passTx);
492
- if (!globalQueue.ee) schedule();
507
+ if (!e.H && e.u & STATUS_PENDING && attrHooks !== null) {
508
+ attrHooks.boundaryFallback(e, e.J, true, passLane !== null ? null : flushTransaction !== null ? resolveTx(flushTransaction) : passTx);
509
+ if (!globalQueue.X) schedule();
510
+ }
511
+ e.H = true;
512
+ // Built in its own scope, like `Show`'s function child, once per show
513
+ // (D-39: the fallback is the display until a new answer replaces the
514
+ // error): a re-derive of the output while it shows — a second reader
515
+ // caught, the same error propagated again through a sibling's re-run, a
516
+ // retry pending after `reset()`, a later error — keeps the built
517
+ // fallback, its DOM and focus with it (#3991). A later error reaches it
518
+ // through the error accessor; only a fallback reading the accessor at its
519
+ // top level is rebuilt by it. Created beside the output — in its owner,
520
+ // outside the boundary, as the output is: its errors and runs are the
521
+ // enclosing boundary's — with the output's id, so what it builds gets the
522
+ // ids a build under the output would; disposed once content is on screen.
523
+ if (e.le === null) {
524
+ const n = getOwner();
525
+ e.le = runWithOwner(n._parent, () => computed(() => e.te(e), {
526
+ id: n.id
527
+ }));
493
528
  }
494
- e.P = true;
495
- return e.le(e);
529
+ return read(e.le);
496
530
  }
497
531
 
498
532
  const ERROR_SIGNAL = {
499
533
  ownedWrite: true,
500
- ie: true
534
+ ae: true
501
535
  };
502
536
 
503
537
  /**
@@ -568,19 +602,19 @@ const ERROR_SIGNAL = {
568
602
  * }
569
603
  * ```
570
604
  */ function createErrorBoundary(e, n) {
571
- return createBoundary(STATUS_ERROR, e, e => n(accessor(e.v), () => reset(e)));
605
+ return createBoundary(STATUS_ERROR, e, e => n(accessor(e.F), () => reset(e)));
572
606
  }
573
607
 
574
608
  // Installed at module evaluation — present exactly when something imports a
575
609
  // boundary. An app without one pays the three null checks and nothing else.
576
- GlobalQueue.fe = catchStatus;
610
+ GlobalQueue.ie = catchStatus;
577
611
 
578
- GlobalQueue.ce = e => e.G & STATUS_UNINITIALIZED && catchStatus(e, STATUS_PENDING);
612
+ GlobalQueue.fe = e => e.S & STATUS_UNINITIALIZED && catchStatus(e, STATUS_PENDING);
579
613
 
580
614
  GlobalQueue.se = hidden;
581
615
 
582
- GlobalQueue.Ee = boundarySeam;
616
+ GlobalQueue.ce = boundarySeam;
583
617
 
584
- GlobalQueue.de = heldRun;
618
+ GlobalQueue.Ee = heldRun;
585
619
 
586
620
  export { REVEAL, createErrorBoundary, createLoadingBoundary, prune, ready, redraw, revealHooks, setRevealHooks };