@tanstack/pacer 0.22.0 → 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 (100) hide show
  1. package/README.md +4 -4
  2. package/dist/async-batcher.d.ts +11 -13
  3. package/dist/async-batcher.js +185 -131
  4. package/dist/async-debouncer.d.ts +6 -8
  5. package/dist/async-debouncer.js +186 -142
  6. package/dist/async-queuer.d.ts +11 -13
  7. package/dist/async-queuer.js +383 -290
  8. package/dist/async-rate-limiter.d.ts +6 -8
  9. package/dist/async-rate-limiter.js +197 -143
  10. package/dist/async-retryer.d.ts +6 -8
  11. package/dist/async-retryer.js +209 -179
  12. package/dist/async-throttler.d.ts +6 -8
  13. package/dist/async-throttler.js +214 -157
  14. package/dist/batcher.d.ts +5 -7
  15. package/dist/batcher.js +107 -87
  16. package/dist/debouncer.d.ts +6 -8
  17. package/dist/debouncer.js +99 -86
  18. package/dist/event-client.d.ts +8 -10
  19. package/dist/event-client.js +1 -2
  20. package/dist/queuer.d.ts +7 -9
  21. package/dist/queuer.js +277 -212
  22. package/dist/rate-limiter.d.ts +6 -8
  23. package/dist/rate-limiter.js +127 -109
  24. package/dist/throttler.d.ts +6 -8
  25. package/dist/throttler.js +127 -90
  26. package/dist/types.d.ts +4 -6
  27. package/dist/utils.d.ts +3 -5
  28. package/dist/utils.js +1 -2
  29. package/package.json +21 -68
  30. package/dist/async-batcher.cjs +0 -337
  31. package/dist/async-batcher.cjs.map +0 -1
  32. package/dist/async-batcher.d.cts +0 -343
  33. package/dist/async-batcher.js.map +0 -1
  34. package/dist/async-debouncer.cjs +0 -327
  35. package/dist/async-debouncer.cjs.map +0 -1
  36. package/dist/async-debouncer.d.cts +0 -299
  37. package/dist/async-debouncer.js.map +0 -1
  38. package/dist/async-queuer.cjs +0 -516
  39. package/dist/async-queuer.cjs.map +0 -1
  40. package/dist/async-queuer.d.cts +0 -440
  41. package/dist/async-queuer.js.map +0 -1
  42. package/dist/async-rate-limiter.cjs +0 -370
  43. package/dist/async-rate-limiter.cjs.map +0 -1
  44. package/dist/async-rate-limiter.d.cts +0 -356
  45. package/dist/async-rate-limiter.js.map +0 -1
  46. package/dist/async-retryer.cjs +0 -365
  47. package/dist/async-retryer.cjs.map +0 -1
  48. package/dist/async-retryer.d.cts +0 -321
  49. package/dist/async-retryer.js.map +0 -1
  50. package/dist/async-throttler.cjs +0 -344
  51. package/dist/async-throttler.cjs.map +0 -1
  52. package/dist/async-throttler.d.cts +0 -319
  53. package/dist/async-throttler.js.map +0 -1
  54. package/dist/batcher.cjs +0 -200
  55. package/dist/batcher.cjs.map +0 -1
  56. package/dist/batcher.d.cts +0 -179
  57. package/dist/batcher.js.map +0 -1
  58. package/dist/debouncer.cjs +0 -203
  59. package/dist/debouncer.cjs.map +0 -1
  60. package/dist/debouncer.d.cts +0 -166
  61. package/dist/debouncer.js.map +0 -1
  62. package/dist/event-client.cjs +0 -64
  63. package/dist/event-client.cjs.map +0 -1
  64. package/dist/event-client.d.cts +0 -65
  65. package/dist/event-client.js.map +0 -1
  66. package/dist/index.cjs +0 -52
  67. package/dist/index.d.cts +0 -15
  68. package/dist/queuer.cjs +0 -406
  69. package/dist/queuer.cjs.map +0 -1
  70. package/dist/queuer.d.cts +0 -345
  71. package/dist/queuer.js.map +0 -1
  72. package/dist/rate-limiter.cjs +0 -263
  73. package/dist/rate-limiter.cjs.map +0 -1
  74. package/dist/rate-limiter.d.cts +0 -214
  75. package/dist/rate-limiter.js.map +0 -1
  76. package/dist/throttler.cjs +0 -215
  77. package/dist/throttler.cjs.map +0 -1
  78. package/dist/throttler.d.cts +0 -206
  79. package/dist/throttler.js.map +0 -1
  80. package/dist/types.cjs +0 -0
  81. package/dist/types.d.cts +0 -13
  82. package/dist/utils.cjs +0 -13
  83. package/dist/utils.cjs.map +0 -1
  84. package/dist/utils.d.cts +0 -7
  85. package/dist/utils.js.map +0 -1
  86. package/src/async-batcher.ts +0 -594
  87. package/src/async-debouncer.ts +0 -566
  88. package/src/async-queuer.ts +0 -988
  89. package/src/async-rate-limiter.ts +0 -648
  90. package/src/async-retryer.ts +0 -673
  91. package/src/async-throttler.ts +0 -634
  92. package/src/batcher.ts +0 -329
  93. package/src/debouncer.ts +0 -334
  94. package/src/event-client.ts +0 -129
  95. package/src/index.ts +0 -24
  96. package/src/queuer.ts +0 -751
  97. package/src/rate-limiter.ts +0 -429
  98. package/src/throttler.ts +0 -380
  99. package/src/types.ts +0 -12
  100. package/src/utils.ts +0 -12
