/** * SQLite-backed credential persistence for AuthStorage. * * The AuthCredentialStore contract lives in ./store so local and remote stores * share the same interface. */ import type { Database } from "bun:sqlite"; import { isSqliteBusyError, isSqliteCorruptionError } from "@oh-my-pi/pi-utils"; import type { AuthCredentialStore, CredentialRefreshLeaseFence } from "./store.js"; import type { AuthCredential, DisabledCredentialSummary, StoredAuthCredential, StoredCredentialBlock } from "./types.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; }; export { isSqliteBusyError, isSqliteCorruptionError }; 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); /** Opens credential storage with bounded busy retries and one-shot corruption recovery. */ static open(dbPath?: string): Promise; listAuthCredentials(provider?: string): StoredAuthCredential[]; listDisabledCredentials(provider?: string): Promise; replaceAuthCredentials(provider: string, credentials: AuthCredential[]): Promise; upsertAuthCredential(provider: string, credential: AuthCredential): Promise; /** * Rewrites a row only when its persisted bytes change: an identical write would * still bump `updated_at` and `auth_change_revision`, making every peer process * reload credentials for nothing. */ updateAuthCredential(id: number, credential: AuthCredential): void; tryUpdateAuthCredentialIfMatches(id: number, expectedData: string, credential: AuthCredential, lease?: CredentialRefreshLeaseFence): boolean; deleteAuthCredential(id: number, disabledCause: string): Promise; /** * 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; deleteAuthCredentials(provider: string, disabledCause: string): Promise; 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): Promise; /** * Get OAuth credentials for a provider. */ getOAuth(provider: string): OAuthCredentials | null; /** * Save API key for a provider (replaces existing). */ saveApiKey(provider: string, apiKey: string): Promise; /** * 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): Promise; /** * SQLite increments `data_version` when another connection commits. Own * writes leave it unchanged and already notify AuthStorage directly. */ pollExternalChanges(): boolean; acknowledgeLocalChanges(): void; close(): void; }