@solidjs/signals 2.0.0-rc.8 → 2.0.0-rc.9

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 (90) hide show
  1. package/dist/dev-shared.js +1399 -285
  2. package/dist/dev.attribution.js +459 -307
  3. package/dist/dev.js +1864 -435
  4. package/dist/observe/affects.js +3 -1
  5. package/dist/observe/attribution.js +7 -1
  6. package/dist/observe/boundaries.js +209 -154
  7. package/dist/observe/core/action.js +18 -8
  8. package/dist/observe/core/async.js +220 -110
  9. package/dist/observe/core/attribution-costs.js +66 -0
  10. package/dist/observe/core/attribution-feedback.js +282 -0
  11. package/dist/observe/core/attribution-hooks.js +23 -1
  12. package/dist/observe/core/attribution-queries.js +28 -0
  13. package/dist/observe/core/attribution.js +262 -485
  14. package/dist/observe/core/constants.js +34 -1
  15. package/dist/observe/core/context.js +3 -3
  16. package/dist/observe/core/core.js +867 -367
  17. package/dist/observe/core/dev.js +78 -17
  18. package/dist/observe/core/effect.js +67 -51
  19. package/dist/observe/core/error-hooks.js +71 -0
  20. package/dist/observe/core/external.js +4 -4
  21. package/dist/observe/core/graph.js +37 -37
  22. package/dist/observe/core/heap.js +45 -45
  23. package/dist/observe/core/invariants.js +2 -0
  24. package/dist/observe/core/lanes.js +86 -49
  25. package/dist/observe/core/optimistic.js +242 -95
  26. package/dist/observe/core/owner.js +98 -84
  27. package/dist/observe/core/scheduler.js +543 -305
  28. package/dist/observe/core/verdict.js +247 -129
  29. package/dist/observe/index.js +7 -3
  30. package/dist/observe/map.js +126 -124
  31. package/dist/observe/signals.js +33 -17
  32. package/dist/observe/store/index.js +2 -0
  33. package/dist/observe/store/next/optimistic.js +141 -132
  34. package/dist/observe/store/next/projection.js +34 -21
  35. package/dist/observe/store/next/reconcile.js +58 -56
  36. package/dist/observe/store/next/store.js +260 -146
  37. package/dist/observe/store/store.js +5 -3
  38. package/dist/observe/store/utils.js +948 -135
  39. package/dist/prod/attribution.js +26 -17
  40. package/dist/prod/boundaries.js +128 -76
  41. package/dist/prod/core/action.js +16 -8
  42. package/dist/prod/core/async.js +251 -143
  43. package/dist/prod/core/constants.js +34 -1
  44. package/dist/prod/core/context.js +3 -3
  45. package/dist/prod/core/core.js +843 -347
  46. package/dist/prod/core/dev.js +17 -1
  47. package/dist/prod/core/effect.js +48 -34
  48. package/dist/prod/core/error-hooks.js +71 -0
  49. package/dist/prod/core/external.js +4 -4
  50. package/dist/prod/core/graph.js +37 -37
  51. package/dist/prod/core/heap.js +45 -45
  52. package/dist/prod/core/lanes.js +90 -53
  53. package/dist/prod/core/optimistic.js +247 -100
  54. package/dist/prod/core/owner.js +57 -45
  55. package/dist/prod/core/scheduler.js +543 -305
  56. package/dist/prod/core/verdict.js +245 -127
  57. package/dist/prod/index.js +7 -3
  58. package/dist/prod/map.js +112 -112
  59. package/dist/prod/signals.js +28 -12
  60. package/dist/prod/store/next/optimistic.js +135 -128
  61. package/dist/prod/store/next/projection.js +31 -20
  62. package/dist/prod/store/next/store.js +325 -252
  63. package/dist/prod/store/store.js +2 -2
  64. package/dist/prod/store/utils.js +946 -135
  65. package/dist/types/attribution.d.ts +7 -2
  66. package/dist/types/attribution.prod.d.ts +10 -1
  67. package/dist/types/boundaries.d.ts +10 -1
  68. package/dist/types/core/action.d.ts +12 -5
  69. package/dist/types/core/attribution-costs.d.ts +35 -0
  70. package/dist/types/core/attribution-feedback.d.ts +133 -0
  71. package/dist/types/core/attribution-hooks.d.ts +28 -3
  72. package/dist/types/core/attribution-queries.d.ts +10 -0
  73. package/dist/types/core/attribution.d.ts +51 -172
  74. package/dist/types/core/constants.d.ts +33 -0
  75. package/dist/types/core/core.d.ts +186 -5
  76. package/dist/types/core/dev.d.ts +129 -9
  77. package/dist/types/core/error-hooks.d.ts +71 -0
  78. package/dist/types/core/index.d.ts +3 -1
  79. package/dist/types/core/invariants.d.ts +4 -0
  80. package/dist/types/core/lanes.d.ts +31 -4
  81. package/dist/types/core/scheduler.d.ts +95 -2
  82. package/dist/types/core/types.d.ts +3 -0
  83. package/dist/types/index.d.ts +2 -2
  84. package/dist/types/signals.d.ts +8 -0
  85. package/dist/types/store/index.d.ts +2 -1
  86. package/dist/types/store/next/optimistic.d.ts +1 -1
  87. package/dist/types/store/next/store.d.ts +6 -5
  88. package/dist/types/store/next/target.d.ts +1 -1
  89. package/dist/types/store/utils.d.ts +177 -6
  90. package/package.json +1 -1
