Type-safe contracts for AMQP/RabbitMQ messaging with TypeScript
Define your AMQP contracts once — get type safety, autocompletion, and runtime validation everywhere.
- 🔒 End-to-end type safety — TypeScript knows your message shapes
- 🔄 Reliable retry — Built-in exponential backoff with Dead Letter Queue support
- 📄 AsyncAPI compatible — Generate documentation from your contracts
import {
defineContract,
defineExchange,
defineQueue,
defineEventPublisher,
defineEventConsumer,
defineMessage,
} from "@amqp-contract/contract";
import { TypedAmqpClient } from "@amqp-contract/client";
import { TypedAmqpWorker } from "@amqp-contract/worker";
import { Future, Result } from "@swan-io/boxed";
import { z } from "zod";
// 1. Define resources with Dead Letter Exchange and retry configuration
const ordersExchange = defineExchange("orders", "topic", { durable: true });
const ordersDlx = defineExchange("orders-dlx", "topic", { durable: true });
const orderProcessingQueue = defineQueue("order-processing", {
deadLetter: { exchange: ordersDlx, routingKey: "order.failed" },
retry: { mode: "ttl-backoff", maxRetries: 3, initialDelayMs: 1000 }, // Retry configured at queue level
});
// 2. Define message with schema validation
const orderMessage = defineMessage(
z.object({
orderId: z.string(),
amount: z.number(),
}),
);
// 3. Event pattern: publisher broadcasts, consumers subscribe
const orderCreatedEvent = defineEventPublisher(ordersExchange, orderMessage, {
routingKey: "order.created",
});
// 4. Define contract - configs go directly in publishers/consumers, bindings auto-generated
const contract = defineContract({
exchanges: { orders: ordersExchange, ordersDlx },
queues: { orderProcessing: orderProcessingQueue },
publishers: {
// EventPublisherConfig → auto-extracted to publisher
orderCreated: orderCreatedEvent,
},
consumers: {
// EventConsumerResult → auto-extracted to consumer + binding
processOrder: defineEventConsumer(orderCreatedEvent, orderProcessingQueue),
},
});
// 6. Type-safe publishing with validation
const client = await TypedAmqpClient.create({
contract,
urls: ["amqp://localhost"],
}).resultToPromise();
await client.publish("orderCreated", {
orderId: "ORD-123", // ✅ TypeScript knows!
amount: 99.99,
});
// 7. Type-safe consuming with automatic retry (configured at queue level)
const worker = await TypedAmqpWorker.create({
contract,
handlers: {
processOrder: ({ payload }) => {
console.log(payload.orderId); // ✅ TypeScript knows!
return Future.value(Result.Ok(undefined));
},
},
urls: ["amqp://localhost"],
}).resultToPromise();pnpm add @amqp-contract/contract @amqp-contract/client @amqp-contract/worker- Get Started — Get running in 5 minutes
- Core Concepts — Understand the fundamentals
- NestJS Integration — First-class NestJS support
- Examples — Real-world usage patterns
| Package | Description |
|---|---|
| @amqp-contract/contract | Contract builder and type definitions |
| @amqp-contract/client | Type-safe client for publishing |
| @amqp-contract/worker | Type-safe worker with retry support |
| @amqp-contract/client-nestjs | NestJS client integration |
| @amqp-contract/worker-nestjs | NestJS worker integration |
| @amqp-contract/asyncapi | AsyncAPI 3.0 generator |
See CONTRIBUTING.md.
MIT