import type { OAuthCredentials } from "../registry/oauth/types.js"; import type { Provider } from "../types.js"; import { type CredentialPool } from "./pool.js"; import type { AccountPolicies } from "./policy.js"; import { type AuthCredentialStore } from "./store.js"; import { type AuthCredentialSnapshotEntry, type AuthStorageOptions, type OAuthCredential, type OAuthRefreshByIdOptions, type OAuthRefreshReason, type StoredOAuthRefreshOptions, type StoredOAuthRefreshResult } from "./types.js"; /** * Refresh OAuth access tokens this many ms before their stated expiry. The * skew exists so callers downstream of {@link OAuthRefresher} (stream providers, * usage probes, web_search) never observe a credential that is expired or * about to expire mid-request — there's a single rotation point and everyone * downstream trusts the token they receive. * * Set to 60s: comfortably absorbs request RTT + a clock-skew window without * triggering a refresh on every request. Provider token endpoints typically * mint access tokens with 30-60min lifetimes, so refreshing 60s early changes * the rotation cadence by <4%. */ export declare const OAUTH_REFRESH_SKEW_MS = 60000; type OrganizationScope = Pick; /** * Organization-scoped identity after a refresh: refreshed values win; stored * org/residency/inference scope carries over only while the organization is * unchanged. The WorkOS selection always falls back to the stored one. */ export declare function mergeRefreshedOrganizationScope(current: OrganizationScope, refreshed: OrganizationScope): OrganizationScope; /** Merge provider refresh bytes with the stored OAuth row, preserving subtype metadata for every refresh path. */ export declare function mergeRefreshedCredential(current: T, refreshed: OAuthCredentials): T; /** Dependencies for lease-guarded OAuth refresh. */ export interface OAuthRefresherDeps { store: AuthCredentialStore; pool: CredentialPool; policies: AccountPolicies; override?: AuthStorageOptions["refreshOAuthCredential"]; } /** Single-flighted, lease-guarded OAuth refresh with compare-and-set persistence. */ export declare class OAuthRefresher { #private; constructor(deps: OAuthRefresherDeps); /** * Refresh one stored OAuth credential under durable row ownership. */ refreshStored(provider: string, options: StoredOAuthRefreshOptions): Promise>; /** * Handles a definitively-dead OAuth grant discovered during refresh (`invalid_grant`, * `revoked`, …): checks for a peer rotation that raced the failure, then CAS-disables * the row and emits `credential_disabled`. Shared by the eager preflight refresh * and the final-candidate refresh so both actually disable the credential — not * just temporarily block it — on a definitive failure. * * Returns `"disabled"` once the row is torn down, `"peer-rotated"` when a concurrent * process refreshed the same row first (the persisted refresh token no longer matches * what we attempted — the caller should reload and retry with the new credential), or * `"cas-lost"` when the disable itself lost a race and the caller should reload before * continuing. */ disableDefinitiveFailure(provider: string, credentialId: number | undefined, attemptedCredential: OAuthCredential, index: number, errorMsg: string): Promise<"disabled" | "peer-rotated" | "cas-lost">; refresh(provider: Provider, credential: OAuthCredential, credentialId: number | undefined, signal?: AbortSignal, reason?: OAuthRefreshReason): Promise; /** * Refresh the OAuth credential with the given id through a per-credential * single-flight. Concurrent callers for the same row await the same upstream * refresh attempt, which is required for providers that rotate refresh tokens * on every successful refresh. */ refreshById(id: number, signal?: AbortSignal, options?: OAuthRefreshByIdOptions): Promise; } export {};