@tanstack/pacer-lite 0.2.1 → 0.3.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 (41) hide show
  1. package/README.md +29 -14
  2. package/dist/lite-batcher.d.ts +4 -6
  3. package/dist/lite-batcher.js +72 -45
  4. package/dist/lite-debouncer.d.ts +5 -9
  5. package/dist/lite-debouncer.js +58 -40
  6. package/dist/lite-queuer.d.ts +5 -7
  7. package/dist/lite-queuer.js +170 -89
  8. package/dist/lite-rate-limiter.d.ts +5 -9
  9. package/dist/lite-rate-limiter.js +89 -63
  10. package/dist/lite-throttler.d.ts +5 -9
  11. package/dist/lite-throttler.js +63 -40
  12. package/dist/pacer/dist/types.d.ts +7 -0
  13. package/package.json +13 -33
  14. package/dist/index.cjs +0 -16
  15. package/dist/index.d.cts +0 -6
  16. package/dist/lite-batcher.cjs +0 -175
  17. package/dist/lite-batcher.cjs.map +0 -1
  18. package/dist/lite-batcher.d.cts +0 -184
  19. package/dist/lite-batcher.js.map +0 -1
  20. package/dist/lite-debouncer.cjs +0 -125
  21. package/dist/lite-debouncer.cjs.map +0 -1
  22. package/dist/lite-debouncer.d.cts +0 -127
  23. package/dist/lite-debouncer.js.map +0 -1
  24. package/dist/lite-queuer.cjs +0 -208
  25. package/dist/lite-queuer.cjs.map +0 -1
  26. package/dist/lite-queuer.d.cts +0 -243
  27. package/dist/lite-queuer.js.map +0 -1
  28. package/dist/lite-rate-limiter.cjs +0 -149
  29. package/dist/lite-rate-limiter.cjs.map +0 -1
  30. package/dist/lite-rate-limiter.d.cts +0 -149
  31. package/dist/lite-rate-limiter.js.map +0 -1
  32. package/dist/lite-throttler.cjs +0 -127
  33. package/dist/lite-throttler.cjs.map +0 -1
  34. package/dist/lite-throttler.d.cts +0 -134
  35. package/dist/lite-throttler.js.map +0 -1
  36. package/src/index.ts +0 -5
  37. package/src/lite-batcher.ts +0 -267
  38. package/src/lite-debouncer.ts +0 -184
  39. package/src/lite-queuer.ts +0 -434
  40. package/src/lite-rate-limiter.ts +0 -246
  41. package/src/lite-throttler.ts +0 -195
