runtry 0.2.3 → 0.3.0
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 +46 -3
- package/dist/error/matchers.d.ts +4 -0
- package/dist/error/matchers.d.ts.map +1 -1
- package/dist/error/matchers.js +53 -0
- package/dist/error/matchers.js.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/run.d.ts.map +1 -1
- package/dist/run.js +41 -17
- package/dist/run.js.map +1 -1
- package/dist/runAll.d.ts +15 -0
- package/dist/runAll.d.ts.map +1 -0
- package/dist/runAll.js +33 -0
- package/dist/runAll.js.map +1 -0
- package/dist/types.d.ts +32 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,6 +5,8 @@ Run async functions and return a typed `Result` **instead of throwing**.
|
|
|
5
5
|
- ✅ No repetitive `try/catch` in UI code
|
|
6
6
|
- ✅ Typed success/error handling
|
|
7
7
|
- ✅ Pluggable error normalization (matchers / adapters)
|
|
8
|
+
- ✅ **Automatic Retries** with backoff & jitter
|
|
9
|
+
- ✅ **Concurrency control** with `runAll`
|
|
8
10
|
|
|
9
11
|
---
|
|
10
12
|
|
|
@@ -52,9 +54,50 @@ declare function run<T, E extends AppError = AppError>(
|
|
|
52
54
|
): Promise<RunResult<T, E>>;
|
|
53
55
|
```
|
|
54
56
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
-
|
|
57
|
+
#### Options
|
|
58
|
+
|
|
59
|
+
- `toError`: Custom error normalizer.
|
|
60
|
+
- `onError`: Callback for final failure.
|
|
61
|
+
- `onSuccess`: Callback for success.
|
|
62
|
+
- `onFinally`: Callback after completion (success or fail).
|
|
63
|
+
- `ignoreAbort`: Don't trigger onError for Abort/Cancellation (default: true).
|
|
64
|
+
|
|
65
|
+
#### Retries
|
|
66
|
+
|
|
67
|
+
You can configure automatic retries for failed operations:
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
await run(fetchData, {
|
|
71
|
+
retries: 3,
|
|
72
|
+
retryDelay: 1000,
|
|
73
|
+
retryBackoff: "exponential", // "fixed" | "linear" | "exponential"
|
|
74
|
+
jitter: true, // adds randomization to delay
|
|
75
|
+
shouldRetry: (err) => err.status === 503, // optional filter
|
|
76
|
+
});
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
### `runAll(tasks, options?)`
|
|
82
|
+
|
|
83
|
+
Executes multiple tasks with **concurrency control**.
|
|
84
|
+
|
|
85
|
+
```ts
|
|
86
|
+
import { runAll } from "runtry";
|
|
87
|
+
|
|
88
|
+
const tasks = [
|
|
89
|
+
() => fetch("/api/1"),
|
|
90
|
+
() => fetch("/api/2"),
|
|
91
|
+
() => fetch("/api/3"),
|
|
92
|
+
];
|
|
93
|
+
|
|
94
|
+
// Run max 2 at a time
|
|
95
|
+
const results = await runAll(tasks, {
|
|
96
|
+
concurrency: 2,
|
|
97
|
+
onSettled: (res, index) => console.log(`Task ${index} done`),
|
|
98
|
+
retries: 2, // Inherits all run() options including retries!
|
|
99
|
+
});
|
|
100
|
+
```
|
|
58
101
|
|
|
59
102
|
---
|
|
60
103
|
|
package/dist/error/matchers.d.ts
CHANGED
|
@@ -2,5 +2,9 @@ import type { AppError } from "./types";
|
|
|
2
2
|
import type { Matcher } from "./normalize";
|
|
3
3
|
export declare const abortMatcher: Matcher;
|
|
4
4
|
export declare const timeoutMatcher: Matcher;
|
|
5
|
+
export declare const messageMatcher: Matcher;
|
|
6
|
+
export declare const stringMatcher: Matcher;
|
|
7
|
+
export declare const statusMatcher: Matcher;
|
|
8
|
+
export declare const aggregateMatcher: Matcher;
|
|
5
9
|
export declare function matchInstance<T extends Error, Meta = unknown>(ErrorCtor: new (...args: any[]) => T, map: (e: T) => AppError<Meta>): Matcher<AppError<Meta>>;
|
|
6
10
|
//# sourceMappingURL=matchers.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"matchers.d.ts","sourceRoot":"","sources":["../../src/error/matchers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACxC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAG3C,eAAO,MAAM,YAAY,EAAE,OAK1B,CAAC;AAGF,eAAO,MAAM,cAAc,EAAE,OAa5B,CAAC;AAGF,wBAAgB,aAAa,CAAC,CAAC,SAAS,KAAK,EAAE,IAAI,GAAG,OAAO,EAC3D,SAAS,EAAE,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,EACpC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,QAAQ,CAAC,IAAI,CAAC,GAC5B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAEzB"}
|
|
1
|
+
{"version":3,"file":"matchers.d.ts","sourceRoot":"","sources":["../../src/error/matchers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACxC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAG3C,eAAO,MAAM,YAAY,EAAE,OAK1B,CAAC;AAGF,eAAO,MAAM,cAAc,EAAE,OAa5B,CAAC;AAGF,eAAO,MAAM,cAAc,EAAE,OAc5B,CAAC;AAGF,eAAO,MAAM,aAAa,EAAE,OAS3B,CAAC;AAGF,eAAO,MAAM,aAAa,EAAE,OAe3B,CAAC;AAGF,eAAO,MAAM,gBAAgB,EAAE,OAU9B,CAAC;AAGF,wBAAgB,aAAa,CAAC,CAAC,SAAS,KAAK,EAAE,IAAI,GAAG,OAAO,EAC3D,SAAS,EAAE,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,EACpC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,QAAQ,CAAC,IAAI,CAAC,GAC5B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAEzB"}
|
package/dist/error/matchers.js
CHANGED
|
@@ -20,6 +20,59 @@ export const timeoutMatcher = (err) => {
|
|
|
20
20
|
}
|
|
21
21
|
return null;
|
|
22
22
|
};
|
|
23
|
+
// Matcher para objetos con propiedad "message" (ej: { message: "Error X" })
|
|
24
|
+
export const messageMatcher = (err) => {
|
|
25
|
+
if (typeof err === "object" &&
|
|
26
|
+
err !== null &&
|
|
27
|
+
"message" in err &&
|
|
28
|
+
typeof err.message === "string") {
|
|
29
|
+
return {
|
|
30
|
+
code: "UNKNOWN",
|
|
31
|
+
message: err.message,
|
|
32
|
+
cause: err,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
return null;
|
|
36
|
+
};
|
|
37
|
+
// Matcher para errores lanzados como string literal (ej: throw "Error X")
|
|
38
|
+
export const stringMatcher = (err) => {
|
|
39
|
+
if (typeof err === "string") {
|
|
40
|
+
return {
|
|
41
|
+
code: "UNKNOWN",
|
|
42
|
+
message: err,
|
|
43
|
+
cause: err,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
return null;
|
|
47
|
+
};
|
|
48
|
+
// Matcher para errores con status/statusCode (común en clientes HTTP y APIs)
|
|
49
|
+
export const statusMatcher = (err) => {
|
|
50
|
+
if (typeof err === "object" && err !== null) {
|
|
51
|
+
// Comprobamos status o statusCode
|
|
52
|
+
const status = err.status ?? err.statusCode;
|
|
53
|
+
if (typeof status === "number") {
|
|
54
|
+
return {
|
|
55
|
+
code: "HTTP",
|
|
56
|
+
message: err.message || `HTTP Error ${status}`,
|
|
57
|
+
status,
|
|
58
|
+
cause: err,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return null;
|
|
63
|
+
};
|
|
64
|
+
// Matcher para AggregateError (Promise.any, etc)
|
|
65
|
+
export const aggregateMatcher = (err) => {
|
|
66
|
+
if (typeof AggregateError !== "undefined" && err instanceof AggregateError) {
|
|
67
|
+
return {
|
|
68
|
+
code: "UNKNOWN",
|
|
69
|
+
message: err.message || "Multiple errors occurred",
|
|
70
|
+
cause: err,
|
|
71
|
+
meta: { errors: err.errors },
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
return null;
|
|
75
|
+
};
|
|
23
76
|
// Helper para crear matcher basado en "instanceof" (plugin-friendly)
|
|
24
77
|
export function matchInstance(ErrorCtor, map) {
|
|
25
78
|
return (err) => (err instanceof ErrorCtor ? map(err) : null);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"matchers.js","sourceRoot":"","sources":["../../src/error/matchers.ts"],"names":[],"mappings":"AAGA,uEAAuE;AACvE,MAAM,CAAC,MAAM,YAAY,GAAY,CAAC,GAAG,EAAE,EAAE;IAC3C,IAAI,GAAG,YAAY,YAAY,IAAI,GAAG,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;QAC7D,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,mBAAmB,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;IACvE,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC,CAAC;AAEF,wFAAwF;AACxF,MAAM,CAAC,MAAM,cAAc,GAAY,CAAC,GAAG,EAAE,EAAE;IAC7C,IAAI,GAAG,YAAY,YAAY,IAAI,GAAG,CAAC,IAAI,KAAK,cAAc,EAAE,CAAC;QAC/D,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,mBAAmB,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;IACvE,CAAC;IACD,qDAAqD;IACrD,IAAI,GAAG,YAAY,KAAK,IAAI,GAAG,CAAC,IAAI,KAAK,cAAc,EAAE,CAAC;QACxD,OAAO;YACL,IAAI,EAAE,SAAS;YACf,OAAO,EAAE,GAAG,CAAC,OAAO,IAAI,mBAAmB;YAC3C,KAAK,EAAE,GAAG;SACX,CAAC;IACJ,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC,CAAC;AAEF,qEAAqE;AACrE,MAAM,UAAU,aAAa,CAC3B,SAAoC,EACpC,GAA6B;IAE7B,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,YAAY,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;AAC/D,CAAC"}
|
|
1
|
+
{"version":3,"file":"matchers.js","sourceRoot":"","sources":["../../src/error/matchers.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
export { run } from "./run";
|
|
2
|
-
export
|
|
2
|
+
export { runAll } from "./runAll";
|
|
3
|
+
export type { RunAllOptions } from "./runAll";
|
|
4
|
+
export type { RunOptions, RunResult, RetryOptions } from "./types";
|
|
3
5
|
export type { AppError, AppErrorCode } from "./error/types";
|
|
4
6
|
export { toAppError, defaultFallback, createNormalizer, } from "./error/normalize";
|
|
5
|
-
export { abortMatcher, timeoutMatcher, matchInstance } from "./error/matchers";
|
|
7
|
+
export { abortMatcher, timeoutMatcher, matchInstance, messageMatcher, stringMatcher, statusMatcher, aggregateMatcher, } from "./error/matchers";
|
|
6
8
|
export { createClient } from "./client";
|
|
7
9
|
export type { CreateClientOptions } from "./client";
|
|
8
10
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAC5B,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAC5B,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,YAAY,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAC9C,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEnE,YAAY,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC5D,OAAO,EACL,UAAU,EACV,eAAe,EACf,gBAAgB,GACjB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,YAAY,EACZ,cAAc,EACd,aAAa,EACb,cAAc,EACd,aAAa,EACb,aAAa,EACb,gBAAgB,GACjB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACxC,YAAY,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { run } from "./run";
|
|
2
|
+
export { runAll } from "./runAll";
|
|
2
3
|
export { toAppError, defaultFallback, createNormalizer, } from "./error/normalize";
|
|
3
|
-
export { abortMatcher, timeoutMatcher, matchInstance } from "./error/matchers";
|
|
4
|
+
export { abortMatcher, timeoutMatcher, matchInstance, messageMatcher, stringMatcher, statusMatcher, aggregateMatcher, } from "./error/matchers";
|
|
4
5
|
export { createClient } from "./client";
|
|
5
6
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAC5B,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAKlC,OAAO,EACL,UAAU,EACV,eAAe,EACf,gBAAgB,GACjB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,YAAY,EACZ,cAAc,EACd,aAAa,EACb,cAAc,EACd,aAAa,EACb,aAAa,EACb,gBAAgB,GACjB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC"}
|
package/dist/run.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE9C,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAErD;;;;;;;;GAQG;AACH,wBAAsB,GAAG,CAAC,CAAC,EAAE,CAAC,SAAS,QAAQ,GAAG,QAAQ,EACxD,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,OAAO,GAAE,UAAU,CAAC,CAAC,EAAE,CAAC,CAAM,GAC7B,OAAO,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,
|
|
1
|
+
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE9C,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAErD;;;;;;;;GAQG;AACH,wBAAsB,GAAG,CAAC,CAAC,EAAE,CAAC,SAAS,QAAQ,GAAG,QAAQ,EACxD,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,OAAO,GAAE,UAAU,CAAC,CAAC,EAAE,CAAC,CAAM,GAC7B,OAAO,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CA4D1B"}
|
package/dist/run.js
CHANGED
|
@@ -9,25 +9,49 @@ import { toAppError as defaultToAppError } from "./error/normalize";
|
|
|
9
9
|
* React effects, and any async context.
|
|
10
10
|
*/
|
|
11
11
|
export async function run(fn, options = {}) {
|
|
12
|
-
const { toError = defaultToAppError, mapError, onError, onSuccess, onFinally, ignoreAbort = true, } = options;
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
12
|
+
const { toError = defaultToAppError, mapError, onError, onSuccess, onFinally, ignoreAbort = true, retries = 0, retryDelay = 0, retryBackoff = "fixed", shouldRetry = () => true, jitter = false, } = options;
|
|
13
|
+
let attempt = 0;
|
|
14
|
+
while (true) {
|
|
15
|
+
try {
|
|
16
|
+
const data = await fn();
|
|
17
|
+
onSuccess?.(data);
|
|
18
|
+
onFinally?.(); // Always call finally on success (last attempt)
|
|
19
|
+
return { ok: true, data, error: null };
|
|
20
|
+
}
|
|
21
|
+
catch (e) {
|
|
22
|
+
let err = toError(e);
|
|
23
|
+
if (mapError)
|
|
24
|
+
err = mapError(err);
|
|
25
|
+
// Abort is critical: stop immediately, no retries
|
|
26
|
+
const isAborted = err.code === "ABORTED";
|
|
27
|
+
if (isAborted) {
|
|
28
|
+
if (ignoreAbort) {
|
|
29
|
+
onFinally?.();
|
|
30
|
+
return { ok: false, data: null, error: err };
|
|
31
|
+
}
|
|
32
|
+
// If not ignoring abort, we fall through to onError and return
|
|
33
|
+
}
|
|
34
|
+
else if (attempt < retries && shouldRetry(err)) {
|
|
35
|
+
attempt++;
|
|
36
|
+
let delay = retryDelay;
|
|
37
|
+
if (retryBackoff === "linear")
|
|
38
|
+
delay *= attempt;
|
|
39
|
+
if (retryBackoff === "exponential")
|
|
40
|
+
delay *= Math.pow(2, attempt - 1); // 1st retry: 2^0=1x, 2nd: 2^1=2x
|
|
41
|
+
if (jitter) {
|
|
42
|
+
delay = delay * (0.5 + Math.random()); // +/- 50% randomization or similar
|
|
43
|
+
}
|
|
44
|
+
// Wait before retrying
|
|
45
|
+
if (delay > 0) {
|
|
46
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
47
|
+
}
|
|
48
|
+
continue; // Retry loop
|
|
49
|
+
}
|
|
50
|
+
// Final failure or aborted
|
|
51
|
+
onError?.(err);
|
|
52
|
+
onFinally?.();
|
|
24
53
|
return { ok: false, data: null, error: err };
|
|
25
54
|
}
|
|
26
|
-
onError?.(err);
|
|
27
|
-
return { ok: false, data: null, error: err };
|
|
28
|
-
}
|
|
29
|
-
finally {
|
|
30
|
-
onFinally?.();
|
|
31
55
|
}
|
|
32
56
|
}
|
|
33
57
|
//# sourceMappingURL=run.js.map
|
package/dist/run.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run.js","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,IAAI,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAGpE;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,GAAG,CACvB,EAAoB,EACpB,UAA4B,EAAE;IAE9B,MAAM,EACJ,OAAO,GAAG,iBAAmD,EAC7D,QAAQ,EACR,OAAO,EACP,SAAS,EACT,SAAS,EACT,WAAW,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"run.js","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,IAAI,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAGpE;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,GAAG,CACvB,EAAoB,EACpB,UAA4B,EAAE;IAE9B,MAAM,EACJ,OAAO,GAAG,iBAAmD,EAC7D,QAAQ,EACR,OAAO,EACP,SAAS,EACT,SAAS,EACT,WAAW,GAAG,IAAI,EAClB,OAAO,GAAG,CAAC,EACX,UAAU,GAAG,CAAC,EACd,YAAY,GAAG,OAAO,EACtB,WAAW,GAAG,GAAG,EAAE,CAAC,IAAI,EACxB,MAAM,GAAG,KAAK,GACf,GAAG,OAAO,CAAC;IAEZ,IAAI,OAAO,GAAG,CAAC,CAAC;IAEhB,OAAO,IAAI,EAAE,CAAC;QACZ,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,EAAE,EAAE,CAAC;YACxB,SAAS,EAAE,CAAC,IAAI,CAAC,CAAC;YAClB,SAAS,EAAE,EAAE,CAAC,CAAC,gDAAgD;YAC/D,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;QACzC,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,IAAI,GAAG,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;YACrB,IAAI,QAAQ;gBAAE,GAAG,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;YAElC,kDAAkD;YAClD,MAAM,SAAS,GAAG,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC;YAEzC,IAAI,SAAS,EAAE,CAAC;gBACb,IAAI,WAAW,EAAE,CAAC;oBACf,SAAS,EAAE,EAAE,CAAC;oBACd,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;gBAChD,CAAC;gBACD,+DAA+D;YAClE,CAAC;iBAAM,IAAI,OAAO,GAAG,OAAO,IAAI,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC;gBACjD,OAAO,EAAE,CAAC;gBAEV,IAAI,KAAK,GAAG,UAAU,CAAC;gBACvB,IAAI,YAAY,KAAK,QAAQ;oBAAE,KAAK,IAAI,OAAO,CAAC;gBAChD,IAAI,YAAY,KAAK,aAAa;oBAAE,KAAK,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,iCAAiC;gBAExG,IAAI,MAAM,EAAE,CAAC;oBACV,KAAK,GAAG,KAAK,GAAG,CAAC,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,mCAAmC;gBAC7E,CAAC;gBAED,uBAAuB;gBACvB,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;oBACZ,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC;gBAC/D,CAAC;gBACD,SAAS,CAAC,aAAa;YACzB,CAAC;YAED,2BAA2B;YAC3B,OAAO,EAAE,CAAC,GAAG,CAAC,CAAC;YACf,SAAS,EAAE,EAAE,CAAC;YACd,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;QAC/C,CAAC;IACH,CAAC;AACH,CAAC"}
|
package/dist/runAll.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { AppError } from "./error/types";
|
|
2
|
+
import type { RunOptions, RunResult } from "./types";
|
|
3
|
+
export type RunAllOptions<T, E extends AppError = AppError> = RunOptions<T, E> & {
|
|
4
|
+
/**
|
|
5
|
+
* Maximum number of concurrent tasks to run.
|
|
6
|
+
* @default Infinity
|
|
7
|
+
*/
|
|
8
|
+
concurrency?: number;
|
|
9
|
+
/**
|
|
10
|
+
* Called after each task finishes (success or error).
|
|
11
|
+
*/
|
|
12
|
+
onSettled?: (result: RunResult<T, E>, index: number) => void;
|
|
13
|
+
};
|
|
14
|
+
export declare function runAll<T, E extends AppError = AppError>(tasks: Array<() => Promise<T>>, options?: RunAllOptions<T, E>): Promise<RunResult<T, E>[]>;
|
|
15
|
+
//# sourceMappingURL=runAll.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runAll.d.ts","sourceRoot":"","sources":["../src/runAll.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAErD,MAAM,MAAM,aAAa,CAAC,CAAC,EAAE,CAAC,SAAS,QAAQ,GAAG,QAAQ,IAAI,UAAU,CACtE,CAAC,EACD,CAAC,CACF,GAAG;IACF;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;OAEG;IACH,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9D,CAAC;AAEF,wBAAsB,MAAM,CAAC,CAAC,EAAE,CAAC,SAAS,QAAQ,GAAG,QAAQ,EAC3D,KAAK,EAAE,KAAK,CAAC,MAAM,OAAO,CAAC,CAAC,CAAC,CAAC,EAC9B,OAAO,GAAE,aAAa,CAAC,CAAC,EAAE,CAAC,CAAM,GAChC,OAAO,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAuC5B"}
|
package/dist/runAll.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { run } from "./run";
|
|
2
|
+
export async function runAll(tasks, options = {}) {
|
|
3
|
+
const { concurrency = Infinity, onSettled, ...runOptions } = options;
|
|
4
|
+
if (tasks.length === 0)
|
|
5
|
+
return [];
|
|
6
|
+
const limit = Number.isFinite(concurrency)
|
|
7
|
+
? Math.max(1, Math.floor(concurrency))
|
|
8
|
+
: Infinity;
|
|
9
|
+
// Run all in parallel if unlimited or limit >= count
|
|
10
|
+
if (limit >= tasks.length) {
|
|
11
|
+
const results = await Promise.all(tasks.map((t) => run(t, runOptions)));
|
|
12
|
+
results.forEach((r, i) => onSettled?.(r, i));
|
|
13
|
+
return results;
|
|
14
|
+
}
|
|
15
|
+
const results = new Array(tasks.length);
|
|
16
|
+
let nextIndex = 0;
|
|
17
|
+
const worker = async () => {
|
|
18
|
+
while (true) {
|
|
19
|
+
const i = nextIndex++;
|
|
20
|
+
if (i >= tasks.length)
|
|
21
|
+
return;
|
|
22
|
+
const task = tasks[i];
|
|
23
|
+
if (!task)
|
|
24
|
+
continue;
|
|
25
|
+
const res = await run(task, runOptions);
|
|
26
|
+
results[i] = res;
|
|
27
|
+
onSettled?.(res, i);
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
await Promise.all(Array.from({ length: Math.min(limit, tasks.length) }, worker));
|
|
31
|
+
return results;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=runAll.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runAll.js","sourceRoot":"","sources":["../src/runAll.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAoB5B,MAAM,CAAC,KAAK,UAAU,MAAM,CAC1B,KAA8B,EAC9B,UAA+B,EAAE;IAEjC,MAAM,EAAE,WAAW,GAAG,QAAQ,EAAE,SAAS,EAAE,GAAG,UAAU,EAAE,GAAG,OAAO,CAAC;IAErE,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAElC,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC;QACxC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;QACtC,CAAC,CAAC,QAAQ,CAAC;IAEb,qDAAqD;IACrD,IAAI,KAAK,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;QAC1B,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAC/B,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAO,CAAC,EAAE,UAAU,CAAC,CAAC,CAC3C,CAAC;QACF,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,SAAS,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAC7C,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,MAAM,OAAO,GAAsB,IAAI,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC3D,IAAI,SAAS,GAAG,CAAC,CAAC;IAElB,MAAM,MAAM,GAAG,KAAK,IAAI,EAAE;QACxB,OAAO,IAAI,EAAE,CAAC;YACZ,MAAM,CAAC,GAAG,SAAS,EAAE,CAAC;YACtB,IAAI,CAAC,IAAI,KAAK,CAAC,MAAM;gBAAE,OAAO;YAE9B,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;YACtB,IAAI,CAAC,IAAI;gBAAE,SAAS;YAEpB,MAAM,GAAG,GAAG,MAAM,GAAG,CAAO,IAAI,EAAE,UAAU,CAAC,CAAC;YAC9C,OAAO,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC;YACjB,SAAS,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QACtB,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,OAAO,CAAC,GAAG,CACf,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,CAC9D,CAAC;IACF,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,5 +1,36 @@
|
|
|
1
1
|
import type { AppError } from "./error/types";
|
|
2
|
-
export type
|
|
2
|
+
export type RetryOptions<E extends AppError = AppError> = {
|
|
3
|
+
/**
|
|
4
|
+
* Number of retries to attempt.
|
|
5
|
+
* @default 0
|
|
6
|
+
*/
|
|
7
|
+
retries?: number;
|
|
8
|
+
/**
|
|
9
|
+
* Delay in milliseconds between retries.
|
|
10
|
+
* @default 0
|
|
11
|
+
*/
|
|
12
|
+
retryDelay?: number;
|
|
13
|
+
/**
|
|
14
|
+
* Type of backoff to apply to the delay.
|
|
15
|
+
* - "fixed": Always waits `retryDelay`.
|
|
16
|
+
* - "linear": Waits `retryDelay * attempt`.
|
|
17
|
+
* - "exponential": Waits `retryDelay * (2 ** attempt)`.
|
|
18
|
+
* @default "fixed"
|
|
19
|
+
*/
|
|
20
|
+
retryBackoff?: "fixed" | "linear" | "exponential";
|
|
21
|
+
/**
|
|
22
|
+
* Function to determine if a retry should be attempted.
|
|
23
|
+
* Returns true to retry, false to stop.
|
|
24
|
+
* @default () => true
|
|
25
|
+
*/
|
|
26
|
+
shouldRetry?: (error: E) => boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Adds random jitter to the delay to prevent thundering herd.
|
|
29
|
+
* @default false
|
|
30
|
+
*/
|
|
31
|
+
jitter?: boolean;
|
|
32
|
+
};
|
|
33
|
+
export type RunOptions<T, E extends AppError = AppError> = RetryOptions<E> & {
|
|
3
34
|
/**
|
|
4
35
|
* Converts an unknown thrown value into your normalized error type `E`.
|
|
5
36
|
*
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE9C,MAAM,MAAM,UAAU,CAAC,CAAC,EAAE,CAAC,SAAS,QAAQ,GAAG,QAAQ,IAAI;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE9C,MAAM,MAAM,YAAY,CAAC,CAAC,SAAS,QAAQ,GAAG,QAAQ,IAAI;IACxD;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,aAAa,CAAC;IAElD;;;;OAIG;IACH,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,OAAO,CAAC;IAEpC;;;OAGG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,UAAU,CAAC,CAAC,EAAE,CAAC,SAAS,QAAQ,GAAG,QAAQ,IAAI,YAAY,CAAC,CAAC,CAAC,GAAG;IAC3E;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,CAAC,CAAC;IAE9B;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,CAAC;IAE3B;;;;OAIG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;IAE7B;;OAEG;IACH,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,IAAI,CAAC;IAE9B;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IAEvB;;;;;;;;OAQG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,SAAS,CAAC,CAAC,EAAE,CAAC,SAAS,QAAQ,GAAG,QAAQ,IAClD;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,CAAC,CAAC;IAAC,KAAK,EAAE,IAAI,CAAA;CAAE,GAClC;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,CAAC,CAAA;CAAE,CAAC"}
|