@zap-studio/retry 0.3.1 → 1.0.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 (61) hide show
  1. package/CHANGELOG.md +55 -14
  2. package/README.md +87 -141
  3. package/dist/base-policy.d.ts +67 -0
  4. package/dist/base-policy.d.ts.map +1 -0
  5. package/dist/base-policy.js +306 -0
  6. package/dist/base-policy.js.map +1 -0
  7. package/dist/{errors-BVZjP1Q5.d.mts → errors-CS5UPJWs.d.ts} +25 -1
  8. package/dist/errors-CS5UPJWs.d.ts.map +1 -0
  9. package/dist/{errors.d.mts → errors.d.ts} +1 -1
  10. package/dist/{errors.mjs → errors.js} +19 -1
  11. package/dist/errors.js.map +1 -0
  12. package/dist/exponential-backoff.d.ts +40 -0
  13. package/dist/exponential-backoff.d.ts.map +1 -0
  14. package/dist/exponential-backoff.js +35 -0
  15. package/dist/exponential-backoff.js.map +1 -0
  16. package/dist/fixed-delay.d.ts +31 -0
  17. package/dist/fixed-delay.d.ts.map +1 -0
  18. package/dist/fixed-delay.js +33 -0
  19. package/dist/fixed-delay.js.map +1 -0
  20. package/dist/index.d.ts +7 -0
  21. package/dist/index.js +6 -0
  22. package/dist/linear-backoff.d.ts +46 -0
  23. package/dist/linear-backoff.d.ts.map +1 -0
  24. package/dist/linear-backoff.js +35 -0
  25. package/dist/linear-backoff.js.map +1 -0
  26. package/dist/{types.d.mts → types.d.ts} +52 -8
  27. package/dist/types.d.ts.map +1 -0
  28. package/dist/types.js +0 -0
  29. package/package.json +12 -22
  30. package/dist/abort.d.mts +0 -29
  31. package/dist/abort.d.mts.map +0 -1
  32. package/dist/abort.mjs +0 -61
  33. package/dist/abort.mjs.map +0 -1
  34. package/dist/errors-BVZjP1Q5.d.mts.map +0 -1
  35. package/dist/errors.mjs.map +0 -1
  36. package/dist/exponential-backoff.d.mts +0 -55
  37. package/dist/exponential-backoff.d.mts.map +0 -1
  38. package/dist/exponential-backoff.mjs +0 -60
  39. package/dist/exponential-backoff.mjs.map +0 -1
  40. package/dist/fixed-delay.d.mts +0 -46
  41. package/dist/fixed-delay.d.mts.map +0 -1
  42. package/dist/fixed-delay.mjs +0 -53
  43. package/dist/fixed-delay.mjs.map +0 -1
  44. package/dist/index.d.mts +0 -59
  45. package/dist/index.d.mts.map +0 -1
  46. package/dist/index.mjs +0 -63
  47. package/dist/index.mjs.map +0 -1
  48. package/dist/result-mode.d.mts +0 -19
  49. package/dist/result-mode.d.mts.map +0 -1
  50. package/dist/result-mode.mjs +0 -145
  51. package/dist/result-mode.mjs.map +0 -1
  52. package/dist/sleep.d.mts +0 -17
  53. package/dist/sleep.d.mts.map +0 -1
  54. package/dist/sleep.mjs +0 -23
  55. package/dist/sleep.mjs.map +0 -1
  56. package/dist/throw-mode.d.mts +0 -21
  57. package/dist/throw-mode.d.mts.map +0 -1
  58. package/dist/throw-mode.mjs +0 -49
  59. package/dist/throw-mode.mjs.map +0 -1
  60. package/dist/types.d.mts.map +0 -1
  61. package/dist/types.mjs +0 -1
package/CHANGELOG.md CHANGED
@@ -1,19 +1,63 @@
1
- ## @zap-studio/retry@0.3.1
1
+ # Changelog
2
2
 
