@solidjs/signals 2.0.0-rc.1 → 2.0.0-rc.10

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.
Files changed (150) hide show
  1. package/dist/dev-shared.js +7138 -0
  2. package/dist/dev.attribution.js +3307 -0
  3. package/dist/dev.js +5691 -4491
  4. package/dist/observe/affects.js +129 -0
  5. package/dist/observe/attribution.js +7 -0
  6. package/dist/observe/boundaries.js +793 -0
  7. package/dist/observe/core/action.js +177 -0
  8. package/dist/observe/core/async.js +849 -0
  9. package/dist/observe/core/attribution-costs.js +66 -0
  10. package/dist/observe/core/attribution-feedback.js +280 -0
  11. package/dist/observe/core/attribution-hooks.js +83 -0
  12. package/dist/observe/core/attribution-queries.js +43 -0
  13. package/dist/observe/core/attribution.js +2904 -0
  14. package/dist/observe/core/constants.js +283 -0
  15. package/dist/{types-cjs/core/context.d.cts → observe/core/context.js} +37 -12
  16. package/dist/observe/core/core.js +1999 -0
  17. package/dist/observe/core/dev.js +343 -0
  18. package/dist/observe/core/effect.js +200 -0
  19. package/dist/observe/core/error-hooks.js +71 -0
  20. package/dist/observe/core/error.js +80 -0
  21. package/dist/observe/core/external.js +98 -0
  22. package/dist/observe/core/graph.js +155 -0
  23. package/dist/observe/core/heap.js +147 -0
  24. package/dist/observe/core/invariants.js +45 -0
  25. package/dist/observe/core/lanes.js +205 -0
  26. package/dist/observe/core/optimistic.js +627 -0
  27. package/dist/observe/core/owner.js +353 -0
  28. package/dist/observe/core/scheduler.js +1547 -0
  29. package/dist/observe/core/verdict.js +674 -0
  30. package/dist/observe/index.js +59 -0
  31. package/dist/observe/map.js +484 -0
  32. package/dist/observe/signals.js +731 -0
  33. package/dist/observe/store/index.js +44 -0
  34. package/dist/observe/store/next/optimistic.js +717 -0
  35. package/dist/observe/store/next/projection.js +266 -0
  36. package/dist/observe/store/next/reconcile.js +375 -0
  37. package/dist/observe/store/next/store.js +2480 -0
  38. package/dist/observe/store/next/target.js +51 -0
  39. package/dist/observe/store/store.js +331 -0
  40. package/dist/observe/store/storePath.js +103 -0
  41. package/dist/observe/store/utils.js +1070 -0
  42. package/dist/prod/affects.js +10 -9
  43. package/dist/prod/attribution.js +45 -0
  44. package/dist/prod/boundaries.js +388 -178
  45. package/dist/prod/core/action.js +65 -37
  46. package/dist/prod/core/async.js +378 -163
  47. package/dist/prod/core/attribution-hooks.js +3 -0
  48. package/dist/prod/core/constants.js +186 -1
  49. package/dist/prod/core/context.js +10 -16
  50. package/dist/prod/core/core.js +1546 -416
  51. package/dist/prod/core/dev.js +18 -1
  52. package/dist/prod/core/effect.js +119 -79
  53. package/dist/prod/core/error-hooks.js +71 -0
  54. package/dist/prod/core/error.js +13 -1
  55. package/dist/prod/core/external.js +4 -4
  56. package/dist/prod/core/graph.js +105 -54
  57. package/dist/prod/core/heap.js +72 -65
  58. package/dist/prod/core/invariants.js +3 -2
  59. package/dist/prod/core/lanes.js +117 -52
  60. package/dist/prod/core/optimistic.js +458 -104
  61. package/dist/prod/core/owner.js +131 -84
  62. package/dist/prod/core/scheduler.js +998 -241
  63. package/dist/prod/core/verdict.js +417 -112
  64. package/dist/prod/index.js +20 -8
  65. package/dist/prod/map.js +312 -151
  66. package/dist/prod/signals.js +363 -32
  67. package/dist/prod/store/index.js +2 -0
  68. package/dist/prod/store/next/optimistic.js +530 -197
  69. package/dist/prod/store/next/projection.js +142 -57
  70. package/dist/prod/store/next/reconcile.js +149 -103
  71. package/dist/prod/store/next/store.js +1470 -346
  72. package/dist/prod/store/next/target.js +40 -9
  73. package/dist/prod/store/store.js +23 -19
  74. package/dist/prod/store/utils.js +997 -130
  75. package/dist/types/attribution.d.ts +19 -0
  76. package/dist/types/attribution.prod.d.ts +22 -0
  77. package/dist/types/boundaries.d.ts +78 -5
  78. package/dist/types/core/action.d.ts +12 -5
  79. package/dist/types/core/async.d.ts +3 -1
  80. package/dist/types/core/attribution-costs.d.ts +35 -0
  81. package/dist/types/core/attribution-feedback.d.ts +133 -0
  82. package/dist/types/core/attribution-hooks.d.ts +304 -0
  83. package/dist/types/core/attribution-queries.d.ts +24 -0
  84. package/dist/types/core/attribution.d.ts +892 -0
  85. package/dist/types/core/constants.d.ts +179 -0
  86. package/dist/types/core/core.d.ts +299 -25
  87. package/dist/types/core/dev.d.ts +421 -8
  88. package/dist/types/core/effect.d.ts +8 -1
  89. package/dist/types/core/error-hooks.d.ts +71 -0
  90. package/dist/types/core/error.d.ts +9 -0
  91. package/dist/types/core/graph.d.ts +23 -0
  92. package/dist/types/core/heap.d.ts +5 -3
  93. package/dist/types/core/index.d.ts +6 -3
  94. package/dist/types/core/invariants.d.ts +5 -1
  95. package/dist/types/core/lanes.d.ts +51 -19
  96. package/dist/types/core/owner.d.ts +15 -3
  97. package/dist/types/core/scheduler.d.ts +248 -1
  98. package/dist/types/core/types.d.ts +124 -41
  99. package/dist/types/index.d.ts +18 -5
  100. package/dist/types/map.d.ts +2 -0
  101. package/dist/types/signals.d.ts +145 -13
  102. package/dist/types/store/index.d.ts +7 -6
  103. package/dist/types/store/next/optimistic.d.ts +18 -13
  104. package/dist/types/store/next/projection.d.ts +5 -2
  105. package/dist/types/store/next/reconcile.d.ts +7 -0
  106. package/dist/types/store/next/store.d.ts +83 -11
  107. package/dist/types/store/next/target.d.ts +108 -11
  108. package/dist/types/store/store.d.ts +20 -11
  109. package/dist/types/store/utils.d.ts +188 -0
  110. package/package.json +31 -26
  111. package/dist/node.cjs +0 -8137
  112. package/dist/types/store/optimistic.d.ts +0 -45
  113. package/dist/types/store/projection.d.ts +0 -70
  114. package/dist/types/store/reconcile.d.ts +0 -46
  115. package/dist/types-cjs/affects.d.cts +0 -47
  116. package/dist/types-cjs/boundaries.d.cts +0 -175
  117. package/dist/types-cjs/core/action.d.cts +0 -64
  118. package/dist/types-cjs/core/async.d.cts +0 -21
  119. package/dist/types-cjs/core/constants.d.cts +0 -71
  120. package/dist/types-cjs/core/core.d.cts +0 -156
  121. package/dist/types-cjs/core/dev.d.cts +0 -64
  122. package/dist/types-cjs/core/effect.d.cts +0 -30
  123. package/dist/types-cjs/core/error.d.cts +0 -47
  124. package/dist/types-cjs/core/external.d.cts +0 -15
  125. package/dist/types-cjs/core/graph.d.cts +0 -5
  126. package/dist/types-cjs/core/heap.d.cts +0 -22
  127. package/dist/types-cjs/core/index.d.cts +0 -13
  128. package/dist/types-cjs/core/invariants.d.cts +0 -59
  129. package/dist/types-cjs/core/lanes.d.cts +0 -56
  130. package/dist/types-cjs/core/optimistic.d.cts +0 -6
  131. package/dist/types-cjs/core/owner.d.cts +0 -124
  132. package/dist/types-cjs/core/scheduler.d.cts +0 -172
  133. package/dist/types-cjs/core/types.d.cts +0 -148
  134. package/dist/types-cjs/core/verdict.d.cts +0 -2
  135. package/dist/types-cjs/index.d.cts +0 -10
  136. package/dist/types-cjs/map.d.cts +0 -69
  137. package/dist/types-cjs/package.json +0 -3
  138. package/dist/types-cjs/signals.d.cts +0 -624
  139. package/dist/types-cjs/store/index.d.cts +0 -19
  140. package/dist/types-cjs/store/next/optimistic.d.cts +0 -20
  141. package/dist/types-cjs/store/next/projection.d.cts +0 -24
  142. package/dist/types-cjs/store/next/reconcile.d.cts +0 -3
  143. package/dist/types-cjs/store/next/store.d.cts +0 -71
  144. package/dist/types-cjs/store/next/target.d.cts +0 -99
  145. package/dist/types-cjs/store/optimistic.d.cts +0 -45
  146. package/dist/types-cjs/store/projection.d.cts +0 -70
  147. package/dist/types-cjs/store/reconcile.d.cts +0 -46
  148. package/dist/types-cjs/store/store.d.cts +0 -138
  149. package/dist/types-cjs/store/storePath.d.cts +0 -58
  150. 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 { Queue, type Computed, type Effect } from "./core/index.js";
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
- _onFn: (() => any) | undefined;
47
- _prevOn: any;
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` — accessor whose value scopes the boundary; when set,
63
- * transitions caused by writes to other reactive sources are *not* caught
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 writes to fresh signals
27
- * between an `await` and the next `yield` escape the transaction and commit
28
- * immediately. `await` is still the ergonomic choice for typed results; just
29
- * put a bare `yield` before any writes that follow it:
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;