@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 +42 -51
- package/dist/index.cjs +83 -0
- package/dist/index.d.cts +528 -1
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +528 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +82 -1
- package/dist/index.mjs.map +1 -1
- package/docs/index.md +276 -51
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -16,76 +16,67 @@
|
|
|
16
16
|
pnpm add @amqp-contract/contract
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
-
##
|
|
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,
|
|
26
|
+
import { definePublisherFirst, defineContract, defineExchange, defineQueue, defineMessage } from '@amqp-contract/contract';
|
|
23
27
|
import { z } from 'zod';
|
|
24
28
|
|
|
25
|
-
//
|
|
29
|
+
// Event-oriented pattern: publisher doesn't need to know about queues
|
|
26
30
|
const ordersExchange = defineExchange('orders', 'topic', { durable: true });
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
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
|
-
//
|
|
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
|
-
|
|
47
|
-
|
|
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:
|
|
74
|
-
|
|
75
|
-
}),
|
|
76
|
-
processAnalytics: defineConsumer(analyticsProcessingQueue, orderMessage),
|
|
57
|
+
processOrder: consumer,
|
|
58
|
+
trackOrders: analyticsConsumer,
|
|
77
59
|
},
|
|
78
60
|
});
|
|
79
61
|
```
|
|
80
62
|
|
|
81
|
-
|
|
63
|
+
**Benefits:**
|
|
82
64
|
|
|
83
|
-
|
|
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;
|