/** * `web.fetch` core orchestration: validate → resolve + pin DNS → SSRF-check * → fetch (following redirects) → classify body → assemble metadata. * `src/tools/web/fetch.ts` wraps this in a `ToolResult` adapter and * audit-log emitter; this module never touches the registry, the safety * classifier, or `auditLog`. All transport calls are injectable via * {@link WebFetchCoreOptions} so tests can stub the network deterministically. */ import { lookup as defaultDnsLookup } from "node:dns/promises"; import type { ClientRequest, IncomingMessage, RequestOptions } from "node:http"; import { type WebFetchArgs, type WebFetchErrorKind, type WebFetchOutcome } from "./types.js"; /** Signature of `node:dns/promises.lookup`. */ export type DnsLookupFn = typeof defaultDnsLookup; /** Signature of `node:http.request` (the overload accepting URL + options). */ export type HttpRequestFn = (url: string | URL, options: RequestOptions, callback?: (res: IncomingMessage) => void) => ClientRequest; /** Signature of `node:https.request` (same shape as {@link HttpRequestFn}). */ export type HttpsRequestFn = HttpRequestFn; /** * Injection points for {@link webFetchCore}. Each defaults to the * corresponding `node:` built-in so production code does not need to * supply anything; tests stub these to drive the pipeline without * touching the network. */ export interface WebFetchCoreOptions { /** HTTPS transport. Defaults to `https.request`. */ httpsRequest?: HttpsRequestFn; /** HTTP transport. Defaults to `http.request`. */ httpRequest?: HttpRequestFn; /** DNS resolver. Defaults to `dns/promises.lookup`. */ dnsLookup?: DnsLookupFn; /** Wall-clock source for timing fields. Defaults to `Date.now`. */ now?: () => number; /** * Caller abort (turn cancel / stall watchdog). When aborted, the * in-flight hop is torn down immediately — without this, Esc/Ctrl+C * and the stall watchdog could leave `web.fetch` hung until its own * 30s timer fired (or forever if a socket ignored that timer). */ signal?: AbortSignal; } /** * Run the full `web.fetch` pipeline for the given arguments. * * Returns a typed {@link WebFetchOutcome}. The outcome is never thrown * — argument validation failures, SSRF blocks, network errors, HTTP * errors, and timeouts all surface as `ok=false` with a categorical * `error.kind` and a human-readable message. The `metadata` field is * always populated: pipeline stages that completed before the failure * are surfaced (e.g. `resolvedIp` when DNS succeeded but a 4xx came * back), and stages that did not run carry default zero/empty values. */ export declare function webFetchCore(args: WebFetchArgs, options?: WebFetchCoreOptions): Promise; export type { WebFetchErrorKind };