@flotrace/runtime 0.1.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/README.md ADDED
@@ -0,0 +1,389 @@
1
+ # @flotrace/runtime
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.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @flotrace/runtime
9
+ # or
10
+ yarn add @flotrace/runtime
11
+ # or
12
+ pnpm add @flotrace/runtime
13
+ ```
14
+
15
+ **Peer dependencies:** React >= 16.9.0 (requires `<Profiler>` API)
16
+
17
+ ## Quick Start
18
+
19
+ Wrap your app with `<FloTraceProvider>`:
20
+
21
+ ```tsx
22
+ import { FloTraceProvider } from '@flotrace/runtime';
23
+ import { createRoot } from 'react-dom/client';
24
+ import App from './App';
25
+
26
+ createRoot(document.getElementById('root')!).render(
27
+ <FloTraceProvider config={{ appName: 'My App' }}>
28
+ <App />
29
+ </FloTraceProvider>
30
+ );
31
+ ```
32
+
33
+ Then launch the FloTrace desktop app — your component tree will appear automatically.
34
+
35
+ ## Configuration
36
+
37
+ All config options are optional. Pass them via the `config` prop:
38
+
39
+ ```tsx
40
+ <FloTraceProvider config={{ port: 3457, appName: 'My App' }}>
41
+ ```
42
+
43
+ | Option | Type | Default | Description |
44
+ |--------|------|---------|-------------|
45
+ | `port` | `number` | `3457` | WebSocket server port |
46
+ | `appName` | `string` | `'React App'` | App name displayed in FloTrace |
47
+ | `enabled` | `boolean` | `true` in dev | Enable/disable tracking |
48
+ | `autoReconnect` | `boolean` | `true` | Auto-reconnect on disconnect |
49
+ | `reconnectInterval` | `number` | `2000` | Reconnect interval (ms) |
50
+ | `trackAllRenders` | `boolean` | `true` | Track all component renders |
51
+ | `includeProps` | `boolean` | `true` | Include props in render events |
52
+ | `trackZustand` | `boolean` | `true` | Enable Zustand state tracking |
53
+ | `trackRedux` | `boolean` | `true` | Enable Redux state tracking |
54
+ | `trackRouter` | `boolean` | `true` | Enable URL navigation tracking |
55
+ | `trackContext` | `boolean` | `true` | Enable React Context tracking |
56
+ | `trackTanstackQuery` | `boolean` | `true` | Enable TanStack Query tracking |
57
+
58
+ ## Framework Setup
59
+
60
+ ### Vite + React
61
+
62
+ ```tsx
63
+ // src/main.tsx
64
+ import { FloTraceProvider } from '@flotrace/runtime';
65
+ import { createRoot } from 'react-dom/client';
66
+ import App from './App';
67
+
68
+ createRoot(document.getElementById('root')!).render(
69
+ <FloTraceProvider config={{ appName: 'My Vite App' }}>
70
+ <App />
71
+ </FloTraceProvider>
72
+ );
73
+ ```
74
+
75
+ ### Next.js (App Router)
76
+
77
+ ```tsx
78
+ // app/providers.tsx
79
+ 'use client';
80
+
81
+ import { FloTraceProvider } from '@flotrace/runtime';
82
+
83
+ export function Providers({ children }: { children: React.ReactNode }) {
84
+ return (
85
+ <FloTraceProvider config={{ appName: 'My Next.js App' }}>
86
+ {children}
87
+ </FloTraceProvider>
88
+ );
89
+ }
90
+
91
+ // app/layout.tsx
92
+ import { Providers } from './providers';
93
+
94
+ export default function RootLayout({ children }: { children: React.ReactNode }) {
95
+ return (
96
+ <html>
97
+ <body>
98
+ <Providers>{children}</Providers>
99
+ </body>
100
+ </html>
101
+ );
102
+ }
103
+ ```
104
+
105
+ ### Next.js (Pages Router)
106
+
107
+ ```tsx
108
+ // pages/_app.tsx
109
+ import { FloTraceProvider } from '@flotrace/runtime';
110
+ import type { AppProps } from 'next/app';
111
+
112
+ export default function App({ Component, pageProps }: AppProps) {
113
+ return (
114
+ <FloTraceProvider config={{ appName: 'My Next.js App' }}>
115
+ <Component {...pageProps} />
116
+ </FloTraceProvider>
117
+ );
118
+ }
119
+ ```
120
+
121
+ ### Create React App
122
+
123
+ ```tsx
124
+ // src/index.tsx
125
+ import { FloTraceProvider } from '@flotrace/runtime';
126
+ import { createRoot } from 'react-dom/client';
127
+ import App from './App';
128
+
129
+ createRoot(document.getElementById('root')!).render(
130
+ <FloTraceProvider config={{ appName: 'My CRA App' }}>
131
+ <App />
132
+ </FloTraceProvider>
133
+ );
134
+ ```
135
+
136
+ ## State Management Integration
137
+
138
+ ### Zustand
139
+
140
+ Pass Zustand stores via the `stores` prop. Keys become store names in FloTrace:
141
+
142
+ ```tsx
143
+ import { FloTraceProvider } from '@flotrace/runtime';
144
+ import { useBearStore } from './store/bearStore';
145
+ import { useUserStore } from './store/userStore';
146
+
147
+ <FloTraceProvider
148
+ stores={{ bearStore: useBearStore, userStore: useUserStore }}
149
+ config={{ appName: 'My App' }}
150
+ >
151
+ <App />
152
+ </FloTraceProvider>
153
+ ```
154
+
155
+ ### Redux
156
+
157
+ Pass your Redux store via the `reduxStore` prop:
158
+
159
+ ```tsx
160
+ import { FloTraceProvider } from '@flotrace/runtime';
161
+ import { store } from './store';
162
+
163
+ <FloTraceProvider
164
+ reduxStore={store}
165
+ config={{ appName: 'My App' }}
166
+ >
167
+ <App />
168
+ </FloTraceProvider>
169
+ ```
170
+
171
+ ### TanStack Query
172
+
173
+ Pass your TanStack Query client via the `queryClient` prop:
174
+
175
+ ```tsx
176
+ import { FloTraceProvider } from '@flotrace/runtime';
177
+ import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
178
+
179
+ const queryClient = new QueryClient();
180
+
181
+ <QueryClientProvider client={queryClient}>
182
+ <FloTraceProvider
183
+ queryClient={queryClient}
184
+ config={{ appName: 'My App' }}
185
+ >
186
+ <App />
187
+ </FloTraceProvider>
188
+ </QueryClientProvider>
189
+ ```
190
+
191
+ ### Combined (Zustand + Redux + TanStack Query + Router)
192
+
193
+ ```tsx
194
+ import { FloTraceProvider } from '@flotrace/runtime';
195
+ import { store } from './reduxStore';
196
+ import { useBearStore } from './zustandStore';
197
+ import { queryClient } from './queryClient';
198
+
199
+ <FloTraceProvider
200
+ config={{ appName: 'My App' }}
201
+ stores={{ bearStore: useBearStore }}
202
+ reduxStore={store}
203
+ queryClient={queryClient}
204
+ >
205
+ <App />
206
+ </FloTraceProvider>
207
+ ```
208
+
209
+ 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.
210
+
211
+ ## Advanced Usage
212
+
213
+ ### `withFloTrace()` — HOC for targeted profiling
214
+
215
+ Wrap specific components to track their renders and props individually:
216
+
217
+ ```tsx
218
+ import { withFloTrace } from '@flotrace/runtime';
219
+
220
+ const ProfiledComponent = withFloTrace(MyComponent, 'MyComponent');
221
+ ```
222
+
223
+ ### `useTrackProps()` — Track prop changes
224
+
225
+ Call at the top of a component to track its prop changes:
226
+
227
+ ```tsx
228
+ import { useTrackProps } from '@flotrace/runtime';
229
+
230
+ function MyComponent(props: MyProps) {
231
+ useTrackProps('MyComponent', props);
232
+ // ... rest of component
233
+ }
234
+ ```
235
+
236
+ ### `useFloTrace()` — Access runtime context
237
+
238
+ ```tsx
239
+ import { useFloTrace } from '@flotrace/runtime';
240
+
241
+ function DebugInfo() {
242
+ const floTrace = useFloTrace();
243
+ return <div>Connected: {floTrace?.connected ? 'Yes' : 'No'}</div>;
244
+ }
245
+ ```
246
+
247
+ ## Production Safety
248
+
249
+ By default, FloTrace is **disabled in production** (`enabled` defaults to `process.env.NODE_ENV === 'development'`).
250
+
251
+ For explicit control, use a conditional import pattern:
252
+
253
+ ```tsx
254
+ // src/main.tsx
255
+ const FloTraceProvider = process.env.NODE_ENV === 'development'
256
+ ? (await import('@flotrace/runtime')).FloTraceProvider
257
+ : ({ children }: { children: React.ReactNode }) => <>{children}</>;
258
+ ```
259
+
260
+ ## Troubleshooting
261
+
262
+ ### "Not connected"
263
+
264
+ 1. Ensure the FloTrace desktop app is running
265
+ 2. Check the port matches (default: 3457)
266
+ 3. Verify `config.enabled` is `true`
267
+ 4. Check browser console for `[FloTrace]` logs
268
+
269
+ ### Zustand stores not appearing
270
+
271
+ - Stores must be passed explicitly via the `stores` prop
272
+ - Each value must be a Zustand hook (function with `.getState()` and `.subscribe()` methods)
273
+ - Check console for `[FloTrace] Skipping "..." — not a valid Zustand store` warnings
274
+
275
+ ### Component tree is missing or incomplete
276
+
277
+ - The fiber tree walker needs React DevTools hook or DOM-based fiber access
278
+ - React DevTools browser extension improves reliability
279
+ - Tree depth is capped at 100 levels, children at 300 per node
280
+ - Reload the page if the tree appears empty
281
+
282
+ ### WebSocket keeps reconnecting
283
+
284
+ - FloTrace uses exponential backoff (2s → 4s → 8s... up to 30s) with a 10-attempt budget
285
+ - After 10 failed attempts, reload the page or restart FloTrace to retry
286
+ - Check that no firewall or proxy is blocking `ws://localhost:3457`
287
+
288
+ ## API Reference
289
+
290
+ ### Components
291
+
292
+ | Export | Description |
293
+ |--------|-------------|
294
+ | `FloTraceProvider` | Main provider — wraps your app, manages WebSocket connection |
295
+ | `withFloTrace(Component, name?)` | HOC for targeted component profiling |
296
+
297
+ ### Hooks
298
+
299
+ | Export | Description |
300
+ |--------|-------------|
301
+ | `useFloTrace()` | Access connection state and config |
302
+ | `useTrackProps(name, props)` | Track prop changes for a component |
303
+
304
+ ### Types
305
+
306
+ | Export | Description |
307
+ |--------|-------------|
308
+ | `FloTraceConfig` | Configuration options interface |
309
+ | `FloTraceProviderProps` | Props for FloTraceProvider |
310
+ | `SerializedValue` | Serialized value type for safe WebSocket transmission |
311
+ | `LiveTreeNode` | Node in the live component tree |
312
+ | `ReduxStoreApi` | Minimal Redux store interface |
313
+ | `TanStackQueryClientApi` | Duck-typed TanStack Query client interface |
314
+ | `TrackingOptions` | Tracking options from extension |
315
+ | `DEFAULT_CONFIG` | Default configuration values |
316
+ | `DetailedRenderReason` | Detailed render reason with prop/state/context diffs |
317
+ | `HookType`, `HookInfo` | Hook type classification and inspection data |
318
+ | `EffectInfo` | Effect info with willRun and dep diffs |
319
+ | `TimelineEvent`, `TimelineEventType` | Component lifecycle events |
320
+ | `TanStackQueryInfo`, `TanStackMutationInfo` | Query and mutation tracking data |
321
+ | `NetworkRequestEntry` | Network request metadata (method, status, timing, correlation) |
322
+ | `Fiber`, `FiberHookState`, `FiberEffect` | React fiber type definitions |
323
+
324
+ ### Advanced Exports
325
+
326
+ | Export | Description |
327
+ |--------|-------------|
328
+ | `getWebSocketClient(config?)` | Get singleton WebSocket client |
329
+ | `disposeWebSocketClient()` | Dispose the WebSocket client |
330
+ | `FloTraceWebSocketClient` | WebSocket client class |
331
+ | `installFiberTreeWalker()` | Manually install fiber tree walker |
332
+ | `uninstallFiberTreeWalker()` | Uninstall fiber tree walker |
333
+ | `requestTreeSnapshot()` | Request a tree snapshot (DOM fallback) |
334
+ | `getNodeHooks(nodeId)` | Inspect hooks for a specific component |
335
+ | `getNodeEffects(nodeId)` | Inspect effects for a specific component |
336
+ | `getDetailedRenderReason(nodeId)` | Get detailed render reason (prop/state/context diffs) |
337
+ | `getFiberRefMap()` | Get map of all tracked fiber refs |
338
+ | `inspectHooks(fiber)` | Classify and inspect hooks from fiber |
339
+ | `inspectEffects(fiber)` | Inspect effects from fiber updateQueue |
340
+ | `installZustandTracker()` / `uninstall...` | Zustand per-store subscription tracking |
341
+ | `installReduxTracker()` / `uninstall...` | Redux store subscription tracking |
342
+ | `installRouterTracker()` / `uninstall...` | History API patching for route tracking |
343
+ | `installTanStackQueryTracker()` / `uninstall...` | TanStack Query cache subscriber (duck-typed) |
344
+ | `installNetworkTracker()` / `uninstall...` | Fetch/XHR patching for network monitoring |
345
+ | `prewarmNetworkTracker()` | Pre-install patches to capture page-load requests |
346
+ | `installTimelineTracker()` / `uninstall...` | Component lifecycle event tracking |
347
+ | `recordTimelineEvent()` | Manually record a timeline event |
348
+ | `getTimeline(componentId)` | Get timeline events for a component |
349
+ | `serializeValue(value)` | Serialize a value for WebSocket |
350
+ | `serializeProps(props)` | Serialize props object |
351
+ | `isReduxStore(obj)` | Type guard for Redux store |
352
+ | `isTanStackQueryClient(obj)` | Type guard for TanStack Query client |
353
+
354
+ ## Publishing
355
+
356
+ ### Prerequisites
357
+
358
+ ```bash
359
+ npm login
360
+ ```
361
+
362
+ ### Release Scripts
363
+
364
+ | Script | Version Change | When to Use |
365
+ |--------|---------------|-------------|
366
+ | `npm run release:patch` | `0.1.0` → `0.1.1` | Bug fixes, small tweaks |
367
+ | `npm run release:minor` | `0.1.0` → `0.2.0` | New features, non-breaking changes |
368
+ | `npm run release:major` | `0.1.0` → `1.0.0` | Breaking API changes |
369
+
370
+ Each release script automatically:
371
+ 1. Bumps the version in `package.json`
372
+ 2. Creates a git commit and tag (e.g. `v0.1.1`)
373
+ 3. Cleans `dist/`, rebuilds, and typechecks (`prepublishOnly`)
374
+ 4. Publishes to npm under `@flotrace` scope
375
+
376
+ ### From the monorepo root
377
+
378
+ | Script | Action |
379
+ |--------|--------|
380
+ | `npm run runtime:release:patch` | Bump patch + build + publish (e.g. `0.1.0` → `0.1.1`) |
381
+ | `npm run runtime:release:minor` | Bump minor + build + publish (e.g. `0.1.0` → `0.2.0`) |
382
+ | `npm run runtime:release:major` | Bump major + build + publish (e.g. `0.1.0` → `1.0.0`) |
383
+ | `npm run runtime:publish` | Publish current version as-is (no version bump) |
384
+
385
+ > **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.
386
+
387
+ ## License
388
+
389
+ MIT