UNPKG

@juspay/neurolink

Version:

The pipe layer of an AI nervous system: one interface connecting provider neurons to your application, across three inference types — generate, stream and decide. `decide` returns typed, calibrated judgements from a non-generative model (~400ms, ~$0.00002

144 lines (143 loc) • 4.58 kB
/** * Timeout Utilities * * Wrapper functions for adding timeout protection to async operations. */ /** * Error thrown when an operation times out. */ export class TimeoutError extends Error { timeoutMs; /** * Creates a new TimeoutError. * * @param message - Error message describing the timeout * @param timeoutMs - The timeout duration that was exceeded */ constructor(message, timeoutMs) { super(message); this.timeoutMs = timeoutMs; this.name = "TimeoutError"; // Maintains proper stack trace for where error was thrown (V8 engines) if (Error.captureStackTrace) { Error.captureStackTrace(this, TimeoutError); } } } /** * Execute a promise with timeout protection. * * Wraps a promise and rejects with a TimeoutError if the operation * takes longer than the specified duration. * * @param promise - The promise to wrap with timeout * @param ms - Maximum time to wait in milliseconds * @param message - Optional custom error message for timeout * @returns Promise that resolves with the result or rejects on timeout * @throws {TimeoutError} If the operation exceeds the timeout duration * * @example * ```typescript * const result = await withTimeout( * fetchData(), * 5000, * 'Data fetch timed out' * ); * ``` * * @example * ```typescript * try { * const data = await withTimeout(slowOperation(), 3000); * } catch (error) { * if (error instanceof TimeoutError) { * console.log(`Timed out after ${error.timeoutMs}ms`); * } * } * ``` */ export async function withTimeout(promise, ms, message) { let timeoutId; const timeoutPromise = new Promise((_, reject) => { timeoutId = setTimeout(() => { reject(new TimeoutError(message || `Operation timed out after ${ms}ms`, ms)); }, ms); }); try { return await Promise.race([promise, timeoutPromise]); } finally { if (timeoutId !== undefined) { clearTimeout(timeoutId); } } } /** * Race a promise against an AbortSignal so the caller observes an abort * IMMEDIATELY instead of waiting for the operation to settle (or for a * separate timeout to expire). Rejects with an abort-shaped error * (`name === "AbortError"`) so provider loops route it to their existing * cancellation handling. * * The underlying operation is NOT cancelled — it continues as a bounded * ghost (the same tradeoff as {@link withTimeout}); its eventual settlement * is swallowed so it can never surface as an unhandled rejection. */ export async function raceWithAbort(promise, signal) { if (!signal || typeof signal.addEventListener !== "function") { return promise; } const makeAbortError = () => { const e = new Error("Operation aborted"); e.name = "AbortError"; return e; }; if (signal.aborted) { promise.catch(() => { // Swallow the abandoned settlement — it must never surface as an // unhandled rejection after the race has already been decided. }); return Promise.reject(makeAbortError()); } return new Promise((resolve, reject) => { const onAbort = () => { promise.catch(() => { // Swallow the abandoned settlement — it must never surface as an // unhandled rejection after the race has already been decided. }); reject(makeAbortError()); }; signal.addEventListener("abort", onAbort, { once: true }); promise.then((value) => { signal.removeEventListener("abort", onAbort); resolve(value); }, (error) => { signal.removeEventListener("abort", onAbort); reject(error); }); }); } /** * Execute a function with timeout protection. * * Alternative signature that accepts a function instead of a promise, * useful when you want to delay starting the operation. * * @param fn - Async function to execute * @param ms - Maximum time to wait in milliseconds * @param message - Optional custom error message for timeout * @returns Promise that resolves with the function result or rejects on timeout * @throws {TimeoutError} If the operation exceeds the timeout duration * * @example * ```typescript * const result = await withTimeoutFn( * () => fetchData(), * 5000, * 'Data fetch timed out' * ); * ``` */ export async function withTimeoutFn(fn, ms, message) { return withTimeout(fn(), ms, message); }