@tanstack/pacer 0.8.0 → 0.9.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 (91) hide show
  1. package/dist/cjs/async-batcher.cjs +163 -0
  2. package/dist/cjs/async-batcher.cjs.map +1 -0
  3. package/dist/cjs/async-batcher.d.cts +273 -0
  4. package/dist/cjs/async-debouncer.cjs +149 -162
  5. package/dist/cjs/async-debouncer.cjs.map +1 -1
  6. package/dist/cjs/async-debouncer.d.cts +76 -57
  7. package/dist/cjs/async-queuer.cjs +282 -343
  8. package/dist/cjs/async-queuer.cjs.map +1 -1
  9. package/dist/cjs/async-queuer.d.cts +121 -100
  10. package/dist/cjs/async-rate-limiter.cjs +128 -185
  11. package/dist/cjs/async-rate-limiter.cjs.map +1 -1
  12. package/dist/cjs/async-rate-limiter.d.cts +72 -61
  13. package/dist/cjs/async-throttler.cjs +168 -178
  14. package/dist/cjs/async-throttler.cjs.map +1 -1
  15. package/dist/cjs/async-throttler.d.cts +97 -69
  16. package/dist/cjs/batcher.cjs +110 -119
  17. package/dist/cjs/batcher.cjs.map +1 -1
  18. package/dist/cjs/batcher.d.cts +76 -51
  19. package/dist/cjs/debouncer.cjs +97 -85
  20. package/dist/cjs/debouncer.cjs.map +1 -1
  21. package/dist/cjs/debouncer.d.cts +54 -26
  22. package/dist/cjs/index.cjs +3 -6
  23. package/dist/cjs/index.cjs.map +1 -1
  24. package/dist/cjs/index.d.cts +1 -1
  25. package/dist/cjs/queuer.cjs +246 -294
  26. package/dist/cjs/queuer.cjs.map +1 -1
  27. package/dist/cjs/queuer.d.cts +102 -81
  28. package/dist/cjs/rate-limiter.cjs +97 -130
  29. package/dist/cjs/rate-limiter.cjs.map +1 -1
  30. package/dist/cjs/rate-limiter.d.cts +50 -37
  31. package/dist/cjs/throttler.cjs +107 -123
  32. package/dist/cjs/throttler.cjs.map +1 -1
  33. package/dist/cjs/throttler.d.cts +59 -35
  34. package/dist/cjs/utils.cjs +0 -13
  35. package/dist/cjs/utils.cjs.map +1 -1
  36. package/dist/cjs/utils.d.cts +0 -1
  37. package/dist/esm/async-batcher.d.ts +273 -0
  38. package/dist/esm/async-batcher.js +163 -0
  39. package/dist/esm/async-batcher.js.map +1 -0
  40. package/dist/esm/async-debouncer.d.ts +76 -57
  41. package/dist/esm/async-debouncer.js +149 -162
  42. package/dist/esm/async-debouncer.js.map +1 -1
  43. package/dist/esm/async-queuer.d.ts +121 -100
  44. package/dist/esm/async-queuer.js +282 -343
  45. package/dist/esm/async-queuer.js.map +1 -1
  46. package/dist/esm/async-rate-limiter.d.ts +72 -61
  47. package/dist/esm/async-rate-limiter.js +128 -185
  48. package/dist/esm/async-rate-limiter.js.map +1 -1
  49. package/dist/esm/async-throttler.d.ts +97 -69
  50. package/dist/esm/async-throttler.js +168 -178
  51. package/dist/esm/async-throttler.js.map +1 -1
  52. package/dist/esm/batcher.d.ts +76 -51
  53. package/dist/esm/batcher.js +110 -119
  54. package/dist/esm/batcher.js.map +1 -1
  55. package/dist/esm/debouncer.d.ts +54 -26
  56. package/dist/esm/debouncer.js +97 -85
  57. package/dist/esm/debouncer.js.map +1 -1
  58. package/dist/esm/index.d.ts +1 -1
  59. package/dist/esm/index.js +4 -7
  60. package/dist/esm/queuer.d.ts +102 -81
  61. package/dist/esm/queuer.js +246 -294
  62. package/dist/esm/queuer.js.map +1 -1
  63. package/dist/esm/rate-limiter.d.ts +50 -37
  64. package/dist/esm/rate-limiter.js +97 -130
  65. package/dist/esm/rate-limiter.js.map +1 -1
  66. package/dist/esm/throttler.d.ts +59 -35
  67. package/dist/esm/throttler.js +107 -123
  68. package/dist/esm/throttler.js.map +1 -1
  69. package/dist/esm/utils.d.ts +0 -1
  70. package/dist/esm/utils.js +0 -13
  71. package/dist/esm/utils.js.map +1 -1
  72. package/package.json +14 -11
  73. package/src/async-batcher.ts +475 -0
  74. package/src/async-debouncer.ts +201 -121
  75. package/src/async-queuer.ts +337 -216
  76. package/src/async-rate-limiter.ts +176 -136
  77. package/src/async-throttler.ts +233 -139
  78. package/src/batcher.ts +158 -92
  79. package/src/debouncer.ts +135 -52
  80. package/src/index.ts +1 -1
  81. package/src/queuer.ts +348 -226
  82. package/src/rate-limiter.ts +125 -80
  83. package/src/throttler.ts +152 -78
  84. package/src/utils.ts +0 -15
  85. package/dist/cjs/compare.cjs +0 -72
  86. package/dist/cjs/compare.cjs.map +0 -1
  87. package/dist/cjs/compare.d.cts +0 -12
  88. package/dist/esm/compare.d.ts +0 -12
  89. package/dist/esm/compare.js +0 -72
  90. package/dist/esm/compare.js.map +0 -1
  91. package/src/compare.ts +0 -105