3
- ### Migrate to ultracite lint/format
3
+ All notable changes to this project will be documented in this file.
4
4
 
5
- Internal formatting and lint cleanup only. No public API or behavior change.
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [1.0.0]
8
+
9
+ ### Added
6
10
 
7
- # @zap-studio/retry
11
+ `RetryPolicy` gains an optional `isKnownError?: (error: unknown) => error is TError` hook that `BaseRetryPolicy.run(...)` now calls before handing a caught value to `next(...)`/`onExhausted(...)`. `BaseRetryPolicy.isKnownError` default checks `error instanceof Error`.
8
12
 
9
- ## 0.3.0
13
+ - Override `isKnownError` when `TError` is a narrower subclass (an HTTP error, a domain-specific error) to get real narrowing instead of an `instanceof Error` assumption, and to stop unrelated `Error` types from being retried as if they belonged to your domain.
10
14
 
11
- ### Breaking
15
+ See [Narrow the Error Domain](https://www.zapstudio.dev/retry/custom-policies#narrow-the-error-domain) for the override pattern.
12
16
 
13
- - **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`.
17
+ New built-in policy: `linearBackoff(options)` adds a fixed `incrementMs` to the delay after each failed attempt, capped at `maxDelayMs` steadier growth than `exponentialBackoff`, more spacing than `fixedDelay`. See [linearBackoff](https://www.zapstudio.dev/retry/linear-backoff).
14
18
 
15
19
  ### Changed
16
20
 
21
+ - **Breaking:** `TError` is now constrained to `TError extends Error` and defaults to `Error` (was `TError = unknown`) on `RetryPolicy`, `RetryDecisionInput`, `RetryExhaustedInput`, and `BaseRetryPolicy`.
22
+ - **Breaking behavior change:** a rejection with a non-`Error` value (a thrown string, plain object, `undefined`, ...) now bypasses retry entirely on the attempt that produced it — it no longer reaches `next(...)`, and no delay/backoff is applied. Previously any thrown value was passed through to the policy unchanged. In throw mode, `run(...)` rethrows the value as-is; with `throwOnExhausted: false`, it's wrapped in a `RetryError` and returned on `result.error` — `run(...)` never throws in that mode.
23
+ - **Breaking:** Policies are plain objects instead of classes, for tree-shaking — bundlers can drop an unused policy factory and its defaults entirely, which isn't possible across a shared class hierarchy. `ExponentialBackoff`/`FixedDelay` classes are replaced by `exponentialBackoff(options)`/`fixedDelay(options)` factory functions that return a `RetryPolicy`. Migrate `new ExponentialBackoff(opts)` to `exponentialBackoff(opts)`, and `new FixedDelay(opts)` to `fixedDelay(opts)`.
24
+ - **Breaking:** `RetryPolicy.onExhausted` is now optional (previously required); omit it to use the same default `RetryError` that `BaseRetryPolicy.onExhausted` used to build.
25
+
26
+ ### Removed
27
+
28
+ - **Breaking:** `BaseRetryPolicy` is removed. Retry orchestration is now the standalone function `runRetryPolicy(policy, execute, options?)`, which accepts any object satisfying `RetryPolicy` — no subclassing required. Migrate `policy.run(execute, options)` to `runRetryPolicy(policy, execute, options)`. A custom policy that previously extended `BaseRetryPolicy` and overrode `next`/`onExhausted`/`isKnownError` becomes an object literal implementing the same members; see [Custom Policies](https://www.zapstudio.dev/retry/custom-policies).
29
+
30
+ ### Removed
31
+
32
+ Collapsed abort/sleep orchestration internals out of the public API.
33
+
34
+ - Removed the `./abort` and `./sleep` subpath exports.
35
+ - Removed the public `sleepWithAbortSignal`, `throwIfAborted`, and `toAbortError` exports — they were orchestration internals with no consumer outside the retry loop, not standalone utilities.
36
+ - `defaultSleep` is unaffected and still exported from `@zap-studio/retry` (no dedicated subpath).
37
+
38
+ ## [0.3.2]
39
+
40
+ ### Added
41
+
42
+ The package root now re-exports the full public API, so everything can be imported from `@zap-studio/retry` directly (`BaseRetryPolicy`, `ExponentialBackoff`, `FixedDelay`, `RetryError`, `AbortError`, abort helpers, `defaultSleep`, and all public types). All exports are side-effect free and tree-shakeable; granular subpath imports keep working.
43
+
44
+ - `BaseRetryPolicy` moved from the entrypoint into its own module, available as the new `./base-policy` subpath.
45
+
46
+ ### Removed
47
+
48
+ - Removed the `./result-mode` and `./throw-mode` subpath exports. Both were orchestration internals (`runResultMode`, `runThrowMode`) and are no longer part of the public API.
49
+
50
+ ## [0.3.1]
51
+
52
+ ### Changed
53
+
54
+ Internal formatting and lint cleanup only. No public API or behavior change.
55
+
56
+ ## [0.3.0]
57
+
58
+ ### Changed
59
+
60
+ - **Breaking:** 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`.
17
61
  - Add dedicated `AbortError` and normalize cancellation paths so retry internals throw/return `RetryError` or `AbortError` instead of plain `Error`.
18
62
  - 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).
