import type { CallerType, IMilanaSessionSingleton, PublicInitOptions, SessionInfo, TrackEventAttributes, UpdatePayloadInternal } from "./types"; export declare const DEBUG_MODE_STORAGE_KEY = "milana_debug_mode"; /** * Use one tag for all events to avoid namespacing issues * * This will be repeated in every single event log * so it's worth it to save some bytes and keep it short. */ export declare const MILANA_CUSTOM_EVENT_TAG = "V"; type MilanaCallback = () => void | Promise; export declare enum StateType { Initializing = "initializing", Recording = "recording", SessionNotSampled = "session_not_sampled" } export type State = { type: StateType.Initializing; } | { type: StateType.Recording; sessionId: string; } | { type: StateType.SessionNotSampled; sessionId: string; }; /** * MilanaSession manages the lifecycle of a Milana analytics session, * including initialization, event recording, batching, retries, and user identification. */ export declare class MilanaSession implements IMilanaSessionSingleton { static currentSession: MilanaSession | null; private static queueProcessorInterval; private static queue; private productId; private clientKey; private sessionInfo; private options; state: State; private lastSendTime; private isSendingEvents; private inFlightEventsAbortController; private retryCount; private retryTimeout; private lastForcedImmediateRetryAt; private flushInterval; private events; private bufferedCharacters; private stopRrwebRecording; private recordingStartIdleCallbackId; private isRecordingStartPending; private visibilityChangeHandler; private windowFocusChangeHandler; private lastEmittedHasFocus; private pageCloseHandler; private hasSentClose; private urlTrackingCleanup; private recordingStartTime; private logMetricsInterval; private isSendingMetrics; private counters; private worstInpValues; private readonly MAX_INP_SAMPLES; private totalInpEventCount; private longTaskDurationSum; private longTaskCount; private totalLongTaskBlockingTime; private eventObserver; private longTaskObserver; private isStartingSession; private entryUrl; private debugMode; private readonly enabledIntegrations; private integrationDetectionInterval; private integrationWarmupTimeout; private callerType; private constructor(); /** * Initializes a new Milana session and sets it as the current session. * @returns { success: true } if session is started and sampled, { success: false } otherwise */ static initializeAsync(productId: string, clientKey: string, info: SessionInfo, callerType: CallerType, options?: PublicInitOptions): Promise<{ success: boolean; }>; static get debugMode(): boolean; static reset(): void; static executeWhenReady(method: string, callback: MilanaCallback): void; private static ensureQueueProcessor; private static stopQueueProcessor; private static processPendingQueue; private startOrRestartOrResumeSession; private runSessionStart; /** * Programmatically ends the current recording session. Sends a * best-effort abort signal to the server so the session is finalized * immediately, tears down all local recording machinery, and clears * `sessionStorage.sessionId` so a subsequent `init()` starts a brand- * new session rather than resuming the one we just closed. * * Each step runs under its own try/catch so a failure in one doesn't * strand a later one — e.g. an error inside `sendStopRequest()` must * not prevent us from removing rrweb and listeners, and a teardown * error must not prevent the `sessionStorage` cleanup that lets * re-`init()` start fresh. */ stop(): void; private sendUpdateRequest; private sendUpdate; private resendSavedIdentity; static sendUpdateWhenReady(method: string, payload: UpdatePayloadInternal): Promise<{ success: boolean; }>; private startIntegrationAutoDetection; private stopIntegrationAutoDetection; private runIntegrationDetection; trackEvent(eventName: string, attributes?: TrackEventAttributes): void; private lastUrl; private debouncedTrackUrlChange; private sanitizeUrl; private shouldSanitizeParameter; private trackUrlChange; private setupUrlTracking; private restartSession; private sendEvents; private _getPostInitializationHeaders; /** * Fixed-size close ping fired from `pagehide`. Event delivery belongs * to the visibility-hidden flush, so this is always ~80 bytes — fits * inside the keepalive budget even when the visibility flush filled * it to the brim. * * The URL matches the regular /batch endpoint so the CORS preflight * cache warmed by earlier batches still applies — a query-string * variant would key a different cache entry and likely fail to * complete a fresh OPTIONS during unload. */ private sendCloseRequest; /** * Issues a POST /batch for a programmatic `stopRecording()` call using * the ingest client-abort schema (`isClientAbort: true` + * `clientAbortReason: "CLIENT_STOPPED"`). Not on the unload path, so * no `keepalive: true` and no 64KB cap is needed — the full buffer * fits in a normal fetch. * * No-op when there is no recording to close (either we never reached * `Recording` or a close already fired via `pagehide`). Owning the * guard here lets callers invoke this unconditionally. */ private sendStopRequest; private clearRetryTimeout; /** * Schedules a retry for sending events, with exponential backoff. */ private scheduleRetry; private scheduleSendIfNecessary; private tryToSendEvents; private logMetrics; /** * Adds an event to the buffer and triggers sending if needed. */ private pushEvent; /** * Starts rrweb recording and sets up periodic flushing. */ private startRecording; private startRecordingAfterIdleCallback; private maskInputValue; private maskValue; private shouldMaskInputValue; private maskText; private isAlwaysMaskedInputType; private getInputType; private elementOrAncestorIsExplicitlyMaskedForInput; private elementOrAncestorIsExplicitlyMaskedForText; private elementOrAncestorCanBeUnmasked; private elementOrAncestorIsBlocked; private elementOrAncestorHasClass; private elementOrAncestorMatchesSelector; /** * Initializes performance observers for event and longtask entries. */ private initializePerformanceObservers; /** * Stops rrweb recording and flushes or drops events as needed. */ private stopRecording; } export type SessionHistograms = { /** The number of events in the event buffer. */ numEventsInBuffer: number; /** The 98th percentile of INP values. */ inpP98Ms?: number; /** The ratio of long tasks blocking the main thread. Measured as the number of milliseconds of blocking time per second of recording duration. */ blockedTimePerSecondMs?: number; averageLongTaskDurationMs?: number; }; export type SessionCounters = { numSessionsAbortedDueToBufferExceeded: number; }; export type SessionPerfMetrics = { version: 1; clientTimestamp: number; histograms: SessionHistograms; counters: SessionCounters; }; export {}; //# sourceMappingURL=session.d.ts.map