@ls-stack/utils 3.28.0 → 3.30.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.
@@ -14,7 +14,7 @@
14
14
  type RetryOptions = object;
15
15
  ```
16
16
 
17
- Defined in: [packages/utils/src/retryOnError.ts:6](https://github.com/lucasols/utils/blob/main/packages/utils/src/retryOnError.ts#L6)
17
+ Defined in: [packages/utils/src/retryOnError.ts:7](https://github.com/lucasols/utils/blob/main/packages/utils/src/retryOnError.ts#L7)
18
18
 
19
19
  Configuration options for retryOnError function.
20
20
 
@@ -26,7 +26,7 @@ Configuration options for retryOnError function.
26
26
  optional debugId: string;
27
27
  ```
28
28
 
29
- Defined in: [packages/utils/src/retryOnError.ts:15](https://github.com/lucasols/utils/blob/main/packages/utils/src/retryOnError.ts#L15)
29
+ Defined in: [packages/utils/src/retryOnError.ts:16](https://github.com/lucasols/utils/blob/main/packages/utils/src/retryOnError.ts#L16)
30
30
 
31
31
  Optional ID for debug logging
32
32
 
@@ -36,17 +36,57 @@ Optional ID for debug logging
36
36
  optional delayBetweenRetriesMs: number | (retry) => number;
37
37
  ```
38
38
 
39
- Defined in: [packages/utils/src/retryOnError.ts:8](https://github.com/lucasols/utils/blob/main/packages/utils/src/retryOnError.ts#L8)
39
+ Defined in: [packages/utils/src/retryOnError.ts:9](https://github.com/lucasols/utils/blob/main/packages/utils/src/retryOnError.ts#L9)
40
40
 
41
41
  Delay between retries in milliseconds or function returning delay
42
42
 
43
+ ##### disableRetries?
44
+
45
+ ```ts
46
+ optional disableRetries: boolean;
47
+ ```
48
+
49
+ Defined in: [packages/utils/src/retryOnError.ts:18](https://github.com/lucasols/utils/blob/main/packages/utils/src/retryOnError.ts#L18)
50
+
51
+ Disable retries
52
+
53
+ ##### onRetry()?
54
+
55
+ ```ts
56
+ optional onRetry: (error, lastAttempt) => void;
57
+ ```
58
+
59
+ Defined in: [packages/utils/src/retryOnError.ts:20](https://github.com/lucasols/utils/blob/main/packages/utils/src/retryOnError.ts#L20)
60
+
61
+ Function to call when retry happens
62
+
63
+ ###### Parameters
64
+
65
+ ###### error
66
+
67
+ `Error`
68
+
69
+ ###### lastAttempt
70
+
71
+ ###### duration
72
+
73
+ `number`
74
+
75
+ ###### retry
76
+
77
+ `number`
78
+
79
+ ###### Returns
80
+
81
+ `void`
82
+
43
83
  ##### retryCondition()?
44
84
 
45
85
  ```ts
46
86
  optional retryCondition: (error, lastAttempt) => boolean;
47
87
  ```
48
88
 
49
- Defined in: [packages/utils/src/retryOnError.ts:10](https://github.com/lucasols/utils/blob/main/packages/utils/src/retryOnError.ts#L10)
89
+ Defined in: [packages/utils/src/retryOnError.ts:11](https://github.com/lucasols/utils/blob/main/packages/utils/src/retryOnError.ts#L11)
50
90
 
51
91
  Function to determine if retry should happen, receives error and duration of last attempt
52
92
 
@@ -54,7 +94,7 @@ Function to determine if retry should happen, receives error and duration of las
54
94
 
55
95
  ###### error
56
96
 
57
- `unknown`
97
+ `Error`
58
98
 
59
99
  ###### lastAttempt
60
100
 
@@ -23,7 +23,7 @@ function retryOnError<T>(
23
23
  originalMaxRetries): Promise<T>;
24
24
  ```
25
25
 
26
- Defined in: [packages/utils/src/retryOnError.ts:38](https://github.com/lucasols/utils/blob/main/packages/utils/src/retryOnError.ts#L38)
26
+ Defined in: [packages/utils/src/retryOnError.ts:46](https://github.com/lucasols/utils/blob/main/packages/utils/src/retryOnError.ts#L46)
27
27
 
28
28
  Retries a function on error with configurable retry logic.
29
29
 
@@ -57,10 +57,14 @@ Configuration options
57
57
 
58
58
  `number` = `0`
59
59
 
60
+ internal use only
61
+
60
62
  ##### originalMaxRetries
61
63
 
62
64
  `number` = `maxRetries`
63
65
 
66
+ internal use only
67
+
64
68
  #### Returns
65
69
 
66
70
  `Promise`\<`T`\>
@@ -79,3 +83,86 @@ await retryOnError(
79
83
  { delayBetweenRetriesMs: 1000 }
80
84
  );
81
85
  ```
86
+
87
+ ***
88
+
89
+ ### retryResultOnError()
90
+
91
+ ```ts
92
+ function retryResultOnError<T, E>(
93
+ fn,
94
+ maxRetries,
95
+ options,
96
+ __retry,
97
+ __originalMaxRetries): Promise<Result<T, E>>;
98
+ ```
99
+
100
+ Defined in: [packages/utils/src/retryOnError.ts:132](https://github.com/lucasols/utils/blob/main/packages/utils/src/retryOnError.ts#L132)
101
+
102
+ Retries a result function on error with configurable retry logic.
103
+
104
+ #### Type Parameters
105
+
106
+ ##### T
107
+
108
+ `T`
109
+
110
+ ##### E
111
+
112
+ `E` *extends* `ResultValidErrors`
113
+
114
+ #### Parameters
115
+
116
+ ##### fn
117
+
118
+ (`ctx`) => `Promise`\<`Result`\<`T`, `E`\>\>
119
+
120
+ Function to retry that receives context with retry count
121
+
122
+ ##### maxRetries
123
+
124
+ `number`
125
+
126
+ Maximum number of retries
127
+
128
+ ##### options
129
+
130
+ Configuration options
131
+
132
+ ###### debugId?
133
+
134
+ `string`
135
+
136
+ ###### delayBetweenRetriesMs?
137
+
138
+ `number` \| (`retry`) => `number`
139
+
140
+ ###### disableRetries?
141
+
142
+ `boolean`
143
+
144
+ ###### onRetry?
145
+
146
+ (`error`, `lastAttempt`) => `void`
147
+
148
+ ###### retryCondition?
149
+
150
+ (`error`, `lastAttempt`) => `boolean`
151
+
152
+ ##### \_\_retry
153
+
154
+ `number` = `0`
155
+
156
+ internal use only
157
+
158
+ ##### \_\_originalMaxRetries
159
+
160
+ `number` = `maxRetries`
161
+
162
+ internal use only
163
+
164
+ #### Returns
165
+
166
+ `Promise`\<`Result`\<`T`, `E`\>\>
167
+
168
+ Promise resolving to the function result or rejecting with the final error
@@ -20,9 +20,11 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/retryOnError.ts
21
21
  var retryOnError_exports = {};
22
22
  __export(retryOnError_exports, {
23
- retryOnError: () => retryOnError
23
+ retryOnError: () => retryOnError,
24
+ retryResultOnError: () => retryResultOnError
24
25
  });
25
26
  module.exports = __toCommonJS(retryOnError_exports);
27
+ var import_t_result = require("t-result");
26
28
 
27
29
  // src/sleep.ts
28
30
  function sleep(ms) {
@@ -31,7 +33,7 @@ function sleep(ms) {
31
33
 
32
34
  // src/retryOnError.ts
33
35
  async function retryOnError(fn, maxRetries, options = {}, retry = 0, originalMaxRetries = maxRetries) {
34
- const { delayBetweenRetriesMs, retryCondition } = options;
36
+ const { delayBetweenRetriesMs, retryCondition, disableRetries, onRetry } = options;
35
37
  if (options.debugId) {
36
38
  if (retry > 0) {
37
39
  console.info(
@@ -43,11 +45,21 @@ async function retryOnError(fn, maxRetries, options = {}, retry = 0, originalMax
43
45
  try {
44
46
  return await fn({ retry });
45
47
  } catch (error) {
46
- if (maxRetries > 0) {
48
+ if (maxRetries > 0 && !disableRetries) {
47
49
  const errorDuration = Date.now() - startTime;
48
- const shouldRetry = retryCondition ? retryCondition(error, { duration: errorDuration, retry }) : true;
50
+ const normalizedError = (0, import_t_result.unknownToError)(error);
51
+ const shouldRetry = retryCondition ? retryCondition(normalizedError, {
52
+ duration: errorDuration,
53
+ retry
54
+ }) : true;
49
55
  if (!shouldRetry) {
50
- throw error;
56
+ throw normalizedError;
57
+ }
58
+ if (onRetry) {
59
+ onRetry(normalizedError, {
60
+ duration: errorDuration,
61
+ retry
62
+ });
51
63
  }
52
64
  if (delayBetweenRetriesMs) {
53
65
  await sleep(
@@ -66,7 +78,53 @@ async function retryOnError(fn, maxRetries, options = {}, retry = 0, originalMax
66
78
  }
67
79
  }
68
80
  }
81
+ async function retryResultOnError(fn, maxRetries, options = {}, __retry = 0, __originalMaxRetries = maxRetries) {
82
+ const { delayBetweenRetriesMs, retryCondition, onRetry } = options;
83
+ if (options.debugId) {
84
+ if (__retry > 0) {
85
+ console.info(
86
+ `Retrying ${options.debugId} (retry ${__retry}/${__originalMaxRetries}) after error`
87
+ );
88
+ }
89
+ }
90
+ const startTime = Date.now();
91
+ const result = await fn({ retry: __retry });
92
+ if (result.ok) {
93
+ return result;
94
+ }
95
+ if (maxRetries > 0 && !options.disableRetries) {
96
+ const errorDuration = Date.now() - startTime;
97
+ const shouldRetry = retryCondition ? retryCondition(result.error, {
98
+ duration: errorDuration,
99
+ retry: __retry
100
+ }) : true;
101
+ if (!shouldRetry) {
102
+ return result;
103
+ }
104
+ if (onRetry) {
105
+ onRetry(result.error, {
106
+ duration: errorDuration,
107
+ retry: __retry
108
+ });
109
+ }
110
+ if (delayBetweenRetriesMs) {
111
+ await sleep(
112
+ typeof delayBetweenRetriesMs === "function" ? delayBetweenRetriesMs(__retry) : delayBetweenRetriesMs
113
+ );
114
+ }
115
+ return retryResultOnError(
116
+ fn,
117
+ maxRetries - 1,
118
+ options,
119
+ __retry + 1,
120
+ __originalMaxRetries
121
+ );
122
+ } else {
123
+ return result;
124
+ }
125
+ }
69
126
  // Annotate the CommonJS export names for ESM import in node:
70
127
  0 && (module.exports = {
71
- retryOnError
128
+ retryOnError,
129
+ retryResultOnError
72
130
  });
@@ -1,3 +1,5 @@
1
+ import { ResultValidErrors, Result } from 't-result';
2
+
1
3
  /**
2
4
  * Configuration options for retryOnError function.
3
5
  */
@@ -5,12 +7,19 @@ type RetryOptions = {
5
7
  /** Delay between retries in milliseconds or function returning delay */
6
8
  delayBetweenRetriesMs?: number | ((retry: number) => number);
7
9
  /** Function to determine if retry should happen, receives error and duration of last attempt */
8
- retryCondition?: (error: unknown, lastAttempt: {
10
+ retryCondition?: (error: Error, lastAttempt: {
9
11
  duration: number;
10
12
  retry: number;
11
13
  }) => boolean;
12
14
  /** Optional ID for debug logging */
13
15
  debugId?: string;
16
+ /** Disable retries */
17
+ disableRetries?: boolean;
18
+ /** Function to call when retry happens */
19
+ onRetry?: (error: Error, lastAttempt: {
20
+ duration: number;
21
+ retry: number;
22
+ }) => void;
14
23
  };
15
24
  /**
16
25
  * Retries a function on error with configurable retry logic.
@@ -18,8 +27,8 @@ type RetryOptions = {
18
27
  * @param fn - Function to retry that receives context with retry count
19
28
  * @param maxRetries - Maximum number of retries
20
29
  * @param options - Configuration options
21
- * @param retry
22
- * @param originalMaxRetries
30
+ * @param retry - internal use only
31
+ * @param originalMaxRetries - internal use only
23
32
  * @returns Promise resolving to the function result or rejecting with the final error
24
33
  *
25
34
  * @example
@@ -36,5 +45,36 @@ declare function retryOnError<T>(fn: (ctx: {
36
45
  /** Current retry count, (0 for first attempt) */
37
46
  retry: number;
38
47
  }) => Promise<T>, maxRetries: number, options?: RetryOptions, retry?: number, originalMaxRetries?: number): Promise<T>;
48
+ /**
49
+ * Retries a result function on error with configurable retry logic.
50
+ *
51
+ * @param fn - Function to retry that receives context with retry count
52
+ * @param maxRetries - Maximum number of retries
53
+ * @param options - Configuration options
54
+ * @param options.delayBetweenRetriesMs
55
+ * @param options.retryCondition
56
+ * @param options.debugId
57
+ * @param options.disableRetries
58
+ * @param options.onRetry
59
+ * @param __retry - internal use only
60
+ * @param __originalMaxRetries - internal use only
61
+ * @returns Promise resolving to the function result or rejecting with the final error
62
+ */
63
+ declare function retryResultOnError<T, E extends ResultValidErrors>(fn: (ctx: {
64
+ /** Current retry count, (0 for first attempt) */
65
+ retry: number;
66
+ }) => Promise<Result<T, E>>, maxRetries: number, options?: {
67
+ delayBetweenRetriesMs?: number | ((retry: number) => number);
68
+ retryCondition?: (error: E, lastAttempt: {
69
+ duration: number;
70
+ retry: number;
71
+ }) => boolean;
72
+ debugId?: string;
73
+ disableRetries?: boolean;
74
+ onRetry?: (error: E, lastAttempt: {
75
+ duration: number;
76
+ retry: number;
77
+ }) => void;
78
+ }, __retry?: number, __originalMaxRetries?: number): Promise<Result<T, E>>;
39
79
 
40
- export { retryOnError };
80
+ export { retryOnError, retryResultOnError };
@@ -1,3 +1,5 @@
1
+ import { ResultValidErrors, Result } from 't-result';
2
+
1
3
  /**
2
4
  * Configuration options for retryOnError function.
3
5
  */
@@ -5,12 +7,19 @@ type RetryOptions = {
5
7
  /** Delay between retries in milliseconds or function returning delay */
6
8
  delayBetweenRetriesMs?: number | ((retry: number) => number);
7
9
  /** Function to determine if retry should happen, receives error and duration of last attempt */
8
- retryCondition?: (error: unknown, lastAttempt: {
10
+ retryCondition?: (error: Error, lastAttempt: {
9
11
  duration: number;
10
12
  retry: number;
11
13
  }) => boolean;
12
14
  /** Optional ID for debug logging */
13
15
  debugId?: string;
16
+ /** Disable retries */
17
+ disableRetries?: boolean;
18
+ /** Function to call when retry happens */
19
+ onRetry?: (error: Error, lastAttempt: {
20
+ duration: number;
21
+ retry: number;
22
+ }) => void;
14
23
  };
15
24
  /**
16
25
  * Retries a function on error with configurable retry logic.
@@ -18,8 +27,8 @@ type RetryOptions = {
18
27
  * @param fn - Function to retry that receives context with retry count
19
28
  * @param maxRetries - Maximum number of retries
20
29
  * @param options - Configuration options
21
- * @param retry
22
- * @param originalMaxRetries
30
+ * @param retry - internal use only
31
+ * @param originalMaxRetries - internal use only
23
32
  * @returns Promise resolving to the function result or rejecting with the final error
24
33
  *
25
34
  * @example
@@ -36,5 +45,36 @@ declare function retryOnError<T>(fn: (ctx: {
36
45
  /** Current retry count, (0 for first attempt) */
37
46
  retry: number;
38
47
  }) => Promise<T>, maxRetries: number, options?: RetryOptions, retry?: number, originalMaxRetries?: number): Promise<T>;
48
+ /**
49
+ * Retries a result function on error with configurable retry logic.
50
+ *
51
+ * @param fn - Function to retry that receives context with retry count
52
+ * @param maxRetries - Maximum number of retries
53
+ * @param options - Configuration options
54
+ * @param options.delayBetweenRetriesMs
55
+ * @param options.retryCondition
56
+ * @param options.debugId
57
+ * @param options.disableRetries
58
+ * @param options.onRetry
59
+ * @param __retry - internal use only
60
+ * @param __originalMaxRetries - internal use only
61
+ * @returns Promise resolving to the function result or rejecting with the final error
62
+ */
63
+ declare function retryResultOnError<T, E extends ResultValidErrors>(fn: (ctx: {
64
+ /** Current retry count, (0 for first attempt) */
65
+ retry: number;
66
+ }) => Promise<Result<T, E>>, maxRetries: number, options?: {
67
+ delayBetweenRetriesMs?: number | ((retry: number) => number);
68
+ retryCondition?: (error: E, lastAttempt: {
69
+ duration: number;
70
+ retry: number;
71
+ }) => boolean;
72
+ debugId?: string;
73
+ disableRetries?: boolean;
74
+ onRetry?: (error: E, lastAttempt: {
75
+ duration: number;
76
+ retry: number;
77
+ }) => void;
78
+ }, __retry?: number, __originalMaxRetries?: number): Promise<Result<T, E>>;
39
79
 
40
- export { retryOnError };
80
+ export { retryOnError, retryResultOnError };
@@ -3,8 +3,9 @@ import {
3
3
  } from "./chunk-5DZT3Z5Z.js";
4
4
 
5
5
  // src/retryOnError.ts
6
+ import { unknownToError } from "t-result";
6
7
  async function retryOnError(fn, maxRetries, options = {}, retry = 0, originalMaxRetries = maxRetries) {
7
- const { delayBetweenRetriesMs, retryCondition } = options;
8
+ const { delayBetweenRetriesMs, retryCondition, disableRetries, onRetry } = options;
8
9
  if (options.debugId) {
9
10
  if (retry > 0) {
10
11
  console.info(
@@ -16,11 +17,21 @@ async function retryOnError(fn, maxRetries, options = {}, retry = 0, originalMax
16
17
  try {
17
18
  return await fn({ retry });
18
19
  } catch (error) {
19
- if (maxRetries > 0) {
20
+ if (maxRetries > 0 && !disableRetries) {
20
21
  const errorDuration = Date.now() - startTime;
21
- const shouldRetry = retryCondition ? retryCondition(error, { duration: errorDuration, retry }) : true;
22
+ const normalizedError = unknownToError(error);
23
+ const shouldRetry = retryCondition ? retryCondition(normalizedError, {
24
+ duration: errorDuration,
25
+ retry
26
+ }) : true;
22
27
  if (!shouldRetry) {
23
- throw error;
28
+ throw normalizedError;
29
+ }
30
+ if (onRetry) {
31
+ onRetry(normalizedError, {
32
+ duration: errorDuration,
33
+ retry
34
+ });
24
35
  }
25
36
  if (delayBetweenRetriesMs) {
26
37
  await sleep(
@@ -39,6 +50,52 @@ async function retryOnError(fn, maxRetries, options = {}, retry = 0, originalMax
39
50
  }
40
51
  }
41
52
  }
53
+ async function retryResultOnError(fn, maxRetries, options = {}, __retry = 0, __originalMaxRetries = maxRetries) {
54
+ const { delayBetweenRetriesMs, retryCondition, onRetry } = options;
55
+ if (options.debugId) {
56
+ if (__retry > 0) {
57
+ console.info(
58
+ `Retrying ${options.debugId} (retry ${__retry}/${__originalMaxRetries}) after error`
59
+ );
60
+ }
61
+ }
62
+ const startTime = Date.now();
63
+ const result = await fn({ retry: __retry });
64
+ if (result.ok) {
65
+ return result;
66
+ }
67
+ if (maxRetries > 0 && !options.disableRetries) {
68
+ const errorDuration = Date.now() - startTime;
69
+ const shouldRetry = retryCondition ? retryCondition(result.error, {
70
+ duration: errorDuration,
71
+ retry: __retry
72
+ }) : true;
73
+ if (!shouldRetry) {
74
+ return result;
75
+ }
76
+ if (onRetry) {
77
+ onRetry(result.error, {
78
+ duration: errorDuration,
79
+ retry: __retry
80
+ });
81
+ }
82
+ if (delayBetweenRetriesMs) {
83
+ await sleep(
84
+ typeof delayBetweenRetriesMs === "function" ? delayBetweenRetriesMs(__retry) : delayBetweenRetriesMs
85
+ );
86
+ }
87
+ return retryResultOnError(
88
+ fn,
89
+ maxRetries - 1,
90
+ options,
91
+ __retry + 1,
92
+ __originalMaxRetries
93
+ );
94
+ } else {
95
+ return result;
96
+ }
97
+ }
42
98
  export {
43
- retryOnError
99
+ retryOnError,
100
+ retryResultOnError
44
101
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ls-stack/utils",
3
3
  "description": "Universal TypeScript utilities for browser and Node.js",
4
- "version": "3.28.0",
4
+ "version": "3.30.0",
5
5
  "license": "MIT",
6
6
  "files": [
7
7
  "lib",