🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

@sebspark/retry

Package Overview
Dependencies
Maintainers
3
Versions
21
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@sebspark/retry - npm Package Compare versions

Comparing version
1.0.16
to
1.0.17
+2
-1
dist/index.cjs

@@ -17,3 +17,4 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });

if (mergedSettings && mergedSettings.retryCondition(error) && retries < mergedSettings.maxRetries) {
await wait(mergedSettings.interval(retries + 1));
const computedDelay = mergedSettings.interval(retries + 1);
await wait(mergedSettings.maxDelay !== void 0 ? Math.min(computedDelay, mergedSettings.maxDelay) : computedDelay);
return makeCall(retries + 1);

@@ -20,0 +21,0 @@ }

@@ -1,1 +0,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"}
{"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;IAKzD,MAAM,KAHJ,eAAe,aAAa,KAAA,IACxB,KAAK,IAAI,eAAe,eAAe,QAAQ,IAC/C,aACU;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 +0,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"}
{"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,cA6BE,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,1 +0,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"}
{"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,cA6BE,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"}

@@ -16,3 +16,4 @@ //#region src/retry.ts

if (mergedSettings && mergedSettings.retryCondition(error) && retries < mergedSettings.maxRetries) {
await wait(mergedSettings.interval(retries + 1));
const computedDelay = mergedSettings.interval(retries + 1);
await wait(mergedSettings.maxDelay !== void 0 ? Math.min(computedDelay, mergedSettings.maxDelay) : computedDelay);
return makeCall(retries + 1);

@@ -19,0 +20,0 @@ }

@@ -1,1 +0,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"}
{"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;IAKzD,MAAM,KAHJ,eAAe,aAAa,KAAA,IACxB,KAAK,IAAI,eAAe,eAAe,QAAQ,IAC/C,aACU;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"}
{
"name": "@sebspark/retry",
"version": "1.0.16",
"version": "1.0.17",
"license": "Apache-2.0",

@@ -31,3 +31,3 @@ "main": "dist/index.cjs",

"devDependencies": {
"axios": "1.18.0"
"axios": "1.18.1"
},

@@ -34,0 +34,0 @@ "repository": {

@@ -14,2 +14,3 @@ # `@sebspark/retry`

maxRetries: 5,
maxDelay: 5000, // Cap each retry wait to at most 5000 ms
retryCondition: retryCondition.serverErrors, // Only retries on server errors

@@ -20,1 +21,13 @@ }

```
## `maxDelay`
`maxDelay` is optional. When set, it caps the computed delay for each retry attempt.
- Without `maxDelay`: waits exactly `interval(retryCount)`
- With `maxDelay`: waits `Math.min(interval(retryCount), maxDelay)`
Example with exponential backoff:
- `interval.exponential(1000)` produces: `1000, 2000, 4000, 8000, ...`
- with `maxDelay: 5000` actual waits become: `1000, 2000, 4000, 5000, ...`