'use strict';

// src/chat/events.ts
var TypedEventEmitter = class {
  listeners = /* @__PURE__ */ new Map();
  /**
   * Subscribe to an event.
   * @param event - Event name
   * @param listener - Callback receiving the event payload
   * @returns Unsubscribe function
   */
  on(event, listener) {
    let set = this.listeners.get(event);
    if (!set) {
      set = /* @__PURE__ */ new Set();
      this.listeners.set(event, set);
    }
    const fn = listener;
    set.add(fn);
    return () => {
      set.delete(fn);
      if (set.size === 0) {
        this.listeners.delete(event);
      }
    };
  }
  /**
   * Subscribe to an event, firing the listener at most once.
   * @param event - Event name
   * @param listener - Callback receiving the event payload
   * @returns Unsubscribe function
   */
  once(event, listener) {
    const unsub = this.on(event, (payload) => {
      unsub();
      listener(payload);
    });
    return unsub;
  }
  /**
   * Remove a specific listener from an event.
   * @param event - Event name
   * @param listener - The listener to remove
   */
  off(event, listener) {
    const set = this.listeners.get(event);
    if (!set) return;
    set.delete(listener);
    if (set.size === 0) {
      this.listeners.delete(event);
    }
  }
  /**
   * Emit an event, calling all registered listeners synchronously.
   * @param event - Event name
   * @param payload - Event payload
   */
  emit(event, payload) {
    const set = this.listeners.get(event);
    if (!set) return;
    for (const fn of [...set]) {
      fn(payload);
    }
  }
  /**
   * Remove all listeners for a specific event, or all events if no event specified.
   * @param event - Optional event name
   */
  removeAllListeners(event) {
    if (event !== void 0) {
      this.listeners.delete(event);
    } else {
      this.listeners.clear();
    }
  }
  /**
   * Get the number of listeners for a specific event.
   * @param event - Event name
   * @returns Number of listeners
   */
  listenerCount(event) {
    const set = this.listeners.get(event);
    return set ? set.size : 0;
  }
  /**
   * Get all event names that have at least one listener.
   * @returns Array of event names
   */
  eventNames() {
    return [...this.listeners.keys()];
  }
};
var ChatEventBus = class extends TypedEventEmitter {
  middlewares = [];
  /**
   * Register a middleware function. Middleware runs in registration order.
   * @param middleware - Middleware function
   * @returns Unsubscribe function to remove the middleware
   */
  use(middleware) {
    this.middlewares.push(middleware);
    return () => {
      const idx = this.middlewares.indexOf(middleware);
      if (idx !== -1) {
        this.middlewares.splice(idx, 1);
      }
    };
  }
  /**
   * Emit a chat event through the middleware pipeline, then to listeners.
   *
   * @param event - ChatEvent type string
   * @param payload - The full ChatEvent object
   */
  emit(event, payload) {
    if (this.middlewares.length === 0) {
      super.emit(event, payload);
      return;
    }
    let suppressed = false;
    let currentEvent = payload;
    let index = 0;
    const runNext = () => {
      if (suppressed) return;
      if (index >= this.middlewares.length) {
        super.emit(
          currentEvent.type,
          currentEvent
        );
        return;
      }
      const mw = this.middlewares[index++];
      const ctx = {
        event: currentEvent,
        next: () => {
          currentEvent = ctx.event;
          runNext();
        },
        suppress: () => {
          suppressed = true;
        }
      };
      mw(ctx);
    };
    runNext();
  }
  /**
   * Replace the event in the middleware context.
   * Middleware should mutate ctx.event or create a new MiddlewareContext
   * to transform events passing through the pipeline.
   */
  /**
   * Remove all middleware functions.
   */
  clearMiddleware() {
    this.middlewares.length = 0;
  }
  /**
   * Get the number of registered middleware functions.
   * @returns Number of middleware
   */
  middlewareCount() {
    return this.middlewares.length;
  }
};
function eventFilter(...types) {
  const allowed = new Set(types);
  return (event) => allowed.has(event.type);
}
async function* filterEvents(source, ...types) {
  const pred = eventFilter(...types);
  for await (const event of source) {
    if (pred(event)) {
      yield event;
    }
  }
}
async function* mapEvents(source, transform) {
  for await (const event of source) {
    const result = transform(event);
    if (result !== null) {
      yield result;
    }
  }
}
async function collectText(source) {
  const parts = [];
  for await (const event of source) {
    if (event.type === "message:delta") {
      parts.push(event.text);
    }
  }
  return parts.join("");
}

exports.ChatEventBus = ChatEventBus;
exports.TypedEventEmitter = TypedEventEmitter;
exports.collectText = collectText;
exports.eventFilter = eventFilter;
exports.filterEvents = filterEvents;
exports.mapEvents = mapEvents;
//# sourceMappingURL=events.cjs.map
//# sourceMappingURL=events.cjs.map