@common.js/p-queue 8.0.1 → 9.3.2

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.
package/dist/options.d.ts CHANGED
@@ -1,15 +1,26 @@
1
1
  import { type Queue, type RunFunction } from './queue.js';
2
2
  type TimeoutOptions = {
3
3
  /**
4
- Per-operation timeout in milliseconds. Operations fulfill once `timeout` elapses if they haven't already.
5
- */
6
- timeout?: number;
7
- /**
8
- Whether or not a timeout is considered an exception.
4
+ Per-operation timeout in milliseconds. Operations will throw a `TimeoutError` if they don't complete within the specified time.
9
5
 
10
- @default false
6
+ The timeout begins when the operation is dequeued and starts execution, not while it's waiting in the queue.
7
+
8
+ @default undefined
9
+
10
+ Can be overridden per task using the `timeout` option in `.add()`:
11
+
12
+ @example
13
+ ```
14
+ const queue = new PQueue({timeout: 5000});
15
+
16
+ // This task uses the global 5s timeout
17
+ await queue.add(() => fetchData());
18
+
19
+ // This task has a 10s timeout
20
+ await queue.add(() => slowTask(), {timeout: 10000});
21
+ ```
11
22
  */
12
- throwOnTimeout?: boolean;
23
+ timeout?: number;
13
24
  };
14
25
  export type Options<QueueType extends Queue<RunFunction, QueueOptions>, QueueOptions extends QueueAddOptions> = {
15
26
  /**
@@ -21,7 +32,7 @@ export type Options<QueueType extends Queue<RunFunction, QueueOptions>, QueueOpt
21
32
  */
22
33
  readonly concurrency?: number;
23
34
  /**
24
- Whether queue tasks within concurrency limit, are auto-executed as soon as they're added.
35
+ Whether queue tasks within the concurrency limit are auto-executed as soon as they're added.
25
36
 
26
37
  @default true
27
38
  */
@@ -51,7 +62,27 @@ export type Options<QueueType extends Queue<RunFunction, QueueOptions>, QueueOpt
51
62
 
52
63
  @default false
53
64
  */
65
+ readonly carryoverIntervalCount?: boolean;
66
+ /**
67
+ @deprecated Renamed to `carryoverIntervalCount`.
68
+ */
54
69
  readonly carryoverConcurrencyCount?: boolean;
70
+ /**
71
+ Whether to use strict mode for rate limiting (sliding window algorithm).
72
+
73
+ When enabled, ensures that no more than `intervalCap` tasks execute in any rolling `interval` window, rather than resetting the count at fixed intervals. This provides more predictable and evenly distributed execution.
74
+
75
+ @default false
76
+
77
+ For example, with `intervalCap: 2` and `interval: 1000`:
78
+ - __Default mode (fixed window)__: Tasks can burst at window boundaries. You could execute 2 tasks at 999ms and 2 more at 1000ms, resulting in 4 tasks within 1ms.
79
+ - __Strict mode (sliding window)__: Enforces that no more than 2 tasks execute in any 1000ms rolling window, preventing bursts.
80
+
81
+ Strict mode is more resource-intensive as it tracks individual execution timestamps. Use it when you need guaranteed rate-limit compliance, such as when interacting with APIs that enforce strict rate limits.
82
+
83
+ The `carryoverIntervalCount` option has no effect when `strict` mode is enabled, as strict mode tracks actual execution timestamps rather than counting pending tasks.
84
+ */
85
+ readonly strict?: boolean;
55
86
  } & TimeoutOptions;
56
87
  export type QueueAddOptions = {
57
88
  /**
@@ -60,6 +91,10 @@ export type QueueAddOptions = {
60
91
  @default 0
61
92
  */
62
93
  readonly priority?: number;
94
+ /**
95
+ Unique identifier for the promise function, used to update its priority before execution. If not specified, it is auto-assigned an incrementing BigInt starting from `1n`.
96
+ */
97
+ id?: string;
63
98
  } & TaskOptions & TimeoutOptions;
64
99
  export type TaskOptions = {
65
100
  /**
@@ -97,6 +132,6 @@ export type TaskOptions = {
97
132
  }
98
133
  ```
99
134
  */
100
- readonly signal?: AbortSignal;
135
+ readonly signal?: AbortSignal | undefined;
101
136
  };
102
137
  export {};
