@solidjs/signals 2.0.0-beta.21 → 2.0.0-beta.23
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 +210 -301
- package/dist/node.cjs +1106 -1196
- package/dist/prod/affects.js +71 -163
- package/dist/prod/boundaries.js +141 -137
- package/dist/prod/core/action.js +3 -3
- package/dist/prod/core/async.js +103 -103
- package/dist/prod/core/core.js +254 -297
- package/dist/prod/core/effect.js +46 -46
- package/dist/prod/core/external.js +4 -4
- package/dist/prod/core/graph.js +60 -47
- package/dist/prod/core/heap.js +50 -50
- package/dist/prod/core/lanes.js +34 -34
- package/dist/prod/core/optimistic.js +64 -106
- package/dist/prod/core/owner.js +52 -52
- package/dist/prod/core/scheduler.js +210 -211
- package/dist/prod/core/verdict.js +129 -78
- package/dist/prod/map.js +101 -101
- package/dist/prod/signals.js +23 -5
- package/dist/prod/store/optimistic.js +11 -11
- package/dist/prod/store/projection.js +2 -2
- package/dist/prod/store/store.js +14 -14
- package/dist/types/affects.d.ts +9 -9
- package/dist/types/core/async.d.ts +1 -1
- package/dist/types/core/error.d.ts +7 -0
- package/dist/types/core/scheduler.d.ts +1 -6
- package/dist/types/core/types.d.ts +6 -11
- package/dist/types-cjs/affects.d.cts +9 -9
- package/dist/types-cjs/core/async.d.cts +1 -1
- package/dist/types-cjs/core/error.d.cts +7 -0
- package/dist/types-cjs/core/scheduler.d.cts +1 -6
- package/dist/types-cjs/core/types.d.cts +6 -11
- package/package.json +1 -1
package/dist/prod/map.js
CHANGED
|
@@ -21,24 +21,24 @@ function mapArray(t, s, i) {
|
|
|
21
21
|
const r = s.length > 1;
|
|
22
22
|
const n = s;
|
|
23
23
|
const h = {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
wt: createOwner(),
|
|
25
|
+
jt: 0,
|
|
26
|
+
Wt: t,
|
|
27
|
+
Mt: [],
|
|
28
|
+
Kt: n,
|
|
27
29
|
xt: [],
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
Yt: i?.keyed === false,
|
|
35
|
-
Zt: i?.fallback
|
|
30
|
+
Ft: [],
|
|
31
|
+
Gt: e,
|
|
32
|
+
Ut: e || i?.keyed === false ? [] : undefined,
|
|
33
|
+
$t: r && i?.keyed !== false ? [] : undefined,
|
|
34
|
+
qt: i?.keyed === false,
|
|
35
|
+
zt: i?.fallback
|
|
36
36
|
};
|
|
37
37
|
const o = computed(updateKeyedMap.bind(h));
|
|
38
38
|
// Untracked reads inside the internal owner resolve via _parentComputed; routing
|
|
39
39
|
// them through node lets store-proxy lookups see pending writes (not stale _value).
|
|
40
|
-
h.
|
|
41
|
-
o.
|
|
40
|
+
h.wt.Nt = o;
|
|
41
|
+
o.T &= ~CONFIG_AUTO_DISPOSE;
|
|
42
42
|
return accessor(o);
|
|
43
43
|
}
|
|
44
44
|
|
|
@@ -56,52 +56,52 @@ const pureOptions = {
|
|
|
56
56
|
// strong-abort ordering: removed rows now dispose AFTER the pass's new rows
|
|
57
57
|
// are created (you cannot destroy state before knowing the pass will land).
|
|
58
58
|
function updateKeyedMap() {
|
|
59
|
-
const t = this.
|
|
59
|
+
const t = this.Wt() || [], s = t.length;
|
|
60
60
|
t[$TRACK];
|
|
61
61
|
// top level tracking
|
|
62
|
-
runWithOwner(this.
|
|
62
|
+
runWithOwner(this.wt, () => {
|
|
63
63
|
let i, e, r, n,
|
|
64
64
|
// Mappers write freshly-created row/index signals into the STAGE
|
|
65
65
|
// arrays (`rows`/`indexes`), never into `this._rows`/`this._indexes`.
|
|
66
|
-
h = this.
|
|
66
|
+
h = this.Ut ? this.qt ? () => {
|
|
67
67
|
r[e] = signal(t[e], pureOptions);
|
|
68
|
-
return this
|
|
68
|
+
return this.Kt(accessor(r[e]), e);
|
|
69
69
|
} : () => {
|
|
70
70
|
r[e] = signal(t[e], pureOptions);
|
|
71
71
|
n && (n[e] = signal(e, pureOptions));
|
|
72
|
-
return this
|
|
73
|
-
} : this
|
|
72
|
+
return this.Kt(accessor(r[e]), n ? accessor(n[e]) : undefined);
|
|
73
|
+
} : this.$t ? () => {
|
|
74
74
|
const s = t[e];
|
|
75
75
|
n[e] = signal(e, pureOptions);
|
|
76
|
-
return this
|
|
76
|
+
return this.Kt(s, accessor(n[e]));
|
|
77
77
|
} : () => {
|
|
78
78
|
const s = t[e];
|
|
79
|
-
return this
|
|
79
|
+
return this.Kt(s);
|
|
80
80
|
};
|
|
81
81
|
// fast path for empty arrays
|
|
82
82
|
if (s === 0) {
|
|
83
|
-
if (this.
|
|
84
|
-
this.
|
|
85
|
-
this.
|
|
83
|
+
if (this.jt !== 0) {
|
|
84
|
+
this.wt.dispose(false);
|
|
85
|
+
this.Ft = [];
|
|
86
|
+
this.Mt = [];
|
|
86
87
|
this.xt = [];
|
|
87
|
-
this.
|
|
88
|
-
this.
|
|
89
|
-
this
|
|
90
|
-
this.Xt && (this.Xt = []);
|
|
88
|
+
this.jt = 0;
|
|
89
|
+
this.Ut && (this.Ut = []);
|
|
90
|
+
this.$t && (this.$t = []);
|
|
91
91
|
}
|
|
92
|
-
if (this.
|
|
92
|
+
if (this.zt && !this.xt[0]) {
|
|
93
93
|
// an aborted fallback attempt leaves an owner without a mapping;
|
|
94
94
|
// dispose it before re-creating
|
|
95
|
-
this.
|
|
96
|
-
this.
|
|
95
|
+
this.Ft[0]?.dispose();
|
|
96
|
+
this.xt[0] = runWithOwner(this.Ft[0] = createOwner(), this.zt);
|
|
97
97
|
}
|
|
98
98
|
}
|
|
99
99
|
// fast path for new create
|
|
100
|
-
else if (this.
|
|
100
|
+
else if (this.jt === 0) {
|
|
101
101
|
const o = new Array(s);
|
|
102
102
|
const c = new Array(s);
|
|
103
|
-
r = this.
|
|
104
|
-
n = this
|
|
103
|
+
r = this.Ut && new Array(s);
|
|
104
|
+
n = this.$t && new Array(s);
|
|
105
105
|
try {
|
|
106
106
|
for (e = 0; e < s; e++) o[e] = runWithOwner(c[e] = createOwner(), h);
|
|
107
107
|
} catch (t) {
|
|
@@ -109,53 +109,53 @@ function updateKeyedMap() {
|
|
|
109
109
|
throw t;
|
|
110
110
|
}
|
|
111
111
|
// commit
|
|
112
|
-
if (this.
|
|
112
|
+
if (this.Ft[0]) this.Ft[0].dispose();
|
|
113
113
|
// previous fallback
|
|
114
|
-
this.
|
|
115
|
-
this.
|
|
116
|
-
r && (this.
|
|
117
|
-
n && (this
|
|
118
|
-
this.
|
|
119
|
-
this.
|
|
114
|
+
this.xt = o;
|
|
115
|
+
this.Ft = c;
|
|
116
|
+
r && (this.Ut = r);
|
|
117
|
+
n && (this.$t = n);
|
|
118
|
+
this.Mt = t.slice(0);
|
|
119
|
+
this.jt = s;
|
|
120
120
|
} else {
|
|
121
121
|
let o, c, a, f, u, p, w, l, d, O = new Array(s), m = new Array(s);
|
|
122
|
-
r = this.
|
|
123
|
-
n = this
|
|
122
|
+
r = this.Ut ? new Array(s) : undefined;
|
|
123
|
+
n = this.$t ? new Array(s) : undefined;
|
|
124
124
|
// skip common prefix
|
|
125
|
-
for (o = 0, c = Math.min(this.
|
|
126
|
-
if (this.
|
|
125
|
+
for (o = 0, c = Math.min(this.jt, s); o < c && (this.Mt[o] === t[o] || this.Ut && compare(this.Gt, this.Mt[o], t[o])); o++) {
|
|
126
|
+
if (this.Ut) setSignal(this.Ut[o], t[o]);
|
|
127
127
|
}
|
|
128
128
|
// common suffix
|
|
129
|
-
for (c = this.
|
|
129
|
+
for (c = this.jt - 1, a = s - 1; c >= o && a >= o && (this.Mt[c] === t[a] || this.Ut && compare(this.Gt, this.Mt[c], t[a])); c--,
|
|
130
130
|
a--) {
|
|
131
|
-
O[a] = this.
|
|
132
|
-
m[a] = this.
|
|
133
|
-
r && (r[a] = this.
|
|
134
|
-
n && (n[a] = this
|
|
131
|
+
O[a] = this.xt[c];
|
|
132
|
+
m[a] = this.Ft[c];
|
|
133
|
+
r && (r[a] = this.Ut[c]);
|
|
134
|
+
n && (n[a] = this.$t[c]);
|
|
135
135
|
}
|
|
136
136
|
// 0) prepare a map of all indices in newItems, scanning backwards so we encounter them in natural order
|
|
137
137
|
p = new Map;
|
|
138
138
|
w = new Array(a + 1);
|
|
139
139
|
for (e = a; e >= o; e--) {
|
|
140
140
|
f = t[e];
|
|
141
|
-
u = this.
|
|
141
|
+
u = this.Gt ? this.Gt(f) : f;
|
|
142
142
|
i = p.get(u);
|
|
143
143
|
w[e] = i === undefined ? -1 : i;
|
|
144
144
|
p.set(u, e);
|
|
145
145
|
}
|
|
146
146
|
// 1) step through all old items and see if they can be found in the new set; if so, save them in a temp array and mark them moved; if not, queue them for disposal at commit
|
|
147
147
|
for (i = o; i <= c; i++) {
|
|
148
|
-
f = this.
|
|
149
|
-
u = this.
|
|
148
|
+
f = this.Mt[i];
|
|
149
|
+
u = this.Gt ? this.Gt(f) : f;
|
|
150
150
|
e = p.get(u);
|
|
151
151
|
if (e !== undefined && e !== -1) {
|
|
152
|
-
O[e] = this.
|
|
153
|
-
m[e] = this.
|
|
154
|
-
r && (r[e] = this.
|
|
155
|
-
n && (n[e] = this
|
|
152
|
+
O[e] = this.xt[i];
|
|
153
|
+
m[e] = this.Ft[i];
|
|
154
|
+
r && (r[e] = this.Ut[i]);
|
|
155
|
+
n && (n[e] = this.$t[i]);
|
|
156
156
|
e = w[e];
|
|
157
157
|
p.set(u, e);
|
|
158
|
-
} else (l ??= []).push(this.
|
|
158
|
+
} else (l ??= []).push(this.Ft[i]);
|
|
159
159
|
}
|
|
160
160
|
// 2) create new rows into the temp arrays; an abort disposes only these
|
|
161
161
|
try {
|
|
@@ -170,25 +170,25 @@ function updateKeyedMap() {
|
|
|
170
170
|
}
|
|
171
171
|
// 3) commit: land positions, then dispose exited rows
|
|
172
172
|
for (e = o; e < s; e++) {
|
|
173
|
-
this.
|
|
174
|
-
this.
|
|
173
|
+
this.xt[e] = O[e];
|
|
174
|
+
this.Ft[e] = m[e];
|
|
175
175
|
if (r) {
|
|
176
|
-
this.
|
|
177
|
-
setSignal(this.
|
|
176
|
+
this.Ut[e] = r[e];
|
|
177
|
+
setSignal(this.Ut[e], t[e]);
|
|
178
178
|
}
|
|
179
179
|
if (n) {
|
|
180
|
-
this
|
|
181
|
-
setSignal(this
|
|
180
|
+
this.$t[e] = n[e];
|
|
181
|
+
setSignal(this.$t[e], e);
|
|
182
182
|
}
|
|
183
183
|
}
|
|
184
184
|
if (l) for (i = 0; i < l.length; i++) l[i].dispose();
|
|
185
185
|
// 4) in case the new set is shorter than the old, set the length of the mapped array
|
|
186
|
-
this.
|
|
186
|
+
this.xt = this.xt.slice(0, this.jt = s);
|
|
187
187
|
// 5) save a copy of the mapped items for the next update
|
|
188
|
-
this.
|
|
188
|
+
this.Mt = t.slice(0);
|
|
189
189
|
}
|
|
190
190
|
});
|
|
191
|
-
return this.
|
|
191
|
+
return this.xt;
|
|
192
192
|
}
|
|
193
193
|
|
|
194
194
|
/**
|
|
@@ -208,22 +208,22 @@ function updateKeyedMap() {
|
|
|
208
208
|
*/ function repeat(t, s, i) {
|
|
209
209
|
const e = s;
|
|
210
210
|
const r = {
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
211
|
+
wt: createOwner(),
|
|
212
|
+
jt: 0,
|
|
213
|
+
Bt: 0,
|
|
214
|
+
Ht: t,
|
|
215
|
+
Kt: e,
|
|
216
|
+
Ft: [],
|
|
217
|
+
xt: [],
|
|
218
|
+
Jt: i?.from,
|
|
219
|
+
zt: i?.fallback
|
|
220
220
|
};
|
|
221
221
|
const n = computed(updateRepeat.bind(r));
|
|
222
222
|
// Same as mapArray: untracked reads inside the internal owner resolve via
|
|
223
223
|
// _parentComputed, so async reads in row callbacks register with the node
|
|
224
224
|
// (pending tracking + post-settle retry) instead of vanishing.
|
|
225
|
-
r.
|
|
226
|
-
n.
|
|
225
|
+
r.wt.Nt = n;
|
|
226
|
+
n.T &= ~CONFIG_AUTO_DISPOSE;
|
|
227
227
|
return accessor(n);
|
|
228
228
|
}
|
|
229
229
|
|
|
@@ -235,55 +235,55 @@ function updateKeyedMap() {
|
|
|
235
235
|
// for the post-settle retry. The overlap math also subsumes the previous
|
|
236
236
|
// disjoint-window/front-clear/end-clear/shift special cases.
|
|
237
237
|
function updateRepeat() {
|
|
238
|
-
const t = this.
|
|
239
|
-
const s = this.
|
|
240
|
-
runWithOwner(this.
|
|
238
|
+
const t = this.Ht();
|
|
239
|
+
const s = this.Jt?.() || 0;
|
|
240
|
+
runWithOwner(this.wt, () => {
|
|
241
241
|
if (t === 0) {
|
|
242
|
-
if (this.
|
|
243
|
-
this.
|
|
244
|
-
this.
|
|
245
|
-
this.
|
|
246
|
-
this.
|
|
242
|
+
if (this.jt !== 0) {
|
|
243
|
+
this.wt.dispose(false);
|
|
244
|
+
this.Ft = [];
|
|
245
|
+
this.xt = [];
|
|
246
|
+
this.jt = 0;
|
|
247
247
|
// Reset offset to match the cleared data (#2767, repro 2).
|
|
248
|
-
this.
|
|
248
|
+
this.Bt = 0;
|
|
249
249
|
}
|
|
250
|
-
if (this.
|
|
250
|
+
if (this.zt && !this.xt[0]) {
|
|
251
251
|
// an aborted fallback attempt leaves an owner without a mapping;
|
|
252
252
|
// dispose it before re-creating
|
|
253
|
-
this.
|
|
254
|
-
this.
|
|
253
|
+
this.Ft[0]?.dispose();
|
|
254
|
+
this.xt[0] = runWithOwner(this.Ft[0] = createOwner(), this.zt);
|
|
255
255
|
}
|
|
256
256
|
return;
|
|
257
257
|
}
|
|
258
258
|
const i = s + t;
|
|
259
|
-
const e = this.
|
|
259
|
+
const e = this.Bt + this.jt;
|
|
260
260
|
// Retained overlap [keepStart, keepEnd) in global indexes; empty when the
|
|
261
261
|
// windows are disjoint or when coming from empty/fallback.
|
|
262
|
-
const r = Math.max(s, this.
|
|
262
|
+
const r = Math.max(s, this.Bt);
|
|
263
263
|
const n = Math.min(i, e);
|
|
264
264
|
const h = new Array(t);
|
|
265
265
|
const o = new Array(t);
|
|
266
266
|
for (let t = r; t < n; t++) {
|
|
267
|
-
o[t - s] = this.
|
|
268
|
-
h[t - s] = this.
|
|
267
|
+
o[t - s] = this.Ft[t - this.Bt];
|
|
268
|
+
h[t - s] = this.xt[t - this.Bt];
|
|
269
269
|
}
|
|
270
270
|
try {
|
|
271
271
|
for (let t = s; t < i; t++) {
|
|
272
272
|
if (t >= r && t < n) continue;
|
|
273
|
-
h[t - s] = runWithOwner(o[t - s] = createOwner(), () => this
|
|
273
|
+
h[t - s] = runWithOwner(o[t - s] = createOwner(), () => this.Kt(t));
|
|
274
274
|
}
|
|
275
275
|
} catch (t) {
|
|
276
276
|
for (let t = s; t < i; t++) if ((t < r || t >= n) && o[t - s]) o[t - s].dispose();
|
|
277
277
|
throw t;
|
|
278
278
|
}
|
|
279
279
|
// commit: dispose the previous fallback or the rows leaving the window
|
|
280
|
-
if (this.
|
|
281
|
-
this.
|
|
282
|
-
this.
|
|
283
|
-
this.
|
|
284
|
-
this.
|
|
280
|
+
if (this.jt === 0) this.Ft[0]?.dispose(); else for (let t = this.Bt; t < e; t++) if (t < s || t >= i) this.Ft[t - this.Bt].dispose();
|
|
281
|
+
this.xt = h;
|
|
282
|
+
this.Ft = o;
|
|
283
|
+
this.Bt = s;
|
|
284
|
+
this.jt = t;
|
|
285
285
|
});
|
|
286
|
-
return this.
|
|
286
|
+
return this.xt;
|
|
287
287
|
}
|
|
288
288
|
|
|
289
289
|
function compare(t, s, i) {
|
package/dist/prod/signals.js
CHANGED
|
@@ -2,7 +2,7 @@ import { computed, optimisticComputed, setSignal, optimisticSignal, runWithOwner
|
|
|
2
2
|
|
|
3
3
|
import { cleanup, createRoot, getOwner, dispose } from "./core/owner.js";
|
|
4
4
|
|
|
5
|
-
import { globalQueue } from "./core/scheduler.js";
|
|
5
|
+
import { globalQueue, Queue } from "./core/scheduler.js";
|
|
6
6
|
|
|
7
7
|
import { CONFIG_AUTO_DISPOSE, CONFIG_CHILDREN_FORBIDDEN, EFFECT_USER, $REFRESH } from "./core/constants.js";
|
|
8
8
|
|
|
@@ -65,7 +65,7 @@ function accessor(e) {
|
|
|
65
65
|
function createSignal(e, t) {
|
|
66
66
|
if (typeof e === "function") {
|
|
67
67
|
const n = computed(e, t);
|
|
68
|
-
n.
|
|
68
|
+
n.T &= ~CONFIG_AUTO_DISPOSE;
|
|
69
69
|
return [ accessor(n), setMemo.bind(null, n) ];
|
|
70
70
|
}
|
|
71
71
|
const n = signal(e, t);
|
|
@@ -239,6 +239,12 @@ function createEffect(e, t, n) {
|
|
|
239
239
|
};
|
|
240
240
|
}
|
|
241
241
|
|
|
242
|
+
/** Delivers effect applies on a microtask instead of queueing them (#2930). */ class MicrotaskQueue extends Queue {
|
|
243
|
+
enqueue(e, t) {
|
|
244
|
+
queueMicrotask(() => t(e));
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
242
248
|
/**
|
|
243
249
|
* Awaits a reactive expression and returns its first fully-settled value as a
|
|
244
250
|
* `Promise`. Pending async reads (`createMemo` returning a promise, etc.) are
|
|
@@ -262,11 +268,23 @@ function createEffect(e, t, n) {
|
|
|
262
268
|
*/ function resolve(e) {
|
|
263
269
|
return new Promise((t, n) => {
|
|
264
270
|
createRoot(c => {
|
|
271
|
+
// Deliver effect applies on a microtask instead of the owner queue: an
|
|
272
|
+
// incomplete transition stashes its effect queues until it settles, but
|
|
273
|
+
// an action yielding this promise is itself what keeps the transition
|
|
274
|
+
// open — the stashed res() deadlocked the action (#2930). The compute
|
|
275
|
+
// still runs in place (under the transaction's view when created inside
|
|
276
|
+
// an action step), and status/boundary notifications keep their normal
|
|
277
|
+
// route through the inherited queue.
|
|
278
|
+
const r = getOwner();
|
|
279
|
+
const o = new MicrotaskQueue;
|
|
280
|
+
o.Ge = r.C;
|
|
281
|
+
// notify() forwards up the normal chain
|
|
282
|
+
r.C = o;
|
|
265
283
|
// A user effect rather than a bare computed: computeds are pull-based and
|
|
266
284
|
// are only re-enqueued when a pending source *resolves* — a rejection just
|
|
267
285
|
// marks them errored, so nothing would re-run and the promise would never
|
|
268
286
|
// settle (#2842). The effect's error channel is notified on rejection.
|
|
269
|
-
|
|
287
|
+
effect(e, e => {
|
|
270
288
|
t(e);
|
|
271
289
|
c();
|
|
272
290
|
}, e => {
|
|
@@ -288,7 +306,7 @@ function createOptimistic(e, t) {
|
|
|
288
306
|
installOptimisticEngine();
|
|
289
307
|
if (typeof e === "function") {
|
|
290
308
|
const n = optimisticComputed(e, t);
|
|
291
|
-
n.
|
|
309
|
+
n.T &= ~CONFIG_AUTO_DISPOSE;
|
|
292
310
|
return [ accessor(n), setSignal.bind(null, n) ];
|
|
293
311
|
}
|
|
294
312
|
const n = optimisticSignal(e, t);
|
|
@@ -377,7 +395,7 @@ function createOptimistic(e, t) {
|
|
|
377
395
|
* on owner disposal
|
|
378
396
|
*/ function onSettled(e) {
|
|
379
397
|
const t = getOwner();
|
|
380
|
-
t && !(t.
|
|
398
|
+
t && !(t.T & CONFIG_CHILDREN_FORBIDDEN) ? createTrackedEffect(() => untrack(e), undefined) : globalQueue.enqueue(EFFECT_USER, () => {
|
|
381
399
|
// Unowned, out-of-band fire (no owner, or a children-forbidden one this
|
|
382
400
|
// one-shot must not bind to): a returned cleanup has no lifecycle to
|
|
383
401
|
// attach to. Reject it in dev; in production the return is simply
|
|
@@ -21,7 +21,7 @@ function createOptimisticStore(e, t, r) {
|
|
|
21
21
|
// STORE_OPTIMISTIC take the engine's write path, so install it before any
|
|
22
22
|
// node can be created.
|
|
23
23
|
installOptimisticEngine();
|
|
24
|
-
GlobalQueue.
|
|
24
|
+
GlobalQueue.Dt ||= clearOptimisticStores;
|
|
25
25
|
const i = typeof e === "function";
|
|
26
26
|
const o = i ? t : e;
|
|
27
27
|
const n = i ? e : undefined;
|
|
@@ -76,8 +76,8 @@ function clearOptimisticStores(e, t) {
|
|
|
76
76
|
// (initTransition mid-batch) or to the plain flush, so it clears on
|
|
77
77
|
// whichever clear call reaches this store first.
|
|
78
78
|
if (e) {
|
|
79
|
-
if (typeof e.
|
|
80
|
-
if (e !== t && e.
|
|
79
|
+
if (typeof e.fn === "object") e = o[O] = currentTransition(e);
|
|
80
|
+
if (e !== t && e.fn !== true) {
|
|
81
81
|
s = true;
|
|
82
82
|
continue;
|
|
83
83
|
}
|
|
@@ -89,7 +89,7 @@ function clearOptimisticStores(e, t) {
|
|
|
89
89
|
const T = i?.[O];
|
|
90
90
|
if (T) {
|
|
91
91
|
// Clear lane association so effects go to regular queue
|
|
92
|
-
T.
|
|
92
|
+
T.je = undefined;
|
|
93
93
|
// Re-read from base — this key left the optimistic layer above, so the
|
|
94
94
|
// overlay resolves to STORE_OVERRIDE or STORE_VALUE.
|
|
95
95
|
const t = getOverlayLayer(e, O);
|
|
@@ -97,11 +97,11 @@ function clearOptimisticStores(e, t) {
|
|
|
97
97
|
const i = r === $DELETED ? undefined : r;
|
|
98
98
|
const o = isWrappable(i) ? wrap(i, e) : i;
|
|
99
99
|
const n = visibleNodeValue(T);
|
|
100
|
-
T.
|
|
101
|
-
T.
|
|
102
|
-
T.
|
|
103
|
-
T.
|
|
104
|
-
if (!T.
|
|
100
|
+
T.Ee = NOT_PENDING;
|
|
101
|
+
T.sn = null;
|
|
102
|
+
T.Ne = NOT_PENDING;
|
|
103
|
+
T.Pe = o;
|
|
104
|
+
if (!T.Re || !T.Re(n, o)) {
|
|
105
105
|
insertSubs(T, true);
|
|
106
106
|
schedule();
|
|
107
107
|
}
|
|
@@ -113,7 +113,7 @@ function clearOptimisticStores(e, t) {
|
|
|
113
113
|
}
|
|
114
114
|
// Notify $TRACK
|
|
115
115
|
if (c && i?.[$TRACK]) {
|
|
116
|
-
i[$TRACK].
|
|
116
|
+
i[$TRACK].je = undefined;
|
|
117
117
|
notifySelf(e);
|
|
118
118
|
}
|
|
119
119
|
} finally {
|
|
@@ -173,7 +173,7 @@ function createOptimisticProjectionInternal(e, t, r) {
|
|
|
173
173
|
setProjectionWriteActive(false);
|
|
174
174
|
}
|
|
175
175
|
}, undefined);
|
|
176
|
-
i.
|
|
176
|
+
i.T &= ~CONFIG_AUTO_DISPOSE;
|
|
177
177
|
}
|
|
178
178
|
return {
|
|
179
179
|
store: n,
|
|
@@ -41,7 +41,7 @@ function createProjectionInternal(e, r, t) {
|
|
|
41
41
|
if (!o) o = getOwner();
|
|
42
42
|
runProjectionComputed(n, e, t?.key || "id");
|
|
43
43
|
}, undefined);
|
|
44
|
-
o.
|
|
44
|
+
o.T &= ~CONFIG_AUTO_DISPOSE;
|
|
45
45
|
return {
|
|
46
46
|
store: n,
|
|
47
47
|
node: o
|
|
@@ -110,7 +110,7 @@ function createProjectionInternal(e, r, t) {
|
|
|
110
110
|
const n = getOwner();
|
|
111
111
|
let c = false;
|
|
112
112
|
let s;
|
|
113
|
-
const u = new Proxy(e, createWriteTraps(() => !c || n.
|
|
113
|
+
const u = new Proxy(e, createWriteTraps(() => !c || n.Te === s, i));
|
|
114
114
|
storeSetter(u, i => {
|
|
115
115
|
s = r(i);
|
|
116
116
|
c = true;
|
package/dist/prod/store/store.js
CHANGED
|
@@ -154,7 +154,7 @@ function ownEnumerableKeysPlain(e) {
|
|
|
154
154
|
* The value a store leaf's backing signal currently shows to readers: active
|
|
155
155
|
* override, else held pending value, else committed value.
|
|
156
156
|
*/ function visibleNodeValue(e) {
|
|
157
|
-
return e.
|
|
157
|
+
return e.Ee !== undefined && e.Ee !== NOT_PENDING ? unwrapOverride(e.Ee) : e.Ne !== NOT_PENDING ? e.Ne : e.Pe;
|
|
158
158
|
}
|
|
159
159
|
|
|
160
160
|
function hasOwnStoreProperty(e, t) {
|
|
@@ -205,11 +205,11 @@ function getNode(e, t, r, n, o = isEqual, i) {
|
|
|
205
205
|
}
|
|
206
206
|
}, e[STORE_FIREWALL]);
|
|
207
207
|
if (e[STORE_OPTIMISTIC]) {
|
|
208
|
-
s.
|
|
208
|
+
s.Ee = NOT_PENDING;
|
|
209
209
|
}
|
|
210
210
|
if (i && r in i) {
|
|
211
211
|
const e = i[r];
|
|
212
|
-
s.
|
|
212
|
+
s.Ve = e === undefined ? NO_SNAPSHOT : e;
|
|
213
213
|
snapshotSources?.add(s);
|
|
214
214
|
}
|
|
215
215
|
if (typeof r === "symbol" && r !== $TRACK && r !== $AFFECTS) symbolKeyedRecords.add(t);
|
|
@@ -238,8 +238,8 @@ function getNode(e, t, r, n, o = isEqual, i) {
|
|
|
238
238
|
*/ function inheritAffectsMarks(e, t, r) {
|
|
239
239
|
// A live scope exists, so affects.ts already installed the mark engine.
|
|
240
240
|
for (const [n, o] of affectsScopes) {
|
|
241
|
-
if (n.
|
|
242
|
-
GlobalQueue.
|
|
241
|
+
if (n.t && o.scope.has(t) && (o.key === undefined || o.key === r)) {
|
|
242
|
+
GlobalQueue.M(e);
|
|
243
243
|
o.inherited.push(e);
|
|
244
244
|
}
|
|
245
245
|
}
|
|
@@ -327,11 +327,11 @@ o) {
|
|
|
327
327
|
// Callers guard on `pendingCheckActive`, which only flips inside
|
|
328
328
|
// isPending() — the verdict layer is loaded and its hook installed.
|
|
329
329
|
const r = e[STORE_NODE]?.[$AFFECTS];
|
|
330
|
-
if (r?.
|
|
330
|
+
if (r?.t) GlobalQueue.Lt(r);
|
|
331
331
|
if (affectsScopes.size) {
|
|
332
332
|
const n = e[STORE_VALUE];
|
|
333
333
|
for (const [e, o] of affectsScopes) {
|
|
334
|
-
if (e !== r && e.
|
|
334
|
+
if (e !== r && e.t && o.scope.has(n) && (o.key === undefined || o.key === t)) GlobalQueue.Lt(e);
|
|
335
335
|
}
|
|
336
336
|
}
|
|
337
337
|
}
|
|
@@ -348,11 +348,11 @@ o) {
|
|
|
348
348
|
* @internal
|
|
349
349
|
*/ function getStoreAffectsNodes(e, t) {
|
|
350
350
|
const r = getNodes(e, STORE_NODE);
|
|
351
|
-
GlobalQueue.
|
|
351
|
+
GlobalQueue.p ||= e => {
|
|
352
352
|
const t = affectsScopes.get(e);
|
|
353
353
|
if (!t) return;
|
|
354
354
|
affectsScopes.delete(e);
|
|
355
|
-
for (let e = 0; e < t.inherited.length; e++) GlobalQueue.
|
|
355
|
+
for (let e = 0; e < t.inherited.length; e++) GlobalQueue.h(t.inherited[e]);
|
|
356
356
|
};
|
|
357
357
|
if (t === undefined) {
|
|
358
358
|
const t = getNode(e, r, $AFFECTS, undefined, false);
|
|
@@ -473,13 +473,13 @@ function getPropertyDescriptor(e, t, r) {
|
|
|
473
473
|
function prepareStoreWrite(e, t, r) {
|
|
474
474
|
if (e[STORE_OPTIMISTIC]) {
|
|
475
475
|
const t = e[STORE_FIREWALL];
|
|
476
|
-
if (t?.
|
|
477
|
-
globalQueue.initTransition(t.
|
|
476
|
+
if (t?.Ue) {
|
|
477
|
+
globalQueue.initTransition(t.Ue);
|
|
478
478
|
}
|
|
479
479
|
}
|
|
480
480
|
const n = e[STORE_VALUE];
|
|
481
481
|
const o = n[r];
|
|
482
|
-
if (snapshotCaptureActive && typeof r !== "symbol" && !((e[STORE_FIREWALL]?.
|
|
482
|
+
if (snapshotCaptureActive && typeof r !== "symbol" && !((e[STORE_FIREWALL]?.S ?? 0) & STATUS_PENDING)) {
|
|
483
483
|
if (!e[STORE_SNAPSHOT_PROPS]) {
|
|
484
484
|
e[STORE_SNAPSHOT_PROPS] = Object.create(null);
|
|
485
485
|
snapshotSources?.add(e);
|
|
@@ -507,7 +507,7 @@ function prepareStoreWrite(e, t, r) {
|
|
|
507
507
|
// STORE_OPTIMISTIC is only set by createOptimisticStore, which installs the
|
|
508
508
|
// optimistic engine before wrapping.
|
|
509
509
|
if (e[STORE_OPTIMISTIC] && !projectionWriteActive) {
|
|
510
|
-
GlobalQueue.
|
|
510
|
+
GlobalQueue.Nn(t);
|
|
511
511
|
}
|
|
512
512
|
}
|
|
513
513
|
|
|
@@ -580,7 +580,7 @@ let Writing = null;
|
|
|
580
580
|
* itself (the derive function works its own draft while uninitialized).
|
|
581
581
|
*/ function throwIfUninitialized(e) {
|
|
582
582
|
const t = e[STORE_FIREWALL];
|
|
583
|
-
if (t && t.
|
|
583
|
+
if (t && t.S & STATUS_UNINITIALIZED) throw t._ ?? new NotReadyError(t);
|
|
584
584
|
}
|
|
585
585
|
|
|
586
586
|
const storeTraps = {
|
package/dist/types/affects.d.ts
CHANGED
|
@@ -4,15 +4,15 @@ import { type Store } from "./store/store.js";
|
|
|
4
4
|
* Declares that in-flight work will change the targeted data: the named
|
|
5
5
|
* slot(s) — and everything DERIVED from them — read as pending
|
|
6
6
|
* (`isPending` → `true`) from the declaration until the surrounding
|
|
7
|
-
* transaction settles or reverts.
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* makes it a real question).
|
|
7
|
+
* transaction settles or reverts. A mark lives on its own channel — a
|
|
8
|
+
* refcount on the marked node plus dep-graph reachability in the verdict
|
|
9
|
+
* layer — so the marked values themselves stay readable (a mark is a promise
|
|
10
|
+
* of change, not an absence of value), no reader ever suspends on one, and
|
|
11
|
+
* completion/settlement accounting never sees one. This is the declaration
|
|
12
|
+
* verb of the pending model — additive only. A mark can turn pending ON for
|
|
13
|
+
* data the graph can't see changing yet; nothing can turn pending OFF while
|
|
14
|
+
* a real change is in flight — a quiet `refresh()` re-ask under a mark still
|
|
15
|
+
* reads pending (declaring the reload is what makes it a real question).
|
|
16
16
|
*
|
|
17
17
|
* Targets:
|
|
18
18
|
* - `affects(store)` — a store proxy (any record, root or nested): every
|
|
@@ -3,7 +3,7 @@ import type { Computed, Link } from "./types.js";
|
|
|
3
3
|
export declare function addPendingSource(el: Computed<any>, source: Computed<any>): boolean;
|
|
4
4
|
export declare function setPendingError(el: Computed<any>, source?: Computed<any>, error?: any): void;
|
|
5
5
|
export declare function forEachDependent(el: Computed<any>, fn: (node: Computed<any>, link: Link) => void): void;
|
|
6
|
-
export declare function settlePendingSource(el: Computed<any
|
|
6
|
+
export declare function settlePendingSource(el: Computed<any>): void;
|
|
7
7
|
export declare function isThenable<T>(value: T | PromiseLike<T>): value is PromiseLike<T>;
|
|
8
8
|
export declare function handleAsync<T>(el: Computed<T>, result: T | PromiseLike<T> | AsyncIterable<T>, setter?: (value: T) => void): T;
|
|
9
9
|
export declare function clearStatus(el: Computed<any>, clearUninitialized?: boolean): void;
|
|
@@ -24,6 +24,13 @@
|
|
|
24
24
|
*/
|
|
25
25
|
export declare class NotReadyError extends Error {
|
|
26
26
|
source: any;
|
|
27
|
+
/**
|
|
28
|
+
* Tags a visibility-only notification on the affects() boundary channel:
|
|
29
|
+
* boundaries update display state from it, but the root queue never
|
|
30
|
+
* registers a reporter — marks are invisible to completion accounting by
|
|
31
|
+
* construction.
|
|
32
|
+
*/
|
|
33
|
+
_markVisual?: boolean;
|
|
27
34
|
constructor(source: any);
|
|
28
35
|
}
|
|
29
36
|
export declare class StatusError extends Error {
|