@amqp-contract/contract 0.12.0 → 0.13.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/README.md CHANGED
@@ -18,21 +18,30 @@ pnpm add @amqp-contract/contract
18
18
 
19
19
  ## Quick Start
20
20
 
21
- ### Recommended: Publisher-First / Consumer-First Patterns
21
+ ### Recommended: Event / Command Patterns
22
22
 
23
- For robust contract definitions with guaranteed consistency, use `definePublisherFirst` (for events) or `defineConsumerFirst` (for commands):
23
+ For robust contract definitions with guaranteed consistency, use Event or Command patterns:
24
+
25
+ | Pattern | Use Case | Flow |
26
+ | ----------- | ------------------------------------------ | -------------------------------------------------- |
27
+ | **Event** | One publisher, many consumers (broadcast) | `defineEventPublisher` → `defineEventConsumer` |
28
+ | **Command** | Many publishers, one consumer (task queue) | `defineCommandConsumer` → `defineCommandPublisher` |
24
29
 
25
30
  ```typescript
26
31
  import {
27
- definePublisherFirst,
32
+ defineEventPublisher,
33
+ defineEventConsumer,
34
+ defineCommandConsumer,
35
+ defineCommandPublisher,
28
36
  defineContract,
29
37
  defineExchange,
30
38
  defineQueue,
39
+ definePublisher,
31
40
  defineMessage,
32
41
  } from "@amqp-contract/contract";
33
42
  import { z } from "zod";
34
43
 
35
- // Event-oriented pattern: publisher doesn't need to know about queues
44
+ // Event pattern: publisher broadcasts, consumers subscribe
36
45
  const ordersExchange = defineExchange("orders", "topic", { durable: true });
37
46
  const orderMessage = defineMessage(
38
47
  z.object({
@@ -41,25 +50,30 @@ const orderMessage = defineMessage(
41
50
  }),
42
51
  );
43
52
 
44
- const { publisher: orderCreatedPublisher, createConsumer: createOrderCreatedConsumer } =
45
- definePublisherFirst(ordersExchange, orderMessage, { routingKey: "order.created" });
53
+ // Define event publisher
54
+ const orderCreatedEvent = defineEventPublisher(ordersExchange, orderMessage, {
55
+ routingKey: "order.created",
56
+ });
46
57
 
47
58
  // Multiple queues can consume the same event
48
59
  const orderQueue = defineQueue("order-processing", { durable: true });
49
- const { consumer, binding } = createOrderCreatedConsumer(orderQueue);
60
+ const { consumer, binding } = defineEventConsumer(orderCreatedEvent, orderQueue);
50
61
 
51
62
  // For topic exchanges, consumers can override with their own pattern
52
63
  const analyticsQueue = defineQueue("analytics", { durable: true });
53
- const { consumer: analyticsConsumer, binding: analyticsBinding } = createOrderCreatedConsumer(
64
+ const { consumer: analyticsConsumer, binding: analyticsBinding } = defineEventConsumer(
65
+ orderCreatedEvent,
54
66
  analyticsQueue,
55
- "order.*",
56
- ); // Subscribe to all order events
67
+ { routingKey: "order.*" }, // Subscribe to all order events
68
+ );
57
69
 
58
70
  const contract = defineContract({
59
71
  exchanges: { orders: ordersExchange },
60
72
  queues: { orderQueue, analyticsQueue },
61
73
  bindings: { orderBinding: binding, analyticsBinding },
62
- publishers: { orderCreated: orderCreatedPublisher },
74
+ publishers: {
75
+ orderCreated: definePublisher(ordersExchange, orderMessage, { routingKey: "order.created" }),
76
+ },
63
77
  consumers: {
64
78
  processOrder: consumer,
65
79
  trackOrders: analyticsConsumer,
@@ -72,7 +86,7 @@ const contract = defineContract({
72
86
  - ✅ Guaranteed message schema consistency between publishers and consumers
73
87
  - ✅ Routing key validation and type safety
74
88
  - ✅ Full type safety with TypeScript inference
75
- - ✅ Event-oriented (publisher-first) and command-oriented (consumer-first) patterns
89
+ - ✅ Event-oriented and command-oriented patterns
76
90
  - ✅ Flexible routing key patterns for topic exchanges
77
91
 
78
92
  ## Documentation
@@ -80,8 +94,8 @@ const contract = defineContract({
80
94
  📖 **[Read the full documentation →](https://btravers.github.io/amqp-contract)**
81
95
 
82
96
  - [Getting Started Guide](https://btravers.github.io/amqp-contract/guide/defining-contracts)
83
- - [Publisher-First Pattern](https://btravers.github.io/amqp-contract/guide/defining-contracts#publisher-first-pattern)
84
- - [Consumer-First Pattern](https://btravers.github.io/amqp-contract/guide/defining-contracts#consumer-first-pattern)
97
+ - [Event Pattern](https://btravers.github.io/amqp-contract/guide/defining-contracts#event-pattern)
98
+ - [Command Pattern](https://btravers.github.io/amqp-contract/guide/defining-contracts#command-pattern)
85
99
  - [Complete API Reference](https://btravers.github.io/amqp-contract/api/contract)
86
100
 
87
101
  ## License
package/dist/index.cjs CHANGED
@@ -165,24 +165,87 @@ function resolveTtlBackoffOptions(options) {
165
165
  }
166
166
  /**
167
167
  * Type guard to check if a queue entry is a QueueWithTtlBackoffInfrastructure.
168
- * @internal
168
+ *
169
+ * When you configure a queue with TTL-backoff retry and a dead letter exchange,
170
+ * `defineQueue` returns a `QueueWithTtlBackoffInfrastructure` instead of a plain
171
+ * `QueueDefinition`. This type guard helps you distinguish between the two.
172
+ *
173
+ * **When to use:**
174
+ * - When you need to check the type of a queue entry at runtime
175
+ * - When writing generic code that handles both plain queues and infrastructure wrappers
176
+ *
177
+ * **Related functions:**
178
+ * - `extractQueue()` - Use this to get the underlying queue definition from either type
179
+ *
180
+ * @param entry - The queue entry to check
181
+ * @returns True if the entry is a QueueWithTtlBackoffInfrastructure, false otherwise
182
+ *
183
+ * @example
184
+ * ```typescript
185
+ * const queue = defineQueue('orders', {
186
+ * deadLetter: { exchange: dlx },
187
+ * retry: { mode: 'ttl-backoff' },
188
+ * });
189
+ *
190
+ * if (isQueueWithTtlBackoffInfrastructure(queue)) {
191
+ * // queue has .queue, .waitQueue, .waitQueueBinding, .mainQueueRetryBinding
192
+ * console.log('Wait queue:', queue.waitQueue.name);
193
+ * } else {
194
+ * // queue is a plain QueueDefinition
195
+ * console.log('Queue:', queue.name);
196
+ * }
197
+ * ```
169
198
  */
170
199
  function isQueueWithTtlBackoffInfrastructure(entry) {
171
200
  return typeof entry === "object" && entry !== null && "__brand" in entry && entry.__brand === "QueueWithTtlBackoffInfrastructure";
172
201
  }
173
202
  /**
174
203
  * Extract the plain QueueDefinition from a QueueEntry.
175
- * If the entry is a QueueWithTtlBackoffInfrastructure, returns the inner queue.
176
- * Otherwise, returns the entry as-is.
204
+ *
205
+ * **Why this function exists:**
206
+ * When you configure a queue with TTL-backoff retry and a dead letter exchange,
207
+ * `defineQueue` (or `defineTtlBackoffQueue`) returns a wrapper object that includes
208
+ * the main queue, wait queue, and bindings. This function extracts the underlying
209
+ * queue definition so you can access properties like `name`, `type`, etc.
210
+ *
211
+ * **When to use:**
212
+ * - When you need to access queue properties (name, type, deadLetter, etc.)
213
+ * - When passing a queue to functions that expect a plain QueueDefinition
214
+ * - Works safely on both plain queues and infrastructure wrappers
215
+ *
216
+ * **How it works:**
217
+ * - If the entry is a `QueueWithTtlBackoffInfrastructure`, returns `entry.queue`
218
+ * - Otherwise, returns the entry as-is (it's already a plain QueueDefinition)
177
219
  *
178
220
  * @param entry - The queue entry (either plain QueueDefinition or QueueWithTtlBackoffInfrastructure)
179
221
  * @returns The plain QueueDefinition
180
222
  *
181
223
  * @example
182
224
  * ```typescript
