@solidjs/signals 2.0.0-rc.1 → 2.0.0-rc.11
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 +7155 -0
- package/dist/dev.attribution.js +3307 -0
- package/dist/dev.js +5765 -4496
- package/dist/observe/affects.js +129 -0
- package/dist/observe/attribution.js +7 -0
- package/dist/observe/boundaries.js +793 -0
- package/dist/observe/core/action.js +177 -0
- package/dist/observe/core/async.js +849 -0
- package/dist/observe/core/attribution-costs.js +66 -0
- package/dist/observe/core/attribution-feedback.js +280 -0
- package/dist/observe/core/attribution-hooks.js +83 -0
- package/dist/observe/core/attribution-queries.js +43 -0
- package/dist/observe/core/attribution.js +2904 -0
- package/dist/observe/core/constants.js +283 -0
- package/dist/{types-cjs/core/context.d.cts → observe/core/context.js} +37 -12
- package/dist/observe/core/core.js +1999 -0
- package/dist/observe/core/dev.js +343 -0
- package/dist/observe/core/effect.js +200 -0
- package/dist/observe/core/error-hooks.js +71 -0
- package/dist/observe/core/error.js +80 -0
- package/dist/observe/core/external.js +98 -0
- package/dist/observe/core/graph.js +155 -0
- package/dist/observe/core/heap.js +147 -0
- package/dist/observe/core/invariants.js +45 -0
- package/dist/observe/core/lanes.js +205 -0
- package/dist/observe/core/optimistic.js +669 -0
- package/dist/observe/core/owner.js +353 -0
- package/dist/observe/core/scheduler.js +1561 -0
- package/dist/observe/core/verdict.js +674 -0
- package/dist/observe/index.js +59 -0
- package/dist/observe/map.js +507 -0
- package/dist/observe/signals.js +731 -0
- package/dist/observe/store/index.js +44 -0
- package/dist/observe/store/next/optimistic.js +717 -0
- package/dist/observe/store/next/projection.js +266 -0
- package/dist/observe/store/next/reconcile.js +375 -0
- package/dist/observe/store/next/store.js +2480 -0
- package/dist/observe/store/next/target.js +51 -0
- package/dist/observe/store/store.js +331 -0
- package/dist/observe/store/storePath.js +103 -0
- package/dist/observe/store/utils.js +1070 -0
- package/dist/prod/affects.js +10 -9
- package/dist/prod/attribution.js +45 -0
- package/dist/prod/boundaries.js +388 -178
- package/dist/prod/core/action.js +65 -37
- package/dist/prod/core/async.js +378 -163
- package/dist/prod/core/attribution-hooks.js +3 -0
- package/dist/prod/core/constants.js +186 -1
- package/dist/prod/core/context.js +10 -16
- package/dist/prod/core/core.js +1546 -416
- package/dist/prod/core/dev.js +18 -1
- package/dist/prod/core/effect.js +119 -79
- package/dist/prod/core/error-hooks.js +71 -0
- package/dist/prod/core/error.js +13 -1
- package/dist/prod/core/external.js +4 -4
- package/dist/prod/core/graph.js +105 -54
- package/dist/prod/core/heap.js +72 -65
- package/dist/prod/core/invariants.js +3 -2
- package/dist/prod/core/lanes.js +117 -52
- package/dist/prod/core/optimistic.js +500 -104
- package/dist/prod/core/owner.js +131 -84
- package/dist/prod/core/scheduler.js +1012 -241
- package/dist/prod/core/verdict.js +417 -112
- package/dist/prod/index.js +20 -8
- package/dist/prod/map.js +355 -171
- package/dist/prod/signals.js +363 -32
- package/dist/prod/store/index.js +2 -0
- package/dist/prod/store/next/optimistic.js +530 -197
- package/dist/prod/store/next/projection.js +142 -57
- package/dist/prod/store/next/reconcile.js +149 -103
- package/dist/prod/store/next/store.js +1470 -346
- package/dist/prod/store/next/target.js +40 -9
- package/dist/prod/store/store.js +23 -19
- package/dist/prod/store/utils.js +997 -130
- package/dist/types/attribution.d.ts +19 -0
- package/dist/types/attribution.prod.d.ts +22 -0
- package/dist/types/boundaries.d.ts +78 -5
- package/dist/types/core/action.d.ts +12 -5
- package/dist/types/core/async.d.ts +3 -1
- package/dist/types/core/attribution-costs.d.ts +35 -0
- package/dist/types/core/attribution-feedback.d.ts +133 -0
- package/dist/types/core/attribution-hooks.d.ts +304 -0
- package/dist/types/core/attribution-queries.d.ts +24 -0
- package/dist/types/core/attribution.d.ts +892 -0
- package/dist/types/core/constants.d.ts +179 -0
- package/dist/types/core/core.d.ts +299 -25
- package/dist/types/core/dev.d.ts +421 -8
- package/dist/types/core/effect.d.ts +8 -1
- package/dist/types/core/error-hooks.d.ts +71 -0
- package/dist/types/core/error.d.ts +9 -0
- package/dist/types/core/graph.d.ts +23 -0
- package/dist/types/core/heap.d.ts +5 -3
- package/dist/types/core/index.d.ts +6 -3
- package/dist/types/core/invariants.d.ts +5 -1
- package/dist/types/core/lanes.d.ts +51 -19
- package/dist/types/core/owner.d.ts +15 -3
- package/dist/types/core/scheduler.d.ts +252 -1
- package/dist/types/core/types.d.ts +124 -41
- package/dist/types/index.d.ts +18 -5
- package/dist/types/map.d.ts +2 -0
- package/dist/types/signals.d.ts +145 -13
- package/dist/types/store/index.d.ts +7 -6
- package/dist/types/store/next/optimistic.d.ts +18 -13
- package/dist/types/store/next/projection.d.ts +5 -2
- package/dist/types/store/next/reconcile.d.ts +7 -0
- package/dist/types/store/next/store.d.ts +83 -11
- package/dist/types/store/next/target.d.ts +108 -11
- package/dist/types/store/store.d.ts +20 -11
- package/dist/types/store/utils.d.ts +188 -0
- package/package.json +31 -26
- package/dist/node.cjs +0 -8137
- package/dist/types/store/optimistic.d.ts +0 -45
- package/dist/types/store/projection.d.ts +0 -70
- package/dist/types/store/reconcile.d.ts +0 -46
- package/dist/types-cjs/affects.d.cts +0 -47
- package/dist/types-cjs/boundaries.d.cts +0 -175
- package/dist/types-cjs/core/action.d.cts +0 -64
- package/dist/types-cjs/core/async.d.cts +0 -21
- package/dist/types-cjs/core/constants.d.cts +0 -71
- package/dist/types-cjs/core/core.d.cts +0 -156
- package/dist/types-cjs/core/dev.d.cts +0 -64
- package/dist/types-cjs/core/effect.d.cts +0 -30
- package/dist/types-cjs/core/error.d.cts +0 -47
- package/dist/types-cjs/core/external.d.cts +0 -15
- package/dist/types-cjs/core/graph.d.cts +0 -5
- package/dist/types-cjs/core/heap.d.cts +0 -22
- package/dist/types-cjs/core/index.d.cts +0 -13
- package/dist/types-cjs/core/invariants.d.cts +0 -59
- package/dist/types-cjs/core/lanes.d.cts +0 -56
- package/dist/types-cjs/core/optimistic.d.cts +0 -6
- package/dist/types-cjs/core/owner.d.cts +0 -124
- package/dist/types-cjs/core/scheduler.d.cts +0 -172
- package/dist/types-cjs/core/types.d.cts +0 -148
- package/dist/types-cjs/core/verdict.d.cts +0 -2
- package/dist/types-cjs/index.d.cts +0 -10
- package/dist/types-cjs/map.d.cts +0 -69
- package/dist/types-cjs/package.json +0 -3
- package/dist/types-cjs/signals.d.cts +0 -624
- package/dist/types-cjs/store/index.d.cts +0 -19
- package/dist/types-cjs/store/next/optimistic.d.cts +0 -20
- package/dist/types-cjs/store/next/projection.d.cts +0 -24
- package/dist/types-cjs/store/next/reconcile.d.cts +0 -3
- package/dist/types-cjs/store/next/store.d.cts +0 -71
- package/dist/types-cjs/store/next/target.d.cts +0 -99
- package/dist/types-cjs/store/optimistic.d.cts +0 -45
- package/dist/types-cjs/store/projection.d.cts +0 -70
- package/dist/types-cjs/store/reconcile.d.cts +0 -46
- package/dist/types-cjs/store/store.d.cts +0 -138
- package/dist/types-cjs/store/storePath.d.cts +0 -58
- package/dist/types-cjs/store/utils.d.cts +0 -74
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@solidjs/signals/attribution` — the "why did this run" engine.
|
|
3
|
+
*
|
|
4
|
+
* A separate entry on purpose: the core ships only the hook slot
|
|
5
|
+
* (`OBSERVE.attribution`, which `enable()` installs into) and the declared
|
|
6
|
+
* frames (`withInteraction`, `withOrigin`); the engine that turns hook facts
|
|
7
|
+
* into re-run explanations, cost tables, holds and feedback lives here, so an
|
|
8
|
+
* observe build carries it only when something imports this module. The dev
|
|
9
|
+
* and observe tiers resolve to this file; the prod tier resolves to
|
|
10
|
+
* `attribution.prod.ts`, an inert engine with the same surface, so app code
|
|
11
|
+
* can import it unconditionally.
|
|
12
|
+
*/
|
|
13
|
+
export { attribution, formatOrigin, formatRerun, graphSize } from "./core/attribution.js";
|
|
14
|
+
export { costs } from "./core/attribution-costs.js";
|
|
15
|
+
export { feedback } from "./core/attribution-feedback.js";
|
|
16
|
+
export { subscriptions, why } from "./core/attribution-queries.js";
|
|
17
|
+
export type { Acknowledgement, Attribution, AttributionOptions, AttributionValues, ChangeKind, ChangeOrigin, ChangeRecord, CreateEvent, EffectRunEvent, FallbackEvent, FlightEvent, FlightLink, FlushEvent, GraphEvent, GraphSize, HeldWrite, HistoryRecords, HistoryType, HoldEvent, InteractionEvent, NavigationEvent, NavigationHop, RerunEvent, WaterfallRecord } from "./core/attribution.js";
|
|
18
|
+
export type { AttributionCostTables, ScopeCost, WriteCost } from "./core/attribution-costs.js";
|
|
19
|
+
export type { AttributionFeedbackTables, FallbackStats, FeedbackInteraction, FeedbackNavigation, FeedbackSource, FlightStats } from "./core/attribution-feedback.js";
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@solidjs/signals/attribution` as the prod tier resolves it.
|
|
3
|
+
*
|
|
4
|
+
* A prod build has no hook sites — `__OBSERVE__` folded every one out — so an
|
|
5
|
+
* engine installed there would never hear a fact. Rather than make apps guard
|
|
6
|
+
* the import per tier, prod resolves this inert twin: the same `Attribution`
|
|
7
|
+
* surface, every query empty, `enable()` a no-op. Type-checked against the
|
|
8
|
+
* real engine's interface so the two cannot drift.
|
|
9
|
+
*/
|
|
10
|
+
import type { Attribution } from "./core/attribution.js";
|
|
11
|
+
import type * as Engine from "./attribution.js";
|
|
12
|
+
export declare const attribution: Attribution;
|
|
13
|
+
export declare const costs: typeof Engine.costs;
|
|
14
|
+
export declare const feedback: typeof Engine.feedback;
|
|
15
|
+
export declare const why: typeof Engine.why;
|
|
16
|
+
export declare const subscriptions: typeof Engine.subscriptions;
|
|
17
|
+
export declare const formatRerun: typeof Engine.formatRerun;
|
|
18
|
+
export declare const formatOrigin: typeof Engine.formatOrigin;
|
|
19
|
+
export declare const graphSize: typeof Engine.graphSize;
|
|
20
|
+
export type { Acknowledgement, Attribution, AttributionOptions, AttributionValues, ChangeKind, ChangeOrigin, ChangeRecord, CreateEvent, EffectRunEvent, FallbackEvent, FlightEvent, FlightLink, FlushEvent, GraphEvent, GraphSize, HeldWrite, HistoryRecords, HistoryType, HoldEvent, InteractionEvent, NavigationEvent, NavigationHop, RerunEvent, WaterfallRecord } from "./core/attribution.js";
|
|
21
|
+
export type { AttributionCostTables, ScopeCost, WriteCost } from "./core/attribution-costs.js";
|
|
22
|
+
export type { AttributionFeedbackTables, FallbackStats, FeedbackInteraction, FeedbackNavigation, FeedbackSource, FlightStats } from "./core/attribution-feedback.js";
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import type { OptimisticLane } from "./core/lanes.js";
|
|
2
|
+
import { Queue, type Computed, type Effect, type Owner } from "./core/index.js";
|
|
2
3
|
import type { Signal } from "./core/index.js";
|
|
3
4
|
import { type Accessor } from "./signals.js";
|
|
4
5
|
export interface BoundaryComputed<T> extends Computed<T> {
|
|
@@ -37,17 +38,70 @@ export declare class CollectionQueue extends Queue {
|
|
|
37
38
|
_collectionType: number;
|
|
38
39
|
_sources: Set<Computed<any>>;
|
|
39
40
|
_tree?: BoundaryComputed<any>;
|
|
41
|
+
/** The output pass — fallback or content (createCollectionBoundary). */
|
|
42
|
+
_output?: Computed<any>;
|
|
40
43
|
_pending: boolean;
|
|
41
44
|
_disabled: Signal<boolean>;
|
|
42
45
|
_error?: Signal<unknown>;
|
|
43
46
|
_collapsed: Signal<boolean>;
|
|
44
47
|
_revealController?: RevealController;
|
|
45
48
|
_initialized: boolean;
|
|
46
|
-
|
|
47
|
-
|
|
49
|
+
/** The boundary's owner — where a `caught` report locates itself, set before the children are built (a creation-time throw arrives before `_tree`). */
|
|
50
|
+
_owner?: Owner;
|
|
51
|
+
/** The lane the `on` pass that queued this re-arm ran under (onNode), if
|
|
52
|
+
* any: the fallback swap is display-ahead — shown through the lane. */
|
|
53
|
+
_rearmLane: OptimisticLane | null;
|
|
48
54
|
constructor(type: number);
|
|
49
55
|
run(type: number): void;
|
|
56
|
+
/** An `on` dependency notified (onNode → scheduler `pendingRearms`);
|
|
57
|
+
* drained after the heap, before the verdict, under the notifying write's
|
|
58
|
+
* transaction (#3540). A boundary showing content is fresh again: it
|
|
59
|
+
* releases its hold now and, if anything under it is still pending, swaps
|
|
60
|
+
* to its fallback. The swap is staged, so it lands with the write's frame
|
|
61
|
+
* — at once when nothing else holds it, with the rest of the new page
|
|
62
|
+
* when something outside the boundary does; if the pending lands first,
|
|
63
|
+
* `_checkSources` clears it and no fallback is shown. An `on` that read a
|
|
64
|
+
* lane (`latest()`, an optimistic write) asked for the change now:
|
|
65
|
+
* `_rearmLane` shows the swap through the lane, beside the held frame.
|
|
66
|
+
* Children stay alive behind the fallback. */
|
|
67
|
+
_rearm(): void;
|
|
68
|
+
/** Show the fallback: the swap the output pass selects on. Staged, it is
|
|
69
|
+
* the frame's and lands with its commit. Re-armed from a lane pass
|
|
70
|
+
* (`lane`), it is the current frame's — committed outright, as the lane's
|
|
71
|
+
* view already is on screen — and shown through the lane: the output pass
|
|
72
|
+
* publishes a derived override and its readers run from the lane's queue,
|
|
73
|
+
* at the park, ahead of the transaction (a lane pass reads staged plain
|
|
74
|
+
* writes committed, so a staged swap would be invisible to it). */
|
|
75
|
+
_swap(lane: OptimisticLane | null): void;
|
|
76
|
+
/** Retry the collected failures of an error boundary: recompute each
|
|
77
|
+
* source that threw, so the boundary can recover. */
|
|
78
|
+
_retry(): void;
|
|
50
79
|
notify(node: Effect<any>, type: number, flags: number, error?: any): boolean;
|
|
80
|
+
/** Is `reporter` live and routed to this boundary — under it, with no
|
|
81
|
+
* collecting pending-type boundary in between (`reporterBlocksSource`'s test)? */
|
|
82
|
+
_holds(reporter: Computed<any>): boolean;
|
|
83
|
+
/** Has a collected source stopped counting for this boundary? A source
|
|
84
|
+
* with a live affects() mark holds display state for the mark's lifetime
|
|
85
|
+
* (the visual channel): the marked node carries no status of its own, so
|
|
86
|
+
* the count is the liveness test. The release sweep (finalizePureQueue
|
|
87
|
+
* after mark release) re-runs this check. A source born held under this
|
|
88
|
+
* boundary (recompute, #3540) carries no status either: it is collected
|
|
89
|
+
* while it has a staged value and no committed one, and released by the
|
|
90
|
+
* commit that initializes it. */
|
|
91
|
+
_settled(source: Computed<any>): boolean;
|
|
92
|
+
/** The pre-verdict sweep (scheduler run(), #3540): a collecting boundary
|
|
93
|
+
* whose OUTPUT is pending — its fallback read something not ready — is
|
|
94
|
+
* judged here, under the transaction. That output is what an initialized
|
|
95
|
+
* parent holds the frame on, and it derives from `_disabled`, not the
|
|
96
|
+
* tree: the tree settling never re-runs it, only a sweep does, and the
|
|
97
|
+
* commit sweep runs after the verdict the output's own read keeps parking
|
|
98
|
+
* — the content waited for the fallback's flight. Judged ready here, the
|
|
99
|
+
* boundary stages `_disabled` false with the frame and the output re-runs
|
|
100
|
+
* in this heap: it reads the tree and drops the fallback's read (recompute
|
|
101
|
+
* settles a pass's outgoing pending sources), so the verdict sees the
|
|
102
|
+
* release. A boundary showing a ready fallback parks nothing and keeps the
|
|
103
|
+
* commit sweep's reveal. */
|
|
104
|
+
_judgeHeld(): void;
|
|
51
105
|
_checkSources(): void;
|
|
52
106
|
}
|
|
53
107
|
/**
|
|
@@ -59,8 +113,27 @@ export declare class CollectionQueue extends Queue {
|
|
|
59
113
|
*
|
|
60
114
|
* @param fn the tracked subtree
|
|
61
115
|
* @param fallback the fallback shown while async reads in `fn` are unresolved
|
|
62
|
-
* @param options `on` —
|
|
63
|
-
*
|
|
116
|
+
* @param options `on` — a dependency list: a tracked function whose reads
|
|
117
|
+
* re-arm the boundary. Its return value is irrelevant (never compared);
|
|
118
|
+
* what matters is what it reads. Without `on`, a boundary that has shown
|
|
119
|
+
* content keeps it through a refetch (the pending holds with the
|
|
120
|
+
* transaction). With `on`, a write to anything it reads makes the boundary
|
|
121
|
+
* fresh again: it stops waiting on its current content, and if something
|
|
122
|
+
* under it is pending it shows `fallback` until the new content is ready;
|
|
123
|
+
* if nothing is pending, the notification is a no-op. The fallback lands
|
|
124
|
+
* with the same frame as the change that caused it — now, when nothing
|
|
125
|
+
* else holds that frame; together with the rest of the new page during a
|
|
126
|
+
* held navigation, not before it. If the same data is also read outside
|
|
127
|
+
* the boundary, the frame waits on it and the fallback can never be seen
|
|
128
|
+
* (DEV warns `LOADING_ON_OUTSIDE_HOLD`); the fix is structural — move the
|
|
129
|
+
* outside read under the boundary so one hold owns the data. A frame held
|
|
130
|
+
* past the content's landing by something else (the write's action, other
|
|
131
|
+
* pending data) also shows no fallback; that is a race the fallback may
|
|
132
|
+
* lose, a legitimate outcome, and not reported. A display-ahead read in
|
|
133
|
+
* `on` (`latest()`) shows the fallback now, beside the held frame; that
|
|
134
|
+
* is a capability, not the recommended shape. Optimistic writes and a
|
|
135
|
+
* source going pending notify like any other. The children are not
|
|
136
|
+
* re-created — they stay alive behind the fallback.
|
|
64
137
|
*
|
|
65
138
|
* @example
|
|
66
139
|
* ```tsx
|
|
@@ -23,15 +23,22 @@
|
|
|
23
23
|
* `yield` is the transaction-safe suspension point: the action waits for a
|
|
24
24
|
* yielded promise and re-enters the transaction before running the code after
|
|
25
25
|
* it. A plain `await` does NOT — the runtime has no hook into an async
|
|
26
|
-
* generator's internal await continuations, so
|
|
27
|
-
*
|
|
28
|
-
* immediately
|
|
29
|
-
*
|
|
26
|
+
* generator's internal await continuations, so code between an `await` and
|
|
27
|
+
* the next `yield` runs OUTSIDE the transaction: writes to fresh signals
|
|
28
|
+
* commit immediately, and anything that creates a reader there — `until()`,
|
|
29
|
+
* `latest()`, a memo or effect, a mount — is created mainline, where a read of
|
|
30
|
+
* this action's held state makes it born held (A29): staged with the
|
|
31
|
+
* transaction and replayed at its commit. For `until()` that commit is the
|
|
32
|
+
* settle its own promise holds open (#3482). `await` is still the ergonomic
|
|
33
|
+
* choice for typed results; just put a bare `yield` before any write or
|
|
34
|
+
* reader creation that follows it — including the expression of the next
|
|
35
|
+
* `yield`, which is evaluated before the step re-enters:
|
|
30
36
|
*
|
|
31
37
|
* ```ts
|
|
32
38
|
* const saved = await api.createTodo(text); // typed result
|
|
33
|
-
* yield; // re-enter the transaction before writing
|
|
39
|
+
* yield; // re-enter the transaction before writing or reading
|
|
34
40
|
* setTodos(t => { ... });
|
|
41
|
+
* yield until(() => todos.some(t => t.id === saved.id));
|
|
35
42
|
* ```
|
|
36
43
|
*
|
|
37
44
|
* (For the same reason, don't call `flush()` inside an action body — it
|
|
@@ -14,8 +14,10 @@ export declare function setPendingError(el: Computed<any>, source?: Computed<any
|
|
|
14
14
|
export declare function forEachDependent(el: Computed<any>, fn: (node: Computed<any>, link: Link) => void): void;
|
|
15
15
|
export declare function releaseSettledDependents(el: Computed<any>): void;
|
|
16
16
|
export declare function settleErroredDependents(el: Computed<any>, error: any): void;
|
|
17
|
-
export declare function settlePendingSource(el: Computed<any>): void;
|
|
17
|
+
export declare function settlePendingSource(el: Computed<any>, source?: Computed<any>): void;
|
|
18
18
|
export declare function isThenable<T>(value: T | PromiseLike<T>): value is PromiseLike<T>;
|
|
19
|
+
/** Fire and clear a node's iterator-flight cancellation hook (#3122). */
|
|
20
|
+
export declare function releaseFlightTeardown(el: Computed<any>): void;
|
|
19
21
|
export declare function handleAsync<T>(el: Computed<T>, result: T | PromiseLike<T> | AsyncIterable<T>, setter?: (value: T) => void): T;
|
|
20
22
|
export declare function clearStatus(el: Computed<any>, clearUninitialized?: boolean): void;
|
|
21
23
|
export declare function notifyStatus(el: Computed<any>, status: number, error: any, blockStatus?: boolean, lane?: OptimisticLane): void;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export interface ScopeCost {
|
|
2
|
+
name: string;
|
|
3
|
+
kind: "effect" | "memo";
|
|
4
|
+
runs: number;
|
|
5
|
+
selfMs: number;
|
|
6
|
+
/**
|
|
7
|
+
* Self-time of PLAIN, non-held runs that produced an unchanged value —
|
|
8
|
+
* the recoverable number. Overlay runs (optimistic/transition) are never
|
|
9
|
+
* counted here: an optimistic recompute landing back on the committed
|
|
10
|
+
* value is the mechanism working, not waste.
|
|
11
|
+
*/
|
|
12
|
+
wastedMs: number;
|
|
13
|
+
/** Self-time spent in optimistic/transition (overlay) runs. */
|
|
14
|
+
overlayMs: number;
|
|
15
|
+
}
|
|
16
|
+
export interface WriteCost {
|
|
17
|
+
/** Root cause name (a signal write, async landing, or refresh target). */
|
|
18
|
+
name: string;
|
|
19
|
+
/** Number of downstream re-runs this root triggered. */
|
|
20
|
+
runs: number;
|
|
21
|
+
/** Summed self-time of every downstream re-run it caused. */
|
|
22
|
+
downstreamMs: number;
|
|
23
|
+
}
|
|
24
|
+
export interface AttributionCostTables {
|
|
25
|
+
/** Ranked by self-time. */
|
|
26
|
+
scopes: ScopeCost[];
|
|
27
|
+
/** Ranked by the total downstream re-run time each root write caused. */
|
|
28
|
+
writes: WriteCost[];
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Aggregated cost tables since `enable()`: `scopes` ranked by self-time
|
|
32
|
+
* (with `wastedMs` = time spent on unchanged-value runs), `writes` ranked by
|
|
33
|
+
* total downstream re-run time each root write caused.
|
|
34
|
+
*/
|
|
35
|
+
export declare function costs(): AttributionCostTables;
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
export interface FeedbackSource {
|
|
2
|
+
/** The async nodes the holds waited on; empty when an action alone kept them open. */
|
|
3
|
+
sources: string[];
|
|
4
|
+
holds: number;
|
|
5
|
+
/** Summed wait across the holds (ms). */
|
|
6
|
+
heldMs: number;
|
|
7
|
+
worstMs: number;
|
|
8
|
+
/** Holds with no acknowledgment at all — the SILENT_HOLD signature, at any duration. */
|
|
9
|
+
silent: number;
|
|
10
|
+
silentMs: number;
|
|
11
|
+
/** Holds whose only acknowledgment was a `latest()` shadow: the input showed, nothing said "loading". */
|
|
12
|
+
latestOnly: number;
|
|
13
|
+
/**
|
|
14
|
+
* Holds whose quiescent tail (last write to join → commit) reached
|
|
15
|
+
* `longHolds.infoMs`, acknowledged or not — the LONG_HOLD signature at the
|
|
16
|
+
* table level. The affordance is not the whole answer there: a fallback
|
|
17
|
+
* (`Loading` keyed with `on`), a preload, a cache, or a faster source is.
|
|
18
|
+
* `longMs` sums the tails.
|
|
19
|
+
*/
|
|
20
|
+
long: number;
|
|
21
|
+
longMs: number;
|
|
22
|
+
/** Which affordances answered, and in how many holds — ranked. */
|
|
23
|
+
acknowledgedBy: {
|
|
24
|
+
by: string;
|
|
25
|
+
holds: number;
|
|
26
|
+
}[];
|
|
27
|
+
/** Interactions whose writes were held here, ranked by holds. */
|
|
28
|
+
interactions: {
|
|
29
|
+
interaction: string;
|
|
30
|
+
holds: number;
|
|
31
|
+
}[];
|
|
32
|
+
/** Distinct root writes that were held. */
|
|
33
|
+
writes: string[];
|
|
34
|
+
/** Holds an action opened or joined. */
|
|
35
|
+
actions: number;
|
|
36
|
+
}
|
|
37
|
+
export interface FeedbackInteraction {
|
|
38
|
+
/** `click on button#next "Next →"` — type and target; repeated dispatches fold together. */
|
|
39
|
+
interaction: string;
|
|
40
|
+
/** Distinct dispatches seen (by dispatch time). */
|
|
41
|
+
dispatches: number;
|
|
42
|
+
/** Re-runs traced back to this interaction, and their summed self-time. */
|
|
43
|
+
runs: number;
|
|
44
|
+
selfMs: number;
|
|
45
|
+
/** The most re-run self-time a single dispatch caused — the long-flush hazard. */
|
|
46
|
+
worstDispatchMs: number;
|
|
47
|
+
/** Holds this interaction's writes waited in — the silent-hold hazard. */
|
|
48
|
+
holds: number;
|
|
49
|
+
heldMs: number;
|
|
50
|
+
silentMs: number;
|
|
51
|
+
worstHoldMs: number;
|
|
52
|
+
}
|
|
53
|
+
/** Per async source: how many flights it started, and how many it threw away. */
|
|
54
|
+
export interface FlightStats {
|
|
55
|
+
source: string;
|
|
56
|
+
/** Flights registered (a recompute that produced a new promise/iterable). */
|
|
57
|
+
flights: number;
|
|
58
|
+
/** Flights that landed (whether or not the value changed). */
|
|
59
|
+
landed: number;
|
|
60
|
+
/**
|
|
61
|
+
* Flights superseded by a newer one before landing — the search-as-you-type
|
|
62
|
+
* signature when large: every keystroke asked, most answers were discarded.
|
|
63
|
+
* A debounced/equality-gated derivation between input and fetch is the repair.
|
|
64
|
+
*/
|
|
65
|
+
abandoned: number;
|
|
66
|
+
/** Summed and worst wall time of landed flights (ms). */
|
|
67
|
+
landedMs: number;
|
|
68
|
+
worstMs: number;
|
|
69
|
+
}
|
|
70
|
+
/** Per loading boundary: how long, and how briefly, it showed its fallback. */
|
|
71
|
+
export interface FallbackStats {
|
|
72
|
+
/** The boundary's owner path (`<App> › <Feed>`), or `boundary` when unnamed. */
|
|
73
|
+
boundary: string;
|
|
74
|
+
/** Times the fallback was shown. */
|
|
75
|
+
shows: number;
|
|
76
|
+
/** Summed and worst fallback duration (ms) across completed shows. */
|
|
77
|
+
shownMs: number;
|
|
78
|
+
worstMs: number;
|
|
79
|
+
/**
|
|
80
|
+
* Shows shorter than the flash window (default 150ms): a spinner that
|
|
81
|
+
* appeared and vanished — the other end of the SILENT_HOLD spectrum, too
|
|
82
|
+
* much feedback for too little wait. A preload, a cache, or lifting the
|
|
83
|
+
* fetch above the boundary removes the flash.
|
|
84
|
+
*/
|
|
85
|
+
flashes: number;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Per route: what navigating to it cost, folded from settled
|
|
89
|
+
* `NavigationEvent`s — the route-level view a router integration used to
|
|
90
|
+
* have to build itself, from the runtime's own facts.
|
|
91
|
+
*/
|
|
92
|
+
export interface FeedbackNavigation {
|
|
93
|
+
/** The route pattern (`/users/:id`), or the concrete `to` when the router gave no pattern. */
|
|
94
|
+
name: string;
|
|
95
|
+
navigations: number;
|
|
96
|
+
/** Summed and worst request-to-settle time (ms) across settled navigations. */
|
|
97
|
+
settledMs: number;
|
|
98
|
+
worstMs: number;
|
|
99
|
+
/** Navigations whose writes waited in a hold, and the time they waited. */
|
|
100
|
+
held: number;
|
|
101
|
+
heldMs: number;
|
|
102
|
+
/** Held navigations the screen acknowledged nothing for — the SILENT_HOLD signature. */
|
|
103
|
+
silent: number;
|
|
104
|
+
/** Navigations overwritten by a later one before they landed. */
|
|
105
|
+
superseded: number;
|
|
106
|
+
/** Navigations a redirect sent elsewhere on the way (keyed by where they ended up). */
|
|
107
|
+
redirected: number;
|
|
108
|
+
}
|
|
109
|
+
export interface AttributionFeedbackTables {
|
|
110
|
+
sources: FeedbackSource[];
|
|
111
|
+
interactions: FeedbackInteraction[];
|
|
112
|
+
/** Routes ranked by the time spent held navigating to them, then by total settle time. */
|
|
113
|
+
navigations: FeedbackNavigation[];
|
|
114
|
+
/** Async sources ranked by abandoned flights, then by flights. */
|
|
115
|
+
flights: FlightStats[];
|
|
116
|
+
/** Loading boundaries ranked by flashes, then by time shown. */
|
|
117
|
+
fallbacks: FallbackStats[];
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* What the user waited on, folded from holds and the interaction on each
|
|
121
|
+
* re-run: `sources` ranks async sources by the silent time writes spent held
|
|
122
|
+
* behind them (with which affordances answered, how often, and which
|
|
123
|
+
* interactions were held); `interactions` ranks user events by the total time
|
|
124
|
+
* they cost — re-run work caused (long-flush hazard) beside time held
|
|
125
|
+
* (silent-hold hazard). Facts at every duration; SILENT_HOLD is the
|
|
126
|
+
* thresholded verdict. Three more tables round out the picture: `navigations`
|
|
127
|
+
* ranks routes by the time spent held navigating to them (folded from settled
|
|
128
|
+
* navigations), `flights` counts each async source's flights and how many
|
|
129
|
+
* were abandoned before landing (the re-ask storm), and `fallbacks` measures
|
|
130
|
+
* how long each loading boundary showed its fallback and how often that was a
|
|
131
|
+
* flash.
|
|
132
|
+
*/
|
|
133
|
+
export declare function feedback(): AttributionFeedbackTables;
|