@chainlink/external-adapter-framework 2.10.0 → 2.11.1

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 (32) hide show
  1. package/README.md +1 -1
  2. package/adapter/market-status.d.ts +6 -0
  3. package/adapter/market-status.js +22 -0
  4. package/adapter/market-status.js.map +1 -1
  5. package/config/index.js +1 -1
  6. package/generator-adapter/node_modules/.yarn-integrity +8 -8
  7. package/generator-adapter/node_modules/@types/node/README.md +1 -1
  8. package/generator-adapter/node_modules/@types/node/package.json +2 -2
  9. package/generator-adapter/node_modules/@types/node/process.d.ts +7 -0
  10. package/generator-adapter/node_modules/@yeoman/adapter/dist/queued-adapter.js +1 -3
  11. package/generator-adapter/node_modules/@yeoman/adapter/dist/queued-adapter.js.map +1 -1
  12. package/generator-adapter/node_modules/@yeoman/adapter/package.json +3 -3
  13. package/generator-adapter/node_modules/@yeoman/types/package.json +3 -3
  14. package/generator-adapter/node_modules/p-queue/dist/index.d.ts +181 -11
  15. package/generator-adapter/node_modules/p-queue/dist/index.js +366 -45
  16. package/generator-adapter/node_modules/p-queue/dist/options copy.d.ts +121 -0
  17. package/generator-adapter/node_modules/p-queue/dist/options copy.js +1 -0
  18. package/generator-adapter/node_modules/p-queue/dist/options.d.ts +26 -7
  19. package/generator-adapter/node_modules/p-queue/dist/priority-queue.d.ts +1 -0
  20. package/generator-adapter/node_modules/p-queue/dist/priority-queue.js +12 -6
  21. package/generator-adapter/node_modules/p-queue/dist/queue.d.ts +1 -0
  22. package/generator-adapter/node_modules/p-queue/package.json +19 -27
  23. package/generator-adapter/node_modules/p-queue/readme.md +541 -19
  24. package/generator-adapter/node_modules/p-timeout/index.d.ts +2 -4
  25. package/generator-adapter/node_modules/p-timeout/index.js +23 -50
  26. package/generator-adapter/node_modules/p-timeout/package.json +11 -9
  27. package/generator-adapter/node_modules/p-timeout/readme.md +11 -9
  28. package/generator-adapter/package.json +3 -3
  29. package/package.json +8 -7
  30. package/validation/market-status.d.ts +6 -0
  31. package/validation/market-status.js +69 -0
  32. package/validation/market-status.js.map +1 -0
@@ -1,16 +1,19 @@
1
1
  import { EventEmitter } from 'eventemitter3';
2
- import pTimeout, { TimeoutError } from 'p-timeout';
2
+ import pTimeout from 'p-timeout';
3
3
  import PriorityQueue from './priority-queue.js';
4
4
  /**
5
5
  Promise queue with concurrency control.
6
6
  */