@@ -71,105 +71,13 @@ const defaultOptions = {
71
71
  * ```
72
72
  */
73
73
  var RateLimiter = class {
74
- #timeoutIds;
74
+ fn;
75
+ store = new Store(getDefaultRateLimiterState());
76
+ key;
77
+ options;
78
+ #timeoutIds = /* @__PURE__ */ new Set();
75
79
  constructor(fn, initialOptions) {
76
80
  this.fn = fn;
77
- this.store = new Store(getDefaultRateLimiterState());
78
- this.#timeoutIds = /* @__PURE__ */ new Set();
79
- this.setOptions = (newOptions) => {
80
- this.options = {
81
- ...this.options,
82
- ...newOptions
83
- };
84
- };
85
- this.#setState = (newState) => {
86
- this.store.setState((state) => {
87
- const combinedState = {
88
- ...state,
89
- ...newState
90
- };
91
- const isExceeded = combinedState.executionTimes.length >= this.#getLimit();
92
- const status = !this.#getEnabled() ? "disabled" : isExceeded ? "exceeded" : "idle";
93
- return {
94
- ...combinedState,
95
- isExceeded,
96
- status
97
- };
98
- });
99
- emitChange("RateLimiter", this);
100
- };
101
- this.#getEnabled = () => {
102
- return !!parseFunctionOrValue(this.options.enabled, this);
103
- };
104
- this.#getLimit = () => {
105
- return parseFunctionOrValue(this.options.limit, this);
106
- };
107
- this.#getWindow = () => {
108
- return parseFunctionOrValue(this.options.window, this);
109
- };
110
- this.maybeExecute = (...args) => {
111
- this.#setState({ maybeExecuteCount: this.store.state.maybeExecuteCount + 1 });
112
- this.#cleanupOldExecutions();
113
- if (this.#getExecutionTimesInWindow().length < this.#getLimit()) {
114
- this.#execute(...args);
115
- return true;
116
- }
117
- this.#setState({ rejectionCount: this.store.state.rejectionCount + 1 });
118
- this.options.onReject?.(this);
119
- return false;
120
- };
121
- this.#execute = (...args) => {
122
- if (!this.#getEnabled()) return;
123
- const now = Date.now();
124
- this.fn(...args);
125
- this.store.state.executionTimes.push(now);
126
- this.#setCleanupTimeout(now);
127
- this.#setState({ executionCount: this.store.state.executionCount + 1 });
128
- this.options.onExecute?.(args, this);
129
- };
130
- this.#getExecutionTimesInWindow = () => {
131
- if (this.options.windowType === "sliding") return this.store.state.executionTimes.filter((time) => time > Date.now() - this.#getWindow());
132
- else {
133
- if (this.store.state.executionTimes.length === 0) return [];
134
- const windowStart = Math.min(...this.store.state.executionTimes);
135
- const windowEnd = windowStart + this.#getWindow();
136
- if (Date.now() > windowEnd) return [];
137
- return this.store.state.executionTimes.filter((time) => time >= windowStart && time <= windowEnd);
138
- }
139
- };
140
- this.#setCleanupTimeout = (executionTime) => {
141
- if (this.options.windowType === "sliding" || this.#timeoutIds.size === 0) {
142
- const timeUntilExpiration = executionTime - Date.now() + this.#getWindow() + 1;
143
- const timeoutId = setTimeout(() => {
144
- this.#cleanupOldExecutions();
145
- this.#clearTimeout(timeoutId);
146
- }, timeUntilExpiration);
147
- this.#timeoutIds.add(timeoutId);
148
- }
149
- };
150
- this.#clearTimeout = (timeoutId) => {
151
- clearTimeout(timeoutId);
152
- this.#timeoutIds.delete(timeoutId);
153
- };
154
- this.#clearTimeouts = () => {
155
- this.#timeoutIds.forEach((timeoutId) => clearTimeout(timeoutId));
156
- this.#timeoutIds.clear();
157
- };
158
- this.#cleanupOldExecutions = () => {
159
- this.#setState({ executionTimes: this.#getExecutionTimesInWindow() });
160
- };
161
- this.getRemainingInWindow = () => {
162
- const relevantExecutionTimes = this.#getExecutionTimesInWindow();
163
- return Math.max(0, this.#getLimit() - relevantExecutionTimes.length);
164
- };
165
- this.getMsUntilNextWindow = () => {
166
- if (this.getRemainingInWindow() > 0) return 0;
167
- return (this.store.state.executionTimes[0] ?? Infinity) + this.#getWindow() - Date.now();
168
- };
169
- this.reset = () => {
170
- this.#setState(getDefaultRateLimiterState());
171
- this.#clearTimeouts();
172
- };
173
81
  this.key = initialOptions.key;
174
82
  this.options = {
175
83
  ...defaultOptions,
@@ -183,25 +91,136 @@ var RateLimiter = class {
183
91
  this.setOptions(event.payload.options);
184
92
  });
185
93
  }
186
- #setState;
94
+ /**
95
+ * Updates the rate limiter options
96
+ */
97
+ setOptions = (newOptions) => {
98
+ this.options = {
99
+ ...this.options,
100
+ ...newOptions
101
+ };
102
+ };
103
+ #setState = (newState) => {
104
+ this.store.setState((state) => {
105
+ const combinedState = {
106
+ ...state,
107
+ ...newState
108
+ };
109
+ const isExceeded = combinedState.executionTimes.length >= this.#getLimit();
110
+ const status = !this.#getEnabled() ? "disabled" : isExceeded ? "exceeded" : "idle";
111
+ return {
112
+ ...combinedState,
113
+ isExceeded,
114
+ status
115
+ };
116
+ });
117
+ emitChange("RateLimiter", this);
118
+ };
187
119
  /**
188
120
  * Returns the current enabled state of the rate limiter
189
121
  */
190
- #getEnabled;
122
+ #getEnabled = () => {
123
+ return !!parseFunctionOrValue(this.options.enabled, this);
124
+ };
191
125
  /**
192
126
  * Returns the current limit of executions allowed within the time window
193
127
  */
194
- #getLimit;
128
+ #getLimit = () => {
129
+ return parseFunctionOrValue(this.options.limit, this);
130
+ };
195
131
  /**
196
132
  * Returns the current time window in milliseconds
197
133
  */
198
- #getWindow;
199
- #execute;
200
- #getExecutionTimesInWindow;
201
- #setCleanupTimeout;
202
- #clearTimeout;
203
- #clearTimeouts;
204
- #cleanupOldExecutions;
134
+ #getWindow = () => {
135
+ return parseFunctionOrValue(this.options.window, this);
136
+ };
137
+ /**
138
+ * Attempts to execute the rate-limited function if within the configured limits.
139
+ * Will reject execution if the number of calls in the current window exceeds the limit.
140
+ *
141
+ * @example
142
+ * ```ts
143
+ * const rateLimiter = new RateLimiter(fn, { limit: 5, window: 1000 });
144
+ *
145
+ * // First 5 calls will return true
146
+ * rateLimiter.maybeExecute('arg1', 'arg2'); // true
147
+ *
148
+ * // Additional calls within the window will return false
149
+ * rateLimiter.maybeExecute('arg1', 'arg2'); // false
150
+ * ```
151
+ */
152
+ maybeExecute = (...args) => {
153
+ this.#setState({ maybeExecuteCount: this.store.state.maybeExecuteCount + 1 });
154
+ this.#cleanupOldExecutions();
155
+ if (this.#getExecutionTimesInWindow().length < this.#getLimit()) {
156
+ this.#execute(...args);
157
+ return true;
158
+ }
159
+ this.#setState({ rejectionCount: this.store.state.rejectionCount + 1 });
160
+ this.options.onReject?.(this);
161
+ return false;
162
+ };
163
+ #execute = (...args) => {
164
+ if (!this.#getEnabled()) return;
165
+ const now = Date.now();
166
+ this.fn(...args);
167
+ this.store.state.executionTimes.push(now);
168
+ this.#setCleanupTimeout(now);
169
+ this.#setState({ executionCount: this.store.state.executionCount + 1 });
170
+ this.options.onExecute?.(args, this);
171
+ };
172
+ #getExecutionTimesInWindow = () => {
173
+ if (this.options.windowType === "sliding") return this.store.state.executionTimes.filter((time) => time > Date.now() - this.#getWindow());
174
+ else {
175
+ if (this.store.state.executionTimes.length === 0) return [];
176
+ const windowStart = Math.min(...this.store.state.executionTimes);
177
+ const windowEnd = windowStart + this.#getWindow();
178
+ if (Date.now() > windowEnd) return [];
179
+ return this.store.state.executionTimes.filter((time) => time >= windowStart && time <= windowEnd);
180
+ }
181
+ };
182
+ #setCleanupTimeout = (executionTime) => {
183
+ if (this.options.windowType === "sliding" || this.#timeoutIds.size === 0) {
184
+ const timeUntilExpiration = executionTime - Date.now() + this.#getWindow() + 1;
185
+ const timeoutId = setTimeout(() => {
186
+ this.#cleanupOldExecutions();
187
+ this.#clearTimeout(timeoutId);
188
+ }, timeUntilExpiration);
189
+ this.#timeoutIds.add(timeoutId);
190
+ }
191
+ };
192
+ #clearTimeout = (timeoutId) => {
193
+ clearTimeout(timeoutId);
194
+ this.#timeoutIds.delete(timeoutId);
195
+ };
196
+ #clearTimeouts = () => {
197
+ this.#timeoutIds.forEach((timeoutId) => clearTimeout(timeoutId));
198
+ this.#timeoutIds.clear();
199
+ };
200
+ #cleanupOldExecutions = () => {
201
+ this.#setState({ executionTimes: this.#getExecutionTimesInWindow() });
202
+ };
203
+ /**
204
+ * Returns the number of remaining executions allowed in the current window
205
+ */
206
+ getRemainingInWindow = () => {
207
+ const relevantExecutionTimes = this.#getExecutionTimesInWindow();
208
+ return Math.max(0, this.#getLimit() - relevantExecutionTimes.length);
209
+ };
210
+ /**
211
+ * Returns the number of milliseconds until the next execution will be possible
212
+ */
213
+ getMsUntilNextWindow = () => {
214
+ if (this.getRemainingInWindow() > 0) return 0;
215
+ return (this.store.state.executionTimes[0] ?? Infinity) + this.#getWindow() - Date.now();
216
+ };
217
+ /**
218
+ * Resets the rate limiter state
219
+ */
220
+ reset = () => {
221
+ this.#setState(getDefaultRateLimiterState());
222
+ this.#clearTimeouts();
223
+ };
205
224
  };
206
225
  /**
207
226
  * Creates a rate-limited function that will execute the provided function up to a maximum number of times within a time window.
@@ -256,5 +275,4 @@ function rateLimit(fn, initialOptions) {
256
275
  }
257
276
 
258
277
  //#endregion
259
- export { RateLimiter, rateLimit, rateLimiterOptions };
260
- //# sourceMappingURL=rate-limiter.js.map
278
+ export { RateLimiter, rateLimit, rateLimiterOptions };
@@ -1,7 +1,7 @@
1
1
  import { AnyFunction } from "./types.js";
2
2
  import { Store } from "@tanstack/store";
3
3
  //#region src/throttler.d.ts
4
- interface ThrottlerState<TFn extends AnyFunction> {
4
+ export interface ThrottlerState<TFn extends AnyFunction> {
5
5
  /**
6
6
  * Number of function executions that have been completed
7
7
  */
@@ -34,7 +34,7 @@ interface ThrottlerState<TFn extends AnyFunction> {
34
34
  /**
35
35
  * Options for configuring a throttled function
36
36
  */
37
- interface ThrottlerOptions<TFn extends AnyFunction> {
37
+ export interface ThrottlerOptions<TFn extends AnyFunction> {
38
38
  /**
39
39
  * Whether the throttler is enabled. When disabled, maybeExecute will not trigger any executions.
40
40
  * Can be a boolean or a function that returns a boolean.
@@ -74,7 +74,7 @@ interface ThrottlerOptions<TFn extends AnyFunction> {
74
74
  /**
75
75
  * Utility function for sharing common `ThrottlerOptions` options between different `Throttler` instances.
76
76
  */
77
- declare function throttlerOptions<TFn extends AnyFunction = AnyFunction, TOptions extends Partial<ThrottlerOptions<TFn>> = Partial<ThrottlerOptions<TFn>>>(options: TOptions): TOptions;
77
+ export declare function throttlerOptions<TFn extends AnyFunction = AnyFunction, TOptions extends Partial<ThrottlerOptions<TFn>> = Partial<ThrottlerOptions<TFn>>>(options: TOptions): TOptions;
78
78
  /**
79
79
  * A class that creates a throttled function.
80
80
  *
@@ -111,7 +111,7 @@ declare function throttlerOptions<TFn extends AnyFunction = AnyFunction, TOption
111
111
  * throttler.maybeExecute('123'); // Throttled
112
112
  * ```
113
113
  */
114
- declare class Throttler<TFn extends AnyFunction> {
114
+ export declare class Throttler<TFn extends AnyFunction> {
115
115
  #private;
116
116
  fn: TFn;
117
117
  readonly store: Store<Readonly<ThrottlerState<TFn>>>;
@@ -200,7 +200,5 @@ declare class Throttler<TFn extends AnyFunction> {
200
200
  * });
201
201
  * ```
202
202
  */
203
- declare function throttle<TFn extends AnyFunction>(fn: TFn, initialOptions: ThrottlerOptions<TFn>): (...args: Parameters<TFn>) => void;
204
- //#endregion
205
- export { Throttler, ThrottlerOptions, ThrottlerState, throttle, throttlerOptions };
206
- //# sourceMappingURL=throttler.d.ts.map
203
+ export declare function throttle<TFn extends AnyFunction>(fn: TFn, initialOptions: ThrottlerOptions<TFn>): (...args: Parameters<TFn>) => void;
204
+ //#endregion
package/dist/throttler.js CHANGED
@@ -63,92 +63,13 @@ const defaultOptions = {
63
63
  * ```
64
64
  */
65
65
  var Throttler = class {
66
+ fn;
67
+ store = new Store(getDefaultThrottlerState());
68
+ key;
69
+ options;
66
70
  #timeoutId;
67
71
  constructor(fn, initialOptions) {
68
72
  this.fn = fn;
69
- this.store = new Store(getDefaultThrottlerState());
70
- this.setOptions = (newOptions) => {
71
- this.options = {
72
- ...this.options,
73
- ...newOptions
74
- };
75
- if (!this.#getEnabled()) this.cancel();
76
- };
77
- this.#setState = (newState) => {
78
- this.store.setState((state) => {
79
- const combinedState = {
80
- ...state,
81
- ...newState
82
- };
83
- const { isPending } = combinedState;
84
- return {
85
- ...combinedState,
86
- status: !this.#getEnabled() ? "disabled" : isPending ? "pending" : "idle"
87
- };
88
- });
89
- emitChange("Throttler", this);
90
- };
91
- this.#getEnabled = () => {
92
- return !!parseFunctionOrValue(this.options.enabled, this);
93
- };
94
- this.#getWait = () => {
95
- return parseFunctionOrValue(this.options.wait, this);
96
- };
97
- this.maybeExecute = (...args) => {
98
- this.#setState({ maybeExecuteCount: this.store.state.maybeExecuteCount + 1 });
99
- const now = Date.now();
100
- const timeSinceLastExecution = now - this.store.state.lastExecutionTime;
101
- const wait = this.#getWait();
102
- if (this.options.leading && timeSinceLastExecution >= wait) this.#execute(...args);
103
- else {
104
- this.#setState({ lastArgs: args });
105
- if (!this.#timeoutId && this.options.trailing) {
106
- const timeoutDuration = wait - (this.store.state.lastExecutionTime ? now - this.store.state.lastExecutionTime : 0);
107
- this.#setState({ isPending: true });
108
- this.#timeoutId = setTimeout(() => {
109
- const { lastArgs } = this.store.state;
110
- if (lastArgs !== void 0) this.#execute(...lastArgs);
111
- }, timeoutDuration);
112
- }
113
- }
114
- };
115
- this.#execute = (...args) => {
116
- if (!this.#getEnabled()) return;
117
- this.fn(...args);
118
- const lastExecutionTime = Date.now();
119
- const nextExecutionTime = lastExecutionTime + this.#getWait();
120
- this.#clearTimeout();
121
- this.#setState({
122
- executionCount: this.store.state.executionCount + 1,
123
- lastExecutionTime,
124
- nextExecutionTime,
125
- isPending: false,
126
- lastArgs: void 0
127
- });
128
- this.options.onExecute?.(args, this);
129
- setTimeout(() => {
130
- if (!this.store.state.isPending) this.#setState({ nextExecutionTime: void 0 });
131
- }, this.#getWait());
132
- };
133
- this.flush = () => {
134
- if (this.store.state.isPending && this.store.state.lastArgs) this.#execute(...this.store.state.lastArgs);
135
- };
136
- this.#clearTimeout = () => {
137
- if (this.#timeoutId) {
138
- clearTimeout(this.#timeoutId);
139
- this.#timeoutId = void 0;
140
- }
141
- };
142
- this.cancel = () => {
143
- this.#clearTimeout();
144
- this.#setState({
145
- lastArgs: void 0,
146
- isPending: false
147
- });
148
- };
149
- this.reset = () => {
150
- this.#setState(getDefaultThrottlerState());
151
- };
152
73
  this.key = initialOptions.key;
