@tanstack/pacer 0.16.3 → 0.17.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.
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 +39 -123
  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,320 @@
1
+ import { AnyAsyncFunction } from "./types.cjs";
2
+ import { AsyncRetryer, AsyncRetryerOptions } from "./async-retryer.cjs";
3
+ import { Store } from "@tanstack/store";
4
+
5
+ //#region src/async-throttler.d.ts
6
+ interface AsyncThrottlerState<TFn extends AnyAsyncFunction> {
7
+ /**
8
+ * Number of function executions that have resulted in errors
9
+ */
10
+ errorCount: number;
11
+ /**
12
+ * Whether the throttled function is currently executing asynchronously
13
+ */
14
+ isExecuting: boolean;
15
+ /**
16
+ * Whether the throttler is waiting for the timeout to trigger execution
17
+ */
18
+ isPending: boolean;
19
+ /**
20
+ * The arguments from the most recent call to maybeExecute
21
+ */
22
+ lastArgs: Parameters<TFn> | undefined;
23
+ /**
24
+ * Timestamp of the last function execution in milliseconds
25
+ */
26
+ lastExecutionTime: number;
27
+ /**
28
+ * The result from the most recent successful function execution
29
+ */
30
+ lastResult: ReturnType<TFn> | undefined;
31
+ /**
32
+ * Number of times maybeExecute has been called (for reduction calculations)
33
+ */
34
+ maybeExecuteCount: number;
35
+ /**
36
+ * Timestamp when the next execution can occur in milliseconds
37
+ */
38
+ nextExecutionTime: number | undefined;
39
+ /**
40
+ * Number of function executions that have completed (either successfully or with errors)
41
+ */
42
+ settleCount: number;
43
+ /**
44
+ * Current execution status - 'idle' when not active, 'pending' when waiting, 'executing' when running, 'settled' when completed
45
+ */
46
+ status: 'disabled' | 'idle' | 'pending' | 'executing' | 'settled';
47
+ /**
48
+ * Number of function executions that have completed successfully
49
+ */
50
+ successCount: number;
51
+ }
52
+ /**
53
+ * Options for configuring an async throttled function
54
+ */
55
+ interface AsyncThrottlerOptions<TFn extends AnyAsyncFunction> {
56
+ /**
57
+ * Options for configuring the underlying async retryer
58
+ */
59
+ asyncRetryerOptions?: AsyncRetryerOptions<TFn>;
60
+ /**
61
+ * Whether the throttler is enabled. When disabled, maybeExecute will not trigger any executions.
62
+ * Can be a boolean or a function that returns a boolean.
63
+ * Defaults to true.
64
+ */
65
+ enabled?: boolean | ((throttler: AsyncThrottler<TFn>) => boolean);
66
+ /**
67
+ * Initial state for the async throttler
68
+ */
69
+ initialState?: Partial<AsyncThrottlerState<TFn>>;
70
+ /**
71
+ * Optional key to identify this async throttler instance.
72
+ * If provided, the async throttler will be identified by this key in the devtools and PacerProvider if applicable.
73
+ */
74
+ key?: string;
75
+ /**
76
+ * Whether to execute the function immediately when called
77
+ * Defaults to true
78
+ */
79
+ leading?: boolean;
80
+ /**
81
+ * Optional error handler for when the throttled function throws.
82
+ * If provided, the handler will be called with the error and throttler instance.
83
+ * This can be used alongside throwOnError - the handler will be called before any error is thrown.
84
+ */
85
+ onError?: (error: Error, args: Parameters<TFn>, asyncThrottler: AsyncThrottler<TFn>) => void;
86
+ /**
87
+ * Optional function to call when the throttled function is executed
88
+ */
89
+ onSettled?: (args: Parameters<TFn>, asyncThrottler: AsyncThrottler<TFn>) => void;
90
+ /**
91
+ * Optional function to call when the throttled function is executed
92
+ */
93
+ onSuccess?: (result: ReturnType<TFn>, args: Parameters<TFn>, asyncThrottler: AsyncThrottler<TFn>) => void;
94
+ /**
95
+ * Whether to throw errors when they occur.
96
+ * Defaults to true if no onError handler is provided, false if an onError handler is provided.
97
+ * Can be explicitly set to override these defaults.
98
+ */
99
+ throwOnError?: boolean;
100
+ /**
101
+ * Whether to execute the function on the trailing edge of the wait period
102
+ * Defaults to true
103
+ */
104
+ trailing?: boolean;
105
+ /**
106
+ * Time window in milliseconds during which the function can only be executed once.
107
+ * Can be a number or a function that returns a number.
108
+ * Defaults to 0ms
109
+ */
110
+ wait: number | ((throttler: AsyncThrottler<TFn>) => number);
111
+ }
112
+ /**
113
+ * Utility function for sharing common `AsyncThrottlerOptions` options between different `AsyncThrottler` instances.
114
+ */
115
+ declare function asyncThrottlerOptions<TFn extends AnyAsyncFunction = AnyAsyncFunction, TOptions extends Partial<AsyncThrottlerOptions<TFn>> = Partial<AsyncThrottlerOptions<TFn>>>(options: TOptions): TOptions;
116
+ /**
117
+ * A class that creates an async throttled function.
118
+ *
119
+ * Async vs Sync Versions:
120
+ * The async version provides advanced features over the sync Throttler:
121
+ * - Returns promises that can be awaited for throttled function results
122
+ * - Built-in retry support via AsyncRetryer integration
123
+ * - Abort support to cancel in-flight executions
124
+ * - Cancel support to prevent pending executions from starting
125
+ * - Comprehensive error handling with onError callbacks and throwOnError control
126
+ * - Detailed execution tracking (success/error/settle counts)
127
+ * - Waits for ongoing executions to complete before scheduling the next one
128
+ *
129
+ * The sync Throttler is lighter weight and simpler when you don't need async features,
130
+ * return values, or execution control.
131
+ *
132
+ * What is Throttling?
133
+ * Throttling limits how often a function can be executed, allowing only one execution within a specified time window.
134
+ * Unlike debouncing which resets the delay timer on each call, throttling ensures the function executes at a
135
+ * regular interval regardless of how often it's called.
136
+ *
137
+ * This is useful for rate-limiting API calls, handling scroll/resize events, or any scenario where you want to
138
+ * ensure a maximum execution frequency.
139
+ *
140
+ * Error Handling:
141
+ * - If an `onError` handler is provided, it will be called with the error and throttler instance
142
+ * - If `throwOnError` is true (default when no onError handler is provided), the error will be thrown
143
+ * - If `throwOnError` is false (default when onError handler is provided), the error will be swallowed
144
+ * - Both onError and throwOnError can be used together - the handler will be called before any error is thrown
145
+ * - The error state can be checked using the underlying AsyncThrottler instance
146
+ *
147
+ * State Management:
148
+ * - Uses TanStack Store for reactive state management
149
+ * - Use `initialState` to provide initial state values when creating the async throttler
150
+ * - Use `onSuccess` callback to react to successful function execution and implement custom logic
151
+ * - Use `onError` callback to react to function execution errors and implement custom error handling
152
+ * - Use `onSettled` callback to react to function execution completion (success or error) and implement custom logic
153
+ * - The state includes error count, execution status, last execution time, and success/settle counts
154
+ * - State can be accessed via `asyncThrottler.store.state` when using the class directly
155
+ * - When using framework adapters (React/Solid), state is accessed from `asyncThrottler.state`
156
+ *
157
+ * @example
158
+ * ```ts
159
+ * const throttler = new AsyncThrottler(async (value: string) => {
160
+ * const result = await saveToAPI(value);
161
+ * return result; // Return value is preserved
162
+ * }, {
163
+ * wait: 1000,
164
+ * onError: (error) => {
165
+ * console.error('API call failed:', error);
166
+ * }
167
+ * });
168
+ *
169
+ * // Will only execute once per second no matter how often called
170
+ * // Returns the API response directly
171
+ * const result = await throttler.maybeExecute(inputElement.value);
172
+ * ```
173
+ */
174
+ declare class AsyncThrottler<TFn extends AnyAsyncFunction> {
175
+ #private;
176
+ fn: TFn;
177
+ readonly store: Store<Readonly<AsyncThrottlerState<TFn>>>;
178
+ key: string | undefined;
179
+ options: AsyncThrottlerOptions<TFn>;
180
+ asyncRetryers: Map<number, AsyncRetryer<TFn>>;
181
+ constructor(fn: TFn, initialOptions: AsyncThrottlerOptions<TFn>);
182
+ /**
183
+ * Updates the async throttler options
184
+ */
185
+ setOptions: (newOptions: Partial<AsyncThrottlerOptions<TFn>>) => void;
186
+ /**
187
+ * Attempts to execute the throttled function. The execution behavior depends on the throttler options:
188
+ *
189
+ * - If enough time has passed since the last execution (>= wait period):
190
+ * - With leading=true: Executes immediately
191
+ * - With leading=false: Waits for the next trailing execution
192
+ *
193
+ * - If within the wait period:
194
+ * - With trailing=true: Schedules execution for end of wait period
195
+ * - With trailing=false: Drops the execution
196
+ *
197
+ * @example
198
+ * ```ts
199
+ * const throttled = new AsyncThrottler(fn, { wait: 1000 });
200
+ *
201
+ * // First call executes immediately
202
+ * await throttled.maybeExecute('a', 'b');
203
+ *
204
+ * // Call during wait period - gets throttled
205
+ * await throttled.maybeExecute('c', 'd');
206
+ * ```
207
+ */
208
+ maybeExecute: (...args: Parameters<TFn>) => Promise<ReturnType<TFn> | undefined>;
209
+ /**
210
+ * Processes the current pending execution immediately
211
+ */
212
+ flush: () => Promise<ReturnType<TFn> | undefined>;
213
+ /**
214
+ * Returns the AbortSignal for a specific execution.
215
+ * If no maybeExecuteCount is provided, returns the signal for the most recent execution.
216
+ * Returns null if no execution is found or not currently executing.
217
+ *
218
+ * @param maybeExecuteCount - Optional specific execution to get signal for
219
+ * @example
220
+ * ```typescript
221
+ * const throttler = new AsyncThrottler(
222
+ * async (data: string) => {
223
+ * const signal = throttler.getAbortSignal()
224
+ * if (signal) {
225
+ * const response = await fetch('/api/save', {
226
+ * method: 'POST',
227
+ * body: data,
228
+ * signal
229
+ * })
230
+ * return response.json()
231
+ * }
232
+ * },
233
+ * { wait: 1000 }
234
+ * )
235
+ * ```
236
+ */
237
+ getAbortSignal(maybeExecuteCount?: number): AbortSignal | null;
238
+ /**
239
+ * Aborts all ongoing executions with the internal abort controllers.
240
+ * Does NOT cancel any pending execution that have not started yet.
241
+ */
242
+ abort: () => void;
243
+ /**
244
+ * Cancels any pending execution that have not started yet.
245
+ * Does NOT abort any execution already in progress.
246
+ */
247
+ cancel: () => void;
248
+ /**
249
+ * Resets the debouncer state to its default values
250
+ */
251
+ reset: () => void;
252
+ }
253
+ /**
254
+ * Creates an async throttled function that limits how often the function can execute.
255
+ * The throttled function will execute at most once per wait period, even if called multiple times.
256
+ * If called while executing, it will wait until execution completes before scheduling the next call.
257
+ *
258
+ * Async vs Sync Versions:
259
+ * The async version provides advanced features over the sync throttle function:
260
+ * - Returns promises that can be awaited for throttled function results
261
+ * - Built-in retry support via AsyncRetryer integration
262
+ * - Abort support to cancel in-flight executions
263
+ * - Cancel support to prevent pending executions from starting
264
+ * - Comprehensive error handling with onError callbacks and throwOnError control
265
+ * - Detailed execution tracking (success/error/settle counts)
266
+ * - Waits for ongoing executions to complete before scheduling the next one
267
+ *
268
+ * The sync throttle function is lighter weight and simpler when you don't need async features,
269
+ * return values, or execution control.
270
+ *
271
+ * What is Throttling?
272
+ * Throttling limits how often a function can be executed, allowing only one execution within a specified time window.
273
+ * Unlike debouncing which resets the delay timer on each call, throttling ensures the function executes at a
274
+ * regular interval regardless of how often it's called.
275
+ *
276
+ * Configuration Options:
277
+ * - `wait`: Time window in milliseconds during which the function can only execute once (required)
278
+ * - `leading`: Execute immediately when called (default: true)
279
+ * - `trailing`: Execute on the trailing edge of the wait period (default: true)
280
+ * - `enabled`: Whether the throttler is enabled (default: true)
281
+ * - `asyncRetryerOptions`: Configure retry behavior for executions
282
+ *
283
+ * Error Handling:
284
+ * - If an `onError` handler is provided, it will be called with the error and throttler instance
285
+ * - If `throwOnError` is true (default when no onError handler is provided), the error will be thrown
286
+ * - If `throwOnError` is false (default when onError handler is provided), the error will be swallowed
287
+ * - Both onError and throwOnError can be used together - the handler will be called before any error is thrown
288
+ * - The error state can be checked using the underlying AsyncThrottler instance
289
+ *
290
+ * State Management:
291
+ * - Uses TanStack Store for reactive state management
292
+ * - Use `initialState` to provide initial state values when creating the async throttler
293
+ * - Use `onSuccess` callback to react to successful function execution and implement custom logic
294
+ * - Use `onError` callback to react to function execution errors and implement custom error handling
295
+ * - Use `onSettled` callback to react to function execution completion (success or error) and implement custom logic
296
+ * - The state includes error count, execution status, last execution time, and success/settle counts
297
+ * - State can be accessed via the underlying AsyncThrottler instance's `store.state` property
298
+ * - When using framework adapters (React/Solid), state is accessed from the hook's state property
299
+ *
300
+ * @example
301
+ * ```ts
302
+ * const throttled = asyncThrottle(async (value: string) => {
303
+ * const result = await saveToAPI(value);
304
+ * return result; // Return value is preserved
305
+ * }, {
306
+ * wait: 1000,
307
+ * onError: (error) => {
308
+ * console.error('API call failed:', error);
309
+ * }
310
+ * });
311
+ *
312
+ * // This will execute at most once per second
313
+ * // Returns the API response directly
314
+ * const result = await throttled(inputElement.value);
315
+ * ```
316
+ */
317
+ declare function asyncThrottle<TFn extends AnyAsyncFunction>(fn: TFn, initialOptions: AsyncThrottlerOptions<TFn>): (...args: Parameters<TFn>) => Promise<ReturnType<TFn> | undefined>;
318
+ //#endregion
319
+ export { AsyncThrottler, AsyncThrottlerOptions, AsyncThrottlerState, asyncThrottle, asyncThrottlerOptions };
320
+ //# sourceMappingURL=async-throttler.d.cts.map
@@ -0,0 +1,320 @@
1
+ import { AnyAsyncFunction } from "./types.js";
2
+ import { AsyncRetryer, AsyncRetryerOptions } from "./async-retryer.js";
3
+ import { Store } from "@tanstack/store";
4
+
5
+ //#region src/async-throttler.d.ts
6
+ interface AsyncThrottlerState<TFn extends AnyAsyncFunction> {
7
+ /**
8
+ * Number of function executions that have resulted in errors
9
+ */
10
+ errorCount: number;
11
+ /**
12
+ * Whether the throttled function is currently executing asynchronously
13
+ */
14
+ isExecuting: boolean;
15
+ /**
16
+ * Whether the throttler is waiting for the timeout to trigger execution
17
+ */
18
+ isPending: boolean;
19
+ /**
20
+ * The arguments from the most recent call to maybeExecute
21
+ */
22
+ lastArgs: Parameters<TFn> | undefined;
23
+ /**
24
+ * Timestamp of the last function execution in milliseconds
25
+ */
26
+ lastExecutionTime: number;
27
+ /**
28
+ * The result from the most recent successful function execution
29
+ */
30
+ lastResult: ReturnType<TFn> | undefined;
31
+ /**
32
+ * Number of times maybeExecute has been called (for reduction calculations)
33
+ */
34
+ maybeExecuteCount: number;
35
+ /**
36
+ * Timestamp when the next execution can occur in milliseconds
37
+ */
38
+ nextExecutionTime: number | undefined;
39
+ /**
40
+ * Number of function executions that have completed (either successfully or with errors)
41
+ */
42
+ settleCount: number;
43
+ /**
44
+ * Current execution status - 'idle' when not active, 'pending' when waiting, 'executing' when running, 'settled' when completed
45
+ */
46
+ status: 'disabled' | 'idle' | 'pending' | 'executing' | 'settled';
47
+ /**
48
+ * Number of function executions that have completed successfully
49
+ */
50
+ successCount: number;
51
+ }
52
+ /**
53
+ * Options for configuring an async throttled function
54
+ */
55
+ interface AsyncThrottlerOptions<TFn extends AnyAsyncFunction> {
56
+ /**
57
+ * Options for configuring the underlying async retryer
58
+ */
59
+ asyncRetryerOptions?: AsyncRetryerOptions<TFn>;
60
+ /**
61
+ * Whether the throttler is enabled. When disabled, maybeExecute will not trigger any executions.
62
+ * Can be a boolean or a function that returns a boolean.
63
+ * Defaults to true.
64
+ */
65
+ enabled?: boolean | ((throttler: AsyncThrottler<TFn>) => boolean);
66
+ /**
67
+ * Initial state for the async throttler
68
+ */
69
+ initialState?: Partial<AsyncThrottlerState<TFn>>;
70
+ /**
71
+ * Optional key to identify this async throttler instance.
72
+ * If provided, the async throttler will be identified by this key in the devtools and PacerProvider if applicable.
73
+ */
74
+ key?: string;
75
+ /**
76
+ * Whether to execute the function immediately when called
77
+ * Defaults to true
78
+ */
79
+ leading?: boolean;
80
+ /**
81
+ * Optional error handler for when the throttled function throws.
82
+ * If provided, the handler will be called with the error and throttler instance.
83
+ * This can be used alongside throwOnError - the handler will be called before any error is thrown.
84
+ */
85
+ onError?: (error: Error, args: Parameters<TFn>, asyncThrottler: AsyncThrottler<TFn>) => void;
86
+ /**
87
+ * Optional function to call when the throttled function is executed
88
+ */
89
+ onSettled?: (args: Parameters<TFn>, asyncThrottler: AsyncThrottler<TFn>) => void;
90
+ /**
91
+ * Optional function to call when the throttled function is executed
92
+ */
93
+ onSuccess?: (result: ReturnType<TFn>, args: Parameters<TFn>, asyncThrottler: AsyncThrottler<TFn>) => void;
94
+ /**
95
+ * Whether to throw errors when they occur.
96
+ * Defaults to true if no onError handler is provided, false if an onError handler is provided.
97
+ * Can be explicitly set to override these defaults.
98
+ */
99
+ throwOnError?: boolean;
100
+ /**
101
+ * Whether to execute the function on the trailing edge of the wait period
102
+ * Defaults to true
103
+ */
104
+ trailing?: boolean;
105
+ /**
106
+ * Time window in milliseconds during which the function can only be executed once.
107
+ * Can be a number or a function that returns a number.
108
+ * Defaults to 0ms
109
+ */
110
+ wait: number | ((throttler: AsyncThrottler<TFn>) => number);
111
+ }
112
+ /**
113
+ * Utility function for sharing common `AsyncThrottlerOptions` options between different `AsyncThrottler` instances.
114
+ */
115
+ declare function asyncThrottlerOptions<TFn extends AnyAsyncFunction = AnyAsyncFunction, TOptions extends Partial<AsyncThrottlerOptions<TFn>> = Partial<AsyncThrottlerOptions<TFn>>>(options: TOptions): TOptions;
116
+ /**
117
+ * A class that creates an async throttled function.
118
+ *
119
+ * Async vs Sync Versions:
120
+ * The async version provides advanced features over the sync Throttler:
121
+ * - Returns promises that can be awaited for throttled function results
122
+ * - Built-in retry support via AsyncRetryer integration
123
+ * - Abort support to cancel in-flight executions
124
+ * - Cancel support to prevent pending executions from starting
125
+ * - Comprehensive error handling with onError callbacks and throwOnError control
126
+ * - Detailed execution tracking (success/error/settle counts)
127
+ * - Waits for ongoing executions to complete before scheduling the next one
128
+ *
129
+ * The sync Throttler is lighter weight and simpler when you don't need async features,
130
+ * return values, or execution control.
131
+ *
132
+ * What is Throttling?
133
+ * Throttling limits how often a function can be executed, allowing only one execution within a specified time window.
134
+ * Unlike debouncing which resets the delay timer on each call, throttling ensures the function executes at a
135
+ * regular interval regardless of how often it's called.
136
+ *
137
+ * This is useful for rate-limiting API calls, handling scroll/resize events, or any scenario where you want to
138
+ * ensure a maximum execution frequency.
139
+ *
140
+ * Error Handling:
141
+ * - If an `onError` handler is provided, it will be called with the error and throttler instance
142
+ * - If `throwOnError` is true (default when no onError handler is provided), the error will be thrown
143
+ * - If `throwOnError` is false (default when onError handler is provided), the error will be swallowed
144
+ * - Both onError and throwOnError can be used together - the handler will be called before any error is thrown
145
+ * - The error state can be checked using the underlying AsyncThrottler instance
146
+ *
147
+ * State Management:
148
+ * - Uses TanStack Store for reactive state management
149
+ * - Use `initialState` to provide initial state values when creating the async throttler
150
+ * - Use `onSuccess` callback to react to successful function execution and implement custom logic
151
+ * - Use `onError` callback to react to function execution errors and implement custom error handling
152
+ * - Use `onSettled` callback to react to function execution completion (success or error) and implement custom logic
153
+ * - The state includes error count, execution status, last execution time, and success/settle counts
154
+ * - State can be accessed via `asyncThrottler.store.state` when using the class directly
155
+ * - When using framework adapters (React/Solid), state is accessed from `asyncThrottler.state`
156
+ *
157
+ * @example
158
+ * ```ts
159
+ * const throttler = new AsyncThrottler(async (value: string) => {
160
+ * const result = await saveToAPI(value);
161
+ * return result; // Return value is preserved
162
+ * }, {
163
+ * wait: 1000,
164
+ * onError: (error) => {
165
+ * console.error('API call failed:', error);
166
+ * }
167
+ * });
168
+ *
169
+ * // Will only execute once per second no matter how often called
170
+ * // Returns the API response directly
171
+ * const result = await throttler.maybeExecute(inputElement.value);
172
+ * ```
173
+ */
174
+ declare class AsyncThrottler<TFn extends AnyAsyncFunction> {
175
+ #private;
176
+ fn: TFn;
177
+ readonly store: Store<Readonly<AsyncThrottlerState<TFn>>>;
178
+ key: string | undefined;
179
+ options: AsyncThrottlerOptions<TFn>;
180
+ asyncRetryers: Map<number, AsyncRetryer<TFn>>;
181
+ constructor(fn: TFn, initialOptions: AsyncThrottlerOptions<TFn>);
182
+ /**
183
+ * Updates the async throttler options
184
+ */
185
+ setOptions: (newOptions: Partial<AsyncThrottlerOptions<TFn>>) => void;
186
+ /**
187
+ * Attempts to execute the throttled function. The execution behavior depends on the throttler options:
188
+ *
189
+ * - If enough time has passed since the last execution (>= wait period):
190
+ * - With leading=true: Executes immediately
191
+ * - With leading=false: Waits for the next trailing execution
192
+ *
193
+ * - If within the wait period:
194
+ * - With trailing=true: Schedules execution for end of wait period
195
+ * - With trailing=false: Drops the execution
196
+ *
197
+ * @example
198
+ * ```ts
199
+ * const throttled = new AsyncThrottler(fn, { wait: 1000 });
200
+ *
201
+ * // First call executes immediately
202
+ * await throttled.maybeExecute('a', 'b');
203
+ *
204
+ * // Call during wait period - gets throttled
205
+ * await throttled.maybeExecute('c', 'd');
206
+ * ```
207
+ */
208
+ maybeExecute: (...args: Parameters<TFn>) => Promise<ReturnType<TFn> | undefined>;
209
+ /**
210
+ * Processes the current pending execution immediately
211
+ */
212
+ flush: () => Promise<ReturnType<TFn> | undefined>;
213
+ /**
214
+ * Returns the AbortSignal for a specific execution.
215
+ * If no maybeExecuteCount is provided, returns the signal for the most recent execution.
216
+ * Returns null if no execution is found or not currently executing.
217
+ *
218
+ * @param maybeExecuteCount - Optional specific execution to get signal for
219
+ * @example
220
+ * ```typescript
221
+ * const throttler = new AsyncThrottler(
222
+ * async (data: string) => {
223
+ * const signal = throttler.getAbortSignal()
224
+ * if (signal) {
225
+ * const response = await fetch('/api/save', {
226
+ * method: 'POST',
227
+ * body: data,
228
+ * signal
229
+ * })
230
+ * return response.json()
231
+ * }
232
+ * },
233
+ * { wait: 1000 }
234
+ * )
235
+ * ```
236
+ */
237
+ getAbortSignal(maybeExecuteCount?: number): AbortSignal | null;
238
+ /**
239
+ * Aborts all ongoing executions with the internal abort controllers.
240
+ * Does NOT cancel any pending execution that have not started yet.
241
+ */
242
+ abort: () => void;
243
+ /**
244
+ * Cancels any pending execution that have not started yet.
245
+ * Does NOT abort any execution already in progress.
246
+ */
247
+ cancel: () => void;
248
+ /**
249
+ * Resets the debouncer state to its default values
250
+ */
251
+ reset: () => void;
252
+ }
253
+ /**
254
+ * Creates an async throttled function that limits how often the function can execute.
255
+ * The throttled function will execute at most once per wait period, even if called multiple times.
256
+ * If called while executing, it will wait until execution completes before scheduling the next call.
257
+ *
258
+ * Async vs Sync Versions:
259
+ * The async version provides advanced features over the sync throttle function:
260
+ * - Returns promises that can be awaited for throttled function results
261
+ * - Built-in retry support via AsyncRetryer integration
262
+ * - Abort support to cancel in-flight executions
263
+ * - Cancel support to prevent pending executions from starting
264
+ * - Comprehensive error handling with onError callbacks and throwOnError control
265
+ * - Detailed execution tracking (success/error/settle counts)
266
+ * - Waits for ongoing executions to complete before scheduling the next one
267
+ *
268
+ * The sync throttle function is lighter weight and simpler when you don't need async features,
269
+ * return values, or execution control.
270
+ *
271
+ * What is Throttling?
272
+ * Throttling limits how often a function can be executed, allowing only one execution within a specified time window.
273
+ * Unlike debouncing which resets the delay timer on each call, throttling ensures the function executes at a
274
+ * regular interval regardless of how often it's called.
275
+ *
276
+ * Configuration Options:
277
+ * - `wait`: Time window in milliseconds during which the function can only execute once (required)
278
+ * - `leading`: Execute immediately when called (default: true)
279
+ * - `trailing`: Execute on the trailing edge of the wait period (default: true)
280
+ * - `enabled`: Whether the throttler is enabled (default: true)
281
+ * - `asyncRetryerOptions`: Configure retry behavior for executions
282
+ *
283
+ * Error Handling:
284
+ * - If an `onError` handler is provided, it will be called with the error and throttler instance
285
+ * - If `throwOnError` is true (default when no onError handler is provided), the error will be thrown
286
+ * - If `throwOnError` is false (default when onError handler is provided), the error will be swallowed
287
+ * - Both onError and throwOnError can be used together - the handler will be called before any error is thrown
288
+ * - The error state can be checked using the underlying AsyncThrottler instance
289
+ *
290
+ * State Management:
291
+ * - Uses TanStack Store for reactive state management
292
+ * - Use `initialState` to provide initial state values when creating the async throttler
293
+ * - Use `onSuccess` callback to react to successful function execution and implement custom logic
294
+ * - Use `onError` callback to react to function execution errors and implement custom error handling
295
+ * - Use `onSettled` callback to react to function execution completion (success or error) and implement custom logic
296
+ * - The state includes error count, execution status, last execution time, and success/settle counts
297
+ * - State can be accessed via the underlying AsyncThrottler instance's `store.state` property
298
+ * - When using framework adapters (React/Solid), state is accessed from the hook's state property
299
+ *
300
+ * @example
301
+ * ```ts
302
+ * const throttled = asyncThrottle(async (value: string) => {
303
+ * const result = await saveToAPI(value);
304
+ * return result; // Return value is preserved
305
+ * }, {
306
+ * wait: 1000,
307
+ * onError: (error) => {
308
+ * console.error('API call failed:', error);
309
+ * }
310
+ * });
311
+ *
312
+ * // This will execute at most once per second
313
+ * // Returns the API response directly
314
+ * const result = await throttled(inputElement.value);
315
+ * ```
316
+ */
317
+ declare function asyncThrottle<TFn extends AnyAsyncFunction>(fn: TFn, initialOptions: AsyncThrottlerOptions<TFn>): (...args: Parameters<TFn>) => Promise<ReturnType<TFn> | undefined>;
318
+ //#endregion
319
+ export { AsyncThrottler, AsyncThrottlerOptions, AsyncThrottlerState, asyncThrottle, asyncThrottlerOptions };
320
+ //# sourceMappingURL=async-throttler.d.ts.map