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