@zap-studio/retry 0.2.0 → 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.
Files changed (42) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +16 -4
  3. package/dist/abort.d.mts +30 -0
  4. package/dist/abort.d.mts.map +1 -0
  5. package/dist/abort.mjs +61 -0
  6. package/dist/abort.mjs.map +1 -0
  7. package/dist/errors-fWo_KyVO.d.mts +76 -0
  8. package/dist/errors-fWo_KyVO.d.mts.map +1 -0
  9. package/dist/errors.d.mts +2 -0
  10. package/dist/{error.mjs → errors.mjs} +21 -3
  11. package/dist/errors.mjs.map +1 -0
  12. package/dist/exponential-backoff.d.mts +18 -0
  13. package/dist/exponential-backoff.d.mts.map +1 -1
  14. package/dist/exponential-backoff.mjs +9 -0
  15. package/dist/exponential-backoff.mjs.map +1 -1
  16. package/dist/fixed-delay.d.mts +12 -0
  17. package/dist/fixed-delay.d.mts.map +1 -1
  18. package/dist/fixed-delay.mjs +6 -0
  19. package/dist/fixed-delay.mjs.map +1 -1
  20. package/dist/index.d.mts +3 -32
  21. package/dist/index.d.mts.map +1 -1
  22. package/dist/index.mjs +9 -172
  23. package/dist/index.mjs.map +1 -1
  24. package/dist/result-mode.d.mts +24 -0
  25. package/dist/result-mode.d.mts.map +1 -0
  26. package/dist/result-mode.mjs +145 -0
  27. package/dist/result-mode.mjs.map +1 -0
  28. package/dist/sleep.d.mts +17 -0
  29. package/dist/sleep.d.mts.map +1 -0
  30. package/dist/sleep.mjs +21 -0
  31. package/dist/sleep.mjs.map +1 -0
  32. package/dist/throw-mode.d.mts +26 -0
  33. package/dist/throw-mode.d.mts.map +1 -0
  34. package/dist/throw-mode.mjs +50 -0
  35. package/dist/throw-mode.mjs.map +1 -0
  36. package/dist/types.d.mts +58 -3
  37. package/dist/types.d.mts.map +1 -1
  38. package/package.json +6 -2
  39. package/dist/error-CVW4I654.d.mts +0 -44
  40. package/dist/error-CVW4I654.d.mts.map +0 -1
  41. package/dist/error.d.mts +0 -2
  42. package/dist/error.mjs.map +0 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # @zap-studio/retry
2
2
 
3
+ ## 0.3.0
4
+
5
+ ### Breaking
6
+
7
+ - **Subpath for error types:** use `@zap-studio/retry/errors` (plural) for `RetryError`, `AbortError`, and related types. A prior JSR `error` subpath that pointed at a non-existent `error.ts` entry is removed; update deep imports from `@zap-studio/retry/error` to `@zap-studio/retry/errors`.
8
+
9
+ ### Changed
10
+
11
+ - Add dedicated `AbortError` and normalize cancellation paths so retry internals throw/return `RetryError` or `AbortError` instead of plain `Error`.
12
+ - Expose `defaultSleep` from the `@zap-studio/retry/sleep` subpath only (the main entry does not re-export it; `run` still uses it internally when `sleep` is omitted).
13
+ - Align non-throw exhaustion metadata so `result.attempts` and `result.error.attempts` stay consistent for `RetryError` outcomes.
14
+ - In non-throw mode, return a normalized `AbortError` on `result.error` for cancellation; `result.attempts` still reports completed attempts.
15
+ - Refactor result-mode internals into smaller helpers for lower complexity and cleaner maintainability.
16
+ - Expand docs across README and package docs pages to explain `AbortError` behavior in throw and non-throw modes.
17
+ - Split the retry runner into dedicated modules: `throw-mode` (throwing execution path), `result-mode` (non-throw `RetryRunResult` path), and `sleep` (the default `defaultSleep` implementation). `BaseRetryPolicy` in `index` now delegates to these modules without changing public behavior.
18
+ - Add exhaustive TSDoc for `result-mode` and other `src` modules, including private helpers, policy option and state fields, and `RetryRunResult` union members.
19
+ - Rework test layout into `sleep`, `throw-mode`, `result-mode`, and `index` test files with a shared `sequence-policy` fixture, replacing the prior combined `index` and `abort` test files.
20
+
3
21
  ## 0.2.0
4
22
 
5
23
  ### Changed