@@ -1 +1 @@
1
- {"version":3,"file":"queuer.cjs","sources":["../../src/queuer.ts"],"sourcesContent":["import { parseFunctionOrValue } from './utils'\n\n/**\n * Options for configuring a Queuer instance.\n *\n * These options control queue behavior, item expiration, callbacks, and more.\n */\nexport interface QueuerOptions<TValue> {\n /**\n * Default position to add items to the queuer\n * @default 'back'\n */\n addItemsTo?: QueuePosition\n /**\n * Maximum time in milliseconds that an item can stay in the queue\n * If not provided, items will never expire\n */\n expirationDuration?: number\n /**\n * Function to determine if an item has expired\n * If provided, this overrides the expirationDuration behavior\n */\n getIsExpired?: (item: TValue, addedAt: number) => boolean\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 */\n getPriority?: (item: TValue) => number\n /**\n * Initial items to populate the queuer with\n */\n initialItems?: Array<TValue>\n /**\n * Maximum number of items allowed in the queuer\n */\n maxSize?: number\n /**\n * Callback fired whenever an item expires in the queuer\n */\n onExpire?: (item: TValue, queuer: Queuer<TValue>) => void\n /**\n * Callback fired whenever an item is removed from the queuer\n */\n onExecute?: (item: TValue, queuer: Queuer<TValue>) => void\n /**\n * Callback fired whenever the queuer's running state changes\n */\n onIsRunningChange?: (queuer: Queuer<TValue>) => void\n /**\n * Callback fired whenever an item is added or removed from the queuer\n */\n onItemsChange?: (queuer: Queuer<TValue>) => void\n /**\n * Callback fired whenever an item is rejected from being added to the queuer\n */\n onReject?: (item: TValue, queuer: Queuer<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 * Can be a number or a function that returns a number.\n * @default 0\n */\n wait?: number | ((queuer: Queuer<TValue>) => number)\n}\n\nconst defaultOptions: Required<QueuerOptions<any>> = {\n addItemsTo: 'back',\n getItemsFrom: 'front',\n getPriority: (item) => item?.priority ?? 0,\n getIsExpired: () => false,\n expirationDuration: Infinity,\n initialItems: [],\n maxSize: Infinity,\n onExecute: () => {},\n onIsRunningChange: () => {},\n onItemsChange: () => {},\n onReject: () => {},\n onExpire: () => {},\n started: true,\n wait: 0,\n}\n\n/**\n * Position type for addItem and getNextItem operations.\n *\n * - 'front': Operate on the front of the queue (FIFO)\n * - 'back': Operate on the back of the queue (LIFO)\n */\nexport type QueuePosition = 'front' | 'back'\n\n/**\n * A flexible queue that processes items with configurable wait times, expiration, and priority.\n *\n * Features:\n * - Automatic or manual processing of items\n * - FIFO (First In First Out), LIFO (Last In First Out), or double-ended queue behavior\n * - Priority-based ordering when getPriority is provided\n * - Item expiration and removal of stale items\n * - Callbacks for queue state changes, execution, rejection, and expiration\n *\n * Running behavior:\n * - `start()`: Begins automatically processing items in the queue (defaults to running)\n * - `stop()`: Pauses processing but maintains queue state\n * - `wait`: Configurable delay between processing items\n * - `onItemsChange`/`onExecute`: Callbacks for monitoring queue state\n *\n * Manual processing is also supported when automatic processing is disabled:\n * - `execute()`: Processes the next item using the provided function\n * - `getNextItem()`: Removes and returns the next item without processing\n *\n * Queue behavior defaults to FIFO:\n * - `addItem(item)`: Adds to the back of the queue\n * - Items processed from the front of the queue\n *\n * Priority queue:\n * - Provide a `getPriority` function; higher values are processed first\n *\n * Stack (LIFO):\n * - `addItem(item, 'back')`: Adds to the back\n * - `getNextItem('back')`: Removes from the back\n *\n * Double-ended queue:\n * - `addItem(item, position)`: Adds to specified position ('front'/'back')\n * - `getNextItem(position)`: Removes from specified position\n *\n * Item expiration:\n * - `expirationDuration`: Maximum time items can stay in the queue\n * - `getIsExpired`: Function to override default expiration\n * - `onExpire`: Callback for expired items\n *\n * Example usage:\n * ```ts\n * // Auto-processing queue with wait time\n * const autoQueue = new Queuer<number>((n) => console.log(n), {\n * started: true, // Begin processing immediately\n * wait: 1000, // Wait 1s between items\n * onExecute: (item) => console.log(`Processed ${item}`)\n * });\n * autoQueue.addItem(1); // Will process after 1s\n * autoQueue.addItem(2); // Will process 1s after first item\n *\n * // Manual processing queue\n * const manualQueue = new Queuer<number>((n) => console.log(n), {\n * started: false\n * });\n * manualQueue.addItem(1); // [1]\n * manualQueue.addItem(2); // [1, 2]\n * manualQueue.execute(); // logs 1, queue is [2]\n * manualQueue.getNextItem(); // returns 2, queue is empty\n * ```\n */\nexport class Queuer<TValue> {\n private _options: Required<QueuerOptions<TValue>>\n private _items: Array<TValue> = []\n private _itemTimestamps: Array<number> = []\n private _executionCount = 0\n private _rejectionCount = 0\n private _expirationCount = 0\n private _onItemsChanges: Array<(item: TValue) => void> = []\n private _running: boolean\n private _pendingTick = false\n\n constructor(\n private fn: (item: TValue) => void,\n initialOptions: QueuerOptions<TValue> = {},\n ) {\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. New options are merged with existing options.\n */\n setOptions(newOptions: Partial<QueuerOptions<TValue>>): void {\n this._options = { ...this._options, ...newOptions }\n }\n\n /**\n * Returns the current queuer options, including defaults and any overrides.\n */\n getOptions(): Required<QueuerOptions<TValue>> {\n return this._options\n }\n\n /**\n * Returns the current wait time (in milliseconds) between processing items.\n * If a function is provided, it is called with the queuer instance.\n */\n getWait(): number {\n return parseFunctionOrValue(this._options.wait, this)\n }\n\n /**\n * Processes items in the queue up to the wait interval. Internal use only.\n */\n private tick() {\n if (!this._running) {\n this._pendingTick = false\n return\n }\n\n // Check for expired items\n this.checkExpiredItems()\n\n while (!this.getIsEmpty()) {\n const nextItem = this.execute(this._options.getItemsFrom)\n if (nextItem === undefined) {\n break\n }\n this._onItemsChanges.forEach((cb) => cb(nextItem))\n\n const wait = this.getWait()\n if (wait > 0) {\n // Use setTimeout to wait before processing next item\n setTimeout(() => this.tick(), wait)\n return\n }\n\n this.tick()\n }\n this._pendingTick = false\n }\n\n /**\n * Checks for expired items in the queue and removes them. Calls onExpire for each expired item.\n * Internal use only.\n */\n private checkExpiredItems() {\n if (\n this._options.expirationDuration === Infinity &&\n this._options.getIsExpired === defaultOptions.getIsExpired\n )\n return\n\n const now = Date.now()\n const expiredIndices: Array<number> = []\n\n // Find indices of expired items\n for (let i = 0; i < this._items.length; i++) {\n const timestamp = this._itemTimestamps[i]\n if (timestamp === undefined) continue\n\n const item = this._items[i]\n if (item === undefined) continue\n\n const isExpired =\n this._options.getIsExpired !== defaultOptions.getIsExpired\n ? this._options.getIsExpired(item, timestamp)\n : now - timestamp > this._options.expirationDuration\n\n if (isExpired) {\n expiredIndices.push(i)\n }\n }\n\n // Remove expired items from back to front to maintain indices\n for (let i = expiredIndices.length - 1; i >= 0; i--) {\n const index = expiredIndices[i]\n if (index === undefined) continue\n\n const expiredItem = this._items[index]\n if (expiredItem === undefined) continue\n\n this._items.splice(index, 1)\n this._itemTimestamps.splice(index, 1)\n this._expirationCount++\n this._options.onExpire(expiredItem, this)\n }\n\n if (expiredIndices.length > 0) {\n this._options.onItemsChange(this)\n }\n }\n\n /**\n * Stops processing items in the queue. Does not clear the queue.\n */\n stop() {\n this._running = false\n this._pendingTick = false\n this._options.onIsRunningChange(this)\n }\n\n /**\n * Starts processing items in the queue. If already running, does nothing.\n */\n start() {\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\n /**\n * Removes all pending items from the queue. Does not affect items being processed.\n */\n clear(): void {\n this._items = []\n this._options.onItemsChange(this)\n }\n\n /**\n * Resets the queuer to its initial state. Optionally repopulates with initial items.\n * Does not affect callbacks or options.\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 an item to the queue. If the queue is full, the item is rejected and onReject is called.\n * Items can be inserted based on priority or at the front/back depending on configuration.\n *\n * Returns true if the item was added, false if the queue is full.\n *\n * Example usage:\n * ```ts\n * queuer.addItem('task');\n * queuer.addItem('task2', 'front');\n * ```\n */\n addItem(\n item: TValue,\n position: QueuePosition = this._options.addItemsTo,\n runOnUpdate: boolean = true,\n ): boolean {\n if (this.getIsFull()) {\n this._rejectionCount++\n this._options.onReject(item, this)\n return false\n }\n\n if (this._options.getPriority !== defaultOptions.getPriority) {\n // If custom priority function is provided, insert based on priority\n const priority = this._options.getPriority(item)\n const insertIndex = this._items.findIndex(\n (existing) => this._options.getPriority(existing) < priority,\n )\n\n if (insertIndex === -1) {\n this._items.push(item)\n this._itemTimestamps.push(Date.now())\n } else {\n this._items.splice(insertIndex, 0, item)\n this._itemTimestamps.splice(insertIndex, 0, Date.now())\n }\n } else {\n // Default FIFO/LIFO behavior\n if (position === 'front') {\n this._items.unshift(item)\n this._itemTimestamps.unshift(Date.now())\n } else {\n this._items.push(item)\n this._itemTimestamps.push(Date.now())\n }\n }\n\n if (this._running && !this._pendingTick) {\n this._pendingTick = true\n this.tick()\n }\n if (runOnUpdate) {\n this._options.onItemsChange(this)\n }\n return true\n }\n\n /**\n * Removes and returns the next item from the queue without executing the function.\n * Use for manual queue management. Normally, use execute() to process items.\n *\n * Example usage:\n * ```ts\n * // FIFO\n * queuer.getNextItem();\n * // LIFO\n * queuer.getNextItem('back');\n * ```\n */\n getNextItem(\n position: QueuePosition = this._options.getItemsFrom,\n ): TValue | undefined {\n let item: TValue | undefined\n\n if (position === 'front') {\n item = this._items.shift()\n this._itemTimestamps.shift()\n } else {\n item = this._items.pop()\n this._itemTimestamps.pop()\n }\n\n if (item !== undefined) {\n this._options.onItemsChange(this)\n }\n\n return item\n }\n\n /**\n * Removes and returns the next item from the queue and processes it using the provided function.\n *\n * Example usage:\n * ```ts\n * queuer.execute();\n * // LIFO\n * queuer.execute('back');\n * ```\n */\n execute(position?: QueuePosition): TValue | undefined {\n const item = this.getNextItem(position)\n if (item !== undefined) {\n this.fn(item)\n this._executionCount++\n this._options.onExecute(item, this)\n }\n return item\n }\n\n /**\n * Returns the next item in the queue without removing it.\n *\n * Example usage:\n * ```ts\n * queuer.peekNextItem(); // front\n * queuer.peekNextItem('back'); // back\n * ```\n */\n peekNextItem(\n position: QueuePosition = this._options.getItemsFrom,\n ): 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 queue is empty (no pending items).\n */\n getIsEmpty(): boolean {\n return this._items.length === 0\n }\n\n /**\n * Returns true if the queue is full (reached maxSize).\n */\n getIsFull(): boolean {\n return this._items.length >= this._options.maxSize\n }\n\n /**\n * Returns the number of pending items in the queue.\n */\n getSize(): number {\n return this._items.length\n }\n\n /**\n * Returns a copy of all items in the queue.\n */\n peekAllItems(): Array<TValue> {\n return [...this._items]\n }\n\n /**\n * Returns the number of items that have been processed and removed from the queue.\n */\n getExecutionCount(): number {\n return this._executionCount\n }\n\n /**\n * Returns the number of items that have been rejected from being added to the queue.\n */\n getRejectionCount(): number {\n return this._rejectionCount\n }\n\n /**\n * Returns the number of items that have expired and been removed from the queue.\n */\n getExpirationCount(): number {\n return this._expirationCount\n }\n\n /**\n * Returns true if the queuer is currently running (processing items).\n */\n getIsRunning() {\n return this._running\n }\n\n /**\n * Returns true if the queuer is running but has no items to process.\n */\n getIsIdle() {\n return this._running && this.getIsEmpty()\n }\n}\n\n/**\n * Creates a queue that processes items immediately upon addition.\n * Items are processed sequentially in FIFO order by default.\n *\n * This is a simplified wrapper around the Queuer class that only exposes the\n * `addItem` method. The queue is always running and will process items as they are added.\n * For more control over queue processing, use the Queuer class directly.\n *\n * Example usage:\n * ```ts\n * // Basic sequential processing\n * const processItems = queue<number>((n) => console.log(n), {\n * wait: 1000,\n * onItemsChange: (queuer) => console.log(queuer.peekAllItems())\n * });\n * processItems(1); // Logs: 1\n * processItems(2); // Logs: 2 after 1 completes\n *\n * // Priority queue\n * const processPriority = queue<number>((n) => console.log(n), {\n * getPriority: n => n // Higher numbers processed first\n * });\n * processPriority(1);\n * processPriority(3); // Processed before 1\n * ```\n */\nexport function queue<TValue>(\n fn: (item: TValue) => void,\n options: QueuerOptions<TValue>,\n) {\n const queuer = new Queuer<TValue>(fn, options)\n return queuer.addItem.bind(queuer)\n}\n"],"names":["parseFunctionOrValue"],"mappings":"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"}
1
+ {"version":3,"file":"queuer.cjs","sources":["../../src/queuer.ts"],"sourcesContent":["import { Store } from '@tanstack/store'\nimport { parseFunctionOrValue } from './utils'\n\nexport interface QueuerState<TValue> {\n /**\n * Number of items that have been processed by the queuer\n */\n executionCount: number\n /**\n * Number of items that have been removed from the queue due to expiration\n */\n expirationCount: number\n /**\n * Whether the queuer has no items to process (items array is empty)\n */\n isEmpty: boolean\n /**\n * Whether the queuer has reached its maximum capacity\n */\n isFull: boolean\n /**\n * Whether the queuer is not currently processing any items\n */\n isIdle: boolean\n /**\n * Whether the queuer is active and will process items automatically\n */\n isRunning: boolean\n /**\n * Timestamps when items were added to the queue for expiration tracking\n */\n itemTimestamps: Array<number>\n /**\n * Array of items currently waiting to be processed\n */\n items: Array<TValue>\n /**\n * Whether the queuer has a pending timeout for processing the next item\n */\n pendingTick: boolean\n /**\n * Number of items that have been rejected from being added to the queue\n */\n rejectionCount: number\n /**\n * Number of items currently in the queue\n */\n size: number\n /**\n * Current processing status - 'idle' when not processing, 'running' when active, 'stopped' when paused\n */\n status: 'idle' | 'running' | 'stopped'\n}\n\nfunction getDefaultQueuerState<TValue>(): QueuerState<TValue> {\n return {\n executionCount: 0,\n expirationCount: 0,\n isEmpty: true,\n isFull: false,\n isIdle: true,\n isRunning: true,\n itemTimestamps: [],\n items: [],\n pendingTick: false,\n rejectionCount: 0,\n size: 0,\n status: 'idle',\n }\n}\n\n/**\n * Options for configuring a Queuer instance.\n *\n * These options control queue behavior, item expiration, callbacks, and more.\n */\nexport interface QueuerOptions<TValue> {\n /**\n * Default position to add items to the queuer\n * @default 'back'\n */\n addItemsTo?: QueuePosition\n /**\n * Maximum time in milliseconds that an item can stay in the queue\n * If not provided, items will never expire\n */\n expirationDuration?: number\n /**\n * Function to determine if an item has expired\n * If provided, this overrides the expirationDuration behavior\n */\n getIsExpired?: (item: TValue, addedAt: number) => boolean\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 */\n getPriority?: (item: TValue) => number\n /**\n * Initial items to populate the queuer with\n */\n initialItems?: Array<TValue>\n /**\n * Initial state for the queuer\n */\n initialState?: Partial<QueuerState<TValue>>\n /**\n * Maximum number of items allowed in the queuer\n */\n maxSize?: number\n /**\n * Callback fired whenever an item expires in the queuer\n */\n onExpire?: (item: TValue, queuer: Queuer<TValue>) => void\n /**\n * Callback fired whenever an item is removed from the queuer\n */\n onExecute?: (item: TValue, queuer: Queuer<TValue>) => void\n /**\n * Callback fired whenever an item is added or removed from the queuer\n */\n onItemsChange?: (queuer: Queuer<TValue>) => void\n /**\n * Callback fired whenever an item is rejected from being added to the queuer\n */\n onReject?: (item: TValue, queuer: Queuer<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 * Can be a number or a function that returns a number.\n * @default 0\n */\n wait?: number | ((queuer: Queuer<TValue>) => number)\n}\n\nconst defaultOptions: Omit<\n Required<QueuerOptions<any>>,\n | 'initialState'\n | 'onExecute'\n | 'onIsRunningChange'\n | 'onItemsChange'\n | 'onReject'\n | 'onExpire'\n> = {\n addItemsTo: 'back',\n getItemsFrom: 'front',\n getPriority: (item) => item?.priority ?? 0,\n getIsExpired: () => false,\n expirationDuration: Infinity,\n initialItems: [],\n maxSize: Infinity,\n started: true,\n wait: 0,\n}\n\n/**\n * Position type for addItem and getNextItem operations.\n *\n * - 'front': Operate on the front of the queue (FIFO)\n * - 'back': Operate on the back of the queue (LIFO)\n */\nexport type QueuePosition = 'front' | 'back'\n\n/**\n * A flexible queue that processes items with configurable wait times, expiration, and priority.\n *\n * Features:\n * - Automatic or manual processing of items\n * - FIFO (First In First Out), LIFO (Last In First Out), or double-ended queue behavior\n * - Priority-based ordering when getPriority is provided\n * - Item expiration and removal of stale items\n * - Callbacks for queue state changes, execution, rejection, and expiration\n *\n * Running behavior:\n * - `start()`: Begins automatically processing items in the queue (defaults to isRunning)\n * - `stop()`: Pauses processing but maintains queue state\n * - `wait`: Configurable delay between processing items\n * - `onItemsChange`/`onExecute`: Callbacks for monitoring queue state\n *\n * Manual processing is also supported when automatic processing is disabled:\n * - `execute()`: Processes the next item using the provided function\n * - `getNextItem()`: Removes and returns the next item without processing\n *\n * Queue behavior defaults to FIFO:\n * - `addItem(item)`: Adds to the back of the queue\n * - Items processed from the front of the queue\n *\n * Priority queue:\n * - Provide a `getPriority` function; higher values are processed first\n *\n * Stack (LIFO):\n * - `addItem(item, 'back')`: Adds to the back\n * - `getNextItem('back')`: Removes from the back\n *\n * Double-ended queue:\n * - `addItem(item, position)`: Adds to specified position ('front'/'back')\n * - `getNextItem(position)`: Removes from specified position\n *\n * Item expiration:\n * - `expirationDuration`: Maximum time items can stay in the queue\n * - `getIsExpired`: Function to override default expiration\n * - `onExpire`: Callback for expired items\n *\n * State Management:\n * - Uses TanStack Store for reactive state management\n * - Use `initialState` to provide initial state values when creating the queuer\n * - Use `onExecute` callback to react to item execution and implement custom logic\n * - Use `onItemsChange` callback to react to items being added or removed from the queue\n * - Use `onExpire` callback to react to items expiring and implement custom logic\n * - Use `onReject` callback to react to items being rejected when the queue is full\n * - The state includes execution count, expiration count, rejection count, and isRunning status\n * - State can be accessed via `queuer.store.state` when using the class directly\n * - When using framework adapters (React/Solid), state is accessed from `queuer.state`\n *\n * Example usage:\n * ```ts\n * // Auto-processing queue with wait time\n * const autoQueue = new Queuer<number>((n) => console.log(n), {\n * started: true, // Begin processing immediately\n * wait: 1000, // Wait 1s between items\n * onExecute: (item) => console.log(`Processed ${item}`)\n * });\n * autoQueue.addItem(1); // Will process after 1s\n * autoQueue.addItem(2); // Will process 1s after first item\n *\n * // Manual processing queue\n * const manualQueue = new Queuer<number>((n) => console.log(n), {\n * started: false\n * });\n * manualQueue.addItem(1); // [1]\n * manualQueue.addItem(2); // [1, 2]\n * manualQueue.execute(); // logs 1, queue is [2]\n * manualQueue.getNextItem(); // returns 2, queue is empty\n * ```\n */\nexport class Queuer<TValue> {\n readonly store: Store<Readonly<QueuerState<TValue>>> = new Store(\n getDefaultQueuerState<TValue>(),\n )\n options: QueuerOptions<TValue>\n #timeoutId: NodeJS.Timeout | null = null\n\n constructor(\n private fn: (item: TValue) => void,\n initialOptions: QueuerOptions<TValue> = {},\n ) {\n this.options = {\n ...defaultOptions,\n ...initialOptions,\n }\n const isInitiallyRunning =\n this.options.initialState?.isRunning ?? this.options.started ?? true\n this.#setState({\n ...this.options.initialState,\n isRunning: isInitiallyRunning,\n })\n\n if (this.options.initialState?.items) {\n if (this.store.state.isRunning) {\n this.#tick()\n }\n } else {\n for (let i = 0; i < (this.options.initialItems?.length ?? 0); i++) {\n const item = this.options.initialItems![i]!\n const isLast = i === (this.options.initialItems?.length ?? 0) - 1\n this.addItem(item, this.options.addItemsTo ?? 'back', isLast)\n }\n }\n }\n\n /**\n * Updates the queuer options. New options are merged with existing options.\n */\n setOptions = (newOptions: Partial<QueuerOptions<TValue>>): void => {\n this.options = { ...this.options, ...newOptions }\n }\n\n #setState = (newState: Partial<QueuerState<TValue>>): void => {\n this.store.setState((state) => {\n const combinedState = {\n ...state,\n ...newState,\n }\n\n const { items, isRunning } = combinedState\n\n const size = items.length\n const isFull = size >= (this.options.maxSize ?? Infinity)\n const isEmpty = size === 0\n const isIdle = isRunning && isEmpty\n\n const status = isIdle ? 'idle' : isRunning ? 'running' : 'stopped'\n\n return {\n ...combinedState,\n isEmpty,\n isFull,\n isIdle,\n size,\n status,\n }\n })\n }\n\n /**\n * Returns the current wait time (in milliseconds) between processing items.\n * If a function is provided, it is called with the queuer instance.\n */\n #getWait = (): number => {\n return parseFunctionOrValue(this.options.wait ?? 0, this)\n }\n\n /**\n * Processes items in the queue up to the wait interval. Internal use only.\n */\n #tick = () => {\n if (!this.store.state.isRunning) {\n this.#setState({ pendingTick: false })\n return\n }\n\n this.#setState({ pendingTick: true })\n\n // Check for expired items\n this.#checkExpiredItems()\n\n while (!this.store.state.isEmpty) {\n const nextItem = this.execute(this.options.getItemsFrom ?? 'front')\n if (nextItem === undefined) {\n break\n }\n\n const wait = this.#getWait()\n if (wait > 0) {\n // Use setTimeout to wait before processing next item\n this.#timeoutId = setTimeout(() => this.#tick(), wait)\n return\n }\n\n this.#tick()\n }\n this.#setState({ pendingTick: false })\n }\n\n /**\n * Adds an item to the queue. If the queue is full, the item is rejected and onReject is called.\n * Items can be inserted based on priority or at the front/back depending on configuration.\n *\n * Returns true if the item was added, false if the queue is full.\n *\n * Example usage:\n * ```ts\n * queuer.addItem('task');\n * queuer.addItem('task2', 'front');\n * ```\n */\n addItem = (\n item: TValue,\n position: QueuePosition = this.options.addItemsTo ?? 'back',\n runOnItemsChange: boolean = true,\n ): boolean => {\n if (this.store.state.isFull) {\n this.#setState({\n rejectionCount: this.store.state.rejectionCount + 1,\n })\n this.options.onReject?.(item, this)\n return false\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!(item)\n : (item as any).priority\n\n const items = this.store.state.items\n const itemTimestamps = this.store.state.itemTimestamps\n\n if (priority !== undefined) {\n // Insert based on priority - higher priority items go to front\n const insertIndex = items.findIndex((existing) => {\n const existingPriority: number =\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 items.push(item)\n itemTimestamps.push(Date.now())\n } else {\n items.splice(insertIndex, 0, item)\n itemTimestamps.splice(insertIndex, 0, Date.now())\n }\n } else {\n if (position === 'front') {\n // Default FIFO/LIFO behavior\n items.unshift(item)\n itemTimestamps.unshift(Date.now())\n } else {\n // LIFO\n items.push(item)\n itemTimestamps.push(Date.now())\n }\n }\n\n this.#setState({\n items,\n itemTimestamps,\n })\n\n if (runOnItemsChange) {\n this.options.onItemsChange?.(this)\n }\n\n if (this.store.state.isRunning && !this.store.state.pendingTick) {\n this.#setState({ pendingTick: true })\n this.#tick()\n }\n\n return true\n }\n\n /**\n * Removes and returns the next item from the queue without executing the function.\n * Use for manual queue management. Normally, use execute() to process items.\n *\n * Example usage:\n * ```ts\n * // FIFO\n * queuer.getNextItem();\n * // LIFO\n * queuer.getNextItem('back');\n * ```\n */\n getNextItem = (\n position: QueuePosition = this.options.getItemsFrom ?? 'front',\n ): TValue | undefined => {\n const { items, itemTimestamps } = this.store.state\n let item: TValue | undefined\n\n if (position === 'front') {\n item = items[0]\n if (item !== undefined) {\n this.#setState({\n items: items.slice(1),\n itemTimestamps: itemTimestamps.slice(1),\n })\n }\n } else {\n item = items[items.length - 1]\n if (item !== undefined) {\n this.#setState({\n items: items.slice(0, -1),\n itemTimestamps: itemTimestamps.slice(0, -1),\n })\n }\n }\n\n if (item !== undefined) {\n this.options.onItemsChange?.(this)\n }\n\n return item\n }\n\n /**\n * Removes and returns the next item from the queue and processes it using the provided function.\n *\n * Example usage:\n * ```ts\n * queuer.execute();\n * // LIFO\n * queuer.execute('back');\n * ```\n */\n execute = (position?: QueuePosition): TValue | undefined => {\n const item = this.getNextItem(position)\n if (item !== undefined) {\n this.fn(item)\n this.#setState({\n executionCount: this.store.state.executionCount + 1,\n })\n this.options.onExecute?.(item, this)\n }\n return item\n }\n\n /**\n * Processes a specified number of items to execute immediately with no wait time\n * If no numberOfItems is provided, all items will be processed\n */\n flush = (\n numberOfItems: number = this.store.state.items.length,\n position?: QueuePosition,\n ): void => {\n this.#clearTimeout() // clear any pending timeout\n for (let i = 0; i < numberOfItems; i++) {\n this.execute(position)\n }\n }\n\n /**\n * Checks for expired items in the queue and removes them. Calls onExpire for each expired item.\n * Internal use only.\n */\n #checkExpiredItems = (): void => {\n if (\n (this.options.expirationDuration ?? Infinity) === Infinity &&\n this.options.getIsExpired === defaultOptions.getIsExpired\n ) {\n return\n }\n\n const now = Date.now()\n const expiredIndices: Array<number> = []\n\n // Find indices of expired items\n for (let i = 0; i < this.store.state.items.length; i++) {\n const timestamp = this.store.state.itemTimestamps[i]\n if (timestamp === undefined) continue\n\n const item = this.store.state.items[i]\n if (item === undefined) continue\n\n const isExpired =\n this.options.getIsExpired !== defaultOptions.getIsExpired\n ? this.options.getIsExpired!(item, timestamp)\n : now - timestamp > (this.options.expirationDuration ?? Infinity)\n\n if (isExpired) {\n expiredIndices.push(i)\n }\n }\n\n // Remove expired items from back to front to maintain indices\n for (let i = expiredIndices.length - 1; i >= 0; i--) {\n const index = expiredIndices[i]\n if (index === undefined) continue\n\n const expiredItem = this.store.state.items[index]\n if (expiredItem === undefined) continue\n\n const newItems = [...this.store.state.items]\n const newTimestamps = [...this.store.state.itemTimestamps]\n newItems.splice(index, 1)\n newTimestamps.splice(index, 1)\n this.#setState({\n items: newItems,\n itemTimestamps: newTimestamps,\n expirationCount: this.store.state.expirationCount + 1,\n })\n this.options.onExpire?.(expiredItem, this)\n }\n\n if (expiredIndices.length > 0) {\n this.options.onItemsChange?.(this)\n }\n }\n\n /**\n * Returns the next item in the queue without removing it.\n *\n * Example usage:\n * ```ts\n * queuer.peekNextItem(); // front\n * queuer.peekNextItem('back'); // back\n * ```\n */\n peekNextItem = (position: QueuePosition = 'front'): TValue | undefined => {\n if (position === 'front') {\n return this.store.state.items[0]\n }\n return this.store.state.items[this.store.state.size - 1]\n }\n\n /**\n * Returns a copy of all items in the queue.\n */\n peekAllItems = (): Array<TValue> => {\n return [...this.store.state.items]\n }\n\n /**\n * Starts processing items in the queue. If already isRunning, does nothing.\n */\n start = () => {\n this.#setState({ isRunning: true })\n if (!this.store.state.pendingTick && !this.store.state.isEmpty) {\n this.#tick()\n }\n }\n\n /**\n * Stops processing items in the queue. Does not clear the queue.\n */\n stop = () => {\n this.#clearTimeout()\n this.#setState({ isRunning: false, pendingTick: false })\n }\n\n #clearTimeout = (): void => {\n if (this.#timeoutId) {\n clearTimeout(this.#timeoutId)\n this.#timeoutId = null\n }\n }\n\n /**\n * Removes all pending items from the queue. Does not affect items being processed.\n */\n clear = (): void => {\n this.#setState({ items: [], itemTimestamps: [] })\n this.options.onItemsChange?.(this)\n }\n\n /**\n * Resets the queuer state to its default values\n */\n reset = (): void => {\n this.#setState(getDefaultQueuerState<TValue>())\n this.options.onItemsChange?.(this)\n }\n}\n\n/**\n * Creates a queue that processes items immediately upon addition.\n * Items are processed sequentially in FIFO order by default.\n *\n * This is a simplified wrapper around the Queuer class that only exposes the\n * `addItem` method. The queue is always isRunning and will process items as they are added.\n * For more control over queue processing, use the Queuer class directly.\n *\n * State Management:\n * - Uses TanStack Store for reactive state management\n * - Use `initialState` to provide initial state values when creating the queuer\n * - Use `onExecute` callback to react to item execution and implement custom logic\n * - Use `onItemsChange` callback to react to items being added or removed from the queue\n * - Use `onExpire` callback to react to items expiring and implement custom logic\n * - Use `onReject` callback to react to items being rejected when the queue is full\n * - The state includes execution count, expiration count, rejection count, and isRunning status\n * - State can be accessed via the underlying Queuer instance's `store.state` property\n * - When using framework adapters (React/Solid), state is accessed from the hook's state property\n *\n * Example usage:\n * ```ts\n * // Basic sequential processing\n * const processItems = queue<number>((n) => console.log(n), {\n * wait: 1000,\n * onItemsChange: (queuer) => console.log(queuer.peekAllItems())\n * });\n * processItems(1); // Logs: 1\n * processItems(2); // Logs: 2 after 1 completes\n *\n * // Priority queue\n * const processPriority = queue<number>((n) => console.log(n), {\n * getPriority: n => n // Higher numbers processed first\n * });\n * processPriority(1);\n * processPriority(3); // Processed before 1\n * ```\n */\nexport function queue<TValue>(\n fn: (item: TValue) => void,\n initialOptions: QueuerOptions<TValue>,\n) {\n const queuer = new Queuer<TValue>(fn, initialOptions)\n return queuer.addItem\n}\n"],"names":["Store","parseFunctionOrValue"],"mappings":"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"}
@@ -1,3 +1,54 @@
1
+ import { Store } from '@tanstack/store';
2
+ export interface QueuerState<TValue> {
3
+ /**
4
+ * Number of items that have been processed by the queuer
5
+ */
6
+ executionCount: number;
7
+ /**
8
+ * Number of items that have been removed from the queue due to expiration
9
+ */
10
+ expirationCount: number;
11
+ /**
12
+ * Whether the queuer has no items to process (items array is empty)
13
+ */
14
+ isEmpty: boolean;
15
+ /**
16
+ * Whether the queuer has reached its maximum capacity
17
+ */
18
+ isFull: boolean;
19
+ /**
20
+ * Whether the queuer is not currently processing any items
21
+ */
22
+ isIdle: boolean;
23
+ /**
24
+ * Whether the queuer is active and will process items automatically
25
+ */
26
+ isRunning: boolean;
27
+ /**
28
+ * Timestamps when items were added to the queue for expiration tracking
29
+ */
30
+ itemTimestamps: Array<number>;
31
+ /**
32
+ * Array of items currently waiting to be processed
33
+ */
34
+ items: Array<TValue>;
35
+ /**
36
+ * Whether the queuer has a pending timeout for processing the next item
37
+ */
38
+ pendingTick: boolean;
39
+ /**
40
+ * Number of items that have been rejected from being added to the queue
41
+ */
42
+ rejectionCount: number;
43
+ /**
44
+ * Number of items currently in the queue
45
+ */
46
+ size: number;
47
+ /**
48
+ * Current processing status - 'idle' when not processing, 'running' when active, 'stopped' when paused
49
+ */
50
+ status: 'idle' | 'running' | 'stopped';
51
+ }
1
52
  /**
2
53
  * Options for configuring a Queuer instance.
3
54
  *
@@ -33,6 +84,10 @@ export interface QueuerOptions<TValue> {
33
84
  * Initial items to populate the queuer with
34
85
  */
