import { EnvHttpProxyAgent, ProxyAgent, fetch as undiciFetch } from "undici" ;
import { logWarn } from "../../logger.js" ;
import { formatErrorMessage } from "../errors.js" ;
import { hasEnvHttpProxyConfigured } from "./proxy-env.js" ;
export const PROXY_FETCH_PROXY_URL = Symbol.for ("openclaw.proxyFetch.proxyUrl" );
type ProxyFetchWithMetadata = typeof fetch & {
[PROXY_FETCH_PROXY_URL]?: string;
};
/**
* Create a fetch function that routes requests through the given HTTP proxy .
* Uses undici ' s ProxyAgent under the hood .
*/
export function makeProxyFetch(proxyUrl: string): typeof fetch {
let agent: ProxyAgent | null = null ;
const resolveAgent = (): ProxyAgent => {
if (!agent) {
agent = new ProxyAgent(proxyUrl);
}
return agent;
};
// undici's fetch is runtime-compatible with global fetch but the types diverge
// on stream/body internals. Single cast at the boundary keeps the rest type-safe.
const proxyFetch = ((input: RequestInfo | URL, init?: RequestInit) =>
undiciFetch(input as string | URL, {
...(init as Record<string, unknown>),
dispatcher: resolveAgent(),
}) as unknown as Promise<Response>) as ProxyFetchWithMetadata;
Object.defineProperty(proxyFetch, PROXY_FETCH_PROXY_URL, {
value: proxyUrl,
enumerable: false ,
configurable: false ,
writable: false ,
});
return proxyFetch;
}
export function getProxyUrlFromFetch(fetchImpl?: typeof fetch): string | undefined {
const proxyUrl = (fetchImpl as ProxyFetchWithMetadata | undefined)?.[PROXY_FETCH_PROXY_URL];
if (typeof proxyUrl !== "string" ) {
return undefined;
}
const trimmed = proxyUrl.trim();
return trimmed ? trimmed : undefined;
}
/**
* Resolve a proxy - aware fetch from standard environment variables
* ( HTTPS_PROXY , HTTP_PROXY , https_proxy , http_proxy ) .
* Respects NO_PROXY / no_proxy exclusions via undici ' s EnvHttpProxyAgent .
* Returns undefined when no proxy is configured .
* Gracefully returns undefined if the proxy URL is malformed .
*/
export function resolveProxyFetchFromEnv(
env: NodeJS.ProcessEnv = process.env,
): typeof fetch | undefined {
if (!hasEnvHttpProxyConfigured("https" , env)) {
return undefined;
}
try {
const agent = new EnvHttpProxyAgent();
return ((input: RequestInfo | URL, init?: RequestInit) =>
undiciFetch(input as string | URL, {
...(init as Record<string, unknown>),
dispatcher: agent,
}) as unknown as Promise<Response>) as typeof fetch;
} catch (err) {
logWarn(
`Proxy env var set but agent creation failed — falling back to direct fetch: ${formatErrorMessage(err)}`,
);
return undefined;
}
}
Messung V0.5 in Prozent C=95 H=95 G=94
¤ Dauer der Verarbeitung: 0.10 Sekunden
(vorverarbeitet am 2026-09-28)
¤
*© Formatika GbR, Deutschland