import { Abortable } from './abortable'; /** * Check if a value is a PromiseLike (has a .then method). * * @example * isPromiseLike(Promise.resolve(1)) // true * isPromiseLike({ then: () => {} }) // true * isPromiseLike(42) // false */ export declare function isPromiseLike(value: unknown): value is PromiseLike; /** * Safe input: any value or parameterless function. * Functions are invoked and their return value is processed. */ export type SafeInput = T | (() => T); /** * Extract the resolved type from a SafeInput. */ export type SafeInputResult = T extends () => infer R ? Awaited : Awaited; type SafeAllArrayResult[]> = { -readonly [K in keyof T]: SafeInputResult; }; type SafeAllObjectResult>> = { [K in keyof T]: SafeInputResult; }; export interface SafeAll { /** * Wait for all inputs to complete. Returns array preserving order and types. * * @example * const [user, posts] = await safe.all([fetchUser(), () => fetchPosts()]); */ []>(inputs: [...T]): Promise>; /** * Wait for all inputs to complete. Returns object preserving keys. * * @example * const { user, posts } = await safe.all({ * user: fetchUser(), * posts: () => fetchPosts(), * }); */ >>(inputs: T): Promise>; } type SafeRaceArrayResult[]> = SafeInputResult; type SafeRaceObjectResult>> = { [K in keyof T]: [K, SafeInputResult]; }[keyof T]; export interface SafeRace { /** * Race inputs. Returns the first value to resolve. * * @example * const fastest = await safe.race([api1(), api2(), api3()]); */ []>(inputs: [...T]): Promise>; /** * Race inputs. Returns [winnerKey, value] tuple. * * @example * const [winner, value] = await safe.race({ * primary: primaryApi(), * fallback: fallbackApi(), * }); * // winner: "primary" | "fallback" */ >>(inputs: T): Promise>; } type SafeSettledArrayResult[]> = { -readonly [K in keyof T]: PromiseSettledResult>; }; type SafeSettledObjectResult>> = { [K in keyof T]: PromiseSettledResult>; }; export interface SafeSettled { /** * Wait for all inputs to settle (resolve or reject). * * @example * const results = await safe.settled([api1(), api2()]); * results.forEach(r => { * if (r.status === "fulfilled") console.log(r.value); * else console.error(r.reason); * }); */ []>(inputs: [...T]): Promise>; /** * Wait for all inputs to settle. Returns object with PromiseSettledResult values. * * @example * const { user, posts } = await safe.settled({ * user: fetchUser(), * posts: fetchPosts(), * }); * if (user.status === "fulfilled") console.log(user.value); */ >>(inputs: T): Promise>; } export interface SafeAny { /** * Returns the first successful result. Throws AggregateError if all fail. * * @example * const result = await safe.any([api1(), api2(), api3()]); */ []>(inputs: [...T]): Promise>; /** * Returns [winnerKey, value] for first success. Throws AggregateError if all fail. * * @example * const [winner, value] = await safe.any({ * primary: primaryApi(), * fallback: fallbackApi(), * }); */ >>(inputs: T): Promise>; } export interface SafeCallback { /** * Wrap a callback to only execute if not cancelled. * If cancelled, the callback is a no-op. * * @example * const handleClick = safe.callback((e: MouseEvent) => { * state.clicked = true; * }); * document.addEventListener('click', handleClick); */ (callback: (...args: TArgs) => void): (...args: TArgs) => void; } export interface SafeDelay { /** * Delay execution for specified milliseconds. * Never resolves if cancelled. * * @example * // Wait 1 second * await safe.delay(1000); * * // Wait and return a value * const result = await safe.delay(500, "done"); */ (ms: number, resolved?: T): Promise; } /** * Safe function type returned by createSafe. * * Overloads: * 1. `safe(promise)` - Wrap promise, never resolve/reject if cancelled * 2. `safe(normalFn, ...args)` - Call function, wrap result if promise * 3. `safe(Abortable, ...args)` - Call with signal, wrap result if promise */ export interface SafeFn { /** * Wrap a promise to never resolve/reject if cancelled. * * @example * ctx.safe(fetchData()).then(data => { * // Only runs if not cancelled * state.data = data; * }); */ (promise: PromiseLike): Promise; /** * Call a normal function and wrap result if it's a promise. * * @example * const result = await ctx.safe(myAsyncFn, arg1, arg2); */ (fn: (...args: TArgs) => TResult, ...args: TArgs): TResult extends PromiseLike ? Promise : TResult; /** * Call an abortable function with the context's signal. * Wraps result if it's a promise. * * @example * const user = await ctx.safe(getUser, userId); */ (fn: Abortable, ...args: TArgs): TResult extends PromiseLike ? Promise : TResult; } /** * Safe function with utility methods for concurrent operations. */ export interface SafeFnWithUtils extends SafeFn { /** Wait for all inputs to complete */ all: SafeAll; /** Race inputs, return first to resolve */ race: SafeRace; /** Wait for all inputs to settle (resolve or reject) */ settled: SafeSettled; /** Return first successful result */ any: SafeAny; /** Wrap callback to only execute if not cancelled */ callback: SafeCallback; /** Delay execution, never resolves if cancelled */ delay: SafeDelay; } /** * Create a safe function for a given context. * * @param getSignal - Function to get the current AbortSignal * @param isCancelled - Function to check if the context is cancelled/stale * @returns A safe function with utility methods * * @example * ```ts * const safe = createSafe( * () => abortController.signal, * () => abortController.signal.aborted * ); * * // Wrap promise * await safe(fetchData()); * * // Call abortable function * await safe(getUser, userId); * * // Concurrent operations * const [a, b] = await safe.all([fetchA(), fetchB()]); * const fastest = await safe.race([api1(), api2()]); * ``` */ export declare function createSafe(getSignal: () => AbortSignal | undefined, isCancelled: () => boolean): SafeFnWithUtils; export {}; //# sourceMappingURL=safe.d.ts.map