@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/dist/index.d.mts CHANGED
@@ -798,7 +798,51 @@ type ConsumerDefinition<TMessage extends MessageDefinition = MessageDefinition>
798
798
  message: TMessage;
799
799
  };
800
800
  /**
801
- * Complete AMQP contract definition.
801
+ * Base type for event publisher configuration.
802
+ *
803
+ * This is a simplified type used in ContractDefinition. The full generic type
804
+ * is defined in the builder module.
805
+ *
806
+ * @see defineEventPublisher for creating event publishers
807
+ */
808
+ type EventPublisherConfigBase = {
809
+ __brand: "EventPublisherConfig";
810
+ exchange: ExchangeDefinition;
811
+ message: MessageDefinition;
812
+ routingKey: string | undefined;
813
+ arguments?: Record<string, unknown>;
814
+ };
815
+ /**
816
+ * Base type for command consumer configuration.
817
+ *
818
+ * This is a simplified type used in ContractDefinition. The full generic type
819
+ * is defined in the builder module.
820
+ *
821
+ * @see defineCommandConsumer for creating command consumers
822
+ */
823
+ type CommandConsumerConfigBase = {
824
+ __brand: "CommandConsumerConfig";
825
+ consumer: ConsumerDefinition;
826
+ binding: QueueBindingDefinition;
827
+ exchange: ExchangeDefinition;
828
+ message: MessageDefinition;
829
+ routingKey: string | undefined;
830
+ };
831
+ /**
832
+ * Base type for event consumer result.
833
+ *
834
+ * This is a simplified type used in ContractDefinitionInput. The full generic type
835
+ * is defined in the builder module.
836
+ *
837
+ * @see defineEventConsumer for creating event consumers
838
+ */
839
+ type EventConsumerResultBase = {
840
+ __brand: "EventConsumerResult";
841
+ consumer: ConsumerDefinition;
842
+ binding: QueueBindingDefinition;
843
+ };
844
+ /**
845
+ * Complete AMQP contract definition (output type).
802
846
  *
803
847
  * A contract brings together all AMQP resources into a single, type-safe definition.
804
848
  * It defines the complete messaging topology including exchanges, queues, bindings,
@@ -862,6 +906,69 @@ type ContractDefinition = {
862
906
  */
863
907
  consumers?: Record<string, ConsumerDefinition>;
864
908
  };
909
+ /**
910
+ * Publisher entry that can be passed to defineContract's publishers section.
911
+ *
912
+ * Can be either:
913
+ * - A plain PublisherDefinition from definePublisher
914
+ * - An EventPublisherConfig from defineEventPublisher (auto-extracted to publisher)
915
+ */
916
+ type PublisherEntry = PublisherDefinition | EventPublisherConfigBase;
917
+ /**
918
+ * Consumer entry that can be passed to defineContract's consumers section.
919
+ *
920
+ * Can be either:
921
+ * - A plain ConsumerDefinition from defineConsumer
922
+ * - An EventConsumerResult from defineEventConsumer (binding auto-extracted)
923
+ * - A CommandConsumerConfig from defineCommandConsumer (binding auto-extracted)
924
+ */
925
+ type ConsumerEntry = ConsumerDefinition | EventConsumerResultBase | CommandConsumerConfigBase;
926
+ /**
927
+ * Contract definition input type with automatic extraction of event/command patterns.
928
+ *
929
+ * This type allows passing event and command configs directly to the publishers
930
+ * and consumers sections. `defineContract` will automatically extract the appropriate
931
+ * definitions and generate bindings.
932
+ *
933
+ * @example
934
+ * ```typescript
935
+ * const contract = defineContract({
936
+ * exchanges: { orders: ordersExchange },
937
+ * queues: { processing: processingQueue },
938
+ * publishers: {
939
+ * // EventPublisherConfig → auto-extracted to publisher
940
+ * orderCreated: defineEventPublisher(ordersExchange, orderMessage, { routingKey: "order.created" }),
941
+ * },
942
+ * consumers: {
943
+ * // CommandConsumerConfig → auto-extracted to consumer + binding
944
+ * processOrder: defineCommandConsumer(orderQueue, ordersExchange, orderMessage, { routingKey: "order.process" }),
945
+ * // EventConsumerResult → auto-extracted to consumer + binding
946
+ * notify: defineEventConsumer(orderCreatedEvent, notificationQueue),
947
+ * },
948
+ * });
949
+ * ```
950
+ *
951
+ * @see defineContract - Processes this input and returns a ContractDefinition
952
+ */
953
+ type ContractDefinitionInput = Omit<ContractDefinition, "publishers" | "consumers"> & {
954
+ /**
955
+ * Named publisher definitions.
956
+ *
957
+ * Can accept:
958
+ * - PublisherDefinition from definePublisher
959
+ * - EventPublisherConfig from defineEventPublisher (auto-extracted to publisher)
960
+ */
961
+ publishers?: Record<string, PublisherEntry>;
962
+ /**
963
+ * Named consumer definitions.
964
+ *
965
+ * Can accept:
966
+ * - ConsumerDefinition from defineConsumer
967
+ * - EventConsumerResult from defineEventConsumer (binding auto-extracted)
968
+ * - CommandConsumerConfig from defineCommandConsumer (binding auto-extracted)
969
+ */
970
+ consumers?: Record<string, ConsumerEntry>;
971
+ };
865
972
  /**
866
973
  * Extract publisher names from a contract.
867
974
  *
@@ -1010,19 +1117,87 @@ declare function defineMessage<TPayload extends MessageDefinition["payload"], TH
1010
1117
  }): MessageDefinition<TPayload, THeaders>;
1011
1118
  //#endregion
1012
1119
  //#region src/builder/queue.d.ts
1120
+ /**
1121
+ * Type guard to check if a queue entry is a QueueWithTtlBackoffInfrastructure.
1122
+ *
1123
+ * When you configure a queue with TTL-backoff retry and a dead letter exchange,
1124
+ * `defineQueue` returns a `QueueWithTtlBackoffInfrastructure` instead of a plain
1125
+ * `QueueDefinition`. This type guard helps you distinguish between the two.
1126
+ *
1127
+ * **When to use:**
1128
+ * - When you need to check the type of a queue entry at runtime
1129
+ * - When writing generic code that handles both plain queues and infrastructure wrappers
1130
+ *
1131
+ * **Related functions:**
1132
+ * - `extractQueue()` - Use this to get the underlying queue definition from either type
1133
+ *
1134
+ * @param entry - The queue entry to check
1135
+ * @returns True if the entry is a QueueWithTtlBackoffInfrastructure, false otherwise
1136
+ *
1137
+ * @example
1138
+ * ```typescript
1139
+ * const queue = defineQueue('orders', {
1140
+ * deadLetter: { exchange: dlx },
1141
+ * retry: { mode: 'ttl-backoff' },
1142
+ * });
1143
+ *
1144
+ * if (isQueueWithTtlBackoffInfrastructure(queue)) {
1145
+ * // queue has .queue, .waitQueue, .waitQueueBinding, .mainQueueRetryBinding
1146
+ * console.log('Wait queue:', queue.waitQueue.name);
1147
+ * } else {
1148
+ * // queue is a plain QueueDefinition
1149
+ * console.log('Queue:', queue.name);
1150
+ * }
1151
+ * ```
1152
+ */
1153
+ declare function isQueueWithTtlBackoffInfrastructure(entry: QueueEntry): entry is QueueWithTtlBackoffInfrastructure;
1013
1154
  /**
1014
1155
  * Extract the plain QueueDefinition from a QueueEntry.
1015
- * If the entry is a QueueWithTtlBackoffInfrastructure, returns the inner queue.
1016
- * Otherwise, returns the entry as-is.
1156
+ *
1157
+ * **Why this function exists:**
1158
+ * When you configure a queue with TTL-backoff retry and a dead letter exchange,
1159
+ * `defineQueue` (or `defineTtlBackoffQueue`) returns a wrapper object that includes
1160
+ * the main queue, wait queue, and bindings. This function extracts the underlying
1161
+ * queue definition so you can access properties like `name`, `type`, etc.
1162
+ *
1163
+ * **When to use:**
1164
+ * - When you need to access queue properties (name, type, deadLetter, etc.)
1165
+ * - When passing a queue to functions that expect a plain QueueDefinition
1166
+ * - Works safely on both plain queues and infrastructure wrappers
1167
+ *
1168
+ * **How it works:**
1169
+ * - If the entry is a `QueueWithTtlBackoffInfrastructure`, returns `entry.queue`
1170
+ * - Otherwise, returns the entry as-is (it's already a plain QueueDefinition)
1017
1171
  *
1018
1172
  * @param entry - The queue entry (either plain QueueDefinition or QueueWithTtlBackoffInfrastructure)
1019
1173
  * @returns The plain QueueDefinition
1020
1174
  *
1021
1175
  * @example
1022
1176
  * ```typescript
1023
- * const queue = defineQueue('orders', { retry: { mode: 'ttl-backoff' }, deadLetter: { exchange: dlx } });
1024
- * const plainQueue = extractQueue(queue); // Returns the inner QueueDefinition
1177
+ * import { defineQueue, defineTtlBackoffQueue, extractQueue } from '@amqp-contract/contract';
1178
+ *
1179
+ * // TTL-backoff queue returns a wrapper
1180
+ * const orderQueue = defineTtlBackoffQueue('orders', {
1181
+ * deadLetterExchange: dlx,
1182
+ * maxRetries: 3,
1183
+ * });
1184
+ *
1185
+ * // Use extractQueue to access the queue name
1186
+ * const queueName = extractQueue(orderQueue).name; // 'orders'
1187
+ *
1188
+ * // Also works safely on plain queues
1189
+ * const plainQueue = defineQueue('simple', { type: 'quorum', retry: { mode: 'quorum-native' } });
1190
+ * const plainName = extractQueue(plainQueue).name; // 'simple'
1191
+ *
1192
+ * // Access other properties
1193
+ * const queueDef = extractQueue(orderQueue);
1194
+ * console.log(queueDef.name); // 'orders'
1195
+ * console.log(queueDef.type); // 'quorum'
1196
+ * console.log(queueDef.deadLetter); // { exchange: dlx, ... }
1025
1197
  * ```
1198
+ *
1199
+ * @see isQueueWithTtlBackoffInfrastructure - Type guard to check if extraction is needed
1200
+ * @see defineTtlBackoffQueue - Creates queues with TTL-backoff infrastructure
1026
1201
  */
