@solidjs/signals 2.0.0-rc.6 → 2.0.0-rc.7

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 (65) hide show
  1. package/dist/dev.js +2033 -1291
  2. package/dist/node.cjs +1821 -2401
  3. package/dist/node.dev.cjs +13724 -0
  4. package/dist/prod/boundaries.js +3 -1
  5. package/dist/prod/core/async.js +6 -1
  6. package/dist/prod/core/attribution-hooks.js +3 -0
  7. package/dist/prod/core/constants.js +9 -1
  8. package/dist/prod/core/context.js +10 -16
  9. package/dist/prod/core/core.js +215 -139
  10. package/dist/prod/core/dev.js +2 -0
  11. package/dist/prod/core/effect.js +37 -28
  12. package/dist/prod/core/external.js +2 -2
  13. package/dist/prod/core/graph.js +35 -31
  14. package/dist/prod/core/heap.js +34 -40
  15. package/dist/prod/core/lanes.js +41 -27
  16. package/dist/prod/core/optimistic.js +42 -32
  17. package/dist/prod/core/owner.js +32 -32
  18. package/dist/prod/core/scheduler.js +140 -154
  19. package/dist/prod/core/verdict.js +31 -34
  20. package/dist/prod/index.js +0 -2
  21. package/dist/prod/map.js +104 -94
  22. package/dist/prod/signals.js +51 -34
  23. package/dist/prod/store/next/optimistic.js +153 -172
  24. package/dist/prod/store/next/reconcile.js +140 -288
  25. package/dist/prod/store/next/store.js +307 -237
  26. package/dist/prod/store/store.js +2 -2
  27. package/dist/types/core/attribution-hooks.d.ts +64 -0
  28. package/dist/types/core/attribution.d.ts +265 -9
  29. package/dist/types/core/constants.d.ts +8 -0
  30. package/dist/types/core/core.d.ts +12 -3
  31. package/dist/types/core/dev.d.ts +49 -8
  32. package/dist/types/core/heap.d.ts +5 -3
  33. package/dist/types/core/invariants.d.ts +1 -1
  34. package/dist/types/core/lanes.d.ts +10 -0
  35. package/dist/types/core/scheduler.d.ts +9 -4
  36. package/dist/types/signals.d.ts +10 -0
  37. package/dist/types/store/index.d.ts +3 -6
  38. package/dist/types/store/next/optimistic.d.ts +4 -2
  39. package/dist/types/store/next/reconcile.d.ts +5 -12
  40. package/dist/types/store/next/store.d.ts +3 -9
  41. package/dist/types/store/next/target.d.ts +20 -46
  42. package/dist/types/store/store.d.ts +14 -9
  43. package/dist/types-cjs/core/attribution-hooks.d.cts +64 -0
  44. package/dist/types-cjs/core/attribution.d.cts +265 -9
  45. package/dist/types-cjs/core/constants.d.cts +8 -0
  46. package/dist/types-cjs/core/core.d.cts +12 -3
  47. package/dist/types-cjs/core/dev.d.cts +49 -8
  48. package/dist/types-cjs/core/heap.d.cts +5 -3
  49. package/dist/types-cjs/core/invariants.d.cts +1 -1
  50. package/dist/types-cjs/core/lanes.d.cts +10 -0
  51. package/dist/types-cjs/core/scheduler.d.cts +9 -4
  52. package/dist/types-cjs/signals.d.cts +10 -0
  53. package/dist/types-cjs/store/index.d.cts +3 -6
  54. package/dist/types-cjs/store/next/optimistic.d.cts +4 -2
  55. package/dist/types-cjs/store/next/reconcile.d.cts +5 -12
  56. package/dist/types-cjs/store/next/store.d.cts +3 -9
  57. package/dist/types-cjs/store/next/target.d.cts +20 -46
  58. package/dist/types-cjs/store/store.d.cts +14 -9
  59. package/package.json +3 -2
  60. package/dist/prod/store/next/patch-hooks.js +0 -13
  61. package/dist/prod/store/next/patch.js +0 -614
  62. package/dist/types/store/next/patch-hooks.d.ts +0 -41
  63. package/dist/types/store/next/patch.d.ts +0 -91
  64. package/dist/types-cjs/store/next/patch-hooks.d.cts +0 -41
  65. package/dist/types-cjs/store/next/patch.d.cts +0 -91
