@tanstack/pacer 0.16.2 → 0.16.4

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 (180) hide show
  1. package/README.md +165 -0
  2. package/dist/async-batcher.cjs +355 -0
  3. package/dist/async-batcher.cjs.map +1 -0
  4. package/dist/async-batcher.d.cts +344 -0
  5. package/dist/async-batcher.d.ts +344 -0
  6. package/dist/async-batcher.js +353 -0
  7. package/dist/async-batcher.js.map +1 -0
  8. package/dist/async-debouncer.cjs +340 -0
  9. package/dist/async-debouncer.cjs.map +1 -0
  10. package/dist/async-debouncer.d.cts +300 -0
  11. package/dist/async-debouncer.d.ts +300 -0
  12. package/dist/async-debouncer.js +338 -0
  13. package/dist/async-debouncer.js.map +1 -0
  14. package/dist/async-queuer.cjs +496 -0
  15. package/dist/async-queuer.cjs.map +1 -0
  16. package/dist/async-queuer.d.cts +440 -0
  17. package/dist/async-queuer.d.ts +440 -0
  18. package/dist/async-queuer.js +494 -0
  19. package/dist/async-queuer.js.map +1 -0
  20. package/dist/async-rate-limiter.cjs +381 -0
  21. package/dist/async-rate-limiter.cjs.map +1 -0
  22. package/dist/{cjs/async-rate-limiter.d.cts → async-rate-limiter.d.cts} +190 -185
  23. package/dist/{esm/async-rate-limiter.d.ts → async-rate-limiter.d.ts} +190 -185
  24. package/dist/async-rate-limiter.js +379 -0
  25. package/dist/async-rate-limiter.js.map +1 -0
  26. package/dist/async-retryer.cjs +378 -0
  27. package/dist/async-retryer.cjs.map +1 -0
  28. package/dist/async-retryer.d.cts +312 -0
  29. package/dist/async-retryer.d.ts +312 -0
  30. package/dist/async-retryer.js +376 -0
  31. package/dist/async-retryer.js.map +1 -0
  32. package/dist/async-throttler.cjs +362 -0
  33. package/dist/async-throttler.cjs.map +1 -0
  34. package/dist/async-throttler.d.cts +320 -0
  35. package/dist/async-throttler.d.ts +320 -0
  36. package/dist/async-throttler.js +360 -0
  37. package/dist/async-throttler.js.map +1 -0
  38. package/dist/batcher.cjs +194 -0
  39. package/dist/batcher.cjs.map +1 -0
  40. package/dist/batcher.d.cts +180 -0
  41. package/dist/batcher.d.ts +180 -0
  42. package/dist/batcher.js +193 -0
  43. package/dist/batcher.js.map +1 -0
  44. package/dist/debouncer.cjs +197 -0
  45. package/dist/debouncer.cjs.map +1 -0
  46. package/dist/debouncer.d.cts +167 -0
  47. package/dist/debouncer.d.ts +167 -0
  48. package/dist/debouncer.js +195 -0
  49. package/dist/debouncer.js.map +1 -0
  50. package/dist/event-client.cjs +20 -0
  51. package/dist/event-client.cjs.map +1 -0
  52. package/dist/event-client.d.cts +49 -0
  53. package/dist/event-client.d.ts +49 -0
  54. package/dist/event-client.js +19 -0
  55. package/dist/event-client.js.map +1 -0
  56. package/dist/index.cjs +49 -0
  57. package/dist/index.d.cts +15 -0
  58. package/dist/index.d.ts +15 -0
  59. package/dist/{esm/index.js → index.js} +5 -41
  60. package/dist/queuer.cjs +393 -0
  61. package/dist/queuer.cjs.map +1 -0
  62. package/dist/queuer.d.cts +345 -0
  63. package/dist/queuer.d.ts +345 -0
  64. package/dist/queuer.js +391 -0
  65. package/dist/queuer.js.map +1 -0
  66. package/dist/rate-limiter.cjs +251 -0
  67. package/dist/rate-limiter.cjs.map +1 -0
  68. package/dist/{cjs/rate-limiter.d.cts → rate-limiter.d.cts} +113 -108
  69. package/dist/{esm/rate-limiter.d.ts → rate-limiter.d.ts} +113 -108
  70. package/dist/rate-limiter.js +249 -0
  71. package/dist/rate-limiter.js.map +1 -0
  72. package/dist/throttler.cjs +209 -0
  73. package/dist/throttler.cjs.map +1 -0
  74. package/dist/throttler.d.cts +207 -0
  75. package/dist/throttler.d.ts +207 -0
  76. package/dist/throttler.js +207 -0
  77. package/dist/throttler.js.map +1 -0
  78. package/dist/types.cjs +0 -0
  79. package/dist/types.d.cts +13 -0
  80. package/dist/types.d.ts +13 -0
  81. package/dist/types.js +1 -0
  82. package/dist/utils.cjs +13 -0
  83. package/dist/utils.cjs.map +1 -0
  84. package/dist/utils.d.cts +8 -0
  85. package/dist/utils.d.ts +8 -0
  86. package/dist/utils.js +11 -0
  87. package/dist/utils.js.map +1 -0
  88. package/package.json +38 -122
  89. package/src/async-batcher.ts +7 -5
  90. package/src/async-debouncer.ts +7 -5
  91. package/src/async-queuer.ts +7 -5
  92. package/src/async-rate-limiter.ts +7 -5
  93. package/src/async-retryer.ts +7 -5
  94. package/src/async-throttler.ts +7 -5
  95. package/src/batcher.ts +7 -5
  96. package/src/debouncer.ts +7 -5
  97. package/src/queuer.ts +7 -5
  98. package/src/rate-limiter.ts +7 -5
  99. package/src/throttler.ts +7 -5
  100. package/dist/cjs/async-batcher.cjs +0 -220
  101. package/dist/cjs/async-batcher.cjs.map +0 -1
  102. package/dist/cjs/async-batcher.d.cts +0 -340
  103. package/dist/cjs/async-debouncer.cjs +0 -231
  104. package/dist/cjs/async-debouncer.cjs.map +0 -1
  105. package/dist/cjs/async-debouncer.d.cts +0 -295
  106. package/dist/cjs/async-queuer.cjs +0 -397
  107. package/dist/cjs/async-queuer.cjs.map +0 -1
  108. package/dist/cjs/async-queuer.d.cts +0 -435
  109. package/dist/cjs/async-rate-limiter.cjs +0 -252
  110. package/dist/cjs/async-rate-limiter.cjs.map +0 -1
  111. package/dist/cjs/async-retryer.cjs +0 -285
  112. package/dist/cjs/async-retryer.cjs.map +0 -1
  113. package/dist/cjs/async-retryer.d.cts +0 -308
  114. package/dist/cjs/async-throttler.cjs +0 -261
  115. package/dist/cjs/async-throttler.cjs.map +0 -1
  116. package/dist/cjs/async-throttler.d.cts +0 -315
  117. package/dist/cjs/batcher.cjs +0 -130
  118. package/dist/cjs/batcher.cjs.map +0 -1
  119. package/dist/cjs/batcher.d.cts +0 -176
  120. package/dist/cjs/debouncer.cjs +0 -137
  121. package/dist/cjs/debouncer.cjs.map +0 -1
  122. package/dist/cjs/debouncer.d.cts +0 -162
  123. package/dist/cjs/event-client.cjs +0 -20
  124. package/dist/cjs/event-client.cjs.map +0 -1
  125. package/dist/cjs/event-client.d.cts +0 -45
  126. package/dist/cjs/index.cjs +0 -51
  127. package/dist/cjs/index.cjs.map +0 -1
  128. package/dist/cjs/index.d.cts +0 -15
  129. package/dist/cjs/queuer.cjs +0 -306
  130. package/dist/cjs/queuer.cjs.map +0 -1
  131. package/dist/cjs/queuer.d.cts +0 -340
  132. package/dist/cjs/rate-limiter.cjs +0 -179
  133. package/dist/cjs/rate-limiter.cjs.map +0 -1
  134. package/dist/cjs/throttler.cjs +0 -151
  135. package/dist/cjs/throttler.cjs.map +0 -1
  136. package/dist/cjs/throttler.d.cts +0 -202
  137. package/dist/cjs/types.d.cts +0 -9
  138. package/dist/cjs/utils.cjs +0 -11
  139. package/dist/cjs/utils.cjs.map +0 -1
  140. package/dist/cjs/utils.d.cts +0 -3
  141. package/dist/esm/async-batcher.d.ts +0 -340
  142. package/dist/esm/async-batcher.js +0 -220
  143. package/dist/esm/async-batcher.js.map +0 -1
  144. package/dist/esm/async-debouncer.d.ts +0 -295
  145. package/dist/esm/async-debouncer.js +0 -231
  146. package/dist/esm/async-debouncer.js.map +0 -1
  147. package/dist/esm/async-queuer.d.ts +0 -435
  148. package/dist/esm/async-queuer.js +0 -397
  149. package/dist/esm/async-queuer.js.map +0 -1
  150. package/dist/esm/async-rate-limiter.js +0 -252
  151. package/dist/esm/async-rate-limiter.js.map +0 -1
  152. package/dist/esm/async-retryer.d.ts +0 -308
  153. package/dist/esm/async-retryer.js +0 -285
  154. package/dist/esm/async-retryer.js.map +0 -1
  155. package/dist/esm/async-throttler.d.ts +0 -315
  156. package/dist/esm/async-throttler.js +0 -261
  157. package/dist/esm/async-throttler.js.map +0 -1
  158. package/dist/esm/batcher.d.ts +0 -176
  159. package/dist/esm/batcher.js +0 -130
  160. package/dist/esm/batcher.js.map +0 -1
  161. package/dist/esm/debouncer.d.ts +0 -162
  162. package/dist/esm/debouncer.js +0 -137
  163. package/dist/esm/debouncer.js.map +0 -1
  164. package/dist/esm/event-client.d.ts +0 -45
  165. package/dist/esm/event-client.js +0 -20
  166. package/dist/esm/event-client.js.map +0 -1
  167. package/dist/esm/index.d.ts +0 -15
  168. package/dist/esm/index.js.map +0 -1
  169. package/dist/esm/queuer.d.ts +0 -340
  170. package/dist/esm/queuer.js +0 -306
  171. package/dist/esm/queuer.js.map +0 -1
  172. package/dist/esm/rate-limiter.js +0 -179
  173. package/dist/esm/rate-limiter.js.map +0 -1
  174. package/dist/esm/throttler.d.ts +0 -202
  175. package/dist/esm/throttler.js +0 -151
  176. package/dist/esm/throttler.js.map +0 -1
  177. package/dist/esm/types.d.ts +0 -9
  178. package/dist/esm/utils.d.ts +0 -3
  179. package/dist/esm/utils.js +0 -11
  180. package/dist/esm/utils.js.map +0 -1
