import type { DpopKey } from './dpop.js';
import { type FetchLike } from './util.js';
export interface HttpOptions {
    fetch?: FetchLike | undefined;
    /** Longest `Retry-After` we wait out automatically before giving up (seconds). */
    maxRetryAfterSeconds?: number | undefined;
    log?: ((line: string) => void) | undefined;
}
export interface PoppyRequestInit {
    method?: string | undefined;
    headers?: Record<string, string> | undefined;
    /**
     * The body, or a builder called once per attempt. Token requests pass a builder so each
     * retry carries brand-new assertions (fresh `jti`s), never a replayed one.
     */
    body?: (string | (() => Promise<string>)) | undefined;
    /** Signs a DPoP proof for every attempt when set. */
    dpop?: DpopKey | undefined;
    /** Sent as `Authorization: {scheme} {token}`. Never put in the URL (4.3). */
    accessToken?: string | undefined;
    scheme?: 'DPoP' | 'Bearer' | undefined;
    signal?: AbortSignal | undefined;
    redirect?: 'follow' | 'manual' | 'error' | undefined;
}
/**
 * The one place requests leave this client. It signs DPoP proofs, remembers `DPoP-Nonce`
 * values per origin and retries once on `use_dpop_nonce` (RFC 9449 section 8/9), and waits
 * out a 429 `Retry-After` once (4.3, "Rate limits").
 */
export declare class PoppyHttp {
    readonly fetch: FetchLike;
    private readonly nonces;
    private readonly maxRetryAfter;
    private readonly log?;
    constructor(opts?: HttpOptions);
    request(url: string, init?: PoppyRequestInit): Promise<Response>;
}
/** Reads a JSON body, tolerating an empty one. */
export declare function readJson<T = Record<string, unknown>>(res: Response): Promise<T | undefined>;
//# sourceMappingURL=http.d.ts.map