183
- * const queue = defineQueue('orders', { retry: { mode: 'ttl-backoff' }, deadLetter: { exchange: dlx } });
184
- * const plainQueue = extractQueue(queue); // Returns the inner QueueDefinition
225
+ * import { defineQueue, defineTtlBackoffQueue, extractQueue } from '@amqp-contract/contract';
226
+ *
227
+ * // TTL-backoff queue returns a wrapper
228
+ * const orderQueue = defineTtlBackoffQueue('orders', {
229
+ * deadLetterExchange: dlx,
230
+ * maxRetries: 3,
231
+ * });
232
+ *
233
+ * // Use extractQueue to access the queue name
234
+ * const queueName = extractQueue(orderQueue).name; // 'orders'
235
+ *
236
+ * // Also works safely on plain queues
237
+ * const plainQueue = defineQueue('simple', { type: 'quorum', retry: { mode: 'quorum-native' } });
238
+ * const plainName = extractQueue(plainQueue).name; // 'simple'
239
+ *
240
+ * // Access other properties
241
+ * const queueDef = extractQueue(orderQueue);
242
+ * console.log(queueDef.name); // 'orders'
243
+ * console.log(queueDef.type); // 'quorum'
244
+ * console.log(queueDef.deadLetter); // { exchange: dlx, ... }
185
245
  * ```
246
+ *
247
+ * @see isQueueWithTtlBackoffInfrastructure - Type guard to check if extraction is needed
248
+ * @see defineTtlBackoffQueue - Creates queues with TTL-backoff infrastructure
186
249
  */
187
250
  function extractQueue(entry) {
188
251
  if (isQueueWithTtlBackoffInfrastructure(entry)) return entry.queue;
@@ -322,6 +385,126 @@ function defineQueue(name, options) {
322
385
  if (retry.mode === "ttl-backoff" && queueDefinition.deadLetter) return wrapWithTtlBackoffInfrastructure(queueDefinition);
323
386
  return queueDefinition;
324
387
  }
388
+ /**
389
+ * Create a quorum queue with quorum-native retry.
390
+ *
391
+ * This is a simplified helper that enforces best practices:
392
+ * - Uses quorum queues (recommended for most use cases)
393
+ * - Requires dead letter exchange for failed message handling
394
+ * - Uses quorum-native retry mode (simpler than TTL-backoff)
395
+ *
396
+ * **When to use:**
397
+ * - You want simple, immediate retries without exponential backoff
398
+ * - You don't need configurable delays between retries
399
+ * - You want the simplest retry configuration
400
+ *
401
+ * @param name - The queue name
402
+ * @param options - Configuration options
403
+ * @returns A quorum queue definition with quorum-native retry
404
+ *
405
+ * @example
406
+ * ```typescript
407
+ * const dlx = defineExchange('orders-dlx', 'direct', { durable: true });
408
+ *
409
+ * const orderQueue = defineQuorumQueue('order-processing', {
410
+ * deadLetterExchange: dlx,
411
+ * deliveryLimit: 3, // Retry up to 3 times
412
+ * });
413
+ *
414
+ * const contract = defineContract({
415
+ * exchanges: { dlx },
416
+ * queues: { orderProcessing: orderQueue },
417
+ * // ...
418
+ * });
419
+ * ```
420
+ *
421
+ * @see defineQueue - For full queue configuration options
422
+ * @see defineTtlBackoffQueue - For queues with exponential backoff retry
423
+ */
424
+ function defineQuorumQueue(name, options) {
425
+ const { deadLetterExchange, deadLetterRoutingKey, deliveryLimit, autoDelete, arguments: args } = options;
426
+ const queueOptions = {
427
+ type: "quorum",
428
+ deadLetter: deadLetterRoutingKey ? {
429
+ exchange: deadLetterExchange,
430
+ routingKey: deadLetterRoutingKey
431
+ } : { exchange: deadLetterExchange },
432
+ deliveryLimit,
433
+ retry: { mode: "quorum-native" }
434
+ };
435
+ if (autoDelete !== void 0) queueOptions.autoDelete = autoDelete;
436
+ if (args !== void 0) queueOptions.arguments = args;
437
+ return defineQueue(name, queueOptions);
438
+ }
439
+ /**
440
+ * Create a queue with TTL-backoff retry (exponential backoff).
441
+ *
442
+ * This is a simplified helper that enforces best practices:
443
+ * - Uses quorum queues (recommended for most use cases)
444
+ * - Requires dead letter exchange for retry routing
445
+ * - Uses TTL-backoff retry mode with configurable delays
446
+ * - Automatically generates wait queue and bindings
447
+ *
448
+ * **When to use:**
449
+ * - You need exponential backoff between retries
450
+ * - You want configurable delays (initial delay, max delay, jitter)
451
+ * - You're processing messages that may need time before retry
452
+ *
453
+ * **Returns:** A `QueueWithTtlBackoffInfrastructure` object that includes the
454
+ * main queue, wait queue, and bindings. Pass this directly to `defineContract`
455
+ * and it will be expanded automatically.
456
+ *
457
+ * @param name - The queue name
458
+ * @param options - Configuration options
459
+ * @returns A queue with TTL-backoff infrastructure
460
+ *
461
+ * @example
462
+ * ```typescript
463
+ * const dlx = defineExchange('orders-dlx', 'direct', { durable: true });
464
+ *
465
+ * const orderQueue = defineTtlBackoffQueue('order-processing', {
466
+ * deadLetterExchange: dlx,
467
+ * maxRetries: 5,
468
+ * initialDelayMs: 1000, // Start with 1s delay
469
+ * maxDelayMs: 30000, // Cap at 30s
470
+ * });
471
+ *
472
+ * const contract = defineContract({
473
+ * exchanges: { dlx },
474
+ * queues: { orderProcessing: orderQueue }, // Wait queue auto-added
475
+ * // ... bindings auto-generated
476
+ * });
477
+ *
478
+ * // To access the underlying queue definition (e.g., for the queue name):
479
+ * import { extractQueue } from '@amqp-contract/contract';
480
+ * const queueName = extractQueue(orderQueue).name;
481
+ * ```
482
+ *
483
+ * @see defineQueue - For full queue configuration options
484
+ * @see defineQuorumQueue - For queues with quorum-native retry (simpler, immediate retries)
485
+ * @see extractQueue - To access the underlying queue definition
486
+ */
487
+ function defineTtlBackoffQueue(name, options) {
488
+ const { deadLetterExchange, deadLetterRoutingKey, maxRetries, initialDelayMs, maxDelayMs, backoffMultiplier, jitter, autoDelete, arguments: args } = options;
489
+ const deadLetter = deadLetterRoutingKey ? {
490
+ exchange: deadLetterExchange,
491
+ routingKey: deadLetterRoutingKey
492
+ } : { exchange: deadLetterExchange };
493
+ const retryOptions = { mode: "ttl-backoff" };
494
+ if (maxRetries !== void 0) retryOptions.maxRetries = maxRetries;
495
+ if (initialDelayMs !== void 0) retryOptions.initialDelayMs = initialDelayMs;
496
+ if (maxDelayMs !== void 0) retryOptions.maxDelayMs = maxDelayMs;
497
+ if (backoffMultiplier !== void 0) retryOptions.backoffMultiplier = backoffMultiplier;
498
+ if (jitter !== void 0) retryOptions.jitter = jitter;
499
+ const queueOptions = {
500
+ type: "quorum",
501
+ deadLetter,
502
+ retry: retryOptions
503
+ };
504
+ if (autoDelete !== void 0) queueOptions.autoDelete = autoDelete;
505
+ if (args !== void 0) queueOptions.arguments = args;
506
+ return defineQueue(name, queueOptions);
507
+ }
325
508
 
326
509
  //#endregion
327
510
  //#region src/builder/publisher.ts
@@ -368,6 +551,19 @@ function definePublisherInternal(exchange, message, options) {
368
551
  * Consumers are associated with a specific queue and message type. When you create a worker
369
552
  * with this consumer, it will process messages from the queue according to the schema.
370
553
  *
554
+ * **Which pattern to use:**
555
+ *
556
+ * | Pattern | Best for | Description |
557
+ * |---------|----------|-------------|
558
+ * | `definePublisher` + `defineConsumer` | Independent definition | Define publishers and consumers separately with manual schema consistency |
559
+ * | `defineEventPublisher` + `defineEventConsumer` | Event broadcasting | Define event publisher first, create consumers that subscribe to it |
560
+ * | `defineCommandConsumer` + `defineCommandPublisher` | Task queues | Define command consumer first, create publishers that send commands to it |
561
+ *
562
+ * Use `defineCommandConsumer` when:
563
+ * - One consumer receives from multiple publishers
564
+ * - You want automatic schema consistency between consumer and publishers
565
+ * - You're building task queue or command patterns
566
+ *
371
567
  * @param queue - The queue definition to consume from
372
568
  * @param message - The message definition with payload schema
373
569
  * @param options - Optional consumer configuration
@@ -400,6 +596,9 @@ function definePublisherInternal(exchange, message, options) {
400
596
  * // connection
401
597
  * // });
402
598
  * ```
