You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat!: harden the runtime and finalize the 3.0 API surface
Full pre-release review sweep. Runtime fixes:
- compression: self-encode wire content (ACM json mode corrupted every
compressed publish into a JSON-serialized Buffer); retry republishes
raw bytes
- worker.close() drains in-flight handlers (drainTimeoutMs, default 30s)
and the defensive nacks can no longer crash the process on a close race
- per-consumer prefetch uses ACM's native consume option (no more QoS
bleed across consumers on reconnect)
- classic-queue immediate-requeue retries republish to the failing queue
via the default exchange, not the original exchange
- connection pool: idempotent leases, close/create race fixed, rejecting
close no longer poisons the key; AmqpClient.close() memoized
- telemetry helpers and the interceptor chain never throw into the data
path; create() routes constructor throws to the defect channel
- handlers with non-callable entries fail fast at create()
Breaking API changes (3.0 window):
- defineHandler(s)/defineMiddleware -> declareHandler(s)/declareMiddleware
- defineRpc errors entries are { data, message? }
- defineContract accepts standalone exchanges/queues/bindings
- worker middleware accepts arrays; ConsumerOptions curated (noAck gone)
- RPC handler responses typed as schema input; testing wait options are
{ count, timeoutMs }; asyncapi failOnMissingConverter defaults true;
invalid connectTimeoutMs is a defect; deprecated _*ForTesting aliases
removed; export-hygiene pass across all six packages
New guarding tests for every fix; tests/ package now typechecks in CI.
Pre-3.0 API review: breaking changes taken while the major window is open.
11
+
12
+
-**`defineHandler` / `defineHandlers` / `defineMiddleware` → `declareHandler` / `declareHandlers` / `declareMiddleware`.** The family convention (shared with temporal-contract) is `define*` for contract authoring and `declare*` for implementation-side APIs, making the contract boundary visible in the name.
13
+
-**`defineRpc` error map entries are now `{ data: schema, message? }`** instead of `defineMessage(schema)`. `data` is the raw Standard Schema for the error payload; the optional `message` is a default human-readable message used when the handler constructs the error without one (and as the client-side fallback when a reply carries none).
14
+
-**`defineContract` accepts standalone topology**: top-level `exchanges`, `queues`, and `bindings` entries declare resources with no publisher/consumer attached (a DLQ bound to the auto-extracted DLX, audit queues). Dead-letter exchanges and TTL-backoff infrastructure are auto-extracted for standalone queues exactly as for consumer queues.
15
+
-**Worker `middleware` accepts an array** (first = outermost), composed like `composeMiddleware(...)`. Pre-compose with `composeMiddleware` when you want stepwise context types inferred.
16
+
-**`worker.close()` now drains in-flight handlers** before closing the channel (their acks land; completed work is not redelivered), bounded by a new `drainTimeoutMs` option (default `DEFAULT_DRAIN_TIMEOUT_MS` = 30 s; `null` waits forever).
17
+
-**Worker `ConsumerOptions` is now a curated subset** (`prefetch`, `priority`, `arguments`, `consumerTag`, `exclusive`). `noAck` is gone — it silently broke the ack-exactly-once and retry/DLQ invariants.
18
+
-**RPC handler response types use the schema's _input_** (defaults optional, transforms not yet applied) — the worker validates before replying, matching the existing RPC error-data convention.
19
+
-**Invalid `connectTimeoutMs`** (NaN, 0, negative, Infinity) now surfaces as a Defect from `create()` instead of silently disabling the timeout. Pass `null` to disable.
20
+
-**Testing fixture wait options renamed**: `{ nbEvents, timeout }` → `{ count, timeoutMs }`, aligning with the library-wide `timeoutMs` convention. The fixture record is exported as `AmqpTestFixtures`, the wait options as `WaitForMessagesOptions`; the package now exposes `./package.json`.
21
+
-**`@amqp-contract/asyncapi`: `failOnMissingConverter` defaults to `true`** — a spec that silently degrades schemas to `{ type: "object" }` placeholders lies to its consumers. It generates AsyncAPI 3.1 (docs previously claimed 3.0).
22
+
-**Deprecated `_*ForTesting` aliases removed** from `@amqp-contract/core` (`_resetConnectionsForTesting`, `_getConnectionCountForTesting`, `_resetTelemetryCacheForTesting`) — use the `_internal_*` forms.
23
+
-**Export hygiene**: `RetryOptions`, `NoneRetryOptions`, `DefineQueueOptionsWithDeadLetterExchange`, `QueueEntryWithDeadLetterExchange`, `RpcErrorDefinition`, `InferSchemaInput`, `InferSchemaOutput` (contract); `PublishError`, `CallError`, `ClientInferCallError` (client); `AnyWorkerMiddleware`, `DEFAULT_DRAIN_TIMEOUT_MS` (worker); `isTechnicalError`, `isMessageValidationError` guards (core). Client and worker re-export `Logger`, `LoggerContext`, `TelemetryProvider`, and `TechnicalError` so naming an option type never forces a direct dependency on core. `defineCommandPublisher` now preserves literal routing-key types. All packages declare `sideEffects: false`.
-**Compression was broken end-to-end**: the channel's JSON mode serialized the compressed Buffer into `'{"type":"Buffer","data":[...]}'` on the wire, so every compressed publish was DLQ'd on arrival. The client now encodes content itself (JSON for plain values, byte-for-byte for Buffers) and JSON mode is off. Retry republishing now passes the original bytes through untouched for all content types.
11
+
-**Per-consumer `prefetch` no longer bleeds across consumers**: it now maps to amqp-connection-manager's native per-consumer prefetch, applied immediately before each `basic.consume` and re-applied per-consumer on reconnect (previously, any reconnect applied one consumer's QoS to all).
12
+
-**Classic-queue immediate-requeue retries republish to the failing queue via the default exchange** instead of the original exchange — a fanout/topic topology no longer delivers retry duplicates (and foreign retry headers) to sibling queues.
13
+
-**Closing a worker under load can no longer crash the process**: the defensive nack in the consume boundary is guarded (a nack racing channel teardown was an unhandled rejection), and `close()` drains in-flight handlers first.
14
+
-**Connection pool races fixed**: releases are idempotent per-lease (a double `close()` can no longer close a shared connection under another live client), the last release removes the pool entry _before_ closing (an acquire racing it gets a fresh connection instead of a dead one), and a rejecting close no longer poisons the pool key. `AmqpClient.close()` is memoized (idempotent).
15
+
-**Sync-throw escape hatches closed on the client**: a synchronously-throwing publish/call interceptor now resolves to a Defect instead of escaping `publish()`/`call()` as a raw throw, and all telemetry helpers swallow provider/span throws (a buggy TelemetryProvider degrades to "no telemetry" instead of poisoning the data path or converting a successful publish into a Defect). `create()` routes synchronous constructor throws to the defect channel.
16
+
-**`handlers: { name: undefined }` now fails fast** at `create()` / `declareHandlers` with a clear error instead of defecting on every delivery.
Handlers can be organized in separate files using `defineHandler` or `defineHandlers`. The `src/handlers.ts` file demonstrates this pattern, which is recommended for:
48
+
Handlers can be organized in separate files using `declareHandler` or `declareHandlers`. The `src/handlers.ts` file demonstrates this pattern, which is recommended for:
49
49
50
50
- Production applications
51
51
- Better code organization and testability
@@ -54,7 +54,7 @@ Handlers can be organized in separate files using `defineHandler` or `defineHand
The main `src/index.ts` file uses inline handlers for simplicity, while `src/handlers.ts` provides an example of how to organize handlers externally for better maintainability.
0 commit comments