// Created on savesnippets.com ยท https://savesnippets.com/X332KcgJhflkS6 export async function fetchAbortable( url: string, opts: RequestInit & { timeoutMs?: number } = {}, ): Promise { const { timeoutMs, signal: externalSignal, ...rest } = opts; const ctl = new AbortController(); const onAbort = () => ctl.abort(externalSignal?.reason); externalSignal?.addEventListener('abort', onAbort, { once: true }); const timeoutId = timeoutMs ? setTimeout(() => ctl.abort(new Error(`Timed out after ${timeoutMs}ms`)), timeoutMs) : undefined; try { return await fetch(url, { ...rest, signal: ctl.signal }); } finally { if (timeoutId) clearTimeout(timeoutId); externalSignal?.removeEventListener('abort', onAbort); } } const ctl = new AbortController(); const resp = await fetchAbortable('/api/slow', { signal: ctl.signal, timeoutMs: 5000 });