@sebspark/retry 1.0.16 → 1.0.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -11,8 +11,21 @@ import axios from 'axios'
11
11
  const settings: RetrySettings = {
12
12
  interval: interval.exponential(1000), // Exponential backoff starting at 1000 ms
13
13
  maxRetries: 5,
14
+ maxDelay: 5000, // Cap each retry wait to at most 5000 ms
14
15
  retryCondition: retryCondition.serverErrors, // Only retries on server errors
15
16
  }
16
17
 
17
18
  const result = await retry(() => axios.get('https://example.com'), settings)
18
19
  ```
20
+
21
+ ## `maxDelay`
22
+
23
+ `maxDelay` is optional. When set, it caps the computed delay for each retry attempt.
24
+
25
+ - Without `maxDelay`: waits exactly `interval(retryCount)`
26
+ - With `maxDelay`: waits `Math.min(interval(retryCount), maxDelay)`
27
+
28
+ Example with exponential backoff:
29
+
30
+ - `interval.exponential(1000)` produces: `1000, 2000, 4000, 8000, ...`
31
+ - with `maxDelay: 5000` actual waits become: `1000, 2000, 4000, 5000, ...`
package/dist/index.cjs CHANGED
@@ -14,7 +14,9 @@ const retry = async (func, ...settings) => {
14
14
  return await func();
15
15
  } catch (error) {
16
16
  if (mergedSettings && mergedSettings.retryCondition(error) && retries < mergedSettings.maxRetries) {
17
- await wait(mergedSettings.interval(retries + 1));
17
+ const computedDelay = mergedSettings.interval(retries + 1);
18
+ const delay = mergedSettings.maxDelay !== void 0 ? Math.min(computedDelay, mergedSettings.maxDelay) : computedDelay;
19
+ await wait(delay);
18
20
  return makeCall(retries + 1);
19
21
  }
20
22
  throw error;
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":[],"sources":["../src/retry.ts"],"sourcesContent":["// biome-ignore lint/suspicious/noExplicitAny: Errors can be anything\nexport type RetryConditionFunction = (error: any) => boolean\n\nexport interface RetrySettings {\n maxRetries: number\n interval: (retryCount: number) => number\n retryCondition?: RetryConditionFunction\n maxDelay?: number\n}\n\nconst defaultSettings: Partial<RetrySettings> = {\n retryCondition: () => true,\n}\nconst mergeSettings = (\n ...settings: Array<RetrySettings | undefined>\n): RetrySettings | undefined => {\n // remove undefineds, return if no settings passed\n const s = settings.filter((s) => s) as RetrySettings[]\n if (!s.length) return undefined\n\n // merge settings with priority to the latest\n const merged: RetrySettings = Object.assign({}, defaultSettings, ...s)\n\n return merged\n}\n\nconst wait = (ms: number) =>\n new Promise<void>((resolve) => setTimeout(() => resolve(), ms))\n\nexport const retry = async <T>(\n func: () => Promise<T>,\n ...settings: Array<RetrySettings | undefined>\n): Promise<T> => {\n const mergedSettings = mergeSettings(...settings)\n\n const makeCall = async <T>(retries = 0): Promise<T> => {\n try {\n const response = await func()\n return response as T\n } catch (error) {\n if (\n mergedSettings &&\n // biome-ignore lint/style/noNonNullAssertion: Will be set by defaultSettings\n mergedSettings.retryCondition!(error) &&\n retries < mergedSettings.maxRetries\n ) {\n await wait(mergedSettings.interval(retries + 1))\n return makeCall(retries + 1)\n }\n\n throw error\n }\n }\n return makeCall(0)\n}\n\nexport const interval = {\n fixed: (delay: number) => (_retries: number) => delay,\n linear: (delay: number) => (retries: number) => retries * delay,\n exponential:\n (delay: number, base = 2) =>\n (retries: number) =>\n base ** (retries - 1) * delay,\n}\n\nconst clientErrorCodes = [\n 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414,\n 415, 416, 417, 418, 421, 422, 423, 424, 425, 426, 428, 429, 431, 451,\n] as const\ntype ClientErrorCode = (typeof clientErrorCodes)[number]\n\nconst serverErrorCodes = [\n 500, 501, 502, 503, 504, 505, 506, 507, 508, 510, 511,\n] as const\ntype ServerErrorCode = (typeof serverErrorCodes)[number]\n\ntype ErrorType = 'server' | 'client' | ServerErrorCode | ClientErrorCode\n\ntype HttpError = {\n status?: number\n statusCode?: number\n response?: {\n status?: number\n statusCode?: number\n }\n}\n\nexport const retryCondition = {\n always: (_error: unknown) => true,\n httpErrors:\n (...codes: ErrorType[]) =>\n (error: HttpError) => {\n const captureCodes = codes\n .flatMap((code) => {\n if (typeof code === 'number') return code\n /* istanbul ignore else */\n if (code === 'client') return clientErrorCodes\n /* istanbul ignore next */\n if (code === 'server') return serverErrorCodes\n /* istanbul ignore next */\n return 500\n })\n .filter((code) => !!code) as number[]\n const status =\n error.status ||\n error.statusCode ||\n error.response?.status ||\n error.response?.statusCode ||\n 0\n return captureCodes.includes(status)\n },\n serverErrors: (error: HttpError) =>\n retryCondition.httpErrors('server')(error),\n // biome-ignore lint/suspicious/noExplicitAny: Errors can be anything\n custom: (func: (error: any) => boolean) => func,\n}\n"],"mappings":";;AAUA,MAAM,kBAA0C,EAC9C,sBAAsB,KACxB;AACA,MAAM,iBACJ,GAAG,aAC2B;CAE9B,MAAM,IAAI,SAAS,QAAQ,MAAM,CAAC;CAClC,IAAI,CAAC,EAAE,QAAQ,OAAO,KAAA;CAKtB,OAF8B,OAAO,OAAO,CAAC,GAAG,iBAAiB,GAAG,CAExD;AACd;AAEA,MAAM,QAAQ,OACZ,IAAI,SAAe,YAAY,iBAAiB,QAAQ,GAAG,EAAE,CAAC;AAEhE,MAAa,QAAQ,OACnB,MACA,GAAG,aACY;CACf,MAAM,iBAAiB,cAAc,GAAG,QAAQ;CAEhD,MAAM,WAAW,OAAU,UAAU,MAAkB;EACrD,IAAI;GAEF,OAAO,MADgB,KAAK;EAE9B,SAAS,OAAO;GACd,IACE,kBAEA,eAAe,eAAgB,KAAK,KACpC,UAAU,eAAe,YACzB;IACA,MAAM,KAAK,eAAe,SAAS,UAAU,CAAC,CAAC;IAC/C,OAAO,SAAS,UAAU,CAAC;GAC7B;GAEA,MAAM;EACR;CACF;CACA,OAAO,SAAS,CAAC;AACnB;AAEA,MAAa,WAAW;CACtB,QAAQ,WAAmB,aAAqB;CAChD,SAAS,WAAmB,YAAoB,UAAU;CAC1D,cACG,OAAe,OAAO,OACtB,YACC,SAAS,UAAU,KAAK;AAC9B;AAEA,MAAM,mBAAmB;CACvB;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CACtE;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;AACnE;AAGA,MAAM,mBAAmB;CACvB;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;AACpD;AAcA,MAAa,iBAAiB;CAC5B,SAAS,WAAoB;CAC7B,aACG,GAAG,WACH,UAAqB;EACpB,MAAM,eAAe,MAClB,SAAS,SAAS;GACjB,IAAI,OAAO,SAAS,UAAU,OAAO;;GAErC,IAAI,SAAS,UAAU,OAAO;;GAE9B,IAAI,SAAS,UAAU,OAAO;;GAE9B,OAAO;EACT,CAAC,CAAC,CACD,QAAQ,SAAS,CAAC,CAAC,IAAI;EAC1B,MAAM,SACJ,MAAM,UACN,MAAM,cACN,MAAM,UAAU,UAChB,MAAM,UAAU,cAChB;EACF,OAAO,aAAa,SAAS,MAAM;CACrC;CACF,eAAe,UACb,eAAe,WAAW,QAAQ,CAAC,CAAC,KAAK;CAE3C,SAAS,SAAkC;AAC7C"}
1
+ {"version":3,"file":"index.cjs","names":[],"sources":["../src/retry.ts"],"sourcesContent":["// biome-ignore lint/suspicious/noExplicitAny: Errors can be anything\nexport type RetryConditionFunction = (error: any) => boolean\n\nexport interface RetrySettings {\n maxRetries: number\n interval: (retryCount: number) => number\n retryCondition?: RetryConditionFunction\n maxDelay?: number\n}\n\nconst defaultSettings: Partial<RetrySettings> = {\n retryCondition: () => true,\n}\nconst mergeSettings = (\n ...settings: Array<RetrySettings | undefined>\n): RetrySettings | undefined => {\n // remove undefineds, return if no settings passed\n const s = settings.filter((s) => s) as RetrySettings[]\n if (!s.length) return undefined\n\n // merge settings with priority to the latest\n const merged: RetrySettings = Object.assign({}, defaultSettings, ...s)\n\n return merged\n}\n\nconst wait = (ms: number) =>\n new Promise<void>((resolve) => setTimeout(() => resolve(), ms))\n\nexport const retry = async <T>(\n func: () => Promise<T>,\n ...settings: Array<RetrySettings | undefined>\n): Promise<T> => {\n const mergedSettings = mergeSettings(...settings)\n\n const makeCall = async <T>(retries = 0): Promise<T> => {\n try {\n const response = await func()\n return response as T\n } catch (error) {\n if (\n mergedSettings &&\n // biome-ignore lint/style/noNonNullAssertion: Will be set by defaultSettings\n mergedSettings.retryCondition!(error) &&\n retries < mergedSettings.maxRetries\n ) {\n const computedDelay = mergedSettings.interval(retries + 1)\n const delay =\n mergedSettings.maxDelay !== undefined\n ? Math.min(computedDelay, mergedSettings.maxDelay)\n : computedDelay\n await wait(delay)\n return makeCall(retries + 1)\n }\n\n throw error\n }\n }\n return makeCall(0)\n}\n\nexport const interval = {\n fixed: (delay: number) => (_retries: number) => delay,\n linear: (delay: number) => (retries: number) => retries * delay,\n exponential:\n (delay: number, base = 2) =>\n (retries: number) =>\n base ** (retries - 1) * delay,\n}\n\nconst clientErrorCodes = [\n 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414,\n 415, 416, 417, 418, 421, 422, 423, 424, 425, 426, 428, 429, 431, 451,\n] as const\ntype ClientErrorCode = (typeof clientErrorCodes)[number]\n\nconst serverErrorCodes = [\n 500, 501, 502, 503, 504, 505, 506, 507, 508, 510, 511,\n] as const\ntype ServerErrorCode = (typeof serverErrorCodes)[number]\n\ntype ErrorType = 'server' | 'client' | ServerErrorCode | ClientErrorCode\n\ntype HttpError = {\n status?: number\n statusCode?: number\n response?: {\n status?: number\n statusCode?: number\n }\n}\n\nexport const retryCondition = {\n always: (_error: unknown) => true,\n httpErrors:\n (...codes: ErrorType[]) =>\n (error: HttpError) => {\n const captureCodes = codes\n .flatMap((code) => {\n if (typeof code === 'number') return code\n /* istanbul ignore else */\n if (code === 'client') return clientErrorCodes\n /* istanbul ignore next */\n if (code === 'server') return serverErrorCodes\n /* istanbul ignore next */\n return 500\n })\n .filter((code) => !!code) as number[]\n const status =\n error.status ||\n error.statusCode ||\n error.response?.status ||\n error.response?.statusCode ||\n 0\n return captureCodes.includes(status)\n },\n serverErrors: (error: HttpError) =>\n retryCondition.httpErrors('server')(error),\n // biome-ignore lint/suspicious/noExplicitAny: Errors can be anything\n custom: (func: (error: any) => boolean) => func,\n}\n"],"mappings":";;AAUA,MAAM,kBAA0C,EAC9C,sBAAsB,KACxB;AACA,MAAM,iBACJ,GAAG,aAC2B;CAE9B,MAAM,IAAI,SAAS,QAAQ,MAAM,CAAC;CAClC,IAAI,CAAC,EAAE,QAAQ,OAAO,KAAA;CAKtB,OAF8B,OAAO,OAAO,CAAC,GAAG,iBAAiB,GAAG,CAExD;AACd;AAEA,MAAM,QAAQ,OACZ,IAAI,SAAe,YAAY,iBAAiB,QAAQ,GAAG,EAAE,CAAC;AAEhE,MAAa,QAAQ,OACnB,MACA,GAAG,aACY;CACf,MAAM,iBAAiB,cAAc,GAAG,QAAQ;CAEhD,MAAM,WAAW,OAAU,UAAU,MAAkB;EACrD,IAAI;GAEF,OAAO,MADgB,KAAK;EAE9B,SAAS,OAAO;GACd,IACE,kBAEA,eAAe,eAAgB,KAAK,KACpC,UAAU,eAAe,YACzB;IACA,MAAM,gBAAgB,eAAe,SAAS,UAAU,CAAC;IACzD,MAAM,QACJ,eAAe,aAAa,KAAA,IACxB,KAAK,IAAI,eAAe,eAAe,QAAQ,IAC/C;IACN,MAAM,KAAK,KAAK;IAChB,OAAO,SAAS,UAAU,CAAC;GAC7B;GAEA,MAAM;EACR;CACF;CACA,OAAO,SAAS,CAAC;AACnB;AAEA,MAAa,WAAW;CACtB,QAAQ,WAAmB,aAAqB;CAChD,SAAS,WAAmB,YAAoB,UAAU;CAC1D,cACG,OAAe,OAAO,OACtB,YACC,SAAS,UAAU,KAAK;AAC9B;AAEA,MAAM,mBAAmB;CACvB;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CACtE;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;AACnE;AAGA,MAAM,mBAAmB;CACvB;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;AACpD;AAcA,MAAa,iBAAiB;CAC5B,SAAS,WAAoB;CAC7B,aACG,GAAG,WACH,UAAqB;EACpB,MAAM,eAAe,MAClB,SAAS,SAAS;GACjB,IAAI,OAAO,SAAS,UAAU,OAAO;;GAErC,IAAI,SAAS,UAAU,OAAO;;GAE9B,IAAI,SAAS,UAAU,OAAO;;GAE9B,OAAO;EACT,CAAC,CAAC,CACD,QAAQ,SAAS,CAAC,CAAC,IAAI;EAC1B,MAAM,SACJ,MAAM,UACN,MAAM,cACN,MAAM,UAAU,UAChB,MAAM,UAAU,cAChB;EACF,OAAO,aAAa,SAAS,MAAM;CACrC;CACF,eAAe,UACb,eAAe,WAAW,QAAQ,CAAC,CAAC,KAAK;CAE3C,SAAS,SAAkC;AAC7C"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","names":[],"sources":["../src/retry.ts"],"mappings":";KACY,sBAAA,IAA0B,KAAU;AAAA,UAE/B,aAAA;EACf,UAAA;EACA,QAAA,GAAW,UAAA;EACX,cAAA,GAAiB,sBAAsB;EACvC,QAAA;AAAA;AAAA,cAsBW,KAAA,MACX,IAAA,QAAY,OAAA,CAAQ,CAAA,MACjB,QAAA,EAAU,KAAA,CAAM,aAAA,kBAClB,OAAA,CAAQ,CAAA;AAAA,cAwBE,QAAA;6BACgB,QAAA;8BACC,OAAA;+BAEZ,IAAA,eACb,OAAA;AAAA;AAAA,cAIC,gBAAA;AAAA,KAID,eAAA,WAA0B,gBAAgB;AAAA,cAEzC,gBAAA;AAAA,KAGD,eAAA,WAA0B,gBAAgB;AAAA,KAE1C,SAAA,yBAAkC,eAAA,GAAkB,eAAe;AAAA,KAEnE,SAAA;EACH,MAAA;EACA,UAAA;EACA,QAAA;IACE,MAAA;IACA,UAAA;EAAA;AAAA;AAAA,cAIS,cAAA;;yBAGE,SAAA,QACV,KAAA,EAAO,SAAA;wBAoBY,SAAA;kBAGN,KAAA,uBAAsB,KAAA;AAAA"}
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../src/retry.ts"],"mappings":";KACY,0BAA0B;UAErB;EACf;EACA,WAAW;EACX,iBAAiB;EACjB;;cAsBW,QAAe,GAC1B,YAAY,QAAQ,OACjB,UAAU,MAAM,+BAClB,QAAQ;cA6BE;EACI,QAAA,mBAAY;EACX,SAAA,mBAAY;EAElB,cAAA,eAAM,mBACb;;cAIC;KAID,0BAA0B;cAEzB;KAGD,0BAA0B;KAE1B,kCAAkC,kBAAkB;KAEpD;EACH;EACA;EACA;IACE;IACA;;;cAIS;EACM,SAAA;EAEJ,gBAAA,OAAA,iBACV,OAAO;EAoBY,eAAA,OAAA;EAGP,SAAA,OAAC,4BAAsB"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/retry.ts"],"mappings":";KACY,sBAAA,IAA0B,KAAU;AAAA,UAE/B,aAAA;EACf,UAAA;EACA,QAAA,GAAW,UAAA;EACX,cAAA,GAAiB,sBAAsB;EACvC,QAAA;AAAA;AAAA,cAsBW,KAAA,MACX,IAAA,QAAY,OAAA,CAAQ,CAAA,MACjB,QAAA,EAAU,KAAA,CAAM,aAAA,kBAClB,OAAA,CAAQ,CAAA;AAAA,cAwBE,QAAA;6BACgB,QAAA;8BACC,OAAA;+BAEZ,IAAA,eACb,OAAA;AAAA;AAAA,cAIC,gBAAA;AAAA,KAID,eAAA,WAA0B,gBAAgB;AAAA,cAEzC,gBAAA;AAAA,KAGD,eAAA,WAA0B,gBAAgB;AAAA,KAE1C,SAAA,yBAAkC,eAAA,GAAkB,eAAe;AAAA,KAEnE,SAAA;EACH,MAAA;EACA,UAAA;EACA,QAAA;IACE,MAAA;IACA,UAAA;EAAA;AAAA;AAAA,cAIS,cAAA;;yBAGE,SAAA,QACV,KAAA,EAAO,SAAA;wBAoBY,SAAA;kBAGN,KAAA,uBAAsB,KAAA;AAAA"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/retry.ts"],"mappings":";KACY,0BAA0B;UAErB;EACf;EACA,WAAW;EACX,iBAAiB;EACjB;;cAsBW,QAAe,GAC1B,YAAY,QAAQ,OACjB,UAAU,MAAM,+BAClB,QAAQ;cA6BE;EACI,QAAA,mBAAY;EACX,SAAA,mBAAY;EAElB,cAAA,eAAM,mBACb;;cAIC;KAID,0BAA0B;cAEzB;KAGD,0BAA0B;KAE1B,kCAAkC,kBAAkB;KAEpD;EACH;EACA;EACA;IACE;IACA;;;cAIS;EACM,SAAA;EAEJ,gBAAA,OAAA,iBACV,OAAO;EAoBY,eAAA,OAAA;EAGP,SAAA,OAAC,4BAAsB"}
package/dist/index.mjs CHANGED
@@ -13,7 +13,9 @@ const retry = async (func, ...settings) => {
13
13
  return await func();
14
14
  } catch (error) {
15
15
  if (mergedSettings && mergedSettings.retryCondition(error) && retries < mergedSettings.maxRetries) {
16
- await wait(mergedSettings.interval(retries + 1));
16
+ const computedDelay = mergedSettings.interval(retries + 1);
17
+ const delay = mergedSettings.maxDelay !== void 0 ? Math.min(computedDelay, mergedSettings.maxDelay) : computedDelay;
18
+ await wait(delay);
17
19
  return makeCall(retries + 1);
18
20
  }
19
21
  throw error;
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../src/retry.ts"],"sourcesContent":["// biome-ignore lint/suspicious/noExplicitAny: Errors can be anything\nexport type RetryConditionFunction = (error: any) => boolean\n\nexport interface RetrySettings {\n maxRetries: number\n interval: (retryCount: number) => number\n retryCondition?: RetryConditionFunction\n maxDelay?: number\n}\n\nconst defaultSettings: Partial<RetrySettings> = {\n retryCondition: () => true,\n}\nconst mergeSettings = (\n ...settings: Array<RetrySettings | undefined>\n): RetrySettings | undefined => {\n // remove undefineds, return if no settings passed\n const s = settings.filter((s) => s) as RetrySettings[]\n if (!s.length) return undefined\n\n // merge settings with priority to the latest\n const merged: RetrySettings = Object.assign({}, defaultSettings, ...s)\n\n return merged\n}\n\nconst wait = (ms: number) =>\n new Promise<void>((resolve) => setTimeout(() => resolve(), ms))\n\nexport const retry = async <T>(\n func: () => Promise<T>,\n ...settings: Array<RetrySettings | undefined>\n): Promise<T> => {\n const mergedSettings = mergeSettings(...settings)\n\n const makeCall = async <T>(retries = 0): Promise<T> => {\n try {\n const response = await func()\n return response as T\n } catch (error) {\n if (\n mergedSettings &&\n // biome-ignore lint/style/noNonNullAssertion: Will be set by defaultSettings\n mergedSettings.retryCondition!(error) &&\n retries < mergedSettings.maxRetries\n ) {\n await wait(mergedSettings.interval(retries + 1))\n return makeCall(retries + 1)\n }\n\n throw error\n }\n }\n return makeCall(0)\n}\n\nexport const interval = {\n fixed: (delay: number) => (_retries: number) => delay,\n linear: (delay: number) => (retries: number) => retries * delay,\n exponential:\n (delay: number, base = 2) =>\n (retries: number) =>\n base ** (retries - 1) * delay,\n}\n\nconst clientErrorCodes = [\n 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414,\n 415, 416, 417, 418, 421, 422, 423, 424, 425, 426, 428, 429, 431, 451,\n] as const\ntype ClientErrorCode = (typeof clientErrorCodes)[number]\n\nconst serverErrorCodes = [\n 500, 501, 502, 503, 504, 505, 506, 507, 508, 510, 511,\n] as const\ntype ServerErrorCode = (typeof serverErrorCodes)[number]\n\ntype ErrorType = 'server' | 'client' | ServerErrorCode | ClientErrorCode\n\ntype HttpError = {\n status?: number\n statusCode?: number\n response?: {\n status?: number\n statusCode?: number\n }\n}\n\nexport const retryCondition = {\n always: (_error: unknown) => true,\n httpErrors:\n (...codes: ErrorType[]) =>\n (error: HttpError) => {\n const captureCodes = codes\n .flatMap((code) => {\n if (typeof code === 'number') return code\n /* istanbul ignore else */\n if (code === 'client') return clientErrorCodes\n /* istanbul ignore next */\n if (code === 'server') return serverErrorCodes\n /* istanbul ignore next */\n return 500\n })\n .filter((code) => !!code) as number[]\n const status =\n error.status ||\n error.statusCode ||\n error.response?.status ||\n error.response?.statusCode ||\n 0\n return captureCodes.includes(status)\n },\n serverErrors: (error: HttpError) =>\n retryCondition.httpErrors('server')(error),\n // biome-ignore lint/suspicious/noExplicitAny: Errors can be anything\n custom: (func: (error: any) => boolean) => func,\n}\n"],"mappings":";AAUA,MAAM,kBAA0C,EAC9C,sBAAsB,KACxB;AACA,MAAM,iBACJ,GAAG,aAC2B;CAE9B,MAAM,IAAI,SAAS,QAAQ,MAAM,CAAC;CAClC,IAAI,CAAC,EAAE,QAAQ,OAAO,KAAA;CAKtB,OAF8B,OAAO,OAAO,CAAC,GAAG,iBAAiB,GAAG,CAExD;AACd;AAEA,MAAM,QAAQ,OACZ,IAAI,SAAe,YAAY,iBAAiB,QAAQ,GAAG,EAAE,CAAC;AAEhE,MAAa,QAAQ,OACnB,MACA,GAAG,aACY;CACf,MAAM,iBAAiB,cAAc,GAAG,QAAQ;CAEhD,MAAM,WAAW,OAAU,UAAU,MAAkB;EACrD,IAAI;GAEF,OAAO,MADgB,KAAK;EAE9B,SAAS,OAAO;GACd,IACE,kBAEA,eAAe,eAAgB,KAAK,KACpC,UAAU,eAAe,YACzB;IACA,MAAM,KAAK,eAAe,SAAS,UAAU,CAAC,CAAC;IAC/C,OAAO,SAAS,UAAU,CAAC;GAC7B;GAEA,MAAM;EACR;CACF;CACA,OAAO,SAAS,CAAC;AACnB;AAEA,MAAa,WAAW;CACtB,QAAQ,WAAmB,aAAqB;CAChD,SAAS,WAAmB,YAAoB,UAAU;CAC1D,cACG,OAAe,OAAO,OACtB,YACC,SAAS,UAAU,KAAK;AAC9B;AAEA,MAAM,mBAAmB;CACvB;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CACtE;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;AACnE;AAGA,MAAM,mBAAmB;CACvB;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;AACpD;AAcA,MAAa,iBAAiB;CAC5B,SAAS,WAAoB;CAC7B,aACG,GAAG,WACH,UAAqB;EACpB,MAAM,eAAe,MAClB,SAAS,SAAS;GACjB,IAAI,OAAO,SAAS,UAAU,OAAO;;GAErC,IAAI,SAAS,UAAU,OAAO;;GAE9B,IAAI,SAAS,UAAU,OAAO;;GAE9B,OAAO;EACT,CAAC,CAAC,CACD,QAAQ,SAAS,CAAC,CAAC,IAAI;EAC1B,MAAM,SACJ,MAAM,UACN,MAAM,cACN,MAAM,UAAU,UAChB,MAAM,UAAU,cAChB;EACF,OAAO,aAAa,SAAS,MAAM;CACrC;CACF,eAAe,UACb,eAAe,WAAW,QAAQ,CAAC,CAAC,KAAK;CAE3C,SAAS,SAAkC;AAC7C"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/retry.ts"],"sourcesContent":["// biome-ignore lint/suspicious/noExplicitAny: Errors can be anything\nexport type RetryConditionFunction = (error: any) => boolean\n\nexport interface RetrySettings {\n maxRetries: number\n interval: (retryCount: number) => number\n retryCondition?: RetryConditionFunction\n maxDelay?: number\n}\n\nconst defaultSettings: Partial<RetrySettings> = {\n retryCondition: () => true,\n}\nconst mergeSettings = (\n ...settings: Array<RetrySettings | undefined>\n): RetrySettings | undefined => {\n // remove undefineds, return if no settings passed\n const s = settings.filter((s) => s) as RetrySettings[]\n if (!s.length) return undefined\n\n // merge settings with priority to the latest\n const merged: RetrySettings = Object.assign({}, defaultSettings, ...s)\n\n return merged\n}\n\nconst wait = (ms: number) =>\n new Promise<void>((resolve) => setTimeout(() => resolve(), ms))\n\nexport const retry = async <T>(\n func: () => Promise<T>,\n ...settings: Array<RetrySettings | undefined>\n): Promise<T> => {\n const mergedSettings = mergeSettings(...settings)\n\n const makeCall = async <T>(retries = 0): Promise<T> => {\n try {\n const response = await func()\n return response as T\n } catch (error) {\n if (\n mergedSettings &&\n // biome-ignore lint/style/noNonNullAssertion: Will be set by defaultSettings\n mergedSettings.retryCondition!(error) &&\n retries < mergedSettings.maxRetries\n ) {\n const computedDelay = mergedSettings.interval(retries + 1)\n const delay =\n mergedSettings.maxDelay !== undefined\n ? Math.min(computedDelay, mergedSettings.maxDelay)\n : computedDelay\n await wait(delay)\n return makeCall(retries + 1)\n }\n\n throw error\n }\n }\n return makeCall(0)\n}\n\nexport const interval = {\n fixed: (delay: number) => (_retries: number) => delay,\n linear: (delay: number) => (retries: number) => retries * delay,\n exponential:\n (delay: number, base = 2) =>\n (retries: number) =>\n base ** (retries - 1) * delay,\n}\n\nconst clientErrorCodes = [\n 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414,\n 415, 416, 417, 418, 421, 422, 423, 424, 425, 426, 428, 429, 431, 451,\n] as const\ntype ClientErrorCode = (typeof clientErrorCodes)[number]\n\nconst serverErrorCodes = [\n 500, 501, 502, 503, 504, 505, 506, 507, 508, 510, 511,\n] as const\ntype ServerErrorCode = (typeof serverErrorCodes)[number]\n\ntype ErrorType = 'server' | 'client' | ServerErrorCode | ClientErrorCode\n\ntype HttpError = {\n status?: number\n statusCode?: number\n response?: {\n status?: number\n statusCode?: number\n }\n}\n\nexport const retryCondition = {\n always: (_error: unknown) => true,\n httpErrors:\n (...codes: ErrorType[]) =>\n (error: HttpError) => {\n const captureCodes = codes\n .flatMap((code) => {\n if (typeof code === 'number') return code\n /* istanbul ignore else */\n if (code === 'client') return clientErrorCodes\n /* istanbul ignore next */\n if (code === 'server') return serverErrorCodes\n /* istanbul ignore next */\n return 500\n })\n .filter((code) => !!code) as number[]\n const status =\n error.status ||\n error.statusCode ||\n error.response?.status ||\n error.response?.statusCode ||\n 0\n return captureCodes.includes(status)\n },\n serverErrors: (error: HttpError) =>\n retryCondition.httpErrors('server')(error),\n // biome-ignore lint/suspicious/noExplicitAny: Errors can be anything\n custom: (func: (error: any) => boolean) => func,\n}\n"],"mappings":";AAUA,MAAM,kBAA0C,EAC9C,sBAAsB,KACxB;AACA,MAAM,iBACJ,GAAG,aAC2B;CAE9B,MAAM,IAAI,SAAS,QAAQ,MAAM,CAAC;CAClC,IAAI,CAAC,EAAE,QAAQ,OAAO,KAAA;CAKtB,OAF8B,OAAO,OAAO,CAAC,GAAG,iBAAiB,GAAG,CAExD;AACd;AAEA,MAAM,QAAQ,OACZ,IAAI,SAAe,YAAY,iBAAiB,QAAQ,GAAG,EAAE,CAAC;AAEhE,MAAa,QAAQ,OACnB,MACA,GAAG,aACY;CACf,MAAM,iBAAiB,cAAc,GAAG,QAAQ;CAEhD,MAAM,WAAW,OAAU,UAAU,MAAkB;EACrD,IAAI;GAEF,OAAO,MADgB,KAAK;EAE9B,SAAS,OAAO;GACd,IACE,kBAEA,eAAe,eAAgB,KAAK,KACpC,UAAU,eAAe,YACzB;IACA,MAAM,gBAAgB,eAAe,SAAS,UAAU,CAAC;IACzD,MAAM,QACJ,eAAe,aAAa,KAAA,IACxB,KAAK,IAAI,eAAe,eAAe,QAAQ,IAC/C;IACN,MAAM,KAAK,KAAK;IAChB,OAAO,SAAS,UAAU,CAAC;GAC7B;GAEA,MAAM;EACR;CACF;CACA,OAAO,SAAS,CAAC;AACnB;AAEA,MAAa,WAAW;CACtB,QAAQ,WAAmB,aAAqB;CAChD,SAAS,WAAmB,YAAoB,UAAU;CAC1D,cACG,OAAe,OAAO,OACtB,YACC,SAAS,UAAU,KAAK;AAC9B;AAEA,MAAM,mBAAmB;CACvB;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CACtE;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;AACnE;AAGA,MAAM,mBAAmB;CACvB;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;AACpD;AAcA,MAAa,iBAAiB;CAC5B,SAAS,WAAoB;CAC7B,aACG,GAAG,WACH,UAAqB;EACpB,MAAM,eAAe,MAClB,SAAS,SAAS;GACjB,IAAI,OAAO,SAAS,UAAU,OAAO;;GAErC,IAAI,SAAS,UAAU,OAAO;;GAE9B,IAAI,SAAS,UAAU,OAAO;;GAE9B,OAAO;EACT,CAAC,CAAC,CACD,QAAQ,SAAS,CAAC,CAAC,IAAI;EAC1B,MAAM,SACJ,MAAM,UACN,MAAM,cACN,MAAM,UAAU,UAChB,MAAM,UAAU,cAChB;EACF,OAAO,aAAa,SAAS,MAAM;CACrC;CACF,eAAe,UACb,eAAe,WAAW,QAAQ,CAAC,CAAC,KAAK;CAE3C,SAAS,SAAkC;AAC7C"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sebspark/retry",
3
- "version": "1.0.16",
3
+ "version": "1.0.18",
4
4
  "license": "Apache-2.0",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.mjs",
@@ -28,7 +28,7 @@
28
28
  "typecheck": "vitest --typecheck.only --passWithNoTests"
29
29
  },
30
30
  "devDependencies": {
31
- "axios": "1.18.0"
31
+ "axios": "1.19.0"
32
32
  },
33
33
  "repository": {
34
34
  "type": "git",