import { type AuthCredential, type AuthCredentialStore, type OAuthCredential, type StoredAuthCredential } from "../auth-storage"; import type { OAuthCredentials } from "../registry/oauth/types"; import type { Provider } from "../types"; import type { UsageReport } from "../usage"; import { type AuthBrokerClient } from "./client"; import type { SnapshotResponse } from "./types"; export interface RemoteAuthCredentialStoreOptions { client: AuthBrokerClient; /** * Initial snapshot. When omitted, callers must call * {@link RemoteAuthCredentialStore.refreshSnapshot} before the first read. */ initialSnapshot?: SnapshotResponse; /** * Subscribe to the broker's SSE snapshot stream when available. Falls back * to long-poll permanently when the broker returns 404. Default `true`. */ streamSnapshots?: boolean; /** * Called after broker-sourced full snapshots are applied. The constructor's * initial snapshot intentionally does not trigger this hook. */ onSnapshot?: (snapshot: SnapshotResponse, generation: number) => void; } export declare class RemoteAuthCredentialStore implements AuthCredentialStore { #private; constructor(opts: RemoteAuthCredentialStoreOptions); get client(): AuthBrokerClient; get snapshot(): SnapshotResponse; /** Re-hydrate the in-memory snapshot from the broker. */ refreshSnapshot(): Promise; listAuthCredentials(provider?: string): StoredAuthCredential[]; /** * In-memory update from a successful refresh through the broker. AuthStorage * calls this after `#replaceCredentialAt`; the broker already persisted the * authoritative row, so we just mirror it. */ updateAuthCredential(id: number, credential: AuthCredential): void; deleteAuthCredential(id: number, disabledCause: string): void; deleteAuthCredentialRemote(id: number, disabledCause: string): Promise; tryDisableAuthCredentialIfMatches(id: number, _expectedData: string, disabledCause: string): boolean; waitForFreshSnapshot(maxWaitMs: number, opts?: { signal?: AbortSignal; }): Promise; prepareForRequest(credentialId: number, opts?: { signal?: AbortSignal; }): Promise; markCredentialSuspect(credentialId: number, opts?: { signal?: AbortSignal; }): Promise; replaceAuthCredentialsForProvider(_provider: string, _credentials: AuthCredential[]): StoredAuthCredential[]; upsertAuthCredentialForProvider(_provider: string, _credential: AuthCredential): StoredAuthCredential[]; deleteAuthCredentialsForProvider(_provider: string, _disabledCause: string): void; /** * Upsert a single credential through the broker. The broker server is the * canonical writer — see `POST /v1/credential`. The redacted snapshot * entries returned by the server replace the provider's rows in our local * snapshot, and the global snapshot is then refreshed in the background so * any concurrent peer (refresh, generation bump) stays in sync. */ upsertAuthCredentialRemote(provider: string, credential: AuthCredential): Promise; /** * Replace-all semantics: disable every active credential for the provider, * then upload each of the new credentials. Used by API-key login so a new * key clobbers any previously stored key for the same provider. */ replaceAuthCredentialsRemote(provider: string, credentials: AuthCredential[]): Promise; /** * Logout: disable every active credential for the provider on the broker, * then drop them from the local snapshot. Refresh fetches the authoritative * post-state in the background. */ deleteAuthCredentialsRemote(provider: string, disabledCause: string): Promise; getCache(key: string): string | null; setCache(key: string, value: string, expiresAtSec: number): void; cleanExpiredCache(): void; /** * Store-level hook consumed by `AuthStorage` — routes refresh through the * broker so the actual refresh token never leaves the broker host. Returns * the broker-redacted credential with {@link REMOTE_REFRESH_SENTINEL} in * the `refresh` slot. */ refreshOAuthCredential(_provider: Provider, credentialId: number, _credential: OAuthCredential, signal?: AbortSignal): Promise; /** * Store-level hook consumed by `AuthStorage.fetchUsageReports()` — proxies * to the broker's `/v1/usage` endpoint. The broker's egress IP isn't * rate-limited by Anthropic's per-IP `/usage` cap the way a heavy * residential laptop is, so all credentials surface every cycle. */ fetchUsageReports(signal?: AbortSignal): Promise; /** * Per-credential usage hook consumed by `AuthStorage.#getUsageReport`. Pulls * the aggregate broker `/v1/usage` once and serves all callers from the * same response (coalesced + cached), then matches the credential to a * report by provider + identity (accountId / email / projectId). * * The broker already aggregates with its own 30s TTL on the server side; our * 15s client TTL is below that so we usually re-use the broker's cache too. */ getUsageReport(provider: Provider, credential: OAuthCredential, signal?: AbortSignal): Promise; close(): void; }