{"version":3,"sources":["../../src/events/event-emitter.ts"],"names":[],"mappings":"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","file":"event-emitter.mjs","sourcesContent":["import type { ILogger } from '../logging/logger';\n\nexport type EventHandler<T = any> = (data: T) => void | Promise<void>;\nexport interface IEventEmitter<EventTypes = Record<string, any>> {\n  on<Event extends keyof EventTypes>(\n    event: Event,\n    handler: EventHandler<EventTypes[Event]>,\n  ): number;\n  once<Event extends keyof EventTypes>(\n    event: Event,\n    handler: EventHandler<EventTypes[Event]>,\n  ): number;\n  off(id: number): void;\n  emit<Event extends keyof EventTypes>(\n    event: Event,\n    value: EventTypes[Event],\n  ): void;\n}\n\nexport class EventEmitter<\n  EventTypes = Record<string, any>,\n> implements IEventEmitter<EventTypes> {\n  protected index: number = -1;\n  protected subscriptions: Map<\n    keyof EventTypes,\n    Array<{\n      readonly id: number;\n      readonly handler: EventHandler;\n    }>\n  > = new Map<\n    keyof EventTypes,\n    Array<{\n      readonly id: number;\n      readonly handler: EventHandler;\n    }>\n  >();\n\n  /**\n   * @param logger Used to report handler failures from {@link emitAsync}.\n   * Defaults to `console` when omitted, so failures are never silent.\n   */\n  constructor(protected readonly logger?: ILogger | undefined) { }\n\n  on<Event extends keyof EventTypes>(\n    event: Event,\n    handler: EventHandler<EventTypes[Event]>,\n  ): number {\n    const id = ++this.index;\n    const subs = this.subscriptions.get(event) || [];\n    subs.push({ id, handler });\n    this.subscriptions.set(event, subs);\n    return id;\n  }\n\n  once<Event extends keyof EventTypes>(\n    event: Event,\n    handler: EventHandler<EventTypes[Event]>,\n  ): number {\n    const id = this.on(event, (value) => {\n      this.off(id);\n      // Returned so `emitAsync` can await an async one-shot handler.\n      return handler(value);\n    });\n\n    return id;\n  }\n\n  off(id: number): void {\n    for (const [_, subs] of this.subscriptions.entries()) {\n      const i = subs.findIndex((s) => s.id === id);\n\n      if (i === -1) continue;\n\n      subs.splice(i, 1);\n      return;\n    }\n  }\n\n  emit<Event extends keyof EventTypes>(\n    event: Event,\n    value: EventTypes[Event],\n  ): void {\n    const subs = this.subscriptions.get(event) || [];\n\n    for (const sub of subs) {\n      sub.handler(value);\n    }\n  }\n\n  /**\n   * Emit an event and wait for every subscribed handler to settle.\n   *\n   * Handlers are started in subscription order and then awaited together, so\n   * async handlers run concurrently. Use this instead of `emit` when the\n   * emitter must not continue until async listeners have finished — for\n   * example when those listeners touch resources that are torn down once the\n   * emitting operation returns.\n   *\n   * A handler that throws or rejects is logged and does not stop the other\n   * handlers; this never rejects.\n   */\n  async emitAsync<Event extends keyof EventTypes>(\n    event: Event,\n    value: EventTypes[Event],\n  ): Promise<void> {\n    // Snapshot so a `once` handler unsubscribing itself mid-emit cannot shift\n    // the list out from under the loop.\n    const subs = [...(this.subscriptions.get(event) || [])];\n    const pending: Array<Promise<void>> = [];\n\n    for (const sub of subs) {\n      try {\n        const result = sub.handler(value);\n\n        if (result) {\n          pending.push(result);\n        }\n      } catch (err) {\n        this.reportHandlerError(event, err);\n      }\n    }\n\n    const results = await Promise.allSettled(pending);\n\n    for (const result of results) {\n      if (result.status === 'rejected') {\n        this.reportHandlerError(event, result.reason);\n      }\n    }\n  }\n\n  private reportHandlerError(event: keyof EventTypes, err: unknown): void {\n    const message = `event handler failed for \"${String(event)}\"`;\n\n    if (this.logger) {\n      this.logger.error(message, err);\n      return;\n    }\n\n    console.error(message, err);\n  }\n}\n"]}