/**
 * Perform a `fetch()` with SSRF defenses applied:
 *
 *  - Reject non-http/https URLs (no `file:`, `gopher:`, `data:`).
 *  - Reject hostnames that resolve to private/loopback IP literals via the
 *    canonicalizer in `ip-canon.ts` (decimal, octal, hex, IPv4-mapped IPv6,
 *    short-form, CGNAT, cloud metadata, etc.).
 *  - Reject `localhost`, `0.0.0.0`, and `*.internal` hostnames.
 *  - DNS-resolve the hostname before fetching and reject if any A/AAAA record
 *    lands in a private range. This defeats DNS rebinding — without it, an
 *    attacker controlling DNS for `evil.tld` returns `8.8.8.8` to our
 *    validator and `127.0.0.1` to the actual `fetch`. The pre-resolution
 *    forces the same lookup.
 *  - Disable HTTP redirects by default (`redirect: 'manual'`) — a 302 to an
 *    internal address would otherwise smuggle the request past the validator.
 *    When `followRedirects: true`, each hop is re-validated AND re-resolved.
 *  - Apply a hard request timeout via `AbortSignal.timeout`.
 *
 * Use this for any internal `fetch()` call that targets a URL derived from
 * user/admin input (webhooks, link health, image URL fetches, etc).
 *
 * **Runtime caveat:** DNS resolution uses `node:dns/promises`. On Edge / Bun
 * / Workers without that module, `resolveDns` is skipped and only the
 * URL-string check applies — set `requireDnsCheck: true` to fail closed on
 * runtimes where the resolver isn't available.
 */
export interface SafeFetchOptions extends RequestInit {
    /** Hard timeout applied via AbortSignal. Defaults to 5000ms. */
    timeoutMs?: number;
    /** When true, allow following redirects. Each hop is re-validated. Default: false. */
    followRedirects?: boolean;
    /** Maximum number of redirect hops when followRedirects is true. Default: 3. */
    maxRedirects?: number;
    /**
     * When true, DNS resolution failures (including missing `node:dns/promises`)
     * cause the request to fail closed with an `SsrfBlockedError` instead of
     * proceeding with only the string-level check. Default: false (best effort
     * — preserves portability across Edge/Workers runtimes).
     */
    requireDnsCheck?: boolean;
    /**
     * Test seam — allows tests to substitute a fake resolver instead of hitting
     * real DNS. Production callers leave this undefined.
     */
    _resolver?: (hostname: string) => Promise<{
        safe: boolean;
        resolvedIp?: string;
        error?: string;
    }>;
}
export declare class SsrfBlockedError extends Error {
    readonly url: string;
    readonly reason: string;
    constructor(url: string, reason: string);
}
export declare function safeFetch(url: string, options?: SafeFetchOptions): Promise<Response>;
//# sourceMappingURL=safe-fetch.d.ts.map