/** * Resolves whether the capture layer crosses shadow boundaries, and how deep. * * {@link ShadowMode} is a union, so `enabled: true` always carries a positive * crossing budget and off is a single value ({@link SHADOW_OFF}). Callers branch * on `enabled` and read `maxDepth` only in the enabled arm. * * {@link ShadowGate} holds the mode for the page. It starts off and latches on * the first remote-config delivery that enables shadow support, notifying * `onArm` subscribers so they can run their one-time discovery scans (attaching * MutationObservers to existing shadow roots, registering in-shadow elements for * exposure). Subsequent deliveries do not change it — including one that * disables shadow support, which takes effect on the next page load. * * The gate is read on every captured event and on every observer callback. * Latching means those reads always agree with each other and with the scans * already performed, without threading the mode through every call. * * Rollout limitations (open roots only, latch-once per page, late * `attachShadow` discovery, DFS performance) are documented in * `packages/plugin-autocapture-browser/SHADOW-DOM.md`. */ import type { ResolvedSelectorConfig } from '@amplitude/element-selector'; /** Shadow piercing on. `maxDepth` is the number of boundaries a walk may cross. */ export type ShadowOn = { readonly enabled: true; readonly maxDepth: number; }; /** Shadow piercing off. `maxDepth` is pinned to 0 so no walk can cross. */ export type ShadowOff = { readonly enabled: false; readonly maxDepth: 0; }; /** Whether the capture layer crosses shadow boundaries, and how deep. */ export type ShadowMode = ShadowOn | ShadowOff; /** The off value. Shared rather than reconstructed, so identity checks hold. */ export declare const SHADOW_OFF: ShadowOff; /** * Project a resolved selector config onto a {@link ShadowMode}. A zero or * negative budget resolves to off, since an enabled mode that cannot cross a * boundary would behave as off while reading as on. The config resolver already * clamps into `[1, MAX_SHADOW_DOM_DEPTH]`; this covers a config that bypassed it. */ export declare const shadowModeFromConfig: (config: Pick) => ShadowMode; /** Holds the {@link ShadowMode} for a page, transitioning from off to on once. */ export interface ShadowGate { /** The current mode: {@link SHADOW_OFF} until armed, then the armed mode. */ get(): ShadowMode; /** * Apply a resolved mode. Takes effect only on the first call with an enabled * mode, which also notifies `onArm` subscribers. Later calls are ignored, * including one carrying {@link SHADOW_OFF}. Returns the current mode. */ arm(mode: ShadowMode): ShadowMode; /** * Register `cb` to run when the gate arms, or synchronously if it is already * armed. Observables use this to run their shadow discovery scan once, whether * they subscribed before or after the arming config arrived. Returns an * unsubscribe function. */ onArm(cb: (mode: ShadowOn) => void): () => void; } export declare const createShadowGate: () => ShadowGate; export declare const getSharedShadowGate: () => ShadowGate; /** * Test-only. `arm` cannot move the gate back to off, so tests that exercise the * enabled path replace the singleton to return to the off mode. */ export declare const resetSharedShadowGateForTesting: () => void; //# sourceMappingURL=shadow-mode.d.ts.map