@flotrace/runtime 2.2.1 → 2.2.3

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Sameer Sitre
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,106 +1,95 @@
1
1
  # @flotrace/runtime
2
2
 
3
- Runtime package for FloTrace enables real-time React component tree visualization, render tracking, state management monitoring, and network health analysis in the FloTrace desktop app.
3
+ **Stop guessing why your React app re-renders.**
4
4
 
5
- > **Using React Native?** Install [`@flotrace/runtime-native`](https://www.npmjs.com/package/@flotrace/runtime-native) instead. It's the dedicated adapter for iOS / Android`@flotrace/runtime` patches `fetch`, `XMLHttpRequest`, `JSON.parse`, and `Response.prototype.json` in ways that crash the React Native JS bridge. See the [migration guide](../../docs/migration-runtime-native.md) if you're switching a shared codebase.
5
+ FloTrace is a desktop app that shows you, live, what your React tree is doingevery render, every prop change, every state mutation, every cascade without leaving your editor and without uploading your source code anywhere.
6
6
 
7
- ## Installation
7
+ This package is the runtime that wires your app into the desktop. Drop it in once and you get:
8
8
 
9
- ```bash
10
- npm install -D @flotrace/runtime
11
- # or
12
- yarn add -D @flotrace/runtime
13
- # or
14
- pnpm add -D @flotrace/runtime
15
- ```
9
+ - **A live component tree graph** — not a flat fiber list. See parent/child structure as it changes in real time.
10
+ - **Render reasons that actually answer "why?"** — props/state/context diffs, render frequency coloring, render-cascade tracing across files.
11
+ - **All your state in one panel** — Zustand, Redux, TanStack Query, Context, Router. No four browser extensions, no console.log.
12
+ - **Hooks + effects, classified and diffed** — 14 hook types, effect dep diffing, "did this effect re-run because X changed."
13
+ - **Network → state correlation** — every fetch/XHR mapped to the store update it caused.
14
+ - **Copy-as-Prompt** — turn any panel into an AI-ready prompt for Cursor/Claude/ChatGPT in one click.
16
15
 
17
- **Peer dependencies:** React >= 16.9.0 (requires `<Profiler>` API)
16
+ Source code never leaves your machine. The runtime sends only metadata over `ws://localhost:3457` to the desktop app.
18
17
 
19
- ## Quick Start
18
+ > **Using React Native?** Install [`@flotrace/runtime-native`](https://www.npmjs.com/package/@flotrace/runtime-native) instead. This package patches `fetch`/`XMLHttpRequest` in ways that crash the RN bridge.
20
19
 
21
- Wrap your app with `<FloTraceProvider>`:
20
+ [**Download the desktop app →**](https://flotrace.dev/download) · [Docs](https://flotrace.dev/docs) · [Compare to React DevTools](https://flotrace.dev/compare/react-devtools)
22
21
 
23
- ```tsx
24
- import { FloTraceProvider } from '@flotrace/runtime';
25
- import { createRoot } from 'react-dom/client';
26
- import App from './App';
22
+ ---
27
23
 
28
- createRoot(document.getElementById('root')!).render(
29
- <FloTraceProvider config={{ appName: 'My App' }}>
30
- <App />
31
- </FloTraceProvider>
32
- );
33
- ```
24
+ ## About FloTrace Desktop
34
25
 
35
- Then launch the FloTrace desktop app your component tree will appear automatically.
26
+ [**FloTrace Desktop**](https://flotrace.dev) is a free Electron app (macOS / Windows / Linux) that visualizes your React app's component hierarchy in real time. This runtime package is the bridge: drop `<FloTraceProvider>` into your app and the desktop renders the live tree, with full inspection of props, hooks, effects, state, network calls, and render cascades.
36
27
 
37
- ## Configuration
28
+ When `@flotrace/runtime` (this package) is paired with the desktop, you get:
38
29
 
39
- All config options are optional. Pass them via the `config` prop:
30
+ - **Live component tree** React Flow graph, render-flash animation, frequency-based heatmap, breadcrumb bar, search-with-fitView.
31
+ - **Per-node inspection** — props (with diff history), hooks (14 classified types + dep diffs), effects (willRun + dep diffs), component timeline.
32
+ - **State tracking** — Zustand (per-store), Redux (with change highlighting), Router, TanStack Query (with health warnings + wasted-refetch detection), Context.
33
+ - **Render cascade tracing** — trigger log, cascade tree, flame chart, cascade compare modal.
34
+ - **Prop drilling detection** — chain detection (≥3 levels deep), severity badges, heatmap overlay, refactor recommendations.
35
+ - **Network health** — fetch / XHR tracking, method badges, status dots, duplicate detection, API → store causal correlation, pin-to-watch.
36
+ - **React 19 + Next.js** — Actions monitor, concurrent-update signals (useTransition / Suspense), compiler memo health, Next.js App Router detection, RSC payload interception.
37
+ - **Watch expressions** — pin values from 8 sources (Zustand / Redux / Router / Context / Props / Hooks / TanStack Query / API), max 20.
38
+ - **AI Code Review Dashboard** — 6-tab review (Re-renders, Memo, Drilling, Effects, Compiler, Network) with Lighthouse-style scores.
39
+ - **Copy-as-Prompt** — turn any panel into an AI-ready prompt for Cursor / Claude / ChatGPT in one click.
40
40
 
41
- ```tsx
42
- <FloTraceProvider config={{ port: 3457, appName: 'My App' }}>
41
+ How it fits together:
42
+
43
+ ```
44
+ your React app ←→ @flotrace/runtime ←→ ws://localhost:3457 ←→ FloTrace Desktop
45
+ (this package — open source, MIT) (closed-source commercial)
43
46
  ```
44
47
 
45
- | Option | Type | Default | Description |
46
- |--------|------|---------|-------------|
47
- | `port` | `number` | `3457` | WebSocket server port |
48
- | `appName` | `string` | `'React App'` | App name displayed in FloTrace |
49
- | `enabled` | `boolean` | `true` in dev | Enable/disable tracking |
50
- | `autoReconnect` | `boolean` | `true` | Auto-reconnect on disconnect |
51
- | `reconnectInterval` | `number` | `2000` | Reconnect interval (ms) |
52
- | `trackAllRenders` | `boolean` | `true` | Track all component renders |
53
- | `includeProps` | `boolean` | `true` | Include props in render events |
54
- | `trackZustand` | `boolean` | `true` | Enable Zustand state tracking |
55
- | `trackRedux` | `boolean` | `true` | Enable Redux state tracking |
56
- | `trackRouter` | `boolean` | `true` | Enable URL navigation tracking |
57
- | `trackContext` | `boolean` | `true` | Enable React Context tracking |
58
- | `trackTanstackQuery` | `boolean` | `true` | Enable TanStack Query tracking |
59
-
60
- ## Framework Setup
61
-
62
- ### Vite + React
48
+ The desktop is free and binds to `127.0.0.1` only by default — your source code, props, and state never leave your machine.
49
+
50
+ ---
51
+
52
+ ## 30-second setup
53
+
54
+ ```bash
55
+ npm install -D @flotrace/runtime
56
+ ```
63
57
 
64
58
  ```tsx
65
- // src/main.tsx
66
59
  import { FloTraceProvider } from '@flotrace/runtime';
67
60
  import { createRoot } from 'react-dom/client';
68
61
  import App from './App';
69
62
 
70
63
  createRoot(document.getElementById('root')!).render(
71
- <FloTraceProvider config={{ appName: 'My Vite App' }}>
64
+ <FloTraceProvider config={{ appName: 'My App' }}>
72
65
  <App />
73
66
  </FloTraceProvider>
74
67
  );
75
68
  ```
76
69
 
70
+ Launch the FloTrace desktop app. Reload your dev server. Done — your tree appears.
71
+
72
+ **Peer dependencies:** React >= 16.9.0 (uses `<Profiler>` API). Auto-disables in production via `process.env.NODE_ENV`.
73
+
74
+ ---
75
+
76
+ ## Framework recipes
77
+
77
78
  ### Next.js (App Router)
78
79
 
79
80
  ```tsx
80
81
  // app/providers.tsx
81
82
  'use client';
82
-
83
83
  import { FloTraceProvider } from '@flotrace/runtime';
84
84
 
85
85
  export function Providers({ children }: { children: React.ReactNode }) {
86
- return (
87
- <FloTraceProvider config={{ appName: 'My Next.js App' }}>
88
- {children}
89
- </FloTraceProvider>
90
- );
86
+ return <FloTraceProvider config={{ appName: 'My Next.js App' }}>{children}</FloTraceProvider>;
91
87
  }
92
88
 
93
89
  // app/layout.tsx
94
90
  import { Providers } from './providers';
95
-
96
91
  export default function RootLayout({ children }: { children: React.ReactNode }) {
97
- return (
98
- <html>
99
- <body>
100
- <Providers>{children}</Providers>
101
- </body>
102
- </html>
103
- );
92
+ return <html><body><Providers>{children}</Providers></body></html>;
104
93
  }
105
94
  ```
106
95
 
@@ -120,272 +109,123 @@ export default function App({ Component, pageProps }: AppProps) {
120
109
  }
121
110
  ```
122
111
 
123
- ### Create React App
112
+ ### Vite / Create React App
124
113
 
125
- ```tsx
126
- // src/index.tsx
127
- import { FloTraceProvider } from '@flotrace/runtime';
128
- import { createRoot } from 'react-dom/client';
129
- import App from './App';
114
+ Same as the 30-second setup above — wrap `<App />` at the root.
130
115
 
131
- createRoot(document.getElementById('root')!).render(
132
- <FloTraceProvider config={{ appName: 'My CRA App' }}>
133
- <App />
134
- </FloTraceProvider>
135
- );
136
- ```
137
-
138
- ## State Management Integration
116
+ ---
139
117
 
140
- ### Zustand
118
+ ## Wire up your state stores
141
119
 
142
- Pass Zustand stores via the `stores` prop. Keys become store names in FloTrace:
120
+ State tracking is the killer feature. Pass your stores to the provider and they show up in the desktop's State panel with live diffs:
143
121
 
144
122
  ```tsx
145
123
  import { FloTraceProvider } from '@flotrace/runtime';
146
- import { useBearStore } from './store/bearStore';
147
- import { useUserStore } from './store/userStore';
124
+ import { useBearStore } from './zustandStore';
125
+ import { store as reduxStore } from './reduxStore';
126
+ import { queryClient } from './queryClient';
148
127
 
149
128
  <FloTraceProvider
150
- stores={{ bearStore: useBearStore, userStore: useUserStore }}
151
129
  config={{ appName: 'My App' }}
130
+ stores={{ bearStore: useBearStore }} // Zustand — keys become store names
131
+ reduxStore={reduxStore} // Redux — pass your store directly
132
+ queryClient={queryClient} // TanStack Query — pass your client
152
133
  >
153
134
  <App />
154
135
  </FloTraceProvider>
155
136
  ```
156
137
 
157
- ### Redux
158
-
159
- Pass your Redux store via the `reduxStore` prop:
138
+ Router tracking is automatic — it patches the History API and works with React Router, TanStack Router, Next.js, etc.
160
139
 
161
- ```tsx
162
- import { FloTraceProvider } from '@flotrace/runtime';
163
- import { store } from './store';
140
+ ---
164
141
 
165
- <FloTraceProvider
166
- reduxStore={store}
167
- config={{ appName: 'My App' }}
168
- >
169
- <App />
170
- </FloTraceProvider>
171
- ```
142
+ ## Configuration
172
143
 
173
- ### TanStack Query
144
+ All options optional. Sensible defaults for development.
174
145
 
175
- Pass your TanStack Query client via the `queryClient` prop:
146
+ | Option | Type | Default | Description |
147
+ |--------|------|---------|-------------|
148
+ | `appName` | `string` | `'React App'` | Shown in the FloTrace connection pill |
149
+ | `port` | `number` | `3457` | WebSocket server port |
150
+ | `enabled` | `boolean` | dev only | `false` to hard-disable |
151
+ | `autoReconnect` | `boolean` | `true` | Reconnect on disconnect |
152
+ | `reconnectInterval` | `number` | `2000` | Base reconnect delay (ms, exponential backoff) |
153
+ | `trackAllRenders` | `boolean` | `true` | Track every commit via `<Profiler>` |
154
+ | `includeProps` | `boolean` | `true` | Include prop values in render events |
155
+ | `trackZustand` / `trackRedux` / `trackRouter` / `trackContext` / `trackTanstackQuery` | `boolean` | `true` | Per-tracker toggles |
176
156
 
177
- ```tsx
178
- import { FloTraceProvider } from '@flotrace/runtime';
179
- import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
157
+ ---
180
158
 
181
- const queryClient = new QueryClient();
159
+ ## Production safety
182
160
 
183
- <QueryClientProvider client={queryClient}>
184
- <FloTraceProvider
185
- queryClient={queryClient}
186
- config={{ appName: 'My App' }}
187
- >
188
- <App />
189
- </FloTraceProvider>
190
- </QueryClientProvider>
191
- ```
192
-
193
- ### Combined (Zustand + Redux + TanStack Query + Router)
161
+ FloTrace is **disabled in production** by default (`enabled` defaults to `process.env.NODE_ENV === 'development'`). For belt-and-braces tree-shaking, dynamic-import in dev only:
194
162
 
195
163
  ```tsx
196
- import { FloTraceProvider } from '@flotrace/runtime';
197
- import { store } from './reduxStore';
198
- import { useBearStore } from './zustandStore';
199
- import { queryClient } from './queryClient';
200
-
201
- <FloTraceProvider
202
- config={{ appName: 'My App' }}
203
- stores={{ bearStore: useBearStore }}
204
- reduxStore={store}
205
- queryClient={queryClient}
206
- >
207
- <App />
208
- </FloTraceProvider>
164
+ const FloTraceProvider = process.env.NODE_ENV === 'development'
165
+ ? (await import('@flotrace/runtime')).FloTraceProvider
166
+ : ({ children }: { children: React.ReactNode }) => <>{children}</>;
209
167
  ```
210
168
 
211
- Router tracking is automatic — no configuration needed. It works with any SPA router (React Router, TanStack Router, Next.js, etc.) by patching the browser's History API.
212
-
213
- ## Advanced Usage
169
+ ---
214
170
 
215
- ### `withFloTrace()` — HOC for targeted profiling
171
+ ## Targeted profiling
216
172
 
217
- Wrap specific components to track their renders and props individually:
173
+ For one-off component tracking without the full provider:
218
174
 
219
175
  ```tsx
220
- import { withFloTrace } from '@flotrace/runtime';
221
-
222
- const ProfiledComponent = withFloTrace(MyComponent, 'MyComponent');
223
- ```
176
+ import { withFloTrace, useTrackProps } from '@flotrace/runtime';
224
177
 
225
- ### `useTrackProps()` Track prop changes
226
-
227
- Call at the top of a component to track its prop changes:
228
-
229
- ```tsx
230
- import { useTrackProps } from '@flotrace/runtime';
178
+ const Profiled = withFloTrace(MyComponent, 'MyComponent');
231
179
 
232
180
  function MyComponent(props: MyProps) {
233
181
  useTrackProps('MyComponent', props);
234
- // ... rest of component
182
+ // ...
235
183
  }
236
184
  ```
237
185
 
238
- ### `useFloTrace()` — Access runtime context
186
+ ---
239
187
 
240
- ```tsx
241
- import { useFloTrace } from '@flotrace/runtime';
242
-
243
- function DebugInfo() {
244
- const floTrace = useFloTrace();
245
- return <div>Connected: {floTrace?.connected ? 'Yes' : 'No'}</div>;
246
- }
247
- ```
188
+ ## Privacy & security
248
189
 
249
- ## Production Safety
190
+ - Source code never leaves your machine. The runtime sends only metadata (component names, prop types, render counts) over `ws://localhost:3457`.
191
+ - Desktop app binds to `127.0.0.1` only. LAN connections (physical devices) require an opt-in auth token.
192
+ - The desktop is closed-source commercial; this runtime package is **MIT-licensed** and open at [github.com/sameersitre/runtime](https://github.com/sameersitre/runtime).
250
193
 
251
- By default, FloTrace is **disabled in production** (`enabled` defaults to `process.env.NODE_ENV === 'development'`).
252
-
253
- For explicit control, use a conditional import pattern:
254
-
255
- ```tsx
256
- // src/main.tsx
257
- const FloTraceProvider = process.env.NODE_ENV === 'development'
258
- ? (await import('@flotrace/runtime')).FloTraceProvider
259
- : ({ children }: { children: React.ReactNode }) => <>{children}</>;
260
- ```
194
+ ---
261
195
 
262
196
  ## Troubleshooting
263
197
 
264
- ### "Not connected"
265
-
266
- 1. Ensure the FloTrace desktop app is running
267
- 2. Check the port matches (default: 3457)
268
- 3. Verify `config.enabled` is `true`
269
- 4. Check browser console for `[FloTrace]` logs
198
+ **"Not connected"** — Is the desktop app running? Is `enabled: true`? Check browser console for `[FloTrace]` logs.
270
199
 
271
- ### Zustand stores not appearing
200
+ **Zustand stores missing** — Stores must be passed via the `stores` prop, and each value must be a Zustand hook (has `.getState()` and `.subscribe()`).
272
201
 
273
- - Stores must be passed explicitly via the `stores` prop
274
- - Each value must be a Zustand hook (function with `.getState()` and `.subscribe()` methods)
275
- - Check console for `[FloTrace] Skipping "..." — not a valid Zustand store` warnings
202
+ **Tree empty or partial** — Reload the page. The walker uses React DevTools hook or DOM-based fiber access; depth is capped at 100, children at 300/node.
276
203
 
277
- ### Component tree is missing or incomplete
204
+ **WebSocket reconnecting** Exponential backoff (2s → 30s, 10 attempts). After that, reload the page or restart the desktop.
278
205
 
279
- - The fiber tree walker needs React DevTools hook or DOM-based fiber access
280
- - React DevTools browser extension improves reliability
281
- - Tree depth is capped at 100 levels, children at 300 per node
282
- - Reload the page if the tree appears empty
206
+ ---
283
207
 
284
- ### WebSocket keeps reconnecting
208
+ ## API reference
285
209
 
286
- - FloTrace uses exponential backoff (2s 4s 8s... up to 30s) with a 10-attempt budget
287
- - After 10 failed attempts, reload the page or restart FloTrace to retry
288
- - Check that no firewall or proxy is blocking `ws://localhost:3457`
289
-
290
- ## API Reference
291
-
292
- ### Components
210
+ See [flotrace.dev/docs/runtime](https://flotrace.dev/docs/runtime) for the full export surface (40+ hooks, trackers, and types). Quick index:
293
211
 
294
212
  | Export | Description |
295
- |--------|-------------|
296
- | `FloTraceProvider` | Main provider wraps your app, manages WebSocket connection |
297
- | `withFloTrace(Component, name?)` | HOC for targeted component profiling |
213
+ |---|---|
214
+ | `FloTraceProvider` | Main provider component |
215
+ | `withFloTrace(Component, name?)` | HOC for targeted profiling |
216
+ | `useFloTrace()` | Connection state + config |
217
+ | `useTrackProps(name, props)` | Track prop changes |
218
+ | `installXxxTracker()` / `uninstallXxxTracker()` | Manual tracker control (Zustand, Redux, Router, TanStack Query, Network, Timeline) |
219
+ | `getNodeHooks(nodeId)` / `getNodeEffects(nodeId)` / `getDetailedRenderReason(nodeId)` | Inspector accessors |
298
220
 
299
- ### Hooks
221
+ Type exports: `FloTraceConfig`, `LiveTreeNode`, `SerializedValue`, `HookInfo`, `EffectInfo`, `TimelineEvent`, `NetworkRequestEntry`, `Fiber`, etc.
300
222
 
301
- | Export | Description |
302
- |--------|-------------|
303
- | `useFloTrace()` | Access connection state and config |
304
- | `useTrackProps(name, props)` | Track prop changes for a component |
223
+ ---
305
224
 
306
- ### Types
307
-
308
- | Export | Description |
309
- |--------|-------------|
310
- | `FloTraceConfig` | Configuration options interface |
311
- | `FloTraceProviderProps` | Props for FloTraceProvider |
312
- | `SerializedValue` | Serialized value type for safe WebSocket transmission |
313
- | `LiveTreeNode` | Node in the live component tree |
314
- | `ReduxStoreApi` | Minimal Redux store interface |
315
- | `TanStackQueryClientApi` | Duck-typed TanStack Query client interface |
316
- | `TrackingOptions` | Tracking options from extension |
317
- | `DEFAULT_CONFIG` | Default configuration values |
318
- | `DetailedRenderReason` | Detailed render reason with prop/state/context diffs |
319
- | `HookType`, `HookInfo` | Hook type classification and inspection data |
320
- | `EffectInfo` | Effect info with willRun and dep diffs |
321
- | `TimelineEvent`, `TimelineEventType` | Component lifecycle events |
322
- | `TanStackQueryInfo`, `TanStackMutationInfo` | Query and mutation tracking data |
323
- | `NetworkRequestEntry` | Network request metadata (method, status, timing, correlation) |
324
- | `Fiber`, `FiberHookState`, `FiberEffect` | React fiber type definitions |
325
-
326
- ### Advanced Exports
327
-
328
- | Export | Description |
329
- |--------|-------------|
330
- | `getWebSocketClient(config?)` | Get singleton WebSocket client |
331
- | `disposeWebSocketClient()` | Dispose the WebSocket client |
332
- | `FloTraceWebSocketClient` | WebSocket client class |
333
- | `installFiberTreeWalker()` | Manually install fiber tree walker |
334
- | `uninstallFiberTreeWalker()` | Uninstall fiber tree walker |
335
- | `requestTreeSnapshot()` | Request a tree snapshot (DOM fallback) |
336
- | `getNodeHooks(nodeId)` | Inspect hooks for a specific component |
337
- | `getNodeEffects(nodeId)` | Inspect effects for a specific component |
338
- | `getDetailedRenderReason(nodeId)` | Get detailed render reason (prop/state/context diffs) |
339
- | `getFiberRefMap()` | Get map of all tracked fiber refs |
340
- | `inspectHooks(fiber)` | Classify and inspect hooks from fiber |
341
- | `inspectEffects(fiber)` | Inspect effects from fiber updateQueue |
342
- | `installZustandTracker()` / `uninstall...` | Zustand per-store subscription tracking |
343
- | `installReduxTracker()` / `uninstall...` | Redux store subscription tracking |
344
- | `installRouterTracker()` / `uninstall...` | History API patching for route tracking |
345
- | `installTanStackQueryTracker()` / `uninstall...` | TanStack Query cache subscriber (duck-typed) |
346
- | `installNetworkTracker()` / `uninstall...` | Fetch/XHR patching for network monitoring |
347
- | `prewarmNetworkTracker()` | Pre-install patches to capture page-load requests |
348
- | `installTimelineTracker()` / `uninstall...` | Component lifecycle event tracking |
349
- | `recordTimelineEvent()` | Manually record a timeline event |
350
- | `getTimeline(componentId)` | Get timeline events for a component |
351
- | `serializeValue(value)` | Serialize a value for WebSocket |
352
- | `serializeProps(props)` | Serialize props object |
353
- | `isReduxStore(obj)` | Type guard for Redux store |
354
- | `isTanStackQueryClient(obj)` | Type guard for TanStack Query client |
355
-
356
- ## Publishing
357
-
358
- ### Prerequisites
359
-
360
- ```bash
361
- npm login
362
- ```
363
-
364
- ### Release Scripts
365
-
366
- | Script | Version Change | When to Use |
367
- |--------|---------------|-------------|
368
- | `npm run release:patch` | `0.1.0` → `0.1.1` | Bug fixes, small tweaks |
369
- | `npm run release:minor` | `0.1.0` → `0.2.0` | New features, non-breaking changes |
370
- | `npm run release:major` | `0.1.0` → `1.0.0` | Breaking API changes |
371
-
372
- Each release script automatically:
373
- 1. Bumps the version in `package.json`
374
- 2. Creates a git commit and tag (e.g. `v0.1.1`)
375
- 3. Cleans `dist/`, rebuilds, and typechecks (`prepublishOnly`)
376
- 4. Publishes to npm under `@flotrace` scope
377
-
378
- ### From the monorepo root
379
-
380
- | Script | Action |
381
- |--------|--------|
382
- | `npm run runtime:release:patch` | Bump patch + build + publish (e.g. `0.1.0` → `0.1.1`) |
383
- | `npm run runtime:release:minor` | Bump minor + build + publish (e.g. `0.1.0` → `0.2.0`) |
384
- | `npm run runtime:release:major` | Bump major + build + publish (e.g. `0.1.0` → `1.0.0`) |
385
- | `npm run runtime:publish` | Publish current version as-is (no version bump) |
225
+ ## License
386
226
 
387
- > **Note:** `runtime:publish` publishes whatever version is currently in `package.json`. Use this for the first publish or to re-publish a fixed build without bumping the version. The `release:*` scripts auto-increment the version, create a git commit + tag, then publish.
227
+ MIT see [LICENSE](./LICENSE). Issues and PRs welcome at [github.com/sameersitre/runtime](https://github.com/sameersitre/runtime).
388
228
 
389
- ## License
229
+ ---
390
230
 
391
- MIT
231
+ > **Mirrored from the [flotrace-desktop](https://github.com/sameersitre/flotrace-desktop) monorepo.** This repo is read-only — every release is regenerated by the lockstep publisher in the desktop monorepo. Issues filed here are tracked, but PRs are best opened against the upstream monorepo where the canonical source lives.
package/dist/index.js CHANGED
@@ -47,6 +47,74 @@ __reExport(index_exports, require("@flotrace/runtime-core"), module.exports);
47
47
  var import_react = __toESM(require("react"));
48
48
  var import_runtime_core3 = require("@flotrace/runtime-core");
49
49
 
50
+ // package.json
51
+ var package_default = {
52
+ name: "@flotrace/runtime",
53
+ version: "2.2.3",
54
+ description: "Runtime package for FloTrace - enables real-time render tracking in your React app",
55
+ main: "./dist/index.js",
56
+ module: "./dist/index.mjs",
57
+ types: "./dist/index.d.ts",
58
+ exports: {
59
+ ".": {
60
+ types: "./dist/index.d.ts",
61
+ import: "./dist/index.mjs",
62
+ require: "./dist/index.js"
63
+ }
64
+ },
65
+ files: [
66
+ "dist",
67
+ "LICENSE",
68
+ "README.md"
69
+ ],
70
+ scripts: {
71
+ build: "tsup",
72
+ dev: "tsup --watch",
73
+ typecheck: "tsc --noEmit",
74
+ clean: "rm -rf dist",
75
+ prepublishOnly: "npm run -w @flotrace/runtime-core build && npm run clean && npm run build && npm run typecheck",
76
+ "release:patch": "npm version patch && npm publish",
77
+ "release:minor": "npm version minor && npm publish",
78
+ "release:major": "npm version major && npm publish"
79
+ },
80
+ dependencies: {
81
+ "@flotrace/runtime-core": "2.2.3"
82
+ },
83
+ peerDependencies: {
84
+ react: ">=16.9.0",
85
+ "@types/react": ">=16.9.0"
86
+ },
87
+ peerDependenciesMeta: {
88
+ "@types/react": {
89
+ optional: true
90
+ }
91
+ },
92
+ devDependencies: {
93
+ tsup: "^8.0.0",
94
+ typescript: "^5.3.0"
95
+ },
96
+ keywords: [
97
+ "react",
98
+ "devtools",
99
+ "profiler",
100
+ "render",
101
+ "performance",
102
+ "flotrace"
103
+ ],
104
+ license: "MIT",
105
+ homepage: "https://flotrace.dev",
106
+ repository: {
107
+ type: "git",
108
+ url: "https://github.com/sameersitre/runtime.git"
109
+ },
110
+ bugs: {
111
+ url: "https://github.com/sameersitre/runtime/issues"
112
+ },
113
+ publishConfig: {
114
+ access: "public"
115
+ }
116
+ };
117
+
50
118
  // src/routerTracker.ts
51
119
  var isInstalled = false;
52
120
  var debounceTimer = null;
@@ -224,6 +292,7 @@ var requestCounter = 0;
224
292
  var requestIndexMap = /* @__PURE__ */ new Map();
225
293
  var earlyRequestIndexMap = /* @__PURE__ */ new Map();
226
294
  var previousFetch = null;
295
+ var trackedFetchRef = null;
227
296
  var originalXhrOpen = null;
228
297
  var originalXhrSend = null;
229
298
  var originalResponseJson = null;
@@ -265,8 +334,11 @@ function installNetworkTracker(wsClient) {
265
334
  function uninstallNetworkTracker() {
266
335
  if (!isInstalled2 && !isPrewarmed) return;
267
336
  if (previousFetch) {
268
- globalThis.fetch = previousFetch;
337
+ if (globalThis.fetch === trackedFetchRef) {
338
+ globalThis.fetch = previousFetch;
339
+ }
269
340
  previousFetch = null;
341
+ trackedFetchRef = null;
270
342
  }
271
343
  if (originalXhrOpen) {
272
344
  XMLHttpRequest.prototype.open = originalXhrOpen;
@@ -304,10 +376,14 @@ function uninstallNetworkTracker() {
304
376
  function patchFetch() {
305
377
  if (typeof globalThis.fetch !== "function") return;
306
378
  previousFetch = globalThis.fetch;
307
- globalThis.fetch = async function trackedFetch(input, init) {
379
+ const capturedPreviousFetch = previousFetch;
380
+ const trackedFetch = async function trackedFetch2(input, init) {
381
+ if (!isInstalled2 && !isPrewarmed) {
382
+ return capturedPreviousFetch.call(globalThis, input, init);
383
+ }
308
384
  const url = extractUrl(input);
309
385
  if (isNoiseUrl(url)) {
310
- return previousFetch.call(globalThis, input, init);
386
+ return capturedPreviousFetch.call(globalThis, input, init);
311
387
  }
312
388
  const method = (init?.method ?? "GET").toUpperCase();
313
389
  const parsedUrl = parseUrl(url);
@@ -322,7 +398,7 @@ function patchFetch() {
322
398
  }
323
399
  pushEntry({ ...entry });
324
400
  try {
325
- const response = await previousFetch.call(globalThis, input, init);
401
+ const response = await capturedPreviousFetch.call(globalThis, input, init);
326
402
  if (entry.state !== "aborted") {
327
403
  entry.state = response.ok ? "success" : "error";
328
404
  entry.status = response.status;
@@ -345,6 +421,8 @@ function patchFetch() {
345
421
  throw err;
346
422
  }
347
423
  };
424
+ trackedFetchRef = trackedFetch;
425
+ globalThis.fetch = trackedFetch;
348
426
  }
349
427
  function patchXhr() {
350
428
  if (typeof XMLHttpRequest === "undefined") return;
@@ -571,6 +649,7 @@ function flushBuffer() {
571
649
 
572
650
  // src/FloTraceProvider.tsx
573
651
  var import_jsx_runtime = require("react/jsx-runtime");
652
+ var RUNTIME_VERSION = package_default.version;
574
653
  var pendingCleanupTimer = null;
575
654
  function safeTrackerOp(name, op) {
576
655
  try {
@@ -616,7 +695,8 @@ function FloTraceProvider({ children, config = {}, stores, reduxStore, queryClie
616
695
  appName: config.appName ?? deriveWebAppName(),
617
696
  appId: config.appId ?? deriveWebAppId(),
618
697
  frameworkName: config.frameworkName ?? framework.frameworkName,
619
- frameworkVersion: config.frameworkVersion ?? framework.frameworkVersion
698
+ frameworkVersion: config.frameworkVersion ?? framework.frameworkVersion,
699
+ runtimeVersion: config.runtimeVersion ?? RUNTIME_VERSION
620
700
  };
621
701
  const [connected, setConnected] = import_react.default.useState(false);
622
702
  const trackingOptionsRef = (0, import_react.useRef)({});
package/dist/index.mjs CHANGED
@@ -30,6 +30,74 @@ import {
30
30
  resolveValueTrace
31
31
  } from "@flotrace/runtime-core";
32
32
 
33
+ // package.json
34
+ var package_default = {
35
+ name: "@flotrace/runtime",
36
+ version: "2.2.3",
37
+ description: "Runtime package for FloTrace - enables real-time render tracking in your React app",
38
+ main: "./dist/index.js",
39
+ module: "./dist/index.mjs",
40
+ types: "./dist/index.d.ts",
41
+ exports: {
42
+ ".": {
43
+ types: "./dist/index.d.ts",
44
+ import: "./dist/index.mjs",
45
+ require: "./dist/index.js"
46
+ }
47
+ },
48
+ files: [
49
+ "dist",
50
+ "LICENSE",
51
+ "README.md"
52
+ ],
53
+ scripts: {
54
+ build: "tsup",
55
+ dev: "tsup --watch",
56
+ typecheck: "tsc --noEmit",
57
+ clean: "rm -rf dist",
58
+ prepublishOnly: "npm run -w @flotrace/runtime-core build && npm run clean && npm run build && npm run typecheck",
59
+ "release:patch": "npm version patch && npm publish",
60
+ "release:minor": "npm version minor && npm publish",
61
+ "release:major": "npm version major && npm publish"
62
+ },
63
+ dependencies: {
64
+ "@flotrace/runtime-core": "2.2.3"
65
+ },
66
+ peerDependencies: {
67
+ react: ">=16.9.0",
68
+ "@types/react": ">=16.9.0"
69
+ },
70
+ peerDependenciesMeta: {
71
+ "@types/react": {
72
+ optional: true
73
+ }
74
+ },
75
+ devDependencies: {
76
+ tsup: "^8.0.0",
77
+ typescript: "^5.3.0"
78
+ },
79
+ keywords: [
80
+ "react",
81
+ "devtools",
82
+ "profiler",
83
+ "render",
84
+ "performance",
85
+ "flotrace"
86
+ ],
87
+ license: "MIT",
88
+ homepage: "https://flotrace.dev",
89
+ repository: {
90
+ type: "git",
91
+ url: "https://github.com/sameersitre/runtime.git"
92
+ },
93
+ bugs: {
94
+ url: "https://github.com/sameersitre/runtime/issues"
95
+ },
96
+ publishConfig: {
97
+ access: "public"
98
+ }
99
+ };
100
+
33
101
  // src/routerTracker.ts
34
102
  var isInstalled = false;
35
103
  var debounceTimer = null;
@@ -213,6 +281,7 @@ var requestCounter = 0;
213
281
  var requestIndexMap = /* @__PURE__ */ new Map();
214
282
  var earlyRequestIndexMap = /* @__PURE__ */ new Map();
215
283
  var previousFetch = null;
284
+ var trackedFetchRef = null;
216
285
  var originalXhrOpen = null;
217
286
  var originalXhrSend = null;
218
287
  var originalResponseJson = null;
@@ -254,8 +323,11 @@ function installNetworkTracker(wsClient) {
254
323
  function uninstallNetworkTracker() {
255
324
  if (!isInstalled2 && !isPrewarmed) return;
256
325
  if (previousFetch) {
257
- globalThis.fetch = previousFetch;
326
+ if (globalThis.fetch === trackedFetchRef) {
327
+ globalThis.fetch = previousFetch;
328
+ }
258
329
  previousFetch = null;
330
+ trackedFetchRef = null;
259
331
  }
260
332
  if (originalXhrOpen) {
261
333
  XMLHttpRequest.prototype.open = originalXhrOpen;
@@ -293,10 +365,14 @@ function uninstallNetworkTracker() {
293
365
  function patchFetch() {
294
366
  if (typeof globalThis.fetch !== "function") return;
295
367
  previousFetch = globalThis.fetch;
296
- globalThis.fetch = async function trackedFetch(input, init) {
368
+ const capturedPreviousFetch = previousFetch;
369
+ const trackedFetch = async function trackedFetch2(input, init) {
370
+ if (!isInstalled2 && !isPrewarmed) {
371
+ return capturedPreviousFetch.call(globalThis, input, init);
372
+ }
297
373
  const url = extractUrl(input);
298
374
  if (isNoiseUrl(url)) {
299
- return previousFetch.call(globalThis, input, init);
375
+ return capturedPreviousFetch.call(globalThis, input, init);
300
376
  }
301
377
  const method = (init?.method ?? "GET").toUpperCase();
302
378
  const parsedUrl = parseUrl(url);
@@ -311,7 +387,7 @@ function patchFetch() {
311
387
  }
312
388
  pushEntry({ ...entry });
313
389
  try {
314
- const response = await previousFetch.call(globalThis, input, init);
390
+ const response = await capturedPreviousFetch.call(globalThis, input, init);
315
391
  if (entry.state !== "aborted") {
316
392
  entry.state = response.ok ? "success" : "error";
317
393
  entry.status = response.status;
@@ -334,6 +410,8 @@ function patchFetch() {
334
410
  throw err;
335
411
  }
336
412
  };
413
+ trackedFetchRef = trackedFetch;
414
+ globalThis.fetch = trackedFetch;
337
415
  }
338
416
  function patchXhr() {
339
417
  if (typeof XMLHttpRequest === "undefined") return;
@@ -560,6 +638,7 @@ function flushBuffer() {
560
638
 
561
639
  // src/FloTraceProvider.tsx
562
640
  import { Fragment, jsx } from "react/jsx-runtime";
641
+ var RUNTIME_VERSION = package_default.version;
563
642
  var pendingCleanupTimer = null;
564
643
  function safeTrackerOp(name, op) {
565
644
  try {
@@ -605,7 +684,8 @@ function FloTraceProvider({ children, config = {}, stores, reduxStore, queryClie
605
684
  appName: config.appName ?? deriveWebAppName(),
606
685
  appId: config.appId ?? deriveWebAppId(),
607
686
  frameworkName: config.frameworkName ?? framework.frameworkName,
608
- frameworkVersion: config.frameworkVersion ?? framework.frameworkVersion
687
+ frameworkVersion: config.frameworkVersion ?? framework.frameworkVersion,
688
+ runtimeVersion: config.runtimeVersion ?? RUNTIME_VERSION
609
689
  };
610
690
  const [connected, setConnected] = React.useState(false);
611
691
  const trackingOptionsRef = useRef({});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flotrace/runtime",
3
- "version": "2.2.1",
3
+ "version": "2.2.3",
4
4
  "description": "Runtime package for FloTrace - enables real-time render tracking in your React app",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -13,7 +13,9 @@
13
13
  }
14
14
  },
15
15
  "files": [
16
- "dist"
16
+ "dist",
17
+ "LICENSE",
18
+ "README.md"
17
19
  ],
18
20
  "scripts": {
19
21
  "build": "tsup",
@@ -26,7 +28,7 @@
26
28
  "release:major": "npm version major && npm publish"
27
29
  },
28
30
  "dependencies": {
29
- "@flotrace/runtime-core": "2.2.1"
31
+ "@flotrace/runtime-core": "2.2.3"
30
32
  },
31
33
  "peerDependencies": {
32
34
  "react": ">=16.9.0",
@@ -50,10 +52,13 @@
50
52
  "flotrace"
51
53
  ],
52
54
  "license": "MIT",
55
+ "homepage": "https://flotrace.dev",
53
56
  "repository": {
54
57
  "type": "git",
55
- "url": "https://github.com/flotrace/flotrace.git",
56
- "directory": "packages/runtime"
58
+ "url": "https://github.com/sameersitre/runtime.git"
59
+ },
60
+ "bugs": {
61
+ "url": "https://github.com/sameersitre/runtime/issues"
57
62
  },
58
63
  "publishConfig": {
59
64
  "access": "public"