{"version":3,"sources":["../../src/lib/_AsyncQueueEntry.ts","../../src/lib/AsyncQueue.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["import type { AsyncQueue } from './AsyncQueue';\n\n/**\n * @internal\n */\nexport class AsyncQueueEntry {\n\tpublic readonly promise: Promise;\n\tprivate resolve!: () => void;\n\tprivate reject!: (error: Error) => void;\n\tprivate readonly queue: AsyncQueue;\n\tprivate signal: PolyFillAbortSignal | null = null;\n\tprivate signalListener: (() => void) | null = null;\n\n\tpublic constructor(queue: AsyncQueue) {\n\t\tthis.queue = queue;\n\t\tthis.promise = new Promise((resolve, reject) => {\n\t\t\tthis.resolve = resolve;\n\t\t\tthis.reject = reject;\n\t\t});\n\t}\n\n\tpublic setSignal(signal: AbortSignal) {\n\t\tif (signal.aborted) return this;\n\n\t\tthis.signal = signal as PolyFillAbortSignal;\n\t\tthis.signalListener = () => {\n\t\t\tconst index = this.queue['promises'].indexOf(this);\n\t\t\tif (index !== -1) this.queue['promises'].splice(index, 1);\n\n\t\t\tthis.reject(new Error('Request aborted manually'));\n\t\t};\n\t\tthis.signal.addEventListener('abort', this.signalListener);\n\t\treturn this;\n\t}\n\n\tpublic use() {\n\t\tthis.dispose();\n\t\tthis.resolve();\n\t\treturn this;\n\t}\n\n\tpublic abort() {\n\t\tthis.dispose();\n\t\tthis.reject(new Error('Request aborted manually'));\n\t\treturn this;\n\t}\n\n\tprivate dispose() {\n\t\tif (this.signal) {\n\t\t\tthis.signal.removeEventListener('abort', this.signalListener!);\n\t\t\tthis.signal = null;\n\t\t\tthis.signalListener = null;\n\t\t}\n\t}\n}\n\ninterface PolyFillAbortSignal {\n\treadonly aborted: boolean;\n\taddEventListener(type: 'abort', listener: () => void): void;\n\tremoveEventListener(type: 'abort', listener: () => void): void;\n}\n","import { AsyncQueueEntry } from './_AsyncQueueEntry';\n\n/**\n * The AsyncQueue class used to sequentialize burst requests\n */\nexport class AsyncQueue {\n\t/**\n\t * The amount of entries in the queue, including the head.\n\t * @seealso {@link queued} for the queued count.\n\t */\n\tpublic get remaining(): number {\n\t\treturn this.promises.length;\n\t}\n\n\t/**\n\t * The amount of queued entries.\n\t * @seealso {@link remaining} for the count with the head.\n\t */\n\tpublic get queued(): number {\n\t\treturn this.remaining === 0 ? 0 : this.remaining - 1;\n\t}\n\n\t/**\n\t * The promises array\n\t */\n\tprivate readonly promises: AsyncQueueEntry[] = [];\n\n\t/**\n\t * Waits for last promise and queues a new one\n\t * @example\n\t * ```typescript\n\t * const queue = new AsyncQueue();\n\t * async function request(url, options) {\n\t * await queue.wait({ signal: options.signal });\n\t * try {\n\t * const result = await fetch(url, options);\n\t * // Do some operations with 'result'\n\t * } finally {\n\t * // Remove first entry from the queue and resolve for the next entry\n\t * queue.shift();\n\t * }\n\t * }\n\t *\n\t * request(someUrl1, someOptions1); // Will call fetch() immediately\n\t * request(someUrl2, someOptions2); // Will call fetch() after the first finished\n\t * request(someUrl3, someOptions3); // Will call fetch() after the second finished\n\t * ```\n\t */\n\tpublic wait(options?: Readonly): Promise {\n\t\tconst entry = new AsyncQueueEntry(this);\n\n\t\tif (this.promises.length === 0) {\n\t\t\tthis.promises.push(entry);\n\t\t\treturn Promise.resolve();\n\t\t}\n\n\t\tthis.promises.push(entry);\n\t\tif (options?.signal) entry.setSignal(options.signal);\n\t\treturn entry.promise;\n\t}\n\n\t/**\n\t * Unlocks the head lock and transfers the next lock (if any) to the head.\n\t */\n\tpublic shift(): void {\n\t\tif (this.promises.length === 0) return;\n\t\tif (this.promises.length === 1) {\n\t\t\t// Remove the head entry.\n\t\t\tthis.promises.shift();\n\t\t\treturn;\n\t\t}\n\n\t\t// Remove the head entry, making the 2nd entry the new one.\n\t\t// Then use the head entry, which will unlock the promise.\n\t\tthis.promises.shift();\n\t\tthis.promises[0].use();\n\t}\n\n\t/**\n\t * Aborts all the pending promises.\n\t * @note To avoid race conditions, this does **not** unlock the head lock.\n\t */\n\tpublic abortAll(): void {\n\t\t// If there are no queued entries, skip early.\n\t\tif (this.queued === 0) return;\n\n\t\t// Abort all the entries except the head, that is why the loop starts at\n\t\t// 1 and not at 0.\n\t\tfor (let i = 1; i < this.promises.length; ++i) {\n\t\t\tthis.promises[i].abort();\n\t\t}\n\n\t\tthis.promises.length = 1;\n\t}\n}\n\nexport interface AsyncQueueWaitOptions {\n\tsignal?: AbortSignal | undefined | null;\n}\n"]}