vinh-async-utils 3.1.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.
package/README.md ADDED
@@ -0,0 +1,129 @@
1
+ # @org/async
2
+
3
+ Async utility functions with retry logic and error handling for TypeScript applications.
4
+
5
+ ## ๐Ÿ“ฆ Package Information
6
+
7
+ - **Version**: 0.0.1
8
+ - **Publishable**: โœ… Yes
9
+ - **Tag**: `scope:async`
10
+ - **Module Boundaries**: Can only import from `scope:shared` packages
11
+
12
+ ## โš ๏ธ CI Demo Note
13
+
14
+ **This package includes an intentionally failing test to demonstrate Nx's self-healing CI feature.** When you run tests, you'll see one failure. This is by design to showcase how `nx fix-ci` works in the CI pipeline.
15
+
16
+ ## ๐Ÿš€ Features
17
+
18
+ This package provides powerful async utilities:
19
+
20
+ - **retry** - Retry failed async operations with configurable options
21
+ - **createRetry** - Create reusable retry functions with default options
22
+ - **withRetry** - Wrap functions to automatically retry on failure
23
+ - **retryAll** - Retry multiple operations and wait for all
24
+ - **retryRace** - Race multiple operations with retry
25
+ - **retryAllSettled** - Get all results regardless of success/failure
26
+ - **TimeoutError** - Custom error class for timeout scenarios
27
+
28
+ ## ๐Ÿ“ Usage Examples
29
+
30
+ ```typescript
31
+ import { retry, createRetry, withRetry, TimeoutError } from '@org/async';
32
+
33
+ // Basic retry with default options
34
+ const result = await retry(async () => {
35
+ const response = await fetch('/api/data');
36
+ return response.json();
37
+ });
38
+
39
+ // Retry with custom options
40
+ const data = await retry(
41
+ async (attempt) => {
42
+ console.log(`Attempt ${attempt + 1}`);
43
+ return await riskyOperation();
44
+ },
45
+ {
46
+ retries: 3, // Max 3 retries
47
+ delay: 1000, // 1 second delay
48
+ backoff: 2 // Exponential backoff factor
49
+ }
50
+ );
51
+
52
+ // Create a reusable retry function
53
+ const retryWithDefaults = createRetry({
54
+ retries: 2,
55
+ delay: 500
56
+ });
57
+
58
+ const result1 = await retryWithDefaults(operation1);
59
+ const result2 = await retryWithDefaults(operation2);
60
+
61
+ // Wrap a function to automatically retry
62
+ const safeFunction = withRetry(riskyFunction, { retries: 3 });
63
+ const result = await safeFunction(arg1, arg2);
64
+
65
+ // Retry multiple operations
66
+ const results = await retryAll([
67
+ operation1,
68
+ operation2,
69
+ operation3
70
+ ], { retries: 2 });
71
+
72
+ // Race operations with retry
73
+ const fastest = await retryRace([
74
+ slowOperation,
75
+ fastOperation
76
+ ]);
77
+ ```
78
+
79
+ ## ๐Ÿงช Testing
80
+
81
+ ```bash
82
+ # Run tests for this package (includes 1 intentional failure for CI demo)
83
+ nx test async
84
+
85
+ # Run tests in watch mode
86
+ nx test async --watch
87
+
88
+ # Run specific test file
89
+ nx test async --testFile=async-retry.spec.ts
90
+ ```
91
+
92
+ ## ๐Ÿ—๏ธ Building
93
+
94
+ ```bash
95
+ # Build the package
96
+ nx build async
97
+
98
+ # The build output will be in dist/packages/async
99
+ ```
100
+
101
+ ## ๐Ÿ“‹ Available Commands
102
+
103
+ ```bash
104
+ nx build async # Build the package
105
+ nx test async # Run tests (includes intentional failure)
106
+ nx lint async # Lint the package
107
+ ```
108
+
109
+ ## ๐Ÿ”’ Module Boundaries
110
+
111
+ This package has the tag `scope:async` and can only import from:
112
+ - `@org/utils` (tagged with `scope:shared`)
113
+
114
+ Attempting to import from `@org/colors` or `@org/strings` will result in a linting error due to module boundary constraints.
115
+
116
+ ## ๐Ÿ”ง Self-Healing CI Demo
117
+
118
+ This package demonstrates Nx's self-healing CI capabilities. The intentionally failing test helps showcase:
119
+
120
+ 1. How CI detects failures
121
+ 2. How `nx fix-ci` provides automated suggestions
122
+ 3. How the system can self-correct common issues
123
+
124
+ To see this in action in CI, the workflow runs:
125
+ ```bash
126
+ npx nx fix-ci
127
+ ```
128
+
129
+ This command analyzes failures and provides actionable fixes.
@@ -0,0 +1,2 @@
1
+ export * from './lib/async-retry.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ export * from './lib/async-retry.js';
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Options for retry function
3
+ */
4
+ export interface RetryOptions {
5
+ /** Maximum number of retries (default: 3) */
6
+ retries?: number;
7
+ /** Initial delay in ms (default: 1000) */
8
+ delay?: number;
9
+ /** Maximum delay in ms (default: 30000) */
10
+ maxDelay?: number;
11
+ /** Exponential backoff factor (default: 2) */
12
+ factor?: number;
13
+ /** Callback on each retry */
14
+ onRetry?: (error: Error, attempt: number, nextDelay: number) => void;
15
+ /** Function to determine if should retry */
16
+ shouldRetry?: (error: Error, attempt: number) => boolean;
17
+ }
18
+ /**
19
+ * Options for retry with timeout
20
+ */
21
+ export interface RetryWithTimeoutOptions extends RetryOptions {
22
+ /** Timeout in milliseconds for each attempt */
23
+ timeout?: number;
24
+ /** Custom timeout error message */
25
+ timeoutMessage?: string;
26
+ }
27
+ /**
28
+ * Timeout error class
29
+ */
30
+ export declare class TimeoutError extends Error {
31
+ code: string;
32
+ constructor(message?: string);
33
+ }
34
+ /**
35
+ * Retry failed async functions with exponential backoff
36
+ */
37
+ export declare function retry<T>(fn: (attempt: number) => Promise<T>, options?: RetryOptions): Promise<T>;
38
+ /**
39
+ * Create a reusable retry wrapper with preset options
40
+ */
41
+ export declare function createRetry(defaultOptions?: RetryOptions): <T>(fn: (attempt: number) => Promise<T>, overrides?: RetryOptions) => Promise<T>;
42
+ /**
43
+ * Wrap a function to always retry on failure
44
+ */
45
+ export declare function withRetry<T extends (...args: any[]) => Promise<any>>(fn: T, options?: RetryOptions): T;
46
+ /**
47
+ * Execute multiple async operations with individual retry logic
48
+ */
49
+ export declare function retryAll<T>(fns: Array<(attempt: number) => Promise<T>>, options?: RetryOptions): Promise<T[]>;
50
+ /**
51
+ * Execute multiple async operations, returning first successful result
52
+ */
53
+ export declare function retryRace<T>(fns: Array<(attempt: number) => Promise<T>>, options?: RetryOptions): Promise<T>;
54
+ /**
55
+ * Execute multiple async operations, returning all results (including errors)
56
+ */
57
+ export declare function retryAllSettled<T>(fns: Array<(attempt: number) => Promise<T>>, options?: RetryOptions): Promise<PromiseSettledResult<T>[]>;
58
+ //# sourceMappingURL=async-retry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"async-retry.d.ts","sourceRoot":"","sources":["../../src/lib/async-retry.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,6CAA6C;IAC7C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,0CAA0C;IAC1C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2CAA2C;IAC3C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8CAA8C;IAC9C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,6BAA6B;IAC7B,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACrE,4CAA4C;IAC5C,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC;CAC1D;AAED;;GAEG;AACH,MAAM,WAAW,uBAAwB,SAAQ,YAAY;IAC3D,+CAA+C;IAC/C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,mCAAmC;IACnC,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;GAEG;AACH,qBAAa,YAAa,SAAQ,KAAK;IACrC,IAAI,SAAa;gBAEL,OAAO,SAAwB;CAI5C;AAQD;;GAEG;AACH,wBAAsB,KAAK,CAAC,CAAC,EAC3B,EAAE,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,EACnC,OAAO,GAAE,YAAiB,GACzB,OAAO,CAAC,CAAC,CAAC,CAsCZ;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,cAAc,GAAE,YAAiB,IACnD,CAAC,EACP,IAAI,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,EACnC,YAAW,YAAiB,KAC3B,OAAO,CAAC,CAAC,CAAC,CAGd;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,OAAO,CAAC,GAAG,CAAC,EAClE,EAAE,EAAE,CAAC,EACL,OAAO,GAAE,YAAiB,GACzB,CAAC,CAIH;AAED;;GAEG;AACH,wBAAsB,QAAQ,CAAC,CAAC,EAC9B,GAAG,EAAE,KAAK,CAAC,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,EAC3C,OAAO,GAAE,YAAiB,GACzB,OAAO,CAAC,CAAC,EAAE,CAAC,CAEd;AAED;;GAEG;AACH,wBAAsB,SAAS,CAAC,CAAC,EAC/B,GAAG,EAAE,KAAK,CAAC,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,EAC3C,OAAO,GAAE,YAAiB,GACzB,OAAO,CAAC,CAAC,CAAC,CAEZ;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,CAAC,EACrC,GAAG,EAAE,KAAK,CAAC,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,EAC3C,OAAO,GAAE,YAAiB,GACzB,OAAO,CAAC,oBAAoB,CAAC,CAAC,CAAC,EAAE,CAAC,CAEpC"}
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Timeout error class
3
+ */
4
+ export class TimeoutError extends Error {
5
+ code = 'TIMEOUT';
6
+ constructor(message = 'Operation timed out') {
7
+ super(message);
8
+ this.name = 'TimeoutError';
9
+ }
10
+ }
11
+ /**
12
+ * Sleep for specified milliseconds
13
+ */
14
+ const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
15
+ /**
16
+ * Retry failed async functions with exponential backoff
17
+ */
18
+ export async function retry(fn, options = {}) {
19
+ const { retries = 3, delay = 1000, maxDelay = 30000, factor = 2, onRetry = () => {
20
+ return;
21
+ }, shouldRetry = () => true, } = options;
22
+ let lastError;
23
+ let currentDelay = delay;
24
+ for (let attempt = 0; attempt <= retries; attempt++) {
25
+ try {
26
+ return await fn(attempt);
27
+ }
28
+ catch (error) {
29
+ lastError = error;
30
+ // Check if we should retry
31
+ if (attempt === retries || !shouldRetry(lastError, attempt)) {
32
+ throw error;
33
+ }
34
+ // Call onRetry callback
35
+ onRetry(lastError, attempt, currentDelay);
36
+ // Wait before retrying
37
+ await sleep(currentDelay);
38
+ // Calculate next delay with exponential backoff
39
+ currentDelay = Math.min(currentDelay * factor, maxDelay);
40
+ }
41
+ }
42
+ throw lastError;
43
+ }
44
+ /**
45
+ * Create a reusable retry wrapper with preset options
46
+ */
47
+ export function createRetry(defaultOptions = {}) {
48
+ return (fn, overrides = {}) => {
49
+ return retry(fn, { ...defaultOptions, ...overrides });
50
+ };
51
+ }
52
+ /**
53
+ * Wrap a function to always retry on failure
54
+ */
55
+ export function withRetry(fn, options = {}) {
56
+ return (async (...args) => {
57
+ return retry(() => fn(...args), options);
58
+ });
59
+ }
60
+ /**
61
+ * Execute multiple async operations with individual retry logic
62
+ */
63
+ export async function retryAll(fns, options = {}) {
64
+ return Promise.all(fns.map((fn) => retry(fn, options)));
65
+ }
66
+ /**
67
+ * Execute multiple async operations, returning first successful result
68
+ */
69
+ export async function retryRace(fns, options = {}) {
70
+ return Promise.race(fns.map((fn) => retry(fn, options)));
71
+ }
72
+ /**
73
+ * Execute multiple async operations, returning all results (including errors)
74
+ */
75
+ export async function retryAllSettled(fns, options = {}) {
76
+ return Promise.allSettled(fns.map((fn) => retry(fn, options)));
77
+ }
package/package.json ADDED
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "vinh-async-utils",
3
+ "version": "3.1.0",
4
+ "type": "module",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ "./package.json": "./package.json",
10
+ ".": {
11
+ "@org/source": "./src/index.ts",
12
+ "types": "./dist/index.d.ts",
13
+ "import": "./dist/index.js",
14
+ "default": "./dist/index.js"
15
+ }
16
+ },
17
+ "files": [
18
+ "dist",
19
+ "!**/*.tsbuildinfo"
20
+ ],
21
+ "dependencies": {
22
+ "tslib": "^2.3.0"
23
+ },
24
+ "nx": {
25
+ "tags": [
26
+ "scope:async"
27
+ ]
28
+ }
29
+ }