@warlock.js/herald 5.28.0 → 5.30.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/CHANGELOG.md +12 -0
- package/cjs/index.cjs +10 -10
- package/cjs/index.cjs.map +1 -1
- package/esm/communicators/broker-registry.d.mts +1 -1
- package/esm/communicators/broker-registry.d.mts.map +1 -1
- package/esm/communicators/broker-registry.mjs +1 -1
- package/esm/communicators/broker-registry.mjs.map +1 -1
- package/esm/communicators/broker.d.mts +1 -1
- package/esm/communicators/broker.d.mts.map +1 -1
- package/esm/communicators/broker.mjs +1 -1
- package/esm/communicators/broker.mjs.map +1 -1
- package/esm/contracts/broker-driver.contract.d.mts +1 -1
- package/esm/contracts/broker-driver.contract.d.mts.map +1 -1
- package/esm/contracts/channel.contract.d.mts +1 -1
- package/esm/contracts/channel.contract.d.mts.map +1 -1
- package/esm/decorators/consumable.d.mts +1 -1
- package/esm/decorators/consumable.d.mts.map +1 -1
- package/esm/decorators/consumable.mjs +1 -1
- package/esm/decorators/consumable.mjs.map +1 -1
- package/esm/drivers/rabbitmq/rabbitmq-channel.d.mts +1 -1
- package/esm/drivers/rabbitmq/rabbitmq-channel.d.mts.map +1 -1
- package/esm/drivers/rabbitmq/rabbitmq-channel.mjs +1 -1
- package/esm/drivers/rabbitmq/rabbitmq-channel.mjs.map +1 -1
- package/esm/drivers/rabbitmq/rabbitmq-driver.d.mts +1 -1
- package/esm/drivers/rabbitmq/rabbitmq-driver.d.mts.map +1 -1
- package/esm/drivers/rabbitmq/rabbitmq-driver.mjs +1 -1
- package/esm/drivers/rabbitmq/rabbitmq-driver.mjs.map +1 -1
- package/esm/message-managers/event-consumer.d.mts +1 -1
- package/esm/message-managers/event-consumer.d.mts.map +1 -1
- package/esm/message-managers/event-consumer.mjs +1 -1
- package/esm/message-managers/event-consumer.mjs.map +1 -1
- package/esm/message-managers/event-message.d.mts +1 -1
- package/esm/message-managers/event-message.d.mts.map +1 -1
- package/esm/message-managers/event-message.mjs +1 -1
- package/esm/message-managers/event-message.mjs.map +1 -1
- package/esm/message-managers/prepare-consumer-subscription.mjs +1 -1
- package/esm/message-managers/prepare-consumer-subscription.mjs.map +1 -1
- package/esm/message-managers/types.d.mts +1 -1
- package/esm/message-managers/types.d.mts.map +1 -1
- package/esm/types/channel.types.d.mts +1 -1
- package/esm/types/channel.types.d.mts.map +1 -1
- package/esm/types/connection.types.d.mts +1 -1
- package/esm/types/connection.types.d.mts.map +1 -1
- package/esm/types/driver.types.d.mts +1 -1
- package/esm/types/driver.types.d.mts.map +1 -1
- package/esm/types/message.types.d.mts +1 -1
- package/esm/types/message.types.d.mts.map +1 -1
- package/esm/types/publish.types.d.mts +1 -1
- package/esm/types/publish.types.d.mts.map +1 -1
- package/esm/types/registry.types.d.mts +1 -1
- package/esm/types/registry.types.d.mts.map +1 -1
- package/esm/types/subscribe.types.d.mts +1 -1
- package/esm/types/subscribe.types.d.mts.map +1 -1
- package/esm/use-case-broadcast.d.mts +1 -1
- package/esm/use-case-broadcast.d.mts.map +1 -1
- package/esm/use-case-broadcast.mjs +1 -1
- package/esm/use-case-broadcast.mjs.map +1 -1
- package/esm/utils/connect-to-broker.d.mts +1 -1
- package/esm/utils/connect-to-broker.d.mts.map +1 -1
- package/esm/utils/connect-to-broker.mjs +1 -1
- package/esm/utils/connect-to-broker.mjs.map +1 -1
- package/llms-full.txt +19 -19
- package/llms.txt +3 -3
- package/package.json +5 -4
- package/skills/README.md +4 -4
- package/skills/consume-message/SKILL.md +4 -4
- package/skills/herald-basics/SKILL.md +5 -5
- package/skills/publish-message/SKILL.md +7 -7
- package/skills/request-and-respond/SKILL.md +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-case-broadcast.mjs","names":[],"sources":["
|
|
1
|
+
{"version":3,"file":"use-case-broadcast.mjs","names":[],"sources":["../../../../../../../packages/herald/src/use-case-broadcast.ts"],"sourcesContent":["import { herald } from \"./utils/connect-to-broker\";\n\n/**\n * Minimal mirror of `@warlock.js/core`'s `UseCaseBroadcastEvent`.\n *\n * Kept local on purpose: this adapter is **structurally typed** so `@warlock.js/herald`\n * takes no dependency on `@warlock.js/core`. The shape only needs the fields the\n * adapter reads (`event` for the channel, `payload` for the body).\n */\nexport type UseCaseBroadcastEvent = {\n useCase: string;\n event: string;\n id: string;\n at: Date;\n payload: unknown;\n};\n\n/**\n * Channel adapter that publishes use-case broadcast events onto a herald broker.\n *\n * Register it in the use-cases config so successful use cases fan out to the bus:\n *\n * @example\n * // src/config/use-cases.ts\n * import { heraldBroadcast } from \"@warlock.js/herald\";\n *\n * export default {\n * broadcast: {\n * enabled: true,\n * channels: [heraldBroadcast({ broker: \"default\" })],\n * },\n * } satisfies UseCaseConfigurations;\n *\n * @param options - Optional broker name (defaults to the default broker)\n */\nexport function heraldBroadcast(options?: { broker?: string }) {\n return {\n async broadcast(event: UseCaseBroadcastEvent): Promise<void> {\n await herald(options?.broker).channel(event.event).publish(event.payload);\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAmCA,SAAgB,gBAAgB,SAA+B;CAC7D,OAAO,EACL,MAAM,UAAU,OAA6C;EAC3D,MAAM,OAAO,SAAS,MAAM,CAAC,CAAC,QAAQ,MAAM,KAAK,CAAC,CAAC,QAAQ,MAAM,OAAO;CAC1E,EACF;AACF"}
|
|
@@ -4,7 +4,7 @@ import { ChannelContract } from "../contracts/channel.contract.mjs";
|
|
|
4
4
|
import { EventMessage } from "../message-managers/event-message.mjs";
|
|
5
5
|
import { EventConsumerClass } from "../message-managers/types.mjs";
|
|
6
6
|
import { Broker } from "../communicators/broker.mjs";
|
|
7
|
-
//#region
|
|
7
|
+
//#region ../../packages/herald/src/utils/connect-to-broker.d.ts
|
|
8
8
|
/**
|
|
9
9
|
* Connect to a message broker and register it.
|
|
10
10
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connect-to-broker.d.mts","names":[],"sources":["
|
|
1
|
+
{"version":3,"file":"connect-to-broker.d.mts","names":[],"sources":["../../../../../../../../packages/herald/src/utils/connect-to-broker.ts"],"mappings":";;;;;;;;;;;;;;;AA0DA;;;;;;;;;;;;;AAAiF;AA6EjF;;;;AAA6C;AAoB7C;;;;;;;;;;;;;;;;;AAG2B;AAgB3B;;;;;;;;iBApHsB,eAAA,CAAgB,OAAA,EAAS,iBAAA,GAAoB,OAAA,CAAQ,MAAA;;;;;;;;AAoHqB;AAgBhG;;;;;;;;;;;;;;;;AACwC;;;;iBAxDxB,MAAA,CAAO,IAAA,YAAgB,MAAM;;;;;;;;;;;;;;;;;iBAoB7B,aAAA,qBACd,IAAA,UACA,OAAA,GAAU,cAAA,CAAe,QAAA,IACxB,eAAA,CAAgB,QAAA;;;;;;;;;;;;;iBAgBG,YAAA,YAAwB,MAAA,eAAqB,KAAA,EAAO,YAAA,CAAa,QAAA,IAAS,OAAA;;;;;;;;;;;;;iBAgB1E,iBAAA,YAA6B,MAAA,eACjD,QAAA,EAAU,kBAAA,CAAmB,QAAA,IAAS,OAAA"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { brokerRegistry } from "../communicators/broker-registry.mjs";
|
|
2
2
|
import "../communicators/index.mjs";
|
|
3
3
|
|
|
4
|
-
//#region
|
|
4
|
+
//#region ../../packages/herald/src/utils/connect-to-broker.ts
|
|
5
5
|
/**
|
|
6
6
|
* Connect to a message broker and register it.
|
|
7
7
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connect-to-broker.mjs","names":[],"sources":["
|
|
1
|
+
{"version":3,"file":"connect-to-broker.mjs","names":[],"sources":["../../../../../../../../packages/herald/src/utils/connect-to-broker.ts"],"sourcesContent":["import { Broker, brokerRegistry } from \"../communicators\";\nimport type { BrokerDriverContract, ChannelContract } from \"../contracts\";\nimport { type EventConsumerClass, EventMessage } from \"../message-managers\";\nimport type { ChannelOptions, ConnectionOptions, RabbitMQConnectionOptions } from \"../types\";\n\n/**\n * Connect to a message broker and register it.\n *\n * This is a high-level utility function that simplifies connection setup\n * for most projects. It handles driver instantiation, connection,\n * broker creation, and automatic registration.\n *\n * **Supported Drivers:**\n * - `rabbitmq` (default) - RabbitMQ/AMQP driver\n * - `kafka` - Apache Kafka driver (coming soon)\n *\n * @param options - Connection configuration options\n * @returns A connected and registered Broker instance\n * @throws {Error} If connection fails or driver is not implemented\n *\n * @example\n * ```typescript\n * // RabbitMQ connection\n * const broker = await connectToBroker({\n * driver: \"rabbitmq\",\n * host: \"localhost\",\n * port: 5672,\n * username: \"guest\",\n * password: \"guest\",\n * });\n *\n * // Use the broker\n * await broker.channel(\"user.created\").publish({ userId: 1 });\n * ```\n *\n * @example\n * ```typescript\n * // Multiple brokers\n * await connectToBroker({\n * driver: \"rabbitmq\",\n * name: \"notifications\",\n * isDefault: true,\n * host: process.env.RABBITMQ_HOST,\n * });\n *\n * await connectToBroker({\n * driver: \"rabbitmq\",\n * name: \"analytics\",\n * host: process.env.ANALYTICS_RABBITMQ_HOST,\n * });\n *\n * // Use default broker\n * herald().channel(\"notifications\").publish({ ... });\n *\n * // Use specific broker\n * herald(\"analytics\").channel(\"events\").publish({ ... });\n * ```\n */\nexport async function connectToBroker(options: ConnectionOptions): Promise<Broker> {\n // Default values\n const driverType = options.driver ?? \"rabbitmq\";\n const brokerName = options.name ?? \"default\";\n const isDefault = options.isDefault ?? true;\n\n // Create driver based on type\n let driver: BrokerDriverContract;\n\n switch (driverType) {\n case \"rabbitmq\": {\n const rabbitOptions = options as RabbitMQConnectionOptions;\n // Dynamic import to avoid requiring amqplib if not used\n const { RabbitMQDriver } = await import(\"../drivers/rabbitmq/rabbitmq-driver\");\n driver = new RabbitMQDriver(rabbitOptions);\n break;\n }\n\n case \"kafka\": {\n // const kafkaOptions = options as KafkaConnectionOptions;\n // Dynamic import to avoid requiring kafkajs if not used\n throw new Error(\n \"Kafka driver is not yet implemented. Coming soon! For now, please use RabbitMQ.\",\n );\n }\n\n default:\n throw new Error(`Unknown driver: \"${driverType}\". Supported drivers: rabbitmq, kafka`);\n }\n\n // Create broker\n const broker = brokerRegistry.register({\n name: brokerName,\n driver,\n isDefault,\n });\n\n // Connect to the message broker\n try {\n await driver.connect();\n } catch (error) {\n throw new Error(\n `Failed to connect to ${driverType}: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n\n return broker;\n}\n\n/**\n * Get a broker by name or the default one.\n *\n * This is the main entry point for using brokers in your application.\n * Named after the package — `herald()` carries your messages!\n *\n * @param name - Optional broker name (uses default if not provided)\n * @returns Broker instance\n * @throws MissingBrokerError if broker not found\n *\n * @example\n * // Get default broker\n * const channel = herald().channel(\"user.created\");\n * await channel.publish({ userId: 1 });\n *\n * // Get specific broker\n * const analyticsChannel = herald(\"analytics\").channel(\"events\");\n * await analyticsChannel.publish({ event: \"page_view\" });\n *\n * // Subscribe to messages\n * herald()\n * .channel<UserPayload>(\"user.created\")\n * .subscribe(async (message, ctx) => {\n * console.log(\"User created:\", message.payload);\n * await ctx.ack();\n * });\n * ```\n */\nexport function herald(name?: string): Broker {\n return brokerRegistry.get(name);\n}\n\n/**\n * Get channel instance for the given name from default broker.\n *\n * Shorthand for `herald().channel(name, options)`.\n *\n * @param name - Channel name\n * @param options - Optional channel options\n * @returns Channel instance\n * @throws MissingBrokerError if broker not found\n *\n * @example\n * ```typescript\n * const channel = heraldChannel(\"user.created\");\n * await channel.publish({ userId: 1 });\n * ```\n */\nexport function heraldChannel<TPayload = unknown>(\n name: string,\n options?: ChannelOptions<TPayload>,\n): ChannelContract<TPayload> {\n return herald().channel<TPayload>(name, options);\n}\n\n/**\n * Publish an EventMessage to the default broker.\n *\n * @param event - Event message to publish\n * @returns Promise that resolves when the event is published\n * @throws Error if the broker is not connected\n *\n * @example\n * ```typescript\n * await publishEvent(new UserUpdatedEvent({ id: 1, name: \"John Doe\" }));\n * ```\n */\nexport async function publishEvent<TPayload = Record<string, any>>(event: EventMessage<TPayload>) {\n return herald().publish(event);\n}\n\n/**\n * Subscribe an EventConsumer class to the default broker.\n *\n * @param Consumer - Event consumer class\n * @returns Unsubscribe function\n * @throws MissingBrokerError if broker not found\n *\n * @example\n * ```typescript\n * await subscribeConsumer(UserUpdatedConsumer);\n * ```\n */\nexport async function subscribeConsumer<TPayload = Record<string, any>>(\n Consumer: EventConsumerClass<TPayload>,\n) {\n return herald().subscribe(Consumer);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0DA,eAAsB,gBAAgB,SAA6C;CAEjF,MAAM,aAAa,QAAQ,UAAU;CACrC,MAAM,aAAa,QAAQ,QAAQ;CACnC,MAAM,YAAY,QAAQ,aAAa;CAGvC,IAAI;CAEJ,QAAQ,YAAR;EACE,KAAK,YAAY;GACf,MAAM,gBAAgB;GAEtB,MAAM,EAAE,mBAAmB,MAAM,OAAO;GACxC,SAAS,IAAI,eAAe,aAAa;GACzC;EACF;EAEA,KAAK,SAGH,MAAM,IAAI,MACR,iFACF;EAGF,SACE,MAAM,IAAI,MAAM,oBAAoB,WAAW,sCAAsC;CACzF;CAGA,MAAM,SAAS,eAAe,SAAS;EACrC,MAAM;EACN;EACA;CACF,CAAC;CAGD,IAAI;EACF,MAAM,OAAO,QAAQ;CACvB,SAAS,OAAO;EACd,MAAM,IAAI,MACR,wBAAwB,WAAW,IAAI,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GAC9F;CACF;CAEA,OAAO;AACT;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8BA,SAAgB,OAAO,MAAuB;CAC5C,OAAO,eAAe,IAAI,IAAI;AAChC;;;;;;;;;;;;;;;;;AAkBA,SAAgB,cACd,MACA,SAC2B;CAC3B,OAAO,OAAO,CAAC,CAAC,QAAkB,MAAM,OAAO;AACjD;;;;;;;;;;;;;AAcA,eAAsB,aAA6C,OAA+B;CAChG,OAAO,OAAO,CAAC,CAAC,QAAQ,KAAK;AAC/B;;;;;;;;;;;;;AAcA,eAAsB,kBACpB,UACA;CACA,OAAO,OAAO,CAAC,CAAC,UAAU,QAAQ;AACpC"}
|
package/llms-full.txt
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
---
|
|
10
10
|
name: consume-message
|
|
11
|
-
description: 'Subscribe to a channel via .subscribe(handler, options?) — handler receives (message, ctx). Control flow via ctx.ack / ctx.nack(requeue?) / ctx.reject / ctx.retry(delayMs). Configure prefetch, retry policy, dead-letter, consumer groups. Triggers: `subscribe`, `ctx.ack`, `ctx.nack`, `ctx.reject`, `ctx.retry`, `prefetch`, `group`, `retry`, `deadLetter`, `@Consumable`, `EventConsumer`, `defineConsumer`, `autoAck`; "consume messages from a queue", "implement a worker", "background queue processor", "set up retry and dead-letter", "class-based event consumer"; typical import `import { herald, Consumable, EventConsumer } from "@warlock.js/herald"`. Skip: setup —
|
|
11
|
+
description: 'Subscribe to a channel via .subscribe(handler, options?) — handler receives (message, ctx). Control flow via ctx.ack / ctx.nack(requeue?) / ctx.reject / ctx.retry(delayMs). Configure prefetch, retry policy, dead-letter, consumer groups. Triggers: `subscribe`, `ctx.ack`, `ctx.nack`, `ctx.reject`, `ctx.retry`, `prefetch`, `group`, `retry`, `deadLetter`, `@Consumable`, `EventConsumer`, `defineConsumer`, `autoAck`; "consume messages from a queue", "implement a worker", "background queue processor", "set up retry and dead-letter", "class-based event consumer"; typical import `import { herald, Consumable, EventConsumer } from "@warlock.js/herald"`. Skip: setup — the `herald-basics` topic; producing — the `publish-message` topic; RPC reply — the `request-and-respond` topic; competing libs `amqplib`, `bullmq`, `kafkajs`; NestJS `@MessagePattern` / `@EventPattern`.'
|
|
12
12
|
---
|
|
13
13
|
|
|
14
14
|
# Consume messages
|
|
@@ -117,7 +117,7 @@ herald().channel("user.created.failed").subscribe(async (message, ctx) => {
|
|
|
117
117
|
|
|
118
118
|
## Decorator-style consumers — `@Consumable` + `EventConsumer`
|
|
119
119
|
|
|
120
|
-
For class-based consumers that pair with the
|
|
120
|
+
For class-based consumers that pair with the `EventMessage` (the `publish-message` topic) producer layer. This is a **different handler shape** from the raw `.subscribe()` above — ack/nack is automatic, and you get the unwrapped payload plus an event-metadata object (no `ctx`):
|
|
121
121
|
|
|
122
122
|
```ts
|
|
123
123
|
import { Consumable, EventConsumer } from "@warlock.js/herald";
|
|
@@ -223,8 +223,8 @@ await channel.delete(); // remove the queue entirely
|
|
|
223
223
|
|
|
224
224
|
## See also
|
|
225
225
|
|
|
226
|
-
-
|
|
227
|
-
-
|
|
226
|
+
- The `publish-message` topic — the producing side
|
|
227
|
+
- The `request-and-respond` topic — when you need to reply to a message
|
|
228
228
|
|
|
229
229
|
|
|
230
230
|
## herald-basics `@warlock.js/herald/herald-basics/SKILL.md`
|
|
@@ -314,10 +314,10 @@ herald("analytics").channel("events").publish({ /* ... */ }); // → analytics
|
|
|
314
314
|
|
|
315
315
|
| If the task is about… | Load |
|
|
316
316
|
| --- | --- |
|
|
317
|
-
| Publishing messages — single + batch + publish options (priority, ttl, delay, persistent, headers) |
|
|
318
|
-
| Subscribing to messages — handler signature, message context (ack/nack/retry), prefetch, retry policy, dead-letter |
|
|
319
|
-
| Request/response (RPC) — `channel.request(...)` + `channel.respond(...)` for synchronous-style calls over a message bus |
|
|
320
|
-
| Schema-validated channels — `.channel(name, { schema })` with `@warlock.js/seal` | See
|
|
317
|
+
| Publishing messages — single + batch + publish options (priority, ttl, delay, persistent, headers) | the `publish-message` topic |
|
|
318
|
+
| Subscribing to messages — handler signature, message context (ack/nack/retry), prefetch, retry policy, dead-letter | the `consume-message` topic |
|
|
319
|
+
| Request/response (RPC) — `channel.request(...)` + `channel.respond(...)` for synchronous-style calls over a message bus | the `request-and-respond` topic |
|
|
320
|
+
| Schema-validated channels — `.channel(name, { schema })` with `@warlock.js/seal` | See the `seal-basics` topic of the `warlock-js-seal` skill + skills below |
|
|
321
321
|
|
|
322
322
|
## Things NOT to do
|
|
323
323
|
|
|
@@ -329,19 +329,19 @@ herald("analytics").channel("events").publish({ /* ... */ }); // → analytics
|
|
|
329
329
|
## See also
|
|
330
330
|
|
|
331
331
|
- README at `@warlock.js/herald/README.md` for the full API surface and RabbitMQ / Kafka driver config
|
|
332
|
-
-
|
|
332
|
+
- The `seal-basics` topic of the `warlock-js-seal` skill — schema validation
|
|
333
333
|
|
|
334
334
|
|
|
335
335
|
## publish-message `@warlock.js/herald/publish-message/SKILL.md`
|
|
336
336
|
|
|
337
337
|
---
|
|
338
338
|
name: publish-message
|
|
339
|
-
description: 'Publish messages to a channel — .publish(payload, options?) for single, .publishBatch([...], options?) for batch, with priority / ttl / delay / persistent / correlationId / headers options. Optional schema validation via .channel(name, {schema}). Triggers: `publish`, `publishBatch`, `channel`, `priority`, `ttl`, `delay`, `persistent`, `correlationId`, `headers`, `schema`; "publish a message", "emit an event after a domain change", "fan out a notification", "schedule delayed work", "batch publish"; typical import `import { herald } from "@warlock.js/herald"`. Skip: setup —
|
|
339
|
+
description: 'Publish messages to a channel — .publish(payload, options?) for single, .publishBatch([...], options?) for batch, with priority / ttl / delay / persistent / correlationId / headers options. Optional schema validation via .channel(name, {schema}). Triggers: `publish`, `publishBatch`, `channel`, `priority`, `ttl`, `delay`, `persistent`, `correlationId`, `headers`, `schema`; "publish a message", "emit an event after a domain change", "fan out a notification", "schedule delayed work", "batch publish"; typical import `import { herald } from "@warlock.js/herald"`. Skip: setup — the `herald-basics` topic; consuming — the `consume-message` topic; RPC — the `request-and-respond` topic; competing libs `amqplib`, `kafkajs`, `bullmq`; NestJS `ClientProxy.emit`.'
|
|
340
340
|
---
|
|
341
341
|
|
|
342
342
|
# Publish messages
|
|
343
343
|
|
|
344
|
-
Push messages into a channel. The consumer side picks them up via
|
|
344
|
+
Push messages into a channel. The consumer side picks them up via the `consume-message` topic.
|
|
345
345
|
|
|
346
346
|
## Single publish
|
|
347
347
|
|
|
@@ -384,7 +384,7 @@ const channel = herald().channel("user.created", { schema: userSchema });
|
|
|
384
384
|
await channel.publish({ userId: 1, email: "invalid" }); // Throws — fails .email()
|
|
385
385
|
```
|
|
386
386
|
|
|
387
|
-
The schema runs `validate()` before the message hits the broker. Invalid payloads never leave the producer. See
|
|
387
|
+
The schema runs `validate()` before the message hits the broker. Invalid payloads never leave the producer. See the `seal-basics` topic of the `warlock-js-seal` skill.
|
|
388
388
|
|
|
389
389
|
## Publish options
|
|
390
390
|
|
|
@@ -471,11 +471,11 @@ export const createUserUseCase = useCase({
|
|
|
471
471
|
});
|
|
472
472
|
```
|
|
473
473
|
|
|
474
|
-
The adapter publishes the broadcast envelope's `payload` to `channel(event.event)`. It's structurally typed, so herald keeps no dependency on core. See
|
|
474
|
+
The adapter publishes the broadcast envelope's `payload` to `channel(event.event)`. It's structurally typed, so herald keeps no dependency on core. See the `write-use-case` topic of the `warlock-js-core` skill for the `broadcast` option (payload projection, custom event name, payload-safety rules).
|
|
475
475
|
|
|
476
476
|
## Event classes (`EventMessage`) — the typed event layer
|
|
477
477
|
|
|
478
|
-
Raw `channel(name).publish(payload)` is the low-level path. For domain events that travel between modules, herald ships a higher-level pair: define the event once as a class, publish instances of it, and consume them with an
|
|
478
|
+
Raw `channel(name).publish(payload)` is the low-level path. For domain events that travel between modules, herald ships a higher-level pair: define the event once as a class, publish instances of it, and consume them with an `EventConsumer` (the `consume-message` topic). The channel name comes from the event's `eventName` — no string to keep in sync across producer and consumer.
|
|
479
479
|
|
|
480
480
|
```ts
|
|
481
481
|
import { defineEvent, publishEvent } from "@warlock.js/herald";
|
|
@@ -504,15 +504,15 @@ Set an optional `version` on the event (instance field) to drive the consumer's
|
|
|
504
504
|
|
|
505
505
|
## See also
|
|
506
506
|
|
|
507
|
-
-
|
|
508
|
-
-
|
|
507
|
+
- The `consume-message` topic — the receiving side
|
|
508
|
+
- The `request-and-respond` topic — when you need a reply
|
|
509
509
|
|
|
510
510
|
|
|
511
511
|
## request-and-respond `@warlock.js/herald/request-and-respond/SKILL.md`
|
|
512
512
|
|
|
513
513
|
---
|
|
514
514
|
name: request-and-respond
|
|
515
|
-
description: 'Synchronous-style RPC over the message bus — channel.request<R>(payload, {timeout}) waits for a reply, channel.respond(handler) registers the responder, ctx.reply(response) sends the answer. Triggers: `channel.request`, `channel.respond`, `ctx.reply`, `timeout`, `correlationId`, `headers.correlationId`; "RPC over message bus", "request-response across services", "wait for a reply", "internal service-to-service call instead of HTTP"; typical import `import { herald } from "@warlock.js/herald"`. Skip: setup —
|
|
515
|
+
description: 'Synchronous-style RPC over the message bus — channel.request<R>(payload, {timeout}) waits for a reply, channel.respond(handler) registers the responder, ctx.reply(response) sends the answer. Triggers: `channel.request`, `channel.respond`, `ctx.reply`, `timeout`, `correlationId`, `headers.correlationId`; "RPC over message bus", "request-response across services", "wait for a reply", "internal service-to-service call instead of HTTP"; typical import `import { herald } from "@warlock.js/herald"`. Skip: setup — the `herald-basics` topic; fire-and-forget — the `publish-message` topic; consumer ctx flow — the `consume-message` topic; competing libs `amqplib` RPC, `nats` request/reply; NestJS `ClientProxy.send`; gRPC; HTTP.'
|
|
516
516
|
---
|
|
517
517
|
|
|
518
518
|
# Request-response over the bus
|
|
@@ -582,7 +582,7 @@ Each `request()` generates its own correlation ID and an exclusive reply queue u
|
|
|
582
582
|
|
|
583
583
|
## See also
|
|
584
584
|
|
|
585
|
-
-
|
|
586
|
-
-
|
|
585
|
+
- The `publish-message` topic — fire-and-forget pattern
|
|
586
|
+
- The `consume-message` topic — subscribe + ctx flow control (including `ctx.reply`)
|
|
587
587
|
|
|
588
588
|
|
package/llms.txt
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
## Skills
|
|
8
8
|
|
|
9
|
-
- [consume-message](@warlock.js/herald/consume-message/SKILL.md): Subscribe to a channel via .subscribe(handler, options?) — handler receives (message, ctx). Control flow via ctx.ack / ctx.nack(requeue?) / ctx.reject / ctx.retry(delayMs). Configure prefetch, retry policy, dead-letter, consumer groups. Triggers: `subscribe`, `ctx.ack`, `ctx.nack`, `ctx.reject`, `ctx.retry`, `prefetch`, `group`, `retry`, `deadLetter`, `@Consumable`, `EventConsumer`, `defineConsumer`, `autoAck`; "consume messages from a queue", "implement a worker", "background queue processor", "set up retry and dead-letter", "class-based event consumer"; typical import `import { herald, Consumable, EventConsumer } from "@warlock.js/herald"`. Skip: setup —
|
|
9
|
+
- [consume-message](@warlock.js/herald/consume-message/SKILL.md): Subscribe to a channel via .subscribe(handler, options?) — handler receives (message, ctx). Control flow via ctx.ack / ctx.nack(requeue?) / ctx.reject / ctx.retry(delayMs). Configure prefetch, retry policy, dead-letter, consumer groups. Triggers: `subscribe`, `ctx.ack`, `ctx.nack`, `ctx.reject`, `ctx.retry`, `prefetch`, `group`, `retry`, `deadLetter`, `@Consumable`, `EventConsumer`, `defineConsumer`, `autoAck`; "consume messages from a queue", "implement a worker", "background queue processor", "set up retry and dead-letter", "class-based event consumer"; typical import `import { herald, Consumable, EventConsumer } from "@warlock.js/herald"`. Skip: setup — the `herald-basics` topic; producing — the `publish-message` topic; RPC reply — the `request-and-respond` topic; competing libs `amqplib`, `bullmq`, `kafkajs`; NestJS `@MessagePattern` / `@EventPattern`.
|
|
10
10
|
- [herald-basics](@warlock.js/herald/herald-basics/SKILL.md): Start here for @warlock.js/herald event publishing, consumers, request-response messaging, and configuration.
|
|
11
|
-
- [publish-message](@warlock.js/herald/publish-message/SKILL.md): Publish messages to a channel — .publish(payload, options?) for single, .publishBatch([...], options?) for batch, with priority / ttl / delay / persistent / correlationId / headers options. Optional schema validation via .channel(name, {schema}). Triggers: `publish`, `publishBatch`, `channel`, `priority`, `ttl`, `delay`, `persistent`, `correlationId`, `headers`, `schema`; "publish a message", "emit an event after a domain change", "fan out a notification", "schedule delayed work", "batch publish"; typical import `import { herald } from "@warlock.js/herald"`. Skip: setup —
|
|
12
|
-
- [request-and-respond](@warlock.js/herald/request-and-respond/SKILL.md): Synchronous-style RPC over the message bus — channel.request<R>(payload, {timeout}) waits for a reply, channel.respond(handler) registers the responder, ctx.reply(response) sends the answer. Triggers: `channel.request`, `channel.respond`, `ctx.reply`, `timeout`, `correlationId`, `headers.correlationId`; "RPC over message bus", "request-response across services", "wait for a reply", "internal service-to-service call instead of HTTP"; typical import `import { herald } from "@warlock.js/herald"`. Skip: setup —
|
|
11
|
+
- [publish-message](@warlock.js/herald/publish-message/SKILL.md): Publish messages to a channel — .publish(payload, options?) for single, .publishBatch([...], options?) for batch, with priority / ttl / delay / persistent / correlationId / headers options. Optional schema validation via .channel(name, {schema}). Triggers: `publish`, `publishBatch`, `channel`, `priority`, `ttl`, `delay`, `persistent`, `correlationId`, `headers`, `schema`; "publish a message", "emit an event after a domain change", "fan out a notification", "schedule delayed work", "batch publish"; typical import `import { herald } from "@warlock.js/herald"`. Skip: setup — the `herald-basics` topic; consuming — the `consume-message` topic; RPC — the `request-and-respond` topic; competing libs `amqplib`, `kafkajs`, `bullmq`; NestJS `ClientProxy.emit`.
|
|
12
|
+
- [request-and-respond](@warlock.js/herald/request-and-respond/SKILL.md): Synchronous-style RPC over the message bus — channel.request<R>(payload, {timeout}) waits for a reply, channel.respond(handler) registers the responder, ctx.reply(response) sends the answer. Triggers: `channel.request`, `channel.respond`, `ctx.reply`, `timeout`, `correlationId`, `headers.correlationId`; "RPC over message bus", "request-response across services", "wait for a reply", "internal service-to-service call instead of HTTP"; typical import `import { herald } from "@warlock.js/herald"`. Skip: setup — the `herald-basics` topic; fire-and-forget — the `publish-message` topic; consumer ctx flow — the `consume-message` topic; competing libs `amqplib` RPC, `nats` request/reply; NestJS `ClientProxy.send`; gRPC; HTTP.
|
package/package.json
CHANGED
|
@@ -8,12 +8,13 @@
|
|
|
8
8
|
"@mongez/copper": "^2.1.3",
|
|
9
9
|
"@mongez/events": "^2.2.8",
|
|
10
10
|
"@mongez/reinforcements": "^4.0.2",
|
|
11
|
-
"@warlock.js/logger": "5.
|
|
12
|
-
"@warlock.js/seal": "5.
|
|
11
|
+
"@warlock.js/logger": "5.30.0",
|
|
12
|
+
"@warlock.js/seal": "5.30.0"
|
|
13
13
|
},
|
|
14
14
|
"repository": {
|
|
15
15
|
"type": "git",
|
|
16
|
-
"url": "https://github.com/warlockjs/
|
|
16
|
+
"url": "git+https://github.com/warlockjs/framework.git",
|
|
17
|
+
"directory": "packages/herald"
|
|
17
18
|
},
|
|
18
19
|
"peerDependencies": {
|
|
19
20
|
"amqplib": "^0.10.0"
|
|
@@ -36,7 +37,7 @@
|
|
|
36
37
|
],
|
|
37
38
|
"author": "hassanzohdy",
|
|
38
39
|
"license": "MIT",
|
|
39
|
-
"version": "5.
|
|
40
|
+
"version": "5.30.0",
|
|
40
41
|
"main": "./cjs/index.cjs",
|
|
41
42
|
"module": "./esm/index.mjs",
|
|
42
43
|
"types": "./esm/index.d.mts",
|
package/skills/README.md
CHANGED
|
@@ -4,18 +4,18 @@ Per-task skills. All cross-references use the form `@warlock.js/<pkg>/<skill>/SK
|
|
|
4
4
|
|
|
5
5
|
## Skills
|
|
6
6
|
|
|
7
|
-
###
|
|
7
|
+
### `consume-message`
|
|
8
8
|
|
|
9
9
|
Subscribe to a channel via .subscribe(handler, options?) — handler receives (message, ctx). Control flow via ctx.ack / ctx.nack(requeue?) / ctx.reject / ctx.retry(delayMs). Configure prefetch, retry policy, dead-letter, consumer groups. Load when implementing a worker processing events, a queue background processor, or consuming an event log.
|
|
10
10
|
|
|
11
|
-
###
|
|
11
|
+
### `herald-basics`
|
|
12
12
|
|
|
13
13
|
Start with @warlock.js/herald — connectToBroker config, herald() factory, channel concept, multi-broker support. Load when wiring connectToBroker at boot, choosing a herald skill, or wiring multiple brokers (notifications + analytics + events).
|
|
14
14
|
|
|
15
|
-
###
|
|
15
|
+
### `publish-message`
|
|
16
16
|
|
|
17
17
|
Publish messages to a channel — .publish(payload, options?) for single, .publishBatch([...], options?) for batch, with priority / ttl / delay / persistent / correlationId / headers options. Optional schema validation via .channel(name, {schema}). Load when emitting an event after a domain change, fanning out a notification, or scheduling delayed work.
|
|
18
18
|
|
|
19
|
-
###
|
|
19
|
+
### `request-and-respond`
|
|
20
20
|
|
|
21
21
|
Synchronous-style RPC over the message bus — channel.request<R>(payload, {timeout}) waits for a reply, channel.respond(handler) registers the responder, ctx.reply(response) sends the answer. Load when needing a request-response shape across services with loose coupling instead of direct HTTP.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: consume-message
|
|
3
|
-
description: 'Subscribe to a channel via .subscribe(handler, options?) — handler receives (message, ctx). Control flow via ctx.ack / ctx.nack(requeue?) / ctx.reject / ctx.retry(delayMs). Configure prefetch, retry policy, dead-letter, consumer groups. Triggers: `subscribe`, `ctx.ack`, `ctx.nack`, `ctx.reject`, `ctx.retry`, `prefetch`, `group`, `retry`, `deadLetter`, `@Consumable`, `EventConsumer`, `defineConsumer`, `autoAck`; "consume messages from a queue", "implement a worker", "background queue processor", "set up retry and dead-letter", "class-based event consumer"; typical import `import { herald, Consumable, EventConsumer } from "@warlock.js/herald"`. Skip: setup —
|
|
3
|
+
description: 'Subscribe to a channel via .subscribe(handler, options?) — handler receives (message, ctx). Control flow via ctx.ack / ctx.nack(requeue?) / ctx.reject / ctx.retry(delayMs). Configure prefetch, retry policy, dead-letter, consumer groups. Triggers: `subscribe`, `ctx.ack`, `ctx.nack`, `ctx.reject`, `ctx.retry`, `prefetch`, `group`, `retry`, `deadLetter`, `@Consumable`, `EventConsumer`, `defineConsumer`, `autoAck`; "consume messages from a queue", "implement a worker", "background queue processor", "set up retry and dead-letter", "class-based event consumer"; typical import `import { herald, Consumable, EventConsumer } from "@warlock.js/herald"`. Skip: setup — the `herald-basics` topic; producing — the `publish-message` topic; RPC reply — the `request-and-respond` topic; competing libs `amqplib`, `bullmq`, `kafkajs`; NestJS `@MessagePattern` / `@EventPattern`.'
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Consume messages
|
|
@@ -109,7 +109,7 @@ herald().channel("user.created.failed").subscribe(async (message, ctx) => {
|
|
|
109
109
|
|
|
110
110
|
## Decorator-style consumers — `@Consumable` + `EventConsumer`
|
|
111
111
|
|
|
112
|
-
For class-based consumers that pair with the
|
|
112
|
+
For class-based consumers that pair with the `EventMessage` (the `publish-message` topic) producer layer. This is a **different handler shape** from the raw `.subscribe()` above — ack/nack is automatic, and you get the unwrapped payload plus an event-metadata object (no `ctx`):
|
|
113
113
|
|
|
114
114
|
```ts
|
|
115
115
|
import { Consumable, EventConsumer } from "@warlock.js/herald";
|
|
@@ -215,5 +215,5 @@ await channel.delete(); // remove the queue entirely
|
|
|
215
215
|
|
|
216
216
|
## See also
|
|
217
217
|
|
|
218
|
-
-
|
|
219
|
-
-
|
|
218
|
+
- The `publish-message` topic — the producing side
|
|
219
|
+
- The `request-and-respond` topic — when you need to reply to a message
|
|
@@ -83,10 +83,10 @@ herald("analytics").channel("events").publish({ /* ... */ }); // → analytics
|
|
|
83
83
|
|
|
84
84
|
| If the task is about… | Load |
|
|
85
85
|
| --- | --- |
|
|
86
|
-
| Publishing messages — single + batch + publish options (priority, ttl, delay, persistent, headers) |
|
|
87
|
-
| Subscribing to messages — handler signature, message context (ack/nack/retry), prefetch, retry policy, dead-letter |
|
|
88
|
-
| Request/response (RPC) — `channel.request(...)` + `channel.respond(...)` for synchronous-style calls over a message bus |
|
|
89
|
-
| Schema-validated channels — `.channel(name, { schema })` with `@warlock.js/seal` | See
|
|
86
|
+
| Publishing messages — single + batch + publish options (priority, ttl, delay, persistent, headers) | the `publish-message` topic |
|
|
87
|
+
| Subscribing to messages — handler signature, message context (ack/nack/retry), prefetch, retry policy, dead-letter | the `consume-message` topic |
|
|
88
|
+
| Request/response (RPC) — `channel.request(...)` + `channel.respond(...)` for synchronous-style calls over a message bus | the `request-and-respond` topic |
|
|
89
|
+
| Schema-validated channels — `.channel(name, { schema })` with `@warlock.js/seal` | See the `seal-basics` topic of the `warlock-js-seal` skill + skills below |
|
|
90
90
|
|
|
91
91
|
## Things NOT to do
|
|
92
92
|
|
|
@@ -98,4 +98,4 @@ herald("analytics").channel("events").publish({ /* ... */ }); // → analytics
|
|
|
98
98
|
## See also
|
|
99
99
|
|
|
100
100
|
- README at `@warlock.js/herald/README.md` for the full API surface and RabbitMQ / Kafka driver config
|
|
101
|
-
-
|
|
101
|
+
- The `seal-basics` topic of the `warlock-js-seal` skill — schema validation
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: publish-message
|
|
3
|
-
description: 'Publish messages to a channel — .publish(payload, options?) for single, .publishBatch([...], options?) for batch, with priority / ttl / delay / persistent / correlationId / headers options. Optional schema validation via .channel(name, {schema}). Triggers: `publish`, `publishBatch`, `channel`, `priority`, `ttl`, `delay`, `persistent`, `correlationId`, `headers`, `schema`; "publish a message", "emit an event after a domain change", "fan out a notification", "schedule delayed work", "batch publish"; typical import `import { herald } from "@warlock.js/herald"`. Skip: setup —
|
|
3
|
+
description: 'Publish messages to a channel — .publish(payload, options?) for single, .publishBatch([...], options?) for batch, with priority / ttl / delay / persistent / correlationId / headers options. Optional schema validation via .channel(name, {schema}). Triggers: `publish`, `publishBatch`, `channel`, `priority`, `ttl`, `delay`, `persistent`, `correlationId`, `headers`, `schema`; "publish a message", "emit an event after a domain change", "fan out a notification", "schedule delayed work", "batch publish"; typical import `import { herald } from "@warlock.js/herald"`. Skip: setup — the `herald-basics` topic; consuming — the `consume-message` topic; RPC — the `request-and-respond` topic; competing libs `amqplib`, `kafkajs`, `bullmq`; NestJS `ClientProxy.emit`.'
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Publish messages
|
|
7
7
|
|
|
8
|
-
Push messages into a channel. The consumer side picks them up via
|
|
8
|
+
Push messages into a channel. The consumer side picks them up via the `consume-message` topic.
|
|
9
9
|
|
|
10
10
|
## Single publish
|
|
11
11
|
|
|
@@ -48,7 +48,7 @@ const channel = herald().channel("user.created", { schema: userSchema });
|
|
|
48
48
|
await channel.publish({ userId: 1, email: "invalid" }); // Throws — fails .email()
|
|
49
49
|
```
|
|
50
50
|
|
|
51
|
-
The schema runs `validate()` before the message hits the broker. Invalid payloads never leave the producer. See
|
|
51
|
+
The schema runs `validate()` before the message hits the broker. Invalid payloads never leave the producer. See the `seal-basics` topic of the `warlock-js-seal` skill.
|
|
52
52
|
|
|
53
53
|
## Publish options
|
|
54
54
|
|
|
@@ -135,11 +135,11 @@ export const createUserUseCase = useCase({
|
|
|
135
135
|
});
|
|
136
136
|
```
|
|
137
137
|
|
|
138
|
-
The adapter publishes the broadcast envelope's `payload` to `channel(event.event)`. It's structurally typed, so herald keeps no dependency on core. See
|
|
138
|
+
The adapter publishes the broadcast envelope's `payload` to `channel(event.event)`. It's structurally typed, so herald keeps no dependency on core. See the `write-use-case` topic of the `warlock-js-core` skill for the `broadcast` option (payload projection, custom event name, payload-safety rules).
|
|
139
139
|
|
|
140
140
|
## Event classes (`EventMessage`) — the typed event layer
|
|
141
141
|
|
|
142
|
-
Raw `channel(name).publish(payload)` is the low-level path. For domain events that travel between modules, herald ships a higher-level pair: define the event once as a class, publish instances of it, and consume them with an
|
|
142
|
+
Raw `channel(name).publish(payload)` is the low-level path. For domain events that travel between modules, herald ships a higher-level pair: define the event once as a class, publish instances of it, and consume them with an `EventConsumer` (the `consume-message` topic). The channel name comes from the event's `eventName` — no string to keep in sync across producer and consumer.
|
|
143
143
|
|
|
144
144
|
```ts
|
|
145
145
|
import { defineEvent, publishEvent } from "@warlock.js/herald";
|
|
@@ -168,5 +168,5 @@ Set an optional `version` on the event (instance field) to drive the consumer's
|
|
|
168
168
|
|
|
169
169
|
## See also
|
|
170
170
|
|
|
171
|
-
-
|
|
172
|
-
-
|
|
171
|
+
- The `consume-message` topic — the receiving side
|
|
172
|
+
- The `request-and-respond` topic — when you need a reply
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: request-and-respond
|
|
3
|
-
description: 'Synchronous-style RPC over the message bus — channel.request<R>(payload, {timeout}) waits for a reply, channel.respond(handler) registers the responder, ctx.reply(response) sends the answer. Triggers: `channel.request`, `channel.respond`, `ctx.reply`, `timeout`, `correlationId`, `headers.correlationId`; "RPC over message bus", "request-response across services", "wait for a reply", "internal service-to-service call instead of HTTP"; typical import `import { herald } from "@warlock.js/herald"`. Skip: setup —
|
|
3
|
+
description: 'Synchronous-style RPC over the message bus — channel.request<R>(payload, {timeout}) waits for a reply, channel.respond(handler) registers the responder, ctx.reply(response) sends the answer. Triggers: `channel.request`, `channel.respond`, `ctx.reply`, `timeout`, `correlationId`, `headers.correlationId`; "RPC over message bus", "request-response across services", "wait for a reply", "internal service-to-service call instead of HTTP"; typical import `import { herald } from "@warlock.js/herald"`. Skip: setup — the `herald-basics` topic; fire-and-forget — the `publish-message` topic; consumer ctx flow — the `consume-message` topic; competing libs `amqplib` RPC, `nats` request/reply; NestJS `ClientProxy.send`; gRPC; HTTP.'
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Request-response over the bus
|
|
@@ -70,5 +70,5 @@ Each `request()` generates its own correlation ID and an exclusive reply queue u
|
|
|
70
70
|
|
|
71
71
|
## See also
|
|
72
72
|
|
|
73
|
-
-
|
|
74
|
-
-
|
|
73
|
+
- The `publish-message` topic — fire-and-forget pattern
|
|
74
|
+
- The `consume-message` topic — subscribe + ctx flow control (including `ctx.reply`)
|