{"version":3,"file":"rabbitmq-channel.mjs","names":[],"sources":["../../../../../../../../@warlock.js/herald/src/drivers/rabbitmq/rabbitmq-channel.ts"],"sourcesContent":["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"],"mappings":"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"}