@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
@@ -1,267 +0,0 @@
1
- /**
2
- * Options for configuring a lite batcher instance
3
- */
4
- export interface LiteBatcherOptions<TValue> {
5
- /**
6
- * Custom function to determine if a batch should be processed
7
- * Return true to process the batch immediately
8
- */
9
- getShouldExecute?: (
10
- items: Array<TValue>,
11
- batcher: LiteBatcher<TValue>,
12
- ) => boolean
13
- /**
14
- * Maximum number of items in a batch
15
- * @default Infinity
16
- */
17
- maxSize?: number
18
- /**
19
- * Callback fired after a batch is processed
20
- */
21
- onExecute?: (batch: Array<TValue>, batcher: LiteBatcher<TValue>) => void
22
- /**
23
- * Callback fired after items are added to the batcher
24
- */
25
- onItemsChange?: (batcher: LiteBatcher<TValue>) => void
26
- /**
27
- * Whether the batcher should start processing immediately
28
- * @default true
29
- */
30
- started?: boolean
31
- /**
32
- * Maximum time in milliseconds to wait before processing a batch.
33
- * If the wait duration has elapsed, the batch will be processed.
34
- * If not provided, the batch will not be triggered by a timeout.
35
- * @default Infinity
36
- */
37
- wait?: number | ((batcher: LiteBatcher<TValue>) => number)
38
- }
39
-
40
- /**
41
- * A lightweight class that collects items and processes them in batches.
42
- *
43
- * This is an alternative to the Batcher in the core @tanstack/pacer package, but is more
44
- * suitable for libraries and npm packages that need minimal overhead. Unlike the core Batcher,
45
- * this version does not use TanStack Store for state management, has no devtools integration,
46
- * no callbacks, and provides only essential batching functionality.
47
- *
48
- * Batching is a technique for grouping multiple operations together to be processed as a single unit.
49
- * This synchronous version is lighter weight and often all you need.
50
- *
51
- * The Batcher provides a flexible way to implement batching with configurable:
52
- * - Maximum batch size (number of items per batch)
53
- * - Time-based batching (process after X milliseconds)
54
- * - Custom batch processing logic via getShouldExecute
55
- *
56
- * Features included:
57
- * - Core batching functionality (addItem, flush, clear, cancel)
58
- * - Size-based batching (maxSize)
59
- * - Time-based batching (wait timeout)
60
- * - Custom condition batching (getShouldExecute)
61
- * - Manual processing controls
62
- * - Public mutable options
63
- * - Callback support for monitoring batch execution and state changes
64
- *
65
- * Features NOT included (compared to core Batcher):
66
- * - No TanStack Store state management
67
- * - No devtools integration
68
- * - No complex state tracking (execution counts, etc.)
69
- * - No reactive state management
70
- *
71
- * @example
72
- * ```ts
73
- * // Basic batching
74
- * const batcher = new LiteBatcher<number>(
75
- * (items) => console.log('Processing batch:', items),
76
- * {
77
- * maxSize: 5,
78
- * wait: 2000,
79
- * onExecute: (batch, batcher) => {
80
- * console.log('Batch executed with', batch.length, 'items');
81
- * },
82
- * onItemsChange: (batcher) => {
83
- * console.log('Batch size changed to:', batcher.size);
84
- * }
85
- * }
86
- * );
87
- *
88
- * batcher.addItem(1);
89
- * batcher.addItem(2);
90
- * // After 2 seconds or when 5 items are added, whichever comes first,
91
- * // the batch will be processed
92
- * ```
93
- *
94
- * @example
95
- * ```ts
96
- * // Custom condition batching
97
- * const batcher = new LiteBatcher<Task>(
98
- * (items) => processTasks(items),
99
- * {
100
- * getShouldExecute: (items) => items.some(task => task.urgent),
101
- * maxSize: 10,
102
- * }
103
- * );
104
- *
105
- * batcher.addItem({ name: 'normal', urgent: false });
106
- * batcher.addItem({ name: 'urgent', urgent: true }); // Triggers immediate processing
107
- * ```
108
- */
109
- export class LiteBatcher<TValue> {
110
- private items: Array<TValue> = []
111
- private timeoutId: NodeJS.Timeout | null = null
112
- private _isPending = false
113
-
114
- constructor(
115
- public fn: (items: Array<TValue>) => void,
116
- public options: LiteBatcherOptions<TValue> = {},
117
- ) {
118
- // Set defaults
119
- this.options.maxSize = this.options.maxSize ?? Infinity
120
- this.options.started = this.options.started ?? true
121
- this.options.wait = this.options.wait ?? Infinity
122
- this.options.getShouldExecute =
123
- this.options.getShouldExecute ?? (() => false)
124
- }
125
-
126
- /**
127
- * Number of items currently in the batch
128
- */
129
- get size(): number {
130
- return this.items.length
131
- }
132
-
133
- /**
134
- * Whether the batch has no items to process (items array is empty)
135
- */
136
- get isEmpty(): boolean {
137
- return this.items.length === 0
138
- }
139
-
140
- /**
141
- * Whether the batcher is waiting for the timeout to trigger batch processing
142
- */
143
- get isPending(): boolean {
144
- return this._isPending
145
- }
146
-
147
- private getWait(): number {
148
- if (typeof this.options.wait === 'function') {
149
- return this.options.wait(this)
150
- }
151
- return this.options.wait!
152
- }
153
-
154
- /**
155
- * Adds an item to the batcher
156
- * If the batch size is reached, timeout occurs, or getShouldExecute returns true, the batch will be processed
157
- */
158
- addItem = (item: TValue): void => {
159
- this.items.push(item)
160
- this._isPending = this.options.wait !== Infinity
161
- this.options.onItemsChange?.(this)
162
-
163
- const shouldProcess =
164
- this.items.length >= this.options.maxSize! ||
165
- this.options.getShouldExecute!(this.items, this)
166
-
167
- if (shouldProcess) {
168
- this.execute()
169
- } else if (this.options.wait !== Infinity) {
170
- this.clearTimeout() // clear any pending timeout to replace it with a new one
171
- this.timeoutId = setTimeout(() => this.execute(), this.getWait())
172
- }
173
- }
174
-
175
- /**
176
- * Processes the current batch of items.
177
- * This method will automatically be triggered if the batcher is running and any of these conditions are met:
178
- * - The number of items reaches maxSize
179
- * - The wait duration has elapsed
180
- * - The getShouldExecute function returns true upon adding an item
181
- *
182
- * You can also call this method manually to process the current batch at any time.
183
- */
184
- private execute = (): void => {
185
- if (this.items.length === 0) {
186
- return
187
- }
188
-
189
- const batch = this.peekAllItems() // copy of the items to be processed (to prevent race conditions)
190
- this.clear() // Clear items before processing to prevent race conditions
191
-
192
- this.fn(batch) // EXECUTE
193
- this.options.onExecute?.(batch, this)
194
- }
195
-
196
- /**
197
- * Processes the current batch of items immediately
198
- */
199
- flush = (): void => {
200
- this.clearTimeout() // clear any pending timeout
201
- this.execute() // execute immediately
202
- }
203
-
204
- /**
205
- * Returns a copy of all items in the batcher
206
- */
207
- peekAllItems = (): Array<TValue> => {
208
- return [...this.items]
209
- }
210
-
211
- private clearTimeout = (): void => {
212
- if (this.timeoutId) {
213
- clearTimeout(this.timeoutId)
214
- this.timeoutId = null
215
- }
216
- }
217
-
218
- /**
219
- * Removes all items from the batcher
220
- */
221
- clear = (): void => {
222
- const hadItems = this.items.length > 0
223
- this.items = []
224
- this._isPending = false
225
- if (hadItems) {
226
- this.options.onItemsChange?.(this)
227
- }
228
- }
229
-
230
- /**
231
- * Cancels any pending execution that was scheduled.
232
- * Does NOT clear out the items.
233
- */
234
- cancel = (): void => {
235
- this.clearTimeout()
236
- this._isPending = false
237
- }
238
- }
239
-
240
- /**
241
- * Creates a batcher that processes items in batches.
242
- *
243
- * This is an alternative to the batch function in the core @tanstack/pacer package, but is more
244
- * suitable for libraries and npm packages that need minimal overhead. Unlike the core version,
245
- * this function creates a batcher with no external dependencies, devtools integration, or reactive state.
246
- *
247
- * @example
248
- * ```ts
249
- * const batchItems = liteBatch<number>(
250
- * (items) => console.log('Processing:', items),
251
- * {
252
- * maxSize: 3,
253
- * }
254
- * );
255
- *
256
- * batchItems(1);
257
- * batchItems(2);
258
- * batchItems(3); // Triggers batch processing
259
- * ```
260
- */
261
- export function liteBatch<TValue>(
262
- fn: (items: Array<TValue>) => void,
263
- options: LiteBatcherOptions<TValue> = {},
264
- ): (item: TValue) => void {
265
- const batcher = new LiteBatcher<TValue>(fn, options)
266
- return batcher.addItem
267
- }
@@ -1,184 +0,0 @@
1
- import type { AnyFunction } from '@tanstack/pacer/types'
2
-
3
- /**
4
- * Options for configuring a lite debounced function
5
- */
6
- export interface LiteDebouncerOptions<TFn extends AnyFunction = AnyFunction> {
7
- /**
8
- * Whether to execute on the leading edge of the timeout.
9
- * The first call will execute immediately and the rest will wait the delay.
10
- * Defaults to false.
11
- */
12
- leading?: boolean
13
- /**
14
- * Callback function that is called after the function is executed
15
- */
16
- onExecute?: (args: Parameters<TFn>, debouncer: LiteDebouncer<TFn>) => void
17
- /**
18
- * Whether to execute on the trailing edge of the timeout.
19
- * Defaults to true.
20
- */
21
- trailing?: boolean
22
- /**
23
- * Delay in milliseconds before executing the function.
24
- */
25
- wait: number
26
- }
27
-
28
- /**
29
- * A lightweight class that creates a debounced function.
30
- *
31
- * This is an alternative to the Debouncer in the core @tanstack/pacer package, but is more
32
- * suitable for libraries and npm packages that need minimal overhead. Unlike the core Debouncer,
33
- * this version does not use TanStack Store for state management, has no devtools integration,
34
- * and provides only essential debouncing functionality.
35
- *
36
- * Debouncing ensures that a function is only executed after a certain amount of time has passed
37
- * since its last invocation. This is useful for handling frequent events like window resizing,
38
- * scroll events, or input changes where you want to limit the rate of execution.
39
- *
40
- * The debounced function can be configured to execute either at the start of the delay period
41
- * (leading edge) or at the end (trailing edge, default). Each new call during the wait period
42
- * will reset the timer.
43
- *
44
- * Features:
45
- * - Zero dependencies - no external libraries required
46
- * - Minimal API surface - only essential methods (maybeExecute, flush, cancel)
47
- * - Simple state management - uses basic private properties instead of reactive stores
48
- * - Callback support for monitoring execution events
49
- * - Lightweight - designed for use in npm packages where bundle size matters
50
- *
51
- * @example
52
- * ```ts
53
- * const debouncer = new LiteDebouncer((value: string) => {
54
- * saveToDatabase(value);
55
- * }, {
56
- * wait: 500,
57
- * onExecute: (args, debouncer) => {
58
- * console.log('Saved value:', args[0]);
59
- * }
60
- * });
61
- *
62
- * // Will only save after 500ms of no new input
63
- * inputElement.addEventListener('input', () => {
64
- * debouncer.maybeExecute(inputElement.value);
65
- * });
66
- * ```
67
- */
68
- export class LiteDebouncer<TFn extends AnyFunction> {
69
- private timeoutId: NodeJS.Timeout | undefined
70
- private lastArgs: Parameters<TFn> | undefined
71
- private canLeadingExecute = true
72
-
73
- constructor(
74
- public fn: TFn,
75
- public options: LiteDebouncerOptions<TFn>,
76
- ) {
77
- // Default trailing to true if neither leading nor trailing is specified
78
- if (
79
- this.options.leading === undefined &&
80
- this.options.trailing === undefined
81
- ) {
82
- this.options.trailing = true
83
- }
84
- }
85
-
86
- /**
87
- * Attempts to execute the debounced function.
88
- * If leading is true and this is the first call, executes immediately.
89
- * Otherwise, queues the execution for after the wait time.
90
- * Each new call resets the timer.
91
- */
92
- maybeExecute = (...args: Parameters<TFn>): void => {
93
- let didLeadingExecute = false
94
-
95
- if (this.options.leading && this.canLeadingExecute) {
96
- this.canLeadingExecute = false
97
- didLeadingExecute = true
98
- this.fn(...args)
99
- this.options.onExecute?.(args, this)
100
- }
101
-
102
- this.lastArgs = args
103
-
104
- if (this.timeoutId) {
105
- clearTimeout(this.timeoutId)
106
- }
107
-
108
- this.timeoutId = setTimeout(() => {
109
- this.canLeadingExecute = true
110
- if (this.options.trailing && !didLeadingExecute && this.lastArgs) {
111
- this.fn(...this.lastArgs)
112
- this.options.onExecute?.(this.lastArgs, this)
113
- }
114
- this.lastArgs = undefined
115
- }, this.options.wait)
116
- }
117
-
118
- /**
119
- * Processes the current pending execution immediately.
120
- * If there's a pending execution, it will be executed right away
121
- * and the timeout will be cleared.
122
- */
123
- flush = (): void => {
124
- if (this.timeoutId && this.lastArgs) {
125
- clearTimeout(this.timeoutId)
126
- this.timeoutId = undefined
127
- const args = this.lastArgs
128
- this.fn(...args)
129
- this.options.onExecute?.(args, this)
130
- this.lastArgs = undefined
131
- this.canLeadingExecute = true
132
- }
133
- }
134
-
135
- /**
136
- * Cancels any pending execution.
137
- * Clears the timeout and resets the internal state.
138
- */
139
- cancel = (): void => {
140
- if (this.timeoutId) {
141
- clearTimeout(this.timeoutId)
142
- this.timeoutId = undefined
143
- }
144
- this.lastArgs = undefined
145
- this.canLeadingExecute = true
146
- }
147
- }
148
-
149
- /**
150
- * Creates a lightweight debounced function that delays invoking the provided function until after a specified wait time.
151
- * Multiple calls during the wait period will cancel previous pending invocations and reset the timer.
152
- *
153
- * This is an alternative to the debounce function in the core @tanstack/pacer package, but is more
154
- * suitable for libraries and npm packages that need minimal overhead. Unlike the core version,
155
- * this function creates a debouncer with no external dependencies, devtools integration, or reactive state.
156
- *
157
- * If leading option is true, the function will execute immediately on the first call, then wait the delay
158
- * before allowing another execution.
159
- *
160
- * @example
161
- * ```ts
162
- * const debouncedSave = liteDebounce(() => {
163
- * saveChanges();
164
- * }, { wait: 1000 });
165
- *
166
- * // Called repeatedly but executes at most once per second
167
- * inputElement.addEventListener('input', debouncedSave);
168
- * ```
169
- *
170
- * @example
171
- * ```ts
172
- * // Leading edge execution - fires immediately then waits
173
- * const debouncedSearch = liteDebounce((query: string) => {
174
- * performSearch(query);
175
- * }, { wait: 300, leading: true });
176
- * ```
177
- */
178
- export function liteDebounce<TFn extends AnyFunction>(
179
- fn: TFn,
180
- options: LiteDebouncerOptions<TFn>,
181
- ): (...args: Parameters<TFn>) => void {
182
- const debouncer = new LiteDebouncer(fn, options)
183
- return debouncer.maybeExecute
184
- }