@tanstack/pacer 0.16.3 → 0.16.4

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.
Files changed (169) hide show
  1. package/README.md +165 -0
  2. package/dist/async-batcher.cjs +355 -0
  3. package/dist/async-batcher.cjs.map +1 -0
  4. package/dist/async-batcher.d.cts +344 -0
  5. package/dist/async-batcher.d.ts +344 -0
  6. package/dist/async-batcher.js +353 -0
  7. package/dist/async-batcher.js.map +1 -0
  8. package/dist/async-debouncer.cjs +340 -0
  9. package/dist/async-debouncer.cjs.map +1 -0
  10. package/dist/async-debouncer.d.cts +300 -0
  11. package/dist/async-debouncer.d.ts +300 -0
  12. package/dist/async-debouncer.js +338 -0
  13. package/dist/async-debouncer.js.map +1 -0
  14. package/dist/async-queuer.cjs +496 -0
  15. package/dist/async-queuer.cjs.map +1 -0
  16. package/dist/async-queuer.d.cts +440 -0
  17. package/dist/async-queuer.d.ts +440 -0
  18. package/dist/async-queuer.js +494 -0
  19. package/dist/async-queuer.js.map +1 -0
  20. package/dist/async-rate-limiter.cjs +381 -0
  21. package/dist/async-rate-limiter.cjs.map +1 -0
  22. package/dist/{cjs/async-rate-limiter.d.cts → async-rate-limiter.d.cts} +190 -185
  23. package/dist/{esm/async-rate-limiter.d.ts → async-rate-limiter.d.ts} +190 -185
  24. package/dist/async-rate-limiter.js +379 -0
  25. package/dist/async-rate-limiter.js.map +1 -0
  26. package/dist/async-retryer.cjs +378 -0
  27. package/dist/async-retryer.cjs.map +1 -0
  28. package/dist/async-retryer.d.cts +312 -0
  29. package/dist/async-retryer.d.ts +312 -0
  30. package/dist/async-retryer.js +376 -0
  31. package/dist/async-retryer.js.map +1 -0
  32. package/dist/async-throttler.cjs +362 -0
  33. package/dist/async-throttler.cjs.map +1 -0
  34. package/dist/async-throttler.d.cts +320 -0
  35. package/dist/async-throttler.d.ts +320 -0
  36. package/dist/async-throttler.js +360 -0
  37. package/dist/async-throttler.js.map +1 -0
  38. package/dist/batcher.cjs +194 -0
  39. package/dist/batcher.cjs.map +1 -0
  40. package/dist/batcher.d.cts +180 -0
  41. package/dist/batcher.d.ts +180 -0
  42. package/dist/batcher.js +193 -0
  43. package/dist/batcher.js.map +1 -0
  44. package/dist/debouncer.cjs +197 -0
  45. package/dist/debouncer.cjs.map +1 -0
  46. package/dist/debouncer.d.cts +167 -0
  47. package/dist/debouncer.d.ts +167 -0
  48. package/dist/debouncer.js +195 -0
  49. package/dist/debouncer.js.map +1 -0
  50. package/dist/event-client.cjs +20 -0
  51. package/dist/event-client.cjs.map +1 -0
  52. package/dist/event-client.d.cts +49 -0
  53. package/dist/event-client.d.ts +49 -0
  54. package/dist/event-client.js +19 -0
  55. package/dist/event-client.js.map +1 -0
  56. package/dist/index.cjs +49 -0
  57. package/dist/index.d.cts +15 -0
  58. package/dist/index.d.ts +15 -0
  59. package/dist/{esm/index.js → index.js} +5 -41
  60. package/dist/queuer.cjs +393 -0
  61. package/dist/queuer.cjs.map +1 -0
  62. package/dist/queuer.d.cts +345 -0
  63. package/dist/queuer.d.ts +345 -0
  64. package/dist/queuer.js +391 -0
  65. package/dist/queuer.js.map +1 -0
  66. package/dist/rate-limiter.cjs +251 -0
  67. package/dist/rate-limiter.cjs.map +1 -0
  68. package/dist/{cjs/rate-limiter.d.cts → rate-limiter.d.cts} +113 -108
  69. package/dist/{esm/rate-limiter.d.ts → rate-limiter.d.ts} +113 -108
  70. package/dist/rate-limiter.js +249 -0
  71. package/dist/rate-limiter.js.map +1 -0
  72. package/dist/throttler.cjs +209 -0
  73. package/dist/throttler.cjs.map +1 -0
  74. package/dist/throttler.d.cts +207 -0
  75. package/dist/throttler.d.ts +207 -0
  76. package/dist/throttler.js +207 -0
  77. package/dist/throttler.js.map +1 -0
  78. package/dist/types.cjs +0 -0
  79. package/dist/types.d.cts +13 -0
  80. package/dist/types.d.ts +13 -0
  81. package/dist/types.js +1 -0
  82. package/dist/utils.cjs +13 -0
  83. package/dist/utils.cjs.map +1 -0
  84. package/dist/utils.d.cts +8 -0
  85. package/dist/utils.d.ts +8 -0
  86. package/dist/utils.js +11 -0
  87. package/dist/utils.js.map +1 -0
  88. package/package.json +38 -122
  89. package/dist/cjs/async-batcher.cjs +0 -222
  90. package/dist/cjs/async-batcher.cjs.map +0 -1
  91. package/dist/cjs/async-batcher.d.cts +0 -340
  92. package/dist/cjs/async-debouncer.cjs +0 -233
  93. package/dist/cjs/async-debouncer.cjs.map +0 -1
  94. package/dist/cjs/async-debouncer.d.cts +0 -295
  95. package/dist/cjs/async-queuer.cjs +0 -399
  96. package/dist/cjs/async-queuer.cjs.map +0 -1
  97. package/dist/cjs/async-queuer.d.cts +0 -435
  98. package/dist/cjs/async-rate-limiter.cjs +0 -254
  99. package/dist/cjs/async-rate-limiter.cjs.map +0 -1
  100. package/dist/cjs/async-retryer.cjs +0 -287
  101. package/dist/cjs/async-retryer.cjs.map +0 -1
  102. package/dist/cjs/async-retryer.d.cts +0 -308
  103. package/dist/cjs/async-throttler.cjs +0 -263
  104. package/dist/cjs/async-throttler.cjs.map +0 -1
  105. package/dist/cjs/async-throttler.d.cts +0 -315
  106. package/dist/cjs/batcher.cjs +0 -132
  107. package/dist/cjs/batcher.cjs.map +0 -1
  108. package/dist/cjs/batcher.d.cts +0 -176
  109. package/dist/cjs/debouncer.cjs +0 -139
  110. package/dist/cjs/debouncer.cjs.map +0 -1
  111. package/dist/cjs/debouncer.d.cts +0 -162
  112. package/dist/cjs/event-client.cjs +0 -20
  113. package/dist/cjs/event-client.cjs.map +0 -1
  114. package/dist/cjs/event-client.d.cts +0 -45
  115. package/dist/cjs/index.cjs +0 -51
  116. package/dist/cjs/index.cjs.map +0 -1
  117. package/dist/cjs/index.d.cts +0 -15
  118. package/dist/cjs/queuer.cjs +0 -308
  119. package/dist/cjs/queuer.cjs.map +0 -1
  120. package/dist/cjs/queuer.d.cts +0 -340
  121. package/dist/cjs/rate-limiter.cjs +0 -181
  122. package/dist/cjs/rate-limiter.cjs.map +0 -1
  123. package/dist/cjs/throttler.cjs +0 -153
  124. package/dist/cjs/throttler.cjs.map +0 -1
  125. package/dist/cjs/throttler.d.cts +0 -202
  126. package/dist/cjs/types.d.cts +0 -9
  127. package/dist/cjs/utils.cjs +0 -11
  128. package/dist/cjs/utils.cjs.map +0 -1
  129. package/dist/cjs/utils.d.cts +0 -3
  130. package/dist/esm/async-batcher.d.ts +0 -340
  131. package/dist/esm/async-batcher.js +0 -222
  132. package/dist/esm/async-batcher.js.map +0 -1
  133. package/dist/esm/async-debouncer.d.ts +0 -295
  134. package/dist/esm/async-debouncer.js +0 -233
  135. package/dist/esm/async-debouncer.js.map +0 -1
  136. package/dist/esm/async-queuer.d.ts +0 -435
  137. package/dist/esm/async-queuer.js +0 -399
  138. package/dist/esm/async-queuer.js.map +0 -1
  139. package/dist/esm/async-rate-limiter.js +0 -254
  140. package/dist/esm/async-rate-limiter.js.map +0 -1
  141. package/dist/esm/async-retryer.d.ts +0 -308
  142. package/dist/esm/async-retryer.js +0 -287
  143. package/dist/esm/async-retryer.js.map +0 -1
  144. package/dist/esm/async-throttler.d.ts +0 -315
  145. package/dist/esm/async-throttler.js +0 -263
  146. package/dist/esm/async-throttler.js.map +0 -1
  147. package/dist/esm/batcher.d.ts +0 -176
  148. package/dist/esm/batcher.js +0 -132
  149. package/dist/esm/batcher.js.map +0 -1
  150. package/dist/esm/debouncer.d.ts +0 -162
  151. package/dist/esm/debouncer.js +0 -139
  152. package/dist/esm/debouncer.js.map +0 -1
  153. package/dist/esm/event-client.d.ts +0 -45
  154. package/dist/esm/event-client.js +0 -20
  155. package/dist/esm/event-client.js.map +0 -1
  156. package/dist/esm/index.d.ts +0 -15
  157. package/dist/esm/index.js.map +0 -1
  158. package/dist/esm/queuer.d.ts +0 -340
  159. package/dist/esm/queuer.js +0 -308
  160. package/dist/esm/queuer.js.map +0 -1
  161. package/dist/esm/rate-limiter.js +0 -181
  162. package/dist/esm/rate-limiter.js.map +0 -1
  163. package/dist/esm/throttler.d.ts +0 -202
  164. package/dist/esm/throttler.js +0 -153
  165. package/dist/esm/throttler.js.map +0 -1
  166. package/dist/esm/types.d.ts +0 -9
  167. package/dist/esm/utils.d.ts +0 -3
  168. package/dist/esm/utils.js +0 -11
  169. package/dist/esm/utils.js.map +0 -1
