runtry 0.3.0 → 0.4.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 CHANGED
@@ -69,10 +69,9 @@ You can configure automatic retries for failed operations:
69
69
  ```ts
70
70
  await run(fetchData, {
71
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
72
+ retryDelay: (attempt, err) => attempt * 1000,
73
+ jitter: { ratio: 0.5, mode: "full" }, // adds randomization to delay
74
+ shouldRetry: (attempt, err) => err.status === 503, // optional filter
76
75
  });
77
76
  ```
78
77
 
@@ -92,7 +91,7 @@ const tasks = [
92
91
  ];
93
92
 
94
93
  // Run max 2 at a time
95
- const results = await runAll(tasks, {
94
+ const results = await runAll(tasks, {
96
95
  concurrency: 2,
97
96
  onSettled: (res, index) => console.log(`Task ${index} done`),
98
97
  retries: 2, // Inherits all run() options including retries!
@@ -146,20 +145,20 @@ const res = await run(getDocuments, {
146
145
 
147
146
  ---
148
147
 
149
- ## `createClient()` (configure once, reuse everywhere)
148
+ ## `createRunner()` (configure once, reuse everywhere)
150
149
 
151
- If you don't want to pass `toError` every time, create a client:
150
+ If you don't want to pass `toError` every time, create a runner:
152
151
 
153
152
  ```ts
154
153
  import {
155
- createClient,
154
+ createRunner,
156
155
  abortMatcher,
157
156
  matchInstance,
158
157
  defaultFallback,
159
158
  } from "runtry";
160
159
  import { HttpError } from "./http-error";
161
160
 
162
- const client = createClient({
161
+ const runner = createRunner({
163
162
  matchers: [
164
163
  abortMatcher,
165
164
  matchInstance(HttpError, (e) => ({
@@ -184,9 +183,9 @@ const result = await client.run(getDocuments, {
184
183
  ## React example (loading + toast, no try/catch)
185
184
 
186
185
  ```ts
187
- import { createClient, abortMatcher, defaultFallback } from "runtry";
186
+ import { createRunner, abortMatcher, defaultFallback } from "runtry";
188
187
 
189
- const client = createClient({
188
+ const runner = createRunner({
190
189
  matchers: [abortMatcher],
191
190
  fallback: defaultFallback,
192
191
  });
@@ -1,6 +1,6 @@
1
1
  import type { AppError } from "./types";
2
- export type Matcher<E extends AppError = AppError> = (err: unknown) => E | null;
3
- export declare function createNormalizer<E extends AppError>(matchers: Matcher<E>[], fallback: (err: unknown) => E): (err: unknown) => E;
2
+ export type Rule<E extends AppError = AppError> = (err: unknown) => E | null;
3
+ export declare function createNormalizer<E extends AppError>(rules: Rule<E>[], fallback: (err: unknown) => E): (err: unknown) => E;
4
4
  export declare function defaultFallback(err: unknown): AppError;
5
5
  export declare function toAppError(err: unknown): AppError;
6
6
  //# sourceMappingURL=normalize.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"normalize.d.ts","sourceRoot":"","sources":["../../src/error/normalize.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAExC,MAAM,MAAM,OAAO,CAAC,CAAC,SAAS,QAAQ,GAAG,QAAQ,IAAI,CAAC,GAAG,EAAE,OAAO,KAAK,CAAC,GAAG,IAAI,CAAC;AAEhF,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,QAAQ,EACjD,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,EACtB,QAAQ,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,CAAC,IAErB,KAAK,OAAO,KAAG,CAAC,CAOzB;AAGD,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,GAAG,QAAQ,CAQtD;AAGD,wBAAgB,UAAU,CAAC,GAAG,EAAE,OAAO,GAAG,QAAQ,CAMjD"}
1
+ {"version":3,"file":"normalize.d.ts","sourceRoot":"","sources":["../../src/error/normalize.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAExC,MAAM,MAAM,IAAI,CAAC,CAAC,SAAS,QAAQ,GAAG,QAAQ,IAAI,CAAC,GAAG,EAAE,OAAO,KAAK,CAAC,GAAG,IAAI,CAAC;AAE7E,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,QAAQ,EACjD,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,EAChB,QAAQ,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,CAAC,IAErB,KAAK,OAAO,KAAG,CAAC,CAOzB;AAGD,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,GAAG,QAAQ,CAQtD;AAGD,wBAAgB,UAAU,CAAC,GAAG,EAAE,OAAO,GAAG,QAAQ,CAMjD"}
@@ -1,7 +1,7 @@
1
- export function createNormalizer(matchers, fallback) {
1
+ export function createNormalizer(rules, fallback) {
2
2
  return (err) => {
3
- for (const m of matchers) {
4
- const out = m(err);
3
+ for (const r of rules) {
4
+ const out = r(err);
5
5
  if (out)
6
6
  return out;
7
7
  }
@@ -18,7 +18,7 @@ export function defaultFallback(err) {
18
18
  }
19
19
  return { code: "UNKNOWN", message: "Something went wrong", cause: err };
20
20
  }
21
- // Normalizador "default" que incluye matcher de abort (muy útil en UI)
21
+ // Normalizador "default" que incluye rule de abort (muy útil en UI)
22
22
  export function toAppError(err) {
23
23
  // AbortError (browser / fetch / AbortController)
24
24
  if (err instanceof DOMException && err.name === "AbortError") {
@@ -1 +1 @@
1
- {"version":3,"file":"normalize.js","sourceRoot":"","sources":["../../src/error/normalize.ts"],"names":[],"mappings":"AAIA,MAAM,UAAU,gBAAgB,CAC9B,QAAsB,EACtB,QAA6B;IAE7B,OAAO,CAAC,GAAY,EAAK,EAAE;QACzB,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;YACzB,MAAM,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;YACnB,IAAI,GAAG;gBAAE,OAAO,GAAG,CAAC;QACtB,CAAC;QACD,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC;IACvB,CAAC,CAAC;AACJ,CAAC;AAED,kDAAkD;AAClD,MAAM,UAAU,eAAe,CAAC,GAAY;IAC1C,IAAI,GAAG,YAAY,KAAK,EAAE,CAAC;QACzB,mEAAmE;QACnE,gEAAgE;QAChE,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;QAC9D,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,IAAI,sBAAsB,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;IAC9E,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,sBAAsB,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;AAC1E,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,UAAU,CAAC,GAAY;IACrC,iDAAiD;IACjD,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,eAAe,CAAC,GAAG,CAAC,CAAC;AAC9B,CAAC"}
1
+ {"version":3,"file":"normalize.js","sourceRoot":"","sources":["../../src/error/normalize.ts"],"names":[],"mappings":"AAIA,MAAM,UAAU,gBAAgB,CAC9B,KAAgB,EAChB,QAA6B;IAE7B,OAAO,CAAC,GAAY,EAAK,EAAE;QACzB,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;YACtB,MAAM,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;YACnB,IAAI,GAAG;gBAAE,OAAO,GAAG,CAAC;QACtB,CAAC;QACD,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC;IACvB,CAAC,CAAC;AACJ,CAAC;AAED,kDAAkD;AAClD,MAAM,UAAU,eAAe,CAAC,GAAY;IAC1C,IAAI,GAAG,YAAY,KAAK,EAAE,CAAC;QACzB,mEAAmE;QACnE,gEAAgE;QAChE,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;QAC9D,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,IAAI,sBAAsB,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;IAC9E,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,sBAAsB,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;AAC1E,CAAC;AAED,oEAAoE;AACpE,MAAM,UAAU,UAAU,CAAC,GAAY;IACrC,iDAAiD;IACjD,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,eAAe,CAAC,GAAG,CAAC,CAAC;AAC9B,CAAC"}
@@ -0,0 +1,10 @@
1
+ import type { AppError } from "./types";
2
+ import type { Rule } from "./normalize";
3
+ export declare const abortRule: Rule;
4
+ export declare const timeoutRule: Rule;
5
+ export declare const messageRule: Rule;
6
+ export declare const stringRule: Rule;
7
+ export declare const statusRule: Rule;
8
+ export declare const aggregateRule: Rule;
9
+ export declare function matchInstance<T extends Error, Meta = unknown>(ErrorCtor: new (...args: any[]) => T, map: (e: T) => AppError<Meta>): Rule<AppError<Meta>>;
10
+ //# sourceMappingURL=rules.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rules.d.ts","sourceRoot":"","sources":["../../src/error/rules.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACxC,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAGxC,eAAO,MAAM,SAAS,EAAE,IAKvB,CAAC;AAGF,eAAO,MAAM,WAAW,EAAE,IAazB,CAAC;AAGF,eAAO,MAAM,WAAW,EAAE,IAczB,CAAC;AAGF,eAAO,MAAM,UAAU,EAAE,IASxB,CAAC;AAGF,eAAO,MAAM,UAAU,EAAE,IAexB,CAAC;AAGF,eAAO,MAAM,aAAa,EAAE,IAU3B,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,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAEtB"}
@@ -0,0 +1,80 @@
1
+ // Matcher genérico para AbortError (por si no quieres usar toAppError)
2
+ export const abortRule = (err) => {
3
+ if (err instanceof DOMException && err.name === "AbortError") {
4
+ return { code: "ABORTED", message: "Request cancelled", cause: err };
5
+ }
6
+ return null;
7
+ };
8
+ // Matcher para "timeout" (si el user usa AbortSignal.timeout o libs que tiran ese name)
9
+ export const timeoutRule = (err) => {
10
+ if (err instanceof DOMException && err.name === "TimeoutError") {
11
+ return { code: "TIMEOUT", message: "Request timed out", cause: err };
12
+ }
13
+ // algunas libs tiran Error con name = "TimeoutError"
14
+ if (err instanceof Error && err.name === "TimeoutError") {
15
+ return {
16
+ code: "TIMEOUT",
17
+ message: err.message || "Request timed out",
18
+ cause: err,
19
+ };
20
+ }
21
+ return null;
22
+ };
23
+ // Matcher para objetos con propiedad "message" (ej: { message: "Error X" })
24
+ export const messageRule = (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 stringRule = (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 statusRule = (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 aggregateRule = (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
+ };
76
+ // Helper para crear matcher basado en "instanceof" (plugin-friendly)
77
+ export function matchInstance(ErrorCtor, map) {
78
+ return (err) => (err instanceof ErrorCtor ? map(err) : null);
79
+ }
80
+ //# sourceMappingURL=rules.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rules.js","sourceRoot":"","sources":["../../src/error/rules.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -4,7 +4,7 @@ export type { RunAllOptions } from "./runAll";
4
4
  export type { RunOptions, RunResult, RetryOptions } from "./types";
5
5
  export type { AppError, AppErrorCode } from "./error/types";
6
6
  export { toAppError, defaultFallback, createNormalizer, } from "./error/normalize";
7
- export { abortMatcher, timeoutMatcher, matchInstance, messageMatcher, stringMatcher, statusMatcher, aggregateMatcher, } from "./error/matchers";
8
- export { createClient } from "./client";
9
- export type { CreateClientOptions } from "./client";
7
+ export { abortRule, timeoutRule, matchInstance, messageRule, stringRule, statusRule, aggregateRule, } from "./error/rules";
8
+ export { createRunner } from "./runner";
9
+ export type { CreateRunnerOptions } from "./runner";
10
10
  //# sourceMappingURL=index.d.ts.map
@@ -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,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"}
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,SAAS,EACT,WAAW,EACX,aAAa,EACb,WAAW,EACX,UAAU,EACV,UAAU,EACV,aAAa,GACd,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACxC,YAAY,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC"}
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export { run } from "./run";
2
2
  export { runAll } from "./runAll";
3
3
  export { toAppError, defaultFallback, createNormalizer, } from "./error/normalize";
4
- export { abortMatcher, timeoutMatcher, matchInstance, messageMatcher, stringMatcher, statusMatcher, aggregateMatcher, } from "./error/matchers";
5
- export { createClient } from "./client";
4
+ export { abortRule, timeoutRule, matchInstance, messageRule, stringRule, statusRule, aggregateRule, } from "./error/rules";
5
+ export { createRunner } from "./runner";
6
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;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"}
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,SAAS,EACT,WAAW,EACX,aAAa,EACb,WAAW,EACX,UAAU,EACV,UAAU,EACV,aAAa,GACd,MAAM,eAAe,CAAC;AAEvB,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,CA4D1B"}
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;AAGrD;;;;;;;;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,CAmE1B"}
package/dist/run.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { toAppError as defaultToAppError } from "./error/normalize";
2
+ import { applyJitter, resolveRetryDelay, sleep } from "./utils";
2
3
  /**
3
4
  * Executes an async operation and returns a Result instead of throwing.
4
5
  *
@@ -9,43 +10,40 @@ import { toAppError as defaultToAppError } from "./error/normalize";
9
10
  * React effects, and any async context.
10
11
  */
11
12
  export async function run(fn, options = {}) {
12
- const { toError = defaultToAppError, mapError, onError, onSuccess, onFinally, ignoreAbort = true, retries = 0, retryDelay = 0, retryBackoff = "fixed", shouldRetry = () => true, jitter = false, } = options;
13
+ const { toError = defaultToAppError, mapError, onError, onSuccess, onFinally, ignoreAbort = true, retries = 0, retryDelay, shouldRetry = () => true, jitter = { ratio: 0.5, mode: "full" }, } = options;
14
+ const defaultBaseDelay = retries > 0 ? 300 : 0;
13
15
  let attempt = 0;
14
16
  while (true) {
15
17
  try {
16
18
  const data = await fn();
17
19
  onSuccess?.(data);
18
- onFinally?.(); // Always call finally on success (last attempt)
20
+ onFinally?.();
19
21
  return { ok: true, data, error: null };
20
22
  }
21
23
  catch (e) {
22
24
  let err = toError(e);
23
25
  if (mapError)
24
26
  err = mapError(err);
25
- // Abort is critical: stop immediately, no retries
26
27
  const isAborted = err.code === "ABORTED";
27
28
  if (isAborted) {
28
- if (ignoreAbort) {
29
- onFinally?.();
30
- return { ok: false, data: null, error: err };
29
+ if (!ignoreAbort) {
30
+ onError?.(err);
31
31
  }
32
+ onFinally?.();
33
+ return { ok: false, data: null, error: err };
32
34
  // If not ignoring abort, we fall through to onError and return
33
35
  }
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
36
+ const nextAttempt = attempt + 1;
37
+ const canRetry = attempt < retries && shouldRetry(nextAttempt, err);
38
+ if (canRetry) {
39
+ attempt = nextAttempt;
40
+ let delay = resolveRetryDelay(retryDelay, attempt, err, defaultBaseDelay);
41
+ if (!Number.isFinite(delay) || delay < 0)
42
+ delay = 0;
43
+ delay = applyJitter(delay, jitter);
44
+ if (delay > 0)
45
+ await sleep(delay);
46
+ continue;
49
47
  }
50
48
  // Final failure or aborted
51
49
  onError?.(err);
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,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"}
1
+ {"version":3,"file":"run.js","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,IAAI,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAEpE,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAEhE;;;;;;;;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,EACV,WAAW,GAAG,GAAG,EAAE,CAAC,IAAI,EACxB,MAAM,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,GACtC,GAAG,OAAO,CAAC;IAEZ,MAAM,gBAAgB,GAAG,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAE/C,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;YACd,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,MAAM,SAAS,GAAG,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC;YAEzC,IAAI,SAAS,EAAE,CAAC;gBACd,IAAI,CAAC,WAAW,EAAE,CAAC;oBACjB,OAAO,EAAE,CAAC,GAAG,CAAC,CAAC;gBACjB,CAAC;gBAED,SAAS,EAAE,EAAE,CAAC;gBACd,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;gBAC7C,+DAA+D;YACjE,CAAC;YAED,MAAM,WAAW,GAAG,OAAO,GAAG,CAAC,CAAC;YAChC,MAAM,QAAQ,GAAG,OAAO,GAAG,OAAO,IAAI,WAAW,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC;YAEpE,IAAI,QAAQ,EAAE,CAAC;gBACb,OAAO,GAAG,WAAW,CAAC;gBAEtB,IAAI,KAAK,GAAG,iBAAiB,CAC3B,UAAU,EACV,OAAO,EACP,GAAG,EACH,gBAAgB,CACjB,CAAC;gBAEF,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC;oBAAE,KAAK,GAAG,CAAC,CAAC;gBAEpD,KAAK,GAAG,WAAW,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;gBAEnC,IAAI,KAAK,GAAG,CAAC;oBAAE,MAAM,KAAK,CAAC,KAAK,CAAC,CAAC;gBAClC,SAAS;YACX,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 CHANGED
@@ -1,5 +1,15 @@
1
1
  import type { AppError } from "./error/types";
2
2
  import type { RunOptions, RunResult } from "./types";
3
+ export type RunAllItemResult<T, E extends AppError = AppError> = ({
4
+ status: "ok";
5
+ } & RunResult<T, E>) | ({
6
+ status: "error";
7
+ } & RunResult<T, E>) | {
8
+ status: "skipped";
9
+ ok: false;
10
+ data: null;
11
+ error: null;
12
+ };
3
13
  export type RunAllOptions<T, E extends AppError = AppError> = RunOptions<T, E> & {
4
14
  /**
5
15
  * Maximum number of concurrent tasks to run.
@@ -7,9 +17,12 @@ export type RunAllOptions<T, E extends AppError = AppError> = RunOptions<T, E> &
7
17
  */
8
18
  concurrency?: number;
9
19
  /**
10
- * Called after each task finishes (success or error).
20
+ * Execution mode regarding errors.
21
+ * - "settle": Run all tasks (default).
22
+ * - "fail-fast": Stop starting new tasks if one fails.
23
+ * @default "settle"
11
24
  */
12
- onSettled?: (result: RunResult<T, E>, index: number) => void;
25
+ mode?: "settle" | "fail-fast";
13
26
  };
14
- export declare function runAll<T, E extends AppError = AppError>(tasks: Array<() => Promise<T>>, options?: RunAllOptions<T, E>): Promise<RunResult<T, E>[]>;
27
+ export declare function runAll<T, E extends AppError = AppError>(tasks: Array<() => Promise<T>>, options?: RunAllOptions<T, E>): Promise<RunAllItemResult<T, E>[]>;
15
28
  //# sourceMappingURL=runAll.d.ts.map
@@ -1 +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"}
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,gBAAgB,CAAC,CAAC,EAAE,CAAC,SAAS,QAAQ,GAAG,QAAQ,IACzD,CAAC;IAAE,MAAM,EAAE,IAAI,CAAA;CAAE,GAAG,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GACpC,CAAC;IAAE,MAAM,EAAE,OAAO,CAAA;CAAE,GAAG,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GACvC;IACE,MAAM,EAAE,SAAS,CAAC;IAClB,EAAE,EAAE,KAAK,CAAC;IACV,IAAI,EAAE,IAAI,CAAC;IACX,KAAK,EAAE,IAAI,CAAC;CACb,CAAC;AAEN,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;;;;;OAKG;IACH,IAAI,CAAC,EAAE,QAAQ,GAAG,WAAW,CAAC;CAC/B,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,gBAAgB,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAmEnC"}
package/dist/runAll.js CHANGED
@@ -1,33 +1,59 @@
1
1
  import { run } from "./run";
2
2
  export async function runAll(tasks, options = {}) {
3
- const { concurrency = Infinity, onSettled, ...runOptions } = options;
3
+ const { concurrency = Infinity, mode = "settle", ...runOptions } = options;
4
4
  if (tasks.length === 0)
5
5
  return [];
6
6
  const limit = Number.isFinite(concurrency)
7
7
  ? Math.max(1, Math.floor(concurrency))
8
8
  : Infinity;
9
+ const results = new Array(tasks.length);
10
+ let nextIndex = 0;
11
+ let aborted = false;
12
+ const setResult = (i, r) => {
13
+ results[i] = r.ok ? { ...r, status: "ok" } : { ...r, status: "error" };
14
+ };
15
+ const markSkipped = () => {
16
+ for (let i = 0; i < tasks.length; i++) {
17
+ if (results[i])
18
+ continue;
19
+ results[i] = {
20
+ status: "skipped",
21
+ ok: false,
22
+ data: null,
23
+ error: null,
24
+ };
25
+ }
26
+ };
9
27
  // Run all in parallel if unlimited or limit >= count
10
28
  if (limit >= tasks.length) {
11
- const results = await Promise.all(tasks.map((t) => run(t, runOptions)));
12
- results.forEach((r, i) => onSettled?.(r, i));
29
+ const rs = await Promise.all(tasks.map((t) => run(t, runOptions)));
30
+ rs.forEach((r, i) => {
31
+ setResult(i, r);
32
+ });
13
33
  return results;
14
34
  }
15
- const results = new Array(tasks.length);
16
- let nextIndex = 0;
17
35
  const worker = async () => {
18
36
  while (true) {
37
+ if (aborted)
38
+ return;
19
39
  const i = nextIndex++;
20
40
  if (i >= tasks.length)
21
41
  return;
22
42
  const task = tasks[i];
23
43
  if (!task)
24
- continue;
25
- const res = await run(task, runOptions);
26
- results[i] = res;
27
- onSettled?.(res, i);
44
+ continue; // skip if task is undefined
45
+ const r = await run(task, runOptions);
46
+ setResult(i, r);
47
+ if (!r.ok) {
48
+ if (mode === "fail-fast") {
49
+ aborted = true;
50
+ return;
51
+ }
52
+ }
28
53
  }
29
54
  };
30
- await Promise.all(Array.from({ length: Math.min(limit, tasks.length) }, worker));
55
+ await Promise.all(Array.from({ length: Math.min(limit, tasks.length) }, () => worker()));
56
+ markSkipped();
31
57
  return results;
32
58
  }
33
59
  //# sourceMappingURL=runAll.js.map
@@ -1 +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"}
1
+ {"version":3,"file":"runAll.js","sourceRoot":"","sources":["../src/runAll.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { AppError } from "./error/types";
2
+ import type { RunOptions } from "./types";
3
+ export type RunAllOrThrowOptions<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
+ export declare function runAllOrThrow<T, E extends AppError = AppError>(tasks: Array<() => Promise<T>>, options?: RunAllOrThrowOptions<T, E>): Promise<T[]>;
11
+ //# sourceMappingURL=runAllOrThrow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runAllOrThrow.d.ts","sourceRoot":"","sources":["../src/runAllOrThrow.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,KAAK,EAAE,UAAU,EAAa,MAAM,SAAS,CAAC;AAErD,MAAM,MAAM,oBAAoB,CAAC,CAAC,EAAE,CAAC,SAAS,QAAQ,GAAG,QAAQ,IAAI,UAAU,CAC7E,CAAC,EACD,CAAC,CACF,GAAG;IACF;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,wBAAsB,aAAa,CAAC,CAAC,EAAE,CAAC,SAAS,QAAQ,GAAG,QAAQ,EAClE,KAAK,EAAE,KAAK,CAAC,MAAM,OAAO,CAAC,CAAC,CAAC,CAAC,EAC9B,OAAO,GAAE,oBAAoB,CAAC,CAAC,EAAE,CAAC,CAAM,GACvC,OAAO,CAAC,CAAC,EAAE,CAAC,CAyDd"}
@@ -0,0 +1,48 @@
1
+ import { run } from "./run";
2
+ export async function runAllOrThrow(tasks, options = {}) {
3
+ const { concurrency = Infinity, ...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
+ const data = new Array(tasks.length);
10
+ // Run all in parallel if unlimited or limit >= count
11
+ if (limit >= tasks.length) {
12
+ await Promise.all(tasks.map(async (t, i) => {
13
+ const r = await run(t, runOptions);
14
+ if (!r.ok)
15
+ throw r.error;
16
+ data[i] = r.data;
17
+ }));
18
+ return data;
19
+ }
20
+ let nextIndex = 0;
21
+ let aborted = false;
22
+ let firstError = null;
23
+ const worker = async () => {
24
+ while (true) {
25
+ if (aborted)
26
+ return;
27
+ const i = nextIndex++;
28
+ if (i >= tasks.length)
29
+ return;
30
+ const task = tasks[i];
31
+ if (!task)
32
+ continue; // skip if task is undefined
33
+ const r = await run(task, runOptions);
34
+ if (!r.ok) {
35
+ firstError ?? (firstError = r.error);
36
+ aborted = true;
37
+ return;
38
+ }
39
+ data[i] = r.data;
40
+ }
41
+ };
42
+ await Promise.all(Array.from({ length: Math.min(limit, tasks.length) }, () => worker()));
43
+ if (firstError)
44
+ throw firstError;
45
+ // Safety fill
46
+ return data;
47
+ }
48
+ //# sourceMappingURL=runAllOrThrow.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runAllOrThrow.js","sourceRoot":"","sources":["../src/runAllOrThrow.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAe5B,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,KAA8B,EAC9B,UAAsC,EAAE;IAExC,MAAM,EAAE,WAAW,GAAG,QAAQ,EAAE,GAAG,UAAU,EAAE,GAAG,OAAO,CAAC;IAE1D,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,MAAM,IAAI,GAAQ,IAAI,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAE1C,qDAAqD;IACrD,IAAI,KAAK,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;QAC1B,MAAM,OAAO,CAAC,GAAG,CACf,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE;YACvB,MAAM,CAAC,GAAG,MAAM,GAAG,CAAO,CAAC,EAAE,UAAU,CAAC,CAAC;YACzC,IAAI,CAAC,CAAC,CAAC,EAAE;gBAAE,MAAM,CAAC,CAAC,KAAK,CAAC;YACzB,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;QACnB,CAAC,CAAC,CACH,CAAC;QACF,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,IAAI,UAAU,GAAa,IAAI,CAAC;IAEhC,MAAM,MAAM,GAAG,KAAK,IAAI,EAAE;QACxB,OAAO,IAAI,EAAE,CAAC;YACZ,IAAI,OAAO;gBAAE,OAAO;YAEpB,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,CAAC,4BAA4B;YAEjD,MAAM,CAAC,GAAG,MAAM,GAAG,CAAO,IAAI,EAAE,UAAU,CAAC,CAAC;YAE5C,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;gBACV,UAAU,KAAV,UAAU,GAAK,CAAC,CAAC,KAAK,EAAC;gBACvB,OAAO,GAAG,IAAI,CAAC;gBACf,OAAO;YACT,CAAC;YAED,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;QACnB,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,GAAG,EAAE,CAAC,MAAM,EAAE,CAAC,CACtE,CAAC;IAEF,IAAI,UAAU;QAAE,MAAM,UAAU,CAAC;IAEjC,cAAc;IACd,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,31 @@
1
+ import type { AppError } from "./error/types";
2
+ import type { Rule } from "./error/normalize";
3
+ import type { RunOptions, RunResult } from "./types";
4
+ import { type RunAllItemResult, type RunAllOptions } from "./runAll";
5
+ export type CreateRunnerOptions<E extends AppError = AppError> = {
6
+ /**
7
+ * Custom matchers to use for normalizing errors.
8
+ * If not provided, the default matchers are used.
9
+ */
10
+ rules?: Rule<E>[];
11
+ /**
12
+ * Custom fallback function to use for normalizing errors.
13
+ * If not provided, the default fallback is used.
14
+ */
15
+ fallback?: (err: unknown) => E;
16
+ /**
17
+ * If you want a completely custom normalizer, you can provide it directly.
18
+ * If set, `matchers` and `fallback` are ignored.
19
+ */
20
+ toError?: (err: unknown) => E;
21
+ /** Default for run options */
22
+ ignoreAbort?: boolean;
23
+ /** Optional default mapper for all runs */
24
+ mapError?: (error: E) => E;
25
+ };
26
+ export declare function createRunner<E extends AppError = AppError>(opts?: CreateRunnerOptions<E>): {
27
+ run<T>(fn: () => Promise<T>, options?: RunOptions<T, E>): Promise<RunResult<T, E>>;
28
+ all<T>(fns: Array<() => Promise<T>>, options?: RunAllOptions<T, E>): Promise<RunAllItemResult<T, E>[]>;
29
+ allOrThrow<T>(fns: (() => Promise<T>)[], options?: RunOptions<T, E>): Promise<T[]>;
30
+ };
31
+ //# sourceMappingURL=runner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAO9C,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAErD,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,aAAa,EACnB,MAAM,UAAU,CAAC;AAElB,MAAM,MAAM,mBAAmB,CAAC,CAAC,SAAS,QAAQ,GAAG,QAAQ,IAAI;IAC/D;;;OAGG;IACH,KAAK,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;IAElB;;;OAGG;IACH,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,CAAC,CAAC;IAE/B;;;OAGG;IACH,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,CAAC,CAAC;IAE9B,8BAA8B;IAC9B,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB,2CAA2C;IAC3C,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,CAAC;CAC5B,CAAC;AAOF,wBAAgB,YAAY,CAAC,CAAC,SAAS,QAAQ,GAAG,QAAQ,EACxD,IAAI,GAAE,mBAAmB,CAAC,CAAC,CAAM;QAiB3B,CAAC,MACC,MAAM,OAAO,CAAC,CAAC,CAAC,YACX,UAAU,CAAC,CAAC,EAAE,CAAC,CAAC,GACxB,OAAO,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAMvB,CAAC,OACE,KAAK,CAAC,MAAM,OAAO,CAAC,CAAC,CAAC,CAAC,YACnB,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,GAC3B,OAAO,CAAC,gBAAgB,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;eAMzB,CAAC,OACL,CAAC,MAAM,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,YAChB,UAAU,CAAC,CAAC,EAAE,CAAC,CAAC,GACxB,OAAO,CAAC,CAAC,EAAE,CAAC;EAOlB"}
package/dist/runner.js ADDED
@@ -0,0 +1,34 @@
1
+ import { createNormalizer, defaultFallback, toAppError, } from "./error/normalize";
2
+ import { run as baseRun } from "./run";
3
+ import { runAllOrThrow as baseRunAllOrThrow } from "./runAllOrThrow";
4
+ import { runAll as baseRunAll, } from "./runAll";
5
+ const composeMapError = (base, local) => (e) => local ? local(base ? base(e) : e) : base ? base(e) : e;
6
+ export function createRunner(opts = {}) {
7
+ const { rules = [], fallback = (e) => defaultFallback(e), toError: customToError, ignoreAbort = true, mapError: defaultMapError, } = opts;
8
+ const toError = customToError ??
9
+ (rules.length > 0
10
+ ? createNormalizer(rules, fallback)
11
+ : toAppError);
12
+ return {
13
+ run(fn, options = {}) {
14
+ return baseRun(fn, {
15
+ ...options,
16
+ mapError: composeMapError(defaultMapError, options.mapError),
17
+ });
18
+ },
19
+ all(fns, options = {}) {
20
+ return baseRunAll(fns, {
21
+ ...options,
22
+ mapError: composeMapError(defaultMapError, options.mapError),
23
+ });
24
+ },
25
+ allOrThrow(fns, options = {}) {
26
+ return baseRunAllOrThrow(fns, {
27
+ ...options,
28
+ mapError: composeMapError(defaultMapError, options.mapError),
29
+ });
30
+ },
31
+ };
32
+ }
33
+ const runner = createRunner();
34
+ //# sourceMappingURL=runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.js","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,UAAU,GACX,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,GAAG,IAAI,OAAO,EAAE,MAAM,OAAO,CAAC;AAEvC,OAAO,EAAE,aAAa,IAAI,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACrE,OAAO,EACL,MAAM,IAAI,UAAU,GAGrB,MAAM,UAAU,CAAC;AA4BlB,MAAM,eAAe,GACnB,CAAI,IAAkB,EAAE,KAAmB,EAAE,EAAE,CAC/C,CAAC,CAAI,EAAE,EAAE,CACP,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAE3D,MAAM,UAAU,YAAY,CAC1B,OAA+B,EAAE;IAEjC,MAAM,EACJ,KAAK,GAAG,EAAE,EACV,QAAQ,GAAG,CAAC,CAAU,EAAE,EAAE,CAAC,eAAe,CAAC,CAAC,CAAiB,EAC7D,OAAO,EAAE,aAAa,EACtB,WAAW,GAAG,IAAI,EAClB,QAAQ,EAAE,eAAe,GAC1B,GAAG,IAAI,CAAC;IAET,MAAM,OAAO,GACX,aAAa;QACb,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC;YACf,CAAC,CAAC,gBAAgB,CAAI,KAAK,EAAE,QAAQ,CAAC;YACtC,CAAC,CAAE,UAA2C,CAAC,CAAC;IAEpD,OAAO;QACL,GAAG,CACD,EAAoB,EACpB,UAA4B,EAAE;YAE9B,OAAO,OAAO,CAAC,EAAE,EAAE;gBACjB,GAAG,OAAO;gBACV,QAAQ,EAAE,eAAe,CAAC,eAAe,EAAE,OAAO,CAAC,QAAQ,CAAC;aAC7D,CAAC,CAAC;QACL,CAAC;QACD,GAAG,CACD,GAA4B,EAC5B,UAA+B,EAAE;YAEjC,OAAO,UAAU,CAAC,GAAG,EAAE;gBACrB,GAAG,OAAO;gBACV,QAAQ,EAAE,eAAe,CAAC,eAAe,EAAE,OAAO,CAAC,QAAQ,CAAC;aAC7D,CAAC,CAAC;QACL,CAAC;QACD,UAAU,CACR,GAAyB,EACzB,UAA4B,EAAE;YAE9B,OAAO,iBAAiB,CAAC,GAAG,EAAE;gBAC5B,GAAG,OAAO;gBACV,QAAQ,EAAE,eAAe,CAAC,eAAe,EAAE,OAAO,CAAC,QAAQ,CAAC;aAC7D,CAAC,CAAC;QACL,CAAC;KACF,CAAC;AACJ,CAAC;AAED,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC"}
package/dist/types.d.ts CHANGED
@@ -1,4 +1,10 @@
1
1
  import type { AppError } from "./error/types";
2
+ export type RetryDelayFn<E> = (attempt: number, err: E) => number;
3
+ export type Jitter = boolean | number | {
4
+ ratio?: number;
5
+ mode?: "full" | "equal";
6
+ rng?: () => number;
7
+ };
2
8
  export type RetryOptions<E extends AppError = AppError> = {
3
9
  /**
4
10
  * Number of retries to attempt.
@@ -7,28 +13,30 @@ export type RetryOptions<E extends AppError = AppError> = {
7
13
  retries?: number;
8
14
  /**
9
15
  * Delay in milliseconds between retries.
16
+ *
17
+ * - `number` for a fixed delay
18
+ * - `function` for custom delay based on attempt and error
19
+ *
10
20
  * @default 0
11
21
  */
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";
22
+ retryDelay?: number | RetryDelayFn<E>;
21
23
  /**
22
24
  * Function to determine if a retry should be attempted.
23
25
  * Returns true to retry, false to stop.
24
26
  * @default () => true
25
27
  */
26
- shouldRetry?: (error: E) => boolean;
28
+ shouldRetry?: (attempt: number, error: E) => boolean;
27
29
  /**
28
30
  * Adds random jitter to the delay to prevent thundering herd.
29
- * @default false
31
+ *
32
+ * - `true` for default 0.5 ratio
33
+ * - `false` to disable jitter
34
+ * - `number` for custom ratio 0..1
35
+ * - `{ ratio, mode, rng }` for full control
36
+ *
37
+ * @default 0.5
30
38
  */
31
- jitter?: boolean;
39
+ jitter?: Jitter;
32
40
  };
33
41
  export type RunOptions<T, E extends AppError = AppError> = RetryOptions<E> & {
34
42
  /**
@@ -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,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"}
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,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,KAAK,MAAM,CAAC;AAElE,MAAM,MAAM,MAAM,GACd,OAAO,GACP,MAAM,GACN;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;CAAE,CAAC;AAEpE,MAAM,MAAM,YAAY,CAAC,CAAC,SAAS,QAAQ,GAAG,QAAQ,IAAI;IACxD;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,MAAM,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC;IAEtC;;;;OAIG;IACH,WAAW,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,KAAK,OAAO,CAAC;IAErD;;;;;;;;;OASG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,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"}
@@ -0,0 +1,6 @@
1
+ import type { Jitter, RetryDelayFn } from "./types";
2
+ export declare const sleep: (ms: number) => Promise<unknown>;
3
+ export declare function clamp(n: number, min: number, max: number): number;
4
+ export declare function resolveRetryDelay<E>(retryDelay: number | RetryDelayFn<E> | undefined, attempt: number, err: E, defaultBaseDelay: number): number;
5
+ export declare function applyJitter(delay: number, jitter: Jitter | undefined): number;
6
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEpD,eAAO,MAAM,KAAK,GAAI,IAAI,MAAM,qBACmB,CAAC;AAEpD,wBAAgB,KAAK,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,UAExD;AAED,wBAAgB,iBAAiB,CAAC,CAAC,EACjC,UAAU,EAAE,MAAM,GAAG,YAAY,CAAC,CAAC,CAAC,GAAG,SAAS,EAChD,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,CAAC,EACN,gBAAgB,EAAE,MAAM,GACvB,MAAM,CAIR;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CA4B7E"}
package/dist/utils.js ADDED
@@ -0,0 +1,34 @@
1
+ export const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
2
+ export function clamp(n, min, max) {
3
+ return Math.max(min, Math.min(max, n));
4
+ }
5
+ export function resolveRetryDelay(retryDelay, attempt, err, defaultBaseDelay) {
6
+ if (typeof retryDelay === "function")
7
+ return retryDelay(attempt, err);
8
+ if (typeof retryDelay === "number")
9
+ return retryDelay;
10
+ return defaultBaseDelay;
11
+ }
12
+ export function applyJitter(delay, jitter) {
13
+ if (delay <= 0 || !jitter)
14
+ return delay;
15
+ const rng = typeof jitter === "object" && jitter.rng ? jitter.rng : Math.random;
16
+ // defaults razonables
17
+ const ratio = typeof jitter === "number"
18
+ ? jitter
19
+ : jitter === true
20
+ ? 0.5
21
+ : typeof jitter === "object" && jitter.ratio != null
22
+ ? jitter.ratio
23
+ : 0.5;
24
+ const r = clamp(ratio, 0, 1);
25
+ const mode = typeof jitter === "object" && jitter.mode ? jitter.mode : "full";
26
+ // "full": 0..delay*r extra (recomendado para evitar thundering herd)
27
+ // "equal": delay*(1-r) + random(0..delay*r)
28
+ if (mode === "equal") {
29
+ return delay * (1 - r) + rng() * delay * r;
30
+ }
31
+ // full jitter
32
+ return rng() * delay * (1 + r);
33
+ }
34
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,EAAU,EAAE,EAAE,CAClC,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AAEpD,MAAM,UAAU,KAAK,CAAC,CAAS,EAAE,GAAW,EAAE,GAAW;IACvD,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;AACzC,CAAC;AAED,MAAM,UAAU,iBAAiB,CAC/B,UAAgD,EAChD,OAAe,EACf,GAAM,EACN,gBAAwB;IAExB,IAAI,OAAO,UAAU,KAAK,UAAU;QAAE,OAAO,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IACtE,IAAI,OAAO,UAAU,KAAK,QAAQ;QAAE,OAAO,UAAU,CAAC;IACtD,OAAO,gBAAgB,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,KAAa,EAAE,MAA0B;IACnE,IAAI,KAAK,IAAI,CAAC,IAAI,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAExC,MAAM,GAAG,GACP,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC;IAEtE,sBAAsB;IACtB,MAAM,KAAK,GACT,OAAO,MAAM,KAAK,QAAQ;QACxB,CAAC,CAAC,MAAM;QACR,CAAC,CAAC,MAAM,KAAK,IAAI;YACjB,CAAC,CAAC,GAAG;YACL,CAAC,CAAC,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,CAAC,KAAK,IAAI,IAAI;gBACpD,CAAC,CAAC,MAAM,CAAC,KAAK;gBACd,CAAC,CAAC,GAAG,CAAC;IAEV,MAAM,CAAC,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IAE7B,MAAM,IAAI,GAAG,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC;IAE9E,qEAAqE;IACrE,4CAA4C;IAC5C,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;QACrB,OAAO,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,GAAG,EAAE,GAAG,KAAK,GAAG,CAAC,CAAC;IAC7C,CAAC;IAED,cAAc;IACd,OAAO,GAAG,EAAE,GAAG,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AACjC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "runtry",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Run async functions and return a typed Result instead of throwing.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -25,8 +25,8 @@
25
25
  "typescript": "^5.0.0"
26
26
  },
27
27
  "license": "MIT",
28
- "homepage": "https://github.com/sebastiansala/runtry#readme",
29
- "bugs": "https://github.com/sebastiansala/runtry/issues",
28
+ "homepage": "https://github.com/sebasxsala/runtry#readme",
29
+ "bugs": "https://github.com/sebasxsala/runtry/issues",
30
30
  "author": {
31
31
  "name": "sebasxsala",
32
32
  "url": "https://github.com/sebasxsala"