| |
| |
| |
| |
| |
| |
| |
| |
|
|
| interface TimeoutOptions { |
| timeoutMs?: number; |
| label?: string; |
| signal?: AbortSignal; |
| } |
|
|
| export async function fetchWithTimeout(url: string, options: RequestInit & TimeoutOptions = {}) { |
| const { timeoutMs = 30000, label = "Request", signal: externalSignal, ...fetchOptions } = options; |
|
|
| const controller = new AbortController(); |
|
|
| |
| if (externalSignal) { |
| externalSignal.addEventListener("abort", () => controller.abort(externalSignal.reason)); |
| } |
|
|
| const timeoutId = setTimeout(() => { |
| controller.abort(new Error(`${label} timed out after ${timeoutMs}ms`)); |
| }, timeoutMs); |
|
|
| try { |
| const response = await fetch(url, { |
| ...fetchOptions, |
| signal: controller.signal, |
| }); |
| return response; |
| } catch (error: any) { |
| if (error.name === "AbortError" || controller.signal.aborted) { |
| const timeoutError: any = new Error(`${label} timed out after ${timeoutMs}ms`); |
| timeoutError.name = "TimeoutError"; |
| timeoutError.originalUrl = url; |
| timeoutError.timeoutMs = timeoutMs; |
| throw timeoutError; |
| } |
| throw error; |
| } finally { |
| clearTimeout(timeoutId); |
| } |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| export async function withTimeout<T>( |
| fn: () => Promise<T>, |
| timeoutMs: number, |
| label = "Operation" |
| ): Promise<T> { |
| return new Promise<T>((resolve, reject) => { |
| const timeoutId = setTimeout(() => { |
| const error: any = new Error(`${label} timed out after ${timeoutMs}ms`); |
| error.name = "TimeoutError"; |
| error.timeoutMs = timeoutMs; |
| reject(error); |
| }, timeoutMs); |
|
|
| fn() |
| .then((result) => { |
| clearTimeout(timeoutId); |
| resolve(result); |
| }) |
| .catch((error) => { |
| clearTimeout(timeoutId); |
| reject(error); |
| }); |
| }); |
| } |
|
|
| |
| |
| |
| export const PROVIDER_TIMEOUTS: Record<string, number> = { |
| openai: 60000, |
| claude: 90000, |
| gemini: 60000, |
| codex: 120000, |
| qwen: 45000, |
| deepseek: 60000, |
| cohere: 45000, |
| groq: 30000, |
| mistral: 45000, |
| openrouter: 60000, |
| default: 60000, |
| }; |
|
|
| export function getProviderTimeout(provider: string): number { |
| return PROVIDER_TIMEOUTS[provider] || PROVIDER_TIMEOUTS.default; |
| } |
|
|