153
74
  this.options = {
154
75
  ...defaultOptions,
@@ -161,11 +82,128 @@ var Throttler = class {
161
82
  this.setOptions(event.payload.options);
162
83
  });
163
84
  }
164
- #setState;
165
- #getEnabled;
166
- #getWait;
167
- #execute;
168
- #clearTimeout;
85
+ /**
86
+ * Updates the throttler options
87
+ */
88
+ setOptions = (newOptions) => {
89
+ this.options = {
90
+ ...this.options,
91
+ ...newOptions
92
+ };
93
+ if (!this.#getEnabled()) this.cancel();
94
+ };
95
+ #setState = (newState) => {
96
+ this.store.setState((state) => {
97
+ const combinedState = {
98
+ ...state,
99
+ ...newState
100
+ };
101
+ const { isPending } = combinedState;
102
+ return {
103
+ ...combinedState,
104
+ status: !this.#getEnabled() ? "disabled" : isPending ? "pending" : "idle"
105
+ };
106
+ });
107
+ emitChange("Throttler", this);
108
+ };
109
+ #getEnabled = () => {
110
+ return !!parseFunctionOrValue(this.options.enabled, this);
111
+ };
112
+ #getWait = () => {
113
+ return parseFunctionOrValue(this.options.wait, this);
114
+ };
115
+ /**
116
+ * Attempts to execute the throttled function. The execution behavior depends on the throttler options:
117
+ *
118
+ * - If enough time has passed since the last execution (>= wait period):
119
+ * - With leading=true: Executes immediately
120
+ * - With leading=false: Waits for the next trailing execution
121
+ *
122
+ * - If within the wait period:
123
+ * - With trailing=true: Schedules execution for end of wait period
124
+ * - With trailing=false: Drops the execution
125
+ *
126
+ * @example
127
+ * ```ts
128
+ * const throttled = new Throttler(fn, { wait: 1000 });
129
+ *
130
+ * // First call executes immediately
131
+ * throttled.maybeExecute('a', 'b');
132
+ *
133
+ * // Call during wait period - gets throttled
134
+ * throttled.maybeExecute('c', 'd');
135
+ * ```
136
+ */
137
+ maybeExecute = (...args) => {
138
+ this.#setState({ maybeExecuteCount: this.store.state.maybeExecuteCount + 1 });
139
+ const now = Date.now();
140
+ const timeSinceLastExecution = now - this.store.state.lastExecutionTime;
141
+ const wait = this.#getWait();
142
+ if (this.options.leading && timeSinceLastExecution >= wait) this.#execute(...args);
143
+ else {
144
+ this.#setState({ lastArgs: args });
145
+ if (!this.#timeoutId && this.options.trailing) {
146
+ const timeoutDuration = wait - (this.store.state.lastExecutionTime ? now - this.store.state.lastExecutionTime : 0);
147
+ this.#setState({ isPending: true });
148
+ this.#timeoutId = setTimeout(() => {
149
+ const { lastArgs } = this.store.state;
150
+ if (lastArgs !== void 0) this.#execute(...lastArgs);
151
+ }, timeoutDuration);
152
+ }
153
+ }
154
+ };
155
+ #execute = (...args) => {
156
+ if (!this.#getEnabled()) return;
157
+ this.fn(...args);
158
+ const lastExecutionTime = Date.now();
159
+ const nextExecutionTime = lastExecutionTime + this.#getWait();
160
+ this.#clearTimeout();
161
+ this.#setState({
162
+ executionCount: this.store.state.executionCount + 1,
163
+ lastExecutionTime,
164
+ nextExecutionTime,
165
+ isPending: false,
166
+ lastArgs: void 0
167
+ });
168
+ this.options.onExecute?.(args, this);
169
+ setTimeout(() => {
170
+ if (!this.store.state.isPending) this.#setState({ nextExecutionTime: void 0 });
171
+ }, this.#getWait());
172
+ };
173
+ /**
174
+ * Processes the current pending execution immediately
175
+ */
176
+ flush = () => {
177
+ if (this.store.state.isPending && this.store.state.lastArgs) this.#execute(...this.store.state.lastArgs);
178
+ };
179
+ #clearTimeout = () => {
180
+ if (this.#timeoutId) {
181
+ clearTimeout(this.#timeoutId);
182
+ this.#timeoutId = void 0;
183
+ }
184
+ };
185
+ /**
186
+ * Cancels any pending trailing execution and clears internal state.
187
+ *
188
+ * If a trailing execution is scheduled (due to throttling with trailing=true),
189
+ * this will prevent that execution from occurring. The internal timeout and
190
+ * stored arguments will be cleared.
191
+ *
192
+ * Has no effect if there is no pending execution.
193
+ */
194
+ cancel = () => {
195
+ this.#clearTimeout();
196
+ this.#setState({
197
+ lastArgs: void 0,
198
+ isPending: false
199
+ });
200
+ };
201
+ /**
202
+ * Resets the throttler state to its default values
203
+ */
204
+ reset = () => {
205
+ this.#setState(getDefaultThrottlerState());
206
+ };
169
207
  };