1027
1202
  declare function extractQueue(entry: QueueEntry): QueueDefinition;
1028
1203
  /**
@@ -1088,6 +1263,176 @@ declare function extractQueue(entry: QueueEntry): QueueDefinition;
1088
1263
  * ```
1089
1264
  */
1090
1265
  declare function defineQueue(name: string, options?: DefineQueueOptions): QueueDefinition | QueueWithTtlBackoffInfrastructure;
1266
+ /**
1267
+ * Options for creating a quorum queue with quorum-native retry.
1268
+ *
1269
+ * This simplified helper enforces the required configuration for quorum-native retry:
1270
+ * - Dead letter exchange is required (for failed messages)
1271
+ * - Delivery limit is required (for retry count)
1272
+ */
1273
+ type DefineQuorumQueueOptions = {
1274
+ /**
1275
+ * Dead letter configuration - required for retry support.
1276
+ * Failed messages will be sent to this exchange.
1277
+ */
1278
+ deadLetterExchange: ExchangeDefinition;
1279
+ /**
1280
+ * Optional routing key for dead-lettered messages.
1281
+ */
1282
+ deadLetterRoutingKey?: string;
1283
+ /**
1284
+ * Maximum number of delivery attempts before dead-lettering.
1285
+ * @minimum 1
1286
+ */
1287
+ deliveryLimit: number;
1288
+ /**
1289
+ * If true, the queue is deleted when the last consumer unsubscribes.
1290
+ * @default false
1291
+ */
1292
+ autoDelete?: boolean;
1293
+ /**
1294
+ * Additional AMQP arguments for advanced configuration.
1295
+ */
1296
+ arguments?: Record<string, unknown>;
1297
+ };
1298
+ /**
1299
+ * Create a quorum queue with quorum-native retry.
1300
+ *
1301
+ * This is a simplified helper that enforces best practices:
1302
+ * - Uses quorum queues (recommended for most use cases)
1303
+ * - Requires dead letter exchange for failed message handling
1304
+ * - Uses quorum-native retry mode (simpler than TTL-backoff)
1305
+ *
1306
+ * **When to use:**
1307
+ * - You want simple, immediate retries without exponential backoff
1308
+ * - You don't need configurable delays between retries
1309
+ * - You want the simplest retry configuration
1310
+ *
1311
+ * @param name - The queue name
1312
+ * @param options - Configuration options
1313
+ * @returns A quorum queue definition with quorum-native retry
1314
+ *
1315
+ * @example
1316
+ * ```typescript
1317
+ * const dlx = defineExchange('orders-dlx', 'direct', { durable: true });
1318
+ *
1319
+ * const orderQueue = defineQuorumQueue('order-processing', {
1320
+ * deadLetterExchange: dlx,
1321
+ * deliveryLimit: 3, // Retry up to 3 times
1322
+ * });
1323
+ *
1324
+ * const contract = defineContract({
1325
+ * exchanges: { dlx },
1326
+ * queues: { orderProcessing: orderQueue },
1327
+ * // ...
1328
+ * });
1329
+ * ```
1330
+ *
1331
+ * @see defineQueue - For full queue configuration options
1332
+ * @see defineTtlBackoffQueue - For queues with exponential backoff retry
1333
+ */
1334
+ declare function defineQuorumQueue(name: string, options: DefineQuorumQueueOptions): QuorumQueueDefinition;
1335
+ /**
1336
+ * Options for creating a queue with TTL-backoff retry.
1337
+ *
1338
+ * This simplified helper enforces the required configuration for TTL-backoff retry:
1339
+ * - Dead letter exchange is required (used for retry routing)
1340
+ * - Returns infrastructure that includes wait queue and bindings
1341
+ */
1342
+ type DefineTtlBackoffQueueOptions = {
1343
+ /**
1344
+ * Dead letter exchange - required for TTL-backoff retry.
1345
+ * Used for routing messages to the wait queue and back.
1346
+ */
1347
+ deadLetterExchange: ExchangeDefinition;
1348
+ /**
1349
+ * Optional routing key for dead-lettered messages.
1350
+ */
1351
+ deadLetterRoutingKey?: string;
1352
+ /**
1353
+ * Maximum retry attempts before sending to DLQ.
1354
+ * @default 3
1355
+ */
1356
+ maxRetries?: number;
1357
+ /**
1358
+ * Initial delay in ms before first retry.
1359
+ * @default 1000
1360
+ */
1361
+ initialDelayMs?: number;
1362
+ /**
1363
+ * Maximum delay in ms between retries.
1364
+ * @default 30000
1365
+ */
1366
+ maxDelayMs?: number;
1367
+ /**
1368
+ * Exponential backoff multiplier.
1369
+ * @default 2
1370
+ */
1371
+ backoffMultiplier?: number;
1372
+ /**
1373
+ * Add jitter to prevent thundering herd.
1374
+ * @default true
1375
+ */
1376
+ jitter?: boolean;
1377
+ /**
1378
+ * If true, the queue is deleted when the last consumer unsubscribes.
1379
+ * @default false
1380
+ */
1381
+ autoDelete?: boolean;
1382
+ /**
1383
+ * Additional AMQP arguments for advanced configuration.
1384
+ */
1385
+ arguments?: Record<string, unknown>;
1386
+ };
1387
+ /**
1388
+ * Create a queue with TTL-backoff retry (exponential backoff).
1389
+ *
1390
+ * This is a simplified helper that enforces best practices:
1391
+ * - Uses quorum queues (recommended for most use cases)
1392
+ * - Requires dead letter exchange for retry routing
1393
+ * - Uses TTL-backoff retry mode with configurable delays
1394
+ * - Automatically generates wait queue and bindings
1395
+ *
1396
+ * **When to use:**
1397
+ * - You need exponential backoff between retries
1398
+ * - You want configurable delays (initial delay, max delay, jitter)
1399
+ * - You're processing messages that may need time before retry
1400
+ *
1401
+ * **Returns:** A `QueueWithTtlBackoffInfrastructure` object that includes the
1402
+ * main queue, wait queue, and bindings. Pass this directly to `defineContract`
1403
+ * and it will be expanded automatically.
1404
+ *
1405
+ * @param name - The queue name
1406
+ * @param options - Configuration options
1407
+ * @returns A queue with TTL-backoff infrastructure
1408
+ *
1409
+ * @example
1410
+ * ```typescript
1411
+ * const dlx = defineExchange('orders-dlx', 'direct', { durable: true });
1412
+ *
1413
+ * const orderQueue = defineTtlBackoffQueue('order-processing', {
1414
+ * deadLetterExchange: dlx,
1415
+ * maxRetries: 5,
1416
+ * initialDelayMs: 1000, // Start with 1s delay
1417
+ * maxDelayMs: 30000, // Cap at 30s
1418
+ * });
1419
+ *
1420
+ * const contract = defineContract({
1421
+ * exchanges: { dlx },
1422
+ * queues: { orderProcessing: orderQueue }, // Wait queue auto-added
1423
+ * // ... bindings auto-generated
1424
+ * });
1425
+ *
1426
+ * // To access the underlying queue definition (e.g., for the queue name):
1427
+ * import { extractQueue } from '@amqp-contract/contract';
1428
+ * const queueName = extractQueue(orderQueue).name;
1429
+ * ```
1430
+ *
1431
+ * @see defineQueue - For full queue configuration options
1432
+ * @see defineQuorumQueue - For queues with quorum-native retry (simpler, immediate retries)
1433
+ * @see extractQueue - To access the underlying queue definition
1434
+ */
1435
+ declare function defineTtlBackoffQueue(name: string, options: DefineTtlBackoffQueueOptions): QueueWithTtlBackoffInfrastructure;
1091
1436
  //#endregion