7
7
  export default class PQueue extends EventEmitter {
8
- #carryoverConcurrencyCount;
8
+ #carryoverIntervalCount;
9
9
  #isIntervalIgnored;
10
10
  #intervalCount = 0;
11
11
  #intervalCap;
12
+ #rateLimitedInInterval = false;
13
+ #rateLimitFlushScheduled = false;
12
14
  #interval;
13
15
  #intervalEnd = 0;
16
+ #lastExecutionTime = 0;
14
17
  #intervalId;
15
18
  #timeoutId;
16
19
  #queue;
@@ -19,19 +22,31 @@ export default class PQueue extends EventEmitter {
19
22
  // The `!` is needed because of https://github.com/microsoft/TypeScript/issues/32194
20
23
  #concurrency;
21
24
  #isPaused;
22
- #throwOnTimeout;
25
+ // Use to assign a unique identifier to a promise function, if not explicitly specified
26
+ #idAssigner = 1n;
27
+ // Track currently running tasks for debugging
28
+ #runningTasks = new Map();
23
29
  /**
24
- Per-operation timeout in milliseconds. Operations fulfill once `timeout` elapses if they haven't already.
30
+ Get or set the default timeout for all tasks. Can be changed at runtime.
25
31
 
26
- Applies to each future operation.
32
+ Operations will throw a `TimeoutError` if they don't complete within the specified time.
33
+
34
+ The timeout begins when the operation is dequeued and starts execution, not while it's waiting in the queue.
35
+
36
+ @example
37
+ ```
38
+ const queue = new PQueue({timeout: 5000});
39
+
40
+ // Change timeout for all future tasks
41
+ queue.timeout = 10000;
42
+ ```
27
43
  */
28
44
  timeout;
29
- // TODO: The `throwOnTimeout` option should affect the return types of `add()` and `addAll()`
30
45
  constructor(options) {
31
46
  super();
32
47
  // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
33
48
  options = {
34
- carryoverConcurrencyCount: false,
49
+ carryoverIntervalCount: false,
35
50
  intervalCap: Number.POSITIVE_INFINITY,
36
51
  interval: 0,
37
52
  concurrency: Number.POSITIVE_INFINITY,
@@ -45,16 +60,21 @@ export default class PQueue extends EventEmitter {
45
60
  if (options.interval === undefined || !(Number.isFinite(options.interval) && options.interval >= 0)) {
46
61
  throw new TypeError(`Expected \`interval\` to be a finite number >= 0, got \`${options.interval?.toString() ?? ''}\` (${typeof options.interval})`);
47
62
  }
48
- this.#carryoverConcurrencyCount = options.carryoverConcurrencyCount;
63
+ // TODO: Remove this fallback in the next major version
64
+ // eslint-disable-next-line @typescript-eslint/no-deprecated
65
+ this.#carryoverIntervalCount = options.carryoverIntervalCount ?? options.carryoverConcurrencyCount ?? false;
49
66
  this.#isIntervalIgnored = options.intervalCap === Number.POSITIVE_INFINITY || options.interval === 0;
50
67
  this.#intervalCap = options.intervalCap;
51
68
  this.#interval = options.interval;
52
69
  this.#queue = new options.queueClass();
53
70
  this.#queueClass = options.queueClass;
54
71
  this.concurrency = options.concurrency;
72
+ if (options.timeout !== undefined && !(Number.isFinite(options.timeout) && options.timeout > 0)) {
73
+ throw new TypeError(`Expected \`timeout\` to be a positive finite number, got \`${options.timeout}\` (${typeof options.timeout})`);
74
+ }
55
75
  this.timeout = options.timeout;
56
- this.#throwOnTimeout = options.throwOnTimeout === true;
57
76
  this.#isPaused = options.autoStart === false;
77
+ this.#setupRateLimitTracking();
58
78
  }
59
79
  get #doesIntervalAllowAnother() {
60
80
  return this.#isIntervalIgnored || this.#intervalCount < this.#intervalCap;
@@ -64,11 +84,14 @@ export default class PQueue extends EventEmitter {
64
84
  }
65
85
  #next() {
66
86
  this.#pending--;
87
+ if (this.#pending === 0) {
88
+ this.emit('pendingZero');
89
+ }
67
90
  this.#tryToStartAnother();
68
91
  this.emit('next');
69
92
  }
70
93
  #onResumeInterval() {
71
- this.#onInterval();
94
+ this.#onInterval(); // Already schedules update
72
95
  this.#initializeIntervalIfNeeded();
73
96
  this.#timeoutId = undefined;
74
97
  }
@@ -77,52 +100,81 @@ export default class PQueue extends EventEmitter {
77
100
  if (this.#intervalId === undefined) {
78
101
  const delay = this.#intervalEnd - now;
79
102
  if (delay < 0) {
80
- // Act as the interval was done
81
- // We don't need to resume it here because it will be resumed on line 160
82
- this.#intervalCount = (this.#carryoverConcurrencyCount) ? this.#pending : 0;
103
+ // If the interval has expired while idle, check if we should enforce the interval
104
+ // from the last task execution. This ensures proper spacing between tasks even
105
+ // when the queue becomes empty and then new tasks are added.
106
+ if (this.#lastExecutionTime > 0) {
107
+ const timeSinceLastExecution = now - this.#lastExecutionTime;
108
+ if (timeSinceLastExecution < this.#interval) {
109
+ // Not enough time has passed since the last task execution
110
+ this.#createIntervalTimeout(this.#interval - timeSinceLastExecution);
111
+ return true;
112
+ }
113
+ }
114
+ // Enough time has passed or no previous execution, allow execution
115
+ this.#intervalCount = (this.#carryoverIntervalCount) ? this.#pending : 0;
83
116
  }
84
117
  else {
85
118
  // Act as the interval is pending
86
- if (this.#timeoutId === undefined) {
87
- this.#timeoutId = setTimeout(() => {
88
- this.#onResumeInterval();
89
- }, delay);
90
- }
119
+ this.#createIntervalTimeout(delay);
91
120
  return true;
92
121
  }
93
122
  }
94
123
  return false;
95
124
  }
