{"version":3,"file":"index.cjs","names":["EventEmitter","v","EventEmitter","v"],"sources":["../../../../../../@warlock.js/herald/src/communicators/broker.ts","../../../../../../@warlock.js/herald/src/communicators/broker-registry.ts","../../../../../../@warlock.js/herald/src/message-managers/prepare-consumer-subscription.ts","../../../../../../@warlock.js/herald/src/drivers/rabbitmq/rabbitmq-channel.ts","../../../../../../@warlock.js/herald/src/drivers/rabbitmq/rabbitmq-driver.ts","../../../../../../@warlock.js/herald/src/utils/connect-to-broker.ts","../../../../../../@warlock.js/herald/src/decorators/consumable.ts","../../../../../../@warlock.js/herald/src/message-managers/event-consumer.ts","../../../../../../@warlock.js/herald/src/message-managers/event-message.ts","../../../../../../@warlock.js/herald/src/use-case-broadcast.ts"],"sourcesContent":["import type { BrokerDriverContract } from \"../contracts\";\r\nimport type { ChannelContract } from \"../contracts/channel.contract\";\r\nimport { EventMessage } from \"../message-managers/event-message\";\r\nimport { EventConsumerClass } from \"../message-managers/types\";\r\nimport type { ChannelOptions } from \"../types\";\r\n\r\n/**\r\n * Options for creating a Broker\r\n */\r\nexport interface BrokerOptions {\r\n  /** Unique name for this broker */\r\n  name: string;\r\n  /** The underlying driver */\r\n  driver: BrokerDriverContract;\r\n  /** Whether this is the default broker */\r\n  isDefault?: boolean;\r\n}\r\n\r\n/**\r\n * Broker - wrapper around a driver with metadata\r\n *\r\n * Similar to DataSource in @warlock.js/cascade\r\n *\r\n * @example\r\n * ```typescript\r\n * const broker = new Broker({\r\n *   name: \"default\",\r\n *   driver: rabbitMQDriver,\r\n *   isDefault: true,\r\n * });\r\n *\r\n * // Get a channel\r\n * const channel = broker.channel(\"user.created\");\r\n * ```\r\n */\r\nexport class Broker {\r\n  /** Unique name identifying this broker */\r\n  public readonly name: string;\r\n\r\n  /** The underlying driver */\r\n  public readonly driver: BrokerDriverContract;\r\n\r\n  /** Whether this is the default broker */\r\n  public readonly isDefault: boolean;\r\n\r\n  /**\r\n   * Create a new Broker\r\n   *\r\n   * @param options - Broker configuration\r\n   */\r\n  public constructor(options: BrokerOptions) {\r\n    this.name = options.name;\r\n    this.driver = options.driver;\r\n    this.isDefault = Boolean(options.isDefault);\r\n  }\r\n\r\n  /**\r\n   * Subscribe the given consumer\r\n   */\r\n  public subscribe(consumer: EventConsumerClass<any>) {\r\n    return this.driver.subscribe(consumer);\r\n  }\r\n\r\n  /**\r\n   * Publish the given event message\r\n   */\r\n  public publish<TPayload = Record<string, any>>(event: EventMessage<TPayload>) {\r\n    this.driver.publish(event);\r\n  }\r\n\r\n  /**\r\n   * Get or create a channel\r\n   *\r\n   * @param name - Channel name\r\n   * @param options - Channel options\r\n   * @returns Channel instance\r\n   *\r\n   * @example\r\n   * ```typescript\r\n   * // Simple channel\r\n   * const channel = broker.channel(\"notifications\");\r\n   *\r\n   * // Typed channel with schema\r\n   * const orderChannel = broker.channel<OrderPayload>(\"orders\", {\r\n   *   schema: OrderSchema,\r\n   *   durable: true,\r\n   * });\r\n   * ```\r\n   */\r\n  public channel<TPayload = unknown>(\r\n    name: string,\r\n    options?: ChannelOptions<TPayload>,\r\n  ): ChannelContract<TPayload> {\r\n    return this.driver.channel<TPayload>(name, options);\r\n  }\r\n\r\n  /**\r\n   * Check if the broker is connected\r\n   */\r\n  public get isConnected(): boolean {\r\n    return this.driver.isConnected;\r\n  }\r\n\r\n  /**\r\n   * Connect the underlying driver\r\n   */\r\n  public async connect(): Promise<void> {\r\n    await this.driver.connect();\r\n  }\r\n\r\n  /**\r\n   * Disconnect the underlying driver\r\n   */\r\n  public async disconnect(): Promise<void> {\r\n    await this.driver.disconnect();\r\n  }\r\n\r\n  /**\r\n   * Start consuming messages\r\n   */\r\n  public async startConsuming(): Promise<void> {\r\n    await this.driver.startConsuming();\r\n  }\r\n\r\n  /**\r\n   * Stop consuming messages\r\n   */\r\n  public async stopConsuming(): Promise<void> {\r\n    await this.driver.stopConsuming();\r\n  }\r\n\r\n  /**\r\n   * Health check\r\n   */\r\n  public async healthCheck() {\r\n    return this.driver.healthCheck();\r\n  }\r\n}\r\n","import { EventEmitter } from \"node:events\";\r\nimport type { BrokerRegistryEvent, BrokerRegistryListener } from \"../types\";\r\nimport { Broker, type BrokerOptions } from \"./broker\";\r\n\r\n/**\r\n * Error thrown when a broker is not found\r\n */\r\nexport class MissingBrokerError extends Error {\r\n  public readonly brokerName?: string;\r\n\r\n  public constructor(message: string, brokerName?: string) {\r\n    super(message);\r\n    this.name = \"MissingBrokerError\";\r\n    this.brokerName = brokerName;\r\n  }\r\n}\r\n\r\n/**\r\n * Broker Registry\r\n *\r\n * Maintains registry of named brokers.\r\n * Similar to DataSourceRegistry in @warlock.js/cascade\r\n *\r\n * @example\r\n * ```typescript\r\n * // Register a broker\r\n * brokerRegistry.register({\r\n *   name: \"default\",\r\n *   driver: rabbitMQDriver,\r\n *   isDefault: true,\r\n * });\r\n *\r\n * // Get the default broker\r\n * const comm = brokerRegistry.get();\r\n *\r\n * // Get a specific broker by name\r\n * const analytics = brokerRegistry.get(\"analytics\");\r\n *\r\n * // Listen for events\r\n * brokerRegistry.on(\"connected\", (comm) => {\r\n *   console.log(`${comm.name} connected`);\r\n * });\r\n * ```\r\n */\r\nclass BrokerRegistry {\r\n  private readonly sources = new Map<string, Broker>();\r\n  private defaultSource?: Broker;\r\n  private readonly events = new EventEmitter();\r\n\r\n  /**\r\n   * Register a new broker\r\n   *\r\n   * Sets up event forwarding from the driver to the registry.\r\n   *\r\n   * @param options - Broker configuration\r\n   * @returns The registered broker instance\r\n   *\r\n   * @example\r\n   * ```typescript\r\n   * const broker = brokerRegistry.register({\r\n   *   name: \"primary\",\r\n   *   driver: myDriver,\r\n   *   isDefault: true,\r\n   * });\r\n   * ```\r\n   */\r\n  public register(options: BrokerOptions): Broker {\r\n    const broker = new Broker(options);\r\n    this.sources.set(broker.name, broker);\r\n\r\n    const isNewDefault = broker.isDefault || !this.defaultSource;\r\n\r\n    if (isNewDefault) {\r\n      this.defaultSource = broker;\r\n    }\r\n\r\n    // Emit registration events\r\n    this.events.emit(\"registered\", broker);\r\n\r\n    if (isNewDefault) {\r\n      this.events.emit(\"default-registered\", broker);\r\n    }\r\n\r\n    // Forward driver events to registry\r\n    broker.driver.on(\"connected\", () => {\r\n      this.events.emit(\"connected\", broker);\r\n    });\r\n\r\n    broker.driver.on(\"disconnected\", () => {\r\n      this.events.emit(\"disconnected\", broker);\r\n    });\r\n\r\n    return broker;\r\n  }\r\n\r\n  /**\r\n   * Clear all registered brokers\r\n   */\r\n  public clear(): void {\r\n    this.defaultSource = undefined;\r\n    this.sources.clear();\r\n  }\r\n\r\n  /**\r\n   * Listen for registry events\r\n   *\r\n   * @param event - Event to listen for\r\n   * @param listener - Callback function\r\n   *\r\n   * @example\r\n   * ```typescript\r\n   * brokerRegistry.on(\"registered\", (comm) => {\r\n   *   console.log(`Broker \"${comm.name}\" registered`);\r\n   * });\r\n   *\r\n   * brokerRegistry.on(\"connected\", (comm) => {\r\n   *   console.log(`Broker \"${comm.name}\" connected`);\r\n   * });\r\n   * ```\r\n   */\r\n  public on(event: BrokerRegistryEvent, listener: BrokerRegistryListener): void {\r\n    this.events.on(event, listener);\r\n  }\r\n\r\n  /**\r\n   * Listen for a registry event once\r\n   *\r\n   * @param event - Event to listen for\r\n   * @param listener - Callback function\r\n   */\r\n  public once(event: BrokerRegistryEvent, listener: BrokerRegistryListener): void {\r\n    this.events.once(event, listener);\r\n  }\r\n\r\n  /**\r\n   * Remove an event listener\r\n   *\r\n   * @param event - Event to stop listening for\r\n   * @param listener - Callback to remove\r\n   */\r\n  public off(event: BrokerRegistryEvent, listener: BrokerRegistryListener): void {\r\n    this.events.off(event, listener);\r\n  }\r\n\r\n  /**\r\n   * Get a broker by name or the default one\r\n   *\r\n   * @param name - Optional broker name\r\n   * @returns Broker instance\r\n   * @throws MissingBrokerError if not found\r\n   *\r\n   * @example\r\n   * ```typescript\r\n   * // Get default broker\r\n   * const comm = brokerRegistry.get();\r\n   *\r\n   * // Get specific broker\r\n   * const analytics = brokerRegistry.get(\"analytics\");\r\n   * ```\r\n   */\r\n  public get(name?: string): Broker {\r\n    if (name !== undefined) {\r\n      const source = this.sources.get(name);\r\n      if (!source) {\r\n        throw new MissingBrokerError(`Broker \"${name}\" is not registered.`, name);\r\n      }\r\n      return source;\r\n    }\r\n\r\n    if (!this.defaultSource) {\r\n      throw new MissingBrokerError(\"No default broker registered.\");\r\n    }\r\n\r\n    return this.defaultSource;\r\n  }\r\n\r\n  /**\r\n   * Check if a broker exists\r\n   *\r\n   * @param name - Broker name to check\r\n   * @returns True if exists\r\n   */\r\n  public has(name: string): boolean {\r\n    return this.sources.has(name);\r\n  }\r\n\r\n  /**\r\n   * Check if any brokers are registered\r\n   */\r\n  public hasAny(): boolean {\r\n    return this.sources.size > 0;\r\n  }\r\n\r\n  /**\r\n   * Get all registered brokers\r\n   *\r\n   * @returns Array of all brokers\r\n   *\r\n   * @example\r\n   * ```typescript\r\n   * // Disconnect all brokers\r\n   * for (const comm of brokerRegistry.getAll()) {\r\n   *   await comm.disconnect();\r\n   * }\r\n   * ```\r\n   */\r\n  public getAll(): Broker[] {\r\n    return Array.from(this.sources.values());\r\n  }\r\n\r\n  /**\r\n   * Get all broker names\r\n   *\r\n   * @returns Array of broker names\r\n   */\r\n  public getNames(): string[] {\r\n    return Array.from(this.sources.keys());\r\n  }\r\n\r\n  /**\r\n   * Get the default broker (if any)\r\n   *\r\n   * @returns Default broker or undefined\r\n   */\r\n  public getDefault(): Broker | undefined {\r\n    return this.defaultSource;\r\n  }\r\n}\r\n\r\n/**\r\n * Global broker registry instance\r\n */\r\nexport const brokerRegistry = new BrokerRegistry();\r\n","import type { MessageHandler } from \"./../types\";\nimport { EventConsumerClass } from \"./types\";\n\nexport function prepareConsumerSubscription(\n  Consumer: EventConsumerClass,\n  onError?: (error: unknown, consumerName: string) => void,\n) {\n  const callback: MessageHandler<any> = async (message, ctx) => {\n    const envelope = message.payload;\n    let eventPayload = envelope.payload;\n\n    if (envelope.version) {\n      if (!Consumer.isAcceptedVersion(Number(envelope.version))) {\n        ctx.ack(); // Acknowledge but don't process\n        return;\n      }\n    }\n\n    const consumer = new Consumer();\n\n    if (consumer.schema) {\n      const result = await consumer.validate(eventPayload);\n      if (!result || result.isValid === false) {\n        ctx.nack();\n        return;\n      }\n\n      eventPayload = result.data;\n    }\n    try {\n      await consumer.handle(eventPayload, {\n        payload: eventPayload,\n        eventName: Consumer.eventName,\n        messageId: message.metadata.messageId!,\n        occurredAt: envelope.occurredAt ? new Date(envelope.occurredAt) : undefined,\n        metadata: envelope.metadata,\n        version: envelope.version,\n        message,\n      });\n      ctx.ack(); // Auto-ack on success?\n    } catch (error) {\n      ctx.nack(true); // Requeue on failure\n      if (onError) {\n        onError(error, Consumer.eventName);\n      }\n    }\n  };\n\n  return callback;\n}\n","import { v } from \"@warlock.js/seal\";\r\nimport { randomUUID } from \"node:crypto\";\r\nimport type { ChannelContract } from \"../../contracts\";\r\nimport type {\r\n  ChannelOptions,\r\n  ChannelStats,\r\n  Message,\r\n  MessageContext,\r\n  MessageHandler,\r\n  MessageMetadata,\r\n  PublishOptions,\r\n  RequestOptions,\r\n  ResponseHandler,\r\n  SubscribeOptions,\r\n  Subscription,\r\n} from \"../../types\";\r\n\r\n/**\r\n * RabbitMQ Channel Implementation\r\n *\r\n * Wraps a RabbitMQ queue/exchange with a unified API.\r\n *\r\n * @template TPayload - The typed payload\r\n */\r\nexport class RabbitMQChannel<TPayload = unknown> implements ChannelContract<TPayload> {\r\n  public readonly name: string;\r\n  public readonly options: ChannelOptions<TPayload>;\r\n\r\n  private readonly amqpChannel: any;\r\n  private readonly subscriptions = new Map<string, RabbitMQSubscription>();\r\n  private asserted = false;\r\n\r\n  /**\r\n   * Create a new RabbitMQ channel\r\n   */\r\n  public constructor(name: string, amqpChannel: any, options?: ChannelOptions<TPayload>) {\r\n    this.name = name;\r\n    this.amqpChannel = amqpChannel;\r\n    this.options = options ?? {};\r\n  }\r\n\r\n  /**\r\n   * Assert the queue exists\r\n   */\r\n  public async assert(): Promise<void> {\r\n    if (this.asserted) return;\r\n\r\n    const queueOptions = {\r\n      durable: this.options.durable ?? true,\r\n      autoDelete: this.options.autoDelete ?? false,\r\n      exclusive: this.options.exclusive ?? false,\r\n      messageTtl: this.options.messageTtl,\r\n      maxLength: this.options.maxLength,\r\n      deadLetterExchange: this.options.deadLetter?.channel ? \"\" : undefined,\r\n      deadLetterRoutingKey: this.options.deadLetter?.channel,\r\n    };\r\n\r\n    await this.amqpChannel.assertQueue(this.name, queueOptions);\r\n    this.asserted = true;\r\n  }\r\n\r\n  /**\r\n   * Publish a message\r\n   */\r\n  public async publish(payload: TPayload, options?: PublishOptions): Promise<void> {\r\n    await this.assert();\r\n\r\n    // Validate with schema if provided\r\n    if (this.options.schema) {\r\n      const context = {\r\n        allValues: payload,\r\n        value: payload,\r\n      };\r\n      const result = await v.validate(this.options.schema, payload, { context });\r\n      if (!result.isValid) {\r\n        throw new Error(`Message validation failed: ${JSON.stringify(result.errors)}`);\r\n      }\r\n      payload = result.data as TPayload;\r\n    }\r\n\r\n    const messageId = randomUUID();\r\n    const timestamp = new Date();\r\n\r\n    const messageContent = JSON.stringify({\r\n      payload,\r\n      metadata: {\r\n        messageId,\r\n        timestamp: timestamp.toISOString(),\r\n        correlationId: options?.correlationId,\r\n        headers: options?.headers,\r\n      },\r\n    });\r\n\r\n    const publishOptions: any = {\r\n      persistent: options?.persistent ?? true,\r\n      messageId,\r\n      timestamp: timestamp.getTime(),\r\n      correlationId: options?.correlationId,\r\n      expiration: options?.expiration?.toString(),\r\n      priority: options?.priority,\r\n      headers: options?.headers,\r\n    };\r\n\r\n    // Handle delayed messages (requires rabbitmq-delayed-message-exchange plugin)\r\n    if (options?.delay) {\r\n      publishOptions.headers = {\r\n        ...publishOptions.headers,\r\n        \"x-delay\": options.delay,\r\n      };\r\n    }\r\n\r\n    this.amqpChannel.sendToQueue(this.name, Buffer.from(messageContent), publishOptions);\r\n  }\r\n\r\n  /**\r\n   * Publish multiple messages\r\n   */\r\n  public async publishBatch(messages: TPayload[], options?: PublishOptions): Promise<void> {\r\n    for (const payload of messages) {\r\n      await this.publish(payload, options);\r\n    }\r\n  }\r\n\r\n  /**\r\n   * Subscribe to messages\r\n   *\r\n   * Smart auto-ack behavior (when autoAck is not true):\r\n   * - If handler completes successfully without explicit ack/nack/reject → auto-ack\r\n   * - If handler throws an error → auto-nack (with retry if configured)\r\n   * - If handler explicitly calls ack/nack/reject → respects that call\r\n   */\r\n  public async subscribe(\r\n    handler: MessageHandler<TPayload>,\r\n    options?: SubscribeOptions,\r\n  ): Promise<Subscription> {\r\n    await this.assert();\r\n\r\n    // Use consumerId from options if provided, otherwise generate a random one\r\n    const subscriptionId = options?.consumerId ?? randomUUID();\r\n\r\n    // Set prefetch if specified\r\n    if (options?.prefetch) {\r\n      await this.amqpChannel.prefetch(options.prefetch);\r\n    }\r\n\r\n    // If autoAck is true, RabbitMQ handles ack immediately (fire-and-forget)\r\n    const isFireAndForget = options?.autoAck === true;\r\n\r\n    const consumerOptions = {\r\n      noAck: isFireAndForget,\r\n      exclusive: options?.exclusive ?? false,\r\n      consumerTag: options?.group ?? subscriptionId,\r\n    };\r\n\r\n    const { consumerTag } = await this.amqpChannel.consume(\r\n      this.name,\r\n      async (msg: any) => {\r\n        if (!msg) return;\r\n\r\n        // Track if acknowledgment was handled explicitly\r\n        let ackHandled = isFireAndForget;\r\n\r\n        try {\r\n          const content = JSON.parse(msg.content.toString());\r\n          let payload = content.payload as TPayload;\r\n\r\n          // Validate with schema if provided\r\n          if (this.options.schema) {\r\n            const context = {\r\n              allValues: payload,\r\n              value: payload,\r\n            };\r\n            const result = await v.validate(this.options.schema, payload, { context });\r\n            if (!result.isValid) {\r\n              // Reject invalid messages\r\n              this.amqpChannel.nack(msg, false, false);\r\n              return;\r\n            }\r\n            payload = result.data as TPayload;\r\n          }\r\n\r\n          const metadata: MessageMetadata = {\r\n            messageId: msg.properties.messageId || content.metadata?.messageId || randomUUID(),\r\n            timestamp: new Date(msg.properties.timestamp || content.metadata?.timestamp),\r\n            correlationId: msg.properties.correlationId || content.metadata?.correlationId,\r\n            replyTo: msg.properties.replyTo,\r\n            priority: msg.properties.priority,\r\n            headers: msg.properties.headers,\r\n            retryCount: msg.properties.headers?.[\"x-retry-count\"] || 0,\r\n            originalChannel: this.name,\r\n          };\r\n\r\n          const message: Message<TPayload> = {\r\n            metadata,\r\n            payload,\r\n            raw: msg,\r\n          };\r\n\r\n          const context: MessageContext = {\r\n            ack: async () => {\r\n              if (!ackHandled) {\r\n                ackHandled = true;\r\n                this.amqpChannel.ack(msg);\r\n              }\r\n            },\r\n            nack: async (requeue = true) => {\r\n              if (!ackHandled) {\r\n                ackHandled = true;\r\n                this.amqpChannel.nack(msg, false, requeue);\r\n              }\r\n            },\r\n            reject: async () => {\r\n              if (!ackHandled) {\r\n                ackHandled = true;\r\n                this.amqpChannel.reject(msg, false);\r\n              }\r\n            },\r\n            reply: async <T>(replyPayload: T) => {\r\n              if (msg.properties.replyTo) {\r\n                const replyContent = JSON.stringify({\r\n                  payload: replyPayload,\r\n                  metadata: {\r\n                    messageId: randomUUID(),\r\n                    timestamp: new Date().toISOString(),\r\n                    correlationId: msg.properties.correlationId,\r\n                  },\r\n                });\r\n\r\n                this.amqpChannel.sendToQueue(msg.properties.replyTo, Buffer.from(replyContent), {\r\n                  correlationId: msg.properties.correlationId,\r\n                });\r\n              }\r\n            },\r\n            retry: async (delay?: number) => {\r\n              if (ackHandled) return;\r\n              ackHandled = true;\r\n\r\n              const retryCount = (metadata.retryCount || 0) + 1;\r\n              const maxRetries = options?.retry?.maxRetries ?? 3;\r\n\r\n              if (retryCount > maxRetries) {\r\n                // Send to dead-letter if configured\r\n                if (options?.deadLetter) {\r\n                  await this.sendToDeadLetter(message, options.deadLetter.channel);\r\n                }\r\n                this.amqpChannel.ack(msg);\r\n                return;\r\n              }\r\n\r\n              // Republish with retry count\r\n              const headers = {\r\n                ...msg.properties.headers,\r\n                \"x-retry-count\": retryCount,\r\n              };\r\n\r\n              if (delay) {\r\n                headers[\"x-delay\"] = delay;\r\n              }\r\n\r\n              this.amqpChannel.sendToQueue(this.name, msg.content, { ...msg.properties, headers });\r\n\r\n              this.amqpChannel.ack(msg);\r\n            },\r\n          };\r\n\r\n          // Execute handler\r\n          await handler(message, context);\r\n\r\n          // Smart auto-ack: if handler succeeded and didn't explicitly handle ack\r\n          if (!ackHandled) {\r\n            this.amqpChannel.ack(msg);\r\n          }\r\n        } catch (error) {\r\n          // Smart auto-nack: if handler threw and didn't explicitly handle ack\r\n          if (ackHandled) return;\r\n\r\n          // Handle errors - nack and potentially retry\r\n          if (options?.retry) {\r\n            const retryCount = msg.properties.headers?.[\"x-retry-count\"] || 0;\r\n            if (retryCount < options.retry.maxRetries) {\r\n              // Requeue for retry\r\n              this.amqpChannel.nack(msg, false, true);\r\n            } else if (options.deadLetter) {\r\n              // Send to dead-letter\r\n              this.amqpChannel.nack(msg, false, false);\r\n            } else {\r\n              this.amqpChannel.reject(msg, false);\r\n            }\r\n          } else {\r\n            // No retry configured - reject without requeue\r\n            this.amqpChannel.nack(msg, false, false);\r\n          }\r\n        }\r\n      },\r\n      consumerOptions,\r\n    );\r\n\r\n    const subscription = new RabbitMQSubscription(\r\n      subscriptionId,\r\n      this.name,\r\n      consumerTag,\r\n      this.amqpChannel,\r\n    );\r\n\r\n    this.subscriptions.set(subscriptionId, subscription);\r\n\r\n    return subscription;\r\n  }\r\n\r\n  /**\r\n   * Unsubscribe by consumer ID\r\n   */\r\n  public async unsubscribeById(consumerId: string): Promise<void> {\r\n    const subscription = this.subscriptions.get(consumerId);\r\n    if (subscription) {\r\n      await subscription.unsubscribe();\r\n      this.subscriptions.delete(consumerId);\r\n    }\r\n  }\r\n\r\n  /**\r\n   * Stop consuming messages on this channel.\r\n   * Cancels all active subscriptions gracefully.\r\n   */\r\n  public async stopConsuming(): Promise<void> {\r\n    const cancellations = Array.from(this.subscriptions.values()).map(sub =>\r\n      sub.unsubscribe(),\r\n    );\r\n    await Promise.all(cancellations);\r\n  }\r\n\r\n  /**\r\n   * Send message to dead-letter queue\r\n   */\r\n  private async sendToDeadLetter(\r\n    message: Message<TPayload>,\r\n    deadLetterChannel: string,\r\n  ): Promise<void> {\r\n    const content = JSON.stringify({\r\n      payload: message.payload,\r\n      metadata: {\r\n        ...message.metadata,\r\n        originalChannel: this.name,\r\n      },\r\n    });\r\n\r\n    this.amqpChannel.sendToQueue(deadLetterChannel, Buffer.from(content), { persistent: true });\r\n  }\r\n\r\n  /**\r\n   * Request-response pattern\r\n   */\r\n  public async request<TResponse = unknown>(\r\n    payload: TPayload,\r\n    options?: RequestOptions,\r\n  ): Promise<TResponse> {\r\n    await this.assert();\r\n\r\n    const correlationId = randomUUID();\r\n    const timeout = options?.timeout ?? 30000;\r\n\r\n    // Create exclusive reply queue\r\n    const { queue: replyQueue } = await this.amqpChannel.assertQueue(\"\", {\r\n      exclusive: true,\r\n      autoDelete: true,\r\n    });\r\n\r\n    return new Promise<TResponse>((resolve, reject) => {\r\n      const timeoutId = setTimeout(() => {\r\n        reject(new Error(`Request timeout after ${timeout}ms`));\r\n      }, timeout);\r\n\r\n      // Consume reply\r\n      this.amqpChannel.consume(\r\n        replyQueue,\r\n        (msg: any) => {\r\n          if (msg?.properties.correlationId === correlationId) {\r\n            clearTimeout(timeoutId);\r\n            const content = JSON.parse(msg.content.toString());\r\n            resolve(content.payload as TResponse);\r\n          }\r\n        },\r\n        { noAck: true },\r\n      );\r\n\r\n      // Send request\r\n      const messageContent = JSON.stringify({\r\n        payload,\r\n        metadata: {\r\n          messageId: randomUUID(),\r\n          timestamp: new Date().toISOString(),\r\n          correlationId,\r\n        },\r\n      });\r\n\r\n      this.amqpChannel.sendToQueue(this.name, Buffer.from(messageContent), {\r\n        correlationId,\r\n        replyTo: replyQueue,\r\n        expiration: timeout.toString(),\r\n        ...options,\r\n      });\r\n    });\r\n  }\r\n\r\n  /**\r\n   * Register response handler for RPC\r\n   */\r\n  public async respond<TResponse = unknown>(\r\n    handler: ResponseHandler<TPayload, TResponse>,\r\n  ): Promise<Subscription> {\r\n    return this.subscribe(async (message, ctx) => {\r\n      const response = await handler(message, ctx);\r\n      await ctx.reply(response);\r\n      await ctx.ack();\r\n    });\r\n  }\r\n\r\n  /**\r\n   * Get queue statistics\r\n   */\r\n  public async stats(): Promise<ChannelStats> {\r\n    await this.assert();\r\n\r\n    const queueInfo = await this.amqpChannel.checkQueue(this.name);\r\n\r\n    return {\r\n      name: this.name,\r\n      messageCount: queueInfo.messageCount,\r\n      consumerCount: queueInfo.consumerCount,\r\n    };\r\n  }\r\n\r\n  /**\r\n   * Purge all messages\r\n   */\r\n  public async purge(): Promise<number> {\r\n    await this.assert();\r\n\r\n    const result = await this.amqpChannel.purgeQueue(this.name);\r\n    return result.messageCount;\r\n  }\r\n\r\n  /**\r\n   * Check if queue exists\r\n   */\r\n  public async exists(): Promise<boolean> {\r\n    try {\r\n      await this.amqpChannel.checkQueue(this.name);\r\n      return true;\r\n    } catch {\r\n      return false;\r\n    }\r\n  }\r\n\r\n  /**\r\n   * Delete the queue\r\n   */\r\n  public async delete(): Promise<void> {\r\n    // Cancel all subscriptions\r\n    for (const subscription of this.subscriptions.values()) {\r\n      await subscription.unsubscribe();\r\n    }\r\n    this.subscriptions.clear();\r\n\r\n    try {\r\n      await this.amqpChannel.deleteQueue(this.name);\r\n    } catch {\r\n      // Ignore if queue doesn't exist\r\n    }\r\n\r\n    this.asserted = false;\r\n  }\r\n}\r\n\r\n/**\r\n * RabbitMQ Subscription Implementation\r\n */\r\nclass RabbitMQSubscription implements Subscription {\r\n  public readonly id: string;\r\n  public readonly channel: string;\r\n  public readonly consumerTag: string;\r\n\r\n  private readonly amqpChannel: any;\r\n  private _isActive = true;\r\n\r\n  public constructor(id: string, channel: string, consumerTag: string, amqpChannel: any) {\r\n    this.id = id;\r\n    this.channel = channel;\r\n    this.consumerTag = consumerTag;\r\n    this.amqpChannel = amqpChannel;\r\n  }\r\n\r\n  public async unsubscribe(): Promise<void> {\r\n    if (!this._isActive) return;\r\n\r\n    await this.amqpChannel.cancel(this.consumerTag);\r\n    this._isActive = false;\r\n  }\r\n\r\n  public async pause(): Promise<void> {\r\n    // RabbitMQ doesn't have native pause, cancel consumer\r\n    await this.amqpChannel.cancel(this.consumerTag);\r\n  }\r\n\r\n  public async resume(): Promise<void> {\r\n    // Would need to re-subscribe - not directly supported\r\n    throw new Error(\"Resume is not supported for RabbitMQ. Please create a new subscription.\");\r\n  }\r\n\r\n  public isActive(): boolean {\r\n    return this._isActive;\r\n  }\r\n}\r\n","import { EventEmitter } from \"node:events\";\r\nimport type { BrokerDriverContract, ChannelContract } from \"../../contracts\";\r\nimport { EventMessage } from \"../../message-managers/event-message\";\r\nimport { EventConsumerClass } from \"../../message-managers/types\";\r\nimport type {\r\n  BrokerDriverType,\r\n  BrokerEvent,\r\n  BrokerEventListener,\r\n  ChannelOptions,\r\n  HealthCheckResult,\r\n  RabbitMQConnectionOptions,\r\n} from \"../../types\";\r\nimport { prepareConsumerSubscription } from \"./../../message-managers/prepare-consumer-subscription\";\r\nimport { RabbitMQChannel } from \"./rabbitmq-channel\";\r\n\r\n// ============================================================\r\n// Lazy-loaded amqplib Module\r\n// ============================================================\r\n\r\n/**\r\n * Cached amqplib module (loaded once, reused)\r\n */\r\nlet amqplibModule: typeof import(\"amqplib\");\r\n\r\n/**\r\n * Module availability flag\r\n */\r\nlet isModuleExists: boolean | null = null;\r\n\r\n/**\r\n * Installation instructions for amqplib\r\n */\r\nconst AMQPLIB_INSTALL_INSTRUCTIONS = `\r\nRabbitMQ driver requires the amqplib package.\r\nInstall it with:\r\n\r\n  npx warlock add herald --driver=rabbitmq\r\n\r\nOr manually:\r\n\r\n  npm install amqplib\r\n  pnpm add amqplib\r\n  yarn add amqplib\r\n`.trim();\r\n\r\n/**\r\n * Load amqplib module\r\n */\r\nasync function loadAmqplibModule() {\r\n  try {\r\n    amqplibModule = await import(\"amqplib\");\r\n    isModuleExists = true;\r\n  } catch {\r\n    isModuleExists = false;\r\n  }\r\n}\r\n\r\n// Kick off eager loading immediately\r\nloadAmqplibModule();\r\n\r\n// ============================================================\r\n// RabbitMQ Driver\r\n// ============================================================\r\n\r\n/**\r\n * RabbitMQ Driver\r\n *\r\n * Implementation of BrokerDriverContract for RabbitMQ/AMQP.\r\n *\r\n * **Important:** This driver requires the `amqplib` package to be installed.\r\n * Install it with: `npx warlock add herald --driver=rabbitmq` or `npm install amqplib`\r\n *\r\n * @example\r\n * ```typescript\r\n * const driver = new RabbitMQDriver({\r\n *   driver: \"rabbitmq\",\r\n *   host: \"localhost\",\r\n *   port: 5672,\r\n *   username: \"guest\",\r\n *   password: \"guest\",\r\n * });\r\n *\r\n * await driver.connect();\r\n * const channel = driver.channel(\"user.created\");\r\n * ```\r\n */\r\nexport class RabbitMQDriver implements BrokerDriverContract {\r\n  public readonly name = \"rabbitmq\" as const;\r\n\r\n  public readonly consumers: EventConsumerClass[] = [];\r\n\r\n  private readonly options: RabbitMQConnectionOptions;\r\n  private readonly events = new EventEmitter();\r\n  private readonly channels = new Map<string, ChannelContract<any>>();\r\n\r\n  private connection: any = null;\r\n  private amqpChannel: any = null;\r\n  private _isConnected = false;\r\n\r\n  /**\r\n   * Create a new RabbitMQ driver\r\n   *\r\n   * @param options - RabbitMQ connection options\r\n   */\r\n  public constructor(options: RabbitMQConnectionOptions) {\r\n    this.options = options;\r\n  }\r\n\r\n  /**\r\n   * Whether connected to RabbitMQ\r\n   */\r\n  public get isConnected(): boolean {\r\n    return this._isConnected;\r\n  }\r\n\r\n  /**\r\n   * Subscribe the given consumer class to the driver\r\n   *\r\n   * @param consumer - Consumer class to subscribe\r\n   *\r\n   * @example\r\n   * ```typescript\r\n   * driver.subscribe(UserUpdatedConsumer);\r\n   * ```\r\n   */\r\n  public subscribe(Consumer: EventConsumerClass) {\r\n    if (this.isConnected) {\r\n      this.channel(Consumer.eventName).subscribe(\r\n        prepareConsumerSubscription(Consumer, (error, eventName) => {\r\n          this.events.emit(\"error\", error, eventName);\r\n        }),\r\n        {\r\n          consumerId: Consumer.consumerId,\r\n        },\r\n      );\r\n    } else {\r\n      this.consumers.push(Consumer);\r\n    }\r\n\r\n    return () => {\r\n      this.unsubscribe(Consumer);\r\n    };\r\n  }\r\n\r\n  /**\r\n   * Unsubscribe the given consumer\r\n   */\r\n  public unsubscribe(Consumer: EventConsumerClass): void {\r\n    if (this.isConnected) {\r\n      this.channel(Consumer.eventName).unsubscribeById(Consumer.consumerId);\r\n    }\r\n    const index = this.consumers.indexOf(Consumer);\r\n    if (index > -1) {\r\n      this.consumers.splice(index, 1);\r\n    }\r\n  }\r\n\r\n  /**\r\n   * Publish the given event message.\r\n   * Auto-creates the channel if it hasn't been accessed before.\r\n   */\r\n  public publish<TPayload = Record<string, any>>(event: EventMessage<TPayload>): void {\r\n    this.channel(event.eventName).publish(event.serialize());\r\n  }\r\n\r\n  /**\r\n   * Connect to RabbitMQ\r\n   */\r\n  public async connect(): Promise<void> {\r\n    // Check if amqplib is installed\r\n    if (isModuleExists === false) {\r\n      throw new Error(`amqplib is not installed.\\n\\n${AMQPLIB_INSTALL_INSTRUCTIONS}`);\r\n    }\r\n\r\n    // Wait for module to load if still loading\r\n    if (isModuleExists === null) {\r\n      await loadAmqplibModule();\r\n      if (!isModuleExists) {\r\n        throw new Error(`amqplib is not installed.\\n\\n${AMQPLIB_INSTALL_INSTRUCTIONS}`);\r\n      }\r\n    }\r\n\r\n    try {\r\n      // Build connection URL\r\n      const url = this.buildConnectionUrl();\r\n\r\n      // Build connection options merging our options with native client options\r\n      const connectOptions = {\r\n        heartbeat: this.options.heartbeat ?? 60,\r\n        timeout: this.options.connectionTimeout,\r\n        // Merge native amqplib client options\r\n        ...this.options.clientOptions,\r\n      };\r\n\r\n      // Connect using cached module\r\n      this.connection = await amqplibModule.connect(url, connectOptions);\r\n\r\n      // Create channel\r\n      this.amqpChannel = await this.connection.createChannel();\r\n\r\n      // Set prefetch if specified\r\n      if (this.options.prefetch) {\r\n        await this.amqpChannel.prefetch(this.options.prefetch);\r\n      }\r\n\r\n      this._isConnected = true;\r\n      this.events.emit(\"connected\");\r\n\r\n      for (const consumer of this.consumers) {\r\n        this.subscribe(consumer);\r\n      }\r\n\r\n      this.consumers.length = 0;\r\n\r\n      // Handle connection close\r\n      this.connection.on(\"close\", () => {\r\n        this._isConnected = false;\r\n        this.events.emit(\"disconnected\");\r\n\r\n        if (this.options.reconnect !== false) {\r\n          this.handleReconnect();\r\n        }\r\n      });\r\n\r\n      // Handle errors\r\n      this.connection.on(\"error\", (error: Error) => {\r\n        this.events.emit(\"error\", error);\r\n      });\r\n    } catch (error) {\r\n      this._isConnected = false;\r\n      throw new Error(\r\n        `Failed to connect to RabbitMQ: ${error instanceof Error ? error.message : String(error)}`,\r\n      );\r\n    }\r\n  }\r\n\r\n  /**\r\n   * Build connection URL from options\r\n   */\r\n  private buildConnectionUrl(): string {\r\n    if (this.options.uri) {\r\n      return this.options.uri;\r\n    }\r\n\r\n    const protocol = \"amqp\";\r\n    const host = this.options.host ?? \"localhost\";\r\n    const port = this.options.port ?? 5672;\r\n    const vhost = this.options.vhost ?? \"/\";\r\n    const username = this.options.username ?? \"guest\";\r\n    const password = this.options.password ?? \"guest\";\r\n\r\n    const encodedVhost = encodeURIComponent(vhost);\r\n\r\n    return `${protocol}://${username}:${password}@${host}:${port}/${encodedVhost}`;\r\n  }\r\n\r\n  /**\r\n   * Handle reconnection\r\n   */\r\n  private async handleReconnect(): Promise<void> {\r\n    const delay = this.options.reconnectDelay ?? 5000;\r\n    let attempt = 0;\r\n\r\n    const tryReconnect = async () => {\r\n      attempt++;\r\n      this.events.emit(\"reconnecting\", attempt);\r\n\r\n      try {\r\n        await this.connect();\r\n      } catch {\r\n        setTimeout(tryReconnect, delay);\r\n      }\r\n    };\r\n\r\n    setTimeout(tryReconnect, delay);\r\n  }\r\n\r\n  /**\r\n   * Disconnect from RabbitMQ\r\n   */\r\n  public async disconnect(): Promise<void> {\r\n    if (this.amqpChannel) {\r\n      try {\r\n        await this.amqpChannel.close();\r\n      } catch {\r\n        // Ignore close errors\r\n      }\r\n      this.amqpChannel = null;\r\n    }\r\n\r\n    if (this.connection) {\r\n      try {\r\n        await this.connection.close();\r\n      } catch {\r\n        // Ignore close errors\r\n      }\r\n      this.connection = null;\r\n    }\r\n\r\n    this._isConnected = false;\r\n    this.events.emit(\"disconnected\");\r\n  }\r\n\r\n  /**\r\n   * Register event listener\r\n   */\r\n  public on(event: BrokerEvent, listener: BrokerEventListener): void {\r\n    this.events.on(event, listener as any);\r\n  }\r\n\r\n  /**\r\n   * Remove event listener\r\n   */\r\n  public off(event: BrokerEvent, listener: BrokerEventListener): void {\r\n    this.events.off(event, listener as any);\r\n  }\r\n\r\n  /**\r\n   * Get or create a channel\r\n   */\r\n  public channel<TPayload = unknown>(\r\n    name: string,\r\n    options?: ChannelOptions<TPayload>,\r\n  ): ChannelContract<TPayload> {\r\n    // Check cache\r\n    const existing = this.channels.get(name);\r\n    if (existing) {\r\n      return existing as ChannelContract<TPayload>;\r\n    }\r\n\r\n    // Create new channel\r\n    const channel = new RabbitMQChannel<TPayload>(name, this.amqpChannel, options);\r\n\r\n    this.channels.set(name, channel);\r\n    return channel;\r\n  }\r\n\r\n  /**\r\n   * Start consuming messages\r\n   */\r\n  public async startConsuming(): Promise<void> {\r\n    // Channels start consuming when subscribe() is called\r\n    // This method is for batch start if needed\r\n  }\r\n\r\n  /**\r\n   * Stop consuming messages from all subscribed channels.\r\n   * Gracefully cancels all active consumers.\r\n   */\r\n  public async stopConsuming(): Promise<void> {\r\n    const stops = Array.from(this.channels.values()).map(channel =>\r\n      (channel as RabbitMQChannel<any>).stopConsuming(),\r\n    );\r\n    await Promise.all(stops);\r\n  }\r\n\r\n  /**\r\n   * Health check\r\n   */\r\n  public async healthCheck(): Promise<HealthCheckResult> {\r\n    if (!this._isConnected || !this.connection) {\r\n      return {\r\n        healthy: false,\r\n        error: \"Not connected to RabbitMQ\",\r\n      };\r\n    }\r\n\r\n    const start = Date.now();\r\n\r\n    try {\r\n      // Simple check - verify channel is open\r\n      await this.amqpChannel.checkQueue(\"amq.rabbitmq.reply-to\").catch(() => {\r\n        // Queue might not exist, but if we get here, connection is alive\r\n      });\r\n\r\n      return {\r\n        healthy: true,\r\n        latency: Date.now() - start,\r\n      };\r\n    } catch (error) {\r\n      return {\r\n        healthy: false,\r\n        error: error instanceof Error ? error.message : String(error),\r\n        latency: Date.now() - start,\r\n      };\r\n    }\r\n  }\r\n\r\n  /**\r\n   * Get all channel names\r\n   */\r\n  public getChannelNames(): string[] {\r\n    return Array.from(this.channels.keys());\r\n  }\r\n\r\n  /**\r\n   * Close a specific channel\r\n   */\r\n  public async closeChannel(name: string): Promise<void> {\r\n    const channel = this.channels.get(name);\r\n    if (channel) {\r\n      await channel.delete();\r\n      this.channels.delete(name);\r\n    }\r\n  }\r\n\r\n  /**\r\n   * Get the raw AMQP channel (for advanced use)\r\n   */\r\n  public getRawChannel(): any {\r\n    return this.amqpChannel;\r\n  }\r\n\r\n  /**\r\n   * Get the raw connection (for advanced use)\r\n   */\r\n  public getRawConnection(): any {\r\n    return this.connection;\r\n  }\r\n}\r\n","import { Broker, brokerRegistry } from \"../communicators\";\r\nimport type { BrokerDriverContract, ChannelContract } from \"../contracts\";\r\nimport { EventConsumerClass, EventMessage } from \"../message-managers\";\r\nimport type { ChannelOptions, ConnectionOptions, RabbitMQConnectionOptions } from \"../types\";\r\n\r\n/**\r\n * Connect to a message broker and register it.\r\n *\r\n * This is a high-level utility function that simplifies connection setup\r\n * for most projects. It handles driver instantiation, connection,\r\n * broker creation, and automatic registration.\r\n *\r\n * **Supported Drivers:**\r\n * - `rabbitmq` (default) - RabbitMQ/AMQP driver\r\n * - `kafka` - Apache Kafka driver (coming soon)\r\n *\r\n * @param options - Connection configuration options\r\n * @returns A connected and registered Broker instance\r\n * @throws {Error} If connection fails or driver is not implemented\r\n *\r\n * @example\r\n * ```typescript\r\n * // RabbitMQ connection\r\n * const broker = await connectToBroker({\r\n *   driver: \"rabbitmq\",\r\n *   host: \"localhost\",\r\n *   port: 5672,\r\n *   username: \"guest\",\r\n *   password: \"guest\",\r\n * });\r\n *\r\n * // Use the broker\r\n * await broker.channel(\"user.created\").publish({ userId: 1 });\r\n * ```\r\n *\r\n * @example\r\n * ```typescript\r\n * // Multiple brokers\r\n * await connectToBroker({\r\n *   driver: \"rabbitmq\",\r\n *   name: \"notifications\",\r\n *   isDefault: true,\r\n *   host: process.env.RABBITMQ_HOST,\r\n * });\r\n *\r\n * await connectToBroker({\r\n *   driver: \"rabbitmq\",\r\n *   name: \"analytics\",\r\n *   host: process.env.ANALYTICS_RABBITMQ_HOST,\r\n * });\r\n *\r\n * // Use default broker\r\n * herald().channel(\"notifications\").publish({ ... });\r\n *\r\n * // Use specific broker\r\n * herald(\"analytics\").channel(\"events\").publish({ ... });\r\n * ```\r\n */\r\nexport async function connectToBroker(options: ConnectionOptions): Promise<Broker> {\r\n  // Default values\r\n  const driverType = options.driver ?? \"rabbitmq\";\r\n  const brokerName = options.name ?? \"default\";\r\n  const isDefault = options.isDefault ?? true;\r\n\r\n  // Create driver based on type\r\n  let driver: BrokerDriverContract;\r\n\r\n  switch (driverType) {\r\n    case \"rabbitmq\": {\r\n      const rabbitOptions = options as RabbitMQConnectionOptions;\r\n      // Dynamic import to avoid requiring amqplib if not used\r\n      const { RabbitMQDriver } = await import(\"../drivers/rabbitmq/rabbitmq-driver\");\r\n      driver = new RabbitMQDriver(rabbitOptions);\r\n      break;\r\n    }\r\n\r\n    case \"kafka\": {\r\n      // const kafkaOptions = options as KafkaConnectionOptions;\r\n      // Dynamic import to avoid requiring kafkajs if not used\r\n      throw new Error(\r\n        \"Kafka driver is not yet implemented. Coming soon! For now, please use RabbitMQ.\",\r\n      );\r\n    }\r\n\r\n    default:\r\n      throw new Error(`Unknown driver: \"${driverType}\". Supported drivers: rabbitmq, kafka`);\r\n  }\r\n\r\n  // Create broker\r\n  const broker = brokerRegistry.register({\r\n    name: brokerName,\r\n    driver,\r\n    isDefault,\r\n  });\r\n\r\n  // Connect to the message broker\r\n  try {\r\n    await driver.connect();\r\n  } catch (error) {\r\n    throw new Error(\r\n      `Failed to connect to ${driverType}: ${error instanceof Error ? error.message : String(error)}`,\r\n    );\r\n  }\r\n\r\n  return broker;\r\n}\r\n\r\n/**\r\n * Get a broker by name or the default one.\r\n *\r\n * This is the main entry point for using brokers in your application.\r\n * Named after the package — `herald()` carries your messages!\r\n *\r\n * @param name - Optional broker name (uses default if not provided)\r\n * @returns Broker instance\r\n * @throws MissingBrokerError if broker not found\r\n *\r\n * @example\r\n * // Get default broker\r\n * const channel = herald().channel(\"user.created\");\r\n * await channel.publish({ userId: 1 });\r\n *\r\n * // Get specific broker\r\n * const analyticsChannel = herald(\"analytics\").channel(\"events\");\r\n * await analyticsChannel.publish({ event: \"page_view\" });\r\n *\r\n * // Subscribe to messages\r\n * herald()\r\n *   .channel<UserPayload>(\"user.created\")\r\n *   .subscribe(async (message, ctx) => {\r\n *     console.log(\"User created:\", message.payload);\r\n *     await ctx.ack();\r\n *   });\r\n * ```\r\n */\r\nexport function herald(name?: string): Broker {\r\n  return brokerRegistry.get(name);\r\n}\r\n\r\n/**\r\n * Get channel instance for the given name from default broker.\r\n *\r\n * Shorthand for `herald().channel(name, options)`.\r\n *\r\n * @param name - Channel name\r\n * @param options - Optional channel options\r\n * @returns Channel instance\r\n * @throws MissingBrokerError if broker not found\r\n *\r\n * @example\r\n * ```typescript\r\n * const channel = heraldChannel(\"user.created\");\r\n * await channel.publish({ userId: 1 });\r\n * ```\r\n */\r\nexport function heraldChannel<TPayload = unknown>(\r\n  name: string,\r\n  options?: ChannelOptions<TPayload>,\r\n): ChannelContract<TPayload> {\r\n  return herald().channel<TPayload>(name, options);\r\n}\r\n\r\n/**\r\n * Publish an EventMessage to the default broker.\r\n *\r\n * @param event - Event message to publish\r\n * @returns Promise that resolves when the event is published\r\n * @throws Error if the broker is not connected\r\n *\r\n * @example\r\n * ```typescript\r\n * await publishEvent(new UserUpdatedEvent({ id: 1, name: \"John Doe\" }));\r\n * ```\r\n */\r\nexport async function publishEvent<TPayload = Record<string, any>>(event: EventMessage<TPayload>) {\r\n  return herald().publish(event);\r\n}\r\n\r\n/**\r\n * Subscribe an EventConsumer class to the default broker.\r\n *\r\n * @param Consumer - Event consumer class\r\n * @returns Unsubscribe function\r\n * @throws MissingBrokerError if broker not found\r\n *\r\n * @example\r\n * ```typescript\r\n * await subscribeConsumer(UserUpdatedConsumer);\r\n * ```\r\n */\r\nexport async function subscribeConsumer<TPayload = Record<string, any>>(\r\n  Consumer: EventConsumerClass<TPayload>,\r\n) {\r\n  return herald().subscribe(Consumer);\r\n}\r\n","import { brokerRegistry } from \"../communicators\";\nimport { type EventConsumerClass } from \"../message-managers/types\";\n\nexport type ConsumableOptions = {\n  broker?: string;\n};\n\nexport const pendingSubscribers = new Set<{\n  Consumer: EventConsumerClass;\n  options?: ConsumableOptions;\n}>();\n\n/**\n * Register the consumer to the broker\n */\nexport function Consumable(options?: ConsumableOptions) {\n  return function (target: EventConsumerClass) {\n    const brokerName = options?.broker;\n\n    try {\n      const currentBroker = brokerRegistry.get(brokerName);\n\n      // if broker is connected, subscribe the consumer\n      if (currentBroker?.isConnected) {\n        currentBroker.subscribe(target);\n      } else {\n        pendingSubscribers.add({ Consumer: target, options });\n      }\n    } catch {\n      // mostly it will be an error that broker is not registered yet\n      // then add it to the pending subscribers\n      pendingSubscribers.add({ Consumer: target, options });\n    }\n  };\n}\n\n// Register pending consumers on broker's connection is done\nbrokerRegistry.on(\"connected\", (broker) => {\n  for (const { Consumer, options } of pendingSubscribers) {\n    if (options?.broker && broker.name !== options.broker) {\n      continue;\n    }\n\n    broker.subscribe(Consumer);\n  }\n});\n","/**\n * This class is used to be part of the Herald Event Consumer Manager.\n * It should be used to consume events from Either RabbitMQ or Kafka through Herald\n *\n * It's highly recommended using it instead of declaring manual channel namd and subscribing to event\n */\nimport { v, ValidationResult, type ObjectValidator } from \"@warlock.js/seal\";\nimport { randomUUID } from \"crypto\";\nimport { Consumable } from \"../decorators\";\nimport { ConsumedEventMessage, EventConsumerClass } from \"./types\";\n\nexport abstract class EventConsumer<Payload = Record<string, any>> {\n  /**\n   * Event name\n   */\n  public static eventName: string;\n\n  private static _consumerId?: string;\n\n  public static get consumerId(): string {\n    if (!this._consumerId) {\n      this._consumerId = randomUUID();\n    }\n    return this._consumerId;\n  }\n\n  public get eventName() {\n    return (this.constructor as typeof EventConsumer).eventName;\n  }\n\n  /**\n   * Min version accepted to be consumed by this class\n   */\n  public static minVersion?: number;\n\n  /**\n   * Max version accepted to be consumed by this class\n   */\n  public static maxVersion?: number;\n\n  /**\n   * Payload validation to auto reject the received event before accessing it in the handle method\n   */\n  public schema?: ObjectValidator;\n\n  /**\n   * The method that will be called when the event is received\n   */\n  public abstract handle(payload: Payload, event: ConsumedEventMessage): Promise<void>;\n\n  /**\n   * Determine whether this is accepted version to be used by this consumer\n   */\n  public static isAcceptedVersion(version: number): boolean {\n    if (this.minVersion && version < this.minVersion) return false;\n    if (this.maxVersion && version > this.maxVersion) return false;\n\n    return true;\n  }\n\n  /**\n   * Validate the given data\n   */\n  public async validate(data: Payload): Promise<ValidationResult | void> {\n    if (!this.schema) return;\n\n    return await v.validate(this.schema, data);\n  }\n}\n\n/**\n * Define Consumer options\n */\ntype ConsumerOptions<Payload> = {\n  /**\n   * Payload validation to auto reject the received event before accessing it in the handle method\n   */\n  schema?: ObjectValidator;\n  /**\n   * Handle data\n   */\n  handle: (payload: Payload, event: ConsumedEventMessage) => Promise<void>;\n  /**\n   * Validate the payload before executing `handle`\n   */\n  validate?: (payload: Payload) => Promise<ValidationResult | boolean>;\n};\n\n/**\n * A shorthand to define an event consumer without declaring an entire class\n */\nexport function defineConsumer<Payload = Record<string, any>>(\n  eventName: string,\n  options: ConsumerOptions<Payload>,\n): EventConsumerClass {\n  const Class = class AnnouncedConsumer extends EventConsumer<Payload> {\n    public static eventName = eventName;\n    public schema = options.schema;\n\n    public async handle(payload: Payload, event: ConsumedEventMessage) {\n      if (options.validate) {\n        const result = await options.validate(payload);\n        if (!result || !(result as ValidationResult).isValid) return;\n      }\n\n      return options.handle(payload, event);\n    }\n  };\n\n  Consumable()(Class as EventConsumerClass);\n\n  return Class as EventConsumerClass;\n}\n","/**\n * This class is used to be part of the Herald Event Message Manager.\n * It should be used to trigger events to Either RabbitMQ or Kafka through Herald\n *\n * It's highly recommended using it instead of declaring manual channel namd and publishing data\n */\nimport { GenericObject } from \"@mongez/reinforcements\";\nimport { type ObjectValidator } from \"@warlock.js/seal\";\nimport { randomUUID } from \"crypto\";\n\nexport abstract class EventMessage<TPayload = Record<string, any>> {\n  /**\n   * Event Name\n   */\n  public abstract eventName: string;\n\n  /**\n   * Event version\n   */\n  public version?: number;\n\n  /**\n   * Additional metadata (if any)\n   */\n  public metadata?: Record<string, any>;\n\n  /**\n   * Event Message id\n   */\n  public messageId?: string;\n\n  /**\n   * Schema of payload that will be used to determine whether this event should be published\n   */\n  public schema?: ObjectValidator;\n\n  /**\n   * Data that will be sent with the event (Payload)\n   */\n  public toJSON(): TPayload {\n    if (!this.data) {\n      throw new Error(`no Data is defined for Event: ${this.eventName}`);\n    }\n\n    return this.data as TPayload;\n  }\n\n  public constructor(protected data?: TPayload) {}\n\n  /**\n   * Serialize the event to be ready for publishing.\n   * Delegates payload resolution to toJSON() — override toJSON() to customize.\n   *\n   * @throws Error if toJSON() throws (e.g. no data provided)\n   */\n  public serialize() {\n    const payload = this.toJSON();\n\n    return {\n      payload,\n      metadata: this.metadata,\n      messageId: this.messageId ?? randomUUID(),\n      eventName: this.eventName,\n      version: this.version,\n      occurredAt: new Date(),\n      __through: \"EventMessage\",\n    };\n  }\n}\n\ntype EventOptions<T> = {\n  /**\n   * Shapen the data that will be used\n   */\n  toJSON?: (data: T) => GenericObject;\n  /**\n   * Validation schema\n   */\n  schema?: ObjectValidator;\n};\n\n/**\n * Represents an EventMessage class constructor.\n *\n * @template TIncoming - The type of data accepted by the constructor\n * @template TOutgoing - The type of data returned by toJSON() (defaults to TIncoming)\n */\ntype EventMessageClass<TIncoming = Record<string, any>, TOutgoing = TIncoming> = new (\n  data?: TIncoming,\n) => EventMessage<TOutgoing>;\n\n/**\n * A shorthand to define an event without declaring an entire class.\n *\n * This factory function creates an EventMessage subclass that transforms\n * input data (IncomingData) into a different output format (OutgoingData).\n *\n * @template IncomingData - The type of data passed to the constructor\n * @template OutgoingData - The type of data returned by toJSON()\n *\n * @example\n * ```typescript\n * const UserCreatedEvent = defineEvent<User, { id: number; name: string }>(\n *   \"user.created\",\n *   { toJSON: (user) => user.only([\"id\", \"name\"]) }\n * );\n *\n * publishEvent(new UserCreatedEvent(user));\n * ```\n */\nexport function defineEvent<IncomingData = unknown, OutgoingData = unknown>(\n  eventName: string,\n  options: EventOptions<IncomingData> = {},\n): EventMessageClass<IncomingData, OutgoingData> {\n  // We need to use `any` here to bridge the IncomingData -> OutgoingData transformation\n  // The class accepts IncomingData in constructor but outputs OutgoingData via toJSON()\n  return class AnnouncedEvent extends EventMessage<OutgoingData> {\n    public eventName = eventName;\n    public schema = options.schema;\n\n    public constructor(data?: IncomingData) {\n      super(data as any);\n    }\n\n    public toJSON(): OutgoingData {\n      if (!options.toJSON) return this.data as OutgoingData;\n\n      return options.toJSON(this.data as IncomingData) as OutgoingData;\n    }\n  };\n}\n","import { herald } from \"./utils/connect-to-broker\";\n\n/**\n * Minimal mirror of `@warlock.js/core`'s `UseCaseBroadcastEvent`.\n *\n * Kept local on purpose: this adapter is **structurally typed** so `@warlock.js/herald`\n * takes no dependency on `@warlock.js/core`. The shape only needs the fields the\n * adapter reads (`event` for the channel, `payload` for the body).\n */\nexport type UseCaseBroadcastEvent = {\n  useCase: string;\n  event: string;\n  id: string;\n  at: Date;\n  payload: unknown;\n};\n\n/**\n * Channel adapter that publishes use-case broadcast events onto a herald broker.\n *\n * Register it in the use-cases config so successful use cases fan out to the bus:\n *\n * @example\n * // src/config/use-cases.ts\n * import { heraldBroadcast } from \"@warlock.js/herald\";\n *\n * export default {\n *   broadcast: {\n *     enabled: true,\n *     channels: [heraldBroadcast({ broker: \"default\" })],\n *   },\n * } satisfies UseCaseConfigurations;\n *\n * @param options - Optional broker name (defaults to the default broker)\n */\nexport function heraldBroadcast(options?: { broker?: string }) {\n  return {\n    async broadcast(event: UseCaseBroadcastEvent): Promise<void> {\n      await herald(options?.broker).channel(event.event).publish(event.payload);\n    },\n  };\n}\n"],"mappings":"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"}