@flotrace/runtime-core 2.2.4 → 2.3.0

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/index.d.ts CHANGED
@@ -1,8 +1,185 @@
1
+ /**
2
+ * Shared utilities for the @flotrace/runtime-core JSX runtime entries.
3
+ *
4
+ * The JSX runtime (jsx-dev-runtime.ts) writes the FLOTRACE_SOURCE symbol onto
5
+ * a JSX element's props at creation time. The fiber walker reads the same
6
+ * symbol back from `fiber.memoizedProps` during tree walking. Centralising
7
+ * the symbol identity + helpers here means there's exactly one place to look
8
+ * for "what shape is fiber.memoizedProps[FLOTRACE_SOURCE]".
9
+ *
10
+ * Per PRD-JSX-RUNTIME.md §8 + IMPLEMENTATION-PLAN-JSX-RUNTIME.md Phase 1.
11
+ */
12
+ /**
13
+ * Global symbol so the same identity is reachable from any module — including
14
+ * dynamically-loaded chunks and multiple bundled copies of runtime-core that
15
+ * may end up linked into the same app (workspace + npm registry mix). The
16
+ * `Symbol.for()` registry guarantees one global slot.
17
+ */
18
+ declare const FLOTRACE_SOURCE: unique symbol;
19
+ /**
20
+ * Adoption sentinel — the dev runtime sets this on first jsxDEV call so the
21
+ * walker (and `runtime:ready` event) can detect that the user opted in via
22
+ * `"jsxImportSource": "@flotrace/runtime-core"`. No per-call telemetry; this
23
+ * is a one-time boolean.
24
+ */
25
+ declare const JSX_RUNTIME_ACTIVE_KEY: unique symbol;
26
+ /**
27
+ * Source attribution attached to a React element's props at JSX-creation time.
28
+ * Stored under the `FLOTRACE_SOURCE` symbol key so it doesn't appear in
29
+ * `Object.keys(props)` or React's unknown-DOM-prop warnings.
30
+ */
31
+ interface FlotraceJsxSource {
32
+ /** Normalized file path (bundler prefixes stripped). */
33
+ fileName: string;
34
+ /** 1-indexed line number. */
35
+ lineNumber: number;
36
+ /** 1-indexed column number. */
37
+ columnNumber: number;
38
+ /** FNV-1a 32-bit hash of `${fileName}:${lineNumber}:${columnNumber}`, 8 hex chars. */
39
+ callSiteId: string;
40
+ /** Map of prop key → inline-literal kind, only present when literals detected. */
41
+ inline?: Record<string, 'fn' | 'obj' | 'arr'>;
42
+ }
43
+ /** Subset of the compiler-supplied `source` argument passed to jsxDEV. */
44
+ interface JsxSourceArg {
45
+ fileName: string;
46
+ lineNumber: number;
47
+ columnNumber: number;
48
+ }
49
+ /**
50
+ * Normalize a bundler-specific file path to a canonical form. Different
51
+ * bundlers emit different path styles for the SAME line of source code:
52
+ *
53
+ * Vite dev → `file:///abs/src/Foo.tsx`
54
+ * Webpack dev → `webpack-internal:///./src/Foo.tsx`
55
+ * esbuild → `./src/Foo.tsx`
56
+ * Next.js Turbopack → `[project]/src/Foo.tsx` (left as-is — no known prefix)
57
+ * Windows → `C:\Users\foo\src\Foo.tsx`
58
+ *
59
+ * Without normalization, the same line of code produces a different
60
+ * `callSiteId` after a bundler swap (or even after switching between Next.js
61
+ * Webpack and Turbopack), breaking per-callsite metrics + HMR-stable watches.
62
+ *
63
+ * Normalization rules (order matters):
64
+ * 1. Strip `file://` prefix.
65
+ * 2. Strip `webpack-internal:///./` prefix.
66
+ * 3. Trim leading `./`.
67
+ * 4. Lowercase Windows drive letters (`C:\` → `c:\`).
68
+ */
69
+ declare function normalizeJsxSourcePath(fileName: string): string;
70
+ /**
71
+ * FNV-1a 32-bit hash → 8-char hex string. Fast, stable, and sufficient for
72
+ * a non-cryptographic per-callsite identity. Operates on the NORMALIZED path
73
+ * so the same source line produces the same hash regardless of bundler.
74
+ *
75
+ * Collision probability across a 5000-callsite app via the birthday paradox
76
+ * on a 32-bit hash space: 1 − e^(−5000²/(2 × 2³²)) ≈ 0.3%. Acceptable for a
77
+ * UI key — a one-in-300 chance of two callsites sharing a row in the Hot
78
+ * Call Sites table is preferable to the wire-format weight of a longer hash.
79
+ * Not suitable as a security token.
80
+ */
81
+ declare function computeCallSiteId(source: JsxSourceArg): string;
82
+ /**
83
+ * Record a render timestamp for a call site. Caller may inject `now` for
84
+ * deterministic tests; production callers use the default `performance.now()`.
85
+ */
86
+ declare function recordCallSiteRender(callSiteId: string, now?: number): void;
87
+ /** Read-only snapshot of recorded timestamps for a call site. */
88
+ declare function getCallSiteRenders(callSiteId: string): readonly number[];
89
+ /**
90
+ * Renders-per-second over the last `windowMs` ms. Walks backwards through the
91
+ * ring buffer; stops at the first entry older than the cutoff (entries are
92
+ * monotonically non-decreasing because the runtime only ever appends).
93
+ *
94
+ * Caller may inject `now` for deterministic tests.
95
+ */
96
+ declare function getCallSiteRenderRate(callSiteId: string, windowMs?: number, now?: number): number;
97
+ /**
98
+ * Clear all ring-buffer state. Called by the walker uninstall path so HMR
99
+ * rapid-reconnect cycles don't accumulate stale entries across sessions.
100
+ */
101
+ declare function clearCallSiteRenders(): void;
102
+ /**
103
+ * Compute a `runtime:callSiteMetrics` payload from the ring buffer — one
104
+ * entry per callsite that has rendered within the last `windowMs` ms (5s
105
+ * default). Callsites with zero recent activity are omitted so the wire-
106
+ * format payload stays small on idle apps.
107
+ *
108
+ * Returns `null` when no callsite has activity → caller skips the WebSocket
109
+ * send entirely. This is load-bearing: a 5000-callsite app with no live
110
+ * renders should NOT emit a 5000-entry map of zeros every second.
111
+ *
112
+ * The `now` arg lets tests inject deterministic timestamps.
113
+ */
114
+ declare function computeCallSiteMetricsPayload(windowMs?: number, now?: number): Record<string, number> | null;
115
+ /**
116
+ * Payload emitted whenever a JSX call site fires twice in the same commit
117
+ * with the same React `key`. Shape mirrors `RuntimeDuplicateKeyMessage` minus
118
+ * the wire-format envelope (`type` + `timestamp`) — those are added by the
119
+ * caller (typically `FloTraceProvider`) at WS-send time.
120
+ */
121
+ interface DuplicateKeyEvent {
122
+ callSiteId: string;
123
+ fileName: string;
124
+ lineNumber: number;
125
+ columnNumber: number;
126
+ duplicateKey: string;
127
+ occurrences: number;
128
+ }
129
+ declare function setDuplicateKeyEmitter(emitter: ((evt: DuplicateKeyEvent) => void) | null): void;
130
+ /**
131
+ * One-time boolean stored on `globalThis` under `JSX_RUNTIME_ACTIVE_KEY`. The
132
+ * dev jsx-runtime sets it on first `jsxDEV` call; the walker reads it to
133
+ * include `jsxRuntimeActive: true` on `runtime:ready` for adoption telemetry.
134
+ *
135
+ * No per-call telemetry — this is a single boolean, set once.
136
+ */
137
+ declare function markJsxRuntimeActive(): void;
138
+ declare function isJsxRuntimeActive(): boolean;
139
+ /**
140
+ * Detect props that look like fresh-each-render literals — the #1 React perf
141
+ * footgun (an inline `onClick={() => ...}` invalidates `memo` + breaks
142
+ * `useEffect` dep arrays). This signal can ONLY be observed at JSX-creation
143
+ * time; after React commits, the prop on the fiber looks identical whether it
144
+ * was a literal or `useCallback`/`useMemo`'d ref.
145
+ *
146
+ * Heuristics (conservative — false-negatives are acceptable; false-positives
147
+ * train users to ignore the warning, so we err toward silence):
148
+ *
149
+ * - **Functions**: only flagged when the fn has no `.name`. `useCallback`'d
150
+ * fns preserve the inner fn's name, named methods are hoisted — the
151
+ * anonymous-arrow case is what catches `{() => doX()}` and `{e => h(e)}`.
152
+ * - **Arrays**: only non-empty arrays. `[]` literals are usually intentional
153
+ * empty defaults and not a perf concern in their own right.
154
+ * - **Plain objects**: detected via prototype check (`Object.prototype` or
155
+ * `null` prototype). React elements (`$$typeof`), class instances, dates,
156
+ * maps, sets — all skipped.
157
+ *
158
+ * Returns `undefined` when nothing is flagged, so callers can use a single
159
+ * truthy check before serialising.
160
+ */
161
+ declare function detectInlineLiterals(props: Record<string, unknown>): Record<string, 'fn' | 'obj' | 'arr'> | undefined;
162
+
1
163
  /**
2
164
  * Types for @flotrace/runtime package
3
165
  * These mirror the shared types from the extension but are standalone
4
166
  * to avoid importing from the extension package.
5
167
  */
