@runtimescope/sdk 0.10.6 → 0.10.7

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/transport.ts","../src/utils/id.ts","../src/interceptors/fetch.ts","../src/utils/serialize.ts","../src/interceptors/console.ts","../src/interceptors/xhr.ts","../src/interceptors/state-stores.ts","../src/interceptors/performance.ts","../src/interceptors/react-renders.ts","../src/interceptors/errors.ts","../src/interceptors/navigation.ts","../src/interceptors/clicks.ts","../src/dsn.ts"],"sourcesContent":["import { Transport, setTransportDebug } from './transport.js';\nimport { interceptFetch } from './interceptors/fetch.js';\nimport { interceptConsole } from './interceptors/console.js';\nimport { interceptXhr } from './interceptors/xhr.js';\nimport { interceptStateStores } from './interceptors/state-stores.js';\nimport { interceptPerformance } from './interceptors/performance.js';\nimport { interceptReactRenders } from './interceptors/react-renders.js';\nimport { interceptErrors } from './interceptors/errors.js';\nimport { interceptNavigation } from './interceptors/navigation.js';\nimport { interceptClicks } from './interceptors/clicks.js';\nimport { generateId, generateSessionId } from './utils/id.js';\nimport { parseDsn } from './dsn.js';\nimport type { RuntimeScopeConfig, RuntimeEvent, DomSnapshotEvent, CustomEvent, UIInteractionEvent, UserContext } from './types.js';\n\nconst SDK_VERSION = '0.10.6';\n\n// Save original console methods BEFORE interceptors patch them. The SDK uses\n// these for its own diagnostics so its messages don't loop back through the\n// console interceptor (which would emit a console event for every internal log).\nconst _origDebug = console.debug.bind(console);\nconst _origWarn = console.warn.bind(console);\n\n/**\n * Internal-only debug logging. Quiet by default — set\n * `localStorage.RUNTIMESCOPE_DEBUG = '1'` or pass `verbose: true` to\n * `RuntimeScope.init()` to see them. Most users never need to see SDK\n * lifecycle chatter, and seeing it stacks up fast in DevTools.\n */\nlet _debugEnabled = false;\nfunction _log(...args: unknown[]): void {\n if (_debugEnabled) _origDebug(...args);\n}\n\n/**\n * Always-visible warning. Reserved for things the user genuinely needs to\n * see: config mistakes, repeated init with conflicting DSN, auth failure.\n * Deduped — the same warning text only fires once per page load so a noisy\n * caller can't fill the console with the same message.\n */\nconst _warnedOnce = new Set<string>();\nfunction _warn(message: string, ...rest: unknown[]): void {\n if (_warnedOnce.has(message)) return;\n _warnedOnce.add(message);\n _origWarn(message, ...rest);\n}\n\n// --- Double-init safety: Symbol.for() originals store ---\n// Survives HMR module reloads because Symbol.for() returns the same symbol across realms.\n// True originals are saved exactly once — never overwritten by subsequent connect() calls.\nconst ORIGINALS_KEY = Symbol.for('__runtimescope_originals__');\n\ninterface SavedOriginals {\n fetch: typeof globalThis.fetch;\n xhrOpen: typeof XMLHttpRequest.prototype.open;\n xhrSend: typeof XMLHttpRequest.prototype.send;\n xhrSetRequestHeader: typeof XMLHttpRequest.prototype.setRequestHeader;\n consoleMethods: Record<string, (...args: unknown[]) => void>;\n}\n\nfunction getOrSaveOriginals(): SavedOriginals {\n const g = globalThis as Record<symbol, SavedOriginals>;\n if (!g[ORIGINALS_KEY]) {\n g[ORIGINALS_KEY] = {\n fetch: window.fetch,\n xhrOpen: XMLHttpRequest.prototype.open,\n xhrSend: XMLHttpRequest.prototype.send,\n xhrSetRequestHeader: XMLHttpRequest.prototype.setRequestHeader,\n consoleMethods: {\n log: console.log.bind(console),\n warn: console.warn.bind(console),\n error: console.error.bind(console),\n info: console.info.bind(console),\n debug: console.debug.bind(console),\n trace: console.trace.bind(console),\n },\n };\n }\n return g[ORIGINALS_KEY];\n}\n\nexport class RuntimeScope {\n private static transport: Transport | null = null;\n private static restoreFns: (() => void)[] = [];\n private static _sessionId: string | null = null;\n private static _state: 'stopped' | 'started' = 'stopped';\n /** Cached config fingerprint from the last init() call — used to detect double-init with conflicting config. */\n private static _initSignature: string | null = null;\n private static _sampleRate: number = 1;\n private static _maxEventsPerSecond: number | undefined;\n private static _windowCount = 0;\n private static _windowStart = 0;\n private static _user: UserContext | undefined;\n\n static get sessionId(): string | null {\n return this._sessionId;\n }\n\n /** Returns true if the SDK is currently connected */\n static get isConnected(): boolean {\n return this._state === 'started';\n }\n\n /** Probabilistic + rate-limit sampling. Returns true if the event should be sent. */\n private static shouldSample(): boolean {\n // Probabilistic sampling\n if (this._sampleRate < 1 && Math.random() > this._sampleRate) {\n return false;\n }\n // Rate limiting\n if (this._maxEventsPerSecond !== undefined) {\n const now = Date.now();\n if (now - this._windowStart >= 1000) {\n this._windowCount = 0;\n this._windowStart = now;\n }\n if (this._windowCount >= this._maxEventsPerSecond) {\n return false;\n }\n this._windowCount++;\n }\n return true;\n }\n\n static connect(config: RuntimeScopeConfig = {}): void {\n if (config.enabled === false) return;\n\n // DSN resolution: single string replaces projectId + endpoint + appName\n let hasDsn = false;\n if (config.dsn) {\n try {\n const parsed = parseDsn(config.dsn);\n config = {\n ...config,\n serverUrl: parsed.wsEndpoint,\n projectId: parsed.projectId,\n // DSN-embedded token takes precedence over an explicit authToken,\n // so pasting a new DSN is the single action users need to do\n ...(parsed.authToken ? { authToken: parsed.authToken } : {}),\n ...(parsed.appName && !config.appName ? { appName: parsed.appName } : {}),\n };\n hasDsn = true;\n } catch (e) {\n _log('[RuntimeScope] Invalid DSN:', (e as Error).message);\n }\n }\n\n // Auto-disable in production: if no explicit endpoint was configured and\n // we're not on localhost, become a no-op. Users with a hosted collector\n // set serverUrl/endpoint explicitly, so this only catches the default case.\n const hasExplicitEndpoint = !!(config.serverUrl || config.endpoint) || hasDsn;\n if (!hasExplicitEndpoint && typeof window !== 'undefined') {\n const host = window.location?.hostname;\n if (host && host !== 'localhost' && host !== '127.0.0.1' && !host.startsWith('192.168.') && !host.startsWith('10.')) {\n _log('[RuntimeScope] No endpoint configured and not on localhost — SDK disabled for production');\n return;\n }\n }\n\n // Resolve `verbose` early so the rest of init logs go through the right path.\n if (config.verbose === true) _debugEnabled = true;\n else if (typeof localStorage !== 'undefined') {\n try {\n if (localStorage.getItem('RUNTIMESCOPE_DEBUG') === '1') _debugEnabled = true;\n } catch {\n // localStorage can throw in sandboxed iframes — just ignore.\n }\n }\n // Propagate to the transport — it has its own _log because it lives in a\n // separate module and the user might construct a Transport directly.\n setTransportDebug(_debugEnabled);\n\n // Idempotent re-init: a second init() call with the same effective config\n // is a silent no-op. With a *different* serverUrl/appName/projectId we\n // warn loudly — that's almost always a footgun where the user has the\n // SDK initialized by the Vite plugin AND by their own bootstrap code,\n // and the second call silently overrides the first to a wrong endpoint.\n const sigCandidate = `${config.appName ?? ''}|${config.serverUrl ?? config.endpoint ?? ''}|${config.dsn ?? ''}|${config.projectId ?? ''}`;\n if (this._state === 'started') {\n if (this._initSignature === sigCandidate) {\n // Same config — nothing to do. Stay connected.\n return;\n }\n _warn(\n `[RuntimeScope] init() called twice with different config — disconnecting and re-initializing.\\n` +\n ` previous: ${this._initSignature}\\n` +\n ` next: ${sigCandidate}\\n` +\n `If the SDK is loaded by @runtimescope/vite, drop your manual RuntimeScope.init() call — the plugin handles it.`,\n );\n this.disconnect();\n }\n this._initSignature = sigCandidate;\n\n const resolved = {\n serverUrl: config.serverUrl ?? config.endpoint ?? 'ws://localhost:6767',\n appName: config.appName ?? 'unknown',\n captureNetwork: config.captureNetwork ?? true,\n captureConsole: config.captureConsole ?? true,\n captureXhr: config.captureXhr ?? true,\n captureBody: config.captureBody ?? false,\n maxBodySize: config.maxBodySize ?? 65536,\n capturePerformance: config.capturePerformance ?? true,\n captureRenders: config.captureRenders ?? true,\n captureNavigation: config.captureNavigation ?? true,\n captureClicks: config.captureClicks ?? true,\n stores: config.stores ?? {},\n beforeSend: config.beforeSend,\n redactHeaders: config.redactHeaders ?? ['authorization', 'cookie'],\n batchSize: config.batchSize ?? 50,\n flushIntervalMs: config.flushIntervalMs ?? 100,\n dedupeConsole: config.dedupeConsole ?? false,\n };\n\n // Save true originals before any patching (idempotent — only saves on first call ever)\n getOrSaveOriginals();\n\n this._sessionId = generateSessionId();\n this._state = 'started';\n\n this.transport = new Transport({\n serverUrl: resolved.serverUrl,\n appName: resolved.appName,\n sessionId: this._sessionId,\n sdkVersion: SDK_VERSION,\n authToken: config.authToken,\n projectId: config.projectId,\n batchSize: resolved.batchSize,\n flushIntervalMs: resolved.flushIntervalMs,\n });\n\n // Sampling config\n this._sampleRate = config.sampleRate ?? 1;\n this._maxEventsPerSecond = config.maxEventsPerSecond;\n this._windowCount = 0;\n this._windowStart = Date.now();\n this._user = config.user;\n\n this.transport.connect();\n _log(`[RuntimeScope] SDK v${SDK_VERSION} initializing — app: ${resolved.appName}, server: ${resolved.serverUrl}`);\n\n // If the transport isn't connected within 10s, emit a visible warning so\n // Claude Code (and humans) see the problem. We use console.warn once —\n // not the patched console (that routes to RuntimeScope itself, which is\n // pointless here) — so the message appears in the user's terminal /\n // browser DevTools.\n const originalWarn = getOrSaveOriginals().consoleMethods.warn;\n const warnTransportRef = this.transport;\n const warnServerUrl = resolved.serverUrl;\n setTimeout(() => {\n // Only warn if init wasn't replaced (user didn't disconnect) AND the\n // transport still hasn't connected. `isConnected()` is a cheap check.\n if (this.transport !== warnTransportRef) return;\n if (warnTransportRef.isConnected?.()) return;\n const isLocalUrl = /localhost|127\\.0\\.0\\.1/.test(warnServerUrl);\n const fix = isLocalUrl\n ? 'Run `npx runtimescope start` in a terminal.'\n : `Check that ${warnServerUrl} is reachable and the collector is running.`;\n originalWarn(\n `[RuntimeScope] Couldn't connect to ${warnServerUrl} after 10s. No events are being captured.`,\n `\\n Fix: ${fix}`,\n );\n }, 10_000);\n\n const emit = (event: RuntimeEvent) => {\n // Session, custom, and UI events always pass through (never sampled out)\n if (event.eventType !== 'session' && event.eventType !== 'custom' && event.eventType !== 'ui') {\n if (!this.shouldSample()) return;\n }\n this.transport?.send(event);\n };\n\n // Send session event\n emit({\n eventId: generateId(),\n sessionId: this._sessionId,\n timestamp: Date.now(),\n eventType: 'session',\n appName: resolved.appName,\n connectedAt: Date.now(),\n sdkVersion: SDK_VERSION,\n buildMeta: config.buildMeta,\n user: this._user,\n projectId: config.projectId,\n });\n\n // Register command handler for server→SDK commands\n const sessionId = this._sessionId;\n this.transport.onCommand((cmd: { command: string; requestId: string; params?: Record<string, unknown> }) => {\n this.handleCommand(cmd, emit, sessionId);\n });\n\n // Fetch interceptor\n if (resolved.captureNetwork) {\n this.restoreFns.push(\n interceptFetch(emit, this._sessionId, resolved.redactHeaders, {\n captureBody: resolved.captureBody,\n maxBodySize: resolved.maxBodySize,\n beforeSend: resolved.beforeSend,\n })\n );\n }\n\n // XHR interceptor\n if (resolved.captureXhr) {\n this.restoreFns.push(\n interceptXhr(emit, this._sessionId, resolved.redactHeaders, {\n captureBody: resolved.captureBody,\n maxBodySize: resolved.maxBodySize,\n beforeSend: resolved.beforeSend,\n })\n );\n }\n\n // Console interceptor\n if (resolved.captureConsole) {\n this.restoreFns.push(\n interceptConsole(emit, this._sessionId, resolved.beforeSend, resolved.dedupeConsole)\n );\n }\n\n // Error interceptor (uncaught errors, resource failures, unhandled rejections)\n // Independent from captureConsole — these don't go through console.* API\n if (config.captureErrors !== false) {\n this.restoreFns.push(\n interceptErrors(emit, this._sessionId, resolved.beforeSend)\n );\n }\n\n // State store inspection\n if (Object.keys(resolved.stores).length > 0) {\n this.restoreFns.push(\n interceptStateStores(emit, this._sessionId, resolved.stores, {\n beforeSend: resolved.beforeSend,\n })\n );\n }\n\n // Performance metrics (Web Vitals)\n if (resolved.capturePerformance) {\n this.restoreFns.push(\n interceptPerformance(emit, this._sessionId, {\n beforeSend: resolved.beforeSend,\n })\n );\n }\n\n // React render tracking\n if (resolved.captureRenders) {\n this.restoreFns.push(\n interceptReactRenders(emit, this._sessionId, {\n beforeSend: resolved.beforeSend,\n })\n );\n }\n\n // Navigation / routing events (pushState, popstate, hashchange)\n if (resolved.captureNavigation) {\n this.restoreFns.push(\n interceptNavigation(emit, this._sessionId)\n );\n }\n\n // Click tracking (UI interaction breadcrumbs)\n if (resolved.captureClicks) {\n this.restoreFns.push(\n interceptClicks(emit, this._sessionId)\n );\n }\n\n const features = [\n resolved.captureNetwork && 'fetch',\n resolved.captureXhr && 'xhr',\n resolved.captureConsole && 'console, errors',\n Object.keys(resolved.stores).length > 0 && 'state',\n resolved.capturePerformance && 'performance',\n resolved.captureRenders && 'renders',\n resolved.captureNavigation && 'navigation',\n resolved.captureClicks && 'clicks',\n ].filter(Boolean);\n _log(`[RuntimeScope] Interceptors active — ${features.join(', ')}`);\n if (this._sampleRate < 1) {\n _log(`[RuntimeScope] Sampling at ${(this._sampleRate * 100).toFixed(0)}%`);\n }\n if (this._maxEventsPerSecond !== undefined) {\n _log(`[RuntimeScope] Rate limited to ${this._maxEventsPerSecond} events/sec`);\n }\n }\n\n private static handleCommand(\n cmd: { command: string; requestId: string; params?: Record<string, unknown> },\n emit: (event: RuntimeEvent) => void,\n sessionId: string\n ): void {\n switch (cmd.command) {\n case 'capture_dom_snapshot': {\n const maxSize = (cmd.params?.maxSize as number) ?? 500_000;\n let html = document.documentElement.outerHTML;\n const truncated = html.length > maxSize;\n if (truncated) html = html.slice(0, maxSize);\n\n const snapshot: DomSnapshotEvent = {\n eventId: generateId(),\n sessionId,\n timestamp: Date.now(),\n eventType: 'dom_snapshot',\n html,\n url: window.location.href,\n viewport: { width: window.innerWidth, height: window.innerHeight },\n scrollPosition: { x: window.scrollX, y: window.scrollY },\n elementCount: document.querySelectorAll('*').length,\n truncated,\n };\n\n emit(snapshot);\n this.transport?.sendCommandResponse(cmd.requestId, cmd.command, snapshot);\n break;\n }\n default:\n this.transport?.sendCommandResponse(cmd.requestId, cmd.command, { error: 'Unknown command' });\n }\n }\n\n /** Alias for `connect` — used by script-tag snippets */\n static init(config: RuntimeScopeConfig = {}): void {\n return this.connect(config);\n }\n\n /**\n * Track a custom business/product event.\n * Use this to mark meaningful moments in your app (e.g. user actions, conversions).\n * These events are correlated with all other telemetry (network, console, state)\n * to build causal chains and detect failures.\n */\n static track(name: string, properties?: Record<string, unknown>): void {\n if (!this.transport || !this._sessionId) return;\n\n const event: CustomEvent = {\n eventId: generateId(),\n sessionId: this._sessionId,\n timestamp: Date.now(),\n eventType: 'custom',\n name,\n properties,\n };\n\n this.transport.send(event);\n }\n\n /**\n * Set user context attached to the current session.\n * Call this after login to associate events with a specific user.\n * Pass null to clear user context.\n */\n static setUser(user: UserContext | null): void {\n this._user = user ?? undefined;\n\n // Send an updated session event so the collector picks up the user context\n if (this.transport && this._sessionId) {\n this.transport.send({\n eventId: generateId(),\n sessionId: this._sessionId,\n timestamp: Date.now(),\n eventType: 'session',\n appName: 'user_update',\n connectedAt: Date.now(),\n sdkVersion: SDK_VERSION,\n user: this._user,\n });\n }\n }\n\n /**\n * Add a manual breadcrumb to the event trail.\n * Use this to mark meaningful moments that help debug errors\n * (e.g., \"user opened settings\", \"form validated\", \"retry attempt 2\").\n */\n static addBreadcrumb(\n message: string,\n data?: Record<string, unknown>\n ): void {\n if (!this.transport || !this._sessionId) return;\n\n const event: UIInteractionEvent = {\n eventId: generateId(),\n sessionId: this._sessionId,\n timestamp: Date.now(),\n eventType: 'ui',\n action: 'breadcrumb',\n target: 'manual',\n text: message,\n ...(data && { data }),\n };\n\n this.transport.send(event);\n }\n\n static disconnect(): void {\n // Run all interceptor restore functions\n for (const fn of this.restoreFns) {\n try { fn(); } catch { /* ensure all restores run */ }\n }\n this.restoreFns = [];\n\n // Safety net: if restore functions didn't fully unwind (e.g. another library\n // patched over us), fall back to true originals saved via Symbol.for()\n const originals = (globalThis as Record<symbol, SavedOriginals>)[ORIGINALS_KEY];\n if (originals) {\n // Only restore if current value is NOT the original (i.e. we or nobody else patched)\n if (window.fetch !== originals.fetch) {\n window.fetch = originals.fetch;\n }\n for (const [level, fn] of Object.entries(originals.consoleMethods)) {\n const c = console as unknown as Record<string, unknown>;\n if (c[level] !== fn) {\n c[level] = fn;\n }\n }\n }\n\n this.transport?.disconnect();\n this.transport = null;\n this._sessionId = null;\n this._state = 'stopped';\n }\n}\n\nexport default RuntimeScope;\nexport { parseDsn, buildDsn } from './dsn.js';\nexport type { ParsedDsn } from './dsn.js';\nexport type {\n RuntimeScopeConfig,\n BuildMeta,\n UserContext,\n NetworkEvent,\n ConsoleEvent,\n SessionEvent,\n StateEvent,\n RenderEvent,\n DomSnapshotEvent,\n PerformanceEvent,\n NavigationEvent,\n CustomEvent,\n UIInteractionEvent,\n RuntimeEvent,\n} from './types.js';\n","import type { RuntimeEvent } from './types.js';\n\n// Save original console methods BEFORE any interceptors patch them. The SDK\n// uses these for its own diagnostics so its logs don't loop back through the\n// console interceptor. `_log` is opt-in (off unless RUNTIMESCOPE_DEBUG flag /\n// localStorage / config.verbose is set) — keeps DevTools clean by default.\nconst _origDebug = console.debug.bind(console);\nconst _origWarn = console.warn.bind(console);\n\nlet _debugEnabled = false;\nfunction _readDebugFlag(): void {\n if (_debugEnabled) return;\n if (typeof localStorage !== 'undefined') {\n try {\n if (localStorage.getItem('RUNTIMESCOPE_DEBUG') === '1') _debugEnabled = true;\n } catch { /* sandboxed iframe — ignore */ }\n }\n}\n_readDebugFlag();\nfunction _log(...args: unknown[]): void {\n if (_debugEnabled) _origDebug(...args);\n}\n/** Public hook so index.ts can flip debug on when `init({ verbose: true })` is set. */\nexport function setTransportDebug(enabled: boolean): void {\n _debugEnabled = enabled;\n}\n\ninterface TransportConfig {\n serverUrl: string;\n appName: string;\n sessionId: string;\n sdkVersion: string;\n authToken?: string;\n projectId?: string;\n batchSize: number;\n flushIntervalMs: number;\n}\n\nexport class Transport {\n private ws: WebSocket | null = null;\n private batch: RuntimeEvent[] = [];\n private offlineQueue: RuntimeEvent[] = [];\n private flushTimer: ReturnType<typeof setInterval> | null = null;\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private reconnectDelay = 500;\n private reconnectAttempt = 0;\n private connected = false;\n private stopped = false;\n private config: TransportConfig;\n\n /** True when the WebSocket handshake has completed and we can send events. */\n isConnected(): boolean {\n return this.connected;\n }\n private commandHandler: ((cmd: { command: string; requestId: string; params?: Record<string, unknown> }) => void) | null = null;\n private hasEverConnected = false;\n private connectionWarningTimer: ReturnType<typeof setTimeout> | null = null;\n private visibilityHandler: (() => void) | null = null;\n private onlineHandler: (() => void) | null = null;\n\n private static readonly MAX_OFFLINE_QUEUE = 1000;\n private static readonly MAX_RECONNECT_DELAY = 30_000;\n private static readonly CONNECTION_WARNING_DELAY = 10_000;\n /** First N retries use a fast 500ms delay before switching to exponential backoff */\n private static readonly FAST_RETRY_COUNT = 3;\n private static readonly FAST_RETRY_DELAY = 500;\n\n constructor(config: TransportConfig) {\n this.config = config;\n }\n\n connect(): void {\n this.stopped = false;\n this.doConnect();\n\n // Warn if we never establish a connection within 10 seconds\n this.connectionWarningTimer = setTimeout(() => {\n if (!this.hasEverConnected && !this.stopped) {\n console.warn(\n `[RuntimeScope] SDK has not connected to ${this.config.serverUrl} after 10s. ` +\n `Is the collector running? Start it with: npx @runtimescope/collector`\n );\n }\n }, Transport.CONNECTION_WARNING_DELAY);\n\n // When the user switches back to this tab, try to reconnect immediately\n if (typeof document !== 'undefined') {\n this.visibilityHandler = () => {\n if (document.visibilityState === 'visible' && !this.connected && !this.stopped) {\n _log('[RuntimeScope] Tab visible — attempting immediate reconnect');\n this.resetReconnectState();\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n this.doConnect();\n }\n };\n document.addEventListener('visibilitychange', this.visibilityHandler);\n }\n\n // Reconnect immediately when network comes back online\n if (typeof window !== 'undefined') {\n this.onlineHandler = () => {\n if (!this.connected && !this.stopped) {\n _log('[RuntimeScope] Network online — attempting immediate reconnect');\n this.resetReconnectState();\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n this.doConnect();\n }\n };\n window.addEventListener('online', this.onlineHandler);\n }\n }\n\n private doConnect(): void {\n if (this.stopped) return;\n\n try {\n this.ws = new WebSocket(this.config.serverUrl);\n } catch {\n this.scheduleReconnect();\n return;\n }\n\n this.ws.onmessage = (event: MessageEvent) => {\n try {\n const msg = JSON.parse(String(event.data));\n if (msg.type === 'command' && msg.payload && this.commandHandler) {\n this.commandHandler(msg.payload);\n }\n // Handle server restart notice — reset backoff for immediate reconnect\n if (msg.type === '__server_restart') {\n _log('[RuntimeScope] Server restart notice received — will reconnect immediately');\n this.resetReconnectState();\n }\n // Handle auth rejection — stop reconnecting\n if (msg.type === 'error' && msg.payload?.code === 'AUTH_FAILED') {\n _log('[RuntimeScope] Authentication failed — stopping reconnection');\n this.stopped = true;\n }\n } catch {\n // Ignore unparseable messages\n }\n };\n\n this.ws.onopen = () => {\n this.connected = true;\n this.hasEverConnected = true;\n this.resetReconnectState();\n _log(`[RuntimeScope] Connected to ${this.config.serverUrl}`);\n\n // Send handshake\n this.sendRaw({\n type: 'handshake',\n payload: {\n appName: this.config.appName,\n sdkVersion: this.config.sdkVersion,\n sessionId: this.config.sessionId,\n ...(this.config.authToken ? { authToken: this.config.authToken } : {}),\n ...(this.config.projectId ? { projectId: this.config.projectId } : {}),\n },\n timestamp: Date.now(),\n sessionId: this.config.sessionId,\n });\n\n // Flush offline queue\n if (this.offlineQueue.length > 0) {\n const queued = this.offlineQueue.splice(0);\n for (const event of queued) {\n this.batch.push(event);\n }\n this.flush();\n }\n\n // Start periodic flush\n this.flushTimer = setInterval(() => this.flush(), this.config.flushIntervalMs);\n };\n\n this.ws.onclose = () => {\n this.connected = false;\n this.clearFlushTimer();\n if (!this.stopped) {\n _log(`[RuntimeScope] Disconnected, will reconnect...`);\n this.scheduleReconnect();\n }\n };\n\n this.ws.onerror = () => {\n _log(`[RuntimeScope] WebSocket error connecting to ${this.config.serverUrl}`);\n };\n }\n\n send(event: RuntimeEvent): void {\n if (this.connected) {\n this.batch.push(event);\n if (this.batch.length >= this.config.batchSize) {\n this.flush();\n }\n } else {\n // Queue for when we reconnect\n if (this.offlineQueue.length < Transport.MAX_OFFLINE_QUEUE) {\n this.offlineQueue.push(event);\n }\n }\n }\n\n private flush(): void {\n if (this.batch.length === 0 || !this.connected || !this.ws) return;\n\n const events = this.batch.splice(0);\n this.sendRaw({\n type: 'event',\n payload: { events },\n timestamp: Date.now(),\n sessionId: this.config.sessionId,\n });\n }\n\n private sendRaw(msg: unknown): void {\n if (this.ws && this.ws.readyState === WebSocket.OPEN) {\n try {\n this.ws.send(JSON.stringify(msg));\n } catch {\n // Drop silently — reconnect will handle it\n }\n }\n }\n\n private scheduleReconnect(): void {\n if (this.stopped || this.reconnectTimer) return;\n\n this.reconnectAttempt++;\n\n // Fast retries for the first few attempts (collector restart gap is typically 1-3s)\n let delay: number;\n if (this.reconnectAttempt <= Transport.FAST_RETRY_COUNT) {\n delay = Transport.FAST_RETRY_DELAY;\n } else {\n // Exponential backoff with jitter after fast retries exhausted\n const jitter = this.reconnectDelay * 0.25 * (Math.random() * 2 - 1);\n delay = Math.min(this.reconnectDelay + jitter, Transport.MAX_RECONNECT_DELAY);\n this.reconnectDelay = Math.min(this.reconnectDelay * 2, Transport.MAX_RECONNECT_DELAY);\n }\n\n this.reconnectTimer = setTimeout(() => {\n this.reconnectTimer = null;\n this.doConnect();\n }, delay);\n }\n\n private resetReconnectState(): void {\n this.reconnectDelay = 500;\n this.reconnectAttempt = 0;\n }\n\n private clearFlushTimer(): void {\n if (this.flushTimer) {\n clearInterval(this.flushTimer);\n this.flushTimer = null;\n }\n }\n\n onCommand(handler: (cmd: { command: string; requestId: string; params?: Record<string, unknown> }) => void): void {\n this.commandHandler = handler;\n }\n\n sendCommandResponse(requestId: string, command: string, payload: unknown): void {\n this.sendRaw({\n type: 'command_response',\n requestId,\n command,\n payload,\n timestamp: Date.now(),\n sessionId: this.config.sessionId,\n });\n }\n\n disconnect(): void {\n this.stopped = true;\n this.clearFlushTimer();\n\n if (this.connectionWarningTimer) {\n clearTimeout(this.connectionWarningTimer);\n this.connectionWarningTimer = null;\n }\n\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n\n if (this.visibilityHandler && typeof document !== 'undefined') {\n document.removeEventListener('visibilitychange', this.visibilityHandler);\n this.visibilityHandler = null;\n }\n\n if (this.onlineHandler && typeof window !== 'undefined') {\n window.removeEventListener('online', this.onlineHandler);\n this.onlineHandler = null;\n }\n\n // Final flush before closing\n this.flush();\n\n if (this.ws) {\n this.ws.onclose = null;\n this.ws.onerror = null;\n this.ws.close();\n this.ws = null;\n }\n\n this.connected = false;\n this.batch = [];\n this.offlineQueue = [];\n }\n}\n","/** 16-char random hex string for event IDs. */\nexport function generateId(): string {\n const arr = new Uint8Array(8);\n crypto.getRandomValues(arr);\n return Array.from(arr, (b) => b.toString(16).padStart(2, '0')).join('');\n}\n\n/** 32-char random hex string for session IDs. */\nexport function generateSessionId(): string {\n const arr = new Uint8Array(16);\n crypto.getRandomValues(arr);\n return Array.from(arr, (b) => b.toString(16).padStart(2, '0')).join('');\n}\n","import { generateId } from '../utils/id.js';\nimport type { NetworkEvent, GraphQLOperation, RuntimeEvent } from '../types.js';\n\ntype EmitFn = (event: NetworkEvent) => void;\n\nexport interface FetchInterceptorOptions {\n captureBody?: boolean;\n maxBodySize?: number;\n beforeSend?: (event: RuntimeEvent) => RuntimeEvent | null;\n}\n\n// Track URLs intercepted by fetch to prevent XHR double-counting (fetch polyfill case).\n// Uses a Map with timestamps + single sweeper instead of per-request setTimeout.\nconst MAX_INFLIGHT = 1000;\nconst INFLIGHT_TTL_MS = 10_000;\nconst SWEEP_INTERVAL_MS = 5_000;\n\nexport const fetchInterceptedRequests = new Map<string, number>();\nlet sweepTimer: ReturnType<typeof setInterval> | null = null;\nlet sweepRefCount = 0;\n\nfunction startSweeper(): void {\n sweepRefCount++;\n if (sweepTimer) return;\n sweepTimer = setInterval(() => {\n const cutoff = Date.now() - INFLIGHT_TTL_MS;\n for (const [key, ts] of fetchInterceptedRequests) {\n if (ts < cutoff) fetchInterceptedRequests.delete(key);\n }\n }, SWEEP_INTERVAL_MS);\n}\n\nfunction stopSweeper(): void {\n sweepRefCount--;\n if (sweepRefCount <= 0 && sweepTimer) {\n clearInterval(sweepTimer);\n sweepTimer = null;\n sweepRefCount = 0;\n }\n}\n\nexport function interceptFetch(\n emit: EmitFn,\n sessionId: string,\n redactHeaders: string[],\n options?: FetchInterceptorOptions\n): () => void {\n const originalFetch = window.fetch;\n const redactSet = new Set(redactHeaders.map((h) => h.toLowerCase()));\n const captureBody = options?.captureBody ?? false;\n const maxBodySize = options?.maxBodySize ?? 65536;\n\n startSweeper();\n\n window.fetch = async function (\n input: RequestInfo | URL,\n init?: RequestInit\n ): Promise<Response> {\n const startTime = performance.now();\n const url =\n typeof input === 'string'\n ? input\n : input instanceof URL\n ? input.href\n : input.url;\n const method = (init?.method ?? 'GET').toUpperCase();\n\n const requestHeaders = extractHeaders(init?.headers, redactSet);\n const requestBodySize = estimateBodySize(init?.body);\n const graphqlOperation = detectGraphQL(init?.body);\n\n // Capture request body if enabled\n let requestBody: string | undefined;\n if (captureBody && init?.body) {\n requestBody = serializeBody(init.body, maxBodySize);\n }\n\n // Mark request to prevent XHR interceptor double-counting (fetch polyfill case)\n const requestKey = `${method}:${url}:${startTime}`;\n // Evict oldest entry if at capacity\n if (fetchInterceptedRequests.size >= MAX_INFLIGHT) {\n const oldest = fetchInterceptedRequests.keys().next().value;\n if (oldest !== undefined) fetchInterceptedRequests.delete(oldest);\n }\n fetchInterceptedRequests.set(requestKey, Date.now());\n\n try {\n const response = await originalFetch.call(window, input, init);\n const duration = performance.now() - startTime;\n\n const responseBodySize = parseInt(\n response.headers.get('content-length') || '0',\n 10\n );\n const responseHeaders = extractResponseHeaders(response.headers, redactSet);\n\n // Capture response body if enabled\n let responseBody: string | undefined;\n if (captureBody) {\n try {\n const clone = response.clone();\n const text = await clone.text();\n responseBody = text.length > maxBodySize ? text.slice(0, maxBodySize) : text;\n } catch {\n // CORS or stream-locked — skip body capture\n }\n }\n\n const event: NetworkEvent = {\n eventId: generateId(),\n sessionId,\n timestamp: Date.now(),\n eventType: 'network',\n url,\n method,\n status: response.status,\n requestHeaders,\n responseHeaders,\n requestBodySize,\n responseBodySize,\n duration,\n ttfb: duration,\n graphqlOperation,\n requestBody,\n responseBody,\n source: 'fetch',\n };\n\n if (options?.beforeSend) {\n const filtered = options.beforeSend(event);\n if (filtered) emit(filtered as NetworkEvent);\n } else {\n emit(event);\n }\n\n return response;\n } catch (error) {\n const duration = performance.now() - startTime;\n\n let errorPhase: 'error' | 'abort' | 'timeout' = 'error';\n let errorMessage = '';\n\n if (error instanceof DOMException && error.name === 'AbortError') {\n errorPhase = 'abort';\n errorMessage = 'Request aborted';\n } else if (error instanceof Error) {\n errorMessage = error.message;\n }\n\n const event: NetworkEvent = {\n eventId: generateId(),\n sessionId,\n timestamp: Date.now(),\n eventType: 'network',\n url,\n method,\n status: 0,\n requestHeaders,\n responseHeaders: {},\n requestBodySize,\n responseBodySize: 0,\n duration,\n ttfb: 0,\n graphqlOperation,\n requestBody,\n errorPhase,\n errorMessage,\n source: 'fetch',\n };\n\n if (options?.beforeSend) {\n const filtered = options.beforeSend(event);\n if (filtered) emit(filtered as NetworkEvent);\n } else {\n emit(event);\n }\n\n throw error;\n }\n };\n\n return () => {\n window.fetch = originalFetch;\n stopSweeper();\n };\n}\n\nfunction extractHeaders(\n headers: HeadersInit | undefined,\n redactSet: Set<string>\n): Record<string, string> {\n const result: Record<string, string> = {};\n if (!headers) return result;\n\n if (headers instanceof Headers) {\n headers.forEach((value, key) => {\n result[key] = redactSet.has(key.toLowerCase()) ? '[REDACTED]' : value;\n });\n } else if (Array.isArray(headers)) {\n for (const [key, value] of headers) {\n result[key] = redactSet.has(key.toLowerCase()) ? '[REDACTED]' : value;\n }\n } else {\n for (const [key, value] of Object.entries(headers)) {\n result[key] = redactSet.has(key.toLowerCase()) ? '[REDACTED]' : value;\n }\n }\n\n return result;\n}\n\nfunction extractResponseHeaders(\n headers: Headers,\n redactSet: Set<string>\n): Record<string, string> {\n const result: Record<string, string> = {};\n headers.forEach((value, key) => {\n result[key] = redactSet.has(key.toLowerCase()) ? '[REDACTED]' : value;\n });\n return result;\n}\n\nfunction estimateBodySize(body: BodyInit | null | undefined): number {\n if (!body) return 0;\n if (typeof body === 'string') return new Blob([body]).size;\n if (body instanceof Blob) return body.size;\n if (body instanceof ArrayBuffer) return body.byteLength;\n if (ArrayBuffer.isView(body)) return body.byteLength;\n if (body instanceof FormData) return 0;\n if (body instanceof URLSearchParams) return new Blob([body.toString()]).size;\n return 0;\n}\n\nfunction serializeBody(body: BodyInit | null | undefined, maxSize: number): string | undefined {\n if (!body) return undefined;\n if (typeof body === 'string') return body.length > maxSize ? body.slice(0, maxSize) : body;\n if (body instanceof URLSearchParams) {\n const s = body.toString();\n return s.length > maxSize ? s.slice(0, maxSize) : s;\n }\n if (body instanceof FormData) return '[FormData]';\n if (body instanceof Blob) return `[Blob ${body.size} bytes]`;\n if (body instanceof ArrayBuffer) return `[ArrayBuffer ${body.byteLength} bytes]`;\n if (ArrayBuffer.isView(body)) return `[TypedArray ${body.byteLength} bytes]`;\n return undefined;\n}\n\nfunction detectGraphQL(body: BodyInit | null | undefined): GraphQLOperation | undefined {\n if (!body || typeof body !== 'string') return undefined;\n\n try {\n const parsed = JSON.parse(body);\n if (typeof parsed.query === 'string') {\n const trimmed = parsed.query.trim();\n let type: GraphQLOperation['type'] = 'query';\n if (trimmed.startsWith('mutation')) type = 'mutation';\n else if (trimmed.startsWith('subscription')) type = 'subscription';\n\n const name = parsed.operationName || extractOperationName(trimmed) || 'anonymous';\n return { type, name };\n }\n } catch {\n // Not GraphQL\n }\n\n return undefined;\n}\n\nfunction extractOperationName(query: string): string | undefined {\n const match = query.match(/^(?:query|mutation|subscription)\\s+(\\w+)/);\n return match?.[1];\n}\n","/** Safely serialize a value, handling circular references, functions, symbols, and errors. */\nexport function safeSerialize(value: unknown, maxDepth = 5): unknown {\n const seen = new WeakSet();\n\n function walk(val: unknown, depth: number): unknown {\n if (depth > maxDepth) return '[max depth]';\n if (val === null || val === undefined) return val;\n if (typeof val === 'function') return `[Function: ${val.name || 'anonymous'}]`;\n if (typeof val === 'symbol') return val.toString();\n if (typeof val === 'bigint') return val.toString();\n if (typeof val !== 'object') return val;\n\n if (val instanceof Error) {\n return { name: val.name, message: val.message, stack: val.stack };\n }\n if (val instanceof Date) {\n return val.toISOString();\n }\n if (val instanceof RegExp) {\n return val.toString();\n }\n\n if (seen.has(val as object)) return '[Circular]';\n seen.add(val as object);\n\n if (Array.isArray(val)) {\n return val.map((v) => walk(v, depth + 1));\n }\n\n const result: Record<string, unknown> = {};\n let keys: string[];\n try {\n keys = Object.keys(val as Record<string, unknown>);\n } catch {\n return '[Object]';\n }\n // Limit keys to avoid huge React fiber-like objects\n const maxKeys = 50;\n for (let i = 0; i < Math.min(keys.length, maxKeys); i++) {\n try {\n result[keys[i]] = walk((val as Record<string, unknown>)[keys[i]], depth + 1);\n } catch {\n result[keys[i]] = '[Error accessing property]';\n }\n }\n if (keys.length > maxKeys) result['...'] = `${keys.length - maxKeys} more keys`;\n return result;\n }\n\n return walk(value, 0);\n}\n","import { generateId } from '../utils/id.js';\nimport { safeSerialize } from '../utils/serialize.js';\nimport type { ConsoleEvent, ConsoleLevel, RuntimeEvent } from '../types.js';\n\ntype EmitFn = (event: ConsoleEvent) => void;\n\nconst LEVELS: ConsoleLevel[] = ['log', 'warn', 'error', 'info', 'debug', 'trace'];\n\nexport interface ConsoleDedupeOptions {\n /** Window during which identical messages are considered duplicates. Default 5000ms. */\n windowMs?: number;\n /** First N occurrences of a duplicate burst still print normally. Default 3 — gives users a sense of frequency without an explosion. */\n maxBurst?: number;\n /** How often to flush the \"suppressed N messages\" summary line. Default 5000ms. */\n summaryIntervalMs?: number;\n}\n\ninterface DedupeState {\n count: number;\n firstAt: number;\n suppressed: number;\n level: ConsoleLevel;\n preview: string;\n}\n\n/**\n * Build a dedupe gate for the console interceptor.\n *\n * The collector still receives every event — this only filters what reaches\n * the actual browser DevTools, keeping the console clean in production.\n *\n * Returns:\n * - shouldPrint(level, message): true if this call should pass through to\n * the original console method, false if it's been suppressed.\n * - dispose(): clears the summary timer (called on interceptor teardown).\n */\nfunction makeDedupeGate(\n options: Required<ConsoleDedupeOptions>,\n printSummary: (text: string) => void,\n): { shouldPrint: (level: ConsoleLevel, message: string) => boolean; dispose: () => void } {\n const seen = new Map<string, DedupeState>();\n\n const summaryTimer = setInterval(() => {\n let totalSuppressed = 0;\n for (const state of seen.values()) {\n if (state.suppressed > 0) {\n totalSuppressed += state.suppressed;\n state.suppressed = 0;\n }\n }\n if (totalSuppressed > 0) {\n printSummary(\n `[RuntimeScope] suppressed ${totalSuppressed} duplicate console message${totalSuppressed === 1 ? '' : 's'} in the last ${options.summaryIntervalMs / 1000}s — full data in the dashboard.`,\n );\n }\n // Garbage-collect entries older than the dedupe window so the map doesn't\n // grow forever for unique-but-rare messages.\n const cutoff = Date.now() - options.windowMs;\n for (const [key, state] of seen) {\n if (state.firstAt < cutoff && state.suppressed === 0) seen.delete(key);\n }\n }, options.summaryIntervalMs);\n // Don't keep the page alive if everything else has shut down.\n if (typeof (summaryTimer as { unref?: () => void }).unref === 'function') {\n (summaryTimer as { unref: () => void }).unref();\n }\n\n return {\n shouldPrint(level, message) {\n const now = Date.now();\n const key = `${level}|${message}`;\n let state = seen.get(key);\n if (state && now - state.firstAt > options.windowMs) {\n // Window elapsed — start fresh.\n state = undefined;\n }\n if (!state) {\n seen.set(key, {\n count: 1,\n firstAt: now,\n suppressed: 0,\n level,\n preview: message.slice(0, 80),\n });\n return true;\n }\n state.count++;\n if (state.count <= options.maxBurst) return true;\n state.suppressed++;\n return false;\n },\n dispose() { clearInterval(summaryTimer); },\n };\n}\n\n/** Extract the caller's source file from an Error stack trace. */\nfunction extractSourceFile(stack: string | undefined): string | undefined {\n if (!stack) return undefined;\n // Skip first 3 lines: \"Error\", our interceptor, and the console wrapper\n const lines = stack.split('\\n').slice(3);\n for (const line of lines) {\n // Match \"at ... (file:line:col)\" or \"at file:line:col\"\n const match = line.match(/(?:at\\s+)?(?:.*?\\()?(.+?):(\\d+):(\\d+)\\)?/);\n if (match && !match[1].includes('interceptor') && !match[1].includes('runtimescope')) {\n return `${match[1]}:${match[2]}`;\n }\n }\n return undefined;\n}\n\nexport function interceptConsole(\n emit: EmitFn,\n sessionId: string,\n beforeSend?: (event: RuntimeEvent) => RuntimeEvent | null,\n dedupe?: ConsoleDedupeOptions | boolean\n): () => void {\n const originals: Record<string, (...args: unknown[]) => void> = {};\n const timers = new Map<string, number>();\n const counters = new Map<string, number>();\n\n // Optional dedupe gate — when enabled, identical messages within `windowMs`\n // print at most `maxBurst` times before being suppressed. The collector\n // still receives every event so the dashboard stays accurate.\n const dedupeOptions: Required<ConsoleDedupeOptions> | null = dedupe\n ? {\n windowMs: (typeof dedupe === 'object' ? dedupe.windowMs : undefined) ?? 5000,\n maxBurst: (typeof dedupe === 'object' ? dedupe.maxBurst : undefined) ?? 3,\n summaryIntervalMs:\n (typeof dedupe === 'object' ? dedupe.summaryIntervalMs : undefined) ?? 5000,\n }\n : null;\n // We need the original console.info ahead of any patching for the summary,\n // captured BEFORE the loop below replaces it. Otherwise the summary line\n // itself loops through the interceptor.\n const summarySink = console.info.bind(console);\n const dedupeGate = dedupeOptions\n ? makeDedupeGate(dedupeOptions, (text) => summarySink(text))\n : null;\n\n // Standard log levels\n for (const level of LEVELS) {\n originals[level] = console[level].bind(console);\n\n console[level] = (...args: unknown[]) => {\n const stack = new Error().stack;\n const message = args\n .map((a) => (typeof a === 'string' ? a : stringifyArg(a)))\n .join(' ');\n\n const event: ConsoleEvent = {\n eventId: generateId(),\n sessionId,\n timestamp: Date.now(),\n eventType: 'console',\n level,\n message,\n args: args.map((a) => safeSerialize(a, 3)),\n stackTrace:\n level === 'error' || level === 'trace' ? stack?.split('\\n').slice(2).join('\\n') : undefined,\n sourceFile: extractSourceFile(stack),\n source: 'browser',\n };\n\n // Always emit to the collector — the dashboard wants the full count.\n if (beforeSend) {\n const filtered = beforeSend(event);\n if (filtered) emit(filtered as ConsoleEvent);\n } else {\n emit(event);\n }\n\n // Only suppress the visible browser output, not the collected event.\n if (dedupeGate && !dedupeGate.shouldPrint(level, message)) return;\n\n originals[level](...args);\n };\n }\n\n // console.assert — logs error when condition is false\n const origAssert = console.assert?.bind(console);\n if (origAssert) {\n console.assert = (condition?: boolean, ...args: unknown[]) => {\n if (!condition) {\n const stack = new Error().stack;\n const message = `Assertion failed: ${args.map((a) => typeof a === 'string' ? a : stringifyArg(a)).join(' ')}`;\n emit({\n eventId: generateId(),\n sessionId,\n timestamp: Date.now(),\n eventType: 'console',\n level: 'error',\n message,\n args: args.map((a) => safeSerialize(a, 3)),\n stackTrace: stack?.split('\\n').slice(2).join('\\n'),\n sourceFile: extractSourceFile(stack),\n source: 'browser',\n });\n }\n origAssert(condition, ...args);\n };\n }\n\n // console.time / console.timeEnd — capture timing\n const origTime = console.time?.bind(console);\n const origTimeEnd = console.timeEnd?.bind(console);\n if (origTime) {\n console.time = (label = 'default') => {\n timers.set(label, performance.now());\n origTime(label);\n };\n }\n if (origTimeEnd) {\n console.timeEnd = (label = 'default') => {\n const start = timers.get(label);\n if (start !== undefined) {\n const duration = performance.now() - start;\n timers.delete(label);\n emit({\n eventId: generateId(),\n sessionId,\n timestamp: Date.now(),\n eventType: 'console',\n level: 'info',\n message: `${label}: ${duration.toFixed(2)}ms`,\n args: [{ label, duration }],\n source: 'browser',\n });\n }\n origTimeEnd(label);\n };\n }\n\n // console.count / console.countReset\n const origCount = console.count?.bind(console);\n const origCountReset = console.countReset?.bind(console);\n if (origCount) {\n console.count = (label = 'default') => {\n const count = (counters.get(label) ?? 0) + 1;\n counters.set(label, count);\n emit({\n eventId: generateId(),\n sessionId,\n timestamp: Date.now(),\n eventType: 'console',\n level: 'info',\n message: `${label}: ${count}`,\n args: [{ label, count }],\n source: 'browser',\n });\n origCount(label);\n };\n }\n if (origCountReset) {\n console.countReset = (label = 'default') => {\n counters.delete(label);\n origCountReset(label);\n };\n }\n\n // console.table — capture as info with structured data\n const origTable = console.table?.bind(console);\n if (origTable) {\n console.table = (data: unknown, columns?: string[]) => {\n emit({\n eventId: generateId(),\n sessionId,\n timestamp: Date.now(),\n eventType: 'console',\n level: 'info',\n message: `[table] ${Array.isArray(data) ? `${data.length} rows` : typeof data}`,\n args: [safeSerialize(data, 3)],\n source: 'browser',\n });\n origTable(data, columns);\n };\n }\n\n return () => {\n for (const level of LEVELS) {\n console[level] = originals[level];\n }\n if (origAssert) console.assert = origAssert;\n if (origTime) console.time = origTime;\n if (origTimeEnd) console.timeEnd = origTimeEnd;\n if (origCount) console.count = origCount;\n if (origCountReset) console.countReset = origCountReset;\n if (origTable) console.table = origTable;\n dedupeGate?.dispose();\n };\n}\n\nfunction stringifyArg(arg: unknown): string {\n try {\n return JSON.stringify(arg);\n } catch {\n return String(arg);\n }\n}\n","import { generateId } from '../utils/id.js';\nimport type { NetworkEvent, GraphQLOperation, RuntimeEvent } from '../types.js';\nimport { fetchInterceptedRequests } from './fetch.js';\n\ntype EmitFn = (event: NetworkEvent) => void;\n\nexport interface XhrInterceptorOptions {\n captureBody?: boolean;\n maxBodySize?: number;\n beforeSend?: (event: RuntimeEvent) => RuntimeEvent | null;\n}\n\ninterface AugmentedXHR extends XMLHttpRequest {\n __rs_method?: string;\n __rs_url?: string;\n __rs_headers?: Record<string, string>;\n __rs_start?: number;\n __rs_body?: string;\n __rs_fetchIntercepted?: boolean;\n}\n\nexport function interceptXhr(\n emit: EmitFn,\n sessionId: string,\n redactHeaders: string[],\n options?: XhrInterceptorOptions\n): () => void {\n const redactSet = new Set(redactHeaders.map((h) => h.toLowerCase()));\n const captureBody = options?.captureBody ?? false;\n const maxBodySize = options?.maxBodySize ?? 65536;\n\n // Global AbortController for teardown — aborts all outstanding XHR listeners on disconnect\n const globalAbort = new AbortController();\n\n const origOpen = XMLHttpRequest.prototype.open;\n const origSetRequestHeader = XMLHttpRequest.prototype.setRequestHeader;\n const origSend = XMLHttpRequest.prototype.send;\n\n XMLHttpRequest.prototype.open = function (\n this: AugmentedXHR,\n method: string,\n url: string | URL\n ) {\n this.__rs_method = method.toUpperCase();\n this.__rs_url = typeof url === 'string' ? url : url.href;\n this.__rs_headers = {};\n // eslint-disable-next-line prefer-rest-params\n return origOpen.apply(this, arguments as unknown as Parameters<typeof origOpen>);\n };\n\n XMLHttpRequest.prototype.setRequestHeader = function (\n this: AugmentedXHR,\n name: string,\n value: string\n ) {\n if (this.__rs_headers) {\n this.__rs_headers[name.toLowerCase()] = redactSet.has(name.toLowerCase())\n ? '[REDACTED]'\n : value;\n }\n return origSetRequestHeader.call(this, name, value);\n };\n\n XMLHttpRequest.prototype.send = function (\n this: AugmentedXHR,\n body?: Document | XMLHttpRequestBodyInit | null\n ) {\n // Skip if this request was already captured by the fetch interceptor\n const method = this.__rs_method ?? 'GET';\n const url = this.__rs_url ?? '';\n const requestKey = `${method}:${url}`;\n let alreadyIntercepted = false;\n for (const k of fetchInterceptedRequests.keys()) {\n if (k.startsWith(requestKey)) { alreadyIntercepted = true; break; }\n }\n if (alreadyIntercepted) {\n this.__rs_fetchIntercepted = true;\n return origSend.call(this, body);\n }\n\n const requestHeaders = { ...(this.__rs_headers ?? {}) };\n const startTime = performance.now();\n\n // Capture request body\n let requestBody: string | undefined;\n let requestBodySize = 0;\n if (body) {\n if (typeof body === 'string') {\n requestBodySize = new Blob([body]).size;\n if (captureBody) {\n requestBody = body.length > maxBodySize ? body.slice(0, maxBodySize) : body;\n }\n } else if (body instanceof Blob) {\n requestBodySize = body.size;\n if (captureBody) requestBody = `[Blob ${body.size} bytes]`;\n } else if (body instanceof ArrayBuffer) {\n requestBodySize = body.byteLength;\n if (captureBody) requestBody = `[ArrayBuffer ${body.byteLength} bytes]`;\n } else if (body instanceof FormData) {\n if (captureBody) requestBody = '[FormData]';\n } else if (body instanceof URLSearchParams) {\n const s = body.toString();\n requestBodySize = new Blob([s]).size;\n if (captureBody) requestBody = s.length > maxBodySize ? s.slice(0, maxBodySize) : s;\n }\n }\n\n // Detect GraphQL\n const graphqlOperation = detectGraphQL(body);\n\n const emitEvent = (overrides: Partial<NetworkEvent>) => {\n const event: NetworkEvent = {\n eventId: generateId(),\n sessionId,\n timestamp: Date.now(),\n eventType: 'network',\n url,\n method,\n status: 0,\n requestHeaders,\n responseHeaders: {},\n requestBodySize,\n responseBodySize: 0,\n duration: 0,\n ttfb: 0,\n graphqlOperation,\n requestBody,\n source: 'xhr',\n ...overrides,\n };\n\n if (options?.beforeSend) {\n const filtered = options.beforeSend(event);\n if (filtered) emit(filtered as NetworkEvent);\n } else {\n emit(event);\n }\n };\n\n // Single loadend listener covers all terminal states (load, error, abort, timeout).\n // { once: true } auto-removes per-request; globalAbort.signal enables bulk teardown.\n this.addEventListener('loadend', () => {\n const duration = performance.now() - startTime;\n\n if (this.status > 0) {\n // Successful completion (includes HTTP errors like 4xx/5xx)\n const responseHeaders = parseResponseHeaders(this.getAllResponseHeaders(), redactSet);\n const responseBodySize = parseInt(\n this.getResponseHeader('content-length') || '0',\n 10\n );\n\n let responseBody: string | undefined;\n if (captureBody && (this.responseType === '' || this.responseType === 'text')) {\n try {\n const text = this.responseText;\n responseBody = text.length > maxBodySize ? text.slice(0, maxBodySize) : text;\n } catch {\n // responseText not available for non-text types\n }\n }\n\n emitEvent({\n status: this.status,\n responseHeaders,\n responseBodySize,\n responseBody,\n duration,\n ttfb: duration,\n });\n } else {\n // Network error, abort, or timeout — status is 0\n let errorPhase: 'error' | 'abort' | 'timeout' = 'error';\n let errorMessage = 'Network error';\n\n if (this.readyState === 0 || (this as XMLHttpRequest).status === 0) {\n // Distinguish abort vs timeout vs network error\n // XHR sets readyState to UNSENT (0) on abort\n }\n\n // Check specific failure modes\n if (this.timeout > 0 && duration >= this.timeout) {\n errorPhase = 'timeout';\n errorMessage = `Request timed out after ${this.timeout}ms`;\n }\n\n emitEvent({ duration, errorPhase, errorMessage });\n }\n }, { once: true, signal: globalAbort.signal });\n\n return origSend.call(this, body);\n };\n\n return () => {\n // Abort all outstanding XHR listeners from this interceptor instance\n globalAbort.abort();\n XMLHttpRequest.prototype.open = origOpen;\n XMLHttpRequest.prototype.setRequestHeader = origSetRequestHeader;\n XMLHttpRequest.prototype.send = origSend;\n };\n}\n\nfunction parseResponseHeaders(\n raw: string,\n redactSet: Set<string>\n): Record<string, string> {\n const result: Record<string, string> = {};\n if (!raw) return result;\n\n for (const line of raw.trim().split(/[\\r\\n]+/)) {\n const idx = line.indexOf(':');\n if (idx === -1) continue;\n const key = line.slice(0, idx).trim().toLowerCase();\n const value = line.slice(idx + 1).trim();\n result[key] = redactSet.has(key) ? '[REDACTED]' : value;\n }\n\n return result;\n}\n\nfunction detectGraphQL(\n body: Document | XMLHttpRequestBodyInit | null | undefined\n): GraphQLOperation | undefined {\n if (!body || typeof body !== 'string') return undefined;\n\n try {\n const parsed = JSON.parse(body);\n if (typeof parsed.query === 'string') {\n const trimmed = parsed.query.trim();\n let type: GraphQLOperation['type'] = 'query';\n if (trimmed.startsWith('mutation')) type = 'mutation';\n else if (trimmed.startsWith('subscription')) type = 'subscription';\n\n const name =\n parsed.operationName || extractOperationName(trimmed) || 'anonymous';\n return { type, name };\n }\n } catch {\n // Not GraphQL\n }\n\n return undefined;\n}\n\nfunction extractOperationName(query: string): string | undefined {\n const match = query.match(/^(?:query|mutation|subscription)\\s+(\\w+)/);\n return match?.[1];\n}\n","import { generateId } from '../utils/id.js';\nimport { safeSerialize } from '../utils/serialize.js';\nimport type { StateEvent, RuntimeEvent } from '../types.js';\n\ntype EmitFn = (event: StateEvent) => void;\n\nexport interface StateStoreOptions {\n beforeSend?: (event: RuntimeEvent) => RuntimeEvent | null;\n}\n\ninterface ZustandStore {\n getState: () => unknown;\n setState: (partial: unknown) => void;\n subscribe: (listener: (state: unknown, prevState: unknown) => void) => () => void;\n}\n\ninterface ReduxStore {\n getState: () => unknown;\n dispatch: (action: unknown) => unknown;\n subscribe: (listener: () => void) => () => void;\n}\n\ntype DetectedLibrary = 'zustand' | 'redux' | 'unknown';\n\nexport function interceptStateStores(\n emit: EmitFn,\n sessionId: string,\n stores: Record<string, unknown>,\n options?: StateStoreOptions\n): () => void {\n const unsubscribers: (() => void)[] = [];\n const originalDispatches: Map<string, ReduxStore['dispatch']> = new Map();\n\n for (const [storeId, store] of Object.entries(stores)) {\n const library = detectLibrary(store);\n\n if (library === 'zustand') {\n const zustand = store as ZustandStore;\n\n // Emit initial state\n emitState(emit, sessionId, options?.beforeSend, {\n storeId,\n library,\n phase: 'init',\n state: safeSerialize(zustand.getState(), 4),\n });\n\n // Subscribe to changes\n const unsub = zustand.subscribe((state, prevState) => {\n const diff = shallowDiff(prevState, state);\n emitState(emit, sessionId, options?.beforeSend, {\n storeId,\n library,\n phase: 'update',\n state: safeSerialize(state, 4),\n previousState: safeSerialize(prevState, 4),\n diff: diff ? safeSerialize(diff, 3) as Record<string, { from: unknown; to: unknown }> : undefined,\n });\n });\n\n unsubscribers.push(unsub);\n } else if (library === 'redux') {\n const redux = store as ReduxStore;\n\n // Emit initial state\n emitState(emit, sessionId, options?.beforeSend, {\n storeId,\n library,\n phase: 'init',\n state: safeSerialize(redux.getState(), 4),\n });\n\n // Wrap dispatch to capture actions\n let lastAction: { type: string; payload?: unknown } | undefined;\n const origDispatch = redux.dispatch.bind(redux);\n originalDispatches.set(storeId, origDispatch);\n\n (redux as { dispatch: ReduxStore['dispatch'] }).dispatch = (action: unknown) => {\n if (action && typeof action === 'object' && 'type' in action) {\n lastAction = {\n type: String((action as { type: unknown }).type),\n payload: (action as { payload?: unknown }).payload,\n };\n }\n return origDispatch(action);\n };\n\n // Subscribe to state changes\n let prevState = redux.getState();\n const unsub = redux.subscribe(() => {\n const state = redux.getState();\n const diff = shallowDiff(prevState, state);\n\n emitState(emit, sessionId, options?.beforeSend, {\n storeId,\n library,\n phase: 'update',\n state: safeSerialize(state, 4),\n previousState: safeSerialize(prevState, 4),\n diff: diff ? safeSerialize(diff, 3) as Record<string, { from: unknown; to: unknown }> : undefined,\n action: lastAction ? safeSerialize(lastAction, 3) as { type: string; payload?: unknown } : undefined,\n });\n\n prevState = state;\n lastAction = undefined;\n });\n\n unsubscribers.push(unsub);\n }\n }\n\n return () => {\n for (const unsub of unsubscribers) unsub();\n\n // Restore original Redux dispatch functions\n for (const [storeId, origDispatch] of originalDispatches) {\n const store = stores[storeId] as ReduxStore;\n if (store) {\n (store as { dispatch: ReduxStore['dispatch'] }).dispatch = origDispatch;\n }\n }\n };\n}\n\nfunction detectLibrary(store: unknown): DetectedLibrary {\n if (!store || typeof store !== 'object') return 'unknown';\n const s = store as Record<string, unknown>;\n\n // Zustand: function-like with getState, setState, subscribe\n if (\n typeof s.getState === 'function' &&\n typeof s.setState === 'function' &&\n typeof s.subscribe === 'function'\n ) {\n return 'zustand';\n }\n\n // Redux: object with dispatch, getState, subscribe\n if (\n typeof s.dispatch === 'function' &&\n typeof s.getState === 'function' &&\n typeof s.subscribe === 'function'\n ) {\n return 'redux';\n }\n\n return 'unknown';\n}\n\nfunction shallowDiff(\n prev: unknown,\n curr: unknown\n): Record<string, { from: unknown; to: unknown }> | null {\n if (!prev || !curr || typeof prev !== 'object' || typeof curr !== 'object') {\n return null;\n }\n\n const diff: Record<string, { from: unknown; to: unknown }> = {};\n const prevObj = prev as Record<string, unknown>;\n const currObj = curr as Record<string, unknown>;\n const allKeys = new Set([...Object.keys(prevObj), ...Object.keys(currObj)]);\n\n for (const key of allKeys) {\n if (prevObj[key] !== currObj[key]) {\n diff[key] = { from: prevObj[key], to: currObj[key] };\n }\n }\n\n return Object.keys(diff).length > 0 ? diff : null;\n}\n\nfunction emitState(\n emit: EmitFn,\n sessionId: string,\n beforeSend: ((event: RuntimeEvent) => RuntimeEvent | null) | undefined,\n data: Omit<StateEvent, 'eventId' | 'sessionId' | 'timestamp' | 'eventType'>\n): void {\n const event: StateEvent = {\n eventId: generateId(),\n sessionId,\n timestamp: Date.now(),\n eventType: 'state',\n ...data,\n };\n\n if (beforeSend) {\n const filtered = beforeSend(event);\n if (filtered) emit(filtered as StateEvent);\n } else {\n emit(event);\n }\n}\n","import { generateId } from '../utils/id.js';\nimport type { PerformanceEvent, WebVitalRating, RuntimeEvent } from '../types.js';\n\ntype EmitFn = (event: PerformanceEvent) => void;\n\nexport interface PerformanceInterceptorOptions {\n beforeSend?: (event: RuntimeEvent) => RuntimeEvent | null;\n}\n\n// Web Vitals thresholds from web.dev\nconst THRESHOLDS: Record<string, [number, number]> = {\n LCP: [2500, 4000],\n FCP: [1800, 3000],\n CLS: [0.1, 0.25],\n TTFB: [800, 1800],\n FID: [100, 300],\n INP: [200, 500],\n};\n\nfunction rate(metric: string, value: number): WebVitalRating {\n const [good, poor] = THRESHOLDS[metric] ?? [Infinity, Infinity];\n if (value <= good) return 'good';\n if (value <= poor) return 'needs-improvement';\n return 'poor';\n}\n\n// Module-level singleton tracking — prevents duplicate observers on double-init (HMR)\nlet activeObservers: PerformanceObserver[] | null = null;\n\nexport function interceptPerformance(\n emit: EmitFn,\n sessionId: string,\n options?: PerformanceInterceptorOptions\n): () => void {\n // Disconnect any existing observers from a previous init (HMR / double-init safety)\n if (activeObservers) {\n for (const obs of activeObservers) {\n try { obs.disconnect(); } catch { /* already disconnected */ }\n }\n }\n\n const observers: PerformanceObserver[] = [];\n activeObservers = observers;\n\n const emitMetric = (\n metricName: PerformanceEvent['metricName'],\n value: number,\n element?: string\n ) => {\n const event: PerformanceEvent = {\n eventId: generateId(),\n sessionId,\n timestamp: Date.now(),\n eventType: 'performance',\n metricName,\n value: Math.round(value * 100) / 100,\n rating: rate(metricName, value),\n element,\n };\n\n if (options?.beforeSend) {\n const filtered = options.beforeSend(event);\n if (filtered) emit(filtered as PerformanceEvent);\n } else {\n emit(event);\n }\n };\n\n // LCP — Largest Contentful Paint\n tryObserve(observers, 'largest-contentful-paint', (entries) => {\n const last = entries[entries.length - 1];\n if (!last) return;\n const el = (last as PerformanceEntry & { element?: Element }).element;\n emitMetric('LCP', last.startTime, el?.tagName?.toLowerCase());\n });\n\n // FCP — First Contentful Paint\n tryObserve(observers, 'paint', (entries) => {\n for (const entry of entries) {\n if (entry.name === 'first-contentful-paint') {\n emitMetric('FCP', entry.startTime);\n }\n }\n });\n\n // CLS — Cumulative Layout Shift\n let clsValue = 0;\n tryObserve(observers, 'layout-shift', (entries) => {\n for (const entry of entries) {\n const ls = entry as PerformanceEntry & { hadRecentInput?: boolean; value?: number };\n if (!ls.hadRecentInput && ls.value) {\n clsValue += ls.value;\n emitMetric('CLS', clsValue);\n }\n }\n });\n\n // FID — First Input Delay\n tryObserve(observers, 'first-input', (entries) => {\n const first = entries[0];\n if (!first) return;\n const fi = first as PerformanceEntry & { processingStart?: number };\n if (fi.processingStart) {\n emitMetric('FID', fi.processingStart - first.startTime);\n }\n });\n\n // TTFB — Time to First Byte\n tryObserve(observers, 'navigation', (entries) => {\n const nav = entries[0] as PerformanceNavigationTiming | undefined;\n if (nav) {\n emitMetric('TTFB', nav.responseStart - nav.requestStart);\n }\n });\n\n // INP — Interaction to Next Paint\n let inpMax = 0;\n tryObserve(\n observers,\n 'event',\n (entries) => {\n for (const entry of entries) {\n if (entry.duration > inpMax) {\n inpMax = entry.duration;\n emitMetric('INP', inpMax);\n }\n }\n },\n { durationThreshold: 16 }\n );\n\n return () => {\n for (const obs of observers) {\n try {\n obs.disconnect();\n } catch {\n // Already disconnected\n }\n }\n if (activeObservers === observers) {\n activeObservers = null;\n }\n };\n}\n\nfunction tryObserve(\n observers: PerformanceObserver[],\n entryType: string,\n callback: (entries: PerformanceEntryList) => void,\n observeOptions?: Record<string, unknown>\n): void {\n try {\n const obs = new PerformanceObserver((list) => {\n callback(list.getEntries());\n });\n obs.observe({\n type: entryType,\n buffered: true,\n ...observeOptions,\n } as PerformanceObserverInit);\n observers.push(obs);\n } catch {\n // Observer type not supported in this browser\n }\n}\n","import { generateId } from '../utils/id.js';\nimport type { RenderEvent, RenderComponentProfile, RuntimeEvent } from '../types.js';\n\ntype EmitFn = (event: RenderEvent) => void;\n\nexport interface RenderInterceptorOptions {\n beforeSend?: (event: RuntimeEvent) => RuntimeEvent | null;\n snapshotIntervalMs?: number;\n}\n\ninterface Fiber {\n tag: number;\n type: { displayName?: string; name?: string } | string | null;\n child: Fiber | null;\n sibling: Fiber | null;\n alternate: Fiber | null;\n memoizedProps: unknown;\n memoizedState: unknown;\n actualDuration?: number;\n stateNode: unknown;\n}\n\ninterface ComponentTracker {\n renderCount: number;\n totalDuration: number;\n lastRenderTime: number;\n lastRenderPhase: 'mount' | 'update' | 'unmount';\n lastRenderCause: 'props' | 'state' | 'context' | 'parent' | 'unknown';\n renderTimestamps: number[];\n}\n\ninterface DevToolsHook {\n onCommitFiberRoot?: (id: number, root: { current?: Fiber }) => void;\n _runtimescope_original?: (id: number, root: { current?: Fiber }) => void;\n}\n\nconst FUNCTION_COMPONENT = 0;\nconst CLASS_COMPONENT = 1;\nconst SNAPSHOT_WINDOW_MS = 10_000;\nconst MAX_TIMESTAMPS = 100;\nconst TRACKER_TTL_MS = 60_000;\nconst MAX_TRACKED_COMPONENTS = 500;\n\nexport function interceptReactRenders(\n emit: EmitFn,\n sessionId: string,\n options?: RenderInterceptorOptions\n): () => void {\n const trackers = new Map<string, ComponentTracker>();\n const snapshotIntervalMs = options?.snapshotIntervalMs ?? 5000;\n let snapshotTimer: ReturnType<typeof setInterval> | null = null;\n\n // Access or create the React DevTools global hook\n const hook = getOrCreateDevToolsHook();\n if (!hook) {\n return () => {}; // Not in a browser environment\n }\n\n // Save original if React DevTools is installed\n const originalOnCommit = hook.onCommitFiberRoot;\n hook._runtimescope_original = originalOnCommit;\n\n hook.onCommitFiberRoot = (id: number, root: { current?: Fiber }) => {\n // Call original first (React DevTools compatibility)\n if (originalOnCommit) {\n try {\n originalOnCommit(id, root);\n } catch {\n // Don't let DevTools errors break our tracking\n }\n }\n\n if (root.current) {\n walkFiber(root.current, trackers);\n }\n };\n\n // Emit snapshots periodically\n snapshotTimer = setInterval(() => {\n emitSnapshot(trackers, emit, sessionId, options?.beforeSend);\n }, snapshotIntervalMs);\n\n return () => {\n if (snapshotTimer) {\n clearInterval(snapshotTimer);\n snapshotTimer = null;\n }\n\n // Restore original hook\n if (hook) {\n if (hook._runtimescope_original) {\n hook.onCommitFiberRoot = hook._runtimescope_original;\n } else {\n delete hook.onCommitFiberRoot;\n }\n delete hook._runtimescope_original;\n }\n };\n}\n\nfunction getOrCreateDevToolsHook(): DevToolsHook | null {\n if (typeof window === 'undefined') return null;\n\n const w = window as unknown as { __REACT_DEVTOOLS_GLOBAL_HOOK__?: DevToolsHook };\n\n if (!w.__REACT_DEVTOOLS_GLOBAL_HOOK__) {\n // Create a minimal shim that React will pick up on init\n w.__REACT_DEVTOOLS_GLOBAL_HOOK__ = {\n // React checks for these methods to decide if DevTools is present\n } as DevToolsHook;\n }\n\n return w.__REACT_DEVTOOLS_GLOBAL_HOOK__!;\n}\n\nfunction walkFiber(fiber: Fiber, trackers: Map<string, ComponentTracker>): void {\n processNode(fiber, trackers);\n\n if (fiber.child) walkFiber(fiber.child, trackers);\n if (fiber.sibling) walkFiber(fiber.sibling, trackers);\n}\n\nfunction processNode(fiber: Fiber, trackers: Map<string, ComponentTracker>): void {\n // Only track function components (0) and class components (1)\n if (fiber.tag !== FUNCTION_COMPONENT && fiber.tag !== CLASS_COMPONENT) return;\n\n const name = getComponentName(fiber);\n if (!name) return;\n\n const now = Date.now();\n const isMount = fiber.alternate === null;\n const duration = fiber.actualDuration ?? 0;\n const cause = inferRenderCause(fiber, isMount);\n\n let tracker = trackers.get(name);\n if (!tracker) {\n tracker = {\n renderCount: 0,\n totalDuration: 0,\n lastRenderTime: 0,\n lastRenderPhase: 'mount',\n lastRenderCause: 'unknown',\n renderTimestamps: [],\n };\n trackers.set(name, tracker);\n }\n\n tracker.renderCount++;\n tracker.totalDuration += duration;\n tracker.lastRenderTime = now;\n tracker.lastRenderPhase = isMount ? 'mount' : 'update';\n tracker.lastRenderCause = cause ?? 'unknown';\n tracker.renderTimestamps.push(now);\n\n // Trim old timestamps\n if (tracker.renderTimestamps.length > MAX_TIMESTAMPS) {\n tracker.renderTimestamps = tracker.renderTimestamps.slice(-MAX_TIMESTAMPS);\n }\n}\n\nfunction getComponentName(fiber: Fiber): string | undefined {\n if (!fiber.type) return undefined;\n if (typeof fiber.type === 'string') return undefined; // HTML elements\n return fiber.type.displayName || fiber.type.name || undefined;\n}\n\nfunction inferRenderCause(\n fiber: Fiber,\n isMount: boolean\n): RenderComponentProfile['lastRenderCause'] {\n if (isMount) return 'props'; // Initial mount, driven by parent passing props\n\n if (!fiber.alternate) return 'unknown';\n\n // Check if props changed\n if (fiber.memoizedProps !== fiber.alternate.memoizedProps) {\n return 'props';\n }\n\n // Check if state changed\n if (fiber.memoizedState !== fiber.alternate.memoizedState) {\n return 'state';\n }\n\n // If neither props nor state changed, likely parent re-rendered\n return 'parent';\n}\n\nfunction computeRenderVelocity(timestamps: number[]): number {\n if (timestamps.length < 2) return 0;\n const now = Date.now();\n const windowStart = now - SNAPSHOT_WINDOW_MS;\n const recent = timestamps.filter((t) => t >= windowStart);\n if (recent.length < 2) return 0;\n const windowMs = now - recent[0];\n if (windowMs === 0) return 0;\n return recent.length / (windowMs / 1000);\n}\n\nfunction emitSnapshot(\n trackers: Map<string, ComponentTracker>,\n emit: EmitFn,\n sessionId: string,\n beforeSend?: (event: RuntimeEvent) => RuntimeEvent | null\n): void {\n if (trackers.size === 0) return;\n\n const profiles: RenderComponentProfile[] = [];\n const suspiciousComponents: string[] = [];\n let totalRenders = 0;\n\n for (const [componentName, tracker] of trackers) {\n const velocity = computeRenderVelocity(tracker.renderTimestamps);\n const suspicious = velocity > 4 || tracker.renderCount > 20;\n\n profiles.push({\n componentName,\n renderCount: tracker.renderCount,\n totalDuration: Math.round(tracker.totalDuration * 100) / 100,\n avgDuration:\n tracker.renderCount > 0\n ? Math.round((tracker.totalDuration / tracker.renderCount) * 100) / 100\n : 0,\n lastRenderPhase: tracker.lastRenderPhase,\n lastRenderCause: tracker.lastRenderCause,\n renderVelocity: Math.round(velocity * 100) / 100,\n suspicious,\n });\n\n if (suspicious) suspiciousComponents.push(componentName);\n totalRenders += tracker.renderCount;\n }\n\n // Sort by render count descending\n profiles.sort((a, b) => b.renderCount - a.renderCount);\n\n const event: RenderEvent = {\n eventId: generateId(),\n sessionId,\n timestamp: Date.now(),\n eventType: 'render',\n profiles,\n snapshotWindowMs: SNAPSHOT_WINDOW_MS,\n totalRenders,\n suspiciousComponents,\n };\n\n if (beforeSend) {\n const filtered = beforeSend(event);\n if (filtered) emit(filtered as RenderEvent);\n } else {\n emit(event);\n }\n\n // Reset counters and prune stale trackers\n const now = Date.now();\n for (const [name, tracker] of trackers) {\n if (now - tracker.lastRenderTime > TRACKER_TTL_MS) {\n // Component hasn't rendered in 60s — remove to prevent unbounded growth\n trackers.delete(name);\n } else {\n tracker.renderCount = 0;\n tracker.totalDuration = 0;\n }\n }\n\n // Hard cap: if still over limit after TTL pruning, evict least-recently-rendered\n if (trackers.size > MAX_TRACKED_COMPONENTS) {\n const sorted = [...trackers.entries()]\n .sort((a, b) => a[1].lastRenderTime - b[1].lastRenderTime);\n const excess = trackers.size - MAX_TRACKED_COMPONENTS;\n for (let i = 0; i < excess; i++) {\n trackers.delete(sorted[i][0]);\n }\n }\n}\n","import { generateId } from '../utils/id.js';\nimport { safeSerialize } from '../utils/serialize.js';\nimport type { ConsoleEvent, RuntimeEvent } from '../types.js';\n\ntype EmitFn = (event: ConsoleEvent) => void;\n\n/**\n * Captures uncaught errors and unhandled promise rejections that appear\n * in DevTools but don't go through the console.* API.\n *\n * - window 'error' (capture phase) — JS runtime errors + resource load failures\n * - window 'unhandledrejection' — unhandled async/await and Promise rejections\n *\n * Events are emitted as ConsoleEvents with level 'error' so they appear\n * alongside console.error() output in get_console_messages.\n */\nexport function interceptErrors(\n emit: EmitFn,\n sessionId: string,\n beforeSend?: (event: RuntimeEvent) => RuntimeEvent | null\n): () => void {\n // Capture uncaught JS errors and resource load failures\n const onError = (e: ErrorEvent | Event) => {\n let message: string;\n let stackTrace: string | undefined;\n let sourceFile: string | undefined;\n\n if (e instanceof ErrorEvent) {\n // Uncaught JS error\n message = e.message || 'Uncaught error';\n stackTrace = e.error?.stack;\n sourceFile = e.filename\n ? `${e.filename}:${e.lineno}:${e.colno}`\n : undefined;\n } else {\n // Resource load error (img, script, link, etc.)\n const target = e.target as HTMLElement | null;\n if (target && target !== window as unknown) {\n const tagName = target.tagName?.toLowerCase() ?? 'unknown';\n const src =\n (target as HTMLImageElement).src ??\n (target as HTMLScriptElement).src ??\n (target as HTMLLinkElement).href ??\n 'unknown';\n message = `Failed to load resource: <${tagName}> ${src}`;\n } else {\n return; // Not a resource error we can identify\n }\n }\n\n const event: ConsoleEvent = {\n eventId: generateId(),\n sessionId,\n timestamp: Date.now(),\n eventType: 'console',\n level: 'error',\n message: `[Uncaught] ${message}`,\n args: [safeSerialize(message, 3)],\n stackTrace,\n sourceFile,\n };\n\n if (beforeSend) {\n const filtered = beforeSend(event);\n if (filtered) emit(filtered as ConsoleEvent);\n } else {\n emit(event);\n }\n };\n\n // Capture unhandled promise rejections\n const onUnhandledRejection = (e: PromiseRejectionEvent) => {\n const reason = e.reason;\n let message: string;\n let stackTrace: string | undefined;\n\n if (reason instanceof Error) {\n message = reason.message;\n stackTrace = reason.stack;\n } else if (typeof reason === 'string') {\n message = reason;\n } else {\n try {\n message = JSON.stringify(reason);\n } catch {\n message = String(reason);\n }\n }\n\n const event: ConsoleEvent = {\n eventId: generateId(),\n sessionId,\n timestamp: Date.now(),\n eventType: 'console',\n level: 'error',\n message: `[Unhandled Rejection] ${message}`,\n args: [safeSerialize(reason, 3)],\n stackTrace,\n sourceFile: undefined,\n };\n\n if (beforeSend) {\n const filtered = beforeSend(event);\n if (filtered) emit(filtered as ConsoleEvent);\n } else {\n emit(event);\n }\n };\n\n // Use capture phase for 'error' to catch resource load failures on child elements\n window.addEventListener('error', onError, true);\n window.addEventListener('unhandledrejection', onUnhandledRejection);\n\n return () => {\n window.removeEventListener('error', onError, true);\n window.removeEventListener('unhandledrejection', onUnhandledRejection);\n };\n}\n","import type { RuntimeEvent, NavigationEvent } from '../types.js';\nimport { generateId } from '../utils/id.js';\n\n/**\n * Intercepts SPA navigation events:\n * - history.pushState / replaceState (client-side routing)\n * - popstate (browser back/forward)\n * - hashchange (hash-based routing)\n *\n * Emits a NavigationEvent with from/to URLs and the trigger type.\n */\nexport function interceptNavigation(\n emit: (event: RuntimeEvent) => void,\n sessionId: string\n): () => void {\n let currentUrl = window.location.href;\n\n function emitNav(to: string, trigger: NavigationEvent['trigger']): void {\n const from = currentUrl;\n if (from === to) return; // Skip no-op navigations\n currentUrl = to;\n\n emit({\n eventId: generateId(),\n sessionId,\n timestamp: Date.now(),\n eventType: 'navigation',\n from,\n to,\n trigger,\n });\n }\n\n // Patch pushState and replaceState\n const origPushState = history.pushState.bind(history);\n const origReplaceState = history.replaceState.bind(history);\n\n history.pushState = function (...args: Parameters<typeof origPushState>) {\n origPushState(...args);\n emitNav(window.location.href, 'pushState');\n };\n\n history.replaceState = function (...args: Parameters<typeof origReplaceState>) {\n origReplaceState(...args);\n emitNav(window.location.href, 'replaceState');\n };\n\n // Listen for back/forward navigation\n const onPopState = () => emitNav(window.location.href, 'popstate');\n window.addEventListener('popstate', onPopState);\n\n // Listen for hash changes (covers hash-based routers)\n const onHashChange = () => emitNav(window.location.href, 'hashchange');\n window.addEventListener('hashchange', onHashChange);\n\n // Restore function\n return () => {\n history.pushState = origPushState;\n history.replaceState = origReplaceState;\n window.removeEventListener('popstate', onPopState);\n window.removeEventListener('hashchange', onHashChange);\n };\n}\n","import type { RuntimeEvent, UIInteractionEvent } from '../types.js';\nimport { generateId } from '../utils/id.js';\n\n/**\n * Intercepts user clicks via event delegation on `document`.\n * Emits a lightweight UIInteractionEvent with the target element's\n * CSS selector and visible text.\n *\n * Uses a single capture-phase listener — no DOM mutation, no patching.\n */\nexport function interceptClicks(\n emit: (event: RuntimeEvent) => void,\n sessionId: string\n): () => void {\n const onClick = (e: MouseEvent) => {\n const target = e.target;\n if (!(target instanceof Element)) return;\n\n // Skip RuntimeScope's own UI (if any)\n if (target.closest('[data-runtimescope]')) return;\n\n const selector = buildSelector(target);\n const text = getVisibleText(target);\n\n const event: UIInteractionEvent = {\n eventId: generateId(),\n sessionId,\n timestamp: Date.now(),\n eventType: 'ui',\n action: 'click',\n target: selector,\n ...(text && { text }),\n };\n\n emit(event);\n };\n\n // Capture phase so we see clicks even if stopPropagation is called\n document.addEventListener('click', onClick, true);\n\n return () => {\n document.removeEventListener('click', onClick, true);\n };\n}\n\n/**\n * Build a short, human-readable CSS selector for the clicked element.\n * Prioritizes: tag + id > tag + data-testid > tag + class (first meaningful one).\n * Keeps it concise — not a full path.\n */\nfunction buildSelector(el: Element): string {\n const tag = el.tagName.toLowerCase();\n\n if (el.id) return `${tag}#${el.id}`;\n\n const testId = el.getAttribute('data-testid') ?? el.getAttribute('data-test-id');\n if (testId) return `${tag}[data-testid=\"${testId}\"]`;\n\n const role = el.getAttribute('role');\n const ariaLabel = el.getAttribute('aria-label');\n if (role && ariaLabel) return `${tag}[role=\"${role}\"][aria-label=\"${ariaLabel}\"]`;\n\n const className = el.className;\n if (typeof className === 'string' && className.trim()) {\n // Take the first non-utility class (skip single-letter or hash-based classes)\n const meaningful = className.split(/\\s+/).find(\n (c) => c.length > 2 && !c.startsWith('_') && !c.includes('__')\n );\n if (meaningful) return `${tag}.${meaningful}`;\n }\n\n // Fallback: tag with nth-child if parent has multiple same-tag children\n const parent = el.parentElement;\n if (parent) {\n const siblings = parent.children;\n const sameTag = Array.from(siblings).filter((s) => s.tagName === el.tagName);\n if (sameTag.length > 1) {\n const idx = sameTag.indexOf(el) + 1;\n return `${tag}:nth-child(${idx})`;\n }\n }\n\n return tag;\n}\n\n/**\n * Get visible text from an element, truncated to 80 chars.\n * Prefers aria-label, then textContent.\n */\nfunction getVisibleText(el: Element): string | undefined {\n const ariaLabel = el.getAttribute('aria-label');\n if (ariaLabel) return ariaLabel.slice(0, 80);\n\n const text = (el as HTMLElement).innerText ?? el.textContent;\n if (!text) return undefined;\n\n const trimmed = text.trim().replace(/\\s+/g, ' ');\n if (trimmed.length === 0) return undefined;\n return trimmed.length > 80 ? trimmed.slice(0, 77) + '...' : trimmed;\n}\n","/**\n * DSN (Data Source Name) parser for RuntimeScope browser SDK.\n *\n * Format: runtimescope://proj_abc123[:token]@localhost:6768/my-app\n * - runtimescope:// or runtimescopes:// (TLS)\n * - projectId before @ (or before : if a token is included)\n * - optional bearer token between : and @ (workspace-scoped API key)\n * - host:port after @ (HTTP API port, default 6768)\n * - WS port = HTTP port - 1 (so 6768 → ws on 6767)\n * - Optional /appName path\n */\n\nexport interface ParsedDsn {\n projectId: string;\n authToken?: string;\n wsEndpoint: string;\n httpEndpoint: string;\n appName?: string;\n tls: boolean;\n}\n\nexport function parseDsn(dsn: string): ParsedDsn {\n const tls = dsn.startsWith('runtimescopes://');\n if (!dsn.startsWith('runtimescope://') && !tls) {\n throw new Error(`Invalid RuntimeScope DSN: must start with runtimescope:// or runtimescopes://`);\n }\n // Replace protocol for URL parsing\n const url = new URL(dsn.replace(/^runtimescopes?:\\/\\//, 'http://'));\n const projectId = url.username;\n if (!projectId || !projectId.startsWith('proj_')) {\n throw new Error(`Invalid RuntimeScope DSN: missing projectId (expected proj_xxx@host)`);\n }\n const authToken = url.password ? decodeURIComponent(url.password) : undefined;\n const host = url.hostname;\n const httpPort = url.port ? parseInt(url.port) : 6768;\n const wsPort = httpPort - 1;\n const appName = url.pathname.replace(/^\\//, '') || undefined;\n const wsProto = tls ? 'wss' : 'ws';\n const httpProto = tls ? 'https' : 'http';\n return {\n projectId,\n authToken,\n wsEndpoint: `${wsProto}://${host}:${wsPort}`,\n httpEndpoint: `${httpProto}://${host}:${httpPort}`,\n appName,\n tls,\n };\n}\n\nexport function buildDsn(opts: {\n projectId: string;\n authToken?: string;\n host?: string;\n port?: number;\n appName?: string;\n tls?: boolean;\n}): string {\n const proto = opts.tls ? 'runtimescopes' : 'runtimescope';\n const host = opts.host ?? 'localhost';\n const port = opts.port ?? 6768;\n const path = opts.appName ? `/${opts.appName}` : '';\n const auth = opts.authToken ? `:${encodeURIComponent(opts.authToken)}` : '';\n return `${proto}://${opts.projectId}${auth}@${host}:${port}${path}`;\n}\n"],"mappings":"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","names":["index_exports","__export","RuntimeScope","buildDsn","index_default","parseDsn","__toCommonJS","_origDebug","_origWarn","_debugEnabled","_readDebugFlag","_log","args","setTransportDebug","enabled","_Transport","config","__publicField","event","msg","queued","events","delay","jitter","handler","requestId","command","payload","Transport","generateId","arr","b","generateSessionId","MAX_INFLIGHT","INFLIGHT_TTL_MS","SWEEP_INTERVAL_MS","fetchInterceptedRequests","sweepTimer","sweepRefCount","startSweeper","cutoff","key","ts","stopSweeper","interceptFetch","emit","sessionId","redactHeaders","options","originalFetch","redactSet","h","captureBody","maxBodySize","input","init","startTime","url","method","requestHeaders","extractHeaders","requestBodySize","estimateBodySize","graphqlOperation","detectGraphQL","requestBody","serializeBody","requestKey","oldest","response","duration","responseBodySize","responseHeaders","extractResponseHeaders","responseBody","text","event","generateId","filtered","error","errorPhase","errorMessage","headers","result","value","body","maxSize","s","parsed","trimmed","type","name","extractOperationName","query","safeSerialize","value","maxDepth","seen","walk","val","depth","v","result","keys","maxKeys","i","LEVELS","makeDedupeGate","options","printSummary","seen","summaryTimer","totalSuppressed","state","cutoff","key","level","message","now","extractSourceFile","stack","lines","line","match","interceptConsole","emit","sessionId","beforeSend","dedupe","originals","timers","counters","dedupeOptions","summarySink","dedupeGate","text","args","a","stringifyArg","event","generateId","safeSerialize","filtered","origAssert","condition","origTime","origTimeEnd","label","start","duration","origCount","origCountReset","count","origTable","data","columns","arg","interceptXhr","emit","sessionId","redactHeaders","options","redactSet","h","captureBody","maxBodySize","globalAbort","origOpen","origSetRequestHeader","origSend","method","url","name","value","body","requestKey","alreadyIntercepted","k","fetchInterceptedRequests","requestHeaders","startTime","requestBody","requestBodySize","s","graphqlOperation","detectGraphQL","emitEvent","overrides","event","generateId","filtered","duration","responseHeaders","parseResponseHeaders","responseBodySize","responseBody","text","errorPhase","errorMessage","raw","result","line","idx","key","parsed","trimmed","type","extractOperationName","query","interceptStateStores","emit","sessionId","stores","options","unsubscribers","originalDispatches","storeId","store","library","detectLibrary","zustand","emitState","safeSerialize","unsub","state","prevState","diff","shallowDiff","redux","lastAction","origDispatch","action","s","prev","curr","prevObj","currObj","allKeys","key","beforeSend","data","event","generateId","filtered","THRESHOLDS","rate","metric","value","good","poor","activeObservers","interceptPerformance","emit","sessionId","options","obs","observers","emitMetric","metricName","element","event","generateId","filtered","tryObserve","entries","last","el","entry","clsValue","ls","first","fi","nav","inpMax","entryType","callback","observeOptions","list","FUNCTION_COMPONENT","CLASS_COMPONENT","SNAPSHOT_WINDOW_MS","MAX_TIMESTAMPS","TRACKER_TTL_MS","MAX_TRACKED_COMPONENTS","interceptReactRenders","emit","sessionId","options","trackers","snapshotIntervalMs","snapshotTimer","hook","getOrCreateDevToolsHook","originalOnCommit","id","root","walkFiber","emitSnapshot","w","fiber","processNode","name","getComponentName","now","isMount","duration","cause","inferRenderCause","tracker","computeRenderVelocity","timestamps","windowStart","recent","t","windowMs","beforeSend","profiles","suspiciousComponents","totalRenders","componentName","velocity","suspicious","a","b","event","generateId","filtered","sorted","excess","i","interceptErrors","emit","sessionId","beforeSend","onError","e","message","stackTrace","sourceFile","target","tagName","src","event","generateId","safeSerialize","filtered","onUnhandledRejection","reason","interceptNavigation","emit","sessionId","currentUrl","emitNav","to","trigger","from","generateId","origPushState","origReplaceState","args","onPopState","onHashChange","interceptClicks","emit","sessionId","onClick","e","target","selector","buildSelector","text","getVisibleText","event","generateId","el","tag","testId","role","ariaLabel","className","meaningful","parent","siblings","sameTag","s","idx","trimmed","parseDsn","dsn","tls","url","projectId","authToken","host","httpPort","wsPort","appName","wsProto","httpProto","buildDsn","opts","proto","port","path","auth","SDK_VERSION","_origDebug","_origWarn","_debugEnabled","_log","args","_warnedOnce","_warn","message","rest","ORIGINALS_KEY","getOrSaveOriginals","g","RuntimeScope","now","config","hasDsn","parsed","parseDsn","e","host","setTransportDebug","sigCandidate","resolved","generateSessionId","Transport","originalWarn","warnTransportRef","warnServerUrl","fix","emit","event","generateId","sessionId","cmd","interceptFetch","interceptXhr","interceptConsole","interceptErrors","interceptStateStores","interceptPerformance","interceptReactRenders","interceptNavigation","interceptClicks","features","maxSize","html","truncated","snapshot","name","properties","user","data","fn","originals","level","c","__publicField","index_default"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/transport.ts","../src/utils/id.ts","../src/interceptors/fetch.ts","../src/utils/serialize.ts","../src/interceptors/console.ts","../src/interceptors/xhr.ts","../src/interceptors/state-stores.ts","../src/interceptors/performance.ts","../src/interceptors/react-renders.ts","../src/interceptors/errors.ts","../src/interceptors/navigation.ts","../src/interceptors/clicks.ts","../src/dsn.ts"],"sourcesContent":["import { Transport, setTransportDebug } from './transport.js';\nimport { interceptFetch } from './interceptors/fetch.js';\nimport { interceptConsole } from './interceptors/console.js';\nimport { interceptXhr } from './interceptors/xhr.js';\nimport { interceptStateStores } from './interceptors/state-stores.js';\nimport { interceptPerformance } from './interceptors/performance.js';\nimport { interceptReactRenders } from './interceptors/react-renders.js';\nimport { interceptErrors } from './interceptors/errors.js';\nimport { interceptNavigation } from './interceptors/navigation.js';\nimport { interceptClicks } from './interceptors/clicks.js';\nimport { generateId, generateSessionId } from './utils/id.js';\nimport { parseDsn } from './dsn.js';\nimport type { RuntimeScopeConfig, RuntimeEvent, DomSnapshotEvent, CustomEvent, UIInteractionEvent, UserContext } from './types.js';\n\nconst SDK_VERSION = '0.10.7';\n\n// Save original console methods BEFORE interceptors patch them. The SDK uses\n// these for its own diagnostics so its messages don't loop back through the\n// console interceptor (which would emit a console event for every internal log).\nconst _origDebug = console.debug.bind(console);\nconst _origWarn = console.warn.bind(console);\n\n/**\n * Internal-only debug logging. Quiet by default — set\n * `localStorage.RUNTIMESCOPE_DEBUG = '1'` or pass `verbose: true` to\n * `RuntimeScope.init()` to see them. Most users never need to see SDK\n * lifecycle chatter, and seeing it stacks up fast in DevTools.\n */\nlet _debugEnabled = false;\nfunction _log(...args: unknown[]): void {\n if (_debugEnabled) _origDebug(...args);\n}\n\n/**\n * Always-visible warning. Reserved for things the user genuinely needs to\n * see: config mistakes, repeated init with conflicting DSN, auth failure.\n * Deduped — the same warning text only fires once per page load so a noisy\n * caller can't fill the console with the same message.\n */\nconst _warnedOnce = new Set<string>();\nfunction _warn(message: string, ...rest: unknown[]): void {\n if (_warnedOnce.has(message)) return;\n _warnedOnce.add(message);\n _origWarn(message, ...rest);\n}\n\n// --- Double-init safety: Symbol.for() originals store ---\n// Survives HMR module reloads because Symbol.for() returns the same symbol across realms.\n// True originals are saved exactly once — never overwritten by subsequent connect() calls.\nconst ORIGINALS_KEY = Symbol.for('__runtimescope_originals__');\n\ninterface SavedOriginals {\n fetch: typeof globalThis.fetch;\n xhrOpen: typeof XMLHttpRequest.prototype.open;\n xhrSend: typeof XMLHttpRequest.prototype.send;\n xhrSetRequestHeader: typeof XMLHttpRequest.prototype.setRequestHeader;\n consoleMethods: Record<string, (...args: unknown[]) => void>;\n}\n\nfunction getOrSaveOriginals(): SavedOriginals {\n const g = globalThis as Record<symbol, SavedOriginals>;\n if (!g[ORIGINALS_KEY]) {\n g[ORIGINALS_KEY] = {\n fetch: window.fetch,\n xhrOpen: XMLHttpRequest.prototype.open,\n xhrSend: XMLHttpRequest.prototype.send,\n xhrSetRequestHeader: XMLHttpRequest.prototype.setRequestHeader,\n consoleMethods: {\n log: console.log.bind(console),\n warn: console.warn.bind(console),\n error: console.error.bind(console),\n info: console.info.bind(console),\n debug: console.debug.bind(console),\n trace: console.trace.bind(console),\n },\n };\n }\n return g[ORIGINALS_KEY];\n}\n\nexport class RuntimeScope {\n private static transport: Transport | null = null;\n private static restoreFns: (() => void)[] = [];\n private static _sessionId: string | null = null;\n private static _state: 'stopped' | 'started' = 'stopped';\n /** Cached config fingerprint from the last init() call — used to detect double-init with conflicting config. */\n private static _initSignature: string | null = null;\n private static _sampleRate: number = 1;\n private static _maxEventsPerSecond: number | undefined;\n private static _windowCount = 0;\n private static _windowStart = 0;\n private static _user: UserContext | undefined;\n\n static get sessionId(): string | null {\n return this._sessionId;\n }\n\n /** Returns true if the SDK is currently connected */\n static get isConnected(): boolean {\n return this._state === 'started';\n }\n\n /** Probabilistic + rate-limit sampling. Returns true if the event should be sent. */\n private static shouldSample(): boolean {\n // Probabilistic sampling\n if (this._sampleRate < 1 && Math.random() > this._sampleRate) {\n return false;\n }\n // Rate limiting\n if (this._maxEventsPerSecond !== undefined) {\n const now = Date.now();\n if (now - this._windowStart >= 1000) {\n this._windowCount = 0;\n this._windowStart = now;\n }\n if (this._windowCount >= this._maxEventsPerSecond) {\n return false;\n }\n this._windowCount++;\n }\n return true;\n }\n\n static connect(config: RuntimeScopeConfig = {}): void {\n if (config.enabled === false) return;\n\n // DSN resolution: single string replaces projectId + endpoint + appName\n let hasDsn = false;\n if (config.dsn) {\n try {\n const parsed = parseDsn(config.dsn);\n config = {\n ...config,\n serverUrl: parsed.wsEndpoint,\n projectId: parsed.projectId,\n // DSN-embedded token takes precedence over an explicit authToken,\n // so pasting a new DSN is the single action users need to do\n ...(parsed.authToken ? { authToken: parsed.authToken } : {}),\n ...(parsed.appName && !config.appName ? { appName: parsed.appName } : {}),\n };\n hasDsn = true;\n } catch (e) {\n _log('[RuntimeScope] Invalid DSN:', (e as Error).message);\n }\n }\n\n // Auto-disable in production: if no explicit endpoint was configured and\n // we're not on localhost, become a no-op. Users with a hosted collector\n // set serverUrl/endpoint explicitly, so this only catches the default case.\n const hasExplicitEndpoint = !!(config.serverUrl || config.endpoint) || hasDsn;\n if (!hasExplicitEndpoint && typeof window !== 'undefined') {\n const host = window.location?.hostname;\n if (host && host !== 'localhost' && host !== '127.0.0.1' && !host.startsWith('192.168.') && !host.startsWith('10.')) {\n _log('[RuntimeScope] No endpoint configured and not on localhost — SDK disabled for production');\n return;\n }\n }\n\n // Resolve `verbose` early so the rest of init logs go through the right path.\n if (config.verbose === true) _debugEnabled = true;\n else if (typeof localStorage !== 'undefined') {\n try {\n if (localStorage.getItem('RUNTIMESCOPE_DEBUG') === '1') _debugEnabled = true;\n } catch {\n // localStorage can throw in sandboxed iframes — just ignore.\n }\n }\n // Propagate to the transport — it has its own _log because it lives in a\n // separate module and the user might construct a Transport directly.\n setTransportDebug(_debugEnabled);\n\n // Idempotent re-init: a second init() call with the same effective config\n // is a silent no-op. With a *different* serverUrl/appName/projectId we\n // warn loudly — that's almost always a footgun where the user has the\n // SDK initialized by the Vite plugin AND by their own bootstrap code,\n // and the second call silently overrides the first to a wrong endpoint.\n const sigCandidate = `${config.appName ?? ''}|${config.serverUrl ?? config.endpoint ?? ''}|${config.dsn ?? ''}|${config.projectId ?? ''}`;\n if (this._state === 'started') {\n if (this._initSignature === sigCandidate) {\n // Same config — nothing to do. Stay connected.\n return;\n }\n _warn(\n `[RuntimeScope] init() called twice with different config — disconnecting and re-initializing.\\n` +\n ` previous: ${this._initSignature}\\n` +\n ` next: ${sigCandidate}\\n` +\n `If the SDK is loaded by @runtimescope/vite, drop your manual RuntimeScope.init() call — the plugin handles it.`,\n );\n this.disconnect();\n }\n this._initSignature = sigCandidate;\n\n const resolved = {\n serverUrl: config.serverUrl ?? config.endpoint ?? 'ws://localhost:6767',\n appName: config.appName ?? 'unknown',\n captureNetwork: config.captureNetwork ?? true,\n captureConsole: config.captureConsole ?? true,\n captureXhr: config.captureXhr ?? true,\n captureBody: config.captureBody ?? false,\n maxBodySize: config.maxBodySize ?? 65536,\n capturePerformance: config.capturePerformance ?? true,\n captureRenders: config.captureRenders ?? true,\n captureNavigation: config.captureNavigation ?? true,\n captureClicks: config.captureClicks ?? true,\n stores: config.stores ?? {},\n beforeSend: config.beforeSend,\n redactHeaders: config.redactHeaders ?? ['authorization', 'cookie'],\n batchSize: config.batchSize ?? 50,\n flushIntervalMs: config.flushIntervalMs ?? 100,\n dedupeConsole: config.dedupeConsole ?? false,\n };\n\n // Save true originals before any patching (idempotent — only saves on first call ever)\n getOrSaveOriginals();\n\n this._sessionId = generateSessionId();\n this._state = 'started';\n\n this.transport = new Transport({\n serverUrl: resolved.serverUrl,\n appName: resolved.appName,\n sessionId: this._sessionId,\n sdkVersion: SDK_VERSION,\n authToken: config.authToken,\n projectId: config.projectId,\n batchSize: resolved.batchSize,\n flushIntervalMs: resolved.flushIntervalMs,\n });\n\n // Sampling config\n this._sampleRate = config.sampleRate ?? 1;\n this._maxEventsPerSecond = config.maxEventsPerSecond;\n this._windowCount = 0;\n this._windowStart = Date.now();\n this._user = config.user;\n\n this.transport.connect();\n _log(`[RuntimeScope] SDK v${SDK_VERSION} initializing — app: ${resolved.appName}, server: ${resolved.serverUrl}`);\n\n // If the transport isn't connected within 10s, emit a visible warning so\n // Claude Code (and humans) see the problem. We use console.warn once —\n // not the patched console (that routes to RuntimeScope itself, which is\n // pointless here) — so the message appears in the user's terminal /\n // browser DevTools.\n const originalWarn = getOrSaveOriginals().consoleMethods.warn;\n const warnTransportRef = this.transport;\n const warnServerUrl = resolved.serverUrl;\n setTimeout(() => {\n // Only warn if init wasn't replaced (user didn't disconnect) AND the\n // transport still hasn't connected. `isConnected()` is a cheap check.\n if (this.transport !== warnTransportRef) return;\n if (warnTransportRef.isConnected?.()) return;\n const isLocalUrl = /localhost|127\\.0\\.0\\.1/.test(warnServerUrl);\n const fix = isLocalUrl\n ? 'Run `npx runtimescope start` in a terminal.'\n : `Check that ${warnServerUrl} is reachable and the collector is running.`;\n originalWarn(\n `[RuntimeScope] Couldn't connect to ${warnServerUrl} after 10s. No events are being captured.`,\n `\\n Fix: ${fix}`,\n );\n }, 10_000);\n\n const emit = (event: RuntimeEvent) => {\n // Session, custom, and UI events always pass through (never sampled out)\n if (event.eventType !== 'session' && event.eventType !== 'custom' && event.eventType !== 'ui') {\n if (!this.shouldSample()) return;\n }\n this.transport?.send(event);\n };\n\n // Send session event\n emit({\n eventId: generateId(),\n sessionId: this._sessionId,\n timestamp: Date.now(),\n eventType: 'session',\n appName: resolved.appName,\n connectedAt: Date.now(),\n sdkVersion: SDK_VERSION,\n buildMeta: config.buildMeta,\n user: this._user,\n projectId: config.projectId,\n });\n\n // Register command handler for server→SDK commands\n const sessionId = this._sessionId;\n this.transport.onCommand((cmd: { command: string; requestId: string; params?: Record<string, unknown> }) => {\n this.handleCommand(cmd, emit, sessionId);\n });\n\n // Fetch interceptor\n if (resolved.captureNetwork) {\n this.restoreFns.push(\n interceptFetch(emit, this._sessionId, resolved.redactHeaders, {\n captureBody: resolved.captureBody,\n maxBodySize: resolved.maxBodySize,\n beforeSend: resolved.beforeSend,\n })\n );\n }\n\n // XHR interceptor\n if (resolved.captureXhr) {\n this.restoreFns.push(\n interceptXhr(emit, this._sessionId, resolved.redactHeaders, {\n captureBody: resolved.captureBody,\n maxBodySize: resolved.maxBodySize,\n beforeSend: resolved.beforeSend,\n })\n );\n }\n\n // Console interceptor\n if (resolved.captureConsole) {\n this.restoreFns.push(\n interceptConsole(emit, this._sessionId, resolved.beforeSend, resolved.dedupeConsole)\n );\n }\n\n // Error interceptor (uncaught errors, resource failures, unhandled rejections)\n // Independent from captureConsole — these don't go through console.* API\n if (config.captureErrors !== false) {\n this.restoreFns.push(\n interceptErrors(emit, this._sessionId, resolved.beforeSend)\n );\n }\n\n // State store inspection\n if (Object.keys(resolved.stores).length > 0) {\n this.restoreFns.push(\n interceptStateStores(emit, this._sessionId, resolved.stores, {\n beforeSend: resolved.beforeSend,\n })\n );\n }\n\n // Performance metrics (Web Vitals)\n if (resolved.capturePerformance) {\n this.restoreFns.push(\n interceptPerformance(emit, this._sessionId, {\n beforeSend: resolved.beforeSend,\n })\n );\n }\n\n // React render tracking\n if (resolved.captureRenders) {\n this.restoreFns.push(\n interceptReactRenders(emit, this._sessionId, {\n beforeSend: resolved.beforeSend,\n })\n );\n }\n\n // Navigation / routing events (pushState, popstate, hashchange)\n if (resolved.captureNavigation) {\n this.restoreFns.push(\n interceptNavigation(emit, this._sessionId)\n );\n }\n\n // Click tracking (UI interaction breadcrumbs)\n if (resolved.captureClicks) {\n this.restoreFns.push(\n interceptClicks(emit, this._sessionId)\n );\n }\n\n const features = [\n resolved.captureNetwork && 'fetch',\n resolved.captureXhr && 'xhr',\n resolved.captureConsole && 'console, errors',\n Object.keys(resolved.stores).length > 0 && 'state',\n resolved.capturePerformance && 'performance',\n resolved.captureRenders && 'renders',\n resolved.captureNavigation && 'navigation',\n resolved.captureClicks && 'clicks',\n ].filter(Boolean);\n _log(`[RuntimeScope] Interceptors active — ${features.join(', ')}`);\n if (this._sampleRate < 1) {\n _log(`[RuntimeScope] Sampling at ${(this._sampleRate * 100).toFixed(0)}%`);\n }\n if (this._maxEventsPerSecond !== undefined) {\n _log(`[RuntimeScope] Rate limited to ${this._maxEventsPerSecond} events/sec`);\n }\n }\n\n private static handleCommand(\n cmd: { command: string; requestId: string; params?: Record<string, unknown> },\n emit: (event: RuntimeEvent) => void,\n sessionId: string\n ): void {\n switch (cmd.command) {\n case 'capture_dom_snapshot': {\n const maxSize = (cmd.params?.maxSize as number) ?? 500_000;\n let html = document.documentElement.outerHTML;\n const truncated = html.length > maxSize;\n if (truncated) html = html.slice(0, maxSize);\n\n const snapshot: DomSnapshotEvent = {\n eventId: generateId(),\n sessionId,\n timestamp: Date.now(),\n eventType: 'dom_snapshot',\n html,\n url: window.location.href,\n viewport: { width: window.innerWidth, height: window.innerHeight },\n scrollPosition: { x: window.scrollX, y: window.scrollY },\n elementCount: document.querySelectorAll('*').length,\n truncated,\n };\n\n emit(snapshot);\n this.transport?.sendCommandResponse(cmd.requestId, cmd.command, snapshot);\n break;\n }\n default:\n this.transport?.sendCommandResponse(cmd.requestId, cmd.command, { error: 'Unknown command' });\n }\n }\n\n /** Alias for `connect` — used by script-tag snippets */\n static init(config: RuntimeScopeConfig = {}): void {\n return this.connect(config);\n }\n\n /**\n * Track a custom business/product event.\n * Use this to mark meaningful moments in your app (e.g. user actions, conversions).\n * These events are correlated with all other telemetry (network, console, state)\n * to build causal chains and detect failures.\n */\n static track(name: string, properties?: Record<string, unknown>): void {\n if (!this.transport || !this._sessionId) return;\n\n const event: CustomEvent = {\n eventId: generateId(),\n sessionId: this._sessionId,\n timestamp: Date.now(),\n eventType: 'custom',\n name,\n properties,\n };\n\n this.transport.send(event);\n }\n\n /**\n * Set user context attached to the current session.\n * Call this after login to associate events with a specific user.\n * Pass null to clear user context.\n */\n static setUser(user: UserContext | null): void {\n this._user = user ?? undefined;\n\n // Send an updated session event so the collector picks up the user context\n if (this.transport && this._sessionId) {\n this.transport.send({\n eventId: generateId(),\n sessionId: this._sessionId,\n timestamp: Date.now(),\n eventType: 'session',\n appName: 'user_update',\n connectedAt: Date.now(),\n sdkVersion: SDK_VERSION,\n user: this._user,\n });\n }\n }\n\n /**\n * Add a manual breadcrumb to the event trail.\n * Use this to mark meaningful moments that help debug errors\n * (e.g., \"user opened settings\", \"form validated\", \"retry attempt 2\").\n */\n static addBreadcrumb(\n message: string,\n data?: Record<string, unknown>\n ): void {\n if (!this.transport || !this._sessionId) return;\n\n const event: UIInteractionEvent = {\n eventId: generateId(),\n sessionId: this._sessionId,\n timestamp: Date.now(),\n eventType: 'ui',\n action: 'breadcrumb',\n target: 'manual',\n text: message,\n ...(data && { data }),\n };\n\n this.transport.send(event);\n }\n\n static disconnect(): void {\n // Run all interceptor restore functions\n for (const fn of this.restoreFns) {\n try { fn(); } catch { /* ensure all restores run */ }\n }\n this.restoreFns = [];\n\n // Safety net: if restore functions didn't fully unwind (e.g. another library\n // patched over us), fall back to true originals saved via Symbol.for()\n const originals = (globalThis as Record<symbol, SavedOriginals>)[ORIGINALS_KEY];\n if (originals) {\n // Only restore if current value is NOT the original (i.e. we or nobody else patched)\n if (window.fetch !== originals.fetch) {\n window.fetch = originals.fetch;\n }\n for (const [level, fn] of Object.entries(originals.consoleMethods)) {\n const c = console as unknown as Record<string, unknown>;\n if (c[level] !== fn) {\n c[level] = fn;\n }\n }\n }\n\n this.transport?.disconnect();\n this.transport = null;\n this._sessionId = null;\n this._state = 'stopped';\n }\n}\n\nexport default RuntimeScope;\nexport { parseDsn, buildDsn } from './dsn.js';\nexport type { ParsedDsn } from './dsn.js';\nexport type {\n RuntimeScopeConfig,\n BuildMeta,\n UserContext,\n NetworkEvent,\n ConsoleEvent,\n SessionEvent,\n StateEvent,\n RenderEvent,\n DomSnapshotEvent,\n PerformanceEvent,\n NavigationEvent,\n CustomEvent,\n UIInteractionEvent,\n RuntimeEvent,\n} from './types.js';\n","import type { RuntimeEvent } from './types.js';\n\n// Save original console methods BEFORE any interceptors patch them. The SDK\n// uses these for its own diagnostics so its logs don't loop back through the\n// console interceptor. `_log` is opt-in (off unless RUNTIMESCOPE_DEBUG flag /\n// localStorage / config.verbose is set) — keeps DevTools clean by default.\nconst _origDebug = console.debug.bind(console);\nconst _origWarn = console.warn.bind(console);\n\nlet _debugEnabled = false;\nfunction _readDebugFlag(): void {\n if (_debugEnabled) return;\n if (typeof localStorage !== 'undefined') {\n try {\n if (localStorage.getItem('RUNTIMESCOPE_DEBUG') === '1') _debugEnabled = true;\n } catch { /* sandboxed iframe — ignore */ }\n }\n}\n_readDebugFlag();\nfunction _log(...args: unknown[]): void {\n if (_debugEnabled) _origDebug(...args);\n}\n/** Public hook so index.ts can flip debug on when `init({ verbose: true })` is set. */\nexport function setTransportDebug(enabled: boolean): void {\n _debugEnabled = enabled;\n}\n\ninterface TransportConfig {\n serverUrl: string;\n appName: string;\n sessionId: string;\n sdkVersion: string;\n authToken?: string;\n projectId?: string;\n batchSize: number;\n flushIntervalMs: number;\n}\n\nexport class Transport {\n private ws: WebSocket | null = null;\n private batch: RuntimeEvent[] = [];\n private offlineQueue: RuntimeEvent[] = [];\n private flushTimer: ReturnType<typeof setInterval> | null = null;\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private reconnectDelay = 500;\n private reconnectAttempt = 0;\n private connected = false;\n private stopped = false;\n private config: TransportConfig;\n\n /** True when the WebSocket handshake has completed and we can send events. */\n isConnected(): boolean {\n return this.connected;\n }\n private commandHandler: ((cmd: { command: string; requestId: string; params?: Record<string, unknown> }) => void) | null = null;\n private hasEverConnected = false;\n private connectionWarningTimer: ReturnType<typeof setTimeout> | null = null;\n private visibilityHandler: (() => void) | null = null;\n private onlineHandler: (() => void) | null = null;\n\n private static readonly MAX_OFFLINE_QUEUE = 1000;\n private static readonly MAX_RECONNECT_DELAY = 30_000;\n private static readonly CONNECTION_WARNING_DELAY = 10_000;\n /** First N retries use a fast 500ms delay before switching to exponential backoff */\n private static readonly FAST_RETRY_COUNT = 3;\n private static readonly FAST_RETRY_DELAY = 500;\n\n constructor(config: TransportConfig) {\n this.config = config;\n }\n\n connect(): void {\n this.stopped = false;\n this.doConnect();\n\n // Warn if we never establish a connection within 10 seconds\n this.connectionWarningTimer = setTimeout(() => {\n if (!this.hasEverConnected && !this.stopped) {\n console.warn(\n `[RuntimeScope] SDK has not connected to ${this.config.serverUrl} after 10s. ` +\n `Is the collector running? Start it with: npx @runtimescope/collector`\n );\n }\n }, Transport.CONNECTION_WARNING_DELAY);\n\n // When the user switches back to this tab, try to reconnect immediately\n if (typeof document !== 'undefined') {\n this.visibilityHandler = () => {\n if (document.visibilityState === 'visible' && !this.connected && !this.stopped) {\n _log('[RuntimeScope] Tab visible — attempting immediate reconnect');\n this.resetReconnectState();\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n this.doConnect();\n }\n };\n document.addEventListener('visibilitychange', this.visibilityHandler);\n }\n\n // Reconnect immediately when network comes back online\n if (typeof window !== 'undefined') {\n this.onlineHandler = () => {\n if (!this.connected && !this.stopped) {\n _log('[RuntimeScope] Network online — attempting immediate reconnect');\n this.resetReconnectState();\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n this.doConnect();\n }\n };\n window.addEventListener('online', this.onlineHandler);\n }\n }\n\n private doConnect(): void {\n if (this.stopped) return;\n\n try {\n this.ws = new WebSocket(this.config.serverUrl);\n } catch {\n this.scheduleReconnect();\n return;\n }\n\n this.ws.onmessage = (event: MessageEvent) => {\n try {\n const msg = JSON.parse(String(event.data));\n if (msg.type === 'command' && msg.payload && this.commandHandler) {\n this.commandHandler(msg.payload);\n }\n // Handle server restart notice — reset backoff for immediate reconnect\n if (msg.type === '__server_restart') {\n _log('[RuntimeScope] Server restart notice received — will reconnect immediately');\n this.resetReconnectState();\n }\n // Handle auth rejection — stop reconnecting\n if (msg.type === 'error' && msg.payload?.code === 'AUTH_FAILED') {\n _log('[RuntimeScope] Authentication failed — stopping reconnection');\n this.stopped = true;\n }\n } catch {\n // Ignore unparseable messages\n }\n };\n\n this.ws.onopen = () => {\n this.connected = true;\n this.hasEverConnected = true;\n this.resetReconnectState();\n _log(`[RuntimeScope] Connected to ${this.config.serverUrl}`);\n\n // Send handshake\n this.sendRaw({\n type: 'handshake',\n payload: {\n appName: this.config.appName,\n sdkVersion: this.config.sdkVersion,\n sessionId: this.config.sessionId,\n ...(this.config.authToken ? { authToken: this.config.authToken } : {}),\n ...(this.config.projectId ? { projectId: this.config.projectId } : {}),\n },\n timestamp: Date.now(),\n sessionId: this.config.sessionId,\n });\n\n // Flush offline queue\n if (this.offlineQueue.length > 0) {\n const queued = this.offlineQueue.splice(0);\n for (const event of queued) {\n this.batch.push(event);\n }\n this.flush();\n }\n\n // Start periodic flush\n this.flushTimer = setInterval(() => this.flush(), this.config.flushIntervalMs);\n };\n\n this.ws.onclose = () => {\n this.connected = false;\n this.clearFlushTimer();\n if (!this.stopped) {\n _log(`[RuntimeScope] Disconnected, will reconnect...`);\n this.scheduleReconnect();\n }\n };\n\n this.ws.onerror = () => {\n _log(`[RuntimeScope] WebSocket error connecting to ${this.config.serverUrl}`);\n };\n }\n\n send(event: RuntimeEvent): void {\n if (this.connected) {\n this.batch.push(event);\n if (this.batch.length >= this.config.batchSize) {\n this.flush();\n }\n } else {\n // Queue for when we reconnect\n if (this.offlineQueue.length < Transport.MAX_OFFLINE_QUEUE) {\n this.offlineQueue.push(event);\n }\n }\n }\n\n private flush(): void {\n if (this.batch.length === 0 || !this.connected || !this.ws) return;\n\n const events = this.batch.splice(0);\n this.sendRaw({\n type: 'event',\n payload: { events },\n timestamp: Date.now(),\n sessionId: this.config.sessionId,\n });\n }\n\n private sendRaw(msg: unknown): void {\n if (this.ws && this.ws.readyState === WebSocket.OPEN) {\n try {\n this.ws.send(JSON.stringify(msg));\n } catch {\n // Drop silently — reconnect will handle it\n }\n }\n }\n\n private scheduleReconnect(): void {\n if (this.stopped || this.reconnectTimer) return;\n\n this.reconnectAttempt++;\n\n // Fast retries for the first few attempts (collector restart gap is typically 1-3s)\n let delay: number;\n if (this.reconnectAttempt <= Transport.FAST_RETRY_COUNT) {\n delay = Transport.FAST_RETRY_DELAY;\n } else {\n // Exponential backoff with jitter after fast retries exhausted\n const jitter = this.reconnectDelay * 0.25 * (Math.random() * 2 - 1);\n delay = Math.min(this.reconnectDelay + jitter, Transport.MAX_RECONNECT_DELAY);\n this.reconnectDelay = Math.min(this.reconnectDelay * 2, Transport.MAX_RECONNECT_DELAY);\n }\n\n this.reconnectTimer = setTimeout(() => {\n this.reconnectTimer = null;\n this.doConnect();\n }, delay);\n }\n\n private resetReconnectState(): void {\n this.reconnectDelay = 500;\n this.reconnectAttempt = 0;\n }\n\n private clearFlushTimer(): void {\n if (this.flushTimer) {\n clearInterval(this.flushTimer);\n this.flushTimer = null;\n }\n }\n\n onCommand(handler: (cmd: { command: string; requestId: string; params?: Record<string, unknown> }) => void): void {\n this.commandHandler = handler;\n }\n\n sendCommandResponse(requestId: string, command: string, payload: unknown): void {\n this.sendRaw({\n type: 'command_response',\n requestId,\n command,\n payload,\n timestamp: Date.now(),\n sessionId: this.config.sessionId,\n });\n }\n\n disconnect(): void {\n this.stopped = true;\n this.clearFlushTimer();\n\n if (this.connectionWarningTimer) {\n clearTimeout(this.connectionWarningTimer);\n this.connectionWarningTimer = null;\n }\n\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n\n if (this.visibilityHandler && typeof document !== 'undefined') {\n document.removeEventListener('visibilitychange', this.visibilityHandler);\n this.visibilityHandler = null;\n }\n\n if (this.onlineHandler && typeof window !== 'undefined') {\n window.removeEventListener('online', this.onlineHandler);\n this.onlineHandler = null;\n }\n\n // Final flush before closing\n this.flush();\n\n if (this.ws) {\n this.ws.onclose = null;\n this.ws.onerror = null;\n this.ws.close();\n this.ws = null;\n }\n\n this.connected = false;\n this.batch = [];\n this.offlineQueue = [];\n }\n}\n","/** 16-char random hex string for event IDs. */\nexport function generateId(): string {\n const arr = new Uint8Array(8);\n crypto.getRandomValues(arr);\n return Array.from(arr, (b) => b.toString(16).padStart(2, '0')).join('');\n}\n\n/** 32-char random hex string for session IDs. */\nexport function generateSessionId(): string {\n const arr = new Uint8Array(16);\n crypto.getRandomValues(arr);\n return Array.from(arr, (b) => b.toString(16).padStart(2, '0')).join('');\n}\n","import { generateId } from '../utils/id.js';\nimport type { NetworkEvent, GraphQLOperation, RuntimeEvent } from '../types.js';\n\ntype EmitFn = (event: NetworkEvent) => void;\n\nexport interface FetchInterceptorOptions {\n captureBody?: boolean;\n maxBodySize?: number;\n beforeSend?: (event: RuntimeEvent) => RuntimeEvent | null;\n}\n\n// Track URLs intercepted by fetch to prevent XHR double-counting (fetch polyfill case).\n// Uses a Map with timestamps + single sweeper instead of per-request setTimeout.\nconst MAX_INFLIGHT = 1000;\nconst INFLIGHT_TTL_MS = 10_000;\nconst SWEEP_INTERVAL_MS = 5_000;\n\nexport const fetchInterceptedRequests = new Map<string, number>();\nlet sweepTimer: ReturnType<typeof setInterval> | null = null;\nlet sweepRefCount = 0;\n\nfunction startSweeper(): void {\n sweepRefCount++;\n if (sweepTimer) return;\n sweepTimer = setInterval(() => {\n const cutoff = Date.now() - INFLIGHT_TTL_MS;\n for (const [key, ts] of fetchInterceptedRequests) {\n if (ts < cutoff) fetchInterceptedRequests.delete(key);\n }\n }, SWEEP_INTERVAL_MS);\n}\n\nfunction stopSweeper(): void {\n sweepRefCount--;\n if (sweepRefCount <= 0 && sweepTimer) {\n clearInterval(sweepTimer);\n sweepTimer = null;\n sweepRefCount = 0;\n }\n}\n\nexport function interceptFetch(\n emit: EmitFn,\n sessionId: string,\n redactHeaders: string[],\n options?: FetchInterceptorOptions\n): () => void {\n const originalFetch = window.fetch;\n const redactSet = new Set(redactHeaders.map((h) => h.toLowerCase()));\n const captureBody = options?.captureBody ?? false;\n const maxBodySize = options?.maxBodySize ?? 65536;\n\n startSweeper();\n\n window.fetch = async function (\n input: RequestInfo | URL,\n init?: RequestInit\n ): Promise<Response> {\n const startTime = performance.now();\n const url =\n typeof input === 'string'\n ? input\n : input instanceof URL\n ? input.href\n : input.url;\n const method = (init?.method ?? 'GET').toUpperCase();\n\n const requestHeaders = extractHeaders(init?.headers, redactSet);\n const requestBodySize = estimateBodySize(init?.body);\n const graphqlOperation = detectGraphQL(init?.body);\n\n // Capture request body if enabled\n let requestBody: string | undefined;\n if (captureBody && init?.body) {\n requestBody = serializeBody(init.body, maxBodySize);\n }\n\n // Mark request to prevent XHR interceptor double-counting (fetch polyfill case)\n const requestKey = `${method}:${url}:${startTime}`;\n // Evict oldest entry if at capacity\n if (fetchInterceptedRequests.size >= MAX_INFLIGHT) {\n const oldest = fetchInterceptedRequests.keys().next().value;\n if (oldest !== undefined) fetchInterceptedRequests.delete(oldest);\n }\n fetchInterceptedRequests.set(requestKey, Date.now());\n\n try {\n const response = await originalFetch.call(window, input, init);\n const duration = performance.now() - startTime;\n\n const responseBodySize = parseInt(\n response.headers.get('content-length') || '0',\n 10\n );\n const responseHeaders = extractResponseHeaders(response.headers, redactSet);\n\n // Capture response body if enabled\n let responseBody: string | undefined;\n if (captureBody) {\n try {\n const clone = response.clone();\n const text = await clone.text();\n responseBody = text.length > maxBodySize ? text.slice(0, maxBodySize) : text;\n } catch {\n // CORS or stream-locked — skip body capture\n }\n }\n\n const event: NetworkEvent = {\n eventId: generateId(),\n sessionId,\n timestamp: Date.now(),\n eventType: 'network',\n url,\n method,\n status: response.status,\n requestHeaders,\n responseHeaders,\n requestBodySize,\n responseBodySize,\n duration,\n ttfb: duration,\n graphqlOperation,\n requestBody,\n responseBody,\n source: 'fetch',\n };\n\n if (options?.beforeSend) {\n const filtered = options.beforeSend(event);\n if (filtered) emit(filtered as NetworkEvent);\n } else {\n emit(event);\n }\n\n return response;\n } catch (error) {\n const duration = performance.now() - startTime;\n\n let errorPhase: 'error' | 'abort' | 'timeout' = 'error';\n let errorMessage = '';\n\n if (error instanceof DOMException && error.name === 'AbortError') {\n errorPhase = 'abort';\n errorMessage = 'Request aborted';\n } else if (error instanceof Error) {\n errorMessage = error.message;\n }\n\n const event: NetworkEvent = {\n eventId: generateId(),\n sessionId,\n timestamp: Date.now(),\n eventType: 'network',\n url,\n method,\n status: 0,\n requestHeaders,\n responseHeaders: {},\n requestBodySize,\n responseBodySize: 0,\n duration,\n ttfb: 0,\n graphqlOperation,\n requestBody,\n errorPhase,\n errorMessage,\n source: 'fetch',\n };\n\n if (options?.beforeSend) {\n const filtered = options.beforeSend(event);\n if (filtered) emit(filtered as NetworkEvent);\n } else {\n emit(event);\n }\n\n throw error;\n }\n };\n\n return () => {\n window.fetch = originalFetch;\n stopSweeper();\n };\n}\n\nfunction extractHeaders(\n headers: HeadersInit | undefined,\n redactSet: Set<string>\n): Record<string, string> {\n const result: Record<string, string> = {};\n if (!headers) return result;\n\n if (headers instanceof Headers) {\n headers.forEach((value, key) => {\n result[key] = redactSet.has(key.toLowerCase()) ? '[REDACTED]' : value;\n });\n } else if (Array.isArray(headers)) {\n for (const [key, value] of headers) {\n result[key] = redactSet.has(key.toLowerCase()) ? '[REDACTED]' : value;\n }\n } else {\n for (const [key, value] of Object.entries(headers)) {\n result[key] = redactSet.has(key.toLowerCase()) ? '[REDACTED]' : value;\n }\n }\n\n return result;\n}\n\nfunction extractResponseHeaders(\n headers: Headers,\n redactSet: Set<string>\n): Record<string, string> {\n const result: Record<string, string> = {};\n headers.forEach((value, key) => {\n result[key] = redactSet.has(key.toLowerCase()) ? '[REDACTED]' : value;\n });\n return result;\n}\n\nfunction estimateBodySize(body: BodyInit | null | undefined): number {\n if (!body) return 0;\n if (typeof body === 'string') return new Blob([body]).size;\n if (body instanceof Blob) return body.size;\n if (body instanceof ArrayBuffer) return body.byteLength;\n if (ArrayBuffer.isView(body)) return body.byteLength;\n if (body instanceof FormData) return 0;\n if (body instanceof URLSearchParams) return new Blob([body.toString()]).size;\n return 0;\n}\n\nfunction serializeBody(body: BodyInit | null | undefined, maxSize: number): string | undefined {\n if (!body) return undefined;\n if (typeof body === 'string') return body.length > maxSize ? body.slice(0, maxSize) : body;\n if (body instanceof URLSearchParams) {\n const s = body.toString();\n return s.length > maxSize ? s.slice(0, maxSize) : s;\n }\n if (body instanceof FormData) return '[FormData]';\n if (body instanceof Blob) return `[Blob ${body.size} bytes]`;\n if (body instanceof ArrayBuffer) return `[ArrayBuffer ${body.byteLength} bytes]`;\n if (ArrayBuffer.isView(body)) return `[TypedArray ${body.byteLength} bytes]`;\n return undefined;\n}\n\nfunction detectGraphQL(body: BodyInit | null | undefined): GraphQLOperation | undefined {\n if (!body || typeof body !== 'string') return undefined;\n\n try {\n const parsed = JSON.parse(body);\n if (typeof parsed.query === 'string') {\n const trimmed = parsed.query.trim();\n let type: GraphQLOperation['type'] = 'query';\n if (trimmed.startsWith('mutation')) type = 'mutation';\n else if (trimmed.startsWith('subscription')) type = 'subscription';\n\n const name = parsed.operationName || extractOperationName(trimmed) || 'anonymous';\n return { type, name };\n }\n } catch {\n // Not GraphQL\n }\n\n return undefined;\n}\n\nfunction extractOperationName(query: string): string | undefined {\n const match = query.match(/^(?:query|mutation|subscription)\\s+(\\w+)/);\n return match?.[1];\n}\n","/** Safely serialize a value, handling circular references, functions, symbols, and errors. */\nexport function safeSerialize(value: unknown, maxDepth = 5): unknown {\n const seen = new WeakSet();\n\n function walk(val: unknown, depth: number): unknown {\n if (depth > maxDepth) return '[max depth]';\n if (val === null || val === undefined) return val;\n if (typeof val === 'function') return `[Function: ${val.name || 'anonymous'}]`;\n if (typeof val === 'symbol') return val.toString();\n if (typeof val === 'bigint') return val.toString();\n if (typeof val !== 'object') return val;\n\n if (val instanceof Error) {\n return { name: val.name, message: val.message, stack: val.stack };\n }\n if (val instanceof Date) {\n return val.toISOString();\n }\n if (val instanceof RegExp) {\n return val.toString();\n }\n\n if (seen.has(val as object)) return '[Circular]';\n seen.add(val as object);\n\n if (Array.isArray(val)) {\n return val.map((v) => walk(v, depth + 1));\n }\n\n const result: Record<string, unknown> = {};\n let keys: string[];\n try {\n keys = Object.keys(val as Record<string, unknown>);\n } catch {\n return '[Object]';\n }\n // Limit keys to avoid huge React fiber-like objects\n const maxKeys = 50;\n for (let i = 0; i < Math.min(keys.length, maxKeys); i++) {\n try {\n result[keys[i]] = walk((val as Record<string, unknown>)[keys[i]], depth + 1);\n } catch {\n result[keys[i]] = '[Error accessing property]';\n }\n }\n if (keys.length > maxKeys) result['...'] = `${keys.length - maxKeys} more keys`;\n return result;\n }\n\n return walk(value, 0);\n}\n","import { generateId } from '../utils/id.js';\nimport { safeSerialize } from '../utils/serialize.js';\nimport type { ConsoleEvent, ConsoleLevel, RuntimeEvent } from '../types.js';\n\ntype EmitFn = (event: ConsoleEvent) => void;\n\nconst LEVELS: ConsoleLevel[] = ['log', 'warn', 'error', 'info', 'debug', 'trace'];\n\nexport interface ConsoleDedupeOptions {\n /** Window during which identical messages are considered duplicates. Default 5000ms. */\n windowMs?: number;\n /** First N occurrences of a duplicate burst still print normally. Default 3 — gives users a sense of frequency without an explosion. */\n maxBurst?: number;\n /** How often to flush the \"suppressed N messages\" summary line. Default 5000ms. */\n summaryIntervalMs?: number;\n}\n\ninterface DedupeState {\n count: number;\n firstAt: number;\n suppressed: number;\n level: ConsoleLevel;\n preview: string;\n}\n\n/**\n * Build a dedupe gate for the console interceptor.\n *\n * The collector still receives every event — this only filters what reaches\n * the actual browser DevTools, keeping the console clean in production.\n *\n * Returns:\n * - shouldPrint(level, message): true if this call should pass through to\n * the original console method, false if it's been suppressed.\n * - dispose(): clears the summary timer (called on interceptor teardown).\n */\nfunction makeDedupeGate(\n options: Required<ConsoleDedupeOptions>,\n printSummary: (text: string) => void,\n): { shouldPrint: (level: ConsoleLevel, message: string) => boolean; dispose: () => void } {\n const seen = new Map<string, DedupeState>();\n\n const summaryTimer = setInterval(() => {\n let totalSuppressed = 0;\n for (const state of seen.values()) {\n if (state.suppressed > 0) {\n totalSuppressed += state.suppressed;\n state.suppressed = 0;\n }\n }\n if (totalSuppressed > 0) {\n printSummary(\n `[RuntimeScope] suppressed ${totalSuppressed} duplicate console message${totalSuppressed === 1 ? '' : 's'} in the last ${options.summaryIntervalMs / 1000}s — full data in the dashboard.`,\n );\n }\n // Garbage-collect entries older than the dedupe window so the map doesn't\n // grow forever for unique-but-rare messages.\n const cutoff = Date.now() - options.windowMs;\n for (const [key, state] of seen) {\n if (state.firstAt < cutoff && state.suppressed === 0) seen.delete(key);\n }\n }, options.summaryIntervalMs);\n // Don't keep the page alive if everything else has shut down.\n if (typeof (summaryTimer as { unref?: () => void }).unref === 'function') {\n (summaryTimer as { unref: () => void }).unref();\n }\n\n return {\n shouldPrint(level, message) {\n const now = Date.now();\n const key = `${level}|${message}`;\n let state = seen.get(key);\n if (state && now - state.firstAt > options.windowMs) {\n // Window elapsed — start fresh.\n state = undefined;\n }\n if (!state) {\n seen.set(key, {\n count: 1,\n firstAt: now,\n suppressed: 0,\n level,\n preview: message.slice(0, 80),\n });\n return true;\n }\n state.count++;\n if (state.count <= options.maxBurst) return true;\n state.suppressed++;\n return false;\n },\n dispose() { clearInterval(summaryTimer); },\n };\n}\n\n/** Extract the caller's source file from an Error stack trace. */\nfunction extractSourceFile(stack: string | undefined): string | undefined {\n if (!stack) return undefined;\n // Skip first 3 lines: \"Error\", our interceptor, and the console wrapper\n const lines = stack.split('\\n').slice(3);\n for (const line of lines) {\n // Match \"at ... (file:line:col)\" or \"at file:line:col\"\n const match = line.match(/(?:at\\s+)?(?:.*?\\()?(.+?):(\\d+):(\\d+)\\)?/);\n if (match && !match[1].includes('interceptor') && !match[1].includes('runtimescope')) {\n return `${match[1]}:${match[2]}`;\n }\n }\n return undefined;\n}\n\nexport function interceptConsole(\n emit: EmitFn,\n sessionId: string,\n beforeSend?: (event: RuntimeEvent) => RuntimeEvent | null,\n dedupe?: ConsoleDedupeOptions | boolean\n): () => void {\n const originals: Record<string, (...args: unknown[]) => void> = {};\n const timers = new Map<string, number>();\n const counters = new Map<string, number>();\n\n // Optional dedupe gate — when enabled, identical messages within `windowMs`\n // print at most `maxBurst` times before being suppressed. The collector\n // still receives every event so the dashboard stays accurate.\n const dedupeOptions: Required<ConsoleDedupeOptions> | null = dedupe\n ? {\n windowMs: (typeof dedupe === 'object' ? dedupe.windowMs : undefined) ?? 5000,\n maxBurst: (typeof dedupe === 'object' ? dedupe.maxBurst : undefined) ?? 3,\n summaryIntervalMs:\n (typeof dedupe === 'object' ? dedupe.summaryIntervalMs : undefined) ?? 5000,\n }\n : null;\n // We need the original console.info ahead of any patching for the summary,\n // captured BEFORE the loop below replaces it. Otherwise the summary line\n // itself loops through the interceptor.\n const summarySink = console.info.bind(console);\n const dedupeGate = dedupeOptions\n ? makeDedupeGate(dedupeOptions, (text) => summarySink(text))\n : null;\n\n // Standard log levels\n for (const level of LEVELS) {\n originals[level] = console[level].bind(console);\n\n console[level] = (...args: unknown[]) => {\n const stack = new Error().stack;\n const message = args\n .map((a) => (typeof a === 'string' ? a : stringifyArg(a)))\n .join(' ');\n\n const event: ConsoleEvent = {\n eventId: generateId(),\n sessionId,\n timestamp: Date.now(),\n eventType: 'console',\n level,\n message,\n args: args.map((a) => safeSerialize(a, 3)),\n stackTrace:\n level === 'error' || level === 'trace' ? stack?.split('\\n').slice(2).join('\\n') : undefined,\n sourceFile: extractSourceFile(stack),\n source: 'browser',\n };\n\n // Always emit to the collector — the dashboard wants the full count.\n if (beforeSend) {\n const filtered = beforeSend(event);\n if (filtered) emit(filtered as ConsoleEvent);\n } else {\n emit(event);\n }\n\n // Only suppress the visible browser output, not the collected event.\n if (dedupeGate && !dedupeGate.shouldPrint(level, message)) return;\n\n originals[level](...args);\n };\n }\n\n // console.assert — logs error when condition is false\n const origAssert = console.assert?.bind(console);\n if (origAssert) {\n console.assert = (condition?: boolean, ...args: unknown[]) => {\n if (!condition) {\n const stack = new Error().stack;\n const message = `Assertion failed: ${args.map((a) => typeof a === 'string' ? a : stringifyArg(a)).join(' ')}`;\n emit({\n eventId: generateId(),\n sessionId,\n timestamp: Date.now(),\n eventType: 'console',\n level: 'error',\n message,\n args: args.map((a) => safeSerialize(a, 3)),\n stackTrace: stack?.split('\\n').slice(2).join('\\n'),\n sourceFile: extractSourceFile(stack),\n source: 'browser',\n });\n }\n origAssert(condition, ...args);\n };\n }\n\n // console.time / console.timeEnd — capture timing\n const origTime = console.time?.bind(console);\n const origTimeEnd = console.timeEnd?.bind(console);\n if (origTime) {\n console.time = (label = 'default') => {\n timers.set(label, performance.now());\n origTime(label);\n };\n }\n if (origTimeEnd) {\n console.timeEnd = (label = 'default') => {\n const start = timers.get(label);\n if (start !== undefined) {\n const duration = performance.now() - start;\n timers.delete(label);\n emit({\n eventId: generateId(),\n sessionId,\n timestamp: Date.now(),\n eventType: 'console',\n level: 'info',\n message: `${label}: ${duration.toFixed(2)}ms`,\n args: [{ label, duration }],\n source: 'browser',\n });\n }\n origTimeEnd(label);\n };\n }\n\n // console.count / console.countReset\n const origCount = console.count?.bind(console);\n const origCountReset = console.countReset?.bind(console);\n if (origCount) {\n console.count = (label = 'default') => {\n const count = (counters.get(label) ?? 0) + 1;\n counters.set(label, count);\n emit({\n eventId: generateId(),\n sessionId,\n timestamp: Date.now(),\n eventType: 'console',\n level: 'info',\n message: `${label}: ${count}`,\n args: [{ label, count }],\n source: 'browser',\n });\n origCount(label);\n };\n }\n if (origCountReset) {\n console.countReset = (label = 'default') => {\n counters.delete(label);\n origCountReset(label);\n };\n }\n\n // console.table — capture as info with structured data\n const origTable = console.table?.bind(console);\n if (origTable) {\n console.table = (data: unknown, columns?: string[]) => {\n emit({\n eventId: generateId(),\n sessionId,\n timestamp: Date.now(),\n eventType: 'console',\n level: 'info',\n message: `[table] ${Array.isArray(data) ? `${data.length} rows` : typeof data}`,\n args: [safeSerialize(data, 3)],\n source: 'browser',\n });\n origTable(data, columns);\n };\n }\n\n return () => {\n for (const level of LEVELS) {\n console[level] = originals[level];\n }\n if (origAssert) console.assert = origAssert;\n if (origTime) console.time = origTime;\n if (origTimeEnd) console.timeEnd = origTimeEnd;\n if (origCount) console.count = origCount;\n if (origCountReset) console.countReset = origCountReset;\n if (origTable) console.table = origTable;\n dedupeGate?.dispose();\n };\n}\n\nfunction stringifyArg(arg: unknown): string {\n try {\n return JSON.stringify(arg);\n } catch {\n return String(arg);\n }\n}\n","import { generateId } from '../utils/id.js';\nimport type { NetworkEvent, GraphQLOperation, RuntimeEvent } from '../types.js';\nimport { fetchInterceptedRequests } from './fetch.js';\n\ntype EmitFn = (event: NetworkEvent) => void;\n\nexport interface XhrInterceptorOptions {\n captureBody?: boolean;\n maxBodySize?: number;\n beforeSend?: (event: RuntimeEvent) => RuntimeEvent | null;\n}\n\ninterface AugmentedXHR extends XMLHttpRequest {\n __rs_method?: string;\n __rs_url?: string;\n __rs_headers?: Record<string, string>;\n __rs_start?: number;\n __rs_body?: string;\n __rs_fetchIntercepted?: boolean;\n}\n\nexport function interceptXhr(\n emit: EmitFn,\n sessionId: string,\n redactHeaders: string[],\n options?: XhrInterceptorOptions\n): () => void {\n const redactSet = new Set(redactHeaders.map((h) => h.toLowerCase()));\n const captureBody = options?.captureBody ?? false;\n const maxBodySize = options?.maxBodySize ?? 65536;\n\n // Global AbortController for teardown — aborts all outstanding XHR listeners on disconnect\n const globalAbort = new AbortController();\n\n const origOpen = XMLHttpRequest.prototype.open;\n const origSetRequestHeader = XMLHttpRequest.prototype.setRequestHeader;\n const origSend = XMLHttpRequest.prototype.send;\n\n XMLHttpRequest.prototype.open = function (\n this: AugmentedXHR,\n method: string,\n url: string | URL\n ) {\n this.__rs_method = method.toUpperCase();\n this.__rs_url = typeof url === 'string' ? url : url.href;\n this.__rs_headers = {};\n // eslint-disable-next-line prefer-rest-params\n return origOpen.apply(this, arguments as unknown as Parameters<typeof origOpen>);\n };\n\n XMLHttpRequest.prototype.setRequestHeader = function (\n this: AugmentedXHR,\n name: string,\n value: string\n ) {\n if (this.__rs_headers) {\n this.__rs_headers[name.toLowerCase()] = redactSet.has(name.toLowerCase())\n ? '[REDACTED]'\n : value;\n }\n return origSetRequestHeader.call(this, name, value);\n };\n\n XMLHttpRequest.prototype.send = function (\n this: AugmentedXHR,\n body?: Document | XMLHttpRequestBodyInit | null\n ) {\n // Skip if this request was already captured by the fetch interceptor\n const method = this.__rs_method ?? 'GET';\n const url = this.__rs_url ?? '';\n const requestKey = `${method}:${url}`;\n let alreadyIntercepted = false;\n for (const k of fetchInterceptedRequests.keys()) {\n if (k.startsWith(requestKey)) { alreadyIntercepted = true; break; }\n }\n if (alreadyIntercepted) {\n this.__rs_fetchIntercepted = true;\n return origSend.call(this, body);\n }\n\n const requestHeaders = { ...(this.__rs_headers ?? {}) };\n const startTime = performance.now();\n\n // Capture request body\n let requestBody: string | undefined;\n let requestBodySize = 0;\n if (body) {\n if (typeof body === 'string') {\n requestBodySize = new Blob([body]).size;\n if (captureBody) {\n requestBody = body.length > maxBodySize ? body.slice(0, maxBodySize) : body;\n }\n } else if (body instanceof Blob) {\n requestBodySize = body.size;\n if (captureBody) requestBody = `[Blob ${body.size} bytes]`;\n } else if (body instanceof ArrayBuffer) {\n requestBodySize = body.byteLength;\n if (captureBody) requestBody = `[ArrayBuffer ${body.byteLength} bytes]`;\n } else if (body instanceof FormData) {\n if (captureBody) requestBody = '[FormData]';\n } else if (body instanceof URLSearchParams) {\n const s = body.toString();\n requestBodySize = new Blob([s]).size;\n if (captureBody) requestBody = s.length > maxBodySize ? s.slice(0, maxBodySize) : s;\n }\n }\n\n // Detect GraphQL\n const graphqlOperation = detectGraphQL(body);\n\n const emitEvent = (overrides: Partial<NetworkEvent>) => {\n const event: NetworkEvent = {\n eventId: generateId(),\n sessionId,\n timestamp: Date.now(),\n eventType: 'network',\n url,\n method,\n status: 0,\n requestHeaders,\n responseHeaders: {},\n requestBodySize,\n responseBodySize: 0,\n duration: 0,\n ttfb: 0,\n graphqlOperation,\n requestBody,\n source: 'xhr',\n ...overrides,\n };\n\n if (options?.beforeSend) {\n const filtered = options.beforeSend(event);\n if (filtered) emit(filtered as NetworkEvent);\n } else {\n emit(event);\n }\n };\n\n // Single loadend listener covers all terminal states (load, error, abort, timeout).\n // { once: true } auto-removes per-request; globalAbort.signal enables bulk teardown.\n this.addEventListener('loadend', () => {\n const duration = performance.now() - startTime;\n\n if (this.status > 0) {\n // Successful completion (includes HTTP errors like 4xx/5xx)\n const responseHeaders = parseResponseHeaders(this.getAllResponseHeaders(), redactSet);\n const responseBodySize = parseInt(\n this.getResponseHeader('content-length') || '0',\n 10\n );\n\n let responseBody: string | undefined;\n if (captureBody && (this.responseType === '' || this.responseType === 'text')) {\n try {\n const text = this.responseText;\n responseBody = text.length > maxBodySize ? text.slice(0, maxBodySize) : text;\n } catch {\n // responseText not available for non-text types\n }\n }\n\n emitEvent({\n status: this.status,\n responseHeaders,\n responseBodySize,\n responseBody,\n duration,\n ttfb: duration,\n });\n } else {\n // Network error, abort, or timeout — status is 0\n let errorPhase: 'error' | 'abort' | 'timeout' = 'error';\n let errorMessage = 'Network error';\n\n if (this.readyState === 0 || (this as XMLHttpRequest).status === 0) {\n // Distinguish abort vs timeout vs network error\n // XHR sets readyState to UNSENT (0) on abort\n }\n\n // Check specific failure modes\n if (this.timeout > 0 && duration >= this.timeout) {\n errorPhase = 'timeout';\n errorMessage = `Request timed out after ${this.timeout}ms`;\n }\n\n emitEvent({ duration, errorPhase, errorMessage });\n }\n }, { once: true, signal: globalAbort.signal });\n\n return origSend.call(this, body);\n };\n\n return () => {\n // Abort all outstanding XHR listeners from this interceptor instance\n globalAbort.abort();\n XMLHttpRequest.prototype.open = origOpen;\n XMLHttpRequest.prototype.setRequestHeader = origSetRequestHeader;\n XMLHttpRequest.prototype.send = origSend;\n };\n}\n\nfunction parseResponseHeaders(\n raw: string,\n redactSet: Set<string>\n): Record<string, string> {\n const result: Record<string, string> = {};\n if (!raw) return result;\n\n for (const line of raw.trim().split(/[\\r\\n]+/)) {\n const idx = line.indexOf(':');\n if (idx === -1) continue;\n const key = line.slice(0, idx).trim().toLowerCase();\n const value = line.slice(idx + 1).trim();\n result[key] = redactSet.has(key) ? '[REDACTED]' : value;\n }\n\n return result;\n}\n\nfunction detectGraphQL(\n body: Document | XMLHttpRequestBodyInit | null | undefined\n): GraphQLOperation | undefined {\n if (!body || typeof body !== 'string') return undefined;\n\n try {\n const parsed = JSON.parse(body);\n if (typeof parsed.query === 'string') {\n const trimmed = parsed.query.trim();\n let type: GraphQLOperation['type'] = 'query';\n if (trimmed.startsWith('mutation')) type = 'mutation';\n else if (trimmed.startsWith('subscription')) type = 'subscription';\n\n const name =\n parsed.operationName || extractOperationName(trimmed) || 'anonymous';\n return { type, name };\n }\n } catch {\n // Not GraphQL\n }\n\n return undefined;\n}\n\nfunction extractOperationName(query: string): string | undefined {\n const match = query.match(/^(?:query|mutation|subscription)\\s+(\\w+)/);\n return match?.[1];\n}\n","import { generateId } from '../utils/id.js';\nimport { safeSerialize } from '../utils/serialize.js';\nimport type { StateEvent, RuntimeEvent } from '../types.js';\n\ntype EmitFn = (event: StateEvent) => void;\n\nexport interface StateStoreOptions {\n beforeSend?: (event: RuntimeEvent) => RuntimeEvent | null;\n}\n\ninterface ZustandStore {\n getState: () => unknown;\n setState: (partial: unknown) => void;\n subscribe: (listener: (state: unknown, prevState: unknown) => void) => () => void;\n}\n\ninterface ReduxStore {\n getState: () => unknown;\n dispatch: (action: unknown) => unknown;\n subscribe: (listener: () => void) => () => void;\n}\n\ntype DetectedLibrary = 'zustand' | 'redux' | 'unknown';\n\nexport function interceptStateStores(\n emit: EmitFn,\n sessionId: string,\n stores: Record<string, unknown>,\n options?: StateStoreOptions\n): () => void {\n const unsubscribers: (() => void)[] = [];\n const originalDispatches: Map<string, ReduxStore['dispatch']> = new Map();\n\n for (const [storeId, store] of Object.entries(stores)) {\n const library = detectLibrary(store);\n\n if (library === 'zustand') {\n const zustand = store as ZustandStore;\n\n // Emit initial state\n emitState(emit, sessionId, options?.beforeSend, {\n storeId,\n library,\n phase: 'init',\n state: safeSerialize(zustand.getState(), 4),\n });\n\n // Subscribe to changes\n const unsub = zustand.subscribe((state, prevState) => {\n const diff = shallowDiff(prevState, state);\n emitState(emit, sessionId, options?.beforeSend, {\n storeId,\n library,\n phase: 'update',\n state: safeSerialize(state, 4),\n previousState: safeSerialize(prevState, 4),\n diff: diff ? safeSerialize(diff, 3) as Record<string, { from: unknown; to: unknown }> : undefined,\n });\n });\n\n unsubscribers.push(unsub);\n } else if (library === 'redux') {\n const redux = store as ReduxStore;\n\n // Emit initial state\n emitState(emit, sessionId, options?.beforeSend, {\n storeId,\n library,\n phase: 'init',\n state: safeSerialize(redux.getState(), 4),\n });\n\n // Wrap dispatch to capture actions\n let lastAction: { type: string; payload?: unknown } | undefined;\n const origDispatch = redux.dispatch.bind(redux);\n originalDispatches.set(storeId, origDispatch);\n\n (redux as { dispatch: ReduxStore['dispatch'] }).dispatch = (action: unknown) => {\n if (action && typeof action === 'object' && 'type' in action) {\n lastAction = {\n type: String((action as { type: unknown }).type),\n payload: (action as { payload?: unknown }).payload,\n };\n }\n return origDispatch(action);\n };\n\n // Subscribe to state changes\n let prevState = redux.getState();\n const unsub = redux.subscribe(() => {\n const state = redux.getState();\n const diff = shallowDiff(prevState, state);\n\n emitState(emit, sessionId, options?.beforeSend, {\n storeId,\n library,\n phase: 'update',\n state: safeSerialize(state, 4),\n previousState: safeSerialize(prevState, 4),\n diff: diff ? safeSerialize(diff, 3) as Record<string, { from: unknown; to: unknown }> : undefined,\n action: lastAction ? safeSerialize(lastAction, 3) as { type: string; payload?: unknown } : undefined,\n });\n\n prevState = state;\n lastAction = undefined;\n });\n\n unsubscribers.push(unsub);\n }\n }\n\n return () => {\n for (const unsub of unsubscribers) unsub();\n\n // Restore original Redux dispatch functions\n for (const [storeId, origDispatch] of originalDispatches) {\n const store = stores[storeId] as ReduxStore;\n if (store) {\n (store as { dispatch: ReduxStore['dispatch'] }).dispatch = origDispatch;\n }\n }\n };\n}\n\nfunction detectLibrary(store: unknown): DetectedLibrary {\n if (!store || typeof store !== 'object') return 'unknown';\n const s = store as Record<string, unknown>;\n\n // Zustand: function-like with getState, setState, subscribe\n if (\n typeof s.getState === 'function' &&\n typeof s.setState === 'function' &&\n typeof s.subscribe === 'function'\n ) {\n return 'zustand';\n }\n\n // Redux: object with dispatch, getState, subscribe\n if (\n typeof s.dispatch === 'function' &&\n typeof s.getState === 'function' &&\n typeof s.subscribe === 'function'\n ) {\n return 'redux';\n }\n\n return 'unknown';\n}\n\nfunction shallowDiff(\n prev: unknown,\n curr: unknown\n): Record<string, { from: unknown; to: unknown }> | null {\n if (!prev || !curr || typeof prev !== 'object' || typeof curr !== 'object') {\n return null;\n }\n\n const diff: Record<string, { from: unknown; to: unknown }> = {};\n const prevObj = prev as Record<string, unknown>;\n const currObj = curr as Record<string, unknown>;\n const allKeys = new Set([...Object.keys(prevObj), ...Object.keys(currObj)]);\n\n for (const key of allKeys) {\n if (prevObj[key] !== currObj[key]) {\n diff[key] = { from: prevObj[key], to: currObj[key] };\n }\n }\n\n return Object.keys(diff).length > 0 ? diff : null;\n}\n\nfunction emitState(\n emit: EmitFn,\n sessionId: string,\n beforeSend: ((event: RuntimeEvent) => RuntimeEvent | null) | undefined,\n data: Omit<StateEvent, 'eventId' | 'sessionId' | 'timestamp' | 'eventType'>\n): void {\n const event: StateEvent = {\n eventId: generateId(),\n sessionId,\n timestamp: Date.now(),\n eventType: 'state',\n ...data,\n };\n\n if (beforeSend) {\n const filtered = beforeSend(event);\n if (filtered) emit(filtered as StateEvent);\n } else {\n emit(event);\n }\n}\n","import { generateId } from '../utils/id.js';\nimport type { PerformanceEvent, WebVitalRating, RuntimeEvent } from '../types.js';\n\ntype EmitFn = (event: PerformanceEvent) => void;\n\nexport interface PerformanceInterceptorOptions {\n beforeSend?: (event: RuntimeEvent) => RuntimeEvent | null;\n}\n\n// Web Vitals thresholds from web.dev\nconst THRESHOLDS: Record<string, [number, number]> = {\n LCP: [2500, 4000],\n FCP: [1800, 3000],\n CLS: [0.1, 0.25],\n TTFB: [800, 1800],\n FID: [100, 300],\n INP: [200, 500],\n};\n\nfunction rate(metric: string, value: number): WebVitalRating {\n const [good, poor] = THRESHOLDS[metric] ?? [Infinity, Infinity];\n if (value <= good) return 'good';\n if (value <= poor) return 'needs-improvement';\n return 'poor';\n}\n\n// Module-level singleton tracking — prevents duplicate observers on double-init (HMR)\nlet activeObservers: PerformanceObserver[] | null = null;\n\nexport function interceptPerformance(\n emit: EmitFn,\n sessionId: string,\n options?: PerformanceInterceptorOptions\n): () => void {\n // Disconnect any existing observers from a previous init (HMR / double-init safety)\n if (activeObservers) {\n for (const obs of activeObservers) {\n try { obs.disconnect(); } catch { /* already disconnected */ }\n }\n }\n\n const observers: PerformanceObserver[] = [];\n activeObservers = observers;\n\n const emitMetric = (\n metricName: PerformanceEvent['metricName'],\n value: number,\n element?: string\n ) => {\n const event: PerformanceEvent = {\n eventId: generateId(),\n sessionId,\n timestamp: Date.now(),\n eventType: 'performance',\n metricName,\n value: Math.round(value * 100) / 100,\n rating: rate(metricName, value),\n element,\n };\n\n if (options?.beforeSend) {\n const filtered = options.beforeSend(event);\n if (filtered) emit(filtered as PerformanceEvent);\n } else {\n emit(event);\n }\n };\n\n // LCP — Largest Contentful Paint\n tryObserve(observers, 'largest-contentful-paint', (entries) => {\n const last = entries[entries.length - 1];\n if (!last) return;\n const el = (last as PerformanceEntry & { element?: Element }).element;\n emitMetric('LCP', last.startTime, el?.tagName?.toLowerCase());\n });\n\n // FCP — First Contentful Paint\n tryObserve(observers, 'paint', (entries) => {\n for (const entry of entries) {\n if (entry.name === 'first-contentful-paint') {\n emitMetric('FCP', entry.startTime);\n }\n }\n });\n\n // CLS — Cumulative Layout Shift\n let clsValue = 0;\n tryObserve(observers, 'layout-shift', (entries) => {\n for (const entry of entries) {\n const ls = entry as PerformanceEntry & { hadRecentInput?: boolean; value?: number };\n if (!ls.hadRecentInput && ls.value) {\n clsValue += ls.value;\n emitMetric('CLS', clsValue);\n }\n }\n });\n\n // FID — First Input Delay\n tryObserve(observers, 'first-input', (entries) => {\n const first = entries[0];\n if (!first) return;\n const fi = first as PerformanceEntry & { processingStart?: number };\n if (fi.processingStart) {\n emitMetric('FID', fi.processingStart - first.startTime);\n }\n });\n\n // TTFB — Time to First Byte\n tryObserve(observers, 'navigation', (entries) => {\n const nav = entries[0] as PerformanceNavigationTiming | undefined;\n if (nav) {\n emitMetric('TTFB', nav.responseStart - nav.requestStart);\n }\n });\n\n // INP — Interaction to Next Paint\n let inpMax = 0;\n tryObserve(\n observers,\n 'event',\n (entries) => {\n for (const entry of entries) {\n if (entry.duration > inpMax) {\n inpMax = entry.duration;\n emitMetric('INP', inpMax);\n }\n }\n },\n { durationThreshold: 16 }\n );\n\n return () => {\n for (const obs of observers) {\n try {\n obs.disconnect();\n } catch {\n // Already disconnected\n }\n }\n if (activeObservers === observers) {\n activeObservers = null;\n }\n };\n}\n\nfunction tryObserve(\n observers: PerformanceObserver[],\n entryType: string,\n callback: (entries: PerformanceEntryList) => void,\n observeOptions?: Record<string, unknown>\n): void {\n try {\n const obs = new PerformanceObserver((list) => {\n callback(list.getEntries());\n });\n obs.observe({\n type: entryType,\n buffered: true,\n ...observeOptions,\n } as PerformanceObserverInit);\n observers.push(obs);\n } catch {\n // Observer type not supported in this browser\n }\n}\n","import { generateId } from '../utils/id.js';\nimport type { RenderEvent, RenderComponentProfile, RuntimeEvent } from '../types.js';\n\ntype EmitFn = (event: RenderEvent) => void;\n\nexport interface RenderInterceptorOptions {\n beforeSend?: (event: RuntimeEvent) => RuntimeEvent | null;\n snapshotIntervalMs?: number;\n}\n\ninterface Fiber {\n tag: number;\n type: { displayName?: string; name?: string } | string | null;\n child: Fiber | null;\n sibling: Fiber | null;\n alternate: Fiber | null;\n memoizedProps: unknown;\n memoizedState: unknown;\n actualDuration?: number;\n stateNode: unknown;\n}\n\ninterface ComponentTracker {\n renderCount: number;\n totalDuration: number;\n lastRenderTime: number;\n lastRenderPhase: 'mount' | 'update' | 'unmount';\n lastRenderCause: 'props' | 'state' | 'context' | 'parent' | 'unknown';\n renderTimestamps: number[];\n}\n\ninterface DevToolsHook {\n onCommitFiberRoot?: (id: number, root: { current?: Fiber }) => void;\n _runtimescope_original?: (id: number, root: { current?: Fiber }) => void;\n}\n\nconst FUNCTION_COMPONENT = 0;\nconst CLASS_COMPONENT = 1;\nconst SNAPSHOT_WINDOW_MS = 10_000;\nconst MAX_TIMESTAMPS = 100;\nconst TRACKER_TTL_MS = 60_000;\nconst MAX_TRACKED_COMPONENTS = 500;\n\nexport function interceptReactRenders(\n emit: EmitFn,\n sessionId: string,\n options?: RenderInterceptorOptions\n): () => void {\n const trackers = new Map<string, ComponentTracker>();\n const snapshotIntervalMs = options?.snapshotIntervalMs ?? 5000;\n let snapshotTimer: ReturnType<typeof setInterval> | null = null;\n\n // Access or create the React DevTools global hook\n const hook = getOrCreateDevToolsHook();\n if (!hook) {\n return () => {}; // Not in a browser environment\n }\n\n // Save original if React DevTools is installed\n const originalOnCommit = hook.onCommitFiberRoot;\n hook._runtimescope_original = originalOnCommit;\n\n hook.onCommitFiberRoot = (id: number, root: { current?: Fiber }) => {\n // Call original first (React DevTools compatibility)\n if (originalOnCommit) {\n try {\n originalOnCommit(id, root);\n } catch {\n // Don't let DevTools errors break our tracking\n }\n }\n\n if (root.current) {\n walkFiber(root.current, trackers);\n }\n };\n\n // Emit snapshots periodically\n snapshotTimer = setInterval(() => {\n emitSnapshot(trackers, emit, sessionId, options?.beforeSend);\n }, snapshotIntervalMs);\n\n return () => {\n if (snapshotTimer) {\n clearInterval(snapshotTimer);\n snapshotTimer = null;\n }\n\n // Restore original hook\n if (hook) {\n if (hook._runtimescope_original) {\n hook.onCommitFiberRoot = hook._runtimescope_original;\n } else {\n delete hook.onCommitFiberRoot;\n }\n delete hook._runtimescope_original;\n }\n };\n}\n\nfunction getOrCreateDevToolsHook(): DevToolsHook | null {\n if (typeof window === 'undefined') return null;\n\n const w = window as unknown as { __REACT_DEVTOOLS_GLOBAL_HOOK__?: DevToolsHook };\n\n if (!w.__REACT_DEVTOOLS_GLOBAL_HOOK__) {\n // Create a minimal shim that React will pick up on init\n w.__REACT_DEVTOOLS_GLOBAL_HOOK__ = {\n // React checks for these methods to decide if DevTools is present\n } as DevToolsHook;\n }\n\n return w.__REACT_DEVTOOLS_GLOBAL_HOOK__!;\n}\n\nfunction walkFiber(fiber: Fiber, trackers: Map<string, ComponentTracker>): void {\n processNode(fiber, trackers);\n\n if (fiber.child) walkFiber(fiber.child, trackers);\n if (fiber.sibling) walkFiber(fiber.sibling, trackers);\n}\n\nfunction processNode(fiber: Fiber, trackers: Map<string, ComponentTracker>): void {\n // Only track function components (0) and class components (1)\n if (fiber.tag !== FUNCTION_COMPONENT && fiber.tag !== CLASS_COMPONENT) return;\n\n const name = getComponentName(fiber);\n if (!name) return;\n\n const now = Date.now();\n const isMount = fiber.alternate === null;\n const duration = fiber.actualDuration ?? 0;\n const cause = inferRenderCause(fiber, isMount);\n\n let tracker = trackers.get(name);\n if (!tracker) {\n tracker = {\n renderCount: 0,\n totalDuration: 0,\n lastRenderTime: 0,\n lastRenderPhase: 'mount',\n lastRenderCause: 'unknown',\n renderTimestamps: [],\n };\n trackers.set(name, tracker);\n }\n\n tracker.renderCount++;\n tracker.totalDuration += duration;\n tracker.lastRenderTime = now;\n tracker.lastRenderPhase = isMount ? 'mount' : 'update';\n tracker.lastRenderCause = cause ?? 'unknown';\n tracker.renderTimestamps.push(now);\n\n // Trim old timestamps\n if (tracker.renderTimestamps.length > MAX_TIMESTAMPS) {\n tracker.renderTimestamps = tracker.renderTimestamps.slice(-MAX_TIMESTAMPS);\n }\n}\n\nfunction getComponentName(fiber: Fiber): string | undefined {\n if (!fiber.type) return undefined;\n if (typeof fiber.type === 'string') return undefined; // HTML elements\n return fiber.type.displayName || fiber.type.name || undefined;\n}\n\nfunction inferRenderCause(\n fiber: Fiber,\n isMount: boolean\n): RenderComponentProfile['lastRenderCause'] {\n if (isMount) return 'props'; // Initial mount, driven by parent passing props\n\n if (!fiber.alternate) return 'unknown';\n\n // Check if props changed\n if (fiber.memoizedProps !== fiber.alternate.memoizedProps) {\n return 'props';\n }\n\n // Check if state changed\n if (fiber.memoizedState !== fiber.alternate.memoizedState) {\n return 'state';\n }\n\n // If neither props nor state changed, likely parent re-rendered\n return 'parent';\n}\n\nfunction computeRenderVelocity(timestamps: number[]): number {\n if (timestamps.length < 2) return 0;\n const now = Date.now();\n const windowStart = now - SNAPSHOT_WINDOW_MS;\n const recent = timestamps.filter((t) => t >= windowStart);\n if (recent.length < 2) return 0;\n const windowMs = now - recent[0];\n if (windowMs === 0) return 0;\n return recent.length / (windowMs / 1000);\n}\n\nfunction emitSnapshot(\n trackers: Map<string, ComponentTracker>,\n emit: EmitFn,\n sessionId: string,\n beforeSend?: (event: RuntimeEvent) => RuntimeEvent | null\n): void {\n if (trackers.size === 0) return;\n\n const profiles: RenderComponentProfile[] = [];\n const suspiciousComponents: string[] = [];\n let totalRenders = 0;\n\n for (const [componentName, tracker] of trackers) {\n const velocity = computeRenderVelocity(tracker.renderTimestamps);\n const suspicious = velocity > 4 || tracker.renderCount > 20;\n\n profiles.push({\n componentName,\n renderCount: tracker.renderCount,\n totalDuration: Math.round(tracker.totalDuration * 100) / 100,\n avgDuration:\n tracker.renderCount > 0\n ? Math.round((tracker.totalDuration / tracker.renderCount) * 100) / 100\n : 0,\n lastRenderPhase: tracker.lastRenderPhase,\n lastRenderCause: tracker.lastRenderCause,\n renderVelocity: Math.round(velocity * 100) / 100,\n suspicious,\n });\n\n if (suspicious) suspiciousComponents.push(componentName);\n totalRenders += tracker.renderCount;\n }\n\n // Sort by render count descending\n profiles.sort((a, b) => b.renderCount - a.renderCount);\n\n const event: RenderEvent = {\n eventId: generateId(),\n sessionId,\n timestamp: Date.now(),\n eventType: 'render',\n profiles,\n snapshotWindowMs: SNAPSHOT_WINDOW_MS,\n totalRenders,\n suspiciousComponents,\n };\n\n if (beforeSend) {\n const filtered = beforeSend(event);\n if (filtered) emit(filtered as RenderEvent);\n } else {\n emit(event);\n }\n\n // Reset counters and prune stale trackers\n const now = Date.now();\n for (const [name, tracker] of trackers) {\n if (now - tracker.lastRenderTime > TRACKER_TTL_MS) {\n // Component hasn't rendered in 60s — remove to prevent unbounded growth\n trackers.delete(name);\n } else {\n tracker.renderCount = 0;\n tracker.totalDuration = 0;\n }\n }\n\n // Hard cap: if still over limit after TTL pruning, evict least-recently-rendered\n if (trackers.size > MAX_TRACKED_COMPONENTS) {\n const sorted = [...trackers.entries()]\n .sort((a, b) => a[1].lastRenderTime - b[1].lastRenderTime);\n const excess = trackers.size - MAX_TRACKED_COMPONENTS;\n for (let i = 0; i < excess; i++) {\n trackers.delete(sorted[i][0]);\n }\n }\n}\n","import { generateId } from '../utils/id.js';\nimport { safeSerialize } from '../utils/serialize.js';\nimport type { ConsoleEvent, RuntimeEvent } from '../types.js';\n\ntype EmitFn = (event: ConsoleEvent) => void;\n\n/**\n * Captures uncaught errors and unhandled promise rejections that appear\n * in DevTools but don't go through the console.* API.\n *\n * - window 'error' (capture phase) — JS runtime errors + resource load failures\n * - window 'unhandledrejection' — unhandled async/await and Promise rejections\n *\n * Events are emitted as ConsoleEvents with level 'error' so they appear\n * alongside console.error() output in get_console_messages.\n */\nexport function interceptErrors(\n emit: EmitFn,\n sessionId: string,\n beforeSend?: (event: RuntimeEvent) => RuntimeEvent | null\n): () => void {\n // Capture uncaught JS errors and resource load failures\n const onError = (e: ErrorEvent | Event) => {\n let message: string;\n let stackTrace: string | undefined;\n let sourceFile: string | undefined;\n\n if (e instanceof ErrorEvent) {\n // Uncaught JS error\n message = e.message || 'Uncaught error';\n stackTrace = e.error?.stack;\n sourceFile = e.filename\n ? `${e.filename}:${e.lineno}:${e.colno}`\n : undefined;\n } else {\n // Resource load error (img, script, link, etc.)\n const target = e.target as HTMLElement | null;\n if (target && target !== window as unknown) {\n const tagName = target.tagName?.toLowerCase() ?? 'unknown';\n const src =\n (target as HTMLImageElement).src ??\n (target as HTMLScriptElement).src ??\n (target as HTMLLinkElement).href ??\n 'unknown';\n message = `Failed to load resource: <${tagName}> ${src}`;\n } else {\n return; // Not a resource error we can identify\n }\n }\n\n const event: ConsoleEvent = {\n eventId: generateId(),\n sessionId,\n timestamp: Date.now(),\n eventType: 'console',\n level: 'error',\n message: `[Uncaught] ${message}`,\n args: [safeSerialize(message, 3)],\n stackTrace,\n sourceFile,\n };\n\n if (beforeSend) {\n const filtered = beforeSend(event);\n if (filtered) emit(filtered as ConsoleEvent);\n } else {\n emit(event);\n }\n };\n\n // Capture unhandled promise rejections\n const onUnhandledRejection = (e: PromiseRejectionEvent) => {\n const reason = e.reason;\n let message: string;\n let stackTrace: string | undefined;\n\n if (reason instanceof Error) {\n message = reason.message;\n stackTrace = reason.stack;\n } else if (typeof reason === 'string') {\n message = reason;\n } else {\n try {\n message = JSON.stringify(reason);\n } catch {\n message = String(reason);\n }\n }\n\n const event: ConsoleEvent = {\n eventId: generateId(),\n sessionId,\n timestamp: Date.now(),\n eventType: 'console',\n level: 'error',\n message: `[Unhandled Rejection] ${message}`,\n args: [safeSerialize(reason, 3)],\n stackTrace,\n sourceFile: undefined,\n };\n\n if (beforeSend) {\n const filtered = beforeSend(event);\n if (filtered) emit(filtered as ConsoleEvent);\n } else {\n emit(event);\n }\n };\n\n // Use capture phase for 'error' to catch resource load failures on child elements\n window.addEventListener('error', onError, true);\n window.addEventListener('unhandledrejection', onUnhandledRejection);\n\n return () => {\n window.removeEventListener('error', onError, true);\n window.removeEventListener('unhandledrejection', onUnhandledRejection);\n };\n}\n","import type { RuntimeEvent, NavigationEvent } from '../types.js';\nimport { generateId } from '../utils/id.js';\n\n/**\n * Intercepts SPA navigation events:\n * - history.pushState / replaceState (client-side routing)\n * - popstate (browser back/forward)\n * - hashchange (hash-based routing)\n *\n * Emits a NavigationEvent with from/to URLs and the trigger type.\n */\nexport function interceptNavigation(\n emit: (event: RuntimeEvent) => void,\n sessionId: string\n): () => void {\n let currentUrl = window.location.href;\n\n function emitNav(to: string, trigger: NavigationEvent['trigger']): void {\n const from = currentUrl;\n if (from === to) return; // Skip no-op navigations\n currentUrl = to;\n\n emit({\n eventId: generateId(),\n sessionId,\n timestamp: Date.now(),\n eventType: 'navigation',\n from,\n to,\n trigger,\n });\n }\n\n // Patch pushState and replaceState\n const origPushState = history.pushState.bind(history);\n const origReplaceState = history.replaceState.bind(history);\n\n history.pushState = function (...args: Parameters<typeof origPushState>) {\n origPushState(...args);\n emitNav(window.location.href, 'pushState');\n };\n\n history.replaceState = function (...args: Parameters<typeof origReplaceState>) {\n origReplaceState(...args);\n emitNav(window.location.href, 'replaceState');\n };\n\n // Listen for back/forward navigation\n const onPopState = () => emitNav(window.location.href, 'popstate');\n window.addEventListener('popstate', onPopState);\n\n // Listen for hash changes (covers hash-based routers)\n const onHashChange = () => emitNav(window.location.href, 'hashchange');\n window.addEventListener('hashchange', onHashChange);\n\n // Restore function\n return () => {\n history.pushState = origPushState;\n history.replaceState = origReplaceState;\n window.removeEventListener('popstate', onPopState);\n window.removeEventListener('hashchange', onHashChange);\n };\n}\n","import type { RuntimeEvent, UIInteractionEvent } from '../types.js';\nimport { generateId } from '../utils/id.js';\n\n/**\n * Intercepts user clicks via event delegation on `document`.\n * Emits a lightweight UIInteractionEvent with the target element's\n * CSS selector and visible text.\n *\n * Uses a single capture-phase listener — no DOM mutation, no patching.\n */\nexport function interceptClicks(\n emit: (event: RuntimeEvent) => void,\n sessionId: string\n): () => void {\n const onClick = (e: MouseEvent) => {\n const target = e.target;\n if (!(target instanceof Element)) return;\n\n // Skip RuntimeScope's own UI (if any)\n if (target.closest('[data-runtimescope]')) return;\n\n const selector = buildSelector(target);\n const text = getVisibleText(target);\n\n const event: UIInteractionEvent = {\n eventId: generateId(),\n sessionId,\n timestamp: Date.now(),\n eventType: 'ui',\n action: 'click',\n target: selector,\n ...(text && { text }),\n };\n\n emit(event);\n };\n\n // Capture phase so we see clicks even if stopPropagation is called\n document.addEventListener('click', onClick, true);\n\n return () => {\n document.removeEventListener('click', onClick, true);\n };\n}\n\n/**\n * Build a short, human-readable CSS selector for the clicked element.\n * Prioritizes: tag + id > tag + data-testid > tag + class (first meaningful one).\n * Keeps it concise — not a full path.\n */\nfunction buildSelector(el: Element): string {\n const tag = el.tagName.toLowerCase();\n\n if (el.id) return `${tag}#${el.id}`;\n\n const testId = el.getAttribute('data-testid') ?? el.getAttribute('data-test-id');\n if (testId) return `${tag}[data-testid=\"${testId}\"]`;\n\n const role = el.getAttribute('role');\n const ariaLabel = el.getAttribute('aria-label');\n if (role && ariaLabel) return `${tag}[role=\"${role}\"][aria-label=\"${ariaLabel}\"]`;\n\n const className = el.className;\n if (typeof className === 'string' && className.trim()) {\n // Take the first non-utility class (skip single-letter or hash-based classes)\n const meaningful = className.split(/\\s+/).find(\n (c) => c.length > 2 && !c.startsWith('_') && !c.includes('__')\n );\n if (meaningful) return `${tag}.${meaningful}`;\n }\n\n // Fallback: tag with nth-child if parent has multiple same-tag children\n const parent = el.parentElement;\n if (parent) {\n const siblings = parent.children;\n const sameTag = Array.from(siblings).filter((s) => s.tagName === el.tagName);\n if (sameTag.length > 1) {\n const idx = sameTag.indexOf(el) + 1;\n return `${tag}:nth-child(${idx})`;\n }\n }\n\n return tag;\n}\n\n/**\n * Get visible text from an element, truncated to 80 chars.\n * Prefers aria-label, then textContent.\n */\nfunction getVisibleText(el: Element): string | undefined {\n const ariaLabel = el.getAttribute('aria-label');\n if (ariaLabel) return ariaLabel.slice(0, 80);\n\n const text = (el as HTMLElement).innerText ?? el.textContent;\n if (!text) return undefined;\n\n const trimmed = text.trim().replace(/\\s+/g, ' ');\n if (trimmed.length === 0) return undefined;\n return trimmed.length > 80 ? trimmed.slice(0, 77) + '...' : trimmed;\n}\n","/**\n * DSN (Data Source Name) parser for RuntimeScope browser SDK.\n *\n * Format: runtimescope://proj_abc123[:token]@localhost:6768/my-app\n * - runtimescope:// or runtimescopes:// (TLS)\n * - projectId before @ (or before : if a token is included)\n * - optional bearer token between : and @ (workspace-scoped API key)\n * - host:port after @ (HTTP API port, default 6768)\n * - WS port = HTTP port - 1 (so 6768 → ws on 6767)\n * - Optional /appName path\n */\n\nexport interface ParsedDsn {\n projectId: string;\n authToken?: string;\n wsEndpoint: string;\n httpEndpoint: string;\n appName?: string;\n tls: boolean;\n}\n\nexport function parseDsn(dsn: string): ParsedDsn {\n const tls = dsn.startsWith('runtimescopes://');\n if (!dsn.startsWith('runtimescope://') && !tls) {\n throw new Error(`Invalid RuntimeScope DSN: must start with runtimescope:// or runtimescopes://`);\n }\n // Replace protocol for URL parsing\n const url = new URL(dsn.replace(/^runtimescopes?:\\/\\//, 'http://'));\n const projectId = url.username;\n if (!projectId || !projectId.startsWith('proj_')) {\n throw new Error(`Invalid RuntimeScope DSN: missing projectId (expected proj_xxx@host)`);\n }\n const authToken = url.password ? decodeURIComponent(url.password) : undefined;\n const host = url.hostname;\n const httpPort = url.port ? parseInt(url.port) : 6768;\n const wsPort = httpPort - 1;\n const appName = url.pathname.replace(/^\\//, '') || undefined;\n const wsProto = tls ? 'wss' : 'ws';\n const httpProto = tls ? 'https' : 'http';\n return {\n projectId,\n authToken,\n wsEndpoint: `${wsProto}://${host}:${wsPort}`,\n httpEndpoint: `${httpProto}://${host}:${httpPort}`,\n appName,\n tls,\n };\n}\n\nexport function buildDsn(opts: {\n projectId: string;\n authToken?: string;\n host?: string;\n port?: number;\n appName?: string;\n tls?: boolean;\n}): string {\n const proto = opts.tls ? 'runtimescopes' : 'runtimescope';\n const host = opts.host ?? 'localhost';\n const port = opts.port ?? 6768;\n const path = opts.appName ? `/${opts.appName}` : '';\n const auth = opts.authToken ? `:${encodeURIComponent(opts.authToken)}` : '';\n return `${proto}://${opts.projectId}${auth}@${host}:${port}${path}`;\n}\n"],"mappings":"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","names":["index_exports","__export","RuntimeScope","buildDsn","index_default","parseDsn","__toCommonJS","_origDebug","_origWarn","_debugEnabled","_readDebugFlag","_log","args","setTransportDebug","enabled","_Transport","config","__publicField","event","msg","queued","events","delay","jitter","handler","requestId","command","payload","Transport","generateId","arr","b","generateSessionId","MAX_INFLIGHT","INFLIGHT_TTL_MS","SWEEP_INTERVAL_MS","fetchInterceptedRequests","sweepTimer","sweepRefCount","startSweeper","cutoff","key","ts","stopSweeper","interceptFetch","emit","sessionId","redactHeaders","options","originalFetch","redactSet","h","captureBody","maxBodySize","input","init","startTime","url","method","requestHeaders","extractHeaders","requestBodySize","estimateBodySize","graphqlOperation","detectGraphQL","requestBody","serializeBody","requestKey","oldest","response","duration","responseBodySize","responseHeaders","extractResponseHeaders","responseBody","text","event","generateId","filtered","error","errorPhase","errorMessage","headers","result","value","body","maxSize","s","parsed","trimmed","type","name","extractOperationName","query","safeSerialize","value","maxDepth","seen","walk","val","depth","v","result","keys","maxKeys","i","LEVELS","makeDedupeGate","options","printSummary","seen","summaryTimer","totalSuppressed","state","cutoff","key","level","message","now","extractSourceFile","stack","lines","line","match","interceptConsole","emit","sessionId","beforeSend","dedupe","originals","timers","counters","dedupeOptions","summarySink","dedupeGate","text","args","a","stringifyArg","event","generateId","safeSerialize","filtered","origAssert","condition","origTime","origTimeEnd","label","start","duration","origCount","origCountReset","count","origTable","data","columns","arg","interceptXhr","emit","sessionId","redactHeaders","options","redactSet","h","captureBody","maxBodySize","globalAbort","origOpen","origSetRequestHeader","origSend","method","url","name","value","body","requestKey","alreadyIntercepted","k","fetchInterceptedRequests","requestHeaders","startTime","requestBody","requestBodySize","s","graphqlOperation","detectGraphQL","emitEvent","overrides","event","generateId","filtered","duration","responseHeaders","parseResponseHeaders","responseBodySize","responseBody","text","errorPhase","errorMessage","raw","result","line","idx","key","parsed","trimmed","type","extractOperationName","query","interceptStateStores","emit","sessionId","stores","options","unsubscribers","originalDispatches","storeId","store","library","detectLibrary","zustand","emitState","safeSerialize","unsub","state","prevState","diff","shallowDiff","redux","lastAction","origDispatch","action","s","prev","curr","prevObj","currObj","allKeys","key","beforeSend","data","event","generateId","filtered","THRESHOLDS","rate","metric","value","good","poor","activeObservers","interceptPerformance","emit","sessionId","options","obs","observers","emitMetric","metricName","element","event","generateId","filtered","tryObserve","entries","last","el","entry","clsValue","ls","first","fi","nav","inpMax","entryType","callback","observeOptions","list","FUNCTION_COMPONENT","CLASS_COMPONENT","SNAPSHOT_WINDOW_MS","MAX_TIMESTAMPS","TRACKER_TTL_MS","MAX_TRACKED_COMPONENTS","interceptReactRenders","emit","sessionId","options","trackers","snapshotIntervalMs","snapshotTimer","hook","getOrCreateDevToolsHook","originalOnCommit","id","root","walkFiber","emitSnapshot","w","fiber","processNode","name","getComponentName","now","isMount","duration","cause","inferRenderCause","tracker","computeRenderVelocity","timestamps","windowStart","recent","t","windowMs","beforeSend","profiles","suspiciousComponents","totalRenders","componentName","velocity","suspicious","a","b","event","generateId","filtered","sorted","excess","i","interceptErrors","emit","sessionId","beforeSend","onError","e","message","stackTrace","sourceFile","target","tagName","src","event","generateId","safeSerialize","filtered","onUnhandledRejection","reason","interceptNavigation","emit","sessionId","currentUrl","emitNav","to","trigger","from","generateId","origPushState","origReplaceState","args","onPopState","onHashChange","interceptClicks","emit","sessionId","onClick","e","target","selector","buildSelector","text","getVisibleText","event","generateId","el","tag","testId","role","ariaLabel","className","meaningful","parent","siblings","sameTag","s","idx","trimmed","parseDsn","dsn","tls","url","projectId","authToken","host","httpPort","wsPort","appName","wsProto","httpProto","buildDsn","opts","proto","port","path","auth","SDK_VERSION","_origDebug","_origWarn","_debugEnabled","_log","args","_warnedOnce","_warn","message","rest","ORIGINALS_KEY","getOrSaveOriginals","g","RuntimeScope","now","config","hasDsn","parsed","parseDsn","e","host","setTransportDebug","sigCandidate","resolved","generateSessionId","Transport","originalWarn","warnTransportRef","warnServerUrl","fix","emit","event","generateId","sessionId","cmd","interceptFetch","interceptXhr","interceptConsole","interceptErrors","interceptStateStores","interceptPerformance","interceptReactRenders","interceptNavigation","interceptClicks","features","maxSize","html","truncated","snapshot","name","properties","user","data","fn","originals","level","c","__publicField","index_default"]}