@ashokreddydev/react-performance-monitor 0.0.0-stage → 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.
Files changed (46) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/LICENSE +21 -0
  3. package/README.md +309 -2
  4. package/dist/PerformanceMonitor-BSWG4Ii-.d.cts +183 -0
  5. package/dist/PerformanceMonitor-BWvrNCvp.d.ts +183 -0
  6. package/dist/PerformancePanel-6LHWD52Q.js +678 -0
  7. package/dist/PerformancePanel-U3KTU2BT.cjs +680 -0
  8. package/dist/axios.cjs +62 -0
  9. package/dist/axios.d.cts +21 -0
  10. package/dist/axios.d.ts +21 -0
  11. package/dist/axios.js +60 -0
  12. package/dist/charts.cjs +320 -0
  13. package/dist/charts.d.cts +56 -0
  14. package/dist/charts.d.ts +56 -0
  15. package/dist/charts.js +291 -0
  16. package/dist/chunk-5TDZ2PFD.js +74 -0
  17. package/dist/chunk-AETFDOCD.js +177 -0
  18. package/dist/chunk-DOY37SMY.cjs +79 -0
  19. package/dist/chunk-K4P4CBNG.cjs +1010 -0
  20. package/dist/chunk-LY4JO6PL.js +122 -0
  21. package/dist/chunk-Q55RPWQK.cjs +183 -0
  22. package/dist/chunk-UPMG6KIA.cjs +347 -0
  23. package/dist/chunk-VAQESCDW.cjs +125 -0
  24. package/dist/chunk-VVPPYDOB.js +338 -0
  25. package/dist/chunk-YUN5C27A.js +993 -0
  26. package/dist/config-Cie78aAE.d.cts +66 -0
  27. package/dist/config-D9H8MUgT.d.ts +66 -0
  28. package/dist/index.cjs +408 -0
  29. package/dist/index.d.cts +305 -0
  30. package/dist/index.d.ts +305 -0
  31. package/dist/index.js +267 -0
  32. package/dist/metrics-LC7_GsyQ.d.cts +115 -0
  33. package/dist/metrics-rSnrCSo0.d.ts +115 -0
  34. package/dist/performanceThresholds-B8-ZCvDG.d.cts +137 -0
  35. package/dist/performanceThresholds-B8-ZCvDG.d.ts +137 -0
  36. package/dist/redux.cjs +55 -0
  37. package/dist/redux.d.cts +27 -0
  38. package/dist/redux.d.ts +27 -0
  39. package/dist/redux.js +53 -0
  40. package/dist/trackora.cjs +17 -0
  41. package/dist/trackora.d.cts +17 -0
  42. package/dist/trackora.d.ts +17 -0
  43. package/dist/trackora.js +14 -0
  44. package/dist/types-9Azbo-h3.d.cts +56 -0
  45. package/dist/types-CQPUx5jX.d.ts +56 -0
  46. package/package.json +150 -3