599
+ *
600
+ * @see defineCommandConsumer - For task queue patterns with automatic schema consistency
601
+ * @see defineEventPublisher - For event-driven patterns with automatic schema consistency
403
602
  */
404
603
  function defineConsumer(queue, message, options) {
405
604
  return {
@@ -409,6 +608,96 @@ function defineConsumer(queue, message, options) {
409
608
  };
410
609
  }
411
610
 
611
+ //#endregion
612
+ //#region src/builder/event.ts
613
+ /**
614
+ * Implementation of defineEventPublisher.
615
+ * @internal
616
+ */
617
+ function defineEventPublisher(exchange, message, options) {
618
+ const config = {
619
+ __brand: "EventPublisherConfig",
620
+ exchange,
621
+ message,
622
+ routingKey: options?.routingKey
623
+ };
624
+ if (options?.arguments !== void 0) config.arguments = options.arguments;
625
+ return config;
626
+ }
627
+ /**
628
+ * Implementation of defineEventConsumer.
629
+ * @internal
630
+ */
631
+ function defineEventConsumer(eventPublisher, queue, options) {
632
+ const { exchange, message, routingKey: publisherRoutingKey } = eventPublisher;
633
+ const bindingRoutingKey = options?.routingKey ?? publisherRoutingKey;
634
+ const bindingOptions = {};
635
+ if (bindingRoutingKey !== void 0) bindingOptions.routingKey = bindingRoutingKey;
636
+ const bindingArguments = options?.arguments ?? eventPublisher.arguments;
637
+ if (bindingArguments !== void 0) bindingOptions.arguments = bindingArguments;
638
+ const binding = defineQueueBindingInternal(queue, exchange, bindingOptions);
639
+ return {
640
+ __brand: "EventConsumerResult",
641
+ consumer: defineConsumer(queue, message),
642
+ binding
643
+ };
644
+ }
645
+ /**
646
+ * Type guard to check if a value is an EventPublisherConfig.
647
+ *
648
+ * @param value - The value to check
649
+ * @returns True if the value is an EventPublisherConfig
650
+ */
651
+ function isEventPublisherConfig(value) {
652
+ return typeof value === "object" && value !== null && "__brand" in value && value.__brand === "EventPublisherConfig";
653
+ }
654
+ /**
655
+ * Type guard to check if a value is an EventConsumerResult.
656
+ *
657
+ * @param value - The value to check
658
+ * @returns True if the value is an EventConsumerResult
659
+ */
660
+ function isEventConsumerResult(value) {
661
+ return typeof value === "object" && value !== null && "__brand" in value && value.__brand === "EventConsumerResult";
662
+ }
663
+
664
+ //#endregion
665
+ //#region src/builder/command.ts
666
+ /**
667
+ * Implementation of defineCommandConsumer.
668
+ * @internal
669
+ */
670
+ function defineCommandConsumer(queue, exchange, message, options) {
671
+ return {
672
+ __brand: "CommandConsumerConfig",
673
+ consumer: defineConsumer(queue, message),
674
+ binding: defineQueueBindingInternal(queue, exchange, options),
675
+ exchange,
676
+ message,
677
+ routingKey: options?.routingKey
678
+ };
679
+ }
680
+ /**
681
+ * Implementation of defineCommandPublisher.
682
+ * @internal
683
+ */
684
+ function defineCommandPublisher(commandConsumer, options) {
685
+ const { exchange, message, routingKey: consumerRoutingKey } = commandConsumer;
686
+ const publisherRoutingKey = options?.routingKey ?? consumerRoutingKey;
687
+ const publisherOptions = {};
688
+ if (publisherRoutingKey !== void 0) publisherOptions.routingKey = publisherRoutingKey;
689
+ return definePublisherInternal(exchange, message, publisherOptions);
690
+ }
691
+ /**
692
+ * Type guard to check if a value is a CommandConsumerConfig.
693
+ *
694
+ * @param value - The value to check
695
+ * @returns True if the value is a CommandConsumerConfig
696
+ */
697
+ function isCommandConsumerConfig(value) {
698
+ return typeof value === "object" && value !== null && "__brand" in value && value.__brand === "CommandConsumerConfig";
699
+ }
700
+
412
701
  //#endregion
413
702
  //#region src/builder/contract.ts
414
703
  /**
@@ -481,100 +770,49 @@ function defineConsumer(queue, message, options) {
481
770
  * ```
482
771
  */
483
772
  function defineContract(definition) {
484
- if (!definition.queues || Object.keys(definition.queues).length === 0) return definition;
485
- const queues = definition.queues;
486
- const expandedQueues = {};
487
- const autoBindings = {};
488
- for (const [name, entry] of Object.entries(queues)) if (isQueueWithTtlBackoffInfrastructure(entry)) {
489
- expandedQueues[name] = entry.queue;
490
- expandedQueues[`${name}Wait`] = entry.waitQueue;
491
- autoBindings[`${name}WaitBinding`] = entry.waitQueueBinding;
492
- autoBindings[`${name}RetryBinding`] = entry.mainQueueRetryBinding;
493
- } else expandedQueues[name] = entry;
494
- if (Object.keys(autoBindings).length > 0) {
495
- const mergedBindings = {
496
- ...definition.bindings,
497
- ...autoBindings
498
- };
499
- return {
500
- ...definition,
501
- queues: expandedQueues,
502
- bindings: mergedBindings
773
+ const { publishers: inputPublishers, consumers: inputConsumers, ...rest } = definition;
774
+ const result = rest;
775
+ if (definition.queues && Object.keys(definition.queues).length > 0) {
776
+ const expandedQueues = {};
777
+ const queueBindings = {};
778
+ for (const [name, entry] of Object.entries(definition.queues)) if (isQueueWithTtlBackoffInfrastructure(entry)) {
779
+ expandedQueues[name] = entry.queue;
780
+ expandedQueues[`${name}Wait`] = entry.waitQueue;
781
+ queueBindings[`${name}WaitBinding`] = entry.waitQueueBinding;
782
+ queueBindings[`${name}RetryBinding`] = entry.mainQueueRetryBinding;
783
+ } else expandedQueues[name] = entry;
784
+ result.queues = expandedQueues;
785
+ if (Object.keys(queueBindings).length > 0) result.bindings = {
786
+ ...result.bindings,
787
+ ...queueBindings
503
788
  };
504
789
  }
505
- return {
506
- ...definition,
507
- queues: expandedQueues
508
- };
509
- }
510
-
511
- //#endregion
512
- //#region src/builder/publisher-first.ts
513
- /**
514
- * Implementation of definePublisherFirst.
515
- * @internal
516
- */
517
- function definePublisherFirst(exchange, message, options) {
518
- const publisher = definePublisherInternal(exchange, message, options);
519
- if (exchange.type === "topic") {
520
- const createConsumer$1 = (queue, routingKey) => {
521
- const binding = defineQueueBindingInternal(queue, exchange, routingKey ? {
522
- ...options,
523
- routingKey
524
- } : options);
525
- return {
526
- consumer: defineConsumer(queue, message),
527
- binding
528
- };
529
- };
530
- return {
531
- publisher,
532
- createConsumer: createConsumer$1
533
- };
790
+ if (inputPublishers && Object.keys(inputPublishers).length > 0) {
791
+ const processedPublishers = {};
792
+ for (const [name, entry] of Object.entries(inputPublishers)) if (isEventPublisherConfig(entry)) {
793
+ const publisherOptions = {};
794
+ if (entry.routingKey !== void 0) publisherOptions.routingKey = entry.routingKey;
795
+ processedPublishers[name] = definePublisherInternal(entry.exchange, entry.message, publisherOptions);
796
+ } else processedPublishers[name] = entry;
797
+ result.publishers = processedPublishers;
534
798
  }
535
- const createConsumer = (queue) => {
536
- const binding = defineQueueBindingInternal(queue, exchange, options);
537
- return {
538
- consumer: defineConsumer(queue, message),
539
- binding
540
- };
541
- };
542
- return {
543
- publisher,
544
- createConsumer
545
- };
546
- }
547
-
548
- //#endregion
549
- //#region src/builder/consumer-first.ts
550
- /**
551
- * Implementation of defineConsumerFirst.
552
- * @internal
553
- */
554
- function defineConsumerFirst(queue, exchange, message, options) {
555
- const consumer = defineConsumer(queue, message);
556
- const binding = defineQueueBindingInternal(queue, exchange, options);
557
- if (exchange.type === "topic") {
558
- const createPublisher$1 = (routingKey) => {
559
- return definePublisherInternal(exchange, message, {
560
- ...options,
561
- routingKey
562
- });
563
- };
564
- return {
565
- consumer,
566
- binding,
567
- createPublisher: createPublisher$1
799
+ if (inputConsumers && Object.keys(inputConsumers).length > 0) {
800
+ const processedConsumers = {};
801
+ const consumerBindings = {};
802
+ for (const [name, entry] of Object.entries(inputConsumers)) if (isEventConsumerResult(entry)) {
803
+ processedConsumers[name] = entry.consumer;
804
+ consumerBindings[`${name}Binding`] = entry.binding;
805
+ } else if (isCommandConsumerConfig(entry)) {
806
+ processedConsumers[name] = entry.consumer;
807
+ consumerBindings[`${name}Binding`] = entry.binding;
808
+ } else processedConsumers[name] = entry;
809
+ result.consumers = processedConsumers;
810
+ if (Object.keys(consumerBindings).length > 0) result.bindings = {
811
+ ...result.bindings,
812
+ ...consumerBindings
568
813
  };
569
814
  }
570
- const createPublisher = () => {
571
- return definePublisherInternal(exchange, message, options);
572
- };
573
- return {
574
- consumer,
575
- binding,
576
- createPublisher
577
- };
815
+ return result;
578
816
  }
579
817
 
580
818
  //#endregion
@@ -650,15 +888,23 @@ function defineTtlBackoffRetryInfrastructure(queueEntry, options) {
650
888
  }
651
889
 
652
890
  //#endregion
891
+ exports.defineCommandConsumer = defineCommandConsumer;
892
+ exports.defineCommandPublisher = defineCommandPublisher;
653
893
  exports.defineConsumer = defineConsumer;
654
- exports.defineConsumerFirst = defineConsumerFirst;
655
894
  exports.defineContract = defineContract;
895
+ exports.defineEventConsumer = defineEventConsumer;
896
+ exports.defineEventPublisher = defineEventPublisher;
656
897
  exports.defineExchange = defineExchange;
657
898
  exports.defineExchangeBinding = defineExchangeBinding;
658
899
  exports.defineMessage = defineMessage;
659
900
  exports.definePublisher = definePublisher;
660
- exports.definePublisherFirst = definePublisherFirst;
661
901
  exports.defineQueue = defineQueue;
662
902
  exports.defineQueueBinding = defineQueueBinding;
903
+ exports.defineQuorumQueue = defineQuorumQueue;
904
+ exports.defineTtlBackoffQueue = defineTtlBackoffQueue;
663
905
  exports.defineTtlBackoffRetryInfrastructure = defineTtlBackoffRetryInfrastructure;
664
- exports.extractQueue = extractQueue;
906
+ exports.extractQueue = extractQueue;
907
+ exports.isCommandConsumerConfig = isCommandConsumerConfig;
908
+ exports.isEventConsumerResult = isEventConsumerResult;
909
+ exports.isEventPublisherConfig = isEventPublisherConfig;
910
+ exports.isQueueWithTtlBackoffInfrastructure = isQueueWithTtlBackoffInfrastructure;