{"version":3,"sources":["../src/stream/events.ts","../src/stream/gzip.ts","../src/stream/recorder.ts","../src/stream/ring-buffer.ts","../src/stream/uuid7.ts","../src/stream/session-manager.ts","../src/stream/transport.ts","../src/stream/stream.ts"],"sourcesContent":["// Copyright 2026 Bitech.id. Licensed under the MIT License.\n\n/**\n * Session-event capture for Biwave Stream — LogRocket-style discrete events\n * (console, network via fetch/XHR, static resource loads, click, navigation)\n * that the backend can count, filter, and search per session, complementing\n * the opaque rrweb chunk stream. Uploaded batched to\n * POST /api/stream/sessions/:id/events (see StreamTransport.sendEvents).\n * Metadata only — request/response bodies and headers are never captured.\n */\n\nconst MAX_CONSOLE_MESSAGE_CHARS = 4096;\nconst MAX_URL_CHARS = 2048;\nconst MAX_SELECTOR_CHARS = 1024;\nconst MAX_CLICK_TEXT_CHARS = 256;\n\nexport type ConsoleLevel = 'debug' | 'log' | 'info' | 'warn' | 'error';\n\nexport type SessionEvent =\n  | { ts: number; type: 'console'; level: ConsoleLevel; message: string }\n  | {\n      ts: number;\n      type: 'network';\n      method: string;\n      url: string;\n      status: number;\n      duration_ms: number;\n    }\n  | {\n      ts: number;\n      type: 'resource';\n      initiator_type: string;\n      url: string;\n      duration_ms: number;\n      size: number;\n    }\n  | { ts: number; type: 'click'; selector: string; text: string }\n  | { ts: number; type: 'navigation'; from: string; to: string };\n\nexport interface SessionEventCaptureOptions {\n  /** The SDK's own ingest origin — its requests are never captured as network events. */\n  ignoreOrigin: string;\n  /** Mirrors the recorder's maskAllText — when true, click text is omitted unless the element opts out via 'biwave-unmask'. */\n  maskAllText: boolean;\n  onEvent: (event: SessionEvent) => void;\n}\n\n/** Installs all instrumentations; returns an uninstall that restores every patched global. */\nexport function installSessionEventCapture(options: SessionEventCaptureOptions): () => void {\n  const uninstalls = [\n    installConsoleCapture(options),\n    installNetworkCapture(options),\n    installXHRCapture(options),\n    installResourceCapture(options),\n    installClickCapture(options),\n    installNavigationCapture(options),\n  ];\n  return () => {\n    for (const uninstall of uninstalls) uninstall();\n  };\n}\n\ntype OriginalConsoleFn = (...args: unknown[]) => void;\n\nfunction installConsoleCapture(options: SessionEventCaptureOptions): () => void {\n  const methods: ConsoleLevel[] = ['debug', 'log', 'info', 'warn', 'error'];\n  const originals = new Map<ConsoleLevel, OriginalConsoleFn>();\n\n  for (const method of methods) {\n    // Kept unbound (and .apply'd) so uninstall restores the exact original.\n    const original = (console as unknown as Record<string, OriginalConsoleFn>)[method];\n    if (typeof original !== 'function') continue;\n    originals.set(method, original);\n\n    (console as unknown as Record<string, OriginalConsoleFn>)[method] = (...args: unknown[]) => {\n      // Same exclusion as console-breadcrumbs: the SDK's own internal logging\n      // is noise about the SDK, not app behavior.\n      const isOwnLog = typeof args[0] === 'string' && args[0].startsWith('[Biwave');\n      if (!isOwnLog) {\n        options.onEvent({\n          ts: Date.now(),\n          type: 'console',\n          level: method,\n          message: args\n            .map((a) => stringifyArg(a))\n            .join(' ')\n            .slice(0, MAX_CONSOLE_MESSAGE_CHARS),\n        });\n      }\n      original.apply(console, args);\n    };\n  }\n\n  return () => {\n    for (const [method, original] of originals) {\n      (console as unknown as Record<string, OriginalConsoleFn>)[method] = original;\n    }\n  };\n}\n\nfunction installNetworkCapture(options: SessionEventCaptureOptions): () => void {\n  if (typeof window.fetch !== 'function') return () => {};\n\n  const original = window.fetch.bind(window);\n\n  window.fetch = ((input: RequestInfo | URL, init?: RequestInit) => {\n    const url = resolveUrl(input);\n    if (url.startsWith(options.ignoreOrigin)) {\n      return original(input, init);\n    }\n\n    const method = resolveMethod(input, init);\n    const startTime = Date.now();\n\n    const emit = (status: number): void => {\n      options.onEvent({\n        ts: startTime,\n        type: 'network',\n        method,\n        url: url.slice(0, MAX_URL_CHARS),\n        status,\n        duration_ms: Date.now() - startTime,\n      });\n    };\n\n    return original(input, init).then(\n      (response) => {\n        emit(response.status);\n        return response;\n      },\n      (error: unknown) => {\n        emit(0); // status 0 = network failure, per the ingest contract\n        throw error;\n      },\n    );\n  }) as typeof fetch;\n\n  return () => {\n    window.fetch = original;\n  };\n}\n\ninterface XHRMeta {\n  method: string;\n  url: string;\n  startTime: number;\n}\n\ntype XHRWithBiwaveMeta = XMLHttpRequest & { __biwave?: XHRMeta };\n\nfunction installXHRCapture(options: SessionEventCaptureOptions): () => void {\n  if (typeof XMLHttpRequest !== 'function') return () => {};\n\n  const originalOpen = XMLHttpRequest.prototype.open;\n  const originalSend = XMLHttpRequest.prototype.send;\n\n  XMLHttpRequest.prototype.open = function patchedOpen(\n    this: XHRWithBiwaveMeta,\n    method: string,\n    url: string | URL,\n    ...rest: unknown[]\n  ) {\n    const urlString = typeof url === 'string' ? url : url.toString();\n    if (!urlString.startsWith(options.ignoreOrigin)) {\n      this.__biwave = { method, url: urlString, startTime: 0 };\n    }\n    return (originalOpen as (...args: unknown[]) => void).apply(this, [method, url, ...rest]);\n  } as typeof XMLHttpRequest.prototype.open;\n\n  XMLHttpRequest.prototype.send = function patchedSend(\n    this: XHRWithBiwaveMeta,\n    ...args: unknown[]\n  ) {\n    const meta = this.__biwave;\n    if (meta) {\n      meta.startTime = Date.now();\n      this.addEventListener('loadend', () => {\n        options.onEvent({\n          ts: meta.startTime,\n          type: 'network',\n          method: meta.method,\n          url: meta.url.slice(0, MAX_URL_CHARS),\n          status: this.status,\n          duration_ms: Date.now() - meta.startTime,\n        });\n      });\n    }\n    return (originalSend as (...args: unknown[]) => void).apply(this, args);\n  } as typeof XMLHttpRequest.prototype.send;\n\n  return () => {\n    XMLHttpRequest.prototype.open = originalOpen;\n    XMLHttpRequest.prototype.send = originalSend;\n  };\n}\n\n// Already captured explicitly (with HTTP status) by installNetworkCapture/installXHRCapture —\n// the resource-timing entries for these initiator types would otherwise double-report them.\nconst RESOURCE_CAPTURE_IGNORED_INITIATOR_TYPES = new Set(['fetch', 'xmlhttprequest']);\n\nfunction installResourceCapture(options: SessionEventCaptureOptions): () => void {\n  if (typeof PerformanceObserver !== 'function') return () => {};\n\n  const emitEntry = (entry: PerformanceResourceTiming): void => {\n    if (RESOURCE_CAPTURE_IGNORED_INITIATOR_TYPES.has(entry.initiatorType)) return;\n    if (entry.name.startsWith(options.ignoreOrigin)) return;\n\n    options.onEvent({\n      ts: Math.round(performance.timeOrigin + entry.startTime),\n      type: 'resource',\n      initiator_type: entry.initiatorType || 'other',\n      url: entry.name.slice(0, MAX_URL_CHARS),\n      duration_ms: Math.round(entry.duration),\n      size: entry.transferSize ?? 0,\n    });\n  };\n\n  const observer = new PerformanceObserver((list) => {\n    for (const entry of list.getEntries() as PerformanceResourceTiming[]) {\n      emitEntry(entry);\n    }\n  });\n\n  try {\n    // buffered: true replays resources that loaded before this observer was installed\n    // (e.g. the page's own initial JS/CSS/image loads).\n    observer.observe({ type: 'resource', buffered: true });\n  } catch {\n    return () => {};\n  }\n\n  return () => observer.disconnect();\n}\n\nfunction installClickCapture(options: SessionEventCaptureOptions): () => void {\n  const onClick = (event: MouseEvent): void => {\n    const el = event.target instanceof Element ? event.target : null;\n    if (!el) return;\n    options.onEvent({\n      ts: Date.now(),\n      type: 'click',\n      selector: buildSelector(el),\n      text: clickText(el, options.maskAllText),\n    });\n  };\n\n  document.addEventListener('click', onClick, { capture: true, passive: true });\n  return () => {\n    document.removeEventListener('click', onClick, { capture: true });\n  };\n}\n\nfunction installNavigationCapture(options: SessionEventCaptureOptions): () => void {\n  let lastUrl = currentRelativeUrl();\n\n  const recordNavigation = (): void => {\n    const url = currentRelativeUrl();\n    if (url === lastUrl) return;\n    options.onEvent({ ts: Date.now(), type: 'navigation', from: lastUrl, to: url });\n    lastUrl = url;\n  };\n\n  // Kept unbound (and .apply'd) so uninstall restores the exact original —\n  // .bind() would produce a new function and break identity on restore.\n  const originalPushState = history.pushState;\n  const originalReplaceState = history.replaceState;\n\n  history.pushState = function patchedPushState(...args: Parameters<typeof history.pushState>) {\n    originalPushState.apply(history, args);\n    recordNavigation();\n  };\n  history.replaceState = function patchedReplaceState(\n    ...args: Parameters<typeof history.replaceState>\n  ) {\n    originalReplaceState.apply(history, args);\n    recordNavigation();\n  };\n  window.addEventListener('popstate', recordNavigation);\n\n  return () => {\n    history.pushState = originalPushState;\n    history.replaceState = originalReplaceState;\n    window.removeEventListener('popstate', recordNavigation);\n  };\n}\n\nfunction currentRelativeUrl(): string {\n  return (window.location.pathname + window.location.search + window.location.hash).slice(\n    0,\n    MAX_URL_CHARS,\n  );\n}\n\n/** Short CSS-ish path: up to 3 ancestors, stopping early at the nearest id. */\nfunction buildSelector(el: Element): string {\n  const parts: string[] = [];\n  let node: Element | null = el;\n  while (node && node !== document.documentElement && parts.length < 3) {\n    parts.unshift(describeElement(node));\n    if (node.id) break;\n    node = node.parentElement;\n  }\n  return parts.join(' > ').slice(0, MAX_SELECTOR_CHARS);\n}\n\nfunction describeElement(el: Element): string {\n  const tag = el.tagName.toLowerCase();\n  if (el.id) return `${tag}#${el.id}`;\n  const classes = Array.from(el.classList).slice(0, 3);\n  return classes.length > 0 ? `${tag}.${classes.join('.')}` : tag;\n}\n\n/** Input *values* are never read here — only rendered text content, and none at all under maskAllText (mirroring the replay's masking). */\nfunction clickText(el: Element, maskAllText: boolean): string {\n  if (maskAllText && !el.closest('.biwave-unmask')) return '';\n  const raw = (el as HTMLElement).innerText ?? el.textContent ?? '';\n  return raw.replace(/\\s+/g, ' ').trim().slice(0, MAX_CLICK_TEXT_CHARS);\n}\n\nfunction stringifyArg(value: unknown): string {\n  if (typeof value === 'string') return value;\n  try {\n    return JSON.stringify(value) ?? String(value);\n  } catch {\n    return String(value);\n  }\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\nfunction resolveMethod(input: RequestInfo | URL, init: RequestInit | undefined): string {\n  if (init?.method) return init.method;\n  if (input instanceof Request) return input.method;\n  return 'GET';\n}\n","// Copyright 2026 Bitech.id. Licensed under the MIT License.\n\n/**\n * Gzips a JSON-serializable value via the native CompressionStream API\n * (available in all modern target browsers). Falls back to uncompressed\n * bytes only if CompressionStream isn't available — callers must still\n * enforce max_chunk_bytes against the returned size either way.\n */\nexport async function gzipJson(value: unknown): Promise<ArrayBuffer> {\n  const bytes = new TextEncoder().encode(JSON.stringify(value));\n\n  if (typeof CompressionStream === 'undefined') {\n    // .slice() copies into a plain, non-generic ArrayBuffer.\n    return bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);\n  }\n\n  const stream = new CompressionStream('gzip');\n  const writer = stream.writable.getWriter();\n  void writer.write(bytes);\n  void writer.close();\n\n  return new Response(stream.readable).arrayBuffer();\n}\n","// Copyright 2026 Bitech.id. Licensed under the MIT License.\n\nimport { record } from 'rrweb';\n\nconst CHECKOUT_EVERY_MS = 60_000;\n\nexport interface RecorderOptions {\n  /** Default false — text is recorded as-is (LogRocket-style: what the user saw is what replays). Set true to mask all text nodes (per-element opt-out via the 'biwave-unmask' class). */\n  maskAllText: boolean;\n  onEvent: (event: unknown, isCheckout: boolean) => void;\n}\n\n/**\n * Thin wrapper around rrweb's record() — records the UI as the user saw it\n * (LogRocket-style). Only password input values are masked; that one is\n * never negotiable. Canvas is not recorded.\n */\nexport function startRecorder(options: RecorderOptions): () => void {\n  const stop = record({\n    emit(event, isCheckout) {\n      options.onEvent(event, Boolean(isCheckout));\n    },\n    checkoutEveryNms: CHECKOUT_EVERY_MS,\n\n    // Replay shows what the user saw — only passwords are masked, always.\n    // When maskAllText is opted into, the 'biwave-unmask' escape hatch is a\n    // selector exclusion (rrweb has no separate \"unmask class\" option) — an\n    // element matching it is simply never matched by maskTextSelector.\n    maskAllInputs: false,\n    maskTextSelector: options.maskAllText ? '*:not(.biwave-unmask)' : undefined,\n    maskInputOptions: {\n      password: true,\n    },\n    blockClass: 'biwave-block',\n    maskTextClass: 'biwave-mask',\n    ignoreClass: 'biwave-ignore',\n    recordCanvas: false,\n  });\n\n  return stop ?? (() => {});\n}\n","// Copyright 2026 Bitech.id. Licensed under the MIT License.\n\ninterface TimestampedEvent {\n  event: unknown;\n  timestampMs: number;\n}\n\n/**\n * Holds the last `bufferSeconds` of rrweb events in memory without\n * uploading them — used in 'buffered' mode so a session that turns out to\n * hit an error can be promoted and its recent history uploaded, instead of\n * only capturing what happens *after* the error.\n */\nexport class RingBuffer {\n  private events: TimestampedEvent[] = [];\n\n  constructor(private readonly bufferSeconds: number) {}\n\n  add(event: unknown, timestampMs: number): void {\n    this.events.push({ event, timestampMs });\n    this.evictOlderThan(Date.now() - this.bufferSeconds * 1000);\n  }\n\n  private evictOlderThan(cutoffMs: number): void {\n    let dropCount = 0;\n    while (dropCount < this.events.length && this.events[dropCount]!.timestampMs < cutoffMs) {\n      dropCount++;\n    }\n    if (dropCount > 0) this.events.splice(0, dropCount);\n  }\n\n  /** Drains and returns all buffered events, oldest first, clearing the buffer. */\n  drain(): unknown[] {\n    const drained = this.events.map((e) => e.event);\n    this.events = [];\n    return drained;\n  }\n\n  get size(): number {\n    return this.events.length;\n  }\n}\n","// Copyright 2026 Bitech.id. Licensed under the MIT License.\n\n// Minimal UUIDv7 (time-ordered) generator — no dependency. A session_id must\n// be time-ordered and generated client-side before any network call, so a\n// crash-buffer flush can stamp events with it even if the init call never\n// completes.\nexport function generateUuidV7(): string {\n  const timestampMs = BigInt(Date.now());\n  const bytes = new Uint8Array(16);\n\n  bytes[0] = Number((timestampMs >> 40n) & 0xffn);\n  bytes[1] = Number((timestampMs >> 32n) & 0xffn);\n  bytes[2] = Number((timestampMs >> 24n) & 0xffn);\n  bytes[3] = Number((timestampMs >> 16n) & 0xffn);\n  bytes[4] = Number((timestampMs >> 8n) & 0xffn);\n  bytes[5] = Number(timestampMs & 0xffn);\n\n  const random = new Uint8Array(10);\n  crypto.getRandomValues(random);\n  bytes.set(random, 6);\n\n  bytes[6] = (bytes[6]! & 0x0f) | 0x70; // version 7\n  bytes[8] = (bytes[8]! & 0x3f) | 0x80; // variant\n\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","// Copyright 2026 Bitech.id. Licensed under the MIT License.\n\nimport { generateUuidV7 } from './uuid7.js';\nimport type {\n  ResolvedStreamOptions,\n  StreamLimits,\n  StreamMode,\n  StreamSessionState,\n} from './types.js';\nimport { DEFAULT_LIMITS } from './types.js';\n\nconst STORAGE_KEY = '__biwave_stream_session__';\n\nfunction readStorage(): StreamSessionState | null {\n  try {\n    const raw = sessionStorage.getItem(STORAGE_KEY);\n    if (!raw) return null;\n    return JSON.parse(raw) as StreamSessionState;\n  } catch {\n    return null;\n  }\n}\n\nfunction writeStorage(state: StreamSessionState): void {\n  try {\n    sessionStorage.setItem(STORAGE_KEY, JSON.stringify(state));\n  } catch {\n    // best-effort — a private-browsing quota error must never bubble up\n  }\n}\n\nfunction clearStorage(): void {\n  try {\n    sessionStorage.removeItem(STORAGE_KEY);\n  } catch {\n    // best-effort\n  }\n}\n\n/** Sampling roll for a brand-new session — recording, buffered (error-only), or inactive. */\nfunction rollMode(options: ResolvedStreamOptions): StreamMode | null {\n  if (Math.random() < options.sessionSampleRate) return 'recording';\n  if (Math.random() < options.errorSampleRate) return 'buffered';\n  return null;\n}\n\n/**\n * Owns Stream session lifecycle: sampling, sessionStorage persistence (so SPA\n * navigation/reload in the same tab resumes the same session), seq counter,\n * and expiry against the limits the backend returned from init.\n */\nexport class SessionManager {\n  private state: StreamSessionState | null = null;\n\n  constructor(private readonly options: ResolvedStreamOptions) {}\n\n  /** Resumes a still-valid session from this tab, or rolls sampling for a new one. Returns null if this tab isn't recording or buffering at all. */\n  start(): StreamSessionState | null {\n    const existing = readStorage();\n    if (existing && !this.isExpiredState(existing)) {\n      this.state = existing;\n      return this.state;\n    }\n\n    const mode = rollMode(this.options);\n    if (!mode) {\n      clearStorage();\n      return null;\n    }\n\n    this.state = {\n      session_id: generateUuidV7(),\n      mode,\n      started_at: Date.now(),\n      next_seq: 0,\n      limits: null,\n      init_sent: false,\n    };\n    writeStorage(this.state);\n    return this.state;\n  }\n\n  getState(): StreamSessionState | null {\n    return this.state;\n  }\n\n  getLimits(): StreamLimits {\n    return this.state?.limits ?? DEFAULT_LIMITS;\n  }\n\n  setLimits(limits: StreamLimits): void {\n    if (!this.state) return;\n    this.state.limits = limits;\n    this.state.init_sent = true;\n    writeStorage(this.state);\n  }\n\n  /** Allocates the next seq — monotonic, never reused for different content. */\n  allocateSeq(): number {\n    if (!this.state) throw new Error('no active stream session');\n    const seq = this.state.next_seq;\n    this.state.next_seq += 1;\n    writeStorage(this.state);\n    return seq;\n  }\n\n  /** Buffered -> recording, on a promote-on-error trigger. Keeps the same session_id/seq counter. */\n  promoteToRecording(): void {\n    if (!this.state || this.state.mode === 'recording') return;\n    this.state.mode = 'recording';\n    writeStorage(this.state);\n  }\n\n  isExpired(): boolean {\n    return this.state ? this.isExpiredState(this.state) : true;\n  }\n\n  private isExpiredState(state: StreamSessionState): boolean {\n    const limits = state.limits ?? DEFAULT_LIMITS;\n    if (Date.now() - state.started_at >= limits.max_session_duration_ms) return true;\n    if (state.next_seq >= limits.max_chunks) return true;\n    return false;\n  }\n\n  end(): void {\n    this.state = null;\n    clearStorage();\n  }\n}\n","// Copyright 2026 Bitech.id. Licensed under the MIT License.\n\nimport type { StreamEndReason, StreamLimits } from './types.js';\n\nconst MAX_RETRIES = 8;\nconst BASE_RETRY_DELAY_MS = 500;\nconst MAX_IN_FLIGHT = 2;\n\ninterface PendingChunk {\n  seq: number;\n  bytes: ArrayBuffer;\n  chunkTs: number;\n  retryCount: number;\n}\n\nexport interface InitSessionResponse {\n  session_id: string;\n  status: string;\n  limits: StreamLimits;\n}\n\n/**\n * Handles all network I/O for a Stream session: init, chunk upload (queued,\n * ack-based eviction, retry with backoff+jitter, respects Retry-After, max 2\n * in-flight), and end. Every method swallows its own errors — a down/slow\n * ingest must never throw into the host app (same contract as\n * @biwave/core's Transport for Trace/Log/Pulse).\n */\nexport class StreamTransport {\n  private readonly queue: PendingChunk[] = [];\n  private inFlight = 0;\n\n  constructor(\n    private readonly baseUrl: string,\n    private readonly clientId: string,\n  ) {}\n\n  async initSession(body: Record<string, unknown>): Promise<InitSessionResponse | null> {\n    try {\n      const res = await fetch(`${this.baseUrl}/stream/sessions`, {\n        method: 'POST',\n        headers: { 'Content-Type': 'application/json', 'X-Biwave-Client-Id': this.clientId },\n        body: JSON.stringify(body),\n      });\n      if (!res.ok) return null;\n      return (await res.json()) as InitSessionResponse;\n    } catch {\n      return null;\n    }\n  }\n\n  /** Queues a chunk for upload — returns immediately, delivery/retry happens in the background. */\n  enqueueChunk(sessionId: string, seq: number, bytes: ArrayBuffer, chunkTs: number): void {\n    this.queue.push({ seq, bytes, chunkTs, retryCount: 0 });\n    this.drain(sessionId);\n  }\n\n  get pendingCount(): number {\n    return this.queue.length + this.inFlight;\n  }\n\n  private drain(sessionId: string): void {\n    while (this.inFlight < MAX_IN_FLIGHT && this.queue.length > 0) {\n      const chunk = this.queue.shift();\n      if (!chunk) break;\n      this.inFlight++;\n      void this.send(sessionId, chunk).finally(() => {\n        this.inFlight--;\n        this.drain(sessionId);\n      });\n    }\n  }\n\n  private async send(sessionId: string, chunk: PendingChunk): Promise<void> {\n    try {\n      const res = await fetch(`${this.baseUrl}/stream/sessions/${sessionId}/chunks/${chunk.seq}`, {\n        method: 'PUT',\n        headers: {\n          'X-Biwave-Client-Id': this.clientId,\n          'X-Biwave-Capture-Mode': 'dom',\n          'X-Biwave-Chunk-Ts': String(chunk.chunkTs),\n          'Content-Type': 'application/json',\n        },\n        // Wrapped in a Blob — some TS/lib.dom versions don't structurally\n        // accept a typed array as BodyInit even though fetch() supports it\n        // natively; a Blob sidesteps that entirely.\n        body: new Blob([chunk.bytes]),\n      });\n\n      // 2xx: acked, already evicted (shift()'d out of the queue in drain()).\n      // 400/413: permanent — content is invalid or oversized, retrying won't help.\n      if (res.ok || res.status === 400 || res.status === 413) return;\n\n      this.retryOrDrop(sessionId, chunk, res.headers.get('Retry-After'));\n    } catch {\n      this.retryOrDrop(sessionId, chunk, null);\n    }\n  }\n\n  private retryOrDrop(\n    sessionId: string,\n    chunk: PendingChunk,\n    retryAfterHeader: string | null,\n  ): void {\n    if (chunk.retryCount >= MAX_RETRIES) return; // drop this seq, don't hold up the rest\n\n    const retryAfterSeconds = retryAfterHeader ? Number(retryAfterHeader) : NaN;\n    const backoff = BASE_RETRY_DELAY_MS * 2 ** chunk.retryCount;\n    const jitter = Math.random() * backoff * 0.3;\n    const delay = Number.isFinite(retryAfterSeconds) ? retryAfterSeconds * 1000 : backoff + jitter;\n\n    setTimeout(() => {\n      this.queue.push({ ...chunk, retryCount: chunk.retryCount + 1 });\n      this.drain(sessionId);\n    }, delay);\n  }\n\n  /**\n   * Fire-and-forget session-events batch (console/network/click/navigation).\n   * Deliberately no retry queue — the contract with the backend is\n   * best-effort: duplicates are tolerated, losses are acceptable, and a\n   * failed batch must never build up memory or traffic pressure.\n   */\n  sendEvents(sessionId: string, events: unknown[], keepalive = false): void {\n    if (events.length === 0) return;\n    const url = `${this.baseUrl}/stream/sessions/${sessionId}/events`;\n    const body = JSON.stringify({ client_id: this.clientId, events });\n\n    if (keepalive) {\n      this.sendKeepalive(url, 'POST', body);\n      return;\n    }\n\n    try {\n      void fetch(url, {\n        method: 'POST',\n        headers: { 'Content-Type': 'application/json', 'X-Biwave-Client-Id': this.clientId },\n        body,\n      }).catch(() => {\n        // best-effort — swallow\n      });\n    } catch {\n      // swallow synchronous throws too\n    }\n  }\n\n  endSession(\n    sessionId: string,\n    body: { ended_at: number; last_seq: number; chunk_count: number; reason: StreamEndReason },\n  ): void {\n    this.sendKeepalive(\n      `${this.baseUrl}/stream/sessions/${sessionId}/end`,\n      'POST',\n      JSON.stringify(body),\n    );\n  }\n\n  /**\n   * Best-effort chunk send for unload time (visibilitychange/pagehide) —\n   * bypasses the retry queue entirely since there's no more page left to\n   * retry from; either it lands or the backend's idle sweeper finalizes the\n   * session without it.\n   */\n  sendChunkKeepalive(sessionId: string, seq: number, bytes: ArrayBuffer, chunkTs: number): void {\n    this.sendKeepalive(\n      `${this.baseUrl}/stream/sessions/${sessionId}/chunks/${seq}`,\n      'PUT',\n      new Blob([bytes]),\n      { 'X-Biwave-Capture-Mode': 'dom', 'X-Biwave-Chunk-Ts': String(chunkTs) },\n    );\n  }\n\n  /**\n   * navigator.sendBeacon() can't set custom headers, so it can't carry\n   * X-Biwave-Client-Id — using it would silently fail auth. fetch's\n   * `keepalive: true` does support headers and survives page unload in all\n   * evergreen browsers, so it's used here instead for every unload-time\n   * send (never blocks the page from closing; failures are swallowed).\n   */\n  private sendKeepalive(\n    url: string,\n    method: 'POST' | 'PUT',\n    body: BodyInit,\n    extraHeaders: Record<string, string> = {},\n  ): void {\n    try {\n      void fetch(url, {\n        method,\n        headers: {\n          'Content-Type': 'application/json',\n          'X-Biwave-Client-Id': this.clientId,\n          ...extraHeaders,\n        },\n        body,\n        keepalive: true,\n      }).catch(() => {\n        // best-effort — swallow, the backend's idle sweeper will finalize the session anyway\n      });\n    } catch {\n      // swallow synchronous throws too (e.g. an unsupported `keepalive` option in an old browser)\n    }\n  }\n}\n","// Copyright 2026 Bitech.id. Licensed under the MIT License.\n\nimport type { BiwaveClient } from '@biwave/core';\nimport { installSessionEventCapture } from './events.js';\nimport type { SessionEvent } from './events.js';\nimport { gzipJson } from './gzip.js';\nimport { startRecorder } from './recorder.js';\nimport { RingBuffer } from './ring-buffer.js';\nimport { SessionManager } from './session-manager.js';\nimport { setErrorCapturedHook, setReplaySessionId, setStopRequestedHook } from './session-ref.js';\nimport { StreamTransport } from './transport.js';\nimport type { ResolvedStreamOptions, StreamEndReason } from './types.js';\n\nconst FLUSH_INTERVAL_MS = 10_000;\n// Heuristic proxy for a ~256-512KB gzipped chunk — rrweb DOM mutation JSON\n// typically compresses 5-10x, so this is checked periodically (not on every\n// event, which would mean re-stringifying the whole buffer constantly) and\n// is only ever a *trigger* for an early flush; the actual 1MB cap is\n// enforced against the real gzipped size in uploadEventsInBudget().\nconst TARGET_CHUNK_RAW_BYTES = 2 * 1024 * 1024;\nconst SIZE_CHECK_EVERY_N_EVENTS = 20;\n\n// Session events (console/network/click/navigation) — per the ingest\n// contract: batched ±5s / 50 events, max 500 per request, soft cap of\n// 10k per session (beyond it the SDK just stops capturing).\nconst SESSION_EVENTS_FLUSH_INTERVAL_MS = 5_000;\nconst SESSION_EVENTS_BATCH_SIZE = 50;\nconst SESSION_EVENTS_MAX_PER_REQUEST = 500;\nconst SESSION_EVENTS_MAX_PER_SESSION = 10_000;\n\ninterface RRwebEventLike {\n  timestamp?: number;\n}\n\nfunction detectDevice(): { os: string; browser: string; model: null } {\n  const ua = typeof navigator !== 'undefined' ? navigator.userAgent : '';\n\n  let os = 'unknown';\n  if (/Windows/.test(ua)) os = 'Windows';\n  else if (/Mac OS X/.test(ua)) os = 'macOS';\n  else if (/Android/.test(ua)) os = 'Android';\n  else if (/iPhone|iPad|iPod/.test(ua)) os = 'iOS';\n  else if (/Linux/.test(ua)) os = 'Linux';\n\n  let browser = 'unknown';\n  if (/Edg\\//.test(ua)) browser = 'Edge';\n  else if (/Chrome\\//.test(ua)) browser = 'Chrome';\n  else if (/Firefox\\//.test(ua)) browser = 'Firefox';\n  else if (/Safari\\//.test(ua) && !/Chrome/.test(ua)) browser = 'Safari';\n\n  return { os, browser, model: null };\n}\n\nexport interface StreamControllerDeps {\n  client: BiwaveClient;\n  clientId: string;\n  endpoint: string;\n  environment: string | undefined;\n  sdkVersion: string;\n  options: ResolvedStreamOptions;\n}\n\n/**\n * Owns a single Stream (session replay) session end to end: sampling,\n * recording, chunk buffering/flushing, the buffered-mode ring buffer and\n * its promote-on-error path, and session teardown. Instantiated by\n * @biwave/browser's init() via a dynamic import — see index.ts — so apps\n * that don't enable Stream never load rrweb.\n */\nexport class StreamController {\n  private readonly sessionManager: SessionManager;\n  private readonly transport: StreamTransport;\n  private readonly client: BiwaveClient;\n  private readonly environment: string | undefined;\n  private readonly sdkVersion: string;\n  private readonly options: ResolvedStreamOptions;\n  private readonly endpoint: string;\n\n  private ringBuffer: RingBuffer | null = null;\n  private currentChunkEvents: unknown[] = [];\n  private eventsSinceSizeCheck = 0;\n  private stopRecorder: (() => void) | null = null;\n  private flushTimer: ReturnType<typeof setInterval> | null = null;\n  private durationTimer: ReturnType<typeof setTimeout> | null = null;\n  private ended = false;\n\n  // Session events (console/network/click/navigation) — a second, lighter\n  // pipeline alongside the rrweb chunk stream, mirroring its two modes:\n  // pending array + flush timer when recording, ring buffer when buffered.\n  private pendingSessionEvents: SessionEvent[] = [];\n  private sessionEventsRing: RingBuffer | null = null;\n  private stopEventCapture: (() => void) | null = null;\n  private sessionEventsFlushTimer: ReturnType<typeof setInterval> | null = null;\n  private sessionEventCount = 0;\n\n  private readonly handleVisibilityChange = (): void => {\n    if (document.visibilityState === 'hidden') this.flushForUnload();\n  };\n\n  private readonly handlePageHide = (): void => {\n    if (this.ended) return;\n    this.flushForUnload();\n\n    const state = this.sessionManager.getState();\n    if (!state || state.mode !== 'recording') return;\n\n    this.stopRecorder?.();\n    this.stopEventCapture?.();\n    if (this.flushTimer) clearInterval(this.flushTimer);\n    if (this.sessionEventsFlushTimer) clearInterval(this.sessionEventsFlushTimer);\n    if (this.durationTimer) clearTimeout(this.durationTimer);\n    document.removeEventListener('visibilitychange', this.handleVisibilityChange);\n    window.removeEventListener('pagehide', this.handlePageHide);\n\n    setReplaySessionId(undefined);\n    setErrorCapturedHook(undefined);\n    setStopRequestedHook(undefined);\n\n    this.transport.endSession(state.session_id, {\n      ended_at: Date.now(),\n      last_seq: Math.max(0, state.next_seq - 1),\n      chunk_count: state.next_seq,\n      reason: 'normal',\n    });\n\n    this.sessionManager.end();\n    this.ended = true;\n  };\n\n  constructor(deps: StreamControllerDeps) {\n    this.client = deps.client;\n    this.environment = deps.environment;\n    this.sdkVersion = deps.sdkVersion;\n    this.options = deps.options;\n    this.endpoint = deps.endpoint;\n    this.sessionManager = new SessionManager(deps.options);\n    this.transport = new StreamTransport(`${deps.endpoint}/api`, deps.clientId);\n  }\n\n  /** Never throws — any internal failure is swallowed (console.debug only), per the SDK's own contract. */\n  start(): void {\n    try {\n      this.startUnsafe();\n    } catch (err) {\n      console.debug('[Biwave Stream] failed to start', err);\n    }\n  }\n\n  private startUnsafe(): void {\n    const state = this.sessionManager.start();\n    if (!state) return; // sampled out entirely — no recording, no buffering\n\n    setReplaySessionId(state.session_id);\n    setErrorCapturedHook(() => this.onErrorCaptured());\n    setStopRequestedHook((reason) => this.stop(reason));\n\n    if (state.mode === 'buffered') {\n      this.ringBuffer = new RingBuffer(this.options.bufferSeconds);\n      this.sessionEventsRing = new RingBuffer(this.options.bufferSeconds);\n    } else if (!state.init_sent) {\n      void this.sendInit(state.session_id, state.started_at);\n    }\n\n    this.stopRecorder = startRecorder({\n      maskAllText: this.options.maskAllText,\n      onEvent: (event, isCheckout) => this.onEvent(event, isCheckout),\n    });\n\n    if (this.options.captureEvents) {\n      this.stopEventCapture = installSessionEventCapture({\n        ignoreOrigin: new URL(this.endpoint).origin,\n        maskAllText: this.options.maskAllText,\n        onEvent: (event) => this.onSessionEvent(event),\n      });\n      this.sessionEventsFlushTimer = setInterval(\n        () => this.flushSessionEvents(),\n        SESSION_EVENTS_FLUSH_INTERVAL_MS,\n      );\n      (this.sessionEventsFlushTimer as unknown as { unref?: () => void }).unref?.();\n    }\n\n    this.flushTimer = setInterval(() => void this.flushCurrentChunk(), FLUSH_INTERVAL_MS);\n    (this.flushTimer as unknown as { unref?: () => void }).unref?.();\n\n    const limits = this.sessionManager.getLimits();\n    const remainingMs = Math.max(\n      0,\n      limits.max_session_duration_ms - (Date.now() - state.started_at),\n    );\n    this.durationTimer = setTimeout(() => this.stop('normal'), remainingMs);\n\n    document.addEventListener('visibilitychange', this.handleVisibilityChange);\n    window.addEventListener('pagehide', this.handlePageHide);\n  }\n\n  private async sendInit(sessionId: string, startedAt: number): Promise<void> {\n    const response = await this.transport.initSession({\n      session_id: sessionId,\n      platform: 'web',\n      capture_mode: 'dom',\n      environment: this.environment,\n      started_at: startedAt,\n      sdk: { name: 'biwave-browser', version: this.sdkVersion },\n      device: detectDevice(),\n      user: this.client.scope.getUser(),\n    });\n\n    if (response) {\n      this.sessionManager.setLimits(response.limits);\n    }\n  }\n\n  private onEvent(event: unknown, _isCheckout: boolean): void {\n    const state = this.sessionManager.getState();\n    if (!state) return;\n\n    if (state.mode === 'buffered') {\n      this.ringBuffer?.add(event, Date.now());\n      return;\n    }\n\n    this.currentChunkEvents.push(event);\n    this.eventsSinceSizeCheck += 1;\n\n    if (this.eventsSinceSizeCheck >= SIZE_CHECK_EVERY_N_EVENTS) {\n      this.eventsSinceSizeCheck = 0;\n      const estimatedRawSize = JSON.stringify(this.currentChunkEvents).length;\n      if (estimatedRawSize >= TARGET_CHUNK_RAW_BYTES) {\n        void this.flushCurrentChunk();\n      }\n    }\n\n    if (this.sessionManager.isExpired()) {\n      this.stop('normal');\n    }\n  }\n\n  private onSessionEvent(event: SessionEvent): void {\n    const state = this.sessionManager.getState();\n    if (!state || this.ended) return;\n    if (this.sessionEventCount >= SESSION_EVENTS_MAX_PER_SESSION) return;\n    this.sessionEventCount += 1;\n\n    if (state.mode === 'buffered') {\n      this.sessionEventsRing?.add(event, event.ts);\n      return;\n    }\n\n    this.pendingSessionEvents.push(event);\n    if (this.pendingSessionEvents.length >= SESSION_EVENTS_BATCH_SIZE) {\n      this.flushSessionEvents();\n    }\n  }\n\n  private flushSessionEvents(keepalive = false): void {\n    if (this.pendingSessionEvents.length === 0) return;\n    const state = this.sessionManager.getState();\n    const events = this.pendingSessionEvents;\n    this.pendingSessionEvents = [];\n    if (!state || state.mode !== 'recording') return;\n    this.sendEventsBatched(state.session_id, events, keepalive);\n  }\n\n  /** The regular flush never exceeds the batch size, but a drained ring buffer can — slice to the contract's per-request max. */\n  private sendEventsBatched(sessionId: string, events: SessionEvent[], keepalive = false): void {\n    for (let i = 0; i < events.length; i += SESSION_EVENTS_MAX_PER_REQUEST) {\n      this.transport.sendEvents(\n        sessionId,\n        events.slice(i, i + SESSION_EVENTS_MAX_PER_REQUEST),\n        keepalive,\n      );\n    }\n  }\n\n  private async flushCurrentChunk(): Promise<void> {\n    if (this.currentChunkEvents.length === 0) return;\n    const events = this.currentChunkEvents;\n    this.currentChunkEvents = [];\n    this.eventsSinceSizeCheck = 0;\n    await this.uploadEventsInBudget(events).catch(() => {\n      // swallow — best-effort; the backend's idle sweeper finalizes the session without this chunk\n    });\n  }\n\n  /** Splits recursively until every batch's gzipped size fits under the backend's max_chunk_bytes. */\n  private async uploadEventsInBudget(events: unknown[]): Promise<void> {\n    if (events.length === 0) return;\n    const state = this.sessionManager.getState();\n    if (!state) return;\n\n    const gzipped = await gzipJson(events);\n\n    // State may have been cleared (e.g. by stop()) during the await above.\n    if (!this.sessionManager.getState()) return;\n\n    const limits = this.sessionManager.getLimits();\n\n    if (gzipped.byteLength > limits.max_chunk_bytes && events.length > 1) {\n      const mid = Math.floor(events.length / 2);\n      await this.uploadEventsInBudget(events.slice(0, mid));\n      await this.uploadEventsInBudget(events.slice(mid));\n      return;\n    }\n\n    const chunkTs = this.lastEventTimestamp(events);\n    const seq = this.sessionManager.allocateSeq();\n    this.transport.enqueueChunk(state.session_id, seq, gzipped, chunkTs);\n  }\n\n  private lastEventTimestamp(events: unknown[]): number {\n    const last = events[events.length - 1] as RRwebEventLike | undefined;\n    return last?.timestamp ?? Date.now();\n  }\n\n  private onErrorCaptured(): void {\n    const state = this.sessionManager.getState();\n    if (!state || state.mode !== 'buffered') return;\n\n    this.sessionManager.promoteToRecording();\n    const bufferedEvents = this.ringBuffer?.drain() ?? [];\n    this.ringBuffer = null;\n    const bufferedSessionEvents = (this.sessionEventsRing?.drain() ?? []) as SessionEvent[];\n    this.sessionEventsRing = null;\n\n    // Chunks may upload before init lands or even succeeds — the backend\n    // accepts chunks (and session events) for a not-yet-initialized session\n    // and enriches it later.\n    if (!state.init_sent) void this.sendInit(state.session_id, state.started_at);\n    void this.uploadEventsInBudget(bufferedEvents);\n    this.sendEventsBatched(state.session_id, bufferedSessionEvents);\n  }\n\n  /** Best-effort flush of whatever's queued, via keepalive — called on visibilitychange/pagehide. Never blocks unload. */\n  private flushForUnload(): void {\n    if (this.ended) return;\n    const state = this.sessionManager.getState();\n    if (!state || state.mode !== 'recording') return;\n\n    this.flushSessionEvents(true);\n\n    if (this.currentChunkEvents.length === 0) return;\n\n    const events = this.currentChunkEvents;\n    this.currentChunkEvents = [];\n    void gzipJson(events)\n      .then((gzipped) => {\n        const limits = this.sessionManager.getLimits();\n        if (gzipped.byteLength > limits.max_chunk_bytes) return; // best-effort — accept the gap, don't split at unload time\n        const seq = this.sessionManager.allocateSeq();\n        this.transport.sendChunkKeepalive(\n          state.session_id,\n          seq,\n          gzipped,\n          this.lastEventTimestamp(events),\n        );\n      })\n      .catch(() => {\n        // swallow — the backend's idle sweeper finalizes the session regardless\n      });\n  }\n\n  /** Stops recording and signals the backend the session is over (best-effort). Safe to call more than once. */\n  stop(reason: StreamEndReason): void {\n    if (this.ended) return;\n    this.ended = true;\n\n    this.stopRecorder?.();\n    this.stopEventCapture?.();\n    if (this.flushTimer) clearInterval(this.flushTimer);\n    if (this.sessionEventsFlushTimer) clearInterval(this.sessionEventsFlushTimer);\n    if (this.durationTimer) clearTimeout(this.durationTimer);\n    document.removeEventListener('visibilitychange', this.handleVisibilityChange);\n    window.removeEventListener('pagehide', this.handlePageHide);\n\n    setReplaySessionId(undefined);\n    setErrorCapturedHook(undefined);\n    setStopRequestedHook(undefined);\n\n    const state = this.sessionManager.getState();\n    // A session still in 'buffered' mode was never promoted/init'd — nothing exists on the backend to end.\n    if (!state || state.mode === 'buffered') {\n      this.sessionManager.end();\n      return;\n    }\n\n    // Inline flush: allocate seq now (session state is still valid), gzip +\n    // enqueue happen async after sessionManager.end(). This avoids the async\n    // gap between gzipJson and allocateSeq that would hit null state.\n    if (this.currentChunkEvents.length > 0) {\n      const pendingEvents = this.currentChunkEvents;\n      this.currentChunkEvents = [];\n      const seq = this.sessionManager.allocateSeq();\n      const lastTs = this.lastEventTimestamp(pendingEvents);\n      void gzipJson(pendingEvents).then((gzipped) => {\n        this.transport.enqueueChunk(state.session_id, seq, gzipped, lastTs);\n      });\n    }\n\n    this.flushSessionEvents();\n\n    this.transport.endSession(state.session_id, {\n      ended_at: Date.now(),\n      last_seq: Math.max(0, state.next_seq - 1),\n      chunk_count: state.next_seq,\n      reason,\n    });\n\n    this.sessionManager.end();\n  }\n}\n"],"mappings":"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","names":[]}