Files
OmniRoute/src/shared/utils/fetchTimeout.ts
MeAdityaB 4dbbbaacf1 fix: NVIDIA NIM API key validation timeout (bypass proxy fetch patch) (#3226)
NVIDIA NIM validation bypasses the proxy-patched fetch (504 fix) + combined with #3116 reliable probe model + test. Integrated into release/v3.8.11.
2026-06-05 11:52:27 -03:00

79 lines
2.1 KiB
TypeScript

/**
* Fetch Timeout — T-25
*
* Wraps fetch() with an AbortController-based timeout.
* Default timeout is 120 seconds (FETCH_TIMEOUT_MS env var).
*
* @module shared/utils/fetchTimeout
*/
const DEFAULT_TIMEOUT_MS =
parseInt(process.env.OMNIROUTE_DEFAULT_FETCH_TIMEOUT_MS || "", 10) || 120000; // 2 minutes
const FETCH_TIMEOUT_MS = parseInt(process.env.FETCH_TIMEOUT_MS || "", 10) || DEFAULT_TIMEOUT_MS;
interface FetchTimeoutOptions extends RequestInit {
timeoutMs?: number;
/** Alternative fetch function to use instead of globalThis.fetch.
* Pass getOriginalFetch() to bypass the proxy/TLS patch layer. */
fetchFn?: typeof globalThis.fetch;
}
export async function fetchWithTimeout(url: string | URL, options: FetchTimeoutOptions = {}) {
const { timeoutMs = FETCH_TIMEOUT_MS, signal: externalSignal, fetchFn, ...fetchOptions } = options;
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
// If an external signal was provided, wire it to abort our controller too
if (externalSignal) {
if (externalSignal.aborted) {
controller.abort();
} else {
externalSignal.addEventListener("abort", () => controller.abort(), { once: true });
}
}
try {
const doFetch = fetchFn || globalThis.fetch;
const response = await doFetch(url, {
...fetchOptions,
signal: controller.signal,
});
return response;
} catch (error: any) {
if (error.name === "AbortError") {
throw new FetchTimeoutError(
`Request to ${url} timed out after ${timeoutMs}ms`,
timeoutMs,
String(url)
);
}
throw error;
} finally {
clearTimeout(timeoutId);
}
}
/**
* Error thrown on fetch timeout.
*/
export class FetchTimeoutError extends Error {
timeoutMs: number;
url: string;
constructor(message: string, timeoutMs: number, url: string) {
super(message);
this.name = "FetchTimeoutError";
this.timeoutMs = timeoutMs;
this.url = url;
}
}
/**
* Get the configured timeout value.
* @returns {number} Timeout in milliseconds
*/
export function getConfiguredTimeout() {
return FETCH_TIMEOUT_MS;
}