35
86
  initialItems?: Array<TValue>;
87
+ /**
88
+ * Initial state for the queuer
89
+ */
90
+ initialState?: Partial<QueuerState<TValue>>;
36
91
  /**
37
92
  * Maximum number of items allowed in the queuer
38
93
  */
@@ -45,10 +100,6 @@ export interface QueuerOptions<TValue> {
45
100
  * Callback fired whenever an item is removed from the queuer
46
101
  */
47
102
  onExecute?: (item: TValue, queuer: Queuer<TValue>) => void;
48
- /**
49
- * Callback fired whenever the queuer's running state changes
50
- */
51
- onIsRunningChange?: (queuer: Queuer<TValue>) => void;
52
103
  /**
53
104
  * Callback fired whenever an item is added or removed from the queuer
54
105
  */
@@ -86,7 +137,7 @@ export type QueuePosition = 'front' | 'back';
86
137
  * - Callbacks for queue state changes, execution, rejection, and expiration
87
138
  *
88
139
  * Running behavior:
89
- * - `start()`: Begins automatically processing items in the queue (defaults to running)
140
+ * - `start()`: Begins automatically processing items in the queue (defaults to isRunning)
90
141
  * - `stop()`: Pauses processing but maintains queue state
91
142
  * - `wait`: Configurable delay between processing items
92
143
  * - `onItemsChange`/`onExecute`: Callbacks for monitoring queue state
@@ -115,6 +166,17 @@ export type QueuePosition = 'front' | 'back';
115
166
  * - `getIsExpired`: Function to override default expiration
116
167
  * - `onExpire`: Callback for expired items
117
168
  *
169
+ * State Management:
170
+ * - Uses TanStack Store for reactive state management
171
+ * - Use `initialState` to provide initial state values when creating the queuer
172
+ * - Use `onExecute` callback to react to item execution and implement custom logic
173
+ * - Use `onItemsChange` callback to react to items being added or removed from the queue
174
+ * - Use `onExpire` callback to react to items expiring and implement custom logic
175
+ * - Use `onReject` callback to react to items being rejected when the queue is full
176
+ * - The state includes execution count, expiration count, rejection count, and isRunning status
177
+ * - State can be accessed via `queuer.store.state` when using the class directly
178
+ * - When using framework adapters (React/Solid), state is accessed from `queuer.state`
179
+ *
118
180
  * Example usage:
119
181
  * ```ts
120
182
  * // Auto-processing queue with wait time
@@ -137,56 +199,15 @@ export type QueuePosition = 'front' | 'back';
137
199
  * ```
138
200
  */
139
201
  export declare class Queuer<TValue> {
202
+ #private;
140
203
  private fn;
141
- private _options;
142
- private _items;
143
- private _itemTimestamps;
144
- private _executionCount;
145
- private _rejectionCount;
146
- private _expirationCount;
147
- private _onItemsChanges;
148
- private _running;
149
- private _pendingTick;
204
+ readonly store: Store<Readonly<QueuerState<TValue>>>;
205
+ options: QueuerOptions<TValue>;
150
206
  constructor(fn: (item: TValue) => void, initialOptions?: QueuerOptions<TValue>);
151
207
  /**
152
208
  * Updates the queuer options. New options are merged with existing options.
153
209
  */
154
- setOptions(newOptions: Partial<QueuerOptions<TValue>>): void;
155
- /**
156
- * Returns the current queuer options, including defaults and any overrides.
157
- */
158
- getOptions(): Required<QueuerOptions<TValue>>;
159
- /**
160
- * Returns the current wait time (in milliseconds) between processing items.
161
- * If a function is provided, it is called with the queuer instance.
162
- */
163
- getWait(): number;
164
- /**
165
- * Processes items in the queue up to the wait interval. Internal use only.
166
- */
167
- private tick;
168
- /**
169
- * Checks for expired items in the queue and removes them. Calls onExpire for each expired item.
170
- * Internal use only.
171
- */
172
- private checkExpiredItems;
173
- /**
174
- * Stops processing items in the queue. Does not clear the queue.
175
- */
176
- stop(): void;
177
- /**
178
- * Starts processing items in the queue. If already running, does nothing.
179
- */
180
- start(): void;
181
- /**
182
- * Removes all pending items from the queue. Does not affect items being processed.
183
- */
184
- clear(): void;
185
- /**
186
- * Resets the queuer to its initial state. Optionally repopulates with initial items.
187
- * Does not affect callbacks or options.
188
- */
189
- reset(withInitialItems?: boolean): void;
210
+ setOptions: (newOptions: Partial<QueuerOptions<TValue>>) => void;
190
211
  /**
191
212
  * Adds an item to the queue. If the queue is full, the item is rejected and onReject is called.
192
213
  * Items can be inserted based on priority or at the front/back depending on configuration.
@@ -199,7 +220,7 @@ export declare class Queuer<TValue> {
199
220
  * queuer.addItem('task2', 'front');
200
221
  * ```
201
222
  */
202
- addItem(item: TValue, position?: QueuePosition, runOnUpdate?: boolean): boolean;
223
+ addItem: (item: TValue, position?: QueuePosition, runOnItemsChange?: boolean) => boolean;
203
224
  /**
204
225
  * Removes and returns the next item from the queue without executing the function.
205
226
  * Use for manual queue management. Normally, use execute() to process items.
@@ -212,7 +233,7 @@ export declare class Queuer<TValue> {
212
233
  * queuer.getNextItem('back');
213
234
  * ```
214
235
  */
215
- getNextItem(position?: QueuePosition): TValue | undefined;
236
+ getNextItem: (position?: QueuePosition) => TValue | undefined;
216
237
  /**
217
238
  * Removes and returns the next item from the queue and processes it using the provided function.
218
239
  *
@@ -223,7 +244,12 @@ export declare class Queuer<TValue> {
223
244
  * queuer.execute('back');
224
245
  * ```
225
246
  */
226
- execute(position?: QueuePosition): TValue | undefined;
247
+ execute: (position?: QueuePosition) => TValue | undefined;
248
+ /**
249
+ * Processes a specified number of items to execute immediately with no wait time
250
+ * If no numberOfItems is provided, all items will be processed
251
+ */
252
+ flush: (numberOfItems?: number, position?: QueuePosition) => void;
227
253
  /**
228
254
  * Returns the next item in the queue without removing it.
229
255
  *
@@ -233,52 +259,47 @@ export declare class Queuer<TValue> {
233
259
  * queuer.peekNextItem('back'); // back
234
260
  * ```
235
261
  */
236
- peekNextItem(position?: QueuePosition): TValue | undefined;
237
- /**
238
- * Returns true if the queue is empty (no pending items).
239
- */
240
- getIsEmpty(): boolean;
241
- /**
242
- * Returns true if the queue is full (reached maxSize).
243
- */
244
- getIsFull(): boolean;
245
- /**
246
- * Returns the number of pending items in the queue.
247
- */
248
- getSize(): number;
262
+ peekNextItem: (position?: QueuePosition) => TValue | undefined;
249
263
  /**
250
264
  * Returns a copy of all items in the queue.
251
265
  */
252
- peekAllItems(): Array<TValue>;
253
- /**
254
- * Returns the number of items that have been processed and removed from the queue.
255
- */
256
- getExecutionCount(): number;
266
+ peekAllItems: () => Array<TValue>;
257
267
  /**
258
- * Returns the number of items that have been rejected from being added to the queue.
268
+ * Starts processing items in the queue. If already isRunning, does nothing.
259
269
  */
260
- getRejectionCount(): number;
270
+ start: () => void;
261
271
  /**
262
- * Returns the number of items that have expired and been removed from the queue.
272
+ * Stops processing items in the queue. Does not clear the queue.
263
273
  */
264
- getExpirationCount(): number;
274
+ stop: () => void;
265
275
  /**
266
- * Returns true if the queuer is currently running (processing items).
276
+ * Removes all pending items from the queue. Does not affect items being processed.
267
277
  */
268
- getIsRunning(): boolean;
278
+ clear: () => void;
269
279
  /**
270
- * Returns true if the queuer is running but has no items to process.
280
+ * Resets the queuer state to its default values
271
281
  */
272
- getIsIdle(): boolean;
282
+ reset: () => void;
273
283
  }
274
284
  /**
275
285
  * Creates a queue that processes items immediately upon addition.
276
286
  * Items are processed sequentially in FIFO order by default.
277
287
  *
278
288
  * This is a simplified wrapper around the Queuer class that only exposes the
279
- * `addItem` method. The queue is always running and will process items as they are added.
289
+ * `addItem` method. The queue is always isRunning and will process items as they are added.
280
290
  * For more control over queue processing, use the Queuer class directly.
281
291
  *
292
+ * State Management:
293
+ * - Uses TanStack Store for reactive state management
294
+ * - Use `initialState` to provide initial state values when creating the queuer
295
+ * - Use `onExecute` callback to react to item execution and implement custom logic
296
+ * - Use `onItemsChange` callback to react to items being added or removed from the queue
297
+ * - Use `onExpire` callback to react to items expiring and implement custom logic
298
+ * - Use `onReject` callback to react to items being rejected when the queue is full
299
+ * - The state includes execution count, expiration count, rejection count, and isRunning status
300
+ * - State can be accessed via the underlying Queuer instance's `store.state` property
301
+ * - When using framework adapters (React/Solid), state is accessed from the hook's state property
302
+ *
282
303
  * Example usage:
283
304
  * ```ts
284
305
  * // Basic sequential processing
@@ -297,4 +318,4 @@ export declare class Queuer<TValue> {
297
318
  * processPriority(3); // Processed before 1
298
319
  * ```
299
320
  */
300
- export declare function queue<TValue>(fn: (item: TValue) => void, options: QueuerOptions<TValue>): (item: TValue, position?: QueuePosition, runOnUpdate?: boolean) => boolean;
321
+ export declare function queue<TValue>(fn: (item: TValue) => void, initialOptions: QueuerOptions<TValue>): (item: TValue, position?: QueuePosition, runOnItemsChange?: boolean) => boolean;
@@ -1,154 +1,121 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const store = require("@tanstack/store");
3
4
  const utils = require("./utils.cjs");
5
+ function getDefaultRateLimiterState() {
6
+ return structuredClone({
7
+ executionCount: 0,
8
+ executionTimes: [],
9
+ rejectionCount: 0
10
+ });
11
+ }
4
12
  const defaultOptions = {
5
13
  enabled: true,
6
14
  limit: 1,
7
- onExecute: () => {
8
- },
9
- onReject: () => {
10
- },
11
15
  window: 0,
12
16
  windowType: "fixed"
13
17
  };
14
18
  class RateLimiter {
15
19
  constructor(fn, initialOptions) {
16
20
  this.fn = fn;
17
- this._executionCount = 0;
18
- this._rejectionCount = 0;
19
- this._executionTimes = [];
20
- this._options = {
21
- ...defaultOptions,
22
- ...initialOptions
21
+ this.store = new store.Store(getDefaultRateLimiterState());
22
+ this.setOptions = (newOptions) => {
23
+ this.options = { ...this.options, ...newOptions };
23
24
  };
24
- }
25
- /**
26
- * Updates the rate limiter options
27
- */
28
- setOptions(newOptions) {
29
- this._options = { ...this._options, ...newOptions };
30
- }
31
- /**
32
- * Returns the current rate limiter options
33
- */
34
- getOptions() {
35
- return this._options;
36
- }
37
- /**
38
- * Returns the current enabled state of the rate limiter
39
- */
40
- getEnabled() {
41
- return utils.parseFunctionOrValue(this._options.enabled, this);
42
- }
43
- /**
44
- * Returns the current limit of executions allowed within the time window
45
- */
46
- getLimit() {
47
- return utils.parseFunctionOrValue(this._options.limit, this);
48
- }
49
- /**
50
- * Returns the current time window in milliseconds
51
- */
52
- getWindow() {
53
- return utils.parseFunctionOrValue(this._options.window, this);
54
- }
55
- /**
56
- * Attempts to execute the rate-limited function if within the configured limits.
57
- * Will reject execution if the number of calls in the current window exceeds the limit.
58
- *
59
- * @example
60
- * ```ts
61
- * const rateLimiter = new RateLimiter(fn, { limit: 5, window: 1000 });
62
- *
63
- * // First 5 calls will return true
64
- * rateLimiter.maybeExecute('arg1', 'arg2'); // true
65
- *
66
- * // Additional calls within the window will return false
67
- * rateLimiter.maybeExecute('arg1', 'arg2'); // false
68
- * ```
69
- */
70
- maybeExecute(...args) {
71
- this.cleanupOldExecutions();
72
- if (this._options.windowType === "sliding") {
73
- if (this._executionTimes.length < this.getLimit()) {
74
- this.execute(...args);
25
+ this.#setState = (newState) => {
26
+ this.store.setState((state) => {
27
+ const combinedState = {
28
+ ...state,
29
+ ...newState
30
+ };
31
+ return combinedState;
32
+ });
33
+ };
34
+ this.#getEnabled = () => {
35
+ return !!utils.parseFunctionOrValue(this.options.enabled, this);
36
+ };
37
+ this.#getLimit = () => {
38
+ return utils.parseFunctionOrValue(this.options.limit, this);
39
+ };
40
+ this.#getWindow = () => {
41
+ return utils.parseFunctionOrValue(this.options.window, this);
42
+ };
43
+ this.maybeExecute = (...args) => {
44
+ this.#cleanupOldExecutions();
45
+ const relevantExecutionTimes = this.#getRelevantExecutionTimes();
46
+ if (relevantExecutionTimes.length < this.#getLimit()) {
47
+ this.#execute(...args);
75
48
  return true;
76
49
  }
77
- } else {
50
+ this.#setState({
51
+ rejectionCount: this.store.state.rejectionCount + 1
52
+ });
53
+ this.options.onReject?.(this);
54
+ return false;
55
+ };
56
+ this.#execute = (...args) => {
57
+ if (!this.#getEnabled()) return;
78
58
  const now = Date.now();
79
- const oldestExecution = Math.min(...this._executionTimes);
80
- const isNewWindow = oldestExecution + this.getWindow() <= now;
81
- if (isNewWindow || this._executionTimes.length < this.getLimit()) {
82
- this.execute(...args);
83
- return true;
59
+ this.fn(...args);
60
+ this.store.state.executionTimes.push(now);
61
+ this.#setState({
62
+ executionCount: this.store.state.executionCount + 1
63
+ });
64
+ this.options.onExecute?.(this);
65
+ };
66
+ this.#getRelevantExecutionTimes = () => {
67
+ if (this.options.windowType === "sliding") {
68
+ return this.store.state.executionTimes.filter(
69
+ (time) => time > Date.now() - this.#getWindow()
70
+ );
71
+ } else {
72
+ const oldestExecution = Math.min(...this.store.state.executionTimes);
73
+ const windowStart = oldestExecution;
74
+ return this.store.state.executionTimes.filter(
75
+ (time) => time >= windowStart && time <= windowStart + this.#getWindow()
76
+ );
84
77
  }
