@sebspark/retry 1.0.3 → 1.0.4
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/dist/index.cjs +94 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +36 -0
- package/dist/index.d.cts.map +1 -0
- package/package.json +12 -6
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
|
|
2
|
+
//#region src/retry.ts
|
|
3
|
+
const defaultSettings = { retryCondition: () => true };
|
|
4
|
+
const mergeSettings = (...settings) => {
|
|
5
|
+
const s = settings.filter((s$1) => s$1);
|
|
6
|
+
if (!s.length) return void 0;
|
|
7
|
+
return Object.assign(defaultSettings, ...s);
|
|
8
|
+
};
|
|
9
|
+
const wait = (ms) => new Promise((resolve) => setTimeout(() => resolve(), ms));
|
|
10
|
+
const retry = async (func, ...settings) => {
|
|
11
|
+
const mergedSettings = mergeSettings(...settings);
|
|
12
|
+
const makeCall = async (retries = 0) => {
|
|
13
|
+
try {
|
|
14
|
+
return await func();
|
|
15
|
+
} catch (error) {
|
|
16
|
+
if (mergedSettings && mergedSettings.retryCondition(error) && retries < mergedSettings.maxRetries) {
|
|
17
|
+
await wait(mergedSettings.interval(retries + 1));
|
|
18
|
+
return makeCall(retries + 1);
|
|
19
|
+
}
|
|
20
|
+
throw error;
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
return makeCall(0);
|
|
24
|
+
};
|
|
25
|
+
const interval = {
|
|
26
|
+
fixed: (delay) => (_retries) => delay,
|
|
27
|
+
linear: (delay) => (retries) => retries * delay,
|
|
28
|
+
exponential: (delay, base = 2) => (retries) => base ** (retries - 1) * delay
|
|
29
|
+
};
|
|
30
|
+
const clientErrorCodes = [
|
|
31
|
+
400,
|
|
32
|
+
401,
|
|
33
|
+
402,
|
|
34
|
+
403,
|
|
35
|
+
404,
|
|
36
|
+
405,
|
|
37
|
+
406,
|
|
38
|
+
407,
|
|
39
|
+
408,
|
|
40
|
+
409,
|
|
41
|
+
410,
|
|
42
|
+
411,
|
|
43
|
+
412,
|
|
44
|
+
413,
|
|
45
|
+
414,
|
|
46
|
+
415,
|
|
47
|
+
416,
|
|
48
|
+
417,
|
|
49
|
+
418,
|
|
50
|
+
421,
|
|
51
|
+
422,
|
|
52
|
+
423,
|
|
53
|
+
424,
|
|
54
|
+
425,
|
|
55
|
+
426,
|
|
56
|
+
428,
|
|
57
|
+
429,
|
|
58
|
+
431,
|
|
59
|
+
451
|
|
60
|
+
];
|
|
61
|
+
const serverErrorCodes = [
|
|
62
|
+
500,
|
|
63
|
+
501,
|
|
64
|
+
502,
|
|
65
|
+
503,
|
|
66
|
+
504,
|
|
67
|
+
505,
|
|
68
|
+
506,
|
|
69
|
+
507,
|
|
70
|
+
508,
|
|
71
|
+
510,
|
|
72
|
+
511
|
|
73
|
+
];
|
|
74
|
+
const retryCondition = {
|
|
75
|
+
always: (_error) => true,
|
|
76
|
+
httpErrors: (...codes) => (error) => {
|
|
77
|
+
const captureCodes = codes.flatMap((code) => {
|
|
78
|
+
if (typeof code === "number") return code;
|
|
79
|
+
if (code === "client") return clientErrorCodes;
|
|
80
|
+
if (code === "server") return serverErrorCodes;
|
|
81
|
+
return 500;
|
|
82
|
+
}).filter((code) => !!code);
|
|
83
|
+
const status = error.status || error.statusCode || error.response?.status || error.response?.statusCode || 0;
|
|
84
|
+
return captureCodes.includes(status);
|
|
85
|
+
},
|
|
86
|
+
serverErrors: (error) => retryCondition.httpErrors("server")(error),
|
|
87
|
+
custom: (func) => func
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
//#endregion
|
|
91
|
+
exports.interval = interval;
|
|
92
|
+
exports.retry = retry;
|
|
93
|
+
exports.retryCondition = retryCondition;
|
|
94
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["defaultSettings: Partial<RetrySettings>","s"],"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 if (code === 'client') return clientErrorCodes\n if (code === 'server') return serverErrorCodes\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,MAAMA,kBAA0C,EAC9C,sBAAsB,MACvB;AACD,MAAM,iBACJ,GAAG,aAC2B;CAE9B,MAAM,IAAI,SAAS,QAAQ,QAAMC,IAAE;AACnC,KAAI,CAAC,EAAE,OAAQ,QAAO;AAKtB,QAF8B,OAAO,OAAO,iBAAiB,GAAG,EAAE;;AAKpE,MAAM,QAAQ,OACZ,IAAI,SAAe,YAAY,iBAAiB,SAAS,EAAE,GAAG,CAAC;AAEjE,MAAa,QAAQ,OACnB,MACA,GAAG,aACY;CACf,MAAM,iBAAiB,cAAc,GAAG,SAAS;CAEjD,MAAM,WAAW,OAAU,UAAU,MAAkB;AACrD,MAAI;AAEF,UADiB,MAAM,MAAM;WAEtB,OAAO;AACd,OACE,kBAEA,eAAe,eAAgB,MAAM,IACrC,UAAU,eAAe,YACzB;AACA,UAAM,KAAK,eAAe,SAAS,UAAU,EAAE,CAAC;AAChD,WAAO,SAAS,UAAU,EAAE;;AAG9B,SAAM;;;AAGV,QAAO,SAAS,EAAE;;AAGpB,MAAa,WAAW;CACtB,QAAQ,WAAmB,aAAqB;CAChD,SAAS,WAAmB,YAAoB,UAAU;CAC1D,cACG,OAAe,OAAO,OACtB,YACC,SAAS,UAAU,KAAK;CAC7B;AAED,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;CAClE;AAGD,MAAM,mBAAmB;CACvB;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CACnD;AAcD,MAAa,iBAAiB;CAC5B,SAAS,WAAoB;CAC7B,aACG,GAAG,WACH,UAAqB;EACpB,MAAM,eAAe,MAClB,SAAS,SAAS;AACjB,OAAI,OAAO,SAAS,SAAU,QAAO;AACrC,OAAI,SAAS,SAAU,QAAO;AAC9B,OAAI,SAAS,SAAU,QAAO;AAC9B,UAAO;IACP,CACD,QAAQ,SAAS,CAAC,CAAC,KAAK;EAC3B,MAAM,SACJ,MAAM,UACN,MAAM,cACN,MAAM,UAAU,UAChB,MAAM,UAAU,cAChB;AACF,SAAO,aAAa,SAAS,OAAO;;CAExC,eAAe,UACb,eAAe,WAAW,SAAS,CAAC,MAAM;CAE5C,SAAS,SAAkC;CAC5C"}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
//#region src/retry.d.ts
|
|
2
|
+
type RetryConditionFunction = (error: any) => boolean;
|
|
3
|
+
interface RetrySettings {
|
|
4
|
+
maxRetries: number;
|
|
5
|
+
interval: (retryCount: number) => number;
|
|
6
|
+
retryCondition?: RetryConditionFunction;
|
|
7
|
+
maxDelay?: number;
|
|
8
|
+
}
|
|
9
|
+
declare const retry: <T>(func: () => Promise<T>, ...settings: Array<RetrySettings | undefined>) => Promise<T>;
|
|
10
|
+
declare const interval: {
|
|
11
|
+
fixed: (delay: number) => (_retries: number) => number;
|
|
12
|
+
linear: (delay: number) => (retries: number) => number;
|
|
13
|
+
exponential: (delay: number, base?: number) => (retries: number) => number;
|
|
14
|
+
};
|
|
15
|
+
declare const clientErrorCodes: readonly [400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 421, 422, 423, 424, 425, 426, 428, 429, 431, 451];
|
|
16
|
+
type ClientErrorCode = (typeof clientErrorCodes)[number];
|
|
17
|
+
declare const serverErrorCodes: readonly [500, 501, 502, 503, 504, 505, 506, 507, 508, 510, 511];
|
|
18
|
+
type ServerErrorCode = (typeof serverErrorCodes)[number];
|
|
19
|
+
type ErrorType = 'server' | 'client' | ServerErrorCode | ClientErrorCode;
|
|
20
|
+
type HttpError = {
|
|
21
|
+
status?: number;
|
|
22
|
+
statusCode?: number;
|
|
23
|
+
response?: {
|
|
24
|
+
status?: number;
|
|
25
|
+
statusCode?: number;
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
declare const retryCondition: {
|
|
29
|
+
always: (_error: unknown) => boolean;
|
|
30
|
+
httpErrors: (...codes: ErrorType[]) => (error: HttpError) => boolean;
|
|
31
|
+
serverErrors: (error: HttpError) => boolean;
|
|
32
|
+
custom: (func: (error: any) => boolean) => (error: any) => boolean;
|
|
33
|
+
};
|
|
34
|
+
//#endregion
|
|
35
|
+
export { RetryConditionFunction, RetrySettings, interval, retry, retryCondition };
|
|
36
|
+
//# sourceMappingURL=index.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/retry.ts"],"sourcesContent":[],"mappings":";KACY,sBAAA;AAAA,UAEK,aAAA,CAFiB;EAEjB,UAAA,EAAA,MAAa;EA0BjB,QAyBZ,EAAA,CAAA,UAAA,EAAA,MAAA,EAAA,GAAA,MAAA;EAxBqB,cAAA,CAAA,EAxBH,sBAwBG;EAAR,QAAA,CAAA,EAAA,MAAA;;AACC,cAFF,KAEE,EAAA,CAAA,CAAA,CAAA,CAAA,IAAA,EAAA,GAAA,GADD,OACC,CADO,CACP,CAAA,EAAA,GAAA,QAAA,EAAA,KAAA,CAAM,aAAN,GAAA,SAAA,CAAA,EAAA,GACZ,OADY,CACJ,CADI,CAAA;AACJ,cAwBE,QAxBF,EAAA;EAAR,KAAA,EAAA,CAAA,KAAA,EAAA,MAAA,EAAA,GAAA,CAAA,QAAA,EAAA,MAAA,EAAA,GAAA,MAAA;EAAO,MAAA,EAAA,CAAA,KAAA,EAAA,MAAA,EAAA,GAAA,CAAA,OAAA,EAAA,MAAA,EAAA,GAAA,MAAA;EAwBG,WAOZ,EAAA,CAAA,KAAA,EAAA,MAAA,EAAA,IAAA,CAAA,EAAA,MAAA,EAAA,GAAA,CAAA,OAAA,EAAA,MAAA,EAAA,GAAA,MAAA;AAAA,CAAA;AAKS,cAHJ,gBAIc,EAAA,SAAW,CAAA,GAAA,EAAA,GAAgB,EAAA,GAAA,EAAA,GAAA,EAAA,GAAA,EAAA,GAAA,EAAA,GAAA,EAAA,GAAA,EAAA,GAAA,EAAA,GAAA,EAAA,GAAA,EAAA,GAAA,EAAA,GAAA,EAAA,GAAA,EAAA,GAAA,EAAA,GAAA,EAAA,GAAA,EAAA,GAAA,EAAA,GAAA,EAAA,GAAA,EAAA,GAAA,EAAA,GAAA,EAAA,GAAA,EAAA,GAAA,EAAA,GAAA,EAAA,GAAA,EAAA,GAAA,EAAA,GAAA,EAAA,GAAA,CAAA;AAAA,KAA1C,eAAA,GAIK,CAAA,OAJqB,gBAIrB,CAAA,CAAA,MAAA,CAAA;AAAA,cAFJ,gBAGc,EAAA,SAAW,CAAA,GAAA,EAAA,GAAgB,EAAA,GAAA,EAAA,GAAA,EAAA,GAAA,EAAA,GAAA,EAAA,GAAA,EAAA,GAAA,EAAA,GAAA,EAAA,GAAA,EAAA,GAAA,CAAA;AAAA,KAA1C,eAAA,GAES,CAAA,OAFiB,gBAE0B,CAAA,CAAA,MAAA,CAAA;AAAe,KAAnE,SAAA,GAES,QAAA,GAAA,QAAA,GAFyB,eAEzB,GAF2C,eAE3C;AASd,KATK,SAAA,GASQ;EAGE,MAAA,CAAA,EAAA,MAAA;EACH,UAAA,CAAA,EAAA,MAAA;EAiBY,QAAA,CAAA,EAAA;IAAS,MAAA,CAAA,EAAA,MAAA;;;;cArBpB;;yBAGE,wBACH;wBAiBY"}
|
package/package.json
CHANGED
|
@@ -1,21 +1,27 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sebspark/retry",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
|
-
"
|
|
6
|
-
"
|
|
5
|
+
"main": "dist/index.cjs",
|
|
6
|
+
"module": "dist/index.mjs",
|
|
7
7
|
"types": "dist/index.d.mts",
|
|
8
8
|
"exports": {
|
|
9
9
|
".": {
|
|
10
|
-
"
|
|
11
|
-
|
|
10
|
+
"import": {
|
|
11
|
+
"types": "./dist/index.d.mts",
|
|
12
|
+
"default": "./dist/index.mjs"
|
|
13
|
+
},
|
|
14
|
+
"require": {
|
|
15
|
+
"types": "./dist/index.d.cts",
|
|
16
|
+
"default": "./dist/index.cjs"
|
|
17
|
+
}
|
|
12
18
|
}
|
|
13
19
|
},
|
|
14
20
|
"files": [
|
|
15
21
|
"dist"
|
|
16
22
|
],
|
|
17
23
|
"scripts": {
|
|
18
|
-
"build": "spark-build src/index.ts",
|
|
24
|
+
"build": "spark-build src/index.ts --format=esm --format=cjs",
|
|
19
25
|
"dev": "tsc --watch --noEmit",
|
|
20
26
|
"lint": "biome lint .",
|
|
21
27
|
"test": "vitest run --passWithNoTests --coverage",
|