19
63
  - Align non-throw exhaustion metadata so `result.attempts` and `result.error.attempts` stay consistent for `RetryError` outcomes.
@@ -24,7 +68,7 @@ Internal formatting and lint cleanup only. No public API or behavior change.
24
68
  - Add exhaustive TSDoc for `result-mode` and other `src` modules, including private helpers, policy option and state fields, and `RetryRunResult` union members.
25
69
  - 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.
26
70
 
27
- ## 0.2.0
71
+ ## [0.2.0]
28
72
 
29
73
  ### Changed
30
74
 
@@ -34,13 +78,13 @@ Internal formatting and lint cleanup only. No public API or behavior change.
34
78
  - Add abort-focused ecosystem benchmarks comparing signal overhead and immediate cancellation behavior.
35
79
  - Expand TSDoc coverage for new runner internals added in this release.
36
80
 
37
- ## 0.1.2
81
+ ## [0.1.2]
38
82
 
39
83
  ### Changed
40
84
 
41
85
  - Expand TSDoc coverage across retry modules and exported contracts for stronger JSR documentation completeness.
42
86
 
43
- ## 0.1.1
87
+ ## [0.1.1]
44
88
 
45
89
  ### Fixed
46
90
 
@@ -50,7 +94,7 @@ Internal formatting and lint cleanup only. No public API or behavior change.
50
94
 
51
95
  - e9903c5: Removed redundant `| undefined` unions from public retry option and decision types.
52
96
 
53
- ## 0.1.0
97
+ ## [0.1.0]
54
98
 
55
99
  ### Added
56
100
 
@@ -62,7 +106,4 @@ Internal formatting and lint cleanup only. No public API or behavior change.
62
106
  - Added `ExponentialBackoff` policy with bounded exponential delay via `baseDelayMs`, `maxDelayMs`, and `maxAttempts`.
63
107
  - Added `FixedDelay` policy with constant delay and bounded attempts.
64
108
  - Added `RetryError` for exhausted-retry failures with structured attempt/error/data context.
65
-
66
- ### Documentation
67
-
68
109
  - Documented throwable behavior on `RetryPolicy`, `BaseRetryPolicy.run`, and related contracts with explicit `@throws` tags for policy, exhaustion, and custom `sleep` failures.
package/README.md CHANGED
@@ -2,26 +2,37 @@
2
2
 
3
3
  Composable retry policy primitives for HTTP clients and async workflows.
4
4
 
