@amqp-contract/contract 0.22.0 → 0.23.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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../src/builder/exchange.ts","../src/builder/message.ts","../src/builder/queue-utils.ts","../src/builder/binding.ts","../src/builder/ttl-backoff.ts","../src/builder/queue.ts","../src/builder/publisher.ts","../src/builder/consumer.ts","../src/builder/command.ts","../src/builder/event.ts","../src/builder/contract.ts","../src/builder/rpc.ts"],"sourcesContent":["import type {\n BaseExchangeDefinition,\n DirectExchangeDefinition,\n ExchangeDefinition,\n FanoutExchangeDefinition,\n HeadersExchangeDefinition,\n TopicExchangeDefinition,\n} from \"../types.js\";\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 options - Optional exchange configuration\n * @param options.type - Exchange type (must be \"topic\", or omitted for default topic exchange)\n * @param options.durable - If true, the exchange survives broker restarts (default: true)\n * @param options.autoDelete - If true, the exchange is deleted when no queues are bound\n * @param options.internal - If true, the exchange cannot be directly published to\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', { type: 'topic' });\n *\n * // Or omit type for default topic exchange\n * const ordersExchange = defineExchange('orders');\n * ```\n */\nexport function defineExchange<TName extends string>(\n name: TName,\n options?: { type?: \"topic\" } & Omit<BaseExchangeDefinition, \"name\" | \"type\">,\n): TopicExchangeDefinition<TName>;\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 options - Exchange configuration\n * @param options.type - Exchange type (must be \"direct\")\n * @param options.durable - If true, the exchange survives broker restarts (default: true)\n * @param options.autoDelete - If true, the exchange is deleted when no queues are bound\n * @param options.internal - If true, the exchange cannot be directly published to\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', { type: 'direct' });\n * ```\n */\nexport function defineExchange<TName extends string>(\n name: TName,\n options: { type: \"direct\" } & Omit<BaseExchangeDefinition, \"name\" | \"type\">,\n): DirectExchangeDefinition<TName>;\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 options - Exchange configuration\n * @param options.type - Exchange type (must be \"fanout\")\n * @param options.durable - If true, the exchange survives broker restarts (default: true)\n * @param options.autoDelete - If true, the exchange is deleted when no queues are bound\n * @param options.internal - If true, the exchange cannot be directly published to\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', { type: 'fanout' });\n * ```\n */\nexport function defineExchange<TName extends string>(\n name: TName,\n options: { type: \"fanout\" } & Omit<BaseExchangeDefinition, \"name\" | \"type\">,\n): FanoutExchangeDefinition<TName>;\n\n/**\n * Define a headers exchange.\n *\n * A headers exchange routes messages to all bound queues based on header matching.\n * This exchange type is ideal for complex routing scenarios.\n *\n * @param name - The name of the exchange\n * @param options - Exchange configuration\n * @param options.type - Exchange type (must be \"headers\")\n * @param options.durable - If true, the exchange survives broker restarts (default: true)\n * @param options.autoDelete - If true, the exchange is deleted when no queues are bound\n * @param options.internal - If true, the exchange cannot be directly published to\n * @param options.arguments - Additional AMQP arguments for the exchange\n * @returns A headers exchange definition\n *\n * @example\n * ```typescript\n * const routesExchange = defineExchange('routes', { type: 'headers' });\n * ```\n */\nexport function defineExchange<TName extends string>(\n name: TName,\n options: { type: \"headers\" } & Omit<BaseExchangeDefinition, \"name\" | \"type\">,\n): HeadersExchangeDefinition<TName>;\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 options - Optional exchange configuration\n * @param options.type - Exchange type (one of \"topic\", \"direct\", \"fanout\", \"headers\") (default: \"topic\")\n * @param options.durable - If true, the exchange survives broker restarts (default: true)\n * @param options.autoDelete - If true, the exchange is deleted when no queues are bound\n * @param options.internal - If true, the exchange cannot be directly published to\n * @param options.arguments - Additional AMQP arguments for the exchange\n * @returns An exchange definition\n * @internal\n */\nexport function defineExchange(\n name: string,\n options?: { type?: \"topic\" | \"direct\" | \"fanout\" | \"headers\" } & Omit<\n BaseExchangeDefinition,\n \"name\" | \"type\"\n >,\n): ExchangeDefinition {\n const type = options?.type ?? \"topic\";\n return {\n name,\n type,\n durable: true,\n ...options,\n };\n}\n","import type { MessageDefinition } from \"../types.js\";\nimport type { StandardSchemaV1 } from \"@standard-schema/spec\";\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","import type { ExtractQueueFromEntry, QueueDefinition, QueueEntry } from \"../types.js\";\nimport { isQueueWithTtlBackoffInfrastructure } from \"./ttl-backoff.js\";\n\n/**\n * Extract the plain QueueDefinition from a QueueEntry.\n * @internal\n */\nfunction extractQueueFromEntry(entry: QueueEntry): QueueDefinition {\n if (isQueueWithTtlBackoffInfrastructure(entry)) {\n return entry.queue;\n }\n return entry;\n}\n\n/**\n * Extract the plain QueueDefinition from a QueueEntry.\n *\n * **Why this function exists:**\n * When you configure a queue with TTL-backoff retry,\n * `defineQueue` returns a wrapper object that includes\n * the main queue, wait queue, headers exchanges, and bindings. This function extracts the underlying\n * queue definition so you can access properties like `name`, `type`, etc.\n *\n * **When to use:**\n * - When you need to access queue properties (name, type, etc.)\n * - When passing a queue to functions that expect a plain QueueDefinition\n * - Works safely on both plain queues and infrastructure wrappers\n *\n * **How it works:**\n * - If the entry is a `QueueWithTtlBackoffInfrastructure`, returns `entry.queue`\n * - Otherwise, returns the entry as-is (it's already a plain QueueDefinition)\n *\n * @param entry - The queue entry (either plain QueueDefinition or QueueWithTtlBackoffInfrastructure)\n * @returns The plain QueueDefinition\n *\n * @example\n * ```typescript\n * import { defineQueue, extractQueue } from '@amqp-contract/contract';\n *\n * // TTL-backoff queue returns a wrapper\n * const orderQueue = defineQueue('orders', {\n * retry: { mode: 'ttl-backoff', maxRetries: 3 },\n * });\n *\n * // Use extractQueue to access the queue name\n * const queueName = extractQueue(orderQueue).name; // 'orders'\n *\n * // Also works safely on plain queues\n * const plainQueue = defineQueue('simple', { type: 'quorum', retry: { mode: 'immediate-requeue' } });\n * const plainName = extractQueue(plainQueue).name; // 'simple'\n *\n * // Access other properties\n * const queueDef = extractQueue(orderQueue);\n * console.log(queueDef.name); // 'orders'\n * console.log(queueDef.type); // 'quorum'\n * ```\n *\n * @see isQueueWithTtlBackoffInfrastructure - Type guard to check if extraction is needed\n */\nexport function extractQueue<T extends QueueEntry>(entry: T): ExtractQueueFromEntry<T> {\n return extractQueueFromEntry(entry) as ExtractQueueFromEntry<T>;\n}\n","import type {\n DirectExchangeDefinition,\n ExchangeBindingDefinition,\n ExchangeDefinition,\n FanoutExchangeDefinition,\n HeadersExchangeDefinition,\n QueueBindingDefinition,\n QueueEntry,\n TopicExchangeDefinition,\n} from \"../types.js\";\nimport { extractQueue } from \"./queue-utils.js\";\n\n/**\n * Define a binding between a queue and a fanout or headers exchange.\n *\n * Binds a queue to a fanout or headers exchange (no routing key needed).\n * Fanout and headers exchanges ignore routing keys, so this overload doesn't require one.\n *\n * @param queue - The queue definition or queue with infrastructure to bind\n * @param exchange - The fanout or headers 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');\n * const logsExchange = defineExchange('logs', { type: 'fanout' });\n *\n * const binding = defineQueueBinding(logsQueue, logsExchange);\n * ```\n */\nexport function defineQueueBinding(\n queue: QueueEntry,\n exchange: FanoutExchangeDefinition | HeadersExchangeDefinition,\n options?: Omit<\n Extract<\n QueueBindingDefinition,\n { exchange: FanoutExchangeDefinition | HeadersExchangeDefinition }\n >,\n \"type\" | \"queue\" | \"exchange\" | \"routingKey\"\n >,\n): Extract<\n QueueBindingDefinition,\n { exchange: FanoutExchangeDefinition | HeadersExchangeDefinition }\n>;\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 or queue with infrastructure 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');\n * const ordersExchange = defineExchange('orders');\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: QueueEntry,\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 or queue with infrastructure 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: QueueEntry,\n exchange: ExchangeDefinition,\n options?: {\n routingKey?: string;\n arguments?: Record<string, unknown>;\n },\n): QueueBindingDefinition {\n // Extract the plain queue definition from QueueEntry\n const queueDef = extractQueue(queue);\n\n if (exchange.type === \"fanout\" || exchange.type === \"headers\") {\n return {\n type: \"queue\",\n queue: queueDef,\n exchange,\n ...(options?.arguments && { arguments: options.arguments }),\n } as QueueBindingDefinition;\n }\n\n return {\n type: \"queue\",\n queue: queueDef,\n exchange,\n routingKey: options?.routingKey,\n ...(options?.arguments && { arguments: options.arguments }),\n } as QueueBindingDefinition;\n}\n\n/**\n * Internal helper to call defineQueueBinding with proper type handling.\n * Used by queue.ts to avoid circular dependency.\n * @internal\n */\nexport function defineQueueBindingInternal(\n queue: QueueEntry,\n exchange: ExchangeDefinition,\n options?: {\n routingKey?: string;\n arguments?: Record<string, unknown>;\n },\n): QueueBindingDefinition {\n if (exchange.type === \"fanout\" || exchange.type === \"headers\") {\n return defineQueueBinding(queue, exchange, options);\n }\n return defineQueueBinding(queue, exchange, options as { routingKey: string });\n}\n\n/**\n * Define a binding between two exchanges (exchange-to-exchange routing).\n *\n * Binds a destination exchange to a fanout or headers source exchange.\n * Messages published to the source exchange will be forwarded to the destination exchange.\n * Fanout and headers exchanges ignore routing keys, so this overload doesn't require one.\n *\n * @param destination - The destination exchange definition\n * @param source - The fanout or headers 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', { type: 'fanout' });\n * const destExchange = defineExchange('all-logs', { type: 'fanout' });\n *\n * const binding = defineExchangeBinding(destExchange, sourceExchange);\n * ```\n */\nexport function defineExchangeBinding(\n destination: ExchangeDefinition,\n source: FanoutExchangeDefinition | HeadersExchangeDefinition,\n options?: Omit<\n Extract<\n ExchangeBindingDefinition,\n { source: FanoutExchangeDefinition | HeadersExchangeDefinition }\n >,\n \"type\" | \"source\" | \"destination\" | \"routingKey\"\n >,\n): Extract<\n ExchangeBindingDefinition,\n { source: FanoutExchangeDefinition | HeadersExchangeDefinition }\n>;\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');\n * const importantExchange = defineExchange('important-orders');\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\" || source.type === \"headers\") {\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","import type {\n BaseQueueDefinition,\n QueueDefinition,\n QueueEntry,\n QueueWithTtlBackoffInfrastructure,\n TtlBackoffRetryInfrastructure,\n} from \"../types.js\";\nimport { defineQueueBindingInternal } from \"./binding.js\";\nimport { defineExchange } from \"./exchange.js\";\n\n/**\n * Type guard to check if a queue entry is a QueueWithTtlBackoffInfrastructure.\n *\n * When you configure a queue with TTL-backoff retry,\n * `defineQueue` returns a `QueueWithTtlBackoffInfrastructure` instead of a plain\n * `QueueDefinition`. This type guard helps you distinguish between the two.\n *\n * **When to use:**\n * - When you need to check the type of a queue entry at runtime\n * - When writing generic code that handles both plain queues and infrastructure wrappers\n *\n * **Related functions:**\n * - `extractQueue()` - Use this to get the underlying queue definition from either type\n *\n * @param entry - The queue entry to check\n * @returns True if the entry is a QueueWithTtlBackoffInfrastructure, false otherwise\n *\n * @example\n * ```typescript\n * const queue = defineQueue('orders', {\n * retry: { mode: 'ttl-backoff' },\n * });\n *\n * if (isQueueWithTtlBackoffInfrastructure(queue)) {\n * // queue has .queue, .waitQueue, .waitQueueBinding, .retryQueueBinding, .waitExchange, .retryExchange\n * console.log('Wait queue:', queue.waitQueue.name);\n * } else {\n * // queue is a plain QueueDefinition\n * console.log('Queue:', queue.name);\n * }\n * ```\n */\nexport function isQueueWithTtlBackoffInfrastructure(\n entry: QueueEntry,\n): entry is QueueWithTtlBackoffInfrastructure {\n return (\n typeof entry === \"object\" &&\n entry !== null &&\n \"__brand\" in entry &&\n entry.__brand === \"QueueWithTtlBackoffInfrastructure\"\n );\n}\n\n/**\n * Wrap a queue definition with TTL-backoff retry infrastructure.\n */\nexport function wrapWithTtlBackoffInfrastructure(\n queue: QueueDefinition,\n): QueueWithTtlBackoffInfrastructure {\n const infra = createTtlBackoffInfrastructure(queue);\n\n return {\n __brand: \"QueueWithTtlBackoffInfrastructure\",\n queue,\n ...infra,\n };\n}\n\n/**\n * Create TTL-backoff retry infrastructure for a queue.\n *\n * This builder helper generates the wait queue, exchanges, and bindings needed for TTL-backoff retry.\n * The generated infrastructure can be spread into a contract definition.\n *\n * TTL-backoff retry works by:\n * 1. Failed messages are sent to the wait exchange with header `x-wait-queue` set to the wait queue name\n * 2. The wait queue receives these messages and holds them for a TTL period\n * 3. After TTL expires, messages are dead-lettered back to the retry exchange with header `x-retry-queue` set to the main queue name\n * 4. The main queue receives the retried message via its binding to the retry exchange\n *\n * @param queue - The main queue definition\n * @param options - Optional configuration for the wait queue\n * @returns TTL-backoff retry infrastructure containing wait queue and bindings\n * @throws {Error} If the queue does not have retry mode set to `ttl-backoff`\n *\n * @example\n * ```typescript\n * const orderQueue = defineQueue('order-processing', {\n * type: 'quorum',\n * retry: {\n * mode: 'ttl-backoff',\n * maxRetries: 5,\n * initialDelayMs: 1000,\n * },\n * });\n *\n * // Infrastructure is auto-extracted when using defineContract:\n * const contract = defineContract({\n * publishers: { ... },\n * consumers: { processOrder: defineEventConsumer(event, orderQueue) },\n * });\n * // contract.queues includes the wait queue, contract.exchanges includes retry exchanges, contract.bindings includes retry bindings\n * ```\n */\nexport function createTtlBackoffInfrastructure(\n queue: QueueDefinition,\n): TtlBackoffRetryInfrastructure {\n // Ensure queue retry mode is ttl-backoff\n if (queue.retry.mode !== \"ttl-backoff\") {\n throw new Error(\n `Queue ${queue.name} does not have ttl-backoff retry mode. Infrastructure can only be created for queues with ttl-backoff retry.`,\n );\n }\n\n // Create wait exchange (headers exchange) for routing failed messages to the wait queue\n const waitExchange = defineExchange(queue.retry.waitExchangeName, {\n type: \"headers\",\n });\n\n // Create retry exchange (headers exchange) for routing messages to retry back to main queue\n const retryExchange = defineExchange(queue.retry.retryExchangeName, {\n type: \"headers\",\n });\n\n // Create the wait queue (of same type as main queue)\n const baseWaitQueue: BaseQueueDefinition = {\n name: queue.retry.waitQueueName,\n deadLetter: {\n exchange: retryExchange, // Routes back to retry exchange after TTL (will preserve original message routing key)\n },\n retry: { mode: \"none\" }, // No retry for wait queue itself\n };\n\n const waitQueue: QueueDefinition =\n queue.type === \"quorum\"\n ? {\n ...baseWaitQueue,\n type: queue.type,\n durable: true, // Quorum queues are always durable\n }\n : {\n ...baseWaitQueue,\n type: queue.type,\n durable: queue.durable,\n };\n\n // Create binding for wait queue to receive failed messages\n const waitQueueBinding = defineQueueBindingInternal(waitQueue, waitExchange, {\n arguments: {\n \"x-match\": \"all\",\n \"x-wait-queue\": waitQueue.name, // Custom header to specify the wait queue to which messages should be routed\n },\n });\n\n // Create binding for main queue to receive messages to retry\n const retryQueueBinding = defineQueueBindingInternal(queue, retryExchange, {\n arguments: {\n \"x-match\": \"all\",\n \"x-retry-queue\": queue.name, // Custom header to specify the retry queue to which messages should be routed\n },\n });\n\n return {\n waitQueue,\n waitExchange,\n retryExchange,\n waitQueueBinding,\n retryQueueBinding,\n };\n}\n","import type {\n BaseQueueDefinition,\n DeadLetterConfig,\n DefineQueueOptions,\n DefineQueueOptionsWithDeadLetterExchange,\n ExchangeDefinition,\n ImmediateRequeueRetryOptions,\n QueueDefinition,\n QueueEntry,\n QueueEntryWithDeadLetterExchange,\n ResolvedImmediateRequeueRetryOptions,\n ResolvedTtlBackoffRetryOptions,\n TtlBackoffRetryOptions,\n} from \"../types.js\";\nimport { wrapWithTtlBackoffInfrastructure } from \"./ttl-backoff.js\";\n\n/**\n * Resolve immediate-requeue retry options with defaults.\n * @internal\n */\nfunction resolveImmediateRequeueOptions(\n options: ImmediateRequeueRetryOptions | undefined,\n): ResolvedImmediateRequeueRetryOptions {\n return {\n mode: \"immediate-requeue\",\n maxRetries: options?.maxRetries ?? 3,\n };\n}\n\n/**\n * Resolve TTL-backoff retry options with defaults.\n * @internal\n */\nfunction resolveTtlBackoffOptions(\n queueName: string,\n options: TtlBackoffRetryOptions | undefined,\n): ResolvedTtlBackoffRetryOptions {\n return {\n mode: \"ttl-backoff\",\n maxRetries: options?.maxRetries ?? 3,\n initialDelayMs: options?.initialDelayMs ?? 1000,\n maxDelayMs: options?.maxDelayMs ?? 30000,\n backoffMultiplier: options?.backoffMultiplier ?? 2,\n jitter: options?.jitter ?? true,\n waitQueueName: options?.waitQueueName ?? `${queueName}-wait`,\n waitExchangeName: options?.waitExchangeName ?? \"wait-exchange\",\n retryExchangeName: options?.retryExchangeName ?? \"retry-exchange\",\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 * By default, queues are created as quorum queues which provide better durability and\n * high-availability. Use `type: 'classic'` for special cases like non-durable queues\n * or priority queues.\n *\n * @param name - The name of the queue\n * @param options - Optional queue configuration\n * @param options.type - Queue type: 'quorum' (default, recommended) or 'classic'\n * @param options.durable - If true, the queue survives broker restarts. Quorum queues only support durable queues (default: true)\n * @param options.exclusive - If true, the queue can only be used by the declaring connection and is deleted when that connection closes. Only supported with classic queues.\n * @param options.autoDelete - If true, the queue is deleted when the last consumer unsubscribes. Only supported with classic queues.\n * @param options.maxPriority - Maximum priority level for priority queue (1-255, recommended: 1-10). Only supported with classic queues.\n * @param options.deadLetter - Dead letter configuration for handling failed messages\n * @param options.retry - Retry configuration for handling failed message processing\n * @param options.arguments - Additional AMQP arguments (e.g., x-message-ttl)\n * @returns A queue definition\n *\n * @example\n * ```typescript\n * // Quorum queue (default, recommended for production)\n * const orderQueue = defineQueue('order-processing');\n *\n * // Explicit quorum queue with dead letter exchange\n * const dlx = defineExchange('orders-dlx');\n * const orderQueueWithDLX = defineQueue('order-processing', {\n * type: 'quorum',\n * deadLetter: {\n * exchange: dlx,\n * routingKey: 'order.failed'\n * },\n * arguments: {\n * 'x-message-ttl': 86400000, // 24 hours\n * }\n * });\n *\n * // Classic queue (for special cases)\n * const tempQueue = defineQueue('temp-queue', {\n * type: 'classic',\n * durable: false,\n * autoDelete: true,\n * });\n *\n * // Priority queue (requires classic type)\n * const taskQueue = defineQueue('urgent-tasks', {\n * type: 'classic',\n * maxPriority: 10,\n * });\n *\n * // Queue with TTL-backoff retry (returns infrastructure automatically)\n * const dlx = defineExchange('orders-dlx', { type: 'direct' });\n * const orderQueue = defineQueue('order-processing', {\n * deadLetter: { exchange: dlx },\n * retry: { mode: 'ttl-backoff', maxRetries: 5 },\n * });\n * // orderQueue is QueueWithTtlBackoffInfrastructure, pass directly to defineContract\n * ```\n */\nexport function defineQueue<TName extends string, TDlx extends ExchangeDefinition>(\n name: TName,\n options: DefineQueueOptionsWithDeadLetterExchange<TDlx>,\n): QueueEntryWithDeadLetterExchange<TName, TDlx>;\n\nexport function defineQueue<TName extends string>(\n name: TName,\n options?: DefineQueueOptions,\n): QueueEntry<TName>;\n\nexport function defineQueue(name: string, options?: DefineQueueOptions): QueueEntry {\n const opts = options ?? {};\n const type = opts.type ?? \"quorum\";\n const durable = opts.durable ?? true;\n\n // Build base properties shared by both queue types\n const baseProps: {\n name: string;\n deadLetter?: DeadLetterConfig;\n arguments?: Record<string, unknown>;\n } = {\n name,\n ...(opts.deadLetter !== undefined && { deadLetter: opts.deadLetter }),\n ...(opts.arguments !== undefined && { arguments: opts.arguments }),\n };\n\n // Build specific properties for classic queues\n const classicProps: {\n exclusive?: boolean;\n autoDelete?: boolean;\n maxPriority?: number;\n } = {\n ...(opts.exclusive !== undefined && { exclusive: opts.exclusive }),\n ...(opts.autoDelete !== undefined && { autoDelete: opts.autoDelete }),\n ...(opts.maxPriority !== undefined && { maxPriority: opts.maxPriority }),\n };\n\n if (type === \"quorum\") {\n // Quorum queues do not support non-durable, exclusive, autoDelete, or maxPriority\n if (opts.durable === false) {\n throw new Error(\"Non-durable queues are not supported with quorum type.\");\n }\n if (opts.exclusive !== undefined) {\n throw new Error(\"Exclusive queues are not supported with quorum type.\");\n }\n if (opts.autoDelete !== undefined) {\n throw new Error(\"Auto-deleting queues are not supported with quorum type.\");\n }\n if (opts.maxPriority !== undefined) {\n throw new Error(\"Priority queues are not supported with quorum type.\");\n }\n } else {\n // Validate maxPriority\n if (opts.maxPriority !== undefined) {\n if (opts.maxPriority < 1 || opts.maxPriority > 255) {\n throw new Error(\n `Invalid maxPriority: ${opts.maxPriority}. Must be between 1 and 255. Recommended range: 1-10.`,\n );\n }\n }\n }\n\n const inputRetry = opts.retry ?? { mode: \"none\" as const };\n\n // Validate retry requirements\n if (inputRetry.mode === \"immediate-requeue\" || inputRetry.mode === \"ttl-backoff\") {\n if (inputRetry.maxRetries !== undefined) {\n if (inputRetry.maxRetries < 1 || !Number.isInteger(inputRetry.maxRetries)) {\n throw new Error(\n `Queue \"${name}\" uses ${inputRetry.mode} retry mode with invalid maxRetries: ${inputRetry.maxRetries}. Must be a positive integer.`,\n );\n }\n }\n }\n\n // Resolve retry options with defaults\n const retry =\n inputRetry.mode === \"immediate-requeue\"\n ? resolveImmediateRequeueOptions(inputRetry)\n : inputRetry.mode === \"ttl-backoff\"\n ? resolveTtlBackoffOptions(name, inputRetry)\n : inputRetry;\n\n const baseQueueDefinition: BaseQueueDefinition = {\n ...baseProps,\n retry,\n };\n\n const queueDefinition: QueueDefinition =\n type === \"quorum\"\n ? {\n ...baseQueueDefinition,\n type,\n durable: true, // Quorum queues are always durable\n }\n : {\n ...baseQueueDefinition,\n ...classicProps,\n type,\n durable,\n };\n\n // If TTL-backoff retry, wrap with infrastructure\n if (retry.mode === \"ttl-backoff\") {\n return wrapWithTtlBackoffInfrastructure(queueDefinition);\n }\n\n return queueDefinition;\n}\n","import type {\n DirectExchangeDefinition,\n ExchangeDefinition,\n FanoutExchangeDefinition,\n HeadersExchangeDefinition,\n MessageDefinition,\n PublisherDefinition,\n TopicExchangeDefinition,\n} from \"../types.js\";\n\n/**\n * Define a message publisher for a fanout or headers 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. For headers exchanges,\n * routing is based on message headers rather than routing keys, so no routing key is required either.\n *\n * The message schema is validated when publishing to ensure type safety.\n *\n * **Which pattern to use:**\n *\n * | Pattern | Best for | Description |\n * |---------|----------|-------------|\n * | `definePublisher` + `defineConsumer` | Independent definition | Define publishers and consumers separately with manual schema consistency |\n * | `defineEventPublisher` + `defineEventConsumer` | Event broadcasting | Define event publisher first, create consumers that subscribe to it |\n * | `defineCommandConsumer` + `defineCommandPublisher` | Task queues | Define command consumer first, create publishers that send commands to it |\n *\n * Use `defineEventPublisher` when:\n * - One publisher feeds multiple consumers\n * - You want automatic schema consistency between publisher and consumers\n * - You're building event-driven architectures\n *\n * @param exchange - The fanout or headers 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', { type: 'fanout' });\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 *\n * @see defineEventPublisher - For event-driven patterns with automatic schema consistency\n * @see defineCommandConsumer - For task queue patterns with automatic schema consistency\n */\nexport function definePublisher<TMessage extends MessageDefinition>(\n exchange: FanoutExchangeDefinition | HeadersExchangeDefinition,\n message: TMessage,\n options?: Omit<\n Extract<\n PublisherDefinition<TMessage>,\n { exchange: FanoutExchangeDefinition | HeadersExchangeDefinition }\n >,\n \"exchange\" | \"message\" | \"routingKey\"\n >,\n): Extract<\n PublisherDefinition<TMessage>,\n { exchange: FanoutExchangeDefinition | HeadersExchangeDefinition }\n>;\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 * **Which pattern to use:**\n *\n * | Pattern | Best for | Description |\n * |---------|----------|-------------|\n * | `definePublisher` + `defineConsumer` | Independent definition | Define publishers and consumers separately with manual schema consistency |\n * | `defineEventPublisher` + `defineEventConsumer` | Event broadcasting | Define event publisher first, create consumers that subscribe to it |\n * | `defineCommandConsumer` + `defineCommandPublisher` | Task queues | Define command consumer first, create publishers that send commands to it |\n *\n * Use `defineEventPublisher` when:\n * - One publisher feeds multiple consumers\n * - You want automatic schema consistency between publisher and consumers\n * - You're building event-driven architectures\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');\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 *\n * @see defineEventPublisher - For event-driven patterns with automatic schema consistency\n * @see defineCommandConsumer - For task queue patterns with automatic schema consistency\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\" || exchange.type === \"headers\") {\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 * Helper to call definePublisher with proper type handling.\n * Type safety is enforced by overloaded public function signatures.\n * @internal\n */\nexport function definePublisherInternal<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\" || exchange.type === \"headers\") {\n return definePublisher(exchange, message, options);\n }\n return definePublisher(exchange, message, options as { routingKey: string });\n}\n","import type {\n CommandConsumerConfigBase,\n ConsumerDefinition,\n ConsumerEntry,\n EventConsumerResultBase,\n MessageDefinition,\n QueueEntry,\n} from \"../types.js\";\n\n/**\n * Type guard to check if an entry is an EventConsumerResult.\n */\nfunction isEventConsumerResultEntry(entry: ConsumerEntry): entry is EventConsumerResultBase {\n return \"__brand\" in entry && entry.__brand === \"EventConsumerResult\";\n}\n\n/**\n * Type guard to check if an entry is a CommandConsumerConfig.\n */\nfunction isCommandConsumerConfigEntry(entry: ConsumerEntry): entry is CommandConsumerConfigBase {\n return \"__brand\" in entry && entry.__brand === \"CommandConsumerConfig\";\n}\n\n/**\n * Extract the ConsumerDefinition from any ConsumerEntry type.\n *\n * Handles the following entry types:\n * - ConsumerDefinition: returned as-is\n * - EventConsumerResult: returns the nested `.consumer` property\n * - CommandConsumerConfig: returns the nested `.consumer` property\n *\n * Use this function when you need to access the underlying ConsumerDefinition\n * from a consumer entry that may have been created with defineEventConsumer\n * or defineCommandConsumer.\n *\n * @param entry - The consumer entry to extract from\n * @returns The underlying ConsumerDefinition\n *\n * @example\n * ```typescript\n * // Works with plain ConsumerDefinition\n * const consumer1 = defineConsumer(queue, message);\n * extractConsumer(consumer1).queue.name; // \"my-queue\"\n *\n * // Works with EventConsumerResult\n * const consumer2 = defineEventConsumer(eventPublisher, queue);\n * extractConsumer(consumer2).queue.name; // \"my-queue\"\n *\n * // Works with CommandConsumerConfig\n * const consumer3 = defineCommandConsumer(queue, exchange, message, { routingKey: \"cmd\" });\n * extractConsumer(consumer3).queue.name; // \"my-queue\"\n * ```\n */\nexport function extractConsumer(entry: ConsumerEntry): ConsumerDefinition {\n if (isEventConsumerResultEntry(entry) || isCommandConsumerConfigEntry(entry)) {\n return entry.consumer;\n }\n // Otherwise it's a plain ConsumerDefinition\n return entry;\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 * **Which pattern to use:**\n *\n * | Pattern | Best for | Description |\n * |---------|----------|-------------|\n * | `definePublisher` + `defineConsumer` | Independent definition | Define publishers and consumers separately with manual schema consistency |\n * | `defineEventPublisher` + `defineEventConsumer` | Event broadcasting | Define event publisher first, create consumers that subscribe to it |\n * | `defineCommandConsumer` + `defineCommandPublisher` | Task queues | Define command consumer first, create publishers that send commands to it |\n *\n * Use `defineCommandConsumer` when:\n * - One consumer receives from multiple publishers\n * - You want automatic schema consistency between consumer and publishers\n * - You're building task queue or command patterns\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');\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 *\n * @see defineCommandConsumer - For task queue patterns with automatic schema consistency\n * @see defineEventPublisher - For event-driven patterns with automatic schema consistency\n */\nexport function defineConsumer<TMessage extends MessageDefinition>(\n queue: QueueEntry,\n message: TMessage,\n options?: Omit<ConsumerDefinition<TMessage>, \"queue\" | \"message\">,\n): ConsumerDefinition<TMessage> {\n return {\n queue,\n message,\n ...options,\n };\n}\n","import type {\n ConsumerDefinition,\n DirectExchangeDefinition,\n ExchangeBindingDefinition,\n ExchangeDefinition,\n FanoutExchangeDefinition,\n HeadersExchangeDefinition,\n MessageDefinition,\n PublisherDefinition,\n QueueBindingDefinition,\n QueueEntry,\n TopicExchangeDefinition,\n} from \"../types.js\";\nimport { defineExchangeBinding, defineQueueBindingInternal } from \"./binding.js\";\nimport { defineConsumer } from \"./consumer.js\";\nimport { definePublisherInternal } from \"./publisher.js\";\nimport type { BindingPattern, RoutingKey } from \"./routing-types.js\";\n\n/**\n * Configuration for a command consumer.\n *\n * Commands are sent by one or more publishers to a single consumer (task queue pattern).\n * The consumer \"owns\" the queue, and publishers send commands to it.\n *\n * @template TMessage - The message definition\n * @template TExchange - The exchange definition\n * @template TRoutingKey - The routing key type (undefined for fanout and headers exchanges)\n */\nexport type CommandConsumerConfig<\n TMessage extends MessageDefinition,\n TExchange extends ExchangeDefinition,\n TRoutingKey extends string | undefined = undefined,\n TQueue extends QueueEntry = QueueEntry,\n> = {\n /** Discriminator to identify this as a command consumer config */\n __brand: \"CommandConsumerConfig\";\n /** The consumer definition for processing commands */\n consumer: ConsumerDefinition<TMessage>;\n /** The binding connecting the queue to the exchange */\n binding: QueueBindingDefinition;\n /** The exchange that receives commands */\n exchange: TExchange;\n /** The queue this consumer reads from */\n queue: TQueue;\n /** The message definition */\n message: TMessage;\n /** The routing key pattern for the binding */\n routingKey: TRoutingKey;\n};\n\n/**\n * Configuration for a bridged command publisher.\n *\n * A bridged publisher publishes to a bridge exchange (local domain), which forwards\n * messages to the target exchange (remote domain) via an exchange-to-exchange binding.\n *\n * @template TMessage - The message definition\n * @template TBridgeExchange - The bridge (local domain) exchange definition\n * @template TTargetExchange - The target (remote domain) exchange definition\n */\nexport type BridgedPublisherConfig<\n TMessage extends MessageDefinition,\n TBridgeExchange extends ExchangeDefinition,\n TTargetExchange extends ExchangeDefinition,\n> = {\n /** Discriminator to identify this as a bridged publisher config */\n __brand: \"BridgedPublisherConfig\";\n /** The publisher definition (publishes to bridge exchange) */\n publisher: PublisherDefinition<TMessage>;\n /** The exchange-to-exchange binding (bridge → target) */\n exchangeBinding: ExchangeBindingDefinition;\n /** The bridge (local domain) exchange */\n bridgeExchange: TBridgeExchange;\n /** The target (remote domain) exchange */\n targetExchange: TTargetExchange;\n};\n\n/**\n * Define a command consumer for receiving commands via fanout exchange.\n *\n * Commands are sent by publishers to a specific queue. The consumer \"owns\" the\n * queue and defines what commands it accepts.\n *\n * @param queue - The queue that will receive commands\n * @param exchange - The fanout exchange that routes commands\n * @param message - The message definition (schema and metadata)\n * @param options - Optional binding configuration\n * @param options.arguments - Additional AMQP arguments\n * @returns A command consumer configuration\n *\n * @example\n * ```typescript\n * const tasksExchange = defineExchange('tasks', { type: 'fanout' });\n * const taskMessage = defineMessage(z.object({ taskId: z.string() }));\n *\n * // Consumer owns the queue\n * const executeTask = defineCommandConsumer(taskQueue, tasksExchange, taskMessage);\n *\n * // Publishers send commands to it\n * const sendTask = defineCommandPublisher(executeTask);\n * ```\n */\nexport function defineCommandConsumer<\n TMessage extends MessageDefinition,\n TQueueEntry extends QueueEntry,\n TExchange extends FanoutExchangeDefinition,\n>(\n queue: TQueueEntry,\n exchange: TExchange,\n message: TMessage,\n options?: {\n arguments?: Record<string, unknown>;\n },\n): CommandConsumerConfig<TMessage, TExchange, undefined, TQueueEntry>;\n\n/**\n * Define a command consumer for receiving commands via headers exchange.\n *\n * Commands are sent by publishers to a specific queue. The consumer \"owns\" the\n * queue and defines what commands it accepts.\n *\n * @param queue - The queue that will receive commands\n * @param exchange - The headers exchange that routes commands\n * @param message - The message definition (schema and metadata)\n * @param options - Optional binding configuration\n * @param options.arguments - Additional AMQP arguments\n * @returns A command consumer configuration\n *\n * @example\n * ```typescript\n * const tasksExchange = defineExchange('tasks', { type: 'headers' });\n * const taskMessage = defineMessage(z.object({ taskId: z.string() }));\n *\n * // Consumer owns the queue\n * const executeTask = defineCommandConsumer(taskQueue, tasksExchange, taskMessage);\n *\n * // Publishers send commands to it\n * const sendTask = defineCommandPublisher(executeTask);\n * ```\n */\nexport function defineCommandConsumer<\n TMessage extends MessageDefinition,\n TQueueEntry extends QueueEntry,\n TExchange extends HeadersExchangeDefinition,\n>(\n queue: TQueueEntry,\n exchange: TExchange,\n message: TMessage,\n options?: {\n arguments?: Record<string, unknown>;\n },\n): CommandConsumerConfig<TMessage, TExchange, undefined, TQueueEntry>;\n\n/**\n * Define a command consumer for receiving commands via direct exchange.\n *\n * Commands are sent by publishers with a specific routing key that matches\n * the binding pattern.\n *\n * @param queue - The queue that will receive commands\n * @param exchange - The direct exchange that routes commands\n * @param message - The message definition (schema and metadata)\n * @param options - Configuration with required routing key\n * @param options.routingKey - The routing key for the binding\n * @param options.arguments - Additional AMQP arguments\n * @returns A command consumer configuration\n *\n * @example\n * ```typescript\n * const tasksExchange = defineExchange('tasks', { type: 'direct' });\n * const taskMessage = defineMessage(z.object({ taskId: z.string() }));\n *\n * const executeTask = defineCommandConsumer(taskQueue, tasksExchange, taskMessage, {\n * routingKey: 'task.execute',\n * });\n *\n * const sendTask = defineCommandPublisher(executeTask);\n * ```\n */\nexport function defineCommandConsumer<\n TMessage extends MessageDefinition,\n TRoutingKey extends string,\n TQueueEntry extends QueueEntry,\n TExchange extends DirectExchangeDefinition,\n>(\n queue: TQueueEntry,\n exchange: TExchange,\n message: TMessage,\n options: {\n routingKey: RoutingKey<TRoutingKey>;\n arguments?: Record<string, unknown>;\n },\n): CommandConsumerConfig<TMessage, TExchange, TRoutingKey, TQueueEntry>;\n\n/**\n * Define a command consumer for receiving commands via topic exchange.\n *\n * The consumer binds with a routing key pattern (can use * and # wildcards).\n * Publishers then send commands with concrete routing keys that match the pattern.\n *\n * @param queue - The queue that will receive commands\n * @param exchange - The topic exchange that routes commands\n * @param message - The message definition (schema and metadata)\n * @param options - Configuration with required routing key pattern\n * @param options.routingKey - The routing key pattern for the binding\n * @param options.arguments - Additional AMQP arguments\n * @returns A command consumer configuration\n *\n * @example\n * ```typescript\n * const ordersExchange = defineExchange('orders', { type: 'topic' });\n * const orderMessage = defineMessage(z.object({ orderId: z.string() }));\n *\n * // Consumer uses pattern to receive multiple command types\n * const processOrder = defineCommandConsumer(orderQueue, ordersExchange, orderMessage, {\n * routingKey: 'order.*',\n * });\n *\n * // Publishers send with concrete keys\n * const createOrder = defineCommandPublisher(processOrder, {\n * routingKey: 'order.create',\n * });\n * const updateOrder = defineCommandPublisher(processOrder, {\n * routingKey: 'order.update',\n * });\n * ```\n */\nexport function defineCommandConsumer<\n TMessage extends MessageDefinition,\n TRoutingKey extends string,\n TQueueEntry extends QueueEntry,\n TExchange extends TopicExchangeDefinition,\n>(\n queue: TQueueEntry,\n exchange: TExchange,\n message: TMessage,\n options: {\n routingKey: BindingPattern<TRoutingKey>;\n arguments?: Record<string, unknown>;\n },\n): CommandConsumerConfig<TMessage, TExchange, TRoutingKey, TQueueEntry>;\n\n/**\n * Implementation of defineCommandConsumer.\n * @internal\n */\nexport function defineCommandConsumer<TMessage extends MessageDefinition>(\n queue: QueueEntry,\n exchange: ExchangeDefinition,\n message: TMessage,\n options?: {\n routingKey?: string;\n arguments?: Record<string, unknown>;\n },\n): CommandConsumerConfig<TMessage, ExchangeDefinition, string | undefined> {\n const consumer = defineConsumer(queue, message);\n const binding = defineQueueBindingInternal(queue, exchange, options);\n\n return {\n __brand: \"CommandConsumerConfig\",\n consumer,\n binding,\n exchange,\n queue,\n message,\n routingKey: options?.routingKey,\n };\n}\n\n/**\n * Create a bridged publisher that sends commands to a fanout exchange consumer via a bridge exchange.\n *\n * @param commandConsumer - The command consumer configuration\n * @param options - Configuration with required bridgeExchange\n * @param options.bridgeExchange - The local domain exchange to bridge through (must be fanout to match target)\n * @returns A bridged publisher configuration\n */\nexport function defineCommandPublisher<\n TMessage extends MessageDefinition,\n TExchange extends FanoutExchangeDefinition,\n TBridgeExchange extends FanoutExchangeDefinition,\n>(\n commandConsumer: CommandConsumerConfig<TMessage, TExchange, undefined>,\n options: {\n bridgeExchange: TBridgeExchange;\n },\n): BridgedPublisherConfig<TMessage, TBridgeExchange, TExchange>;\n\n/**\n * Create a bridged publisher that sends commands to a headers exchange consumer via a bridge exchange.\n *\n * @param commandConsumer - The command consumer configuration\n * @param options - Configuration with required bridgeExchange\n * @param options.bridgeExchange - The local domain exchange to bridge through (must be headers to match target)\n * @returns A bridged publisher configuration\n */\nexport function defineCommandPublisher<\n TMessage extends MessageDefinition,\n TExchange extends HeadersExchangeDefinition,\n TBridgeExchange extends HeadersExchangeDefinition,\n>(\n commandConsumer: CommandConsumerConfig<TMessage, TExchange, undefined>,\n options: {\n bridgeExchange: TBridgeExchange;\n },\n): BridgedPublisherConfig<TMessage, TBridgeExchange, TExchange>;\n\n/**\n * Create a bridged publisher that sends commands to a direct exchange consumer via a bridge exchange.\n *\n * @param commandConsumer - The command consumer configuration\n * @param options - Configuration with required bridgeExchange\n * @param options.bridgeExchange - The bridge exchange (must be direct or topic to preserve routing keys)\n * @returns A bridged publisher configuration\n */\nexport function defineCommandPublisher<\n TMessage extends MessageDefinition,\n TRoutingKey extends string,\n TExchange extends DirectExchangeDefinition,\n TBridgeExchange extends DirectExchangeDefinition | TopicExchangeDefinition,\n>(\n commandConsumer: CommandConsumerConfig<TMessage, TExchange, TRoutingKey>,\n options: {\n bridgeExchange: TBridgeExchange;\n },\n): BridgedPublisherConfig<TMessage, TBridgeExchange, TExchange>;\n\n/**\n * Create a bridged publisher that sends commands to a topic exchange consumer via a bridge exchange.\n *\n * @param commandConsumer - The command consumer configuration\n * @param options - Configuration with required bridgeExchange and optional routingKey override\n * @param options.bridgeExchange - The bridge exchange (must be direct or topic to preserve routing keys)\n * @param options.routingKey - Override routing key (must match consumer's pattern)\n * @returns A bridged publisher configuration\n */\nexport function defineCommandPublisher<\n TMessage extends MessageDefinition,\n TRoutingKey extends string,\n TExchange extends TopicExchangeDefinition,\n TBridgeExchange extends DirectExchangeDefinition | TopicExchangeDefinition,\n TPublisherRoutingKey extends string = TRoutingKey,\n>(\n commandConsumer: CommandConsumerConfig<TMessage, TExchange, TRoutingKey>,\n options: {\n bridgeExchange: TBridgeExchange;\n routingKey?: RoutingKey<TPublisherRoutingKey>;\n },\n): BridgedPublisherConfig<TMessage, TBridgeExchange, TExchange>;\n\n/**\n * Create a publisher that sends commands to a fanout exchange consumer.\n *\n * @param commandConsumer - The command consumer configuration\n * @returns A publisher definition\n *\n * @example\n * ```typescript\n * const executeTask = defineCommandConsumer(taskQueue, fanoutExchange, taskMessage);\n * const sendTask = defineCommandPublisher(executeTask);\n * ```\n */\nexport function defineCommandPublisher<TMessage extends MessageDefinition>(\n commandConsumer: CommandConsumerConfig<TMessage, FanoutExchangeDefinition, undefined>,\n): { message: TMessage; exchange: FanoutExchangeDefinition };\n\n/**\n * Create a publisher that sends commands to a headers exchange consumer.\n *\n * @param commandConsumer - The command consumer configuration\n * @returns A publisher definition\n *\n * @example\n * ```typescript\n * const executeTask = defineCommandConsumer(taskQueue, headersExchange, taskMessage);\n * const sendTask = defineCommandPublisher(executeTask);\n * ```\n */\nexport function defineCommandPublisher<TMessage extends MessageDefinition>(\n commandConsumer: CommandConsumerConfig<TMessage, HeadersExchangeDefinition, undefined>,\n): { message: TMessage; exchange: HeadersExchangeDefinition };\n\n/**\n * Create a publisher that sends commands to a direct exchange consumer.\n *\n * @param commandConsumer - The command consumer configuration\n * @returns A publisher definition\n */\nexport function defineCommandPublisher<\n TMessage extends MessageDefinition,\n TRoutingKey extends string,\n>(\n commandConsumer: CommandConsumerConfig<TMessage, DirectExchangeDefinition, TRoutingKey>,\n): { message: TMessage; exchange: DirectExchangeDefinition; routingKey: string };\n\n/**\n * Create a publisher that sends commands to a topic exchange consumer.\n *\n * For topic exchanges where the consumer uses a pattern, the publisher can\n * optionally specify a concrete routing key that matches the pattern.\n *\n * @param commandConsumer - The command consumer configuration\n * @param options - Optional binding configuration\n * @param options.routingKey - Override routing key (must match consumer's pattern)\n * @returns A publisher definition\n *\n * @example\n * ```typescript\n * // Consumer binds with pattern\n * const processOrder = defineCommandConsumer(orderQueue, topicExchange, orderMessage, {\n * routingKey: 'order.*',\n * });\n *\n * // Publisher uses concrete key matching the pattern\n * const createOrder = defineCommandPublisher(processOrder, {\n * routingKey: 'order.create',\n * });\n * ```\n */\nexport function defineCommandPublisher<\n TMessage extends MessageDefinition,\n TRoutingKey extends string,\n TPublisherRoutingKey extends string = TRoutingKey,\n>(\n commandConsumer: CommandConsumerConfig<TMessage, TopicExchangeDefinition, TRoutingKey>,\n options?: {\n routingKey?: RoutingKey<TPublisherRoutingKey>;\n },\n): { message: TMessage; exchange: TopicExchangeDefinition; routingKey: string };\n\n/**\n * Implementation of defineCommandPublisher.\n * @internal\n */\nexport function defineCommandPublisher<TMessage extends MessageDefinition>(\n commandConsumer: CommandConsumerConfig<TMessage, ExchangeDefinition, string | undefined>,\n options?: {\n routingKey?: string;\n bridgeExchange?: ExchangeDefinition;\n },\n):\n | PublisherDefinition<TMessage>\n | BridgedPublisherConfig<TMessage, ExchangeDefinition, ExchangeDefinition> {\n const { exchange: targetExchange, message, routingKey: consumerRoutingKey } = commandConsumer;\n\n // For topic exchanges, publisher can override the routing key\n const publisherRoutingKey = options?.routingKey ?? consumerRoutingKey;\n\n const bridgeExchange = options?.bridgeExchange;\n\n if (bridgeExchange) {\n // Bridged: publisher publishes to bridge exchange, e2e binding from bridge → target\n const publisherOptions: { routingKey?: string } = {};\n if (publisherRoutingKey !== undefined) {\n publisherOptions.routingKey = publisherRoutingKey;\n }\n\n const publisher = definePublisherInternal(bridgeExchange, message, publisherOptions);\n\n // Create e2e binding: target ← bridge (destination = target, source = bridge)\n const e2eBindingOptions: { routingKey?: string } = {};\n if (publisherRoutingKey !== undefined) {\n e2eBindingOptions.routingKey = publisherRoutingKey;\n }\n const e2eBinding =\n bridgeExchange.type === \"fanout\" || bridgeExchange.type === \"headers\"\n ? defineExchangeBinding(targetExchange, bridgeExchange)\n : defineExchangeBinding(\n targetExchange,\n bridgeExchange as DirectExchangeDefinition | TopicExchangeDefinition,\n e2eBindingOptions as { routingKey: string },\n );\n\n return {\n __brand: \"BridgedPublisherConfig\",\n publisher,\n exchangeBinding: e2eBinding,\n bridgeExchange,\n targetExchange,\n };\n }\n\n const publisherOptions: { routingKey?: string } = {};\n if (publisherRoutingKey !== undefined) {\n publisherOptions.routingKey = publisherRoutingKey;\n }\n\n return definePublisherInternal(targetExchange, message, publisherOptions);\n}\n\n/**\n * Type guard to check if a value is a CommandConsumerConfig.\n *\n * @param value - The value to check\n * @returns True if the value is a CommandConsumerConfig\n */\nexport function isCommandConsumerConfig(\n value: unknown,\n): value is CommandConsumerConfig<MessageDefinition, ExchangeDefinition, string | undefined> {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"__brand\" in value &&\n value.__brand === \"CommandConsumerConfig\"\n );\n}\n\n/**\n * Type guard to check if a value is a BridgedPublisherConfig.\n *\n * @param value - The value to check\n * @returns True if the value is a BridgedPublisherConfig\n */\nexport function isBridgedPublisherConfig(\n value: unknown,\n): value is BridgedPublisherConfig<MessageDefinition, ExchangeDefinition, ExchangeDefinition> {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"__brand\" in value &&\n value.__brand === \"BridgedPublisherConfig\"\n );\n}\n","import type {\n ConsumerDefinition,\n DirectExchangeDefinition,\n ExchangeBindingDefinition,\n ExchangeDefinition,\n FanoutExchangeDefinition,\n HeadersExchangeDefinition,\n MessageDefinition,\n QueueBindingDefinition,\n QueueEntry,\n TopicExchangeDefinition,\n} from \"../types.js\";\nimport { defineExchangeBinding, defineQueueBindingInternal } from \"./binding.js\";\nimport { defineConsumer } from \"./consumer.js\";\nimport type { BindingPattern, RoutingKey } from \"./routing-types.js\";\n\n/**\n * Configuration for an event publisher.\n *\n * Events are published without knowing who consumes them. Multiple consumers\n * can subscribe to the same event. This follows the pub/sub pattern where\n * publishers broadcast events and consumers subscribe to receive them.\n *\n * @template TMessage - The message definition\n * @template TExchange - The exchange definition\n * @template TRoutingKey - The routing key type (undefined for fanout and headers exchanges)\n */\nexport type EventPublisherConfig<\n TMessage extends MessageDefinition,\n TExchange extends ExchangeDefinition,\n TRoutingKey extends string | undefined = undefined,\n> = {\n /** Discriminator to identify this as an event publisher config */\n __brand: \"EventPublisherConfig\";\n /** The exchange to publish to */\n exchange: TExchange;\n /** The message definition */\n message: TMessage;\n /** The routing key for direct/topic exchanges */\n routingKey: TRoutingKey;\n /** Additional AMQP arguments */\n arguments?: Record<string, unknown>;\n};\n\n/**\n * Result from defineEventConsumer.\n *\n * Contains the consumer definition and binding needed to subscribe to an event.\n * Can be used directly in defineContract's consumers section - the binding\n * will be automatically extracted.\n *\n * @template TMessage - The message definition\n */\nexport type EventConsumerResult<\n TMessage extends MessageDefinition,\n TExchange extends ExchangeDefinition = ExchangeDefinition,\n TQueue extends QueueEntry = QueueEntry,\n TExchangeBinding extends ExchangeBindingDefinition | undefined =\n | ExchangeBindingDefinition\n | undefined,\n TBridgeExchange extends ExchangeDefinition | undefined = ExchangeDefinition | undefined,\n> = {\n /** Discriminator to identify this as an event consumer result */\n __brand: \"EventConsumerResult\";\n /** The consumer definition for processing messages */\n consumer: ConsumerDefinition<TMessage>;\n /** The binding connecting the queue to the exchange */\n binding: QueueBindingDefinition;\n /** The source exchange this consumer subscribes to */\n exchange: TExchange;\n /** The queue this consumer reads from */\n queue: TQueue;\n /** The exchange-to-exchange binding when bridging, if configured */\n exchangeBinding: TExchangeBinding;\n /** The bridge (local domain) exchange when bridging, if configured */\n bridgeExchange: TBridgeExchange;\n};\n\n/**\n * Define an event publisher for broadcasting messages via fanout exchange.\n *\n * Events are published without knowing who consumes them. Multiple consumers\n * can subscribe to the same event using `defineEventConsumer`.\n *\n * @param exchange - The fanout exchange to publish to\n * @param message - The message definition (schema and metadata)\n * @param options - Optional binding configuration\n * @param options.arguments - Additional AMQP arguments\n * @returns An event publisher configuration\n *\n * @example\n * ```typescript\n * const logsExchange = defineExchange('logs', { type: 'fanout' });\n * const logMessage = defineMessage(z.object({\n * level: z.enum(['info', 'warn', 'error']),\n * message: z.string(),\n * }));\n *\n * // Create event publisher\n * const logEvent = defineEventPublisher(logsExchange, logMessage);\n *\n * // Multiple consumers can subscribe\n * const { consumer: fileConsumer, binding: fileBinding } =\n * defineEventConsumer(logEvent, fileLogsQueue);\n * const { consumer: alertConsumer, binding: alertBinding } =\n * defineEventConsumer(logEvent, alertsQueue);\n * ```\n */\nexport function defineEventPublisher<\n TMessage extends MessageDefinition,\n TExchange extends FanoutExchangeDefinition,\n>(\n exchange: TExchange,\n message: TMessage,\n options?: {\n arguments?: Record<string, unknown>;\n },\n): EventPublisherConfig<TMessage, TExchange, undefined>;\n\n/**\n * Define an event publisher for broadcasting messages via headers exchange.\n *\n * Events are published without knowing who consumes them. Multiple consumers\n * can subscribe to the same event using `defineEventConsumer`.\n *\n * @param exchange - The headers exchange to publish to\n * @param message - The message definition (schema and metadata)\n * @param options - Optional binding configuration\n * @param options.arguments - Additional AMQP arguments\n * @returns An event publisher configuration\n *\n * @example\n * ```typescript\n * const logsExchange = defineExchange('logs', { type: 'headers' });\n * const logMessage = defineMessage(z.object({\n * level: z.enum(['info', 'warn', 'error']),\n * message: z.string(),\n * }));\n *\n * // Create event publisher\n * const logEvent = defineEventPublisher(logsExchange, logMessage);\n *\n * // Multiple consumers can subscribe\n * const { consumer: fileConsumer, binding: fileBinding } =\n * defineEventConsumer(logEvent, fileLogsQueue);\n * const { consumer: alertConsumer, binding: alertBinding } =\n * defineEventConsumer(logEvent, alertsQueue);\n * ```\n */\nexport function defineEventPublisher<\n TMessage extends MessageDefinition,\n TExchange extends HeadersExchangeDefinition,\n>(\n exchange: TExchange,\n message: TMessage,\n options?: {\n arguments?: Record<string, unknown>;\n },\n): EventPublisherConfig<TMessage, TExchange, undefined>;\n\n/**\n * Define an event publisher for broadcasting messages via direct exchange.\n *\n * Events are published with a specific routing key. Consumers will receive\n * messages that match the routing key exactly.\n *\n * @param exchange - The direct exchange to publish to\n * @param message - The message definition (schema and metadata)\n * @param options - Configuration with required routing key\n * @param options.routingKey - The routing key for message routing\n * @param options.arguments - Additional AMQP arguments\n * @returns An event publisher configuration\n *\n * @example\n * ```typescript\n * const tasksExchange = defineExchange('tasks', { type: 'direct' });\n * const taskMessage = defineMessage(z.object({ taskId: z.string() }));\n *\n * const taskEvent = defineEventPublisher(tasksExchange, taskMessage, {\n * routingKey: 'task.execute',\n * });\n * ```\n */\nexport function defineEventPublisher<\n TMessage extends MessageDefinition,\n TRoutingKey extends string,\n TExchange extends DirectExchangeDefinition,\n>(\n exchange: TExchange,\n message: TMessage,\n options: {\n routingKey: RoutingKey<TRoutingKey>;\n arguments?: Record<string, unknown>;\n },\n): EventPublisherConfig<TMessage, TExchange, TRoutingKey>;\n\n/**\n * Define an event publisher for broadcasting messages via topic exchange.\n *\n * Events are published with a concrete routing key. Consumers can subscribe\n * using patterns (with * and # wildcards) to receive matching messages.\n *\n * @param exchange - The topic exchange to publish to\n * @param message - The message definition (schema and metadata)\n * @param options - Configuration with required routing key\n * @param options.routingKey - The concrete routing key (no wildcards)\n * @param options.arguments - Additional AMQP arguments\n * @returns An event publisher configuration\n *\n * @example\n * ```typescript\n * const ordersExchange = defineExchange('orders', { type: 'topic' });\n * const orderMessage = defineMessage(z.object({\n * orderId: z.string(),\n * amount: z.number(),\n * }));\n *\n * // Publisher uses concrete routing key\n * const orderCreatedEvent = defineEventPublisher(ordersExchange, orderMessage, {\n * routingKey: 'order.created',\n * });\n *\n * // Consumer can use pattern\n * const { consumer, binding } = defineEventConsumer(\n * orderCreatedEvent,\n * allOrdersQueue,\n * { routingKey: 'order.*' },\n * );\n * ```\n */\nexport function defineEventPublisher<\n TMessage extends MessageDefinition,\n TRoutingKey extends string,\n TExchange extends TopicExchangeDefinition,\n>(\n exchange: TExchange,\n message: TMessage,\n options: {\n routingKey: RoutingKey<TRoutingKey>;\n arguments?: Record<string, unknown>;\n },\n): EventPublisherConfig<TMessage, TExchange, TRoutingKey>;\n\n/**\n * Implementation of defineEventPublisher.\n * @internal\n */\nexport function defineEventPublisher<TMessage extends MessageDefinition>(\n exchange: ExchangeDefinition,\n message: TMessage,\n options?: {\n routingKey?: string;\n arguments?: Record<string, unknown>;\n },\n): EventPublisherConfig<TMessage, ExchangeDefinition, string | undefined> {\n const config: EventPublisherConfig<TMessage, ExchangeDefinition, string | undefined> = {\n __brand: \"EventPublisherConfig\",\n exchange,\n message,\n routingKey: options?.routingKey,\n };\n\n if (options?.arguments !== undefined) {\n config.arguments = options.arguments;\n }\n\n return config;\n}\n\n/**\n * Create a consumer that subscribes to an event from a fanout exchange via a bridge exchange.\n *\n * When `bridgeExchange` is provided, the queue binds to the bridge exchange instead of the\n * source exchange, and an exchange-to-exchange binding is created from the source to the bridge.\n *\n * @param eventPublisher - The event publisher configuration\n * @param queue - The queue that will receive messages\n * @param options - Binding configuration with required bridgeExchange\n * @param options.bridgeExchange - The fanout bridge exchange (must be fanout to match source)\n * @param options.arguments - Additional AMQP arguments\n * @returns An object with the consumer definition, queue binding, and exchange binding\n */\nexport function defineEventConsumer<\n TMessage extends MessageDefinition,\n TExchange extends FanoutExchangeDefinition,\n TQueueEntry extends QueueEntry,\n TBridgeExchange extends FanoutExchangeDefinition,\n>(\n eventPublisher: EventPublisherConfig<TMessage, TExchange, undefined>,\n queue: TQueueEntry,\n options: {\n bridgeExchange: TBridgeExchange;\n arguments?: Record<string, unknown>;\n },\n): EventConsumerResult<\n TMessage,\n TExchange,\n TQueueEntry,\n ExchangeBindingDefinition,\n TBridgeExchange\n>;\n\n/**\n * Create a consumer that subscribes to an event from a headers exchange via a bridge exchange.\n *\n * When `bridgeExchange` is provided, the queue binds to the bridge exchange instead of the\n * source exchange, and an exchange-to-exchange binding is created from the source to the bridge.\n *\n * @param eventPublisher - The event publisher configuration\n * @param queue - The queue that will receive messages\n * @param options - Binding configuration with required bridgeExchange\n * @param options.bridgeExchange - The headers bridge exchange (must be headers to match source)\n * @param options.arguments - Additional AMQP arguments\n * @returns An object with the consumer definition, queue binding, and exchange binding\n */\nexport function defineEventConsumer<\n TMessage extends MessageDefinition,\n TExchange extends HeadersExchangeDefinition,\n TQueueEntry extends QueueEntry,\n TBridgeExchange extends HeadersExchangeDefinition,\n>(\n eventPublisher: EventPublisherConfig<TMessage, TExchange, undefined>,\n queue: TQueueEntry,\n options: {\n bridgeExchange: TBridgeExchange;\n arguments?: Record<string, unknown>;\n },\n): EventConsumerResult<\n TMessage,\n TExchange,\n TQueueEntry,\n ExchangeBindingDefinition,\n TBridgeExchange\n>;\n\n/**\n * Create a consumer that subscribes to an event from a direct exchange via a bridge exchange.\n *\n * @param eventPublisher - The event publisher configuration\n * @param queue - The queue that will receive messages\n * @param options - Binding configuration with required bridgeExchange\n * @param options.bridgeExchange - The bridge exchange (must be direct or topic to preserve routing keys)\n * @param options.arguments - Additional AMQP arguments\n * @returns An object with the consumer definition, queue binding, and exchange binding\n */\nexport function defineEventConsumer<\n TMessage extends MessageDefinition,\n TRoutingKey extends string,\n TExchange extends DirectExchangeDefinition,\n TQueueEntry extends QueueEntry,\n TBridgeExchange extends DirectExchangeDefinition | TopicExchangeDefinition,\n>(\n eventPublisher: EventPublisherConfig<TMessage, TExchange, TRoutingKey>,\n queue: TQueueEntry,\n options: {\n bridgeExchange: TBridgeExchange;\n arguments?: Record<string, unknown>;\n },\n): EventConsumerResult<\n TMessage,\n TExchange,\n TQueueEntry,\n ExchangeBindingDefinition,\n TBridgeExchange\n>;\n\n/**\n * Create a consumer that subscribes to an event from a topic exchange via a bridge exchange.\n *\n * @param eventPublisher - The event publisher configuration\n * @param queue - The queue that will receive messages\n * @param options - Binding configuration with required bridgeExchange\n * @param options.bridgeExchange - The bridge exchange (must be direct or topic to preserve routing keys)\n * @param options.routingKey - Override routing key with pattern (defaults to publisher's key)\n * @param options.arguments - Additional AMQP arguments\n * @returns An object with the consumer definition, queue binding, and exchange binding\n */\nexport function defineEventConsumer<\n TMessage extends MessageDefinition,\n TRoutingKey extends string,\n TExchange extends TopicExchangeDefinition,\n TQueueEntry extends QueueEntry,\n TBridgeExchange extends DirectExchangeDefinition | TopicExchangeDefinition,\n TConsumerRoutingKey extends string = TRoutingKey,\n>(\n eventPublisher: EventPublisherConfig<TMessage, TExchange, TRoutingKey>,\n queue: TQueueEntry,\n options: {\n bridgeExchange: TBridgeExchange;\n routingKey?: BindingPattern<TConsumerRoutingKey>;\n arguments?: Record<string, unknown>;\n },\n): EventConsumerResult<\n TMessage,\n TExchange,\n TQueueEntry,\n ExchangeBindingDefinition,\n TBridgeExchange\n>;\n\n/**\n * Create a consumer that subscribes to an event from a fanout exchange.\n *\n * @param eventPublisher - The event publisher configuration\n * @param queue - The queue that will receive messages\n * @param options - Optional binding configuration\n * @param options.arguments - Additional AMQP arguments\n * @returns An object with the consumer definition and binding\n *\n * @example\n * ```typescript\n * const logEvent = defineEventPublisher(logsExchange, logMessage);\n * const { consumer, binding } = defineEventConsumer(logEvent, logsQueue);\n * ```\n */\nexport function defineEventConsumer<\n TMessage extends MessageDefinition,\n TExchange extends FanoutExchangeDefinition,\n TQueueEntry extends QueueEntry,\n>(\n eventPublisher: EventPublisherConfig<TMessage, TExchange, undefined>,\n queue: TQueueEntry,\n options?: {\n arguments?: Record<string, unknown>;\n },\n): EventConsumerResult<TMessage, TExchange, TQueueEntry>;\n\n/**\n * Create a consumer that subscribes to an event from a headers exchange.\n *\n * @param eventPublisher - The event publisher configuration\n * @param queue - The queue that will receive messages\n * @param options - Optional binding configuration\n * @param options.arguments - Additional AMQP arguments\n * @returns An object with the consumer definition and binding\n *\n * @example\n * ```typescript\n * const logEvent = defineEventPublisher(logsExchange, logMessage);\n * const { consumer, binding } = defineEventConsumer(logEvent, logsQueue);\n * ```\n */\nexport function defineEventConsumer<\n TMessage extends MessageDefinition,\n TExchange extends HeadersExchangeDefinition,\n TQueueEntry extends QueueEntry,\n>(\n eventPublisher: EventPublisherConfig<TMessage, TExchange, undefined>,\n queue: TQueueEntry,\n options?: {\n arguments?: Record<string, unknown>;\n },\n): EventConsumerResult<TMessage, TExchange, TQueueEntry>;\n\n/**\n * Create a consumer that subscribes to an event from a direct exchange.\n *\n * @param eventPublisher - The event publisher configuration\n * @param queue - The queue that will receive messages\n * @param options - Optional binding configuration\n * @param options.arguments - Additional AMQP arguments\n * @returns An object with the consumer definition and binding\n */\nexport function defineEventConsumer<\n TMessage extends MessageDefinition,\n TRoutingKey extends string,\n TExchange extends DirectExchangeDefinition,\n TQueueEntry extends QueueEntry,\n>(\n eventPublisher: EventPublisherConfig<TMessage, TExchange, TRoutingKey>,\n queue: TQueueEntry,\n options?: {\n arguments?: Record<string, unknown>;\n },\n): EventConsumerResult<TMessage, TExchange, TQueueEntry>;\n\n/**\n * Create a consumer that subscribes to an event from a topic exchange.\n *\n * For topic exchanges, the consumer can optionally override the routing key\n * with a pattern to subscribe to multiple events.\n *\n * @param eventPublisher - The event publisher configuration\n * @param queue - The queue that will receive messages\n * @param options - Optional binding configuration\n * @param options.routingKey - Override routing key with pattern (defaults to publisher's key)\n * @param options.arguments - Additional AMQP arguments\n * @returns An object with the consumer definition and binding\n *\n * @example\n * ```typescript\n * const orderCreatedEvent = defineEventPublisher(ordersExchange, orderMessage, {\n * routingKey: 'order.created',\n * });\n *\n * // Use exact routing key from publisher\n * const { consumer: exactConsumer } = defineEventConsumer(orderCreatedEvent, exactQueue);\n *\n * // Override with pattern to receive all order events\n * const { consumer: allConsumer } = defineEventConsumer(orderCreatedEvent, allQueue, {\n * routingKey: 'order.*',\n * });\n * ```\n */\nexport function defineEventConsumer<\n TMessage extends MessageDefinition,\n TRoutingKey extends string,\n TExchange extends TopicExchangeDefinition,\n TQueueEntry extends QueueEntry,\n TConsumerRoutingKey extends string = TRoutingKey,\n>(\n eventPublisher: EventPublisherConfig<TMessage, TExchange, TRoutingKey>,\n queue: TQueueEntry,\n options?: {\n routingKey?: BindingPattern<TConsumerRoutingKey>;\n arguments?: Record<string, unknown>;\n },\n): EventConsumerResult<TMessage, TExchange, TQueueEntry>;\n\n/**\n * Implementation of defineEventConsumer.\n * @internal\n */\nexport function defineEventConsumer<TMessage extends MessageDefinition>(\n eventPublisher: EventPublisherConfig<TMessage, ExchangeDefinition, string | undefined>,\n queue: QueueEntry,\n options?: {\n routingKey?: string;\n bridgeExchange?: ExchangeDefinition;\n arguments?: Record<string, unknown>;\n },\n): EventConsumerResult<TMessage> {\n const { exchange: sourceExchange, message, routingKey: publisherRoutingKey } = eventPublisher;\n\n // For topic exchanges, consumer can override the routing key\n const bindingRoutingKey = options?.routingKey ?? publisherRoutingKey;\n\n const bindingOptions: { routingKey?: string; arguments?: Record<string, unknown> } = {};\n if (bindingRoutingKey !== undefined) {\n bindingOptions.routingKey = bindingRoutingKey;\n }\n const bindingArguments = options?.arguments ?? eventPublisher.arguments;\n if (bindingArguments !== undefined) {\n bindingOptions.arguments = bindingArguments;\n }\n\n const bridgeExchange = options?.bridgeExchange;\n\n if (bridgeExchange) {\n // Bridged: queue binds to bridge exchange, e2e binding from source → bridge\n const binding = defineQueueBindingInternal(queue, bridgeExchange, bindingOptions);\n const consumer = defineConsumer(queue, message);\n\n // Create e2e binding: bridge ← source (destination ← source)\n const exchangeBindingOptions: { routingKey?: string } = {};\n if (bindingRoutingKey !== undefined) {\n exchangeBindingOptions.routingKey = bindingRoutingKey;\n }\n const e2eBinding =\n sourceExchange.type === \"fanout\" || sourceExchange.type === \"headers\"\n ? defineExchangeBinding(bridgeExchange, sourceExchange)\n : defineExchangeBinding(\n bridgeExchange,\n sourceExchange as DirectExchangeDefinition | TopicExchangeDefinition,\n exchangeBindingOptions as { routingKey: string },\n );\n\n return {\n __brand: \"EventConsumerResult\",\n consumer,\n binding,\n exchange: sourceExchange,\n queue,\n exchangeBinding: e2eBinding,\n bridgeExchange,\n } as EventConsumerResult<TMessage>;\n }\n\n const binding = defineQueueBindingInternal(queue, sourceExchange, bindingOptions);\n const consumer = defineConsumer(queue, message);\n\n return {\n __brand: \"EventConsumerResult\",\n consumer,\n binding,\n exchange: sourceExchange,\n queue,\n exchangeBinding: undefined,\n bridgeExchange: undefined,\n };\n}\n\n/**\n * Type guard to check if a value is an EventPublisherConfig.\n *\n * @param value - The value to check\n * @returns True if the value is an EventPublisherConfig\n */\nexport function isEventPublisherConfig(\n value: unknown,\n): value is EventPublisherConfig<MessageDefinition, ExchangeDefinition, string | undefined> {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"__brand\" in value &&\n value.__brand === \"EventPublisherConfig\"\n );\n}\n\n/**\n * Type guard to check if a value is an EventConsumerResult.\n *\n * @param value - The value to check\n * @returns True if the value is an EventConsumerResult\n */\nexport function isEventConsumerResult(\n value: unknown,\n): value is EventConsumerResult<MessageDefinition> {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"__brand\" in value &&\n value.__brand === \"EventConsumerResult\"\n );\n}\n","import type {\n BindingDefinition,\n ConsumerDefinition,\n ContractDefinition,\n ContractDefinitionInput,\n ContractOutput,\n ExchangeDefinition,\n PublisherDefinition,\n QueueEntry,\n RpcDefinition,\n} from \"../types.js\";\nimport { isBridgedPublisherConfig, isCommandConsumerConfig } from \"./command.js\";\nimport { isEventConsumerResult, isEventPublisherConfig } from \"./event.js\";\nimport { definePublisherInternal } from \"./publisher.js\";\nimport { extractQueue } from \"./queue-utils.js\";\nimport { isQueueWithTtlBackoffInfrastructure } from \"./ttl-backoff.js\";\n\n/**\n * Define an AMQP contract.\n *\n * A contract is the central definition of your AMQP messaging topology. It brings together\n * publishers and consumers in a single, type-safe definition. Exchanges, queues, and bindings\n * are automatically extracted from publishers and consumers.\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 publishers and consumers\n * @param definition.publishers - Named publisher definitions for sending messages\n * @param definition.consumers - Named consumer definitions for receiving messages\n * @returns The contract definition with fully inferred exchanges, queues, bindings, publishers, and consumers\n *\n * @example\n * ```typescript\n * import {\n * defineContract,\n * defineExchange,\n * defineQueue,\n * defineEventPublisher,\n * defineEventConsumer,\n * defineMessage,\n * } from '@amqp-contract/contract';\n * import { z } from 'zod';\n *\n * // Define resources\n * const ordersExchange = defineExchange('orders');\n * const dlx = defineExchange('orders-dlx', { type: 'direct' });\n * const orderQueue = defineQueue('order-processing', {\n * deadLetter: { exchange: dlx },\n * retry: { mode: 'immediate-requeue', maxRetries: 3 },\n * });\n * const orderMessage = defineMessage(\n * z.object({\n * orderId: z.string(),\n * amount: z.number(),\n * })\n * );\n *\n * // Define event publisher\n * const orderCreatedEvent = defineEventPublisher(ordersExchange, orderMessage, {\n * routingKey: 'order.created',\n * });\n *\n * // Compose contract - exchanges, queues, bindings are auto-extracted\n * export const contract = defineContract({\n * publishers: {\n * orderCreated: orderCreatedEvent,\n * },\n * consumers: {\n * processOrder: defineEventConsumer(orderCreatedEvent, orderQueue),\n * },\n * });\n *\n * // TypeScript now knows:\n * // - contract.exchanges.orders, contract.exchanges['orders-dlx']\n * // - contract.queues['order-processing']\n * // - contract.bindings.processOrderBinding\n * // - client.publish('orderCreated', { orderId: string, amount: number })\n * // - handler: (message: { orderId: string, amount: number }) => Future<Result<void, HandlerError>>\n * ```\n */\nexport function defineContract<TContract extends ContractDefinitionInput>(\n definition: TContract,\n): ContractOutput<TContract> {\n const { publishers: inputPublishers, consumers: inputConsumers, rpcs: inputRpcs } = definition;\n\n // Consumer names and RPC names share the worker handler keyspace; if the\n // same key appeared in both, the worker would consume from two queues under\n // one name and dispatch ambiguously. Fail fast at contract-definition time\n // rather than producing surprising runtime behavior.\n if (inputConsumers && inputRpcs) {\n const collisions = Object.keys(inputConsumers).filter((name) => Object.hasOwn(inputRpcs, name));\n if (collisions.length > 0) {\n throw new Error(\n `defineContract: name collision between consumers and rpcs — keys must be disjoint. Conflicting names: ${collisions.join(\", \")}`,\n );\n }\n }\n\n const result: ContractDefinition = {\n exchanges: {},\n queues: {},\n bindings: {},\n publishers: {},\n consumers: {},\n rpcs: {},\n };\n\n // Process publishers section - extract exchanges and convert EventPublisherConfig entries\n if (inputPublishers && Object.keys(inputPublishers).length > 0) {\n const processedPublishers: Record<string, PublisherDefinition> = {};\n const exchanges: Record<string, ExchangeDefinition> = {};\n const publisherBindings: Record<string, BindingDefinition> = {};\n\n for (const [name, entry] of Object.entries(inputPublishers)) {\n if (isBridgedPublisherConfig(entry)) {\n // BridgedPublisherConfig: extract publisher, exchanges, and e2e binding\n exchanges[entry.bridgeExchange.name] = entry.bridgeExchange;\n exchanges[entry.targetExchange.name] = entry.targetExchange;\n publisherBindings[`${name}ExchangeBinding`] = entry.exchangeBinding;\n processedPublishers[name] = entry.publisher;\n } else if (isEventPublisherConfig(entry)) {\n // EventPublisherConfig: extract exchange and convert to publisher definition\n exchanges[entry.exchange.name] = entry.exchange;\n const publisherOptions: { routingKey?: string } = {};\n if (entry.routingKey !== undefined) {\n publisherOptions.routingKey = entry.routingKey;\n }\n processedPublishers[name] = definePublisherInternal(\n entry.exchange,\n entry.message,\n publisherOptions,\n );\n } else {\n // Plain PublisherDefinition: extract exchange\n const publisher = entry as PublisherDefinition;\n exchanges[publisher.exchange.name] = publisher.exchange;\n processedPublishers[name] = publisher;\n }\n }\n\n result.publishers = processedPublishers;\n result.exchanges = { ...result.exchanges, ...exchanges };\n result.bindings = { ...result.bindings, ...publisherBindings };\n }\n\n // Process consumers section - extract queues, exchanges, bindings, and consumer definitions\n if (inputConsumers && Object.keys(inputConsumers).length > 0) {\n const processedConsumers: Record<string, ConsumerDefinition> = {};\n const consumerBindings: Record<string, BindingDefinition> = {};\n const queues: Record<string, QueueEntry> = {};\n const exchanges: Record<string, ExchangeDefinition> = {};\n\n for (const [name, entry] of Object.entries(inputConsumers)) {\n if (isEventConsumerResult(entry)) {\n // EventConsumerResult: extract consumer, binding, queue, and exchange\n processedConsumers[name] = entry.consumer;\n consumerBindings[`${name}Binding`] = entry.binding;\n\n // Extract queue (handle TTL-backoff infrastructure)\n const queueEntry = entry.consumer.queue;\n // Extract the plain queue definition from QueueEntry\n const queueDef = extractQueue(queueEntry);\n queues[queueDef.name] = queueEntry;\n\n // Extract exchange from binding\n exchanges[entry.binding.exchange.name] = entry.binding.exchange;\n\n // Extract dead letter exchange if present\n if (queueDef.deadLetter?.exchange) {\n exchanges[queueDef.deadLetter.exchange.name] = queueDef.deadLetter.exchange;\n }\n\n // Extract bridge exchange and e2e binding if present\n if (entry.exchangeBinding) {\n consumerBindings[`${name}ExchangeBinding`] = entry.exchangeBinding;\n }\n if (entry.bridgeExchange) {\n exchanges[entry.bridgeExchange.name] = entry.bridgeExchange;\n }\n // Also extract the source exchange (stored in entry.exchange for bridged consumers)\n if (entry.exchange) {\n exchanges[entry.exchange.name] = entry.exchange;\n }\n } else if (isCommandConsumerConfig(entry)) {\n // CommandConsumerConfig: extract consumer, binding, queue, and exchange\n processedConsumers[name] = entry.consumer;\n consumerBindings[`${name}Binding`] = entry.binding;\n\n // Extract queue (handle TTL-backoff infrastructure)\n const queueEntry = entry.consumer.queue;\n // Extract the plain queue definition from QueueEntry\n const queueDef = extractQueue(queueEntry);\n queues[queueDef.name] = queueEntry;\n\n // Extract exchange\n exchanges[entry.exchange.name] = entry.exchange;\n\n // Extract dead letter exchange if present\n if (queueDef.deadLetter?.exchange) {\n exchanges[queueDef.deadLetter.exchange.name] = queueDef.deadLetter.exchange;\n }\n } else {\n // Plain ConsumerDefinition: extract queue\n const consumer = entry as ConsumerDefinition;\n processedConsumers[name] = consumer;\n\n // Extract queue (handle TTL-backoff infrastructure)\n const queueEntry = consumer.queue;\n // Extract the plain queue definition from QueueEntry\n const queueDef = extractQueue(queueEntry);\n queues[queueDef.name] = queueEntry;\n\n // Extract dead letter exchange if present\n if (queueDef.deadLetter?.exchange) {\n exchanges[queueDef.deadLetter.exchange.name] = queueDef.deadLetter.exchange;\n }\n }\n }\n\n // Auto-generate TTL-backoff retry infrastructure for queues with TTL-backoff retry mode\n for (const queueEntry of Object.values(queues) as QueueEntry[]) {\n if (isQueueWithTtlBackoffInfrastructure(queueEntry)) {\n queues[queueEntry.waitQueue.name] = queueEntry.waitQueue;\n consumerBindings[`${queueEntry.queue.name}WaitBinding`] = queueEntry.waitQueueBinding;\n consumerBindings[`${queueEntry.queue.name}RetryBinding`] = queueEntry.retryQueueBinding;\n exchanges[queueEntry.waitExchange.name] = queueEntry.waitExchange;\n exchanges[queueEntry.retryExchange.name] = queueEntry.retryExchange;\n }\n }\n\n result.consumers = processedConsumers;\n result.bindings = { ...result.bindings, ...consumerBindings };\n result.queues = { ...result.queues, ...queues };\n result.exchanges = { ...result.exchanges, ...exchanges };\n }\n\n // Process rpcs section — extract each RPC's queue (and DLX if any) into the\n // contract topology. RPCs use the AMQP default exchange with the queue name\n // as routing key, so no exchange or binding declarations are needed.\n if (inputRpcs && Object.keys(inputRpcs).length > 0) {\n const processedRpcs: Record<string, RpcDefinition> = {};\n const rpcQueues: Record<string, QueueEntry> = {};\n const rpcExchanges: Record<string, ExchangeDefinition> = {};\n\n for (const [name, rpc] of Object.entries(inputRpcs)) {\n processedRpcs[name] = rpc;\n const queueDef = extractQueue(rpc.queue);\n rpcQueues[queueDef.name] = rpc.queue;\n if (queueDef.deadLetter?.exchange) {\n rpcExchanges[queueDef.deadLetter.exchange.name] = queueDef.deadLetter.exchange;\n }\n }\n\n result.rpcs = processedRpcs;\n result.queues = { ...result.queues, ...rpcQueues };\n result.exchanges = { ...result.exchanges, ...rpcExchanges };\n }\n\n return result as ContractOutput<TContract>;\n}\n","import type { MessageDefinition, QueueEntry, RpcDefinition } from \"../types.js\";\n\n/**\n * Define an RPC operation: a request/response pair flowing over a request\n * queue with replies routed back via RabbitMQ direct reply-to.\n *\n * RPC is bidirectional on both ends — the worker handler consumes the request\n * and produces the response; `client.call(name, request, options)` publishes\n * the request and awaits the typed response. Both sides share the same\n * definition, so request and response schemas cannot drift between them.\n *\n * Plug the result into `defineContract({ rpcs: { name: ... } })`. RPCs do not\n * appear in `publishers` or `consumers`.\n *\n * @param queue - The queue that receives RPC requests. The queue name is\n * used as the routing key on the AMQP default direct exchange.\n * @param messages.request - Schema validated against incoming request payloads\n * (server side) and outgoing requests (client side).\n * @param messages.response - Schema validated against handler return values\n * (server side) and incoming replies (client side).\n *\n * @example\n * ```typescript\n * import { defineQueue, defineMessage, defineRpc, defineContract } from '@amqp-contract/contract';\n * import { z } from 'zod';\n *\n * const calculate = defineRpc(defineQueue('rpc.calculate'), {\n * request: defineMessage(z.object({ a: z.number(), b: z.number() })),\n * response: defineMessage(z.object({ sum: z.number() })),\n * });\n *\n * const contract = defineContract({ rpcs: { calculate } });\n *\n * // Server (worker): handler returns the typed response\n * // handlers: { calculate: ({ payload }) => Future.value(Result.Ok({ sum: payload.a + payload.b })) }\n *\n * // Client: typed call with required timeout\n * // const result = await client.call('calculate', { a: 1, b: 2 }, { timeoutMs: 5_000 }).toPromise();\n * ```\n */\nexport function defineRpc<\n TRequestMessage extends MessageDefinition,\n TResponseMessage extends MessageDefinition,\n TQueue extends QueueEntry,\n>(\n queue: TQueue,\n messages: { request: TRequestMessage; response: TResponseMessage },\n): RpcDefinition<TRequestMessage, TResponseMessage, TQueue> {\n return {\n queue,\n request: messages.request,\n response: messages.response,\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/builder/exchange.ts","../src/builder/message.ts","../src/builder/queue-utils.ts","../src/builder/binding.ts","../src/builder/ttl-backoff.ts","../src/builder/queue.ts","../src/builder/publisher.ts","../src/builder/consumer.ts","../src/builder/command.ts","../src/builder/event.ts","../src/builder/contract.ts","../src/builder/rpc.ts"],"sourcesContent":["import type {\n BaseExchangeDefinition,\n DirectExchangeDefinition,\n ExchangeDefinition,\n FanoutExchangeDefinition,\n HeadersExchangeDefinition,\n TopicExchangeDefinition,\n} from \"../types.js\";\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 options - Optional exchange configuration\n * @param options.type - Exchange type (must be \"topic\", or omitted for default topic exchange)\n * @param options.durable - If true, the exchange survives broker restarts (default: true)\n * @param options.autoDelete - If true, the exchange is deleted when no queues are bound\n * @param options.internal - If true, the exchange cannot be directly published to\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', { type: 'topic' });\n *\n * // Or omit type for default topic exchange\n * const ordersExchange = defineExchange('orders');\n * ```\n */\nexport function defineExchange<TName extends string>(\n name: TName,\n options?: { type?: \"topic\" } & Omit<BaseExchangeDefinition, \"name\" | \"type\">,\n): TopicExchangeDefinition<TName>;\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 options - Exchange configuration\n * @param options.type - Exchange type (must be \"direct\")\n * @param options.durable - If true, the exchange survives broker restarts (default: true)\n * @param options.autoDelete - If true, the exchange is deleted when no queues are bound\n * @param options.internal - If true, the exchange cannot be directly published to\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', { type: 'direct' });\n * ```\n */\nexport function defineExchange<TName extends string>(\n name: TName,\n options: { type: \"direct\" } & Omit<BaseExchangeDefinition, \"name\" | \"type\">,\n): DirectExchangeDefinition<TName>;\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 options - Exchange configuration\n * @param options.type - Exchange type (must be \"fanout\")\n * @param options.durable - If true, the exchange survives broker restarts (default: true)\n * @param options.autoDelete - If true, the exchange is deleted when no queues are bound\n * @param options.internal - If true, the exchange cannot be directly published to\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', { type: 'fanout' });\n * ```\n */\nexport function defineExchange<TName extends string>(\n name: TName,\n options: { type: \"fanout\" } & Omit<BaseExchangeDefinition, \"name\" | \"type\">,\n): FanoutExchangeDefinition<TName>;\n\n/**\n * Define a headers exchange.\n *\n * A headers exchange routes messages to all bound queues based on header matching.\n * This exchange type is ideal for complex routing scenarios.\n *\n * @param name - The name of the exchange\n * @param options - Exchange configuration\n * @param options.type - Exchange type (must be \"headers\")\n * @param options.durable - If true, the exchange survives broker restarts (default: true)\n * @param options.autoDelete - If true, the exchange is deleted when no queues are bound\n * @param options.internal - If true, the exchange cannot be directly published to\n * @param options.arguments - Additional AMQP arguments for the exchange\n * @returns A headers exchange definition\n *\n * @example\n * ```typescript\n * const routesExchange = defineExchange('routes', { type: 'headers' });\n * ```\n */\nexport function defineExchange<TName extends string>(\n name: TName,\n options: { type: \"headers\" } & Omit<BaseExchangeDefinition, \"name\" | \"type\">,\n): HeadersExchangeDefinition<TName>;\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 options - Optional exchange configuration\n * @param options.type - Exchange type (one of \"topic\", \"direct\", \"fanout\", \"headers\") (default: \"topic\")\n * @param options.durable - If true, the exchange survives broker restarts (default: true)\n * @param options.autoDelete - If true, the exchange is deleted when no queues are bound\n * @param options.internal - If true, the exchange cannot be directly published to\n * @param options.arguments - Additional AMQP arguments for the exchange\n * @returns An exchange definition\n * @internal\n */\nexport function defineExchange(\n name: string,\n options?: { type?: \"topic\" | \"direct\" | \"fanout\" | \"headers\" } & Omit<\n BaseExchangeDefinition,\n \"name\" | \"type\"\n >,\n): ExchangeDefinition {\n const type = options?.type ?? \"topic\";\n return {\n name,\n type,\n durable: true,\n ...options,\n };\n}\n","import type { MessageDefinition } from \"../types.js\";\nimport type { StandardSchemaV1 } from \"@standard-schema/spec\";\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","import type { ExtractQueueFromEntry, QueueDefinition, QueueEntry } from \"../types.js\";\nimport { isQueueWithTtlBackoffInfrastructure } from \"./ttl-backoff.js\";\n\n/**\n * Extract the plain QueueDefinition from a QueueEntry.\n * @internal\n */\nfunction extractQueueFromEntry(entry: QueueEntry): QueueDefinition {\n if (isQueueWithTtlBackoffInfrastructure(entry)) {\n return entry.queue;\n }\n return entry;\n}\n\n/**\n * Extract the plain QueueDefinition from a QueueEntry.\n *\n * **Why this function exists:**\n * When you configure a queue with TTL-backoff retry,\n * `defineQueue` returns a wrapper object that includes\n * the main queue, wait queue, headers exchanges, and bindings. This function extracts the underlying\n * queue definition so you can access properties like `name`, `type`, etc.\n *\n * **When to use:**\n * - When you need to access queue properties (name, type, etc.)\n * - When passing a queue to functions that expect a plain QueueDefinition\n * - Works safely on both plain queues and infrastructure wrappers\n *\n * **How it works:**\n * - If the entry is a `QueueWithTtlBackoffInfrastructure`, returns `entry.queue`\n * - Otherwise, returns the entry as-is (it's already a plain QueueDefinition)\n *\n * @param entry - The queue entry (either plain QueueDefinition or QueueWithTtlBackoffInfrastructure)\n * @returns The plain QueueDefinition\n *\n * @example\n * ```typescript\n * import { defineQueue, extractQueue } from '@amqp-contract/contract';\n *\n * // TTL-backoff queue returns a wrapper\n * const orderQueue = defineQueue('orders', {\n * retry: { mode: 'ttl-backoff', maxRetries: 3 },\n * });\n *\n * // Use extractQueue to access the queue name\n * const queueName = extractQueue(orderQueue).name; // 'orders'\n *\n * // Also works safely on plain queues\n * const plainQueue = defineQueue('simple', { type: 'quorum', retry: { mode: 'immediate-requeue' } });\n * const plainName = extractQueue(plainQueue).name; // 'simple'\n *\n * // Access other properties\n * const queueDef = extractQueue(orderQueue);\n * console.log(queueDef.name); // 'orders'\n * console.log(queueDef.type); // 'quorum'\n * ```\n *\n * @see isQueueWithTtlBackoffInfrastructure - Type guard to check if extraction is needed\n */\nexport function extractQueue<T extends QueueEntry>(entry: T): ExtractQueueFromEntry<T> {\n return extractQueueFromEntry(entry) as ExtractQueueFromEntry<T>;\n}\n","import type {\n DirectExchangeDefinition,\n ExchangeBindingDefinition,\n ExchangeDefinition,\n FanoutExchangeDefinition,\n HeadersExchangeDefinition,\n QueueBindingDefinition,\n QueueEntry,\n TopicExchangeDefinition,\n} from \"../types.js\";\nimport { extractQueue } from \"./queue-utils.js\";\n\n/**\n * Define a binding between a queue and a fanout or headers exchange.\n *\n * Binds a queue to a fanout or headers exchange (no routing key needed).\n * Fanout and headers exchanges ignore routing keys, so this overload doesn't require one.\n *\n * @param queue - The queue definition or queue with infrastructure to bind\n * @param exchange - The fanout or headers 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');\n * const logsExchange = defineExchange('logs', { type: 'fanout' });\n *\n * const binding = defineQueueBinding(logsQueue, logsExchange);\n * ```\n */\nexport function defineQueueBinding(\n queue: QueueEntry,\n exchange: FanoutExchangeDefinition | HeadersExchangeDefinition,\n options?: Omit<\n Extract<\n QueueBindingDefinition,\n { exchange: FanoutExchangeDefinition | HeadersExchangeDefinition }\n >,\n \"type\" | \"queue\" | \"exchange\" | \"routingKey\"\n >,\n): Extract<\n QueueBindingDefinition,\n { exchange: FanoutExchangeDefinition | HeadersExchangeDefinition }\n>;\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 or queue with infrastructure 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');\n * const ordersExchange = defineExchange('orders');\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: QueueEntry,\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 or queue with infrastructure 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: QueueEntry,\n exchange: ExchangeDefinition,\n options?: {\n routingKey?: string;\n arguments?: Record<string, unknown>;\n },\n): QueueBindingDefinition {\n // Extract the plain queue definition from QueueEntry\n const queueDef = extractQueue(queue);\n\n if (exchange.type === \"fanout\" || exchange.type === \"headers\") {\n return {\n type: \"queue\",\n queue: queueDef,\n exchange,\n ...(options?.arguments && { arguments: options.arguments }),\n } as QueueBindingDefinition;\n }\n\n return {\n type: \"queue\",\n queue: queueDef,\n exchange,\n routingKey: options?.routingKey,\n ...(options?.arguments && { arguments: options.arguments }),\n } as QueueBindingDefinition;\n}\n\n/**\n * Internal helper to call defineQueueBinding with proper type handling.\n * Used by queue.ts to avoid circular dependency.\n * @internal\n */\nexport function defineQueueBindingInternal(\n queue: QueueEntry,\n exchange: ExchangeDefinition,\n options?: {\n routingKey?: string;\n arguments?: Record<string, unknown>;\n },\n): QueueBindingDefinition {\n if (exchange.type === \"fanout\" || exchange.type === \"headers\") {\n return defineQueueBinding(queue, exchange, options);\n }\n return defineQueueBinding(queue, exchange, options as { routingKey: string });\n}\n\n/**\n * Define a binding between two exchanges (exchange-to-exchange routing).\n *\n * Binds a destination exchange to a fanout or headers source exchange.\n * Messages published to the source exchange will be forwarded to the destination exchange.\n * Fanout and headers exchanges ignore routing keys, so this overload doesn't require one.\n *\n * @param destination - The destination exchange definition\n * @param source - The fanout or headers 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', { type: 'fanout' });\n * const destExchange = defineExchange('all-logs', { type: 'fanout' });\n *\n * const binding = defineExchangeBinding(destExchange, sourceExchange);\n * ```\n */\nexport function defineExchangeBinding(\n destination: ExchangeDefinition,\n source: FanoutExchangeDefinition | HeadersExchangeDefinition,\n options?: Omit<\n Extract<\n ExchangeBindingDefinition,\n { source: FanoutExchangeDefinition | HeadersExchangeDefinition }\n >,\n \"type\" | \"source\" | \"destination\" | \"routingKey\"\n >,\n): Extract<\n ExchangeBindingDefinition,\n { source: FanoutExchangeDefinition | HeadersExchangeDefinition }\n>;\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');\n * const importantExchange = defineExchange('important-orders');\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\" || source.type === \"headers\") {\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","import type {\n BaseQueueDefinition,\n QueueDefinition,\n QueueEntry,\n QueueWithTtlBackoffInfrastructure,\n TtlBackoffRetryInfrastructure,\n} from \"../types.js\";\nimport { defineQueueBindingInternal } from \"./binding.js\";\nimport { defineExchange } from \"./exchange.js\";\n\n/**\n * Type guard to check if a queue entry is a QueueWithTtlBackoffInfrastructure.\n *\n * When you configure a queue with TTL-backoff retry,\n * `defineQueue` returns a `QueueWithTtlBackoffInfrastructure` instead of a plain\n * `QueueDefinition`. This type guard helps you distinguish between the two.\n *\n * **When to use:**\n * - When you need to check the type of a queue entry at runtime\n * - When writing generic code that handles both plain queues and infrastructure wrappers\n *\n * **Related functions:**\n * - `extractQueue()` - Use this to get the underlying queue definition from either type\n *\n * @param entry - The queue entry to check\n * @returns True if the entry is a QueueWithTtlBackoffInfrastructure, false otherwise\n *\n * @example\n * ```typescript\n * const queue = defineQueue('orders', {\n * retry: { mode: 'ttl-backoff' },\n * });\n *\n * if (isQueueWithTtlBackoffInfrastructure(queue)) {\n * // queue has .queue, .waitQueue, .waitQueueBinding, .retryQueueBinding, .waitExchange, .retryExchange\n * console.log('Wait queue:', queue.waitQueue.name);\n * } else {\n * // queue is a plain QueueDefinition\n * console.log('Queue:', queue.name);\n * }\n * ```\n */\nexport function isQueueWithTtlBackoffInfrastructure(\n entry: QueueEntry,\n): entry is QueueWithTtlBackoffInfrastructure {\n return (\n typeof entry === \"object\" &&\n entry !== null &&\n \"__brand\" in entry &&\n entry.__brand === \"QueueWithTtlBackoffInfrastructure\"\n );\n}\n\n/**\n * Wrap a queue definition with TTL-backoff retry infrastructure.\n */\nexport function wrapWithTtlBackoffInfrastructure(\n queue: QueueDefinition,\n): QueueWithTtlBackoffInfrastructure {\n const infra = createTtlBackoffInfrastructure(queue);\n\n return {\n __brand: \"QueueWithTtlBackoffInfrastructure\",\n queue,\n ...infra,\n };\n}\n\n/**\n * Create TTL-backoff retry infrastructure for a queue.\n *\n * This builder helper generates the wait queue, exchanges, and bindings needed for TTL-backoff retry.\n * The generated infrastructure can be spread into a contract definition.\n *\n * TTL-backoff retry works by:\n * 1. Failed messages are sent to the wait exchange with header `x-wait-queue` set to the wait queue name\n * 2. The wait queue receives these messages and holds them for a TTL period\n * 3. After TTL expires, messages are dead-lettered back to the retry exchange with header `x-retry-queue` set to the main queue name\n * 4. The main queue receives the retried message via its binding to the retry exchange\n *\n * @param queue - The main queue definition\n * @param options - Optional configuration for the wait queue\n * @returns TTL-backoff retry infrastructure containing wait queue and bindings\n * @throws {Error} If the queue does not have retry mode set to `ttl-backoff`\n *\n * @example\n * ```typescript\n * const orderQueue = defineQueue('order-processing', {\n * type: 'quorum',\n * retry: {\n * mode: 'ttl-backoff',\n * maxRetries: 5,\n * initialDelayMs: 1000,\n * },\n * });\n *\n * // Infrastructure is auto-extracted when using defineContract:\n * const contract = defineContract({\n * publishers: { ... },\n * consumers: { processOrder: defineEventConsumer(event, orderQueue) },\n * });\n * // contract.queues includes the wait queue, contract.exchanges includes retry exchanges, contract.bindings includes retry bindings\n * ```\n */\nexport function createTtlBackoffInfrastructure(\n queue: QueueDefinition,\n): TtlBackoffRetryInfrastructure {\n // Ensure queue retry mode is ttl-backoff\n if (queue.retry.mode !== \"ttl-backoff\") {\n throw new Error(\n `Queue ${queue.name} does not have ttl-backoff retry mode. Infrastructure can only be created for queues with ttl-backoff retry.`,\n );\n }\n\n // Create wait exchange (headers exchange) for routing failed messages to the wait queue\n const waitExchange = defineExchange(queue.retry.waitExchangeName, {\n type: \"headers\",\n });\n\n // Create retry exchange (headers exchange) for routing messages to retry back to main queue\n const retryExchange = defineExchange(queue.retry.retryExchangeName, {\n type: \"headers\",\n });\n\n // Create the wait queue (of same type as main queue)\n const baseWaitQueue: BaseQueueDefinition = {\n name: queue.retry.waitQueueName,\n deadLetter: {\n exchange: retryExchange, // Routes back to retry exchange after TTL (will preserve original message routing key)\n },\n retry: { mode: \"none\" }, // No retry for wait queue itself\n };\n\n const waitQueue: QueueDefinition =\n queue.type === \"quorum\"\n ? {\n ...baseWaitQueue,\n type: queue.type,\n durable: true, // Quorum queues are always durable\n }\n : {\n ...baseWaitQueue,\n type: queue.type,\n durable: queue.durable,\n };\n\n // Create binding for wait queue to receive failed messages\n const waitQueueBinding = defineQueueBindingInternal(waitQueue, waitExchange, {\n arguments: {\n \"x-match\": \"all\",\n \"x-wait-queue\": waitQueue.name, // Custom header to specify the wait queue to which messages should be routed\n },\n });\n\n // Create binding for main queue to receive messages to retry\n const retryQueueBinding = defineQueueBindingInternal(queue, retryExchange, {\n arguments: {\n \"x-match\": \"all\",\n \"x-retry-queue\": queue.name, // Custom header to specify the retry queue to which messages should be routed\n },\n });\n\n return {\n waitQueue,\n waitExchange,\n retryExchange,\n waitQueueBinding,\n retryQueueBinding,\n };\n}\n","import type {\n BaseQueueDefinition,\n DeadLetterConfig,\n DefineQueueOptions,\n DefineQueueOptionsWithDeadLetterExchange,\n ExchangeDefinition,\n ImmediateRequeueRetryOptions,\n QueueDefinition,\n QueueEntry,\n QueueEntryWithDeadLetterExchange,\n ResolvedImmediateRequeueRetryOptions,\n ResolvedTtlBackoffRetryOptions,\n TtlBackoffRetryOptions,\n} from \"../types.js\";\nimport { wrapWithTtlBackoffInfrastructure } from \"./ttl-backoff.js\";\n\n/**\n * Resolve immediate-requeue retry options with defaults.\n * @internal\n */\nfunction resolveImmediateRequeueOptions(\n options: ImmediateRequeueRetryOptions | undefined,\n): ResolvedImmediateRequeueRetryOptions {\n return {\n mode: \"immediate-requeue\",\n maxRetries: options?.maxRetries ?? 3,\n };\n}\n\n/**\n * Resolve TTL-backoff retry options with defaults.\n * @internal\n */\nfunction resolveTtlBackoffOptions(\n queueName: string,\n options: TtlBackoffRetryOptions | undefined,\n): ResolvedTtlBackoffRetryOptions {\n return {\n mode: \"ttl-backoff\",\n maxRetries: options?.maxRetries ?? 3,\n initialDelayMs: options?.initialDelayMs ?? 1000,\n maxDelayMs: options?.maxDelayMs ?? 30000,\n backoffMultiplier: options?.backoffMultiplier ?? 2,\n jitter: options?.jitter ?? true,\n waitQueueName: options?.waitQueueName ?? `${queueName}-wait`,\n waitExchangeName: options?.waitExchangeName ?? \"wait-exchange\",\n retryExchangeName: options?.retryExchangeName ?? \"retry-exchange\",\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 * By default, queues are created as quorum queues which provide better durability and\n * high-availability. Use `type: 'classic'` for special cases like non-durable queues\n * or priority queues.\n *\n * @param name - The name of the queue\n * @param options - Optional queue configuration\n * @param options.type - Queue type: 'quorum' (default, recommended) or 'classic'\n * @param options.durable - If true, the queue survives broker restarts. Quorum queues only support durable queues (default: true)\n * @param options.exclusive - If true, the queue can only be used by the declaring connection and is deleted when that connection closes. Only supported with classic queues.\n * @param options.autoDelete - If true, the queue is deleted when the last consumer unsubscribes. Only supported with classic queues.\n * @param options.maxPriority - Maximum priority level for priority queue (1-255, recommended: 1-10). Only supported with classic queues.\n * @param options.deadLetter - Dead letter configuration for handling failed messages\n * @param options.retry - Retry configuration for handling failed message processing\n * @param options.arguments - Additional AMQP arguments (e.g., x-message-ttl)\n * @returns A queue definition\n *\n * @example\n * ```typescript\n * // Quorum queue (default, recommended for production)\n * const orderQueue = defineQueue('order-processing');\n *\n * // Explicit quorum queue with dead letter exchange\n * const dlx = defineExchange('orders-dlx');\n * const orderQueueWithDLX = defineQueue('order-processing', {\n * type: 'quorum',\n * deadLetter: {\n * exchange: dlx,\n * routingKey: 'order.failed'\n * },\n * arguments: {\n * 'x-message-ttl': 86400000, // 24 hours\n * }\n * });\n *\n * // Classic queue (for special cases)\n * const tempQueue = defineQueue('temp-queue', {\n * type: 'classic',\n * durable: false,\n * autoDelete: true,\n * });\n *\n * // Priority queue (requires classic type)\n * const taskQueue = defineQueue('urgent-tasks', {\n * type: 'classic',\n * maxPriority: 10,\n * });\n *\n * // Queue with TTL-backoff retry (returns infrastructure automatically)\n * const dlx = defineExchange('orders-dlx', { type: 'direct' });\n * const orderQueue = defineQueue('order-processing', {\n * deadLetter: { exchange: dlx },\n * retry: { mode: 'ttl-backoff', maxRetries: 5 },\n * });\n * // orderQueue is QueueWithTtlBackoffInfrastructure, pass directly to defineContract\n * ```\n */\nexport function defineQueue<TName extends string, TDlx extends ExchangeDefinition>(\n name: TName,\n options: DefineQueueOptionsWithDeadLetterExchange<TDlx>,\n): QueueEntryWithDeadLetterExchange<TName, TDlx>;\n\nexport function defineQueue<TName extends string>(\n name: TName,\n options?: DefineQueueOptions,\n): QueueEntry<TName>;\n\nexport function defineQueue(name: string, options?: DefineQueueOptions): QueueEntry {\n const opts = options ?? {};\n const type = opts.type ?? \"quorum\";\n const durable = opts.durable ?? true;\n\n // Build base properties shared by both queue types\n const baseProps: {\n name: string;\n deadLetter?: DeadLetterConfig;\n arguments?: Record<string, unknown>;\n } = {\n name,\n ...(opts.deadLetter !== undefined && { deadLetter: opts.deadLetter }),\n ...(opts.arguments !== undefined && { arguments: opts.arguments }),\n };\n\n // Build specific properties for classic queues\n const classicProps: {\n exclusive?: boolean;\n autoDelete?: boolean;\n maxPriority?: number;\n } = {\n ...(opts.exclusive !== undefined && { exclusive: opts.exclusive }),\n ...(opts.autoDelete !== undefined && { autoDelete: opts.autoDelete }),\n ...(opts.maxPriority !== undefined && { maxPriority: opts.maxPriority }),\n };\n\n if (type === \"quorum\") {\n // Quorum queues do not support non-durable, exclusive, autoDelete, or maxPriority\n if (opts.durable === false) {\n throw new Error(\"Non-durable queues are not supported with quorum type.\");\n }\n if (opts.exclusive !== undefined) {\n throw new Error(\"Exclusive queues are not supported with quorum type.\");\n }\n if (opts.autoDelete !== undefined) {\n throw new Error(\"Auto-deleting queues are not supported with quorum type.\");\n }\n if (opts.maxPriority !== undefined) {\n throw new Error(\"Priority queues are not supported with quorum type.\");\n }\n } else {\n // Validate maxPriority\n if (opts.maxPriority !== undefined) {\n if (opts.maxPriority < 1 || opts.maxPriority > 255) {\n throw new Error(\n `Invalid maxPriority: ${opts.maxPriority}. Must be between 1 and 255. Recommended range: 1-10.`,\n );\n }\n }\n }\n\n const inputRetry = opts.retry ?? { mode: \"none\" as const };\n\n // Validate retry requirements\n if (inputRetry.mode === \"immediate-requeue\" || inputRetry.mode === \"ttl-backoff\") {\n if (inputRetry.maxRetries !== undefined) {\n if (inputRetry.maxRetries < 1 || !Number.isInteger(inputRetry.maxRetries)) {\n throw new Error(\n `Queue \"${name}\" uses ${inputRetry.mode} retry mode with invalid maxRetries: ${inputRetry.maxRetries}. Must be a positive integer.`,\n );\n }\n }\n }\n\n // Resolve retry options with defaults\n const retry =\n inputRetry.mode === \"immediate-requeue\"\n ? resolveImmediateRequeueOptions(inputRetry)\n : inputRetry.mode === \"ttl-backoff\"\n ? resolveTtlBackoffOptions(name, inputRetry)\n : inputRetry;\n\n const baseQueueDefinition: BaseQueueDefinition = {\n ...baseProps,\n retry,\n };\n\n const queueDefinition: QueueDefinition =\n type === \"quorum\"\n ? {\n ...baseQueueDefinition,\n type,\n durable: true, // Quorum queues are always durable\n }\n : {\n ...baseQueueDefinition,\n ...classicProps,\n type,\n durable,\n };\n\n // If TTL-backoff retry, wrap with infrastructure\n if (retry.mode === \"ttl-backoff\") {\n return wrapWithTtlBackoffInfrastructure(queueDefinition);\n }\n\n return queueDefinition;\n}\n","import type {\n DirectExchangeDefinition,\n ExchangeDefinition,\n FanoutExchangeDefinition,\n HeadersExchangeDefinition,\n MessageDefinition,\n PublisherDefinition,\n TopicExchangeDefinition,\n} from \"../types.js\";\n\n/**\n * Define a message publisher for a fanout or headers 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. For headers exchanges,\n * routing is based on message headers rather than routing keys, so no routing key is required either.\n *\n * The message schema is validated when publishing to ensure type safety.\n *\n * **Which pattern to use:**\n *\n * | Pattern | Best for | Description |\n * |---------|----------|-------------|\n * | `definePublisher` + `defineConsumer` | Independent definition | Define publishers and consumers separately with manual schema consistency |\n * | `defineEventPublisher` + `defineEventConsumer` | Event broadcasting | Define event publisher first, create consumers that subscribe to it |\n * | `defineCommandConsumer` + `defineCommandPublisher` | Task queues | Define command consumer first, create publishers that send commands to it |\n *\n * Use `defineEventPublisher` when:\n * - One publisher feeds multiple consumers\n * - You want automatic schema consistency between publisher and consumers\n * - You're building event-driven architectures\n *\n * @param exchange - The fanout or headers 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', { type: 'fanout' });\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 *\n * @see defineEventPublisher - For event-driven patterns with automatic schema consistency\n * @see defineCommandConsumer - For task queue patterns with automatic schema consistency\n */\nexport function definePublisher<TMessage extends MessageDefinition>(\n exchange: FanoutExchangeDefinition | HeadersExchangeDefinition,\n message: TMessage,\n options?: Omit<\n Extract<\n PublisherDefinition<TMessage>,\n { exchange: FanoutExchangeDefinition | HeadersExchangeDefinition }\n >,\n \"exchange\" | \"message\" | \"routingKey\"\n >,\n): Extract<\n PublisherDefinition<TMessage>,\n { exchange: FanoutExchangeDefinition | HeadersExchangeDefinition }\n>;\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 * **Which pattern to use:**\n *\n * | Pattern | Best for | Description |\n * |---------|----------|-------------|\n * | `definePublisher` + `defineConsumer` | Independent definition | Define publishers and consumers separately with manual schema consistency |\n * | `defineEventPublisher` + `defineEventConsumer` | Event broadcasting | Define event publisher first, create consumers that subscribe to it |\n * | `defineCommandConsumer` + `defineCommandPublisher` | Task queues | Define command consumer first, create publishers that send commands to it |\n *\n * Use `defineEventPublisher` when:\n * - One publisher feeds multiple consumers\n * - You want automatic schema consistency between publisher and consumers\n * - You're building event-driven architectures\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');\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 *\n * @see defineEventPublisher - For event-driven patterns with automatic schema consistency\n * @see defineCommandConsumer - For task queue patterns with automatic schema consistency\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\" || exchange.type === \"headers\") {\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 * Helper to call definePublisher with proper type handling.\n * Type safety is enforced by overloaded public function signatures.\n * @internal\n */\nexport function definePublisherInternal<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\" || exchange.type === \"headers\") {\n return definePublisher(exchange, message, options);\n }\n return definePublisher(exchange, message, options as { routingKey: string });\n}\n","import type {\n CommandConsumerConfigBase,\n ConsumerDefinition,\n ConsumerEntry,\n EventConsumerResultBase,\n MessageDefinition,\n QueueEntry,\n} from \"../types.js\";\n\n/**\n * Type guard to check if an entry is an EventConsumerResult.\n */\nfunction isEventConsumerResultEntry(entry: ConsumerEntry): entry is EventConsumerResultBase {\n return \"__brand\" in entry && entry.__brand === \"EventConsumerResult\";\n}\n\n/**\n * Type guard to check if an entry is a CommandConsumerConfig.\n */\nfunction isCommandConsumerConfigEntry(entry: ConsumerEntry): entry is CommandConsumerConfigBase {\n return \"__brand\" in entry && entry.__brand === \"CommandConsumerConfig\";\n}\n\n/**\n * Extract the ConsumerDefinition from any ConsumerEntry type.\n *\n * Handles the following entry types:\n * - ConsumerDefinition: returned as-is\n * - EventConsumerResult: returns the nested `.consumer` property\n * - CommandConsumerConfig: returns the nested `.consumer` property\n *\n * Use this function when you need to access the underlying ConsumerDefinition\n * from a consumer entry that may have been created with defineEventConsumer\n * or defineCommandConsumer.\n *\n * @param entry - The consumer entry to extract from\n * @returns The underlying ConsumerDefinition\n *\n * @example\n * ```typescript\n * // Works with plain ConsumerDefinition\n * const consumer1 = defineConsumer(queue, message);\n * extractConsumer(consumer1).queue.name; // \"my-queue\"\n *\n * // Works with EventConsumerResult\n * const consumer2 = defineEventConsumer(eventPublisher, queue);\n * extractConsumer(consumer2).queue.name; // \"my-queue\"\n *\n * // Works with CommandConsumerConfig\n * const consumer3 = defineCommandConsumer(queue, exchange, message, { routingKey: \"cmd\" });\n * extractConsumer(consumer3).queue.name; // \"my-queue\"\n * ```\n */\nexport function extractConsumer(entry: ConsumerEntry): ConsumerDefinition {\n if (isEventConsumerResultEntry(entry) || isCommandConsumerConfigEntry(entry)) {\n return entry.consumer;\n }\n // Otherwise it's a plain ConsumerDefinition\n return entry;\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 * **Which pattern to use:**\n *\n * | Pattern | Best for | Description |\n * |---------|----------|-------------|\n * | `definePublisher` + `defineConsumer` | Independent definition | Define publishers and consumers separately with manual schema consistency |\n * | `defineEventPublisher` + `defineEventConsumer` | Event broadcasting | Define event publisher first, create consumers that subscribe to it |\n * | `defineCommandConsumer` + `defineCommandPublisher` | Task queues | Define command consumer first, create publishers that send commands to it |\n *\n * Use `defineCommandConsumer` when:\n * - One consumer receives from multiple publishers\n * - You want automatic schema consistency between consumer and publishers\n * - You're building task queue or command patterns\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');\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 *\n * @see defineCommandConsumer - For task queue patterns with automatic schema consistency\n * @see defineEventPublisher - For event-driven patterns with automatic schema consistency\n */\nexport function defineConsumer<TMessage extends MessageDefinition>(\n queue: QueueEntry,\n message: TMessage,\n options?: Omit<ConsumerDefinition<TMessage>, \"queue\" | \"message\">,\n): ConsumerDefinition<TMessage> {\n return {\n queue,\n message,\n ...options,\n };\n}\n","import type {\n ConsumerDefinition,\n DirectExchangeDefinition,\n ExchangeBindingDefinition,\n ExchangeDefinition,\n FanoutExchangeDefinition,\n HeadersExchangeDefinition,\n MessageDefinition,\n PublisherDefinition,\n QueueBindingDefinition,\n QueueEntry,\n TopicExchangeDefinition,\n} from \"../types.js\";\nimport { defineExchangeBinding, defineQueueBindingInternal } from \"./binding.js\";\nimport { defineConsumer } from \"./consumer.js\";\nimport { definePublisherInternal } from \"./publisher.js\";\nimport type { BindingPattern, RoutingKey } from \"./routing-types.js\";\n\n/**\n * Configuration for a command consumer.\n *\n * Commands are sent by one or more publishers to a single consumer (task queue pattern).\n * The consumer \"owns\" the queue, and publishers send commands to it.\n *\n * @template TMessage - The message definition\n * @template TExchange - The exchange definition\n * @template TRoutingKey - The routing key type (undefined for fanout and headers exchanges)\n */\nexport type CommandConsumerConfig<\n TMessage extends MessageDefinition,\n TExchange extends ExchangeDefinition,\n TRoutingKey extends string | undefined = undefined,\n TQueue extends QueueEntry = QueueEntry,\n> = {\n /** Discriminator to identify this as a command consumer config */\n __brand: \"CommandConsumerConfig\";\n /** The consumer definition for processing commands */\n consumer: ConsumerDefinition<TMessage>;\n /** The binding connecting the queue to the exchange */\n binding: QueueBindingDefinition;\n /** The exchange that receives commands */\n exchange: TExchange;\n /** The queue this consumer reads from */\n queue: TQueue;\n /** The message definition */\n message: TMessage;\n /** The routing key pattern for the binding */\n routingKey: TRoutingKey;\n};\n\n/**\n * Configuration for a bridged command publisher.\n *\n * A bridged publisher publishes to a bridge exchange (local domain), which forwards\n * messages to the target exchange (remote domain) via an exchange-to-exchange binding.\n *\n * @template TMessage - The message definition\n * @template TBridgeExchange - The bridge (local domain) exchange definition\n * @template TTargetExchange - The target (remote domain) exchange definition\n */\nexport type BridgedPublisherConfig<\n TMessage extends MessageDefinition,\n TBridgeExchange extends ExchangeDefinition,\n TTargetExchange extends ExchangeDefinition,\n> = {\n /** Discriminator to identify this as a bridged publisher config */\n __brand: \"BridgedPublisherConfig\";\n /** The publisher definition (publishes to bridge exchange) */\n publisher: PublisherDefinition<TMessage>;\n /** The exchange-to-exchange binding (bridge → target) */\n exchangeBinding: ExchangeBindingDefinition;\n /** The bridge (local domain) exchange */\n bridgeExchange: TBridgeExchange;\n /** The target (remote domain) exchange */\n targetExchange: TTargetExchange;\n};\n\n/**\n * Define a command consumer for receiving commands via fanout exchange.\n *\n * Commands are sent by publishers to a specific queue. The consumer \"owns\" the\n * queue and defines what commands it accepts.\n *\n * @param queue - The queue that will receive commands\n * @param exchange - The fanout exchange that routes commands\n * @param message - The message definition (schema and metadata)\n * @param options - Optional binding configuration\n * @param options.arguments - Additional AMQP arguments\n * @returns A command consumer configuration\n *\n * @example\n * ```typescript\n * const tasksExchange = defineExchange('tasks', { type: 'fanout' });\n * const taskMessage = defineMessage(z.object({ taskId: z.string() }));\n *\n * // Consumer owns the queue\n * const executeTask = defineCommandConsumer(taskQueue, tasksExchange, taskMessage);\n *\n * // Publishers send commands to it\n * const sendTask = defineCommandPublisher(executeTask);\n * ```\n */\nexport function defineCommandConsumer<\n TMessage extends MessageDefinition,\n TQueueEntry extends QueueEntry,\n TExchange extends FanoutExchangeDefinition,\n>(\n queue: TQueueEntry,\n exchange: TExchange,\n message: TMessage,\n options?: {\n arguments?: Record<string, unknown>;\n },\n): CommandConsumerConfig<TMessage, TExchange, undefined, TQueueEntry>;\n\n/**\n * Define a command consumer for receiving commands via headers exchange.\n *\n * Commands are sent by publishers to a specific queue. The consumer \"owns\" the\n * queue and defines what commands it accepts.\n *\n * @param queue - The queue that will receive commands\n * @param exchange - The headers exchange that routes commands\n * @param message - The message definition (schema and metadata)\n * @param options - Optional binding configuration\n * @param options.arguments - Additional AMQP arguments\n * @returns A command consumer configuration\n *\n * @example\n * ```typescript\n * const tasksExchange = defineExchange('tasks', { type: 'headers' });\n * const taskMessage = defineMessage(z.object({ taskId: z.string() }));\n *\n * // Consumer owns the queue\n * const executeTask = defineCommandConsumer(taskQueue, tasksExchange, taskMessage);\n *\n * // Publishers send commands to it\n * const sendTask = defineCommandPublisher(executeTask);\n * ```\n */\nexport function defineCommandConsumer<\n TMessage extends MessageDefinition,\n TQueueEntry extends QueueEntry,\n TExchange extends HeadersExchangeDefinition,\n>(\n queue: TQueueEntry,\n exchange: TExchange,\n message: TMessage,\n options?: {\n arguments?: Record<string, unknown>;\n },\n): CommandConsumerConfig<TMessage, TExchange, undefined, TQueueEntry>;\n\n/**\n * Define a command consumer for receiving commands via direct exchange.\n *\n * Commands are sent by publishers with a specific routing key that matches\n * the binding pattern.\n *\n * @param queue - The queue that will receive commands\n * @param exchange - The direct exchange that routes commands\n * @param message - The message definition (schema and metadata)\n * @param options - Configuration with required routing key\n * @param options.routingKey - The routing key for the binding\n * @param options.arguments - Additional AMQP arguments\n * @returns A command consumer configuration\n *\n * @example\n * ```typescript\n * const tasksExchange = defineExchange('tasks', { type: 'direct' });\n * const taskMessage = defineMessage(z.object({ taskId: z.string() }));\n *\n * const executeTask = defineCommandConsumer(taskQueue, tasksExchange, taskMessage, {\n * routingKey: 'task.execute',\n * });\n *\n * const sendTask = defineCommandPublisher(executeTask);\n * ```\n */\nexport function defineCommandConsumer<\n TMessage extends MessageDefinition,\n TRoutingKey extends string,\n TQueueEntry extends QueueEntry,\n TExchange extends DirectExchangeDefinition,\n>(\n queue: TQueueEntry,\n exchange: TExchange,\n message: TMessage,\n options: {\n routingKey: RoutingKey<TRoutingKey>;\n arguments?: Record<string, unknown>;\n },\n): CommandConsumerConfig<TMessage, TExchange, TRoutingKey, TQueueEntry>;\n\n/**\n * Define a command consumer for receiving commands via topic exchange.\n *\n * The consumer binds with a routing key pattern (can use * and # wildcards).\n * Publishers then send commands with concrete routing keys that match the pattern.\n *\n * @param queue - The queue that will receive commands\n * @param exchange - The topic exchange that routes commands\n * @param message - The message definition (schema and metadata)\n * @param options - Configuration with required routing key pattern\n * @param options.routingKey - The routing key pattern for the binding\n * @param options.arguments - Additional AMQP arguments\n * @returns A command consumer configuration\n *\n * @example\n * ```typescript\n * const ordersExchange = defineExchange('orders', { type: 'topic' });\n * const orderMessage = defineMessage(z.object({ orderId: z.string() }));\n *\n * // Consumer uses pattern to receive multiple command types\n * const processOrder = defineCommandConsumer(orderQueue, ordersExchange, orderMessage, {\n * routingKey: 'order.*',\n * });\n *\n * // Publishers send with concrete keys\n * const createOrder = defineCommandPublisher(processOrder, {\n * routingKey: 'order.create',\n * });\n * const updateOrder = defineCommandPublisher(processOrder, {\n * routingKey: 'order.update',\n * });\n * ```\n */\nexport function defineCommandConsumer<\n TMessage extends MessageDefinition,\n TRoutingKey extends string,\n TQueueEntry extends QueueEntry,\n TExchange extends TopicExchangeDefinition,\n>(\n queue: TQueueEntry,\n exchange: TExchange,\n message: TMessage,\n options: {\n routingKey: BindingPattern<TRoutingKey>;\n arguments?: Record<string, unknown>;\n },\n): CommandConsumerConfig<TMessage, TExchange, TRoutingKey, TQueueEntry>;\n\n/**\n * Implementation of defineCommandConsumer.\n * @internal\n */\nexport function defineCommandConsumer<TMessage extends MessageDefinition>(\n queue: QueueEntry,\n exchange: ExchangeDefinition,\n message: TMessage,\n options?: {\n routingKey?: string;\n arguments?: Record<string, unknown>;\n },\n): CommandConsumerConfig<TMessage, ExchangeDefinition, string | undefined> {\n const consumer = defineConsumer(queue, message);\n const binding = defineQueueBindingInternal(queue, exchange, options);\n\n return {\n __brand: \"CommandConsumerConfig\",\n consumer,\n binding,\n exchange,\n queue,\n message,\n routingKey: options?.routingKey,\n };\n}\n\n/**\n * Create a bridged publisher that sends commands to a fanout exchange consumer via a bridge exchange.\n *\n * @param commandConsumer - The command consumer configuration\n * @param options - Configuration with required bridgeExchange\n * @param options.bridgeExchange - The local domain exchange to bridge through (must be fanout to match target)\n * @returns A bridged publisher configuration\n */\nexport function defineCommandPublisher<\n TMessage extends MessageDefinition,\n TExchange extends FanoutExchangeDefinition,\n TBridgeExchange extends FanoutExchangeDefinition,\n>(\n commandConsumer: CommandConsumerConfig<TMessage, TExchange, undefined>,\n options: {\n bridgeExchange: TBridgeExchange;\n },\n): BridgedPublisherConfig<TMessage, TBridgeExchange, TExchange>;\n\n/**\n * Create a bridged publisher that sends commands to a headers exchange consumer via a bridge exchange.\n *\n * @param commandConsumer - The command consumer configuration\n * @param options - Configuration with required bridgeExchange\n * @param options.bridgeExchange - The local domain exchange to bridge through (must be headers to match target)\n * @returns A bridged publisher configuration\n */\nexport function defineCommandPublisher<\n TMessage extends MessageDefinition,\n TExchange extends HeadersExchangeDefinition,\n TBridgeExchange extends HeadersExchangeDefinition,\n>(\n commandConsumer: CommandConsumerConfig<TMessage, TExchange, undefined>,\n options: {\n bridgeExchange: TBridgeExchange;\n },\n): BridgedPublisherConfig<TMessage, TBridgeExchange, TExchange>;\n\n/**\n * Create a bridged publisher that sends commands to a direct exchange consumer via a bridge exchange.\n *\n * @param commandConsumer - The command consumer configuration\n * @param options - Configuration with required bridgeExchange\n * @param options.bridgeExchange - The bridge exchange (must be direct or topic to preserve routing keys)\n * @returns A bridged publisher configuration\n */\nexport function defineCommandPublisher<\n TMessage extends MessageDefinition,\n TRoutingKey extends string,\n TExchange extends DirectExchangeDefinition,\n TBridgeExchange extends DirectExchangeDefinition | TopicExchangeDefinition,\n>(\n commandConsumer: CommandConsumerConfig<TMessage, TExchange, TRoutingKey>,\n options: {\n bridgeExchange: TBridgeExchange;\n },\n): BridgedPublisherConfig<TMessage, TBridgeExchange, TExchange>;\n\n/**\n * Create a bridged publisher that sends commands to a topic exchange consumer via a bridge exchange.\n *\n * @param commandConsumer - The command consumer configuration\n * @param options - Configuration with required bridgeExchange and optional routingKey override\n * @param options.bridgeExchange - The bridge exchange (must be direct or topic to preserve routing keys)\n * @param options.routingKey - Override routing key (must match consumer's pattern)\n * @returns A bridged publisher configuration\n */\nexport function defineCommandPublisher<\n TMessage extends MessageDefinition,\n TRoutingKey extends string,\n TExchange extends TopicExchangeDefinition,\n TBridgeExchange extends DirectExchangeDefinition | TopicExchangeDefinition,\n TPublisherRoutingKey extends string = TRoutingKey,\n>(\n commandConsumer: CommandConsumerConfig<TMessage, TExchange, TRoutingKey>,\n options: {\n bridgeExchange: TBridgeExchange;\n routingKey?: RoutingKey<TPublisherRoutingKey>;\n },\n): BridgedPublisherConfig<TMessage, TBridgeExchange, TExchange>;\n\n/**\n * Create a publisher that sends commands to a fanout exchange consumer.\n *\n * @param commandConsumer - The command consumer configuration\n * @returns A publisher definition\n *\n * @example\n * ```typescript\n * const executeTask = defineCommandConsumer(taskQueue, fanoutExchange, taskMessage);\n * const sendTask = defineCommandPublisher(executeTask);\n * ```\n */\nexport function defineCommandPublisher<TMessage extends MessageDefinition>(\n commandConsumer: CommandConsumerConfig<TMessage, FanoutExchangeDefinition, undefined>,\n): { message: TMessage; exchange: FanoutExchangeDefinition };\n\n/**\n * Create a publisher that sends commands to a headers exchange consumer.\n *\n * @param commandConsumer - The command consumer configuration\n * @returns A publisher definition\n *\n * @example\n * ```typescript\n * const executeTask = defineCommandConsumer(taskQueue, headersExchange, taskMessage);\n * const sendTask = defineCommandPublisher(executeTask);\n * ```\n */\nexport function defineCommandPublisher<TMessage extends MessageDefinition>(\n commandConsumer: CommandConsumerConfig<TMessage, HeadersExchangeDefinition, undefined>,\n): { message: TMessage; exchange: HeadersExchangeDefinition };\n\n/**\n * Create a publisher that sends commands to a direct exchange consumer.\n *\n * @param commandConsumer - The command consumer configuration\n * @returns A publisher definition\n */\nexport function defineCommandPublisher<\n TMessage extends MessageDefinition,\n TRoutingKey extends string,\n>(\n commandConsumer: CommandConsumerConfig<TMessage, DirectExchangeDefinition, TRoutingKey>,\n): { message: TMessage; exchange: DirectExchangeDefinition; routingKey: string };\n\n/**\n * Create a publisher that sends commands to a topic exchange consumer.\n *\n * For topic exchanges where the consumer uses a pattern, the publisher can\n * optionally specify a concrete routing key that matches the pattern.\n *\n * @param commandConsumer - The command consumer configuration\n * @param options - Optional binding configuration\n * @param options.routingKey - Override routing key (must match consumer's pattern)\n * @returns A publisher definition\n *\n * @example\n * ```typescript\n * // Consumer binds with pattern\n * const processOrder = defineCommandConsumer(orderQueue, topicExchange, orderMessage, {\n * routingKey: 'order.*',\n * });\n *\n * // Publisher uses concrete key matching the pattern\n * const createOrder = defineCommandPublisher(processOrder, {\n * routingKey: 'order.create',\n * });\n * ```\n */\nexport function defineCommandPublisher<\n TMessage extends MessageDefinition,\n TRoutingKey extends string,\n TPublisherRoutingKey extends string = TRoutingKey,\n>(\n commandConsumer: CommandConsumerConfig<TMessage, TopicExchangeDefinition, TRoutingKey>,\n options?: {\n routingKey?: RoutingKey<TPublisherRoutingKey>;\n },\n): { message: TMessage; exchange: TopicExchangeDefinition; routingKey: string };\n\n/**\n * Implementation of defineCommandPublisher.\n * @internal\n */\nexport function defineCommandPublisher<TMessage extends MessageDefinition>(\n commandConsumer: CommandConsumerConfig<TMessage, ExchangeDefinition, string | undefined>,\n options?: {\n routingKey?: string;\n bridgeExchange?: ExchangeDefinition;\n },\n):\n | PublisherDefinition<TMessage>\n | BridgedPublisherConfig<TMessage, ExchangeDefinition, ExchangeDefinition> {\n const { exchange: targetExchange, message, routingKey: consumerRoutingKey } = commandConsumer;\n\n // For topic exchanges, publisher can override the routing key\n const publisherRoutingKey = options?.routingKey ?? consumerRoutingKey;\n\n const bridgeExchange = options?.bridgeExchange;\n\n if (bridgeExchange) {\n // Bridged: publisher publishes to bridge exchange, e2e binding from bridge → target\n const publisherOptions: { routingKey?: string } = {};\n if (publisherRoutingKey !== undefined) {\n publisherOptions.routingKey = publisherRoutingKey;\n }\n\n const publisher = definePublisherInternal(bridgeExchange, message, publisherOptions);\n\n // Create e2e binding: target ← bridge (destination = target, source = bridge)\n const e2eBindingOptions: { routingKey?: string } = {};\n if (publisherRoutingKey !== undefined) {\n e2eBindingOptions.routingKey = publisherRoutingKey;\n }\n const e2eBinding =\n bridgeExchange.type === \"fanout\" || bridgeExchange.type === \"headers\"\n ? defineExchangeBinding(targetExchange, bridgeExchange)\n : defineExchangeBinding(\n targetExchange,\n bridgeExchange as DirectExchangeDefinition | TopicExchangeDefinition,\n e2eBindingOptions as { routingKey: string },\n );\n\n return {\n __brand: \"BridgedPublisherConfig\",\n publisher,\n exchangeBinding: e2eBinding,\n bridgeExchange,\n targetExchange,\n };\n }\n\n const publisherOptions: { routingKey?: string } = {};\n if (publisherRoutingKey !== undefined) {\n publisherOptions.routingKey = publisherRoutingKey;\n }\n\n return definePublisherInternal(targetExchange, message, publisherOptions);\n}\n\n/**\n * Type guard to check if a value is a CommandConsumerConfig.\n *\n * @param value - The value to check\n * @returns True if the value is a CommandConsumerConfig\n */\nexport function isCommandConsumerConfig(\n value: unknown,\n): value is CommandConsumerConfig<MessageDefinition, ExchangeDefinition, string | undefined> {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"__brand\" in value &&\n value.__brand === \"CommandConsumerConfig\"\n );\n}\n\n/**\n * Type guard to check if a value is a BridgedPublisherConfig.\n *\n * @param value - The value to check\n * @returns True if the value is a BridgedPublisherConfig\n */\nexport function isBridgedPublisherConfig(\n value: unknown,\n): value is BridgedPublisherConfig<MessageDefinition, ExchangeDefinition, ExchangeDefinition> {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"__brand\" in value &&\n value.__brand === \"BridgedPublisherConfig\"\n );\n}\n","import type {\n ConsumerDefinition,\n DirectExchangeDefinition,\n ExchangeBindingDefinition,\n ExchangeDefinition,\n FanoutExchangeDefinition,\n HeadersExchangeDefinition,\n MessageDefinition,\n QueueBindingDefinition,\n QueueEntry,\n TopicExchangeDefinition,\n} from \"../types.js\";\nimport { defineExchangeBinding, defineQueueBindingInternal } from \"./binding.js\";\nimport { defineConsumer } from \"./consumer.js\";\nimport type { BindingPattern, RoutingKey } from \"./routing-types.js\";\n\n/**\n * Configuration for an event publisher.\n *\n * Events are published without knowing who consumes them. Multiple consumers\n * can subscribe to the same event. This follows the pub/sub pattern where\n * publishers broadcast events and consumers subscribe to receive them.\n *\n * @template TMessage - The message definition\n * @template TExchange - The exchange definition\n * @template TRoutingKey - The routing key type (undefined for fanout and headers exchanges)\n */\nexport type EventPublisherConfig<\n TMessage extends MessageDefinition,\n TExchange extends ExchangeDefinition,\n TRoutingKey extends string | undefined = undefined,\n> = {\n /** Discriminator to identify this as an event publisher config */\n __brand: \"EventPublisherConfig\";\n /** The exchange to publish to */\n exchange: TExchange;\n /** The message definition */\n message: TMessage;\n /** The routing key for direct/topic exchanges */\n routingKey: TRoutingKey;\n /** Additional AMQP arguments */\n arguments?: Record<string, unknown>;\n};\n\n/**\n * Result from defineEventConsumer.\n *\n * Contains the consumer definition and binding needed to subscribe to an event.\n * Can be used directly in defineContract's consumers section - the binding\n * will be automatically extracted.\n *\n * @template TMessage - The message definition\n */\nexport type EventConsumerResult<\n TMessage extends MessageDefinition,\n TExchange extends ExchangeDefinition = ExchangeDefinition,\n TQueue extends QueueEntry = QueueEntry,\n TExchangeBinding extends ExchangeBindingDefinition | undefined =\n | ExchangeBindingDefinition\n | undefined,\n TBridgeExchange extends ExchangeDefinition | undefined = ExchangeDefinition | undefined,\n> = {\n /** Discriminator to identify this as an event consumer result */\n __brand: \"EventConsumerResult\";\n /** The consumer definition for processing messages */\n consumer: ConsumerDefinition<TMessage>;\n /** The binding connecting the queue to the exchange */\n binding: QueueBindingDefinition;\n /** The source exchange this consumer subscribes to */\n exchange: TExchange;\n /** The queue this consumer reads from */\n queue: TQueue;\n /** The exchange-to-exchange binding when bridging, if configured */\n exchangeBinding: TExchangeBinding;\n /** The bridge (local domain) exchange when bridging, if configured */\n bridgeExchange: TBridgeExchange;\n};\n\n/**\n * Define an event publisher for broadcasting messages via fanout exchange.\n *\n * Events are published without knowing who consumes them. Multiple consumers\n * can subscribe to the same event using `defineEventConsumer`.\n *\n * @param exchange - The fanout exchange to publish to\n * @param message - The message definition (schema and metadata)\n * @param options - Optional binding configuration\n * @param options.arguments - Additional AMQP arguments\n * @returns An event publisher configuration\n *\n * @example\n * ```typescript\n * const logsExchange = defineExchange('logs', { type: 'fanout' });\n * const logMessage = defineMessage(z.object({\n * level: z.enum(['info', 'warn', 'error']),\n * message: z.string(),\n * }));\n *\n * // Create event publisher\n * const logEvent = defineEventPublisher(logsExchange, logMessage);\n *\n * // Multiple consumers can subscribe\n * const { consumer: fileConsumer, binding: fileBinding } =\n * defineEventConsumer(logEvent, fileLogsQueue);\n * const { consumer: alertConsumer, binding: alertBinding } =\n * defineEventConsumer(logEvent, alertsQueue);\n * ```\n */\nexport function defineEventPublisher<\n TMessage extends MessageDefinition,\n TExchange extends FanoutExchangeDefinition,\n>(\n exchange: TExchange,\n message: TMessage,\n options?: {\n arguments?: Record<string, unknown>;\n },\n): EventPublisherConfig<TMessage, TExchange, undefined>;\n\n/**\n * Define an event publisher for broadcasting messages via headers exchange.\n *\n * Events are published without knowing who consumes them. Multiple consumers\n * can subscribe to the same event using `defineEventConsumer`.\n *\n * @param exchange - The headers exchange to publish to\n * @param message - The message definition (schema and metadata)\n * @param options - Optional binding configuration\n * @param options.arguments - Additional AMQP arguments\n * @returns An event publisher configuration\n *\n * @example\n * ```typescript\n * const logsExchange = defineExchange('logs', { type: 'headers' });\n * const logMessage = defineMessage(z.object({\n * level: z.enum(['info', 'warn', 'error']),\n * message: z.string(),\n * }));\n *\n * // Create event publisher\n * const logEvent = defineEventPublisher(logsExchange, logMessage);\n *\n * // Multiple consumers can subscribe\n * const { consumer: fileConsumer, binding: fileBinding } =\n * defineEventConsumer(logEvent, fileLogsQueue);\n * const { consumer: alertConsumer, binding: alertBinding } =\n * defineEventConsumer(logEvent, alertsQueue);\n * ```\n */\nexport function defineEventPublisher<\n TMessage extends MessageDefinition,\n TExchange extends HeadersExchangeDefinition,\n>(\n exchange: TExchange,\n message: TMessage,\n options?: {\n arguments?: Record<string, unknown>;\n },\n): EventPublisherConfig<TMessage, TExchange, undefined>;\n\n/**\n * Define an event publisher for broadcasting messages via direct exchange.\n *\n * Events are published with a specific routing key. Consumers will receive\n * messages that match the routing key exactly.\n *\n * @param exchange - The direct exchange to publish to\n * @param message - The message definition (schema and metadata)\n * @param options - Configuration with required routing key\n * @param options.routingKey - The routing key for message routing\n * @param options.arguments - Additional AMQP arguments\n * @returns An event publisher configuration\n *\n * @example\n * ```typescript\n * const tasksExchange = defineExchange('tasks', { type: 'direct' });\n * const taskMessage = defineMessage(z.object({ taskId: z.string() }));\n *\n * const taskEvent = defineEventPublisher(tasksExchange, taskMessage, {\n * routingKey: 'task.execute',\n * });\n * ```\n */\nexport function defineEventPublisher<\n TMessage extends MessageDefinition,\n TRoutingKey extends string,\n TExchange extends DirectExchangeDefinition,\n>(\n exchange: TExchange,\n message: TMessage,\n options: {\n routingKey: RoutingKey<TRoutingKey>;\n arguments?: Record<string, unknown>;\n },\n): EventPublisherConfig<TMessage, TExchange, TRoutingKey>;\n\n/**\n * Define an event publisher for broadcasting messages via topic exchange.\n *\n * Events are published with a concrete routing key. Consumers can subscribe\n * using patterns (with * and # wildcards) to receive matching messages.\n *\n * @param exchange - The topic exchange to publish to\n * @param message - The message definition (schema and metadata)\n * @param options - Configuration with required routing key\n * @param options.routingKey - The concrete routing key (no wildcards)\n * @param options.arguments - Additional AMQP arguments\n * @returns An event publisher configuration\n *\n * @example\n * ```typescript\n * const ordersExchange = defineExchange('orders', { type: 'topic' });\n * const orderMessage = defineMessage(z.object({\n * orderId: z.string(),\n * amount: z.number(),\n * }));\n *\n * // Publisher uses concrete routing key\n * const orderCreatedEvent = defineEventPublisher(ordersExchange, orderMessage, {\n * routingKey: 'order.created',\n * });\n *\n * // Consumer can use pattern\n * const { consumer, binding } = defineEventConsumer(\n * orderCreatedEvent,\n * allOrdersQueue,\n * { routingKey: 'order.*' },\n * );\n * ```\n */\nexport function defineEventPublisher<\n TMessage extends MessageDefinition,\n TRoutingKey extends string,\n TExchange extends TopicExchangeDefinition,\n>(\n exchange: TExchange,\n message: TMessage,\n options: {\n routingKey: RoutingKey<TRoutingKey>;\n arguments?: Record<string, unknown>;\n },\n): EventPublisherConfig<TMessage, TExchange, TRoutingKey>;\n\n/**\n * Implementation of defineEventPublisher.\n * @internal\n */\nexport function defineEventPublisher<TMessage extends MessageDefinition>(\n exchange: ExchangeDefinition,\n message: TMessage,\n options?: {\n routingKey?: string;\n arguments?: Record<string, unknown>;\n },\n): EventPublisherConfig<TMessage, ExchangeDefinition, string | undefined> {\n const config: EventPublisherConfig<TMessage, ExchangeDefinition, string | undefined> = {\n __brand: \"EventPublisherConfig\",\n exchange,\n message,\n routingKey: options?.routingKey,\n };\n\n if (options?.arguments !== undefined) {\n config.arguments = options.arguments;\n }\n\n return config;\n}\n\n/**\n * Create a consumer that subscribes to an event from a fanout exchange via a bridge exchange.\n *\n * When `bridgeExchange` is provided, the queue binds to the bridge exchange instead of the\n * source exchange, and an exchange-to-exchange binding is created from the source to the bridge.\n *\n * @param eventPublisher - The event publisher configuration\n * @param queue - The queue that will receive messages\n * @param options - Binding configuration with required bridgeExchange\n * @param options.bridgeExchange - The fanout bridge exchange (must be fanout to match source)\n * @param options.arguments - Additional AMQP arguments\n * @returns An object with the consumer definition, queue binding, and exchange binding\n */\nexport function defineEventConsumer<\n TMessage extends MessageDefinition,\n TExchange extends FanoutExchangeDefinition,\n TQueueEntry extends QueueEntry,\n TBridgeExchange extends FanoutExchangeDefinition,\n>(\n eventPublisher: EventPublisherConfig<TMessage, TExchange, undefined>,\n queue: TQueueEntry,\n options: {\n bridgeExchange: TBridgeExchange;\n arguments?: Record<string, unknown>;\n },\n): EventConsumerResult<\n TMessage,\n TExchange,\n TQueueEntry,\n ExchangeBindingDefinition,\n TBridgeExchange\n>;\n\n/**\n * Create a consumer that subscribes to an event from a headers exchange via a bridge exchange.\n *\n * When `bridgeExchange` is provided, the queue binds to the bridge exchange instead of the\n * source exchange, and an exchange-to-exchange binding is created from the source to the bridge.\n *\n * @param eventPublisher - The event publisher configuration\n * @param queue - The queue that will receive messages\n * @param options - Binding configuration with required bridgeExchange\n * @param options.bridgeExchange - The headers bridge exchange (must be headers to match source)\n * @param options.arguments - Additional AMQP arguments\n * @returns An object with the consumer definition, queue binding, and exchange binding\n */\nexport function defineEventConsumer<\n TMessage extends MessageDefinition,\n TExchange extends HeadersExchangeDefinition,\n TQueueEntry extends QueueEntry,\n TBridgeExchange extends HeadersExchangeDefinition,\n>(\n eventPublisher: EventPublisherConfig<TMessage, TExchange, undefined>,\n queue: TQueueEntry,\n options: {\n bridgeExchange: TBridgeExchange;\n arguments?: Record<string, unknown>;\n },\n): EventConsumerResult<\n TMessage,\n TExchange,\n TQueueEntry,\n ExchangeBindingDefinition,\n TBridgeExchange\n>;\n\n/**\n * Create a consumer that subscribes to an event from a direct exchange via a bridge exchange.\n *\n * @param eventPublisher - The event publisher configuration\n * @param queue - The queue that will receive messages\n * @param options - Binding configuration with required bridgeExchange\n * @param options.bridgeExchange - The bridge exchange (must be direct or topic to preserve routing keys)\n * @param options.arguments - Additional AMQP arguments\n * @returns An object with the consumer definition, queue binding, and exchange binding\n */\nexport function defineEventConsumer<\n TMessage extends MessageDefinition,\n TRoutingKey extends string,\n TExchange extends DirectExchangeDefinition,\n TQueueEntry extends QueueEntry,\n TBridgeExchange extends DirectExchangeDefinition | TopicExchangeDefinition,\n>(\n eventPublisher: EventPublisherConfig<TMessage, TExchange, TRoutingKey>,\n queue: TQueueEntry,\n options: {\n bridgeExchange: TBridgeExchange;\n arguments?: Record<string, unknown>;\n },\n): EventConsumerResult<\n TMessage,\n TExchange,\n TQueueEntry,\n ExchangeBindingDefinition,\n TBridgeExchange\n>;\n\n/**\n * Create a consumer that subscribes to an event from a topic exchange via a bridge exchange.\n *\n * @param eventPublisher - The event publisher configuration\n * @param queue - The queue that will receive messages\n * @param options - Binding configuration with required bridgeExchange\n * @param options.bridgeExchange - The bridge exchange (must be direct or topic to preserve routing keys)\n * @param options.routingKey - Override routing key with pattern (defaults to publisher's key)\n * @param options.arguments - Additional AMQP arguments\n * @returns An object with the consumer definition, queue binding, and exchange binding\n */\nexport function defineEventConsumer<\n TMessage extends MessageDefinition,\n TRoutingKey extends string,\n TExchange extends TopicExchangeDefinition,\n TQueueEntry extends QueueEntry,\n TBridgeExchange extends DirectExchangeDefinition | TopicExchangeDefinition,\n TConsumerRoutingKey extends string = TRoutingKey,\n>(\n eventPublisher: EventPublisherConfig<TMessage, TExchange, TRoutingKey>,\n queue: TQueueEntry,\n options: {\n bridgeExchange: TBridgeExchange;\n routingKey?: BindingPattern<TConsumerRoutingKey>;\n arguments?: Record<string, unknown>;\n },\n): EventConsumerResult<\n TMessage,\n TExchange,\n TQueueEntry,\n ExchangeBindingDefinition,\n TBridgeExchange\n>;\n\n/**\n * Create a consumer that subscribes to an event from a fanout exchange.\n *\n * @param eventPublisher - The event publisher configuration\n * @param queue - The queue that will receive messages\n * @param options - Optional binding configuration\n * @param options.arguments - Additional AMQP arguments\n * @returns An object with the consumer definition and binding\n *\n * @example\n * ```typescript\n * const logEvent = defineEventPublisher(logsExchange, logMessage);\n * const { consumer, binding } = defineEventConsumer(logEvent, logsQueue);\n * ```\n */\nexport function defineEventConsumer<\n TMessage extends MessageDefinition,\n TExchange extends FanoutExchangeDefinition,\n TQueueEntry extends QueueEntry,\n>(\n eventPublisher: EventPublisherConfig<TMessage, TExchange, undefined>,\n queue: TQueueEntry,\n options?: {\n arguments?: Record<string, unknown>;\n },\n): EventConsumerResult<TMessage, TExchange, TQueueEntry>;\n\n/**\n * Create a consumer that subscribes to an event from a headers exchange.\n *\n * @param eventPublisher - The event publisher configuration\n * @param queue - The queue that will receive messages\n * @param options - Optional binding configuration\n * @param options.arguments - Additional AMQP arguments\n * @returns An object with the consumer definition and binding\n *\n * @example\n * ```typescript\n * const logEvent = defineEventPublisher(logsExchange, logMessage);\n * const { consumer, binding } = defineEventConsumer(logEvent, logsQueue);\n * ```\n */\nexport function defineEventConsumer<\n TMessage extends MessageDefinition,\n TExchange extends HeadersExchangeDefinition,\n TQueueEntry extends QueueEntry,\n>(\n eventPublisher: EventPublisherConfig<TMessage, TExchange, undefined>,\n queue: TQueueEntry,\n options?: {\n arguments?: Record<string, unknown>;\n },\n): EventConsumerResult<TMessage, TExchange, TQueueEntry>;\n\n/**\n * Create a consumer that subscribes to an event from a direct exchange.\n *\n * @param eventPublisher - The event publisher configuration\n * @param queue - The queue that will receive messages\n * @param options - Optional binding configuration\n * @param options.arguments - Additional AMQP arguments\n * @returns An object with the consumer definition and binding\n */\nexport function defineEventConsumer<\n TMessage extends MessageDefinition,\n TRoutingKey extends string,\n TExchange extends DirectExchangeDefinition,\n TQueueEntry extends QueueEntry,\n>(\n eventPublisher: EventPublisherConfig<TMessage, TExchange, TRoutingKey>,\n queue: TQueueEntry,\n options?: {\n arguments?: Record<string, unknown>;\n },\n): EventConsumerResult<TMessage, TExchange, TQueueEntry>;\n\n/**\n * Create a consumer that subscribes to an event from a topic exchange.\n *\n * For topic exchanges, the consumer can optionally override the routing key\n * with a pattern to subscribe to multiple events.\n *\n * @param eventPublisher - The event publisher configuration\n * @param queue - The queue that will receive messages\n * @param options - Optional binding configuration\n * @param options.routingKey - Override routing key with pattern (defaults to publisher's key)\n * @param options.arguments - Additional AMQP arguments\n * @returns An object with the consumer definition and binding\n *\n * @example\n * ```typescript\n * const orderCreatedEvent = defineEventPublisher(ordersExchange, orderMessage, {\n * routingKey: 'order.created',\n * });\n *\n * // Use exact routing key from publisher\n * const { consumer: exactConsumer } = defineEventConsumer(orderCreatedEvent, exactQueue);\n *\n * // Override with pattern to receive all order events\n * const { consumer: allConsumer } = defineEventConsumer(orderCreatedEvent, allQueue, {\n * routingKey: 'order.*',\n * });\n * ```\n */\nexport function defineEventConsumer<\n TMessage extends MessageDefinition,\n TRoutingKey extends string,\n TExchange extends TopicExchangeDefinition,\n TQueueEntry extends QueueEntry,\n TConsumerRoutingKey extends string = TRoutingKey,\n>(\n eventPublisher: EventPublisherConfig<TMessage, TExchange, TRoutingKey>,\n queue: TQueueEntry,\n options?: {\n routingKey?: BindingPattern<TConsumerRoutingKey>;\n arguments?: Record<string, unknown>;\n },\n): EventConsumerResult<TMessage, TExchange, TQueueEntry>;\n\n/**\n * Implementation of defineEventConsumer.\n * @internal\n */\nexport function defineEventConsumer<TMessage extends MessageDefinition>(\n eventPublisher: EventPublisherConfig<TMessage, ExchangeDefinition, string | undefined>,\n queue: QueueEntry,\n options?: {\n routingKey?: string;\n bridgeExchange?: ExchangeDefinition;\n arguments?: Record<string, unknown>;\n },\n): EventConsumerResult<TMessage> {\n const { exchange: sourceExchange, message, routingKey: publisherRoutingKey } = eventPublisher;\n\n // For topic exchanges, consumer can override the routing key\n const bindingRoutingKey = options?.routingKey ?? publisherRoutingKey;\n\n const bindingOptions: { routingKey?: string; arguments?: Record<string, unknown> } = {};\n if (bindingRoutingKey !== undefined) {\n bindingOptions.routingKey = bindingRoutingKey;\n }\n const bindingArguments = options?.arguments ?? eventPublisher.arguments;\n if (bindingArguments !== undefined) {\n bindingOptions.arguments = bindingArguments;\n }\n\n const bridgeExchange = options?.bridgeExchange;\n\n if (bridgeExchange) {\n // Bridged: queue binds to bridge exchange, e2e binding from source → bridge\n const binding = defineQueueBindingInternal(queue, bridgeExchange, bindingOptions);\n const consumer = defineConsumer(queue, message);\n\n // Create e2e binding: bridge ← source (destination ← source)\n const exchangeBindingOptions: { routingKey?: string } = {};\n if (bindingRoutingKey !== undefined) {\n exchangeBindingOptions.routingKey = bindingRoutingKey;\n }\n const e2eBinding =\n sourceExchange.type === \"fanout\" || sourceExchange.type === \"headers\"\n ? defineExchangeBinding(bridgeExchange, sourceExchange)\n : defineExchangeBinding(\n bridgeExchange,\n sourceExchange as DirectExchangeDefinition | TopicExchangeDefinition,\n exchangeBindingOptions as { routingKey: string },\n );\n\n return {\n __brand: \"EventConsumerResult\",\n consumer,\n binding,\n exchange: sourceExchange,\n queue,\n exchangeBinding: e2eBinding,\n bridgeExchange,\n } as EventConsumerResult<TMessage>;\n }\n\n const binding = defineQueueBindingInternal(queue, sourceExchange, bindingOptions);\n const consumer = defineConsumer(queue, message);\n\n return {\n __brand: \"EventConsumerResult\",\n consumer,\n binding,\n exchange: sourceExchange,\n queue,\n exchangeBinding: undefined,\n bridgeExchange: undefined,\n };\n}\n\n/**\n * Type guard to check if a value is an EventPublisherConfig.\n *\n * @param value - The value to check\n * @returns True if the value is an EventPublisherConfig\n */\nexport function isEventPublisherConfig(\n value: unknown,\n): value is EventPublisherConfig<MessageDefinition, ExchangeDefinition, string | undefined> {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"__brand\" in value &&\n value.__brand === \"EventPublisherConfig\"\n );\n}\n\n/**\n * Type guard to check if a value is an EventConsumerResult.\n *\n * @param value - The value to check\n * @returns True if the value is an EventConsumerResult\n */\nexport function isEventConsumerResult(\n value: unknown,\n): value is EventConsumerResult<MessageDefinition> {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"__brand\" in value &&\n value.__brand === \"EventConsumerResult\"\n );\n}\n","import type {\n BindingDefinition,\n ConsumerDefinition,\n ContractDefinition,\n ContractDefinitionInput,\n ContractOutput,\n ExchangeDefinition,\n PublisherDefinition,\n QueueEntry,\n RpcDefinition,\n} from \"../types.js\";\nimport { isBridgedPublisherConfig, isCommandConsumerConfig } from \"./command.js\";\nimport { isEventConsumerResult, isEventPublisherConfig } from \"./event.js\";\nimport { definePublisherInternal } from \"./publisher.js\";\nimport { extractQueue } from \"./queue-utils.js\";\nimport { isQueueWithTtlBackoffInfrastructure } from \"./ttl-backoff.js\";\n\n/**\n * Structural equality for resource definitions. We compare on a JSON projection\n * after stripping non-comparable fields (Standard Schema instances, branded\n * symbols) so that, e.g., two `defineExchange(\"orders\")` calls in different\n * files are treated as the same exchange.\n */\nfunction resourcesEqual(a: unknown, b: unknown): boolean {\n if (a === b) return true;\n try {\n return JSON.stringify(a, replacer) === JSON.stringify(b, replacer);\n } catch {\n return false;\n }\n}\n\nfunction replacer(_key: string, value: unknown): unknown {\n // Standard Schema validators are functions / proxies that JSON.stringify\n // cannot meaningfully compare. Reduce them to a structural marker so two\n // independent `defineMessage(z.object({...}))` declarations of the same\n // shape don't trip the collision check.\n if (typeof value === \"function\") return \"[function]\";\n if (value && typeof value === \"object\" && \"~standard\" in (value as object)) {\n return \"[standard-schema]\";\n }\n return value;\n}\n\n/**\n * Add an entry to a name-keyed map, throwing if the name is already taken by a\n * structurally-different definition. Identical re-declarations are silently\n * deduplicated — that's how the same exchange can flow into the contract via\n * both a publisher and a consumer.\n */\nfunction addResource<T>(\n bucket: Record<string, T>,\n name: string,\n value: T,\n kind: \"exchange\" | \"queue\" | \"binding\",\n): void {\n const existing = bucket[name];\n if (existing === undefined) {\n bucket[name] = value;\n return;\n }\n if (!resourcesEqual(existing, value)) {\n throw new Error(\n `defineContract: ${kind} \"${name}\" was declared with conflicting definitions. ` +\n `Two ${kind}s sharing a name must be the exact same definition; ` +\n `define the ${kind} once and reference it from every publisher/consumer that needs it.`,\n );\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 * publishers and consumers in a single, type-safe definition. Exchanges, queues, and bindings\n * are automatically extracted from publishers and consumers.\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 publishers and consumers\n * @param definition.publishers - Named publisher definitions for sending messages\n * @param definition.consumers - Named consumer definitions for receiving messages\n * @returns The contract definition with fully inferred exchanges, queues, bindings, publishers, and consumers\n *\n * @example\n * ```typescript\n * import {\n * defineContract,\n * defineExchange,\n * defineQueue,\n * defineEventPublisher,\n * defineEventConsumer,\n * defineMessage,\n * } from '@amqp-contract/contract';\n * import { z } from 'zod';\n *\n * // Define resources\n * const ordersExchange = defineExchange('orders');\n * const dlx = defineExchange('orders-dlx', { type: 'direct' });\n * const orderQueue = defineQueue('order-processing', {\n * deadLetter: { exchange: dlx },\n * retry: { mode: 'immediate-requeue', maxRetries: 3 },\n * });\n * const orderMessage = defineMessage(\n * z.object({\n * orderId: z.string(),\n * amount: z.number(),\n * })\n * );\n *\n * // Define event publisher\n * const orderCreatedEvent = defineEventPublisher(ordersExchange, orderMessage, {\n * routingKey: 'order.created',\n * });\n *\n * // Compose contract - exchanges, queues, bindings are auto-extracted\n * export const contract = defineContract({\n * publishers: {\n * orderCreated: orderCreatedEvent,\n * },\n * consumers: {\n * processOrder: defineEventConsumer(orderCreatedEvent, orderQueue),\n * },\n * });\n *\n * // TypeScript now knows:\n * // - contract.exchanges.orders, contract.exchanges['orders-dlx']\n * // - contract.queues['order-processing']\n * // - contract.bindings.processOrderBinding\n * // - client.publish('orderCreated', { orderId: string, amount: number })\n * // - handler: (message: { orderId: string, amount: number }) => Future<Result<void, HandlerError>>\n * ```\n */\nexport function defineContract<TContract extends ContractDefinitionInput>(\n definition: TContract,\n): ContractOutput<TContract> {\n const { publishers: inputPublishers, consumers: inputConsumers, rpcs: inputRpcs } = definition;\n\n // Consumer names and RPC names share the worker handler keyspace; if the\n // same key appeared in both, the worker would consume from two queues under\n // one name and dispatch ambiguously. Fail fast at contract-definition time\n // rather than producing surprising runtime behavior.\n if (inputConsumers && inputRpcs) {\n const collisions = Object.keys(inputConsumers).filter((name) => Object.hasOwn(inputRpcs, name));\n if (collisions.length > 0) {\n throw new Error(\n `defineContract: name collision between consumers and rpcs — keys must be disjoint. Conflicting names: ${collisions.join(\", \")}`,\n );\n }\n }\n\n const result: ContractDefinition = {\n exchanges: {},\n queues: {},\n bindings: {},\n publishers: {},\n consumers: {},\n rpcs: {},\n };\n\n const exchanges: Record<string, ExchangeDefinition> = {};\n const queues: Record<string, QueueEntry> = {};\n const bindings: Record<string, BindingDefinition> = {};\n\n // Process publishers section - extract exchanges and convert EventPublisherConfig entries\n if (inputPublishers && Object.keys(inputPublishers).length > 0) {\n const processedPublishers: Record<string, PublisherDefinition> = {};\n\n for (const [name, entry] of Object.entries(inputPublishers)) {\n if (isBridgedPublisherConfig(entry)) {\n // BridgedPublisherConfig: extract publisher, exchanges, and e2e binding\n addResource(exchanges, entry.bridgeExchange.name, entry.bridgeExchange, \"exchange\");\n addResource(exchanges, entry.targetExchange.name, entry.targetExchange, \"exchange\");\n addResource(bindings, `${name}ExchangeBinding`, entry.exchangeBinding, \"binding\");\n processedPublishers[name] = entry.publisher;\n } else if (isEventPublisherConfig(entry)) {\n // EventPublisherConfig: extract exchange and convert to publisher definition\n addResource(exchanges, entry.exchange.name, entry.exchange, \"exchange\");\n const publisherOptions: { routingKey?: string } = {};\n if (entry.routingKey !== undefined) {\n publisherOptions.routingKey = entry.routingKey;\n }\n processedPublishers[name] = definePublisherInternal(\n entry.exchange,\n entry.message,\n publisherOptions,\n );\n } else {\n // Plain PublisherDefinition: extract exchange\n const publisher = entry as PublisherDefinition;\n addResource(exchanges, publisher.exchange.name, publisher.exchange, \"exchange\");\n processedPublishers[name] = publisher;\n }\n }\n\n result.publishers = processedPublishers;\n }\n\n // Process consumers section - extract queues, exchanges, bindings, and consumer definitions\n if (inputConsumers && Object.keys(inputConsumers).length > 0) {\n const processedConsumers: Record<string, ConsumerDefinition> = {};\n const consumerQueueEntries: QueueEntry[] = [];\n\n for (const [name, entry] of Object.entries(inputConsumers)) {\n if (isEventConsumerResult(entry)) {\n // EventConsumerResult: extract consumer, binding, queue, and exchange\n processedConsumers[name] = entry.consumer;\n addResource(bindings, `${name}Binding`, entry.binding, \"binding\");\n\n const queueEntry = entry.consumer.queue;\n const queueDef = extractQueue(queueEntry);\n addResource(queues, queueDef.name, queueEntry, \"queue\");\n consumerQueueEntries.push(queueEntry);\n\n addResource(exchanges, entry.binding.exchange.name, entry.binding.exchange, \"exchange\");\n\n if (queueDef.deadLetter?.exchange) {\n addResource(\n exchanges,\n queueDef.deadLetter.exchange.name,\n queueDef.deadLetter.exchange,\n \"exchange\",\n );\n }\n\n if (entry.exchangeBinding) {\n addResource(bindings, `${name}ExchangeBinding`, entry.exchangeBinding, \"binding\");\n }\n if (entry.bridgeExchange) {\n addResource(exchanges, entry.bridgeExchange.name, entry.bridgeExchange, \"exchange\");\n }\n // Source exchange (stored in entry.exchange for bridged consumers)\n if (entry.exchange) {\n addResource(exchanges, entry.exchange.name, entry.exchange, \"exchange\");\n }\n } else if (isCommandConsumerConfig(entry)) {\n // CommandConsumerConfig: extract consumer, binding, queue, and exchange\n processedConsumers[name] = entry.consumer;\n addResource(bindings, `${name}Binding`, entry.binding, \"binding\");\n\n const queueEntry = entry.consumer.queue;\n const queueDef = extractQueue(queueEntry);\n addResource(queues, queueDef.name, queueEntry, \"queue\");\n consumerQueueEntries.push(queueEntry);\n\n addResource(exchanges, entry.exchange.name, entry.exchange, \"exchange\");\n\n if (queueDef.deadLetter?.exchange) {\n addResource(\n exchanges,\n queueDef.deadLetter.exchange.name,\n queueDef.deadLetter.exchange,\n \"exchange\",\n );\n }\n } else {\n // Plain ConsumerDefinition: extract queue\n const consumer = entry as ConsumerDefinition;\n processedConsumers[name] = consumer;\n\n const queueEntry = consumer.queue;\n const queueDef = extractQueue(queueEntry);\n addResource(queues, queueDef.name, queueEntry, \"queue\");\n consumerQueueEntries.push(queueEntry);\n\n if (queueDef.deadLetter?.exchange) {\n addResource(\n exchanges,\n queueDef.deadLetter.exchange.name,\n queueDef.deadLetter.exchange,\n \"exchange\",\n );\n }\n }\n }\n\n // Auto-generate TTL-backoff retry infrastructure for queues with TTL-backoff retry mode\n for (const queueEntry of consumerQueueEntries) {\n if (isQueueWithTtlBackoffInfrastructure(queueEntry)) {\n addResource(queues, queueEntry.waitQueue.name, queueEntry.waitQueue, \"queue\");\n addResource(\n bindings,\n `${queueEntry.queue.name}WaitBinding`,\n queueEntry.waitQueueBinding,\n \"binding\",\n );\n addResource(\n bindings,\n `${queueEntry.queue.name}RetryBinding`,\n queueEntry.retryQueueBinding,\n \"binding\",\n );\n addResource(exchanges, queueEntry.waitExchange.name, queueEntry.waitExchange, \"exchange\");\n addResource(exchanges, queueEntry.retryExchange.name, queueEntry.retryExchange, \"exchange\");\n }\n }\n\n result.consumers = processedConsumers;\n }\n\n // Process rpcs section — extract each RPC's queue (and DLX if any) into the\n // contract topology. RPCs use the AMQP default exchange with the queue name\n // as routing key, so no exchange or binding declarations are needed.\n if (inputRpcs && Object.keys(inputRpcs).length > 0) {\n const processedRpcs: Record<string, RpcDefinition> = {};\n\n for (const [name, rpc] of Object.entries(inputRpcs)) {\n processedRpcs[name] = rpc;\n const queueDef = extractQueue(rpc.queue);\n addResource(queues, queueDef.name, rpc.queue, \"queue\");\n if (queueDef.deadLetter?.exchange) {\n addResource(\n exchanges,\n queueDef.deadLetter.exchange.name,\n queueDef.deadLetter.exchange,\n \"exchange\",\n );\n }\n }\n\n result.rpcs = processedRpcs;\n }\n\n result.exchanges = exchanges;\n result.queues = queues;\n result.bindings = bindings;\n\n return result as ContractOutput<TContract>;\n}\n","import type { MessageDefinition, QueueEntry, RpcDefinition } from \"../types.js\";\n\n/**\n * Define an RPC operation: a request/response pair flowing over a request\n * queue with replies routed back via RabbitMQ direct reply-to.\n *\n * RPC is bidirectional on both ends — the worker handler consumes the request\n * and produces the response; `client.call(name, request, options)` publishes\n * the request and awaits the typed response. Both sides share the same\n * definition, so request and response schemas cannot drift between them.\n *\n * Plug the result into `defineContract({ rpcs: { name: ... } })`. RPCs do not\n * appear in `publishers` or `consumers`.\n *\n * @param queue - The queue that receives RPC requests. The queue name is\n * used as the routing key on the AMQP default direct exchange.\n * @param messages.request - Schema validated against incoming request payloads\n * (server side) and outgoing requests (client side).\n * @param messages.response - Schema validated against handler return values\n * (server side) and incoming replies (client side).\n *\n * @example\n * ```typescript\n * import { defineQueue, defineMessage, defineRpc, defineContract } from '@amqp-contract/contract';\n * import { z } from 'zod';\n *\n * const calculate = defineRpc(defineQueue('rpc.calculate'), {\n * request: defineMessage(z.object({ a: z.number(), b: z.number() })),\n * response: defineMessage(z.object({ sum: z.number() })),\n * });\n *\n * const contract = defineContract({ rpcs: { calculate } });\n *\n * // Server (worker): handler returns the typed response\n * // handlers: { calculate: ({ payload }) => Future.value(Result.Ok({ sum: payload.a + payload.b })) }\n *\n * // Client: typed call with required timeout\n * // const result = await client.call('calculate', { a: 1, b: 2 }, { timeoutMs: 5_000 }).toPromise();\n * ```\n */\nexport function defineRpc<\n TRequestMessage extends MessageDefinition,\n TResponseMessage extends MessageDefinition,\n TQueue extends QueueEntry,\n>(\n queue: TQueue,\n messages: { request: TRequestMessage; response: TResponseMessage },\n): RpcDefinition<TRequestMessage, TResponseMessage, TQueue> {\n return {\n queue,\n request: messages.request,\n response: messages.response,\n };\n}\n"],"mappings":"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"}