{"version":3,"file":"event-emitter-80LrFIBS.cjs","names":["EventEmitter"],"sources":["../src/events/pubsub.ts","../src/events/event-emitter/batch-policy.ts","../src/events/event-emitter/ack-handle-buffer.ts","../src/events/event-emitter/index.ts"],"sourcesContent":["import type { Event, EventCallback, SubscribeOptions } from './types';\n\n/**\n * Delivery model for a PubSub implementation.\n *\n * - `pull`: consumers actively read from the broker (e.g. Redis Streams\n *   XREADGROUP, GCP Pub/Sub streamingPull, SQS ReceiveMessage). Mastra runs\n *   a long-lived `OrchestrationWorker` that owns a subscription loop.\n *\n * - `push`: events arrive without the consumer asking — either in-process\n *   (EventEmitter dispatching to a registered listener) or out-of-process\n *   (the broker POSTs to an HTTP endpoint, e.g. GCP Pub/Sub push, SNS,\n *   EventBridge). Mastra wires the workflow handler directly to the pubsub\n *   for in-process push, or relies on `POST /api/workers/events` for\n *   broker push delivered over HTTP.\n */\nexport type PubSubDeliveryMode = 'pull' | 'push';\n\nexport abstract class PubSub {\n  abstract publish(\n    topic: string,\n    event: Omit<Event, 'id' | 'createdAt'>,\n    options?: { localOnly?: boolean },\n  ): Promise<void>;\n  abstract subscribe(topic: string, cb: EventCallback, options?: SubscribeOptions): Promise<void>;\n  abstract unsubscribe(topic: string, cb: EventCallback): Promise<void>;\n  /**\n   * Drain any buffered or in-flight deliveries before resolving.\n   *\n   * Best-effort: a `flush()` that resolves successfully does not guarantee\n   * every subscriber callback succeeded — implementations surface per-event\n   * delivery errors via their configured logger rather than re-throwing,\n   * so a single failed callback does not mask later cleanup work.\n   */\n  abstract flush(): Promise<void>;\n\n  /**\n   * Delete all retained state for a topic (cached history, persistent stream\n   * entries, consumer groups) once no more events will be published to it.\n   *\n   * Called by run lifecycles (durable agents, the evented workflow engine)\n   * when a run reaches a terminal state, so per-run topics don't accumulate\n   * forever on transports that retain messages (e.g. Redis Streams).\n   *\n   * Default implementation is a no-op: transports that don't retain anything\n   * per topic (e.g. plain EventEmitter delivery) have nothing to clear.\n   *\n   * Best-effort contract: implementations should not throw — callers invoke\n   * this fire-and-forget at cleanup boundaries, so failures should be logged\n   * by the implementation rather than rejected.\n   *\n   * @param topic - The topic whose retained state should be deleted\n   */\n  clearTopic(_topic: string): Promise<void> {\n    return Promise.resolve();\n  }\n\n  /**\n   * Delivery modes this PubSub implementation supports.\n   *\n   * Defaults to `['pull']` for backward compatibility — third-party\n   * implementations that don't override this property are treated as\n   * pull-mode, which preserves today's behavior.\n   *\n   * Implementations that deliver events without an active read loop (e.g.\n   * EventEmitter, GCP Pub/Sub push subscriptions) should declare `'push'`.\n   * Implementations that support both modes should declare both.\n   */\n  get supportedModes(): ReadonlyArray<PubSubDeliveryMode> {\n    return ['pull'];\n  }\n\n  /**\n   * Whether this implementation honors `options.batch` on `subscribe()`\n   * natively. Defaults to `false`.\n   *\n   * Implementations that integrate batching internally (e.g. against their\n   * own broker retention or via an `AckHandleBuffer`) override this getter\n   * and return `true`.\n   */\n  get supportsNativeBatching(): boolean {\n    return false;\n  }\n\n  /**\n   * Get historical events for a topic.\n   * Default implementation returns empty array (no history support).\n   * Override in implementations that support event caching.\n   *\n   * @param topic - The topic to get history for\n   * @param offset - Starting index (0-based), defaults to 0\n   * @returns Array of events from the specified index\n   */\n  getHistory(_topic: string, _offset?: number): Promise<Event[]> {\n    return Promise.resolve([]);\n  }\n\n  /**\n   * Subscribe to a topic with automatic replay of cached events.\n   * First replays any cached history, then subscribes to live events.\n   * Default implementation falls back to regular subscribe (no replay).\n   * Override in implementations that support event caching.\n   *\n   * @param topic - The topic to subscribe to\n   * @param cb - Callback invoked for each event (both cached and live)\n   */\n  subscribeWithReplay(topic: string, cb: EventCallback): Promise<void> {\n    return this.subscribe(topic, cb);\n  }\n\n  /**\n   * Subscribe to a topic with replay starting from a specific index.\n   * This is more efficient than full replay when the client knows their last position.\n   * Default implementation falls back to subscribeWithReplay (full replay).\n   * Override in implementations that support indexed event caching.\n   *\n   * @param topic - The topic to subscribe to\n   * @param offset - Start replaying from this index (0-based)\n   * @param cb - Callback invoked for each event\n   */\n  subscribeFromOffset(topic: string, _offset: number, cb: EventCallback): Promise<void> {\n    return this.subscribeWithReplay(topic, cb);\n  }\n}\n\n/**\n * Distributed leasing capability, separate from event delivery (`PubSub`).\n *\n * Used by the signals layer to elect a single owner across multiple\n * processes (e.g. serverless invocations) for a given resource — most\n * commonly a thread-key, where the owner is the process that will wake\n * and run the agent stream.\n *\n * Leasing is a distinct concern from pub/sub: a backend only implements\n * this when it can genuinely coordinate a lock (Redis via SET-NX, an\n * in-memory map for single-process). Backends that cannot lease simply do\n * not implement `LeaseProvider`; the signals runtime feature-detects and\n * falls back to {@link NoopLeaseProvider} (always-win / no-op), preserving\n * single-process behavior.\n */\nexport interface LeaseProvider {\n  /**\n   * Atomically try to acquire a lease on a key.\n   *\n   * Returns `{ acquired: true, owner }` if the caller claimed the lease,\n   * or `{ acquired: false, owner }` where `owner` is the current holder\n   * (so the caller can route follow-up work to them). `owner` may be\n   * `undefined` if the holder could not be read (rare).\n   *\n   * @param key - The lease key (e.g. thread key)\n   * @param owner - Identifier for the owner (e.g. runId) — used so the\n   *   same owner can call `acquireLease` idempotently and renew/release.\n   * @param ttlMs - Time-to-live in milliseconds for the lease\n   */\n  acquireLease(key: string, owner: string, ttlMs: number): Promise<{ acquired: boolean; owner?: string }>;\n\n  /**\n   * Read the current owner of a lease, or `undefined` if no lease is held.\n   */\n  getLeaseOwner(key: string): Promise<string | undefined>;\n\n  /**\n   * Release a lease. No-op if the caller is not the current owner\n   * (implementations should atomically check ownership before releasing\n   * to avoid clobbering a renewal that happened concurrently).\n   */\n  releaseLease(key: string, owner: string): Promise<void>;\n\n  /**\n   * Renew an existing lease owned by `owner`, extending its TTL.\n   *\n   * Returns `true` if the renewal succeeded (caller still owns it),\n   * `false` if the lease was lost (TTL expired or another owner took it).\n   */\n  renewLease(key: string, owner: string, ttlMs: number): Promise<boolean>;\n\n  /**\n   * Atomically hand a held lease from `fromOwner` to `toOwner`, refreshing\n   * its TTL, without ever releasing the key in between.\n   *\n   * This is the gap-free primitive used when one owner finishes but a\n   * follow-up owner must take over the *same* lease key immediately (e.g. a\n   * thread run completes and a queued follow-up run drains on the same\n   * thread). A naive release-then-acquire would briefly leave the key empty,\n   * letting a racing process win the freed lease and start a competing run.\n   *\n   * Returns `true` if `fromOwner` still held the lease and ownership moved to\n   * `toOwner`; `false` if the lease was already lost (expired or taken by a\n   * third owner), in which case the caller should fall back to a fresh\n   * `acquireLease`.\n   *\n   * Backends that cannot perform this atomically must still implement it —\n   * as a best-effort `releaseLease(from)` followed by `acquireLease(to)` — and\n   * document that the swap is non-atomic (a racing process can win the key in\n   * the gap). Keeping it required means callers have a single code path and the\n   * atomicity guarantee is an explicit per-backend decision rather than a\n   * silent caller-side fallback.\n   */\n  transferLease(key: string, fromOwner: string, toOwner: string, ttlMs: number): Promise<boolean>;\n}\n\n/**\n * Duck-typed check for whether a value implements {@link LeaseProvider}.\n *\n * Uses structural detection rather than `instanceof` so it works across\n * package boundaries (e.g. a separately-published pubsub backend resolving\n * a different copy of `@mastra/core`).\n */\nexport function isLeaseProvider(value: unknown): value is LeaseProvider {\n  if (!value || (typeof value !== 'object' && typeof value !== 'function')) return false;\n  const candidate = value as Partial<LeaseProvider>;\n  return (\n    typeof candidate.acquireLease === 'function' &&\n    typeof candidate.getLeaseOwner === 'function' &&\n    typeof candidate.releaseLease === 'function' &&\n    typeof candidate.renewLease === 'function' &&\n    typeof candidate.transferLease === 'function'\n  );\n}\n\n/**\n * Always-win / no-op {@link LeaseProvider}. Used by the signals runtime\n * when the configured pubsub does not implement `LeaseProvider` — this\n * preserves single-process behavior where every caller \"wins\" its own\n * lease race and release/renew are inert.\n */\nexport const NoopLeaseProvider: LeaseProvider = {\n  acquireLease(_key: string, owner: string, _ttlMs: number): Promise<{ acquired: boolean; owner?: string }> {\n    return Promise.resolve({ acquired: true, owner });\n  },\n  getLeaseOwner(_key: string): Promise<string | undefined> {\n    return Promise.resolve(undefined);\n  },\n  releaseLease(_key: string, _owner: string): Promise<void> {\n    return Promise.resolve();\n  },\n  renewLease(_key: string, _owner: string, _ttlMs: number): Promise<boolean> {\n    return Promise.resolve(true);\n  },\n  transferLease(_key: string, _fromOwner: string, _toOwner: string, _ttlMs: number): Promise<boolean> {\n    // Single-process: there is no competing holder, so the handoff always\n    // \"succeeds\" — the next owner is free to proceed.\n    return Promise.resolve(true);\n  },\n};\n","import type { Event, SubscribeBatchOptions } from '../types';\n\n/**\n * Opaque timer handle. We don't care whether the runtime returns a number\n * (browser) or a `Timeout` (Node) — we only ever hand it back to\n * `clearTimeout`. Branding it keeps the type honest (you can't pass an\n * arbitrary number) while staying erasure-free at runtime.\n */\ndeclare const batchPolicyTimerHandleBrand: unique symbol;\nexport type BatchPolicyTimerHandle = { readonly [batchPolicyTimerHandleBrand]: true };\n\n/**\n * Injectable dependencies for `BatchPolicy`. Tests pass fake timers /\n * controllable clocks; production uses Node's `Date.now` / `setTimeout` /\n * `clearTimeout`.\n */\nexport interface BatchPolicyDeps {\n  now: () => number;\n  setTimeout: (cb: () => void, ms: number) => BatchPolicyTimerHandle;\n  clearTimeout: (handle: BatchPolicyTimerHandle) => void;\n}\n\nconst defaultDeps: BatchPolicyDeps = {\n  now: () => Date.now(),\n  setTimeout: (cb, ms) => setTimeout(cb, ms) as unknown as BatchPolicyTimerHandle,\n  clearTimeout: handle => clearTimeout(handle as unknown as Parameters<typeof clearTimeout>[0]),\n};\n\nexport type EnqueueDecision = 'flush-now' | 'wait';\n\nexport const DEFAULT_MAX_BUFFER_SIZE = 256;\nexport const DEFAULT_OVERFLOW: NonNullable<SubscribeBatchOptions['overflow']> = 'coalesce-or-drop-oldest';\n\n/**\n * Internal to `EventEmitterPubSub`. Embedded by `AckHandleBuffer` to decide\n * when a batched subscription should flush (size, time, coalesce, overflow).\n *\n * Not part of the public API — users configure batching via\n * `SubscribeBatchOptions` on `subscribe`.\n */\nexport class BatchPolicy {\n  private readonly opts: SubscribeBatchOptions;\n  private readonly deps: BatchPolicyDeps;\n  private readonly maxBufferSize: number;\n  private readonly overflow: NonNullable<SubscribeBatchOptions['overflow']>;\n\n  private firstQueuedAt: number | null = null;\n  private lastDeliveredAt: number = -Infinity;\n  private size = 0;\n  private timer: BatchPolicyTimerHandle | null = null;\n  private flushHandler: (() => void | Promise<void>) | null = null;\n\n  constructor(opts: SubscribeBatchOptions, deps: BatchPolicyDeps = defaultDeps) {\n    this.opts = opts;\n    this.deps = deps;\n    this.maxBufferSize = opts.maxBufferSize ?? DEFAULT_MAX_BUFFER_SIZE;\n    this.overflow = opts.overflow ?? DEFAULT_OVERFLOW;\n  }\n\n  /** Bind the function invoked when the deadline timer fires. */\n  bindFlushHandler(fn: () => void | Promise<void>): void {\n    this.flushHandler = fn;\n  }\n\n  /**\n   * Called by the integrator each time an event is enqueued.\n   * Returns whether the integrator should flush immediately.\n   */\n  onEnqueue(event: Event): EnqueueDecision {\n    this.size += 1;\n    if (this.firstQueuedAt === null) {\n      this.firstQueuedAt = this.deps.now();\n    }\n\n    const now = this.deps.now();\n    const intervalFloor = this.lastDeliveredAt + (this.opts.minIntervalMs ?? 0);\n\n    // Immediate event — bypass maxWait/maxSize gating, but still respect interval floor.\n    if (this.opts.isImmediate?.(event)) {\n      if (now >= intervalFloor) {\n        return 'flush-now';\n      }\n      // Hold until the floor; reschedule timer there.\n      this.scheduleAt(intervalFloor);\n      return 'wait';\n    }\n\n    // Overflow trigger (regardless of interval — overflow is a budget enforcement).\n    if (this.size >= this.maxBufferSize) {\n      return 'flush-now';\n    }\n\n    // maxSize trigger — respects interval floor.\n    if (this.opts.maxSize !== undefined && this.size >= this.opts.maxSize) {\n      if (now >= intervalFloor) {\n        return 'flush-now';\n      }\n      this.scheduleAt(intervalFloor);\n      return 'wait';\n    }\n\n    // No immediate trigger — schedule the deadline if there is one.\n    this.scheduleDeadline();\n    return 'wait';\n  }\n\n  /**\n   * Called by the integrator after a successful flush has delivered\n   * `deliveredCount` events. Resets timer + firstQueuedAt.\n   */\n  onFlushed(deliveredCount: number): void {\n    this.lastDeliveredAt = this.deps.now();\n    this.size = Math.max(0, this.size - deliveredCount);\n    this.firstQueuedAt = null;\n    this.cancelTimer();\n  }\n\n  /**\n   * Pure helper. Given the caller-owned queue contents, applies `coalesce`\n   * and `overflow` to decide what to deliver and what to drop.\n   * Order-preserving for kept events.\n   */\n  prepareBatch(events: Event[]): { delivered: Event[]; dropped: Event[] } {\n    let working = events;\n\n    // 1. Coalesce, if configured.\n    if (this.opts.coalesce) {\n      const coalesced = this.opts.coalesce(working);\n      // Contract: `coalesce` MUST return a subset of `working` by reference\n      // identity. Anything else (fresh objects, even with matching ids)\n      // breaks ack routing downstream — AckHandleBuffer keys ack/nack by\n      // event reference, and there's no way to map a manufactured event\n      // back to the original transport handle. Detect the violation here\n      // and discard the whole batch (treat all originals as dropped) rather\n      // than silently deliver references with no ack/nack wired up.\n      const inputRefs = new Set<Event>(working);\n      const allInInput = coalesced.every(e => inputRefs.has(e));\n      working = allInInput ? coalesced : [];\n    }\n\n    const keptRefs = new Set<Event>(working);\n    const computeDropped = (): Event[] => events.filter(e => !keptRefs.has(e));\n\n    // 2. Overflow handling — only if still over `maxBufferSize`.\n    if (working.length <= this.maxBufferSize) {\n      return { delivered: working, dropped: computeDropped() };\n    }\n\n    const overBy = working.length - this.maxBufferSize;\n    const isImmediate = this.opts.isImmediate;\n\n    let kept: Event[];\n    let droppedFromOverflow: Event[];\n\n    switch (this.overflow) {\n      case 'drop-newest': {\n        const splitFromEnd = this.takeWithoutDropping(working, overBy, isImmediate, /* fromEnd */ true);\n        kept = splitFromEnd.kept;\n        droppedFromOverflow = splitFromEnd.dropped;\n        break;\n      }\n      case 'drop-oldest':\n      case 'coalesce-or-drop-oldest':\n      default: {\n        const splitFromStart = this.takeWithoutDropping(working, overBy, isImmediate, /* fromEnd */ false);\n        kept = splitFromStart.kept;\n        droppedFromOverflow = splitFromStart.dropped;\n        break;\n      }\n    }\n\n    return { delivered: kept, dropped: [...computeDropped(), ...droppedFromOverflow] };\n  }\n\n  /** Stop the timer and clear policy state. */\n  dispose(): void {\n    this.cancelTimer();\n    this.flushHandler = null;\n    this.firstQueuedAt = null;\n    this.size = 0;\n  }\n\n  private scheduleDeadline(): void {\n    if (this.opts.maxWaitMs === undefined && this.opts.minIntervalMs === undefined) {\n      // No time-based trigger — only `maxSize` / `isImmediate` can flush.\n      return;\n    }\n\n    const firstQueuedAt = this.firstQueuedAt ?? this.deps.now();\n    const deadline = this.opts.maxWaitMs !== undefined ? firstQueuedAt + this.opts.maxWaitMs : Number.POSITIVE_INFINITY;\n    const floor = this.lastDeliveredAt + (this.opts.minIntervalMs ?? 0);\n    const at = Math.max(deadline, floor);\n    this.scheduleAt(at);\n  }\n\n  private scheduleAt(at: number): void {\n    if (!isFinite(at)) {\n      return;\n    }\n    this.cancelTimer();\n    const delay = Math.max(0, at - this.deps.now());\n    this.timer = this.deps.setTimeout(() => {\n      this.timer = null;\n      const handler = this.flushHandler;\n      if (handler) {\n        void handler();\n      }\n    }, delay);\n  }\n\n  private cancelTimer(): void {\n    if (this.timer !== null) {\n      this.deps.clearTimeout(this.timer);\n      this.timer = null;\n    }\n  }\n\n  /**\n   * Drop `count` non-immediate items from the start (or end) of `items`.\n   * Immediate items are never dropped — if every candidate is immediate,\n   * fewer than `count` items are dropped.\n   */\n  private takeWithoutDropping(\n    items: Event[],\n    count: number,\n    isImmediate: ((e: Event) => boolean) | undefined,\n    fromEnd: boolean,\n  ): { kept: Event[]; dropped: Event[] } {\n    const dropped: Event[] = [];\n    const result = [...items];\n    let remaining = count;\n\n    const order = fromEnd ? [...result.keys()].reverse() : [...result.keys()];\n\n    for (const idx of order) {\n      if (remaining === 0) break;\n      const ev = result[idx]!;\n      if (isImmediate?.(ev)) continue;\n      dropped.push(ev);\n      result[idx] = undefined as unknown as Event;\n      remaining -= 1;\n    }\n\n    const kept = result.filter((e): e is Event => e !== undefined);\n    return { kept, dropped };\n  }\n}\n","import type { Event, EventCallback, SubscribeBatchOptions } from '../types';\nimport type { BatchPolicyDeps } from './batch-policy';\nimport { BatchPolicy } from './batch-policy';\n\ninterface Entry {\n  event: Event;\n  ack?: () => Promise<void>;\n  nack?: () => Promise<void>;\n}\n\n/**\n * In-process queue used by `EventEmitterPubSub` to turn its\n * one-event-per-emit stream into batched callback invocations.\n * Owns a `BatchPolicy` that decides when to flush (size, time,\n * quiet-period) and holds (event, ack, nack) triples in publish\n * order until that decision fires.\n *\n * Extracted from `EventEmitterPubSub` only so the batching state\n * machine can be tested in isolation. Not a public extension point.\n * State is per-process; the queue dies with the process.\n */\nexport class AckHandleBuffer {\n  private readonly policy: BatchPolicy;\n  private queue: Entry[] = [];\n  private flushing = false;\n  private reflush = false;\n  private disposed = false;\n\n  constructor(\n    private readonly cb: EventCallback,\n    opts: SubscribeBatchOptions,\n    deps?: BatchPolicyDeps,\n    private readonly onError?: (err: unknown, ctx: { phase: 'cb' | 'ack-dropped' }) => void,\n  ) {\n    this.policy = new BatchPolicy(opts, deps);\n    // The policy's deadline timer fires this handler fire-and-forget (it\n    // discards the returned promise), so a rejection from `flush()` — e.g. a\n    // user-supplied `coalesce` throwing inside `prepareBatch`, which lands\n    // outside the per-event try/catch below — would otherwise escape as an\n    // unhandled rejection on the timer path. The inline flush-now, group, and\n    // explicit `flush()` paths each catch this already; route the timer path\n    // through the same `onError` channel.\n    this.policy.bindFlushHandler(() =>\n      this.flush().catch(err => {\n        this.onError?.(err, { phase: 'cb' });\n      }),\n    );\n  }\n\n  /**\n   * Called by the adapter for each event arriving from the underlying transport.\n   */\n  async push(event: Event, ack?: () => Promise<void>, nack?: () => Promise<void>): Promise<void> {\n    if (this.disposed) return;\n    this.queue.push({ event, ack, nack });\n    const decision = this.policy.onEnqueue(event);\n    if (decision === 'flush-now') {\n      await this.flush();\n    }\n  }\n\n  /**\n   * Drain the current queue regardless of policy state. Safe to call from\n   * adapter `flush()` or external code that wants to force delivery.\n   */\n  async flush(): Promise<void> {\n    // A flush-now request that lands while we're already draining is not\n    // dropped — latch it so the current pass picks up the new events as\n    // soon as it finishes its current snapshot, instead of forcing those\n    // events to wait until the policy timer fires.\n    if (this.flushing) {\n      this.reflush = true;\n      return;\n    }\n    // Empty buffer is a true no-op. `policy.onFlushed` bumps `lastDeliveredAt`,\n    // which extends the `minIntervalMs` floor — calling it on every empty\n    // flush silently corrupts the cadence for callers that flush() defensively.\n    if (this.queue.length === 0) return;\n\n    this.flushing = true;\n    try {\n      do {\n        this.reflush = false;\n        if (this.queue.length === 0) break;\n\n        const snapshot = this.queue;\n        this.queue = [];\n\n        const events = snapshot.map(e => e.event);\n        // Build a reverse index once so we don't pay O(n) per event looking up\n        // the original Entry below.\n        const byEvent = new Map<Event, Entry>();\n        for (const e of snapshot) byEvent.set(e.event, e);\n\n        const { delivered, dropped } = this.policy.prepareBatch(events);\n\n        // Ack events that were coalesced or overflow-dropped — they should\n        // not be redelivered. The transport's own ack is the right hook.\n        for (const ev of dropped) {\n          const entry = byEvent.get(ev);\n          if (entry?.ack) {\n            try {\n              await entry.ack();\n            } catch (err) {\n              this.onError?.(err, { phase: 'ack-dropped' });\n            }\n          }\n        }\n\n        for (const ev of delivered) {\n          // A cb may dispose the buffer mid-flush (e.g. subscriber tearing\n          // itself down on a fatal event). Honor it immediately — don't keep\n          // feeding events into a callback that asked to stop.\n          if (this.disposed) break;\n          const entry = byEvent.get(ev);\n          try {\n            // The declared EventCallback return type is `void`, but real\n            // implementations frequently return a Promise. Await both kinds\n            // so per-event isolation actually waits for the cb to settle.\n            await (this.cb(ev, entry?.ack, entry?.nack) as void | Promise<void>);\n          } catch (err) {\n            this.onError?.(err, { phase: 'cb' });\n          }\n        }\n\n        // `policy.size` was incremented once per push; decrement it by\n        // everything that left the queue (delivered + dropped) so it doesn't\n        // drift upward and trip maxSize prematurely.\n        this.policy.onFlushed(delivered.length + dropped.length);\n      } while (this.reflush && !this.disposed);\n    } finally {\n      this.flushing = false;\n    }\n  }\n\n  dispose(): void {\n    this.disposed = true;\n    this.queue = [];\n    this.policy.dispose();\n  }\n}\n","import EventEmitter from 'node:events';\nimport type { IMastraLogger } from '../../logger';\nimport { PubSub } from '../pubsub';\nimport type { LeaseProvider, PubSubDeliveryMode } from '../pubsub';\nimport type { Event, EventCallback, SubscribeOptions } from '../types';\nimport { AckHandleBuffer } from './ack-handle-buffer';\n\nexport interface EventEmitterPubSubOptions {\n  /**\n   * Optional logger for surfacing batched-delivery errors. Falls back to\n   * `console.error` when not provided.\n   */\n  logger?: IMastraLogger;\n}\n\n// Reused for the fan-out delivery path where ack/nack are no-ops: the process\n// is the broker, there is no transport-level redelivery to negotiate. Hoisted\n// to module scope so we don't allocate two new closures per emitted event.\nconst NOOP_ACK = async (): Promise<void> => {};\n\nexport class EventEmitterPubSub extends PubSub implements LeaseProvider {\n  // EventEmitter dispatches synchronously to listeners, so it can serve both\n  // a push consumer (no worker) and a pull-style worker that simply calls\n  // `subscribe()` to register a listener. Both modes are advertised so the\n  // default in-process setup keeps using OrchestrationWorker, while\n  // genuinely push-only transports (GCP Pub/Sub push, SNS, EventBridge)\n  // declare `['push']` only and skip the worker.\n  override get supportedModes(): ReadonlyArray<PubSubDeliveryMode> {\n    return ['pull', 'push'];\n  }\n\n  /**\n   * `EventEmitterPubSub` is strictly in-process, so the `AckHandleBuffer`\n   * queue it uses for batching shares the same lifetime as everything\n   * else here. Nothing more durable is promised, and nothing less is\n   * needed.\n   */\n  override get supportsNativeBatching(): boolean {\n    return true;\n  }\n\n  private emitter: EventEmitter;\n\n  // group → topic → callbacks[]\n  private groups: Map<string, Map<string, EventCallback[]>> = new Map();\n  // \"topic:group\" → round-robin counter\n  private groupCounters: Map<string, number> = new Map();\n  // \"topic:group\" → the single listener registered on the emitter for this group\n  private groupListeners: Map<string, (event: Event) => void> = new Map();\n\n  // Track pending nack redeliveries so flush() can wait and close() can cancel them\n  private pendingNacks: Set<ReturnType<typeof setTimeout>> = new Set();\n\n  // Track delivery attempts per message id\n  private deliveryAttempts: Map<string, number> = new Map();\n\n  // topic → (original callback → wrapped listener) for fan-out (non-group) subscribers.\n  // Nested keying so the same callback registered on multiple topics keeps\n  // a distinct wrapper per topic.\n  private fanoutWrappers: Map<string, Map<EventCallback, (event: Event) => void>> = new Map();\n\n  // topic → (original callback → buffer). Present only for subscribers that\n  // opt into batching via `options.batch`. The buffer is the destination of\n  // the emitter listener; it invokes the user cb according to its policy.\n  private batchBuffers: Map<string, Map<EventCallback, AckHandleBuffer>> = new Map();\n\n  private readonly logger?: IMastraLogger;\n\n  constructor(existingEmitter?: EventEmitter, options: EventEmitterPubSubOptions = {}) {\n    super();\n    this.emitter = existingEmitter ?? new EventEmitter();\n    this.logger = options.logger;\n  }\n\n  /**\n   * Debug-hostile silent failures are the default for emitter listeners.\n   * Surface buffer-side errors on a single channel so they're at least visible.\n   */\n  private logBufferError(topic: string, err: unknown, ctx: { phase: 'cb' | 'ack-dropped' }): void {\n    const message = `[EventEmitterPubSub] batched ${ctx.phase} failed for ${topic}`;\n    if (this.logger) {\n      this.logger.error(message, err);\n    } else {\n      console.error(message, err);\n    }\n  }\n\n  async publish(\n    topic: string,\n    event: Omit<Event, 'id' | 'createdAt'>,\n    _options?: { localOnly?: boolean },\n  ): Promise<void> {\n    const id = crypto.randomUUID();\n    const createdAt = new Date();\n    this.emitter.emit(topic, {\n      ...event,\n      id,\n      createdAt,\n      deliveryAttempt: 1,\n    });\n  }\n\n  async subscribe(topic: string, cb: EventCallback, options?: SubscribeOptions): Promise<void> {\n    if (options?.batch) {\n      // Batched path: insert an AckHandleBuffer between the emitter and cb.\n      // ack/nack are no-ops at this layer — the process is the broker.\n      const buffer = new AckHandleBuffer(cb, options.batch, undefined, (err, ctx) => {\n        this.logBufferError(topic, err, ctx);\n      });\n      let byCb = this.batchBuffers.get(topic);\n      if (!byCb) {\n        byCb = new Map();\n        this.batchBuffers.set(topic, byCb);\n      }\n      byCb.set(cb, buffer);\n\n      if (options.group) {\n        // Group path: the group's member list keeps the original `cb` so\n        // `unsubscribe(topic, cb)` and round-robin tracking work unchanged.\n        // `deliverToGroup` checks `batchBuffers` and routes through the\n        // buffer when present.\n        this.subscribeWithGroup(topic, cb, options.group);\n      } else {\n        const wrapper = (event: Event) => {\n          // Fire-and-forget — buffer.push can reject if the user-supplied\n          // `coalesce` throws or any other policy step fails during an\n          // inline flush-now. Surface those through the logger rather\n          // than letting them become unhandled rejections.\n          void buffer.push(event, NOOP_ACK, NOOP_ACK).catch(err => {\n            this.logBufferError(topic, err, { phase: 'cb' });\n          });\n        };\n        let byCbFanout = this.fanoutWrappers.get(topic);\n        if (!byCbFanout) {\n          byCbFanout = new Map();\n          this.fanoutWrappers.set(topic, byCbFanout);\n        }\n        byCbFanout.set(cb, wrapper);\n        this.emitter.on(topic, wrapper);\n      }\n      return;\n    }\n\n    if (options?.group) {\n      this.subscribeWithGroup(topic, cb, options.group);\n    } else {\n      const wrapper = (event: Event) => {\n        cb(event, NOOP_ACK, NOOP_ACK);\n      };\n      let byCb = this.fanoutWrappers.get(topic);\n      if (!byCb) {\n        byCb = new Map();\n        this.fanoutWrappers.set(topic, byCb);\n      }\n      byCb.set(cb, wrapper);\n      this.emitter.on(topic, wrapper);\n    }\n  }\n\n  async unsubscribe(topic: string, cb: EventCallback): Promise<void> {\n    // Tear down a batching buffer for this (topic, cb) pair, if one was set\n    // up by `subscribe`. Done first so any in-flight emitter dispatches\n    // ignore further events into a disposed buffer.\n    const byCbBuffers = this.batchBuffers.get(topic);\n    const buffer = byCbBuffers?.get(cb);\n    if (buffer && byCbBuffers) {\n      buffer.dispose();\n      byCbBuffers.delete(cb);\n      if (byCbBuffers.size === 0) this.batchBuffers.delete(topic);\n    }\n\n    // Check if this callback is in any group for this topic\n    for (const [group, topicMap] of this.groups) {\n      const members = topicMap.get(topic);\n      if (members) {\n        const idx = members.indexOf(cb);\n        if (idx !== -1) {\n          members.splice(idx, 1);\n          // If group is now empty for this topic, remove the emitter listener\n          if (members.length === 0) {\n            topicMap.delete(topic);\n            const listenerKey = `${topic}:${group}`;\n            const listener = this.groupListeners.get(listenerKey);\n            if (listener) {\n              this.emitter.off(topic, listener);\n              this.groupListeners.delete(listenerKey);\n              this.groupCounters.delete(listenerKey);\n            }\n          }\n          if (topicMap.size === 0) {\n            this.groups.delete(group);\n          }\n          return;\n        }\n      }\n    }\n\n    // Not in a group — remove as fan-out listener\n    const byCb = this.fanoutWrappers.get(topic);\n    const wrapper = byCb?.get(cb);\n    if (wrapper && byCb) {\n      this.emitter.off(topic, wrapper);\n      byCb.delete(cb);\n      if (byCb.size === 0) this.fanoutWrappers.delete(topic);\n    } else {\n      this.emitter.off(topic, cb);\n    }\n  }\n\n  async flush(): Promise<void> {\n    // A batched cb can nack mid-delivery, which schedules a redelivery via\n    // setTimeout(0). The redelivered event lands back in `batchBuffers`\n    // (the buffer is the group member's destination) and may sit there\n    // below maxSize/maxWaitMs thresholds. So we loop: drain buffers, wait\n    // for pending nacks to fire, then check whether either side produced\n    // more work. Stable-state termination requires both to be empty at the\n    // top of a single iteration.\n    while (true) {\n      const drains: { topic: string; promise: Promise<void> }[] = [];\n      for (const [topic, byCb] of this.batchBuffers.entries()) {\n        for (const buffer of byCb.values()) {\n          drains.push({ topic, promise: buffer.flush() });\n        }\n      }\n      if (drains.length > 0) {\n        // allSettled — a single throwing buffer should not block the rest from\n        // flushing during shutdown. Rejections that propagate this far skipped\n        // the per-event try/catch in AckHandleBuffer (e.g. a throwing coalesce)\n        // and must be surfaced or they vanish at shutdown.\n        const results = await Promise.allSettled(drains.map(d => d.promise));\n        for (let i = 0; i < results.length; i++) {\n          const result = results[i]!;\n          if (result.status === 'rejected') {\n            this.logBufferError(drains[i]!.topic, result.reason, { phase: 'cb' });\n          }\n        }\n      }\n\n      if (this.pendingNacks.size === 0) {\n        // Nothing scheduled — and the drain above either did nothing or\n        // produced no new pending nacks, so we're stable.\n        return;\n      }\n\n      // Wait for the currently-scheduled nacks to fire. Each redelivery\n      // may land in a buffer; loop and re-drain.\n      await new Promise<void>(resolve => {\n        const check = () => {\n          if (this.pendingNacks.size === 0) {\n            resolve();\n          } else {\n            setTimeout(check, 10);\n          }\n        };\n        check();\n      });\n    }\n  }\n\n  /**\n   * Clean up all listeners during graceful shutdown.\n   */\n  async close(): Promise<void> {\n    // Cancel pending nack redeliveries\n    for (const handle of this.pendingNacks) {\n      clearTimeout(handle);\n    }\n    this.pendingNacks.clear();\n    this.deliveryAttempts.clear();\n\n    // Dispose every batching buffer so timers are cleared.\n    for (const byCb of this.batchBuffers.values()) {\n      for (const buffer of byCb.values()) {\n        buffer.dispose();\n      }\n    }\n    this.batchBuffers.clear();\n\n    this.emitter.removeAllListeners();\n    this.groups.clear();\n    this.groupCounters.clear();\n    this.groupListeners.clear();\n    this.fanoutWrappers.clear();\n  }\n\n  private subscribeWithGroup(topic: string, cb: EventCallback, group: string): void {\n    let topicMap = this.groups.get(group);\n    if (!topicMap) {\n      topicMap = new Map();\n      this.groups.set(group, topicMap);\n    }\n\n    let members = topicMap.get(topic);\n    if (!members) {\n      members = [];\n      topicMap.set(topic, members);\n    }\n\n    members.push(cb);\n\n    // Register a single emitter listener per topic:group pair\n    const listenerKey = `${topic}:${group}`;\n    if (!this.groupListeners.has(listenerKey)) {\n      const listener = (event: Event) => {\n        this.deliverToGroup(topic, group, listenerKey, event);\n      };\n\n      this.groupListeners.set(listenerKey, listener);\n      this.emitter.on(topic, listener);\n    }\n  }\n\n  private deliverToGroup(topic: string, group: string, listenerKey: string, event: Event): void {\n    const currentMembers = this.groups.get(group)?.get(topic);\n    if (!currentMembers || currentMembers.length === 0) return;\n\n    const counter = this.groupCounters.get(listenerKey) ?? 0;\n    const idx = counter % currentMembers.length;\n    this.groupCounters.set(listenerKey, counter + 1);\n\n    // Track delivery attempts scoped per group listener, so ack/nack in one\n    // group doesn't disturb another group's attempt counter for the same event.\n    const attemptKey = `${listenerKey}:${event.id}`;\n    const attempt = this.deliveryAttempts.get(attemptKey) ?? 1;\n    const eventWithAttempt = { ...event, deliveryAttempt: attempt };\n\n    const ack = async () => {\n      // Message successfully processed — clean up attempt tracking\n      this.deliveryAttempts.delete(attemptKey);\n    };\n\n    const nack = async () => {\n      // Message processing failed — redeliver to the group after a short delay\n      // Increment delivery attempt counter\n      this.deliveryAttempts.set(attemptKey, attempt + 1);\n\n      const handle = setTimeout(() => {\n        this.pendingNacks.delete(handle);\n        this.deliverToGroup(topic, group, listenerKey, event);\n      }, 0);\n      this.pendingNacks.add(handle);\n    };\n\n    const member = currentMembers[idx]!;\n    // If this member opted into batching, route through its buffer.\n    const buffer = this.batchBuffers.get(topic)?.get(member);\n    if (buffer) {\n      // Same rationale as the fan-out push above: surface rejections\n      // through the logger so they don't escape as unhandled.\n      void buffer.push(eventWithAttempt, ack, nack).catch(err => {\n        this.logBufferError(topic, err, { phase: 'cb' });\n      });\n    } else {\n      member(eventWithAttempt, ack, nack);\n    }\n  }\n\n  // key → { owner, expiresAt }. In-process so a single Map is enough;\n  // there is no other process to race against. The same owner can renew\n  // their own lease; expired entries are reclaimed lazily on the next\n  // acquireLease call.\n  private leases: Map<string, { owner: string; expiresAt: number }> = new Map();\n\n  acquireLease(key: string, owner: string, ttlMs: number): Promise<{ acquired: boolean; owner?: string }> {\n    const now = Date.now();\n    const existing = this.leases.get(key);\n    if (existing && existing.expiresAt > now && existing.owner !== owner) {\n      return Promise.resolve({ acquired: false, owner: existing.owner });\n    }\n    this.leases.set(key, { owner, expiresAt: now + ttlMs });\n    return Promise.resolve({ acquired: true, owner });\n  }\n\n  getLeaseOwner(key: string): Promise<string | undefined> {\n    const existing = this.leases.get(key);\n    if (!existing) return Promise.resolve(undefined);\n    if (existing.expiresAt <= Date.now()) {\n      this.leases.delete(key);\n      return Promise.resolve(undefined);\n    }\n    return Promise.resolve(existing.owner);\n  }\n\n  releaseLease(key: string, owner: string): Promise<void> {\n    const existing = this.leases.get(key);\n    if (existing && existing.owner === owner) {\n      this.leases.delete(key);\n    }\n    return Promise.resolve();\n  }\n\n  renewLease(key: string, owner: string, ttlMs: number): Promise<boolean> {\n    const existing = this.leases.get(key);\n    if (!existing || existing.owner !== owner || existing.expiresAt <= Date.now()) {\n      return Promise.resolve(false);\n    }\n    existing.expiresAt = Date.now() + ttlMs;\n    return Promise.resolve(true);\n  }\n\n  // Atomic owner-guarded handoff: only the current owner can transfer, and the\n  // key is never empty during the swap (mirrors the Redis GET==from -> SET to\n  // Lua). Lets a finishing run hand the lease to its drain run without a\n  // release/acquire gap, even on the in-process backend.\n  transferLease(key: string, fromOwner: string, toOwner: string, ttlMs: number): Promise<boolean> {\n    const existing = this.leases.get(key);\n    if (!existing || existing.owner !== fromOwner || existing.expiresAt <= Date.now()) {\n      return Promise.resolve(false);\n    }\n    this.leases.set(key, { owner: toOwner, expiresAt: Date.now() + ttlMs });\n    return Promise.resolve(true);\n  }\n}\n"],"mappings":"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"}