@observtech/rum 0.1.32 → 0.1.34

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/baggage.ts","../src/resource.ts","../src/constants.ts","../src/session.ts","../src/otel-logs.ts","../src/js-errors.ts","../src/otel-metrics.ts","../node_modules/@opentelemetry/instrumentation/src/autoLoaderUtils.ts","../node_modules/@opentelemetry/instrumentation/src/autoLoader.ts","../src/otel-rum.ts","../src/privacy.ts","../src/transport.ts","../src/rrweb-record.ts","../src/selector.ts","../src/semantic-events.ts","../src/index.ts"],"names":["init","provider","record","disableInstrumentations","current","active","NOOP","metrics"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Backend correlation via the W3C **baggage** header (parity story).\n *\n * The fetch/XHR auto-instrumentations already inject `traceparent` on requests to\n * allowed backends; this adds `session.id` to the **baggage** header on those same\n * requests, so the server spans (Strapi / API / KV) can read the session identity\n * and stamp it server-side — making `session.id ⇄ backend span` traversable\n * beyond the `trace_id` link.\n *\n * We wrap `window.fetch` (installed AFTER OTel's fetch instrumentation, so our\n * wrapper is the outermost) and append `session.id` to any existing `baggage`\n * header, but ONLY for URLs matching `backendUrls` — never leaking the id to\n * third parties. Best-effort and reversible (returns an uninstall fn).\n *\n * Gated by the `propagateBaggage` init option; the allowlist defaults to\n * `propagateTraceHeaderCorsUrls` (the same backends that receive `traceparent`).\n */\ntype Matcher = string | RegExp\n\nfunction matches(url: string, matchers: Matcher[]): boolean {\n return matchers.some((m) => (typeof m === 'string' ? url.startsWith(m) : m.test(url)))\n}\n\nfunction resolveUrl(input: RequestInfo | URL): string {\n if (typeof input === 'string') return input\n if (input instanceof URL) return input.href\n return input.url\n}\n\n/** Merge `session.id=<id>` into an existing W3C `baggage` header value. */\nexport function withSessionBaggage(existing: string | null, sessionId: string): string {\n const entry = `session.id=${encodeURIComponent(sessionId)}`\n if (!existing) return entry\n // Don't duplicate if a session.id is already present (e.g. nested wrappers).\n const hasSession = existing.split(',').some((p) => p.trim().startsWith('session.id='))\n return hasSession ? existing : `${existing},${entry}`\n}\n\n/**\n * Install the baggage propagation fetch wrapper. No-op (returns a no-op\n * uninstaller) when there is no `window.fetch`. `getId` is the session-id source\n * ({@link import('./session.js').getSessionId}); `ignoreUrls` excludes the\n * telemetry pipeline itself.\n */\nexport function installBaggagePropagation(\n getId: () => string,\n backendUrls: Matcher[],\n ignoreUrls: Matcher[] = [],\n): () => void {\n if (\n typeof window === 'undefined' ||\n typeof window.fetch !== 'function' ||\n backendUrls.length === 0\n ) {\n return () => {}\n }\n\n const originalFetch = window.fetch.bind(window)\n\n window.fetch = function patchedFetch(input: RequestInfo | URL, init?: RequestInit) {\n let sessionId = ''\n let url = ''\n try {\n sessionId = getId()\n url = resolveUrl(input)\n } catch {\n return originalFetch(input, init)\n }\n\n // Skip non-backend URLs and the telemetry pipeline itself.\n if (!sessionId || !matches(url, backendUrls) || matches(url, ignoreUrls)) {\n return originalFetch(input, init)\n }\n\n try {\n const headers = new Headers(\n init?.headers ?? (input instanceof Request ? input.headers : undefined),\n )\n headers.set('baggage', withSessionBaggage(headers.get('baggage'), sessionId))\n return originalFetch(input, { ...init, headers })\n } catch {\n // Header juggling failed → fall back to an unmodified request.\n return originalFetch(input, init)\n }\n }\n\n return () => {\n window.fetch = originalFetch\n }\n}\n","/**\n * Shared OTel `Resource` for every RUM signal (traces, logs, metrics).\n *\n * Parity story (epic \"RUM parity\"): the original SDK created its providers with\n * NO resource, so every signal landed under `unknown_service`. This builds a\n * single resource from the public init options + ambient browser facts, applied\n * identically to the trace / log / meter providers so all three carry the same\n * `service.name` and `session`-independent context.\n *\n * `telemetry.sdk.language: 'webjs'` marks the signal as browser-originated (the\n * backend uses it to tell RUM apart from server SDKs).\n */\nimport { resourceFromAttributes, type Resource } from '@opentelemetry/resources'\nimport { ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION } from '@opentelemetry/semantic-conventions'\n\nimport type { ObservInitOptions } from './types.js'\n\n/**\n * Build the resource attached to every provider. `service.name` is set only when\n * the host supplies one (otherwise the OTel default `unknown_service` stands, but\n * at least `telemetry.sdk.language` flags it as browser RUM). Browser facts are\n * read defensively so the SDK stays no-throw under SSR / no-`navigator`.\n */\nexport function buildResource(options: ObservInitOptions): Resource {\n const attrs: Record<string, string | boolean> = {\n 'telemetry.sdk.language': 'webjs',\n }\n if (options.serviceName) attrs[ATTR_SERVICE_NAME] = options.serviceName\n if (options.serviceVersion) attrs[ATTR_SERVICE_VERSION] = options.serviceVersion\n if (options.environment) attrs['deployment.environment.name'] = options.environment\n\n try {\n if (typeof navigator !== 'undefined') {\n if (navigator.language) attrs['browser.language'] = navigator.language\n attrs['browser.mobile'] = /Mobi|Android/i.test(navigator.userAgent || '')\n }\n } catch {\n /* swallow — resource enrichment must never break init */\n }\n\n return resourceFromAttributes(attrs)\n}\n","/**\n * Cross-cutting constants for the Observ RUM SDK.\n *\n * Kept in a leaf module (no SDK imports beyond semconv constants) so both the\n * public entry point (`index.ts`) and internal modules (`otel-rum.ts`) can share\n * them without a circular import.\n */\nimport { ATTR_SESSION_ID } from '@opentelemetry/semantic-conventions/incubating'\n\n/**\n * Attribute key used everywhere to correlate signals of a single session.\n * Sourced from the pinned `@opentelemetry/semantic-conventions` (incubating\n * `ATTR_SESSION_ID`) rather than a hand-typed literal, so the key tracks the\n * standard. Enforcement rule (architecture): the OTel session attribute is\n * EXACTLY `session.id` — never `sessionId` nor `session_id`. Single source of\n * truth so every signal (spans, semantic events, rrweb) stamps the identical key.\n * A test asserts `=== 'session.id'` to guard that invariant across semconv bumps.\n */\nexport const SESSION_ID_ATTRIBUTE: 'session.id' = ATTR_SESSION_ID\n","/**\n * Session lifecycle for the Observ RUM SDK (FR-1).\n *\n * Produces a single, stable `session.id` per visit and exposes it INTERNALLY as\n * the one source of truth that later modules (`rrweb-record`, `semantic-events`,\n * `otel-rum`) stamp onto every signal. Not part of the public `observ` surface.\n *\n * Authoritative rules (architecture D5):\n * - `session.id` is a UUID v4, generated in the browser,\n * - persisted in `sessionStorage` (per-tab — two tabs are two visits, by design),\n * - rotated after 30 min of inactivity.\n *\n * Rotation is LAZY: there is no background timer — the window is evaluated on the\n * next `ensureSession`/`getSessionId`/`touchSession` call, and a fresh id is\n * minted then if the window has elapsed.\n *\n * This module performs NO network I/O. It must never throw: if `sessionStorage`\n * or `crypto` are unavailable (private mode, disabled storage, SSR / insecure\n * context), it degrades to an in-memory session.id. NOTE: in that degraded mode\n * persistence is lost across full page loads, so each navigation starts a new\n * session (the per-visit guarantee holds only while `sessionStorage` works).\n */\n\n/** Single `sessionStorage` key holding the serialized session state. */\nexport const SESSION_STORAGE_KEY = 'observ.rum.session'\n\n/**\n * Inactivity window after which a new `session.id` is minted (architecture D5,\n * resolves PRD Open Q2). 30 minutes, in milliseconds.\n */\nexport const SESSION_INACTIVITY_TIMEOUT_MS = 30 * 60 * 1000\n\n/** Shape persisted under {@link SESSION_STORAGE_KEY}. Timestamps are epoch ms. */\ninterface PersistedSession {\n id: string\n startedAt: number\n lastActivityAt: number\n}\n\n/**\n * In-memory memoization. Within a single page it is the source of truth (one\n * `init` per SPA load); it is also the sole fallback when storage is unusable.\n */\nlet current: PersistedSession | null = null\n\n/** Build a UUID v4, preferring crypto; falls back gracefully (documented). */\nfunction generateSessionId(): string {\n const c: Crypto | undefined = globalThis.crypto\n // `crypto.randomUUID` requires a secure context (https or localhost). Detection\n // tests presence, not callability — guard the call so a throwing implementation\n // falls through instead of escaping (the module must never throw).\n if (c && typeof c.randomUUID === 'function') {\n try {\n return c.randomUUID()\n } catch {\n // fall through to getRandomValues\n }\n }\n if (c && typeof c.getRandomValues === 'function') {\n const bytes = c.getRandomValues(new Uint8Array(16))\n bytes[6] = ((bytes[6] ?? 0) & 0x0f) | 0x40 // version 4\n bytes[8] = ((bytes[8] ?? 0) & 0x3f) | 0x80 // variant 10\n const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join('')\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`\n }\n // Last-resort, non-crypto fallback (SSR / no Web Crypto). Not cryptographically\n // strong — acceptable only because no real entropy source exists here.\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (ch) => {\n const r = (Math.random() * 16) | 0\n const v = ch === 'x' ? r : (r & 0x3) | 0x8\n return v.toString(16)\n })\n}\n\n/** Read from `sessionStorage`, swallowing any access error. */\nfunction safeRead(): string | null {\n try {\n return globalThis.sessionStorage?.getItem(SESSION_STORAGE_KEY) ?? null\n } catch {\n return null\n }\n}\n\n/** Write to `sessionStorage`, swallowing any access/quota error. */\nfunction safeWrite(value: string): void {\n try {\n globalThis.sessionStorage?.setItem(SESSION_STORAGE_KEY, value)\n } catch {\n // In-memory `current` stays authoritative; nothing else to do.\n }\n}\n\n/** Validate the parsed storage payload before trusting it. */\nfunction isPersistedSession(value: unknown): value is PersistedSession {\n if (typeof value !== 'object' || value === null) return false\n const v = value as Record<string, unknown>\n return (\n typeof v.id === 'string' &&\n v.id.length > 0 &&\n typeof v.startedAt === 'number' &&\n Number.isFinite(v.startedAt) &&\n typeof v.lastActivityAt === 'number' &&\n Number.isFinite(v.lastActivityAt)\n )\n}\n\n/** Resolve the current session, from memory first, then storage. */\nfunction load(): PersistedSession | null {\n if (current) return current\n const raw = safeRead()\n if (raw === null) return null\n try {\n const parsed: unknown = JSON.parse(raw)\n return isPersistedSession(parsed) ? parsed : null\n } catch {\n return null // corrupt JSON → treat as absent\n }\n}\n\n/** Memoize in memory and best-effort persist to storage. */\nfunction save(session: PersistedSession): void {\n current = session\n safeWrite(JSON.stringify(session))\n}\n\n/**\n * Ensure a `session.id` exists for this visit and return it.\n *\n * Reuses the stored id when within the inactivity window (refreshing\n * `lastActivityAt`); otherwise mints a fresh session. `now` is injectable for\n * deterministic tests.\n */\nexport function ensureSession(now: number = Date.now()): string {\n const existing = load()\n if (existing) {\n // Clamp to 0 so a backward clock jump (now < lastActivityAt, e.g. NTP/DST)\n // can't yield a negative \"elapsed\" that silently extends the session; the\n // stale future timestamp is then corrected to `now` below.\n const elapsed = Math.max(0, now - existing.lastActivityAt)\n if (elapsed <= SESSION_INACTIVITY_TIMEOUT_MS) {\n save({ ...existing, lastActivityAt: now })\n return existing.id\n }\n }\n const fresh: PersistedSession = { id: generateSessionId(), startedAt: now, lastActivityAt: now }\n save(fresh)\n return fresh.id\n}\n\n/**\n * Return the `session.id` for the current visit.\n *\n * Delegates to {@link ensureSession} so every read enforces the inactivity\n * timeout (rotating to a fresh id once the window has elapsed) — a memoized\n * read must not be able to hand back a session that should have rotated. As a\n * consequence a read also refreshes `lastActivityAt`, i.e. reading the id counts\n * as activity.\n */\nexport function getSessionId(now: number = Date.now()): string {\n return ensureSession(now)\n}\n\n/**\n * Push the inactivity window forward on real activity (rotating if the session\n * has already expired). Wiring to actual interactions arrives in stories 2.x;\n * this is the hook + the write.\n */\nexport function touchSession(now: number = Date.now()): void {\n ensureSession(now)\n}\n\n/**\n * @internal Test-only. Clears the in-memory memoization to simulate a fresh\n * page load / module re-import (storage is left untouched).\n */\nexport function resetSessionState(): void {\n current = null\n}\n","/**\n * OpenTelemetry Logs pipeline for the Observ RUM SDK (story 2.3).\n *\n * Semantic events (`observ.session.*`) are emitted as OTel **log records** and\n * exported over OTLP/HTTP to `{endpoint}/v1/logs` (received by the backend since\n * story 1.4; the session-assembly writer taps them in 1.6). This is the mirror\n * of the trace pipeline in `otel-rum.ts`, on a dedicated, separate provider —\n * the light \"logs\" channel, never the heavy `/v1/replay` channel.\n *\n * `session.id` is stamped once, at emit time, by {@link emitSessionEvent} — the\n * single point through which every semantic event flows (so a separate\n * `LogRecordProcessor` would be redundant; this also keeps the SDK's\n * sdk-logs API surface minimal).\n */\nimport type { Logger } from '@opentelemetry/api-logs'\nimport { OTLPLogExporter } from '@opentelemetry/exporter-logs-otlp-http'\nimport { BatchLogRecordProcessor, LoggerProvider } from '@opentelemetry/sdk-logs'\n\nimport { buildResource } from './resource.js'\nimport { SESSION_ID_ATTRIBUTE } from './constants.js'\nimport { getSessionId } from './session.js'\nimport type { ObservInitOptions } from './types.js'\n\n/**\n * Join an endpoint base URL with the OTLP/HTTP logs path. Mirror of\n * {@link import('./otel-rum.js').buildTracesUrl}: preserves a path prefix, never\n * doubles a trailing slash, drops query/fragment; relative/empty → same-origin.\n */\nexport function buildLogsUrl(endpoint: string): string {\n try {\n const url = new URL(endpoint)\n url.pathname = `${url.pathname.replace(/\\/+$/, '')}/v1/logs`\n url.search = ''\n url.hash = ''\n return url.toString()\n } catch {\n return `${endpoint.replace(/\\/+$/, '')}/v1/logs`\n }\n}\n\nlet provider: LoggerProvider | null = null\nlet activeLogger: Logger | null = null\n\n/**\n * Wire up the OTel Logs provider and return a `Logger`. Idempotent: a second\n * call returns the already-active logger (first init wins, mirrors\n * `setupOtelRum`). The `x-observ-key` header is omitted when the key is empty\n * (the trace setup already warns about a missing key).\n */\nexport function setupOtelLogs(options: ObservInitOptions): Logger {\n if (activeLogger) return activeLogger\n\n const headers: Record<string, string> = {}\n if (options.key) headers['x-observ-key'] = options.key\n\n const exporter = new OTLPLogExporter({ url: buildLogsUrl(options.endpoint), headers })\n const p = new LoggerProvider({\n resource: buildResource(options),\n processors: [new BatchLogRecordProcessor(exporter)],\n })\n\n try {\n const logger = p.getLogger('@observtech/rum')\n // Commit the module state ONLY once everything succeeded — otherwise a\n // partial init would leak the provider's flush timer and latch the guard.\n provider = p\n activeLogger = logger\n return logger\n } catch (err) {\n // Roll back a partial init (mirrors otel-rum.ts): shut the provider down so\n // its BatchLogRecordProcessor timer can't outlive the failure, and leave the\n // guards null so a later setup can retry.\n void p.shutdown()\n throw err\n }\n}\n\n/** Inactivity refresh throttle for the cached session id (story 1.2 — avoid a\n * synchronous sessionStorage write on every event). */\nconst SESSION_ID_REFRESH_MS = 1_000\nlet cachedSessionId = ''\nlet cachedSessionIdAt = 0\n\n/**\n * Resolve the visit `session.id`, refreshing it (and the session's inactivity\n * window) at most once per second. A click burst therefore costs ≤ 1\n * `getSessionId` (→ ≤ 1 sessionStorage write) per second instead of one per\n * event, while still counting interaction as session activity.\n */\nfunction currentSessionId(): string {\n const now = Date.now()\n if (!cachedSessionId || now - cachedSessionIdAt >= SESSION_ID_REFRESH_MS) {\n cachedSessionId = getSessionId()\n cachedSessionIdAt = now\n }\n return cachedSessionId\n}\n\n/**\n * Emit one semantic event as an OTel log record: `event.name` in the\n * `observ.session.*` namespace + the exact `session.id` correlation attribute\n * (throttled refresh, so an event read also counts as session activity, 1.2) +\n * the caller's attributes. Best-effort: never throws to the host page.\n */\nexport function emitSessionEvent(\n logger: Logger,\n eventName: string,\n attrs: Record<string, string> = {},\n): void {\n try {\n logger.emit({\n attributes: {\n 'event.name': eventName,\n [SESSION_ID_ATTRIBUTE]: currentSessionId(),\n ...attrs,\n },\n })\n } catch (err) {\n console.warn('[observ] semantic event emit failed', err)\n }\n}\n\n/**\n * @internal Flush + shut the logs provider down and reset the idempotence guard\n * so a later setup can re-init. Called by the SDK teardown.\n */\nexport async function shutdownOtelLogs(): Promise<void> {\n const p = provider\n provider = null\n activeLogger = null\n await p?.shutdown()\n}\n\n/** @internal Test-only: the active logger, or `null` when logs are not set up. */\nexport function getActiveLogger(): Logger | null {\n return activeLogger\n}\n","/**\n * JS error capture for the Observ RUM SDK (FR-9, story 2.4).\n *\n * Captures uncaught errors (`window` `error`) and unhandled promise rejections\n * (`unhandledrejection`) and emits them as OTel log records\n * (`observ.session.js_error`) on the SAME logs channel as the semantic events\n * (story 2.3): standard exception semconv attributes + `session.id`. The stack\n * trace is carried as a log/event attribute — never a metric (architecture\n * enforcement).\n *\n * Invariant (1.1/1.2/1.3): never break the host page. Handlers run when the\n * browser is already handling an error, so each is `try/catch`-guarded and we\n * NEVER `preventDefault()` — the site's own error flow (console, other handlers)\n * is left untouched; we only observe.\n */\nimport type { Logger } from '@opentelemetry/api-logs'\nimport {\n ATTR_EXCEPTION_MESSAGE,\n ATTR_EXCEPTION_STACKTRACE,\n ATTR_EXCEPTION_TYPE,\n} from '@opentelemetry/semantic-conventions'\n\nimport { emitSessionEvent, setupOtelLogs } from './otel-logs.js'\nimport type { ObservInitOptions } from './types.js'\n\n/** Max `js_error` events per rolling window — bounds an error storm (AC#5)\n * without going permanently blind: the window resets, so capture self-heals. */\nexport const MAX_JS_ERRORS = 50\n/** Rolling window (ms) for the {@link MAX_JS_ERRORS} rate limit. */\nexport const RATE_WINDOW_MS = 60_000\n/** Truncation bounds so one error can't produce a huge log record. */\nconst MAX_MESSAGE = 1_024\nconst MAX_STACK = 4_096\n\n/** Best-effort string for a rejection reason: Error→message handled by the\n * caller; objects → JSON (so `{code:500}` isn't flattened to \"[object Object]\");\n * everything else → `String`. */\nfunction reasonToMessage(reason: unknown): string {\n if (typeof reason === 'string') return reason\n if (typeof reason === 'object' && reason !== null) {\n try {\n return JSON.stringify(reason) ?? String(reason)\n } catch {\n return String(reason)\n }\n }\n return String(reason)\n}\n\n/** Public handle for the running JS-error capture. */\nexport interface JsErrorHandle {\n /** Remove the global error listeners. Idempotent. The shared logs provider is\n * shut down by `index.shutdown()`, NOT here (two taps share it). */\n stop(): void\n}\n\nconst NOOP: JsErrorHandle = { stop: () => {} }\n\n/** Module-level guard so the capture is self-idempotent. */\nlet active: JsErrorHandle | null = null\n\nfunction truncate(s: string, max: number): string {\n return s.length > max ? s.slice(0, max) : s\n}\n\n/**\n * Start capturing uncaught JS errors + unhandled rejections. Returns a handle\n * whose `stop()` removes the listeners. Never throws; no-op in a non-DOM env.\n * Not gated by `disableReplay` — errors are useful even without replay.\n */\nexport function startJsErrorCapture(options: ObservInitOptions): JsErrorHandle {\n if (active) return active\n if (typeof window === 'undefined') return NOOP\n\n let logger: Logger\n try {\n logger = setupOtelLogs(options) // shared, idempotent — same logger as 2.3\n } catch (err) {\n console.warn('[observ] js-errors: logs setup failed', err)\n return NOOP\n }\n\n // Sliding-window rate limit: at most MAX_JS_ERRORS per RATE_WINDOW_MS. Resets\n // each window so a burst at boot doesn't blind capture for the rest of a long\n // SPA session.\n let windowStart = 0\n let inWindow = 0\n\n const emit = (type: string | undefined, message: string, stack: string | undefined): void => {\n const now = Date.now()\n if (now - windowStart >= RATE_WINDOW_MS) {\n windowStart = now\n inWindow = 0\n }\n if (inWindow >= MAX_JS_ERRORS) return // anti-flood cap (AC#5)\n inWindow++\n const attrs: Record<string, string> = {\n [ATTR_EXCEPTION_MESSAGE]: truncate(message, MAX_MESSAGE),\n }\n if (type) attrs[ATTR_EXCEPTION_TYPE] = type\n if (stack) attrs[ATTR_EXCEPTION_STACKTRACE] = truncate(stack, MAX_STACK)\n emitSessionEvent(logger, 'observ.session.js_error', attrs)\n }\n\n const onError = (e: ErrorEvent): void => {\n try {\n // `e.error` is the Error in modern browsers; cross-origin \"Script error.\"\n // has `e.error === null`, so fall back to `e.message` with no stack.\n const err = e.error as Error | null | undefined\n emit(err?.name, err?.message ?? e.message ?? 'unknown error', err?.stack ?? undefined)\n } catch {\n /* never let the error handler break the host page */\n }\n }\n\n const onRejection = (e: PromiseRejectionEvent): void => {\n try {\n const reason: unknown = e.reason\n if (reason instanceof Error) {\n emit(reason.name, reason.message, reason.stack ?? undefined)\n } else {\n emit('UnhandledRejection', reasonToMessage(reason), undefined)\n }\n } catch {\n /* swallow — observe, never interfere */\n }\n }\n\n // Do NOT use `window.onerror =` (would clobber a host handler). Never call\n // preventDefault — we observe without suppressing the site's error flow.\n window.addEventListener('error', onError)\n window.addEventListener('unhandledrejection', onRejection)\n\n const handle: JsErrorHandle = {\n stop(): void {\n window.removeEventListener('error', onError)\n window.removeEventListener('unhandledrejection', onRejection)\n active = null\n },\n }\n active = handle\n return handle\n}\n","/**\n * OpenTelemetry Metrics + Core Web Vitals for the Observ RUM SDK (parity story).\n *\n * Net-new \"metrics\" channel — the third OTLP/HTTP signal, exported to\n * `{endpoint}/v1/metrics` on its own `MeterProvider` (the heavy `/v1/replay`\n * channel is never crossed). It captures Core Web Vitals (LCP / INP / CLS / FCP /\n * TTFB) as **histograms** (queryable as metrics) and ALSO mirrors each as an\n * `observ.session.web_vital` **log event** carrying `session.id`, so a single\n * vital appears both on the metrics dashboards and on the session timeline.\n *\n * Gated by `disableMetrics` (default ON). Like the rest of the SDK it is\n * best-effort and never throws to the host page.\n */\nimport { type Meter } from '@opentelemetry/api'\nimport { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-http'\nimport { MeterProvider, PeriodicExportingMetricReader } from '@opentelemetry/sdk-metrics'\nimport { onCLS, onFCP, onINP, onLCP, onTTFB, type Metric } from 'web-vitals'\n\nimport { buildResource } from './resource.js'\nimport { emitSessionEvent, setupOtelLogs } from './otel-logs.js'\nimport type { ObservInitOptions } from './types.js'\n\n/** Export interval for the periodic metric reader (ms). */\nconst METRIC_EXPORT_INTERVAL_MS = 30_000\n\n/** Web-Vital name → histogram spec. CLS is unit-less; the rest are milliseconds. */\nconst VITAL_HISTOGRAMS: Record<string, { name: string; unit: string; description: string }> = {\n LCP: { name: 'web_vitals.lcp', unit: 'ms', description: 'Largest Contentful Paint' },\n INP: { name: 'web_vitals.inp', unit: 'ms', description: 'Interaction to Next Paint' },\n FCP: { name: 'web_vitals.fcp', unit: 'ms', description: 'First Contentful Paint' },\n TTFB: { name: 'web_vitals.ttfb', unit: 'ms', description: 'Time To First Byte' },\n CLS: { name: 'web_vitals.cls', unit: '1', description: 'Cumulative Layout Shift' },\n}\n\n/**\n * Join an endpoint base URL with the OTLP/HTTP metrics path. Mirror of\n * {@link import('./otel-rum.js').buildTracesUrl}.\n */\nexport function buildMetricsUrl(endpoint: string): string {\n try {\n const url = new URL(endpoint)\n url.pathname = `${url.pathname.replace(/\\/+$/, '')}/v1/metrics`\n url.search = ''\n url.hash = ''\n return url.toString()\n } catch {\n return `${endpoint.replace(/\\/+$/, '')}/v1/metrics`\n }\n}\n\nlet provider: MeterProvider | null = null\n\n/** Handle returned by {@link setupOtelMetrics} for teardown. */\nexport interface MetricsHandle {\n meter: Meter\n stop(): Promise<void>\n}\n\n/**\n * Wire up the meter provider + Web-Vitals capture. Idempotent: a second call is a\n * no-op returning the existing handle (first init wins, mirrors `setupOtelLogs`).\n * The `x-observ-key` header is omitted when the key is empty.\n */\nexport function setupOtelMetrics(options: ObservInitOptions): MetricsHandle {\n if (provider) return { meter: provider.getMeter('@observtech/rum'), stop: shutdownOtelMetrics }\n\n const headers: Record<string, string> = {}\n if (options.key) headers['x-observ-key'] = options.key\n\n const reader = new PeriodicExportingMetricReader({\n exporter: new OTLPMetricExporter({ url: buildMetricsUrl(options.endpoint), headers }),\n exportIntervalMillis: METRIC_EXPORT_INTERVAL_MS,\n })\n\n const p = new MeterProvider({ resource: buildResource(options), readers: [reader] })\n const meter = p.getMeter('@observtech/rum')\n\n // Histograms for each Core Web Vital; the logger mirrors them as timeline events.\n const histograms = Object.fromEntries(\n Object.entries(VITAL_HISTOGRAMS).map(([key, h]) => [\n key,\n meter.createHistogram(h.name, { unit: h.unit, description: h.description }),\n ]),\n )\n // Reuse the (idempotent) logs provider so a vital also lands on the session\n // timeline as `observ.session.web_vital`. Never let a logs failure break metrics.\n let logger: ReturnType<typeof setupOtelLogs> | null = null\n try {\n logger = setupOtelLogs(options)\n } catch {\n /* metrics still work without the timeline mirror */\n }\n\n const record = (m: Metric): void => {\n try {\n const path = typeof location !== 'undefined' ? location.pathname : ''\n const dims = {\n 'web_vital.rating': m.rating,\n 'web_vital.navigation_type': m.navigationType,\n 'url.path': path,\n }\n histograms[m.name]?.record(m.value, dims)\n if (logger) {\n emitSessionEvent(logger, 'observ.session.web_vital', {\n 'web_vital.name': m.name,\n 'web_vital.value': String(m.value),\n 'web_vital.id': m.id,\n 'web_vital.rating': m.rating,\n 'web_vital.navigation_type': m.navigationType,\n 'url.path': path,\n })\n }\n } catch {\n /* swallow — a single vital must never break the page */\n }\n }\n\n try {\n onLCP(record)\n onINP(record)\n onFCP(record)\n onTTFB(record)\n onCLS(record)\n } catch {\n /* web-vitals unavailable (e.g. non-browser) — provider still set up */\n }\n\n provider = p\n return { meter, stop: shutdownOtelMetrics }\n}\n\n/**\n * @internal Flush + shut the meter provider down and reset the idempotence guard.\n * Called by the SDK teardown.\n */\nexport async function shutdownOtelMetrics(): Promise<void> {\n const p = provider\n provider = null\n await p?.shutdown()\n}\n\n/** @internal Test-only: the active meter provider, or `null` when metrics are off. */\nexport function getActiveMeterProvider(): MeterProvider | null {\n return provider\n}\n","/*\n * Copyright The OpenTelemetry Authors\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type { TracerProvider, MeterProvider } from '@opentelemetry/api';\nimport type { Instrumentation } from './types';\nimport type { LoggerProvider } from '@opentelemetry/api-logs';\n\n/**\n * Enable instrumentations\n * @param instrumentations\n * @param tracerProvider\n * @param meterProvider\n */\nexport function enableInstrumentations(\n instrumentations: Instrumentation[],\n tracerProvider?: TracerProvider,\n meterProvider?: MeterProvider,\n loggerProvider?: LoggerProvider\n): void {\n for (let i = 0, j = instrumentations.length; i < j; i++) {\n const instrumentation = instrumentations[i];\n if (tracerProvider) {\n instrumentation.setTracerProvider(tracerProvider);\n }\n if (meterProvider) {\n instrumentation.setMeterProvider(meterProvider);\n }\n if (loggerProvider && instrumentation.setLoggerProvider) {\n instrumentation.setLoggerProvider(loggerProvider);\n }\n // instrumentations have been already enabled during creation\n // so enable only if user prevented that by setting enabled to false\n // this is to prevent double enabling but when calling register all\n // instrumentations should be now enabled\n if (!instrumentation.getConfig().enabled) {\n instrumentation.enable();\n }\n }\n}\n\n/**\n * Disable instrumentations\n * @param instrumentations\n */\nexport function disableInstrumentations(\n instrumentations: Instrumentation[]\n): void {\n instrumentations.forEach(instrumentation => instrumentation.disable());\n}\n","/*\n * Copyright The OpenTelemetry Authors\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { trace, metrics } from '@opentelemetry/api';\nimport { logs } from '@opentelemetry/api-logs';\nimport {\n disableInstrumentations,\n enableInstrumentations,\n} from './autoLoaderUtils';\nimport type { AutoLoaderOptions } from './types_internal';\n\n/**\n * It will register instrumentations and plugins\n * @param options\n * @return returns function to unload instrumentation and plugins that were\n * registered\n */\nexport function registerInstrumentations(\n options: AutoLoaderOptions\n): () => void {\n const tracerProvider = options.tracerProvider || trace.getTracerProvider();\n const meterProvider = options.meterProvider || metrics.getMeterProvider();\n const loggerProvider = options.loggerProvider || logs.getLoggerProvider();\n const instrumentations = options.instrumentations?.flat() ?? [];\n\n enableInstrumentations(\n instrumentations,\n tracerProvider,\n meterProvider,\n loggerProvider\n );\n\n return () => {\n disableInstrumentations(instrumentations);\n };\n}\n","/**\n * OpenTelemetry RUM wiring for the Observ SDK (FR-4, story 1.3).\n *\n * Sets up a {@link WebTracerProvider} that:\n * - creates `http.client` spans for browser `fetch`/XHR (auto-instrumentation),\n * - stamps every span with the visit's `session.id` (via {@link SessionAttributeSpanProcessor}),\n * - injects the W3C `traceparent` header on outgoing requests (default\n * trace-context propagator; cross-origin gated by `propagateTraceHeaderCorsUrls`),\n * - exports spans over OTLP/HTTP to `{endpoint}/v1/traces` (BatchSpanProcessor).\n *\n * Like the rest of the SDK, this must never throw out to the host page: the\n * caller ({@link import('./index.js')}) wraps {@link setupOtelRum} defensively.\n *\n * NOTE: until the backend OTLP/HTTP receiver lands (story 1.4), exports will fail\n * at the network layer (CORS / 404). That is expected — span creation, attribute\n * stamping and header propagation are fully exercised regardless.\n */\nimport { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http'\nimport { registerInstrumentations } from '@opentelemetry/instrumentation'\nimport { DocumentLoadInstrumentation } from '@opentelemetry/instrumentation-document-load'\nimport { FetchInstrumentation } from '@opentelemetry/instrumentation-fetch'\nimport { XMLHttpRequestInstrumentation } from '@opentelemetry/instrumentation-xml-http-request'\nimport {\n AlwaysOnSampler,\n ParentBasedSampler,\n TraceIdRatioBasedSampler,\n type Sampler,\n} from '@opentelemetry/sdk-trace-base'\nimport {\n BatchSpanProcessor,\n WebTracerProvider,\n type ReadableSpan,\n type Span,\n type SpanProcessor,\n} from '@opentelemetry/sdk-trace-web'\n\nimport { buildResource } from './resource.js'\nimport { SESSION_ID_ATTRIBUTE } from './constants.js'\nimport { getSessionId } from './session.js'\nimport type { ObservInitOptions } from './types.js'\n\n/**\n * Head sampler from `sampleRate`: a `ParentBasedSampler(TraceIdRatioBased)` for a\n * ratio in `[0, 1)`, else `AlwaysOn` (sample everything — the default).\n */\nexport function buildSampler(options: ObservInitOptions): Sampler {\n const rate = options.sampleRate\n if (typeof rate === 'number' && Number.isFinite(rate) && rate >= 0 && rate < 1) {\n return new ParentBasedSampler({ root: new TraceIdRatioBasedSampler(rate) })\n }\n return new AlwaysOnSampler()\n}\n\n/**\n * URLs the auto-instrumentations must NEVER trace: the telemetry pipeline itself\n * (`{endpoint}/v1/...`). Without this the exporter's own POST gets traced,\n * spawning a self-perpetuating trickle of `http.client` spans.\n */\nexport function telemetryIgnoreUrls(endpoint: string): RegExp[] {\n const escaped = endpoint.replace(/\\/+$/, '').replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n return [new RegExp(`${escaped}/v1/`)]\n}\n\n/**\n * Join an endpoint base URL with the OTLP/HTTP traces path. Uses the `URL` API\n * for absolute endpoints so a path prefix is preserved, a trailing slash never\n * doubles, and any query/fragment (meaningless on the traces endpoint) is\n * dropped — `https://x?a=1` ⇒ `https://x/v1/traces`, not `https://x?a=1/v1/traces`.\n * A relative or empty endpoint falls back to a string join, yielding a\n * same-origin `…/v1/traces` path.\n */\nexport function buildTracesUrl(endpoint: string): string {\n try {\n const url = new URL(endpoint)\n url.pathname = `${url.pathname.replace(/\\/+$/, '')}/v1/traces`\n url.search = ''\n url.hash = ''\n return url.toString()\n } catch {\n return `${endpoint.replace(/\\/+$/, '')}/v1/traces`\n }\n}\n\n/**\n * Span processor whose only job is to stamp `session.id` on every span at start.\n *\n * Using a processor (rather than per-instrumentation `applyCustomAttributesOnSpan`)\n * guarantees ALL spans — fetch, XHR, and any future document-load — carry the\n * attribute through a single code path. It reads the id via {@link getSessionId},\n * which also refreshes the session's inactivity window (story 1.2 decision): a\n * span therefore counts as session activity.\n */\nexport class SessionAttributeSpanProcessor implements SpanProcessor {\n onStart(span: Span): void {\n // onStart runs synchronously inside the host page's own fetch/XHR. The SDK\n // must never throw out to the page, so guard here even though getSessionId()\n // is contractually no-throw: a missing attribute beats a broken host request.\n try {\n span.setAttribute(SESSION_ID_ATTRIBUTE, getSessionId())\n } catch {\n /* swallow — never let span stamping break a host request */\n }\n }\n onEnd(_span: ReadableSpan): void {}\n forceFlush(): Promise<void> {\n return Promise.resolve()\n }\n shutdown(): Promise<void> {\n return Promise.resolve()\n }\n}\n\nlet provider: WebTracerProvider | null = null\nlet disableInstrumentations: (() => void) | null = null\nlet activeConfig: { endpoint: string; key: string } | null = null\n\n/**\n * Wire up OTel RUM tracing. Idempotent: a second call is a no-op while a provider\n * is already active (mirrors the single-`init` contract; first call wins). Not\n * defensive on its own — `init` owns the try/catch so a setup failure never\n * escapes to the page — but it cleans up after itself: a partial init (register\n * or instrumentation throwing, e.g. SSR / no `fetch`/XHR) shuts the provider down\n * and resets the guard before rethrowing, so no `WebTracerProvider`\n * (BatchSpanProcessor timer + global registration) leaks and a later retry works.\n */\nexport function setupOtelRum(options: ObservInitOptions): void {\n if (provider) {\n // First init wins. Warn if a later call diverges (key rotation / env switch)\n // so the dropped config isn't silently swallowed by the idempotence guard.\n if (\n activeConfig &&\n (activeConfig.endpoint !== options.endpoint || activeConfig.key !== options.key)\n ) {\n console.warn(\n '[observ] OTel RUM already initialized; ignoring divergent endpoint/key on this init() (first call wins).',\n )\n }\n return\n }\n\n // API-key auth via the custom `x-observ-key` header — the receiver (story 1.4)\n // must decode the same name and list it in `Access-Control-Allow-Headers`. An\n // empty key would produce a malformed credential, so omit the header (and warn)\n // rather than send a blank one.\n const headers: Record<string, string> = {}\n if (options.key) {\n headers['x-observ-key'] = options.key\n } else {\n console.warn('[observ] no API key provided; front-end spans will export unauthenticated.')\n }\n\n const exporter = new OTLPTraceExporter({\n url: buildTracesUrl(options.endpoint),\n headers,\n })\n\n const ignoreUrls = telemetryIgnoreUrls(options.endpoint)\n\n // SDK 2.x: span processors are constructor-only (`addSpanProcessor` was removed).\n // Order matters — stamp `session.id` before the batch processor exports.\n const p = new WebTracerProvider({\n resource: buildResource(options),\n sampler: buildSampler(options),\n spanProcessors: [new SessionAttributeSpanProcessor(), new BatchSpanProcessor(exporter)],\n })\n\n try {\n // Default registration: W3C trace-context propagator + web StackContextManager.\n p.register()\n disableInstrumentations = registerInstrumentations({\n tracerProvider: p,\n instrumentations: [\n // Page-load timing: documentLoad / documentFetch / resourceFetch spans.\n new DocumentLoadInstrumentation(),\n new FetchInstrumentation({\n propagateTraceHeaderCorsUrls: options.propagateTraceHeaderCorsUrls,\n ignoreUrls,\n }),\n new XMLHttpRequestInstrumentation({\n propagateTraceHeaderCorsUrls: options.propagateTraceHeaderCorsUrls,\n ignoreUrls,\n }),\n ],\n })\n } catch (err) {\n // Roll back a partial init so nothing leaks and the guard doesn't latch.\n disableInstrumentations?.()\n disableInstrumentations = null\n void p.shutdown()\n throw err\n }\n\n provider = p\n activeConfig = { endpoint: options.endpoint, key: options.key }\n}\n\n/**\n * @internal Test-only. The active provider, or `null` when tracing is not set\n * up. Lets tests assert idempotence (same instance after a second `setupOtelRum`).\n */\nexport function getActiveProvider(): WebTracerProvider | null {\n return provider\n}\n\n/**\n * @internal Tear down instrumentations and the provider, resetting the\n * idempotence guard. Used by tests (and any future explicit teardown). Not on\n * the public {@link import('./types.js').ObservSdk} surface.\n */\nexport async function shutdownOtelRum(): Promise<void> {\n const p = provider\n // Atomic: even if disabling instrumentations throws, still null the guard and\n // shut the provider down so the BatchSpanProcessor timer can't outlive teardown.\n try {\n disableInstrumentations?.()\n } finally {\n disableInstrumentations = null\n provider = null\n activeConfig = null\n await p?.shutdown()\n }\n}\n","/**\n * PII masking / privacy controls for the heavy rrweb replay flux\n * (Epic 4 — Confidentialité, story 4.1).\n *\n * The heavy replay records the live DOM. By default rrweb captures the *values*\n * users type into inputs (passwords aside, which it already masks) and the\n * visible text. On any real-data surface that is PII — architecture decision D7\n * and PRD Open Q5 require masking to be enabled **before** any real data flows.\n * This module is that gate.\n *\n * SAFE-BY-DEFAULT: with no `privacy` config at all, ALL input values are masked\n * in the replay (`maskAllInputs: true`). A surface that is known to be free of\n * sensitive input can opt out with `privacy: { maskAllInputs: false }`.\n *\n * The defaults map the SDK's small `PrivacyOptions` bag onto rrweb's native\n * masking knobs, and expose three conventional CSS classes so a host page can\n * mark sensitive nodes declaratively without writing custom functions:\n * - `observ-mask` → mask the TEXT of the element (rrweb `maskTextClass`)\n * - `observ-block` → drop the element from the replay entirely (`blockClass`)\n * - `observ-ignore` → record the element but ignore its user input (`ignoreClass`)\n *\n * Channel scope: this governs the HEAVY flux only (rrweb → `/v1/replay`). Masking\n * the LIGHT semantic-event text (`element.text` on `observ.session.click`) is a\n * separate concern handled by a later story (4.2); the two channels are never\n * crossed (enforcement rule).\n */\nimport type { PrivacyOptions } from './types.js'\n\n/** Default class marking elements whose TEXT is masked in the replay (rrweb `maskTextClass`). */\nexport const DEFAULT_MASK_TEXT_CLASS = 'observ-mask'\n/** Default class marking elements dropped entirely from the replay (rrweb `blockClass`). */\nexport const DEFAULT_BLOCK_CLASS = 'observ-block'\n/** Default class marking inputs whose user input events are ignored (rrweb `ignoreClass`). */\nexport const DEFAULT_IGNORE_CLASS = 'observ-ignore'\n\n/**\n * The subset of rrweb `recordOptions` that govern masking. Intentionally a flat,\n * fully-resolved shape (no `undefined` for the always-present fields) so the\n * recorder can spread it straight into `record({ ... })` and tests can assert it.\n */\nexport interface ReplayMaskingOptions {\n /** Mask the value of every `<input>`/`<textarea>`/`<select>` in the replay. */\n maskAllInputs: boolean\n /** Mask the text of elements carrying this class. */\n maskTextClass: string\n /** Drop elements carrying this class from the replay. */\n blockClass: string\n /** Ignore user input on elements carrying this class. */\n ignoreClass: string\n /**\n * When `maskAllText` is on, a selector matching every element so rrweb masks\n * ALL text node content. Omitted otherwise (only class-scoped text masking).\n */\n maskTextSelector?: string\n}\n\n/**\n * Resolve the public {@link PrivacyOptions} into the rrweb masking options,\n * applying the safe-by-default policy. Pure (no DOM/global access) so it is\n * trivially unit-testable and reusable from `init()`.\n */\nexport function resolveReplayMasking(privacy?: PrivacyOptions): ReplayMaskingOptions {\n const resolved: ReplayMaskingOptions = {\n // Safe-by-default: inputs are masked unless the host *explicitly* opts out.\n maskAllInputs: privacy?.maskAllInputs ?? true,\n maskTextClass: privacy?.maskTextClass ?? DEFAULT_MASK_TEXT_CLASS,\n blockClass: privacy?.blockClass ?? DEFAULT_BLOCK_CLASS,\n ignoreClass: privacy?.ignoreClass ?? DEFAULT_IGNORE_CLASS,\n }\n // Full-text masking is opt-in: it heavily degrades replay usefulness, so it is\n // off by default and only class-scoped text masking applies. '*' tells rrweb\n // to treat every element as a masked-text element.\n if (privacy?.maskAllText) resolved.maskTextSelector = '*'\n return resolved\n}\n","/**\n * Replay chunk transport for the Observ RUM SDK (FR-2/FR-5, story 2.2).\n *\n * The heavy rrweb flux travels on its OWN channel — `POST /v1/replay` — never\n * through the OTLP exporter (architecture: the two channels are never crossed).\n * The body is the raw gzip bytes of a `.jsonl.gz` chunk; the backend (story 2.1)\n * stores it verbatim and rejects an empty body (400), so we never POST one.\n *\n * Contract frozen by story 2.1:\n * POST {endpoint}/v1/replay?session_id=<id>&seq=<n>\n * headers: x-observ-key: <key>, content-type: application/octet-stream\n * body: gzip bytes (≤ 16 MiB)\n */\n\n/**\n * Join an endpoint base URL with the `/v1/replay` path. Mirror of\n * {@link import('./otel-rum.js').buildTracesUrl}: the `URL` API preserves a path\n * prefix, never doubles a trailing slash, and drops any query/fragment; a\n * relative or empty endpoint falls back to a same-origin path.\n */\nexport function buildReplayUrl(endpoint: string): string {\n try {\n const url = new URL(endpoint)\n url.pathname = `${url.pathname.replace(/\\/+$/, '')}/v1/replay`\n url.search = ''\n url.hash = ''\n return url.toString()\n } catch {\n return `${endpoint.replace(/\\/+$/, '')}/v1/replay`\n }\n}\n\n/**\n * Gzip newline-delimited JSON lines via the native `CompressionStream` — no\n * dependency (resolves the story 1.1 gzip-strategy deferral). Available in every\n * evergreen browser and Node ≥ 18. Uses the `Blob.stream()` → `pipeThrough` →\n * `Response.arrayBuffer()` pipeline so there is no manual writer/reader (no\n * unhandled rejection, no backpressure deadlock). The output is the gzip stream,\n * stored as-is by the backend.\n */\nexport async function gzipJsonl(lines: string[]): Promise<Uint8Array> {\n const data = new TextEncoder().encode(lines.join('\\n'))\n const stream = new Blob([data as BlobPart]).stream().pipeThrough(new CompressionStream('gzip'))\n const buf = await new Response(stream).arrayBuffer()\n return new Uint8Array(buf)\n}\n\n/** Arguments for {@link postReplayChunk}. */\nexport interface PostReplayChunkOptions {\n /** Replay endpoint URL (from {@link buildReplayUrl}). */\n url: string\n /** API key for the `x-observ-key` header (omitted when empty). */\n key: string\n /** Current visit `session.id` (query param, keys the object-store prefix). */\n sessionId: string\n /** Monotonic chunk sequence within the session (query param). */\n seq: number\n /** Gzip bytes of the chunk. An empty body is never sent (server returns 400). */\n body: Uint8Array\n /** Use `fetch` keepalive for an unload flush (body capped ~64 KiB by the spec). */\n keepalive?: boolean\n}\n\n/**\n * POST one gzip replay chunk. **Best-effort: never throws** — a network failure\n * degrades to \"this chunk is lost\", it must not break the host page.\n */\nexport async function postReplayChunk(opts: PostReplayChunkOptions): Promise<void> {\n if (opts.body.length === 0) return // backend rejects an empty body (400)\n\n const headers: Record<string, string> = { 'content-type': 'application/octet-stream' }\n // Mirror otel-rum.ts: a blank key would be a malformed credential — omit it.\n if (opts.key) headers['x-observ-key'] = opts.key\n\n const url = `${opts.url}?session_id=${encodeURIComponent(opts.sessionId)}&seq=${opts.seq}`\n try {\n const res = await fetch(url, {\n method: 'POST',\n headers,\n body: opts.body as BodyInit,\n keepalive: opts.keepalive,\n })\n // `fetch` only rejects on network failure — surface server rejections\n // (400 empty / 401 auth / 413 over the 16 MiB cap) instead of silent success.\n if (!res.ok) {\n console.warn(`[observ] replay chunk rejected: HTTP ${res.status}`)\n }\n } catch (err) {\n console.warn('[observ] replay chunk upload failed', err)\n }\n}\n","/**\n * rrweb recording + chunked replay upload for the Observ RUM SDK (FR-2, story 2.2).\n *\n * Captures the visual session with `@rrweb/record` (initial FullSnapshot + DOM\n * mutations), buffers events in memory, and POSTs gzip chunks to `/v1/replay`\n * (story 2.1) — triggered by SIZE or TIME, whichever comes first. The heavy flux\n * uses this channel exclusively, never the OTLP exporter.\n *\n * Invariant (1.1/1.2/1.3): the SDK must NEVER break the host page. Every path —\n * capture, serialize, gzip, upload — is defensive: a failure degrades to \"no\n * replay\", never an exception that escapes to the page.\n *\n * Flushes are SERIALIZED through a promise chain (`pending`): every trigger is\n * queued — never dropped — so the buffer cannot grow unbounded behind an\n * in-flight flush, `seq` is assigned in order, and two uploads never overlap.\n *\n * Session activity (1.2 deferral): `getSessionId` is read once per flush (~5 s),\n * NOT per rrweb event — touching the session on every high-frequency mutation\n * would thrash `sessionStorage` and jank the main thread.\n */\nimport { record } from '@rrweb/record'\n\nimport { resolveReplayMasking } from './privacy.js'\nimport { getSessionId } from './session.js'\nimport { buildReplayUrl, gzipJsonl, postReplayChunk } from './transport.js'\nimport type { ObservInitOptions } from './types.js'\n\n/** Serialized buffer size (pre-gzip) that triggers a size-based flush. */\nexport const CHUNK_MAX_BYTES = 512 * 1024 // ~512 KiB — well under the 16 MiB cap\n/** Interval (ms) for the time-based flush. */\nexport const CHUNK_INTERVAL_MS = 5_000\n/** rrweb full-snapshot cadence so a reader can resync from a checkpoint. */\nexport const CHECKOUT_INTERVAL_MS = 5 * 60 * 1_000\n\n/** Public handle for the running recorder. */\nexport interface ReplayRecorder {\n /** Stop capture, remove listeners, and flush the residual. Idempotent. */\n stop(): Promise<void>\n}\n\n/** No-op recorder returned in a non-DOM environment (SSR) — nothing runs. */\nconst NOOP_RECORDER: ReplayRecorder = { stop: () => Promise.resolve() }\n\n/**\n * Start rrweb capture + chunked upload. Returns a handle whose `stop()` tears\n * everything down and flushes the tail. Never throws: a capture/start failure is\n * swallowed (the page keeps working, just without replay).\n */\nexport function startReplayRecording(options: ObservInitOptions): ReplayRecorder {\n // SSR / non-DOM guard: rrweb and the lifecycle listeners need `document` /\n // `window`. Degrade to a no-op recorder (mirrors session.ts's globalThis-\n // defensive style) rather than throwing a ReferenceError / leaking a timer.\n if (typeof document === 'undefined' || typeof window === 'undefined') {\n return NOOP_RECORDER\n }\n\n const url = buildReplayUrl(options.endpoint)\n const key = options.key\n\n let buffer: string[] = []\n let bufferedBytes = 0\n let seq = 0\n let lastSessionId: string | null = null\n let stopped = false\n // Flush chain: each trigger appends to this promise so flushes run one after\n // another (never concurrently, never dropped). Kept reject-free by the inner\n // try/catch + the trailing `.catch`.\n let pending: Promise<void> = Promise.resolve()\n\n /** Serialize → gzip → upload the current buffer. Swapped before the first await. */\n async function doFlush(keepalive: boolean): Promise<void> {\n if (buffer.length === 0) return\n const lines = buffer\n buffer = []\n bufferedBytes = 0\n try {\n const body = await gzipJsonl(lines)\n const sessionId = getSessionId()\n // The session id rotated (idle tab past the 30-min window): restart `seq`\n // so the new object-store prefix begins at 0 (its own checkpoint).\n if (lastSessionId !== null && lastSessionId !== sessionId) seq = 0\n lastSessionId = sessionId\n await postReplayChunk({ url, key, sessionId, seq: seq++, body, keepalive })\n } catch (err) {\n console.warn('[observ] replay flush failed', err)\n }\n }\n\n /** Queue a flush after any in-flight one (never dropped). */\n function enqueueFlush(keepalive = false): void {\n pending = pending.then(() => doFlush(keepalive)).catch(() => {})\n }\n\n const emit = (event: unknown): void => {\n if (stopped) return // drop trailing events after teardown\n try {\n const line = JSON.stringify(event)\n buffer.push(line)\n bufferedBytes += line.length\n if (bufferedBytes >= CHUNK_MAX_BYTES) enqueueFlush()\n } catch {\n /* never let capture break the host page */\n }\n }\n\n // PII masking (story 4.1): safe-by-default — input values are masked unless\n // the host explicitly opts out via `privacy.maskAllInputs: false`. Resolved\n // once here and spread into the recorder config so the heavy replay flux is\n // privacy-safe by construction (architecture D7 / PRD Open Q5).\n const masking = resolveReplayMasking(options.privacy)\n\n let stopFn: (() => void) | undefined\n try {\n // `record` returns the stop handler (or undefined if unsupported).\n stopFn = record({ emit, checkoutEveryNms: CHECKOUT_INTERVAL_MS, ...masking }) ?? undefined\n } catch (err) {\n console.warn('[observ] rrweb recording failed to start', err)\n }\n\n const interval = setInterval(() => enqueueFlush(), CHUNK_INTERVAL_MS)\n\n // Lifecycle flush (1.3 deferral). visibilitychange→hidden fires on tab\n // switch / minimize / most mobile navigations while the page is still alive;\n // pagehide is the best-effort last resort (keepalive — a body the browser\n // can't keepalive-send is rejected and logged, not silently pre-dropped).\n const onVisibility = (): void => {\n if (document.visibilityState === 'hidden') enqueueFlush()\n }\n const onPageHide = (): void => {\n enqueueFlush(true)\n }\n document.addEventListener('visibilitychange', onVisibility)\n window.addEventListener('pagehide', onPageHide)\n\n return {\n async stop(): Promise<void> {\n if (stopped) return\n stopped = true\n clearInterval(interval)\n document.removeEventListener('visibilitychange', onVisibility)\n window.removeEventListener('pagehide', onPageHide)\n try {\n stopFn?.()\n } catch {\n /* swallow — teardown must not throw */\n }\n enqueueFlush() // final residual\n await pending // wait for the whole chain (incl. the final flush) to settle\n },\n }\n}\n","/**\n * Minimal, defensive CSS-selector + text derivation for semantic events\n * (story 2.3). Produces a short, reasonably stable selector for a clicked\n * element and a truncated text label. Never throws (the SDK must never break\n * the host page); degrades to the tag name or `''`.\n */\n\nconst MAX_TEXT = 100\nconst MAX_CLASSES = 3\nconst MAX_CLASS_LEN = 30\nconst MAX_DEPTH = 4\n\n/**\n * Build a short CSS selector for `el`:\n * - `tag#id` when the element has an id,\n * - else `tag.class1.class2` (≤ 3 short classes),\n * - else a depth-bounded `tag:nth-of-type(n)` ancestor path (≤ 4 levels).\n * Returns `''` for a non-element / null, or the bare tag name on any failure.\n */\nexport function cssSelector(el: Element | null): string {\n if (!el || el.nodeType !== 1) return ''\n try {\n // `localName` is lowercase for HTML but case-preserved for SVG\n // (`linearGradient`, `clipPath`) — `tagName.toLowerCase()` would corrupt those.\n const tag = el.localName\n if (el.id) return `${tag}#${el.id}`\n\n const classes = Array.from(el.classList)\n .filter((c) => c.length > 0 && c.length <= MAX_CLASS_LEN)\n .slice(0, MAX_CLASSES)\n if (classes.length > 0) return `${tag}.${classes.join('.')}`\n\n // Depth-bounded structural path.\n const parts: string[] = []\n let node: Element | null = el\n let depth = 0\n while (node && node.nodeType === 1 && depth < MAX_DEPTH) {\n const t = node.localName\n if (node.id) {\n parts.unshift(`${t}#${node.id}`)\n break\n }\n const parent: Element | null = node.parentElement\n if (parent) {\n const current = node\n const sameTag = Array.from(parent.children).filter((c) => c.tagName === current.tagName)\n if (sameTag.length > 1) {\n parts.unshift(`${t}:nth-of-type(${sameTag.indexOf(current) + 1})`)\n } else {\n parts.unshift(t)\n }\n } else {\n parts.unshift(t)\n }\n node = node.parentElement\n depth++\n }\n return parts.join(' > ')\n } catch {\n return el.localName ?? ''\n }\n}\n\n/** Trimmed, whitespace-collapsed, truncated `textContent` of `el` (≤ 100 chars). */\nexport function elementText(el: Element | null): string {\n if (!el) return ''\n try {\n const text = (el.textContent ?? '').trim().replace(/\\s+/g, ' ')\n return text.length > MAX_TEXT ? text.slice(0, MAX_TEXT) : text\n } catch {\n return ''\n }\n}\n","/**\n * Semantic event derivation for the Observ RUM SDK (FR-3 / D8, story 2.3).\n *\n * Derives high-value interaction facts from native DOM listeners and emits them\n * as OTel log records (`observ.session.*`) on the logs channel (`/v1/logs`):\n * - `observ.session.click` — every click, with `element.selector` / `element.text`\n * - `observ.session.rage_click` — ≥ 3 clicks < 1 s on the SAME selector\n * - `observ.session.navigate` — SPA navigation (`pushState`/`replaceState`/`popstate`), `url`\n *\n * Variance vs architecture D8 (\"tap rrweb emit\"): we use native DOM listeners\n * rather than reverse-mapping rrweb node ids — `element.selector`/`element.text`\n * are derived directly and reliably from `event.target`. Same OTel-logs output.\n *\n * Invariant (1.1/1.2/1.3): never break the host page. Listeners run in the\n * page's own context, so every handler is `try/catch`-guarded; the patched\n * `history` methods are restored on `stop()` (no leaked global).\n */\nimport type { Logger } from '@opentelemetry/api-logs'\n\nimport { emitSessionEvent, setupOtelLogs } from './otel-logs.js'\nimport { cssSelector, elementText } from './selector.js'\nimport type { ObservInitOptions } from './types.js'\n\n/** Rage-click window (ms) and click threshold (architecture D8 / AC#2). */\nexport const RAGE_CLICK_WINDOW_MS = 1_000\nexport const RAGE_CLICK_THRESHOLD = 3\n/** Cap on tracked selectors so the rage-click map can't grow unbounded over a\n * long session (cleared past this — rage detection is best-effort). */\nconst MAX_TRACKED_SELECTORS = 100\n\n/** Module-level guard so the tap is self-idempotent (a second start without a\n * stop() between would double-patch `history` / double-add listeners). */\nlet active: SemanticEventsHandle | null = null\n\n/** Public handle for the running semantic-event tap. */\nexport interface SemanticEventsHandle {\n /** Remove listeners, restore patched `history`, shut the logs provider down. */\n stop(): Promise<void>\n}\n\nconst NOOP: SemanticEventsHandle = { stop: () => Promise.resolve() }\n\n/** Resolve an `EventTarget` to the nearest `Element` (text/SVG nodes → parent). */\nfunction toElement(target: EventTarget | null): Element | null {\n if (target instanceof Element) return target\n const node = target as Node | null\n return node && node.parentElement ? node.parentElement : null\n}\n\n/**\n * Start deriving + emitting semantic events. Returns a handle whose `stop()`\n * tears everything down. Never throws; degrades to a no-op in a non-DOM env.\n * NOTE: not gated by `disableReplay` — semantic events are useful even without\n * the heavy replay capture.\n */\nexport function startSemanticEvents(options: ObservInitOptions): SemanticEventsHandle {\n if (active) return active\n if (typeof document === 'undefined' || typeof window === 'undefined') return NOOP\n\n let logger: Logger\n try {\n logger = setupOtelLogs(options)\n } catch (err) {\n console.warn('[observ] semantic events: logs setup failed', err)\n return NOOP\n }\n\n // Recent click timestamps per selector, for rage-click clustering.\n const clickTimes = new Map<string, number[]>()\n\n const onClick = (event: Event): void => {\n try {\n const el = toElement(event.target)\n if (!el) return\n const selector = cssSelector(el)\n emitSessionEvent(logger, 'observ.session.click', {\n 'element.selector': selector,\n 'element.text': elementText(el),\n })\n\n // Rage-click: ≥ THRESHOLD clicks within WINDOW on the same selector.\n const now = Date.now()\n const recent = (clickTimes.get(selector) ?? []).filter((t) => now - t < RAGE_CLICK_WINDOW_MS)\n recent.push(now)\n if (recent.length >= RAGE_CLICK_THRESHOLD) {\n emitSessionEvent(logger, 'observ.session.rage_click', { 'element.selector': selector })\n clickTimes.delete(selector) // reset the burst (one rage_click per burst)\n } else {\n // Bound the map: a selector clicked once never reaches the threshold and\n // would otherwise linger forever. Clear past the cap (rare; best-effort).\n if (clickTimes.size > MAX_TRACKED_SELECTORS) clickTimes.clear()\n clickTimes.set(selector, recent)\n }\n } catch {\n /* never let a click handler break the host page */\n }\n }\n\n const emitNavigate = (): void => {\n emitSessionEvent(logger, 'observ.session.navigate', { url: location.href })\n }\n const onPopState = (): void => emitNavigate()\n\n document.addEventListener('click', onClick, { capture: true })\n window.addEventListener('popstate', onPopState)\n\n // No native event fires for pushState/replaceState — patch them (and restore\n // on stop, so the global is never left monkey-patched).\n const origPushState = history.pushState\n const origReplaceState = history.replaceState\n let historyPatched = false\n try {\n history.pushState = function (this: History, ...args: Parameters<History['pushState']>): void {\n origPushState.apply(this, args)\n emitNavigate()\n }\n history.replaceState = function (\n this: History,\n ...args: Parameters<History['replaceState']>\n ): void {\n origReplaceState.apply(this, args)\n emitNavigate()\n }\n historyPatched = true\n } catch {\n /* leave history unpatched — popstate still works */\n }\n\n let stopped = false\n const handle: SemanticEventsHandle = {\n async stop(): Promise<void> {\n if (stopped) return\n stopped = true\n active = null\n document.removeEventListener('click', onClick, { capture: true })\n window.removeEventListener('popstate', onPopState)\n if (historyPatched) {\n try {\n history.pushState = origPushState\n history.replaceState = origReplaceState\n } catch {\n /* swallow — teardown must not throw */\n }\n }\n // The shared logs provider is shut down once by index.shutdown() (story\n // 2.4) — not here, since js-errors shares it.\n },\n }\n active = handle\n return handle\n}\n","import { installBaggagePropagation } from './baggage.js'\nimport { startJsErrorCapture, type JsErrorHandle } from './js-errors.js'\nimport { shutdownOtelLogs } from './otel-logs.js'\nimport { setupOtelMetrics, type MetricsHandle } from './otel-metrics.js'\nimport { setupOtelRum, shutdownOtelRum, telemetryIgnoreUrls } from './otel-rum.js'\nimport { startReplayRecording, type ReplayRecorder } from './rrweb-record.js'\nimport { startSemanticEvents, type SemanticEventsHandle } from './semantic-events.js'\nimport { ensureSession, getSessionId } from './session.js'\nimport type { ObservInitOptions, ObservSdk } from './types.js'\n\nexport type { ObservInitOptions, ObservSdk } from './types.js'\n\n/**\n * Attribute key used everywhere to correlate signals of a single session.\n * Re-exported from {@link ./constants.js} (the leaf module that internal modules\n * also import, avoiding an `index ↔ otel-rum` cycle). EXACTLY `session.id`.\n */\nexport { SESSION_ID_ATTRIBUTE } from './constants.js'\n\n/** Singleton replay recorder handle (one capture per page, like the OTel provider). */\nlet replayRecorder: ReplayRecorder | null = null\n/** Singleton semantic-events tap (story 2.3). */\nlet semanticEvents: SemanticEventsHandle | null = null\n/** Singleton JS-error capture (story 2.4). */\nlet jsErrors: JsErrorHandle | null = null\n/** Singleton metrics handle — Core Web Vitals + OTLP metrics (parity). */\nlet metrics: MetricsHandle | null = null\n/** Baggage-propagation uninstaller, set when `propagateBaggage` is on (parity). */\nlet baggageUninstall: (() => void) | null = null\n\n/**\n * Initialize the Observ RUM SDK.\n *\n * 1. Establishes (or resumes) the visit's `session.id` — the single\n * correlation key shared by every signal (story 1.2).\n * 2. Wires OTel RUM tracing (story 1.3): `http.client` spans for fetch/XHR,\n * carrying `session.id`, with W3C `traceparent` propagation and OTLP/HTTP\n * export to `{endpoint}/v1/traces`.\n * 3. Starts rrweb replay capture (story 2.2): buffered gzip chunks POSTed to\n * `{endpoint}/v1/replay` (size/time triggered), unless `disableReplay`.\n * 4. Derives semantic events (story 2.3): `click` / `rage_click` / `navigate`\n * emitted as OTel log records to `{endpoint}/v1/logs` (independent of\n * `disableReplay`).\n * 5. Captures JS errors (story 2.4): `observ.session.js_error` (uncaught\n * errors + unhandled rejections) on the same logs channel.\n *\n * Idempotent (a second call re-registers nothing) and never throws — any setup\n * failure is swallowed so the SDK can never break the host page; it degrades to\n * \"no tracing / no replay / no semantic events\".\n */\nexport function init(options: ObservInitOptions): void {\n try {\n ensureSession()\n setupOtelRum(options)\n if (!options.disableReplay && !replayRecorder) {\n replayRecorder = startReplayRecording(options)\n }\n // Semantic events + JS errors are useful even without replay → not gated.\n if (!semanticEvents) {\n semanticEvents = startSemanticEvents(options)\n }\n if (!jsErrors) {\n jsErrors = startJsErrorCapture(options)\n }\n // Metrics + Core Web Vitals (parity) — independent of replay; opt-out via `disableMetrics`.\n if (!options.disableMetrics && !metrics) {\n metrics = setupOtelMetrics(options)\n }\n // Baggage: stamp `session.id` on requests to the same backends that receive\n // `traceparent` (+ same-origin), so backend spans can read the session identity.\n if (options.propagateBaggage && !baggageUninstall) {\n const backends = [...(options.propagateTraceHeaderCorsUrls ?? [])]\n if (typeof location !== 'undefined') backends.push(location.origin)\n baggageUninstall = installBaggagePropagation(\n getSessionId,\n backends,\n telemetryIgnoreUrls(options.endpoint),\n )\n }\n } catch (err) {\n // The SDK must never break the host page (1.1/1.2 guarantee). Degrade to\n // \"no tracing / no replay / no semantic events\" rather than propagating.\n console.warn('[observ] RUM setup failed; tracing/replay/events degraded.', err)\n }\n}\n\n/**\n * Stop replay capture (flushing the residual chunk), the semantic-event tap, and\n * tear down OTel tracing + logs. Best-effort and never throws (resolves the\n * story 1.3 \"no public teardown\" deferral). After this, a later {@link init} can\n * re-start the SDK.\n */\nexport async function shutdown(): Promise<void> {\n const recorder = replayRecorder\n const events = semanticEvents\n const errors = jsErrors\n const metricsHandle = metrics\n const uninstallBaggage = baggageUninstall\n replayRecorder = null\n semanticEvents = null\n jsErrors = null\n metrics = null\n baggageUninstall = null\n try {\n uninstallBaggage?.()\n } catch {\n /* swallow — restoring window.fetch must never throw */\n }\n try {\n await recorder?.stop()\n } catch {\n /* swallow — teardown must never throw to the host page */\n }\n try {\n await events?.stop()\n } catch {\n /* swallow */\n }\n try {\n errors?.stop()\n } catch {\n /* swallow */\n }\n try {\n await metricsHandle?.stop()\n } catch {\n /* swallow */\n }\n // Both the semantic-events tap and the JS-error capture share ONE logs\n // provider — shut it down once, here, after both taps have stopped. Each\n // provider shutdown is guarded so a flush rejection can't skip the next one\n // or escape to the host page (shutdown must never throw — 1.3 guarantee).\n try {\n await shutdownOtelLogs()\n } catch {\n /* swallow */\n }\n try {\n await shutdownOtelRum()\n } catch {\n /* swallow */\n }\n}\n\n/** Singleton SDK handle. Usage: `observ.init({ endpoint, key })`. */\nexport const observ: ObservSdk = { init, shutdown }\n\nexport default observ\n"]}
1
+ {"version":3,"sources":["../src/baggage.ts","../src/consent.ts","../src/resource.ts","../src/constants.ts","../src/random-id.ts","../src/session.ts","../src/user.ts","../src/otel-logs.ts","../src/console-forward.ts","../src/js-errors.ts","../src/otel-metrics.ts","../src/otel-rum.ts","../src/history-nav.ts","../src/page-views.ts","../src/privacy.ts","../src/transport.ts","../src/rrweb-record.ts","../src/selector.ts","../src/semantic-events.ts","../src/session-lifecycle.ts","../src/index.ts"],"names":["init","NOOP","active","provider","record","notify","current","handle"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Backend correlation via the W3C **baggage** header (parity story).\n *\n * The fetch/XHR auto-instrumentations already inject `traceparent` on requests to\n * allowed backends; this adds `session.id` to the **baggage** header on those same\n * requests, so the server spans (Strapi / API / KV) can read the session identity\n * and stamp it server-side — making `session.id ⇄ backend span` traversable\n * beyond the `trace_id` link.\n *\n * We wrap `window.fetch` (installed AFTER OTel's fetch instrumentation, so our\n * wrapper is the outermost) and append `session.id` to any existing `baggage`\n * header, but ONLY for URLs matching `backendUrls` — never leaking the id to\n * third parties. Best-effort and reversible (returns an uninstall fn).\n *\n * Gated by the `propagateBaggage` init option; the allowlist defaults to\n * `propagateTraceHeaderCorsUrls` (the same backends that receive `traceparent`).\n */\ntype Matcher = string | RegExp\n\nfunction matches(url: string, matchers: Matcher[]): boolean {\n return matchers.some((m) => (typeof m === 'string' ? url.startsWith(m) : m.test(url)))\n}\n\nfunction resolveUrl(input: RequestInfo | URL): string {\n if (typeof input === 'string') return input\n if (input instanceof URL) return input.href\n return input.url\n}\n\n/** Merge `session.id=<id>` into an existing W3C `baggage` header value. */\nexport function withSessionBaggage(existing: string | null, sessionId: string): string {\n const entry = `session.id=${encodeURIComponent(sessionId)}`\n if (!existing) return entry\n // Don't duplicate if a session.id is already present (e.g. nested wrappers).\n const hasSession = existing.split(',').some((p) => p.trim().startsWith('session.id='))\n return hasSession ? existing : `${existing},${entry}`\n}\n\n/**\n * Install the baggage propagation fetch wrapper. No-op (returns a no-op\n * uninstaller) when there is no `window.fetch`. `getId` is the session-id source\n * ({@link import('./session.js').getSessionId}); `ignoreUrls` excludes the\n * telemetry pipeline itself.\n */\nexport function installBaggagePropagation(\n getId: () => string,\n backendUrls: Matcher[],\n ignoreUrls: Matcher[] = [],\n): () => void {\n if (\n typeof window === 'undefined' ||\n typeof window.fetch !== 'function' ||\n backendUrls.length === 0\n ) {\n return () => {}\n }\n\n const originalFetch = window.fetch.bind(window)\n\n window.fetch = function patchedFetch(input: RequestInfo | URL, init?: RequestInit) {\n let sessionId = ''\n let url = ''\n try {\n sessionId = getId()\n url = resolveUrl(input)\n } catch {\n return originalFetch(input, init)\n }\n\n // Skip non-backend URLs and the telemetry pipeline itself.\n if (!sessionId || !matches(url, backendUrls) || matches(url, ignoreUrls)) {\n return originalFetch(input, init)\n }\n\n try {\n const headers = new Headers(\n init?.headers ?? (input instanceof Request ? input.headers : undefined),\n )\n headers.set('baggage', withSessionBaggage(headers.get('baggage'), sessionId))\n return originalFetch(input, { ...init, headers })\n } catch {\n // Header juggling failed → fall back to an unmodified request.\n return originalFetch(input, init)\n }\n }\n\n return () => {\n window.fetch = originalFetch\n }\n}\n","/**\n * GDPR analytics-consent barrier (Kapitalvins parity).\n *\n * When consent is REQUIRED (opt-in via `requireConsent`), the SDK must not\n * initialise — and therefore emit nothing, create no persistent id — until the\n * visitor has granted analytics consent. Consent is read from a cookie or a\n * `localStorage` key written by the site's consent banner; this module assumes\n * nothing about the banner beyond the stored value.\n *\n * Default (`requireConsent` false): always granted — telemetry is driven solely by\n * the operator's config, preserving the historical behaviour. Leaf module (no SDK\n * imports); reads/writes are guarded — it never throws.\n */\n\n/** Default storage/cookie key the banner is expected to write. */\nconst DEFAULT_KEY = 'observ.consent'\n/** Values that count as \"granted\" (case-insensitive). */\nconst DEFAULT_GRANTED = ['granted', 'true', '1', 'yes', 'all']\n\n/** The subset of init options this module reads (ObservInitOptions satisfies it). */\nexport interface ConsentOptions {\n requireConsent?: boolean\n consentKey?: string\n consentGrantedValues?: string[]\n}\n\nfunction readCookie(key: string): string | undefined {\n if (typeof document === 'undefined' || !document.cookie) return undefined\n for (const part of document.cookie.split(';')) {\n const idx = part.indexOf('=')\n if (idx === -1) continue\n if (part.slice(0, idx).trim() === key) {\n try {\n return decodeURIComponent(part.slice(idx + 1).trim())\n } catch {\n return part.slice(idx + 1).trim()\n }\n }\n }\n return undefined\n}\n\nfunction readStorage(key: string): string | undefined {\n try {\n return globalThis.localStorage?.getItem(key) ?? undefined\n } catch {\n // localStorage can throw (private mode, cookies blocked) — treat as absent.\n return undefined\n }\n}\n\n/** The effective consent key for these options. */\nexport function consentKey(opts: ConsentOptions): string {\n return opts.consentKey || DEFAULT_KEY\n}\n\n/** The value {@link writeConsent} persists when granting programmatically. */\nfunction grantedValue(opts: ConsentOptions): string {\n return opts.consentGrantedValues?.[0] ?? 'granted'\n}\n\n/**\n * True when the SDK is allowed to start. With `requireConsent` off, always true;\n * otherwise the configured cookie is checked first, then `localStorage`.\n */\nexport function hasAnalyticsConsent(opts: ConsentOptions): boolean {\n if (!opts.requireConsent) return true\n const key = consentKey(opts)\n const granted = (opts.consentGrantedValues ?? DEFAULT_GRANTED).map((v) => v.toLowerCase())\n const value = readCookie(key) ?? readStorage(key)\n return value != null && granted.includes(value.toLowerCase())\n}\n\n/** Persist analytics consent to `localStorage` (used by `observ.grantConsent()`). */\nexport function writeConsent(opts: ConsentOptions): void {\n try {\n globalThis.localStorage?.setItem(consentKey(opts), grantedValue(opts))\n } catch {\n /* storage blocked — the in-tab grant still starts the SDK */\n }\n}\n\n/** Remove the stored consent so future inits gate again (used by `revokeConsent()`). */\nexport function clearConsent(opts: ConsentOptions): void {\n try {\n globalThis.localStorage?.removeItem(consentKey(opts))\n } catch {\n /* swallow */\n }\n}\n","/**\n * Shared OTel `Resource` for every RUM signal (traces, logs, metrics).\n *\n * Parity story (epic \"RUM parity\"): the original SDK created its providers with\n * NO resource, so every signal landed under `unknown_service`. This builds a\n * single resource from the public init options + ambient browser facts, applied\n * identically to the trace / log / meter providers so all three carry the same\n * `service.name` and `session`-independent context.\n *\n * `telemetry.sdk.language: 'webjs'` marks the signal as browser-originated (the\n * backend uses it to tell RUM apart from server SDKs).\n */\nimport { resourceFromAttributes, type Resource } from '@opentelemetry/resources'\nimport { ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION } from '@opentelemetry/semantic-conventions'\n\nimport type { ObservInitOptions } from './types.js'\n\n/**\n * Build the resource attached to every provider. `service.name` is set only when\n * the host supplies one (otherwise the OTel default `unknown_service` stands, but\n * at least `telemetry.sdk.language` flags it as browser RUM). Browser facts are\n * read defensively so the SDK stays no-throw under SSR / no-`navigator`.\n */\nexport function buildResource(options: ObservInitOptions): Resource {\n const attrs: Record<string, string | boolean> = {\n 'telemetry.sdk.language': 'webjs',\n }\n if (options.serviceName) attrs[ATTR_SERVICE_NAME] = options.serviceName\n if (options.serviceVersion) attrs[ATTR_SERVICE_VERSION] = options.serviceVersion\n if (options.environment) attrs['deployment.environment.name'] = options.environment\n\n try {\n if (typeof navigator !== 'undefined') {\n if (navigator.language) attrs['browser.language'] = navigator.language\n attrs['browser.mobile'] = /Mobi|Android/i.test(navigator.userAgent || '')\n }\n } catch {\n /* swallow — resource enrichment must never break init */\n }\n\n return resourceFromAttributes(attrs)\n}\n","/**\n * Cross-cutting constants for the Observ RUM SDK.\n *\n * Kept in a leaf module (no SDK imports beyond semconv constants) so both the\n * public entry point (`index.ts`) and internal modules (`otel-rum.ts`) can share\n * them without a circular import.\n */\nimport { ATTR_SESSION_ID } from '@opentelemetry/semantic-conventions/incubating'\n\n/**\n * Attribute key used everywhere to correlate signals of a single session.\n * Sourced from the pinned `@opentelemetry/semantic-conventions` (incubating\n * `ATTR_SESSION_ID`) rather than a hand-typed literal, so the key tracks the\n * standard. Enforcement rule (architecture): the OTel session attribute is\n * EXACTLY `session.id` — never `sessionId` nor `session_id`. Single source of\n * truth so every signal (spans, semantic events, rrweb) stamps the identical key.\n * A test asserts `=== 'session.id'` to guard that invariant across semconv bumps.\n */\nexport const SESSION_ID_ATTRIBUTE: 'session.id' = ATTR_SESSION_ID\n","/**\n * UUID v4 generation, shared by the session id ({@link ./session.js}) and the\n * pseudonymous end-user id ({@link ./user.js}).\n *\n * Leaf module (no SDK imports) so any module can use it without a cycle. Prefers\n * Web Crypto, degrades gracefully, and NEVER throws — the SDK must never break the\n * host page, so a missing/insecure `crypto` falls through to a weaker source\n * rather than escaping.\n */\n\n/** Build a UUID v4, preferring crypto; falls back gracefully (documented). */\nexport function generateUuid(): string {\n const c: Crypto | undefined = globalThis.crypto\n // `crypto.randomUUID` requires a secure context (https or localhost). Detection\n // tests presence, not callability — guard the call so a throwing implementation\n // falls through instead of escaping (the module must never throw).\n if (c && typeof c.randomUUID === 'function') {\n try {\n return c.randomUUID()\n } catch {\n // fall through to getRandomValues\n }\n }\n if (c && typeof c.getRandomValues === 'function') {\n const bytes = c.getRandomValues(new Uint8Array(16))\n bytes[6] = ((bytes[6] ?? 0) & 0x0f) | 0x40 // version 4\n bytes[8] = ((bytes[8] ?? 0) & 0x3f) | 0x80 // variant 10\n const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join('')\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`\n }\n // Last-resort, non-crypto fallback (SSR / no Web Crypto). Not cryptographically\n // strong — acceptable only because no real entropy source exists here.\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (ch) => {\n const r = (Math.random() * 16) | 0\n const v = ch === 'x' ? r : (r & 0x3) | 0x8\n return v.toString(16)\n })\n}\n","/**\n * Session lifecycle for the Observ RUM SDK (FR-1).\n *\n * Produces a single, stable `session.id` per visit and exposes it INTERNALLY as\n * the one source of truth that later modules (`rrweb-record`, `semantic-events`,\n * `otel-rum`) stamp onto every signal. Not part of the public `observ` surface.\n *\n * Authoritative rules (architecture D5):\n * - `session.id` is a UUID v4, generated in the browser,\n * - persisted in `sessionStorage` (per-tab — two tabs are two visits, by design;\n * opt into cross-tab sharing via {@link configureSession} `crossTab`),\n * - rotated after 30 min of inactivity OR a 4 h hard duration cap,\n * - on rotation a fresh id is minted and chained to the prior one via\n * `previousId`, so the backend can stitch consecutive sessions of one visit.\n *\n * Rotation is LAZY: there is no background timer in THIS module — the window is\n * evaluated on the next `ensureSession`/`getSessionId`/`touchSession` call, and a\n * fresh id is minted then if a window has elapsed. The active-session sweep timer,\n * the `session.start`/`session.end` event emission and the activity listeners live\n * in `session-lifecycle.ts`, which subscribes via {@link addSessionListener}.\n *\n * This module performs NO network I/O. It must never throw: if `sessionStorage`/\n * `localStorage` or `crypto` are unavailable (private mode, disabled storage,\n * SSR / insecure context), it degrades to an in-memory session.id. NOTE: in that\n * degraded mode persistence is lost across full page loads, so each navigation\n * starts a new session (the per-visit guarantee holds only while storage works).\n */\nimport { generateUuid } from './random-id.js'\n\n/** Single storage key holding the serialized session state. */\nexport const SESSION_STORAGE_KEY = 'observ.rum.session'\n\n/**\n * Default inactivity window after which a new `session.id` is minted (architecture\n * D5, resolves PRD Open Q2). 30 minutes, in milliseconds. Overridable per app via\n * {@link configureSession}.\n */\nexport const SESSION_INACTIVITY_TIMEOUT_MS = 30 * 60 * 1000\n\n/**\n * Default hard cap on a single session's total duration, regardless of activity\n * (parity with the Kapitalvins reference). 4 hours, in milliseconds. A session\n * older than this rotates even under continuous use, bounding how long one id can\n * follow a visitor. Overridable via {@link configureSession}.\n */\nexport const SESSION_MAX_DURATION_MS = 4 * 60 * 60 * 1000\n\n/** Shape persisted under {@link SESSION_STORAGE_KEY}. Timestamps are epoch ms. */\ninterface PersistedSession {\n id: string\n startedAt: number\n lastActivityAt: number\n /** Id of the session this one replaced, set on every rotation (chaining). */\n previousId?: string\n /** Epoch ms at which a `session.end` was already emitted for this id (so the\n * sweep/pagehide end and the rotation end are never emitted twice). */\n endedAt?: number\n}\n\n/**\n * One session lifecycle transition, published to subscribers of\n * {@link addSessionListener}. `start` fires when a fresh id is minted (first visit\n * or a rotation); `end` fires once per session, when it expires (rotation,\n * inactivity sweep, or pagehide).\n */\nexport type SessionLifecycleEvent =\n | { type: 'start'; id: string; previousId?: string }\n | { type: 'end'; id: string; durationMs: number }\n\n/**\n * In-memory memoization. Within a single page it is the source of truth (one\n * `init` per SPA load); it is also the sole fallback when storage is unusable.\n */\nlet current: PersistedSession | null = null\n\n/** Effective windows + storage backend, mutable via {@link configureSession}. */\nlet inactivityTimeoutMs = SESSION_INACTIVITY_TIMEOUT_MS\nlet maxDurationMs = SESSION_MAX_DURATION_MS\nlet storageMode: 'session' | 'local' = 'session'\n\n/** Lifecycle subscribers (see {@link addSessionListener}). */\nconst listeners = new Set<(event: SessionLifecycleEvent) => void>()\n\n/**\n * Tune the session windows and storage scope. Called once by `init` from the\n * public options; no-op for any field left undefined. `crossTab: true` switches\n * the backing store from `sessionStorage` (per-tab, the default) to\n * `localStorage`, letting the same visitor's tabs share one session — opt-in, so\n * the historical per-tab model is preserved unless explicitly requested.\n */\nexport function configureSession(opts: {\n inactivityTimeoutMs?: number\n maxDurationMs?: number\n crossTab?: boolean\n}): void {\n if (typeof opts.inactivityTimeoutMs === 'number' && opts.inactivityTimeoutMs > 0) {\n inactivityTimeoutMs = opts.inactivityTimeoutMs\n }\n if (typeof opts.maxDurationMs === 'number' && opts.maxDurationMs > 0) {\n maxDurationMs = opts.maxDurationMs\n }\n if (typeof opts.crossTab === 'boolean') {\n storageMode = opts.crossTab ? 'local' : 'session'\n }\n}\n\n/**\n * Subscribe to session lifecycle transitions. Returns an unsubscribe fn. Listeners\n * are invoked synchronously inside `ensureSession`/`endSessionIfExpired`; each call\n * is guarded so a throwing subscriber can never break session resolution.\n */\nexport function addSessionListener(fn: (event: SessionLifecycleEvent) => void): () => void {\n listeners.add(fn)\n return () => {\n listeners.delete(fn)\n }\n}\n\nfunction notify(event: SessionLifecycleEvent): void {\n for (const fn of listeners) {\n try {\n fn(event)\n } catch {\n /* swallow — a subscriber must never break session resolution */\n }\n }\n}\n\n/** The active storage backend (per-tab by default, shared when `crossTab`). */\nfunction backend(): Storage | undefined {\n try {\n return storageMode === 'local' ? globalThis.localStorage : globalThis.sessionStorage\n } catch {\n return undefined\n }\n}\n\n/** Read from the active storage, swallowing any access error. */\nfunction safeRead(): string | null {\n try {\n return backend()?.getItem(SESSION_STORAGE_KEY) ?? null\n } catch {\n return null\n }\n}\n\n/** Write to the active storage, swallowing any access/quota error. */\nfunction safeWrite(value: string): void {\n try {\n backend()?.setItem(SESSION_STORAGE_KEY, value)\n } catch {\n // In-memory `current` stays authoritative; nothing else to do.\n }\n}\n\n/** Validate the parsed storage payload before trusting it. */\nfunction isPersistedSession(value: unknown): value is PersistedSession {\n if (typeof value !== 'object' || value === null) return false\n const v = value as Record<string, unknown>\n return (\n typeof v.id === 'string' &&\n v.id.length > 0 &&\n typeof v.startedAt === 'number' &&\n Number.isFinite(v.startedAt) &&\n typeof v.lastActivityAt === 'number' &&\n Number.isFinite(v.lastActivityAt)\n )\n}\n\n/** Resolve the current session, from memory first, then storage. */\nfunction load(): PersistedSession | null {\n if (current) return current\n const raw = safeRead()\n if (raw === null) return null\n try {\n const parsed: unknown = JSON.parse(raw)\n return isPersistedSession(parsed) ? parsed : null\n } catch {\n return null // corrupt JSON → treat as absent\n }\n}\n\n/** Memoize in memory and best-effort persist to storage. */\nfunction save(session: PersistedSession): void {\n current = session\n safeWrite(JSON.stringify(session))\n}\n\n/**\n * True when `session` has crossed the inactivity window OR the hard duration cap.\n * Both deltas are clamped to 0 so a backward clock jump (now < a stored timestamp,\n * e.g. NTP/DST) can't yield a negative \"elapsed\" that silently extends OR\n * prematurely expires the session.\n */\nexport function isExpired(session: PersistedSession | null, now: number): boolean {\n if (!session) return true\n const inactiveFor = Math.max(0, now - session.lastActivityAt)\n const ageFor = Math.max(0, now - session.startedAt)\n return inactiveFor > inactivityTimeoutMs || ageFor > maxDurationMs\n}\n\n/**\n * Ensure a `session.id` exists for this visit and return it.\n *\n * Reuses the stored id when still within both windows (refreshing\n * `lastActivityAt`); otherwise ends the expiring session (unless a `session.end`\n * was already emitted by the sweep) and mints a fresh, chained session — emitting\n * `start`/`end` to subscribers. `now` is injectable for deterministic tests.\n */\nexport function ensureSession(now: number = Date.now()): string {\n const existing = load()\n if (existing && !isExpired(existing, now)) {\n save({ ...existing, lastActivityAt: now })\n return existing.id\n }\n // Expired (or none) → mint a fresh session chained to the previous one.\n if (existing && existing.endedAt == null) {\n notify({ type: 'end', id: existing.id, durationMs: Math.max(0, now - existing.startedAt) })\n }\n const fresh: PersistedSession = {\n id: generateUuid(),\n startedAt: now,\n lastActivityAt: now,\n ...(existing ? { previousId: existing.id } : {}),\n }\n save(fresh)\n notify({ type: 'start', id: fresh.id, ...(existing ? { previousId: existing.id } : {}) })\n return fresh.id\n}\n\n/**\n * Return the `session.id` for the current visit.\n *\n * Delegates to {@link ensureSession} so every read enforces both windows\n * (rotating to a fresh id once a window has elapsed) — a memoized read must not be\n * able to hand back a session that should have rotated. As a consequence a read\n * also refreshes `lastActivityAt`, i.e. reading the id counts as activity.\n */\nexport function getSessionId(now: number = Date.now()): string {\n return ensureSession(now)\n}\n\n/**\n * Push the inactivity window forward on real activity (rotating, and emitting\n * `end`/`start`, if the session has already expired). The activity listeners in\n * `session-lifecycle.ts` call this; reads also count as activity via\n * {@link ensureSession}.\n */\nexport function touchSession(now: number = Date.now()): void {\n ensureSession(now)\n}\n\n/**\n * Emit `session.end` for the active session IFF it has expired and no end was\n * emitted yet, marking it ended so neither the next rotation nor a later\n * sweep/pagehide re-emits it. Used by the lifecycle sweep timer + pagehide hook so\n * a session that simply goes idle (no further activity to trigger a lazy rotation)\n * still produces a timely `session.end`. Does NOT rotate — the next activity does.\n */\nexport function endSessionIfExpired(now: number = Date.now()): void {\n const session = load()\n if (!session || session.endedAt != null || !isExpired(session, now)) return\n save({ ...session, endedAt: now })\n notify({ type: 'end', id: session.id, durationMs: Math.max(0, now - session.startedAt) })\n}\n\n/**\n * Re-read the persisted session from storage into memory, bypassing the in-memory\n * memo. Used by the cross-tab `storage`-event handler so this tab adopts the\n * session another tab just wrote (only meaningful when `crossTab` is enabled).\n */\nexport function adoptStoredSession(): void {\n const raw = safeRead()\n if (raw === null) return\n try {\n const parsed: unknown = JSON.parse(raw)\n if (isPersistedSession(parsed)) current = parsed\n } catch {\n /* corrupt cross-tab write → keep our own state */\n }\n}\n\n/**\n * @internal Test-only. Clears the in-memory memoization to simulate a fresh page\n * load / module re-import (storage is left untouched), drops all lifecycle\n * subscribers, and restores the default windows / per-tab storage so config from\n * one test can't leak into the next.\n */\nexport function resetSessionState(): void {\n current = null\n listeners.clear()\n inactivityTimeoutMs = SESSION_INACTIVITY_TIMEOUT_MS\n maxDurationMs = SESSION_MAX_DURATION_MS\n storageMode = 'session'\n}\n","/**\n * End-user identity for the Observ RUM SDK (Kapitalvins parity).\n *\n * Two complementary identifiers, stamped onto every signal (spans by\n * {@link import('./otel-rum.js').UserAttributeSpanProcessor}, logs by\n * {@link import('./otel-logs.js').emitSessionEvent}) so RUM is filterable per user:\n *\n * - `enduser.pseudo.id` — a stable, pseudonymous browser id minted on first\n * visit and persisted in `localStorage`. Present even for anonymous visitors;\n * it ties a visitor's sessions together WITHOUT carrying authenticated PII.\n * Opt out entirely via {@link configureUser} `disablePseudoUser`.\n * - `enduser.id` (+ optional `enduser.role` / `enduser.name`) — the AUTHENTICATED\n * identity. Absent until the host calls {@link setUser} after sign-in; cleared\n * by {@link clearUser} on sign-out.\n *\n * Leaf module: no SDK imports beyond {@link ./random-id.js}, so both the span and\n * log paths can read it without a cycle. Reads/writes are guarded — it never\n * throws, degrading to an in-memory pseudo id when `localStorage` is unusable.\n */\nimport { generateUuid } from './random-id.js'\n\n/** Attribute keys (OTel `enduser.*` convention, matching the Kapitalvins SDK). */\nconst ATTR_ENDUSER_ID = 'enduser.id'\nconst ATTR_ENDUSER_ROLE = 'enduser.role'\nconst ATTR_ENDUSER_NAME = 'enduser.name'\nconst ATTR_ENDUSER_PSEUDO_ID = 'enduser.pseudo.id'\n\n/** `localStorage` key holding the persistent pseudonymous id (cross-visit). */\nexport const PSEUDO_USER_STORAGE_KEY = 'observ.rum.pseudo'\n\n/**\n * Authenticated end-user identity passed to {@link setUser}. `id` is required; the\n * label/role are optional. Numbers are accepted for `id` and stringified.\n */\nexport interface ObservUser {\n /** Stable application user id → `enduser.id`. */\n id: string | number\n /** Optional role/permission tag → `enduser.role`. */\n role?: string\n /** Optional display name → `enduser.name` (avoid storing raw PII if sensitive). */\n name?: string\n}\n\n/** The authenticated user, or `null` while anonymous. */\nlet currentUser: ObservUser | null = null\n/** Whether the pseudonymous id is enabled (default on). */\nlet pseudoEnabled = true\n/** In-memory cache of the pseudo id (also the fallback when storage is unusable). */\nlet pseudoId: string | undefined\n\n/** Tune the user layer. Called once by `init`; no-op for undefined fields. */\nexport function configureUser(opts: { disablePseudoUser?: boolean }): void {\n if (typeof opts.disablePseudoUser === 'boolean') {\n pseudoEnabled = !opts.disablePseudoUser\n }\n}\n\n/** Attach the authenticated user to all subsequent telemetry. */\nexport function setUser(user: ObservUser): void {\n currentUser = user\n}\n\n/** Clear the authenticated identity (call on sign-out). The pseudo id persists. */\nexport function clearUser(): void {\n currentUser = null\n}\n\n/** The current authenticated user, or `null`. */\nexport function getUser(): ObservUser | null {\n return currentUser\n}\n\n/**\n * Resolve the persistent pseudonymous id, creating + persisting one on first use.\n * Returns `undefined` when disabled. Never throws: a blocked `localStorage`\n * (private mode / quota) degrades to an in-memory id that lasts the page's life.\n */\nexport function getPseudoUserId(): string | undefined {\n if (!pseudoEnabled) return undefined\n if (pseudoId) return pseudoId\n try {\n const existing = globalThis.localStorage?.getItem(PSEUDO_USER_STORAGE_KEY)\n if (existing) {\n pseudoId = existing\n return pseudoId\n }\n } catch {\n /* storage blocked → mint an in-memory id below */\n }\n pseudoId = generateUuid()\n try {\n globalThis.localStorage?.setItem(PSEUDO_USER_STORAGE_KEY, pseudoId)\n } catch {\n /* in-memory `pseudoId` stays authoritative */\n }\n return pseudoId\n}\n\n/**\n * The end-user attributes to stamp on a signal: the pseudo id (when enabled) plus\n * the authenticated `enduser.id` (+ role/name) once {@link setUser} was called.\n * Returns a fresh object each call so callers can spread it safely.\n */\nexport function userAttributes(): Record<string, string> {\n const attrs: Record<string, string> = {}\n const pseudo = getPseudoUserId()\n if (pseudo) attrs[ATTR_ENDUSER_PSEUDO_ID] = pseudo\n if (currentUser) {\n attrs[ATTR_ENDUSER_ID] = String(currentUser.id)\n if (currentUser.role) attrs[ATTR_ENDUSER_ROLE] = currentUser.role\n if (currentUser.name) attrs[ATTR_ENDUSER_NAME] = currentUser.name\n }\n return attrs\n}\n\n/**\n * Stamp the end-user attributes via a `setAttribute(key, value)` sink (used by the\n * span processor). Guarded so a throwing sink can never break a host request.\n */\nexport function applyUserAttributes(setAttribute: (key: string, value: string) => void): void {\n try {\n for (const [key, value] of Object.entries(userAttributes())) {\n setAttribute(key, value)\n }\n } catch {\n /* swallow — never let user stamping break a host span */\n }\n}\n\n/**\n * @internal Test-only. Clears the authenticated user + the in-memory pseudo cache\n * and restores the default (pseudo enabled), so config from one test can't leak.\n */\nexport function resetUserState(): void {\n currentUser = null\n pseudoId = undefined\n pseudoEnabled = true\n}\n","/**\n * OpenTelemetry Logs pipeline for the Observ RUM SDK (story 2.3).\n *\n * Semantic events (`observ.session.*`) are emitted as OTel **log records** and\n * exported over OTLP/HTTP to `{endpoint}/v1/logs` (received by the backend since\n * story 1.4; the session-assembly writer taps them in 1.6). This is the mirror\n * of the trace pipeline in `otel-rum.ts`, on a dedicated, separate provider —\n * the light \"logs\" channel, never the heavy `/v1/replay` channel.\n *\n * `session.id` is stamped once, at emit time, by {@link emitSessionEvent} — the\n * single point through which every semantic event flows (so a separate\n * `LogRecordProcessor` would be redundant; this also keeps the SDK's\n * sdk-logs API surface minimal).\n */\nimport type { Logger } from '@opentelemetry/api-logs'\nimport { OTLPLogExporter } from '@opentelemetry/exporter-logs-otlp-http'\nimport { BatchLogRecordProcessor, LoggerProvider } from '@opentelemetry/sdk-logs'\n\nimport { buildResource } from './resource.js'\nimport { SESSION_ID_ATTRIBUTE } from './constants.js'\nimport { getSessionId } from './session.js'\nimport { userAttributes } from './user.js'\nimport type { ObservInitOptions } from './types.js'\n\n/**\n * Join an endpoint base URL with the OTLP/HTTP logs path. Mirror of\n * {@link import('./otel-rum.js').buildTracesUrl}: preserves a path prefix, never\n * doubles a trailing slash, drops query/fragment; relative/empty → same-origin.\n */\nexport function buildLogsUrl(endpoint: string): string {\n try {\n const url = new URL(endpoint)\n url.pathname = `${url.pathname.replace(/\\/+$/, '')}/v1/logs`\n url.search = ''\n url.hash = ''\n return url.toString()\n } catch {\n return `${endpoint.replace(/\\/+$/, '')}/v1/logs`\n }\n}\n\nlet provider: LoggerProvider | null = null\nlet activeLogger: Logger | null = null\n\n/**\n * Wire up the OTel Logs provider and return a `Logger`. Idempotent: a second\n * call returns the already-active logger (first init wins, mirrors\n * `setupOtelRum`). The `x-observ-key` header is omitted when the key is empty\n * (the trace setup already warns about a missing key).\n */\nexport function setupOtelLogs(options: ObservInitOptions): Logger {\n if (activeLogger) return activeLogger\n\n const headers: Record<string, string> = {}\n if (options.key) headers['x-observ-key'] = options.key\n\n const exporter = new OTLPLogExporter({ url: buildLogsUrl(options.endpoint), headers })\n const p = new LoggerProvider({\n resource: buildResource(options),\n processors: [new BatchLogRecordProcessor(exporter)],\n })\n\n try {\n const logger = p.getLogger('@observtech/rum')\n // Commit the module state ONLY once everything succeeded — otherwise a\n // partial init would leak the provider's flush timer and latch the guard.\n provider = p\n activeLogger = logger\n return logger\n } catch (err) {\n // Roll back a partial init (mirrors otel-rum.ts): shut the provider down so\n // its BatchLogRecordProcessor timer can't outlive the failure, and leave the\n // guards null so a later setup can retry.\n void p.shutdown()\n throw err\n }\n}\n\n/** Inactivity refresh throttle for the cached session id (story 1.2 — avoid a\n * synchronous sessionStorage write on every event). */\nconst SESSION_ID_REFRESH_MS = 1_000\nlet cachedSessionId = ''\nlet cachedSessionIdAt = 0\n\n/**\n * Resolve the visit `session.id`, refreshing it (and the session's inactivity\n * window) at most once per second. A click burst therefore costs ≤ 1\n * `getSessionId` (→ ≤ 1 sessionStorage write) per second instead of one per\n * event, while still counting interaction as session activity.\n */\nfunction currentSessionId(): string {\n const now = Date.now()\n if (!cachedSessionId || now - cachedSessionIdAt >= SESSION_ID_REFRESH_MS) {\n cachedSessionId = getSessionId()\n cachedSessionIdAt = now\n }\n return cachedSessionId\n}\n\n/**\n * Drop the throttled `session.id` cache so the next {@link emitSessionEvent}\n * re-reads it. Called by the session lifecycle the instant a rotation mints a new\n * id, so events emitted within the throttle window after a rotation carry the new\n * id rather than the stale cached one.\n */\nexport function resetSessionIdCache(): void {\n cachedSessionId = ''\n cachedSessionIdAt = 0\n}\n\n/**\n * Emit one semantic event as an OTel log record: `event.name` in the\n * `observ.session.*` namespace + the exact `session.id` correlation attribute\n * (throttled refresh, so an event read also counts as session activity, 1.2) +\n * the end-user identity (`enduser.pseudo.id` / `enduser.id`) + the caller's\n * attributes (which win on key collisions, e.g. lifecycle events passing an\n * explicit `session.id`). Best-effort: never throws to the host page.\n */\nexport function emitSessionEvent(\n logger: Logger,\n eventName: string,\n attrs: Record<string, string> = {},\n): void {\n try {\n logger.emit({\n attributes: {\n 'event.name': eventName,\n [SESSION_ID_ATTRIBUTE]: currentSessionId(),\n ...userAttributes(),\n ...attrs,\n },\n })\n } catch (err) {\n console.warn('[observ] semantic event emit failed', err)\n }\n}\n\n/**\n * Emit a free-form log record (severity + body), as opposed to a named semantic\n * event. Used by the `console.*` forwarder: it carries the visit `session.id` +\n * end-user identity but NO `event.name`. Critically, its failure path swallows\n * silently — it must NEVER call `console.*` (the caller may have patched console,\n * which would recurse).\n */\nexport function emitLogRecord(\n logger: Logger,\n severityNumber: number,\n severityText: string,\n body: string,\n): void {\n try {\n logger.emit({\n severityNumber,\n severityText,\n body,\n attributes: {\n [SESSION_ID_ATTRIBUTE]: currentSessionId(),\n ...userAttributes(),\n },\n })\n } catch {\n /* swallow silently — never console.* here (the forwarder patched console) */\n }\n}\n\n/**\n * @internal Flush + shut the logs provider down and reset the idempotence guard\n * so a later setup can re-init. Called by the SDK teardown.\n */\nexport async function shutdownOtelLogs(): Promise<void> {\n const p = provider\n provider = null\n activeLogger = null\n await p?.shutdown()\n}\n\n/** @internal Test-only: the active logger, or `null` when logs are not set up. */\nexport function getActiveLogger(): Logger | null {\n return activeLogger\n}\n","/**\n * `console.*` forwarding to the OTLP logs pipeline (Kapitalvins parity).\n *\n * When enabled, wraps the chosen `console` methods so each call ALSO emits an OTel\n * log record (carrying `session.id` + end-user identity, severity-mapped) before\n * delegating to the original console — the page's own console output is never\n * suppressed, only mirrored.\n *\n * Opt-in (`forwardConsole`), because console output can be noisy and may contain\n * PII the host didn't intend to ship; the SDK stays quiet by default. Invariant\n * (1.1/1.2/1.3): never break the host page. Each wrapper is `try/catch`-guarded\n * and re-entrancy-guarded (so emitting a record can't recurse back through a\n * patched console), and the originals are restored on `stop()`.\n */\nimport type { Logger } from '@opentelemetry/api-logs'\nimport { SeverityNumber } from '@opentelemetry/api-logs'\n\nimport { emitLogRecord, setupOtelLogs } from './otel-logs.js'\nimport type { ObservInitOptions } from './types.js'\n\n/** Console methods we can forward, in increasing severity. */\nexport type ConsoleLevel = 'debug' | 'log' | 'info' | 'warn' | 'error'\n\n/** Console level → OTel severity (number + canonical text). */\nconst LEVELS: Record<ConsoleLevel, { number: SeverityNumber; text: string }> = {\n debug: { number: SeverityNumber.DEBUG, text: 'DEBUG' },\n log: { number: SeverityNumber.INFO, text: 'INFO' },\n info: { number: SeverityNumber.INFO, text: 'INFO' },\n warn: { number: SeverityNumber.WARN, text: 'WARN' },\n error: { number: SeverityNumber.ERROR, text: 'ERROR' },\n}\n\nconst ALL_LEVELS = Object.keys(LEVELS) as ConsoleLevel[]\n/** Bound on a forwarded record's body so one giant log can't bloat the channel. */\nconst MAX_BODY = 4_096\n\n/** Public handle for the running console forwarder. */\nexport interface ConsoleForwardHandle {\n /** Restore the original console methods. Idempotent. */\n stop(): void\n}\n\nconst NOOP: ConsoleForwardHandle = { stop: () => {} }\n\n/** Module-level guard so the forwarder is self-idempotent (one patch per page). */\nlet active: ConsoleForwardHandle | null = null\n\n/** Resolve the levels to forward from the option (true ⇒ all; array ⇒ as given). */\nfunction resolveLevels(forwardConsole: ObservInitOptions['forwardConsole']): ConsoleLevel[] {\n if (forwardConsole === true) return ALL_LEVELS\n if (Array.isArray(forwardConsole)) return forwardConsole.filter((l) => l in LEVELS)\n return []\n}\n\n/** Render one console argument to a string (Error → `name: message`, object → JSON). */\nfunction formatArg(arg: unknown): string {\n if (arg instanceof Error) return `${arg.name}: ${arg.message}`\n if (typeof arg === 'object' && arg !== null) {\n try {\n return JSON.stringify(arg) ?? String(arg)\n } catch {\n return String(arg)\n }\n }\n return String(arg)\n}\n\nfunction formatBody(args: unknown[]): string {\n const body = args.map(formatArg).join(' ')\n return body.length > MAX_BODY ? body.slice(0, MAX_BODY) : body\n}\n\n/**\n * Start forwarding the configured `console.*` methods to the logs channel. Returns\n * a handle whose `stop()` restores the originals. Never throws; degrades to a\n * no-op when `forwardConsole` is unset/empty, when `console` is unavailable, or\n * when the logs channel fails to set up.\n */\nexport function startConsoleForward(options: ObservInitOptions): ConsoleForwardHandle {\n if (active) return active\n const levels = resolveLevels(options.forwardConsole)\n if (levels.length === 0 || typeof console === 'undefined') return NOOP\n\n let logger: Logger\n try {\n logger = setupOtelLogs(options) // shared, idempotent — same logger as 2.3/2.4\n } catch {\n return NOOP\n }\n\n // Re-entrancy guard: while we synchronously emit a record, a nested console call\n // (e.g. from deep inside the SDK) must not forward again.\n let emitting = false\n const originals = new Map<ConsoleLevel, (...args: unknown[]) => void>()\n\n for (const level of levels) {\n const original = console[level] as ((...args: unknown[]) => void) | undefined\n if (typeof original !== 'function') continue\n originals.set(level, original)\n const { number, text } = LEVELS[level]\n console[level] = (...args: unknown[]): void => {\n if (!emitting) {\n emitting = true\n try {\n emitLogRecord(logger, number, text, formatBody(args))\n } catch {\n /* swallow — never let forwarding break a console call */\n } finally {\n emitting = false\n }\n }\n original.apply(console, args)\n }\n }\n\n let stopped = false\n const handle: ConsoleForwardHandle = {\n stop(): void {\n if (stopped) return\n stopped = true\n active = null\n for (const [level, original] of originals) {\n console[level] = original\n }\n originals.clear()\n },\n }\n active = handle\n return handle\n}\n","/**\n * JS error capture for the Observ RUM SDK (FR-9, story 2.4).\n *\n * Captures uncaught errors (`window` `error`) and unhandled promise rejections\n * (`unhandledrejection`) and emits them as OTel log records\n * (`observ.session.js_error`) on the SAME logs channel as the semantic events\n * (story 2.3): standard exception semconv attributes + `session.id`. The stack\n * trace is carried as a log/event attribute — never a metric (architecture\n * enforcement).\n *\n * Invariant (1.1/1.2/1.3): never break the host page. Handlers run when the\n * browser is already handling an error, so each is `try/catch`-guarded and we\n * NEVER `preventDefault()` — the site's own error flow (console, other handlers)\n * is left untouched; we only observe.\n */\nimport type { Logger } from '@opentelemetry/api-logs'\nimport {\n ATTR_EXCEPTION_MESSAGE,\n ATTR_EXCEPTION_STACKTRACE,\n ATTR_EXCEPTION_TYPE,\n} from '@opentelemetry/semantic-conventions'\n\nimport { emitSessionEvent, setupOtelLogs } from './otel-logs.js'\nimport type { ObservInitOptions } from './types.js'\n\n/** Max `js_error` events per rolling window — bounds an error storm (AC#5)\n * without going permanently blind: the window resets, so capture self-heals. */\nexport const MAX_JS_ERRORS = 50\n/** Rolling window (ms) for the {@link MAX_JS_ERRORS} rate limit. */\nexport const RATE_WINDOW_MS = 60_000\n/** Truncation bounds so one error can't produce a huge log record. */\nconst MAX_MESSAGE = 1_024\nconst MAX_STACK = 4_096\n\n/** Best-effort string for a rejection reason: Error→message handled by the\n * caller; objects → JSON (so `{code:500}` isn't flattened to \"[object Object]\");\n * everything else → `String`. */\nfunction reasonToMessage(reason: unknown): string {\n if (typeof reason === 'string') return reason\n if (typeof reason === 'object' && reason !== null) {\n try {\n return JSON.stringify(reason) ?? String(reason)\n } catch {\n return String(reason)\n }\n }\n return String(reason)\n}\n\n/** Public handle for the running JS-error capture. */\nexport interface JsErrorHandle {\n /** Remove the global error listeners. Idempotent. The shared logs provider is\n * shut down by `index.shutdown()`, NOT here (two taps share it). */\n stop(): void\n}\n\nconst NOOP: JsErrorHandle = { stop: () => {} }\n\n/** Module-level guard so the capture is self-idempotent. */\nlet active: JsErrorHandle | null = null\n\nfunction truncate(s: string, max: number): string {\n return s.length > max ? s.slice(0, max) : s\n}\n\n/**\n * Start capturing uncaught JS errors + unhandled rejections. Returns a handle\n * whose `stop()` removes the listeners. Never throws; no-op in a non-DOM env.\n * Not gated by `disableReplay` — errors are useful even without replay.\n */\nexport function startJsErrorCapture(options: ObservInitOptions): JsErrorHandle {\n if (active) return active\n if (typeof window === 'undefined') return NOOP\n\n let logger: Logger\n try {\n logger = setupOtelLogs(options) // shared, idempotent — same logger as 2.3\n } catch (err) {\n console.warn('[observ] js-errors: logs setup failed', err)\n return NOOP\n }\n\n // Sliding-window rate limit: at most MAX_JS_ERRORS per RATE_WINDOW_MS. Resets\n // each window so a burst at boot doesn't blind capture for the rest of a long\n // SPA session.\n let windowStart = 0\n let inWindow = 0\n\n const emit = (type: string | undefined, message: string, stack: string | undefined): void => {\n const now = Date.now()\n if (now - windowStart >= RATE_WINDOW_MS) {\n windowStart = now\n inWindow = 0\n }\n if (inWindow >= MAX_JS_ERRORS) return // anti-flood cap (AC#5)\n inWindow++\n const attrs: Record<string, string> = {\n [ATTR_EXCEPTION_MESSAGE]: truncate(message, MAX_MESSAGE),\n }\n if (type) attrs[ATTR_EXCEPTION_TYPE] = type\n if (stack) attrs[ATTR_EXCEPTION_STACKTRACE] = truncate(stack, MAX_STACK)\n emitSessionEvent(logger, 'observ.session.js_error', attrs)\n }\n\n const onError = (e: ErrorEvent): void => {\n try {\n // `e.error` is the Error in modern browsers; cross-origin \"Script error.\"\n // has `e.error === null`, so fall back to `e.message` with no stack.\n const err = e.error as Error | null | undefined\n emit(err?.name, err?.message ?? e.message ?? 'unknown error', err?.stack ?? undefined)\n } catch {\n /* never let the error handler break the host page */\n }\n }\n\n const onRejection = (e: PromiseRejectionEvent): void => {\n try {\n const reason: unknown = e.reason\n if (reason instanceof Error) {\n emit(reason.name, reason.message, reason.stack ?? undefined)\n } else {\n emit('UnhandledRejection', reasonToMessage(reason), undefined)\n }\n } catch {\n /* swallow — observe, never interfere */\n }\n }\n\n // Do NOT use `window.onerror =` (would clobber a host handler). Never call\n // preventDefault — we observe without suppressing the site's error flow.\n window.addEventListener('error', onError)\n window.addEventListener('unhandledrejection', onRejection)\n\n const handle: JsErrorHandle = {\n stop(): void {\n window.removeEventListener('error', onError)\n window.removeEventListener('unhandledrejection', onRejection)\n active = null\n },\n }\n active = handle\n return handle\n}\n","/**\n * OpenTelemetry Metrics + Core Web Vitals for the Observ RUM SDK (parity story).\n *\n * Net-new \"metrics\" channel — the third OTLP/HTTP signal, exported to\n * `{endpoint}/v1/metrics` on its own `MeterProvider` (the heavy `/v1/replay`\n * channel is never crossed). It captures Core Web Vitals (LCP / INP / CLS / FCP /\n * TTFB) as **histograms** (queryable as metrics) and ALSO mirrors each as an\n * `observ.session.web_vital` **log event** carrying `session.id`, so a single\n * vital appears both on the metrics dashboards and on the session timeline.\n *\n * Gated by `disableMetrics` (default ON). Like the rest of the SDK it is\n * best-effort and never throws to the host page.\n */\nimport { type Meter } from '@opentelemetry/api'\nimport { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-http'\nimport { MeterProvider, PeriodicExportingMetricReader } from '@opentelemetry/sdk-metrics'\nimport { onCLS, onFCP, onINP, onLCP, onTTFB, type Metric } from 'web-vitals'\n\nimport { buildResource } from './resource.js'\nimport { emitSessionEvent, setupOtelLogs } from './otel-logs.js'\nimport type { ObservInitOptions } from './types.js'\n\n/** Export interval for the periodic metric reader (ms). */\nconst METRIC_EXPORT_INTERVAL_MS = 30_000\n\n/** Web-Vital name → histogram spec. CLS is unit-less; the rest are milliseconds. */\nconst VITAL_HISTOGRAMS: Record<string, { name: string; unit: string; description: string }> = {\n LCP: { name: 'web_vitals.lcp', unit: 'ms', description: 'Largest Contentful Paint' },\n INP: { name: 'web_vitals.inp', unit: 'ms', description: 'Interaction to Next Paint' },\n FCP: { name: 'web_vitals.fcp', unit: 'ms', description: 'First Contentful Paint' },\n TTFB: { name: 'web_vitals.ttfb', unit: 'ms', description: 'Time To First Byte' },\n CLS: { name: 'web_vitals.cls', unit: '1', description: 'Cumulative Layout Shift' },\n}\n\n/**\n * Join an endpoint base URL with the OTLP/HTTP metrics path. Mirror of\n * {@link import('./otel-rum.js').buildTracesUrl}.\n */\nexport function buildMetricsUrl(endpoint: string): string {\n try {\n const url = new URL(endpoint)\n url.pathname = `${url.pathname.replace(/\\/+$/, '')}/v1/metrics`\n url.search = ''\n url.hash = ''\n return url.toString()\n } catch {\n return `${endpoint.replace(/\\/+$/, '')}/v1/metrics`\n }\n}\n\nlet provider: MeterProvider | null = null\n\n/** Handle returned by {@link setupOtelMetrics} for teardown. */\nexport interface MetricsHandle {\n meter: Meter\n stop(): Promise<void>\n}\n\n/**\n * Wire up the meter provider + Web-Vitals capture. Idempotent: a second call is a\n * no-op returning the existing handle (first init wins, mirrors `setupOtelLogs`).\n * The `x-observ-key` header is omitted when the key is empty.\n */\nexport function setupOtelMetrics(options: ObservInitOptions): MetricsHandle {\n if (provider) return { meter: provider.getMeter('@observtech/rum'), stop: shutdownOtelMetrics }\n\n const headers: Record<string, string> = {}\n if (options.key) headers['x-observ-key'] = options.key\n\n const reader = new PeriodicExportingMetricReader({\n exporter: new OTLPMetricExporter({ url: buildMetricsUrl(options.endpoint), headers }),\n exportIntervalMillis: METRIC_EXPORT_INTERVAL_MS,\n })\n\n const p = new MeterProvider({ resource: buildResource(options), readers: [reader] })\n const meter = p.getMeter('@observtech/rum')\n\n // Histograms for each Core Web Vital; the logger mirrors them as timeline events.\n const histograms = Object.fromEntries(\n Object.entries(VITAL_HISTOGRAMS).map(([key, h]) => [\n key,\n meter.createHistogram(h.name, { unit: h.unit, description: h.description }),\n ]),\n )\n // Reuse the (idempotent) logs provider so a vital also lands on the session\n // timeline as `observ.session.web_vital`. Never let a logs failure break metrics.\n let logger: ReturnType<typeof setupOtelLogs> | null = null\n try {\n logger = setupOtelLogs(options)\n } catch {\n /* metrics still work without the timeline mirror */\n }\n\n const record = (m: Metric): void => {\n try {\n const path = typeof location !== 'undefined' ? location.pathname : ''\n const dims = {\n 'web_vital.rating': m.rating,\n 'web_vital.navigation_type': m.navigationType,\n 'url.path': path,\n }\n histograms[m.name]?.record(m.value, dims)\n if (logger) {\n emitSessionEvent(logger, 'observ.session.web_vital', {\n 'web_vital.name': m.name,\n 'web_vital.value': String(m.value),\n 'web_vital.id': m.id,\n 'web_vital.rating': m.rating,\n 'web_vital.navigation_type': m.navigationType,\n 'url.path': path,\n })\n }\n } catch {\n /* swallow — a single vital must never break the page */\n }\n }\n\n try {\n onLCP(record)\n onINP(record)\n onFCP(record)\n onTTFB(record)\n onCLS(record)\n } catch {\n /* web-vitals unavailable (e.g. non-browser) — provider still set up */\n }\n\n provider = p\n return { meter, stop: shutdownOtelMetrics }\n}\n\n/**\n * @internal Flush + shut the meter provider down and reset the idempotence guard.\n * Called by the SDK teardown.\n */\nexport async function shutdownOtelMetrics(): Promise<void> {\n const p = provider\n provider = null\n await p?.shutdown()\n}\n\n/** @internal Test-only: the active meter provider, or `null` when metrics are off. */\nexport function getActiveMeterProvider(): MeterProvider | null {\n return provider\n}\n","/**\n * OpenTelemetry RUM wiring for the Observ SDK (FR-4, story 1.3).\n *\n * Sets up a {@link WebTracerProvider} that:\n * - creates `http.client` spans for browser `fetch`/XHR (auto-instrumentation),\n * - stamps every span with the visit's `session.id` (via {@link SessionAttributeSpanProcessor}),\n * - injects the W3C `traceparent` header on outgoing requests (default\n * trace-context propagator; cross-origin gated by `propagateTraceHeaderCorsUrls`),\n * - exports spans over OTLP/HTTP to `{endpoint}/v1/traces` (BatchSpanProcessor).\n *\n * Like the rest of the SDK, this must never throw out to the host page: the\n * caller ({@link import('./index.js')}) wraps {@link setupOtelRum} defensively.\n *\n * NOTE: until the backend OTLP/HTTP receiver lands (story 1.4), exports will fail\n * at the network layer (CORS / 404). That is expected — span creation, attribute\n * stamping and header propagation are fully exercised regardless.\n */\nimport { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http'\nimport { registerInstrumentations, type Instrumentation } from '@opentelemetry/instrumentation'\nimport { DocumentLoadInstrumentation } from '@opentelemetry/instrumentation-document-load'\nimport { FetchInstrumentation } from '@opentelemetry/instrumentation-fetch'\nimport { XMLHttpRequestInstrumentation } from '@opentelemetry/instrumentation-xml-http-request'\nimport {\n AlwaysOnSampler,\n ParentBasedSampler,\n TraceIdRatioBasedSampler,\n type Sampler,\n} from '@opentelemetry/sdk-trace-base'\nimport {\n BatchSpanProcessor,\n WebTracerProvider,\n type ReadableSpan,\n type Span,\n type SpanProcessor,\n} from '@opentelemetry/sdk-trace-web'\n\nimport { buildResource } from './resource.js'\nimport { SESSION_ID_ATTRIBUTE } from './constants.js'\nimport { getSessionId } from './session.js'\nimport { applyUserAttributes } from './user.js'\nimport type { ObservInitOptions } from './types.js'\n\n/**\n * Head sampler from `sampleRate`: a `ParentBasedSampler(TraceIdRatioBased)` for a\n * ratio in `[0, 1)`, else `AlwaysOn` (sample everything — the default).\n */\nexport function buildSampler(options: ObservInitOptions): Sampler {\n const rate = options.sampleRate\n if (typeof rate === 'number' && Number.isFinite(rate) && rate >= 0 && rate < 1) {\n return new ParentBasedSampler({ root: new TraceIdRatioBasedSampler(rate) })\n }\n return new AlwaysOnSampler()\n}\n\n/**\n * URLs the auto-instrumentations must NEVER trace: the telemetry pipeline itself\n * (`{endpoint}/v1/...`). Without this the exporter's own POST gets traced,\n * spawning a self-perpetuating trickle of `http.client` spans.\n */\nexport function telemetryIgnoreUrls(endpoint: string): RegExp[] {\n const escaped = endpoint.replace(/\\/+$/, '').replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n return [new RegExp(`${escaped}/v1/`)]\n}\n\n/**\n * Join an endpoint base URL with the OTLP/HTTP traces path. Uses the `URL` API\n * for absolute endpoints so a path prefix is preserved, a trailing slash never\n * doubles, and any query/fragment (meaningless on the traces endpoint) is\n * dropped — `https://x?a=1` ⇒ `https://x/v1/traces`, not `https://x?a=1/v1/traces`.\n * A relative or empty endpoint falls back to a string join, yielding a\n * same-origin `…/v1/traces` path.\n */\nexport function buildTracesUrl(endpoint: string): string {\n try {\n const url = new URL(endpoint)\n url.pathname = `${url.pathname.replace(/\\/+$/, '')}/v1/traces`\n url.search = ''\n url.hash = ''\n return url.toString()\n } catch {\n return `${endpoint.replace(/\\/+$/, '')}/v1/traces`\n }\n}\n\n/**\n * Span processor whose only job is to stamp `session.id` on every span at start.\n *\n * Using a processor (rather than per-instrumentation `applyCustomAttributesOnSpan`)\n * guarantees ALL spans — fetch, XHR, and any future document-load — carry the\n * attribute through a single code path. It reads the id via {@link getSessionId},\n * which also refreshes the session's inactivity window (story 1.2 decision): a\n * span therefore counts as session activity.\n */\nexport class SessionAttributeSpanProcessor implements SpanProcessor {\n onStart(span: Span): void {\n // onStart runs synchronously inside the host page's own fetch/XHR. The SDK\n // must never throw out to the page, so guard here even though getSessionId()\n // is contractually no-throw: a missing attribute beats a broken host request.\n try {\n span.setAttribute(SESSION_ID_ATTRIBUTE, getSessionId())\n } catch {\n /* swallow — never let span stamping break a host request */\n }\n }\n onEnd(_span: ReadableSpan): void {}\n forceFlush(): Promise<void> {\n return Promise.resolve()\n }\n shutdown(): Promise<void> {\n return Promise.resolve()\n }\n}\n\n/**\n * Span processor that stamps the end-user identity (`enduser.pseudo.id`, and\n * `enduser.id`/role/name once {@link import('./user.js').setUser} was called) on\n * every span at start — the trace mirror of how {@link import('./otel-logs.js')}\n * stamps logs. Kept separate from {@link SessionAttributeSpanProcessor} so each\n * concern stays single-purpose; both run before the batch/export processor.\n */\nexport class UserAttributeSpanProcessor implements SpanProcessor {\n onStart(span: Span): void {\n // Runs synchronously inside the host's fetch/XHR; applyUserAttributes is itself\n // guarded, but a span without enduser attrs beats a broken host request.\n applyUserAttributes((key, value) => span.setAttribute(key, value))\n }\n onEnd(_span: ReadableSpan): void {}\n forceFlush(): Promise<void> {\n return Promise.resolve()\n }\n shutdown(): Promise<void> {\n return Promise.resolve()\n }\n}\n\nlet provider: WebTracerProvider | null = null\nlet disableInstrumentations: (() => void) | null = null\nlet activeConfig: { endpoint: string; key: string } | null = null\n/** Resolves once the opt-in `userInteraction` async setup has attached (or null\n * when not opted in). Test-only readers use {@link getUserInteractionReady}. */\nlet userInteractionReady: Promise<void> | null = null\n\n/**\n * The always-on web auto-instrumentations: page-load timing + fetch/XHR with W3C\n * `traceparent` propagation. Built here (no zone.js) and shared by both the\n * default registration and the opt-in user-interaction path.\n */\nfunction buildBaseInstrumentations(\n options: ObservInitOptions,\n ignoreUrls: RegExp[],\n): Instrumentation[] {\n return [\n // Page-load timing: documentLoad / documentFetch / resourceFetch spans.\n new DocumentLoadInstrumentation(),\n new FetchInstrumentation({\n propagateTraceHeaderCorsUrls: options.propagateTraceHeaderCorsUrls,\n ignoreUrls,\n }),\n new XMLHttpRequestInstrumentation({\n propagateTraceHeaderCorsUrls: options.propagateTraceHeaderCorsUrls,\n ignoreUrls,\n }),\n ]\n}\n\n/**\n * Wire up OTel RUM tracing. Idempotent: a second call is a no-op while a provider\n * is already active (mirrors the single-`init` contract; first call wins). Not\n * defensive on its own — `init` owns the try/catch so a setup failure never\n * escapes to the page — but it cleans up after itself: a partial init (register\n * or instrumentation throwing, e.g. SSR / no `fetch`/XHR) shuts the provider down\n * and resets the guard before rethrowing, so no `WebTracerProvider`\n * (BatchSpanProcessor timer + global registration) leaks and a later retry works.\n */\nexport function setupOtelRum(options: ObservInitOptions): void {\n if (provider) {\n // First init wins. Warn if a later call diverges (key rotation / env switch)\n // so the dropped config isn't silently swallowed by the idempotence guard.\n if (\n activeConfig &&\n (activeConfig.endpoint !== options.endpoint || activeConfig.key !== options.key)\n ) {\n console.warn(\n '[observ] OTel RUM already initialized; ignoring divergent endpoint/key on this init() (first call wins).',\n )\n }\n return\n }\n\n // API-key auth via the custom `x-observ-key` header — the receiver (story 1.4)\n // must decode the same name and list it in `Access-Control-Allow-Headers`. An\n // empty key would produce a malformed credential, so omit the header (and warn)\n // rather than send a blank one.\n const headers: Record<string, string> = {}\n if (options.key) {\n headers['x-observ-key'] = options.key\n } else {\n console.warn('[observ] no API key provided; front-end spans will export unauthenticated.')\n }\n\n const exporter = new OTLPTraceExporter({\n url: buildTracesUrl(options.endpoint),\n headers,\n })\n\n const ignoreUrls = telemetryIgnoreUrls(options.endpoint)\n\n // SDK 2.x: span processors are constructor-only (`addSpanProcessor` was removed).\n // Order matters — stamp `session.id` before the batch processor exports.\n const p = new WebTracerProvider({\n resource: buildResource(options),\n sampler: buildSampler(options),\n spanProcessors: [\n new SessionAttributeSpanProcessor(),\n new UserAttributeSpanProcessor(),\n new BatchSpanProcessor(exporter),\n ],\n })\n\n const base = buildBaseInstrumentations(options, ignoreUrls)\n\n if (options.userInteraction) {\n // Opt-in: user-interaction spans need a ZoneContextManager to keep trace\n // context across the interaction's async work. Both pull in zone.js, which\n // monkey-patches the host's global timers/Promise AT IMPORT — so they live in\n // a separate module loaded ONLY here, via dynamic import, keeping the default\n // bundle (and the host globals) untouched for everyone who doesn't opt in.\n // The provider is committed synchronously (idempotence); the ZoneContextManager\n // registration + instrumentation attach one microtask later.\n provider = p\n activeConfig = { endpoint: options.endpoint, key: options.key }\n userInteractionReady = import('./user-interaction.js')\n .then(({ setupUserInteraction }) => {\n // A concurrent shutdown may have cleared the provider before we resolved.\n if (provider !== p) return\n disableInstrumentations = setupUserInteraction(p, base)\n })\n .catch((err) => {\n console.warn('[observ] user-interaction setup failed; tracing degraded.', err)\n if (provider === p) {\n provider = null\n activeConfig = null\n void p.shutdown()\n }\n })\n return\n }\n\n try {\n // Default registration: W3C trace-context propagator + web StackContextManager.\n p.register()\n disableInstrumentations = registerInstrumentations({\n tracerProvider: p,\n instrumentations: base,\n })\n } catch (err) {\n // Roll back a partial init so nothing leaks and the guard doesn't latch.\n disableInstrumentations?.()\n disableInstrumentations = null\n void p.shutdown()\n throw err\n }\n\n provider = p\n activeConfig = { endpoint: options.endpoint, key: options.key }\n}\n\n/**\n * @internal Test-only. The promise that resolves once the opt-in\n * `userInteraction` async setup has attached, or `null` when not opted in (proving\n * the default path stays synchronous and never loads zone.js).\n */\nexport function getUserInteractionReady(): Promise<void> | null {\n return userInteractionReady\n}\n\n/**\n * @internal Test-only. The active provider, or `null` when tracing is not set\n * up. Lets tests assert idempotence (same instance after a second `setupOtelRum`).\n */\nexport function getActiveProvider(): WebTracerProvider | null {\n return provider\n}\n\n/**\n * @internal Tear down instrumentations and the provider, resetting the\n * idempotence guard. Used by tests (and any future explicit teardown). Not on\n * the public {@link import('./types.js').ObservSdk} surface.\n */\nexport async function shutdownOtelRum(): Promise<void> {\n // Let any in-flight opt-in user-interaction setup settle first, so its async\n // `registerInstrumentations` can't attach after we've torn the provider down.\n const pending = userInteractionReady\n userInteractionReady = null\n if (pending) {\n try {\n await pending\n } catch {\n /* the setup already logged + rolled back */\n }\n }\n const p = provider\n // Atomic: even if disabling instrumentations throws, still null the guard and\n // shut the provider down so the BatchSpanProcessor timer can't outlive teardown.\n try {\n disableInstrumentations?.()\n } finally {\n disableInstrumentations = null\n provider = null\n activeConfig = null\n await p?.shutdown()\n }\n}\n","/**\n * Shared SPA-navigation observer.\n *\n * No native event fires for `history.pushState` / `replaceState`, so they must be\n * monkey-patched to detect client-side route changes. BOTH the semantic-event tap\n * (`observ.session.navigate`) and rich page-view tracking (`app.page_view`) need\n * that signal — patching `history` independently in each would double-wrap the\n * global and make restore order-dependent. This module patches ONCE, fans out to\n * any number of subscribers, and restores the originals only when the last one\n * unsubscribes (ref-counted).\n *\n * Best-effort and reversible; never throws. If the `history` methods can't be\n * patched (frozen / exotic env), `popstate` still drives subscribers.\n */\n\n/** A history navigation, tagged by what triggered it. */\nexport type HistoryNavigation = { type: 'pushState' | 'replaceState' | 'popstate' }\n\n/** Listener invoked AFTER the navigation has applied (so `location` is updated). */\ntype NavListener = (nav: HistoryNavigation) => void\n\nconst subscribers = new Set<NavListener>()\nlet patched = false\nlet originalPush: History['pushState'] | null = null\nlet originalReplace: History['replaceState'] | null = null\nlet popStateHandler: (() => void) | null = null\n\nfunction notify(type: HistoryNavigation['type']): void {\n for (const fn of subscribers) {\n try {\n fn({ type })\n } catch {\n /* swallow — a subscriber must never break navigation */\n }\n }\n}\n\nfunction patch(): void {\n if (patched || typeof window === 'undefined' || typeof history === 'undefined') return\n\n try {\n originalPush = history.pushState\n originalReplace = history.replaceState\n history.pushState = function (this: History, ...args: Parameters<History['pushState']>): void {\n originalPush?.apply(this, args)\n notify('pushState')\n }\n history.replaceState = function (\n this: History,\n ...args: Parameters<History['replaceState']>\n ): void {\n originalReplace?.apply(this, args)\n notify('replaceState')\n }\n } catch {\n // Roll back any partial patch — popstate below still works.\n if (originalPush) history.pushState = originalPush\n if (originalReplace) history.replaceState = originalReplace\n originalPush = null\n originalReplace = null\n }\n\n popStateHandler = (): void => notify('popstate')\n window.addEventListener('popstate', popStateHandler)\n patched = true\n}\n\nfunction unpatch(): void {\n if (!patched) return\n try {\n if (originalPush) history.pushState = originalPush\n if (originalReplace) history.replaceState = originalReplace\n if (popStateHandler) window.removeEventListener('popstate', popStateHandler)\n } catch {\n /* swallow — teardown must never throw */\n }\n originalPush = null\n originalReplace = null\n popStateHandler = null\n patched = false\n}\n\n/**\n * Subscribe to SPA navigations (pushState / replaceState / popstate). Patches the\n * `history` API on the first subscriber and returns an unsubscribe fn; the\n * originals are restored once the last subscriber leaves. No-op without a DOM.\n */\nexport function onHistoryNavigation(listener: NavListener): () => void {\n if (typeof window === 'undefined') return () => {}\n subscribers.add(listener)\n patch()\n return () => {\n subscribers.delete(listener)\n if (subscribers.size === 0) unpatch()\n }\n}\n\n/**\n * @internal Test-only. Drop all subscribers and restore `history`, so one test's\n * patch can't leak into the next.\n */\nexport function resetHistoryNav(): void {\n subscribers.clear()\n unpatch()\n}\n","/**\n * Rich page-view tracking for the Observ RUM SDK (Kapitalvins parity).\n *\n * Emits an `app.page_view` OTel log event on:\n * - the initial document load (`navigation_type=load`, with the entry `url.path`\n * and the document `referrer` when present), and\n * - each SPA route change (`navigation_type=spa`), carrying the previous path\n * (`referrer_path`) and the time spent on it (`time_on_previous_ms`).\n *\n * This is the richer analytics counterpart to the lightweight\n * `observ.session.navigate` marker emitted by the semantic-event tap (both ride\n * the shared `history` observer, so `history` is patched once). `url.path` is\n * captured WITHOUT query string or hash, so no PII leaks through it. A navigation\n * counts as activity → the session is `touch()`-ed.\n *\n * Best-effort and never throws; degrades to a no-op without a DOM / logs channel.\n */\nimport type { Logger } from '@opentelemetry/api-logs'\n\nimport { onHistoryNavigation } from './history-nav.js'\nimport { emitSessionEvent, setupOtelLogs } from './otel-logs.js'\nimport { touchSession } from './session.js'\nimport type { ObservInitOptions } from './types.js'\n\n/** Canonical `event.name` for a page view. */\nexport const PAGE_VIEW_EVENT = 'app.page_view'\n\n/** Public handle for the running page-view tracker. */\nexport interface PageViewsHandle {\n /** Unsubscribe from history navigations. Idempotent. */\n stop(): void\n}\n\nconst NOOP: PageViewsHandle = { stop: () => {} }\n\n/** Module-level guard so the tracker is self-idempotent (one per page). */\nlet active: PageViewsHandle | null = null\n\n/** Strip query string + hash so `url.path` never carries PII. */\nexport function sanitizePath(path: string): string {\n return (path.split('?')[0] ?? path).split('#')[0] ?? ''\n}\n\n/** High-resolution-ish clock for time-on-page, falling back to epoch ms. */\nfunction nowMs(): number {\n return typeof performance !== 'undefined' && typeof performance.now === 'function'\n ? performance.now()\n : Date.now()\n}\n\n/**\n * Start emitting `app.page_view` events. Returns a handle whose `stop()`\n * unsubscribes. Emits the initial `load` view synchronously, then one `spa` view\n * per path change. NOT gated by `disableReplay` — page views are useful without\n * replay.\n */\nexport function startPageViews(options: ObservInitOptions): PageViewsHandle {\n if (active) return active\n if (typeof window === 'undefined' || typeof document === 'undefined') return NOOP\n\n let logger: Logger\n try {\n logger = setupOtelLogs(options)\n } catch {\n return NOOP\n }\n\n let currentPath = sanitizePath(typeof location !== 'undefined' ? location.pathname : '/')\n let enteredAt = nowMs()\n\n // Initial load view (alongside the auto-instrumented documentLoad span).\n try {\n const loadAttrs: Record<string, string> = {\n 'url.path': currentPath,\n 'app.page_view.navigation_type': 'load',\n }\n if (document.referrer) loadAttrs['app.page_view.referrer'] = document.referrer\n emitSessionEvent(logger, PAGE_VIEW_EVENT, loadAttrs)\n } catch {\n /* swallow — a failed initial view must never break init */\n }\n\n const unsubscribe = onHistoryNavigation(() => {\n try {\n const toPath = sanitizePath(typeof location !== 'undefined' ? location.pathname : currentPath)\n touchSession() // a navigation is activity\n // Only a real path change is a page view — skip query-only replaceState and\n // duplicate events so analytics stay clean.\n if (toPath === currentPath) return\n const now = nowMs()\n emitSessionEvent(logger, PAGE_VIEW_EVENT, {\n 'url.path': toPath,\n 'app.page_view.referrer_path': currentPath,\n 'app.page_view.time_on_previous_ms': String(Math.round(now - enteredAt)),\n 'app.page_view.navigation_type': 'spa',\n })\n currentPath = toPath\n enteredAt = now\n } catch {\n /* never let a navigation handler break the host page */\n }\n })\n\n let stopped = false\n const handle: PageViewsHandle = {\n stop(): void {\n if (stopped) return\n stopped = true\n active = null\n unsubscribe()\n },\n }\n active = handle\n return handle\n}\n","/**\n * PII masking / privacy controls for the heavy rrweb replay flux\n * (Epic 4 — Confidentialité, story 4.1).\n *\n * The heavy replay records the live DOM. By default rrweb captures the *values*\n * users type into inputs (passwords aside, which it already masks) and the\n * visible text. On any real-data surface that is PII — architecture decision D7\n * and PRD Open Q5 require masking to be enabled **before** any real data flows.\n * This module is that gate.\n *\n * SAFE-BY-DEFAULT: with no `privacy` config at all, ALL input values are masked\n * in the replay (`maskAllInputs: true`). A surface that is known to be free of\n * sensitive input can opt out with `privacy: { maskAllInputs: false }`.\n *\n * The defaults map the SDK's small `PrivacyOptions` bag onto rrweb's native\n * masking knobs, and expose three conventional CSS classes so a host page can\n * mark sensitive nodes declaratively without writing custom functions:\n * - `observ-mask` → mask the TEXT of the element (rrweb `maskTextClass`)\n * - `observ-block` → drop the element from the replay entirely (`blockClass`)\n * - `observ-ignore` → record the element but ignore its user input (`ignoreClass`)\n *\n * Channel scope: this governs the HEAVY flux only (rrweb → `/v1/replay`). Masking\n * the LIGHT semantic-event text (`element.text` on `observ.session.click`) is a\n * separate concern handled by a later story (4.2); the two channels are never\n * crossed (enforcement rule).\n */\nimport type { PrivacyOptions } from './types.js'\n\n/** Default class marking elements whose TEXT is masked in the replay (rrweb `maskTextClass`). */\nexport const DEFAULT_MASK_TEXT_CLASS = 'observ-mask'\n/** Default class marking elements dropped entirely from the replay (rrweb `blockClass`). */\nexport const DEFAULT_BLOCK_CLASS = 'observ-block'\n/** Default class marking inputs whose user input events are ignored (rrweb `ignoreClass`). */\nexport const DEFAULT_IGNORE_CLASS = 'observ-ignore'\n\n/**\n * The subset of rrweb `recordOptions` that govern masking. Intentionally a flat,\n * fully-resolved shape (no `undefined` for the always-present fields) so the\n * recorder can spread it straight into `record({ ... })` and tests can assert it.\n */\nexport interface ReplayMaskingOptions {\n /** Mask the value of every `<input>`/`<textarea>`/`<select>` in the replay. */\n maskAllInputs: boolean\n /** Mask the text of elements carrying this class. */\n maskTextClass: string\n /** Drop elements carrying this class from the replay. */\n blockClass: string\n /** Ignore user input on elements carrying this class. */\n ignoreClass: string\n /**\n * When `maskAllText` is on, a selector matching every element so rrweb masks\n * ALL text node content. Omitted otherwise (only class-scoped text masking).\n */\n maskTextSelector?: string\n}\n\n/**\n * Resolve the public {@link PrivacyOptions} into the rrweb masking options,\n * applying the safe-by-default policy. Pure (no DOM/global access) so it is\n * trivially unit-testable and reusable from `init()`.\n */\nexport function resolveReplayMasking(privacy?: PrivacyOptions): ReplayMaskingOptions {\n const resolved: ReplayMaskingOptions = {\n // Safe-by-default: inputs are masked unless the host *explicitly* opts out.\n maskAllInputs: privacy?.maskAllInputs ?? true,\n maskTextClass: privacy?.maskTextClass ?? DEFAULT_MASK_TEXT_CLASS,\n blockClass: privacy?.blockClass ?? DEFAULT_BLOCK_CLASS,\n ignoreClass: privacy?.ignoreClass ?? DEFAULT_IGNORE_CLASS,\n }\n // Full-text masking is opt-in: it heavily degrades replay usefulness, so it is\n // off by default and only class-scoped text masking applies. '*' tells rrweb\n // to treat every element as a masked-text element.\n if (privacy?.maskAllText) resolved.maskTextSelector = '*'\n return resolved\n}\n","/**\n * Replay chunk transport for the Observ RUM SDK (FR-2/FR-5, story 2.2).\n *\n * The heavy rrweb flux travels on its OWN channel — `POST /v1/replay` — never\n * through the OTLP exporter (architecture: the two channels are never crossed).\n * The body is the raw gzip bytes of a `.jsonl.gz` chunk; the backend (story 2.1)\n * stores it verbatim and rejects an empty body (400), so we never POST one.\n *\n * Contract frozen by story 2.1:\n * POST {endpoint}/v1/replay?session_id=<id>&seq=<n>\n * headers: x-observ-key: <key>, content-type: application/octet-stream\n * body: gzip bytes (≤ 16 MiB)\n */\n\n/**\n * Join an endpoint base URL with the `/v1/replay` path. Mirror of\n * {@link import('./otel-rum.js').buildTracesUrl}: the `URL` API preserves a path\n * prefix, never doubles a trailing slash, and drops any query/fragment; a\n * relative or empty endpoint falls back to a same-origin path.\n */\nexport function buildReplayUrl(endpoint: string): string {\n try {\n const url = new URL(endpoint)\n url.pathname = `${url.pathname.replace(/\\/+$/, '')}/v1/replay`\n url.search = ''\n url.hash = ''\n return url.toString()\n } catch {\n return `${endpoint.replace(/\\/+$/, '')}/v1/replay`\n }\n}\n\n/**\n * Gzip newline-delimited JSON lines via the native `CompressionStream` — no\n * dependency (resolves the story 1.1 gzip-strategy deferral). Available in every\n * evergreen browser and Node ≥ 18. Uses the `Blob.stream()` → `pipeThrough` →\n * `Response.arrayBuffer()` pipeline so there is no manual writer/reader (no\n * unhandled rejection, no backpressure deadlock). The output is the gzip stream,\n * stored as-is by the backend.\n */\nexport async function gzipJsonl(lines: string[]): Promise<Uint8Array> {\n const data = new TextEncoder().encode(lines.join('\\n'))\n const stream = new Blob([data as BlobPart]).stream().pipeThrough(new CompressionStream('gzip'))\n const buf = await new Response(stream).arrayBuffer()\n return new Uint8Array(buf)\n}\n\n/** Arguments for {@link postReplayChunk}. */\nexport interface PostReplayChunkOptions {\n /** Replay endpoint URL (from {@link buildReplayUrl}). */\n url: string\n /** API key for the `x-observ-key` header (omitted when empty). */\n key: string\n /** Current visit `session.id` (query param, keys the object-store prefix). */\n sessionId: string\n /** Monotonic chunk sequence within the session (query param). */\n seq: number\n /** Gzip bytes of the chunk. An empty body is never sent (server returns 400). */\n body: Uint8Array\n /** Use `fetch` keepalive for an unload flush (body capped ~64 KiB by the spec). */\n keepalive?: boolean\n}\n\n/**\n * POST one gzip replay chunk. **Best-effort: never throws** — a network failure\n * degrades to \"this chunk is lost\", it must not break the host page.\n */\nexport async function postReplayChunk(opts: PostReplayChunkOptions): Promise<void> {\n if (opts.body.length === 0) return // backend rejects an empty body (400)\n\n const headers: Record<string, string> = { 'content-type': 'application/octet-stream' }\n // Mirror otel-rum.ts: a blank key would be a malformed credential — omit it.\n if (opts.key) headers['x-observ-key'] = opts.key\n\n const url = `${opts.url}?session_id=${encodeURIComponent(opts.sessionId)}&seq=${opts.seq}`\n try {\n const res = await fetch(url, {\n method: 'POST',\n headers,\n body: opts.body as BodyInit,\n keepalive: opts.keepalive,\n })\n // `fetch` only rejects on network failure — surface server rejections\n // (400 empty / 401 auth / 413 over the 16 MiB cap) instead of silent success.\n if (!res.ok) {\n console.warn(`[observ] replay chunk rejected: HTTP ${res.status}`)\n }\n } catch (err) {\n console.warn('[observ] replay chunk upload failed', err)\n }\n}\n","/**\n * rrweb recording + chunked replay upload for the Observ RUM SDK (FR-2, story 2.2).\n *\n * Captures the visual session with `@rrweb/record` (initial FullSnapshot + DOM\n * mutations), buffers events in memory, and POSTs gzip chunks to `/v1/replay`\n * (story 2.1) — triggered by SIZE or TIME, whichever comes first. The heavy flux\n * uses this channel exclusively, never the OTLP exporter.\n *\n * Invariant (1.1/1.2/1.3): the SDK must NEVER break the host page. Every path —\n * capture, serialize, gzip, upload — is defensive: a failure degrades to \"no\n * replay\", never an exception that escapes to the page.\n *\n * Flushes are SERIALIZED through a promise chain (`pending`): every trigger is\n * queued — never dropped — so the buffer cannot grow unbounded behind an\n * in-flight flush, `seq` is assigned in order, and two uploads never overlap.\n *\n * Session activity (1.2 deferral): `getSessionId` is read once per flush (~5 s),\n * NOT per rrweb event — touching the session on every high-frequency mutation\n * would thrash `sessionStorage` and jank the main thread.\n */\nimport { record } from '@rrweb/record'\n\nimport { resolveReplayMasking } from './privacy.js'\nimport { getSessionId } from './session.js'\nimport { buildReplayUrl, gzipJsonl, postReplayChunk } from './transport.js'\nimport type { ObservInitOptions } from './types.js'\n\n/** Serialized buffer size (pre-gzip) that triggers a size-based flush. */\nexport const CHUNK_MAX_BYTES = 512 * 1024 // ~512 KiB — well under the 16 MiB cap\n/** Interval (ms) for the time-based flush. */\nexport const CHUNK_INTERVAL_MS = 5_000\n/** rrweb full-snapshot cadence so a reader can resync from a checkpoint. */\nexport const CHECKOUT_INTERVAL_MS = 5 * 60 * 1_000\n\n/** Public handle for the running recorder. */\nexport interface ReplayRecorder {\n /** Stop capture, remove listeners, and flush the residual. Idempotent. */\n stop(): Promise<void>\n}\n\n/** No-op recorder returned in a non-DOM environment (SSR) — nothing runs. */\nconst NOOP_RECORDER: ReplayRecorder = { stop: () => Promise.resolve() }\n\n/**\n * Start rrweb capture + chunked upload. Returns a handle whose `stop()` tears\n * everything down and flushes the tail. Never throws: a capture/start failure is\n * swallowed (the page keeps working, just without replay).\n */\nexport function startReplayRecording(options: ObservInitOptions): ReplayRecorder {\n // SSR / non-DOM guard: rrweb and the lifecycle listeners need `document` /\n // `window`. Degrade to a no-op recorder (mirrors session.ts's globalThis-\n // defensive style) rather than throwing a ReferenceError / leaking a timer.\n if (typeof document === 'undefined' || typeof window === 'undefined') {\n return NOOP_RECORDER\n }\n\n const url = buildReplayUrl(options.endpoint)\n const key = options.key\n\n let buffer: string[] = []\n let bufferedBytes = 0\n let seq = 0\n let lastSessionId: string | null = null\n let stopped = false\n // Flush chain: each trigger appends to this promise so flushes run one after\n // another (never concurrently, never dropped). Kept reject-free by the inner\n // try/catch + the trailing `.catch`.\n let pending: Promise<void> = Promise.resolve()\n\n /** Serialize → gzip → upload the current buffer. Swapped before the first await. */\n async function doFlush(keepalive: boolean): Promise<void> {\n if (buffer.length === 0) return\n const lines = buffer\n buffer = []\n bufferedBytes = 0\n try {\n const body = await gzipJsonl(lines)\n const sessionId = getSessionId()\n // The session id rotated (idle tab past the 30-min window): restart `seq`\n // so the new object-store prefix begins at 0 (its own checkpoint).\n if (lastSessionId !== null && lastSessionId !== sessionId) seq = 0\n lastSessionId = sessionId\n await postReplayChunk({ url, key, sessionId, seq: seq++, body, keepalive })\n } catch (err) {\n console.warn('[observ] replay flush failed', err)\n }\n }\n\n /** Queue a flush after any in-flight one (never dropped). */\n function enqueueFlush(keepalive = false): void {\n pending = pending.then(() => doFlush(keepalive)).catch(() => {})\n }\n\n const emit = (event: unknown): void => {\n if (stopped) return // drop trailing events after teardown\n try {\n const line = JSON.stringify(event)\n buffer.push(line)\n bufferedBytes += line.length\n if (bufferedBytes >= CHUNK_MAX_BYTES) enqueueFlush()\n } catch {\n /* never let capture break the host page */\n }\n }\n\n // PII masking (story 4.1): safe-by-default — input values are masked unless\n // the host explicitly opts out via `privacy.maskAllInputs: false`. Resolved\n // once here and spread into the recorder config so the heavy replay flux is\n // privacy-safe by construction (architecture D7 / PRD Open Q5).\n const masking = resolveReplayMasking(options.privacy)\n\n let stopFn: (() => void) | undefined\n try {\n // `record` returns the stop handler (or undefined if unsupported).\n stopFn = record({ emit, checkoutEveryNms: CHECKOUT_INTERVAL_MS, ...masking }) ?? undefined\n } catch (err) {\n console.warn('[observ] rrweb recording failed to start', err)\n }\n\n const interval = setInterval(() => enqueueFlush(), CHUNK_INTERVAL_MS)\n\n // Lifecycle flush (1.3 deferral). visibilitychange→hidden fires on tab\n // switch / minimize / most mobile navigations while the page is still alive;\n // pagehide is the best-effort last resort (keepalive — a body the browser\n // can't keepalive-send is rejected and logged, not silently pre-dropped).\n const onVisibility = (): void => {\n if (document.visibilityState === 'hidden') enqueueFlush()\n }\n const onPageHide = (): void => {\n enqueueFlush(true)\n }\n document.addEventListener('visibilitychange', onVisibility)\n window.addEventListener('pagehide', onPageHide)\n\n return {\n async stop(): Promise<void> {\n if (stopped) return\n stopped = true\n clearInterval(interval)\n document.removeEventListener('visibilitychange', onVisibility)\n window.removeEventListener('pagehide', onPageHide)\n try {\n stopFn?.()\n } catch {\n /* swallow — teardown must not throw */\n }\n enqueueFlush() // final residual\n await pending // wait for the whole chain (incl. the final flush) to settle\n },\n }\n}\n","/**\n * Minimal, defensive CSS-selector + text derivation for semantic events\n * (story 2.3). Produces a short, reasonably stable selector for a clicked\n * element and a truncated text label. Never throws (the SDK must never break\n * the host page); degrades to the tag name or `''`.\n */\n\nconst MAX_TEXT = 100\nconst MAX_CLASSES = 3\nconst MAX_CLASS_LEN = 30\nconst MAX_DEPTH = 4\n\n/**\n * Build a short CSS selector for `el`:\n * - `tag#id` when the element has an id,\n * - else `tag.class1.class2` (≤ 3 short classes),\n * - else a depth-bounded `tag:nth-of-type(n)` ancestor path (≤ 4 levels).\n * Returns `''` for a non-element / null, or the bare tag name on any failure.\n */\nexport function cssSelector(el: Element | null): string {\n if (!el || el.nodeType !== 1) return ''\n try {\n // `localName` is lowercase for HTML but case-preserved for SVG\n // (`linearGradient`, `clipPath`) — `tagName.toLowerCase()` would corrupt those.\n const tag = el.localName\n if (el.id) return `${tag}#${el.id}`\n\n const classes = Array.from(el.classList)\n .filter((c) => c.length > 0 && c.length <= MAX_CLASS_LEN)\n .slice(0, MAX_CLASSES)\n if (classes.length > 0) return `${tag}.${classes.join('.')}`\n\n // Depth-bounded structural path.\n const parts: string[] = []\n let node: Element | null = el\n let depth = 0\n while (node && node.nodeType === 1 && depth < MAX_DEPTH) {\n const t = node.localName\n if (node.id) {\n parts.unshift(`${t}#${node.id}`)\n break\n }\n const parent: Element | null = node.parentElement\n if (parent) {\n const current = node\n const sameTag = Array.from(parent.children).filter((c) => c.tagName === current.tagName)\n if (sameTag.length > 1) {\n parts.unshift(`${t}:nth-of-type(${sameTag.indexOf(current) + 1})`)\n } else {\n parts.unshift(t)\n }\n } else {\n parts.unshift(t)\n }\n node = node.parentElement\n depth++\n }\n return parts.join(' > ')\n } catch {\n return el.localName ?? ''\n }\n}\n\n/** Trimmed, whitespace-collapsed, truncated `textContent` of `el` (≤ 100 chars). */\nexport function elementText(el: Element | null): string {\n if (!el) return ''\n try {\n const text = (el.textContent ?? '').trim().replace(/\\s+/g, ' ')\n return text.length > MAX_TEXT ? text.slice(0, MAX_TEXT) : text\n } catch {\n return ''\n }\n}\n","/**\n * Semantic event derivation for the Observ RUM SDK (FR-3 / D8, story 2.3).\n *\n * Derives high-value interaction facts from native DOM listeners and emits them\n * as OTel log records (`observ.session.*`) on the logs channel (`/v1/logs`):\n * - `observ.session.click` — every click, with `element.selector` / `element.text`\n * - `observ.session.rage_click` — ≥ 3 clicks < 1 s on the SAME selector\n * - `observ.session.navigate` — SPA navigation (`pushState`/`replaceState`/`popstate`), `url`\n *\n * Variance vs architecture D8 (\"tap rrweb emit\"): we use native DOM listeners\n * rather than reverse-mapping rrweb node ids — `element.selector`/`element.text`\n * are derived directly and reliably from `event.target`. Same OTel-logs output.\n *\n * Invariant (1.1/1.2/1.3): never break the host page. Listeners run in the\n * page's own context, so every handler is `try/catch`-guarded. SPA navigation is\n * detected through the shared {@link import('./history-nav.js')} observer (which\n * patches `history` once for both this tap and page-view tracking), unsubscribed\n * on `stop()` so no global stays monkey-patched.\n */\nimport type { Logger } from '@opentelemetry/api-logs'\n\nimport { onHistoryNavigation } from './history-nav.js'\nimport { emitSessionEvent, setupOtelLogs } from './otel-logs.js'\nimport { cssSelector, elementText } from './selector.js'\nimport type { ObservInitOptions } from './types.js'\n\n/** Rage-click window (ms) and click threshold (architecture D8 / AC#2). */\nexport const RAGE_CLICK_WINDOW_MS = 1_000\nexport const RAGE_CLICK_THRESHOLD = 3\n/** Cap on tracked selectors so the rage-click map can't grow unbounded over a\n * long session (cleared past this — rage detection is best-effort). */\nconst MAX_TRACKED_SELECTORS = 100\n\n/** Module-level guard so the tap is self-idempotent (a second start without a\n * stop() between would double-patch `history` / double-add listeners). */\nlet active: SemanticEventsHandle | null = null\n\n/** Public handle for the running semantic-event tap. */\nexport interface SemanticEventsHandle {\n /** Remove listeners, restore patched `history`, shut the logs provider down. */\n stop(): Promise<void>\n}\n\nconst NOOP: SemanticEventsHandle = { stop: () => Promise.resolve() }\n\n/** Resolve an `EventTarget` to the nearest `Element` (text/SVG nodes → parent). */\nfunction toElement(target: EventTarget | null): Element | null {\n if (target instanceof Element) return target\n const node = target as Node | null\n return node && node.parentElement ? node.parentElement : null\n}\n\n/**\n * Start deriving + emitting semantic events. Returns a handle whose `stop()`\n * tears everything down. Never throws; degrades to a no-op in a non-DOM env.\n * NOTE: not gated by `disableReplay` — semantic events are useful even without\n * the heavy replay capture.\n */\nexport function startSemanticEvents(options: ObservInitOptions): SemanticEventsHandle {\n if (active) return active\n if (typeof document === 'undefined' || typeof window === 'undefined') return NOOP\n\n let logger: Logger\n try {\n logger = setupOtelLogs(options)\n } catch (err) {\n console.warn('[observ] semantic events: logs setup failed', err)\n return NOOP\n }\n\n // Recent click timestamps per selector, for rage-click clustering.\n const clickTimes = new Map<string, number[]>()\n\n const onClick = (event: Event): void => {\n try {\n const el = toElement(event.target)\n if (!el) return\n const selector = cssSelector(el)\n emitSessionEvent(logger, 'observ.session.click', {\n 'element.selector': selector,\n 'element.text': elementText(el),\n })\n\n // Rage-click: ≥ THRESHOLD clicks within WINDOW on the same selector.\n const now = Date.now()\n const recent = (clickTimes.get(selector) ?? []).filter((t) => now - t < RAGE_CLICK_WINDOW_MS)\n recent.push(now)\n if (recent.length >= RAGE_CLICK_THRESHOLD) {\n emitSessionEvent(logger, 'observ.session.rage_click', { 'element.selector': selector })\n clickTimes.delete(selector) // reset the burst (one rage_click per burst)\n } else {\n // Bound the map: a selector clicked once never reaches the threshold and\n // would otherwise linger forever. Clear past the cap (rare; best-effort).\n if (clickTimes.size > MAX_TRACKED_SELECTORS) clickTimes.clear()\n clickTimes.set(selector, recent)\n }\n } catch {\n /* never let a click handler break the host page */\n }\n }\n\n document.addEventListener('click', onClick, { capture: true })\n\n // SPA navigation (pushState/replaceState/popstate) via the shared observer.\n const unsubscribeNav = onHistoryNavigation(() => {\n emitSessionEvent(logger, 'observ.session.navigate', { url: location.href })\n })\n\n let stopped = false\n const handle: SemanticEventsHandle = {\n async stop(): Promise<void> {\n if (stopped) return\n stopped = true\n active = null\n document.removeEventListener('click', onClick, { capture: true })\n unsubscribeNav()\n // The shared logs provider is shut down once by index.shutdown() (story\n // 2.4) — not here, since js-errors shares it.\n },\n }\n active = handle\n return handle\n}\n","/**\n * Session lifecycle wiring for the Observ RUM SDK (Kapitalvins parity).\n *\n * `session.ts` owns the pure rotation logic (lazy, no timers, no I/O). THIS module\n * turns those transitions into observable signals and drives them in real time:\n *\n * - emits `session.start` (with `session.previous_id` on a continuation) and\n * `session.end` (with `session.duration_ms`) as OTel **log events** on the\n * shared `/v1/logs` channel — by subscribing to {@link addSessionListener},\n * so the events fire from the single code path that mints/ends a session,\n * never from a scattered call site;\n * - resets the throttled `session.id` cache the instant a rotation happens, so\n * post-rotation events carry the new id;\n * - treats user input (`click`/`keydown`/`scroll`/`mousemove`) as activity that\n * refreshes the inactivity window (and triggers a lazy rotation when due);\n * - runs a periodic **sweep** so an idle session still produces a timely\n * `session.end` even with no further events to trigger a lazy rotation;\n * - flushes a best-effort `session.end` on `pagehide`/`visibilitychange:hidden`\n * (the browser can't guarantee it on a crash — duration is derived backend\n * side, this is the at-best signal);\n * - when `crossTab` is enabled, adopts the session another tab just wrote.\n *\n * Like the rest of the SDK it is best-effort and never throws to the host page.\n * The shared logs provider is shut down once by `index.shutdown()` (it is also\n * used by semantic-events / js-errors), never here.\n */\nimport type { Logger } from '@opentelemetry/api-logs'\n\nimport { emitSessionEvent, resetSessionIdCache, setupOtelLogs } from './otel-logs.js'\nimport { SESSION_ID_ATTRIBUTE } from './constants.js'\nimport {\n addSessionListener,\n adoptStoredSession,\n endSessionIfExpired,\n SESSION_STORAGE_KEY,\n touchSession,\n type SessionLifecycleEvent,\n} from './session.js'\nimport type { ObservInitOptions } from './types.js'\n\n/** Canonical `event.name` values for the session lifecycle events. */\nexport const SESSION_START_EVENT = 'session.start'\nexport const SESSION_END_EVENT = 'session.end'\n\n/** Sweep cadence: how often we check the active session for idle expiry. */\nexport const SWEEP_INTERVAL_MS = 60_000\n/** Throttle for the high-frequency `mousemove` activity signal. */\nconst MOUSEMOVE_THROTTLE_MS = 1_000\n\n/** DOM events treated as user activity (each refreshes the inactivity window). */\nconst ACTIVITY_EVENTS = ['click', 'keydown', 'scroll'] as const\n\n/** Public handle for the running session-lifecycle wiring. */\nexport interface SessionLifecycleHandle {\n /** Remove listeners + sweep timer and unsubscribe. Idempotent. */\n stop(): void\n}\n\n/** Module-level guard so the wiring is self-idempotent (one per page). */\nlet active: SessionLifecycleHandle | null = null\n\n/**\n * Translate a {@link SessionLifecycleEvent} into a `session.start` / `session.end`\n * log event. The `session.id` is passed explicitly (overriding the throttled one\n * that {@link emitSessionEvent} would inject) so the event always carries the id\n * of the session it describes, even within the post-rotation throttle window.\n */\nfunction emitLifecycle(logger: Logger, event: SessionLifecycleEvent): void {\n if (event.type === 'start') {\n // A rotation just minted this id — drop the stale cache so later events read it.\n resetSessionIdCache()\n const attrs: Record<string, string> = { [SESSION_ID_ATTRIBUTE]: event.id }\n if (event.previousId) attrs['session.previous_id'] = event.previousId\n emitSessionEvent(logger, SESSION_START_EVENT, attrs)\n } else {\n emitSessionEvent(logger, SESSION_END_EVENT, {\n [SESSION_ID_ATTRIBUTE]: event.id,\n 'session.duration_ms': String(event.durationMs),\n })\n }\n}\n\n/**\n * Start the session lifecycle wiring. Returns a handle whose `stop()` tears\n * everything down. Subscribes the lifecycle listener BEFORE the caller bootstraps\n * the session (`ensureSession` in `index.init`) so the very first `session.start`\n * is captured. Never throws; degrades to a no-op without a DOM or a logs channel.\n */\nexport function startSessionLifecycle(options: ObservInitOptions): SessionLifecycleHandle {\n if (active) return active\n\n let logger: Logger | null = null\n try {\n logger = setupOtelLogs(options)\n } catch (err) {\n // Without a logger we can't emit start/end, but activity tracking + rotation\n // still matter — keep going with a null logger (emit becomes a no-op).\n console.warn('[observ] session lifecycle: logs setup failed; events disabled.', err)\n }\n\n const unsubscribe = addSessionListener((event) => {\n if (logger) emitLifecycle(logger, event)\n })\n\n // No DOM (SSR / worker): keep the subscription so a programmatic ensureSession\n // still emits start/end, but skip the browser-only listeners + timers.\n if (typeof window === 'undefined' || typeof document === 'undefined') {\n const handle: SessionLifecycleHandle = {\n stop() {\n unsubscribe()\n active = null\n },\n }\n active = handle\n return handle\n }\n\n const onActivity = (): void => {\n try {\n touchSession()\n } catch {\n /* never let an activity listener break the host page */\n }\n }\n\n // Throttle the firehose `mousemove` so a drag can't hammer touchSession.\n let lastMove = 0\n const onMouseMove = (): void => {\n const now = Date.now()\n if (now - lastMove < MOUSEMOVE_THROTTLE_MS) return\n lastMove = now\n onActivity()\n }\n\n for (const evt of ACTIVITY_EVENTS) {\n window.addEventListener(evt, onActivity, { passive: true })\n }\n window.addEventListener('mousemove', onMouseMove, { passive: true })\n\n // Best-effort end on background / unload (the browser can't guarantee it).\n const onHide = (): void => {\n try {\n endSessionIfExpired()\n } catch {\n /* swallow */\n }\n }\n const onVisibility = (): void => {\n if (document.visibilityState === 'hidden') onHide()\n }\n window.addEventListener('pagehide', onHide)\n document.addEventListener('visibilitychange', onVisibility)\n\n // Cross-tab: adopt the session another tab just wrote (only fires across\n // documents, and only when `crossTab` switched the store to localStorage).\n const onStorage = (e: StorageEvent): void => {\n if (e.key !== SESSION_STORAGE_KEY || e.newValue == null) return\n try {\n adoptStoredSession()\n resetSessionIdCache()\n } catch {\n /* swallow */\n }\n }\n window.addEventListener('storage', onStorage)\n\n // Periodic sweep: detect idle expiry without waiting for the next event/read.\n const sweepTimer = setInterval(() => {\n try {\n endSessionIfExpired()\n } catch {\n /* swallow */\n }\n }, SWEEP_INTERVAL_MS)\n\n let stopped = false\n const handle: SessionLifecycleHandle = {\n stop() {\n if (stopped) return\n stopped = true\n active = null\n unsubscribe()\n clearInterval(sweepTimer)\n for (const evt of ACTIVITY_EVENTS) window.removeEventListener(evt, onActivity)\n window.removeEventListener('mousemove', onMouseMove)\n window.removeEventListener('pagehide', onHide)\n document.removeEventListener('visibilitychange', onVisibility)\n window.removeEventListener('storage', onStorage)\n },\n }\n active = handle\n return handle\n}\n","import { installBaggagePropagation } from './baggage.js'\nimport { clearConsent, consentKey, hasAnalyticsConsent, writeConsent } from './consent.js'\nimport { startConsoleForward, type ConsoleForwardHandle } from './console-forward.js'\nimport { startJsErrorCapture, type JsErrorHandle } from './js-errors.js'\nimport { shutdownOtelLogs } from './otel-logs.js'\nimport { setupOtelMetrics, type MetricsHandle } from './otel-metrics.js'\nimport { setupOtelRum, shutdownOtelRum, telemetryIgnoreUrls } from './otel-rum.js'\nimport { startPageViews, type PageViewsHandle } from './page-views.js'\nimport { startReplayRecording, type ReplayRecorder } from './rrweb-record.js'\nimport { startSemanticEvents, type SemanticEventsHandle } from './semantic-events.js'\nimport { startSessionLifecycle, type SessionLifecycleHandle } from './session-lifecycle.js'\nimport { configureSession, ensureSession, getSessionId } from './session.js'\nimport { clearUser, configureUser, getPseudoUserId, setUser } from './user.js'\nimport type { ObservInitOptions, ObservSdk } from './types.js'\n\nexport type { ObservInitOptions, ObservSdk, ObservUser } from './types.js'\nexport { setUser, clearUser } from './user.js'\n\n/**\n * Attribute key used everywhere to correlate signals of a single session.\n * Re-exported from {@link ./constants.js} (the leaf module that internal modules\n * also import, avoiding an `index ↔ otel-rum` cycle). EXACTLY `session.id`.\n */\nexport { SESSION_ID_ATTRIBUTE } from './constants.js'\n\n/** Singleton replay recorder handle (one capture per page, like the OTel provider). */\nlet replayRecorder: ReplayRecorder | null = null\n/** Singleton semantic-events tap (story 2.3). */\nlet semanticEvents: SemanticEventsHandle | null = null\n/** Singleton JS-error capture (story 2.4). */\nlet jsErrors: JsErrorHandle | null = null\n/** Singleton metrics handle — Core Web Vitals + OTLP metrics (parity). */\nlet metrics: MetricsHandle | null = null\n/** Baggage-propagation uninstaller, set when `propagateBaggage` is on (parity). */\nlet baggageUninstall: (() => void) | null = null\n/** Singleton session-lifecycle wiring (start/end events + activity + sweep). */\nlet sessionLifecycle: SessionLifecycleHandle | null = null\n/** Singleton console forwarder, set when `forwardConsole` is on (parity). */\nlet consoleForward: ConsoleForwardHandle | null = null\n/** Singleton page-view tracker — `app.page_view` load + SPA events (parity). */\nlet pageViews: PageViewsHandle | null = null\n/** Options held while a `requireConsent` init waits for consent (else null). */\nlet pendingConsentOptions: ObservInitOptions | null = null\n/** Options of the last started SDK — lets {@link revokeConsent} find the consent\n * key after the SDK has already started (no longer \"pending\"). */\nlet lastStartedOptions: ObservInitOptions | null = null\n/** Tears down the consent watcher (storage listener + poll), if installed. */\nlet consentWatcherCleanup: (() => void) | null = null\n\n/** Poll cadence while waiting for same-tab consent (storage events only fire\n * cross-tab, so a poll covers the banner writing consent in THIS tab). */\nconst CONSENT_POLL_MS = 1_500\n\n/**\n * Initialize the Observ RUM SDK.\n *\n * 1. Establishes (or resumes) the visit's `session.id` — the single\n * correlation key shared by every signal (story 1.2).\n * 2. Wires OTel RUM tracing (story 1.3): `http.client` spans for fetch/XHR,\n * carrying `session.id`, with W3C `traceparent` propagation and OTLP/HTTP\n * export to `{endpoint}/v1/traces`.\n * 3. Starts rrweb replay capture (story 2.2): buffered gzip chunks POSTed to\n * `{endpoint}/v1/replay` (size/time triggered), unless `disableReplay`.\n * 4. Derives semantic events (story 2.3): `click` / `rage_click` / `navigate`\n * emitted as OTel log records to `{endpoint}/v1/logs` (independent of\n * `disableReplay`).\n * 5. Captures JS errors (story 2.4): `observ.session.js_error` (uncaught\n * errors + unhandled rejections) on the same logs channel.\n *\n * Idempotent (a second call re-registers nothing) and never throws — any setup\n * failure is swallowed so the SDK can never break the host page; it degrades to\n * \"no tracing / no replay / no semantic events\".\n *\n * When `requireConsent` is set, init becomes a GDPR consent barrier: it does\n * nothing (no session, no persistent id, no providers, no network) until consent\n * is present, then auto-starts — watching for a banner that grants consent later\n * (cross-tab via `storage`, same-tab via a light poll) or {@link grantConsent}.\n */\nexport function init(options: ObservInitOptions): void {\n try {\n if (options.requireConsent && !hasAnalyticsConsent(options)) {\n // Gate everything until consent arrives. Remember the options and watch.\n pendingConsentOptions = options\n installConsentWatcher(options)\n return\n }\n startSdk(options)\n } catch (err) {\n // The SDK must never break the host page (1.1/1.2 guarantee).\n console.warn('[observ] RUM init failed; telemetry disabled.', err)\n }\n}\n\n/** Wire every layer of the SDK. Assumes consent (if required) is granted. */\nfunction startSdk(options: ObservInitOptions): void {\n try {\n lastStartedOptions = options\n // Apply session tuning (inactivity / max-duration / cross-tab) BEFORE the\n // session is first resolved, then start the lifecycle wiring so its listener\n // is subscribed in time to capture the very first `session.start`. The\n // bootstrap read (`ensureSession`) comes right after.\n configureSession({\n inactivityTimeoutMs: options.sessionInactivityMs,\n maxDurationMs: options.sessionMaxDurationMs,\n crossTab: options.crossTabSessions,\n })\n // End-user identity: honour the pseudo-user opt-out, then mint/restore the\n // pseudonymous id once so `enduser.pseudo.id` is ready for the first signal.\n configureUser({ disablePseudoUser: options.disablePseudoUser })\n getPseudoUserId()\n if (!sessionLifecycle) {\n sessionLifecycle = startSessionLifecycle(options)\n }\n ensureSession()\n setupOtelRum(options)\n if (!options.disableReplay && !replayRecorder) {\n replayRecorder = startReplayRecording(options)\n }\n // Semantic events + JS errors are useful even without replay → not gated.\n if (!semanticEvents) {\n semanticEvents = startSemanticEvents(options)\n }\n // Rich page views (parity) — independent of replay; opt-out via `disablePageViews`.\n if (!options.disablePageViews && !pageViews) {\n pageViews = startPageViews(options)\n }\n if (!jsErrors) {\n jsErrors = startJsErrorCapture(options)\n }\n // Console forwarding (parity) — opt-in via `forwardConsole`; mirrors console.*\n // to the same logs channel. startConsoleForward no-ops when the option is off.\n if (options.forwardConsole && !consoleForward) {\n consoleForward = startConsoleForward(options)\n }\n // Metrics + Core Web Vitals (parity) — independent of replay; opt-out via `disableMetrics`.\n if (!options.disableMetrics && !metrics) {\n metrics = setupOtelMetrics(options)\n }\n // Baggage: stamp `session.id` on requests to the same backends that receive\n // `traceparent` (+ same-origin), so backend spans can read the session identity.\n if (options.propagateBaggage && !baggageUninstall) {\n const backends = [...(options.propagateTraceHeaderCorsUrls ?? [])]\n if (typeof location !== 'undefined') backends.push(location.origin)\n baggageUninstall = installBaggagePropagation(\n getSessionId,\n backends,\n telemetryIgnoreUrls(options.endpoint),\n )\n }\n } catch (err) {\n // The SDK must never break the host page (1.1/1.2 guarantee). Degrade to\n // \"no tracing / no replay / no semantic events\" rather than propagating.\n console.warn('[observ] RUM setup failed; tracing/replay/events degraded.', err)\n }\n}\n\n/** Remove the consent watcher (storage listener + poll), if any. */\nfunction removeConsentWatcher(): void {\n const cleanup = consentWatcherCleanup\n consentWatcherCleanup = null\n try {\n cleanup?.()\n } catch {\n /* swallow */\n }\n}\n\n/** Start the deferred SDK once consent appears; tears the watcher down first. */\nfunction startFromConsent(options: ObservInitOptions): void {\n removeConsentWatcher()\n pendingConsentOptions = null\n startSdk(options)\n}\n\n/**\n * Watch for consent granted AFTER a gated init: cross-tab via the `storage` event\n * (the banner writing the key in another tab) and same-tab via a light poll (a\n * same-tab `localStorage` write fires no `storage` event). Either way, the SDK\n * starts the instant consent is present. {@link grantConsent} is the explicit path.\n */\nfunction installConsentWatcher(options: ObservInitOptions): void {\n if (consentWatcherCleanup || typeof window === 'undefined') return\n const key = consentKey(options)\n const tryStart = (): void => {\n if (hasAnalyticsConsent(options)) startFromConsent(options)\n }\n const onStorage = (e: StorageEvent): void => {\n if (e.key === key) tryStart()\n }\n window.addEventListener('storage', onStorage)\n const interval = setInterval(tryStart, CONSENT_POLL_MS)\n consentWatcherCleanup = (): void => {\n window.removeEventListener('storage', onStorage)\n clearInterval(interval)\n }\n}\n\n/**\n * Grant analytics consent at runtime: persist the consent value and immediately\n * start a `requireConsent` init that was waiting. No-op when nothing is gated.\n */\nexport function grantConsent(): void {\n const options = pendingConsentOptions\n if (!options) return\n writeConsent(options) // persist so the next visit starts without re-prompting\n startFromConsent(options)\n}\n\n/**\n * Revoke analytics consent: clear the stored consent (so future inits gate again)\n * and shut the SDK down. Already-sent data cannot be recalled. A later `init()` /\n * {@link grantConsent} re-arms it.\n */\nexport function revokeConsent(): void {\n const options = pendingConsentOptions ?? lastStartedOptions\n if (options) clearConsent(options)\n removeConsentWatcher()\n pendingConsentOptions = null\n void shutdown()\n}\n\n/**\n * Stop replay capture (flushing the residual chunk), the semantic-event tap, and\n * tear down OTel tracing + logs. Best-effort and never throws (resolves the\n * story 1.3 \"no public teardown\" deferral). After this, a later {@link init} can\n * re-start the SDK.\n */\nexport async function shutdown(): Promise<void> {\n // Drop any unsatisfied consent gate so a stale watcher can't auto-start later.\n removeConsentWatcher()\n pendingConsentOptions = null\n const recorder = replayRecorder\n const events = semanticEvents\n const errors = jsErrors\n const metricsHandle = metrics\n const uninstallBaggage = baggageUninstall\n const lifecycle = sessionLifecycle\n const consoleHandle = consoleForward\n const pageViewsHandle = pageViews\n replayRecorder = null\n semanticEvents = null\n jsErrors = null\n metrics = null\n baggageUninstall = null\n sessionLifecycle = null\n consoleForward = null\n pageViews = null\n try {\n // Restore the patched console BEFORE the logs provider is shut down, so a\n // late console call can't try to emit through a dead provider.\n consoleHandle?.stop()\n } catch {\n /* swallow — restoring console must never throw */\n }\n try {\n pageViewsHandle?.stop()\n } catch {\n /* swallow — unsubscribing the history observer must never throw */\n }\n try {\n lifecycle?.stop()\n } catch {\n /* swallow — removing listeners / clearing the sweep timer must never throw */\n }\n try {\n uninstallBaggage?.()\n } catch {\n /* swallow — restoring window.fetch must never throw */\n }\n try {\n await recorder?.stop()\n } catch {\n /* swallow — teardown must never throw to the host page */\n }\n try {\n await events?.stop()\n } catch {\n /* swallow */\n }\n try {\n errors?.stop()\n } catch {\n /* swallow */\n }\n try {\n await metricsHandle?.stop()\n } catch {\n /* swallow */\n }\n // Both the semantic-events tap and the JS-error capture share ONE logs\n // provider — shut it down once, here, after both taps have stopped. Each\n // provider shutdown is guarded so a flush rejection can't skip the next one\n // or escape to the host page (shutdown must never throw — 1.3 guarantee).\n try {\n await shutdownOtelLogs()\n } catch {\n /* swallow */\n }\n try {\n await shutdownOtelRum()\n } catch {\n /* swallow */\n }\n}\n\n/** Singleton SDK handle. Usage: `observ.init({ endpoint, key })`. */\nexport const observ: ObservSdk = {\n init,\n shutdown,\n setUser,\n clearUser,\n grantConsent,\n revokeConsent,\n}\n\nexport default observ\n"]}