@@ -1,6 +1,6 @@
1
- import { EFFECT_RENDER, EFFECT_USER, STATUS_PENDING, REACTIVE_IN_HEAP_HEIGHT, REACTIVE_DISPOSED, CONFIG_HELD_TRUTH, REACTIVE_ZOMBIE, CONFIG_HAS_LANE, CONFIG_HAS_SNAPSHOT, REACTIVE_RECOMPUTING_DEPS, REACTIVE_MISSED_WAKE, CONFIG_IN_SNAPSHOT_SCOPE, REACTIVE_SNAPSHOT_STALE, REACTIVE_OPTIMISTIC_DIRTY, NOT_PENDING, CONFIG_HAS_COMPANIONS, EFFECT_TRACKED, REACTIVE_REASK, REACTIVE_MANUAL_WRITE, STATUS_UNINITIALIZED, CONFIG_AUTHORITATIVE_READ } from "./constants.js";
1
+ import { EFFECT_RENDER, EFFECT_USER, STATUS_PENDING, REACTIVE_IN_HEAP_HEIGHT, REACTIVE_DISPOSED, CONFIG_HELD_TRUTH, REACTIVE_ZOMBIE, CONFIG_HAS_LANE, CONFIG_HAS_SNAPSHOT, REACTIVE_RECOMPUTING_DEPS, REACTIVE_MISSED_WAKE, CONFIG_IN_SNAPSHOT_SCOPE, REACTIVE_SNAPSHOT_STALE, REACTIVE_OPTIMISTIC_DIRTY, NOT_PENDING, CONFIG_SLOT_NODE, CONFIG_HAS_COMPANIONS, EFFECT_TRACKED, REACTIVE_REASK, REACTIVE_MANUAL_WRITE, STATUS_UNINITIALIZED, CONFIG_AUTHORITATIVE_READ } from "./constants.js";
2
2
 
3
- import { currentOptimisticLane } from "./core.js";
3
+ import { currentOptimisticLane, slotUnobservedHook } from "./core.js";
4
4
 
5
5
  import { DEV } from "./dev.js";
6
6
 
@@ -21,14 +21,14 @@ const transitions = new Set;
21
21
  const dirtyQueue = {
22
22
  eE: new Array(2e3).fill(undefined),
23
23
  tE: false,
24
- Qe: 0,
24
+ Me: 0,
25
25
  EE: 0
26
26
  };
27
27
 
28
28
  const zombieQueue = {
29
29
  eE: new Array(2e3).fill(undefined),
30
30
  tE: false,
31
- Qe: 0,
31
+ Me: 0,
32
32
  EE: 0
33
33
  };
34
34
 
@@ -63,7 +63,7 @@ const transientStoreNodes = new Set;
63
63
 
64
64
  function canUseSimpleSyncFlush(e) {
65
65
  const t = e.m;
66
- return transitions.size === 0 && activeLanes.size === 0 && e.Qt.length === 0 && t.ze.length === 0 && t.A.length === 0 && t.En.size === 0 && transientStoreNodes.size === 0;
66
+ return transitions.size === 0 && activeLanes.size === 0 && e.Bt.length === 0 && t.Xe.length === 0 && t.A.length === 0 && t.En.size === 0 && transientStoreNodes.size === 0;
67
67
  }
68
68
 
69
69
  function sweepTransientStoreNodes() {
@@ -80,7 +80,7 @@ function sweepTransientStoreNodes() {
80
80
  // unmarked node for the same property).
81
81
  if (e.o?.t) continue;
82
82
  transientStoreNodes.delete(e);
83
- e.o?.Et?.();
83
+ if (e.T & CONFIG_SLOT_NODE) slotUnobservedHook(e); else e.o?.Nt?.();
84
84
  }
85
85
  }
86
86
 