@@ -0,0 +1,180 @@
1
+ import { OptionalKeys } from "./types.cjs";
2
+ import { Store } from "@tanstack/store";
3
+
4
+ //#region src/batcher.d.ts
5
+ interface BatcherState<TValue> {
6
+ /**
7
+ * Number of batch executions that have been completed
8
+ */
9
+ executionCount: number;
10
+ /**
11
+ * Whether the batcher has no items to process (items array is empty)
12
+ */
13
+ isEmpty: boolean;
14
+ /**
15
+ * Whether the batcher is waiting for the timeout to trigger batch processing
16
+ */
17
+ isPending: boolean;
18
+ /**
19
+ * Array of items currently queued for batch processing
20
+ */
21
+ items: Array<TValue>;
22
+ /**
23
+ * Number of items currently in the batch queue
24
+ */
25
+ size: number;
26
+ /**
27
+ * Current processing status - 'idle' when not processing, 'pending' when waiting for timeout
28
+ */
29
+ status: 'idle' | 'pending';
30
+ /**
31
+ * Total number of items that have been processed across all batches
32
+ */
33
+ totalItemsProcessed: number;
34
+ }
35
+ /**
36
+ * Options for configuring a Batcher instance
37
+ */
38
+ interface BatcherOptions<TValue> {
39
+ /**
40
+ * Custom function to determine if a batch should be processed
41
+ * Return true to process the batch immediately
42
+ */
43
+ getShouldExecute?: (items: Array<TValue>, batcher: Batcher<TValue>) => boolean;
44
+ /**
45
+ * Initial state for the batcher
46
+ */
47
+ initialState?: Partial<BatcherState<TValue>>;
48
+ /**
49
+ * Optional key to identify this batcher instance.
50
+ * If provided, the batcher will be identified by this key in the devtools and PacerProvider if applicable.
51
+ */
52
+ key?: string;
53
+ /**
54
+ * Maximum number of items in a batch
55
+ * @default Infinity
56
+ */
57
+ maxSize?: number;
58
+ /**
59
+ * Callback fired after a batch is processed
60
+ */
61
+ onExecute?: (batch: Array<TValue>, batcher: Batcher<TValue>) => void;
62
+ /**
63
+ * Callback fired after items are added to the batcher
64
+ */
65
+ onItemsChange?: (batcher: Batcher<TValue>) => void;
66
+ /**
67
+ * Whether the batcher should start processing immediately
68
+ * @default true
69
+ */
70
+ started?: boolean;
71
+ /**
72
+ * Maximum time in milliseconds to wait before processing a batch.
73
+ * If the wait duration has elapsed, the batch will be processed.
74
+ * If not provided, the batch will not be triggered by a timeout.
75
+ * @default Infinity
76
+ */
77
+ wait?: number | ((batcher: Batcher<TValue>) => number);
78
+ }
79
+ type BatcherOptionsWithOptionalCallbacks<TValue> = OptionalKeys<Required<BatcherOptions<TValue>>, 'initialState' | 'onExecute' | 'onItemsChange' | 'key'>;
80
+ /**
81
+ * A class that collects items and processes them in batches.
82
+ *
83
+ * Batching is a technique for grouping multiple operations together to be processed as a single unit.
84
+ * This synchronous version is lighter weight and often all you need - upgrade to AsyncBatcher when you need promises, retry support, abort/cancel capabilities, or advanced error handling.
85
+ *
86
+ * The Batcher provides a flexible way to implement batching with configurable:
87
+ * - Maximum batch size (number of items per batch)
88
+ * - Time-based batching (process after X milliseconds)
89
+ * - Custom batch processing logic via getShouldExecute
90
+ * - Event callbacks for monitoring batch operations
91
+ *
92
+ * State Management:
93
+ * - Uses TanStack Store for reactive state management
94
+ * - Use `initialState` to provide initial state values when creating the batcher
95
+ * - Use `onExecute` callback to react to batch execution and implement custom logic
96
+ * - Use `onItemsChange` callback to react to items being added or removed from the batcher
97
+ * - The state includes batch execution count, total items processed, items, and running status
98
+ * - State can be accessed via `batcher.store.state` when using the class directly
99
+ * - When using framework adapters (React/Solid), state is accessed from `batcher.state`
100
+ *
101
+ * @example
102
+ * ```ts
103
+ * const batcher = new Batcher<number>(
104
+ * (items) => console.log('Processing batch:', items),
105
+ * {
106
+ * maxSize: 5,
107
+ * wait: 2000,
108
+ * onExecute: (batch, batcher) => console.log('Batch executed:', batch)
109
+ * }
110
+ * );
111
+ *
112
+ * batcher.addItem(1);
113
+ * batcher.addItem(2);
114
+ * // After 2 seconds or when 5 items are added, whichever comes first,
115
+ * // the batch will be processed
116
+ * // batcher.flush() // manually trigger a batch
117
+ * ```
118
+ */
119
+ declare class Batcher<TValue> {
120
+ #private;
121
+ fn: (items: Array<TValue>) => void;
122
+ readonly store: Store<Readonly<BatcherState<TValue>>>;
123
+ key: string | undefined;
124
+ options: BatcherOptionsWithOptionalCallbacks<TValue>;
125
+ constructor(fn: (items: Array<TValue>) => void, initialOptions: BatcherOptions<TValue>);
126
+ /**
127
+ * Updates the batcher options
128
+ */
129
+ setOptions: (newOptions: Partial<BatcherOptions<TValue>>) => void;
130
+ /**
131
+ * Adds an item to the batcher
132
+ * If the batch size is reached, timeout occurs, or shouldProcess returns true, the batch will be processed
133
+ */
134
+ addItem: (item: TValue) => void;
135
+ /**
136
+ * Processes the current batch of items immediately
137
+ */
138
+ flush: () => void;
139
+ /**
140
+ * Returns a copy of all items in the batcher
141
+ */
142
+ peekAllItems: () => Array<TValue>;
143
+ /**
144
+ * Removes all items from the batcher
145
+ */
146
+ clear: () => void;
147
+ /**
148
+ * Cancels any pending execution that was scheduled.
149
+ * Does NOT clear out the items.
150
+ */
151
+ cancel: () => void;
152
+ /**
153
+ * Resets the batcher state to its default values
154
+ */
155
+ reset: () => void;
156
+ }
157
+ /**
158
+ * Creates a batcher that processes items in batches.
159
+ *
160
+ * This synchronous version is lighter weight and often all you need - upgrade to asyncBatch when you need promises, retry support, abort/cancel capabilities, or advanced error handling.
161
+ *
162
+ * @example
163
+ * ```ts
164
+ * const batchItems = batch<number>(
165
+ * (items) => console.log('Processing:', items),
166
+ * {
167
+ * maxSize: 3,
168
+ * onExecute: (batch, batcher) => console.log('Batch executed:', batch)
169
+ * }
170
+ * );
171
+ *
172
+ * batchItems(1);
173
+ * batchItems(2);
174
+ * batchItems(3); // Triggers batch processing
175
+ * ```
176
+ */
177
+ declare function batch<TValue>(fn: (items: Array<TValue>) => void, options: BatcherOptions<TValue>): (item: TValue) => void;
178
+ //#endregion
179
+ export { Batcher, BatcherOptions, BatcherState, batch };
180
+ //# sourceMappingURL=batcher.d.cts.map
@@ -0,0 +1,180 @@
1
+ import { OptionalKeys } from "./types.js";
2
+ import { Store } from "@tanstack/store";
3
+
4
+ //#region src/batcher.d.ts
5
+ interface BatcherState<TValue> {
6
+ /**
7
+ * Number of batch executions that have been completed
8
+ */
9
+ executionCount: number;
10
+ /**
11
+ * Whether the batcher has no items to process (items array is empty)
12
+ */
13
+ isEmpty: boolean;
14
+ /**
15
+ * Whether the batcher is waiting for the timeout to trigger batch processing
16
+ */
17
+ isPending: boolean;
18
+ /**
19
+ * Array of items currently queued for batch processing
20
+ */
21
+ items: Array<TValue>;
22
+ /**
23
+ * Number of items currently in the batch queue
24
+ */
25
+ size: number;
26
+ /**
27
+ * Current processing status - 'idle' when not processing, 'pending' when waiting for timeout
28
+ */
29
+ status: 'idle' | 'pending';
30
+ /**
31
+ * Total number of items that have been processed across all batches
32
+ */
33
+ totalItemsProcessed: number;
34
+ }
35
+ /**
36
+ * Options for configuring a Batcher instance
37
+ */
38
+ interface BatcherOptions<TValue> {
39
+ /**
40
+ * Custom function to determine if a batch should be processed
41
+ * Return true to process the batch immediately
42
+ */
43
+ getShouldExecute?: (items: Array<TValue>, batcher: Batcher<TValue>) => boolean;
44
+ /**
45
+ * Initial state for the batcher
46
+ */
47
+ initialState?: Partial<BatcherState<TValue>>;
48
+ /**
49
+ * Optional key to identify this batcher instance.
50
+ * If provided, the batcher will be identified by this key in the devtools and PacerProvider if applicable.
51
+ */
52
+ key?: string;
53
+ /**
54
+ * Maximum number of items in a batch
55
+ * @default Infinity
56
+ */
57
+ maxSize?: number;
58
+ /**
59
+ * Callback fired after a batch is processed
60
+ */
61
+ onExecute?: (batch: Array<TValue>, batcher: Batcher<TValue>) => void;
62
+ /**
63
+ * Callback fired after items are added to the batcher
64
+ */
65
+ onItemsChange?: (batcher: Batcher<TValue>) => void;
66
+ /**
67
+ * Whether the batcher should start processing immediately
68
+ * @default true
69
+ */
70
+ started?: boolean;
71
+ /**
72
+ * Maximum time in milliseconds to wait before processing a batch.
73
+ * If the wait duration has elapsed, the batch will be processed.
74
+ * If not provided, the batch will not be triggered by a timeout.
75
+ * @default Infinity
76
+ */
77
+ wait?: number | ((batcher: Batcher<TValue>) => number);
78
+ }
79
+ type BatcherOptionsWithOptionalCallbacks<TValue> = OptionalKeys<Required<BatcherOptions<TValue>>, 'initialState' | 'onExecute' | 'onItemsChange' | 'key'>;
80
+ /**
81
+ * A class that collects items and processes them in batches.
82
+ *
83
+ * Batching is a technique for grouping multiple operations together to be processed as a single unit.
84
+ * This synchronous version is lighter weight and often all you need - upgrade to AsyncBatcher when you need promises, retry support, abort/cancel capabilities, or advanced error handling.
85
+ *
86
+ * The Batcher provides a flexible way to implement batching with configurable:
87
+ * - Maximum batch size (number of items per batch)
88
+ * - Time-based batching (process after X milliseconds)
89
+ * - Custom batch processing logic via getShouldExecute
90
+ * - Event callbacks for monitoring batch operations
91
+ *
92
+ * State Management:
93
+ * - Uses TanStack Store for reactive state management
94
+ * - Use `initialState` to provide initial state values when creating the batcher
95
+ * - Use `onExecute` callback to react to batch execution and implement custom logic
96
+ * - Use `onItemsChange` callback to react to items being added or removed from the batcher
97
+ * - The state includes batch execution count, total items processed, items, and running status
98
+ * - State can be accessed via `batcher.store.state` when using the class directly
99
+ * - When using framework adapters (React/Solid), state is accessed from `batcher.state`
100
+ *
101
+ * @example
102
+ * ```ts
103
+ * const batcher = new Batcher<number>(
104
+ * (items) => console.log('Processing batch:', items),
105
+ * {
106
+ * maxSize: 5,
107
+ * wait: 2000,
108
+ * onExecute: (batch, batcher) => console.log('Batch executed:', batch)
109
+ * }
110
+ * );
111
+ *
112
+ * batcher.addItem(1);
113
+ * batcher.addItem(2);
114
+ * // After 2 seconds or when 5 items are added, whichever comes first,
115
+ * // the batch will be processed
116
+ * // batcher.flush() // manually trigger a batch
117
+ * ```
118
+ */
119
+ declare class Batcher<TValue> {
120
+ #private;
121
+ fn: (items: Array<TValue>) => void;
122
+ readonly store: Store<Readonly<BatcherState<TValue>>>;
123
+ key: string | undefined;
124
+ options: BatcherOptionsWithOptionalCallbacks<TValue>;
125
+ constructor(fn: (items: Array<TValue>) => void, initialOptions: BatcherOptions<TValue>);
126
+ /**
127
+ * Updates the batcher options
128
+ */
129
+ setOptions: (newOptions: Partial<BatcherOptions<TValue>>) => void;
130
+ /**
131
+ * Adds an item to the batcher
132
+ * If the batch size is reached, timeout occurs, or shouldProcess returns true, the batch will be processed
133
+ */
134
+ addItem: (item: TValue) => void;
135
+ /**
136
+ * Processes the current batch of items immediately
137
+ */
138
+ flush: () => void;
139
+ /**
140
+ * Returns a copy of all items in the batcher
141
+ */
142
+ peekAllItems: () => Array<TValue>;
143
+ /**
144
+ * Removes all items from the batcher
145
+ */
146
+ clear: () => void;
147
+ /**
148
+ * Cancels any pending execution that was scheduled.
149
+ * Does NOT clear out the items.
150
+ */
151
+ cancel: () => void;
152
+ /**
153
+ * Resets the batcher state to its default values
154
+ */
155
+ reset: () => void;
156
+ }
157
+ /**
158
+ * Creates a batcher that processes items in batches.
159
+ *
160
+ * This synchronous version is lighter weight and often all you need - upgrade to asyncBatch when you need promises, retry support, abort/cancel capabilities, or advanced error handling.
161
+ *
162
+ * @example
163
+ * ```ts
164
+ * const batchItems = batch<number>(
165
+ * (items) => console.log('Processing:', items),
166
+ * {
167
+ * maxSize: 3,
168
+ * onExecute: (batch, batcher) => console.log('Batch executed:', batch)
169
+ * }
170
+ * );
171
+ *
172
+ * batchItems(1);
173
+ * batchItems(2);
174
+ * batchItems(3); // Triggers batch processing
175
+ * ```
176
+ */
177
+ declare function batch<TValue>(fn: (items: Array<TValue>) => void, options: BatcherOptions<TValue>): (item: TValue) => void;
178
+ //#endregion
179
+ export { Batcher, BatcherOptions, BatcherState, batch };
180
+ //# sourceMappingURL=batcher.d.ts.map
@@ -0,0 +1,193 @@
1
+ import { parseFunctionOrValue } from "./utils.js";
2
+ import { emitChange, pacerEventClient } from "./event-client.js";
3
+ import { Store } from "@tanstack/store";
4
+
5
+ //#region src/batcher.ts
6
+ function getDefaultBatcherState() {
7
+ return {
8
+ executionCount: 0,
9
+ isEmpty: true,
10
+ isPending: false,
11
+ totalItemsProcessed: 0,
12
+ items: [],
13
+ size: 0,
14
+ status: "idle"
15
+ };
16
+ }
17
+ const defaultOptions = {
18
+ getShouldExecute: () => false,
19
+ maxSize: Infinity,
20
+ started: true,
21
+ wait: Infinity
22
+ };
23
+ /**
24
+ * A class that collects items and processes them in batches.
25
+ *
26
+ * Batching is a technique for grouping multiple operations together to be processed as a single unit.
27
+ * This synchronous version is lighter weight and often all you need - upgrade to AsyncBatcher when you need promises, retry support, abort/cancel capabilities, or advanced error handling.
28
+ *
29
+ * The Batcher provides a flexible way to implement batching with configurable:
30
+ * - Maximum batch size (number of items per batch)
31
+ * - Time-based batching (process after X milliseconds)
32
+ * - Custom batch processing logic via getShouldExecute
33
+ * - Event callbacks for monitoring batch operations
34
+ *
35
+ * State Management:
36
+ * - Uses TanStack Store for reactive state management
37
+ * - Use `initialState` to provide initial state values when creating the batcher
38
+ * - Use `onExecute` callback to react to batch execution and implement custom logic
39
+ * - Use `onItemsChange` callback to react to items being added or removed from the batcher
40
+ * - The state includes batch execution count, total items processed, items, and running status
41
+ * - State can be accessed via `batcher.store.state` when using the class directly
42
+ * - When using framework adapters (React/Solid), state is accessed from `batcher.state`
43
+ *
44
+ * @example
45
+ * ```ts
46
+ * const batcher = new Batcher<number>(
47
+ * (items) => console.log('Processing batch:', items),
48
+ * {
49
+ * maxSize: 5,
50
+ * wait: 2000,
51
+ * onExecute: (batch, batcher) => console.log('Batch executed:', batch)
52
+ * }
53
+ * );
54
+ *
55
+ * batcher.addItem(1);
56
+ * batcher.addItem(2);
57
+ * // After 2 seconds or when 5 items are added, whichever comes first,
58
+ * // the batch will be processed
59
+ * // batcher.flush() // manually trigger a batch
60
+ * ```
61
+ */
62
+ var Batcher = class {
63
+ #timeoutId = null;
64
+ constructor(fn, initialOptions) {
65
+ this.fn = fn;
66
+ this.store = new Store(getDefaultBatcherState());
67
+ this.setOptions = (newOptions) => {
68
+ this.options = {
69
+ ...this.options,
70
+ ...newOptions
71
+ };
72
+ };
73
+ this.addItem = (item) => {
74
+ this.#setState({
75
+ items: [...this.store.state.items, item],
76
+ isPending: this.options.wait !== Infinity
77
+ });
78
+ this.options.onItemsChange?.(this);
79
+ if (this.store.state.items.length >= this.options.maxSize || this.options.getShouldExecute(this.store.state.items, this)) this.#execute();
80
+ else if (this.options.wait !== Infinity) {
81
+ this.#clearTimeout();
82
+ this.#timeoutId = setTimeout(() => this.#execute(), this.#getWait());
83
+ }
84
+ };
85
+ this.flush = () => {
86
+ this.#clearTimeout();
87
+ this.#execute();
88
+ };
89
+ this.peekAllItems = () => {
90
+ return [...this.store.state.items];
91
+ };
92
+ this.clear = () => {
93
+ this.#setState({
94
+ items: [],
95
+ isPending: false
96
+ });
97
+ };
98
+ this.cancel = () => {
99
+ this.#clearTimeout();
100
+ this.#setState({ isPending: false });
101
+ };
102
+ this.reset = () => {
103
+ this.#setState(getDefaultBatcherState());
104
+ this.options.onItemsChange?.(this);
105
+ };
106
+ this.key = initialOptions.key;
107
+ this.options = {
108
+ ...defaultOptions,
109
+ ...initialOptions
110
+ };
111
+ this.#setState(this.options.initialState ?? {});
112
+ if (this.key) pacerEventClient.on("d-Batcher", (event) => {
113
+ if (event.payload.key !== this.key) return;
114
+ this.#setState(event.payload.store.state);
115
+ this.setOptions(event.payload.options);
116
+ });
117
+ }
118
+ #setState = (newState) => {
119
+ this.store.setState((state) => {
120
+ const combinedState = {
121
+ ...state,
122
+ ...newState
123
+ };
124
+ const { isPending, items } = combinedState;
125
+ const size = items.length;
126
+ const isEmpty = size === 0;
127
+ return {
128
+ ...combinedState,
129
+ isEmpty,
130
+ size,
131
+ status: isPending ? "pending" : "idle"
132
+ };
133
+ });
134
+ emitChange("Batcher", this);
135
+ };
136
+ #getWait = () => {
137
+ return parseFunctionOrValue(this.options.wait, this);
138
+ };
139
+ /**
140
+ * Processes the current batch of items.
141
+ * This method will automatically be triggered if the batcher is running and any of these conditions are met:
142
+ * - The number of items reaches batchSize
143
+ * - The wait duration has elapsed
144
+ * - The getShouldExecute function returns true upon adding an item
145
+ *
146
+ * You can also call this method manually to process the current batch at any time.
147
+ */
148
+ #execute = () => {
149
+ if (this.store.state.items.length === 0) return;
150
+ const batch$1 = this.peekAllItems();
151
+ this.clear();
152
+ this.options.onItemsChange?.(this);
153
+ this.fn(batch$1);
154
+ this.#setState({
155
+ executionCount: this.store.state.executionCount + 1,
156
+ totalItemsProcessed: this.store.state.totalItemsProcessed + batch$1.length
157
+ });
158
+ this.options.onExecute?.(batch$1, this);
159
+ };
160
+ #clearTimeout = () => {
161
+ if (this.#timeoutId) {
162
+ clearTimeout(this.#timeoutId);
163
+ this.#timeoutId = null;
164
+ }
165
+ };
166
+ };
167
+ /**
168
+ * Creates a batcher that processes items in batches.
169
+ *
170
+ * This synchronous version is lighter weight and often all you need - upgrade to asyncBatch when you need promises, retry support, abort/cancel capabilities, or advanced error handling.
171
+ *
172
+ * @example
173
+ * ```ts
174
+ * const batchItems = batch<number>(
175
+ * (items) => console.log('Processing:', items),
176
+ * {
177
+ * maxSize: 3,
178
+ * onExecute: (batch, batcher) => console.log('Batch executed:', batch)
179
+ * }
180
+ * );
181
+ *
182
+ * batchItems(1);
183
+ * batchItems(2);
184
+ * batchItems(3); // Triggers batch processing
185
+ * ```
186
+ */
187
+ function batch(fn, options) {
188
+ return new Batcher(fn, options).addItem;
189
+ }
190
+
191
+ //#endregion
192
+ export { Batcher, batch };
193
+ //# sourceMappingURL=batcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"batcher.js","names":["defaultOptions: BatcherOptionsWithOptionalCallbacks<any>","fn: (items: Array<TValue>) => void","#setState","#execute","#clearTimeout","#timeoutId","#getWait","batch"],"sources":["../src/batcher.ts"],"sourcesContent":["import { Store } from '@tanstack/store'\nimport { parseFunctionOrValue } from './utils'\nimport { emitChange, pacerEventClient } from './event-client'\nimport type { OptionalKeys } from './types'\n\nexport interface BatcherState<TValue> {\n /**\n * Number of batch executions that have been completed\n */\n executionCount: number\n /**\n * Whether the batcher has no items to process (items array is empty)\n */\n isEmpty: boolean\n /**\n * Whether the batcher is waiting for the timeout to trigger batch processing\n */\n isPending: boolean\n /**\n * Array of items currently queued for batch processing\n */\n items: Array<TValue>\n /**\n * Number of items currently in the batch queue\n */\n size: number\n /**\n * Current processing status - 'idle' when not processing, 'pending' when waiting for timeout\n */\n status: 'idle' | 'pending'\n /**\n * Total number of items that have been processed across all batches\n */\n totalItemsProcessed: number\n}\n\nfunction getDefaultBatcherState<TValue>(): BatcherState<TValue> {\n return {\n executionCount: 0,\n isEmpty: true,\n isPending: false,\n totalItemsProcessed: 0,\n items: [],\n size: 0,\n status: 'idle',\n }\n}\n\n/**\n * Options for configuring a Batcher instance\n */\nexport interface BatcherOptions<TValue> {\n /**\n * Custom function to determine if a batch should be processed\n * Return true to process the batch immediately\n */\n getShouldExecute?: (items: Array<TValue>, batcher: Batcher<TValue>) => boolean\n /**\n * Initial state for the batcher\n */\n initialState?: Partial<BatcherState<TValue>>\n /**\n * Optional key to identify this batcher instance.\n * If provided, the batcher will be identified by this key in the devtools and PacerProvider if applicable.\n */\n key?: string\n /**\n * Maximum number of items in a batch\n * @default Infinity\n */\n maxSize?: number\n /**\n * Callback fired after a batch is processed\n */\n onExecute?: (batch: Array<TValue>, batcher: Batcher<TValue>) => void\n /**\n * Callback fired after items are added to the batcher\n */\n onItemsChange?: (batcher: Batcher<TValue>) => void\n /**\n * Whether the batcher should start processing immediately\n * @default true\n */\n started?: boolean\n /**\n * Maximum time in milliseconds to wait before processing a batch.\n * If the wait duration has elapsed, the batch will be processed.\n * If not provided, the batch will not be triggered by a timeout.\n * @default Infinity\n */\n wait?: number | ((batcher: Batcher<TValue>) => number)\n}\n\ntype BatcherOptionsWithOptionalCallbacks<TValue> = OptionalKeys<\n Required<BatcherOptions<TValue>>,\n 'initialState' | 'onExecute' | 'onItemsChange' | 'key'\n>\n\nconst defaultOptions: BatcherOptionsWithOptionalCallbacks<any> = {\n getShouldExecute: () => false,\n maxSize: Infinity,\n started: true,\n wait: Infinity,\n}\n\n/**\n * A class that collects items and processes them in batches.\n *\n * Batching is a technique for grouping multiple operations together to be processed as a single unit.\n * This synchronous version is lighter weight and often all you need - upgrade to AsyncBatcher when you need promises, retry support, abort/cancel capabilities, or advanced error handling.\n *\n * The Batcher provides a flexible way to implement batching with configurable:\n * - Maximum batch size (number of items per batch)\n * - Time-based batching (process after X milliseconds)\n * - Custom batch processing logic via getShouldExecute\n * - Event callbacks for monitoring batch operations\n *\n * State Management:\n * - Uses TanStack Store for reactive state management\n * - Use `initialState` to provide initial state values when creating the batcher\n * - Use `onExecute` callback to react to batch execution and implement custom logic\n * - Use `onItemsChange` callback to react to items being added or removed from the batcher\n * - The state includes batch execution count, total items processed, items, and running status\n * - State can be accessed via `batcher.store.state` when using the class directly\n * - When using framework adapters (React/Solid), state is accessed from `batcher.state`\n *\n * @example\n * ```ts\n * const batcher = new Batcher<number>(\n * (items) => console.log('Processing batch:', items),\n * {\n * maxSize: 5,\n * wait: 2000,\n * onExecute: (batch, batcher) => console.log('Batch executed:', batch)\n * }\n * );\n *\n * batcher.addItem(1);\n * batcher.addItem(2);\n * // After 2 seconds or when 5 items are added, whichever comes first,\n * // the batch will be processed\n * // batcher.flush() // manually trigger a batch\n * ```\n */\nexport class Batcher<TValue> {\n readonly store: Store<Readonly<BatcherState<TValue>>> = new Store(\n getDefaultBatcherState<TValue>(),\n )\n key: string | undefined\n options: BatcherOptionsWithOptionalCallbacks<TValue>\n #timeoutId: NodeJS.Timeout | null = null\n\n constructor(\n public fn: (items: Array<TValue>) => void,\n initialOptions: BatcherOptions<TValue>,\n ) {\n this.key = initialOptions.key\n this.options = {\n ...defaultOptions,\n ...initialOptions,\n }\n this.#setState(this.options.initialState ?? {})\n\n if (this.key) {\n pacerEventClient.on('d-Batcher', (event) => {\n if (event.payload.key !== this.key) return\n this.#setState(event.payload.store.state)\n this.setOptions(event.payload.options)\n })\n }\n }\n\n /**\n * Updates the batcher options\n */\n setOptions = (newOptions: Partial<BatcherOptions<TValue>>): void => {\n this.options = { ...this.options, ...newOptions }\n }\n\n #setState = (newState: Partial<BatcherState<TValue>>): void => {\n this.store.setState((state) => {\n const combinedState = {\n ...state,\n ...newState,\n }\n const { isPending, items } = combinedState\n const size = items.length\n const isEmpty = size === 0\n return {\n ...combinedState,\n isEmpty,\n size,\n status: isPending ? 'pending' : 'idle',\n }\n })\n emitChange('Batcher', this)\n }\n\n #getWait = (): number => {\n return parseFunctionOrValue(this.options.wait, this)\n }\n\n /**\n * Adds an item to the batcher\n * If the batch size is reached, timeout occurs, or shouldProcess returns true, the batch will be processed\n */\n addItem = (item: TValue): void => {\n this.#setState({\n items: [...this.store.state.items, item],\n isPending: this.options.wait !== Infinity,\n })\n this.options.onItemsChange?.(this)\n\n const shouldProcess =\n this.store.state.items.length >= this.options.maxSize ||\n this.options.getShouldExecute(this.store.state.items, this)\n\n if (shouldProcess) {\n this.#execute()\n } else if (this.options.wait !== Infinity) {\n this.#clearTimeout() // clear any pending timeout to replace it with a new one\n this.#timeoutId = setTimeout(() => this.#execute(), this.#getWait())\n }\n }\n\n /**\n * Processes the current batch of items.\n * This method will automatically be triggered if the batcher is running and any of these conditions are met:\n * - The number of items reaches batchSize\n * - The wait duration has elapsed\n * - The getShouldExecute function returns true upon adding an item\n *\n * You can also call this method manually to process the current batch at any time.\n */\n #execute = (): void => {\n if (this.store.state.items.length === 0) {\n return\n }\n\n const batch = this.peekAllItems() // copy of the items to be processed (to prevent race conditions)\n this.clear() // Clear items before processing to prevent race conditions\n this.options.onItemsChange?.(this) // Call onItemsChange to notify listeners that the items have changed\n\n this.fn(batch) // EXECUTE\n this.#setState({\n executionCount: this.store.state.executionCount + 1,\n totalItemsProcessed: this.store.state.totalItemsProcessed + batch.length,\n })\n this.options.onExecute?.(batch, this)\n }\n\n /**\n * Processes the current batch of items immediately\n */\n flush = (): void => {\n this.#clearTimeout() // clear any pending timeout\n this.#execute() // execute immediately\n }\n\n /**\n * Returns a copy of all items in the batcher\n */\n peekAllItems = (): Array<TValue> => {\n return [...this.store.state.items]\n }\n\n #clearTimeout = (): void => {\n if (this.#timeoutId) {\n clearTimeout(this.#timeoutId)\n this.#timeoutId = null\n }\n }\n\n /**\n * Removes all items from the batcher\n */\n clear = (): void => {\n this.#setState({ items: [], isPending: false })\n }\n\n /**\n * Cancels any pending execution that was scheduled.\n * Does NOT clear out the items.\n */\n cancel = (): void => {\n this.#clearTimeout()\n this.#setState({ isPending: false })\n }\n\n /**\n * Resets the batcher state to its default values\n */\n reset = (): void => {\n this.#setState(getDefaultBatcherState<TValue>())\n this.options.onItemsChange?.(this)\n }\n}\n\n/**\n * Creates a batcher that processes items in batches.\n *\n * This synchronous version is lighter weight and often all you need - upgrade to asyncBatch when you need promises, retry support, abort/cancel capabilities, or advanced error handling.\n *\n * @example\n * ```ts\n * const batchItems = batch<number>(\n * (items) => console.log('Processing:', items),\n * {\n * maxSize: 3,\n * onExecute: (batch, batcher) => console.log('Batch executed:', batch)\n * }\n * );\n *\n * batchItems(1);\n * batchItems(2);\n * batchItems(3); // Triggers batch processing\n * ```\n */\nexport function batch<TValue>(\n fn: (items: Array<TValue>) => void,\n options: BatcherOptions<TValue>,\n) {\n const batcher = new Batcher<TValue>(fn, options)\n return batcher.addItem\n}\n"],"mappings":"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"}