@solidjs/signals 2.0.0-rc.1 → 2.0.0-rc.3
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 +1779 -383
- package/dist/node.cjs +2058 -1359
- package/dist/prod/affects.js +16 -16
- package/dist/prod/boundaries.js +90 -90
- package/dist/prod/core/action.js +3 -3
- package/dist/prod/core/async.js +74 -72
- package/dist/prod/core/constants.js +39 -1
- package/dist/prod/core/core.js +332 -224
- package/dist/prod/core/effect.js +56 -56
- package/dist/prod/core/external.js +4 -4
- package/dist/prod/core/graph.js +65 -54
- package/dist/prod/core/heap.js +52 -44
- package/dist/prod/core/invariants.js +3 -2
- package/dist/prod/core/lanes.js +41 -34
- package/dist/prod/core/optimistic.js +93 -68
- package/dist/prod/core/owner.js +97 -96
- package/dist/prod/core/scheduler.js +243 -194
- package/dist/prod/core/verdict.js +191 -77
- package/dist/prod/map.js +104 -104
- package/dist/prod/signals.js +1 -1
- package/dist/prod/store/next/optimistic.js +31 -23
- package/dist/prod/store/next/projection.js +109 -47
- package/dist/prod/store/next/reconcile.js +78 -74
- package/dist/prod/store/next/store.js +357 -90
- package/dist/prod/store/store.js +7 -7
- package/dist/types/core/attribution-hooks.d.ts +52 -0
- package/dist/types/core/attribution.d.ts +186 -0
- package/dist/types/core/constants.d.ts +26 -0
- package/dist/types/core/core.d.ts +8 -1
- package/dist/types/core/dev.d.ts +20 -3
- package/dist/types/core/graph.d.ts +1 -0
- package/dist/types/core/invariants.d.ts +1 -1
- package/dist/types/core/lanes.d.ts +4 -16
- package/dist/types/core/scheduler.d.ts +8 -0
- package/dist/types/core/types.d.ts +85 -41
- package/dist/types/store/next/projection.d.ts +0 -16
- package/dist/types/store/next/store.d.ts +6 -0
- package/dist/types/store/next/target.d.ts +18 -0
- package/dist/types-cjs/core/attribution-hooks.d.cts +52 -0
- package/dist/types-cjs/core/attribution.d.cts +186 -0
- package/dist/types-cjs/core/constants.d.cts +26 -0
- package/dist/types-cjs/core/core.d.cts +8 -1
- package/dist/types-cjs/core/dev.d.cts +20 -3
- package/dist/types-cjs/core/graph.d.cts +1 -0
- package/dist/types-cjs/core/invariants.d.cts +1 -1
- package/dist/types-cjs/core/lanes.d.cts +4 -16
- package/dist/types-cjs/core/scheduler.d.cts +8 -0
- package/dist/types-cjs/core/types.d.cts +85 -41
- package/dist/types-cjs/store/next/projection.d.cts +0 -16
- package/dist/types-cjs/store/next/store.d.cts +6 -0
- package/dist/types-cjs/store/next/target.d.cts +18 -0
- package/package.json +15 -15
- package/dist/types/store/optimistic.d.ts +0 -45
- package/dist/types/store/projection.d.ts +0 -70
- package/dist/types/store/reconcile.d.ts +0 -46
- package/dist/types-cjs/store/optimistic.d.cts +0 -45
- package/dist/types-cjs/store/projection.d.cts +0 -70
- package/dist/types-cjs/store/reconcile.d.cts +0 -46
package/dist/prod/core/lanes.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import { NOT_PENDING } from "./constants.js";
|
|
1
|
+
import { NOT_PENDING, CONFIG_HAS_LANE } from "./constants.js";
|
|
2
|
+
|
|
3
|
+
import { ext } from "./core.js";
|
|
2
4
|
|
|
3
5
|
import { currentTransition, activeTransition } from "./scheduler.js";
|
|
4
6
|
|
|
@@ -18,15 +20,16 @@ const activeLanes = new Set;
|
|
|
18
20
|
}
|
|
19
21
|
// Detect parent lane: _parentSource chains from pendingSignal → pendingValueComputed → original.
|
|
20
22
|
// The child lane should not merge with the parent lane.
|
|
21
|
-
const i = n.
|
|
22
|
-
const
|
|
23
|
+
const i = n.o?.It;
|
|
24
|
+
const t = i?.o?.Be;
|
|
25
|
+
const r = t ? findLane(t) : null;
|
|
23
26
|
e = {
|
|
24
|
-
|
|
27
|
+
nn: n,
|
|
25
28
|
Ae: new Set,
|
|
26
|
-
|
|
29
|
+
en: [ [], [] ],
|
|
27
30
|
tn: null,
|
|
28
|
-
|
|
29
|
-
|
|
31
|
+
_e: activeTransition,
|
|
32
|
+
rn: r
|
|
30
33
|
};
|
|
31
34
|
signalLanes.set(n, e);
|
|
32
35
|
activeLanes.add(e);
|
|
@@ -36,8 +39,8 @@ const activeLanes = new Set;
|
|
|
36
39
|
// parent-child is a property of the nodes, not of write order — otherwise
|
|
37
40
|
// the owner's write merges the companion's subscribers into this lane and
|
|
38
41
|
// their effects wait on its async instead of flushing immediately.
|
|
39
|
-
adoptCompanionLane(n.
|
|
40
|
-
adoptCompanionLane(n.ge, e);
|
|
42
|
+
adoptCompanionLane(n.o?.Ge, e);
|
|
43
|
+
adoptCompanionLane(n.o?.ge, e);
|
|
41
44
|
return e;
|
|
42
45
|
}
|
|
43
46
|
|
|
@@ -45,10 +48,10 @@ function adoptCompanionLane(n, e) {
|
|
|
45
48
|
if (!n) return;
|
|
46
49
|
const i = signalLanes.get(n);
|
|
47
50
|
if (!i) return;
|
|
48
|
-
const
|
|
51
|
+
const t = findLane(i);
|
|
49
52
|
// Only the companion's own unmerged root is safely re-parentable: a root
|
|
50
53
|
// that absorbed other lanes carries work that is not a child of this owner.
|
|
51
|
-
if (
|
|
54
|
+
if (t !== e && t.nn === n && !t.rn) t.rn = e;
|
|
52
55
|
}
|
|
53
56
|
|
|
54
57
|
/**
|
|
@@ -70,21 +73,21 @@ function adoptCompanionLane(n, e) {
|
|
|
70
73
|
// and anything *added* here later is a routing bug (INV-5).
|
|
71
74
|
for (const i of e.Ae) n.Ae.add(i);
|
|
72
75
|
e.Ae.clear();
|
|
73
|
-
n.
|
|
74
|
-
n.
|
|
75
|
-
e.
|
|
76
|
-
e.
|
|
76
|
+
n.en[0].push(...e.en[0]);
|
|
77
|
+
n.en[1].push(...e.en[1]);
|
|
78
|
+
e.en[0].length = 0;
|
|
79
|
+
e.en[1].length = 0;
|
|
77
80
|
return n;
|
|
78
81
|
}
|
|
79
82
|
|
|
80
83
|
/**
|
|
81
84
|
* Resolve a node's lane: follow union-find chain, verify active, clear if stale.
|
|
82
85
|
*/ function resolveLane(n) {
|
|
83
|
-
const e = n.
|
|
86
|
+
const e = n.o?.Be;
|
|
84
87
|
if (!e) return undefined;
|
|
85
88
|
const i = findLane(e);
|
|
86
89
|
if (activeLanes.has(i)) return i;
|
|
87
|
-
n.
|
|
90
|
+
if (n.o !== null) n.o.Be = undefined;
|
|
88
91
|
return undefined;
|
|
89
92
|
}
|
|
90
93
|
|
|
@@ -94,18 +97,19 @@ function resolveTransition(n) {
|
|
|
94
97
|
// transactions (#2912) — the merged root's _transition would hand this
|
|
95
98
|
// node's override to whichever action wrote last through the shared
|
|
96
99
|
// reader. Chase merge chains; a dead owner settled through another path.
|
|
97
|
-
if (hasActiveOverride(n) && n.
|
|
98
|
-
const e = n.
|
|
99
|
-
if (e.
|
|
100
|
-
n.
|
|
100
|
+
if (hasActiveOverride(n) && n.o?.Et) {
|
|
101
|
+
const e = ext(n).Et = currentTransition(n.o?.Et);
|
|
102
|
+
if (e.an !== true) return e;
|
|
103
|
+
if (n.o !== null) n.o.Et = null;
|
|
101
104
|
}
|
|
102
|
-
return resolveLane(n)?.
|
|
105
|
+
return resolveLane(n)?._e ?? n._e;
|
|
103
106
|
}
|
|
104
107
|
|
|
105
108
|
/**
|
|
106
109
|
* Check if a node has an active optimistic override.
|
|
107
110
|
*/ function hasActiveOverride(n) {
|
|
108
|
-
|
|
111
|
+
const e = n.o;
|
|
112
|
+
return e !== null && e.De !== undefined && e.De !== NOT_PENDING;
|
|
109
113
|
}
|
|
110
114
|
|
|
111
115
|
/**
|
|
@@ -113,28 +117,31 @@ function resolveTransition(n) {
|
|
|
113
117
|
* a different active lane), merge unless the node has an active override.
|
|
114
118
|
*/ function assignOrMergeLane(n, e) {
|
|
115
119
|
const i = findLane(e);
|
|
116
|
-
const
|
|
117
|
-
if (
|
|
120
|
+
const t = n.o?.Be;
|
|
121
|
+
if (t) {
|
|
118
122
|
// If the subscriber's lane was merged into another lane, it's stale —
|
|
119
123
|
// replace it with the new source lane instead of following the merge chain
|
|
120
124
|
// (which would incorrectly merge the new lane into the old group)
|
|
121
|
-
if (
|
|
122
|
-
n.
|
|
125
|
+
if (t.tn) {
|
|
126
|
+
ext(n).Be = e;
|
|
127
|
+
n.T |= CONFIG_HAS_LANE;
|
|
123
128
|
return;
|
|
124
129
|
}
|
|
125
|
-
const
|
|
126
|
-
if (activeLanes.has(
|
|
127
|
-
if (
|
|
130
|
+
const r = findLane(t);
|
|
131
|
+
if (activeLanes.has(r)) {
|
|
132
|
+
if (r !== i && !hasActiveOverride(n)) {
|
|
128
133
|
// Parent-child lanes stay independent so isPending resolves without
|
|
129
134
|
// waiting for the parent's async. The child keeps ownership.
|
|
130
|
-
if (i.
|
|
131
|
-
n.
|
|
132
|
-
|
|
135
|
+
if (i.rn && findLane(i.rn) === r) {
|
|
136
|
+
ext(n).Be = e;
|
|
137
|
+
n.T |= CONFIG_HAS_LANE;
|
|
138
|
+
} else if (r.rn && findLane(r.rn) === i) ; else mergeLanes(i, r);
|
|
133
139
|
}
|
|
134
140
|
return;
|
|
135
141
|
}
|
|
136
142
|
}
|
|
137
|
-
n.
|
|
143
|
+
ext(n).Be = e;
|
|
144
|
+
n.T |= CONFIG_HAS_LANE;
|
|
138
145
|
}
|
|
139
146
|
|
|
140
147
|
export { activeLanes, assignOrMergeLane, findLane, getOrCreateLane, hasActiveOverride, mergeLanes, resolveLane, resolveTransition, signalLanes };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { NOT_PENDING, unwrapOverride, STATUS_UNINITIALIZED, OVERRIDE_UNDEFINED, STATUS_PENDING, REACTIVE_MANUAL_WRITE, REACTIVE_OPTIMISTIC_DIRTY, EFFECT_RENDER, EFFECT_USER } from "./constants.js";
|
|
1
|
+
import { NOT_PENDING, unwrapOverride, STATUS_UNINITIALIZED, REACTIVE_DIRTY, REACTIVE_CHECK, CONFIG_HAS_LANE, OVERRIDE_UNDEFINED, STATUS_PENDING, REACTIVE_MANUAL_WRITE, REACTIVE_OPTIMISTIC_DIRTY, EFFECT_RENDER, EFFECT_USER } from "./constants.js";
|
|
2
2
|
|
|
3
|
-
import { latestReadActive, currentOptimisticLane, stale } from "./core.js";
|
|
3
|
+
import { ext, latestReadActive, currentOptimisticLane, stale } from "./core.js";
|
|
4
4
|
|
|
5
5
|
import { NotReadyError } from "./error.js";
|
|
6
6
|
|
|
@@ -24,10 +24,17 @@ import { GlobalQueue, activeTransition, globalQueue, clock, insertSubs, schedule
|
|
|
24
24
|
* once the gate holds — the same late-binding contract as verdict.ts.
|
|
25
25
|
*/
|
|
26
26
|
/** The optimistic half of setSignal, fired when `_overrideValue !== undefined`. */ function optimisticWrite(e, n) {
|
|
27
|
-
const t = e.De !== NOT_PENDING;
|
|
28
|
-
const i = t ? unwrapOverride(e.De) : e.be;
|
|
27
|
+
const t = e.o?.De !== NOT_PENDING;
|
|
28
|
+
const i = t ? unwrapOverride(e.o?.De) : e.be;
|
|
29
29
|
if (typeof n === "function") n = n(i);
|
|
30
|
-
const u = !!(e.S & STATUS_UNINITIALIZED) ||
|
|
30
|
+
const u = !!(e.S & STATUS_UNINITIALIZED) ||
|
|
31
|
+
// A dirty node's _value is stale (its queued recompute hasn't run — e.g.
|
|
32
|
+
// a latest() shadow marked by the previous landing's companion snap), so
|
|
33
|
+
// equality against it must not swallow the write. Without this, a sync
|
|
34
|
+
// push returning the shadow to that stale value was dropped, the snap
|
|
35
|
+
// recompute then committed the parent's old value, and the banner showed
|
|
36
|
+
// the previous transition's target (#3041 follow-up).
|
|
37
|
+
!!((e.ie ?? 0) & (REACTIVE_DIRTY | REACTIVE_CHECK)) || !e.Ue || !e.Ue(i, n);
|
|
31
38
|
if (!u) {
|
|
32
39
|
// Same-value write with an active override still entangles the current
|
|
33
40
|
// action's transition — the hold must outlast all overlapping actions.
|
|
@@ -41,22 +48,24 @@ import { GlobalQueue, activeTransition, globalQueue, clock, insertSubs, schedule
|
|
|
41
48
|
// No revert target is stashed: while the override is active every reader
|
|
42
49
|
// sees it (A17), so authoritative arrivals commit silently into _value and
|
|
43
50
|
// reverting is just dropping the override — _value is already correct.
|
|
44
|
-
else globalQueue.
|
|
51
|
+
else globalQueue.k.Ke.push(e);
|
|
45
52
|
// Stamp ownership on the node (post-merge, so entangled writers share the
|
|
46
53
|
// joint root). resolveTransition prefers this over the lane's _transition,
|
|
47
54
|
// which a shared subscriber can merge across transactions (#2912).
|
|
48
|
-
e.
|
|
49
|
-
const
|
|
50
|
-
e.
|
|
55
|
+
ext(e).Et = activeTransition;
|
|
56
|
+
const l = getOrCreateLane(e);
|
|
57
|
+
ext(e).Be = l;
|
|
58
|
+
e.T |= CONFIG_HAS_LANE;
|
|
51
59
|
// Literal undefined must not land raw: the slot doubles as the optimistic
|
|
52
60
|
// brand, and erasing it makes the write invisible and routes follow-up
|
|
53
61
|
// writes off the optimistic path into permanent commits (#2898).
|
|
54
|
-
e.De = n === undefined ? OVERRIDE_UNDEFINED : n;
|
|
62
|
+
ext(e).De = n === undefined ? OVERRIDE_UNDEFINED : n;
|
|
55
63
|
// syncCompanions only pokes _pendingSignal/_latestValueComputed — with
|
|
56
64
|
// neither companion present the call is a guaranteed no-op.
|
|
57
|
-
(e.
|
|
58
|
-
e.
|
|
59
|
-
|
|
65
|
+
(e.o?.Ge !== undefined || e.o?.ge !== undefined) && GlobalQueue.Oe !== null && GlobalQueue.Oe(e, n);
|
|
66
|
+
if (e.Se !== undefined) e.Te = clock;
|
|
67
|
+
// §12e: computed-only slot
|
|
68
|
+
insertSubs(e, true);
|
|
60
69
|
schedule();
|
|
61
70
|
return n;
|
|
62
71
|
}
|
|
@@ -66,9 +75,9 @@ import { GlobalQueue, activeTransition, globalQueue, clock, insertSubs, schedule
|
|
|
66
75
|
* while one of its optimistic nodes holds an active override that is still
|
|
67
76
|
* pending on real (non-affects-sentinel) async.
|
|
68
77
|
*/ function transitionBlocked(e) {
|
|
69
|
-
for (let n = 0; n < e.
|
|
70
|
-
const t = e.
|
|
71
|
-
if (hasActiveOverride(t) && "S" in t && t.S & STATUS_PENDING && t._ instanceof NotReadyError) {
|
|
78
|
+
for (let n = 0; n < e.Ke.length; n++) {
|
|
79
|
+
const t = e.Ke[n];
|
|
80
|
+
if (hasActiveOverride(t) && "S" in t && t.S & STATUS_PENDING && t.o?._ instanceof NotReadyError) {
|
|
72
81
|
return true;
|
|
73
82
|
}
|
|
74
83
|
}
|
|
@@ -82,25 +91,25 @@ function resolveOptimisticNodes(e) {
|
|
|
82
91
|
const n = e.length;
|
|
83
92
|
for (let t = 0; t < n; t++) {
|
|
84
93
|
const n = e[t];
|
|
85
|
-
n.
|
|
94
|
+
if (n.o !== null) n.o.Be = undefined;
|
|
86
95
|
// Revert is a pure drop: there is no revert target to commit —
|
|
87
96
|
// override-covered authoritative values hold in _pendingValue and
|
|
88
97
|
// elevate on their OWN transition's schedule (A18 as re-ruled 2026-07-07).
|
|
89
98
|
if (!(n.S & STATUS_PENDING)) n.S &= ~STATUS_UNINITIALIZED;
|
|
90
|
-
const i = n.De;
|
|
91
|
-
n.De = NOT_PENDING;
|
|
99
|
+
const i = n.o?.De;
|
|
100
|
+
ext(n).De = NOT_PENDING;
|
|
92
101
|
if (i !== NOT_PENDING && n.be !== unwrapOverride(i)) insertSubs(n, true);
|
|
93
|
-
n.
|
|
94
|
-
n.
|
|
102
|
+
n._e = null;
|
|
103
|
+
if (n.o !== null) n.o.Et = null;
|
|
95
104
|
}
|
|
96
105
|
// Settlement checkpoint (#2838): companions caught in this batch (or owned
|
|
97
106
|
// by a node in it) re-derive from committed state, so verdicts survive the
|
|
98
107
|
// transition that produced them (A19 — pending is a property of the data).
|
|
99
108
|
for (let t = 0; t < n; t++) {
|
|
100
109
|
const n = e[t];
|
|
101
|
-
if (n.
|
|
102
|
-
const i = n.
|
|
103
|
-
if (i && (i.
|
|
110
|
+
if (n.o?.Ge || n.o?.ge) GlobalQueue.un(n);
|
|
111
|
+
const i = n.o?.It;
|
|
112
|
+
if (i && (i.o?.Ge === n || i.o?.ge === n)) GlobalQueue.un(i);
|
|
104
113
|
}
|
|
105
114
|
e.splice(0, n);
|
|
106
115
|
}
|
|
@@ -114,9 +123,9 @@ function runQueue(e, n) {
|
|
|
114
123
|
*/ function runLaneEffects(e) {
|
|
115
124
|
for (const n of activeLanes) {
|
|
116
125
|
if (n.tn || n.Ae.size > 0) continue;
|
|
117
|
-
const t = n.
|
|
126
|
+
const t = n.en[e - 1];
|
|
118
127
|
if (t.length) {
|
|
119
|
-
n.
|
|
128
|
+
n.en[e - 1] = [];
|
|
120
129
|
runQueue(t, e);
|
|
121
130
|
}
|
|
122
131
|
}
|
|
@@ -124,18 +133,18 @@ function runQueue(e, n) {
|
|
|
124
133
|
|
|
125
134
|
function cleanupCompletedLanes(e) {
|
|
126
135
|
for (const n of activeLanes) {
|
|
127
|
-
const t = e ? n.
|
|
136
|
+
const t = e ? n._e === e : !n._e;
|
|
128
137
|
if (!t) continue;
|
|
129
138
|
if (!n.tn) {
|
|
130
|
-
if (n.
|
|
131
|
-
if (n.
|
|
139
|
+
if (n.en[0].length) runQueue(n.en[0], EFFECT_RENDER);
|
|
140
|
+
if (n.en[1].length) runQueue(n.en[1], EFFECT_USER);
|
|
132
141
|
}
|
|
133
|
-
if (n.
|
|
142
|
+
if (n.nn.o?.Be === n) if (n.nn.o !== null) n.nn.o.Be = undefined;
|
|
134
143
|
n.Ae.clear();
|
|
135
|
-
n.
|
|
136
|
-
n.
|
|
144
|
+
n.en[0].length = 0;
|
|
145
|
+
n.en[1].length = 0;
|
|
137
146
|
activeLanes.delete(n);
|
|
138
|
-
signalLanes.delete(n.
|
|
147
|
+
signalLanes.delete(n.nn);
|
|
139
148
|
}
|
|
140
149
|
}
|
|
141
150
|
|
|
@@ -143,7 +152,7 @@ function cleanupCompletedLanes(e) {
|
|
|
143
152
|
// Per-lane suspension: only throw if in same lane as pending async
|
|
144
153
|
// AND the node doesn't have an active override (overrides are the visible value,
|
|
145
154
|
// downstream in the lane should read the override, not throw)
|
|
146
|
-
const n = e.
|
|
155
|
+
const n = e.o?.Be;
|
|
147
156
|
if (!n) return false;
|
|
148
157
|
return findLane(n) === findLane(currentOptimisticLane) && !hasActiveOverride(e);
|
|
149
158
|
}
|
|
@@ -153,7 +162,7 @@ function cleanupCompletedLanes(e) {
|
|
|
153
162
|
* that reads a pending mid-transition write sees the committed value; the sub
|
|
154
163
|
* is recorded for replay at commit.
|
|
155
164
|
*/ function gatedRead(e, n, t) {
|
|
156
|
-
if (latestReadActive || e.
|
|
165
|
+
if (latestReadActive || e.Pe === NOT_PENDING || e.Se || n !== e && !(n.ie & REACTIVE_MANUAL_WRITE)) {
|
|
157
166
|
return false;
|
|
158
167
|
}
|
|
159
168
|
activeTransition.ln.add(t);
|
|
@@ -164,16 +173,31 @@ function cleanupCompletedLanes(e) {
|
|
|
164
173
|
* read()'s value selection under a lane: return the committed `_value` for
|
|
165
174
|
* optimistic/lane-assigned signals, stale-mode reads, and pending owners.
|
|
166
175
|
*/ function laneReadsCommitted(e, n, t) {
|
|
167
|
-
if (e.De !== undefined || !!e.
|
|
168
|
-
|
|
169
|
-
//
|
|
170
|
-
//
|
|
171
|
-
//
|
|
172
|
-
//
|
|
173
|
-
//
|
|
174
|
-
//
|
|
175
|
-
//
|
|
176
|
-
if (e.
|
|
176
|
+
if (e.o?.De !== undefined || !!e.o?.Be || !!(n.S & STATUS_PENDING)) {
|
|
177
|
+
// The committed view hides a staged in-flight value that will promote
|
|
178
|
+
// silently (commitPendingNode never re-notifies). gatedRead records plain
|
|
179
|
+
// signals for replay at commit; async memos are excluded from it by the
|
|
180
|
+
// `_fn` check and reach here instead — a lane-assigned source whose async
|
|
181
|
+
// already settled (laneAsyncSettled keeps _optimisticLane) served its
|
|
182
|
+
// committed value to a reader that never re-ran after the landing, so a
|
|
183
|
+
// pending-gated branch stayed one value behind permanently (#3041
|
|
184
|
+
// follow-up). Record the reader under the same replay contract.
|
|
185
|
+
if (e.Pe !== NOT_PENDING) (activeTransition ?? globalQueue.k).ln.add(t);
|
|
186
|
+
return true;
|
|
187
|
+
}
|
|
188
|
+
if (n === e && stale && t.o?.It !== e) {
|
|
189
|
+
// The committed view can hide a staged write (a lane member — even just
|
|
190
|
+
// an isPending companion flip — puts the reader "under a lane"). The
|
|
191
|
+
// staged value commits with no re-delivery (commitPendingNode never
|
|
192
|
+
// re-notifies), so record the reader for replay at commit — the same
|
|
193
|
+
// contract gatedRead provides (#2963). gatedRead itself only covers
|
|
194
|
+
// signal reads where the reading computed differs from the source; the
|
|
195
|
+
// owner === el memo/self read lands here instead. With a transaction
|
|
196
|
+
// active the staged value promotes silently at ITS landing, so record
|
|
197
|
+
// into the transaction (#3041 follow-up: a pending-gated branch that
|
|
198
|
+
// first read its async source during the landing flush stayed one value
|
|
199
|
+
// behind permanently); with none, into the ambient batch.
|
|
200
|
+
if (e.Pe !== NOT_PENDING) (activeTransition ?? globalQueue.k).ln.add(t);
|
|
177
201
|
return true;
|
|
178
202
|
}
|
|
179
203
|
return false;
|
|
@@ -196,18 +220,18 @@ function cleanupCompletedLanes(e) {
|
|
|
196
220
|
// recompute() runs plain: the value stages and commits with the flush.
|
|
197
221
|
// (el's own override slot excludes companions themselves; a lane merged
|
|
198
222
|
// into a real optimistic lane resolves to a non-companion source.)
|
|
199
|
-
if (!globalQueue.
|
|
200
|
-
e.
|
|
223
|
+
if (!globalQueue.sn && !activeTransition && !n._e && n.nn.o?.It !== undefined && e.o?.De === undefined) {
|
|
224
|
+
if (e.o !== null) e.o.Be = undefined;
|
|
201
225
|
return false;
|
|
202
226
|
}
|
|
203
227
|
return n;
|
|
204
228
|
}
|
|
205
|
-
for (let n = e.
|
|
206
|
-
const t = n.
|
|
207
|
-
if (t.
|
|
229
|
+
for (let n = e.nt; n; n = n.it) {
|
|
230
|
+
const t = n.ut;
|
|
231
|
+
if (t.ie & REACTIVE_OPTIMISTIC_DIRTY) {
|
|
208
232
|
const n = resolveLane(t);
|
|
209
233
|
if (n) {
|
|
210
|
-
e.
|
|
234
|
+
e.ie |= REACTIVE_OPTIMISTIC_DIRTY;
|
|
211
235
|
assignOrMergeLane(e, n);
|
|
212
236
|
return n;
|
|
213
237
|
}
|
|
@@ -218,10 +242,11 @@ function cleanupCompletedLanes(e) {
|
|
|
218
242
|
|
|
219
243
|
/** recompute()'s catch path: track pending async in the current lane. */ function laneAsyncPending(e) {
|
|
220
244
|
const n = findLane(currentOptimisticLane);
|
|
221
|
-
if (n.
|
|
245
|
+
if (n.nn !== e) {
|
|
222
246
|
n.Ae.add(e);
|
|
223
|
-
e.
|
|
224
|
-
|
|
247
|
+
ext(e).Be = n;
|
|
248
|
+
e.T |= CONFIG_HAS_LANE;
|
|
249
|
+
GlobalQueue.de !== null && GlobalQueue.de(n.nn);
|
|
225
250
|
}
|
|
226
251
|
}
|
|
227
252
|
|
|
@@ -229,13 +254,13 @@ function cleanupCompletedLanes(e) {
|
|
|
229
254
|
const n = resolveLane(e);
|
|
230
255
|
if (n) {
|
|
231
256
|
n.Ae.delete(e);
|
|
232
|
-
GlobalQueue.
|
|
257
|
+
GlobalQueue.de !== null && GlobalQueue.de(n.nn);
|
|
233
258
|
}
|
|
234
259
|
}
|
|
235
260
|
|
|
236
261
|
function trackOptimisticStore(e) {
|
|
237
262
|
// After initTransition, globalQueue._batch IS activeTransition (same reference)
|
|
238
|
-
globalQueue.
|
|
263
|
+
globalQueue.k.cn.add(e);
|
|
239
264
|
schedule();
|
|
240
265
|
}
|
|
241
266
|
|
|
@@ -244,19 +269,19 @@ function trackOptimisticStore(e) {
|
|
|
244
269
|
* create optimistic state (verdict.ts at module top level, createOptimistic
|
|
245
270
|
* and createOptimisticStore at first call) BEFORE any optimistic node exists.
|
|
246
271
|
*/ function installOptimisticEngine() {
|
|
247
|
-
if (GlobalQueue.
|
|
248
|
-
GlobalQueue.
|
|
249
|
-
GlobalQueue.
|
|
250
|
-
GlobalQueue.
|
|
251
|
-
GlobalQueue.
|
|
252
|
-
GlobalQueue.
|
|
253
|
-
GlobalQueue.
|
|
254
|
-
GlobalQueue.
|
|
255
|
-
GlobalQueue.
|
|
272
|
+
if (GlobalQueue.vt !== null) return;
|
|
273
|
+
GlobalQueue.vt = optimisticWrite;
|
|
274
|
+
GlobalQueue.fn = resolveOptimisticNodes;
|
|
275
|
+
GlobalQueue.En = transitionBlocked;
|
|
276
|
+
GlobalQueue.Tn = cleanupCompletedLanes;
|
|
277
|
+
GlobalQueue.dn = runLaneEffects;
|
|
278
|
+
GlobalQueue.Ft = gatedRead;
|
|
279
|
+
GlobalQueue.ht = laneSuspends;
|
|
280
|
+
GlobalQueue.gt = laneReadsCommitted;
|
|
256
281
|
GlobalQueue.je = recomputeLane;
|
|
257
|
-
GlobalQueue
|
|
258
|
-
GlobalQueue.
|
|
259
|
-
GlobalQueue.
|
|
282
|
+
GlobalQueue.$e = laneAsyncPending;
|
|
283
|
+
GlobalQueue.ze = laneAsyncSettled;
|
|
284
|
+
GlobalQueue.In = trackOptimisticStore;
|
|
260
285
|
}
|
|
261
286
|
|
|
262
287
|
export { installOptimisticEngine };
|