- Updated dependencies [bfc138c]
- @amqp-contract/contract@2.2.0
- @amqp-contract/core@2.2.0
- Updated dependencies [a8628d5]
- @amqp-contract/contract@2.1.0
- @amqp-contract/core@2.1.0
- Updated dependencies [8707df1]
- @amqp-contract/contract@2.0.0
- @amqp-contract/core@2.0.0
- Updated dependencies [d5fec7e]
- Updated dependencies [4ed4abe]
- @amqp-contract/contract@1.0.0
- @amqp-contract/core@1.0.0
-
abc6de3: Correctness fixes from a project audit. All six packages bump together (
fixedgroup) — most changes land incoreandworker, but the version move covers the whole release.Worker — retry message safety (
packages/worker/src/retry.ts)publishForRetrynow publishes the retry copy first and only acks the original delivery if the publish is confirmed. Previously the original was ack'd before the publish was attempted: a publish failure (channel buffer full, channel error, etc.) would lose the message — the broker had already discarded the delivery and no retry copy was ever sent. On a publish failure the original is now left un-ack'd so amqp-connection-manager (or the broker on channel close) can redeliver it.
Worker — jitter range (
packages/worker/src/retry.ts)- The TTL-backoff retry jitter formula is now
delay * (0.5 + Math.random())giving a symmetric[0.5x, 1.5x]range with mean 1.0x. The previous formula0.5 + Math.random() * 0.5produced[0.5x, 1.0x](mean 0.75x) and never overshot — a one-sided bias, not real jitter. The clamp againstmaxDelayMsnow runs after jitter so the upper jitter bound cannot push the calculated delay past the configured maximum. User-visible change: the average retry delay under jitter increases by ~33% (0.75x → 1.0x of the configured base) and individual delays may now exceed the pre-clamp base by up to 50%.
Worker — double-ack guard (
packages/worker/src/worker.ts)- The defensive
nack(requeue=false)in the consume callback's catch-all is now skipped if the message has already been ack'd or nack'd by the dispatch path. Previously a throw from anywhere after the success-pathack(most notably the telemetry tail) would land in the catch-all and nack the same delivery tag — RabbitMQ then closed the channel with406 PRECONDITION_FAILED. Telemetry calls in the dispatch tail are also now wrapped in a try/catch so an instrumentation bug cannot crash the consume loop.
Core —
PublishOptions.timeoutremoved (packages/core/src/amqp-client.ts)- Breaking-shaped change (shipped as minor under 0.x): the
timeoutfield onPublishOptionshas been removed. It was a stale type-level declaration that suggested a publish-level timeout this library does not meaningfully provide. Code passingtimeoutwill now fail to typecheck; remove the option (or move toamqp-connection-manager's channel-levelpublishTimeoutif you actually need it).
Core —
ConsumerOptions.prefetchnow wired up (packages/core/src/amqp-client.ts)AmqpClient.consume(...)now appliesoptions.prefetchviachannel.prefetch(count, false)registered on the channel wrapper before the consume call (so the value is in effect when the consumer starts and is reapplied on channel reconnect). The value is also stripped from the options handed tochannelWrapper.consume(...)sinceprefetchis not a validamqplibOptions.Consumefield. Theprefetchoption advertised on the worker's per-handler tuple form is now actually applied.
Core — connection key URL ordering (
packages/core/src/connection-manager.ts)- Added an inline comment confirming that URL list order is intentionally
part of the pooled-connection key.
['a','b']and['b','a']continue to get different pooled connections because the URL list is a failover list with the first entry as the preferred broker — sorting would silently merge those into one connection and pin one caller's preference onto the other. No behaviour change.
-
bf08a27: Close public-API gaps surfaced by the audit:
defineHandler/defineHandlersnow accept RPC names in addition to consumer names. The handler type fordefineHandleris inferred from the contract — consumer names yieldWorkerInferConsumerHandler, RPC names yieldWorkerInferRpcHandler.defineHandlersis typed againstWorkerInferHandlers<TContract>, which already spansconsumers ∪ rpcs. Runtime validation walks both sets and the error message lists both.- The RPC-side
Infer*helpers and the unified handlers type are now re-exported from@amqp-contract/worker:WorkerInferHandlers,WorkerInferRpcHandler,WorkerInferRpcHandlerEntry,WorkerInferRpcConsumedMessage,WorkerInferRpcRequest,WorkerInferRpcResponse,WorkerInferRpcHeaders. This makes the worker package symmetrical with the client package's RPC-side exports. HandlerErroris now an abstract base class (error instanceof HandlerErrorworks).RetryableErrorandNonRetryableErrorextend it, and thenameproperty still discriminates so exhaustive narrowing in user code keeps working. Public type signature is unchanged (a class can be used as a type).- Removed
WorkerInferConsumerHandlers(was@deprecatedfor one cycle). UseWorkerInferHandlersinstead — same shape, accurate name.
- Updated dependencies [abc6de3]
- Updated dependencies [bf08a27]
- Updated dependencies [72d37af]
- @amqp-contract/contract@0.25.0
- @amqp-contract/core@0.25.0
-
91a9d47: Replace
@swan-io/boxedwithneverthrowfor the public Result/async API.Breaking. Public method signatures change from
Future<Result<T, E>>toResultAsync<T, E>. Handlers must now returnResultAsync<void, HandlerError>(regular consumers) orResultAsync<TResponse, HandlerError>(RPCs).Migration cheat-sheet:
Before ( @swan-io/boxed)After ( neverthrow)Future.value(Result.Ok(x))okAsync(x)Future.value(Result.Error(e))errAsync(e)Result.Ok(x)/Result.Error(e)ok(x)/err(e)Future.fromPromise(p).mapError(fn)ResultAsync.fromPromise(p, fn)f.mapOk(fn)/f.mapError(fn)f.map(fn)/f.mapErr(fn)f.flatMapOk(fn)/f.flatMapErrorf.andThen(fn)/f.orElse(fn)f.tapOk(fn)/f.tapError(fn)f.andTee(fn)/f.orTee(fn)r.match({ Ok, Error })r.match(okFn, errFn)(positional)Future.all([...])of Result-FuturesResultAsync.combine([...])await x.resultToPromise()(unwrap)(await x)._unsafeUnwrap()await x.toPromise()(Result wrap)await x(ResultAsyncis thenable)result.isError()result.isErr()Futuresemantics that are not preserved: laziness and cancellation.ResultAsyncis eager and Promise-backed. None of the library internals depended on Future-side cancel.
- Updated dependencies [91a9d47]
- @amqp-contract/contract@0.24.0
- @amqp-contract/core@0.24.0
-
1cf3b2d: Pin
amqplibback to the0.10.xline (was1.0.3). The1.xseries ships breaking API changes that the worker and client paths haven't been validated against; staying on0.10.9keeps runtime behaviour aligned with what's covered by the integration tests and whatamqp-connection-manager@5expects.Workspace housekeeping with no user-visible impact: top-level
pnpmsettings inpnpm-workspace.yamlare now under the correct keys (the previoussettings:nested block was silently ignored by pnpm 9+), and apeerDependencyRules.ignoreMissingentry is added forsearch-insights— VitePress bundles@docsearch/reacteven when the docs site usesprovider: "local", and the missing peer was trippingstrictPeerDependenciesonce the settings actually took effect. -
Updated dependencies [1cf3b2d]
- @amqp-contract/contract@0.23.1
- @amqp-contract/core@0.23.1
-
91959fb: Harden the worker dispatch loop, surface AMQP topology details in the AsyncAPI generator, and tighten a few public defaults.
Worker
- The consume callback is now wrapped in a defensive try/catch — a handler that throws synchronously (or an unexpected fault inside the dispatch chain) no longer leaves messages neither acked nor nacked. The message is logged and nacked with
requeue=falseso a configured DLX still receives it. - Schema validation and parse errors take an explicit DLQ path and never enter the queue's retry pipeline. Retrying a malformed payload cannot succeed, so the previous behaviour wasted retry budget on guaranteed failures.
- RPC reply-side failures (missing
replyTo, missingcorrelationId, response schema failure, reply publish failure) now returnNonRetryableErrorinstead of being swallowed or surfacing asRetryableError. The original message lands in the DLQ for inspection rather than being silently retried against a caller that has already gone away. - The retry re-publish path respects
properties.contentType: only round-trip JSON payloads, pass binary content through unchanged.
Contract
defineContractnow throws when two publishers/consumers reference the same exchange or queue name with conflicting definitions (e.g. differenttype,durable, orretrysettings). Identical re-declarations continue to deduplicate silently — the common pattern of one exchange flowing into the contract through both a publisher and a consumer is unaffected.
Core
AmqpClient.connectTimeoutMsdefaults to 30 s (DEFAULT_CONNECT_TIMEOUT_MS). Passnullto opt back into the legacy "wait forever" behaviour. Avoids hangs on misconfigured URLs or down brokers.ConnectionManagerSingletonis no longer part of the public API. Use the underscore-prefixed_resetConnectionsForTestingand_getConnectionCountForTestinghelpers instead.- New
recordLateRpcReplytelemetry helper andamqp.client.rpc.late_replycounter. The client uses it whenever a reply arrives without a matching pending call (caller already timed out / cancelled / unknown correlationId), and elevates the corresponding log fromdebugtowarn. - The OpenTelemetry instrumentation scope version is now sourced from
package.jsoninstead of a hardcoded constant.
AsyncAPI
- Queue channels surface dead-lettering via
x-dead-letter-exchange/x-dead-letter-routing-keyin the AMQP binding'sarguments, the queue description summarises DLX + retry mode, and anx-amqp-retryextension carries the structured retry config. - Exchange channels surface bridge / e2e bindings via the description (
forwards to '…',receives from '…') and anx-amqp-exchange-bindingsextension so cross-domain topology is visible in the generated spec. - New
failOnMissingConvertergenerator option throws when a payload schema cannot be converted instead of falling back to a generic{ type: "object" }placeholder. Recommended for CI pipelines.
Docs
- New guide pages:
error-model,retry-strategies,bridge-exchanges. New example:command-pattern.worker-usagenow leads withdefineHandler.CONTRIBUTINGdocuments the changesets-driven release workflow.
- The consume callback is now wrapped in a defensive try/catch — a handler that throws synchronously (or an unexpected fault inside the dispatch chain) no longer leaves messages neither acked nor nacked. The message is logged and nacked with
- Updated dependencies [91959fb]
- @amqp-contract/contract@0.23.0
- @amqp-contract/core@0.23.0
-
61d1af9: Add
connectTimeoutMsoption toTypedAmqpClient.create(),TypedAmqpWorker.create(), andAmqpClient, and fix a connection leak on the failure path.amqp-connection-managerretries connections indefinitely and never rejectswaitForConnecton its own. Without a timeout, a misconfigured URL or unreachable broker pinned the call forever. The newconnectTimeoutMsoption raceswaitForConnectagainst a timer socreate()can fail fast.The same code path also fixes a connection leak: when
create()failed (timeout, orconsumeAllerroring after some consumers had registered), the connection's reference count inConnectionManagerSingletonstayed incremented and any registered consumers stayed running. Both factories now invokeclose()before propagating the error. -
203ad3a: Add RPC pattern: typed request/response over RabbitMQ via a single
defineRpcbuilder and a dedicatedrpcsslot on the contract.import { defineContract, defineMessage, defineQueue, defineRpc } from "@amqp-contract/contract"; import { z } from "zod"; const calculate = defineRpc(defineQueue("rpc.calculate"), { request: defineMessage(z.object({ a: z.number(), b: z.number() })), response: defineMessage(z.object({ sum: z.number() })), }); const contract = defineContract({ rpcs: { calculate }, });
The worker handler returns the response payload (validated against the response schema before being published back to the caller's
replyTo):TypedAmqpWorker.create({ contract, handlers: { calculate: ({ payload }) => Future.value(Result.Ok({ sum: payload.a + payload.b })), }, urls: ["amqp://localhost"], });
The client calls with a required timeout and receives a typed
Result:const result = await client.call("calculate", { a: 1, b: 2 }, { timeoutMs: 5_000 }).toPromise(); // Result<{ sum: number }, TechnicalError | MessageValidationError | RpcTimeoutError | RpcCancelledError>
Design notes:
- RPC is bidirectional on both ends (server consumes requests + publishes
responses; client publishes requests + consumes responses), so it has
its own
rpcsslot rather than being shoehorned intopublishersorconsumers. - A single
defineRpc(queue, { request, response })produces one definition shared by both ends — no client/server split, no risk of schema drift. - Worker handler keys live in the same object as
consumershandlers; RPC handlers return the typed response payload, regular consumers returnvoid. - Uses RabbitMQ direct reply-to (
amq.rabbitmq.reply-to) — no reply queue declaration needed. - A single reply consumer demultiplexes responses by
correlationId; the client manages an in-memory pending-call map. - Closing the client rejects every in-flight call with
RpcCancelledError. - Response-schema validation failures on the server map to
NonRetryableError(handler bug → DLQ). - AsyncAPI generation does not yet emit dedicated requestReply pairs for RPCs — tracked as a follow-up.
- RPC is bidirectional on both ends (server consumes requests + publishes
responses; client publishes requests + consumes responses), so it has
its own
- Updated dependencies [61d1af9]
- Updated dependencies [203ad3a]
- @amqp-contract/core@0.22.0
- @amqp-contract/contract@0.22.0
-
Retry system and configuration normalization
- None retry
- Introduced new
noneretry option to represent the "no retry" mode - Changed queue builder default from
ttl-backoffretry tononeretry - Removed implicit TTL-backoff infrastructure creation when no retry config specified
- Worker error handler now detects
noneretry mode and rejects failed messages without retry - Aligns with "explicit over implicit" configuration philosophy
- Immediate-requeue retry
- Migrated from
quorum-native(quorum-only) toimmediate-requeue(universal) - Now works with both quorum and classic queues
- Improved handling: quorum uses native
x-delivery-count, classic uses custom headers - Simplified API:
maxRetriesparameter replacesdeliveryLimit
- TTL-backoff via headers exchanges
- Replaced DLX routing with headers exchange infrastructure
- Preserves original routing keys through retry flow
- Eliminates dangerous infinite retry loop behavior
- Configurable infrastructure names (
waitQueueName,waitExchangeName,retryExchangeName)
- Exchange configuration normalization
- Exchange
typedefaults totopic(most used) durabledefaults totrue(production-friendly)- Added support for headers exchange types
- Reduced verbosity while supporting all exchange types
- Queue configuration normalization
- Queue
typedefaults toquorum(modern choice) durabledefaults totrue(production-friendly)autoDeletemode restricted to classic queues only (likeexclusiveandmaxPriority)- Better type safety and runtime validation of queue options
- Removed over-specific queue definition helpers:
defineQuorumQueue(),defineTtlBackoffQueue() - Removed
deliveryLimitin favor ofmaxRetries - Retry config consolidated at queue level
- Default publish/consumer options
- Added
defaultPublishOptionstoTypedAmqpClient- Set once, applies to all publishes (can be overridden per-call)
persistentdefaults totrue(production-friendly)
- Added
defaultConsumerOptionstoTypedAmqpWorker- Set once, applies to all consumers (can be overridden per-consumer handler)
- Removed custom prefetch implementation in favor of built-in configuration in
amqp-connection-manager - Eliminates configuration repetition across codebase
- Handler type safety fix
- Consumer handler payloads and headers now properly typed from schema output types
- Removed unnecessary type extraction utilities
⚠️ Users upgrading will need to:- Configure TTL-backoff explicitly, since queues now default to no retry
- Migrate TTL-backoff queue names if using custom infrastructure naming
- Change
mode: "quorum-native"tomode: "immediate-requeue" - Replace
deliveryLimitwithmaxRetriesin retry config - Replace
typeparameter fromdefineExchange()calls withtypeoptions property (defaults totopic) - Replace
defineQuorumQueue()anddefineTtlBackoffQueue()helpers with genericdefineQueue()
Exchange Definition
// Before defineExchange("orders", "topic", { durable: true }); // After defineExchange("orders"); // topic + durable by default
Queue Definition
// Before defineQueue("orders", { durable: true }); // After defineQueue("orders"); // quorum + durable by default
Retry Configuration
// Before: TTL-backoff created automatically defineQueue("orders"); // Had retry: ttl-backoff by default // After: No retry by default defineQueue("orders"); // Now has no retry by default // To enable TTL-backoff retry, explicitly opt-in: defineQueue("orders", { retry: { mode: "ttl-backoff", maxRetries: 3 }, }); // Before: "quorum-native" with deliveryLimit (for quorum queues only) defineQueue("orders", { type: "quorum", deliveryLimit: 3, retry: { mode: "quorum-native" }, }); // After: "immediate-requeue" with maxRetries (for any queue) defineQueue("orders", { retry: { mode: "immediate-requeue", maxRetries: 3 }, });
Default Publish/Consumer Options
// Default publish options in client const client = await TypedAmqpClient.create({ contract, urls: ["amqp://localhost"], defaultPublishOptions: { priority: 5 }, }); // Default consumer options in worker const worker = await TypedAmqpWorker.create({ contract, handlers, urls: ["amqp://localhost"], defaultConsumerOptions: { prefetch: 10 }, });
- Updated dependencies
- @amqp-contract/contract@0.21.0
- @amqp-contract/core@0.21.0
- Updated dependencies
- @amqp-contract/contract@0.20.0
- @amqp-contract/core@0.20.0
-
acfd949: BREAKING:
MessageValidationErroris now defined in@amqp-contract/coreand re-exported from@amqp-contract/clientand@amqp-contract/worker.The
publisherName(client) andconsumerName(worker) properties have been replaced with a unifiedsourceproperty. Update any code that accesses these properties:- error.publisherName - error.consumerName + error.source
- Updated dependencies [acfd949]
- @amqp-contract/core@0.19.0
- @amqp-contract/contract@0.19.0
- Updated dependencies
- @amqp-contract/contract@0.18.0
- @amqp-contract/core@0.18.0
- Updated dependencies [22242a4]
- @amqp-contract/contract@0.17.0
- @amqp-contract/core@0.17.0
- Updated dependencies
- @amqp-contract/contract@0.16.0
- @amqp-contract/core@0.16.0
- Simplify contract definition API and preserve literal types in ContractOutput
- Updated dependencies
- @amqp-contract/contract@0.15.0
- @amqp-contract/core@0.15.0
-
feat: add Event/Command Pattern API for intuitive messaging patterns
Event Pattern - For broadcasting events to multiple consumers:
defineEventPublisher(exchange, message, options)- Define an event publisherdefineEventConsumer(eventPublisher, queue, options)- Subscribe to an event (auto-generates binding)
Command Pattern - For task queues with single consumer:
defineCommandConsumer(queue, exchange, message, options)- Define a command consumer (auto-generates binding)defineCommandPublisher(commandConsumer, options)- Create a publisher for a command
Helper Functions:
extractConsumer(entry)- Extract ConsumerDefinition from any ConsumerEntry type
- Removed
definePublisherFirstanddefineConsumerFirst(replaced by Event/Command patterns)
// Event pattern: one publisher, many consumers const orderCreated = defineEventPublisher(ordersExchange, orderMessage, { routingKey: "order.created", }); const processOrder = defineEventConsumer(orderCreated, orderQueue); const notifyOrder = defineEventConsumer(orderCreated, notificationQueue); // Command pattern: many publishers, one consumer const shipOrder = defineCommandConsumer(shippingQueue, ordersExchange, shipMessage, { routingKey: "order.ship", }); const sendShipOrder = defineCommandPublisher(shipOrder); // Use in contract - bindings are auto-generated const contract = defineContract({ exchanges: { orders: ordersExchange }, queues: { orderQueue, notificationQueue, shippingQueue }, publishers: { orderCreated, sendShipOrder }, consumers: { processOrder, notifyOrder, shipOrder }, });
- Updated dependencies
- @amqp-contract/contract@0.14.0
- @amqp-contract/core@0.14.0
- Updated dependencies
- @amqp-contract/contract@0.13.0
- @amqp-contract/core@0.13.0
-
- Added main export entry point for
@amqp-contract/testing- users can nowimport { it, globalSetup } from '@amqp-contract/testing'
- Added comprehensive OpenTelemetry observability guide covering traces, metrics, and configuration
- Added security audit job to CI pipeline
- Added bundle size monitoring with GitHub Step Summary reporting
- Split
builder.ts(1,911 lines) into modular files for better maintainability:builder/exchange.ts- defineExchangebuilder/queue.ts- defineQueue, extractQueuebuilder/message.ts- defineMessagebuilder/binding.ts- defineQueueBinding, defineExchangeBindingbuilder/publisher.ts- definePublisherbuilder/consumer.ts- defineConsumerbuilder/contract.ts- defineContractbuilder/publisher-first.ts- definePublisherFirstbuilder/consumer-first.ts- defineConsumerFirstbuilder/ttl-backoff.ts- defineTtlBackoffRetryInfrastructurebuilder/routing-types.ts- RoutingKey, BindingPattern types
- All existing imports continue to work (backward compatible)
- Improved compression validation error messages with helpful context:
- Shows received encoding
- Lists supported encodings (gzip, deflate)
- Suggests checking publisher configuration
- Fixed high severity vulnerability in
preactdependency (CVE in vitepress transitive dependency)
- Added main export entry point for
- Updated dependencies
- @amqp-contract/contract@0.12.0
- @amqp-contract/core@0.12.0
-
feat: move retry configuration from worker to contract level
Breaking Change: Retry configuration has moved from handler-level to queue-level.
const worker = await TypedAmqpWorker.create({ contract, handlers: { processOrder: [handler, { retry: { maxRetries: 3, initialDelayMs: 1000 } }], }, urls: ["amqp://localhost"], });
// Configure retry at queue level in the contract const orderQueue = defineQueue("order-processing", { deadLetter: { exchange: dlx }, retry: { mode: "ttl-backoff", maxRetries: 3, initialDelayMs: 1000, }, }); // Worker no longer specifies retry options const worker = await TypedAmqpWorker.create({ contract, handlers: { processOrder: handler, }, urls: ["amqp://localhost"], });
- Retry types moved to contract package:
RetryOptions,TtlBackoffRetryOptions,QuorumNativeRetryOptionsare now exported from@amqp-contract/contract - Queue-level retry configuration: Use
retryoption indefineQueue()instead of handler tuples - Automatic TTL-backoff infrastructure:
defineContract()automatically generates wait queues and bindings for TTL-backoff mode extractQueue()helper: Use this to access queue properties fromQueueWithTtlBackoffInfrastructurewrapper- Removed
setupWaitQueues: Wait queues are now created bysetupAmqpTopologylike any other queue
- Move
retryconfiguration from handler options to queue definition - Add
mode: "ttl-backoff"ormode: "quorum-native"to your retry config - Remove handler tuple syntax
[handler, { retry: ... }]- just usehandlerdirectly - Use
extractQueue()when accessing queue properties if using TTL-backoff mode
- Retry types moved to contract package:
- Updated dependencies
- @amqp-contract/contract@0.11.0
- @amqp-contract/core@0.11.0
-
Automatically bind main queue to DLX for retry flow
The worker now automatically creates a binding from the Dead Letter Exchange (DLX) to the main queue using the queue name as the routing key. This completes the retry flow: DLX → wait queue → DLX → main queue.
Users no longer need to manually create a
waitBindingin their contracts when implementing retry logic. The binding is now handled automatically by the worker setup process. -
Updated dependencies
- @amqp-contract/core@0.10.0
- @amqp-contract/contract@0.10.0
-
Add OpenTelemetry instrumentation for spans and metrics
This release adds comprehensive OpenTelemetry instrumentation support for AMQP operations:
- Automatic tracing: Distributed tracing spans for publish and consume operations with semantic conventions following OpenTelemetry standards
- Metrics collection: Counters and histograms for message throughput and latency monitoring
- Optional dependency: OpenTelemetry is an optional peer dependency that is gracefully loaded when available
- Zero configuration: Instrumentation automatically integrates with your existing OpenTelemetry setup
- Semantic conventions: Follows OpenTelemetry messaging semantic conventions for AMQP/RabbitMQ
Key features:
- Producer and consumer spans with proper span kinds
- Message metadata tracking (message ID, routing key, delivery tag, payload size)
- Error tracking with error types and attributes
- Performance metrics for publish and consume operations
- Compatible with any OpenTelemetry-compliant APM solution
See the documentation for configuration details and usage examples.
- Updated dependencies
- @amqp-contract/core@0.9.0
- @amqp-contract/contract@0.9.0
- @amqp-contract/contract@0.8.0
- @amqp-contract/core@0.8.0
-
Release version 0.7.0 with runtime message compression support for AMQP payloads.
This release adds the ability to compress messages at runtime using gzip or deflate algorithms. Key features include:
- Added
CompressionAlgorithmtype supporting 'gzip' and 'deflate' - Added optional
compressionparameter to thepublish()method for runtime compression - Automatic decompression in workers based on content-encoding header
- Backward compatible - no compression by default
- New sample demonstrating compression usage
See PR #225 for complete details.
- Added
- Updated dependencies
- @amqp-contract/contract@0.7.0
- @amqp-contract/core@0.7.0
-
Restructure repository to follow vitest pattern with docs as workspace package
This release includes a major refactoring of the repository structure:
- Move documentation to workspace package for better integration
- Simplify docs build workflow
- Remove orchestration scripts in favor of turbo
- Improve overall project organization following vitest pattern
- Updated dependencies
- @amqp-contract/contract@0.6.0
- @amqp-contract/core@0.6.0
-
Add routing key parameters with type validation for all exchange types
This release introduces comprehensive routing key parameter support with compile-time type validation:
New Features:
- Added routing key parameter support for topic and direct exchanges
- Implemented type-level validation for routing keys and binding patterns
RoutingKey<T>type validates routing key format and character setBindingPattern<T>type validates AMQP pattern syntax (*, #)MatchingRoutingKey<Pattern, Key>validates key matches pattern
- Enhanced
definePublisherFirstanddefineConsumerFirstfunctions:createPublisher()accepts routing key parameter for topic exchangescreateConsumer()accepts optional routing key pattern
- Routing key validation ensures AMQP compliance at compile-time:
- Validates allowed characters (a-z, A-Z, 0-9, -, _)
- Validates proper segment formatting with dot separators
- Implements AMQP topic exchange pattern matching logic
Type Safety Improvements:
- When consumer uses pattern with wildcards (e.g., "order.*"), publishers can use any matching string
- When consumer uses concrete key, publishers must use exact same key
- When publisher uses concrete key, consumers can use any pattern
- Pattern matching logic:
*matches exactly one word#matches zero or more words
Usage Example:
// Topic exchange with routing key parameters const consumer = defineConsumerFirst( topicExchange, "order.*", // Pattern with wildcard orderSchema, ); // Publishers can specify concrete keys matching the pattern const publisher = consumer.createPublisher("order.created"); // Or define publisher first with concrete key const publisher2 = definePublisherFirst( topicExchange, "order.updated", // Concrete routing key orderSchema, ); // Consumers can subscribe with any pattern const consumer2 = publisher2.createConsumer("order.*");
This feature provides end-to-end type safety for routing keys and binding patterns, catching configuration errors at compile time rather than runtime.
- Updated dependencies
- @amqp-contract/contract@0.5.0
- @amqp-contract/core@0.5.0
-
Release version 0.4.0
This release includes stability improvements and prepares the packages for wider adoption.
- Updated dependencies
- @amqp-contract/contract@0.4.0
- @amqp-contract/core@0.4.0
- @amqp-contract/contract@0.3.5
- @amqp-contract/core@0.3.5
-
Add generic type parameters to NestJS module forRoot/forRootAsync methods
This change replaces ConfigurableModuleBuilder with manual forRoot/forRootAsync implementations that support generic type parameters. This enables full type safety for worker handlers and client publishers based on the specific contract type.
BREAKING CHANGE: MODULE_OPTIONS_TOKEN is now a Symbol instead of string|symbol union
-
Updated dependencies
- @amqp-contract/contract@0.3.4
- @amqp-contract/core@0.3.4
- @amqp-contract/contract@0.3.3
- @amqp-contract/core@0.3.3
-
Add optional Logger interface for message publishing and consumption
This release introduces an optional Logger interface that allows users to integrate their preferred logging framework with amqp-contract:
New Features:
- Added
Loggerinterface in@amqp-contract/corewith debug, info, warn, and error methods - Added
LoggerContexttype for structured logging context - Client and Worker now accept an optional
loggeroption to enable message logging - NestJS modules support logger injection
Usage:
// Simple console logger implementation const logger: Logger = { debug: (message, context) => console.debug(message, context), info: (message, context) => console.info(message, context), warn: (message, context) => console.warn(message, context), error: (message, context) => console.error(message, context), }; // Use with client const client = await TypedAmqpClient.create({ contract, urls, logger, }); // Use with worker const worker = await TypedAmqpWorker.create({ contract, urls, logger, });
- Added
-
Updated dependencies
- @amqp-contract/core@0.3.2
- @amqp-contract/contract@0.3.2
- @amqp-contract/contract@0.3.1
- @amqp-contract/core@0.3.1
-
Add waitForConnectionReady feature
This release introduces connection readiness handling with the following changes:
Breaking Changes:
TypedAmqpClient.create()now returnsFuture<Result<TypedAmqpClient, TechnicalError>>instead of directly returning the client instanceTypedAmqpWorker.create()now returnsFuture<Result<TypedAmqpWorker, TechnicalError>>instead of directly returning the worker instance
New Features:
- Added
waitForConnectionReady()method to ensure AMQP connection is established before operations - Improved error handling with explicit Result types for connection failures
Migration Guide: Update your client/worker creation code to handle the new async Result type:
Before:
const client = TypedAmqpClient.create({ contract, urls });
After:
const result = await TypedAmqpClient.create({ contract, urls }); if (result.isError()) { // Handle connection error console.error("Failed to create client:", result.getError()); return; } const client = result.get();
- Updated dependencies
- @amqp-contract/contract@0.3.0
- @amqp-contract/core@0.3.0
- Documentation improvements including TypeDoc-generated API documentation and standardized package READMEs with badges and documentation links.
- Updated dependencies
- @amqp-contract/contract@0.2.1
- @amqp-contract/core@0.2.1
-
Extract AMQP setup logic into core package
This release introduces a new
@amqp-contract/corepackage that centralizes AMQP infrastructure setup logic. The core package provides asetupInfrafunction that handles the creation of exchanges, queues, and bindings, eliminating code duplication across client and worker packages.New Features:
- New
@amqp-contract/corepackage with centralized AMQP setup logic setupInfrafunction for creating exchanges, queues, and bindings from contract definitions
Changes:
- Updated
@amqp-contract/clientto use core setup function - Updated
@amqp-contract/workerto use core setup function - All packages are now versioned together as a fixed group
Migration: No breaking changes. Existing code will continue to work as before. The core package is used internally by client and worker packages.
- New
- Updated dependencies
- @amqp-contract/core@0.2.0
- @amqp-contract/contract@0.2.0
- @amqp-contract/contract@0.1.4
- Add exchange-to-exchange binding support
- Updated dependencies
- @amqp-contract/contract@0.1.3
- Fix: configurable module type
- Updated dependencies
- @amqp-contract/contract@0.1.2
- 498358d: Patch version bump for all packages
- Updated dependencies [498358d]
- @amqp-contract/contract@0.1.1
-
Replace exceptions with explicit Result error handling for client
BREAKING CHANGE: The client
publish()method now returns aResult<void, MessageValidationError>instead of throwing exceptions. Update your code to handle the Result type:// Before (0.0.6) try { await client.publish.orderCreated({ orderId: "123", amount: 100 }); } catch (error) { // Handle error } // After (0.1.0) const result = client.publish.orderCreated({ orderId: "123", amount: 100 }); if (result.isError()) { // Handle error: result.error }
This change provides more explicit and type-safe error handling, making it easier to handle validation failures at compile time.
- @amqp-contract/contract@0.1.0
- Release version 0.0.6 for all packages
- Updated dependencies
- @amqp-contract/contract@0.0.6
- Refactor to use factory pattern with static create() methods. Remove unnecessary type casts and improve internal implementation.
- Updated dependencies
- @amqp-contract/contract@0.0.5
- Release version 0.0.4
- Updated dependencies
- @amqp-contract/contract@0.0.4
-
Refactor createClient and createWorker to accept options object and auto-connect
- createClient now accepts { contract, connection } and auto-connects
- createWorker now accepts { contract, handlers, connection } and auto-connects/consumeAll
- Updated all tests and samples to use new API
-
Documentation updates and API improvements for 0.0.4 release
-
Updated dependencies
- @amqp-contract/contract@0.0.3
- Release version 0.0.2
- Updated dependencies
- @amqp-contract/contract@0.0.2