@amqp-contract/contract 0.18.0 → 0.20.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":["isQueueWithTtlBackoffInfrastructure"],"sources":["../src/builder/exchange.ts","../src/builder/message.ts","../src/builder/binding.ts","../src/builder/queue.ts","../src/builder/publisher.ts","../src/builder/consumer.ts","../src/builder/event.ts","../src/builder/command.ts","../src/builder/contract.ts","../src/builder/ttl-backoff.ts"],"sourcesContent":["import type {\n BaseExchangeDefinition,\n DirectExchangeDefinition,\n ExchangeDefinition,\n FanoutExchangeDefinition,\n TopicExchangeDefinition,\n} from \"../types.js\";\n\n/**\n * Define a fanout exchange.\n *\n * A fanout exchange routes messages to all bound queues without considering routing keys.\n * This exchange type is ideal for broadcasting messages to multiple consumers.\n *\n * @param name - The name of the exchange\n * @param type - Must be \"fanout\"\n * @param options - Optional exchange configuration\n * @param options.durable - If true, the exchange survives broker restarts (default: false)\n * @param options.autoDelete - If true, the exchange is deleted when no queues are bound (default: false)\n * @param options.internal - If true, the exchange cannot be directly published to (default: false)\n * @param options.arguments - Additional AMQP arguments for the exchange\n * @returns A fanout exchange definition\n *\n * @example\n * ```typescript\n * const logsExchange = defineExchange('logs', 'fanout', {\n * durable: true\n * });\n * ```\n */\nexport function defineExchange<TName extends string>(\n name: TName,\n type: \"fanout\",\n options?: Omit<BaseExchangeDefinition, \"name\" | \"type\">,\n): FanoutExchangeDefinition<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 type - Must be \"direct\"\n * @param options - Optional exchange configuration\n * @param options.durable - If true, the exchange survives broker restarts (default: false)\n * @param options.autoDelete - If true, the exchange is deleted when no queues are bound (default: false)\n * @param options.internal - If true, the exchange cannot be directly published to (default: false)\n * @param options.arguments - Additional AMQP arguments for the exchange\n * @returns A direct exchange definition\n *\n * @example\n * ```typescript\n * const tasksExchange = defineExchange('tasks', 'direct', {\n * durable: true\n * });\n * ```\n */\nexport function defineExchange<TName extends string>(\n name: TName,\n type: \"direct\",\n options?: Omit<BaseExchangeDefinition, \"name\" | \"type\">,\n): DirectExchangeDefinition<TName>;\n\n/**\n * Define a topic exchange.\n *\n * A topic exchange routes messages to queues based on routing key patterns.\n * Routing keys can use wildcards: `*` matches one word, `#` matches zero or more words.\n * This exchange type is ideal for flexible message routing based on hierarchical topics.\n *\n * @param name - The name of the exchange\n * @param type - Must be \"topic\"\n * @param options - Optional exchange configuration\n * @param options.durable - If true, the exchange survives broker restarts (default: false)\n * @param options.autoDelete - If true, the exchange is deleted when no queues are bound (default: false)\n * @param options.internal - If true, the exchange cannot be directly published to (default: false)\n * @param options.arguments - Additional AMQP arguments for the exchange\n * @returns A topic exchange definition\n *\n * @example\n * ```typescript\n * const ordersExchange = defineExchange('orders', 'topic', {\n * durable: true\n * });\n * ```\n */\nexport function defineExchange<TName extends string>(\n name: TName,\n type: \"topic\",\n options?: Omit<BaseExchangeDefinition, \"name\" | \"type\">,\n): TopicExchangeDefinition<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 type - The type of exchange: \"fanout\", \"direct\", or \"topic\"\n * @param options - Optional exchange configuration\n * @returns An exchange definition\n * @internal\n */\nexport function defineExchange(\n name: string,\n type: \"fanout\" | \"direct\" | \"topic\",\n options?: Omit<BaseExchangeDefinition, \"name\" | \"type\">,\n): ExchangeDefinition {\n return {\n name,\n type,\n ...options,\n };\n}\n","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 {\n DirectExchangeDefinition,\n ExchangeBindingDefinition,\n ExchangeDefinition,\n FanoutExchangeDefinition,\n QueueBindingDefinition,\n QueueDefinition,\n QueueEntry,\n QueueWithTtlBackoffInfrastructure,\n TopicExchangeDefinition,\n} from \"../types.js\";\n\n/**\n * Type guard to check if a queue entry is a QueueWithTtlBackoffInfrastructure.\n * Duplicated here to avoid circular dependency with queue.ts.\n * @internal\n */\nfunction 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 * Extract the plain QueueDefinition from a QueueEntry.\n * Duplicated here to avoid circular dependency with queue.ts.\n * @internal\n */\nfunction extractQueueInternal(entry: QueueEntry): QueueDefinition {\n if (isQueueWithTtlBackoffInfrastructure(entry)) {\n return entry.queue;\n }\n return entry;\n}\n\n/**\n * Define a binding between a queue and a fanout exchange.\n *\n * Binds a queue to a fanout exchange to receive all messages published to the exchange.\n * Fanout exchanges ignore routing keys, so this overload doesn't require one.\n *\n * @param queue - The queue definition or queue with infrastructure to bind\n * @param exchange - The fanout exchange definition\n * @param options - Optional binding configuration\n * @param options.arguments - Additional AMQP arguments for the binding\n * @returns A queue binding definition\n *\n * @example\n * ```typescript\n * const logsQueue = defineQueue('logs-queue', { durable: true });\n * const logsExchange = defineExchange('logs', 'fanout', { durable: true });\n *\n * const binding = defineQueueBinding(logsQueue, logsExchange);\n * ```\n */\nexport function defineQueueBinding(\n queue: QueueEntry,\n exchange: FanoutExchangeDefinition,\n options?: Omit<\n Extract<QueueBindingDefinition, { exchange: FanoutExchangeDefinition }>,\n \"type\" | \"queue\" | \"exchange\" | \"routingKey\"\n >,\n): Extract<QueueBindingDefinition, { exchange: FanoutExchangeDefinition }>;\n\n/**\n * Define a binding between a queue and a direct or topic exchange.\n *\n * Binds a queue to an exchange with a specific routing key pattern.\n * Messages are only routed to the queue if the routing key matches the pattern.\n *\n * For direct exchanges: The routing key must match exactly.\n * For topic exchanges: The routing key can include wildcards:\n * - `*` matches exactly one word\n * - `#` matches zero or more words\n *\n * @param queue - The queue definition 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', { durable: true });\n * const ordersExchange = defineExchange('orders', 'topic', { durable: true });\n *\n * // Bind with exact routing key\n * const binding = defineQueueBinding(orderQueue, ordersExchange, {\n * routingKey: 'order.created'\n * });\n *\n * // Bind with wildcard pattern\n * const allOrdersBinding = defineQueueBinding(orderQueue, ordersExchange, {\n * routingKey: 'order.*' // Matches order.created, order.updated, etc.\n * });\n * ```\n */\nexport function defineQueueBinding(\n queue: 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 = extractQueueInternal(queue);\n\n if (exchange.type === \"fanout\") {\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\") {\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 source exchange.\n * Messages published to the source exchange will be forwarded to the destination exchange.\n * Fanout exchanges ignore routing keys, so this overload doesn't require one.\n *\n * @param destination - The destination exchange definition\n * @param source - The fanout source exchange definition\n * @param options - Optional binding configuration\n * @param options.arguments - Additional AMQP arguments for the binding\n * @returns An exchange binding definition\n *\n * @example\n * ```typescript\n * const sourceExchange = defineExchange('logs', 'fanout', { durable: true });\n * const destExchange = defineExchange('all-logs', 'fanout', { durable: true });\n *\n * const binding = defineExchangeBinding(destExchange, sourceExchange);\n * ```\n */\nexport function defineExchangeBinding(\n destination: ExchangeDefinition,\n source: FanoutExchangeDefinition,\n options?: Omit<\n Extract<ExchangeBindingDefinition, { source: FanoutExchangeDefinition }>,\n \"type\" | \"source\" | \"destination\" | \"routingKey\"\n >,\n): Extract<ExchangeBindingDefinition, { source: FanoutExchangeDefinition }>;\n\n/**\n * Define a binding between two exchanges (exchange-to-exchange routing).\n *\n * Binds a destination exchange to a direct or topic source exchange with a routing key pattern.\n * Messages are forwarded from source to destination only if the routing key matches the pattern.\n *\n * @param destination - The destination exchange definition\n * @param source - The direct or topic source exchange definition\n * @param options - Binding configuration (routingKey is required)\n * @param options.routingKey - The routing key pattern for message routing\n * @param options.arguments - Additional AMQP arguments for the binding\n * @returns An exchange binding definition\n *\n * @example\n * ```typescript\n * const ordersExchange = defineExchange('orders', 'topic', { durable: true });\n * const importantExchange = defineExchange('important-orders', 'topic', { durable: true });\n *\n * // Forward only high-value orders\n * const binding = defineExchangeBinding(importantExchange, ordersExchange, {\n * routingKey: 'order.high-value.*'\n * });\n * ```\n */\nexport function defineExchangeBinding(\n destination: ExchangeDefinition,\n source: DirectExchangeDefinition | TopicExchangeDefinition,\n options: Omit<\n Extract<\n ExchangeBindingDefinition,\n { source: DirectExchangeDefinition | TopicExchangeDefinition }\n >,\n \"type\" | \"source\" | \"destination\"\n >,\n): Extract<\n ExchangeBindingDefinition,\n { source: DirectExchangeDefinition | TopicExchangeDefinition }\n>;\n\n/**\n * Define a binding between two exchanges (exchange-to-exchange routing).\n *\n * This is the implementation function - use the type-specific overloads for better type safety.\n *\n * @param destination - The destination exchange definition\n * @param source - The source exchange definition\n * @param options - Optional binding configuration\n * @returns An exchange binding definition\n * @internal\n */\nexport function defineExchangeBinding(\n destination: ExchangeDefinition,\n source: ExchangeDefinition,\n options?: {\n routingKey?: string;\n arguments?: Record<string, unknown>;\n },\n): ExchangeBindingDefinition {\n if (source.type === \"fanout\") {\n return {\n type: \"exchange\",\n source,\n destination,\n ...(options?.arguments && { arguments: options.arguments }),\n } as ExchangeBindingDefinition;\n }\n\n return {\n type: \"exchange\",\n source,\n destination,\n routingKey: options?.routingKey ?? \"\",\n ...(options?.arguments && { arguments: options.arguments }),\n } as ExchangeBindingDefinition;\n}\n","import type {\n ClassicQueueDefinition,\n ClassicQueueOptions,\n DeadLetterConfig,\n DefineQueueOptions,\n ExchangeDefinition,\n ExtractQueueFromEntry,\n QueueDefinition,\n QueueEntry,\n QueueWithTtlBackoffInfrastructure,\n QuorumQueueDefinition,\n QuorumQueueOptions,\n ResolvedTtlBackoffRetryOptions,\n TtlBackoffRetryOptions,\n} from \"../types.js\";\nimport { defineQueueBindingInternal } from \"./binding.js\";\n\n/**\n * Resolve TTL-backoff retry options with defaults applied.\n * @internal\n */\nexport function resolveTtlBackoffOptions(\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 };\n}\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 and a dead letter exchange,\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 * deadLetter: { exchange: dlx },\n * retry: { mode: 'ttl-backoff' },\n * });\n *\n * if (isQueueWithTtlBackoffInfrastructure(queue)) {\n * // queue has .queue, .waitQueue, .waitQueueBinding, .mainQueueRetryBinding\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 * Extract the plain QueueDefinition from a QueueEntry.\n *\n * **Why this function exists:**\n * When you configure a queue with TTL-backoff retry and a dead letter exchange,\n * `defineQueue` (or `defineTtlBackoffQueue`) returns a wrapper object that includes\n * the main queue, wait queue, 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, deadLetter, 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, defineTtlBackoffQueue, extractQueue } from '@amqp-contract/contract';\n *\n * // TTL-backoff queue returns a wrapper\n * const orderQueue = defineTtlBackoffQueue('orders', {\n * deadLetter: { exchange: dlx },\n * 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: 'quorum-native' } });\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 * console.log(queueDef.deadLetter); // { exchange: dlx, ... }\n * ```\n *\n * @see isQueueWithTtlBackoffInfrastructure - Type guard to check if extraction is needed\n * @see defineTtlBackoffQueue - Creates queues with TTL-backoff infrastructure\n */\nexport function extractQueue<T extends QueueEntry>(entry: T): ExtractQueueFromEntry<T> {\n if (isQueueWithTtlBackoffInfrastructure(entry)) {\n return entry.queue as unknown as ExtractQueueFromEntry<T>;\n }\n return entry as unknown as ExtractQueueFromEntry<T>;\n}\n\n/**\n * Wrap a queue definition with TTL-backoff retry infrastructure.\n * @internal\n */\nfunction wrapWithTtlBackoffInfrastructure(\n queue: QueueDefinition,\n): QueueWithTtlBackoffInfrastructure {\n if (!queue.deadLetter) {\n throw new Error(\n `Queue \"${queue.name}\" does not have a dead letter exchange configured. ` +\n `TTL-backoff retry requires deadLetter to be set on the queue.`,\n );\n }\n\n const dlx = queue.deadLetter.exchange;\n const waitQueueName = `${queue.name}-wait`;\n\n // Create the wait queue - quorum for better durability\n // Wait queue uses TTL-backoff mode (infrastructure queue, not directly consumed)\n const waitQueue: QuorumQueueDefinition = {\n name: waitQueueName,\n type: \"quorum\",\n durable: queue.durable ?? true,\n deadLetter: {\n exchange: dlx,\n routingKey: queue.name, // Routes back to main queue after TTL\n },\n retry: resolveTtlBackoffOptions(undefined),\n };\n\n // Create binding for wait queue to receive failed messages\n const waitQueueBinding = defineQueueBindingInternal(waitQueue, dlx, {\n routingKey: waitQueueName,\n });\n\n // Create binding for main queue to receive retried messages\n const mainQueueRetryBinding = defineQueueBindingInternal(queue, dlx, {\n routingKey: queue.name,\n });\n\n return {\n __brand: \"QueueWithTtlBackoffInfrastructure\",\n queue,\n deadLetter: queue.deadLetter,\n waitQueue,\n waitQueueBinding,\n mainQueueRetryBinding,\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 are always durable.\n * @param options.exclusive - If true, the queue can only be used by the declaring connection. Only supported with classic queues.\n * @param options.autoDelete - If true, the queue is deleted when the last consumer unsubscribes (default: false)\n * @param options.deadLetter - Dead letter configuration for handling failed messages\n * @param options.maxPriority - Maximum priority level for priority queue (1-255, recommended: 1-10). Only supported with classic queues.\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', 'topic', { durable: true });\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 * durable: true,\n * maxPriority: 10,\n * });\n *\n * // Queue with TTL-backoff retry (returns infrastructure automatically)\n * const dlx = defineExchange('orders-dlx', 'direct', { durable: true });\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: DefineQueueOptions & { deadLetter: { exchange: TDlx } },\n): (QueueDefinition<TName> | QueueWithTtlBackoffInfrastructure<TName>) & {\n deadLetter: { exchange: TDlx };\n};\n\nexport function defineQueue<TName extends string>(\n name: TName,\n options?: DefineQueueOptions,\n): QueueDefinition<TName> | QueueWithTtlBackoffInfrastructure<TName>;\n\nexport function defineQueue(\n name: string,\n options?: DefineQueueOptions,\n): QueueDefinition | QueueWithTtlBackoffInfrastructure {\n const opts = options ?? {};\n const type = opts.type ?? \"quorum\";\n\n // Build base properties shared by both queue types\n const baseProps: {\n name: string;\n durable?: boolean;\n autoDelete?: boolean;\n deadLetter?: DeadLetterConfig;\n arguments?: Record<string, unknown>;\n } = { name };\n\n if (opts.durable !== undefined) {\n baseProps.durable = opts.durable;\n }\n\n if (opts.autoDelete !== undefined) {\n baseProps.autoDelete = opts.autoDelete;\n }\n\n if (opts.deadLetter !== undefined) {\n baseProps.deadLetter = opts.deadLetter;\n }\n\n if (opts.arguments !== undefined) {\n baseProps.arguments = opts.arguments;\n }\n\n // Build quorum queue\n if (type === \"quorum\") {\n const quorumOpts = opts as QuorumQueueOptions;\n const inputRetry = quorumOpts.retry ?? { mode: \"ttl-backoff\" as const };\n\n // Validate quorum-native retry requirements\n if (inputRetry.mode === \"quorum-native\") {\n if (quorumOpts.deliveryLimit === undefined) {\n throw new Error(\n `Queue \"${name}\" uses quorum-native retry mode but deliveryLimit is not configured. ` +\n `Quorum-native retry requires deliveryLimit to be set.`,\n );\n }\n }\n\n // Resolve retry options: apply defaults for TTL-backoff, keep quorum-native as-is\n const retry =\n inputRetry.mode === \"quorum-native\" ? inputRetry : resolveTtlBackoffOptions(inputRetry);\n\n const queueDefinition: QuorumQueueDefinition = {\n ...baseProps,\n type: \"quorum\",\n retry,\n };\n\n // Validate and add deliveryLimit\n if (quorumOpts.deliveryLimit !== undefined) {\n if (quorumOpts.deliveryLimit < 1 || !Number.isInteger(quorumOpts.deliveryLimit)) {\n throw new Error(\n `Invalid deliveryLimit: ${quorumOpts.deliveryLimit}. Must be a positive integer.`,\n );\n }\n queueDefinition.deliveryLimit = quorumOpts.deliveryLimit;\n }\n\n // If TTL-backoff retry with dead letter exchange, wrap with infrastructure\n if (retry.mode === \"ttl-backoff\" && queueDefinition.deadLetter) {\n return wrapWithTtlBackoffInfrastructure(queueDefinition);\n }\n\n return queueDefinition;\n }\n\n // Build classic queue\n const classicOpts = opts as ClassicQueueOptions;\n\n // Classic queues cannot use quorum-native retry mode\n if ((classicOpts.retry as { mode?: string } | undefined)?.mode === \"quorum-native\") {\n throw new Error(\n `Queue \"${name}\" uses quorum-native retry mode but is a classic queue. ` +\n `Quorum-native retry requires quorum queues (type: \"quorum\").`,\n );\n }\n\n // Resolve TTL-backoff options with defaults\n const retry = resolveTtlBackoffOptions(classicOpts.retry);\n\n const queueDefinition: ClassicQueueDefinition = {\n ...baseProps,\n type: \"classic\",\n retry,\n };\n\n // Add exclusive\n if (classicOpts.exclusive !== undefined) {\n queueDefinition.exclusive = classicOpts.exclusive;\n }\n\n // Validate and add maxPriority argument\n if (classicOpts.maxPriority !== undefined) {\n if (classicOpts.maxPriority < 1 || classicOpts.maxPriority > 255) {\n throw new Error(\n `Invalid maxPriority: ${classicOpts.maxPriority}. Must be between 1 and 255. Recommended range: 1-10.`,\n );\n }\n queueDefinition.arguments = {\n ...queueDefinition.arguments,\n \"x-max-priority\": classicOpts.maxPriority,\n };\n }\n\n // If TTL-backoff retry with dead letter exchange, wrap with infrastructure\n if (retry.mode === \"ttl-backoff\" && queueDefinition.deadLetter) {\n return wrapWithTtlBackoffInfrastructure(queueDefinition);\n }\n\n return queueDefinition;\n}\n\n// =============================================================================\n// Simplified Queue Configuration Helpers\n// =============================================================================\n\n/**\n * Options for creating a quorum queue with quorum-native retry.\n *\n * This simplified helper enforces the required configuration for quorum-native retry:\n * - Dead letter exchange is required (for failed messages)\n * - Delivery limit is required (for retry count)\n */\nexport type DefineQuorumQueueOptions = {\n /**\n * Dead letter configuration - required for retry support.\n * Failed messages will be sent to this exchange.\n */\n deadLetter: DeadLetterConfig;\n\n /**\n * Maximum number of delivery attempts before dead-lettering.\n * @minimum 1\n */\n deliveryLimit: number;\n\n /**\n * If true, the queue is deleted when the last consumer unsubscribes.\n * @default false\n */\n autoDelete?: boolean;\n\n /**\n * Additional AMQP arguments for advanced configuration.\n */\n arguments?: Record<string, unknown>;\n};\n\n/**\n * Create a quorum queue with quorum-native retry.\n *\n * This is a simplified helper that enforces best practices:\n * - Uses quorum queues (recommended for most use cases)\n * - Requires dead letter exchange for failed message handling\n * - Uses quorum-native retry mode (simpler than TTL-backoff)\n *\n * **When to use:**\n * - You want simple, immediate retries without exponential backoff\n * - You don't need configurable delays between retries\n * - You want the simplest retry configuration\n *\n * @param name - The queue name\n * @param options - Configuration options\n * @returns A quorum queue definition with quorum-native retry\n *\n * @example\n * ```typescript\n * const dlx = defineExchange('orders-dlx', 'direct', { durable: true });\n *\n * const orderQueue = defineQuorumQueue('order-processing', {\n * deadLetter: { exchange: dlx },\n * deliveryLimit: 3, // Retry up to 3 times\n * });\n *\n * // Use in a contract — exchanges, queues, and bindings are auto-extracted\n * const contract = defineContract({\n * publishers: { ... },\n * consumers: { processOrder: defineEventConsumer(event, orderQueue) },\n * });\n * ```\n *\n * @see defineQueue - For full queue configuration options\n * @see defineTtlBackoffQueue - For queues with exponential backoff retry\n */\nexport function defineQuorumQueue<TName extends string>(\n name: TName,\n options: DefineQuorumQueueOptions,\n): QuorumQueueDefinition<TName> {\n const { deadLetter, deliveryLimit, autoDelete, arguments: args } = options;\n\n const queueOptions: QuorumQueueOptions = {\n type: \"quorum\",\n deadLetter,\n deliveryLimit,\n retry: { mode: \"quorum-native\" },\n };\n\n if (autoDelete !== undefined) queueOptions.autoDelete = autoDelete;\n if (args !== undefined) queueOptions.arguments = args;\n\n return defineQueue(name, queueOptions) as QuorumQueueDefinition<TName>;\n}\n\n/**\n * Options for creating a queue with TTL-backoff retry.\n *\n * This simplified helper enforces the required configuration for TTL-backoff retry:\n * - Dead letter exchange is required (used for retry routing)\n * - Returns infrastructure that includes wait queue and bindings\n */\nexport type DefineTtlBackoffQueueOptions = {\n /**\n * Dead letter configuration - required for TTL-backoff retry.\n * Used for routing messages to the wait queue and back.\n */\n deadLetter: DeadLetterConfig;\n\n /**\n * Maximum retry attempts before sending to DLQ.\n * @default 3\n */\n maxRetries?: number;\n\n /**\n * Initial delay in ms before first retry.\n * @default 1000\n */\n initialDelayMs?: number;\n\n /**\n * Maximum delay in ms between retries.\n * @default 30000\n */\n maxDelayMs?: number;\n\n /**\n * Exponential backoff multiplier.\n * @default 2\n */\n backoffMultiplier?: number;\n\n /**\n * Add jitter to prevent thundering herd.\n * @default true\n */\n jitter?: boolean;\n\n /**\n * If true, the queue is deleted when the last consumer unsubscribes.\n * @default false\n */\n autoDelete?: boolean;\n\n /**\n * Additional AMQP arguments for advanced configuration.\n */\n arguments?: Record<string, unknown>;\n};\n\n/**\n * Create a queue with TTL-backoff retry (exponential backoff).\n *\n * This is a simplified helper that enforces best practices:\n * - Uses quorum queues (recommended for most use cases)\n * - Requires dead letter exchange for retry routing\n * - Uses TTL-backoff retry mode with configurable delays\n * - Automatically generates wait queue and bindings\n *\n * **When to use:**\n * - You need exponential backoff between retries\n * - You want configurable delays (initial delay, max delay, jitter)\n * - You're processing messages that may need time before retry\n *\n * **Returns:** A `QueueWithTtlBackoffInfrastructure` object that includes the\n * main queue, wait queue, and bindings. Pass this directly to `defineContract`\n * and it will be expanded automatically.\n *\n * @param name - The queue name\n * @param options - Configuration options\n * @returns A queue with TTL-backoff infrastructure\n *\n * @example\n * ```typescript\n * const dlx = defineExchange('orders-dlx', 'direct', { durable: true });\n *\n * const orderQueue = defineTtlBackoffQueue('order-processing', {\n * deadLetter: { exchange: dlx },\n * maxRetries: 5,\n * initialDelayMs: 1000, // Start with 1s delay\n * maxDelayMs: 30000, // Cap at 30s\n * });\n *\n * // Use in a contract — wait queue, bindings, and DLX are auto-extracted\n * const contract = defineContract({\n * publishers: { ... },\n * consumers: { processOrder: defineEventConsumer(event, extractQueue(orderQueue)) },\n * });\n *\n * // To access the underlying queue definition (e.g., for the queue name):\n * import { extractQueue } from '@amqp-contract/contract';\n * const queueName = extractQueue(orderQueue).name;\n * ```\n *\n * @see defineQueue - For full queue configuration options\n * @see defineQuorumQueue - For queues with quorum-native retry (simpler, immediate retries)\n * @see extractQueue - To access the underlying queue definition\n */\nexport function defineTtlBackoffQueue<TName extends string>(\n name: TName,\n options: DefineTtlBackoffQueueOptions,\n): QueueWithTtlBackoffInfrastructure<TName> {\n const {\n deadLetter,\n maxRetries,\n initialDelayMs,\n maxDelayMs,\n backoffMultiplier,\n jitter,\n autoDelete,\n arguments: args,\n } = options;\n\n // Build retry options, only including defined values\n const retryOptions: TtlBackoffRetryOptions = { mode: \"ttl-backoff\" };\n if (maxRetries !== undefined) retryOptions.maxRetries = maxRetries;\n if (initialDelayMs !== undefined) retryOptions.initialDelayMs = initialDelayMs;\n if (maxDelayMs !== undefined) retryOptions.maxDelayMs = maxDelayMs;\n if (backoffMultiplier !== undefined) retryOptions.backoffMultiplier = backoffMultiplier;\n if (jitter !== undefined) retryOptions.jitter = jitter;\n\n const queueOptions: QuorumQueueOptions = {\n type: \"quorum\",\n deadLetter,\n retry: retryOptions,\n };\n\n if (autoDelete !== undefined) queueOptions.autoDelete = autoDelete;\n if (args !== undefined) queueOptions.arguments = args;\n\n const result = defineQueue(name, queueOptions);\n\n // Since we configured TTL-backoff with a dead letter exchange, the result will\n // always be QueueWithTtlBackoffInfrastructure\n return result as QueueWithTtlBackoffInfrastructure<TName>;\n}\n","import type {\n DirectExchangeDefinition,\n ExchangeDefinition,\n FanoutExchangeDefinition,\n MessageDefinition,\n PublisherDefinition,\n TopicExchangeDefinition,\n} from \"../types.js\";\n\n/**\n * Define a message publisher for a fanout exchange.\n *\n * A publisher sends messages to an exchange. For fanout exchanges, messages are broadcast\n * to all bound queues regardless of routing key, so no routing key is required.\n *\n * The message schema is validated when publishing to ensure type safety.\n *\n * **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 exchange definition to publish to\n * @param message - The message definition with payload schema\n * @param options - Optional publisher configuration\n * @returns A publisher definition with inferred message types\n *\n * @example\n * ```typescript\n * import { z } from 'zod';\n *\n * const logsExchange = defineExchange('logs', 'fanout', { durable: true });\n * const logMessage = defineMessage(\n * z.object({\n * level: z.enum(['info', 'warn', 'error']),\n * message: z.string(),\n * timestamp: z.string().datetime(),\n * })\n * );\n *\n * const logPublisher = definePublisher(logsExchange, logMessage);\n * ```\n *\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,\n message: TMessage,\n options?: Omit<\n Extract<PublisherDefinition<TMessage>, { exchange: FanoutExchangeDefinition }>,\n \"exchange\" | \"message\" | \"routingKey\"\n >,\n): Extract<PublisherDefinition<TMessage>, { exchange: FanoutExchangeDefinition }>;\n\n/**\n * Define a message publisher for a direct or topic exchange.\n *\n * A publisher sends messages to an exchange with a specific routing key.\n * The routing key determines which queues receive the message.\n *\n * The message schema is validated when publishing to ensure type safety.\n *\n * **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', 'topic', { durable: true });\n * const orderMessage = defineMessage(\n * z.object({\n * orderId: z.string().uuid(),\n * amount: z.number().positive(),\n * }),\n * {\n * summary: 'Order created event',\n * description: 'Emitted when a new order is created'\n * }\n * );\n *\n * const orderCreatedPublisher = definePublisher(ordersExchange, orderMessage, {\n * routingKey: 'order.created'\n * });\n * ```\n *\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\") {\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\") {\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\";\nimport { extractQueue } from \"./queue.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', { durable: true });\n * const orderMessage = defineMessage(\n * z.object({\n * orderId: z.string().uuid(),\n * customerId: z.string().uuid(),\n * amount: z.number().positive(),\n * })\n * );\n *\n * const processOrderConsumer = defineConsumer(orderQueue, orderMessage);\n *\n * // Later, when creating a worker, you'll provide a handler for this consumer:\n * // const worker = await TypedAmqpWorker.create({\n * // contract,\n * // handlers: {\n * // processOrder: async (message) => {\n * // // message is automatically typed based on the schema\n * // console.log(message.orderId); // string\n * // }\n * // },\n * // connection\n * // });\n * ```\n *\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: extractQueue(queue),\n message,\n ...options,\n };\n}\n","import type { BindingPattern, RoutingKey } from \"./routing-types.js\";\nimport type {\n ConsumerDefinition,\n DirectExchangeDefinition,\n ExchangeBindingDefinition,\n ExchangeDefinition,\n ExtractDlxFromEntry,\n ExtractQueueFromEntry,\n FanoutExchangeDefinition,\n MessageDefinition,\n QueueBindingDefinition,\n QueueDefinition,\n QueueEntry,\n TopicExchangeDefinition,\n} from \"../types.js\";\nimport { defineConsumer } from \"./consumer.js\";\nimport { defineExchangeBinding, defineQueueBindingInternal } from \"./binding.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)\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 QueueDefinition = QueueDefinition,\n TDlxExchange extends ExchangeDefinition | undefined = ExchangeDefinition | undefined,\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 dead letter exchange from the queue, if configured */\n deadLetterExchange: TDlxExchange;\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 * @returns An event publisher configuration\n *\n * @example\n * ```typescript\n * const logsExchange = defineExchange('logs', 'fanout', { durable: true });\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>(exchange: TExchange, message: TMessage): 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', 'direct', { durable: true });\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', 'topic', { durable: true });\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 * @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 ExtractQueueFromEntry<TQueueEntry>,\n ExtractDlxFromEntry<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 * @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 ExtractQueueFromEntry<TQueueEntry>,\n ExtractDlxFromEntry<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 * @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 ExtractQueueFromEntry<TQueueEntry>,\n ExtractDlxFromEntry<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 * @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<\n TMessage,\n TExchange,\n ExtractQueueFromEntry<TQueueEntry>,\n ExtractDlxFromEntry<TQueueEntry>\n>;\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 * @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<\n TMessage,\n TExchange,\n ExtractQueueFromEntry<TQueueEntry>,\n ExtractDlxFromEntry<TQueueEntry>\n>;\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 * @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<\n TMessage,\n TExchange,\n ExtractQueueFromEntry<TQueueEntry>,\n ExtractDlxFromEntry<TQueueEntry>\n>;\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\"\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: consumer.queue,\n deadLetterExchange: consumer.queue.deadLetter?.exchange,\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: consumer.queue,\n deadLetterExchange: consumer.queue.deadLetter?.exchange,\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 { BindingPattern, RoutingKey } from \"./routing-types.js\";\nimport type {\n ConsumerDefinition,\n DirectExchangeDefinition,\n ExchangeBindingDefinition,\n ExchangeDefinition,\n ExtractDlxFromEntry,\n ExtractQueueFromEntry,\n FanoutExchangeDefinition,\n MessageDefinition,\n PublisherDefinition,\n QueueBindingDefinition,\n QueueDefinition,\n QueueEntry,\n TopicExchangeDefinition,\n} from \"../types.js\";\nimport { defineConsumer } from \"./consumer.js\";\nimport { definePublisherInternal } from \"./publisher.js\";\nimport { defineExchangeBinding, defineQueueBindingInternal } from \"./binding.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)\n */\nexport type CommandConsumerConfig<\n TMessage extends MessageDefinition,\n TExchange extends ExchangeDefinition,\n TRoutingKey extends string | undefined = undefined,\n TQueue extends QueueDefinition = QueueDefinition,\n TDlxExchange extends ExchangeDefinition | undefined = ExchangeDefinition | undefined,\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 dead letter exchange from the queue, if configured */\n deadLetterExchange: TDlxExchange;\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 * @returns A command consumer configuration\n *\n * @example\n * ```typescript\n * const tasksExchange = defineExchange('tasks', 'fanout', { durable: true });\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): CommandConsumerConfig<\n TMessage,\n TExchange,\n undefined,\n ExtractQueueFromEntry<TQueueEntry>,\n ExtractDlxFromEntry<TQueueEntry>\n>;\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', 'direct', { durable: true });\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<\n TMessage,\n TExchange,\n TRoutingKey,\n ExtractQueueFromEntry<TQueueEntry>,\n ExtractDlxFromEntry<TQueueEntry>\n>;\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', 'topic', { durable: true });\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<\n TMessage,\n TExchange,\n TRoutingKey,\n ExtractQueueFromEntry<TQueueEntry>,\n ExtractDlxFromEntry<TQueueEntry>\n>;\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: consumer.queue,\n deadLetterExchange: consumer.queue.deadLetter?.exchange,\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\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 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 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 publisher 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\"\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 BindingDefinition,\n ConsumerDefinition,\n ContractDefinition,\n ContractDefinitionInput,\n ContractOutput,\n ExchangeDefinition,\n PublisherDefinition,\n QueueDefinition,\n QuorumQueueDefinition,\n} from \"../types.js\";\nimport { isEventConsumerResult, isEventPublisherConfig } from \"./event.js\";\nimport { definePublisherInternal } from \"./publisher.js\";\nimport { isBridgedPublisherConfig, isCommandConsumerConfig } from \"./command.js\";\nimport { defineQueueBindingInternal } from \"./binding.js\";\nimport { resolveTtlBackoffOptions } from \"./queue.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', 'topic', { durable: true });\n * const dlx = defineExchange('orders-dlx', 'direct', { durable: true });\n * const orderQueue = defineQueue('order-processing', {\n * deadLetter: { exchange: dlx },\n * retry: { mode: 'quorum-native' },\n * deliveryLimit: 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 } = definition;\n const result: ContractDefinition = {\n exchanges: {},\n queues: {},\n bindings: {},\n publishers: {},\n consumers: {},\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, QueueDefinition> = {};\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 queues[queueEntry.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 (queueEntry.deadLetter?.exchange) {\n exchanges[queueEntry.deadLetter.exchange.name] = queueEntry.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 queues[queueEntry.name] = queueEntry;\n\n // Extract exchange\n exchanges[entry.exchange.name] = entry.exchange;\n\n // Extract dead letter exchange if present\n if (queueEntry.deadLetter?.exchange) {\n exchanges[queueEntry.deadLetter.exchange.name] = queueEntry.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 queues[queueEntry.name] = queueEntry;\n\n // Extract dead letter exchange if present\n if (queueEntry.deadLetter?.exchange) {\n exchanges[queueEntry.deadLetter.exchange.name] = queueEntry.deadLetter.exchange;\n }\n }\n }\n\n // Auto-generate TTL-backoff retry infrastructure for queues with retry.mode === \"ttl-backoff\" and deadLetter\n for (const queue of Object.values(queues) as QueueDefinition[]) {\n if (queue.retry?.mode === \"ttl-backoff\" && queue.deadLetter) {\n const dlx = queue.deadLetter.exchange;\n const waitQueueName = `${queue.name}-wait`;\n\n // Create wait queue (quorum for durability)\n const waitQueue: QuorumQueueDefinition = {\n name: waitQueueName,\n type: \"quorum\",\n durable: queue.durable ?? true,\n deadLetter: {\n exchange: dlx,\n routingKey: queue.name,\n },\n retry: resolveTtlBackoffOptions(undefined),\n };\n queues[waitQueueName] = waitQueue;\n\n // Binding: DLX → wait queue (receives failed messages)\n consumerBindings[`${queue.name}WaitBinding`] = defineQueueBindingInternal(waitQueue, dlx, {\n routingKey: waitQueueName,\n });\n\n // Binding: DLX → main queue (retried messages after TTL expires)\n consumerBindings[`${queue.name}RetryBinding`] = defineQueueBindingInternal(queue, dlx, {\n routingKey: queue.name,\n });\n\n // Ensure DLX is in exchanges\n exchanges[dlx.name] = dlx;\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 return result as ContractOutput<TContract>;\n}\n","import type { QueueBindingDefinition, QueueDefinition, QueueEntry } from \"../types.js\";\nimport { defineQueue, extractQueue } from \"./queue.js\";\nimport { defineQueueBindingInternal } from \"./binding.js\";\n\n/**\n * Result type for TTL-backoff retry infrastructure builder.\n *\n * Contains the wait queue and bindings needed for TTL-backoff retry.\n */\nexport type TtlBackoffRetryInfrastructure = {\n /**\n * The wait queue for holding messages during backoff delay.\n * This is a classic queue with a dead letter exchange pointing back to the main queue.\n */\n waitQueue: QueueDefinition;\n /**\n * Binding that routes failed messages to the wait queue.\n */\n waitQueueBinding: QueueBindingDefinition;\n /**\n * Binding that routes retried messages back to the main queue.\n */\n mainQueueRetryBinding: QueueBindingDefinition;\n};\n\n/**\n * Create TTL-backoff retry infrastructure for a queue.\n *\n * This builder helper generates the wait queue 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 DLX with routing key `{queueName}-wait`\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 DLX with routing key `{queueName}`\n * 4. The main queue receives the retried message via its binding to the DLX\n *\n * @param queue - The main queue definition (must have deadLetter configured)\n * @param options - Optional configuration for the wait queue\n * @param options.waitQueueDurable - Whether the wait queue should be durable (default: same as main queue)\n * @returns TTL-backoff retry infrastructure containing wait queue and bindings\n * @throws {Error} If the queue does not have a dead letter exchange configured\n *\n * @example\n * ```typescript\n * const dlx = defineExchange('orders-dlx', 'direct', { durable: true });\n * const orderQueue = defineQueue('order-processing', {\n * type: 'quorum',\n * deadLetter: { exchange: dlx },\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, extractQueue(orderQueue)) },\n * });\n * // contract.queues includes the wait queue, contract.bindings includes retry bindings\n *\n * // Or generate manually for advanced use cases:\n * const retryInfra = defineTtlBackoffRetryInfrastructure(orderQueue);\n * ```\n */\nexport function defineTtlBackoffRetryInfrastructure(\n queueEntry: QueueEntry,\n options?: {\n waitQueueDurable?: boolean;\n },\n): TtlBackoffRetryInfrastructure {\n const queue = extractQueue(queueEntry);\n if (!queue.deadLetter) {\n throw new Error(\n `Queue \"${queue.name}\" does not have a dead letter exchange configured. ` +\n `TTL-backoff retry requires deadLetter to be set on the queue.`,\n );\n }\n\n const dlx = queue.deadLetter.exchange;\n const waitQueueName = `${queue.name}-wait`;\n\n // Create the wait queue - quorum for better durability\n // Wait queue uses default TTL-backoff retry (infrastructure queue, not directly consumed)\n const waitQueue = defineQueue(waitQueueName, {\n type: \"quorum\",\n durable: options?.waitQueueDurable ?? queue.durable ?? true,\n deadLetter: {\n exchange: dlx,\n routingKey: queue.name, // Routes back to main queue after TTL\n },\n }) as QueueDefinition;\n\n // Create binding for wait queue to receive failed messages\n const waitQueueBinding = defineQueueBindingInternal(waitQueue, dlx, {\n routingKey: waitQueueName,\n });\n\n // Create binding for main queue to receive retried messages\n const mainQueueRetryBinding = defineQueueBindingInternal(queue, dlx, {\n routingKey: queue.name,\n });\n\n return {\n waitQueue,\n waitQueueBinding,\n mainQueueRetryBinding,\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":["isQueueWithTtlBackoffInfrastructure","isQueueWithTtlBackoffInfrastructureImpl"],"sources":["../src/builder/exchange.ts","../src/builder/message.ts","../src/builder/queue-utils.ts","../src/builder/binding.ts","../src/builder/queue.ts","../src/builder/publisher.ts","../src/builder/consumer.ts","../src/builder/event.ts","../src/builder/command.ts","../src/builder/contract.ts","../src/builder/ttl-backoff.ts"],"sourcesContent":["import type {\n BaseExchangeDefinition,\n DirectExchangeDefinition,\n ExchangeDefinition,\n FanoutExchangeDefinition,\n TopicExchangeDefinition,\n} from \"../types.js\";\n\n/**\n * Define a fanout exchange.\n *\n * A fanout exchange routes messages to all bound queues without considering routing keys.\n * This exchange type is ideal for broadcasting messages to multiple consumers.\n *\n * @param name - The name of the exchange\n * @param type - Must be \"fanout\"\n * @param options - Optional exchange configuration\n * @param options.durable - If true, the exchange survives broker restarts (default: false)\n * @param options.autoDelete - If true, the exchange is deleted when no queues are bound (default: false)\n * @param options.internal - If true, the exchange cannot be directly published to (default: false)\n * @param options.arguments - Additional AMQP arguments for the exchange\n * @returns A fanout exchange definition\n *\n * @example\n * ```typescript\n * const logsExchange = defineExchange('logs', 'fanout', {\n * durable: true\n * });\n * ```\n */\nexport function defineExchange<TName extends string>(\n name: TName,\n type: \"fanout\",\n options?: Omit<BaseExchangeDefinition, \"name\" | \"type\">,\n): FanoutExchangeDefinition<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 type - Must be \"direct\"\n * @param options - Optional exchange configuration\n * @param options.durable - If true, the exchange survives broker restarts (default: false)\n * @param options.autoDelete - If true, the exchange is deleted when no queues are bound (default: false)\n * @param options.internal - If true, the exchange cannot be directly published to (default: false)\n * @param options.arguments - Additional AMQP arguments for the exchange\n * @returns A direct exchange definition\n *\n * @example\n * ```typescript\n * const tasksExchange = defineExchange('tasks', 'direct', {\n * durable: true\n * });\n * ```\n */\nexport function defineExchange<TName extends string>(\n name: TName,\n type: \"direct\",\n options?: Omit<BaseExchangeDefinition, \"name\" | \"type\">,\n): DirectExchangeDefinition<TName>;\n\n/**\n * Define a topic exchange.\n *\n * A topic exchange routes messages to queues based on routing key patterns.\n * Routing keys can use wildcards: `*` matches one word, `#` matches zero or more words.\n * This exchange type is ideal for flexible message routing based on hierarchical topics.\n *\n * @param name - The name of the exchange\n * @param type - Must be \"topic\"\n * @param options - Optional exchange configuration\n * @param options.durable - If true, the exchange survives broker restarts (default: false)\n * @param options.autoDelete - If true, the exchange is deleted when no queues are bound (default: false)\n * @param options.internal - If true, the exchange cannot be directly published to (default: false)\n * @param options.arguments - Additional AMQP arguments for the exchange\n * @returns A topic exchange definition\n *\n * @example\n * ```typescript\n * const ordersExchange = defineExchange('orders', 'topic', {\n * durable: true\n * });\n * ```\n */\nexport function defineExchange<TName extends string>(\n name: TName,\n type: \"topic\",\n options?: Omit<BaseExchangeDefinition, \"name\" | \"type\">,\n): TopicExchangeDefinition<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 type - The type of exchange: \"fanout\", \"direct\", or \"topic\"\n * @param options - Optional exchange configuration\n * @returns An exchange definition\n * @internal\n */\nexport function defineExchange(\n name: string,\n type: \"fanout\" | \"direct\" | \"topic\",\n options?: Omit<BaseExchangeDefinition, \"name\" | \"type\">,\n): ExchangeDefinition {\n return {\n name,\n type,\n ...options,\n };\n}\n","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 { QueueDefinition, QueueEntry, QueueWithTtlBackoffInfrastructure } from \"../types.js\";\n\n/**\n * Type guard to check if a queue entry is a QueueWithTtlBackoffInfrastructure.\n * @internal\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 * Extract the plain QueueDefinition from a QueueEntry.\n * @internal\n */\nexport function extractQueueFromEntry(entry: QueueEntry): QueueDefinition {\n if (isQueueWithTtlBackoffInfrastructure(entry)) {\n return entry.queue;\n }\n return entry;\n}\n","import type {\n DirectExchangeDefinition,\n ExchangeBindingDefinition,\n ExchangeDefinition,\n FanoutExchangeDefinition,\n QueueBindingDefinition,\n QueueEntry,\n TopicExchangeDefinition,\n} from \"../types.js\";\nimport { extractQueueFromEntry } from \"./queue-utils.js\";\n\n/**\n * Define a binding between a queue and a fanout exchange.\n *\n * Binds a queue to a fanout exchange to receive all messages published to the exchange.\n * Fanout exchanges ignore routing keys, so this overload doesn't require one.\n *\n * @param queue - The queue definition or queue with infrastructure to bind\n * @param exchange - The fanout exchange definition\n * @param options - Optional binding configuration\n * @param options.arguments - Additional AMQP arguments for the binding\n * @returns A queue binding definition\n *\n * @example\n * ```typescript\n * const logsQueue = defineQueue('logs-queue', { durable: true });\n * const logsExchange = defineExchange('logs', 'fanout', { durable: true });\n *\n * const binding = defineQueueBinding(logsQueue, logsExchange);\n * ```\n */\nexport function defineQueueBinding(\n queue: QueueEntry,\n exchange: FanoutExchangeDefinition,\n options?: Omit<\n Extract<QueueBindingDefinition, { exchange: FanoutExchangeDefinition }>,\n \"type\" | \"queue\" | \"exchange\" | \"routingKey\"\n >,\n): Extract<QueueBindingDefinition, { exchange: FanoutExchangeDefinition }>;\n\n/**\n * Define a binding between a queue and a direct or topic exchange.\n *\n * Binds a queue to an exchange with a specific routing key pattern.\n * Messages are only routed to the queue if the routing key matches the pattern.\n *\n * For direct exchanges: The routing key must match exactly.\n * For topic exchanges: The routing key can include wildcards:\n * - `*` matches exactly one word\n * - `#` matches zero or more words\n *\n * @param queue - The queue definition 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', { durable: true });\n * const ordersExchange = defineExchange('orders', 'topic', { durable: true });\n *\n * // Bind with exact routing key\n * const binding = defineQueueBinding(orderQueue, ordersExchange, {\n * routingKey: 'order.created'\n * });\n *\n * // Bind with wildcard pattern\n * const allOrdersBinding = defineQueueBinding(orderQueue, ordersExchange, {\n * routingKey: 'order.*' // Matches order.created, order.updated, etc.\n * });\n * ```\n */\nexport function defineQueueBinding(\n queue: 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 = extractQueueFromEntry(queue);\n\n if (exchange.type === \"fanout\") {\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\") {\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 source exchange.\n * Messages published to the source exchange will be forwarded to the destination exchange.\n * Fanout exchanges ignore routing keys, so this overload doesn't require one.\n *\n * @param destination - The destination exchange definition\n * @param source - The fanout source exchange definition\n * @param options - Optional binding configuration\n * @param options.arguments - Additional AMQP arguments for the binding\n * @returns An exchange binding definition\n *\n * @example\n * ```typescript\n * const sourceExchange = defineExchange('logs', 'fanout', { durable: true });\n * const destExchange = defineExchange('all-logs', 'fanout', { durable: true });\n *\n * const binding = defineExchangeBinding(destExchange, sourceExchange);\n * ```\n */\nexport function defineExchangeBinding(\n destination: ExchangeDefinition,\n source: FanoutExchangeDefinition,\n options?: Omit<\n Extract<ExchangeBindingDefinition, { source: FanoutExchangeDefinition }>,\n \"type\" | \"source\" | \"destination\" | \"routingKey\"\n >,\n): Extract<ExchangeBindingDefinition, { source: FanoutExchangeDefinition }>;\n\n/**\n * Define a binding between two exchanges (exchange-to-exchange routing).\n *\n * Binds a destination exchange to a direct or topic source exchange with a routing key pattern.\n * Messages are forwarded from source to destination only if the routing key matches the pattern.\n *\n * @param destination - The destination exchange definition\n * @param source - The direct or topic source exchange definition\n * @param options - Binding configuration (routingKey is required)\n * @param options.routingKey - The routing key pattern for message routing\n * @param options.arguments - Additional AMQP arguments for the binding\n * @returns An exchange binding definition\n *\n * @example\n * ```typescript\n * const ordersExchange = defineExchange('orders', 'topic', { durable: true });\n * const importantExchange = defineExchange('important-orders', 'topic', { durable: true });\n *\n * // Forward only high-value orders\n * const binding = defineExchangeBinding(importantExchange, ordersExchange, {\n * routingKey: 'order.high-value.*'\n * });\n * ```\n */\nexport function defineExchangeBinding(\n destination: ExchangeDefinition,\n source: DirectExchangeDefinition | TopicExchangeDefinition,\n options: Omit<\n Extract<\n ExchangeBindingDefinition,\n { source: DirectExchangeDefinition | TopicExchangeDefinition }\n >,\n \"type\" | \"source\" | \"destination\"\n >,\n): Extract<\n ExchangeBindingDefinition,\n { source: DirectExchangeDefinition | TopicExchangeDefinition }\n>;\n\n/**\n * Define a binding between two exchanges (exchange-to-exchange routing).\n *\n * This is the implementation function - use the type-specific overloads for better type safety.\n *\n * @param destination - The destination exchange definition\n * @param source - The source exchange definition\n * @param options - Optional binding configuration\n * @returns An exchange binding definition\n * @internal\n */\nexport function defineExchangeBinding(\n destination: ExchangeDefinition,\n source: ExchangeDefinition,\n options?: {\n routingKey?: string;\n arguments?: Record<string, unknown>;\n },\n): ExchangeBindingDefinition {\n if (source.type === \"fanout\") {\n return {\n type: \"exchange\",\n source,\n destination,\n ...(options?.arguments && { arguments: options.arguments }),\n } as ExchangeBindingDefinition;\n }\n\n return {\n type: \"exchange\",\n source,\n destination,\n routingKey: options?.routingKey ?? \"\",\n ...(options?.arguments && { arguments: options.arguments }),\n } as ExchangeBindingDefinition;\n}\n","import type {\n ClassicQueueDefinition,\n ClassicQueueOptions,\n DeadLetterConfig,\n DefineQueueOptions,\n ExchangeDefinition,\n ExtractQueueFromEntry,\n QueueBindingDefinition,\n QueueDefinition,\n QueueEntry,\n QueueWithTtlBackoffInfrastructure,\n QuorumQueueDefinition,\n QuorumQueueOptions,\n ResolvedTtlBackoffRetryOptions,\n TtlBackoffRetryOptions,\n} from \"../types.js\";\nimport { defineQueueBindingInternal } from \"./binding.js\";\nimport {\n isQueueWithTtlBackoffInfrastructure as isQueueWithTtlBackoffInfrastructureImpl,\n extractQueueFromEntry,\n} from \"./queue-utils.js\";\n\n/**\n * Resolve TTL-backoff retry options with defaults applied.\n * @internal\n */\nexport function resolveTtlBackoffOptions(\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 };\n}\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 and a dead letter exchange,\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 * deadLetter: { exchange: dlx },\n * retry: { mode: 'ttl-backoff' },\n * });\n *\n * if (isQueueWithTtlBackoffInfrastructure(queue)) {\n * // queue has .queue, .waitQueue, .waitQueueBinding, .mainQueueRetryBinding\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 isQueueWithTtlBackoffInfrastructureImpl(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 and a dead letter exchange,\n * `defineQueue` (or `defineTtlBackoffQueue`) returns a wrapper object that includes\n * the main queue, wait queue, 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, deadLetter, 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, defineTtlBackoffQueue, extractQueue } from '@amqp-contract/contract';\n *\n * // TTL-backoff queue returns a wrapper\n * const orderQueue = defineTtlBackoffQueue('orders', {\n * deadLetter: { exchange: dlx },\n * 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: 'quorum-native' } });\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 * console.log(queueDef.deadLetter); // { exchange: dlx, ... }\n * ```\n *\n * @see isQueueWithTtlBackoffInfrastructure - Type guard to check if extraction is needed\n * @see defineTtlBackoffQueue - Creates queues with TTL-backoff infrastructure\n */\nexport function extractQueue<T extends QueueEntry>(entry: T): ExtractQueueFromEntry<T> {\n return extractQueueFromEntry(entry) as ExtractQueueFromEntry<T>;\n}\n\n/**\n * Create TTL-backoff retry infrastructure (wait queue + bindings) for a queue.\n * @internal\n */\nexport function createTtlBackoffInfrastructure(queue: QueueDefinition): {\n waitQueue: QuorumQueueDefinition;\n waitQueueBinding: QueueBindingDefinition;\n mainQueueRetryBinding: QueueBindingDefinition;\n} {\n if (!queue.deadLetter) {\n throw new Error(\n `Queue \"${queue.name}\" does not have a dead letter exchange configured. ` +\n `TTL-backoff retry requires deadLetter to be set on the queue.`,\n );\n }\n\n const dlx = queue.deadLetter.exchange;\n const waitQueueName = `${queue.name}-wait`;\n\n // Create the wait queue - quorum for better durability\n // Wait queue uses TTL-backoff mode (infrastructure queue, not directly consumed)\n const waitQueue: QuorumQueueDefinition = {\n name: waitQueueName,\n type: \"quorum\",\n durable: queue.durable ?? true,\n deadLetter: {\n exchange: dlx,\n routingKey: queue.name, // Routes back to main queue after TTL\n },\n retry: resolveTtlBackoffOptions(undefined),\n };\n\n // Create binding for wait queue to receive failed messages\n const waitQueueBinding = defineQueueBindingInternal(waitQueue, dlx, {\n routingKey: waitQueueName,\n });\n\n // Create binding for main queue to receive retried messages\n const mainQueueRetryBinding = defineQueueBindingInternal(queue, dlx, {\n routingKey: queue.name,\n });\n\n return { waitQueue, waitQueueBinding, mainQueueRetryBinding };\n}\n\n/**\n * Wrap a queue definition with TTL-backoff retry infrastructure.\n * @internal\n */\nfunction wrapWithTtlBackoffInfrastructure(\n queue: QueueDefinition,\n): QueueWithTtlBackoffInfrastructure {\n const infra = createTtlBackoffInfrastructure(queue);\n\n return {\n __brand: \"QueueWithTtlBackoffInfrastructure\",\n queue,\n deadLetter: queue.deadLetter!,\n ...infra,\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 are always durable.\n * @param options.exclusive - If true, the queue can only be used by the declaring connection. Only supported with classic queues.\n * @param options.autoDelete - If true, the queue is deleted when the last consumer unsubscribes (default: false)\n * @param options.deadLetter - Dead letter configuration for handling failed messages\n * @param options.maxPriority - Maximum priority level for priority queue (1-255, recommended: 1-10). Only supported with classic queues.\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', 'topic', { durable: true });\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 * durable: true,\n * maxPriority: 10,\n * });\n *\n * // Queue with TTL-backoff retry (returns infrastructure automatically)\n * const dlx = defineExchange('orders-dlx', 'direct', { durable: true });\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: DefineQueueOptions & { deadLetter: { exchange: TDlx } },\n): (QueueDefinition<TName> | QueueWithTtlBackoffInfrastructure<TName>) & {\n deadLetter: { exchange: TDlx };\n};\n\nexport function defineQueue<TName extends string>(\n name: TName,\n options?: DefineQueueOptions,\n): QueueDefinition<TName> | QueueWithTtlBackoffInfrastructure<TName>;\n\nexport function defineQueue(\n name: string,\n options?: DefineQueueOptions,\n): QueueDefinition | QueueWithTtlBackoffInfrastructure {\n const opts = options ?? {};\n const type = opts.type ?? \"quorum\";\n\n // Build base properties shared by both queue types\n const baseProps: {\n name: string;\n durable?: boolean;\n autoDelete?: boolean;\n deadLetter?: DeadLetterConfig;\n arguments?: Record<string, unknown>;\n } = { name };\n\n if (opts.durable !== undefined) {\n baseProps.durable = opts.durable;\n }\n\n if (opts.autoDelete !== undefined) {\n baseProps.autoDelete = opts.autoDelete;\n }\n\n if (opts.deadLetter !== undefined) {\n baseProps.deadLetter = opts.deadLetter;\n }\n\n if (opts.arguments !== undefined) {\n baseProps.arguments = opts.arguments;\n }\n\n // Build quorum queue\n if (type === \"quorum\") {\n const quorumOpts = opts as QuorumQueueOptions;\n const inputRetry = quorumOpts.retry ?? { mode: \"ttl-backoff\" as const };\n\n // Validate quorum-native retry requirements\n if (inputRetry.mode === \"quorum-native\") {\n if (quorumOpts.deliveryLimit === undefined) {\n throw new Error(\n `Queue \"${name}\" uses quorum-native retry mode but deliveryLimit is not configured. ` +\n `Quorum-native retry requires deliveryLimit to be set.`,\n );\n }\n }\n\n // Resolve retry options: apply defaults for TTL-backoff, keep quorum-native as-is\n const retry =\n inputRetry.mode === \"quorum-native\" ? inputRetry : resolveTtlBackoffOptions(inputRetry);\n\n const queueDefinition: QuorumQueueDefinition = {\n ...baseProps,\n type: \"quorum\",\n retry,\n };\n\n // Validate and add deliveryLimit\n if (quorumOpts.deliveryLimit !== undefined) {\n if (quorumOpts.deliveryLimit < 1 || !Number.isInteger(quorumOpts.deliveryLimit)) {\n throw new Error(\n `Invalid deliveryLimit: ${quorumOpts.deliveryLimit}. Must be a positive integer.`,\n );\n }\n queueDefinition.deliveryLimit = quorumOpts.deliveryLimit;\n }\n\n // If TTL-backoff retry with dead letter exchange, wrap with infrastructure\n if (retry.mode === \"ttl-backoff\" && queueDefinition.deadLetter) {\n return wrapWithTtlBackoffInfrastructure(queueDefinition);\n }\n\n return queueDefinition;\n }\n\n // Build classic queue\n const classicOpts = opts as ClassicQueueOptions;\n\n // Classic queues cannot use quorum-native retry mode\n if ((classicOpts.retry as { mode?: string } | undefined)?.mode === \"quorum-native\") {\n throw new Error(\n `Queue \"${name}\" uses quorum-native retry mode but is a classic queue. ` +\n `Quorum-native retry requires quorum queues (type: \"quorum\").`,\n );\n }\n\n // Resolve TTL-backoff options with defaults\n const retry = resolveTtlBackoffOptions(classicOpts.retry);\n\n const queueDefinition: ClassicQueueDefinition = {\n ...baseProps,\n type: \"classic\",\n retry,\n };\n\n // Add exclusive\n if (classicOpts.exclusive !== undefined) {\n queueDefinition.exclusive = classicOpts.exclusive;\n }\n\n // Validate and add maxPriority argument\n if (classicOpts.maxPriority !== undefined) {\n if (classicOpts.maxPriority < 1 || classicOpts.maxPriority > 255) {\n throw new Error(\n `Invalid maxPriority: ${classicOpts.maxPriority}. Must be between 1 and 255. Recommended range: 1-10.`,\n );\n }\n queueDefinition.arguments = {\n ...queueDefinition.arguments,\n \"x-max-priority\": classicOpts.maxPriority,\n };\n }\n\n // If TTL-backoff retry with dead letter exchange, wrap with infrastructure\n if (retry.mode === \"ttl-backoff\" && queueDefinition.deadLetter) {\n return wrapWithTtlBackoffInfrastructure(queueDefinition);\n }\n\n return queueDefinition;\n}\n\n// =============================================================================\n// Simplified Queue Configuration Helpers\n// =============================================================================\n\n/**\n * Options for creating a quorum queue with quorum-native retry.\n *\n * This simplified helper enforces the required configuration for quorum-native retry:\n * - Dead letter exchange is required (for failed messages)\n * - Delivery limit is required (for retry count)\n */\nexport type DefineQuorumQueueOptions = {\n /**\n * Dead letter configuration - required for retry support.\n * Failed messages will be sent to this exchange.\n */\n deadLetter: DeadLetterConfig;\n\n /**\n * Maximum number of delivery attempts before dead-lettering.\n * @minimum 1\n */\n deliveryLimit: number;\n\n /**\n * If true, the queue is deleted when the last consumer unsubscribes.\n * @default false\n */\n autoDelete?: boolean;\n\n /**\n * Additional AMQP arguments for advanced configuration.\n */\n arguments?: Record<string, unknown>;\n};\n\n/**\n * Create a quorum queue with quorum-native retry.\n *\n * This is a simplified helper that enforces best practices:\n * - Uses quorum queues (recommended for most use cases)\n * - Requires dead letter exchange for failed message handling\n * - Uses quorum-native retry mode (simpler than TTL-backoff)\n *\n * **When to use:**\n * - You want simple, immediate retries without exponential backoff\n * - You don't need configurable delays between retries\n * - You want the simplest retry configuration\n *\n * @param name - The queue name\n * @param options - Configuration options\n * @returns A quorum queue definition with quorum-native retry\n *\n * @example\n * ```typescript\n * const dlx = defineExchange('orders-dlx', 'direct', { durable: true });\n *\n * const orderQueue = defineQuorumQueue('order-processing', {\n * deadLetter: { exchange: dlx },\n * deliveryLimit: 3, // Retry up to 3 times\n * });\n *\n * // Use in a contract — exchanges, queues, and bindings are auto-extracted\n * const contract = defineContract({\n * publishers: { ... },\n * consumers: { processOrder: defineEventConsumer(event, orderQueue) },\n * });\n * ```\n *\n * @see defineQueue - For full queue configuration options\n * @see defineTtlBackoffQueue - For queues with exponential backoff retry\n */\nexport function defineQuorumQueue<TName extends string>(\n name: TName,\n options: DefineQuorumQueueOptions,\n): QuorumQueueDefinition<TName> {\n const { deadLetter, deliveryLimit, autoDelete, arguments: args } = options;\n\n const queueOptions: QuorumQueueOptions = {\n type: \"quorum\",\n deadLetter,\n deliveryLimit,\n retry: { mode: \"quorum-native\" },\n };\n\n if (autoDelete !== undefined) queueOptions.autoDelete = autoDelete;\n if (args !== undefined) queueOptions.arguments = args;\n\n return defineQueue(name, queueOptions) as QuorumQueueDefinition<TName>;\n}\n\n/**\n * Options for creating a queue with TTL-backoff retry.\n *\n * This simplified helper enforces the required configuration for TTL-backoff retry:\n * - Dead letter exchange is required (used for retry routing)\n * - Returns infrastructure that includes wait queue and bindings\n */\nexport type DefineTtlBackoffQueueOptions = {\n /**\n * Dead letter configuration - required for TTL-backoff retry.\n * Used for routing messages to the wait queue and back.\n */\n deadLetter: DeadLetterConfig;\n\n /**\n * Maximum retry attempts before sending to DLQ.\n * @default 3\n */\n maxRetries?: number;\n\n /**\n * Initial delay in ms before first retry.\n * @default 1000\n */\n initialDelayMs?: number;\n\n /**\n * Maximum delay in ms between retries.\n * @default 30000\n */\n maxDelayMs?: number;\n\n /**\n * Exponential backoff multiplier.\n * @default 2\n */\n backoffMultiplier?: number;\n\n /**\n * Add jitter to prevent thundering herd.\n * @default true\n */\n jitter?: boolean;\n\n /**\n * If true, the queue is deleted when the last consumer unsubscribes.\n * @default false\n */\n autoDelete?: boolean;\n\n /**\n * Additional AMQP arguments for advanced configuration.\n */\n arguments?: Record<string, unknown>;\n};\n\n/**\n * Create a queue with TTL-backoff retry (exponential backoff).\n *\n * This is a simplified helper that enforces best practices:\n * - Uses quorum queues (recommended for most use cases)\n * - Requires dead letter exchange for retry routing\n * - Uses TTL-backoff retry mode with configurable delays\n * - Automatically generates wait queue and bindings\n *\n * **When to use:**\n * - You need exponential backoff between retries\n * - You want configurable delays (initial delay, max delay, jitter)\n * - You're processing messages that may need time before retry\n *\n * **Returns:** A `QueueWithTtlBackoffInfrastructure` object that includes the\n * main queue, wait queue, and bindings. Pass this directly to `defineContract`\n * and it will be expanded automatically.\n *\n * @param name - The queue name\n * @param options - Configuration options\n * @returns A queue with TTL-backoff infrastructure\n *\n * @example\n * ```typescript\n * const dlx = defineExchange('orders-dlx', 'direct', { durable: true });\n *\n * const orderQueue = defineTtlBackoffQueue('order-processing', {\n * deadLetter: { exchange: dlx },\n * maxRetries: 5,\n * initialDelayMs: 1000, // Start with 1s delay\n * maxDelayMs: 30000, // Cap at 30s\n * });\n *\n * // Use in a contract — wait queue, bindings, and DLX are auto-extracted\n * const contract = defineContract({\n * publishers: { ... },\n * consumers: { processOrder: defineEventConsumer(event, extractQueue(orderQueue)) },\n * });\n *\n * // To access the underlying queue definition (e.g., for the queue name):\n * import { extractQueue } from '@amqp-contract/contract';\n * const queueName = extractQueue(orderQueue).name;\n * ```\n *\n * @see defineQueue - For full queue configuration options\n * @see defineQuorumQueue - For queues with quorum-native retry (simpler, immediate retries)\n * @see extractQueue - To access the underlying queue definition\n */\nexport function defineTtlBackoffQueue<TName extends string>(\n name: TName,\n options: DefineTtlBackoffQueueOptions,\n): QueueWithTtlBackoffInfrastructure<TName> {\n const {\n deadLetter,\n maxRetries,\n initialDelayMs,\n maxDelayMs,\n backoffMultiplier,\n jitter,\n autoDelete,\n arguments: args,\n } = options;\n\n // Build retry options, only including defined values\n const retryOptions: TtlBackoffRetryOptions = { mode: \"ttl-backoff\" };\n if (maxRetries !== undefined) retryOptions.maxRetries = maxRetries;\n if (initialDelayMs !== undefined) retryOptions.initialDelayMs = initialDelayMs;\n if (maxDelayMs !== undefined) retryOptions.maxDelayMs = maxDelayMs;\n if (backoffMultiplier !== undefined) retryOptions.backoffMultiplier = backoffMultiplier;\n if (jitter !== undefined) retryOptions.jitter = jitter;\n\n const queueOptions: QuorumQueueOptions = {\n type: \"quorum\",\n deadLetter,\n retry: retryOptions,\n };\n\n if (autoDelete !== undefined) queueOptions.autoDelete = autoDelete;\n if (args !== undefined) queueOptions.arguments = args;\n\n const result = defineQueue(name, queueOptions);\n\n // Since we configured TTL-backoff with a dead letter exchange, the result will\n // always be QueueWithTtlBackoffInfrastructure\n return result as QueueWithTtlBackoffInfrastructure<TName>;\n}\n","import type {\n DirectExchangeDefinition,\n ExchangeDefinition,\n FanoutExchangeDefinition,\n MessageDefinition,\n PublisherDefinition,\n TopicExchangeDefinition,\n} from \"../types.js\";\n\n/**\n * Define a message publisher for a fanout exchange.\n *\n * A publisher sends messages to an exchange. For fanout exchanges, messages are broadcast\n * to all bound queues regardless of routing key, so no routing key is required.\n *\n * The message schema is validated when publishing to ensure type safety.\n *\n * **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 exchange definition to publish to\n * @param message - The message definition with payload schema\n * @param options - Optional publisher configuration\n * @returns A publisher definition with inferred message types\n *\n * @example\n * ```typescript\n * import { z } from 'zod';\n *\n * const logsExchange = defineExchange('logs', 'fanout', { durable: true });\n * const logMessage = defineMessage(\n * z.object({\n * level: z.enum(['info', 'warn', 'error']),\n * message: z.string(),\n * timestamp: z.string().datetime(),\n * })\n * );\n *\n * const logPublisher = definePublisher(logsExchange, logMessage);\n * ```\n *\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,\n message: TMessage,\n options?: Omit<\n Extract<PublisherDefinition<TMessage>, { exchange: FanoutExchangeDefinition }>,\n \"exchange\" | \"message\" | \"routingKey\"\n >,\n): Extract<PublisherDefinition<TMessage>, { exchange: FanoutExchangeDefinition }>;\n\n/**\n * Define a message publisher for a direct or topic exchange.\n *\n * A publisher sends messages to an exchange with a specific routing key.\n * The routing key determines which queues receive the message.\n *\n * The message schema is validated when publishing to ensure type safety.\n *\n * **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', 'topic', { durable: true });\n * const orderMessage = defineMessage(\n * z.object({\n * orderId: z.string().uuid(),\n * amount: z.number().positive(),\n * }),\n * {\n * summary: 'Order created event',\n * description: 'Emitted when a new order is created'\n * }\n * );\n *\n * const orderCreatedPublisher = definePublisher(ordersExchange, orderMessage, {\n * routingKey: 'order.created'\n * });\n * ```\n *\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\") {\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\") {\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\";\nimport { extractQueue } from \"./queue.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', { durable: true });\n * const orderMessage = defineMessage(\n * z.object({\n * orderId: z.string().uuid(),\n * customerId: z.string().uuid(),\n * amount: z.number().positive(),\n * })\n * );\n *\n * const processOrderConsumer = defineConsumer(orderQueue, orderMessage);\n *\n * // Later, when creating a worker, you'll provide a handler for this consumer:\n * // const worker = await TypedAmqpWorker.create({\n * // contract,\n * // handlers: {\n * // processOrder: async (message) => {\n * // // message is automatically typed based on the schema\n * // console.log(message.orderId); // string\n * // }\n * // },\n * // connection\n * // });\n * ```\n *\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: extractQueue(queue),\n message,\n ...options,\n };\n}\n","import type { BindingPattern, RoutingKey } from \"./routing-types.js\";\nimport type {\n ConsumerDefinition,\n DirectExchangeDefinition,\n ExchangeBindingDefinition,\n ExchangeDefinition,\n ExtractDlxFromEntry,\n ExtractQueueFromEntry,\n FanoutExchangeDefinition,\n MessageDefinition,\n QueueBindingDefinition,\n QueueDefinition,\n QueueEntry,\n TopicExchangeDefinition,\n} from \"../types.js\";\nimport { defineConsumer } from \"./consumer.js\";\nimport { defineExchangeBinding, defineQueueBindingInternal } from \"./binding.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)\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 QueueDefinition = QueueDefinition,\n TDlxExchange extends ExchangeDefinition | undefined = ExchangeDefinition | undefined,\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 dead letter exchange from the queue, if configured */\n deadLetterExchange: TDlxExchange;\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 * @returns An event publisher configuration\n *\n * @example\n * ```typescript\n * const logsExchange = defineExchange('logs', 'fanout', { durable: true });\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>(exchange: TExchange, message: TMessage): 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', 'direct', { durable: true });\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', 'topic', { durable: true });\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 * @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 ExtractQueueFromEntry<TQueueEntry>,\n ExtractDlxFromEntry<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 * @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 ExtractQueueFromEntry<TQueueEntry>,\n ExtractDlxFromEntry<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 * @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 ExtractQueueFromEntry<TQueueEntry>,\n ExtractDlxFromEntry<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 * @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<\n TMessage,\n TExchange,\n ExtractQueueFromEntry<TQueueEntry>,\n ExtractDlxFromEntry<TQueueEntry>\n>;\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 * @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<\n TMessage,\n TExchange,\n ExtractQueueFromEntry<TQueueEntry>,\n ExtractDlxFromEntry<TQueueEntry>\n>;\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 * @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<\n TMessage,\n TExchange,\n ExtractQueueFromEntry<TQueueEntry>,\n ExtractDlxFromEntry<TQueueEntry>\n>;\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\"\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: consumer.queue,\n deadLetterExchange: consumer.queue.deadLetter?.exchange,\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: consumer.queue,\n deadLetterExchange: consumer.queue.deadLetter?.exchange,\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 { BindingPattern, RoutingKey } from \"./routing-types.js\";\nimport type {\n ConsumerDefinition,\n DirectExchangeDefinition,\n ExchangeBindingDefinition,\n ExchangeDefinition,\n ExtractDlxFromEntry,\n ExtractQueueFromEntry,\n FanoutExchangeDefinition,\n MessageDefinition,\n PublisherDefinition,\n QueueBindingDefinition,\n QueueDefinition,\n QueueEntry,\n TopicExchangeDefinition,\n} from \"../types.js\";\nimport { defineConsumer } from \"./consumer.js\";\nimport { definePublisherInternal } from \"./publisher.js\";\nimport { defineExchangeBinding, defineQueueBindingInternal } from \"./binding.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)\n */\nexport type CommandConsumerConfig<\n TMessage extends MessageDefinition,\n TExchange extends ExchangeDefinition,\n TRoutingKey extends string | undefined = undefined,\n TQueue extends QueueDefinition = QueueDefinition,\n TDlxExchange extends ExchangeDefinition | undefined = ExchangeDefinition | undefined,\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 dead letter exchange from the queue, if configured */\n deadLetterExchange: TDlxExchange;\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 * @returns A command consumer configuration\n *\n * @example\n * ```typescript\n * const tasksExchange = defineExchange('tasks', 'fanout', { durable: true });\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): CommandConsumerConfig<\n TMessage,\n TExchange,\n undefined,\n ExtractQueueFromEntry<TQueueEntry>,\n ExtractDlxFromEntry<TQueueEntry>\n>;\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', 'direct', { durable: true });\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<\n TMessage,\n TExchange,\n TRoutingKey,\n ExtractQueueFromEntry<TQueueEntry>,\n ExtractDlxFromEntry<TQueueEntry>\n>;\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', 'topic', { durable: true });\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<\n TMessage,\n TExchange,\n TRoutingKey,\n ExtractQueueFromEntry<TQueueEntry>,\n ExtractDlxFromEntry<TQueueEntry>\n>;\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: consumer.queue,\n deadLetterExchange: consumer.queue.deadLetter?.exchange,\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\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 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 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 publisher 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\"\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 BindingDefinition,\n ConsumerDefinition,\n ContractDefinition,\n ContractDefinitionInput,\n ContractOutput,\n ExchangeDefinition,\n PublisherDefinition,\n QueueDefinition,\n} from \"../types.js\";\nimport { isEventConsumerResult, isEventPublisherConfig } from \"./event.js\";\nimport { definePublisherInternal } from \"./publisher.js\";\nimport { isBridgedPublisherConfig, isCommandConsumerConfig } from \"./command.js\";\nimport { createTtlBackoffInfrastructure } from \"./queue.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', 'topic', { durable: true });\n * const dlx = defineExchange('orders-dlx', 'direct', { durable: true });\n * const orderQueue = defineQueue('order-processing', {\n * deadLetter: { exchange: dlx },\n * retry: { mode: 'quorum-native' },\n * deliveryLimit: 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 } = definition;\n const result: ContractDefinition = {\n exchanges: {},\n queues: {},\n bindings: {},\n publishers: {},\n consumers: {},\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, QueueDefinition> = {};\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 queues[queueEntry.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 (queueEntry.deadLetter?.exchange) {\n exchanges[queueEntry.deadLetter.exchange.name] = queueEntry.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 queues[queueEntry.name] = queueEntry;\n\n // Extract exchange\n exchanges[entry.exchange.name] = entry.exchange;\n\n // Extract dead letter exchange if present\n if (queueEntry.deadLetter?.exchange) {\n exchanges[queueEntry.deadLetter.exchange.name] = queueEntry.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 queues[queueEntry.name] = queueEntry;\n\n // Extract dead letter exchange if present\n if (queueEntry.deadLetter?.exchange) {\n exchanges[queueEntry.deadLetter.exchange.name] = queueEntry.deadLetter.exchange;\n }\n }\n }\n\n // Auto-generate TTL-backoff retry infrastructure for queues with retry.mode === \"ttl-backoff\" and deadLetter\n for (const queue of Object.values(queues) as QueueDefinition[]) {\n if (queue.retry?.mode === \"ttl-backoff\" && queue.deadLetter) {\n const infra = createTtlBackoffInfrastructure(queue);\n queues[infra.waitQueue.name] = infra.waitQueue;\n consumerBindings[`${queue.name}WaitBinding`] = infra.waitQueueBinding;\n consumerBindings[`${queue.name}RetryBinding`] = infra.mainQueueRetryBinding;\n exchanges[queue.deadLetter.exchange.name] = queue.deadLetter.exchange;\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 return result as ContractOutput<TContract>;\n}\n","import type { QueueBindingDefinition, QueueDefinition, QueueEntry } from \"../types.js\";\nimport { createTtlBackoffInfrastructure, extractQueue } from \"./queue.js\";\n\n/**\n * Result type for TTL-backoff retry infrastructure builder.\n *\n * Contains the wait queue and bindings needed for TTL-backoff retry.\n */\nexport type TtlBackoffRetryInfrastructure = {\n /**\n * The wait queue for holding messages during backoff delay.\n * This is a classic queue with a dead letter exchange pointing back to the main queue.\n */\n waitQueue: QueueDefinition;\n /**\n * Binding that routes failed messages to the wait queue.\n */\n waitQueueBinding: QueueBindingDefinition;\n /**\n * Binding that routes retried messages back to the main queue.\n */\n mainQueueRetryBinding: QueueBindingDefinition;\n};\n\n/**\n * Create TTL-backoff retry infrastructure for a queue.\n *\n * This builder helper generates the wait queue 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 DLX with routing key `{queueName}-wait`\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 DLX with routing key `{queueName}`\n * 4. The main queue receives the retried message via its binding to the DLX\n *\n * @param queue - The main queue definition (must have deadLetter configured)\n * @param options - Optional configuration for the wait queue\n * @param options.waitQueueDurable - Whether the wait queue should be durable (default: same as main queue)\n * @returns TTL-backoff retry infrastructure containing wait queue and bindings\n * @throws {Error} If the queue does not have a dead letter exchange configured\n *\n * @example\n * ```typescript\n * const dlx = defineExchange('orders-dlx', 'direct', { durable: true });\n * const orderQueue = defineQueue('order-processing', {\n * type: 'quorum',\n * deadLetter: { exchange: dlx },\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, extractQueue(orderQueue)) },\n * });\n * // contract.queues includes the wait queue, contract.bindings includes retry bindings\n *\n * // Or generate manually for advanced use cases:\n * const retryInfra = defineTtlBackoffRetryInfrastructure(orderQueue);\n * ```\n */\nexport function defineTtlBackoffRetryInfrastructure(\n queueEntry: QueueEntry,\n options?: {\n waitQueueDurable?: boolean;\n },\n): TtlBackoffRetryInfrastructure {\n const queue = extractQueue(queueEntry);\n const infra = createTtlBackoffInfrastructure(queue);\n\n // Apply waitQueueDurable override if specified\n if (options?.waitQueueDurable !== undefined) {\n infra.waitQueue.durable = options.waitQueueDurable;\n }\n\n return infra;\n}\n"],"mappings":"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"}