{"version":3,"file":"promisebuffer.js","sources":["../../src/promisebuffer.ts"],"sourcesContent":["import { SentryError } from './error';\nimport { SyncPromise, rejectedSyncPromise, resolvedSyncPromise } from './syncpromise';\n\nexport interface PromiseBuffer {\n // exposes the internal array so tests can assert on the state of it.\n // XXX: this really should not be public api.\n $: Array>;\n add(taskProducer: () => PromiseLike): PromiseLike;\n drain(timeout?: number): PromiseLike;\n}\n\n/**\n * Creates an new PromiseBuffer object with the specified limit\n * @param limit max number of promises that can be stored in the buffer\n */\nexport function makePromiseBuffer(limit?: number): PromiseBuffer {\n const buffer: Array> = [];\n\n function isReady(): boolean {\n return limit === undefined || buffer.length < limit;\n }\n\n /**\n * Remove a promise from the queue.\n *\n * @param task Can be any PromiseLike\n * @returns Removed promise.\n */\n function remove(task: PromiseLike): PromiseLike {\n return buffer.splice(buffer.indexOf(task), 1)[0];\n }\n\n /**\n * Add a promise (representing an in-flight action) to the queue, and set it to remove itself on fulfillment.\n *\n * @param taskProducer A function producing any PromiseLike; In previous versions this used to be `task:\n * PromiseLike`, but under that model, Promises were instantly created on the call-site and their executor\n * functions therefore ran immediately. Thus, even if the buffer was full, the action still happened. By\n * requiring the promise to be wrapped in a function, we can defer promise creation until after the buffer\n * limit check.\n * @returns The original promise.\n */\n function add(taskProducer: () => PromiseLike): PromiseLike {\n if (!isReady()) {\n return rejectedSyncPromise(new SentryError('Not adding Promise because buffer limit was reached.'));\n }\n\n // start the task and add its promise to the queue\n const task = taskProducer();\n if (buffer.indexOf(task) === -1) {\n buffer.push(task);\n }\n void task\n .then(() => remove(task))\n // Use `then(null, rejectionHandler)` rather than `catch(rejectionHandler)` so that we can use `PromiseLike`\n // rather than `Promise`. `PromiseLike` doesn't have a `.catch` method, making its polyfill smaller. (ES5 didn't\n // have promises, so TS has to polyfill when down-compiling.)\n .then(null, () =>\n remove(task).then(null, () => {\n // We have to add another catch here because `remove()` starts a new promise chain.\n }),\n );\n return task;\n }\n\n /**\n * Wait for all promises in the queue to resolve or for timeout to expire, whichever comes first.\n *\n * @param timeout The time, in ms, after which to resolve to `false` if the queue is still non-empty. Passing `0` (or\n * not passing anything) will make the promise wait as long as it takes for the queue to drain before resolving to\n * `true`.\n * @returns A promise which will resolve to `true` if the queue is already empty or drains before the timeout, and\n * `false` otherwise\n */\n function drain(timeout?: number): PromiseLike {\n return new SyncPromise((resolve, reject) => {\n let counter = buffer.length;\n\n if (!counter) {\n return resolve(true);\n }\n\n // wait for `timeout` ms and then resolve to `false` (if not cancelled first)\n const capturedSetTimeout = setTimeout(() => {\n if (timeout && timeout > 0) {\n resolve(false);\n }\n }, timeout);\n\n // if all promises resolve in time, cancel the timer and resolve to `true`\n buffer.forEach(item => {\n void resolvedSyncPromise(item).then(() => {\n if (!--counter) {\n clearTimeout(capturedSetTimeout);\n resolve(true);\n }\n }, reject);\n });\n });\n }\n\n return {\n $: buffer,\n add,\n drain,\n };\n}\n"],"names":[],"mappings":";;;AAWA;AACA;AACA;AACA;AACO,SAAS,iBAAiB,CAAI,KAAK,EAA6B;AACvE,EAAE,MAAM,MAAM,GAA0B,EAAE,CAAA;AAC1C;AACA,EAAE,SAAS,OAAO,GAAY;AAC9B,IAAI,OAAO,UAAU,SAAA,IAAa,MAAM,CAAC,MAAO,GAAE,KAAK,CAAA;AACvD,GAAE;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAE,SAAS,MAAM,CAAC,IAAI,EAAkC;AACxD,IAAI,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;AACpD,GAAE;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAE,SAAS,GAAG,CAAC,YAAY,EAAwC;AACnE,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE;AACpB,MAAM,OAAO,mBAAmB,CAAC,IAAI,WAAW,CAAC,sDAAsD,CAAC,CAAC,CAAA;AACzG,KAAI;AACJ;AACA;AACA,IAAI,MAAM,IAAA,GAAO,YAAY,EAAE,CAAA;AAC/B,IAAI,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAE,KAAI,CAAC,CAAC,EAAE;AACrC,MAAM,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACvB,KAAI;AACJ,IAAI,KAAK,IAAA;AACT,OAAO,IAAI,CAAC,MAAM,MAAM,CAAC,IAAI,CAAC,CAAA;AAC9B;AACA;AACA;AACA,OAAO,IAAI,CAAC,IAAI,EAAE;AAClB,QAAQ,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM;AACtC;AACA,SAAS,CAAC;AACV,OAAO,CAAA;AACP,IAAI,OAAO,IAAI,CAAA;AACf,GAAE;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAE,SAAS,KAAK,CAAC,OAAO,EAAiC;AACzD,IAAI,OAAO,IAAI,WAAW,CAAU,CAAC,OAAO,EAAE,MAAM,KAAK;AACzD,MAAM,IAAI,OAAA,GAAU,MAAM,CAAC,MAAM,CAAA;AACjC;AACA,MAAM,IAAI,CAAC,OAAO,EAAE;AACpB,QAAQ,OAAO,OAAO,CAAC,IAAI,CAAC,CAAA;AAC5B,OAAM;AACN;AACA;AACA,MAAM,MAAM,kBAAmB,GAAE,UAAU,CAAC,MAAM;AAClD,QAAQ,IAAI,OAAA,IAAW,OAAQ,GAAE,CAAC,EAAE;AACpC,UAAU,OAAO,CAAC,KAAK,CAAC,CAAA;AACxB,SAAQ;AACR,OAAO,EAAE,OAAO,CAAC,CAAA;AACjB;AACA;AACA,MAAM,MAAM,CAAC,OAAO,CAAC,QAAQ;AAC7B,QAAQ,KAAK,mBAAmB,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM;AAClD,UAAU,IAAI,CAAC,EAAE,OAAO,EAAE;AAC1B,YAAY,YAAY,CAAC,kBAAkB,CAAC,CAAA;AAC5C,YAAY,OAAO,CAAC,IAAI,CAAC,CAAA;AACzB,WAAU;AACV,SAAS,EAAE,MAAM,CAAC,CAAA;AAClB,OAAO,CAAC,CAAA;AACR,KAAK,CAAC,CAAA;AACN,GAAE;AACF;AACA,EAAE,OAAO;AACT,IAAI,CAAC,EAAE,MAAM;AACb,IAAI,GAAG;AACP,IAAI,KAAK;AACT,GAAG,CAAA;AACH;;;;"}