@tanstack/pacer 0.1.0 → 0.2.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 (74) hide show
  1. package/dist/cjs/async-debouncer.cjs +60 -44
  2. package/dist/cjs/async-debouncer.cjs.map +1 -1
  3. package/dist/cjs/async-debouncer.d.cts +37 -24
  4. package/dist/cjs/async-queuer.cjs +149 -125
  5. package/dist/cjs/async-queuer.cjs.map +1 -1
  6. package/dist/cjs/async-queuer.d.cts +65 -48
  7. package/dist/cjs/async-rate-limiter.cjs +63 -46
  8. package/dist/cjs/async-rate-limiter.cjs.map +1 -1
  9. package/dist/cjs/async-rate-limiter.d.cts +39 -27
  10. package/dist/cjs/async-throttler.cjs +70 -47
  11. package/dist/cjs/async-throttler.cjs.map +1 -1
  12. package/dist/cjs/async-throttler.d.cts +43 -25
  13. package/dist/cjs/debouncer.cjs +46 -22
  14. package/dist/cjs/debouncer.cjs.map +1 -1
  15. package/dist/cjs/debouncer.d.cts +25 -11
  16. package/dist/cjs/index.cjs +2 -0
  17. package/dist/cjs/index.cjs.map +1 -1
  18. package/dist/cjs/index.d.cts +2 -0
  19. package/dist/cjs/queuer.cjs +114 -104
  20. package/dist/cjs/queuer.cjs.map +1 -1
  21. package/dist/cjs/queuer.d.cts +53 -40
  22. package/dist/cjs/rate-limiter.cjs +54 -42
  23. package/dist/cjs/rate-limiter.cjs.map +1 -1
  24. package/dist/cjs/rate-limiter.d.cts +37 -45
  25. package/dist/cjs/throttler.cjs +61 -41
  26. package/dist/cjs/throttler.cjs.map +1 -1
  27. package/dist/cjs/throttler.d.cts +35 -22
  28. package/dist/cjs/types.d.cts +12 -0
  29. package/dist/cjs/utils.cjs +13 -0
  30. package/dist/cjs/utils.cjs.map +1 -0
  31. package/dist/cjs/utils.d.cts +1 -0
  32. package/dist/esm/async-debouncer.d.ts +37 -24
  33. package/dist/esm/async-debouncer.js +60 -44
  34. package/dist/esm/async-debouncer.js.map +1 -1
  35. package/dist/esm/async-queuer.d.ts +65 -48
  36. package/dist/esm/async-queuer.js +149 -125
  37. package/dist/esm/async-queuer.js.map +1 -1
  38. package/dist/esm/async-rate-limiter.d.ts +39 -27
  39. package/dist/esm/async-rate-limiter.js +63 -46
  40. package/dist/esm/async-rate-limiter.js.map +1 -1
  41. package/dist/esm/async-throttler.d.ts +43 -25
  42. package/dist/esm/async-throttler.js +70 -47
  43. package/dist/esm/async-throttler.js.map +1 -1
  44. package/dist/esm/debouncer.d.ts +25 -11
  45. package/dist/esm/debouncer.js +46 -22
  46. package/dist/esm/debouncer.js.map +1 -1
  47. package/dist/esm/index.d.ts +2 -0
  48. package/dist/esm/index.js +2 -0
  49. package/dist/esm/index.js.map +1 -1
  50. package/dist/esm/queuer.d.ts +53 -40
  51. package/dist/esm/queuer.js +114 -104
  52. package/dist/esm/queuer.js.map +1 -1
  53. package/dist/esm/rate-limiter.d.ts +37 -45
  54. package/dist/esm/rate-limiter.js +54 -42
  55. package/dist/esm/rate-limiter.js.map +1 -1
  56. package/dist/esm/throttler.d.ts +35 -22
  57. package/dist/esm/throttler.js +61 -41
  58. package/dist/esm/throttler.js.map +1 -1
  59. package/dist/esm/types.d.ts +12 -0
  60. package/dist/esm/utils.d.ts +1 -0
  61. package/dist/esm/utils.js +13 -0
  62. package/dist/esm/utils.js.map +1 -0
  63. package/package.json +8 -1
  64. package/src/async-debouncer.ts +90 -62
  65. package/src/async-queuer.ts +178 -145
  66. package/src/async-rate-limiter.ts +93 -67
  67. package/src/async-throttler.ts +98 -63
  68. package/src/debouncer.ts +71 -35
  69. package/src/index.ts +2 -0
  70. package/src/queuer.ts +135 -118
  71. package/src/rate-limiter.ts +79 -81
  72. package/src/throttler.ts +87 -61
  73. package/src/types.ts +17 -0
  74. package/src/utils.ts +13 -0
