/** * @file Unified Async Utilities * @description Centralized async operation utilities including sleep, retry, * debounce, throttle, timeout, mutex, semaphore, and promise pools. * * This module consolidates duplicate implementations from: * - utils/asyncUtils.ts * - utils/resilience.ts * - services/EnhancedInterceptors.ts * - state/sync/broadcast-sync.ts * * @module shared/async-utils */ /** * Sleep for a specified duration with optional abort signal support. * * @param ms - Duration in milliseconds * @param signal - Optional AbortSignal for cancellation * @returns Promise that resolves after the delay * @throws Error if aborted * * @example * ```ts * // Simple delay * await sleep(1000); * * // With abort signal * const controller = new AbortController(); * setTimeout(() => controller.abort(), 500); * await sleep(1000, controller.signal); // throws after 500ms * ``` */ export declare function sleep(ms: number, signal?: AbortSignal): Promise; /** * Retry configuration options */ export interface RetryConfig { /** Maximum retry attempts (default: 3) */ maxAttempts?: number; /** Initial delay between retries in ms (default: 1000) */ initialDelayMs?: number; /** Maximum delay between retries in ms (default: 30000) */ maxDelayMs?: number; /** Delay multiplier for exponential backoff (default: 2) */ backoffMultiplier?: number; /** Whether to add random jitter to delays (default: true) */ jitter?: boolean; /** Predicate to determine if error is retryable */ shouldRetry?: (error: unknown, attempt: number) => boolean; /** Callback on each retry attempt */ onRetry?: (error: unknown, attempt: number, delayMs: number) => void; /** Abort signal for cancellation */ signal?: AbortSignal; } /** * Execute an async function with retry logic and exponential backoff. * * @param fn - Async function to execute * @param config - Retry configuration * @returns Result of the function * @throws Last error if all retries fail * * @example * ```ts * const result = await withRetry( * () => fetchData(), * { * maxAttempts: 5, * initialDelayMs: 500, * shouldRetry: (error) => error instanceof NetworkError, * onRetry: (error, attempt) => console.log(`Retry ${attempt}...`), * } * ); * ``` */ export declare function withRetry(fn: () => Promise, config?: RetryConfig): Promise; /** * Fluent retry policy builder * * @example * ```ts * const policy = new RetryPolicy() * .attempts(5) * .delays(500, 10000) * .backoff(2) * .withJitter() * .retryIf((error) => error instanceof NetworkError); * * const result = await policy.execute(() => fetchData()); * ``` */ export declare class RetryPolicy { private readonly config; constructor(config?: RetryConfig); /** Set maximum retry attempts */ attempts(max: number): RetryPolicy; /** Set initial and maximum delay in milliseconds */ delays(initialMs: number, maxMs?: number): RetryPolicy; /** Set backoff multiplier */ backoff(multiplier: number): RetryPolicy; /** Enable or disable jitter */ withJitter(enabled?: boolean): RetryPolicy; /** Set retry condition predicate */ retryIf(predicate: (error: unknown, attempt: number) => boolean): RetryPolicy; /** Set retry callback */ onRetry(callback: (error: unknown, attempt: number, delayMs: number) => void): RetryPolicy; /** Execute a function with this policy */ execute(fn: () => Promise, signal?: AbortSignal): Promise; } /** * Predefined retry policies for common use cases */ export declare const retryPolicies: { /** No retry - execute once */ readonly none: RetryPolicy; /** Quick retry - 3 attempts, 100ms start, for fast operations */ readonly quick: RetryPolicy; /** Standard retry - 3 attempts, 1s start, for typical API calls */ readonly standard: RetryPolicy; /** Extended retry - 5 attempts, 2s start, for critical operations */ readonly extended: RetryPolicy; /** Network retry - retries on network-related errors */ readonly network: RetryPolicy; }; /** * Timeout error class */ export declare class TimeoutError extends Error { readonly isTimeout = true; constructor(message?: string); } /** * Execute a function with a timeout limit. * * @param fn - Async function to execute * @param timeoutMs - Timeout in milliseconds * @param errorMessage - Optional custom error message * @returns Result of the function * @throws TimeoutError if operation exceeds timeout * * @example * ```ts * const result = await withTimeout( * () => fetchData(), * 5000, * 'Data fetch timed out' * ); * ``` */ export declare function withTimeout(fn: () => Promise, timeoutMs: number, errorMessage?: string): Promise; /** * Debounce options */ export interface DebounceOptions { /** Debounce delay in milliseconds */ delayMs: number; /** Maximum wait time in milliseconds before forced execution */ maxWaitMs?: number; /** Execute on leading edge (default: false) */ leading?: boolean; /** Execute on trailing edge (default: true) */ trailing?: boolean; } /** * Debounced function interface */ export interface DebouncedFn { (...args: Args): Promise; /** Cancel pending execution */ cancel(): void; /** Execute immediately and return result */ flush(): Promise; /** Check if there's a pending execution */ pending(): boolean; } /** * Deferred promise with external resolve/reject */ export interface Deferred { promise: Promise; resolve: (value: T | PromiseLike) => void; reject: (reason?: unknown) => void; } export declare function defer(): Deferred; export declare const createDeferred: typeof defer; /** * Create a debounced function that delays execution until after the * specified delay has elapsed since the last call. * * @param fn - Function to debounce * @param options - Debounce options or delay in milliseconds * @returns Debounced function with cancel, flush, and pending methods * * @example * ```ts * const debouncedSearch = debounce( * (query: string) => searchApi(query), * { delayMs: 300, maxWaitMs: 1000 } * ); * * // These calls will be debounced * debouncedSearch('h'); * debouncedSearch('he'); * debouncedSearch('hel'); * const result = await debouncedSearch('hello'); // Only this executes * ``` */ export declare function debounce(fn: (...args: Args) => R | Promise, options: DebounceOptions | number): DebouncedFn; /** * Throttle options */ export interface ThrottleOptions { /** Throttle interval in milliseconds */ intervalMs: number; /** Execute on leading edge (default: true) */ leading?: boolean; /** Execute on trailing edge (default: true) */ trailing?: boolean; } /** * Throttled function interface */ export interface ThrottledFn { (...args: Args): R | undefined; /** Cancel pending trailing execution */ cancel(): void; /** Execute immediately with last arguments */ flush(): R | undefined; } /** * Create a throttled function that only executes at most once per interval. * * @param fn - Function to throttle * @param options - Throttle options or interval in milliseconds * @returns Throttled function with cancel and flush methods * * @example * ```ts * const throttledScroll = throttle( * (event: ScrollEvent) => handleScroll(event), * { intervalMs: 100 } * ); * * window.addEventListener('scroll', throttledScroll); * ``` */ export declare function throttle(fn: (...args: Args) => R, options: ThrottleOptions | number): ThrottledFn; /** * Mutex for exclusive access to a resource. * * @example * ```ts * const mutex = new Mutex(); * * // Manual lock/unlock * const release = await mutex.acquire(); * try { * await criticalOperation(); * } finally { * release(); * } * * // Or use runExclusive * const result = await mutex.runExclusive(async () => { * return await criticalOperation(); * }); * ``` */ export declare class Mutex { private locked; private queue; /** Acquire the lock, returns a release function */ acquire(): Promise<() => void>; /** Execute a function with exclusive lock */ runExclusive(fn: () => Promise): Promise; /** Check if the mutex is currently locked */ isLocked(): boolean; /** Get the number of waiting acquires */ getQueueLength(): number; private release; } /** * Semaphore for limiting concurrent access to a resource. * * @example * ```ts * // Allow max 5 concurrent operations * const semaphore = new Semaphore(5); * * const results = await Promise.all( * urls.map(url => * semaphore.runWithPermit(() => fetch(url)) * ) * ); * ``` */ export declare class Semaphore { private permits; private readonly maxPermits; private queue; constructor(permits: number); /** Acquire a permit, returns a release function */ acquire(): Promise<() => void>; /** Execute a function with a permit */ runWithPermit(fn: () => Promise): Promise; /** Get available permits */ availablePermits(): number; /** Get the number of waiting acquires */ getQueueLength(): number; /** Get max permits configured */ getMaxPermits(): number; private release; } /** * Cancellation token for aborting async operations. * * @example * ```ts * const token = new CancellationToken(); * * // Start operation * fetchWithCancellation(url, token.signal); * * // Cancel after 5 seconds * setTimeout(() => token.cancel('Timeout'), 5000); * ``` */ export declare class CancellationToken { private controller; private reason?; constructor(); /** Get the abort signal */ get signal(): AbortSignal; /** Check if cancelled */ get isCancelled(): boolean; /** Cancel the token with an optional reason */ cancel(reason?: string | Error): void; /** Get cancellation reason */ getCancellationReason(): Error | undefined; /** Throw if cancelled */ throwIfCancelled(): void; /** Register callback for cancellation */ onCancel(callback: (reason?: Error) => void): () => void; } /** * Map over items with controlled concurrency. * * @param items - Items to process * @param mapper - Async mapper function * @param concurrency - Max concurrent operations (default: 5) * @returns Array of results in same order as input * * @example * ```ts * const results = await pMap( * urls, * async (url) => fetch(url).then(r => r.json()), * 3 // Max 3 concurrent requests * ); * ``` */ export declare function pMap(items: T[], mapper: (item: T, index: number) => Promise, concurrency?: number): Promise; /** * Execute async functions sequentially. * * @param items - Items to process * @param mapper - Async mapper function * @returns Array of results in same order as input */ export declare function pSeries(items: T[], mapper: (item: T, index: number) => Promise): Promise; /** * Execute with cleanup guaranteed after completion. * * @param fn - Async function to execute * @param cleanup - Cleanup function to run after fn completes * @returns Result of fn */ export declare function withCleanup(fn: () => Promise, cleanup: () => void | Promise): Promise; /** * Safe async execution returning tuple of [result, error]. * * @param fn - Async function to execute * @returns Tuple of [result, null] on success or [null, error] on failure * * @example * ```ts * const [data, error] = await safeAsync(() => fetchData()); * if (error) { * console.error('Failed:', error); * } else { * console.log('Success:', data); * } * ``` */ export declare function safeAsync(fn: () => Promise): Promise<[T, null] | [null, Error]>; /** * Safe sync execution returning tuple of [result, error]. */ export declare function safeSync(fn: () => T): [T, null] | [null, Error];