import type { LookupFunction } from "node:net"; import { fetch as undiciFetch, type Dispatcher } from "undici"; import { type Refusal, type Resolution } from "./ssrf.js"; import type { ConnectorRecord } from "./store.js"; export interface CallParams { method: string; path: string; query?: Record; body?: unknown; headers?: Record; } export interface CallDeps { /** Override for tests; defaults to undici's fetch (same instance as the pinned dispatcher). */ fetchImpl?: typeof undiciFetch; /** Override for tests so a loopback stub resolves; defaults to the real address-validating resolve. */ resolve?: (targetHost: string, registeredHost: string, kind: "request" | "redirect") => Promise; /** * Build the dispatcher that pins the connection to the validated addresses. Defaults to * the real pinned dispatcher. Tests return `undefined` to skip pinning (a pinned loopback * address would otherwise fail the public re-validation). */ makeDispatcher?: (addresses: string[]) => Dispatcher | undefined; /** Sink for `[connector]` lifecycle lines; the secret is never passed to it. */ log?: (line: string) => void; reqId?: string; } export type CallResult = { ok: true; status: number; headers: Record; body: string; truncated: boolean; } | { ok: false; refused: Refusal; }; /** * Build the DNS lookup an undici dispatcher uses to dial a connector. It returns the * pre-validated addresses without consulting DNS — so no second, independent lookup * happens at connect time — and re-validates each is public, failing closed. undici * always calls it with `{ all: true }`; the single-result branch is kept for completeness. */ export declare function pinnedLookup(addresses: string[]): LookupFunction; /** Dispatcher that dials only the validated addresses; TLS/SNI still use the hostname, so cert validation is unchanged. */ export declare function pinnedDispatcher(addresses: string[]): Dispatcher; /** * Make one authenticated, host-bound request to a registered connector. The host is resolved * and validated before the request and before every redirect hop, and the socket is pinned to * the validated addresses so no second connect-time lookup can land on a rebind. The credential * is injected from the caller-supplied secret and never logged. Returns status + redacted headers * + capped body, or a refusal when resolution rejects the target. */ export declare function performCall(rec: ConnectorRecord, secret: string, params: CallParams, deps?: CallDeps): Promise; //# sourceMappingURL=call.d.ts.map