1092
1437
  //#region src/builder/binding.d.ts
1093
1438
  /**
@@ -1219,6 +1564,19 @@ declare function defineExchangeBinding(destination: ExchangeDefinition, source:
1219
1564
  *
1220
1565
  * The message schema is validated when publishing to ensure type safety.
1221
1566
  *
1567
+ * **Which pattern to use:**
1568
+ *
1569
+ * | Pattern | Best for | Description |
1570
+ * |---------|----------|-------------|
1571
+ * | `definePublisher` + `defineConsumer` | Independent definition | Define publishers and consumers separately with manual schema consistency |
1572
+ * | `defineEventPublisher` + `defineEventConsumer` | Event broadcasting | Define event publisher first, create consumers that subscribe to it |
1573
+ * | `defineCommandConsumer` + `defineCommandPublisher` | Task queues | Define command consumer first, create publishers that send commands to it |
1574
+ *
1575
+ * Use `defineEventPublisher` when:
1576
+ * - One publisher feeds multiple consumers
1577
+ * - You want automatic schema consistency between publisher and consumers
1578
+ * - You're building event-driven architectures
1579
+ *
1222
1580
  * @param exchange - The fanout exchange definition to publish to
1223
1581
  * @param message - The message definition with payload schema
1224
1582
  * @param options - Optional publisher configuration
@@ -1239,6 +1597,9 @@ declare function defineExchangeBinding(destination: ExchangeDefinition, source:
1239
1597
  *
1240
1598
  * const logPublisher = definePublisher(logsExchange, logMessage);
1241
1599
  * ```
1600
+ *
1601
+ * @see defineEventPublisher - For event-driven patterns with automatic schema consistency
1602
+ * @see defineCommandConsumer - For task queue patterns with automatic schema consistency
1242
1603
  */