168
+
169
+ /**
170
+ * Confidence tier for `LiveTreeNode` source attribution. Drives the
171
+ * OriginBadge variant in the renderer:
172
+ *
173
+ * - `'exact'` — JSX-runtime symbol present OR `_debugSource.fileName`
174
+ * populated (Babel JSX plugin / React 17–18 dev).
175
+ * - `'inferred'` — path resolved via the owner-chain walk or
176
+ * `_debugStack.stack` first-non-react frame (R19+).
177
+ * - `'package'` — fiber classified as framework/library; user clicks won't
178
+ * land in user code anyway.
179
+ * - `'unknown'` — no signal at any tier. Renders an amber `?` pill so the
180
+ * UI is honest about what it doesn't know.
181
+ */
182
+ type SourceConfidence = 'exact' | 'inferred' | 'package' | 'unknown';
6
183
  /**
7
184
  * Serialized value for safe transmission over WebSocket
8
185
  */
@@ -26,7 +203,7 @@ type SerializedValue = null | boolean | number | string | SerializedValue[] | {
26
203
  /**
27
204
  * Messages sent from runtime to extension
28
205
  */
29
- type RuntimeMessage = RuntimeReadyMessage | RuntimeRenderMessage | RuntimePropsUpdateMessage | RuntimeNodePropsMessage | RuntimeZustandUpdateMessage | RuntimeReduxUpdateMessage | RuntimeRouterUpdateMessage | RuntimeContextUpdateMessage | RuntimeDisconnectMessage | RuntimeTreeSnapshotMessage | RuntimeTreeDiffMessage | RuntimeNodeHooksMessage | RuntimeNodeEffectsMessage | RuntimeDetailedRenderReasonMessage | RuntimeTimelineEventMessage | RuntimeTanStackQueryUpdateMessage | RuntimeRenderTriggerMessage | RuntimeRenderCascadeMessage | RuntimePropDrillingMessage | RuntimeActionStateMessage | RuntimeOptimisticDiffMessage | RuntimeNextjsContextMessage | RuntimeRscPayloadMessage | RuntimeHydrationEventMessage | RuntimeNetworkRequestMessage | RuntimeLocalStateCorrelationMessage | RuntimeValueTraceMessage | RuntimePongMessage;
206
+ type RuntimeMessage = RuntimeReadyMessage | RuntimeRenderMessage | RuntimePropsUpdateMessage | RuntimeNodePropsMessage | RuntimeZustandUpdateMessage | RuntimeReduxUpdateMessage | RuntimeRouterUpdateMessage | RuntimeContextUpdateMessage | RuntimeDisconnectMessage | RuntimeTreeSnapshotMessage | RuntimeTreeDiffMessage | RuntimeNodeHooksMessage | RuntimeNodeEffectsMessage | RuntimeDetailedRenderReasonMessage | RuntimeTimelineEventMessage | RuntimeTanStackQueryUpdateMessage | RuntimeRenderTriggerMessage | RuntimeRenderCascadeMessage | RuntimePropDrillingMessage | RuntimeActionStateMessage | RuntimeOptimisticDiffMessage | RuntimeNextjsContextMessage | RuntimeRscPayloadMessage | RuntimeHydrationEventMessage | RuntimeCallSiteMetricsMessage | RuntimeDuplicateKeyMessage | RuntimeNetworkRequestMessage | RuntimeLocalStateCorrelationMessage | RuntimeValueTraceMessage | RuntimePongMessage;
30
207
  interface RuntimeReadyMessage {
31
208
  type: 'runtime:ready';
32
209
  appName?: string;
@@ -55,6 +232,14 @@ interface RuntimeReadyMessage {
55
232
  * release script keeps runtime-core pinned identically, so a separate
56
233
  * core-version field would be redundant. */
57
234
  runtimeVersion?: string;
235
+ /**
236
+ * Milestone 8 Phase 5 — adoption signal for the JSX-runtime opt-in
237
+ * (`"jsxImportSource": "@flotrace/runtime-core"`). `true` when the dev
238
+ * runtime's global sentinel has been set (i.e. at least one user
239
+ * component went through `jsxDEV`). Desktop forwards to telemetry so
240
+ * the admin dashboard can track rollout rate. No PII; one-time boolean.
241
+ */
242
+ jsxRuntimeActive?: boolean;
58
243
  }
59
244
  interface RuntimeRenderMessage {
60
245
  type: 'runtime:render';
@@ -226,6 +411,22 @@ interface LiveTreeNode {
226
411
  isLibrary?: boolean;
227
412
  /** Short display label for the library source (e.g. 'framer', 'fontawesome', 'sonner') */
228
413
  libraryName?: string;
414
+ /**
415
+ * Source attribution captured at JSX-creation time by the optional
416
+ * `@flotrace/runtime-core/jsx-dev-runtime` opt-in. Present only when the
417
+ * user has set `"jsxImportSource": "@flotrace/runtime-core"` in their
418
+ * tsconfig.json — the highest-confidence source signal available.
419
+ *
420
+ * When present, `filePath` / `lineNumber` are filled from `jsxSource` so
421
+ * existing consumers (click-to-IDE, breadcrumb path display) keep working
422
+ * without changes.
423
+ */
424
+ jsxSource?: FlotraceJsxSource;
425
+ /**
426
+ * Confidence tier of the resolved source. See `SourceConfidence` doc-comment
427
+ * for the four tiers and what each means for the UI.
428
+ */
429
+ sourceConfidence?: SourceConfidence;
229
430
  }
230
431
  /**
231
432
  * Enhanced render reason with specific prop/state/context changes.
@@ -460,6 +661,8 @@ interface CascadeNode {
460
661
  children: CascadeNode[];
461
662
  depth: number;
462
663
  isMemoized: boolean;
664
+ /** JSX-runtime attribution (Milestone 8 Phase 6) — mirror of shared LiveTreeNode field. */
665
+ jsxSource?: FlotraceJsxSource;
463
666
  }
464
667
  type LanePriority = 'sync' | 'discrete' | 'continuous' | 'default' | 'transition' | 'deferred' | 'idle' | 'offscreen';
465
668
  interface LaneInfo {
@@ -494,6 +697,8 @@ interface PropDrillingChainNode {
494
697
  role: 'source' | 'passthrough' | 'consumer';
495
698
  hookCount: number;
496
699
  hasContextHook: boolean;
700
+ /** JSX-runtime attribution (Milestone 8 Phase 6). */
701
+ jsxSource?: FlotraceJsxSource;
497
702
  }
498
703
  interface PropDrillingChain {
499
704
  chainId: string;
@@ -521,21 +726,27 @@ interface RuntimePropDrillingMessage {
521
726
  treeSize: number;
522
727
  };
523
728
  }
729
+ /**
730
+ * State of a single useActionState / useOptimistic hook instance on a fiber.
731
+ * Mirror of `ActionStateEntry` in flotrace-desktop's `shared/liveMessages.ts`
732
+ * — keep the field set in sync.
733
+ */
734
+ interface ActionStateEntry {
735
+ hookIndex: number;
736
+ hookKind: 'action' | 'optimistic';
737
+ isPending: boolean;
738
+ state: SerializedValue;
739
+ error?: SerializedValue;
740
+ pendingSince?: number;
741
+ durationMs?: number;
742
+ }
524
743
  /** Sent whenever a useActionState or useOptimistic hook changes on any fiber */
525
744
  interface RuntimeActionStateMessage {
526
745
  type: 'runtime:actionState';
527
746
  nodeId: string;
528
747
  componentName: string;
529
748
  /** One entry per useActionState / useOptimistic hook on this fiber */
530
- actions: Array<{
531
- hookIndex: number;
532
- hookKind: 'action' | 'optimistic';
533
- isPending: boolean;
534
- state: SerializedValue;
535
- error?: SerializedValue;
536
- pendingSince?: number;
537
- durationMs?: number;
538
- }>;
749
+ actions: ActionStateEntry[];
539
750
  timestamp: number;
540
751
  }
541
752
  /** Sent when a useOptimistic value diverges from its underlying actual value */
@@ -557,12 +768,17 @@ interface RuntimeNextjsContextMessage {
557
768
  initialRoute?: string;
558
769
  timestamp: number;
559
770
  }
771
+ /**
772
+ * RSC / Next.js cache header status. Mirror of the union in
773
+ * `shared/liveMessages.ts`'s `RscPayloadEntry.cacheStatus` — keep in sync.
774
+ */
775
+ type RscCacheStatus = 'HIT' | 'MISS' | 'STALE' | 'unknown';
560
776
  /** Sent when an RSC / Next.js data fetch is intercepted (metadata only, no values) */
561
777
  interface RuntimeRscPayloadMessage {
562
778
  type: 'runtime:rscPayload';
563
779
  route: string;
564
780
  payloadSizeBytes: number;
565
- cacheStatus: 'HIT' | 'MISS' | 'STALE' | 'unknown';
781
+ cacheStatus: RscCacheStatus;
566
782
  timestamp: number;
567
783
  }
568
784
  /** Sent when React hydration completes or a mismatch is detected */
@@ -573,6 +789,48 @@ interface RuntimeHydrationEventMessage {
573
789
  errorMessage?: string;
574
790
  timestamp: number;
575
791
  }
792
+ /**
793
+ * Per-callsite render frequency snapshot. Emitted at most once per second by
794
+ * the runtime when the JSX-runtime opt-in is active — the ring buffer in
795
+ * `jsxRuntimeUtils.ts` is the source of truth, this message is a periodic
796
+ * compaction of the buffer into "renders/sec over last 5s" so the desktop
797
+ * doesn't need to mirror the buffer.
798
+ *
799
+ * Independent of the React Profiler — works in concurrent rendering where the
800
+ * Profiler may miss commits. Only emitted when there's at least one callsite
801
+ * with non-zero recent activity (no metric-flood on idle apps).
802
+ */
803
+ interface RuntimeCallSiteMetricsMessage {
804
+ type: 'runtime:callSiteMetrics';
805
+ /** Map of callSiteId → renders/sec over the last 5-second window. */
806
+ metrics: Record<string, number>;
807
+ timestamp: number;
808
+ }
809
+ /**
810
+ * Duplicate-key warning. Emitted by the JSX runtime when it observes the same
811
+ * `(callSiteId, key)` pair on two or more JSX calls within a single commit —
812
+ * the classic `{items.map(item => <Row key={item.id} />)}` pattern where
813
+ * `item.id` repeats. React logs a console warning for this; we surface it
814
+ * with full file:line attribution so the user can navigate directly to the
815
+ * map call site.
816
+ *
817
+ * One message per (callSiteId, duplicateKey) per emission window — the
818
+ * runtime de-duplicates so a list with 100 duplicate rows doesn't spam 100
819
+ * messages.
820
+ */
821
+ interface RuntimeDuplicateKeyMessage {
822
+ type: 'runtime:duplicateKey';
823
+ /** The JSX call site that produced the duplicates. */
824
+ callSiteId: string;
825
+ fileName: string;
826
+ lineNumber: number;
827
+ columnNumber: number;
828
+ /** The key value that appeared more than once. */
829
+ duplicateKey: string;
830
+ /** How many times the same key fired at this call site in the commit. */
831
+ occurrences: number;
832
+ timestamp: number;
833
+ }
576
834
  /** Metadata for a single intercepted network request. Privacy-first: no bodies, no query params, no auth headers. */
577
835
  interface NetworkRequestEntry {
578
836
  /** Incrementing request ID */
@@ -646,6 +904,13 @@ type TraceStep = {
646
904
  /** If this step came via a rename edge in the drilling graph. */
647
905
  renamedFrom?: string;
648
906
  confidence: TraceConfidence;
907
+ /**
908
+ * JSX-runtime attribution of the PARENT fiber that wrote the value into
909
+ * this prop (Milestone 8 Phase 6). Captured by `readJsxSourceFromFiber`
910
+ * on the ancestor at trace-resolution time. Undefined when the parent
911
+ * fiber lacks attribution.
912
+ */
913
+ callSiteOfParentJsx?: FlotraceJsxSource;
649
914
  } | {
650
915
  kind: 'hook-state';
651
916
  nodeId: string;
@@ -1181,7 +1446,7 @@ declare function uninstallFiberTreeWalker(): void;
1181
1446
  *
1182
1447
  * Works across React 18 and 19 by probing different internal property names.
1183
1448
  */
1184
- interface FiberLike {
1449
+ interface FiberLike$1 {
1185
1450
  type: {
1186
1451
  name?: string;
1187
1452
  displayName?: string;
@@ -1194,7 +1459,7 @@ interface FiberLike {
1194
1459
  displayName?: string;
1195
1460
  };
1196
1461
  } | ((...args: unknown[]) => unknown) | string | null;
1197
- return: FiberLike | null;
1462
+ return: FiberLike$1 | null;
1198
1463
  tag: number;
1199
1464
  }
1200
1465
  /**
@@ -1204,16 +1469,16 @@ interface FiberLike {
1204
1469
  * Strategy 2 (React 19): __CLIENT_INTERNALS...owner field (renamed + flattened)
1205
1470
  * Both return the fiber currently being rendered (null between renders).
1206
1471
  */
1207
- declare function getCurrentRenderingFiber(): FiberLike | null;
1472
+ declare function getCurrentRenderingFiber(): FiberLike$1 | null;
1208
1473
  /**
1209
1474
  * Extract display name from a fiber node.
1210
1475
  */
1211
- declare function getComponentNameFromFiber(fiber: FiberLike): string | null;
1476
+ declare function getComponentNameFromFiber(fiber: FiberLike$1): string | null;
1212
1477
  /**
1213
1478
  * Walk up the fiber tree to build an ancestor chain of component names.
1214
1479
  * Stops after 10 levels to prevent excessive traversal.
1215
1480
  */
1216
- declare function buildAncestorChain(fiber: FiberLike): string[];
1481
+ declare function buildAncestorChain(fiber: FiberLike$1): string[];
1217
1482
 
1218
1483
  /**
1219
1484
  * Hook Inspector for @flotrace/runtime
@@ -1714,4 +1979,99 @@ declare function installRscPayloadInterceptor(client: FloTraceWebSocketClient):
1714
1979
  /** Remove the RSC payload interceptor and restore original fetch */
1715
1980
  declare function uninstallRscPayloadInterceptor(): void;
1716
1981
 
1717
- export { DEFAULT_CONFIG, type DetailedRenderReason, type DetailedRenderReasonType, type EffectInfo, type Fiber$1 as Fiber, type FiberEffect, type FiberHookState, type FiberTreeWalkerOptions, type FloTraceConfig, FloTraceWebSocketClient, type FrameworkInfo, type HookInfo, type HookType, type LiveTreeNode, type MutationCorrelation, type NetworkRequestEntry, type PropChange, type ReduxStoreApi, type ResolvedFloTraceConfig, type RuntimeTreeDiffMessage, type RuntimeValueTraceMessage, type SerializedValue, type TanStackMutationInfo, type TanStackQueryClientApi, type TanStackQueryEvent, type TanStackQueryInfo, type TimelineEvent, type TimelineEventType, type TraceConfidence, type TraceStep, type TrackingOptions, type ValueTrace, type ValueTraceInput, type ZustandStoreApi, buildAncestorChain, clearFetchOriginTags, detectServerComponent, detectWebFramework, disposeWebSocketClient, findFetchOrigin, getChangedKeys, getComponentNameFromFiber, getCurrentRenderingFiber, getDetailedRenderReason, getFiberRefMap, getNodeEffects, getNodeHooks, getNodeProps, getReduxSnapshot, getTanstackSnapshot, getTimeline, getWebSocketClient, getZustandSnapshot, hasActiveTags, inspectEffects, inspectHooks, installFiberTreeWalker, installReduxTracker, installRscPayloadInterceptor, installTanStackQueryTracker, installTimelineTracker, installZustandTracker, isReduxStore, isTanStackQueryClient, maybeEmitNextjsContext, recordTimelineEvent, requestFullSnapshot, requestTreeSnapshot, resetNextjsDetection, resolveValueTrace, serializeProps, serializeValue, tagFetchData, uninstallFiberTreeWalker, uninstallReduxTracker, uninstallRscPayloadInterceptor, uninstallTanStackQueryTracker, uninstallTimelineTracker, uninstallZustandTracker };
1982
+ /**
1983
+ * Fiber debug recorder — buffers fiber + LiveTreeNode observations into
1984
+ * capped in-memory tables, then dumps them to the console *on demand*.
1985
+ *
1986
+ * Why not log eagerly? `getComponentName` runs once per fiber per commit.
1987
+ * A 200-node tree at 60Hz produces ~12k console entries/sec, which OOMs
1988
+ * DevTools. The recorder keeps recording silent until you ask for a dump.
1989
+ *
1990
+ * Usage (from any console — Next.js app, FloTrace renderer, Electron main):
1991
+ * globalThis.__FT_DEBUG = true // start recording
1992
+ * __ft.dump() // print digest (fibers + snapshots)
1993
+ * __ft.fibers() // just the fiber-name table
1994
+ * __ft.snapshots() // just the snapshot timeline
1995
+ * __ft.tail(20) // recent activity
1996
+ * __ft.clear() // reset buffers
1997
+ * __ft.export() // returns a JSON object
1998
+ * __ft.download() // browser-only: save buffers as JSON
1999
+ * __ft.size() // current buffer sizes
2000
+ *
2001
+ * All recorders are no-ops when __FT_DEBUG is falsy, so the wired call
2002
+ * sites cost ~1 boolean check each.
2003
+ */
2004
+
2005
+ interface FiberRecord {
2006
+ /** Resolved component name (what FloTrace ultimately shows on the node). */
2007
+ name: string;
2008
+ /** Raw `fiber.type.name` — present even for ForwardRef/Memo's inner render. */
2009
+ rawName: string | undefined;
2010
+ /** Raw `fiber.type.displayName` — what the author explicitly set. */
2011
+ rawDisplayName: string | undefined;
2012
+ kind: 'function' | 'class' | 'forwardRef' | 'memo' | 'host' | 'unknown';
2013
+ /** Fiber tag number (0=Function, 1=Class, 11=ForwardRef, 14=Memo, etc.). */
2014
+ fiberTag: number | undefined;
2015
+ looksMinified: boolean;
2016
+ count: number;
2017
+ contexts: Set<string>;
2018
+ firstSeen: number;
2019
+ lastSeen: number;
2020
+ /** First captured _debugSource (if any) — only available in dev builds. */
2021
+ source?: {
2022
+ fileName?: string;
2023
+ lineNumber?: number;
2024
+ };
2025
+ /** First non-null react key observed (useful for diagnosing list rows). */
2026
+ exampleKey?: string;
2027
+ }
2028
+ interface TreeRecord {
2029
+ ts: number;
2030
+ ctx: string;
2031
+ rootName: string;
2032
+ totalNodes: number;
2033
+ maxDepth: number;
2034
+ minifiedLike: number;
2035
+ topNames: string;
2036
+ }
2037
+ declare global {
2038
+ var __FT_DEBUG: boolean | undefined;
2039
+ var __ft: FtConsoleApi | undefined;
2040
+ }
2041
+ declare function setFiberDebug(enabled: boolean): void;
2042
+ type FiberLike = {
2043
+ tag?: number;
2044
+ type?: unknown;
2045
+ key?: string | null;
2046
+ _debugSource?: {
2047
+ fileName?: string;
2048
+ lineNumber?: number;
2049
+ } | null;
2050
+ };
2051
+ declare function describeFiberType(fiber: FiberLike): {
2052
+ kind: FiberRecord['kind'];
2053
+ name: string | undefined;
2054
+ displayName: string | undefined;
2055
+ resolved: string;
2056
+ looksMinified: boolean;
2057
+ };
2058
+ declare function logTreeSnapshot(tree: LiveTreeNode | null, context?: string): void;
2059
+ declare const logTreeSummary: typeof logTreeSnapshot;
2060
+ interface FtConsoleApi {
2061
+ dump(): void;
2062
+ fibers(): void;
2063
+ snapshots(): void;
2064
+ tail(n?: number): void;
2065
+ clear(): void;
2066
+ size(): {
2067
+ fibers: number;
2068
+ snapshots: number;
2069
+ };
2070
+ export(): {
2071
+ fibers: Array<Record<string, unknown>>;
2072
+ snapshots: TreeRecord[];
2073
+ };
2074
+ download(filename?: string): void;
2075
+ }
2076
+
2077
+ export { type ActionStateEntry, DEFAULT_CONFIG, type DetailedRenderReason, type DetailedRenderReasonType, type DuplicateKeyEvent, type EffectInfo, FLOTRACE_SOURCE, type Fiber$1 as Fiber, type FiberEffect, type FiberHookState, type FiberTreeWalkerOptions, type FloTraceConfig, FloTraceWebSocketClient, type FlotraceJsxSource, type FrameworkInfo, type HookInfo, type HookType, JSX_RUNTIME_ACTIVE_KEY, type LiveTreeNode, type MutationCorrelation, type NetworkRequestEntry, type PropChange, type ReduxStoreApi, type ResolvedFloTraceConfig, type RscCacheStatus, type RuntimeActionStateMessage, type RuntimeCallSiteMetricsMessage, type RuntimeDuplicateKeyMessage, type RuntimeHydrationEventMessage, type RuntimeNextjsContextMessage, type RuntimeOptimisticDiffMessage, type RuntimeRscPayloadMessage, type RuntimeTreeDiffMessage, type RuntimeValueTraceMessage, type SerializedValue, type SourceConfidence, type TanStackMutationInfo, type TanStackQueryClientApi, type TanStackQueryEvent, type TanStackQueryInfo, type TimelineEvent, type TimelineEventType, type TraceConfidence, type TraceStep, type TrackingOptions, type ValueTrace, type ValueTraceInput, type ZustandStoreApi, buildAncestorChain, clearCallSiteRenders, clearFetchOriginTags, computeCallSiteId, computeCallSiteMetricsPayload, describeFiberType, detectInlineLiterals, detectServerComponent, detectWebFramework, disposeWebSocketClient, findFetchOrigin, getCallSiteRenderRate, getCallSiteRenders, getChangedKeys, getComponentNameFromFiber, getCurrentRenderingFiber, getDetailedRenderReason, getFiberRefMap, getNodeEffects, getNodeHooks, getNodeProps, getReduxSnapshot, getTanstackSnapshot, getTimeline, getWebSocketClient, getZustandSnapshot, hasActiveTags, inspectEffects, inspectHooks, installFiberTreeWalker, installReduxTracker, installRscPayloadInterceptor, installTanStackQueryTracker, installTimelineTracker, installZustandTracker, isJsxRuntimeActive, isReduxStore, isTanStackQueryClient, logTreeSnapshot, logTreeSummary, markJsxRuntimeActive, maybeEmitNextjsContext, normalizeJsxSourcePath, recordCallSiteRender, recordTimelineEvent, requestFullSnapshot, requestTreeSnapshot, resetNextjsDetection, resolveValueTrace, serializeProps, serializeValue, setDuplicateKeyEmitter, setFiberDebug, tagFetchData, uninstallFiberTreeWalker, uninstallReduxTracker, uninstallRscPayloadInterceptor, uninstallTanStackQueryTracker, uninstallTimelineTracker, uninstallZustandTracker };