UNPKG

@tldraw/utils

Version:

tldraw infinite canvas SDK (private utilities).

8 lines (7 loc) 3 kB
{ "version": 3, "sources": ["../../src/lib/retry.ts"], "sourcesContent": ["import { sleep } from './control'\n\n/**\n * Retries an async operation with configurable attempt count, wait duration, and error filtering.\n * Executes the provided async function repeatedly until it succeeds or the maximum number of attempts is reached.\n * Includes support for abort signals and custom error matching to determine which errors should trigger retries.\n *\n * @param fn - The async function to retry on failure\n * @param options - Configuration options for retry behavior:\n * - `attempts`: Maximum number of retry attempts (default: 3)\n * - `waitDuration`: Milliseconds to wait between retry attempts (default: 1000)\n * - `abortSignal`: Optional AbortSignal to cancel the retry operation\n * - `matchError`: Optional function to determine if an error should trigger a retry\n * @returns Promise that resolves with the function's return value on success\n *\n * @example\n * ```ts\n * // Basic retry with default settings (3 attempts, 1 second wait)\n * const data = await retry(async () => {\n * const response = await fetch('/api/data')\n * if (!response.ok) throw new Error('Network error')\n * return response.json()\n * })\n *\n * // Custom retry configuration\n * const result = await retry(\n * async () => unreliableApiCall(),\n * {\n * attempts: 5,\n * waitDuration: 2000,\n * matchError: (error) => error instanceof NetworkError\n * }\n * )\n *\n * // With abort signal for cancellation\n * const controller = new AbortController()\n * setTimeout(() => controller.abort(), 10000) // Cancel after 10 seconds\n *\n * const data = await retry(\n * async () => fetchData(),\n * {\n * attempts: 10,\n * abortSignal: controller.signal\n * }\n * )\n * ```\n *\n * @internal\n */\nexport async function retry<T>(\n\tfn: (args: { attempt: number; remaining: number; total: number }) => Promise<T>,\n\t{\n\t\tattempts = 3,\n\t\twaitDuration = 1000,\n\t\tabortSignal,\n\t\tmatchError,\n\t}: {\n\t\tattempts?: number\n\t\twaitDuration?: number\n\t\tabortSignal?: AbortSignal\n\t\tmatchError?(error: unknown): boolean\n\t} = {}\n): Promise<T> {\n\tlet error: unknown = null\n\tfor (let i = 0; i < attempts; i++) {\n\t\tif (abortSignal?.aborted) throw new Error('aborted')\n\t\ttry {\n\t\t\treturn await fn({ attempt: i, remaining: attempts - i, total: attempts })\n\t\t} catch (e) {\n\t\t\tif (matchError && !matchError(e)) throw e\n\t\t\terror = e\n\t\t\tawait sleep(waitDuration)\n\t\t}\n\t}\n\tthrow error\n}\n"], "mappings": "AAAA,SAAS,aAAa;AAiDtB,eAAsB,MACrB,IACA;AAAA,EACC,WAAW;AAAA,EACX,eAAe;AAAA,EACf;AAAA,EACA;AACD,IAKI,CAAC,GACQ;AACb,MAAI,QAAiB;AACrB,WAAS,IAAI,GAAG,IAAI,UAAU,KAAK;AAClC,QAAI,aAAa,QAAS,OAAM,IAAI,MAAM,SAAS;AACnD,QAAI;AACH,aAAO,MAAM,GAAG,EAAE,SAAS,GAAG,WAAW,WAAW,GAAG,OAAO,SAAS,CAAC;AAAA,IACzE,SAAS,GAAG;AACX,UAAI,cAAc,CAAC,WAAW,CAAC,EAAG,OAAM;AACxC,cAAQ;AACR,YAAM,MAAM,YAAY;AAAA,IACzB;AAAA,EACD;AACA,QAAM;AACP;", "names": [] }