@solidjs/signals 2.0.0-beta.32 → 2.0.0-beta.34
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.
- package/dist/dev.js +235 -87
- package/dist/node.cjs +758 -635
- package/dist/prod/core/async.js +108 -54
- package/dist/prod/core/core.js +241 -204
- package/dist/prod/core/effect.js +27 -27
- package/dist/prod/core/external.js +4 -4
- package/dist/prod/core/graph.js +32 -32
- package/dist/prod/core/heap.js +36 -36
- package/dist/prod/core/lanes.js +14 -14
- package/dist/prod/core/optimistic.js +39 -39
- package/dist/prod/core/owner.js +53 -44
- package/dist/prod/core/scheduler.js +76 -72
- package/dist/prod/core/verdict.js +59 -48
- package/dist/prod/map.js +6 -6
- package/dist/prod/signals.js +2 -34
- package/dist/prod/store/optimistic.js +37 -32
- package/dist/prod/store/projection.js +41 -6
- package/dist/prod/store/store.js +7 -7
- package/dist/types/core/async.d.ts +9 -0
- package/dist/types/core/types.d.ts +24 -0
- package/dist/types/signals.d.ts +60 -4
- package/dist/types/store/store.d.ts +14 -0
- package/dist/types-cjs/core/async.d.cts +9 -0
- package/dist/types-cjs/core/types.d.cts +24 -0
- package/dist/types-cjs/signals.d.cts +60 -4
- package/dist/types-cjs/store/store.d.cts +14 -0
- package/package.json +1 -1
|
@@ -19,14 +19,14 @@ const transitions = new Set;
|
|
|
19
19
|
const dirtyQueue = {
|
|
20
20
|
eE: new Array(2e3).fill(undefined),
|
|
21
21
|
tE: false,
|
|
22
|
-
|
|
22
|
+
Ve: 0,
|
|
23
23
|
EE: 0
|
|
24
24
|
};
|
|
25
25
|
|
|
26
26
|
const zombieQueue = {
|
|
27
27
|
eE: new Array(2e3).fill(undefined),
|
|
28
28
|
tE: false,
|
|
29
|
-
|
|
29
|
+
Ve: 0,
|
|
30
30
|
EE: 0
|
|
31
31
|
};
|
|
32
32
|
|
|
@@ -65,7 +65,7 @@ function registerTransientStoreNode(e) {
|
|
|
65
65
|
|
|
66
66
|
function canUseSimpleSyncFlush(e) {
|
|
67
67
|
const t = e.m;
|
|
68
|
-
return transitions.size === 0 && activeLanes.size === 0 && e.vt.length === 0 && t.
|
|
68
|
+
return transitions.size === 0 && activeLanes.size === 0 && e.vt.length === 0 && t.Me.length === 0 && t.A.length === 0 && t.cn.size === 0 && transientStoreNodes.size === 0;
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
function sweepTransientStoreNodes() {
|
|
@@ -76,7 +76,7 @@ function sweepTransientStoreNodes() {
|
|
|
76
76
|
continue;
|
|
77
77
|
}
|
|
78
78
|
if (e.De !== NOT_PENDING) continue;
|
|
79
|
-
if (e.
|
|
79
|
+
if (e._e !== undefined && e._e !== NOT_PENDING) continue;
|
|
80
80
|
// A live affects() mark keeps the node addressable: sweeping it would
|
|
81
81
|
// detach the refcount from the slot (a fresh probe would upsert a new,
|
|
82
82
|
// unmarked node for the same property).
|
|
@@ -109,10 +109,10 @@ function setProjectionWriteActive(e) {
|
|
|
109
109
|
* land there directly — no per-field aliasing.
|
|
110
110
|
*/ function createBatch() {
|
|
111
111
|
return {
|
|
112
|
-
|
|
112
|
+
de: clock,
|
|
113
113
|
Qt: [],
|
|
114
|
-
|
|
115
|
-
|
|
114
|
+
Ie: new Map,
|
|
115
|
+
Me: [],
|
|
116
116
|
A: [],
|
|
117
117
|
cn: new Set,
|
|
118
118
|
ie: [],
|
|
@@ -128,13 +128,13 @@ function setProjectionWriteActive(e) {
|
|
|
128
128
|
function mergeTransitionState(e, t) {
|
|
129
129
|
t.fn = e;
|
|
130
130
|
e.ie.push(...t.ie);
|
|
131
|
-
for (const i of activeLanes) if (i.
|
|
132
|
-
if (t.
|
|
131
|
+
for (const i of activeLanes) if (i.Ne === t) i.Ne = e;
|
|
132
|
+
if (t.Me.length) {
|
|
133
133
|
// Move (don't copy): the global queue's batch may still be the outgoing
|
|
134
134
|
// transition, and the adoption pass in initTransition would re-push its
|
|
135
135
|
// contents into the target — duplicating every entry.
|
|
136
|
-
e.
|
|
137
|
-
t.
|
|
136
|
+
e.Me.push(...t.Me);
|
|
137
|
+
t.Me.length = 0;
|
|
138
138
|
}
|
|
139
139
|
if (t.A.length) {
|
|
140
140
|
// Move (don't copy): the global queue's batch may still be the outgoing
|
|
@@ -144,9 +144,9 @@ function mergeTransitionState(e, t) {
|
|
|
144
144
|
t.A.length = 0;
|
|
145
145
|
}
|
|
146
146
|
for (const i of t.cn) e.cn.add(i);
|
|
147
|
-
for (const [i, n] of t.
|
|
148
|
-
let t = e.
|
|
149
|
-
if (!t) e.
|
|
147
|
+
for (const [i, n] of t.Ie) {
|
|
148
|
+
let t = e.Ie.get(i);
|
|
149
|
+
if (!t) e.Ie.set(i, t = new Set);
|
|
150
150
|
for (const e of n) t.add(e);
|
|
151
151
|
}
|
|
152
152
|
for (const i of t.ln) e.ln.add(i);
|
|
@@ -193,24 +193,24 @@ function notifyHalted() {
|
|
|
193
193
|
let queueRunToken = 0;
|
|
194
194
|
|
|
195
195
|
class Queue {
|
|
196
|
-
|
|
196
|
+
ke=null;
|
|
197
197
|
bt=[ [], [] ];
|
|
198
198
|
vt=[];
|
|
199
199
|
kt=0;
|
|
200
200
|
created=clock;
|
|
201
201
|
addChild(e) {
|
|
202
202
|
this.vt.push(e);
|
|
203
|
-
e.
|
|
203
|
+
e.ke = this;
|
|
204
204
|
}
|
|
205
205
|
removeChild(e) {
|
|
206
206
|
const t = this.vt.indexOf(e);
|
|
207
207
|
if (t >= 0) {
|
|
208
208
|
this.vt.splice(t, 1);
|
|
209
|
-
e.
|
|
209
|
+
e.ke = null;
|
|
210
210
|
}
|
|
211
211
|
}
|
|
212
212
|
notify(e, t, i, n) {
|
|
213
|
-
if (this.
|
|
213
|
+
if (this.ke) return this.ke.notify(e, t, i, n);
|
|
214
214
|
return false;
|
|
215
215
|
}
|
|
216
216
|
run(e) {
|
|
@@ -288,7 +288,7 @@ class GlobalQueue extends Queue {
|
|
|
288
288
|
m=createBatch();
|
|
289
289
|
static Ce;
|
|
290
290
|
static me;
|
|
291
|
-
static
|
|
291
|
+
static et;
|
|
292
292
|
static Dt=null;
|
|
293
293
|
// Store-side hook: drops a keyless affects() mark's identity scope when the
|
|
294
294
|
// carrier node's last registration releases (wired by store.ts, mirroring
|
|
@@ -303,24 +303,24 @@ class GlobalQueue extends Queue {
|
|
|
303
303
|
static h=null;
|
|
304
304
|
// External-source bridge (wired by enableExternalSource(); null while no
|
|
305
305
|
// config is active — including after _resetExternalSourceConfig()).
|
|
306
|
-
static dt=null;
|
|
307
306
|
static It=null;
|
|
307
|
+
static St=null;
|
|
308
308
|
// Verdict-layer hooks (wired by verdict.ts when isPending()/latest() are
|
|
309
309
|
// imported; null in apps that never use them). Call sites either guard for
|
|
310
310
|
// null or sit behind state only the verdict layer can create (`!` is safe
|
|
311
311
|
// there: `_pendingSignal`/`_latestValueComputed` are only ever assigned by
|
|
312
312
|
// verdict.ts, and `pendingCheckActive`/`latestReadActive` only flip inside
|
|
313
313
|
// isPending()/latest()).
|
|
314
|
-
static
|
|
315
|
-
static
|
|
316
|
-
static
|
|
314
|
+
static Pe=null;
|
|
315
|
+
static Se=null;
|
|
316
|
+
static Oe=null;
|
|
317
317
|
static un=null;
|
|
318
|
-
static St=null;
|
|
319
318
|
static At=null;
|
|
320
|
-
static
|
|
321
|
-
static
|
|
319
|
+
static Ct=null;
|
|
320
|
+
static ht=null;
|
|
321
|
+
static Be=null;
|
|
322
322
|
static k=null;
|
|
323
|
-
static
|
|
323
|
+
static Lt=null;
|
|
324
324
|
// Optimistic-engine hooks (wired by core/optimistic.ts via
|
|
325
325
|
// installOptimisticEngine(), called from verdict.ts / createOptimistic /
|
|
326
326
|
// createOptimisticStore — every module that can create optimistic state).
|
|
@@ -328,17 +328,17 @@ class GlobalQueue extends Queue {
|
|
|
328
328
|
// `_overrideValue` slot, a lane in `activeLanes`, an `_optimisticNodes`
|
|
329
329
|
// entry, or a non-null `currentOptimisticLane`, so `!` invocations are safe
|
|
330
330
|
// once the gate holds.
|
|
331
|
-
static
|
|
331
|
+
static Gt=null;
|
|
332
332
|
static En=null;
|
|
333
333
|
static Tn=null;
|
|
334
334
|
static dn=null;
|
|
335
335
|
static In=null;
|
|
336
|
-
static Ot=null;
|
|
337
|
-
static Ct=null;
|
|
338
336
|
static Rt=null;
|
|
339
|
-
static
|
|
337
|
+
static Ot=null;
|
|
338
|
+
static Pt=null;
|
|
339
|
+
static je=null;
|
|
340
|
+
static $e=null;
|
|
340
341
|
static ze=null;
|
|
341
|
-
static Ke=null;
|
|
342
342
|
static Nn=null;
|
|
343
343
|
flush() {
|
|
344
344
|
if (this.gt) return;
|
|
@@ -376,7 +376,7 @@ class GlobalQueue extends Queue {
|
|
|
376
376
|
// A kept ambient batch may hold pending nodes (#2916): stay
|
|
377
377
|
// scheduled so the outer drain loop commits them via the plain
|
|
378
378
|
// flush path instead of leaving them until the next natural flush.
|
|
379
|
-
scheduled = dirtyQueue.EE >= dirtyQueue.
|
|
379
|
+
scheduled = dirtyQueue.EE >= dirtyQueue.Ve || this.m.Qt.length > 0;
|
|
380
380
|
reassignPendingTransition(e.Qt);
|
|
381
381
|
activeTransition = null;
|
|
382
382
|
finalizePureQueue(null, true);
|
|
@@ -396,7 +396,7 @@ class GlobalQueue extends Queue {
|
|
|
396
396
|
// there and must survive to the next flush.
|
|
397
397
|
const e = createBatch();
|
|
398
398
|
e.Qt = i.Qt;
|
|
399
|
-
e.
|
|
399
|
+
e.Me = i.Me;
|
|
400
400
|
e.A = i.A;
|
|
401
401
|
e.cn = i.cn;
|
|
402
402
|
currentBatch = this.m = e;
|
|
@@ -404,7 +404,7 @@ class GlobalQueue extends Queue {
|
|
|
404
404
|
} else {
|
|
405
405
|
if (canUseSimpleSyncFlush(this)) {
|
|
406
406
|
commitPendingNodes();
|
|
407
|
-
if (dirtyQueue.EE >= dirtyQueue.
|
|
407
|
+
if (dirtyQueue.EE >= dirtyQueue.Ve) {
|
|
408
408
|
runHeap(dirtyQueue, GlobalQueue.Ce);
|
|
409
409
|
commitPendingNodes();
|
|
410
410
|
}
|
|
@@ -415,7 +415,7 @@ class GlobalQueue extends Queue {
|
|
|
415
415
|
}
|
|
416
416
|
clock++;
|
|
417
417
|
// Check if finalization added items to the heap (from optimistic reversion)
|
|
418
|
-
scheduled = dirtyQueue.EE >= dirtyQueue.
|
|
418
|
+
scheduled = dirtyQueue.EE >= dirtyQueue.Ve;
|
|
419
419
|
// Run lane effects first (for ready lanes), then regular effects
|
|
420
420
|
activeLanes.size && GlobalQueue.In(EFFECT_RENDER);
|
|
421
421
|
this.run(EFFECT_RENDER);
|
|
@@ -440,8 +440,8 @@ class GlobalQueue extends Queue {
|
|
|
440
440
|
if (t?.l) return true;
|
|
441
441
|
if (activeTransition && t) {
|
|
442
442
|
const i = t.source;
|
|
443
|
-
let n = activeTransition.
|
|
444
|
-
if (!n) activeTransition.
|
|
443
|
+
let n = activeTransition.Ie.get(i);
|
|
444
|
+
if (!n) activeTransition.Ie.set(i, n = new Set);
|
|
445
445
|
const s = n.size;
|
|
446
446
|
n.add(e);
|
|
447
447
|
if (n.size !== s) schedule();
|
|
@@ -454,7 +454,7 @@ class GlobalQueue extends Queue {
|
|
|
454
454
|
initTransition(e) {
|
|
455
455
|
if (e) e = currentTransition(e);
|
|
456
456
|
if (e && e === activeTransition) return;
|
|
457
|
-
if (!e && activeTransition && activeTransition.
|
|
457
|
+
if (!e && activeTransition && activeTransition.de === clock) return;
|
|
458
458
|
if (!activeTransition) {
|
|
459
459
|
activeTransition = e ?? createBatch();
|
|
460
460
|
} else if (e) {
|
|
@@ -464,7 +464,7 @@ class GlobalQueue extends Queue {
|
|
|
464
464
|
activeTransition = e;
|
|
465
465
|
}
|
|
466
466
|
transitions.add(activeTransition);
|
|
467
|
-
activeTransition.
|
|
467
|
+
activeTransition.de = clock;
|
|
468
468
|
const t = this.m;
|
|
469
469
|
if (t !== activeTransition) {
|
|
470
470
|
// Adopt the ambient batch into the transaction, then make the
|
|
@@ -476,13 +476,13 @@ class GlobalQueue extends Queue {
|
|
|
476
476
|
// nodes, see propagateAffectsMark, #2893.
|
|
477
477
|
for (let e = 0; e < t.Qt.length; e++) {
|
|
478
478
|
const i = t.Qt[e];
|
|
479
|
-
i.
|
|
479
|
+
i.Ne = activeTransition;
|
|
480
480
|
activeTransition.Qt.push(i);
|
|
481
481
|
}
|
|
482
|
-
for (let e = 0; e < t.
|
|
483
|
-
const i = t.
|
|
484
|
-
i.
|
|
485
|
-
activeTransition.
|
|
482
|
+
for (let e = 0; e < t.Me.length; e++) {
|
|
483
|
+
const i = t.Me[e];
|
|
484
|
+
i.Ne = activeTransition;
|
|
485
|
+
activeTransition.Me.push(i);
|
|
486
486
|
}
|
|
487
487
|
if (t.A.length) activeTransition.A.push(...t.A);
|
|
488
488
|
for (const e of t.cn) activeTransition.cn.add(e);
|
|
@@ -495,7 +495,7 @@ class GlobalQueue extends Queue {
|
|
|
495
495
|
currentBatch = this.m = activeTransition;
|
|
496
496
|
}
|
|
497
497
|
for (const e of activeLanes) {
|
|
498
|
-
if (!e.
|
|
498
|
+
if (!e.Ne) e.Ne = activeTransition;
|
|
499
499
|
}
|
|
500
500
|
}
|
|
501
501
|
}
|
|
@@ -516,49 +516,53 @@ function armReaskClear() {
|
|
|
516
516
|
function insertSubs(e, t = false) {
|
|
517
517
|
// Get source lane: prefer node's own lane over current context
|
|
518
518
|
// This is important for isPending signals which need their own lane to flush immediately
|
|
519
|
-
const i = e.
|
|
520
|
-
const n = e.
|
|
519
|
+
const i = e.Ke || currentOptimisticLane;
|
|
520
|
+
const n = e.Le !== undefined;
|
|
521
521
|
const s = reaskArmed;
|
|
522
|
-
for (let r = e.o; r !== null; r = r.
|
|
522
|
+
for (let r = e.o; r !== null; r = r.le) {
|
|
523
523
|
// A value-change notification is a new question for the subscriber: any
|
|
524
524
|
// pending re-ask mark (refresh) it carried is superseded.
|
|
525
|
-
if (s) r.
|
|
526
|
-
if (n && r.
|
|
527
|
-
r.
|
|
525
|
+
if (s) r.fe.se &= ~REACTIVE_REASK;
|
|
526
|
+
if (n && r.fe.T & CONFIG_IN_SNAPSHOT_SCOPE) {
|
|
527
|
+
r.fe.se |= REACTIVE_SNAPSHOT_STALE;
|
|
528
528
|
continue;
|
|
529
529
|
}
|
|
530
530
|
if (t && i) {
|
|
531
|
-
r.
|
|
532
|
-
assignOrMergeLane(r.
|
|
531
|
+
r.fe.se |= REACTIVE_OPTIMISTIC_DIRTY;
|
|
532
|
+
assignOrMergeLane(r.fe, i);
|
|
533
533
|
} else if (t) {
|
|
534
|
-
r.
|
|
534
|
+
r.fe.se |= REACTIVE_OPTIMISTIC_DIRTY;
|
|
535
535
|
// No source lane means reversion - clear subscriber's lane so effects go to regular queue
|
|
536
|
-
r.
|
|
536
|
+
r.fe.Ke = undefined;
|
|
537
537
|
}
|
|
538
|
-
enqueueSub(r.
|
|
538
|
+
enqueueSub(r.fe);
|
|
539
539
|
}
|
|
540
540
|
}
|
|
541
541
|
|
|
542
542
|
function commitPendingNode(e) {
|
|
543
543
|
const t = e;
|
|
544
|
-
if (!t.
|
|
544
|
+
if (!t.ce) {
|
|
545
545
|
if (e.De !== NOT_PENDING) {
|
|
546
|
-
e.
|
|
546
|
+
e.Ue = e.De;
|
|
547
547
|
e.De = NOT_PENDING;
|
|
548
548
|
}
|
|
549
|
-
if (e.
|
|
549
|
+
if (e.ge || e.pe) GlobalQueue.un(e);
|
|
550
550
|
return;
|
|
551
551
|
}
|
|
552
552
|
if (e.De !== NOT_PENDING) {
|
|
553
|
-
e.
|
|
553
|
+
e.Ue = e.De;
|
|
554
554
|
e.De = NOT_PENDING;
|
|
555
555
|
// Set _modified for effects, but not for tracked effects (they handle their own scheduling)
|
|
556
|
-
if (e.
|
|
556
|
+
if (e.Re && e.Re !== EFFECT_TRACKED) e.Je = true;
|
|
557
557
|
}
|
|
558
|
+
// The committed hold is the first observable answer for a loading-window
|
|
559
|
+
// node — the window closes here, not at compute time (#2990). Unconditional
|
|
560
|
+
// store to an always-present computed slot.
|
|
561
|
+
t.Ee = false;
|
|
558
562
|
t.se &= ~REACTIVE_MANUAL_WRITE;
|
|
559
563
|
if (!(t.S & STATUS_PENDING)) t.S &= ~STATUS_UNINITIALIZED;
|
|
560
|
-
if (t.
|
|
561
|
-
if (e.
|
|
564
|
+
if (t.We !== null || t.Qe !== null) GlobalQueue.me(t, false, true);
|
|
565
|
+
if (e.ge || e.pe) GlobalQueue.un(e);
|
|
562
566
|
}
|
|
563
567
|
|
|
564
568
|
function commitPendingNodes() {
|
|
@@ -575,7 +579,7 @@ function finalizePureQueue(e = null, t = false) {
|
|
|
575
579
|
const i = !t;
|
|
576
580
|
if (i) commitPendingNodes();
|
|
577
581
|
if (!t && globalQueue.vt.length) checkBoundaryChildren(globalQueue);
|
|
578
|
-
const n = dirtyQueue.EE >= dirtyQueue.
|
|
582
|
+
const n = dirtyQueue.EE >= dirtyQueue.Ve;
|
|
579
583
|
if (n) runHeap(dirtyQueue, GlobalQueue.Ce);
|
|
580
584
|
if (i) {
|
|
581
585
|
if (n) commitPendingNodes();
|
|
@@ -583,7 +587,7 @@ function finalizePureQueue(e = null, t = false) {
|
|
|
583
587
|
const t = e ?? globalQueue.m;
|
|
584
588
|
// Optimistic reversion: a non-empty batch means _optimisticWrite ran,
|
|
585
589
|
// which installed the engine's hooks.
|
|
586
|
-
if (t.
|
|
590
|
+
if (t.Me.length) GlobalQueue.En(t.Me);
|
|
587
591
|
// Replay entanglement: subs recorded by the read-time gate get rescheduled
|
|
588
592
|
// so they re-run with the now-committed values visible. The ambient batch
|
|
589
593
|
// replays too — laneReadsCommitted records readers whose committed-view
|
|
@@ -645,7 +649,7 @@ function checkBoundaryChildren(e) {
|
|
|
645
649
|
|
|
646
650
|
function reassignPendingTransition(e) {
|
|
647
651
|
for (let t = 0; t < e.length; t++) {
|
|
648
|
-
e[t].
|
|
652
|
+
e[t].Ne = activeTransition;
|
|
649
653
|
}
|
|
650
654
|
}
|
|
651
655
|
|
|
@@ -691,10 +695,10 @@ function runQueue(e, t) {
|
|
|
691
695
|
function reporterBlocksSource(e, t) {
|
|
692
696
|
if (e.se & (REACTIVE_ZOMBIE | REACTIVE_DISPOSED)) return false;
|
|
693
697
|
if (e.oe?.has(t)) return true;
|
|
694
|
-
for (let i = e.
|
|
695
|
-
let e = i.
|
|
698
|
+
for (let i = e.tt; i; i = i.nt) {
|
|
699
|
+
let e = i.it;
|
|
696
700
|
while (e) {
|
|
697
|
-
if (e === t || e.
|
|
701
|
+
if (e === t || e.lt === t) return true;
|
|
698
702
|
e = e.nn;
|
|
699
703
|
}
|
|
700
704
|
}
|
|
@@ -705,7 +709,7 @@ function transitionComplete(e) {
|
|
|
705
709
|
if (e.fn) return true;
|
|
706
710
|
if (e.ie.length) return false;
|
|
707
711
|
let t = true;
|
|
708
|
-
for (const [i, n] of e.
|
|
712
|
+
for (const [i, n] of e.Ie) {
|
|
709
713
|
let s = false;
|
|
710
714
|
for (const e of n) {
|
|
711
715
|
if (reporterBlocksSource(e, i)) {
|
|
@@ -714,7 +718,7 @@ function transitionComplete(e) {
|
|
|
714
718
|
}
|
|
715
719
|
n.delete(e);
|
|
716
720
|
}
|
|
717
|
-
if (!s) e.
|
|
721
|
+
if (!s) e.Ie.delete(i); else if (i.S & STATUS_PENDING && i._?.source === i) {
|
|
718
722
|
t = false;
|
|
719
723
|
break;
|
|
720
724
|
}
|
|
@@ -32,21 +32,21 @@ let pendingProbe = null;
|
|
|
32
32
|
* Get or create the pending signal for a node (lazy).
|
|
33
33
|
* Used by isPending() to track pending state reactively.
|
|
34
34
|
*/ function getPendingSignal(e) {
|
|
35
|
-
if (!e.
|
|
35
|
+
if (!e.ge) {
|
|
36
36
|
// Start false, write true if pending - ensures reversion returns to false
|
|
37
|
-
e.
|
|
37
|
+
e.ge = optimisticSignal(false, {
|
|
38
38
|
ownedWrite: true
|
|
39
39
|
});
|
|
40
|
-
e.
|
|
41
|
-
if (computePendingState(e)) setSignal(e.
|
|
40
|
+
e.ge.nn = e;
|
|
41
|
+
if (computePendingState(e)) setSignal(e.ge, true);
|
|
42
42
|
}
|
|
43
|
-
return e.
|
|
43
|
+
return e.ge;
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
function collectPendingSources(e) {
|
|
47
47
|
if (!pendingProbe) return;
|
|
48
48
|
pendingProbe.sources.add(e);
|
|
49
|
-
const t = e.
|
|
49
|
+
const t = e.lt || e;
|
|
50
50
|
if (t !== e) pendingProbe.sources.add(t);
|
|
51
51
|
}
|
|
52
52
|
|
|
@@ -79,17 +79,17 @@ function collectPendingSources(e) {
|
|
|
79
79
|
if (e.S & STATUS_ERROR) return false;
|
|
80
80
|
if (t.has(e)) return false;
|
|
81
81
|
t.add(e);
|
|
82
|
-
const n = e.
|
|
82
|
+
const n = e.lt;
|
|
83
83
|
if (n && markWalk(n, t)) return true;
|
|
84
84
|
// Mid-recompute (the clearStatus companion poke runs before
|
|
85
85
|
// trimStaleDeps), only the validated prefix [_deps.._depsTail] is this
|
|
86
86
|
// pass's dependency set — walking past it would read dropped deps and
|
|
87
87
|
// latch a stale verdict on the companion.
|
|
88
88
|
const i = e;
|
|
89
|
-
const r = i.se & REACTIVE_RECOMPUTING_DEPS ? i.
|
|
89
|
+
const r = i.se & REACTIVE_RECOMPUTING_DEPS ? i.Ye : undefined;
|
|
90
90
|
if (r !== null) {
|
|
91
|
-
for (let e = i.
|
|
92
|
-
if (!e.
|
|
91
|
+
for (let e = i.tt ?? null; e !== null; e = e.nt) {
|
|
92
|
+
if (!e.Ge && markWalk(e.it, t)) return true;
|
|
93
93
|
if (e === r) break;
|
|
94
94
|
}
|
|
95
95
|
}
|
|
@@ -102,12 +102,19 @@ function collectPendingSources(e) {
|
|
|
102
102
|
|
|
103
103
|
function quietPending(e) {
|
|
104
104
|
if (e.oe) {
|
|
105
|
-
for (const t of e.oe) if (!t.
|
|
105
|
+
for (const t of e.oe) if (!t.he) return false;
|
|
106
106
|
return true;
|
|
107
107
|
}
|
|
108
|
-
return e.
|
|
108
|
+
return e.he;
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
+
// NOTE: a loadingValue node's open loading window (_loading) is verdict-quiet
|
|
112
|
+
// on purpose: commit #0 answers the question by declaration, so the window
|
|
113
|
+
// reads NOT pending — first-load affordances live in the value channel
|
|
114
|
+
// (null / skeleton provenance the author encoded), and isPending stays what
|
|
115
|
+
// it always was: refetch truth for an answered question. This keeps the
|
|
116
|
+
// verdict fully correlated with transition-class machinery and keeps server
|
|
117
|
+
// (always false) and client hydration trivially consistent.
|
|
111
118
|
function newQuestionInFlight(e) {
|
|
112
119
|
return !!(e.S & STATUS_PENDING) && !(e.S & STATUS_UNINITIALIZED) && !quietPending(e);
|
|
113
120
|
}
|
|
@@ -119,37 +126,41 @@ function computePendingState(e) {
|
|
|
119
126
|
// reaches its owner (and a store leaf its firewall) through its own deps,
|
|
120
127
|
// so the one walk covers direct marks, derivation, and companion chains.
|
|
121
128
|
if (markCovered(e)) return true;
|
|
122
|
-
const n = e.
|
|
129
|
+
const n = e.lt;
|
|
123
130
|
if (e.nn) {
|
|
124
131
|
const t = e.nn;
|
|
125
|
-
const n = t.
|
|
132
|
+
const n = t.lt || t;
|
|
126
133
|
return newQuestionInFlight(n);
|
|
127
134
|
}
|
|
128
135
|
if (n && e.De !== NOT_PENDING && !hasActiveOverride(e)) {
|
|
129
136
|
return !!(n.se & REACTIVE_MANUAL_WRITE) || !n.Te && !(n.S & STATUS_PENDING) || !!(n.S & STATUS_PENDING) && quietPending(n);
|
|
130
137
|
}
|
|
131
|
-
|
|
132
|
-
|
|
138
|
+
// `!comp._loading`: a hold created while the loading window is still open is
|
|
139
|
+
// the window's own landing in flight to its commit — verdict-quiet like the
|
|
140
|
+
// rest of the window (the UNINITIALIZED check suppresses exactly this frame
|
|
141
|
+
// for windowless first loads; born-committed nodes need their own gate, #2990).
|
|
142
|
+
if (e.De !== NOT_PENDING && !(t.S & STATUS_UNINITIALIZED) && !t.Ee) {
|
|
143
|
+
if (hasActiveOverride(e)) return !e.be || !e.be(e.De, unwrapOverride(e._e));
|
|
133
144
|
return true;
|
|
134
145
|
}
|
|
135
146
|
return newQuestionInFlight(t);
|
|
136
147
|
}
|
|
137
148
|
|
|
138
149
|
function syncCompanions(e, t) {
|
|
139
|
-
if (e.
|
|
150
|
+
if (e.ge) updatePendingSignal(e);
|
|
140
151
|
if (e.pe) setSignal(e.pe, t);
|
|
141
152
|
}
|
|
142
153
|
|
|
143
154
|
function updatePendingSignal(e) {
|
|
144
|
-
if (e.
|
|
145
|
-
setSignal(e.
|
|
155
|
+
if (e.ge) {
|
|
156
|
+
setSignal(e.ge, computePendingState(e));
|
|
146
157
|
}
|
|
147
158
|
if (e.pe) updatePendingSignal(e.pe);
|
|
148
159
|
}
|
|
149
160
|
|
|
150
161
|
function updateChildCompanions(e) {
|
|
151
|
-
for (let t = e.u; t !== null; t = t.
|
|
152
|
-
if (t.
|
|
162
|
+
for (let t = e.u; t !== null; t = t.ae) {
|
|
163
|
+
if (t.ge || t.pe) updatePendingSignal(t);
|
|
153
164
|
}
|
|
154
165
|
}
|
|
155
166
|
|
|
@@ -167,9 +178,9 @@ function updateChildCompanions(e) {
|
|
|
167
178
|
const visit = e => {
|
|
168
179
|
if (i.has(e)) return;
|
|
169
180
|
i.add(e);
|
|
170
|
-
if (e.
|
|
171
|
-
for (let t = e.o; t !== null; t = t.
|
|
172
|
-
for (let t = e.u ?? null; t !== null; t = t.
|
|
181
|
+
if (e.ge || e.pe) n(e);
|
|
182
|
+
for (let t = e.o; t !== null; t = t.le) visit(t.fe);
|
|
183
|
+
for (let t = e.u ?? null; t !== null; t = t.ae) {
|
|
173
184
|
visit(t);
|
|
174
185
|
}
|
|
175
186
|
};
|
|
@@ -177,20 +188,20 @@ function updateChildCompanions(e) {
|
|
|
177
188
|
}
|
|
178
189
|
|
|
179
190
|
function snapCompanionsToState(e) {
|
|
180
|
-
const t = e.
|
|
181
|
-
if (t && (t.
|
|
191
|
+
const t = e.ge;
|
|
192
|
+
if (t && (t._e === undefined || t._e === NOT_PENDING)) {
|
|
182
193
|
const n = computePendingState(e);
|
|
183
|
-
if (t.
|
|
184
|
-
t.
|
|
194
|
+
if (t.Ue !== n || t.De !== NOT_PENDING) {
|
|
195
|
+
t.Ue = n;
|
|
185
196
|
t.De = NOT_PENDING;
|
|
186
|
-
t.
|
|
197
|
+
t.de = clock;
|
|
187
198
|
insertSubs(t);
|
|
188
199
|
schedule();
|
|
189
200
|
}
|
|
190
201
|
}
|
|
191
202
|
const n = e.pe;
|
|
192
203
|
if (n && !(n.se & REACTIVE_DISPOSED)) {
|
|
193
|
-
if ((n.
|
|
204
|
+
if ((n._e === undefined || n._e === NOT_PENDING) && n.De === NOT_PENDING && !Object.is(n.Ue, e.Ue) && !(n.se & (REACTIVE_DIRTY | REACTIVE_CHECK))) {
|
|
194
205
|
n.se |= REACTIVE_DIRTY;
|
|
195
206
|
insertIntoHeap(n, queueFor(n));
|
|
196
207
|
insertSubs(n);
|
|
@@ -223,7 +234,7 @@ function getLatestValueComputed(e) {
|
|
|
223
234
|
const t = getLatestValueComputed(e);
|
|
224
235
|
const n = latestReadActive;
|
|
225
236
|
setLatestReadActive(false);
|
|
226
|
-
const i = e.
|
|
237
|
+
const i = e._e !== undefined && e._e !== NOT_PENDING ? unwrapOverride(e._e) : e.Ue;
|
|
227
238
|
let r;
|
|
228
239
|
try {
|
|
229
240
|
// An untracked latest() read has no reading context, so read() never
|
|
@@ -232,7 +243,7 @@ function getLatestValueComputed(e) {
|
|
|
232
243
|
// until the flush (#2922). Mirror the tracked-read pull here: mark the
|
|
233
244
|
// queued staleness through the graph, then bring the shadow up to date.
|
|
234
245
|
const e = queueFor(t);
|
|
235
|
-
if (t.
|
|
246
|
+
if (t.xe >= e.Ve && !(t.se & (REACTIVE_DISPOSED | REACTIVE_ZOMBIE))) {
|
|
236
247
|
markHeap(e);
|
|
237
248
|
prepareComputed(t, true);
|
|
238
249
|
}
|
|
@@ -244,10 +255,10 @@ function getLatestValueComputed(e) {
|
|
|
244
255
|
setLatestReadActive(n);
|
|
245
256
|
}
|
|
246
257
|
if (t.S & STATUS_PENDING) return i;
|
|
247
|
-
if (stale && currentOptimisticLane && t.
|
|
248
|
-
const e = findLane(t.
|
|
258
|
+
if (stale && currentOptimisticLane && t.Ke) {
|
|
259
|
+
const e = findLane(t.Ke);
|
|
249
260
|
const n = findLane(currentOptimisticLane);
|
|
250
|
-
if (e !== n && e.
|
|
261
|
+
if (e !== n && e.Ae.size > 0) {
|
|
251
262
|
return i;
|
|
252
263
|
}
|
|
253
264
|
}
|
|
@@ -255,13 +266,13 @@ function getLatestValueComputed(e) {
|
|
|
255
266
|
// speculative value in _pendingValue; a contextless read() only surfaces
|
|
256
267
|
// _value. Overrides stay authoritative (A17), and stale readers keep the
|
|
257
268
|
// other transition's committed view, matching read()'s own selection.
|
|
258
|
-
if (t.De !== NOT_PENDING && !hasActiveOverride(t) && !(stale && t.
|
|
269
|
+
if (t.De !== NOT_PENDING && !hasActiveOverride(t) && !(stale && t.Ne && activeTransition !== t.Ne)) return t.De;
|
|
259
270
|
return r;
|
|
260
271
|
}
|
|
261
272
|
|
|
262
273
|
/** The isPending()-probe read path, installed as GlobalQueue._pendingCheck. */ function pendingCheckRead(e, t, n, i) {
|
|
263
274
|
setPendingCheckActive(false);
|
|
264
|
-
if (typeof e.
|
|
275
|
+
if (typeof e.ce === "function") prepareComputed(e, true);
|
|
265
276
|
const r = n.S;
|
|
266
277
|
if (t && r & STATUS_PENDING && r & STATUS_UNINITIALIZED) {
|
|
267
278
|
if (tracking && e !== t) link(e, t);
|
|
@@ -279,9 +290,9 @@ function recordFreshRead(e, t) {
|
|
|
279
290
|
|
|
280
291
|
function applyReask(e, t) {
|
|
281
292
|
const n = !!(e.S & STATUS_PENDING);
|
|
282
|
-
const i = t && !(n && !e.
|
|
283
|
-
const r = n && e.
|
|
284
|
-
e.
|
|
293
|
+
const i = t && !(n && !e.he);
|
|
294
|
+
const r = n && e.he !== i;
|
|
295
|
+
e.he = i;
|
|
285
296
|
return r;
|
|
286
297
|
}
|
|
287
298
|
|
|
@@ -335,24 +346,24 @@ function isPending(e) {
|
|
|
335
346
|
// Hook installation (same late-binding pattern as GlobalQueue._update /
|
|
336
347
|
// _propagateAffects): core call sites fire these behind the same guards the
|
|
337
348
|
// direct calls used, so behavior is identical once this module loads.
|
|
338
|
-
GlobalQueue.
|
|
349
|
+
GlobalQueue.Pe = syncCompanions;
|
|
339
350
|
|
|
340
|
-
GlobalQueue.
|
|
351
|
+
GlobalQueue.Se = updatePendingSignal;
|
|
341
352
|
|
|
342
|
-
GlobalQueue.
|
|
353
|
+
GlobalQueue.Oe = updateChildCompanions;
|
|
343
354
|
|
|
344
355
|
GlobalQueue.un = snapCompanionsToState;
|
|
345
356
|
|
|
346
|
-
GlobalQueue.
|
|
357
|
+
GlobalQueue.At = latestRead;
|
|
347
358
|
|
|
348
|
-
GlobalQueue.
|
|
359
|
+
GlobalQueue.Ct = pendingCheckRead;
|
|
349
360
|
|
|
350
|
-
GlobalQueue.
|
|
361
|
+
GlobalQueue.ht = recordFreshRead;
|
|
351
362
|
|
|
352
|
-
GlobalQueue
|
|
363
|
+
GlobalQueue.Be = applyReask;
|
|
353
364
|
|
|
354
365
|
GlobalQueue.k = repollDownstreamVerdicts;
|
|
355
366
|
|
|
356
|
-
GlobalQueue.
|
|
367
|
+
GlobalQueue.Lt = witnessAffects;
|
|
357
368
|
|
|
358
369
|
export { isPending, latest };
|