react-render-pulse 1.0.1 → 1.0.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/README.md CHANGED
@@ -173,6 +173,8 @@ Measures the renders of its children as one area named `id`. Areas with the same
173
173
 
174
174
  Measures the component that calls it. Render counts are exact. The duration runs from the hook to the commit, so it's an upper bound that can include components rendered after it in the same update.
175
175
 
176
+ Don't use it in a component that renders before the rest of the page, such as a header or layout: on the first render its duration covers the whole page, and long frames during page load are blamed on it. Put `<RenderMonitor>` inside the component instead, around what it returns; below the component's state, it still measures the component's own updates.
177
+
176
178
  ### Exporters
177
179
 
178
180
  An exporter receives data as it's measured:
@@ -305,10 +307,22 @@ The client is 3.6 kB brotli (`initRenderPulse` + `RenderMonitor` + `useRenderMon
305
307
  ## Limitations
306
308
 
307
309
  - Lightweight mode doesn't see updates that start below an area, such as a child's own state change. Monitor the component that owns the state, or use profiling mode for those sessions.
308
- - `useRenderMonitor` durations are an upper bound. Use `<RenderMonitor>` around the component for its own render time.
310
+ - `useRenderMonitor` durations are an upper bound. Use `<RenderMonitor>` around the component for its own render time, and never use the hook in a header or layout that renders before the rest of the page.
309
311
  - Long tasks are observed only where the browser supports them: Chromium for long tasks and long animation frames. Other browsers still report render timings.
310
312
  - Profiling mode needs React's profiling build, which is slower than the regular build. Ship it to a sample, not everyone.
311
313
 
314
+ ## What's next
315
+
316
+ Planned for v1.5 (no dates; plans can change):
317
+
318
+ - Slow interactions (INP) attributed to the component areas that caused them
319
+ - Separate timings for first renders and updates in each area
320
+ - Release comparisons: which areas got faster or slower between two app versions
321
+ - Render budgets checked in pull requests, with a GitHub Action
322
+ - Regression alerts by webhook, and adaptive sampling (more data from slow devices)
323
+
324
+ Full list: [ROADMAP.md](https://github.com/Amalmktk/react-render-pulse/blob/main/ROADMAP.md). Ideas and feedback are welcome in [issues](https://github.com/Amalmktk/react-render-pulse/issues).
325
+
312
326
  ## Related packages
313
327
 
314
328
  - [`react-render-pulse-collector`](https://www.npmjs.com/package/react-render-pulse-collector): validates and stores batches (Postgres, JSON file, custom)
@@ -5,5 +5,8 @@
5
5
  * commit, so it also includes anything React renders after this component
6
6
  * in the same update: an upper bound. Wrap the component in `<RenderMonitor>`
7
7
  * when you need its own render time.
8
+ *
9
+ * Don't use it in a component that renders before the rest of the page, such
10
+ * as a header or layout: on the first render its duration covers the whole page.
8
11
  */
9
12
  export declare function useRenderMonitor(id: string): void;
@@ -5,6 +5,9 @@
5
5
  * commit, so it also includes anything React renders after this component
6
6
  * in the same update: an upper bound. Wrap the component in `<RenderMonitor>`
7
7
  * when you need its own render time.
8
+ *
9
+ * Don't use it in a component that renders before the rest of the page, such
10
+ * as a header or layout: on the first render its duration covers the whole page.
8
11
  */
9
12
  export declare function useRenderMonitor(id: string): void;
10
13
  //# sourceMappingURL=useRenderMonitor.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useRenderMonitor.d.ts","sourceRoot":"","sources":["../../src/hooks/useRenderMonitor.ts"],"names":[],"mappings":"AAOA;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAgBjD"}
1
+ {"version":3,"file":"useRenderMonitor.d.ts","sourceRoot":"","sources":["../../src/hooks/useRenderMonitor.ts"],"names":[],"mappings":"AAOA;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAgBjD"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/aggregate/histogram.ts","../src/aggregate/aggregator.ts","../src/context/device.ts","../src/context/route.ts","../src/export/console.ts","../src/modes/detect.ts","../src/observe/longtasks.ts","../src/observe/renderWindows.ts","../src/sample/sample.ts","../src/transport/payload.ts","../src/transport/transport.ts","../src/runtime/guard.ts","../src/runtime/runtime.ts","../src/runtime/initRenderPulse.ts","../src/components/RenderMonitor.tsx","../src/runtime/useIsomorphicLayoutEffect.ts","../src/hooks/useRenderMonitor.ts"],"sourcesContent":["export type {\n AreaReport,\n DeviceContext,\n Exporter,\n LongTaskEvent,\n LongTaskKind,\n LongTaskReport,\n Mode,\n ModeOption,\n Payload,\n RenderEvent,\n RenderPhase,\n SessionInfo,\n SessionSummary,\n WorstCase,\n} from \"./types.js\";\nexport { HISTOGRAM_BOUNDS, histogramPercentile } from \"./aggregate/histogram.js\";\n\nexport { initRenderPulse } from \"./runtime/initRenderPulse.js\";\nexport type { RenderPulse, RenderPulseOptions } from \"./runtime/initRenderPulse.js\";\nexport { createConsoleExporter } from \"./export/console.js\";\n\nexport { RenderMonitor } from \"./components/RenderMonitor.js\";\nexport type { RenderMonitorProps } from \"./components/RenderMonitor.js\";\nexport { useRenderMonitor } from \"./hooks/useRenderMonitor.js\";\n","/**\n * Upper bounds (ms, inclusive) of the render-duration histogram buckets, plus\n * an implicit overflow bucket. Part of payload v1: the collector merges\n * histograms by index, so changing these needs a new payload version.\n */\nexport const HISTOGRAM_BOUNDS = [1, 2, 4, 8, 12, 16, 24, 33, 50, 75, 100, 150, 250, 500, 1000] as const;\n\nexport function createHistogram(): number[] {\n return new Array<number>(HISTOGRAM_BOUNDS.length + 1).fill(0);\n}\n\nexport function bucketIndex(ms: number): number {\n for (let i = 0; i < HISTOGRAM_BOUNDS.length; i++) {\n if (ms <= (HISTOGRAM_BOUNDS[i] ?? 0)) return i;\n }\n return HISTOGRAM_BOUNDS.length;\n}\n\n/**\n * Estimates a percentile (0–100) from bucket counts, interpolating linearly\n * inside the bucket. The observed `min` and `max` narrow the bucket's range\n * (every value lies between them): without them, durations clustered at a\n * bucket edge, like many renders of exactly 8 ms, would be estimated from\n * the bucket's middle instead.\n */\nexport function histogramPercentile(hist: readonly number[], p: number, max: number, min = 0): number {\n const total = hist.reduce((sum, n) => sum + n, 0);\n if (total === 0) return 0;\n\n const target = Math.max((p / 100) * total, Number.MIN_VALUE);\n let seen = 0;\n\n for (let i = 0; i < hist.length; i++) {\n const count = hist[i] ?? 0;\n if (count === 0) continue;\n\n if (seen + count >= target) {\n const upper = Math.min(HISTOGRAM_BOUNDS[i] ?? max, max);\n const lower = Math.min(Math.max(i === 0 ? 0 : (HISTOGRAM_BOUNDS[i - 1] ?? 0), min), upper);\n const fraction = (target - seen) / count;\n return round(Math.min(lower + (upper - lower) * fraction, max));\n }\n\n seen += count;\n }\n\n return round(max);\n}\n\n/** Rounds to 0.1 ms: finer precision isn't meaningful and costs payload bytes. */\nexport function round(ms: number): number {\n return Math.round(ms * 10) / 10;\n}\n","import { bucketIndex, createHistogram, histogramPercentile, round } from \"./histogram.js\";\nimport type { AreaReport, LongTaskEvent, LongTaskReport, RenderEvent, SessionSummary, WorstCase } from \"../types.js\";\n\nexport interface AggregatorOptions {\n /** Renders slower than this count as slow. */\n slowRenderMs: number;\n /** Most distinct area/route pairs kept per batch; renders for new ones past this are dropped. */\n maxAreas: number;\n /** How many of the slowest renders to keep per area. */\n worstCases: number;\n /** `performance.now()` at session start, so worst cases report time since then. */\n sessionStart: number;\n}\n\nexport interface AggregatedBatch {\n summary: SessionSummary;\n areas: AreaReport[];\n longTasks: LongTaskReport[];\n longFrames: LongTaskReport[];\n droppedAreas: number;\n}\n\nexport interface Aggregator {\n addRender: (event: RenderEvent) => void;\n addLongTask: (event: LongTaskEvent) => void;\n /** True when nothing was recorded since the last `drain()`. */\n isEmpty: () => boolean;\n /** Returns everything recorded since the last call, and starts a new batch. */\n drain: () => AggregatedBatch;\n}\n\ninterface AreaAccumulator {\n id: string;\n route: string;\n renders: number;\n mounts: number;\n slow: number;\n totalMs: number;\n min: number;\n max: number;\n hist: number[];\n worst: WorstCase[];\n}\n\ninterface LongTaskAccumulator {\n area: string | null;\n route: string;\n count: number;\n totalMs: number;\n maxMs: number;\n}\n\n// Only counts, histograms, and a few worst cases are kept, never raw event\n// streams, so memory stays flat however long the session runs.\nexport function createAggregator(options: AggregatorOptions): Aggregator {\n let areas = new Map<string, AreaAccumulator>();\n let longTasks = new Map<string, LongTaskAccumulator>();\n let longFrames = new Map<string, LongTaskAccumulator>();\n let droppedAreas = 0;\n\n function addRender(event: RenderEvent): void {\n const key = `${event.route}\\u0000${event.area}`;\n let area = areas.get(key);\n\n if (!area) {\n if (areas.size >= options.maxAreas) {\n droppedAreas++;\n return;\n }\n area = {\n id: event.area,\n route: event.route,\n renders: 0,\n mounts: 0,\n slow: 0,\n totalMs: 0,\n min: Infinity,\n max: 0,\n hist: createHistogram(),\n worst: [],\n };\n areas.set(key, area);\n }\n\n const ms = event.duration;\n area.renders++;\n if (event.phase === \"mount\") area.mounts++;\n if (ms > options.slowRenderMs) area.slow++;\n area.totalMs += ms;\n area.min = Math.min(area.min, ms);\n area.max = Math.max(area.max, ms);\n const bucket = bucketIndex(ms);\n area.hist[bucket] = (area.hist[bucket] ?? 0) + 1;\n addWorstCase(area.worst, { ms, phase: event.phase, at: event.startTime - options.sessionStart });\n }\n\n function addWorstCase(worst: WorstCase[], candidate: WorstCase): void {\n if (worst.length < options.worstCases) {\n worst.push(candidate);\n } else {\n const fastest = worst.reduce((min, w, i) => (w.ms < (worst[min]?.ms ?? 0) ? i : min), 0);\n if (candidate.ms <= (worst[fastest]?.ms ?? 0)) return;\n worst[fastest] = candidate;\n }\n }\n\n function addLongTask(event: LongTaskEvent): void {\n const target = event.kind === \"longtask\" ? longTasks : longFrames;\n const key = `${event.route}\\u0000${event.area ?? \"\"}`;\n let entry = target.get(key);\n\n if (!entry) {\n entry = { area: event.area, route: event.route, count: 0, totalMs: 0, maxMs: 0 };\n target.set(key, entry);\n }\n\n entry.count++;\n entry.totalMs += event.duration;\n entry.maxMs = Math.max(entry.maxMs, event.duration);\n }\n\n function drain(): AggregatedBatch {\n const areaReports = Array.from(areas.values(), toAreaReport);\n const taskReports = Array.from(longTasks.values(), toLongTaskReport);\n const frameReports = Array.from(longFrames.values(), toLongTaskReport);\n\n const batch: AggregatedBatch = {\n summary: {\n renders: sum(areaReports, (a) => a.renders),\n slowRenders: sum(areaReports, (a) => a.slow),\n longTasks: sum(taskReports, (t) => t.count),\n longTaskMs: round(sum(taskReports, (t) => t.totalMs)),\n longFrames: sum(frameReports, (t) => t.count),\n longFrameMs: round(sum(frameReports, (t) => t.totalMs)),\n },\n areas: areaReports,\n longTasks: taskReports,\n longFrames: frameReports,\n droppedAreas,\n };\n\n areas = new Map();\n longTasks = new Map();\n longFrames = new Map();\n droppedAreas = 0;\n return batch;\n }\n\n return {\n addRender,\n addLongTask,\n isEmpty: () => areas.size === 0 && longTasks.size === 0 && longFrames.size === 0 && droppedAreas === 0,\n drain,\n };\n}\n\nfunction toAreaReport(area: AreaAccumulator): AreaReport {\n return {\n id: area.id,\n route: area.route,\n renders: area.renders,\n mounts: area.mounts,\n slow: area.slow,\n totalMs: round(area.totalMs),\n min: round(area.min),\n max: round(area.max),\n p50: histogramPercentile(area.hist, 50, area.max, area.min),\n p75: histogramPercentile(area.hist, 75, area.max, area.min),\n p95: histogramPercentile(area.hist, 95, area.max, area.min),\n hist: area.hist,\n worst: area.worst\n .sort((a, b) => b.ms - a.ms)\n .map((w) => ({ ms: round(w.ms), phase: w.phase, at: Math.round(w.at) })),\n };\n}\n\nfunction toLongTaskReport(entry: LongTaskAccumulator): LongTaskReport {\n return { ...entry, totalMs: round(entry.totalMs), maxMs: round(entry.maxMs) };\n}\n\nfunction sum<T>(items: readonly T[], pick: (item: T) => number): number {\n return items.reduce((total, item) => total + pick(item), 0);\n}\n","import type { DeviceContext } from \"../types.js\";\n\n// Non-standard APIs (Chromium only), so they're read defensively.\ninterface NavigatorWithHints {\n deviceMemory?: number;\n hardwareConcurrency?: number;\n connection?: { effectiveType?: string };\n}\n\nexport function getDeviceContext(): DeviceContext {\n const nav = (typeof navigator === \"undefined\" ? {} : navigator) as NavigatorWithHints;\n\n return {\n memoryGb: typeof nav.deviceMemory === \"number\" ? nav.deviceMemory : null,\n cores: typeof nav.hardwareConcurrency === \"number\" ? nav.hardwareConcurrency : null,\n connection: nav.connection?.effectiveType ?? null,\n viewport: typeof window === \"undefined\" ? \"0x0\" : `${window.innerWidth}x${window.innerHeight}`,\n };\n}\n","/** Default route reader: the path with numeric segments replaced, so `/orders/42` and `/orders/7` group together. */\nexport function defaultGetRoute(): string {\n if (typeof location === \"undefined\") return \"/\";\n return location.pathname.replace(/\\/\\d+(?=\\/|$)/g, \"/:id\");\n}\n\n/**\n * Wraps a route reader so it only runs when the URL changes, since it's\n * called on every measured render.\n */\nexport function createRouteReader(getRoute: () => string): () => string {\n let lastHref: string | null = null;\n let lastRoute = \"/\";\n\n return () => {\n const href = typeof location === \"undefined\" ? \"\" : location.href;\n if (href !== lastHref) {\n lastHref = href;\n lastRoute = getRoute();\n }\n return lastRoute;\n };\n}\n","import type { Exporter } from \"../types.js\";\n\n/** Logs each batch as a table, slowest areas first. Used by default when no `endpoint` is set, for local testing. */\nexport function createConsoleExporter(): Exporter {\n return {\n onFlush(payload) {\n if (typeof console === \"undefined\") return;\n\n const rows = [...payload.areas]\n .sort((a, b) => b.p75 - a.p75)\n .map((a) => ({\n area: a.id,\n route: a.route,\n renders: a.renders,\n slow: a.slow,\n p50: a.p50,\n p75: a.p75,\n p95: a.p95,\n max: a.max,\n }));\n\n console.groupCollapsed(\n `[render-pulse] batch ${payload.session.seq} (${payload.session.mode}): ${payload.summary.renders} renders, ${payload.summary.longTasks} long tasks`,\n );\n if (rows.length > 0) console.table(rows);\n if (payload.longTasks.length > 0) console.table(payload.longTasks);\n if (payload.longFrames.length > 0) console.table(payload.longFrames);\n console.groupEnd();\n },\n };\n}\n","import type { Mode, ModeOption } from \"../types.js\";\n\nexport interface ModeDetector {\n /** The mode measurements are currently taken in. */\n current: () => Mode;\n /** True when the performance-mark measurements in `<RenderMonitor>` should run. */\n measuresWithMarks: () => boolean;\n /** Called on every `<Profiler>` callback; in `\"auto\"` mode the first one switches to profiling mode. */\n profilerFired: () => void;\n}\n\n/**\n * React only calls `<Profiler onRender>` in development and in its profiling\n * build, so a callback arriving is proof that per-subtree timings are\n * available. There's no public API to ask which build is loaded, and this\n * avoids relying on React internals.\n */\nexport function createModeDetector(option: ModeOption): ModeDetector {\n let mode: Mode = option === \"profiling\" ? \"profiling\" : \"lightweight\";\n\n return {\n current: () => mode,\n measuresWithMarks: () => mode === \"lightweight\",\n profilerFired() {\n if (option === \"auto\") mode = \"profiling\";\n },\n };\n}\n","import type { LongTaskKind } from \"../types.js\";\n\nexport interface ObservedLongTask {\n kind: LongTaskKind;\n startTime: number;\n duration: number;\n}\n\n/**\n * Observes long tasks (Chromium) and long animation frames (Chromium 123+)\n * at or above `thresholdMs`. Entry types the browser doesn't support are\n * skipped. Returns a function that stops observing.\n */\nexport function observeLongTasks(thresholdMs: number, onEntry: (task: ObservedLongTask) => void): () => void {\n if (typeof PerformanceObserver === \"undefined\") return () => {};\n\n const supported = PerformanceObserver.supportedEntryTypes ?? [];\n const observers: PerformanceObserver[] = [];\n\n for (const kind of [\"longtask\", \"long-animation-frame\"] as const) {\n if (!supported.includes(kind)) continue;\n\n try {\n const observer = new PerformanceObserver((list) => {\n for (const entry of list.getEntries()) {\n if (entry.duration < thresholdMs) continue;\n onEntry({ kind, startTime: entry.startTime, duration: entry.duration });\n }\n });\n observer.observe({ type: kind, buffered: true });\n observers.push(observer);\n } catch {\n // Observing is best-effort; a browser quirk here must not reach the app.\n }\n }\n\n return () => {\n for (const observer of observers) observer.disconnect();\n };\n}\n","interface RenderWindow {\n area: string;\n start: number;\n end: number;\n duration: number;\n}\n\nexport interface RenderWindows {\n /** Records that `area` rendered for `duration` ms somewhere between `start` and `end`. */\n add: (area: string, start: number, end: number, duration: number) => void;\n /** The area to blame for a main-thread block over `[start, end]`, or `null` when no recent render overlaps it. */\n findArea: (start: number, end: number) => string | null;\n}\n\n/**\n * A fixed-size ring of recent render windows. Long-task entries arrive a\n * little after the fact, so attribution looks back over the last `size` renders.\n *\n * Nested areas overlap the same block, and an outer area's duration includes\n * its inner ones. So the blame goes to the innermost overlapping area that\n * still accounts for at least half of the longest overlapping render: an\n * inner area that's responsible for most of the time, rather than always the\n * outermost wrapper or a tiny sibling that happened to render in the same commit.\n */\nexport function createRenderWindows(size = 200): RenderWindows {\n const windows: (RenderWindow | undefined)[] = new Array(size);\n let next = 0;\n\n return {\n add(area, start, end, duration) {\n windows[next] = { area, start, end, duration };\n next = (next + 1) % size;\n },\n findArea(start, end) {\n const overlapping = windows.filter((w): w is RenderWindow => w !== undefined && w.end >= start && w.start <= end);\n if (overlapping.length === 0) return null;\n\n const longest = Math.max(...overlapping.map((w) => w.duration));\n let best: RenderWindow | null = null;\n\n for (const window of overlapping) {\n if (window.duration < longest / 2) continue;\n if (!best || window.duration < best.duration) best = window;\n }\n\n return best?.area ?? null;\n },\n };\n}\n","/**\n * Decides once per session whether to collect, so unsampled sessions pay\n * almost nothing. `sampleRate` is clamped to 0–1.\n */\nexport function shouldSample(sampleRate: number, random: () => number = Math.random): boolean {\n if (!(sampleRate > 0)) return false;\n if (sampleRate >= 1) return true;\n return random() < sampleRate;\n}\n\n/** A random session id. Not derived from anything about the user, and never persisted. */\nexport function createSessionId(): string {\n try {\n // randomUUID only exists in secure contexts (HTTPS, localhost).\n const cryptoApi = globalThis.crypto as Crypto | undefined;\n if (cryptoApi && typeof cryptoApi.randomUUID === \"function\") return cryptoApi.randomUUID();\n } catch {\n // Fall through to the non-crypto id.\n }\n return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;\n}\n","import type { Payload } from \"../types.js\";\n\nexport function byteLength(text: string): number {\n return typeof TextEncoder === \"undefined\" ? text.length * 3 : new TextEncoder().encode(text).length;\n}\n\n/**\n * Serializes a payload, shrinking it until it fits in `maxBytes`: first the\n * worst-case lists go, then the areas with the fewest renders. Returns `null`\n * when even an empty payload doesn't fit.\n */\nexport function serializePayload(payload: Payload, maxBytes: number): string | null {\n let json = JSON.stringify(payload);\n if (byteLength(json) <= maxBytes) return json;\n\n let trimmed: Payload = { ...payload, areas: payload.areas.map((a) => ({ ...a, worst: [] })) };\n json = JSON.stringify(trimmed);\n\n if (byteLength(json) > maxBytes) {\n const areas = [...trimmed.areas].sort((a, b) => b.renders - a.renders);\n let dropped = trimmed.dropped.areas;\n\n // Halve the kept areas until it fits, then the list is short enough to stop.\n while (areas.length > 0 && byteLength(json) > maxBytes) {\n const remove = Math.max(1, Math.floor(areas.length / 2));\n areas.splice(areas.length - remove, remove);\n dropped += remove;\n trimmed = { ...trimmed, areas: [...areas], dropped: { areas: dropped } };\n json = JSON.stringify(trimmed);\n }\n }\n\n return byteLength(json) <= maxBytes ? json : null;\n}\n","export interface TransportOptions {\n endpoint: string;\n /** Failed sends are retried on later flushes, up to this many attempts in total. */\n maxAttempts: number;\n /** Most failed bodies kept for retry; the oldest are dropped past this. */\n maxQueued: number;\n}\n\nexport interface Transport {\n /**\n * Sends a serialized payload. With `unloading`, uses `navigator.sendBeacon`\n * (falling back to `fetch` with `keepalive`), since the page may be gone\n * before a normal request finishes. Never throws or rejects.\n */\n send: (body: string, options: { unloading: boolean }) => void;\n}\n\ninterface QueuedBody {\n body: string;\n attempts: number;\n}\n\nexport function createTransport(options: TransportOptions): Transport {\n const queue: QueuedBody[] = [];\n\n function enqueue(item: QueuedBody): void {\n if (item.attempts >= options.maxAttempts) return;\n queue.push(item);\n if (queue.length > options.maxQueued) queue.shift();\n }\n\n function beacon(body: string): boolean {\n try {\n // A string body is sent as text/plain, a CORS-safelisted type, so\n // cross-origin collectors don't need a preflight the beacon can't do.\n return typeof navigator !== \"undefined\" && typeof navigator.sendBeacon === \"function\"\n ? navigator.sendBeacon(options.endpoint, body)\n : false;\n } catch {\n return false;\n }\n }\n\n function post(item: QueuedBody): void {\n if (typeof fetch !== \"function\") return;\n const attempt = { body: item.body, attempts: item.attempts + 1 };\n\n try {\n fetch(options.endpoint, { method: \"POST\", body: item.body, keepalive: true })\n .then((response) => {\n // 4xx means the collector rejected the payload; retrying won't help.\n if (response.status >= 500 || response.status === 429) enqueue(attempt);\n })\n .catch(() => enqueue(attempt));\n } catch {\n enqueue(attempt);\n }\n }\n\n return {\n send(body, { unloading }) {\n const items = [...queue.splice(0), { body, attempts: 0 }];\n\n for (const item of items) {\n if (unloading && beacon(item.body)) continue;\n post(item);\n }\n },\n };\n}\n","let debug = false;\n\nexport function setDebug(value: boolean): void {\n debug = value;\n}\n\n/**\n * Runs `fn`, swallowing anything it throws, so an error inside render-pulse\n * (or a user-supplied exporter or `getRoute`) never reaches the app. With\n * `debug`, the error is logged instead of silently dropped.\n */\nexport function guard<T>(fn: () => T, fallback: T): T {\n try {\n return fn();\n } catch (error) {\n if (debug && typeof console !== \"undefined\") console.warn(\"[render-pulse]\", error);\n return fallback;\n }\n}\n","import type { RenderPhase } from \"../types.js\";\n\n/** What `<RenderMonitor>` and `useRenderMonitor` call into. Every method is safe to call and never throws. */\nexport interface PulseRuntime {\n readonly sampled: boolean;\n /** True when `<RenderMonitor>` should take performance-mark measurements (lightweight mode). */\n measuresWithMarks: () => boolean;\n now: () => number;\n recordMarks: (area: string, phase: RenderPhase, start: number, end: number) => void;\n /** Returns true when the measurement was recorded, i.e. the session is in profiling mode. */\n recordProfiler: (\n area: string,\n phase: RenderPhase,\n actualDuration: number,\n startTime: number,\n commitTime: number,\n ) => boolean;\n}\n\n// Kept on globalThis so the ESM and CommonJS builds, or two bundled copies,\n// share one runtime instead of a component silently reading an empty one.\nconst KEY = Symbol.for(\"react-render-pulse.runtime\");\n\ntype RuntimeHolder = { [KEY]?: PulseRuntime | null };\n\nexport function getRuntime(): PulseRuntime | null {\n return (globalThis as RuntimeHolder)[KEY] ?? null;\n}\n\nexport function setRuntime(runtime: PulseRuntime | null): void {\n (globalThis as RuntimeHolder)[KEY] = runtime;\n}\n","import { createAggregator } from \"../aggregate/aggregator.js\";\nimport { getDeviceContext } from \"../context/device.js\";\nimport { createRouteReader, defaultGetRoute } from \"../context/route.js\";\nimport { createConsoleExporter } from \"../export/console.js\";\nimport { createModeDetector } from \"../modes/detect.js\";\nimport { observeLongTasks } from \"../observe/longtasks.js\";\nimport { createRenderWindows } from \"../observe/renderWindows.js\";\nimport { createSessionId, shouldSample } from \"../sample/sample.js\";\nimport { serializePayload } from \"../transport/payload.js\";\nimport { createTransport } from \"../transport/transport.js\";\nimport type { Exporter, LongTaskEvent, Mode, ModeOption, Payload, RenderEvent, RenderPhase } from \"../types.js\";\nimport { guard, setDebug } from \"./guard.js\";\nimport { getRuntime, setRuntime, type PulseRuntime } from \"./runtime.js\";\n\nexport interface RenderPulseOptions {\n /** Where batches are POSTed. Without one, batches only go to `exporters` (and the console, see `debug`). */\n endpoint?: string | undefined;\n /** Fraction of sessions that collect anything, 0–1, decided once at startup. Defaults to 1. */\n sampleRate?: number | undefined;\n /** `\"profiling\"`, `\"lightweight\"`, or `\"auto\"` (the default): lightweight until React's profiling build is detected. */\n mode?: ModeOption | undefined;\n /** Renders slower than this are counted as slow. Defaults to 16 (one frame at 60 Hz). */\n slowRenderMs?: number | undefined;\n /** Long tasks and long animation frames shorter than this are ignored. Defaults to 50. */\n longTaskMs?: number | undefined;\n /** Your app's version, e.g. from `import.meta.env.VITE_APP_VERSION`, for comparing releases. */\n appVersion?: string | undefined;\n /** Returns the current route, ideally a template like `/orders/:id`. Defaults to the path with numeric segments replaced by `:id`. */\n getRoute?: (() => string) | undefined;\n /** Also sends a batch this often while the page is visible. `0` sends only when the page is hidden. Defaults to 180000 (3 minutes). */\n flushIntervalMs?: number | undefined;\n /** Largest batch in bytes; bigger ones are trimmed. Defaults to 60000, under the 64 KB `sendBeacon` limit. Capped at 65536, the collector's default limit. */\n maxPayloadBytes?: number | undefined;\n /** Most area/route pairs per batch. Defaults to 200, capped at 1000 (the collector's limit). */\n maxAreas?: number | undefined;\n /** Slowest renders kept per area per batch. Defaults to 5, capped at 50 (the collector's limit). */\n worstCases?: number | undefined;\n /** Receive measurements and batches, e.g. `createOtelExporter`. */\n exporters?: Exporter[] | undefined;\n /** Logs each batch to the console and reports internal errors as warnings. Defaults to true when there's no `endpoint`. */\n debug?: boolean | undefined;\n}\n\nexport interface RenderPulse {\n /** False when this session was left out by `sampleRate`; nothing is measured or sent. */\n readonly sampled: boolean;\n /** The current measurement mode. In `\"auto\"`, this changes to `\"profiling\"` once the profiling build is detected. */\n readonly mode: Mode;\n /** Builds a batch from everything measured since the last one and sends it. Returns it, or `null` when there was nothing to send. */\n flush: () => Payload | null;\n /** Stops observing and sending, and detaches `<RenderMonitor>`s, which keep rendering their children as usual. */\n destroy: () => void;\n}\n\nconst INERT: RenderPulse = { sampled: false, mode: \"lightweight\", flush: () => null, destroy: () => {} };\n\nlet active: { destroy: () => void } | null = null;\n\n/**\n * Starts render-pulse. Call it once, before your app renders. Calling it\n * again replaces the previous setup. On the server it does nothing.\n */\nexport function initRenderPulse(options: RenderPulseOptions = {}): RenderPulse {\n if (typeof window === \"undefined\") return INERT;\n return guard(() => start(options), INERT);\n}\n\nfunction start(options: RenderPulseOptions): RenderPulse {\n active?.destroy();\n\n const {\n endpoint,\n sampleRate = 1,\n mode: modeOption = \"auto\",\n slowRenderMs = 16,\n longTaskMs = 50,\n flushIntervalMs = 180_000,\n debug = !endpoint,\n } = options;\n // Clamped to what the collector accepts, so a generous setting can't get every batch rejected.\n const maxPayloadBytes = clamp(options.maxPayloadBytes ?? 60_000, 1_000, 65_536);\n const maxAreas = clamp(options.maxAreas ?? 200, 1, 1000);\n const worstCases = clamp(options.worstCases ?? 5, 0, 50);\n const appVersion = options.appVersion?.slice(0, 100);\n\n setDebug(debug);\n const sampled = shouldSample(sampleRate);\n const now = () => performance.now();\n const sessionStart = now();\n const startedAt = Date.now();\n const sessionId = createSessionId();\n let seq = 0;\n\n const detector = createModeDetector(modeOption);\n const readRoute = createRouteReader(options.getRoute ?? defaultGetRoute);\n const route = () => guard(readRoute, \"/\").slice(0, 500);\n const areaId = (id: string) => (id ? id.slice(0, 200) : \"(unnamed)\");\n const exporters = [...(options.exporters ?? []), ...(debug ? [createConsoleExporter()] : [])];\n const aggregator = createAggregator({ slowRenderMs, maxAreas, worstCases, sessionStart });\n const windows = createRenderWindows();\n const transport = endpoint ? createTransport({ endpoint, maxAttempts: 3, maxQueued: 5 }) : null;\n\n function record(event: RenderEvent): void {\n aggregator.addRender(event);\n windows.add(event.area, event.startTime, event.endTime, event.duration);\n for (const exporter of exporters) guard(() => exporter.onRender?.(event), undefined);\n }\n\n function recordLongTask(event: LongTaskEvent): void {\n aggregator.addLongTask(event);\n for (const exporter of exporters) guard(() => exporter.onLongTask?.(event), undefined);\n }\n\n const runtime: PulseRuntime = {\n sampled,\n now,\n measuresWithMarks: () => sampled && detector.measuresWithMarks(),\n recordMarks(area, phase, startTime, endTime) {\n if (!sampled) return;\n guard(() => {\n const duration = endTime - startTime;\n // Marks measurements are lightweight-mode data even in a profiling session (e.g. from useRenderMonitor).\n record({ area: areaId(area), route: route(), phase, duration, startTime, endTime, mode: \"lightweight\" });\n }, undefined);\n },\n recordProfiler(area, phase: RenderPhase, actualDuration, startTime, commitTime) {\n if (!sampled) return false;\n return guard(() => {\n detector.profilerFired();\n if (detector.current() !== \"profiling\") return false;\n record({\n area: areaId(area),\n route: route(),\n phase,\n duration: actualDuration,\n startTime,\n endTime: commitTime,\n mode: \"profiling\",\n });\n return true;\n }, false);\n },\n };\n\n function flush(unloading: boolean): Payload | null {\n if (!sampled || aggregator.isEmpty()) return null;\n\n return guard(() => {\n const batch = aggregator.drain();\n const payload: Payload = {\n v: 1,\n session: {\n id: sessionId,\n seq: ++seq,\n mode: detector.current(),\n route: route(),\n appVersion: appVersion ?? null,\n startedAt,\n sentAt: Date.now(),\n },\n device: getDeviceContext(),\n summary: batch.summary,\n areas: batch.areas,\n longTasks: batch.longTasks,\n longFrames: batch.longFrames,\n dropped: { areas: batch.droppedAreas },\n };\n\n for (const exporter of exporters) guard(() => exporter.onFlush?.(payload), undefined);\n\n if (transport) {\n const body = serializePayload(payload, maxPayloadBytes);\n if (body) transport.send(body, { unloading });\n }\n\n return payload;\n }, null);\n }\n\n const cleanups: (() => void)[] = [];\n\n if (sampled) {\n cleanups.push(\n observeLongTasks(longTaskMs, (task) =>\n guard(() => {\n const area = windows.findArea(task.startTime, task.startTime + task.duration);\n recordLongTask({ ...task, area, route: route() });\n }, undefined),\n ),\n );\n\n // `pagehide` covers browsers (older Safari) that skip `visibilitychange` on unload.\n const onHidden = () => {\n if (document.visibilityState === \"hidden\") flush(true);\n };\n const onPageHide = () => flush(true);\n document.addEventListener(\"visibilitychange\", onHidden);\n window.addEventListener(\"pagehide\", onPageHide);\n cleanups.push(() => {\n document.removeEventListener(\"visibilitychange\", onHidden);\n window.removeEventListener(\"pagehide\", onPageHide);\n });\n\n if (flushIntervalMs > 0) {\n const timer = setInterval(() => flush(false), flushIntervalMs);\n cleanups.push(() => clearInterval(timer));\n }\n }\n\n setRuntime(runtime);\n\n const instance = {\n destroy() {\n for (const cleanup of cleanups.splice(0)) guard(cleanup, undefined);\n if (getRuntime() === runtime) setRuntime(null);\n if (active === instance) active = null;\n },\n };\n active = instance;\n\n return {\n sampled,\n get mode() {\n return detector.current();\n },\n flush: () => flush(false),\n destroy: instance.destroy,\n };\n}\n\nfunction clamp(value: number, min: number, max: number): number {\n return Number.isFinite(value) ? Math.min(max, Math.max(min, Math.floor(value))) : min;\n}\n","\"use client\";\n\nimport { Profiler, useCallback, useRef, type ProfilerOnRenderCallback, type ReactNode } from \"react\";\nimport { guard } from \"../runtime/guard.js\";\nimport { getRuntime } from \"../runtime/runtime.js\";\nimport { useIsomorphicLayoutEffect } from \"../runtime/useIsomorphicLayoutEffect.js\";\n\nexport interface RenderMonitorProps {\n /** Names this area in reports, e.g. `\"orders-table\"`. Areas with the same id are reported together. */\n id: string;\n children?: ReactNode;\n}\n\ninterface MonitorState {\n id: string;\n mounted: boolean;\n start: number;\n end: number;\n /** The `start` of the last recorded measurement, so StrictMode's repeated effects don't record it twice. */\n recordedStart: number;\n /** The latest marks measurement, waiting to see whether a `<Profiler>` callback for the same commit supersedes it. */\n pending: PendingMeasurement | null;\n}\n\ninterface PendingMeasurement {\n start: number;\n end: number;\n phase: \"mount\" | \"update\";\n superseded: boolean;\n}\n\n/**\n * Measures the renders of its children and reports them under `id`.\n *\n * The tree it renders is the same in every mode and whether or not the\n * session is sampled (a `<Profiler>` around two empty marker components), so\n * switching modes or calling `initRenderPulse` late never remounts children.\n * - Profiling mode: React's `<Profiler>` reports each commit's actual render time.\n * - Lightweight mode: the time between the start and end markers rendering,\n * which brackets the children's render. Updates that start below this area\n * (a child's own state change) don't re-render the markers, so they aren't\n * seen; profiling mode catches those.\n */\nexport function RenderMonitor({ id, children }: RenderMonitorProps): ReactNode {\n const stateRef = useRef<MonitorState | null>(null);\n if (stateRef.current === null) {\n stateRef.current = { id, mounted: false, start: 0, end: 0, recordedStart: -1, pending: null };\n }\n const state = stateRef.current;\n state.id = id;\n\n const onRender = useCallback<ProfilerOnRenderCallback>(\n (_id, phase, actualDuration, _baseDuration, startTime, commitTime) => {\n // When the Profiler's measurement of this commit is used, a marks measurement of it is a duplicate.\n if (getRuntime()?.recordProfiler(state.id, phase, actualDuration, startTime, commitTime) && state.pending) {\n state.pending.superseded = true;\n }\n },\n [state],\n );\n\n return (\n <Profiler id={id} onRender={onRender}>\n <StartMarker state={state} />\n {children}\n <EndMarker state={state} />\n </Profiler>\n );\n}\n\nfunction StartMarker({ state }: { state: MonitorState }): null {\n const runtime = getRuntime();\n if (runtime?.measuresWithMarks()) state.start = runtime.now();\n return null;\n}\n\nfunction EndMarker({ state }: { state: MonitorState }): null {\n const runtime = getRuntime();\n if (runtime?.measuresWithMarks()) state.end = runtime.now();\n\n // Layout effects only run for renders that commit, so abandoned concurrent renders aren't recorded.\n useIsomorphicLayoutEffect(() => {\n guard(() => {\n const current = getRuntime();\n if (!current?.measuresWithMarks() || state.start === state.recordedStart || state.end < state.start) return;\n\n state.recordedStart = state.start;\n const measurement: PendingMeasurement = {\n start: state.start,\n end: state.end,\n phase: state.mounted ? \"update\" : \"mount\",\n superseded: false,\n };\n state.pending = measurement;\n state.mounted = true;\n\n // The Profiler's callback for this commit (if the profiling build is in\n // use) runs later in the same commit, so wait a microtask before\n // deciding this measurement is the only one. Each commit gets its own\n // object, so several commits in one task are all kept.\n queueMicrotask(() => {\n if (state.pending === measurement) state.pending = null;\n if (!measurement.superseded) {\n getRuntime()?.recordMarks(state.id, measurement.phase, measurement.start, measurement.end);\n }\n });\n }, undefined);\n });\n\n return null;\n}\n","import { useEffect, useLayoutEffect } from \"react\";\n\n// useLayoutEffect warns during SSR on React 18; measurements only happen in the browser.\nexport const useIsomorphicLayoutEffect = typeof window === \"undefined\" ? useEffect : useLayoutEffect;\n","\"use client\";\n\nimport { useRef } from \"react\";\nimport { guard } from \"../runtime/guard.js\";\nimport { getRuntime } from \"../runtime/runtime.js\";\nimport { useIsomorphicLayoutEffect } from \"../runtime/useIsomorphicLayoutEffect.js\";\n\n/**\n * Tracks the renders of the component that calls it, reported under `id`.\n *\n * Render counts are exact. The duration runs from the hook's call to the\n * commit, so it also includes anything React renders after this component\n * in the same update: an upper bound. Wrap the component in `<RenderMonitor>`\n * when you need its own render time.\n */\nexport function useRenderMonitor(id: string): void {\n const state = useRef({ start: 0, recordedStart: -1, mounted: false }).current;\n const runtime = getRuntime();\n if (runtime?.sampled) state.start = runtime.now();\n\n useIsomorphicLayoutEffect(() => {\n guard(() => {\n const current = getRuntime();\n // `recordedStart` stops StrictMode's repeated effects from recording one render twice.\n if (!current?.sampled || state.start === state.recordedStart) return;\n\n state.recordedStart = state.start;\n current.recordMarks(id, state.mounted ? \"update\" : \"mount\", state.start, current.now());\n state.mounted = true;\n }, undefined);\n });\n}\n"],"mappings":"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","names":["sum","start","window","debug","import_react","import_react"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/aggregate/histogram.ts","../src/aggregate/aggregator.ts","../src/context/device.ts","../src/context/route.ts","../src/export/console.ts","../src/modes/detect.ts","../src/observe/longtasks.ts","../src/observe/renderWindows.ts","../src/sample/sample.ts","../src/transport/payload.ts","../src/transport/transport.ts","../src/runtime/guard.ts","../src/runtime/runtime.ts","../src/runtime/initRenderPulse.ts","../src/components/RenderMonitor.tsx","../src/runtime/useIsomorphicLayoutEffect.ts","../src/hooks/useRenderMonitor.ts"],"sourcesContent":["export type {\n AreaReport,\n DeviceContext,\n Exporter,\n LongTaskEvent,\n LongTaskKind,\n LongTaskReport,\n Mode,\n ModeOption,\n Payload,\n RenderEvent,\n RenderPhase,\n SessionInfo,\n SessionSummary,\n WorstCase,\n} from \"./types.js\";\nexport { HISTOGRAM_BOUNDS, histogramPercentile } from \"./aggregate/histogram.js\";\n\nexport { initRenderPulse } from \"./runtime/initRenderPulse.js\";\nexport type { RenderPulse, RenderPulseOptions } from \"./runtime/initRenderPulse.js\";\nexport { createConsoleExporter } from \"./export/console.js\";\n\nexport { RenderMonitor } from \"./components/RenderMonitor.js\";\nexport type { RenderMonitorProps } from \"./components/RenderMonitor.js\";\nexport { useRenderMonitor } from \"./hooks/useRenderMonitor.js\";\n","/**\n * Upper bounds (ms, inclusive) of the render-duration histogram buckets, plus\n * an implicit overflow bucket. Part of payload v1: the collector merges\n * histograms by index, so changing these needs a new payload version.\n */\nexport const HISTOGRAM_BOUNDS = [1, 2, 4, 8, 12, 16, 24, 33, 50, 75, 100, 150, 250, 500, 1000] as const;\n\nexport function createHistogram(): number[] {\n return new Array<number>(HISTOGRAM_BOUNDS.length + 1).fill(0);\n}\n\nexport function bucketIndex(ms: number): number {\n for (let i = 0; i < HISTOGRAM_BOUNDS.length; i++) {\n if (ms <= (HISTOGRAM_BOUNDS[i] ?? 0)) return i;\n }\n return HISTOGRAM_BOUNDS.length;\n}\n\n/**\n * Estimates a percentile (0–100) from bucket counts, interpolating linearly\n * inside the bucket. The observed `min` and `max` narrow the bucket's range\n * (every value lies between them): without them, durations clustered at a\n * bucket edge, like many renders of exactly 8 ms, would be estimated from\n * the bucket's middle instead.\n */\nexport function histogramPercentile(hist: readonly number[], p: number, max: number, min = 0): number {\n const total = hist.reduce((sum, n) => sum + n, 0);\n if (total === 0) return 0;\n\n const target = Math.max((p / 100) * total, Number.MIN_VALUE);\n let seen = 0;\n\n for (let i = 0; i < hist.length; i++) {\n const count = hist[i] ?? 0;\n if (count === 0) continue;\n\n if (seen + count >= target) {\n const upper = Math.min(HISTOGRAM_BOUNDS[i] ?? max, max);\n const lower = Math.min(Math.max(i === 0 ? 0 : (HISTOGRAM_BOUNDS[i - 1] ?? 0), min), upper);\n const fraction = (target - seen) / count;\n return round(Math.min(lower + (upper - lower) * fraction, max));\n }\n\n seen += count;\n }\n\n return round(max);\n}\n\n/** Rounds to 0.1 ms: finer precision isn't meaningful and costs payload bytes. */\nexport function round(ms: number): number {\n return Math.round(ms * 10) / 10;\n}\n","import { bucketIndex, createHistogram, histogramPercentile, round } from \"./histogram.js\";\nimport type { AreaReport, LongTaskEvent, LongTaskReport, RenderEvent, SessionSummary, WorstCase } from \"../types.js\";\n\nexport interface AggregatorOptions {\n /** Renders slower than this count as slow. */\n slowRenderMs: number;\n /** Most distinct area/route pairs kept per batch; renders for new ones past this are dropped. */\n maxAreas: number;\n /** How many of the slowest renders to keep per area. */\n worstCases: number;\n /** `performance.now()` at session start, so worst cases report time since then. */\n sessionStart: number;\n}\n\nexport interface AggregatedBatch {\n summary: SessionSummary;\n areas: AreaReport[];\n longTasks: LongTaskReport[];\n longFrames: LongTaskReport[];\n droppedAreas: number;\n}\n\nexport interface Aggregator {\n addRender: (event: RenderEvent) => void;\n addLongTask: (event: LongTaskEvent) => void;\n /** True when nothing was recorded since the last `drain()`. */\n isEmpty: () => boolean;\n /** Returns everything recorded since the last call, and starts a new batch. */\n drain: () => AggregatedBatch;\n}\n\ninterface AreaAccumulator {\n id: string;\n route: string;\n renders: number;\n mounts: number;\n slow: number;\n totalMs: number;\n min: number;\n max: number;\n hist: number[];\n worst: WorstCase[];\n}\n\ninterface LongTaskAccumulator {\n area: string | null;\n route: string;\n count: number;\n totalMs: number;\n maxMs: number;\n}\n\n// Only counts, histograms, and a few worst cases are kept, never raw event\n// streams, so memory stays flat however long the session runs.\nexport function createAggregator(options: AggregatorOptions): Aggregator {\n let areas = new Map<string, AreaAccumulator>();\n let longTasks = new Map<string, LongTaskAccumulator>();\n let longFrames = new Map<string, LongTaskAccumulator>();\n let droppedAreas = 0;\n\n function addRender(event: RenderEvent): void {\n const key = `${event.route}\\u0000${event.area}`;\n let area = areas.get(key);\n\n if (!area) {\n if (areas.size >= options.maxAreas) {\n droppedAreas++;\n return;\n }\n area = {\n id: event.area,\n route: event.route,\n renders: 0,\n mounts: 0,\n slow: 0,\n totalMs: 0,\n min: Infinity,\n max: 0,\n hist: createHistogram(),\n worst: [],\n };\n areas.set(key, area);\n }\n\n const ms = event.duration;\n area.renders++;\n if (event.phase === \"mount\") area.mounts++;\n if (ms > options.slowRenderMs) area.slow++;\n area.totalMs += ms;\n area.min = Math.min(area.min, ms);\n area.max = Math.max(area.max, ms);\n const bucket = bucketIndex(ms);\n area.hist[bucket] = (area.hist[bucket] ?? 0) + 1;\n addWorstCase(area.worst, { ms, phase: event.phase, at: event.startTime - options.sessionStart });\n }\n\n function addWorstCase(worst: WorstCase[], candidate: WorstCase): void {\n if (worst.length < options.worstCases) {\n worst.push(candidate);\n } else {\n const fastest = worst.reduce((min, w, i) => (w.ms < (worst[min]?.ms ?? 0) ? i : min), 0);\n if (candidate.ms <= (worst[fastest]?.ms ?? 0)) return;\n worst[fastest] = candidate;\n }\n }\n\n function addLongTask(event: LongTaskEvent): void {\n const target = event.kind === \"longtask\" ? longTasks : longFrames;\n const key = `${event.route}\\u0000${event.area ?? \"\"}`;\n let entry = target.get(key);\n\n if (!entry) {\n entry = { area: event.area, route: event.route, count: 0, totalMs: 0, maxMs: 0 };\n target.set(key, entry);\n }\n\n entry.count++;\n entry.totalMs += event.duration;\n entry.maxMs = Math.max(entry.maxMs, event.duration);\n }\n\n function drain(): AggregatedBatch {\n const areaReports = Array.from(areas.values(), toAreaReport);\n const taskReports = Array.from(longTasks.values(), toLongTaskReport);\n const frameReports = Array.from(longFrames.values(), toLongTaskReport);\n\n const batch: AggregatedBatch = {\n summary: {\n renders: sum(areaReports, (a) => a.renders),\n slowRenders: sum(areaReports, (a) => a.slow),\n longTasks: sum(taskReports, (t) => t.count),\n longTaskMs: round(sum(taskReports, (t) => t.totalMs)),\n longFrames: sum(frameReports, (t) => t.count),\n longFrameMs: round(sum(frameReports, (t) => t.totalMs)),\n },\n areas: areaReports,\n longTasks: taskReports,\n longFrames: frameReports,\n droppedAreas,\n };\n\n areas = new Map();\n longTasks = new Map();\n longFrames = new Map();\n droppedAreas = 0;\n return batch;\n }\n\n return {\n addRender,\n addLongTask,\n isEmpty: () => areas.size === 0 && longTasks.size === 0 && longFrames.size === 0 && droppedAreas === 0,\n drain,\n };\n}\n\nfunction toAreaReport(area: AreaAccumulator): AreaReport {\n return {\n id: area.id,\n route: area.route,\n renders: area.renders,\n mounts: area.mounts,\n slow: area.slow,\n totalMs: round(area.totalMs),\n min: round(area.min),\n max: round(area.max),\n p50: histogramPercentile(area.hist, 50, area.max, area.min),\n p75: histogramPercentile(area.hist, 75, area.max, area.min),\n p95: histogramPercentile(area.hist, 95, area.max, area.min),\n hist: area.hist,\n worst: area.worst\n .sort((a, b) => b.ms - a.ms)\n .map((w) => ({ ms: round(w.ms), phase: w.phase, at: Math.round(w.at) })),\n };\n}\n\nfunction toLongTaskReport(entry: LongTaskAccumulator): LongTaskReport {\n return { ...entry, totalMs: round(entry.totalMs), maxMs: round(entry.maxMs) };\n}\n\nfunction sum<T>(items: readonly T[], pick: (item: T) => number): number {\n return items.reduce((total, item) => total + pick(item), 0);\n}\n","import type { DeviceContext } from \"../types.js\";\n\n// Non-standard APIs (Chromium only), so they're read defensively.\ninterface NavigatorWithHints {\n deviceMemory?: number;\n hardwareConcurrency?: number;\n connection?: { effectiveType?: string };\n}\n\nexport function getDeviceContext(): DeviceContext {\n const nav = (typeof navigator === \"undefined\" ? {} : navigator) as NavigatorWithHints;\n\n return {\n memoryGb: typeof nav.deviceMemory === \"number\" ? nav.deviceMemory : null,\n cores: typeof nav.hardwareConcurrency === \"number\" ? nav.hardwareConcurrency : null,\n connection: nav.connection?.effectiveType ?? null,\n viewport: typeof window === \"undefined\" ? \"0x0\" : `${window.innerWidth}x${window.innerHeight}`,\n };\n}\n","/** Default route reader: the path with numeric segments replaced, so `/orders/42` and `/orders/7` group together. */\nexport function defaultGetRoute(): string {\n if (typeof location === \"undefined\") return \"/\";\n return location.pathname.replace(/\\/\\d+(?=\\/|$)/g, \"/:id\");\n}\n\n/**\n * Wraps a route reader so it only runs when the URL changes, since it's\n * called on every measured render.\n */\nexport function createRouteReader(getRoute: () => string): () => string {\n let lastHref: string | null = null;\n let lastRoute = \"/\";\n\n return () => {\n const href = typeof location === \"undefined\" ? \"\" : location.href;\n if (href !== lastHref) {\n lastHref = href;\n lastRoute = getRoute();\n }\n return lastRoute;\n };\n}\n","import type { Exporter } from \"../types.js\";\n\n/** Logs each batch as a table, slowest areas first. Used by default when no `endpoint` is set, for local testing. */\nexport function createConsoleExporter(): Exporter {\n return {\n onFlush(payload) {\n if (typeof console === \"undefined\") return;\n\n const rows = [...payload.areas]\n .sort((a, b) => b.p75 - a.p75)\n .map((a) => ({\n area: a.id,\n route: a.route,\n renders: a.renders,\n slow: a.slow,\n p50: a.p50,\n p75: a.p75,\n p95: a.p95,\n max: a.max,\n }));\n\n console.groupCollapsed(\n `[render-pulse] batch ${payload.session.seq} (${payload.session.mode}): ${payload.summary.renders} renders, ${payload.summary.longTasks} long tasks`,\n );\n if (rows.length > 0) console.table(rows);\n if (payload.longTasks.length > 0) console.table(payload.longTasks);\n if (payload.longFrames.length > 0) console.table(payload.longFrames);\n console.groupEnd();\n },\n };\n}\n","import type { Mode, ModeOption } from \"../types.js\";\n\nexport interface ModeDetector {\n /** The mode measurements are currently taken in. */\n current: () => Mode;\n /** True when the performance-mark measurements in `<RenderMonitor>` should run. */\n measuresWithMarks: () => boolean;\n /** Called on every `<Profiler>` callback; in `\"auto\"` mode the first one switches to profiling mode. */\n profilerFired: () => void;\n}\n\n/**\n * React only calls `<Profiler onRender>` in development and in its profiling\n * build, so a callback arriving is proof that per-subtree timings are\n * available. There's no public API to ask which build is loaded, and this\n * avoids relying on React internals.\n */\nexport function createModeDetector(option: ModeOption): ModeDetector {\n let mode: Mode = option === \"profiling\" ? \"profiling\" : \"lightweight\";\n\n return {\n current: () => mode,\n measuresWithMarks: () => mode === \"lightweight\",\n profilerFired() {\n if (option === \"auto\") mode = \"profiling\";\n },\n };\n}\n","import type { LongTaskKind } from \"../types.js\";\n\nexport interface ObservedLongTask {\n kind: LongTaskKind;\n startTime: number;\n duration: number;\n}\n\n/**\n * Observes long tasks (Chromium) and long animation frames (Chromium 123+)\n * at or above `thresholdMs`. Entry types the browser doesn't support are\n * skipped. Returns a function that stops observing.\n */\nexport function observeLongTasks(thresholdMs: number, onEntry: (task: ObservedLongTask) => void): () => void {\n if (typeof PerformanceObserver === \"undefined\") return () => {};\n\n const supported = PerformanceObserver.supportedEntryTypes ?? [];\n const observers: PerformanceObserver[] = [];\n\n for (const kind of [\"longtask\", \"long-animation-frame\"] as const) {\n if (!supported.includes(kind)) continue;\n\n try {\n const observer = new PerformanceObserver((list) => {\n for (const entry of list.getEntries()) {\n if (entry.duration < thresholdMs) continue;\n onEntry({ kind, startTime: entry.startTime, duration: entry.duration });\n }\n });\n observer.observe({ type: kind, buffered: true });\n observers.push(observer);\n } catch {\n // Observing is best-effort; a browser quirk here must not reach the app.\n }\n }\n\n return () => {\n for (const observer of observers) observer.disconnect();\n };\n}\n","interface RenderWindow {\n area: string;\n start: number;\n end: number;\n duration: number;\n}\n\nexport interface RenderWindows {\n /** Records that `area` rendered for `duration` ms somewhere between `start` and `end`. */\n add: (area: string, start: number, end: number, duration: number) => void;\n /** The area to blame for a main-thread block over `[start, end]`, or `null` when no recent render overlaps it. */\n findArea: (start: number, end: number) => string | null;\n}\n\n/**\n * A fixed-size ring of recent render windows. Long-task entries arrive a\n * little after the fact, so attribution looks back over the last `size` renders.\n *\n * Nested areas overlap the same block, and an outer area's duration includes\n * its inner ones. So the blame goes to the innermost overlapping area that\n * still accounts for at least half of the longest overlapping render: an\n * inner area that's responsible for most of the time, rather than always the\n * outermost wrapper or a tiny sibling that happened to render in the same commit.\n */\nexport function createRenderWindows(size = 200): RenderWindows {\n const windows: (RenderWindow | undefined)[] = new Array(size);\n let next = 0;\n\n return {\n add(area, start, end, duration) {\n windows[next] = { area, start, end, duration };\n next = (next + 1) % size;\n },\n findArea(start, end) {\n const overlapping = windows.filter((w): w is RenderWindow => w !== undefined && w.end >= start && w.start <= end);\n if (overlapping.length === 0) return null;\n\n const longest = Math.max(...overlapping.map((w) => w.duration));\n let best: RenderWindow | null = null;\n\n for (const window of overlapping) {\n if (window.duration < longest / 2) continue;\n if (!best || window.duration < best.duration) best = window;\n }\n\n return best?.area ?? null;\n },\n };\n}\n","/**\n * Decides once per session whether to collect, so unsampled sessions pay\n * almost nothing. `sampleRate` is clamped to 0–1.\n */\nexport function shouldSample(sampleRate: number, random: () => number = Math.random): boolean {\n if (!(sampleRate > 0)) return false;\n if (sampleRate >= 1) return true;\n return random() < sampleRate;\n}\n\n/** A random session id. Not derived from anything about the user, and never persisted. */\nexport function createSessionId(): string {\n try {\n // randomUUID only exists in secure contexts (HTTPS, localhost).\n const cryptoApi = globalThis.crypto as Crypto | undefined;\n if (cryptoApi && typeof cryptoApi.randomUUID === \"function\") return cryptoApi.randomUUID();\n } catch {\n // Fall through to the non-crypto id.\n }\n return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;\n}\n","import type { Payload } from \"../types.js\";\n\nexport function byteLength(text: string): number {\n return typeof TextEncoder === \"undefined\" ? text.length * 3 : new TextEncoder().encode(text).length;\n}\n\n/**\n * Serializes a payload, shrinking it until it fits in `maxBytes`: first the\n * worst-case lists go, then the areas with the fewest renders. Returns `null`\n * when even an empty payload doesn't fit.\n */\nexport function serializePayload(payload: Payload, maxBytes: number): string | null {\n let json = JSON.stringify(payload);\n if (byteLength(json) <= maxBytes) return json;\n\n let trimmed: Payload = { ...payload, areas: payload.areas.map((a) => ({ ...a, worst: [] })) };\n json = JSON.stringify(trimmed);\n\n if (byteLength(json) > maxBytes) {\n const areas = [...trimmed.areas].sort((a, b) => b.renders - a.renders);\n let dropped = trimmed.dropped.areas;\n\n // Halve the kept areas until it fits, then the list is short enough to stop.\n while (areas.length > 0 && byteLength(json) > maxBytes) {\n const remove = Math.max(1, Math.floor(areas.length / 2));\n areas.splice(areas.length - remove, remove);\n dropped += remove;\n trimmed = { ...trimmed, areas: [...areas], dropped: { areas: dropped } };\n json = JSON.stringify(trimmed);\n }\n }\n\n return byteLength(json) <= maxBytes ? json : null;\n}\n","export interface TransportOptions {\n endpoint: string;\n /** Failed sends are retried on later flushes, up to this many attempts in total. */\n maxAttempts: number;\n /** Most failed bodies kept for retry; the oldest are dropped past this. */\n maxQueued: number;\n}\n\nexport interface Transport {\n /**\n * Sends a serialized payload. With `unloading`, uses `navigator.sendBeacon`\n * (falling back to `fetch` with `keepalive`), since the page may be gone\n * before a normal request finishes. Never throws or rejects.\n */\n send: (body: string, options: { unloading: boolean }) => void;\n}\n\ninterface QueuedBody {\n body: string;\n attempts: number;\n}\n\nexport function createTransport(options: TransportOptions): Transport {\n const queue: QueuedBody[] = [];\n\n function enqueue(item: QueuedBody): void {\n if (item.attempts >= options.maxAttempts) return;\n queue.push(item);\n if (queue.length > options.maxQueued) queue.shift();\n }\n\n function beacon(body: string): boolean {\n try {\n // A string body is sent as text/plain, a CORS-safelisted type, so\n // cross-origin collectors don't need a preflight the beacon can't do.\n return typeof navigator !== \"undefined\" && typeof navigator.sendBeacon === \"function\"\n ? navigator.sendBeacon(options.endpoint, body)\n : false;\n } catch {\n return false;\n }\n }\n\n function post(item: QueuedBody): void {\n if (typeof fetch !== \"function\") return;\n const attempt = { body: item.body, attempts: item.attempts + 1 };\n\n try {\n fetch(options.endpoint, { method: \"POST\", body: item.body, keepalive: true })\n .then((response) => {\n // 4xx means the collector rejected the payload; retrying won't help.\n if (response.status >= 500 || response.status === 429) enqueue(attempt);\n })\n .catch(() => enqueue(attempt));\n } catch {\n enqueue(attempt);\n }\n }\n\n return {\n send(body, { unloading }) {\n const items = [...queue.splice(0), { body, attempts: 0 }];\n\n for (const item of items) {\n if (unloading && beacon(item.body)) continue;\n post(item);\n }\n },\n };\n}\n","let debug = false;\n\nexport function setDebug(value: boolean): void {\n debug = value;\n}\n\n/**\n * Runs `fn`, swallowing anything it throws, so an error inside render-pulse\n * (or a user-supplied exporter or `getRoute`) never reaches the app. With\n * `debug`, the error is logged instead of silently dropped.\n */\nexport function guard<T>(fn: () => T, fallback: T): T {\n try {\n return fn();\n } catch (error) {\n if (debug && typeof console !== \"undefined\") console.warn(\"[render-pulse]\", error);\n return fallback;\n }\n}\n","import type { RenderPhase } from \"../types.js\";\n\n/** What `<RenderMonitor>` and `useRenderMonitor` call into. Every method is safe to call and never throws. */\nexport interface PulseRuntime {\n readonly sampled: boolean;\n /** True when `<RenderMonitor>` should take performance-mark measurements (lightweight mode). */\n measuresWithMarks: () => boolean;\n now: () => number;\n recordMarks: (area: string, phase: RenderPhase, start: number, end: number) => void;\n /** Returns true when the measurement was recorded, i.e. the session is in profiling mode. */\n recordProfiler: (\n area: string,\n phase: RenderPhase,\n actualDuration: number,\n startTime: number,\n commitTime: number,\n ) => boolean;\n}\n\n// Kept on globalThis so the ESM and CommonJS builds, or two bundled copies,\n// share one runtime instead of a component silently reading an empty one.\nconst KEY = Symbol.for(\"react-render-pulse.runtime\");\n\ntype RuntimeHolder = { [KEY]?: PulseRuntime | null };\n\nexport function getRuntime(): PulseRuntime | null {\n return (globalThis as RuntimeHolder)[KEY] ?? null;\n}\n\nexport function setRuntime(runtime: PulseRuntime | null): void {\n (globalThis as RuntimeHolder)[KEY] = runtime;\n}\n","import { createAggregator } from \"../aggregate/aggregator.js\";\nimport { getDeviceContext } from \"../context/device.js\";\nimport { createRouteReader, defaultGetRoute } from \"../context/route.js\";\nimport { createConsoleExporter } from \"../export/console.js\";\nimport { createModeDetector } from \"../modes/detect.js\";\nimport { observeLongTasks } from \"../observe/longtasks.js\";\nimport { createRenderWindows } from \"../observe/renderWindows.js\";\nimport { createSessionId, shouldSample } from \"../sample/sample.js\";\nimport { serializePayload } from \"../transport/payload.js\";\nimport { createTransport } from \"../transport/transport.js\";\nimport type { Exporter, LongTaskEvent, Mode, ModeOption, Payload, RenderEvent, RenderPhase } from \"../types.js\";\nimport { guard, setDebug } from \"./guard.js\";\nimport { getRuntime, setRuntime, type PulseRuntime } from \"./runtime.js\";\n\nexport interface RenderPulseOptions {\n /** Where batches are POSTed. Without one, batches only go to `exporters` (and the console, see `debug`). */\n endpoint?: string | undefined;\n /** Fraction of sessions that collect anything, 0–1, decided once at startup. Defaults to 1. */\n sampleRate?: number | undefined;\n /** `\"profiling\"`, `\"lightweight\"`, or `\"auto\"` (the default): lightweight until React's profiling build is detected. */\n mode?: ModeOption | undefined;\n /** Renders slower than this are counted as slow. Defaults to 16 (one frame at 60 Hz). */\n slowRenderMs?: number | undefined;\n /** Long tasks and long animation frames shorter than this are ignored. Defaults to 50. */\n longTaskMs?: number | undefined;\n /** Your app's version, e.g. from `import.meta.env.VITE_APP_VERSION`, for comparing releases. */\n appVersion?: string | undefined;\n /** Returns the current route, ideally a template like `/orders/:id`. Defaults to the path with numeric segments replaced by `:id`. */\n getRoute?: (() => string) | undefined;\n /** Also sends a batch this often while the page is visible. `0` sends only when the page is hidden. Defaults to 180000 (3 minutes). */\n flushIntervalMs?: number | undefined;\n /** Largest batch in bytes; bigger ones are trimmed. Defaults to 60000, under the 64 KB `sendBeacon` limit. Capped at 65536, the collector's default limit. */\n maxPayloadBytes?: number | undefined;\n /** Most area/route pairs per batch. Defaults to 200, capped at 1000 (the collector's limit). */\n maxAreas?: number | undefined;\n /** Slowest renders kept per area per batch. Defaults to 5, capped at 50 (the collector's limit). */\n worstCases?: number | undefined;\n /** Receive measurements and batches, e.g. `createOtelExporter`. */\n exporters?: Exporter[] | undefined;\n /** Logs each batch to the console and reports internal errors as warnings. Defaults to true when there's no `endpoint`. */\n debug?: boolean | undefined;\n}\n\nexport interface RenderPulse {\n /** False when this session was left out by `sampleRate`; nothing is measured or sent. */\n readonly sampled: boolean;\n /** The current measurement mode. In `\"auto\"`, this changes to `\"profiling\"` once the profiling build is detected. */\n readonly mode: Mode;\n /** Builds a batch from everything measured since the last one and sends it. Returns it, or `null` when there was nothing to send. */\n flush: () => Payload | null;\n /** Stops observing and sending, and detaches `<RenderMonitor>`s, which keep rendering their children as usual. */\n destroy: () => void;\n}\n\nconst INERT: RenderPulse = { sampled: false, mode: \"lightweight\", flush: () => null, destroy: () => {} };\n\nlet active: { destroy: () => void } | null = null;\n\n/**\n * Starts render-pulse. Call it once, before your app renders. Calling it\n * again replaces the previous setup. On the server it does nothing.\n */\nexport function initRenderPulse(options: RenderPulseOptions = {}): RenderPulse {\n if (typeof window === \"undefined\") return INERT;\n return guard(() => start(options), INERT);\n}\n\nfunction start(options: RenderPulseOptions): RenderPulse {\n active?.destroy();\n\n const {\n endpoint,\n sampleRate = 1,\n mode: modeOption = \"auto\",\n slowRenderMs = 16,\n longTaskMs = 50,\n flushIntervalMs = 180_000,\n debug = !endpoint,\n } = options;\n // Clamped to what the collector accepts, so a generous setting can't get every batch rejected.\n const maxPayloadBytes = clamp(options.maxPayloadBytes ?? 60_000, 1_000, 65_536);\n const maxAreas = clamp(options.maxAreas ?? 200, 1, 1000);\n const worstCases = clamp(options.worstCases ?? 5, 0, 50);\n const appVersion = options.appVersion?.slice(0, 100);\n\n setDebug(debug);\n const sampled = shouldSample(sampleRate);\n const now = () => performance.now();\n const sessionStart = now();\n const startedAt = Date.now();\n const sessionId = createSessionId();\n let seq = 0;\n\n const detector = createModeDetector(modeOption);\n const readRoute = createRouteReader(options.getRoute ?? defaultGetRoute);\n const route = () => guard(readRoute, \"/\").slice(0, 500);\n const areaId = (id: string) => (id ? id.slice(0, 200) : \"(unnamed)\");\n const exporters = [...(options.exporters ?? []), ...(debug ? [createConsoleExporter()] : [])];\n const aggregator = createAggregator({ slowRenderMs, maxAreas, worstCases, sessionStart });\n const windows = createRenderWindows();\n const transport = endpoint ? createTransport({ endpoint, maxAttempts: 3, maxQueued: 5 }) : null;\n\n function record(event: RenderEvent): void {\n aggregator.addRender(event);\n windows.add(event.area, event.startTime, event.endTime, event.duration);\n for (const exporter of exporters) guard(() => exporter.onRender?.(event), undefined);\n }\n\n function recordLongTask(event: LongTaskEvent): void {\n aggregator.addLongTask(event);\n for (const exporter of exporters) guard(() => exporter.onLongTask?.(event), undefined);\n }\n\n const runtime: PulseRuntime = {\n sampled,\n now,\n measuresWithMarks: () => sampled && detector.measuresWithMarks(),\n recordMarks(area, phase, startTime, endTime) {\n if (!sampled) return;\n guard(() => {\n const duration = endTime - startTime;\n // Marks measurements are lightweight-mode data even in a profiling session (e.g. from useRenderMonitor).\n record({ area: areaId(area), route: route(), phase, duration, startTime, endTime, mode: \"lightweight\" });\n }, undefined);\n },\n recordProfiler(area, phase: RenderPhase, actualDuration, startTime, commitTime) {\n if (!sampled) return false;\n return guard(() => {\n detector.profilerFired();\n if (detector.current() !== \"profiling\") return false;\n record({\n area: areaId(area),\n route: route(),\n phase,\n duration: actualDuration,\n startTime,\n endTime: commitTime,\n mode: \"profiling\",\n });\n return true;\n }, false);\n },\n };\n\n function flush(unloading: boolean): Payload | null {\n if (!sampled || aggregator.isEmpty()) return null;\n\n return guard(() => {\n const batch = aggregator.drain();\n const payload: Payload = {\n v: 1,\n session: {\n id: sessionId,\n seq: ++seq,\n mode: detector.current(),\n route: route(),\n appVersion: appVersion ?? null,\n startedAt,\n sentAt: Date.now(),\n },\n device: getDeviceContext(),\n summary: batch.summary,\n areas: batch.areas,\n longTasks: batch.longTasks,\n longFrames: batch.longFrames,\n dropped: { areas: batch.droppedAreas },\n };\n\n for (const exporter of exporters) guard(() => exporter.onFlush?.(payload), undefined);\n\n if (transport) {\n const body = serializePayload(payload, maxPayloadBytes);\n if (body) transport.send(body, { unloading });\n }\n\n return payload;\n }, null);\n }\n\n const cleanups: (() => void)[] = [];\n\n if (sampled) {\n cleanups.push(\n observeLongTasks(longTaskMs, (task) =>\n guard(() => {\n const area = windows.findArea(task.startTime, task.startTime + task.duration);\n recordLongTask({ ...task, area, route: route() });\n }, undefined),\n ),\n );\n\n // `pagehide` covers browsers (older Safari) that skip `visibilitychange` on unload.\n const onHidden = () => {\n if (document.visibilityState === \"hidden\") flush(true);\n };\n const onPageHide = () => flush(true);\n document.addEventListener(\"visibilitychange\", onHidden);\n window.addEventListener(\"pagehide\", onPageHide);\n cleanups.push(() => {\n document.removeEventListener(\"visibilitychange\", onHidden);\n window.removeEventListener(\"pagehide\", onPageHide);\n });\n\n if (flushIntervalMs > 0) {\n const timer = setInterval(() => flush(false), flushIntervalMs);\n cleanups.push(() => clearInterval(timer));\n }\n }\n\n setRuntime(runtime);\n\n const instance = {\n destroy() {\n for (const cleanup of cleanups.splice(0)) guard(cleanup, undefined);\n if (getRuntime() === runtime) setRuntime(null);\n if (active === instance) active = null;\n },\n };\n active = instance;\n\n return {\n sampled,\n get mode() {\n return detector.current();\n },\n flush: () => flush(false),\n destroy: instance.destroy,\n };\n}\n\nfunction clamp(value: number, min: number, max: number): number {\n return Number.isFinite(value) ? Math.min(max, Math.max(min, Math.floor(value))) : min;\n}\n","\"use client\";\n\nimport { Profiler, useCallback, useRef, type ProfilerOnRenderCallback, type ReactNode } from \"react\";\nimport { guard } from \"../runtime/guard.js\";\nimport { getRuntime } from \"../runtime/runtime.js\";\nimport { useIsomorphicLayoutEffect } from \"../runtime/useIsomorphicLayoutEffect.js\";\n\nexport interface RenderMonitorProps {\n /** Names this area in reports, e.g. `\"orders-table\"`. Areas with the same id are reported together. */\n id: string;\n children?: ReactNode;\n}\n\ninterface MonitorState {\n id: string;\n mounted: boolean;\n start: number;\n end: number;\n /** The `start` of the last recorded measurement, so StrictMode's repeated effects don't record it twice. */\n recordedStart: number;\n /** The latest marks measurement, waiting to see whether a `<Profiler>` callback for the same commit supersedes it. */\n pending: PendingMeasurement | null;\n}\n\ninterface PendingMeasurement {\n start: number;\n end: number;\n phase: \"mount\" | \"update\";\n superseded: boolean;\n}\n\n/**\n * Measures the renders of its children and reports them under `id`.\n *\n * The tree it renders is the same in every mode and whether or not the\n * session is sampled (a `<Profiler>` around two empty marker components), so\n * switching modes or calling `initRenderPulse` late never remounts children.\n * - Profiling mode: React's `<Profiler>` reports each commit's actual render time.\n * - Lightweight mode: the time between the start and end markers rendering,\n * which brackets the children's render. Updates that start below this area\n * (a child's own state change) don't re-render the markers, so they aren't\n * seen; profiling mode catches those.\n */\nexport function RenderMonitor({ id, children }: RenderMonitorProps): ReactNode {\n const stateRef = useRef<MonitorState | null>(null);\n if (stateRef.current === null) {\n stateRef.current = { id, mounted: false, start: 0, end: 0, recordedStart: -1, pending: null };\n }\n const state = stateRef.current;\n state.id = id;\n\n const onRender = useCallback<ProfilerOnRenderCallback>(\n (_id, phase, actualDuration, _baseDuration, startTime, commitTime) => {\n // When the Profiler's measurement of this commit is used, a marks measurement of it is a duplicate.\n if (getRuntime()?.recordProfiler(state.id, phase, actualDuration, startTime, commitTime) && state.pending) {\n state.pending.superseded = true;\n }\n },\n [state],\n );\n\n return (\n <Profiler id={id} onRender={onRender}>\n <StartMarker state={state} />\n {children}\n <EndMarker state={state} />\n </Profiler>\n );\n}\n\nfunction StartMarker({ state }: { state: MonitorState }): null {\n const runtime = getRuntime();\n if (runtime?.measuresWithMarks()) state.start = runtime.now();\n return null;\n}\n\nfunction EndMarker({ state }: { state: MonitorState }): null {\n const runtime = getRuntime();\n if (runtime?.measuresWithMarks()) state.end = runtime.now();\n\n // Layout effects only run for renders that commit, so abandoned concurrent renders aren't recorded.\n useIsomorphicLayoutEffect(() => {\n guard(() => {\n const current = getRuntime();\n if (!current?.measuresWithMarks() || state.start === state.recordedStart || state.end < state.start) return;\n\n state.recordedStart = state.start;\n const measurement: PendingMeasurement = {\n start: state.start,\n end: state.end,\n phase: state.mounted ? \"update\" : \"mount\",\n superseded: false,\n };\n state.pending = measurement;\n state.mounted = true;\n\n // The Profiler's callback for this commit (if the profiling build is in\n // use) runs later in the same commit, so wait a microtask before\n // deciding this measurement is the only one. Each commit gets its own\n // object, so several commits in one task are all kept.\n queueMicrotask(() => {\n if (state.pending === measurement) state.pending = null;\n if (!measurement.superseded) {\n getRuntime()?.recordMarks(state.id, measurement.phase, measurement.start, measurement.end);\n }\n });\n }, undefined);\n });\n\n return null;\n}\n","import { useEffect, useLayoutEffect } from \"react\";\n\n// useLayoutEffect warns during SSR on React 18; measurements only happen in the browser.\nexport const useIsomorphicLayoutEffect = typeof window === \"undefined\" ? useEffect : useLayoutEffect;\n","\"use client\";\n\nimport { useRef } from \"react\";\nimport { guard } from \"../runtime/guard.js\";\nimport { getRuntime } from \"../runtime/runtime.js\";\nimport { useIsomorphicLayoutEffect } from \"../runtime/useIsomorphicLayoutEffect.js\";\n\n/**\n * Tracks the renders of the component that calls it, reported under `id`.\n *\n * Render counts are exact. The duration runs from the hook's call to the\n * commit, so it also includes anything React renders after this component\n * in the same update: an upper bound. Wrap the component in `<RenderMonitor>`\n * when you need its own render time.\n *\n * Don't use it in a component that renders before the rest of the page, such\n * as a header or layout: on the first render its duration covers the whole page.\n */\nexport function useRenderMonitor(id: string): void {\n const state = useRef({ start: 0, recordedStart: -1, mounted: false }).current;\n const runtime = getRuntime();\n if (runtime?.sampled) state.start = runtime.now();\n\n useIsomorphicLayoutEffect(() => {\n guard(() => {\n const current = getRuntime();\n // `recordedStart` stops StrictMode's repeated effects from recording one render twice.\n if (!current?.sampled || state.start === state.recordedStart) return;\n\n state.recordedStart = state.start;\n current.recordMarks(id, state.mounted ? \"update\" : \"mount\", state.start, current.now());\n state.mounted = true;\n }, undefined);\n });\n}\n"],"mappings":"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","names":["sum","start","window","debug","import_react","import_react"]}
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/aggregate/histogram.ts","../src/aggregate/aggregator.ts","../src/context/device.ts","../src/context/route.ts","../src/export/console.ts","../src/modes/detect.ts","../src/observe/longtasks.ts","../src/observe/renderWindows.ts","../src/sample/sample.ts","../src/transport/payload.ts","../src/transport/transport.ts","../src/runtime/guard.ts","../src/runtime/runtime.ts","../src/runtime/initRenderPulse.ts","../src/components/RenderMonitor.tsx","../src/runtime/useIsomorphicLayoutEffect.ts","../src/hooks/useRenderMonitor.ts"],"sourcesContent":["/**\n * Upper bounds (ms, inclusive) of the render-duration histogram buckets, plus\n * an implicit overflow bucket. Part of payload v1: the collector merges\n * histograms by index, so changing these needs a new payload version.\n */\nexport const HISTOGRAM_BOUNDS = [1, 2, 4, 8, 12, 16, 24, 33, 50, 75, 100, 150, 250, 500, 1000] as const;\n\nexport function createHistogram(): number[] {\n return new Array<number>(HISTOGRAM_BOUNDS.length + 1).fill(0);\n}\n\nexport function bucketIndex(ms: number): number {\n for (let i = 0; i < HISTOGRAM_BOUNDS.length; i++) {\n if (ms <= (HISTOGRAM_BOUNDS[i] ?? 0)) return i;\n }\n return HISTOGRAM_BOUNDS.length;\n}\n\n/**\n * Estimates a percentile (0–100) from bucket counts, interpolating linearly\n * inside the bucket. The observed `min` and `max` narrow the bucket's range\n * (every value lies between them): without them, durations clustered at a\n * bucket edge, like many renders of exactly 8 ms, would be estimated from\n * the bucket's middle instead.\n */\nexport function histogramPercentile(hist: readonly number[], p: number, max: number, min = 0): number {\n const total = hist.reduce((sum, n) => sum + n, 0);\n if (total === 0) return 0;\n\n const target = Math.max((p / 100) * total, Number.MIN_VALUE);\n let seen = 0;\n\n for (let i = 0; i < hist.length; i++) {\n const count = hist[i] ?? 0;\n if (count === 0) continue;\n\n if (seen + count >= target) {\n const upper = Math.min(HISTOGRAM_BOUNDS[i] ?? max, max);\n const lower = Math.min(Math.max(i === 0 ? 0 : (HISTOGRAM_BOUNDS[i - 1] ?? 0), min), upper);\n const fraction = (target - seen) / count;\n return round(Math.min(lower + (upper - lower) * fraction, max));\n }\n\n seen += count;\n }\n\n return round(max);\n}\n\n/** Rounds to 0.1 ms: finer precision isn't meaningful and costs payload bytes. */\nexport function round(ms: number): number {\n return Math.round(ms * 10) / 10;\n}\n","import { bucketIndex, createHistogram, histogramPercentile, round } from \"./histogram.js\";\nimport type { AreaReport, LongTaskEvent, LongTaskReport, RenderEvent, SessionSummary, WorstCase } from \"../types.js\";\n\nexport interface AggregatorOptions {\n /** Renders slower than this count as slow. */\n slowRenderMs: number;\n /** Most distinct area/route pairs kept per batch; renders for new ones past this are dropped. */\n maxAreas: number;\n /** How many of the slowest renders to keep per area. */\n worstCases: number;\n /** `performance.now()` at session start, so worst cases report time since then. */\n sessionStart: number;\n}\n\nexport interface AggregatedBatch {\n summary: SessionSummary;\n areas: AreaReport[];\n longTasks: LongTaskReport[];\n longFrames: LongTaskReport[];\n droppedAreas: number;\n}\n\nexport interface Aggregator {\n addRender: (event: RenderEvent) => void;\n addLongTask: (event: LongTaskEvent) => void;\n /** True when nothing was recorded since the last `drain()`. */\n isEmpty: () => boolean;\n /** Returns everything recorded since the last call, and starts a new batch. */\n drain: () => AggregatedBatch;\n}\n\ninterface AreaAccumulator {\n id: string;\n route: string;\n renders: number;\n mounts: number;\n slow: number;\n totalMs: number;\n min: number;\n max: number;\n hist: number[];\n worst: WorstCase[];\n}\n\ninterface LongTaskAccumulator {\n area: string | null;\n route: string;\n count: number;\n totalMs: number;\n maxMs: number;\n}\n\n// Only counts, histograms, and a few worst cases are kept, never raw event\n// streams, so memory stays flat however long the session runs.\nexport function createAggregator(options: AggregatorOptions): Aggregator {\n let areas = new Map<string, AreaAccumulator>();\n let longTasks = new Map<string, LongTaskAccumulator>();\n let longFrames = new Map<string, LongTaskAccumulator>();\n let droppedAreas = 0;\n\n function addRender(event: RenderEvent): void {\n const key = `${event.route}\\u0000${event.area}`;\n let area = areas.get(key);\n\n if (!area) {\n if (areas.size >= options.maxAreas) {\n droppedAreas++;\n return;\n }\n area = {\n id: event.area,\n route: event.route,\n renders: 0,\n mounts: 0,\n slow: 0,\n totalMs: 0,\n min: Infinity,\n max: 0,\n hist: createHistogram(),\n worst: [],\n };\n areas.set(key, area);\n }\n\n const ms = event.duration;\n area.renders++;\n if (event.phase === \"mount\") area.mounts++;\n if (ms > options.slowRenderMs) area.slow++;\n area.totalMs += ms;\n area.min = Math.min(area.min, ms);\n area.max = Math.max(area.max, ms);\n const bucket = bucketIndex(ms);\n area.hist[bucket] = (area.hist[bucket] ?? 0) + 1;\n addWorstCase(area.worst, { ms, phase: event.phase, at: event.startTime - options.sessionStart });\n }\n\n function addWorstCase(worst: WorstCase[], candidate: WorstCase): void {\n if (worst.length < options.worstCases) {\n worst.push(candidate);\n } else {\n const fastest = worst.reduce((min, w, i) => (w.ms < (worst[min]?.ms ?? 0) ? i : min), 0);\n if (candidate.ms <= (worst[fastest]?.ms ?? 0)) return;\n worst[fastest] = candidate;\n }\n }\n\n function addLongTask(event: LongTaskEvent): void {\n const target = event.kind === \"longtask\" ? longTasks : longFrames;\n const key = `${event.route}\\u0000${event.area ?? \"\"}`;\n let entry = target.get(key);\n\n if (!entry) {\n entry = { area: event.area, route: event.route, count: 0, totalMs: 0, maxMs: 0 };\n target.set(key, entry);\n }\n\n entry.count++;\n entry.totalMs += event.duration;\n entry.maxMs = Math.max(entry.maxMs, event.duration);\n }\n\n function drain(): AggregatedBatch {\n const areaReports = Array.from(areas.values(), toAreaReport);\n const taskReports = Array.from(longTasks.values(), toLongTaskReport);\n const frameReports = Array.from(longFrames.values(), toLongTaskReport);\n\n const batch: AggregatedBatch = {\n summary: {\n renders: sum(areaReports, (a) => a.renders),\n slowRenders: sum(areaReports, (a) => a.slow),\n longTasks: sum(taskReports, (t) => t.count),\n longTaskMs: round(sum(taskReports, (t) => t.totalMs)),\n longFrames: sum(frameReports, (t) => t.count),\n longFrameMs: round(sum(frameReports, (t) => t.totalMs)),\n },\n areas: areaReports,\n longTasks: taskReports,\n longFrames: frameReports,\n droppedAreas,\n };\n\n areas = new Map();\n longTasks = new Map();\n longFrames = new Map();\n droppedAreas = 0;\n return batch;\n }\n\n return {\n addRender,\n addLongTask,\n isEmpty: () => areas.size === 0 && longTasks.size === 0 && longFrames.size === 0 && droppedAreas === 0,\n drain,\n };\n}\n\nfunction toAreaReport(area: AreaAccumulator): AreaReport {\n return {\n id: area.id,\n route: area.route,\n renders: area.renders,\n mounts: area.mounts,\n slow: area.slow,\n totalMs: round(area.totalMs),\n min: round(area.min),\n max: round(area.max),\n p50: histogramPercentile(area.hist, 50, area.max, area.min),\n p75: histogramPercentile(area.hist, 75, area.max, area.min),\n p95: histogramPercentile(area.hist, 95, area.max, area.min),\n hist: area.hist,\n worst: area.worst\n .sort((a, b) => b.ms - a.ms)\n .map((w) => ({ ms: round(w.ms), phase: w.phase, at: Math.round(w.at) })),\n };\n}\n\nfunction toLongTaskReport(entry: LongTaskAccumulator): LongTaskReport {\n return { ...entry, totalMs: round(entry.totalMs), maxMs: round(entry.maxMs) };\n}\n\nfunction sum<T>(items: readonly T[], pick: (item: T) => number): number {\n return items.reduce((total, item) => total + pick(item), 0);\n}\n","import type { DeviceContext } from \"../types.js\";\n\n// Non-standard APIs (Chromium only), so they're read defensively.\ninterface NavigatorWithHints {\n deviceMemory?: number;\n hardwareConcurrency?: number;\n connection?: { effectiveType?: string };\n}\n\nexport function getDeviceContext(): DeviceContext {\n const nav = (typeof navigator === \"undefined\" ? {} : navigator) as NavigatorWithHints;\n\n return {\n memoryGb: typeof nav.deviceMemory === \"number\" ? nav.deviceMemory : null,\n cores: typeof nav.hardwareConcurrency === \"number\" ? nav.hardwareConcurrency : null,\n connection: nav.connection?.effectiveType ?? null,\n viewport: typeof window === \"undefined\" ? \"0x0\" : `${window.innerWidth}x${window.innerHeight}`,\n };\n}\n","/** Default route reader: the path with numeric segments replaced, so `/orders/42` and `/orders/7` group together. */\nexport function defaultGetRoute(): string {\n if (typeof location === \"undefined\") return \"/\";\n return location.pathname.replace(/\\/\\d+(?=\\/|$)/g, \"/:id\");\n}\n\n/**\n * Wraps a route reader so it only runs when the URL changes, since it's\n * called on every measured render.\n */\nexport function createRouteReader(getRoute: () => string): () => string {\n let lastHref: string | null = null;\n let lastRoute = \"/\";\n\n return () => {\n const href = typeof location === \"undefined\" ? \"\" : location.href;\n if (href !== lastHref) {\n lastHref = href;\n lastRoute = getRoute();\n }\n return lastRoute;\n };\n}\n","import type { Exporter } from \"../types.js\";\n\n/** Logs each batch as a table, slowest areas first. Used by default when no `endpoint` is set, for local testing. */\nexport function createConsoleExporter(): Exporter {\n return {\n onFlush(payload) {\n if (typeof console === \"undefined\") return;\n\n const rows = [...payload.areas]\n .sort((a, b) => b.p75 - a.p75)\n .map((a) => ({\n area: a.id,\n route: a.route,\n renders: a.renders,\n slow: a.slow,\n p50: a.p50,\n p75: a.p75,\n p95: a.p95,\n max: a.max,\n }));\n\n console.groupCollapsed(\n `[render-pulse] batch ${payload.session.seq} (${payload.session.mode}): ${payload.summary.renders} renders, ${payload.summary.longTasks} long tasks`,\n );\n if (rows.length > 0) console.table(rows);\n if (payload.longTasks.length > 0) console.table(payload.longTasks);\n if (payload.longFrames.length > 0) console.table(payload.longFrames);\n console.groupEnd();\n },\n };\n}\n","import type { Mode, ModeOption } from \"../types.js\";\n\nexport interface ModeDetector {\n /** The mode measurements are currently taken in. */\n current: () => Mode;\n /** True when the performance-mark measurements in `<RenderMonitor>` should run. */\n measuresWithMarks: () => boolean;\n /** Called on every `<Profiler>` callback; in `\"auto\"` mode the first one switches to profiling mode. */\n profilerFired: () => void;\n}\n\n/**\n * React only calls `<Profiler onRender>` in development and in its profiling\n * build, so a callback arriving is proof that per-subtree timings are\n * available. There's no public API to ask which build is loaded, and this\n * avoids relying on React internals.\n */\nexport function createModeDetector(option: ModeOption): ModeDetector {\n let mode: Mode = option === \"profiling\" ? \"profiling\" : \"lightweight\";\n\n return {\n current: () => mode,\n measuresWithMarks: () => mode === \"lightweight\",\n profilerFired() {\n if (option === \"auto\") mode = \"profiling\";\n },\n };\n}\n","import type { LongTaskKind } from \"../types.js\";\n\nexport interface ObservedLongTask {\n kind: LongTaskKind;\n startTime: number;\n duration: number;\n}\n\n/**\n * Observes long tasks (Chromium) and long animation frames (Chromium 123+)\n * at or above `thresholdMs`. Entry types the browser doesn't support are\n * skipped. Returns a function that stops observing.\n */\nexport function observeLongTasks(thresholdMs: number, onEntry: (task: ObservedLongTask) => void): () => void {\n if (typeof PerformanceObserver === \"undefined\") return () => {};\n\n const supported = PerformanceObserver.supportedEntryTypes ?? [];\n const observers: PerformanceObserver[] = [];\n\n for (const kind of [\"longtask\", \"long-animation-frame\"] as const) {\n if (!supported.includes(kind)) continue;\n\n try {\n const observer = new PerformanceObserver((list) => {\n for (const entry of list.getEntries()) {\n if (entry.duration < thresholdMs) continue;\n onEntry({ kind, startTime: entry.startTime, duration: entry.duration });\n }\n });\n observer.observe({ type: kind, buffered: true });\n observers.push(observer);\n } catch {\n // Observing is best-effort; a browser quirk here must not reach the app.\n }\n }\n\n return () => {\n for (const observer of observers) observer.disconnect();\n };\n}\n","interface RenderWindow {\n area: string;\n start: number;\n end: number;\n duration: number;\n}\n\nexport interface RenderWindows {\n /** Records that `area` rendered for `duration` ms somewhere between `start` and `end`. */\n add: (area: string, start: number, end: number, duration: number) => void;\n /** The area to blame for a main-thread block over `[start, end]`, or `null` when no recent render overlaps it. */\n findArea: (start: number, end: number) => string | null;\n}\n\n/**\n * A fixed-size ring of recent render windows. Long-task entries arrive a\n * little after the fact, so attribution looks back over the last `size` renders.\n *\n * Nested areas overlap the same block, and an outer area's duration includes\n * its inner ones. So the blame goes to the innermost overlapping area that\n * still accounts for at least half of the longest overlapping render: an\n * inner area that's responsible for most of the time, rather than always the\n * outermost wrapper or a tiny sibling that happened to render in the same commit.\n */\nexport function createRenderWindows(size = 200): RenderWindows {\n const windows: (RenderWindow | undefined)[] = new Array(size);\n let next = 0;\n\n return {\n add(area, start, end, duration) {\n windows[next] = { area, start, end, duration };\n next = (next + 1) % size;\n },\n findArea(start, end) {\n const overlapping = windows.filter((w): w is RenderWindow => w !== undefined && w.end >= start && w.start <= end);\n if (overlapping.length === 0) return null;\n\n const longest = Math.max(...overlapping.map((w) => w.duration));\n let best: RenderWindow | null = null;\n\n for (const window of overlapping) {\n if (window.duration < longest / 2) continue;\n if (!best || window.duration < best.duration) best = window;\n }\n\n return best?.area ?? null;\n },\n };\n}\n","/**\n * Decides once per session whether to collect, so unsampled sessions pay\n * almost nothing. `sampleRate` is clamped to 0–1.\n */\nexport function shouldSample(sampleRate: number, random: () => number = Math.random): boolean {\n if (!(sampleRate > 0)) return false;\n if (sampleRate >= 1) return true;\n return random() < sampleRate;\n}\n\n/** A random session id. Not derived from anything about the user, and never persisted. */\nexport function createSessionId(): string {\n try {\n // randomUUID only exists in secure contexts (HTTPS, localhost).\n const cryptoApi = globalThis.crypto as Crypto | undefined;\n if (cryptoApi && typeof cryptoApi.randomUUID === \"function\") return cryptoApi.randomUUID();\n } catch {\n // Fall through to the non-crypto id.\n }\n return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;\n}\n","import type { Payload } from \"../types.js\";\n\nexport function byteLength(text: string): number {\n return typeof TextEncoder === \"undefined\" ? text.length * 3 : new TextEncoder().encode(text).length;\n}\n\n/**\n * Serializes a payload, shrinking it until it fits in `maxBytes`: first the\n * worst-case lists go, then the areas with the fewest renders. Returns `null`\n * when even an empty payload doesn't fit.\n */\nexport function serializePayload(payload: Payload, maxBytes: number): string | null {\n let json = JSON.stringify(payload);\n if (byteLength(json) <= maxBytes) return json;\n\n let trimmed: Payload = { ...payload, areas: payload.areas.map((a) => ({ ...a, worst: [] })) };\n json = JSON.stringify(trimmed);\n\n if (byteLength(json) > maxBytes) {\n const areas = [...trimmed.areas].sort((a, b) => b.renders - a.renders);\n let dropped = trimmed.dropped.areas;\n\n // Halve the kept areas until it fits, then the list is short enough to stop.\n while (areas.length > 0 && byteLength(json) > maxBytes) {\n const remove = Math.max(1, Math.floor(areas.length / 2));\n areas.splice(areas.length - remove, remove);\n dropped += remove;\n trimmed = { ...trimmed, areas: [...areas], dropped: { areas: dropped } };\n json = JSON.stringify(trimmed);\n }\n }\n\n return byteLength(json) <= maxBytes ? json : null;\n}\n","export interface TransportOptions {\n endpoint: string;\n /** Failed sends are retried on later flushes, up to this many attempts in total. */\n maxAttempts: number;\n /** Most failed bodies kept for retry; the oldest are dropped past this. */\n maxQueued: number;\n}\n\nexport interface Transport {\n /**\n * Sends a serialized payload. With `unloading`, uses `navigator.sendBeacon`\n * (falling back to `fetch` with `keepalive`), since the page may be gone\n * before a normal request finishes. Never throws or rejects.\n */\n send: (body: string, options: { unloading: boolean }) => void;\n}\n\ninterface QueuedBody {\n body: string;\n attempts: number;\n}\n\nexport function createTransport(options: TransportOptions): Transport {\n const queue: QueuedBody[] = [];\n\n function enqueue(item: QueuedBody): void {\n if (item.attempts >= options.maxAttempts) return;\n queue.push(item);\n if (queue.length > options.maxQueued) queue.shift();\n }\n\n function beacon(body: string): boolean {\n try {\n // A string body is sent as text/plain, a CORS-safelisted type, so\n // cross-origin collectors don't need a preflight the beacon can't do.\n return typeof navigator !== \"undefined\" && typeof navigator.sendBeacon === \"function\"\n ? navigator.sendBeacon(options.endpoint, body)\n : false;\n } catch {\n return false;\n }\n }\n\n function post(item: QueuedBody): void {\n if (typeof fetch !== \"function\") return;\n const attempt = { body: item.body, attempts: item.attempts + 1 };\n\n try {\n fetch(options.endpoint, { method: \"POST\", body: item.body, keepalive: true })\n .then((response) => {\n // 4xx means the collector rejected the payload; retrying won't help.\n if (response.status >= 500 || response.status === 429) enqueue(attempt);\n })\n .catch(() => enqueue(attempt));\n } catch {\n enqueue(attempt);\n }\n }\n\n return {\n send(body, { unloading }) {\n const items = [...queue.splice(0), { body, attempts: 0 }];\n\n for (const item of items) {\n if (unloading && beacon(item.body)) continue;\n post(item);\n }\n },\n };\n}\n","let debug = false;\n\nexport function setDebug(value: boolean): void {\n debug = value;\n}\n\n/**\n * Runs `fn`, swallowing anything it throws, so an error inside render-pulse\n * (or a user-supplied exporter or `getRoute`) never reaches the app. With\n * `debug`, the error is logged instead of silently dropped.\n */\nexport function guard<T>(fn: () => T, fallback: T): T {\n try {\n return fn();\n } catch (error) {\n if (debug && typeof console !== \"undefined\") console.warn(\"[render-pulse]\", error);\n return fallback;\n }\n}\n","import type { RenderPhase } from \"../types.js\";\n\n/** What `<RenderMonitor>` and `useRenderMonitor` call into. Every method is safe to call and never throws. */\nexport interface PulseRuntime {\n readonly sampled: boolean;\n /** True when `<RenderMonitor>` should take performance-mark measurements (lightweight mode). */\n measuresWithMarks: () => boolean;\n now: () => number;\n recordMarks: (area: string, phase: RenderPhase, start: number, end: number) => void;\n /** Returns true when the measurement was recorded, i.e. the session is in profiling mode. */\n recordProfiler: (\n area: string,\n phase: RenderPhase,\n actualDuration: number,\n startTime: number,\n commitTime: number,\n ) => boolean;\n}\n\n// Kept on globalThis so the ESM and CommonJS builds, or two bundled copies,\n// share one runtime instead of a component silently reading an empty one.\nconst KEY = Symbol.for(\"react-render-pulse.runtime\");\n\ntype RuntimeHolder = { [KEY]?: PulseRuntime | null };\n\nexport function getRuntime(): PulseRuntime | null {\n return (globalThis as RuntimeHolder)[KEY] ?? null;\n}\n\nexport function setRuntime(runtime: PulseRuntime | null): void {\n (globalThis as RuntimeHolder)[KEY] = runtime;\n}\n","import { createAggregator } from \"../aggregate/aggregator.js\";\nimport { getDeviceContext } from \"../context/device.js\";\nimport { createRouteReader, defaultGetRoute } from \"../context/route.js\";\nimport { createConsoleExporter } from \"../export/console.js\";\nimport { createModeDetector } from \"../modes/detect.js\";\nimport { observeLongTasks } from \"../observe/longtasks.js\";\nimport { createRenderWindows } from \"../observe/renderWindows.js\";\nimport { createSessionId, shouldSample } from \"../sample/sample.js\";\nimport { serializePayload } from \"../transport/payload.js\";\nimport { createTransport } from \"../transport/transport.js\";\nimport type { Exporter, LongTaskEvent, Mode, ModeOption, Payload, RenderEvent, RenderPhase } from \"../types.js\";\nimport { guard, setDebug } from \"./guard.js\";\nimport { getRuntime, setRuntime, type PulseRuntime } from \"./runtime.js\";\n\nexport interface RenderPulseOptions {\n /** Where batches are POSTed. Without one, batches only go to `exporters` (and the console, see `debug`). */\n endpoint?: string | undefined;\n /** Fraction of sessions that collect anything, 0–1, decided once at startup. Defaults to 1. */\n sampleRate?: number | undefined;\n /** `\"profiling\"`, `\"lightweight\"`, or `\"auto\"` (the default): lightweight until React's profiling build is detected. */\n mode?: ModeOption | undefined;\n /** Renders slower than this are counted as slow. Defaults to 16 (one frame at 60 Hz). */\n slowRenderMs?: number | undefined;\n /** Long tasks and long animation frames shorter than this are ignored. Defaults to 50. */\n longTaskMs?: number | undefined;\n /** Your app's version, e.g. from `import.meta.env.VITE_APP_VERSION`, for comparing releases. */\n appVersion?: string | undefined;\n /** Returns the current route, ideally a template like `/orders/:id`. Defaults to the path with numeric segments replaced by `:id`. */\n getRoute?: (() => string) | undefined;\n /** Also sends a batch this often while the page is visible. `0` sends only when the page is hidden. Defaults to 180000 (3 minutes). */\n flushIntervalMs?: number | undefined;\n /** Largest batch in bytes; bigger ones are trimmed. Defaults to 60000, under the 64 KB `sendBeacon` limit. Capped at 65536, the collector's default limit. */\n maxPayloadBytes?: number | undefined;\n /** Most area/route pairs per batch. Defaults to 200, capped at 1000 (the collector's limit). */\n maxAreas?: number | undefined;\n /** Slowest renders kept per area per batch. Defaults to 5, capped at 50 (the collector's limit). */\n worstCases?: number | undefined;\n /** Receive measurements and batches, e.g. `createOtelExporter`. */\n exporters?: Exporter[] | undefined;\n /** Logs each batch to the console and reports internal errors as warnings. Defaults to true when there's no `endpoint`. */\n debug?: boolean | undefined;\n}\n\nexport interface RenderPulse {\n /** False when this session was left out by `sampleRate`; nothing is measured or sent. */\n readonly sampled: boolean;\n /** The current measurement mode. In `\"auto\"`, this changes to `\"profiling\"` once the profiling build is detected. */\n readonly mode: Mode;\n /** Builds a batch from everything measured since the last one and sends it. Returns it, or `null` when there was nothing to send. */\n flush: () => Payload | null;\n /** Stops observing and sending, and detaches `<RenderMonitor>`s, which keep rendering their children as usual. */\n destroy: () => void;\n}\n\nconst INERT: RenderPulse = { sampled: false, mode: \"lightweight\", flush: () => null, destroy: () => {} };\n\nlet active: { destroy: () => void } | null = null;\n\n/**\n * Starts render-pulse. Call it once, before your app renders. Calling it\n * again replaces the previous setup. On the server it does nothing.\n */\nexport function initRenderPulse(options: RenderPulseOptions = {}): RenderPulse {\n if (typeof window === \"undefined\") return INERT;\n return guard(() => start(options), INERT);\n}\n\nfunction start(options: RenderPulseOptions): RenderPulse {\n active?.destroy();\n\n const {\n endpoint,\n sampleRate = 1,\n mode: modeOption = \"auto\",\n slowRenderMs = 16,\n longTaskMs = 50,\n flushIntervalMs = 180_000,\n debug = !endpoint,\n } = options;\n // Clamped to what the collector accepts, so a generous setting can't get every batch rejected.\n const maxPayloadBytes = clamp(options.maxPayloadBytes ?? 60_000, 1_000, 65_536);\n const maxAreas = clamp(options.maxAreas ?? 200, 1, 1000);\n const worstCases = clamp(options.worstCases ?? 5, 0, 50);\n const appVersion = options.appVersion?.slice(0, 100);\n\n setDebug(debug);\n const sampled = shouldSample(sampleRate);\n const now = () => performance.now();\n const sessionStart = now();\n const startedAt = Date.now();\n const sessionId = createSessionId();\n let seq = 0;\n\n const detector = createModeDetector(modeOption);\n const readRoute = createRouteReader(options.getRoute ?? defaultGetRoute);\n const route = () => guard(readRoute, \"/\").slice(0, 500);\n const areaId = (id: string) => (id ? id.slice(0, 200) : \"(unnamed)\");\n const exporters = [...(options.exporters ?? []), ...(debug ? [createConsoleExporter()] : [])];\n const aggregator = createAggregator({ slowRenderMs, maxAreas, worstCases, sessionStart });\n const windows = createRenderWindows();\n const transport = endpoint ? createTransport({ endpoint, maxAttempts: 3, maxQueued: 5 }) : null;\n\n function record(event: RenderEvent): void {\n aggregator.addRender(event);\n windows.add(event.area, event.startTime, event.endTime, event.duration);\n for (const exporter of exporters) guard(() => exporter.onRender?.(event), undefined);\n }\n\n function recordLongTask(event: LongTaskEvent): void {\n aggregator.addLongTask(event);\n for (const exporter of exporters) guard(() => exporter.onLongTask?.(event), undefined);\n }\n\n const runtime: PulseRuntime = {\n sampled,\n now,\n measuresWithMarks: () => sampled && detector.measuresWithMarks(),\n recordMarks(area, phase, startTime, endTime) {\n if (!sampled) return;\n guard(() => {\n const duration = endTime - startTime;\n // Marks measurements are lightweight-mode data even in a profiling session (e.g. from useRenderMonitor).\n record({ area: areaId(area), route: route(), phase, duration, startTime, endTime, mode: \"lightweight\" });\n }, undefined);\n },\n recordProfiler(area, phase: RenderPhase, actualDuration, startTime, commitTime) {\n if (!sampled) return false;\n return guard(() => {\n detector.profilerFired();\n if (detector.current() !== \"profiling\") return false;\n record({\n area: areaId(area),\n route: route(),\n phase,\n duration: actualDuration,\n startTime,\n endTime: commitTime,\n mode: \"profiling\",\n });\n return true;\n }, false);\n },\n };\n\n function flush(unloading: boolean): Payload | null {\n if (!sampled || aggregator.isEmpty()) return null;\n\n return guard(() => {\n const batch = aggregator.drain();\n const payload: Payload = {\n v: 1,\n session: {\n id: sessionId,\n seq: ++seq,\n mode: detector.current(),\n route: route(),\n appVersion: appVersion ?? null,\n startedAt,\n sentAt: Date.now(),\n },\n device: getDeviceContext(),\n summary: batch.summary,\n areas: batch.areas,\n longTasks: batch.longTasks,\n longFrames: batch.longFrames,\n dropped: { areas: batch.droppedAreas },\n };\n\n for (const exporter of exporters) guard(() => exporter.onFlush?.(payload), undefined);\n\n if (transport) {\n const body = serializePayload(payload, maxPayloadBytes);\n if (body) transport.send(body, { unloading });\n }\n\n return payload;\n }, null);\n }\n\n const cleanups: (() => void)[] = [];\n\n if (sampled) {\n cleanups.push(\n observeLongTasks(longTaskMs, (task) =>\n guard(() => {\n const area = windows.findArea(task.startTime, task.startTime + task.duration);\n recordLongTask({ ...task, area, route: route() });\n }, undefined),\n ),\n );\n\n // `pagehide` covers browsers (older Safari) that skip `visibilitychange` on unload.\n const onHidden = () => {\n if (document.visibilityState === \"hidden\") flush(true);\n };\n const onPageHide = () => flush(true);\n document.addEventListener(\"visibilitychange\", onHidden);\n window.addEventListener(\"pagehide\", onPageHide);\n cleanups.push(() => {\n document.removeEventListener(\"visibilitychange\", onHidden);\n window.removeEventListener(\"pagehide\", onPageHide);\n });\n\n if (flushIntervalMs > 0) {\n const timer = setInterval(() => flush(false), flushIntervalMs);\n cleanups.push(() => clearInterval(timer));\n }\n }\n\n setRuntime(runtime);\n\n const instance = {\n destroy() {\n for (const cleanup of cleanups.splice(0)) guard(cleanup, undefined);\n if (getRuntime() === runtime) setRuntime(null);\n if (active === instance) active = null;\n },\n };\n active = instance;\n\n return {\n sampled,\n get mode() {\n return detector.current();\n },\n flush: () => flush(false),\n destroy: instance.destroy,\n };\n}\n\nfunction clamp(value: number, min: number, max: number): number {\n return Number.isFinite(value) ? Math.min(max, Math.max(min, Math.floor(value))) : min;\n}\n","\"use client\";\n\nimport { Profiler, useCallback, useRef, type ProfilerOnRenderCallback, type ReactNode } from \"react\";\nimport { guard } from \"../runtime/guard.js\";\nimport { getRuntime } from \"../runtime/runtime.js\";\nimport { useIsomorphicLayoutEffect } from \"../runtime/useIsomorphicLayoutEffect.js\";\n\nexport interface RenderMonitorProps {\n /** Names this area in reports, e.g. `\"orders-table\"`. Areas with the same id are reported together. */\n id: string;\n children?: ReactNode;\n}\n\ninterface MonitorState {\n id: string;\n mounted: boolean;\n start: number;\n end: number;\n /** The `start` of the last recorded measurement, so StrictMode's repeated effects don't record it twice. */\n recordedStart: number;\n /** The latest marks measurement, waiting to see whether a `<Profiler>` callback for the same commit supersedes it. */\n pending: PendingMeasurement | null;\n}\n\ninterface PendingMeasurement {\n start: number;\n end: number;\n phase: \"mount\" | \"update\";\n superseded: boolean;\n}\n\n/**\n * Measures the renders of its children and reports them under `id`.\n *\n * The tree it renders is the same in every mode and whether or not the\n * session is sampled (a `<Profiler>` around two empty marker components), so\n * switching modes or calling `initRenderPulse` late never remounts children.\n * - Profiling mode: React's `<Profiler>` reports each commit's actual render time.\n * - Lightweight mode: the time between the start and end markers rendering,\n * which brackets the children's render. Updates that start below this area\n * (a child's own state change) don't re-render the markers, so they aren't\n * seen; profiling mode catches those.\n */\nexport function RenderMonitor({ id, children }: RenderMonitorProps): ReactNode {\n const stateRef = useRef<MonitorState | null>(null);\n if (stateRef.current === null) {\n stateRef.current = { id, mounted: false, start: 0, end: 0, recordedStart: -1, pending: null };\n }\n const state = stateRef.current;\n state.id = id;\n\n const onRender = useCallback<ProfilerOnRenderCallback>(\n (_id, phase, actualDuration, _baseDuration, startTime, commitTime) => {\n // When the Profiler's measurement of this commit is used, a marks measurement of it is a duplicate.\n if (getRuntime()?.recordProfiler(state.id, phase, actualDuration, startTime, commitTime) && state.pending) {\n state.pending.superseded = true;\n }\n },\n [state],\n );\n\n return (\n <Profiler id={id} onRender={onRender}>\n <StartMarker state={state} />\n {children}\n <EndMarker state={state} />\n </Profiler>\n );\n}\n\nfunction StartMarker({ state }: { state: MonitorState }): null {\n const runtime = getRuntime();\n if (runtime?.measuresWithMarks()) state.start = runtime.now();\n return null;\n}\n\nfunction EndMarker({ state }: { state: MonitorState }): null {\n const runtime = getRuntime();\n if (runtime?.measuresWithMarks()) state.end = runtime.now();\n\n // Layout effects only run for renders that commit, so abandoned concurrent renders aren't recorded.\n useIsomorphicLayoutEffect(() => {\n guard(() => {\n const current = getRuntime();\n if (!current?.measuresWithMarks() || state.start === state.recordedStart || state.end < state.start) return;\n\n state.recordedStart = state.start;\n const measurement: PendingMeasurement = {\n start: state.start,\n end: state.end,\n phase: state.mounted ? \"update\" : \"mount\",\n superseded: false,\n };\n state.pending = measurement;\n state.mounted = true;\n\n // The Profiler's callback for this commit (if the profiling build is in\n // use) runs later in the same commit, so wait a microtask before\n // deciding this measurement is the only one. Each commit gets its own\n // object, so several commits in one task are all kept.\n queueMicrotask(() => {\n if (state.pending === measurement) state.pending = null;\n if (!measurement.superseded) {\n getRuntime()?.recordMarks(state.id, measurement.phase, measurement.start, measurement.end);\n }\n });\n }, undefined);\n });\n\n return null;\n}\n","import { useEffect, useLayoutEffect } from \"react\";\n\n// useLayoutEffect warns during SSR on React 18; measurements only happen in the browser.\nexport const useIsomorphicLayoutEffect = typeof window === \"undefined\" ? useEffect : useLayoutEffect;\n","\"use client\";\n\nimport { useRef } from \"react\";\nimport { guard } from \"../runtime/guard.js\";\nimport { getRuntime } from \"../runtime/runtime.js\";\nimport { useIsomorphicLayoutEffect } from \"../runtime/useIsomorphicLayoutEffect.js\";\n\n/**\n * Tracks the renders of the component that calls it, reported under `id`.\n *\n * Render counts are exact. The duration runs from the hook's call to the\n * commit, so it also includes anything React renders after this component\n * in the same update: an upper bound. Wrap the component in `<RenderMonitor>`\n * when you need its own render time.\n */\nexport function useRenderMonitor(id: string): void {\n const state = useRef({ start: 0, recordedStart: -1, mounted: false }).current;\n const runtime = getRuntime();\n if (runtime?.sampled) state.start = runtime.now();\n\n useIsomorphicLayoutEffect(() => {\n guard(() => {\n const current = getRuntime();\n // `recordedStart` stops StrictMode's repeated effects from recording one render twice.\n if (!current?.sampled || state.start === state.recordedStart) return;\n\n state.recordedStart = state.start;\n current.recordMarks(id, state.mounted ? \"update\" : \"mount\", state.start, current.now());\n state.mounted = true;\n }, undefined);\n });\n}\n"],"mappings":";AAKO,IAAM,mBAAmB,CAAC,GAAG,GAAG,GAAG,GAAG,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,KAAK,KAAK,KAAK,KAAK,GAAI;AAEtF,SAAS,kBAA4B;AAC1C,SAAO,IAAI,MAAc,iBAAiB,SAAS,CAAC,EAAE,KAAK,CAAC;AAC9D;AAEO,SAAS,YAAY,IAAoB;AAC9C,WAAS,IAAI,GAAG,IAAI,iBAAiB,QAAQ,KAAK;AAChD,QAAI,OAAO,iBAAiB,CAAC,KAAK,GAAI,QAAO;AAAA,EAC/C;AACA,SAAO,iBAAiB;AAC1B;AASO,SAAS,oBAAoB,MAAyB,GAAW,KAAa,MAAM,GAAW;AACpG,QAAM,QAAQ,KAAK,OAAO,CAACA,MAAK,MAAMA,OAAM,GAAG,CAAC;AAChD,MAAI,UAAU,EAAG,QAAO;AAExB,QAAM,SAAS,KAAK,IAAK,IAAI,MAAO,OAAO,OAAO,SAAS;AAC3D,MAAI,OAAO;AAEX,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,UAAM,QAAQ,KAAK,CAAC,KAAK;AACzB,QAAI,UAAU,EAAG;AAEjB,QAAI,OAAO,SAAS,QAAQ;AAC1B,YAAM,QAAQ,KAAK,IAAI,iBAAiB,CAAC,KAAK,KAAK,GAAG;AACtD,YAAM,QAAQ,KAAK,IAAI,KAAK,IAAI,MAAM,IAAI,IAAK,iBAAiB,IAAI,CAAC,KAAK,GAAI,GAAG,GAAG,KAAK;AACzF,YAAM,YAAY,SAAS,QAAQ;AACnC,aAAO,MAAM,KAAK,IAAI,SAAS,QAAQ,SAAS,UAAU,GAAG,CAAC;AAAA,IAChE;AAEA,YAAQ;AAAA,EACV;AAEA,SAAO,MAAM,GAAG;AAClB;AAGO,SAAS,MAAM,IAAoB;AACxC,SAAO,KAAK,MAAM,KAAK,EAAE,IAAI;AAC/B;;;ACEO,SAAS,iBAAiB,SAAwC;AACvE,MAAI,QAAQ,oBAAI,IAA6B;AAC7C,MAAI,YAAY,oBAAI,IAAiC;AACrD,MAAI,aAAa,oBAAI,IAAiC;AACtD,MAAI,eAAe;AAEnB,WAAS,UAAU,OAA0B;AAC3C,UAAM,MAAM,GAAG,MAAM,KAAK,KAAS,MAAM,IAAI;AAC7C,QAAI,OAAO,MAAM,IAAI,GAAG;AAExB,QAAI,CAAC,MAAM;AACT,UAAI,MAAM,QAAQ,QAAQ,UAAU;AAClC;AACA;AAAA,MACF;AACA,aAAO;AAAA,QACL,IAAI,MAAM;AAAA,QACV,OAAO,MAAM;AAAA,QACb,SAAS;AAAA,QACT,QAAQ;AAAA,QACR,MAAM;AAAA,QACN,SAAS;AAAA,QACT,KAAK;AAAA,QACL,KAAK;AAAA,QACL,MAAM,gBAAgB;AAAA,QACtB,OAAO,CAAC;AAAA,MACV;AACA,YAAM,IAAI,KAAK,IAAI;AAAA,IACrB;AAEA,UAAM,KAAK,MAAM;AACjB,SAAK;AACL,QAAI,MAAM,UAAU,QAAS,MAAK;AAClC,QAAI,KAAK,QAAQ,aAAc,MAAK;AACpC,SAAK,WAAW;AAChB,SAAK,MAAM,KAAK,IAAI,KAAK,KAAK,EAAE;AAChC,SAAK,MAAM,KAAK,IAAI,KAAK,KAAK,EAAE;AAChC,UAAM,SAAS,YAAY,EAAE;AAC7B,SAAK,KAAK,MAAM,KAAK,KAAK,KAAK,MAAM,KAAK,KAAK;AAC/C,iBAAa,KAAK,OAAO,EAAE,IAAI,OAAO,MAAM,OAAO,IAAI,MAAM,YAAY,QAAQ,aAAa,CAAC;AAAA,EACjG;AAEA,WAAS,aAAa,OAAoB,WAA4B;AACpE,QAAI,MAAM,SAAS,QAAQ,YAAY;AACrC,YAAM,KAAK,SAAS;AAAA,IACtB,OAAO;AACL,YAAM,UAAU,MAAM,OAAO,CAAC,KAAK,GAAG,MAAO,EAAE,MAAM,MAAM,GAAG,GAAG,MAAM,KAAK,IAAI,KAAM,CAAC;AACvF,UAAI,UAAU,OAAO,MAAM,OAAO,GAAG,MAAM,GAAI;AAC/C,YAAM,OAAO,IAAI;AAAA,IACnB;AAAA,EACF;AAEA,WAAS,YAAY,OAA4B;AAC/C,UAAM,SAAS,MAAM,SAAS,aAAa,YAAY;AACvD,UAAM,MAAM,GAAG,MAAM,KAAK,KAAS,MAAM,QAAQ,EAAE;AACnD,QAAI,QAAQ,OAAO,IAAI,GAAG;AAE1B,QAAI,CAAC,OAAO;AACV,cAAQ,EAAE,MAAM,MAAM,MAAM,OAAO,MAAM,OAAO,OAAO,GAAG,SAAS,GAAG,OAAO,EAAE;AAC/E,aAAO,IAAI,KAAK,KAAK;AAAA,IACvB;AAEA,UAAM;AACN,UAAM,WAAW,MAAM;AACvB,UAAM,QAAQ,KAAK,IAAI,MAAM,OAAO,MAAM,QAAQ;AAAA,EACpD;AAEA,WAAS,QAAyB;AAChC,UAAM,cAAc,MAAM,KAAK,MAAM,OAAO,GAAG,YAAY;AAC3D,UAAM,cAAc,MAAM,KAAK,UAAU,OAAO,GAAG,gBAAgB;AACnE,UAAM,eAAe,MAAM,KAAK,WAAW,OAAO,GAAG,gBAAgB;AAErE,UAAM,QAAyB;AAAA,MAC7B,SAAS;AAAA,QACP,SAAS,IAAI,aAAa,CAAC,MAAM,EAAE,OAAO;AAAA,QAC1C,aAAa,IAAI,aAAa,CAAC,MAAM,EAAE,IAAI;AAAA,QAC3C,WAAW,IAAI,aAAa,CAAC,MAAM,EAAE,KAAK;AAAA,QAC1C,YAAY,MAAM,IAAI,aAAa,CAAC,MAAM,EAAE,OAAO,CAAC;AAAA,QACpD,YAAY,IAAI,cAAc,CAAC,MAAM,EAAE,KAAK;AAAA,QAC5C,aAAa,MAAM,IAAI,cAAc,CAAC,MAAM,EAAE,OAAO,CAAC;AAAA,MACxD;AAAA,MACA,OAAO;AAAA,MACP,WAAW;AAAA,MACX,YAAY;AAAA,MACZ;AAAA,IACF;AAEA,YAAQ,oBAAI,IAAI;AAChB,gBAAY,oBAAI,IAAI;AACpB,iBAAa,oBAAI,IAAI;AACrB,mBAAe;AACf,WAAO;AAAA,EACT;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,SAAS,MAAM,MAAM,SAAS,KAAK,UAAU,SAAS,KAAK,WAAW,SAAS,KAAK,iBAAiB;AAAA,IACrG;AAAA,EACF;AACF;AAEA,SAAS,aAAa,MAAmC;AACvD,SAAO;AAAA,IACL,IAAI,KAAK;AAAA,IACT,OAAO,KAAK;AAAA,IACZ,SAAS,KAAK;AAAA,IACd,QAAQ,KAAK;AAAA,IACb,MAAM,KAAK;AAAA,IACX,SAAS,MAAM,KAAK,OAAO;AAAA,IAC3B,KAAK,MAAM,KAAK,GAAG;AAAA,IACnB,KAAK,MAAM,KAAK,GAAG;AAAA,IACnB,KAAK,oBAAoB,KAAK,MAAM,IAAI,KAAK,KAAK,KAAK,GAAG;AAAA,IAC1D,KAAK,oBAAoB,KAAK,MAAM,IAAI,KAAK,KAAK,KAAK,GAAG;AAAA,IAC1D,KAAK,oBAAoB,KAAK,MAAM,IAAI,KAAK,KAAK,KAAK,GAAG;AAAA,IAC1D,MAAM,KAAK;AAAA,IACX,OAAO,KAAK,MACT,KAAK,CAAC,GAAG,MAAM,EAAE,KAAK,EAAE,EAAE,EAC1B,IAAI,CAAC,OAAO,EAAE,IAAI,MAAM,EAAE,EAAE,GAAG,OAAO,EAAE,OAAO,IAAI,KAAK,MAAM,EAAE,EAAE,EAAE,EAAE;AAAA,EAC3E;AACF;AAEA,SAAS,iBAAiB,OAA4C;AACpE,SAAO,EAAE,GAAG,OAAO,SAAS,MAAM,MAAM,OAAO,GAAG,OAAO,MAAM,MAAM,KAAK,EAAE;AAC9E;AAEA,SAAS,IAAO,OAAqB,MAAmC;AACtE,SAAO,MAAM,OAAO,CAAC,OAAO,SAAS,QAAQ,KAAK,IAAI,GAAG,CAAC;AAC5D;;;AC7KO,SAAS,mBAAkC;AAChD,QAAM,MAAO,OAAO,cAAc,cAAc,CAAC,IAAI;AAErD,SAAO;AAAA,IACL,UAAU,OAAO,IAAI,iBAAiB,WAAW,IAAI,eAAe;AAAA,IACpE,OAAO,OAAO,IAAI,wBAAwB,WAAW,IAAI,sBAAsB;AAAA,IAC/E,YAAY,IAAI,YAAY,iBAAiB;AAAA,IAC7C,UAAU,OAAO,WAAW,cAAc,QAAQ,GAAG,OAAO,UAAU,IAAI,OAAO,WAAW;AAAA,EAC9F;AACF;;;ACjBO,SAAS,kBAA0B;AACxC,MAAI,OAAO,aAAa,YAAa,QAAO;AAC5C,SAAO,SAAS,SAAS,QAAQ,kBAAkB,MAAM;AAC3D;AAMO,SAAS,kBAAkB,UAAsC;AACtE,MAAI,WAA0B;AAC9B,MAAI,YAAY;AAEhB,SAAO,MAAM;AACX,UAAM,OAAO,OAAO,aAAa,cAAc,KAAK,SAAS;AAC7D,QAAI,SAAS,UAAU;AACrB,iBAAW;AACX,kBAAY,SAAS;AAAA,IACvB;AACA,WAAO;AAAA,EACT;AACF;;;ACnBO,SAAS,wBAAkC;AAChD,SAAO;AAAA,IACL,QAAQ,SAAS;AACf,UAAI,OAAO,YAAY,YAAa;AAEpC,YAAM,OAAO,CAAC,GAAG,QAAQ,KAAK,EAC3B,KAAK,CAAC,GAAG,MAAM,EAAE,MAAM,EAAE,GAAG,EAC5B,IAAI,CAAC,OAAO;AAAA,QACX,MAAM,EAAE;AAAA,QACR,OAAO,EAAE;AAAA,QACT,SAAS,EAAE;AAAA,QACX,MAAM,EAAE;AAAA,QACR,KAAK,EAAE;AAAA,QACP,KAAK,EAAE;AAAA,QACP,KAAK,EAAE;AAAA,QACP,KAAK,EAAE;AAAA,MACT,EAAE;AAEJ,cAAQ;AAAA,QACN,wBAAwB,QAAQ,QAAQ,GAAG,KAAK,QAAQ,QAAQ,IAAI,MAAM,QAAQ,QAAQ,OAAO,aAAa,QAAQ,QAAQ,SAAS;AAAA,MACzI;AACA,UAAI,KAAK,SAAS,EAAG,SAAQ,MAAM,IAAI;AACvC,UAAI,QAAQ,UAAU,SAAS,EAAG,SAAQ,MAAM,QAAQ,SAAS;AACjE,UAAI,QAAQ,WAAW,SAAS,EAAG,SAAQ,MAAM,QAAQ,UAAU;AACnE,cAAQ,SAAS;AAAA,IACnB;AAAA,EACF;AACF;;;ACbO,SAAS,mBAAmB,QAAkC;AACnE,MAAI,OAAa,WAAW,cAAc,cAAc;AAExD,SAAO;AAAA,IACL,SAAS,MAAM;AAAA,IACf,mBAAmB,MAAM,SAAS;AAAA,IAClC,gBAAgB;AACd,UAAI,WAAW,OAAQ,QAAO;AAAA,IAChC;AAAA,EACF;AACF;;;ACdO,SAAS,iBAAiB,aAAqB,SAAuD;AAC3G,MAAI,OAAO,wBAAwB,YAAa,QAAO,MAAM;AAAA,EAAC;AAE9D,QAAM,YAAY,oBAAoB,uBAAuB,CAAC;AAC9D,QAAM,YAAmC,CAAC;AAE1C,aAAW,QAAQ,CAAC,YAAY,sBAAsB,GAAY;AAChE,QAAI,CAAC,UAAU,SAAS,IAAI,EAAG;AAE/B,QAAI;AACF,YAAM,WAAW,IAAI,oBAAoB,CAAC,SAAS;AACjD,mBAAW,SAAS,KAAK,WAAW,GAAG;AACrC,cAAI,MAAM,WAAW,YAAa;AAClC,kBAAQ,EAAE,MAAM,WAAW,MAAM,WAAW,UAAU,MAAM,SAAS,CAAC;AAAA,QACxE;AAAA,MACF,CAAC;AACD,eAAS,QAAQ,EAAE,MAAM,MAAM,UAAU,KAAK,CAAC;AAC/C,gBAAU,KAAK,QAAQ;AAAA,IACzB,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,SAAO,MAAM;AACX,eAAW,YAAY,UAAW,UAAS,WAAW;AAAA,EACxD;AACF;;;ACfO,SAAS,oBAAoB,OAAO,KAAoB;AAC7D,QAAM,UAAwC,IAAI,MAAM,IAAI;AAC5D,MAAI,OAAO;AAEX,SAAO;AAAA,IACL,IAAI,MAAMC,QAAO,KAAK,UAAU;AAC9B,cAAQ,IAAI,IAAI,EAAE,MAAM,OAAAA,QAAO,KAAK,SAAS;AAC7C,cAAQ,OAAO,KAAK;AAAA,IACtB;AAAA,IACA,SAASA,QAAO,KAAK;AACnB,YAAM,cAAc,QAAQ,OAAO,CAAC,MAAyB,MAAM,UAAa,EAAE,OAAOA,UAAS,EAAE,SAAS,GAAG;AAChH,UAAI,YAAY,WAAW,EAAG,QAAO;AAErC,YAAM,UAAU,KAAK,IAAI,GAAG,YAAY,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC;AAC9D,UAAI,OAA4B;AAEhC,iBAAWC,WAAU,aAAa;AAChC,YAAIA,QAAO,WAAW,UAAU,EAAG;AACnC,YAAI,CAAC,QAAQA,QAAO,WAAW,KAAK,SAAU,QAAOA;AAAA,MACvD;AAEA,aAAO,MAAM,QAAQ;AAAA,IACvB;AAAA,EACF;AACF;;;AC5CO,SAAS,aAAa,YAAoB,SAAuB,KAAK,QAAiB;AAC5F,MAAI,EAAE,aAAa,GAAI,QAAO;AAC9B,MAAI,cAAc,EAAG,QAAO;AAC5B,SAAO,OAAO,IAAI;AACpB;AAGO,SAAS,kBAA0B;AACxC,MAAI;AAEF,UAAM,YAAY,WAAW;AAC7B,QAAI,aAAa,OAAO,UAAU,eAAe,WAAY,QAAO,UAAU,WAAW;AAAA,EAC3F,QAAQ;AAAA,EAER;AACA,SAAO,GAAG,KAAK,IAAI,EAAE,SAAS,EAAE,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,EAAE,CAAC;AAC9E;;;AClBO,SAAS,WAAW,MAAsB;AAC/C,SAAO,OAAO,gBAAgB,cAAc,KAAK,SAAS,IAAI,IAAI,YAAY,EAAE,OAAO,IAAI,EAAE;AAC/F;AAOO,SAAS,iBAAiB,SAAkB,UAAiC;AAClF,MAAI,OAAO,KAAK,UAAU,OAAO;AACjC,MAAI,WAAW,IAAI,KAAK,SAAU,QAAO;AAEzC,MAAI,UAAmB,EAAE,GAAG,SAAS,OAAO,QAAQ,MAAM,IAAI,CAAC,OAAO,EAAE,GAAG,GAAG,OAAO,CAAC,EAAE,EAAE,EAAE;AAC5F,SAAO,KAAK,UAAU,OAAO;AAE7B,MAAI,WAAW,IAAI,IAAI,UAAU;AAC/B,UAAM,QAAQ,CAAC,GAAG,QAAQ,KAAK,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,UAAU,EAAE,OAAO;AACrE,QAAI,UAAU,QAAQ,QAAQ;AAG9B,WAAO,MAAM,SAAS,KAAK,WAAW,IAAI,IAAI,UAAU;AACtD,YAAM,SAAS,KAAK,IAAI,GAAG,KAAK,MAAM,MAAM,SAAS,CAAC,CAAC;AACvD,YAAM,OAAO,MAAM,SAAS,QAAQ,MAAM;AAC1C,iBAAW;AACX,gBAAU,EAAE,GAAG,SAAS,OAAO,CAAC,GAAG,KAAK,GAAG,SAAS,EAAE,OAAO,QAAQ,EAAE;AACvE,aAAO,KAAK,UAAU,OAAO;AAAA,IAC/B;AAAA,EACF;AAEA,SAAO,WAAW,IAAI,KAAK,WAAW,OAAO;AAC/C;;;ACXO,SAAS,gBAAgB,SAAsC;AACpE,QAAM,QAAsB,CAAC;AAE7B,WAAS,QAAQ,MAAwB;AACvC,QAAI,KAAK,YAAY,QAAQ,YAAa;AAC1C,UAAM,KAAK,IAAI;AACf,QAAI,MAAM,SAAS,QAAQ,UAAW,OAAM,MAAM;AAAA,EACpD;AAEA,WAAS,OAAO,MAAuB;AACrC,QAAI;AAGF,aAAO,OAAO,cAAc,eAAe,OAAO,UAAU,eAAe,aACvE,UAAU,WAAW,QAAQ,UAAU,IAAI,IAC3C;AAAA,IACN,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAEA,WAAS,KAAK,MAAwB;AACpC,QAAI,OAAO,UAAU,WAAY;AACjC,UAAM,UAAU,EAAE,MAAM,KAAK,MAAM,UAAU,KAAK,WAAW,EAAE;AAE/D,QAAI;AACF,YAAM,QAAQ,UAAU,EAAE,QAAQ,QAAQ,MAAM,KAAK,MAAM,WAAW,KAAK,CAAC,EACzE,KAAK,CAAC,aAAa;AAElB,YAAI,SAAS,UAAU,OAAO,SAAS,WAAW,IAAK,SAAQ,OAAO;AAAA,MACxE,CAAC,EACA,MAAM,MAAM,QAAQ,OAAO,CAAC;AAAA,IACjC,QAAQ;AACN,cAAQ,OAAO;AAAA,IACjB;AAAA,EACF;AAEA,SAAO;AAAA,IACL,KAAK,MAAM,EAAE,UAAU,GAAG;AACxB,YAAM,QAAQ,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE,MAAM,UAAU,EAAE,CAAC;AAExD,iBAAW,QAAQ,OAAO;AACxB,YAAI,aAAa,OAAO,KAAK,IAAI,EAAG;AACpC,aAAK,IAAI;AAAA,MACX;AAAA,IACF;AAAA,EACF;AACF;;;ACrEA,IAAI,QAAQ;AAEL,SAAS,SAAS,OAAsB;AAC7C,UAAQ;AACV;AAOO,SAAS,MAAS,IAAa,UAAgB;AACpD,MAAI;AACF,WAAO,GAAG;AAAA,EACZ,SAAS,OAAO;AACd,QAAI,SAAS,OAAO,YAAY,YAAa,SAAQ,KAAK,kBAAkB,KAAK;AACjF,WAAO;AAAA,EACT;AACF;;;ACGA,IAAM,MAAM,uBAAO,IAAI,4BAA4B;AAI5C,SAAS,aAAkC;AAChD,SAAQ,WAA6B,GAAG,KAAK;AAC/C;AAEO,SAAS,WAAW,SAAoC;AAC7D,EAAC,WAA6B,GAAG,IAAI;AACvC;;;ACuBA,IAAM,QAAqB,EAAE,SAAS,OAAO,MAAM,eAAe,OAAO,MAAM,MAAM,SAAS,MAAM;AAAC,EAAE;AAEvG,IAAI,SAAyC;AAMtC,SAAS,gBAAgB,UAA8B,CAAC,GAAgB;AAC7E,MAAI,OAAO,WAAW,YAAa,QAAO;AAC1C,SAAO,MAAM,MAAM,MAAM,OAAO,GAAG,KAAK;AAC1C;AAEA,SAAS,MAAM,SAA0C;AACvD,UAAQ,QAAQ;AAEhB,QAAM;AAAA,IACJ;AAAA,IACA,aAAa;AAAA,IACb,MAAM,aAAa;AAAA,IACnB,eAAe;AAAA,IACf,aAAa;AAAA,IACb,kBAAkB;AAAA,IAClB,OAAAC,SAAQ,CAAC;AAAA,EACX,IAAI;AAEJ,QAAM,kBAAkB,MAAM,QAAQ,mBAAmB,KAAQ,KAAO,KAAM;AAC9E,QAAM,WAAW,MAAM,QAAQ,YAAY,KAAK,GAAG,GAAI;AACvD,QAAM,aAAa,MAAM,QAAQ,cAAc,GAAG,GAAG,EAAE;AACvD,QAAM,aAAa,QAAQ,YAAY,MAAM,GAAG,GAAG;AAEnD,WAASA,MAAK;AACd,QAAM,UAAU,aAAa,UAAU;AACvC,QAAM,MAAM,MAAM,YAAY,IAAI;AAClC,QAAM,eAAe,IAAI;AACzB,QAAM,YAAY,KAAK,IAAI;AAC3B,QAAM,YAAY,gBAAgB;AAClC,MAAI,MAAM;AAEV,QAAM,WAAW,mBAAmB,UAAU;AAC9C,QAAM,YAAY,kBAAkB,QAAQ,YAAY,eAAe;AACvE,QAAM,QAAQ,MAAM,MAAM,WAAW,GAAG,EAAE,MAAM,GAAG,GAAG;AACtD,QAAM,SAAS,CAAC,OAAgB,KAAK,GAAG,MAAM,GAAG,GAAG,IAAI;AACxD,QAAM,YAAY,CAAC,GAAI,QAAQ,aAAa,CAAC,GAAI,GAAIA,SAAQ,CAAC,sBAAsB,CAAC,IAAI,CAAC,CAAE;AAC5F,QAAM,aAAa,iBAAiB,EAAE,cAAc,UAAU,YAAY,aAAa,CAAC;AACxF,QAAM,UAAU,oBAAoB;AACpC,QAAM,YAAY,WAAW,gBAAgB,EAAE,UAAU,aAAa,GAAG,WAAW,EAAE,CAAC,IAAI;AAE3F,WAAS,OAAO,OAA0B;AACxC,eAAW,UAAU,KAAK;AAC1B,YAAQ,IAAI,MAAM,MAAM,MAAM,WAAW,MAAM,SAAS,MAAM,QAAQ;AACtE,eAAW,YAAY,UAAW,OAAM,MAAM,SAAS,WAAW,KAAK,GAAG,MAAS;AAAA,EACrF;AAEA,WAAS,eAAe,OAA4B;AAClD,eAAW,YAAY,KAAK;AAC5B,eAAW,YAAY,UAAW,OAAM,MAAM,SAAS,aAAa,KAAK,GAAG,MAAS;AAAA,EACvF;AAEA,QAAM,UAAwB;AAAA,IAC5B;AAAA,IACA;AAAA,IACA,mBAAmB,MAAM,WAAW,SAAS,kBAAkB;AAAA,IAC/D,YAAY,MAAM,OAAO,WAAW,SAAS;AAC3C,UAAI,CAAC,QAAS;AACd,YAAM,MAAM;AACV,cAAM,WAAW,UAAU;AAE3B,eAAO,EAAE,MAAM,OAAO,IAAI,GAAG,OAAO,MAAM,GAAG,OAAO,UAAU,WAAW,SAAS,MAAM,cAAc,CAAC;AAAA,MACzG,GAAG,MAAS;AAAA,IACd;AAAA,IACA,eAAe,MAAM,OAAoB,gBAAgB,WAAW,YAAY;AAC9E,UAAI,CAAC,QAAS,QAAO;AACrB,aAAO,MAAM,MAAM;AACjB,iBAAS,cAAc;AACvB,YAAI,SAAS,QAAQ,MAAM,YAAa,QAAO;AAC/C,eAAO;AAAA,UACL,MAAM,OAAO,IAAI;AAAA,UACjB,OAAO,MAAM;AAAA,UACb;AAAA,UACA,UAAU;AAAA,UACV;AAAA,UACA,SAAS;AAAA,UACT,MAAM;AAAA,QACR,CAAC;AACD,eAAO;AAAA,MACT,GAAG,KAAK;AAAA,IACV;AAAA,EACF;AAEA,WAAS,MAAM,WAAoC;AACjD,QAAI,CAAC,WAAW,WAAW,QAAQ,EAAG,QAAO;AAE7C,WAAO,MAAM,MAAM;AACjB,YAAM,QAAQ,WAAW,MAAM;AAC/B,YAAM,UAAmB;AAAA,QACvB,GAAG;AAAA,QACH,SAAS;AAAA,UACP,IAAI;AAAA,UACJ,KAAK,EAAE;AAAA,UACP,MAAM,SAAS,QAAQ;AAAA,UACvB,OAAO,MAAM;AAAA,UACb,YAAY,cAAc;AAAA,UAC1B;AAAA,UACA,QAAQ,KAAK,IAAI;AAAA,QACnB;AAAA,QACA,QAAQ,iBAAiB;AAAA,QACzB,SAAS,MAAM;AAAA,QACf,OAAO,MAAM;AAAA,QACb,WAAW,MAAM;AAAA,QACjB,YAAY,MAAM;AAAA,QAClB,SAAS,EAAE,OAAO,MAAM,aAAa;AAAA,MACvC;AAEA,iBAAW,YAAY,UAAW,OAAM,MAAM,SAAS,UAAU,OAAO,GAAG,MAAS;AAEpF,UAAI,WAAW;AACb,cAAM,OAAO,iBAAiB,SAAS,eAAe;AACtD,YAAI,KAAM,WAAU,KAAK,MAAM,EAAE,UAAU,CAAC;AAAA,MAC9C;AAEA,aAAO;AAAA,IACT,GAAG,IAAI;AAAA,EACT;AAEA,QAAM,WAA2B,CAAC;AAElC,MAAI,SAAS;AACX,aAAS;AAAA,MACP;AAAA,QAAiB;AAAA,QAAY,CAAC,SAC5B,MAAM,MAAM;AACV,gBAAM,OAAO,QAAQ,SAAS,KAAK,WAAW,KAAK,YAAY,KAAK,QAAQ;AAC5E,yBAAe,EAAE,GAAG,MAAM,MAAM,OAAO,MAAM,EAAE,CAAC;AAAA,QAClD,GAAG,MAAS;AAAA,MACd;AAAA,IACF;AAGA,UAAM,WAAW,MAAM;AACrB,UAAI,SAAS,oBAAoB,SAAU,OAAM,IAAI;AAAA,IACvD;AACA,UAAM,aAAa,MAAM,MAAM,IAAI;AACnC,aAAS,iBAAiB,oBAAoB,QAAQ;AACtD,WAAO,iBAAiB,YAAY,UAAU;AAC9C,aAAS,KAAK,MAAM;AAClB,eAAS,oBAAoB,oBAAoB,QAAQ;AACzD,aAAO,oBAAoB,YAAY,UAAU;AAAA,IACnD,CAAC;AAED,QAAI,kBAAkB,GAAG;AACvB,YAAM,QAAQ,YAAY,MAAM,MAAM,KAAK,GAAG,eAAe;AAC7D,eAAS,KAAK,MAAM,cAAc,KAAK,CAAC;AAAA,IAC1C;AAAA,EACF;AAEA,aAAW,OAAO;AAElB,QAAM,WAAW;AAAA,IACf,UAAU;AACR,iBAAW,WAAW,SAAS,OAAO,CAAC,EAAG,OAAM,SAAS,MAAS;AAClE,UAAI,WAAW,MAAM,QAAS,YAAW,IAAI;AAC7C,UAAI,WAAW,SAAU,UAAS;AAAA,IACpC;AAAA,EACF;AACA,WAAS;AAET,SAAO;AAAA,IACL;AAAA,IACA,IAAI,OAAO;AACT,aAAO,SAAS,QAAQ;AAAA,IAC1B;AAAA,IACA,OAAO,MAAM,MAAM,KAAK;AAAA,IACxB,SAAS,SAAS;AAAA,EACpB;AACF;AAEA,SAAS,MAAM,OAAe,KAAa,KAAqB;AAC9D,SAAO,OAAO,SAAS,KAAK,IAAI,KAAK,IAAI,KAAK,KAAK,IAAI,KAAK,KAAK,MAAM,KAAK,CAAC,CAAC,IAAI;AACpF;;;ACtOA,SAAS,UAAU,aAAa,cAA6D;;;ACF7F,SAAS,WAAW,uBAAuB;AAGpC,IAAM,4BAA4B,OAAO,WAAW,cAAc,YAAY;;;AD2DjF,SACE,KADF;AAnBG,SAAS,cAAc,EAAE,IAAI,SAAS,GAAkC;AAC7E,QAAM,WAAW,OAA4B,IAAI;AACjD,MAAI,SAAS,YAAY,MAAM;AAC7B,aAAS,UAAU,EAAE,IAAI,SAAS,OAAO,OAAO,GAAG,KAAK,GAAG,eAAe,IAAI,SAAS,KAAK;AAAA,EAC9F;AACA,QAAM,QAAQ,SAAS;AACvB,QAAM,KAAK;AAEX,QAAM,WAAW;AAAA,IACf,CAAC,KAAK,OAAO,gBAAgB,eAAe,WAAW,eAAe;AAEpE,UAAI,WAAW,GAAG,eAAe,MAAM,IAAI,OAAO,gBAAgB,WAAW,UAAU,KAAK,MAAM,SAAS;AACzG,cAAM,QAAQ,aAAa;AAAA,MAC7B;AAAA,IACF;AAAA,IACA,CAAC,KAAK;AAAA,EACR;AAEA,SACE,qBAAC,YAAS,IAAQ,UAChB;AAAA,wBAAC,eAAY,OAAc;AAAA,IAC1B;AAAA,IACD,oBAAC,aAAU,OAAc;AAAA,KAC3B;AAEJ;AAEA,SAAS,YAAY,EAAE,MAAM,GAAkC;AAC7D,QAAM,UAAU,WAAW;AAC3B,MAAI,SAAS,kBAAkB,EAAG,OAAM,QAAQ,QAAQ,IAAI;AAC5D,SAAO;AACT;AAEA,SAAS,UAAU,EAAE,MAAM,GAAkC;AAC3D,QAAM,UAAU,WAAW;AAC3B,MAAI,SAAS,kBAAkB,EAAG,OAAM,MAAM,QAAQ,IAAI;AAG1D,4BAA0B,MAAM;AAC9B,UAAM,MAAM;AACV,YAAM,UAAU,WAAW;AAC3B,UAAI,CAAC,SAAS,kBAAkB,KAAK,MAAM,UAAU,MAAM,iBAAiB,MAAM,MAAM,MAAM,MAAO;AAErG,YAAM,gBAAgB,MAAM;AAC5B,YAAM,cAAkC;AAAA,QACtC,OAAO,MAAM;AAAA,QACb,KAAK,MAAM;AAAA,QACX,OAAO,MAAM,UAAU,WAAW;AAAA,QAClC,YAAY;AAAA,MACd;AACA,YAAM,UAAU;AAChB,YAAM,UAAU;AAMhB,qBAAe,MAAM;AACnB,YAAI,MAAM,YAAY,YAAa,OAAM,UAAU;AACnD,YAAI,CAAC,YAAY,YAAY;AAC3B,qBAAW,GAAG,YAAY,MAAM,IAAI,YAAY,OAAO,YAAY,OAAO,YAAY,GAAG;AAAA,QAC3F;AAAA,MACF,CAAC;AAAA,IACH,GAAG,MAAS;AAAA,EACd,CAAC;AAED,SAAO;AACT;;;AE5GA,SAAS,UAAAC,eAAc;AAahB,SAAS,iBAAiB,IAAkB;AACjD,QAAM,QAAQC,QAAO,EAAE,OAAO,GAAG,eAAe,IAAI,SAAS,MAAM,CAAC,EAAE;AACtE,QAAM,UAAU,WAAW;AAC3B,MAAI,SAAS,QAAS,OAAM,QAAQ,QAAQ,IAAI;AAEhD,4BAA0B,MAAM;AAC9B,UAAM,MAAM;AACV,YAAM,UAAU,WAAW;AAE3B,UAAI,CAAC,SAAS,WAAW,MAAM,UAAU,MAAM,cAAe;AAE9D,YAAM,gBAAgB,MAAM;AAC5B,cAAQ,YAAY,IAAI,MAAM,UAAU,WAAW,SAAS,MAAM,OAAO,QAAQ,IAAI,CAAC;AACtF,YAAM,UAAU;AAAA,IAClB,GAAG,MAAS;AAAA,EACd,CAAC;AACH;","names":["sum","start","window","debug","useRef","useRef"]}
1
+ {"version":3,"sources":["../src/aggregate/histogram.ts","../src/aggregate/aggregator.ts","../src/context/device.ts","../src/context/route.ts","../src/export/console.ts","../src/modes/detect.ts","../src/observe/longtasks.ts","../src/observe/renderWindows.ts","../src/sample/sample.ts","../src/transport/payload.ts","../src/transport/transport.ts","../src/runtime/guard.ts","../src/runtime/runtime.ts","../src/runtime/initRenderPulse.ts","../src/components/RenderMonitor.tsx","../src/runtime/useIsomorphicLayoutEffect.ts","../src/hooks/useRenderMonitor.ts"],"sourcesContent":["/**\n * Upper bounds (ms, inclusive) of the render-duration histogram buckets, plus\n * an implicit overflow bucket. Part of payload v1: the collector merges\n * histograms by index, so changing these needs a new payload version.\n */\nexport const HISTOGRAM_BOUNDS = [1, 2, 4, 8, 12, 16, 24, 33, 50, 75, 100, 150, 250, 500, 1000] as const;\n\nexport function createHistogram(): number[] {\n return new Array<number>(HISTOGRAM_BOUNDS.length + 1).fill(0);\n}\n\nexport function bucketIndex(ms: number): number {\n for (let i = 0; i < HISTOGRAM_BOUNDS.length; i++) {\n if (ms <= (HISTOGRAM_BOUNDS[i] ?? 0)) return i;\n }\n return HISTOGRAM_BOUNDS.length;\n}\n\n/**\n * Estimates a percentile (0–100) from bucket counts, interpolating linearly\n * inside the bucket. The observed `min` and `max` narrow the bucket's range\n * (every value lies between them): without them, durations clustered at a\n * bucket edge, like many renders of exactly 8 ms, would be estimated from\n * the bucket's middle instead.\n */\nexport function histogramPercentile(hist: readonly number[], p: number, max: number, min = 0): number {\n const total = hist.reduce((sum, n) => sum + n, 0);\n if (total === 0) return 0;\n\n const target = Math.max((p / 100) * total, Number.MIN_VALUE);\n let seen = 0;\n\n for (let i = 0; i < hist.length; i++) {\n const count = hist[i] ?? 0;\n if (count === 0) continue;\n\n if (seen + count >= target) {\n const upper = Math.min(HISTOGRAM_BOUNDS[i] ?? max, max);\n const lower = Math.min(Math.max(i === 0 ? 0 : (HISTOGRAM_BOUNDS[i - 1] ?? 0), min), upper);\n const fraction = (target - seen) / count;\n return round(Math.min(lower + (upper - lower) * fraction, max));\n }\n\n seen += count;\n }\n\n return round(max);\n}\n\n/** Rounds to 0.1 ms: finer precision isn't meaningful and costs payload bytes. */\nexport function round(ms: number): number {\n return Math.round(ms * 10) / 10;\n}\n","import { bucketIndex, createHistogram, histogramPercentile, round } from \"./histogram.js\";\nimport type { AreaReport, LongTaskEvent, LongTaskReport, RenderEvent, SessionSummary, WorstCase } from \"../types.js\";\n\nexport interface AggregatorOptions {\n /** Renders slower than this count as slow. */\n slowRenderMs: number;\n /** Most distinct area/route pairs kept per batch; renders for new ones past this are dropped. */\n maxAreas: number;\n /** How many of the slowest renders to keep per area. */\n worstCases: number;\n /** `performance.now()` at session start, so worst cases report time since then. */\n sessionStart: number;\n}\n\nexport interface AggregatedBatch {\n summary: SessionSummary;\n areas: AreaReport[];\n longTasks: LongTaskReport[];\n longFrames: LongTaskReport[];\n droppedAreas: number;\n}\n\nexport interface Aggregator {\n addRender: (event: RenderEvent) => void;\n addLongTask: (event: LongTaskEvent) => void;\n /** True when nothing was recorded since the last `drain()`. */\n isEmpty: () => boolean;\n /** Returns everything recorded since the last call, and starts a new batch. */\n drain: () => AggregatedBatch;\n}\n\ninterface AreaAccumulator {\n id: string;\n route: string;\n renders: number;\n mounts: number;\n slow: number;\n totalMs: number;\n min: number;\n max: number;\n hist: number[];\n worst: WorstCase[];\n}\n\ninterface LongTaskAccumulator {\n area: string | null;\n route: string;\n count: number;\n totalMs: number;\n maxMs: number;\n}\n\n// Only counts, histograms, and a few worst cases are kept, never raw event\n// streams, so memory stays flat however long the session runs.\nexport function createAggregator(options: AggregatorOptions): Aggregator {\n let areas = new Map<string, AreaAccumulator>();\n let longTasks = new Map<string, LongTaskAccumulator>();\n let longFrames = new Map<string, LongTaskAccumulator>();\n let droppedAreas = 0;\n\n function addRender(event: RenderEvent): void {\n const key = `${event.route}\\u0000${event.area}`;\n let area = areas.get(key);\n\n if (!area) {\n if (areas.size >= options.maxAreas) {\n droppedAreas++;\n return;\n }\n area = {\n id: event.area,\n route: event.route,\n renders: 0,\n mounts: 0,\n slow: 0,\n totalMs: 0,\n min: Infinity,\n max: 0,\n hist: createHistogram(),\n worst: [],\n };\n areas.set(key, area);\n }\n\n const ms = event.duration;\n area.renders++;\n if (event.phase === \"mount\") area.mounts++;\n if (ms > options.slowRenderMs) area.slow++;\n area.totalMs += ms;\n area.min = Math.min(area.min, ms);\n area.max = Math.max(area.max, ms);\n const bucket = bucketIndex(ms);\n area.hist[bucket] = (area.hist[bucket] ?? 0) + 1;\n addWorstCase(area.worst, { ms, phase: event.phase, at: event.startTime - options.sessionStart });\n }\n\n function addWorstCase(worst: WorstCase[], candidate: WorstCase): void {\n if (worst.length < options.worstCases) {\n worst.push(candidate);\n } else {\n const fastest = worst.reduce((min, w, i) => (w.ms < (worst[min]?.ms ?? 0) ? i : min), 0);\n if (candidate.ms <= (worst[fastest]?.ms ?? 0)) return;\n worst[fastest] = candidate;\n }\n }\n\n function addLongTask(event: LongTaskEvent): void {\n const target = event.kind === \"longtask\" ? longTasks : longFrames;\n const key = `${event.route}\\u0000${event.area ?? \"\"}`;\n let entry = target.get(key);\n\n if (!entry) {\n entry = { area: event.area, route: event.route, count: 0, totalMs: 0, maxMs: 0 };\n target.set(key, entry);\n }\n\n entry.count++;\n entry.totalMs += event.duration;\n entry.maxMs = Math.max(entry.maxMs, event.duration);\n }\n\n function drain(): AggregatedBatch {\n const areaReports = Array.from(areas.values(), toAreaReport);\n const taskReports = Array.from(longTasks.values(), toLongTaskReport);\n const frameReports = Array.from(longFrames.values(), toLongTaskReport);\n\n const batch: AggregatedBatch = {\n summary: {\n renders: sum(areaReports, (a) => a.renders),\n slowRenders: sum(areaReports, (a) => a.slow),\n longTasks: sum(taskReports, (t) => t.count),\n longTaskMs: round(sum(taskReports, (t) => t.totalMs)),\n longFrames: sum(frameReports, (t) => t.count),\n longFrameMs: round(sum(frameReports, (t) => t.totalMs)),\n },\n areas: areaReports,\n longTasks: taskReports,\n longFrames: frameReports,\n droppedAreas,\n };\n\n areas = new Map();\n longTasks = new Map();\n longFrames = new Map();\n droppedAreas = 0;\n return batch;\n }\n\n return {\n addRender,\n addLongTask,\n isEmpty: () => areas.size === 0 && longTasks.size === 0 && longFrames.size === 0 && droppedAreas === 0,\n drain,\n };\n}\n\nfunction toAreaReport(area: AreaAccumulator): AreaReport {\n return {\n id: area.id,\n route: area.route,\n renders: area.renders,\n mounts: area.mounts,\n slow: area.slow,\n totalMs: round(area.totalMs),\n min: round(area.min),\n max: round(area.max),\n p50: histogramPercentile(area.hist, 50, area.max, area.min),\n p75: histogramPercentile(area.hist, 75, area.max, area.min),\n p95: histogramPercentile(area.hist, 95, area.max, area.min),\n hist: area.hist,\n worst: area.worst\n .sort((a, b) => b.ms - a.ms)\n .map((w) => ({ ms: round(w.ms), phase: w.phase, at: Math.round(w.at) })),\n };\n}\n\nfunction toLongTaskReport(entry: LongTaskAccumulator): LongTaskReport {\n return { ...entry, totalMs: round(entry.totalMs), maxMs: round(entry.maxMs) };\n}\n\nfunction sum<T>(items: readonly T[], pick: (item: T) => number): number {\n return items.reduce((total, item) => total + pick(item), 0);\n}\n","import type { DeviceContext } from \"../types.js\";\n\n// Non-standard APIs (Chromium only), so they're read defensively.\ninterface NavigatorWithHints {\n deviceMemory?: number;\n hardwareConcurrency?: number;\n connection?: { effectiveType?: string };\n}\n\nexport function getDeviceContext(): DeviceContext {\n const nav = (typeof navigator === \"undefined\" ? {} : navigator) as NavigatorWithHints;\n\n return {\n memoryGb: typeof nav.deviceMemory === \"number\" ? nav.deviceMemory : null,\n cores: typeof nav.hardwareConcurrency === \"number\" ? nav.hardwareConcurrency : null,\n connection: nav.connection?.effectiveType ?? null,\n viewport: typeof window === \"undefined\" ? \"0x0\" : `${window.innerWidth}x${window.innerHeight}`,\n };\n}\n","/** Default route reader: the path with numeric segments replaced, so `/orders/42` and `/orders/7` group together. */\nexport function defaultGetRoute(): string {\n if (typeof location === \"undefined\") return \"/\";\n return location.pathname.replace(/\\/\\d+(?=\\/|$)/g, \"/:id\");\n}\n\n/**\n * Wraps a route reader so it only runs when the URL changes, since it's\n * called on every measured render.\n */\nexport function createRouteReader(getRoute: () => string): () => string {\n let lastHref: string | null = null;\n let lastRoute = \"/\";\n\n return () => {\n const href = typeof location === \"undefined\" ? \"\" : location.href;\n if (href !== lastHref) {\n lastHref = href;\n lastRoute = getRoute();\n }\n return lastRoute;\n };\n}\n","import type { Exporter } from \"../types.js\";\n\n/** Logs each batch as a table, slowest areas first. Used by default when no `endpoint` is set, for local testing. */\nexport function createConsoleExporter(): Exporter {\n return {\n onFlush(payload) {\n if (typeof console === \"undefined\") return;\n\n const rows = [...payload.areas]\n .sort((a, b) => b.p75 - a.p75)\n .map((a) => ({\n area: a.id,\n route: a.route,\n renders: a.renders,\n slow: a.slow,\n p50: a.p50,\n p75: a.p75,\n p95: a.p95,\n max: a.max,\n }));\n\n console.groupCollapsed(\n `[render-pulse] batch ${payload.session.seq} (${payload.session.mode}): ${payload.summary.renders} renders, ${payload.summary.longTasks} long tasks`,\n );\n if (rows.length > 0) console.table(rows);\n if (payload.longTasks.length > 0) console.table(payload.longTasks);\n if (payload.longFrames.length > 0) console.table(payload.longFrames);\n console.groupEnd();\n },\n };\n}\n","import type { Mode, ModeOption } from \"../types.js\";\n\nexport interface ModeDetector {\n /** The mode measurements are currently taken in. */\n current: () => Mode;\n /** True when the performance-mark measurements in `<RenderMonitor>` should run. */\n measuresWithMarks: () => boolean;\n /** Called on every `<Profiler>` callback; in `\"auto\"` mode the first one switches to profiling mode. */\n profilerFired: () => void;\n}\n\n/**\n * React only calls `<Profiler onRender>` in development and in its profiling\n * build, so a callback arriving is proof that per-subtree timings are\n * available. There's no public API to ask which build is loaded, and this\n * avoids relying on React internals.\n */\nexport function createModeDetector(option: ModeOption): ModeDetector {\n let mode: Mode = option === \"profiling\" ? \"profiling\" : \"lightweight\";\n\n return {\n current: () => mode,\n measuresWithMarks: () => mode === \"lightweight\",\n profilerFired() {\n if (option === \"auto\") mode = \"profiling\";\n },\n };\n}\n","import type { LongTaskKind } from \"../types.js\";\n\nexport interface ObservedLongTask {\n kind: LongTaskKind;\n startTime: number;\n duration: number;\n}\n\n/**\n * Observes long tasks (Chromium) and long animation frames (Chromium 123+)\n * at or above `thresholdMs`. Entry types the browser doesn't support are\n * skipped. Returns a function that stops observing.\n */\nexport function observeLongTasks(thresholdMs: number, onEntry: (task: ObservedLongTask) => void): () => void {\n if (typeof PerformanceObserver === \"undefined\") return () => {};\n\n const supported = PerformanceObserver.supportedEntryTypes ?? [];\n const observers: PerformanceObserver[] = [];\n\n for (const kind of [\"longtask\", \"long-animation-frame\"] as const) {\n if (!supported.includes(kind)) continue;\n\n try {\n const observer = new PerformanceObserver((list) => {\n for (const entry of list.getEntries()) {\n if (entry.duration < thresholdMs) continue;\n onEntry({ kind, startTime: entry.startTime, duration: entry.duration });\n }\n });\n observer.observe({ type: kind, buffered: true });\n observers.push(observer);\n } catch {\n // Observing is best-effort; a browser quirk here must not reach the app.\n }\n }\n\n return () => {\n for (const observer of observers) observer.disconnect();\n };\n}\n","interface RenderWindow {\n area: string;\n start: number;\n end: number;\n duration: number;\n}\n\nexport interface RenderWindows {\n /** Records that `area` rendered for `duration` ms somewhere between `start` and `end`. */\n add: (area: string, start: number, end: number, duration: number) => void;\n /** The area to blame for a main-thread block over `[start, end]`, or `null` when no recent render overlaps it. */\n findArea: (start: number, end: number) => string | null;\n}\n\n/**\n * A fixed-size ring of recent render windows. Long-task entries arrive a\n * little after the fact, so attribution looks back over the last `size` renders.\n *\n * Nested areas overlap the same block, and an outer area's duration includes\n * its inner ones. So the blame goes to the innermost overlapping area that\n * still accounts for at least half of the longest overlapping render: an\n * inner area that's responsible for most of the time, rather than always the\n * outermost wrapper or a tiny sibling that happened to render in the same commit.\n */\nexport function createRenderWindows(size = 200): RenderWindows {\n const windows: (RenderWindow | undefined)[] = new Array(size);\n let next = 0;\n\n return {\n add(area, start, end, duration) {\n windows[next] = { area, start, end, duration };\n next = (next + 1) % size;\n },\n findArea(start, end) {\n const overlapping = windows.filter((w): w is RenderWindow => w !== undefined && w.end >= start && w.start <= end);\n if (overlapping.length === 0) return null;\n\n const longest = Math.max(...overlapping.map((w) => w.duration));\n let best: RenderWindow | null = null;\n\n for (const window of overlapping) {\n if (window.duration < longest / 2) continue;\n if (!best || window.duration < best.duration) best = window;\n }\n\n return best?.area ?? null;\n },\n };\n}\n","/**\n * Decides once per session whether to collect, so unsampled sessions pay\n * almost nothing. `sampleRate` is clamped to 0–1.\n */\nexport function shouldSample(sampleRate: number, random: () => number = Math.random): boolean {\n if (!(sampleRate > 0)) return false;\n if (sampleRate >= 1) return true;\n return random() < sampleRate;\n}\n\n/** A random session id. Not derived from anything about the user, and never persisted. */\nexport function createSessionId(): string {\n try {\n // randomUUID only exists in secure contexts (HTTPS, localhost).\n const cryptoApi = globalThis.crypto as Crypto | undefined;\n if (cryptoApi && typeof cryptoApi.randomUUID === \"function\") return cryptoApi.randomUUID();\n } catch {\n // Fall through to the non-crypto id.\n }\n return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;\n}\n","import type { Payload } from \"../types.js\";\n\nexport function byteLength(text: string): number {\n return typeof TextEncoder === \"undefined\" ? text.length * 3 : new TextEncoder().encode(text).length;\n}\n\n/**\n * Serializes a payload, shrinking it until it fits in `maxBytes`: first the\n * worst-case lists go, then the areas with the fewest renders. Returns `null`\n * when even an empty payload doesn't fit.\n */\nexport function serializePayload(payload: Payload, maxBytes: number): string | null {\n let json = JSON.stringify(payload);\n if (byteLength(json) <= maxBytes) return json;\n\n let trimmed: Payload = { ...payload, areas: payload.areas.map((a) => ({ ...a, worst: [] })) };\n json = JSON.stringify(trimmed);\n\n if (byteLength(json) > maxBytes) {\n const areas = [...trimmed.areas].sort((a, b) => b.renders - a.renders);\n let dropped = trimmed.dropped.areas;\n\n // Halve the kept areas until it fits, then the list is short enough to stop.\n while (areas.length > 0 && byteLength(json) > maxBytes) {\n const remove = Math.max(1, Math.floor(areas.length / 2));\n areas.splice(areas.length - remove, remove);\n dropped += remove;\n trimmed = { ...trimmed, areas: [...areas], dropped: { areas: dropped } };\n json = JSON.stringify(trimmed);\n }\n }\n\n return byteLength(json) <= maxBytes ? json : null;\n}\n","export interface TransportOptions {\n endpoint: string;\n /** Failed sends are retried on later flushes, up to this many attempts in total. */\n maxAttempts: number;\n /** Most failed bodies kept for retry; the oldest are dropped past this. */\n maxQueued: number;\n}\n\nexport interface Transport {\n /**\n * Sends a serialized payload. With `unloading`, uses `navigator.sendBeacon`\n * (falling back to `fetch` with `keepalive`), since the page may be gone\n * before a normal request finishes. Never throws or rejects.\n */\n send: (body: string, options: { unloading: boolean }) => void;\n}\n\ninterface QueuedBody {\n body: string;\n attempts: number;\n}\n\nexport function createTransport(options: TransportOptions): Transport {\n const queue: QueuedBody[] = [];\n\n function enqueue(item: QueuedBody): void {\n if (item.attempts >= options.maxAttempts) return;\n queue.push(item);\n if (queue.length > options.maxQueued) queue.shift();\n }\n\n function beacon(body: string): boolean {\n try {\n // A string body is sent as text/plain, a CORS-safelisted type, so\n // cross-origin collectors don't need a preflight the beacon can't do.\n return typeof navigator !== \"undefined\" && typeof navigator.sendBeacon === \"function\"\n ? navigator.sendBeacon(options.endpoint, body)\n : false;\n } catch {\n return false;\n }\n }\n\n function post(item: QueuedBody): void {\n if (typeof fetch !== \"function\") return;\n const attempt = { body: item.body, attempts: item.attempts + 1 };\n\n try {\n fetch(options.endpoint, { method: \"POST\", body: item.body, keepalive: true })\n .then((response) => {\n // 4xx means the collector rejected the payload; retrying won't help.\n if (response.status >= 500 || response.status === 429) enqueue(attempt);\n })\n .catch(() => enqueue(attempt));\n } catch {\n enqueue(attempt);\n }\n }\n\n return {\n send(body, { unloading }) {\n const items = [...queue.splice(0), { body, attempts: 0 }];\n\n for (const item of items) {\n if (unloading && beacon(item.body)) continue;\n post(item);\n }\n },\n };\n}\n","let debug = false;\n\nexport function setDebug(value: boolean): void {\n debug = value;\n}\n\n/**\n * Runs `fn`, swallowing anything it throws, so an error inside render-pulse\n * (or a user-supplied exporter or `getRoute`) never reaches the app. With\n * `debug`, the error is logged instead of silently dropped.\n */\nexport function guard<T>(fn: () => T, fallback: T): T {\n try {\n return fn();\n } catch (error) {\n if (debug && typeof console !== \"undefined\") console.warn(\"[render-pulse]\", error);\n return fallback;\n }\n}\n","import type { RenderPhase } from \"../types.js\";\n\n/** What `<RenderMonitor>` and `useRenderMonitor` call into. Every method is safe to call and never throws. */\nexport interface PulseRuntime {\n readonly sampled: boolean;\n /** True when `<RenderMonitor>` should take performance-mark measurements (lightweight mode). */\n measuresWithMarks: () => boolean;\n now: () => number;\n recordMarks: (area: string, phase: RenderPhase, start: number, end: number) => void;\n /** Returns true when the measurement was recorded, i.e. the session is in profiling mode. */\n recordProfiler: (\n area: string,\n phase: RenderPhase,\n actualDuration: number,\n startTime: number,\n commitTime: number,\n ) => boolean;\n}\n\n// Kept on globalThis so the ESM and CommonJS builds, or two bundled copies,\n// share one runtime instead of a component silently reading an empty one.\nconst KEY = Symbol.for(\"react-render-pulse.runtime\");\n\ntype RuntimeHolder = { [KEY]?: PulseRuntime | null };\n\nexport function getRuntime(): PulseRuntime | null {\n return (globalThis as RuntimeHolder)[KEY] ?? null;\n}\n\nexport function setRuntime(runtime: PulseRuntime | null): void {\n (globalThis as RuntimeHolder)[KEY] = runtime;\n}\n","import { createAggregator } from \"../aggregate/aggregator.js\";\nimport { getDeviceContext } from \"../context/device.js\";\nimport { createRouteReader, defaultGetRoute } from \"../context/route.js\";\nimport { createConsoleExporter } from \"../export/console.js\";\nimport { createModeDetector } from \"../modes/detect.js\";\nimport { observeLongTasks } from \"../observe/longtasks.js\";\nimport { createRenderWindows } from \"../observe/renderWindows.js\";\nimport { createSessionId, shouldSample } from \"../sample/sample.js\";\nimport { serializePayload } from \"../transport/payload.js\";\nimport { createTransport } from \"../transport/transport.js\";\nimport type { Exporter, LongTaskEvent, Mode, ModeOption, Payload, RenderEvent, RenderPhase } from \"../types.js\";\nimport { guard, setDebug } from \"./guard.js\";\nimport { getRuntime, setRuntime, type PulseRuntime } from \"./runtime.js\";\n\nexport interface RenderPulseOptions {\n /** Where batches are POSTed. Without one, batches only go to `exporters` (and the console, see `debug`). */\n endpoint?: string | undefined;\n /** Fraction of sessions that collect anything, 0–1, decided once at startup. Defaults to 1. */\n sampleRate?: number | undefined;\n /** `\"profiling\"`, `\"lightweight\"`, or `\"auto\"` (the default): lightweight until React's profiling build is detected. */\n mode?: ModeOption | undefined;\n /** Renders slower than this are counted as slow. Defaults to 16 (one frame at 60 Hz). */\n slowRenderMs?: number | undefined;\n /** Long tasks and long animation frames shorter than this are ignored. Defaults to 50. */\n longTaskMs?: number | undefined;\n /** Your app's version, e.g. from `import.meta.env.VITE_APP_VERSION`, for comparing releases. */\n appVersion?: string | undefined;\n /** Returns the current route, ideally a template like `/orders/:id`. Defaults to the path with numeric segments replaced by `:id`. */\n getRoute?: (() => string) | undefined;\n /** Also sends a batch this often while the page is visible. `0` sends only when the page is hidden. Defaults to 180000 (3 minutes). */\n flushIntervalMs?: number | undefined;\n /** Largest batch in bytes; bigger ones are trimmed. Defaults to 60000, under the 64 KB `sendBeacon` limit. Capped at 65536, the collector's default limit. */\n maxPayloadBytes?: number | undefined;\n /** Most area/route pairs per batch. Defaults to 200, capped at 1000 (the collector's limit). */\n maxAreas?: number | undefined;\n /** Slowest renders kept per area per batch. Defaults to 5, capped at 50 (the collector's limit). */\n worstCases?: number | undefined;\n /** Receive measurements and batches, e.g. `createOtelExporter`. */\n exporters?: Exporter[] | undefined;\n /** Logs each batch to the console and reports internal errors as warnings. Defaults to true when there's no `endpoint`. */\n debug?: boolean | undefined;\n}\n\nexport interface RenderPulse {\n /** False when this session was left out by `sampleRate`; nothing is measured or sent. */\n readonly sampled: boolean;\n /** The current measurement mode. In `\"auto\"`, this changes to `\"profiling\"` once the profiling build is detected. */\n readonly mode: Mode;\n /** Builds a batch from everything measured since the last one and sends it. Returns it, or `null` when there was nothing to send. */\n flush: () => Payload | null;\n /** Stops observing and sending, and detaches `<RenderMonitor>`s, which keep rendering their children as usual. */\n destroy: () => void;\n}\n\nconst INERT: RenderPulse = { sampled: false, mode: \"lightweight\", flush: () => null, destroy: () => {} };\n\nlet active: { destroy: () => void } | null = null;\n\n/**\n * Starts render-pulse. Call it once, before your app renders. Calling it\n * again replaces the previous setup. On the server it does nothing.\n */\nexport function initRenderPulse(options: RenderPulseOptions = {}): RenderPulse {\n if (typeof window === \"undefined\") return INERT;\n return guard(() => start(options), INERT);\n}\n\nfunction start(options: RenderPulseOptions): RenderPulse {\n active?.destroy();\n\n const {\n endpoint,\n sampleRate = 1,\n mode: modeOption = \"auto\",\n slowRenderMs = 16,\n longTaskMs = 50,\n flushIntervalMs = 180_000,\n debug = !endpoint,\n } = options;\n // Clamped to what the collector accepts, so a generous setting can't get every batch rejected.\n const maxPayloadBytes = clamp(options.maxPayloadBytes ?? 60_000, 1_000, 65_536);\n const maxAreas = clamp(options.maxAreas ?? 200, 1, 1000);\n const worstCases = clamp(options.worstCases ?? 5, 0, 50);\n const appVersion = options.appVersion?.slice(0, 100);\n\n setDebug(debug);\n const sampled = shouldSample(sampleRate);\n const now = () => performance.now();\n const sessionStart = now();\n const startedAt = Date.now();\n const sessionId = createSessionId();\n let seq = 0;\n\n const detector = createModeDetector(modeOption);\n const readRoute = createRouteReader(options.getRoute ?? defaultGetRoute);\n const route = () => guard(readRoute, \"/\").slice(0, 500);\n const areaId = (id: string) => (id ? id.slice(0, 200) : \"(unnamed)\");\n const exporters = [...(options.exporters ?? []), ...(debug ? [createConsoleExporter()] : [])];\n const aggregator = createAggregator({ slowRenderMs, maxAreas, worstCases, sessionStart });\n const windows = createRenderWindows();\n const transport = endpoint ? createTransport({ endpoint, maxAttempts: 3, maxQueued: 5 }) : null;\n\n function record(event: RenderEvent): void {\n aggregator.addRender(event);\n windows.add(event.area, event.startTime, event.endTime, event.duration);\n for (const exporter of exporters) guard(() => exporter.onRender?.(event), undefined);\n }\n\n function recordLongTask(event: LongTaskEvent): void {\n aggregator.addLongTask(event);\n for (const exporter of exporters) guard(() => exporter.onLongTask?.(event), undefined);\n }\n\n const runtime: PulseRuntime = {\n sampled,\n now,\n measuresWithMarks: () => sampled && detector.measuresWithMarks(),\n recordMarks(area, phase, startTime, endTime) {\n if (!sampled) return;\n guard(() => {\n const duration = endTime - startTime;\n // Marks measurements are lightweight-mode data even in a profiling session (e.g. from useRenderMonitor).\n record({ area: areaId(area), route: route(), phase, duration, startTime, endTime, mode: \"lightweight\" });\n }, undefined);\n },\n recordProfiler(area, phase: RenderPhase, actualDuration, startTime, commitTime) {\n if (!sampled) return false;\n return guard(() => {\n detector.profilerFired();\n if (detector.current() !== \"profiling\") return false;\n record({\n area: areaId(area),\n route: route(),\n phase,\n duration: actualDuration,\n startTime,\n endTime: commitTime,\n mode: \"profiling\",\n });\n return true;\n }, false);\n },\n };\n\n function flush(unloading: boolean): Payload | null {\n if (!sampled || aggregator.isEmpty()) return null;\n\n return guard(() => {\n const batch = aggregator.drain();\n const payload: Payload = {\n v: 1,\n session: {\n id: sessionId,\n seq: ++seq,\n mode: detector.current(),\n route: route(),\n appVersion: appVersion ?? null,\n startedAt,\n sentAt: Date.now(),\n },\n device: getDeviceContext(),\n summary: batch.summary,\n areas: batch.areas,\n longTasks: batch.longTasks,\n longFrames: batch.longFrames,\n dropped: { areas: batch.droppedAreas },\n };\n\n for (const exporter of exporters) guard(() => exporter.onFlush?.(payload), undefined);\n\n if (transport) {\n const body = serializePayload(payload, maxPayloadBytes);\n if (body) transport.send(body, { unloading });\n }\n\n return payload;\n }, null);\n }\n\n const cleanups: (() => void)[] = [];\n\n if (sampled) {\n cleanups.push(\n observeLongTasks(longTaskMs, (task) =>\n guard(() => {\n const area = windows.findArea(task.startTime, task.startTime + task.duration);\n recordLongTask({ ...task, area, route: route() });\n }, undefined),\n ),\n );\n\n // `pagehide` covers browsers (older Safari) that skip `visibilitychange` on unload.\n const onHidden = () => {\n if (document.visibilityState === \"hidden\") flush(true);\n };\n const onPageHide = () => flush(true);\n document.addEventListener(\"visibilitychange\", onHidden);\n window.addEventListener(\"pagehide\", onPageHide);\n cleanups.push(() => {\n document.removeEventListener(\"visibilitychange\", onHidden);\n window.removeEventListener(\"pagehide\", onPageHide);\n });\n\n if (flushIntervalMs > 0) {\n const timer = setInterval(() => flush(false), flushIntervalMs);\n cleanups.push(() => clearInterval(timer));\n }\n }\n\n setRuntime(runtime);\n\n const instance = {\n destroy() {\n for (const cleanup of cleanups.splice(0)) guard(cleanup, undefined);\n if (getRuntime() === runtime) setRuntime(null);\n if (active === instance) active = null;\n },\n };\n active = instance;\n\n return {\n sampled,\n get mode() {\n return detector.current();\n },\n flush: () => flush(false),\n destroy: instance.destroy,\n };\n}\n\nfunction clamp(value: number, min: number, max: number): number {\n return Number.isFinite(value) ? Math.min(max, Math.max(min, Math.floor(value))) : min;\n}\n","\"use client\";\n\nimport { Profiler, useCallback, useRef, type ProfilerOnRenderCallback, type ReactNode } from \"react\";\nimport { guard } from \"../runtime/guard.js\";\nimport { getRuntime } from \"../runtime/runtime.js\";\nimport { useIsomorphicLayoutEffect } from \"../runtime/useIsomorphicLayoutEffect.js\";\n\nexport interface RenderMonitorProps {\n /** Names this area in reports, e.g. `\"orders-table\"`. Areas with the same id are reported together. */\n id: string;\n children?: ReactNode;\n}\n\ninterface MonitorState {\n id: string;\n mounted: boolean;\n start: number;\n end: number;\n /** The `start` of the last recorded measurement, so StrictMode's repeated effects don't record it twice. */\n recordedStart: number;\n /** The latest marks measurement, waiting to see whether a `<Profiler>` callback for the same commit supersedes it. */\n pending: PendingMeasurement | null;\n}\n\ninterface PendingMeasurement {\n start: number;\n end: number;\n phase: \"mount\" | \"update\";\n superseded: boolean;\n}\n\n/**\n * Measures the renders of its children and reports them under `id`.\n *\n * The tree it renders is the same in every mode and whether or not the\n * session is sampled (a `<Profiler>` around two empty marker components), so\n * switching modes or calling `initRenderPulse` late never remounts children.\n * - Profiling mode: React's `<Profiler>` reports each commit's actual render time.\n * - Lightweight mode: the time between the start and end markers rendering,\n * which brackets the children's render. Updates that start below this area\n * (a child's own state change) don't re-render the markers, so they aren't\n * seen; profiling mode catches those.\n */\nexport function RenderMonitor({ id, children }: RenderMonitorProps): ReactNode {\n const stateRef = useRef<MonitorState | null>(null);\n if (stateRef.current === null) {\n stateRef.current = { id, mounted: false, start: 0, end: 0, recordedStart: -1, pending: null };\n }\n const state = stateRef.current;\n state.id = id;\n\n const onRender = useCallback<ProfilerOnRenderCallback>(\n (_id, phase, actualDuration, _baseDuration, startTime, commitTime) => {\n // When the Profiler's measurement of this commit is used, a marks measurement of it is a duplicate.\n if (getRuntime()?.recordProfiler(state.id, phase, actualDuration, startTime, commitTime) && state.pending) {\n state.pending.superseded = true;\n }\n },\n [state],\n );\n\n return (\n <Profiler id={id} onRender={onRender}>\n <StartMarker state={state} />\n {children}\n <EndMarker state={state} />\n </Profiler>\n );\n}\n\nfunction StartMarker({ state }: { state: MonitorState }): null {\n const runtime = getRuntime();\n if (runtime?.measuresWithMarks()) state.start = runtime.now();\n return null;\n}\n\nfunction EndMarker({ state }: { state: MonitorState }): null {\n const runtime = getRuntime();\n if (runtime?.measuresWithMarks()) state.end = runtime.now();\n\n // Layout effects only run for renders that commit, so abandoned concurrent renders aren't recorded.\n useIsomorphicLayoutEffect(() => {\n guard(() => {\n const current = getRuntime();\n if (!current?.measuresWithMarks() || state.start === state.recordedStart || state.end < state.start) return;\n\n state.recordedStart = state.start;\n const measurement: PendingMeasurement = {\n start: state.start,\n end: state.end,\n phase: state.mounted ? \"update\" : \"mount\",\n superseded: false,\n };\n state.pending = measurement;\n state.mounted = true;\n\n // The Profiler's callback for this commit (if the profiling build is in\n // use) runs later in the same commit, so wait a microtask before\n // deciding this measurement is the only one. Each commit gets its own\n // object, so several commits in one task are all kept.\n queueMicrotask(() => {\n if (state.pending === measurement) state.pending = null;\n if (!measurement.superseded) {\n getRuntime()?.recordMarks(state.id, measurement.phase, measurement.start, measurement.end);\n }\n });\n }, undefined);\n });\n\n return null;\n}\n","import { useEffect, useLayoutEffect } from \"react\";\n\n// useLayoutEffect warns during SSR on React 18; measurements only happen in the browser.\nexport const useIsomorphicLayoutEffect = typeof window === \"undefined\" ? useEffect : useLayoutEffect;\n","\"use client\";\n\nimport { useRef } from \"react\";\nimport { guard } from \"../runtime/guard.js\";\nimport { getRuntime } from \"../runtime/runtime.js\";\nimport { useIsomorphicLayoutEffect } from \"../runtime/useIsomorphicLayoutEffect.js\";\n\n/**\n * Tracks the renders of the component that calls it, reported under `id`.\n *\n * Render counts are exact. The duration runs from the hook's call to the\n * commit, so it also includes anything React renders after this component\n * in the same update: an upper bound. Wrap the component in `<RenderMonitor>`\n * when you need its own render time.\n *\n * Don't use it in a component that renders before the rest of the page, such\n * as a header or layout: on the first render its duration covers the whole page.\n */\nexport function useRenderMonitor(id: string): void {\n const state = useRef({ start: 0, recordedStart: -1, mounted: false }).current;\n const runtime = getRuntime();\n if (runtime?.sampled) state.start = runtime.now();\n\n useIsomorphicLayoutEffect(() => {\n guard(() => {\n const current = getRuntime();\n // `recordedStart` stops StrictMode's repeated effects from recording one render twice.\n if (!current?.sampled || state.start === state.recordedStart) return;\n\n state.recordedStart = state.start;\n current.recordMarks(id, state.mounted ? \"update\" : \"mount\", state.start, current.now());\n state.mounted = true;\n }, undefined);\n });\n}\n"],"mappings":"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","names":["sum","start","window","debug","useRef","useRef"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-render-pulse",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "Real-user render performance monitoring for React, at the component level.",
5
5
  "keywords": [
6
6
  "react",