170
208
  /**
171
209
  * Creates a throttled function that limits how often the provided function can execute.
@@ -208,5 +246,4 @@ function throttle(fn, initialOptions) {
208
246
  }
209
247
 
210
248
  //#endregion
211
- export { Throttler, throttle, throttlerOptions };
212
- //# sourceMappingURL=throttler.js.map
249
+ export { Throttler, throttle, throttlerOptions };
package/dist/types.d.ts CHANGED
@@ -2,12 +2,10 @@
2
2
  /**
3
3
  * Represents a function that can be called with any arguments and returns any value.
4
4
  */
5
- type AnyFunction = (...args: Array<any>) => any;
5
+ export type AnyFunction = (...args: Array<any>) => any;
6
6
  /**
7
7
  * Represents an asynchronous function that can be called with any arguments and returns a promise.
8
8
  */
9
- type AnyAsyncFunction = (...args: Array<any>) => Promise<any>;
10
- type OptionalKeys<T, TKey extends keyof T> = Omit<T, TKey> & Partial<Pick<T, TKey>>;
11
- //#endregion
12
- export { AnyAsyncFunction, AnyFunction, OptionalKeys };
13
- //# sourceMappingURL=types.d.ts.map
9
+ export type AnyAsyncFunction = (...args: Array<any>) => Promise<any>;
10
+ export type OptionalKeys<T, TKey extends keyof T> = Omit<T, TKey> & Partial<Pick<T, TKey>>;
11
+ //#endregion
package/dist/utils.d.ts CHANGED
@@ -1,7 +1,5 @@
1
1
  import { AnyFunction } from "./types.js";
2
2
  //#region src/utils.d.ts
3
- declare function isFunction<T extends AnyFunction>(value: any): value is T;
4
- declare function parseFunctionOrValue<T, TArgs extends Array<any>>(value: T | ((...args: TArgs) => T), ...args: TArgs): T;
5
- //#endregion
6
- export { isFunction, parseFunctionOrValue };
7
- //# sourceMappingURL=utils.d.ts.map
3
+ export declare function isFunction<T extends AnyFunction>(value: any): value is T;
4
+ export declare function parseFunctionOrValue<T, TArgs extends Array<any>>(value: T | ((...args: TArgs) => T), ...args: TArgs): T;
5
+ //#endregion
package/dist/utils.js CHANGED
@@ -7,5 +7,4 @@ function parseFunctionOrValue(value, ...args) {
7
7
  }
8
8
 
9
9
  //#endregion
10
- export { isFunction, parseFunctionOrValue };
11
- //# sourceMappingURL=utils.js.map
10
+ export { isFunction, parseFunctionOrValue };