//#region src/uploader/client-context.d.ts /** * JSON-shaped values accepted in a Context — matches `google.protobuf.Struct`. */ type ContextValue = string | number | boolean | null | ContextValue[] | { [key: string]: ContextValue; }; /** * Browser-environment metadata captured at session init. Sent verbatim in the * `context` field of the InitSession request. */ type UserAgentContext = { userAgent?: string; /** Coarse OS family — `windows`, `macos`, `ios`, `android`, `linux`, or `unknown`. */ os?: string; /** Coarse browser family — `chrome`, `firefox`, `safari`, `edge`, or `unknown`. */ browser?: string; /** Browser major version. */ browserVersion?: string; mobile?: boolean; /** BCP-47 language tag (e.g. `en-US`). */ languageCode?: string; /** IANA time zone (e.g. `Europe/Stockholm`). */ timeZone?: string; /** Viewport in CSS pixels. */ viewportWidth?: number; viewportHeight?: number; /** Physical screen in CSS pixels. */ screenWidth?: number; screenHeight?: number; devicePixelRatio?: number; /** Initial document URI — without query/hash to avoid leaking PII. */ uri?: string; /** Document referrer — without query/hash to avoid leaking PII. */ referrer?: string; }; interface ClientContext { userAgent?: UserAgentContext; [key: string]: ContextValue | undefined; } declare function collectUserAgentContext(): UserAgentContext | undefined; //#endregion //#region src/uploader/types.d.ts interface Uploader { (event: unknown): void; close(): void; } interface CreateUploaderOptions { /** Base URL of the recording backend (serves `/v1/sessions:initSession` and, by default, the WS ingest endpoint). */ apiUrl: string; /** * URL of the WebSocket ingest endpoint, including the path (e.g. * `wss://recording-ws.confidence.dev/sessions/stream`). The worker sends the session * token through the WebSocket subprotocol header. A `session_token` query parameter is * rejected. Other query parameters are retained. Optional: when omitted the worker * derives one from `apiUrl` by swapping `http(s)://` → `ws(s)://` and appending * `/sessions/stream`. Set this when the init endpoint and the WS ingest live on different * hosts (e.g. prod). */ websocketUrl?: string; /** Per-tenant secret. Hashed to scope the SharedWorker so different secrets never share a session, and sent in the `initSession` request body. */ clientSecret: string; /** * Session context sent in the InitSession request. The SDK auto-populates * `userAgent` with browser/OS/screen metadata. Pass any extra keys as * custom dimensions. */ context?: ClientContext; /** Force a worker mode for testing. Default `"auto"`. */ workerMode?: "shared" | "dedicated" | "auto"; /** * Optional override for the worker script URL. By default the bundled worker is loaded * from a `data:` URL — self-contained, no infrastructure setup, works across tabs * (`SharedWorker` is keyed by `(scriptURL, name)` and identical content yields identical * data: URLs). Provide this only if your `worker-src` CSP forbids `data:`; you can serve * the bundled worker yourself by re-exporting `workerScript` from * `csr-common/uploader` and pointing `workerUrl` at the route. */ workerUrl?: string; /** Tab-side hint expiry; cached `sessionId`s older than this are discarded on init. */ sessionTtlMs?: number; onStateChange?: (state: { sessionId: string | null; tabId: string | null; connected: boolean; /** * Token issued by `initSession`. Null until the session is established. * Most consumers should ignore this; it's exposed for tooling that needs * to call session-lifecycle endpoints directly (e.g. `closeSession`). */ sessionToken: string | null; }) => void; /** Called once when recording is permanently dead. SDK should dismantle the recorder. */ onTerminate?: (info: { reason: string; }) => void; /** * Called after an expired backend session is replaced so capture can emit a fresh full * snapshot. Required: a consumer that ignores this produces a replacement recording of * incremental mutations with no snapshot to apply them to, which cannot be replayed. */ onSessionRestart: () => void; /** * Optional verbose tracer. Called on key tab- and worker-side events * (hello/welcome, init-session URL, credential-free ws connect URL, retries, transitions). * Worker messages are forwarded over the port and tagged so you can tell them apart. */ debugLogger?: (msg: string) => void; /** @internal Override the welcome-handshake timeout for testing. */ _welcomeTimeoutMs?: number; } /** Internal: wire-level frame. Session-id is implicit (Transport is session-bound at open). */ interface Frame { tabId: string; /** Monotonic, 0-based per Recording. Resets on adoption. */ eventCounter: number; /** Opaque payload from the recorder. */ data: unknown; /** Whether the frame should refresh the backend's session inactivity timeout. */ userActivity?: boolean; /** Set only on the first frame emitted after the tab was adopted into a different session. */ adoptedFromSessionId?: string; /** Epoch millis of the adoption event. */ adoptedAt?: number; } //#endregion export { ContextValue as a, ClientContext as i, Frame as n, UserAgentContext as o, Uploader as r, collectUserAgentContext as s, CreateUploaderOptions as t };