125
+ #createIntervalTimeout(delay) {
126
+ if (this.#timeoutId !== undefined) {
127
+ return;
128
+ }
129
+ this.#timeoutId = setTimeout(() => {
130
+ this.#onResumeInterval();
131
+ }, delay);
132
+ }
133
+ #clearIntervalTimer() {
134
+ if (this.#intervalId) {
135
+ clearInterval(this.#intervalId);
136
+ this.#intervalId = undefined;
137
+ }
138
+ }
139
+ #clearTimeoutTimer() {
140
+ if (this.#timeoutId) {
141
+ clearTimeout(this.#timeoutId);
142
+ this.#timeoutId = undefined;
143
+ }
144
+ }
96
145
  #tryToStartAnother() {
97
146
  if (this.#queue.size === 0) {
98
147
  // We can clear the interval ("pause")
99
148
  // Because we can redo it later ("resume")
100
- if (this.#intervalId) {
101
- clearInterval(this.#intervalId);
102
- }
103
- this.#intervalId = undefined;
149
+ this.#clearIntervalTimer();
104
150
  this.emit('empty');
105
151
  if (this.#pending === 0) {
152
+ // Clear timeout as well when completely idle
153
+ this.#clearTimeoutTimer();
106
154
  this.emit('idle');
107
155
  }
108
156
  return false;
109
157
  }
158
+ let taskStarted = false;
110
159
  if (!this.#isPaused) {
111
160
  const canInitializeInterval = !this.#isIntervalPaused;
112
161
  if (this.#doesIntervalAllowAnother && this.#doesConcurrentAllowAnother) {
113
162
  const job = this.#queue.dequeue();
114
- if (!job) {
115
- return false;
163
+ // Increment interval count immediately to prevent race conditions
164
+ if (!this.#isIntervalIgnored) {
165
+ this.#intervalCount++;
166
+ this.#scheduleRateLimitUpdate();
116
167
  }
117
168
  this.emit('active');
169
+ this.#lastExecutionTime = Date.now();
118
170
  job();
119
171
  if (canInitializeInterval) {
120
172
  this.#initializeIntervalIfNeeded();
121
173
  }
122
- return true;
174
+ taskStarted = true;
123
175
  }
124
176
  }
125
- return false;
177
+ return taskStarted;
126
178
  }
127
179
  #initializeIntervalIfNeeded() {
128
180
  if (this.#isIntervalIgnored || this.#intervalId !== undefined) {
@@ -135,11 +187,11 @@ export default class PQueue extends EventEmitter {
135
187
  }
136
188
  #onInterval() {
137
189
  if (this.#intervalCount === 0 && this.#pending === 0 && this.#intervalId) {
138
- clearInterval(this.#intervalId);
139
- this.#intervalId = undefined;
190
+ this.#clearIntervalTimer();
140
191
  }
141
- this.#intervalCount = this.#carryoverConcurrencyCount ? this.#pending : 0;
192
+ this.#intervalCount = this.#carryoverIntervalCount ? this.#pending : 0;
142
193
  this.#processQueue();
194
+ this.#scheduleRateLimitUpdate();
143
195
  }
144
196
  /**
145
197
  Executes all queued functions until it reaches the limit.
@@ -158,46 +210,118 @@ export default class PQueue extends EventEmitter {
158
210
  this.#concurrency = newConcurrency;
159
211
  this.#processQueue();
160
212
  }
161
- async #throwOnAbort(signal) {
162
- return new Promise((_resolve, reject) => {
163
- signal.addEventListener('abort', () => {
164
- reject(signal.reason);
165
- }, { once: true });
166
- });
213
+ /**
214
+ Updates the priority of a promise function by its id, affecting its execution order. Requires a defined concurrency limit to take effect.
215
+
216
+ For example, this can be used to prioritize a promise function to run earlier.
217
+
218
+ ```js
219
+ import PQueue from 'p-queue';
220
+
221
+ const queue = new PQueue({concurrency: 1});
222
+
223
+ queue.add(async () => '🦄', {priority: 1});
224
+ queue.add(async () => '🦀', {priority: 0, id: '🦀'});
225
+ queue.add(async () => '🦄', {priority: 1});
226
+ queue.add(async () => '🦄', {priority: 1});
227
+
228
+ queue.setPriority('🦀', 2);
229
+ ```
230
+
231
+ In this case, the promise function with `id: '🦀'` runs second.
232
+
233
+ You can also deprioritize a promise function to delay its execution:
234
+
235
+ ```js
236
+ import PQueue from 'p-queue';
237
+
238
+ const queue = new PQueue({concurrency: 1});
239
+
240
+ queue.add(async () => '🦄', {priority: 1});
241
+ queue.add(async () => '🦀', {priority: 1, id: '🦀'});
242
+ queue.add(async () => '🦄');
243
+ queue.add(async () => '🦄', {priority: 0});
244
+
245
+ queue.setPriority('🦀', -1);
246
+ ```
247
+ Here, the promise function with `id: '🦀'` executes last.
248
+ */
249
+ setPriority(id, priority) {
250
+ if (typeof priority !== 'number' || !Number.isFinite(priority)) {
251
+ throw new TypeError(`Expected \`priority\` to be a finite number, got \`${priority}\` (${typeof priority})`);
252
+ }
253
+ this.#queue.setPriority(id, priority);
167
254
  }
168
255
  async add(function_, options = {}) {
256
+ // In case `id` is not defined.
257
+ options.id ??= (this.#idAssigner++).toString();
169
258
  options = {
170
259
  timeout: this.timeout,
171
- throwOnTimeout: this.#throwOnTimeout,
172
260
  ...options,
173
261
  };
174
262
  return new Promise((resolve, reject) => {
263
+ // Create a unique symbol for tracking this task
264
+ const taskSymbol = Symbol(`task-${options.id}`);
175
265
  this.#queue.enqueue(async () => {
176
266
  this.#pending++;
177
- this.#intervalCount++;
267
+ // Track this running task
268
+ this.#runningTasks.set(taskSymbol, {
269
+ id: options.id,
270
+ priority: options.priority ?? 0, // Match priority-queue default
271
+ startTime: Date.now(),
272
+ timeout: options.timeout,
273
+ });
274
+ let eventListener;
178
275
  try {
179
- options.signal?.throwIfAborted();
276
+ // Check abort signal - if aborted, need to decrement the counter
277
+ // that was incremented in tryToStartAnother
278
+ try {
279
+ options.signal?.throwIfAborted();
280
+ }
281
+ catch (error) {
282
+ // Decrement the counter that was already incremented
283
+ if (!this.#isIntervalIgnored) {
284
+ this.#intervalCount--;
285
+ }
286
+ // Clean up tracking before throwing
287
+ this.#runningTasks.delete(taskSymbol);
288
+ throw error;
289
+ }
180
290
  let operation = function_({ signal: options.signal });
181
291
  if (options.timeout) {
182
- operation = pTimeout(Promise.resolve(operation), { milliseconds: options.timeout });
292
+ operation = pTimeout(Promise.resolve(operation), {
293
+ milliseconds: options.timeout,
294
+ message: `Task timed out after ${options.timeout}ms (queue has ${this.#pending} running, ${this.#queue.size} waiting)`,
295
+ });
183
296
  }
184
297
  if (options.signal) {
185
- operation = Promise.race([operation, this.#throwOnAbort(options.signal)]);
298
+ const { signal } = options;
299
+ operation = Promise.race([operation, new Promise((_resolve, reject) => {
300
+ eventListener = () => {
301
+ reject(signal.reason);
302
+ };
303
+ signal.addEventListener('abort', eventListener, { once: true });
304
+ })]);
186
305
  }
187
306
  const result = await operation;
188
307
  resolve(result);
189
308
  this.emit('completed', result);
190
309
  }
191
310
  catch (error) {
192
- if (error instanceof TimeoutError && !options.throwOnTimeout) {
193
- resolve();
194
- return;
195
- }
196
311
  reject(error);
197
312
  this.emit('error', error);
198
313
  }
199
314
  finally {
200
- this.#next();
315
+ // Clean up abort event listener
316
+ if (eventListener) {
317
+ options.signal?.removeEventListener('abort', eventListener);
318
+ }
319
+ // Remove from running tasks
320
+ this.#runningTasks.delete(taskSymbol);
321
+ // Use queueMicrotask to prevent deep recursion while maintaining timing
322
+ queueMicrotask(() => {
323
+ this.#next();
324
+ });
201
325
  }
202
326
  }, options);
203
327
  this.emit('add');
@@ -229,6 +353,10 @@ export default class PQueue extends EventEmitter {
229
353
  */
230
354
  clear() {
231
355
  this.#queue = new this.#queueClass();
356
+ // Note: We don't clear #runningTasks as those tasks are still running
357
+ // They will be removed when they complete in the finally block
358
+ // Force synchronous update since clear() should have immediate effect
359
+ this.#updateRateLimitState();
232
360
  }
233
361
  /**
234
362
  Can be called multiple times. Useful if you for example add additional items at a later time.
@@ -268,6 +396,74 @@ export default class PQueue extends EventEmitter {
268
396
  }
269
397
  await this.#onEvent('idle');
270
398
  }
399
+ /**
400
+ The difference with `.onIdle` is that `.onPendingZero` only waits for currently running tasks to finish, ignoring queued tasks.
401
+
402
+ @returns A promise that settles when all currently running tasks have completed; `queue.pending === 0`.
403
+ */
404
+ async onPendingZero() {
405
+ if (this.#pending === 0) {
406
+ return;
407
+ }
408
+ await this.#onEvent('pendingZero');
409
+ }
410
+ /**
411
+ @returns A promise that settles when the queue becomes rate-limited due to intervalCap.
412
+ */
413
+ async onRateLimit() {
414
+ if (this.isRateLimited) {
415
+ return;
416
+ }
417
+ await this.#onEvent('rateLimit');
418
+ }
419
+ /**
420
+ @returns A promise that settles when the queue is no longer rate-limited.
421
+ */
422
+ async onRateLimitCleared() {
423
+ if (!this.isRateLimited) {
424
+ return;
425
+ }
426
+ await this.#onEvent('rateLimitCleared');
427
+ }
428
+ /**
429
+ @returns A promise that rejects when any task in the queue errors.
430
+
431
+ Use with `Promise.race([queue.onError(), queue.onIdle()])` to fail fast on the first error while still resolving normally when the queue goes idle.
432
+
433
+ Important: The promise returned by `add()` still rejects. You must handle each `add()` promise (for example, `.catch(() => {})`) to avoid unhandled rejections.
434
+
435
+ @example
436
+ ```
437
+ import PQueue from 'p-queue';
438
+
439
+ const queue = new PQueue({concurrency: 2});
440
+
441
+ queue.add(() => fetchData(1)).catch(() => {});
442
+ queue.add(() => fetchData(2)).catch(() => {});
443
+ queue.add(() => fetchData(3)).catch(() => {});
444
+
445
+ // Stop processing on first error
446
+ try {
447
+ await Promise.race([
448
+ queue.onError(),
449
+ queue.onIdle()
450
+ ]);
451
+ } catch (error) {
452
+ queue.pause(); // Stop processing remaining tasks
453
+ console.error('Queue failed:', error);
454
+ }
455
+ ```
456
+ */
457
+ // eslint-disable-next-line @typescript-eslint/promise-function-async
458
+ async onError() {
459
+ return new Promise((_resolve, reject) => {
460
+ const handleError = (error) => {
461
+ this.off('error', handleError);
462
+ reject(error);
463
+ };
464
+ this.on('error', handleError);
465
+ });
466
+ }
271
467
  async #onEvent(event, filter) {
272
468
  return new Promise(resolve => {
273
469
  const listener = () => {
@@ -307,4 +503,129 @@ export default class PQueue extends EventEmitter {
307
503
  get isPaused() {
308
504
  return this.#isPaused;
309
505
  }
506
+ #setupRateLimitTracking() {
507
+ // Only schedule updates when rate limiting is enabled
508
+ if (this.#isIntervalIgnored) {
509
+ return;
510
+ }
511
+ // Wire up to lifecycle events that affect rate limit state
512
+ // Only 'add' and 'next' can actually change rate limit state
513
+ this.on('add', () => {
514
+ if (this.#queue.size > 0) {
515
+ this.#scheduleRateLimitUpdate();
516
+ }
517
+ });
518
+ this.on('next', () => {
519
+ this.#scheduleRateLimitUpdate();
520
+ });
521
+ }
522
+ #scheduleRateLimitUpdate() {
523
+ // Skip if rate limiting is not enabled or already scheduled
524
+ if (this.#isIntervalIgnored || this.#rateLimitFlushScheduled) {
525
+ return;
526
+ }
527
+ this.#rateLimitFlushScheduled = true;
528
+ queueMicrotask(() => {
529
+ this.#rateLimitFlushScheduled = false;
530
+ this.#updateRateLimitState();
531
+ });
532
+ }
533
+ #updateRateLimitState() {
534
+ const previous = this.#rateLimitedInInterval;
535
+ const shouldBeRateLimited = !this.#isIntervalIgnored
536
+ && this.#intervalCount >= this.#intervalCap
537
+ && this.#queue.size > 0;
538
+ if (shouldBeRateLimited !== previous) {
539
+ this.#rateLimitedInInterval = shouldBeRateLimited;
540
+ this.emit(shouldBeRateLimited ? 'rateLimit' : 'rateLimitCleared');
541
+ }
542
+ }
543
+ /**
544
+ Whether the queue is currently rate-limited due to intervalCap.
545
+ */
546
+ get isRateLimited() {
547
+ return this.#rateLimitedInInterval;
548
+ }
549
+ /**
550
+ Whether the queue is saturated. Returns `true` when:
551
+ - All concurrency slots are occupied and tasks are waiting, OR
552
+ - The queue is rate-limited and tasks are waiting
553
+
554
+ Useful for detecting backpressure and potential hanging tasks.
555
+
556
+ ```js
557
+ import PQueue from 'p-queue';
558
+
559
+ const queue = new PQueue({concurrency: 2});
560
+
561
+ // Backpressure handling
562
+ if (queue.isSaturated) {
563
+ console.log('Queue is saturated, waiting for capacity...');
564
+ await queue.onSizeLessThan(queue.concurrency);
565
+ }
566
+
567
+ // Monitoring for stuck tasks
568
+ setInterval(() => {
569
+ if (queue.isSaturated) {
570
+ console.warn(`Queue saturated: ${queue.pending} running, ${queue.size} waiting`);
571
+ }
572
+ }, 60000);
573
+ ```
574
+ */
575
+ get isSaturated() {
576
+ return (this.#pending === this.#concurrency && this.#queue.size > 0)
577
+ || (this.isRateLimited && this.#queue.size > 0);
578
+ }
579
+ /**
580
+ The tasks currently being executed. Each task includes its `id`, `priority`, `startTime`, and `timeout` (if set).
581
+
582
+ Returns an array of task info objects.
583
+
584
+ ```js
585
+ import PQueue from 'p-queue';
586
+
587
+ const queue = new PQueue({concurrency: 2});
588
+
589
+ // Add tasks with IDs for better debugging
590
+ queue.add(() => fetchUser(123), {id: 'user-123'});
591
+ queue.add(() => fetchPosts(456), {id: 'posts-456', priority: 1});
592
+
593
+ // Check what's running
594
+ console.log(queue.runningTasks);
595
+ // => [{
596
+ // id: 'user-123',
597
+ // priority: 0,
598
+ // startTime: 1759253001716,
599
+ // timeout: undefined
600
+ // }, {
601
+ // id: 'posts-456',
602
+ // priority: 1,
603
+ // startTime: 1759253001916,
604
+ // timeout: undefined
605
+ // }]
606
+ ```
607
+ */
608
+ get runningTasks() {
609
+ // Return fresh array with fresh objects to prevent mutations
610
+ return [...this.#runningTasks.values()].map(task => ({ ...task }));
611
+ }
310
612
  }
613
+ /**
614
+ Error thrown when a task times out.
615
+
616
+ @example
617
+ ```
618
+ import PQueue, {TimeoutError} from 'p-queue';
619
+
620
+ const queue = new PQueue({timeout: 1000});
621
+
622
+ try {
623
+ await queue.add(() => someTask());
624
+ } catch (error) {
625
+ if (error instanceof TimeoutError) {
626
+ console.log('Task timed out');
627
+ }
628
+ }
629
+ ```
630
+ */
631
+ export { TimeoutError } from 'p-timeout';
@@ -0,0 +1,121 @@
1
+ import { type Queue, type RunFunction } from './queue.js';
2
+ type TimeoutOptions = {
3
+ /**
4
+ Per-operation timeout in milliseconds. Operations will throw a `TimeoutError` if they don't complete within the specified time.
5
+
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
+ ```
22
+ */
23
+ timeout?: number;
24
+ };
25
+ export type Options<QueueType extends Queue<RunFunction, QueueOptions>, QueueOptions extends QueueAddOptions> = {
26
+ /**
27
+ Concurrency limit.
28
+
29
+ Minimum: `1`.
30
+
31
+ @default Infinity
32
+ */
33
+ readonly concurrency?: number;
34
+ /**
35
+ Whether queue tasks within concurrency limit, are auto-executed as soon as they're added.
36
+
37
+ @default true
38
+ */
39
+ readonly autoStart?: boolean;
40
+ /**
41
+ Class with a `enqueue` and `dequeue` method, and a `size` getter. See the [Custom QueueClass](https://github.com/sindresorhus/p-queue#custom-queueclass) section.
42
+ */
43
+ readonly queueClass?: new () => QueueType;
44
+ /**
45
+ The max number of runs in the given interval of time.
46
+
47
+ Minimum: `1`.
48
+
49
+ @default Infinity
50
+ */
51
+ readonly intervalCap?: number;
52
+ /**
53
+ The length of time in milliseconds before the interval count resets. Must be finite.
54
+
55
+ Minimum: `0`.
56
+
57
+ @default 0
58
+ */
59
+ readonly interval?: number;
60
+ /**
61
+ Whether the task must finish in the given interval or will be carried over into the next interval count.
62
+
63
+ @default false
64
+ */
65
+ readonly carryoverIntervalCount?: boolean;
66
+ /**
67
+ @deprecated Renamed to `carryoverIntervalCount`.
68
+ */
69
+ readonly carryoverConcurrencyCount?: boolean;
70
+ } & TimeoutOptions;
71
+ export type QueueAddOptions = {
72
+ /**
73
+ Priority of operation. Operations with greater priority will be scheduled first.
74
+
75
+ @default 0
76
+ */
77
+ readonly priority?: number;
78
+ /**
79
+ 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`.
80
+ */
81
+ id?: string;
82
+ } & TaskOptions & TimeoutOptions;
83
+ export type TaskOptions = {
84
+ /**
85
+ [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) for cancellation of the operation. When aborted, it will be removed from the queue and the `queue.add()` call will reject with an `AbortError`. If the operation is already running, the signal will need to be handled by the operation itself.
86
+
87
+ @example
88
+ ```
89
+ import PQueue, {AbortError} from 'p-queue';
90
+ import got, {CancelError} from 'got';
91
+
92
+ const queue = new PQueue();
93
+
94
+ const controller = new AbortController();
95
+
96
+ try {
97
+ await queue.add(({signal}) => {
98
+ const request = got('https://sindresorhus.com');
99
+
100
+ signal.addEventListener('abort', () => {
101
+ request.cancel();
102
+ });
103
+
104
+ try {
105
+ return await request;
106
+ } catch (error) {
107
+ if (!(error instanceof CancelError)) {
108
+ throw error;
109
+ }
110
+ }
111
+ }, {signal: controller.signal});
112
+ } catch (error) {
113
+ if (!(error instanceof AbortError)) {
114
+ throw error;
115
+ }
116
+ }
117
+ ```
118
+ */
119
+ readonly signal?: AbortSignal;
120
+ };
121
+ export {};