@@ -108,15 +108,15 @@ function setProjectionWriteActive(e) {
108
108
  */ function createBatch() {
109
109
  return {
110
110
  Te: clock,
111
- Lt: [],
111
+ Mt: [],
112
112
  _e: new Map,
113
- ze: [],
113
+ Xe: [],
114
114
  A: [],
115
115
  En: new Set,
116
116
  ue: [],
117
- Bt: {
118
- Mt: [ [], [] ],
119
- Qt: []
117
+ wt: {
118
+ jt: [ [], [] ],
119
+ Bt: []
120
120
  },
121
121
  sn: false,
122
122
  cn: new Set
@@ -127,12 +127,12 @@ function mergeTransitionState(e, t) {
127
127
  t.sn = e;
128
128
  e.ue.push(...t.ue);
129
129
  for (const i of activeLanes) if (i.Ae === t) i.Ae = e;
130
- if (t.ze.length) {
130
+ if (t.Xe.length) {
131
131
  // Move (don't copy): the global queue's batch may still be the outgoing
132
132
  // transition, and the adoption pass in initTransition would re-push its
133
133
  // contents into the target — duplicating every entry.
134
- e.ze.push(...t.ze);
135
- t.ze.length = 0;
134
+ e.Xe.push(...t.Xe);
135
+ t.Xe.length = 0;
136
136
  }
137
137
  if (t.A.length) {
138
138
  // Move (don't copy): the global queue's batch may still be the outgoing
@@ -142,26 +142,6 @@ function mergeTransitionState(e, t) {
142
142
  t.A.length = 0;
143
143
  }
144
144
  for (const i of t.En) e.En.add(i);
145
- // Patch-channel stash (store/next/patch.ts): entries held for the outgoing
146
- // transition must ride the merge like every other per-transition
147
- // collection — releaseBatch only reads the COMMITTING transition's stash,
148
- // so a stranded sidecar would silently drop its patches. Move (don't
149
- // copy), same aliasing rule as the collections above. The field is an
150
- // expando so this module stays free of patch imports (pay-for-use).
151
- const i = t.wt;
152
- if (i !== undefined) {
153
- t.wt = undefined;
154
- let n = e.wt;
155
- if (n !== undefined) n.push(...i); else n = e.wt = i;
156
- // Retarget the entries' coalescing stamps to the surviving stash
157
- // (opaque backref contract with store/next/patch.ts): without this a
158
- // post-merge emission misses the stamp and pushes a SECOND entry —
159
- // the record's patch applies twice at commit (re-audit 5, P1-2).
160
- for (let e = 0; e < i.length; e++) {
161
- const t = i[e].pc;
162
- if (t !== undefined && t.qe === i[e]) t.qa = n;
163
- }
164
- }
165
145
  for (const [i, n] of t._e) {
166
146
  let t = e._e.get(i);
167
147
  if (!t) e._e.set(i, t = new Set);
@@ -201,8 +181,8 @@ function mergeTransitionState(e, t) {
201
181
  // the awaiting transaction to landings that haven't happened; a merged
202
182
  // reporter deadlocked exactly that way).
203
183
  let i = false;
204
- for (let n = e.ut; n !== null; n = n.lt) {
205
- const r = n.ot;
184
+ for (let n = e.lt; n !== null; n = n.ot) {
185
+ const r = n.st;
206
186
  if (r.Re !== NOT_PENDING) {
207
187
  const e = r.Ae;
208
188
  const n = e != null ? currentTransition(e) : null;
@@ -212,10 +192,10 @@ function mergeTransitionState(e, t) {
212
192
  // (t === null) must leave the batch NOW — it commits at this flush's
213
193
  // end, which would reveal the confirmation under the live optimism
214
194
  // it just confirmed.
215
- const s = n === null ? currentBatch.Lt : n !== t && n.sn !== true ? n.Lt : null;
195
+ const s = n === null ? currentBatch.Mt : n !== t && n.sn !== true ? n.Mt : null;
216
196
  if (s !== null) i = stealEntangledCargo(s, t) || i;
217
197
  }
218
- if (n === e.je) break;
198
+ if (n === e.Be) break;
219
199
  }
220
200
  // The steal never activates the awaiting transaction: the predicate can
221
201
  // flip inside another transaction's finalize heap, and adopting the queue
@@ -244,11 +224,11 @@ function mergeTransitionState(e, t) {
244
224
  * committed value — while re-running them would re-derive the OLD world
245
225
  * and re-stage it over the held truth. The reveal re-notifies
246
226
  * (commitPendingNodes), which is when they re-derive for real. */ function stealEntangledCargo(e, t) {
247
- if (e === t.Lt || e.length === 0) return false;
227
+ if (e === t.Mt || e.length === 0) return false;
248
228
  for (let i = 0; i < e.length; i++) {
249
229
  const n = e[i];
250
230
  n.Ae = t;
251
- t.Lt.push(n);
231
+ t.Mt.push(n);
252
232
  // Override-covered nodes stay silent AND unmasked: the override is the
253
233
  // display (A17 — its staging never notified, its revert will), so their
254
234
  // subs saw nothing and re-running one would break the silence with a
@@ -307,30 +287,30 @@ function notifyHalted() {
307
287
  let queueRunToken = 0;
308
288
 
309
289
  class Queue {
310
- ke=null;
311
- Mt=[ [], [] ];
312
- Qt=[];
313
- jt=0;
290
+ Le=null;
291
+ jt=[ [], [] ];
292
+ Bt=[];
293
+ qt=0;
314
294
  created=clock;
315
295
  addChild(e) {
316
- this.Qt.push(e);
317
- e.ke = this;
296
+ this.Bt.push(e);
297
+ e.Le = this;
318
298
  }
319
299
  removeChild(e) {
320
- const t = this.Qt.indexOf(e);
300
+ const t = this.Bt.indexOf(e);
321
301
  if (t >= 0) {
322
- this.Qt.splice(t, 1);
323
- e.ke = null;
302
+ this.Bt.splice(t, 1);
303
+ e.Le = null;
324
304
  }
325
305
  }
326
306
  notify(e, t, i, n) {
327
- if (this.ke) return this.ke.notify(e, t, i, n);
307
+ if (this.Le) return this.Le.notify(e, t, i, n);
328
308
  return false;
329
309
  }
330
310
  run(e) {
331
- if (this.Mt[e - 1].length) {
332
- const t = this.Mt[e - 1];
333
- this.Mt[e - 1] = [];
311
+ if (this.jt[e - 1].length) {
312
+ const t = this.jt[e - 1];
313
+ this.jt[e - 1] = [];
334
314
  runQueue(t, e);
335
315
  }
336
316
  // Effects run here can dispose owners, and disposal removes queues from
@@ -340,12 +320,12 @@ class Queue {
340
320
  // can be recovered by rescanning from the front and every child still runs
341
321
  // exactly once. Children appended mid-pass carry a stale stamp and run,
342
322
  // matching the previous live-array behaviour.
343
- const t = this.Qt;
323
+ const t = this.Bt;
344
324
  const i = ++queueRunToken;
345
325
  for (let n = 0; n < t.length; ) {
346
326
  const r = t[n];
347
- if (r.jt !== i) {
348
- r.jt = i;
327
+ if (r.qt !== i) {
328
+ r.qt = i;
349
329
  r.run?.(e);
350
330
  if (t[n] !== r) {
351
331
  n = 0;
@@ -362,34 +342,34 @@ class Queue {
362
342
  const i = findLane(currentOptimisticLane);
363
343
  i.tn[e - 1].push(t);
364
344
  } else {
365
- this.Mt[e - 1].push(t);
345
+ this.jt[e - 1].push(t);
366
346
  }
367
347
  }
368
348
  schedule();
369
349
  }
370
350
  stashQueues(e) {
371
- e.Mt[0].push(...this.Mt[0]);
372
- e.Mt[1].push(...this.Mt[1]);
373
- this.Mt = [ [], [] ];
374
- for (let t = 0; t < this.Qt.length; t++) {
375
- let i = this.Qt[t];
376
- let n = e.Qt[t];
351
+ e.jt[0].push(...this.jt[0]);
352
+ e.jt[1].push(...this.jt[1]);
353
+ this.jt = [ [], [] ];
354
+ for (let t = 0; t < this.Bt.length; t++) {
355
+ let i = this.Bt[t];
356
+ let n = e.Bt[t];
377
357
  if (!n) {
378
358
  n = {
379
- Mt: [ [], [] ],
380
- Qt: []
359
+ jt: [ [], [] ],
360
+ Bt: []
381
361
  };
382
- e.Qt[t] = n;
362
+ e.Bt[t] = n;
383
363
  }
384
364
  i.stashQueues(n);
385
365
  }
386
366
  }
387
367
  restoreQueues(e) {
388
- this.Mt[0].push(...e.Mt[0]);
389
- this.Mt[1].push(...e.Mt[1]);
390
- for (let t = 0; t < e.Qt.length; t++) {
391
- const i = e.Qt[t];
392
- let n = this.Qt[t];
368
+ this.jt[0].push(...e.jt[0]);
369
+ this.jt[1].push(...e.jt[1]);
370
+ for (let t = 0; t < e.Bt.length; t++) {
371
+ const i = e.Bt[t];
372
+ let n = this.Bt[t];
393
373
  if (n) n.restoreQueues(i);
394
374
  }
395
375
  }
@@ -401,9 +381,9 @@ class GlobalQueue extends Queue {
401
381
  // transition is active, the active transition itself after initTransition.
402
382
  m=createBatch();
403
383
  static Fe;
404
- static He;
405
- static it;
406
- static qt=null;
384
+ static ke;
385
+ static ut;
386
+ static Wt=null;
407
387
  // Store-side hook: drops a keyless affects() mark's identity scope when the
408
388
  // carrier node's last registration releases (wired by store.ts, mirroring
409
389
  // _clearOptimisticStore).
@@ -417,8 +397,8 @@ class GlobalQueue extends Queue {
417
397
  static N=null;
418
398
  // External-source bridge (wired by enableExternalSource(); null while no
419
399
  // config is active — including after _resetExternalSourceConfig()).
420
- static Pt=null;
421
- static ht=null;
400
+ static Ft=null;
401
+ static gt=null;
422
402
  // Verdict-layer hooks (wired by verdict.ts when isPending()/latest() are
423
403
  // imported; null in apps that never use them). Call sites either guard for
424
404
  // null or sit behind state only the verdict layer can create (`!` is safe
@@ -429,15 +409,15 @@ class GlobalQueue extends Queue {
429
409
  static de=null;
430
410
  static me=null;
431
411
  static un=null;
432
- static gt=null;
433
- static Ht=null;
434
- static kt=null;
435
- static et=null;
412
+ static Vt=null;
413
+ static bt=null;
414
+ static Lt=null;
415
+ static nt=null;
436
416
  static k=null;
437
- static Wt=null;
417
+ static zt=null;
438
418
  // Re-asks probes whose verdict was provisionally suppressed by a fresh read
439
419
  // of a held value, once the transaction gains an async blocker (#3028).
440
- static zt=null;
420
+ static Kt=null;
441
421
  // Optimistic-engine hooks (wired by core/optimistic.ts via
442
422
  // installOptimisticEngine(), called from verdict.ts / createOptimistic /
443
423
  // createOptimisticStore — every module that can create optimistic state).
@@ -445,7 +425,7 @@ class GlobalQueue extends Queue {
445
425
  // `_overrideValue` slot, a lane in `activeLanes`, an `_optimisticNodes`
446
426
  // entry, or a non-null `currentOptimisticLane`, so `!` invocations are safe
447
427
  // once the gate holds.
448
- static xt=null;
428
+ static yt=null;
449
429
  static Tn=null;
450
430
  static dn=null;
451
431
  static In=null;
@@ -454,16 +434,17 @@ class GlobalQueue extends Queue {
454
434
  * apply at lane-effect timing — visible in flight, unlike the regular
455
435
  * effect queues an action stashes. Injected; null when unused. */
456
436
  static ln=null;
457
- static vt=null;
458
- static Vt=null;
459
- static bt=null;
460
- static Be=null;
461
- static $e=null;
462
- /** Authoritative-view reader wakeup (until()): installed at first until() call.
463
- * Call sites are gated by CONFIG_AUTHORITATIVE_OBSERVED, which only until()'s
464
- * carve-out read can set, so `!` invocations are safe once the gate holds. */
437
+ static Ut=null;
438
+ static kt=null;
439
+ static xt=null;
440
+ static Je=null;
441
+ static tt=null;
442
+ /** Authoritative-view reader wakeup: installed by until() and refresh() before
443
+ * their first read. Call sites are gated by CONFIG_AUTHORITATIVE_OBSERVED, which
444
+ * only such a reader's carve-out read can set, so `!` invocations are safe once
445
+ * the gate holds (#3303). */
465
446
  static he=null;
466
- static Xe=null;
447
+ static et=null;
467
448
  static _n=null;
468
449
  flush() {
469
450
  if (this.fn) return;
@@ -472,7 +453,7 @@ class GlobalQueue extends Queue {
472
453
  // optimistic state. Commit and go; anything a commit hook schedules
473
454
  // (companion snaps, store folds notifying subs) re-arms `scheduled`
474
455
  // below and the outer drain loop takes the full spine next round.
475
- if (activeTransition === null && dirtyQueue.EE < dirtyQueue.Qe && this.Mt[0].length === 0 && this.Mt[1].length === 0 && this.Qt.length === 0 && canUseSimpleSyncFlush(this)) {
456
+ if (activeTransition === null && dirtyQueue.EE < dirtyQueue.Me && this.jt[0].length === 0 && this.jt[1].length === 0 && this.Bt.length === 0 && canUseSimpleSyncFlush(this)) {
476
457
  this.fn = true;
477
458
  try {
478
459
  // Sweep first: unobserved() pulls swept nodes out of the dirty heap,
@@ -484,7 +465,7 @@ class GlobalQueue extends Queue {
484
465
  this.fn = false;
485
466
  }
486
467
  clock++;
487
- scheduled = dirtyQueue.EE >= dirtyQueue.Qe || this.Mt[0].length !== 0 || this.Mt[1].length !== 0 || this.m.Lt.length !== 0;
468
+ scheduled = dirtyQueue.EE >= dirtyQueue.Me || this.jt[0].length !== 0 || this.jt[1].length !== 0 || this.m.Mt.length !== 0;
488
469
  return;
489
470
  }
490
471
  this.fn = true;
@@ -520,32 +501,32 @@ class GlobalQueue extends Queue {
520
501
  GlobalQueue.Nn(EFFECT_RENDER);
521
502
  GlobalQueue.Nn(EFFECT_USER);
522
503
  }
523
- this.stashQueues(e.Bt);
504
+ this.stashQueues(e.wt);
524
505
  clock++;
525
506
  // A kept ambient batch may hold pending nodes (#2916): stay
526
507
  // scheduled so the outer drain loop commits them via the plain
527
508
  // flush path instead of leaving them until the next natural flush.
528
- scheduled = dirtyQueue.EE >= dirtyQueue.Qe || this.m.Lt.length > 0;
529
- reassignPendingTransition(e.Lt);
509
+ scheduled = dirtyQueue.EE >= dirtyQueue.Me || this.m.Mt.length > 0;
510
+ reassignPendingTransition(e.Mt);
530
511
  activeTransition = null;
531
512
  finalizePureQueue(null, true);
532
513
  return;
533
514
  }
534
515
  const t = activeTransition;
535
516
  const i = this.m;
536
- i !== t && i.Lt.push(...t.Lt);
537
- this.restoreQueues(t.Bt);
517
+ i !== t && i.Mt.push(...t.Mt);
518
+ this.restoreQueues(t.wt);
538
519
  transitions.delete(t);
539
520
  activeTransition = null;
540
- reassignPendingTransition(i.Lt);
521
+ reassignPendingTransition(i.Mt);
541
522
  finalizePureQueue(t);
542
523
  if (i === t) {
543
524
  // Drop the dead Transition wrapper but keep its (drained) containers
544
525
  // as the ambient batch — late registrations during finalization live
545
526
  // there and must survive to the next flush.
546
527
  const e = createBatch();
547
- e.Lt = i.Lt;
548
- e.ze = i.ze;
528
+ e.Mt = i.Mt;
529
+ e.Xe = i.Xe;
549
530
  e.A = i.A;
550
531
  e.En = i.En;
551
532
  currentBatch = this.m = e;
@@ -553,7 +534,7 @@ class GlobalQueue extends Queue {
553
534
  } else {
554
535
  if (canUseSimpleSyncFlush(this)) {
555
536
  commitPendingNodes();
556
- if (dirtyQueue.EE >= dirtyQueue.Qe) {
537
+ if (dirtyQueue.EE >= dirtyQueue.Me) {
557
538
  runHeap(dirtyQueue, GlobalQueue.Fe);
558
539
  commitPendingNodes();
559
540
  }
@@ -564,7 +545,7 @@ class GlobalQueue extends Queue {
564
545
  }
565
546
  clock++;
566
547
  // Check if finalization added items to the heap (from optimistic reversion)
567
- scheduled = dirtyQueue.EE >= dirtyQueue.Qe;
548
+ scheduled = dirtyQueue.EE >= dirtyQueue.Me;
568
549
  // Run lane effects first (for ready lanes), then regular effects
569
550
  activeLanes.size && GlobalQueue.Nn(EFFECT_RENDER);
570
551
  this.run(EFFECT_RENDER);
@@ -581,21 +562,31 @@ class GlobalQueue extends Queue {
581
562
  // Only track async if the boundary is propagating STATUS_PENDING (not caught by boundary)
582
563
  if (t & STATUS_PENDING) {
583
564
  if (i & STATUS_PENDING) {
584
- const t = n !== undefined ? n : e.o?._;
565
+ // Callers pass either nothing or this node's own `_x._error`, so `??`
566
+ // is exact (a null error falls back to the same null).
567
+ const t = n ?? e.o?._;
585
568
  // A visibility-only mark notification (the affects() boundary
586
569
  // channel) updates display state on its way up but must be invisible
587
570
  // to completion accounting BY CONSTRUCTION: it never registers a
588
571
  // reporter and never counts toward the loading-boundary diagnostic.
589
572
  if (t?.l) return true;
590
- if (activeTransition && t) {
591
- const i = t.source;
592
- let n = activeTransition._e.get(i);
593
- if (!n) activeTransition._e.set(i, n = new Set);
594
- const r = n.size;
595
- n.add(e);
596
- if (n.size !== r) {
597
- schedule();
598
- GlobalQueue.zt?.(activeTransition);
573
+ if (t) {
574
+ // A reveal can discover a flight started in an earlier flush. Hold
575
+ // the staged writes with that reader (A15), even if the reader is
576
+ // new. Fresh/reset loading boundaries consume pending before it
577
+ // reaches here. A reader already parked in a transition must not
578
+ // open a second one.
579
+ if (!activeTransition && !e.Ae && currentBatch.Mt.length) this.initTransition();
580
+ if (activeTransition) {
581
+ const i = t.source;
582
+ let n = activeTransition._e.get(i);
583
+ if (!n) activeTransition._e.set(i, n = new Set);
584
+ const r = n.size;
585
+ n.add(e);
586
+ if (n.size !== r) {
587
+ schedule();
588
+ GlobalQueue.Kt?.(activeTransition);
589
+ }
599
590
  }
600
591
  }
601
592
  }
@@ -621,6 +612,11 @@ class GlobalQueue extends Queue {
621
612
  } else if (e) {
622
613
  const t = activeTransition;
623
614
  mergeTransitionState(e, t);
615
+ // Effects the outgoing transaction parked belong to the surviving one
616
+ // now: back onto the live queue, where this flush parks them under
617
+ // `transition` or runs them at its completion. The outgoing stash is
618
+ // never read again — the transaction is dead (#3310).
619
+ this.restoreQueues(t.wt);
624
620
  transitions.delete(t);
625
621
  activeTransition = e;
626
622
  }
@@ -635,15 +631,15 @@ class GlobalQueue extends Queue {
635
631
  // must not entangle unrelated writes to it; the same rule holds one hop
636
632
  // downstream: propagation never queues pended subscribers as pending
637
633
  // nodes, see propagateAffectsMark, #2893.
638
- for (let e = 0; e < t.Lt.length; e++) {
639
- const i = t.Lt[e];
634
+ for (let e = 0; e < t.Mt.length; e++) {
635
+ const i = t.Mt[e];
640
636
  i.Ae = activeTransition;
641
- activeTransition.Lt.push(i);
637
+ activeTransition.Mt.push(i);
642
638
  }
643
- for (let e = 0; e < t.ze.length; e++) {
644
- const i = t.ze[e];
639
+ for (let e = 0; e < t.Xe.length; e++) {
640
+ const i = t.Xe[e];
645
641
  i.Ae = activeTransition;
646
- activeTransition.ze.push(i);
642
+ activeTransition.Xe.push(i);
647
643
  }
648
644
  if (t.A.length) activeTransition.A.push(...t.A);
649
645
  for (const e of t.En) activeTransition.En.add(e);
@@ -671,7 +667,7 @@ class GlobalQueue extends Queue {
671
667
  }
672
668
 
673
669
  function queuePendingNode(e) {
674
- currentBatch.Lt.push(e);
670
+ currentBatch.Mt.push(e);
675
671
  }
676
672
 
677
673
  // Sticky: flips true on the first refresh() ever (the only setter of
@@ -695,7 +691,7 @@ function armReaskClear() {
695
691
  function insertSubs(e, t = false) {
696
692
  // §12d: stamp before walking — setSignal's staged-rewrite fast path skips
697
693
  // the next walk for this node while the epoch holds (marking is idempotent).
698
- e.It = notifyEpoch;
694
+ e.Et = notifyEpoch;
699
695
  // Get source lane: prefer node's own lane over current context
700
696
  // This is important for isPending signals which need their own lane to flush immediately
701
697
  // Presence bits gate the optional-slot probes (see constants.ts): one
@@ -703,8 +699,8 @@ function insertSubs(e, t = false) {
703
699
  // lookups in the hottest notify loop. Bits are sticky — the field read
704
700
  // stays authoritative when a bit is set.
705
701
  const i = e.T;
706
- const n = (i & CONFIG_HAS_LANE ? e.o?.Je : undefined) || currentOptimisticLane;
707
- const r = (i & CONFIG_HAS_SNAPSHOT) !== 0 && e.o?.We !== undefined;
702
+ const n = (i & CONFIG_HAS_LANE ? e.o?.$e : undefined) || currentOptimisticLane;
703
+ const r = (i & CONFIG_HAS_SNAPSHOT) !== 0 && e.o?.Ye !== undefined;
708
704
  const s = reaskArmed;
709
705
  for (let i = e.u; i !== null; i = i.ae) {
710
706
  const e = i.ce;
@@ -719,7 +715,7 @@ function insertSubs(e, t = false) {
719
715
  // pass either re-reads them fresh or trims them), and neither does the
720
716
  // tail link: it is the read IN FLIGHT — read() links before it pulls, so
721
717
  // this very commit is what that read returns.
722
- if (e.ie & REACTIVE_RECOMPUTING_DEPS && i.Ft === e.Ke && i !== e.je) e.ie |= REACTIVE_MISSED_WAKE;
718
+ if (e.ie & REACTIVE_RECOMPUTING_DEPS && i.vt === e.ze && i !== e.Be) e.ie |= REACTIVE_MISSED_WAKE;
723
719
  if (r && e.T & CONFIG_IN_SNAPSHOT_SCOPE) {
724
720
  e.ie |= REACTIVE_SNAPSHOT_STALE;
725
721
  continue;
@@ -730,7 +726,7 @@ function insertSubs(e, t = false) {
730
726
  } else if (t) {
731
727
  e.ie |= REACTIVE_OPTIMISTIC_DIRTY;
732
728
  // No source lane means reversion - clear subscriber's lane so effects go to regular queue
733
- if (e.o) e.o.Je = undefined;
729
+ if (e.o) e.o.$e = undefined;
734
730
  }
735
731
  enqueueSub(e);
736
732
  }
@@ -750,7 +746,7 @@ function commitPendingNode(e) {
750
746
  e.be = e.Re;
751
747
  e.Re = NOT_PENDING;
752
748
  // Set _modified for effects, but not for tracked effects (they handle their own scheduling)
753
- if (e.ge && e.ge !== EFFECT_TRACKED) e.tt = true;
749
+ if (e.ge && e.ge !== EFFECT_TRACKED) e.He = true;
754
750
  // A quiet re-ask classification preserved through a held landing dies
755
751
  // with the value commit — the commit IS the reveal (#3178). Gated on the
756
752
  // staged value: status propagation queues pending nodes whose windows
@@ -764,7 +760,7 @@ function commitPendingNode(e) {
764
760
  t.Ne = false;
765
761
  t.ie &= ~REACTIVE_MANUAL_WRITE;
766
762
  if (!(t.S & STATUS_PENDING)) t.S &= ~STATUS_UNINITIALIZED;
767
- if (t.o != null && (t.o.Ye !== null || t.o.qe !== null)) GlobalQueue.He(t, false, true);
763
+ if (t.o != null && (t.o.Ke !== null || t.o.Ze !== null)) GlobalQueue.ke(t, false, true);
768
764
  if (e.T & CONFIG_HAS_COMPANIONS) GlobalQueue.un(e);
769
765
  }
770
766
 
@@ -779,17 +775,6 @@ function setStoreCommitHook(e) {
779
775
  storeCommitHook = e;
780
776
  }
781
777
 
782
- /** Patch-channel release hook (next/patch.ts): transition-stamped patch
783
- * emissions are released when THEIR batch commits. Transitions never
784
- * abort: failed actions still commit (only optimistic overrides revert),
785
- * and merged-away transitions hand their stash to the survivor
786
- * (mergeTransitionState) — every stash drains exactly once. Injected like
787
- * storeCommitHook to stay tree-shakeable. */ let patchCommitHook = null;
788
-
789
- function setPatchCommitHook(e) {
790
- patchCommitHook = e;
791
- }
792
-
793
778
  /** Held truth committed this finalize, awaiting its post-revert wake (see
794
779
  * finalizePureQueue): the commit IS the reveal, but subscribers must not
795
780
  * re-derive until the settling transaction's optimistic overrides have
@@ -798,7 +783,7 @@ function setPatchCommitHook(e) {
798
783
  * frame no timeline contains. */ const heldRevealed = [];
799
784
 
800
785
  function commitPendingNodes() {
801
- const e = currentBatch.Lt;
786
+ const e = currentBatch.Mt;
802
787
  for (let t = 0; t < e.length; t++) {
803
788
  const i = e[t];
804
789
  commitPendingNode(i);
@@ -821,7 +806,6 @@ function commitPendingNodes() {
821
806
  }
822
807
  e.length = 0;
823
808
  storeCommitHook?.();
824
- patchCommitHook?.(currentBatch);
825
809
  }
826
810
 
827
811
  function finalizePureQueue(e = null, t = false) {
@@ -829,8 +813,8 @@ function finalizePureQueue(e = null, t = false) {
829
813
  // For completing transitions or no-transition, resolve pending and revert optimistic
830
814
  const i = !t;
831
815
  if (i) commitPendingNodes();
832
- if (!t && globalQueue.Qt.length) checkBoundaryChildren(globalQueue);
833
- const n = dirtyQueue.EE >= dirtyQueue.Qe;
816
+ if (!t && globalQueue.Bt.length) checkBoundaryChildren(globalQueue);
817
+ const n = dirtyQueue.EE >= dirtyQueue.Me;
834
818
  if (n) runHeap(dirtyQueue, GlobalQueue.Fe);
835
819
  if (i) {
836
820
  if (n) commitPendingNodes();
@@ -838,7 +822,7 @@ function finalizePureQueue(e = null, t = false) {
838
822
  const t = e ?? globalQueue.m;
839
823
  // Optimistic reversion: a non-empty batch means _optimisticWrite ran,
840
824
  // which installed the engine's hooks.
841
- if (t.ze.length) GlobalQueue.Tn(t.ze);
825
+ if (t.Xe.length) GlobalQueue.Tn(t.Xe);
842
826
  // Replay entanglement: subs recorded by the read-time gate get rescheduled
843
827
  // so they re-run with the now-committed values visible. The ambient batch
844
828
  // replays too — laneReadsCommitted records readers whose committed-view
@@ -862,13 +846,13 @@ function finalizePureQueue(e = null, t = false) {
862
846
  // (the earlier sweep above ran while the marks were still live).
863
847
  if (t.A.length) {
864
848
  GlobalQueue.G(t.A);
865
- if (globalQueue.Qt.length) checkBoundaryChildren(globalQueue);
849
+ if (globalQueue.Bt.length) checkBoundaryChildren(globalQueue);
866
850
  }
867
851
  // A non-empty set means trackOptimisticStore ran, which installed the
868
852
  // hook; the hook iterates, clears, and schedules (keeping the loop out of
869
853
  // core lets esbuild shake it — rollup already folds the null guard). The
870
854
  // completing transition scopes the clear to its own layer keys (#2899).
871
- if (t.En.size) GlobalQueue.qt(t.En, e);
855
+ if (t.En.size) GlobalQueue.Wt(t.En, e);
872
856
  // Held-truth reveal wake (#3164), post-revert by construction: this
873
857
  // finalize committed confirming truth whose subscribers were masked all
874
858
  // hold — some re-derived against the committed view (the staging, or a
@@ -880,7 +864,7 @@ function finalizePureQueue(e = null, t = false) {
880
864
  // committed but the settling transaction's overrides still display.
881
865
  if (heldRevealed.length !== 0) {
882
866
  while (heldRevealed.length) insertSubs(heldRevealed.pop());
883
- if (dirtyQueue.EE >= dirtyQueue.Qe) {
867
+ if (dirtyQueue.EE >= dirtyQueue.Me) {
884
868
  runHeap(dirtyQueue, GlobalQueue.Fe);
885
869
  commitPendingNodes();
886
870
  }
@@ -892,7 +876,7 @@ function finalizePureQueue(e = null, t = false) {
892
876
  }
893
877
 
894
878
  function checkBoundaryChildren(e) {
895
- for (const t of e.Qt) {
879
+ for (const t of e.Bt) {
896
880
  t.se?.();
897
881
  checkBoundaryChildren(t);
898
882
  }
@@ -962,11 +946,11 @@ function runQueue(e, t) {
962
946
  function reporterBlocksSource(e, t) {
963
947
  if (e.ie & (REACTIVE_ZOMBIE | REACTIVE_DISPOSED)) return false;
964
948
  if (e.o?.le?.has(t)) return true;
965
- for (let i = e.ut; i; i = i.lt) {
966
- let e = i.ot;
949
+ for (let i = e.lt; i; i = i.ot) {
950
+ let e = i.st;
967
951
  while (e) {
968
- if (e === t || e.st === t) return true;
969
- e = e.o?.Tt;
952
+ if (e === t || e.rt === t) return true;
953
+ e = e.o?.St;
970
954
  }
971
955
  }
972
956
  return !!(e.S & STATUS_PENDING && e.o?._ instanceof NotReadyError && e.o?._.source === t);
@@ -974,7 +958,9 @@ function reporterBlocksSource(e, t) {
974
958
 
975
959
  function transitionComplete(e) {
976
960
  if (e.sn) return true;
977
- if (e.ue.length) return false;
961
+ if (e.ue.length) {
962
+ return false;
963
+ }
978
964
  let t = true;
979
965
  for (const [i, n] of e._e) {
980
966
  let r = false;
@@ -1043,4 +1029,4 @@ function runInTransition(e, t) {
1043
1029
  }
1044
1030
  }
1045
1031
 
1046
- export { GlobalQueue, Queue, activeAffectsMarks, activeLanes, activeTransition, armReaskClear, assignOrMergeLane, bumpNotifyEpoch, clock, createTransition, currentTransition, dirtyQueue, enforceLoadingBoundary, entangleConfirmingTransitions, finalizePureQueue, findLane, flush, globalQueue, haltReactivity, hasActiveOverride, insertSubs, notifyEpoch, patchCommitHook, projectionWriteActive, queuePendingNode, reaskArmed, resetErrorHalt, runAsTransitionBatch, runInTransition, schedule, setPatchCommitHook, setProjectionWriteActive, setStoreCommitHook, shiftAffectsMarks, storeCommitHook, zombieQueue };
1032
+ export { GlobalQueue, Queue, activeAffectsMarks, activeLanes, activeTransition, armReaskClear, assignOrMergeLane, bumpNotifyEpoch, clock, createTransition, currentTransition, dirtyQueue, enforceLoadingBoundary, entangleConfirmingTransitions, finalizePureQueue, findLane, flush, globalQueue, haltReactivity, hasActiveOverride, insertSubs, notifyEpoch, projectionWriteActive, queuePendingNode, reaskArmed, resetErrorHalt, runAsTransitionBatch, runInTransition, schedule, setProjectionWriteActive, setStoreCommitHook, shiftAffectsMarks, storeCommitHook, zombieQueue };