@solidjs/signals 2.0.0-beta.31 → 2.0.0-beta.33
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 +250 -89
- package/dist/node.cjs +775 -637
- package/dist/prod/core/async.js +131 -62
- package/dist/prod/core/core.js +231 -194
- 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 +37 -37
- package/dist/prod/core/owner.js +53 -44
- package/dist/prod/core/scheduler.js +74 -70
- package/dist/prod/core/verdict.js +57 -46
- package/dist/prod/map.js +6 -6
- package/dist/prod/signals.js +2 -34
- package/dist/prod/store/optimistic.js +35 -30
- 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
package/dist/node.cjs
CHANGED
|
@@ -653,8 +653,8 @@ class GlobalQueue extends Queue {
|
|
|
653
653
|
static Ae=null;
|
|
654
654
|
static he=null;
|
|
655
655
|
static Ne=null;
|
|
656
|
-
static ye=null;
|
|
657
656
|
static Pe=null;
|
|
657
|
+
static ye=null;
|
|
658
658
|
static Ce=null;
|
|
659
659
|
static ge=null;
|
|
660
660
|
static be=null;
|
|
@@ -875,9 +875,13 @@ function commitPendingNode(e) {
|
|
|
875
875
|
// Set _modified for effects, but not for tracked effects (they handle their own scheduling)
|
|
876
876
|
if (e.Fe && e.Fe !== EFFECT_TRACKED) e.Qe = true;
|
|
877
877
|
}
|
|
878
|
+
// The committed hold is the first observable answer for a loading-window
|
|
879
|
+
// node — the window closes here, not at compute time (#2990). Unconditional
|
|
880
|
+
// store to an always-present computed slot.
|
|
881
|
+
t.xe = false;
|
|
878
882
|
t.D &= ~REACTIVE_MANUAL_WRITE;
|
|
879
|
-
if (!(t.
|
|
880
|
-
if (t.
|
|
883
|
+
if (!(t.He & STATUS_PENDING)) t.He &= ~STATUS_UNINITIALIZED;
|
|
884
|
+
if (t.Me !== null || t.$e !== null) GlobalQueue.ee(t, false, true);
|
|
881
885
|
if (e._ || e.R) GlobalQueue.Ee(e);
|
|
882
886
|
}
|
|
883
887
|
|
|
@@ -942,7 +946,7 @@ function finalizePureQueue(e = null, t = false) {
|
|
|
942
946
|
|
|
943
947
|
function checkBoundaryChildren(e) {
|
|
944
948
|
for (const t of e.v) {
|
|
945
|
-
t
|
|
949
|
+
t.je?.();
|
|
946
950
|
checkBoundaryChildren(t);
|
|
947
951
|
}
|
|
948
952
|
}
|
|
@@ -1010,15 +1014,15 @@ function runQueue$1(e, t) {
|
|
|
1010
1014
|
|
|
1011
1015
|
function reporterBlocksSource(e, t) {
|
|
1012
1016
|
if (e.D & (REACTIVE_ZOMBIE | REACTIVE_DISPOSED)) return false;
|
|
1013
|
-
if (e.
|
|
1014
|
-
for (let n = e.
|
|
1015
|
-
let e = n.
|
|
1017
|
+
if (e.Ke?.has(t)) return true;
|
|
1018
|
+
for (let n = e.Ye; n; n = n.qe) {
|
|
1019
|
+
let e = n.Be;
|
|
1016
1020
|
while (e) {
|
|
1017
|
-
if (e === t || e.
|
|
1021
|
+
if (e === t || e.Ze === t) return true;
|
|
1018
1022
|
e = e.t;
|
|
1019
1023
|
}
|
|
1020
1024
|
}
|
|
1021
|
-
return !!(e.
|
|
1025
|
+
return !!(e.He & STATUS_PENDING && e.me instanceof NotReadyError && e.me.source === t);
|
|
1022
1026
|
}
|
|
1023
1027
|
|
|
1024
1028
|
function transitionComplete(e) {
|
|
@@ -1034,7 +1038,7 @@ function transitionComplete(e) {
|
|
|
1034
1038
|
}
|
|
1035
1039
|
r.delete(e);
|
|
1036
1040
|
}
|
|
1037
|
-
if (!i) e.$.delete(n); else if (n.
|
|
1041
|
+
if (!i) e.$.delete(n); else if (n.He & STATUS_PENDING && n.me?.source === n) {
|
|
1038
1042
|
t = false;
|
|
1039
1043
|
break;
|
|
1040
1044
|
}
|
|
@@ -1075,25 +1079,25 @@ function runInTransition(e, t) {
|
|
|
1075
1079
|
const t = e;
|
|
1076
1080
|
if (!t.Qe) {
|
|
1077
1081
|
t.Qe = true;
|
|
1078
|
-
t.
|
|
1082
|
+
t.Xe.enqueue(EFFECT_USER, t.ze);
|
|
1079
1083
|
}
|
|
1080
1084
|
return;
|
|
1081
1085
|
}
|
|
1082
1086
|
const t = queueFor(e);
|
|
1083
|
-
if (t.P > e.
|
|
1087
|
+
if (t.P > e.Je) t.P = e.Je;
|
|
1084
1088
|
insertIntoHeap(e, t);
|
|
1085
1089
|
}
|
|
1086
1090
|
|
|
1087
1091
|
function actualInsertIntoHeap(e, t) {
|
|
1088
|
-
const n = (e.Z?.
|
|
1089
|
-
if (n >= e.
|
|
1090
|
-
const r = e.
|
|
1092
|
+
const n = (e.Z?.et ? e.Z.tt?.Je : e.Z?.Je) ?? -1;
|
|
1093
|
+
if (n >= e.Je) e.Je = n + 1;
|
|
1094
|
+
const r = e.Je;
|
|
1091
1095
|
const i = t.h[r];
|
|
1092
1096
|
if (i === undefined) t.h[r] = e; else {
|
|
1093
|
-
const t = i.
|
|
1094
|
-
t.
|
|
1095
|
-
e.
|
|
1096
|
-
i.
|
|
1097
|
+
const t = i.nt;
|
|
1098
|
+
t.rt = e;
|
|
1099
|
+
e.nt = t;
|
|
1100
|
+
i.nt = e;
|
|
1097
1101
|
}
|
|
1098
1102
|
if (r > t.C) t.C = r;
|
|
1099
1103
|
}
|
|
@@ -1126,23 +1130,23 @@ function deleteFromHeap(e, t) {
|
|
|
1126
1130
|
const n = e.D;
|
|
1127
1131
|
if (!(n & (REACTIVE_IN_HEAP | REACTIVE_IN_HEAP_HEIGHT))) return;
|
|
1128
1132
|
e.D = n & -25;
|
|
1129
|
-
const r = e.
|
|
1130
|
-
if (e.
|
|
1131
|
-
const n = e.
|
|
1133
|
+
const r = e.Je;
|
|
1134
|
+
if (e.nt === e) t.h[r] = undefined; else {
|
|
1135
|
+
const n = e.rt;
|
|
1132
1136
|
const i = t.h[r];
|
|
1133
1137
|
const o = n ?? i;
|
|
1134
|
-
if (e === i) t.h[r] = n; else e.
|
|
1135
|
-
o.
|
|
1138
|
+
if (e === i) t.h[r] = n; else e.nt.rt = n;
|
|
1139
|
+
o.nt = e.nt;
|
|
1136
1140
|
}
|
|
1137
|
-
e.
|
|
1138
|
-
e.
|
|
1141
|
+
e.nt = e;
|
|
1142
|
+
e.rt = undefined;
|
|
1139
1143
|
}
|
|
1140
1144
|
|
|
1141
1145
|
function markHeap(e) {
|
|
1142
1146
|
if (e.N) return;
|
|
1143
1147
|
e.N = true;
|
|
1144
1148
|
for (let t = 0; t <= e.C; t++) {
|
|
1145
|
-
for (let n = e.h[t]; n !== undefined; n = n.
|
|
1149
|
+
for (let n = e.h[t]; n !== undefined; n = n.rt) {
|
|
1146
1150
|
if (n.D & REACTIVE_IN_HEAP) markNode(n);
|
|
1147
1151
|
}
|
|
1148
1152
|
}
|
|
@@ -1155,8 +1159,8 @@ function markNode(e, t = REACTIVE_DIRTY) {
|
|
|
1155
1159
|
for (let t = e.U; t !== null; t = t.Ge) {
|
|
1156
1160
|
markNode(t.Ve, REACTIVE_CHECK);
|
|
1157
1161
|
}
|
|
1158
|
-
if (e.
|
|
1159
|
-
for (let t = e.
|
|
1162
|
+
if (e.it !== null) {
|
|
1163
|
+
for (let t = e.it; t !== null; t = t.ot) {
|
|
1160
1164
|
for (let e = t.U; e !== null; e = e.Ge) {
|
|
1161
1165
|
markNode(e.Ve, REACTIVE_CHECK);
|
|
1162
1166
|
}
|
|
@@ -1178,14 +1182,14 @@ function runHeap(e, t) {
|
|
|
1178
1182
|
|
|
1179
1183
|
function adjustHeight(e, t) {
|
|
1180
1184
|
deleteFromHeap(e, t);
|
|
1181
|
-
let n = e.
|
|
1182
|
-
for (let t = e.
|
|
1183
|
-
const e = t.
|
|
1184
|
-
const r = e.
|
|
1185
|
-
if (r.ke && r.
|
|
1186
|
-
}
|
|
1187
|
-
if (e.
|
|
1188
|
-
e.
|
|
1185
|
+
let n = e.Je;
|
|
1186
|
+
for (let t = e.Ye; t; t = t.qe) {
|
|
1187
|
+
const e = t.Be;
|
|
1188
|
+
const r = e.Ze || e;
|
|
1189
|
+
if (r.ke && r.Je >= n) n = r.Je + 1;
|
|
1190
|
+
}
|
|
1191
|
+
if (e.Je !== n) {
|
|
1192
|
+
e.Je = n;
|
|
1189
1193
|
for (let t = e.U; t !== null; t = t.Ge) {
|
|
1190
1194
|
// Route each subscriber by its own zombie flag, mirroring the
|
|
1191
1195
|
// post-recompute height-adjust path. Inserting into the running `heap`
|
|
@@ -1201,7 +1205,7 @@ const PENDING_OWNER = {};
|
|
|
1201
1205
|
|
|
1202
1206
|
// Dummy owner to trigger store's read() path
|
|
1203
1207
|
function markDisposal(e) {
|
|
1204
|
-
let t = e.
|
|
1208
|
+
let t = e.st;
|
|
1205
1209
|
while (t) {
|
|
1206
1210
|
const e = t.D;
|
|
1207
1211
|
t.D = e | REACTIVE_ZOMBIE;
|
|
@@ -1215,17 +1219,21 @@ function markDisposal(e) {
|
|
|
1215
1219
|
if (e & REACTIVE_IN_HEAP) insertIntoHeap(t, zombieQueue); else insertIntoHeapHeight(t, zombieQueue);
|
|
1216
1220
|
}
|
|
1217
1221
|
markDisposal(t);
|
|
1218
|
-
t = t.
|
|
1222
|
+
t = t.ut;
|
|
1219
1223
|
}
|
|
1220
1224
|
}
|
|
1221
1225
|
|
|
1222
1226
|
function dispose(e) {
|
|
1223
|
-
|
|
1227
|
+
// Leave every scheduler heap on disposal (mirrors `unobserved`): a node
|
|
1228
|
+
// still queued here would be recomputed by the next flush, and recompute()
|
|
1229
|
+
// rewriting `_flags` would clear REACTIVE_DISPOSED — resurrecting it (#2983).
|
|
1230
|
+
deleteFromHeap(e, queueFor(e));
|
|
1231
|
+
let t = e.Ye;
|
|
1224
1232
|
while (t !== null) {
|
|
1225
1233
|
t = unlinkSubs(t);
|
|
1226
1234
|
}
|
|
1227
|
-
e.
|
|
1228
|
-
e.
|
|
1235
|
+
e.Ye = null;
|
|
1236
|
+
e.lt = null;
|
|
1229
1237
|
disposeChildren(e, true);
|
|
1230
1238
|
}
|
|
1231
1239
|
|
|
@@ -1242,52 +1250,57 @@ function disposeChildren(e, t = false, n) {
|
|
|
1242
1250
|
const t = e;
|
|
1243
1251
|
if (t._ || t.R) GlobalQueue.Ee(t);
|
|
1244
1252
|
}
|
|
1245
|
-
if (t && e.ke) e.
|
|
1246
|
-
let i = n ? e.
|
|
1253
|
+
if (t && e.ke) e.ct = null;
|
|
1254
|
+
let i = n ? e.Me : e.st;
|
|
1247
1255
|
while (i) {
|
|
1248
|
-
const e = i.
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1256
|
+
const e = i.ut;
|
|
1257
|
+
const t = i;
|
|
1258
|
+
// Heap removal must not be gated on `_deps`: a dependency-free
|
|
1259
|
+
// computation queued by refresh() has a null dep list but still sits in
|
|
1260
|
+
// the dirty heap, and left there the post-disposal flush recomputes it —
|
|
1261
|
+
// recompute() rewriting `_flags` clears REACTIVE_DISPOSED and the node
|
|
1262
|
+
// comes back to life (post-unmount runs, leaked cleanups, #2983).
|
|
1263
|
+
if (t.D & (REACTIVE_IN_HEAP | REACTIVE_IN_HEAP_HEIGHT)) deleteFromHeap(t, queueFor(t));
|
|
1264
|
+
if (t.Ye) {
|
|
1265
|
+
let e = t.Ye;
|
|
1253
1266
|
do {
|
|
1254
|
-
|
|
1255
|
-
} while (
|
|
1256
|
-
|
|
1257
|
-
|
|
1267
|
+
e = unlinkSubs(e);
|
|
1268
|
+
} while (e !== null);
|
|
1269
|
+
t.Ye = null;
|
|
1270
|
+
t.lt = null;
|
|
1258
1271
|
}
|
|
1259
1272
|
disposeChildren(i, true);
|
|
1260
1273
|
i = e;
|
|
1261
1274
|
}
|
|
1262
1275
|
if (n) {
|
|
1263
|
-
e.
|
|
1276
|
+
e.Me = null;
|
|
1264
1277
|
} else {
|
|
1265
|
-
e.
|
|
1266
|
-
e.
|
|
1278
|
+
e.st = null;
|
|
1279
|
+
e.ft = 0;
|
|
1267
1280
|
}
|
|
1268
1281
|
// O(1) splice out of parent's chain on individual dispose. Skipped during
|
|
1269
1282
|
// batch dispose (parent already disposed) and zombie disposal (node sits on
|
|
1270
1283
|
// parent's _pendingFirstChild). We leave node._nextSibling intact so outer
|
|
1271
1284
|
// walks that already advanced past us still reach later siblings.
|
|
1272
1285
|
if (t && !n && !(r & REACTIVE_ZOMBIE) && e.Z !== null && !(e.Z.D & REACTIVE_DISPOSED)) {
|
|
1273
|
-
const t = e.
|
|
1274
|
-
const n = e.
|
|
1275
|
-
if (t !== null) t.
|
|
1276
|
-
if (n !== null) n.
|
|
1277
|
-
e.
|
|
1286
|
+
const t = e.Et;
|
|
1287
|
+
const n = e.ut;
|
|
1288
|
+
if (t !== null) t.ut = n; else e.Z.st = n;
|
|
1289
|
+
if (n !== null) n.Et = t;
|
|
1290
|
+
e.Et = null;
|
|
1278
1291
|
}
|
|
1279
1292
|
runDisposal(e, n);
|
|
1280
1293
|
// Final effect-returned cleanup fires at true disposal, after `_disposal`
|
|
1281
1294
|
// to mirror rerun ordering (compute-phase teardown first, cleanup last).
|
|
1282
|
-
if (t && e.
|
|
1283
|
-
const t = e.
|
|
1284
|
-
e.
|
|
1295
|
+
if (t && e.dt) {
|
|
1296
|
+
const t = e.dt;
|
|
1297
|
+
e.dt = undefined;
|
|
1285
1298
|
t();
|
|
1286
1299
|
}
|
|
1287
1300
|
}
|
|
1288
1301
|
|
|
1289
1302
|
function runDisposal(e, t) {
|
|
1290
|
-
let n = t ? e
|
|
1303
|
+
let n = t ? e.$e : e.St;
|
|
1291
1304
|
if (!n) return;
|
|
1292
1305
|
if (Array.isArray(n)) {
|
|
1293
1306
|
for (let e = 0; e < n.length; e++) {
|
|
@@ -1297,13 +1310,13 @@ function runDisposal(e, t) {
|
|
|
1297
1310
|
} else {
|
|
1298
1311
|
n.call(n);
|
|
1299
1312
|
}
|
|
1300
|
-
t ? e
|
|
1313
|
+
t ? e.$e = null : e.St = null;
|
|
1301
1314
|
}
|
|
1302
1315
|
|
|
1303
1316
|
function childId(e, t) {
|
|
1304
1317
|
let n = e;
|
|
1305
1318
|
while (n.Ue & CONFIG_TRANSPARENT && n.Z) n = n.Z;
|
|
1306
|
-
if (n.id != null) return formatId(n.id, t ? n.
|
|
1319
|
+
if (n.id != null) return formatId(n.id, t ? n.ft++ : n.ft);
|
|
1307
1320
|
throw new Error("");
|
|
1308
1321
|
}
|
|
1309
1322
|
|
|
@@ -1384,7 +1397,7 @@ function formatId(e, t) {
|
|
|
1384
1397
|
* checks. `cleanup()` is the unchecked primitive used by internals.
|
|
1385
1398
|
*/ function cleanup(e) {
|
|
1386
1399
|
if (!context) return e;
|
|
1387
|
-
if (!context.
|
|
1400
|
+
if (!context.St) context.St = e; else if (Array.isArray(context.St)) context.St.push(e); else context.St = [ context.St, e ];
|
|
1388
1401
|
return e;
|
|
1389
1402
|
}
|
|
1390
1403
|
|
|
@@ -1424,28 +1437,28 @@ function disposeRootSelf(e = true) {
|
|
|
1424
1437
|
const r = {
|
|
1425
1438
|
id: inheritId(e, n, t),
|
|
1426
1439
|
Ue: n ? CONFIG_TRANSPARENT : 0,
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
ot: null,
|
|
1440
|
+
et: true,
|
|
1441
|
+
tt: t?.et ? t.tt : t,
|
|
1430
1442
|
st: null,
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1443
|
+
ut: null,
|
|
1444
|
+
Et: null,
|
|
1445
|
+
St: null,
|
|
1446
|
+
Xe: t?.Xe ?? globalQueue,
|
|
1447
|
+
Tt: t?.Tt || defaultContext,
|
|
1448
|
+
ft: 0,
|
|
1449
|
+
$e: null,
|
|
1436
1450
|
Me: null,
|
|
1437
|
-
He: null,
|
|
1438
1451
|
Z: t,
|
|
1439
1452
|
dispose: disposeRootSelf
|
|
1440
1453
|
};
|
|
1441
1454
|
if (t) {
|
|
1442
|
-
const e = t.
|
|
1455
|
+
const e = t.st;
|
|
1443
1456
|
if (e === null) {
|
|
1444
|
-
t.
|
|
1457
|
+
t.st = r;
|
|
1445
1458
|
} else {
|
|
1446
|
-
r.
|
|
1447
|
-
e.
|
|
1448
|
-
t.
|
|
1459
|
+
r.ut = e;
|
|
1460
|
+
e.Et = r;
|
|
1461
|
+
t.st = r;
|
|
1449
1462
|
}
|
|
1450
1463
|
}
|
|
1451
1464
|
return r;
|
|
@@ -1481,11 +1494,11 @@ function disposeRootSelf(e = true) {
|
|
|
1481
1494
|
|
|
1482
1495
|
// https://github.com/stackblitz/alien-signals/blob/v2.0.3/src/system.ts#L100
|
|
1483
1496
|
function unlinkSubs(e) {
|
|
1484
|
-
const t = e.
|
|
1485
|
-
const n = e.
|
|
1497
|
+
const t = e.Be;
|
|
1498
|
+
const n = e.qe;
|
|
1486
1499
|
const r = e.Ge;
|
|
1487
|
-
const i = e.
|
|
1488
|
-
if (r !== null) r.
|
|
1500
|
+
const i = e.Ot;
|
|
1501
|
+
if (r !== null) r.Ot = i; else t._t = i;
|
|
1489
1502
|
if (i !== null) i.Ge = r; else {
|
|
1490
1503
|
t.U = r;
|
|
1491
1504
|
if (r === null) {
|
|
@@ -1497,31 +1510,31 @@ function unlinkSubs(e) {
|
|
|
1497
1510
|
// this same last-one-out check when that observer releases (the
|
|
1498
1511
|
// untracked-read dispose in core.ts guards on pending identically).
|
|
1499
1512
|
const e = t;
|
|
1500
|
-
e.ke && e.Ue & CONFIG_AUTO_DISPOSE && !(e.D & REACTIVE_ZOMBIE) && !(e.
|
|
1513
|
+
e.ke && e.Ue & CONFIG_AUTO_DISPOSE && !(e.D & REACTIVE_ZOMBIE) && !(e.He & STATUS_PENDING) && unobserved(e);
|
|
1501
1514
|
}
|
|
1502
1515
|
}
|
|
1503
1516
|
return n;
|
|
1504
1517
|
}
|
|
1505
1518
|
|
|
1506
1519
|
function trimStaleDeps(e) {
|
|
1507
|
-
const t = e.
|
|
1508
|
-
let n = t !== null ? t.
|
|
1520
|
+
const t = e.lt;
|
|
1521
|
+
let n = t !== null ? t.qe : e.Ye;
|
|
1509
1522
|
if (n !== null) {
|
|
1510
1523
|
do {
|
|
1511
1524
|
n = unlinkSubs(n);
|
|
1512
1525
|
} while (n !== null);
|
|
1513
|
-
if (t !== null) t.
|
|
1526
|
+
if (t !== null) t.qe = null; else e.Ye = null;
|
|
1514
1527
|
}
|
|
1515
1528
|
}
|
|
1516
1529
|
|
|
1517
1530
|
function unobserved(e) {
|
|
1518
1531
|
deleteFromHeap(e, queueFor(e));
|
|
1519
|
-
let t = e.
|
|
1532
|
+
let t = e.Ye;
|
|
1520
1533
|
while (t !== null) {
|
|
1521
1534
|
t = unlinkSubs(t);
|
|
1522
1535
|
}
|
|
1523
|
-
e.
|
|
1524
|
-
e.
|
|
1536
|
+
e.Ye = null;
|
|
1537
|
+
e.lt = null;
|
|
1525
1538
|
disposeChildren(e, true);
|
|
1526
1539
|
}
|
|
1527
1540
|
|
|
@@ -1532,20 +1545,20 @@ function link(e, t, n = false) {
|
|
|
1532
1545
|
// not relabel the value dependency as probe-only — the value read is what
|
|
1533
1546
|
// real-error propagation and affects() coverage key off, regardless of
|
|
1534
1547
|
// read order within the computation.
|
|
1535
|
-
const r = t.
|
|
1536
|
-
if (r !== null && r.
|
|
1537
|
-
r.
|
|
1548
|
+
const r = t.lt;
|
|
1549
|
+
if (r !== null && r.Be === e) {
|
|
1550
|
+
r.Rt &&= n;
|
|
1538
1551
|
return;
|
|
1539
1552
|
}
|
|
1540
1553
|
let i = null;
|
|
1541
1554
|
const o = t.D & REACTIVE_RECOMPUTING_DEPS;
|
|
1542
1555
|
if (o) {
|
|
1543
|
-
i = r !== null ? r.
|
|
1544
|
-
if (i !== null && i.
|
|
1545
|
-
i.
|
|
1546
|
-
t.
|
|
1556
|
+
i = r !== null ? r.qe : t.Ye;
|
|
1557
|
+
if (i !== null && i.Be === e) {
|
|
1558
|
+
i.It = t.At;
|
|
1559
|
+
t.lt = i;
|
|
1547
1560
|
// First touch of this pass: the previous pass's label is stale.
|
|
1548
|
-
i.
|
|
1561
|
+
i.Rt = n;
|
|
1549
1562
|
return;
|
|
1550
1563
|
}
|
|
1551
1564
|
}
|
|
@@ -1554,23 +1567,23 @@ function link(e, t, n = false) {
|
|
|
1554
1567
|
// [deps.._depsTail] prefix — the O(1) equivalent of scanning the dep list
|
|
1555
1568
|
// (the old alien-signals `isValidLink` walk, O(n²) when a computation
|
|
1556
1569
|
// re-reads earlier deps non-consecutively, e.g. store leaf reads).
|
|
1557
|
-
const s = e.
|
|
1558
|
-
if (s !== null && s.Ve === t && (!o || s.
|
|
1570
|
+
const s = e._t;
|
|
1571
|
+
if (s !== null && s.Ve === t && (!o || s.It === t.At)) {
|
|
1559
1572
|
// Gen-matched during a recompute = repeat touch this pass (AND); outside
|
|
1560
1573
|
// a recompute there is no pass boundary, so the latest read labels it.
|
|
1561
|
-
if (o) s.
|
|
1574
|
+
if (o) s.Rt &&= n; else s.Rt = n;
|
|
1562
1575
|
return;
|
|
1563
1576
|
}
|
|
1564
|
-
const u = t.
|
|
1565
|
-
|
|
1577
|
+
const u = t.lt = e._t = {
|
|
1578
|
+
Be: e,
|
|
1566
1579
|
Ve: t,
|
|
1567
|
-
|
|
1568
|
-
|
|
1580
|
+
qe: i,
|
|
1581
|
+
Ot: s,
|
|
1569
1582
|
Ge: null,
|
|
1570
|
-
|
|
1571
|
-
|
|
1583
|
+
It: t.At,
|
|
1584
|
+
Rt: n
|
|
1572
1585
|
};
|
|
1573
|
-
if (r !== null) r.
|
|
1586
|
+
if (r !== null) r.qe = u; else t.Ye = u;
|
|
1574
1587
|
if (s !== null) s.Ge = u; else e.U = u;
|
|
1575
1588
|
}
|
|
1576
1589
|
|
|
@@ -1580,20 +1593,36 @@ function link(e, t, n = false) {
|
|
|
1580
1593
|
// overlapping source landed beside the Set and removePendingSource refused
|
|
1581
1594
|
// to clear it, stranding the Set members' pending forever (#2893).
|
|
1582
1595
|
function addPendingSource(e, t) {
|
|
1583
|
-
if (e.
|
|
1584
|
-
(e.
|
|
1596
|
+
if (e.Ke?.has(t)) return false;
|
|
1597
|
+
(e.Ke ??= new Set).add(t);
|
|
1585
1598
|
return true;
|
|
1586
1599
|
}
|
|
1587
1600
|
|
|
1588
1601
|
function removePendingSource(e, t) {
|
|
1589
|
-
if (!e.
|
|
1590
|
-
if (e.
|
|
1602
|
+
if (!e.Ke?.delete(t)) return false;
|
|
1603
|
+
if (e.Ke.size === 0) e.Ke = undefined;
|
|
1591
1604
|
return true;
|
|
1592
1605
|
}
|
|
1593
1606
|
|
|
1594
1607
|
function clearPendingSources(e) {
|
|
1595
|
-
e.
|
|
1596
|
-
e.
|
|
1608
|
+
e.Ke?.clear();
|
|
1609
|
+
e.Ke = undefined;
|
|
1610
|
+
}
|
|
1611
|
+
|
|
1612
|
+
/**
|
|
1613
|
+
* A loading-window node hit an unready source (sync throw in recompute, or a
|
|
1614
|
+
* NotReadyError-rejected flight): register for the source's settle — the
|
|
1615
|
+
* settlePendingSource walk runs off `_pendingSources` + `_blocked` alone —
|
|
1616
|
+
* with NO read-visible pending status, no downstream propagation, no
|
|
1617
|
+
* transition, no lane registration. Commit #0 keeps serving.
|
|
1618
|
+
*/ function parkLoadingWindow(e, t) {
|
|
1619
|
+
e.ht = true;
|
|
1620
|
+
if (t.source) addPendingSource(e, t.source);
|
|
1621
|
+
// A settled error is the node's answer ("the error stays the answer until
|
|
1622
|
+
// this retry can actually run") — the park must not replace it: reads
|
|
1623
|
+
// throw `_error` while STATUS_ERROR is set, and overwriting it here leaks
|
|
1624
|
+
// a pending-class NotReadyError from a read-invisible park (#2989).
|
|
1625
|
+
if (!(e.He & STATUS_ERROR)) setPendingError(e, t.source, t);
|
|
1597
1626
|
}
|
|
1598
1627
|
|
|
1599
1628
|
function setPendingError(e, t, n) {
|
|
@@ -1614,7 +1643,7 @@ function setPendingError(e, t, n) {
|
|
|
1614
1643
|
function forEachDependent(e, t) {
|
|
1615
1644
|
for (let n = e.U; n !== null; n = n.Ge) t(n.Ve, n);
|
|
1616
1645
|
// `?? null`: affects() marks route plain signals (no `_child` slot) through here.
|
|
1617
|
-
for (let n = e.
|
|
1646
|
+
for (let n = e.it ?? null; n !== null; n = n.ot) {
|
|
1618
1647
|
for (let e = n.U; e !== null; e = e.Ge) t(e.Ve, e);
|
|
1619
1648
|
}
|
|
1620
1649
|
}
|
|
@@ -1630,7 +1659,7 @@ function forEachDependent(e, t) {
|
|
|
1630
1659
|
// callbacks handle their own release (settleAutodispose in handleAsync); this
|
|
1631
1660
|
// covers derivatively-pending dependents, which have no callbacks of their own.
|
|
1632
1661
|
function releaseIfSettledUnobserved(e) {
|
|
1633
|
-
e.ke && e.Ue & CONFIG_AUTO_DISPOSE && !e.U && !(e.D & REACTIVE_ZOMBIE) && !(e.
|
|
1662
|
+
e.ke && e.Ue & CONFIG_AUTO_DISPOSE && !e.U && !(e.D & REACTIVE_ZOMBIE) && !(e.He & STATUS_PENDING) && unobserved(e);
|
|
1634
1663
|
}
|
|
1635
1664
|
|
|
1636
1665
|
// Error-path sweep: notifyStatus(STATUS_ERROR) clears dependents' pending
|
|
@@ -1691,19 +1720,25 @@ function settlePendingSource(e) {
|
|
|
1691
1720
|
if (r.has(o) || !removePendingSource(o, e)) return;
|
|
1692
1721
|
r.add(o);
|
|
1693
1722
|
o.H = clock;
|
|
1694
|
-
const s = o.
|
|
1723
|
+
const s = o.Ke?.values().next().value;
|
|
1724
|
+
// STATUS_ERROR + pending sources only coexist via an errored loading
|
|
1725
|
+
// window's park (notifyStatus(STATUS_ERROR) clears pending sources
|
|
1726
|
+
// otherwise): the settled error stays the answer through the settle —
|
|
1727
|
+
// nulling it here would have reads throw `null` until the re-enqueued
|
|
1728
|
+
// retry lands, or lose it entirely if that retry parks again (#2989).
|
|
1729
|
+
const u = o.He & STATUS_ERROR;
|
|
1695
1730
|
if (s) {
|
|
1696
|
-
setPendingError(o, s);
|
|
1731
|
+
if (!u) setPendingError(o, s);
|
|
1697
1732
|
i !== null && i(o);
|
|
1698
1733
|
} else {
|
|
1699
|
-
o.
|
|
1700
|
-
setPendingError(o);
|
|
1734
|
+
o.He &= ~STATUS_PENDING;
|
|
1735
|
+
if (!u) setPendingError(o);
|
|
1701
1736
|
i !== null && i(o);
|
|
1702
|
-
if (o.
|
|
1737
|
+
if (o.ht) {
|
|
1703
1738
|
enqueueSub(o);
|
|
1704
1739
|
t = true;
|
|
1705
1740
|
}
|
|
1706
|
-
o.
|
|
1741
|
+
o.ht = false;
|
|
1707
1742
|
// Fully settled with nobody watching: release candidate (#2934). Checked
|
|
1708
1743
|
// again at release time — deferred so unobserved() can't unlink subs
|
|
1709
1744
|
// lists this walk is still iterating.
|
|
@@ -1733,10 +1768,12 @@ function handleAsync(e, t, n) {
|
|
|
1733
1768
|
});
|
|
1734
1769
|
}
|
|
1735
1770
|
if (!i && !r) {
|
|
1736
|
-
e.
|
|
1771
|
+
e.ct = null;
|
|
1772
|
+
// A sync landing is the first real answer for a loadingValue node.
|
|
1773
|
+
e.xe = false;
|
|
1737
1774
|
return t;
|
|
1738
1775
|
}
|
|
1739
|
-
e.
|
|
1776
|
+
e.ct = t;
|
|
1740
1777
|
let o;
|
|
1741
1778
|
// Settle-time transition re-entry. The loading rail is invisible to
|
|
1742
1779
|
// transactions (#2933): a boundary-caught first load never registers as an
|
|
@@ -1750,7 +1787,7 @@ function handleAsync(e, t, n) {
|
|
|
1750
1787
|
// are the transaction's reveal machinery and always re-enter.
|
|
1751
1788
|
const settleTransition = () => {
|
|
1752
1789
|
const t = resolveTransition(e);
|
|
1753
|
-
if (t && e.
|
|
1790
|
+
if (t && e.He & STATUS_UNINITIALIZED && !currentTransition(t).$.has(e)) {
|
|
1754
1791
|
// Drop the stale stamp too: the plain settle write (setSignal) and the
|
|
1755
1792
|
// stash-path restamp both re-enter the transaction through it.
|
|
1756
1793
|
e.T = null;
|
|
@@ -1759,10 +1796,20 @@ function handleAsync(e, t, n) {
|
|
|
1759
1796
|
globalQueue.initTransition(t);
|
|
1760
1797
|
};
|
|
1761
1798
|
const handleError = n => {
|
|
1762
|
-
if (e.
|
|
1763
|
-
settleTransition();
|
|
1799
|
+
if (e.ct !== t) return;
|
|
1764
1800
|
// NotReadyError from rejected promises should be treated as pending, not error
|
|
1765
|
-
|
|
1801
|
+
let r = n instanceof NotReadyError;
|
|
1802
|
+
if (r && e.xe) {
|
|
1803
|
+
// Loading window: the flight died waiting on an unready source. Keep
|
|
1804
|
+
// serving commit #0 — same parking as recompute's catch for sync
|
|
1805
|
+
// dependency throws. The dead flight is released so the clock-gated
|
|
1806
|
+
// error-retry pull (updateIfNecessary) can also re-ask.
|
|
1807
|
+
e.ct = null;
|
|
1808
|
+
parkLoadingWindow(e, n);
|
|
1809
|
+
e.H = clock;
|
|
1810
|
+
return;
|
|
1811
|
+
}
|
|
1812
|
+
settleTransition();
|
|
1766
1813
|
notifyStatus(e, r ? STATUS_PENDING : STATUS_ERROR, n);
|
|
1767
1814
|
e.H = clock;
|
|
1768
1815
|
// A real error settles derivatively-pending dependents (notifyStatus
|
|
@@ -1771,13 +1818,13 @@ function handleAsync(e, t, n) {
|
|
|
1771
1818
|
if (!r) releaseSettledDependents(e);
|
|
1772
1819
|
};
|
|
1773
1820
|
const asyncWrite = (r, i) => {
|
|
1774
|
-
if (e.
|
|
1821
|
+
if (e.ct !== t) return;
|
|
1775
1822
|
// If the node was dirtied by a newer write (optimistic override or regular),
|
|
1776
1823
|
// skip this stale async result — the upcoming flush will recompute the node
|
|
1777
1824
|
// with the new value, creating a fresh Promise that supersedes this one.
|
|
1778
1825
|
if (e.D & (REACTIVE_DIRTY | REACTIVE_OPTIMISTIC_DIRTY)) return;
|
|
1779
1826
|
settleTransition();
|
|
1780
|
-
const o = !!(e.
|
|
1827
|
+
const o = !!(e.He & STATUS_UNINITIALIZED);
|
|
1781
1828
|
trimStaleDeps(e);
|
|
1782
1829
|
clearStatus(e);
|
|
1783
1830
|
const s = resolveLane(e);
|
|
@@ -1811,7 +1858,7 @@ function handleAsync(e, t, n) {
|
|
|
1811
1858
|
// Route through lane's effect queue for independent flushing
|
|
1812
1859
|
const t = e.Fe;
|
|
1813
1860
|
const n = e.We;
|
|
1814
|
-
const i = e.
|
|
1861
|
+
const i = e.Nt;
|
|
1815
1862
|
try {
|
|
1816
1863
|
if (!t && o || !i || !i(r, n)) {
|
|
1817
1864
|
e.We = r;
|
|
@@ -1838,6 +1885,13 @@ function handleAsync(e, t, n) {
|
|
|
1838
1885
|
notifyStatus(e, STATUS_ERROR, t);
|
|
1839
1886
|
}
|
|
1840
1887
|
}
|
|
1888
|
+
// First real answer landing: the window closes when the answer becomes
|
|
1889
|
+
// OBSERVABLE. A direct commit is observable now; a transition-held write
|
|
1890
|
+
// (`_pendingValue` set above or inside setSignal) is not — the verdict's
|
|
1891
|
+
// held-value branch is window-gated, and commitPendingNode closes the
|
|
1892
|
+
// window when the hold commits, so no one-frame isPending pulse can leak
|
|
1893
|
+
// to live observers between the landing and its commit (#2990).
|
|
1894
|
+
if (e.k === NOT_PENDING) e.xe = false;
|
|
1841
1895
|
settlePendingSource(e);
|
|
1842
1896
|
schedule();
|
|
1843
1897
|
flush();
|
|
@@ -1851,7 +1905,7 @@ function handleAsync(e, t, n) {
|
|
|
1851
1905
|
// Returns whether the node released, so the iterator branch can stop
|
|
1852
1906
|
// pulling values instead of pumping an unobserved stream forever (#2935).
|
|
1853
1907
|
const settleAutodispose = () => {
|
|
1854
|
-
if (e.Ue & CONFIG_AUTO_DISPOSE && !e.U && !(e.
|
|
1908
|
+
if (e.Ue & CONFIG_AUTO_DISPOSE && !e.U && !(e.He & STATUS_PENDING)) {
|
|
1855
1909
|
unobserved(e);
|
|
1856
1910
|
return true;
|
|
1857
1911
|
}
|
|
@@ -1884,8 +1938,16 @@ function handleAsync(e, t, n) {
|
|
|
1884
1938
|
handleError(i);
|
|
1885
1939
|
throw i;
|
|
1886
1940
|
} else if (!n) {
|
|
1941
|
+
// Loading window: serve commit #0 instead of suspending. No transition
|
|
1942
|
+
// is opened — first-flight work on a loadingValue node is loading-class
|
|
1943
|
+
// (invisible to boundaries and transitions); the flight itself is
|
|
1944
|
+
// already registered in _inFlight and lands through asyncWrite.
|
|
1945
|
+
if (e.xe) return e.We;
|
|
1887
1946
|
globalQueue.initTransition(resolveTransition(e));
|
|
1888
1947
|
throw new NotReadyError(context);
|
|
1948
|
+
} else {
|
|
1949
|
+
// Synchronously-resolved promise: the first real answer landed.
|
|
1950
|
+
e.xe = false;
|
|
1889
1951
|
}
|
|
1890
1952
|
}
|
|
1891
1953
|
if (r) {
|
|
@@ -1909,12 +1971,27 @@ function handleAsync(e, t, n) {
|
|
|
1909
1971
|
};
|
|
1910
1972
|
const iterate = () => {
|
|
1911
1973
|
let u, l, a = false, c = false, f = true;
|
|
1912
|
-
|
|
1913
|
-
|
|
1974
|
+
// Protocol tolerance, matching `for await`: `await` unwraps whatever
|
|
1975
|
+
// next() returns — a thenable OR a bare IteratorResult. Real producers
|
|
1976
|
+
// use the bare form as a promise-free fast path when a value is already
|
|
1977
|
+
// buffered (seroval's deserialized streams do), so a bare result is
|
|
1978
|
+
// assimilated as an already-settled step instead of crashing on `.then`.
|
|
1979
|
+
const E = n.next();
|
|
1980
|
+
const d = isThenable(E) ? E : {
|
|
1981
|
+
then: e => void e(E)
|
|
1982
|
+
};
|
|
1983
|
+
d.then(n => {
|
|
1984
|
+
// The sync stash only serves the INITIAL drain (handleAsync's caller
|
|
1985
|
+
// consumes syncValue / throws NotReady from it). A sync-settled step
|
|
1986
|
+
// after an async gap — seroval buffering values between pulls, a
|
|
1987
|
+
// sync-thenable producer mid-stream — has no caller reading the
|
|
1988
|
+
// stash: it must write through the async path or the value is
|
|
1989
|
+
// silently dropped.
|
|
1990
|
+
if (f && s) {
|
|
1914
1991
|
u = n;
|
|
1915
1992
|
a = true;
|
|
1916
1993
|
if (n.done) i = true;
|
|
1917
|
-
} else if (e.
|
|
1994
|
+
} else if (e.ct !== t) {
|
|
1918
1995
|
return;
|
|
1919
1996
|
} else if (!n.done) {
|
|
1920
1997
|
r = true;
|
|
@@ -1934,7 +2011,7 @@ function handleAsync(e, t, n) {
|
|
|
1934
2011
|
if (f) {
|
|
1935
2012
|
l = n;
|
|
1936
2013
|
c = true;
|
|
1937
|
-
} else if (e.
|
|
2014
|
+
} else if (e.ct === t) {
|
|
1938
2015
|
i = true;
|
|
1939
2016
|
handleError(n);
|
|
1940
2017
|
settleAutodispose();
|
|
@@ -1959,26 +2036,31 @@ function handleAsync(e, t, n) {
|
|
|
1959
2036
|
// Later iterate() calls run from asyncWrite, where rethrowing would be unhandled.
|
|
1960
2037
|
s = false;
|
|
1961
2038
|
if (!r && !u) {
|
|
2039
|
+
// Loading window: serve commit #0 (see the promise branch above).
|
|
2040
|
+
if (e.xe) return e.We;
|
|
1962
2041
|
globalQueue.initTransition(resolveTransition(e));
|
|
1963
2042
|
throw new NotReadyError(context);
|
|
1964
2043
|
}
|
|
2044
|
+
// A sync first yield (or immediate empty completion) is the first real
|
|
2045
|
+
// answer; async yields clear inside asyncWrite.
|
|
2046
|
+
e.xe = false;
|
|
1965
2047
|
}
|
|
1966
2048
|
return o;
|
|
1967
2049
|
}
|
|
1968
2050
|
|
|
1969
2051
|
function clearStatus(e, t = false) {
|
|
1970
|
-
if (e.
|
|
1971
|
-
if (e.
|
|
2052
|
+
if (e.Ke) clearPendingSources(e);
|
|
2053
|
+
if (e.ht) e.ht = false;
|
|
1972
2054
|
// The pending window is over; its quiet classification dies with it.
|
|
1973
2055
|
// (Unconditional: _reask is baked into the node literals, so this is a
|
|
1974
2056
|
// plain store to an existing slot — no shape change.)
|
|
1975
|
-
e.
|
|
1976
|
-
e.
|
|
2057
|
+
e.Pt = false;
|
|
2058
|
+
e.He = t ? 0 : e.He & STATUS_UNINITIALIZED;
|
|
1977
2059
|
if (e.me) setPendingError(e);
|
|
1978
2060
|
// Update pending signal for isPending() reactivity (companions only exist
|
|
1979
2061
|
// once the verdict layer created them, which installs the hooks).
|
|
1980
2062
|
if (e._ || e.R) GlobalQueue.ce(e);
|
|
1981
|
-
if (e.
|
|
2063
|
+
if (e.it && GlobalQueue.fe !== null) GlobalQueue.fe(e);
|
|
1982
2064
|
if (e.yt) e.yt();
|
|
1983
2065
|
}
|
|
1984
2066
|
|
|
@@ -1992,17 +2074,17 @@ function notifyStatus(e, t, n, r, i) {
|
|
|
1992
2074
|
if (!r) {
|
|
1993
2075
|
if (t === STATUS_PENDING && o) {
|
|
1994
2076
|
addPendingSource(e, o);
|
|
1995
|
-
e.
|
|
2077
|
+
e.He = STATUS_PENDING | e.He & STATUS_UNINITIALIZED;
|
|
1996
2078
|
// Preserve the current source on this propagation so render-effect notification
|
|
1997
2079
|
// can register every distinct pending source with the transition.
|
|
1998
2080
|
setPendingError(e, o, n);
|
|
1999
2081
|
} else {
|
|
2000
2082
|
clearPendingSources(e);
|
|
2001
|
-
e.
|
|
2083
|
+
e.He = t | (t !== STATUS_ERROR ? e.He & STATUS_UNINITIALIZED : 0);
|
|
2002
2084
|
e.me = n;
|
|
2003
2085
|
}
|
|
2004
2086
|
GlobalQueue.ce !== null && GlobalQueue.ce(e);
|
|
2005
|
-
if (e.
|
|
2087
|
+
if (e.it && GlobalQueue.fe !== null) GlobalQueue.fe(e);
|
|
2006
2088
|
}
|
|
2007
2089
|
if (i && !r) {
|
|
2008
2090
|
assignOrMergeLane(e, i);
|
|
@@ -2022,13 +2104,13 @@ function notifyStatus(e, t, n, r, i) {
|
|
|
2022
2104
|
}
|
|
2023
2105
|
forEachDependent(e, (e, r) => {
|
|
2024
2106
|
e.H = clock;
|
|
2025
|
-
if (t === STATUS_PENDING && o && !e.
|
|
2107
|
+
if (t === STATUS_PENDING && o && !e.Ke?.has(o) || t !== STATUS_PENDING && (e.me !== n || e.Ke)) {
|
|
2026
2108
|
// A pending-observer link is the subscription an `isPending` read created.
|
|
2027
2109
|
// It exists so the observer re-runs when the source settles, but it must
|
|
2028
2110
|
// not carry a real (non-NotReadyError) error — the synchronous `isPending`
|
|
2029
2111
|
// read swallows those, and the async path must match. Re-run the observer
|
|
2030
2112
|
// so `isPending` re-evaluates (to not-pending) instead of forwarding.
|
|
2031
|
-
if (r.
|
|
2113
|
+
if (r.Rt && t !== STATUS_PENDING && !(n instanceof NotReadyError)) {
|
|
2032
2114
|
enqueueSub(e);
|
|
2033
2115
|
schedule();
|
|
2034
2116
|
return;
|
|
@@ -2073,7 +2155,7 @@ let snapshotSources = null;
|
|
|
2073
2155
|
|
|
2074
2156
|
function ownerInSnapshotScope(e) {
|
|
2075
2157
|
while (e) {
|
|
2076
|
-
if (e.
|
|
2158
|
+
if (e.Ct) return true;
|
|
2077
2159
|
e = e.Z;
|
|
2078
2160
|
}
|
|
2079
2161
|
return false;
|
|
@@ -2085,20 +2167,20 @@ function setSnapshotCapture(e) {
|
|
|
2085
2167
|
}
|
|
2086
2168
|
|
|
2087
2169
|
function markSnapshotScope(e) {
|
|
2088
|
-
e.
|
|
2170
|
+
e.Ct = true;
|
|
2089
2171
|
}
|
|
2090
2172
|
|
|
2091
2173
|
function releaseSnapshotScope(e) {
|
|
2092
|
-
e.
|
|
2174
|
+
e.Ct = false;
|
|
2093
2175
|
releaseSubtree(e);
|
|
2094
2176
|
schedule();
|
|
2095
2177
|
}
|
|
2096
2178
|
|
|
2097
2179
|
function releaseSubtree(e) {
|
|
2098
|
-
let t = e.
|
|
2180
|
+
let t = e.st;
|
|
2099
2181
|
while (t) {
|
|
2100
|
-
if (t.
|
|
2101
|
-
t = t.
|
|
2182
|
+
if (t.Ct) {
|
|
2183
|
+
t = t.ut;
|
|
2102
2184
|
continue;
|
|
2103
2185
|
}
|
|
2104
2186
|
if (t.ke) {
|
|
@@ -2107,12 +2189,12 @@ function releaseSubtree(e) {
|
|
|
2107
2189
|
if (e.D & REACTIVE_SNAPSHOT_STALE) {
|
|
2108
2190
|
e.D &= ~REACTIVE_SNAPSHOT_STALE;
|
|
2109
2191
|
e.D |= REACTIVE_DIRTY;
|
|
2110
|
-
if (dirtyQueue.P > e.
|
|
2192
|
+
if (dirtyQueue.P > e.Je) dirtyQueue.P = e.Je;
|
|
2111
2193
|
insertIntoHeap(e, dirtyQueue);
|
|
2112
2194
|
}
|
|
2113
2195
|
}
|
|
2114
2196
|
releaseSubtree(t);
|
|
2115
|
-
t = t.
|
|
2197
|
+
t = t.ut;
|
|
2116
2198
|
}
|
|
2117
2199
|
}
|
|
2118
2200
|
|
|
@@ -2135,37 +2217,42 @@ function recompute(e, t = false) {
|
|
|
2135
2217
|
if (!t) {
|
|
2136
2218
|
if (e.T && (!n || activeTransition) && activeTransition !== e.T) globalQueue.initTransition(e.T);
|
|
2137
2219
|
deleteFromHeap(e, queueFor(e));
|
|
2138
|
-
e.
|
|
2220
|
+
e.ct = null;
|
|
2139
2221
|
// Tracked effects run after finalizePureQueue, so dispose immediately instead of deferring
|
|
2140
|
-
if (e.T || n === EFFECT_TRACKED) disposeChildren(e); else if (e.
|
|
2222
|
+
if (e.T || n === EFFECT_TRACKED) disposeChildren(e); else if (e.st !== null || e.St !== null) {
|
|
2141
2223
|
markDisposal(e);
|
|
2142
|
-
e
|
|
2143
|
-
e.
|
|
2144
|
-
e.
|
|
2145
|
-
e.
|
|
2146
|
-
e.
|
|
2224
|
+
e.$e = e.St;
|
|
2225
|
+
e.Me = e.st;
|
|
2226
|
+
e.St = null;
|
|
2227
|
+
e.st = null;
|
|
2228
|
+
e.ft = 0;
|
|
2147
2229
|
} else ;
|
|
2148
2230
|
}
|
|
2149
2231
|
let r = !!(e.D & REACTIVE_OPTIMISTIC_DIRTY);
|
|
2150
2232
|
const i = e.A !== undefined && e.A !== NOT_PENDING;
|
|
2151
|
-
const o = !!(e.
|
|
2233
|
+
const o = !!(e.He & STATUS_UNINITIALIZED);
|
|
2152
2234
|
// Outgoing error, captured before the compute clears status: if this run
|
|
2153
2235
|
// recovers to an unchanged value, dependents still holding this object must
|
|
2154
2236
|
// be swept (settleErroredDependents, #2949).
|
|
2155
|
-
const s = e.
|
|
2237
|
+
const s = e.He & STATUS_ERROR ? e.me : undefined;
|
|
2156
2238
|
// Re-ask classification lives in the verdict module; capture the flag before
|
|
2157
2239
|
// the recompute wipes _flags below.
|
|
2158
2240
|
const u = (e.D & REACTIVE_REASK) !== 0;
|
|
2159
|
-
|
|
2241
|
+
// Captured before the compute clears it on a sync landing: if that landing
|
|
2242
|
+
// is transition-held below, the window must stay open until the hold
|
|
2243
|
+
// commits (commitPendingNode) — a closed window plus a held value reads as
|
|
2244
|
+
// a pending frame to live observers of the verdict (#2990).
|
|
2245
|
+
const l = e.xe;
|
|
2246
|
+
const a = context;
|
|
2160
2247
|
context = e;
|
|
2161
|
-
e.
|
|
2162
|
-
e.
|
|
2248
|
+
e.lt = null;
|
|
2249
|
+
e.At++;
|
|
2163
2250
|
e.D = REACTIVE_RECOMPUTING_DEPS;
|
|
2164
2251
|
e.H = clock;
|
|
2165
|
-
let
|
|
2166
|
-
let
|
|
2167
|
-
let
|
|
2168
|
-
let
|
|
2252
|
+
let c = e.k === NOT_PENDING ? e.We : e.k;
|
|
2253
|
+
let f = e.Je;
|
|
2254
|
+
let E = tracking;
|
|
2255
|
+
let d = currentOptimisticLane;
|
|
2169
2256
|
tracking = true;
|
|
2170
2257
|
// A computed's fn establishes its OWN dependencies, so it must never run
|
|
2171
2258
|
// inside a latest() read window: read() short-circuits through the
|
|
@@ -2173,7 +2260,7 @@ function recompute(e, t = false) {
|
|
|
2173
2260
|
// computed) inside latest(fn) came out permanently dependency-less (#2926).
|
|
2174
2261
|
// latestRead() already suspends the flag for its pull-recomputes; this
|
|
2175
2262
|
// covers creation-time computes and flushes that run inside the window.
|
|
2176
|
-
const
|
|
2263
|
+
const S = latestReadActive;
|
|
2177
2264
|
latestReadActive = false;
|
|
2178
2265
|
// Lane posture lives with the engine: OPTIMISTIC_DIRTY is only ever set by
|
|
2179
2266
|
// engine-driven paths, and _optimisticNodes is only pushed by
|
|
@@ -2191,56 +2278,76 @@ function recompute(e, t = false) {
|
|
|
2191
2278
|
currentOptimisticLane = t;
|
|
2192
2279
|
}
|
|
2193
2280
|
}
|
|
2194
|
-
const
|
|
2195
|
-
const
|
|
2196
|
-
if (
|
|
2281
|
+
const T = n && n !== EFFECT_USER;
|
|
2282
|
+
const O = stale;
|
|
2283
|
+
if (T) stale = true;
|
|
2197
2284
|
try {
|
|
2198
2285
|
if (!false && e.Ue & CONFIG_SYNC) {
|
|
2199
|
-
|
|
2200
|
-
e.
|
|
2286
|
+
c = e.ke(c);
|
|
2287
|
+
e.ct = null;
|
|
2288
|
+
e.xe = false;
|
|
2201
2289
|
} else {
|
|
2202
2290
|
// Snapshot `_inFlight` so we can detect whether `_fn` self-registered an async
|
|
2203
2291
|
// subscription (e.g. `createProjection` calls `handleAsync` from inside its body
|
|
2204
2292
|
// with a setter callback). In that case, the outer `handleAsync` call below would
|
|
2205
2293
|
// clobber the fresh subscription, so we skip it and let the internally-registered
|
|
2206
2294
|
// iteration drive updates.
|
|
2207
|
-
const t = e.
|
|
2208
|
-
const n = e.ke(
|
|
2295
|
+
const t = e.ct;
|
|
2296
|
+
const n = e.ke(c);
|
|
2209
2297
|
const r = typeof n === "object" && n !== null;
|
|
2210
|
-
const i = e.
|
|
2211
|
-
|
|
2212
|
-
if (!i && !r)
|
|
2298
|
+
const i = e.ct !== t;
|
|
2299
|
+
c = i || !r ? n : handleAsync(e, n);
|
|
2300
|
+
if (!i && !r) {
|
|
2301
|
+
e.ct = null;
|
|
2302
|
+
// A sync (non-object) return is the first real answer; async-shaped
|
|
2303
|
+
// results clear inside handleAsync at their own landing points, and a
|
|
2304
|
+
// self-registered flight (inFlightChanged — projections) clears when
|
|
2305
|
+
// its internal handleAsync lands.
|
|
2306
|
+
e.xe = false;
|
|
2307
|
+
}
|
|
2213
2308
|
}
|
|
2214
2309
|
// On a status-free node clearStatus is a guaranteed no-op: every branch
|
|
2215
2310
|
// in its body is gated on one of these fields, and with _statusFlags === 0
|
|
2216
2311
|
// the flags write (create or not) stores the 0 already there.
|
|
2217
|
-
if (e.
|
|
2312
|
+
if (e.He !== 0 || e.yt !== undefined || e.me || e.Pt || e.ht || e.Ke !== undefined || e._ !== undefined || e.R !== undefined || e.it !== null) clearStatus(e, t);
|
|
2218
2313
|
// _optimisticLane is only ever assigned by engine paths.
|
|
2219
2314
|
if (e.i) GlobalQueue.De(e);
|
|
2220
2315
|
} catch (t) {
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2316
|
+
const n = t instanceof NotReadyError;
|
|
2317
|
+
if (n && e.xe) {
|
|
2318
|
+
// Loading window with an unready sync dependency: register for the
|
|
2319
|
+
// source's settle (the settlePendingSource walk runs off
|
|
2320
|
+
// _pendingSources + _blocked alone) but take NO read-visible pending
|
|
2321
|
+
// status, no downstream propagation, no transition, no lane
|
|
2322
|
+
// registration — the committed loading value keeps serving. If the
|
|
2323
|
+
// node is currently errored the error stays the answer until this
|
|
2324
|
+
// retry can actually run.
|
|
2325
|
+
parkLoadingWindow(e, t);
|
|
2326
|
+
} else {
|
|
2327
|
+
// Track pending async in the lane (not the lane's source — it creates the lane
|
|
2328
|
+
// but doesn't belong to it). Set lane BEFORE notifyStatus for downstream propagation.
|
|
2329
|
+
if (n && currentOptimisticLane) GlobalQueue.be(e);
|
|
2330
|
+
let r = false;
|
|
2331
|
+
if (n) {
|
|
2332
|
+
e.ht = true;
|
|
2333
|
+
if (GlobalQueue.Oe !== null) r = GlobalQueue.Oe(e, u);
|
|
2334
|
+
}
|
|
2335
|
+
notifyStatus(e, n ? STATUS_PENDING : STATUS_ERROR, t, undefined, n ? e.i : undefined);
|
|
2336
|
+
if (r) GlobalQueue._e(e);
|
|
2337
|
+
}
|
|
2231
2338
|
} finally {
|
|
2232
|
-
tracking =
|
|
2233
|
-
latestReadActive =
|
|
2234
|
-
if (
|
|
2339
|
+
tracking = E;
|
|
2340
|
+
latestReadActive = S;
|
|
2341
|
+
if (T) stale = O;
|
|
2235
2342
|
e.D = REACTIVE_NONE | (t ? e.D & REACTIVE_SNAPSHOT_STALE : 0);
|
|
2236
|
-
context =
|
|
2343
|
+
context = a;
|
|
2237
2344
|
}
|
|
2238
2345
|
if (!e.me) {
|
|
2239
2346
|
trimStaleDeps(e);
|
|
2240
2347
|
const u = i ? unwrapOverride(e.A) : e.k === NOT_PENDING ? e.We : e.k;
|
|
2241
|
-
let
|
|
2348
|
+
let a = false;
|
|
2242
2349
|
try {
|
|
2243
|
-
|
|
2350
|
+
a = !n && o || !e.Nt || !e.Nt(u, c);
|
|
2244
2351
|
} catch (t) {
|
|
2245
2352
|
// A throwing user comparator is an error of this node's computation.
|
|
2246
2353
|
// Route it through the same status path as a compute-phase throw so
|
|
@@ -2253,13 +2360,13 @@ function recompute(e, t = false) {
|
|
|
2253
2360
|
// its runner — happen here instead. `!create` matches the previous `initialized`
|
|
2254
2361
|
// gate: the explicit recompute(node, true) inside effect() does not enqueue, so
|
|
2255
2362
|
// effect() can call its runner synchronously for the first run.
|
|
2256
|
-
if (n &&
|
|
2363
|
+
if (n && a) {
|
|
2257
2364
|
e.Qe = !e.me;
|
|
2258
2365
|
// Reuse one bound runner per effect — runEffect no-ops on a stale
|
|
2259
2366
|
// `_modified`, so re-enqueueing the same function is harmless.
|
|
2260
|
-
if (!t) e.
|
|
2367
|
+
if (!t) e.Xe.enqueue(n, e.gt ??= GlobalQueue.te.bind(null, e));
|
|
2261
2368
|
}
|
|
2262
|
-
if (e.me) ; else if (
|
|
2369
|
+
if (e.me) ; else if (a) {
|
|
2263
2370
|
const o = i ? e.A : undefined;
|
|
2264
2371
|
if (t ||
|
|
2265
2372
|
// Plain sync flush (no transition on either side) commits effect
|
|
@@ -2267,23 +2374,26 @@ function recompute(e, t = false) {
|
|
|
2267
2374
|
// commitPendingNodes) exists to sequence transition reveals, and
|
|
2268
2375
|
// paying it per effect on the plain path is pure overhead.
|
|
2269
2376
|
n && (activeTransition !== e.T || activeTransition === null) || r) {
|
|
2270
|
-
e.We =
|
|
2377
|
+
e.We = c;
|
|
2271
2378
|
// Lane-propagated correction: upstream data is fresh, correct the
|
|
2272
2379
|
// override unconditionally. The direct _value commit is the lane's
|
|
2273
2380
|
// own reveal schedule; drop any superseded older hold so its queued
|
|
2274
2381
|
// commit can't clobber the fresh value.
|
|
2275
2382
|
if (i && r) {
|
|
2276
|
-
e.A =
|
|
2383
|
+
e.A = c === undefined ? OVERRIDE_UNDEFINED : c;
|
|
2277
2384
|
e.k = NOT_PENDING;
|
|
2278
2385
|
}
|
|
2279
2386
|
} else {
|
|
2280
|
-
e.k =
|
|
2387
|
+
e.k = c;
|
|
2388
|
+
// A window landing that gets held re-opens the window until the hold
|
|
2389
|
+
// commits — the verdict's held-value branch is window-gated (#2990).
|
|
2390
|
+
if (l) e.xe = true;
|
|
2281
2391
|
// Transition-held sync recompute is a write path like setSignal/asyncWrite,
|
|
2282
2392
|
// so sync derivations of held sources stay visible to isPending()/latest()
|
|
2283
2393
|
// (#2831). Both companion writes are transition-scoped (optimistic) and
|
|
2284
2394
|
// auto-revert/re-derive at commit. Skipped for plain flushes where the
|
|
2285
2395
|
// pending value commits before effects run.
|
|
2286
|
-
if ((activeTransition || e.T) && GlobalQueue.ae !== null) GlobalQueue.ae(e,
|
|
2396
|
+
if ((activeTransition || e.T) && GlobalQueue.ae !== null) GlobalQueue.ae(e, c);
|
|
2287
2397
|
}
|
|
2288
2398
|
// insertSubs only walks _subs (no scheduling of its own), so a
|
|
2289
2399
|
// subscriber-less node has nothing to notify.
|
|
@@ -2293,8 +2403,10 @@ function recompute(e, t = false) {
|
|
|
2293
2403
|
// is active: _value may still be stale, so hold the authoritative value
|
|
2294
2404
|
// for commit on its own transition's schedule — invisibly (A17/A18).
|
|
2295
2405
|
if (e.k === NOT_PENDING) queuePendingNode(e);
|
|
2296
|
-
e.k =
|
|
2297
|
-
|
|
2406
|
+
e.k = c;
|
|
2407
|
+
if (l) e.xe = true;
|
|
2408
|
+
// see the held branch above (#2990)
|
|
2409
|
+
} else if (e.Je != f) {
|
|
2298
2410
|
for (let t = e.U; t !== null; t = t.Ge) {
|
|
2299
2411
|
insertIntoHeapHeight(t.Ve, queueFor(t.Ve));
|
|
2300
2412
|
}
|
|
@@ -2304,24 +2416,24 @@ function recompute(e, t = false) {
|
|
|
2304
2416
|
// in an errored run and may sit on stale commits (#2949). Changed-value
|
|
2305
2417
|
// recoveries ride insertSubs above; a comparator throw re-errored the node
|
|
2306
2418
|
// (el._error re-set), so this only runs on a genuinely clean recovery.
|
|
2307
|
-
if (s !== undefined && !
|
|
2419
|
+
if (s !== undefined && !a && !e.me) settleErroredDependents(e, s);
|
|
2308
2420
|
}
|
|
2309
|
-
currentOptimisticLane =
|
|
2310
|
-
const
|
|
2421
|
+
currentOptimisticLane = d;
|
|
2422
|
+
const _ = e.k !== NOT_PENDING || e.Me !== null || e.$e !== null || (e.He & (STATUS_PENDING | STATUS_UNINITIALIZED)) !== 0;
|
|
2311
2423
|
// Override-covered holds (hasOverride) always queue: their commit belongs
|
|
2312
2424
|
// to their own transition's schedule (A18 re-rule) and is unobservable
|
|
2313
2425
|
// under the override (A17). Revert no longer commits anything, so an
|
|
2314
2426
|
// unqueued covered hold would leak (INV-7) once the revert clears
|
|
2315
2427
|
// _transition.
|
|
2316
|
-
|
|
2428
|
+
_ && (!t || e.He & STATUS_PENDING) && (!e.T || i) && queuePendingNode(e);
|
|
2317
2429
|
e.T && n && activeTransition !== e.T && runInTransition(e.T, () => recompute(e));
|
|
2318
2430
|
}
|
|
2319
2431
|
|
|
2320
2432
|
function updateIfNecessary(e) {
|
|
2321
2433
|
if (e.D & REACTIVE_CHECK) {
|
|
2322
|
-
for (let t = e.
|
|
2323
|
-
const n = t.
|
|
2324
|
-
const r = n.
|
|
2434
|
+
for (let t = e.Ye; t; t = t.qe) {
|
|
2435
|
+
const n = t.Be;
|
|
2436
|
+
const r = n.Ze || n;
|
|
2325
2437
|
if (r.ke) {
|
|
2326
2438
|
updateIfNecessary(r);
|
|
2327
2439
|
}
|
|
@@ -2330,7 +2442,7 @@ function updateIfNecessary(e) {
|
|
|
2330
2442
|
}
|
|
2331
2443
|
}
|
|
2332
2444
|
}
|
|
2333
|
-
if (e.D & (REACTIVE_DIRTY | REACTIVE_OPTIMISTIC_DIRTY) || e.me && e.H < clock && !e.
|
|
2445
|
+
if (e.D & (REACTIVE_DIRTY | REACTIVE_OPTIMISTIC_DIRTY) || e.me && e.H < clock && !e.ct) {
|
|
2334
2446
|
recompute(e);
|
|
2335
2447
|
}
|
|
2336
2448
|
e.D = e.D & (REACTIVE_SNAPSHOT_STALE | REACTIVE_IN_HEAP | REACTIVE_IN_HEAP_HEIGHT);
|
|
@@ -2338,42 +2450,48 @@ function updateIfNecessary(e) {
|
|
|
2338
2450
|
|
|
2339
2451
|
function computed(e, t) {
|
|
2340
2452
|
const n = t?.transparent ?? false;
|
|
2341
|
-
|
|
2453
|
+
// `in` (not `!== undefined`): an explicit `loadingValue: undefined` on a
|
|
2454
|
+
// `T | undefined` node is a real commit #0. The typeof guard tolerates
|
|
2455
|
+
// non-object option values that older call shapes force through `as any`.
|
|
2456
|
+
const r = t !== null && typeof t === "object" && "loadingValue" in t;
|
|
2457
|
+
const i = {
|
|
2342
2458
|
id: inheritId(t, n, context),
|
|
2343
|
-
Ue: (n ? CONFIG_TRANSPARENT : 0) | (t?.ownedWrite ? CONFIG_OWNED_WRITE : 0) | (!context || t?.lazy ? CONFIG_AUTO_DISPOSE : 0) | (t?.sync ? CONFIG_SYNC : 0) | (t?.
|
|
2344
|
-
|
|
2459
|
+
Ue: (n ? CONFIG_TRANSPARENT : 0) | (t?.ownedWrite ? CONFIG_OWNED_WRITE : 0) | (!context || t?.lazy ? CONFIG_AUTO_DISPOSE : 0) | (t?.sync ? CONFIG_SYNC : 0) | (t?.bt ? CONFIG_NO_SNAPSHOT : 0) | (snapshotCaptureActive && ownerInSnapshotScope(context) ? CONFIG_IN_SNAPSHOT_SCOPE : 0),
|
|
2460
|
+
Nt: t?.equals != null ? t.equals : isEqual,
|
|
2345
2461
|
F: t?.unobserved,
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2462
|
+
St: null,
|
|
2463
|
+
Xe: context?.Xe ?? globalQueue,
|
|
2464
|
+
Tt: context?.Tt ?? defaultContext,
|
|
2465
|
+
ft: 0,
|
|
2350
2466
|
ke: e,
|
|
2351
|
-
We: undefined,
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2467
|
+
We: r ? t.loadingValue : undefined,
|
|
2468
|
+
Je: 0,
|
|
2469
|
+
it: null,
|
|
2470
|
+
rt: undefined,
|
|
2471
|
+
nt: null,
|
|
2472
|
+
Ye: null,
|
|
2473
|
+
lt: null,
|
|
2474
|
+
At: 0,
|
|
2359
2475
|
U: null,
|
|
2360
|
-
|
|
2476
|
+
_t: null,
|
|
2361
2477
|
Z: context,
|
|
2478
|
+
ut: null,
|
|
2479
|
+
Et: null,
|
|
2362
2480
|
st: null,
|
|
2363
|
-
ft: null,
|
|
2364
|
-
ot: null,
|
|
2365
2481
|
D: t?.lazy ? REACTIVE_LAZY : REACTIVE_NONE,
|
|
2366
|
-
|
|
2482
|
+
// A loadingValue node is born committed: commit #0 is already in _value.
|
|
2483
|
+
He: r ? 0 : STATUS_UNINITIALIZED,
|
|
2367
2484
|
H: clock,
|
|
2368
2485
|
k: NOT_PENDING,
|
|
2486
|
+
$e: null,
|
|
2369
2487
|
Me: null,
|
|
2370
|
-
|
|
2371
|
-
lt: null,
|
|
2488
|
+
ct: null,
|
|
2372
2489
|
T: null,
|
|
2373
|
-
|
|
2490
|
+
Pt: false,
|
|
2491
|
+
xe: r
|
|
2374
2492
|
};
|
|
2375
|
-
setupComputedNode(
|
|
2376
|
-
return
|
|
2493
|
+
setupComputedNode(i, t);
|
|
2494
|
+
return i;
|
|
2377
2495
|
}
|
|
2378
2496
|
|
|
2379
2497
|
/**
|
|
@@ -2386,41 +2504,42 @@ function computed(e, t) {
|
|
|
2386
2504
|
const u = {
|
|
2387
2505
|
id: inheritId(o, s, context),
|
|
2388
2506
|
Ue: (s ? CONFIG_TRANSPARENT : 0) | (o?.ownedWrite ? CONFIG_OWNED_WRITE : 0) | (o?.sync ? CONFIG_SYNC : 0) | (snapshotCaptureActive && ownerInSnapshotScope(context) ? CONFIG_IN_SNAPSHOT_SCOPE : 0),
|
|
2389
|
-
|
|
2507
|
+
Nt: false,
|
|
2390
2508
|
F: o?.unobserved,
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2509
|
+
St: null,
|
|
2510
|
+
Xe: context?.Xe ?? globalQueue,
|
|
2511
|
+
Tt: context?.Tt ?? defaultContext,
|
|
2512
|
+
ft: 0,
|
|
2395
2513
|
ke: e,
|
|
2396
2514
|
We: undefined,
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2515
|
+
Je: 0,
|
|
2516
|
+
it: null,
|
|
2517
|
+
rt: undefined,
|
|
2518
|
+
nt: null,
|
|
2519
|
+
Ye: null,
|
|
2520
|
+
lt: null,
|
|
2521
|
+
At: 0,
|
|
2404
2522
|
U: null,
|
|
2405
|
-
|
|
2523
|
+
_t: null,
|
|
2406
2524
|
Z: context,
|
|
2525
|
+
ut: null,
|
|
2526
|
+
Et: null,
|
|
2407
2527
|
st: null,
|
|
2408
|
-
ft: null,
|
|
2409
|
-
ot: null,
|
|
2410
2528
|
D: REACTIVE_LAZY,
|
|
2411
|
-
|
|
2529
|
+
He: STATUS_UNINITIALIZED,
|
|
2412
2530
|
H: clock,
|
|
2413
2531
|
k: NOT_PENDING,
|
|
2532
|
+
$e: null,
|
|
2414
2533
|
Me: null,
|
|
2415
|
-
|
|
2416
|
-
lt: null,
|
|
2534
|
+
ct: null,
|
|
2417
2535
|
T: null,
|
|
2418
|
-
|
|
2536
|
+
Pt: false,
|
|
2537
|
+
xe: false,
|
|
2419
2538
|
Qe: false,
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2539
|
+
Dt: undefined,
|
|
2540
|
+
wt: t,
|
|
2541
|
+
vt: n,
|
|
2542
|
+
dt: undefined,
|
|
2424
2543
|
Fe: r,
|
|
2425
2544
|
yt: i
|
|
2426
2545
|
};
|
|
@@ -2433,23 +2552,23 @@ const lazyOptions = {
|
|
|
2433
2552
|
};
|
|
2434
2553
|
|
|
2435
2554
|
function setupComputedNode(e, t) {
|
|
2436
|
-
e.
|
|
2437
|
-
const n = context?.
|
|
2555
|
+
e.nt = e;
|
|
2556
|
+
const n = context?.et ? context.tt : context;
|
|
2438
2557
|
if (context) {
|
|
2439
|
-
const t = context.
|
|
2558
|
+
const t = context.st;
|
|
2440
2559
|
if (t === null) {
|
|
2441
|
-
context.
|
|
2560
|
+
context.st = e;
|
|
2442
2561
|
} else {
|
|
2443
|
-
e.
|
|
2444
|
-
t.
|
|
2445
|
-
context.
|
|
2562
|
+
e.ut = t;
|
|
2563
|
+
t.Et = e;
|
|
2564
|
+
context.st = e;
|
|
2446
2565
|
}
|
|
2447
2566
|
}
|
|
2448
|
-
if (n) e.
|
|
2567
|
+
if (n) e.Je = n.Je + 1;
|
|
2449
2568
|
if (GlobalQueue.ue !== null) GlobalQueue.ue(e);
|
|
2450
2569
|
!t?.lazy && recompute(e, true);
|
|
2451
2570
|
if (snapshotCaptureActive && !t?.lazy) {
|
|
2452
|
-
if (!(e.
|
|
2571
|
+
if (!(e.He & STATUS_PENDING) && !(e.Ue & CONFIG_NO_SNAPSHOT)) {
|
|
2453
2572
|
e.Le = e.We === undefined ? NO_SNAPSHOT : e.We;
|
|
2454
2573
|
snapshotSources.add(e);
|
|
2455
2574
|
}
|
|
@@ -2458,19 +2577,19 @@ function setupComputedNode(e, t) {
|
|
|
2458
2577
|
|
|
2459
2578
|
function signal(e, t, n = null) {
|
|
2460
2579
|
const r = {
|
|
2461
|
-
|
|
2462
|
-
Ue: (t?.ownedWrite ? CONFIG_OWNED_WRITE : 0) | (t?.
|
|
2580
|
+
Nt: t?.equals != null ? t.equals : isEqual,
|
|
2581
|
+
Ue: (t?.ownedWrite ? CONFIG_OWNED_WRITE : 0) | (t?.bt ? CONFIG_NO_SNAPSHOT : 0),
|
|
2463
2582
|
F: t?.unobserved,
|
|
2464
2583
|
We: e,
|
|
2465
2584
|
U: null,
|
|
2466
|
-
|
|
2585
|
+
_t: null,
|
|
2467
2586
|
H: clock,
|
|
2468
|
-
|
|
2469
|
-
|
|
2587
|
+
Ze: n,
|
|
2588
|
+
ot: n?.it || null,
|
|
2470
2589
|
k: NOT_PENDING
|
|
2471
2590
|
};
|
|
2472
|
-
n && (n.
|
|
2473
|
-
if (snapshotCaptureActive && !(r.Ue & CONFIG_NO_SNAPSHOT) && !((n?.
|
|
2591
|
+
n && (n.it = r);
|
|
2592
|
+
if (snapshotCaptureActive && !(r.Ue & CONFIG_NO_SNAPSHOT) && !((n?.He ?? 0) & STATUS_PENDING)) {
|
|
2474
2593
|
r.Le = e === undefined ? NO_SNAPSHOT : e;
|
|
2475
2594
|
snapshotSources.add(r);
|
|
2476
2595
|
}
|
|
@@ -2555,9 +2674,9 @@ function isEqual(e, t) {
|
|
|
2555
2674
|
* snapshot / transition / lane / dev-strictRead state all take the full
|
|
2556
2675
|
* resolution. Anything slow returns READ_SLOW; the caller then calls read().
|
|
2557
2676
|
*/ function readNodeFast(e) {
|
|
2558
|
-
if (latestReadActive || pendingCheckActive || e.ke || e.
|
|
2677
|
+
if (latestReadActive || pendingCheckActive || e.ke || e.Ze || e.A !== undefined || e.Le !== undefined || activeTransition !== null || currentOptimisticLane !== null || snapshotCaptureActive || false) return READ_SLOW;
|
|
2559
2678
|
let t = context;
|
|
2560
|
-
if (t?.
|
|
2679
|
+
if (t?.et) t = t.tt;
|
|
2561
2680
|
if (t && tracking) link(e, t);
|
|
2562
2681
|
return !t || e.k === NOT_PENDING ? e.We : e.k;
|
|
2563
2682
|
}
|
|
@@ -2569,9 +2688,9 @@ function read(e) {
|
|
|
2569
2688
|
// than the original node (which stays "pending" while held in a transition).
|
|
2570
2689
|
if (latestReadActive) return GlobalQueue.de(e);
|
|
2571
2690
|
let t = context;
|
|
2572
|
-
if (t?.
|
|
2691
|
+
if (t?.et) t = t.tt;
|
|
2573
2692
|
const n = e;
|
|
2574
|
-
const r = e.
|
|
2693
|
+
const r = e.Ze;
|
|
2575
2694
|
const i = r || e;
|
|
2576
2695
|
// Handle isPending() mode: collect pending state while preserving normal read semantics.
|
|
2577
2696
|
// Probe mode is suspended while preparing the node so nested reads during a
|
|
@@ -2589,31 +2708,31 @@ function read(e) {
|
|
|
2589
2708
|
link(e, t, pendingCheckActive);
|
|
2590
2709
|
if (i.ke) {
|
|
2591
2710
|
const n = queueFor(e);
|
|
2592
|
-
if (i.
|
|
2711
|
+
if (i.Je >= n.P) {
|
|
2593
2712
|
markNode(t);
|
|
2594
2713
|
markHeap(n);
|
|
2595
2714
|
updateIfNecessary(i);
|
|
2596
2715
|
}
|
|
2597
|
-
const r = i.
|
|
2716
|
+
const r = i.Je;
|
|
2598
2717
|
// parent check is shallow, might need to be recursive
|
|
2599
|
-
if (r >= t.
|
|
2600
|
-
t.
|
|
2718
|
+
if (r >= t.Je && e.Z !== t) {
|
|
2719
|
+
t.Je = r + 1;
|
|
2601
2720
|
}
|
|
2602
2721
|
}
|
|
2603
2722
|
}
|
|
2604
|
-
if (i.
|
|
2723
|
+
if (i.He & STATUS_PENDING) {
|
|
2605
2724
|
if (t && !(stale && i.T && activeTransition !== i.T)) {
|
|
2606
2725
|
// Per-lane suspension lives with the engine (a non-null lane implies it
|
|
2607
2726
|
// is installed): under a lane, only same-lane pending async without an
|
|
2608
2727
|
// active override throws.
|
|
2609
|
-
if (currentOptimisticLane === null || GlobalQueue.
|
|
2728
|
+
if (currentOptimisticLane === null || GlobalQueue.ye(i)) {
|
|
2610
2729
|
if (!tracking && e !== t) link(e, t);
|
|
2611
2730
|
throw i.me;
|
|
2612
2731
|
}
|
|
2613
|
-
} else if (t && i !== e && i.
|
|
2732
|
+
} else if (t && i !== e && i.He & STATUS_UNINITIALIZED) {
|
|
2614
2733
|
if (!tracking && e !== t) link(e, t);
|
|
2615
2734
|
throw i.me;
|
|
2616
|
-
} else if (!t && i.
|
|
2735
|
+
} else if (!t && i.He & STATUS_UNINITIALIZED) {
|
|
2617
2736
|
throw i.me;
|
|
2618
2737
|
}
|
|
2619
2738
|
}
|
|
@@ -2621,7 +2740,7 @@ function read(e) {
|
|
|
2621
2740
|
// firewall-backed reads follow the same rules (memo parity, #2897 ruling):
|
|
2622
2741
|
// an errored derive throws for every late reader instead of silently
|
|
2623
2742
|
// serving node values (the seed, or last-good data after a failed refetch).
|
|
2624
|
-
if (i.ke && i.
|
|
2743
|
+
if (i.ke && i.He & STATUS_ERROR) {
|
|
2625
2744
|
// Only a genuine reactive re-read may retry an errored async source:
|
|
2626
2745
|
// - tracking: owned/tracked scope only (never events / `untrack` / effect side-effect phase)
|
|
2627
2746
|
// - !pendingCheckActive: an `isPending` probe observes the error, never refetches
|
|
@@ -2651,7 +2770,7 @@ function read(e) {
|
|
|
2651
2770
|
// _pendingValue for correct fetching. The sub is recorded for replay at commit
|
|
2652
2771
|
// so it re-runs with the new committed view. (Gate details live with the
|
|
2653
2772
|
// engine — a non-null lane implies it is installed.)
|
|
2654
|
-
if (currentOptimisticLane !== null && activeTransition !== null && t !== null && GlobalQueue.
|
|
2773
|
+
if (currentOptimisticLane !== null && activeTransition !== null && t !== null && GlobalQueue.Pe(e, i, t)) {
|
|
2655
2774
|
return e.We;
|
|
2656
2775
|
}
|
|
2657
2776
|
// In optimistic lane context, return _value for optimistic/lane-assigned signals
|
|
@@ -2662,7 +2781,7 @@ function read(e) {
|
|
|
2662
2781
|
// Record that this isPending() probe observed the fresh pending value, so
|
|
2663
2782
|
// the probe doesn't pair "pending" with the new value (#2831).
|
|
2664
2783
|
if (pendingCheckActive) GlobalQueue.Te(e, o);
|
|
2665
|
-
if (!t && i === e && typeof n.ke === "function" && e.Ue & CONFIG_AUTO_DISPOSE && !(i.
|
|
2784
|
+
if (!t && i === e && typeof n.ke === "function" && e.Ue & CONFIG_AUTO_DISPOSE && !(i.He & STATUS_PENDING) && !e.U) {
|
|
2666
2785
|
unobserved(e);
|
|
2667
2786
|
}
|
|
2668
2787
|
return o;
|
|
@@ -2679,7 +2798,7 @@ function setSignal(e, t) {
|
|
|
2679
2798
|
if (typeof t === "function") t = t(n);
|
|
2680
2799
|
// Uninitialized check first: the first commit has no previous value, so the
|
|
2681
2800
|
// user comparator must not run against `undefined` (matches recompute).
|
|
2682
|
-
const r = !!(e.
|
|
2801
|
+
const r = !!(e.He & STATUS_UNINITIALIZED) || !e.Nt || !e.Nt(n, t);
|
|
2683
2802
|
if (!r) return t;
|
|
2684
2803
|
if (e.k === NOT_PENDING) queuePendingNode(e);
|
|
2685
2804
|
e.k = t;
|
|
@@ -2920,7 +3039,7 @@ function enableExternalSource(e) {
|
|
|
2920
3039
|
if (!t) {
|
|
2921
3040
|
throw new NoOwnerError;
|
|
2922
3041
|
}
|
|
2923
|
-
const n = hasContext(e, t) ? t.
|
|
3042
|
+
const n = hasContext(e, t) ? t.Tt[e.id] : e.defaultValue;
|
|
2924
3043
|
if (isUndefined(n)) {
|
|
2925
3044
|
throw new ContextNotFoundError;
|
|
2926
3045
|
}
|
|
@@ -2941,14 +3060,14 @@ function enableExternalSource(e) {
|
|
|
2941
3060
|
}
|
|
2942
3061
|
// We're creating a new object to avoid child context values being exposed to parent owners. If
|
|
2943
3062
|
// we don't do this, everything will be a singleton and all hell will break lose.
|
|
2944
|
-
n.
|
|
2945
|
-
...n.
|
|
3063
|
+
n.Tt = {
|
|
3064
|
+
...n.Tt,
|
|
2946
3065
|
[e.id]: isUndefined(t) ? e.defaultValue : t
|
|
2947
3066
|
};
|
|
2948
3067
|
}
|
|
2949
3068
|
|
|
2950
3069
|
function hasContext(e, t) {
|
|
2951
|
-
return !isUndefined(t?.
|
|
3070
|
+
return !isUndefined(t?.Tt[e.id]);
|
|
2952
3071
|
}
|
|
2953
3072
|
|
|
2954
3073
|
function isUndefined(e) {
|
|
@@ -2972,7 +3091,7 @@ function isUndefined(e) {
|
|
|
2972
3091
|
const n = e.A !== NOT_PENDING;
|
|
2973
3092
|
const r = n ? unwrapOverride(e.A) : e.We;
|
|
2974
3093
|
if (typeof t === "function") t = t(r);
|
|
2975
|
-
const i = !!(e.
|
|
3094
|
+
const i = !!(e.He & STATUS_UNINITIALIZED) || !e.Nt || !e.Nt(r, t);
|
|
2976
3095
|
if (!i) {
|
|
2977
3096
|
// Same-value write with an active override still entangles the current
|
|
2978
3097
|
// action's transition — the hold must outlast all overlapping actions.
|
|
@@ -3013,7 +3132,7 @@ function isUndefined(e) {
|
|
|
3013
3132
|
*/ function transitionBlocked(e) {
|
|
3014
3133
|
for (let t = 0; t < e.L.length; t++) {
|
|
3015
3134
|
const n = e.L[t];
|
|
3016
|
-
if (hasActiveOverride(n) && "
|
|
3135
|
+
if (hasActiveOverride(n) && "He" in n && n.He & STATUS_PENDING && n.me instanceof NotReadyError) {
|
|
3017
3136
|
return true;
|
|
3018
3137
|
}
|
|
3019
3138
|
}
|
|
@@ -3031,7 +3150,7 @@ function resolveOptimisticNodes(e) {
|
|
|
3031
3150
|
// Revert is a pure drop: there is no revert target to commit —
|
|
3032
3151
|
// override-covered authoritative values hold in _pendingValue and
|
|
3033
3152
|
// elevate on their OWN transition's schedule (A18 as re-ruled 2026-07-07).
|
|
3034
|
-
if (!(t.
|
|
3153
|
+
if (!(t.He & STATUS_PENDING)) t.He &= ~STATUS_UNINITIALIZED;
|
|
3035
3154
|
const r = t.A;
|
|
3036
3155
|
t.A = NOT_PENDING;
|
|
3037
3156
|
if (r !== NOT_PENDING && t.We !== unwrapOverride(r)) insertSubs(t, true);
|
|
@@ -3109,7 +3228,7 @@ function cleanupCompletedLanes(e) {
|
|
|
3109
3228
|
* read()'s value selection under a lane: return the committed `_value` for
|
|
3110
3229
|
* optimistic/lane-assigned signals, stale-mode reads, and pending owners.
|
|
3111
3230
|
*/ function laneReadsCommitted(e, t, n) {
|
|
3112
|
-
if (e.A !== undefined || !!e.i || !!(t.
|
|
3231
|
+
if (e.A !== undefined || !!e.i || !!(t.He & STATUS_PENDING)) return true;
|
|
3113
3232
|
if (t === e && stale && n.t !== e) {
|
|
3114
3233
|
// The committed view can hide a same-tick ambient write (a lane member —
|
|
3115
3234
|
// even just an isPending companion flip — puts the reader "under a lane"
|
|
@@ -3130,8 +3249,8 @@ function cleanupCompletedLanes(e) {
|
|
|
3130
3249
|
* can run before its OPT-dirty child propagates).
|
|
3131
3250
|
*/ function recomputeLane(e, t) {
|
|
3132
3251
|
if (t) return resolveLane(e) ?? null;
|
|
3133
|
-
for (let t = e.
|
|
3134
|
-
const n = t.
|
|
3252
|
+
for (let t = e.Ye; t; t = t.qe) {
|
|
3253
|
+
const n = t.Be;
|
|
3135
3254
|
if (n.D & REACTIVE_OPTIMISTIC_DIRTY) {
|
|
3136
3255
|
const t = resolveLane(n);
|
|
3137
3256
|
if (t) {
|
|
@@ -3178,8 +3297,8 @@ function trackOptimisticStore(e) {
|
|
|
3178
3297
|
GlobalQueue.Ae = transitionBlocked;
|
|
3179
3298
|
GlobalQueue.he = cleanupCompletedLanes;
|
|
3180
3299
|
GlobalQueue.Ne = runLaneEffects;
|
|
3181
|
-
GlobalQueue.
|
|
3182
|
-
GlobalQueue.
|
|
3300
|
+
GlobalQueue.Pe = gatedRead;
|
|
3301
|
+
GlobalQueue.ye = laneSuspends;
|
|
3183
3302
|
GlobalQueue.Ce = laneReadsCommitted;
|
|
3184
3303
|
GlobalQueue.ge = recomputeLane;
|
|
3185
3304
|
GlobalQueue.be = laneAsyncPending;
|
|
@@ -3217,7 +3336,7 @@ let pendingProbe = null;
|
|
|
3217
3336
|
function collectPendingSources(e) {
|
|
3218
3337
|
if (!pendingProbe) return;
|
|
3219
3338
|
pendingProbe.sources.add(e);
|
|
3220
|
-
const t = e.
|
|
3339
|
+
const t = e.Ze || e;
|
|
3221
3340
|
if (t !== e) pendingProbe.sources.add(t);
|
|
3222
3341
|
}
|
|
3223
3342
|
|
|
@@ -3247,20 +3366,20 @@ function collectPendingSources(e) {
|
|
|
3247
3366
|
// not flow through it — matching the rails' behavior, where propagation
|
|
3248
3367
|
// stopped at errored nodes. A DIRECT mark on an errored node still reads
|
|
3249
3368
|
// pending (the count check above), also matching.
|
|
3250
|
-
if (e.
|
|
3369
|
+
if (e.He & STATUS_ERROR) return false;
|
|
3251
3370
|
if (t.has(e)) return false;
|
|
3252
3371
|
t.add(e);
|
|
3253
|
-
const n = e.
|
|
3372
|
+
const n = e.Ze;
|
|
3254
3373
|
if (n && markWalk(n, t)) return true;
|
|
3255
3374
|
// Mid-recompute (the clearStatus companion poke runs before
|
|
3256
3375
|
// trimStaleDeps), only the validated prefix [_deps.._depsTail] is this
|
|
3257
3376
|
// pass's dependency set — walking past it would read dropped deps and
|
|
3258
3377
|
// latch a stale verdict on the companion.
|
|
3259
3378
|
const r = e;
|
|
3260
|
-
const i = r.D & REACTIVE_RECOMPUTING_DEPS ? r.
|
|
3379
|
+
const i = r.D & REACTIVE_RECOMPUTING_DEPS ? r.lt : undefined;
|
|
3261
3380
|
if (i !== null) {
|
|
3262
|
-
for (let e = r.
|
|
3263
|
-
if (!e.
|
|
3381
|
+
for (let e = r.Ye ?? null; e !== null; e = e.qe) {
|
|
3382
|
+
if (!e.Rt && markWalk(e.Be, t)) return true;
|
|
3264
3383
|
if (e === i) break;
|
|
3265
3384
|
}
|
|
3266
3385
|
}
|
|
@@ -3272,15 +3391,22 @@ function collectPendingSources(e) {
|
|
|
3272
3391
|
}
|
|
3273
3392
|
|
|
3274
3393
|
function quietPending(e) {
|
|
3275
|
-
if (e.
|
|
3276
|
-
for (const t of e.
|
|
3394
|
+
if (e.Ke) {
|
|
3395
|
+
for (const t of e.Ke) if (!t.Pt) return false;
|
|
3277
3396
|
return true;
|
|
3278
3397
|
}
|
|
3279
|
-
return e.
|
|
3398
|
+
return e.Pt;
|
|
3280
3399
|
}
|
|
3281
3400
|
|
|
3401
|
+
// NOTE: a loadingValue node's open loading window (_loading) is verdict-quiet
|
|
3402
|
+
// on purpose: commit #0 answers the question by declaration, so the window
|
|
3403
|
+
// reads NOT pending — first-load affordances live in the value channel
|
|
3404
|
+
// (null / skeleton provenance the author encoded), and isPending stays what
|
|
3405
|
+
// it always was: refetch truth for an answered question. This keeps the
|
|
3406
|
+
// verdict fully correlated with transition-class machinery and keeps server
|
|
3407
|
+
// (always false) and client hydration trivially consistent.
|
|
3282
3408
|
function newQuestionInFlight(e) {
|
|
3283
|
-
return !!(e.
|
|
3409
|
+
return !!(e.He & STATUS_PENDING) && !(e.He & STATUS_UNINITIALIZED) && !quietPending(e);
|
|
3284
3410
|
}
|
|
3285
3411
|
|
|
3286
3412
|
function computePendingState(e) {
|
|
@@ -3290,17 +3416,21 @@ function computePendingState(e) {
|
|
|
3290
3416
|
// reaches its owner (and a store leaf its firewall) through its own deps,
|
|
3291
3417
|
// so the one walk covers direct marks, derivation, and companion chains.
|
|
3292
3418
|
if (markCovered(e)) return true;
|
|
3293
|
-
const n = e.
|
|
3419
|
+
const n = e.Ze;
|
|
3294
3420
|
if (e.t) {
|
|
3295
3421
|
const t = e.t;
|
|
3296
|
-
const n = t.
|
|
3422
|
+
const n = t.Ze || t;
|
|
3297
3423
|
return newQuestionInFlight(n);
|
|
3298
3424
|
}
|
|
3299
3425
|
if (n && e.k !== NOT_PENDING && !hasActiveOverride(e)) {
|
|
3300
|
-
return !!(n.D & REACTIVE_MANUAL_WRITE) || !n.
|
|
3301
|
-
}
|
|
3302
|
-
|
|
3303
|
-
|
|
3426
|
+
return !!(n.D & REACTIVE_MANUAL_WRITE) || !n.ct && !(n.He & STATUS_PENDING) || !!(n.He & STATUS_PENDING) && quietPending(n);
|
|
3427
|
+
}
|
|
3428
|
+
// `!comp._loading`: a hold created while the loading window is still open is
|
|
3429
|
+
// the window's own landing in flight to its commit — verdict-quiet like the
|
|
3430
|
+
// rest of the window (the UNINITIALIZED check suppresses exactly this frame
|
|
3431
|
+
// for windowless first loads; born-committed nodes need their own gate, #2990).
|
|
3432
|
+
if (e.k !== NOT_PENDING && !(t.He & STATUS_UNINITIALIZED) && !t.xe) {
|
|
3433
|
+
if (hasActiveOverride(e)) return !e.Nt || !e.Nt(e.k, unwrapOverride(e.A));
|
|
3304
3434
|
return true;
|
|
3305
3435
|
}
|
|
3306
3436
|
return newQuestionInFlight(t);
|
|
@@ -3319,7 +3449,7 @@ function updatePendingSignal(e) {
|
|
|
3319
3449
|
}
|
|
3320
3450
|
|
|
3321
3451
|
function updateChildCompanions(e) {
|
|
3322
|
-
for (let t = e.
|
|
3452
|
+
for (let t = e.it; t !== null; t = t.ot) {
|
|
3323
3453
|
if (t._ || t.R) updatePendingSignal(t);
|
|
3324
3454
|
}
|
|
3325
3455
|
}
|
|
@@ -3340,7 +3470,7 @@ function updateChildCompanions(e) {
|
|
|
3340
3470
|
r.add(e);
|
|
3341
3471
|
if (e._ || e.R) n(e);
|
|
3342
3472
|
for (let t = e.U; t !== null; t = t.Ge) visit(t.Ve);
|
|
3343
|
-
for (let t = e.
|
|
3473
|
+
for (let t = e.it ?? null; t !== null; t = t.ot) {
|
|
3344
3474
|
visit(t);
|
|
3345
3475
|
}
|
|
3346
3476
|
};
|
|
@@ -3403,18 +3533,18 @@ function getLatestValueComputed(e) {
|
|
|
3403
3533
|
// until the flush (#2922). Mirror the tracked-read pull here: mark the
|
|
3404
3534
|
// queued staleness through the graph, then bring the shadow up to date.
|
|
3405
3535
|
const e = queueFor(t);
|
|
3406
|
-
if (t.
|
|
3536
|
+
if (t.Je >= e.P && !(t.D & (REACTIVE_DISPOSED | REACTIVE_ZOMBIE))) {
|
|
3407
3537
|
markHeap(e);
|
|
3408
3538
|
prepareComputed(t, true);
|
|
3409
3539
|
}
|
|
3410
3540
|
i = read(t);
|
|
3411
3541
|
} catch (t) {
|
|
3412
|
-
if (t instanceof NotReadyError && (!context || !(e.
|
|
3542
|
+
if (t instanceof NotReadyError && (!context || !(e.He & STATUS_UNINITIALIZED))) return r;
|
|
3413
3543
|
throw t;
|
|
3414
3544
|
} finally {
|
|
3415
3545
|
setLatestReadActive(n);
|
|
3416
3546
|
}
|
|
3417
|
-
if (t.
|
|
3547
|
+
if (t.He & STATUS_PENDING) return r;
|
|
3418
3548
|
if (stale && currentOptimisticLane && t.i) {
|
|
3419
3549
|
const e = findLane(t.i);
|
|
3420
3550
|
const n = findLane(currentOptimisticLane);
|
|
@@ -3433,7 +3563,7 @@ function getLatestValueComputed(e) {
|
|
|
3433
3563
|
/** The isPending()-probe read path, installed as GlobalQueue._pendingCheck. */ function pendingCheckRead(e, t, n, r) {
|
|
3434
3564
|
setPendingCheckActive(false);
|
|
3435
3565
|
if (typeof e.ke === "function") prepareComputed(e, true);
|
|
3436
|
-
const i = n.
|
|
3566
|
+
const i = n.He;
|
|
3437
3567
|
if (t && i & STATUS_PENDING && i & STATUS_UNINITIALIZED) {
|
|
3438
3568
|
if (tracking && e !== t) link(e, t);
|
|
3439
3569
|
setPendingCheckActive(true);
|
|
@@ -3449,10 +3579,10 @@ function recordFreshRead(e, t) {
|
|
|
3449
3579
|
}
|
|
3450
3580
|
|
|
3451
3581
|
function applyReask(e, t) {
|
|
3452
|
-
const n = !!(e.
|
|
3453
|
-
const r = t && !(n && !e.
|
|
3454
|
-
const i = n && e.
|
|
3455
|
-
e.
|
|
3582
|
+
const n = !!(e.He & STATUS_PENDING);
|
|
3583
|
+
const r = t && !(n && !e.Pt);
|
|
3584
|
+
const i = n && e.Pt !== r;
|
|
3585
|
+
e.Pt = r;
|
|
3456
3586
|
return i;
|
|
3457
3587
|
}
|
|
3458
3588
|
|
|
@@ -3492,7 +3622,7 @@ function isPending(e) {
|
|
|
3492
3622
|
} catch (e) {
|
|
3493
3623
|
collectPending();
|
|
3494
3624
|
if (e instanceof NotReadyError) {
|
|
3495
|
-
const t = !!(e.source?.
|
|
3625
|
+
const t = !!(e.source?.He & STATUS_UNINITIALIZED);
|
|
3496
3626
|
if (r.found && !t) return true;
|
|
3497
3627
|
if (context && t) throw e;
|
|
3498
3628
|
}
|
|
@@ -3534,15 +3664,15 @@ GlobalQueue.Re = witnessAffects;
|
|
|
3534
3664
|
const i = !!r?.user;
|
|
3535
3665
|
const o = createEffectNode(e, t, n, i ? EFFECT_USER : EFFECT_RENDER, notifyEffectStatus, r);
|
|
3536
3666
|
recompute(o, true);
|
|
3537
|
-
!r?.defer && (o.Fe === EFFECT_USER || r?.schedule ? o.
|
|
3667
|
+
!r?.defer && (o.Fe === EFFECT_USER || r?.schedule ? o.Xe.enqueue(o.Fe, runEffect.bind(null, o)) : runEffect(o));
|
|
3538
3668
|
}
|
|
3539
3669
|
|
|
3540
3670
|
function notifyEffectStatus(e, t) {
|
|
3541
3671
|
// Use passed values if provided, otherwise read from node
|
|
3542
|
-
const n = e !== undefined ? e : this.
|
|
3672
|
+
const n = e !== undefined ? e : this.He;
|
|
3543
3673
|
const r = t !== undefined ? t : this.me;
|
|
3544
3674
|
if (n & STATUS_ERROR) {
|
|
3545
|
-
this.
|
|
3675
|
+
this.Xe.notify(this, STATUS_PENDING, 0);
|
|
3546
3676
|
if (this.Fe === EFFECT_USER) {
|
|
3547
3677
|
// The error handler is the error arm of the effect phase (#2840 ruling):
|
|
3548
3678
|
// queue it like the effect function. It runs in the same imperative,
|
|
@@ -3553,18 +3683,18 @@ function notifyEffectStatus(e, t) {
|
|
|
3553
3683
|
// phase takes the success arm instead. Blocked forwards (explicit
|
|
3554
3684
|
// `status` arg without node-state writes) don't queue: the status
|
|
3555
3685
|
// re-propagates unblocked at commit.
|
|
3556
|
-
if (this.
|
|
3686
|
+
if (this.He & STATUS_ERROR) {
|
|
3557
3687
|
this.Qe = true;
|
|
3558
|
-
this.
|
|
3688
|
+
this.Xe.enqueue(this.Fe, this.gt ??= runEffect.bind(null, this));
|
|
3559
3689
|
}
|
|
3560
3690
|
return;
|
|
3561
3691
|
}
|
|
3562
|
-
if (!this.
|
|
3692
|
+
if (!this.Xe.notify(this, STATUS_ERROR, STATUS_ERROR)) {
|
|
3563
3693
|
haltReactivity(unwrapStatusError(r));
|
|
3564
3694
|
throw r;
|
|
3565
3695
|
}
|
|
3566
3696
|
} else if (this.Fe === EFFECT_RENDER) {
|
|
3567
|
-
this.
|
|
3697
|
+
this.Xe.notify(this, STATUS_PENDING | STATUS_ERROR, n, r);
|
|
3568
3698
|
}
|
|
3569
3699
|
}
|
|
3570
3700
|
|
|
@@ -3580,41 +3710,41 @@ function runEffect(e) {
|
|
|
3580
3710
|
// Render effects bypass: their errors route to boundaries synchronously in
|
|
3581
3711
|
// notifyEffectStatus, and a runner queued by an earlier valueChanged in the
|
|
3582
3712
|
// same flush must not be hijacked by a later-arriving error status.
|
|
3583
|
-
if (e.
|
|
3713
|
+
if (e.He & STATUS_ERROR && e.Fe === EFFECT_USER) {
|
|
3584
3714
|
const t = unwrapStatusError(e.me);
|
|
3585
|
-
e.
|
|
3715
|
+
e.Dt = e.We;
|
|
3586
3716
|
e.Qe = false;
|
|
3587
3717
|
try {
|
|
3588
|
-
e.
|
|
3589
|
-
const t = e.
|
|
3590
|
-
e.
|
|
3718
|
+
e.vt ? e.vt(t, () => {
|
|
3719
|
+
const t = e.dt;
|
|
3720
|
+
e.dt = undefined;
|
|
3591
3721
|
t?.();
|
|
3592
3722
|
}) : console.error(t);
|
|
3593
3723
|
} catch (t) {
|
|
3594
|
-
if (!e.
|
|
3724
|
+
if (!e.Xe.notify(e, STATUS_ERROR, STATUS_ERROR)) {
|
|
3595
3725
|
haltReactivity(t);
|
|
3596
3726
|
throw t;
|
|
3597
3727
|
}
|
|
3598
3728
|
}
|
|
3599
3729
|
return;
|
|
3600
3730
|
}
|
|
3601
|
-
const t = e.
|
|
3602
|
-
e.
|
|
3731
|
+
const t = e.dt;
|
|
3732
|
+
e.dt = undefined;
|
|
3603
3733
|
try {
|
|
3604
3734
|
t?.();
|
|
3605
|
-
const n = e.
|
|
3735
|
+
const n = e.wt(e.We, e.Dt);
|
|
3606
3736
|
if (false && n !== undefined && typeof n !== "function") ;
|
|
3607
3737
|
// The final cleanup is invoked by disposeChildren at true disposal.
|
|
3608
|
-
e.
|
|
3738
|
+
e.dt = n;
|
|
3609
3739
|
} catch (t) {
|
|
3610
3740
|
e.me = new StatusError(e, t);
|
|
3611
|
-
e.
|
|
3612
|
-
if (!e.
|
|
3741
|
+
e.He |= STATUS_ERROR;
|
|
3742
|
+
if (!e.Xe.notify(e, STATUS_ERROR, STATUS_ERROR)) {
|
|
3613
3743
|
haltReactivity(t);
|
|
3614
3744
|
throw t;
|
|
3615
3745
|
}
|
|
3616
3746
|
} finally {
|
|
3617
|
-
e.
|
|
3747
|
+
e.Dt = e.We;
|
|
3618
3748
|
e.Qe = false;
|
|
3619
3749
|
}
|
|
3620
3750
|
}
|
|
@@ -3634,32 +3764,32 @@ GlobalQueue.te = runEffect;
|
|
|
3634
3764
|
} finally {}
|
|
3635
3765
|
};
|
|
3636
3766
|
const n = computed(() => {
|
|
3637
|
-
const t = n.
|
|
3638
|
-
n.
|
|
3767
|
+
const t = n.dt;
|
|
3768
|
+
n.dt = undefined;
|
|
3639
3769
|
t?.();
|
|
3640
3770
|
const r = staleValues(e);
|
|
3641
|
-
n.
|
|
3771
|
+
n.dt = r;
|
|
3642
3772
|
}, {
|
|
3643
3773
|
...t,
|
|
3644
3774
|
lazy: true
|
|
3645
3775
|
});
|
|
3646
|
-
n.
|
|
3776
|
+
n.dt = undefined;
|
|
3647
3777
|
n.Ue = n.Ue & ~CONFIG_AUTO_DISPOSE | CONFIG_CHILDREN_FORBIDDEN;
|
|
3648
3778
|
n.Qe = true;
|
|
3649
3779
|
n.Fe = EFFECT_TRACKED;
|
|
3650
3780
|
n.yt = (e, t) => {
|
|
3651
|
-
const r = e !== undefined ? e : n.
|
|
3781
|
+
const r = e !== undefined ? e : n.He;
|
|
3652
3782
|
if (r & STATUS_ERROR) {
|
|
3653
|
-
n.
|
|
3783
|
+
n.Xe.notify(n, STATUS_PENDING, 0);
|
|
3654
3784
|
const e = t !== undefined ? t : n.me;
|
|
3655
|
-
if (!n.
|
|
3785
|
+
if (!n.Xe.notify(n, STATUS_ERROR, STATUS_ERROR)) {
|
|
3656
3786
|
haltReactivity(unwrapStatusError(e));
|
|
3657
3787
|
throw e;
|
|
3658
3788
|
}
|
|
3659
3789
|
}
|
|
3660
3790
|
};
|
|
3661
|
-
n.
|
|
3662
|
-
n.
|
|
3791
|
+
n.ze = run;
|
|
3792
|
+
n.Xe.enqueue(EFFECT_USER, run);
|
|
3663
3793
|
}
|
|
3664
3794
|
|
|
3665
3795
|
function restoreTransition(e, t) {
|
|
@@ -3852,38 +3982,6 @@ function createSignal(e, t) {
|
|
|
3852
3982
|
return [ accessor(n), setSignal.bind(null, n) ];
|
|
3853
3983
|
}
|
|
3854
3984
|
|
|
3855
|
-
/**
|
|
3856
|
-
* Creates a readonly derived reactive memoized signal.
|
|
3857
|
-
*
|
|
3858
|
-
* ```typescript
|
|
3859
|
-
* const value = createMemo<T>(compute, options?: MemoOptions<T>);
|
|
3860
|
-
* ```
|
|
3861
|
-
* @param compute a function that receives its previous value and returns a new value used to react on a computation
|
|
3862
|
-
* @param options `MemoOptions` -- id, name, equals, unobserved, lazy
|
|
3863
|
-
*
|
|
3864
|
-
* @example
|
|
3865
|
-
* ```ts
|
|
3866
|
-
* const [first, setFirst] = createSignal("Ada");
|
|
3867
|
-
* const [last, setLast] = createSignal("Lovelace");
|
|
3868
|
-
*
|
|
3869
|
-
* const fullName = createMemo(() => `${first()} ${last()}`);
|
|
3870
|
-
*
|
|
3871
|
-
* fullName(); // "Ada Lovelace"
|
|
3872
|
-
* ```
|
|
3873
|
-
*
|
|
3874
|
-
* @example
|
|
3875
|
-
* ```ts
|
|
3876
|
-
* // Async memo — reads surface as pending inside <Loading>
|
|
3877
|
-
* const user = createMemo(async () => {
|
|
3878
|
-
* const res = await fetch(`/users/${id()}`);
|
|
3879
|
-
* return res.json();
|
|
3880
|
-
* });
|
|
3881
|
-
* ```
|
|
3882
|
-
*
|
|
3883
|
-
* @description https://docs.solidjs.com/reference/basic-reactivity/create-memo
|
|
3884
|
-
*/
|
|
3885
|
-
// NoInfer keeps the previous-value parameter from influencing T inference, so
|
|
3886
|
-
// the memo/effect result type is still driven by the compute return type.
|
|
3887
3985
|
function createMemo(e, t) {
|
|
3888
3986
|
return accessor(computed(e, t));
|
|
3889
3987
|
}
|
|
@@ -3909,7 +4007,7 @@ function createEffect(e, t, n) {
|
|
|
3909
4007
|
* ```
|
|
3910
4008
|
* @param compute a function that receives its previous value and returns a new value used to react on a computation
|
|
3911
4009
|
* @param effectFn a function that receives the new value and is used to perform side effects
|
|
3912
|
-
* @param options `EffectOptions` -- name, defer, schedule
|
|
4010
|
+
* @param options `EffectOptions` -- name, defer, schedule, transparent
|
|
3913
4011
|
*
|
|
3914
4012
|
* @example
|
|
3915
4013
|
* ```ts
|
|
@@ -4057,9 +4155,9 @@ function createEffect(e, t, n) {
|
|
|
4057
4155
|
// route through the inherited queue.
|
|
4058
4156
|
const i = getOwner();
|
|
4059
4157
|
const o = new MicrotaskQueue;
|
|
4060
|
-
o.Z = i.
|
|
4158
|
+
o.Z = i.Xe;
|
|
4061
4159
|
// notify() forwards up the normal chain
|
|
4062
|
-
i.
|
|
4160
|
+
i.Xe = o;
|
|
4063
4161
|
// A user effect rather than a bare computed: computeds are pull-based and
|
|
4064
4162
|
// are only re-enqueued when a pending source *resolves* — a rejection just
|
|
4065
4163
|
// marks them errored, so nothing would re-run and the promise would never
|
|
@@ -4906,10 +5004,18 @@ function createProjectionInternal(e, t, n) {
|
|
|
4906
5004
|
return t;
|
|
4907
5005
|
};
|
|
4908
5006
|
const s = wrapProjection(t);
|
|
5007
|
+
// seedLoadingValue: the firewall is born committed (the seed is commit #0);
|
|
5008
|
+
// the internal handleAsync serves it during the derive's first flight. The
|
|
5009
|
+
// node's own value channel is void, so the loading value itself is
|
|
5010
|
+
// `undefined` — presence of the key is what flips the mode.
|
|
5011
|
+
let u;
|
|
5012
|
+
if (n?.seedLoadingValue) u = {
|
|
5013
|
+
loadingValue: undefined
|
|
5014
|
+
};
|
|
4909
5015
|
r = computed(() => {
|
|
4910
5016
|
if (!r) r = getOwner();
|
|
4911
5017
|
runProjectionComputed(s, e, n?.key === undefined ? "id" : n.key);
|
|
4912
|
-
},
|
|
5018
|
+
}, u);
|
|
4913
5019
|
r.Ue &= ~CONFIG_AUTO_DISPOSE;
|
|
4914
5020
|
return {
|
|
4915
5021
|
store: s,
|
|
@@ -4984,16 +5090,43 @@ function createProjectionInternal(e, t, n) {
|
|
|
4984
5090
|
const o = getOwner();
|
|
4985
5091
|
let s = false;
|
|
4986
5092
|
let u;
|
|
4987
|
-
|
|
4988
|
-
|
|
4989
|
-
|
|
5093
|
+
// Open loading window (seedLoadingValue): the observable store IS commit #0
|
|
5094
|
+
// for the whole first flight, so the derive works a detached shadow of the
|
|
5095
|
+
// seed — draft writes (pre-await, or between yields) land on the shadow and
|
|
5096
|
+
// cannot tear through to readers (#2988; store reads resolve from the live
|
|
5097
|
+
// backing, and the born-committed firewall removed the status gate that hid
|
|
5098
|
+
// windowless drafts). Every commit point — sync return, each yield, the
|
|
5099
|
+
// async landing — reconciles the shadow through the normal commit path, so
|
|
5100
|
+
// a fully-sync derive still lands immediately (commit #0 superseded before
|
|
5101
|
+
// any observer runs, same as a sync answer superseding loadingValue). The
|
|
5102
|
+
// JSON round-trip matches the server's frozen-seed copy (seedLock): a
|
|
5103
|
+
// loading-window seed is renderable data by contract. Optimistic note:
|
|
5104
|
+
// onDraftWrite (override clearing) shifts from write-time to commit-time
|
|
5105
|
+
// for the shadow run — an invisible draft write must not clobber a visible
|
|
5106
|
+
// optimistic override mid-window.
|
|
5107
|
+
const l = o.xe ? JSON.parse(JSON.stringify(e[$TARGET][STORE_VALUE])) : null;
|
|
5108
|
+
const a = new Proxy(e, createWriteTraps(() => !s || o.ct === u, i));
|
|
5109
|
+
storeSetter(a, i => {
|
|
5110
|
+
u = t(l ?? i);
|
|
4990
5111
|
s = true;
|
|
4991
5112
|
const commit = t => {
|
|
5113
|
+
// Shadow run: a void/self return is the mutation form — the shadow
|
|
5114
|
+
// carries the writes and is what commits. Commit a detached snapshot,
|
|
5115
|
+
// never the shadow itself: reconcile adopts a new root value by
|
|
5116
|
+
// identity, and handing it the live shadow would fuse the draft to the
|
|
5117
|
+
// observable store — later shadow writes would mutate the backing
|
|
5118
|
+
// silently and the next yield would diff the shadow against itself.
|
|
5119
|
+
if (l && (t === undefined || t === l)) t = JSON.parse(JSON.stringify(l));
|
|
4992
5120
|
if (t === i || t === undefined) return;
|
|
4993
5121
|
const write = () => storeSetter(e, e => reconcileState(t, e, n, true));
|
|
4994
5122
|
r ? r(write) : write();
|
|
4995
5123
|
};
|
|
4996
|
-
|
|
5124
|
+
const a = handleAsync(o, u, commit);
|
|
5125
|
+
// A still-open window after handleAsync means the return was the
|
|
5126
|
+
// commit-#0 fall-through, not a landing — real landings arrive through
|
|
5127
|
+
// the setter. A closed one is a genuine sync landing (windowless nodes
|
|
5128
|
+
// were never open); commit it.
|
|
5129
|
+
if (!o.xe) commit(a);
|
|
4997
5130
|
});
|
|
4998
5131
|
return o;
|
|
4999
5132
|
}
|
|
@@ -5653,7 +5786,7 @@ function prepareStoreWrite(e, t, n) {
|
|
|
5653
5786
|
}
|
|
5654
5787
|
const r = e[STORE_VALUE];
|
|
5655
5788
|
const i = r[n];
|
|
5656
|
-
if (snapshotCaptureActive && typeof n !== "symbol" && !((e[STORE_FIREWALL]?.
|
|
5789
|
+
if (snapshotCaptureActive && typeof n !== "symbol" && !((e[STORE_FIREWALL]?.He ?? 0) & STATUS_PENDING)) {
|
|
5657
5790
|
if (!e[STORE_SNAPSHOT_PROPS]) {
|
|
5658
5791
|
e[STORE_SNAPSHOT_PROPS] = Object.create(null);
|
|
5659
5792
|
snapshotSources?.add(e);
|
|
@@ -5776,7 +5909,7 @@ let Writing = null;
|
|
|
5776
5909
|
*/ function throwIfUnreadable(e) {
|
|
5777
5910
|
const t = e[STORE_FIREWALL];
|
|
5778
5911
|
if (!t) return;
|
|
5779
|
-
const n = t.
|
|
5912
|
+
const n = t.He;
|
|
5780
5913
|
if (n & STATUS_ERROR || n & STATUS_UNINITIALIZED && n & STATUS_PENDING) throw t.me ?? new NotReadyError(t);
|
|
5781
5914
|
}
|
|
5782
5915
|
|
|
@@ -6139,7 +6272,7 @@ function createStore(e, t, n) {
|
|
|
6139
6272
|
* flush that would surface them, before effects run — verdict-only, netting
|
|
6140
6273
|
* no visual change.
|
|
6141
6274
|
*/ function notifyMarkBoundaries(e) {
|
|
6142
|
-
if (!e.U && !e.
|
|
6275
|
+
if (!e.U && !e.it) return;
|
|
6143
6276
|
const t = new NotReadyError(e);
|
|
6144
6277
|
t.ve = true;
|
|
6145
6278
|
const n = new Set;
|
|
@@ -6242,7 +6375,7 @@ function createOptimisticStore(e, t, n) {
|
|
|
6242
6375
|
const e = GlobalQueue.Ae;
|
|
6243
6376
|
GlobalQueue.Ae = t => {
|
|
6244
6377
|
for (const e of t.V) {
|
|
6245
|
-
if ((e[$TARGET]?.[STORE_FIREWALL]?.
|
|
6378
|
+
if ((e[$TARGET]?.[STORE_FIREWALL]?.He ?? 0) & STATUS_PENDING) return true;
|
|
6246
6379
|
}
|
|
6247
6380
|
return e(t);
|
|
6248
6381
|
};
|
|
@@ -6328,7 +6461,7 @@ function clearOptimisticStores(e, t) {
|
|
|
6328
6461
|
a.p = null;
|
|
6329
6462
|
a.k = NOT_PENDING;
|
|
6330
6463
|
a.We = i;
|
|
6331
|
-
if (!a.
|
|
6464
|
+
if (!a.Nt || !a.Nt(o, i)) {
|
|
6332
6465
|
insertSubs(a, true);
|
|
6333
6466
|
schedule();
|
|
6334
6467
|
}
|
|
@@ -6399,6 +6532,11 @@ function createOptimisticProjectionInternal(e, t, n) {
|
|
|
6399
6532
|
setProjectionWriteActive(t);
|
|
6400
6533
|
}
|
|
6401
6534
|
};
|
|
6535
|
+
// seedLoadingValue: born-committed firewall, same as createProjection.
|
|
6536
|
+
let t;
|
|
6537
|
+
if (n?.seedLoadingValue) t = {
|
|
6538
|
+
loadingValue: undefined
|
|
6539
|
+
};
|
|
6402
6540
|
r = computed(() => {
|
|
6403
6541
|
setProjectionWriteActive(true);
|
|
6404
6542
|
try {
|
|
@@ -6406,7 +6544,7 @@ function createOptimisticProjectionInternal(e, t, n) {
|
|
|
6406
6544
|
} finally {
|
|
6407
6545
|
setProjectionWriteActive(false);
|
|
6408
6546
|
}
|
|
6409
|
-
},
|
|
6547
|
+
}, t);
|
|
6410
6548
|
r.Ue &= ~CONFIG_AUTO_DISPOSE;
|
|
6411
6549
|
}
|
|
6412
6550
|
return {
|
|
@@ -6831,23 +6969,23 @@ function mapArray(e, t, n) {
|
|
|
6831
6969
|
const i = t.length > 1;
|
|
6832
6970
|
const o = t;
|
|
6833
6971
|
const s = {
|
|
6834
|
-
|
|
6835
|
-
|
|
6836
|
-
|
|
6837
|
-
|
|
6838
|
-
|
|
6839
|
-
kt: [],
|
|
6972
|
+
Lt: createOwner(),
|
|
6973
|
+
Gt: 0,
|
|
6974
|
+
Vt: e,
|
|
6975
|
+
Ut: [],
|
|
6976
|
+
kt: o,
|
|
6840
6977
|
Wt: [],
|
|
6841
|
-
Ft:
|
|
6842
|
-
Qt: r
|
|
6843
|
-
xt:
|
|
6844
|
-
Ht: n?.keyed
|
|
6845
|
-
Mt: n?.
|
|
6978
|
+
Ft: [],
|
|
6979
|
+
Qt: r,
|
|
6980
|
+
xt: r || n?.keyed === false ? [] : undefined,
|
|
6981
|
+
Ht: i && n?.keyed !== false ? [] : undefined,
|
|
6982
|
+
Mt: n?.keyed === false,
|
|
6983
|
+
$t: n?.fallback
|
|
6846
6984
|
};
|
|
6847
6985
|
const u = computed(updateKeyedMap.bind(s));
|
|
6848
6986
|
// Untracked reads inside the internal owner resolve via _parentComputed; routing
|
|
6849
6987
|
// them through node lets store-proxy lookups see pending writes (not stale _value).
|
|
6850
|
-
s.
|
|
6988
|
+
s.Lt.tt = u;
|
|
6851
6989
|
u.Ue &= ~CONFIG_AUTO_DISPOSE;
|
|
6852
6990
|
return accessor(u);
|
|
6853
6991
|
}
|
|
@@ -6866,52 +7004,52 @@ const pureOptions = {
|
|
|
6866
7004
|
// strong-abort ordering: removed rows now dispose AFTER the pass's new rows
|
|
6867
7005
|
// are created (you cannot destroy state before knowing the pass will land).
|
|
6868
7006
|
function updateKeyedMap() {
|
|
6869
|
-
const e = this.
|
|
7007
|
+
const e = this.Vt() || [], t = e.length;
|
|
6870
7008
|
e[$TRACK];
|
|
6871
7009
|
// top level tracking
|
|
6872
|
-
runWithOwner(this.
|
|
7010
|
+
runWithOwner(this.Lt, () => {
|
|
6873
7011
|
let n, r, i, o,
|
|
6874
7012
|
// Mappers write freshly-created row/index signals into the STAGE
|
|
6875
7013
|
// arrays (`rows`/`indexes`), never into `this._rows`/`this._indexes`.
|
|
6876
|
-
s = this.
|
|
7014
|
+
s = this.xt ? this.Mt ? () => {
|
|
6877
7015
|
i[r] = signal(e[r], pureOptions);
|
|
6878
|
-
return this.
|
|
7016
|
+
return this.kt(accessor(i[r]), r);
|
|
6879
7017
|
} : () => {
|
|
6880
7018
|
i[r] = signal(e[r], pureOptions);
|
|
6881
7019
|
o && (o[r] = signal(r, pureOptions));
|
|
6882
|
-
return this.
|
|
6883
|
-
} : this.
|
|
7020
|
+
return this.kt(accessor(i[r]), o ? accessor(o[r]) : undefined);
|
|
7021
|
+
} : this.Ht ? () => {
|
|
6884
7022
|
const t = e[r];
|
|
6885
7023
|
o[r] = signal(r, pureOptions);
|
|
6886
|
-
return this.
|
|
7024
|
+
return this.kt(t, accessor(o[r]));
|
|
6887
7025
|
} : () => {
|
|
6888
7026
|
const t = e[r];
|
|
6889
|
-
return this.
|
|
7027
|
+
return this.kt(t);
|
|
6890
7028
|
};
|
|
6891
7029
|
// fast path for empty arrays
|
|
6892
7030
|
if (t === 0) {
|
|
6893
|
-
if (this.
|
|
6894
|
-
this.
|
|
7031
|
+
if (this.Gt !== 0) {
|
|
7032
|
+
this.Lt.dispose(false);
|
|
7033
|
+
this.Ft = [];
|
|
7034
|
+
this.Ut = [];
|
|
6895
7035
|
this.Wt = [];
|
|
6896
|
-
this.
|
|
6897
|
-
this.kt = [];
|
|
6898
|
-
this.Lt = 0;
|
|
6899
|
-
this.Qt && (this.Qt = []);
|
|
7036
|
+
this.Gt = 0;
|
|
6900
7037
|
this.xt && (this.xt = []);
|
|
7038
|
+
this.Ht && (this.Ht = []);
|
|
6901
7039
|
}
|
|
6902
|
-
if (this
|
|
7040
|
+
if (this.$t && !this.Wt[0]) {
|
|
6903
7041
|
// an aborted fallback attempt leaves an owner without a mapping;
|
|
6904
7042
|
// dispose it before re-creating
|
|
6905
|
-
this.
|
|
6906
|
-
this.
|
|
7043
|
+
this.Ft[0]?.dispose();
|
|
7044
|
+
this.Wt[0] = runWithOwner(this.Ft[0] = createOwner(), this.$t);
|
|
6907
7045
|
}
|
|
6908
7046
|
}
|
|
6909
7047
|
// fast path for new create
|
|
6910
|
-
else if (this.
|
|
7048
|
+
else if (this.Gt === 0) {
|
|
6911
7049
|
const u = new Array(t);
|
|
6912
7050
|
const l = new Array(t);
|
|
6913
|
-
i = this.
|
|
6914
|
-
o = this.
|
|
7051
|
+
i = this.xt && new Array(t);
|
|
7052
|
+
o = this.Ht && new Array(t);
|
|
6915
7053
|
try {
|
|
6916
7054
|
for (r = 0; r < t; r++) u[r] = runWithOwner(l[r] = createOwner(), s);
|
|
6917
7055
|
} catch (e) {
|
|
@@ -6919,43 +7057,43 @@ function updateKeyedMap() {
|
|
|
6919
7057
|
throw e;
|
|
6920
7058
|
}
|
|
6921
7059
|
// commit
|
|
6922
|
-
if (this.
|
|
7060
|
+
if (this.Ft[0]) this.Ft[0].dispose();
|
|
6923
7061
|
// previous fallback
|
|
6924
|
-
this.
|
|
6925
|
-
this.
|
|
6926
|
-
i && (this.
|
|
6927
|
-
o && (this.
|
|
6928
|
-
this.
|
|
6929
|
-
this.
|
|
7062
|
+
this.Wt = u;
|
|
7063
|
+
this.Ft = l;
|
|
7064
|
+
i && (this.xt = i);
|
|
7065
|
+
o && (this.Ht = o);
|
|
7066
|
+
this.Ut = e.slice(0);
|
|
7067
|
+
this.Gt = t;
|
|
6930
7068
|
} else {
|
|
6931
7069
|
let u, l, a, c, f, E, d, S, T;
|
|
6932
7070
|
// skip common prefix
|
|
6933
|
-
for (u = 0, l = Math.min(this.
|
|
6934
|
-
if (this.
|
|
7071
|
+
for (u = 0, l = Math.min(this.Gt, t); u < l && (this.Ut[u] === e[u] || this.xt && compare(this.Qt, this.Ut[u], e[u])); u++) {
|
|
7072
|
+
if (this.xt) setSignal(this.xt[u], e[u]);
|
|
6935
7073
|
}
|
|
6936
7074
|
// skip common suffix — counted only; retained entries land in one pass
|
|
6937
7075
|
// at commit instead of being staged and copied twice
|
|
6938
|
-
for (l = this.
|
|
7076
|
+
for (l = this.Gt - 1, a = t - 1; l >= u && a >= u && (this.Ut[l] === e[a] || this.xt && compare(this.Qt, this.Ut[l], e[a])); l--,
|
|
6939
7077
|
a--) ;
|
|
6940
7078
|
// no structural change (every position matched in place at equal
|
|
6941
7079
|
// length — the common post-reconcile shape): keep the same mapped
|
|
6942
7080
|
// array identity so downstream consumers don't re-run at all
|
|
6943
|
-
if (u === t && this.
|
|
6944
|
-
this.
|
|
7081
|
+
if (u === t && this.Gt === t) {
|
|
7082
|
+
this.Ut = e.slice(0);
|
|
6945
7083
|
return;
|
|
6946
7084
|
}
|
|
6947
|
-
const O = t - this.
|
|
7085
|
+
const O = t - this.Gt;
|
|
6948
7086
|
const _ = new Array(t);
|
|
6949
7087
|
const R = new Array(t);
|
|
6950
|
-
i = this.
|
|
6951
|
-
o = this.
|
|
7088
|
+
i = this.xt ? new Array(t) : undefined;
|
|
7089
|
+
o = this.Ht ? new Array(t) : undefined;
|
|
6952
7090
|
// 0) prepare a map of all indices in the changed window of newItems,
|
|
6953
7091
|
// scanning backwards so we encounter them in natural order
|
|
6954
7092
|
E = new Map;
|
|
6955
7093
|
d = new Array(a + 1);
|
|
6956
7094
|
for (r = a; r >= u; r--) {
|
|
6957
7095
|
c = e[r];
|
|
6958
|
-
f = this.
|
|
7096
|
+
f = this.Qt ? this.Qt(c) : c;
|
|
6959
7097
|
n = E.get(f);
|
|
6960
7098
|
d[r] = n === undefined ? -1 : n;
|
|
6961
7099
|
E.set(f, r);
|
|
@@ -6964,17 +7102,17 @@ function updateKeyedMap() {
|
|
|
6964
7102
|
// in the new set; if so, stage them at their new positions; if not,
|
|
6965
7103
|
// queue them for disposal at commit
|
|
6966
7104
|
for (n = u; n <= l; n++) {
|
|
6967
|
-
c = this.
|
|
6968
|
-
f = this.
|
|
7105
|
+
c = this.Ut[n];
|
|
7106
|
+
f = this.Qt ? this.Qt(c) : c;
|
|
6969
7107
|
r = E.get(f);
|
|
6970
7108
|
if (r !== undefined && r !== -1) {
|
|
6971
|
-
_[r] = this.
|
|
6972
|
-
R[r] = this.
|
|
6973
|
-
i && (i[r] = this.
|
|
6974
|
-
o && (o[r] = this.
|
|
7109
|
+
_[r] = this.Wt[n];
|
|
7110
|
+
R[r] = this.Ft[n];
|
|
7111
|
+
i && (i[r] = this.xt[n]);
|
|
7112
|
+
o && (o[r] = this.Ht[n]);
|
|
6975
7113
|
r = d[r];
|
|
6976
7114
|
E.set(f, r);
|
|
6977
|
-
} else (S ??= []).push(this.
|
|
7115
|
+
} else (S ??= []).push(this.Ft[n]);
|
|
6978
7116
|
}
|
|
6979
7117
|
// 2) create new rows into the temp arrays; an abort disposes only these
|
|
6980
7118
|
try {
|
|
@@ -6991,38 +7129,38 @@ function updateKeyedMap() {
|
|
|
6991
7129
|
// into the fresh arrays, swap them in (new identity for downstream
|
|
6992
7130
|
// change propagation), then dispose exited rows
|
|
6993
7131
|
for (n = 0; n < u; n++) {
|
|
6994
|
-
_[n] = this.
|
|
6995
|
-
R[n] = this.
|
|
6996
|
-
i && (i[n] = this.
|
|
6997
|
-
o && (o[n] = this.
|
|
7132
|
+
_[n] = this.Wt[n];
|
|
7133
|
+
R[n] = this.Ft[n];
|
|
7134
|
+
i && (i[n] = this.xt[n]);
|
|
7135
|
+
o && (o[n] = this.Ht[n]);
|
|
6998
7136
|
}
|
|
6999
7137
|
for (r = u; r <= a; r++) {
|
|
7000
7138
|
if (i) setSignal(i[r], e[r]);
|
|
7001
7139
|
if (o) setSignal(o[r], r);
|
|
7002
7140
|
}
|
|
7003
7141
|
for (r = a + 1; r < t; r++) {
|
|
7004
|
-
_[r] = this.
|
|
7005
|
-
R[r] = this.
|
|
7142
|
+
_[r] = this.Wt[r - O];
|
|
7143
|
+
R[r] = this.Ft[r - O];
|
|
7006
7144
|
if (i) {
|
|
7007
|
-
i[r] = this.
|
|
7145
|
+
i[r] = this.xt[r - O];
|
|
7008
7146
|
setSignal(i[r], e[r]);
|
|
7009
7147
|
}
|
|
7010
7148
|
if (o) {
|
|
7011
|
-
o[r] = this.
|
|
7149
|
+
o[r] = this.Ht[r - O];
|
|
7012
7150
|
if (O !== 0) setSignal(o[r], r);
|
|
7013
7151
|
}
|
|
7014
7152
|
}
|
|
7015
|
-
this.
|
|
7016
|
-
this.
|
|
7017
|
-
i && (this.
|
|
7018
|
-
o && (this.
|
|
7019
|
-
this.
|
|
7153
|
+
this.Wt = _;
|
|
7154
|
+
this.Ft = R;
|
|
7155
|
+
i && (this.xt = i);
|
|
7156
|
+
o && (this.Ht = o);
|
|
7157
|
+
this.Gt = t;
|
|
7020
7158
|
// save a copy of the mapped items for the next update
|
|
7021
|
-
this.
|
|
7159
|
+
this.Ut = e.slice(0);
|
|
7022
7160
|
if (S) for (n = 0; n < S.length; n++) S[n].dispose();
|
|
7023
7161
|
}
|
|
7024
7162
|
});
|
|
7025
|
-
return this.
|
|
7163
|
+
return this.Wt;
|
|
7026
7164
|
}
|
|
7027
7165
|
|
|
7028
7166
|
/**
|
|
@@ -7042,21 +7180,21 @@ function updateKeyedMap() {
|
|
|
7042
7180
|
*/ function repeat(e, t, n) {
|
|
7043
7181
|
const r = t;
|
|
7044
7182
|
const i = {
|
|
7045
|
-
|
|
7046
|
-
|
|
7047
|
-
|
|
7048
|
-
|
|
7049
|
-
|
|
7183
|
+
Lt: createOwner(),
|
|
7184
|
+
Gt: 0,
|
|
7185
|
+
jt: 0,
|
|
7186
|
+
Kt: e,
|
|
7187
|
+
kt: r,
|
|
7188
|
+
Ft: [],
|
|
7050
7189
|
Wt: [],
|
|
7051
|
-
|
|
7052
|
-
|
|
7053
|
-
Mt: n?.fallback
|
|
7190
|
+
Yt: n?.from,
|
|
7191
|
+
$t: n?.fallback
|
|
7054
7192
|
};
|
|
7055
7193
|
const o = computed(updateRepeat.bind(i));
|
|
7056
7194
|
// Same as mapArray: untracked reads inside the internal owner resolve via
|
|
7057
7195
|
// _parentComputed, so async reads in row callbacks register with the node
|
|
7058
7196
|
// (pending tracking + post-settle retry) instead of vanishing.
|
|
7059
|
-
i.
|
|
7197
|
+
i.Lt.tt = o;
|
|
7060
7198
|
o.Ue &= ~CONFIG_AUTO_DISPOSE;
|
|
7061
7199
|
return accessor(o);
|
|
7062
7200
|
}
|
|
@@ -7069,55 +7207,55 @@ function updateKeyedMap() {
|
|
|
7069
7207
|
// for the post-settle retry. The overlap math also subsumes the previous
|
|
7070
7208
|
// disjoint-window/front-clear/end-clear/shift special cases.
|
|
7071
7209
|
function updateRepeat() {
|
|
7072
|
-
const e = this.
|
|
7073
|
-
const t = this.
|
|
7074
|
-
runWithOwner(this.
|
|
7210
|
+
const e = this.Kt();
|
|
7211
|
+
const t = this.Yt?.() || 0;
|
|
7212
|
+
runWithOwner(this.Lt, () => {
|
|
7075
7213
|
if (e === 0) {
|
|
7076
|
-
if (this.
|
|
7077
|
-
this.
|
|
7214
|
+
if (this.Gt !== 0) {
|
|
7215
|
+
this.Lt.dispose(false);
|
|
7216
|
+
this.Ft = [];
|
|
7078
7217
|
this.Wt = [];
|
|
7079
|
-
this.
|
|
7080
|
-
this.Lt = 0;
|
|
7218
|
+
this.Gt = 0;
|
|
7081
7219
|
// Reset offset to match the cleared data (#2767, repro 2).
|
|
7082
|
-
this
|
|
7220
|
+
this.jt = 0;
|
|
7083
7221
|
}
|
|
7084
|
-
if (this
|
|
7222
|
+
if (this.$t && !this.Wt[0]) {
|
|
7085
7223
|
// an aborted fallback attempt leaves an owner without a mapping;
|
|
7086
7224
|
// dispose it before re-creating
|
|
7087
|
-
this.
|
|
7088
|
-
this.
|
|
7225
|
+
this.Ft[0]?.dispose();
|
|
7226
|
+
this.Wt[0] = runWithOwner(this.Ft[0] = createOwner(), this.$t);
|
|
7089
7227
|
}
|
|
7090
7228
|
return;
|
|
7091
7229
|
}
|
|
7092
7230
|
const n = t + e;
|
|
7093
|
-
const r = this
|
|
7231
|
+
const r = this.jt + this.Gt;
|
|
7094
7232
|
// Retained overlap [keepStart, keepEnd) in global indexes; empty when the
|
|
7095
7233
|
// windows are disjoint or when coming from empty/fallback.
|
|
7096
|
-
const i = Math.max(t, this
|
|
7234
|
+
const i = Math.max(t, this.jt);
|
|
7097
7235
|
const o = Math.min(n, r);
|
|
7098
7236
|
const s = new Array(e);
|
|
7099
7237
|
const u = new Array(e);
|
|
7100
7238
|
for (let e = i; e < o; e++) {
|
|
7101
|
-
u[e - t] = this.
|
|
7102
|
-
s[e - t] = this.
|
|
7239
|
+
u[e - t] = this.Ft[e - this.jt];
|
|
7240
|
+
s[e - t] = this.Wt[e - this.jt];
|
|
7103
7241
|
}
|
|
7104
7242
|
try {
|
|
7105
7243
|
for (let e = t; e < n; e++) {
|
|
7106
7244
|
if (e >= i && e < o) continue;
|
|
7107
|
-
s[e - t] = runWithOwner(u[e - t] = createOwner(), () => this.
|
|
7245
|
+
s[e - t] = runWithOwner(u[e - t] = createOwner(), () => this.kt(e));
|
|
7108
7246
|
}
|
|
7109
7247
|
} catch (e) {
|
|
7110
7248
|
for (let e = t; e < n; e++) if ((e < i || e >= o) && u[e - t]) u[e - t].dispose();
|
|
7111
7249
|
throw e;
|
|
7112
7250
|
}
|
|
7113
7251
|
// commit: dispose the previous fallback or the rows leaving the window
|
|
7114
|
-
if (this.
|
|
7115
|
-
this.
|
|
7116
|
-
this.
|
|
7117
|
-
this
|
|
7118
|
-
this.
|
|
7252
|
+
if (this.Gt === 0) this.Ft[0]?.dispose(); else for (let e = this.jt; e < r; e++) if (e < t || e >= n) this.Ft[e - this.jt].dispose();
|
|
7253
|
+
this.Wt = s;
|
|
7254
|
+
this.Ft = u;
|
|
7255
|
+
this.jt = t;
|
|
7256
|
+
this.Gt = e;
|
|
7119
7257
|
});
|
|
7120
|
-
return this.
|
|
7258
|
+
return this.Wt;
|
|
7121
7259
|
}
|
|
7122
7260
|
|
|
7123
7261
|
function compare(e, t, n) {
|
|
@@ -7130,21 +7268,21 @@ function boundaryComputed(e, t) {
|
|
|
7130
7268
|
});
|
|
7131
7269
|
n.yt = (e, t) => {
|
|
7132
7270
|
// Use passed values if provided, otherwise read from node
|
|
7133
|
-
const r = e !== undefined ? e : n.
|
|
7271
|
+
const r = e !== undefined ? e : n.He;
|
|
7134
7272
|
const i = t !== undefined ? t : n.me;
|
|
7135
7273
|
// Notify both status dimensions like a render effect does; the queue chain
|
|
7136
7274
|
// consumes this boundary's own type and forwards the remainder upward until
|
|
7137
7275
|
// a boundary that handles it is found.
|
|
7138
|
-
n.
|
|
7139
|
-
const o = n.
|
|
7276
|
+
n.He &= ~n.qt;
|
|
7277
|
+
const o = n.Xe.notify(n, STATUS_PENDING | STATUS_ERROR, r, i);
|
|
7140
7278
|
// The queue is the only propagation channel: a foreign status must not stay
|
|
7141
7279
|
// reader-visible on the tree, or reads re-throw it across the boundary and
|
|
7142
7280
|
// link unrelated ambient contexts (the #2809 nested-boundary loop). Deps are
|
|
7143
7281
|
// untouched, so the tree still recomputes when the foreign source settles.
|
|
7144
|
-
const s = r & ~n.
|
|
7282
|
+
const s = r & ~n.qt & (STATUS_PENDING | STATUS_ERROR);
|
|
7145
7283
|
if (s) {
|
|
7146
|
-
n.
|
|
7147
|
-
if (n.me === i && !(n.
|
|
7284
|
+
n.He &= ~s;
|
|
7285
|
+
if (n.me === i && !(n.He & (STATUS_PENDING | STATUS_ERROR))) n.me = undefined;
|
|
7148
7286
|
}
|
|
7149
7287
|
// An ERROR the chain could not deliver to any boundary is uncaught. The
|
|
7150
7288
|
// scrub above already removed it from reader-visible state, so without
|
|
@@ -7155,16 +7293,16 @@ function boundaryComputed(e, t) {
|
|
|
7155
7293
|
throw i;
|
|
7156
7294
|
}
|
|
7157
7295
|
};
|
|
7158
|
-
n.
|
|
7296
|
+
n.qt = t;
|
|
7159
7297
|
n.Ue &= ~CONFIG_AUTO_DISPOSE;
|
|
7160
7298
|
recompute(n, true);
|
|
7161
7299
|
return n;
|
|
7162
7300
|
}
|
|
7163
7301
|
|
|
7164
7302
|
function createBoundChildren(e, t, n, r) {
|
|
7165
|
-
const i = e.
|
|
7166
|
-
i.addChild(e.
|
|
7167
|
-
cleanup(() => i.removeChild(e.
|
|
7303
|
+
const i = e.Xe;
|
|
7304
|
+
i.addChild(e.Xe = n);
|
|
7305
|
+
cleanup(() => i.removeChild(e.Xe));
|
|
7168
7306
|
return runWithOwner(e, () => {
|
|
7169
7307
|
const e = computed(t);
|
|
7170
7308
|
return boundaryComputed(() => flatten(read(e)), r);
|
|
@@ -7186,53 +7324,53 @@ function isRevealController(e) {
|
|
|
7186
7324
|
}
|
|
7187
7325
|
|
|
7188
7326
|
function isSlotReady(e) {
|
|
7189
|
-
return isRevealController(e) ? e.
|
|
7327
|
+
return isRevealController(e) ? e.Bt() : e.Zt.size === 0 && !e.Xt;
|
|
7190
7328
|
}
|
|
7191
7329
|
|
|
7192
7330
|
function isSlotMinimallyReady(e) {
|
|
7193
|
-
return isRevealController(e) ? e.
|
|
7331
|
+
return isRevealController(e) ? e.zt() : isSlotReady(e);
|
|
7194
7332
|
}
|
|
7195
7333
|
|
|
7196
7334
|
function setSlotState(e, t, n, r) {
|
|
7197
|
-
setSignal(e.
|
|
7198
|
-
setSignal(e.
|
|
7335
|
+
setSignal(e.Jt, n);
|
|
7336
|
+
setSignal(e.en, r);
|
|
7199
7337
|
if (isRevealController(e)) {
|
|
7200
|
-
if (!n && e.
|
|
7201
|
-
return e.
|
|
7338
|
+
if (!n && e.tn === t) e.tn = undefined;
|
|
7339
|
+
return e.nn(n, r);
|
|
7202
7340
|
}
|
|
7203
|
-
if (!n && e.
|
|
7341
|
+
if (!n && e.rn === t && e.sn) e.rn = undefined;
|
|
7204
7342
|
}
|
|
7205
7343
|
|
|
7206
7344
|
class RevealController {
|
|
7207
|
-
sn;
|
|
7208
7345
|
un;
|
|
7209
|
-
ln
|
|
7210
|
-
|
|
7211
|
-
|
|
7346
|
+
ln;
|
|
7347
|
+
an=[];
|
|
7348
|
+
tn;
|
|
7349
|
+
Jt=signal(false, {
|
|
7212
7350
|
ownedWrite: true,
|
|
7213
|
-
|
|
7351
|
+
bt: true
|
|
7214
7352
|
});
|
|
7215
|
-
|
|
7353
|
+
en=signal(false, {
|
|
7216
7354
|
ownedWrite: true,
|
|
7217
|
-
|
|
7355
|
+
bt: true
|
|
7218
7356
|
});
|
|
7219
|
-
an=true;
|
|
7220
7357
|
cn=true;
|
|
7221
|
-
fn=
|
|
7358
|
+
fn=true;
|
|
7359
|
+
En=false;
|
|
7222
7360
|
constructor(e, t) {
|
|
7223
|
-
this.
|
|
7224
|
-
this.
|
|
7361
|
+
this.un = e;
|
|
7362
|
+
this.ln = t;
|
|
7225
7363
|
}
|
|
7226
|
-
|
|
7227
|
-
for (let t = 0; t < this.
|
|
7228
|
-
const n = this.
|
|
7229
|
-
if ((isRevealController(n) ? n.
|
|
7364
|
+
dn(e) {
|
|
7365
|
+
for (let t = 0; t < this.an.length; t++) {
|
|
7366
|
+
const n = this.an[t];
|
|
7367
|
+
if ((isRevealController(n) ? n.tn : n.rn) !== this) continue;
|
|
7230
7368
|
if (e(n) === false) return false;
|
|
7231
7369
|
}
|
|
7232
7370
|
return true;
|
|
7233
7371
|
}
|
|
7234
|
-
|
|
7235
|
-
return this.
|
|
7372
|
+
Bt() {
|
|
7373
|
+
return this.dn(isSlotReady);
|
|
7236
7374
|
}
|
|
7237
7375
|
/**
|
|
7238
7376
|
* "Minimally ready" = this group has something visible to show under its own policy.
|
|
@@ -7240,13 +7378,13 @@ class RevealController {
|
|
|
7240
7378
|
* - `together`: every direct slot is minimally ready.
|
|
7241
7379
|
* - `sequential`: the first owned slot is minimally ready (frontier can advance).
|
|
7242
7380
|
* - `natural`: any owned slot is minimally ready.
|
|
7243
|
-
*/
|
|
7244
|
-
const e = untrack(this.
|
|
7245
|
-
if (e === "together") return this.
|
|
7381
|
+
*/ zt() {
|
|
7382
|
+
const e = untrack(this.un);
|
|
7383
|
+
if (e === "together") return this.dn(isSlotMinimallyReady);
|
|
7246
7384
|
if (e === "natural") {
|
|
7247
7385
|
let e = false;
|
|
7248
7386
|
let t = false;
|
|
7249
|
-
this.
|
|
7387
|
+
this.dn(n => {
|
|
7250
7388
|
e = true;
|
|
7251
7389
|
if (isSlotMinimallyReady(n)) {
|
|
7252
7390
|
t = true;
|
|
@@ -7257,45 +7395,45 @@ class RevealController {
|
|
|
7257
7395
|
}
|
|
7258
7396
|
// sequential: only the first owned slot matters.
|
|
7259
7397
|
let t = true;
|
|
7260
|
-
this.
|
|
7398
|
+
this.dn(e => {
|
|
7261
7399
|
t = isSlotMinimallyReady(e);
|
|
7262
7400
|
return false;
|
|
7263
7401
|
});
|
|
7264
7402
|
return t;
|
|
7265
7403
|
}
|
|
7266
|
-
dn(e) {
|
|
7267
|
-
if (this.ln.includes(e)) return;
|
|
7268
|
-
this.ln.push(e);
|
|
7269
|
-
const t = untrack(this.sn);
|
|
7270
|
-
setSignal(e.zt, true), setSignal(e.Jt, t === "sequential" ? !!untrack(this.un) : false);
|
|
7271
|
-
untrack(() => this.tn());
|
|
7272
|
-
}
|
|
7273
7404
|
Sn(e) {
|
|
7274
|
-
|
|
7275
|
-
|
|
7276
|
-
untrack(
|
|
7277
|
-
|
|
7278
|
-
|
|
7279
|
-
|
|
7280
|
-
|
|
7281
|
-
const
|
|
7282
|
-
|
|
7405
|
+
if (this.an.includes(e)) return;
|
|
7406
|
+
this.an.push(e);
|
|
7407
|
+
const t = untrack(this.un);
|
|
7408
|
+
setSignal(e.Jt, true), setSignal(e.en, t === "sequential" ? !!untrack(this.ln) : false);
|
|
7409
|
+
untrack(() => this.nn());
|
|
7410
|
+
}
|
|
7411
|
+
Tn(e) {
|
|
7412
|
+
const t = this.an.indexOf(e);
|
|
7413
|
+
if (t >= 0) this.an.splice(t, 1);
|
|
7414
|
+
untrack(() => this.nn());
|
|
7415
|
+
}
|
|
7416
|
+
nn(e, t) {
|
|
7417
|
+
if (this.En) return;
|
|
7418
|
+
this.En = true;
|
|
7419
|
+
const n = this.cn;
|
|
7420
|
+
const r = this.fn;
|
|
7283
7421
|
try {
|
|
7284
|
-
const n = e ?? read(this.
|
|
7422
|
+
const n = e ?? read(this.Jt), r = untrack(this.un), i = r === "sequential" && !!untrack(this.ln), o = t ?? i;
|
|
7285
7423
|
if (n) {
|
|
7286
7424
|
// Held by an outer group. Propagate the hold (and whatever collapsed policy
|
|
7287
7425
|
// the outer asked for) down the whole subtree. Inner order is ignored while
|
|
7288
7426
|
// held; it resumes once the outer releases us.
|
|
7289
|
-
this.
|
|
7427
|
+
this.dn(e => setSlotState(e, this, true, o));
|
|
7290
7428
|
} else if (r === "natural") {
|
|
7291
7429
|
// Each child reveals based on its own readiness. A nested controller slot
|
|
7292
7430
|
// is released to run its own order locally — we bypass setSlotState for it
|
|
7293
7431
|
// so the parent backpointer survives for upward readiness notifications.
|
|
7294
|
-
this.
|
|
7432
|
+
this.dn(e => {
|
|
7295
7433
|
if (isRevealController(e)) {
|
|
7434
|
+
setSignal(e.en, false);
|
|
7296
7435
|
setSignal(e.Jt, false);
|
|
7297
|
-
|
|
7298
|
-
e.tn(false, false);
|
|
7436
|
+
e.nn(false, false);
|
|
7299
7437
|
} else {
|
|
7300
7438
|
setSlotState(e, this, !isSlotReady(e), false);
|
|
7301
7439
|
}
|
|
@@ -7306,11 +7444,11 @@ class RevealController {
|
|
|
7306
7444
|
// sequential's first slot being ready is minimally ready; natural having any
|
|
7307
7445
|
// ready child is minimally ready. This lets `together` guarantee a single
|
|
7308
7446
|
// cohesive reveal without waiting for every grandchild.
|
|
7309
|
-
const e = this.
|
|
7310
|
-
this.
|
|
7447
|
+
const e = this.dn(isSlotMinimallyReady);
|
|
7448
|
+
this.dn(t => setSlotState(t, this, !e, false));
|
|
7311
7449
|
} else {
|
|
7312
7450
|
let e = false;
|
|
7313
|
-
this.
|
|
7451
|
+
this.dn(t => {
|
|
7314
7452
|
if (e) return setSlotState(t, this, true, i);
|
|
7315
7453
|
if (isSlotReady(t)) return setSlotState(t, this, false, false);
|
|
7316
7454
|
e = true;
|
|
@@ -7321,63 +7459,63 @@ class RevealController {
|
|
|
7321
7459
|
// advancing past this slot, and we bypass setSlotState so the parent
|
|
7322
7460
|
// backpointer survives for upward readiness notifications.
|
|
7323
7461
|
if (isRevealController(t)) {
|
|
7462
|
+
setSignal(t.en, false);
|
|
7324
7463
|
setSignal(t.Jt, false);
|
|
7325
|
-
|
|
7326
|
-
t.tn(false, false);
|
|
7464
|
+
t.nn(false, false);
|
|
7327
7465
|
} else {
|
|
7328
7466
|
setSlotState(t, this, true, false);
|
|
7329
7467
|
}
|
|
7330
7468
|
});
|
|
7331
7469
|
}
|
|
7332
7470
|
} finally {
|
|
7333
|
-
this.
|
|
7334
|
-
this.
|
|
7335
|
-
this.
|
|
7471
|
+
this.cn = this.Bt();
|
|
7472
|
+
this.fn = this.zt();
|
|
7473
|
+
this.En = false;
|
|
7336
7474
|
}
|
|
7337
|
-
if (this.
|
|
7475
|
+
if (this.tn && (n !== this.cn || r !== this.fn)) this.tn.nn();
|
|
7338
7476
|
}
|
|
7339
7477
|
}
|
|
7340
7478
|
|
|
7341
7479
|
class CollectionQueue extends Queue {
|
|
7342
|
-
Tn;
|
|
7343
|
-
Bt=new Set;
|
|
7344
7480
|
On;
|
|
7345
|
-
Zt=
|
|
7346
|
-
|
|
7481
|
+
Zt=new Set;
|
|
7482
|
+
_n;
|
|
7483
|
+
Xt=true;
|
|
7484
|
+
Jt=signal(false, {
|
|
7347
7485
|
ownedWrite: true,
|
|
7348
|
-
|
|
7486
|
+
bt: true
|
|
7349
7487
|
});
|
|
7350
7488
|
me;
|
|
7351
|
-
|
|
7489
|
+
en=signal(false, {
|
|
7352
7490
|
ownedWrite: true,
|
|
7353
|
-
|
|
7491
|
+
bt: true
|
|
7354
7492
|
});
|
|
7355
|
-
|
|
7356
|
-
|
|
7357
|
-
|
|
7358
|
-
|
|
7493
|
+
rn;
|
|
7494
|
+
sn=false;
|
|
7495
|
+
Rn;
|
|
7496
|
+
pn=ON_INIT;
|
|
7359
7497
|
constructor(e) {
|
|
7360
7498
|
super();
|
|
7361
|
-
this.
|
|
7499
|
+
this.On = e;
|
|
7362
7500
|
}
|
|
7363
7501
|
run(e) {
|
|
7364
|
-
if (!e || read(this.
|
|
7502
|
+
if (!e || read(this.Jt) && (!_revealUsed || read(this.en))) return;
|
|
7365
7503
|
return super.run(e);
|
|
7366
7504
|
}
|
|
7367
7505
|
notify(e, t, n, r) {
|
|
7368
|
-
if (!(t & this.
|
|
7369
|
-
if (this.
|
|
7506
|
+
if (!(t & this.On)) return super.notify(e, t, n, r);
|
|
7507
|
+
if (this.sn && this.Rn) {
|
|
7370
7508
|
const e = untrack(() => {
|
|
7371
7509
|
try {
|
|
7372
|
-
return this.
|
|
7510
|
+
return this.Rn();
|
|
7373
7511
|
} catch {
|
|
7374
7512
|
return ON_INIT;
|
|
7375
7513
|
}
|
|
7376
7514
|
});
|
|
7377
|
-
if (e !== this.
|
|
7378
|
-
this.
|
|
7379
|
-
this.
|
|
7380
|
-
this.
|
|
7515
|
+
if (e !== this.pn) {
|
|
7516
|
+
this.pn = e;
|
|
7517
|
+
this.sn = false;
|
|
7518
|
+
this.Zt.clear();
|
|
7381
7519
|
}
|
|
7382
7520
|
}
|
|
7383
7521
|
// Routing is dimension-independent: each boundary consumes only its own
|
|
@@ -7390,47 +7528,47 @@ class CollectionQueue extends Queue {
|
|
|
7390
7528
|
// dimension, while a status already caught by an inner boundary arrives with
|
|
7391
7529
|
// its dimension consumed from the mask and is correctly not re-routed
|
|
7392
7530
|
// (the Loading > Errored > content composition escape, #2856).
|
|
7393
|
-
if (this.
|
|
7394
|
-
if (n & this.
|
|
7395
|
-
this.
|
|
7531
|
+
if (this.On & STATUS_PENDING && this.sn) return super.notify(e, t, n, r);
|
|
7532
|
+
if (n & this.On) {
|
|
7533
|
+
this.Xt = true;
|
|
7396
7534
|
const t = r?.source || e.me?.source;
|
|
7397
7535
|
if (t) {
|
|
7398
|
-
const e = this.
|
|
7399
|
-
this.
|
|
7400
|
-
if (e) setSignal(this.
|
|
7401
|
-
if (this.
|
|
7536
|
+
const e = this.Zt.size === 0;
|
|
7537
|
+
this.Zt.add(t);
|
|
7538
|
+
if (e) setSignal(this.Jt, true);
|
|
7539
|
+
if (this.On & STATUS_ERROR) {
|
|
7402
7540
|
setSignal(this.me, unwrapStatusError(t.me));
|
|
7403
7541
|
}
|
|
7404
7542
|
}
|
|
7405
7543
|
}
|
|
7406
|
-
t &= ~this.
|
|
7544
|
+
t &= ~this.On;
|
|
7407
7545
|
return t ? super.notify(e, t, n, r) : true;
|
|
7408
7546
|
}
|
|
7409
|
-
|
|
7410
|
-
for (const e of this.
|
|
7547
|
+
je() {
|
|
7548
|
+
for (const e of this.Zt) {
|
|
7411
7549
|
// A source with a live affects() mark holds display state for the
|
|
7412
7550
|
// mark's lifetime (the visual channel): the marked node carries no
|
|
7413
7551
|
// status of its own, so the count is the liveness test. The release
|
|
7414
7552
|
// sweep (finalizePureQueue after mark release) re-runs this check.
|
|
7415
|
-
if (e.D & REACTIVE_DISPOSED || !e.W && !(e.
|
|
7553
|
+
if (e.D & REACTIVE_DISPOSED || !e.W && !(e.He & this.On) && !(this.On & STATUS_ERROR && e.He & STATUS_PENDING)) this.Zt.delete(e);
|
|
7416
7554
|
}
|
|
7417
|
-
if (!this.
|
|
7418
|
-
if (this.
|
|
7419
|
-
this.
|
|
7555
|
+
if (!this.Zt.size) {
|
|
7556
|
+
if (this.On & STATUS_PENDING && this.Xt && !this.sn && this._n) {
|
|
7557
|
+
this.Xt = !!(this._n.He & this.On);
|
|
7420
7558
|
} else {
|
|
7421
|
-
this.
|
|
7559
|
+
this.Xt = false;
|
|
7422
7560
|
}
|
|
7423
|
-
if (!this.
|
|
7424
|
-
setSignal(this.
|
|
7425
|
-
if (this.
|
|
7561
|
+
if (!this.Xt) {
|
|
7562
|
+
setSignal(this.Jt, false);
|
|
7563
|
+
if (this.Rn) {
|
|
7426
7564
|
try {
|
|
7427
|
-
this.
|
|
7565
|
+
this.pn = untrack(() => this.Rn());
|
|
7428
7566
|
} catch {
|
|
7429
7567
|
/* value not yet committed — _prevOn stays stale, next notify will reset */}
|
|
7430
7568
|
}
|
|
7431
7569
|
}
|
|
7432
7570
|
}
|
|
7433
|
-
if (_revealUsed) this.nn
|
|
7571
|
+
if (_revealUsed) this.rn?.nn();
|
|
7434
7572
|
}
|
|
7435
7573
|
}
|
|
7436
7574
|
|
|
@@ -7440,10 +7578,10 @@ function createCollectionBoundary(e, t, n, r) {
|
|
|
7440
7578
|
const o = new CollectionQueue(e);
|
|
7441
7579
|
if (e === STATUS_ERROR) o.me = signal(undefined, {
|
|
7442
7580
|
ownedWrite: true,
|
|
7443
|
-
|
|
7581
|
+
bt: true
|
|
7444
7582
|
});
|
|
7445
|
-
if (r) o.
|
|
7446
|
-
const s = o.
|
|
7583
|
+
if (r) o.Rn = r;
|
|
7584
|
+
const s = o._n = createBoundChildren(i, t, o, e);
|
|
7447
7585
|
// Prime source tracking so reveal registration sees pending sources.
|
|
7448
7586
|
untrack(() => {
|
|
7449
7587
|
let t = false;
|
|
@@ -7452,23 +7590,23 @@ function createCollectionBoundary(e, t, n, r) {
|
|
|
7452
7590
|
} catch (e) {
|
|
7453
7591
|
if (e instanceof NotReadyError) t = true; else throw e;
|
|
7454
7592
|
}
|
|
7455
|
-
o.
|
|
7593
|
+
o.Xt = t || !!(s.He & e) || s.me instanceof NotReadyError;
|
|
7456
7594
|
});
|
|
7457
7595
|
const u = _revealUsed && e === STATUS_PENDING ? getContext(RevealControllerContext) : null;
|
|
7458
7596
|
if (u) {
|
|
7459
|
-
o.
|
|
7460
|
-
u.
|
|
7461
|
-
cleanup(() => u.
|
|
7597
|
+
o.rn = u;
|
|
7598
|
+
u.Sn(o);
|
|
7599
|
+
cleanup(() => u.Tn(o));
|
|
7462
7600
|
}
|
|
7463
7601
|
return accessor(computed(() => {
|
|
7464
|
-
if (!read(o.
|
|
7602
|
+
if (!read(o.Jt)) {
|
|
7465
7603
|
const e = read(s);
|
|
7466
|
-
if (!untrack(() => read(o.
|
|
7604
|
+
if (!untrack(() => read(o.Jt))) return o.sn = true, e;
|
|
7467
7605
|
}
|
|
7468
7606
|
// Collapsed reveal slots suppress their own output entirely; the
|
|
7469
7607
|
// renderer treats the hole as empty, so the cast never leaks to users
|
|
7470
7608
|
// outside a `createRevealOrder` scope.
|
|
7471
|
-
if (_revealUsed && read(o.
|
|
7609
|
+
if (_revealUsed && read(o.en)) return undefined;
|
|
7472
7610
|
return n(o);
|
|
7473
7611
|
},
|
|
7474
7612
|
// Boundary structure, not a user source: its value is fallback-or-content and
|
|
@@ -7476,7 +7614,7 @@ function createCollectionBoundary(e, t, n, r) {
|
|
|
7476
7614
|
// by snapshot capture. The tree no longer carries foreign status flags, so
|
|
7477
7615
|
// capture can't rely on PENDING to skip this node the way it used to.
|
|
7478
7616
|
{
|
|
7479
|
-
|
|
7617
|
+
bt: true
|
|
7480
7618
|
}));
|
|
7481
7619
|
}
|
|
7482
7620
|
|
|
@@ -7530,7 +7668,7 @@ function createCollectionBoundary(e, t, n, r) {
|
|
|
7530
7668
|
* ```
|
|
7531
7669
|
*/ function createErrorBoundary(e, t) {
|
|
7532
7670
|
return createCollectionBoundary(STATUS_ERROR, e, e => t(accessor(e.me), () => {
|
|
7533
|
-
for (const t of e.
|
|
7671
|
+
for (const t of e.Zt) recompute(t);
|
|
7534
7672
|
schedule();
|
|
7535
7673
|
}));
|
|
7536
7674
|
}
|
|
@@ -7587,12 +7725,12 @@ function createCollectionBoundary(e, t, n, r) {
|
|
|
7587
7725
|
computed(() => {
|
|
7588
7726
|
i();
|
|
7589
7727
|
o();
|
|
7590
|
-
s.
|
|
7728
|
+
s.nn();
|
|
7591
7729
|
});
|
|
7592
7730
|
if (r) {
|
|
7593
|
-
s.
|
|
7594
|
-
r.
|
|
7595
|
-
cleanup(() => r.
|
|
7731
|
+
s.tn = r;
|
|
7732
|
+
r.Sn(s);
|
|
7733
|
+
cleanup(() => r.Tn(s));
|
|
7596
7734
|
}
|
|
7597
7735
|
return t;
|
|
7598
7736
|
});
|