5
+ Full documentation: [zapstudio.dev/retry](https://www.zapstudio.dev/retry)
6
+
5
7
  ## Installation
6
8
 
7
9
  ```bash
8
10
  npm install @zap-studio/retry
9
11
  ```
10
12
 
11
- ## Usage
13
+ ## Features
14
+
15
+ - **Built-in policies**: `fixedDelay(...)`, `linearBackoff(...)`, and `exponentialBackoff(...)`.
16
+ - **A shared runner** via `runRetryPolicy(policy, execute, options?)` with attempt-aware callbacks and custom sleep injection.
17
+ - **Structured terminal errors**: `RetryError` on exhaustion, `AbortError` on cancellation.
18
+ - **Non-throw mode** (`throwOnExhausted: false`) returns a `RetryRunResult` instead of throwing.
19
+ - **Cancellation** through `AbortSignal`, checked before, between, and during retries.
20
+ - **Custom policies** as plain objects implementing `RetryPolicy` — just a `next(...)` function, no subclassing.
21
+ - **Tree-shakeable** — policies are functions returning plain objects, not classes; unused policies are dropped by any modern bundler.
22
+
23
+ ## Quick Start
12
24
 
13
25
  ```ts
14
- import { ExponentialBackoff } from "@zap-studio/retry/exponential-backoff";
15
- import { FixedDelay } from "@zap-studio/retry/fixed-delay";
26
+ import { exponentialBackoff, runRetryPolicy } from "@zap-studio/retry";
16
27
  import { $fetch } from "@zap-studio/fetch";
17
28
 
18
- const exponential = new ExponentialBackoff({
29
+ const policy = exponentialBackoff({
19
30
  maxAttempts: 5,
20
31
  baseDelayMs: 100,
21
32
  maxDelayMs: 2_000,
22
33
  });
23
34
 
24
- const data = await exponential.run(async () => {
35
+ const data = await runRetryPolicy(policy, async () => {
25
36
  const response = await $fetch("https://api.example.com/users", {
26
37
  throwOnFetchError: true,
27
38
  });
@@ -29,189 +40,124 @@ const data = await exponential.run(async () => {
29
40
  });
30
41
  ```
31
42
 
32
- ## Handling Errors
33
-
34
- `run(...)` throws when retries are exhausted.
43
+ ## Built-in Policies
35
44
 
36
- By default, policies extending `BaseRetryPolicy` throw `RetryError` on exhaustion and `AbortError` on cancellation.
45
+ `fixedDelay(...)`, `linearBackoff(...)`, and `exponentialBackoff(...)`.
37
46
 
38
47
  ```ts
39
- import { AbortError, RetryError } from "@zap-studio/retry/errors";
48
+ import {
49
+ exponentialBackoff,
50
+ fixedDelay,
51
+ linearBackoff,
52
+ } from "@zap-studio/retry";
40
53
 
41
- try {
42
- const data = await exponential.run(async () => {
43
- const response = await $fetch("https://api.example.com/users", {
44
- throwOnFetchError: true,
45
- });
46
- return await response.json();
47
- });
48
- console.log(data);
49
- } catch (error) {
50
- if (error instanceof RetryError) {
51
- console.error("Retries exhausted:", error.attempts);
52
- console.error("Last error:", error.lastError);
53
- } else if (error instanceof AbortError) {
54
- console.error("Retry aborted:", error.message);
55
- } else {
56
- throw error;
57
- }
58
- }
54
+ const exponential = exponentialBackoff({
55
+ maxAttempts: 5,
56
+ baseDelayMs: 100,
57
+ maxDelayMs: 2_000,
58
+ });
59
+ const linear = linearBackoff({
60
+ maxAttempts: 5,
61
+ baseDelayMs: 100,
62
+ incrementMs: 100,
63
+ maxDelayMs: 2_000,
64
+ });
65
+ const fixed = fixedDelay({ maxAttempts: 4, delayMs: 300 });
59
66
  ```
60
67
 
61
- To handle exhaustion without throwing, pass `throwOnExhausted: false`:
68
+ ## Shared Runner
62
69
 
63
- ```ts
64
- const result = await exponential.run(
65
- async () => {
66
- const response = await $fetch("https://api.example.com/users", {
67
- throwOnFetchError: true,
68
- });
69
- return await response.json();
70
- },
71
- { throwOnExhausted: false }
72
- );
70
+ Via `runRetryPolicy(policy, execute, options?)` with attempt-aware callbacks and custom sleep injection.
73
71
 
74
- if (!result.ok) {
75
- console.error("Retries exhausted:", result.attempts);
76
- console.error("Last error:", result.error.lastError);
77
- } else {
78
- console.log(result.value);
79
- }
72
+ ```ts
73
+ await runRetryPolicy(policy, execute, {
74
+ sleep: (delayMs) => customSleep(delayMs),
75
+ });
80
76
  ```
81
77
 
82
- ## Default sleep
78
+ ## Structured Terminal Errors
83
79
 
84
- `BaseRetryPolicy.run` automatically applies a delay between retry attempts when no custom `sleep` function is provided in the options.
85
-
86
- That default is the `defaultSleep` helper, exported from `@zap-studio/retry/sleep`.
87
-
88
- 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.
89
-
90
- ## Cancellation With AbortSignal
91
-
92
- Use `signal` in `run(...)` options to stop retrying early.
80
+ `RetryError` on exhaustion, `AbortError` on cancellation.
93
81
 
94
82
  ```ts
95
- const controller = new AbortController();
96
-
97
- const promise = exponential.run(
98
- async () => {
99
- const response = await $fetch("https://api.example.com/users", {
100
- throwOnFetchError: true,
101
- });
102
- return await response.json();
103
- },
104
- { signal: controller.signal }
105
- );
83
+ import { AbortError, RetryError, runRetryPolicy } from "@zap-studio/retry";
106
84
 
107
- controller.abort(new Error("Request canceled"));
108
-
109
- await promise;
85
+ try {
86
+ await runRetryPolicy(policy, execute);
87
+ } catch (error) {
88
+ if (error instanceof RetryError)
89
+ console.error(error.attempts, error.lastError);
90
+ if (error instanceof AbortError) console.error(error.message);
91
+ }
110
92
  ```
111
93
 
112
- In non-throw mode, abort is returned as `{ ok: false }` with `AbortError` on `result.error`:
94
+ ## Non-throw Mode
113
95
 
114
- ```ts
115
- const controller = new AbortController();
96
+ `throwOnExhausted: false` returns a `RetryRunResult` instead of throwing.
116
97
 
117
- const result = await exponential.run(
118
- async () => {
119
- const response = await $fetch("https://api.example.com/users", {
120
- throwOnFetchError: true,
121
- });
122
- return await response.json();
123
- },
124
- {
125
- signal: controller.signal,
126
- throwOnExhausted: false,
127
- }
128
- );
98
+ ```ts
99
+ const result = await runRetryPolicy(policy, execute, {
100
+ throwOnExhausted: false,
101
+ });
129
102
 
130
103
  if (!result.ok) {
131
- console.error("Retry stopped:", result.error);
104
+ console.error(result.error);
105
+ } else {
106
+ console.log(result.value);
132
107
  }
133
108
  ```
134
109
 
135
- ## Choosing The Right Policy
110
+ ## Cancellation
136
111
 
137
- Use `ExponentialBackoff` for transient network instability and shared upstream services.
112
+ Through `AbortSignal`, checked before, between, and during retries.
138
113
 
139
114
  ```ts
140
- const unstableNetworkPolicy = new ExponentialBackoff({
141
- maxAttempts: 6,
142
- baseDelayMs: 100,
143
- maxDelayMs: 2_000,
144
- });
145
- ```
115
+ const controller = new AbortController();
146
116
 
147
- Use `FixedDelay` for stable, predictable retry intervals in controlled environments.
117
+ const promise = runRetryPolicy(policy, execute, { signal: controller.signal });
148
118
 
149
- ```ts
150
- const predictableIntervalPolicy = new FixedDelay({
151
- maxAttempts: 4,
152
- delayMs: 300,
153
- });
119
+ controller.abort(new Error("Request canceled"));
154
120
  ```
155
121
 
156
122
  ## Custom Policies
157
123
 
158
- Extend `BaseRetryPolicy` when the built-in policies do not match your retry rules.
159
-
160
- You implement `next(...)` only; the base class supplies `onExhausted` with a default `RetryError` and keeps the shared `run(...)` orchestration (override `onExhausted` when you need a different terminal error).
124
+ As plain objects implementing `RetryPolicy` just a `next(...)` function, no subclassing.
161
125
 
162
126
  ```ts
163
- import { BaseRetryPolicy } from "@zap-studio/retry";
127
+ import { runRetryPolicy } from "@zap-studio/retry";
164
128
  import type {
165
129
  RetryDecision,
166
130
  RetryDecisionInput,
167
- } from "@zap-studio/retry/types";
168
-
169
- class LinearBackoff extends BaseRetryPolicy {
170
- constructor(
171
- private readonly maxAttempts: number,
172
- private readonly stepMs: number
173
- ) {
174
- super();
175
- }
176
-
177
- public next(input: RetryDecisionInput): RetryDecision {
178
- if (input.attempt >= this.maxAttempts) {
179
- return {
180
- shouldRetry: false,
181
- delayMs: 0,
182
- reason: "max-attempts-reached",
183
- };
184
- }
131
+ RetryPolicy,
132
+ } from "@zap-studio/retry";
185
133
 
134
+ const stepDelay = (maxAttempts: number, stepMs: number): RetryPolicy => ({
135
+ next(input: RetryDecisionInput): RetryDecision {
136
+ if (input.attempt >= maxAttempts) {
137
+ return { shouldRetry: false, delayMs: 0, reason: "max-attempts-reached" };
138
+ }
186
139
  return {
187
140
  shouldRetry: true,
188
- delayMs: input.attempt * this.stepMs,
141
+ delayMs: input.attempt * stepMs,
189
142
  reason: "retry",
190
143
  };
191
- }
192
- }
144
+ },
145
+ });
193
146
 
194
- const policy = new LinearBackoff(5, 250);
195
- const value = await policy.run(doWork);
147
+ const data = await runRetryPolicy(stepDelay(5, 100), execute);
196
148
  ```
197
149
 
198
- ## RetryError
199
-
200
- Use `RetryError` when an orchestrator exhausts retries and needs to surface final context.
201
-
202
- ```ts
203
- import { RetryError } from "@zap-studio/retry/errors";
204
-
205
- throw new RetryError("Retry policy exhausted all attempts.", {
206
- attempts: attempt,
207
- lastError: error,
208
- lastData: data,
209
- });
210
- ```
150
+ ## Runtime Support
211
151
 
212
- Policies implement `onExhausted(input)` to return the terminal error used by the built-in runner.
152
+ | Runtime | Minimum version |
153
+ | ------------------ | --------------------------------------- |
154
+ | Node.js | 18.0.0 |
155
+ | Bun | 1.0.0 |
156
+ | Deno | 1.42 |
157
+ | Cloudflare Workers | Any current release |
158
+ | Browsers | Chrome/Edge 98, Firefox 97, Safari 15.4 |
213
159
 
214
- `ExponentialBackoff` and `FixedDelay` inherit the default implementation from `BaseRetryPolicy`.
160
+ Cancellation relies on `AbortSignal.reason`, which sets the browser minimums above. Deno 1.42 is the first release that can install packages from JSR (`deno add jsr:@zap-studio/retry`).
215
161
 
216
162
  ## License
217
163
 
@@ -0,0 +1,67 @@
1
+ import { RetryPolicy, RetryRunOptions, RetryRunResult } from "./types.js";
2
+ //#region src/base-policy.d.ts
3
+ /**
4
+ * Awaits a timer-based delay, unless `delayMs` is non-positive.
5
+ *
6
+ * @param delayMs - Milliseconds to wait before resolving.
7
+ * @returns Promise that resolves when the delay completes.
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * import { defaultSleep } from "@zap-studio/retry";
12
+ *
13
+ * await defaultSleep(250); // waits 250ms
14
+ * ```
15
+ */
16
+ declare const defaultSleep: (delayMs: number) => Promise<void>;
17
+ /**
18
+ * Runs retry orchestration in non-throw mode.
19
+ *
20
+ * @param policy - Retry policy: `next` is required, `onExhausted` and
21
+ * `isKnownError` fall back to their defaults when omitted.
22
+ * @param execute - Async function to execute per attempt.
23
+ * @param options - Runner settings with `throwOnExhausted: false`.
24
+ * @returns A discriminated result union containing success value or terminal error.
25
+ * When `policy.isKnownError` rejects a caught value, it is wrapped in a
26
+ * `RetryError` and returned as the terminal failure instead of thrown.
27
+ * @throws {Error} Any error thrown by `next`, `onExhausted`, or a custom `sleep`.
28
+ */
29
+ declare function runRetryPolicy<T, TError extends Error = Error, TData = unknown>(policy: RetryPolicy<TError, TData>, execute: (attempt: number) => Promise<T>, options: RetryRunOptions & {
30
+ throwOnExhausted: false;
31
+ }): Promise<RetryRunResult<T>>;
32
+ /**
33
+ * Runs retry orchestration and throws terminal error on exhaustion.
34
+ *
35
+ * @param policy - Retry policy: `next` is required, `onExhausted` and
36
+ * `isKnownError` fall back to their defaults when omitted.
37
+ * @param execute - Async function to execute per attempt.
38
+ * @param options - Optional runner settings.
39
+ * @returns The successful execution value.
40
+ * @throws {RetryError} When retries are exhausted and `onExhausted` returns the
41
+ * terminal retry error. The default implementation returns `RetryError` with the last
42
+ * execution failure available on `RetryError.lastError`.
43
+ * @throws {AbortError} When `options.signal` is already aborted or aborts while retrying.
44
+ * @throws {Error} Any error thrown by `next`, by `onExhausted`, or by a custom `sleep`
45
+ * function.
46
+ *
47
+ * @example
48
+ * ```ts
49
+ * import { runRetryPolicy } from "@zap-studio/retry";
50
+ * import type { RetryPolicy } from "@zap-studio/retry";
51
+ *
52
+ * const linearBackoff: RetryPolicy = {
53
+ * next: ({ attempt }) =>
54
+ * attempt < 3
55
+ * ? { shouldRetry: true, delayMs: attempt * 100, reason: "retry" }
56
+ * : { shouldRetry: false, delayMs: 0, reason: "max-attempts-reached" },
57
+ * };
58
+ *
59
+ * const data = await runRetryPolicy(linearBackoff, async () => fetchFlakyResource());
60
+ * ```
61
+ */
62
+ declare function runRetryPolicy<T, TError extends Error = Error, TData = unknown>(policy: RetryPolicy<TError, TData>, execute: (attempt: number) => Promise<T>, options?: RetryRunOptions & {
63
+ throwOnExhausted?: true;
64
+ }): Promise<T>;
65
+ //#endregion
66
+ export { defaultSleep, runRetryPolicy };
67
+ //# sourceMappingURL=base-policy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base-policy.d.ts","names":[],"sources":["../src/base-policy.ts"],"mappings":";;;;;;;;;;;;;;;cA4Ba,eAAsB,oBAAkB;;;;;;;;;;;;;iBA8YrC,eACd,GACA,eAAe,QAAQ,OACvB,iBAEA,QAAQ,YAAY,QAAQ,QAC5B,UAAU,oBAAoB,QAAQ,IACtC,SAAS;EAAoB;IAC5B,QAAQ,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAgCV,eACd,GACA,eAAe,QAAQ,OACvB,iBAEA,QAAQ,YAAY,QAAQ,QAC5B,UAAU,oBAAoB,QAAQ,IACtC,UAAU;EAAoB;IAC7B,QAAQ"}