/**
 * Slice D2 — TLS-fingerprint HTTP tier.
 *
 * Wraps the `wreq-js` napi backend in the same surface as the default HTTP
 * tier (HttpClient.fetch shape). The wreq module is lazy-imported on the
 * first call so MCP servers that never need TLS impersonation don't pay the
 * 654ms cold-start cost. The cached module is null when the optional dep is
 * not installed for the host platform; callers must handle the
 * `tls_tier_unavailable` rejection.
 *
 * Anti-bot signals are recognised by status code (403 / 429 / 503) and by
 * three challenge-page body markers (Cloudflare's `cf-browser-verification`
 * and `Just a moment`, plus DataDome sensor scripts). Callers (router) use
 * these helpers to decide whether to escalate.
 */
export interface TlsFetchOptions {
    headers?: Record<string, string>;
    timeoutMs?: number;
}
export interface TlsFetchResult {
    url: string;
    finalUrl: string;
    html: string;
    contentType: string;
    statusCode: number;
    headers: Record<string, string>;
    rawBuffer?: Buffer;
}
export declare class TlsTierUnavailableError extends Error {
    readonly cause: unknown;
    constructor(cause: unknown);
}
interface WreqHeaders {
    entries?: () => Iterable<[string, string]>;
    forEach?: (cb: (v: string, k: string) => void) => void;
}
interface WreqResponse {
    status: number;
    url?: string;
    headers: WreqHeaders;
    text(): Promise<string>;
    arrayBuffer?(): Promise<ArrayBuffer>;
}
interface WreqFetchInit {
    headers?: Record<string, string>;
    browser?: string;
    signal?: AbortSignal;
    redirect?: 'follow' | 'manual' | 'error';
}
type WreqFetch = (url: string, init?: WreqFetchInit) => Promise<WreqResponse>;
interface LoadedTlsBackend {
    fetch: WreqFetch;
}
/** Test-only: reset the lazy-load memo so the next call re-imports. */
export declare function _resetTlsBackend(): void;
export declare function _setTlsBackendForTests(backend: LoadedTlsBackend | null): void;
/**
 * Single-shot TLS-impersonation fetch. Returns the same shape as the default
 * HTTP tier so router.ts can swap tiers without branching elsewhere.
 */
export declare function tlsFetch(url: string, options?: TlsFetchOptions): Promise<TlsFetchResult>;
export declare function isAntiBotStatus(status: number): boolean;
export declare function hasChallengeBody(html: string | null | undefined): boolean;
/**
 * Slice 5 (audit H4): a 429 without an anti-bot challenge body is a plain
 * rate-limit, not an anti-bot wall. Playwright will hit the same rate
 * limit, so escalation just pays the browser cold-start cost for no gain.
 *
 * We treat the response as rate-limited (NOT anti-bot) when:
 *   (a) statusCode === 429, AND
 *   (b) the body does NOT carry a Cloudflare/DataDome challenge marker.
 *
 * Callers (router) check this first and surface the 429 up the stack
 * instead of escalating. A Retry-After header strengthens the signal but
 * isn't required — many CDNs return 429 without one.
 */
export declare function isRateLimit(statusCode: number, html: string | null | undefined): boolean;
export declare function isAntiBotSignal(statusCode: number, html: string | null | undefined): boolean;
/**
 * Heuristic: the page came back but tells the user that JavaScript is
 * required. Mirrors playwright-tier.shouldEscalate's marker check but is
 * exposed separately so the router can distinguish "TLS failed → try
 * Playwright" from "anti-bot wall → already escalated".
 */
export declare function looksJsRequired(html: string | null | undefined): boolean;
/** Lightweight debug helper used by router to log routing decisions. */
export declare function describeAntiBot(statusCode: number, html: string | null | undefined): string | null;
export {};
//# sourceMappingURL=tls-tier.d.ts.map