diff --git a/README.md b/README.md index 2521cd7c..2889b510 100644 --- a/README.md +++ b/README.md @@ -79,11 +79,10 @@ const contract = defineContract({ }); // 6. Client - type-safe publishing with explicit error handling -const clientResult = await TypedAmqpClient.create({ contract, connection }); -if (clientResult.isError()) { - throw clientResult.error; // or handle error appropriately -} -const client = clientResult.get(); +const client = await TypedAmqpClient.create({ + contract, + urls: ["amqp://localhost"], +}).resultToPromise(); const result = await client.publish("orderCreated", { orderId: "ORD-123", // ✅ TypeScript knows! @@ -107,8 +106,8 @@ const worker = await TypedAmqpWorker.create({ console.log(message.orderId); // ✅ TypeScript knows! }, }, - connection, -}); + urls: ["amqp://localhost"], +}).resultToPromise(); ``` > **Note**: If your application both publishes and consumes messages, see the [Architecture Review](docs/review/2025-12-25-architecture-review.md#3-connection-sharing-analysis) for connection sharing strategies to optimize resource usage. @@ -144,12 +143,12 @@ import { contract } from "./contract"; console.log("Processing:", message.orderId); }, }, - connection: "amqp://localhost", + urls: ["amqp://localhost"], }), // Client for publishing messages AmqpClientModule.forRoot({ contract, - connection: "amqp://localhost", + urls: ["amqp://localhost"], }), ], }) diff --git a/docs/TERMINOLOGY.md b/docs/TERMINOLOGY.md index afcdbb3d..09b36857 100644 --- a/docs/TERMINOLOGY.md +++ b/docs/TERMINOLOGY.md @@ -80,8 +80,9 @@ When implementing the contract, we use our terms: ```typescript // Client = runtime publisher -const client = await TypedAmqpClient.create({ contract, urls }); -await client.publish("orderCreated", message); +const client = await TypedAmqpClient.create({ contract, urls }).resultToPromise(); + +await client.publish("orderCreated", message).resultToPromise(); // Worker = runtime consumer const worker = await TypedAmqpWorker.create({ @@ -92,7 +93,7 @@ const worker = await TypedAmqpWorker.create({ }, }, urls, -}); +}).resultToPromise(); ``` These terms (`TypedAmqpClient`, `TypedAmqpWorker`) describe the **runtime components** that implement the contract. @@ -148,14 +149,15 @@ await publisher.publish(exchange, routingKey, message); const consumer = await createConsumer(queue, handler); // amqp-contract uses: -const client = await TypedAmqpClient.create({ contract, urls }); -await client.publish("orderCreated", message); +const client = await TypedAmqpClient.create({ contract, urls }).resultToPromise(); + +await client.publish("orderCreated", message).resultToPromise(); const worker = await TypedAmqpWorker.create({ contract, handlers: { processOrder: handler }, urls, -}); +}).resultToPromise(); ``` The functionality is identical; only the naming differs. diff --git a/docs/adr/002-separate-packages.md b/docs/adr/002-separate-packages.md index b4087472..54999731 100644 --- a/docs/adr/002-separate-packages.md +++ b/docs/adr/002-separate-packages.md @@ -305,8 +305,9 @@ Each can be used independently or together. ```typescript import { TypedAmqpClient } from '@amqp-contract/client'; -const client = await TypedAmqpClient.create({ contract, urls }); -await client.publish('orderCreated', { ... }); +const client = await TypedAmqpClient.create({ contract, urls }).resultToPromise(); + +await client.publish('orderCreated', { ... }).resultToPromise(); ``` **Use case**: API services, webhook handlers, event publishers diff --git a/docs/blog/introducing-amqp-contract.md b/docs/blog/introducing-amqp-contract.md index 5c60399d..5574c807 100644 --- a/docs/blog/introducing-amqp-contract.md +++ b/docs/blog/introducing-amqp-contract.md @@ -247,7 +247,7 @@ TypeScript catches errors before runtime: ```typescript // ❌ TypeScript error - "orderDeleted" doesn't exist in contract -await client.publish("orderDeleted", { orderId: "123" }); +await client.publish("orderDeleted", { orderId: "123" }).resultToPromise(); // ❌ TypeScript error - missing handler for "processOrder" await TypedAmqpWorker.create({ @@ -316,12 +316,12 @@ import { contract } from "./contract"; console.log("Processing:", message.orderId); }, }, - connection: process.env.RABBITMQ_URL, + urls: [process.env.RABBITMQ_URL], }), // Client module for publishing messages AmqpClientModule.forRoot({ contract, - connection: process.env.RABBITMQ_URL, + urls: [process.env.RABBITMQ_URL], }), ], }) diff --git a/docs/guide/client-nestjs-usage.md b/docs/guide/client-nestjs-usage.md index b7112c27..a3767171 100644 --- a/docs/guide/client-nestjs-usage.md +++ b/docs/guide/client-nestjs-usage.md @@ -97,7 +97,7 @@ import { contract } from "./contract"; imports: [ AmqpClientModule.forRoot({ contract, - connection: "amqp://localhost", + urls: ["amqp://localhost"], }), ], }) @@ -121,7 +121,7 @@ export class OrderService { async createOrder(customerId: string, amount: number, items: any[]) { const orderId = this.generateOrderId(); - const result = this.client.publish("orderCreated", { + const result = await this.client.publish("orderCreated", { orderId, customerId, amount, @@ -177,30 +177,53 @@ That's it! The client automatically connects when the application starts and dis ## Configuration with Environment Variables -Use `@nestjs/config` for environment-based configuration: +Use `@nestjs/config` with `registerAs` and Zod for type-safe configuration: ```typescript import { Module } from "@nestjs/common"; -import { ConfigModule, ConfigService } from "@nestjs/config"; +import { ConfigModule } from "@nestjs/config"; import { AmqpClientModule } from "@amqp-contract/client-nestjs"; import { contract } from "./contract"; +import { amqpConfig } from "./config/amqp.config"; @Module({ imports: [ - ConfigModule.forRoot(), + ConfigModule.forRoot({ + load: [amqpConfig], + }), AmqpClientModule.forRootAsync({ imports: [ConfigModule], - useFactory: (configService: ConfigService) => ({ + useFactory: () => ({ contract, - connection: configService.get("RABBITMQ_URL") || "amqp://localhost", + urls: [amqpConfig().url], }), - inject: [ConfigService], }), ], }) export class AppModule {} ``` +Create a config file with Zod validation: + +```typescript +// config/amqp.config.ts +import { registerAs } from "@nestjs/config"; +import { z } from "zod"; + +const amqpConfigSchema = z.object({ + url: z.string().url().default("amqp://localhost"), +}); + +export const amqpConfig = registerAs("amqp", () => { + const config = amqpConfigSchema.parse({ + url: process.env.RABBITMQ_URL, + }); + return config; +}); + +export type AmqpConfig = z.infer; +``` + Then set the environment variable: ```bash @@ -476,10 +499,13 @@ export const orderRouter = initServer.router({ const orderId = generateOrderId(); - await client.publish("orderCreated", { - orderId, - ...input, - }); + await client + .publish("orderCreated", { + orderId, + ...input, + }) + .mapError((error) => new Error(`Failed to publish order: ${error.message}`)) + .resultToPromise(); return { orderId, @@ -499,7 +525,7 @@ import { OrderService } from "./order.service"; imports: [ AmqpClientModule.forRoot({ contract, - connection: "amqp://localhost", + urls: ["amqp://localhost"], }), ], controllers: [OrderController], @@ -559,47 +585,53 @@ export class OrderEventService { async publishOrderCreated(order: any) { this.logger.log(`Publishing OrderCreated event for ${order.orderId}`); - await this.client.publish("orderCreated", order, { - persistent: true, - headers: { - "event-type": "OrderCreated", - "event-version": "1.0", - "aggregate-id": order.orderId, - timestamp: new Date().toISOString(), - }, - }); + await this.client + .publish("orderCreated", order, { + persistent: true, + headers: { + "event-type": "OrderCreated", + "event-version": "1.0", + "aggregate-id": order.orderId, + timestamp: new Date().toISOString(), + }, + }) + .resultToPromise(); } async publishOrderUpdated(order: any) { this.logger.log(`Publishing OrderUpdated event for ${order.orderId}`); - await this.client.publish("orderUpdated", order, { - persistent: true, - headers: { - "event-type": "OrderUpdated", - "event-version": "1.0", - "aggregate-id": order.orderId, - timestamp: new Date().toISOString(), - }, - }); + await this.client + .publish("orderUpdated", order, { + persistent: true, + headers: { + "event-type": "OrderUpdated", + "event-version": "1.0", + "aggregate-id": order.orderId, + timestamp: new Date().toISOString(), + }, + }) + .resultToPromise(); } async publishOrderCancelled(orderId: string) { this.logger.log(`Publishing OrderCancelled event for ${orderId}`); - await this.client.publish( - "orderCancelled", - { orderId }, - { - persistent: true, - headers: { - "event-type": "OrderCancelled", - "event-version": "1.0", - "aggregate-id": orderId, - timestamp: new Date().toISOString(), + await this.client + .publish( + "orderCancelled", + { orderId }, + { + persistent: true, + headers: { + "event-type": "OrderCancelled", + "event-version": "1.0", + "aggregate-id": orderId, + timestamp: new Date().toISOString(), + }, }, - }, - ); + ) + .resultToPromise(); } } ``` @@ -614,7 +646,7 @@ Use multiple clients for different domains: imports: [ AmqpClientModule.forRoot({ contract: orderContract, - connection: "amqp://localhost", + urls: ["amqp://localhost"], }), ], providers: [OrderService, OrderController], @@ -627,7 +659,7 @@ export class OrderModule {} imports: [ AmqpClientModule.forRoot({ contract: paymentContract, - connection: "amqp://localhost", + urls: ["amqp://localhost"], }), ], providers: [PaymentService, PaymentController], @@ -837,8 +869,8 @@ export class OrderService { this.logger.log(`Creating order ${orderId} for customer ${customerId}`); - try { - await this.client.publish( + await this.client + .publish( "orderCreated", { orderId, @@ -854,23 +886,15 @@ export class OrderService { "x-customer-id": customerId, }, }, - ); - - this.logger.log(`Order ${orderId} published successfully`); - return { orderId }; - } catch (error: unknown) { - if (error instanceof Error) { - this.logger.error(`Failed to publish order ${orderId}`, error.stack); - } else { - this.logger.error(`Failed to publish order ${orderId}`); - } + ) + .mapError((error) => { + this.logger.error(`Failed to publish order ${orderId}`, error); + return new Error(`Failed to create order: ${error.message}`); + }) + .resultToPromise(); - // Handle schema validation errors - if (this.isValidationError(error)) { - throw new BadRequestException("Invalid order data"); - } - throw error; - } + this.logger.log(`Order ${orderId} published successfully`); + return { orderId }; } private isValidationError(error: unknown): error is { issues: unknown } { @@ -916,22 +940,24 @@ export class OrderController { ```typescript [app.module.ts] import { Module } from "@nestjs/common"; -import { ConfigModule, ConfigService } from "@nestjs/config"; +import { ConfigModule } from "@nestjs/config"; import { AmqpClientModule } from "@amqp-contract/client-nestjs"; import { contract } from "./contract"; import { OrderService } from "./order.service"; import { OrderController } from "./order.controller"; +import { amqpConfig } from "./config/amqp.config"; @Module({ imports: [ - ConfigModule.forRoot(), + ConfigModule.forRoot({ + load: [amqpConfig], + }), AmqpClientModule.forRootAsync({ imports: [ConfigModule], - useFactory: (configService: ConfigService) => ({ + useFactory: () => ({ contract, - connection: configService.get("RABBITMQ_URL") || "amqp://localhost", + urls: [amqpConfig().url], }), - inject: [ConfigService], }), ], controllers: [OrderController], diff --git a/docs/guide/client-usage.md b/docs/guide/client-usage.md index 9fea0508..3f211687 100644 --- a/docs/guide/client-usage.md +++ b/docs/guide/client-usage.md @@ -84,11 +84,13 @@ result.match({ Override the routing key for specific messages: ```typescript -const result = await client.publish( - "orderCreated", - { orderId: "ORD-123", amount: 99.99 }, - { routingKey: "order.created.urgent" }, -); +const result = await client + .publish( + "orderCreated", + { orderId: "ORD-123", amount: 99.99 }, + { routingKey: "order.created.urgent" }, + ) + .resultToPromise(); ``` ### Message Properties @@ -96,17 +98,19 @@ const result = await client.publish( Set AMQP message properties: ```typescript -const result = await client.publish( - "orderCreated", - { orderId: "ORD-123", amount: 99.99 }, - { - options: { - persistent: true, - priority: 10, - headers: { "x-request-id": "req-123" }, +const result = await client + .publish( + "orderCreated", + { orderId: "ORD-123", amount: 99.99 }, + { + options: { + persistent: true, + priority: 10, + headers: { "x-request-id": "req-123" }, + }, }, - }, -); + ) + .resultToPromise(); ``` ## Connection Management @@ -161,24 +165,19 @@ async function main() { let client; try { - const clientResult = await TypedAmqpClient.create({ + client = await TypedAmqpClient.create({ contract, urls: ["amqp://localhost"], - }); - - if (clientResult.isError()) { - console.error("Failed to create client:", clientResult.error); - throw clientResult.error; - } - - client = clientResult.get(); - - const result = await client.publish("orderCreated", { - orderId: "ORD-123", - customerId: "CUST-456", - amount: 99.99, - items: [{ productId: "PROD-A", quantity: 2 }], - }); + }).resultToPromise(); + + const result = await client + .publish("orderCreated", { + orderId: "ORD-123", + customerId: "CUST-456", + amount: 99.99, + items: [{ productId: "PROD-A", quantity: 2 }], + }) + .resultToPromise(); result.match({ Ok: () => console.log("✅ Message published"), diff --git a/docs/guide/getting-started.md b/docs/guide/getting-started.md index 7e5b7a2b..4386aa66 100644 --- a/docs/guide/getting-started.md +++ b/docs/guide/getting-started.md @@ -185,17 +185,10 @@ import { TypedAmqpClient } from "@amqp-contract/client"; import { contract } from "./contract"; async function main() { - const clientResult = await TypedAmqpClient.create({ + const client = await TypedAmqpClient.create({ contract, urls: ["amqp://localhost"], - }); - - if (clientResult.isError()) { - console.error("Failed to create client:", clientResult.error); - throw clientResult.error; - } - - const client = clientResult.get(); + }).resultToPromise(); const result = await client.publish("orderCreated", { orderId: "ORD-123", @@ -228,7 +221,7 @@ import { TypedAmqpWorker } from "@amqp-contract/worker"; import { contract } from "./contract"; async function main() { - const workerResult = await TypedAmqpWorker.create({ + const worker = await TypedAmqpWorker.create({ contract, handlers: { processOrder: async (message) => { @@ -244,16 +237,9 @@ async function main() { }, }, urls: ["amqp://localhost"], - }); + }).resultToPromise(); - workerResult.match({ - Ok: (worker) => { - console.log("✅ Worker ready, waiting for messages..."); - }, - Error: (error) => { - throw error; - }, - }); + console.log("✅ Worker ready, waiting for messages..."); } main(); diff --git a/docs/guide/message-compression.md b/docs/guide/message-compression.md index 95132af2..a34076c6 100644 --- a/docs/guide/message-compression.md +++ b/docs/guide/message-compression.md @@ -47,26 +47,40 @@ const clientResult = await TypedAmqpClient.create({ const client = clientResult.get(); // Publish with gzip compression -await client.publish("orderCreated", { - orderId: "ORD-123", - items: [...], // Large array of items -}, { - compression: "gzip" -}).resultToPromise(); +await client + .publish( + "orderCreated", + { + orderId: "ORD-123", + items: [...], // Large array of items + }, + { + compression: "gzip", + }, + ) + .resultToPromise(); // Publish with deflate compression -await client.publish("orderCreated", { - orderId: "ORD-124", - items: [...], -}, { - compression: "deflate" -}).resultToPromise(); +await client + .publish( + "orderCreated", + { + orderId: "ORD-124", + items: [...], + }, + { + compression: "deflate", + }, + ) + .resultToPromise(); // Publish without compression -await client.publish("orderCreated", { - orderId: "ORD-125", - items: [], -}); +await client + .publish("orderCreated", { + orderId: "ORD-125", + items: [], + }) + .resultToPromise(); ``` ### Consuming Compressed Messages @@ -303,9 +317,11 @@ function shouldCompress(message: unknown): boolean { return JSON.stringify(message).length > SIZE_THRESHOLD; } -await client.publish("event", data, { - compression: shouldCompress(data) ? "gzip" : undefined, -}); +await client + .publish("event", data, { + compression: shouldCompress(data) ? "gzip" : undefined, + }) + .resultToPromise(); ``` ### 3. Monitor Performance diff --git a/docs/guide/testing.md b/docs/guide/testing.md index 34586b3e..b23eb53e 100644 --- a/docs/guide/testing.md +++ b/docs/guide/testing.md @@ -109,8 +109,8 @@ You can use the testing utilities with your AMQP contracts: ```typescript import { describe, expect } from "vitest"; import { it } from "@amqp-contract/testing/extension"; -import { createClient } from "@amqp-contract/client"; -import { createWorker } from "@amqp-contract/worker"; +import { TypedAmqpClient } from "@amqp-contract/client"; +import { TypedAmqpWorker } from "@amqp-contract/worker"; import { contract } from "./contract.js"; describe("Order Processing Contract", () => { @@ -119,20 +119,22 @@ describe("Order Processing Contract", () => { amqpConnectionUrl, }) => { // Create client - const client = await createClient(contract, { - connection: amqpConnection, - }); + const client = await TypedAmqpClient.create({ + contract, + urls: [amqpConnectionUrl], + }).resultToPromise(); // Create worker with handler const receivedOrders: unknown[] = []; - const worker = await createWorker(contract, { + const worker = await TypedAmqpWorker.create({ + contract, handlers: { processOrder: async (message) => { receivedOrders.push(message); }, }, urls: [amqpConnectionUrl], - }); + }).resultToPromise(); // Publish message const result = await client diff --git a/docs/guide/why-amqp-contract.md b/docs/guide/why-amqp-contract.md index 6a5ca044..0e5fb864 100644 --- a/docs/guide/why-amqp-contract.md +++ b/docs/guide/why-amqp-contract.md @@ -162,7 +162,7 @@ const result = await client.publish("orderCreated", { }); // 5. Consumer gets fully typed messages -const workerResult = await TypedAmqpWorker.create({ +const worker = await TypedAmqpWorker.create({ contract, handlers: { processOrder: async (message) => { @@ -172,7 +172,7 @@ const workerResult = await TypedAmqpWorker.create({ }, }, urls: ["amqp://localhost"], -}); +}).resultToPromise(); ``` ### 2. Automatic Validation @@ -199,17 +199,21 @@ TypeScript catches errors before runtime: ```typescript // ❌ TypeScript error at compile time -await client.publish("orderCreated", { - orderId: "ORD-123", - // Missing customerId and amount - TypeScript error! -}); +await client + .publish("orderCreated", { + orderId: "ORD-123", + // Missing customerId and amount - TypeScript error! + }) + .resultToPromise(); // ❌ TypeScript error for wrong types -await client.publish("orderCreated", { - orderId: 123, // Error: orderId must be string - customerId: "CUST-456", - amount: 99.99, -}); +await client + .publish("orderCreated", { + orderId: 123, // Error: orderId must be string + customerId: "CUST-456", + amount: 99.99, + }) + .resultToPromise(); ``` ### 4. Single Source of Truth diff --git a/docs/guide/worker-nestjs-usage.md b/docs/guide/worker-nestjs-usage.md index 268bcbcf..46b03570 100644 --- a/docs/guide/worker-nestjs-usage.md +++ b/docs/guide/worker-nestjs-usage.md @@ -117,7 +117,7 @@ import { contract } from "./contract"; // Your business logic here }, }, - connection: "amqp://localhost", + urls: ["amqp://localhost"], }), ], }) @@ -192,7 +192,7 @@ import { OrderService } from "./order.service"; } }, }, - connection: "amqp://localhost", + urls: ["amqp://localhost"], }), inject: [OrderService], }), @@ -230,7 +230,7 @@ import { OrderService } from "./order.service"; } }, }, - connection: configService.get("RABBITMQ_URL") || "amqp://localhost", + urls: [configService.get("RABBITMQ_URL") ?? "amqp://localhost"], }), inject: [ConfigService, OrderService], }), @@ -261,7 +261,7 @@ AmqpWorkerModule.forRoot({ // Message is automatically acked if no error is thrown }, }, - connection: "amqp://localhost", + urls: ["amqp://localhost"], }); ``` @@ -286,7 +286,7 @@ AmqpWorkerModule.forRoot({ } }, }, - connection: "amqp://localhost", + urls: ["amqp://localhost"], }); ``` @@ -339,7 +339,7 @@ AmqpWorkerModule.forRootAsync({ } }, }, - connection: "amqp://localhost", + urls: ["amqp://localhost"], }), inject: [OrderService], }); @@ -385,7 +385,7 @@ Create separate modules for different domains: // Handle order processing }, }, - connection: "amqp://localhost", + urls: ["amqp://localhost"], }), ], }) @@ -401,7 +401,7 @@ export class OrderWorkerModule {} // Handle payment processing }, }, - connection: "amqp://localhost", + urls: ["amqp://localhost"], }), ], }) @@ -671,7 +671,7 @@ import { OrderService, BusinessRuleError, TemporaryError } from "./order.service } }, }, - connection: configService.get("RABBITMQ_URL") || "amqp://localhost", + urls: [configService.get("RABBITMQ_URL") ?? "amqp://localhost"], }), inject: [ConfigService, OrderService], }), diff --git a/docs/review/2025-12-25-architecture-review.md b/docs/review/2025-12-25-architecture-review.md index e27009fa..bdfc0608 100644 --- a/docs/review/2025-12-25-architecture-review.md +++ b/docs/review/2025-12-25-architecture-review.md @@ -426,11 +426,13 @@ The project has successfully implemented automatic connection sharing using a si ```typescript // Type inference works perfectly: -const result = await client.publish("orderCreated", { - orderId: "ORD-123", // ✅ TypeScript knows the exact type - amount: 99.99, - // invalid: true // ❌ TypeScript catches this -}); +const result = await client + .publish("orderCreated", { + orderId: "ORD-123", // ✅ TypeScript knows the exact type + amount: 99.99, + // invalid: true // ❌ TypeScript catches this + }) + .resultToPromise(); ``` #### 2. Error Handling ⭐⭐⭐⭐⭐ diff --git a/packages/client-nestjs/README.md b/packages/client-nestjs/README.md index c42e6b2d..9d5d1f7c 100644 --- a/packages/client-nestjs/README.md +++ b/packages/client-nestjs/README.md @@ -27,7 +27,7 @@ import { contract } from "./contract"; imports: [ AmqpClientModule.forRoot({ contract, - connection: "amqp://localhost", + urls: ["amqp://localhost"], }), ], }) @@ -38,7 +38,7 @@ export class OrderService { constructor(private readonly client: AmqpClientService) {} async createOrder(orderId: string, amount: number) { - await this.client.publish("orderCreated", { orderId, amount }); + await this.client.publish("orderCreated", { orderId, amount }).resultToPromise(); } } ``` diff --git a/packages/client/README.md b/packages/client/README.md index ae6d58ee..ab3ee62e 100644 --- a/packages/client/README.md +++ b/packages/client/README.md @@ -37,10 +37,12 @@ if (clientResult.isError()) { const client = clientResult.get(); // Publish message with explicit error handling -const result = await client.publish("orderCreated", { - orderId: "ORD-123", - amount: 99.99, -}); +const result = await client + .publish("orderCreated", { + orderId: "ORD-123", + amount: 99.99, + }) + .resultToPromise(); // Handle errors explicitly - no exceptions thrown if (result.isError()) { diff --git a/packages/worker-nestjs/README.md b/packages/worker-nestjs/README.md index f24d485f..2c575123 100644 --- a/packages/worker-nestjs/README.md +++ b/packages/worker-nestjs/README.md @@ -32,7 +32,7 @@ import { contract } from "./contract"; console.log("Processing order:", message.orderId); }, }, - connection: "amqp://localhost", + urls: ["amqp://localhost"], }), ], }) diff --git a/samples/basic-order-processing-client-nestjs/README.md b/samples/basic-order-processing-client-nestjs/README.md index 8f1585cb..b2faaeee 100644 --- a/samples/basic-order-processing-client-nestjs/README.md +++ b/samples/basic-order-processing-client-nestjs/README.md @@ -62,10 +62,12 @@ export class OrderService { constructor(private readonly amqpClient: AmqpClientService) {} async createOrder(order: Order) { - const result = await this.amqpClient.publish("orderCreated", { - ...order, - createdAt: new Date().toISOString(), - }); + const result = await this.amqpClient + .publish("orderCreated", { + ...order, + createdAt: new Date().toISOString(), + }) + .resultToPromise(); if (result.isError()) { throw result.error; diff --git a/samples/basic-order-processing-contract/README.md b/samples/basic-order-processing-contract/README.md index 45753e82..466527c7 100644 --- a/samples/basic-order-processing-contract/README.md +++ b/samples/basic-order-processing-contract/README.md @@ -28,9 +28,11 @@ if (clientResult.isError()) { } const client = clientResult.get(); -await client.publish("orderCreated", { - /* fully typed */ -}); +await client + .publish("orderCreated", { + /* fully typed */ + }) + .resultToPromise(); ``` ## Patterns Demonstrated diff --git a/samples/message-compression-example/README.md b/samples/message-compression-example/README.md index 1fab6a75..5ee839aa 100644 --- a/samples/message-compression-example/README.md +++ b/samples/message-compression-example/README.md @@ -88,17 +88,21 @@ Compression is chosen when publishing, not when defining the contract: ```typescript // No compression -await client.publish("largeData", payload); +await client.publish("largeData", payload).resultToPromise(); // With GZIP compression -await client.publish("largeData", payload, { - compression: "gzip", -}); +await client + .publish("largeData", payload, { + compression: "gzip", + }) + .resultToPromise(); // With DEFLATE compression -await client.publish("largeData", payload, { - compression: "deflate", -}); +await client + .publish("largeData", payload, { + compression: "deflate", + }) + .resultToPromise(); ``` ### Automatic Decompression diff --git a/samples/priority-queue-example/README.md b/samples/priority-queue-example/README.md index 9f7c70bc..b4b7811c 100644 --- a/samples/priority-queue-example/README.md +++ b/samples/priority-queue-example/README.md @@ -92,13 +92,15 @@ const taskQueue = defineQueue("task-processing", { ```typescript // Publish a message with priority 10 (critical) -await client.publish( - "submitTask", - { taskId: "task-1", title: "Critical task", priority: 10, createdAt: now }, - { - priority: 10, // Set RabbitMQ message priority - }, -); +await client + .publish( + "submitTask", + { taskId: "task-1", title: "Critical task", priority: 10, createdAt: now }, + { + priority: 10, // Set RabbitMQ message priority + }, + ) + .resultToPromise(); ``` ### Worker Configuration (`src/worker.ts`)