85
- }
86
- this.rejectFunction();
87
- return false;
88
- }
89
- execute(...args) {
90
- var _a, _b;
91
- if (!this.getEnabled()) return;
92
- const now = Date.now();
93
- this._executionCount++;
94
- this._executionTimes.push(now);
95
- this.fn(...args);
96
- (_b = (_a = this._options).onExecute) == null ? void 0 : _b.call(_a, this);
97
- }
98
- rejectFunction() {
99
- this._rejectionCount++;
100
- if (this._options.onReject) {
101
- this._options.onReject(this);
102
- }
103
- }
104
- cleanupOldExecutions() {
105
- const now = Date.now();
106
- const windowStart = now - this.getWindow();
107
- this._executionTimes = this._executionTimes.filter(
108
- (time) => time > windowStart
109
- );
110
- }
111
- /**
112
- * Returns the number of times the function has been executed
113
- */
114
- getExecutionCount() {
115
- return this._executionCount;
116
- }
117
- /**
118
- * Returns the number of times the function has been rejected
119
- */
120
- getRejectionCount() {
121
- return this._rejectionCount;
122
- }
123
- /**
124
- * Returns the number of remaining executions allowed in the current window
125
- */
126
- getRemainingInWindow() {
127
- this.cleanupOldExecutions();
128
- return Math.max(0, this.getLimit() - this._executionTimes.length);
129
- }
130
- /**
131
- * Returns the number of milliseconds until the next execution will be possible
132
- */
133
- getMsUntilNextWindow() {
134
- if (this.getRemainingInWindow() > 0) {
135
- return 0;
136
- }
137
- const oldestExecution = Math.min(...this._executionTimes);
138
- return oldestExecution + this.getWindow() - Date.now();
139
- }
140
- /**
141
- * Resets the rate limiter state
142
- */
143
- reset() {
144
- this._executionTimes = [];
145
- this._executionCount = 0;
146
- this._rejectionCount = 0;
78
+ };
79
+ this.#cleanupOldExecutions = () => {
80
+ const now = Date.now();
81
+ const windowStart = now - this.#getWindow();
82
+ this.#setState({
83
+ executionTimes: this.store.state.executionTimes.filter(
84
+ (time) => time > windowStart
85
+ )
86
+ });
87
+ };
88
+ this.getRemainingInWindow = () => {
89
+ const relevantExecutionTimes = this.#getRelevantExecutionTimes();
90
+ return Math.max(0, this.#getLimit() - relevantExecutionTimes.length);
91
+ };
92
+ this.getMsUntilNextWindow = () => {
93
+ if (this.getRemainingInWindow() > 0) {
94
+ return 0;
95
+ }
96
+ const oldestExecution = this.store.state.executionTimes[0] ?? Infinity;
97
+ return oldestExecution + this.#getWindow() - Date.now();
98
+ };
99
+ this.reset = () => {
100
+ this.#setState(getDefaultRateLimiterState());
101
+ };
102
+ this.options = {
103
+ ...defaultOptions,
104
+ ...initialOptions
105
+ };
106
+ this.#setState(this.options.initialState ?? {});
147
107
  }
108
+ #setState;
109
+ #getEnabled;
110
+ #getLimit;
111
+ #getWindow;
112
+ #execute;
113
+ #getRelevantExecutionTimes;
114
+ #cleanupOldExecutions;
148
115
  }
149
116
  function rateLimit(fn, initialOptions) {
150
117
  const rateLimiter = new RateLimiter(fn, initialOptions);
151
- return rateLimiter.maybeExecute.bind(rateLimiter);
118
+ return rateLimiter.maybeExecute;
152
119
  }
153
120
  exports.RateLimiter = RateLimiter;
154
121
  exports.rateLimit = rateLimit;