nice-retry
Version:
Type-safe, lightweight (zero-dependency) retry utility for async operations that simply works.
153 lines (149 loc) • 5.22 kB
TypeScript
type Awaitable<T> = T | Promise<T>;
/**
* Represents a function that can be asynchronous or synchronous
*/
type AsyncFunction<T = any, Args extends any[] = any[]> = (...args: Args) => Awaitable<T>;
type FallbackFunction<T> = AsyncFunction<T>;
type ErrorFilter = (error: Error) => boolean;
/**
* Different strategies for adding jitter to retry delays
*/
type JitterStrategy = 'full' | 'equal' | 'decorrelated' | 'none';
/**
* Different strategies for increasing delay between retries
*/
type BackoffStrategy = 'exponential' | 'fixed' | 'linear' | 'aggressive';
/**
* Base options for retry operations
* @template T The type of data being returned by the retried function
*/
type BaseRetryOptions<T> = {
/**
* Maximum number of retry attempts before giving up
* @default 3
*/
maxAttempts?: number;
/**
* Initial delay in milliseconds between retry attempts
* @default 1000
*/
initialDelay?: number;
/**
* Maximum delay in milliseconds between retry attempts
* @default 30000
*/
maxDelay?: number;
/**
* Strategy to use for adding jitter to delays
* - `full`: Completely random delay between 0 and calculated delay
* - `equal`: Random delay between calculated/2 and calculated*1.5
* - `decorrelated`: Independent random delays with mean = calculated
* - `none`: No jitter, use exact calculated delay
* @default `full`
*/
jitterStrategy?: JitterStrategy;
/**
* Strategy for increasing delay between retries
* - `exponential`: Doubles delay each time (1s → 2s → 4s → 8s)
* - `linear`: Increases delay linearly (1s → 2s → 3s → 4s)
* - `aggressive`: Triples delay each time (1s → 3s → 9s → 27s)
* - `fixed`: Keeps delay constant (1s → 1s → 1s)
* @default `exponential`
*/
backoffStrategy?: BackoffStrategy;
/**
* AbortSignal to cancel retry attempts
*/
signal?: AbortSignal;
/**
* Fallback function(s) to try if all retries fail
*/
fallback?: FallbackFunction<T> | FallbackFunction<T>[];
/**
* Function to determine if a particular error should trigger a retry
*/
retryIf?: ErrorFilter;
/**
* Callback function called before each retry attempt
* @param error The error that triggered the retry
* @param attempt The number of the upcoming retry attempt
*/
onRetry?: (error: Error, attempt: number) => void;
};
/**
* Options specific to retryAsync
*/
type RetryAsyncOptions<T> = BaseRetryOptions<T>;
/**
* Options specific to retryFetch
*/
type RetryFetchOptions<T> = BaseRetryOptions<T> & {
/**
* HTTP status codes to retry on
* @default [408, 429, 500, 502, 503, 504]
*/
retryStatusCodes?: readonly number[];
/**
* Whether to retry on network errors
* @default true
*/
retryNetworkErrors?: boolean;
};
type BaseRetryResult = {
/** Number of attempts made before success or giving up */
attempts: number;
/** Total time elapsed in milliseconds across all retry attempts */
totalTime: number;
/** Array of errors from failed attempts */
errors: Error[];
};
/**
* Represents the result of a generic retry operation
* @template T The type of data returned from the successful retry attempt
* @extends BaseRetryResult
*/
type RetryAsyncResult<T> = BaseRetryResult & {
/** The data returned from the successful retry attempt */
data: T;
};
/**
* Represents the result of a retry operation specifically for fetch requests
* @extends BaseRetryResult
*/
type RetryFetchResult = BaseRetryResult & {
/** The Response object returned from the successful fetch retry attempt */
response: Response;
};
declare class RetryOperationError extends Error {
readonly cause?: Error;
readonly attempts: number;
readonly errors: Error[];
constructor(message: string, attempts: number, errors?: Error[]);
}
declare class MaxRetriesExceededError extends RetryOperationError {
constructor(attempts: number, errors?: Error[]);
}
declare class RetryConditionFailedError extends RetryOperationError {
constructor(attempts: number, errors?: Error[]);
}
declare class RetryAbortedError extends RetryOperationError {
constructor(attempts: number, errors?: Error[]);
}
/**
* Main retry utility object containing retry functions for different use cases
*/
declare const retry: {
/**
* Retries fetch requests with configurable options and built-in error handling
* for common HTTP and network errors
*/
fetch: (input: RequestInfo | URL, init?: RequestInit & {
retry?: RetryFetchOptions<Response>;
}) => Promise<RetryFetchResult>;
/**
* Generic async retry function that can wrap any async operation with
* configurable retry behavior and exponential backoff
*/
async: <T>(fn: AsyncFunction<T>, options?: RetryAsyncOptions<T>) => Promise<RetryAsyncResult<T>>;
};
export { type BackoffStrategy, type JitterStrategy, MaxRetriesExceededError, RetryAbortedError, type RetryAsyncOptions, type RetryAsyncResult, RetryConditionFailedError, type RetryFetchOptions, type RetryFetchResult, RetryOperationError, retry };