/** * SQLite-backed credential persistence for AuthStorage. * * The public AuthCredentialStore interface remains in ../auth-storage so local * and remote stores share the same contract. */ import { Database } from "bun:sqlite"; import type { AuthCredential, AuthCredentialStore, CredentialRefreshLeaseFence, DisabledCredentialSummary, StoredAuthCredential, StoredCredentialBlock } from "../auth-storage.js"; import type { OAuthCredentials } from "../registry/oauth/types.js"; import type { ClientUsageReport, ClientUsageSummary, UsageHistoryEntry, UsageHistoryQuery } from "../usage.js"; export declare const USAGE_REPORT_TTL_MS: number; type SerializedCredentialRecord = { credentialType: AuthCredential["type"]; data: string; identityKey: string | null; }; /** * SQLite's busy result code family — base `SQLITE_BUSY` plus the extended * variants `SQLITE_BUSY_RECOVERY` (concurrent WAL recovery), `SQLITE_BUSY_SNAPSHOT`, * and `SQLITE_BUSY_TIMEOUT`. All warrant the same backoff-and-retry treatment. */ export declare function isSqliteBusyError(err: unknown): boolean; /** * SQLite's unrecoverable-corruption result codes — the `SQLITE_CORRUPT` family * (base plus extended variants like `SQLITE_CORRUPT_VTAB` / `SQLITE_CORRUPT_INDEX`) * and `SQLITE_NOTADB` (the file header is not a database). Unlike * {@link isSqliteBusyError}, these never clear by retrying: the store must be * repaired or replaced, so callers latch and stop touching it. */ export declare function isSqliteCorruptionError(err: unknown): boolean; export declare function serializeCredential(provider: string, credential: AuthCredential): SerializedCredentialRecord | null; export declare function resolveCredentialIdentityKey(provider: string, credential: AuthCredential): string | null; /** * Default SQLite-backed implementation of {@link AuthCredentialStore}. * * Used by the pi-ai CLI and as the default store for `AuthStorage.create()`. * Also exposes convenience methods (`saveOAuth`, `getOAuth`, `saveApiKey`, * `getApiKey`, `listProviders`, `deleteProvider`) that callers can use directly * without going through `AuthStorage`. */ export declare class SqliteAuthCredentialStore implements AuthCredentialStore { #private; constructor(db: Database); static open(dbPath?: string): Promise; listAuthCredentials(provider?: string): StoredAuthCredential[]; listDisabledCredentials(provider?: string): Promise; replaceAuthCredentialsForProvider(provider: string, credentials: AuthCredential[]): StoredAuthCredential[]; upsertAuthCredentialForProvider(provider: string, credential: AuthCredential): StoredAuthCredential[]; updateAuthCredential(id: number, credential: AuthCredential): void; tryUpdateAuthCredentialIfMatches(id: number, expectedData: string, credential: AuthCredential, lease?: CredentialRefreshLeaseFence): boolean; deleteAuthCredential(id: number, disabledCause: string): void; /** * CAS-style disable: only soft-deletes the row when its `data` column still * matches `expectedData` and the row has not already been disabled. Used by * the OAuth refresh-failure path to avoid clobbering a peer that rotated the * row between our pre-check and the disable. */ tryDisableAuthCredentialIfMatches(id: number, expectedData: string, disabledCause: string, lease?: CredentialRefreshLeaseFence): boolean; deleteAuthCredentialsForProvider(provider: string, disabledCause: string): void; getCache(key: string, options?: { includeExpired?: boolean; }): string | null; setCache(key: string, value: string, expiresAtSec: number): void; /** Drop all cache rows whose keys start with the supplied prefix. */ deleteCachePrefix(prefix: string): void; cleanExpiredCache(): void; getCredentialBlock(credentialId: number, providerKey: string, blockScope: string): number | undefined; getCredentialBlockReconcileAfter(credentialId: number, providerKey: string, blockScope: string): number | undefined; upsertCredentialBlock(block: StoredCredentialBlock): void; deleteCredentialBlock(credentialId: number, providerKey: string, blockScope: string): void; deleteCredentialBlocks(credentialId: number): void; cleanExpiredCredentialBlocks(nowMs: number): void; listCredentialBlocks(credentialIds: readonly number[]): StoredCredentialBlock[]; tryAcquireCredentialRefreshLease(credentialId: number, owner: string, expiresAtMs: number): boolean; getCredentialRefreshLeaseExpiresAt(credentialId: number): number | undefined; renewCredentialRefreshLease(credentialId: number, owner: string, expiresAtMs: number): boolean; releaseCredentialRefreshLease(credentialId: number, owner: string): void; recordUsageSnapshots(entries: UsageHistoryEntry[]): void; listUsageHistory(query?: UsageHistoryQuery): UsageHistoryEntry[]; recordClientUsage(report: ClientUsageReport): void; getClientUsageSummary(sinceMs: number): ClientUsageSummary; /** * Save OAuth credentials for a provider. * Preserves unrelated identities and replaces only the matching credential. */ saveOAuth(provider: string, credentials: OAuthCredentials): void; /** * Get OAuth credentials for a provider. */ getOAuth(provider: string): OAuthCredentials | null; /** * Save API key for a provider (replaces existing). */ saveApiKey(provider: string, apiKey: string): void; /** * Get API key for a provider. */ getApiKey(provider: string): string | null; /** * List all providers with credentials. */ listProviders(): string[]; /** * Delete all credentials for a provider. */ deleteProvider(provider: string): void; /** * SQLite increments `data_version` when another connection commits. Own * writes leave it unchanged and already notify AuthStorage directly. */ pollExternalChanges(): boolean; acknowledgeLocalChanges(): void; close(): void; } export {};