@@ -0,0 +1,344 @@
1
+ import { OptionalKeys } from "./types.cjs";
2
+ import { AsyncRetryer, AsyncRetryerOptions } from "./async-retryer.cjs";
3
+ import { Store } from "@tanstack/store";
4
+
5
+ //#region src/async-batcher.d.ts
6
+ interface AsyncBatcherState<TValue> {
7
+ /**
8
+ * Number of batch executions that have resulted in errors
9
+ */
10
+ errorCount: number;
11
+ /**
12
+ * Number of batch executions that have been executed
13
+ */
14
+ executeCount: number;
15
+ /**
16
+ * Array of items that failed during batch processing
17
+ */
18
+ failedItems: Array<TValue>;
19
+ /**
20
+ * Whether the batcher has no items to process (items array is empty)
21
+ */
22
+ isEmpty: boolean;
23
+ /**
24
+ * Whether a batch is currently being processed asynchronously
25
+ */
26
+ isExecuting: boolean;
27
+ /**
28
+ * Whether the batcher is waiting for the timeout to trigger batch processing
29
+ */
30
+ isPending: boolean;
31
+ /**
32
+ * Array of items currently queued for batch processing
33
+ */
34
+ items: Array<TValue>;
35
+ /**
36
+ * The result from the most recent batch execution
37
+ */
38
+ lastResult: any;
39
+ /**
40
+ * Number of batch executions that have completed (either successfully or with errors)
41
+ */
42
+ settleCount: number;
43
+ /**
44
+ * Number of items currently in the batch queue
45
+ */
46
+ size: number;
47
+ /**
48
+ * Current processing status - 'idle' when not processing, 'pending' when waiting for timeout, 'executing' when processing, 'populated' when items are present, but no wait is configured
49
+ */
50
+ status: 'idle' | 'pending' | 'executing' | 'populated';
51
+ /**
52
+ * Number of batch executions that have completed successfully
53
+ */
54
+ successCount: number;
55
+ /**
56
+ * Total number of items that have failed processing across all batches
57
+ */
58
+ totalItemsFailed: number;
59
+ /**
60
+ * Total number of items that have been processed across all batches
61
+ */
62
+ totalItemsProcessed: number;
63
+ }
64
+ /**
65
+ * Options for configuring an AsyncBatcher instance
66
+ */
67
+ interface AsyncBatcherOptions<TValue> {
68
+ /**
69
+ * Options for configuring the underlying async retryer
70
+ */
71
+ asyncRetryerOptions?: AsyncRetryerOptions<(items: Array<TValue>) => Promise<any>>;
72
+ /**
73
+ * Custom function to determine if a batch should be processed
74
+ * Return true to process the batch immediately
75
+ */
76
+ getShouldExecute?: (items: Array<TValue>, batcher: AsyncBatcher<TValue>) => boolean;
77
+ /**
78
+ * Initial state for the async batcher
79
+ */
80
+ initialState?: Partial<AsyncBatcherState<TValue>>;
81
+ /**
82
+ * Optional key to identify this async batcher instance.
83
+ * If provided, the async batcher will be identified by this key in the devtools and PacerProvider if applicable.
84
+ */
85
+ key?: string;
86
+ /**
87
+ * Maximum number of items in a batch
88
+ * @default Infinity
89
+ */
90
+ maxSize?: number;
91
+ /**
92
+ * Optional error handler for when the batch function throws.
93
+ * If provided, the handler will be called with the error, the batch of items that failed, and batcher instance.
94
+ * This can be used alongside throwOnError - the handler will be called before any error is thrown.
95
+ */
96
+ onError?: (error: Error, batch: Array<TValue>, batcher: AsyncBatcher<TValue>) => void;
97
+ /**
98
+ * Callback fired after items are added to the batcher
99
+ */
100
+ onItemsChange?: (batcher: AsyncBatcher<TValue>) => void;
101
+ /**
102
+ * Optional callback to call when a batch is settled (completed or failed)
103
+ */
104
+ onSettled?: (batch: Array<TValue>, batcher: AsyncBatcher<TValue>) => void;
105
+ /**
106
+ * Optional callback to call when a batch succeeds
107
+ */
108
+ onSuccess?: (result: any, batch: Array<TValue>, batcher: AsyncBatcher<TValue>) => void;
109
+ /**
110
+ * Whether the batcher should start processing immediately
111
+ * @default true
112
+ */
113
+ started?: boolean;
114
+ /**
115
+ * Whether to throw errors when they occur.
116
+ * Defaults to true if no onError handler is provided, false if an onError handler is provided.
117
+ * Can be explicitly set to override these defaults.
118
+ */
119
+ throwOnError?: boolean;
120
+ /**
121
+ * Maximum time in milliseconds to wait before processing a batch.
122
+ * If the wait duration has elapsed, the batch will be processed.
123
+ * If not provided, the batch will not be triggered by a timeout.
124
+ * @default Infinity
125
+ */
126
+ wait?: number | ((asyncBatcher: AsyncBatcher<TValue>) => number);
127
+ }
128
+ /**
129
+ * Utility function for sharing common `AsyncBatcherOptions` options between different `AsyncBatcher` instances.
130
+ *
131
+ */
132
+ declare function asyncBatcherOptions<TValue = any, TOptions extends Partial<AsyncBatcherOptions<TValue>> = Partial<AsyncBatcherOptions<TValue>>>(options: TOptions): TOptions;
133
+ type AsyncBatcherOptionsWithOptionalCallbacks<TValue> = OptionalKeys<Required<AsyncBatcherOptions<TValue>>, 'initialState' | 'onError' | 'onItemsChange' | 'onSettled' | 'onSuccess' | 'key'>;
134
+ /**
135
+ * A class that collects items and processes them in batches asynchronously.
136
+ *
137
+ * Async vs Sync Versions:
138
+ * The async version provides advanced features over the sync Batcher:
139
+ * - Returns promises that can be awaited for batch results
140
+ * - Built-in retry support via AsyncRetryer integration
141
+ * - Abort support to cancel in-flight batch executions
142
+ * - Cancel support to prevent pending batches from starting
143
+ * - Comprehensive error handling with onError callbacks and throwOnError control
144
+ * - Detailed execution tracking (success/error/settle counts)
145
+ *
146
+ * The sync Batcher is lighter weight and simpler when you don't need async features,
147
+ * return values, or execution control.
148
+ *
149
+ * What is Batching?
150
+ * Batching is a technique for grouping multiple operations together to be processed as a single unit.
151
+ *
152
+ * The AsyncBatcher provides a flexible way to implement async batching with configurable:
153
+ * - Maximum batch size (number of items per batch)
154
+ * - Time-based batching (process after X milliseconds)
155
+ * - Custom batch processing logic via getShouldExecute
156
+ * - Event callbacks for monitoring batch operations
157
+ * - Error handling for failed batch operations
158
+ *
159
+ * Error Handling:
160
+ * - If an `onError` handler is provided, it will be called with the error, the batch of items that failed, and batcher instance
161
+ * - If `throwOnError` is true (default when no onError handler is provided), the error will be thrown
162
+ * - If `throwOnError` is false (default when onError handler is provided), the error will be swallowed
163
+ * - Both onError and throwOnError can be used together - the handler will be called before any error is thrown
164
+ * - The error state can be checked using the AsyncBatcher instance
165
+ *
166
+ * State Management:
167
+ * - Uses TanStack Store for reactive state management
168
+ * - Use `initialState` to provide initial state values when creating the async batcher
169
+ * - Use `onSuccess` callback to react to successful batch execution and implement custom logic
170
+ * - Use `onError` callback to react to batch execution errors and implement custom error handling
171
+ * - Use `onSettled` callback to react to batch execution completion (success or error) and implement custom logic
172
+ * - Use `onExecute` callback to react to batch execution and implement custom logic
173
+ * - Use `onItemsChange` callback to react to items being added or removed from the batcher
174
+ * - The state includes total items processed, success/error counts, and execution status
175
+ * - State can be accessed via `asyncBatcher.store.state` when using the class directly
176
+ * - When using framework adapters (React/Solid), state is accessed from `asyncBatcher.state`
177
+ *
178
+ * @example
179
+ * ```ts
180
+ * const batcher = new AsyncBatcher<number>(
181
+ * async (items) => {
182
+ * const result = await processItems(items);
183
+ * console.log('Processing batch:', items);
184
+ * return result;
185
+ * },
186
+ * {
187
+ * maxSize: 5,
188
+ * wait: 2000,
189
+ * onSuccess: (result) => console.log('Batch succeeded:', result),
190
+ * onError: (error) => console.error('Batch failed:', error)
191
+ * }
192
+ * );
193
+ *
194
+ * batcher.addItem(1);
195
+ * batcher.addItem(2);
196
+ * // After 2 seconds or when 5 items are added, whichever comes first,
197
+ * // the batch will be processed and the result will be available
198
+ * // batcher.execute() // manually trigger a batch
199
+ * ```
200
+ */
201
+ declare class AsyncBatcher<TValue> {
202
+ #private;
203
+ fn: (items: Array<TValue>) => Promise<any>;
204
+ readonly store: Store<Readonly<AsyncBatcherState<TValue>>>;
205
+ key: string | undefined;
206
+ options: AsyncBatcherOptionsWithOptionalCallbacks<TValue>;
207
+ asyncRetryers: Map<number, AsyncRetryer<(items: Array<TValue>) => Promise<any>>>;
208
+ constructor(fn: (items: Array<TValue>) => Promise<any>, initialOptions: AsyncBatcherOptions<TValue>);
209
+ /**
210
+ * Updates the async batcher options
211
+ */
212
+ setOptions: (newOptions: Partial<AsyncBatcherOptions<TValue>>) => void;
213
+ /**
214
+ * Adds an item to the async batcher
215
+ * If the batch size is reached, timeout occurs, or shouldProcess returns true, the batch will be processed
216
+ *
217
+ * @returns The result from the batch function, or undefined if an error occurred and was handled by onError
218
+ *
219
+ * @throws The error from the batch function if no onError handler is configured or throwOnError is true
220
+ */
221
+ addItem: (item: TValue) => Promise<any>;
222
+ /**
223
+ * Processes the current batch of items immediately
224
+ */
225
+ flush: () => Promise<any>;
226
+ /**
227
+ * Returns a copy of all items in the async batcher
228
+ */
229
+ peekAllItems: () => Array<TValue>;
230
+ peekFailedItems: () => Array<TValue>;
231
+ /**
232
+ * Removes all items from the async batcher
233
+ */
234
+ clear: () => void;
235
+ /**
236
+ * Returns the AbortSignal for a specific execution.
237
+ * If no executeCount is provided, returns the signal for the most recent execution.
238
+ * Returns null if no execution is found or not currently executing.
239
+ *
240
+ * @param executeCount - Optional specific execution to get signal for
241
+ * @example
242
+ * ```typescript
243
+ * const batcher = new AsyncBatcher(
244
+ * async (items: string[]) => {
245
+ * const signal = batcher.getAbortSignal()
246
+ * if (signal) {
247
+ * const response = await fetch('/api/batch', {
248
+ * method: 'POST',
249
+ * body: JSON.stringify(items),
250
+ * signal
251
+ * })
252
+ * return response.json()
253
+ * }
254
+ * },
255
+ * { maxSize: 10, wait: 100 }
256
+ * )
257
+ * ```
258
+ */
259
+ getAbortSignal(executeCount?: number): AbortSignal | null;
260
+ /**
261
+ * Aborts all ongoing executions with the internal abort controllers.
262
+ * Does NOT cancel any pending execution that have not started yet.
263
+ * Does NOT clear out the items.
264
+ */
265
+ abort: () => void;
266
+ /**
267
+ * Cancels any pending execution that have not started yet.
268
+ * Does NOT abort any execution already in progress.
269
+ * Does NOT clear out the items.
270
+ */
271
+ cancel: () => void;
272
+ /**
273
+ * Resets the async batcher state to its default values
274
+ */
275
+ reset: () => void;
276
+ }
277
+ /**
278
+ * Creates an async batcher that processes items in batches.
279
+ *
280
+ * Async vs Sync Versions:
281
+ * The async version provides advanced features over the sync batch function:
282
+ * - Returns promises that can be awaited for batch results
283
+ * - Built-in retry support via AsyncRetryer integration
284
+ * - Abort support to cancel in-flight batch executions
285
+ * - Cancel support to prevent pending batches from starting
286
+ * - Comprehensive error handling with onError callbacks and throwOnError control
287
+ * - Detailed execution tracking (success/error/settle counts)
288
+ *
289
+ * The sync batch function is lighter weight and simpler when you don't need async features,
290
+ * return values, or execution control.
291
+ *
292
+ * What is Batching?
293
+ * Batching is a technique for grouping multiple operations together to be processed as a single unit.
294
+ *
295
+ * Configuration Options:
296
+ * - `maxSize`: Maximum number of items per batch (default: Infinity)
297
+ * - `wait`: Time to wait before processing batch (default: Infinity)
298
+ * - `getShouldExecute`: Custom logic to trigger batch processing
299
+ * - `asyncRetryerOptions`: Configure retry behavior for batch executions
300
+ * - `started`: Whether to start processing immediately (default: true)
301
+ *
302
+ * Error Handling:
303
+ * - If an `onError` handler is provided, it will be called with the error, the batch of items that failed, and batcher instance
304
+ * - If `throwOnError` is true (default when no onError handler is provided), the error will be thrown
305
+ * - If `throwOnError` is false (default when onError handler is provided), the error will be swallowed
306
+ * - Both onError and throwOnError can be used together - the handler will be called before any error is thrown
307
+ * - The error state can be checked using the underlying AsyncBatcher instance
308
+ *
309
+ * State Management:
310
+ * - Uses TanStack Store for reactive state management
311
+ * - Use `initialState` to provide initial state values when creating the async batcher
312
+ * - Use `onSuccess` callback to react to successful batch execution and implement custom logic
313
+ * - Use `onError` callback to react to batch execution errors and implement custom error handling
314
+ * - Use `onSettled` callback to react to batch execution completion (success or error) and implement custom logic
315
+ * - Use `onItemsChange` callback to react to items being added or removed from the batcher
316
+ * - The state includes total items processed, success/error counts, and execution status
317
+ * - State can be accessed via the underlying AsyncBatcher instance's `store.state` property
318
+ * - When using framework adapters (React/Solid), state is accessed from the hook's state property
319
+ *
320
+ * @example
321
+ * ```ts
322
+ * const batchItems = asyncBatch<number>(
323
+ * async (items) => {
324
+ * const result = await processApiCall(items);
325
+ * console.log('Processing:', items);
326
+ * return result;
327
+ * },
328
+ * {
329
+ * maxSize: 3,
330
+ * wait: 1000,
331
+ * onSuccess: (result) => console.log('Batch succeeded:', result),
332
+ * onError: (error) => console.error('Batch failed:', error)
333
+ * }
334
+ * );
335
+ *
336
+ * batchItems(1);
337
+ * batchItems(2);
338
+ * batchItems(3); // Triggers batch processing
339
+ * ```
340
+ */
341
+ declare function asyncBatch<TValue>(fn: (items: Array<TValue>) => Promise<any>, options: AsyncBatcherOptions<TValue>): (item: TValue) => Promise<any>;
342
+ //#endregion
343
+ export { AsyncBatcher, AsyncBatcherOptions, AsyncBatcherState, asyncBatch, asyncBatcherOptions };
344
+ //# sourceMappingURL=async-batcher.d.cts.map
@@ -0,0 +1,344 @@
1
+ import { OptionalKeys } from "./types.js";
2
+ import { AsyncRetryer, AsyncRetryerOptions } from "./async-retryer.js";
3
+ import { Store } from "@tanstack/store";
4
+
5
+ //#region src/async-batcher.d.ts
6
+ interface AsyncBatcherState<TValue> {
7
+ /**
8
+ * Number of batch executions that have resulted in errors
9
+ */
10
+ errorCount: number;
11
+ /**
12
+ * Number of batch executions that have been executed
13
+ */
14
+ executeCount: number;
15
+ /**
16
+ * Array of items that failed during batch processing
17
+ */
18
+ failedItems: Array<TValue>;
19
+ /**
20
+ * Whether the batcher has no items to process (items array is empty)
21
+ */
22
+ isEmpty: boolean;
23
+ /**
24
+ * Whether a batch is currently being processed asynchronously
25
+ */
26
+ isExecuting: boolean;
27
+ /**
28
+ * Whether the batcher is waiting for the timeout to trigger batch processing
29
+ */
30
+ isPending: boolean;
31
+ /**
32
+ * Array of items currently queued for batch processing
33
+ */
34
+ items: Array<TValue>;
35
+ /**
36
+ * The result from the most recent batch execution
37
+ */
38
+ lastResult: any;
39
+ /**
40
+ * Number of batch executions that have completed (either successfully or with errors)
41
+ */
42
+ settleCount: number;
43
+ /**
44
+ * Number of items currently in the batch queue
45
+ */
46
+ size: number;
47
+ /**
48
+ * Current processing status - 'idle' when not processing, 'pending' when waiting for timeout, 'executing' when processing, 'populated' when items are present, but no wait is configured
49
+ */
50
+ status: 'idle' | 'pending' | 'executing' | 'populated';
51
+ /**
52
+ * Number of batch executions that have completed successfully
53
+ */
54
+ successCount: number;
55
+ /**
56
+ * Total number of items that have failed processing across all batches
57
+ */
58
+ totalItemsFailed: number;
59
+ /**
60
+ * Total number of items that have been processed across all batches
61
+ */
62
+ totalItemsProcessed: number;
63
+ }
64
+ /**
65
+ * Options for configuring an AsyncBatcher instance
66
+ */
67
+ interface AsyncBatcherOptions<TValue> {
68
+ /**
69
+ * Options for configuring the underlying async retryer
70
+ */
71
+ asyncRetryerOptions?: AsyncRetryerOptions<(items: Array<TValue>) => Promise<any>>;
72
+ /**
73
+ * Custom function to determine if a batch should be processed
74
+ * Return true to process the batch immediately
75
+ */
76
+ getShouldExecute?: (items: Array<TValue>, batcher: AsyncBatcher<TValue>) => boolean;
77
+ /**
78
+ * Initial state for the async batcher
79
+ */
80
+ initialState?: Partial<AsyncBatcherState<TValue>>;
81
+ /**
82
+ * Optional key to identify this async batcher instance.
83
+ * If provided, the async batcher will be identified by this key in the devtools and PacerProvider if applicable.
84
+ */
85
+ key?: string;
86
+ /**
87
+ * Maximum number of items in a batch
88
+ * @default Infinity
89
+ */
90
+ maxSize?: number;
91
+ /**
92
+ * Optional error handler for when the batch function throws.
93
+ * If provided, the handler will be called with the error, the batch of items that failed, and batcher instance.
94
+ * This can be used alongside throwOnError - the handler will be called before any error is thrown.
95
+ */
96
+ onError?: (error: Error, batch: Array<TValue>, batcher: AsyncBatcher<TValue>) => void;
97
+ /**
98
+ * Callback fired after items are added to the batcher
99
+ */
100
+ onItemsChange?: (batcher: AsyncBatcher<TValue>) => void;
101
+ /**
102
+ * Optional callback to call when a batch is settled (completed or failed)
103
+ */
104
+ onSettled?: (batch: Array<TValue>, batcher: AsyncBatcher<TValue>) => void;
105
+ /**
106
+ * Optional callback to call when a batch succeeds
107
+ */
108
+ onSuccess?: (result: any, batch: Array<TValue>, batcher: AsyncBatcher<TValue>) => void;
109
+ /**
110
+ * Whether the batcher should start processing immediately
111
+ * @default true
112
+ */
113
+ started?: boolean;
114
+ /**
115
+ * Whether to throw errors when they occur.
116
+ * Defaults to true if no onError handler is provided, false if an onError handler is provided.
117
+ * Can be explicitly set to override these defaults.
118
+ */
119
+ throwOnError?: boolean;
120
+ /**
121
+ * Maximum time in milliseconds to wait before processing a batch.
122
+ * If the wait duration has elapsed, the batch will be processed.
123
+ * If not provided, the batch will not be triggered by a timeout.
124
+ * @default Infinity
125
+ */
126
+ wait?: number | ((asyncBatcher: AsyncBatcher<TValue>) => number);
127
+ }
128
+ /**
129
+ * Utility function for sharing common `AsyncBatcherOptions` options between different `AsyncBatcher` instances.
130
+ *
131
+ */
132
+ declare function asyncBatcherOptions<TValue = any, TOptions extends Partial<AsyncBatcherOptions<TValue>> = Partial<AsyncBatcherOptions<TValue>>>(options: TOptions): TOptions;
133
+ type AsyncBatcherOptionsWithOptionalCallbacks<TValue> = OptionalKeys<Required<AsyncBatcherOptions<TValue>>, 'initialState' | 'onError' | 'onItemsChange' | 'onSettled' | 'onSuccess' | 'key'>;
134
+ /**
135
+ * A class that collects items and processes them in batches asynchronously.
136
+ *
137
+ * Async vs Sync Versions:
138
+ * The async version provides advanced features over the sync Batcher:
139
+ * - Returns promises that can be awaited for batch results
140
+ * - Built-in retry support via AsyncRetryer integration
141
+ * - Abort support to cancel in-flight batch executions
142
+ * - Cancel support to prevent pending batches from starting
143
+ * - Comprehensive error handling with onError callbacks and throwOnError control
144
+ * - Detailed execution tracking (success/error/settle counts)
145
+ *
146
+ * The sync Batcher is lighter weight and simpler when you don't need async features,
147
+ * return values, or execution control.
148
+ *
149
+ * What is Batching?
150
+ * Batching is a technique for grouping multiple operations together to be processed as a single unit.
151
+ *
152
+ * The AsyncBatcher provides a flexible way to implement async batching with configurable:
153
+ * - Maximum batch size (number of items per batch)
154
+ * - Time-based batching (process after X milliseconds)
155
+ * - Custom batch processing logic via getShouldExecute
156
+ * - Event callbacks for monitoring batch operations
157
+ * - Error handling for failed batch operations
158
+ *
159
+ * Error Handling:
160
+ * - If an `onError` handler is provided, it will be called with the error, the batch of items that failed, and batcher instance
161
+ * - If `throwOnError` is true (default when no onError handler is provided), the error will be thrown
162
+ * - If `throwOnError` is false (default when onError handler is provided), the error will be swallowed
163
+ * - Both onError and throwOnError can be used together - the handler will be called before any error is thrown
164
+ * - The error state can be checked using the AsyncBatcher instance
165
+ *
166
+ * State Management:
167
+ * - Uses TanStack Store for reactive state management
168
+ * - Use `initialState` to provide initial state values when creating the async batcher
169
+ * - Use `onSuccess` callback to react to successful batch execution and implement custom logic
170
+ * - Use `onError` callback to react to batch execution errors and implement custom error handling
171
+ * - Use `onSettled` callback to react to batch execution completion (success or error) and implement custom logic
172
+ * - Use `onExecute` callback to react to batch execution and implement custom logic
173
+ * - Use `onItemsChange` callback to react to items being added or removed from the batcher
174
+ * - The state includes total items processed, success/error counts, and execution status
175
+ * - State can be accessed via `asyncBatcher.store.state` when using the class directly
176
+ * - When using framework adapters (React/Solid), state is accessed from `asyncBatcher.state`
177
+ *
178
+ * @example
179
+ * ```ts
180
+ * const batcher = new AsyncBatcher<number>(
181
+ * async (items) => {
182
+ * const result = await processItems(items);
183
+ * console.log('Processing batch:', items);
184
+ * return result;
185
+ * },
186
+ * {
187
+ * maxSize: 5,
188
+ * wait: 2000,
189
+ * onSuccess: (result) => console.log('Batch succeeded:', result),
190
+ * onError: (error) => console.error('Batch failed:', error)
191
+ * }
192
+ * );
193
+ *
194
+ * batcher.addItem(1);
195
+ * batcher.addItem(2);
196
+ * // After 2 seconds or when 5 items are added, whichever comes first,
197
+ * // the batch will be processed and the result will be available
198
+ * // batcher.execute() // manually trigger a batch
199
+ * ```
200
+ */
201
+ declare class AsyncBatcher<TValue> {
202
+ #private;
203
+ fn: (items: Array<TValue>) => Promise<any>;
204
+ readonly store: Store<Readonly<AsyncBatcherState<TValue>>>;
205
+ key: string | undefined;
206
+ options: AsyncBatcherOptionsWithOptionalCallbacks<TValue>;
207
+ asyncRetryers: Map<number, AsyncRetryer<(items: Array<TValue>) => Promise<any>>>;
208
+ constructor(fn: (items: Array<TValue>) => Promise<any>, initialOptions: AsyncBatcherOptions<TValue>);
209
+ /**
210
+ * Updates the async batcher options
211
+ */
212
+ setOptions: (newOptions: Partial<AsyncBatcherOptions<TValue>>) => void;
213
+ /**
214
+ * Adds an item to the async batcher
215
+ * If the batch size is reached, timeout occurs, or shouldProcess returns true, the batch will be processed
216
+ *
217
+ * @returns The result from the batch function, or undefined if an error occurred and was handled by onError
218
+ *
219
+ * @throws The error from the batch function if no onError handler is configured or throwOnError is true
220
+ */
221
+ addItem: (item: TValue) => Promise<any>;
222
+ /**
223
+ * Processes the current batch of items immediately
224
+ */
225
+ flush: () => Promise<any>;
226
+ /**
227
+ * Returns a copy of all items in the async batcher
228
+ */
229
+ peekAllItems: () => Array<TValue>;
230
+ peekFailedItems: () => Array<TValue>;
231
+ /**
232
+ * Removes all items from the async batcher
233
+ */
234
+ clear: () => void;
235
+ /**
236
+ * Returns the AbortSignal for a specific execution.
237
+ * If no executeCount is provided, returns the signal for the most recent execution.
238
+ * Returns null if no execution is found or not currently executing.
239
+ *
240
+ * @param executeCount - Optional specific execution to get signal for
241
+ * @example
242
+ * ```typescript
243
+ * const batcher = new AsyncBatcher(
244
+ * async (items: string[]) => {
245
+ * const signal = batcher.getAbortSignal()
246
+ * if (signal) {
247
+ * const response = await fetch('/api/batch', {
248
+ * method: 'POST',
249
+ * body: JSON.stringify(items),
250
+ * signal
251
+ * })
252
+ * return response.json()
253
+ * }
254
+ * },
255
+ * { maxSize: 10, wait: 100 }
256
+ * )
257
+ * ```
258
+ */
259
+ getAbortSignal(executeCount?: number): AbortSignal | null;
260
+ /**
261
+ * Aborts all ongoing executions with the internal abort controllers.
262
+ * Does NOT cancel any pending execution that have not started yet.
263
+ * Does NOT clear out the items.
264
+ */
265
+ abort: () => void;
266
+ /**
267
+ * Cancels any pending execution that have not started yet.
268
+ * Does NOT abort any execution already in progress.
269
+ * Does NOT clear out the items.
270
+ */
271
+ cancel: () => void;
272
+ /**
273
+ * Resets the async batcher state to its default values
274
+ */
275
+ reset: () => void;
276
+ }
277
+ /**
278
+ * Creates an async batcher that processes items in batches.
279
+ *
280
+ * Async vs Sync Versions:
281
+ * The async version provides advanced features over the sync batch function:
282
+ * - Returns promises that can be awaited for batch results
283
+ * - Built-in retry support via AsyncRetryer integration
284
+ * - Abort support to cancel in-flight batch executions
285
+ * - Cancel support to prevent pending batches from starting
286
+ * - Comprehensive error handling with onError callbacks and throwOnError control
287
+ * - Detailed execution tracking (success/error/settle counts)
288
+ *
289
+ * The sync batch function is lighter weight and simpler when you don't need async features,
290
+ * return values, or execution control.
291
+ *
292
+ * What is Batching?
293
+ * Batching is a technique for grouping multiple operations together to be processed as a single unit.
294
+ *
295
+ * Configuration Options:
296
+ * - `maxSize`: Maximum number of items per batch (default: Infinity)
297
+ * - `wait`: Time to wait before processing batch (default: Infinity)
298
+ * - `getShouldExecute`: Custom logic to trigger batch processing
299
+ * - `asyncRetryerOptions`: Configure retry behavior for batch executions
300
+ * - `started`: Whether to start processing immediately (default: true)
301
+ *
302
+ * Error Handling:
303
+ * - If an `onError` handler is provided, it will be called with the error, the batch of items that failed, and batcher instance
304
+ * - If `throwOnError` is true (default when no onError handler is provided), the error will be thrown
305
+ * - If `throwOnError` is false (default when onError handler is provided), the error will be swallowed
306
+ * - Both onError and throwOnError can be used together - the handler will be called before any error is thrown
307
+ * - The error state can be checked using the underlying AsyncBatcher instance
308
+ *
309
+ * State Management:
310
+ * - Uses TanStack Store for reactive state management
311
+ * - Use `initialState` to provide initial state values when creating the async batcher
312
+ * - Use `onSuccess` callback to react to successful batch execution and implement custom logic
313
+ * - Use `onError` callback to react to batch execution errors and implement custom error handling
314
+ * - Use `onSettled` callback to react to batch execution completion (success or error) and implement custom logic
315
+ * - Use `onItemsChange` callback to react to items being added or removed from the batcher
316
+ * - The state includes total items processed, success/error counts, and execution status
317
+ * - State can be accessed via the underlying AsyncBatcher instance's `store.state` property
318
+ * - When using framework adapters (React/Solid), state is accessed from the hook's state property
319
+ *
320
+ * @example
321
+ * ```ts
322
+ * const batchItems = asyncBatch<number>(
323
+ * async (items) => {
324
+ * const result = await processApiCall(items);
325
+ * console.log('Processing:', items);
326
+ * return result;
327
+ * },
328
+ * {
329
+ * maxSize: 3,
330
+ * wait: 1000,
331
+ * onSuccess: (result) => console.log('Batch succeeded:', result),
332
+ * onError: (error) => console.error('Batch failed:', error)
333
+ * }
334
+ * );
335
+ *
336
+ * batchItems(1);
337
+ * batchItems(2);
338
+ * batchItems(3); // Triggers batch processing
339
+ * ```
340
+ */
341
+ declare function asyncBatch<TValue>(fn: (items: Array<TValue>) => Promise<any>, options: AsyncBatcherOptions<TValue>): (item: TValue) => Promise<any>;
342
+ //#endregion
343
+ export { AsyncBatcher, AsyncBatcherOptions, AsyncBatcherState, asyncBatch, asyncBatcherOptions };
344
+ //# sourceMappingURL=async-batcher.d.ts.map