UNPKG

@atproto/common-web

Version:

Shared web-platform-friendly code for atproto libraries

209 lines 6.25 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.AsyncBufferFullError = exports.AsyncBuffer = exports.allComplete = exports.createDeferrables = exports.createDeferrable = exports.readFromGenerator = void 0; exports.allFulfilled = allFulfilled; exports.handleAllSettledErrors = handleAllSettledErrors; exports.isRejectedResult = isRejectedResult; exports.isFulfilledResult = isFulfilledResult; const util_1 = require("./util"); // reads values from a generator into a list // breaks when isDone signals `true` AND `waitFor` completes OR when a max length is reached // NOTE: does not signal generator to close. it *will* continue to produce values const readFromGenerator = async (gen, isDone, waitFor = Promise.resolve(), maxLength = Number.MAX_SAFE_INTEGER) => { const evts = []; let bail; let hasBroke = false; const awaitDone = async () => { if (await isDone(evts.at(-1))) { return true; } const bailable = (0, util_1.bailableWait)(20); await bailable.wait(); bail = bailable.bail; if (hasBroke) return false; return await awaitDone(); }; const breakOn = new Promise((resolve) => { waitFor.then(() => { awaitDone().then(() => resolve()); }); }); try { while (evts.length < maxLength) { const maybeEvt = await Promise.race([gen.next(), breakOn]); if (!maybeEvt) break; const evt = maybeEvt; if (evt.done) break; evts.push(evt.value); } } finally { hasBroke = true; bail && bail(); } return evts; }; exports.readFromGenerator = readFromGenerator; const createDeferrable = () => { let resolve; const promise = new Promise((res) => { resolve = () => res(); }); return { resolve, complete: promise }; }; exports.createDeferrable = createDeferrable; const createDeferrables = (count) => { const list = []; for (let i = 0; i < count; i++) { list.push((0, exports.createDeferrable)()); } return list; }; exports.createDeferrables = createDeferrables; const allComplete = async (deferrables) => { await Promise.all(deferrables.map((d) => d.complete)); }; exports.allComplete = allComplete; class AsyncBuffer { constructor(maxSize) { Object.defineProperty(this, "maxSize", { enumerable: true, configurable: true, writable: true, value: maxSize }); Object.defineProperty(this, "buffer", { enumerable: true, configurable: true, writable: true, value: [] }); Object.defineProperty(this, "promise", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "resolve", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "closed", { enumerable: true, configurable: true, writable: true, value: false }); Object.defineProperty(this, "toThrow", { enumerable: true, configurable: true, writable: true, value: void 0 }); // Initializing to satisfy types/build, immediately reset by resetPromise() this.promise = Promise.resolve(); this.resolve = () => null; this.resetPromise(); } get curr() { return this.buffer; } get size() { return this.buffer.length; } get isClosed() { return this.closed; } resetPromise() { this.promise = new Promise((r) => (this.resolve = r)); } push(item) { this.buffer.push(item); this.resolve(); } pushMany(items) { items.forEach((i) => this.buffer.push(i)); this.resolve(); } async *events() { while (true) { if (this.closed && this.buffer.length === 0) { if (this.toThrow) { throw this.toThrow; } else { return; } } await this.promise; if (this.toThrow) { throw this.toThrow; } if (this.maxSize && this.size > this.maxSize) { throw new AsyncBufferFullError(this.maxSize); } const [first, ...rest] = this.buffer; if (first) { this.buffer = rest; yield first; } else { this.resetPromise(); } } } throw(err) { this.toThrow = err; this.closed = true; this.resolve(); } close() { this.closed = true; this.resolve(); } } exports.AsyncBuffer = AsyncBuffer; class AsyncBufferFullError extends Error { constructor(maxSize) { super(`ReachedMaxBufferSize: ${maxSize}`); } } exports.AsyncBufferFullError = AsyncBufferFullError; function allFulfilled(promises) { return Promise.allSettled(promises).then(handleAllSettledErrors); } function handleAllSettledErrors(results) { const errors = results.filter(isRejectedResult).map(extractReason); if (errors.length === 0) { // No need to filter here, it is safe to assume that all promises are fulfilled return results.map(extractValue); } if (errors.length === 1) { throw errors[0]; } throw new AggregateError(errors, `Multiple errors: ${errors.map(stringifyReason).join('\n')}`); } function isRejectedResult(result) { return result.status === 'rejected'; } function extractReason(result) { return result.reason; } function isFulfilledResult(result) { return result.status === 'fulfilled'; } function extractValue(result) { return result.value; } function stringifyReason(reason) { if (reason instanceof Error) { return reason.message; } return String(reason); } //# sourceMappingURL=async.js.map