@warlock.js/herald 4.0.174 → 4.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (236) hide show
  1. package/README.md +36 -33
  2. package/cjs/index.cjs +1355 -0
  3. package/cjs/index.cjs.map +1 -0
  4. package/esm/communicators/broker-registry.d.mts +157 -0
  5. package/esm/communicators/broker-registry.d.mts.map +1 -0
  6. package/esm/communicators/broker-registry.mjs +204 -0
  7. package/esm/communicators/broker-registry.mjs.map +1 -0
  8. package/esm/communicators/broker.d.mts +104 -0
  9. package/esm/communicators/broker.d.mts.map +1 -0
  10. package/esm/communicators/broker.mjs +104 -0
  11. package/esm/communicators/broker.mjs.map +1 -0
  12. package/esm/communicators/index.d.mts +2 -0
  13. package/esm/communicators/index.mjs +4 -0
  14. package/esm/contracts/broker-driver.contract.d.mts +200 -0
  15. package/esm/contracts/broker-driver.contract.d.mts.map +1 -0
  16. package/esm/contracts/channel.contract.d.mts +197 -0
  17. package/esm/contracts/channel.contract.d.mts.map +1 -0
  18. package/esm/contracts/index.d.mts +2 -0
  19. package/esm/decorators/consumable.d.mts +17 -0
  20. package/esm/decorators/consumable.d.mts.map +1 -0
  21. package/esm/decorators/consumable.mjs +36 -0
  22. package/esm/decorators/consumable.mjs.map +1 -0
  23. package/esm/decorators/index.d.mts +1 -0
  24. package/esm/decorators/index.mjs +3 -0
  25. package/esm/drivers/index.d.mts +2 -0
  26. package/esm/drivers/index.mjs +5 -0
  27. package/esm/drivers/rabbitmq/index.d.mts +2 -0
  28. package/esm/drivers/rabbitmq/index.mjs +4 -0
  29. package/esm/drivers/rabbitmq/rabbitmq-channel.d.mts +85 -0
  30. package/esm/drivers/rabbitmq/rabbitmq-channel.d.mts.map +1 -0
  31. package/esm/drivers/rabbitmq/rabbitmq-channel.mjs +352 -0
  32. package/esm/drivers/rabbitmq/rabbitmq-channel.mjs.map +1 -0
  33. package/esm/drivers/rabbitmq/rabbitmq-driver.d.mts +130 -0
  34. package/esm/drivers/rabbitmq/rabbitmq-driver.d.mts.map +1 -0
  35. package/esm/drivers/rabbitmq/rabbitmq-driver.mjs +291 -0
  36. package/esm/drivers/rabbitmq/rabbitmq-driver.mjs.map +1 -0
  37. package/esm/index.d.mts +20 -0
  38. package/esm/index.mjs +16 -0
  39. package/esm/message-managers/event-consumer.d.mts +61 -0
  40. package/esm/message-managers/event-consumer.d.mts.map +1 -0
  41. package/esm/message-managers/event-consumer.mjs +63 -0
  42. package/esm/message-managers/event-consumer.mjs.map +1 -0
  43. package/esm/message-managers/event-message.d.mts +87 -0
  44. package/esm/message-managers/event-message.d.mts.map +1 -0
  45. package/esm/message-managers/event-message.mjs +68 -0
  46. package/esm/message-managers/event-message.mjs.map +1 -0
  47. package/esm/message-managers/index.d.mts +3 -0
  48. package/esm/message-managers/index.mjs +4 -0
  49. package/esm/message-managers/prepare-consumer-subscription.mjs +42 -0
  50. package/esm/message-managers/prepare-consumer-subscription.mjs.map +1 -0
  51. package/esm/message-managers/types.d.mts +23 -0
  52. package/esm/message-managers/types.d.mts.map +1 -0
  53. package/esm/types/channel.types.d.mts +23 -0
  54. package/esm/types/channel.types.d.mts.map +1 -0
  55. package/esm/types/connection.types.d.mts +67 -0
  56. package/esm/types/connection.types.d.mts.map +1 -0
  57. package/esm/types/driver.types.d.mts +13 -0
  58. package/esm/types/driver.types.d.mts.map +1 -0
  59. package/esm/types/index.d.mts +7 -0
  60. package/esm/types/message.types.d.mts +37 -0
  61. package/esm/types/message.types.d.mts.map +1 -0
  62. package/esm/types/publish.types.d.mts +16 -0
  63. package/esm/types/publish.types.d.mts.map +1 -0
  64. package/esm/types/registry.types.d.mts +8 -0
  65. package/esm/types/registry.types.d.mts.map +1 -0
  66. package/esm/types/subscribe.types.d.mts +21 -0
  67. package/esm/types/subscribe.types.d.mts.map +1 -0
  68. package/esm/use-case-broadcast.d.mts +41 -0
  69. package/esm/use-case-broadcast.d.mts.map +1 -0
  70. package/esm/use-case-broadcast.mjs +30 -0
  71. package/esm/use-case-broadcast.mjs.map +1 -0
  72. package/esm/utils/{connect-to-broker.d.ts → connect-to-broker.d.mts} +15 -10
  73. package/esm/utils/connect-to-broker.d.mts.map +1 -0
  74. package/esm/utils/connect-to-broker.mjs +168 -0
  75. package/esm/utils/connect-to-broker.mjs.map +1 -0
  76. package/esm/utils/index.d.mts +1 -0
  77. package/esm/utils/index.mjs +3 -0
  78. package/llms-full.txt +581 -0
  79. package/llms.txt +12 -0
  80. package/package.json +46 -46
  81. package/skills/README.md +21 -0
  82. package/skills/consume-message/SKILL.md +217 -0
  83. package/skills/herald-basics/SKILL.md +96 -0
  84. package/skills/publish-message/SKILL.md +172 -0
  85. package/skills/request-and-respond/SKILL.md +74 -0
  86. package/cjs/communicators/broker-registry.d.ts +0 -155
  87. package/cjs/communicators/broker-registry.d.ts.map +0 -1
  88. package/cjs/communicators/broker-registry.js +0 -206
  89. package/cjs/communicators/broker-registry.js.map +0 -1
  90. package/cjs/communicators/broker.d.ts +0 -100
  91. package/cjs/communicators/broker.d.ts.map +0 -1
  92. package/cjs/communicators/broker.js +0 -105
  93. package/cjs/communicators/broker.js.map +0 -1
  94. package/cjs/communicators/index.d.ts +0 -3
  95. package/cjs/communicators/index.d.ts.map +0 -1
  96. package/cjs/contracts/broker-driver.contract.d.ts +0 -196
  97. package/cjs/contracts/broker-driver.contract.d.ts.map +0 -1
  98. package/cjs/contracts/channel.contract.d.ts +0 -191
  99. package/cjs/contracts/channel.contract.d.ts.map +0 -1
  100. package/cjs/contracts/index.d.ts +0 -3
  101. package/cjs/contracts/index.d.ts.map +0 -1
  102. package/cjs/decorators/consumable.d.ts +0 -13
  103. package/cjs/decorators/consumable.d.ts.map +0 -1
  104. package/cjs/decorators/consumable.js +0 -33
  105. package/cjs/decorators/consumable.js.map +0 -1
  106. package/cjs/decorators/index.d.ts +0 -2
  107. package/cjs/decorators/index.d.ts.map +0 -1
  108. package/cjs/drivers/index.d.ts +0 -2
  109. package/cjs/drivers/index.d.ts.map +0 -1
  110. package/cjs/drivers/rabbitmq/index.d.ts +0 -3
  111. package/cjs/drivers/rabbitmq/index.d.ts.map +0 -1
  112. package/cjs/drivers/rabbitmq/rabbitmq-channel.d.ts +0 -79
  113. package/cjs/drivers/rabbitmq/rabbitmq-channel.d.ts.map +0 -1
  114. package/cjs/drivers/rabbitmq/rabbitmq-channel.js +0 -414
  115. package/cjs/drivers/rabbitmq/rabbitmq-channel.js.map +0 -1
  116. package/cjs/drivers/rabbitmq/rabbitmq-driver.d.ts +0 -124
  117. package/cjs/drivers/rabbitmq/rabbitmq-driver.d.ts.map +0 -1
  118. package/cjs/drivers/rabbitmq/rabbitmq-driver.js +0 -347
  119. package/cjs/drivers/rabbitmq/rabbitmq-driver.js.map +0 -1
  120. package/cjs/index.d.ts +0 -47
  121. package/cjs/index.d.ts.map +0 -1
  122. package/cjs/index.js +0 -1
  123. package/cjs/index.js.map +0 -1
  124. package/cjs/message-managers/event-consumer.d.ts +0 -64
  125. package/cjs/message-managers/event-consumer.d.ts.map +0 -1
  126. package/cjs/message-managers/event-consumer.js +0 -71
  127. package/cjs/message-managers/event-consumer.js.map +0 -1
  128. package/cjs/message-managers/event-message.d.ts +0 -90
  129. package/cjs/message-managers/event-message.d.ts.map +0 -1
  130. package/cjs/message-managers/event-message.js +0 -84
  131. package/cjs/message-managers/event-message.js.map +0 -1
  132. package/cjs/message-managers/index.d.ts +0 -4
  133. package/cjs/message-managers/index.d.ts.map +0 -1
  134. package/cjs/message-managers/prepare-consumer-subscription.d.ts +0 -4
  135. package/cjs/message-managers/prepare-consumer-subscription.d.ts.map +0 -1
  136. package/cjs/message-managers/prepare-consumer-subscription.js +0 -40
  137. package/cjs/message-managers/prepare-consumer-subscription.js.map +0 -1
  138. package/cjs/message-managers/types.d.ts +0 -20
  139. package/cjs/message-managers/types.d.ts.map +0 -1
  140. package/cjs/types/channel.types.d.ts +0 -19
  141. package/cjs/types/channel.types.d.ts.map +0 -1
  142. package/cjs/types/connection.types.d.ts +0 -65
  143. package/cjs/types/connection.types.d.ts.map +0 -1
  144. package/cjs/types/driver.types.d.ts +0 -10
  145. package/cjs/types/driver.types.d.ts.map +0 -1
  146. package/cjs/types/index.d.ts +0 -8
  147. package/cjs/types/index.d.ts.map +0 -1
  148. package/cjs/types/message.types.d.ts +0 -34
  149. package/cjs/types/message.types.d.ts.map +0 -1
  150. package/cjs/types/publish.types.d.ts +0 -13
  151. package/cjs/types/publish.types.d.ts.map +0 -1
  152. package/cjs/types/registry.types.d.ts +0 -4
  153. package/cjs/types/registry.types.d.ts.map +0 -1
  154. package/cjs/types/subscribe.types.d.ts +0 -18
  155. package/cjs/types/subscribe.types.d.ts.map +0 -1
  156. package/cjs/utils/connect-to-broker.d.ts +0 -131
  157. package/cjs/utils/connect-to-broker.d.ts.map +0 -1
  158. package/cjs/utils/connect-to-broker.js +0 -171
  159. package/cjs/utils/connect-to-broker.js.map +0 -1
  160. package/cjs/utils/index.d.ts +0 -2
  161. package/cjs/utils/index.d.ts.map +0 -1
  162. package/esm/communicators/broker-registry.d.ts +0 -155
  163. package/esm/communicators/broker-registry.d.ts.map +0 -1
  164. package/esm/communicators/broker-registry.js +0 -206
  165. package/esm/communicators/broker-registry.js.map +0 -1
  166. package/esm/communicators/broker.d.ts +0 -100
  167. package/esm/communicators/broker.d.ts.map +0 -1
  168. package/esm/communicators/broker.js +0 -105
  169. package/esm/communicators/broker.js.map +0 -1
  170. package/esm/communicators/index.d.ts +0 -3
  171. package/esm/communicators/index.d.ts.map +0 -1
  172. package/esm/contracts/broker-driver.contract.d.ts +0 -196
  173. package/esm/contracts/broker-driver.contract.d.ts.map +0 -1
  174. package/esm/contracts/channel.contract.d.ts +0 -191
  175. package/esm/contracts/channel.contract.d.ts.map +0 -1
  176. package/esm/contracts/index.d.ts +0 -3
  177. package/esm/contracts/index.d.ts.map +0 -1
  178. package/esm/decorators/consumable.d.ts +0 -13
  179. package/esm/decorators/consumable.d.ts.map +0 -1
  180. package/esm/decorators/consumable.js +0 -33
  181. package/esm/decorators/consumable.js.map +0 -1
  182. package/esm/decorators/index.d.ts +0 -2
  183. package/esm/decorators/index.d.ts.map +0 -1
  184. package/esm/drivers/index.d.ts +0 -2
  185. package/esm/drivers/index.d.ts.map +0 -1
  186. package/esm/drivers/rabbitmq/index.d.ts +0 -3
  187. package/esm/drivers/rabbitmq/index.d.ts.map +0 -1
  188. package/esm/drivers/rabbitmq/rabbitmq-channel.d.ts +0 -79
  189. package/esm/drivers/rabbitmq/rabbitmq-channel.d.ts.map +0 -1
  190. package/esm/drivers/rabbitmq/rabbitmq-channel.js +0 -414
  191. package/esm/drivers/rabbitmq/rabbitmq-channel.js.map +0 -1
  192. package/esm/drivers/rabbitmq/rabbitmq-driver.d.ts +0 -124
  193. package/esm/drivers/rabbitmq/rabbitmq-driver.d.ts.map +0 -1
  194. package/esm/drivers/rabbitmq/rabbitmq-driver.js +0 -347
  195. package/esm/drivers/rabbitmq/rabbitmq-driver.js.map +0 -1
  196. package/esm/index.d.ts +0 -47
  197. package/esm/index.d.ts.map +0 -1
  198. package/esm/index.js +0 -1
  199. package/esm/index.js.map +0 -1
  200. package/esm/message-managers/event-consumer.d.ts +0 -64
  201. package/esm/message-managers/event-consumer.d.ts.map +0 -1
  202. package/esm/message-managers/event-consumer.js +0 -71
  203. package/esm/message-managers/event-consumer.js.map +0 -1
  204. package/esm/message-managers/event-message.d.ts +0 -90
  205. package/esm/message-managers/event-message.d.ts.map +0 -1
  206. package/esm/message-managers/event-message.js +0 -84
  207. package/esm/message-managers/event-message.js.map +0 -1
  208. package/esm/message-managers/index.d.ts +0 -4
  209. package/esm/message-managers/index.d.ts.map +0 -1
  210. package/esm/message-managers/prepare-consumer-subscription.d.ts +0 -4
  211. package/esm/message-managers/prepare-consumer-subscription.d.ts.map +0 -1
  212. package/esm/message-managers/prepare-consumer-subscription.js +0 -40
  213. package/esm/message-managers/prepare-consumer-subscription.js.map +0 -1
  214. package/esm/message-managers/types.d.ts +0 -20
  215. package/esm/message-managers/types.d.ts.map +0 -1
  216. package/esm/types/channel.types.d.ts +0 -19
  217. package/esm/types/channel.types.d.ts.map +0 -1
  218. package/esm/types/connection.types.d.ts +0 -65
  219. package/esm/types/connection.types.d.ts.map +0 -1
  220. package/esm/types/driver.types.d.ts +0 -10
  221. package/esm/types/driver.types.d.ts.map +0 -1
  222. package/esm/types/index.d.ts +0 -8
  223. package/esm/types/index.d.ts.map +0 -1
  224. package/esm/types/message.types.d.ts +0 -34
  225. package/esm/types/message.types.d.ts.map +0 -1
  226. package/esm/types/publish.types.d.ts +0 -13
  227. package/esm/types/publish.types.d.ts.map +0 -1
  228. package/esm/types/registry.types.d.ts +0 -4
  229. package/esm/types/registry.types.d.ts.map +0 -1
  230. package/esm/types/subscribe.types.d.ts +0 -18
  231. package/esm/types/subscribe.types.d.ts.map +0 -1
  232. package/esm/utils/connect-to-broker.d.ts.map +0 -1
  233. package/esm/utils/connect-to-broker.js +0 -171
  234. package/esm/utils/connect-to-broker.js.map +0 -1
  235. package/esm/utils/index.d.ts +0 -2
  236. package/esm/utils/index.d.ts.map +0 -1
