@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,85 @@
1
+ import { SubscribeOptions } from "../../types/subscribe.types.mjs";
2
+ import { ChannelOptions, ChannelStats } from "../../types/channel.types.mjs";
3
+ import { MessageHandler, ResponseHandler, Subscription } from "../../types/message.types.mjs";
4
+ import { PublishOptions, RequestOptions } from "../../types/publish.types.mjs";
5
+ import { ChannelContract } from "../../contracts/channel.contract.mjs";
6
+ //#region ../../@warlock.js/herald/src/drivers/rabbitmq/rabbitmq-channel.d.ts
7
+ /**
8
+ * RabbitMQ Channel Implementation
9
+ *
10
+ * Wraps a RabbitMQ queue/exchange with a unified API.
11
+ *
12
+ * @template TPayload - The typed payload
13
+ */
14
+ declare class RabbitMQChannel<TPayload = unknown> implements ChannelContract<TPayload> {
15
+ readonly name: string;
16
+ readonly options: ChannelOptions<TPayload>;
17
+ private readonly amqpChannel;
18
+ private readonly subscriptions;
19
+ private asserted;
20
+ /**
21
+ * Create a new RabbitMQ channel
22
+ */
23
+ constructor(name: string, amqpChannel: any, options?: ChannelOptions<TPayload>);
24
+ /**
25
+ * Assert the queue exists
26
+ */
27
+ assert(): Promise<void>;
28
+ /**
29
+ * Publish a message
30
+ */
31
+ publish(payload: TPayload, options?: PublishOptions): Promise<void>;
32
+ /**
33
+ * Publish multiple messages
34
+ */
35
+ publishBatch(messages: TPayload[], options?: PublishOptions): Promise<void>;
36
+ /**
37
+ * Subscribe to messages
38
+ *
39
+ * Smart auto-ack behavior (when autoAck is not true):
40
+ * - If handler completes successfully without explicit ack/nack/reject → auto-ack
41
+ * - If handler throws an error → auto-nack (with retry if configured)
42
+ * - If handler explicitly calls ack/nack/reject → respects that call
43
+ */
44
+ subscribe(handler: MessageHandler<TPayload>, options?: SubscribeOptions): Promise<Subscription>;
45
+ /**
46
+ * Unsubscribe by consumer ID
47
+ */
48
+ unsubscribeById(consumerId: string): Promise<void>;
49
+ /**
50
+ * Stop consuming messages on this channel.
51
+ * Cancels all active subscriptions gracefully.
52
+ */
53
+ stopConsuming(): Promise<void>;
54
+ /**
55
+ * Send message to dead-letter queue
56
+ */
57
+ private sendToDeadLetter;
58
+ /**
59
+ * Request-response pattern
60
+ */
61
+ request<TResponse = unknown>(payload: TPayload, options?: RequestOptions): Promise<TResponse>;
62
+ /**
63
+ * Register response handler for RPC
64
+ */
65
+ respond<TResponse = unknown>(handler: ResponseHandler<TPayload, TResponse>): Promise<Subscription>;
66
+ /**
67
+ * Get queue statistics
68
+ */
69
+ stats(): Promise<ChannelStats>;
70
+ /**
71
+ * Purge all messages
72
+ */
73
+ purge(): Promise<number>;
74
+ /**
75
+ * Check if queue exists
76
+ */
77
+ exists(): Promise<boolean>;
78
+ /**
79
+ * Delete the queue
80
+ */
81
+ delete(): Promise<void>;
82
+ }
83
+ //#endregion
84
+ export { RabbitMQChannel };
85
+ //# sourceMappingURL=rabbitmq-channel.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rabbitmq-channel.d.mts","names":[],"sources":["../../../../../../../@warlock.js/herald/src/drivers/rabbitmq/rabbitmq-channel.ts"],"mappings":";;;;;;;;;;;;;cAwBa,eAAA,gCAA+C,eAAA,CAAgB,QAAA;EAAA,SAC1D,IAAA;EAAA,SACA,OAAA,EAAS,cAAA,CAAe,QAAA;EAAA,iBAEvB,WAAA;EAAA,iBACA,aAAA;EAAA,QACT,QAAA;EAKoE;;;cAAzD,IAAA,UAAc,WAAA,OAAkB,OAAA,GAAU,cAAA,CAAe,QAAA;EA6B1B;;;EApBrC,MAAA,CAAA,GAAU,OAAA;EAyEoD;;;EArD9D,OAAA,CAAQ,OAAA,EAAS,QAAA,EAAU,OAAA,GAAU,cAAA,GAAiB,OAAA;EAsExD;;;EAjBE,YAAA,CAAa,QAAA,EAAU,QAAA,IAAY,OAAA,GAAU,cAAA,GAAiB,OAAA;EA4OhE;;;;;;;;EA9NE,SAAA,CACX,OAAA,EAAS,cAAA,CAAe,QAAA,GACxB,OAAA,GAAU,gBAAA,GACT,OAAA,CAAQ,YAAA;EA8RmB;;;EA5GjB,eAAA,CAAgB,UAAA,WAAqB,OAAA;EAiJ3B;;;;EArIV,aAAA,CAAA,GAAiB,OAAA;EA5S4B;;;EAAA,QAsT5C,gBAAA;EApTW;;;EAsUZ,OAAA,qBAAA,CACX,OAAA,EAAS,QAAA,EACT,OAAA,GAAU,cAAA,GACT,OAAA,CAAQ,SAAA;EArUH;;;EAyXK,OAAA,qBAAA,CACX,OAAA,EAAS,eAAA,CAAgB,QAAA,EAAU,SAAA,IAClC,OAAA,CAAQ,YAAA;EAtXkD;;;EAiYhD,KAAA,CAAA,GAAS,OAAA,CAAQ,YAAA;EAxXP;;;EAuYV,KAAA,CAAA,GAAS,OAAA;EAnX4B;;;EA6XrC,MAAA,CAAA,GAAU,OAAA;EAxUa;;;EAoVvB,MAAA,CAAA,GAAU,OAAA;AAAA"}
@@ -0,0 +1,352 @@
1
+ import { v } from "@warlock.js/seal";
2
+ import { randomUUID } from "node:crypto";
3
+
4
+ //#region ../../@warlock.js/herald/src/drivers/rabbitmq/rabbitmq-channel.ts
5
+ /**
6
+ * RabbitMQ Channel Implementation
7
+ *
8
+ * Wraps a RabbitMQ queue/exchange with a unified API.
9
+ *
10
+ * @template TPayload - The typed payload
11
+ */
12
+ var RabbitMQChannel = class {
13
+ /**
14
+ * Create a new RabbitMQ channel
15
+ */
16
+ constructor(name, amqpChannel, options) {
17
+ this.subscriptions = /* @__PURE__ */ new Map();
18
+ this.asserted = false;
19
+ this.name = name;
20
+ this.amqpChannel = amqpChannel;
21
+ this.options = options ?? {};
22
+ }
23
+ /**
24
+ * Assert the queue exists
25
+ */
26
+ async assert() {
27
+ if (this.asserted) return;
28
+ const queueOptions = {
29
+ durable: this.options.durable ?? true,
30
+ autoDelete: this.options.autoDelete ?? false,
31
+ exclusive: this.options.exclusive ?? false,
32
+ messageTtl: this.options.messageTtl,
33
+ maxLength: this.options.maxLength,
34
+ deadLetterExchange: this.options.deadLetter?.channel ? "" : void 0,
35
+ deadLetterRoutingKey: this.options.deadLetter?.channel
36
+ };
37
+ await this.amqpChannel.assertQueue(this.name, queueOptions);
38
+ this.asserted = true;
39
+ }
40
+ /**
41
+ * Publish a message
42
+ */
43
+ async publish(payload, options) {
44
+ await this.assert();
45
+ if (this.options.schema) {
46
+ const context = {
47
+ allValues: payload,
48
+ value: payload
49
+ };
50
+ const result = await v.validate(this.options.schema, payload, { context });
51
+ if (!result.isValid) throw new Error(`Message validation failed: ${JSON.stringify(result.errors)}`);
52
+ payload = result.data;
53
+ }
54
+ const messageId = randomUUID();
55
+ const timestamp = /* @__PURE__ */ new Date();
56
+ const messageContent = JSON.stringify({
57
+ payload,
58
+ metadata: {
59
+ messageId,
60
+ timestamp: timestamp.toISOString(),
61
+ correlationId: options?.correlationId,
62
+ headers: options?.headers
63
+ }
64
+ });
65
+ const publishOptions = {
66
+ persistent: options?.persistent ?? true,
67
+ messageId,
68
+ timestamp: timestamp.getTime(),
69
+ correlationId: options?.correlationId,
70
+ expiration: options?.expiration?.toString(),
71
+ priority: options?.priority,
72
+ headers: options?.headers
73
+ };
74
+ if (options?.delay) publishOptions.headers = {
75
+ ...publishOptions.headers,
76
+ "x-delay": options.delay
77
+ };
78
+ this.amqpChannel.sendToQueue(this.name, Buffer.from(messageContent), publishOptions);
79
+ }
80
+ /**
81
+ * Publish multiple messages
82
+ */
83
+ async publishBatch(messages, options) {
84
+ for (const payload of messages) await this.publish(payload, options);
85
+ }
86
+ /**
87
+ * Subscribe to messages
88
+ *
89
+ * Smart auto-ack behavior (when autoAck is not true):
90
+ * - If handler completes successfully without explicit ack/nack/reject → auto-ack
91
+ * - If handler throws an error → auto-nack (with retry if configured)
92
+ * - If handler explicitly calls ack/nack/reject → respects that call
93
+ */
94
+ async subscribe(handler, options) {
95
+ await this.assert();
96
+ const subscriptionId = options?.consumerId ?? randomUUID();
97
+ if (options?.prefetch) await this.amqpChannel.prefetch(options.prefetch);
98
+ const isFireAndForget = options?.autoAck === true;
99
+ const consumerOptions = {
100
+ noAck: isFireAndForget,
101
+ exclusive: options?.exclusive ?? false,
102
+ consumerTag: options?.group ?? subscriptionId
103
+ };
104
+ const { consumerTag } = await this.amqpChannel.consume(this.name, async (msg) => {
105
+ if (!msg) return;
106
+ let ackHandled = isFireAndForget;
107
+ try {
108
+ const content = JSON.parse(msg.content.toString());
109
+ let payload = content.payload;
110
+ if (this.options.schema) {
111
+ const context = {
112
+ allValues: payload,
113
+ value: payload
114
+ };
115
+ const result = await v.validate(this.options.schema, payload, { context });
116
+ if (!result.isValid) {
117
+ this.amqpChannel.nack(msg, false, false);
118
+ return;
119
+ }
120
+ payload = result.data;
121
+ }
122
+ const metadata = {
123
+ messageId: msg.properties.messageId || content.metadata?.messageId || randomUUID(),
124
+ timestamp: new Date(msg.properties.timestamp || content.metadata?.timestamp),
125
+ correlationId: msg.properties.correlationId || content.metadata?.correlationId,
126
+ replyTo: msg.properties.replyTo,
127
+ priority: msg.properties.priority,
128
+ headers: msg.properties.headers,
129
+ retryCount: msg.properties.headers?.["x-retry-count"] || 0,
130
+ originalChannel: this.name
131
+ };
132
+ const message = {
133
+ metadata,
134
+ payload,
135
+ raw: msg
136
+ };
137
+ await handler(message, {
138
+ ack: async () => {
139
+ if (!ackHandled) {
140
+ ackHandled = true;
141
+ this.amqpChannel.ack(msg);
142
+ }
143
+ },
144
+ nack: async (requeue = true) => {
145
+ if (!ackHandled) {
146
+ ackHandled = true;
147
+ this.amqpChannel.nack(msg, false, requeue);
148
+ }
149
+ },
150
+ reject: async () => {
151
+ if (!ackHandled) {
152
+ ackHandled = true;
153
+ this.amqpChannel.reject(msg, false);
154
+ }
155
+ },
156
+ reply: async (replyPayload) => {
157
+ if (msg.properties.replyTo) {
158
+ const replyContent = JSON.stringify({
159
+ payload: replyPayload,
160
+ metadata: {
161
+ messageId: randomUUID(),
162
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
163
+ correlationId: msg.properties.correlationId
164
+ }
165
+ });
166
+ this.amqpChannel.sendToQueue(msg.properties.replyTo, Buffer.from(replyContent), { correlationId: msg.properties.correlationId });
167
+ }
168
+ },
169
+ retry: async (delay) => {
170
+ if (ackHandled) return;
171
+ ackHandled = true;
172
+ const retryCount = (metadata.retryCount || 0) + 1;
173
+ if (retryCount > (options?.retry?.maxRetries ?? 3)) {
174
+ if (options?.deadLetter) await this.sendToDeadLetter(message, options.deadLetter.channel);
175
+ this.amqpChannel.ack(msg);
176
+ return;
177
+ }
178
+ const headers = {
179
+ ...msg.properties.headers,
180
+ "x-retry-count": retryCount
181
+ };
182
+ if (delay) headers["x-delay"] = delay;
183
+ this.amqpChannel.sendToQueue(this.name, msg.content, {
184
+ ...msg.properties,
185
+ headers
186
+ });
187
+ this.amqpChannel.ack(msg);
188
+ }
189
+ });
190
+ if (!ackHandled) this.amqpChannel.ack(msg);
191
+ } catch (error) {
192
+ if (ackHandled) return;
193
+ if (options?.retry) if ((msg.properties.headers?.["x-retry-count"] || 0) < options.retry.maxRetries) this.amqpChannel.nack(msg, false, true);
194
+ else if (options.deadLetter) this.amqpChannel.nack(msg, false, false);
195
+ else this.amqpChannel.reject(msg, false);
196
+ else this.amqpChannel.nack(msg, false, false);
197
+ }
198
+ }, consumerOptions);
199
+ const subscription = new RabbitMQSubscription(subscriptionId, this.name, consumerTag, this.amqpChannel);
200
+ this.subscriptions.set(subscriptionId, subscription);
201
+ return subscription;
202
+ }
203
+ /**
204
+ * Unsubscribe by consumer ID
205
+ */
206
+ async unsubscribeById(consumerId) {
207
+ const subscription = this.subscriptions.get(consumerId);
208
+ if (subscription) {
209
+ await subscription.unsubscribe();
210
+ this.subscriptions.delete(consumerId);
211
+ }
212
+ }
213
+ /**
214
+ * Stop consuming messages on this channel.
215
+ * Cancels all active subscriptions gracefully.
216
+ */
217
+ async stopConsuming() {
218
+ const cancellations = Array.from(this.subscriptions.values()).map((sub) => sub.unsubscribe());
219
+ await Promise.all(cancellations);
220
+ }
221
+ /**
222
+ * Send message to dead-letter queue
223
+ */
224
+ async sendToDeadLetter(message, deadLetterChannel) {
225
+ const content = JSON.stringify({
226
+ payload: message.payload,
227
+ metadata: {
228
+ ...message.metadata,
229
+ originalChannel: this.name
230
+ }
231
+ });
232
+ this.amqpChannel.sendToQueue(deadLetterChannel, Buffer.from(content), { persistent: true });
233
+ }
234
+ /**
235
+ * Request-response pattern
236
+ */
237
+ async request(payload, options) {
238
+ await this.assert();
239
+ const correlationId = randomUUID();
240
+ const timeout = options?.timeout ?? 3e4;
241
+ const { queue: replyQueue } = await this.amqpChannel.assertQueue("", {
242
+ exclusive: true,
243
+ autoDelete: true
244
+ });
245
+ return new Promise((resolve, reject) => {
246
+ const timeoutId = setTimeout(() => {
247
+ reject(/* @__PURE__ */ new Error(`Request timeout after ${timeout}ms`));
248
+ }, timeout);
249
+ this.amqpChannel.consume(replyQueue, (msg) => {
250
+ if (msg?.properties.correlationId === correlationId) {
251
+ clearTimeout(timeoutId);
252
+ resolve(JSON.parse(msg.content.toString()).payload);
253
+ }
254
+ }, { noAck: true });
255
+ const messageContent = JSON.stringify({
256
+ payload,
257
+ metadata: {
258
+ messageId: randomUUID(),
259
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
260
+ correlationId
261
+ }
262
+ });
263
+ this.amqpChannel.sendToQueue(this.name, Buffer.from(messageContent), {
264
+ correlationId,
265
+ replyTo: replyQueue,
266
+ expiration: timeout.toString(),
267
+ ...options
268
+ });
269
+ });
270
+ }
271
+ /**
272
+ * Register response handler for RPC
273
+ */
274
+ async respond(handler) {
275
+ return this.subscribe(async (message, ctx) => {
276
+ const response = await handler(message, ctx);
277
+ await ctx.reply(response);
278
+ await ctx.ack();
279
+ });
280
+ }
281
+ /**
282
+ * Get queue statistics
283
+ */
284
+ async stats() {
285
+ await this.assert();
286
+ const queueInfo = await this.amqpChannel.checkQueue(this.name);
287
+ return {
288
+ name: this.name,
289
+ messageCount: queueInfo.messageCount,
290
+ consumerCount: queueInfo.consumerCount
291
+ };
292
+ }
293
+ /**
294
+ * Purge all messages
295
+ */
296
+ async purge() {
297
+ await this.assert();
298
+ return (await this.amqpChannel.purgeQueue(this.name)).messageCount;
299
+ }
300
+ /**
301
+ * Check if queue exists
302
+ */
303
+ async exists() {
304
+ try {
305
+ await this.amqpChannel.checkQueue(this.name);
306
+ return true;
307
+ } catch {
308
+ return false;
309
+ }
310
+ }
311
+ /**
312
+ * Delete the queue
313
+ */
314
+ async delete() {
315
+ for (const subscription of this.subscriptions.values()) await subscription.unsubscribe();
316
+ this.subscriptions.clear();
317
+ try {
318
+ await this.amqpChannel.deleteQueue(this.name);
319
+ } catch {}
320
+ this.asserted = false;
321
+ }
322
+ };
323
+ /**
324
+ * RabbitMQ Subscription Implementation
325
+ */
326
+ var RabbitMQSubscription = class {
327
+ constructor(id, channel, consumerTag, amqpChannel) {
328
+ this._isActive = true;
329
+ this.id = id;
330
+ this.channel = channel;
331
+ this.consumerTag = consumerTag;
332
+ this.amqpChannel = amqpChannel;
333
+ }
334
+ async unsubscribe() {
335
+ if (!this._isActive) return;
336
+ await this.amqpChannel.cancel(this.consumerTag);
337
+ this._isActive = false;
338
+ }
339
+ async pause() {
340
+ await this.amqpChannel.cancel(this.consumerTag);
341
+ }
342
+ async resume() {
343
+ throw new Error("Resume is not supported for RabbitMQ. Please create a new subscription.");
344
+ }
345
+ isActive() {
346
+ return this._isActive;
347
+ }
348
+ };
349
+
350
+ //#endregion
351
+ export { RabbitMQChannel };
352
+ //# sourceMappingURL=rabbitmq-channel.mjs.map
@@ -0,0 +1 @@
1
+ {"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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"}
@@ -0,0 +1,130 @@
1
+ import { ChannelOptions } from "../../types/channel.types.mjs";
2
+ import { RabbitMQConnectionOptions } from "../../types/connection.types.mjs";
3
+ import { BrokerEvent, BrokerEventListener, HealthCheckResult } from "../../types/driver.types.mjs";
4
+ import { ChannelContract } from "../../contracts/channel.contract.mjs";
5
+ import { EventMessage } from "../../message-managers/event-message.mjs";
6
+ import { EventConsumerClass } from "../../message-managers/types.mjs";
7
+ import { BrokerDriverContract } from "../../contracts/broker-driver.contract.mjs";
8
+ //#region ../../@warlock.js/herald/src/drivers/rabbitmq/rabbitmq-driver.d.ts
9
+ /**
10
+ * RabbitMQ Driver
11
+ *
12
+ * Implementation of BrokerDriverContract for RabbitMQ/AMQP.
13
+ *
14
+ * **Important:** This driver requires the `amqplib` package to be installed.
15
+ * Install it with: `npx warlock add herald --driver=rabbitmq` or `npm install amqplib`
16
+ *
17
+ * @example
18
+ * ```typescript
19
+ * const driver = new RabbitMQDriver({
20
+ * driver: "rabbitmq",
21
+ * host: "localhost",
22
+ * port: 5672,
23
+ * username: "guest",
24
+ * password: "guest",
25
+ * });
26
+ *
27
+ * await driver.connect();
28
+ * const channel = driver.channel("user.created");
29
+ * ```
30
+ */
31
+ declare class RabbitMQDriver implements BrokerDriverContract {
32
+ readonly name: "rabbitmq";
33
+ readonly consumers: EventConsumerClass[];
34
+ private readonly options;
35
+ private readonly events;
36
+ private readonly channels;
37
+ private connection;
38
+ private amqpChannel;
39
+ private _isConnected;
40
+ /**
41
+ * Create a new RabbitMQ driver
42
+ *
43
+ * @param options - RabbitMQ connection options
44
+ */
45
+ constructor(options: RabbitMQConnectionOptions);
46
+ /**
47
+ * Whether connected to RabbitMQ
48
+ */
49
+ get isConnected(): boolean;
50
+ /**
51
+ * Subscribe the given consumer class to the driver
52
+ *
53
+ * @param consumer - Consumer class to subscribe
54
+ *
55
+ * @example
56
+ * ```typescript
57
+ * driver.subscribe(UserUpdatedConsumer);
58
+ * ```
59
+ */
60
+ subscribe(Consumer: EventConsumerClass): () => void;
61
+ /**
62
+ * Unsubscribe the given consumer
63
+ */
64
+ unsubscribe(Consumer: EventConsumerClass): void;
65
+ /**
66
+ * Publish the given event message.
67
+ * Auto-creates the channel if it hasn't been accessed before.
68
+ */
69
+ publish<TPayload = Record<string, any>>(event: EventMessage<TPayload>): void;
70
+ /**
71
+ * Connect to RabbitMQ
72
+ */
73
+ connect(): Promise<void>;
74
+ /**
75
+ * Build connection URL from options
76
+ */
77
+ private buildConnectionUrl;
78
+ /**
79
+ * Handle reconnection
80
+ */
81
+ private handleReconnect;
82
+ /**
83
+ * Disconnect from RabbitMQ
84
+ */
85
+ disconnect(): Promise<void>;
86
+ /**
87
+ * Register event listener
88
+ */
89
+ on(event: BrokerEvent, listener: BrokerEventListener): void;
90
+ /**
91
+ * Remove event listener
92
+ */
93
+ off(event: BrokerEvent, listener: BrokerEventListener): void;
94
+ /**
95
+ * Get or create a channel
96
+ */
97
+ channel<TPayload = unknown>(name: string, options?: ChannelOptions<TPayload>): ChannelContract<TPayload>;
98
+ /**
99
+ * Start consuming messages
100
+ */
101
+ startConsuming(): Promise<void>;
102
+ /**
103
+ * Stop consuming messages from all subscribed channels.
104
+ * Gracefully cancels all active consumers.
105
+ */
106
+ stopConsuming(): Promise<void>;
107
+ /**
108
+ * Health check
109
+ */
110
+ healthCheck(): Promise<HealthCheckResult>;
111
+ /**
112
+ * Get all channel names
113
+ */
114
+ getChannelNames(): string[];
115
+ /**
116
+ * Close a specific channel
117
+ */
118
+ closeChannel(name: string): Promise<void>;
119
+ /**
120
+ * Get the raw AMQP channel (for advanced use)
121
+ */
122
+ getRawChannel(): any;
123
+ /**
124
+ * Get the raw connection (for advanced use)
125
+ */
126
+ getRawConnection(): any;
127
+ }
128
+ //#endregion
129
+ export { RabbitMQDriver };
130
+ //# sourceMappingURL=rabbitmq-driver.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rabbitmq-driver.d.mts","names":[],"sources":["../../../../../../../@warlock.js/herald/src/drivers/rabbitmq/rabbitmq-driver.ts"],"mappings":";;;;;;;;;;;;;;;AAsFA;;;;;;;;;;;;;;;cAAa,cAAA,YAA0B,oBAAA;EAAA,SACrB,IAAA;EAAA,SAEA,SAAA,EAAW,kBAAA;EAAA,iBAEV,OAAA;EAAA,iBACA,MAAA;EAAA,iBACA,QAAA;EAAA,QAET,UAAA;EAAA,QACA,WAAA;EAAA,QACA,YAAA;EA6SiC;;;;;cAtStB,OAAA,EAAS,yBAAA;EAfZ;;;EAAA,IAsBL,WAAA,CAAA;EAlBM;;;;;;;;;;EAgCV,SAAA,CAAU,QAAA,EAAU,kBAAA;EAsBpB;;;EAAA,WAAA,CAAY,QAAA,EAAU,kBAAA;EAcd;;;;EAAR,OAAA,YAAmB,MAAA,cAAA,CAAqB,KAAA,EAAO,YAAA,CAAa,QAAA;EAOtD;;;EAAA,OAAA,CAAA,GAAW,OAAA;EAgHX;;;EAAA,QAzCL,kBAAA;EAmEE;;;EAAA,QA/CI,eAAA;EAsDI;;;EAjCL,UAAA,CAAA,GAAc,OAAA;EAwCpB;;;EAdA,EAAA,CAAG,KAAA,EAAO,WAAA,EAAa,QAAA,EAAU,mBAAA;EAgBb;;;EATpB,GAAA,CAAI,KAAA,EAAO,WAAA,EAAa,QAAA,EAAU,mBAAA;EA2B5B;;;EApBN,OAAA,oBAAA,CACL,IAAA,UACA,OAAA,GAAU,cAAA,CAAe,QAAA,IACxB,eAAA,CAAgB,QAAA;EAoCN;;;EAnBA,cAAA,CAAA,GAAkB,OAAA;EA0DlB;;;;EAjDA,aAAA,CAAA,GAAiB,OAAA;EAmEP;AAAA;;EAzDV,WAAA,CAAA,GAAe,OAAA,CAAQ,iBAAA;;;;EAgC7B,eAAA,CAAA;;;;EAOM,YAAA,CAAa,IAAA,WAAe,OAAA;;;;EAWlC,aAAA,CAAA;;;;EAOA,gBAAA,CAAA;AAAA"}