package/README.md CHANGED
@@ -33,10 +33,11 @@ const data = await exponential.run(async () => {
33
33
 
34
34
  `run(...)` throws when retries are exhausted.
35
35
 
36
- By default, policies extending `BaseRetryPolicy` throw `RetryError`.
36
+ By default, policies extending `BaseRetryPolicy` throw `RetryError` on exhaustion
37
+ and `AbortError` on cancellation.
37
38
 
38
39
  ```ts
39
- import { RetryError } from "@zap-studio/retry/error";
40
+ import { AbortError, RetryError } from "@zap-studio/retry/errors";
40
41
 
41
42
  try {
42
43
  const data = await exponential.run(async () => {
@@ -50,6 +51,8 @@ try {
50
51
  if (error instanceof RetryError) {
51
52
  console.error("Retries exhausted:", error.attempts);
52
53
  console.error("Last error:", error.lastError);
54
+ } else if (error instanceof AbortError) {
55
+ console.error("Retry aborted:", error.message);
53
56
  } else {
54
57
  throw error;
55
58
  }
@@ -77,6 +80,14 @@ if (!result.ok) {
77
80
  }
78
81
  ```
79
82
 
83
+ ## Default sleep
84
+
85
+ `BaseRetryPolicy.run` automatically applies a delay between retry attempts when no custom `sleep` function is provided in the options.
86
+
87
+ That default is the `defaultSleep` helper, exported from `@zap-studio/retry/sleep`.
88
+
89
+ By default, this delay mechanism relies on the native JavaScript `setTimeout`, meaning retries are scheduled using the standard event loop timing rather than any custom or blocking implementation.
90
+
80
91
  ## Cancellation With AbortSignal
81
92
 
82
93
  Use `signal` in `run(...)` options to stop retrying early.
@@ -99,7 +110,8 @@ controller.abort(new Error("Request canceled"));
99
110
  await promise;
100
111
  ```
101
112
 
102
- In non-throw mode, abort is returned as `{ ok: false }`:
113
+ In non-throw mode, abort is returned as `{ ok: false }` with `AbortError` on
114
+ `result.error`:
103
115
 
104
116
  ```ts
105
117
  const controller = new AbortController();
@@ -189,7 +201,7 @@ const value = await policy.run(doWork);
189
201
  Use `RetryError` when an orchestrator exhausts retries and needs to surface final context.
190
202
 
191
203
  ```ts
192
- import { RetryError } from "@zap-studio/retry/error";
204
+ import { RetryError } from "@zap-studio/retry/errors";
193
205
 
194
206
  throw new RetryError("Retry policy exhausted all attempts.", {
195
207
  attempts: attempt,
@@ -0,0 +1,30 @@
1
+ import { t as AbortError } from "./errors-fWo_KyVO.mjs";
2
+
3
+ //#region src/abort.d.ts
4
+ /**
5
+ * Throws when the provided abort signal is already aborted.
6
+ *
7
+ * @param signal - Optional abort signal to inspect.
8
+ * @throws {AbortError} When the signal is aborted.
9
+ */
10
+ declare function throwIfAborted(signal?: AbortSignal): void;
11
+ /**
12
+ * Converts an abort reason into a normalized `AbortError`.
13
+ *
14
+ * @param reason - Arbitrary abort reason value.
15
+ * @returns Normalized abort error instance.
16
+ */
17
+ declare function toAbortError(reason: unknown): AbortError;
18
+ /**
19
+ * Waits for delay sleep while observing cancellation through an abort signal.
20
+ *
21
+ * @param sleep - Sleep function used to await `delayMs`.
22
+ * @param delayMs - Delay duration in milliseconds.
23
+ * @param signal - Abort signal to observe while waiting.
24
+ * @returns Promise that resolves when delay finishes.
25
+ * @throws {AbortError} When the signal aborts before or during wait.
26
+ */
27
+ declare function sleepWithAbortSignal(sleep: (delayMs: number) => Promise<void>, delayMs: number, signal: AbortSignal): Promise<void>;
28
+ //#endregion
29
+ export { sleepWithAbortSignal, throwIfAborted, toAbortError };
30
+ //# sourceMappingURL=abort.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"abort.d.mts","names":[],"sources":["../src/abort.ts"],"mappings":";;;;;AA4BA;;;;iBAdgB,cAAA,CAAe,MAAA,GAAS,WAAA;AA+CxC;;;;;;AAAA,iBAjCgB,YAAA,CAAa,MAAA,YAAkB,UAAA;;;;;;;;;;iBAiCzB,oBAAA,CACpB,KAAA,GAAQ,OAAA,aAAoB,OAAA,QAC5B,OAAA,UACA,MAAA,EAAQ,WAAA,GACP,OAAA"}
package/dist/abort.mjs ADDED
@@ -0,0 +1,61 @@
1
+ import { AbortError } from "./errors.mjs";
2
+ //#region src/abort.ts
3
+ /**
4
+ * Abort-signal helpers for retry orchestration internals.
5
+ *
6
+ * @module @zap-studio/retry/abort
7
+ */
8
+ /**
9
+ * Throws when the provided abort signal is already aborted.
10
+ *
11
+ * @param signal - Optional abort signal to inspect.
12
+ * @throws {AbortError} When the signal is aborted.
13
+ */
14
+ function throwIfAborted(signal) {
15
+ if (!signal?.aborted) return;
16
+ throw toAbortError(signal.reason);
17
+ }
18
+ /**
19
+ * Converts an abort reason into a normalized `AbortError`.
20
+ *
21
+ * @param reason - Arbitrary abort reason value.
22
+ * @returns Normalized abort error instance.
23
+ */
24
+ function toAbortError(reason) {
25
+ if (reason instanceof AbortError) return reason;
26
+ if (reason instanceof Error) return new AbortError(reason.message, { cause: reason });
27
+ if (typeof reason === "string" && reason.length > 0) return new AbortError(reason);
28
+ if (reason === void 0) return new AbortError("Retry aborted.");
29
+ try {
30
+ return new AbortError(`Retry aborted: ${JSON.stringify(reason)}`);
31
+ } catch {
32
+ return new AbortError("Retry aborted.");
33
+ }
34
+ }
35
+ /**
36
+ * Waits for delay sleep while observing cancellation through an abort signal.
37
+ *
38
+ * @param sleep - Sleep function used to await `delayMs`.
39
+ * @param delayMs - Delay duration in milliseconds.
40
+ * @param signal - Abort signal to observe while waiting.
41
+ * @returns Promise that resolves when delay finishes.
42
+ * @throws {AbortError} When the signal aborts before or during wait.
43
+ */
44
+ async function sleepWithAbortSignal(sleep, delayMs, signal) {
45
+ if (signal.aborted) throw toAbortError(signal.reason);
46
+ let onAbort;
47
+ try {
48
+ await Promise.race([sleep(delayMs), new Promise((_, reject) => {
49
+ onAbort = () => {
50
+ reject(toAbortError(signal.reason));
51
+ };
52
+ signal.addEventListener("abort", onAbort, { once: true });
53
+ })]);
54
+ } finally {
55
+ if (onAbort) signal.removeEventListener("abort", onAbort);
56
+ }
57
+ }
58
+ //#endregion
59
+ export { sleepWithAbortSignal, throwIfAborted, toAbortError };
60
+
61
+ //# sourceMappingURL=abort.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"abort.mjs","names":[],"sources":["../src/abort.ts"],"sourcesContent":["/**\n * Abort-signal helpers for retry orchestration internals.\n *\n * @module @zap-studio/retry/abort\n */\n\nimport { AbortError } from \"./errors.js\";\n\n/**\n * Throws when the provided abort signal is already aborted.\n *\n * @param signal - Optional abort signal to inspect.\n * @throws {AbortError} When the signal is aborted.\n */\nexport function throwIfAborted(signal?: AbortSignal): void {\n if (!signal?.aborted) {\n return;\n }\n\n throw toAbortError(signal.reason);\n}\n\n/**\n * Converts an abort reason into a normalized `AbortError`.\n *\n * @param reason - Arbitrary abort reason value.\n * @returns Normalized abort error instance.\n */\nexport function toAbortError(reason: unknown): AbortError {\n if (reason instanceof AbortError) {\n return reason;\n }\n\n if (reason instanceof Error) {\n return new AbortError(reason.message, { cause: reason });\n }\n\n if (typeof reason === \"string\" && reason.length > 0) {\n return new AbortError(reason);\n }\n\n if (reason === undefined) {\n return new AbortError(\"Retry aborted.\");\n }\n\n try {\n return new AbortError(`Retry aborted: ${JSON.stringify(reason)}`);\n } catch {\n return new AbortError(\"Retry aborted.\");\n }\n}\n\n/**\n * Waits for delay sleep while observing cancellation through an abort signal.\n *\n * @param sleep - Sleep function used to await `delayMs`.\n * @param delayMs - Delay duration in milliseconds.\n * @param signal - Abort signal to observe while waiting.\n * @returns Promise that resolves when delay finishes.\n * @throws {AbortError} When the signal aborts before or during wait.\n */\nexport async function sleepWithAbortSignal(\n sleep: (delayMs: number) => Promise<void>,\n delayMs: number,\n signal: AbortSignal,\n): Promise<void> {\n if (signal.aborted) {\n throw toAbortError(signal.reason);\n }\n\n let onAbort: (() => void) | undefined;\n\n try {\n await Promise.race([\n sleep(delayMs),\n new Promise<never>((_, reject) => {\n onAbort = (): void => {\n reject(toAbortError(signal.reason));\n };\n\n signal.addEventListener(\"abort\", onAbort, { once: true });\n }),\n ]);\n } finally {\n if (onAbort) {\n signal.removeEventListener(\"abort\", onAbort);\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;AAcA,SAAgB,eAAe,QAA4B;AACzD,KAAI,CAAC,QAAQ,QACX;AAGF,OAAM,aAAa,OAAO,OAAO;;;;;;;;AASnC,SAAgB,aAAa,QAA6B;AACxD,KAAI,kBAAkB,WACpB,QAAO;AAGT,KAAI,kBAAkB,MACpB,QAAO,IAAI,WAAW,OAAO,SAAS,EAAE,OAAO,QAAQ,CAAC;AAG1D,KAAI,OAAO,WAAW,YAAY,OAAO,SAAS,EAChD,QAAO,IAAI,WAAW,OAAO;AAG/B,KAAI,WAAW,KAAA,EACb,QAAO,IAAI,WAAW,iBAAiB;AAGzC,KAAI;AACF,SAAO,IAAI,WAAW,kBAAkB,KAAK,UAAU,OAAO,GAAG;SAC3D;AACN,SAAO,IAAI,WAAW,iBAAiB;;;;;;;;;;;;AAa3C,eAAsB,qBACpB,OACA,SACA,QACe;AACf,KAAI,OAAO,QACT,OAAM,aAAa,OAAO,OAAO;CAGnC,IAAI;AAEJ,KAAI;AACF,QAAM,QAAQ,KAAK,CACjB,MAAM,QAAQ,EACd,IAAI,SAAgB,GAAG,WAAW;AAChC,mBAAsB;AACpB,WAAO,aAAa,OAAO,OAAO,CAAC;;AAGrC,UAAO,iBAAiB,SAAS,SAAS,EAAE,MAAM,MAAM,CAAC;IACzD,CACH,CAAC;WACM;AACR,MAAI,QACF,QAAO,oBAAoB,SAAS,QAAQ"}
@@ -0,0 +1,76 @@
1
+ //#region src/errors.d.ts
2
+ /**
3
+ * Terminal error types used by retry policies and runners.
4
+ *
5
+ * @module @zap-studio/retry/errors
6
+ */
7
+ /**
8
+ * Context payload attached to `RetryError`.
9
+ */
10
+ interface RetryErrorContext {
11
+ /**
12
+ * Count of completed attempts at exhaustion.
13
+ */
14
+ readonly attempts: number;
15
+ /**
16
+ * The last error object raised by a failed `execute` attempt.
17
+ */
18
+ readonly lastError?: unknown;
19
+ /**
20
+ * Optional data captured from the last attempt when provided by a policy.
21
+ */
22
+ readonly lastData?: unknown;
23
+ }
24
+ /**
25
+ * Context payload attached to `AbortError`.
26
+ */
27
+ interface AbortErrorContext {
28
+ /**
29
+ * When the abort `reason` was an `Error`, the optional wrapped cause.
30
+ */
31
+ readonly cause?: unknown;
32
+ }
33
+ /**
34
+ * Error thrown when retries are exhausted.
35
+ *
36
+ * @example
37
+ * throw new RetryError("Retry exhausted", {
38
+ * attempts: 3,
39
+ * lastError: new Error("network"),
40
+ * });
41
+ */
42
+ declare class RetryError extends Error {
43
+ /**
44
+ * Total attempts performed before exhaustion.
45
+ */
46
+ readonly attempts: number;
47
+ /**
48
+ * Last captured error from execution.
49
+ */
50
+ readonly lastError?: unknown;
51
+ /**
52
+ * Last captured data value, when available.
53
+ */
54
+ readonly lastData?: unknown;
55
+ /**
56
+ * Creates a RetryError with structured terminal context.
57
+ */
58
+ constructor(message: string, context: RetryErrorContext);
59
+ }
60
+ /**
61
+ * Error thrown when retry orchestration is canceled through `AbortSignal`.
62
+ */
63
+ declare class AbortError extends Error {
64
+ /**
65
+ * Optional wrapped cause when the native abort `reason` was an `Error`.
66
+ */
67
+ override readonly cause?: unknown;
68
+ /**
69
+ * @param message - Human-readable abort description.
70
+ * @param context - Optional `cause` link for diagnostic chaining.
71
+ */
72
+ constructor(message: string, context?: AbortErrorContext);
73
+ }
74
+ //#endregion
75
+ export { RetryErrorContext as i, AbortErrorContext as n, RetryError as r, AbortError as t };
76
+ //# sourceMappingURL=errors-fWo_KyVO.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors-fWo_KyVO.d.mts","names":[],"sources":["../src/errors.ts"],"mappings":";;AASA;;;;;;;UAAiB,iBAAA;EAYN;AAMX;;EANW,SARA,QAAA;EAcM;;AAgBjB;EAhBiB,SAVN,SAAA;;;;WAIA,QAAA;AAAA;;;;UAMM,iBAAA;;;;WAIN,KAAA;AAAA;;;;;;;;;;cAYE,UAAA,SAAmB,KAAA;;;;WAId,QAAA;;;;WAIA,SAAA;;;;WAIA,QAAA;;;;EAKhB,WAAA,CAAY,OAAA,UAAiB,OAAA,EAAS,iBAAA;AAAA;;;;cAY3B,UAAA,SAAmB,KAAA;;;;oBAIL,KAAA;;;;;EAMzB,WAAA,CAAY,OAAA,UAAiB,OAAA,GAAS,iBAAA;AAAA"}
@@ -0,0 +1,2 @@
1
+ import { i as RetryErrorContext, n as AbortErrorContext, r as RetryError, t as AbortError } from "./errors-fWo_KyVO.mjs";
2
+ export { AbortError, AbortErrorContext, RetryError, RetryErrorContext };
@@ -1,4 +1,4 @@
1
- //#region src/error.ts
1
+ //#region src/errors.ts
2
2
  /**
3
3
  * Error thrown when retries are exhausted.
4
4
  *
@@ -32,7 +32,25 @@ var RetryError = class extends Error {
32
32
  this.lastData = context.lastData;
33
33
  }
34
34
  };
35
+ /**
36
+ * Error thrown when retry orchestration is canceled through `AbortSignal`.
37
+ */
38
+ var AbortError = class extends Error {
39
+ /**
40
+ * Optional wrapped cause when the native abort `reason` was an `Error`.
41
+ */
42
+ cause;
43
+ /**
44
+ * @param message - Human-readable abort description.
45
+ * @param context - Optional `cause` link for diagnostic chaining.
46
+ */
47
+ constructor(message, context = {}) {
48
+ super(message);
49
+ this.name = "AbortError";
50
+ this.cause = context.cause;
51
+ }
52
+ };
35
53
  //#endregion
36
- export { RetryError };
54
+ export { AbortError, RetryError };
37
55
 
38
- //# sourceMappingURL=error.mjs.map
56
+ //# sourceMappingURL=errors.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.mjs","names":[],"sources":["../src/errors.ts"],"sourcesContent":["/**\n * Terminal error types used by retry policies and runners.\n *\n * @module @zap-studio/retry/errors\n */\n\n/**\n * Context payload attached to `RetryError`.\n */\nexport interface RetryErrorContext {\n /**\n * Count of completed attempts at exhaustion.\n */\n readonly attempts: number;\n /**\n * The last error object raised by a failed `execute` attempt.\n */\n readonly lastError?: unknown;\n /**\n * Optional data captured from the last attempt when provided by a policy.\n */\n readonly lastData?: unknown;\n}\n\n/**\n * Context payload attached to `AbortError`.\n */\nexport interface AbortErrorContext {\n /**\n * When the abort `reason` was an `Error`, the optional wrapped cause.\n */\n readonly cause?: unknown;\n}\n\n/**\n * Error thrown when retries are exhausted.\n *\n * @example\n * throw new RetryError(\"Retry exhausted\", {\n * attempts: 3,\n * lastError: new Error(\"network\"),\n * });\n */\nexport class RetryError extends Error {\n /**\n * Total attempts performed before exhaustion.\n */\n public readonly attempts: number;\n /**\n * Last captured error from execution.\n */\n public readonly lastError?: unknown;\n /**\n * Last captured data value, when available.\n */\n public readonly lastData?: unknown;\n\n /**\n * Creates a RetryError with structured terminal context.\n */\n constructor(message: string, context: RetryErrorContext) {\n super(message);\n this.name = \"RetryError\";\n this.attempts = context.attempts;\n this.lastError = context.lastError;\n this.lastData = context.lastData;\n }\n}\n\n/**\n * Error thrown when retry orchestration is canceled through `AbortSignal`.\n */\nexport class AbortError extends Error {\n /**\n * Optional wrapped cause when the native abort `reason` was an `Error`.\n */\n public override readonly cause?: unknown;\n\n /**\n * @param message - Human-readable abort description.\n * @param context - Optional `cause` link for diagnostic chaining.\n */\n constructor(message: string, context: AbortErrorContext = {}) {\n super(message);\n this.name = \"AbortError\";\n this.cause = context.cause;\n }\n}\n"],"mappings":";;;;;;;;;;AA2CA,IAAa,aAAb,cAAgC,MAAM;;;;CAIpC;;;;CAIA;;;;CAIA;;;;CAKA,YAAY,SAAiB,SAA4B;AACvD,QAAM,QAAQ;AACd,OAAK,OAAO;AACZ,OAAK,WAAW,QAAQ;AACxB,OAAK,YAAY,QAAQ;AACzB,OAAK,WAAW,QAAQ;;;;;;AAO5B,IAAa,aAAb,cAAgC,MAAM;;;;CAIpC;;;;;CAMA,YAAY,SAAiB,UAA6B,EAAE,EAAE;AAC5D,QAAM,QAAQ;AACd,OAAK,OAAO;AACZ,OAAK,QAAQ,QAAQ"}
@@ -6,8 +6,17 @@ import { BaseRetryPolicy } from "./index.mjs";
6
6
  * Configuration for `ExponentialBackoff`.
7
7
  */
8
8
  interface ExponentialBackoffOptions {
9
+ /**
10
+ * Maximum number of attempts (including the first) before giving up.
11
+ */
9
12
  maxAttempts: number;
13
+ /**
14
+ * Initial delay in milliseconds, doubled each retry until capped.
15
+ */
10
16
  baseDelayMs: number;
17
+ /**
18
+ * Hard upper bound in milliseconds for computed exponential delay.
19
+ */
11
20
  maxDelayMs: number;
12
21
  }
13
22
  /**
@@ -21,8 +30,17 @@ interface ExponentialBackoffOptions {
21
30
  * });
22
31
  */
23
32
  declare class ExponentialBackoff extends BaseRetryPolicy {
33
+ /**
34
+ * Maximum number of attempts before the policy returns `max-attempts-reached`.
35
+ */
24
36
  private readonly maxAttempts;
37
+ /**
38
+ * Base delay in milliseconds used in `baseDelayMs * 2 ** (attempt - 1)`.
39
+ */
25
40
  private readonly baseDelayMs;
41
+ /**
42
+ * Upper cap for computed delay, applied with `Math.min`.
43
+ */
26
44
  private readonly maxDelayMs;
27
45
  /**
28
46
  * Creates an exponential backoff retry policy.
@@ -1 +1 @@
1
- {"version":3,"file":"exponential-backoff.d.mts","names":[],"sources":["../src/exponential-backoff.ts"],"mappings":";;;;;;;UAYiB,yBAAA;EACf,WAAA;EACA,WAAA;EACA,UAAA;AAAA;;;;;;;;;;;cAaW,kBAAA,SAA2B,eAAA;EAAA,iBACrB,WAAA;EAAA,iBACA,WAAA;EAAA,iBACA,UAAA;;;;EAKjB,WAAA,CAAY,OAAA,EAAS,yBAAA;;;;EAUrB,IAAA,CAAY,KAAA,EAAO,kBAAA,GAAqB,aAAA;AAAA"}
1
+ {"version":3,"file":"exponential-backoff.d.mts","names":[],"sources":["../src/exponential-backoff.ts"],"mappings":";;;;;;;UAYiB,yBAAA;;;AAyBjB;EArBE,WAAA;;;;EAIA,WAAA;;;;EAIA,UAAA;AAAA;;;;;;;;;;;cAaW,kBAAA,SAA2B,eAAA;;;;mBAIrB,WAAA;;;;mBAIA,WAAA;;;;mBAIA,UAAA;;;;EAKjB,WAAA,CAAY,OAAA,EAAS,yBAAA;;;;EAUrB,IAAA,CAAY,KAAA,EAAO,kBAAA,GAAqB,aAAA;AAAA"}
@@ -16,8 +16,17 @@ import { BaseRetryPolicy } from "./index.mjs";
16
16
  * });
17
17
  */
18
18
  var ExponentialBackoff = class extends BaseRetryPolicy {
19
+ /**
20
+ * Maximum number of attempts before the policy returns `max-attempts-reached`.
21
+ */
19
22
  maxAttempts;
23
+ /**
24
+ * Base delay in milliseconds used in `baseDelayMs * 2 ** (attempt - 1)`.
25
+ */
20
26
  baseDelayMs;
27
+ /**
28
+ * Upper cap for computed delay, applied with `Math.min`.
29
+ */
21
30
  maxDelayMs;
22
31
  /**
23
32
  * Creates an exponential backoff retry policy.
@@ -1 +1 @@
1
- {"version":3,"file":"exponential-backoff.mjs","names":[],"sources":["../src/exponential-backoff.ts"],"sourcesContent":["/**\n * Exponential backoff retry strategy.\n *\n * @module @zap-studio/retry/exponential-backoff\n */\n\nimport { BaseRetryPolicy } from \"./index.js\";\nimport type { RetryDecision, RetryDecisionInput } from \"./types.js\";\n\n/**\n * Configuration for `ExponentialBackoff`.\n */\nexport interface ExponentialBackoffOptions {\n maxAttempts: number;\n baseDelayMs: number;\n maxDelayMs: number;\n}\n\n/**\n * Retries with exponential delay growth up to a max cap.\n *\n * @example\n * const policy = new ExponentialBackoff({\n * maxAttempts: 5,\n * baseDelayMs: 100,\n * maxDelayMs: 2_000,\n * });\n */\nexport class ExponentialBackoff extends BaseRetryPolicy {\n private readonly maxAttempts: number;\n private readonly baseDelayMs: number;\n private readonly maxDelayMs: number;\n\n /**\n * Creates an exponential backoff retry policy.\n */\n constructor(options: ExponentialBackoffOptions) {\n super();\n this.maxAttempts = options.maxAttempts;\n this.baseDelayMs = options.baseDelayMs;\n this.maxDelayMs = options.maxDelayMs;\n }\n\n /**\n * Computes retry decision for the current attempt.\n */\n public next(input: RetryDecisionInput): RetryDecision {\n if (input.attempt >= this.maxAttempts) {\n return { shouldRetry: false, delayMs: 0, reason: \"max-attempts-reached\" };\n }\n\n const exponent = Math.max(0, input.attempt - 1);\n const delayMs = Math.min(this.maxDelayMs, this.baseDelayMs * 2 ** exponent);\n\n return { shouldRetry: true, delayMs, reason: \"retry\" };\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AA4BA,IAAa,qBAAb,cAAwC,gBAAgB;CACtD;CACA;CACA;;;;CAKA,YAAY,SAAoC;AAC9C,SAAO;AACP,OAAK,cAAc,QAAQ;AAC3B,OAAK,cAAc,QAAQ;AAC3B,OAAK,aAAa,QAAQ;;;;;CAM5B,KAAY,OAA0C;AACpD,MAAI,MAAM,WAAW,KAAK,YACxB,QAAO;GAAE,aAAa;GAAO,SAAS;GAAG,QAAQ;GAAwB;EAG3E,MAAM,WAAW,KAAK,IAAI,GAAG,MAAM,UAAU,EAAE;AAG/C,SAAO;GAAE,aAAa;GAAM,SAFZ,KAAK,IAAI,KAAK,YAAY,KAAK,cAAc,KAAK,SAAS;GAEtC,QAAQ;GAAS"}
1
+ {"version":3,"file":"exponential-backoff.mjs","names":[],"sources":["../src/exponential-backoff.ts"],"sourcesContent":["/**\n * Exponential backoff retry strategy.\n *\n * @module @zap-studio/retry/exponential-backoff\n */\n\nimport { BaseRetryPolicy } from \"./index.js\";\nimport type { RetryDecision, RetryDecisionInput } from \"./types.js\";\n\n/**\n * Configuration for `ExponentialBackoff`.\n */\nexport interface ExponentialBackoffOptions {\n /**\n * Maximum number of attempts (including the first) before giving up.\n */\n maxAttempts: number;\n /**\n * Initial delay in milliseconds, doubled each retry until capped.\n */\n baseDelayMs: number;\n /**\n * Hard upper bound in milliseconds for computed exponential delay.\n */\n maxDelayMs: number;\n}\n\n/**\n * Retries with exponential delay growth up to a max cap.\n *\n * @example\n * const policy = new ExponentialBackoff({\n * maxAttempts: 5,\n * baseDelayMs: 100,\n * maxDelayMs: 2_000,\n * });\n */\nexport class ExponentialBackoff extends BaseRetryPolicy {\n /**\n * Maximum number of attempts before the policy returns `max-attempts-reached`.\n */\n private readonly maxAttempts: number;\n /**\n * Base delay in milliseconds used in `baseDelayMs * 2 ** (attempt - 1)`.\n */\n private readonly baseDelayMs: number;\n /**\n * Upper cap for computed delay, applied with `Math.min`.\n */\n private readonly maxDelayMs: number;\n\n /**\n * Creates an exponential backoff retry policy.\n */\n constructor(options: ExponentialBackoffOptions) {\n super();\n this.maxAttempts = options.maxAttempts;\n this.baseDelayMs = options.baseDelayMs;\n this.maxDelayMs = options.maxDelayMs;\n }\n\n /**\n * Computes retry decision for the current attempt.\n */\n public next(input: RetryDecisionInput): RetryDecision {\n if (input.attempt >= this.maxAttempts) {\n return { shouldRetry: false, delayMs: 0, reason: \"max-attempts-reached\" };\n }\n\n const exponent = Math.max(0, input.attempt - 1);\n const delayMs = Math.min(this.maxDelayMs, this.baseDelayMs * 2 ** exponent);\n\n return { shouldRetry: true, delayMs, reason: \"retry\" };\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAqCA,IAAa,qBAAb,cAAwC,gBAAgB;;;;CAItD;;;;CAIA;;;;CAIA;;;;CAKA,YAAY,SAAoC;AAC9C,SAAO;AACP,OAAK,cAAc,QAAQ;AAC3B,OAAK,cAAc,QAAQ;AAC3B,OAAK,aAAa,QAAQ;;;;;CAM5B,KAAY,OAA0C;AACpD,MAAI,MAAM,WAAW,KAAK,YACxB,QAAO;GAAE,aAAa;GAAO,SAAS;GAAG,QAAQ;GAAwB;EAG3E,MAAM,WAAW,KAAK,IAAI,GAAG,MAAM,UAAU,EAAE;AAG/C,SAAO;GAAE,aAAa;GAAM,SAFZ,KAAK,IAAI,KAAK,YAAY,KAAK,cAAc,KAAK,SAAS;GAEtC,QAAQ;GAAS"}
@@ -6,7 +6,13 @@ import { BaseRetryPolicy } from "./index.mjs";
6
6
  * Configuration for `FixedDelay`.
7
7
  */
8
8
  interface FixedDelayOptions {
9
+ /**
10
+ * Maximum number of attempts (including the first) before giving up.
11
+ */
9
12
  maxAttempts: number;
13
+ /**
14
+ * Constant delay in milliseconds before each retry after a failure.
15
+ */
10
16
  delayMs: number;
11
17
  }
12
18
  /**
@@ -19,7 +25,13 @@ interface FixedDelayOptions {
19
25
  * });
20
26
  */
21
27
  declare class FixedDelay extends BaseRetryPolicy {
28
+ /**
29
+ * Maximum number of attempts before the policy returns `max-attempts-reached`.
30
+ */
22
31
  private readonly maxAttempts;
32
+ /**
33
+ * Constant delay in milliseconds before each subsequent attempt.
34
+ */
23
35
  private readonly delayMs;
24
36
  /**
25
37
  * Creates a fixed-delay retry policy.
@@ -1 +1 @@
1
- {"version":3,"file":"fixed-delay.d.mts","names":[],"sources":["../src/fixed-delay.ts"],"mappings":";;;;;;AA0BA;UAdiB,iBAAA;EACf,WAAA;EACA,OAAA;AAAA;;;;;;;;;;cAYW,UAAA,SAAmB,eAAA;EAAA,iBACb,WAAA;EAAA,iBACA,OAAA;;;;EAKjB,WAAA,CAAY,OAAA,EAAS,iBAAA;;;;EASrB,IAAA,CAAY,KAAA,EAAO,kBAAA,GAAqB,aAAA;AAAA"}
1
+ {"version":3,"file":"fixed-delay.d.mts","names":[],"sources":["../src/fixed-delay.ts"],"mappings":";;;;;;AAgCA;UApBiB,iBAAA;;;;EAIf,WAAA;;;;EAIA,OAAA;AAAA;;;;;;;;;;cAYW,UAAA,SAAmB,eAAA;;;;mBAIb,WAAA;;;;mBAIA,OAAA;;;;EAKjB,WAAA,CAAY,OAAA,EAAS,iBAAA;;;;EASrB,IAAA,CAAY,KAAA,EAAO,kBAAA,GAAqB,aAAA;AAAA"}
@@ -15,7 +15,13 @@ import { BaseRetryPolicy } from "./index.mjs";
15
15
  * });
16
16
  */
17
17
  var FixedDelay = class extends BaseRetryPolicy {
18
+ /**
19
+ * Maximum number of attempts before the policy returns `max-attempts-reached`.
20
+ */
18
21
  maxAttempts;
22
+ /**
23
+ * Constant delay in milliseconds before each subsequent attempt.
24
+ */
19
25
  delayMs;
20
26
  /**
21
27
  * Creates a fixed-delay retry policy.
@@ -1 +1 @@
1
- {"version":3,"file":"fixed-delay.mjs","names":[],"sources":["../src/fixed-delay.ts"],"sourcesContent":["/**\n * Fixed-delay retry strategy.\n *\n * @module @zap-studio/retry/fixed-delay\n */\n\nimport { BaseRetryPolicy } from \"./index.js\";\nimport type { RetryDecision, RetryDecisionInput } from \"./types.js\";\n\n/**\n * Configuration for `FixedDelay`.\n */\nexport interface FixedDelayOptions {\n maxAttempts: number;\n delayMs: number;\n}\n\n/**\n * Retries with a constant delay between attempts.\n *\n * @example\n * const policy = new FixedDelay({\n * maxAttempts: 3,\n * delayMs: 250,\n * });\n */\nexport class FixedDelay extends BaseRetryPolicy {\n private readonly maxAttempts: number;\n private readonly delayMs: number;\n\n /**\n * Creates a fixed-delay retry policy.\n */\n constructor(options: FixedDelayOptions) {\n super();\n this.maxAttempts = options.maxAttempts;\n this.delayMs = options.delayMs;\n }\n\n /**\n * Computes retry decision for the current attempt.\n */\n public next(input: RetryDecisionInput): RetryDecision {\n if (input.attempt >= this.maxAttempts) {\n return { shouldRetry: false, delayMs: 0, reason: \"max-attempts-reached\" };\n }\n\n return { shouldRetry: true, delayMs: this.delayMs, reason: \"retry\" };\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;AA0BA,IAAa,aAAb,cAAgC,gBAAgB;CAC9C;CACA;;;;CAKA,YAAY,SAA4B;AACtC,SAAO;AACP,OAAK,cAAc,QAAQ;AAC3B,OAAK,UAAU,QAAQ;;;;;CAMzB,KAAY,OAA0C;AACpD,MAAI,MAAM,WAAW,KAAK,YACxB,QAAO;GAAE,aAAa;GAAO,SAAS;GAAG,QAAQ;GAAwB;AAG3E,SAAO;GAAE,aAAa;GAAM,SAAS,KAAK;GAAS,QAAQ;GAAS"}
1
+ {"version":3,"file":"fixed-delay.mjs","names":[],"sources":["../src/fixed-delay.ts"],"sourcesContent":["/**\n * Fixed-delay retry strategy.\n *\n * @module @zap-studio/retry/fixed-delay\n */\n\nimport { BaseRetryPolicy } from \"./index.js\";\nimport type { RetryDecision, RetryDecisionInput } from \"./types.js\";\n\n/**\n * Configuration for `FixedDelay`.\n */\nexport interface FixedDelayOptions {\n /**\n * Maximum number of attempts (including the first) before giving up.\n */\n maxAttempts: number;\n /**\n * Constant delay in milliseconds before each retry after a failure.\n */\n delayMs: number;\n}\n\n/**\n * Retries with a constant delay between attempts.\n *\n * @example\n * const policy = new FixedDelay({\n * maxAttempts: 3,\n * delayMs: 250,\n * });\n */\nexport class FixedDelay extends BaseRetryPolicy {\n /**\n * Maximum number of attempts before the policy returns `max-attempts-reached`.\n */\n private readonly maxAttempts: number;\n /**\n * Constant delay in milliseconds before each subsequent attempt.\n */\n private readonly delayMs: number;\n\n /**\n * Creates a fixed-delay retry policy.\n */\n constructor(options: FixedDelayOptions) {\n super();\n this.maxAttempts = options.maxAttempts;\n this.delayMs = options.delayMs;\n }\n\n /**\n * Computes retry decision for the current attempt.\n */\n public next(input: RetryDecisionInput): RetryDecision {\n if (input.attempt >= this.maxAttempts) {\n return { shouldRetry: false, delayMs: 0, reason: \"max-attempts-reached\" };\n }\n\n return { shouldRetry: true, delayMs: this.delayMs, reason: \"retry\" };\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAgCA,IAAa,aAAb,cAAgC,gBAAgB;;;;CAI9C;;;;CAIA;;;;CAKA,YAAY,SAA4B;AACtC,SAAO;AACP,OAAK,cAAc,QAAQ;AAC3B,OAAK,UAAU,QAAQ;;;;;CAMzB,KAAY,OAA0C;AACpD,MAAI,MAAM,WAAW,KAAK,YACxB,QAAO;GAAE,aAAa;GAAO,SAAS;GAAG,QAAQ;GAAwB;AAG3E,SAAO;GAAE,aAAa;GAAM,SAAS,KAAK;GAAS,QAAQ;GAAS"}
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { t as RetryError } from "./error-CVW4I654.mjs";
1
+ import { r as RetryError } from "./errors-fWo_KyVO.mjs";
2
2
  import { RetryDecision, RetryDecisionInput, RetryExhaustedInput, RetryPolicy, RetryRunOptions, RetryRunResult } from "./types.mjs";
3
3
 
4
4
  //#region src/index.d.ts
@@ -47,43 +47,14 @@ declare abstract class BaseRetryPolicy<TError = unknown, TData = unknown> implem
47
47
  * @throws {RetryError} When retries are exhausted and `onExhausted` returns the
48
48
  * terminal retry error. The default implementation returns `RetryError` with the last
49
49
  * execution failure available on `RetryError.lastError`.
50
- * @throws {Error} When `options.signal` is already aborted or aborts while retrying.
50
+ * @throws {AbortError} When `options.signal` is already aborted or aborts while retrying.
51
51
  * @throws Any error thrown by `next`, by `onExhausted`, or by a custom `sleep`
52
52
  * function.
53
53
  */
54
54
  run<T>(execute: (attempt: number) => Promise<T>, options?: RetryRunOptions & {
55
55
  throwOnExhausted?: true;
56
56
  }): Promise<T>;
57
- /**
58
- * Runs retry orchestration in throwing mode.
59
- *
60
- * This path is selected when `throwOnExhausted` is not `false`.
61
- *
62
- * @param execute - Async function to execute per attempt.
63
- * @param sleep - Delay function used between retry attempts.
64
- * @returns The successful execution value.
65
- * @throws {RetryError} Terminal error returned by `onExhausted(...)`.
66
- * @throws Any error thrown by `next`, by `onExhausted`, or by `sleep`.
67
- */
68
- private runThrowMode;
69
- /**
70
- * Runs retry orchestration in non-throw mode.
71
- *
72
- * This path is selected when `throwOnExhausted` is `false`.
73
- *
74
- * @param execute - Async function to execute per attempt.
75
- * @param sleep - Delay function used between retry attempts.
76
- * @returns A discriminated result union containing success value or terminal error.
77
- * @throws Any error thrown by `next`, by `onExhausted`, or by `sleep`.
78
- */
79
- private runResultMode;
80
57
  }
81
- /**
82
- * Default delay implementation used by `run(...)` when no custom sleep function is provided.
83
- *
84
- * Returns immediately when `delayMs` is non-positive.
85
- */
86
- declare function defaultSleep(delayMs: number): Promise<void>;
87
58
  //#endregion
88
- export { BaseRetryPolicy, defaultSleep };
59
+ export { BaseRetryPolicy };
89
60
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;;;;;;;uBAuBsB,eAAA,+CAA8D,WAAA,CAClF,MAAA,EACA,KAAA;;;;;;;WAQgB,IAAA,CAAK,KAAA,EAAO,kBAAA,CAAmB,MAAA,EAAQ,KAAA,IAAS,aAAA;;;;;;;;;;EAWhE,WAAA,CAAmB,KAAA,EAAO,mBAAA,CAAoB,MAAA,EAAQ,KAAA,IAAS,UAAA;;;;;;;;;EAgB/D,GAAA,GAAA,CACE,OAAA,GAAU,OAAA,aAAoB,OAAA,CAAQ,CAAA,GACtC,OAAA,EAAS,eAAA;IAAoB,gBAAA;EAAA,IAC5B,OAAA,CAAQ,cAAA,CAAe,CAAA;;;;;;;;;;;;;;EAe1B,GAAA,GAAA,CACE,OAAA,GAAU,OAAA,aAAoB,OAAA,CAAQ,CAAA,GACtC,OAAA,GAAU,eAAA;IAAoB,gBAAA;EAAA,IAC7B,OAAA,CAAQ,CAAA;;;;;;;;;;;;UA2CG,YAAA;EAmDA;AA+EhB;;;;;;;;;EA/EgB,QAAA,aAAA;AAAA;;;;;;iBA+EM,YAAA,CAAa,OAAA,WAAkB,OAAA"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;;;;;;;uBA0BsB,eAAA,+CAA8D,WAAA,CAClF,MAAA,EACA,KAAA;;;;;;;WAQgB,IAAA,CAAK,KAAA,EAAO,kBAAA,CAAmB,MAAA,EAAQ,KAAA,IAAS,aAAA;;;;;;;;;;EAWhE,WAAA,CAAmB,KAAA,EAAO,mBAAA,CAAoB,MAAA,EAAQ,KAAA,IAAS,UAAA;;;;;;;;;EAgB/D,GAAA,GAAA,CACE,OAAA,GAAU,OAAA,aAAoB,OAAA,CAAQ,CAAA,GACtC,OAAA,EAAS,eAAA;IAAoB,gBAAA;EAAA,IAC5B,OAAA,CAAQ,cAAA,CAAe,CAAA;;;;;;;;;;;;;;EAe1B,GAAA,GAAA,CACE,OAAA,GAAU,OAAA,aAAoB,OAAA,CAAQ,CAAA,GACtC,OAAA,GAAU,eAAA;IAAoB,gBAAA;EAAA,IAC7B,OAAA,CAAQ,CAAA;AAAA"}