/** * The event kinds the browser SDK ships today. This is the DEFAULT vocabulary, * not the only permitted one — see `BaseEvent`. */ type KnownEventType = "dom.event" | "exception" | "network" | "log" | "pageload" | "navigation" | "custom" | "performance" | "replay"; /** * `TType` is what lets a platform package name its own event kinds without * editing core: React Native can pass `KnownEventType | "tap" | "screen_view"` * and every core class below flows it through. It defaults to * `KnownEventType`, so nothing that only deals in the shipped browser kinds * has to spell it out. * * Shared shapes are still shared — the point is that the set of names is open, * not that each platform reinvents the envelope. */ type BaseEvent = { type: TType; timestamp?: number; end_timestamp?: number; start_timestamp?: number; span_name?: string; id: string; spanId: string; parentSpanId: string | undefined; traceId: string | undefined; attributes?: Record; }; type UserIdentifiers = { id: string; email: string; role: string; name: string; organization: string; properties: Record; }; type DomEventAttributes = { dom_event_type: string; dom_event_coordinates: { clientX: number; clientY: number; }; dom_event_target: { tagName: string; id: string; className: string; text: string; role: string; accessibleName: string; ariaLabel: string; title: string; alt: string; placeholder: string; name: string; inputType: string; href: string; }; dom_event_selector: string; dom_event_key_code: string; }; type NetworkEventAttributes = { type: "HTTP"; resource_name: string; status: string; subType: string; level?: string; timestamp?: number; operation: { name: string; startTime?: number; endTime?: number; }; url: { full: string; }; http: { route: string; path: string; status: string; method: string; request: { headers: Record; method: string; }; response: { headers: Record; status_code: string; }; duration_ms?: number; }; gc: { request: { body: string; }; response: { body: string; }; }; error?: { type: string; }; }; type Stacktrace = { filename: string; function: string; lineno: number; colno: number; }; type ErrorEventAttributes = { error_type: string; error_message: string; error_stacktrace?: Array; error_fingerprint: string; error_handled: boolean; error_metadata?: Record; }; declare const LOG_LEVELS: readonly ["log", "info", "warn", "error", "debug", "trace"]; type LogLevel = (typeof LOG_LEVELS)[number]; type LogEventAttributes = { message: string; level: string; } & Record; type PageLoadEventAttributes = { page_url: string; page_resources: { count: number; totalSize: number; totalDuration: number; byType: { [key: string]: { count: number; size: number; duration: number; }; }; }; page_referrer: string; page_load_time: number; }; type NavigationEventAttributes = { page_url: string; from_url?: string; metadata?: Record; duration_ms: number; start_timestamp: number; end_timestamp: number; }; type UserDefinedEventAttributes = { custom_event_name: string; custom_event_attributes?: Record; }; type PerformanceEventAttributes = { performance_metric_name: string; performance_metric_value: number; performance_metric_id: string; performance_metric_navigation_type: string; }; type ReplayEventAttributes = { /** * Groundcover session replay payload. * * NOTE: This key is intentionally prefixed to avoid collisions with customer attributes. */ _gc_replay_data: { events: string[]; }; /** * Indicates this batch starts with a full DOM snapshot. * Full snapshots are taken at regular intervals to allow seeking directly to any point. * Queryable for filtering/indexing purposes. */ replay_is_full_snapshot?: boolean; /** * Timestamp when the full snapshot was taken (if replay_is_full_snapshot is true). */ replay_full_snapshot_timestamp?: number; }; type Event$1 = Omit, "attributes"> & { type: T; attributes: A; }; type EventTypes$1 = { "dom.event": Event$1<"dom.event", DomEventAttributes>; exception: Event$1<"exception", ErrorEventAttributes>; network: Event$1<"network", NetworkEventAttributes>; log: Event$1<"log", LogEventAttributes>; pageload: Event$1<"pageload", PageLoadEventAttributes>; navigation: Event$1<"navigation", NavigationEventAttributes>; custom: Event$1<"custom", UserDefinedEventAttributes>; performance: Event$1<"performance", PerformanceEventAttributes>; replay: Event$1<"replay", ReplayEventAttributes>; }; type PrivacyLevel = "mask-sensitive" | "mask-all" | "allow"; /** The non-replay event surface a redactor field belongs to. */ type RedactKind = "request-body" | "response-body" | "query" | "header" | "log" | "error"; interface RedactField { /** Immediate key of the value; `""` for whole-string fields (log/error message). */ key: string; /** The leaf value — always a primitive, never an object/array. */ value: string | number | boolean | null; /** Full key path to this leaf; `[]` for whole-string fields. */ path: string[]; /** Which event surface this field came from (header name is in `key`). */ kind: RedactKind; /** Whether the built-in patterns + `sensitiveKeys` would redact this field. */ sensitive: boolean; } /** * Per-field redaction hook. Invoked on each LEAF value during the redaction * walk (never on objects/arrays — the SDK recurses those itself and never * passes them here). Return a primitive replacement, or `undefined` to defer * to the SDK default (`sensitive ? '[REDACTED]' : value`) — so a hook that * only cares about one field can't accidentally disable masking elsewhere. */ type Redactor = (field: RedactField) => string | number | boolean | null | undefined; interface PrivacyOptions$1 { /** * Master switch for data masking. `'mask-sensitive'` (default) masks only * SENSITIVE data (sensitive-key matches, platform-flagged UI elements) and * redacts network/log/error payloads while capturing the rest; * `'mask-all'` also masks all captured input/text; `'allow'` opts out. * Platform packages define what "sensitive UI element" means on their host. */ level?: PrivacyLevel; /** Redact network request/response bodies. Default on unless `level` is `'allow'`. */ maskNetworkBodies?: boolean; /** Redact network URL query params. Default on unless `level` is `'allow'`. */ maskNetworkQueryParams?: boolean; /** Redact console log messages and attributes. Default on unless `level` is `'allow'`. */ maskLogs?: boolean; /** Redact error messages, metadata and stack-frame URLs. Default on unless `level` is `'allow'`. */ maskErrors?: boolean; /** Extra case-insensitive key substrings treated as sensitive, merged with the built-in patterns. */ sensitiveKeys?: string[]; /** * Per-field custom redaction hook for non-replay events. Called on each leaf * value during the redaction walk with the original typed value; see * {@link Redactor}. For arbitrary whole-event changes use `enrichEvent`. */ redact?: Redactor; /** * Session-recording masking — replay is a platform feature (rrweb on the * browser), so its masking surface is typed by the platform package: the * browser SDK narrows this to `{ maskTextFn?, maskInputFn? }` over * HTMLElement (see the browser package's `config/types.ts`). Core never * reads it — it is resolved platform-side at record() time. */ replay?: unknown; } /** Distributed-tracing header propagation for outgoing network requests. */ interface TracingOptions { /** Request URLs (prefix match) that receive injected tracing headers. */ propagationUrls?: string[]; /** Inbound header names to read/propagate onto traced requests. */ propagationHeaders?: string[]; /** Header name carrying the trace id. */ traceIdHeaderName?: string; /** Header name carrying the span id. */ spanIdHeaderName?: string; /** Origin tag stamped on injected trace headers. */ origin?: { name: string; value: string; }; } /** Batching and delivery of outgoing event batches. */ interface TransportOptions { /** Max events buffered before a batch is flushed (default 10). */ batchSize?: number; /** Max ms a batch waits before flushing regardless of size (default 10000). */ batchTimeout?: number; /** Gzip-compress outgoing batches; offloaded to the Web Worker when available (default true). */ compression?: boolean; } interface SDKOptions$1 = EventTypes$1[keyof EventTypes$1]> { /** * Which signal listeners to enable, by name. Empty array = all. The NAMES * are platform-defined (each platform ships its own listener set) — the * platform package narrows this to its literal union (see the browser * package's `config/types.ts`). */ enabledEvents: string[]; eventSampleRate: number; sessionSampleRate: number; debug: boolean; excludedUrls?: Array; beforeSend?: (event: TEvent) => boolean; enrichEvent?: (event: TEvent) => TEvent; /** * Unified privacy / data-masking config driving replay + non-replay masking. * ON by default (`level: 'mask-sensitive'`); see {@link PrivacyOptions}. */ privacy?: PrivacyOptions$1; /** Distributed-tracing header propagation; see {@link TracingOptions}. */ tracing?: TracingOptions; /** Batching & delivery of outgoing events; see {@link TransportOptions}. */ transport?: TransportOptions; /** * Session-recording controls — a platform feature slot core never reads. * The platform package types it (the browser SDK narrows this to its * rrweb `ReplayOptions`; platforms without recording ignore it). */ replay?: unknown; /** * Target maximum wall-clock duration of a session, in milliseconds. * * Enforced LAZILY, on activity — not by a background timer. Once the cap has * elapsed, the next user/business event (click, navigation, log, custom, * network, exception, …) flushes buffered events under the current session * id, then mints a fresh session id and restarts replay recording if it was * active. * * Because it is activity-gated, this is NOT a hard upper bound: a session * only rotates when the next qualifying event arrives. An idle or * backgrounded tab that produces no such events — including one that is only * emitting session-replay heartbeats, which never trigger rotation on their * own — keeps the same session id past the cap until activity resumes. This * is deliberate: it avoids minting "phantom" sessions for dormant tabs. (An * idle tab with replay on is ultimately bounded by the 30-minute user-idle * pause — recording stops when no user presence is detected — not by this * cap.) * * Sessions are also bounded by a 30-minute inactivity gap, enforced the same * lazy way: when a user-interaction event (click, navigation, pageload, * custom — not background network/log/performance traffic) arrives after 30+ * minutes without one, the session rotates first and replay recording * restarts for the returning user. Raw user input (scroll, pointer, key, * touch) also counts as presence even when it produces no SDK event, so * passive engagement — reading, watching — doesn't end the session. The * same gap check runs at init, so a reload after a long break also starts a * fresh session. * * The flush is best-effort and the rotation always proceeds — it does not * wait for or depend on successful delivery, so if that network request * fails the batch may be lost while the new session id still takes effect. * * Defaults to 4 hours when omitted; must be between 1 minute and 8 hours. * Values outside that range or otherwise invalid fall back to the 4-hour * default with a `console.warn`. */ sessionMaxDuration?: number; } interface SDKConfigInput$1 = EventTypes$1[keyof EventTypes$1]> { apiKey: string; cluster: string; environment: string; dsn: string; appId: string; namespace?: string; releaseId?: string; user?: Partial; options?: Partial>; sessionId?: string; } /** * The view an event was captured on. Browser-owned: core has no notion of a * "current view" — it merges whatever the platform's `enrichAttributes` * contributor returns. `makeWebViewProvider` derives these (hash-route * detection, query-param redaction) and the SessionManager contributes them * under the `location` key. */ type LocationAttributes = { path: string; url: string; title: string; }; /** * The browser's event shape. Identical to core's `Event` plus the `location` * this platform stamps during enrichment — which is why `beforeSend` / * `enrichEvent` below are re-declared over THIS map rather than core's. */ type Event = Omit, "attributes"> & { type: T; attributes: A & { location?: LocationAttributes; }; }; type EventTypes = { "dom.event": Event<"dom.event", DomEventAttributes>; exception: Event<"exception", ErrorEventAttributes>; network: Event<"network", NetworkEventAttributes>; log: Event<"log", LogEventAttributes>; pageload: Event<"pageload", PageLoadEventAttributes>; navigation: Event<"navigation", NavigationEventAttributes>; custom: Event<"custom", UserDefinedEventAttributes>; performance: Event<"performance", PerformanceEventAttributes>; replay: Event<"replay", ReplayEventAttributes>; }; /** The browser SDK's listener names for `enabledEvents`. */ type BrowserEventName = "dom" | "network" | "exceptions" | "logs" | "pageload" | "navigation" | "performance" | "replay"; /** * Session-replay (rrweb) recording controls. This is NOT a privacy surface — * to mask sensitive content use `privacy`. */ interface ReplayOptions { /** * CSS selectors whose matching elements (and their subtrees) are excluded * from session recording. Matching elements appear in the replay as empty * placeholders of their original size. Useful for skipping noisy DOM injected * by browser extensions (e.g. Grammarly). * * NOTE: this is a noise-reduction control, NOT a privacy control. To mask * sensitive content use `privacy` instead. */ blockedSelectors?: string[]; } /** Session-recording (rrweb replay) masking — the only place replay can be masked. */ interface ReplayMaskingOptions { /** rrweb `maskTextFn` pass-through. */ maskTextFn?: (text: string, el: HTMLElement | null) => string; /** rrweb `maskInputFn` pass-through. */ maskInputFn?: (text: string, el: HTMLElement) => string; } interface PrivacyOptions extends Omit { /** CSS selectors whose text/inputs are always masked (replay + DOM), regardless of `level` except `'allow'`. */ maskSelectors?: string[]; /** Session-recording (rrweb replay) masking — the only place replay can be masked. */ replay?: ReplayMaskingOptions; } interface SDKOptions extends Omit { /** * Inspect each event before it is queued; return false to drop it. Typed * over the BROWSER event map, so `attributes.location` is visible here. */ beforeSend?: (event: EventTypes[keyof EventTypes]) => boolean; /** Modify each event before it is queued. Typed over the browser event map. */ enrichEvent?: (event: EventTypes[keyof EventTypes]) => EventTypes[keyof EventTypes]; /** Which browser listeners to enable. Empty array = all. */ enabledEvents: BrowserEventName[]; /** * Unified privacy / data-masking config driving replay + non-replay masking. * ON by default (`level: 'mask-sensitive'`); see {@link PrivacyOptions}. */ privacy?: PrivacyOptions; /** * Session-replay recording controls (noise reduction). For replay MASKING use * `privacy` instead. See {@link ReplayOptions}. */ replay?: ReplayOptions; } interface SDKConfigInput extends Omit { options?: Partial; } type SDKConfigUpdate = Partial> & { user?: SDKConfigInput["user"] | null; }; declare class SessionManager { private logger; private readonly storage; private idGenerator; private core; private hideWired; private hideHandler; constructor(config: SDKConfigInput); private wireHideHandler; private unwireHideHandler; identifyUser(userIdentifier: Partial): void; updateConfig(params: SDKConfigUpdate): void; sendCustomEvent(event: { event: string; attributes: Record; }): void; startNavigation(metadata: Record): void; endNavigation(metadata: Record): void; captureException(error: Error, metadata?: Record): void; emitLog(message: string, level: LogLevel, attributes?: Record): void; getSessionId(): string; setSessionId(newSessionId?: string): Promise; startReplayRecording(): void; stopReplayRecording(): void; handoffForReinit(): void; destroy(): void; } declare class Logger { manager?: SessionManager | undefined; constructor(manager?: SessionManager | undefined); private emit; log(message: string, attributes?: Record): void; info(message: string, attributes?: Record): void; warn(message: string, attributes?: Record): void; error(message: string, attributes?: Record): void; debug(message: string, attributes?: Record): void; trace(message: string, attributes?: Record): void; } declare global { interface Window { groundcover?: typeof groundcover; } } declare function init(params?: { cluster?: string; environment?: string; namespace?: string; appId?: string; releaseId?: string; user?: Partial; dsn?: string; options?: Partial; apiKey?: string; sessionId?: string; }): void; declare function identifyUser(userIdentifier: Partial): void; declare function sendCustomEvent(params: { event: string; attributes: Record; }): void; declare function captureException(error: Error, metadata?: Record): void; declare function updateConfig(params: SDKConfigUpdate): void; declare function startNavigation(metadata: Record): void; declare function endNavigation(metadata: Record): void; declare function getSessionId(): string; declare function setSessionId(newSessionId?: string): Promise; declare function startReplayRecording(): void; declare function stopReplayRecording(): void; declare const groundcover: { init: typeof init; identifyUser: typeof identifyUser; sendCustomEvent: typeof sendCustomEvent; captureException: typeof captureException; logger: Logger; updateConfig: typeof updateConfig; startNavigation: typeof startNavigation; endNavigation: typeof endNavigation; getSessionId: typeof getSessionId; setSessionId: typeof setSessionId; startReplayRecording: typeof startReplayRecording; stopReplayRecording: typeof stopReplayRecording; }; export { type EventTypes, type PrivacyLevel, type PrivacyOptions, type RedactField, type RedactKind, type Redactor, type SDKOptions, groundcover as default };