1243
1604
  declare function definePublisher<TMessage extends MessageDefinition>(exchange: FanoutExchangeDefinition, message: TMessage, options?: Omit<Extract<PublisherDefinition<TMessage>, {
1244
1605
  exchange: FanoutExchangeDefinition;
@@ -1253,6 +1614,19 @@ declare function definePublisher<TMessage extends MessageDefinition>(exchange: F
1253
1614
  *
1254
1615
  * The message schema is validated when publishing to ensure type safety.
1255
1616
  *
1617
+ * **Which pattern to use:**
1618
+ *
1619
+ * | Pattern | Best for | Description |
1620
+ * |---------|----------|-------------|
1621
+ * | `definePublisher` + `defineConsumer` | Independent definition | Define publishers and consumers separately with manual schema consistency |
1622
+ * | `defineEventPublisher` + `defineEventConsumer` | Event broadcasting | Define event publisher first, create consumers that subscribe to it |
1623
+ * | `defineCommandConsumer` + `defineCommandPublisher` | Task queues | Define command consumer first, create publishers that send commands to it |
1624
+ *
1625
+ * Use `defineEventPublisher` when:
1626
+ * - One publisher feeds multiple consumers
1627
+ * - You want automatic schema consistency between publisher and consumers
1628
+ * - You're building event-driven architectures
1629
+ *
1256
1630
  * @param exchange - The direct or topic exchange definition to publish to
1257
1631
  * @param message - The message definition with payload schema
1258
1632
  * @param options - Publisher configuration (routingKey is required)
@@ -1279,6 +1653,9 @@ declare function definePublisher<TMessage extends MessageDefinition>(exchange: F
1279
1653
  * routingKey: 'order.created'
1280
1654
  * });
1281
1655
  * ```
1656
+ *
1657
+ * @see defineEventPublisher - For event-driven patterns with automatic schema consistency
1658
+ * @see defineCommandConsumer - For task queue patterns with automatic schema consistency
1282
1659
  */
1283
1660
  declare function definePublisher<TMessage extends MessageDefinition>(exchange: DirectExchangeDefinition | TopicExchangeDefinition, message: TMessage, options: Omit<Extract<PublisherDefinition<TMessage>, {
1284
1661
  exchange: DirectExchangeDefinition | TopicExchangeDefinition;
@@ -1296,6 +1673,19 @@ declare function definePublisher<TMessage extends MessageDefinition>(exchange: D
1296
1673
  * Consumers are associated with a specific queue and message type. When you create a worker
1297
1674
  * with this consumer, it will process messages from the queue according to the schema.
1298
1675
  *
1676
+ * **Which pattern to use:**
1677
+ *
1678
+ * | Pattern | Best for | Description |
1679
+ * |---------|----------|-------------|
1680
+ * | `definePublisher` + `defineConsumer` | Independent definition | Define publishers and consumers separately with manual schema consistency |
1681
+ * | `defineEventPublisher` + `defineEventConsumer` | Event broadcasting | Define event publisher first, create consumers that subscribe to it |
1682
+ * | `defineCommandConsumer` + `defineCommandPublisher` | Task queues | Define command consumer first, create publishers that send commands to it |
1683
+ *
1684
+ * Use `defineCommandConsumer` when:
1685
+ * - One consumer receives from multiple publishers
1686
+ * - You want automatic schema consistency between consumer and publishers
1687
+ * - You're building task queue or command patterns
1688
+ *
1299
1689
  * @param queue - The queue definition to consume from
1300
1690
  * @param message - The message definition with payload schema
1301
1691
  * @param options - Optional consumer configuration
@@ -1328,10 +1718,19 @@ declare function definePublisher<TMessage extends MessageDefinition>(exchange: D
1328
1718
  * // connection
1329
1719
  * // });
1330
1720
  * ```
1721
+ *
1722
+ * @see defineCommandConsumer - For task queue patterns with automatic schema consistency
1723
+ * @see defineEventPublisher - For event-driven patterns with automatic schema consistency
1331
1724
  */
1332
1725
  declare function defineConsumer<TMessage extends MessageDefinition>(queue: QueueEntry, message: TMessage, options?: Omit<ConsumerDefinition<TMessage>, "queue" | "message">): ConsumerDefinition<TMessage>;
1333
1726
  //#endregion
1334
1727
  //#region src/builder/contract.d.ts
1728
+ /**
1729
+ * Type utility to produce the output contract type from the input.
1730
+ * The output has the same structure but with all entries normalized to
1731
+ * their base definition types (PublisherDefinition, ConsumerDefinition).
1732
+ */
1733
+ type ContractOutput<TContract extends ContractDefinitionInput> = TContract;
1335
1734
  /**
1336
1735
  * Define an AMQP contract.
1337
1736
  *
@@ -1401,7 +1800,7 @@ declare function defineConsumer<TMessage extends MessageDefinition>(queue: Queue
1401
1800
  * // - handler: async (message: { orderId: string, amount: number }) => void
1402
1801
  * ```
1403
1802
  */
1404
- declare function defineContract<TContract extends ContractDefinition>(definition: TContract): TContract;
1803
+ declare function defineContract<TContract extends ContractDefinitionInput>(definition: TContract): ContractOutput<TContract>;
1405
1804
  //#endregion
1406
1805
  //#region src/builder/routing-types.d.ts
1407
1806
  /**
@@ -1481,460 +1880,396 @@ type MatchesPattern<Key extends string, Pattern extends string> = Pattern extend
1481
1880
  */
1482
1881
  type MatchingRoutingKey<Pattern extends string, Key extends string> = RoutingKey<Key> extends never ? never : BindingPattern<Pattern> extends never ? never : MatchesPattern<Key, Pattern> extends true ? Key : never;
1483
1882
  //#endregion
1484
- //#region src/builder/publisher-first.d.ts
1883
+ //#region src/builder/event.d.ts
1485
1884
  /**
1486
- * Publisher-first builder result for fanout and direct exchanges.
1487
- *
1488
- * This type represents a publisher and provides a method to create
1489
- * a consumer that uses the same message schema with a binding to the exchange.
1885
+ * Configuration for an event publisher.
1490
1886
  *
1491
- * This pattern is suitable for event-oriented messaging where publishers
1492
- * emit events without knowing which queues will consume them.
1887
+ * Events are published without knowing who consumes them. Multiple consumers
1888
+ * can subscribe to the same event. This follows the pub/sub pattern where
1889
+ * publishers broadcast events and consumers subscribe to receive them.
1493
1890
  *
1494
1891
  * @template TMessage - The message definition
1495
- * @template TPublisher - The publisher definition
1892
+ * @template TExchange - The exchange definition
1893
+ * @template TRoutingKey - The routing key type (undefined for fanout)
1496
1894
  */
1497
- type PublisherFirstResult<TMessage extends MessageDefinition, TPublisher extends PublisherDefinition<TMessage>> = {
1498
- /** The publisher definition */
1499
- publisher: TPublisher;
1500
- /**
1501
- * Create a consumer that receives messages from this publisher.
1502
- * The consumer will automatically use the same message schema and
1503
- * a binding will be created with the same routing key.
1504
- *
1505
- * @param queue - The queue (or queue with infrastructure) that will consume the messages
1506
- * @returns An object with the consumer definition and binding
1507
- */
1508
- createConsumer: (queue: QueueEntry) => {
1509
- consumer: ConsumerDefinition<TMessage>;
1510
- binding: QueueBindingDefinition;
1511
- };
1895
+ type EventPublisherConfig<TMessage extends MessageDefinition, TExchange extends ExchangeDefinition, TRoutingKey extends string | undefined = undefined> = {
1896
+ /** Discriminator to identify this as an event publisher config */
1897
+ __brand: "EventPublisherConfig";
1898
+ /** The exchange to publish to */
1899
+ exchange: TExchange;
1900
+ /** The message definition */
1901
+ message: TMessage;
1902
+ /** The routing key for direct/topic exchanges */
1903
+ routingKey: TRoutingKey;
1904
+ /** Additional AMQP arguments */
1905
+ arguments?: Record<string, unknown>;
1512
1906
  };
1513
1907
  /**
1514
- * Publisher-first builder result for topic exchanges.
1908
+ * Result from defineEventConsumer.
1515
1909
  *
1516
- * This type represents a publisher with a concrete routing key and provides a method
1517
- * to create consumers that can use routing key patterns matching the publisher's key.
1910
+ * Contains the consumer definition and binding needed to subscribe to an event.
1911
+ * Can be used directly in defineContract's consumers section - the binding
1912
+ * will be automatically extracted.
1518
1913
  *
1519
1914
  * @template TMessage - The message definition
1520
- * @template TPublisher - The publisher definition
1521
- * @template TRoutingKey - The literal routing key type from the publisher (for documentation purposes)
1522
1915
  */
1523
- type PublisherFirstResultWithRoutingKey<TMessage extends MessageDefinition, TPublisher extends PublisherDefinition<TMessage>, TRoutingKey extends string> = {
1524
- /** The publisher definition */
1525
- publisher: TPublisher;
1526
- /**
1527
- * Create a consumer that receives messages from this publisher.
1528
- * For topic exchanges, the routing key pattern can be specified for the binding.
1529
- *
1530
- * @param queue - The queue (or queue with infrastructure) that will consume the messages
1531
- * @param routingKey - Optional routing key pattern for the binding (defaults to publisher's routing key)
1532
- * @returns An object with the consumer definition and binding
1533
- */
1534
- createConsumer: <TConsumerRoutingKey extends string = TRoutingKey>(queue: QueueEntry, routingKey?: BindingPattern<TConsumerRoutingKey>) => {
1535
- consumer: ConsumerDefinition<TMessage>;
1536
- binding: QueueBindingDefinition;
1537
- };
1916
+ type EventConsumerResult<TMessage extends MessageDefinition> = {
1917
+ /** Discriminator to identify this as an event consumer result */
1918
+ __brand: "EventConsumerResult";
1919
+ /** The consumer definition for processing messages */
1920
+ consumer: ConsumerDefinition<TMessage>;
1921
+ /** The binding connecting the queue to the exchange */
1922
+ binding: QueueBindingDefinition;
1538
1923
  };
1539
1924
  /**
1540
- * Define a publisher-first relationship for event-oriented messaging.
1925
+ * Define an event publisher for broadcasting messages via fanout exchange.
1541
1926
  *
1542
- * This builder enforces consistency by:
1543
- * 1. Ensuring the publisher and consumer use the same message schema
1544
- * 2. Linking the routing key from the publisher to the binding
1927
+ * Events are published without knowing who consumes them. Multiple consumers
1928
+ * can subscribe to the same event using `defineEventConsumer`.
1545
1929
  *
1546
- * Use this pattern for events where publishers don't need to know about queues.
1547
- * Multiple consumers can be created for different queues, all using the same message schema.
1548
- *
1549
- * @param exchange - The exchange to publish to (fanout type)
1930
+ * @param exchange - The fanout exchange to publish to
1550
1931
  * @param message - The message definition (schema and metadata)
1551
- * @param options - Optional binding configuration
1552
- * @returns A publisher-first result with publisher and consumer factory
1932
+ * @returns An event publisher configuration
1553
1933
  *
1554
1934
  * @example
1555
1935
  * ```typescript
1556
- * import { z } from 'zod';
1557
- *
1558
1936
  * const logsExchange = defineExchange('logs', 'fanout', { durable: true });
1559
- * const logMessage = defineMessage(
1560
- * z.object({
1561
- * level: z.enum(['info', 'warn', 'error']),
1562
- * message: z.string(),
1563
- * })
1564
- * );
1565
- *
1566
- * // Create publisher-first relationship (event pattern)
1567
- * const { publisher: publishLog, createConsumer: createLogConsumer } = definePublisherFirst(logsExchange, logMessage);
1568
- *
1569
- * // Multiple queues can consume the same event
1570
- * const logsQueue1 = defineQueue('logs-queue-1', { durable: true });
1571
- * const logsQueue2 = defineQueue('logs-queue-2', { durable: true });
1572
- *
1573
- * // Use in contract
1574
- * const { consumer: consumer1, binding: binding1 } = createLogConsumer(logsQueue1);
1575
- * const { consumer: consumer2, binding: binding2 } = createLogConsumer(logsQueue2);
1576
- *
1577
- * const contract = defineContract({
1578
- * exchanges: { logs: logsExchange },
1579
- * queues: { logsQueue1, logsQueue2 },
1580
- * bindings: {
1581
- * logBinding1: binding1,
1582
- * logBinding2: binding2,
1583
- * },
1584
- * publishers: { publishLog },
1585
- * consumers: {
1586
- * consumeLog1: consumer1,
1587
- * consumeLog2: consumer2,
1588
- * },
1589
- * });
1937
+ * const logMessage = defineMessage(z.object({
1938
+ * level: z.enum(['info', 'warn', 'error']),
1939
+ * message: z.string(),
1940
+ * }));
1941
+ *
1942
+ * // Create event publisher
1943
+ * const logEvent = defineEventPublisher(logsExchange, logMessage);
1944
+ *
1945
+ * // Multiple consumers can subscribe
1946
+ * const { consumer: fileConsumer, binding: fileBinding } =
1947
+ * defineEventConsumer(logEvent, fileLogsQueue);
1948
+ * const { consumer: alertConsumer, binding: alertBinding } =
1949
+ * defineEventConsumer(logEvent, alertsQueue);
1590
1950
  * ```
1591
1951
  */
1592
- declare function definePublisherFirst<TMessage extends MessageDefinition>(exchange: FanoutExchangeDefinition, message: TMessage, options?: Omit<Extract<QueueBindingDefinition, {
1593
- exchange: FanoutExchangeDefinition;
1594
- }>, "type" | "queue" | "exchange" | "routingKey">): PublisherFirstResult<TMessage, Extract<PublisherDefinition<TMessage>, {
1595
- exchange: FanoutExchangeDefinition;
1596
- }>>;
1952
+ declare function defineEventPublisher<TMessage extends MessageDefinition>(exchange: FanoutExchangeDefinition, message: TMessage): EventPublisherConfig<TMessage, FanoutExchangeDefinition, undefined>;
1597
1953
  /**
1598
- * Define a publisher-first relationship for event-oriented messaging with direct exchange.
1599
- *
1600
- * This builder enforces consistency by:
1601
- * 1. Ensuring the publisher and consumer use the same message schema
1602
- * 2. Linking the routing key from the publisher to the binding
1954
+ * Define an event publisher for broadcasting messages via direct exchange.
1603
1955
  *
1604
- * Use this pattern for events where publishers don't need to know about queues.
1605
- * Multiple consumers can be created for different queues, all using the same message schema.
1956
+ * Events are published with a specific routing key. Consumers will receive
1957
+ * messages that match the routing key exactly.
1606
1958
  *
1607
- * @param exchange - The exchange to publish to (direct type)
1959
+ * @param exchange - The direct exchange to publish to
1608
1960
  * @param message - The message definition (schema and metadata)
1609
- * @param options - Binding configuration (routingKey is required)
1961
+ * @param options - Configuration with required routing key
1610
1962
  * @param options.routingKey - The routing key for message routing
1611
- * @returns A publisher-first result with publisher and consumer factory
1963
+ * @param options.arguments - Additional AMQP arguments
1964
+ * @returns An event publisher configuration
1612
1965
  *
1613
1966
  * @example
1614
1967
  * ```typescript
1615
- * import { z } from 'zod';
1616
- *
1617
1968
  * const tasksExchange = defineExchange('tasks', 'direct', { durable: true });
1618
- * const taskMessage = defineMessage(
1619
- * z.object({
1620
- * taskId: z.string(),
1621
- * payload: z.record(z.unknown()),
1622
- * })
1623
- * );
1624
- *
1625
- * // Create publisher-first relationship with routing key
1626
- * const { publisher: executeTaskPublisher, createConsumer: createTaskConsumer } = definePublisherFirst(
1627
- * tasksExchange,
1628
- * taskMessage,
1629
- * { routingKey: 'task.execute' }
1630
- * );
1969
+ * const taskMessage = defineMessage(z.object({ taskId: z.string() }));
1631
1970
  *
1632
- * // Use in contract - routing key is consistent across publisher and bindings
1633
- * const taskQueue = defineQueue('task-queue', { durable: true });
1634
- * const { consumer, binding } = createTaskConsumer(taskQueue);
1635
- *
1636
- * const contract = defineContract({
1637
- * exchanges: { tasks: tasksExchange },
1638
- * queues: { taskQueue },
1639
- * bindings: { taskBinding: binding },
1640
- * publishers: { executeTask: executeTaskPublisher },
1641
- * consumers: { processTask: consumer },
1971
+ * const taskEvent = defineEventPublisher(tasksExchange, taskMessage, {
1972
+ * routingKey: 'task.execute',
1642
1973
  * });
1643
1974
  * ```
1644
1975
  */
1645
- declare function definePublisherFirst<TMessage extends MessageDefinition, TRoutingKey extends string>(exchange: DirectExchangeDefinition, message: TMessage, options: {
1976
+ declare function defineEventPublisher<TMessage extends MessageDefinition, TRoutingKey extends string>(exchange: DirectExchangeDefinition, message: TMessage, options: {
1646
1977
  routingKey: RoutingKey<TRoutingKey>;
1647
1978
  arguments?: Record<string, unknown>;
1648
- }): PublisherFirstResult<TMessage, Extract<PublisherDefinition<TMessage>, {
1649
- exchange: DirectExchangeDefinition | TopicExchangeDefinition;
1650
- }>>;
1979
+ }): EventPublisherConfig<TMessage, DirectExchangeDefinition, TRoutingKey>;
1651
1980
  /**
1652
- * Define a publisher-first relationship for event-oriented messaging with topic exchange.
1981
+ * Define an event publisher for broadcasting messages via topic exchange.
1653
1982
  *
1654
- * This builder enforces consistency by:
1655
- * 1. Ensuring the publisher and consumer use the same message schema
1656
- * 2. The publisher uses a concrete routing key (e.g., 'order.created')
1657
- * 3. Consumers can optionally specify routing key patterns (e.g., 'order.*') or use the default
1983
+ * Events are published with a concrete routing key. Consumers can subscribe
1984
+ * using patterns (with * and # wildcards) to receive matching messages.
1658
1985
  *
1659
- * Use this pattern for events where publishers emit with specific routing keys,
1660
- * and consumers can subscribe with patterns. This is less common than the consumer-first pattern.
1661
- *
1662
- * @param exchange - The exchange to publish to (topic type)
1986
+ * @param exchange - The topic exchange to publish to
1663
1987
  * @param message - The message definition (schema and metadata)
1664
- * @param options - Binding configuration (routingKey is required)
1665
- * @param options.routingKey - The concrete routing key for the publisher
1666
- * @returns A publisher-first result with publisher and consumer factory that accepts optional routing key patterns
1988
+ * @param options - Configuration with required routing key
1989
+ * @param options.routingKey - The concrete routing key (no wildcards)
1990
+ * @param options.arguments - Additional AMQP arguments
1991
+ * @returns An event publisher configuration
1667
1992
  *
1668
1993
  * @example
1669
1994
  * ```typescript
1670
- * import { z } from 'zod';
1671
- *
1672
1995
  * const ordersExchange = defineExchange('orders', 'topic', { durable: true });
1673
- * const orderMessage = defineMessage(
1674
- * z.object({
1675
- * orderId: z.string(),
1676
- * amount: z.number(),
1677
- * })
1678
- * );
1996
+ * const orderMessage = defineMessage(z.object({
1997
+ * orderId: z.string(),
1998
+ * amount: z.number(),
1999
+ * }));
2000
+ *
2001
+ * // Publisher uses concrete routing key
2002
+ * const orderCreatedEvent = defineEventPublisher(ordersExchange, orderMessage, {
2003
+ * routingKey: 'order.created',
2004
+ * });
1679
2005
  *
1680
- * // Create publisher-first relationship with concrete routing key
1681
- * const { publisher: orderCreatedPublisher, createConsumer: createOrderCreatedConsumer } = definePublisherFirst(
1682
- * ordersExchange,
1683
- * orderMessage,
1684
- * { routingKey: 'order.created' } // Concrete key
2006
+ * // Consumer can use pattern
2007
+ * const { consumer, binding } = defineEventConsumer(
2008
+ * orderCreatedEvent,
2009
+ * allOrdersQueue,
2010
+ * { routingKey: 'order.*' },
1685
2011
  * );
2012
+ * ```
2013
+ */
2014
+ declare function defineEventPublisher<TMessage extends MessageDefinition, TRoutingKey extends string>(exchange: TopicExchangeDefinition, message: TMessage, options: {
2015
+ routingKey: RoutingKey<TRoutingKey>;
2016
+ arguments?: Record<string, unknown>;
2017
+ }): EventPublisherConfig<TMessage, TopicExchangeDefinition, TRoutingKey>;
2018
+ /**
2019
+ * Create a consumer that subscribes to an event from a fanout exchange.
1686
2020
  *
1687
- * // Consumers can use patterns or specific keys
1688
- * const orderQueue = defineQueue('order-processing', { durable: true });
1689
- * const allOrdersQueue = defineQueue('all-orders', { durable: true });
2021
+ * @param eventPublisher - The event publisher configuration
2022
+ * @param queue - The queue that will receive messages
2023
+ * @param options - Optional binding configuration
2024
+ * @returns An object with the consumer definition and binding
1690
2025
  *
1691
- * // Use in contract
1692
- * const { consumer: processConsumer, binding: processBinding } =
1693
- * createOrderCreatedConsumer(orderQueue); // Uses 'order.created'
1694
- * const { consumer: allOrdersConsumer, binding: allOrdersBinding } =
1695
- * createOrderCreatedConsumer(allOrdersQueue, 'order.*'); // Uses pattern
2026
+ * @example
2027
+ * ```typescript
2028
+ * const logEvent = defineEventPublisher(logsExchange, logMessage);
2029
+ * const { consumer, binding } = defineEventConsumer(logEvent, logsQueue);
2030
+ * ```
2031
+ */
2032
+ declare function defineEventConsumer<TMessage extends MessageDefinition>(eventPublisher: EventPublisherConfig<TMessage, FanoutExchangeDefinition, undefined>, queue: QueueEntry, options?: {
2033
+ arguments?: Record<string, unknown>;
2034
+ }): EventConsumerResult<TMessage>;
2035
+ /**
2036
+ * Create a consumer that subscribes to an event from a direct exchange.
1696
2037
  *
1697
- * const contract = defineContract({
1698
- * exchanges: { orders: ordersExchange },
1699
- * queues: { orderQueue, allOrdersQueue },
1700
- * bindings: {
1701
- * orderBinding: processBinding,
1702
- * allOrdersBinding,
1703
- * },
1704
- * publishers: { orderCreated: orderCreatedPublisher },
1705
- * consumers: {
1706
- * processOrder: processConsumer,
1707
- * trackAllOrders: allOrdersConsumer,
1708
- * },
2038
+ * @param eventPublisher - The event publisher configuration
2039
+ * @param queue - The queue that will receive messages
2040
+ * @param options - Optional binding configuration
2041
+ * @returns An object with the consumer definition and binding
2042
+ */
2043
+ declare function defineEventConsumer<TMessage extends MessageDefinition, TRoutingKey extends string>(eventPublisher: EventPublisherConfig<TMessage, DirectExchangeDefinition, TRoutingKey>, queue: QueueEntry, options?: {
2044
+ arguments?: Record<string, unknown>;
2045
+ }): EventConsumerResult<TMessage>;
2046
+ /**
2047
+ * Create a consumer that subscribes to an event from a topic exchange.
2048
+ *
2049
+ * For topic exchanges, the consumer can optionally override the routing key
2050
+ * with a pattern to subscribe to multiple events.
2051
+ *
2052
+ * @param eventPublisher - The event publisher configuration
2053
+ * @param queue - The queue that will receive messages
2054
+ * @param options - Optional binding configuration
2055
+ * @param options.routingKey - Override routing key with pattern (defaults to publisher's key)
2056
+ * @returns An object with the consumer definition and binding
2057
+ *
2058
+ * @example
2059
+ * ```typescript
2060
+ * const orderCreatedEvent = defineEventPublisher(ordersExchange, orderMessage, {
2061
+ * routingKey: 'order.created',
2062
+ * });
2063
+ *
2064
+ * // Use exact routing key from publisher
2065
+ * const { consumer: exactConsumer } = defineEventConsumer(orderCreatedEvent, exactQueue);
2066
+ *
2067
+ * // Override with pattern to receive all order events
2068
+ * const { consumer: allConsumer } = defineEventConsumer(orderCreatedEvent, allQueue, {
2069
+ * routingKey: 'order.*',
1709
2070
  * });
1710
2071
  * ```
1711
2072
  */
1712
- declare function definePublisherFirst<TMessage extends MessageDefinition, TRoutingKey extends string>(exchange: TopicExchangeDefinition, message: TMessage, options: {
1713
- routingKey: RoutingKey<TRoutingKey>;
2073
+ declare function defineEventConsumer<TMessage extends MessageDefinition, TRoutingKey extends string, TConsumerRoutingKey extends string = TRoutingKey>(eventPublisher: EventPublisherConfig<TMessage, TopicExchangeDefinition, TRoutingKey>, queue: QueueEntry, options?: {
2074
+ routingKey?: BindingPattern<TConsumerRoutingKey>;
1714
2075
  arguments?: Record<string, unknown>;
1715
- }): PublisherFirstResultWithRoutingKey<TMessage, Extract<PublisherDefinition<TMessage>, {
1716
- exchange: DirectExchangeDefinition | TopicExchangeDefinition;
1717
- }>, TRoutingKey>;
1718
- //#endregion
1719
- //#region src/builder/consumer-first.d.ts
2076
+ }): EventConsumerResult<TMessage>;
1720
2077
  /**
1721
- * Consumer-first builder result for fanout and direct exchanges.
2078
+ * Type guard to check if a value is an EventPublisherConfig.
1722
2079
  *
1723
- * This type represents a consumer with its binding and provides a method to create
1724
- * a publisher that uses the same message schema and routing key.
2080
+ * @param value - The value to check
2081
+ * @returns True if the value is an EventPublisherConfig
2082
+ */
2083
+ declare function isEventPublisherConfig(value: unknown): value is EventPublisherConfig<MessageDefinition, ExchangeDefinition, string | undefined>;
2084
+ /**
2085
+ * Type guard to check if a value is an EventConsumerResult.
1725
2086
  *
1726
- * @template TMessage - The message definition
1727
- * @template TConsumer - The consumer definition
1728
- * @template TBinding - The queue binding definition
2087
+ * @param value - The value to check
2088
+ * @returns True if the value is an EventConsumerResult
1729
2089
  */
1730
- type ConsumerFirstResult<TMessage extends MessageDefinition, TConsumer extends ConsumerDefinition<TMessage>, TBinding extends QueueBindingDefinition> = {
1731
- /** The consumer definition */
1732
- consumer: TConsumer;
1733
- /** The binding definition connecting the exchange to the queue */
1734
- binding: TBinding;
1735
- /**
1736
- * Create a publisher that sends messages to this consumer.
1737
- * The publisher will automatically use the same message schema and routing key.
1738
- *
1739
- * @returns A publisher definition with the same message type and routing key
1740
- */
1741
- createPublisher: () => TBinding["exchange"] extends FanoutExchangeDefinition ? Extract<PublisherDefinition<TMessage>, {
1742
- exchange: FanoutExchangeDefinition;
1743
- }> : Extract<PublisherDefinition<TMessage>, {
1744
- exchange: DirectExchangeDefinition | TopicExchangeDefinition;
1745
- }>;
1746
- };
2090
+ declare function isEventConsumerResult(value: unknown): value is EventConsumerResult<MessageDefinition>;
2091
+ //#endregion
2092
+ //#region src/builder/command.d.ts
1747
2093
  /**
1748
- * Consumer-first builder result for topic exchanges.
2094
+ * Configuration for a command consumer.
1749
2095
  *
1750
- * This type represents a consumer with its binding (which may use a pattern) and provides
1751
- * a method to create a publisher with a concrete routing key that matches the pattern.
2096
+ * Commands are sent by one or more publishers to a single consumer (task queue pattern).
2097
+ * The consumer "owns" the queue, and publishers send commands to it.
1752
2098
  *
1753
2099
  * @template TMessage - The message definition
1754
- * @template TConsumer - The consumer definition
1755
- * @template TBinding - The queue binding definition
2100
+ * @template TExchange - The exchange definition
2101
+ * @template TRoutingKey - The routing key type (undefined for fanout)
1756
2102
  */
1757
- type ConsumerFirstResultWithRoutingKey<TMessage extends MessageDefinition, TConsumer extends ConsumerDefinition<TMessage>, TBinding extends QueueBindingDefinition> = {
1758
- /** The consumer definition */
1759
- consumer: TConsumer;
1760
- /** The binding definition connecting the exchange to the queue */
1761
- binding: TBinding;
1762
- /**
1763
- * Create a publisher that sends messages to this consumer.
1764
- * For topic exchanges, the routing key can be specified to match the binding pattern.
1765
- *
1766
- * @param routingKey - The concrete routing key that matches the binding pattern
1767
- * @returns A publisher definition with the specified routing key
1768
- */
1769
- createPublisher: <TPublisherRoutingKey extends string>(routingKey: RoutingKey<TPublisherRoutingKey>) => Extract<PublisherDefinition<TMessage>, {
1770
- exchange: DirectExchangeDefinition | TopicExchangeDefinition;
1771
- }>;
2103
+ type CommandConsumerConfig<TMessage extends MessageDefinition, TExchange extends ExchangeDefinition, TRoutingKey extends string | undefined = undefined> = {
2104
+ /** Discriminator to identify this as a command consumer config */
2105
+ __brand: "CommandConsumerConfig";
2106
+ /** The consumer definition for processing commands */
2107
+ consumer: ConsumerDefinition<TMessage>;
2108
+ /** The binding connecting the queue to the exchange */
2109
+ binding: QueueBindingDefinition;
2110
+ /** The exchange that receives commands */
2111
+ exchange: TExchange;
2112
+ /** The message definition */
2113
+ message: TMessage;
2114
+ /** The routing key pattern for the binding */
2115
+ routingKey: TRoutingKey;
1772
2116
  };
1773
2117
  /**
1774
- * Define a consumer-first relationship between a consumer and publisher.
1775
- *
1776
- * This builder enforces consistency by:
1777
- * 1. Ensuring the consumer and publisher use the same message schema
1778
- * 2. Linking the routing key from the binding to the publisher
1779
- * 3. Creating a binding that connects the exchange to the queue
2118
+ * Define a command consumer for receiving commands via fanout exchange.
1780
2119
  *
1781
- * Use this when you want to start with a consumer and ensure publishers
1782
- * send messages of the correct type.
2120
+ * Commands are sent by publishers to a specific queue. The consumer "owns" the
2121
+ * queue and defines what commands it accepts.
1783
2122
  *
1784
- * @param queue - The queue to consume from
1785
- * @param exchange - The exchange that routes to the queue (fanout type)
2123
+ * @param queue - The queue that will receive commands
2124
+ * @param exchange - The fanout exchange that routes commands
1786
2125
  * @param message - The message definition (schema and metadata)
1787
- * @param options - Optional binding configuration
1788
- * @returns A consumer-first result with consumer, binding, and publisher factory
2126
+ * @returns A command consumer configuration
1789
2127
  *
1790
2128
  * @example
1791
2129
  * ```typescript
1792
- * import { z } from 'zod';
2130
+ * const tasksExchange = defineExchange('tasks', 'fanout', { durable: true });
2131
+ * const taskMessage = defineMessage(z.object({ taskId: z.string() }));
1793
2132
  *
1794
- * const notificationsQueue = defineQueue('notifications', { durable: true });
1795
- * const notificationsExchange = defineExchange('notifications', 'fanout', { durable: true });
1796
- * const notificationMessage = defineMessage(
1797
- * z.object({
1798
- * userId: z.string(),
1799
- * message: z.string(),
1800
- * })
1801
- * );
2133
+ * // Consumer owns the queue
2134
+ * const executeTask = defineCommandConsumer(taskQueue, tasksExchange, taskMessage);
1802
2135
  *
1803
- * // Create consumer-first relationship
1804
- * const { consumer: processNotificationConsumer, binding: notificationBinding, createPublisher: createNotificationPublisher } = defineConsumerFirst(
1805
- * notificationsQueue,
1806
- * notificationsExchange,
1807
- * notificationMessage
1808
- * );
1809
- *
1810
- * // Use in contract
1811
- * const contract = defineContract({
1812
- * exchanges: { notifications: notificationsExchange },
1813
- * queues: { notificationsQueue },
1814
- * bindings: { notificationBinding },
1815
- * publishers: { sendNotification: createNotificationPublisher() },
1816
- * consumers: { processNotification: processNotificationConsumer },
1817
- * });
2136
+ * // Publishers send commands to it
2137
+ * const sendTask = defineCommandPublisher(executeTask);
1818
2138
  * ```
1819
2139
  */
1820
- declare function defineConsumerFirst<TMessage extends MessageDefinition>(queue: QueueEntry, exchange: FanoutExchangeDefinition, message: TMessage, options?: Omit<Extract<QueueBindingDefinition, {
1821
- exchange: FanoutExchangeDefinition;
1822
- }>, "type" | "queue" | "exchange" | "routingKey">): ConsumerFirstResult<TMessage, ConsumerDefinition<TMessage>, Extract<QueueBindingDefinition, {
1823
- exchange: FanoutExchangeDefinition;
1824
- }>>;
2140
+ declare function defineCommandConsumer<TMessage extends MessageDefinition>(queue: QueueEntry, exchange: FanoutExchangeDefinition, message: TMessage): CommandConsumerConfig<TMessage, FanoutExchangeDefinition, undefined>;
1825
2141
  /**
1826
- * Define a consumer-first relationship between a consumer and publisher.
1827
- *
1828
- * This builder enforces consistency by:
1829
- * 1. Ensuring the consumer and publisher use the same message schema
1830
- * 2. Linking the routing key from the binding to the publisher
1831
- * 3. Creating a binding that connects the exchange to the queue
2142
+ * Define a command consumer for receiving commands via direct exchange.
1832
2143
  *
1833
- * Use this when you want to start with a consumer and ensure publishers
1834
- * send messages with the correct type and routing key.
2144
+ * Commands are sent by publishers with a specific routing key that matches
2145
+ * the binding pattern.
1835
2146
  *
1836
- * @param queue - The queue to consume from
1837
- * @param exchange - The exchange that routes to the queue (direct type)
2147
+ * @param queue - The queue that will receive commands
2148
+ * @param exchange - The direct exchange that routes commands
1838
2149
  * @param message - The message definition (schema and metadata)
1839
- * @param options - Binding configuration (routingKey is required)
1840
- * @param options.routingKey - The routing key for message routing
1841
- * @returns A consumer-first result with consumer, binding, and publisher factory
2150
+ * @param options - Configuration with required routing key
2151
+ * @param options.routingKey - The routing key for the binding
2152
+ * @param options.arguments - Additional AMQP arguments
2153
+ * @returns A command consumer configuration
1842
2154
  *
1843
2155
  * @example
1844
2156
  * ```typescript
1845
- * import { z } from 'zod';
1846
- *
1847
- * const taskQueue = defineQueue('tasks', { durable: true });
1848
2157
  * const tasksExchange = defineExchange('tasks', 'direct', { durable: true });
1849
- * const taskMessage = defineMessage(
1850
- * z.object({
1851
- * taskId: z.string(),
1852
- * payload: z.record(z.unknown()),
1853
- * })
1854
- * );
1855
- *
1856
- * // Create consumer-first relationship with routing key
1857
- * const { consumer: processTaskConsumer, binding: taskBinding, createPublisher: createTaskPublisher } = defineConsumerFirst(
1858
- * taskQueue,
1859
- * tasksExchange,
1860
- * taskMessage,
1861
- * { routingKey: 'task.execute' }
1862
- * );
2158
+ * const taskMessage = defineMessage(z.object({ taskId: z.string() }));
1863
2159
  *
1864
- * // Use in contract - routing key is consistent across consumer and publisher
1865
- * const contract = defineContract({
1866
- * exchanges: { tasks: tasksExchange },
1867
- * queues: { taskQueue },
1868
- * bindings: { taskBinding },
1869
- * publishers: { executeTask: createTaskPublisher() },
1870
- * consumers: { processTask: processTaskConsumer },
2160
+ * const executeTask = defineCommandConsumer(taskQueue, tasksExchange, taskMessage, {
2161
+ * routingKey: 'task.execute',
1871
2162
  * });
2163
+ *
2164
+ * const sendTask = defineCommandPublisher(executeTask);
1872
2165
  * ```
1873
2166
  */
1874
- declare function defineConsumerFirst<TMessage extends MessageDefinition, TRoutingKey extends string>(queue: QueueEntry, exchange: DirectExchangeDefinition, message: TMessage, options: {
2167
+ declare function defineCommandConsumer<TMessage extends MessageDefinition, TRoutingKey extends string>(queue: QueueEntry, exchange: DirectExchangeDefinition, message: TMessage, options: {
1875
2168
  routingKey: RoutingKey<TRoutingKey>;
1876
2169
  arguments?: Record<string, unknown>;
1877
- }): ConsumerFirstResult<TMessage, ConsumerDefinition<TMessage>, Extract<QueueBindingDefinition, {
1878
- exchange: DirectExchangeDefinition;
1879
- }>>;
2170
+ }): CommandConsumerConfig<TMessage, DirectExchangeDefinition, TRoutingKey>;
1880
2171
  /**
1881
- * Define a consumer-first relationship between a consumer and publisher with topic exchange.
2172
+ * Define a command consumer for receiving commands via topic exchange.
1882
2173
  *
1883
- * This builder enforces consistency by:
1884
- * 1. Ensuring the consumer and publisher use the same message schema
1885
- * 2. The binding uses a routing key pattern (e.g., 'order.*')
1886
- * 3. The publisher factory accepts a concrete routing key that matches the pattern (e.g., 'order.created')
2174
+ * The consumer binds with a routing key pattern (can use * and # wildcards).
2175
+ * Publishers then send commands with concrete routing keys that match the pattern.
1887
2176
  *
1888
- * Use this when you want to start with a consumer that uses a routing key pattern,
1889
- * and allow publishers to specify concrete routing keys that match that pattern.
1890
- *
1891
- * @param queue - The queue to consume from
1892
- * @param exchange - The exchange that routes to the queue (topic type)
2177
+ * @param queue - The queue that will receive commands
2178
+ * @param exchange - The topic exchange that routes commands
1893
2179
  * @param message - The message definition (schema and metadata)
1894
- * @param options - Binding configuration (routingKey is required)
1895
- * @param options.routingKey - The routing key pattern for the binding (can use wildcards)
1896
- * @returns A consumer-first result with consumer, binding, and publisher factory that accepts a routing key
2180
+ * @param options - Configuration with required routing key pattern
2181
+ * @param options.routingKey - The routing key pattern for the binding
2182
+ * @param options.arguments - Additional AMQP arguments
2183
+ * @returns A command consumer configuration
1897
2184
  *
1898
2185
  * @example
1899
2186
  * ```typescript
1900
- * import { z } from 'zod';
1901
- *
1902
- * const orderQueue = defineQueue('order-processing', { durable: true });
1903
2187
  * const ordersExchange = defineExchange('orders', 'topic', { durable: true });
1904
- * const orderMessage = defineMessage(
1905
- * z.object({
1906
- * orderId: z.string(),
1907
- * amount: z.number(),
1908
- * })
1909
- * );
2188
+ * const orderMessage = defineMessage(z.object({ orderId: z.string() }));
1910
2189
  *
1911
- * // Create consumer-first relationship with pattern
1912
- * const { consumer: processOrderConsumer, binding: orderBinding, createPublisher: createOrderPublisher } = defineConsumerFirst(
1913
- * orderQueue,
1914
- * ordersExchange,
1915
- * orderMessage,
1916
- * { routingKey: 'order.*' } // Pattern in binding
1917
- * );
2190
+ * // Consumer uses pattern to receive multiple command types
2191
+ * const processOrder = defineCommandConsumer(orderQueue, ordersExchange, orderMessage, {
2192
+ * routingKey: 'order.*',
2193
+ * });
1918
2194
  *
1919
- * // Use in contract - publisher can specify concrete routing key
1920
- * const contract = defineContract({
1921
- * exchanges: { orders: ordersExchange },
1922
- * queues: { orderQueue },
1923
- * bindings: { orderBinding },
1924
- * publishers: {
1925
- * orderCreated: createOrderPublisher('order.created'), // Concrete key
1926
- * orderUpdated: createOrderPublisher('order.updated'), // Concrete key
1927
- * },
1928
- * consumers: { processOrder: processOrderConsumer },
2195
+ * // Publishers send with concrete keys
2196
+ * const createOrder = defineCommandPublisher(processOrder, {
2197
+ * routingKey: 'order.create',
2198
+ * });
2199
+ * const updateOrder = defineCommandPublisher(processOrder, {
2200
+ * routingKey: 'order.update',
1929
2201
  * });
1930
2202
  * ```
1931
2203
  */
1932
- declare function defineConsumerFirst<TMessage extends MessageDefinition, TRoutingKey extends string>(queue: QueueEntry, exchange: TopicExchangeDefinition, message: TMessage, options: {
2204
+ declare function defineCommandConsumer<TMessage extends MessageDefinition, TRoutingKey extends string>(queue: QueueEntry, exchange: TopicExchangeDefinition, message: TMessage, options: {
1933
2205
  routingKey: BindingPattern<TRoutingKey>;
1934
2206
  arguments?: Record<string, unknown>;
1935
- }): ConsumerFirstResultWithRoutingKey<TMessage, ConsumerDefinition<TMessage>, Extract<QueueBindingDefinition, {
2207
+ }): CommandConsumerConfig<TMessage, TopicExchangeDefinition, TRoutingKey>;
2208
+ /**
2209
+ * Create a publisher that sends commands to a fanout exchange consumer.
2210
+ *
2211
+ * @param commandConsumer - The command consumer configuration
2212
+ * @returns A publisher definition
2213
+ *
2214
+ * @example
2215
+ * ```typescript
2216
+ * const executeTask = defineCommandConsumer(taskQueue, fanoutExchange, taskMessage);
2217
+ * const sendTask = defineCommandPublisher(executeTask);
2218
+ * ```
2219
+ */
2220
+ declare function defineCommandPublisher<TMessage extends MessageDefinition>(commandConsumer: CommandConsumerConfig<TMessage, FanoutExchangeDefinition, undefined>): {
2221
+ message: TMessage;
2222
+ exchange: FanoutExchangeDefinition;
2223
+ };
2224
+ /**
2225
+ * Create a publisher that sends commands to a direct exchange consumer.
2226
+ *
2227
+ * @param commandConsumer - The command consumer configuration
2228
+ * @returns A publisher definition
2229
+ */
2230
+ declare function defineCommandPublisher<TMessage extends MessageDefinition, TRoutingKey extends string>(commandConsumer: CommandConsumerConfig<TMessage, DirectExchangeDefinition, TRoutingKey>): {
2231
+ message: TMessage;
2232
+ exchange: DirectExchangeDefinition;
2233
+ routingKey: string;
2234
+ };
2235
+ /**
2236
+ * Create a publisher that sends commands to a topic exchange consumer.
2237
+ *
2238
+ * For topic exchanges where the consumer uses a pattern, the publisher can
2239
+ * optionally specify a concrete routing key that matches the pattern.
2240
+ *
2241
+ * @param commandConsumer - The command consumer configuration
2242
+ * @param options - Optional publisher configuration
2243
+ * @param options.routingKey - Override routing key (must match consumer's pattern)
2244
+ * @returns A publisher definition
2245
+ *
2246
+ * @example
2247
+ * ```typescript
2248
+ * // Consumer binds with pattern
2249
+ * const processOrder = defineCommandConsumer(orderQueue, topicExchange, orderMessage, {
2250
+ * routingKey: 'order.*',
2251
+ * });
2252
+ *
2253
+ * // Publisher uses concrete key matching the pattern
2254
+ * const createOrder = defineCommandPublisher(processOrder, {
2255
+ * routingKey: 'order.create',
2256
+ * });
2257
+ * ```
2258
+ */
2259
+ declare function defineCommandPublisher<TMessage extends MessageDefinition, TRoutingKey extends string, TPublisherRoutingKey extends string = TRoutingKey>(commandConsumer: CommandConsumerConfig<TMessage, TopicExchangeDefinition, TRoutingKey>, options?: {
2260
+ routingKey?: RoutingKey<TPublisherRoutingKey>;
2261
+ }): {
2262
+ message: TMessage;
1936
2263
  exchange: TopicExchangeDefinition;
1937
- }>>;
2264
+ routingKey: string;
2265
+ };
2266
+ /**
2267
+ * Type guard to check if a value is a CommandConsumerConfig.
2268
+ *
2269
+ * @param value - The value to check
2270
+ * @returns True if the value is a CommandConsumerConfig
2271
+ */
2272
+ declare function isCommandConsumerConfig(value: unknown): value is CommandConsumerConfig<MessageDefinition, ExchangeDefinition, string | undefined>;
1938
2273
  //#endregion
1939
2274
  //#region src/builder/ttl-backoff.d.ts
1940
2275
  /**
@@ -2011,5 +2346,5 @@ declare function defineTtlBackoffRetryInfrastructure(queueEntry: QueueEntry, opt
2011
2346
  waitQueueDurable?: boolean;
2012
2347
  }): TtlBackoffRetryInfrastructure;
2013
2348
  //#endregion
2014
- export { type AnySchema, type BaseExchangeDefinition, type BindingDefinition, type BindingPattern, type ClassicQueueDefinition, type ClassicQueueOptions, type CompressionAlgorithm, type ConsumerDefinition, type ConsumerFirstResult, type ConsumerFirstResultWithRoutingKey, type ContractDefinition, type DeadLetterConfig, type DefineQueueOptions, type DirectExchangeDefinition, type ExchangeBindingDefinition, type ExchangeDefinition, type FanoutExchangeDefinition, type InferConsumerNames, type InferPublisherNames, type MatchingRoutingKey, type MessageDefinition, type PublisherDefinition, type PublisherFirstResult, type PublisherFirstResultWithRoutingKey, type QueueBindingDefinition, type QueueDefinition, type QueueEntry, type QueueType, type QueueWithTtlBackoffInfrastructure, type QuorumNativeRetryOptions, type QuorumQueueDefinition, type QuorumQueueOptions, type ResolvedRetryOptions, type ResolvedTtlBackoffRetryOptions, type RoutingKey, type TopicExchangeDefinition, type TtlBackoffRetryInfrastructure, type TtlBackoffRetryOptions, defineConsumer, defineConsumerFirst, defineContract, defineExchange, defineExchangeBinding, defineMessage, definePublisher, definePublisherFirst, defineQueue, defineQueueBinding, defineTtlBackoffRetryInfrastructure, extractQueue };
2349
+ export { type AnySchema, type BaseExchangeDefinition, type BindingDefinition, type BindingPattern, type ClassicQueueDefinition, type ClassicQueueOptions, type CommandConsumerConfig, type CommandConsumerConfigBase, type CompressionAlgorithm, type ConsumerDefinition, type ConsumerEntry, type ContractDefinition, type ContractDefinitionInput, type DeadLetterConfig, type DefineQueueOptions, type DefineQuorumQueueOptions, type DefineTtlBackoffQueueOptions, type DirectExchangeDefinition, type EventConsumerResult, type EventConsumerResultBase, type EventPublisherConfig, type EventPublisherConfigBase, type ExchangeBindingDefinition, type ExchangeDefinition, type FanoutExchangeDefinition, type InferConsumerNames, type InferPublisherNames, type MatchingRoutingKey, type MessageDefinition, type PublisherDefinition, type PublisherEntry, type QueueBindingDefinition, type QueueDefinition, type QueueEntry, type QueueType, type QueueWithTtlBackoffInfrastructure, type QuorumNativeRetryOptions, type QuorumQueueDefinition, type QuorumQueueOptions, type ResolvedRetryOptions, type ResolvedTtlBackoffRetryOptions, type RoutingKey, type TopicExchangeDefinition, type TtlBackoffRetryInfrastructure, type TtlBackoffRetryOptions, defineCommandConsumer, defineCommandPublisher, defineConsumer, defineContract, defineEventConsumer, defineEventPublisher, defineExchange, defineExchangeBinding, defineMessage, definePublisher, defineQueue, defineQueueBinding, defineQuorumQueue, defineTtlBackoffQueue, defineTtlBackoffRetryInfrastructure, extractQueue, isCommandConsumerConfig, isEventConsumerResult, isEventPublisherConfig, isQueueWithTtlBackoffInfrastructure };
2015
2350
  //# sourceMappingURL=index.d.mts.map