evnty
Version:
Async-first, reactive event handling library for complex event flows in browser and Node.js
165 lines (164 loc) • 5.73 kB
TypeScript
import { Signal } from './signal.js';
import { Action, Fn, Emitter, MaybePromise, Promiseable } from './types.js';
/**
* A handle representing a consumer's position in a Broadcast.
* Returned by `Broadcast.join()` and used to consume values.
* Implements Disposable for automatic cleanup via `using` keyword.
*
* @example
* ```typescript
* const broadcast = new Broadcast<number>();
* using handle = broadcast.join();
* broadcast.emit(42);
* const value = broadcast.consume(handle); // 42
* ```
*/
export declare class ConsumerHandle<T> implements Disposable {
#private;
constructor(broadcast: Broadcast<T>);
/**
* The current position of this consumer in the buffer.
*/
get cursor(): number;
/**
* Leaves the broadcast, releasing this consumer's position.
*/
[Symbol.dispose](): void;
}
/**
* @internal
*/
export declare class BroadcastIterator<T> implements AsyncIterator<T, void, void> {
#private;
constructor(broadcast: Broadcast<T>, signal: Signal<T>, handle: ConsumerHandle<T>);
next(): Promise<IteratorResult<T, void>>;
return(): Promise<IteratorResult<T, void>>;
}
/**
* A multi-consumer FIFO queue where each consumer maintains its own read position.
* Values are buffered and each consumer can read them independently at their own pace.
* The buffer automatically compacts when all consumers have read past a position.
*
* Key characteristics:
* - Multiple consumers - each gets their own cursor position
* - Buffered delivery - values are stored until all consumers read them
* - Late joiners only see values emitted after joining
* - Automatic cleanup via FinalizationRegistry when handles are garbage collected
*
* Differs from:
* - Event: Broadcast buffers values, Event does not
* - Sequence: Broadcast supports multiple consumers, Sequence is single-consumer
* - Signal: Broadcast buffers values, Signal only notifies current waiters
*
* @template T - The type of values in the broadcast
*
* @example
* ```typescript
* const broadcast = new Broadcast<number>();
*
* const handle1 = broadcast.join();
* const handle2 = broadcast.join();
*
* broadcast.emit(1);
* broadcast.emit(2);
*
* broadcast.consume(handle1); // 1
* broadcast.consume(handle2); // 1
* broadcast.consume(handle1); // 2
* ```
*/
export declare class Broadcast<T> implements Emitter<T, boolean>, Promiseable<T>, Promise<T>, Disposable, AsyncIterable<T> {
#private;
readonly [Symbol.toStringTag] = "Broadcast";
constructor();
/**
* Returns a bound emit function for use as a callback.
*/
get sink(): Fn<[T], boolean>;
/**
* DOM EventListener interface compatibility.
*/
handleEvent(event: T): void;
/**
* The number of active consumers.
*/
get size(): number;
/**
* Emits a value to all consumers. The value is buffered for consumption.
*
* @param value - The value to emit.
* @returns `true` if the value was emitted.
*/
emit(value: T): boolean;
/**
* Waits for the next emitted value without joining as a consumer.
* Does not buffer - only receives values emitted after calling.
*
* @returns A promise that resolves with the next emitted value.
*/
receive(): Promise<T>;
then<OK = T, ERR = never>(onfulfilled?: Fn<[T], MaybePromise<OK>> | null, onrejected?: Fn<[unknown], MaybePromise<ERR>> | null): Promise<OK | ERR>;
catch<ERR = never>(onrejected?: Fn<[unknown], MaybePromise<ERR>> | null): Promise<T | ERR>;
finally(onfinally?: Action | null): Promise<T>;
/**
* Joins the broadcast as a consumer. Returns a handle used to consume values.
* The consumer starts at the current buffer position and will only see
* values emitted after joining.
*
* @example
* ```typescript
* const handle = broadcast.join();
* // Use handle with consume(), readable(), leave()
* ```
*/
join(): ConsumerHandle<T>;
/**
* Gets the current cursor position for a consumer handle.
*
* @param handle - The consumer handle.
* @returns The cursor position.
* @throws If the handle is invalid (already left or never joined).
*/
getCursor(handle: ConsumerHandle<T>): number;
/**
* Removes a consumer from the broadcast. The handle becomes invalid after this call.
* Idempotent - calling multiple times has no effect.
*
* @param handle - The consumer handle to remove.
*/
leave(handle: ConsumerHandle<T>): void;
/**
* Consumes and returns the next value for a consumer.
* Advances the consumer's cursor position.
*
* @param handle - The consumer handle.
* @throws If no value is available or the handle is invalid.
*
* @example
* ```typescript
* if (broadcast.readable(handle)) {
* const value = broadcast.consume(handle);
* }
* ```
*/
consume(handle: ConsumerHandle<T>): T;
/**
* Attempts to consume the next value for a consumer.
* Returns `{ done: true }` when no value is currently available.
*
* @param handle - The consumer handle.
* @returns The next value, or `{ done: true }` when nothing is available.
* @throws If the handle is invalid.
*/
tryConsume(handle: ConsumerHandle<T>): IteratorResult<T, void>;
/**
* Checks if there are values available for a consumer to read.
*
* @param handle - The consumer handle.
* @returns `true` if there are unread values, `false` otherwise.
*/
readable(handle: ConsumerHandle<T>): boolean;
[Symbol.asyncIterator](): AsyncIterator<T, void, void>;
dispose(): void;
[Symbol.dispose](): void;
}