@solidjs/signals 2.0.0-beta.32 → 2.0.0-beta.34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/dev.js +235 -87
- package/dist/node.cjs +758 -635
- package/dist/prod/core/async.js +108 -54
- package/dist/prod/core/core.js +241 -204
- package/dist/prod/core/effect.js +27 -27
- package/dist/prod/core/external.js +4 -4
- package/dist/prod/core/graph.js +32 -32
- package/dist/prod/core/heap.js +36 -36
- package/dist/prod/core/lanes.js +14 -14
- package/dist/prod/core/optimistic.js +39 -39
- package/dist/prod/core/owner.js +53 -44
- package/dist/prod/core/scheduler.js +76 -72
- package/dist/prod/core/verdict.js +59 -48
- package/dist/prod/map.js +6 -6
- package/dist/prod/signals.js +2 -34
- package/dist/prod/store/optimistic.js +37 -32
- package/dist/prod/store/projection.js +41 -6
- package/dist/prod/store/store.js +7 -7
- package/dist/types/core/async.d.ts +9 -0
- package/dist/types/core/types.d.ts +24 -0
- package/dist/types/signals.d.ts +60 -4
- package/dist/types/store/store.d.ts +14 -0
- package/dist/types-cjs/core/async.d.cts +9 -0
- package/dist/types-cjs/core/types.d.cts +24 -0
- package/dist/types-cjs/signals.d.cts +60 -4
- package/dist/types-cjs/store/store.d.cts +14 -0
- package/package.json +1 -1
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) {
|
|
@@ -1929,7 +1991,7 @@ function handleAsync(e, t, n) {
|
|
|
1929
1991
|
u = n;
|
|
1930
1992
|
a = true;
|
|
1931
1993
|
if (n.done) i = true;
|
|
1932
|
-
} else if (e.
|
|
1994
|
+
} else if (e.ct !== t) {
|
|
1933
1995
|
return;
|
|
1934
1996
|
} else if (!n.done) {
|
|
1935
1997
|
r = true;
|
|
@@ -1949,7 +2011,7 @@ function handleAsync(e, t, n) {
|
|
|
1949
2011
|
if (f) {
|
|
1950
2012
|
l = n;
|
|
1951
2013
|
c = true;
|
|
1952
|
-
} else if (e.
|
|
2014
|
+
} else if (e.ct === t) {
|
|
1953
2015
|
i = true;
|
|
1954
2016
|
handleError(n);
|
|
1955
2017
|
settleAutodispose();
|
|
@@ -1974,26 +2036,31 @@ function handleAsync(e, t, n) {
|
|
|
1974
2036
|
// Later iterate() calls run from asyncWrite, where rethrowing would be unhandled.
|
|
1975
2037
|
s = false;
|
|
1976
2038
|
if (!r && !u) {
|
|
2039
|
+
// Loading window: serve commit #0 (see the promise branch above).
|
|
2040
|
+
if (e.xe) return e.We;
|
|
1977
2041
|
globalQueue.initTransition(resolveTransition(e));
|
|
1978
2042
|
throw new NotReadyError(context);
|
|
1979
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;
|
|
1980
2047
|
}
|
|
1981
2048
|
return o;
|
|
1982
2049
|
}
|
|
1983
2050
|
|
|
1984
2051
|
function clearStatus(e, t = false) {
|
|
1985
|
-
if (e.
|
|
1986
|
-
if (e.
|
|
2052
|
+
if (e.Ke) clearPendingSources(e);
|
|
2053
|
+
if (e.ht) e.ht = false;
|
|
1987
2054
|
// The pending window is over; its quiet classification dies with it.
|
|
1988
2055
|
// (Unconditional: _reask is baked into the node literals, so this is a
|
|
1989
2056
|
// plain store to an existing slot — no shape change.)
|
|
1990
|
-
e.
|
|
1991
|
-
e.
|
|
2057
|
+
e.Pt = false;
|
|
2058
|
+
e.He = t ? 0 : e.He & STATUS_UNINITIALIZED;
|
|
1992
2059
|
if (e.me) setPendingError(e);
|
|
1993
2060
|
// Update pending signal for isPending() reactivity (companions only exist
|
|
1994
2061
|
// once the verdict layer created them, which installs the hooks).
|
|
1995
2062
|
if (e._ || e.R) GlobalQueue.ce(e);
|
|
1996
|
-
if (e.
|
|
2063
|
+
if (e.it && GlobalQueue.fe !== null) GlobalQueue.fe(e);
|
|
1997
2064
|
if (e.yt) e.yt();
|
|
1998
2065
|
}
|
|
1999
2066
|
|
|
@@ -2007,17 +2074,17 @@ function notifyStatus(e, t, n, r, i) {
|
|
|
2007
2074
|
if (!r) {
|
|
2008
2075
|
if (t === STATUS_PENDING && o) {
|
|
2009
2076
|
addPendingSource(e, o);
|
|
2010
|
-
e.
|
|
2077
|
+
e.He = STATUS_PENDING | e.He & STATUS_UNINITIALIZED;
|
|
2011
2078
|
// Preserve the current source on this propagation so render-effect notification
|
|
2012
2079
|
// can register every distinct pending source with the transition.
|
|
2013
2080
|
setPendingError(e, o, n);
|
|
2014
2081
|
} else {
|
|
2015
2082
|
clearPendingSources(e);
|
|
2016
|
-
e.
|
|
2083
|
+
e.He = t | (t !== STATUS_ERROR ? e.He & STATUS_UNINITIALIZED : 0);
|
|
2017
2084
|
e.me = n;
|
|
2018
2085
|
}
|
|
2019
2086
|
GlobalQueue.ce !== null && GlobalQueue.ce(e);
|
|
2020
|
-
if (e.
|
|
2087
|
+
if (e.it && GlobalQueue.fe !== null) GlobalQueue.fe(e);
|
|
2021
2088
|
}
|
|
2022
2089
|
if (i && !r) {
|
|
2023
2090
|
assignOrMergeLane(e, i);
|
|
@@ -2037,13 +2104,13 @@ function notifyStatus(e, t, n, r, i) {
|
|
|
2037
2104
|
}
|
|
2038
2105
|
forEachDependent(e, (e, r) => {
|
|
2039
2106
|
e.H = clock;
|
|
2040
|
-
if (t === STATUS_PENDING && o && !e.
|
|
2107
|
+
if (t === STATUS_PENDING && o && !e.Ke?.has(o) || t !== STATUS_PENDING && (e.me !== n || e.Ke)) {
|
|
2041
2108
|
// A pending-observer link is the subscription an `isPending` read created.
|
|
2042
2109
|
// It exists so the observer re-runs when the source settles, but it must
|
|
2043
2110
|
// not carry a real (non-NotReadyError) error — the synchronous `isPending`
|
|
2044
2111
|
// read swallows those, and the async path must match. Re-run the observer
|
|
2045
2112
|
// so `isPending` re-evaluates (to not-pending) instead of forwarding.
|
|
2046
|
-
if (r.
|
|
2113
|
+
if (r.Rt && t !== STATUS_PENDING && !(n instanceof NotReadyError)) {
|
|
2047
2114
|
enqueueSub(e);
|
|
2048
2115
|
schedule();
|
|
2049
2116
|
return;
|
|
@@ -2088,7 +2155,7 @@ let snapshotSources = null;
|
|
|
2088
2155
|
|
|
2089
2156
|
function ownerInSnapshotScope(e) {
|
|
2090
2157
|
while (e) {
|
|
2091
|
-
if (e.
|
|
2158
|
+
if (e.Ct) return true;
|
|
2092
2159
|
e = e.Z;
|
|
2093
2160
|
}
|
|
2094
2161
|
return false;
|
|
@@ -2100,20 +2167,20 @@ function setSnapshotCapture(e) {
|
|
|
2100
2167
|
}
|
|
2101
2168
|
|
|
2102
2169
|
function markSnapshotScope(e) {
|
|
2103
|
-
e.
|
|
2170
|
+
e.Ct = true;
|
|
2104
2171
|
}
|
|
2105
2172
|
|
|
2106
2173
|
function releaseSnapshotScope(e) {
|
|
2107
|
-
e.
|
|
2174
|
+
e.Ct = false;
|
|
2108
2175
|
releaseSubtree(e);
|
|
2109
2176
|
schedule();
|
|
2110
2177
|
}
|
|
2111
2178
|
|
|
2112
2179
|
function releaseSubtree(e) {
|
|
2113
|
-
let t = e.
|
|
2180
|
+
let t = e.st;
|
|
2114
2181
|
while (t) {
|
|
2115
|
-
if (t.
|
|
2116
|
-
t = t.
|
|
2182
|
+
if (t.Ct) {
|
|
2183
|
+
t = t.ut;
|
|
2117
2184
|
continue;
|
|
2118
2185
|
}
|
|
2119
2186
|
if (t.ke) {
|
|
@@ -2122,12 +2189,12 @@ function releaseSubtree(e) {
|
|
|
2122
2189
|
if (e.D & REACTIVE_SNAPSHOT_STALE) {
|
|
2123
2190
|
e.D &= ~REACTIVE_SNAPSHOT_STALE;
|
|
2124
2191
|
e.D |= REACTIVE_DIRTY;
|
|
2125
|
-
if (dirtyQueue.P > e.
|
|
2192
|
+
if (dirtyQueue.P > e.Je) dirtyQueue.P = e.Je;
|
|
2126
2193
|
insertIntoHeap(e, dirtyQueue);
|
|
2127
2194
|
}
|
|
2128
2195
|
}
|
|
2129
2196
|
releaseSubtree(t);
|
|
2130
|
-
t = t.
|
|
2197
|
+
t = t.ut;
|
|
2131
2198
|
}
|
|
2132
2199
|
}
|
|
2133
2200
|
|
|
@@ -2150,37 +2217,42 @@ function recompute(e, t = false) {
|
|
|
2150
2217
|
if (!t) {
|
|
2151
2218
|
if (e.T && (!n || activeTransition) && activeTransition !== e.T) globalQueue.initTransition(e.T);
|
|
2152
2219
|
deleteFromHeap(e, queueFor(e));
|
|
2153
|
-
e.
|
|
2220
|
+
e.ct = null;
|
|
2154
2221
|
// Tracked effects run after finalizePureQueue, so dispose immediately instead of deferring
|
|
2155
|
-
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) {
|
|
2156
2223
|
markDisposal(e);
|
|
2157
|
-
e
|
|
2158
|
-
e.
|
|
2159
|
-
e.
|
|
2160
|
-
e.
|
|
2161
|
-
e.
|
|
2224
|
+
e.$e = e.St;
|
|
2225
|
+
e.Me = e.st;
|
|
2226
|
+
e.St = null;
|
|
2227
|
+
e.st = null;
|
|
2228
|
+
e.ft = 0;
|
|
2162
2229
|
} else ;
|
|
2163
2230
|
}
|
|
2164
2231
|
let r = !!(e.D & REACTIVE_OPTIMISTIC_DIRTY);
|
|
2165
2232
|
const i = e.A !== undefined && e.A !== NOT_PENDING;
|
|
2166
|
-
const o = !!(e.
|
|
2233
|
+
const o = !!(e.He & STATUS_UNINITIALIZED);
|
|
2167
2234
|
// Outgoing error, captured before the compute clears status: if this run
|
|
2168
2235
|
// recovers to an unchanged value, dependents still holding this object must
|
|
2169
2236
|
// be swept (settleErroredDependents, #2949).
|
|
2170
|
-
const s = e.
|
|
2237
|
+
const s = e.He & STATUS_ERROR ? e.me : undefined;
|
|
2171
2238
|
// Re-ask classification lives in the verdict module; capture the flag before
|
|
2172
2239
|
// the recompute wipes _flags below.
|
|
2173
2240
|
const u = (e.D & REACTIVE_REASK) !== 0;
|
|
2174
|
-
|
|
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;
|
|
2175
2247
|
context = e;
|
|
2176
|
-
e.
|
|
2177
|
-
e.
|
|
2248
|
+
e.lt = null;
|
|
2249
|
+
e.At++;
|
|
2178
2250
|
e.D = REACTIVE_RECOMPUTING_DEPS;
|
|
2179
2251
|
e.H = clock;
|
|
2180
|
-
let
|
|
2181
|
-
let
|
|
2182
|
-
let
|
|
2183
|
-
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;
|
|
2184
2256
|
tracking = true;
|
|
2185
2257
|
// A computed's fn establishes its OWN dependencies, so it must never run
|
|
2186
2258
|
// inside a latest() read window: read() short-circuits through the
|
|
@@ -2188,7 +2260,7 @@ function recompute(e, t = false) {
|
|
|
2188
2260
|
// computed) inside latest(fn) came out permanently dependency-less (#2926).
|
|
2189
2261
|
// latestRead() already suspends the flag for its pull-recomputes; this
|
|
2190
2262
|
// covers creation-time computes and flushes that run inside the window.
|
|
2191
|
-
const
|
|
2263
|
+
const S = latestReadActive;
|
|
2192
2264
|
latestReadActive = false;
|
|
2193
2265
|
// Lane posture lives with the engine: OPTIMISTIC_DIRTY is only ever set by
|
|
2194
2266
|
// engine-driven paths, and _optimisticNodes is only pushed by
|
|
@@ -2206,56 +2278,76 @@ function recompute(e, t = false) {
|
|
|
2206
2278
|
currentOptimisticLane = t;
|
|
2207
2279
|
}
|
|
2208
2280
|
}
|
|
2209
|
-
const
|
|
2210
|
-
const
|
|
2211
|
-
if (
|
|
2281
|
+
const T = n && n !== EFFECT_USER;
|
|
2282
|
+
const O = stale;
|
|
2283
|
+
if (T) stale = true;
|
|
2212
2284
|
try {
|
|
2213
2285
|
if (!false && e.Ue & CONFIG_SYNC) {
|
|
2214
|
-
|
|
2215
|
-
e.
|
|
2286
|
+
c = e.ke(c);
|
|
2287
|
+
e.ct = null;
|
|
2288
|
+
e.xe = false;
|
|
2216
2289
|
} else {
|
|
2217
2290
|
// Snapshot `_inFlight` so we can detect whether `_fn` self-registered an async
|
|
2218
2291
|
// subscription (e.g. `createProjection` calls `handleAsync` from inside its body
|
|
2219
2292
|
// with a setter callback). In that case, the outer `handleAsync` call below would
|
|
2220
2293
|
// clobber the fresh subscription, so we skip it and let the internally-registered
|
|
2221
2294
|
// iteration drive updates.
|
|
2222
|
-
const t = e.
|
|
2223
|
-
const n = e.ke(
|
|
2295
|
+
const t = e.ct;
|
|
2296
|
+
const n = e.ke(c);
|
|
2224
2297
|
const r = typeof n === "object" && n !== null;
|
|
2225
|
-
const i = e.
|
|
2226
|
-
|
|
2227
|
-
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
|
+
}
|
|
2228
2308
|
}
|
|
2229
2309
|
// On a status-free node clearStatus is a guaranteed no-op: every branch
|
|
2230
2310
|
// in its body is gated on one of these fields, and with _statusFlags === 0
|
|
2231
2311
|
// the flags write (create or not) stores the 0 already there.
|
|
2232
|
-
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);
|
|
2233
2313
|
// _optimisticLane is only ever assigned by engine paths.
|
|
2234
2314
|
if (e.i) GlobalQueue.De(e);
|
|
2235
2315
|
} catch (t) {
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
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
|
+
}
|
|
2246
2338
|
} finally {
|
|
2247
|
-
tracking =
|
|
2248
|
-
latestReadActive =
|
|
2249
|
-
if (
|
|
2339
|
+
tracking = E;
|
|
2340
|
+
latestReadActive = S;
|
|
2341
|
+
if (T) stale = O;
|
|
2250
2342
|
e.D = REACTIVE_NONE | (t ? e.D & REACTIVE_SNAPSHOT_STALE : 0);
|
|
2251
|
-
context =
|
|
2343
|
+
context = a;
|
|
2252
2344
|
}
|
|
2253
2345
|
if (!e.me) {
|
|
2254
2346
|
trimStaleDeps(e);
|
|
2255
2347
|
const u = i ? unwrapOverride(e.A) : e.k === NOT_PENDING ? e.We : e.k;
|
|
2256
|
-
let
|
|
2348
|
+
let a = false;
|
|
2257
2349
|
try {
|
|
2258
|
-
|
|
2350
|
+
a = !n && o || !e.Nt || !e.Nt(u, c);
|
|
2259
2351
|
} catch (t) {
|
|
2260
2352
|
// A throwing user comparator is an error of this node's computation.
|
|
2261
2353
|
// Route it through the same status path as a compute-phase throw so
|
|
@@ -2268,13 +2360,13 @@ function recompute(e, t = false) {
|
|
|
2268
2360
|
// its runner — happen here instead. `!create` matches the previous `initialized`
|
|
2269
2361
|
// gate: the explicit recompute(node, true) inside effect() does not enqueue, so
|
|
2270
2362
|
// effect() can call its runner synchronously for the first run.
|
|
2271
|
-
if (n &&
|
|
2363
|
+
if (n && a) {
|
|
2272
2364
|
e.Qe = !e.me;
|
|
2273
2365
|
// Reuse one bound runner per effect — runEffect no-ops on a stale
|
|
2274
2366
|
// `_modified`, so re-enqueueing the same function is harmless.
|
|
2275
|
-
if (!t) e.
|
|
2367
|
+
if (!t) e.Xe.enqueue(n, e.gt ??= GlobalQueue.te.bind(null, e));
|
|
2276
2368
|
}
|
|
2277
|
-
if (e.me) ; else if (
|
|
2369
|
+
if (e.me) ; else if (a) {
|
|
2278
2370
|
const o = i ? e.A : undefined;
|
|
2279
2371
|
if (t ||
|
|
2280
2372
|
// Plain sync flush (no transition on either side) commits effect
|
|
@@ -2282,23 +2374,26 @@ function recompute(e, t = false) {
|
|
|
2282
2374
|
// commitPendingNodes) exists to sequence transition reveals, and
|
|
2283
2375
|
// paying it per effect on the plain path is pure overhead.
|
|
2284
2376
|
n && (activeTransition !== e.T || activeTransition === null) || r) {
|
|
2285
|
-
e.We =
|
|
2377
|
+
e.We = c;
|
|
2286
2378
|
// Lane-propagated correction: upstream data is fresh, correct the
|
|
2287
2379
|
// override unconditionally. The direct _value commit is the lane's
|
|
2288
2380
|
// own reveal schedule; drop any superseded older hold so its queued
|
|
2289
2381
|
// commit can't clobber the fresh value.
|
|
2290
2382
|
if (i && r) {
|
|
2291
|
-
e.A =
|
|
2383
|
+
e.A = c === undefined ? OVERRIDE_UNDEFINED : c;
|
|
2292
2384
|
e.k = NOT_PENDING;
|
|
2293
2385
|
}
|
|
2294
2386
|
} else {
|
|
2295
|
-
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;
|
|
2296
2391
|
// Transition-held sync recompute is a write path like setSignal/asyncWrite,
|
|
2297
2392
|
// so sync derivations of held sources stay visible to isPending()/latest()
|
|
2298
2393
|
// (#2831). Both companion writes are transition-scoped (optimistic) and
|
|
2299
2394
|
// auto-revert/re-derive at commit. Skipped for plain flushes where the
|
|
2300
2395
|
// pending value commits before effects run.
|
|
2301
|
-
if ((activeTransition || e.T) && GlobalQueue.ae !== null) GlobalQueue.ae(e,
|
|
2396
|
+
if ((activeTransition || e.T) && GlobalQueue.ae !== null) GlobalQueue.ae(e, c);
|
|
2302
2397
|
}
|
|
2303
2398
|
// insertSubs only walks _subs (no scheduling of its own), so a
|
|
2304
2399
|
// subscriber-less node has nothing to notify.
|
|
@@ -2308,8 +2403,10 @@ function recompute(e, t = false) {
|
|
|
2308
2403
|
// is active: _value may still be stale, so hold the authoritative value
|
|
2309
2404
|
// for commit on its own transition's schedule — invisibly (A17/A18).
|
|
2310
2405
|
if (e.k === NOT_PENDING) queuePendingNode(e);
|
|
2311
|
-
e.k =
|
|
2312
|
-
|
|
2406
|
+
e.k = c;
|
|
2407
|
+
if (l) e.xe = true;
|
|
2408
|
+
// see the held branch above (#2990)
|
|
2409
|
+
} else if (e.Je != f) {
|
|
2313
2410
|
for (let t = e.U; t !== null; t = t.Ge) {
|
|
2314
2411
|
insertIntoHeapHeight(t.Ve, queueFor(t.Ve));
|
|
2315
2412
|
}
|
|
@@ -2319,24 +2416,24 @@ function recompute(e, t = false) {
|
|
|
2319
2416
|
// in an errored run and may sit on stale commits (#2949). Changed-value
|
|
2320
2417
|
// recoveries ride insertSubs above; a comparator throw re-errored the node
|
|
2321
2418
|
// (el._error re-set), so this only runs on a genuinely clean recovery.
|
|
2322
|
-
if (s !== undefined && !
|
|
2419
|
+
if (s !== undefined && !a && !e.me) settleErroredDependents(e, s);
|
|
2323
2420
|
}
|
|
2324
|
-
currentOptimisticLane =
|
|
2325
|
-
const
|
|
2421
|
+
currentOptimisticLane = d;
|
|
2422
|
+
const _ = e.k !== NOT_PENDING || e.Me !== null || e.$e !== null || (e.He & (STATUS_PENDING | STATUS_UNINITIALIZED)) !== 0;
|
|
2326
2423
|
// Override-covered holds (hasOverride) always queue: their commit belongs
|
|
2327
2424
|
// to their own transition's schedule (A18 re-rule) and is unobservable
|
|
2328
2425
|
// under the override (A17). Revert no longer commits anything, so an
|
|
2329
2426
|
// unqueued covered hold would leak (INV-7) once the revert clears
|
|
2330
2427
|
// _transition.
|
|
2331
|
-
|
|
2428
|
+
_ && (!t || e.He & STATUS_PENDING) && (!e.T || i) && queuePendingNode(e);
|
|
2332
2429
|
e.T && n && activeTransition !== e.T && runInTransition(e.T, () => recompute(e));
|
|
2333
2430
|
}
|
|
2334
2431
|
|
|
2335
2432
|
function updateIfNecessary(e) {
|
|
2336
2433
|
if (e.D & REACTIVE_CHECK) {
|
|
2337
|
-
for (let t = e.
|
|
2338
|
-
const n = t.
|
|
2339
|
-
const r = n.
|
|
2434
|
+
for (let t = e.Ye; t; t = t.qe) {
|
|
2435
|
+
const n = t.Be;
|
|
2436
|
+
const r = n.Ze || n;
|
|
2340
2437
|
if (r.ke) {
|
|
2341
2438
|
updateIfNecessary(r);
|
|
2342
2439
|
}
|
|
@@ -2345,7 +2442,7 @@ function updateIfNecessary(e) {
|
|
|
2345
2442
|
}
|
|
2346
2443
|
}
|
|
2347
2444
|
}
|
|
2348
|
-
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) {
|
|
2349
2446
|
recompute(e);
|
|
2350
2447
|
}
|
|
2351
2448
|
e.D = e.D & (REACTIVE_SNAPSHOT_STALE | REACTIVE_IN_HEAP | REACTIVE_IN_HEAP_HEIGHT);
|
|
@@ -2353,42 +2450,48 @@ function updateIfNecessary(e) {
|
|
|
2353
2450
|
|
|
2354
2451
|
function computed(e, t) {
|
|
2355
2452
|
const n = t?.transparent ?? false;
|
|
2356
|
-
|
|
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 = {
|
|
2357
2458
|
id: inheritId(t, n, context),
|
|
2358
|
-
Ue: (n ? CONFIG_TRANSPARENT : 0) | (t?.ownedWrite ? CONFIG_OWNED_WRITE : 0) | (!context || t?.lazy ? CONFIG_AUTO_DISPOSE : 0) | (t?.sync ? CONFIG_SYNC : 0) | (t?.
|
|
2359
|
-
|
|
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,
|
|
2360
2461
|
F: t?.unobserved,
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2462
|
+
St: null,
|
|
2463
|
+
Xe: context?.Xe ?? globalQueue,
|
|
2464
|
+
Tt: context?.Tt ?? defaultContext,
|
|
2465
|
+
ft: 0,
|
|
2365
2466
|
ke: e,
|
|
2366
|
-
We: undefined,
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
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,
|
|
2374
2475
|
U: null,
|
|
2375
|
-
|
|
2476
|
+
_t: null,
|
|
2376
2477
|
Z: context,
|
|
2478
|
+
ut: null,
|
|
2479
|
+
Et: null,
|
|
2377
2480
|
st: null,
|
|
2378
|
-
ft: null,
|
|
2379
|
-
ot: null,
|
|
2380
2481
|
D: t?.lazy ? REACTIVE_LAZY : REACTIVE_NONE,
|
|
2381
|
-
|
|
2482
|
+
// A loadingValue node is born committed: commit #0 is already in _value.
|
|
2483
|
+
He: r ? 0 : STATUS_UNINITIALIZED,
|
|
2382
2484
|
H: clock,
|
|
2383
2485
|
k: NOT_PENDING,
|
|
2486
|
+
$e: null,
|
|
2384
2487
|
Me: null,
|
|
2385
|
-
|
|
2386
|
-
lt: null,
|
|
2488
|
+
ct: null,
|
|
2387
2489
|
T: null,
|
|
2388
|
-
|
|
2490
|
+
Pt: false,
|
|
2491
|
+
xe: r
|
|
2389
2492
|
};
|
|
2390
|
-
setupComputedNode(
|
|
2391
|
-
return
|
|
2493
|
+
setupComputedNode(i, t);
|
|
2494
|
+
return i;
|
|
2392
2495
|
}
|
|
2393
2496
|
|
|
2394
2497
|
/**
|
|
@@ -2401,41 +2504,42 @@ function computed(e, t) {
|
|
|
2401
2504
|
const u = {
|
|
2402
2505
|
id: inheritId(o, s, context),
|
|
2403
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),
|
|
2404
|
-
|
|
2507
|
+
Nt: false,
|
|
2405
2508
|
F: o?.unobserved,
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2509
|
+
St: null,
|
|
2510
|
+
Xe: context?.Xe ?? globalQueue,
|
|
2511
|
+
Tt: context?.Tt ?? defaultContext,
|
|
2512
|
+
ft: 0,
|
|
2410
2513
|
ke: e,
|
|
2411
2514
|
We: undefined,
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2515
|
+
Je: 0,
|
|
2516
|
+
it: null,
|
|
2517
|
+
rt: undefined,
|
|
2518
|
+
nt: null,
|
|
2519
|
+
Ye: null,
|
|
2520
|
+
lt: null,
|
|
2521
|
+
At: 0,
|
|
2419
2522
|
U: null,
|
|
2420
|
-
|
|
2523
|
+
_t: null,
|
|
2421
2524
|
Z: context,
|
|
2525
|
+
ut: null,
|
|
2526
|
+
Et: null,
|
|
2422
2527
|
st: null,
|
|
2423
|
-
ft: null,
|
|
2424
|
-
ot: null,
|
|
2425
2528
|
D: REACTIVE_LAZY,
|
|
2426
|
-
|
|
2529
|
+
He: STATUS_UNINITIALIZED,
|
|
2427
2530
|
H: clock,
|
|
2428
2531
|
k: NOT_PENDING,
|
|
2532
|
+
$e: null,
|
|
2429
2533
|
Me: null,
|
|
2430
|
-
|
|
2431
|
-
lt: null,
|
|
2534
|
+
ct: null,
|
|
2432
2535
|
T: null,
|
|
2433
|
-
|
|
2536
|
+
Pt: false,
|
|
2537
|
+
xe: false,
|
|
2434
2538
|
Qe: false,
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2539
|
+
Dt: undefined,
|
|
2540
|
+
wt: t,
|
|
2541
|
+
vt: n,
|
|
2542
|
+
dt: undefined,
|
|
2439
2543
|
Fe: r,
|
|
2440
2544
|
yt: i
|
|
2441
2545
|
};
|
|
@@ -2448,23 +2552,23 @@ const lazyOptions = {
|
|
|
2448
2552
|
};
|
|
2449
2553
|
|
|
2450
2554
|
function setupComputedNode(e, t) {
|
|
2451
|
-
e.
|
|
2452
|
-
const n = context?.
|
|
2555
|
+
e.nt = e;
|
|
2556
|
+
const n = context?.et ? context.tt : context;
|
|
2453
2557
|
if (context) {
|
|
2454
|
-
const t = context.
|
|
2558
|
+
const t = context.st;
|
|
2455
2559
|
if (t === null) {
|
|
2456
|
-
context.
|
|
2560
|
+
context.st = e;
|
|
2457
2561
|
} else {
|
|
2458
|
-
e.
|
|
2459
|
-
t.
|
|
2460
|
-
context.
|
|
2562
|
+
e.ut = t;
|
|
2563
|
+
t.Et = e;
|
|
2564
|
+
context.st = e;
|
|
2461
2565
|
}
|
|
2462
2566
|
}
|
|
2463
|
-
if (n) e.
|
|
2567
|
+
if (n) e.Je = n.Je + 1;
|
|
2464
2568
|
if (GlobalQueue.ue !== null) GlobalQueue.ue(e);
|
|
2465
2569
|
!t?.lazy && recompute(e, true);
|
|
2466
2570
|
if (snapshotCaptureActive && !t?.lazy) {
|
|
2467
|
-
if (!(e.
|
|
2571
|
+
if (!(e.He & STATUS_PENDING) && !(e.Ue & CONFIG_NO_SNAPSHOT)) {
|
|
2468
2572
|
e.Le = e.We === undefined ? NO_SNAPSHOT : e.We;
|
|
2469
2573
|
snapshotSources.add(e);
|
|
2470
2574
|
}
|
|
@@ -2473,19 +2577,19 @@ function setupComputedNode(e, t) {
|
|
|
2473
2577
|
|
|
2474
2578
|
function signal(e, t, n = null) {
|
|
2475
2579
|
const r = {
|
|
2476
|
-
|
|
2477
|
-
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),
|
|
2478
2582
|
F: t?.unobserved,
|
|
2479
2583
|
We: e,
|
|
2480
2584
|
U: null,
|
|
2481
|
-
|
|
2585
|
+
_t: null,
|
|
2482
2586
|
H: clock,
|
|
2483
|
-
|
|
2484
|
-
|
|
2587
|
+
Ze: n,
|
|
2588
|
+
ot: n?.it || null,
|
|
2485
2589
|
k: NOT_PENDING
|
|
2486
2590
|
};
|
|
2487
|
-
n && (n.
|
|
2488
|
-
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)) {
|
|
2489
2593
|
r.Le = e === undefined ? NO_SNAPSHOT : e;
|
|
2490
2594
|
snapshotSources.add(r);
|
|
2491
2595
|
}
|
|
@@ -2570,9 +2674,9 @@ function isEqual(e, t) {
|
|
|
2570
2674
|
* snapshot / transition / lane / dev-strictRead state all take the full
|
|
2571
2675
|
* resolution. Anything slow returns READ_SLOW; the caller then calls read().
|
|
2572
2676
|
*/ function readNodeFast(e) {
|
|
2573
|
-
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;
|
|
2574
2678
|
let t = context;
|
|
2575
|
-
if (t?.
|
|
2679
|
+
if (t?.et) t = t.tt;
|
|
2576
2680
|
if (t && tracking) link(e, t);
|
|
2577
2681
|
return !t || e.k === NOT_PENDING ? e.We : e.k;
|
|
2578
2682
|
}
|
|
@@ -2584,9 +2688,9 @@ function read(e) {
|
|
|
2584
2688
|
// than the original node (which stays "pending" while held in a transition).
|
|
2585
2689
|
if (latestReadActive) return GlobalQueue.de(e);
|
|
2586
2690
|
let t = context;
|
|
2587
|
-
if (t?.
|
|
2691
|
+
if (t?.et) t = t.tt;
|
|
2588
2692
|
const n = e;
|
|
2589
|
-
const r = e.
|
|
2693
|
+
const r = e.Ze;
|
|
2590
2694
|
const i = r || e;
|
|
2591
2695
|
// Handle isPending() mode: collect pending state while preserving normal read semantics.
|
|
2592
2696
|
// Probe mode is suspended while preparing the node so nested reads during a
|
|
@@ -2604,31 +2708,31 @@ function read(e) {
|
|
|
2604
2708
|
link(e, t, pendingCheckActive);
|
|
2605
2709
|
if (i.ke) {
|
|
2606
2710
|
const n = queueFor(e);
|
|
2607
|
-
if (i.
|
|
2711
|
+
if (i.Je >= n.P) {
|
|
2608
2712
|
markNode(t);
|
|
2609
2713
|
markHeap(n);
|
|
2610
2714
|
updateIfNecessary(i);
|
|
2611
2715
|
}
|
|
2612
|
-
const r = i.
|
|
2716
|
+
const r = i.Je;
|
|
2613
2717
|
// parent check is shallow, might need to be recursive
|
|
2614
|
-
if (r >= t.
|
|
2615
|
-
t.
|
|
2718
|
+
if (r >= t.Je && e.Z !== t) {
|
|
2719
|
+
t.Je = r + 1;
|
|
2616
2720
|
}
|
|
2617
2721
|
}
|
|
2618
2722
|
}
|
|
2619
|
-
if (i.
|
|
2723
|
+
if (i.He & STATUS_PENDING) {
|
|
2620
2724
|
if (t && !(stale && i.T && activeTransition !== i.T)) {
|
|
2621
2725
|
// Per-lane suspension lives with the engine (a non-null lane implies it
|
|
2622
2726
|
// is installed): under a lane, only same-lane pending async without an
|
|
2623
2727
|
// active override throws.
|
|
2624
|
-
if (currentOptimisticLane === null || GlobalQueue.
|
|
2728
|
+
if (currentOptimisticLane === null || GlobalQueue.ye(i)) {
|
|
2625
2729
|
if (!tracking && e !== t) link(e, t);
|
|
2626
2730
|
throw i.me;
|
|
2627
2731
|
}
|
|
2628
|
-
} else if (t && i !== e && i.
|
|
2732
|
+
} else if (t && i !== e && i.He & STATUS_UNINITIALIZED) {
|
|
2629
2733
|
if (!tracking && e !== t) link(e, t);
|
|
2630
2734
|
throw i.me;
|
|
2631
|
-
} else if (!t && i.
|
|
2735
|
+
} else if (!t && i.He & STATUS_UNINITIALIZED) {
|
|
2632
2736
|
throw i.me;
|
|
2633
2737
|
}
|
|
2634
2738
|
}
|
|
@@ -2636,7 +2740,7 @@ function read(e) {
|
|
|
2636
2740
|
// firewall-backed reads follow the same rules (memo parity, #2897 ruling):
|
|
2637
2741
|
// an errored derive throws for every late reader instead of silently
|
|
2638
2742
|
// serving node values (the seed, or last-good data after a failed refetch).
|
|
2639
|
-
if (i.ke && i.
|
|
2743
|
+
if (i.ke && i.He & STATUS_ERROR) {
|
|
2640
2744
|
// Only a genuine reactive re-read may retry an errored async source:
|
|
2641
2745
|
// - tracking: owned/tracked scope only (never events / `untrack` / effect side-effect phase)
|
|
2642
2746
|
// - !pendingCheckActive: an `isPending` probe observes the error, never refetches
|
|
@@ -2666,7 +2770,7 @@ function read(e) {
|
|
|
2666
2770
|
// _pendingValue for correct fetching. The sub is recorded for replay at commit
|
|
2667
2771
|
// so it re-runs with the new committed view. (Gate details live with the
|
|
2668
2772
|
// engine — a non-null lane implies it is installed.)
|
|
2669
|
-
if (currentOptimisticLane !== null && activeTransition !== null && t !== null && GlobalQueue.
|
|
2773
|
+
if (currentOptimisticLane !== null && activeTransition !== null && t !== null && GlobalQueue.Pe(e, i, t)) {
|
|
2670
2774
|
return e.We;
|
|
2671
2775
|
}
|
|
2672
2776
|
// In optimistic lane context, return _value for optimistic/lane-assigned signals
|
|
@@ -2677,7 +2781,7 @@ function read(e) {
|
|
|
2677
2781
|
// Record that this isPending() probe observed the fresh pending value, so
|
|
2678
2782
|
// the probe doesn't pair "pending" with the new value (#2831).
|
|
2679
2783
|
if (pendingCheckActive) GlobalQueue.Te(e, o);
|
|
2680
|
-
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) {
|
|
2681
2785
|
unobserved(e);
|
|
2682
2786
|
}
|
|
2683
2787
|
return o;
|
|
@@ -2694,7 +2798,7 @@ function setSignal(e, t) {
|
|
|
2694
2798
|
if (typeof t === "function") t = t(n);
|
|
2695
2799
|
// Uninitialized check first: the first commit has no previous value, so the
|
|
2696
2800
|
// user comparator must not run against `undefined` (matches recompute).
|
|
2697
|
-
const r = !!(e.
|
|
2801
|
+
const r = !!(e.He & STATUS_UNINITIALIZED) || !e.Nt || !e.Nt(n, t);
|
|
2698
2802
|
if (!r) return t;
|
|
2699
2803
|
if (e.k === NOT_PENDING) queuePendingNode(e);
|
|
2700
2804
|
e.k = t;
|
|
@@ -2935,7 +3039,7 @@ function enableExternalSource(e) {
|
|
|
2935
3039
|
if (!t) {
|
|
2936
3040
|
throw new NoOwnerError;
|
|
2937
3041
|
}
|
|
2938
|
-
const n = hasContext(e, t) ? t.
|
|
3042
|
+
const n = hasContext(e, t) ? t.Tt[e.id] : e.defaultValue;
|
|
2939
3043
|
if (isUndefined(n)) {
|
|
2940
3044
|
throw new ContextNotFoundError;
|
|
2941
3045
|
}
|
|
@@ -2956,14 +3060,14 @@ function enableExternalSource(e) {
|
|
|
2956
3060
|
}
|
|
2957
3061
|
// We're creating a new object to avoid child context values being exposed to parent owners. If
|
|
2958
3062
|
// we don't do this, everything will be a singleton and all hell will break lose.
|
|
2959
|
-
n.
|
|
2960
|
-
...n.
|
|
3063
|
+
n.Tt = {
|
|
3064
|
+
...n.Tt,
|
|
2961
3065
|
[e.id]: isUndefined(t) ? e.defaultValue : t
|
|
2962
3066
|
};
|
|
2963
3067
|
}
|
|
2964
3068
|
|
|
2965
3069
|
function hasContext(e, t) {
|
|
2966
|
-
return !isUndefined(t?.
|
|
3070
|
+
return !isUndefined(t?.Tt[e.id]);
|
|
2967
3071
|
}
|
|
2968
3072
|
|
|
2969
3073
|
function isUndefined(e) {
|
|
@@ -2987,7 +3091,7 @@ function isUndefined(e) {
|
|
|
2987
3091
|
const n = e.A !== NOT_PENDING;
|
|
2988
3092
|
const r = n ? unwrapOverride(e.A) : e.We;
|
|
2989
3093
|
if (typeof t === "function") t = t(r);
|
|
2990
|
-
const i = !!(e.
|
|
3094
|
+
const i = !!(e.He & STATUS_UNINITIALIZED) || !e.Nt || !e.Nt(r, t);
|
|
2991
3095
|
if (!i) {
|
|
2992
3096
|
// Same-value write with an active override still entangles the current
|
|
2993
3097
|
// action's transition — the hold must outlast all overlapping actions.
|
|
@@ -3028,7 +3132,7 @@ function isUndefined(e) {
|
|
|
3028
3132
|
*/ function transitionBlocked(e) {
|
|
3029
3133
|
for (let t = 0; t < e.L.length; t++) {
|
|
3030
3134
|
const n = e.L[t];
|
|
3031
|
-
if (hasActiveOverride(n) && "
|
|
3135
|
+
if (hasActiveOverride(n) && "He" in n && n.He & STATUS_PENDING && n.me instanceof NotReadyError) {
|
|
3032
3136
|
return true;
|
|
3033
3137
|
}
|
|
3034
3138
|
}
|
|
@@ -3046,7 +3150,7 @@ function resolveOptimisticNodes(e) {
|
|
|
3046
3150
|
// Revert is a pure drop: there is no revert target to commit —
|
|
3047
3151
|
// override-covered authoritative values hold in _pendingValue and
|
|
3048
3152
|
// elevate on their OWN transition's schedule (A18 as re-ruled 2026-07-07).
|
|
3049
|
-
if (!(t.
|
|
3153
|
+
if (!(t.He & STATUS_PENDING)) t.He &= ~STATUS_UNINITIALIZED;
|
|
3050
3154
|
const r = t.A;
|
|
3051
3155
|
t.A = NOT_PENDING;
|
|
3052
3156
|
if (r !== NOT_PENDING && t.We !== unwrapOverride(r)) insertSubs(t, true);
|
|
@@ -3124,7 +3228,7 @@ function cleanupCompletedLanes(e) {
|
|
|
3124
3228
|
* read()'s value selection under a lane: return the committed `_value` for
|
|
3125
3229
|
* optimistic/lane-assigned signals, stale-mode reads, and pending owners.
|
|
3126
3230
|
*/ function laneReadsCommitted(e, t, n) {
|
|
3127
|
-
if (e.A !== undefined || !!e.i || !!(t.
|
|
3231
|
+
if (e.A !== undefined || !!e.i || !!(t.He & STATUS_PENDING)) return true;
|
|
3128
3232
|
if (t === e && stale && n.t !== e) {
|
|
3129
3233
|
// The committed view can hide a same-tick ambient write (a lane member —
|
|
3130
3234
|
// even just an isPending companion flip — puts the reader "under a lane"
|
|
@@ -3145,8 +3249,8 @@ function cleanupCompletedLanes(e) {
|
|
|
3145
3249
|
* can run before its OPT-dirty child propagates).
|
|
3146
3250
|
*/ function recomputeLane(e, t) {
|
|
3147
3251
|
if (t) return resolveLane(e) ?? null;
|
|
3148
|
-
for (let t = e.
|
|
3149
|
-
const n = t.
|
|
3252
|
+
for (let t = e.Ye; t; t = t.qe) {
|
|
3253
|
+
const n = t.Be;
|
|
3150
3254
|
if (n.D & REACTIVE_OPTIMISTIC_DIRTY) {
|
|
3151
3255
|
const t = resolveLane(n);
|
|
3152
3256
|
if (t) {
|
|
@@ -3193,8 +3297,8 @@ function trackOptimisticStore(e) {
|
|
|
3193
3297
|
GlobalQueue.Ae = transitionBlocked;
|
|
3194
3298
|
GlobalQueue.he = cleanupCompletedLanes;
|
|
3195
3299
|
GlobalQueue.Ne = runLaneEffects;
|
|
3196
|
-
GlobalQueue.
|
|
3197
|
-
GlobalQueue.
|
|
3300
|
+
GlobalQueue.Pe = gatedRead;
|
|
3301
|
+
GlobalQueue.ye = laneSuspends;
|
|
3198
3302
|
GlobalQueue.Ce = laneReadsCommitted;
|
|
3199
3303
|
GlobalQueue.ge = recomputeLane;
|
|
3200
3304
|
GlobalQueue.be = laneAsyncPending;
|
|
@@ -3232,7 +3336,7 @@ let pendingProbe = null;
|
|
|
3232
3336
|
function collectPendingSources(e) {
|
|
3233
3337
|
if (!pendingProbe) return;
|
|
3234
3338
|
pendingProbe.sources.add(e);
|
|
3235
|
-
const t = e.
|
|
3339
|
+
const t = e.Ze || e;
|
|
3236
3340
|
if (t !== e) pendingProbe.sources.add(t);
|
|
3237
3341
|
}
|
|
3238
3342
|
|
|
@@ -3262,20 +3366,20 @@ function collectPendingSources(e) {
|
|
|
3262
3366
|
// not flow through it — matching the rails' behavior, where propagation
|
|
3263
3367
|
// stopped at errored nodes. A DIRECT mark on an errored node still reads
|
|
3264
3368
|
// pending (the count check above), also matching.
|
|
3265
|
-
if (e.
|
|
3369
|
+
if (e.He & STATUS_ERROR) return false;
|
|
3266
3370
|
if (t.has(e)) return false;
|
|
3267
3371
|
t.add(e);
|
|
3268
|
-
const n = e.
|
|
3372
|
+
const n = e.Ze;
|
|
3269
3373
|
if (n && markWalk(n, t)) return true;
|
|
3270
3374
|
// Mid-recompute (the clearStatus companion poke runs before
|
|
3271
3375
|
// trimStaleDeps), only the validated prefix [_deps.._depsTail] is this
|
|
3272
3376
|
// pass's dependency set — walking past it would read dropped deps and
|
|
3273
3377
|
// latch a stale verdict on the companion.
|
|
3274
3378
|
const r = e;
|
|
3275
|
-
const i = r.D & REACTIVE_RECOMPUTING_DEPS ? r.
|
|
3379
|
+
const i = r.D & REACTIVE_RECOMPUTING_DEPS ? r.lt : undefined;
|
|
3276
3380
|
if (i !== null) {
|
|
3277
|
-
for (let e = r.
|
|
3278
|
-
if (!e.
|
|
3381
|
+
for (let e = r.Ye ?? null; e !== null; e = e.qe) {
|
|
3382
|
+
if (!e.Rt && markWalk(e.Be, t)) return true;
|
|
3279
3383
|
if (e === i) break;
|
|
3280
3384
|
}
|
|
3281
3385
|
}
|
|
@@ -3287,15 +3391,22 @@ function collectPendingSources(e) {
|
|
|
3287
3391
|
}
|
|
3288
3392
|
|
|
3289
3393
|
function quietPending(e) {
|
|
3290
|
-
if (e.
|
|
3291
|
-
for (const t of e.
|
|
3394
|
+
if (e.Ke) {
|
|
3395
|
+
for (const t of e.Ke) if (!t.Pt) return false;
|
|
3292
3396
|
return true;
|
|
3293
3397
|
}
|
|
3294
|
-
return e.
|
|
3398
|
+
return e.Pt;
|
|
3295
3399
|
}
|
|
3296
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.
|
|
3297
3408
|
function newQuestionInFlight(e) {
|
|
3298
|
-
return !!(e.
|
|
3409
|
+
return !!(e.He & STATUS_PENDING) && !(e.He & STATUS_UNINITIALIZED) && !quietPending(e);
|
|
3299
3410
|
}
|
|
3300
3411
|
|
|
3301
3412
|
function computePendingState(e) {
|
|
@@ -3305,17 +3416,21 @@ function computePendingState(e) {
|
|
|
3305
3416
|
// reaches its owner (and a store leaf its firewall) through its own deps,
|
|
3306
3417
|
// so the one walk covers direct marks, derivation, and companion chains.
|
|
3307
3418
|
if (markCovered(e)) return true;
|
|
3308
|
-
const n = e.
|
|
3419
|
+
const n = e.Ze;
|
|
3309
3420
|
if (e.t) {
|
|
3310
3421
|
const t = e.t;
|
|
3311
|
-
const n = t.
|
|
3422
|
+
const n = t.Ze || t;
|
|
3312
3423
|
return newQuestionInFlight(n);
|
|
3313
3424
|
}
|
|
3314
3425
|
if (n && e.k !== NOT_PENDING && !hasActiveOverride(e)) {
|
|
3315
|
-
return !!(n.D & REACTIVE_MANUAL_WRITE) || !n.
|
|
3316
|
-
}
|
|
3317
|
-
|
|
3318
|
-
|
|
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));
|
|
3319
3434
|
return true;
|
|
3320
3435
|
}
|
|
3321
3436
|
return newQuestionInFlight(t);
|
|
@@ -3334,7 +3449,7 @@ function updatePendingSignal(e) {
|
|
|
3334
3449
|
}
|
|
3335
3450
|
|
|
3336
3451
|
function updateChildCompanions(e) {
|
|
3337
|
-
for (let t = e.
|
|
3452
|
+
for (let t = e.it; t !== null; t = t.ot) {
|
|
3338
3453
|
if (t._ || t.R) updatePendingSignal(t);
|
|
3339
3454
|
}
|
|
3340
3455
|
}
|
|
@@ -3355,7 +3470,7 @@ function updateChildCompanions(e) {
|
|
|
3355
3470
|
r.add(e);
|
|
3356
3471
|
if (e._ || e.R) n(e);
|
|
3357
3472
|
for (let t = e.U; t !== null; t = t.Ge) visit(t.Ve);
|
|
3358
|
-
for (let t = e.
|
|
3473
|
+
for (let t = e.it ?? null; t !== null; t = t.ot) {
|
|
3359
3474
|
visit(t);
|
|
3360
3475
|
}
|
|
3361
3476
|
};
|
|
@@ -3418,18 +3533,18 @@ function getLatestValueComputed(e) {
|
|
|
3418
3533
|
// until the flush (#2922). Mirror the tracked-read pull here: mark the
|
|
3419
3534
|
// queued staleness through the graph, then bring the shadow up to date.
|
|
3420
3535
|
const e = queueFor(t);
|
|
3421
|
-
if (t.
|
|
3536
|
+
if (t.Je >= e.P && !(t.D & (REACTIVE_DISPOSED | REACTIVE_ZOMBIE))) {
|
|
3422
3537
|
markHeap(e);
|
|
3423
3538
|
prepareComputed(t, true);
|
|
3424
3539
|
}
|
|
3425
3540
|
i = read(t);
|
|
3426
3541
|
} catch (t) {
|
|
3427
|
-
if (t instanceof NotReadyError && (!context || !(e.
|
|
3542
|
+
if (t instanceof NotReadyError && (!context || !(e.He & STATUS_UNINITIALIZED))) return r;
|
|
3428
3543
|
throw t;
|
|
3429
3544
|
} finally {
|
|
3430
3545
|
setLatestReadActive(n);
|
|
3431
3546
|
}
|
|
3432
|
-
if (t.
|
|
3547
|
+
if (t.He & STATUS_PENDING) return r;
|
|
3433
3548
|
if (stale && currentOptimisticLane && t.i) {
|
|
3434
3549
|
const e = findLane(t.i);
|
|
3435
3550
|
const n = findLane(currentOptimisticLane);
|
|
@@ -3448,7 +3563,7 @@ function getLatestValueComputed(e) {
|
|
|
3448
3563
|
/** The isPending()-probe read path, installed as GlobalQueue._pendingCheck. */ function pendingCheckRead(e, t, n, r) {
|
|
3449
3564
|
setPendingCheckActive(false);
|
|
3450
3565
|
if (typeof e.ke === "function") prepareComputed(e, true);
|
|
3451
|
-
const i = n.
|
|
3566
|
+
const i = n.He;
|
|
3452
3567
|
if (t && i & STATUS_PENDING && i & STATUS_UNINITIALIZED) {
|
|
3453
3568
|
if (tracking && e !== t) link(e, t);
|
|
3454
3569
|
setPendingCheckActive(true);
|
|
@@ -3464,10 +3579,10 @@ function recordFreshRead(e, t) {
|
|
|
3464
3579
|
}
|
|
3465
3580
|
|
|
3466
3581
|
function applyReask(e, t) {
|
|
3467
|
-
const n = !!(e.
|
|
3468
|
-
const r = t && !(n && !e.
|
|
3469
|
-
const i = n && e.
|
|
3470
|
-
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;
|
|
3471
3586
|
return i;
|
|
3472
3587
|
}
|
|
3473
3588
|
|
|
@@ -3507,7 +3622,7 @@ function isPending(e) {
|
|
|
3507
3622
|
} catch (e) {
|
|
3508
3623
|
collectPending();
|
|
3509
3624
|
if (e instanceof NotReadyError) {
|
|
3510
|
-
const t = !!(e.source?.
|
|
3625
|
+
const t = !!(e.source?.He & STATUS_UNINITIALIZED);
|
|
3511
3626
|
if (r.found && !t) return true;
|
|
3512
3627
|
if (context && t) throw e;
|
|
3513
3628
|
}
|
|
@@ -3549,15 +3664,15 @@ GlobalQueue.Re = witnessAffects;
|
|
|
3549
3664
|
const i = !!r?.user;
|
|
3550
3665
|
const o = createEffectNode(e, t, n, i ? EFFECT_USER : EFFECT_RENDER, notifyEffectStatus, r);
|
|
3551
3666
|
recompute(o, true);
|
|
3552
|
-
!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));
|
|
3553
3668
|
}
|
|
3554
3669
|
|
|
3555
3670
|
function notifyEffectStatus(e, t) {
|
|
3556
3671
|
// Use passed values if provided, otherwise read from node
|
|
3557
|
-
const n = e !== undefined ? e : this.
|
|
3672
|
+
const n = e !== undefined ? e : this.He;
|
|
3558
3673
|
const r = t !== undefined ? t : this.me;
|
|
3559
3674
|
if (n & STATUS_ERROR) {
|
|
3560
|
-
this.
|
|
3675
|
+
this.Xe.notify(this, STATUS_PENDING, 0);
|
|
3561
3676
|
if (this.Fe === EFFECT_USER) {
|
|
3562
3677
|
// The error handler is the error arm of the effect phase (#2840 ruling):
|
|
3563
3678
|
// queue it like the effect function. It runs in the same imperative,
|
|
@@ -3568,18 +3683,18 @@ function notifyEffectStatus(e, t) {
|
|
|
3568
3683
|
// phase takes the success arm instead. Blocked forwards (explicit
|
|
3569
3684
|
// `status` arg without node-state writes) don't queue: the status
|
|
3570
3685
|
// re-propagates unblocked at commit.
|
|
3571
|
-
if (this.
|
|
3686
|
+
if (this.He & STATUS_ERROR) {
|
|
3572
3687
|
this.Qe = true;
|
|
3573
|
-
this.
|
|
3688
|
+
this.Xe.enqueue(this.Fe, this.gt ??= runEffect.bind(null, this));
|
|
3574
3689
|
}
|
|
3575
3690
|
return;
|
|
3576
3691
|
}
|
|
3577
|
-
if (!this.
|
|
3692
|
+
if (!this.Xe.notify(this, STATUS_ERROR, STATUS_ERROR)) {
|
|
3578
3693
|
haltReactivity(unwrapStatusError(r));
|
|
3579
3694
|
throw r;
|
|
3580
3695
|
}
|
|
3581
3696
|
} else if (this.Fe === EFFECT_RENDER) {
|
|
3582
|
-
this.
|
|
3697
|
+
this.Xe.notify(this, STATUS_PENDING | STATUS_ERROR, n, r);
|
|
3583
3698
|
}
|
|
3584
3699
|
}
|
|
3585
3700
|
|
|
@@ -3595,41 +3710,41 @@ function runEffect(e) {
|
|
|
3595
3710
|
// Render effects bypass: their errors route to boundaries synchronously in
|
|
3596
3711
|
// notifyEffectStatus, and a runner queued by an earlier valueChanged in the
|
|
3597
3712
|
// same flush must not be hijacked by a later-arriving error status.
|
|
3598
|
-
if (e.
|
|
3713
|
+
if (e.He & STATUS_ERROR && e.Fe === EFFECT_USER) {
|
|
3599
3714
|
const t = unwrapStatusError(e.me);
|
|
3600
|
-
e.
|
|
3715
|
+
e.Dt = e.We;
|
|
3601
3716
|
e.Qe = false;
|
|
3602
3717
|
try {
|
|
3603
|
-
e.
|
|
3604
|
-
const t = e.
|
|
3605
|
-
e.
|
|
3718
|
+
e.vt ? e.vt(t, () => {
|
|
3719
|
+
const t = e.dt;
|
|
3720
|
+
e.dt = undefined;
|
|
3606
3721
|
t?.();
|
|
3607
3722
|
}) : console.error(t);
|
|
3608
3723
|
} catch (t) {
|
|
3609
|
-
if (!e.
|
|
3724
|
+
if (!e.Xe.notify(e, STATUS_ERROR, STATUS_ERROR)) {
|
|
3610
3725
|
haltReactivity(t);
|
|
3611
3726
|
throw t;
|
|
3612
3727
|
}
|
|
3613
3728
|
}
|
|
3614
3729
|
return;
|
|
3615
3730
|
}
|
|
3616
|
-
const t = e.
|
|
3617
|
-
e.
|
|
3731
|
+
const t = e.dt;
|
|
3732
|
+
e.dt = undefined;
|
|
3618
3733
|
try {
|
|
3619
3734
|
t?.();
|
|
3620
|
-
const n = e.
|
|
3735
|
+
const n = e.wt(e.We, e.Dt);
|
|
3621
3736
|
if (false && n !== undefined && typeof n !== "function") ;
|
|
3622
3737
|
// The final cleanup is invoked by disposeChildren at true disposal.
|
|
3623
|
-
e.
|
|
3738
|
+
e.dt = n;
|
|
3624
3739
|
} catch (t) {
|
|
3625
3740
|
e.me = new StatusError(e, t);
|
|
3626
|
-
e.
|
|
3627
|
-
if (!e.
|
|
3741
|
+
e.He |= STATUS_ERROR;
|
|
3742
|
+
if (!e.Xe.notify(e, STATUS_ERROR, STATUS_ERROR)) {
|
|
3628
3743
|
haltReactivity(t);
|
|
3629
3744
|
throw t;
|
|
3630
3745
|
}
|
|
3631
3746
|
} finally {
|
|
3632
|
-
e.
|
|
3747
|
+
e.Dt = e.We;
|
|
3633
3748
|
e.Qe = false;
|
|
3634
3749
|
}
|
|
3635
3750
|
}
|
|
@@ -3649,32 +3764,32 @@ GlobalQueue.te = runEffect;
|
|
|
3649
3764
|
} finally {}
|
|
3650
3765
|
};
|
|
3651
3766
|
const n = computed(() => {
|
|
3652
|
-
const t = n.
|
|
3653
|
-
n.
|
|
3767
|
+
const t = n.dt;
|
|
3768
|
+
n.dt = undefined;
|
|
3654
3769
|
t?.();
|
|
3655
3770
|
const r = staleValues(e);
|
|
3656
|
-
n.
|
|
3771
|
+
n.dt = r;
|
|
3657
3772
|
}, {
|
|
3658
3773
|
...t,
|
|
3659
3774
|
lazy: true
|
|
3660
3775
|
});
|
|
3661
|
-
n.
|
|
3776
|
+
n.dt = undefined;
|
|
3662
3777
|
n.Ue = n.Ue & ~CONFIG_AUTO_DISPOSE | CONFIG_CHILDREN_FORBIDDEN;
|
|
3663
3778
|
n.Qe = true;
|
|
3664
3779
|
n.Fe = EFFECT_TRACKED;
|
|
3665
3780
|
n.yt = (e, t) => {
|
|
3666
|
-
const r = e !== undefined ? e : n.
|
|
3781
|
+
const r = e !== undefined ? e : n.He;
|
|
3667
3782
|
if (r & STATUS_ERROR) {
|
|
3668
|
-
n.
|
|
3783
|
+
n.Xe.notify(n, STATUS_PENDING, 0);
|
|
3669
3784
|
const e = t !== undefined ? t : n.me;
|
|
3670
|
-
if (!n.
|
|
3785
|
+
if (!n.Xe.notify(n, STATUS_ERROR, STATUS_ERROR)) {
|
|
3671
3786
|
haltReactivity(unwrapStatusError(e));
|
|
3672
3787
|
throw e;
|
|
3673
3788
|
}
|
|
3674
3789
|
}
|
|
3675
3790
|
};
|
|
3676
|
-
n.
|
|
3677
|
-
n.
|
|
3791
|
+
n.ze = run;
|
|
3792
|
+
n.Xe.enqueue(EFFECT_USER, run);
|
|
3678
3793
|
}
|
|
3679
3794
|
|
|
3680
3795
|
function restoreTransition(e, t) {
|
|
@@ -3867,38 +3982,6 @@ function createSignal(e, t) {
|
|
|
3867
3982
|
return [ accessor(n), setSignal.bind(null, n) ];
|
|
3868
3983
|
}
|
|
3869
3984
|
|
|
3870
|
-
/**
|
|
3871
|
-
* Creates a readonly derived reactive memoized signal.
|
|
3872
|
-
*
|
|
3873
|
-
* ```typescript
|
|
3874
|
-
* const value = createMemo<T>(compute, options?: MemoOptions<T>);
|
|
3875
|
-
* ```
|
|
3876
|
-
* @param compute a function that receives its previous value and returns a new value used to react on a computation
|
|
3877
|
-
* @param options `MemoOptions` -- id, name, equals, unobserved, lazy
|
|
3878
|
-
*
|
|
3879
|
-
* @example
|
|
3880
|
-
* ```ts
|
|
3881
|
-
* const [first, setFirst] = createSignal("Ada");
|
|
3882
|
-
* const [last, setLast] = createSignal("Lovelace");
|
|
3883
|
-
*
|
|
3884
|
-
* const fullName = createMemo(() => `${first()} ${last()}`);
|
|
3885
|
-
*
|
|
3886
|
-
* fullName(); // "Ada Lovelace"
|
|
3887
|
-
* ```
|
|
3888
|
-
*
|
|
3889
|
-
* @example
|
|
3890
|
-
* ```ts
|
|
3891
|
-
* // Async memo — reads surface as pending inside <Loading>
|
|
3892
|
-
* const user = createMemo(async () => {
|
|
3893
|
-
* const res = await fetch(`/users/${id()}`);
|
|
3894
|
-
* return res.json();
|
|
3895
|
-
* });
|
|
3896
|
-
* ```
|
|
3897
|
-
*
|
|
3898
|
-
* @description https://docs.solidjs.com/reference/basic-reactivity/create-memo
|
|
3899
|
-
*/
|
|
3900
|
-
// NoInfer keeps the previous-value parameter from influencing T inference, so
|
|
3901
|
-
// the memo/effect result type is still driven by the compute return type.
|
|
3902
3985
|
function createMemo(e, t) {
|
|
3903
3986
|
return accessor(computed(e, t));
|
|
3904
3987
|
}
|
|
@@ -3924,7 +4007,7 @@ function createEffect(e, t, n) {
|
|
|
3924
4007
|
* ```
|
|
3925
4008
|
* @param compute a function that receives its previous value and returns a new value used to react on a computation
|
|
3926
4009
|
* @param effectFn a function that receives the new value and is used to perform side effects
|
|
3927
|
-
* @param options `EffectOptions` -- name, defer, schedule
|
|
4010
|
+
* @param options `EffectOptions` -- name, defer, schedule, transparent
|
|
3928
4011
|
*
|
|
3929
4012
|
* @example
|
|
3930
4013
|
* ```ts
|
|
@@ -4072,9 +4155,9 @@ function createEffect(e, t, n) {
|
|
|
4072
4155
|
// route through the inherited queue.
|
|
4073
4156
|
const i = getOwner();
|
|
4074
4157
|
const o = new MicrotaskQueue;
|
|
4075
|
-
o.Z = i.
|
|
4158
|
+
o.Z = i.Xe;
|
|
4076
4159
|
// notify() forwards up the normal chain
|
|
4077
|
-
i.
|
|
4160
|
+
i.Xe = o;
|
|
4078
4161
|
// A user effect rather than a bare computed: computeds are pull-based and
|
|
4079
4162
|
// are only re-enqueued when a pending source *resolves* — a rejection just
|
|
4080
4163
|
// marks them errored, so nothing would re-run and the promise would never
|
|
@@ -4921,10 +5004,18 @@ function createProjectionInternal(e, t, n) {
|
|
|
4921
5004
|
return t;
|
|
4922
5005
|
};
|
|
4923
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
|
+
};
|
|
4924
5015
|
r = computed(() => {
|
|
4925
5016
|
if (!r) r = getOwner();
|
|
4926
5017
|
runProjectionComputed(s, e, n?.key === undefined ? "id" : n.key);
|
|
4927
|
-
},
|
|
5018
|
+
}, u);
|
|
4928
5019
|
r.Ue &= ~CONFIG_AUTO_DISPOSE;
|
|
4929
5020
|
return {
|
|
4930
5021
|
store: s,
|
|
@@ -4999,16 +5090,43 @@ function createProjectionInternal(e, t, n) {
|
|
|
4999
5090
|
const o = getOwner();
|
|
5000
5091
|
let s = false;
|
|
5001
5092
|
let u;
|
|
5002
|
-
|
|
5003
|
-
|
|
5004
|
-
|
|
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);
|
|
5005
5111
|
s = true;
|
|
5006
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));
|
|
5007
5120
|
if (t === i || t === undefined) return;
|
|
5008
5121
|
const write = () => storeSetter(e, e => reconcileState(t, e, n, true));
|
|
5009
5122
|
r ? r(write) : write();
|
|
5010
5123
|
};
|
|
5011
|
-
|
|
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);
|
|
5012
5130
|
});
|
|
5013
5131
|
return o;
|
|
5014
5132
|
}
|
|
@@ -5668,7 +5786,7 @@ function prepareStoreWrite(e, t, n) {
|
|
|
5668
5786
|
}
|
|
5669
5787
|
const r = e[STORE_VALUE];
|
|
5670
5788
|
const i = r[n];
|
|
5671
|
-
if (snapshotCaptureActive && typeof n !== "symbol" && !((e[STORE_FIREWALL]?.
|
|
5789
|
+
if (snapshotCaptureActive && typeof n !== "symbol" && !((e[STORE_FIREWALL]?.He ?? 0) & STATUS_PENDING)) {
|
|
5672
5790
|
if (!e[STORE_SNAPSHOT_PROPS]) {
|
|
5673
5791
|
e[STORE_SNAPSHOT_PROPS] = Object.create(null);
|
|
5674
5792
|
snapshotSources?.add(e);
|
|
@@ -5791,7 +5909,7 @@ let Writing = null;
|
|
|
5791
5909
|
*/ function throwIfUnreadable(e) {
|
|
5792
5910
|
const t = e[STORE_FIREWALL];
|
|
5793
5911
|
if (!t) return;
|
|
5794
|
-
const n = t.
|
|
5912
|
+
const n = t.He;
|
|
5795
5913
|
if (n & STATUS_ERROR || n & STATUS_UNINITIALIZED && n & STATUS_PENDING) throw t.me ?? new NotReadyError(t);
|
|
5796
5914
|
}
|
|
5797
5915
|
|
|
@@ -6154,7 +6272,7 @@ function createStore(e, t, n) {
|
|
|
6154
6272
|
* flush that would surface them, before effects run — verdict-only, netting
|
|
6155
6273
|
* no visual change.
|
|
6156
6274
|
*/ function notifyMarkBoundaries(e) {
|
|
6157
|
-
if (!e.U && !e.
|
|
6275
|
+
if (!e.U && !e.it) return;
|
|
6158
6276
|
const t = new NotReadyError(e);
|
|
6159
6277
|
t.ve = true;
|
|
6160
6278
|
const n = new Set;
|
|
@@ -6257,7 +6375,7 @@ function createOptimisticStore(e, t, n) {
|
|
|
6257
6375
|
const e = GlobalQueue.Ae;
|
|
6258
6376
|
GlobalQueue.Ae = t => {
|
|
6259
6377
|
for (const e of t.V) {
|
|
6260
|
-
if ((e[$TARGET]?.[STORE_FIREWALL]?.
|
|
6378
|
+
if ((e[$TARGET]?.[STORE_FIREWALL]?.He ?? 0) & STATUS_PENDING) return true;
|
|
6261
6379
|
}
|
|
6262
6380
|
return e(t);
|
|
6263
6381
|
};
|
|
@@ -6343,7 +6461,7 @@ function clearOptimisticStores(e, t) {
|
|
|
6343
6461
|
a.p = null;
|
|
6344
6462
|
a.k = NOT_PENDING;
|
|
6345
6463
|
a.We = i;
|
|
6346
|
-
if (!a.
|
|
6464
|
+
if (!a.Nt || !a.Nt(o, i)) {
|
|
6347
6465
|
insertSubs(a, true);
|
|
6348
6466
|
schedule();
|
|
6349
6467
|
}
|
|
@@ -6414,6 +6532,11 @@ function createOptimisticProjectionInternal(e, t, n) {
|
|
|
6414
6532
|
setProjectionWriteActive(t);
|
|
6415
6533
|
}
|
|
6416
6534
|
};
|
|
6535
|
+
// seedLoadingValue: born-committed firewall, same as createProjection.
|
|
6536
|
+
let t;
|
|
6537
|
+
if (n?.seedLoadingValue) t = {
|
|
6538
|
+
loadingValue: undefined
|
|
6539
|
+
};
|
|
6417
6540
|
r = computed(() => {
|
|
6418
6541
|
setProjectionWriteActive(true);
|
|
6419
6542
|
try {
|
|
@@ -6421,7 +6544,7 @@ function createOptimisticProjectionInternal(e, t, n) {
|
|
|
6421
6544
|
} finally {
|
|
6422
6545
|
setProjectionWriteActive(false);
|
|
6423
6546
|
}
|
|
6424
|
-
},
|
|
6547
|
+
}, t);
|
|
6425
6548
|
r.Ue &= ~CONFIG_AUTO_DISPOSE;
|
|
6426
6549
|
}
|
|
6427
6550
|
return {
|
|
@@ -6846,23 +6969,23 @@ function mapArray(e, t, n) {
|
|
|
6846
6969
|
const i = t.length > 1;
|
|
6847
6970
|
const o = t;
|
|
6848
6971
|
const s = {
|
|
6849
|
-
|
|
6850
|
-
|
|
6851
|
-
|
|
6852
|
-
|
|
6853
|
-
|
|
6854
|
-
kt: [],
|
|
6972
|
+
Lt: createOwner(),
|
|
6973
|
+
Gt: 0,
|
|
6974
|
+
Vt: e,
|
|
6975
|
+
Ut: [],
|
|
6976
|
+
kt: o,
|
|
6855
6977
|
Wt: [],
|
|
6856
|
-
Ft:
|
|
6857
|
-
Qt: r
|
|
6858
|
-
xt:
|
|
6859
|
-
Ht: n?.keyed
|
|
6860
|
-
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
|
|
6861
6984
|
};
|
|
6862
6985
|
const u = computed(updateKeyedMap.bind(s));
|
|
6863
6986
|
// Untracked reads inside the internal owner resolve via _parentComputed; routing
|
|
6864
6987
|
// them through node lets store-proxy lookups see pending writes (not stale _value).
|
|
6865
|
-
s.
|
|
6988
|
+
s.Lt.tt = u;
|
|
6866
6989
|
u.Ue &= ~CONFIG_AUTO_DISPOSE;
|
|
6867
6990
|
return accessor(u);
|
|
6868
6991
|
}
|
|
@@ -6881,52 +7004,52 @@ const pureOptions = {
|
|
|
6881
7004
|
// strong-abort ordering: removed rows now dispose AFTER the pass's new rows
|
|
6882
7005
|
// are created (you cannot destroy state before knowing the pass will land).
|
|
6883
7006
|
function updateKeyedMap() {
|
|
6884
|
-
const e = this.
|
|
7007
|
+
const e = this.Vt() || [], t = e.length;
|
|
6885
7008
|
e[$TRACK];
|
|
6886
7009
|
// top level tracking
|
|
6887
|
-
runWithOwner(this.
|
|
7010
|
+
runWithOwner(this.Lt, () => {
|
|
6888
7011
|
let n, r, i, o,
|
|
6889
7012
|
// Mappers write freshly-created row/index signals into the STAGE
|
|
6890
7013
|
// arrays (`rows`/`indexes`), never into `this._rows`/`this._indexes`.
|
|
6891
|
-
s = this.
|
|
7014
|
+
s = this.xt ? this.Mt ? () => {
|
|
6892
7015
|
i[r] = signal(e[r], pureOptions);
|
|
6893
|
-
return this.
|
|
7016
|
+
return this.kt(accessor(i[r]), r);
|
|
6894
7017
|
} : () => {
|
|
6895
7018
|
i[r] = signal(e[r], pureOptions);
|
|
6896
7019
|
o && (o[r] = signal(r, pureOptions));
|
|
6897
|
-
return this.
|
|
6898
|
-
} : this.
|
|
7020
|
+
return this.kt(accessor(i[r]), o ? accessor(o[r]) : undefined);
|
|
7021
|
+
} : this.Ht ? () => {
|
|
6899
7022
|
const t = e[r];
|
|
6900
7023
|
o[r] = signal(r, pureOptions);
|
|
6901
|
-
return this.
|
|
7024
|
+
return this.kt(t, accessor(o[r]));
|
|
6902
7025
|
} : () => {
|
|
6903
7026
|
const t = e[r];
|
|
6904
|
-
return this.
|
|
7027
|
+
return this.kt(t);
|
|
6905
7028
|
};
|
|
6906
7029
|
// fast path for empty arrays
|
|
6907
7030
|
if (t === 0) {
|
|
6908
|
-
if (this.
|
|
6909
|
-
this.
|
|
7031
|
+
if (this.Gt !== 0) {
|
|
7032
|
+
this.Lt.dispose(false);
|
|
7033
|
+
this.Ft = [];
|
|
7034
|
+
this.Ut = [];
|
|
6910
7035
|
this.Wt = [];
|
|
6911
|
-
this.
|
|
6912
|
-
this.kt = [];
|
|
6913
|
-
this.Lt = 0;
|
|
6914
|
-
this.Qt && (this.Qt = []);
|
|
7036
|
+
this.Gt = 0;
|
|
6915
7037
|
this.xt && (this.xt = []);
|
|
7038
|
+
this.Ht && (this.Ht = []);
|
|
6916
7039
|
}
|
|
6917
|
-
if (this
|
|
7040
|
+
if (this.$t && !this.Wt[0]) {
|
|
6918
7041
|
// an aborted fallback attempt leaves an owner without a mapping;
|
|
6919
7042
|
// dispose it before re-creating
|
|
6920
|
-
this.
|
|
6921
|
-
this.
|
|
7043
|
+
this.Ft[0]?.dispose();
|
|
7044
|
+
this.Wt[0] = runWithOwner(this.Ft[0] = createOwner(), this.$t);
|
|
6922
7045
|
}
|
|
6923
7046
|
}
|
|
6924
7047
|
// fast path for new create
|
|
6925
|
-
else if (this.
|
|
7048
|
+
else if (this.Gt === 0) {
|
|
6926
7049
|
const u = new Array(t);
|
|
6927
7050
|
const l = new Array(t);
|
|
6928
|
-
i = this.
|
|
6929
|
-
o = this.
|
|
7051
|
+
i = this.xt && new Array(t);
|
|
7052
|
+
o = this.Ht && new Array(t);
|
|
6930
7053
|
try {
|
|
6931
7054
|
for (r = 0; r < t; r++) u[r] = runWithOwner(l[r] = createOwner(), s);
|
|
6932
7055
|
} catch (e) {
|
|
@@ -6934,43 +7057,43 @@ function updateKeyedMap() {
|
|
|
6934
7057
|
throw e;
|
|
6935
7058
|
}
|
|
6936
7059
|
// commit
|
|
6937
|
-
if (this.
|
|
7060
|
+
if (this.Ft[0]) this.Ft[0].dispose();
|
|
6938
7061
|
// previous fallback
|
|
6939
|
-
this.
|
|
6940
|
-
this.
|
|
6941
|
-
i && (this.
|
|
6942
|
-
o && (this.
|
|
6943
|
-
this.
|
|
6944
|
-
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;
|
|
6945
7068
|
} else {
|
|
6946
7069
|
let u, l, a, c, f, E, d, S, T;
|
|
6947
7070
|
// skip common prefix
|
|
6948
|
-
for (u = 0, l = Math.min(this.
|
|
6949
|
-
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]);
|
|
6950
7073
|
}
|
|
6951
7074
|
// skip common suffix — counted only; retained entries land in one pass
|
|
6952
7075
|
// at commit instead of being staged and copied twice
|
|
6953
|
-
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--,
|
|
6954
7077
|
a--) ;
|
|
6955
7078
|
// no structural change (every position matched in place at equal
|
|
6956
7079
|
// length — the common post-reconcile shape): keep the same mapped
|
|
6957
7080
|
// array identity so downstream consumers don't re-run at all
|
|
6958
|
-
if (u === t && this.
|
|
6959
|
-
this.
|
|
7081
|
+
if (u === t && this.Gt === t) {
|
|
7082
|
+
this.Ut = e.slice(0);
|
|
6960
7083
|
return;
|
|
6961
7084
|
}
|
|
6962
|
-
const O = t - this.
|
|
7085
|
+
const O = t - this.Gt;
|
|
6963
7086
|
const _ = new Array(t);
|
|
6964
7087
|
const R = new Array(t);
|
|
6965
|
-
i = this.
|
|
6966
|
-
o = this.
|
|
7088
|
+
i = this.xt ? new Array(t) : undefined;
|
|
7089
|
+
o = this.Ht ? new Array(t) : undefined;
|
|
6967
7090
|
// 0) prepare a map of all indices in the changed window of newItems,
|
|
6968
7091
|
// scanning backwards so we encounter them in natural order
|
|
6969
7092
|
E = new Map;
|
|
6970
7093
|
d = new Array(a + 1);
|
|
6971
7094
|
for (r = a; r >= u; r--) {
|
|
6972
7095
|
c = e[r];
|
|
6973
|
-
f = this.
|
|
7096
|
+
f = this.Qt ? this.Qt(c) : c;
|
|
6974
7097
|
n = E.get(f);
|
|
6975
7098
|
d[r] = n === undefined ? -1 : n;
|
|
6976
7099
|
E.set(f, r);
|
|
@@ -6979,17 +7102,17 @@ function updateKeyedMap() {
|
|
|
6979
7102
|
// in the new set; if so, stage them at their new positions; if not,
|
|
6980
7103
|
// queue them for disposal at commit
|
|
6981
7104
|
for (n = u; n <= l; n++) {
|
|
6982
|
-
c = this.
|
|
6983
|
-
f = this.
|
|
7105
|
+
c = this.Ut[n];
|
|
7106
|
+
f = this.Qt ? this.Qt(c) : c;
|
|
6984
7107
|
r = E.get(f);
|
|
6985
7108
|
if (r !== undefined && r !== -1) {
|
|
6986
|
-
_[r] = this.
|
|
6987
|
-
R[r] = this.
|
|
6988
|
-
i && (i[r] = this.
|
|
6989
|
-
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]);
|
|
6990
7113
|
r = d[r];
|
|
6991
7114
|
E.set(f, r);
|
|
6992
|
-
} else (S ??= []).push(this.
|
|
7115
|
+
} else (S ??= []).push(this.Ft[n]);
|
|
6993
7116
|
}
|
|
6994
7117
|
// 2) create new rows into the temp arrays; an abort disposes only these
|
|
6995
7118
|
try {
|
|
@@ -7006,38 +7129,38 @@ function updateKeyedMap() {
|
|
|
7006
7129
|
// into the fresh arrays, swap them in (new identity for downstream
|
|
7007
7130
|
// change propagation), then dispose exited rows
|
|
7008
7131
|
for (n = 0; n < u; n++) {
|
|
7009
|
-
_[n] = this.
|
|
7010
|
-
R[n] = this.
|
|
7011
|
-
i && (i[n] = this.
|
|
7012
|
-
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]);
|
|
7013
7136
|
}
|
|
7014
7137
|
for (r = u; r <= a; r++) {
|
|
7015
7138
|
if (i) setSignal(i[r], e[r]);
|
|
7016
7139
|
if (o) setSignal(o[r], r);
|
|
7017
7140
|
}
|
|
7018
7141
|
for (r = a + 1; r < t; r++) {
|
|
7019
|
-
_[r] = this.
|
|
7020
|
-
R[r] = this.
|
|
7142
|
+
_[r] = this.Wt[r - O];
|
|
7143
|
+
R[r] = this.Ft[r - O];
|
|
7021
7144
|
if (i) {
|
|
7022
|
-
i[r] = this.
|
|
7145
|
+
i[r] = this.xt[r - O];
|
|
7023
7146
|
setSignal(i[r], e[r]);
|
|
7024
7147
|
}
|
|
7025
7148
|
if (o) {
|
|
7026
|
-
o[r] = this.
|
|
7149
|
+
o[r] = this.Ht[r - O];
|
|
7027
7150
|
if (O !== 0) setSignal(o[r], r);
|
|
7028
7151
|
}
|
|
7029
7152
|
}
|
|
7030
|
-
this.
|
|
7031
|
-
this.
|
|
7032
|
-
i && (this.
|
|
7033
|
-
o && (this.
|
|
7034
|
-
this.
|
|
7153
|
+
this.Wt = _;
|
|
7154
|
+
this.Ft = R;
|
|
7155
|
+
i && (this.xt = i);
|
|
7156
|
+
o && (this.Ht = o);
|
|
7157
|
+
this.Gt = t;
|
|
7035
7158
|
// save a copy of the mapped items for the next update
|
|
7036
|
-
this.
|
|
7159
|
+
this.Ut = e.slice(0);
|
|
7037
7160
|
if (S) for (n = 0; n < S.length; n++) S[n].dispose();
|
|
7038
7161
|
}
|
|
7039
7162
|
});
|
|
7040
|
-
return this.
|
|
7163
|
+
return this.Wt;
|
|
7041
7164
|
}
|
|
7042
7165
|
|
|
7043
7166
|
/**
|
|
@@ -7057,21 +7180,21 @@ function updateKeyedMap() {
|
|
|
7057
7180
|
*/ function repeat(e, t, n) {
|
|
7058
7181
|
const r = t;
|
|
7059
7182
|
const i = {
|
|
7060
|
-
|
|
7061
|
-
|
|
7062
|
-
|
|
7063
|
-
|
|
7064
|
-
|
|
7183
|
+
Lt: createOwner(),
|
|
7184
|
+
Gt: 0,
|
|
7185
|
+
jt: 0,
|
|
7186
|
+
Kt: e,
|
|
7187
|
+
kt: r,
|
|
7188
|
+
Ft: [],
|
|
7065
7189
|
Wt: [],
|
|
7066
|
-
|
|
7067
|
-
|
|
7068
|
-
Mt: n?.fallback
|
|
7190
|
+
Yt: n?.from,
|
|
7191
|
+
$t: n?.fallback
|
|
7069
7192
|
};
|
|
7070
7193
|
const o = computed(updateRepeat.bind(i));
|
|
7071
7194
|
// Same as mapArray: untracked reads inside the internal owner resolve via
|
|
7072
7195
|
// _parentComputed, so async reads in row callbacks register with the node
|
|
7073
7196
|
// (pending tracking + post-settle retry) instead of vanishing.
|
|
7074
|
-
i.
|
|
7197
|
+
i.Lt.tt = o;
|
|
7075
7198
|
o.Ue &= ~CONFIG_AUTO_DISPOSE;
|
|
7076
7199
|
return accessor(o);
|
|
7077
7200
|
}
|
|
@@ -7084,55 +7207,55 @@ function updateKeyedMap() {
|
|
|
7084
7207
|
// for the post-settle retry. The overlap math also subsumes the previous
|
|
7085
7208
|
// disjoint-window/front-clear/end-clear/shift special cases.
|
|
7086
7209
|
function updateRepeat() {
|
|
7087
|
-
const e = this.
|
|
7088
|
-
const t = this.
|
|
7089
|
-
runWithOwner(this.
|
|
7210
|
+
const e = this.Kt();
|
|
7211
|
+
const t = this.Yt?.() || 0;
|
|
7212
|
+
runWithOwner(this.Lt, () => {
|
|
7090
7213
|
if (e === 0) {
|
|
7091
|
-
if (this.
|
|
7092
|
-
this.
|
|
7214
|
+
if (this.Gt !== 0) {
|
|
7215
|
+
this.Lt.dispose(false);
|
|
7216
|
+
this.Ft = [];
|
|
7093
7217
|
this.Wt = [];
|
|
7094
|
-
this.
|
|
7095
|
-
this.Lt = 0;
|
|
7218
|
+
this.Gt = 0;
|
|
7096
7219
|
// Reset offset to match the cleared data (#2767, repro 2).
|
|
7097
|
-
this
|
|
7220
|
+
this.jt = 0;
|
|
7098
7221
|
}
|
|
7099
|
-
if (this
|
|
7222
|
+
if (this.$t && !this.Wt[0]) {
|
|
7100
7223
|
// an aborted fallback attempt leaves an owner without a mapping;
|
|
7101
7224
|
// dispose it before re-creating
|
|
7102
|
-
this.
|
|
7103
|
-
this.
|
|
7225
|
+
this.Ft[0]?.dispose();
|
|
7226
|
+
this.Wt[0] = runWithOwner(this.Ft[0] = createOwner(), this.$t);
|
|
7104
7227
|
}
|
|
7105
7228
|
return;
|
|
7106
7229
|
}
|
|
7107
7230
|
const n = t + e;
|
|
7108
|
-
const r = this
|
|
7231
|
+
const r = this.jt + this.Gt;
|
|
7109
7232
|
// Retained overlap [keepStart, keepEnd) in global indexes; empty when the
|
|
7110
7233
|
// windows are disjoint or when coming from empty/fallback.
|
|
7111
|
-
const i = Math.max(t, this
|
|
7234
|
+
const i = Math.max(t, this.jt);
|
|
7112
7235
|
const o = Math.min(n, r);
|
|
7113
7236
|
const s = new Array(e);
|
|
7114
7237
|
const u = new Array(e);
|
|
7115
7238
|
for (let e = i; e < o; e++) {
|
|
7116
|
-
u[e - t] = this.
|
|
7117
|
-
s[e - t] = this.
|
|
7239
|
+
u[e - t] = this.Ft[e - this.jt];
|
|
7240
|
+
s[e - t] = this.Wt[e - this.jt];
|
|
7118
7241
|
}
|
|
7119
7242
|
try {
|
|
7120
7243
|
for (let e = t; e < n; e++) {
|
|
7121
7244
|
if (e >= i && e < o) continue;
|
|
7122
|
-
s[e - t] = runWithOwner(u[e - t] = createOwner(), () => this.
|
|
7245
|
+
s[e - t] = runWithOwner(u[e - t] = createOwner(), () => this.kt(e));
|
|
7123
7246
|
}
|
|
7124
7247
|
} catch (e) {
|
|
7125
7248
|
for (let e = t; e < n; e++) if ((e < i || e >= o) && u[e - t]) u[e - t].dispose();
|
|
7126
7249
|
throw e;
|
|
7127
7250
|
}
|
|
7128
7251
|
// commit: dispose the previous fallback or the rows leaving the window
|
|
7129
|
-
if (this.
|
|
7130
|
-
this.
|
|
7131
|
-
this.
|
|
7132
|
-
this
|
|
7133
|
-
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;
|
|
7134
7257
|
});
|
|
7135
|
-
return this.
|
|
7258
|
+
return this.Wt;
|
|
7136
7259
|
}
|
|
7137
7260
|
|
|
7138
7261
|
function compare(e, t, n) {
|
|
@@ -7145,21 +7268,21 @@ function boundaryComputed(e, t) {
|
|
|
7145
7268
|
});
|
|
7146
7269
|
n.yt = (e, t) => {
|
|
7147
7270
|
// Use passed values if provided, otherwise read from node
|
|
7148
|
-
const r = e !== undefined ? e : n.
|
|
7271
|
+
const r = e !== undefined ? e : n.He;
|
|
7149
7272
|
const i = t !== undefined ? t : n.me;
|
|
7150
7273
|
// Notify both status dimensions like a render effect does; the queue chain
|
|
7151
7274
|
// consumes this boundary's own type and forwards the remainder upward until
|
|
7152
7275
|
// a boundary that handles it is found.
|
|
7153
|
-
n.
|
|
7154
|
-
const o = n.
|
|
7276
|
+
n.He &= ~n.qt;
|
|
7277
|
+
const o = n.Xe.notify(n, STATUS_PENDING | STATUS_ERROR, r, i);
|
|
7155
7278
|
// The queue is the only propagation channel: a foreign status must not stay
|
|
7156
7279
|
// reader-visible on the tree, or reads re-throw it across the boundary and
|
|
7157
7280
|
// link unrelated ambient contexts (the #2809 nested-boundary loop). Deps are
|
|
7158
7281
|
// untouched, so the tree still recomputes when the foreign source settles.
|
|
7159
|
-
const s = r & ~n.
|
|
7282
|
+
const s = r & ~n.qt & (STATUS_PENDING | STATUS_ERROR);
|
|
7160
7283
|
if (s) {
|
|
7161
|
-
n.
|
|
7162
|
-
if (n.me === i && !(n.
|
|
7284
|
+
n.He &= ~s;
|
|
7285
|
+
if (n.me === i && !(n.He & (STATUS_PENDING | STATUS_ERROR))) n.me = undefined;
|
|
7163
7286
|
}
|
|
7164
7287
|
// An ERROR the chain could not deliver to any boundary is uncaught. The
|
|
7165
7288
|
// scrub above already removed it from reader-visible state, so without
|
|
@@ -7170,16 +7293,16 @@ function boundaryComputed(e, t) {
|
|
|
7170
7293
|
throw i;
|
|
7171
7294
|
}
|
|
7172
7295
|
};
|
|
7173
|
-
n.
|
|
7296
|
+
n.qt = t;
|
|
7174
7297
|
n.Ue &= ~CONFIG_AUTO_DISPOSE;
|
|
7175
7298
|
recompute(n, true);
|
|
7176
7299
|
return n;
|
|
7177
7300
|
}
|
|
7178
7301
|
|
|
7179
7302
|
function createBoundChildren(e, t, n, r) {
|
|
7180
|
-
const i = e.
|
|
7181
|
-
i.addChild(e.
|
|
7182
|
-
cleanup(() => i.removeChild(e.
|
|
7303
|
+
const i = e.Xe;
|
|
7304
|
+
i.addChild(e.Xe = n);
|
|
7305
|
+
cleanup(() => i.removeChild(e.Xe));
|
|
7183
7306
|
return runWithOwner(e, () => {
|
|
7184
7307
|
const e = computed(t);
|
|
7185
7308
|
return boundaryComputed(() => flatten(read(e)), r);
|
|
@@ -7201,53 +7324,53 @@ function isRevealController(e) {
|
|
|
7201
7324
|
}
|
|
7202
7325
|
|
|
7203
7326
|
function isSlotReady(e) {
|
|
7204
|
-
return isRevealController(e) ? e.
|
|
7327
|
+
return isRevealController(e) ? e.Bt() : e.Zt.size === 0 && !e.Xt;
|
|
7205
7328
|
}
|
|
7206
7329
|
|
|
7207
7330
|
function isSlotMinimallyReady(e) {
|
|
7208
|
-
return isRevealController(e) ? e.
|
|
7331
|
+
return isRevealController(e) ? e.zt() : isSlotReady(e);
|
|
7209
7332
|
}
|
|
7210
7333
|
|
|
7211
7334
|
function setSlotState(e, t, n, r) {
|
|
7212
|
-
setSignal(e.
|
|
7213
|
-
setSignal(e.
|
|
7335
|
+
setSignal(e.Jt, n);
|
|
7336
|
+
setSignal(e.en, r);
|
|
7214
7337
|
if (isRevealController(e)) {
|
|
7215
|
-
if (!n && e.
|
|
7216
|
-
return e.
|
|
7338
|
+
if (!n && e.tn === t) e.tn = undefined;
|
|
7339
|
+
return e.nn(n, r);
|
|
7217
7340
|
}
|
|
7218
|
-
if (!n && e.
|
|
7341
|
+
if (!n && e.rn === t && e.sn) e.rn = undefined;
|
|
7219
7342
|
}
|
|
7220
7343
|
|
|
7221
7344
|
class RevealController {
|
|
7222
|
-
sn;
|
|
7223
7345
|
un;
|
|
7224
|
-
ln
|
|
7225
|
-
|
|
7226
|
-
|
|
7346
|
+
ln;
|
|
7347
|
+
an=[];
|
|
7348
|
+
tn;
|
|
7349
|
+
Jt=signal(false, {
|
|
7227
7350
|
ownedWrite: true,
|
|
7228
|
-
|
|
7351
|
+
bt: true
|
|
7229
7352
|
});
|
|
7230
|
-
|
|
7353
|
+
en=signal(false, {
|
|
7231
7354
|
ownedWrite: true,
|
|
7232
|
-
|
|
7355
|
+
bt: true
|
|
7233
7356
|
});
|
|
7234
|
-
an=true;
|
|
7235
7357
|
cn=true;
|
|
7236
|
-
fn=
|
|
7358
|
+
fn=true;
|
|
7359
|
+
En=false;
|
|
7237
7360
|
constructor(e, t) {
|
|
7238
|
-
this.
|
|
7239
|
-
this.
|
|
7361
|
+
this.un = e;
|
|
7362
|
+
this.ln = t;
|
|
7240
7363
|
}
|
|
7241
|
-
|
|
7242
|
-
for (let t = 0; t < this.
|
|
7243
|
-
const n = this.
|
|
7244
|
-
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;
|
|
7245
7368
|
if (e(n) === false) return false;
|
|
7246
7369
|
}
|
|
7247
7370
|
return true;
|
|
7248
7371
|
}
|
|
7249
|
-
|
|
7250
|
-
return this.
|
|
7372
|
+
Bt() {
|
|
7373
|
+
return this.dn(isSlotReady);
|
|
7251
7374
|
}
|
|
7252
7375
|
/**
|
|
7253
7376
|
* "Minimally ready" = this group has something visible to show under its own policy.
|
|
@@ -7255,13 +7378,13 @@ class RevealController {
|
|
|
7255
7378
|
* - `together`: every direct slot is minimally ready.
|
|
7256
7379
|
* - `sequential`: the first owned slot is minimally ready (frontier can advance).
|
|
7257
7380
|
* - `natural`: any owned slot is minimally ready.
|
|
7258
|
-
*/
|
|
7259
|
-
const e = untrack(this.
|
|
7260
|
-
if (e === "together") return this.
|
|
7381
|
+
*/ zt() {
|
|
7382
|
+
const e = untrack(this.un);
|
|
7383
|
+
if (e === "together") return this.dn(isSlotMinimallyReady);
|
|
7261
7384
|
if (e === "natural") {
|
|
7262
7385
|
let e = false;
|
|
7263
7386
|
let t = false;
|
|
7264
|
-
this.
|
|
7387
|
+
this.dn(n => {
|
|
7265
7388
|
e = true;
|
|
7266
7389
|
if (isSlotMinimallyReady(n)) {
|
|
7267
7390
|
t = true;
|
|
@@ -7272,45 +7395,45 @@ class RevealController {
|
|
|
7272
7395
|
}
|
|
7273
7396
|
// sequential: only the first owned slot matters.
|
|
7274
7397
|
let t = true;
|
|
7275
|
-
this.
|
|
7398
|
+
this.dn(e => {
|
|
7276
7399
|
t = isSlotMinimallyReady(e);
|
|
7277
7400
|
return false;
|
|
7278
7401
|
});
|
|
7279
7402
|
return t;
|
|
7280
7403
|
}
|
|
7281
|
-
dn(e) {
|
|
7282
|
-
if (this.ln.includes(e)) return;
|
|
7283
|
-
this.ln.push(e);
|
|
7284
|
-
const t = untrack(this.sn);
|
|
7285
|
-
setSignal(e.zt, true), setSignal(e.Jt, t === "sequential" ? !!untrack(this.un) : false);
|
|
7286
|
-
untrack(() => this.tn());
|
|
7287
|
-
}
|
|
7288
7404
|
Sn(e) {
|
|
7289
|
-
|
|
7290
|
-
|
|
7291
|
-
untrack(
|
|
7292
|
-
|
|
7293
|
-
|
|
7294
|
-
|
|
7295
|
-
|
|
7296
|
-
const
|
|
7297
|
-
|
|
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;
|
|
7298
7421
|
try {
|
|
7299
|
-
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;
|
|
7300
7423
|
if (n) {
|
|
7301
7424
|
// Held by an outer group. Propagate the hold (and whatever collapsed policy
|
|
7302
7425
|
// the outer asked for) down the whole subtree. Inner order is ignored while
|
|
7303
7426
|
// held; it resumes once the outer releases us.
|
|
7304
|
-
this.
|
|
7427
|
+
this.dn(e => setSlotState(e, this, true, o));
|
|
7305
7428
|
} else if (r === "natural") {
|
|
7306
7429
|
// Each child reveals based on its own readiness. A nested controller slot
|
|
7307
7430
|
// is released to run its own order locally — we bypass setSlotState for it
|
|
7308
7431
|
// so the parent backpointer survives for upward readiness notifications.
|
|
7309
|
-
this.
|
|
7432
|
+
this.dn(e => {
|
|
7310
7433
|
if (isRevealController(e)) {
|
|
7434
|
+
setSignal(e.en, false);
|
|
7311
7435
|
setSignal(e.Jt, false);
|
|
7312
|
-
|
|
7313
|
-
e.tn(false, false);
|
|
7436
|
+
e.nn(false, false);
|
|
7314
7437
|
} else {
|
|
7315
7438
|
setSlotState(e, this, !isSlotReady(e), false);
|
|
7316
7439
|
}
|
|
@@ -7321,11 +7444,11 @@ class RevealController {
|
|
|
7321
7444
|
// sequential's first slot being ready is minimally ready; natural having any
|
|
7322
7445
|
// ready child is minimally ready. This lets `together` guarantee a single
|
|
7323
7446
|
// cohesive reveal without waiting for every grandchild.
|
|
7324
|
-
const e = this.
|
|
7325
|
-
this.
|
|
7447
|
+
const e = this.dn(isSlotMinimallyReady);
|
|
7448
|
+
this.dn(t => setSlotState(t, this, !e, false));
|
|
7326
7449
|
} else {
|
|
7327
7450
|
let e = false;
|
|
7328
|
-
this.
|
|
7451
|
+
this.dn(t => {
|
|
7329
7452
|
if (e) return setSlotState(t, this, true, i);
|
|
7330
7453
|
if (isSlotReady(t)) return setSlotState(t, this, false, false);
|
|
7331
7454
|
e = true;
|
|
@@ -7336,63 +7459,63 @@ class RevealController {
|
|
|
7336
7459
|
// advancing past this slot, and we bypass setSlotState so the parent
|
|
7337
7460
|
// backpointer survives for upward readiness notifications.
|
|
7338
7461
|
if (isRevealController(t)) {
|
|
7462
|
+
setSignal(t.en, false);
|
|
7339
7463
|
setSignal(t.Jt, false);
|
|
7340
|
-
|
|
7341
|
-
t.tn(false, false);
|
|
7464
|
+
t.nn(false, false);
|
|
7342
7465
|
} else {
|
|
7343
7466
|
setSlotState(t, this, true, false);
|
|
7344
7467
|
}
|
|
7345
7468
|
});
|
|
7346
7469
|
}
|
|
7347
7470
|
} finally {
|
|
7348
|
-
this.
|
|
7349
|
-
this.
|
|
7350
|
-
this.
|
|
7471
|
+
this.cn = this.Bt();
|
|
7472
|
+
this.fn = this.zt();
|
|
7473
|
+
this.En = false;
|
|
7351
7474
|
}
|
|
7352
|
-
if (this.
|
|
7475
|
+
if (this.tn && (n !== this.cn || r !== this.fn)) this.tn.nn();
|
|
7353
7476
|
}
|
|
7354
7477
|
}
|
|
7355
7478
|
|
|
7356
7479
|
class CollectionQueue extends Queue {
|
|
7357
|
-
Tn;
|
|
7358
|
-
Bt=new Set;
|
|
7359
7480
|
On;
|
|
7360
|
-
Zt=
|
|
7361
|
-
|
|
7481
|
+
Zt=new Set;
|
|
7482
|
+
_n;
|
|
7483
|
+
Xt=true;
|
|
7484
|
+
Jt=signal(false, {
|
|
7362
7485
|
ownedWrite: true,
|
|
7363
|
-
|
|
7486
|
+
bt: true
|
|
7364
7487
|
});
|
|
7365
7488
|
me;
|
|
7366
|
-
|
|
7489
|
+
en=signal(false, {
|
|
7367
7490
|
ownedWrite: true,
|
|
7368
|
-
|
|
7491
|
+
bt: true
|
|
7369
7492
|
});
|
|
7370
|
-
|
|
7371
|
-
|
|
7372
|
-
|
|
7373
|
-
|
|
7493
|
+
rn;
|
|
7494
|
+
sn=false;
|
|
7495
|
+
Rn;
|
|
7496
|
+
pn=ON_INIT;
|
|
7374
7497
|
constructor(e) {
|
|
7375
7498
|
super();
|
|
7376
|
-
this.
|
|
7499
|
+
this.On = e;
|
|
7377
7500
|
}
|
|
7378
7501
|
run(e) {
|
|
7379
|
-
if (!e || read(this.
|
|
7502
|
+
if (!e || read(this.Jt) && (!_revealUsed || read(this.en))) return;
|
|
7380
7503
|
return super.run(e);
|
|
7381
7504
|
}
|
|
7382
7505
|
notify(e, t, n, r) {
|
|
7383
|
-
if (!(t & this.
|
|
7384
|
-
if (this.
|
|
7506
|
+
if (!(t & this.On)) return super.notify(e, t, n, r);
|
|
7507
|
+
if (this.sn && this.Rn) {
|
|
7385
7508
|
const e = untrack(() => {
|
|
7386
7509
|
try {
|
|
7387
|
-
return this.
|
|
7510
|
+
return this.Rn();
|
|
7388
7511
|
} catch {
|
|
7389
7512
|
return ON_INIT;
|
|
7390
7513
|
}
|
|
7391
7514
|
});
|
|
7392
|
-
if (e !== this.
|
|
7393
|
-
this.
|
|
7394
|
-
this.
|
|
7395
|
-
this.
|
|
7515
|
+
if (e !== this.pn) {
|
|
7516
|
+
this.pn = e;
|
|
7517
|
+
this.sn = false;
|
|
7518
|
+
this.Zt.clear();
|
|
7396
7519
|
}
|
|
7397
7520
|
}
|
|
7398
7521
|
// Routing is dimension-independent: each boundary consumes only its own
|
|
@@ -7405,47 +7528,47 @@ class CollectionQueue extends Queue {
|
|
|
7405
7528
|
// dimension, while a status already caught by an inner boundary arrives with
|
|
7406
7529
|
// its dimension consumed from the mask and is correctly not re-routed
|
|
7407
7530
|
// (the Loading > Errored > content composition escape, #2856).
|
|
7408
|
-
if (this.
|
|
7409
|
-
if (n & this.
|
|
7410
|
-
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;
|
|
7411
7534
|
const t = r?.source || e.me?.source;
|
|
7412
7535
|
if (t) {
|
|
7413
|
-
const e = this.
|
|
7414
|
-
this.
|
|
7415
|
-
if (e) setSignal(this.
|
|
7416
|
-
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) {
|
|
7417
7540
|
setSignal(this.me, unwrapStatusError(t.me));
|
|
7418
7541
|
}
|
|
7419
7542
|
}
|
|
7420
7543
|
}
|
|
7421
|
-
t &= ~this.
|
|
7544
|
+
t &= ~this.On;
|
|
7422
7545
|
return t ? super.notify(e, t, n, r) : true;
|
|
7423
7546
|
}
|
|
7424
|
-
|
|
7425
|
-
for (const e of this.
|
|
7547
|
+
je() {
|
|
7548
|
+
for (const e of this.Zt) {
|
|
7426
7549
|
// A source with a live affects() mark holds display state for the
|
|
7427
7550
|
// mark's lifetime (the visual channel): the marked node carries no
|
|
7428
7551
|
// status of its own, so the count is the liveness test. The release
|
|
7429
7552
|
// sweep (finalizePureQueue after mark release) re-runs this check.
|
|
7430
|
-
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);
|
|
7431
7554
|
}
|
|
7432
|
-
if (!this.
|
|
7433
|
-
if (this.
|
|
7434
|
-
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);
|
|
7435
7558
|
} else {
|
|
7436
|
-
this.
|
|
7559
|
+
this.Xt = false;
|
|
7437
7560
|
}
|
|
7438
|
-
if (!this.
|
|
7439
|
-
setSignal(this.
|
|
7440
|
-
if (this.
|
|
7561
|
+
if (!this.Xt) {
|
|
7562
|
+
setSignal(this.Jt, false);
|
|
7563
|
+
if (this.Rn) {
|
|
7441
7564
|
try {
|
|
7442
|
-
this.
|
|
7565
|
+
this.pn = untrack(() => this.Rn());
|
|
7443
7566
|
} catch {
|
|
7444
7567
|
/* value not yet committed — _prevOn stays stale, next notify will reset */}
|
|
7445
7568
|
}
|
|
7446
7569
|
}
|
|
7447
7570
|
}
|
|
7448
|
-
if (_revealUsed) this.nn
|
|
7571
|
+
if (_revealUsed) this.rn?.nn();
|
|
7449
7572
|
}
|
|
7450
7573
|
}
|
|
7451
7574
|
|
|
@@ -7455,10 +7578,10 @@ function createCollectionBoundary(e, t, n, r) {
|
|
|
7455
7578
|
const o = new CollectionQueue(e);
|
|
7456
7579
|
if (e === STATUS_ERROR) o.me = signal(undefined, {
|
|
7457
7580
|
ownedWrite: true,
|
|
7458
|
-
|
|
7581
|
+
bt: true
|
|
7459
7582
|
});
|
|
7460
|
-
if (r) o.
|
|
7461
|
-
const s = o.
|
|
7583
|
+
if (r) o.Rn = r;
|
|
7584
|
+
const s = o._n = createBoundChildren(i, t, o, e);
|
|
7462
7585
|
// Prime source tracking so reveal registration sees pending sources.
|
|
7463
7586
|
untrack(() => {
|
|
7464
7587
|
let t = false;
|
|
@@ -7467,23 +7590,23 @@ function createCollectionBoundary(e, t, n, r) {
|
|
|
7467
7590
|
} catch (e) {
|
|
7468
7591
|
if (e instanceof NotReadyError) t = true; else throw e;
|
|
7469
7592
|
}
|
|
7470
|
-
o.
|
|
7593
|
+
o.Xt = t || !!(s.He & e) || s.me instanceof NotReadyError;
|
|
7471
7594
|
});
|
|
7472
7595
|
const u = _revealUsed && e === STATUS_PENDING ? getContext(RevealControllerContext) : null;
|
|
7473
7596
|
if (u) {
|
|
7474
|
-
o.
|
|
7475
|
-
u.
|
|
7476
|
-
cleanup(() => u.
|
|
7597
|
+
o.rn = u;
|
|
7598
|
+
u.Sn(o);
|
|
7599
|
+
cleanup(() => u.Tn(o));
|
|
7477
7600
|
}
|
|
7478
7601
|
return accessor(computed(() => {
|
|
7479
|
-
if (!read(o.
|
|
7602
|
+
if (!read(o.Jt)) {
|
|
7480
7603
|
const e = read(s);
|
|
7481
|
-
if (!untrack(() => read(o.
|
|
7604
|
+
if (!untrack(() => read(o.Jt))) return o.sn = true, e;
|
|
7482
7605
|
}
|
|
7483
7606
|
// Collapsed reveal slots suppress their own output entirely; the
|
|
7484
7607
|
// renderer treats the hole as empty, so the cast never leaks to users
|
|
7485
7608
|
// outside a `createRevealOrder` scope.
|
|
7486
|
-
if (_revealUsed && read(o.
|
|
7609
|
+
if (_revealUsed && read(o.en)) return undefined;
|
|
7487
7610
|
return n(o);
|
|
7488
7611
|
},
|
|
7489
7612
|
// Boundary structure, not a user source: its value is fallback-or-content and
|
|
@@ -7491,7 +7614,7 @@ function createCollectionBoundary(e, t, n, r) {
|
|
|
7491
7614
|
// by snapshot capture. The tree no longer carries foreign status flags, so
|
|
7492
7615
|
// capture can't rely on PENDING to skip this node the way it used to.
|
|
7493
7616
|
{
|
|
7494
|
-
|
|
7617
|
+
bt: true
|
|
7495
7618
|
}));
|
|
7496
7619
|
}
|
|
7497
7620
|
|
|
@@ -7545,7 +7668,7 @@ function createCollectionBoundary(e, t, n, r) {
|
|
|
7545
7668
|
* ```
|
|
7546
7669
|
*/ function createErrorBoundary(e, t) {
|
|
7547
7670
|
return createCollectionBoundary(STATUS_ERROR, e, e => t(accessor(e.me), () => {
|
|
7548
|
-
for (const t of e.
|
|
7671
|
+
for (const t of e.Zt) recompute(t);
|
|
7549
7672
|
schedule();
|
|
7550
7673
|
}));
|
|
7551
7674
|
}
|
|
@@ -7602,12 +7725,12 @@ function createCollectionBoundary(e, t, n, r) {
|
|
|
7602
7725
|
computed(() => {
|
|
7603
7726
|
i();
|
|
7604
7727
|
o();
|
|
7605
|
-
s.
|
|
7728
|
+
s.nn();
|
|
7606
7729
|
});
|
|
7607
7730
|
if (r) {
|
|
7608
|
-
s.
|
|
7609
|
-
r.
|
|
7610
|
-
cleanup(() => r.
|
|
7731
|
+
s.tn = r;
|
|
7732
|
+
r.Sn(s);
|
|
7733
|
+
cleanup(() => r.Tn(s));
|
|
7611
7734
|
}
|
|
7612
7735
|
return t;
|
|
7613
7736
|
});
|