Merge branch 'development' into sse-and-backoff
This commit is contained in:
@@ -23,24 +23,31 @@
|
||||
*/
|
||||
export class AsyncPushIterator<T> {
|
||||
/** ReadableStream backing the async iterator returned from {@link Symbol.asyncIterator}. */
|
||||
private readonly stream: ReadableStream<T>;
|
||||
#stream: ReadableStream<T>;
|
||||
|
||||
/** Controller used to enqueue values and close the stream from {@link push} and {@link close}. */
|
||||
private controller: ReadableStreamDefaultController<T> | undefined;
|
||||
#controller: ReadableStreamDefaultController<T> | undefined;
|
||||
|
||||
/** When true, no more values are accepted and iteration eventually completes. */
|
||||
public closed = false;
|
||||
#closed = false;
|
||||
|
||||
public constructor() {
|
||||
// `start`'s `this` is the underlying source object when using a plain method.
|
||||
// An arrow function captures the class instance so the controller is stored here.
|
||||
this.stream = new ReadableStream({
|
||||
this.#stream = new ReadableStream({
|
||||
start: (controller: ReadableStreamDefaultController<T>): void => {
|
||||
this.controller = controller;
|
||||
this.#controller = controller;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Flag indicating if the iterator is closed.
|
||||
*/
|
||||
public get closed(): boolean {
|
||||
return this.#closed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueues a value for the consumer.
|
||||
*
|
||||
@@ -49,9 +56,22 @@ export class AsyncPushIterator<T> {
|
||||
* @param value - The next value to yield from the iterator.
|
||||
*/
|
||||
push(value: T): void {
|
||||
if (this.closed) return;
|
||||
if (this.#closed) return;
|
||||
|
||||
this.controller?.enqueue(value);
|
||||
this.#controller?.enqueue(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Causes any future interactions with the associated stream to error with {@link error}.
|
||||
* Calling this will also clear the pending values immediately, so iterators that were listening will not receive them.
|
||||
*
|
||||
* @param error - The error to throw from the stream.
|
||||
*/
|
||||
error(error: Error): void {
|
||||
if (this.#closed) return;
|
||||
|
||||
this.#closed = true;
|
||||
this.#controller?.error(error);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -61,10 +81,10 @@ export class AsyncPushIterator<T> {
|
||||
* Buffered values are still yielded before iteration completes.
|
||||
*/
|
||||
close(): void {
|
||||
this.closed = true;
|
||||
this.#closed = true;
|
||||
|
||||
try {
|
||||
this.controller?.close();
|
||||
this.#controller?.close();
|
||||
} catch {
|
||||
// The reader may already have released or cancelled the stream.
|
||||
}
|
||||
@@ -75,8 +95,11 @@ export class AsyncPushIterator<T> {
|
||||
*
|
||||
* Uses `preventCancel: true` so early `break` from `for await...of` does not
|
||||
* close the stream and block later pushes.
|
||||
*
|
||||
* Because values are discarded after being read, only a single consumer is supported.
|
||||
* Additional consumers will receive a stream lock error. Unread values will be preserved until {@link close} is called.
|
||||
*/
|
||||
[Symbol.asyncIterator](): AsyncIterableIterator<T> {
|
||||
return this.stream.values({ preventCancel: true });
|
||||
return this.#stream.values({ preventCancel: true });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
export * from './async-push-iterator.ts';
|
||||
export * from './types.ts';
|
||||
export * from './sse-session.ts';
|
||||
export * from './sse-event-parser.ts';
|
||||
|
||||
Reference in New Issue
Block a user