@zap-studio/retry 0.3.0 → 0.3.2
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/CHANGELOG.md +15 -0
- package/LICENSE +1 -1
- package/README.md +28 -17
- package/dist/abort.d.ts +29 -0
- package/dist/abort.d.ts.map +1 -0
- package/dist/{abort.mjs → abort.js} +17 -17
- package/dist/abort.js.map +1 -0
- package/dist/base-policy-Dn3TOJd3.js +248 -0
- package/dist/base-policy-Dn3TOJd3.js.map +1 -0
- package/dist/base-policy.d.ts +59 -0
- package/dist/base-policy.d.ts.map +1 -0
- package/dist/base-policy.js +2 -0
- package/dist/errors-BVZjP1Q5.d.ts +76 -0
- package/dist/errors-BVZjP1Q5.d.ts.map +1 -0
- package/dist/{errors.d.mts → errors.d.ts} +1 -1
- package/dist/{errors.mjs → errors.js} +1 -1
- package/dist/errors.js.map +1 -0
- package/dist/exponential-backoff.d.ts +55 -0
- package/dist/exponential-backoff.d.ts.map +1 -0
- package/dist/{exponential-backoff.mjs → exponential-backoff.js} +6 -6
- package/dist/exponential-backoff.js.map +1 -0
- package/dist/fixed-delay.d.ts +46 -0
- package/dist/fixed-delay.d.ts.map +1 -0
- package/dist/{fixed-delay.mjs → fixed-delay.js} +6 -6
- package/dist/fixed-delay.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +7 -0
- package/dist/sleep.d.ts +17 -0
- package/dist/sleep.d.ts.map +1 -0
- package/dist/{sleep.mjs → sleep.js} +6 -4
- package/dist/sleep.js.map +1 -0
- package/dist/types.d.ts +143 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +0 -0
- package/package.json +15 -26
- package/dist/abort.d.mts +0 -30
- package/dist/abort.d.mts.map +0 -1
- package/dist/abort.mjs.map +0 -1
- package/dist/errors-fWo_KyVO.d.mts +0 -76
- package/dist/errors-fWo_KyVO.d.mts.map +0 -1
- package/dist/errors.mjs.map +0 -1
- package/dist/exponential-backoff.d.mts +0 -56
- package/dist/exponential-backoff.d.mts.map +0 -1
- package/dist/exponential-backoff.mjs.map +0 -1
- package/dist/fixed-delay.d.mts +0 -47
- package/dist/fixed-delay.d.mts.map +0 -1
- package/dist/fixed-delay.mjs.map +0 -1
- package/dist/index.d.mts +0 -60
- package/dist/index.d.mts.map +0 -1
- package/dist/index.mjs +0 -63
- package/dist/index.mjs.map +0 -1
- package/dist/result-mode.d.mts +0 -24
- package/dist/result-mode.d.mts.map +0 -1
- package/dist/result-mode.mjs +0 -145
- package/dist/result-mode.mjs.map +0 -1
- package/dist/sleep.d.mts +0 -17
- package/dist/sleep.d.mts.map +0 -1
- package/dist/sleep.mjs.map +0 -1
- package/dist/throw-mode.d.mts +0 -26
- package/dist/throw-mode.d.mts.map +0 -1
- package/dist/throw-mode.mjs +0 -50
- package/dist/throw-mode.mjs.map +0 -1
- package/dist/types.d.mts +0 -145
- package/dist/types.d.mts.map +0 -1
- package/dist/types.mjs +0 -1
|
@@ -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-BVZjP1Q5.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors-BVZjP1Q5.d.ts","names":[],"sources":["../src/errors.ts"],"mappings":";;;;;;;;;UAWiB;;;;WAIN;;;;WAIA;;;;WAIA;;;;;UAMM;;;;WAIN;;;;;;;;;;;cAYE,mBAAmB;;;;WAId;;;;WAIA;;;;WAIA;;;;EAKhB,YAAY,iBAAiB,SAAS;;;;;cAY3B,mBAAmB;;;;oBAIL;;;;;EAMzB,YAAY,iBAAiB,UAAS"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { i as RetryErrorContext, n as AbortErrorContext, r as RetryError, t as AbortError } from "./errors-
|
|
1
|
+
import { i as RetryErrorContext, n as AbortErrorContext, r as RetryError, t as AbortError } from "./errors-BVZjP1Q5.js";
|
|
2
2
|
export { AbortError, AbortErrorContext, RetryError, RetryErrorContext };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","names":[],"sources":["../src/errors.ts"],"sourcesContent":["// oxlint-disable max-classes-per-file -- Public retry error types are intentionally colocated.\n\n/**\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":";;;;;;;;;;AA6CA,IAAa,aAAb,cAAgC,MAAM;;;;CAIpC;;;;CAIA;;;;CAIA;;;;CAKA,YAAY,SAAiB,SAA4B;EACvD,MAAM,OAAO;EACb,KAAK,OAAO;EACZ,KAAK,WAAW,QAAQ;EACxB,KAAK,YAAY,QAAQ;EACzB,KAAK,WAAW,QAAQ;CAC1B;AACF;;;;AAKA,IAAa,aAAb,cAAgC,MAAM;;;;CAIpC;;;;;CAMA,YAAY,SAAiB,UAA6B,CAAC,GAAG;EAC5D,MAAM,OAAO;EACb,KAAK,OAAO;EACZ,KAAK,QAAQ,QAAQ;CACvB;AACF"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { RetryDecision, RetryDecisionInput } from "./types.js";
|
|
2
|
+
import { BaseRetryPolicy } from "./base-policy.js";
|
|
3
|
+
//#region src/exponential-backoff.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Configuration for `ExponentialBackoff`.
|
|
6
|
+
*/
|
|
7
|
+
interface ExponentialBackoffOptions {
|
|
8
|
+
/**
|
|
9
|
+
* Maximum number of attempts (including the first) before giving up.
|
|
10
|
+
*/
|
|
11
|
+
maxAttempts: number;
|
|
12
|
+
/**
|
|
13
|
+
* Initial delay in milliseconds, doubled each retry until capped.
|
|
14
|
+
*/
|
|
15
|
+
baseDelayMs: number;
|
|
16
|
+
/**
|
|
17
|
+
* Hard upper bound in milliseconds for computed exponential delay.
|
|
18
|
+
*/
|
|
19
|
+
maxDelayMs: number;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Retries with exponential delay growth up to a max cap.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* const policy = new ExponentialBackoff({
|
|
26
|
+
* maxAttempts: 5,
|
|
27
|
+
* baseDelayMs: 100,
|
|
28
|
+
* maxDelayMs: 2_000,
|
|
29
|
+
* });
|
|
30
|
+
*/
|
|
31
|
+
declare class ExponentialBackoff extends BaseRetryPolicy {
|
|
32
|
+
/**
|
|
33
|
+
* Maximum number of attempts before the policy returns `max-attempts-reached`.
|
|
34
|
+
*/
|
|
35
|
+
private readonly maxAttempts;
|
|
36
|
+
/**
|
|
37
|
+
* Base delay in milliseconds used in `baseDelayMs * 2 ** (attempt - 1)`.
|
|
38
|
+
*/
|
|
39
|
+
private readonly baseDelayMs;
|
|
40
|
+
/**
|
|
41
|
+
* Upper cap for computed delay, applied with `Math.min`.
|
|
42
|
+
*/
|
|
43
|
+
private readonly maxDelayMs;
|
|
44
|
+
/**
|
|
45
|
+
* Creates an exponential backoff retry policy.
|
|
46
|
+
*/
|
|
47
|
+
constructor(options: ExponentialBackoffOptions);
|
|
48
|
+
/**
|
|
49
|
+
* Computes retry decision for the current attempt.
|
|
50
|
+
*/
|
|
51
|
+
next(input: RetryDecisionInput): RetryDecision;
|
|
52
|
+
}
|
|
53
|
+
//#endregion
|
|
54
|
+
export { ExponentialBackoff, ExponentialBackoffOptions };
|
|
55
|
+
//# sourceMappingURL=exponential-backoff.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exponential-backoff.d.ts","names":[],"sources":["../src/exponential-backoff.ts"],"mappings":";;;;;;UAYiB;;;;EAIf;;;;EAIA;;;;EAIA;;;;;;;;;;;;cAaW,2BAA2B;;;;mBAIrB;;;;mBAIA;;;;mBAIA;;;;EAKjB,YAAY,SAAS;;;;EAUrB,KAAY,OAAO,qBAAqB"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BaseRetryPolicy } from "./
|
|
1
|
+
import { t as BaseRetryPolicy } from "./base-policy-Dn3TOJd3.js";
|
|
2
2
|
//#region src/exponential-backoff.ts
|
|
3
3
|
/**
|
|
4
4
|
* Exponential backoff retry strategy.
|
|
@@ -42,19 +42,19 @@ var ExponentialBackoff = class extends BaseRetryPolicy {
|
|
|
42
42
|
*/
|
|
43
43
|
next(input) {
|
|
44
44
|
if (input.attempt >= this.maxAttempts) return {
|
|
45
|
-
shouldRetry: false,
|
|
46
45
|
delayMs: 0,
|
|
47
|
-
reason: "max-attempts-reached"
|
|
46
|
+
reason: "max-attempts-reached",
|
|
47
|
+
shouldRetry: false
|
|
48
48
|
};
|
|
49
49
|
const exponent = Math.max(0, input.attempt - 1);
|
|
50
50
|
return {
|
|
51
|
-
shouldRetry: true,
|
|
52
51
|
delayMs: Math.min(this.maxDelayMs, this.baseDelayMs * 2 ** exponent),
|
|
53
|
-
reason: "retry"
|
|
52
|
+
reason: "retry",
|
|
53
|
+
shouldRetry: true
|
|
54
54
|
};
|
|
55
55
|
}
|
|
56
56
|
};
|
|
57
57
|
//#endregion
|
|
58
58
|
export { ExponentialBackoff };
|
|
59
59
|
|
|
60
|
-
//# sourceMappingURL=exponential-backoff.
|
|
60
|
+
//# sourceMappingURL=exponential-backoff.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exponential-backoff.js","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 \"./base-policy.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 { delayMs: 0, reason: \"max-attempts-reached\", shouldRetry: false };\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 { delayMs, reason: \"retry\", shouldRetry: true };\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAqCA,IAAa,qBAAb,cAAwC,gBAAgB;;;;CAItD;;;;CAIA;;;;CAIA;;;;CAKA,YAAY,SAAoC;EAC9C,MAAM;EACN,KAAK,cAAc,QAAQ;EAC3B,KAAK,cAAc,QAAQ;EAC3B,KAAK,aAAa,QAAQ;CAC5B;;;;CAKA,KAAY,OAA0C;EACpD,IAAI,MAAM,WAAW,KAAK,aACxB,OAAO;GAAE,SAAS;GAAG,QAAQ;GAAwB,aAAa;EAAM;EAG1E,MAAM,WAAW,KAAK,IAAI,GAAG,MAAM,UAAU,CAAC;EAG9C,OAAO;GAAE,SAFO,KAAK,IAAI,KAAK,YAAY,KAAK,cAAc,KAAK,QAEnD;GAAG,QAAQ;GAAS,aAAa;EAAK;CACvD;AACF"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { RetryDecision, RetryDecisionInput } from "./types.js";
|
|
2
|
+
import { BaseRetryPolicy } from "./base-policy.js";
|
|
3
|
+
//#region src/fixed-delay.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Configuration for `FixedDelay`.
|
|
6
|
+
*/
|
|
7
|
+
interface FixedDelayOptions {
|
|
8
|
+
/**
|
|
9
|
+
* Maximum number of attempts (including the first) before giving up.
|
|
10
|
+
*/
|
|
11
|
+
maxAttempts: number;
|
|
12
|
+
/**
|
|
13
|
+
* Constant delay in milliseconds before each retry after a failure.
|
|
14
|
+
*/
|
|
15
|
+
delayMs: number;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Retries with a constant delay between attempts.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* const policy = new FixedDelay({
|
|
22
|
+
* maxAttempts: 3,
|
|
23
|
+
* delayMs: 250,
|
|
24
|
+
* });
|
|
25
|
+
*/
|
|
26
|
+
declare class FixedDelay extends BaseRetryPolicy {
|
|
27
|
+
/**
|
|
28
|
+
* Maximum number of attempts before the policy returns `max-attempts-reached`.
|
|
29
|
+
*/
|
|
30
|
+
private readonly maxAttempts;
|
|
31
|
+
/**
|
|
32
|
+
* Constant delay in milliseconds before each subsequent attempt.
|
|
33
|
+
*/
|
|
34
|
+
private readonly delayMs;
|
|
35
|
+
/**
|
|
36
|
+
* Creates a fixed-delay retry policy.
|
|
37
|
+
*/
|
|
38
|
+
constructor(options: FixedDelayOptions);
|
|
39
|
+
/**
|
|
40
|
+
* Computes retry decision for the current attempt.
|
|
41
|
+
*/
|
|
42
|
+
next(input: RetryDecisionInput): RetryDecision;
|
|
43
|
+
}
|
|
44
|
+
//#endregion
|
|
45
|
+
export { FixedDelay, FixedDelayOptions };
|
|
46
|
+
//# sourceMappingURL=fixed-delay.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fixed-delay.d.ts","names":[],"sources":["../src/fixed-delay.ts"],"mappings":";;;;;;UAYiB;;;;EAIf;;;;EAIA;;;;;;;;;;;cAYW,mBAAmB;;;;mBAIb;;;;mBAIA;;;;EAKjB,YAAY,SAAS;;;;EASrB,KAAY,OAAO,qBAAqB"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BaseRetryPolicy } from "./
|
|
1
|
+
import { t as BaseRetryPolicy } from "./base-policy-Dn3TOJd3.js";
|
|
2
2
|
//#region src/fixed-delay.ts
|
|
3
3
|
/**
|
|
4
4
|
* Fixed-delay retry strategy.
|
|
@@ -36,18 +36,18 @@ var FixedDelay = class extends BaseRetryPolicy {
|
|
|
36
36
|
*/
|
|
37
37
|
next(input) {
|
|
38
38
|
if (input.attempt >= this.maxAttempts) return {
|
|
39
|
-
shouldRetry: false,
|
|
40
39
|
delayMs: 0,
|
|
41
|
-
reason: "max-attempts-reached"
|
|
40
|
+
reason: "max-attempts-reached",
|
|
41
|
+
shouldRetry: false
|
|
42
42
|
};
|
|
43
43
|
return {
|
|
44
|
-
shouldRetry: true,
|
|
45
44
|
delayMs: this.delayMs,
|
|
46
|
-
reason: "retry"
|
|
45
|
+
reason: "retry",
|
|
46
|
+
shouldRetry: true
|
|
47
47
|
};
|
|
48
48
|
}
|
|
49
49
|
};
|
|
50
50
|
//#endregion
|
|
51
51
|
export { FixedDelay };
|
|
52
52
|
|
|
53
|
-
//# sourceMappingURL=fixed-delay.
|
|
53
|
+
//# sourceMappingURL=fixed-delay.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fixed-delay.js","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 \"./base-policy.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 { delayMs: 0, reason: \"max-attempts-reached\", shouldRetry: false };\n }\n\n return { delayMs: this.delayMs, reason: \"retry\", shouldRetry: true };\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAgCA,IAAa,aAAb,cAAgC,gBAAgB;;;;CAI9C;;;;CAIA;;;;CAKA,YAAY,SAA4B;EACtC,MAAM;EACN,KAAK,cAAc,QAAQ;EAC3B,KAAK,UAAU,QAAQ;CACzB;;;;CAKA,KAAY,OAA0C;EACpD,IAAI,MAAM,WAAW,KAAK,aACxB,OAAO;GAAE,SAAS;GAAG,QAAQ;GAAwB,aAAa;EAAM;EAG1E,OAAO;GAAE,SAAS,KAAK;GAAS,QAAQ;GAAS,aAAa;EAAK;CACrE;AACF"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { i as RetryErrorContext, n as AbortErrorContext, r as RetryError, t as AbortError } from "./errors-BVZjP1Q5.js";
|
|
2
|
+
import { sleepWithAbortSignal, throwIfAborted, toAbortError } from "./abort.js";
|
|
3
|
+
import { RetryDecision, RetryDecisionInput, RetryExhaustedInput, RetryPolicy, RetryRunOptions, RetryRunResult } from "./types.js";
|
|
4
|
+
import { BaseRetryPolicy } from "./base-policy.js";
|
|
5
|
+
import { ExponentialBackoff, ExponentialBackoffOptions } from "./exponential-backoff.js";
|
|
6
|
+
import { FixedDelay, FixedDelayOptions } from "./fixed-delay.js";
|
|
7
|
+
import { defaultSleep } from "./sleep.js";
|
|
8
|
+
export { AbortError, type AbortErrorContext, BaseRetryPolicy, ExponentialBackoff, type ExponentialBackoffOptions, FixedDelay, type FixedDelayOptions, type RetryDecision, type RetryDecisionInput, RetryError, type RetryErrorContext, type RetryExhaustedInput, type RetryPolicy, type RetryRunOptions, type RetryRunResult, defaultSleep, sleepWithAbortSignal, throwIfAborted, toAbortError };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { AbortError, RetryError } from "./errors.js";
|
|
2
|
+
import { sleepWithAbortSignal, throwIfAborted, toAbortError } from "./abort.js";
|
|
3
|
+
import { t as BaseRetryPolicy } from "./base-policy-Dn3TOJd3.js";
|
|
4
|
+
import { defaultSleep } from "./sleep.js";
|
|
5
|
+
import { ExponentialBackoff } from "./exponential-backoff.js";
|
|
6
|
+
import { FixedDelay } from "./fixed-delay.js";
|
|
7
|
+
export { AbortError, BaseRetryPolicy, ExponentialBackoff, FixedDelay, RetryError, defaultSleep, sleepWithAbortSignal, throwIfAborted, toAbortError };
|
package/dist/sleep.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
//#region src/sleep.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Default delay implementation used by `BaseRetryPolicy.run` when no custom
|
|
4
|
+
* `sleep` is provided.
|
|
5
|
+
*
|
|
6
|
+
* @module @zap-studio/retry/sleep
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Awaits a timer-based delay, unless `delayMs` is non-positive.
|
|
10
|
+
*
|
|
11
|
+
* @param delayMs - Milliseconds to wait before resolving.
|
|
12
|
+
* @returns Promise that resolves when the delay completes.
|
|
13
|
+
*/
|
|
14
|
+
declare const defaultSleep: (delayMs: number) => Promise<void>;
|
|
15
|
+
//#endregion
|
|
16
|
+
export { defaultSleep };
|
|
17
|
+
//# sourceMappingURL=sleep.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sleep.d.ts","names":[],"sources":["../src/sleep.ts"],"mappings":";;;;;;;;;;;;;cAaa,eAAsB,oBAAkB"}
|
|
@@ -11,11 +11,13 @@
|
|
|
11
11
|
* @param delayMs - Milliseconds to wait before resolving.
|
|
12
12
|
* @returns Promise that resolves when the delay completes.
|
|
13
13
|
*/
|
|
14
|
-
async
|
|
14
|
+
const defaultSleep = async (delayMs) => {
|
|
15
15
|
if (delayMs <= 0) return;
|
|
16
|
-
await new Promise((resolve) =>
|
|
17
|
-
|
|
16
|
+
await new Promise((resolve) => {
|
|
17
|
+
setTimeout(resolve, delayMs);
|
|
18
|
+
});
|
|
19
|
+
};
|
|
18
20
|
//#endregion
|
|
19
21
|
export { defaultSleep };
|
|
20
22
|
|
|
21
|
-
//# sourceMappingURL=sleep.
|
|
23
|
+
//# sourceMappingURL=sleep.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sleep.js","names":[],"sources":["../src/sleep.ts"],"sourcesContent":["/**\n * Default delay implementation used by `BaseRetryPolicy.run` when no custom\n * `sleep` is provided.\n *\n * @module @zap-studio/retry/sleep\n */\n\n/**\n * Awaits a timer-based delay, unless `delayMs` is non-positive.\n *\n * @param delayMs - Milliseconds to wait before resolving.\n * @returns Promise that resolves when the delay completes.\n */\nexport const defaultSleep = async (delayMs: number): Promise<void> => {\n if (delayMs <= 0) {\n return;\n }\n\n // oxlint-disable-next-line promise/avoid-new -- Timer sleep requires adapting callback API to a promise.\n await new Promise<void>((resolve) => {\n setTimeout(resolve, delayMs);\n });\n};\n"],"mappings":";;;;;;;;;;;;;AAaA,MAAa,eAAe,OAAO,YAAmC;CACpE,IAAI,WAAW,GACb;CAIF,MAAM,IAAI,SAAe,YAAY;EACnC,WAAW,SAAS,OAAO;CAC7B,CAAC;AACH"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { r as RetryError, t as AbortError } from "./errors-BVZjP1Q5.js";
|
|
2
|
+
//#region src/types.d.ts
|
|
3
|
+
/**
|
|
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
|
+
*/
|
|
12
|
+
interface RetryPolicy<TError = unknown, TData = unknown> {
|
|
13
|
+
/**
|
|
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;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Decision returned by a retry policy for a specific attempt.
|
|
28
|
+
*/
|
|
29
|
+
interface RetryDecision {
|
|
30
|
+
/**
|
|
31
|
+
* When `true`, the runner may schedule another attempt (subject to
|
|
32
|
+
* `delayMs` and the runner's abort rules).
|
|
33
|
+
*/
|
|
34
|
+
readonly shouldRetry: boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Milliseconds to wait before the next attempt when `shouldRetry` is `true`.
|
|
37
|
+
*/
|
|
38
|
+
readonly delayMs: number;
|
|
39
|
+
/**
|
|
40
|
+
* Optional machine-readable reason for the decision.
|
|
41
|
+
*/
|
|
42
|
+
readonly reason?: "retry" | "max-attempts-reached" | "policy-declined";
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Input passed to `RetryPolicy.next(...)` for each failed attempt.
|
|
46
|
+
*/
|
|
47
|
+
interface RetryDecisionInput<TError = unknown, TData = unknown> {
|
|
48
|
+
/**
|
|
49
|
+
* One-based attempt number for the current failure.
|
|
50
|
+
*/
|
|
51
|
+
readonly attempt: number;
|
|
52
|
+
/**
|
|
53
|
+
* Optional policy-level maximum attempts, when a policy wants to pass it
|
|
54
|
+
* through to `next`.
|
|
55
|
+
*/
|
|
56
|
+
readonly maxAttempts?: number;
|
|
57
|
+
/**
|
|
58
|
+
* Error raised by the most recent `execute(attempt)` call, when a failure
|
|
59
|
+
* occurred.
|
|
60
|
+
*/
|
|
61
|
+
readonly error?: TError;
|
|
62
|
+
/**
|
|
63
|
+
* Optional data captured alongside the failure, when a policy populates
|
|
64
|
+
* it.
|
|
65
|
+
*/
|
|
66
|
+
readonly data?: TData;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Input passed to `RetryPolicy.onExhausted(...)` when retries stop.
|
|
70
|
+
*/
|
|
71
|
+
interface RetryExhaustedInput<TError = unknown, TData = unknown> {
|
|
72
|
+
/**
|
|
73
|
+
* Count of completed attempts that led to stopping retries.
|
|
74
|
+
*/
|
|
75
|
+
readonly attempts: number;
|
|
76
|
+
/**
|
|
77
|
+
* Last execution error, when available.
|
|
78
|
+
*/
|
|
79
|
+
readonly error?: TError;
|
|
80
|
+
/**
|
|
81
|
+
* Last captured data, when a policy or runner supplies it.
|
|
82
|
+
*/
|
|
83
|
+
readonly data?: TData;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Options for `BaseRetryPolicy.run(...)`.
|
|
87
|
+
*/
|
|
88
|
+
interface RetryRunOptions {
|
|
89
|
+
/**
|
|
90
|
+
* Delay function used between retry attempts.
|
|
91
|
+
*
|
|
92
|
+
* @throws {Error} Any error thrown or rejected by the custom delay implementation.
|
|
93
|
+
*/
|
|
94
|
+
readonly sleep?: (delayMs: number) => Promise<void>;
|
|
95
|
+
/**
|
|
96
|
+
* Abort signal used to cancel retry orchestration.
|
|
97
|
+
*
|
|
98
|
+
* When aborted, the runner stops retrying and terminates immediately.
|
|
99
|
+
*/
|
|
100
|
+
readonly signal?: AbortSignal;
|
|
101
|
+
/**
|
|
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
|
+
*/
|
|
108
|
+
readonly throwOnExhausted?: boolean;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
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
|
+
*/
|
|
117
|
+
type RetryRunResult<T> = {
|
|
118
|
+
/**
|
|
119
|
+
* Discriminator for a successful run.
|
|
120
|
+
*/
|
|
121
|
+
ok: true;
|
|
122
|
+
/**
|
|
123
|
+
* Successful return value from the final attempt.
|
|
124
|
+
*/
|
|
125
|
+
value: T;
|
|
126
|
+
} | {
|
|
127
|
+
/**
|
|
128
|
+
* Discriminator for a failed or aborted run.
|
|
129
|
+
*/
|
|
130
|
+
ok: false;
|
|
131
|
+
/**
|
|
132
|
+
* Terminal error: `RetryError` when retries are exhausted, or
|
|
133
|
+
* `AbortError` when the run is canceled.
|
|
134
|
+
*/
|
|
135
|
+
error: RetryError | AbortError;
|
|
136
|
+
/**
|
|
137
|
+
* Number of attempts that completed before the terminal outcome.
|
|
138
|
+
*/
|
|
139
|
+
attempts: number;
|
|
140
|
+
};
|
|
141
|
+
//#endregion
|
|
142
|
+
export { RetryDecision, RetryDecisionInput, RetryExhaustedInput, RetryPolicy, RetryRunOptions, RetryRunResult };
|
|
143
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","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/dist/types.js
ADDED
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zap-studio/retry",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.2",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Composable retry policies for resilient async operations.",
|
|
6
6
|
"keywords": [
|
|
@@ -27,39 +27,28 @@
|
|
|
27
27
|
],
|
|
28
28
|
"type": "module",
|
|
29
29
|
"sideEffects": false,
|
|
30
|
-
"types": "./dist/index.d.
|
|
30
|
+
"types": "./dist/index.d.ts",
|
|
31
31
|
"exports": {
|
|
32
|
-
".": "./dist/index.
|
|
33
|
-
"./abort": "./dist/abort.
|
|
34
|
-
"./
|
|
35
|
-
"./
|
|
36
|
-
"./
|
|
37
|
-
"./
|
|
38
|
-
"./sleep": "./dist/sleep.
|
|
39
|
-
"./
|
|
40
|
-
"./types": "./dist/types.mjs",
|
|
32
|
+
".": "./dist/index.js",
|
|
33
|
+
"./abort": "./dist/abort.js",
|
|
34
|
+
"./base-policy": "./dist/base-policy.js",
|
|
35
|
+
"./errors": "./dist/errors.js",
|
|
36
|
+
"./exponential-backoff": "./dist/exponential-backoff.js",
|
|
37
|
+
"./fixed-delay": "./dist/fixed-delay.js",
|
|
38
|
+
"./sleep": "./dist/sleep.js",
|
|
39
|
+
"./types": "./dist/types.js",
|
|
41
40
|
"./package.json": "./package.json"
|
|
42
41
|
},
|
|
43
42
|
"publishConfig": {
|
|
44
43
|
"access": "public"
|
|
45
44
|
},
|
|
46
45
|
"devDependencies": {
|
|
47
|
-
"@
|
|
48
|
-
"
|
|
49
|
-
"
|
|
50
|
-
"
|
|
51
|
-
"p-retry": "^8.0.0",
|
|
52
|
-
"promise-retry": "^2.0.1",
|
|
53
|
-
"typescript": "^6.0.3",
|
|
54
|
-
"vite-plus": "^0.1.19",
|
|
55
|
-
"@zap-studio/typescript": "0.0.0"
|
|
46
|
+
"@zap-studio/typescript": "workspace:*",
|
|
47
|
+
"tsdown": "catalog:",
|
|
48
|
+
"typescript": "catalog:",
|
|
49
|
+
"vitest": "catalog:"
|
|
56
50
|
},
|
|
57
51
|
"engines": {
|
|
58
52
|
"node": ">=18.0.0"
|
|
59
|
-
},
|
|
60
|
-
"scripts": {
|
|
61
|
-
"build": "vp pack",
|
|
62
|
-
"test": "vp test run",
|
|
63
|
-
"test:watch": "vp test watch"
|
|
64
53
|
}
|
|
65
|
-
}
|
|
54
|
+
}
|
package/dist/abort.d.mts
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
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
|
package/dist/abort.d.mts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
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.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
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"}
|