@@ -6,6 +6,9 @@ export type PriorityQueueOptions = {
6
6
  export default class PriorityQueue implements Queue<RunFunction, PriorityQueueOptions> {
7
7
  #private;
8
8
  enqueue(run: RunFunction, options?: Partial<PriorityQueueOptions>): void;
9
+ setPriority(id: string, priority: number): void;
10
+ remove(id: string): void;
11
+ remove(run: RunFunction): void;
9
12
  dequeue(): RunFunction | undefined;
10
13
  filter(options: Readonly<Partial<PriorityQueueOptions>>): RunFunction[];
11
14
  get size(): number;
@@ -9,6 +9,14 @@ Object.defineProperty(exports, "default", {
9
9
  }
10
10
  });
11
11
  var _lowerBoundJs = /*#__PURE__*/ _interopRequireDefault(require("./lower-bound.js"));
12
+ function _arrayLikeToArray(arr, len) {
13
+ if (len == null || len > arr.length) len = arr.length;
14
+ for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
15
+ return arr2;
16
+ }
17
+ function _arrayWithHoles(arr) {
18
+ if (Array.isArray(arr)) return arr;
19
+ }
12
20
  function _checkPrivateRedeclaration(obj, privateCollection) {
13
21
  if (privateCollection.has(obj)) {
14
22
  throw new TypeError("Cannot initialize the same private elements twice on an object");
@@ -20,6 +28,36 @@ function _classApplyDescriptorGet(receiver, descriptor) {
20
28
  }
21
29
  return descriptor.value;
22
30
  }
31
+ function _classApplyDescriptorSet(receiver, descriptor, value) {
32
+ if (descriptor.set) {
33
+ descriptor.set.call(receiver, value);
34
+ } else {
35
+ if (!descriptor.writable) {
36
+ throw new TypeError("attempted to set read only private field");
37
+ }
38
+ descriptor.value = value;
39
+ }
40
+ }
41
+ function _classApplyDescriptorUpdate(receiver, descriptor) {
42
+ if (descriptor.set) {
43
+ if (!("__destrWrapper" in descriptor)) {
44
+ descriptor.__destrWrapper = {
45
+ set value (v){
46
+ descriptor.set.call(receiver, v);
47
+ },
48
+ get value () {
49
+ return descriptor.get.call(receiver);
50
+ }
51
+ };
52
+ }
53
+ return descriptor.__destrWrapper;
54
+ } else {
55
+ if (!descriptor.writable) {
56
+ throw new TypeError("attempted to set read only private field");
57
+ }
58
+ return descriptor;
59
+ }
60
+ }
23
61
  function _classCallCheck(instance, Constructor) {
24
62
  if (!(instance instanceof Constructor)) {
25
63
  throw new TypeError("Cannot call a class as a function");
@@ -39,6 +77,25 @@ function _classPrivateFieldInit(obj, privateMap, value) {
39
77
  _checkPrivateRedeclaration(obj, privateMap);
40
78
  privateMap.set(obj, value);
41
79
  }
80
+ function _classPrivateFieldSet(receiver, privateMap, value) {
81
+ var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "set");
82
+ _classApplyDescriptorSet(receiver, descriptor, value);
83
+ return value;
84
+ }
85
+ function _classPrivateFieldUpdate(receiver, privateMap) {
86
+ var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "update");
87
+ return _classApplyDescriptorUpdate(receiver, descriptor);
88
+ }
89
+ function _classPrivateMethodGet(receiver, privateSet, fn) {
90
+ if (!privateSet.has(receiver)) {
91
+ throw new TypeError("attempted to get private field on non-instance");
92
+ }
93
+ return fn;
94
+ }
95
+ function _classPrivateMethodInit(obj, privateSet) {
96
+ _checkPrivateRedeclaration(obj, privateSet);
97
+ privateSet.add(obj);
98
+ }
42
99
  function _defineProperties(target, props) {
43
100
  for(var i = 0; i < props.length; i++){
44
101
  var descriptor = props[i];
@@ -53,93 +110,180 @@ function _createClass(Constructor, protoProps, staticProps) {
53
110
  if (staticProps) _defineProperties(Constructor, staticProps);
54
111
  return Constructor;
55
112
  }
56
- function _defineProperty(obj, key, value) {
57
- if (key in obj) {
58
- Object.defineProperty(obj, key, {
59
- value: value,
60
- enumerable: true,
61
- configurable: true,
62
- writable: true
63
- });
64
- } else {
65
- obj[key] = value;
66
- }
67
- return obj;
68
- }
69
113
  function _interopRequireDefault(obj) {
70
114
  return obj && obj.__esModule ? obj : {
71
115
  default: obj
72
116
  };
73
117
  }
74
- function _objectSpread(target) {
75
- for(var i = 1; i < arguments.length; i++){
76
- var source = arguments[i] != null ? arguments[i] : {};
77
- var ownKeys = Object.keys(source);
78
- if (typeof Object.getOwnPropertySymbols === "function") {
79
- ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
80
- return Object.getOwnPropertyDescriptor(source, sym).enumerable;
81
- }));
118
+ function _iterableToArrayLimit(arr, i) {
119
+ var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"];
120
+ if (_i == null) return;
121
+ var _arr = [];
122
+ var _n = true;
123
+ var _d = false;
124
+ var _s, _e;
125
+ try {
126
+ for(_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true){
127
+ _arr.push(_s.value);
128
+ if (i && _arr.length === i) break;
129
+ }
130
+ } catch (err) {
131
+ _d = true;
132
+ _e = err;
133
+ } finally{
134
+ try {
135
+ if (!_n && _i["return"] != null) _i["return"]();
136
+ } finally{
137
+ if (_d) throw _e;
82
138
  }
83
- ownKeys.forEach(function(key) {
84
- _defineProperty(target, key, source[key]);
85
- });
86
139
  }
87
- return target;
140
+ return _arr;
141
+ }
142
+ function _nonIterableRest() {
143
+ throw new TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
88
144
  }
89
- var _queue = /*#__PURE__*/ new WeakMap();
145
+ function _slicedToArray(arr, i) {
146
+ return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest();
147
+ }
148
+ function _unsupportedIterableToArray(o, minLen) {
149
+ if (!o) return;
150
+ if (typeof o === "string") return _arrayLikeToArray(o, minLen);
151
+ var n = Object.prototype.toString.call(o).slice(8, -1);
152
+ if (n === "Object" && o.constructor) n = o.constructor.name;
153
+ if (n === "Map" || n === "Set") return Array.from(n);
154
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
155
+ }
156
+ var compactionThreshold = 100;
157
+ var _queue = /*#__PURE__*/ new WeakMap(), // The queue is stored as a sorted array, but dequeued items are left before `#head` until compaction. Only items from `#head` onward are live, which keeps repeated dequeues amortized O(1).
158
+ _head = /*#__PURE__*/ new WeakMap(), _compact = /*#__PURE__*/ new WeakSet();
90
159
  var PriorityQueue = /*#__PURE__*/ function() {
91
160
  "use strict";
92
161
  function PriorityQueue() {
93
162
  _classCallCheck(this, PriorityQueue);
163
+ _classPrivateMethodInit(this, _compact);
94
164
  _classPrivateFieldInit(this, _queue, {
95
165
  writable: true,
96
166
  value: []
97
167
  });
168
+ _classPrivateFieldInit(this, _head, {
169
+ writable: true,
170
+ value: 0
171
+ });
98
172
  }
99
173
  _createClass(PriorityQueue, [
100
174
  {
101
175
  key: "enqueue",
102
176
  value: function enqueue(run, options) {
103
- options = _objectSpread({
104
- priority: 0
105
- }, options);
177
+ var ref = options !== null && options !== void 0 ? options : {}, _priority = ref.priority, priority = _priority === void 0 ? 0 : _priority, id = ref.id;
178
+ var size = this.size;
106
179
  var element = {
107
- priority: options.priority,
180
+ priority: priority,
181
+ id: id,
108
182
  run: run
109
183
  };
110
- if (this.size && _classPrivateFieldGet(this, _queue)[this.size - 1].priority >= options.priority) {
184
+ if (size === 0) {
185
+ // When the queue is logically empty, discard any consumed prefix before accepting new work.
186
+ _classPrivateFieldGet(this, _queue).length = 0;
187
+ _classPrivateFieldSet(this, _head, 0);
188
+ _classPrivateFieldGet(this, _queue).push(element);
189
+ return;
190
+ }
191
+ if (_classPrivateFieldGet(this, _queue).at(-1).priority >= priority) {
192
+ // Same-priority and lower-priority items belong after the current tail. Appending preserves FIFO order for equal priorities.
111
193
  _classPrivateFieldGet(this, _queue).push(element);
112
194
  return;
113
195
  }
196
+ // Binary insertion must run on the live sorted range only.
197
+ _classPrivateMethodGet(this, _compact, compact).call(this);
114
198
  var index = (0, _lowerBoundJs.default)(_classPrivateFieldGet(this, _queue), element, function(a, b) {
115
199
  return b.priority - a.priority;
116
200
  });
117
201
  _classPrivateFieldGet(this, _queue).splice(index, 0, element);
118
202
  }
119
203
  },
204
+ {
205
+ key: "setPriority",
206
+ value: function setPriority(id, priority) {
207
+ var _this = this;
208
+ // A dequeued item with the same id is no longer part of the queue.
209
+ var index = _classPrivateFieldGet(this, _queue).findIndex(function(element, index) {
210
+ return index >= _classPrivateFieldGet(_this, _head) && element.id === id;
211
+ });
212
+ if (index === -1) {
213
+ throw new ReferenceError('No promise function with the id "'.concat(id, '" exists in the queue.'));
214
+ }
215
+ var ref = _slicedToArray(_classPrivateFieldGet(this, _queue).splice(index, 1), 1), item = ref[0];
216
+ this.enqueue(item.run, {
217
+ priority: priority,
218
+ id: id
219
+ });
220
+ }
221
+ },
222
+ {
223
+ key: "remove",
224
+ value: function remove(idOrRun) {
225
+ var _this = this;
226
+ var index = _classPrivateFieldGet(this, _queue).findIndex(function(element, index) {
227
+ // The consumed prefix may still contain references that should not be removable.
228
+ if (index < _classPrivateFieldGet(_this, _head)) {
229
+ return false;
230
+ }
231
+ if (typeof idOrRun === "string") {
232
+ return element.id === idOrRun;
233
+ }
234
+ return element.run === idOrRun;
235
+ });
236
+ if (index !== -1) {
237
+ _classPrivateFieldGet(this, _queue).splice(index, 1);
238
+ }
239
+ }
240
+ },
120
241
  {
121
242
  key: "dequeue",
122
243
  value: function dequeue() {
123
- var item = _classPrivateFieldGet(this, _queue).shift();
244
+ if (_classPrivateFieldGet(this, _head) === _classPrivateFieldGet(this, _queue).length) {
245
+ return undefined;
246
+ }
247
+ var item = _classPrivateFieldGet(this, _queue)[_classPrivateFieldGet(this, _head)];
248
+ _classPrivateFieldUpdate(this, _head).value++;
249
+ if (_classPrivateFieldGet(this, _head) === _classPrivateFieldGet(this, _queue).length) {
250
+ // Fully drained queues are reset immediately so the next enqueue starts from a clean array.
251
+ _classPrivateFieldGet(this, _queue).length = 0;
252
+ _classPrivateFieldSet(this, _head, 0);
253
+ } else if (_classPrivateFieldGet(this, _head) > compactionThreshold && _classPrivateFieldGet(this, _head) > _classPrivateFieldGet(this, _queue).length / 2) {
254
+ // Keep repeated dequeues cheap, but stop the consumed prefix from growing without bound.
255
+ _classPrivateMethodGet(this, _compact, compact).call(this);
256
+ }
124
257
  return item === null || item === void 0 ? void 0 : item.run;
125
258
  }
126
259
  },
127
260
  {
128
261
  key: "filter",
129
262
  value: function filter(options) {
130
- return _classPrivateFieldGet(this, _queue).filter(function(element) {
131
- return element.priority === options.priority;
132
- }).map(function(element) {
133
- return element.run;
134
- });
263
+ var result = [];
264
+ for(var index = _classPrivateFieldGet(this, _head); index < _classPrivateFieldGet(this, _queue).length; index++){
265
+ var element = _classPrivateFieldGet(this, _queue)[index];
266
+ if (element.priority === options.priority) {
267
+ result.push(element.run);
268
+ }
269
+ }
270
+ return result;
135
271
  }
136
272
  },
137
273
  {
138
274
  key: "size",
139
275
  get: function get() {
140
- return _classPrivateFieldGet(this, _queue).length;
276
+ return _classPrivateFieldGet(this, _queue).length - _classPrivateFieldGet(this, _head);
141
277
  }
142
278
  }
143
279
  ]);
144
280
  return PriorityQueue;
145
281
  }();
282
+ function compact() {
283
+ // Compaction restores the invariant that the whole array is the live sorted range.
284
+ if (_classPrivateFieldGet(this, _head) === 0) {
285
+ return;
286
+ }
287
+ _classPrivateFieldGet(this, _queue).splice(0, _classPrivateFieldGet(this, _head));
288
+ _classPrivateFieldSet(this, _head, 0);
289
+ }
package/dist/queue.d.ts CHANGED
@@ -4,4 +4,6 @@ export type Queue<Element, Options> = {
4
4
  filter: (options: Readonly<Partial<Options>>) => Element[];
5
5
  dequeue: () => Element | undefined;
6
6
  enqueue: (run: Element, options?: Partial<Options>) => void;
7
+ setPriority: (id: string, priority: number) => void;
8
+ remove?: (id: string) => void;
7
9
  };
package/package.json CHANGED
@@ -1,18 +1,22 @@
1
1
  {
2
2
  "name": "@common.js/p-queue",
3
- "version": "8.0.1",
3
+ "version": "9.3.2",
4
4
  "description": "p-queue package exported as CommonJS modules",
5
5
  "license": "MIT",
6
6
  "repository": "etienne-martin/common.js",
7
7
  "funding": "https://github.com/sponsors/sindresorhus",
8
8
  "type": "commonjs",
9
+ "exports": {
10
+ "types": "./dist/index.d.ts",
11
+ "default": "./dist/index.js"
12
+ },
9
13
  "sideEffects": false,
10
14
  "engines": {
11
- "node": ">=18"
15
+ "node": ">=20"
12
16
  },
13
17
  "scripts": {
14
18
  "build": "del-cli dist && tsc",
15
- "test": "xo && ava && del-cli dist && tsc && tsd",
19
+ "test": "xo && node --import=tsx/esm --test test/*.ts && del-cli dist && tsc && tsd",
16
20
  "bench": "node --import=tsx/esm bench.ts"
17
21
  },
18
22
  "files": [
@@ -20,45 +24,45 @@
20
24
  ],
21
25
  "types": "./dist/index.d.ts",
22
26
  "dependencies": {
23
- "eventemitter3": "^5.0.1",
24
- "@common.js/p-timeout": "^6.1.2"
27
+ "eventemitter3": "^5.0.4",
28
+ "p-timeout": "npm:@common.js/p-timeout@7.0.2"
25
29
  },
26
30
  "devDependencies": {
27
- "@sindresorhus/tsconfig": "^5.0.0",
31
+ "@sindresorhus/tsconfig": "^8.0.1",
28
32
  "@types/benchmark": "^2.1.5",
29
- "@types/node": "^20.10.4",
30
- "ava": "^5.3.1",
33
+ "@types/node": "^25.6.0",
31
34
  "benchmark": "^2.1.4",
32
- "del-cli": "^5.1.0",
35
+ "del-cli": "^6.0.0",
33
36
  "delay": "^6.0.0",
34
37
  "in-range": "^3.0.0",
35
- "p-defer": "^4.0.0",
36
- "random-int": "^3.0.0",
38
+ "p-defer": "^4.0.1",
39
+ "random-int": "^3.1.0",
37
40
  "time-span": "^5.1.0",
38
- "tsd": "^0.29.0",
39
- "tsx": "^4.6.2",
40
- "typescript": "^5.3.3",
41
- "xo": "^0.56.0"
42
- },
43
- "ava": {
44
- "workerThreads": false,
45
- "files": [
46
- "test/**"
47
- ],
48
- "extensions": {
49
- "ts": "module"
50
- },
51
- "nodeArguments": [
52
- "--import=tsx/esm"
53
- ]
41
+ "tsd": "^0.33.0",
42
+ "tsx": "^4.20.5",
43
+ "typescript": "^5.9.2",
44
+ "xo": "^1.2.2"
54
45
  },
55
46
  "xo": {
56
47
  "rules": {
57
48
  "@typescript-eslint/member-ordering": "off",
58
49
  "@typescript-eslint/no-floating-promises": "off",
59
- "@typescript-eslint/no-invalid-void-type": "off"
50
+ "@typescript-eslint/no-unsafe-call": "off",
51
+ "@typescript-eslint/no-unsafe-assignment": "off",
52
+ "@typescript-eslint/no-unsafe-return": "off",
53
+ "@typescript-eslint/no-unsafe-argument": "off",
54
+ "@typescript-eslint/prefer-promise-reject-errors": "off",
55
+ "ava/no-import-test-files": "off"
60
56
  }
61
57
  },
62
58
  "homepage": "https://github.com/etienne-martin/common.js#readme",
59
+ "commonjs": {
60
+ "source": {
61
+ "name": "p-queue",
62
+ "version": "9.3.1"
63
+ },
64
+ "transformRevision": 1,
65
+ "buildKey": "1c5a0547a6fb30fb020261462496d5e23236d4c736fb264264b7d89ccf4319c3"
66
+ },
63
67
  "main": "./dist/index.js"
64
68
  }