{"version":3,"file":"event-emitter.cjs","sources":["../../src/event-emitter.ts"],"sourcesContent":["/**\n * Generic type-safe event emitter\n * @template TEvents - Record of event names to event payload types\n */\nexport class EventEmitter<TEvents extends Record<string, any>> {\n  private listeners = new Map<\n    keyof TEvents,\n    Map<(event: TEvents[keyof TEvents]) => void, object>\n  >()\n  private onceCallbacks = new WeakMap<\n    (event: TEvents[keyof TEvents]) => void,\n    (event: TEvents[keyof TEvents]) => void\n  >()\n\n  /**\n   * Subscribe to an event\n   * @param event - Event name to listen for\n   * @param callback - Function to call when event is emitted\n   * @returns Unsubscribe function\n   */\n  on<T extends keyof TEvents>(\n    event: T,\n    callback: (event: TEvents[T]) => void,\n  ): () => void {\n    if (!this.listeners.has(event)) {\n      this.listeners.set(event, new Map())\n    }\n    const listeners = this.listeners.get(event)!\n    const registered = callback as (event: any) => void\n    let registration = listeners.get(registered)\n    if (!registration) {\n      registration = {}\n      listeners.set(registered, registration)\n    }\n\n    return () => {\n      const current = this.listeners.get(event)\n      if (current?.get(registered) === registration) {\n        current.delete(registered)\n      }\n    }\n  }\n\n  /**\n   * Subscribe to an event once (automatically unsubscribes after first emission)\n   * @param event - Event name to listen for\n   * @param callback - Function to call when event is emitted\n   * @returns Unsubscribe function\n   */\n  once<T extends keyof TEvents>(\n    event: T,\n    callback: (event: TEvents[T]) => void,\n  ): () => void {\n    let unsubscribe = () => {}\n    const listener = (eventPayload: TEvents[T]) => {\n      unsubscribe()\n      callback(eventPayload)\n    }\n    this.onceCallbacks.set(\n      listener as (event: TEvents[keyof TEvents]) => void,\n      callback as (event: TEvents[keyof TEvents]) => void,\n    )\n    unsubscribe = this.on(event, listener)\n    return unsubscribe\n  }\n\n  /**\n   * Unsubscribe from an event\n   * @param event - Event name to stop listening for\n   * @param callback - Function to remove\n   */\n  off<T extends keyof TEvents>(\n    event: T,\n    callback: (event: TEvents[T]) => void,\n  ): void {\n    const listeners = this.listeners.get(event)\n    if (!listeners) return\n    for (const listener of listeners.keys()) {\n      if (\n        listener === callback ||\n        this.onceCallbacks.get(listener) === callback\n      ) {\n        listeners.delete(listener)\n      }\n    }\n  }\n\n  /**\n   * Wait for an event to be emitted\n   * @param event - Event name to wait for\n   * @param timeout - Optional timeout in milliseconds\n   * @returns Promise that resolves with the event payload\n   */\n  waitFor<T extends keyof TEvents>(\n    event: T,\n    timeout?: number,\n  ): Promise<TEvents[T]> {\n    return new Promise((resolve, reject) => {\n      let timeoutId: NodeJS.Timeout | undefined\n      const unsubscribe = this.on(event, (eventPayload) => {\n        if (timeoutId) {\n          clearTimeout(timeoutId)\n          timeoutId = undefined\n        }\n        resolve(eventPayload)\n        unsubscribe()\n      })\n      if (timeout) {\n        timeoutId = setTimeout(() => {\n          timeoutId = undefined\n          unsubscribe()\n          reject(new Error(`Timeout waiting for event ${String(event)}`))\n        }, timeout)\n      }\n    })\n  }\n\n  /**\n   * Emit an event to all listeners\n   * @param event - Event name to emit\n   * @param eventPayload - Event payload\n   * @internal For use by subclasses - subclasses should wrap this with a public emit if needed\n   */\n  protected emitInner<T extends keyof TEvents>(\n    event: T,\n    eventPayload: TEvents[T],\n  ): void {\n    this.emitInnerWhile(event, eventPayload, () => true)\n  }\n\n  /** Emit until a reentrant callback invalidates the event being delivered. */\n  protected emitInnerWhile<T extends keyof TEvents>(\n    event: T,\n    eventPayload: TEvents[T],\n    isCurrent: () => boolean,\n  ): void {\n    const listeners = this.listeners.get(event)\n    if (!listeners) return\n    for (const [listener, registration] of [...listeners]) {\n      if (!isCurrent()) break\n      if (this.listeners.get(event)?.get(listener) !== registration) continue\n      try {\n        listener(eventPayload)\n      } catch (error) {\n        // Re-throw in a microtask to surface the error\n        queueMicrotask(() => {\n          throw error\n        })\n      }\n    }\n  }\n\n  /**\n   * Clear all listeners\n   */\n  protected clearListeners(): void {\n    this.listeners.clear()\n  }\n}\n"],"names":[],"mappings":";;AAIO,MAAM,aAAkD;AAAA,EAAxD,cAAA;AACL,SAAQ,gCAAgB,IAAA;AAIxB,SAAQ,oCAAoB,QAAA;AAAA,EAG1B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQF,GACE,OACA,UACY;AACZ,QAAI,CAAC,KAAK,UAAU,IAAI,KAAK,GAAG;AAC9B,WAAK,UAAU,IAAI,OAAO,oBAAI,KAAK;AAAA,IACrC;AACA,UAAM,YAAY,KAAK,UAAU,IAAI,KAAK;AAC1C,UAAM,aAAa;AACnB,QAAI,eAAe,UAAU,IAAI,UAAU;AAC3C,QAAI,CAAC,cAAc;AACjB,qBAAe,CAAA;AACf,gBAAU,IAAI,YAAY,YAAY;AAAA,IACxC;AAEA,WAAO,MAAM;AACX,YAAM,UAAU,KAAK,UAAU,IAAI,KAAK;AACxC,UAAI,SAAS,IAAI,UAAU,MAAM,cAAc;AAC7C,gBAAQ,OAAO,UAAU;AAAA,MAC3B;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,KACE,OACA,UACY;AACZ,QAAI,cAAc,MAAM;AAAA,IAAC;AACzB,UAAM,WAAW,CAAC,iBAA6B;AAC7C,kBAAA;AACA,eAAS,YAAY;AAAA,IACvB;AACA,SAAK,cAAc;AAAA,MACjB;AAAA,MACA;AAAA,IAAA;AAEF,kBAAc,KAAK,GAAG,OAAO,QAAQ;AACrC,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,IACE,OACA,UACM;AACN,UAAM,YAAY,KAAK,UAAU,IAAI,KAAK;AAC1C,QAAI,CAAC,UAAW;AAChB,eAAW,YAAY,UAAU,QAAQ;AACvC,UACE,aAAa,YACb,KAAK,cAAc,IAAI,QAAQ,MAAM,UACrC;AACA,kBAAU,OAAO,QAAQ;AAAA,MAC3B;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,QACE,OACA,SACqB;AACrB,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAI;AACJ,YAAM,cAAc,KAAK,GAAG,OAAO,CAAC,iBAAiB;AACnD,YAAI,WAAW;AACb,uBAAa,SAAS;AACtB,sBAAY;AAAA,QACd;AACA,gBAAQ,YAAY;AACpB,oBAAA;AAAA,MACF,CAAC;AACD,UAAI,SAAS;AACX,oBAAY,WAAW,MAAM;AAC3B,sBAAY;AACZ,sBAAA;AACA,iBAAO,IAAI,MAAM,6BAA6B,OAAO,KAAK,CAAC,EAAE,CAAC;AAAA,QAChE,GAAG,OAAO;AAAA,MACZ;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQU,UACR,OACA,cACM;AACN,SAAK,eAAe,OAAO,cAAc,MAAM,IAAI;AAAA,EACrD;AAAA;AAAA,EAGU,eACR,OACA,cACA,WACM;AACN,UAAM,YAAY,KAAK,UAAU,IAAI,KAAK;AAC1C,QAAI,CAAC,UAAW;AAChB,eAAW,CAAC,UAAU,YAAY,KAAK,CAAC,GAAG,SAAS,GAAG;AACrD,UAAI,CAAC,YAAa;AAClB,UAAI,KAAK,UAAU,IAAI,KAAK,GAAG,IAAI,QAAQ,MAAM,aAAc;AAC/D,UAAI;AACF,iBAAS,YAAY;AAAA,MACvB,SAAS,OAAO;AAEd,uBAAe,MAAM;AACnB,gBAAM;AAAA,QACR,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKU,iBAAuB;AAC/B,SAAK,UAAU,MAAA;AAAA,EACjB;AACF;;"}