@@ -60,96 +60,15 @@
60
60
  * ```
61
61
  */
62
62
  var LiteQueuer = class {
63
+ fn;
64
+ options;
65
+ items = [];
66
+ timeoutId = null;
67
+ isRunning = true;
68
+ pendingTick = false;
63
69
  constructor(fn, options = {}) {
64
70
  this.fn = fn;
65
71
  this.options = options;
66
- this.items = [];
67
- this.timeoutId = null;
68
- this.isRunning = true;
69
- this.pendingTick = false;
70
- this.addItem = (item, position = this.options.addItemsTo, startProcessing = true) => {
71
- if (this.items.length >= this.options.maxSize) return false;
72
- if (this.options.getPriority) {
73
- const priority = this.options.getPriority(item);
74
- if (priority !== void 0) {
75
- const insertIndex = this.items.findIndex((existing) => {
76
- return (this.options.getPriority(existing) ?? -Infinity) < priority;
77
- });
78
- if (insertIndex === -1) this.items.push(item);
79
- else this.items.splice(insertIndex, 0, item);
80
- } else this.insertAtPosition(item, position);
81
- } else this.insertAtPosition(item, position);
82
- if (startProcessing && this.isRunning && !this.pendingTick) this.tick();
83
- return true;
84
- };
85
- this.insertAtPosition = (item, position) => {
86
- if (position === "front") this.items.unshift(item);
87
- else this.items.push(item);
88
- };
89
- this.getNextItem = (position = this.options.getItemsFrom) => {
90
- if (this.items.length === 0) return;
91
- let item;
92
- if (this.options.getPriority || position === "front") item = this.items.shift();
93
- else item = this.items.pop();
94
- return item;
95
- };
96
- this.execute = (position) => {
97
- const item = this.getNextItem(position);
98
- if (item !== void 0) this.fn(item);
99
- return item;
100
- };
101
- this.tick = () => {
102
- if (!this.isRunning) {
103
- this.pendingTick = false;
104
- return;
105
- }
106
- this.pendingTick = true;
107
- while (this.items.length > 0) {
108
- if (this.execute(this.options.getItemsFrom) === void 0) break;
109
- const wait = this.options.wait;
110
- if (wait > 0) {
111
- this.timeoutId = setTimeout(() => this.tick(), wait);
112
- return;
113
- }
114
- }
115
- this.pendingTick = false;
116
- };
117
- this.start = () => {
118
- this.isRunning = true;
119
- if (!this.pendingTick && this.items.length > 0) this.tick();
120
- };
121
- this.stop = () => {
122
- this.clearTimeout();
123
- this.isRunning = false;
124
- this.pendingTick = false;
125
- };
126
- this.clearTimeout = () => {
127
- if (this.timeoutId) {
128
- clearTimeout(this.timeoutId);
129
- this.timeoutId = null;
130
- }
131
- };
132
- this.peekNextItem = (position = "front") => {
133
- if (this.items.length === 0) return;
134
- if (this.options.getPriority || position === "front") return this.items[0];
135
- else return this.items[this.items.length - 1];
136
- };
137
- this.peekAllItems = () => {
138
- return [...this.items];
139
- };
140
- this.flush = (numberOfItems = this.items.length, position) => {
141
- this.clearTimeout();
142
- for (let i = 0; i < numberOfItems && this.items.length > 0; i++) this.execute(position);
143
- if (this.isRunning && this.items.length > 0 && !this.pendingTick) this.tick();
144
- };
145
- this.flushAsBatch = (batchFunction) => {
146
- const items = this.peekAllItems();
147
- this.clear();
148
- batchFunction(items);
149
- };
150
- this.clear = () => {
151
- this.items = [];
152
- };
153
72
  this.options.addItemsTo = this.options.addItemsTo ?? "back";
154
73
  this.options.getItemsFrom = this.options.getItemsFrom ?? "front";
155
74
  this.options.maxSize = this.options.maxSize ?? Infinity;
@@ -177,6 +96,169 @@ var LiteQueuer = class {
177
96
  get isQueueRunning() {
178
97
  return this.isRunning;
179
98
  }
99
+ /**
100
+ * Adds an item to the queue. If the queue is full, the item is rejected.
101
+ * Items can be inserted at the front or back, and priority ordering is applied if getPriority is configured.
102
+ *
103
+ * Returns true if the item was added, false if the queue is full.
104
+ *
105
+ * @example
106
+ * ```ts
107
+ * queue.addItem('task1'); // Add to default position (back)
108
+ * queue.addItem('task2', 'front'); // Add to front
109
+ * ```
110
+ */
111
+ addItem = (item, position = this.options.addItemsTo, startProcessing = true) => {
112
+ if (this.items.length >= this.options.maxSize) return false;
113
+ if (this.options.getPriority) {
114
+ const priority = this.options.getPriority(item);
115
+ if (priority !== void 0) {
116
+ const insertIndex = this.items.findIndex((existing) => {
117
+ return (this.options.getPriority(existing) ?? -Infinity) < priority;
118
+ });
119
+ if (insertIndex === -1) this.items.push(item);
120
+ else this.items.splice(insertIndex, 0, item);
121
+ } else this.insertAtPosition(item, position);
122
+ } else this.insertAtPosition(item, position);
123
+ if (startProcessing && this.isRunning && !this.pendingTick) this.tick();
124
+ return true;
125
+ };
126
+ insertAtPosition = (item, position) => {
127
+ if (position === "front") this.items.unshift(item);
128
+ else this.items.push(item);
129
+ };
130
+ /**
131
+ * Removes and returns the next item from the queue without executing the function.
132
+ * Use for manual queue management. Normally, use execute() to process items.
133
+ *
134
+ * @example
135
+ * ```ts
136
+ * const nextItem = queue.getNextItem(); // Get from default position (front)
137
+ * const lastItem = queue.getNextItem('back'); // Get from back (LIFO)
138
+ * ```
139
+ */
140
+ getNextItem = (position = this.options.getItemsFrom) => {
141
+ if (this.items.length === 0) return;
142
+ let item;
143
+ if (this.options.getPriority || position === "front") item = this.items.shift();
144
+ else item = this.items.pop();
145
+ return item;
146
+ };
147
+ /**
148
+ * Removes and returns the next item from the queue and processes it using the provided function.
149
+ *
150
+ * @example
151
+ * ```ts
152
+ * queue.execute(); // Execute from default position
153
+ * queue.execute('back'); // Execute from back (LIFO)
154
+ * ```
155
+ */
156
+ execute = (position) => {
157
+ const item = this.getNextItem(position);
158
+ if (item !== void 0) this.fn(item);
159
+ return item;
160
+ };
161
+ /**
162
+ * Internal method that processes items in the queue with wait intervals
163
+ */
164
+ tick = () => {
165
+ if (!this.isRunning) {
166
+ this.pendingTick = false;
167
+ return;
168
+ }
169
+ this.pendingTick = true;
170
+ while (this.items.length > 0) {
171
+ if (this.execute(this.options.getItemsFrom) === void 0) break;
172
+ const wait = this.options.wait;
173
+ if (wait > 0) {
174
+ this.timeoutId = setTimeout(() => this.tick(), wait);
175
+ return;
176
+ }
177
+ }
178
+ this.pendingTick = false;
179
+ };
180
+ /**
181
+ * Starts processing items in the queue. If already running, does nothing.
182
+ */
183
+ start = () => {
184
+ this.isRunning = true;
185
+ if (!this.pendingTick && this.items.length > 0) this.tick();
186
+ };
187
+ /**
188
+ * Stops processing items in the queue. Does not clear the queue.
189
+ */
190
+ stop = () => {
191
+ this.clearTimeout();
192
+ this.isRunning = false;
193
+ this.pendingTick = false;
194
+ };
195
+ /**
196
+ * Clears any pending timeout
197
+ */
198
+ clearTimeout = () => {
199
+ if (this.timeoutId) {
200
+ clearTimeout(this.timeoutId);
201
+ this.timeoutId = null;
202
+ }
203
+ };
204
+ /**
205
+ * Returns the next item in the queue without removing it.
206
+ *
207
+ * @example
208
+ * ```ts
209
+ * const next = queue.peekNextItem(); // Peek at front
210
+ * const last = queue.peekNextItem('back'); // Peek at back
211
+ * ```
212
+ */
213
+ peekNextItem = (position = "front") => {
214
+ if (this.items.length === 0) return;
215
+ if (this.options.getPriority || position === "front") return this.items[0];
216
+ else return this.items[this.items.length - 1];
217
+ };
218
+ /**
219
+ * Returns a copy of all items in the queue.
220
+ */
221
+ peekAllItems = () => {
222
+ return [...this.items];
223
+ };
224
+ /**
225
+ * Processes a specified number of items immediately with no wait time.
226
+ * If no numberOfItems is provided, all items will be processed.
227
+ *
228
+ * @example
229
+ * ```ts
230
+ * queue.flush(); // Process all items immediately
231
+ * queue.flush(3); // Process next 3 items immediately
232
+ * ```
233
+ */
234
+ flush = (numberOfItems = this.items.length, position) => {
235
+ this.clearTimeout();
236
+ for (let i = 0; i < numberOfItems && this.items.length > 0; i++) this.execute(position);
237
+ if (this.isRunning && this.items.length > 0 && !this.pendingTick) this.tick();
238
+ };
239
+ /**
240
+ * Processes all items in the queue as a batch using the provided function.
241
+ * The queue is cleared after processing.
242
+ *
243
+ * @example
244
+ * ```ts
245
+ * queue.flushAsBatch((items) => {
246
+ * console.log('Processing batch:', items);
247
+ * // Process all items together
248
+ * });
249
+ * ```
250
+ */
251
+ flushAsBatch = (batchFunction) => {
252
+ const items = this.peekAllItems();
253
+ this.clear();
254
+ batchFunction(items);
255
+ };
256
+ /**
257
+ * Removes all items from the queue. Does not affect items being processed.
258
+ */
259
+ clear = () => {
260
+ this.items = [];
261
+ };
180
262
  };
181
263
  /**
182
264
  * Creates a lightweight queue that processes items using the provided function.
@@ -202,5 +284,4 @@ function liteQueue(fn, options = {}) {
202
284
  }
203
285
 
204
286
  //#endregion
205
- export { LiteQueuer, liteQueue };
206
- //# sourceMappingURL=lite-queuer.js.map
287
+ export { LiteQueuer, liteQueue };
@@ -1,11 +1,9 @@
1
- import { AnyFunction } from "@tanstack/pacer/types";
2
-
1
+ import { AnyFunction } from "./pacer/dist/types.js";
3
2
  //#region src/lite-rate-limiter.d.ts
4
-
5
3
  /**
6
4
  * Options for configuring a lite rate-limited function
7
5
  */
8
- interface LiteRateLimiterOptions<TFn extends AnyFunction = AnyFunction> {
6
+ export interface LiteRateLimiterOptions<TFn extends AnyFunction = AnyFunction> {
9
7
  /**
10
8
  * Maximum number of executions allowed within the time window.
11
9
  */
@@ -68,7 +66,7 @@ interface LiteRateLimiterOptions<TFn extends AnyFunction = AnyFunction> {
68
66
  * }
69
67
  * ```
