/** * Creates a typed synchronous event emitter and returns it as an `EmitterInterface`, * wiring the initial `on` hooks and the `error` handler its options carry. * * @remarks * Entities that own an emitter construct `new Emitter(...)` for their `#emitter` * field directly; this factory is the standalone entry point. * * @typeParam TMap - The event map: each event name to its listener argument tuple. * @param options - Optional `on` hooks (initial listeners wired at construction) and * an optional `error` handler for a listener's throw * @returns A typed {@link EmitterInterface} * * @example Standalone emitter * ```ts * import { createEmitter } from '@orkestrel/emitter' * * type DownloadEventMap = { * chunk: readonly [bytes: number] * done: readonly [] * } * * const emitter = createEmitter() * emitter.on('chunk', (bytes) => accumulate(bytes)) * emitter.once('done', () => finish()) * emitter.emit('chunk', 1024) * emitter.emit('done') * ``` */ export declare function createEmitter(options?: EmitterOptions): EmitterInterface; /** * Implements `EmitterInterface` over one listener `Set` per event, so every public method is * precisely typed with no assertion. A stateful entity owns one as a `#emitter` field and * exposes it through `readonly emitter`; it never inherits from it. * * @typeParam TMap - The event map: each event name to the argument tuple its * listeners receive. * * @remarks * - **Synchronous.** `emit` invokes listeners in registration order, in the * current tick. * - **Listener isolation.** A throwing listener never stops its siblings: every * listener runs, and a throw is routed to the `error` handler * ({@link EmitterOptions.error}) — never rethrown. Every throwing listener * surfaces (not only the first), and with no `error` handler a throw is swallowed * silently. The `error` handler runs inside its own try/catch, so a throwing * error-handler is swallowed too (anti-recursion — it cannot escape or re-enter). * - **Destroyed → no-op.** After `destroy()`, `on` / `once` / `emit` do nothing * and `destroyed` is `true`. * * @example * ```ts * type CounterEventMap = { * tick: readonly [count: number] * done: readonly [] * } * * const emitter = new Emitter({ * on: { done: () => stop() }, * error: (error, event) => log(`listener for ${event} threw`, error), * }) * emitter.on('tick', (count) => render(count)) * emitter.emit('tick', 1) * ``` */ export declare class Emitter implements EmitterInterface { #private; constructor(options?: EmitterOptions); get destroyed(): boolean; on(event: K, handler: EmitterHandler): void; once(event: K, handler: EmitterHandler): void; off(event: K, handler: EmitterHandler): void; emit(event: K, ...args: TMap[K]): void; count(event?: keyof TMap): number; clear(event?: keyof TMap): void; destroy(): void; } /** * Represents the emitter's own listener-error handler — the `error` option, invoked when a * listener throws during `emit`, with the caught error and the stringified event name. * * @remarks * This is machinery, NOT a domain event: a throwing listener is isolated by the * emitter and its error routed here, never onto the entity's `EventMap`. An entity * exposes it by threading `EmitterOptions.error` (beside `on`) into its `#emitter`. * The handler runs inside its own try/catch, so a throwing error-handler is swallowed * (anti-recursion) — it can neither escape nor re-enter the emit loop. */ export declare type EmitterErrorHandler = (error: unknown, event: string) => void; /** Represents a listener for one event's argument tuple. */ export declare type EmitterHandler = (...args: TArgs) => void; /** * Declares the initial event listeners for an emitter — the reserved `on` option: a partial map * of event name to its handler, wired at construction. */ export declare type EmitterHooks = { readonly [K in keyof TMap]?: EmitterHandler; }; /** * Represents the contract a consumer of an emitter holds: the `destroyed` reading, the * `on` / `once` / `off` registration trio, the synchronous `emit`, and the * `count` / `clear` / `destroy` set that reports on and releases listeners. */ export declare interface EmitterInterface { /** Reports the teardown state: true after `destroy()`; false otherwise. */ readonly destroyed: boolean; /** * Registers a listener for an event. Does nothing after `destroy()`. * * @param event - The event to listen for. * @param handler - The listener invoked with the event's argument tuple. */ on(event: K, handler: EmitterHandler): void; /** * Registers a listener that removes itself after its first call. Does nothing after * `destroy()`. * * @param event - The event to listen for. * @param handler - The listener invoked with the event's argument tuple, once. */ once(event: K, handler: EmitterHandler): void; /** * Removes a listener registered for an event by its original handler, including one * registered through `once`. * * @param event - The event to unregister from. * @param handler - The original handler passed to `on` or `once`, never a `once` wrapper. */ off(event: K, handler: EmitterHandler): void; /** * Invokes an event's listeners synchronously, in registration order, isolating a throw. * Does nothing after `destroy()`. * * @remarks * Every listener runs, and an isolated throw routes to {@link EmitterOptions.error} * rather than being rethrown. The listeners are snapshotted before the loop, so one * registered during this call does not run in it. * * @param event - The event to fire. * @param args - The argument tuple the event's listeners receive. */ emit(event: K, ...args: TMap[K]): void; /** * Returns the live listener count, for one event or across every event. * * @param event - The event to count listeners for. Omit to count across every event. * @returns The number of registered listeners. */ count(event?: keyof TMap): number; /** * Drops registered listeners, for one event or every event, leaving the emitter usable and * `destroyed` unchanged. * * @param event - The event to clear. Omit to clear every event. */ clear(event?: keyof TMap): void; /** Tears down the emitter: drops every listener and sets `destroyed` to `true`. Idempotent. */ destroy(): void; } /** Configures `createEmitter` and the `Emitter` constructor. */ export declare interface EmitterOptions { readonly on?: EmitterHooks; /** * Holds the emitter's listener-error handler — a throw from ANY listener during `emit` is * routed here (with the error + the event name) instead of being rethrown. Omit it * and a listener throw is swallowed silently. */ readonly error?: EmitterErrorHandler; } /** Maps each event name to the argument tuple its listeners receive. */ export declare type EventMap = Record; /** * Extracts the own enumerable keys of a mapped object, typed as its key union. * * @remarks * `Object.keys` widens its result to `string[]`, which breaks the key↔value * correlation a mapped type (like `EmitterHooks`) otherwise guarantees. * A `for…in` push into a `keyof`-typed array narrows the result back, * type-safely and with no assertion. Inherited enumerable keys are excluded, as * `Object.keys` excludes them. * * @typeParam T - The object shape whose keys are extracted. * @param object - The object to read keys from. * @returns The object's own enumerable keys, typed as `ReadonlyArray`. * * @example * ```ts * import { extractKeys } from '@src/core' * * const hooks = { tick: () => {}, done: () => {} } * extractKeys(hooks) // ['tick', 'done'] * extractKeys({}) // [] * ``` */ export declare function extractKeys(object: T): ReadonlyArray; export { }