{"version":3,"file":"emitter.mjs","names":[],"sources":["../../../../../../../ai/src/orchestrator/emitter.ts"],"sourcesContent":["import type {\n  EventIdentity,\n  WithoutIdentity,\n} from \"../contracts/events/event-identity.type\";\nimport type {\n  OrchestratorEventHandler,\n  OrchestratorEventHandlers,\n  OrchestratorEventMap,\n  OrchestratorEventName,\n} from \"../contracts/orchestrator/orchestrator-event.type\";\n\n/** Full identity-stamped payload an orchestrator handler receives. */\ntype EventPayload<K extends OrchestratorEventName> = OrchestratorEventMap[K] &\n  EventIdentity;\n\n/**\n * Erased handler shape for the instance registry. Per-event handlers\n * are contravariant in their payload, so the registry stores them under\n * a single structural `(payload) => void` and re-narrows at the call\n * site — the `on` / `off` public surface keeps the precise per-event\n * typing.\n */\ntype AnyHandler = (payload: EventPayload<OrchestratorEventName>) => void;\n\n/**\n * Three-tier orchestrator event emitter — definition (factory) →\n * instance → per-call — for the `orchestrator.*` namespace (design\n * §14.3). Mirrors {@link import(\"../supervisor/emitter\").SupervisorEmitter}\n * structurally; the differences are the event map and a central\n * identity-injection chokepoint (`emit` accepts an identity-less\n * payload and stamps {@link EventIdentity} once so all three tiers, and\n * any mirror like the stream, see the same value).\n *\n * Owns: the instance-handler registry and the fan-out order. Does NOT\n * own: child `supervisor.*` / `agent.*` events — those bubble up\n * unmodified under their own identity (§14.2) and never pass through\n * this emitter. All matching handlers fire in tier order; a handler\n * throwing never derails the turn.\n *\n * @example\n * const emitter = new OrchestratorEmitter(config.on);\n * const off = emitter.on(\"orchestrator.turn.completed\", (event) => log(event));\n * emitter.emit(\n *   \"orchestrator.turn.starting\",\n *   { sessionId, turnIndex },\n *   { runId, rootRunId },\n *   perCallHandlers,\n * );\n */\nexport class OrchestratorEmitter {\n  private readonly factoryHandlers?: OrchestratorEventHandlers;\n  private readonly instanceHandlers = new Map<\n    OrchestratorEventName,\n    Set<AnyHandler>\n  >();\n\n  public constructor(factoryHandlers?: OrchestratorEventHandlers) {\n    this.factoryHandlers = factoryHandlers;\n  }\n\n  /**\n   * Subscribe an instance-level handler (tier 2). Returns an\n   * unsubscribe function equivalent to `off(event, handler)`.\n   */\n  public on<K extends OrchestratorEventName>(\n    event: K,\n    handler: OrchestratorEventHandler<K>,\n  ): () => void {\n    let bucket = this.instanceHandlers.get(event);\n\n    if (!bucket) {\n      bucket = new Set();\n      this.instanceHandlers.set(event, bucket);\n    }\n\n    bucket.add(handler as unknown as AnyHandler);\n\n    return () => this.off(event, handler);\n  }\n\n  /**\n   * Remove a previously-subscribed instance handler. No-op when the\n   * handler was never registered or already removed.\n   */\n  public off<K extends OrchestratorEventName>(\n    event: K,\n    handler: OrchestratorEventHandler<K>,\n  ): void {\n    this.instanceHandlers.get(event)?.delete(handler as unknown as AnyHandler);\n  }\n\n  /**\n   * Stamp run identity onto the payload, then fan out through all three\n   * tiers in order: definition → instance → per-call. Returns the full\n   * identity-stamped payload so the caller can mirror the same value\n   * into the stream controller (keeping `.on()` and iteration in lockstep).\n   */\n  public emit<K extends OrchestratorEventName>(\n    event: K,\n    payload: WithoutIdentity<OrchestratorEventMap[K]>,\n    identity: EventIdentity,\n    perCallHandlers?: OrchestratorEventHandlers,\n  ): EventPayload<K> {\n    const fullPayload = { ...payload, ...identity } as EventPayload<K>;\n\n    invoke(this.factoryHandlers?.[event], fullPayload);\n\n    const bucket = this.instanceHandlers.get(event);\n\n    if (bucket) {\n      for (const handler of bucket) {\n        invoke(handler as unknown as (payload: EventPayload<K>) => void, fullPayload);\n      }\n    }\n\n    invoke(perCallHandlers?.[event], fullPayload);\n\n    return fullPayload;\n  }\n}\n\n/**\n * Invoke a single handler, swallowing any throw. A listener bug must\n * never derail the orchestrator turn. Typed structurally (a plain\n * `(payload) => void`) so the identity-stamped payload flows in without\n * fighting the contravariant `OrchestratorEventHandler<K>` union.\n */\nfunction invoke<K extends OrchestratorEventName>(\n  handler: ((payload: EventPayload<K>) => void) | undefined,\n  payload: EventPayload<K>,\n): void {\n  if (typeof handler !== \"function\") {\n    return;\n  }\n\n  try {\n    handler(payload);\n  } catch {\n    // Listener bugs must not derail the orchestrator.\n  }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAiDA,IAAa,sBAAb,MAAiC;CAO/B,AAAO,YAAY,iBAA6C;0CAL5B,IAAI,IAGtC;EAGA,KAAK,kBAAkB;CACzB;;;;;CAMA,AAAO,GACL,OACA,SACY;EACZ,IAAI,SAAS,KAAK,iBAAiB,IAAI,KAAK;EAE5C,IAAI,CAAC,QAAQ;GACX,yBAAS,IAAI,IAAI;GACjB,KAAK,iBAAiB,IAAI,OAAO,MAAM;EACzC;EAEA,OAAO,IAAI,OAAgC;EAE3C,aAAa,KAAK,IAAI,OAAO,OAAO;CACtC;;;;;CAMA,AAAO,IACL,OACA,SACM;EACN,KAAK,iBAAiB,IAAI,KAAK,CAAC,EAAE,OAAO,OAAgC;CAC3E;;;;;;;CAQA,AAAO,KACL,OACA,SACA,UACA,iBACiB;EACjB,MAAM,cAAc;GAAE,GAAG;GAAS,GAAG;EAAS;EAE9C,OAAO,KAAK,kBAAkB,QAAQ,WAAW;EAEjD,MAAM,SAAS,KAAK,iBAAiB,IAAI,KAAK;EAE9C,IAAI,QACF,KAAK,MAAM,WAAW,QACpB,OAAO,SAA0D,WAAW;EAIhF,OAAO,kBAAkB,QAAQ,WAAW;EAE5C,OAAO;CACT;AACF;;;;;;;AAQA,SAAS,OACP,SACA,SACM;CACN,IAAI,OAAO,YAAY,YACrB;CAGF,IAAI;EACF,QAAQ,OAAO;CACjB,QAAQ,CAER;AACF"}