70
68
  */
71
- declare class LiteRateLimiter<TFn extends AnyFunction> {
69
+ export declare class LiteRateLimiter<TFn extends AnyFunction> {
72
70
  fn: TFn;
73
71
  options: LiteRateLimiterOptions<TFn>;
74
72
  private executionTimes;
@@ -143,7 +141,5 @@ declare class LiteRateLimiter<TFn extends AnyFunction> {
143
141
  * });
144
142
  * ```
145
143
  */
146
- declare function liteRateLimit<TFn extends AnyFunction>(fn: TFn, options: LiteRateLimiterOptions<TFn>): (...args: Parameters<TFn>) => boolean;
147
- //#endregion
148
- export { LiteRateLimiter, LiteRateLimiterOptions, liteRateLimit };
149
- //# sourceMappingURL=lite-rate-limiter.d.ts.map
144
+ export declare function liteRateLimit<TFn extends AnyFunction>(fn: TFn, options: LiteRateLimiterOptions<TFn>): (...args: Parameters<TFn>) => boolean;
145
+ //#endregion
@@ -38,72 +38,99 @@
38
38
  * ```
39
39
  */
40
40
  var LiteRateLimiter = class {
41
+ fn;
42
+ options;
43
+ executionTimes = [];
44
+ timeoutIds = /* @__PURE__ */ new Set();
41
45
  constructor(fn, options) {
42
46
  this.fn = fn;
43
47
  this.options = options;
44
- this.executionTimes = [];
45
- this.timeoutIds = /* @__PURE__ */ new Set();
46
- this.maybeExecute = (...args) => {
47
- this.cleanupOldExecutions();
48
- if (this.getExecutionTimesInWindow().length < this.options.limit) {
49
- this.execute(...args);
50
- return true;
51
- }
52
- this.options.onReject?.(this);
53
- return false;
54
- };
55
- this.execute = (...args) => {
56
- const now = Date.now();
57
- this.fn(...args);
58
- this.options.onExecute?.(args, this);
59
- this.executionTimes.push(now);
60
- this.setCleanupTimeout(now);
61
- };
62
- this.getExecutionTimesInWindow = () => {
63
- if (this.options.windowType === "sliding") return this.executionTimes.filter((time) => time > Date.now() - this.options.window);
64
- else {
65
- if (this.executionTimes.length === 0) return [];
66
- const windowStart = Math.min(...this.executionTimes);
67
- const windowEnd = windowStart + this.options.window;
68
- if (Date.now() > windowEnd) return [];
69
- return this.executionTimes.filter((time) => time >= windowStart && time <= windowEnd);
70
- }
71
- };
72
- this.setCleanupTimeout = (executionTime) => {
73
- if (this.options.windowType === "sliding" || this.timeoutIds.size === 0) {
74
- const timeUntilExpiration = executionTime - Date.now() + this.options.window + 1;
75
- const timeoutId = setTimeout(() => {
76
- this.cleanupOldExecutions();
77
- this.clearTimeout(timeoutId);
78
- }, timeUntilExpiration);
79
- this.timeoutIds.add(timeoutId);
80
- }
81
- };
82
- this.clearTimeout = (timeoutId) => {
83
- clearTimeout(timeoutId);
84
- this.timeoutIds.delete(timeoutId);
85
- };
86
- this.clearTimeouts = () => {
87
- this.timeoutIds.forEach((timeoutId) => clearTimeout(timeoutId));
88
- this.timeoutIds.clear();
89
- };
90
- this.cleanupOldExecutions = () => {
91
- this.executionTimes = this.getExecutionTimesInWindow();
92
- };
93
- this.getRemainingInWindow = () => {
94
- const relevantExecutionTimes = this.getExecutionTimesInWindow();
95
- return Math.max(0, this.options.limit - relevantExecutionTimes.length);
96
- };
97
- this.getMsUntilNextWindow = () => {
98
- if (this.getRemainingInWindow() > 0) return 0;
99
- return (this.executionTimes[0] ?? Infinity) + this.options.window - Date.now();
100
- };
101
- this.reset = () => {
102
- this.executionTimes = [];
103
- this.clearTimeouts();
104
- };
105
48
  if (this.options.windowType === void 0) this.options.windowType = "fixed";
106
49
  }
50
+ /**
51
+ * Attempts to execute the rate-limited function if within the configured limits.
52
+ * Returns true if executed, false if rejected due to rate limiting.
53
+ *
54
+ * @example
55
+ * ```ts
56
+ * const rateLimiter = new LiteRateLimiter(fn, { limit: 5, window: 1000 });
57
+ *
58
+ * // First 5 calls return true
59
+ * rateLimiter.maybeExecute('arg1', 'arg2'); // true
60
+ *
61
+ * // Additional calls within the window return false
62
+ * rateLimiter.maybeExecute('arg1', 'arg2'); // false
63
+ * ```
64
+ */
65
+ maybeExecute = (...args) => {
66
+ this.cleanupOldExecutions();
67
+ if (this.getExecutionTimesInWindow().length < this.options.limit) {
68
+ this.execute(...args);
69
+ return true;
70
+ }
71
+ this.options.onReject?.(this);
72
+ return false;
73
+ };
74
+ execute = (...args) => {
75
+ const now = Date.now();
76
+ this.fn(...args);
77
+ this.options.onExecute?.(args, this);
78
+ this.executionTimes.push(now);
79
+ this.setCleanupTimeout(now);
80
+ };
81
+ getExecutionTimesInWindow = () => {
82
+ if (this.options.windowType === "sliding") return this.executionTimes.filter((time) => time > Date.now() - this.options.window);
83
+ else {
84
+ if (this.executionTimes.length === 0) return [];
85
+ const windowStart = Math.min(...this.executionTimes);
86
+ const windowEnd = windowStart + this.options.window;
87
+ if (Date.now() > windowEnd) return [];
88
+ return this.executionTimes.filter((time) => time >= windowStart && time <= windowEnd);
89
+ }
90
+ };
91
+ setCleanupTimeout = (executionTime) => {
92
+ if (this.options.windowType === "sliding" || this.timeoutIds.size === 0) {
93
+ const timeUntilExpiration = executionTime - Date.now() + this.options.window + 1;
94
+ const timeoutId = setTimeout(() => {
95
+ this.cleanupOldExecutions();
96
+ this.clearTimeout(timeoutId);
97
+ }, timeUntilExpiration);
98
+ this.timeoutIds.add(timeoutId);
99
+ }
100
+ };
101
+ clearTimeout = (timeoutId) => {
102
+ clearTimeout(timeoutId);
103
+ this.timeoutIds.delete(timeoutId);
104
+ };
105
+ clearTimeouts = () => {
106
+ this.timeoutIds.forEach((timeoutId) => clearTimeout(timeoutId));
107
+ this.timeoutIds.clear();
108
+ };
109
+ cleanupOldExecutions = () => {
110
+ this.executionTimes = this.getExecutionTimesInWindow();
111
+ };
112
+ /**
113
+ * Returns the number of remaining executions allowed in the current window.
114
+ */
115
+ getRemainingInWindow = () => {
116
+ const relevantExecutionTimes = this.getExecutionTimesInWindow();
117
+ return Math.max(0, this.options.limit - relevantExecutionTimes.length);
118
+ };
119
+ /**
120
+ * Returns the number of milliseconds until the next execution will be possible.
121
+ * Returns 0 if executions are currently allowed.
122
+ */
123
+ getMsUntilNextWindow = () => {
124
+ if (this.getRemainingInWindow() > 0) return 0;
125
+ return (this.executionTimes[0] ?? Infinity) + this.options.window - Date.now();
126
+ };
127
+ /**
128
+ * Resets the rate limiter state, clearing all execution history.
129
+ */
130
+ reset = () => {
131
+ this.executionTimes = [];
132
+ this.clearTimeouts();
133
+ };
107
134
  };
108
135
  /**
109
136
  * Creates a lightweight rate-limited function that will execute the provided function up to a maximum number of times within a time window.
@@ -143,5 +170,4 @@ function liteRateLimit(fn, options) {
143
170
  }
144
171
 
145
172
  //#endregion
146
- export { LiteRateLimiter, liteRateLimit };
147
- //# sourceMappingURL=lite-rate-limiter.js.map
173
+ export { LiteRateLimiter, liteRateLimit };
@@ -1,11 +1,9 @@
1
- import { AnyFunction } from "@tanstack/pacer/types";
2
-
1
+ import { AnyFunction } from "./pacer/dist/types.js";
3
2
  //#region src/lite-throttler.d.ts
4
-
5
3
  /**
6
4
  * Options for configuring a lite throttled function
7
5
  */
8
- interface LiteThrottlerOptions<TFn extends AnyFunction = AnyFunction> {
6
+ export interface LiteThrottlerOptions<TFn extends AnyFunction = AnyFunction> {
9
7
  /**
10
8
  * Whether to execute on the leading edge of the timeout.
11
9
  * Defaults to true.
@@ -65,7 +63,7 @@ interface LiteThrottlerOptions<TFn extends AnyFunction = AnyFunction> {
65
63
  * });
66
64
  * ```
67
65
  */
68
- declare class LiteThrottler<TFn extends AnyFunction> {
66
+ export declare class LiteThrottler<TFn extends AnyFunction> {
69
67
  fn: TFn;
70
68
  options: LiteThrottlerOptions<TFn>;
71
69
  private timeoutId;
@@ -128,7 +126,5 @@ declare class LiteThrottler<TFn extends AnyFunction> {
128
126
  * }, { wait: 250, leading: true, trailing: false });
129
127
  * ```
130
128
  */
131
- declare function liteThrottle<TFn extends AnyFunction>(fn: TFn, options: LiteThrottlerOptions<TFn>): (...args: Parameters<TFn>) => void;
132
- //#endregion
133
- export { LiteThrottler, LiteThrottlerOptions, liteThrottle };
134
- //# sourceMappingURL=lite-throttler.d.ts.map
129
+ export declare function liteThrottle<TFn extends AnyFunction>(fn: TFn, options: LiteThrottlerOptions<TFn>): (...args: Parameters<TFn>) => void;
130
+ //#endregion
@@ -40,52 +40,76 @@
40
40
  * ```
41
41
  */
42
42
  var LiteThrottler = class {
43
+ fn;
44
+ options;
45
+ timeoutId;
46
+ lastArgs;
47
+ lastExecutionTime = 0;
48
+ isPending = false;
43
49
  constructor(fn, options) {
44
50
  this.fn = fn;
45
51
  this.options = options;
46
- this.lastExecutionTime = 0;
47
- this.isPending = false;
48
- this.maybeExecute = (...args) => {
49
- const timeSinceLastExecution = Date.now() - this.lastExecutionTime;
50
- if (this.options.leading && timeSinceLastExecution >= this.options.wait) this.execute(...args);
51
- else {
52
- this.lastArgs = args;
53
- if (!this.timeoutId && this.options.trailing) {
54
- const timeoutDuration = this.options.wait - timeSinceLastExecution;
55
- this.isPending = true;
56
- this.timeoutId = setTimeout(() => {
57
- if (this.lastArgs !== void 0) this.execute(...this.lastArgs);
58
- }, timeoutDuration);
59
- }
60
- }
61
- };
62
- this.execute = (...args) => {
63
- this.fn(...args);
64
- this.options.onExecute?.(args, this);
65
- this.lastExecutionTime = Date.now();
66
- this.clearTimeout();
67
- this.lastArgs = void 0;
68
- this.isPending = false;
69
- };
70
- this.flush = () => {
71
- if (this.isPending && this.lastArgs) this.execute(...this.lastArgs);
72
- };
73
- this.cancel = () => {
74
- this.clearTimeout();
75
- this.lastArgs = void 0;
76
- this.isPending = false;
77
- };
78
- this.clearTimeout = () => {
79
- if (this.timeoutId) {
80
- clearTimeout(this.timeoutId);
81
- this.timeoutId = void 0;
82
- }
83
- };
84
52
  if (this.options.leading === void 0 && this.options.trailing === void 0) {
85
53
  this.options.leading = true;
86
54
  this.options.trailing = true;
87
55
  }
88
56
  }
57
+ /**
58
+ * Attempts to execute the throttled function. The execution behavior depends on the throttler options:
59
+ *
60
+ * - If enough time has passed since the last execution (>= wait period):
61
+ * - With leading=true: Executes immediately
62
+ * - With leading=false: Waits for the next trailing execution
63
+ *
64
+ * - If within the wait period:
65
+ * - With trailing=true: Schedules execution for end of wait period
66
+ * - With trailing=false: Drops the execution
67
+ */
68
+ maybeExecute = (...args) => {
69
+ const timeSinceLastExecution = Date.now() - this.lastExecutionTime;
70
+ if (this.options.leading && timeSinceLastExecution >= this.options.wait) this.execute(...args);
71
+ else {
72
+ this.lastArgs = args;
73
+ if (!this.timeoutId && this.options.trailing) {
74
+ const timeoutDuration = this.options.wait - timeSinceLastExecution;
75
+ this.isPending = true;
76
+ this.timeoutId = setTimeout(() => {
77
+ if (this.lastArgs !== void 0) this.execute(...this.lastArgs);
78
+ }, timeoutDuration);
79
+ }
80
+ }
81
+ };
82
+ execute = (...args) => {
83
+ this.fn(...args);
84
+ this.options.onExecute?.(args, this);
85
+ this.lastExecutionTime = Date.now();
86
+ this.clearTimeout();
87
+ this.lastArgs = void 0;
88
+ this.isPending = false;
89
+ };
90
+ /**
91
+ * Processes the current pending execution immediately.
92
+ * If there's a pending execution, it will be executed right away
93
+ * and the timeout will be cleared.
94
+ */
95
+ flush = () => {
96
+ if (this.isPending && this.lastArgs) this.execute(...this.lastArgs);
97
+ };
98
+ /**
99
+ * Cancels any pending trailing execution and clears internal state.
100
+ * If a trailing execution is scheduled, this will prevent that execution from occurring.
101
+ */
102
+ cancel = () => {
103
+ this.clearTimeout();
104
+ this.lastArgs = void 0;
105
+ this.isPending = false;
106
+ };
107
+ clearTimeout = () => {
108
+ if (this.timeoutId) {
109
+ clearTimeout(this.timeoutId);
110
+ this.timeoutId = void 0;
111
+ }
112
+ };
89
113
  };
90
114
  /**
91
115
  * Creates a lightweight throttled function that limits how often the provided function can execute.
@@ -121,5 +145,4 @@ function liteThrottle(fn, options) {
121
145
  }
122
146
 
123
147
  //#endregion
124
- export { LiteThrottler, liteThrottle };
125
- //# sourceMappingURL=lite-throttler.js.map
148
+ export { LiteThrottler, liteThrottle };
@@ -0,0 +1,7 @@
1
+ //#region ../pacer/dist/types.d.ts
2
+ //#region src/types.d.ts
3
+ /**
4
+ * Represents a function that can be called with any arguments and returns any value.
5
+ */
6
+ export type AnyFunction = (...args: Array<any>) => any;
7
+ //#endregion