@zap-studio/retry 0.3.0 → 0.3.1

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.
@@ -1 +1 @@
1
- {"version":3,"file":"throw-mode.mjs","names":[],"sources":["../src/throw-mode.ts"],"sourcesContent":["/**\n * Throw-mode execution path for `BaseRetryPolicy.run` (default when\n * `throwOnExhausted` is not `false`).\n *\n * @module @zap-studio/retry/throw-mode\n */\n\nimport { sleepWithAbortSignal, throwIfAborted } from \"./abort.js\";\nimport { RetryError } from \"./errors.js\";\nimport type { RetryDecision, RetryDecisionInput, RetryExhaustedInput } from \"./types.js\";\n\n/**\n * Runs the throw-mode retry loop: throws `RetryError` on exhaustion and\n * `AbortError` when `signal` aborts.\n *\n * @param policy - Object providing `next` and `onExhausted` (same contract as\n * `BaseRetryPolicy`).\n * @param execute - Async work callback per attempt.\n * @param sleep - Delay function between retries.\n * @param signal - Optional cancel signal.\n * @returns Resolves to the first successful return value.\n * @throws {RetryError} When retries are exhausted and `onExhausted` returns\n * the terminal error.\n * @throws {AbortError} When `signal` is already aborted or aborts while waiting.\n * @throws Any error thrown by `next`, `onExhausted`, or `sleep`.\n */\nexport async function runThrowMode<T, TError, TData>(\n policy: {\n next: (input: RetryDecisionInput<TError, TData>) => RetryDecision;\n onExhausted: (input: RetryExhaustedInput<TError, TData>) => RetryError;\n },\n execute: (attempt: number) => Promise<T>,\n sleep: (delayMs: number) => Promise<void>,\n signal?: AbortSignal,\n): Promise<T> {\n let attempt = 1;\n\n while (true) {\n throwIfAborted(signal);\n\n try {\n return await execute(attempt);\n } catch (error) {\n throwIfAborted(signal);\n\n const typedError = error as TError;\n const decision = policy.next({\n attempt,\n error: typedError,\n });\n\n if (!decision.shouldRetry) {\n throw policy.onExhausted({\n attempts: attempt,\n error: typedError,\n });\n }\n\n if (decision.delayMs > 0) {\n if (signal) {\n await sleepWithAbortSignal(sleep, decision.delayMs, signal);\n } else {\n await sleep(decision.delayMs);\n }\n }\n\n attempt += 1;\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AA0BA,eAAsB,aACpB,QAIA,SACA,OACA,QACY;CACZ,IAAI,UAAU;AAEd,QAAO,MAAM;AACX,iBAAe,OAAO;AAEtB,MAAI;AACF,UAAO,MAAM,QAAQ,QAAQ;WACtB,OAAO;AACd,kBAAe,OAAO;GAEtB,MAAM,aAAa;GACnB,MAAM,WAAW,OAAO,KAAK;IAC3B;IACA,OAAO;IACR,CAAC;AAEF,OAAI,CAAC,SAAS,YACZ,OAAM,OAAO,YAAY;IACvB,UAAU;IACV,OAAO;IACR,CAAC;AAGJ,OAAI,SAAS,UAAU,EACrB,KAAI,OACF,OAAM,qBAAqB,OAAO,SAAS,SAAS,OAAO;OAE3D,OAAM,MAAM,SAAS,QAAQ;AAIjC,cAAW"}
1
+ {"version":3,"file":"throw-mode.mjs","names":[],"sources":["../src/throw-mode.ts"],"sourcesContent":["/**\n * Throw-mode execution path for `BaseRetryPolicy.run` (default when\n * `throwOnExhausted` is not `false`).\n *\n * @module @zap-studio/retry/throw-mode\n */\n\nimport { sleepWithAbortSignal, throwIfAborted } from \"./abort.js\";\nimport type { RetryPolicy } from \"./types.js\";\n\n/**\n * Runs the throw-mode retry loop: throws `RetryError` on exhaustion and\n * `AbortError` when `signal` aborts.\n *\n * @param policy - Object providing `next` and `onExhausted` (same contract as\n * `BaseRetryPolicy`).\n * @param execute - Async work callback per attempt.\n * @param sleep - Delay function between retries.\n * @param signal - Optional cancel signal.\n * @returns Resolves to the first successful return value.\n * @throws {RetryError} When retries are exhausted and `onExhausted` returns\n * the terminal error.\n * @throws {AbortError} When `signal` is already aborted or aborts while waiting.\n * @throws {Error} Any error thrown by `next`, `onExhausted`, or `sleep`.\n */\nexport const runThrowMode = async <T, TError, TData>(\n policy: RetryPolicy<TError, TData>,\n execute: (attempt: number) => Promise<T>,\n sleep: (delayMs: number) => Promise<void>,\n signal?: AbortSignal\n): Promise<T> => {\n let attempt = 1;\n\n while (true) {\n throwIfAborted(signal);\n\n try {\n // oxlint-disable-next-line no-await-in-loop -- Retry attempts must run sequentially.\n return await execute(attempt);\n } catch (error) {\n throwIfAborted(signal);\n\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- Policy error generic represents the caller's thrown error domain.\n const typedError = error as TError;\n const decision = policy.next({\n attempt,\n error: typedError,\n });\n\n if (!decision.shouldRetry) {\n throw policy.onExhausted({\n attempts: attempt,\n error: typedError,\n });\n }\n\n if (decision.delayMs > 0) {\n // oxlint-disable-next-line no-await-in-loop -- Delay belongs between sequential retry attempts.\n await (signal === undefined\n ? sleep(decision.delayMs)\n : sleepWithAbortSignal(sleep, decision.delayMs, signal));\n }\n\n attempt += 1;\n }\n }\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAyBA,MAAa,eAAe,OAC1B,QACA,SACA,OACA,WACe;CACf,IAAI,UAAU;CAEd,OAAO,MAAM;EACX,eAAe,MAAM;EAErB,IAAI;GAEF,OAAO,MAAM,QAAQ,OAAO;EAC9B,SAAS,OAAO;GACd,eAAe,MAAM;GAGrB,MAAM,aAAa;GACnB,MAAM,WAAW,OAAO,KAAK;IAC3B;IACA,OAAO;GACT,CAAC;GAED,IAAI,CAAC,SAAS,aACZ,MAAM,OAAO,YAAY;IACvB,UAAU;IACV,OAAO;GACT,CAAC;GAGH,IAAI,SAAS,UAAU,GAErB,OAAO,WAAW,KAAA,IACd,MAAM,SAAS,OAAO,IACtB,qBAAqB,OAAO,SAAS,SAAS,MAAM;GAG1D,WAAW;EACb;CACF;AACF"}
package/dist/types.d.mts CHANGED
@@ -1,143 +1,141 @@
1
- import { r as RetryError, t as AbortError } from "./errors-fWo_KyVO.mjs";
2
-
1
+ import { r as RetryError, t as AbortError } from "./errors-BVZjP1Q5.mjs";
3
2
  //#region src/types.d.ts
4
3
  /**
5
- * Retry policy contract used by `BaseRetryPolicy`.
6
- *
7
- * @example
8
- * const policy: RetryPolicy = {
9
- * next: ({ attempt }) => ({ shouldRetry: attempt < 3, delayMs: 100 }),
10
- * onExhausted: ({ attempts }) => new RetryError("done", { attempts }),
11
- * };
12
- */
4
+ * Retry policy contract used by `BaseRetryPolicy`.
5
+ *
6
+ * @example
7
+ * const policy: RetryPolicy = {
8
+ * next: ({ attempt }) => ({ shouldRetry: attempt < 3, delayMs: 100 }),
9
+ * onExhausted: ({ attempts }) => new RetryError("done", { attempts }),
10
+ * };
11
+ */
13
12
  interface RetryPolicy<TError = unknown, TData = unknown> {
14
13
  /**
15
- * Returns the retry decision for a failed attempt.
16
- *
17
- * @throws Any error thrown by the policy implementation.
18
- */
19
- next(input: RetryDecisionInput<TError, TData>): RetryDecision;
20
- /**
21
- * Builds the terminal error used when retries are exhausted.
22
- *
23
- * @throws Any error thrown by the policy implementation.
24
- */
25
- onExhausted(input: RetryExhaustedInput<TError, TData>): RetryError;
14
+ * Returns the retry decision for a failed attempt.
15
+ *
16
+ * @throws {Error} Any error thrown by the policy implementation.
17
+ */
18
+ next: (input: RetryDecisionInput<TError, TData>) => RetryDecision;
19
+ /**
20
+ * Builds the terminal error used when retries are exhausted.
21
+ *
22
+ * @throws {Error} Any error thrown by the policy implementation.
23
+ */
24
+ onExhausted: (input: RetryExhaustedInput<TError, TData>) => RetryError;
26
25
  }
27
26
  /**
28
- * Decision returned by a retry policy for a specific attempt.
29
- */
27
+ * Decision returned by a retry policy for a specific attempt.
28
+ */
30
29
  interface RetryDecision {
31
30
  /**
32
- * When `true`, the runner may schedule another attempt (subject to
33
- * `delayMs` and the runner's abort rules).
34
- */
31
+ * When `true`, the runner may schedule another attempt (subject to
32
+ * `delayMs` and the runner's abort rules).
33
+ */
35
34
  readonly shouldRetry: boolean;
36
35
  /**
37
- * Milliseconds to wait before the next attempt when `shouldRetry` is `true`.
38
- */
36
+ * Milliseconds to wait before the next attempt when `shouldRetry` is `true`.
37
+ */
39
38
  readonly delayMs: number;
40
39
  /**
41
- * Optional machine-readable reason for the decision.
42
- */
40
+ * Optional machine-readable reason for the decision.
41
+ */
43
42
  readonly reason?: "retry" | "max-attempts-reached" | "policy-declined";
44
43
  }
45
44
  /**
46
- * Input passed to `RetryPolicy.next(...)` for each failed attempt.
47
- */
45
+ * Input passed to `RetryPolicy.next(...)` for each failed attempt.
46
+ */
48
47
  interface RetryDecisionInput<TError = unknown, TData = unknown> {
49
48
  /**
50
- * One-based attempt number for the current failure.
51
- */
49
+ * One-based attempt number for the current failure.
50
+ */
52
51
  readonly attempt: number;
53
52
  /**
54
- * Optional policy-level maximum attempts, when a policy wants to pass it
55
- * through to `next`.
56
- */
53
+ * Optional policy-level maximum attempts, when a policy wants to pass it
54
+ * through to `next`.
55
+ */
57
56
  readonly maxAttempts?: number;
58
57
  /**
59
- * Error raised by the most recent `execute(attempt)` call, when a failure
60
- * occurred.
61
- */
58
+ * Error raised by the most recent `execute(attempt)` call, when a failure
59
+ * occurred.
60
+ */
62
61
  readonly error?: TError;
63
62
  /**
64
- * Optional data captured alongside the failure, when a policy populates
65
- * it.
66
- */
63
+ * Optional data captured alongside the failure, when a policy populates
64
+ * it.
65
+ */
67
66
  readonly data?: TData;
68
67
  }
69
68
  /**
70
- * Input passed to `RetryPolicy.onExhausted(...)` when retries stop.
71
- */
69
+ * Input passed to `RetryPolicy.onExhausted(...)` when retries stop.
70
+ */
72
71
  interface RetryExhaustedInput<TError = unknown, TData = unknown> {
73
72
  /**
74
- * Count of completed attempts that led to stopping retries.
75
- */
73
+ * Count of completed attempts that led to stopping retries.
74
+ */
76
75
  readonly attempts: number;
77
76
  /**
78
- * Last execution error, when available.
79
- */
77
+ * Last execution error, when available.
78
+ */
80
79
  readonly error?: TError;
81
80
  /**
82
- * Last captured data, when a policy or runner supplies it.
83
- */
81
+ * Last captured data, when a policy or runner supplies it.
82
+ */
84
83
  readonly data?: TData;
85
84
  }
86
85
  /**
87
- * Options for `BaseRetryPolicy.run(...)`.
88
- */
86
+ * Options for `BaseRetryPolicy.run(...)`.
87
+ */
89
88
  interface RetryRunOptions {
90
89
  /**
91
- * Delay function used between retry attempts.
92
- *
93
- * @throws Any error thrown or rejected by the custom delay implementation.
94
- */
90
+ * Delay function used between retry attempts.
91
+ *
92
+ * @throws {Error} Any error thrown or rejected by the custom delay implementation.
93
+ */
95
94
  readonly sleep?: (delayMs: number) => Promise<void>;
96
95
  /**
97
- * Abort signal used to cancel retry orchestration.
98
- *
99
- * When aborted, the runner stops retrying and terminates immediately.
100
- */
96
+ * Abort signal used to cancel retry orchestration.
97
+ *
98
+ * When aborted, the runner stops retrying and terminates immediately.
99
+ */
101
100
  readonly signal?: AbortSignal;
102
101
  /**
103
- * When `true`, the runner throws a `RetryError` when retries are exhausted.
104
- *
105
- * When `false`, the runner returns a `RetryRunResult` discriminated union.
106
- *
107
- * @default true
108
- */
102
+ * When `true`, the runner throws a `RetryError` when retries are exhausted.
103
+ *
104
+ * When `false`, the runner returns a `RetryRunResult` discriminated union.
105
+ *
106
+ * @default true
107
+ */
109
108
  readonly throwOnExhausted?: boolean;
110
109
  }
111
110
  /**
112
- * Result union returned by non-throw runner mode.
113
- *
114
- * - Success: `ok: true` with the resolved `value`.
115
- * - Failure: `ok: false` with terminal `error` and completed `attempts` count
116
- * (exhaustion or abort).
117
- */
111
+ * Result union returned by non-throw runner mode.
112
+ *
113
+ * - Success: `ok: true` with the resolved `value`.
114
+ * - Failure: `ok: false` with terminal `error` and completed `attempts` count
115
+ * (exhaustion or abort).
116
+ */
118
117
  type RetryRunResult<T> = {
119
118
  /**
120
- * Discriminator for a successful run.
121
- */
119
+ * Discriminator for a successful run.
120
+ */
122
121
  ok: true;
123
122
  /**
124
- * Successful return value from the final attempt.
125
- */
123
+ * Successful return value from the final attempt.
124
+ */
126
125
  value: T;
127
126
  } | {
128
127
  /**
129
- * Discriminator for a failed or aborted run.
130
- */
128
+ * Discriminator for a failed or aborted run.
129
+ */
131
130
  ok: false;
132
131
  /**
133
- * Terminal error: `RetryError` when retries are exhausted, or
134
- * `AbortError` when the run is canceled (non-throw path uses the same
135
- * instances as throw mode, not wrapped).
136
- */
132
+ * Terminal error: `RetryError` when retries are exhausted, or
133
+ * `AbortError` when the run is canceled.
134
+ */
137
135
  error: RetryError | AbortError;
138
136
  /**
139
- * Number of attempts that completed before the terminal outcome.
140
- */
137
+ * Number of attempts that completed before the terminal outcome.
138
+ */
141
139
  attempts: number;
142
140
  };
143
141
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.mts","names":[],"sources":["../src/types.ts"],"mappings":";;;;;;;;;;;;UAiBiB,WAAA;;;;;;EAMf,IAAA,CAAK,KAAA,EAAO,kBAAA,CAAmB,MAAA,EAAQ,KAAA,IAAS,aAAA;;;;;;EAMhD,WAAA,CAAY,KAAA,EAAO,mBAAA,CAAoB,MAAA,EAAQ,KAAA,IAAS,UAAA;AAAA;AAM1D;;;AAAA,UAAiB,aAAA;;;;;WAKN,WAAA;EAcX;;;EAAA,SAVW,OAAA;;;;WAIA,MAAA;AAAA;;;;UAMM,kBAAA;;;;WAIN,OAAA;;;;;WAKA,WAAA;;;AAkCX;;WA7BW,KAAA,GAAQ,MAAA;EAyCC;;;;EAAA,SApCT,IAAA,GAAO,KAAA;AAAA;;;;UAMD,mBAAA;;;;WAIN,QAAA;;;;WAIA,KAAA,GAAQ,MAAA;;;;WAIR,IAAA,GAAO,KAAA;AAAA;;;;UAMD,eAAA;;;;;;WAMN,KAAA,IAAS,OAAA,aAAoB,OAAA;;;;;;WAM7B,MAAA,GAAS,WAAA;;;;;;;;WAQT,gBAAA;AAAA;;;;;;;;KAUC,cAAA;;;;EAKN,EAAA;;;;EAIA,KAAA,EAAO,CAAA;AAAA;;;;EAMP,EAAA;;;;;;EAMA,KAAA,EAAO,UAAA,GAAa,UAAA;;;;EAIpB,QAAA;AAAA"}
1
+ {"version":3,"file":"types.d.mts","names":[],"sources":["../src/types.ts"],"mappings":";;;;;;;;;;;UAiBiB,YAAY,kBAAkB;;;;;;EAM7C,OAAO,OAAO,mBAAmB,QAAQ,WAAW;;;;;;EAMpD,cAAc,OAAO,oBAAoB,QAAQ,WAAW;;;;;UAM7C;;;;;WAKN;;;;WAIA;;;;WAIA;;;;;UAMM,mBAAmB,kBAAkB;;;;WAI3C;;;;;WAKA;;;;;WAKA,QAAQ;;;;;WAKR,OAAO;;;;;UAMD,oBAAoB,kBAAkB;;;;WAI5C;;;;WAIA,QAAQ;;;;WAIR,OAAO;;;;;UAMD;;;;;;WAMN,SAAS,oBAAoB;;;;;;WAM7B,SAAS;;;;;;;;WAQT;;;;;;;;;KAUC,eAAe;;;;EAKrB;;;;EAIA,OAAO;;;;;EAMP;;;;;EAKA,OAAO,aAAa;;;;EAIpB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zap-studio/retry",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "private": false,
5
5
  "description": "Composable retry policies for resilient async operations.",
6
6
  "keywords": [
@@ -50,16 +50,15 @@
50
50
  "exponential-backoff": "^3.1.3",
51
51
  "p-retry": "^8.0.0",
52
52
  "promise-retry": "^2.0.1",
53
- "typescript": "^6.0.3",
54
- "vite-plus": "^0.1.19",
53
+ "tsdown": "^0.22.4",
54
+ "typescript": "^7.0.2",
55
+ "vitest": "^4.1.10",
55
56
  "@zap-studio/typescript": "0.0.0"
56
57
  },
57
58
  "engines": {
58
59
  "node": ">=18.0.0"
59
60
  },
60
61
  "scripts": {
61
- "build": "vp pack",
62
- "test": "vp test run",
63
- "test:watch": "vp test watch"
62
+ "build": "tsdown --config ./tsdown.config.ts"
64
63
  }
65
64
  }
@@ -1,76 +0,0 @@
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
@@ -1 +0,0 @@
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"}