@amqp-contract/contract 0.17.0 → 0.19.0

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.
package/dist/index.mjs CHANGED
@@ -65,10 +65,9 @@ function defineMessage(payload, options) {
65
65
  }
66
66
 
67
67
  //#endregion
68
- //#region src/builder/binding.ts
68
+ //#region src/builder/queue-utils.ts
69
69
  /**
70
70
  * Type guard to check if a queue entry is a QueueWithTtlBackoffInfrastructure.
71
- * Duplicated here to avoid circular dependency with queue.ts.
72
71
  * @internal
73
72
  */
74
73
  function isQueueWithTtlBackoffInfrastructure$1(entry) {
@@ -76,13 +75,15 @@ function isQueueWithTtlBackoffInfrastructure$1(entry) {
76
75
  }
77
76
  /**
78
77
  * Extract the plain QueueDefinition from a QueueEntry.
79
- * Duplicated here to avoid circular dependency with queue.ts.
80
78
  * @internal
81
79
  */
82
- function extractQueueInternal(entry) {
80
+ function extractQueueFromEntry(entry) {
83
81
  if (isQueueWithTtlBackoffInfrastructure$1(entry)) return entry.queue;
84
82
  return entry;
85
83
  }
84
+
85
+ //#endregion
86
+ //#region src/builder/binding.ts
86
87
  /**
87
88
  * Define a binding between a queue and an exchange.
88
89
  *
@@ -95,7 +96,7 @@ function extractQueueInternal(entry) {
95
96
  * @internal
96
97
  */
97
98
  function defineQueueBinding(queue, exchange, options) {
98
- const queueDef = extractQueueInternal(queue);
99
+ const queueDef = extractQueueFromEntry(queue);
99
100
  if (exchange.type === "fanout") return {
100
101
  type: "queue",
101
102
  queue: queueDef,
@@ -196,7 +197,7 @@ function resolveTtlBackoffOptions(options) {
196
197
  * ```
197
198
  */
198
199
  function isQueueWithTtlBackoffInfrastructure(entry) {
199
- return typeof entry === "object" && entry !== null && "__brand" in entry && entry.__brand === "QueueWithTtlBackoffInfrastructure";
200
+ return isQueueWithTtlBackoffInfrastructure$1(entry);
200
201
  }
201
202
  /**
202
203
  * Extract the plain QueueDefinition from a QueueEntry.
@@ -247,14 +248,13 @@ function isQueueWithTtlBackoffInfrastructure(entry) {
247
248
  * @see defineTtlBackoffQueue - Creates queues with TTL-backoff infrastructure
248
249
  */
249
250
  function extractQueue(entry) {
250
- if (isQueueWithTtlBackoffInfrastructure(entry)) return entry.queue;
251
- return entry;
251
+ return extractQueueFromEntry(entry);
252
252
  }
253
253
  /**
254
- * Wrap a queue definition with TTL-backoff retry infrastructure.
254
+ * Create TTL-backoff retry infrastructure (wait queue + bindings) for a queue.
255
255
  * @internal
256
256
  */
257
- function wrapWithTtlBackoffInfrastructure(queue) {
257
+ function createTtlBackoffInfrastructure(queue) {
258
258
  if (!queue.deadLetter) throw new Error(`Queue "${queue.name}" does not have a dead letter exchange configured. TTL-backoff retry requires deadLetter to be set on the queue.`);
259
259
  const dlx = queue.deadLetter.exchange;
260
260
  const waitQueueName = `${queue.name}-wait`;
@@ -268,15 +268,23 @@ function wrapWithTtlBackoffInfrastructure(queue) {
268
268
  },
269
269
  retry: resolveTtlBackoffOptions(void 0)
270
270
  };
271
- const waitQueueBinding = defineQueueBindingInternal(waitQueue, dlx, { routingKey: waitQueueName });
272
- const mainQueueRetryBinding = defineQueueBindingInternal(queue, dlx, { routingKey: queue.name });
271
+ return {
272
+ waitQueue,
273
+ waitQueueBinding: defineQueueBindingInternal(waitQueue, dlx, { routingKey: waitQueueName }),
274
+ mainQueueRetryBinding: defineQueueBindingInternal(queue, dlx, { routingKey: queue.name })
275
+ };
276
+ }
277
+ /**
278
+ * Wrap a queue definition with TTL-backoff retry infrastructure.
279
+ * @internal
280
+ */
281
+ function wrapWithTtlBackoffInfrastructure(queue) {
282
+ const infra = createTtlBackoffInfrastructure(queue);
273
283
  return {
274
284
  __brand: "QueueWithTtlBackoffInfrastructure",
275
285
  queue,
276
286
  deadLetter: queue.deadLetter,
277
- waitQueue,
278
- waitQueueBinding,
279
- mainQueueRetryBinding
287
+ ...infra
280
288
  };
281
289
  }
282
290
  function defineQueue(name, options) {
@@ -608,21 +616,41 @@ function defineEventPublisher(exchange, message, options) {
608
616
  * @internal
609
617
  */
610
618
  function defineEventConsumer(eventPublisher, queue, options) {
611
- const { exchange, message, routingKey: publisherRoutingKey } = eventPublisher;
619
+ const { exchange: sourceExchange, message, routingKey: publisherRoutingKey } = eventPublisher;
612
620
  const bindingRoutingKey = options?.routingKey ?? publisherRoutingKey;
613
621
  const bindingOptions = {};
614
622
  if (bindingRoutingKey !== void 0) bindingOptions.routingKey = bindingRoutingKey;
615
623
  const bindingArguments = options?.arguments ?? eventPublisher.arguments;
616
624
  if (bindingArguments !== void 0) bindingOptions.arguments = bindingArguments;
617
- const binding = defineQueueBindingInternal(queue, exchange, bindingOptions);
625
+ const bridgeExchange = options?.bridgeExchange;
626
+ if (bridgeExchange) {
627
+ const binding = defineQueueBindingInternal(queue, bridgeExchange, bindingOptions);
628
+ const consumer = defineConsumer(queue, message);
629
+ const exchangeBindingOptions = {};
630
+ if (bindingRoutingKey !== void 0) exchangeBindingOptions.routingKey = bindingRoutingKey;
631
+ const e2eBinding = sourceExchange.type === "fanout" ? defineExchangeBinding(bridgeExchange, sourceExchange) : defineExchangeBinding(bridgeExchange, sourceExchange, exchangeBindingOptions);
632
+ return {
633
+ __brand: "EventConsumerResult",
634
+ consumer,
635
+ binding,
636
+ exchange: sourceExchange,
637
+ queue: consumer.queue,
638
+ deadLetterExchange: consumer.queue.deadLetter?.exchange,
639
+ exchangeBinding: e2eBinding,
640
+ bridgeExchange
641
+ };
642
+ }
643
+ const binding = defineQueueBindingInternal(queue, sourceExchange, bindingOptions);
618
644
  const consumer = defineConsumer(queue, message);
619
645
  return {
620
646
  __brand: "EventConsumerResult",
621
647
  consumer,
622
648
  binding,
623
- exchange,
649
+ exchange: sourceExchange,
624
650
  queue: consumer.queue,
625
- deadLetterExchange: consumer.queue.deadLetter?.exchange
651
+ deadLetterExchange: consumer.queue.deadLetter?.exchange,
652
+ exchangeBinding: void 0,
653
+ bridgeExchange: void 0
626
654
  };
627
655
  }
628
656
  /**
@@ -668,11 +696,26 @@ function defineCommandConsumer(queue, exchange, message, options) {
668
696
  * @internal
669
697
  */
670
698
  function defineCommandPublisher(commandConsumer, options) {
671
- const { exchange, message, routingKey: consumerRoutingKey } = commandConsumer;
699
+ const { exchange: targetExchange, message, routingKey: consumerRoutingKey } = commandConsumer;
672
700
  const publisherRoutingKey = options?.routingKey ?? consumerRoutingKey;
701
+ const bridgeExchange = options?.bridgeExchange;
702
+ if (bridgeExchange) {
703
+ const publisherOptions = {};
704
+ if (publisherRoutingKey !== void 0) publisherOptions.routingKey = publisherRoutingKey;
705
+ const publisher = definePublisherInternal(bridgeExchange, message, publisherOptions);
706
+ const e2eBindingOptions = {};
707
+ if (publisherRoutingKey !== void 0) e2eBindingOptions.routingKey = publisherRoutingKey;
708
+ return {
709
+ __brand: "BridgedPublisherConfig",
710
+ publisher,
711
+ exchangeBinding: bridgeExchange.type === "fanout" ? defineExchangeBinding(targetExchange, bridgeExchange) : defineExchangeBinding(targetExchange, bridgeExchange, e2eBindingOptions),
712
+ bridgeExchange,
713
+ targetExchange
714
+ };
715
+ }
673
716
  const publisherOptions = {};
674
717
  if (publisherRoutingKey !== void 0) publisherOptions.routingKey = publisherRoutingKey;
675
- return definePublisherInternal(exchange, message, publisherOptions);
718
+ return definePublisherInternal(targetExchange, message, publisherOptions);
676
719
  }
677
720
  /**
678
721
  * Type guard to check if a value is a CommandConsumerConfig.
@@ -683,6 +726,15 @@ function defineCommandPublisher(commandConsumer, options) {
683
726
  function isCommandConsumerConfig(value) {
684
727
  return typeof value === "object" && value !== null && "__brand" in value && value.__brand === "CommandConsumerConfig";
685
728
  }
729
+ /**
730
+ * Type guard to check if a value is a BridgedPublisherConfig.
731
+ *
732
+ * @param value - The value to check
733
+ * @returns True if the value is a BridgedPublisherConfig
734
+ */
735
+ function isBridgedPublisherConfig(value) {
736
+ return typeof value === "object" && value !== null && "__brand" in value && value.__brand === "BridgedPublisherConfig";
737
+ }
686
738
 
687
739
  //#endregion
688
740
  //#region src/builder/contract.ts
@@ -764,7 +816,13 @@ function defineContract(definition) {
764
816
  if (inputPublishers && Object.keys(inputPublishers).length > 0) {
765
817
  const processedPublishers = {};
766
818
  const exchanges = {};
767
- for (const [name, entry] of Object.entries(inputPublishers)) if (isEventPublisherConfig(entry)) {
819
+ const publisherBindings = {};
820
+ for (const [name, entry] of Object.entries(inputPublishers)) if (isBridgedPublisherConfig(entry)) {
821
+ exchanges[entry.bridgeExchange.name] = entry.bridgeExchange;
822
+ exchanges[entry.targetExchange.name] = entry.targetExchange;
823
+ publisherBindings[`${name}ExchangeBinding`] = entry.exchangeBinding;
824
+ processedPublishers[name] = entry.publisher;
825
+ } else if (isEventPublisherConfig(entry)) {
768
826
  exchanges[entry.exchange.name] = entry.exchange;
769
827
  const publisherOptions = {};
770
828
  if (entry.routingKey !== void 0) publisherOptions.routingKey = entry.routingKey;
@@ -779,6 +837,10 @@ function defineContract(definition) {
779
837
  ...result.exchanges,
780
838
  ...exchanges
781
839
  };
840
+ result.bindings = {
841
+ ...result.bindings,
842
+ ...publisherBindings
843
+ };
782
844
  }
783
845
  if (inputConsumers && Object.keys(inputConsumers).length > 0) {
784
846
  const processedConsumers = {};
@@ -792,6 +854,9 @@ function defineContract(definition) {
792
854
  queues[queueEntry.name] = queueEntry;
793
855
  exchanges[entry.binding.exchange.name] = entry.binding.exchange;
794
856
  if (queueEntry.deadLetter?.exchange) exchanges[queueEntry.deadLetter.exchange.name] = queueEntry.deadLetter.exchange;
857
+ if (entry.exchangeBinding) consumerBindings[`${name}ExchangeBinding`] = entry.exchangeBinding;
858
+ if (entry.bridgeExchange) exchanges[entry.bridgeExchange.name] = entry.bridgeExchange;
859
+ if (entry.exchange) exchanges[entry.exchange.name] = entry.exchange;
795
860
  } else if (isCommandConsumerConfig(entry)) {
796
861
  processedConsumers[name] = entry.consumer;
797
862
  consumerBindings[`${name}Binding`] = entry.binding;
@@ -807,22 +872,11 @@ function defineContract(definition) {
807
872
  if (queueEntry.deadLetter?.exchange) exchanges[queueEntry.deadLetter.exchange.name] = queueEntry.deadLetter.exchange;
808
873
  }
809
874
  for (const queue of Object.values(queues)) if (queue.retry?.mode === "ttl-backoff" && queue.deadLetter) {
810
- const dlx = queue.deadLetter.exchange;
811
- const waitQueueName = `${queue.name}-wait`;
812
- const waitQueue = {
813
- name: waitQueueName,
814
- type: "quorum",
815
- durable: queue.durable ?? true,
816
- deadLetter: {
817
- exchange: dlx,
818
- routingKey: queue.name
819
- },
820
- retry: resolveTtlBackoffOptions(void 0)
821
- };
822
- queues[waitQueueName] = waitQueue;
823
- consumerBindings[`${queue.name}WaitBinding`] = defineQueueBindingInternal(waitQueue, dlx, { routingKey: waitQueueName });
824
- consumerBindings[`${queue.name}RetryBinding`] = defineQueueBindingInternal(queue, dlx, { routingKey: queue.name });
825
- exchanges[dlx.name] = dlx;
875
+ const infra = createTtlBackoffInfrastructure(queue);
876
+ queues[infra.waitQueue.name] = infra.waitQueue;
877
+ consumerBindings[`${queue.name}WaitBinding`] = infra.waitQueueBinding;
878
+ consumerBindings[`${queue.name}RetryBinding`] = infra.mainQueueRetryBinding;
879
+ exchanges[queue.deadLetter.exchange.name] = queue.deadLetter.exchange;
826
880
  }
827
881
  result.consumers = processedConsumers;
828
882
  result.bindings = {
@@ -886,25 +940,11 @@ function defineContract(definition) {
886
940
  * ```
887
941
  */
888
942
  function defineTtlBackoffRetryInfrastructure(queueEntry, options) {
889
- const queue = extractQueue(queueEntry);
890
- if (!queue.deadLetter) throw new Error(`Queue "${queue.name}" does not have a dead letter exchange configured. TTL-backoff retry requires deadLetter to be set on the queue.`);
891
- const dlx = queue.deadLetter.exchange;
892
- const waitQueueName = `${queue.name}-wait`;
893
- const waitQueue = defineQueue(waitQueueName, {
894
- type: "quorum",
895
- durable: options?.waitQueueDurable ?? queue.durable ?? true,
896
- deadLetter: {
897
- exchange: dlx,
898
- routingKey: queue.name
899
- }
900
- });
901
- return {
902
- waitQueue,
903
- waitQueueBinding: defineQueueBindingInternal(waitQueue, dlx, { routingKey: waitQueueName }),
904
- mainQueueRetryBinding: defineQueueBindingInternal(queue, dlx, { routingKey: queue.name })
905
- };
943
+ const infra = createTtlBackoffInfrastructure(extractQueue(queueEntry));
944
+ if (options?.waitQueueDurable !== void 0) infra.waitQueue.durable = options.waitQueueDurable;
945
+ return infra;
906
946
  }
907
947
 
908
948
  //#endregion
909
- export { defineCommandConsumer, defineCommandPublisher, defineConsumer, defineContract, defineEventConsumer, defineEventPublisher, defineExchange, defineExchangeBinding, defineMessage, definePublisher, defineQueue, defineQueueBinding, defineQuorumQueue, defineTtlBackoffQueue, defineTtlBackoffRetryInfrastructure, extractConsumer, extractQueue, isCommandConsumerConfig, isEventConsumerResult, isEventPublisherConfig, isQueueWithTtlBackoffInfrastructure };
949
+ export { defineCommandConsumer, defineCommandPublisher, defineConsumer, defineContract, defineEventConsumer, defineEventPublisher, defineExchange, defineExchangeBinding, defineMessage, definePublisher, defineQueue, defineQueueBinding, defineQuorumQueue, defineTtlBackoffQueue, defineTtlBackoffRetryInfrastructure, extractConsumer, extractQueue, isBridgedPublisherConfig, isCommandConsumerConfig, isEventConsumerResult, isEventPublisherConfig, isQueueWithTtlBackoffInfrastructure };
910
950
  //# sourceMappingURL=index.mjs.map