@react-perfscope/core 0.7.0 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -139,23 +139,25 @@ function isSelfRequest(url) {
139
139
  // src/sourcemap.ts
140
140
  var CHROME_FRAME = /^\s*at\s+(?:(.+?)\s+\()?(.+?):(\d+):(\d+)\)?$/;
141
141
  var FIREFOX_FRAME = /^(.*?)@(.+?):(\d+):(\d+)$/;
142
+ function lookupFrame(tracer, frame) {
143
+ const pos = (0, import_trace_mapping.originalPositionFor)(tracer, { line: frame.line, column: frame.col - 1 });
144
+ if (pos.source == null || pos.line == null || pos.column == null) {
145
+ return frame;
146
+ }
147
+ const resolved = {
148
+ file: pos.source,
149
+ line: pos.line,
150
+ col: pos.column + 1
151
+ };
152
+ if (pos.name) resolved.fnName = pos.name;
153
+ else if (frame.fnName) resolved.fnName = frame.fnName;
154
+ return resolved;
155
+ }
142
156
  async function resolveFrame(frame, fetchMap) {
143
157
  try {
144
158
  const map = await fetchMap(frame.file);
145
159
  if (!map) return frame;
146
- const tracer = new import_trace_mapping.TraceMap(map);
147
- const pos = (0, import_trace_mapping.originalPositionFor)(tracer, { line: frame.line, column: frame.col });
148
- if (pos.source == null || pos.line == null || pos.column == null) {
149
- return frame;
150
- }
151
- const resolved = {
152
- file: pos.source,
153
- line: pos.line,
154
- col: pos.column
155
- };
156
- if (pos.name) resolved.fnName = pos.name;
157
- else if (frame.fnName) resolved.fnName = frame.fnName;
158
- return resolved;
160
+ return lookupFrame(new import_trace_mapping.TraceMap(map), frame);
159
161
  } catch (err) {
160
162
  console.warn("[react-perfscope] resolveFrame failed:", err);
161
163
  return frame;
@@ -178,7 +180,7 @@ function attachLazyStack(target, raw, skipTopFrames = 0) {
178
180
  function createSourceMapResolver(opts = {}) {
179
181
  const f = opts.fetch ?? (typeof fetch !== "undefined" ? fetch.bind(globalThis) : null);
180
182
  const cache = /* @__PURE__ */ new Map();
181
- function fetchMapFor(sourceUrl) {
183
+ function fetchTracerFor(sourceUrl) {
182
184
  if (!f) return Promise.resolve(null);
183
185
  const existing = cache.get(sourceUrl);
184
186
  if (existing) return existing;
@@ -197,13 +199,13 @@ function createSourceMapResolver(opts = {}) {
197
199
  const header = ref.slice(0, commaIdx);
198
200
  const payload = ref.slice(commaIdx + 1);
199
201
  const decoded = header.includes("base64") ? typeof atob === "function" ? atob(payload) : globalThis.Buffer.from(payload, "base64").toString("utf8") : decodeURIComponent(payload);
200
- return JSON.parse(decoded);
202
+ return new import_trace_mapping.TraceMap(JSON.parse(decoded));
201
203
  }
202
204
  const mapUrl = new URL(ref, sourceUrl).href;
203
205
  markSelfRequest(mapUrl);
204
206
  const mapRes = await f(mapUrl);
205
207
  if (!mapRes || !mapRes.ok) return null;
206
- return await mapRes.json();
208
+ return new import_trace_mapping.TraceMap(await mapRes.json());
207
209
  } catch {
208
210
  return null;
209
211
  }
@@ -214,7 +216,9 @@ function createSourceMapResolver(opts = {}) {
214
216
  return {
215
217
  async resolve(frame) {
216
218
  try {
217
- return await resolveFrame(frame, fetchMapFor);
219
+ const tracer = await fetchTracerFor(frame.file);
220
+ if (!tracer) return frame;
221
+ return lookupFrame(tracer, frame);
218
222
  } catch {
219
223
  return frame;
220
224
  }
@@ -771,37 +775,40 @@ function createNetworkCollector() {
771
775
 
772
776
  // src/collectors/web-vitals.ts
773
777
  var import_web_vitals = require("web-vitals");
778
+ var subscribed = false;
779
+ var sinks = /* @__PURE__ */ new Set();
780
+ function ensureSubscribed() {
781
+ if (subscribed) return true;
782
+ try {
783
+ const fan = (name) => (metric) => {
784
+ for (const sink of sinks) sink(name, metric.value);
785
+ };
786
+ (0, import_web_vitals.onLCP)(fan("LCP"));
787
+ (0, import_web_vitals.onINP)(fan("INP"));
788
+ (0, import_web_vitals.onCLS)(fan("CLS"));
789
+ (0, import_web_vitals.onFCP)(fan("FCP"));
790
+ (0, import_web_vitals.onTTFB)(fan("TTFB"));
791
+ subscribed = true;
792
+ } catch (err) {
793
+ console.warn("[react-perfscope] web-vitals collector failed to subscribe:", err);
794
+ }
795
+ return subscribed;
796
+ }
774
797
  function createWebVitalsCollector() {
775
- let active = false;
776
- let subscribed = false;
777
798
  let emit = () => {
778
799
  };
779
- function makeHandler(name) {
780
- return (metric) => {
781
- if (!active) return;
782
- emit({ kind: "web-vital", name, value: metric.value });
783
- };
784
- }
800
+ const sink = (name, value) => {
801
+ emit({ kind: "web-vital", name, value });
802
+ };
785
803
  return {
786
804
  kind: "web-vital",
787
805
  activate(emitFn) {
806
+ if (!ensureSubscribed()) return;
788
807
  emit = emitFn;
789
- active = true;
790
- if (subscribed) return;
791
- try {
792
- (0, import_web_vitals.onLCP)(makeHandler("LCP"));
793
- (0, import_web_vitals.onINP)(makeHandler("INP"));
794
- (0, import_web_vitals.onCLS)(makeHandler("CLS"));
795
- (0, import_web_vitals.onFCP)(makeHandler("FCP"));
796
- (0, import_web_vitals.onTTFB)(makeHandler("TTFB"));
797
- subscribed = true;
798
- } catch (err) {
799
- console.warn("[react-perfscope] web-vitals collector failed to subscribe:", err);
800
- active = false;
801
- }
808
+ sinks.add(sink);
802
809
  },
803
810
  deactivate() {
804
- active = false;
811
+ sinks.delete(sink);
805
812
  }
806
813
  };
807
814
  }
@@ -894,6 +901,7 @@ function createHeapCollector() {
894
901
 
895
902
  // src/collectors/interaction.ts
896
903
  var DURATION_THRESHOLD = 40;
904
+ var MAX_ENTRIES = 5e3;
897
905
  function selectorFor(target) {
898
906
  const el = target;
899
907
  if (!el || typeof el.tagName !== "string") return void 0;
@@ -922,7 +930,10 @@ function createInteractionCollector() {
922
930
  try {
923
931
  observer = new PerformanceObserver((list) => {
924
932
  if (!active) return;
925
- for (const e of list.getEntries()) entries.push(e);
933
+ for (const e of list.getEntries()) {
934
+ if (entries.length >= MAX_ENTRIES) break;
935
+ entries.push(e);
936
+ }
926
937
  });
927
938
  observer.observe({ type: "event", buffered: false, durationThreshold: DURATION_THRESHOLD });
928
939
  try {
@@ -946,8 +957,10 @@ function createInteractionCollector() {
946
957
  }
947
958
  },
948
959
  finalize(result) {
960
+ const buffered = entries;
961
+ entries = [];
949
962
  const byId = /* @__PURE__ */ new Map();
950
- for (const e of entries) {
963
+ for (const e of buffered) {
951
964
  const id = e.interactionId;
952
965
  if (!id) continue;
953
966
  const group = byId.get(id);
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/recorder.ts","../src/sourcemap.ts","../src/self-requests.ts","../src/capabilities.ts","../src/leak-trend.ts","../src/correlate.ts","../src/collectors/long-tasks.ts","../src/collectors/forced-reflow.ts","../src/collectors/layout-shift.ts","../src/collectors/network.ts","../src/collectors/web-vitals.ts","../src/collectors/heap.ts","../src/collectors/interaction.ts","../src/collectors/frames.ts","../src/collectors/self-profiling.ts"],"sourcesContent":["// Types\nexport * from './types'\n\n// Recorder\nexport { createRecorder, BUFFER_CAP } from './recorder'\n\n// Sourcemap utilities\nexport { parseStack, resolveFrame, attachLazyStack, createSourceMapResolver } from './sourcemap'\nexport type { FetchMap, SourceMapResolver, CreateSourceMapResolverOptions } from './sourcemap'\n\n// Self-request registry (excludes the tool's own traffic from network signals)\nexport { markSelfRequest, isSelfRequest } from './self-requests'\n\n// Browser capability detection (which signal kinds this browser can measure)\nexport { detectCapabilities, unsupportedKinds } from './capabilities'\nexport type { Capabilities } from './capabilities'\n\n// Component leak-trend analysis (rising retained-after-unmount instances)\nexport { analyzeLeakTrend } from './leak-trend'\nexport type { LeakSample } from './leak-trend'\n\n// Cross-signal correlation (groups signals into interaction/long-task episodes)\nexport { correlate } from './correlate'\nexport type { Episode, EpisodeMember, AnchorSignal, LinkConfidence, InpPhase, CommitCause } from './correlate'\n\n// Collectors\nexport { createLongTasksCollector } from './collectors/long-tasks'\nexport { createForcedReflowCollector } from './collectors/forced-reflow'\nexport { createLayoutShiftCollector } from './collectors/layout-shift'\nexport { createNetworkCollector } from './collectors/network'\nexport { createWebVitalsCollector } from './collectors/web-vitals'\nexport { createHeapCollector, analyzeHeapTrend } from './collectors/heap'\nexport type { HeapCollector } from './collectors/heap'\nexport { createInteractionCollector } from './collectors/interaction'\nexport type { InteractionCollector } from './collectors/interaction'\nexport { createFrameCollector, analyzeFrames } from './collectors/frames'\nexport type { FrameCollector } from './collectors/frames'\nexport {\n createSelfProfilingCollector,\n attributeWindow,\n attributeLongTaskSignals,\n isUserResource,\n} from './collectors/self-profiling'\nexport type {\n ProfilerTrace,\n ProfilerFrame,\n ProfilerStack,\n ProfilerSample,\n} from './collectors/self-profiling'\n","import type { Collector, Recorder, RecordingResult, Signal } from './types'\n\n/** Hard cap on retained signals; the oldest are dropped past this. Exported so\n * downstream tests can assert the buffer never grows beyond it. */\nexport const BUFFER_CAP = 10_000\n\nexport interface InternalRecorder extends Recorder {\n __push: (signal: Signal) => void\n}\n\nexport function createRecorder(): Recorder {\n let recording = false\n let startedAt = 0\n let buffer: Signal[] = []\n const subscribers = new Set<(s: Signal) => void>()\n const collectors: Collector[] = []\n\n function notify(signal: Signal) {\n for (const cb of subscribers) {\n try {\n cb(signal)\n } catch (err) {\n console.warn('[react-perfscope] subscriber threw:', err)\n }\n }\n }\n\n function push(signal: Signal) {\n if (!recording) return\n buffer.push(signal)\n if (buffer.length > BUFFER_CAP) {\n buffer.splice(0, buffer.length - BUFFER_CAP)\n }\n notify(signal)\n }\n\n const recorder: InternalRecorder = {\n start() {\n if (recording) return\n recording = true\n startedAt = performance.now()\n buffer = []\n for (const c of collectors) {\n try {\n c.activate(push)\n } catch (err) {\n console.warn(`[react-perfscope] collector ${c.kind} failed to activate:`, err)\n }\n }\n },\n stop(): RecordingResult {\n if (!recording) {\n return { signals: [], startedAt: 0, duration: 0 }\n }\n for (const c of collectors) {\n try {\n c.deactivate()\n } catch (err) {\n console.warn(`[react-perfscope] collector ${c.kind} failed to deactivate:`, err)\n }\n }\n const duration = performance.now() - startedAt\n const result: RecordingResult = {\n signals: buffer.slice(),\n startedAt,\n duration,\n }\n recording = false\n buffer = []\n return result\n },\n isRecording() {\n return recording\n },\n onSignal(cb) {\n subscribers.add(cb)\n return () => subscribers.delete(cb)\n },\n use(collector) {\n collectors.push(collector)\n },\n __push: push,\n }\n return recorder\n}\n","import { TraceMap, originalPositionFor, type SourceMapInput } from '@jridgewell/trace-mapping'\nimport type { StackFrame } from './types'\nimport { markSelfRequest } from './self-requests'\n\nconst CHROME_FRAME = /^\\s*at\\s+(?:(.+?)\\s+\\()?(.+?):(\\d+):(\\d+)\\)?$/\nconst FIREFOX_FRAME = /^(.*?)@(.+?):(\\d+):(\\d+)$/\n\n/** A parsed source map (the JSON object), as returned by a FetchMap. */\nexport type RawSourceMap = SourceMapInput\n\nexport type FetchMap = (file: string) => Promise<RawSourceMap | null>\n\nexport async function resolveFrame(\n frame: StackFrame,\n fetchMap: FetchMap\n): Promise<StackFrame> {\n try {\n const map = await fetchMap(frame.file)\n if (!map) return frame\n // trace-mapping is pure JS (no wasm), so this works in the browser where\n // Mozilla's source-map SourceMapConsumer needs an explicitly-initialized\n // mappings.wasm. Columns are 0-based here, matching the captured frames.\n const tracer = new TraceMap(map)\n const pos = originalPositionFor(tracer, { line: frame.line, column: frame.col })\n if (pos.source == null || pos.line == null || pos.column == null) {\n return frame\n }\n const resolved: StackFrame = {\n file: pos.source,\n line: pos.line,\n col: pos.column,\n }\n if (pos.name) resolved.fnName = pos.name\n else if (frame.fnName) resolved.fnName = frame.fnName\n return resolved\n } catch (err) {\n console.warn('[react-perfscope] resolveFrame failed:', err)\n return frame\n }\n}\n\n/**\n * Attach a lazy `stack` getter to `target` that parses `raw` on first access\n * and memoizes the result. Use this from collectors to defer parseStack cost\n * until a consumer actually reads `signal.stack`.\n *\n * `skipTopFrames` drops the leading N parsed frames — useful for collectors\n * that wrap a patched function (the wrapper itself shows up as the topmost\n * frame, but it's noise from the user's perspective).\n */\nexport function attachLazyStack(\n target: object,\n raw: string | undefined,\n skipTopFrames = 0\n): void {\n let cached: StackFrame[] | null = null\n Object.defineProperty(target, 'stack', {\n enumerable: true,\n configurable: true,\n get() {\n if (cached === null) {\n const all = parseStack(raw)\n cached = skipTopFrames > 0 ? all.slice(skipTopFrames) : all\n }\n return cached\n },\n })\n}\n\nexport interface SourceMapResolver {\n /** Resolve a parsed StackFrame to its original source position. Falls back to the input frame on any failure. */\n resolve(frame: StackFrame): Promise<StackFrame>\n}\n\nexport interface CreateSourceMapResolverOptions {\n /** Override the global fetch. Useful for tests and non-browser environments. */\n fetch?: typeof globalThis.fetch\n}\n\n/**\n * Create a SourceMap resolver that fetches `.map` files from the live URL\n * referenced in each source file's `//# sourceMappingURL=` directive.\n * Caches the parsed source map per source URL so repeated resolves against\n * the same file are O(1) after the first.\n *\n * Returns the input frame on any failure (network error, missing map, etc.).\n */\nexport function createSourceMapResolver(opts: CreateSourceMapResolverOptions = {}): SourceMapResolver {\n const f = opts.fetch ?? (typeof fetch !== 'undefined' ? fetch.bind(globalThis) : null)\n const cache = new Map<string, Promise<RawSourceMap | null>>()\n\n function fetchMapFor(sourceUrl: string): Promise<RawSourceMap | null> {\n if (!f) return Promise.resolve(null)\n const existing = cache.get(sourceUrl)\n if (existing) return existing\n const promise = (async () => {\n try {\n markSelfRequest(sourceUrl)\n const res = await f(sourceUrl)\n if (!res || !res.ok) return null\n const text = await res.text()\n const m = text.match(/\\/\\/[#@]\\s*sourceMappingURL=(.+?)\\s*$/m)\n if (!m) return null\n const ref = m[1]!.trim()\n if (ref.startsWith('data:')) {\n const commaIdx = ref.indexOf(',')\n if (commaIdx === -1) return null\n const header = ref.slice(0, commaIdx)\n const payload = ref.slice(commaIdx + 1)\n const decoded = header.includes('base64')\n ? typeof atob === 'function'\n ? atob(payload)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n : (globalThis as any).Buffer.from(payload, 'base64').toString('utf8')\n : decodeURIComponent(payload)\n return JSON.parse(decoded) as RawSourceMap\n }\n const mapUrl = new URL(ref, sourceUrl).href\n markSelfRequest(mapUrl)\n const mapRes = await f(mapUrl)\n if (!mapRes || !mapRes.ok) return null\n return (await mapRes.json()) as RawSourceMap\n } catch {\n return null\n }\n })()\n cache.set(sourceUrl, promise)\n return promise\n }\n\n return {\n async resolve(frame) {\n try {\n return await resolveFrame(frame, fetchMapFor)\n } catch {\n return frame\n }\n },\n }\n}\n\nexport function parseStack(raw: string | undefined): StackFrame[] {\n if (!raw) return []\n const frames: StackFrame[] = []\n for (const line of raw.split('\\n')) {\n const chromeMatch = line.match(CHROME_FRAME)\n if (chromeMatch) {\n const [, fnName, file, lineStr, colStr] = chromeMatch\n const frame: StackFrame = {\n file: file ?? '',\n line: Number(lineStr),\n col: Number(colStr),\n }\n if (fnName) frame.fnName = fnName\n frames.push(frame)\n continue\n }\n const firefoxMatch = line.match(FIREFOX_FRAME)\n if (firefoxMatch) {\n const [, fnName, file, lineStr, colStr] = firefoxMatch\n const frame: StackFrame = {\n file: file ?? '',\n line: Number(lineStr),\n col: Number(colStr),\n }\n if (fnName) frame.fnName = fnName\n frames.push(frame)\n }\n }\n return frames\n}\n","// Registry of URLs that react-perfscope itself fetched (source files and their\n// source maps, when resolving stack frames). The network collector consults\n// this so the tool's own traffic never shows up as one of the app's network\n// signals — measuring shouldn't report the measurer.\n\nconst selfRequests = new Set<string>()\n\n/** Record that react-perfscope is about to fetch `url`, so the network\n * collector can exclude its resource-timing entry. */\nexport function markSelfRequest(url: string): void {\n selfRequests.add(url)\n}\n\n/** True when `url` was fetched by react-perfscope itself. */\nexport function isSelfRequest(url: string): boolean {\n return selfRequests.has(url)\n}\n","import type { SignalKind } from './types'\n\nexport type Capabilities = Record<SignalKind, boolean>\n\nfunction supportedEntryTypes(): readonly string[] | undefined {\n const PO = (globalThis as { PerformanceObserver?: { supportedEntryTypes?: readonly string[] } })\n .PerformanceObserver\n return PO?.supportedEntryTypes\n}\n\n/** True unless the browser exposes `supportedEntryTypes` AND it includes none of\n * the needed entry types. An unknown environment (older browsers / test envs\n * that don't expose the list) is treated as supported, so we never falsely\n * report a feature missing — the collector's own try/catch is the backstop. */\nfunction observerSupported(needed: readonly string[]): boolean {\n const types = supportedEntryTypes()\n if (!Array.isArray(types)) return true\n return needed.some((t) => types.includes(t))\n}\n\n/** Which signal kinds the current browser can actually measure. The render and\n * forced-reflow collectors are pure JS (React fibers / DOM-API instrumentation)\n * so they work everywhere; the rest depend on PerformanceObserver entry types\n * that Firefox and Safari do not implement (long tasks, layout shift, INP). */\nexport function detectCapabilities(): Capabilities {\n return {\n 'forced-reflow': true,\n render: true,\n 'web-vital': true,\n 'layout-shift': observerSupported(['layout-shift']),\n 'long-task': observerSupported(['long-animation-frame', 'longtask']),\n interaction: observerSupported(['event']),\n network: observerSupported(['resource']),\n }\n}\n\n/** Signal kinds the current browser cannot measure — for telling the user a\n * tab is empty because of the platform, not because nothing happened. */\nexport function unsupportedKinds(): SignalKind[] {\n const caps = detectCapabilities()\n return (Object.keys(caps) as SignalKind[]).filter((k) => !caps[k])\n}\n","/** One reading of how many unmounted instances of a component are still\n * retained (alive, not yet garbage-collected) at a point in time. */\nexport type LeakSample = { at: number; retained: number }\n\n/** Minimum samples before a trend can be estimated. */\nconst MIN_SAMPLES = 4\n/** Segments to split the series into when estimating the retained floor. */\nconst FLOOR_SEGMENTS = 8\n/** Require the retained floor to climb by at least this many instances across\n * the window before flagging — a transient one or two awaiting GC is not a\n * leak. */\nconst MIN_NET_GROWTH = 3\n\nfunction slope(points: { x: number; y: number }[]): number {\n const n = points.length\n if (n < 2) return 0\n let sx = 0\n let sy = 0\n let sxy = 0\n let sxx = 0\n for (const { x, y } of points) {\n sx += x\n sy += y\n sxy += x * y\n sxx += x * x\n }\n const denom = n * sxx - sx * sx\n if (denom === 0) return 0\n return (n * sxy - sx * sy) / denom\n}\n\n/**\n * Decide whether a component's retained-instance series indicates a leak.\n *\n * Mirrors {@link analyzeHeapTrend}: GC makes the raw retained count a sawtooth\n * (instances pile up, then a sweep collects a batch), so the reliable signal is\n * the *floor* — the post-GC troughs. We segment the series, take each segment's\n * minimum, and regress those minima against time.\n *\n * A rising slope alone is not enough: a one-time step (a screen mounts N\n * long-lived instances once, then plateaus) regresses positive but is not a\n * leak. So we additionally require the recent half of the floor to still be\n * rising, and gate on a minimum net growth in instances. This is what makes the\n * detector robust to React StrictMode's intentional mount→unmount→remount\n * churn, whose discarded fibers get collected and keep the floor flat.\n *\n * Returns null when there are too few samples to say anything.\n */\nexport function analyzeLeakTrend(\n samples: LeakSample[]\n): { leaking: boolean; slopePerMin: number } | null {\n if (samples.length < MIN_SAMPLES) return null\n const t0 = samples[0]!.at\n const segSize = Math.max(1, Math.ceil(samples.length / FLOOR_SEGMENTS))\n const floorPoints: { x: number; y: number }[] = []\n for (let i = 0; i < samples.length; i += segSize) {\n const seg = samples.slice(i, i + segSize)\n let min = Infinity\n for (const s of seg) min = Math.min(min, s.retained)\n const mid = seg[Math.floor(seg.length / 2)]!\n floorPoints.push({ x: (mid.at - t0) / 60000, y: min })\n }\n const slopePerMin = slope(floorPoints)\n const spanMin = (samples[samples.length - 1]!.at - t0) / 60000\n const projectedGrowth = slopePerMin * spanMin\n const recent = floorPoints.slice(Math.floor(floorPoints.length / 2))\n const recentSlope = recent.length >= 2 ? slope(recent) : slopePerMin\n const leaking = projectedGrowth >= MIN_NET_GROWTH && recentSlope > 0\n return { leaking, slopePerMin }\n}\n","import type {\n ForcedReflowSignal,\n InteractionSignal,\n LongTaskSignal,\n RenderSignal,\n Signal,\n StackFrame,\n} from './types'\n\n/** One frame at 60fps. A commit's `at` is sampled when it completes (after its\n * layout effects), so a reflow forced during that commit finishes up to ~a\n * frame before the commit is timestamped. */\nconst FRAME_MS = 16\n\nexport type AnchorSignal = InteractionSignal | LongTaskSignal\n\n/** How strongly a member is linked to its episode anchor. `caused` means a\n * member's source location matches one of the anchor's hot frames — a real\n * causal claim. `co-occurred` means it only overlapped in time; the link is\n * temporal, not proven. The distinction keeps the tool from overclaiming. */\nexport type LinkConfidence = 'caused' | 'co-occurred'\n\n/** Which slice of an interaction's INP latency a member fell into. Only set\n * for interaction-anchored episodes; long tasks have no phase breakdown. */\nexport type InpPhase = 'input-delay' | 'processing' | 'presentation'\n\n/** Signals that carry an `at` timestamp and can be nested inside an episode.\n * Excludes the anchors themselves and signals with no point in time\n * (web-vital has no `at`; network uses `startedAt`). */\ntype MemberSignal = Exclude<Extract<Signal, { at: number }>, AnchorSignal>\n\n/** The render commit a forced reflow happened inside — the component whose\n * commit forced the synchronous layout. Set when the reflow's timestamp falls\n * within a render commit's window. */\nexport type CommitCause = {\n commitId: number\n component: string\n}\n\nexport type EpisodeMember = {\n signal: MemberSignal\n confidence: LinkConfidence\n phase?: InpPhase\n causedBy?: CommitCause\n}\n\nexport type Episode = {\n anchor: AnchorSignal\n members: EpisodeMember[]\n}\n\nfunction isAnchor(signal: Signal): signal is AnchorSignal {\n return signal.kind === 'interaction' || signal.kind === 'long-task'\n}\n\nfunction sourceKey(frame: StackFrame): string {\n return `${frame.file}:${frame.line}`\n}\n\nfunction anchorHotLocations(anchor: AnchorSignal): Set<string> {\n return new Set((anchor.attribution ?? []).map((a) => sourceKey(a.frame)))\n}\n\nfunction isMember(s: Signal, anchor: AnchorSignal): s is MemberSignal {\n return s !== anchor && s.kind !== 'interaction' && s.kind !== 'long-task' && 'at' in s\n}\n\nfunction linkConfidence(signal: MemberSignal, hotLocations: Set<string>): LinkConfidence {\n if (signal.kind === 'forced-reflow') {\n if (signal.stack.some((f) => hotLocations.has(sourceKey(f)))) return 'caused'\n }\n return 'co-occurred'\n}\n\n/** Finds the render commit that forced a reflow. A render signal's `at` is\n * sampled when the commit completes — *after* its layout effects, where forced\n * reflows happen — and its `duration` covers only the render phase, not the\n * layout work. So the triggering commit is the one that completes at or just\n * after the reflow (within a frame of the reflow finishing), not one whose\n * narrow render-phase window contains it. */\nfunction commitForReflow(reflow: ForcedReflowSignal, renders: RenderSignal[]): RenderSignal | undefined {\n const reflowEnd = reflow.at + reflow.duration\n return renders.find((r) => r.at >= reflow.at && r.at <= reflowEnd + FRAME_MS)\n}\n\nfunction inpPhaseAt(anchor: AnchorSignal, at: number): InpPhase | undefined {\n if (anchor.kind !== 'interaction') return undefined\n const processingStart = anchor.at + anchor.inputDelay\n const presentationStart = processingStart + anchor.processing\n if (at < processingStart) return 'input-delay'\n if (at < presentationStart) return 'processing'\n return 'presentation'\n}\n\nexport function correlate(signals: Signal[]): Episode[] {\n const anchors = signals.filter(isAnchor)\n\n return anchors.map((anchor) => {\n const start = anchor.at\n const end = anchor.at + anchor.duration\n const hotLocations = anchorHotLocations(anchor)\n const windowed = signals.filter(\n (s): s is MemberSignal => isMember(s, anchor) && s.at >= start && s.at <= end,\n )\n const renders = windowed.filter((s): s is RenderSignal => s.kind === 'render')\n\n const members = windowed.map((signal) => {\n const member: EpisodeMember = {\n signal,\n confidence: linkConfidence(signal, hotLocations),\n phase: inpPhaseAt(anchor, signal.at),\n }\n if (signal.kind === 'forced-reflow') {\n const commit = commitForReflow(signal, renders)\n if (commit) {\n member.confidence = 'caused'\n member.causedBy = { commitId: commit.commitId, component: commit.component }\n }\n }\n return member\n })\n\n return { anchor, members }\n })\n}\n","import type { Collector, LongTaskScript, Signal } from '../types'\n\nconst LOAF = 'long-animation-frame'\nconst LEGACY = 'longtask'\n\n/** A single script entry inside a Long Animation Frame. */\ninterface ScriptTiming {\n duration?: number\n invoker?: string\n invokerType?: string\n sourceURL?: string\n sourceFunctionName?: string\n sourceCharPosition?: number\n}\n\ninterface LoAFEntry extends PerformanceEntry {\n blockingDuration?: number\n scripts?: ScriptTiming[]\n}\n\nfunction supportsLoAF(): boolean {\n const PO = (globalThis as { PerformanceObserver?: { supportedEntryTypes?: readonly string[] } })\n .PerformanceObserver\n const types = PO?.supportedEntryTypes\n return Array.isArray(types) && types.includes(LOAF)\n}\n\nfunction mapScripts(scripts: ScriptTiming[]): LongTaskScript[] {\n return scripts.map((s) => ({\n invokerType: s.invokerType ?? 'unknown',\n invoker: s.invoker ?? '',\n sourceURL: s.sourceURL ?? '',\n sourceFunctionName: s.sourceFunctionName ?? '',\n charPosition: typeof s.sourceCharPosition === 'number' ? s.sourceCharPosition : -1,\n duration: typeof s.duration === 'number' ? s.duration : 0,\n }))\n}\n\nexport function createLongTasksCollector(): Collector {\n let observer: PerformanceObserver | null = null\n let active = false\n\n return {\n kind: 'long-task',\n activate(emit: (signal: Signal) => void) {\n if (typeof PerformanceObserver === 'undefined') {\n console.warn('[react-perfscope] PerformanceObserver not supported; long-tasks disabled')\n return\n }\n active = true\n const useLoAF = supportsLoAF()\n try {\n observer = new PerformanceObserver((list) => {\n if (!active) return\n for (const entry of list.getEntries()) {\n if (useLoAF) {\n const loaf = entry as LoAFEntry\n const scripts = Array.isArray(loaf.scripts) ? mapScripts(loaf.scripts) : []\n emit({\n kind: 'long-task',\n at: entry.startTime,\n duration: entry.duration,\n stack: [],\n scripts,\n ...(typeof loaf.blockingDuration === 'number'\n ? { blockingDuration: loaf.blockingDuration }\n : {}),\n })\n } else {\n emit({\n kind: 'long-task',\n at: entry.startTime,\n duration: entry.duration,\n stack: [],\n })\n }\n }\n })\n observer.observe({ type: useLoAF ? LOAF : LEGACY, buffered: false })\n } catch (err) {\n console.warn('[react-perfscope] long-tasks collector failed to start:', err)\n observer = null\n active = false\n }\n },\n deactivate() {\n active = false\n if (observer) {\n try {\n observer.disconnect()\n } catch {\n // ignore\n }\n observer = null\n }\n },\n }\n}\n","import type { Collector, Signal } from '../types'\nimport { attachLazyStack } from '../sourcemap'\n\nconst LAYOUT_GETTERS = [\n 'offsetWidth',\n 'offsetHeight',\n 'offsetLeft',\n 'offsetTop',\n 'clientWidth',\n 'clientHeight',\n 'scrollWidth',\n 'scrollHeight',\n] as const\n\nconst LAYOUT_METHODS = ['getBoundingClientRect', 'getClientRects'] as const\n\ntype SavedDescriptor = {\n proto: object\n key: string\n descriptor: PropertyDescriptor\n}\n\ntype OpenGroup = {\n at: number\n duration: number\n count: number\n rawStack: string | undefined\n}\n\n// Close the coalescing window at the end of the current synchronous turn.\n// queueMicrotask runs after the running task drains, so a layout-thrash loop\n// (read offsetWidth N times in one turn) collapses into a single group.\nconst scheduleFlush: (cb: () => void) => void =\n typeof queueMicrotask === 'function'\n ? queueMicrotask\n : typeof Promise !== 'undefined'\n ? (cb) => {\n Promise.resolve().then(cb)\n }\n : (cb) => cb()\n\nexport function createForcedReflowCollector(): Collector {\n let active = false\n let emit: (s: Signal) => void = () => {}\n const saved: SavedDescriptor[] = []\n let mutationObserver: MutationObserver | null = null\n let group: OpenGroup | null = null\n\n function consumePendingMutations(): boolean {\n if (!mutationObserver) {\n // Fallback when MutationObserver isn't available: always treat as dirty\n // (Phase 1 over-report behavior).\n return true\n }\n return mutationObserver.takeRecords().length > 0\n }\n\n function flush() {\n if (!group) return\n const g = group\n group = null\n const signal = {\n kind: 'forced-reflow' as const,\n at: g.at,\n duration: g.duration,\n count: g.count,\n } as unknown as Signal\n attachLazyStack(signal, g.rawStack, 1)\n emit(signal)\n }\n\n // A layout read happened while recording and layout was dirty. Open a group\n // on the first such read of the turn, then just accumulate count/duration for\n // the rest of the turn. `rawStack` is captured by the caller (the patched\n // accessor) so the stack's top user frame stays at a fixed depth — passing it\n // through a helper would add a frame and misattribute the reflow to this file.\n function record(at: number, duration: number, rawStack: string | undefined) {\n if (group) {\n group.count++\n group.duration += duration\n return\n }\n group = { at, duration, count: 1, rawStack }\n scheduleFlush(flush)\n }\n\n // True when the next dirty read opens a fresh group and so needs a stack.\n // Lets the accessor skip `new Error().stack` (the dominant cost) on the\n // subsequent reads it coalesces into an already-open group.\n function needsStack(): boolean {\n return group === null\n }\n\n function patchGetter(proto: object, key: string) {\n if (typeof proto !== 'object' || proto === null) return\n const desc = Object.getOwnPropertyDescriptor(proto, key)\n if (!desc || !desc.get) return\n saved.push({ proto, key, descriptor: desc })\n const originalGet = desc.get\n Object.defineProperty(proto, key, {\n configurable: true,\n get(this: unknown) {\n if (active) {\n if (!consumePendingMutations()) {\n return originalGet.call(this)\n }\n const rawStack = needsStack() ? new Error().stack : undefined\n const at = performance.now()\n const value = originalGet.call(this)\n record(at, performance.now() - at, rawStack)\n return value\n }\n return originalGet.call(this)\n },\n set: desc.set,\n })\n }\n\n function patchMethod(proto: object, key: string) {\n if (typeof proto !== 'object' || proto === null) return\n const desc = Object.getOwnPropertyDescriptor(proto, key)\n if (!desc || typeof desc.value !== 'function') return\n saved.push({ proto, key, descriptor: desc })\n const original = desc.value as (...args: unknown[]) => unknown\n Object.defineProperty(proto, key, {\n configurable: true,\n writable: true,\n value: function patchedLayoutMethod(this: unknown, ...args: unknown[]) {\n if (active) {\n if (!consumePendingMutations()) {\n return original.apply(this, args)\n }\n const rawStack = needsStack() ? new Error().stack : undefined\n const at = performance.now()\n const value = original.apply(this, args)\n record(at, performance.now() - at, rawStack)\n return value\n }\n return original.apply(this, args)\n },\n })\n }\n\n return {\n kind: 'forced-reflow',\n activate(emitFn) {\n if (active) return\n emit = emitFn\n active = true\n\n if (typeof MutationObserver !== 'undefined' && typeof document !== 'undefined') {\n try {\n mutationObserver = new MutationObserver(() => {})\n mutationObserver.observe(document, {\n attributes: true,\n childList: true,\n subtree: true,\n characterData: true,\n })\n } catch (err) {\n console.warn('[react-perfscope] forced-reflow MutationObserver failed:', err)\n mutationObserver = null\n }\n }\n\n if (typeof HTMLElement !== 'undefined') {\n for (const key of LAYOUT_GETTERS) {\n patchGetter(HTMLElement.prototype, key)\n }\n }\n if (typeof Element !== 'undefined') {\n for (const key of LAYOUT_METHODS) {\n patchMethod(Element.prototype, key)\n }\n }\n },\n deactivate() {\n if (!active) return\n active = false\n // Emit any group still open before the scheduled microtask runs, so the\n // last burst isn't lost when stop() is called mid-turn.\n flush()\n if (mutationObserver) {\n try {\n mutationObserver.disconnect()\n } catch {\n // ignore\n }\n mutationObserver = null\n }\n for (const { proto, key, descriptor } of saved) {\n Object.defineProperty(proto, key, descriptor)\n }\n saved.length = 0\n },\n }\n}\n","import type { Collector, Signal } from '../types'\n\ninterface LayoutShiftSource {\n currentRect: DOMRect\n previousRect?: DOMRect\n node?: Node | null\n}\n\ninterface LayoutShiftEntryLike extends PerformanceEntry {\n value: number\n hadRecentInput: boolean\n sources?: LayoutShiftSource[]\n}\n\nconst PERFSCOPE_HOST_ATTR = 'data-perfscope-host'\n\nfunction rectsOverlap(a: DOMRect, b: DOMRect, tolerance = 0): boolean {\n return !(\n a.x + a.width < b.x - tolerance ||\n b.x + b.width < a.x - tolerance ||\n a.y + a.height < b.y - tolerance ||\n b.y + b.height < a.y - tolerance\n )\n}\n\n/**\n * Returns true when every source in the entry is part of our floating\n * widget. We want to ignore shifts caused by the perfscope UI itself.\n *\n * Detection has two paths:\n * 1. Node-based: walk up `source.node` looking for `[data-perfscope-host]`.\n * Works when the node is in light DOM.\n * 2. Rect-based fallback: compare `source.currentRect` against every host\n * element's bounding rect. This catches the Shadow-DOM case where the\n * browser doesn't expose the inner node (Shadow root boundary).\n */\nfunction collectPerfscopeRects(): DOMRect[] {\n const hosts = Array.from(document.querySelectorAll(`[${PERFSCOPE_HOST_ATTR}]`))\n const rects: DOMRect[] = []\n for (const h of hosts) {\n // The light-DOM host element usually has height 0 because Shadow DOM\n // content isn't part of its layout. We need to peek inside the shadow\n // root and collect bounds of any positioned children.\n const sr = (h as Element & { shadowRoot?: ShadowRoot | null }).shadowRoot\n if (sr) {\n for (const child of Array.from(sr.children)) {\n const r = (child as Element).getBoundingClientRect()\n if (r.width > 0 && r.height > 0) rects.push(r)\n }\n } else {\n const r = h.getBoundingClientRect()\n if (r.width > 0 && r.height > 0) rects.push(r)\n }\n }\n return rects\n}\n\nfunction entryIsOnlyFromPerfscope(sources: LayoutShiftSource[]): boolean {\n if (sources.length === 0) return false\n if (typeof document === 'undefined') return false\n\n const hostRects = collectPerfscopeRects()\n if (hostRects.length === 0) return false\n\n for (const src of sources) {\n let matched = false\n const node = src.node as (Node & { closest?: (sel: string) => Element | null }) | null | undefined\n if (node) {\n // Node-based check\n if (typeof (node as { closest?: unknown }).closest === 'function') {\n if ((node as Element).closest(`[${PERFSCOPE_HOST_ATTR}]`)) matched = true\n } else {\n let parent: (Element | null) = (node as Node).parentElement as Element | null\n while (parent) {\n if (parent.hasAttribute(PERFSCOPE_HOST_ATTR)) { matched = true; break }\n parent = parent.parentElement\n }\n }\n }\n // Rect-based fallback (shadow DOM): if source rect overlaps any of our\n // host rects, consider it our widget. Tolerance covers the case where\n // the widget changes size during the shift (its previous/current bounds\n // differ but both sit in the same screen corner).\n if (!matched) {\n for (const hostRect of hostRects) {\n if (rectsOverlap(src.currentRect, hostRect, 24)) {\n matched = true\n break\n }\n }\n }\n if (!matched) return false\n }\n return true\n}\n\nexport function createLayoutShiftCollector(): Collector {\n let observer: PerformanceObserver | null = null\n let active = false\n\n return {\n kind: 'layout-shift',\n activate(emit: (signal: Signal) => void) {\n if (typeof PerformanceObserver === 'undefined') {\n console.warn('[react-perfscope] PerformanceObserver not supported; layout-shift disabled')\n return\n }\n active = true\n try {\n observer = new PerformanceObserver((list) => {\n if (!active) return\n for (const raw of list.getEntries()) {\n const entry = raw as LayoutShiftEntryLike\n // Note: production CLS metrics exclude shifts with hadRecentInput\n // (user-initiated movements are considered intentional). For a\n // dev tool, the user explicitly WANTS to see what their clicks\n // caused — so we report these too.\n const sources = entry.sources ?? []\n if (entryIsOnlyFromPerfscope(sources)) continue\n // Convert viewport-relative rects to document-relative coords so\n // overlays stay anchored to the shifted DOM position when the\n // user scrolls. Filter above runs first on viewport coords (our\n // widget is position:fixed, lives in viewport space).\n const sx = (typeof window !== 'undefined' && window.scrollX) || 0\n const sy = (typeof window !== 'undefined' && window.scrollY) || 0\n const toDocRect = (r: DOMRect) =>\n new DOMRect(r.x + sx, r.y + sy, r.width, r.height)\n const rects = sources.map((s) => toDocRect(s.currentRect))\n // previousRect is undefined when the element was newly inserted.\n // An \"empty\" rect (w=0, h=0) likewise means there was no prior\n // box — treat both as `null` so the overlay can decide not to\n // draw an arrow for these.\n const prevRects: (DOMRect | null)[] = sources.map((s) => {\n const pr = s.previousRect\n if (!pr) return null\n if (pr.width === 0 && pr.height === 0) return null\n return toDocRect(pr)\n })\n emit({\n kind: 'layout-shift',\n at: entry.startTime,\n value: entry.value,\n sources: rects,\n previousSources: prevRects,\n })\n }\n })\n observer.observe({ type: 'layout-shift', buffered: false })\n } catch (err) {\n console.warn('[react-perfscope] layout-shift collector failed to start:', err)\n observer = null\n active = false\n }\n },\n deactivate() {\n active = false\n if (observer) {\n try {\n observer.disconnect()\n } catch {\n // ignore\n }\n observer = null\n }\n },\n }\n}\n","import type { Collector, Signal } from '../types'\nimport { isSelfRequest } from '../self-requests'\n\ninterface ResourceTimingLike extends PerformanceEntry {\n transferSize?: number\n renderBlockingStatus?: 'blocking' | 'non-blocking'\n}\n\nexport function createNetworkCollector(): Collector {\n let observer: PerformanceObserver | null = null\n let active = false\n\n return {\n kind: 'network',\n activate(emit: (signal: Signal) => void) {\n if (typeof PerformanceObserver === 'undefined') {\n console.warn('[react-perfscope] PerformanceObserver not supported; network disabled')\n return\n }\n active = true\n try {\n observer = new PerformanceObserver((list) => {\n if (!active) return\n for (const raw of list.getEntries()) {\n const entry = raw as ResourceTimingLike\n // Skip react-perfscope's own traffic (source-map fetches).\n if (isSelfRequest(entry.name)) continue\n emit({\n kind: 'network',\n url: entry.name,\n startedAt: entry.startTime,\n duration: entry.duration,\n size: entry.transferSize ?? 0,\n blocking: entry.renderBlockingStatus === 'blocking',\n })\n }\n })\n observer.observe({ type: 'resource', buffered: false })\n } catch (err) {\n console.warn('[react-perfscope] network collector failed to start:', err)\n observer = null\n active = false\n }\n },\n deactivate() {\n active = false\n if (observer) {\n try {\n observer.disconnect()\n } catch {\n // ignore\n }\n observer = null\n }\n },\n }\n}\n","import { onLCP, onINP, onCLS, onFCP, onTTFB, type Metric } from 'web-vitals'\nimport type { Collector, Signal, WebVitalSignal } from '../types'\n\ntype VitalName = WebVitalSignal['name']\n\nexport function createWebVitalsCollector(): Collector {\n let active = false\n let subscribed = false\n let emit: (signal: Signal) => void = () => {}\n\n function makeHandler(name: VitalName) {\n return (metric: Metric) => {\n if (!active) return\n emit({ kind: 'web-vital', name, value: metric.value })\n }\n }\n\n return {\n kind: 'web-vital',\n activate(emitFn) {\n emit = emitFn\n active = true\n if (subscribed) return\n try {\n onLCP(makeHandler('LCP'))\n onINP(makeHandler('INP'))\n onCLS(makeHandler('CLS'))\n onFCP(makeHandler('FCP'))\n onTTFB(makeHandler('TTFB'))\n subscribed = true\n } catch (err) {\n console.warn('[react-perfscope] web-vitals collector failed to subscribe:', err)\n active = false\n }\n },\n deactivate() {\n // The web-vitals library does not expose unsubscribe. We keep the\n // handlers attached and gate emission via `active`. Re-activating\n // updates `emit` without re-subscribing.\n active = false\n },\n }\n}\n","import type {\n Collector,\n HeapSample,\n HeapTrend,\n HeapTrendClass,\n RecordingResult,\n} from '../types'\n\n/** How often to read heap usage while recording. Reading performance.memory\n * is cheap, so we sample at 4Hz: a 1s cadence is too coarse — short spikes fall\n * between samples and the line, drawn straight between sparse points, smooths\n * them into a ramp. 250ms localizes spikes without meaningful overhead. */\nconst SAMPLE_INTERVAL_MS = 250\n/** Cap on retained samples so a multi-hour session can't grow the array\n * unbounded. At 250ms this is ~83 min; past that, oldest samples drop. */\nconst MAX_SAMPLES = 20_000\n\n/** Below this, a trend can't be estimated reliably. */\nconst MIN_SAMPLES = 4\n/** How many contiguous segments to split the series into when estimating the\n * floor. Each segment contributes its minimum (the post-GC trough). */\nconst FLOOR_SEGMENTS = 8\n\nconst MB = 1024 * 1024\n/** Floor-growth thresholds, in bytes per minute. */\nconst GROWING_SLOPE = 1 * MB\nconst LEAK_SLOPE = 5 * MB\n/** A rate alone isn't enough: over a short recording, a sub-megabyte wobble in\n * the floor extrapolates to a huge MB/min and would false-positive. Require the\n * floor to have actually risen by at least this much across the window before\n * calling anything growing/leaking. */\nconst MIN_NET_GROWTH = 2 * MB\n\ninterface MemoryInfo {\n usedJSHeapSize: number\n totalJSHeapSize: number\n jsHeapSizeLimit: number\n}\n\nfunction readMemory(): MemoryInfo | null {\n const perf = (globalThis as { performance?: { memory?: MemoryInfo } }).performance\n const mem = perf?.memory\n if (!mem || typeof mem.usedJSHeapSize !== 'number') return null\n return mem\n}\n\n/**\n * Least-squares slope of points (x, y). Returns 0 when x has no spread\n * (vertical / single distinct x) to avoid a divide-by-zero blow-up.\n */\nfunction slope(points: { x: number; y: number }[]): number {\n const n = points.length\n if (n < 2) return 0\n let sx = 0\n let sy = 0\n let sxy = 0\n let sxx = 0\n for (const { x, y } of points) {\n sx += x\n sy += y\n sxy += x * y\n sxx += x * x\n }\n const denom = n * sxx - sx * sx\n if (denom === 0) return 0\n return (n * sxy - sx * sy) / denom\n}\n\n/**\n * Estimate whether memory is being retained across the recording.\n *\n * GC makes raw heap usage a sawtooth, so the peak is noisy. The reliable\n * signal is the *floor* — the post-GC troughs. We split the series into\n * contiguous segments, take the minimum of each (its trough), and regress\n * those minima against time.\n *\n * A rising overall slope is necessary but NOT sufficient: a one-time step\n * (heap warms up early, then plateaus) also regresses to a positive slope, and\n * flagging that as a leak is a false positive — the classic \"idle recording\n * reads abnormal\" bug. A real leak keeps climbing, so we additionally require\n * the *recent* half of the floor to still be rising. We also gate on a minimum\n * net growth, since over a short window a sub-MB wobble extrapolates to a steep\n * per-minute slope.\n *\n * Returns null when there are too few samples to say anything.\n */\nexport function analyzeHeapTrend(samples: HeapSample[]): HeapTrend | null {\n if (samples.length < MIN_SAMPLES) return null\n const t0 = samples[0]!.at\n const segSize = Math.max(1, Math.ceil(samples.length / FLOOR_SEGMENTS))\n const floorPoints: { x: number; y: number }[] = []\n for (let i = 0; i < samples.length; i += segSize) {\n const seg = samples.slice(i, i + segSize)\n let min = Infinity\n for (const s of seg) min = Math.min(min, s.used)\n const mid = seg[Math.floor(seg.length / 2)]!\n floorPoints.push({ x: (mid.at - t0) / 60000, y: min })\n }\n const slopeBytesPerMin = slope(floorPoints)\n const spanMin = (samples[samples.length - 1]!.at - t0) / 60000\n const projectedGrowth = slopeBytesPerMin * spanMin\n // Recent trend: is the floor still climbing in the latter half? Distinguishes\n // a sustained leak from a one-time step that has since plateaued.\n const recent = floorPoints.slice(Math.floor(floorPoints.length / 2))\n const recentSlope = recent.length >= 2 ? slope(recent) : slopeBytesPerMin\n\n let classification: HeapTrendClass = 'stable'\n const sustained = projectedGrowth >= MIN_NET_GROWTH && recentSlope >= GROWING_SLOPE\n if (sustained) {\n classification =\n slopeBytesPerMin >= LEAK_SLOPE && recentSlope >= LEAK_SLOPE ? 'leak-suspected' : 'growing'\n }\n return { classification, slopeBytesPerMin }\n}\n\nexport interface HeapCollector extends Collector {\n /** Attach the sampled heap series to the recording result. Returns the\n * input untouched when nothing was sampled (unsupported browser). */\n finalize(result: RecordingResult): RecordingResult\n}\n\n/**\n * Samples `performance.memory` on an interval for the duration of a recording\n * and attaches the series via `finalize`. It is a Collector so the recorder\n * drives its start/stop, but it emits no signals — the series is a separate\n * track (see RecordingResult.heapSamples), so a busy session's signal buffer\n * can't evict it. No-ops entirely when performance.memory is unavailable\n * (non-Chromium), leaving `heapSamples` absent so the UI can show a fallback.\n */\nexport function createHeapCollector(): HeapCollector {\n let samples: HeapSample[] = []\n let timer: ReturnType<typeof setInterval> | null = null\n\n function sample(): void {\n const mem = readMemory()\n if (!mem) return\n samples.push({ at: performance.now(), used: mem.usedJSHeapSize, total: mem.totalJSHeapSize })\n if (samples.length > MAX_SAMPLES) samples.splice(0, samples.length - MAX_SAMPLES)\n }\n\n return {\n kind: 'heap',\n activate() {\n samples = []\n if (!readMemory()) return // unsupported → never start the timer\n sample()\n timer = setInterval(sample, SAMPLE_INTERVAL_MS)\n },\n deactivate() {\n if (timer == null) return\n clearInterval(timer)\n timer = null\n sample() // one final reading at stop\n },\n finalize(result) {\n if (samples.length === 0) return result\n return { ...result, heapSamples: samples.slice() }\n },\n }\n}\n","import type { Collector, InteractionSignal, RecordingResult } from '../types'\n\n/** Event Timing only surfaces events at/over this duration (ms); 40ms keeps\n * trivial interactions out while still catching anything a user would feel. */\nconst DURATION_THRESHOLD = 40\n\ninterface EventTimingEntry extends PerformanceEntry {\n processingStart: number\n processingEnd: number\n interactionId?: number\n target?: unknown\n}\n\nfunction selectorFor(target: unknown): string | undefined {\n const el = target as { tagName?: string; id?: string; className?: unknown } | null\n if (!el || typeof el.tagName !== 'string') return undefined\n let s = el.tagName.toLowerCase()\n if (el.id) s += `#${el.id}`\n else if (typeof el.className === 'string' && el.className.trim()) {\n s += `.${el.className.trim().split(/\\s+/)[0]}`\n }\n return s\n}\n\nfunction supportsEventTiming(): boolean {\n const PO = (globalThis as { PerformanceObserver?: { supportedEntryTypes?: readonly string[] } })\n .PerformanceObserver\n const types = PO?.supportedEntryTypes\n // happy-dom / older browsers may not expose supportedEntryTypes; if the\n // observer exists at all we still try, and observe() throwing is caught.\n return !types || types.includes('event')\n}\n\nexport interface InteractionCollector extends Collector {\n /** Group buffered Event Timing entries into one interaction each and append\n * them to the result. Returns the input untouched when none qualified. */\n finalize(result: RecordingResult): RecordingResult\n}\n\n/**\n * Records Event Timing entries during a recording and, on finalize, turns each\n * user interaction (grouped by interactionId) into one signal carrying the INP\n * latency breakdown: input delay → processing → presentation. The longest\n * event in a group defines the interaction's latency (matching how INP is\n * attributed). Emits no live signals — interactions are assembled at finalize,\n * then the self-profiling collector attributes the processing window to the\n * developer's hot functions.\n */\nexport function createInteractionCollector(): InteractionCollector {\n let active = false\n let observer: PerformanceObserver | null = null\n let entries: EventTimingEntry[] = []\n\n return {\n kind: 'interaction',\n activate() {\n if (typeof PerformanceObserver === 'undefined' || !supportsEventTiming()) return\n active = true\n entries = []\n try {\n observer = new PerformanceObserver((list) => {\n if (!active) return\n for (const e of list.getEntries()) entries.push(e as EventTimingEntry)\n })\n // `event` covers all interaction events; `first-input` guarantees the\n // first one even if it's under the duration threshold.\n observer.observe({ type: 'event', buffered: false, durationThreshold: DURATION_THRESHOLD } as PerformanceObserverInit)\n try {\n observer.observe({ type: 'first-input', buffered: false } as PerformanceObserverInit)\n } catch {\n // first-input not supported everywhere; the event stream is enough.\n }\n } catch (err) {\n console.warn('[react-perfscope] interaction collector failed to start:', err)\n observer = null\n active = false\n }\n },\n deactivate() {\n active = false\n if (observer) {\n try {\n observer.disconnect()\n } catch {\n // ignore\n }\n observer = null\n }\n },\n finalize(result) {\n const byId = new Map<number, EventTimingEntry[]>()\n for (const e of entries) {\n const id = e.interactionId\n if (!id) continue // 0 / undefined → not part of a discrete interaction\n const group = byId.get(id)\n if (group) group.push(e)\n else byId.set(id, [e])\n }\n const interactions: InteractionSignal[] = []\n for (const group of byId.values()) {\n // All events of one interaction (pointerdown/up/click) report the same\n // `duration` (the whole interaction latency), so the breakdown can't\n // come from a single event. Span the processing across the group:\n // earliest processingStart → latest processingEnd (matches web-vitals).\n // The \"defining\" event for label/target is the one with the most\n // processing — typically the click/keydown that actually ran handlers.\n let duration = 0\n let startTime = Infinity\n let processingStart = Infinity\n let processingEnd = -Infinity\n let defining = group[0]!\n let maxProcessing = -Infinity\n for (const e of group) {\n if (e.duration > duration) duration = e.duration\n if (e.startTime < startTime) startTime = e.startTime\n if (e.processingStart < processingStart) processingStart = e.processingStart\n if (e.processingEnd > processingEnd) processingEnd = e.processingEnd\n const proc = e.processingEnd - e.processingStart\n if (proc > maxProcessing) {\n maxProcessing = proc\n defining = e\n }\n }\n if (duration < DURATION_THRESHOLD) continue\n const inputDelay = Math.max(0, processingStart - startTime)\n const processing = Math.max(0, processingEnd - processingStart)\n const presentation = Math.max(0, startTime + duration - processingEnd)\n interactions.push({\n kind: 'interaction',\n at: startTime,\n eventType: defining.name,\n ...(selectorFor(defining.target) ? { target: selectorFor(defining.target) } : {}),\n duration,\n inputDelay,\n processing,\n presentation,\n })\n }\n if (interactions.length === 0) return result\n interactions.sort((a, b) => a.at - b.at)\n return { ...result, signals: [...result.signals, ...interactions] }\n },\n }\n}\n","import type { Collector, FpsSample, FrameStats, RecordingResult } from '../types'\n\n/** 60fps frame budget (ms). Gaps are scored against this to count drops. */\nconst FRAME_BUDGET = 1000 / 60\n/** Window for the FPS series; 500ms smooths per-frame noise while still showing\n * a scroll-jank dip. */\nconst BUCKET_MS = 500\n/** A trailing window shorter than this is too small to estimate FPS reliably. */\nconst MIN_BUCKET_SPAN = 100\n/** Below this we can't say anything useful. */\nconst MIN_FRAMES = 8\n/** Cap retained frames so a long session can't grow the array unbounded\n * (~5.5 min at 60fps); past that, oldest drop. */\nconst MAX_FRAMES = 20_000\n\n/**\n * Turn raw requestAnimationFrame timestamps into a frame-rate picture:\n * a windowed FPS series, the lowest sustained FPS, the worst single hitch,\n * and an approximate dropped-frame count. Long tasks (>50ms) show up here as\n * big gaps, but so does sustained scroll jank (30–50ms frames) that the\n * long-task collector's threshold misses.\n *\n * Returns null when there are too few frames to analyze.\n */\nexport function analyzeFrames(frames: number[]): FrameStats | null {\n if (frames.length < MIN_FRAMES) return null\n\n let longestFrameMs = 0\n let droppedFrames = 0\n for (let i = 1; i < frames.length; i++) {\n const gap = frames[i]! - frames[i - 1]!\n if (gap > longestFrameMs) longestFrameMs = gap\n const dropped = Math.round(gap / FRAME_BUDGET) - 1\n if (dropped > 0) droppedFrames += dropped\n }\n\n const t0 = frames[0]!\n const end = frames[frames.length - 1]!\n const series: FpsSample[] = []\n let minFps = Infinity\n let idx = 0\n for (let bStart = t0; bStart < end; bStart += BUCKET_MS) {\n const bEnd = Math.min(bStart + BUCKET_MS, end)\n const span = bEnd - bStart\n let count = 0\n while (idx < frames.length && frames[idx]! < bEnd) {\n count++\n idx++\n }\n if (span < MIN_BUCKET_SPAN) break // skip a tiny trailing window\n const fps = count / (span / 1000)\n series.push({ at: bStart + span / 2, fps })\n if (fps < minFps) minFps = fps\n }\n if (series.length === 0) return null\n return { series, minFps, longestFrameMs, droppedFrames }\n}\n\nexport interface FrameCollector extends Collector {\n /** Attach the captured frame timestamps to the result. Returns the input\n * untouched when too few frames were seen (or rAF was unavailable). */\n finalize(result: RecordingResult): RecordingResult\n}\n\n/**\n * Records requestAnimationFrame timestamps for the duration of a recording so\n * the UI can chart frame rate and surface jank. Emits no signals — the\n * timestamps are a side track attached at finalize. No-ops when\n * requestAnimationFrame is unavailable (non-DOM environments).\n */\nexport function createFrameCollector(): FrameCollector {\n let active = false\n let rafId: number | null = null\n let frames: number[] = []\n\n function loop(t: number): void {\n if (!active) return\n frames.push(t)\n if (frames.length > MAX_FRAMES) frames.splice(0, frames.length - MAX_FRAMES)\n rafId = requestAnimationFrame(loop)\n }\n\n return {\n kind: 'frame',\n activate() {\n if (typeof requestAnimationFrame === 'undefined') return\n active = true\n frames = []\n rafId = requestAnimationFrame(loop)\n },\n deactivate() {\n active = false\n if (rafId != null && typeof cancelAnimationFrame !== 'undefined') {\n try {\n cancelAnimationFrame(rafId)\n } catch {\n // ignore\n }\n }\n rafId = null\n },\n finalize(result) {\n if (frames.length < MIN_FRAMES) return result\n return { ...result, frames: frames.slice() }\n },\n }\n}\n","import type { Collector, LongTaskAttribution, RecordingResult, Signal, StackFrame } from '../types'\n\n/**\n * JS Self-Profiling API trace shape (the subset we consume).\n * @see https://wicg.github.io/js-self-profiling/\n */\nexport interface ProfilerFrame {\n name?: string\n resourceId?: number\n line?: number\n column?: number\n}\nexport interface ProfilerStack {\n frameId: number\n parentId?: number\n}\nexport interface ProfilerSample {\n /** DOMHighResTimeStamp, same clock as performance.now() / entry.startTime. */\n timestamp: number\n stackId?: number\n}\nexport interface ProfilerTrace {\n resources: string[]\n frames: ProfilerFrame[]\n stacks: ProfilerStack[]\n samples: ProfilerSample[]\n}\n\ninterface ProfilerInstance {\n stop(): Promise<ProfilerTrace>\n}\ninterface ProfilerCtor {\n new (opts: { sampleInterval: number; maxBufferSize: number }): ProfilerInstance\n}\n\n/** Default sampling cadence. The browser may coarsen this. */\nconst SAMPLE_INTERVAL_MS = 10\nconst MAX_BUFFER_SIZE = 100_000\n/** Keep the noisiest few; deeper tails rarely help the developer. */\nconst MAX_FRAMES_PER_TASK = 5\n\n/**\n * Whether a resource URL belongs to the developer's own source (vs. a\n * dependency or tooling shim). Dependency frames are noise when the question\n * is \"which of MY functions is slow\".\n */\nexport function isUserResource(url: string | undefined): boolean {\n if (!url) return false\n if (url.includes('/node_modules/')) return false\n // Vite/dev tooling virtual modules: /@vite/client, /@react-refresh, /@id/...\n try {\n const path = new URL(url).pathname\n if (path.startsWith('/@')) return false\n } catch {\n if (url.startsWith('/@')) return false\n }\n return true\n}\n\nfunction frameToStackFrame(trace: ProfilerTrace, frame: ProfilerFrame): StackFrame {\n const file = frame.resourceId != null ? (trace.resources[frame.resourceId] ?? '') : ''\n const sf: StackFrame = {\n file,\n line: frame.line ?? 0,\n col: frame.column ?? 0,\n }\n if (frame.name) sf.fnName = frame.name\n return sf\n}\n\n/**\n * Climb a sample's stack from the leaf toward the root, returning the first\n * (deepest) frame that lives in user source. That frame is where the\n * developer's own code was actually executing when the sample was taken.\n */\nfunction leafUserFrame(trace: ProfilerTrace, stackId: number | undefined): ProfilerFrame | null {\n let id = stackId\n let guard = 0\n while (id != null && guard++ < 1000) {\n const stack = trace.stacks[id]\n if (!stack) break\n const frame = trace.frames[stack.frameId]\n if (frame && isUserResource(trace.resources[frame.resourceId ?? -1])) {\n return frame\n }\n id = stack.parentId\n }\n return null\n}\n\n/**\n * Aggregate the hottest user-source frames among samples whose timestamp\n * falls in [start, end]. `selfRatio` is relative to ALL in-window samples\n * (including vendor-only ones), so it reflects the share of the task's\n * blocking time spent in that user function.\n */\nexport function attributeWindow(\n trace: ProfilerTrace,\n start: number,\n end: number\n): LongTaskAttribution[] {\n let total = 0\n const counts = new Map<string, { frame: StackFrame; count: number }>()\n for (const sample of trace.samples) {\n if (sample.timestamp < start || sample.timestamp > end) continue\n total++\n const frame = leafUserFrame(trace, sample.stackId)\n if (!frame) continue\n const sf = frameToStackFrame(trace, frame)\n const key = `${sf.file}:${sf.line}:${sf.col}:${sf.fnName ?? ''}`\n const entry = counts.get(key)\n if (entry) entry.count++\n else counts.set(key, { frame: sf, count: 1 })\n }\n if (total === 0) return []\n return [...counts.values()]\n .sort((a, b) => b.count - a.count)\n .slice(0, MAX_FRAMES_PER_TASK)\n .map(({ frame, count }) => ({ frame, selfRatio: count / total, sampleCount: count }))\n}\n\n/**\n * Return a copy of `signals` with each long-task signal enriched with the\n * hottest user frames sampled during its window. Long tasks with no in-window\n * user samples are left without `attribution`. Non-long-task signals pass\n * through by reference.\n */\nexport function attributeLongTaskSignals(trace: ProfilerTrace, signals: Signal[]): Signal[] {\n return signals.map((signal) => {\n if (signal.kind !== 'long-task') return signal\n const attribution = attributeWindow(trace, signal.at, signal.at + signal.duration)\n if (attribution.length === 0) return signal\n return { ...signal, attribution }\n })\n}\n\n/**\n * Like {@link attributeLongTaskSignals} but for interactions: attributes the\n * *processing* window (handlers running, `[at+inputDelay, +processing]`) to the\n * developer's hot functions — answering \"which of my code made this click\n * slow\". Input delay and presentation aren't JS-on-the-stack, so they're\n * excluded from the window.\n */\nexport function attributeInteractionSignals(trace: ProfilerTrace, signals: Signal[]): Signal[] {\n return signals.map((signal) => {\n if (signal.kind !== 'interaction') return signal\n const start = signal.at + signal.inputDelay\n const attribution = attributeWindow(trace, start, start + signal.processing)\n if (attribution.length === 0) return signal\n return { ...signal, attribution }\n })\n}\n\ninterface SelfProfilingCollector extends Collector {\n /** Stop the profiler (if running), await its trace, and return a result\n * with long-task signals enriched. Falls back to the input on any failure\n * or when the Profiler API / Document-Policy header is unavailable. */\n finalize(result: RecordingResult): Promise<RecordingResult>\n}\n\n/**\n * Collector that runs the JS Self-Profiling API across a recording and, on\n * finalize, attributes each long task to the developer's own hot functions —\n * something LoAF can't do for React-delegated events (it only sees React's\n * single root dispatcher).\n *\n * It reports `kind: 'long-task'` because it enriches that signal rather than\n * emitting its own. Requires Chromium + a `Document-Policy: js-profiling`\n * response header (the dev plugins inject it); degrades to a no-op otherwise.\n */\nexport function createSelfProfilingCollector(): SelfProfilingCollector {\n let profiler: ProfilerInstance | null = null\n let tracePromise: Promise<ProfilerTrace> | null = null\n\n return {\n kind: 'long-task',\n activate() {\n tracePromise = null\n const Ctor = (globalThis as { Profiler?: ProfilerCtor }).Profiler\n if (typeof Ctor !== 'function') return\n try {\n profiler = new Ctor({ sampleInterval: SAMPLE_INTERVAL_MS, maxBufferSize: MAX_BUFFER_SIZE })\n } catch (err) {\n // Thrown when the Document-Policy: js-profiling header is absent.\n console.warn(\n '[react-perfscope] self-profiling unavailable (needs Document-Policy: js-profiling header); long tasks keep LoAF-only attribution:',\n err\n )\n profiler = null\n }\n },\n deactivate() {\n if (!profiler) return\n try {\n tracePromise = profiler.stop()\n } catch (err) {\n console.warn('[react-perfscope] self-profiling stop failed:', err)\n tracePromise = null\n }\n profiler = null\n },\n async finalize(result: RecordingResult): Promise<RecordingResult> {\n if (!tracePromise) return result\n try {\n const trace = await tracePromise\n const signals = attributeInteractionSignals(trace, attributeLongTaskSignals(trace, result.signals))\n return { ...result, signals }\n } catch (err) {\n console.warn('[react-perfscope] self-profiling finalize failed:', err)\n return result\n } finally {\n tracePromise = null\n }\n },\n }\n}\n"],"mappings":"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","names":["MIN_SAMPLES","FLOOR_SEGMENTS","MIN_NET_GROWTH","slope","SAMPLE_INTERVAL_MS"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/recorder.ts","../src/sourcemap.ts","../src/self-requests.ts","../src/capabilities.ts","../src/leak-trend.ts","../src/correlate.ts","../src/collectors/long-tasks.ts","../src/collectors/forced-reflow.ts","../src/collectors/layout-shift.ts","../src/collectors/network.ts","../src/collectors/web-vitals.ts","../src/collectors/heap.ts","../src/collectors/interaction.ts","../src/collectors/frames.ts","../src/collectors/self-profiling.ts"],"sourcesContent":["// Types\nexport * from './types'\n\n// Recorder\nexport { createRecorder, BUFFER_CAP } from './recorder'\n\n// Sourcemap utilities\nexport { parseStack, resolveFrame, attachLazyStack, createSourceMapResolver } from './sourcemap'\nexport type { FetchMap, SourceMapResolver, CreateSourceMapResolverOptions } from './sourcemap'\n\n// Self-request registry (excludes the tool's own traffic from network signals)\nexport { markSelfRequest, isSelfRequest } from './self-requests'\n\n// Browser capability detection (which signal kinds this browser can measure)\nexport { detectCapabilities, unsupportedKinds } from './capabilities'\nexport type { Capabilities } from './capabilities'\n\n// Component leak-trend analysis (rising retained-after-unmount instances)\nexport { analyzeLeakTrend } from './leak-trend'\nexport type { LeakSample } from './leak-trend'\n\n// Cross-signal correlation (groups signals into interaction/long-task episodes)\nexport { correlate } from './correlate'\nexport type { Episode, EpisodeMember, AnchorSignal, LinkConfidence, InpPhase, CommitCause } from './correlate'\n\n// Collectors\nexport { createLongTasksCollector } from './collectors/long-tasks'\nexport { createForcedReflowCollector } from './collectors/forced-reflow'\nexport { createLayoutShiftCollector } from './collectors/layout-shift'\nexport { createNetworkCollector } from './collectors/network'\nexport { createWebVitalsCollector } from './collectors/web-vitals'\nexport { createHeapCollector, analyzeHeapTrend } from './collectors/heap'\nexport type { HeapCollector } from './collectors/heap'\nexport { createInteractionCollector } from './collectors/interaction'\nexport type { InteractionCollector } from './collectors/interaction'\nexport { createFrameCollector, analyzeFrames } from './collectors/frames'\nexport type { FrameCollector } from './collectors/frames'\nexport {\n createSelfProfilingCollector,\n attributeWindow,\n attributeLongTaskSignals,\n isUserResource,\n} from './collectors/self-profiling'\nexport type {\n ProfilerTrace,\n ProfilerFrame,\n ProfilerStack,\n ProfilerSample,\n} from './collectors/self-profiling'\n","import type { Collector, Recorder, RecordingResult, Signal } from './types'\n\n/** Hard cap on retained signals; the oldest are dropped past this. Exported so\n * downstream tests can assert the buffer never grows beyond it. */\nexport const BUFFER_CAP = 10_000\n\nexport interface InternalRecorder extends Recorder {\n __push: (signal: Signal) => void\n}\n\nexport function createRecorder(): Recorder {\n let recording = false\n let startedAt = 0\n let buffer: Signal[] = []\n const subscribers = new Set<(s: Signal) => void>()\n const collectors: Collector[] = []\n\n function notify(signal: Signal) {\n for (const cb of subscribers) {\n try {\n cb(signal)\n } catch (err) {\n console.warn('[react-perfscope] subscriber threw:', err)\n }\n }\n }\n\n function push(signal: Signal) {\n if (!recording) return\n buffer.push(signal)\n if (buffer.length > BUFFER_CAP) {\n buffer.splice(0, buffer.length - BUFFER_CAP)\n }\n notify(signal)\n }\n\n const recorder: InternalRecorder = {\n start() {\n if (recording) return\n recording = true\n startedAt = performance.now()\n buffer = []\n for (const c of collectors) {\n try {\n c.activate(push)\n } catch (err) {\n console.warn(`[react-perfscope] collector ${c.kind} failed to activate:`, err)\n }\n }\n },\n stop(): RecordingResult {\n if (!recording) {\n return { signals: [], startedAt: 0, duration: 0 }\n }\n for (const c of collectors) {\n try {\n c.deactivate()\n } catch (err) {\n console.warn(`[react-perfscope] collector ${c.kind} failed to deactivate:`, err)\n }\n }\n const duration = performance.now() - startedAt\n const result: RecordingResult = {\n signals: buffer.slice(),\n startedAt,\n duration,\n }\n recording = false\n buffer = []\n return result\n },\n isRecording() {\n return recording\n },\n onSignal(cb) {\n subscribers.add(cb)\n return () => subscribers.delete(cb)\n },\n use(collector) {\n collectors.push(collector)\n },\n __push: push,\n }\n return recorder\n}\n","import { TraceMap, originalPositionFor, type SourceMapInput } from '@jridgewell/trace-mapping'\nimport type { StackFrame } from './types'\nimport { markSelfRequest } from './self-requests'\n\nconst CHROME_FRAME = /^\\s*at\\s+(?:(.+?)\\s+\\()?(.+?):(\\d+):(\\d+)\\)?$/\nconst FIREFOX_FRAME = /^(.*?)@(.+?):(\\d+):(\\d+)$/\n\n/** A parsed source map (the JSON object), as returned by a FetchMap. */\nexport type RawSourceMap = SourceMapInput\n\nexport type FetchMap = (file: string) => Promise<RawSourceMap | null>\n\nfunction lookupFrame(tracer: TraceMap, frame: StackFrame): StackFrame {\n // Stack-trace columns (Chrome and Firefox alike) are 1-based, while source\n // map segments store 0-based columns — shift on the way in and back out.\n // In minified bundles one column is often a whole identifier, so an\n // off-by-one maps to the wrong token.\n const pos = originalPositionFor(tracer, { line: frame.line, column: frame.col - 1 })\n if (pos.source == null || pos.line == null || pos.column == null) {\n return frame\n }\n const resolved: StackFrame = {\n file: pos.source,\n line: pos.line,\n col: pos.column + 1,\n }\n if (pos.name) resolved.fnName = pos.name\n else if (frame.fnName) resolved.fnName = frame.fnName\n return resolved\n}\n\nexport async function resolveFrame(\n frame: StackFrame,\n fetchMap: FetchMap\n): Promise<StackFrame> {\n try {\n const map = await fetchMap(frame.file)\n if (!map) return frame\n // trace-mapping is pure JS (no wasm), so this works in the browser where\n // Mozilla's source-map SourceMapConsumer needs an explicitly-initialized\n // mappings.wasm.\n return lookupFrame(new TraceMap(map), frame)\n } catch (err) {\n console.warn('[react-perfscope] resolveFrame failed:', err)\n return frame\n }\n}\n\n/**\n * Attach a lazy `stack` getter to `target` that parses `raw` on first access\n * and memoizes the result. Use this from collectors to defer parseStack cost\n * until a consumer actually reads `signal.stack`.\n *\n * `skipTopFrames` drops the leading N parsed frames — useful for collectors\n * that wrap a patched function (the wrapper itself shows up as the topmost\n * frame, but it's noise from the user's perspective).\n */\nexport function attachLazyStack(\n target: object,\n raw: string | undefined,\n skipTopFrames = 0\n): void {\n let cached: StackFrame[] | null = null\n Object.defineProperty(target, 'stack', {\n enumerable: true,\n configurable: true,\n get() {\n if (cached === null) {\n const all = parseStack(raw)\n cached = skipTopFrames > 0 ? all.slice(skipTopFrames) : all\n }\n return cached\n },\n })\n}\n\nexport interface SourceMapResolver {\n /** Resolve a parsed StackFrame to its original source position. Falls back to the input frame on any failure. */\n resolve(frame: StackFrame): Promise<StackFrame>\n}\n\nexport interface CreateSourceMapResolverOptions {\n /** Override the global fetch. Useful for tests and non-browser environments. */\n fetch?: typeof globalThis.fetch\n}\n\n/**\n * Create a SourceMap resolver that fetches `.map` files from the live URL\n * referenced in each source file's `//# sourceMappingURL=` directive.\n * Caches the DECODED TraceMap per source URL — decoding the mappings is the\n * expensive step, so repeated resolves against the same file are O(log n)\n * lookups after the first.\n *\n * Returns the input frame on any failure (network error, missing map, etc.).\n */\nexport function createSourceMapResolver(opts: CreateSourceMapResolverOptions = {}): SourceMapResolver {\n const f = opts.fetch ?? (typeof fetch !== 'undefined' ? fetch.bind(globalThis) : null)\n const cache = new Map<string, Promise<TraceMap | null>>()\n\n function fetchTracerFor(sourceUrl: string): Promise<TraceMap | null> {\n if (!f) return Promise.resolve(null)\n const existing = cache.get(sourceUrl)\n if (existing) return existing\n const promise = (async () => {\n try {\n markSelfRequest(sourceUrl)\n const res = await f(sourceUrl)\n if (!res || !res.ok) return null\n const text = await res.text()\n const m = text.match(/\\/\\/[#@]\\s*sourceMappingURL=(.+?)\\s*$/m)\n if (!m) return null\n const ref = m[1]!.trim()\n if (ref.startsWith('data:')) {\n const commaIdx = ref.indexOf(',')\n if (commaIdx === -1) return null\n const header = ref.slice(0, commaIdx)\n const payload = ref.slice(commaIdx + 1)\n const decoded = header.includes('base64')\n ? typeof atob === 'function'\n ? atob(payload)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n : (globalThis as any).Buffer.from(payload, 'base64').toString('utf8')\n : decodeURIComponent(payload)\n return new TraceMap(JSON.parse(decoded) as RawSourceMap)\n }\n const mapUrl = new URL(ref, sourceUrl).href\n markSelfRequest(mapUrl)\n const mapRes = await f(mapUrl)\n if (!mapRes || !mapRes.ok) return null\n return new TraceMap((await mapRes.json()) as RawSourceMap)\n } catch {\n return null\n }\n })()\n cache.set(sourceUrl, promise)\n return promise\n }\n\n return {\n async resolve(frame) {\n try {\n const tracer = await fetchTracerFor(frame.file)\n if (!tracer) return frame\n return lookupFrame(tracer, frame)\n } catch {\n return frame\n }\n },\n }\n}\n\nexport function parseStack(raw: string | undefined): StackFrame[] {\n if (!raw) return []\n const frames: StackFrame[] = []\n for (const line of raw.split('\\n')) {\n const chromeMatch = line.match(CHROME_FRAME)\n if (chromeMatch) {\n const [, fnName, file, lineStr, colStr] = chromeMatch\n const frame: StackFrame = {\n file: file ?? '',\n line: Number(lineStr),\n col: Number(colStr),\n }\n if (fnName) frame.fnName = fnName\n frames.push(frame)\n continue\n }\n const firefoxMatch = line.match(FIREFOX_FRAME)\n if (firefoxMatch) {\n const [, fnName, file, lineStr, colStr] = firefoxMatch\n const frame: StackFrame = {\n file: file ?? '',\n line: Number(lineStr),\n col: Number(colStr),\n }\n if (fnName) frame.fnName = fnName\n frames.push(frame)\n }\n }\n return frames\n}\n","// Registry of URLs that react-perfscope itself fetched (source files and their\n// source maps, when resolving stack frames). The network collector consults\n// this so the tool's own traffic never shows up as one of the app's network\n// signals — measuring shouldn't report the measurer.\n\nconst selfRequests = new Set<string>()\n\n/** Record that react-perfscope is about to fetch `url`, so the network\n * collector can exclude its resource-timing entry. */\nexport function markSelfRequest(url: string): void {\n selfRequests.add(url)\n}\n\n/** True when `url` was fetched by react-perfscope itself. */\nexport function isSelfRequest(url: string): boolean {\n return selfRequests.has(url)\n}\n","import type { SignalKind } from './types'\n\nexport type Capabilities = Record<SignalKind, boolean>\n\nfunction supportedEntryTypes(): readonly string[] | undefined {\n const PO = (globalThis as { PerformanceObserver?: { supportedEntryTypes?: readonly string[] } })\n .PerformanceObserver\n return PO?.supportedEntryTypes\n}\n\n/** True unless the browser exposes `supportedEntryTypes` AND it includes none of\n * the needed entry types. An unknown environment (older browsers / test envs\n * that don't expose the list) is treated as supported, so we never falsely\n * report a feature missing — the collector's own try/catch is the backstop. */\nfunction observerSupported(needed: readonly string[]): boolean {\n const types = supportedEntryTypes()\n if (!Array.isArray(types)) return true\n return needed.some((t) => types.includes(t))\n}\n\n/** Which signal kinds the current browser can actually measure. The render and\n * forced-reflow collectors are pure JS (React fibers / DOM-API instrumentation)\n * so they work everywhere; the rest depend on PerformanceObserver entry types\n * that Firefox and Safari do not implement (long tasks, layout shift, INP). */\nexport function detectCapabilities(): Capabilities {\n return {\n 'forced-reflow': true,\n render: true,\n 'web-vital': true,\n 'layout-shift': observerSupported(['layout-shift']),\n 'long-task': observerSupported(['long-animation-frame', 'longtask']),\n interaction: observerSupported(['event']),\n network: observerSupported(['resource']),\n }\n}\n\n/** Signal kinds the current browser cannot measure — for telling the user a\n * tab is empty because of the platform, not because nothing happened. */\nexport function unsupportedKinds(): SignalKind[] {\n const caps = detectCapabilities()\n return (Object.keys(caps) as SignalKind[]).filter((k) => !caps[k])\n}\n","/** One reading of how many unmounted instances of a component are still\n * retained (alive, not yet garbage-collected) at a point in time. */\nexport type LeakSample = { at: number; retained: number }\n\n/** Minimum samples before a trend can be estimated. */\nconst MIN_SAMPLES = 4\n/** Segments to split the series into when estimating the retained floor. */\nconst FLOOR_SEGMENTS = 8\n/** Require the retained floor to climb by at least this many instances across\n * the window before flagging — a transient one or two awaiting GC is not a\n * leak. */\nconst MIN_NET_GROWTH = 3\n\nfunction slope(points: { x: number; y: number }[]): number {\n const n = points.length\n if (n < 2) return 0\n let sx = 0\n let sy = 0\n let sxy = 0\n let sxx = 0\n for (const { x, y } of points) {\n sx += x\n sy += y\n sxy += x * y\n sxx += x * x\n }\n const denom = n * sxx - sx * sx\n if (denom === 0) return 0\n return (n * sxy - sx * sy) / denom\n}\n\n/**\n * Decide whether a component's retained-instance series indicates a leak.\n *\n * Mirrors {@link analyzeHeapTrend}: GC makes the raw retained count a sawtooth\n * (instances pile up, then a sweep collects a batch), so the reliable signal is\n * the *floor* — the post-GC troughs. We segment the series, take each segment's\n * minimum, and regress those minima against time.\n *\n * A rising slope alone is not enough: a one-time step (a screen mounts N\n * long-lived instances once, then plateaus) regresses positive but is not a\n * leak. So we additionally require the recent half of the floor to still be\n * rising, and gate on a minimum net growth in instances. This is what makes the\n * detector robust to React StrictMode's intentional mount→unmount→remount\n * churn, whose discarded fibers get collected and keep the floor flat.\n *\n * Returns null when there are too few samples to say anything.\n */\nexport function analyzeLeakTrend(\n samples: LeakSample[]\n): { leaking: boolean; slopePerMin: number } | null {\n if (samples.length < MIN_SAMPLES) return null\n const t0 = samples[0]!.at\n const segSize = Math.max(1, Math.ceil(samples.length / FLOOR_SEGMENTS))\n const floorPoints: { x: number; y: number }[] = []\n for (let i = 0; i < samples.length; i += segSize) {\n const seg = samples.slice(i, i + segSize)\n let min = Infinity\n for (const s of seg) min = Math.min(min, s.retained)\n const mid = seg[Math.floor(seg.length / 2)]!\n floorPoints.push({ x: (mid.at - t0) / 60000, y: min })\n }\n const slopePerMin = slope(floorPoints)\n const spanMin = (samples[samples.length - 1]!.at - t0) / 60000\n const projectedGrowth = slopePerMin * spanMin\n const recent = floorPoints.slice(Math.floor(floorPoints.length / 2))\n const recentSlope = recent.length >= 2 ? slope(recent) : slopePerMin\n const leaking = projectedGrowth >= MIN_NET_GROWTH && recentSlope > 0\n return { leaking, slopePerMin }\n}\n","import type {\n ForcedReflowSignal,\n InteractionSignal,\n LongTaskSignal,\n RenderSignal,\n Signal,\n StackFrame,\n} from './types'\n\n/** One frame at 60fps. A commit's `at` is sampled when it completes (after its\n * layout effects), so a reflow forced during that commit finishes up to ~a\n * frame before the commit is timestamped. */\nconst FRAME_MS = 16\n\nexport type AnchorSignal = InteractionSignal | LongTaskSignal\n\n/** How strongly a member is linked to its episode anchor. `caused` means a\n * member's source location matches one of the anchor's hot frames — a real\n * causal claim. `co-occurred` means it only overlapped in time; the link is\n * temporal, not proven. The distinction keeps the tool from overclaiming. */\nexport type LinkConfidence = 'caused' | 'co-occurred'\n\n/** Which slice of an interaction's INP latency a member fell into. Only set\n * for interaction-anchored episodes; long tasks have no phase breakdown. */\nexport type InpPhase = 'input-delay' | 'processing' | 'presentation'\n\n/** Signals that carry an `at` timestamp and can be nested inside an episode.\n * Excludes the anchors themselves and signals with no point in time\n * (web-vital has no `at`; network uses `startedAt`). */\ntype MemberSignal = Exclude<Extract<Signal, { at: number }>, AnchorSignal>\n\n/** The render commit a forced reflow happened inside — the component whose\n * commit forced the synchronous layout. Set when the reflow's timestamp falls\n * within a render commit's window. */\nexport type CommitCause = {\n commitId: number\n component: string\n}\n\nexport type EpisodeMember = {\n signal: MemberSignal\n confidence: LinkConfidence\n phase?: InpPhase\n causedBy?: CommitCause\n}\n\nexport type Episode = {\n anchor: AnchorSignal\n members: EpisodeMember[]\n}\n\nfunction isAnchor(signal: Signal): signal is AnchorSignal {\n return signal.kind === 'interaction' || signal.kind === 'long-task'\n}\n\nfunction sourceKey(frame: StackFrame): string {\n return `${frame.file}:${frame.line}`\n}\n\nfunction anchorHotLocations(anchor: AnchorSignal): Set<string> {\n return new Set((anchor.attribution ?? []).map((a) => sourceKey(a.frame)))\n}\n\nfunction isMember(s: Signal, anchor: AnchorSignal): s is MemberSignal {\n return s !== anchor && s.kind !== 'interaction' && s.kind !== 'long-task' && 'at' in s\n}\n\nfunction linkConfidence(signal: MemberSignal, hotLocations: Set<string>): LinkConfidence {\n if (signal.kind === 'forced-reflow') {\n if (signal.stack.some((f) => hotLocations.has(sourceKey(f)))) return 'caused'\n }\n return 'co-occurred'\n}\n\n/** Finds the render commit that forced a reflow. A render signal's `at` is\n * sampled when the commit completes — *after* its layout effects, where forced\n * reflows happen — and its `duration` covers only the render phase, not the\n * layout work. So the triggering commit is the one that completes at or just\n * after the reflow (within a frame of the reflow finishing), not one whose\n * narrow render-phase window contains it. */\nfunction commitForReflow(reflow: ForcedReflowSignal, renders: RenderSignal[]): RenderSignal | undefined {\n const reflowEnd = reflow.at + reflow.duration\n return renders.find((r) => r.at >= reflow.at && r.at <= reflowEnd + FRAME_MS)\n}\n\nfunction inpPhaseAt(anchor: AnchorSignal, at: number): InpPhase | undefined {\n if (anchor.kind !== 'interaction') return undefined\n const processingStart = anchor.at + anchor.inputDelay\n const presentationStart = processingStart + anchor.processing\n if (at < processingStart) return 'input-delay'\n if (at < presentationStart) return 'processing'\n return 'presentation'\n}\n\nexport function correlate(signals: Signal[]): Episode[] {\n const anchors = signals.filter(isAnchor)\n\n return anchors.map((anchor) => {\n const start = anchor.at\n const end = anchor.at + anchor.duration\n const hotLocations = anchorHotLocations(anchor)\n const windowed = signals.filter(\n (s): s is MemberSignal => isMember(s, anchor) && s.at >= start && s.at <= end,\n )\n const renders = windowed.filter((s): s is RenderSignal => s.kind === 'render')\n\n const members = windowed.map((signal) => {\n const member: EpisodeMember = {\n signal,\n confidence: linkConfidence(signal, hotLocations),\n phase: inpPhaseAt(anchor, signal.at),\n }\n if (signal.kind === 'forced-reflow') {\n const commit = commitForReflow(signal, renders)\n if (commit) {\n member.confidence = 'caused'\n member.causedBy = { commitId: commit.commitId, component: commit.component }\n }\n }\n return member\n })\n\n return { anchor, members }\n })\n}\n","import type { Collector, LongTaskScript, Signal } from '../types'\n\nconst LOAF = 'long-animation-frame'\nconst LEGACY = 'longtask'\n\n/** A single script entry inside a Long Animation Frame. */\ninterface ScriptTiming {\n duration?: number\n invoker?: string\n invokerType?: string\n sourceURL?: string\n sourceFunctionName?: string\n sourceCharPosition?: number\n}\n\ninterface LoAFEntry extends PerformanceEntry {\n blockingDuration?: number\n scripts?: ScriptTiming[]\n}\n\nfunction supportsLoAF(): boolean {\n const PO = (globalThis as { PerformanceObserver?: { supportedEntryTypes?: readonly string[] } })\n .PerformanceObserver\n const types = PO?.supportedEntryTypes\n return Array.isArray(types) && types.includes(LOAF)\n}\n\nfunction mapScripts(scripts: ScriptTiming[]): LongTaskScript[] {\n return scripts.map((s) => ({\n invokerType: s.invokerType ?? 'unknown',\n invoker: s.invoker ?? '',\n sourceURL: s.sourceURL ?? '',\n sourceFunctionName: s.sourceFunctionName ?? '',\n charPosition: typeof s.sourceCharPosition === 'number' ? s.sourceCharPosition : -1,\n duration: typeof s.duration === 'number' ? s.duration : 0,\n }))\n}\n\nexport function createLongTasksCollector(): Collector {\n let observer: PerformanceObserver | null = null\n let active = false\n\n return {\n kind: 'long-task',\n activate(emit: (signal: Signal) => void) {\n if (typeof PerformanceObserver === 'undefined') {\n console.warn('[react-perfscope] PerformanceObserver not supported; long-tasks disabled')\n return\n }\n active = true\n const useLoAF = supportsLoAF()\n try {\n observer = new PerformanceObserver((list) => {\n if (!active) return\n for (const entry of list.getEntries()) {\n if (useLoAF) {\n const loaf = entry as LoAFEntry\n const scripts = Array.isArray(loaf.scripts) ? mapScripts(loaf.scripts) : []\n emit({\n kind: 'long-task',\n at: entry.startTime,\n duration: entry.duration,\n stack: [],\n scripts,\n ...(typeof loaf.blockingDuration === 'number'\n ? { blockingDuration: loaf.blockingDuration }\n : {}),\n })\n } else {\n emit({\n kind: 'long-task',\n at: entry.startTime,\n duration: entry.duration,\n stack: [],\n })\n }\n }\n })\n observer.observe({ type: useLoAF ? LOAF : LEGACY, buffered: false })\n } catch (err) {\n console.warn('[react-perfscope] long-tasks collector failed to start:', err)\n observer = null\n active = false\n }\n },\n deactivate() {\n active = false\n if (observer) {\n try {\n observer.disconnect()\n } catch {\n // ignore\n }\n observer = null\n }\n },\n }\n}\n","import type { Collector, Signal } from '../types'\nimport { attachLazyStack } from '../sourcemap'\n\nconst LAYOUT_GETTERS = [\n 'offsetWidth',\n 'offsetHeight',\n 'offsetLeft',\n 'offsetTop',\n 'clientWidth',\n 'clientHeight',\n 'scrollWidth',\n 'scrollHeight',\n] as const\n\nconst LAYOUT_METHODS = ['getBoundingClientRect', 'getClientRects'] as const\n\ntype SavedDescriptor = {\n proto: object\n key: string\n descriptor: PropertyDescriptor\n}\n\ntype OpenGroup = {\n at: number\n duration: number\n count: number\n rawStack: string | undefined\n}\n\n// Close the coalescing window at the end of the current synchronous turn.\n// queueMicrotask runs after the running task drains, so a layout-thrash loop\n// (read offsetWidth N times in one turn) collapses into a single group.\nconst scheduleFlush: (cb: () => void) => void =\n typeof queueMicrotask === 'function'\n ? queueMicrotask\n : typeof Promise !== 'undefined'\n ? (cb) => {\n Promise.resolve().then(cb)\n }\n : (cb) => cb()\n\nexport function createForcedReflowCollector(): Collector {\n let active = false\n let emit: (s: Signal) => void = () => {}\n const saved: SavedDescriptor[] = []\n let mutationObserver: MutationObserver | null = null\n let group: OpenGroup | null = null\n\n function consumePendingMutations(): boolean {\n if (!mutationObserver) {\n // Fallback when MutationObserver isn't available: always treat as dirty\n // (Phase 1 over-report behavior).\n return true\n }\n return mutationObserver.takeRecords().length > 0\n }\n\n function flush() {\n if (!group) return\n const g = group\n group = null\n const signal = {\n kind: 'forced-reflow' as const,\n at: g.at,\n duration: g.duration,\n count: g.count,\n } as unknown as Signal\n attachLazyStack(signal, g.rawStack, 1)\n emit(signal)\n }\n\n // A layout read happened while recording and layout was dirty. Open a group\n // on the first such read of the turn, then just accumulate count/duration for\n // the rest of the turn. `rawStack` is captured by the caller (the patched\n // accessor) so the stack's top user frame stays at a fixed depth — passing it\n // through a helper would add a frame and misattribute the reflow to this file.\n function record(at: number, duration: number, rawStack: string | undefined) {\n if (group) {\n group.count++\n group.duration += duration\n return\n }\n group = { at, duration, count: 1, rawStack }\n scheduleFlush(flush)\n }\n\n // True when the next dirty read opens a fresh group and so needs a stack.\n // Lets the accessor skip `new Error().stack` (the dominant cost) on the\n // subsequent reads it coalesces into an already-open group.\n function needsStack(): boolean {\n return group === null\n }\n\n function patchGetter(proto: object, key: string) {\n if (typeof proto !== 'object' || proto === null) return\n const desc = Object.getOwnPropertyDescriptor(proto, key)\n if (!desc || !desc.get) return\n saved.push({ proto, key, descriptor: desc })\n const originalGet = desc.get\n Object.defineProperty(proto, key, {\n configurable: true,\n get(this: unknown) {\n if (active) {\n if (!consumePendingMutations()) {\n return originalGet.call(this)\n }\n const rawStack = needsStack() ? new Error().stack : undefined\n const at = performance.now()\n const value = originalGet.call(this)\n record(at, performance.now() - at, rawStack)\n return value\n }\n return originalGet.call(this)\n },\n set: desc.set,\n })\n }\n\n function patchMethod(proto: object, key: string) {\n if (typeof proto !== 'object' || proto === null) return\n const desc = Object.getOwnPropertyDescriptor(proto, key)\n if (!desc || typeof desc.value !== 'function') return\n saved.push({ proto, key, descriptor: desc })\n const original = desc.value as (...args: unknown[]) => unknown\n Object.defineProperty(proto, key, {\n configurable: true,\n writable: true,\n value: function patchedLayoutMethod(this: unknown, ...args: unknown[]) {\n if (active) {\n if (!consumePendingMutations()) {\n return original.apply(this, args)\n }\n const rawStack = needsStack() ? new Error().stack : undefined\n const at = performance.now()\n const value = original.apply(this, args)\n record(at, performance.now() - at, rawStack)\n return value\n }\n return original.apply(this, args)\n },\n })\n }\n\n return {\n kind: 'forced-reflow',\n activate(emitFn) {\n if (active) return\n emit = emitFn\n active = true\n\n if (typeof MutationObserver !== 'undefined' && typeof document !== 'undefined') {\n try {\n mutationObserver = new MutationObserver(() => {})\n mutationObserver.observe(document, {\n attributes: true,\n childList: true,\n subtree: true,\n characterData: true,\n })\n } catch (err) {\n console.warn('[react-perfscope] forced-reflow MutationObserver failed:', err)\n mutationObserver = null\n }\n }\n\n if (typeof HTMLElement !== 'undefined') {\n for (const key of LAYOUT_GETTERS) {\n patchGetter(HTMLElement.prototype, key)\n }\n }\n if (typeof Element !== 'undefined') {\n for (const key of LAYOUT_METHODS) {\n patchMethod(Element.prototype, key)\n }\n }\n },\n deactivate() {\n if (!active) return\n active = false\n // Emit any group still open before the scheduled microtask runs, so the\n // last burst isn't lost when stop() is called mid-turn.\n flush()\n if (mutationObserver) {\n try {\n mutationObserver.disconnect()\n } catch {\n // ignore\n }\n mutationObserver = null\n }\n for (const { proto, key, descriptor } of saved) {\n Object.defineProperty(proto, key, descriptor)\n }\n saved.length = 0\n },\n }\n}\n","import type { Collector, Signal } from '../types'\n\ninterface LayoutShiftSource {\n currentRect: DOMRect\n previousRect?: DOMRect\n node?: Node | null\n}\n\ninterface LayoutShiftEntryLike extends PerformanceEntry {\n value: number\n hadRecentInput: boolean\n sources?: LayoutShiftSource[]\n}\n\nconst PERFSCOPE_HOST_ATTR = 'data-perfscope-host'\n\nfunction rectsOverlap(a: DOMRect, b: DOMRect, tolerance = 0): boolean {\n return !(\n a.x + a.width < b.x - tolerance ||\n b.x + b.width < a.x - tolerance ||\n a.y + a.height < b.y - tolerance ||\n b.y + b.height < a.y - tolerance\n )\n}\n\n/**\n * Returns true when every source in the entry is part of our floating\n * widget. We want to ignore shifts caused by the perfscope UI itself.\n *\n * Detection has two paths:\n * 1. Node-based: walk up `source.node` looking for `[data-perfscope-host]`.\n * Works when the node is in light DOM.\n * 2. Rect-based fallback: compare `source.currentRect` against every host\n * element's bounding rect. This catches the Shadow-DOM case where the\n * browser doesn't expose the inner node (Shadow root boundary).\n */\nfunction collectPerfscopeRects(): DOMRect[] {\n const hosts = Array.from(document.querySelectorAll(`[${PERFSCOPE_HOST_ATTR}]`))\n const rects: DOMRect[] = []\n for (const h of hosts) {\n // The light-DOM host element usually has height 0 because Shadow DOM\n // content isn't part of its layout. We need to peek inside the shadow\n // root and collect bounds of any positioned children.\n const sr = (h as Element & { shadowRoot?: ShadowRoot | null }).shadowRoot\n if (sr) {\n for (const child of Array.from(sr.children)) {\n const r = (child as Element).getBoundingClientRect()\n if (r.width > 0 && r.height > 0) rects.push(r)\n }\n } else {\n const r = h.getBoundingClientRect()\n if (r.width > 0 && r.height > 0) rects.push(r)\n }\n }\n return rects\n}\n\nfunction entryIsOnlyFromPerfscope(sources: LayoutShiftSource[]): boolean {\n if (sources.length === 0) return false\n if (typeof document === 'undefined') return false\n\n const hostRects = collectPerfscopeRects()\n if (hostRects.length === 0) return false\n\n for (const src of sources) {\n let matched = false\n const node = src.node as (Node & { closest?: (sel: string) => Element | null }) | null | undefined\n if (node) {\n // Node-based check\n if (typeof (node as { closest?: unknown }).closest === 'function') {\n if ((node as Element).closest(`[${PERFSCOPE_HOST_ATTR}]`)) matched = true\n } else {\n let parent: (Element | null) = (node as Node).parentElement as Element | null\n while (parent) {\n if (parent.hasAttribute(PERFSCOPE_HOST_ATTR)) { matched = true; break }\n parent = parent.parentElement\n }\n }\n }\n // Rect-based fallback (shadow DOM): if source rect overlaps any of our\n // host rects, consider it our widget. Tolerance covers the case where\n // the widget changes size during the shift (its previous/current bounds\n // differ but both sit in the same screen corner).\n if (!matched) {\n for (const hostRect of hostRects) {\n if (rectsOverlap(src.currentRect, hostRect, 24)) {\n matched = true\n break\n }\n }\n }\n if (!matched) return false\n }\n return true\n}\n\nexport function createLayoutShiftCollector(): Collector {\n let observer: PerformanceObserver | null = null\n let active = false\n\n return {\n kind: 'layout-shift',\n activate(emit: (signal: Signal) => void) {\n if (typeof PerformanceObserver === 'undefined') {\n console.warn('[react-perfscope] PerformanceObserver not supported; layout-shift disabled')\n return\n }\n active = true\n try {\n observer = new PerformanceObserver((list) => {\n if (!active) return\n for (const raw of list.getEntries()) {\n const entry = raw as LayoutShiftEntryLike\n // Note: production CLS metrics exclude shifts with hadRecentInput\n // (user-initiated movements are considered intentional). For a\n // dev tool, the user explicitly WANTS to see what their clicks\n // caused — so we report these too.\n const sources = entry.sources ?? []\n if (entryIsOnlyFromPerfscope(sources)) continue\n // Convert viewport-relative rects to document-relative coords so\n // overlays stay anchored to the shifted DOM position when the\n // user scrolls. Filter above runs first on viewport coords (our\n // widget is position:fixed, lives in viewport space).\n const sx = (typeof window !== 'undefined' && window.scrollX) || 0\n const sy = (typeof window !== 'undefined' && window.scrollY) || 0\n const toDocRect = (r: DOMRect) =>\n new DOMRect(r.x + sx, r.y + sy, r.width, r.height)\n const rects = sources.map((s) => toDocRect(s.currentRect))\n // previousRect is undefined when the element was newly inserted.\n // An \"empty\" rect (w=0, h=0) likewise means there was no prior\n // box — treat both as `null` so the overlay can decide not to\n // draw an arrow for these.\n const prevRects: (DOMRect | null)[] = sources.map((s) => {\n const pr = s.previousRect\n if (!pr) return null\n if (pr.width === 0 && pr.height === 0) return null\n return toDocRect(pr)\n })\n emit({\n kind: 'layout-shift',\n at: entry.startTime,\n value: entry.value,\n sources: rects,\n previousSources: prevRects,\n })\n }\n })\n observer.observe({ type: 'layout-shift', buffered: false })\n } catch (err) {\n console.warn('[react-perfscope] layout-shift collector failed to start:', err)\n observer = null\n active = false\n }\n },\n deactivate() {\n active = false\n if (observer) {\n try {\n observer.disconnect()\n } catch {\n // ignore\n }\n observer = null\n }\n },\n }\n}\n","import type { Collector, Signal } from '../types'\nimport { isSelfRequest } from '../self-requests'\n\ninterface ResourceTimingLike extends PerformanceEntry {\n transferSize?: number\n renderBlockingStatus?: 'blocking' | 'non-blocking'\n}\n\nexport function createNetworkCollector(): Collector {\n let observer: PerformanceObserver | null = null\n let active = false\n\n return {\n kind: 'network',\n activate(emit: (signal: Signal) => void) {\n if (typeof PerformanceObserver === 'undefined') {\n console.warn('[react-perfscope] PerformanceObserver not supported; network disabled')\n return\n }\n active = true\n try {\n observer = new PerformanceObserver((list) => {\n if (!active) return\n for (const raw of list.getEntries()) {\n const entry = raw as ResourceTimingLike\n // Skip react-perfscope's own traffic (source-map fetches).\n if (isSelfRequest(entry.name)) continue\n emit({\n kind: 'network',\n url: entry.name,\n startedAt: entry.startTime,\n duration: entry.duration,\n size: entry.transferSize ?? 0,\n blocking: entry.renderBlockingStatus === 'blocking',\n })\n }\n })\n observer.observe({ type: 'resource', buffered: false })\n } catch (err) {\n console.warn('[react-perfscope] network collector failed to start:', err)\n observer = null\n active = false\n }\n },\n deactivate() {\n active = false\n if (observer) {\n try {\n observer.disconnect()\n } catch {\n // ignore\n }\n observer = null\n }\n },\n }\n}\n","import { onLCP, onINP, onCLS, onFCP, onTTFB, type Metric } from 'web-vitals'\nimport type { Collector, Signal, WebVitalSignal } from '../types'\n\ntype VitalName = WebVitalSignal['name']\ntype Sink = (name: VitalName, value: number) => void\n\n// The web-vitals library exposes no unsubscribe, and some metrics (LCP, FCP,\n// TTFB) only report once per page — so the module subscribes exactly once and\n// fans metrics out to whichever collector instances are currently active.\n// Per-instance subscriptions would both leak permanent handlers on every new\n// recorder and starve later instances of already-finalized metrics.\nlet subscribed = false\nconst sinks = new Set<Sink>()\n\nfunction ensureSubscribed(): boolean {\n if (subscribed) return true\n try {\n const fan = (name: VitalName) => (metric: Metric) => {\n for (const sink of sinks) sink(name, metric.value)\n }\n onLCP(fan('LCP'))\n onINP(fan('INP'))\n onCLS(fan('CLS'))\n onFCP(fan('FCP'))\n onTTFB(fan('TTFB'))\n subscribed = true\n } catch (err) {\n console.warn('[react-perfscope] web-vitals collector failed to subscribe:', err)\n }\n return subscribed\n}\n\nexport function createWebVitalsCollector(): Collector {\n let emit: (signal: Signal) => void = () => {}\n const sink: Sink = (name, value) => {\n emit({ kind: 'web-vital', name, value })\n }\n\n return {\n kind: 'web-vital',\n activate(emitFn) {\n if (!ensureSubscribed()) return\n emit = emitFn\n sinks.add(sink)\n },\n deactivate() {\n sinks.delete(sink)\n },\n }\n}\n","import type {\n Collector,\n HeapSample,\n HeapTrend,\n HeapTrendClass,\n RecordingResult,\n} from '../types'\n\n/** How often to read heap usage while recording. Reading performance.memory\n * is cheap, so we sample at 4Hz: a 1s cadence is too coarse — short spikes fall\n * between samples and the line, drawn straight between sparse points, smooths\n * them into a ramp. 250ms localizes spikes without meaningful overhead. */\nconst SAMPLE_INTERVAL_MS = 250\n/** Cap on retained samples so a multi-hour session can't grow the array\n * unbounded. At 250ms this is ~83 min; past that, oldest samples drop. */\nconst MAX_SAMPLES = 20_000\n\n/** Below this, a trend can't be estimated reliably. */\nconst MIN_SAMPLES = 4\n/** How many contiguous segments to split the series into when estimating the\n * floor. Each segment contributes its minimum (the post-GC trough). */\nconst FLOOR_SEGMENTS = 8\n\nconst MB = 1024 * 1024\n/** Floor-growth thresholds, in bytes per minute. */\nconst GROWING_SLOPE = 1 * MB\nconst LEAK_SLOPE = 5 * MB\n/** A rate alone isn't enough: over a short recording, a sub-megabyte wobble in\n * the floor extrapolates to a huge MB/min and would false-positive. Require the\n * floor to have actually risen by at least this much across the window before\n * calling anything growing/leaking. */\nconst MIN_NET_GROWTH = 2 * MB\n\ninterface MemoryInfo {\n usedJSHeapSize: number\n totalJSHeapSize: number\n jsHeapSizeLimit: number\n}\n\nfunction readMemory(): MemoryInfo | null {\n const perf = (globalThis as { performance?: { memory?: MemoryInfo } }).performance\n const mem = perf?.memory\n if (!mem || typeof mem.usedJSHeapSize !== 'number') return null\n return mem\n}\n\n/**\n * Least-squares slope of points (x, y). Returns 0 when x has no spread\n * (vertical / single distinct x) to avoid a divide-by-zero blow-up.\n */\nfunction slope(points: { x: number; y: number }[]): number {\n const n = points.length\n if (n < 2) return 0\n let sx = 0\n let sy = 0\n let sxy = 0\n let sxx = 0\n for (const { x, y } of points) {\n sx += x\n sy += y\n sxy += x * y\n sxx += x * x\n }\n const denom = n * sxx - sx * sx\n if (denom === 0) return 0\n return (n * sxy - sx * sy) / denom\n}\n\n/**\n * Estimate whether memory is being retained across the recording.\n *\n * GC makes raw heap usage a sawtooth, so the peak is noisy. The reliable\n * signal is the *floor* — the post-GC troughs. We split the series into\n * contiguous segments, take the minimum of each (its trough), and regress\n * those minima against time.\n *\n * A rising overall slope is necessary but NOT sufficient: a one-time step\n * (heap warms up early, then plateaus) also regresses to a positive slope, and\n * flagging that as a leak is a false positive — the classic \"idle recording\n * reads abnormal\" bug. A real leak keeps climbing, so we additionally require\n * the *recent* half of the floor to still be rising. We also gate on a minimum\n * net growth, since over a short window a sub-MB wobble extrapolates to a steep\n * per-minute slope.\n *\n * Returns null when there are too few samples to say anything.\n */\nexport function analyzeHeapTrend(samples: HeapSample[]): HeapTrend | null {\n if (samples.length < MIN_SAMPLES) return null\n const t0 = samples[0]!.at\n const segSize = Math.max(1, Math.ceil(samples.length / FLOOR_SEGMENTS))\n const floorPoints: { x: number; y: number }[] = []\n for (let i = 0; i < samples.length; i += segSize) {\n const seg = samples.slice(i, i + segSize)\n let min = Infinity\n for (const s of seg) min = Math.min(min, s.used)\n const mid = seg[Math.floor(seg.length / 2)]!\n floorPoints.push({ x: (mid.at - t0) / 60000, y: min })\n }\n const slopeBytesPerMin = slope(floorPoints)\n const spanMin = (samples[samples.length - 1]!.at - t0) / 60000\n const projectedGrowth = slopeBytesPerMin * spanMin\n // Recent trend: is the floor still climbing in the latter half? Distinguishes\n // a sustained leak from a one-time step that has since plateaued.\n const recent = floorPoints.slice(Math.floor(floorPoints.length / 2))\n const recentSlope = recent.length >= 2 ? slope(recent) : slopeBytesPerMin\n\n let classification: HeapTrendClass = 'stable'\n const sustained = projectedGrowth >= MIN_NET_GROWTH && recentSlope >= GROWING_SLOPE\n if (sustained) {\n classification =\n slopeBytesPerMin >= LEAK_SLOPE && recentSlope >= LEAK_SLOPE ? 'leak-suspected' : 'growing'\n }\n return { classification, slopeBytesPerMin }\n}\n\nexport interface HeapCollector extends Collector {\n /** Attach the sampled heap series to the recording result. Returns the\n * input untouched when nothing was sampled (unsupported browser). */\n finalize(result: RecordingResult): RecordingResult\n}\n\n/**\n * Samples `performance.memory` on an interval for the duration of a recording\n * and attaches the series via `finalize`. It is a Collector so the recorder\n * drives its start/stop, but it emits no signals — the series is a separate\n * track (see RecordingResult.heapSamples), so a busy session's signal buffer\n * can't evict it. No-ops entirely when performance.memory is unavailable\n * (non-Chromium), leaving `heapSamples` absent so the UI can show a fallback.\n */\nexport function createHeapCollector(): HeapCollector {\n let samples: HeapSample[] = []\n let timer: ReturnType<typeof setInterval> | null = null\n\n function sample(): void {\n const mem = readMemory()\n if (!mem) return\n samples.push({ at: performance.now(), used: mem.usedJSHeapSize, total: mem.totalJSHeapSize })\n if (samples.length > MAX_SAMPLES) samples.splice(0, samples.length - MAX_SAMPLES)\n }\n\n return {\n kind: 'heap',\n activate() {\n samples = []\n if (!readMemory()) return // unsupported → never start the timer\n sample()\n timer = setInterval(sample, SAMPLE_INTERVAL_MS)\n },\n deactivate() {\n if (timer == null) return\n clearInterval(timer)\n timer = null\n sample() // one final reading at stop\n },\n finalize(result) {\n if (samples.length === 0) return result\n return { ...result, heapSamples: samples.slice() }\n },\n }\n}\n","import type { Collector, InteractionSignal, RecordingResult } from '../types'\n\n/** Event Timing only surfaces events at/over this duration (ms); 40ms keeps\n * trivial interactions out while still catching anything a user would feel. */\nconst DURATION_THRESHOLD = 40\n\n/** Each buffered entry retains its `target` DOM node, so the buffer must stay\n * bounded even during very long recordings. */\nconst MAX_ENTRIES = 5000\n\ninterface EventTimingEntry extends PerformanceEntry {\n processingStart: number\n processingEnd: number\n interactionId?: number\n target?: unknown\n}\n\nfunction selectorFor(target: unknown): string | undefined {\n const el = target as { tagName?: string; id?: string; className?: unknown } | null\n if (!el || typeof el.tagName !== 'string') return undefined\n let s = el.tagName.toLowerCase()\n if (el.id) s += `#${el.id}`\n else if (typeof el.className === 'string' && el.className.trim()) {\n s += `.${el.className.trim().split(/\\s+/)[0]}`\n }\n return s\n}\n\nfunction supportsEventTiming(): boolean {\n const PO = (globalThis as { PerformanceObserver?: { supportedEntryTypes?: readonly string[] } })\n .PerformanceObserver\n const types = PO?.supportedEntryTypes\n // happy-dom / older browsers may not expose supportedEntryTypes; if the\n // observer exists at all we still try, and observe() throwing is caught.\n return !types || types.includes('event')\n}\n\nexport interface InteractionCollector extends Collector {\n /** Group buffered Event Timing entries into one interaction each and append\n * them to the result. Returns the input untouched when none qualified. */\n finalize(result: RecordingResult): RecordingResult\n}\n\n/**\n * Records Event Timing entries during a recording and, on finalize, turns each\n * user interaction (grouped by interactionId) into one signal carrying the INP\n * latency breakdown: input delay → processing → presentation. The longest\n * event in a group defines the interaction's latency (matching how INP is\n * attributed). Emits no live signals — interactions are assembled at finalize,\n * then the self-profiling collector attributes the processing window to the\n * developer's hot functions.\n */\nexport function createInteractionCollector(): InteractionCollector {\n let active = false\n let observer: PerformanceObserver | null = null\n let entries: EventTimingEntry[] = []\n\n return {\n kind: 'interaction',\n activate() {\n if (typeof PerformanceObserver === 'undefined' || !supportsEventTiming()) return\n active = true\n entries = []\n try {\n observer = new PerformanceObserver((list) => {\n if (!active) return\n for (const e of list.getEntries()) {\n if (entries.length >= MAX_ENTRIES) break\n entries.push(e as EventTimingEntry)\n }\n })\n // `event` covers all interaction events; `first-input` guarantees the\n // first one even if it's under the duration threshold.\n observer.observe({ type: 'event', buffered: false, durationThreshold: DURATION_THRESHOLD } as PerformanceObserverInit)\n try {\n observer.observe({ type: 'first-input', buffered: false } as PerformanceObserverInit)\n } catch {\n // first-input not supported everywhere; the event stream is enough.\n }\n } catch (err) {\n console.warn('[react-perfscope] interaction collector failed to start:', err)\n observer = null\n active = false\n }\n },\n deactivate() {\n active = false\n if (observer) {\n try {\n observer.disconnect()\n } catch {\n // ignore\n }\n observer = null\n }\n },\n finalize(result) {\n // Consume the buffer: entries reference `target` DOM nodes, and the\n // recorder finalizes after stop — holding them past this point would\n // pin interacted (possibly detached) elements until the next recording.\n const buffered = entries\n entries = []\n const byId = new Map<number, EventTimingEntry[]>()\n for (const e of buffered) {\n const id = e.interactionId\n if (!id) continue // 0 / undefined → not part of a discrete interaction\n const group = byId.get(id)\n if (group) group.push(e)\n else byId.set(id, [e])\n }\n const interactions: InteractionSignal[] = []\n for (const group of byId.values()) {\n // All events of one interaction (pointerdown/up/click) report the same\n // `duration` (the whole interaction latency), so the breakdown can't\n // come from a single event. Span the processing across the group:\n // earliest processingStart → latest processingEnd (matches web-vitals).\n // The \"defining\" event for label/target is the one with the most\n // processing — typically the click/keydown that actually ran handlers.\n let duration = 0\n let startTime = Infinity\n let processingStart = Infinity\n let processingEnd = -Infinity\n let defining = group[0]!\n let maxProcessing = -Infinity\n for (const e of group) {\n if (e.duration > duration) duration = e.duration\n if (e.startTime < startTime) startTime = e.startTime\n if (e.processingStart < processingStart) processingStart = e.processingStart\n if (e.processingEnd > processingEnd) processingEnd = e.processingEnd\n const proc = e.processingEnd - e.processingStart\n if (proc > maxProcessing) {\n maxProcessing = proc\n defining = e\n }\n }\n if (duration < DURATION_THRESHOLD) continue\n const inputDelay = Math.max(0, processingStart - startTime)\n const processing = Math.max(0, processingEnd - processingStart)\n const presentation = Math.max(0, startTime + duration - processingEnd)\n interactions.push({\n kind: 'interaction',\n at: startTime,\n eventType: defining.name,\n ...(selectorFor(defining.target) ? { target: selectorFor(defining.target) } : {}),\n duration,\n inputDelay,\n processing,\n presentation,\n })\n }\n if (interactions.length === 0) return result\n interactions.sort((a, b) => a.at - b.at)\n return { ...result, signals: [...result.signals, ...interactions] }\n },\n }\n}\n","import type { Collector, FpsSample, FrameStats, RecordingResult } from '../types'\n\n/** 60fps frame budget (ms). Gaps are scored against this to count drops. */\nconst FRAME_BUDGET = 1000 / 60\n/** Window for the FPS series; 500ms smooths per-frame noise while still showing\n * a scroll-jank dip. */\nconst BUCKET_MS = 500\n/** A trailing window shorter than this is too small to estimate FPS reliably. */\nconst MIN_BUCKET_SPAN = 100\n/** Below this we can't say anything useful. */\nconst MIN_FRAMES = 8\n/** Cap retained frames so a long session can't grow the array unbounded\n * (~5.5 min at 60fps); past that, oldest drop. */\nconst MAX_FRAMES = 20_000\n\n/**\n * Turn raw requestAnimationFrame timestamps into a frame-rate picture:\n * a windowed FPS series, the lowest sustained FPS, the worst single hitch,\n * and an approximate dropped-frame count. Long tasks (>50ms) show up here as\n * big gaps, but so does sustained scroll jank (30–50ms frames) that the\n * long-task collector's threshold misses.\n *\n * Returns null when there are too few frames to analyze.\n */\nexport function analyzeFrames(frames: number[]): FrameStats | null {\n if (frames.length < MIN_FRAMES) return null\n\n let longestFrameMs = 0\n let droppedFrames = 0\n for (let i = 1; i < frames.length; i++) {\n const gap = frames[i]! - frames[i - 1]!\n if (gap > longestFrameMs) longestFrameMs = gap\n const dropped = Math.round(gap / FRAME_BUDGET) - 1\n if (dropped > 0) droppedFrames += dropped\n }\n\n const t0 = frames[0]!\n const end = frames[frames.length - 1]!\n const series: FpsSample[] = []\n let minFps = Infinity\n let idx = 0\n for (let bStart = t0; bStart < end; bStart += BUCKET_MS) {\n const bEnd = Math.min(bStart + BUCKET_MS, end)\n const span = bEnd - bStart\n let count = 0\n while (idx < frames.length && frames[idx]! < bEnd) {\n count++\n idx++\n }\n if (span < MIN_BUCKET_SPAN) break // skip a tiny trailing window\n const fps = count / (span / 1000)\n series.push({ at: bStart + span / 2, fps })\n if (fps < minFps) minFps = fps\n }\n if (series.length === 0) return null\n return { series, minFps, longestFrameMs, droppedFrames }\n}\n\nexport interface FrameCollector extends Collector {\n /** Attach the captured frame timestamps to the result. Returns the input\n * untouched when too few frames were seen (or rAF was unavailable). */\n finalize(result: RecordingResult): RecordingResult\n}\n\n/**\n * Records requestAnimationFrame timestamps for the duration of a recording so\n * the UI can chart frame rate and surface jank. Emits no signals — the\n * timestamps are a side track attached at finalize. No-ops when\n * requestAnimationFrame is unavailable (non-DOM environments).\n */\nexport function createFrameCollector(): FrameCollector {\n let active = false\n let rafId: number | null = null\n let frames: number[] = []\n\n function loop(t: number): void {\n if (!active) return\n frames.push(t)\n if (frames.length > MAX_FRAMES) frames.splice(0, frames.length - MAX_FRAMES)\n rafId = requestAnimationFrame(loop)\n }\n\n return {\n kind: 'frame',\n activate() {\n if (typeof requestAnimationFrame === 'undefined') return\n active = true\n frames = []\n rafId = requestAnimationFrame(loop)\n },\n deactivate() {\n active = false\n if (rafId != null && typeof cancelAnimationFrame !== 'undefined') {\n try {\n cancelAnimationFrame(rafId)\n } catch {\n // ignore\n }\n }\n rafId = null\n },\n finalize(result) {\n if (frames.length < MIN_FRAMES) return result\n return { ...result, frames: frames.slice() }\n },\n }\n}\n","import type { Collector, LongTaskAttribution, RecordingResult, Signal, StackFrame } from '../types'\n\n/**\n * JS Self-Profiling API trace shape (the subset we consume).\n * @see https://wicg.github.io/js-self-profiling/\n */\nexport interface ProfilerFrame {\n name?: string\n resourceId?: number\n line?: number\n column?: number\n}\nexport interface ProfilerStack {\n frameId: number\n parentId?: number\n}\nexport interface ProfilerSample {\n /** DOMHighResTimeStamp, same clock as performance.now() / entry.startTime. */\n timestamp: number\n stackId?: number\n}\nexport interface ProfilerTrace {\n resources: string[]\n frames: ProfilerFrame[]\n stacks: ProfilerStack[]\n samples: ProfilerSample[]\n}\n\ninterface ProfilerInstance {\n stop(): Promise<ProfilerTrace>\n}\ninterface ProfilerCtor {\n new (opts: { sampleInterval: number; maxBufferSize: number }): ProfilerInstance\n}\n\n/** Default sampling cadence. The browser may coarsen this. */\nconst SAMPLE_INTERVAL_MS = 10\nconst MAX_BUFFER_SIZE = 100_000\n/** Keep the noisiest few; deeper tails rarely help the developer. */\nconst MAX_FRAMES_PER_TASK = 5\n\n/**\n * Whether a resource URL belongs to the developer's own source (vs. a\n * dependency or tooling shim). Dependency frames are noise when the question\n * is \"which of MY functions is slow\".\n */\nexport function isUserResource(url: string | undefined): boolean {\n if (!url) return false\n if (url.includes('/node_modules/')) return false\n // Vite/dev tooling virtual modules: /@vite/client, /@react-refresh, /@id/...\n try {\n const path = new URL(url).pathname\n if (path.startsWith('/@')) return false\n } catch {\n if (url.startsWith('/@')) return false\n }\n return true\n}\n\nfunction frameToStackFrame(trace: ProfilerTrace, frame: ProfilerFrame): StackFrame {\n const file = frame.resourceId != null ? (trace.resources[frame.resourceId] ?? '') : ''\n const sf: StackFrame = {\n file,\n line: frame.line ?? 0,\n col: frame.column ?? 0,\n }\n if (frame.name) sf.fnName = frame.name\n return sf\n}\n\n/**\n * Climb a sample's stack from the leaf toward the root, returning the first\n * (deepest) frame that lives in user source. That frame is where the\n * developer's own code was actually executing when the sample was taken.\n */\nfunction leafUserFrame(trace: ProfilerTrace, stackId: number | undefined): ProfilerFrame | null {\n let id = stackId\n let guard = 0\n while (id != null && guard++ < 1000) {\n const stack = trace.stacks[id]\n if (!stack) break\n const frame = trace.frames[stack.frameId]\n if (frame && isUserResource(trace.resources[frame.resourceId ?? -1])) {\n return frame\n }\n id = stack.parentId\n }\n return null\n}\n\n/**\n * Aggregate the hottest user-source frames among samples whose timestamp\n * falls in [start, end]. `selfRatio` is relative to ALL in-window samples\n * (including vendor-only ones), so it reflects the share of the task's\n * blocking time spent in that user function.\n */\nexport function attributeWindow(\n trace: ProfilerTrace,\n start: number,\n end: number\n): LongTaskAttribution[] {\n let total = 0\n const counts = new Map<string, { frame: StackFrame; count: number }>()\n for (const sample of trace.samples) {\n if (sample.timestamp < start || sample.timestamp > end) continue\n total++\n const frame = leafUserFrame(trace, sample.stackId)\n if (!frame) continue\n const sf = frameToStackFrame(trace, frame)\n const key = `${sf.file}:${sf.line}:${sf.col}:${sf.fnName ?? ''}`\n const entry = counts.get(key)\n if (entry) entry.count++\n else counts.set(key, { frame: sf, count: 1 })\n }\n if (total === 0) return []\n return [...counts.values()]\n .sort((a, b) => b.count - a.count)\n .slice(0, MAX_FRAMES_PER_TASK)\n .map(({ frame, count }) => ({ frame, selfRatio: count / total, sampleCount: count }))\n}\n\n/**\n * Return a copy of `signals` with each long-task signal enriched with the\n * hottest user frames sampled during its window. Long tasks with no in-window\n * user samples are left without `attribution`. Non-long-task signals pass\n * through by reference.\n */\nexport function attributeLongTaskSignals(trace: ProfilerTrace, signals: Signal[]): Signal[] {\n return signals.map((signal) => {\n if (signal.kind !== 'long-task') return signal\n const attribution = attributeWindow(trace, signal.at, signal.at + signal.duration)\n if (attribution.length === 0) return signal\n return { ...signal, attribution }\n })\n}\n\n/**\n * Like {@link attributeLongTaskSignals} but for interactions: attributes the\n * *processing* window (handlers running, `[at+inputDelay, +processing]`) to the\n * developer's hot functions — answering \"which of my code made this click\n * slow\". Input delay and presentation aren't JS-on-the-stack, so they're\n * excluded from the window.\n */\nexport function attributeInteractionSignals(trace: ProfilerTrace, signals: Signal[]): Signal[] {\n return signals.map((signal) => {\n if (signal.kind !== 'interaction') return signal\n const start = signal.at + signal.inputDelay\n const attribution = attributeWindow(trace, start, start + signal.processing)\n if (attribution.length === 0) return signal\n return { ...signal, attribution }\n })\n}\n\ninterface SelfProfilingCollector extends Collector {\n /** Stop the profiler (if running), await its trace, and return a result\n * with long-task signals enriched. Falls back to the input on any failure\n * or when the Profiler API / Document-Policy header is unavailable. */\n finalize(result: RecordingResult): Promise<RecordingResult>\n}\n\n/**\n * Collector that runs the JS Self-Profiling API across a recording and, on\n * finalize, attributes each long task to the developer's own hot functions —\n * something LoAF can't do for React-delegated events (it only sees React's\n * single root dispatcher).\n *\n * It reports `kind: 'long-task'` because it enriches that signal rather than\n * emitting its own. Requires Chromium + a `Document-Policy: js-profiling`\n * response header (the dev plugins inject it); degrades to a no-op otherwise.\n */\nexport function createSelfProfilingCollector(): SelfProfilingCollector {\n let profiler: ProfilerInstance | null = null\n let tracePromise: Promise<ProfilerTrace> | null = null\n\n return {\n kind: 'long-task',\n activate() {\n tracePromise = null\n const Ctor = (globalThis as { Profiler?: ProfilerCtor }).Profiler\n if (typeof Ctor !== 'function') return\n try {\n profiler = new Ctor({ sampleInterval: SAMPLE_INTERVAL_MS, maxBufferSize: MAX_BUFFER_SIZE })\n } catch (err) {\n // Thrown when the Document-Policy: js-profiling header is absent.\n console.warn(\n '[react-perfscope] self-profiling unavailable (needs Document-Policy: js-profiling header); long tasks keep LoAF-only attribution:',\n err\n )\n profiler = null\n }\n },\n deactivate() {\n if (!profiler) return\n try {\n tracePromise = profiler.stop()\n } catch (err) {\n console.warn('[react-perfscope] self-profiling stop failed:', err)\n tracePromise = null\n }\n profiler = null\n },\n async finalize(result: RecordingResult): Promise<RecordingResult> {\n if (!tracePromise) return result\n try {\n const trace = await tracePromise\n const signals = attributeInteractionSignals(trace, attributeLongTaskSignals(trace, result.signals))\n return { ...result, signals }\n } catch (err) {\n console.warn('[react-perfscope] self-profiling finalize failed:', err)\n return result\n } finally {\n tracePromise = null\n }\n },\n }\n}\n"],"mappings":"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","names":["MIN_SAMPLES","FLOOR_SEGMENTS","MIN_NET_GROWTH","slope","SAMPLE_INTERVAL_MS"]}
package/dist/index.d.cts CHANGED
@@ -246,8 +246,9 @@ interface CreateSourceMapResolverOptions {
246
246
  /**
247
247
  * Create a SourceMap resolver that fetches `.map` files from the live URL
248
248
  * referenced in each source file's `//# sourceMappingURL=` directive.
249
- * Caches the parsed source map per source URL so repeated resolves against
250
- * the same file are O(1) after the first.
249
+ * Caches the DECODED TraceMap per source URL decoding the mappings is the
250
+ * expensive step, so repeated resolves against the same file are O(log n)
251
+ * lookups after the first.
251
252
  *
252
253
  * Returns the input frame on any failure (network error, missing map, etc.).
253
254
  */
package/dist/index.d.ts CHANGED
@@ -246,8 +246,9 @@ interface CreateSourceMapResolverOptions {
246
246
  /**
247
247
  * Create a SourceMap resolver that fetches `.map` files from the live URL
248
248
  * referenced in each source file's `//# sourceMappingURL=` directive.
249
- * Caches the parsed source map per source URL so repeated resolves against
250
- * the same file are O(1) after the first.
249
+ * Caches the DECODED TraceMap per source URL decoding the mappings is the
250
+ * expensive step, so repeated resolves against the same file are O(log n)
251
+ * lookups after the first.
251
252
  *
252
253
  * Returns the input frame on any failure (network error, missing map, etc.).
253
254
  */
package/dist/index.js CHANGED
@@ -88,23 +88,25 @@ function isSelfRequest(url) {
88
88
  // src/sourcemap.ts
89
89
  var CHROME_FRAME = /^\s*at\s+(?:(.+?)\s+\()?(.+?):(\d+):(\d+)\)?$/;
90
90
  var FIREFOX_FRAME = /^(.*?)@(.+?):(\d+):(\d+)$/;
91
+ function lookupFrame(tracer, frame) {
92
+ const pos = originalPositionFor(tracer, { line: frame.line, column: frame.col - 1 });
93
+ if (pos.source == null || pos.line == null || pos.column == null) {
94
+ return frame;
95
+ }
96
+ const resolved = {
97
+ file: pos.source,
98
+ line: pos.line,
99
+ col: pos.column + 1
100
+ };
101
+ if (pos.name) resolved.fnName = pos.name;
102
+ else if (frame.fnName) resolved.fnName = frame.fnName;
103
+ return resolved;
104
+ }
91
105
  async function resolveFrame(frame, fetchMap) {
92
106
  try {
93
107
  const map = await fetchMap(frame.file);
94
108
  if (!map) return frame;
95
- const tracer = new TraceMap(map);
96
- const pos = originalPositionFor(tracer, { line: frame.line, column: frame.col });
97
- if (pos.source == null || pos.line == null || pos.column == null) {
98
- return frame;
99
- }
100
- const resolved = {
101
- file: pos.source,
102
- line: pos.line,
103
- col: pos.column
104
- };
105
- if (pos.name) resolved.fnName = pos.name;
106
- else if (frame.fnName) resolved.fnName = frame.fnName;
107
- return resolved;
109
+ return lookupFrame(new TraceMap(map), frame);
108
110
  } catch (err) {
109
111
  console.warn("[react-perfscope] resolveFrame failed:", err);
110
112
  return frame;
@@ -127,7 +129,7 @@ function attachLazyStack(target, raw, skipTopFrames = 0) {
127
129
  function createSourceMapResolver(opts = {}) {
128
130
  const f = opts.fetch ?? (typeof fetch !== "undefined" ? fetch.bind(globalThis) : null);
129
131
  const cache = /* @__PURE__ */ new Map();
130
- function fetchMapFor(sourceUrl) {
132
+ function fetchTracerFor(sourceUrl) {
131
133
  if (!f) return Promise.resolve(null);
132
134
  const existing = cache.get(sourceUrl);
133
135
  if (existing) return existing;
@@ -146,13 +148,13 @@ function createSourceMapResolver(opts = {}) {
146
148
  const header = ref.slice(0, commaIdx);
147
149
  const payload = ref.slice(commaIdx + 1);
148
150
  const decoded = header.includes("base64") ? typeof atob === "function" ? atob(payload) : globalThis.Buffer.from(payload, "base64").toString("utf8") : decodeURIComponent(payload);
149
- return JSON.parse(decoded);
151
+ return new TraceMap(JSON.parse(decoded));
150
152
  }
151
153
  const mapUrl = new URL(ref, sourceUrl).href;
152
154
  markSelfRequest(mapUrl);
153
155
  const mapRes = await f(mapUrl);
154
156
  if (!mapRes || !mapRes.ok) return null;
155
- return await mapRes.json();
157
+ return new TraceMap(await mapRes.json());
156
158
  } catch {
157
159
  return null;
158
160
  }
@@ -163,7 +165,9 @@ function createSourceMapResolver(opts = {}) {
163
165
  return {
164
166
  async resolve(frame) {
165
167
  try {
166
- return await resolveFrame(frame, fetchMapFor);
168
+ const tracer = await fetchTracerFor(frame.file);
169
+ if (!tracer) return frame;
170
+ return lookupFrame(tracer, frame);
167
171
  } catch {
168
172
  return frame;
169
173
  }
@@ -720,37 +724,40 @@ function createNetworkCollector() {
720
724
 
721
725
  // src/collectors/web-vitals.ts
722
726
  import { onLCP, onINP, onCLS, onFCP, onTTFB } from "web-vitals";
727
+ var subscribed = false;
728
+ var sinks = /* @__PURE__ */ new Set();
729
+ function ensureSubscribed() {
730
+ if (subscribed) return true;
731
+ try {
732
+ const fan = (name) => (metric) => {
733
+ for (const sink of sinks) sink(name, metric.value);
734
+ };
735
+ onLCP(fan("LCP"));
736
+ onINP(fan("INP"));
737
+ onCLS(fan("CLS"));
738
+ onFCP(fan("FCP"));
739
+ onTTFB(fan("TTFB"));
740
+ subscribed = true;
741
+ } catch (err) {
742
+ console.warn("[react-perfscope] web-vitals collector failed to subscribe:", err);
743
+ }
744
+ return subscribed;
745
+ }
723
746
  function createWebVitalsCollector() {
724
- let active = false;
725
- let subscribed = false;
726
747
  let emit = () => {
727
748
  };
728
- function makeHandler(name) {
729
- return (metric) => {
730
- if (!active) return;
731
- emit({ kind: "web-vital", name, value: metric.value });
732
- };
733
- }
749
+ const sink = (name, value) => {
750
+ emit({ kind: "web-vital", name, value });
751
+ };
734
752
  return {
735
753
  kind: "web-vital",
736
754
  activate(emitFn) {
755
+ if (!ensureSubscribed()) return;
737
756
  emit = emitFn;
738
- active = true;
739
- if (subscribed) return;
740
- try {
741
- onLCP(makeHandler("LCP"));
742
- onINP(makeHandler("INP"));
743
- onCLS(makeHandler("CLS"));
744
- onFCP(makeHandler("FCP"));
745
- onTTFB(makeHandler("TTFB"));
746
- subscribed = true;
747
- } catch (err) {
748
- console.warn("[react-perfscope] web-vitals collector failed to subscribe:", err);
749
- active = false;
750
- }
757
+ sinks.add(sink);
751
758
  },
752
759
  deactivate() {
753
- active = false;
760
+ sinks.delete(sink);
754
761
  }
755
762
  };
756
763
  }
@@ -843,6 +850,7 @@ function createHeapCollector() {
843
850
 
844
851
  // src/collectors/interaction.ts
845
852
  var DURATION_THRESHOLD = 40;
853
+ var MAX_ENTRIES = 5e3;
846
854
  function selectorFor(target) {
847
855
  const el = target;
848
856
  if (!el || typeof el.tagName !== "string") return void 0;
@@ -871,7 +879,10 @@ function createInteractionCollector() {
871
879
  try {
872
880
  observer = new PerformanceObserver((list) => {
873
881
  if (!active) return;
874
- for (const e of list.getEntries()) entries.push(e);
882
+ for (const e of list.getEntries()) {
883
+ if (entries.length >= MAX_ENTRIES) break;
884
+ entries.push(e);
885
+ }
875
886
  });
876
887
  observer.observe({ type: "event", buffered: false, durationThreshold: DURATION_THRESHOLD });
877
888
  try {
@@ -895,8 +906,10 @@ function createInteractionCollector() {
895
906
  }
896
907
  },
897
908
  finalize(result) {
909
+ const buffered = entries;
910
+ entries = [];
898
911
  const byId = /* @__PURE__ */ new Map();
899
- for (const e of entries) {
912
+ for (const e of buffered) {
900
913
  const id = e.interactionId;
901
914
  if (!id) continue;
902
915
  const group = byId.get(id);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/recorder.ts","../src/sourcemap.ts","../src/self-requests.ts","../src/capabilities.ts","../src/leak-trend.ts","../src/correlate.ts","../src/collectors/long-tasks.ts","../src/collectors/forced-reflow.ts","../src/collectors/layout-shift.ts","../src/collectors/network.ts","../src/collectors/web-vitals.ts","../src/collectors/heap.ts","../src/collectors/interaction.ts","../src/collectors/frames.ts","../src/collectors/self-profiling.ts"],"sourcesContent":["import type { Collector, Recorder, RecordingResult, Signal } from './types'\n\n/** Hard cap on retained signals; the oldest are dropped past this. Exported so\n * downstream tests can assert the buffer never grows beyond it. */\nexport const BUFFER_CAP = 10_000\n\nexport interface InternalRecorder extends Recorder {\n __push: (signal: Signal) => void\n}\n\nexport function createRecorder(): Recorder {\n let recording = false\n let startedAt = 0\n let buffer: Signal[] = []\n const subscribers = new Set<(s: Signal) => void>()\n const collectors: Collector[] = []\n\n function notify(signal: Signal) {\n for (const cb of subscribers) {\n try {\n cb(signal)\n } catch (err) {\n console.warn('[react-perfscope] subscriber threw:', err)\n }\n }\n }\n\n function push(signal: Signal) {\n if (!recording) return\n buffer.push(signal)\n if (buffer.length > BUFFER_CAP) {\n buffer.splice(0, buffer.length - BUFFER_CAP)\n }\n notify(signal)\n }\n\n const recorder: InternalRecorder = {\n start() {\n if (recording) return\n recording = true\n startedAt = performance.now()\n buffer = []\n for (const c of collectors) {\n try {\n c.activate(push)\n } catch (err) {\n console.warn(`[react-perfscope] collector ${c.kind} failed to activate:`, err)\n }\n }\n },\n stop(): RecordingResult {\n if (!recording) {\n return { signals: [], startedAt: 0, duration: 0 }\n }\n for (const c of collectors) {\n try {\n c.deactivate()\n } catch (err) {\n console.warn(`[react-perfscope] collector ${c.kind} failed to deactivate:`, err)\n }\n }\n const duration = performance.now() - startedAt\n const result: RecordingResult = {\n signals: buffer.slice(),\n startedAt,\n duration,\n }\n recording = false\n buffer = []\n return result\n },\n isRecording() {\n return recording\n },\n onSignal(cb) {\n subscribers.add(cb)\n return () => subscribers.delete(cb)\n },\n use(collector) {\n collectors.push(collector)\n },\n __push: push,\n }\n return recorder\n}\n","import { TraceMap, originalPositionFor, type SourceMapInput } from '@jridgewell/trace-mapping'\nimport type { StackFrame } from './types'\nimport { markSelfRequest } from './self-requests'\n\nconst CHROME_FRAME = /^\\s*at\\s+(?:(.+?)\\s+\\()?(.+?):(\\d+):(\\d+)\\)?$/\nconst FIREFOX_FRAME = /^(.*?)@(.+?):(\\d+):(\\d+)$/\n\n/** A parsed source map (the JSON object), as returned by a FetchMap. */\nexport type RawSourceMap = SourceMapInput\n\nexport type FetchMap = (file: string) => Promise<RawSourceMap | null>\n\nexport async function resolveFrame(\n frame: StackFrame,\n fetchMap: FetchMap\n): Promise<StackFrame> {\n try {\n const map = await fetchMap(frame.file)\n if (!map) return frame\n // trace-mapping is pure JS (no wasm), so this works in the browser where\n // Mozilla's source-map SourceMapConsumer needs an explicitly-initialized\n // mappings.wasm. Columns are 0-based here, matching the captured frames.\n const tracer = new TraceMap(map)\n const pos = originalPositionFor(tracer, { line: frame.line, column: frame.col })\n if (pos.source == null || pos.line == null || pos.column == null) {\n return frame\n }\n const resolved: StackFrame = {\n file: pos.source,\n line: pos.line,\n col: pos.column,\n }\n if (pos.name) resolved.fnName = pos.name\n else if (frame.fnName) resolved.fnName = frame.fnName\n return resolved\n } catch (err) {\n console.warn('[react-perfscope] resolveFrame failed:', err)\n return frame\n }\n}\n\n/**\n * Attach a lazy `stack` getter to `target` that parses `raw` on first access\n * and memoizes the result. Use this from collectors to defer parseStack cost\n * until a consumer actually reads `signal.stack`.\n *\n * `skipTopFrames` drops the leading N parsed frames — useful for collectors\n * that wrap a patched function (the wrapper itself shows up as the topmost\n * frame, but it's noise from the user's perspective).\n */\nexport function attachLazyStack(\n target: object,\n raw: string | undefined,\n skipTopFrames = 0\n): void {\n let cached: StackFrame[] | null = null\n Object.defineProperty(target, 'stack', {\n enumerable: true,\n configurable: true,\n get() {\n if (cached === null) {\n const all = parseStack(raw)\n cached = skipTopFrames > 0 ? all.slice(skipTopFrames) : all\n }\n return cached\n },\n })\n}\n\nexport interface SourceMapResolver {\n /** Resolve a parsed StackFrame to its original source position. Falls back to the input frame on any failure. */\n resolve(frame: StackFrame): Promise<StackFrame>\n}\n\nexport interface CreateSourceMapResolverOptions {\n /** Override the global fetch. Useful for tests and non-browser environments. */\n fetch?: typeof globalThis.fetch\n}\n\n/**\n * Create a SourceMap resolver that fetches `.map` files from the live URL\n * referenced in each source file's `//# sourceMappingURL=` directive.\n * Caches the parsed source map per source URL so repeated resolves against\n * the same file are O(1) after the first.\n *\n * Returns the input frame on any failure (network error, missing map, etc.).\n */\nexport function createSourceMapResolver(opts: CreateSourceMapResolverOptions = {}): SourceMapResolver {\n const f = opts.fetch ?? (typeof fetch !== 'undefined' ? fetch.bind(globalThis) : null)\n const cache = new Map<string, Promise<RawSourceMap | null>>()\n\n function fetchMapFor(sourceUrl: string): Promise<RawSourceMap | null> {\n if (!f) return Promise.resolve(null)\n const existing = cache.get(sourceUrl)\n if (existing) return existing\n const promise = (async () => {\n try {\n markSelfRequest(sourceUrl)\n const res = await f(sourceUrl)\n if (!res || !res.ok) return null\n const text = await res.text()\n const m = text.match(/\\/\\/[#@]\\s*sourceMappingURL=(.+?)\\s*$/m)\n if (!m) return null\n const ref = m[1]!.trim()\n if (ref.startsWith('data:')) {\n const commaIdx = ref.indexOf(',')\n if (commaIdx === -1) return null\n const header = ref.slice(0, commaIdx)\n const payload = ref.slice(commaIdx + 1)\n const decoded = header.includes('base64')\n ? typeof atob === 'function'\n ? atob(payload)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n : (globalThis as any).Buffer.from(payload, 'base64').toString('utf8')\n : decodeURIComponent(payload)\n return JSON.parse(decoded) as RawSourceMap\n }\n const mapUrl = new URL(ref, sourceUrl).href\n markSelfRequest(mapUrl)\n const mapRes = await f(mapUrl)\n if (!mapRes || !mapRes.ok) return null\n return (await mapRes.json()) as RawSourceMap\n } catch {\n return null\n }\n })()\n cache.set(sourceUrl, promise)\n return promise\n }\n\n return {\n async resolve(frame) {\n try {\n return await resolveFrame(frame, fetchMapFor)\n } catch {\n return frame\n }\n },\n }\n}\n\nexport function parseStack(raw: string | undefined): StackFrame[] {\n if (!raw) return []\n const frames: StackFrame[] = []\n for (const line of raw.split('\\n')) {\n const chromeMatch = line.match(CHROME_FRAME)\n if (chromeMatch) {\n const [, fnName, file, lineStr, colStr] = chromeMatch\n const frame: StackFrame = {\n file: file ?? '',\n line: Number(lineStr),\n col: Number(colStr),\n }\n if (fnName) frame.fnName = fnName\n frames.push(frame)\n continue\n }\n const firefoxMatch = line.match(FIREFOX_FRAME)\n if (firefoxMatch) {\n const [, fnName, file, lineStr, colStr] = firefoxMatch\n const frame: StackFrame = {\n file: file ?? '',\n line: Number(lineStr),\n col: Number(colStr),\n }\n if (fnName) frame.fnName = fnName\n frames.push(frame)\n }\n }\n return frames\n}\n","// Registry of URLs that react-perfscope itself fetched (source files and their\n// source maps, when resolving stack frames). The network collector consults\n// this so the tool's own traffic never shows up as one of the app's network\n// signals — measuring shouldn't report the measurer.\n\nconst selfRequests = new Set<string>()\n\n/** Record that react-perfscope is about to fetch `url`, so the network\n * collector can exclude its resource-timing entry. */\nexport function markSelfRequest(url: string): void {\n selfRequests.add(url)\n}\n\n/** True when `url` was fetched by react-perfscope itself. */\nexport function isSelfRequest(url: string): boolean {\n return selfRequests.has(url)\n}\n","import type { SignalKind } from './types'\n\nexport type Capabilities = Record<SignalKind, boolean>\n\nfunction supportedEntryTypes(): readonly string[] | undefined {\n const PO = (globalThis as { PerformanceObserver?: { supportedEntryTypes?: readonly string[] } })\n .PerformanceObserver\n return PO?.supportedEntryTypes\n}\n\n/** True unless the browser exposes `supportedEntryTypes` AND it includes none of\n * the needed entry types. An unknown environment (older browsers / test envs\n * that don't expose the list) is treated as supported, so we never falsely\n * report a feature missing — the collector's own try/catch is the backstop. */\nfunction observerSupported(needed: readonly string[]): boolean {\n const types = supportedEntryTypes()\n if (!Array.isArray(types)) return true\n return needed.some((t) => types.includes(t))\n}\n\n/** Which signal kinds the current browser can actually measure. The render and\n * forced-reflow collectors are pure JS (React fibers / DOM-API instrumentation)\n * so they work everywhere; the rest depend on PerformanceObserver entry types\n * that Firefox and Safari do not implement (long tasks, layout shift, INP). */\nexport function detectCapabilities(): Capabilities {\n return {\n 'forced-reflow': true,\n render: true,\n 'web-vital': true,\n 'layout-shift': observerSupported(['layout-shift']),\n 'long-task': observerSupported(['long-animation-frame', 'longtask']),\n interaction: observerSupported(['event']),\n network: observerSupported(['resource']),\n }\n}\n\n/** Signal kinds the current browser cannot measure — for telling the user a\n * tab is empty because of the platform, not because nothing happened. */\nexport function unsupportedKinds(): SignalKind[] {\n const caps = detectCapabilities()\n return (Object.keys(caps) as SignalKind[]).filter((k) => !caps[k])\n}\n","/** One reading of how many unmounted instances of a component are still\n * retained (alive, not yet garbage-collected) at a point in time. */\nexport type LeakSample = { at: number; retained: number }\n\n/** Minimum samples before a trend can be estimated. */\nconst MIN_SAMPLES = 4\n/** Segments to split the series into when estimating the retained floor. */\nconst FLOOR_SEGMENTS = 8\n/** Require the retained floor to climb by at least this many instances across\n * the window before flagging — a transient one or two awaiting GC is not a\n * leak. */\nconst MIN_NET_GROWTH = 3\n\nfunction slope(points: { x: number; y: number }[]): number {\n const n = points.length\n if (n < 2) return 0\n let sx = 0\n let sy = 0\n let sxy = 0\n let sxx = 0\n for (const { x, y } of points) {\n sx += x\n sy += y\n sxy += x * y\n sxx += x * x\n }\n const denom = n * sxx - sx * sx\n if (denom === 0) return 0\n return (n * sxy - sx * sy) / denom\n}\n\n/**\n * Decide whether a component's retained-instance series indicates a leak.\n *\n * Mirrors {@link analyzeHeapTrend}: GC makes the raw retained count a sawtooth\n * (instances pile up, then a sweep collects a batch), so the reliable signal is\n * the *floor* — the post-GC troughs. We segment the series, take each segment's\n * minimum, and regress those minima against time.\n *\n * A rising slope alone is not enough: a one-time step (a screen mounts N\n * long-lived instances once, then plateaus) regresses positive but is not a\n * leak. So we additionally require the recent half of the floor to still be\n * rising, and gate on a minimum net growth in instances. This is what makes the\n * detector robust to React StrictMode's intentional mount→unmount→remount\n * churn, whose discarded fibers get collected and keep the floor flat.\n *\n * Returns null when there are too few samples to say anything.\n */\nexport function analyzeLeakTrend(\n samples: LeakSample[]\n): { leaking: boolean; slopePerMin: number } | null {\n if (samples.length < MIN_SAMPLES) return null\n const t0 = samples[0]!.at\n const segSize = Math.max(1, Math.ceil(samples.length / FLOOR_SEGMENTS))\n const floorPoints: { x: number; y: number }[] = []\n for (let i = 0; i < samples.length; i += segSize) {\n const seg = samples.slice(i, i + segSize)\n let min = Infinity\n for (const s of seg) min = Math.min(min, s.retained)\n const mid = seg[Math.floor(seg.length / 2)]!\n floorPoints.push({ x: (mid.at - t0) / 60000, y: min })\n }\n const slopePerMin = slope(floorPoints)\n const spanMin = (samples[samples.length - 1]!.at - t0) / 60000\n const projectedGrowth = slopePerMin * spanMin\n const recent = floorPoints.slice(Math.floor(floorPoints.length / 2))\n const recentSlope = recent.length >= 2 ? slope(recent) : slopePerMin\n const leaking = projectedGrowth >= MIN_NET_GROWTH && recentSlope > 0\n return { leaking, slopePerMin }\n}\n","import type {\n ForcedReflowSignal,\n InteractionSignal,\n LongTaskSignal,\n RenderSignal,\n Signal,\n StackFrame,\n} from './types'\n\n/** One frame at 60fps. A commit's `at` is sampled when it completes (after its\n * layout effects), so a reflow forced during that commit finishes up to ~a\n * frame before the commit is timestamped. */\nconst FRAME_MS = 16\n\nexport type AnchorSignal = InteractionSignal | LongTaskSignal\n\n/** How strongly a member is linked to its episode anchor. `caused` means a\n * member's source location matches one of the anchor's hot frames — a real\n * causal claim. `co-occurred` means it only overlapped in time; the link is\n * temporal, not proven. The distinction keeps the tool from overclaiming. */\nexport type LinkConfidence = 'caused' | 'co-occurred'\n\n/** Which slice of an interaction's INP latency a member fell into. Only set\n * for interaction-anchored episodes; long tasks have no phase breakdown. */\nexport type InpPhase = 'input-delay' | 'processing' | 'presentation'\n\n/** Signals that carry an `at` timestamp and can be nested inside an episode.\n * Excludes the anchors themselves and signals with no point in time\n * (web-vital has no `at`; network uses `startedAt`). */\ntype MemberSignal = Exclude<Extract<Signal, { at: number }>, AnchorSignal>\n\n/** The render commit a forced reflow happened inside — the component whose\n * commit forced the synchronous layout. Set when the reflow's timestamp falls\n * within a render commit's window. */\nexport type CommitCause = {\n commitId: number\n component: string\n}\n\nexport type EpisodeMember = {\n signal: MemberSignal\n confidence: LinkConfidence\n phase?: InpPhase\n causedBy?: CommitCause\n}\n\nexport type Episode = {\n anchor: AnchorSignal\n members: EpisodeMember[]\n}\n\nfunction isAnchor(signal: Signal): signal is AnchorSignal {\n return signal.kind === 'interaction' || signal.kind === 'long-task'\n}\n\nfunction sourceKey(frame: StackFrame): string {\n return `${frame.file}:${frame.line}`\n}\n\nfunction anchorHotLocations(anchor: AnchorSignal): Set<string> {\n return new Set((anchor.attribution ?? []).map((a) => sourceKey(a.frame)))\n}\n\nfunction isMember(s: Signal, anchor: AnchorSignal): s is MemberSignal {\n return s !== anchor && s.kind !== 'interaction' && s.kind !== 'long-task' && 'at' in s\n}\n\nfunction linkConfidence(signal: MemberSignal, hotLocations: Set<string>): LinkConfidence {\n if (signal.kind === 'forced-reflow') {\n if (signal.stack.some((f) => hotLocations.has(sourceKey(f)))) return 'caused'\n }\n return 'co-occurred'\n}\n\n/** Finds the render commit that forced a reflow. A render signal's `at` is\n * sampled when the commit completes — *after* its layout effects, where forced\n * reflows happen — and its `duration` covers only the render phase, not the\n * layout work. So the triggering commit is the one that completes at or just\n * after the reflow (within a frame of the reflow finishing), not one whose\n * narrow render-phase window contains it. */\nfunction commitForReflow(reflow: ForcedReflowSignal, renders: RenderSignal[]): RenderSignal | undefined {\n const reflowEnd = reflow.at + reflow.duration\n return renders.find((r) => r.at >= reflow.at && r.at <= reflowEnd + FRAME_MS)\n}\n\nfunction inpPhaseAt(anchor: AnchorSignal, at: number): InpPhase | undefined {\n if (anchor.kind !== 'interaction') return undefined\n const processingStart = anchor.at + anchor.inputDelay\n const presentationStart = processingStart + anchor.processing\n if (at < processingStart) return 'input-delay'\n if (at < presentationStart) return 'processing'\n return 'presentation'\n}\n\nexport function correlate(signals: Signal[]): Episode[] {\n const anchors = signals.filter(isAnchor)\n\n return anchors.map((anchor) => {\n const start = anchor.at\n const end = anchor.at + anchor.duration\n const hotLocations = anchorHotLocations(anchor)\n const windowed = signals.filter(\n (s): s is MemberSignal => isMember(s, anchor) && s.at >= start && s.at <= end,\n )\n const renders = windowed.filter((s): s is RenderSignal => s.kind === 'render')\n\n const members = windowed.map((signal) => {\n const member: EpisodeMember = {\n signal,\n confidence: linkConfidence(signal, hotLocations),\n phase: inpPhaseAt(anchor, signal.at),\n }\n if (signal.kind === 'forced-reflow') {\n const commit = commitForReflow(signal, renders)\n if (commit) {\n member.confidence = 'caused'\n member.causedBy = { commitId: commit.commitId, component: commit.component }\n }\n }\n return member\n })\n\n return { anchor, members }\n })\n}\n","import type { Collector, LongTaskScript, Signal } from '../types'\n\nconst LOAF = 'long-animation-frame'\nconst LEGACY = 'longtask'\n\n/** A single script entry inside a Long Animation Frame. */\ninterface ScriptTiming {\n duration?: number\n invoker?: string\n invokerType?: string\n sourceURL?: string\n sourceFunctionName?: string\n sourceCharPosition?: number\n}\n\ninterface LoAFEntry extends PerformanceEntry {\n blockingDuration?: number\n scripts?: ScriptTiming[]\n}\n\nfunction supportsLoAF(): boolean {\n const PO = (globalThis as { PerformanceObserver?: { supportedEntryTypes?: readonly string[] } })\n .PerformanceObserver\n const types = PO?.supportedEntryTypes\n return Array.isArray(types) && types.includes(LOAF)\n}\n\nfunction mapScripts(scripts: ScriptTiming[]): LongTaskScript[] {\n return scripts.map((s) => ({\n invokerType: s.invokerType ?? 'unknown',\n invoker: s.invoker ?? '',\n sourceURL: s.sourceURL ?? '',\n sourceFunctionName: s.sourceFunctionName ?? '',\n charPosition: typeof s.sourceCharPosition === 'number' ? s.sourceCharPosition : -1,\n duration: typeof s.duration === 'number' ? s.duration : 0,\n }))\n}\n\nexport function createLongTasksCollector(): Collector {\n let observer: PerformanceObserver | null = null\n let active = false\n\n return {\n kind: 'long-task',\n activate(emit: (signal: Signal) => void) {\n if (typeof PerformanceObserver === 'undefined') {\n console.warn('[react-perfscope] PerformanceObserver not supported; long-tasks disabled')\n return\n }\n active = true\n const useLoAF = supportsLoAF()\n try {\n observer = new PerformanceObserver((list) => {\n if (!active) return\n for (const entry of list.getEntries()) {\n if (useLoAF) {\n const loaf = entry as LoAFEntry\n const scripts = Array.isArray(loaf.scripts) ? mapScripts(loaf.scripts) : []\n emit({\n kind: 'long-task',\n at: entry.startTime,\n duration: entry.duration,\n stack: [],\n scripts,\n ...(typeof loaf.blockingDuration === 'number'\n ? { blockingDuration: loaf.blockingDuration }\n : {}),\n })\n } else {\n emit({\n kind: 'long-task',\n at: entry.startTime,\n duration: entry.duration,\n stack: [],\n })\n }\n }\n })\n observer.observe({ type: useLoAF ? LOAF : LEGACY, buffered: false })\n } catch (err) {\n console.warn('[react-perfscope] long-tasks collector failed to start:', err)\n observer = null\n active = false\n }\n },\n deactivate() {\n active = false\n if (observer) {\n try {\n observer.disconnect()\n } catch {\n // ignore\n }\n observer = null\n }\n },\n }\n}\n","import type { Collector, Signal } from '../types'\nimport { attachLazyStack } from '../sourcemap'\n\nconst LAYOUT_GETTERS = [\n 'offsetWidth',\n 'offsetHeight',\n 'offsetLeft',\n 'offsetTop',\n 'clientWidth',\n 'clientHeight',\n 'scrollWidth',\n 'scrollHeight',\n] as const\n\nconst LAYOUT_METHODS = ['getBoundingClientRect', 'getClientRects'] as const\n\ntype SavedDescriptor = {\n proto: object\n key: string\n descriptor: PropertyDescriptor\n}\n\ntype OpenGroup = {\n at: number\n duration: number\n count: number\n rawStack: string | undefined\n}\n\n// Close the coalescing window at the end of the current synchronous turn.\n// queueMicrotask runs after the running task drains, so a layout-thrash loop\n// (read offsetWidth N times in one turn) collapses into a single group.\nconst scheduleFlush: (cb: () => void) => void =\n typeof queueMicrotask === 'function'\n ? queueMicrotask\n : typeof Promise !== 'undefined'\n ? (cb) => {\n Promise.resolve().then(cb)\n }\n : (cb) => cb()\n\nexport function createForcedReflowCollector(): Collector {\n let active = false\n let emit: (s: Signal) => void = () => {}\n const saved: SavedDescriptor[] = []\n let mutationObserver: MutationObserver | null = null\n let group: OpenGroup | null = null\n\n function consumePendingMutations(): boolean {\n if (!mutationObserver) {\n // Fallback when MutationObserver isn't available: always treat as dirty\n // (Phase 1 over-report behavior).\n return true\n }\n return mutationObserver.takeRecords().length > 0\n }\n\n function flush() {\n if (!group) return\n const g = group\n group = null\n const signal = {\n kind: 'forced-reflow' as const,\n at: g.at,\n duration: g.duration,\n count: g.count,\n } as unknown as Signal\n attachLazyStack(signal, g.rawStack, 1)\n emit(signal)\n }\n\n // A layout read happened while recording and layout was dirty. Open a group\n // on the first such read of the turn, then just accumulate count/duration for\n // the rest of the turn. `rawStack` is captured by the caller (the patched\n // accessor) so the stack's top user frame stays at a fixed depth — passing it\n // through a helper would add a frame and misattribute the reflow to this file.\n function record(at: number, duration: number, rawStack: string | undefined) {\n if (group) {\n group.count++\n group.duration += duration\n return\n }\n group = { at, duration, count: 1, rawStack }\n scheduleFlush(flush)\n }\n\n // True when the next dirty read opens a fresh group and so needs a stack.\n // Lets the accessor skip `new Error().stack` (the dominant cost) on the\n // subsequent reads it coalesces into an already-open group.\n function needsStack(): boolean {\n return group === null\n }\n\n function patchGetter(proto: object, key: string) {\n if (typeof proto !== 'object' || proto === null) return\n const desc = Object.getOwnPropertyDescriptor(proto, key)\n if (!desc || !desc.get) return\n saved.push({ proto, key, descriptor: desc })\n const originalGet = desc.get\n Object.defineProperty(proto, key, {\n configurable: true,\n get(this: unknown) {\n if (active) {\n if (!consumePendingMutations()) {\n return originalGet.call(this)\n }\n const rawStack = needsStack() ? new Error().stack : undefined\n const at = performance.now()\n const value = originalGet.call(this)\n record(at, performance.now() - at, rawStack)\n return value\n }\n return originalGet.call(this)\n },\n set: desc.set,\n })\n }\n\n function patchMethod(proto: object, key: string) {\n if (typeof proto !== 'object' || proto === null) return\n const desc = Object.getOwnPropertyDescriptor(proto, key)\n if (!desc || typeof desc.value !== 'function') return\n saved.push({ proto, key, descriptor: desc })\n const original = desc.value as (...args: unknown[]) => unknown\n Object.defineProperty(proto, key, {\n configurable: true,\n writable: true,\n value: function patchedLayoutMethod(this: unknown, ...args: unknown[]) {\n if (active) {\n if (!consumePendingMutations()) {\n return original.apply(this, args)\n }\n const rawStack = needsStack() ? new Error().stack : undefined\n const at = performance.now()\n const value = original.apply(this, args)\n record(at, performance.now() - at, rawStack)\n return value\n }\n return original.apply(this, args)\n },\n })\n }\n\n return {\n kind: 'forced-reflow',\n activate(emitFn) {\n if (active) return\n emit = emitFn\n active = true\n\n if (typeof MutationObserver !== 'undefined' && typeof document !== 'undefined') {\n try {\n mutationObserver = new MutationObserver(() => {})\n mutationObserver.observe(document, {\n attributes: true,\n childList: true,\n subtree: true,\n characterData: true,\n })\n } catch (err) {\n console.warn('[react-perfscope] forced-reflow MutationObserver failed:', err)\n mutationObserver = null\n }\n }\n\n if (typeof HTMLElement !== 'undefined') {\n for (const key of LAYOUT_GETTERS) {\n patchGetter(HTMLElement.prototype, key)\n }\n }\n if (typeof Element !== 'undefined') {\n for (const key of LAYOUT_METHODS) {\n patchMethod(Element.prototype, key)\n }\n }\n },\n deactivate() {\n if (!active) return\n active = false\n // Emit any group still open before the scheduled microtask runs, so the\n // last burst isn't lost when stop() is called mid-turn.\n flush()\n if (mutationObserver) {\n try {\n mutationObserver.disconnect()\n } catch {\n // ignore\n }\n mutationObserver = null\n }\n for (const { proto, key, descriptor } of saved) {\n Object.defineProperty(proto, key, descriptor)\n }\n saved.length = 0\n },\n }\n}\n","import type { Collector, Signal } from '../types'\n\ninterface LayoutShiftSource {\n currentRect: DOMRect\n previousRect?: DOMRect\n node?: Node | null\n}\n\ninterface LayoutShiftEntryLike extends PerformanceEntry {\n value: number\n hadRecentInput: boolean\n sources?: LayoutShiftSource[]\n}\n\nconst PERFSCOPE_HOST_ATTR = 'data-perfscope-host'\n\nfunction rectsOverlap(a: DOMRect, b: DOMRect, tolerance = 0): boolean {\n return !(\n a.x + a.width < b.x - tolerance ||\n b.x + b.width < a.x - tolerance ||\n a.y + a.height < b.y - tolerance ||\n b.y + b.height < a.y - tolerance\n )\n}\n\n/**\n * Returns true when every source in the entry is part of our floating\n * widget. We want to ignore shifts caused by the perfscope UI itself.\n *\n * Detection has two paths:\n * 1. Node-based: walk up `source.node` looking for `[data-perfscope-host]`.\n * Works when the node is in light DOM.\n * 2. Rect-based fallback: compare `source.currentRect` against every host\n * element's bounding rect. This catches the Shadow-DOM case where the\n * browser doesn't expose the inner node (Shadow root boundary).\n */\nfunction collectPerfscopeRects(): DOMRect[] {\n const hosts = Array.from(document.querySelectorAll(`[${PERFSCOPE_HOST_ATTR}]`))\n const rects: DOMRect[] = []\n for (const h of hosts) {\n // The light-DOM host element usually has height 0 because Shadow DOM\n // content isn't part of its layout. We need to peek inside the shadow\n // root and collect bounds of any positioned children.\n const sr = (h as Element & { shadowRoot?: ShadowRoot | null }).shadowRoot\n if (sr) {\n for (const child of Array.from(sr.children)) {\n const r = (child as Element).getBoundingClientRect()\n if (r.width > 0 && r.height > 0) rects.push(r)\n }\n } else {\n const r = h.getBoundingClientRect()\n if (r.width > 0 && r.height > 0) rects.push(r)\n }\n }\n return rects\n}\n\nfunction entryIsOnlyFromPerfscope(sources: LayoutShiftSource[]): boolean {\n if (sources.length === 0) return false\n if (typeof document === 'undefined') return false\n\n const hostRects = collectPerfscopeRects()\n if (hostRects.length === 0) return false\n\n for (const src of sources) {\n let matched = false\n const node = src.node as (Node & { closest?: (sel: string) => Element | null }) | null | undefined\n if (node) {\n // Node-based check\n if (typeof (node as { closest?: unknown }).closest === 'function') {\n if ((node as Element).closest(`[${PERFSCOPE_HOST_ATTR}]`)) matched = true\n } else {\n let parent: (Element | null) = (node as Node).parentElement as Element | null\n while (parent) {\n if (parent.hasAttribute(PERFSCOPE_HOST_ATTR)) { matched = true; break }\n parent = parent.parentElement\n }\n }\n }\n // Rect-based fallback (shadow DOM): if source rect overlaps any of our\n // host rects, consider it our widget. Tolerance covers the case where\n // the widget changes size during the shift (its previous/current bounds\n // differ but both sit in the same screen corner).\n if (!matched) {\n for (const hostRect of hostRects) {\n if (rectsOverlap(src.currentRect, hostRect, 24)) {\n matched = true\n break\n }\n }\n }\n if (!matched) return false\n }\n return true\n}\n\nexport function createLayoutShiftCollector(): Collector {\n let observer: PerformanceObserver | null = null\n let active = false\n\n return {\n kind: 'layout-shift',\n activate(emit: (signal: Signal) => void) {\n if (typeof PerformanceObserver === 'undefined') {\n console.warn('[react-perfscope] PerformanceObserver not supported; layout-shift disabled')\n return\n }\n active = true\n try {\n observer = new PerformanceObserver((list) => {\n if (!active) return\n for (const raw of list.getEntries()) {\n const entry = raw as LayoutShiftEntryLike\n // Note: production CLS metrics exclude shifts with hadRecentInput\n // (user-initiated movements are considered intentional). For a\n // dev tool, the user explicitly WANTS to see what their clicks\n // caused — so we report these too.\n const sources = entry.sources ?? []\n if (entryIsOnlyFromPerfscope(sources)) continue\n // Convert viewport-relative rects to document-relative coords so\n // overlays stay anchored to the shifted DOM position when the\n // user scrolls. Filter above runs first on viewport coords (our\n // widget is position:fixed, lives in viewport space).\n const sx = (typeof window !== 'undefined' && window.scrollX) || 0\n const sy = (typeof window !== 'undefined' && window.scrollY) || 0\n const toDocRect = (r: DOMRect) =>\n new DOMRect(r.x + sx, r.y + sy, r.width, r.height)\n const rects = sources.map((s) => toDocRect(s.currentRect))\n // previousRect is undefined when the element was newly inserted.\n // An \"empty\" rect (w=0, h=0) likewise means there was no prior\n // box — treat both as `null` so the overlay can decide not to\n // draw an arrow for these.\n const prevRects: (DOMRect | null)[] = sources.map((s) => {\n const pr = s.previousRect\n if (!pr) return null\n if (pr.width === 0 && pr.height === 0) return null\n return toDocRect(pr)\n })\n emit({\n kind: 'layout-shift',\n at: entry.startTime,\n value: entry.value,\n sources: rects,\n previousSources: prevRects,\n })\n }\n })\n observer.observe({ type: 'layout-shift', buffered: false })\n } catch (err) {\n console.warn('[react-perfscope] layout-shift collector failed to start:', err)\n observer = null\n active = false\n }\n },\n deactivate() {\n active = false\n if (observer) {\n try {\n observer.disconnect()\n } catch {\n // ignore\n }\n observer = null\n }\n },\n }\n}\n","import type { Collector, Signal } from '../types'\nimport { isSelfRequest } from '../self-requests'\n\ninterface ResourceTimingLike extends PerformanceEntry {\n transferSize?: number\n renderBlockingStatus?: 'blocking' | 'non-blocking'\n}\n\nexport function createNetworkCollector(): Collector {\n let observer: PerformanceObserver | null = null\n let active = false\n\n return {\n kind: 'network',\n activate(emit: (signal: Signal) => void) {\n if (typeof PerformanceObserver === 'undefined') {\n console.warn('[react-perfscope] PerformanceObserver not supported; network disabled')\n return\n }\n active = true\n try {\n observer = new PerformanceObserver((list) => {\n if (!active) return\n for (const raw of list.getEntries()) {\n const entry = raw as ResourceTimingLike\n // Skip react-perfscope's own traffic (source-map fetches).\n if (isSelfRequest(entry.name)) continue\n emit({\n kind: 'network',\n url: entry.name,\n startedAt: entry.startTime,\n duration: entry.duration,\n size: entry.transferSize ?? 0,\n blocking: entry.renderBlockingStatus === 'blocking',\n })\n }\n })\n observer.observe({ type: 'resource', buffered: false })\n } catch (err) {\n console.warn('[react-perfscope] network collector failed to start:', err)\n observer = null\n active = false\n }\n },\n deactivate() {\n active = false\n if (observer) {\n try {\n observer.disconnect()\n } catch {\n // ignore\n }\n observer = null\n }\n },\n }\n}\n","import { onLCP, onINP, onCLS, onFCP, onTTFB, type Metric } from 'web-vitals'\nimport type { Collector, Signal, WebVitalSignal } from '../types'\n\ntype VitalName = WebVitalSignal['name']\n\nexport function createWebVitalsCollector(): Collector {\n let active = false\n let subscribed = false\n let emit: (signal: Signal) => void = () => {}\n\n function makeHandler(name: VitalName) {\n return (metric: Metric) => {\n if (!active) return\n emit({ kind: 'web-vital', name, value: metric.value })\n }\n }\n\n return {\n kind: 'web-vital',\n activate(emitFn) {\n emit = emitFn\n active = true\n if (subscribed) return\n try {\n onLCP(makeHandler('LCP'))\n onINP(makeHandler('INP'))\n onCLS(makeHandler('CLS'))\n onFCP(makeHandler('FCP'))\n onTTFB(makeHandler('TTFB'))\n subscribed = true\n } catch (err) {\n console.warn('[react-perfscope] web-vitals collector failed to subscribe:', err)\n active = false\n }\n },\n deactivate() {\n // The web-vitals library does not expose unsubscribe. We keep the\n // handlers attached and gate emission via `active`. Re-activating\n // updates `emit` without re-subscribing.\n active = false\n },\n }\n}\n","import type {\n Collector,\n HeapSample,\n HeapTrend,\n HeapTrendClass,\n RecordingResult,\n} from '../types'\n\n/** How often to read heap usage while recording. Reading performance.memory\n * is cheap, so we sample at 4Hz: a 1s cadence is too coarse — short spikes fall\n * between samples and the line, drawn straight between sparse points, smooths\n * them into a ramp. 250ms localizes spikes without meaningful overhead. */\nconst SAMPLE_INTERVAL_MS = 250\n/** Cap on retained samples so a multi-hour session can't grow the array\n * unbounded. At 250ms this is ~83 min; past that, oldest samples drop. */\nconst MAX_SAMPLES = 20_000\n\n/** Below this, a trend can't be estimated reliably. */\nconst MIN_SAMPLES = 4\n/** How many contiguous segments to split the series into when estimating the\n * floor. Each segment contributes its minimum (the post-GC trough). */\nconst FLOOR_SEGMENTS = 8\n\nconst MB = 1024 * 1024\n/** Floor-growth thresholds, in bytes per minute. */\nconst GROWING_SLOPE = 1 * MB\nconst LEAK_SLOPE = 5 * MB\n/** A rate alone isn't enough: over a short recording, a sub-megabyte wobble in\n * the floor extrapolates to a huge MB/min and would false-positive. Require the\n * floor to have actually risen by at least this much across the window before\n * calling anything growing/leaking. */\nconst MIN_NET_GROWTH = 2 * MB\n\ninterface MemoryInfo {\n usedJSHeapSize: number\n totalJSHeapSize: number\n jsHeapSizeLimit: number\n}\n\nfunction readMemory(): MemoryInfo | null {\n const perf = (globalThis as { performance?: { memory?: MemoryInfo } }).performance\n const mem = perf?.memory\n if (!mem || typeof mem.usedJSHeapSize !== 'number') return null\n return mem\n}\n\n/**\n * Least-squares slope of points (x, y). Returns 0 when x has no spread\n * (vertical / single distinct x) to avoid a divide-by-zero blow-up.\n */\nfunction slope(points: { x: number; y: number }[]): number {\n const n = points.length\n if (n < 2) return 0\n let sx = 0\n let sy = 0\n let sxy = 0\n let sxx = 0\n for (const { x, y } of points) {\n sx += x\n sy += y\n sxy += x * y\n sxx += x * x\n }\n const denom = n * sxx - sx * sx\n if (denom === 0) return 0\n return (n * sxy - sx * sy) / denom\n}\n\n/**\n * Estimate whether memory is being retained across the recording.\n *\n * GC makes raw heap usage a sawtooth, so the peak is noisy. The reliable\n * signal is the *floor* — the post-GC troughs. We split the series into\n * contiguous segments, take the minimum of each (its trough), and regress\n * those minima against time.\n *\n * A rising overall slope is necessary but NOT sufficient: a one-time step\n * (heap warms up early, then plateaus) also regresses to a positive slope, and\n * flagging that as a leak is a false positive — the classic \"idle recording\n * reads abnormal\" bug. A real leak keeps climbing, so we additionally require\n * the *recent* half of the floor to still be rising. We also gate on a minimum\n * net growth, since over a short window a sub-MB wobble extrapolates to a steep\n * per-minute slope.\n *\n * Returns null when there are too few samples to say anything.\n */\nexport function analyzeHeapTrend(samples: HeapSample[]): HeapTrend | null {\n if (samples.length < MIN_SAMPLES) return null\n const t0 = samples[0]!.at\n const segSize = Math.max(1, Math.ceil(samples.length / FLOOR_SEGMENTS))\n const floorPoints: { x: number; y: number }[] = []\n for (let i = 0; i < samples.length; i += segSize) {\n const seg = samples.slice(i, i + segSize)\n let min = Infinity\n for (const s of seg) min = Math.min(min, s.used)\n const mid = seg[Math.floor(seg.length / 2)]!\n floorPoints.push({ x: (mid.at - t0) / 60000, y: min })\n }\n const slopeBytesPerMin = slope(floorPoints)\n const spanMin = (samples[samples.length - 1]!.at - t0) / 60000\n const projectedGrowth = slopeBytesPerMin * spanMin\n // Recent trend: is the floor still climbing in the latter half? Distinguishes\n // a sustained leak from a one-time step that has since plateaued.\n const recent = floorPoints.slice(Math.floor(floorPoints.length / 2))\n const recentSlope = recent.length >= 2 ? slope(recent) : slopeBytesPerMin\n\n let classification: HeapTrendClass = 'stable'\n const sustained = projectedGrowth >= MIN_NET_GROWTH && recentSlope >= GROWING_SLOPE\n if (sustained) {\n classification =\n slopeBytesPerMin >= LEAK_SLOPE && recentSlope >= LEAK_SLOPE ? 'leak-suspected' : 'growing'\n }\n return { classification, slopeBytesPerMin }\n}\n\nexport interface HeapCollector extends Collector {\n /** Attach the sampled heap series to the recording result. Returns the\n * input untouched when nothing was sampled (unsupported browser). */\n finalize(result: RecordingResult): RecordingResult\n}\n\n/**\n * Samples `performance.memory` on an interval for the duration of a recording\n * and attaches the series via `finalize`. It is a Collector so the recorder\n * drives its start/stop, but it emits no signals — the series is a separate\n * track (see RecordingResult.heapSamples), so a busy session's signal buffer\n * can't evict it. No-ops entirely when performance.memory is unavailable\n * (non-Chromium), leaving `heapSamples` absent so the UI can show a fallback.\n */\nexport function createHeapCollector(): HeapCollector {\n let samples: HeapSample[] = []\n let timer: ReturnType<typeof setInterval> | null = null\n\n function sample(): void {\n const mem = readMemory()\n if (!mem) return\n samples.push({ at: performance.now(), used: mem.usedJSHeapSize, total: mem.totalJSHeapSize })\n if (samples.length > MAX_SAMPLES) samples.splice(0, samples.length - MAX_SAMPLES)\n }\n\n return {\n kind: 'heap',\n activate() {\n samples = []\n if (!readMemory()) return // unsupported → never start the timer\n sample()\n timer = setInterval(sample, SAMPLE_INTERVAL_MS)\n },\n deactivate() {\n if (timer == null) return\n clearInterval(timer)\n timer = null\n sample() // one final reading at stop\n },\n finalize(result) {\n if (samples.length === 0) return result\n return { ...result, heapSamples: samples.slice() }\n },\n }\n}\n","import type { Collector, InteractionSignal, RecordingResult } from '../types'\n\n/** Event Timing only surfaces events at/over this duration (ms); 40ms keeps\n * trivial interactions out while still catching anything a user would feel. */\nconst DURATION_THRESHOLD = 40\n\ninterface EventTimingEntry extends PerformanceEntry {\n processingStart: number\n processingEnd: number\n interactionId?: number\n target?: unknown\n}\n\nfunction selectorFor(target: unknown): string | undefined {\n const el = target as { tagName?: string; id?: string; className?: unknown } | null\n if (!el || typeof el.tagName !== 'string') return undefined\n let s = el.tagName.toLowerCase()\n if (el.id) s += `#${el.id}`\n else if (typeof el.className === 'string' && el.className.trim()) {\n s += `.${el.className.trim().split(/\\s+/)[0]}`\n }\n return s\n}\n\nfunction supportsEventTiming(): boolean {\n const PO = (globalThis as { PerformanceObserver?: { supportedEntryTypes?: readonly string[] } })\n .PerformanceObserver\n const types = PO?.supportedEntryTypes\n // happy-dom / older browsers may not expose supportedEntryTypes; if the\n // observer exists at all we still try, and observe() throwing is caught.\n return !types || types.includes('event')\n}\n\nexport interface InteractionCollector extends Collector {\n /** Group buffered Event Timing entries into one interaction each and append\n * them to the result. Returns the input untouched when none qualified. */\n finalize(result: RecordingResult): RecordingResult\n}\n\n/**\n * Records Event Timing entries during a recording and, on finalize, turns each\n * user interaction (grouped by interactionId) into one signal carrying the INP\n * latency breakdown: input delay → processing → presentation. The longest\n * event in a group defines the interaction's latency (matching how INP is\n * attributed). Emits no live signals — interactions are assembled at finalize,\n * then the self-profiling collector attributes the processing window to the\n * developer's hot functions.\n */\nexport function createInteractionCollector(): InteractionCollector {\n let active = false\n let observer: PerformanceObserver | null = null\n let entries: EventTimingEntry[] = []\n\n return {\n kind: 'interaction',\n activate() {\n if (typeof PerformanceObserver === 'undefined' || !supportsEventTiming()) return\n active = true\n entries = []\n try {\n observer = new PerformanceObserver((list) => {\n if (!active) return\n for (const e of list.getEntries()) entries.push(e as EventTimingEntry)\n })\n // `event` covers all interaction events; `first-input` guarantees the\n // first one even if it's under the duration threshold.\n observer.observe({ type: 'event', buffered: false, durationThreshold: DURATION_THRESHOLD } as PerformanceObserverInit)\n try {\n observer.observe({ type: 'first-input', buffered: false } as PerformanceObserverInit)\n } catch {\n // first-input not supported everywhere; the event stream is enough.\n }\n } catch (err) {\n console.warn('[react-perfscope] interaction collector failed to start:', err)\n observer = null\n active = false\n }\n },\n deactivate() {\n active = false\n if (observer) {\n try {\n observer.disconnect()\n } catch {\n // ignore\n }\n observer = null\n }\n },\n finalize(result) {\n const byId = new Map<number, EventTimingEntry[]>()\n for (const e of entries) {\n const id = e.interactionId\n if (!id) continue // 0 / undefined → not part of a discrete interaction\n const group = byId.get(id)\n if (group) group.push(e)\n else byId.set(id, [e])\n }\n const interactions: InteractionSignal[] = []\n for (const group of byId.values()) {\n // All events of one interaction (pointerdown/up/click) report the same\n // `duration` (the whole interaction latency), so the breakdown can't\n // come from a single event. Span the processing across the group:\n // earliest processingStart → latest processingEnd (matches web-vitals).\n // The \"defining\" event for label/target is the one with the most\n // processing — typically the click/keydown that actually ran handlers.\n let duration = 0\n let startTime = Infinity\n let processingStart = Infinity\n let processingEnd = -Infinity\n let defining = group[0]!\n let maxProcessing = -Infinity\n for (const e of group) {\n if (e.duration > duration) duration = e.duration\n if (e.startTime < startTime) startTime = e.startTime\n if (e.processingStart < processingStart) processingStart = e.processingStart\n if (e.processingEnd > processingEnd) processingEnd = e.processingEnd\n const proc = e.processingEnd - e.processingStart\n if (proc > maxProcessing) {\n maxProcessing = proc\n defining = e\n }\n }\n if (duration < DURATION_THRESHOLD) continue\n const inputDelay = Math.max(0, processingStart - startTime)\n const processing = Math.max(0, processingEnd - processingStart)\n const presentation = Math.max(0, startTime + duration - processingEnd)\n interactions.push({\n kind: 'interaction',\n at: startTime,\n eventType: defining.name,\n ...(selectorFor(defining.target) ? { target: selectorFor(defining.target) } : {}),\n duration,\n inputDelay,\n processing,\n presentation,\n })\n }\n if (interactions.length === 0) return result\n interactions.sort((a, b) => a.at - b.at)\n return { ...result, signals: [...result.signals, ...interactions] }\n },\n }\n}\n","import type { Collector, FpsSample, FrameStats, RecordingResult } from '../types'\n\n/** 60fps frame budget (ms). Gaps are scored against this to count drops. */\nconst FRAME_BUDGET = 1000 / 60\n/** Window for the FPS series; 500ms smooths per-frame noise while still showing\n * a scroll-jank dip. */\nconst BUCKET_MS = 500\n/** A trailing window shorter than this is too small to estimate FPS reliably. */\nconst MIN_BUCKET_SPAN = 100\n/** Below this we can't say anything useful. */\nconst MIN_FRAMES = 8\n/** Cap retained frames so a long session can't grow the array unbounded\n * (~5.5 min at 60fps); past that, oldest drop. */\nconst MAX_FRAMES = 20_000\n\n/**\n * Turn raw requestAnimationFrame timestamps into a frame-rate picture:\n * a windowed FPS series, the lowest sustained FPS, the worst single hitch,\n * and an approximate dropped-frame count. Long tasks (>50ms) show up here as\n * big gaps, but so does sustained scroll jank (30–50ms frames) that the\n * long-task collector's threshold misses.\n *\n * Returns null when there are too few frames to analyze.\n */\nexport function analyzeFrames(frames: number[]): FrameStats | null {\n if (frames.length < MIN_FRAMES) return null\n\n let longestFrameMs = 0\n let droppedFrames = 0\n for (let i = 1; i < frames.length; i++) {\n const gap = frames[i]! - frames[i - 1]!\n if (gap > longestFrameMs) longestFrameMs = gap\n const dropped = Math.round(gap / FRAME_BUDGET) - 1\n if (dropped > 0) droppedFrames += dropped\n }\n\n const t0 = frames[0]!\n const end = frames[frames.length - 1]!\n const series: FpsSample[] = []\n let minFps = Infinity\n let idx = 0\n for (let bStart = t0; bStart < end; bStart += BUCKET_MS) {\n const bEnd = Math.min(bStart + BUCKET_MS, end)\n const span = bEnd - bStart\n let count = 0\n while (idx < frames.length && frames[idx]! < bEnd) {\n count++\n idx++\n }\n if (span < MIN_BUCKET_SPAN) break // skip a tiny trailing window\n const fps = count / (span / 1000)\n series.push({ at: bStart + span / 2, fps })\n if (fps < minFps) minFps = fps\n }\n if (series.length === 0) return null\n return { series, minFps, longestFrameMs, droppedFrames }\n}\n\nexport interface FrameCollector extends Collector {\n /** Attach the captured frame timestamps to the result. Returns the input\n * untouched when too few frames were seen (or rAF was unavailable). */\n finalize(result: RecordingResult): RecordingResult\n}\n\n/**\n * Records requestAnimationFrame timestamps for the duration of a recording so\n * the UI can chart frame rate and surface jank. Emits no signals — the\n * timestamps are a side track attached at finalize. No-ops when\n * requestAnimationFrame is unavailable (non-DOM environments).\n */\nexport function createFrameCollector(): FrameCollector {\n let active = false\n let rafId: number | null = null\n let frames: number[] = []\n\n function loop(t: number): void {\n if (!active) return\n frames.push(t)\n if (frames.length > MAX_FRAMES) frames.splice(0, frames.length - MAX_FRAMES)\n rafId = requestAnimationFrame(loop)\n }\n\n return {\n kind: 'frame',\n activate() {\n if (typeof requestAnimationFrame === 'undefined') return\n active = true\n frames = []\n rafId = requestAnimationFrame(loop)\n },\n deactivate() {\n active = false\n if (rafId != null && typeof cancelAnimationFrame !== 'undefined') {\n try {\n cancelAnimationFrame(rafId)\n } catch {\n // ignore\n }\n }\n rafId = null\n },\n finalize(result) {\n if (frames.length < MIN_FRAMES) return result\n return { ...result, frames: frames.slice() }\n },\n }\n}\n","import type { Collector, LongTaskAttribution, RecordingResult, Signal, StackFrame } from '../types'\n\n/**\n * JS Self-Profiling API trace shape (the subset we consume).\n * @see https://wicg.github.io/js-self-profiling/\n */\nexport interface ProfilerFrame {\n name?: string\n resourceId?: number\n line?: number\n column?: number\n}\nexport interface ProfilerStack {\n frameId: number\n parentId?: number\n}\nexport interface ProfilerSample {\n /** DOMHighResTimeStamp, same clock as performance.now() / entry.startTime. */\n timestamp: number\n stackId?: number\n}\nexport interface ProfilerTrace {\n resources: string[]\n frames: ProfilerFrame[]\n stacks: ProfilerStack[]\n samples: ProfilerSample[]\n}\n\ninterface ProfilerInstance {\n stop(): Promise<ProfilerTrace>\n}\ninterface ProfilerCtor {\n new (opts: { sampleInterval: number; maxBufferSize: number }): ProfilerInstance\n}\n\n/** Default sampling cadence. The browser may coarsen this. */\nconst SAMPLE_INTERVAL_MS = 10\nconst MAX_BUFFER_SIZE = 100_000\n/** Keep the noisiest few; deeper tails rarely help the developer. */\nconst MAX_FRAMES_PER_TASK = 5\n\n/**\n * Whether a resource URL belongs to the developer's own source (vs. a\n * dependency or tooling shim). Dependency frames are noise when the question\n * is \"which of MY functions is slow\".\n */\nexport function isUserResource(url: string | undefined): boolean {\n if (!url) return false\n if (url.includes('/node_modules/')) return false\n // Vite/dev tooling virtual modules: /@vite/client, /@react-refresh, /@id/...\n try {\n const path = new URL(url).pathname\n if (path.startsWith('/@')) return false\n } catch {\n if (url.startsWith('/@')) return false\n }\n return true\n}\n\nfunction frameToStackFrame(trace: ProfilerTrace, frame: ProfilerFrame): StackFrame {\n const file = frame.resourceId != null ? (trace.resources[frame.resourceId] ?? '') : ''\n const sf: StackFrame = {\n file,\n line: frame.line ?? 0,\n col: frame.column ?? 0,\n }\n if (frame.name) sf.fnName = frame.name\n return sf\n}\n\n/**\n * Climb a sample's stack from the leaf toward the root, returning the first\n * (deepest) frame that lives in user source. That frame is where the\n * developer's own code was actually executing when the sample was taken.\n */\nfunction leafUserFrame(trace: ProfilerTrace, stackId: number | undefined): ProfilerFrame | null {\n let id = stackId\n let guard = 0\n while (id != null && guard++ < 1000) {\n const stack = trace.stacks[id]\n if (!stack) break\n const frame = trace.frames[stack.frameId]\n if (frame && isUserResource(trace.resources[frame.resourceId ?? -1])) {\n return frame\n }\n id = stack.parentId\n }\n return null\n}\n\n/**\n * Aggregate the hottest user-source frames among samples whose timestamp\n * falls in [start, end]. `selfRatio` is relative to ALL in-window samples\n * (including vendor-only ones), so it reflects the share of the task's\n * blocking time spent in that user function.\n */\nexport function attributeWindow(\n trace: ProfilerTrace,\n start: number,\n end: number\n): LongTaskAttribution[] {\n let total = 0\n const counts = new Map<string, { frame: StackFrame; count: number }>()\n for (const sample of trace.samples) {\n if (sample.timestamp < start || sample.timestamp > end) continue\n total++\n const frame = leafUserFrame(trace, sample.stackId)\n if (!frame) continue\n const sf = frameToStackFrame(trace, frame)\n const key = `${sf.file}:${sf.line}:${sf.col}:${sf.fnName ?? ''}`\n const entry = counts.get(key)\n if (entry) entry.count++\n else counts.set(key, { frame: sf, count: 1 })\n }\n if (total === 0) return []\n return [...counts.values()]\n .sort((a, b) => b.count - a.count)\n .slice(0, MAX_FRAMES_PER_TASK)\n .map(({ frame, count }) => ({ frame, selfRatio: count / total, sampleCount: count }))\n}\n\n/**\n * Return a copy of `signals` with each long-task signal enriched with the\n * hottest user frames sampled during its window. Long tasks with no in-window\n * user samples are left without `attribution`. Non-long-task signals pass\n * through by reference.\n */\nexport function attributeLongTaskSignals(trace: ProfilerTrace, signals: Signal[]): Signal[] {\n return signals.map((signal) => {\n if (signal.kind !== 'long-task') return signal\n const attribution = attributeWindow(trace, signal.at, signal.at + signal.duration)\n if (attribution.length === 0) return signal\n return { ...signal, attribution }\n })\n}\n\n/**\n * Like {@link attributeLongTaskSignals} but for interactions: attributes the\n * *processing* window (handlers running, `[at+inputDelay, +processing]`) to the\n * developer's hot functions — answering \"which of my code made this click\n * slow\". Input delay and presentation aren't JS-on-the-stack, so they're\n * excluded from the window.\n */\nexport function attributeInteractionSignals(trace: ProfilerTrace, signals: Signal[]): Signal[] {\n return signals.map((signal) => {\n if (signal.kind !== 'interaction') return signal\n const start = signal.at + signal.inputDelay\n const attribution = attributeWindow(trace, start, start + signal.processing)\n if (attribution.length === 0) return signal\n return { ...signal, attribution }\n })\n}\n\ninterface SelfProfilingCollector extends Collector {\n /** Stop the profiler (if running), await its trace, and return a result\n * with long-task signals enriched. Falls back to the input on any failure\n * or when the Profiler API / Document-Policy header is unavailable. */\n finalize(result: RecordingResult): Promise<RecordingResult>\n}\n\n/**\n * Collector that runs the JS Self-Profiling API across a recording and, on\n * finalize, attributes each long task to the developer's own hot functions —\n * something LoAF can't do for React-delegated events (it only sees React's\n * single root dispatcher).\n *\n * It reports `kind: 'long-task'` because it enriches that signal rather than\n * emitting its own. Requires Chromium + a `Document-Policy: js-profiling`\n * response header (the dev plugins inject it); degrades to a no-op otherwise.\n */\nexport function createSelfProfilingCollector(): SelfProfilingCollector {\n let profiler: ProfilerInstance | null = null\n let tracePromise: Promise<ProfilerTrace> | null = null\n\n return {\n kind: 'long-task',\n activate() {\n tracePromise = null\n const Ctor = (globalThis as { Profiler?: ProfilerCtor }).Profiler\n if (typeof Ctor !== 'function') return\n try {\n profiler = new Ctor({ sampleInterval: SAMPLE_INTERVAL_MS, maxBufferSize: MAX_BUFFER_SIZE })\n } catch (err) {\n // Thrown when the Document-Policy: js-profiling header is absent.\n console.warn(\n '[react-perfscope] self-profiling unavailable (needs Document-Policy: js-profiling header); long tasks keep LoAF-only attribution:',\n err\n )\n profiler = null\n }\n },\n deactivate() {\n if (!profiler) return\n try {\n tracePromise = profiler.stop()\n } catch (err) {\n console.warn('[react-perfscope] self-profiling stop failed:', err)\n tracePromise = null\n }\n profiler = null\n },\n async finalize(result: RecordingResult): Promise<RecordingResult> {\n if (!tracePromise) return result\n try {\n const trace = await tracePromise\n const signals = attributeInteractionSignals(trace, attributeLongTaskSignals(trace, result.signals))\n return { ...result, signals }\n } catch (err) {\n console.warn('[react-perfscope] self-profiling finalize failed:', err)\n return result\n } finally {\n tracePromise = null\n }\n },\n }\n}\n"],"mappings":"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","names":["MIN_SAMPLES","FLOOR_SEGMENTS","MIN_NET_GROWTH","slope","SAMPLE_INTERVAL_MS"]}
1
+ {"version":3,"sources":["../src/recorder.ts","../src/sourcemap.ts","../src/self-requests.ts","../src/capabilities.ts","../src/leak-trend.ts","../src/correlate.ts","../src/collectors/long-tasks.ts","../src/collectors/forced-reflow.ts","../src/collectors/layout-shift.ts","../src/collectors/network.ts","../src/collectors/web-vitals.ts","../src/collectors/heap.ts","../src/collectors/interaction.ts","../src/collectors/frames.ts","../src/collectors/self-profiling.ts"],"sourcesContent":["import type { Collector, Recorder, RecordingResult, Signal } from './types'\n\n/** Hard cap on retained signals; the oldest are dropped past this. Exported so\n * downstream tests can assert the buffer never grows beyond it. */\nexport const BUFFER_CAP = 10_000\n\nexport interface InternalRecorder extends Recorder {\n __push: (signal: Signal) => void\n}\n\nexport function createRecorder(): Recorder {\n let recording = false\n let startedAt = 0\n let buffer: Signal[] = []\n const subscribers = new Set<(s: Signal) => void>()\n const collectors: Collector[] = []\n\n function notify(signal: Signal) {\n for (const cb of subscribers) {\n try {\n cb(signal)\n } catch (err) {\n console.warn('[react-perfscope] subscriber threw:', err)\n }\n }\n }\n\n function push(signal: Signal) {\n if (!recording) return\n buffer.push(signal)\n if (buffer.length > BUFFER_CAP) {\n buffer.splice(0, buffer.length - BUFFER_CAP)\n }\n notify(signal)\n }\n\n const recorder: InternalRecorder = {\n start() {\n if (recording) return\n recording = true\n startedAt = performance.now()\n buffer = []\n for (const c of collectors) {\n try {\n c.activate(push)\n } catch (err) {\n console.warn(`[react-perfscope] collector ${c.kind} failed to activate:`, err)\n }\n }\n },\n stop(): RecordingResult {\n if (!recording) {\n return { signals: [], startedAt: 0, duration: 0 }\n }\n for (const c of collectors) {\n try {\n c.deactivate()\n } catch (err) {\n console.warn(`[react-perfscope] collector ${c.kind} failed to deactivate:`, err)\n }\n }\n const duration = performance.now() - startedAt\n const result: RecordingResult = {\n signals: buffer.slice(),\n startedAt,\n duration,\n }\n recording = false\n buffer = []\n return result\n },\n isRecording() {\n return recording\n },\n onSignal(cb) {\n subscribers.add(cb)\n return () => subscribers.delete(cb)\n },\n use(collector) {\n collectors.push(collector)\n },\n __push: push,\n }\n return recorder\n}\n","import { TraceMap, originalPositionFor, type SourceMapInput } from '@jridgewell/trace-mapping'\nimport type { StackFrame } from './types'\nimport { markSelfRequest } from './self-requests'\n\nconst CHROME_FRAME = /^\\s*at\\s+(?:(.+?)\\s+\\()?(.+?):(\\d+):(\\d+)\\)?$/\nconst FIREFOX_FRAME = /^(.*?)@(.+?):(\\d+):(\\d+)$/\n\n/** A parsed source map (the JSON object), as returned by a FetchMap. */\nexport type RawSourceMap = SourceMapInput\n\nexport type FetchMap = (file: string) => Promise<RawSourceMap | null>\n\nfunction lookupFrame(tracer: TraceMap, frame: StackFrame): StackFrame {\n // Stack-trace columns (Chrome and Firefox alike) are 1-based, while source\n // map segments store 0-based columns — shift on the way in and back out.\n // In minified bundles one column is often a whole identifier, so an\n // off-by-one maps to the wrong token.\n const pos = originalPositionFor(tracer, { line: frame.line, column: frame.col - 1 })\n if (pos.source == null || pos.line == null || pos.column == null) {\n return frame\n }\n const resolved: StackFrame = {\n file: pos.source,\n line: pos.line,\n col: pos.column + 1,\n }\n if (pos.name) resolved.fnName = pos.name\n else if (frame.fnName) resolved.fnName = frame.fnName\n return resolved\n}\n\nexport async function resolveFrame(\n frame: StackFrame,\n fetchMap: FetchMap\n): Promise<StackFrame> {\n try {\n const map = await fetchMap(frame.file)\n if (!map) return frame\n // trace-mapping is pure JS (no wasm), so this works in the browser where\n // Mozilla's source-map SourceMapConsumer needs an explicitly-initialized\n // mappings.wasm.\n return lookupFrame(new TraceMap(map), frame)\n } catch (err) {\n console.warn('[react-perfscope] resolveFrame failed:', err)\n return frame\n }\n}\n\n/**\n * Attach a lazy `stack` getter to `target` that parses `raw` on first access\n * and memoizes the result. Use this from collectors to defer parseStack cost\n * until a consumer actually reads `signal.stack`.\n *\n * `skipTopFrames` drops the leading N parsed frames — useful for collectors\n * that wrap a patched function (the wrapper itself shows up as the topmost\n * frame, but it's noise from the user's perspective).\n */\nexport function attachLazyStack(\n target: object,\n raw: string | undefined,\n skipTopFrames = 0\n): void {\n let cached: StackFrame[] | null = null\n Object.defineProperty(target, 'stack', {\n enumerable: true,\n configurable: true,\n get() {\n if (cached === null) {\n const all = parseStack(raw)\n cached = skipTopFrames > 0 ? all.slice(skipTopFrames) : all\n }\n return cached\n },\n })\n}\n\nexport interface SourceMapResolver {\n /** Resolve a parsed StackFrame to its original source position. Falls back to the input frame on any failure. */\n resolve(frame: StackFrame): Promise<StackFrame>\n}\n\nexport interface CreateSourceMapResolverOptions {\n /** Override the global fetch. Useful for tests and non-browser environments. */\n fetch?: typeof globalThis.fetch\n}\n\n/**\n * Create a SourceMap resolver that fetches `.map` files from the live URL\n * referenced in each source file's `//# sourceMappingURL=` directive.\n * Caches the DECODED TraceMap per source URL — decoding the mappings is the\n * expensive step, so repeated resolves against the same file are O(log n)\n * lookups after the first.\n *\n * Returns the input frame on any failure (network error, missing map, etc.).\n */\nexport function createSourceMapResolver(opts: CreateSourceMapResolverOptions = {}): SourceMapResolver {\n const f = opts.fetch ?? (typeof fetch !== 'undefined' ? fetch.bind(globalThis) : null)\n const cache = new Map<string, Promise<TraceMap | null>>()\n\n function fetchTracerFor(sourceUrl: string): Promise<TraceMap | null> {\n if (!f) return Promise.resolve(null)\n const existing = cache.get(sourceUrl)\n if (existing) return existing\n const promise = (async () => {\n try {\n markSelfRequest(sourceUrl)\n const res = await f(sourceUrl)\n if (!res || !res.ok) return null\n const text = await res.text()\n const m = text.match(/\\/\\/[#@]\\s*sourceMappingURL=(.+?)\\s*$/m)\n if (!m) return null\n const ref = m[1]!.trim()\n if (ref.startsWith('data:')) {\n const commaIdx = ref.indexOf(',')\n if (commaIdx === -1) return null\n const header = ref.slice(0, commaIdx)\n const payload = ref.slice(commaIdx + 1)\n const decoded = header.includes('base64')\n ? typeof atob === 'function'\n ? atob(payload)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n : (globalThis as any).Buffer.from(payload, 'base64').toString('utf8')\n : decodeURIComponent(payload)\n return new TraceMap(JSON.parse(decoded) as RawSourceMap)\n }\n const mapUrl = new URL(ref, sourceUrl).href\n markSelfRequest(mapUrl)\n const mapRes = await f(mapUrl)\n if (!mapRes || !mapRes.ok) return null\n return new TraceMap((await mapRes.json()) as RawSourceMap)\n } catch {\n return null\n }\n })()\n cache.set(sourceUrl, promise)\n return promise\n }\n\n return {\n async resolve(frame) {\n try {\n const tracer = await fetchTracerFor(frame.file)\n if (!tracer) return frame\n return lookupFrame(tracer, frame)\n } catch {\n return frame\n }\n },\n }\n}\n\nexport function parseStack(raw: string | undefined): StackFrame[] {\n if (!raw) return []\n const frames: StackFrame[] = []\n for (const line of raw.split('\\n')) {\n const chromeMatch = line.match(CHROME_FRAME)\n if (chromeMatch) {\n const [, fnName, file, lineStr, colStr] = chromeMatch\n const frame: StackFrame = {\n file: file ?? '',\n line: Number(lineStr),\n col: Number(colStr),\n }\n if (fnName) frame.fnName = fnName\n frames.push(frame)\n continue\n }\n const firefoxMatch = line.match(FIREFOX_FRAME)\n if (firefoxMatch) {\n const [, fnName, file, lineStr, colStr] = firefoxMatch\n const frame: StackFrame = {\n file: file ?? '',\n line: Number(lineStr),\n col: Number(colStr),\n }\n if (fnName) frame.fnName = fnName\n frames.push(frame)\n }\n }\n return frames\n}\n","// Registry of URLs that react-perfscope itself fetched (source files and their\n// source maps, when resolving stack frames). The network collector consults\n// this so the tool's own traffic never shows up as one of the app's network\n// signals — measuring shouldn't report the measurer.\n\nconst selfRequests = new Set<string>()\n\n/** Record that react-perfscope is about to fetch `url`, so the network\n * collector can exclude its resource-timing entry. */\nexport function markSelfRequest(url: string): void {\n selfRequests.add(url)\n}\n\n/** True when `url` was fetched by react-perfscope itself. */\nexport function isSelfRequest(url: string): boolean {\n return selfRequests.has(url)\n}\n","import type { SignalKind } from './types'\n\nexport type Capabilities = Record<SignalKind, boolean>\n\nfunction supportedEntryTypes(): readonly string[] | undefined {\n const PO = (globalThis as { PerformanceObserver?: { supportedEntryTypes?: readonly string[] } })\n .PerformanceObserver\n return PO?.supportedEntryTypes\n}\n\n/** True unless the browser exposes `supportedEntryTypes` AND it includes none of\n * the needed entry types. An unknown environment (older browsers / test envs\n * that don't expose the list) is treated as supported, so we never falsely\n * report a feature missing — the collector's own try/catch is the backstop. */\nfunction observerSupported(needed: readonly string[]): boolean {\n const types = supportedEntryTypes()\n if (!Array.isArray(types)) return true\n return needed.some((t) => types.includes(t))\n}\n\n/** Which signal kinds the current browser can actually measure. The render and\n * forced-reflow collectors are pure JS (React fibers / DOM-API instrumentation)\n * so they work everywhere; the rest depend on PerformanceObserver entry types\n * that Firefox and Safari do not implement (long tasks, layout shift, INP). */\nexport function detectCapabilities(): Capabilities {\n return {\n 'forced-reflow': true,\n render: true,\n 'web-vital': true,\n 'layout-shift': observerSupported(['layout-shift']),\n 'long-task': observerSupported(['long-animation-frame', 'longtask']),\n interaction: observerSupported(['event']),\n network: observerSupported(['resource']),\n }\n}\n\n/** Signal kinds the current browser cannot measure — for telling the user a\n * tab is empty because of the platform, not because nothing happened. */\nexport function unsupportedKinds(): SignalKind[] {\n const caps = detectCapabilities()\n return (Object.keys(caps) as SignalKind[]).filter((k) => !caps[k])\n}\n","/** One reading of how many unmounted instances of a component are still\n * retained (alive, not yet garbage-collected) at a point in time. */\nexport type LeakSample = { at: number; retained: number }\n\n/** Minimum samples before a trend can be estimated. */\nconst MIN_SAMPLES = 4\n/** Segments to split the series into when estimating the retained floor. */\nconst FLOOR_SEGMENTS = 8\n/** Require the retained floor to climb by at least this many instances across\n * the window before flagging — a transient one or two awaiting GC is not a\n * leak. */\nconst MIN_NET_GROWTH = 3\n\nfunction slope(points: { x: number; y: number }[]): number {\n const n = points.length\n if (n < 2) return 0\n let sx = 0\n let sy = 0\n let sxy = 0\n let sxx = 0\n for (const { x, y } of points) {\n sx += x\n sy += y\n sxy += x * y\n sxx += x * x\n }\n const denom = n * sxx - sx * sx\n if (denom === 0) return 0\n return (n * sxy - sx * sy) / denom\n}\n\n/**\n * Decide whether a component's retained-instance series indicates a leak.\n *\n * Mirrors {@link analyzeHeapTrend}: GC makes the raw retained count a sawtooth\n * (instances pile up, then a sweep collects a batch), so the reliable signal is\n * the *floor* — the post-GC troughs. We segment the series, take each segment's\n * minimum, and regress those minima against time.\n *\n * A rising slope alone is not enough: a one-time step (a screen mounts N\n * long-lived instances once, then plateaus) regresses positive but is not a\n * leak. So we additionally require the recent half of the floor to still be\n * rising, and gate on a minimum net growth in instances. This is what makes the\n * detector robust to React StrictMode's intentional mount→unmount→remount\n * churn, whose discarded fibers get collected and keep the floor flat.\n *\n * Returns null when there are too few samples to say anything.\n */\nexport function analyzeLeakTrend(\n samples: LeakSample[]\n): { leaking: boolean; slopePerMin: number } | null {\n if (samples.length < MIN_SAMPLES) return null\n const t0 = samples[0]!.at\n const segSize = Math.max(1, Math.ceil(samples.length / FLOOR_SEGMENTS))\n const floorPoints: { x: number; y: number }[] = []\n for (let i = 0; i < samples.length; i += segSize) {\n const seg = samples.slice(i, i + segSize)\n let min = Infinity\n for (const s of seg) min = Math.min(min, s.retained)\n const mid = seg[Math.floor(seg.length / 2)]!\n floorPoints.push({ x: (mid.at - t0) / 60000, y: min })\n }\n const slopePerMin = slope(floorPoints)\n const spanMin = (samples[samples.length - 1]!.at - t0) / 60000\n const projectedGrowth = slopePerMin * spanMin\n const recent = floorPoints.slice(Math.floor(floorPoints.length / 2))\n const recentSlope = recent.length >= 2 ? slope(recent) : slopePerMin\n const leaking = projectedGrowth >= MIN_NET_GROWTH && recentSlope > 0\n return { leaking, slopePerMin }\n}\n","import type {\n ForcedReflowSignal,\n InteractionSignal,\n LongTaskSignal,\n RenderSignal,\n Signal,\n StackFrame,\n} from './types'\n\n/** One frame at 60fps. A commit's `at` is sampled when it completes (after its\n * layout effects), so a reflow forced during that commit finishes up to ~a\n * frame before the commit is timestamped. */\nconst FRAME_MS = 16\n\nexport type AnchorSignal = InteractionSignal | LongTaskSignal\n\n/** How strongly a member is linked to its episode anchor. `caused` means a\n * member's source location matches one of the anchor's hot frames — a real\n * causal claim. `co-occurred` means it only overlapped in time; the link is\n * temporal, not proven. The distinction keeps the tool from overclaiming. */\nexport type LinkConfidence = 'caused' | 'co-occurred'\n\n/** Which slice of an interaction's INP latency a member fell into. Only set\n * for interaction-anchored episodes; long tasks have no phase breakdown. */\nexport type InpPhase = 'input-delay' | 'processing' | 'presentation'\n\n/** Signals that carry an `at` timestamp and can be nested inside an episode.\n * Excludes the anchors themselves and signals with no point in time\n * (web-vital has no `at`; network uses `startedAt`). */\ntype MemberSignal = Exclude<Extract<Signal, { at: number }>, AnchorSignal>\n\n/** The render commit a forced reflow happened inside — the component whose\n * commit forced the synchronous layout. Set when the reflow's timestamp falls\n * within a render commit's window. */\nexport type CommitCause = {\n commitId: number\n component: string\n}\n\nexport type EpisodeMember = {\n signal: MemberSignal\n confidence: LinkConfidence\n phase?: InpPhase\n causedBy?: CommitCause\n}\n\nexport type Episode = {\n anchor: AnchorSignal\n members: EpisodeMember[]\n}\n\nfunction isAnchor(signal: Signal): signal is AnchorSignal {\n return signal.kind === 'interaction' || signal.kind === 'long-task'\n}\n\nfunction sourceKey(frame: StackFrame): string {\n return `${frame.file}:${frame.line}`\n}\n\nfunction anchorHotLocations(anchor: AnchorSignal): Set<string> {\n return new Set((anchor.attribution ?? []).map((a) => sourceKey(a.frame)))\n}\n\nfunction isMember(s: Signal, anchor: AnchorSignal): s is MemberSignal {\n return s !== anchor && s.kind !== 'interaction' && s.kind !== 'long-task' && 'at' in s\n}\n\nfunction linkConfidence(signal: MemberSignal, hotLocations: Set<string>): LinkConfidence {\n if (signal.kind === 'forced-reflow') {\n if (signal.stack.some((f) => hotLocations.has(sourceKey(f)))) return 'caused'\n }\n return 'co-occurred'\n}\n\n/** Finds the render commit that forced a reflow. A render signal's `at` is\n * sampled when the commit completes — *after* its layout effects, where forced\n * reflows happen — and its `duration` covers only the render phase, not the\n * layout work. So the triggering commit is the one that completes at or just\n * after the reflow (within a frame of the reflow finishing), not one whose\n * narrow render-phase window contains it. */\nfunction commitForReflow(reflow: ForcedReflowSignal, renders: RenderSignal[]): RenderSignal | undefined {\n const reflowEnd = reflow.at + reflow.duration\n return renders.find((r) => r.at >= reflow.at && r.at <= reflowEnd + FRAME_MS)\n}\n\nfunction inpPhaseAt(anchor: AnchorSignal, at: number): InpPhase | undefined {\n if (anchor.kind !== 'interaction') return undefined\n const processingStart = anchor.at + anchor.inputDelay\n const presentationStart = processingStart + anchor.processing\n if (at < processingStart) return 'input-delay'\n if (at < presentationStart) return 'processing'\n return 'presentation'\n}\n\nexport function correlate(signals: Signal[]): Episode[] {\n const anchors = signals.filter(isAnchor)\n\n return anchors.map((anchor) => {\n const start = anchor.at\n const end = anchor.at + anchor.duration\n const hotLocations = anchorHotLocations(anchor)\n const windowed = signals.filter(\n (s): s is MemberSignal => isMember(s, anchor) && s.at >= start && s.at <= end,\n )\n const renders = windowed.filter((s): s is RenderSignal => s.kind === 'render')\n\n const members = windowed.map((signal) => {\n const member: EpisodeMember = {\n signal,\n confidence: linkConfidence(signal, hotLocations),\n phase: inpPhaseAt(anchor, signal.at),\n }\n if (signal.kind === 'forced-reflow') {\n const commit = commitForReflow(signal, renders)\n if (commit) {\n member.confidence = 'caused'\n member.causedBy = { commitId: commit.commitId, component: commit.component }\n }\n }\n return member\n })\n\n return { anchor, members }\n })\n}\n","import type { Collector, LongTaskScript, Signal } from '../types'\n\nconst LOAF = 'long-animation-frame'\nconst LEGACY = 'longtask'\n\n/** A single script entry inside a Long Animation Frame. */\ninterface ScriptTiming {\n duration?: number\n invoker?: string\n invokerType?: string\n sourceURL?: string\n sourceFunctionName?: string\n sourceCharPosition?: number\n}\n\ninterface LoAFEntry extends PerformanceEntry {\n blockingDuration?: number\n scripts?: ScriptTiming[]\n}\n\nfunction supportsLoAF(): boolean {\n const PO = (globalThis as { PerformanceObserver?: { supportedEntryTypes?: readonly string[] } })\n .PerformanceObserver\n const types = PO?.supportedEntryTypes\n return Array.isArray(types) && types.includes(LOAF)\n}\n\nfunction mapScripts(scripts: ScriptTiming[]): LongTaskScript[] {\n return scripts.map((s) => ({\n invokerType: s.invokerType ?? 'unknown',\n invoker: s.invoker ?? '',\n sourceURL: s.sourceURL ?? '',\n sourceFunctionName: s.sourceFunctionName ?? '',\n charPosition: typeof s.sourceCharPosition === 'number' ? s.sourceCharPosition : -1,\n duration: typeof s.duration === 'number' ? s.duration : 0,\n }))\n}\n\nexport function createLongTasksCollector(): Collector {\n let observer: PerformanceObserver | null = null\n let active = false\n\n return {\n kind: 'long-task',\n activate(emit: (signal: Signal) => void) {\n if (typeof PerformanceObserver === 'undefined') {\n console.warn('[react-perfscope] PerformanceObserver not supported; long-tasks disabled')\n return\n }\n active = true\n const useLoAF = supportsLoAF()\n try {\n observer = new PerformanceObserver((list) => {\n if (!active) return\n for (const entry of list.getEntries()) {\n if (useLoAF) {\n const loaf = entry as LoAFEntry\n const scripts = Array.isArray(loaf.scripts) ? mapScripts(loaf.scripts) : []\n emit({\n kind: 'long-task',\n at: entry.startTime,\n duration: entry.duration,\n stack: [],\n scripts,\n ...(typeof loaf.blockingDuration === 'number'\n ? { blockingDuration: loaf.blockingDuration }\n : {}),\n })\n } else {\n emit({\n kind: 'long-task',\n at: entry.startTime,\n duration: entry.duration,\n stack: [],\n })\n }\n }\n })\n observer.observe({ type: useLoAF ? LOAF : LEGACY, buffered: false })\n } catch (err) {\n console.warn('[react-perfscope] long-tasks collector failed to start:', err)\n observer = null\n active = false\n }\n },\n deactivate() {\n active = false\n if (observer) {\n try {\n observer.disconnect()\n } catch {\n // ignore\n }\n observer = null\n }\n },\n }\n}\n","import type { Collector, Signal } from '../types'\nimport { attachLazyStack } from '../sourcemap'\n\nconst LAYOUT_GETTERS = [\n 'offsetWidth',\n 'offsetHeight',\n 'offsetLeft',\n 'offsetTop',\n 'clientWidth',\n 'clientHeight',\n 'scrollWidth',\n 'scrollHeight',\n] as const\n\nconst LAYOUT_METHODS = ['getBoundingClientRect', 'getClientRects'] as const\n\ntype SavedDescriptor = {\n proto: object\n key: string\n descriptor: PropertyDescriptor\n}\n\ntype OpenGroup = {\n at: number\n duration: number\n count: number\n rawStack: string | undefined\n}\n\n// Close the coalescing window at the end of the current synchronous turn.\n// queueMicrotask runs after the running task drains, so a layout-thrash loop\n// (read offsetWidth N times in one turn) collapses into a single group.\nconst scheduleFlush: (cb: () => void) => void =\n typeof queueMicrotask === 'function'\n ? queueMicrotask\n : typeof Promise !== 'undefined'\n ? (cb) => {\n Promise.resolve().then(cb)\n }\n : (cb) => cb()\n\nexport function createForcedReflowCollector(): Collector {\n let active = false\n let emit: (s: Signal) => void = () => {}\n const saved: SavedDescriptor[] = []\n let mutationObserver: MutationObserver | null = null\n let group: OpenGroup | null = null\n\n function consumePendingMutations(): boolean {\n if (!mutationObserver) {\n // Fallback when MutationObserver isn't available: always treat as dirty\n // (Phase 1 over-report behavior).\n return true\n }\n return mutationObserver.takeRecords().length > 0\n }\n\n function flush() {\n if (!group) return\n const g = group\n group = null\n const signal = {\n kind: 'forced-reflow' as const,\n at: g.at,\n duration: g.duration,\n count: g.count,\n } as unknown as Signal\n attachLazyStack(signal, g.rawStack, 1)\n emit(signal)\n }\n\n // A layout read happened while recording and layout was dirty. Open a group\n // on the first such read of the turn, then just accumulate count/duration for\n // the rest of the turn. `rawStack` is captured by the caller (the patched\n // accessor) so the stack's top user frame stays at a fixed depth — passing it\n // through a helper would add a frame and misattribute the reflow to this file.\n function record(at: number, duration: number, rawStack: string | undefined) {\n if (group) {\n group.count++\n group.duration += duration\n return\n }\n group = { at, duration, count: 1, rawStack }\n scheduleFlush(flush)\n }\n\n // True when the next dirty read opens a fresh group and so needs a stack.\n // Lets the accessor skip `new Error().stack` (the dominant cost) on the\n // subsequent reads it coalesces into an already-open group.\n function needsStack(): boolean {\n return group === null\n }\n\n function patchGetter(proto: object, key: string) {\n if (typeof proto !== 'object' || proto === null) return\n const desc = Object.getOwnPropertyDescriptor(proto, key)\n if (!desc || !desc.get) return\n saved.push({ proto, key, descriptor: desc })\n const originalGet = desc.get\n Object.defineProperty(proto, key, {\n configurable: true,\n get(this: unknown) {\n if (active) {\n if (!consumePendingMutations()) {\n return originalGet.call(this)\n }\n const rawStack = needsStack() ? new Error().stack : undefined\n const at = performance.now()\n const value = originalGet.call(this)\n record(at, performance.now() - at, rawStack)\n return value\n }\n return originalGet.call(this)\n },\n set: desc.set,\n })\n }\n\n function patchMethod(proto: object, key: string) {\n if (typeof proto !== 'object' || proto === null) return\n const desc = Object.getOwnPropertyDescriptor(proto, key)\n if (!desc || typeof desc.value !== 'function') return\n saved.push({ proto, key, descriptor: desc })\n const original = desc.value as (...args: unknown[]) => unknown\n Object.defineProperty(proto, key, {\n configurable: true,\n writable: true,\n value: function patchedLayoutMethod(this: unknown, ...args: unknown[]) {\n if (active) {\n if (!consumePendingMutations()) {\n return original.apply(this, args)\n }\n const rawStack = needsStack() ? new Error().stack : undefined\n const at = performance.now()\n const value = original.apply(this, args)\n record(at, performance.now() - at, rawStack)\n return value\n }\n return original.apply(this, args)\n },\n })\n }\n\n return {\n kind: 'forced-reflow',\n activate(emitFn) {\n if (active) return\n emit = emitFn\n active = true\n\n if (typeof MutationObserver !== 'undefined' && typeof document !== 'undefined') {\n try {\n mutationObserver = new MutationObserver(() => {})\n mutationObserver.observe(document, {\n attributes: true,\n childList: true,\n subtree: true,\n characterData: true,\n })\n } catch (err) {\n console.warn('[react-perfscope] forced-reflow MutationObserver failed:', err)\n mutationObserver = null\n }\n }\n\n if (typeof HTMLElement !== 'undefined') {\n for (const key of LAYOUT_GETTERS) {\n patchGetter(HTMLElement.prototype, key)\n }\n }\n if (typeof Element !== 'undefined') {\n for (const key of LAYOUT_METHODS) {\n patchMethod(Element.prototype, key)\n }\n }\n },\n deactivate() {\n if (!active) return\n active = false\n // Emit any group still open before the scheduled microtask runs, so the\n // last burst isn't lost when stop() is called mid-turn.\n flush()\n if (mutationObserver) {\n try {\n mutationObserver.disconnect()\n } catch {\n // ignore\n }\n mutationObserver = null\n }\n for (const { proto, key, descriptor } of saved) {\n Object.defineProperty(proto, key, descriptor)\n }\n saved.length = 0\n },\n }\n}\n","import type { Collector, Signal } from '../types'\n\ninterface LayoutShiftSource {\n currentRect: DOMRect\n previousRect?: DOMRect\n node?: Node | null\n}\n\ninterface LayoutShiftEntryLike extends PerformanceEntry {\n value: number\n hadRecentInput: boolean\n sources?: LayoutShiftSource[]\n}\n\nconst PERFSCOPE_HOST_ATTR = 'data-perfscope-host'\n\nfunction rectsOverlap(a: DOMRect, b: DOMRect, tolerance = 0): boolean {\n return !(\n a.x + a.width < b.x - tolerance ||\n b.x + b.width < a.x - tolerance ||\n a.y + a.height < b.y - tolerance ||\n b.y + b.height < a.y - tolerance\n )\n}\n\n/**\n * Returns true when every source in the entry is part of our floating\n * widget. We want to ignore shifts caused by the perfscope UI itself.\n *\n * Detection has two paths:\n * 1. Node-based: walk up `source.node` looking for `[data-perfscope-host]`.\n * Works when the node is in light DOM.\n * 2. Rect-based fallback: compare `source.currentRect` against every host\n * element's bounding rect. This catches the Shadow-DOM case where the\n * browser doesn't expose the inner node (Shadow root boundary).\n */\nfunction collectPerfscopeRects(): DOMRect[] {\n const hosts = Array.from(document.querySelectorAll(`[${PERFSCOPE_HOST_ATTR}]`))\n const rects: DOMRect[] = []\n for (const h of hosts) {\n // The light-DOM host element usually has height 0 because Shadow DOM\n // content isn't part of its layout. We need to peek inside the shadow\n // root and collect bounds of any positioned children.\n const sr = (h as Element & { shadowRoot?: ShadowRoot | null }).shadowRoot\n if (sr) {\n for (const child of Array.from(sr.children)) {\n const r = (child as Element).getBoundingClientRect()\n if (r.width > 0 && r.height > 0) rects.push(r)\n }\n } else {\n const r = h.getBoundingClientRect()\n if (r.width > 0 && r.height > 0) rects.push(r)\n }\n }\n return rects\n}\n\nfunction entryIsOnlyFromPerfscope(sources: LayoutShiftSource[]): boolean {\n if (sources.length === 0) return false\n if (typeof document === 'undefined') return false\n\n const hostRects = collectPerfscopeRects()\n if (hostRects.length === 0) return false\n\n for (const src of sources) {\n let matched = false\n const node = src.node as (Node & { closest?: (sel: string) => Element | null }) | null | undefined\n if (node) {\n // Node-based check\n if (typeof (node as { closest?: unknown }).closest === 'function') {\n if ((node as Element).closest(`[${PERFSCOPE_HOST_ATTR}]`)) matched = true\n } else {\n let parent: (Element | null) = (node as Node).parentElement as Element | null\n while (parent) {\n if (parent.hasAttribute(PERFSCOPE_HOST_ATTR)) { matched = true; break }\n parent = parent.parentElement\n }\n }\n }\n // Rect-based fallback (shadow DOM): if source rect overlaps any of our\n // host rects, consider it our widget. Tolerance covers the case where\n // the widget changes size during the shift (its previous/current bounds\n // differ but both sit in the same screen corner).\n if (!matched) {\n for (const hostRect of hostRects) {\n if (rectsOverlap(src.currentRect, hostRect, 24)) {\n matched = true\n break\n }\n }\n }\n if (!matched) return false\n }\n return true\n}\n\nexport function createLayoutShiftCollector(): Collector {\n let observer: PerformanceObserver | null = null\n let active = false\n\n return {\n kind: 'layout-shift',\n activate(emit: (signal: Signal) => void) {\n if (typeof PerformanceObserver === 'undefined') {\n console.warn('[react-perfscope] PerformanceObserver not supported; layout-shift disabled')\n return\n }\n active = true\n try {\n observer = new PerformanceObserver((list) => {\n if (!active) return\n for (const raw of list.getEntries()) {\n const entry = raw as LayoutShiftEntryLike\n // Note: production CLS metrics exclude shifts with hadRecentInput\n // (user-initiated movements are considered intentional). For a\n // dev tool, the user explicitly WANTS to see what their clicks\n // caused — so we report these too.\n const sources = entry.sources ?? []\n if (entryIsOnlyFromPerfscope(sources)) continue\n // Convert viewport-relative rects to document-relative coords so\n // overlays stay anchored to the shifted DOM position when the\n // user scrolls. Filter above runs first on viewport coords (our\n // widget is position:fixed, lives in viewport space).\n const sx = (typeof window !== 'undefined' && window.scrollX) || 0\n const sy = (typeof window !== 'undefined' && window.scrollY) || 0\n const toDocRect = (r: DOMRect) =>\n new DOMRect(r.x + sx, r.y + sy, r.width, r.height)\n const rects = sources.map((s) => toDocRect(s.currentRect))\n // previousRect is undefined when the element was newly inserted.\n // An \"empty\" rect (w=0, h=0) likewise means there was no prior\n // box — treat both as `null` so the overlay can decide not to\n // draw an arrow for these.\n const prevRects: (DOMRect | null)[] = sources.map((s) => {\n const pr = s.previousRect\n if (!pr) return null\n if (pr.width === 0 && pr.height === 0) return null\n return toDocRect(pr)\n })\n emit({\n kind: 'layout-shift',\n at: entry.startTime,\n value: entry.value,\n sources: rects,\n previousSources: prevRects,\n })\n }\n })\n observer.observe({ type: 'layout-shift', buffered: false })\n } catch (err) {\n console.warn('[react-perfscope] layout-shift collector failed to start:', err)\n observer = null\n active = false\n }\n },\n deactivate() {\n active = false\n if (observer) {\n try {\n observer.disconnect()\n } catch {\n // ignore\n }\n observer = null\n }\n },\n }\n}\n","import type { Collector, Signal } from '../types'\nimport { isSelfRequest } from '../self-requests'\n\ninterface ResourceTimingLike extends PerformanceEntry {\n transferSize?: number\n renderBlockingStatus?: 'blocking' | 'non-blocking'\n}\n\nexport function createNetworkCollector(): Collector {\n let observer: PerformanceObserver | null = null\n let active = false\n\n return {\n kind: 'network',\n activate(emit: (signal: Signal) => void) {\n if (typeof PerformanceObserver === 'undefined') {\n console.warn('[react-perfscope] PerformanceObserver not supported; network disabled')\n return\n }\n active = true\n try {\n observer = new PerformanceObserver((list) => {\n if (!active) return\n for (const raw of list.getEntries()) {\n const entry = raw as ResourceTimingLike\n // Skip react-perfscope's own traffic (source-map fetches).\n if (isSelfRequest(entry.name)) continue\n emit({\n kind: 'network',\n url: entry.name,\n startedAt: entry.startTime,\n duration: entry.duration,\n size: entry.transferSize ?? 0,\n blocking: entry.renderBlockingStatus === 'blocking',\n })\n }\n })\n observer.observe({ type: 'resource', buffered: false })\n } catch (err) {\n console.warn('[react-perfscope] network collector failed to start:', err)\n observer = null\n active = false\n }\n },\n deactivate() {\n active = false\n if (observer) {\n try {\n observer.disconnect()\n } catch {\n // ignore\n }\n observer = null\n }\n },\n }\n}\n","import { onLCP, onINP, onCLS, onFCP, onTTFB, type Metric } from 'web-vitals'\nimport type { Collector, Signal, WebVitalSignal } from '../types'\n\ntype VitalName = WebVitalSignal['name']\ntype Sink = (name: VitalName, value: number) => void\n\n// The web-vitals library exposes no unsubscribe, and some metrics (LCP, FCP,\n// TTFB) only report once per page — so the module subscribes exactly once and\n// fans metrics out to whichever collector instances are currently active.\n// Per-instance subscriptions would both leak permanent handlers on every new\n// recorder and starve later instances of already-finalized metrics.\nlet subscribed = false\nconst sinks = new Set<Sink>()\n\nfunction ensureSubscribed(): boolean {\n if (subscribed) return true\n try {\n const fan = (name: VitalName) => (metric: Metric) => {\n for (const sink of sinks) sink(name, metric.value)\n }\n onLCP(fan('LCP'))\n onINP(fan('INP'))\n onCLS(fan('CLS'))\n onFCP(fan('FCP'))\n onTTFB(fan('TTFB'))\n subscribed = true\n } catch (err) {\n console.warn('[react-perfscope] web-vitals collector failed to subscribe:', err)\n }\n return subscribed\n}\n\nexport function createWebVitalsCollector(): Collector {\n let emit: (signal: Signal) => void = () => {}\n const sink: Sink = (name, value) => {\n emit({ kind: 'web-vital', name, value })\n }\n\n return {\n kind: 'web-vital',\n activate(emitFn) {\n if (!ensureSubscribed()) return\n emit = emitFn\n sinks.add(sink)\n },\n deactivate() {\n sinks.delete(sink)\n },\n }\n}\n","import type {\n Collector,\n HeapSample,\n HeapTrend,\n HeapTrendClass,\n RecordingResult,\n} from '../types'\n\n/** How often to read heap usage while recording. Reading performance.memory\n * is cheap, so we sample at 4Hz: a 1s cadence is too coarse — short spikes fall\n * between samples and the line, drawn straight between sparse points, smooths\n * them into a ramp. 250ms localizes spikes without meaningful overhead. */\nconst SAMPLE_INTERVAL_MS = 250\n/** Cap on retained samples so a multi-hour session can't grow the array\n * unbounded. At 250ms this is ~83 min; past that, oldest samples drop. */\nconst MAX_SAMPLES = 20_000\n\n/** Below this, a trend can't be estimated reliably. */\nconst MIN_SAMPLES = 4\n/** How many contiguous segments to split the series into when estimating the\n * floor. Each segment contributes its minimum (the post-GC trough). */\nconst FLOOR_SEGMENTS = 8\n\nconst MB = 1024 * 1024\n/** Floor-growth thresholds, in bytes per minute. */\nconst GROWING_SLOPE = 1 * MB\nconst LEAK_SLOPE = 5 * MB\n/** A rate alone isn't enough: over a short recording, a sub-megabyte wobble in\n * the floor extrapolates to a huge MB/min and would false-positive. Require the\n * floor to have actually risen by at least this much across the window before\n * calling anything growing/leaking. */\nconst MIN_NET_GROWTH = 2 * MB\n\ninterface MemoryInfo {\n usedJSHeapSize: number\n totalJSHeapSize: number\n jsHeapSizeLimit: number\n}\n\nfunction readMemory(): MemoryInfo | null {\n const perf = (globalThis as { performance?: { memory?: MemoryInfo } }).performance\n const mem = perf?.memory\n if (!mem || typeof mem.usedJSHeapSize !== 'number') return null\n return mem\n}\n\n/**\n * Least-squares slope of points (x, y). Returns 0 when x has no spread\n * (vertical / single distinct x) to avoid a divide-by-zero blow-up.\n */\nfunction slope(points: { x: number; y: number }[]): number {\n const n = points.length\n if (n < 2) return 0\n let sx = 0\n let sy = 0\n let sxy = 0\n let sxx = 0\n for (const { x, y } of points) {\n sx += x\n sy += y\n sxy += x * y\n sxx += x * x\n }\n const denom = n * sxx - sx * sx\n if (denom === 0) return 0\n return (n * sxy - sx * sy) / denom\n}\n\n/**\n * Estimate whether memory is being retained across the recording.\n *\n * GC makes raw heap usage a sawtooth, so the peak is noisy. The reliable\n * signal is the *floor* — the post-GC troughs. We split the series into\n * contiguous segments, take the minimum of each (its trough), and regress\n * those minima against time.\n *\n * A rising overall slope is necessary but NOT sufficient: a one-time step\n * (heap warms up early, then plateaus) also regresses to a positive slope, and\n * flagging that as a leak is a false positive — the classic \"idle recording\n * reads abnormal\" bug. A real leak keeps climbing, so we additionally require\n * the *recent* half of the floor to still be rising. We also gate on a minimum\n * net growth, since over a short window a sub-MB wobble extrapolates to a steep\n * per-minute slope.\n *\n * Returns null when there are too few samples to say anything.\n */\nexport function analyzeHeapTrend(samples: HeapSample[]): HeapTrend | null {\n if (samples.length < MIN_SAMPLES) return null\n const t0 = samples[0]!.at\n const segSize = Math.max(1, Math.ceil(samples.length / FLOOR_SEGMENTS))\n const floorPoints: { x: number; y: number }[] = []\n for (let i = 0; i < samples.length; i += segSize) {\n const seg = samples.slice(i, i + segSize)\n let min = Infinity\n for (const s of seg) min = Math.min(min, s.used)\n const mid = seg[Math.floor(seg.length / 2)]!\n floorPoints.push({ x: (mid.at - t0) / 60000, y: min })\n }\n const slopeBytesPerMin = slope(floorPoints)\n const spanMin = (samples[samples.length - 1]!.at - t0) / 60000\n const projectedGrowth = slopeBytesPerMin * spanMin\n // Recent trend: is the floor still climbing in the latter half? Distinguishes\n // a sustained leak from a one-time step that has since plateaued.\n const recent = floorPoints.slice(Math.floor(floorPoints.length / 2))\n const recentSlope = recent.length >= 2 ? slope(recent) : slopeBytesPerMin\n\n let classification: HeapTrendClass = 'stable'\n const sustained = projectedGrowth >= MIN_NET_GROWTH && recentSlope >= GROWING_SLOPE\n if (sustained) {\n classification =\n slopeBytesPerMin >= LEAK_SLOPE && recentSlope >= LEAK_SLOPE ? 'leak-suspected' : 'growing'\n }\n return { classification, slopeBytesPerMin }\n}\n\nexport interface HeapCollector extends Collector {\n /** Attach the sampled heap series to the recording result. Returns the\n * input untouched when nothing was sampled (unsupported browser). */\n finalize(result: RecordingResult): RecordingResult\n}\n\n/**\n * Samples `performance.memory` on an interval for the duration of a recording\n * and attaches the series via `finalize`. It is a Collector so the recorder\n * drives its start/stop, but it emits no signals — the series is a separate\n * track (see RecordingResult.heapSamples), so a busy session's signal buffer\n * can't evict it. No-ops entirely when performance.memory is unavailable\n * (non-Chromium), leaving `heapSamples` absent so the UI can show a fallback.\n */\nexport function createHeapCollector(): HeapCollector {\n let samples: HeapSample[] = []\n let timer: ReturnType<typeof setInterval> | null = null\n\n function sample(): void {\n const mem = readMemory()\n if (!mem) return\n samples.push({ at: performance.now(), used: mem.usedJSHeapSize, total: mem.totalJSHeapSize })\n if (samples.length > MAX_SAMPLES) samples.splice(0, samples.length - MAX_SAMPLES)\n }\n\n return {\n kind: 'heap',\n activate() {\n samples = []\n if (!readMemory()) return // unsupported → never start the timer\n sample()\n timer = setInterval(sample, SAMPLE_INTERVAL_MS)\n },\n deactivate() {\n if (timer == null) return\n clearInterval(timer)\n timer = null\n sample() // one final reading at stop\n },\n finalize(result) {\n if (samples.length === 0) return result\n return { ...result, heapSamples: samples.slice() }\n },\n }\n}\n","import type { Collector, InteractionSignal, RecordingResult } from '../types'\n\n/** Event Timing only surfaces events at/over this duration (ms); 40ms keeps\n * trivial interactions out while still catching anything a user would feel. */\nconst DURATION_THRESHOLD = 40\n\n/** Each buffered entry retains its `target` DOM node, so the buffer must stay\n * bounded even during very long recordings. */\nconst MAX_ENTRIES = 5000\n\ninterface EventTimingEntry extends PerformanceEntry {\n processingStart: number\n processingEnd: number\n interactionId?: number\n target?: unknown\n}\n\nfunction selectorFor(target: unknown): string | undefined {\n const el = target as { tagName?: string; id?: string; className?: unknown } | null\n if (!el || typeof el.tagName !== 'string') return undefined\n let s = el.tagName.toLowerCase()\n if (el.id) s += `#${el.id}`\n else if (typeof el.className === 'string' && el.className.trim()) {\n s += `.${el.className.trim().split(/\\s+/)[0]}`\n }\n return s\n}\n\nfunction supportsEventTiming(): boolean {\n const PO = (globalThis as { PerformanceObserver?: { supportedEntryTypes?: readonly string[] } })\n .PerformanceObserver\n const types = PO?.supportedEntryTypes\n // happy-dom / older browsers may not expose supportedEntryTypes; if the\n // observer exists at all we still try, and observe() throwing is caught.\n return !types || types.includes('event')\n}\n\nexport interface InteractionCollector extends Collector {\n /** Group buffered Event Timing entries into one interaction each and append\n * them to the result. Returns the input untouched when none qualified. */\n finalize(result: RecordingResult): RecordingResult\n}\n\n/**\n * Records Event Timing entries during a recording and, on finalize, turns each\n * user interaction (grouped by interactionId) into one signal carrying the INP\n * latency breakdown: input delay → processing → presentation. The longest\n * event in a group defines the interaction's latency (matching how INP is\n * attributed). Emits no live signals — interactions are assembled at finalize,\n * then the self-profiling collector attributes the processing window to the\n * developer's hot functions.\n */\nexport function createInteractionCollector(): InteractionCollector {\n let active = false\n let observer: PerformanceObserver | null = null\n let entries: EventTimingEntry[] = []\n\n return {\n kind: 'interaction',\n activate() {\n if (typeof PerformanceObserver === 'undefined' || !supportsEventTiming()) return\n active = true\n entries = []\n try {\n observer = new PerformanceObserver((list) => {\n if (!active) return\n for (const e of list.getEntries()) {\n if (entries.length >= MAX_ENTRIES) break\n entries.push(e as EventTimingEntry)\n }\n })\n // `event` covers all interaction events; `first-input` guarantees the\n // first one even if it's under the duration threshold.\n observer.observe({ type: 'event', buffered: false, durationThreshold: DURATION_THRESHOLD } as PerformanceObserverInit)\n try {\n observer.observe({ type: 'first-input', buffered: false } as PerformanceObserverInit)\n } catch {\n // first-input not supported everywhere; the event stream is enough.\n }\n } catch (err) {\n console.warn('[react-perfscope] interaction collector failed to start:', err)\n observer = null\n active = false\n }\n },\n deactivate() {\n active = false\n if (observer) {\n try {\n observer.disconnect()\n } catch {\n // ignore\n }\n observer = null\n }\n },\n finalize(result) {\n // Consume the buffer: entries reference `target` DOM nodes, and the\n // recorder finalizes after stop — holding them past this point would\n // pin interacted (possibly detached) elements until the next recording.\n const buffered = entries\n entries = []\n const byId = new Map<number, EventTimingEntry[]>()\n for (const e of buffered) {\n const id = e.interactionId\n if (!id) continue // 0 / undefined → not part of a discrete interaction\n const group = byId.get(id)\n if (group) group.push(e)\n else byId.set(id, [e])\n }\n const interactions: InteractionSignal[] = []\n for (const group of byId.values()) {\n // All events of one interaction (pointerdown/up/click) report the same\n // `duration` (the whole interaction latency), so the breakdown can't\n // come from a single event. Span the processing across the group:\n // earliest processingStart → latest processingEnd (matches web-vitals).\n // The \"defining\" event for label/target is the one with the most\n // processing — typically the click/keydown that actually ran handlers.\n let duration = 0\n let startTime = Infinity\n let processingStart = Infinity\n let processingEnd = -Infinity\n let defining = group[0]!\n let maxProcessing = -Infinity\n for (const e of group) {\n if (e.duration > duration) duration = e.duration\n if (e.startTime < startTime) startTime = e.startTime\n if (e.processingStart < processingStart) processingStart = e.processingStart\n if (e.processingEnd > processingEnd) processingEnd = e.processingEnd\n const proc = e.processingEnd - e.processingStart\n if (proc > maxProcessing) {\n maxProcessing = proc\n defining = e\n }\n }\n if (duration < DURATION_THRESHOLD) continue\n const inputDelay = Math.max(0, processingStart - startTime)\n const processing = Math.max(0, processingEnd - processingStart)\n const presentation = Math.max(0, startTime + duration - processingEnd)\n interactions.push({\n kind: 'interaction',\n at: startTime,\n eventType: defining.name,\n ...(selectorFor(defining.target) ? { target: selectorFor(defining.target) } : {}),\n duration,\n inputDelay,\n processing,\n presentation,\n })\n }\n if (interactions.length === 0) return result\n interactions.sort((a, b) => a.at - b.at)\n return { ...result, signals: [...result.signals, ...interactions] }\n },\n }\n}\n","import type { Collector, FpsSample, FrameStats, RecordingResult } from '../types'\n\n/** 60fps frame budget (ms). Gaps are scored against this to count drops. */\nconst FRAME_BUDGET = 1000 / 60\n/** Window for the FPS series; 500ms smooths per-frame noise while still showing\n * a scroll-jank dip. */\nconst BUCKET_MS = 500\n/** A trailing window shorter than this is too small to estimate FPS reliably. */\nconst MIN_BUCKET_SPAN = 100\n/** Below this we can't say anything useful. */\nconst MIN_FRAMES = 8\n/** Cap retained frames so a long session can't grow the array unbounded\n * (~5.5 min at 60fps); past that, oldest drop. */\nconst MAX_FRAMES = 20_000\n\n/**\n * Turn raw requestAnimationFrame timestamps into a frame-rate picture:\n * a windowed FPS series, the lowest sustained FPS, the worst single hitch,\n * and an approximate dropped-frame count. Long tasks (>50ms) show up here as\n * big gaps, but so does sustained scroll jank (30–50ms frames) that the\n * long-task collector's threshold misses.\n *\n * Returns null when there are too few frames to analyze.\n */\nexport function analyzeFrames(frames: number[]): FrameStats | null {\n if (frames.length < MIN_FRAMES) return null\n\n let longestFrameMs = 0\n let droppedFrames = 0\n for (let i = 1; i < frames.length; i++) {\n const gap = frames[i]! - frames[i - 1]!\n if (gap > longestFrameMs) longestFrameMs = gap\n const dropped = Math.round(gap / FRAME_BUDGET) - 1\n if (dropped > 0) droppedFrames += dropped\n }\n\n const t0 = frames[0]!\n const end = frames[frames.length - 1]!\n const series: FpsSample[] = []\n let minFps = Infinity\n let idx = 0\n for (let bStart = t0; bStart < end; bStart += BUCKET_MS) {\n const bEnd = Math.min(bStart + BUCKET_MS, end)\n const span = bEnd - bStart\n let count = 0\n while (idx < frames.length && frames[idx]! < bEnd) {\n count++\n idx++\n }\n if (span < MIN_BUCKET_SPAN) break // skip a tiny trailing window\n const fps = count / (span / 1000)\n series.push({ at: bStart + span / 2, fps })\n if (fps < minFps) minFps = fps\n }\n if (series.length === 0) return null\n return { series, minFps, longestFrameMs, droppedFrames }\n}\n\nexport interface FrameCollector extends Collector {\n /** Attach the captured frame timestamps to the result. Returns the input\n * untouched when too few frames were seen (or rAF was unavailable). */\n finalize(result: RecordingResult): RecordingResult\n}\n\n/**\n * Records requestAnimationFrame timestamps for the duration of a recording so\n * the UI can chart frame rate and surface jank. Emits no signals — the\n * timestamps are a side track attached at finalize. No-ops when\n * requestAnimationFrame is unavailable (non-DOM environments).\n */\nexport function createFrameCollector(): FrameCollector {\n let active = false\n let rafId: number | null = null\n let frames: number[] = []\n\n function loop(t: number): void {\n if (!active) return\n frames.push(t)\n if (frames.length > MAX_FRAMES) frames.splice(0, frames.length - MAX_FRAMES)\n rafId = requestAnimationFrame(loop)\n }\n\n return {\n kind: 'frame',\n activate() {\n if (typeof requestAnimationFrame === 'undefined') return\n active = true\n frames = []\n rafId = requestAnimationFrame(loop)\n },\n deactivate() {\n active = false\n if (rafId != null && typeof cancelAnimationFrame !== 'undefined') {\n try {\n cancelAnimationFrame(rafId)\n } catch {\n // ignore\n }\n }\n rafId = null\n },\n finalize(result) {\n if (frames.length < MIN_FRAMES) return result\n return { ...result, frames: frames.slice() }\n },\n }\n}\n","import type { Collector, LongTaskAttribution, RecordingResult, Signal, StackFrame } from '../types'\n\n/**\n * JS Self-Profiling API trace shape (the subset we consume).\n * @see https://wicg.github.io/js-self-profiling/\n */\nexport interface ProfilerFrame {\n name?: string\n resourceId?: number\n line?: number\n column?: number\n}\nexport interface ProfilerStack {\n frameId: number\n parentId?: number\n}\nexport interface ProfilerSample {\n /** DOMHighResTimeStamp, same clock as performance.now() / entry.startTime. */\n timestamp: number\n stackId?: number\n}\nexport interface ProfilerTrace {\n resources: string[]\n frames: ProfilerFrame[]\n stacks: ProfilerStack[]\n samples: ProfilerSample[]\n}\n\ninterface ProfilerInstance {\n stop(): Promise<ProfilerTrace>\n}\ninterface ProfilerCtor {\n new (opts: { sampleInterval: number; maxBufferSize: number }): ProfilerInstance\n}\n\n/** Default sampling cadence. The browser may coarsen this. */\nconst SAMPLE_INTERVAL_MS = 10\nconst MAX_BUFFER_SIZE = 100_000\n/** Keep the noisiest few; deeper tails rarely help the developer. */\nconst MAX_FRAMES_PER_TASK = 5\n\n/**\n * Whether a resource URL belongs to the developer's own source (vs. a\n * dependency or tooling shim). Dependency frames are noise when the question\n * is \"which of MY functions is slow\".\n */\nexport function isUserResource(url: string | undefined): boolean {\n if (!url) return false\n if (url.includes('/node_modules/')) return false\n // Vite/dev tooling virtual modules: /@vite/client, /@react-refresh, /@id/...\n try {\n const path = new URL(url).pathname\n if (path.startsWith('/@')) return false\n } catch {\n if (url.startsWith('/@')) return false\n }\n return true\n}\n\nfunction frameToStackFrame(trace: ProfilerTrace, frame: ProfilerFrame): StackFrame {\n const file = frame.resourceId != null ? (trace.resources[frame.resourceId] ?? '') : ''\n const sf: StackFrame = {\n file,\n line: frame.line ?? 0,\n col: frame.column ?? 0,\n }\n if (frame.name) sf.fnName = frame.name\n return sf\n}\n\n/**\n * Climb a sample's stack from the leaf toward the root, returning the first\n * (deepest) frame that lives in user source. That frame is where the\n * developer's own code was actually executing when the sample was taken.\n */\nfunction leafUserFrame(trace: ProfilerTrace, stackId: number | undefined): ProfilerFrame | null {\n let id = stackId\n let guard = 0\n while (id != null && guard++ < 1000) {\n const stack = trace.stacks[id]\n if (!stack) break\n const frame = trace.frames[stack.frameId]\n if (frame && isUserResource(trace.resources[frame.resourceId ?? -1])) {\n return frame\n }\n id = stack.parentId\n }\n return null\n}\n\n/**\n * Aggregate the hottest user-source frames among samples whose timestamp\n * falls in [start, end]. `selfRatio` is relative to ALL in-window samples\n * (including vendor-only ones), so it reflects the share of the task's\n * blocking time spent in that user function.\n */\nexport function attributeWindow(\n trace: ProfilerTrace,\n start: number,\n end: number\n): LongTaskAttribution[] {\n let total = 0\n const counts = new Map<string, { frame: StackFrame; count: number }>()\n for (const sample of trace.samples) {\n if (sample.timestamp < start || sample.timestamp > end) continue\n total++\n const frame = leafUserFrame(trace, sample.stackId)\n if (!frame) continue\n const sf = frameToStackFrame(trace, frame)\n const key = `${sf.file}:${sf.line}:${sf.col}:${sf.fnName ?? ''}`\n const entry = counts.get(key)\n if (entry) entry.count++\n else counts.set(key, { frame: sf, count: 1 })\n }\n if (total === 0) return []\n return [...counts.values()]\n .sort((a, b) => b.count - a.count)\n .slice(0, MAX_FRAMES_PER_TASK)\n .map(({ frame, count }) => ({ frame, selfRatio: count / total, sampleCount: count }))\n}\n\n/**\n * Return a copy of `signals` with each long-task signal enriched with the\n * hottest user frames sampled during its window. Long tasks with no in-window\n * user samples are left without `attribution`. Non-long-task signals pass\n * through by reference.\n */\nexport function attributeLongTaskSignals(trace: ProfilerTrace, signals: Signal[]): Signal[] {\n return signals.map((signal) => {\n if (signal.kind !== 'long-task') return signal\n const attribution = attributeWindow(trace, signal.at, signal.at + signal.duration)\n if (attribution.length === 0) return signal\n return { ...signal, attribution }\n })\n}\n\n/**\n * Like {@link attributeLongTaskSignals} but for interactions: attributes the\n * *processing* window (handlers running, `[at+inputDelay, +processing]`) to the\n * developer's hot functions — answering \"which of my code made this click\n * slow\". Input delay and presentation aren't JS-on-the-stack, so they're\n * excluded from the window.\n */\nexport function attributeInteractionSignals(trace: ProfilerTrace, signals: Signal[]): Signal[] {\n return signals.map((signal) => {\n if (signal.kind !== 'interaction') return signal\n const start = signal.at + signal.inputDelay\n const attribution = attributeWindow(trace, start, start + signal.processing)\n if (attribution.length === 0) return signal\n return { ...signal, attribution }\n })\n}\n\ninterface SelfProfilingCollector extends Collector {\n /** Stop the profiler (if running), await its trace, and return a result\n * with long-task signals enriched. Falls back to the input on any failure\n * or when the Profiler API / Document-Policy header is unavailable. */\n finalize(result: RecordingResult): Promise<RecordingResult>\n}\n\n/**\n * Collector that runs the JS Self-Profiling API across a recording and, on\n * finalize, attributes each long task to the developer's own hot functions —\n * something LoAF can't do for React-delegated events (it only sees React's\n * single root dispatcher).\n *\n * It reports `kind: 'long-task'` because it enriches that signal rather than\n * emitting its own. Requires Chromium + a `Document-Policy: js-profiling`\n * response header (the dev plugins inject it); degrades to a no-op otherwise.\n */\nexport function createSelfProfilingCollector(): SelfProfilingCollector {\n let profiler: ProfilerInstance | null = null\n let tracePromise: Promise<ProfilerTrace> | null = null\n\n return {\n kind: 'long-task',\n activate() {\n tracePromise = null\n const Ctor = (globalThis as { Profiler?: ProfilerCtor }).Profiler\n if (typeof Ctor !== 'function') return\n try {\n profiler = new Ctor({ sampleInterval: SAMPLE_INTERVAL_MS, maxBufferSize: MAX_BUFFER_SIZE })\n } catch (err) {\n // Thrown when the Document-Policy: js-profiling header is absent.\n console.warn(\n '[react-perfscope] self-profiling unavailable (needs Document-Policy: js-profiling header); long tasks keep LoAF-only attribution:',\n err\n )\n profiler = null\n }\n },\n deactivate() {\n if (!profiler) return\n try {\n tracePromise = profiler.stop()\n } catch (err) {\n console.warn('[react-perfscope] self-profiling stop failed:', err)\n tracePromise = null\n }\n profiler = null\n },\n async finalize(result: RecordingResult): Promise<RecordingResult> {\n if (!tracePromise) return result\n try {\n const trace = await tracePromise\n const signals = attributeInteractionSignals(trace, attributeLongTaskSignals(trace, result.signals))\n return { ...result, signals }\n } catch (err) {\n console.warn('[react-perfscope] self-profiling finalize failed:', err)\n return result\n } finally {\n tracePromise = null\n }\n },\n }\n}\n"],"mappings":"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","names":["MIN_SAMPLES","FLOOR_SEGMENTS","MIN_NET_GROWTH","slope","SAMPLE_INTERVAL_MS"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@react-perfscope/core",
3
- "version": "0.7.0",
3
+ "version": "0.7.1",
4
4
  "description": "Recorder and signal collectors for react-perfscope.",
5
5
  "keywords": [
6
6
  "react",