UNPKG

evnty

Version:

Async-first, reactive event handling library for complex event flows in browser and Node.js

165 lines (164 loc) 5.73 kB
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; }