const require_index = require("../../../../eventemitter3@5.0.4/node_modules/eventemitter3/index2.cjs");
const require_index$1 = require("../../../../p-timeout@7.0.1/node_modules/p-timeout/index.cjs");
const require_priority_queue = require("./priority-queue.cjs");
//#region ../../node_modules/.pnpm/p-queue@9.1.0/node_modules/p-queue/dist/index.js
/**
Promise queue with concurrency control.
*/
var PQueue = class extends require_index.import_eventemitter3.default {
	#carryoverIntervalCount;
	#isIntervalIgnored;
	#intervalCount = 0;
	#intervalCap;
	#rateLimitedInInterval = false;
	#rateLimitFlushScheduled = false;
	#interval;
	#intervalEnd = 0;
	#lastExecutionTime = 0;
	#intervalId;
	#timeoutId;
	#strict;
	#strictTicks = [];
	#strictTicksStartIndex = 0;
	#queue;
	#queueClass;
	#pending = 0;
	#concurrency;
	#isPaused;
	#idAssigner = 1n;
	#runningTasks = /* @__PURE__ */ new Map();
	/**
	Get or set the default timeout for all tasks. Can be changed at runtime.
	
	Operations will throw a `TimeoutError` if they don't complete within the specified time.
	
	The timeout begins when the operation is dequeued and starts execution, not while it's waiting in the queue.
	
	@example
	```
	const queue = new PQueue({timeout: 5000});
	
	// Change timeout for all future tasks
	queue.timeout = 10000;
	```
	*/
	timeout;
	constructor(options) {
		super();
		options = {
			carryoverIntervalCount: false,
			intervalCap: Number.POSITIVE_INFINITY,
			interval: 0,
			concurrency: Number.POSITIVE_INFINITY,
			autoStart: true,
			queueClass: require_priority_queue.default,
			strict: false,
			...options
		};
		if (!(typeof options.intervalCap === "number" && options.intervalCap >= 1)) throw new TypeError(`Expected \`intervalCap\` to be a number from 1 and up, got \`${options.intervalCap?.toString() ?? ""}\` (${typeof options.intervalCap})`);
		if (options.interval === void 0 || !(Number.isFinite(options.interval) && options.interval >= 0)) throw new TypeError(`Expected \`interval\` to be a finite number >= 0, got \`${options.interval?.toString() ?? ""}\` (${typeof options.interval})`);
		if (options.strict && options.interval === 0) throw new TypeError("The `strict` option requires a non-zero `interval`");
		if (options.strict && options.intervalCap === Number.POSITIVE_INFINITY) throw new TypeError("The `strict` option requires a finite `intervalCap`");
		this.#carryoverIntervalCount = options.carryoverIntervalCount ?? options.carryoverConcurrencyCount ?? false;
		this.#isIntervalIgnored = options.intervalCap === Number.POSITIVE_INFINITY || options.interval === 0;
		this.#intervalCap = options.intervalCap;
		this.#interval = options.interval;
		this.#strict = options.strict;
		this.#queue = new options.queueClass();
		this.#queueClass = options.queueClass;
		this.concurrency = options.concurrency;
		if (options.timeout !== void 0 && !(Number.isFinite(options.timeout) && options.timeout > 0)) throw new TypeError(`Expected \`timeout\` to be a positive finite number, got \`${options.timeout}\` (${typeof options.timeout})`);
		this.timeout = options.timeout;
		this.#isPaused = options.autoStart === false;
		this.#setupRateLimitTracking();
	}
	#cleanupStrictTicks(now) {
		while (this.#strictTicksStartIndex < this.#strictTicks.length) {
			const oldestTick = this.#strictTicks[this.#strictTicksStartIndex];
			if (oldestTick !== void 0 && now - oldestTick >= this.#interval) this.#strictTicksStartIndex++;
			else break;
		}
		if (this.#strictTicksStartIndex > 100 && this.#strictTicksStartIndex > this.#strictTicks.length / 2 || this.#strictTicksStartIndex === this.#strictTicks.length) {
			this.#strictTicks = this.#strictTicks.slice(this.#strictTicksStartIndex);
			this.#strictTicksStartIndex = 0;
		}
	}
	#consumeIntervalSlot(now) {
		if (this.#strict) this.#strictTicks.push(now);
		else this.#intervalCount++;
	}
	#rollbackIntervalSlot() {
		if (this.#strict) {
			if (this.#strictTicks.length > this.#strictTicksStartIndex) this.#strictTicks.pop();
		} else if (this.#intervalCount > 0) this.#intervalCount--;
	}
	#getActiveTicksCount() {
		return this.#strictTicks.length - this.#strictTicksStartIndex;
	}
	get #doesIntervalAllowAnother() {
		if (this.#isIntervalIgnored) return true;
		if (this.#strict) return this.#getActiveTicksCount() < this.#intervalCap;
		return this.#intervalCount < this.#intervalCap;
	}
	get #doesConcurrentAllowAnother() {
		return this.#pending < this.#concurrency;
	}
	#next() {
		this.#pending--;
		if (this.#pending === 0) this.emit("pendingZero");
		this.#tryToStartAnother();
		this.emit("next");
	}
	#onResumeInterval() {
		this.#timeoutId = void 0;
		this.#onInterval();
		this.#initializeIntervalIfNeeded();
	}
	#isIntervalPausedAt(now) {
		if (this.#strict) {
			this.#cleanupStrictTicks(now);
			if (this.#getActiveTicksCount() >= this.#intervalCap) {
				const oldestTick = this.#strictTicks[this.#strictTicksStartIndex];
				const delay = this.#interval - (now - oldestTick);
				this.#createIntervalTimeout(delay);
				return true;
			}
			return false;
		}
		if (this.#intervalId === void 0) {
			const delay = this.#intervalEnd - now;
			if (delay < 0) {
				if (this.#lastExecutionTime > 0) {
					const timeSinceLastExecution = now - this.#lastExecutionTime;
					if (timeSinceLastExecution < this.#interval) {
						this.#createIntervalTimeout(this.#interval - timeSinceLastExecution);
						return true;
					}
				}
				this.#intervalCount = this.#carryoverIntervalCount ? this.#pending : 0;
			} else {
				this.#createIntervalTimeout(delay);
				return true;
			}
		}
		return false;
	}
	#createIntervalTimeout(delay) {
		if (this.#timeoutId !== void 0) return;
		this.#timeoutId = setTimeout(() => {
			this.#onResumeInterval();
		}, delay);
	}
	#clearIntervalTimer() {
		if (this.#intervalId) {
			clearInterval(this.#intervalId);
			this.#intervalId = void 0;
		}
	}
	#clearTimeoutTimer() {
		if (this.#timeoutId) {
			clearTimeout(this.#timeoutId);
			this.#timeoutId = void 0;
		}
	}
	#tryToStartAnother() {
		if (this.#queue.size === 0) {
			this.#clearIntervalTimer();
			this.emit("empty");
			if (this.#pending === 0) {
				this.#clearTimeoutTimer();
				if (this.#strict && this.#strictTicksStartIndex > 0) {
					const now = Date.now();
					this.#cleanupStrictTicks(now);
				}
				this.emit("idle");
			}
			return false;
		}
		let taskStarted = false;
		if (!this.#isPaused) {
			const now = Date.now();
			const canInitializeInterval = !this.#isIntervalPausedAt(now);
			if (this.#doesIntervalAllowAnother && this.#doesConcurrentAllowAnother) {
				const job = this.#queue.dequeue();
				if (!this.#isIntervalIgnored) {
					this.#consumeIntervalSlot(now);
					this.#scheduleRateLimitUpdate();
				}
				this.emit("active");
				job();
				if (canInitializeInterval) this.#initializeIntervalIfNeeded();
				taskStarted = true;
			}
		}
		return taskStarted;
	}
	#initializeIntervalIfNeeded() {
		if (this.#isIntervalIgnored || this.#intervalId !== void 0) return;
		if (this.#strict) return;
		this.#intervalId = setInterval(() => {
			this.#onInterval();
		}, this.#interval);
		this.#intervalEnd = Date.now() + this.#interval;
	}
	#onInterval() {
		if (!this.#strict) {
			if (this.#intervalCount === 0 && this.#pending === 0 && this.#intervalId) this.#clearIntervalTimer();
			this.#intervalCount = this.#carryoverIntervalCount ? this.#pending : 0;
		}
		this.#processQueue();
		this.#scheduleRateLimitUpdate();
	}
	/**
	Executes all queued functions until it reaches the limit.
	*/
	#processQueue() {
		while (this.#tryToStartAnother());
	}
	get concurrency() {
		return this.#concurrency;
	}
	set concurrency(newConcurrency) {
		if (!(typeof newConcurrency === "number" && newConcurrency >= 1)) throw new TypeError(`Expected \`concurrency\` to be a number from 1 and up, got \`${newConcurrency}\` (${typeof newConcurrency})`);
		this.#concurrency = newConcurrency;
		this.#processQueue();
	}
	/**
	Updates the priority of a promise function by its id, affecting its execution order. Requires a defined concurrency limit to take effect.
	
	For example, this can be used to prioritize a promise function to run earlier.
	
	```js
	import PQueue from 'p-queue';
	
	const queue = new PQueue({concurrency: 1});
	
	queue.add(async () => '🦄', {priority: 1});
	queue.add(async () => '🦀', {priority: 0, id: '🦀'});
	queue.add(async () => '🦄', {priority: 1});
	queue.add(async () => '🦄', {priority: 1});
	
	queue.setPriority('🦀', 2);
	```
	
	In this case, the promise function with `id: '🦀'` runs second.
	
	You can also deprioritize a promise function to delay its execution:
	
	```js
	import PQueue from 'p-queue';
	
	const queue = new PQueue({concurrency: 1});
	
	queue.add(async () => '🦄', {priority: 1});
	queue.add(async () => '🦀', {priority: 1, id: '🦀'});
	queue.add(async () => '🦄');
	queue.add(async () => '🦄', {priority: 0});
	
	queue.setPriority('🦀', -1);
	```
	Here, the promise function with `id: '🦀'` executes last.
	*/
	setPriority(id, priority) {
		if (typeof priority !== "number" || !Number.isFinite(priority)) throw new TypeError(`Expected \`priority\` to be a finite number, got \`${priority}\` (${typeof priority})`);
		this.#queue.setPriority(id, priority);
	}
	async add(function_, options = {}) {
		options = {
			timeout: this.timeout,
			...options,
			id: options.id ?? (this.#idAssigner++).toString()
		};
		return new Promise((resolve, reject) => {
			const taskSymbol = Symbol(`task-${options.id}`);
			this.#queue.enqueue(async () => {
				this.#pending++;
				this.#runningTasks.set(taskSymbol, {
					id: options.id,
					priority: options.priority ?? 0,
					startTime: Date.now(),
					timeout: options.timeout
				});
				let eventListener;
				try {
					try {
						options.signal?.throwIfAborted();
					} catch (error) {
						this.#rollbackIntervalConsumption();
						this.#runningTasks.delete(taskSymbol);
						throw error;
					}
					this.#lastExecutionTime = Date.now();
					let operation = function_({ signal: options.signal });
					if (options.timeout) operation = require_index$1.default(Promise.resolve(operation), {
						milliseconds: options.timeout,
						message: `Task timed out after ${options.timeout}ms (queue has ${this.#pending} running, ${this.#queue.size} waiting)`
					});
					if (options.signal) {
						const { signal } = options;
						operation = Promise.race([operation, new Promise((_resolve, reject) => {
							eventListener = () => {
								reject(signal.reason);
							};
							signal.addEventListener("abort", eventListener, { once: true });
						})]);
					}
					const result = await operation;
					resolve(result);
					this.emit("completed", result);
				} catch (error) {
					reject(error);
					this.emit("error", error);
				} finally {
					if (eventListener) options.signal?.removeEventListener("abort", eventListener);
					this.#runningTasks.delete(taskSymbol);
					queueMicrotask(() => {
						this.#next();
					});
				}
			}, options);
			this.emit("add");
			this.#tryToStartAnother();
		});
	}
	async addAll(functions, options) {
		return Promise.all(functions.map(async (function_) => this.add(function_, options)));
	}
	/**
	Start (or resume) executing enqueued tasks within concurrency limit. No need to call this if queue is not paused (via `options.autoStart = false` or by `.pause()` method.)
	*/
	start() {
		if (!this.#isPaused) return this;
		this.#isPaused = false;
		this.#processQueue();
		return this;
	}
	/**
	Put queue execution on hold.
	*/
	pause() {
		this.#isPaused = true;
	}
	/**
	Clear the queue.
	*/
	clear() {
		this.#queue = new this.#queueClass();
		this.#clearIntervalTimer();
		this.#updateRateLimitState();
		this.emit("empty");
		if (this.#pending === 0) {
			this.#clearTimeoutTimer();
			this.emit("idle");
		}
		this.emit("next");
	}
	/**
	Can be called multiple times. Useful if you for example add additional items at a later time.
	
	@returns A promise that settles when the queue becomes empty.
	*/
	async onEmpty() {
		if (this.#queue.size === 0) return;
		await this.#onEvent("empty");
	}
	/**
	@returns A promise that settles when the queue size is less than the given limit: `queue.size < limit`.
	
	If you want to avoid having the queue grow beyond a certain size you can `await queue.onSizeLessThan()` before adding a new item.
	
	Note that this only limits the number of items waiting to start. There could still be up to `concurrency` jobs already running that this call does not include in its calculation.
	*/
	async onSizeLessThan(limit) {
		if (this.#queue.size < limit) return;
		await this.#onEvent("next", () => this.#queue.size < limit);
	}
	/**
	The difference with `.onEmpty` is that `.onIdle` guarantees that all work from the queue has finished. `.onEmpty` merely signals that the queue is empty, but it could mean that some promises haven't completed yet.
	
	@returns A promise that settles when the queue becomes empty, and all promises have completed; `queue.size === 0 && queue.pending === 0`.
	*/
	async onIdle() {
		if (this.#pending === 0 && this.#queue.size === 0) return;
		await this.#onEvent("idle");
	}
	/**
	The difference with `.onIdle` is that `.onPendingZero` only waits for currently running tasks to finish, ignoring queued tasks.
	
	@returns A promise that settles when all currently running tasks have completed; `queue.pending === 0`.
	*/
	async onPendingZero() {
		if (this.#pending === 0) return;
		await this.#onEvent("pendingZero");
	}
	/**
	@returns A promise that settles when the queue becomes rate-limited due to intervalCap.
	*/
	async onRateLimit() {
		if (this.isRateLimited) return;
		await this.#onEvent("rateLimit");
	}
	/**
	@returns A promise that settles when the queue is no longer rate-limited.
	*/
	async onRateLimitCleared() {
		if (!this.isRateLimited) return;
		await this.#onEvent("rateLimitCleared");
	}
	/**
	@returns A promise that rejects when any task in the queue errors.
	
	Use with `Promise.race([queue.onError(), queue.onIdle()])` to fail fast on the first error while still resolving normally when the queue goes idle.
	
	Important: The promise returned by `add()` still rejects. You must handle each `add()` promise (for example, `.catch(() => {})`) to avoid unhandled rejections.
	
	@example
	```
	import PQueue from 'p-queue';
	
	const queue = new PQueue({concurrency: 2});
	
	queue.add(() => fetchData(1)).catch(() => {});
	queue.add(() => fetchData(2)).catch(() => {});
	queue.add(() => fetchData(3)).catch(() => {});
	
	// Stop processing on first error
	try {
	await Promise.race([
	queue.onError(),
	queue.onIdle()
	]);
	} catch (error) {
	queue.pause(); // Stop processing remaining tasks
	console.error('Queue failed:', error);
	}
	```
	*/
	onError() {
		return new Promise((_resolve, reject) => {
			const handleError = (error) => {
				this.off("error", handleError);
				reject(error);
			};
			this.on("error", handleError);
		});
	}
	async #onEvent(event, filter) {
		return new Promise((resolve) => {
			const listener = () => {
				if (filter && !filter()) return;
				this.off(event, listener);
				resolve();
			};
			this.on(event, listener);
		});
	}
	/**
	Size of the queue, the number of queued items waiting to run.
	*/
	get size() {
		return this.#queue.size;
	}
	/**
	Size of the queue, filtered by the given options.
	
	For example, this can be used to find the number of items remaining in the queue with a specific priority level.
	*/
	sizeBy(options) {
		return this.#queue.filter(options).length;
	}
	/**
	Number of running items (no longer in the queue).
	*/
	get pending() {
		return this.#pending;
	}
	/**
	Whether the queue is currently paused.
	*/
	get isPaused() {
		return this.#isPaused;
	}
	#setupRateLimitTracking() {
		if (this.#isIntervalIgnored) return;
		this.on("add", () => {
			if (this.#queue.size > 0) this.#scheduleRateLimitUpdate();
		});
		this.on("next", () => {
			this.#scheduleRateLimitUpdate();
		});
	}
	#scheduleRateLimitUpdate() {
		if (this.#isIntervalIgnored || this.#rateLimitFlushScheduled) return;
		this.#rateLimitFlushScheduled = true;
		queueMicrotask(() => {
			this.#rateLimitFlushScheduled = false;
			this.#updateRateLimitState();
		});
	}
	#rollbackIntervalConsumption() {
		if (this.#isIntervalIgnored) return;
		this.#rollbackIntervalSlot();
		this.#scheduleRateLimitUpdate();
	}
	#updateRateLimitState() {
		const previous = this.#rateLimitedInInterval;
		if (this.#isIntervalIgnored || this.#queue.size === 0) {
			if (previous) {
				this.#rateLimitedInInterval = false;
				this.emit("rateLimitCleared");
			}
			return;
		}
		let count;
		if (this.#strict) {
			const now = Date.now();
			this.#cleanupStrictTicks(now);
			count = this.#getActiveTicksCount();
		} else count = this.#intervalCount;
		const shouldBeRateLimited = count >= this.#intervalCap;
		if (shouldBeRateLimited !== previous) {
			this.#rateLimitedInInterval = shouldBeRateLimited;
			this.emit(shouldBeRateLimited ? "rateLimit" : "rateLimitCleared");
		}
	}
	/**
	Whether the queue is currently rate-limited due to intervalCap.
	*/
	get isRateLimited() {
		return this.#rateLimitedInInterval;
	}
	/**
	Whether the queue is saturated. Returns `true` when:
	- All concurrency slots are occupied and tasks are waiting, OR
	- The queue is rate-limited and tasks are waiting
	
	Useful for detecting backpressure and potential hanging tasks.
	
	```js
	import PQueue from 'p-queue';
	
	const queue = new PQueue({concurrency: 2});
	
	// Backpressure handling
	if (queue.isSaturated) {
	console.log('Queue is saturated, waiting for capacity...');
	await queue.onSizeLessThan(queue.concurrency);
	}
	
	// Monitoring for stuck tasks
	setInterval(() => {
	if (queue.isSaturated) {
	console.warn(`Queue saturated: ${queue.pending} running, ${queue.size} waiting`);
	}
	}, 60000);
	```
	*/
	get isSaturated() {
		return this.#pending === this.#concurrency && this.#queue.size > 0 || this.isRateLimited && this.#queue.size > 0;
	}
	/**
	The tasks currently being executed. Each task includes its `id`, `priority`, `startTime`, and `timeout` (if set).
	
	Returns an array of task info objects.
	
	```js
	import PQueue from 'p-queue';
	
	const queue = new PQueue({concurrency: 2});
	
	// Add tasks with IDs for better debugging
	queue.add(() => fetchUser(123), {id: 'user-123'});
	queue.add(() => fetchPosts(456), {id: 'posts-456', priority: 1});
	
	// Check what's running
	console.log(queue.runningTasks);
	// => [{
	//   id: 'user-123',
	//   priority: 0,
	//   startTime: 1759253001716,
	//   timeout: undefined
	// }, {
	//   id: 'posts-456',
	//   priority: 1,
	//   startTime: 1759253001916,
	//   timeout: undefined
	// }]
	```
	*/
	get runningTasks() {
		return [...this.#runningTasks.values()].map((task) => ({ ...task }));
	}
};
//#endregion
exports.default = PQueue;

//# sourceMappingURL=index.cjs.map