package/CHANGELOG.md ADDED
@@ -0,0 +1,10 @@
1
+ # @ashokreddydev/react-performance-monitor
2
+
3
+ ## 0.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 23aecb8: New package: React performance monitoring — React Profiler boundaries, fetch/XHR/Axios timing with p50/p95/p99,
8
+ Core Web Vitals (web-vitals), Redux Toolkit middleware, browser timings (navigation, resources, long tasks,
9
+ visibility, memory) and error capture, a lazy developer panel with optional ECharts charts, bounded batching with
10
+ sendBeacon/fetch delivery and retry, and a backend-independent transport (plus a Trackora adapter).
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ashok Penamalli
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,3 +1,310 @@
1
- # Temporary Holding Version
1
+ # react-performance-monitor
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Performance monitoring for React apps. It measures:
4
+
5
+ - **component render times**, with React's Profiler
6
+ - **API latency**: fetch, XHR and Axios, with p50/p95/p99
7
+ - **Core Web Vitals**: LCP, INP, CLS, FCP and TTFB
8
+ - **Redux action timing**
9
+ - **long tasks, navigation and resource timing**, plus memory where the browser supports it
10
+ - **uncaught errors**
11
+
12
+ It also includes a floating developer panel with charts. It sends data to **any backend**: you give it an HTTP
13
+ endpoint or your own transport.
14
+
15
+ - **Safe by default.** It never throws into your app, and memory and retries are bounded. A session that is not
16
+ sampled does no work at all, and production sends no per-render events unless you turn them on.
17
+ - **Private by default.** It never reads headers, cookies, request or response bodies, Redux state or action payloads.
18
+ URLs become templates (`/users/:id`). Query values are removed unless you allow them, and free text is masked.
19
+ - **No re-renders caused by the SDK.** The provider's context never changes. Only components that read live
20
+ metrics update, at most twice a second.
21
+
22
+ > Status: 0.x — the API may still change in minor versions.
23
+
24
+ ## Contents
25
+
26
+ [Install](#install) · [Quick start](#quick-start) · [Configuration](#configuration) · [Collectors](#collectors) ·
27
+ [Developer panel](#developer-panel) · [Redux](#redux) · [Axios](#axios) · [Hooks](#hooks) · [Delivery](#delivery) ·
28
+ [Privacy](#privacy) · [Performance overhead](#performance-overhead) · [Production checklist](#production-checklist) ·
29
+ [Troubleshooting](#troubleshooting) · [Custom collectors](#custom-collectors)
30
+
31
+ ## Install
32
+
33
+ ```bash
34
+ npm install @ashokreddydev/react-performance-monitor
35
+ # optional, only for the charts in the developer panel:
36
+ npm install echarts
37
+ ```
38
+
39
+ You need React 18 or newer. `web-vitals` is installed with the package. Redux Toolkit, Axios, ECharts and
40
+ React Scan are optional. Only their own entry points use them.
41
+
42
+ | Import | What it adds |
43
+ |---|---|
44
+ | `@ashokreddydev/react-performance-monitor` | provider, monitor, built-in collectors, `<ProfiledBoundary>`, hooks, `<PerformanceButton>` |
45
+ | `…/redux` | `createPerformanceMiddleware()` |
46
+ | `…/axios` | `instrumentAxios(instance, monitor)` |
47
+ | `…/charts` | ECharts charts for the panel (needs `echarts`) |
48
+ | `…/trackora` | `trackoraTransport()` for a Trackora server |
49
+
50
+ ESM and CommonJS builds ship with TypeScript declarations. The package works in JavaScript and TypeScript apps and
51
+ is tree-shakeable (`sideEffects: false`).
52
+
53
+ ## Quick start
54
+
55
+ ```tsx
56
+ import { PerformanceButton, PerformanceProvider, ProfiledBoundary } from '@ashokreddydev/react-performance-monitor';
57
+
58
+ export function Root() {
59
+ return (
60
+ <PerformanceProvider
61
+ config={{
62
+ applicationId: 'my-app',
63
+ environment: import.meta.env.MODE,
64
+ sampleRate: 0.2, // 20 % of sessions send telemetry
65
+ collectors: { components: true, api: true, webVitals: true, browser: true, errors: true },
66
+ transport: { endpoint: '/api/performance/batch', batchSize: 20, flushInterval: 10_000 },
67
+ }}
68
+ >
69
+ <ProfiledBoundary id="App">
70
+ <App />
71
+ </ProfiledBoundary>
72
+ <PerformanceButton loadCharts={() => import('@ashokreddydev/react-performance-monitor/charts')} />
73
+ </PerformanceProvider>
74
+ );
75
+ }
76
+ ```
77
+
78
+ The provider reads `config` once, on the first render. To change it, remount the provider (for example with a new
79
+ `key`). The API, Web Vitals, browser and error collectors start automatically, and each one can be switched off.
80
+
81
+ ## Configuration
82
+
83
+ | Option | Default | Notes |
84
+ |---|---|---|
85
+ | `applicationId` | (required) | 1–64 letters, digits, `.`, `_`, `-` |
86
+ | `environment` | `development` | Free text. `production` or `prod` turns off the dev-only defaults below. |
87
+ | `release` | none | Your app version. Regressions are easier to tie to a deploy. |
88
+ | `enabled` | `true` | Master switch. |
89
+ | `sampleRate` | `1` | Share of sessions that send telemetry. Decided once per browser session. |
90
+ | `collectors` | all on except `redux` | `{ components, api, webVitals, redux, browser, errors }` |
91
+ | `thresholds` | renders 16 ms, API 1 000 ms, actions 16 ms, resources 1 000 ms, Google's Web Vitals | What counts as slow. |
92
+ | `transport` | `false` (local only) | `{ endpoint, headers?, batchSize? (20, max 100), flushInterval? (10 s), maxRetries? (5) }`, or your own `Transport`. |
93
+ | `maxBufferedEvents` | `500` (max 5 000) | Beyond this the oldest events are dropped, and the drop is counted and reported. |
94
+ | `devtools` | on unless production | Collects locally for the panel even in unsampled sessions, and shows `<PerformanceButton>`. |
95
+ | `components.recordRenders` | on unless production | In production only slow renders are sent. Every render is still aggregated. |
96
+ | `redux.recordActions` | on unless production | In production only slow actions are sent. |
97
+ | `api.ignoreUrls` | `[]` | URLs that are never measured. The SDK's own endpoint is always ignored. |
98
+ | `api.allowedQueryParams` | `[]` | Query parameter names whose values are kept. |
99
+ | `api.groupEndpoint` | none | Your own endpoint grouping, applied after the built-in templating. |
100
+ | `beforeSend` | none | Change an event, or drop it with `null`, before it is queued. |
101
+ | `debug` | `false` | `console.warn` for SDK problems, once per kind. |
102
+
103
+ An invalid config never throws. The monitor disables itself and warns once.
104
+
105
+ ## Collectors
106
+
107
+ Each collector is independent and has its own switch in `collectors`.
108
+
109
+ | Collector | Measures | Notes |
110
+ |---|---|---|
111
+ | `components` | React Profiler `actualDuration`, `baseDuration`, mount or update, per `<ProfiledBoundary id>` / `withProfiler()` | React reports timings only in development and in the `react-dom/profiling` build. In a normal production build the boundary is free but silent. |
112
+ | `api` | `fetch` and `XMLHttpRequest`: endpoint template, method, status, duration, success | It never reads headers or bodies. Its patches are removed on stop, but only if they are still the SDK's own. |
113
+ | `webVitals` | LCP, INP, CLS, FCP, TTFB via `web-vitals` | Each metric is reported once per page view, when final. Its rating comes from your thresholds. Missing APIs are shown as "not supported". |
114
+ | `redux` | Action type, dispatch time, whether state changed | Needs the `/redux` middleware. |
115
+ | `browser` | Navigation timing, slow or failed resources, long tasks, visibility, JS heap | Long tasks are Chromium-only and memory is Chromium's `performance.memory`. Both are marked unsupported elsewhere. At most 100 resources and 200 long tasks are sent per page. |
116
+ | `errors` | `error` and `unhandledrejection`: name, masked message, fingerprint | Stacks are not collected. Each error is sent at most 10× per page and then counted locally. Use an error tracker for full details. |
117
+
118
+ **What counts as measured and what is inferred.** Render counts and durations come straight from React. The
119
+ panel's "possibly unnecessary re-render" flag is a heuristic: many updates per mount, each costing close to a full
120
+ render (actual ≈ base). It is labelled **inferred**. The SDK does not claim to detect every unnecessary re-render.
121
+ Use React DevTools or React Scan to confirm.
122
+
123
+ ## Developer panel
124
+
125
+ `<PerformanceButton>` puts a floating button in the bottom-right corner. It opens a responsive panel with eight tabs:
126
+ Overview (warnings and recommendations), Components, Re-render analysis, API performance, Web Vitals, Redux, Browser
127
+ and Errors.
128
+
129
+ ```tsx
130
+ <PerformanceButton
131
+ theme="auto" // 'light' | 'dark' | 'auto'
132
+ themeOverrides={{ accent: '#7C3AED' }}
133
+ position="right"
134
+ loadCharts={() => import('@ashokreddydev/react-performance-monitor/charts')}
135
+ reactScan={scan} // optional: `import { scan } from 'react-scan'` adds an overlay toggle
136
+ />
137
+ ```
138
+
139
+ - The panel code (about 6 KB gzip) is downloaded the first time the button is clicked.
140
+ - Charts use Apache ECharts and load lazily. Large series are down-sampled (LTTB) and animation is switched off
141
+ above 500 points. Without `loadCharts` the panel shows simple built-in bars.
142
+ - In production the button renders nothing (`devtools` is off) unless you pass `force`.
143
+ - Accessibility: the panel is a labelled dialog, the tabs support arrow keys, Home and End, Escape closes the panel,
144
+ focus returns to the button, and no information is carried by colour alone.
145
+
146
+ ## Redux
147
+
148
+ ```ts
149
+ import { configureStore } from '@reduxjs/toolkit';
150
+ import { createPerformanceMiddleware } from '@ashokreddydev/react-performance-monitor/redux';
151
+
152
+ export const store = configureStore({
153
+ reducer,
154
+ middleware: (getDefault) => getDefault().concat(createPerformanceMiddleware({ ignore: [/^ui\//] })),
155
+ });
156
+ ```
157
+
158
+ Set `collectors: { redux: true }`. By default the middleware reports to the running monitor. Pass
159
+ `{ monitor }` to use a specific one, for example a `new PerformanceMonitor(config)` that you also give to
160
+ `<PerformanceProvider monitor={monitor}>`. Thunks pass through untouched, and errors from reducers propagate
161
+ unchanged.
162
+
163
+ ## Axios
164
+
165
+ The global XHR patch already measures Axios' browser adapter. Use the Axios integration when you need Axios' own
166
+ view instead: custom adapters, SSR, or `collectors.api` off. It claims each request, so nothing is counted twice.
167
+
168
+ ```ts
169
+ import { instrumentAxios } from '@ashokreddydev/react-performance-monitor/axios';
170
+ const stop = instrumentAxios(apiClient, monitor); // call stop() to remove the interceptors
171
+ ```
172
+
173
+ ## Hooks
174
+
175
+ ```tsx
176
+ const monitor = usePerformance(); // stable; never re-renders
177
+ monitor.setRoute('/orders/:id'); // call from your router on navigation
178
+ monitor.record({ eventType: 'long_task', duration: 120, data: { source: 'self' } });
179
+
180
+ const metrics = usePerformanceMetrics(); // live aggregates; re-renders at most every 500 ms
181
+ const slowest = useApiPerformance('/api/orders'); // API stats, filtered by endpoint
182
+ ```
183
+
184
+ Outside a provider the hooks return a disabled monitor, so shared components can call them safely.
185
+
186
+ ## Delivery
187
+
188
+ - **When batches go out.** A batch is sent when it is full, every `flushInterval`, and when the page is hidden or
189
+ closed.
190
+ - **Sending while the page closes.** Without custom headers the SDK uses `navigator.sendBeacon`. The body is sent
191
+ as `text/plain` to avoid a CORS preflight, so parse it as JSON. With headers it uses `fetch` with `keepalive`.
192
+ Cookies are never sent.
193
+ - **Retries.** Retries use exponential backoff with jitter: 1 s, 2 s, 4 s and so on, up to 60 s, 5 attempts by
194
+ default.
195
+ - `4xx` responses are not retried.
196
+ - `Retry-After` is honoured.
197
+ - A request that hangs for 30 s counts as failed.
198
+ - **Offline.** Nothing is sent while the browser is offline. Events wait in the bounded buffer.
199
+ - **Dropped events.** Drops are never silent. Every batch carries `dropped: { overflow, failed, filtered }`.
200
+
201
+ Each request body is one `PerformanceBatch`, with every event carrying its `eventType`, `timestamp`, `route`,
202
+ `duration?`, `data` and `metadata?`:
203
+
204
+ ```json
205
+ {
206
+ "schemaVersion": 1,
207
+ "applicationId": "my-app",
208
+ "environment": "production",
209
+ "release": "1.4.0",
210
+ "sessionId": "0f8fad5b-d9cb-469f-a165-70867728950e",
211
+ "sampleRate": 0.2,
212
+ "sentAt": 1794220000000,
213
+ "sdk": { "name": "react-performance-monitor", "version": "0.1.0" },
214
+ "dropped": { "overflow": 0, "failed": 0, "filtered": 0 },
215
+ "events": [
216
+ {
217
+ "eventType": "api_request",
218
+ "timestamp": 1794219999000,
219
+ "route": "/orders/:id",
220
+ "duration": 420,
221
+ "data": { "endpoint": "/api/orders/:id", "host": "", "method": "GET", "status": 200, "ok": true, "slow": false, "client": "fetch" }
222
+ }
223
+ ]
224
+ }
225
+ ```
226
+
227
+ On your server:
228
+ - Authenticate the request with your own key or cookie.
229
+ - Validate every field and cap the body at about 128 KB.
230
+ - Take the application id from your authentication, not from the body.
231
+ - Keep the data with a retention limit (TTL).
232
+
233
+ ## Privacy
234
+
235
+ What it collects:
236
+ - endpoint templates, methods, status codes and durations
237
+ - component names that you choose
238
+ - Redux action types
239
+ - masked error messages and fingerprints
240
+ - vitals and timings
241
+ - a random session id
242
+
243
+ It does not collect a user id. What it never collects:
244
+ - request or response headers or bodies, or cookies
245
+ - passwords
246
+ - Redux state or payloads
247
+ - stack traces
248
+ - query values that are not allow-listed
249
+
250
+ Sensitive-looking values (e-mails, card numbers, JWTs, phone numbers, government ids) are replaced with
251
+ `[REDACTED]`, and so is `metadata` whose key names look sensitive.
252
+
253
+ ## Performance overhead
254
+
255
+ | Measure | Value |
256
+ |---|---|
257
+ | `record()` per event (aggregation, sampling, buffer) | ~1–2 µs (measured over 50 000 events in CI) |
258
+ | Unsampled production session | collectors are not started, no listeners, no timers |
259
+ | Memory | buffer ≤ `maxBufferedEvents`, ≤ 100 keys per table plus `(other)`, 10-minute timeline, bounded quantile samples |
260
+ | Bundle, main entry (minified + gzip) | ~15 KB, plus `web-vitals` ~2 KB |
261
+ | Panel (lazy) / charts (lazy, excluding ECharts) | ~6 KB / ~2 KB |
262
+
263
+ ## Production checklist
264
+
265
+ - Set `environment` from your build (`import.meta.env.MODE`). Production turns off `devtools`, `recordRenders` and
266
+ `recordActions`.
267
+ - Pick a `sampleRate`, for example `0.1`–`0.3`.
268
+ - Use an authenticated, rate-limited endpoint with a body limit and retention.
269
+ - Wrap only the parts of the tree you care about in `<ProfiledBoundary>`. For production render timings, use the
270
+ `react-dom/profiling` build only if you need it.
271
+
272
+ ## Troubleshooting
273
+
274
+ | Symptom | Cause and fix |
275
+ |---|---|
276
+ | No component data | React reports Profiler timings only in development or `react-dom/profiling`, and only inside `<ProfiledBoundary>`. |
277
+ | A Web Vital stays "waiting…" | Vitals are final when the page is hidden. INP needs an interaction. LCP and INP are not supported in every browser. |
278
+ | A metric shows "not supported" | The browser lacks the API (for example `longtask` or `memory` outside Chromium). The value is never shown as 0. |
279
+ | Requests counted twice | You use `instrumentAxios` *and* a non-claiming wrapper. Use one, or set `collectors.api: false`. |
280
+ | Nothing is sent | Check that the session is sampled (the panel chip says "sending" or "local only"), that `transport` is set, and run `debug: true`. |
281
+ | Beacon requests fail on the server | Parse `text/plain` bodies as JSON. |
282
+
283
+ ## Custom collectors
284
+
285
+ ```ts
286
+ import type { Collector } from '@ashokreddydev/react-performance-monitor';
287
+
288
+ export const longTasks: Collector = {
289
+ name: 'browser',
290
+ start(ctx) {
291
+ if (typeof PerformanceObserver === 'undefined') {
292
+ ctx.markUnsupported('longtask');
293
+ return undefined;
294
+ }
295
+ const po = new PerformanceObserver((list) => {
296
+ for (const e of list.getEntries())
297
+ ctx.record({ eventType: 'long_task', duration: e.duration, data: { source: e.name } });
298
+ });
299
+ po.observe({ type: 'longtask', buffered: true });
300
+ return () => po.disconnect(); // always clean up
301
+ },
302
+ };
303
+ ```
304
+
305
+ Pass collectors with `<PerformanceProvider collectors={[longTasks]} builtInCollectors={false} />`. A collector that
306
+ throws is contained, and reported when `debug` is on. It never stops the other collectors or your app.
307
+
308
+ ## License
309
+
310
+ MIT
@@ -0,0 +1,183 @@
1
+ import { C as CollectorName, T as Transport, H as HttpTransportOptions, P as PerformanceMonitorConfig } from './config-Cie78aAE.cjs';
2
+ import { P as PerformanceThresholds, a as PerformanceEvent, f as PerformanceEventInput } from './performanceThresholds-B8-ZCvDG.cjs';
3
+ import { M as MetricsSnapshot } from './metrics-LC7_GsyQ.cjs';
4
+
5
+ /** Config after validation: every field present, every number inside its safe range. */
6
+ interface ResolvedPerformanceConfig {
7
+ applicationId: string;
8
+ environment: string;
9
+ release: string | undefined;
10
+ enabled: boolean;
11
+ sampleRate: number;
12
+ collectors: Readonly<Record<CollectorName, boolean>>;
13
+ thresholds: PerformanceThresholds;
14
+ /** null = local only (no telemetry leaves the page). */
15
+ transport: Transport | HttpTransportOptions | null;
16
+ batchSize: number;
17
+ flushInterval: number;
18
+ maxRetries: number;
19
+ maxBufferedEvents: number;
20
+ devtools: boolean;
21
+ recordRenders: boolean;
22
+ recordActions: boolean;
23
+ api: {
24
+ ignoreUrls: readonly (string | RegExp)[];
25
+ allowedQueryParams: readonly string[];
26
+ groupEndpoint: ((endpoint: string) => string) | undefined;
27
+ };
28
+ beforeSend: ((event: PerformanceEvent) => PerformanceEvent | null) | undefined;
29
+ debug: boolean;
30
+ }
31
+ declare const COLLECTOR_NAMES: readonly CollectorName[];
32
+ /** A problem found in the config. The monitor does not throw on bad config — it disables itself and warns once. */
33
+ declare class PerformanceConfigError extends Error {
34
+ readonly name = "PerformanceConfigError";
35
+ }
36
+ /**
37
+ * Validates and fills defaults. Throws `PerformanceConfigError` only for things that cannot be defaulted
38
+ * (missing/invalid `applicationId`, invalid transport endpoint); `PerformanceMonitor` catches it and stays disabled.
39
+ */
40
+ declare function resolveConfig(input: PerformanceMonitorConfig): ResolvedPerformanceConfig;
41
+
42
+ declare const SDK_NAME = "react-performance-monitor";
43
+ declare const SDK_VERSION: string;
44
+ /** What a collector gets. Everything here is safe to call at any time — it never throws. */
45
+ interface CollectorContext {
46
+ readonly config: ResolvedPerformanceConfig;
47
+ record(event: PerformanceEventInput, metadata?: Record<string, unknown>, options?: RecordOptions): void;
48
+ /** Current route template (e.g. `/orders/:id`). */
49
+ getRoute(): string;
50
+ /** true for the monitor's own telemetry requests and `api.ignoreUrls` — never measure these. */
51
+ isIgnoredUrl(url: string): boolean;
52
+ /** true when an integration (e.g. Axios) already measures this request — skip it. */
53
+ consumeClaim(method: string, url: string): boolean;
54
+ /** Tell the panel a browser API is missing (shown as "not supported", never as zero). */
55
+ markUnsupported(feature: string): void;
56
+ now(): number;
57
+ /** Report a problem inside the collector without breaking the host app. */
58
+ reportError(where: string, error: unknown): void;
59
+ }
60
+ interface RecordOptions {
61
+ /** Aggregate for the panel and hooks only; never sent (used for high-frequency, non-slow events). */
62
+ localOnly?: boolean;
63
+ }
64
+ /** The most recently started monitor — what `createPerformanceMiddleware()` uses when not given one. */
65
+ declare function getActiveMonitor(): PerformanceMonitor | null;
66
+ /** One independent measurement source. `start` returns its cleanup (observers, listeners, patches). */
67
+ interface Collector {
68
+ readonly name: CollectorName;
69
+ start(ctx: CollectorContext): (() => void) | undefined;
70
+ }
71
+ interface PerformanceMonitorDeps {
72
+ /** Overrides the transport from the config (tests, custom delivery). */
73
+ transport?: Transport;
74
+ now?: () => number;
75
+ random?: () => number;
76
+ /** How often subscribers (panel, hooks) are told about new metrics. Default 500 ms. */
77
+ notifyIntervalMs?: number;
78
+ /** A send that takes longer counts as failed and is retried (a hanging request never blocks delivery). Default 30 s. */
79
+ sendTimeoutMs?: number;
80
+ }
81
+ /**
82
+ * The runtime: owns the config, session, sampling decision, collectors, buffer, aggregation and delivery.
83
+ * Rules: it never throws into the host app, holds a bounded amount of memory, and cleans up everything on `stop()`.
84
+ */
85
+ declare class PerformanceMonitor {
86
+ /** null when the config was invalid — the monitor is then a no-op. */
87
+ readonly config: ResolvedPerformanceConfig | null;
88
+ /** `config`, or a disabled stand-in when it was invalid — so internals never deal with null. */
89
+ private readonly settings;
90
+ readonly sessionId: string;
91
+ /** This session sends telemetry (decided once per session from `sampleRate`). */
92
+ readonly sampled: boolean;
93
+ private readonly now;
94
+ private readonly random;
95
+ private readonly transport;
96
+ private readonly ownUrls;
97
+ private readonly buffer;
98
+ private readonly aggregate;
99
+ private readonly collectors;
100
+ private readonly cleanups;
101
+ private readonly listeners;
102
+ private readonly notify;
103
+ private readonly warned;
104
+ private readonly sendTimeoutMs;
105
+ private published;
106
+ private running;
107
+ private stopped;
108
+ private readonly claims;
109
+ private recordingDepth;
110
+ private route;
111
+ private pendingDropped;
112
+ private inflight;
113
+ private retry;
114
+ private retryTimer;
115
+ private flushTimer;
116
+ private soonTimer;
117
+ private detachWindow;
118
+ /** Internal problems so far (shown in the panel; never thrown). */
119
+ internalErrors: number;
120
+ constructor(config: PerformanceMonitorConfig, deps?: PerformanceMonitorDeps);
121
+ private transportOrThrow;
122
+ /** A monitor that does nothing — what hooks use outside a `<PerformanceProvider>`. */
123
+ static disabled(): PerformanceMonitor;
124
+ /** Telemetry leaves the page in this session. */
125
+ get sending(): boolean;
126
+ /** Collectors run: sending, or the developer panel needs local data. */
127
+ get collecting(): boolean;
128
+ get isRunning(): boolean;
129
+ /** The collector is switched on and this session collects (cheap check for hot paths, e.g. Redux, Profiler). */
130
+ isEnabled(name: CollectorName): boolean;
131
+ /**
132
+ * An integration that measures a request itself (e.g. Axios interceptors) claims it, so the global fetch/XHR
133
+ * patch skips the same request — no double counting. Claims expire after 60 s.
134
+ */
135
+ claimRequest(method: string, url: string): void;
136
+ /** true (and removes the claim) when an integration already measures this request. */
137
+ consumeClaim(method: string, url: string): boolean;
138
+ private absolute;
139
+ /** Register a collector (once per name). Skipped when switched off in `config.collectors`. */
140
+ use(collector: Collector): this;
141
+ start(): void;
142
+ /** Stops collectors, timers and listeners; sends what is buffered. Safe to call twice; `start()` works again. */
143
+ stop(): void;
144
+ /** The route attached to new events. Routers call this on navigation; default is the templated `location.pathname`. */
145
+ setRoute(route: string): void;
146
+ getRoute(): string;
147
+ /**
148
+ * Add one event. Never throws. Accepted from construction on (React Profiler callbacks fire before the provider's
149
+ * effect starts the monitor), ignored after `stop()` and when this session does not collect.
150
+ */
151
+ record(input: PerformanceEventInput, metadata?: Record<string, unknown>, options?: RecordOptions): void;
152
+ /** Per-render events are sent only when `recordRenders` is on; slow renders always are. */
153
+ private shouldSend;
154
+ private enqueue;
155
+ private countDropped;
156
+ private takeDropped;
157
+ private returnDropped;
158
+ private batch;
159
+ /**
160
+ * Sends buffered events. Normal flush: one batch at a time, failed batches retried with backoff.
161
+ * Unloading: everything left is handed to `sendBeacon`/`keepalive` at once, without waiting or retrying.
162
+ */
163
+ flush(options?: {
164
+ unloading?: boolean;
165
+ }): Promise<void>;
166
+ private deliver;
167
+ private flushUnloading;
168
+ private returnDroppedInto;
169
+ /** Stable function — pass straight to `useSyncExternalStore`. */
170
+ readonly subscribe: (listener: () => void) => (() => void);
171
+ /** Stable function; returns the same object until new metrics are published (at most every `notifyIntervalMs`). */
172
+ readonly getSnapshot: () => MetricsSnapshot;
173
+ /** Number of events waiting to be sent. */
174
+ get bufferedCount(): number;
175
+ private publish;
176
+ private context;
177
+ private startCollector;
178
+ isIgnoredUrl(url: string): boolean;
179
+ private reportError;
180
+ private warnOnce;
181
+ }
182
+
183
+ export { type Collector as C, PerformanceMonitor as P, type RecordOptions as R, SDK_NAME as S, COLLECTOR_NAMES as a, type CollectorContext as b, PerformanceConfigError as c, type PerformanceMonitorDeps as d, type ResolvedPerformanceConfig as e, SDK_VERSION as f, getActiveMonitor as g, resolveConfig as r };