Spracherkennung für: .ts vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]
import * as net from "node:net";
import { Agent, EnvHttpProxyAgent, getGlobalDispatcher, setGlobalDispatcher } from "undici";
import { isWSL2Sync } from "../wsl.js";
import { hasEnvHttpProxyConfigured } from "./proxy-env.js";
export const DEFAULT_UNDICI_STREAM_TIMEOUT_MS = 30 * 60 * 1000;
/**
* Module-level bridge so `resolveDispatcherTimeoutMs` in fetch-guard.ts
* can read the global dispatcher timeout without relying on Undici's
* non-public `.options` field.
*/
export let _globalUndiciStreamTimeoutMs: number | undefined;
const AUTO_SELECT_FAMILY_ATTEMPT_TIMEOUT_MS = 300;
let lastAppliedTimeoutKey: string | null = null;
let lastAppliedProxyBootstrap = false;
type DispatcherKind = "agent" | "env-proxy" | "unsupported";
function resolveDispatcherKind(dispatcher: unknown): DispatcherKind {
const ctorName = (dispatcher as { constructor?: { name?: string } })?.constructor?.name;
if (typeof ctorName !== "string" || ctorName.length === 0) {
return "unsupported";
}
if (ctorName.includes("EnvHttpProxyAgent")) {
return "env-proxy";
}
if (ctorName.includes("ProxyAgent")) {
return "unsupported";
}
if (ctorName.includes("Agent")) {
return "agent";
}
return "unsupported";
}
function resolveAutoSelectFamily(): boolean | undefined {
if (typeof net.getDefaultAutoSelectFamily !== "function") {
return undefined;
}
try {
const systemDefault = net.getDefaultAutoSelectFamily();
// WSL2 has unstable IPv6 connectivity; disable autoSelectFamily to
// force IPv4 connections and avoid "fetch failed" errors when reaching
// Windows-host services (e.g. Ollama) from inside WSL2.
if (systemDefault && isWSL2Sync()) {
return false;
}
return systemDefault;
} catch {
return undefined;
}
}
function resolveConnectOptions(
autoSelectFamily: boolean | undefined,
): { autoSelectFamily: boolean; autoSelectFamilyAttemptTimeout: number } | undefined {
if (autoSelectFamily === undefined) {
return undefined;
}
return {
autoSelectFamily,
autoSelectFamilyAttemptTimeout: AUTO_SELECT_FAMILY_ATTEMPT_TIMEOUT_MS,
};
}
function resolveDispatcherKey(params: {
kind: DispatcherKind;
timeoutMs: number;
autoSelectFamily: boolean | undefined;
}): string {
const autoSelectToken =
params.autoSelectFamily === undefined ? "na" : params.autoSelectFamily ? "on" : "off";
return `${params.kind}:${params.timeoutMs}:${autoSelectToken}`;
}
function resolveCurrentDispatcherKind(): DispatcherKind | null {
let dispatcher: unknown;
try {
dispatcher = getGlobalDispatcher();
} catch {
return null;
}
const currentKind = resolveDispatcherKind(dispatcher);
return currentKind === "unsupported" ? null : currentKind;
}
export function ensureGlobalUndiciEnvProxyDispatcher(): void {
const shouldUseEnvProxy = hasEnvHttpProxyConfigured("https");
if (!shouldUseEnvProxy) {
return;
}
if (lastAppliedProxyBootstrap) {
if (resolveCurrentDispatcherKind() === "env-proxy") {
return;
}
lastAppliedProxyBootstrap = false;
}
const currentKind = resolveCurrentDispatcherKind();
if (currentKind === null) {
return;
}
if (currentKind === "env-proxy") {
lastAppliedProxyBootstrap = true;
return;
}
try {
setGlobalDispatcher(new EnvHttpProxyAgent());
lastAppliedProxyBootstrap = true;
} catch {
// Best-effort bootstrap only.
}
}
export function ensureGlobalUndiciStreamTimeouts(opts?: { timeoutMs?: number }): void {
const timeoutMsRaw = opts?.timeoutMs ?? DEFAULT_UNDICI_STREAM_TIMEOUT_MS;
if (!Number.isFinite(timeoutMsRaw)) {
return;
}
const timeoutMs = Math.max(DEFAULT_UNDICI_STREAM_TIMEOUT_MS, Math.floor(timeoutMsRaw));
_globalUndiciStreamTimeoutMs = timeoutMs;
const kind = resolveCurrentDispatcherKind();
if (kind === null) {
return;
}
const autoSelectFamily = resolveAutoSelectFamily();
const nextKey = resolveDispatcherKey({ kind, timeoutMs, autoSelectFamily });
if (lastAppliedTimeoutKey === nextKey) {
return;
}
const connect = resolveConnectOptions(autoSelectFamily);
try {
if (kind === "env-proxy") {
const proxyOptions = {
bodyTimeout: timeoutMs,
headersTimeout: timeoutMs,
...(connect ? { connect } : {}),
} as ConstructorParameters<typeof EnvHttpProxyAgent>[0];
setGlobalDispatcher(new EnvHttpProxyAgent(proxyOptions));
} else {
setGlobalDispatcher(
new Agent({
bodyTimeout: timeoutMs,
headersTimeout: timeoutMs,
...(connect ? { connect } : {}),
}),
);
}
lastAppliedTimeoutKey = nextKey;
} catch {
// Best-effort hardening only.
}
}
export function resetGlobalUndiciStreamTimeoutsForTests(): void {
lastAppliedTimeoutKey = null;
lastAppliedProxyBootstrap = false;
_globalUndiciStreamTimeoutMs = undefined;
}
¤ Dauer der Verarbeitung: 0.21 Sekunden
(vorverarbeitet am 2026-04-27)
¤
*© Formatika GbR, Deutschland