@@ -0,0 +1 @@
1
+ {"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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"}
@@ -0,0 +1,157 @@
1
+ import { Broker, BrokerOptions } from "./broker.mjs";
2
+ import { BrokerRegistryEvent, BrokerRegistryListener } from "../types/registry.types.mjs";
3
+ //#region ../../@warlock.js/herald/src/communicators/broker-registry.d.ts
4
+ /**
5
+ * Error thrown when a broker is not found
6
+ */
7
+ declare class MissingBrokerError extends Error {
8
+ readonly brokerName?: string;
9
+ constructor(message: string, brokerName?: string);
10
+ }
11
+ /**
12
+ * Broker Registry
13
+ *
14
+ * Maintains registry of named brokers.
15
+ * Similar to DataSourceRegistry in @warlock.js/cascade
16
+ *
17
+ * @example
18
+ * ```typescript
19
+ * // Register a broker
20
+ * brokerRegistry.register({
21
+ * name: "default",
22
+ * driver: rabbitMQDriver,
23
+ * isDefault: true,
24
+ * });
25
+ *
26
+ * // Get the default broker
27
+ * const comm = brokerRegistry.get();
28
+ *
29
+ * // Get a specific broker by name
30
+ * const analytics = brokerRegistry.get("analytics");
31
+ *
32
+ * // Listen for events
33
+ * brokerRegistry.on("connected", (comm) => {
34
+ * console.log(`${comm.name} connected`);
35
+ * });
36
+ * ```
37
+ */
38
+ declare class BrokerRegistry {
39
+ private readonly sources;
40
+ private defaultSource?;
41
+ private readonly events;
42
+ /**
43
+ * Register a new broker
44
+ *
45
+ * Sets up event forwarding from the driver to the registry.
46
+ *
47
+ * @param options - Broker configuration
48
+ * @returns The registered broker instance
49
+ *
50
+ * @example
51
+ * ```typescript
52
+ * const broker = brokerRegistry.register({
53
+ * name: "primary",
54
+ * driver: myDriver,
55
+ * isDefault: true,
56
+ * });
57
+ * ```
58
+ */
59
+ register(options: BrokerOptions): Broker;
60
+ /**
61
+ * Clear all registered brokers
62
+ */
63
+ clear(): void;
64
+ /**
65
+ * Listen for registry events
66
+ *
67
+ * @param event - Event to listen for
68
+ * @param listener - Callback function
69
+ *
70
+ * @example
71
+ * ```typescript
72
+ * brokerRegistry.on("registered", (comm) => {
73
+ * console.log(`Broker "${comm.name}" registered`);
74
+ * });
75
+ *
76
+ * brokerRegistry.on("connected", (comm) => {
77
+ * console.log(`Broker "${comm.name}" connected`);
78
+ * });
79
+ * ```
80
+ */
81
+ on(event: BrokerRegistryEvent, listener: BrokerRegistryListener): void;
82
+ /**
83
+ * Listen for a registry event once
84
+ *
85
+ * @param event - Event to listen for
86
+ * @param listener - Callback function
87
+ */
88
+ once(event: BrokerRegistryEvent, listener: BrokerRegistryListener): void;
89
+ /**
90
+ * Remove an event listener
91
+ *
92
+ * @param event - Event to stop listening for
93
+ * @param listener - Callback to remove
94
+ */
95
+ off(event: BrokerRegistryEvent, listener: BrokerRegistryListener): void;
96
+ /**
97
+ * Get a broker by name or the default one
98
+ *
99
+ * @param name - Optional broker name
100
+ * @returns Broker instance
101
+ * @throws MissingBrokerError if not found
102
+ *
103
+ * @example
104
+ * ```typescript
105
+ * // Get default broker
106
+ * const comm = brokerRegistry.get();
107
+ *
108
+ * // Get specific broker
109
+ * const analytics = brokerRegistry.get("analytics");
110
+ * ```
111
+ */
112
+ get(name?: string): Broker;
113
+ /**
114
+ * Check if a broker exists
115
+ *
116
+ * @param name - Broker name to check
117
+ * @returns True if exists
118
+ */
119
+ has(name: string): boolean;
120
+ /**
121
+ * Check if any brokers are registered
122
+ */
123
+ hasAny(): boolean;
124
+ /**
125
+ * Get all registered brokers
126
+ *
127
+ * @returns Array of all brokers
128
+ *
129
+ * @example
130
+ * ```typescript
131
+ * // Disconnect all brokers
132
+ * for (const comm of brokerRegistry.getAll()) {
133
+ * await comm.disconnect();
134
+ * }
135
+ * ```
136
+ */
137
+ getAll(): Broker[];
138
+ /**
139
+ * Get all broker names
140
+ *
141
+ * @returns Array of broker names
142
+ */
143
+ getNames(): string[];
144
+ /**
145
+ * Get the default broker (if any)
146
+ *
147
+ * @returns Default broker or undefined
148
+ */
149
+ getDefault(): Broker | undefined;
150
+ }
151
+ /**
152
+ * Global broker registry instance
153
+ */
154
+ declare const brokerRegistry: BrokerRegistry;
155
+ //#endregion
156
+ export { MissingBrokerError, brokerRegistry };
157
+ //# sourceMappingURL=broker-registry.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"broker-registry.d.mts","names":[],"sources":["../../../../../../@warlock.js/herald/src/communicators/broker-registry.ts"],"mappings":";;;;;;cAOa,kBAAA,SAA2B,KAAK;EAAA,SAC3B,UAAA;cAEG,OAAA,UAAiB,UAAA;AAAA;;;;;;;AAAmB;AAKxD;;;;;;;;;;;;;;;;;;;;cA6BK,cAAA;EAAA,iBACa,OAAA;EAAA,QACT,aAAA;EAAA,iBACS,MAAA;EAyEV;;;;;;;;;;;;;;;;;EAtDA,QAAA,CAAS,OAAA,EAAS,aAAA,GAAgB,MAAA;EAoHlC;;;EApFA,KAAA,CAAA;EA4GU;;;;;AAkBU;AAQ7B;;;;AAAkD;;;;;;;EAhHzC,EAAA,CAAG,KAAA,EAAO,mBAAA,EAAqB,QAAA,EAAU,sBAAA;;;;;;;EAUzC,IAAA,CAAK,KAAA,EAAO,mBAAA,EAAqB,QAAA,EAAU,sBAAA;;;;;;;EAU3C,GAAA,CAAI,KAAA,EAAO,mBAAA,EAAqB,QAAA,EAAU,sBAAA;;;;;;;;;;;;;;;;;EAoB1C,GAAA,CAAI,IAAA,YAAgB,MAAA;;;;;;;EAsBpB,GAAA,CAAI,IAAA;;;;EAOJ,MAAA,CAAA;;;;;;;;;;;;;;EAiBA,MAAA,CAAA,GAAU,MAAA;;;;;;EASV,QAAA,CAAA;;;;;;EASA,UAAA,CAAA,GAAc,MAAA;AAAA;;;;cAQV,cAAA,EAAc,cAAuB"}
@@ -0,0 +1,204 @@
1
+ import { Broker } from "./broker.mjs";
2
+ import { EventEmitter } from "node:events";
3
+
4
+ //#region ../../@warlock.js/herald/src/communicators/broker-registry.ts
5
+ /**
6
+ * Error thrown when a broker is not found
7
+ */
8
+ var MissingBrokerError = class extends Error {
9
+ constructor(message, brokerName) {
10
+ super(message);
11
+ this.name = "MissingBrokerError";
12
+ this.brokerName = brokerName;
13
+ }
14
+ };
15
+ /**
16
+ * Broker Registry
17
+ *
18
+ * Maintains registry of named brokers.
19
+ * Similar to DataSourceRegistry in @warlock.js/cascade
20
+ *
21
+ * @example
22
+ * ```typescript
23
+ * // Register a broker
24
+ * brokerRegistry.register({
25
+ * name: "default",
26
+ * driver: rabbitMQDriver,
27
+ * isDefault: true,
28
+ * });
29
+ *
30
+ * // Get the default broker
31
+ * const comm = brokerRegistry.get();
32
+ *
33
+ * // Get a specific broker by name
34
+ * const analytics = brokerRegistry.get("analytics");
35
+ *
36
+ * // Listen for events
37
+ * brokerRegistry.on("connected", (comm) => {
38
+ * console.log(`${comm.name} connected`);
39
+ * });
40
+ * ```
41
+ */
42
+ var BrokerRegistry = class {
43
+ constructor() {
44
+ this.sources = /* @__PURE__ */ new Map();
45
+ this.events = new EventEmitter();
46
+ }
47
+ /**
48
+ * Register a new broker
49
+ *
50
+ * Sets up event forwarding from the driver to the registry.
51
+ *
52
+ * @param options - Broker configuration
53
+ * @returns The registered broker instance
54
+ *
55
+ * @example
56
+ * ```typescript
57
+ * const broker = brokerRegistry.register({
58
+ * name: "primary",
59
+ * driver: myDriver,
60
+ * isDefault: true,
61
+ * });
62
+ * ```
63
+ */
64
+ register(options) {
65
+ const broker = new Broker(options);
66
+ this.sources.set(broker.name, broker);
67
+ const isNewDefault = broker.isDefault || !this.defaultSource;
68
+ if (isNewDefault) this.defaultSource = broker;
69
+ this.events.emit("registered", broker);
70
+ if (isNewDefault) this.events.emit("default-registered", broker);
71
+ broker.driver.on("connected", () => {
72
+ this.events.emit("connected", broker);
73
+ });
74
+ broker.driver.on("disconnected", () => {
75
+ this.events.emit("disconnected", broker);
76
+ });
77
+ return broker;
78
+ }
79
+ /**
80
+ * Clear all registered brokers
81
+ */
82
+ clear() {
83
+ this.defaultSource = void 0;
84
+ this.sources.clear();
85
+ }
86
+ /**
87
+ * Listen for registry events
88
+ *
89
+ * @param event - Event to listen for
90
+ * @param listener - Callback function
91
+ *
92
+ * @example
93
+ * ```typescript
94
+ * brokerRegistry.on("registered", (comm) => {
95
+ * console.log(`Broker "${comm.name}" registered`);
96
+ * });
97
+ *
98
+ * brokerRegistry.on("connected", (comm) => {
99
+ * console.log(`Broker "${comm.name}" connected`);
100
+ * });
101
+ * ```
102
+ */
103
+ on(event, listener) {
104
+ this.events.on(event, listener);
105
+ }
106
+ /**
107
+ * Listen for a registry event once
108
+ *
109
+ * @param event - Event to listen for
110
+ * @param listener - Callback function
111
+ */
112
+ once(event, listener) {
113
+ this.events.once(event, listener);
114
+ }
115
+ /**
116
+ * Remove an event listener
117
+ *
118
+ * @param event - Event to stop listening for
119
+ * @param listener - Callback to remove
120
+ */
121
+ off(event, listener) {
122
+ this.events.off(event, listener);
123
+ }
124
+ /**
125
+ * Get a broker by name or the default one
126
+ *
127
+ * @param name - Optional broker name
128
+ * @returns Broker instance
129
+ * @throws MissingBrokerError if not found
130
+ *
131
+ * @example
132
+ * ```typescript
133
+ * // Get default broker
134
+ * const comm = brokerRegistry.get();
135
+ *
136
+ * // Get specific broker
137
+ * const analytics = brokerRegistry.get("analytics");
138
+ * ```
139
+ */
140
+ get(name) {
141
+ if (name !== void 0) {
142
+ const source = this.sources.get(name);
143
+ if (!source) throw new MissingBrokerError(`Broker "${name}" is not registered.`, name);
144
+ return source;
145
+ }
146
+ if (!this.defaultSource) throw new MissingBrokerError("No default broker registered.");
147
+ return this.defaultSource;
148
+ }
149
+ /**
150
+ * Check if a broker exists
151
+ *
152
+ * @param name - Broker name to check
153
+ * @returns True if exists
154
+ */
155
+ has(name) {
156
+ return this.sources.has(name);
157
+ }
158
+ /**
159
+ * Check if any brokers are registered
160
+ */
161
+ hasAny() {
162
+ return this.sources.size > 0;
163
+ }
164
+ /**
165
+ * Get all registered brokers
166
+ *
167
+ * @returns Array of all brokers
168
+ *
169
+ * @example
170
+ * ```typescript
171
+ * // Disconnect all brokers
172
+ * for (const comm of brokerRegistry.getAll()) {
173
+ * await comm.disconnect();
174
+ * }
175
+ * ```
176
+ */
177
+ getAll() {
178
+ return Array.from(this.sources.values());
179
+ }
180
+ /**
181
+ * Get all broker names
182
+ *
183
+ * @returns Array of broker names
184
+ */
185
+ getNames() {
186
+ return Array.from(this.sources.keys());
187
+ }
188
+ /**
189
+ * Get the default broker (if any)
190
+ *
191
+ * @returns Default broker or undefined
192
+ */
193
+ getDefault() {
194
+ return this.defaultSource;
195
+ }
196
+ };
197
+ /**
198
+ * Global broker registry instance
199
+ */
200
+ const brokerRegistry = new BrokerRegistry();
201
+
202
+ //#endregion
203
+ export { MissingBrokerError, brokerRegistry };
204
+ //# sourceMappingURL=broker-registry.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"broker-registry.mjs","names":[],"sources":["../../../../../../@warlock.js/herald/src/communicators/broker-registry.ts"],"sourcesContent":["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"],"mappings":";;;;;;;AAOA,IAAa,qBAAb,cAAwC,MAAM;CAG5C,AAAO,YAAY,SAAiB,YAAqB;EACvD,MAAM,OAAO;EACb,KAAK,OAAO;EACZ,KAAK,aAAa;CACpB;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BA,IAAM,iBAAN,MAAqB;;iCACQ,IAAI,IAAoB;gBAEzB,IAAI,aAAa;;;;;;;;;;;;;;;;;;;CAmB3C,AAAO,SAAS,SAAgC;EAC9C,MAAM,SAAS,IAAI,OAAO,OAAO;EACjC,KAAK,QAAQ,IAAI,OAAO,MAAM,MAAM;EAEpC,MAAM,eAAe,OAAO,aAAa,CAAC,KAAK;EAE/C,IAAI,cACF,KAAK,gBAAgB;EAIvB,KAAK,OAAO,KAAK,cAAc,MAAM;EAErC,IAAI,cACF,KAAK,OAAO,KAAK,sBAAsB,MAAM;EAI/C,OAAO,OAAO,GAAG,mBAAmB;GAClC,KAAK,OAAO,KAAK,aAAa,MAAM;EACtC,CAAC;EAED,OAAO,OAAO,GAAG,sBAAsB;GACrC,KAAK,OAAO,KAAK,gBAAgB,MAAM;EACzC,CAAC;EAED,OAAO;CACT;;;;CAKA,AAAO,QAAc;EACnB,KAAK,gBAAgB;EACrB,KAAK,QAAQ,MAAM;CACrB;;;;;;;;;;;;;;;;;;CAmBA,AAAO,GAAG,OAA4B,UAAwC;EAC5E,KAAK,OAAO,GAAG,OAAO,QAAQ;CAChC;;;;;;;CAQA,AAAO,KAAK,OAA4B,UAAwC;EAC9E,KAAK,OAAO,KAAK,OAAO,QAAQ;CAClC;;;;;;;CAQA,AAAO,IAAI,OAA4B,UAAwC;EAC7E,KAAK,OAAO,IAAI,OAAO,QAAQ;CACjC;;;;;;;;;;;;;;;;;CAkBA,AAAO,IAAI,MAAuB;EAChC,IAAI,SAAS,QAAW;GACtB,MAAM,SAAS,KAAK,QAAQ,IAAI,IAAI;GACpC,IAAI,CAAC,QACH,MAAM,IAAI,mBAAmB,WAAW,KAAK,uBAAuB,IAAI;GAE1E,OAAO;EACT;EAEA,IAAI,CAAC,KAAK,eACR,MAAM,IAAI,mBAAmB,+BAA+B;EAG9D,OAAO,KAAK;CACd;;;;;;;CAQA,AAAO,IAAI,MAAuB;EAChC,OAAO,KAAK,QAAQ,IAAI,IAAI;CAC9B;;;;CAKA,AAAO,SAAkB;EACvB,OAAO,KAAK,QAAQ,OAAO;CAC7B;;;;;;;;;;;;;;CAeA,AAAO,SAAmB;EACxB,OAAO,MAAM,KAAK,KAAK,QAAQ,OAAO,CAAC;CACzC;;;;;;CAOA,AAAO,WAAqB;EAC1B,OAAO,MAAM,KAAK,KAAK,QAAQ,KAAK,CAAC;CACvC;;;;;;CAOA,AAAO,aAAiC;EACtC,OAAO,KAAK;CACd;AACF;;;;AAKA,MAAa,iBAAiB,IAAI,eAAe"}
@@ -0,0 +1,104 @@
1
+ import { ChannelOptions } from "../types/channel.types.mjs";
2
+ import { HealthCheckResult } from "../types/driver.types.mjs";
3
+ import { ChannelContract } from "../contracts/channel.contract.mjs";
4
+ import { EventMessage } from "../message-managers/event-message.mjs";
5
+ import { EventConsumerClass } from "../message-managers/types.mjs";
6
+ import { BrokerDriverContract } from "../contracts/broker-driver.contract.mjs";
7
+ //#region ../../@warlock.js/herald/src/communicators/broker.d.ts
8
+ /**
9
+ * Options for creating a Broker
10
+ */
11
+ interface BrokerOptions {
12
+ /** Unique name for this broker */
13
+ name: string;
14
+ /** The underlying driver */
15
+ driver: BrokerDriverContract;
16
+ /** Whether this is the default broker */
17
+ isDefault?: boolean;
18
+ }
19
+ /**
20
+ * Broker - wrapper around a driver with metadata
21
+ *
22
+ * Similar to DataSource in @warlock.js/cascade
23
+ *
24
+ * @example
25
+ * ```typescript
26
+ * const broker = new Broker({
27
+ * name: "default",
28
+ * driver: rabbitMQDriver,
29
+ * isDefault: true,
30
+ * });
31
+ *
32
+ * // Get a channel
33
+ * const channel = broker.channel("user.created");
34
+ * ```
35
+ */
36
+ declare class Broker {
37
+ /** Unique name identifying this broker */
38
+ readonly name: string;
39
+ /** The underlying driver */
40
+ readonly driver: BrokerDriverContract;
41
+ /** Whether this is the default broker */
42
+ readonly isDefault: boolean;
43
+ /**
44
+ * Create a new Broker
45
+ *
46
+ * @param options - Broker configuration
47
+ */
48
+ constructor(options: BrokerOptions);
49
+ /**
50
+ * Subscribe the given consumer
51
+ */
52
+ subscribe(consumer: EventConsumerClass<any>): () => void;
53
+ /**
54
+ * Publish the given event message
55
+ */
56
+ publish<TPayload = Record<string, any>>(event: EventMessage<TPayload>): void;
57
+ /**
58
+ * Get or create a channel
59
+ *
60
+ * @param name - Channel name
61
+ * @param options - Channel options
62
+ * @returns Channel instance
63
+ *
64
+ * @example
65
+ * ```typescript
66
+ * // Simple channel
67
+ * const channel = broker.channel("notifications");
68
+ *
69
+ * // Typed channel with schema
70
+ * const orderChannel = broker.channel<OrderPayload>("orders", {
71
+ * schema: OrderSchema,
72
+ * durable: true,
73
+ * });
74
+ * ```
75
+ */
76
+ channel<TPayload = unknown>(name: string, options?: ChannelOptions<TPayload>): ChannelContract<TPayload>;
77
+ /**
78
+ * Check if the broker is connected
79
+ */
80
+ get isConnected(): boolean;
81
+ /**
82
+ * Connect the underlying driver
83
+ */
84
+ connect(): Promise<void>;
85
+ /**
86
+ * Disconnect the underlying driver
87
+ */
88
+ disconnect(): Promise<void>;
89
+ /**
90
+ * Start consuming messages
91
+ */
92
+ startConsuming(): Promise<void>;
93
+ /**
94
+ * Stop consuming messages
95
+ */
96
+ stopConsuming(): Promise<void>;
97
+ /**
98
+ * Health check
99
+ */
100
+ healthCheck(): Promise<HealthCheckResult>;
101
+ }
102
+ //#endregion
103
+ export { Broker, BrokerOptions };
104
+ //# sourceMappingURL=broker.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"broker.d.mts","names":[],"sources":["../../../../../../@warlock.js/herald/src/communicators/broker.ts"],"mappings":";;;;;;;;;;UASiB,aAAA;;EAEf,IAAA;EAF4B;EAI5B,MAAA,EAAQ,oBAAoB;EAAA;EAE5B,SAAA;AAAA;;;;AAAS;AAoBX;;;;;;;;;;;;;cAAa,MAAA;EA8EgB;EAAA,SA5EX,IAAA;EA0Fc;EAAA,SAvFd,MAAA,EAAQ,oBAAA;EA8FA;EAAA,SA3FR,SAAA;EA2FQ;;;;;cApFL,OAAA,EAAS,aAAA;EAAA;;;EASrB,SAAA,CAAU,QAAA,EAAU,kBAAA;EAAV;;;EAOV,OAAA,YAAmB,MAAA,cAAA,CAAqB,KAAA,EAAO,YAAA,CAAa,QAAA;EAAb;;;;;;;;;;;;;;;;;;;EAuB/C,OAAA,oBAAA,CACL,IAAA,UACA,OAAA,GAAU,cAAA,CAAe,QAAA,IACxB,eAAA,CAAgB,QAAA;EA0CN;;;EAAA,IAnCF,WAAA,CAAA;EAmCa;;;EA5BX,OAAA,CAAA,GAAW,OAAA;;;;EAOX,UAAA,CAAA,GAAc,OAAA;;;;EAOd,cAAA,CAAA,GAAkB,OAAA;;;;EAOlB,aAAA,CAAA,GAAiB,OAAA;;;;EAOjB,WAAA,CAAA,GAAW,OAAA,CAPa,iBAAA;AAAA"}