import type { SessionEvent } from "@a4anthony/proctorkit-types"; export interface EventQueueOptions { dbName?: string; maxBytes?: number; /** * IndexedDB is the normal durable mode. Memory mode is used as a * degraded fallback when the browser denies IndexedDB in a worker * context. */ storage?: "indexeddb" | "memory"; /** * When true, an IndexedDB open failure falls back to a non-durable * in-memory queue instead of failing SDK startup. Defaults to true. */ fallbackToMemory?: boolean; } /** * Prefix for the per-session IndexedDB databases the worker creates * (one per `sessionId`, named `proctoring-`). The sweep * below uses this to recognise the SDK's own leaked databases without * touching anything else on the origin. Keep in sync with the * queueFactory in worker-core.ts. */ export declare const SESSION_DB_PREFIX = "proctoring-sess"; /** * The IndexedDB database name the SDK uses for a given session. Single * source of truth for the `proctoring-` scheme so the * worker's queue factory and its stale-database sweep can't drift on * the naming. Session ids are already `sess_…`, so this yields names * under {@link SESSION_DB_PREFIX}. */ export declare function sessionDbName(sessionId: string): string; /** * IndexedDB-backed FIFO queue of session events. Survives page * reloads and tab crashes — events are only removed on explicit * {@link EventQueue.ack}, so an event that left the queue has been * confirmed durable somewhere downstream. * * Ordering is by an internal monotonic `seq` (1, 2, 3 ...), not by * the event's timestamp. Two events with identical timestamps still * have a stable order. * * Concurrent calls from JS are safe: IndexedDB serialises overlapping * `readwrite` transactions on the same object stores, so the byte and * size accounting cannot drift under contention. */ export declare class EventQueue { private db; private memory; private readonly dbName; private readonly maxBytes; private readonly storage; private readonly fallbackToMemory; constructor(options?: EventQueueOptions); /** Opens (or upgrades) the underlying IndexedDB database. Must be called once before any other method. Idempotent. */ open(): Promise; storageMode(): "indexeddb" | "memory"; storageFallbackReason(): string | null; /** * Appends an event to the tail. If the queue would exceed * `maxBytes`, drops the oldest events until it fits — the new * event is never the one dropped. Returns the count of dropped * events so callers can surface backpressure to the host. */ enqueue(event: SessionEvent): Promise<{ dropped: number; }>; /** Returns up to `limit` oldest events without removing them. */ peek(limit: number): Promise; /** * Removes events by id. Unknown ids are silently skipped so callers * can safely ack the same id twice (eg. when an idempotency-keyed * server retry returns success after we already acked locally). */ ack(ids: string[]): Promise; /** Number of events currently queued. */ size(): Promise; /** Cumulative byte size of all queued events (JSON-encoded). */ bytes(): Promise; /** Closes the database handle. Safe to call multiple times. */ close(): Promise; /** * Closes the handle AND deletes the underlying database from disk. * * Call this only once the queue is known to be fully drained — a * deleted database takes any not-yet-uploaded events with it. The * worker gates this on `size() === 0` after draining at teardown, so * an offline teardown (events still queued) keeps the database for a * later page load to flush. Reclaiming the database is what stops the * per-session databases accumulating until the origin hits its * storage quota and `open()` starts throwing. */ destroy(): Promise; /** * Best-effort reclamation of leaked per-session databases left by * earlier sessions on this origin. Enumerates all IndexedDB * databases, and for each `proctoring-sess-*` one NOT in `keep`, * opens it, checks it holds zero events, and deletes it if so. A * database with pending events is left alone — it may still flush on * a future load. * * No-ops where `indexedDB.databases()` is unavailable (Firefox, older * Safari): there is no enumeration API there, so leaked databases * can't be discovered. New sessions still self-clean via destroy(), * so the leak is bounded going forward even on those browsers. * * Never throws — cleanup must not be able to fail a session. */ static sweepStale(keep?: ReadonlySet): Promise; private requireDb; private openMemory; private enqueueMemory; } //# sourceMappingURL=event-queue.d.ts.map