@solidjs/signals 2.0.0-rc.14 → 2.0.0-rc.15
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-shared.js +248 -189
- package/dist/dev.attribution.js +124 -41
- package/dist/dev.js +553 -322
- package/dist/observe/affects.js +34 -31
- package/dist/observe/boundaries.js +166 -132
- package/dist/observe/core/async.js +90 -83
- package/dist/observe/core/attribution-queries.js +1 -1
- package/dist/observe/core/attribution.js +281 -197
- package/dist/observe/core/constants.js +7 -2
- package/dist/observe/core/context.js +3 -3
- package/dist/observe/core/core.js +277 -245
- package/dist/observe/core/dev.js +3 -3
- package/dist/observe/core/effect.js +21 -21
- package/dist/observe/core/external.js +2 -2
- package/dist/observe/core/graph.js +25 -25
- package/dist/observe/core/heap.js +9 -9
- package/dist/observe/core/lanes.js +206 -160
- package/dist/observe/core/owner.js +27 -27
- package/dist/observe/core/scheduler.js +92 -86
- package/dist/observe/core/verdict.js +66 -54
- package/dist/observe/map.js +35 -35
- package/dist/observe/reveal.js +24 -24
- package/dist/observe/signals.js +38 -28
- package/dist/observe/store/affects.js +75 -68
- package/dist/observe/store/hooks.js +13 -0
- package/dist/observe/store/index.js +0 -2
- package/dist/observe/store/optimistic.js +67 -34
- package/dist/observe/store/projection.js +37 -31
- package/dist/observe/store/reconcile.js +32 -30
- package/dist/observe/store/store.js +128 -85
- package/dist/prod/affects.js +34 -31
- package/dist/prod/boundaries.js +143 -109
- package/dist/prod/core/async.js +64 -67
- package/dist/prod/core/constants.js +7 -2
- package/dist/prod/core/context.js +3 -3
- package/dist/prod/core/core.js +302 -270
- package/dist/prod/core/effect.js +38 -38
- package/dist/prod/core/external.js +4 -4
- package/dist/prod/core/graph.js +27 -27
- package/dist/prod/core/heap.js +30 -30
- package/dist/prod/core/lanes.js +257 -211
- package/dist/prod/core/owner.js +39 -39
- package/dist/prod/core/scheduler.js +125 -119
- package/dist/prod/core/verdict.js +70 -58
- package/dist/prod/map.js +73 -73
- package/dist/prod/reveal.js +38 -38
- package/dist/prod/signals.js +30 -20
- package/dist/prod/store/affects.js +75 -68
- package/dist/prod/store/hooks.js +13 -0
- package/dist/prod/store/index.js +0 -2
- package/dist/prod/store/optimistic.js +114 -81
- package/dist/prod/store/projection.js +30 -24
- package/dist/prod/store/reconcile.js +32 -30
- package/dist/prod/store/store.js +136 -93
- package/dist/types/boundaries.d.ts +4 -0
- package/dist/types/core/attribution.d.ts +6 -2
- package/dist/types/core/constants.d.ts +5 -0
- package/dist/types/core/core.d.ts +33 -3
- package/dist/types/core/lanes.d.ts +10 -0
- package/dist/types/core/scheduler.d.ts +12 -6
- package/dist/types/core/types.d.ts +0 -6
- package/dist/types/store/affects.d.ts +11 -0
- package/dist/types/store/hooks.d.ts +48 -0
- package/dist/types/store/index.d.ts +0 -1
- package/dist/types/store/store.d.ts +3 -38
- package/package.json +1 -1
package/dist/prod/store/store.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { CONFIG_MANUAL_WRITE, CONFIG_OVERRIDE, CONFIG_HELD, $REFRESH, NOT_PENDING, STATUS_PENDING, STATUS_ERROR, EFFECT_RENDER, REACTIVE_RECOMPUTING_DEPS, REACTIVE_STAGED_READ, CONFIG_VERDICT, CONFIG_CHILDREN_FORBIDDEN, CONFIG_PROMOTED, REACTIVE_DIRTY, REACTIVE_CHECK } from "../core/constants.js";
|
|
2
2
|
|
|
3
|
-
import { setSignal, isEqual, read, verdict, context, notePromotedWrite, untrack, slotSignal, stagedScreen, stagedRead } from "../core/core.js";
|
|
3
|
+
import { setSignal, isEqual, read, verdict, snapshotCaptureActive, captureWriteSnapshot, context, notePromotedWrite, untrack, slotSignal, stagedScreen, stagedRead } from "../core/core.js";
|
|
4
4
|
|
|
5
5
|
import { setSlotUnobserved } from "../core/graph.js";
|
|
6
6
|
|
|
@@ -12,6 +12,8 @@ import { txOf, flushTransaction, holdNode, joinFuture, insertSubs, schedule, pas
|
|
|
12
12
|
|
|
13
13
|
import { lookupTarget, setLookup, $OWNER, isOwned, markDescendants, devAssertNeverUserMutation } from "./target.js";
|
|
14
14
|
|
|
15
|
+
import { optHooks, affectsHooks } from "./hooks.js";
|
|
16
|
+
|
|
15
17
|
import { $TARGET, rawValuesUsed, isRawValue, isWrappable, markRawIngest, writeOverride, markRawOne, $RECORD, $PROXY, $TRACK } from "./types.js";
|
|
16
18
|
|
|
17
19
|
export { markRaw } from "./types.js";
|
|
@@ -45,18 +47,7 @@ export { markRaw } from "./types.js";
|
|
|
45
47
|
* Perf contracts (plan sec. 31.4): lazy nodes; one literal per node; O(written) per
|
|
46
48
|
* setter (`wk`); overlay drafts for large plain records; no new named
|
|
47
49
|
* fields on array targets; zero allocation for adopted-but-unread objects.
|
|
48
|
-
*/
|
|
49
|
-
|
|
50
|
-
function installOptHooks(e) {
|
|
51
|
-
optHooks = e;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
let affectsHooks = null;
|
|
55
|
-
|
|
56
|
-
function installAffectsHooks(e) {
|
|
57
|
-
affectsHooks = e;
|
|
58
|
-
}
|
|
59
|
-
|
|
50
|
+
*/
|
|
60
51
|
/** Key of the deep-witness slot node (never a user key). */ const $DEEP = Symbol(0);
|
|
61
52
|
|
|
62
53
|
// ---------------------------------------------------------------------------
|
|
@@ -175,7 +166,7 @@ function wrap(e, n = null, t = null, r = n?.fam ?? null) {
|
|
|
175
166
|
// adoption swap raw identity without changing the logical value — only
|
|
176
167
|
// changed leaves notify, R9).
|
|
177
168
|
const slotNodeEquals = function(e, n) {
|
|
178
|
-
return isEqual(e, n) || sameLogicalSlot(this.
|
|
169
|
+
return isEqual(e, n) || sameLogicalSlot(this.lt, e, n);
|
|
179
170
|
};
|
|
180
171
|
|
|
181
172
|
/** The deep witness: the store decides when it notifies. */ const never = false;
|
|
@@ -213,7 +204,7 @@ function sameKey(e, n) {
|
|
|
213
204
|
/** The container node's comparator: a staging is a backing (identity — a
|
|
214
205
|
* pending backing is never "equal" to the committed one); a lane value is
|
|
215
206
|
* an arrangement (`LaneView`), judged by the optimistic machinery. */ const containerEquals = function(e, n) {
|
|
216
|
-
return e === n || optHooks !== null && optHooks.arrangement(this.
|
|
207
|
+
return e === n || optHooks !== null && optHooks.arrangement(this.lt, e, n);
|
|
217
208
|
};
|
|
218
209
|
|
|
219
210
|
function sameLogicalSlot(e, n, t) {
|
|
@@ -226,8 +217,8 @@ function sameLogicalSlot(e, n, t) {
|
|
|
226
217
|
* released at the commit that resolves it (`drainFolds`). */ const deferredReleases = new Set;
|
|
227
218
|
|
|
228
219
|
function releaseSlot(e) {
|
|
229
|
-
const n = e.
|
|
230
|
-
const t = e.
|
|
220
|
+
const n = e.lt;
|
|
221
|
+
const t = e.ot;
|
|
231
222
|
if (t === $TRACK) {
|
|
232
223
|
if (n.k === e) n.k = null;
|
|
233
224
|
} else if (t === $DEEP) {
|
|
@@ -243,7 +234,7 @@ function releaseSlot(e) {
|
|
|
243
234
|
/** A node was born on `target`: a family target enters the live index. */ function noteNode(e, n, t) {
|
|
244
235
|
if (e.fam !== null) e.fam.live.add(e);
|
|
245
236
|
markDescendants(e);
|
|
246
|
-
if (affectsHooks !== null) affectsHooks.
|
|
237
|
+
if (affectsHooks !== null) affectsHooks.fo(e, n, t);
|
|
247
238
|
}
|
|
248
239
|
|
|
249
240
|
// Shared slot-node release handler: registered once; the core sweep
|
|
@@ -253,7 +244,7 @@ function releaseSlot(e) {
|
|
|
253
244
|
setSlotUnobserved(e => {
|
|
254
245
|
// A staged write — or a lane's value (a guess, S4) — is state only the
|
|
255
246
|
// node holds: defer the release to the commit that resolves it.
|
|
256
|
-
if (e.
|
|
247
|
+
if (e.Oe !== NOT_PENDING || e.i & CONFIG_OVERRIDE) deferredReleases.add(e); else releaseSlot(e);
|
|
257
248
|
});
|
|
258
249
|
|
|
259
250
|
/** A node born while its container has a staging is born from the two
|
|
@@ -261,19 +252,19 @@ setSlotUnobserved(e => {
|
|
|
261
252
|
* pending one — and held by the container's transaction when the container
|
|
262
253
|
* is held (#3706: the unit of the hold is the key — a key the batch left
|
|
263
254
|
* unchanged stages nothing and holds no one). */ function bornStaged(e, n, t, r) {
|
|
264
|
-
if (n.
|
|
255
|
+
if (n.ye && n.ye(n.Ae, t)) return;
|
|
265
256
|
queuePendingNode(n);
|
|
266
|
-
n.
|
|
257
|
+
n.Oe = t;
|
|
267
258
|
const i = e.k;
|
|
268
259
|
if (i === null) return;
|
|
269
260
|
// a node-less staging holds nothing (`stageOn`)
|
|
270
261
|
// Held by the container's transaction only for a key the HELD staging
|
|
271
262
|
// changed — a mainline layer's change above it stages mainline. (A
|
|
272
263
|
// container carrying a guess is a lane's: the flush's park decides.)
|
|
273
|
-
if ((i.
|
|
264
|
+
if ((i.i & (CONFIG_HELD | CONFIG_OVERRIDE)) === CONFIG_HELD && heldKeyChanged(e, r)) holdNode(n, txOf(i));
|
|
274
265
|
// A28 (4): a batch written inside a creation-time pass is promoted — its
|
|
275
266
|
// late-materialized leaf with it.
|
|
276
|
-
if (i.
|
|
267
|
+
if (i.i & CONFIG_PROMOTED) notePromotedWrite(n);
|
|
277
268
|
}
|
|
278
269
|
|
|
279
270
|
function getNode(e, n,
|
|
@@ -323,8 +314,8 @@ function getHasNode(e, n) {
|
|
|
323
314
|
// pending backing staged — so whoever asked for it reads the frame it
|
|
324
315
|
// would have read had the node been there from the write.
|
|
325
316
|
if (e.pb !== null && !directCommit) {
|
|
326
|
-
n.
|
|
327
|
-
n.
|
|
317
|
+
n.Ae = preBatch(e);
|
|
318
|
+
n.Oe = e.pb;
|
|
328
319
|
queuePendingNode(n);
|
|
329
320
|
}
|
|
330
321
|
}
|
|
@@ -341,10 +332,10 @@ function getHasNode(e, n) {
|
|
|
341
332
|
* re-created, queued, swept and dropped ~7000 container nodes). If the
|
|
342
333
|
* flush parks, the seam materializes and holds the node then
|
|
343
334
|
* (`_storePark`) — the one case the staging home exists for. */ function stageOn(e, n) {
|
|
344
|
-
if (e.k === null && passLane === null && (context === null || globalQueue.
|
|
335
|
+
if (e.k === null && passLane === null && (context === null || globalQueue.X) && !deriveHolds(e)) return;
|
|
345
336
|
const t = getContainerNode(e);
|
|
346
|
-
if (t.
|
|
347
|
-
t.
|
|
337
|
+
if (t.Oe === NOT_PENDING) queuePendingNode(t);
|
|
338
|
+
t.Oe = n;
|
|
348
339
|
// A28 (4): a write issued inside a pass outside a flush (a creation-time
|
|
349
340
|
// derive) is promoted at the pass's end — the batch with it.
|
|
350
341
|
if (context !== null) notePromotedWrite(t);
|
|
@@ -354,7 +345,7 @@ function getHasNode(e, n) {
|
|
|
354
345
|
/** The projection's derive is held by a transaction and this is its own
|
|
355
346
|
* write (not a user setter's): the staging is the derive's (`holdWithDerive`). */ function deriveHolds(e) {
|
|
356
347
|
const n = e.fam?.node;
|
|
357
|
-
return n != null && !userWrite && (n.
|
|
348
|
+
return n != null && !userWrite && (n.i & CONFIG_HELD) !== 0;
|
|
358
349
|
}
|
|
359
350
|
|
|
360
351
|
GlobalQueue.Tn = e => {
|
|
@@ -385,8 +376,9 @@ function bumpDeep(e) {
|
|
|
385
376
|
// on the guess (`laneWrite` → `supersede`, judged by `containerEquals`);
|
|
386
377
|
// otherwise the structural readers are walked (the staging is already on
|
|
387
378
|
// the node; the comparator is the store's, done).
|
|
388
|
-
if (e.
|
|
389
|
-
if (e.
|
|
379
|
+
if (e.i & CONFIG_OVERRIDE) setSignal(e, n); else {
|
|
380
|
+
if (e.i & CONFIG_HELD) joinFuture(txOf(e));
|
|
381
|
+
if (snapshotCaptureActive) captureWriteSnapshot(e, e.Ae);
|
|
390
382
|
insertSubs(e);
|
|
391
383
|
schedule();
|
|
392
384
|
}
|
|
@@ -498,7 +490,7 @@ const plainProto = e => {
|
|
|
498
490
|
e.pb = t;
|
|
499
491
|
e.ovl = false;
|
|
500
492
|
// The staging IS the pending backing: re-point the container node.
|
|
501
|
-
if (e.k !== null && e.k.
|
|
493
|
+
if (e.k !== null && e.k.Oe === n) e.k.Oe = t;
|
|
502
494
|
return t;
|
|
503
495
|
}
|
|
504
496
|
|
|
@@ -519,7 +511,7 @@ const plainProto = e => {
|
|
|
519
511
|
// mainline setter mid-hold publishes mainline; the held keys stay held).
|
|
520
512
|
n = e.pb = cloneRaw(n, e);
|
|
521
513
|
const t = e.k;
|
|
522
|
-
if (t !== null && !(t.
|
|
514
|
+
if (t !== null && !(t.i & CONFIG_HELD)) t.Oe = n;
|
|
523
515
|
} else if (n === null) {
|
|
524
516
|
const t = e.v;
|
|
525
517
|
if (!directCommit) queueFold(e);
|
|
@@ -598,7 +590,7 @@ const plainProto = e => {
|
|
|
598
590
|
} else r = e.v;
|
|
599
591
|
if (directCommit) {
|
|
600
592
|
e.pb = null;
|
|
601
|
-
if (e.k !== null) e.k.
|
|
593
|
+
if (e.k !== null) e.k.Ae = n;
|
|
602
594
|
} else {
|
|
603
595
|
// Eager (INTERNALS §3): the backing swaps now — handlers read the
|
|
604
596
|
// adopted object before the flush — while the container node, when
|
|
@@ -694,7 +686,7 @@ let foldIndex = null;
|
|
|
694
686
|
if (r.pb === null) continue;
|
|
695
687
|
// folded already (a direct commit)
|
|
696
688
|
const i = r.k;
|
|
697
|
-
if (i !== null && i.
|
|
689
|
+
if (i !== null && i.Oe !== NOT_PENDING) {
|
|
698
690
|
// held: commits with its hold
|
|
699
691
|
foldList.push(r);
|
|
700
692
|
foldOlds.push(n[t]);
|
|
@@ -705,7 +697,7 @@ let foldIndex = null;
|
|
|
705
697
|
}
|
|
706
698
|
if (deferredReleases.size !== 0) {
|
|
707
699
|
for (const e of deferredReleases) {
|
|
708
|
-
if (e.
|
|
700
|
+
if (e.Oe === NOT_PENDING && !(e.i & CONFIG_OVERRIDE) && e.t === null) {
|
|
709
701
|
deferredReleases.delete(e);
|
|
710
702
|
releaseSlot(e);
|
|
711
703
|
}
|
|
@@ -716,29 +708,34 @@ let foldIndex = null;
|
|
|
716
708
|
/** Core asks: is a slot node's truth in flight? Its family's derive is —
|
|
717
709
|
* lanes (A17, #2864: a guess mid-refetch stands in for the flight) and
|
|
718
710
|
* marks (an ambient `affects()` over a declared reload lives to the
|
|
719
|
-
* landing) read it. */ GlobalQueue.
|
|
720
|
-
const n = e.
|
|
721
|
-
return n != null && n.node !== null && (n.node.
|
|
711
|
+
* landing) read it. */ GlobalQueue.C = e => {
|
|
712
|
+
const n = e.lt?.fam;
|
|
713
|
+
return n != null && n.node !== null && (n.node.S & STATUS_PENDING) !== 0;
|
|
722
714
|
};
|
|
723
715
|
|
|
724
716
|
/** Core asks (lanes.ts `covered`): the value a slot node's guess covered.
|
|
725
717
|
* A chained link's committed value is the inner store's at the last
|
|
726
718
|
* read-through — refreshed here, since a guess served the reads since
|
|
727
|
-
* (#3672: the revert compares against the base's live value). */ GlobalQueue.
|
|
728
|
-
const n = e.
|
|
719
|
+
* (#3672: the revert compares against the base's live value). */ GlobalQueue.Nn = e => {
|
|
720
|
+
const n = e.lt;
|
|
729
721
|
if (n.ch) {
|
|
730
|
-
const t = e.
|
|
722
|
+
const t = e.ot;
|
|
731
723
|
const r = n.v;
|
|
732
|
-
if (n.h !== null && n.h[t] === e) e.
|
|
724
|
+
if (n.h !== null && n.h[t] === e) e.Ae = untrack(() => t in r); else if (n.n !== null && n.n[t] === e) e.Ae = untrack(() => unwrapValue(r[t]));
|
|
733
725
|
}
|
|
734
|
-
return e.
|
|
726
|
+
return e.Ae;
|
|
735
727
|
};
|
|
736
728
|
|
|
737
|
-
GlobalQueue.
|
|
729
|
+
GlobalQueue.Sn = () => {
|
|
738
730
|
drainFolds();
|
|
739
731
|
optHooks?.sweep();
|
|
740
732
|
};
|
|
741
733
|
|
|
734
|
+
/** The store half of `affects()` (store/affects.ts) makes its marks' nodes
|
|
735
|
+
* and walks records through these: it never imports the engine. */ GlobalQueue.no = getNode;
|
|
736
|
+
|
|
737
|
+
GlobalQueue.so = isWrappable;
|
|
738
|
+
|
|
742
739
|
/** A projection's creation run commits directly (a memo's first value is
|
|
743
740
|
* its `_value`, not a staging): the draft still writes a clone of the seed,
|
|
744
741
|
* nothing is staged on the nodes, and the setter's exit folds the touched
|
|
@@ -765,7 +762,7 @@ function runDirect(e) {
|
|
|
765
762
|
// the adopted object (shared ownership — never cloned).
|
|
766
763
|
e.pb = null;
|
|
767
764
|
e.wk = null;
|
|
768
|
-
} else if (e.ovl && (e.v !== n || !overlayRebuilds(e, r))) {
|
|
765
|
+
} else if (e.ovl && (e.v !== n || !overlayRebuilds(e, r) && t?.m?.Le !== n)) {
|
|
769
766
|
// Overlay flatten (#3044): the backing keeps its identity, so the
|
|
770
767
|
// `t.v === old` gate below skips path copying (the parent slot
|
|
771
768
|
// already points here) and the adopted-notify (setter
|
|
@@ -807,7 +804,7 @@ function runDirect(e) {
|
|
|
807
804
|
// subscribes to was a transient staging home (INTERNALS §5: an
|
|
808
805
|
// observer-less write holds a transient record until the fold,
|
|
809
806
|
// discarded with it) — gone with the batch.
|
|
810
|
-
if (t.t === null) e.k = null; else if (t.
|
|
807
|
+
if (t.t === null) e.k = null; else if (t.Ae instanceof LaneView) t.Ae.base = e.v; else t.Ae = e.v;
|
|
811
808
|
}
|
|
812
809
|
if (e.v !== n && e.u) {
|
|
813
810
|
const t = parentSlotKey(e, n);
|
|
@@ -834,9 +831,9 @@ function runDirect(e) {
|
|
|
834
831
|
|
|
835
832
|
function heldDerivation(e, n, t) {
|
|
836
833
|
if (e.fam === null || !userWrite) return false;
|
|
837
|
-
if (n !== undefined) return (n.
|
|
834
|
+
if (n !== undefined) return (n.i & (CONFIG_HELD | CONFIG_MANUAL_WRITE)) === CONFIG_HELD && txOf(n) !== flushTransaction;
|
|
838
835
|
const r = e.k;
|
|
839
|
-
return r !== null && (r.
|
|
836
|
+
return r !== null && (r.i & CONFIG_HELD) !== 0 && txOf(r) !== flushTransaction && heldKeyChanged(e, t);
|
|
840
837
|
}
|
|
841
838
|
|
|
842
839
|
/** Setter exit: one node write per changed observed key (the leaves stage
|
|
@@ -881,15 +878,18 @@ function heldDerivation(e, n, t) {
|
|
|
881
878
|
if (i.acc === true || hasOwn.call(n, o) && lookupGetter.call(n, o) !== undefined) {
|
|
882
879
|
// Accessor keys: the node is linked for shape-change notification,
|
|
883
880
|
// its value is never served (the getter runs with the proxy
|
|
884
|
-
// receiver on read) — FORCE wakes the readers.
|
|
881
|
+
// receiver on read) — FORCE wakes the readers. A data descriptor
|
|
882
|
+
// falls through so the cleared-acc hot read serves it (#3949);
|
|
883
|
+
// an own getter's descriptor has no `value`, so the compare below
|
|
884
|
+
// would otherwise keep the getter's result (or FORCE) for `undefined`.
|
|
885
885
|
i.acc = isOwnAccessor(n, o);
|
|
886
886
|
const e = Object.getOwnPropertyDescriptor(t, o);
|
|
887
887
|
const r = Object.getOwnPropertyDescriptor(n, o);
|
|
888
|
-
if (
|
|
888
|
+
if (!r || r.get || r.set) {
|
|
889
889
|
if (e?.get !== r?.get || e?.set !== r?.set || e?.value !== r?.value) setSignal(i, () => FORCE);
|
|
890
890
|
continue;
|
|
891
891
|
}
|
|
892
|
-
if (!isEqual(e?.value, r
|
|
892
|
+
if (e?.get || e?.set || !isEqual(e?.value, r.value)) setSignal(i, () => r.value);
|
|
893
893
|
continue;
|
|
894
894
|
}
|
|
895
895
|
const l = e.del !== null && e.del.has(o) ? undefined : n[o];
|
|
@@ -898,9 +898,9 @@ function heldDerivation(e, n, t) {
|
|
|
898
898
|
// The derive's write is a derivation; a user setter's is a proposal
|
|
899
899
|
// (A34 (3)'s discriminator).
|
|
900
900
|
if (!userWrite) {
|
|
901
|
-
i.
|
|
901
|
+
i.i &= ~CONFIG_MANUAL_WRITE;
|
|
902
902
|
holdWithDerive(e, i);
|
|
903
|
-
} else i.
|
|
903
|
+
} else i.i |= CONFIG_MANUAL_WRITE;
|
|
904
904
|
}
|
|
905
905
|
}
|
|
906
906
|
}
|
|
@@ -931,7 +931,7 @@ function heldDerivation(e, n, t) {
|
|
|
931
931
|
// container carrying an arrangement guess is told whether or not anyone
|
|
932
932
|
// subscribes: the write is a landing on the guess (`notifyContainer`).
|
|
933
933
|
const u = e.k;
|
|
934
|
-
if (u !== null && (u.t !== null || u.
|
|
934
|
+
if (u !== null && (u.t !== null || u.i & CONFIG_OVERRIDE)) {
|
|
935
935
|
let r;
|
|
936
936
|
if (e.ovl) {
|
|
937
937
|
r = e.del !== null && e.del.size !== 0;
|
|
@@ -980,13 +980,14 @@ function membershipChanged(e, n) {
|
|
|
980
980
|
e.acc = isOwnAccessor(r, n);
|
|
981
981
|
const i = Object.getOwnPropertyDescriptor(t, n);
|
|
982
982
|
const o = Object.getOwnPropertyDescriptor(r, n);
|
|
983
|
-
|
|
983
|
+
// Data descriptors fall through, as in notifyWrites (#3949).
|
|
984
|
+
if (!o || o.get || o.set) {
|
|
984
985
|
if (i?.get !== o?.get || i?.set !== o?.set || i?.value !== o?.value) setSignal(e, () => FORCE);
|
|
985
986
|
return;
|
|
986
987
|
}
|
|
987
988
|
const l = i?.value;
|
|
988
989
|
const u = o?.value;
|
|
989
|
-
if (!isEqual(l, u) && !targetsEqual(l, u)) setSignal(e, typeof u === "function" ? () => u : u);
|
|
990
|
+
if (i?.get || i?.set || !isEqual(l, u) && !targetsEqual(l, u)) setSignal(e, typeof u === "function" ? () => u : u);
|
|
990
991
|
} else {
|
|
991
992
|
const i = t[n];
|
|
992
993
|
const o = r[n];
|
|
@@ -1032,7 +1033,7 @@ function hasAccessorFlag(e) {
|
|
|
1032
1033
|
for (const i of Reflect.ownKeys(r)) if (e || i in n !== i in t) setSignal(r[i], i in t);
|
|
1033
1034
|
}
|
|
1034
1035
|
const i = e.k;
|
|
1035
|
-
if (i !== null && (i.t !== null || i.
|
|
1036
|
+
if (i !== null && (i.t !== null || i.i & CONFIG_OVERRIDE)) {
|
|
1036
1037
|
const e = Array.isArray(t) && Array.isArray(n) ? arrayStructureChanged(n, t) : membershipChanged(n, t);
|
|
1037
1038
|
if (e) notifyContainer(i, t);
|
|
1038
1039
|
}
|
|
@@ -1089,7 +1090,7 @@ function inDraft(e) {
|
|
|
1089
1090
|
* "adoption is eager by contract" — and the node keeps the frame committed
|
|
1090
1091
|
* readers under a hold still see), `t.v` otherwise. */ function committed(e) {
|
|
1091
1092
|
const n = e.k;
|
|
1092
|
-
if (n !== null) return n.
|
|
1093
|
+
if (n !== null) return n.Oe !== NOT_PENDING ? asBacking(n.Ae) : e.v;
|
|
1093
1094
|
// A node-less staging (`stageOn`): the fold queue remembers the frame.
|
|
1094
1095
|
return e.pb !== null ? preBatch(e) : e.v;
|
|
1095
1096
|
}
|
|
@@ -1101,8 +1102,8 @@ function inDraft(e) {
|
|
|
1101
1102
|
* committed frame. */ function stagingReader() {
|
|
1102
1103
|
let e = context;
|
|
1103
1104
|
if (e === null) return null;
|
|
1104
|
-
if (e
|
|
1105
|
-
return e === null || e.
|
|
1105
|
+
if (e.$e) e = e.et ?? null;
|
|
1106
|
+
return e === null || e.i & CONFIG_CHILDREN_FORBIDDEN ? null : e;
|
|
1106
1107
|
}
|
|
1107
1108
|
|
|
1108
1109
|
/** The backing a read serves (RUL-1, signal parity): the draft and the write
|
|
@@ -1140,10 +1141,10 @@ function inDraft(e) {
|
|
|
1140
1141
|
if (writeOverride && !userWrite) {
|
|
1141
1142
|
const t = n !== undefined ? e.n?.[n] : undefined;
|
|
1142
1143
|
if (t !== undefined) {
|
|
1143
|
-
if ((t.
|
|
1144
|
+
if ((t.i & (CONFIG_HELD | CONFIG_OVERRIDE)) === CONFIG_HELD) joinPassTx(txOf(t));
|
|
1144
1145
|
} else {
|
|
1145
1146
|
const t = e.k;
|
|
1146
|
-
if (t !== null && (t.
|
|
1147
|
+
if (t !== null && (t.i & (CONFIG_HELD | CONFIG_OVERRIDE)) === CONFIG_HELD && (n === undefined || heldKeyChanged(e, n))) joinPassTx(txOf(t));
|
|
1147
1148
|
}
|
|
1148
1149
|
}
|
|
1149
1150
|
return r;
|
|
@@ -1155,9 +1156,9 @@ function inDraft(e) {
|
|
|
1155
1156
|
// it).
|
|
1156
1157
|
if (n !== undefined) {
|
|
1157
1158
|
const t = e.n?.[n];
|
|
1158
|
-
if (t !== undefined && t.
|
|
1159
|
+
if (t !== undefined && t.i & CONFIG_OVERRIDE) return committed(e);
|
|
1159
1160
|
}
|
|
1160
|
-
const o = i !== null && (i.
|
|
1161
|
+
const o = i !== null && (i.i & CONFIG_HELD) !== 0;
|
|
1161
1162
|
// A held container: the hold's unit is the key (#3706). A key the HELD
|
|
1162
1163
|
// staging left unchanged reads the ambient view — a mainline layer's
|
|
1163
1164
|
// write above the hold publishes mainline (#3688, #3612); a key it
|
|
@@ -1175,7 +1176,7 @@ function inDraft(e) {
|
|
|
1175
1176
|
// probe) judges the container like any node — for a key the batch
|
|
1176
1177
|
// changed; an unchanged key is committed and final (A22: pending is per
|
|
1177
1178
|
// key). A held container's committed frame is the node's.
|
|
1178
|
-
if (verdict === null || !o && n !== undefined && !keyChanged(e, n, t)) return o ? asBacking(i.
|
|
1179
|
+
if (verdict === null || !o && n !== undefined && !keyChanged(e, n, t)) return o ? asBacking(i.Ae) : e.v;
|
|
1179
1180
|
return i === null ? committed(e) : asBacking(read(i));
|
|
1180
1181
|
}
|
|
1181
1182
|
// A pass reading a key the batch left unchanged: the same value in both
|
|
@@ -1192,13 +1193,13 @@ function inDraft(e) {
|
|
|
1192
1193
|
// frames, a changed one is what the mark already stands for. The
|
|
1193
1194
|
// per-key question is asked once per pass, not once per key (a
|
|
1194
1195
|
// `mapArray` over 1k shifted rows asked it 1k times).
|
|
1195
|
-
if (l.R & REACTIVE_STAGED_READ && !(l.
|
|
1196
|
+
if (l.R & REACTIVE_STAGED_READ && !(l.i & (CONFIG_VERDICT | CONFIG_CHILDREN_FORBIDDEN))) return r;
|
|
1196
1197
|
if (n !== undefined && !keyChanged(e, n, t)) return committed(e);
|
|
1197
1198
|
// A node-less staging (`stageOn`): what `read()` of its node would do
|
|
1198
1199
|
// for this pass — a verdict reader sees the screen, any other derives
|
|
1199
1200
|
// from the staging and is marked as having read it.
|
|
1200
1201
|
if (i === null) {
|
|
1201
|
-
if (l.
|
|
1202
|
+
if (l.i & CONFIG_VERDICT && stagedScreen(l)) return committed(e);
|
|
1202
1203
|
stagedRead(l);
|
|
1203
1204
|
return r;
|
|
1204
1205
|
}
|
|
@@ -1208,11 +1209,52 @@ function inDraft(e) {
|
|
|
1208
1209
|
|
|
1209
1210
|
/** Did the HELD staging (the container node's, not a mainline layer above
|
|
1210
1211
|
* it) change `key`? */ function heldKeyChanged(e, n, t = true) {
|
|
1211
|
-
return changedBetween(e, e.k.
|
|
1212
|
+
return changedBetween(e, e.k.Ae, e.k.Oe, n, t) && !adoptChild(e, n);
|
|
1213
|
+
}
|
|
1214
|
+
|
|
1215
|
+
/** The values of a held frame, built once per frame: neither the committed
|
|
1216
|
+
* frame nor the held staging changes while the hold stands (a draft writes a
|
|
1217
|
+
* clone), so the set stays true for every first read of the hold. */ const frameRaws = new WeakMap;
|
|
1218
|
+
|
|
1219
|
+
function rawsOf(e) {
|
|
1220
|
+
let n = frameRaws.get(e);
|
|
1221
|
+
if (n === undefined) frameRaws.set(e, n = new Set(Object.values(e)));
|
|
1222
|
+
return n;
|
|
1223
|
+
}
|
|
1224
|
+
|
|
1225
|
+
/** The same row at a slot, as the adoption pairs rows (reconcile.ts): two
|
|
1226
|
+
* objects whose keys agree — positionally for an unkeyed family. */ function sameRow(e, n, t) {
|
|
1227
|
+
return e !== null && typeof e === "object" && n !== null && typeof n === "object" && (t === null || sameKey(t(e), t(n)));
|
|
1228
|
+
}
|
|
1229
|
+
|
|
1230
|
+
/** A key of a held adoption whose old and new values are the same row that
|
|
1231
|
+
* nothing had proxied when the adoption ran, so `descend` never paired
|
|
1232
|
+
* them: paired now, as it would have been (#3712) — one target, the old
|
|
1233
|
+
* raw its committed frame, the new raw its staging, held by the same
|
|
1234
|
+
* transaction. Both raws resolve to it, so the slot reads as unchanged and
|
|
1235
|
+
* the row's own leaves decide: `id` the same in both frames holds no one,
|
|
1236
|
+
* `version` holds. A record's keys pair by name; an array's by the family's
|
|
1237
|
+
* key — without a family the pairing is not known here and the hold stands. */ function adoptChild(e, n) {
|
|
1238
|
+
const t = e.k;
|
|
1239
|
+
const r = asBacking(t.Ae);
|
|
1240
|
+
const i = r[n];
|
|
1241
|
+
const o = t.Oe[n];
|
|
1242
|
+
const l = Array.isArray(r) ? e.fam?.key : null;
|
|
1243
|
+
if (e.s || l === undefined || !sameRow(i, o, l) || !isWrappable(i) || !isWrappable(o) || Array.isArray(i) !== Array.isArray(o) || lookupTarget(i, e.fam) !== undefined || lookupTarget(o, e.fam) !== undefined ||
|
|
1244
|
+
// A raw in both frames (the same objects swapped or reordered) is its
|
|
1245
|
+
// own row: pairing it with another would alias the two after the commit.
|
|
1246
|
+
rawsOf(r).has(o) || rawsOf(t.Oe).has(i)) return false;
|
|
1247
|
+
// A raw-marked value wraps to itself, a proxy to its own target: neither
|
|
1248
|
+
// is a fresh target around `ov`.
|
|
1249
|
+
const u = wrap(i, e, n)[$TARGET];
|
|
1250
|
+
if (u === undefined || u.v !== i) return false;
|
|
1251
|
+
adoptPB(u, o, false);
|
|
1252
|
+
holdNode(getContainerNode(u), txOf(t));
|
|
1253
|
+
return true;
|
|
1212
1254
|
}
|
|
1213
1255
|
|
|
1214
1256
|
/** A family target's unheld staging, read with no pass (a handler). */ function familyAhead(e) {
|
|
1215
|
-
return e.fam !== null && context === null && !(e.k !== null && e.k.
|
|
1257
|
+
return e.fam !== null && context === null && !(e.k !== null && e.k.i & CONFIG_HELD);
|
|
1216
1258
|
}
|
|
1217
1259
|
|
|
1218
1260
|
/** Did this batch change `key` — value (slot equality), presence, and (for
|
|
@@ -1246,7 +1288,7 @@ function changedBetween(e, n, t, r, i) {
|
|
|
1246
1288
|
* tracked or not, applies the hold and A28 rules a signal's read does. A
|
|
1247
1289
|
* projection's unheld staging is ahead for a handler (`familyAhead`). */ function nodeValue(e, n, t) {
|
|
1248
1290
|
let r = read(e);
|
|
1249
|
-
if (e.
|
|
1291
|
+
if (e.Oe !== NOT_PENDING && !(e.i & CONFIG_HELD) && context === null && t.fam !== null) r = e.Oe;
|
|
1250
1292
|
return r === FORCE ? n : r;
|
|
1251
1293
|
}
|
|
1252
1294
|
|
|
@@ -1266,8 +1308,8 @@ function changedBetween(e, n, t, r, i) {
|
|
|
1266
1308
|
if (l) {
|
|
1267
1309
|
// The link's committed value follows the inner store's (what a lane
|
|
1268
1310
|
// over it covers — its reveal and revert compare against it, S4).
|
|
1269
|
-
i.
|
|
1270
|
-
if (i.
|
|
1311
|
+
i.Ae = t;
|
|
1312
|
+
if (i.i & CONFIG_OVERRIDE) u = n;
|
|
1271
1313
|
} else u = n;
|
|
1272
1314
|
}
|
|
1273
1315
|
}
|
|
@@ -1288,7 +1330,7 @@ function changedBetween(e, n, t, r, i) {
|
|
|
1288
1330
|
}
|
|
1289
1331
|
|
|
1290
1332
|
/** Is `n` among `c`'s dependencies (any pass's — a kept tail included)? */ function linkedTo(e, n) {
|
|
1291
|
-
for (let t = e.
|
|
1333
|
+
for (let t = e.p; t !== null; t = t._) if (t.I === n) return true;
|
|
1292
1334
|
return false;
|
|
1293
1335
|
}
|
|
1294
1336
|
|
|
@@ -1307,7 +1349,7 @@ function changedBetween(e, n, t, r, i) {
|
|
|
1307
1349
|
// reader of a memo would — linked, so it re-runs at the landing (the
|
|
1308
1350
|
// next settled pass pulls without linking and the stale link trims), a
|
|
1309
1351
|
// verdict reader registered, a tracked pass suspended.
|
|
1310
|
-
if (n.
|
|
1352
|
+
if (n.S & (STATUS_PENDING | STATUS_ERROR)) {
|
|
1311
1353
|
// A render effect outside the flight's own flush is the frame, not a
|
|
1312
1354
|
// derivation: it keeps what it shows and learns of the landing from the
|
|
1313
1355
|
// leaves the landing changes (unchanged leaves say nothing — it is not a
|
|
@@ -1315,9 +1357,10 @@ function changedBetween(e, n, t, r, i) {
|
|
|
1315
1357
|
// One that already observes the flight (linked by the pass that saw it
|
|
1316
1358
|
// go up — the frame's hold, `blocked`) keeps observing it: a re-run for
|
|
1317
1359
|
// another reason (a guess it read, the seam) that dropped the link would
|
|
1318
|
-
// release the hold with the flight still up.
|
|
1360
|
+
// release the hold with the flight still up. An errored derive has no
|
|
1361
|
+
// landing to learn of: the error is what the frame shows.
|
|
1319
1362
|
const t = context;
|
|
1320
|
-
if (t !== null && t.
|
|
1363
|
+
if (t !== null && t.u === EFFECT_RENDER && !(n.S & STATUS_ERROR) && n.i & CONFIG_HELD && flushTransaction !== txOf(n) && !linkedTo(t, n)) return;
|
|
1321
1364
|
// An optimistic family carrying guesses that stand in for the flight
|
|
1322
1365
|
// (A17): the guesses are the display — a reader is served the leaves
|
|
1323
1366
|
// (committed plus the guesses) and does not suspend on the derive; a
|
|
@@ -1325,7 +1368,7 @@ function changedBetween(e, n, t, r, i) {
|
|
|
1325
1368
|
// up). The family's, not the target's: the edit stands in for the one
|
|
1326
1369
|
// flight the family has.
|
|
1327
1370
|
const r = e.fam.overlaid;
|
|
1328
|
-
if (verdict === null && n.
|
|
1371
|
+
if (verdict === null && n.S & STATUS_PENDING && r !== undefined && r.size !== 0) return;
|
|
1329
1372
|
read(n);
|
|
1330
1373
|
} else untrack(() => read(n));
|
|
1331
1374
|
}
|
|
@@ -1338,12 +1381,12 @@ function changedBetween(e, n, t, r, i) {
|
|
|
1338
1381
|
* classification, as core reads it — `heldNotFinal`). */ function holdWithDerive(e, n) {
|
|
1339
1382
|
const t = e.fam?.node;
|
|
1340
1383
|
if (t !== undefined && t !== null && !userWrite && // the derive's own write (its draft or landing), not a user setter's
|
|
1341
|
-
t.
|
|
1384
|
+
t.i & CONFIG_HELD && n.Oe !== NOT_PENDING &&
|
|
1342
1385
|
// A node carrying a guess is the lane's: its staging is the truth beneath
|
|
1343
1386
|
// the guess (`setSignal` → `laneWrite`), never re-homed by the store.
|
|
1344
|
-
!(n.
|
|
1387
|
+
!(n.i & (CONFIG_HELD | CONFIG_OVERRIDE))) {
|
|
1345
1388
|
holdNode(n, txOf(t));
|
|
1346
|
-
n.m.
|
|
1389
|
+
n.m.ke = t.m.ke;
|
|
1347
1390
|
}
|
|
1348
1391
|
}
|
|
1349
1392
|
|
|
@@ -1414,7 +1457,7 @@ const traps = {
|
|
|
1414
1457
|
}
|
|
1415
1458
|
// (The witness before the pull: a mark on an uninitialized derived
|
|
1416
1459
|
// store is witnessed, then the pull throws — loading, declared pending.)
|
|
1417
|
-
if (verdict !== null && affectsHooks !== null && getObserver() === null) affectsHooks.
|
|
1460
|
+
if (verdict !== null && affectsHooks !== null && getObserver() === null) affectsHooks.ro(e, n);
|
|
1418
1461
|
if (e.fam !== null) pullFamily(e);
|
|
1419
1462
|
// Hot inline case: existing PLAIN node (non-accessor) read outside any
|
|
1420
1463
|
// draft — the dbmon/uibench effect re-read shape. Core's `read()` serves
|
|
@@ -1429,7 +1472,7 @@ const traps = {
|
|
|
1429
1472
|
const r = e.n?.[n];
|
|
1430
1473
|
if (writeScopes === null && !writeOverride) {
|
|
1431
1474
|
const t = r;
|
|
1432
|
-
if (t !== undefined && t.acc !== true && (!e.ch || t.
|
|
1475
|
+
if (t !== undefined && t.acc !== true && (!e.ch || t.i & CONFIG_OVERRIDE)) {
|
|
1433
1476
|
const r = nodeValue(t, undefined, e);
|
|
1434
1477
|
if (r === null || typeof r !== "object") return r;
|
|
1435
1478
|
if (e.s) return serveShallow(e, n, r);
|
|
@@ -1511,7 +1554,7 @@ const traps = {
|
|
|
1511
1554
|
if (n === $OWNER || n === $RECORD) return false;
|
|
1512
1555
|
// (The witness before the pull: a mark on an uninitialized derived
|
|
1513
1556
|
// store is witnessed, then the pull throws — loading, declared pending.)
|
|
1514
|
-
if (verdict !== null && affectsHooks !== null && getObserver() === null) affectsHooks.
|
|
1557
|
+
if (verdict !== null && affectsHooks !== null && getObserver() === null) affectsHooks.ro(e, n);
|
|
1515
1558
|
if (e.fam !== null) pullFamily(e);
|
|
1516
1559
|
const t = readSource(e, n);
|
|
1517
1560
|
// A tracked reader's presence node answers (born from the two frames;
|
|
@@ -1524,9 +1567,9 @@ const traps = {
|
|
|
1524
1567
|
const i = read(r);
|
|
1525
1568
|
if (!e.ch || t !== e.v) return !!i;
|
|
1526
1569
|
const o = n in t;
|
|
1527
|
-
r.
|
|
1570
|
+
r.Ae = o;
|
|
1528
1571
|
// the link follows the inner store (S4)
|
|
1529
|
-
if (r.
|
|
1572
|
+
if (r.i & CONFIG_OVERRIDE) return !!i;
|
|
1530
1573
|
return o;
|
|
1531
1574
|
} else if (optRead(e)) {
|
|
1532
1575
|
const t = optHooks.has(e, n);
|
|
@@ -1536,14 +1579,14 @@ const traps = {
|
|
|
1536
1579
|
return n in t && !(e.del !== null && t === e.pb && e.del.has(n));
|
|
1537
1580
|
},
|
|
1538
1581
|
ownKeys(e) {
|
|
1539
|
-
if (verdict !== null && affectsHooks !== null && getObserver() === null) affectsHooks.
|
|
1582
|
+
if (verdict !== null && affectsHooks !== null && getObserver() === null) affectsHooks.ro(e, undefined);
|
|
1540
1583
|
if (e.fam !== null) pullFamily(e);
|
|
1541
1584
|
return visibleKeys(e, enumerationSource(e));
|
|
1542
1585
|
},
|
|
1543
1586
|
getOwnPropertyDescriptor(e, n) {
|
|
1544
1587
|
if (n === $OWNER || n === $RECORD) return undefined;
|
|
1545
1588
|
const t = getObserver();
|
|
1546
|
-
if (verdict !== null && affectsHooks !== null && t === null) affectsHooks.
|
|
1589
|
+
if (verdict !== null && affectsHooks !== null && t === null) affectsHooks.ro(e, n);
|
|
1547
1590
|
if (e.fam !== null) pullFamily(e);
|
|
1548
1591
|
// An enumerator (spread, Object.entries) already holds the container
|
|
1549
1592
|
// node and reads its frame; a descriptor read on its own tracks
|
|
@@ -1561,7 +1604,7 @@ const traps = {
|
|
|
1561
1604
|
const t = getHasNode(e, n);
|
|
1562
1605
|
const r = read(t);
|
|
1563
1606
|
o = readSource(e, n, true);
|
|
1564
|
-
if (!r && (!e.ch || t.
|
|
1607
|
+
if (!r && (!e.ch || t.i & CONFIG_OVERRIDE || !(n in o))) return undefined;
|
|
1565
1608
|
} else o = readSource(e, n, true);
|
|
1566
1609
|
let l;
|
|
1567
1610
|
if (!i && optRead(e)) {
|
|
@@ -1654,8 +1697,8 @@ const traps = {
|
|
|
1654
1697
|
* to the key's presence node or a later add never re-runs it. */ function observerHoldsContainer(e, n) {
|
|
1655
1698
|
const t = e.k;
|
|
1656
1699
|
if (t === null) return false;
|
|
1657
|
-
const r = t.
|
|
1658
|
-
return r !== null && r.
|
|
1700
|
+
const r = t.Ye;
|
|
1701
|
+
return r !== null && r.l === n && (!(n.R & REACTIVE_RECOMPUTING_DEPS) || r.Pe === n.pe);
|
|
1659
1702
|
}
|
|
1660
1703
|
|
|
1661
1704
|
function storeSetter(e, n, t = true) {
|
|
@@ -1842,7 +1885,7 @@ function snapshotWalk(e, n, t) {
|
|
|
1842
1885
|
// R27: a snapshot sees the batch's pending backing — a held one (another
|
|
1843
1886
|
// transaction's future) only from its own draft.
|
|
1844
1887
|
let o = i.v;
|
|
1845
|
-
if (i.pb !== null && (inDraft(i) || writeOverride || i.k === null || !(i.k.
|
|
1888
|
+
if (i.pb !== null && (inDraft(i) || writeOverride || i.k === null || !(i.k.i & CONFIG_HELD))) {
|
|
1846
1889
|
if (i.ovl) materializePB(i);
|
|
1847
1890
|
o = i.pb;
|
|
1848
1891
|
}
|
|
@@ -1894,4 +1937,4 @@ function snapshotWalk(e, n, t) {
|
|
|
1894
1937
|
return o ?? r;
|
|
1895
1938
|
}
|
|
1896
1939
|
|
|
1897
|
-
export { $PROXY, $TARGET, $TRACK, LaneView, adoptPB,
|
|
1940
|
+
export { $PROXY, $TARGET, $TRACK, LaneView, adoptPB, arrayStructureChanged, asBacking, bumpDeep, cloneRaw, committed, containerEquals, createStore, deep, getContainerNode, getHasNode, getNode, hasAccessorFlag, materializePB, membershipChanged, notifyFold, notifyFoldTail, notifyKeyDiff, notifyKeyValue, resolveChainedRaw, runDirect, sameKey, sameRow, snapshot, storeHasFamily, storeHasOptimisticFamily, storeIsShallow, storeSetter, targetsEqual, unwrapValue, userWriting, wrap };
|
|
@@ -40,6 +40,10 @@ interface Boundary {
|
|
|
40
40
|
_collapsed: boolean;
|
|
41
41
|
_error: Signal<unknown> | null;
|
|
42
42
|
_show: (b: Boundary) => unknown;
|
|
43
|
+
/** The fallback's own computed, in its own scope like `Show`'s function
|
|
44
|
+
* child: instantiated once per show and kept across the output's
|
|
45
|
+
* re-derives while it shows (#3991). */
|
|
46
|
+
_fb: Computed<unknown> | null;
|
|
43
47
|
}
|
|
44
48
|
/** Context key: the reveal controller a Loading boundary created here is a
|
|
45
49
|
* slot of (reveal.ts); a boundary clears it for its content — only direct
|
|
@@ -502,9 +502,13 @@ export interface AttributionOptions {
|
|
|
502
502
|
/**
|
|
503
503
|
* Graph-growth warning: emit GRAPH_GROWTH when the live owner count at the
|
|
504
504
|
* settle of the same route has climbed on `visits` consecutive visits
|
|
505
|
-
* (default 3) to `ratio` or more of the first (default 1.25)
|
|
505
|
+
* (default 3) to `ratio` or more of the first (default 1.25), and so has
|
|
506
|
+
* the part of it that outlived each of those navigations — a root or a
|
|
506
507
|
* subscription each visit leaves behind, the leak class a heap snapshot
|
|
507
|
-
* finds
|
|
508
|
+
* finds, not content a visit owns and leaving disposes. The count is a walk
|
|
509
|
+
* when a navigation opens and at its settle, never per node. Navigations
|
|
510
|
+
* that stay on a route pattern continue its visit and are not compared.
|
|
511
|
+
* `false` disables.
|
|
508
512
|
*/
|
|
509
513
|
graphGrowth?: {
|
|
510
514
|
visits: number;
|