@@ -4,6 +4,8 @@ import { ext, statusNotifierOf } from "./core/core.js";
4
4
 
5
5
  import { $REFRESH, STATUS_PENDING } from "./core/constants.js";
6
6
 
7
+ import "./core/dev.js";
8
+
7
9
  import { NotReadyError } from "./core/error.js";
8
10
 
9
11
  import { GlobalQueue, globalQueue, schedule, shiftAffectsMarks } from "./core/scheduler.js";
@@ -108,7 +110,7 @@ GlobalQueue.G = releaseAffectsMarks;
108
110
 
109
111
  GlobalQueue.M = markAffects;
110
112
 
111
- GlobalQueue.N = releaseAffectsMark;
113
+ GlobalQueue.j = releaseAffectsMark;
112
114
 
113
115
  function affects(e, r) {
114
116
  const t = e?.[$TARGET];
@@ -1 +1,7 @@
1
- export { attribution } from "./core/attribution.js";
1
+ export { attribution, formatOrigin, formatRerun } from "./core/attribution.js";
2
+
3
+ export { costs } from "./core/attribution-costs.js";
4
+
5
+ export { feedback } from "./core/attribution-feedback.js";
6
+
7
+ export { subscriptions, why } from "./core/attribution-queries.js";
@@ -1,23 +1,27 @@
1
- import { runWithOwner, signal, untrack, read, computed, setSignal, ext, recompute } from "./core/core.js";
1
+ import { runWithOwner, signal, untrack, read, computed, spectate, setSignal, ext, recompute } from "./core/core.js";
2
2
 
3
3
  import { NotReadyError, unwrapStatusError } from "./core/error.js";
4
4
 
5
5
  import { createOwner, cleanup } from "./core/owner.js";
6
6
 
7
- import { Queue, haltReactivity, schedule } from "./core/scheduler.js";
7
+ import { Queue, transitions, wakeParked, haltReactivity, schedule } from "./core/scheduler.js";
8
8
 
9
9
  import { getContext, setContext, createContext } from "./core/context.js";
10
10
 
11
- import { STATUS_PENDING, STATUS_ERROR, REACTIVE_DISPOSED, CONFIG_AUTO_DISPOSE } from "./core/constants.js";
11
+ import { STATUS_PENDING, STATUS_ERROR, REACTIVE_ZOMBIE, REACTIVE_DISPOSED, CONFIG_AUTO_DISPOSE } from "./core/constants.js";
12
12
 
13
13
  import { attrHooks } from "./core/attribution-hooks.js";
14
14
 
15
15
  import "./core/invariants.js";
16
16
 
17
+ import "./core/dev.js";
18
+
17
19
  import "./core/verdict.js";
18
20
 
19
21
  import "./core/effect.js";
20
22
 
23
+ import { reportClientError } from "./core/error-hooks.js";
24
+
21
25
  import { accessor } from "./signals.js";
22
26
 
23
27
  function boundaryComputed(t, e) {
@@ -26,44 +30,44 @@ function boundaryComputed(t, e) {
26
30
  });
27
31
  ext(r).h = (t, e) => {
28
32
  // Use passed values if provided, otherwise read from node
29
- const n = t !== undefined ? t : r.S;
30
- const s = e !== undefined ? e : r.o?._;
33
+ const s = t !== undefined ? t : r.S;
34
+ const n = e !== undefined ? e : r.o?._;
31
35
  // Notify both status dimensions like a render effect does; the queue chain
32
36
  // consumes this boundary's own type and forwards the remainder upward until
33
37
  // a boundary that handles it is found.
34
38
  r.S &= ~r.R;
35
- const i = r.C.notify(r, STATUS_PENDING | STATUS_ERROR, n, s);
39
+ const i = r.T.notify(r, STATUS_PENDING | STATUS_ERROR, s, n);
36
40
  // The queue is the only propagation channel: a foreign status must not stay
37
41
  // reader-visible on the tree, or reads re-throw it across the boundary and
38
42
  // link unrelated ambient contexts (the #2809 nested-boundary loop). Deps are
39
43
  // untouched, so the tree still recomputes when the foreign source settles.
40
- const o = n & ~r.R & (STATUS_PENDING | STATUS_ERROR);
44
+ const o = s & ~r.R & (STATUS_PENDING | STATUS_ERROR);
41
45
  if (o) {
42
46
  r.S &= ~o;
43
- if (r.o?._ === s && !(r.S & (STATUS_PENDING | STATUS_ERROR))) if (r.o !== null) r.o._ = undefined;
47
+ if (r.o?._ === n && !(r.S & (STATUS_PENDING | STATUS_ERROR))) if (r.o !== null) r.o._ = undefined;
44
48
  }
45
49
  // An ERROR the chain could not deliver to any boundary is uncaught. The
46
50
  // scrub above already removed it from reader-visible state, so without
47
51
  // escalation here it would vanish entirely (#2884) — halt-and-throw,
48
52
  // exactly like an unhandled effect error.
49
- if (!i && n & STATUS_ERROR) {
50
- haltReactivity(unwrapStatusError(s));
51
- throw s;
53
+ if (!i && s & STATUS_ERROR) {
54
+ haltReactivity(unwrapStatusError(n));
55
+ throw n;
52
56
  }
53
57
  };
54
58
  r.R = e;
55
- r.T &= ~CONFIG_AUTO_DISPOSE;
59
+ r.C &= ~CONFIG_AUTO_DISPOSE;
56
60
  recompute(r, true);
57
61
  return r;
58
62
  }
59
63
 
60
- function createBoundChildren(t, e, r, n) {
61
- const s = t.C;
62
- s.addChild(t.C = r);
63
- cleanup(() => s.removeChild(t.C));
64
+ function createBoundChildren(t, e, r, s) {
65
+ const n = t.T;
66
+ n.addChild(t.T = r);
67
+ cleanup(() => n.removeChild(t.T));
64
68
  return runWithOwner(t, () => {
65
69
  const t = computed(e);
66
- return boundaryComputed(() => flatten(read(t)), n);
70
+ return boundaryComputed(() => flatten(read(t)), s);
67
71
  });
68
72
  }
69
73
 
@@ -82,53 +86,53 @@ function isRevealController(t) {
82
86
  }
83
87
 
84
88
  function isSlotReady(t) {
85
- return isRevealController(t) ? t.O() : t.v.size === 0 && !t.U;
89
+ return isRevealController(t) ? t.N() : t.O.size === 0 && !t.I;
86
90
  }
87
91
 
88
92
  function isSlotMinimallyReady(t) {
89
- return isRevealController(t) ? t.I() : isSlotReady(t);
93
+ return isRevealController(t) ? t.U() : isSlotReady(t);
90
94
  }
91
95
 
92
- function setSlotState(t, e, r, n) {
93
- setSignal(t.D, r);
94
- setSignal(t.P, n);
96
+ function setSlotState(t, e, r, s) {
97
+ setSignal(t.v, r);
98
+ setSignal(t.D, s);
95
99
  if (isRevealController(t)) {
96
- if (!r && t.j === e) t.j = undefined;
97
- return t.B(r, n);
100
+ if (!r && t.P === e) t.P = undefined;
101
+ return t.B(r, s);
98
102
  }
99
- if (!r && t.W === e && t.L) t.W = undefined;
103
+ if (!r && t.W === e && t.H) t.W = undefined;
100
104
  }
101
105
 
102
106
  class RevealController {
107
+ L;
103
108
  F;
104
- H;
105
- q=[];
106
- j;
107
- D=signal(false, {
109
+ V=[];
110
+ P;
111
+ v=signal(false, {
108
112
  ownedWrite: true,
109
- V: true
113
+ q: true
110
114
  });
111
- P=signal(false, {
115
+ D=signal(false, {
112
116
  ownedWrite: true,
113
- V: true
117
+ q: true
114
118
  });
119
+ Z=true;
115
120
  J=true;
116
- K=true;
117
- X=false;
121
+ K=false;
118
122
  constructor(t, e) {
119
- this.F = t;
120
- this.H = e;
123
+ this.L = t;
124
+ this.F = e;
121
125
  }
122
- Y(t) {
123
- for (let e = 0; e < this.q.length; e++) {
124
- const r = this.q[e];
125
- if ((isRevealController(r) ? r.j : r.W) !== this) continue;
126
+ X(t) {
127
+ for (let e = 0; e < this.V.length; e++) {
128
+ const r = this.V[e];
129
+ if ((isRevealController(r) ? r.P : r.W) !== this) continue;
126
130
  if (t(r) === false) return false;
127
131
  }
128
132
  return true;
129
133
  }
130
- O() {
131
- return this.Y(isSlotReady);
134
+ N() {
135
+ return this.X(isSlotReady);
132
136
  }
133
137
  /**
134
138
  * "Minimally ready" = this group has something visible to show under its own policy.
@@ -136,13 +140,13 @@ class RevealController {
136
140
  * - `together`: every direct slot is minimally ready.
137
141
  * - `sequential`: the first owned slot is minimally ready (frontier can advance).
138
142
  * - `natural`: any owned slot is minimally ready.
139
- */ I() {
140
- const t = untrack(this.F);
141
- if (t === "together") return this.Y(isSlotMinimallyReady);
143
+ */ U() {
144
+ const t = untrack(this.L);
145
+ if (t === "together") return this.X(isSlotMinimallyReady);
142
146
  if (t === "natural") {
143
147
  let t = false;
144
148
  let e = false;
145
- this.Y(r => {
149
+ this.X(r => {
146
150
  t = true;
147
151
  if (isSlotMinimallyReady(r)) {
148
152
  e = true;
@@ -153,61 +157,61 @@ class RevealController {
153
157
  }
154
158
  // sequential: only the first owned slot matters.
155
159
  let e = true;
156
- this.Y(t => {
160
+ this.X(t => {
157
161
  e = isSlotMinimallyReady(t);
158
162
  return false;
159
163
  });
160
164
  return e;
161
165
  }
162
- Z(t) {
163
- if (this.q.includes(t)) return;
164
- this.q.push(t);
165
- const e = untrack(this.F);
166
- setSignal(t.D, true), setSignal(t.P, e === "sequential" ? !!untrack(this.H) : false);
166
+ Y(t) {
167
+ if (this.V.includes(t)) return;
168
+ this.V.push(t);
169
+ const e = untrack(this.L);
170
+ setSignal(t.v, true), setSignal(t.D, e === "sequential" ? !!untrack(this.F) : false);
167
171
  untrack(() => this.B());
168
172
  }
169
173
  $(t) {
170
- const e = this.q.indexOf(t);
171
- if (e >= 0) this.q.splice(e, 1);
174
+ const e = this.V.indexOf(t);
175
+ if (e >= 0) this.V.splice(e, 1);
172
176
  untrack(() => this.B());
173
177
  }
174
178
  B(t, e) {
175
- if (this.X) return;
176
- this.X = true;
177
- const r = this.J;
178
- const n = this.K;
179
+ if (this.K) return;
180
+ this.K = true;
181
+ const r = this.Z;
182
+ const s = this.J;
179
183
  try {
180
- const r = t ?? read(this.D), n = untrack(this.F), s = n === "sequential" && !!untrack(this.H), i = e ?? s;
184
+ const r = t ?? read(this.v), s = untrack(this.L), n = s === "sequential" && !!untrack(this.F), i = e ?? n;
181
185
  if (r) {
182
186
  // Held by an outer group. Propagate the hold (and whatever collapsed policy
183
187
  // the outer asked for) down the whole subtree. Inner order is ignored while
184
188
  // held; it resumes once the outer releases us.
185
- this.Y(t => setSlotState(t, this, true, i));
186
- } else if (n === "natural") {
189
+ this.X(t => setSlotState(t, this, true, i));
190
+ } else if (s === "natural") {
187
191
  // Each child reveals based on its own readiness. A nested controller slot
188
192
  // is released to run its own order locally — we bypass setSlotState for it
189
193
  // so the parent backpointer survives for upward readiness notifications.
190
- this.Y(t => {
194
+ this.X(t => {
191
195
  if (isRevealController(t)) {
192
- setSignal(t.P, false);
193
196
  setSignal(t.D, false);
197
+ setSignal(t.v, false);
194
198
  t.B(false, false);
195
199
  } else {
196
200
  setSlotState(t, this, !isSlotReady(t), false);
197
201
  }
198
202
  });
199
- } else if (n === "together") {
203
+ } else if (s === "together") {
200
204
  // Release when every direct slot is minimally ready (has something to show
201
205
  // under its own order). A fully-ready inner together is minimally ready;
202
206
  // sequential's first slot being ready is minimally ready; natural having any
203
207
  // ready child is minimally ready. This lets `together` guarantee a single
204
208
  // cohesive reveal without waiting for every grandchild.
205
- const t = this.Y(isSlotMinimallyReady);
206
- this.Y(e => setSlotState(e, this, !t, false));
209
+ const t = this.X(isSlotMinimallyReady);
210
+ this.X(e => setSlotState(e, this, !t, false));
207
211
  } else {
208
212
  let t = false;
209
- this.Y(e => {
210
- if (t) return setSlotState(e, this, true, s);
213
+ this.X(e => {
214
+ if (t) return setSlotState(e, this, true, n);
211
215
  if (isSlotReady(e)) return setSlotState(e, this, false, false);
212
216
  t = true;
213
217
  // Frontier slot. For a leaf, holding `_disabled=true` is what keeps its
@@ -217,8 +221,8 @@ class RevealController {
217
221
  // advancing past this slot, and we bypass setSlotState so the parent
218
222
  // backpointer survives for upward readiness notifications.
219
223
  if (isRevealController(e)) {
220
- setSignal(e.P, false);
221
224
  setSignal(e.D, false);
225
+ setSignal(e.v, false);
222
226
  e.B(false, false);
223
227
  } else {
224
228
  setSlotState(e, this, true, false);
@@ -226,54 +230,78 @@ class RevealController {
226
230
  });
227
231
  }
228
232
  } finally {
229
- this.J = this.O();
230
- this.K = this.I();
231
- this.X = false;
233
+ this.Z = this.N();
234
+ this.J = this.U();
235
+ this.K = false;
232
236
  }
233
- if (this.j && (r !== this.J || n !== this.K)) this.j.B();
237
+ if (this.P && (r !== this.Z || s !== this.J)) this.P.B();
234
238
  }
235
239
  }
236
240
 
237
241
  class CollectionQueue extends Queue {
238
242
  tt;
239
- v=new Set;
243
+ O=new Set;
240
244
  et;
241
- U=true;
242
- D=signal(false, {
245
+ I=true;
246
+ v=signal(false, {
243
247
  ownedWrite: true,
244
- V: true
248
+ q: true
245
249
  });
246
250
  _;
247
- P=signal(false, {
251
+ D=signal(false, {
248
252
  ownedWrite: true,
249
- V: true
253
+ q: true
250
254
  });
251
255
  W;
252
- L=false;
256
+ H=false;
253
257
  rt;
254
- nt=ON_INIT;
258
+ st=ON_INIT;
259
+ /** The boundary's owner — where a `caught` report locates itself, set before the children are built (a creation-time throw arrives before `_tree`). */
260
+ nt;
255
261
  constructor(t) {
256
262
  super();
257
263
  this.tt = t;
258
264
  }
259
265
  run(t) {
260
- if (!t || read(this.D) && (!_revealUsed || read(this.P))) return;
266
+ if (!t || read(this.v) && (!_revealUsed || read(this.D))) return;
261
267
  return super.run(t);
262
268
  }
263
- notify(t, e, r, n) {
264
- if (!(e & this.tt)) return super.notify(t, e, r, n);
265
- if (this.L && this.rt) {
266
- const t = untrack(() => {
267
- try {
268
- return this.rt();
269
- } catch {
270
- return ON_INIT;
269
+ /** The `on` key, or ON_INIT when it throws. Evaluated mid-propagation,
270
+ * inside the pending node's own pass: read as a spectator so the key's
271
+ * sources never become that node's dependencies (#3528). */ it() {
272
+ return spectate(() => {
273
+ try {
274
+ return this.rt();
275
+ } catch {
276
+ return ON_INIT;
277
+ }
278
+ });
279
+ }
280
+ notify(t, e, r, s) {
281
+ if (!(e & this.tt)) return super.notify(t, e, r, s);
282
+ if (this.H && this.rt) {
283
+ const t = this.it();
284
+ if (t !== this.st) {
285
+ this.st = t;
286
+ this.H = false;
287
+ this.O.clear();
288
+ // Readers forwarded while this boundary showed content are behind the
289
+ // fallback now: they stop blocking (`reporterBlocksSource`), and the
290
+ // transactions they were holding must be re-judged for it (A33, #3375).
291
+ // What those readers still wait on is this boundary's to wait on now:
292
+ // they never re-notify (status propagation dedupes on the reader's
293
+ // `_pendingSources`), so the reset collects it from their registrations
294
+ // — the one place a forwarded reader is recorded (INV-3) — or a sibling
295
+ // reader's flight that lands first reveals them stale (A33, #3459).
296
+ for (const t of transitions) for (const [e, r] of t.ot) for (const t of r) if (this.lt(t)) {
297
+ this.O.add(e);
298
+ t.o?.ut?.forEach(t => this.O.add(t));
271
299
  }
272
- });
273
- if (t !== this.nt) {
274
- this.nt = t;
275
- this.L = false;
276
- this.v.clear();
300
+ if (this.O.size) {
301
+ setSignal(this.v, true);
302
+ if (attrHooks !== null && this.tt & STATUS_PENDING) attrHooks.boundaryFallback(this, this.et, true);
303
+ }
304
+ wakeParked();
277
305
  }
278
306
  }
279
307
  // Routing is dimension-independent: each boundary consumes only its own
@@ -286,47 +314,73 @@ class CollectionQueue extends Queue {
286
314
  // dimension, while a status already caught by an inner boundary arrives with
287
315
  // its dimension consumed from the mask and is correctly not re-routed
288
316
  // (the Loading > Errored > content composition escape, #2856).
289
- if (this.tt & STATUS_PENDING && this.L) return super.notify(t, e, r, n);
317
+ if (this.tt & STATUS_PENDING && this.H) return super.notify(t, e, r, s);
290
318
  if (r & this.tt) {
291
- this.U = true;
292
- const e = n?.source || t.o?._?.source;
319
+ this.I = true;
320
+ const e = s?.source || t.o?._?.source;
293
321
  if (e) {
294
- const t = this.v.size === 0;
295
- this.v.add(e);
296
- if (t) {
297
- setSignal(this.D, true);
322
+ const r = this.O.size === 0;
323
+ this.O.add(e);
324
+ // A collecting boundary waits on everything the effect is pending on,
325
+ // not only the source this notification carries. Status propagation
326
+ // dedupes on the effect's `_pendingSources`: a source it already
327
+ // carries (a flight that started before an `on` reset cleared the
328
+ // set) is never re-reported, and that source's later re-flight
329
+ // stays invisible — the boundary revealed when its one collected
330
+ // source settled while the effect was still pending (#3375).
331
+ if (this.tt & STATUS_PENDING) t.o?.ut?.forEach(t => this.O.add(t));
332
+ if (r) {
333
+ setSignal(this.v, true);
298
334
  if (attrHooks !== null && this.tt & STATUS_PENDING) attrHooks.boundaryFallback(this, this.et, true);
299
335
  }
300
336
  if (this.tt & STATUS_ERROR) {
301
- setSignal(this._, unwrapStatusError(e.o?._));
337
+ const t = unwrapStatusError(e.o?._);
338
+ setSignal(this._, t);
339
+ // The client error hook: this boundary renders its fallback for
340
+ // it — the one road a rendered failure took that no global handler
341
+ // ever saw. `source` is the computation that threw (the status
342
+ // wrapper's, made at the first landing and kept downstream), so the
343
+ // hook hears where it broke as well as where it was met. Once per
344
+ // error object; a `reset()` re-collecting the same failure says
345
+ // nothing new.
346
+ reportClientError(t, this.nt, e);
302
347
  }
303
348
  }
304
349
  }
305
350
  e &= ~this.tt;
306
- return e ? super.notify(t, e, r, n) : true;
351
+ return e ? super.notify(t, e, r, s) : true;
352
+ }
353
+ /** Is `reporter` live and routed to this boundary — under it, with no
354
+ * collecting pending-type boundary in between (`reporterBlocksSource`'s test)? */ lt(t) {
355
+ if (t.ft & (REACTIVE_ZOMBIE | REACTIVE_DISPOSED)) return false;
356
+ for (let e = t.T; e; e = e._parent) {
357
+ if (e === this) return true;
358
+ if (e.tt & STATUS_PENDING && !e.H) return false;
359
+ }
360
+ return false;
307
361
  }
308
- st() {
309
- for (const t of this.v) {
362
+ ct() {
363
+ for (const t of this.O) {
310
364
  // A source with a live affects() mark holds display state for the
311
365
  // mark's lifetime (the visual channel): the marked node carries no
312
366
  // status of its own, so the count is the liveness test. The release
313
367
  // sweep (finalizePureQueue after mark release) re-runs this check.
314
- if (t.it & REACTIVE_DISPOSED || !t.o?.t && !(t.S & this.tt) && !(this.tt & STATUS_ERROR && t.S & STATUS_PENDING)) this.v.delete(t);
368
+ if (t.ft & REACTIVE_DISPOSED || !t.o?.t && !(t.S & this.tt) && !(this.tt & STATUS_ERROR && t.S & STATUS_PENDING)) this.O.delete(t);
315
369
  }
316
- if (!this.v.size) {
317
- if (this.tt & STATUS_PENDING && this.U && !this.L && this.et) {
318
- this.U = !!(this.et.S & this.tt);
370
+ if (!this.O.size) {
371
+ if (this.tt & STATUS_PENDING && this.I && !this.H && this.et) {
372
+ this.I = !!(this.et.S & this.tt);
319
373
  } else {
320
- this.U = false;
374
+ this.I = false;
321
375
  }
322
- if (!this.U) {
323
- setSignal(this.D, false);
376
+ if (!this.I) {
377
+ setSignal(this.v, false);
324
378
  if (attrHooks !== null && this.tt & STATUS_PENDING) attrHooks.boundaryFallback(this, this.et, false);
325
379
  if (this.rt) {
326
- try {
327
- this.nt = untrack(() => this.rt());
328
- } catch {
329
- /* value not yet committed _prevOn stays stale, next notify will reset */}
380
+ // A throw (value not yet committed) leaves _prevOn stale; the next
381
+ // notify then resets.
382
+ const t = this.it();
383
+ if (t !== ON_INIT) this.st = t;
330
384
  }
331
385
  }
332
386
  }
@@ -334,16 +388,17 @@ class CollectionQueue extends Queue {
334
388
  }
335
389
  }
336
390
 
337
- function createCollectionBoundary(t, e, r, n) {
338
- const s = createOwner();
339
- if (_revealUsed) setContext(RevealControllerContext, null, s);
391
+ function createCollectionBoundary(t, e, r, s) {
392
+ const n = createOwner();
393
+ if (_revealUsed) setContext(RevealControllerContext, null, n);
340
394
  const i = new CollectionQueue(t);
395
+ i.nt = n;
341
396
  if (t === STATUS_ERROR) i._ = signal(undefined, {
342
397
  ownedWrite: true,
343
- V: true
398
+ q: true
344
399
  });
345
- if (n) i.rt = n;
346
- const o = i.et = createBoundChildren(s, e, i, t);
400
+ if (s) i.rt = s;
401
+ const o = i.et = createBoundChildren(n, e, i, t);
347
402
  // Prime source tracking so reveal registration sees pending sources.
348
403
  untrack(() => {
349
404
  let e = false;
@@ -352,23 +407,23 @@ function createCollectionBoundary(t, e, r, n) {
352
407
  } catch (t) {
353
408
  if (t instanceof NotReadyError) e = true; else throw t;
354
409
  }
355
- i.U = e || !!(o.S & t) || o.o?._ instanceof NotReadyError;
410
+ i.I = e || !!(o.S & t) || o.o?._ instanceof NotReadyError;
356
411
  });
357
412
  const l = _revealUsed && t === STATUS_PENDING ? getContext(RevealControllerContext) : null;
358
413
  if (l) {
359
414
  i.W = l;
360
- l.Z(i);
415
+ l.Y(i);
361
416
  cleanup(() => l.$(i));
362
417
  }
363
418
  return accessor(computed(() => {
364
- if (!read(i.D)) {
419
+ if (!read(i.v)) {
365
420
  const t = read(o);
366
- if (!untrack(() => read(i.D))) return i.L = true, t;
421
+ if (!untrack(() => read(i.v))) return i.H = true, t;
367
422
  }
368
423
  // Collapsed reveal slots suppress their own output entirely; the
369
424
  // renderer treats the hole as empty, so the cast never leaks to users
370
425
  // outside a `createRevealOrder` scope.
371
- if (_revealUsed && read(i.P)) return undefined;
426
+ if (_revealUsed && read(i.D)) return undefined;
372
427
  return r(i);
373
428
  },
374
429
  // Boundary structure, not a user source: its value is fallback-or-content and
@@ -376,7 +431,7 @@ function createCollectionBoundary(t, e, r, n) {
376
431
  // by snapshot capture. The tree no longer carries foreign status flags, so
377
432
  // capture can't rely on PENDING to skip this node the way it used to.
378
433
  {
379
- V: true
434
+ q: true
380
435
  }));
381
436
  }
382
437
 
@@ -430,11 +485,11 @@ function createCollectionBoundary(t, e, r, n) {
430
485
  * ```
431
486
  */ function createErrorBoundary(t, e) {
432
487
  return createCollectionBoundary(STATUS_ERROR, t, t => e(accessor(t._), () => {
433
- for (const e of t.v) {
488
+ for (const e of t.O) {
434
489
  // Non-computed sources (patch-channel registrations under plain
435
490
  // owners) are not recomputable — their reset is the record's next
436
491
  // transition re-applying the patch (re-audit 2, P1-4).
437
- if (e.ot !== undefined) recompute(e);
492
+ if (e.ht !== undefined) recompute(e);
438
493
  }
439
494
  schedule();
440
495
  }));
@@ -483,21 +538,21 @@ function createCollectionBoundary(t, e, r, n) {
483
538
  */ function createRevealOrder(t, e) {
484
539
  _revealUsed = true;
485
540
  const r = createOwner();
486
- const n = getContext(RevealControllerContext);
487
- const s = e?.order || SEQUENTIAL_ACCESSOR, i = e?.collapsed || FALSE_ACCESSOR;
488
- const o = new RevealController(s, i);
541
+ const s = getContext(RevealControllerContext);
542
+ const n = e?.order || SEQUENTIAL_ACCESSOR, i = e?.collapsed || FALSE_ACCESSOR;
543
+ const o = new RevealController(n, i);
489
544
  setContext(RevealControllerContext, o, r);
490
545
  return runWithOwner(r, () => {
491
546
  const e = t();
492
547
  computed(() => {
493
- s();
548
+ n();
494
549
  i();
495
550
  o.B();
496
551
  });
497
- if (n) {
498
- o.j = n;
499
- n.Z(o);
500
- cleanup(() => n.$(o));
552
+ if (s) {
553
+ o.P = s;
554
+ s.Y(o);
555
+ cleanup(() => s.$(o));
501
556
  }
502
557
  return e;
503
558
  });
@@ -551,36 +606,36 @@ function createCollectionBoundary(t, e, r, n) {
551
606
  }
552
607
 
553
608
  function flattenArray(t, e = [], r) {
554
- let n = null;
555
- let s = false;
609
+ let s = null;
610
+ let n = false;
556
611
  for (let i = 0; i < t.length; i++) {
557
612
  try {
558
- let n = t[i];
559
- if (typeof n === "function" && !n.length) {
613
+ let s = t[i];
614
+ if (typeof s === "function" && !s.length) {
560
615
  if (r?.doNotUnwrap) {
561
- e.push(n);
562
- s = true;
616
+ e.push(s);
617
+ n = true;
563
618
  continue;
564
619
  }
565
620
  do {
566
- n = n();
567
- } while (typeof n === "function" && !n.length);
621
+ s = s();
622
+ } while (typeof s === "function" && !s.length);
568
623
  }
569
- if (Array.isArray(n)) {
624
+ if (Array.isArray(s)) {
570
625
  // OR, don't overwrite: an accessor already pushed under doNotUnwrap
571
626
  // still needs the resolving wrapper even when a later sibling
572
627
  // fragment contains no functions (#3133).
573
- s = flattenArray(n, e, r) || s;
574
- } else if (r?.skipNonRendered && (n == null || n === true || n === false || n === "")) {
628
+ n = flattenArray(s, e, r) || n;
629
+ } else if (r?.skipNonRendered && (s == null || s === true || s === false || s === "")) {
575
630
  // skip
576
- } else e.push(n);
631
+ } else e.push(s);
577
632
  } catch (t) {
578
633
  if (!(t instanceof NotReadyError)) throw t;
579
- n = t;
634
+ s = t;
580
635
  }
581
636
  }
582
- if (n) throw n;
583
- return s;
637
+ if (s) throw s;
638
+ return n;
584
639
  }
585
640
 
586
641
  export { CollectionQueue, RevealController, createErrorBoundary, createLoadingBoundary, createRevealOrder, flatten };