{"version":3,"file":"emitter.cjs","names":["DefaultLogger","safeTimeout","getGlobalContext"],"sources":["../../../src/common/msg/emitter.ts"],"sourcesContent":["import type { DisposerFunction } from '../dispose-types'\nimport { getGlobalContext } from '../global'\nimport { DefaultLogger } from '../log/log'\nimport { safeTimeout } from '../timeout'\n\nexport type EmitterHandler = (...objs: any[]) => void\nexport type EmitterAllHandler<T = string> = (key: T, ...objs: any[]) => void\n\n// For magic see https://www.npmjs.com/package/tiny-typed-emitter / License MIT\n// https://stackoverflow.com/a/61609010/140927\n// https://basarat.gitbook.io/typescript/main-1/typed-event\n// https://github.com/andywer/typed-emitter#extending-an-emitter\n\n// TODO: Allow symbols? https://github.com/sindresorhus/emittery\n\nexport declare type ListenerSignature<L> = {\n  [E in keyof L]: (...args: any[]) => any\n}\n\nexport declare interface DefaultListener {\n  [k: string]: (...args: any[]) => any\n}\n\ninterface EmitterSubscriber {\n  fn: EmitterHandler // (...args: any[]) => any\n  priority: number\n}\n\nexport interface EmitterSubscriberOptions {\n  priority?: number\n}\n\nexport class Emitter<\n  RemoteListener extends ListenerSignature<RemoteListener> = DefaultListener,\n  LocalListener extends ListenerSignature<LocalListener> = DefaultListener,\n> {\n  private subscribers: Record<any, EmitterSubscriber[]> = {}\n  private subscribersOnAny: any[] = []\n\n  _logEmitter = DefaultLogger('zeed:emitter', 'warn')\n\n  /** RPC like emitting of events. */\n  call: RemoteListener = new Proxy<RemoteListener>({} as any, {\n    get:\n      (target: any, name: any) =>\n        async (...args: any): Promise<boolean> =>\n          await this.emit(name, ...args),\n  })\n\n  /**\n   * Emits an event to all subscribers and executes their corresponding event handlers.\n   *\n   * @param event - The event to emit.\n   * @param args - The arguments to pass to the event handlers.\n   * @returns A promise that resolves to an array of results from all subscribers, or undefined if no subscribers are present.\n   */\n  public async getAll<U extends keyof RemoteListener>(event: U, ...args: Parameters<RemoteListener[U]>): Promise<ReturnType<RemoteListener[U]>[] | undefined> {\n    try {\n      const subscribers = (this.subscribers[event] || []) as EmitterSubscriber[]\n      this._logEmitter.debug('emit', this?.constructor?.name, event, ...args, subscribers)\n\n      this.subscribersOnAny.forEach(fn => fn(event, ...args))\n\n      if (subscribers.length > 0) {\n        const all = subscribers.map(({ fn }) => {\n          try {\n            return Promise.resolve(fn(...args))\n          }\n          catch (err) {\n            this._logEmitter.warn('emit warning:', err)\n          }\n          return null\n        }).filter(fn => fn != null)\n        return (await Promise.all(all)) as any[]\n      }\n    }\n    catch (err) {\n      this._logEmitter.error('emit exception', err)\n    }\n    return undefined\n  }\n\n  /**\n   * Emits an event to all subscribers and executes their corresponding event handlers.\n   *\n   * @param event - The event to emit.\n   * @param args - The arguments to pass to the event handlers.\n   * @returns A promise that resolves to the result of the first subscriber's handler, or undefined if no subscribers are present.\n   */\n  public async get<U extends keyof RemoteListener>(event: U, ...args: Parameters<RemoteListener[U]>): Promise<ReturnType<RemoteListener[U]> | undefined> {\n    const results = await this.getAll(event, ...args)\n    if (results && results.length > 0) {\n      return results[0] // Return first result\n    }\n    return undefined\n  }\n\n  /**\n   * Emits an event to all subscribers and executes their corresponding event handlers.\n   *\n   * @param event - The event to emit.\n   * @param args - The arguments to pass to the event handlers.\n   * @returns A promise that resolves to a boolean indicating whether the event was successfully emitted.\n   */\n  public async emit<U extends keyof RemoteListener>(event: U, ...args: Parameters<RemoteListener[U]>): Promise<boolean> {\n    const result = await this.getAll(event, ...args)\n    return result != null\n  }\n\n  public onAny(fn: EmitterHandler) {\n    this.subscribersOnAny.push(fn)\n  }\n\n  public on<U extends keyof LocalListener>(\n    event: U,\n    fn: LocalListener[U],\n    opt: EmitterSubscriberOptions = {},\n  ): DisposerFunction {\n    const { priority = 0 } = opt\n    const subscribers = (this.subscribers[event] || [])\n    const slen = subscribers.length\n    const sobj = { fn, priority }\n    if (slen <= 0) {\n      this.subscribers[event] = [sobj]\n    }\n    else {\n      let pos = slen\n      for (let i = subscribers.length - 1; i >= 0; i--) {\n        const s = subscribers[i]\n        // Insert after last entry of same priority\n        if (priority <= s.priority)\n          break\n        pos -= 1\n      }\n      subscribers.splice(pos, 0, sobj) // in place\n    }\n    return () => {\n      this.off(event, fn)\n    }\n  }\n\n  public onCall(handlers: Partial<LocalListener>) {\n    for (const [name, handler] of Object.entries(handlers))\n      this.on(name as any, handler as any)\n  }\n\n  public once<U extends keyof LocalListener>(\n    event: U,\n    listener: LocalListener[U],\n  ): DisposerFunction {\n    const onceListener = async (...args: any[]) => {\n      this.off(event, onceListener as any)\n      return await Promise.resolve(listener(...args))\n    }\n    this.on(event, onceListener as any)\n    return () => {\n      this.off(event, listener)\n    }\n  }\n\n  public off<U extends keyof LocalListener>(\n    event: U,\n    listener: LocalListener[U],\n  ): this {\n    // log(\"off\", key)\n    this.subscribers[event] = (this.subscribers[event] || []).filter(f => listener && f.fn !== listener)\n    return this\n  }\n\n  public removeAllListeners(): this {\n    this.subscribers = {}\n    return this\n  }\n\n  public hasListeners(event: keyof LocalListener): boolean {\n    return !!this.subscribers[event] && this.subscribers[event].length > 0\n  }\n\n  ///\n\n  waitOn<U extends keyof LocalListener, R = Parameters<LocalListener[U]>[0]>(\n    event: U,\n    timeoutMS = 1000,\n  ): Promise<R> {\n    return new Promise((resolve, reject) => {\n      let disposeTimer: any\n\n      const disposeListener = this.once(event, ((value): void => {\n        disposeTimer?.()\n        resolve(value)\n      }) as LocalListener[U])\n\n      disposeTimer = safeTimeout(() => {\n        disposeListener()\n        reject(new Error('Did not respond in time'))\n      }, timeoutMS)\n    })\n  }\n\n  // For compatibility reasons: provide explicitly typed wrapper methods so\n  // documentation generator (TypeDoc) can resolve signatures/URLs correctly.\n  public addEventListener<U extends keyof LocalListener>(\n    event: U,\n    fn: LocalListener[U],\n    opt: EmitterSubscriberOptions = {},\n  ): DisposerFunction {\n    return this.on(event, fn, opt)\n  }\n\n  public removeEventListener<U extends keyof LocalListener>(\n    event: U,\n    listener: LocalListener[U],\n  ): this {\n    return this.off(event, listener)\n  }\n}\n\ndeclare global {\n  interface ZeedGlobalContext {\n    emitter?: Emitter\n  }\n\n  /**\n   * Global emitter interface for Zeed, used for cross-module event emission.\n   * @category Global\n   */\n  interface ZeedGlobalEmitter {}\n}\n\n/** Global emitter that will listen even across modules */\nexport function getGlobalEmitter<T extends ListenerSignature<T> = ZeedGlobalEmitter>(): Emitter<T> {\n  let emitter = getGlobalContext().emitter\n  if (!emitter) {\n    emitter = new Emitter()\n    getGlobalContext().emitter = emitter\n  }\n  return emitter as any\n}\n\n// Public alias so typedoc lists the global emitter under an Emitter-prefixed name\nexport interface ZeedGlobalEmitter extends DefaultListener {}\n"],"mappings":"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"}