import type { BrowserAccountScope, BrowserDataResult, BrowserStoragePolicy, } from "./shared.ts"; /** * Registry-issued, non-semantic dataset identity. Tokens must be random and * must never contain a tenant, account, user, email, domain object ID, or the * human-readable policy namespace. */ export type IndexedDbDatasetScope = Readonly<{ authorityToken: string; namespaceToken: string; partitionToken: string; accountScope: BrowserAccountScope; }>; export type IndexedDbSynchronizationState = | "PENDING" | "CONFIRMED"; export type IndexedDbConnectionStatus = | Readonly<{ kind: "CLOSED"; /** * NOT_OPENED means the current open attempt has settled without a live * connection. A blocked upgrade may therefore be observed as BLOCKED * while it is waiting, then transition to CLOSED/NOT_OPENED when its * blocked deadline fails closed. */ reason: "NOT_OPENED" | "VERSION_CHANGE" | "FORCED"; }> | Readonly<{ kind: "OPENING"; targetVersion: number }> | Readonly<{ /** * A live open/upgrade attempt is currently waiting for another * IndexedDB context. BLOCKED is transient and is not the settled state * after the blocked deadline has expired. */ kind: "BLOCKED"; currentVersion: number; targetVersion: number; }> | Readonly<{ kind: "READY"; schemaVersion: number }> | Readonly<{ kind: "DISPOSED" }>; export type IndexedDbCursorKey = | string | number | Date | ArrayBuffer | readonly IndexedDbCursorKey[]; /** * Opaque continuation state owned by an adapter query policy. Feature ports * should wrap this value if a cursor crosses a presentation or URL boundary. */ export type IndexedDbCursor = Readonly<{ indexKey: IndexedDbCursorKey; primaryKey: IndexedDbCursorKey; }>; export type IndexedDbPage = Readonly<{ items: readonly Value[]; nextCursor: IndexedDbCursor | null; }>; export type IndexedDbWriteReceipt = Readonly<{ key: string; revision: number; replayed: boolean; }>; export type IndexedDbCompareAndSwapInput = Readonly<{ key: string; value: Value; expectedRevision: number | null; idempotencyKey: string; /** * Required only for UNTIL_SYNCED datasets. The adapter never infers server * acknowledgement from a successful local write. */ synchronization?: IndexedDbSynchronizationState; signal?: AbortSignal; }>; export type IndexedDbDeleteInput = Readonly<{ key: string; expectedRevision: number; idempotencyKey: string; signal?: AbortSignal; }>; export type IndexedDbMaintenanceBatchInput = Readonly<{ /** * Hard row-count ceiling for one invocation. The adapter also observes the * cooperative duration budget between asynchronous storage operations. */ maxRows: number; maxDurationMs: number; signal?: AbortSignal; }>; export type IndexedDbMaintenanceBatchReceipt = Readonly<{ state: "MORE" | "COMPLETE"; scannedRows: number; checkpointedRows: number; migratedRows: number; concurrentlyChangedRows: number; budgetExhausted: boolean; }>; export type IndexedDbReceiptPruneBatchReceipt = Readonly<{ state: "MORE" | "COMPLETE"; scannedRows: number; deletedRows: number; budgetExhausted: boolean; }>; export type IndexedDbLifecycleAction = | "SESSION_END" | "LOGOUT" | "ACCOUNT_DELETION" | "RETENTION_SWEEP"; export type IndexedDbLifecycleBatchInput = Readonly<{ action: IndexedDbLifecycleAction; maxRows: number; maxDurationMs: number; signal?: AbortSignal; }>; export type IndexedDbLifecycleBatchReceipt = Readonly<{ state: "MORE" | "COMPLETE"; scannedRows: number; deletedRows: number; budgetExhausted: boolean; }>; export type IndexedDbLifecycleAuthorityRequest = Readonly<{ action: IndexedDbLifecycleAction; scope: IndexedDbDatasetScope; storagePolicy: BrowserStoragePolicy; signal?: AbortSignal; }>; export type IndexedDbLifecycleAuthorityDecision = | Readonly<{ authorized: false }> | Readonly<{ authorized: true; /** Opaque, short-lived proof. It is validated and discarded, never stored. */ proofToken: string; }>; /** * Domain-neutral asynchronous repository boundary. Native IndexedDB objects, * object-store names, indexes and transaction callbacks remain adapter-local. */ export interface IndexedDbRepositoryPort { open(signal?: AbortSignal): Promise>; read( key: string, signal?: AbortSignal, ): Promise | null>>; query( query: Query, cursor?: IndexedDbCursor | null, signal?: AbortSignal, ): Promise>>; compareAndSwap( input: IndexedDbCompareAndSwapInput, ): Promise>; remove( input: IndexedDbDeleteInput, ): Promise>; /** * Bounded destructive lifecycle work. Every deleting invocation is gated by * the composition-root authority callback; callers cannot provide proof. */ enforceLifecycleBatch( input: IndexedDbLifecycleBatchInput, ): Promise>; getStatus(): IndexedDbConnectionStatus; subscribeStatus(listener: (status: IndexedDbConnectionStatus) => void): () => void; close(): void; } /** * Bounded, restart-safe maintenance boundary. Checkpoint keys and raw stored * records stay private to the adapter; callers receive aggregate progress only. */ export interface IndexedDbMaintenancePort { migrateCodecBatch( input: IndexedDbMaintenanceBatchInput, ): Promise>; pruneExpiredReceipts( input: IndexedDbMaintenanceBatchInput, ): Promise>; }