@amqp-contract/contract 0.4.0 → 0.6.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 +19 -7
- package/dist/index.cjs +43 -3
- package/dist/index.d.cts +344 -45
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +344 -45
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +43 -3
- package/dist/index.mjs.map +1 -1
- package/docs/index.md +258 -62
- package/package.json +2 -2
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/builder.ts"],"sourcesContent":[],"mappings":";;;;;;AAWA;AAQA;AA6CA;AAiBA;AAqBA;AASA;;AAEI,KAtGQ,SAAA,GAAY,gBAsGpB;;;
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/builder.ts"],"sourcesContent":[],"mappings":"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"}
|
package/dist/index.mjs
CHANGED
|
@@ -30,16 +30,27 @@ function defineExchange(name, type, options) {
|
|
|
30
30
|
* @param options.durable - If true, the queue survives broker restarts (default: false)
|
|
31
31
|
* @param options.exclusive - If true, the queue can only be used by the declaring connection (default: false)
|
|
32
32
|
* @param options.autoDelete - If true, the queue is deleted when the last consumer unsubscribes (default: false)
|
|
33
|
-
* @param options.
|
|
33
|
+
* @param options.deadLetter - Dead letter configuration for handling failed messages
|
|
34
|
+
* @param options.arguments - Additional AMQP arguments (e.g., x-message-ttl, x-max-priority)
|
|
34
35
|
* @returns A queue definition
|
|
35
36
|
*
|
|
36
37
|
* @example
|
|
37
38
|
* ```typescript
|
|
38
|
-
*
|
|
39
|
+
* // Basic queue
|
|
40
|
+
* const orderQueue = defineQueue('order-processing', {
|
|
39
41
|
* durable: true,
|
|
42
|
+
* });
|
|
43
|
+
*
|
|
44
|
+
* // Queue with dead letter exchange
|
|
45
|
+
* const dlx = defineExchange('orders-dlx', 'topic', { durable: true });
|
|
46
|
+
* const orderQueueWithDLX = defineQueue('order-processing', {
|
|
47
|
+
* durable: true,
|
|
48
|
+
* deadLetter: {
|
|
49
|
+
* exchange: dlx,
|
|
50
|
+
* routingKey: 'order.failed'
|
|
51
|
+
* },
|
|
40
52
|
* arguments: {
|
|
41
53
|
* 'x-message-ttl': 86400000, // 24 hours
|
|
42
|
-
* 'x-dead-letter-exchange': 'orders-dlx'
|
|
43
54
|
* }
|
|
44
55
|
* });
|
|
45
56
|
* ```
|
|
@@ -310,6 +321,22 @@ function callDefineQueueBinding(queue, exchange, options) {
|
|
|
310
321
|
*/
|
|
311
322
|
function definePublisherFirst(exchange, message, options) {
|
|
312
323
|
const publisher = callDefinePublisher(exchange, message, options);
|
|
324
|
+
if (exchange.type === "topic") {
|
|
325
|
+
const createConsumer$1 = (queue, routingKey) => {
|
|
326
|
+
const binding = callDefineQueueBinding(queue, exchange, routingKey ? {
|
|
327
|
+
...options,
|
|
328
|
+
routingKey
|
|
329
|
+
} : options);
|
|
330
|
+
return {
|
|
331
|
+
consumer: defineConsumer(queue, message),
|
|
332
|
+
binding
|
|
333
|
+
};
|
|
334
|
+
};
|
|
335
|
+
return {
|
|
336
|
+
publisher,
|
|
337
|
+
createConsumer: createConsumer$1
|
|
338
|
+
};
|
|
339
|
+
}
|
|
313
340
|
const createConsumer = (queue) => {
|
|
314
341
|
const binding = callDefineQueueBinding(queue, exchange, options);
|
|
315
342
|
return {
|
|
@@ -329,6 +356,19 @@ function definePublisherFirst(exchange, message, options) {
|
|
|
329
356
|
function defineConsumerFirst(queue, exchange, message, options) {
|
|
330
357
|
const consumer = defineConsumer(queue, message);
|
|
331
358
|
const binding = callDefineQueueBinding(queue, exchange, options);
|
|
359
|
+
if (exchange.type === "topic") {
|
|
360
|
+
const createPublisher$1 = (routingKey) => {
|
|
361
|
+
return callDefinePublisher(exchange, message, {
|
|
362
|
+
...options,
|
|
363
|
+
routingKey
|
|
364
|
+
});
|
|
365
|
+
};
|
|
366
|
+
return {
|
|
367
|
+
consumer,
|
|
368
|
+
binding,
|
|
369
|
+
createPublisher: createPublisher$1
|
|
370
|
+
};
|
|
371
|
+
}
|
|
332
372
|
const createPublisher = () => {
|
|
333
373
|
return callDefinePublisher(exchange, message, options);
|
|
334
374
|
};
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../src/builder.ts"],"sourcesContent":["import type {\n BaseExchangeDefinition,\n ConsumerDefinition,\n ContractDefinition,\n DirectExchangeDefinition,\n ExchangeBindingDefinition,\n ExchangeDefinition,\n FanoutExchangeDefinition,\n MessageDefinition,\n PublisherDefinition,\n QueueBindingDefinition,\n QueueDefinition,\n TopicExchangeDefinition,\n} from \"./types.js\";\nimport type { StandardSchemaV1 } from \"@standard-schema/spec\";\n\n/**\n * Define a fanout exchange.\n *\n * A fanout exchange routes messages to all bound queues without considering routing keys.\n * This exchange type is ideal for broadcasting messages to multiple consumers.\n *\n * @param name - The name of the exchange\n * @param type - Must be \"fanout\"\n * @param options - Optional exchange configuration\n * @param options.durable - If true, the exchange survives broker restarts (default: false)\n * @param options.autoDelete - If true, the exchange is deleted when no queues are bound (default: false)\n * @param options.internal - If true, the exchange cannot be directly published to (default: false)\n * @param options.arguments - Additional AMQP arguments for the exchange\n * @returns A fanout exchange definition\n *\n * @example\n * ```typescript\n * const logsExchange = defineExchange('logs', 'fanout', {\n * durable: true\n * });\n * ```\n */\nexport function defineExchange(\n name: string,\n type: \"fanout\",\n options?: Omit<BaseExchangeDefinition, \"name\" | \"type\">,\n): FanoutExchangeDefinition;\n\n/**\n * Define a direct exchange.\n *\n * A direct exchange routes messages to queues based on exact routing key matches.\n * This exchange type is ideal for point-to-point messaging.\n *\n * @param name - The name of the exchange\n * @param type - Must be \"direct\"\n * @param options - Optional exchange configuration\n * @param options.durable - If true, the exchange survives broker restarts (default: false)\n * @param options.autoDelete - If true, the exchange is deleted when no queues are bound (default: false)\n * @param options.internal - If true, the exchange cannot be directly published to (default: false)\n * @param options.arguments - Additional AMQP arguments for the exchange\n * @returns A direct exchange definition\n *\n * @example\n * ```typescript\n * const tasksExchange = defineExchange('tasks', 'direct', {\n * durable: true\n * });\n * ```\n */\nexport function defineExchange(\n name: string,\n type: \"direct\",\n options?: Omit<BaseExchangeDefinition, \"name\" | \"type\">,\n): DirectExchangeDefinition;\n\n/**\n * Define a topic exchange.\n *\n * A topic exchange routes messages to queues based on routing key patterns.\n * Routing keys can use wildcards: `*` matches one word, `#` matches zero or more words.\n * This exchange type is ideal for flexible message routing based on hierarchical topics.\n *\n * @param name - The name of the exchange\n * @param type - Must be \"topic\"\n * @param options - Optional exchange configuration\n * @param options.durable - If true, the exchange survives broker restarts (default: false)\n * @param options.autoDelete - If true, the exchange is deleted when no queues are bound (default: false)\n * @param options.internal - If true, the exchange cannot be directly published to (default: false)\n * @param options.arguments - Additional AMQP arguments for the exchange\n * @returns A topic exchange definition\n *\n * @example\n * ```typescript\n * const ordersExchange = defineExchange('orders', 'topic', {\n * durable: true\n * });\n * ```\n */\nexport function defineExchange(\n name: string,\n type: \"topic\",\n options?: Omit<BaseExchangeDefinition, \"name\" | \"type\">,\n): TopicExchangeDefinition;\n\n/**\n * Define an AMQP exchange.\n *\n * An exchange receives messages from publishers and routes them to queues based on the exchange type\n * and routing rules. This is the implementation function - use the type-specific overloads for better\n * type safety.\n *\n * @param name - The name of the exchange\n * @param type - The type of exchange: \"fanout\", \"direct\", or \"topic\"\n * @param options - Optional exchange configuration\n * @returns An exchange definition\n * @internal\n */\nexport function defineExchange(\n name: string,\n type: \"fanout\" | \"direct\" | \"topic\",\n options?: Omit<BaseExchangeDefinition, \"name\" | \"type\">,\n): ExchangeDefinition {\n return {\n name,\n type,\n ...options,\n };\n}\n\n/**\n * Define an AMQP queue.\n *\n * A queue stores messages until they are consumed by workers. Queues can be bound to exchanges\n * to receive messages based on routing rules.\n *\n * @param name - The name of the queue\n * @param options - Optional queue configuration\n * @param options.durable - If true, the queue survives broker restarts (default: false)\n * @param options.exclusive - If true, the queue can only be used by the declaring connection (default: false)\n * @param options.autoDelete - If true, the queue is deleted when the last consumer unsubscribes (default: false)\n * @param options.arguments - Additional AMQP arguments (e.g., x-message-ttl, x-dead-letter-exchange)\n * @returns A queue definition\n *\n * @example\n * ```typescript\n * const orderProcessingQueue = defineQueue('order-processing', {\n * durable: true,\n * arguments: {\n * 'x-message-ttl': 86400000, // 24 hours\n * 'x-dead-letter-exchange': 'orders-dlx'\n * }\n * });\n * ```\n */\nexport function defineQueue(\n name: string,\n options?: Omit<QueueDefinition, \"name\">,\n): QueueDefinition {\n return {\n name,\n ...options,\n };\n}\n\n/**\n * Define a message definition with payload and optional headers/metadata.\n *\n * A message definition specifies the schema for message payloads and headers using\n * Standard Schema v1 compatible libraries (Zod, Valibot, ArkType, etc.).\n * The schemas are used for automatic validation when publishing or consuming messages.\n *\n * @param payload - The payload schema (must be Standard Schema v1 compatible)\n * @param options - Optional message metadata\n * @param options.headers - Optional header schema for message headers\n * @param options.summary - Brief description for documentation (used in AsyncAPI generation)\n * @param options.description - Detailed description for documentation (used in AsyncAPI generation)\n * @returns A message definition with inferred types\n *\n * @example\n * ```typescript\n * import { z } from 'zod';\n *\n * const orderMessage = defineMessage(\n * z.object({\n * orderId: z.string().uuid(),\n * customerId: z.string().uuid(),\n * amount: z.number().positive(),\n * items: z.array(z.object({\n * productId: z.string(),\n * quantity: z.number().int().positive(),\n * })),\n * }),\n * {\n * summary: 'Order created event',\n * description: 'Emitted when a new order is created in the system'\n * }\n * );\n * ```\n */\nexport function defineMessage<\n TPayload extends MessageDefinition[\"payload\"],\n THeaders extends StandardSchemaV1<Record<string, unknown>> | undefined = undefined,\n>(\n payload: TPayload,\n options?: {\n headers?: THeaders;\n summary?: string;\n description?: string;\n },\n): MessageDefinition<TPayload, THeaders> {\n return {\n payload,\n ...options,\n };\n}\n\n/**\n * Define a binding between a queue and a fanout exchange.\n *\n * Binds a queue to a fanout exchange to receive all messages published to the exchange.\n * Fanout exchanges ignore routing keys, so this overload doesn't require one.\n *\n * @param queue - The queue definition to bind\n * @param exchange - The fanout exchange definition\n * @param options - Optional binding configuration\n * @param options.arguments - Additional AMQP arguments for the binding\n * @returns A queue binding definition\n *\n * @example\n * ```typescript\n * const logsQueue = defineQueue('logs-queue', { durable: true });\n * const logsExchange = defineExchange('logs', 'fanout', { durable: true });\n *\n * const binding = defineQueueBinding(logsQueue, logsExchange);\n * ```\n */\nexport function defineQueueBinding(\n queue: QueueDefinition,\n exchange: FanoutExchangeDefinition,\n options?: Omit<\n Extract<QueueBindingDefinition, { exchange: FanoutExchangeDefinition }>,\n \"type\" | \"queue\" | \"exchange\" | \"routingKey\"\n >,\n): Extract<QueueBindingDefinition, { exchange: FanoutExchangeDefinition }>;\n\n/**\n * Define a binding between a queue and a direct or topic exchange.\n *\n * Binds a queue to an exchange with a specific routing key pattern.\n * Messages are only routed to the queue if the routing key matches the pattern.\n *\n * For direct exchanges: The routing key must match exactly.\n * For topic exchanges: The routing key can include wildcards:\n * - `*` matches exactly one word\n * - `#` matches zero or more words\n *\n * @param queue - The queue definition to bind\n * @param exchange - The direct or topic exchange definition\n * @param options - Binding configuration (routingKey is required)\n * @param options.routingKey - The routing key pattern for message routing\n * @param options.arguments - Additional AMQP arguments for the binding\n * @returns A queue binding definition\n *\n * @example\n * ```typescript\n * const orderQueue = defineQueue('order-processing', { durable: true });\n * const ordersExchange = defineExchange('orders', 'topic', { durable: true });\n *\n * // Bind with exact routing key\n * const binding = defineQueueBinding(orderQueue, ordersExchange, {\n * routingKey: 'order.created'\n * });\n *\n * // Bind with wildcard pattern\n * const allOrdersBinding = defineQueueBinding(orderQueue, ordersExchange, {\n * routingKey: 'order.*' // Matches order.created, order.updated, etc.\n * });\n * ```\n */\nexport function defineQueueBinding(\n queue: QueueDefinition,\n exchange: DirectExchangeDefinition | TopicExchangeDefinition,\n options: Omit<\n Extract<\n QueueBindingDefinition,\n { exchange: DirectExchangeDefinition | TopicExchangeDefinition }\n >,\n \"type\" | \"queue\" | \"exchange\"\n >,\n): Extract<\n QueueBindingDefinition,\n { exchange: DirectExchangeDefinition | TopicExchangeDefinition }\n>;\n\n/**\n * Define a binding between a queue and an exchange.\n *\n * This is the implementation function - use the type-specific overloads for better type safety.\n *\n * @param queue - The queue definition to bind\n * @param exchange - The exchange definition\n * @param options - Optional binding configuration\n * @returns A queue binding definition\n * @internal\n */\nexport function defineQueueBinding(\n queue: QueueDefinition,\n exchange: ExchangeDefinition,\n options?: {\n routingKey?: string;\n arguments?: Record<string, unknown>;\n },\n): QueueBindingDefinition {\n if (exchange.type === \"fanout\") {\n return {\n type: \"queue\",\n queue,\n exchange,\n ...(options?.arguments && { arguments: options.arguments }),\n } as QueueBindingDefinition;\n }\n\n return {\n type: \"queue\",\n queue,\n exchange,\n routingKey: options?.routingKey,\n ...(options?.arguments && { arguments: options.arguments }),\n } as QueueBindingDefinition;\n}\n\n/**\n * Define a binding between two exchanges (exchange-to-exchange routing).\n *\n * Binds a destination exchange to a fanout source exchange.\n * Messages published to the source exchange will be forwarded to the destination exchange.\n * Fanout exchanges ignore routing keys, so this overload doesn't require one.\n *\n * @param destination - The destination exchange definition\n * @param source - The fanout source exchange definition\n * @param options - Optional binding configuration\n * @param options.arguments - Additional AMQP arguments for the binding\n * @returns An exchange binding definition\n *\n * @example\n * ```typescript\n * const sourceExchange = defineExchange('logs', 'fanout', { durable: true });\n * const destExchange = defineExchange('all-logs', 'fanout', { durable: true });\n *\n * const binding = defineExchangeBinding(destExchange, sourceExchange);\n * ```\n */\nexport function defineExchangeBinding(\n destination: ExchangeDefinition,\n source: FanoutExchangeDefinition,\n options?: Omit<\n Extract<ExchangeBindingDefinition, { source: FanoutExchangeDefinition }>,\n \"type\" | \"source\" | \"destination\" | \"routingKey\"\n >,\n): Extract<ExchangeBindingDefinition, { source: FanoutExchangeDefinition }>;\n\n/**\n * Define a binding between two exchanges (exchange-to-exchange routing).\n *\n * Binds a destination exchange to a direct or topic source exchange with a routing key pattern.\n * Messages are forwarded from source to destination only if the routing key matches the pattern.\n *\n * @param destination - The destination exchange definition\n * @param source - The direct or topic source exchange definition\n * @param options - Binding configuration (routingKey is required)\n * @param options.routingKey - The routing key pattern for message routing\n * @param options.arguments - Additional AMQP arguments for the binding\n * @returns An exchange binding definition\n *\n * @example\n * ```typescript\n * const ordersExchange = defineExchange('orders', 'topic', { durable: true });\n * const importantExchange = defineExchange('important-orders', 'topic', { durable: true });\n *\n * // Forward only high-value orders\n * const binding = defineExchangeBinding(importantExchange, ordersExchange, {\n * routingKey: 'order.high-value.*'\n * });\n * ```\n */\nexport function defineExchangeBinding(\n destination: ExchangeDefinition,\n source: DirectExchangeDefinition | TopicExchangeDefinition,\n options: Omit<\n Extract<\n ExchangeBindingDefinition,\n { source: DirectExchangeDefinition | TopicExchangeDefinition }\n >,\n \"type\" | \"source\" | \"destination\"\n >,\n): Extract<\n ExchangeBindingDefinition,\n { source: DirectExchangeDefinition | TopicExchangeDefinition }\n>;\n\n/**\n * Define a binding between two exchanges (exchange-to-exchange routing).\n *\n * This is the implementation function - use the type-specific overloads for better type safety.\n *\n * @param destination - The destination exchange definition\n * @param source - The source exchange definition\n * @param options - Optional binding configuration\n * @returns An exchange binding definition\n * @internal\n */\nexport function defineExchangeBinding(\n destination: ExchangeDefinition,\n source: ExchangeDefinition,\n options?: {\n routingKey?: string;\n arguments?: Record<string, unknown>;\n },\n): ExchangeBindingDefinition {\n if (source.type === \"fanout\") {\n return {\n type: \"exchange\",\n source,\n destination,\n ...(options?.arguments && { arguments: options.arguments }),\n } as ExchangeBindingDefinition;\n }\n\n return {\n type: \"exchange\",\n source,\n destination,\n routingKey: options?.routingKey ?? \"\",\n ...(options?.arguments && { arguments: options.arguments }),\n } as ExchangeBindingDefinition;\n}\n\n/**\n * Define a message publisher for a fanout exchange.\n *\n * A publisher sends messages to an exchange. For fanout exchanges, messages are broadcast\n * to all bound queues regardless of routing key, so no routing key is required.\n *\n * The message schema is validated when publishing to ensure type safety.\n *\n * @param exchange - The fanout exchange definition to publish to\n * @param message - The message definition with payload schema\n * @param options - Optional publisher configuration\n * @returns A publisher definition with inferred message types\n *\n * @example\n * ```typescript\n * import { z } from 'zod';\n *\n * const logsExchange = defineExchange('logs', 'fanout', { durable: true });\n * const logMessage = defineMessage(\n * z.object({\n * level: z.enum(['info', 'warn', 'error']),\n * message: z.string(),\n * timestamp: z.string().datetime(),\n * })\n * );\n *\n * const logPublisher = definePublisher(logsExchange, logMessage);\n * ```\n */\nexport function definePublisher<TMessage extends MessageDefinition>(\n exchange: FanoutExchangeDefinition,\n message: TMessage,\n options?: Omit<\n Extract<PublisherDefinition<TMessage>, { exchange: FanoutExchangeDefinition }>,\n \"exchange\" | \"message\" | \"routingKey\"\n >,\n): Extract<PublisherDefinition<TMessage>, { exchange: FanoutExchangeDefinition }>;\n\n/**\n * Define a message publisher for a direct or topic exchange.\n *\n * A publisher sends messages to an exchange with a specific routing key.\n * The routing key determines which queues receive the message.\n *\n * The message schema is validated when publishing to ensure type safety.\n *\n * @param exchange - The direct or topic exchange definition to publish to\n * @param message - The message definition with payload schema\n * @param options - Publisher configuration (routingKey is required)\n * @param options.routingKey - The routing key for message routing\n * @returns A publisher definition with inferred message types\n *\n * @example\n * ```typescript\n * import { z } from 'zod';\n *\n * const ordersExchange = defineExchange('orders', 'topic', { durable: true });\n * const orderMessage = defineMessage(\n * z.object({\n * orderId: z.string().uuid(),\n * amount: z.number().positive(),\n * }),\n * {\n * summary: 'Order created event',\n * description: 'Emitted when a new order is created'\n * }\n * );\n *\n * const orderCreatedPublisher = definePublisher(ordersExchange, orderMessage, {\n * routingKey: 'order.created'\n * });\n * ```\n */\nexport function definePublisher<TMessage extends MessageDefinition>(\n exchange: DirectExchangeDefinition | TopicExchangeDefinition,\n message: TMessage,\n options: Omit<\n Extract<\n PublisherDefinition<TMessage>,\n { exchange: DirectExchangeDefinition | TopicExchangeDefinition }\n >,\n \"exchange\" | \"message\"\n >,\n): Extract<\n PublisherDefinition<TMessage>,\n { exchange: DirectExchangeDefinition | TopicExchangeDefinition }\n>;\n\n/**\n * Define a message publisher.\n *\n * This is the implementation function - use the type-specific overloads for better type safety.\n *\n * @param exchange - The exchange definition\n * @param message - The message definition\n * @param options - Optional publisher configuration\n * @returns A publisher definition\n * @internal\n */\nexport function definePublisher<TMessage extends MessageDefinition>(\n exchange: ExchangeDefinition,\n message: TMessage,\n options?: { routingKey?: string },\n): PublisherDefinition<TMessage> {\n if (exchange.type === \"fanout\") {\n return {\n exchange,\n message,\n } as PublisherDefinition<TMessage>;\n }\n\n return {\n exchange,\n message,\n routingKey: options?.routingKey ?? \"\",\n } as PublisherDefinition<TMessage>;\n}\n\n/**\n * Define a message consumer.\n *\n * A consumer receives and processes messages from a queue. The message schema is validated\n * automatically when messages are consumed, ensuring type safety for your handlers.\n *\n * Consumers are associated with a specific queue and message type. When you create a worker\n * with this consumer, it will process messages from the queue according to the schema.\n *\n * @param queue - The queue definition to consume from\n * @param message - The message definition with payload schema\n * @param options - Optional consumer configuration\n * @returns A consumer definition with inferred message types\n *\n * @example\n * ```typescript\n * import { z } from 'zod';\n *\n * const orderQueue = defineQueue('order-processing', { durable: true });\n * const orderMessage = defineMessage(\n * z.object({\n * orderId: z.string().uuid(),\n * customerId: z.string().uuid(),\n * amount: z.number().positive(),\n * })\n * );\n *\n * const processOrderConsumer = defineConsumer(orderQueue, orderMessage);\n *\n * // Later, when creating a worker, you'll provide a handler for this consumer:\n * // const worker = await TypedAmqpWorker.create({\n * // contract,\n * // handlers: {\n * // processOrder: async (message) => {\n * // // message is automatically typed based on the schema\n * // console.log(message.orderId); // string\n * // }\n * // },\n * // connection\n * // });\n * ```\n */\nexport function defineConsumer<TMessage extends MessageDefinition>(\n queue: QueueDefinition,\n message: TMessage,\n options?: Omit<ConsumerDefinition<TMessage>, \"queue\" | \"message\">,\n): ConsumerDefinition<TMessage> {\n return {\n queue,\n message,\n ...options,\n };\n}\n\n/**\n * Define an AMQP contract.\n *\n * A contract is the central definition of your AMQP messaging topology. It brings together\n * all exchanges, queues, bindings, publishers, and consumers in a single, type-safe definition.\n *\n * The contract is used by both clients (for publishing) and workers (for consuming) to ensure\n * type safety throughout your messaging infrastructure. TypeScript will infer all message types\n * and publisher/consumer names from the contract.\n *\n * @param definition - The contract definition containing all AMQP resources\n * @param definition.exchanges - Named exchange definitions\n * @param definition.queues - Named queue definitions\n * @param definition.bindings - Named binding definitions (queue-to-exchange or exchange-to-exchange)\n * @param definition.publishers - Named publisher definitions for sending messages\n * @param definition.consumers - Named consumer definitions for receiving messages\n * @returns The same contract definition with full type inference\n *\n * @example\n * ```typescript\n * import {\n * defineContract,\n * defineExchange,\n * defineQueue,\n * defineQueueBinding,\n * definePublisher,\n * defineConsumer,\n * defineMessage,\n * } from '@amqp-contract/contract';\n * import { z } from 'zod';\n *\n * // Define resources\n * const ordersExchange = defineExchange('orders', 'topic', { durable: true });\n * const orderQueue = defineQueue('order-processing', { durable: true });\n * const orderMessage = defineMessage(\n * z.object({\n * orderId: z.string(),\n * amount: z.number(),\n * })\n * );\n *\n * // Compose contract\n * export const contract = defineContract({\n * exchanges: {\n * orders: ordersExchange,\n * },\n * queues: {\n * orderProcessing: orderQueue,\n * },\n * bindings: {\n * orderBinding: defineQueueBinding(orderQueue, ordersExchange, {\n * routingKey: 'order.created',\n * }),\n * },\n * publishers: {\n * orderCreated: definePublisher(ordersExchange, orderMessage, {\n * routingKey: 'order.created',\n * }),\n * },\n * consumers: {\n * processOrder: defineConsumer(orderQueue, orderMessage),\n * },\n * });\n *\n * // TypeScript now knows:\n * // - client.publish('orderCreated', { orderId: string, amount: number })\n * // - handler: async (message: { orderId: string, amount: number }) => void\n * ```\n */\nexport function defineContract<TContract extends ContractDefinition>(\n definition: TContract,\n): TContract {\n return definition;\n}\n\n/**\n * Helper to call definePublisher with proper type handling.\n * Type safety is enforced by overloaded public function signatures.\n * @internal\n */\nfunction callDefinePublisher<TMessage extends MessageDefinition>(\n exchange: ExchangeDefinition,\n message: TMessage,\n options?: {\n routingKey?: string;\n arguments?: Record<string, unknown>;\n },\n): PublisherDefinition<TMessage> {\n // Type assertion is safe because overloaded signatures enforce routingKey requirement\n if (exchange.type === \"fanout\") {\n return definePublisher(exchange, message, options);\n }\n return definePublisher(exchange, message, options as { routingKey: string });\n}\n\n/**\n * Helper to call defineQueueBinding with proper type handling.\n * Type safety is enforced by overloaded public function signatures.\n * @internal\n */\nfunction callDefineQueueBinding(\n queue: QueueDefinition,\n exchange: ExchangeDefinition,\n options?: {\n routingKey?: string;\n arguments?: Record<string, unknown>;\n },\n): QueueBindingDefinition {\n // Type assertion is safe because overloaded signatures enforce routingKey requirement\n if (exchange.type === \"fanout\") {\n return defineQueueBinding(queue, exchange, options);\n }\n return defineQueueBinding(queue, exchange, options as { routingKey: string });\n}\n\n/**\n * Publisher-first builder result.\n *\n * This type represents a publisher and provides a method to create\n * a consumer that uses the same message schema with a binding to the exchange.\n *\n * This pattern is suitable for event-oriented messaging where publishers\n * emit events without knowing which queues will consume them.\n *\n * @template TMessage - The message definition\n * @template TPublisher - The publisher definition\n */\nexport type PublisherFirstResult<\n TMessage extends MessageDefinition,\n TPublisher extends PublisherDefinition<TMessage>,\n> = {\n /** The publisher definition */\n publisher: TPublisher;\n /**\n * Create a consumer that receives messages from this publisher.\n * The consumer will automatically use the same message schema and\n * a binding will be created with the same routing key.\n *\n * @param queue - The queue that will consume the messages\n * @returns An object with the consumer definition and binding\n */\n createConsumer: (queue: QueueDefinition) => {\n consumer: ConsumerDefinition<TMessage>;\n binding: QueueBindingDefinition;\n };\n};\n\n/**\n * Define a publisher-first relationship for event-oriented messaging.\n *\n * This builder enforces consistency by:\n * 1. Ensuring the publisher and consumer use the same message schema\n * 2. Linking the routing key from the publisher to the binding\n *\n * Use this pattern for events where publishers don't need to know about queues.\n * Multiple consumers can be created for different queues, all using the same message schema.\n *\n * @param exchange - The exchange to publish to (fanout type)\n * @param message - The message definition (schema and metadata)\n * @param options - Optional binding configuration\n * @returns A publisher-first result with publisher and consumer factory\n *\n * @example\n * ```typescript\n * import { z } from 'zod';\n *\n * const logsExchange = defineExchange('logs', 'fanout', { durable: true });\n * const logMessage = defineMessage(\n * z.object({\n * level: z.enum(['info', 'warn', 'error']),\n * message: z.string(),\n * })\n * );\n *\n * // Create publisher-first relationship (event pattern)\n * const logEvent = definePublisherFirst(logsExchange, logMessage);\n *\n * // Multiple queues can consume the same event\n * const logsQueue1 = defineQueue('logs-queue-1', { durable: true });\n * const logsQueue2 = defineQueue('logs-queue-2', { durable: true });\n *\n * // Use in contract\n * const { consumer: consumer1, binding: binding1 } = logEvent.createConsumer(logsQueue1);\n * const { consumer: consumer2, binding: binding2 } = logEvent.createConsumer(logsQueue2);\n *\n * const contract = defineContract({\n * exchanges: { logs: logsExchange },\n * queues: { logsQueue1, logsQueue2 },\n * bindings: {\n * logBinding1: binding1,\n * logBinding2: binding2,\n * },\n * publishers: { publishLog: logEvent.publisher },\n * consumers: {\n * consumeLog1: consumer1,\n * consumeLog2: consumer2,\n * },\n * });\n * ```\n */\nexport function definePublisherFirst<TMessage extends MessageDefinition>(\n exchange: FanoutExchangeDefinition,\n message: TMessage,\n options?: Omit<\n Extract<QueueBindingDefinition, { exchange: FanoutExchangeDefinition }>,\n \"type\" | \"queue\" | \"exchange\" | \"routingKey\"\n >,\n): PublisherFirstResult<\n TMessage,\n Extract<PublisherDefinition<TMessage>, { exchange: FanoutExchangeDefinition }>\n>;\n\n/**\n * Define a publisher-first relationship for event-oriented messaging.\n *\n * This builder enforces consistency by:\n * 1. Ensuring the publisher and consumer use the same message schema\n * 2. Linking the routing key from the publisher to the binding\n *\n * Use this pattern for events where publishers don't need to know about queues.\n * Multiple consumers can be created for different queues, all using the same message schema.\n *\n * @param exchange - The exchange to publish to (direct or topic type)\n * @param message - The message definition (schema and metadata)\n * @param options - Binding configuration (routingKey is required)\n * @param options.routingKey - The routing key for message routing\n * @returns A publisher-first result with publisher and consumer factory\n *\n * @example\n * ```typescript\n * import { z } from 'zod';\n *\n * const ordersExchange = defineExchange('orders', 'topic', { durable: true });\n * const orderMessage = defineMessage(\n * z.object({\n * orderId: z.string(),\n * amount: z.number(),\n * })\n * );\n *\n * // Create publisher-first relationship with routing key (event pattern)\n * const orderCreatedEvent = definePublisherFirst(\n * ordersExchange,\n * orderMessage,\n * { routingKey: 'order.created' }\n * );\n *\n * // Multiple queues can consume the same event\n * const orderQueue = defineQueue('order-processing', { durable: true });\n * const analyticsQueue = defineQueue('analytics', { durable: true });\n *\n * // Use in contract - routing key is consistent across publisher and bindings\n * const { consumer: processConsumer, binding: processBinding } = orderCreatedEvent.createConsumer(orderQueue);\n * const { consumer: analyticsConsumer, binding: analyticsBinding } = orderCreatedEvent.createConsumer(analyticsQueue);\n *\n * const contract = defineContract({\n * exchanges: { orders: ordersExchange },\n * queues: { orderQueue, analyticsQueue },\n * bindings: {\n * orderBinding: processBinding,\n * analyticsBinding,\n * },\n * publishers: { orderCreated: orderCreatedEvent.publisher },\n * consumers: {\n * processOrder: processConsumer,\n * trackOrder: analyticsConsumer,\n * },\n * });\n * ```\n */\nexport function definePublisherFirst<TMessage extends MessageDefinition>(\n exchange: DirectExchangeDefinition | TopicExchangeDefinition,\n message: TMessage,\n options: Omit<\n Extract<\n QueueBindingDefinition,\n { exchange: DirectExchangeDefinition | TopicExchangeDefinition }\n >,\n \"type\" | \"queue\" | \"exchange\"\n >,\n): PublisherFirstResult<\n TMessage,\n Extract<\n PublisherDefinition<TMessage>,\n { exchange: DirectExchangeDefinition | TopicExchangeDefinition }\n >\n>;\n\n/**\n * Implementation of definePublisherFirst.\n * @internal\n */\nexport function definePublisherFirst<TMessage extends MessageDefinition>(\n exchange: ExchangeDefinition,\n message: TMessage,\n options?: {\n routingKey?: string;\n arguments?: Record<string, unknown>;\n },\n): PublisherFirstResult<TMessage, PublisherDefinition<TMessage>> {\n // Create the publisher\n const publisher = callDefinePublisher(exchange, message, options);\n\n // Factory function to create a consumer with the same message type\n const createConsumer = (queue: QueueDefinition) => {\n const binding = callDefineQueueBinding(queue, exchange, options);\n const consumer = defineConsumer(queue, message);\n return {\n consumer,\n binding,\n };\n };\n\n return {\n publisher,\n createConsumer,\n };\n}\n\n/**\n * Consumer-first builder result.\n *\n * This type represents a consumer with its binding and provides a method to create\n * a publisher that uses the same message schema and routing key.\n *\n * @template TMessage - The message definition\n * @template TConsumer - The consumer definition\n * @template TBinding - The queue binding definition\n */\nexport type ConsumerFirstResult<\n TMessage extends MessageDefinition,\n TConsumer extends ConsumerDefinition<TMessage>,\n TBinding extends QueueBindingDefinition,\n> = {\n /** The consumer definition */\n consumer: TConsumer;\n /** The binding definition connecting the exchange to the queue */\n binding: TBinding;\n /**\n * Create a publisher that sends messages to this consumer.\n * The publisher will automatically use the same message schema and routing key.\n *\n * @returns A publisher definition with the same message type and routing key\n */\n createPublisher: () => PublisherDefinition<TMessage>;\n};\n\n/**\n * Define a consumer-first relationship between a consumer and publisher.\n *\n * This builder enforces consistency by:\n * 1. Ensuring the consumer and publisher use the same message schema\n * 2. Linking the routing key from the binding to the publisher\n * 3. Creating a binding that connects the exchange to the queue\n *\n * Use this when you want to start with a consumer and ensure publishers\n * send messages of the correct type.\n *\n * @param queue - The queue to consume from\n * @param exchange - The exchange that routes to the queue (fanout type)\n * @param message - The message definition (schema and metadata)\n * @param options - Optional binding configuration\n * @returns A consumer-first result with consumer, binding, and publisher factory\n *\n * @example\n * ```typescript\n * import { z } from 'zod';\n *\n * const notificationsQueue = defineQueue('notifications', { durable: true });\n * const notificationsExchange = defineExchange('notifications', 'fanout', { durable: true });\n * const notificationMessage = defineMessage(\n * z.object({\n * userId: z.string(),\n * message: z.string(),\n * })\n * );\n *\n * // Create consumer-first relationship\n * const notificationConsumerFirst = defineConsumerFirst(\n * notificationsQueue,\n * notificationsExchange,\n * notificationMessage\n * );\n *\n * // Use in contract\n * const contract = defineContract({\n * exchanges: { notifications: notificationsExchange },\n * queues: { notificationsQueue },\n * bindings: { notificationBinding: notificationConsumerFirst.binding },\n * publishers: { sendNotification: notificationConsumerFirst.createPublisher() },\n * consumers: { processNotification: notificationConsumerFirst.consumer },\n * });\n * ```\n */\nexport function defineConsumerFirst<TMessage extends MessageDefinition>(\n queue: QueueDefinition,\n exchange: FanoutExchangeDefinition,\n message: TMessage,\n options?: Omit<\n Extract<QueueBindingDefinition, { exchange: FanoutExchangeDefinition }>,\n \"type\" | \"queue\" | \"exchange\" | \"routingKey\"\n >,\n): ConsumerFirstResult<\n TMessage,\n ConsumerDefinition<TMessage>,\n Extract<QueueBindingDefinition, { exchange: FanoutExchangeDefinition }>\n>;\n\n/**\n * Define a consumer-first relationship between a consumer and publisher.\n *\n * This builder enforces consistency by:\n * 1. Ensuring the consumer and publisher use the same message schema\n * 2. Linking the routing key from the binding to the publisher\n * 3. Creating a binding that connects the exchange to the queue\n *\n * Use this when you want to start with a consumer and ensure publishers\n * send messages with the correct type and routing key.\n *\n * @param queue - The queue to consume from\n * @param exchange - The exchange that routes to the queue (direct or topic type)\n * @param message - The message definition (schema and metadata)\n * @param options - Binding configuration (routingKey is required)\n * @param options.routingKey - The routing key for message routing\n * @returns A consumer-first result with consumer, binding, and publisher factory\n *\n * @example\n * ```typescript\n * import { z } from 'zod';\n *\n * const taskQueue = defineQueue('tasks', { durable: true });\n * const tasksExchange = defineExchange('tasks', 'direct', { durable: true });\n * const taskMessage = defineMessage(\n * z.object({\n * taskId: z.string(),\n * payload: z.record(z.unknown()),\n * })\n * );\n *\n * // Create consumer-first relationship with routing key\n * const taskConsumerFirst = defineConsumerFirst(\n * taskQueue,\n * tasksExchange,\n * taskMessage,\n * { routingKey: 'task.execute' }\n * );\n *\n * // Use in contract - routing key is consistent across consumer and publisher\n * const contract = defineContract({\n * exchanges: { tasks: tasksExchange },\n * queues: { taskQueue },\n * bindings: { taskBinding: taskConsumerFirst.binding },\n * publishers: { executeTask: taskConsumerFirst.createPublisher() },\n * consumers: { processTask: taskConsumerFirst.consumer },\n * });\n * ```\n */\nexport function defineConsumerFirst<TMessage extends MessageDefinition>(\n queue: QueueDefinition,\n exchange: DirectExchangeDefinition | TopicExchangeDefinition,\n message: TMessage,\n options: Omit<\n Extract<\n QueueBindingDefinition,\n { exchange: DirectExchangeDefinition | TopicExchangeDefinition }\n >,\n \"type\" | \"queue\" | \"exchange\"\n >,\n): ConsumerFirstResult<\n TMessage,\n ConsumerDefinition<TMessage>,\n Extract<QueueBindingDefinition, { exchange: DirectExchangeDefinition | TopicExchangeDefinition }>\n>;\n\n/**\n * Implementation of defineConsumerFirst.\n * @internal\n */\nexport function defineConsumerFirst<TMessage extends MessageDefinition>(\n queue: QueueDefinition,\n exchange: ExchangeDefinition,\n message: TMessage,\n options?: {\n routingKey?: string;\n arguments?: Record<string, unknown>;\n },\n): ConsumerFirstResult<TMessage, ConsumerDefinition<TMessage>, QueueBindingDefinition> {\n // Create the consumer\n const consumer = defineConsumer(queue, message);\n\n // Create the binding\n const binding = callDefineQueueBinding(queue, exchange, options);\n\n // Factory function to create a publisher with the same message type and routing key\n const createPublisher = (): PublisherDefinition<TMessage> => {\n return callDefinePublisher(exchange, message, options);\n };\n\n return {\n consumer,\n binding,\n createPublisher,\n };\n}\n"],"mappings":";;;;;;;;;;;;;;AAkHA,SAAgB,eACd,MACA,MACA,SACoB;AACpB,QAAO;EACL;EACA;EACA,GAAG;EACJ;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BH,SAAgB,YACd,MACA,SACiB;AACjB,QAAO;EACL;EACA,GAAG;EACJ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsCH,SAAgB,cAId,SACA,SAKuC;AACvC,QAAO;EACL;EACA,GAAG;EACJ;;;;;;;;;;;;;AA4FH,SAAgB,mBACd,OACA,UACA,SAIwB;AACxB,KAAI,SAAS,SAAS,SACpB,QAAO;EACL,MAAM;EACN;EACA;EACA,GAAI,SAAS,aAAa,EAAE,WAAW,QAAQ,WAAW;EAC3D;AAGH,QAAO;EACL,MAAM;EACN;EACA;EACA,YAAY,SAAS;EACrB,GAAI,SAAS,aAAa,EAAE,WAAW,QAAQ,WAAW;EAC3D;;;;;;;;;;;;;AAmFH,SAAgB,sBACd,aACA,QACA,SAI2B;AAC3B,KAAI,OAAO,SAAS,SAClB,QAAO;EACL,MAAM;EACN;EACA;EACA,GAAI,SAAS,aAAa,EAAE,WAAW,QAAQ,WAAW;EAC3D;AAGH,QAAO;EACL,MAAM;EACN;EACA;EACA,YAAY,SAAS,cAAc;EACnC,GAAI,SAAS,aAAa,EAAE,WAAW,QAAQ,WAAW;EAC3D;;;;;;;;;;;;;AAsGH,SAAgB,gBACd,UACA,SACA,SAC+B;AAC/B,KAAI,SAAS,SAAS,SACpB,QAAO;EACL;EACA;EACD;AAGH,QAAO;EACL;EACA;EACA,YAAY,SAAS,cAAc;EACpC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6CH,SAAgB,eACd,OACA,SACA,SAC8B;AAC9B,QAAO;EACL;EACA;EACA,GAAG;EACJ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwEH,SAAgB,eACd,YACW;AACX,QAAO;;;;;;;AAQT,SAAS,oBACP,UACA,SACA,SAI+B;AAE/B,KAAI,SAAS,SAAS,SACpB,QAAO,gBAAgB,UAAU,SAAS,QAAQ;AAEpD,QAAO,gBAAgB,UAAU,SAAS,QAAkC;;;;;;;AAQ9E,SAAS,uBACP,OACA,UACA,SAIwB;AAExB,KAAI,SAAS,SAAS,SACpB,QAAO,mBAAmB,OAAO,UAAU,QAAQ;AAErD,QAAO,mBAAmB,OAAO,UAAU,QAAkC;;;;;;AAoL/E,SAAgB,qBACd,UACA,SACA,SAI+D;CAE/D,MAAM,YAAY,oBAAoB,UAAU,SAAS,QAAQ;CAGjE,MAAM,kBAAkB,UAA2B;EACjD,MAAM,UAAU,uBAAuB,OAAO,UAAU,QAAQ;AAEhE,SAAO;GACL,UAFe,eAAe,OAAO,QAAQ;GAG7C;GACD;;AAGH,QAAO;EACL;EACA;EACD;;;;;;AAkKH,SAAgB,oBACd,OACA,UACA,SACA,SAIqF;CAErF,MAAM,WAAW,eAAe,OAAO,QAAQ;CAG/C,MAAM,UAAU,uBAAuB,OAAO,UAAU,QAAQ;CAGhE,MAAM,wBAAuD;AAC3D,SAAO,oBAAoB,UAAU,SAAS,QAAQ;;AAGxD,QAAO;EACL;EACA;EACA;EACD"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["createConsumer","createPublisher"],"sources":["../src/builder.ts"],"sourcesContent":["import type {\n BaseExchangeDefinition,\n ConsumerDefinition,\n ContractDefinition,\n DirectExchangeDefinition,\n ExchangeBindingDefinition,\n ExchangeDefinition,\n FanoutExchangeDefinition,\n MessageDefinition,\n PublisherDefinition,\n QueueBindingDefinition,\n QueueDefinition,\n TopicExchangeDefinition,\n} from \"./types.js\";\nimport type { StandardSchemaV1 } from \"@standard-schema/spec\";\n\n/**\n * Define a fanout exchange.\n *\n * A fanout exchange routes messages to all bound queues without considering routing keys.\n * This exchange type is ideal for broadcasting messages to multiple consumers.\n *\n * @param name - The name of the exchange\n * @param type - Must be \"fanout\"\n * @param options - Optional exchange configuration\n * @param options.durable - If true, the exchange survives broker restarts (default: false)\n * @param options.autoDelete - If true, the exchange is deleted when no queues are bound (default: false)\n * @param options.internal - If true, the exchange cannot be directly published to (default: false)\n * @param options.arguments - Additional AMQP arguments for the exchange\n * @returns A fanout exchange definition\n *\n * @example\n * ```typescript\n * const logsExchange = defineExchange('logs', 'fanout', {\n * durable: true\n * });\n * ```\n */\nexport function defineExchange(\n name: string,\n type: \"fanout\",\n options?: Omit<BaseExchangeDefinition, \"name\" | \"type\">,\n): FanoutExchangeDefinition;\n\n/**\n * Define a direct exchange.\n *\n * A direct exchange routes messages to queues based on exact routing key matches.\n * This exchange type is ideal for point-to-point messaging.\n *\n * @param name - The name of the exchange\n * @param type - Must be \"direct\"\n * @param options - Optional exchange configuration\n * @param options.durable - If true, the exchange survives broker restarts (default: false)\n * @param options.autoDelete - If true, the exchange is deleted when no queues are bound (default: false)\n * @param options.internal - If true, the exchange cannot be directly published to (default: false)\n * @param options.arguments - Additional AMQP arguments for the exchange\n * @returns A direct exchange definition\n *\n * @example\n * ```typescript\n * const tasksExchange = defineExchange('tasks', 'direct', {\n * durable: true\n * });\n * ```\n */\nexport function defineExchange(\n name: string,\n type: \"direct\",\n options?: Omit<BaseExchangeDefinition, \"name\" | \"type\">,\n): DirectExchangeDefinition;\n\n/**\n * Define a topic exchange.\n *\n * A topic exchange routes messages to queues based on routing key patterns.\n * Routing keys can use wildcards: `*` matches one word, `#` matches zero or more words.\n * This exchange type is ideal for flexible message routing based on hierarchical topics.\n *\n * @param name - The name of the exchange\n * @param type - Must be \"topic\"\n * @param options - Optional exchange configuration\n * @param options.durable - If true, the exchange survives broker restarts (default: false)\n * @param options.autoDelete - If true, the exchange is deleted when no queues are bound (default: false)\n * @param options.internal - If true, the exchange cannot be directly published to (default: false)\n * @param options.arguments - Additional AMQP arguments for the exchange\n * @returns A topic exchange definition\n *\n * @example\n * ```typescript\n * const ordersExchange = defineExchange('orders', 'topic', {\n * durable: true\n * });\n * ```\n */\nexport function defineExchange(\n name: string,\n type: \"topic\",\n options?: Omit<BaseExchangeDefinition, \"name\" | \"type\">,\n): TopicExchangeDefinition;\n\n/**\n * Define an AMQP exchange.\n *\n * An exchange receives messages from publishers and routes them to queues based on the exchange type\n * and routing rules. This is the implementation function - use the type-specific overloads for better\n * type safety.\n *\n * @param name - The name of the exchange\n * @param type - The type of exchange: \"fanout\", \"direct\", or \"topic\"\n * @param options - Optional exchange configuration\n * @returns An exchange definition\n * @internal\n */\nexport function defineExchange(\n name: string,\n type: \"fanout\" | \"direct\" | \"topic\",\n options?: Omit<BaseExchangeDefinition, \"name\" | \"type\">,\n): ExchangeDefinition {\n return {\n name,\n type,\n ...options,\n };\n}\n\n/**\n * Define an AMQP queue.\n *\n * A queue stores messages until they are consumed by workers. Queues can be bound to exchanges\n * to receive messages based on routing rules.\n *\n * @param name - The name of the queue\n * @param options - Optional queue configuration\n * @param options.durable - If true, the queue survives broker restarts (default: false)\n * @param options.exclusive - If true, the queue can only be used by the declaring connection (default: false)\n * @param options.autoDelete - If true, the queue is deleted when the last consumer unsubscribes (default: false)\n * @param options.deadLetter - Dead letter configuration for handling failed messages\n * @param options.arguments - Additional AMQP arguments (e.g., x-message-ttl, x-max-priority)\n * @returns A queue definition\n *\n * @example\n * ```typescript\n * // Basic queue\n * const orderQueue = defineQueue('order-processing', {\n * durable: true,\n * });\n *\n * // Queue with dead letter exchange\n * const dlx = defineExchange('orders-dlx', 'topic', { durable: true });\n * const orderQueueWithDLX = defineQueue('order-processing', {\n * durable: true,\n * deadLetter: {\n * exchange: dlx,\n * routingKey: 'order.failed'\n * },\n * arguments: {\n * 'x-message-ttl': 86400000, // 24 hours\n * }\n * });\n * ```\n */\nexport function defineQueue(\n name: string,\n options?: Omit<QueueDefinition, \"name\">,\n): QueueDefinition {\n return {\n name,\n ...options,\n };\n}\n\n/**\n * Define a message definition with payload and optional headers/metadata.\n *\n * A message definition specifies the schema for message payloads and headers using\n * Standard Schema v1 compatible libraries (Zod, Valibot, ArkType, etc.).\n * The schemas are used for automatic validation when publishing or consuming messages.\n *\n * @param payload - The payload schema (must be Standard Schema v1 compatible)\n * @param options - Optional message metadata\n * @param options.headers - Optional header schema for message headers\n * @param options.summary - Brief description for documentation (used in AsyncAPI generation)\n * @param options.description - Detailed description for documentation (used in AsyncAPI generation)\n * @returns A message definition with inferred types\n *\n * @example\n * ```typescript\n * import { z } from 'zod';\n *\n * const orderMessage = defineMessage(\n * z.object({\n * orderId: z.string().uuid(),\n * customerId: z.string().uuid(),\n * amount: z.number().positive(),\n * items: z.array(z.object({\n * productId: z.string(),\n * quantity: z.number().int().positive(),\n * })),\n * }),\n * {\n * summary: 'Order created event',\n * description: 'Emitted when a new order is created in the system'\n * }\n * );\n * ```\n */\nexport function defineMessage<\n TPayload extends MessageDefinition[\"payload\"],\n THeaders extends StandardSchemaV1<Record<string, unknown>> | undefined = undefined,\n>(\n payload: TPayload,\n options?: {\n headers?: THeaders;\n summary?: string;\n description?: string;\n },\n): MessageDefinition<TPayload, THeaders> {\n return {\n payload,\n ...options,\n };\n}\n\n/**\n * Define a binding between a queue and a fanout exchange.\n *\n * Binds a queue to a fanout exchange to receive all messages published to the exchange.\n * Fanout exchanges ignore routing keys, so this overload doesn't require one.\n *\n * @param queue - The queue definition to bind\n * @param exchange - The fanout exchange definition\n * @param options - Optional binding configuration\n * @param options.arguments - Additional AMQP arguments for the binding\n * @returns A queue binding definition\n *\n * @example\n * ```typescript\n * const logsQueue = defineQueue('logs-queue', { durable: true });\n * const logsExchange = defineExchange('logs', 'fanout', { durable: true });\n *\n * const binding = defineQueueBinding(logsQueue, logsExchange);\n * ```\n */\nexport function defineQueueBinding(\n queue: QueueDefinition,\n exchange: FanoutExchangeDefinition,\n options?: Omit<\n Extract<QueueBindingDefinition, { exchange: FanoutExchangeDefinition }>,\n \"type\" | \"queue\" | \"exchange\" | \"routingKey\"\n >,\n): Extract<QueueBindingDefinition, { exchange: FanoutExchangeDefinition }>;\n\n/**\n * Define a binding between a queue and a direct or topic exchange.\n *\n * Binds a queue to an exchange with a specific routing key pattern.\n * Messages are only routed to the queue if the routing key matches the pattern.\n *\n * For direct exchanges: The routing key must match exactly.\n * For topic exchanges: The routing key can include wildcards:\n * - `*` matches exactly one word\n * - `#` matches zero or more words\n *\n * @param queue - The queue definition to bind\n * @param exchange - The direct or topic exchange definition\n * @param options - Binding configuration (routingKey is required)\n * @param options.routingKey - The routing key pattern for message routing\n * @param options.arguments - Additional AMQP arguments for the binding\n * @returns A queue binding definition\n *\n * @example\n * ```typescript\n * const orderQueue = defineQueue('order-processing', { durable: true });\n * const ordersExchange = defineExchange('orders', 'topic', { durable: true });\n *\n * // Bind with exact routing key\n * const binding = defineQueueBinding(orderQueue, ordersExchange, {\n * routingKey: 'order.created'\n * });\n *\n * // Bind with wildcard pattern\n * const allOrdersBinding = defineQueueBinding(orderQueue, ordersExchange, {\n * routingKey: 'order.*' // Matches order.created, order.updated, etc.\n * });\n * ```\n */\nexport function defineQueueBinding(\n queue: QueueDefinition,\n exchange: DirectExchangeDefinition | TopicExchangeDefinition,\n options: Omit<\n Extract<\n QueueBindingDefinition,\n { exchange: DirectExchangeDefinition | TopicExchangeDefinition }\n >,\n \"type\" | \"queue\" | \"exchange\"\n >,\n): Extract<\n QueueBindingDefinition,\n { exchange: DirectExchangeDefinition | TopicExchangeDefinition }\n>;\n\n/**\n * Define a binding between a queue and an exchange.\n *\n * This is the implementation function - use the type-specific overloads for better type safety.\n *\n * @param queue - The queue definition to bind\n * @param exchange - The exchange definition\n * @param options - Optional binding configuration\n * @returns A queue binding definition\n * @internal\n */\nexport function defineQueueBinding(\n queue: QueueDefinition,\n exchange: ExchangeDefinition,\n options?: {\n routingKey?: string;\n arguments?: Record<string, unknown>;\n },\n): QueueBindingDefinition {\n if (exchange.type === \"fanout\") {\n return {\n type: \"queue\",\n queue,\n exchange,\n ...(options?.arguments && { arguments: options.arguments }),\n } as QueueBindingDefinition;\n }\n\n return {\n type: \"queue\",\n queue,\n exchange,\n routingKey: options?.routingKey,\n ...(options?.arguments && { arguments: options.arguments }),\n } as QueueBindingDefinition;\n}\n\n/**\n * Define a binding between two exchanges (exchange-to-exchange routing).\n *\n * Binds a destination exchange to a fanout source exchange.\n * Messages published to the source exchange will be forwarded to the destination exchange.\n * Fanout exchanges ignore routing keys, so this overload doesn't require one.\n *\n * @param destination - The destination exchange definition\n * @param source - The fanout source exchange definition\n * @param options - Optional binding configuration\n * @param options.arguments - Additional AMQP arguments for the binding\n * @returns An exchange binding definition\n *\n * @example\n * ```typescript\n * const sourceExchange = defineExchange('logs', 'fanout', { durable: true });\n * const destExchange = defineExchange('all-logs', 'fanout', { durable: true });\n *\n * const binding = defineExchangeBinding(destExchange, sourceExchange);\n * ```\n */\nexport function defineExchangeBinding(\n destination: ExchangeDefinition,\n source: FanoutExchangeDefinition,\n options?: Omit<\n Extract<ExchangeBindingDefinition, { source: FanoutExchangeDefinition }>,\n \"type\" | \"source\" | \"destination\" | \"routingKey\"\n >,\n): Extract<ExchangeBindingDefinition, { source: FanoutExchangeDefinition }>;\n\n/**\n * Define a binding between two exchanges (exchange-to-exchange routing).\n *\n * Binds a destination exchange to a direct or topic source exchange with a routing key pattern.\n * Messages are forwarded from source to destination only if the routing key matches the pattern.\n *\n * @param destination - The destination exchange definition\n * @param source - The direct or topic source exchange definition\n * @param options - Binding configuration (routingKey is required)\n * @param options.routingKey - The routing key pattern for message routing\n * @param options.arguments - Additional AMQP arguments for the binding\n * @returns An exchange binding definition\n *\n * @example\n * ```typescript\n * const ordersExchange = defineExchange('orders', 'topic', { durable: true });\n * const importantExchange = defineExchange('important-orders', 'topic', { durable: true });\n *\n * // Forward only high-value orders\n * const binding = defineExchangeBinding(importantExchange, ordersExchange, {\n * routingKey: 'order.high-value.*'\n * });\n * ```\n */\nexport function defineExchangeBinding(\n destination: ExchangeDefinition,\n source: DirectExchangeDefinition | TopicExchangeDefinition,\n options: Omit<\n Extract<\n ExchangeBindingDefinition,\n { source: DirectExchangeDefinition | TopicExchangeDefinition }\n >,\n \"type\" | \"source\" | \"destination\"\n >,\n): Extract<\n ExchangeBindingDefinition,\n { source: DirectExchangeDefinition | TopicExchangeDefinition }\n>;\n\n/**\n * Define a binding between two exchanges (exchange-to-exchange routing).\n *\n * This is the implementation function - use the type-specific overloads for better type safety.\n *\n * @param destination - The destination exchange definition\n * @param source - The source exchange definition\n * @param options - Optional binding configuration\n * @returns An exchange binding definition\n * @internal\n */\nexport function defineExchangeBinding(\n destination: ExchangeDefinition,\n source: ExchangeDefinition,\n options?: {\n routingKey?: string;\n arguments?: Record<string, unknown>;\n },\n): ExchangeBindingDefinition {\n if (source.type === \"fanout\") {\n return {\n type: \"exchange\",\n source,\n destination,\n ...(options?.arguments && { arguments: options.arguments }),\n } as ExchangeBindingDefinition;\n }\n\n return {\n type: \"exchange\",\n source,\n destination,\n routingKey: options?.routingKey ?? \"\",\n ...(options?.arguments && { arguments: options.arguments }),\n } as ExchangeBindingDefinition;\n}\n\n/**\n * Define a message publisher for a fanout exchange.\n *\n * A publisher sends messages to an exchange. For fanout exchanges, messages are broadcast\n * to all bound queues regardless of routing key, so no routing key is required.\n *\n * The message schema is validated when publishing to ensure type safety.\n *\n * @param exchange - The fanout exchange definition to publish to\n * @param message - The message definition with payload schema\n * @param options - Optional publisher configuration\n * @returns A publisher definition with inferred message types\n *\n * @example\n * ```typescript\n * import { z } from 'zod';\n *\n * const logsExchange = defineExchange('logs', 'fanout', { durable: true });\n * const logMessage = defineMessage(\n * z.object({\n * level: z.enum(['info', 'warn', 'error']),\n * message: z.string(),\n * timestamp: z.string().datetime(),\n * })\n * );\n *\n * const logPublisher = definePublisher(logsExchange, logMessage);\n * ```\n */\nexport function definePublisher<TMessage extends MessageDefinition>(\n exchange: FanoutExchangeDefinition,\n message: TMessage,\n options?: Omit<\n Extract<PublisherDefinition<TMessage>, { exchange: FanoutExchangeDefinition }>,\n \"exchange\" | \"message\" | \"routingKey\"\n >,\n): Extract<PublisherDefinition<TMessage>, { exchange: FanoutExchangeDefinition }>;\n\n/**\n * Define a message publisher for a direct or topic exchange.\n *\n * A publisher sends messages to an exchange with a specific routing key.\n * The routing key determines which queues receive the message.\n *\n * The message schema is validated when publishing to ensure type safety.\n *\n * @param exchange - The direct or topic exchange definition to publish to\n * @param message - The message definition with payload schema\n * @param options - Publisher configuration (routingKey is required)\n * @param options.routingKey - The routing key for message routing\n * @returns A publisher definition with inferred message types\n *\n * @example\n * ```typescript\n * import { z } from 'zod';\n *\n * const ordersExchange = defineExchange('orders', 'topic', { durable: true });\n * const orderMessage = defineMessage(\n * z.object({\n * orderId: z.string().uuid(),\n * amount: z.number().positive(),\n * }),\n * {\n * summary: 'Order created event',\n * description: 'Emitted when a new order is created'\n * }\n * );\n *\n * const orderCreatedPublisher = definePublisher(ordersExchange, orderMessage, {\n * routingKey: 'order.created'\n * });\n * ```\n */\nexport function definePublisher<TMessage extends MessageDefinition>(\n exchange: DirectExchangeDefinition | TopicExchangeDefinition,\n message: TMessage,\n options: Omit<\n Extract<\n PublisherDefinition<TMessage>,\n { exchange: DirectExchangeDefinition | TopicExchangeDefinition }\n >,\n \"exchange\" | \"message\"\n >,\n): Extract<\n PublisherDefinition<TMessage>,\n { exchange: DirectExchangeDefinition | TopicExchangeDefinition }\n>;\n\n/**\n * Define a message publisher.\n *\n * This is the implementation function - use the type-specific overloads for better type safety.\n *\n * @param exchange - The exchange definition\n * @param message - The message definition\n * @param options - Optional publisher configuration\n * @returns A publisher definition\n * @internal\n */\nexport function definePublisher<TMessage extends MessageDefinition>(\n exchange: ExchangeDefinition,\n message: TMessage,\n options?: { routingKey?: string },\n): PublisherDefinition<TMessage> {\n if (exchange.type === \"fanout\") {\n return {\n exchange,\n message,\n } as PublisherDefinition<TMessage>;\n }\n\n return {\n exchange,\n message,\n routingKey: options?.routingKey ?? \"\",\n } as PublisherDefinition<TMessage>;\n}\n\n/**\n * Define a message consumer.\n *\n * A consumer receives and processes messages from a queue. The message schema is validated\n * automatically when messages are consumed, ensuring type safety for your handlers.\n *\n * Consumers are associated with a specific queue and message type. When you create a worker\n * with this consumer, it will process messages from the queue according to the schema.\n *\n * @param queue - The queue definition to consume from\n * @param message - The message definition with payload schema\n * @param options - Optional consumer configuration\n * @returns A consumer definition with inferred message types\n *\n * @example\n * ```typescript\n * import { z } from 'zod';\n *\n * const orderQueue = defineQueue('order-processing', { durable: true });\n * const orderMessage = defineMessage(\n * z.object({\n * orderId: z.string().uuid(),\n * customerId: z.string().uuid(),\n * amount: z.number().positive(),\n * })\n * );\n *\n * const processOrderConsumer = defineConsumer(orderQueue, orderMessage);\n *\n * // Later, when creating a worker, you'll provide a handler for this consumer:\n * // const worker = await TypedAmqpWorker.create({\n * // contract,\n * // handlers: {\n * // processOrder: async (message) => {\n * // // message is automatically typed based on the schema\n * // console.log(message.orderId); // string\n * // }\n * // },\n * // connection\n * // });\n * ```\n */\nexport function defineConsumer<TMessage extends MessageDefinition>(\n queue: QueueDefinition,\n message: TMessage,\n options?: Omit<ConsumerDefinition<TMessage>, \"queue\" | \"message\">,\n): ConsumerDefinition<TMessage> {\n return {\n queue,\n message,\n ...options,\n };\n}\n\n/**\n * Define an AMQP contract.\n *\n * A contract is the central definition of your AMQP messaging topology. It brings together\n * all exchanges, queues, bindings, publishers, and consumers in a single, type-safe definition.\n *\n * The contract is used by both clients (for publishing) and workers (for consuming) to ensure\n * type safety throughout your messaging infrastructure. TypeScript will infer all message types\n * and publisher/consumer names from the contract.\n *\n * @param definition - The contract definition containing all AMQP resources\n * @param definition.exchanges - Named exchange definitions\n * @param definition.queues - Named queue definitions\n * @param definition.bindings - Named binding definitions (queue-to-exchange or exchange-to-exchange)\n * @param definition.publishers - Named publisher definitions for sending messages\n * @param definition.consumers - Named consumer definitions for receiving messages\n * @returns The same contract definition with full type inference\n *\n * @example\n * ```typescript\n * import {\n * defineContract,\n * defineExchange,\n * defineQueue,\n * defineQueueBinding,\n * definePublisher,\n * defineConsumer,\n * defineMessage,\n * } from '@amqp-contract/contract';\n * import { z } from 'zod';\n *\n * // Define resources\n * const ordersExchange = defineExchange('orders', 'topic', { durable: true });\n * const orderQueue = defineQueue('order-processing', { durable: true });\n * const orderMessage = defineMessage(\n * z.object({\n * orderId: z.string(),\n * amount: z.number(),\n * })\n * );\n *\n * // Compose contract\n * export const contract = defineContract({\n * exchanges: {\n * orders: ordersExchange,\n * },\n * queues: {\n * orderProcessing: orderQueue,\n * },\n * bindings: {\n * orderBinding: defineQueueBinding(orderQueue, ordersExchange, {\n * routingKey: 'order.created',\n * }),\n * },\n * publishers: {\n * orderCreated: definePublisher(ordersExchange, orderMessage, {\n * routingKey: 'order.created',\n * }),\n * },\n * consumers: {\n * processOrder: defineConsumer(orderQueue, orderMessage),\n * },\n * });\n *\n * // TypeScript now knows:\n * // - client.publish('orderCreated', { orderId: string, amount: number })\n * // - handler: async (message: { orderId: string, amount: number }) => void\n * ```\n */\nexport function defineContract<TContract extends ContractDefinition>(\n definition: TContract,\n): TContract {\n return definition;\n}\n\n/**\n * Helper to call definePublisher with proper type handling.\n * Type safety is enforced by overloaded public function signatures.\n * @internal\n */\nfunction callDefinePublisher<TMessage extends MessageDefinition>(\n exchange: ExchangeDefinition,\n message: TMessage,\n options?: {\n routingKey?: string;\n arguments?: Record<string, unknown>;\n },\n): PublisherDefinition<TMessage> {\n // Type assertion is safe because overloaded signatures enforce routingKey requirement\n if (exchange.type === \"fanout\") {\n return definePublisher(exchange, message, options);\n }\n return definePublisher(exchange, message, options as { routingKey: string });\n}\n\n/**\n * Helper to call defineQueueBinding with proper type handling.\n * Type safety is enforced by overloaded public function signatures.\n * @internal\n */\nfunction callDefineQueueBinding(\n queue: QueueDefinition,\n exchange: ExchangeDefinition,\n options?: {\n routingKey?: string;\n arguments?: Record<string, unknown>;\n },\n): QueueBindingDefinition {\n // Type assertion is safe because overloaded signatures enforce routingKey requirement\n if (exchange.type === \"fanout\") {\n return defineQueueBinding(queue, exchange, options);\n }\n return defineQueueBinding(queue, exchange, options as { routingKey: string });\n}\n\n/**\n * Publisher-first builder result for fanout and direct exchanges.\n *\n * This type represents a publisher and provides a method to create\n * a consumer that uses the same message schema with a binding to the exchange.\n *\n * This pattern is suitable for event-oriented messaging where publishers\n * emit events without knowing which queues will consume them.\n *\n * @template TMessage - The message definition\n * @template TPublisher - The publisher definition\n */\nexport type PublisherFirstResult<\n TMessage extends MessageDefinition,\n TPublisher extends PublisherDefinition<TMessage>,\n> = {\n /** The publisher definition */\n publisher: TPublisher;\n /**\n * Create a consumer that receives messages from this publisher.\n * The consumer will automatically use the same message schema and\n * a binding will be created with the same routing key.\n *\n * @param queue - The queue that will consume the messages\n * @returns An object with the consumer definition and binding\n */\n createConsumer: (queue: QueueDefinition) => {\n consumer: ConsumerDefinition<TMessage>;\n binding: QueueBindingDefinition;\n };\n};\n\n// ============================================================================\n// Routing Key and Binding Pattern Validation Types\n// ============================================================================\n\n/**\n * Type-safe routing key that validates basic format.\n *\n * Validates that a routing key follows basic AMQP routing key rules:\n * - Must not contain wildcards (* or #)\n * - Must not be empty\n * - Should contain alphanumeric characters, dots, hyphens, and underscores\n *\n * Note: Full character-by-character validation is not performed to avoid TypeScript\n * recursion depth limits. Runtime validation is still recommended.\n *\n * @public\n * @template S - The routing key string to validate\n * @example\n * ```typescript\n * type Valid = RoutingKey<\"order.created\">; // \"order.created\"\n * type Invalid = RoutingKey<\"order.*\">; // never (contains wildcard)\n * type Invalid2 = RoutingKey<\"\">; // never (empty string)\n * ```\n */\nexport type RoutingKey<S extends string> = S extends \"\"\n ? never // Empty string not allowed\n : S extends `${string}*${string}` | `${string}#${string}`\n ? never // Wildcards not allowed in routing keys\n : S; // Accept the routing key as-is\n\n/**\n * Type-safe binding pattern that validates basic format and wildcards.\n *\n * Validates that a binding pattern follows basic AMQP binding pattern rules:\n * - Can contain wildcards (* for one word, # for zero or more words)\n * - Must not be empty\n * - Should contain alphanumeric characters, dots, hyphens, underscores, and wildcards\n *\n * Note: Full character-by-character validation is not performed to avoid TypeScript\n * recursion depth limits. Runtime validation is still recommended.\n *\n * @public\n * @template S - The binding pattern string to validate\n * @example\n * ```typescript\n * type ValidPattern = BindingPattern<\"order.*\">; // \"order.*\"\n * type ValidHash = BindingPattern<\"order.#\">; // \"order.#\"\n * type ValidConcrete = BindingPattern<\"order.created\">; // \"order.created\"\n * type Invalid = BindingPattern<\"\">; // never (empty string)\n * ```\n */\nexport type BindingPattern<S extends string> = S extends \"\" ? never : S;\n\n/**\n * Helper type for pattern matching with # in the middle\n * Handles backtracking to match # with zero or more segments\n * @internal\n */\ntype MatchesAfterHash<Key extends string, PatternRest extends string> =\n MatchesPattern<Key, PatternRest> extends true\n ? true // # matches zero segments\n : Key extends `${string}.${infer KeyRest}`\n ? MatchesAfterHash<KeyRest, PatternRest> // # matches one or more segments\n : false;\n\n/**\n * Check if a routing key matches a binding pattern\n * Implements AMQP topic exchange pattern matching:\n * - * matches exactly one word\n * - # matches zero or more words\n * @internal\n */\ntype MatchesPattern<\n Key extends string,\n Pattern extends string,\n> = Pattern extends `${infer PatternPart}.${infer PatternRest}`\n ? PatternPart extends \"#\"\n ? MatchesAfterHash<Key, PatternRest> // # in the middle: backtrack over all possible segment lengths\n : Key extends `${infer KeyPart}.${infer KeyRest}`\n ? PatternPart extends \"*\"\n ? MatchesPattern<KeyRest, PatternRest> // * matches one segment\n : PatternPart extends KeyPart\n ? MatchesPattern<KeyRest, PatternRest> // Exact match\n : false\n : false\n : Pattern extends \"#\"\n ? true // # matches everything (including empty)\n : Pattern extends \"*\"\n ? Key extends `${string}.${string}`\n ? false // * matches exactly 1 segment, not multiple\n : true\n : Pattern extends Key\n ? true // Exact match\n : false;\n\n/**\n * Validate that a routing key matches a binding pattern.\n *\n * This is a utility type provided for users who want compile-time validation\n * that a routing key matches a specific pattern. It's not enforced internally\n * in the API to avoid TypeScript recursion depth issues with complex routing keys.\n *\n * Returns the routing key if it's valid and matches the pattern, `never` otherwise.\n *\n * @example\n * ```typescript\n * type ValidKey = MatchingRoutingKey<\"order.*\", \"order.created\">; // \"order.created\"\n * type InvalidKey = MatchingRoutingKey<\"order.*\", \"user.created\">; // never\n * ```\n *\n * @template Pattern - The binding pattern (can contain * and # wildcards)\n * @template Key - The routing key to validate\n */\nexport type MatchingRoutingKey<Pattern extends string, Key extends string> =\n RoutingKey<Key> extends never\n ? never // Invalid routing key\n : BindingPattern<Pattern> extends never\n ? never // Invalid pattern\n : MatchesPattern<Key, Pattern> extends true\n ? Key\n : never;\n\n/**\n * Publisher-first builder result for topic exchanges.\n *\n * This type represents a publisher with a concrete routing key and provides a method\n * to create consumers that can use routing key patterns matching the publisher's key.\n *\n * @template TMessage - The message definition\n * @template TPublisher - The publisher definition\n * @template TRoutingKey - The literal routing key type from the publisher (for documentation purposes)\n */\nexport type PublisherFirstResultWithRoutingKey<\n TMessage extends MessageDefinition,\n TPublisher extends PublisherDefinition<TMessage>,\n TRoutingKey extends string,\n> = {\n /** The publisher definition */\n publisher: TPublisher;\n /**\n * Create a consumer that receives messages from this publisher.\n * For topic exchanges, the routing key pattern can be specified for the binding.\n *\n * @param queue - The queue that will consume the messages\n * @param routingKey - Optional routing key pattern for the binding (defaults to publisher's routing key)\n * @returns An object with the consumer definition and binding\n */\n createConsumer: <TConsumerRoutingKey extends string = TRoutingKey>(\n queue: QueueDefinition,\n routingKey?: BindingPattern<TConsumerRoutingKey>,\n ) => {\n consumer: ConsumerDefinition<TMessage>;\n binding: QueueBindingDefinition;\n };\n};\n\n/**\n * Define a publisher-first relationship for event-oriented messaging.\n *\n * This builder enforces consistency by:\n * 1. Ensuring the publisher and consumer use the same message schema\n * 2. Linking the routing key from the publisher to the binding\n *\n * Use this pattern for events where publishers don't need to know about queues.\n * Multiple consumers can be created for different queues, all using the same message schema.\n *\n * @param exchange - The exchange to publish to (fanout type)\n * @param message - The message definition (schema and metadata)\n * @param options - Optional binding configuration\n * @returns A publisher-first result with publisher and consumer factory\n *\n * @example\n * ```typescript\n * import { z } from 'zod';\n *\n * const logsExchange = defineExchange('logs', 'fanout', { durable: true });\n * const logMessage = defineMessage(\n * z.object({\n * level: z.enum(['info', 'warn', 'error']),\n * message: z.string(),\n * })\n * );\n *\n * // Create publisher-first relationship (event pattern)\n * const { publisher: publishLog, createConsumer: createLogConsumer } = definePublisherFirst(logsExchange, logMessage);\n *\n * // Multiple queues can consume the same event\n * const logsQueue1 = defineQueue('logs-queue-1', { durable: true });\n * const logsQueue2 = defineQueue('logs-queue-2', { durable: true });\n *\n * // Use in contract\n * const { consumer: consumer1, binding: binding1 } = createLogConsumer(logsQueue1);\n * const { consumer: consumer2, binding: binding2 } = createLogConsumer(logsQueue2);\n *\n * const contract = defineContract({\n * exchanges: { logs: logsExchange },\n * queues: { logsQueue1, logsQueue2 },\n * bindings: {\n * logBinding1: binding1,\n * logBinding2: binding2,\n * },\n * publishers: { publishLog },\n * consumers: {\n * consumeLog1: consumer1,\n * consumeLog2: consumer2,\n * },\n * });\n * ```\n */\nexport function definePublisherFirst<TMessage extends MessageDefinition>(\n exchange: FanoutExchangeDefinition,\n message: TMessage,\n options?: Omit<\n Extract<QueueBindingDefinition, { exchange: FanoutExchangeDefinition }>,\n \"type\" | \"queue\" | \"exchange\" | \"routingKey\"\n >,\n): PublisherFirstResult<\n TMessage,\n Extract<PublisherDefinition<TMessage>, { exchange: FanoutExchangeDefinition }>\n>;\n\n/**\n * Define a publisher-first relationship for event-oriented messaging with direct exchange.\n *\n * This builder enforces consistency by:\n * 1. Ensuring the publisher and consumer use the same message schema\n * 2. Linking the routing key from the publisher to the binding\n *\n * Use this pattern for events where publishers don't need to know about queues.\n * Multiple consumers can be created for different queues, all using the same message schema.\n *\n * @param exchange - The exchange to publish to (direct type)\n * @param message - The message definition (schema and metadata)\n * @param options - Binding configuration (routingKey is required)\n * @param options.routingKey - The routing key for message routing\n * @returns A publisher-first result with publisher and consumer factory\n *\n * @example\n * ```typescript\n * import { z } from 'zod';\n *\n * const tasksExchange = defineExchange('tasks', 'direct', { durable: true });\n * const taskMessage = defineMessage(\n * z.object({\n * taskId: z.string(),\n * payload: z.record(z.unknown()),\n * })\n * );\n *\n * // Create publisher-first relationship with routing key\n * const { publisher: executeTaskPublisher, createConsumer: createTaskConsumer } = definePublisherFirst(\n * tasksExchange,\n * taskMessage,\n * { routingKey: 'task.execute' }\n * );\n *\n * // Use in contract - routing key is consistent across publisher and bindings\n * const taskQueue = defineQueue('task-queue', { durable: true });\n * const { consumer, binding } = createTaskConsumer(taskQueue);\n *\n * const contract = defineContract({\n * exchanges: { tasks: tasksExchange },\n * queues: { taskQueue },\n * bindings: { taskBinding: binding },\n * publishers: { executeTask: executeTaskPublisher },\n * consumers: { processTask: consumer },\n * });\n * ```\n */\nexport function definePublisherFirst<\n TMessage extends MessageDefinition,\n TRoutingKey extends string,\n>(\n exchange: DirectExchangeDefinition,\n message: TMessage,\n options: {\n routingKey: RoutingKey<TRoutingKey>;\n arguments?: Record<string, unknown>;\n },\n): PublisherFirstResult<\n TMessage,\n Extract<\n PublisherDefinition<TMessage>,\n { exchange: DirectExchangeDefinition | TopicExchangeDefinition }\n >\n>;\n\n/**\n * Define a publisher-first relationship for event-oriented messaging with topic exchange.\n *\n * This builder enforces consistency by:\n * 1. Ensuring the publisher and consumer use the same message schema\n * 2. The publisher uses a concrete routing key (e.g., 'order.created')\n * 3. Consumers can optionally specify routing key patterns (e.g., 'order.*') or use the default\n *\n * Use this pattern for events where publishers emit with specific routing keys,\n * and consumers can subscribe with patterns. This is less common than the consumer-first pattern.\n *\n * @param exchange - The exchange to publish to (topic type)\n * @param message - The message definition (schema and metadata)\n * @param options - Binding configuration (routingKey is required)\n * @param options.routingKey - The concrete routing key for the publisher\n * @returns A publisher-first result with publisher and consumer factory that accepts optional routing key patterns\n *\n * @example\n * ```typescript\n * import { z } from 'zod';\n *\n * const ordersExchange = defineExchange('orders', 'topic', { durable: true });\n * const orderMessage = defineMessage(\n * z.object({\n * orderId: z.string(),\n * amount: z.number(),\n * })\n * );\n *\n * // Create publisher-first relationship with concrete routing key\n * const { publisher: orderCreatedPublisher, createConsumer: createOrderCreatedConsumer } = definePublisherFirst(\n * ordersExchange,\n * orderMessage,\n * { routingKey: 'order.created' } // Concrete key\n * );\n *\n * // Consumers can use patterns or specific keys\n * const orderQueue = defineQueue('order-processing', { durable: true });\n * const allOrdersQueue = defineQueue('all-orders', { durable: true });\n *\n * // Use in contract\n * const { consumer: processConsumer, binding: processBinding } =\n * createOrderCreatedConsumer(orderQueue); // Uses 'order.created'\n * const { consumer: allOrdersConsumer, binding: allOrdersBinding } =\n * createOrderCreatedConsumer(allOrdersQueue, 'order.*'); // Uses pattern\n *\n * const contract = defineContract({\n * exchanges: { orders: ordersExchange },\n * queues: { orderQueue, allOrdersQueue },\n * bindings: {\n * orderBinding: processBinding,\n * allOrdersBinding,\n * },\n * publishers: { orderCreated: orderCreatedPublisher },\n * consumers: {\n * processOrder: processConsumer,\n * trackAllOrders: allOrdersConsumer,\n * },\n * });\n * ```\n */\nexport function definePublisherFirst<\n TMessage extends MessageDefinition,\n TRoutingKey extends string,\n>(\n exchange: TopicExchangeDefinition,\n message: TMessage,\n options: {\n routingKey: RoutingKey<TRoutingKey>;\n arguments?: Record<string, unknown>;\n },\n): PublisherFirstResultWithRoutingKey<\n TMessage,\n Extract<\n PublisherDefinition<TMessage>,\n { exchange: DirectExchangeDefinition | TopicExchangeDefinition }\n >,\n TRoutingKey\n>;\n\n/**\n * Implementation of definePublisherFirst.\n * @internal\n */\nexport function definePublisherFirst<TMessage extends MessageDefinition>(\n exchange: ExchangeDefinition,\n message: TMessage,\n options?: {\n routingKey?: string;\n arguments?: Record<string, unknown>;\n },\n):\n | PublisherFirstResult<TMessage, PublisherDefinition<TMessage>>\n | PublisherFirstResultWithRoutingKey<TMessage, PublisherDefinition<TMessage>, string> {\n // Create the publisher\n const publisher = callDefinePublisher(exchange, message, options);\n\n // For topic exchanges, allow specifying routing key pattern when creating consumer\n if (exchange.type === \"topic\") {\n const createConsumer = (queue: QueueDefinition, routingKey?: string) => {\n const bindingOptions = routingKey ? { ...options, routingKey } : options;\n const binding = callDefineQueueBinding(queue, exchange, bindingOptions);\n const consumer = defineConsumer(queue, message);\n return {\n consumer,\n binding,\n };\n };\n\n return {\n publisher,\n createConsumer,\n } as PublisherFirstResultWithRoutingKey<TMessage, PublisherDefinition<TMessage>, string>;\n }\n\n // For fanout and direct exchanges, use the same routing key from publisher\n const createConsumer = (queue: QueueDefinition) => {\n const binding = callDefineQueueBinding(queue, exchange, options);\n const consumer = defineConsumer(queue, message);\n return {\n consumer,\n binding,\n };\n };\n\n return {\n publisher,\n createConsumer,\n } as PublisherFirstResult<TMessage, PublisherDefinition<TMessage>>;\n}\n\n/**\n * Consumer-first builder result for fanout and direct exchanges.\n *\n * This type represents a consumer with its binding and provides a method to create\n * a publisher that uses the same message schema and routing key.\n *\n * @template TMessage - The message definition\n * @template TConsumer - The consumer definition\n * @template TBinding - The queue binding definition\n */\nexport type ConsumerFirstResult<\n TMessage extends MessageDefinition,\n TConsumer extends ConsumerDefinition<TMessage>,\n TBinding extends QueueBindingDefinition,\n> = {\n /** The consumer definition */\n consumer: TConsumer;\n /** The binding definition connecting the exchange to the queue */\n binding: TBinding;\n /**\n * Create a publisher that sends messages to this consumer.\n * The publisher will automatically use the same message schema and routing key.\n *\n * @returns A publisher definition with the same message type and routing key\n */\n createPublisher: () => TBinding[\"exchange\"] extends FanoutExchangeDefinition\n ? Extract<PublisherDefinition<TMessage>, { exchange: FanoutExchangeDefinition }>\n : Extract<\n PublisherDefinition<TMessage>,\n { exchange: DirectExchangeDefinition | TopicExchangeDefinition }\n >;\n};\n\n/**\n * Consumer-first builder result for topic exchanges.\n *\n * This type represents a consumer with its binding (which may use a pattern) and provides\n * a method to create a publisher with a concrete routing key that matches the pattern.\n *\n * @template TMessage - The message definition\n * @template TConsumer - The consumer definition\n * @template TBinding - The queue binding definition\n */\nexport type ConsumerFirstResultWithRoutingKey<\n TMessage extends MessageDefinition,\n TConsumer extends ConsumerDefinition<TMessage>,\n TBinding extends QueueBindingDefinition,\n> = {\n /** The consumer definition */\n consumer: TConsumer;\n /** The binding definition connecting the exchange to the queue */\n binding: TBinding;\n /**\n * Create a publisher that sends messages to this consumer.\n * For topic exchanges, the routing key can be specified to match the binding pattern.\n *\n * @param routingKey - The concrete routing key that matches the binding pattern\n * @returns A publisher definition with the specified routing key\n */\n createPublisher: <TPublisherRoutingKey extends string>(\n routingKey: RoutingKey<TPublisherRoutingKey>,\n ) => Extract<\n PublisherDefinition<TMessage>,\n { exchange: DirectExchangeDefinition | TopicExchangeDefinition }\n >;\n};\n\n/**\n * Define a consumer-first relationship between a consumer and publisher.\n *\n * This builder enforces consistency by:\n * 1. Ensuring the consumer and publisher use the same message schema\n * 2. Linking the routing key from the binding to the publisher\n * 3. Creating a binding that connects the exchange to the queue\n *\n * Use this when you want to start with a consumer and ensure publishers\n * send messages of the correct type.\n *\n * @param queue - The queue to consume from\n * @param exchange - The exchange that routes to the queue (fanout type)\n * @param message - The message definition (schema and metadata)\n * @param options - Optional binding configuration\n * @returns A consumer-first result with consumer, binding, and publisher factory\n *\n * @example\n * ```typescript\n * import { z } from 'zod';\n *\n * const notificationsQueue = defineQueue('notifications', { durable: true });\n * const notificationsExchange = defineExchange('notifications', 'fanout', { durable: true });\n * const notificationMessage = defineMessage(\n * z.object({\n * userId: z.string(),\n * message: z.string(),\n * })\n * );\n *\n * // Create consumer-first relationship\n * const { consumer: processNotificationConsumer, binding: notificationBinding, createPublisher: createNotificationPublisher } = defineConsumerFirst(\n * notificationsQueue,\n * notificationsExchange,\n * notificationMessage\n * );\n *\n * // Use in contract\n * const contract = defineContract({\n * exchanges: { notifications: notificationsExchange },\n * queues: { notificationsQueue },\n * bindings: { notificationBinding },\n * publishers: { sendNotification: createNotificationPublisher() },\n * consumers: { processNotification: processNotificationConsumer },\n * });\n * ```\n */\nexport function defineConsumerFirst<TMessage extends MessageDefinition>(\n queue: QueueDefinition,\n exchange: FanoutExchangeDefinition,\n message: TMessage,\n options?: Omit<\n Extract<QueueBindingDefinition, { exchange: FanoutExchangeDefinition }>,\n \"type\" | \"queue\" | \"exchange\" | \"routingKey\"\n >,\n): ConsumerFirstResult<\n TMessage,\n ConsumerDefinition<TMessage>,\n Extract<QueueBindingDefinition, { exchange: FanoutExchangeDefinition }>\n>;\n\n/**\n * Define a consumer-first relationship between a consumer and publisher.\n *\n * This builder enforces consistency by:\n * 1. Ensuring the consumer and publisher use the same message schema\n * 2. Linking the routing key from the binding to the publisher\n * 3. Creating a binding that connects the exchange to the queue\n *\n * Use this when you want to start with a consumer and ensure publishers\n * send messages with the correct type and routing key.\n *\n * @param queue - The queue to consume from\n * @param exchange - The exchange that routes to the queue (direct type)\n * @param message - The message definition (schema and metadata)\n * @param options - Binding configuration (routingKey is required)\n * @param options.routingKey - The routing key for message routing\n * @returns A consumer-first result with consumer, binding, and publisher factory\n *\n * @example\n * ```typescript\n * import { z } from 'zod';\n *\n * const taskQueue = defineQueue('tasks', { durable: true });\n * const tasksExchange = defineExchange('tasks', 'direct', { durable: true });\n * const taskMessage = defineMessage(\n * z.object({\n * taskId: z.string(),\n * payload: z.record(z.unknown()),\n * })\n * );\n *\n * // Create consumer-first relationship with routing key\n * const { consumer: processTaskConsumer, binding: taskBinding, createPublisher: createTaskPublisher } = defineConsumerFirst(\n * taskQueue,\n * tasksExchange,\n * taskMessage,\n * { routingKey: 'task.execute' }\n * );\n *\n * // Use in contract - routing key is consistent across consumer and publisher\n * const contract = defineContract({\n * exchanges: { tasks: tasksExchange },\n * queues: { taskQueue },\n * bindings: { taskBinding },\n * publishers: { executeTask: createTaskPublisher() },\n * consumers: { processTask: processTaskConsumer },\n * });\n * ```\n */\nexport function defineConsumerFirst<TMessage extends MessageDefinition, TRoutingKey extends string>(\n queue: QueueDefinition,\n exchange: DirectExchangeDefinition,\n message: TMessage,\n options: {\n routingKey: RoutingKey<TRoutingKey>;\n arguments?: Record<string, unknown>;\n },\n): ConsumerFirstResult<\n TMessage,\n ConsumerDefinition<TMessage>,\n Extract<QueueBindingDefinition, { exchange: DirectExchangeDefinition }>\n>;\n\n/**\n * Define a consumer-first relationship between a consumer and publisher with topic exchange.\n *\n * This builder enforces consistency by:\n * 1. Ensuring the consumer and publisher use the same message schema\n * 2. The binding uses a routing key pattern (e.g., 'order.*')\n * 3. The publisher factory accepts a concrete routing key that matches the pattern (e.g., 'order.created')\n *\n * Use this when you want to start with a consumer that uses a routing key pattern,\n * and allow publishers to specify concrete routing keys that match that pattern.\n *\n * @param queue - The queue to consume from\n * @param exchange - The exchange that routes to the queue (topic type)\n * @param message - The message definition (schema and metadata)\n * @param options - Binding configuration (routingKey is required)\n * @param options.routingKey - The routing key pattern for the binding (can use wildcards)\n * @returns A consumer-first result with consumer, binding, and publisher factory that accepts a routing key\n *\n * @example\n * ```typescript\n * import { z } from 'zod';\n *\n * const orderQueue = defineQueue('order-processing', { durable: true });\n * const ordersExchange = defineExchange('orders', 'topic', { durable: true });\n * const orderMessage = defineMessage(\n * z.object({\n * orderId: z.string(),\n * amount: z.number(),\n * })\n * );\n *\n * // Create consumer-first relationship with pattern\n * const { consumer: processOrderConsumer, binding: orderBinding, createPublisher: createOrderPublisher } = defineConsumerFirst(\n * orderQueue,\n * ordersExchange,\n * orderMessage,\n * { routingKey: 'order.*' } // Pattern in binding\n * );\n *\n * // Use in contract - publisher can specify concrete routing key\n * const contract = defineContract({\n * exchanges: { orders: ordersExchange },\n * queues: { orderQueue },\n * bindings: { orderBinding },\n * publishers: {\n * orderCreated: createOrderPublisher('order.created'), // Concrete key\n * orderUpdated: createOrderPublisher('order.updated'), // Concrete key\n * },\n * consumers: { processOrder: processOrderConsumer },\n * });\n * ```\n */\nexport function defineConsumerFirst<TMessage extends MessageDefinition, TRoutingKey extends string>(\n queue: QueueDefinition,\n exchange: TopicExchangeDefinition,\n message: TMessage,\n options: {\n routingKey: BindingPattern<TRoutingKey>;\n arguments?: Record<string, unknown>;\n },\n): ConsumerFirstResultWithRoutingKey<\n TMessage,\n ConsumerDefinition<TMessage>,\n Extract<QueueBindingDefinition, { exchange: TopicExchangeDefinition }>\n>;\n\n/**\n * Implementation of defineConsumerFirst.\n * @internal\n */\nexport function defineConsumerFirst<TMessage extends MessageDefinition>(\n queue: QueueDefinition,\n exchange: ExchangeDefinition,\n message: TMessage,\n options?: {\n routingKey?: string;\n arguments?: Record<string, unknown>;\n },\n):\n | ConsumerFirstResult<TMessage, ConsumerDefinition<TMessage>, QueueBindingDefinition>\n | ConsumerFirstResultWithRoutingKey<\n TMessage,\n ConsumerDefinition<TMessage>,\n QueueBindingDefinition\n > {\n // Create the consumer\n const consumer = defineConsumer(queue, message);\n\n // Create the binding\n const binding = callDefineQueueBinding(queue, exchange, options);\n\n // For topic exchanges, allow specifying routing key when creating publisher\n if (exchange.type === \"topic\") {\n const createPublisher = (\n routingKey: string,\n ): Extract<\n PublisherDefinition<TMessage>,\n { exchange: DirectExchangeDefinition | TopicExchangeDefinition }\n > => {\n return callDefinePublisher(exchange, message, { ...options, routingKey }) as Extract<\n PublisherDefinition<TMessage>,\n { exchange: DirectExchangeDefinition | TopicExchangeDefinition }\n >;\n };\n\n return {\n consumer,\n binding,\n createPublisher,\n } as ConsumerFirstResultWithRoutingKey<\n TMessage,\n ConsumerDefinition<TMessage>,\n QueueBindingDefinition\n >;\n }\n\n // For fanout and direct exchanges, use the same routing key from binding\n const createPublisher = () => {\n return callDefinePublisher(exchange, message, options);\n };\n\n return {\n consumer,\n binding,\n createPublisher,\n } as ConsumerFirstResult<TMessage, ConsumerDefinition<TMessage>, QueueBindingDefinition>;\n}\n"],"mappings":"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"}
|