@@ -4,31 +4,36 @@ const defaultOptions = {
4
4
  addItemsTo: "back",
5
5
  concurrency: 1,
6
6
  getItemsFrom: "front",
7
- getPriority: (item) => item.priority ?? 0,
7
+ getPriority: (item) => (item == null ? void 0 : item.priority) ?? 0,
8
8
  initialItems: [],
9
9
  maxSize: Infinity,
10
10
  onGetNextItem: () => {
11
11
  },
12
- onUpdate: () => {
12
+ onIsRunningChange: () => {
13
+ },
14
+ onItemsChange: () => {
15
+ },
16
+ onReject: () => {
13
17
  },
14
18
  started: false,
15
19
  wait: 0
16
20
  };
17
21
  class AsyncQueuer {
18
22
  constructor(initialOptions = defaultOptions) {
19
- this.items = [];
20
- this.activeItems = /* @__PURE__ */ new Set();
21
- this.onSuccessCallbacks = [];
22
- this.onErrorCallbacks = [];
23
- this.onSettledCallbacks = [];
24
- this.pendingTick = false;
25
- this.executionCount = 0;
26
- this.options = { ...defaultOptions, ...initialOptions };
27
- this.running = this.options.started;
28
- for (let i = 0; i < this.options.initialItems.length; i++) {
29
- const item = this.options.initialItems[i];
30
- const isLast = i === this.options.initialItems.length - 1;
31
- this.addItem(item, this.options.addItemsTo, isLast);
23
+ this._activeItems = /* @__PURE__ */ new Set();
24
+ this._executionCount = 0;
25
+ this._rejectionCount = 0;
26
+ this._items = [];
27
+ this._onErrorCallbacks = [];
28
+ this._onSettledCallbacks = [];
29
+ this._onSuccessCallbacks = [];
30
+ this._pendingTick = false;
31
+ this._options = { ...defaultOptions, ...initialOptions };
32
+ this._running = this._options.started;
33
+ for (let i = 0; i < this._options.initialItems.length; i++) {
34
+ const item = this._options.initialItems[i];
35
+ const isLast = i === this._options.initialItems.length - 1;
36
+ this.addItem(item, this._options.addItemsTo, isLast);
32
37
  }
33
38
  }
34
39
  /**
@@ -36,23 +41,30 @@ class AsyncQueuer {
36
41
  * Returns the new options state
37
42
  */
38
43
  setOptions(newOptions) {
39
- this.options = { ...this.options, ...newOptions };
40
- return this.options;
44
+ this._options = { ...this._options, ...newOptions };
45
+ return this._options;
46
+ }
47
+ /**
48
+ * Returns the current queuer options
49
+ */
50
+ getOptions() {
51
+ return this._options;
41
52
  }
42
53
  /**
43
54
  * Processes items in the queuer
44
55
  */
45
56
  tick() {
46
- if (!this.running) {
47
- this.pendingTick = false;
57
+ if (!this._running) {
58
+ this._pendingTick = false;
48
59
  return;
49
60
  }
50
- while (this.activeItems.size < this.options.concurrency && !this.isEmpty()) {
61
+ while (this._activeItems.size < this._options.concurrency && !this.getIsEmpty()) {
51
62
  const nextFn = this.getNextItem();
52
63
  if (!nextFn) {
53
64
  break;
54
65
  }
55
- this.activeItems.add(nextFn);
66
+ this._activeItems.add(nextFn);
67
+ this._options.onItemsChange(this);
56
68
  (async () => {
57
69
  let success = false;
58
70
  let res;
@@ -63,29 +75,78 @@ class AsyncQueuer {
63
75
  } catch (e) {
64
76
  error = e;
65
77
  } finally {
66
- this.options.onUpdate(this);
78
+ this._activeItems.delete(nextFn);
79
+ this._options.onItemsChange(this);
67
80
  }
68
- this.activeItems.delete(nextFn);
69
81
  if (success) {
70
- this.onSuccessCallbacks.forEach((cb) => cb(res));
82
+ this._onSuccessCallbacks.forEach((cb) => cb(res));
71
83
  } else {
72
- this.onErrorCallbacks.forEach((cb) => cb(error));
84
+ this._onErrorCallbacks.forEach((cb) => cb(error));
73
85
  }
74
- this.onSettledCallbacks.forEach((cb) => cb(success ? res : error));
75
- if (this.options.wait > 0) {
76
- setTimeout(() => this.tick(), this.options.wait);
86
+ this._onSettledCallbacks.forEach((cb) => cb(success ? res : error));
87
+ if (this._options.wait > 0) {
88
+ setTimeout(() => this.tick(), this._options.wait);
77
89
  return;
78
90
  }
79
91
  this.tick();
80
92
  })();
81
93
  }
82
- this.pendingTick = false;
94
+ this._pendingTick = false;
95
+ }
96
+ /**
97
+ * Starts the queuer and processes items
98
+ */
99
+ start() {
100
+ this._running = true;
101
+ if (!this._pendingTick && !this.getIsEmpty()) {
102
+ this._pendingTick = true;
103
+ this.tick();
104
+ }
105
+ this._options.onIsRunningChange(this);
106
+ return new Promise((resolve) => {
107
+ const checkIdle = () => {
108
+ if (this.getIsIdle()) {
109
+ resolve();
110
+ } else {
111
+ setTimeout(checkIdle, 100);
112
+ }
113
+ };
114
+ checkIdle();
115
+ });
116
+ }
117
+ /**
118
+ * Stops the queuer from processing items
119
+ */
120
+ stop() {
121
+ this._running = false;
122
+ this._pendingTick = false;
123
+ this._options.onIsRunningChange(this);
124
+ }
125
+ /**
126
+ * Removes all items from the queuer
127
+ */
128
+ clear() {
129
+ this._items = [];
130
+ this._options.onItemsChange(this);
131
+ }
132
+ /**
133
+ * Resets the queuer to its initial state
134
+ */
135
+ reset(withInitialItems) {
136
+ this.clear();
137
+ this._executionCount = 0;
138
+ if (withInitialItems) {
139
+ this._items = [...this._options.initialItems];
140
+ }
141
+ this._running = this._options.started;
83
142
  }
84
143
  /**
85
144
  * Adds a task to the queuer
86
145
  */
87
- addItem(fn, position = this.options.addItemsTo, runOnUpdate = true) {
88
- if (this.isFull()) {
146
+ addItem(fn, position = this._options.addItemsTo, runOnUpdate = true) {
147
+ if (this.getIsFull()) {
148
+ this._rejectionCount++;
149
+ this._options.onReject(fn, this);
89
150
  return Promise.reject(new Error("Queuer is full"));
90
151
  }
91
152
  return new Promise((resolve, reject) => {
@@ -102,29 +163,29 @@ class AsyncQueuer {
102
163
  },
103
164
  { priority: fn.priority ?? void 0 }
104
165
  );
105
- const priority = this.options.getPriority !== defaultOptions.getPriority ? this.options.getPriority(task) : task.priority;
166
+ const priority = this._options.getPriority !== defaultOptions.getPriority ? this._options.getPriority(task) : task.priority;
106
167
  if (priority !== void 0) {
107
- const insertIndex = this.items.findIndex((existing) => {
108
- const existingPriority = this.options.getPriority !== defaultOptions.getPriority ? this.options.getPriority(existing) : existing.priority;
168
+ const insertIndex = this._items.findIndex((existing) => {
169
+ const existingPriority = this._options.getPriority !== defaultOptions.getPriority ? this._options.getPriority(existing) : existing.priority;
109
170
  return existingPriority > priority;
110
171
  });
111
172
  if (insertIndex === -1) {
112
- this.items.push(task);
173
+ this._items.push(task);
113
174
  } else {
114
- this.items.splice(insertIndex, 0, task);
175
+ this._items.splice(insertIndex, 0, task);
115
176
  }
116
177
  } else {
117
178
  if (position === "front") {
118
- this.items.unshift(task);
179
+ this._items.unshift(task);
119
180
  } else {
120
- this.items.push(task);
181
+ this._items.push(task);
121
182
  }
122
183
  }
123
184
  if (runOnUpdate) {
124
- this.options.onUpdate(this);
185
+ this._options.onItemsChange(this);
125
186
  }
126
- if (this.running && !this.pendingTick) {
127
- this.pendingTick = true;
187
+ if (this._running && !this._pendingTick) {
188
+ this._pendingTick = true;
128
189
  this.tick();
129
190
  }
130
191
  });
@@ -132,157 +193,120 @@ class AsyncQueuer {
132
193
  /**
133
194
  * Removes and returns an item from the queuer
134
195
  */
135
- getNextItem(position = this.options.getItemsFrom) {
196
+ getNextItem(position = this._options.getItemsFrom) {
136
197
  let item;
137
198
  if (position === "front") {
138
- item = this.items.shift();
199
+ item = this._items.shift();
139
200
  } else {
140
- item = this.items.pop();
201
+ item = this._items.pop();
141
202
  }
142
203
  if (item !== void 0) {
143
- this.executionCount++;
144
- this.options.onUpdate(this);
145
- this.options.onGetNextItem(item, this);
204
+ this._executionCount++;
205
+ this._options.onItemsChange(this);
206
+ this._options.onGetNextItem(item, this);
146
207
  }
147
208
  return item;
148
209
  }
149
210
  /**
150
211
  * Returns an item without removing it
151
212
  */
152
- peek(position = "front") {
213
+ getPeek(position = "front") {
153
214
  if (position === "front") {
154
- return this.items[0];
215
+ return this._items[0];
155
216
  }
156
- return this.items[this.items.length - 1];
217
+ return this._items[this._items.length - 1];
157
218
  }
158
219
  /**
159
220
  * Returns true if the queuer is empty
160
221
  */
161
- isEmpty() {
162
- return this.items.length === 0;
222
+ getIsEmpty() {
223
+ return this._items.length === 0;
163
224
  }
164
225
  /**
165
226
  * Returns true if the queuer is full
166
227
  */
167
- isFull() {
168
- return this.items.length >= this.options.maxSize;
228
+ getIsFull() {
229
+ return this._items.length >= this._options.maxSize;
169
230
  }
170
231
  /**
171
232
  * Returns the current size of the queuer
172
233
  */
173
- size() {
174
- return this.items.length;
234
+ getSize() {
235
+ return this._items.length;
175
236
  }
176
237
  /**
177
- * Removes all items from the queuer
238
+ * Returns a copy of all items in the queuer
178
239
  */
179
- clear() {
180
- this.items = [];
181
- this.options.onUpdate(this);
240
+ getAllItems() {
241
+ return [...this.getActiveItems(), ...this.getPendingItems()];
182
242
  }
183
243
  /**
184
- * Resets the queuer to its initial state
244
+ * Returns the active items
185
245
  */
186
- reset(withInitialItems) {
187
- this.clear();
188
- this.executionCount = 0;
189
- if (withInitialItems) {
190
- this.items = [...this.options.initialItems];
191
- }
192
- this.running = this.options.started;
246
+ getActiveItems() {
247
+ return Array.from(this._activeItems);
193
248
  }
194
249
  /**
195
- * Returns a copy of all items in the queuer
250
+ * Returns the pending items
196
251
  */
197
- getAllItems() {
198
- return [...this.items];
252
+ getPendingItems() {
253
+ return [...this._items];
199
254
  }
200
255
  /**
201
256
  * Returns the number of items that have been removed from the queuer
202
257
  */
203
258
  getExecutionCount() {
204
- return this.executionCount;
259
+ return this._executionCount;
205
260
  }
206
261
  /**
207
- * Returns the active items
262
+ * Returns the number of items that have been rejected from the queuer
208
263
  */
209
- getActiveItems() {
210
- return Array.from(this.activeItems);
264
+ getRejectionCount() {
265
+ return this._rejectionCount;
211
266
  }
212
267
  /**
213
- * Returns the pending items
268
+ * Returns true if the queuer is running
214
269
  */
215
- getPendingItems() {
216
- return this.getAllItems();
270
+ getIsRunning() {
271
+ return this._running;
272
+ }
273
+ /**
274
+ * Returns true if the queuer is running but has no items to process
275
+ */
276
+ getIsIdle() {
277
+ return this._running && this.getIsEmpty() && this._activeItems.size === 0;
217
278
  }
218
279
  /**
219
280
  * Adds a callback to be called when a task succeeds
220
281
  */
221
282
  onSuccess(cb) {
222
- this.onSuccessCallbacks.push(cb);
283
+ this._onSuccessCallbacks.push(cb);
223
284
  return () => {
224
- this.onSuccessCallbacks = this.onSuccessCallbacks.filter((d) => d !== cb);
285
+ this._onSuccessCallbacks = this._onSuccessCallbacks.filter(
286
+ (d) => d !== cb
287
+ );
225
288
  };
226
289
  }
227
290
  /**
228
291
  * Adds a callback to be called when a task errors
229
292
  */
230
293
  onError(cb) {
231
- this.onErrorCallbacks.push(cb);
294
+ this._onErrorCallbacks.push(cb);
232
295
  return () => {
233
- this.onErrorCallbacks = this.onErrorCallbacks.filter((d) => d !== cb);
296
+ this._onErrorCallbacks = this._onErrorCallbacks.filter((d) => d !== cb);
234
297
  };
235
298
  }
236
299
  /**
237
300
  * Adds a callback to be called when a task is settled
238
301
  */
239
302
  onSettled(cb) {
240
- this.onSettledCallbacks.push(cb);
303
+ this._onSettledCallbacks.push(cb);
241
304
  return () => {
242
- this.onSettledCallbacks = this.onSettledCallbacks.filter((d) => d !== cb);
305
+ this._onSettledCallbacks = this._onSettledCallbacks.filter(
306
+ (d) => d !== cb
307
+ );
243
308
  };
244
309
  }
245
- /**
246
- * Starts the queuer and processes items
247
- */
248
- start() {
249
- this.running = true;
250
- if (!this.pendingTick && !this.isEmpty()) {
251
- this.pendingTick = true;
252
- this.tick();
253
- }
254
- this.options.onUpdate(this);
255
- return new Promise((resolve) => {
256
- const checkIdle = () => {
257
- if (this.isIdle()) {
258
- resolve();
259
- } else {
260
- setTimeout(checkIdle, 100);
261
- }
262
- };
263
- checkIdle();
264
- });
265
- }
266
- /**
267
- * Stops the queuer from processing items
268
- */
269
- stop() {
270
- this.running = false;
271
- this.pendingTick = false;
272
- this.options.onUpdate(this);
273
- }
274
- /**
275
- * Returns true if the queuer is running
276
- */
277
- isRunning() {
278
- return this.running;
279
- }
280
- /**
281
- * Returns true if the queuer is running but has no items to process
282
- */
283
- isIdle() {
284
- return this.running && this.isEmpty() && this.activeItems.size === 0;
285
- }
286
310
  }
287
311
  function asyncQueue(options = {}) {
288
312
  const queuer = new AsyncQueuer({ ...options, started: true });
@@ -1 +1 @@
1
- {"version":3,"file":"async-queuer.cjs","sources":["../../src/async-queuer.ts"],"sourcesContent":["import type { QueuePosition } from './queuer'\n\nexport interface AsyncQueuerOptions<TValue> {\n /**\n * Default position to add items to the queuer\n * @default 'back'\n */\n addItemsTo?: QueuePosition\n /**\n * Maximum number of concurrent tasks to process\n */\n concurrency?: number\n /**\n * Default position to get items from during processing\n * @default 'front'\n */\n getItemsFrom?: QueuePosition\n /**\n * Function to determine priority of items in the queuer\n * Higher priority items will be processed first\n * If not provided, will use static priority values attached to tasks\n */\n getPriority?: (item: () => Promise<TValue>) => number\n /**\n * Initial items to populate the queuer with\n */\n initialItems?: Array<(() => Promise<TValue>) & { priority?: number }>\n /**\n * Maximum number of items allowed in the queuer\n */\n maxSize?: number\n /**\n * Callback fired whenever an item is removed from the queuer\n */\n onGetNextItem?: (\n item: () => Promise<TValue>,\n queuer: AsyncQueuer<TValue>,\n ) => void\n /**\n * Callback fired whenever an item is added or removed from the queuer\n */\n onUpdate?: (queuer: AsyncQueuer<TValue>) => void\n /**\n * Whether the queuer should start processing tasks immediately\n */\n started?: boolean\n /**\n * Time in milliseconds to wait between processing items\n */\n wait?: number\n}\n\nconst defaultOptions: Required<AsyncQueuerOptions<any>> = {\n addItemsTo: 'back',\n concurrency: 1,\n getItemsFrom: 'front',\n getPriority: (item) => (item as any).priority ?? 0,\n initialItems: [],\n maxSize: Infinity,\n onGetNextItem: () => {},\n onUpdate: () => {},\n started: false,\n wait: 0,\n}\n\n/**\n * A flexible asynchronous queuer that processes tasks with configurable concurrency control.\n *\n * Features:\n * - Priority queuer support via getPriority option\n * - Configurable concurrency limit\n * - Task success/error/completion callbacks\n * - FIFO (First In First Out) or LIFO (Last In First Out) queuer behavior\n * - Pause/resume task processing\n * - Task cancellation\n *\n * Tasks are processed concurrently up to the configured concurrency limit. When a task completes,\n * the next pending task is processed if below the concurrency limit.\n *\n * @example\n * ```ts\n * const queuer = new AsyncQueuer<string>({ concurrency: 2 });\n *\n * queuer.addItem(async () => {\n * return 'Hello';\n * });\n *\n * queuer.start();\n *\n * queuer.onSuccess((result) => {\n * console.log(result); // 'Hello'\n * });\n * ```\n */\nexport class AsyncQueuer<TValue> {\n protected options: Required<AsyncQueuerOptions<TValue>>\n private items: Array<() => Promise<TValue>> = []\n private activeItems: Set<() => Promise<TValue>> = new Set()\n private onSuccessCallbacks: Array<(result: TValue) => void> = []\n private onErrorCallbacks: Array<(error: Error) => void> = []\n private onSettledCallbacks: Array<(result: TValue | Error) => void> = []\n private running: boolean\n private pendingTick = false\n private executionCount = 0\n\n constructor(initialOptions: AsyncQueuerOptions<TValue> = defaultOptions) {\n this.options = { ...defaultOptions, ...initialOptions }\n this.running = this.options.started\n\n for (let i = 0; i < this.options.initialItems.length; i++) {\n const item = this.options.initialItems[i]!\n const isLast = i === this.options.initialItems.length - 1\n this.addItem(item, this.options.addItemsTo, isLast)\n }\n }\n\n /**\n * Updates the queuer options\n * Returns the new options state\n */\n setOptions(\n newOptions: Partial<AsyncQueuerOptions<TValue>>,\n ): AsyncQueuerOptions<TValue> {\n this.options = { ...this.options, ...newOptions }\n return this.options\n }\n\n /**\n * Processes items in the queuer\n */\n protected tick() {\n if (!this.running) {\n this.pendingTick = false\n return\n }\n\n while (\n this.activeItems.size < this.options.concurrency &&\n !this.isEmpty()\n ) {\n const nextFn = this.getNextItem()\n if (!nextFn) {\n break\n }\n\n this.activeItems.add(nextFn)\n ;(async () => {\n let success = false\n let res!: TValue\n let error: Error | undefined\n\n try {\n res = await nextFn()\n success = true\n } catch (e) {\n error = e as Error\n } finally {\n this.options.onUpdate(this)\n }\n\n this.activeItems.delete(nextFn)\n if (success) {\n this.onSuccessCallbacks.forEach((cb) => cb(res))\n } else {\n this.onErrorCallbacks.forEach((cb) => cb(error!))\n }\n this.onSettledCallbacks.forEach((cb) => cb(success ? res : error!))\n\n if (this.options.wait > 0) {\n setTimeout(() => this.tick(), this.options.wait)\n return\n }\n\n this.tick()\n })()\n }\n\n this.pendingTick = false\n }\n\n /**\n * Adds a task to the queuer\n */\n addItem(\n fn: (() => Promise<TValue>) & { priority?: number },\n position: QueuePosition = this.options.addItemsTo,\n runOnUpdate: boolean = true,\n ): Promise<TValue> {\n if (this.isFull()) {\n return Promise.reject(new Error('Queuer is full'))\n }\n\n return new Promise<TValue>((resolve, reject) => {\n const task = Object.assign(\n async () => {\n try {\n const result = await fn()\n resolve(result)\n return result\n } catch (error) {\n reject(error)\n throw error\n }\n },\n { priority: fn.priority ?? undefined },\n )\n\n // Get priority either from the function or from getPriority option\n const priority =\n this.options.getPriority !== defaultOptions.getPriority\n ? this.options.getPriority(task)\n : task.priority\n\n if (priority !== undefined) {\n // Insert based on priority\n const insertIndex = this.items.findIndex((existing) => {\n const existingPriority =\n this.options.getPriority !== defaultOptions.getPriority\n ? this.options.getPriority(existing)\n : (existing as any).priority\n return existingPriority > priority\n })\n\n if (insertIndex === -1) {\n this.items.push(task)\n } else {\n this.items.splice(insertIndex, 0, task)\n }\n } else {\n // Default FIFO/LIFO behavior\n if (position === 'front') {\n this.items.unshift(task)\n } else {\n this.items.push(task)\n }\n }\n\n if (runOnUpdate) {\n this.options.onUpdate(this)\n }\n\n if (this.running && !this.pendingTick) {\n this.pendingTick = true\n this.tick()\n }\n })\n }\n\n /**\n * Removes and returns an item from the queuer\n */\n getNextItem(\n position: QueuePosition = this.options.getItemsFrom,\n ): (() => Promise<TValue>) | undefined {\n let item: (() => Promise<TValue>) | undefined\n\n if (position === 'front') {\n item = this.items.shift()\n } else {\n item = this.items.pop()\n }\n\n if (item !== undefined) {\n this.executionCount++\n this.options.onUpdate(this)\n this.options.onGetNextItem(item, this)\n }\n return item\n }\n\n /**\n * Returns an item without removing it\n */\n peek(position: QueuePosition = 'front'): (() => Promise<TValue>) | undefined {\n if (position === 'front') {\n return this.items[0]\n }\n return this.items[this.items.length - 1]\n }\n\n /**\n * Returns true if the queuer is empty\n */\n isEmpty(): boolean {\n return this.items.length === 0\n }\n\n /**\n * Returns true if the queuer is full\n */\n isFull(): boolean {\n return this.items.length >= this.options.maxSize\n }\n\n /**\n * Returns the current size of the queuer\n */\n size(): number {\n return this.items.length\n }\n\n /**\n * Removes all items from the queuer\n */\n clear(): void {\n this.items = []\n this.options.onUpdate(this)\n }\n\n /**\n * Resets the queuer to its initial state\n */\n reset(withInitialItems?: boolean): void {\n this.clear()\n this.executionCount = 0\n if (withInitialItems) {\n this.items = [...this.options.initialItems]\n }\n this.running = this.options.started\n }\n\n /**\n * Returns a copy of all items in the queuer\n */\n getAllItems(): Array<() => Promise<TValue>> {\n return [...this.items]\n }\n\n /**\n * Returns the number of items that have been removed from the queuer\n */\n getExecutionCount(): number {\n return this.executionCount\n }\n\n /**\n * Returns the active items\n */\n getActiveItems(): Array<() => Promise<TValue>> {\n return Array.from(this.activeItems)\n }\n\n /**\n * Returns the pending items\n */\n getPendingItems(): Array<() => Promise<TValue>> {\n return this.getAllItems()\n }\n\n /**\n * Adds a callback to be called when a task succeeds\n */\n onSuccess(cb: (result: TValue) => void) {\n this.onSuccessCallbacks.push(cb)\n return () => {\n this.onSuccessCallbacks = this.onSuccessCallbacks.filter((d) => d !== cb)\n }\n }\n\n /**\n * Adds a callback to be called when a task errors\n */\n onError(cb: (error: Error) => void) {\n this.onErrorCallbacks.push(cb)\n return () => {\n this.onErrorCallbacks = this.onErrorCallbacks.filter((d) => d !== cb)\n }\n }\n\n /**\n * Adds a callback to be called when a task is settled\n */\n onSettled(cb: (result: TValue | Error) => void) {\n this.onSettledCallbacks.push(cb)\n return () => {\n this.onSettledCallbacks = this.onSettledCallbacks.filter((d) => d !== cb)\n }\n }\n\n /**\n * Starts the queuer and processes items\n */\n start(): Promise<void> {\n this.running = true\n if (!this.pendingTick && !this.isEmpty()) {\n this.pendingTick = true\n this.tick()\n }\n this.options.onUpdate(this)\n\n return new Promise<void>((resolve) => {\n const checkIdle = () => {\n if (this.isIdle()) {\n resolve()\n } else {\n setTimeout(checkIdle, 100)\n }\n }\n checkIdle()\n })\n }\n\n /**\n * Stops the queuer from processing items\n */\n stop(): void {\n this.running = false\n this.pendingTick = false\n this.options.onUpdate(this)\n }\n\n /**\n * Returns true if the queuer is running\n */\n isRunning(): boolean {\n return this.running\n }\n\n /**\n * Returns true if the queuer is running but has no items to process\n */\n isIdle(): boolean {\n return this.running && this.isEmpty() && this.activeItems.size === 0\n }\n}\n\n/**\n * Creates a new AsyncQueuer instance with the given options and returns a bound addItem function.\n * The queuer is automatically started and ready to process items.\n *\n * @example\n * ```ts\n * const enqueue = asyncQueue<string>();\n *\n * // Add items to be processed\n * enqueue(async () => {\n * return 'Hello';\n * });\n * ```\n *\n * @param options - Configuration options for the AsyncQueuer\n * @returns A bound addItem function that can be used to add tasks to the queuer\n */\nexport function asyncQueue<TValue>(options: AsyncQueuerOptions<TValue> = {}) {\n const queuer = new AsyncQueuer<TValue>({ ...options, started: true })\n return queuer.addItem.bind(queuer)\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"async-queuer.cjs","sources":["../../src/async-queuer.ts"],"sourcesContent":["import type { QueuePosition } from './queuer'\n\nexport interface AsyncQueuerOptions<TValue> {\n /**\n * Default position to add items to the queuer\n * @default 'back'\n */\n addItemsTo?: QueuePosition\n /**\n * Maximum number of concurrent tasks to process\n */\n concurrency?: number\n /**\n * Default position to get items from during processing\n * @default 'front'\n */\n getItemsFrom?: QueuePosition\n /**\n * Function to determine priority of items in the queuer\n * Higher priority items will be processed first\n * If not provided, will use static priority values attached to tasks\n */\n getPriority?: (item: () => Promise<TValue>) => number\n /**\n * Initial items to populate the queuer with\n */\n initialItems?: Array<(() => Promise<TValue>) & { priority?: number }>\n /**\n * Maximum number of items allowed in the queuer\n */\n maxSize?: number\n /**\n * Callback fired whenever an item is removed from the queuer\n */\n onGetNextItem?: (\n item: () => Promise<TValue>,\n queuer: AsyncQueuer<TValue>,\n ) => void\n /**\n * Callback fired whenever the queuer's running state changes\n */\n onIsRunningChange?: (queuer: AsyncQueuer<TValue>) => void\n /**\n * Callback fired whenever an item is added or removed from the queuer\n */\n onItemsChange?: (queuer: AsyncQueuer<TValue>) => void\n /**\n * Callback fired whenever an item is rejected from being added to the queuer\n */\n onReject?: (item: () => Promise<TValue>, queuer: AsyncQueuer<TValue>) => void\n /**\n * Whether the queuer should start processing tasks immediately\n */\n started?: boolean\n /**\n * Time in milliseconds to wait between processing items\n */\n wait?: number\n}\n\nconst defaultOptions: Required<AsyncQueuerOptions<any>> = {\n addItemsTo: 'back',\n concurrency: 1,\n getItemsFrom: 'front',\n getPriority: (item) => (item as any)?.priority ?? 0,\n initialItems: [],\n maxSize: Infinity,\n onGetNextItem: () => {},\n onIsRunningChange: () => {},\n onItemsChange: () => {},\n onReject: () => {},\n started: false,\n wait: 0,\n}\n\n/**\n * A flexible asynchronous queue that processes tasks with configurable concurrency control.\n *\n * Features:\n * - Priority queue support via getPriority option\n * - Configurable concurrency limit\n * - Task success/error/completion callbacks\n * - FIFO (First In First Out) or LIFO (Last In First Out) queue behavior\n * - Pause/resume task processing\n * - Task cancellation\n *\n * Tasks are processed concurrently up to the configured concurrency limit. When a task completes,\n * the next pending task is processed if below the concurrency limit.\n *\n * @example\n * ```ts\n * const asyncQueuer = new AsyncQueuer<string>({ concurrency: 2 });\n *\n * asyncQueuer.addItem(async () => {\n * return 'Hello';\n * });\n *\n * asyncQueuer.start();\n *\n * asyncQueuer.onSuccess((result) => {\n * console.log(result); // 'Hello'\n * });\n * ```\n */\nexport class AsyncQueuer<TValue> {\n private _options: Required<AsyncQueuerOptions<TValue>>\n private _activeItems: Set<() => Promise<TValue>> = new Set()\n private _executionCount = 0\n private _rejectionCount = 0\n private _items: Array<() => Promise<TValue>> = []\n private _onErrorCallbacks: Array<(error: Error) => void> = []\n private _onSettledCallbacks: Array<(result: TValue | Error) => void> = []\n private _onSuccessCallbacks: Array<(result: TValue) => void> = []\n private _pendingTick = false\n private _running: boolean\n\n constructor(initialOptions: AsyncQueuerOptions<TValue> = defaultOptions) {\n this._options = { ...defaultOptions, ...initialOptions }\n this._running = this._options.started\n\n for (let i = 0; i < this._options.initialItems.length; i++) {\n const item = this._options.initialItems[i]!\n const isLast = i === this._options.initialItems.length - 1\n this.addItem(item, this._options.addItemsTo, isLast)\n }\n }\n\n /**\n * Updates the queuer options\n * Returns the new options state\n */\n setOptions(\n newOptions: Partial<AsyncQueuerOptions<TValue>>,\n ): AsyncQueuerOptions<TValue> {\n this._options = { ...this._options, ...newOptions }\n return this._options\n }\n\n /**\n * Returns the current queuer options\n */\n getOptions(): Required<AsyncQueuerOptions<TValue>> {\n return this._options\n }\n\n /**\n * Processes items in the queuer\n */\n private tick() {\n if (!this._running) {\n this._pendingTick = false\n return\n }\n\n while (\n this._activeItems.size < this._options.concurrency &&\n !this.getIsEmpty()\n ) {\n const nextFn = this.getNextItem()\n if (!nextFn) {\n break\n }\n this._activeItems.add(nextFn)\n this._options.onItemsChange(this)\n ;(async () => {\n let success = false\n let res!: TValue\n let error: Error | undefined\n\n try {\n res = await nextFn()\n success = true\n } catch (e) {\n error = e as Error\n } finally {\n this._activeItems.delete(nextFn)\n this._options.onItemsChange(this)\n }\n\n if (success) {\n this._onSuccessCallbacks.forEach((cb) => cb(res))\n } else {\n this._onErrorCallbacks.forEach((cb) => cb(error!))\n }\n this._onSettledCallbacks.forEach((cb) => cb(success ? res : error!))\n\n if (this._options.wait > 0) {\n setTimeout(() => this.tick(), this._options.wait)\n return\n }\n\n this.tick()\n })()\n }\n\n this._pendingTick = false\n }\n\n /**\n * Starts the queuer and processes items\n */\n start(): Promise<void> {\n this._running = true\n if (!this._pendingTick && !this.getIsEmpty()) {\n this._pendingTick = true\n this.tick()\n }\n this._options.onIsRunningChange(this)\n\n return new Promise<void>((resolve) => {\n const checkIdle = () => {\n if (this.getIsIdle()) {\n resolve()\n } else {\n setTimeout(checkIdle, 100)\n }\n }\n checkIdle()\n })\n }\n\n /**\n * Stops the queuer from processing items\n */\n stop(): void {\n this._running = false\n this._pendingTick = false\n this._options.onIsRunningChange(this)\n }\n\n /**\n * Removes all items from the queuer\n */\n clear(): void {\n this._items = []\n this._options.onItemsChange(this)\n }\n\n /**\n * Resets the queuer to its initial state\n */\n reset(withInitialItems?: boolean): void {\n this.clear()\n this._executionCount = 0\n if (withInitialItems) {\n this._items = [...this._options.initialItems]\n }\n this._running = this._options.started\n }\n\n /**\n * Adds a task to the queuer\n */\n addItem(\n fn: (() => Promise<TValue>) & { priority?: number },\n position: QueuePosition = this._options.addItemsTo,\n runOnUpdate: boolean = true,\n ): Promise<TValue> {\n if (this.getIsFull()) {\n this._rejectionCount++\n this._options.onReject(fn, this)\n return Promise.reject(new Error('Queuer is full'))\n }\n\n return new Promise<TValue>((resolve, reject) => {\n const task = Object.assign(\n async () => {\n try {\n const result = await fn()\n resolve(result)\n return result\n } catch (error) {\n reject(error)\n throw error\n }\n },\n { priority: fn.priority ?? undefined },\n )\n\n // Get priority either from the function or from getPriority option\n const priority =\n this._options.getPriority !== defaultOptions.getPriority\n ? this._options.getPriority(task)\n : task.priority\n\n if (priority !== undefined) {\n // Insert based on priority\n const insertIndex = this._items.findIndex((existing) => {\n const existingPriority =\n this._options.getPriority !== defaultOptions.getPriority\n ? this._options.getPriority(existing)\n : (existing as any).priority\n return existingPriority > priority\n })\n\n if (insertIndex === -1) {\n this._items.push(task)\n } else {\n this._items.splice(insertIndex, 0, task)\n }\n } else {\n // Default FIFO/LIFO behavior\n if (position === 'front') {\n this._items.unshift(task)\n } else {\n this._items.push(task)\n }\n }\n\n if (runOnUpdate) {\n this._options.onItemsChange(this)\n }\n\n if (this._running && !this._pendingTick) {\n this._pendingTick = true\n this.tick()\n }\n })\n }\n\n /**\n * Removes and returns an item from the queuer\n */\n getNextItem(\n position: QueuePosition = this._options.getItemsFrom,\n ): (() => Promise<TValue>) | undefined {\n let item: (() => Promise<TValue>) | undefined\n\n if (position === 'front') {\n item = this._items.shift()\n } else {\n item = this._items.pop()\n }\n\n if (item !== undefined) {\n this._executionCount++\n this._options.onItemsChange(this)\n this._options.onGetNextItem(item, this)\n }\n return item\n }\n\n /**\n * Returns an item without removing it\n */\n getPeek(\n position: QueuePosition = 'front',\n ): (() => Promise<TValue>) | undefined {\n if (position === 'front') {\n return this._items[0]\n }\n return this._items[this._items.length - 1]\n }\n\n /**\n * Returns true if the queuer is empty\n */\n getIsEmpty(): boolean {\n return this._items.length === 0\n }\n\n /**\n * Returns true if the queuer is full\n */\n getIsFull(): boolean {\n return this._items.length >= this._options.maxSize\n }\n\n /**\n * Returns the current size of the queuer\n */\n getSize(): number {\n return this._items.length\n }\n\n /**\n * Returns a copy of all items in the queuer\n */\n getAllItems(): Array<() => Promise<TValue>> {\n return [...this.getActiveItems(), ...this.getPendingItems()]\n }\n\n /**\n * Returns the active items\n */\n getActiveItems(): Array<() => Promise<TValue>> {\n return Array.from(this._activeItems)\n }\n\n /**\n * Returns the pending items\n */\n getPendingItems(): Array<() => Promise<TValue>> {\n return [...this._items]\n }\n\n /**\n * Returns the number of items that have been removed from the queuer\n */\n getExecutionCount(): number {\n return this._executionCount\n }\n\n /**\n * Returns the number of items that have been rejected from the queuer\n */\n getRejectionCount(): number {\n return this._rejectionCount\n }\n\n /**\n * Returns true if the queuer is running\n */\n getIsRunning(): boolean {\n return this._running\n }\n\n /**\n * Returns true if the queuer is running but has no items to process\n */\n getIsIdle(): boolean {\n return this._running && this.getIsEmpty() && this._activeItems.size === 0\n }\n\n /**\n * Adds a callback to be called when a task succeeds\n */\n onSuccess(cb: (result: TValue) => void) {\n this._onSuccessCallbacks.push(cb)\n return () => {\n this._onSuccessCallbacks = this._onSuccessCallbacks.filter(\n (d) => d !== cb,\n )\n }\n }\n\n /**\n * Adds a callback to be called when a task errors\n */\n onError(cb: (error: Error) => void) {\n this._onErrorCallbacks.push(cb)\n return () => {\n this._onErrorCallbacks = this._onErrorCallbacks.filter((d) => d !== cb)\n }\n }\n\n /**\n * Adds a callback to be called when a task is settled\n */\n onSettled(cb: (result: TValue | Error) => void) {\n this._onSettledCallbacks.push(cb)\n return () => {\n this._onSettledCallbacks = this._onSettledCallbacks.filter(\n (d) => d !== cb,\n )\n }\n }\n}\n\n/**\n * Creates a new AsyncQueuer instance with the given options and returns a bound addItem function.\n * The queuer is automatically started and ready to process items.\n *\n * @example\n * ```ts\n * const enqueue = asyncQueue<string>();\n *\n * // Add items to be processed\n * enqueue(async () => {\n * return 'Hello';\n * });\n * ```\n *\n * @param options - Configuration options for the AsyncQueuer\n * @returns A bound addItem function that can be used to add tasks to the queuer\n */\nexport function asyncQueue<TValue>(options: AsyncQueuerOptions<TValue> = {}) {\n const queuer = new AsyncQueuer<TValue>({ ...options, started: true })\n return queuer.addItem.bind(queuer)\n}\n"],"names":[],"mappings":"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"}