async-flex-loop 1.0.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.
@@ -0,0 +1,282 @@
1
+ /**
2
+ * Result of a task - similar to Promise.allSettled()
3
+ */
4
+ type TaskResult<T, I = unknown> = {
5
+ status: "fulfilled";
6
+ value: T;
7
+ index: number;
8
+ } | {
9
+ status: "rejected";
10
+ reason: Error;
11
+ item: I;
12
+ index: number;
13
+ };
14
+ /**
15
+ * Item in the internal queue with metadata
16
+ */
17
+ interface QueueItem<T> {
18
+ item: T;
19
+ index: number;
20
+ retryCount: number;
21
+ addedAt: number;
22
+ }
23
+ interface QueueStats {
24
+ totalProcessed: number;
25
+ totalSuccess: number;
26
+ totalFailed: number;
27
+ avgProcessingTime: number;
28
+ successRate: number;
29
+ }
30
+ /**
31
+ * Options for AsyncFlexLoop (does not include initialItems and onItem - those are passed via constructor)
32
+ */
33
+ interface AsyncFlexLoopOptions<InputType, ResponseType> {
34
+ /**
35
+ * Number of tasks that run concurrently
36
+ * @default Infinity
37
+ */
38
+ concurrency?: number;
39
+ /**
40
+ * Automatically start processing after construction
41
+ * @default true
42
+ */
43
+ autoStart?: boolean;
44
+ /**
45
+ * Number of retries when a task fails
46
+ * @default 0
47
+ */
48
+ retry?: number;
49
+ /**
50
+ * Delay between retries (ms)
51
+ * @default 0
52
+ */
53
+ retryDelay?: number;
54
+ /**
55
+ * Exponential backoff multiplier for retry
56
+ * @default 1 (no backoff)
57
+ */
58
+ retryBackoff?: number;
59
+ /**
60
+ * Delay after each task completes (ms)
61
+ * @default 0
62
+ */
63
+ delayAfterTask?: number;
64
+ /**
65
+ * Timeout for each task (ms)
66
+ * @default undefined (no timeout)
67
+ */
68
+ timeout?: number;
69
+ /**
70
+ * Yield to the event loop (setTimeout(0)) to reduce blocking
71
+ * @default true
72
+ */
73
+ yieldLoop?: boolean;
74
+ /**
75
+ * Throw error and stop the queue when an error occurs
76
+ * @default true
77
+ */
78
+ throwOnError?: boolean;
79
+ /**
80
+ * Callback when an error occurs
81
+ * @param this - AsyncFlexLoop instance for accessing queue methods
82
+ */
83
+ onError?: (this: any, error: Error, item: InputType, index: number) => void | Promise<void>;
84
+ /**
85
+ * Callback when a task completes
86
+ * @param this - AsyncFlexLoop instance for accessing queue methods
87
+ */
88
+ onTaskComplete?: (this: any, result: ResponseType | undefined, item: InputType, index: number) => Promise<void>;
89
+ /**
90
+ * Callback for progress updates
91
+ * @param this - AsyncFlexLoop instance for accessing queue methods
92
+ */
93
+ onProgress?: (this: any) => Promise<void>;
94
+ /**
95
+ * Callback when the queue becomes idle (all items processed)
96
+ * @param this - AsyncFlexLoop instance for accessing queue methods
97
+ */
98
+ onIdle?: (this: any) => void | Promise<void>;
99
+ }
100
+
101
+ declare enum QueueState {
102
+ Idle = "idle",
103
+ Pending = "pending",
104
+ Processing = "processing",
105
+ Paused = "paused"
106
+ }
107
+
108
+ /**
109
+ * AsyncFlexLoop - Flexible async array processing with dynamic concurrency
110
+ *
111
+ * @example
112
+ * ```typescript
113
+ * const queue = new AsyncFlexLoop(
114
+ * [1, 2, 3],
115
+ * async (item) => item * 2,
116
+ * { concurrency: 2 }
117
+ * );
118
+ *
119
+ * await queue.onIdle();
120
+ * const results = await queue.getResults();
121
+ * ```
122
+ */
123
+ declare class AsyncFlexLoop<InputType, ResponseType> {
124
+ private state;
125
+ private queue;
126
+ private activeCount;
127
+ private nextIndex;
128
+ private readonly results;
129
+ private idleResolvers;
130
+ private idleRejectors;
131
+ private readonly stats;
132
+ private readonly onItemHandler;
133
+ private readonly options;
134
+ /**
135
+ * Constructor with required parameters
136
+ */
137
+ constructor(initialItems: InputType[], onItem: (item: InputType, index: number) => Promise<ResponseType>, options?: AsyncFlexLoopOptions<InputType, ResponseType>);
138
+ /**
139
+ * Add items to the queue
140
+ * @returns Array of assigned indices
141
+ */
142
+ push(...items: InputType[]): number[];
143
+ /**
144
+ * Start processing the queue
145
+ */
146
+ start(): void;
147
+ /**
148
+ * Pause processing (currently running tasks will finish)
149
+ */
150
+ pause(): void;
151
+ /**
152
+ * Resume processing after a pause
153
+ */
154
+ resume(): void;
155
+ /**
156
+ * Clear all remaining items in the queue
157
+ */
158
+ clear(): void;
159
+ /**
160
+ * Wait until the queue is empty and all tasks have completed
161
+ */
162
+ onIdle(): Promise<void>;
163
+ getNextItem(): InputType | undefined;
164
+ /**
165
+ * Get results (waits for queue to finish)
166
+ * @returns Array with undefined for failed tasks
167
+ */
168
+ getResults(): Promise<(ResponseType | undefined)[]>;
169
+ /**
170
+ * Get raw results with full information (waits for queue to finish)
171
+ */
172
+ getRawResults(): Promise<TaskResult<ResponseType, InputType>[]>;
173
+ /**
174
+ * Get only successful results (waits for queue to finish)
175
+ */
176
+ getCompletedResultsAsync(): Promise<ResponseType[]>;
177
+ /**
178
+ * Get current successful results (does not wait)
179
+ */
180
+ getCompletedResults(): ResponseType[];
181
+ /**
182
+ * Number of items remaining in the queue
183
+ */
184
+ getPendingCount(): number;
185
+ /**
186
+ * Number of items that have been processed
187
+ */
188
+ getProcessedCount(): number;
189
+ /**
190
+ * Check whether the queue is currently processing
191
+ */
192
+ isRunning(): boolean;
193
+ /**
194
+ * Get the current state
195
+ */
196
+ getState(): QueueState;
197
+ /**
198
+ * Get statistics
199
+ */
200
+ getStats(): QueueStats;
201
+ /**
202
+ * Process the next items if there are available slots
203
+ */
204
+ private processNext;
205
+ /**
206
+ * Process a single item
207
+ */
208
+ private processItem;
209
+ /**
210
+ * Execute the task with optional timeout
211
+ */
212
+ private executeTask;
213
+ /**
214
+ * Handle successful task execution
215
+ */
216
+ private handleSuccess;
217
+ /**
218
+ * Handle task execution error
219
+ */
220
+ private handleError;
221
+ /**
222
+ * Finalize task processing
223
+ */
224
+ private finalizeTask;
225
+ /**
226
+ * Schedule a retry for a failed task
227
+ */
228
+ private scheduleRetry;
229
+ /**
230
+ * Record successful result
231
+ */
232
+ private recordSuccess;
233
+ /**
234
+ * Record failed result
235
+ */
236
+ private recordFailure;
237
+ /**
238
+ * Update statistics
239
+ */
240
+ private updateStats;
241
+ /**
242
+ * Handle fatal error (throwOnError=true)
243
+ */
244
+ private handleFatalError;
245
+ /**
246
+ * Check if queue is idle
247
+ */
248
+ private checkIdle;
249
+ /**
250
+ * Resolve all idle waiters
251
+ */
252
+ private resolveIdleWaiters;
253
+ /**
254
+ * Build results array maintaining order
255
+ */
256
+ private buildResultsArray;
257
+ }
258
+
259
+ declare class TimeoutError extends Error {
260
+ readonly item: unknown;
261
+ readonly index: number;
262
+ readonly timeoutMs: number;
263
+ constructor(item: unknown, index: number, timeoutMs: number);
264
+ }
265
+ declare class MaxRetryError extends Error {
266
+ readonly item: unknown;
267
+ readonly index: number;
268
+ readonly retryCount: number;
269
+ readonly originalError: Error;
270
+ constructor(item: unknown, index: number, retryCount: number, originalError: Error);
271
+ }
272
+ declare class QueueAbortError extends Error {
273
+ constructor(message?: string);
274
+ }
275
+
276
+ declare const delay: (ms: number) => Promise<void>;
277
+ declare const yieldToEventLoop: () => Promise<void>;
278
+ declare const calculateRetryDelay: (baseDelay: number, backoff: number, attemptNumber: number) => number;
279
+
280
+ declare const withTimeout: <T>(promise: Promise<T>, ms: number, item: unknown, index: number) => Promise<T>;
281
+
282
+ export { AsyncFlexLoop, type AsyncFlexLoopOptions, MaxRetryError, QueueAbortError, type QueueItem, QueueState, type QueueStats, type TaskResult, TimeoutError, calculateRetryDelay, delay, withTimeout, yieldToEventLoop };
@@ -0,0 +1,282 @@
1
+ /**
2
+ * Result of a task - similar to Promise.allSettled()
3
+ */
4
+ type TaskResult<T, I = unknown> = {
5
+ status: "fulfilled";
6
+ value: T;
7
+ index: number;
8
+ } | {
9
+ status: "rejected";
10
+ reason: Error;
11
+ item: I;
12
+ index: number;
13
+ };
14
+ /**
15
+ * Item in the internal queue with metadata
16
+ */
17
+ interface QueueItem<T> {
18
+ item: T;
19
+ index: number;
20
+ retryCount: number;
21
+ addedAt: number;
22
+ }
23
+ interface QueueStats {
24
+ totalProcessed: number;
25
+ totalSuccess: number;
26
+ totalFailed: number;
27
+ avgProcessingTime: number;
28
+ successRate: number;
29
+ }
30
+ /**
31
+ * Options for AsyncFlexLoop (does not include initialItems and onItem - those are passed via constructor)
32
+ */
33
+ interface AsyncFlexLoopOptions<InputType, ResponseType> {
34
+ /**
35
+ * Number of tasks that run concurrently
36
+ * @default Infinity
37
+ */
38
+ concurrency?: number;
39
+ /**
40
+ * Automatically start processing after construction
41
+ * @default true
42
+ */
43
+ autoStart?: boolean;
44
+ /**
45
+ * Number of retries when a task fails
46
+ * @default 0
47
+ */
48
+ retry?: number;
49
+ /**
50
+ * Delay between retries (ms)
51
+ * @default 0
52
+ */
53
+ retryDelay?: number;
54
+ /**
55
+ * Exponential backoff multiplier for retry
56
+ * @default 1 (no backoff)
57
+ */
58
+ retryBackoff?: number;
59
+ /**
60
+ * Delay after each task completes (ms)
61
+ * @default 0
62
+ */
63
+ delayAfterTask?: number;
64
+ /**
65
+ * Timeout for each task (ms)
66
+ * @default undefined (no timeout)
67
+ */
68
+ timeout?: number;
69
+ /**
70
+ * Yield to the event loop (setTimeout(0)) to reduce blocking
71
+ * @default true
72
+ */
73
+ yieldLoop?: boolean;
74
+ /**
75
+ * Throw error and stop the queue when an error occurs
76
+ * @default true
77
+ */
78
+ throwOnError?: boolean;
79
+ /**
80
+ * Callback when an error occurs
81
+ * @param this - AsyncFlexLoop instance for accessing queue methods
82
+ */
83
+ onError?: (this: any, error: Error, item: InputType, index: number) => void | Promise<void>;
84
+ /**
85
+ * Callback when a task completes
86
+ * @param this - AsyncFlexLoop instance for accessing queue methods
87
+ */
88
+ onTaskComplete?: (this: any, result: ResponseType | undefined, item: InputType, index: number) => Promise<void>;
89
+ /**
90
+ * Callback for progress updates
91
+ * @param this - AsyncFlexLoop instance for accessing queue methods
92
+ */
93
+ onProgress?: (this: any) => Promise<void>;
94
+ /**
95
+ * Callback when the queue becomes idle (all items processed)
96
+ * @param this - AsyncFlexLoop instance for accessing queue methods
97
+ */
98
+ onIdle?: (this: any) => void | Promise<void>;
99
+ }
100
+
101
+ declare enum QueueState {
102
+ Idle = "idle",
103
+ Pending = "pending",
104
+ Processing = "processing",
105
+ Paused = "paused"
106
+ }
107
+
108
+ /**
109
+ * AsyncFlexLoop - Flexible async array processing with dynamic concurrency
110
+ *
111
+ * @example
112
+ * ```typescript
113
+ * const queue = new AsyncFlexLoop(
114
+ * [1, 2, 3],
115
+ * async (item) => item * 2,
116
+ * { concurrency: 2 }
117
+ * );
118
+ *
119
+ * await queue.onIdle();
120
+ * const results = await queue.getResults();
121
+ * ```
122
+ */
123
+ declare class AsyncFlexLoop<InputType, ResponseType> {
124
+ private state;
125
+ private queue;
126
+ private activeCount;
127
+ private nextIndex;
128
+ private readonly results;
129
+ private idleResolvers;
130
+ private idleRejectors;
131
+ private readonly stats;
132
+ private readonly onItemHandler;
133
+ private readonly options;
134
+ /**
135
+ * Constructor with required parameters
136
+ */
137
+ constructor(initialItems: InputType[], onItem: (item: InputType, index: number) => Promise<ResponseType>, options?: AsyncFlexLoopOptions<InputType, ResponseType>);
138
+ /**
139
+ * Add items to the queue
140
+ * @returns Array of assigned indices
141
+ */
142
+ push(...items: InputType[]): number[];
143
+ /**
144
+ * Start processing the queue
145
+ */
146
+ start(): void;
147
+ /**
148
+ * Pause processing (currently running tasks will finish)
149
+ */
150
+ pause(): void;
151
+ /**
152
+ * Resume processing after a pause
153
+ */
154
+ resume(): void;
155
+ /**
156
+ * Clear all remaining items in the queue
157
+ */
158
+ clear(): void;
159
+ /**
160
+ * Wait until the queue is empty and all tasks have completed
161
+ */
162
+ onIdle(): Promise<void>;
163
+ getNextItem(): InputType | undefined;
164
+ /**
165
+ * Get results (waits for queue to finish)
166
+ * @returns Array with undefined for failed tasks
167
+ */
168
+ getResults(): Promise<(ResponseType | undefined)[]>;
169
+ /**
170
+ * Get raw results with full information (waits for queue to finish)
171
+ */
172
+ getRawResults(): Promise<TaskResult<ResponseType, InputType>[]>;
173
+ /**
174
+ * Get only successful results (waits for queue to finish)
175
+ */
176
+ getCompletedResultsAsync(): Promise<ResponseType[]>;
177
+ /**
178
+ * Get current successful results (does not wait)
179
+ */
180
+ getCompletedResults(): ResponseType[];
181
+ /**
182
+ * Number of items remaining in the queue
183
+ */
184
+ getPendingCount(): number;
185
+ /**
186
+ * Number of items that have been processed
187
+ */
188
+ getProcessedCount(): number;
189
+ /**
190
+ * Check whether the queue is currently processing
191
+ */
192
+ isRunning(): boolean;
193
+ /**
194
+ * Get the current state
195
+ */
196
+ getState(): QueueState;
197
+ /**
198
+ * Get statistics
199
+ */
200
+ getStats(): QueueStats;
201
+ /**
202
+ * Process the next items if there are available slots
203
+ */
204
+ private processNext;
205
+ /**
206
+ * Process a single item
207
+ */
208
+ private processItem;
209
+ /**
210
+ * Execute the task with optional timeout
211
+ */
212
+ private executeTask;
213
+ /**
214
+ * Handle successful task execution
215
+ */
216
+ private handleSuccess;
217
+ /**
218
+ * Handle task execution error
219
+ */
220
+ private handleError;
221
+ /**
222
+ * Finalize task processing
223
+ */
224
+ private finalizeTask;
225
+ /**
226
+ * Schedule a retry for a failed task
227
+ */
228
+ private scheduleRetry;
229
+ /**
230
+ * Record successful result
231
+ */
232
+ private recordSuccess;
233
+ /**
234
+ * Record failed result
235
+ */
236
+ private recordFailure;
237
+ /**
238
+ * Update statistics
239
+ */
240
+ private updateStats;
241
+ /**
242
+ * Handle fatal error (throwOnError=true)
243
+ */
244
+ private handleFatalError;
245
+ /**
246
+ * Check if queue is idle
247
+ */
248
+ private checkIdle;
249
+ /**
250
+ * Resolve all idle waiters
251
+ */
252
+ private resolveIdleWaiters;
253
+ /**
254
+ * Build results array maintaining order
255
+ */
256
+ private buildResultsArray;
257
+ }
258
+
259
+ declare class TimeoutError extends Error {
260
+ readonly item: unknown;
261
+ readonly index: number;
262
+ readonly timeoutMs: number;
263
+ constructor(item: unknown, index: number, timeoutMs: number);
264
+ }
265
+ declare class MaxRetryError extends Error {
266
+ readonly item: unknown;
267
+ readonly index: number;
268
+ readonly retryCount: number;
269
+ readonly originalError: Error;
270
+ constructor(item: unknown, index: number, retryCount: number, originalError: Error);
271
+ }
272
+ declare class QueueAbortError extends Error {
273
+ constructor(message?: string);
274
+ }
275
+
276
+ declare const delay: (ms: number) => Promise<void>;
277
+ declare const yieldToEventLoop: () => Promise<void>;
278
+ declare const calculateRetryDelay: (baseDelay: number, backoff: number, attemptNumber: number) => number;
279
+
280
+ declare const withTimeout: <T>(promise: Promise<T>, ms: number, item: unknown, index: number) => Promise<T>;
281
+
282
+ export { AsyncFlexLoop, type AsyncFlexLoopOptions, MaxRetryError, QueueAbortError, type QueueItem, QueueState, type QueueStats, type TaskResult, TimeoutError, calculateRetryDelay, delay, withTimeout, yieldToEventLoop };