/**
 * OAuthRefresher — mint a fresh Claude Code OAuth access token from its stored
 * refresh token, so the QuotaPoller never falsely flags a still-valid login as
 * `needs-reauth` (P1.2 hardening of the Subscription & Auth Standard).
 *
 * ── Why this exists (the bug it fixes) ──
 * A Claude Code login holds TWO tokens in its config home's credential store:
 *   - a short-lived ACCESS token (`sk-ant-oat…`, ~8–12h), and
 *   - a long-lived REFRESH token (`sk-ant-ort…`, weeks→months).
 * The `claude` client silently exchanges the refresh token for a new access
 * token on every real use. The QuotaPoller reads the access token out-of-band
 * and calls the usage endpoint directly — so when the access token has expired
 * (which is routine, daily) but the refresh token is still perfectly valid, the
 * usage read returns 401 and the poller wrongly marks the account `needs-reauth`.
 * That cried wolf: the login is intact, only the access token lapsed. This module
 * performs the same refresh-token exchange the client does, so a routine expiry
 * recovers silently and `needs-reauth` is reserved for a genuinely dead login
 * (refresh token revoked / password change) — exactly what SubscriptionPool's
 * status comment already promises.
 *
 * ── Corruption safety (the load-bearing invariant) ──
 * The ONLY way this module could harm a working login is by writing a bad
 * credential back. So the write is gated three ways:
 *   1. it happens ONLY on a fully-validated 200 response (new access token shaped
 *      `sk-ant-oat…`, a positive numeric `expires_in`);
 *   2. it is a READ-MERGE-WRITE — the existing credential JSON is re-read and only
 *      the access token / refresh token / expiry are overwritten, so scopes,
 *      subscriptionType, rateLimitTier and any unknown fields are preserved; and
 *   3. if the server rotates the refresh token, the NEW one is persisted; if the
 *      response omits a refresh token (non-rotating server), the existing one is
 *      kept — never dropped.
 * A wrong endpoint / client id / network failure can therefore only ever make the
 * exchange FAIL (→ the caller's existing `needs-reauth` path), never corrupt.
 *
 * Token values are NEVER logged or returned to any persisted surface. The OAuth
 * token endpoint + client id are the public Claude Code values, extracted from
 * the official client binary (verified 2026-06-08).
 *
 * Testability: the credential store, the fetch surface, and the clock are all
 * injectable, so the whole refresh runs hermetically with zero keychain, zero
 * network, and a deterministic clock in tests.
 */
import { CredentialWriteFunnel } from './CredentialWriteFunnel.js';
/** Public Claude Code OAuth token endpoint (from the official client binary). */
export declare const CLAUDE_TOKEN_URL = "https://platform.claude.com/v1/oauth/token";
/** Public Claude Code OAuth client id (from the official client binary). */
export declare const CLAUDE_CODE_CLIENT_ID = "9d1c250a-e61b-44d9-88ed-5944d1962f5e";
export type RefreshFailReason = 'unsupported-account' | 'read-failed' | 'no-refresh-token' | 'exchange-failed' | 'malformed-response' | 'write-failed' | 'write-skipped';
export type RefreshResult = {
    ok: true;
    accessToken: string;
    expiresAt: number;
    rotated: boolean;
} | {
    ok: false;
    reason: RefreshFailReason;
    status?: number;
};
/** The OAuth access + refresh tokens parsed out of a credential store entry. */
export interface ClaudeOauth {
    accessToken?: string;
    refreshToken?: string;
    expiresAt?: number;
    [k: string]: unknown;
}
/**
 * A credential store for one config home. `read` returns the RAW JSON string of
 * the stored entry (so the refresher can merge-preserve every field); `write`
 * persists a replacement raw JSON string. Injectable so tests use a fake.
 */
export interface CredentialStore {
    read(configHome: string): string | null;
    write(configHome: string, rawJson: string): boolean;
}
/** POST-capable fetch surface (distinct from QuotaPoller's GET-only FetchImpl). */
export type RefreshFetch = (url: string, init: {
    method: string;
    headers: Record<string, string>;
    body: string;
}) => Promise<{
    ok: boolean;
    status: number;
    json: () => Promise<unknown>;
}>;
export interface RefreshDeps {
    store?: CredentialStore;
    fetchImpl?: RefreshFetch;
    now?: () => number;
    tokenUrl?: string;
    clientId?: string;
    /**
     * The credential-write funnel (Step 4b). The token write is serialized through
     * `withSlotLock(configHome, …)` so a refresh write can never interleave with a
     * swap (Step 5) or another refresh on the SAME slot. Defaults to the process-wide
     * `credentialWriteFunnel` singleton; tests inject their own to assert serialization.
     */
    funnel?: CredentialWriteFunnel;
}
export declare function expandHome(p: string): string;
/**
 * Canonical per-slot lock key for a config home (Step 4b). The funnel keys its per-slot lock on
 * THIS string, so two writers to the SAME keychain entry must derive the SAME key regardless of
 * how the home was spelled. `path.resolve` over the home-expanded path strips a trailing slash and
 * collapses `.`/`..` so `~/.claude` and `~/.claude/` (or `/h/.claude` and `/h/./.claude`) map to one
 * lock — closing the string-identity race a refresh and a switch could otherwise have on the same
 * account (second-pass review, 2026-06-13).
 */
export declare function credentialSlotKey(configHome: string): string;
/**
 * macOS keychain service name for a config home's Claude Code credentials.
 * The default home (`~/.claude`) has no hash suffix; every other config home is
 * suffixed with the first 8 hex of sha256(configHome) — verified empirically and
 * matched by the official client.
 */
export declare function claudeCredentialService(configHome: string): string;
/** Non-darwin credential file for a config home. */
export declare function claudeCredentialFilePath(configHome: string): string;
/** Default store: macOS keychain, else a per-config-home credentials file. */
export declare const defaultCredentialStore: CredentialStore;
/** Parse the `claudeAiOauth` block out of a config home's credential store. */
export declare function readClaudeOauth(configHome: string, store?: CredentialStore): ClaudeOauth | null;
/**
 * Refresh a config home's Claude Code access token from its stored refresh token.
 * Returns the new access token + expiry on success; otherwise a typed failure
 * reason the caller maps to its `needs-reauth` decision. Writes NOTHING on any
 * failure — a working login is never put at risk by an unsuccessful refresh.
 */
export declare function refreshClaudeToken(configHome: string, deps?: RefreshDeps): Promise<RefreshResult>;
//# sourceMappingURL=OAuthRefresher.d.ts.map