@nasriya/atomix
Advanced tools
@@ -0,1 +1,2 @@ | ||
| import { Prettify } from "../../docs/docs"; | ||
| export interface EventData { | ||
@@ -42,2 +43,23 @@ name: string; | ||
| } | ||
| export type EventHandler = (...args: any) => any | Promise<any>; | ||
| export type EventHandler = (...args: any[]) => any | Promise<any>; | ||
| export type GlobalEventHandler<TMap> = (eventName: EventName<TMap>, ...args: any) => any | Promise<any>; | ||
| export type EventName<TMap> = Extract<keyof TMap, string>; | ||
| export type IsNever<T> = [T] extends [never] ? true : false; | ||
| export type ProcessorEventsConfigs = { | ||
| /** | ||
| * The name of the emitted event. | ||
| */ | ||
| emittedBy: string; | ||
| /** | ||
| * The internal data of the event. | ||
| */ | ||
| data: EventData; | ||
| /** | ||
| * Whether the events are global or not. | ||
| * @default false | ||
| */ | ||
| isGlobal?: boolean; | ||
| }; | ||
| export type ProcessorMetaData = Prettify<{ | ||
| triggeredBy: ProcessorEventsConfigs['emittedBy']; | ||
| } & Pick<ProcessorEventsConfigs, 'isGlobal'>>; |
@@ -1,11 +0,16 @@ | ||
| import { EventHandler, AddHandlerOptions } from './docs'; | ||
| import type { EventHandler, AddHandlerOptions, EventName, GlobalEventHandler } from './docs'; | ||
| /** | ||
| * A flexible and lightweight event emitter class that supports advanced features like: | ||
| * - `beforeAll` and `afterAll` handler types | ||
| * - One-time (`once`) handlers | ||
| * - Handler limits with overflow detection | ||
| * - Custom max-handler overflow behavior | ||
| * A flexible and lightweight event emitter class with full TypeScript support. | ||
| * | ||
| * This implementation allows both standard event handlers and lifecycle-style hooks around them. | ||
| * Features: | ||
| * - Strongly typed event names and handler arguments using generics (`EventsMap`). | ||
| * - Global `'*'` handlers that receive the event name as the first argument, followed by the event's arguments. | ||
| * - `beforeAll` and `afterAll` handler types for lifecycle-style hooks. | ||
| * - One-time handlers via `on` with `{ once: true }` option (removed automatically after first execution). | ||
| * - Handler limits with overflow detection via `maxTotalHandlers` and custom overflow behavior. | ||
| * - Backward-compatible `maxHandlers` property (deprecated in favor of `maxTotalHandlers`). | ||
| * | ||
| * This implementation allows both standard event handlers and advanced lifecycle hooks, | ||
| * while supporting both typed and untyped usage. | ||
| * | ||
| * @example | ||
@@ -27,2 +32,5 @@ * ```ts | ||
| * | ||
| * // Global handler receives the event name first | ||
| * emitter.on(`'*'`, (event, ...args) => console.log(`Global: ${event}`, args)); | ||
| * | ||
| * // Emit the event | ||
@@ -34,16 +42,23 @@ * await emitter.emit('data', 42); | ||
| * ```ts | ||
| * // Custom behavior when handler count exceeds limit | ||
| * emitter.maxHandlers = 2; | ||
| * emitter.onMaxHandlers((eventName) => { | ||
| * throw new Error(`Handler overflow on ${eventName}`); | ||
| * }); | ||
| * const emitter = new atomix.tools.EventEmitter(); | ||
| * | ||
| * // Option 1: Throw an Error immediately when the limit is exceeded | ||
| * emitter.maxTotalHandlers = 2; | ||
| * emitter.onMaxHandlers(new Error('Handler limit exceeded')); | ||
| * | ||
| * emitter.on('load', () => {}); | ||
| * emitter.on('load', () => {}); | ||
| * emitter.on('load', () => {}); // throws | ||
| * emitter.on('load', () => {}); // throws immediately | ||
| * | ||
| * // Option 2: Use a custom function to handle overflows (debounced) | ||
| * emitter.onMaxHandlers((eventName) => { | ||
| * console.warn(`Handler overflow on event: ${eventName}`); | ||
| * }); | ||
| * ``` | ||
| * | ||
| * @template EventsMap - Optional type map for event names and handler signatures. Defaults to `{}` for untyped usage. | ||
| * | ||
| * @since v1.0.8 | ||
| */ | ||
| export declare class EventEmitter { | ||
| export declare class EventEmitter<EventsMap extends Record<string, EventHandler> = {}> { | ||
| #private; | ||
@@ -53,2 +68,13 @@ /** | ||
| * | ||
| * This method supports both **typed** and **untyped** emitters: | ||
| * | ||
| * - In a **typed emitter** (`EventEmitter<{ load: () => void; data: (value: number) => void }>`), | ||
| * the `eventName` parameter is restricted to the keys of the provided map, | ||
| * and the `args` are automatically typed according to the event's parameters. | ||
| * | ||
| * - In an **untyped emitter** (`EventEmitter` with default `{}`), `eventName` can be any string, | ||
| * and `args` are of type `any[]`. | ||
| * | ||
| * Global (`'*'`) handlers are triggered on every emit and receive the actual event name as the first argument. | ||
| * | ||
| * Handlers are invoked in the following order for each `emit` call: | ||
@@ -59,16 +85,11 @@ * 1. The `beforeAll` handler (if set) runs before all `normal` handlers. | ||
| * | ||
| * `beforeAll` and `afterAll` are special singleton handlers — only one of each | ||
| * may be set per event name. They are not removed automatically and are executed | ||
| * on every `emit` call. | ||
| * `beforeAll` and `afterAll` are singleton handlers — only one of each may be set per event name. | ||
| * They are not removed automatically and are executed on every `emit` call. | ||
| * | ||
| * `normal` handlers may be marked as `once`, in which case they will be removed | ||
| * after their first invocation. | ||
| * `normal` handlers may be marked as `once`, in which case they are removed after their first invocation. | ||
| * | ||
| * Global (`'*'`) handlers are triggered on every emit and receive the actual event | ||
| * name as their first argument. | ||
| * @template E - The event name type; inferred automatically. | ||
| * @param eventName - The name of the event to emit, or `'*'` for global handlers. Must be a non-empty string. | ||
| * @param args - Arguments to pass to all applicable handlers. Automatically typed for typed emitters. | ||
| * | ||
| * @async | ||
| * @param eventName - The name of the event to emit. Must be a non-empty string. | ||
| * @param args - Arguments to pass to all applicable handler functions. | ||
| * | ||
| * @throws {TypeError} If the event name is not a string. | ||
@@ -78,46 +99,69 @@ * @throws {RangeError} If the event name is an empty string. | ||
| * @example | ||
| * ```ts | ||
| * // Untyped emitter | ||
| * const emitter = new EventEmitter(); | ||
| * emitter.on('*', (event, ...args) => console.log(`Global: ${event}`, args)); | ||
| * await emitter.emit('load', true); | ||
| * | ||
| * emitter.on('data', (value) => console.log('Normal:', value)); | ||
| * emitter.on('data', () => console.log('Before All'), { type: 'beforeAll' }); | ||
| * emitter.on('data', () => console.log('After All'), { type: 'afterAll' }); | ||
| * | ||
| * await emitter.emit('data', 123); | ||
| * // Output: | ||
| * // Before All | ||
| * // Normal: 123 | ||
| * // After All | ||
| * ``` | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * emitter.on('*', (event, ...args) => { | ||
| * console.log(`Global handler: ${event}`, args); | ||
| * }); | ||
| * // Typed emitter | ||
| * type MyEvents = { load: (ok: boolean) => void; data: (value: number) => void }; | ||
| * const typedEmitter = new EventEmitter<MyEvents>(); | ||
| * typedEmitter.on('data', (value) => console.log('Data:', value)); | ||
| * typedEmitter.on('*', (event, ...args) => console.log(`Global: ${event}`, args)); | ||
| * await typedEmitter.emit('data', 42); // value typed as number | ||
| * | ||
| * await emitter.emit('load', true); | ||
| * // Output: | ||
| * // Global handler: load [true] | ||
| * ``` | ||
| * | ||
| * @since v1.0.8 | ||
| */ | ||
| emit(eventName: string, ...args: any): Promise<void>; | ||
| emit<E extends EventName<EventsMap>>(eventName: [E] extends [never] ? string : E, ...args: [E] extends [never] ? any[] : Parameters<EventsMap[E]>): Promise<void>; | ||
| /** | ||
| * Adds a handler to an event. | ||
| * | ||
| * @param eventName - The name of the event to add the handler to. | ||
| * @param handler - The handler function to add. | ||
| * @param options - (Optional) Additional configuration options for the handler. If not provided, defaults to `{ once: false, type: 'normal' }`. | ||
| * @param options.once - (Optional) If true, the handler is removed after being called once. Defaults to false. | ||
| * @param options.type - (Optional) The type of event handler to add. One of "before", "after", or "normal". Defaults to "normal". | ||
| * This method supports both **typed** and **untyped** event emitters: | ||
| * | ||
| * @throws {TypeError} Throws if the event name is not a string or the handler is not a function. | ||
| * @throws {RangeError} Throws if the event name is an empty string or the type is not a valid event type. | ||
| * - In a **typed emitter** (`EventEmitter<{ load: () => void; data: (value: number) => void }>`), | ||
| * the `eventName` parameter is restricted to the keys of the provided map, | ||
| * and the `handler` function is automatically typed according to the event's parameters. | ||
| * | ||
| * @returns The EventEmitter instance. | ||
| * - In an **untyped emitter** (`EventEmitter` with default `{}`), `eventName` can be any string. | ||
| * | ||
| * Special support for `'*'` allows registering a **global handler** that listens to all events: | ||
| * - The `handler` receives the actual event name as the first argument. | ||
| * - This works for both typed and untyped emitters. | ||
| * | ||
| * Handler types: | ||
| * - `"normal"`: Runs on every emit (default) | ||
| * - `"beforeAll"`: Runs before all normal handlers for the event | ||
| * - `"afterAll"`: Runs after all normal handlers for the event | ||
| * | ||
| * @template E - The event name type; inferred automatically. | ||
| * @param eventName - The name of the event to add the handler to, or `'*'` for a global handler. | ||
| * @param handler - The handler function for the event: | ||
| * - For specific events, receives the event parameters. | ||
| * - For `'*'`, receives the event name followed by its parameters. | ||
| * @param options - Optional configuration for the handler. Defaults to `{ once: false, type: 'normal' }`. | ||
| * @param options.once - If true, the handler is removed after being called once. | ||
| * @param options.type - The type of handler. One of `"normal"`, `"beforeAll"`, or `"afterAll"`. | ||
| * | ||
| * @throws {TypeError} If `eventName` is not a string, or `handler` is not a function. | ||
| * @throws {RangeError} If `eventName` is an empty string, or `options.type` is invalid. | ||
| * | ||
| * @returns The EventEmitter instance, allowing method chaining. | ||
| * | ||
| * @example | ||
| * // Untyped emitter | ||
| * const emitter = new EventEmitter(); | ||
| * emitter.on('*', (event, ...args) => { | ||
| * console.log(`Event "${event}" emitted with args:`, args); | ||
| * }); | ||
| * | ||
| * @example | ||
| * // Typed emitter | ||
| * type MyEvents = { load: (ok: boolean) => void; data: (value: number) => void }; | ||
| * const typedEmitter = new EventEmitter<MyEvents>(); | ||
| * typedEmitter.on('data', (value) => console.log('Data:', value)); | ||
| * typedEmitter.on('*', (event, ...args) => console.log(`Event "${event}"`, args)); | ||
| * | ||
| * @since v1.0.8 | ||
| */ | ||
| on(eventName: string, handler: EventHandler, options?: AddHandlerOptions): this; | ||
| on<E extends EventName<EventsMap> | '*'>(eventName: [Exclude<E, '*'>] extends [never] ? string : E, handler: E extends '*' ? GlobalEventHandler<EventsMap> : EventsMap[E], options?: AddHandlerOptions): this; | ||
| /** | ||
@@ -128,7 +172,23 @@ * Registers a custom handler for the "max handlers exceeded" event. | ||
| * | ||
| * The handler is debounced to prevent excessive calls when the maximum number of handlers is exceeded multiple times in quick succession. | ||
| * - If a **function** is provided, it is debounced (100ms) to prevent excessive calls during rapid handler additions. | ||
| * - If an **Error** object is provided, it will be thrown immediately when the limit is exceeded. | ||
| * | ||
| * @param handler - A function to call when the maximum number of handlers is exceeded or an error to throw. | ||
| * @returns The EventEmitter instance. | ||
| * @throws {TypeError} If the handler is not a function or an error. | ||
| * @param handler - A function to call when the maximum number of handlers is exceeded, or an Error to throw. | ||
| * @returns The EventEmitter instance, allowing method chaining. | ||
| * | ||
| * @throws {TypeError} If the handler is not a function or an Error instance. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * const emitter = new atomix.tools.EventEmitter(); | ||
| * | ||
| * // Throw an error when the max handlers limit is exceeded | ||
| * emitter.onMaxHandlers(new Error('Handler limit exceeded')); | ||
| * | ||
| * // Or provide a custom function | ||
| * emitter.onMaxHandlers((eventName) => { | ||
| * console.warn(`Handler overflow on event: ${eventName}`); | ||
| * }); | ||
| * ``` | ||
| * | ||
| * @since v1.0.8 | ||
@@ -156,2 +216,23 @@ */ | ||
| * @returns {number} The maximum number of handlers. A positive integer or Infinity. | ||
| * @since v1.0.24 | ||
| */ | ||
| get maxTotalHandlers(): number; | ||
| /** | ||
| * Sets the maximum number of event handlers allowed for this EventEmitter instance. | ||
| * | ||
| * The value must be a positive integer or Infinity. If set to Infinity, there is no limit to the number of handlers. | ||
| * | ||
| * @param {number} value The maximum number of handlers. Must be a positive integer or Infinity. | ||
| * @throws {TypeError} If the provided value is not a number or not an integer. | ||
| * @throws {RangeError} If the provided value is not greater than 0. | ||
| * @since v1.0.24 | ||
| */ | ||
| set maxTotalHandlers(value: number); | ||
| /** | ||
| * Retrieves the maximum number of event handlers allowed for this EventEmitter instance. | ||
| * | ||
| * The value is a positive integer or Infinity. If set to Infinity, there is no limit to the number of handlers. | ||
| * | ||
| * @returns {number} The maximum number of handlers. A positive integer or Infinity. | ||
| * @deprecated Use {@link maxTotalHandlers} getter/setter instead. | ||
| * @since v1.0.8 | ||
@@ -168,2 +249,3 @@ */ | ||
| * @throws {RangeError} If the provided value is not greater than 0. | ||
| * @deprecated Use {@link maxTotalHandlers} getter/setter instead. | ||
| * @since v1.0.8 | ||
@@ -170,0 +252,0 @@ */ |
@@ -121,3 +121,3 @@ import AdaptiveTaskQueue from "./queues/AdaptiveTaskQueue"; | ||
| * // Custom behavior when handler count exceeds limit | ||
| * emitter.maxHandlers = 2; | ||
| * emitter.maxTotalHandlers = 2; | ||
| * emitter.onMaxHandlers((eventName) => { | ||
@@ -124,0 +124,0 @@ * throw new Error(`Handler overflow on ${eventName}`); |
@@ -11,10 +11,15 @@ "use strict"; | ||
| /** | ||
| * A flexible and lightweight event emitter class that supports advanced features like: | ||
| * - `beforeAll` and `afterAll` handler types | ||
| * - One-time (`once`) handlers | ||
| * - Handler limits with overflow detection | ||
| * - Custom max-handler overflow behavior | ||
| * A flexible and lightweight event emitter class with full TypeScript support. | ||
| * | ||
| * This implementation allows both standard event handlers and lifecycle-style hooks around them. | ||
| * Features: | ||
| * - Strongly typed event names and handler arguments using generics (`EventsMap`). | ||
| * - Global `'*'` handlers that receive the event name as the first argument, followed by the event's arguments. | ||
| * - `beforeAll` and `afterAll` handler types for lifecycle-style hooks. | ||
| * - One-time handlers via `on` with `{ once: true }` option (removed automatically after first execution). | ||
| * - Handler limits with overflow detection via `maxTotalHandlers` and custom overflow behavior. | ||
| * - Backward-compatible `maxHandlers` property (deprecated in favor of `maxTotalHandlers`). | ||
| * | ||
| * This implementation allows both standard event handlers and advanced lifecycle hooks, | ||
| * while supporting both typed and untyped usage. | ||
| * | ||
| * @example | ||
@@ -36,2 +41,5 @@ * ```ts | ||
| * | ||
| * // Global handler receives the event name first | ||
| * emitter.on(`'*'`, (event, ...args) => console.log(`Global: ${event}`, args)); | ||
| * | ||
| * // Emit the event | ||
@@ -43,13 +51,20 @@ * await emitter.emit('data', 42); | ||
| * ```ts | ||
| * // Custom behavior when handler count exceeds limit | ||
| * emitter.maxHandlers = 2; | ||
| * emitter.onMaxHandlers((eventName) => { | ||
| * throw new Error(`Handler overflow on ${eventName}`); | ||
| * }); | ||
| * const emitter = new atomix.tools.EventEmitter(); | ||
| * | ||
| * // Option 1: Throw an Error immediately when the limit is exceeded | ||
| * emitter.maxTotalHandlers = 2; | ||
| * emitter.onMaxHandlers(new Error('Handler limit exceeded')); | ||
| * | ||
| * emitter.on('load', () => {}); | ||
| * emitter.on('load', () => {}); | ||
| * emitter.on('load', () => {}); // throws | ||
| * emitter.on('load', () => {}); // throws immediately | ||
| * | ||
| * // Option 2: Use a custom function to handle overflows (debounced) | ||
| * emitter.onMaxHandlers((eventName) => { | ||
| * console.warn(`Handler overflow on event: ${eventName}`); | ||
| * }); | ||
| * ``` | ||
| * | ||
| * @template EventsMap - Optional type map for event names and handler signatures. Defaults to `{}` for untyped usage. | ||
| * | ||
| * @since v1.0.8 | ||
@@ -115,33 +130,42 @@ */ | ||
| }; | ||
| #_runner = { | ||
| processEvents: async (events, ...args) => { | ||
| if (events.handlers.before) { | ||
| await this.#_runner.runHandler(events.handlers.before, events.name, ...args); | ||
| #_processor = { | ||
| process: async (events, ...args) => { | ||
| const { emittedBy, data, isGlobal } = events; | ||
| if (data.handlers.before) { | ||
| await this.#_processor.processHandler(data.handlers.before, { triggeredBy: emittedBy, isGlobal }, ...args); | ||
| } | ||
| // Handle normal events | ||
| for (let i = 0; i < events.handlers.normal.index; i++) { | ||
| const handler = (events.handlers.normal.handlers.get(i) || events.handlers.normal.onceHandlers.get(i)); | ||
| for (let i = 0; i < data.handlers.normal.index; i++) { | ||
| const handler = (data.handlers.normal.handlers.get(i) || data.handlers.normal.onceHandlers.get(i)); | ||
| if (!handler) { | ||
| continue; | ||
| } | ||
| await this.#_runner.runHandler(handler, events.name, ...args); | ||
| await this.#_processor.processHandler(handler, { triggeredBy: emittedBy, isGlobal }, ...args); | ||
| } | ||
| if (events.handlers.after) { | ||
| await this.#_runner.runHandler(events.handlers.after, events.name, ...args); | ||
| if (data.handlers.after) { | ||
| await this.#_processor.processHandler(data.handlers.after, { triggeredBy: emittedBy, isGlobal }, ...args); | ||
| } | ||
| const onceHandlersCount = events.handlers.normal.onceHandlers.size; | ||
| this.#_helpers.updateEventHandlersNum(events, -onceHandlersCount); | ||
| events.handlers.normal.onceHandlers.clear(); | ||
| const onceHandlersCount = data.handlers.normal.onceHandlers.size; | ||
| this.#_helpers.updateEventHandlersNum(data, -onceHandlersCount); | ||
| data.handlers.normal.onceHandlers.clear(); | ||
| }, | ||
| runHandler: async (handler, eventName, ...args) => { | ||
| processHandler: async (handler, meta, ...args) => { | ||
| const triggeredBy = meta.triggeredBy; | ||
| const isGlobal = meta.isGlobal; | ||
| try { | ||
| await handler(...args); | ||
| if (isGlobal) { | ||
| await handler(triggeredBy, ...args); | ||
| } | ||
| else { | ||
| await handler(...args); | ||
| } | ||
| } | ||
| catch (error) { | ||
| this.#_runner.onError(error, eventName); | ||
| this.#_processor.onError(error, meta); | ||
| } | ||
| }, | ||
| onError: (err, eventName) => { | ||
| console.error(`[HandlerError] (${eventName})`, err); | ||
| }, | ||
| onError(error, meta) { | ||
| const errMsg = `[Atomix][EventEmitter:UserHandlerError]: An error occurred while processing event '${meta.triggeredBy}'.`; | ||
| console.error(errMsg, error); | ||
| } | ||
| }; | ||
@@ -151,2 +175,13 @@ /** | ||
| * | ||
| * This method supports both **typed** and **untyped** emitters: | ||
| * | ||
| * - In a **typed emitter** (`EventEmitter<{ load: () => void; data: (value: number) => void }>`), | ||
| * the `eventName` parameter is restricted to the keys of the provided map, | ||
| * and the `args` are automatically typed according to the event's parameters. | ||
| * | ||
| * - In an **untyped emitter** (`EventEmitter` with default `{}`), `eventName` can be any string, | ||
| * and `args` are of type `any[]`. | ||
| * | ||
| * Global (`'*'`) handlers are triggered on every emit and receive the actual event name as the first argument. | ||
| * | ||
| * Handlers are invoked in the following order for each `emit` call: | ||
@@ -157,16 +192,11 @@ * 1. The `beforeAll` handler (if set) runs before all `normal` handlers. | ||
| * | ||
| * `beforeAll` and `afterAll` are special singleton handlers — only one of each | ||
| * may be set per event name. They are not removed automatically and are executed | ||
| * on every `emit` call. | ||
| * `beforeAll` and `afterAll` are singleton handlers — only one of each may be set per event name. | ||
| * They are not removed automatically and are executed on every `emit` call. | ||
| * | ||
| * `normal` handlers may be marked as `once`, in which case they will be removed | ||
| * after their first invocation. | ||
| * `normal` handlers may be marked as `once`, in which case they are removed after their first invocation. | ||
| * | ||
| * Global (`'*'`) handlers are triggered on every emit and receive the actual event | ||
| * name as their first argument. | ||
| * @template E - The event name type; inferred automatically. | ||
| * @param eventName - The name of the event to emit, or `'*'` for global handlers. Must be a non-empty string. | ||
| * @param args - Arguments to pass to all applicable handlers. Automatically typed for typed emitters. | ||
| * | ||
| * @async | ||
| * @param eventName - The name of the event to emit. Must be a non-empty string. | ||
| * @param args - Arguments to pass to all applicable handler functions. | ||
| * | ||
| * @throws {TypeError} If the event name is not a string. | ||
@@ -176,27 +206,15 @@ * @throws {RangeError} If the event name is an empty string. | ||
| * @example | ||
| * ```ts | ||
| * // Untyped emitter | ||
| * const emitter = new EventEmitter(); | ||
| * emitter.on('*', (event, ...args) => console.log(`Global: ${event}`, args)); | ||
| * await emitter.emit('load', true); | ||
| * | ||
| * emitter.on('data', (value) => console.log('Normal:', value)); | ||
| * emitter.on('data', () => console.log('Before All'), { type: 'beforeAll' }); | ||
| * emitter.on('data', () => console.log('After All'), { type: 'afterAll' }); | ||
| * | ||
| * await emitter.emit('data', 123); | ||
| * // Output: | ||
| * // Before All | ||
| * // Normal: 123 | ||
| * // After All | ||
| * ``` | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * emitter.on('*', (event, ...args) => { | ||
| * console.log(`Global handler: ${event}`, args); | ||
| * }); | ||
| * // Typed emitter | ||
| * type MyEvents = { load: (ok: boolean) => void; data: (value: number) => void }; | ||
| * const typedEmitter = new EventEmitter<MyEvents>(); | ||
| * typedEmitter.on('data', (value) => console.log('Data:', value)); | ||
| * typedEmitter.on('*', (event, ...args) => console.log(`Global: ${event}`, args)); | ||
| * await typedEmitter.emit('data', 42); // value typed as number | ||
| * | ||
| * await emitter.emit('load', true); | ||
| * // Output: | ||
| * // Global handler: load [true] | ||
| * ``` | ||
| * | ||
| * @since v1.0.8 | ||
@@ -214,6 +232,6 @@ */ | ||
| if (namedEvents) { | ||
| await this.#_runner.processEvents(namedEvents, ...args); | ||
| await this.#_processor.process({ emittedBy: eventName, data: namedEvents }, ...args); | ||
| } | ||
| if (globalEvents) { | ||
| await this.#_runner.processEvents(globalEvents, ...args); | ||
| await this.#_processor.process({ emittedBy: eventName, data: globalEvents, isGlobal: true }, ...args); | ||
| } | ||
@@ -224,12 +242,47 @@ } | ||
| * | ||
| * @param eventName - The name of the event to add the handler to. | ||
| * @param handler - The handler function to add. | ||
| * @param options - (Optional) Additional configuration options for the handler. If not provided, defaults to `{ once: false, type: 'normal' }`. | ||
| * @param options.once - (Optional) If true, the handler is removed after being called once. Defaults to false. | ||
| * @param options.type - (Optional) The type of event handler to add. One of "before", "after", or "normal". Defaults to "normal". | ||
| * This method supports both **typed** and **untyped** event emitters: | ||
| * | ||
| * @throws {TypeError} Throws if the event name is not a string or the handler is not a function. | ||
| * @throws {RangeError} Throws if the event name is an empty string or the type is not a valid event type. | ||
| * - In a **typed emitter** (`EventEmitter<{ load: () => void; data: (value: number) => void }>`), | ||
| * the `eventName` parameter is restricted to the keys of the provided map, | ||
| * and the `handler` function is automatically typed according to the event's parameters. | ||
| * | ||
| * @returns The EventEmitter instance. | ||
| * - In an **untyped emitter** (`EventEmitter` with default `{}`), `eventName` can be any string. | ||
| * | ||
| * Special support for `'*'` allows registering a **global handler** that listens to all events: | ||
| * - The `handler` receives the actual event name as the first argument. | ||
| * - This works for both typed and untyped emitters. | ||
| * | ||
| * Handler types: | ||
| * - `"normal"`: Runs on every emit (default) | ||
| * - `"beforeAll"`: Runs before all normal handlers for the event | ||
| * - `"afterAll"`: Runs after all normal handlers for the event | ||
| * | ||
| * @template E - The event name type; inferred automatically. | ||
| * @param eventName - The name of the event to add the handler to, or `'*'` for a global handler. | ||
| * @param handler - The handler function for the event: | ||
| * - For specific events, receives the event parameters. | ||
| * - For `'*'`, receives the event name followed by its parameters. | ||
| * @param options - Optional configuration for the handler. Defaults to `{ once: false, type: 'normal' }`. | ||
| * @param options.once - If true, the handler is removed after being called once. | ||
| * @param options.type - The type of handler. One of `"normal"`, `"beforeAll"`, or `"afterAll"`. | ||
| * | ||
| * @throws {TypeError} If `eventName` is not a string, or `handler` is not a function. | ||
| * @throws {RangeError} If `eventName` is an empty string, or `options.type` is invalid. | ||
| * | ||
| * @returns The EventEmitter instance, allowing method chaining. | ||
| * | ||
| * @example | ||
| * // Untyped emitter | ||
| * const emitter = new EventEmitter(); | ||
| * emitter.on('*', (event, ...args) => { | ||
| * console.log(`Event "${event}" emitted with args:`, args); | ||
| * }); | ||
| * | ||
| * @example | ||
| * // Typed emitter | ||
| * type MyEvents = { load: (ok: boolean) => void; data: (value: number) => void }; | ||
| * const typedEmitter = new EventEmitter<MyEvents>(); | ||
| * typedEmitter.on('data', (value) => console.log('Data:', value)); | ||
| * typedEmitter.on('*', (event, ...args) => console.log(`Event "${event}"`, args)); | ||
| * | ||
| * @since v1.0.8 | ||
@@ -293,7 +346,23 @@ */ | ||
| * | ||
| * The handler is debounced to prevent excessive calls when the maximum number of handlers is exceeded multiple times in quick succession. | ||
| * - If a **function** is provided, it is debounced (100ms) to prevent excessive calls during rapid handler additions. | ||
| * - If an **Error** object is provided, it will be thrown immediately when the limit is exceeded. | ||
| * | ||
| * @param handler - A function to call when the maximum number of handlers is exceeded or an error to throw. | ||
| * @returns The EventEmitter instance. | ||
| * @throws {TypeError} If the handler is not a function or an error. | ||
| * @param handler - A function to call when the maximum number of handlers is exceeded, or an Error to throw. | ||
| * @returns The EventEmitter instance, allowing method chaining. | ||
| * | ||
| * @throws {TypeError} If the handler is not a function or an Error instance. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * const emitter = new atomix.tools.EventEmitter(); | ||
| * | ||
| * // Throw an error when the max handlers limit is exceeded | ||
| * emitter.onMaxHandlers(new Error('Handler limit exceeded')); | ||
| * | ||
| * // Or provide a custom function | ||
| * emitter.onMaxHandlers((eventName) => { | ||
| * console.warn(`Handler overflow on event: ${eventName}`); | ||
| * }); | ||
| * ``` | ||
| * | ||
| * @since v1.0.8 | ||
@@ -348,5 +417,5 @@ */ | ||
| * @returns {number} The maximum number of handlers. A positive integer or Infinity. | ||
| * @since v1.0.8 | ||
| * @since v1.0.24 | ||
| */ | ||
| get maxHandlers() { return this.#_stats.handlers.max; } | ||
| get maxTotalHandlers() { return this.#_stats.handlers.max; } | ||
| /** | ||
@@ -360,7 +429,7 @@ * Sets the maximum number of event handlers allowed for this EventEmitter instance. | ||
| * @throws {RangeError} If the provided value is not greater than 0. | ||
| * @since v1.0.8 | ||
| * @since v1.0.24 | ||
| */ | ||
| set maxHandlers(value) { | ||
| set maxTotalHandlers(value) { | ||
| if (!valueIs_1.default.number(value)) { | ||
| throw new TypeError('maxHandlers must be a number'); | ||
| throw new TypeError('maxTotalHandlers must be a number'); | ||
| } | ||
@@ -372,6 +441,6 @@ if (value === Infinity) { | ||
| if (value <= 0) { | ||
| throw new RangeError('maxHandlers must be greater than 0'); | ||
| throw new RangeError('maxTotalHandlers must be greater than 0'); | ||
| } | ||
| if (!valueIs_1.default.integer(value)) { | ||
| throw new TypeError('maxHandlers must be an integer'); | ||
| throw new TypeError('maxTotalHandlers must be an integer'); | ||
| } | ||
@@ -381,2 +450,26 @@ this.#_stats.handlers.max = value; | ||
| /** | ||
| * Retrieves the maximum number of event handlers allowed for this EventEmitter instance. | ||
| * | ||
| * The value is a positive integer or Infinity. If set to Infinity, there is no limit to the number of handlers. | ||
| * | ||
| * @returns {number} The maximum number of handlers. A positive integer or Infinity. | ||
| * @deprecated Use {@link maxTotalHandlers} getter/setter instead. | ||
| * @since v1.0.8 | ||
| */ | ||
| get maxHandlers() { return this.maxTotalHandlers; } | ||
| /** | ||
| * Sets the maximum number of event handlers allowed for this EventEmitter instance. | ||
| * | ||
| * The value must be a positive integer or Infinity. If set to Infinity, there is no limit to the number of handlers. | ||
| * | ||
| * @param {number} value The maximum number of handlers. Must be a positive integer or Infinity. | ||
| * @throws {TypeError} If the provided value is not a number or not an integer. | ||
| * @throws {RangeError} If the provided value is not greater than 0. | ||
| * @deprecated Use {@link maxTotalHandlers} getter/setter instead. | ||
| * @since v1.0.8 | ||
| */ | ||
| set maxHandlers(value) { | ||
| this.maxTotalHandlers = value; | ||
| } | ||
| /** | ||
| * Retrieves the total number of event handlers registered with this EventEmitter instance. | ||
@@ -383,0 +476,0 @@ * @returns {number} The total number of event handlers. |
@@ -126,3 +126,3 @@ "use strict"; | ||
| * // Custom behavior when handler count exceeds limit | ||
| * emitter.maxHandlers = 2; | ||
| * emitter.maxTotalHandlers = 2; | ||
| * emitter.onMaxHandlers((eventName) => { | ||
@@ -129,0 +129,0 @@ * throw new Error(`Handler overflow on ${eventName}`); |
@@ -5,10 +5,15 @@ import valueIs from '../../valueIs.js'; | ||
| /** | ||
| * A flexible and lightweight event emitter class that supports advanced features like: | ||
| * - `beforeAll` and `afterAll` handler types | ||
| * - One-time (`once`) handlers | ||
| * - Handler limits with overflow detection | ||
| * - Custom max-handler overflow behavior | ||
| * A flexible and lightweight event emitter class with full TypeScript support. | ||
| * | ||
| * This implementation allows both standard event handlers and lifecycle-style hooks around them. | ||
| * Features: | ||
| * - Strongly typed event names and handler arguments using generics (`EventsMap`). | ||
| * - Global `'*'` handlers that receive the event name as the first argument, followed by the event's arguments. | ||
| * - `beforeAll` and `afterAll` handler types for lifecycle-style hooks. | ||
| * - One-time handlers via `on` with `{ once: true }` option (removed automatically after first execution). | ||
| * - Handler limits with overflow detection via `maxTotalHandlers` and custom overflow behavior. | ||
| * - Backward-compatible `maxHandlers` property (deprecated in favor of `maxTotalHandlers`). | ||
| * | ||
| * This implementation allows both standard event handlers and advanced lifecycle hooks, | ||
| * while supporting both typed and untyped usage. | ||
| * | ||
| * @example | ||
@@ -30,2 +35,5 @@ * ```ts | ||
| * | ||
| * // Global handler receives the event name first | ||
| * emitter.on(`'*'`, (event, ...args) => console.log(`Global: ${event}`, args)); | ||
| * | ||
| * // Emit the event | ||
@@ -37,13 +45,20 @@ * await emitter.emit('data', 42); | ||
| * ```ts | ||
| * // Custom behavior when handler count exceeds limit | ||
| * emitter.maxHandlers = 2; | ||
| * emitter.onMaxHandlers((eventName) => { | ||
| * throw new Error(`Handler overflow on ${eventName}`); | ||
| * }); | ||
| * const emitter = new atomix.tools.EventEmitter(); | ||
| * | ||
| * // Option 1: Throw an Error immediately when the limit is exceeded | ||
| * emitter.maxTotalHandlers = 2; | ||
| * emitter.onMaxHandlers(new Error('Handler limit exceeded')); | ||
| * | ||
| * emitter.on('load', () => {}); | ||
| * emitter.on('load', () => {}); | ||
| * emitter.on('load', () => {}); // throws | ||
| * emitter.on('load', () => {}); // throws immediately | ||
| * | ||
| * // Option 2: Use a custom function to handle overflows (debounced) | ||
| * emitter.onMaxHandlers((eventName) => { | ||
| * console.warn(`Handler overflow on event: ${eventName}`); | ||
| * }); | ||
| * ``` | ||
| * | ||
| * @template EventsMap - Optional type map for event names and handler signatures. Defaults to `{}` for untyped usage. | ||
| * | ||
| * @since v1.0.8 | ||
@@ -109,33 +124,42 @@ */ | ||
| }; | ||
| #_runner = { | ||
| processEvents: async (events, ...args) => { | ||
| if (events.handlers.before) { | ||
| await this.#_runner.runHandler(events.handlers.before, events.name, ...args); | ||
| #_processor = { | ||
| process: async (events, ...args) => { | ||
| const { emittedBy, data, isGlobal } = events; | ||
| if (data.handlers.before) { | ||
| await this.#_processor.processHandler(data.handlers.before, { triggeredBy: emittedBy, isGlobal }, ...args); | ||
| } | ||
| // Handle normal events | ||
| for (let i = 0; i < events.handlers.normal.index; i++) { | ||
| const handler = (events.handlers.normal.handlers.get(i) || events.handlers.normal.onceHandlers.get(i)); | ||
| for (let i = 0; i < data.handlers.normal.index; i++) { | ||
| const handler = (data.handlers.normal.handlers.get(i) || data.handlers.normal.onceHandlers.get(i)); | ||
| if (!handler) { | ||
| continue; | ||
| } | ||
| await this.#_runner.runHandler(handler, events.name, ...args); | ||
| await this.#_processor.processHandler(handler, { triggeredBy: emittedBy, isGlobal }, ...args); | ||
| } | ||
| if (events.handlers.after) { | ||
| await this.#_runner.runHandler(events.handlers.after, events.name, ...args); | ||
| if (data.handlers.after) { | ||
| await this.#_processor.processHandler(data.handlers.after, { triggeredBy: emittedBy, isGlobal }, ...args); | ||
| } | ||
| const onceHandlersCount = events.handlers.normal.onceHandlers.size; | ||
| this.#_helpers.updateEventHandlersNum(events, -onceHandlersCount); | ||
| events.handlers.normal.onceHandlers.clear(); | ||
| const onceHandlersCount = data.handlers.normal.onceHandlers.size; | ||
| this.#_helpers.updateEventHandlersNum(data, -onceHandlersCount); | ||
| data.handlers.normal.onceHandlers.clear(); | ||
| }, | ||
| runHandler: async (handler, eventName, ...args) => { | ||
| processHandler: async (handler, meta, ...args) => { | ||
| const triggeredBy = meta.triggeredBy; | ||
| const isGlobal = meta.isGlobal; | ||
| try { | ||
| await handler(...args); | ||
| if (isGlobal) { | ||
| await handler(triggeredBy, ...args); | ||
| } | ||
| else { | ||
| await handler(...args); | ||
| } | ||
| } | ||
| catch (error) { | ||
| this.#_runner.onError(error, eventName); | ||
| this.#_processor.onError(error, meta); | ||
| } | ||
| }, | ||
| onError: (err, eventName) => { | ||
| console.error(`[HandlerError] (${eventName})`, err); | ||
| }, | ||
| onError(error, meta) { | ||
| const errMsg = `[Atomix][EventEmitter:UserHandlerError]: An error occurred while processing event '${meta.triggeredBy}'.`; | ||
| console.error(errMsg, error); | ||
| } | ||
| }; | ||
@@ -145,2 +169,13 @@ /** | ||
| * | ||
| * This method supports both **typed** and **untyped** emitters: | ||
| * | ||
| * - In a **typed emitter** (`EventEmitter<{ load: () => void; data: (value: number) => void }>`), | ||
| * the `eventName` parameter is restricted to the keys of the provided map, | ||
| * and the `args` are automatically typed according to the event's parameters. | ||
| * | ||
| * - In an **untyped emitter** (`EventEmitter` with default `{}`), `eventName` can be any string, | ||
| * and `args` are of type `any[]`. | ||
| * | ||
| * Global (`'*'`) handlers are triggered on every emit and receive the actual event name as the first argument. | ||
| * | ||
| * Handlers are invoked in the following order for each `emit` call: | ||
@@ -151,16 +186,11 @@ * 1. The `beforeAll` handler (if set) runs before all `normal` handlers. | ||
| * | ||
| * `beforeAll` and `afterAll` are special singleton handlers — only one of each | ||
| * may be set per event name. They are not removed automatically and are executed | ||
| * on every `emit` call. | ||
| * `beforeAll` and `afterAll` are singleton handlers — only one of each may be set per event name. | ||
| * They are not removed automatically and are executed on every `emit` call. | ||
| * | ||
| * `normal` handlers may be marked as `once`, in which case they will be removed | ||
| * after their first invocation. | ||
| * `normal` handlers may be marked as `once`, in which case they are removed after their first invocation. | ||
| * | ||
| * Global (`'*'`) handlers are triggered on every emit and receive the actual event | ||
| * name as their first argument. | ||
| * @template E - The event name type; inferred automatically. | ||
| * @param eventName - The name of the event to emit, or `'*'` for global handlers. Must be a non-empty string. | ||
| * @param args - Arguments to pass to all applicable handlers. Automatically typed for typed emitters. | ||
| * | ||
| * @async | ||
| * @param eventName - The name of the event to emit. Must be a non-empty string. | ||
| * @param args - Arguments to pass to all applicable handler functions. | ||
| * | ||
| * @throws {TypeError} If the event name is not a string. | ||
@@ -170,27 +200,15 @@ * @throws {RangeError} If the event name is an empty string. | ||
| * @example | ||
| * ```ts | ||
| * // Untyped emitter | ||
| * const emitter = new EventEmitter(); | ||
| * emitter.on('*', (event, ...args) => console.log(`Global: ${event}`, args)); | ||
| * await emitter.emit('load', true); | ||
| * | ||
| * emitter.on('data', (value) => console.log('Normal:', value)); | ||
| * emitter.on('data', () => console.log('Before All'), { type: 'beforeAll' }); | ||
| * emitter.on('data', () => console.log('After All'), { type: 'afterAll' }); | ||
| * | ||
| * await emitter.emit('data', 123); | ||
| * // Output: | ||
| * // Before All | ||
| * // Normal: 123 | ||
| * // After All | ||
| * ``` | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * emitter.on('*', (event, ...args) => { | ||
| * console.log(`Global handler: ${event}`, args); | ||
| * }); | ||
| * // Typed emitter | ||
| * type MyEvents = { load: (ok: boolean) => void; data: (value: number) => void }; | ||
| * const typedEmitter = new EventEmitter<MyEvents>(); | ||
| * typedEmitter.on('data', (value) => console.log('Data:', value)); | ||
| * typedEmitter.on('*', (event, ...args) => console.log(`Global: ${event}`, args)); | ||
| * await typedEmitter.emit('data', 42); // value typed as number | ||
| * | ||
| * await emitter.emit('load', true); | ||
| * // Output: | ||
| * // Global handler: load [true] | ||
| * ``` | ||
| * | ||
| * @since v1.0.8 | ||
@@ -208,6 +226,6 @@ */ | ||
| if (namedEvents) { | ||
| await this.#_runner.processEvents(namedEvents, ...args); | ||
| await this.#_processor.process({ emittedBy: eventName, data: namedEvents }, ...args); | ||
| } | ||
| if (globalEvents) { | ||
| await this.#_runner.processEvents(globalEvents, ...args); | ||
| await this.#_processor.process({ emittedBy: eventName, data: globalEvents, isGlobal: true }, ...args); | ||
| } | ||
@@ -218,12 +236,47 @@ } | ||
| * | ||
| * @param eventName - The name of the event to add the handler to. | ||
| * @param handler - The handler function to add. | ||
| * @param options - (Optional) Additional configuration options for the handler. If not provided, defaults to `{ once: false, type: 'normal' }`. | ||
| * @param options.once - (Optional) If true, the handler is removed after being called once. Defaults to false. | ||
| * @param options.type - (Optional) The type of event handler to add. One of "before", "after", or "normal". Defaults to "normal". | ||
| * This method supports both **typed** and **untyped** event emitters: | ||
| * | ||
| * @throws {TypeError} Throws if the event name is not a string or the handler is not a function. | ||
| * @throws {RangeError} Throws if the event name is an empty string or the type is not a valid event type. | ||
| * - In a **typed emitter** (`EventEmitter<{ load: () => void; data: (value: number) => void }>`), | ||
| * the `eventName` parameter is restricted to the keys of the provided map, | ||
| * and the `handler` function is automatically typed according to the event's parameters. | ||
| * | ||
| * @returns The EventEmitter instance. | ||
| * - In an **untyped emitter** (`EventEmitter` with default `{}`), `eventName` can be any string. | ||
| * | ||
| * Special support for `'*'` allows registering a **global handler** that listens to all events: | ||
| * - The `handler` receives the actual event name as the first argument. | ||
| * - This works for both typed and untyped emitters. | ||
| * | ||
| * Handler types: | ||
| * - `"normal"`: Runs on every emit (default) | ||
| * - `"beforeAll"`: Runs before all normal handlers for the event | ||
| * - `"afterAll"`: Runs after all normal handlers for the event | ||
| * | ||
| * @template E - The event name type; inferred automatically. | ||
| * @param eventName - The name of the event to add the handler to, or `'*'` for a global handler. | ||
| * @param handler - The handler function for the event: | ||
| * - For specific events, receives the event parameters. | ||
| * - For `'*'`, receives the event name followed by its parameters. | ||
| * @param options - Optional configuration for the handler. Defaults to `{ once: false, type: 'normal' }`. | ||
| * @param options.once - If true, the handler is removed after being called once. | ||
| * @param options.type - The type of handler. One of `"normal"`, `"beforeAll"`, or `"afterAll"`. | ||
| * | ||
| * @throws {TypeError} If `eventName` is not a string, or `handler` is not a function. | ||
| * @throws {RangeError} If `eventName` is an empty string, or `options.type` is invalid. | ||
| * | ||
| * @returns The EventEmitter instance, allowing method chaining. | ||
| * | ||
| * @example | ||
| * // Untyped emitter | ||
| * const emitter = new EventEmitter(); | ||
| * emitter.on('*', (event, ...args) => { | ||
| * console.log(`Event "${event}" emitted with args:`, args); | ||
| * }); | ||
| * | ||
| * @example | ||
| * // Typed emitter | ||
| * type MyEvents = { load: (ok: boolean) => void; data: (value: number) => void }; | ||
| * const typedEmitter = new EventEmitter<MyEvents>(); | ||
| * typedEmitter.on('data', (value) => console.log('Data:', value)); | ||
| * typedEmitter.on('*', (event, ...args) => console.log(`Event "${event}"`, args)); | ||
| * | ||
| * @since v1.0.8 | ||
@@ -287,7 +340,23 @@ */ | ||
| * | ||
| * The handler is debounced to prevent excessive calls when the maximum number of handlers is exceeded multiple times in quick succession. | ||
| * - If a **function** is provided, it is debounced (100ms) to prevent excessive calls during rapid handler additions. | ||
| * - If an **Error** object is provided, it will be thrown immediately when the limit is exceeded. | ||
| * | ||
| * @param handler - A function to call when the maximum number of handlers is exceeded or an error to throw. | ||
| * @returns The EventEmitter instance. | ||
| * @throws {TypeError} If the handler is not a function or an error. | ||
| * @param handler - A function to call when the maximum number of handlers is exceeded, or an Error to throw. | ||
| * @returns The EventEmitter instance, allowing method chaining. | ||
| * | ||
| * @throws {TypeError} If the handler is not a function or an Error instance. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * const emitter = new atomix.tools.EventEmitter(); | ||
| * | ||
| * // Throw an error when the max handlers limit is exceeded | ||
| * emitter.onMaxHandlers(new Error('Handler limit exceeded')); | ||
| * | ||
| * // Or provide a custom function | ||
| * emitter.onMaxHandlers((eventName) => { | ||
| * console.warn(`Handler overflow on event: ${eventName}`); | ||
| * }); | ||
| * ``` | ||
| * | ||
| * @since v1.0.8 | ||
@@ -342,5 +411,5 @@ */ | ||
| * @returns {number} The maximum number of handlers. A positive integer or Infinity. | ||
| * @since v1.0.8 | ||
| * @since v1.0.24 | ||
| */ | ||
| get maxHandlers() { return this.#_stats.handlers.max; } | ||
| get maxTotalHandlers() { return this.#_stats.handlers.max; } | ||
| /** | ||
@@ -354,7 +423,7 @@ * Sets the maximum number of event handlers allowed for this EventEmitter instance. | ||
| * @throws {RangeError} If the provided value is not greater than 0. | ||
| * @since v1.0.8 | ||
| * @since v1.0.24 | ||
| */ | ||
| set maxHandlers(value) { | ||
| set maxTotalHandlers(value) { | ||
| if (!valueIs.number(value)) { | ||
| throw new TypeError('maxHandlers must be a number'); | ||
| throw new TypeError('maxTotalHandlers must be a number'); | ||
| } | ||
@@ -366,6 +435,6 @@ if (value === Infinity) { | ||
| if (value <= 0) { | ||
| throw new RangeError('maxHandlers must be greater than 0'); | ||
| throw new RangeError('maxTotalHandlers must be greater than 0'); | ||
| } | ||
| if (!valueIs.integer(value)) { | ||
| throw new TypeError('maxHandlers must be an integer'); | ||
| throw new TypeError('maxTotalHandlers must be an integer'); | ||
| } | ||
@@ -375,2 +444,26 @@ this.#_stats.handlers.max = value; | ||
| /** | ||
| * Retrieves the maximum number of event handlers allowed for this EventEmitter instance. | ||
| * | ||
| * The value is a positive integer or Infinity. If set to Infinity, there is no limit to the number of handlers. | ||
| * | ||
| * @returns {number} The maximum number of handlers. A positive integer or Infinity. | ||
| * @deprecated Use {@link maxTotalHandlers} getter/setter instead. | ||
| * @since v1.0.8 | ||
| */ | ||
| get maxHandlers() { return this.maxTotalHandlers; } | ||
| /** | ||
| * Sets the maximum number of event handlers allowed for this EventEmitter instance. | ||
| * | ||
| * The value must be a positive integer or Infinity. If set to Infinity, there is no limit to the number of handlers. | ||
| * | ||
| * @param {number} value The maximum number of handlers. Must be a positive integer or Infinity. | ||
| * @throws {TypeError} If the provided value is not a number or not an integer. | ||
| * @throws {RangeError} If the provided value is not greater than 0. | ||
| * @deprecated Use {@link maxTotalHandlers} getter/setter instead. | ||
| * @since v1.0.8 | ||
| */ | ||
| set maxHandlers(value) { | ||
| this.maxTotalHandlers = value; | ||
| } | ||
| /** | ||
| * Retrieves the total number of event handlers registered with this EventEmitter instance. | ||
@@ -377,0 +470,0 @@ * @returns {number} The total number of event handlers. |
@@ -121,3 +121,3 @@ import AdaptiveTaskQueue from "./queues/AdaptiveTaskQueue.js"; | ||
| * // Custom behavior when handler count exceeds limit | ||
| * emitter.maxHandlers = 2; | ||
| * emitter.maxTotalHandlers = 2; | ||
| * emitter.onMaxHandlers((eventName) => { | ||
@@ -124,0 +124,0 @@ * throw new Error(`Handler overflow on ${eventName}`); |
+1
-1
| { | ||
| "name": "@nasriya/atomix", | ||
| "version": "1.0.23", | ||
| "version": "1.0.24", | ||
| "description": "Composable helper functions for building reliable systems", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
675805
2.5%17319
1.7%