bytekit 1.0.21 → 1.0.23
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/bin/{sutils.js → bytekit.js} +2 -4
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +104 -474
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/swagger-generator.d.ts +9 -0
- package/dist/cli/swagger-generator.d.ts.map +1 -0
- package/dist/cli/swagger-generator.js +149 -0
- package/dist/cli/swagger-generator.js.map +1 -0
- package/dist/cli/type-generator.d.ts +1 -0
- package/dist/cli/type-generator.d.ts.map +1 -1
- package/dist/cli/type-generator.js +2 -1
- package/dist/cli/type-generator.js.map +1 -1
- package/dist/utils/async/allSettled.d.ts +27 -0
- package/dist/utils/async/allSettled.d.ts.map +1 -0
- package/dist/utils/async/allSettled.js +45 -0
- package/dist/utils/async/allSettled.js.map +1 -0
- package/dist/utils/async/debounce.d.ts +24 -0
- package/dist/utils/async/debounce.d.ts.map +1 -0
- package/dist/utils/async/debounce.js +138 -0
- package/dist/utils/async/debounce.js.map +1 -0
- package/dist/utils/async/errors.d.ts +22 -0
- package/dist/utils/async/errors.d.ts.map +1 -0
- package/dist/utils/async/errors.js +58 -0
- package/dist/utils/async/errors.js.map +1 -0
- package/dist/utils/async/index.d.ts +19 -0
- package/dist/utils/async/index.d.ts.map +1 -0
- package/dist/utils/async/index.js +20 -0
- package/dist/utils/async/index.js.map +1 -0
- package/dist/utils/async/parallel.d.ts +24 -0
- package/dist/utils/async/parallel.d.ts.map +1 -0
- package/dist/utils/async/parallel.js +98 -0
- package/dist/utils/async/parallel.js.map +1 -0
- package/dist/utils/async/race.d.ts +37 -0
- package/dist/utils/async/race.d.ts.map +1 -0
- package/dist/utils/async/race.js +69 -0
- package/dist/utils/async/race.js.map +1 -0
- package/dist/utils/async/retry.d.ts +34 -0
- package/dist/utils/async/retry.d.ts.map +1 -0
- package/dist/utils/async/retry.js +118 -0
- package/dist/utils/async/retry.js.map +1 -0
- package/dist/utils/async/sequential.d.ts +28 -0
- package/dist/utils/async/sequential.d.ts.map +1 -0
- package/dist/utils/async/sequential.js +66 -0
- package/dist/utils/async/sequential.js.map +1 -0
- package/dist/utils/async/sleep.d.ts +28 -0
- package/dist/utils/async/sleep.d.ts.map +1 -0
- package/dist/utils/async/sleep.js +64 -0
- package/dist/utils/async/sleep.js.map +1 -0
- package/dist/utils/async/throttle.d.ts +24 -0
- package/dist/utils/async/throttle.d.ts.map +1 -0
- package/dist/utils/async/throttle.js +118 -0
- package/dist/utils/async/throttle.js.map +1 -0
- package/dist/utils/async/timeout.d.ts +45 -0
- package/dist/utils/async/timeout.d.ts.map +1 -0
- package/dist/utils/async/timeout.js +75 -0
- package/dist/utils/async/timeout.js.map +1 -0
- package/dist/utils/async/types.d.ts +105 -0
- package/dist/utils/async/types.d.ts.map +1 -0
- package/dist/utils/async/types.js +5 -0
- package/dist/utils/async/types.js.map +1 -0
- package/dist/utils/core/ApiClient.d.ts.map +1 -1
- package/dist/utils/core/ApiClient.js +28 -9
- package/dist/utils/core/ApiClient.js.map +1 -1
- package/dist/utils/core/RetryPolicy.d.ts +7 -0
- package/dist/utils/core/RetryPolicy.d.ts.map +1 -1
- package/dist/utils/core/RetryPolicy.js +9 -0
- package/dist/utils/core/RetryPolicy.js.map +1 -1
- package/dist/utils/helpers/ObjectUtils.d.ts +2 -2
- package/dist/utils/helpers/ObjectUtils.d.ts.map +1 -1
- package/dist/utils/helpers/ObjectUtils.js +4 -0
- package/dist/utils/helpers/ObjectUtils.js.map +1 -1
- package/dist/utils/helpers/index.d.ts +1 -0
- package/dist/utils/helpers/index.d.ts.map +1 -1
- package/dist/utils/helpers/index.js +1 -0
- package/dist/utils/helpers/index.js.map +1 -1
- package/package.json +250 -249
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AsyncUtils Module
|
|
3
|
+
*
|
|
4
|
+
* Comprehensive utilities for managing asynchronous operations in TypeScript.
|
|
5
|
+
* Provides Promise-based utilities for delays, timeouts, retries, parallel/sequential
|
|
6
|
+
* execution, and rate limiting with zero dependencies.
|
|
7
|
+
*/
|
|
8
|
+
export { TimeoutError, AbortError, RetryError } from "./errors.js";
|
|
9
|
+
export type { BackoffStrategy, Task, SequentialTask, AsyncFunction, RetryOptions, ParallelOptions, SequentialOptions, AllSettledResult, DebounceOptions, DebouncedFunction, ThrottleOptions, ThrottledFunction, } from "./types.js";
|
|
10
|
+
export { sleep } from "./sleep.js";
|
|
11
|
+
export { timeout, withTimeout } from "./timeout.js";
|
|
12
|
+
export { retry } from "./retry.js";
|
|
13
|
+
export { parallel } from "./parallel.js";
|
|
14
|
+
export { sequential } from "./sequential.js";
|
|
15
|
+
export { race } from "./race.js";
|
|
16
|
+
export { allSettled } from "./allSettled.js";
|
|
17
|
+
export { debounceAsync } from "./debounce.js";
|
|
18
|
+
export { throttleAsync } from "./throttle.js";
|
|
19
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/utils/async/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAGnE,YAAY,EACR,eAAe,EACf,IAAI,EACJ,cAAc,EACd,aAAa,EACb,YAAY,EACZ,eAAe,EACf,iBAAiB,EACjB,gBAAgB,EAChB,eAAe,EACf,iBAAiB,EACjB,eAAe,EACf,iBAAiB,GACpB,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AsyncUtils Module
|
|
3
|
+
*
|
|
4
|
+
* Comprehensive utilities for managing asynchronous operations in TypeScript.
|
|
5
|
+
* Provides Promise-based utilities for delays, timeouts, retries, parallel/sequential
|
|
6
|
+
* execution, and rate limiting with zero dependencies.
|
|
7
|
+
*/
|
|
8
|
+
// Export error classes
|
|
9
|
+
export { TimeoutError, AbortError, RetryError } from "./errors.js";
|
|
10
|
+
// Utility functions will be exported as they are implemented
|
|
11
|
+
export { sleep } from "./sleep.js";
|
|
12
|
+
export { timeout, withTimeout } from "./timeout.js";
|
|
13
|
+
export { retry } from "./retry.js";
|
|
14
|
+
export { parallel } from "./parallel.js";
|
|
15
|
+
export { sequential } from "./sequential.js";
|
|
16
|
+
export { race } from "./race.js";
|
|
17
|
+
export { allSettled } from "./allSettled.js";
|
|
18
|
+
export { debounceAsync } from "./debounce.js";
|
|
19
|
+
export { throttleAsync } from "./throttle.js";
|
|
20
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/utils/async/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,uBAAuB;AACvB,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAkBnE,6DAA6D;AAC7D,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Task, ParallelOptions } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Execute multiple async tasks in parallel with optional concurrency control
|
|
4
|
+
*
|
|
5
|
+
* @param tasks - Array of async task functions to execute
|
|
6
|
+
* @param options - Optional configuration for concurrency control
|
|
7
|
+
* @returns Promise that resolves with array of results in original order
|
|
8
|
+
* @throws First error encountered if any task fails
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* // Unlimited concurrency
|
|
13
|
+
* const results = await parallel([
|
|
14
|
+
* () => fetchUser(1),
|
|
15
|
+
* () => fetchUser(2),
|
|
16
|
+
* () => fetchUser(3)
|
|
17
|
+
* ]);
|
|
18
|
+
*
|
|
19
|
+
* // Limited concurrency
|
|
20
|
+
* const results = await parallel(tasks, { concurrency: 2 });
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export declare function parallel<T>(tasks: Array<Task<T>>, options?: ParallelOptions): Promise<T[]>;
|
|
24
|
+
//# sourceMappingURL=parallel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parallel.d.ts","sourceRoot":"","sources":["../../../src/utils/async/parallel.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAExD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,QAAQ,CAAC,CAAC,EAC5B,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EACrB,OAAO,CAAC,EAAE,eAAe,GAC1B,OAAO,CAAC,CAAC,EAAE,CAAC,CAqCd"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Execute multiple async tasks in parallel with optional concurrency control
|
|
3
|
+
*
|
|
4
|
+
* @param tasks - Array of async task functions to execute
|
|
5
|
+
* @param options - Optional configuration for concurrency control
|
|
6
|
+
* @returns Promise that resolves with array of results in original order
|
|
7
|
+
* @throws First error encountered if any task fails
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```typescript
|
|
11
|
+
* // Unlimited concurrency
|
|
12
|
+
* const results = await parallel([
|
|
13
|
+
* () => fetchUser(1),
|
|
14
|
+
* () => fetchUser(2),
|
|
15
|
+
* () => fetchUser(3)
|
|
16
|
+
* ]);
|
|
17
|
+
*
|
|
18
|
+
* // Limited concurrency
|
|
19
|
+
* const results = await parallel(tasks, { concurrency: 2 });
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export async function parallel(tasks, options) {
|
|
23
|
+
// Validate input
|
|
24
|
+
if (!Array.isArray(tasks)) {
|
|
25
|
+
throw new TypeError("tasks must be an array");
|
|
26
|
+
}
|
|
27
|
+
// Handle empty array
|
|
28
|
+
if (tasks.length === 0) {
|
|
29
|
+
return [];
|
|
30
|
+
}
|
|
31
|
+
// Validate all tasks are functions
|
|
32
|
+
for (let i = 0; i < tasks.length; i++) {
|
|
33
|
+
if (typeof tasks[i] !== "function") {
|
|
34
|
+
throw new TypeError(`Task at index ${i} is not a function`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
const concurrency = options?.concurrency;
|
|
38
|
+
// Validate concurrency if provided
|
|
39
|
+
if (concurrency !== undefined) {
|
|
40
|
+
if (typeof concurrency !== "number" || !Number.isInteger(concurrency)) {
|
|
41
|
+
throw new TypeError("concurrency must be an integer");
|
|
42
|
+
}
|
|
43
|
+
if (concurrency < 1) {
|
|
44
|
+
throw new TypeError("concurrency must be at least 1");
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
// If no concurrency limit, use Promise.all for maximum performance
|
|
48
|
+
if (concurrency === undefined) {
|
|
49
|
+
return Promise.all(tasks.map((task) => task()));
|
|
50
|
+
}
|
|
51
|
+
// Queue-based execution with concurrency limit
|
|
52
|
+
return executeWithConcurrencyLimit(tasks, concurrency);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Execute tasks with a concurrency limit using a queue-based approach
|
|
56
|
+
*/
|
|
57
|
+
async function executeWithConcurrencyLimit(tasks, concurrency) {
|
|
58
|
+
const results = new Array(tasks.length);
|
|
59
|
+
let nextIndex = 0;
|
|
60
|
+
let hasError = false;
|
|
61
|
+
let firstError = null;
|
|
62
|
+
// Worker function that processes tasks from the queue
|
|
63
|
+
const worker = async () => {
|
|
64
|
+
while (nextIndex < tasks.length && !hasError) {
|
|
65
|
+
const index = nextIndex++;
|
|
66
|
+
try {
|
|
67
|
+
const result = await tasks[index]();
|
|
68
|
+
// Only store result if no error has occurred
|
|
69
|
+
if (!hasError) {
|
|
70
|
+
results[index] = result;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
catch (err) {
|
|
74
|
+
// Store first error and set flag
|
|
75
|
+
if (!hasError) {
|
|
76
|
+
hasError = true;
|
|
77
|
+
firstError = err;
|
|
78
|
+
}
|
|
79
|
+
// Stop this worker
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
// Start workers up to concurrency limit
|
|
85
|
+
const workers = [];
|
|
86
|
+
const workerCount = Math.min(concurrency, tasks.length);
|
|
87
|
+
for (let i = 0; i < workerCount; i++) {
|
|
88
|
+
workers.push(worker());
|
|
89
|
+
}
|
|
90
|
+
// Wait for all workers to complete
|
|
91
|
+
await Promise.all(workers);
|
|
92
|
+
// If an error occurred, throw it
|
|
93
|
+
if (hasError) {
|
|
94
|
+
throw firstError;
|
|
95
|
+
}
|
|
96
|
+
return results;
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=parallel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parallel.js","sourceRoot":"","sources":["../../../src/utils/async/parallel.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enhanced Promise.race implementation with better error handling
|
|
3
|
+
*
|
|
4
|
+
* Unlike native Promise.race, this implementation:
|
|
5
|
+
* - Validates non-empty array input
|
|
6
|
+
* - Returns AggregateError when all promises reject
|
|
7
|
+
* - Tracks all promise settlements for comprehensive error reporting
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Race multiple promises and resolve/reject with the first settled promise.
|
|
11
|
+
* If all promises reject, rejects with an AggregateError containing all rejection reasons.
|
|
12
|
+
*
|
|
13
|
+
* @param promises - Array of promises to race
|
|
14
|
+
* @returns Promise that resolves/rejects with the first settled promise
|
|
15
|
+
* @throws TypeError if promises array is empty
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* // Resolves with the fastest promise
|
|
20
|
+
* const result = await race([
|
|
21
|
+
* fetch('/api/fast'),
|
|
22
|
+
* fetch('/api/slow')
|
|
23
|
+
* ]);
|
|
24
|
+
*
|
|
25
|
+
* // Rejects with AggregateError if all fail
|
|
26
|
+
* try {
|
|
27
|
+
* await race([
|
|
28
|
+
* Promise.reject('error 1'),
|
|
29
|
+
* Promise.reject('error 2')
|
|
30
|
+
* ]);
|
|
31
|
+
* } catch (error) {
|
|
32
|
+
* console.log(error.errors); // ['error 1', 'error 2']
|
|
33
|
+
* }
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export declare function race<T>(promises: Array<Promise<T>>): Promise<T>;
|
|
37
|
+
//# sourceMappingURL=race.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"race.d.ts","sourceRoot":"","sources":["../../../src/utils/async/race.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,IAAI,CAAC,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CA4C/D"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enhanced Promise.race implementation with better error handling
|
|
3
|
+
*
|
|
4
|
+
* Unlike native Promise.race, this implementation:
|
|
5
|
+
* - Validates non-empty array input
|
|
6
|
+
* - Returns AggregateError when all promises reject
|
|
7
|
+
* - Tracks all promise settlements for comprehensive error reporting
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Race multiple promises and resolve/reject with the first settled promise.
|
|
11
|
+
* If all promises reject, rejects with an AggregateError containing all rejection reasons.
|
|
12
|
+
*
|
|
13
|
+
* @param promises - Array of promises to race
|
|
14
|
+
* @returns Promise that resolves/rejects with the first settled promise
|
|
15
|
+
* @throws TypeError if promises array is empty
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* // Resolves with the fastest promise
|
|
20
|
+
* const result = await race([
|
|
21
|
+
* fetch('/api/fast'),
|
|
22
|
+
* fetch('/api/slow')
|
|
23
|
+
* ]);
|
|
24
|
+
*
|
|
25
|
+
* // Rejects with AggregateError if all fail
|
|
26
|
+
* try {
|
|
27
|
+
* await race([
|
|
28
|
+
* Promise.reject('error 1'),
|
|
29
|
+
* Promise.reject('error 2')
|
|
30
|
+
* ]);
|
|
31
|
+
* } catch (error) {
|
|
32
|
+
* console.log(error.errors); // ['error 1', 'error 2']
|
|
33
|
+
* }
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export function race(promises) {
|
|
37
|
+
// Validate non-empty array
|
|
38
|
+
if (!Array.isArray(promises)) {
|
|
39
|
+
throw new TypeError("Expected an array of promises");
|
|
40
|
+
}
|
|
41
|
+
if (promises.length === 0) {
|
|
42
|
+
throw new TypeError("Cannot race an empty array of promises");
|
|
43
|
+
}
|
|
44
|
+
// Use a custom implementation to support AggregateError when ALL reject
|
|
45
|
+
return new Promise((resolve, reject) => {
|
|
46
|
+
let rejectionCount = 0;
|
|
47
|
+
const errors = new Array(promises.length);
|
|
48
|
+
let settled = false;
|
|
49
|
+
promises.forEach((promise, index) => {
|
|
50
|
+
Promise.resolve(promise).then((value) => {
|
|
51
|
+
if (!settled) {
|
|
52
|
+
settled = true;
|
|
53
|
+
resolve(value);
|
|
54
|
+
}
|
|
55
|
+
}, (error) => {
|
|
56
|
+
errors[index] = error;
|
|
57
|
+
rejectionCount++;
|
|
58
|
+
// If all promises have rejected, reject with AggregateError
|
|
59
|
+
if (rejectionCount === promises.length) {
|
|
60
|
+
if (!settled) {
|
|
61
|
+
settled = true;
|
|
62
|
+
reject(new AggregateError(errors, `All ${promises.length} promises rejected`));
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=race.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"race.js","sourceRoot":"","sources":["../../../src/utils/async/race.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,UAAU,IAAI,CAAI,QAA2B;IAC/C,2BAA2B;IAC3B,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC3B,MAAM,IAAI,SAAS,CAAC,+BAA+B,CAAC,CAAC;IACzD,CAAC;IAED,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,SAAS,CAAC,wCAAwC,CAAC,CAAC;IAClE,CAAC;IAED,wEAAwE;IACxE,OAAO,IAAI,OAAO,CAAI,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACtC,IAAI,cAAc,GAAG,CAAC,CAAC;QACvB,MAAM,MAAM,GAAc,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QACrD,IAAI,OAAO,GAAG,KAAK,CAAC;QAEpB,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE;YAChC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,IAAI,CACzB,CAAC,KAAK,EAAE,EAAE;gBACN,IAAI,CAAC,OAAO,EAAE,CAAC;oBACX,OAAO,GAAG,IAAI,CAAC;oBACf,OAAO,CAAC,KAAK,CAAC,CAAC;gBACnB,CAAC;YACL,CAAC,EACD,CAAC,KAAK,EAAE,EAAE;gBACN,MAAM,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC;gBACtB,cAAc,EAAE,CAAC;gBAEjB,4DAA4D;gBAC5D,IAAI,cAAc,KAAK,QAAQ,CAAC,MAAM,EAAE,CAAC;oBACrC,IAAI,CAAC,OAAO,EAAE,CAAC;wBACX,OAAO,GAAG,IAAI,CAAC;wBACf,MAAM,CACF,IAAI,cAAc,CACd,MAAM,EACN,OAAO,QAAQ,CAAC,MAAM,oBAAoB,CAC7C,CACJ,CAAC;oBACN,CAAC;gBACL,CAAC;YACL,CAAC,CACJ,CAAC;QACN,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;AACP,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { RetryOptions } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Retry a failed async operation with configurable backoff strategies
|
|
4
|
+
*
|
|
5
|
+
* @param fn - The async function to retry
|
|
6
|
+
* @param options - Configuration options for retry behavior
|
|
7
|
+
* @returns Promise that resolves with the function result or rejects after all attempts fail
|
|
8
|
+
* @throws {RetryError} If all retry attempts are exhausted
|
|
9
|
+
* @throws {AbortError} If the operation is aborted via AbortSignal
|
|
10
|
+
* @throws {TypeError} If invalid options are provided
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* // Basic usage with defaults (3 attempts, exponential backoff)
|
|
15
|
+
* const result = await retry(() => fetchData());
|
|
16
|
+
*
|
|
17
|
+
* // Custom configuration
|
|
18
|
+
* const result = await retry(() => fetchData(), {
|
|
19
|
+
* maxAttempts: 5,
|
|
20
|
+
* baseDelay: 500,
|
|
21
|
+
* maxDelay: 10000,
|
|
22
|
+
* backoff: 'linear',
|
|
23
|
+
* shouldRetry: (error) => error instanceof NetworkError
|
|
24
|
+
* });
|
|
25
|
+
*
|
|
26
|
+
* // With cancellation
|
|
27
|
+
* const controller = new AbortController();
|
|
28
|
+
* const result = await retry(() => fetchData(), {
|
|
29
|
+
* signal: controller.signal
|
|
30
|
+
* });
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export declare function retry<T>(fn: () => Promise<T>, options?: RetryOptions): Promise<T>;
|
|
34
|
+
//# sourceMappingURL=retry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../../../src/utils/async/retry.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAsB,KAAK,CAAC,CAAC,EACzB,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,OAAO,GAAE,YAAiB,GAC3B,OAAO,CAAC,CAAC,CAAC,CA8EZ"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { sleep } from "./sleep.js";
|
|
2
|
+
import { AbortError, RetryError } from "./errors.js";
|
|
3
|
+
/**
|
|
4
|
+
* Retry a failed async operation with configurable backoff strategies
|
|
5
|
+
*
|
|
6
|
+
* @param fn - The async function to retry
|
|
7
|
+
* @param options - Configuration options for retry behavior
|
|
8
|
+
* @returns Promise that resolves with the function result or rejects after all attempts fail
|
|
9
|
+
* @throws {RetryError} If all retry attempts are exhausted
|
|
10
|
+
* @throws {AbortError} If the operation is aborted via AbortSignal
|
|
11
|
+
* @throws {TypeError} If invalid options are provided
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* // Basic usage with defaults (3 attempts, exponential backoff)
|
|
16
|
+
* const result = await retry(() => fetchData());
|
|
17
|
+
*
|
|
18
|
+
* // Custom configuration
|
|
19
|
+
* const result = await retry(() => fetchData(), {
|
|
20
|
+
* maxAttempts: 5,
|
|
21
|
+
* baseDelay: 500,
|
|
22
|
+
* maxDelay: 10000,
|
|
23
|
+
* backoff: 'linear',
|
|
24
|
+
* shouldRetry: (error) => error instanceof NetworkError
|
|
25
|
+
* });
|
|
26
|
+
*
|
|
27
|
+
* // With cancellation
|
|
28
|
+
* const controller = new AbortController();
|
|
29
|
+
* const result = await retry(() => fetchData(), {
|
|
30
|
+
* signal: controller.signal
|
|
31
|
+
* });
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export async function retry(fn, options = {}) {
|
|
35
|
+
// Validate function parameter
|
|
36
|
+
if (typeof fn !== "function") {
|
|
37
|
+
throw new TypeError("First argument must be a function");
|
|
38
|
+
}
|
|
39
|
+
// Extract and validate options with defaults
|
|
40
|
+
const { maxAttempts = 3, baseDelay = 1000, maxDelay = Infinity, backoff = "exponential", shouldRetry, signal, } = options;
|
|
41
|
+
// Validate numeric options
|
|
42
|
+
if (maxAttempts < 1) {
|
|
43
|
+
throw new TypeError(`maxAttempts must be at least 1, got ${maxAttempts}`);
|
|
44
|
+
}
|
|
45
|
+
if (baseDelay < 0) {
|
|
46
|
+
throw new TypeError(`baseDelay must be non-negative, got ${baseDelay}`);
|
|
47
|
+
}
|
|
48
|
+
if (maxDelay < 0) {
|
|
49
|
+
throw new TypeError(`maxDelay must be non-negative, got ${maxDelay}`);
|
|
50
|
+
}
|
|
51
|
+
// Check if already aborted
|
|
52
|
+
if (signal?.aborted) {
|
|
53
|
+
throw new AbortError("Retry aborted before starting");
|
|
54
|
+
}
|
|
55
|
+
let lastError;
|
|
56
|
+
// Attempt execution up to maxAttempts times
|
|
57
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
58
|
+
try {
|
|
59
|
+
// Execute the function
|
|
60
|
+
const result = await fn();
|
|
61
|
+
return result;
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
lastError = error;
|
|
65
|
+
// Check if we should retry this error
|
|
66
|
+
if (shouldRetry && !shouldRetry(error)) {
|
|
67
|
+
throw error;
|
|
68
|
+
}
|
|
69
|
+
// If this was the last attempt, don't delay
|
|
70
|
+
if (attempt === maxAttempts) {
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
// Calculate delay based on backoff strategy
|
|
74
|
+
const delay = calculateDelay(attempt, baseDelay, maxDelay, backoff);
|
|
75
|
+
// Wait before next attempt (with abort support)
|
|
76
|
+
try {
|
|
77
|
+
await sleep(delay, signal);
|
|
78
|
+
}
|
|
79
|
+
catch (sleepError) {
|
|
80
|
+
// If sleep was aborted, throw AbortError
|
|
81
|
+
if (sleepError instanceof AbortError) {
|
|
82
|
+
throw sleepError;
|
|
83
|
+
}
|
|
84
|
+
// Otherwise, rethrow the error
|
|
85
|
+
throw sleepError;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
// All attempts exhausted, throw RetryError
|
|
90
|
+
throw new RetryError(`Failed after ${maxAttempts} attempts`, maxAttempts, lastError);
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Calculate the delay for a retry attempt based on the backoff strategy
|
|
94
|
+
*
|
|
95
|
+
* @param attempt - Current attempt number (1-indexed)
|
|
96
|
+
* @param baseDelay - Base delay in milliseconds
|
|
97
|
+
* @param maxDelay - Maximum delay cap in milliseconds
|
|
98
|
+
* @param backoff - Backoff strategy to use
|
|
99
|
+
* @returns Delay in milliseconds, capped at maxDelay
|
|
100
|
+
*/
|
|
101
|
+
function calculateDelay(attempt, baseDelay, maxDelay, backoff) {
|
|
102
|
+
let delay;
|
|
103
|
+
if (typeof backoff === "function") {
|
|
104
|
+
// Custom backoff function
|
|
105
|
+
delay = backoff(attempt);
|
|
106
|
+
}
|
|
107
|
+
else if (backoff === "linear") {
|
|
108
|
+
// Linear backoff: baseDelay * attempt
|
|
109
|
+
delay = baseDelay * attempt;
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
// Exponential backoff: baseDelay * (2 ^ (attempt - 1))
|
|
113
|
+
delay = baseDelay * Math.pow(2, attempt - 1);
|
|
114
|
+
}
|
|
115
|
+
// Apply maxDelay cap
|
|
116
|
+
return Math.min(delay, maxDelay);
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=retry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retry.js","sourceRoot":"","sources":["../../../src/utils/async/retry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { SequentialTask, SequentialOptions } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Execute async tasks sequentially, one after another
|
|
4
|
+
*
|
|
5
|
+
* Each task receives the result of the previous task as an optional parameter.
|
|
6
|
+
* By default, execution stops on the first error. Use continueOnError option
|
|
7
|
+
* to execute all tasks regardless of failures.
|
|
8
|
+
*
|
|
9
|
+
* @param tasks - Array of async task functions to execute sequentially
|
|
10
|
+
* @param options - Optional configuration for error handling
|
|
11
|
+
* @returns Promise that resolves with array of results in execution order
|
|
12
|
+
* @throws First error encountered if any task fails (unless continueOnError is true)
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* // Basic sequential execution
|
|
17
|
+
* const results = await sequential([
|
|
18
|
+
* () => fetchUser(1),
|
|
19
|
+
* (user) => fetchPosts(user.id),
|
|
20
|
+
* (posts) => processPosts(posts)
|
|
21
|
+
* ]);
|
|
22
|
+
*
|
|
23
|
+
* // Continue on error
|
|
24
|
+
* const results = await sequential(tasks, { continueOnError: true });
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export declare function sequential<T>(tasks: Array<SequentialTask<T>>, options?: SequentialOptions): Promise<T[]>;
|
|
28
|
+
//# sourceMappingURL=sequential.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sequential.d.ts","sourceRoot":"","sources":["../../../src/utils/async/sequential.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEpE;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAsB,UAAU,CAAC,CAAC,EAC9B,KAAK,EAAE,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,EAC/B,OAAO,CAAC,EAAE,iBAAiB,GAC5B,OAAO,CAAC,CAAC,EAAE,CAAC,CA0Cd"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Execute async tasks sequentially, one after another
|
|
3
|
+
*
|
|
4
|
+
* Each task receives the result of the previous task as an optional parameter.
|
|
5
|
+
* By default, execution stops on the first error. Use continueOnError option
|
|
6
|
+
* to execute all tasks regardless of failures.
|
|
7
|
+
*
|
|
8
|
+
* @param tasks - Array of async task functions to execute sequentially
|
|
9
|
+
* @param options - Optional configuration for error handling
|
|
10
|
+
* @returns Promise that resolves with array of results in execution order
|
|
11
|
+
* @throws First error encountered if any task fails (unless continueOnError is true)
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* // Basic sequential execution
|
|
16
|
+
* const results = await sequential([
|
|
17
|
+
* () => fetchUser(1),
|
|
18
|
+
* (user) => fetchPosts(user.id),
|
|
19
|
+
* (posts) => processPosts(posts)
|
|
20
|
+
* ]);
|
|
21
|
+
*
|
|
22
|
+
* // Continue on error
|
|
23
|
+
* const results = await sequential(tasks, { continueOnError: true });
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export async function sequential(tasks, options) {
|
|
27
|
+
// Validate input
|
|
28
|
+
if (!Array.isArray(tasks)) {
|
|
29
|
+
throw new TypeError("tasks must be an array");
|
|
30
|
+
}
|
|
31
|
+
// Handle empty array
|
|
32
|
+
if (tasks.length === 0) {
|
|
33
|
+
return [];
|
|
34
|
+
}
|
|
35
|
+
// Validate all tasks are functions
|
|
36
|
+
for (let i = 0; i < tasks.length; i++) {
|
|
37
|
+
if (typeof tasks[i] !== "function") {
|
|
38
|
+
throw new TypeError(`Task at index ${i} is not a function`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
const continueOnError = options?.continueOnError ?? false;
|
|
42
|
+
const results = [];
|
|
43
|
+
let previousResult = undefined;
|
|
44
|
+
// Execute tasks one by one using for...of loop
|
|
45
|
+
for (let i = 0; i < tasks.length; i++) {
|
|
46
|
+
try {
|
|
47
|
+
// Pass previous result to current task
|
|
48
|
+
const result = await tasks[i](previousResult);
|
|
49
|
+
results.push(result);
|
|
50
|
+
previousResult = result;
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
if (continueOnError) {
|
|
54
|
+
// Store error as result and continue
|
|
55
|
+
results.push(error);
|
|
56
|
+
previousResult = error;
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
// Fail fast - reject immediately
|
|
60
|
+
throw error;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return results;
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=sequential.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sequential.js","sourceRoot":"","sources":["../../../src/utils/async/sequential.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC5B,KAA+B,EAC/B,OAA2B;IAE3B,iBAAiB;IACjB,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,SAAS,CAAC,wBAAwB,CAAC,CAAC;IAClD,CAAC;IAED,qBAAqB;IACrB,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACrB,OAAO,EAAE,CAAC;IACd,CAAC;IAED,mCAAmC;IACnC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACpC,IAAI,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,UAAU,EAAE,CAAC;YACjC,MAAM,IAAI,SAAS,CAAC,iBAAiB,CAAC,oBAAoB,CAAC,CAAC;QAChE,CAAC;IACL,CAAC;IAED,MAAM,eAAe,GAAG,OAAO,EAAE,eAAe,IAAI,KAAK,CAAC;IAC1D,MAAM,OAAO,GAAQ,EAAE,CAAC;IACxB,IAAI,cAAc,GAAQ,SAAS,CAAC;IAEpC,+CAA+C;IAC/C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACpC,IAAI,CAAC;YACD,uCAAuC;YACvC,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC;YAC9C,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACrB,cAAc,GAAG,MAAM,CAAC;QAC5B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,IAAI,eAAe,EAAE,CAAC;gBAClB,qCAAqC;gBACrC,OAAO,CAAC,IAAI,CAAC,KAAU,CAAC,CAAC;gBACzB,cAAc,GAAG,KAAK,CAAC;YAC3B,CAAC;iBAAM,CAAC;gBACJ,iCAAiC;gBACjC,MAAM,KAAK,CAAC;YAChB,CAAC;QACL,CAAC;IACL,CAAC;IAED,OAAO,OAAO,CAAC;AACnB,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Promise-based delay function with optional cancellation support
|
|
3
|
+
*
|
|
4
|
+
* @param ms - Duration to sleep in milliseconds (must be non-negative)
|
|
5
|
+
* @param signal - Optional AbortSignal for cancellation
|
|
6
|
+
* @returns Promise that resolves after the specified duration
|
|
7
|
+
* @throws {TypeError} If ms is negative
|
|
8
|
+
* @throws {AbortError} If the operation is aborted via AbortSignal
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* // Basic usage
|
|
13
|
+
* await sleep(1000); // Wait 1 second
|
|
14
|
+
*
|
|
15
|
+
* // With cancellation
|
|
16
|
+
* const controller = new AbortController();
|
|
17
|
+
* setTimeout(() => controller.abort(), 500);
|
|
18
|
+
* try {
|
|
19
|
+
* await sleep(1000, controller.signal);
|
|
20
|
+
* } catch (error) {
|
|
21
|
+
* if (error instanceof AbortError) {
|
|
22
|
+
* console.log('Sleep was cancelled');
|
|
23
|
+
* }
|
|
24
|
+
* }
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export declare function sleep(ms: number, signal?: AbortSignal): Promise<void>;
|
|
28
|
+
//# sourceMappingURL=sleep.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sleep.d.ts","sourceRoot":"","sources":["../../../src/utils/async/sleep.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CA2CrE"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { AbortError } from "./errors.js";
|
|
2
|
+
/**
|
|
3
|
+
* Promise-based delay function with optional cancellation support
|
|
4
|
+
*
|
|
5
|
+
* @param ms - Duration to sleep in milliseconds (must be non-negative)
|
|
6
|
+
* @param signal - Optional AbortSignal for cancellation
|
|
7
|
+
* @returns Promise that resolves after the specified duration
|
|
8
|
+
* @throws {TypeError} If ms is negative
|
|
9
|
+
* @throws {AbortError} If the operation is aborted via AbortSignal
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* // Basic usage
|
|
14
|
+
* await sleep(1000); // Wait 1 second
|
|
15
|
+
*
|
|
16
|
+
* // With cancellation
|
|
17
|
+
* const controller = new AbortController();
|
|
18
|
+
* setTimeout(() => controller.abort(), 500);
|
|
19
|
+
* try {
|
|
20
|
+
* await sleep(1000, controller.signal);
|
|
21
|
+
* } catch (error) {
|
|
22
|
+
* if (error instanceof AbortError) {
|
|
23
|
+
* console.log('Sleep was cancelled');
|
|
24
|
+
* }
|
|
25
|
+
* }
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export function sleep(ms, signal) {
|
|
29
|
+
// Validate input
|
|
30
|
+
if (ms < 0) {
|
|
31
|
+
throw new TypeError(`Sleep duration must be non-negative, got ${ms} milliseconds`);
|
|
32
|
+
}
|
|
33
|
+
// Check if already aborted
|
|
34
|
+
if (signal?.aborted) {
|
|
35
|
+
return Promise.reject(new AbortError("Sleep aborted before starting"));
|
|
36
|
+
}
|
|
37
|
+
return new Promise((resolve, reject) => {
|
|
38
|
+
// Handle zero milliseconds - resolve immediately
|
|
39
|
+
if (ms === 0) {
|
|
40
|
+
resolve();
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
// Set up the timeout
|
|
44
|
+
const timeoutId = setTimeout(() => {
|
|
45
|
+
cleanup();
|
|
46
|
+
resolve();
|
|
47
|
+
}, ms);
|
|
48
|
+
// Set up abort handler
|
|
49
|
+
const abortHandler = () => {
|
|
50
|
+
cleanup();
|
|
51
|
+
reject(new AbortError("Sleep aborted"));
|
|
52
|
+
};
|
|
53
|
+
// Cleanup function to prevent memory leaks
|
|
54
|
+
const cleanup = () => {
|
|
55
|
+
clearTimeout(timeoutId);
|
|
56
|
+
signal?.removeEventListener("abort", abortHandler);
|
|
57
|
+
};
|
|
58
|
+
// Register abort listener if signal provided
|
|
59
|
+
if (signal) {
|
|
60
|
+
signal.addEventListener("abort", abortHandler, { once: true });
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=sleep.js.map
|