@amqp-contract/contract 0.3.5 → 0.5.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.
package/README.md CHANGED
@@ -16,76 +16,67 @@
16
16
  pnpm add @amqp-contract/contract
17
17
  ```
18
18
 
19
- ## Usage
19
+ ## Quick Start
20
+
21
+ ### Recommended: Publisher-First / Consumer-First Patterns
22
+
23
+ For robust contract definitions with guaranteed consistency, use `definePublisherFirst` (for events) or `defineConsumerFirst` (for commands):
20
24
 
21
25
  ```typescript
22
- import { defineContract, defineExchange, defineQueue, defineQueueBinding, defineExchangeBinding, definePublisher, defineConsumer, defineMessage } from '@amqp-contract/contract';
26
+ import { definePublisherFirst, defineContract, defineExchange, defineQueue, defineMessage } from '@amqp-contract/contract';
23
27
  import { z } from 'zod';
24
28
 
25
- // Define exchanges and queues first so they can be referenced
29
+ // Event-oriented pattern: publisher doesn't need to know about queues
26
30
  const ordersExchange = defineExchange('orders', 'topic', { durable: true });
27
- const analyticsExchange = defineExchange('analytics', 'topic', { durable: true });
28
- const orderProcessingQueue = defineQueue('order-processing', { durable: true });
29
- const analyticsProcessingQueue = defineQueue('analytics-processing', { durable: true });
30
-
31
- // Define message schemas with metadata
32
- const orderMessage = defineMessage(
33
- z.object({
34
- orderId: z.string(),
35
- amount: z.number(),
36
- }),
37
- {
38
- summary: 'Order created event',
39
- description: 'Emitted when a new order is created',
40
- }
31
+ const orderMessage = defineMessage(z.object({
32
+ orderId: z.string(),
33
+ amount: z.number(),
34
+ }));
35
+
36
+ const orderCreatedEvent = definePublisherFirst(
37
+ ordersExchange,
38
+ orderMessage,
39
+ { routingKey: 'order.created' }
41
40
  );
42
41
 
43
- // Define your contract using object references
42
+ // Multiple queues can consume the same event
43
+ const orderQueue = defineQueue('order-processing', { durable: true });
44
+ const { consumer, binding } = orderCreatedEvent.createConsumer(orderQueue);
45
+
46
+ // For topic exchanges, consumers can override with their own pattern
47
+ const analyticsQueue = defineQueue('analytics', { durable: true });
48
+ const { consumer: analyticsConsumer, binding: analyticsBinding } =
49
+ orderCreatedEvent.createConsumer(analyticsQueue, 'order.*'); // Subscribe to all order events
50
+
44
51
  const contract = defineContract({
45
- exchanges: {
46
- orders: ordersExchange,
47
- analytics: analyticsExchange,
48
- },
49
- queues: {
50
- orderProcessing: orderProcessingQueue,
51
- analyticsProcessing: analyticsProcessingQueue,
52
- },
53
- bindings: {
54
- // Queue-to-exchange binding
55
- orderBinding: defineQueueBinding(orderProcessingQueue, ordersExchange, {
56
- routingKey: 'order.created',
57
- }),
58
- // Exchange-to-exchange binding
59
- analyticsBinding: defineExchangeBinding(analyticsExchange, ordersExchange, {
60
- routingKey: 'order.#',
61
- }),
62
- // Queue receives from analytics exchange
63
- analyticsQueueBinding: defineQueueBinding(analyticsProcessingQueue, analyticsExchange, {
64
- routingKey: 'order.#',
65
- }),
66
- },
67
- publishers: {
68
- orderCreated: definePublisher(ordersExchange, orderMessage, {
69
- routingKey: 'order.created',
70
- }),
71
- },
52
+ exchanges: { orders: ordersExchange },
53
+ queues: { orderQueue, analyticsQueue },
54
+ bindings: { orderBinding: binding, analyticsBinding },
55
+ publishers: { orderCreated: orderCreatedEvent.publisher },
72
56
  consumers: {
73
- processOrder: defineConsumer(orderProcessingQueue, orderMessage, {
74
- prefetch: 10,
75
- }),
76
- processAnalytics: defineConsumer(analyticsProcessingQueue, orderMessage),
57
+ processOrder: consumer,
58
+ trackOrders: analyticsConsumer,
77
59
  },
78
60
  });
79
61
  ```
80
62
 
81
- ## API
63
+ **Benefits:**
82
64
 
83
- For complete API documentation, see the [Contract API Reference](https://btravers.github.io/amqp-contract/api/contract).
65
+ - Guaranteed message schema consistency between publishers and consumers
66
+ - ✅ Routing key validation and type safety
67
+ - ✅ Full type safety with TypeScript inference
68
+ - ✅ Event-oriented (publisher-first) and command-oriented (consumer-first) patterns
69
+ - ✅ Flexible routing key patterns for topic exchanges
84
70
 
85
71
  ## Documentation
86
72
 
87
73
  📖 **[Read the full documentation →](https://btravers.github.io/amqp-contract)**
88
74
 
75
+ - [Getting Started Guide](https://btravers.github.io/amqp-contract/guide/defining-contracts)
76
+ - [Publisher-First Pattern](https://btravers.github.io/amqp-contract/guide/defining-contracts#publisher-first-pattern)
77
+ - [Consumer-First Pattern](https://btravers.github.io/amqp-contract/guide/defining-contracts#consumer-first-pattern)
78
+ - [Complete API Reference](https://btravers.github.io/amqp-contract/api/contract)
79
+
89
80
  ## License
90
81
 
91
82
  MIT
package/dist/index.cjs CHANGED
@@ -287,13 +287,96 @@ function defineConsumer(queue, message, options) {
287
287
  function defineContract(definition) {
288
288
  return definition;
289
289
  }
290
+ /**
291
+ * Helper to call definePublisher with proper type handling.
292
+ * Type safety is enforced by overloaded public function signatures.
293
+ * @internal
294
+ */
295
+ function callDefinePublisher(exchange, message, options) {
296
+ if (exchange.type === "fanout") return definePublisher(exchange, message, options);
297
+ return definePublisher(exchange, message, options);
298
+ }
299
+ /**
300
+ * Helper to call defineQueueBinding with proper type handling.
301
+ * Type safety is enforced by overloaded public function signatures.
302
+ * @internal
303
+ */
304
+ function callDefineQueueBinding(queue, exchange, options) {
305
+ if (exchange.type === "fanout") return defineQueueBinding(queue, exchange, options);
306
+ return defineQueueBinding(queue, exchange, options);
307
+ }
308
+ /**
309
+ * Implementation of definePublisherFirst.
310
+ * @internal
311
+ */
312
+ function definePublisherFirst(exchange, message, options) {
313
+ const publisher = callDefinePublisher(exchange, message, options);
314
+ if (exchange.type === "topic") {
315
+ const createConsumer$1 = (queue, routingKey) => {
316
+ const binding = callDefineQueueBinding(queue, exchange, routingKey ? {
317
+ ...options,
318
+ routingKey
319
+ } : options);
320
+ return {
321
+ consumer: defineConsumer(queue, message),
322
+ binding
323
+ };
324
+ };
325
+ return {
326
+ publisher,
327
+ createConsumer: createConsumer$1
328
+ };
329
+ }
330
+ const createConsumer = (queue) => {
331
+ const binding = callDefineQueueBinding(queue, exchange, options);
332
+ return {
333
+ consumer: defineConsumer(queue, message),
334
+ binding
335
+ };
336
+ };
337
+ return {
338
+ publisher,
339
+ createConsumer
340
+ };
341
+ }
342
+ /**
343
+ * Implementation of defineConsumerFirst.
344
+ * @internal
345
+ */
346
+ function defineConsumerFirst(queue, exchange, message, options) {
347
+ const consumer = defineConsumer(queue, message);
348
+ const binding = callDefineQueueBinding(queue, exchange, options);
349
+ if (exchange.type === "topic") {
350
+ const createPublisher$1 = (routingKey) => {
351
+ return callDefinePublisher(exchange, message, {
352
+ ...options,
353
+ routingKey
354
+ });
355
+ };
356
+ return {
357
+ consumer,
358
+ binding,
359
+ createPublisher: createPublisher$1
360
+ };
361
+ }
362
+ const createPublisher = () => {
363
+ return callDefinePublisher(exchange, message, options);
364
+ };
365
+ return {
366
+ consumer,
367
+ binding,
368
+ createPublisher
369
+ };
370
+ }
290
371
 
291
372
  //#endregion
292
373
  exports.defineConsumer = defineConsumer;
374
+ exports.defineConsumerFirst = defineConsumerFirst;
293
375
  exports.defineContract = defineContract;
294
376
  exports.defineExchange = defineExchange;
295
377
  exports.defineExchangeBinding = defineExchangeBinding;
296
378
  exports.defineMessage = defineMessage;
297
379
  exports.definePublisher = definePublisher;
380
+ exports.definePublisherFirst = definePublisherFirst;
298
381
  exports.defineQueue = defineQueue;
299
382
  exports.defineQueueBinding = defineQueueBinding;