type PendingMessage = ReturnType< typeof Promise.withResolvers> >; export class AsyncMessageQueue implements AsyncIterable, AsyncIterator { readonly #messages: string[] = []; readonly #waiters: PendingMessage[] = []; #closed = false; [Symbol.asyncIterator](): AsyncIterator { return this; } close(): void { if (this.#closed) { return; } this.#closed = true; for (const waiter of this.#waiters.splice(0)) { waiter.resolve({ done: true, value: undefined }); } } next(): Promise> { const message = this.#messages.shift(); if (message !== undefined) { return Promise.resolve({ done: false, value: message }); } if (this.#closed) { return Promise.resolve({ done: true, value: undefined }); } const waiter = Promise.withResolvers>(); this.#waiters.push(waiter); return waiter.promise; } push(message: string): void { const waiter = this.#waiters.shift(); if (waiter) { waiter.resolve({ done: false, value: message }); } else { this.#messages.push(message); } } }