@palmetto/pubsub 1.0.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.
Files changed (42) hide show
  1. package/README.md +154 -0
  2. package/dist/bullmq/config.d.ts +21 -0
  3. package/dist/bullmq/config.js +2 -0
  4. package/dist/bullmq/connection.d.ts +2 -0
  5. package/dist/bullmq/connection.js +5 -0
  6. package/dist/bullmq/main.d.ts +6 -0
  7. package/dist/bullmq/main.js +21 -0
  8. package/dist/bullmq/publisher.d.ts +13 -0
  9. package/dist/bullmq/publisher.js +62 -0
  10. package/dist/bullmq/pubsub.d.ts +12 -0
  11. package/dist/bullmq/pubsub.js +35 -0
  12. package/dist/bullmq/subscriber.d.ts +27 -0
  13. package/dist/bullmq/subscriber.js +118 -0
  14. package/dist/errors.d.ts +17 -0
  15. package/dist/errors.js +37 -0
  16. package/dist/interfaces.d.ts +120 -0
  17. package/dist/interfaces.js +28 -0
  18. package/dist/lazy-load.d.ts +11 -0
  19. package/dist/lazy-load.js +79 -0
  20. package/dist/main.d.ts +6 -0
  21. package/dist/main.js +22 -0
  22. package/dist/publisher.d.ts +11 -0
  23. package/dist/publisher.js +87 -0
  24. package/dist/rabbitmq/config.d.ts +84 -0
  25. package/dist/rabbitmq/config.js +82 -0
  26. package/dist/rabbitmq/connection.d.ts +41 -0
  27. package/dist/rabbitmq/connection.js +140 -0
  28. package/dist/rabbitmq/main.d.ts +5 -0
  29. package/dist/rabbitmq/main.js +21 -0
  30. package/dist/rabbitmq/publisher.d.ts +29 -0
  31. package/dist/rabbitmq/publisher.js +98 -0
  32. package/dist/rabbitmq/pubsub.d.ts +15 -0
  33. package/dist/rabbitmq/pubsub.js +37 -0
  34. package/dist/rabbitmq/subscriber.d.ts +33 -0
  35. package/dist/rabbitmq/subscriber.js +197 -0
  36. package/dist/rabbitmq/utility.d.ts +6 -0
  37. package/dist/rabbitmq/utility.js +11 -0
  38. package/dist/subscriber.d.ts +28 -0
  39. package/dist/subscriber.js +140 -0
  40. package/package.json +54 -0
  41. package/src/bullmq/README.md +63 -0
  42. package/src/rabbitmq/README.md +184 -0
package/README.md ADDED
@@ -0,0 +1,154 @@
1
+ # @palmetto/pubsub
2
+
3
+ Provides a standard mechanism to publish and subscribe to events using a zod v4 schema. The schema is used to validate that the message published or subscribed is valid.
4
+
5
+ Messages pub/sub is done using JSON strings. The JSON strings are converted into the type using the schema. JSON strings that fail the schema parsing are rejected.
6
+
7
+ Subscribers must return one of 3 results from MessageResult:
8
+
9
+ - Ok - the message was processed successfully
10
+ - Retry - the message should be retried.
11
+ - Fail - the message processing failed and can be discarded [or dead-lettered, depending on the queue implementation]
12
+
13
+ It is up to the pub/sub implementations what to do with rejected messages. Options include:
14
+
15
+ - Dead letter queue
16
+ - Log an error
17
+ - Retry the message
18
+
19
+ ## Installation
20
+
21
+ ```sh
22
+ yarn add @palmetto/pubsub zod
23
+ ```
24
+
25
+ ## Usage
26
+
27
+ 1. Create a publisher and send a message
28
+
29
+ ```ts
30
+ import { z as z4 } from "zod/v4";
31
+ import { IdMetaSchema, Publisher, RabbitMqPublisher, RabbitQueueExchangeConfiguration } from "@palmetto/pubsub";
32
+
33
+ const rabbitMqPublisher = new RabbitMqPublisher(...);
34
+
35
+ const schema = IdMetaSchema.extend({
36
+ message: z4.string(),
37
+ });
38
+
39
+ const Model = z.infer<typeof schema>;
40
+
41
+ const schemaConfig: RabbitQueueExchangeConfiguration = {
42
+ name: "TestModel",
43
+ schema: TestModelSchema,
44
+ transport: RABBITMQ_TRANSPORT,
45
+ type: "direct",
46
+ };
47
+
48
+ const publisher = new Publisher(console, [rabbitMqPublisher]);
49
+
50
+ const message: Model = {
51
+ id: undefined,
52
+ meta: undefined,
53
+ message: "Hello, world!",
54
+ };
55
+
56
+ await publisher.publish(schemaConfig, message);
57
+ ```
58
+
59
+ 1. Create subscriber and subscriber to a message
60
+
61
+ ```ts
62
+ import { z as z4 } from "zod/v4";
63
+ import { BaseMessage, IdMetaSchema, MessageResult, Subscriber, RabbitMqSubscriber } from "@palmetto/pubsub";
64
+
65
+ const rabbitMqSubscriber = new RabbitMqSubscriber(...);
66
+
67
+ const schema = IdMetaSchema.extend({
68
+ message: z4.string(),
69
+ code: z4.string(),
70
+ });
71
+
72
+ const Model = z.infer<typeof schema>;
73
+
74
+ const schemaConfig: RabbitQueueExchangeConfiguration = {
75
+ name: "TestModel",
76
+ schema: TestModelSchema,
77
+ retryDelay: 1_000,
78
+ retries: 20,
79
+ transport: RABBITMQ_TRANSPORT,
80
+ type: "direct",
81
+ };
82
+
83
+ function onMessage(message: Model) {
84
+ console.log(message.message);
85
+ const success = ...;
86
+
87
+ return success ? MessageResult.Ok : MessageResult.Retry;
88
+ };
89
+
90
+ const subscriber = new Subscriber(console, [rabbitMqSubscriber]);
91
+
92
+ await subscriber.startSubscribe(schemaConfig, onMessage);
93
+ ```
94
+
95
+ ### Defining schemas
96
+
97
+ All schemas must be defined using `zod/z4`. By convention, all messages should extend the `IdMetaSchema` schema, but it is not strictly required.
98
+
99
+ IdMetaSchema provides several fields useful for message tracking:
100
+
101
+ - id: a string GUID representing the unique message
102
+ - meta.createdAt: when the message was originally sent (ISO datetime string)
103
+ - meta.schemaId: a string value representing the schema
104
+ - currently: a hash of the JSON schema itself
105
+ - future use: an id into a schema registry that supports schema evolution
106
+ - meta.publishedBy: [[future use]] the name of the service that published the message
107
+
108
+ ## Handling errors
109
+
110
+ ### Schema failures
111
+
112
+ The message is checked against the provided schema for every publish and subscribe.
113
+
114
+ - Publisher: catch the `SchemaValidationError` exception.
115
+
116
+ ```ts
117
+ try {
118
+ await publisher.publish(config, message);
119
+ } catch (err: unknown) {
120
+ if (error instanceof SchemaValidationError) {
121
+ // TODO
122
+ }
123
+ }
124
+ ```
125
+
126
+ - Subscriber: add an event monitor on `schemaError`
127
+
128
+ ```ts
129
+ subscriber.on(
130
+ "schemaError",
131
+ (
132
+ message: string, // the JSON string of the message
133
+ context: MessageContext, // the context of the message provided by the SubscriptionProvider
134
+ config: PubSubConfiguration, // the configuration for the message (eg: BullMqQueueConfiguration, RabbitQueueExchangeConfiguration)
135
+ ) => {
136
+ // TODO
137
+ },
138
+ );
139
+ ```
140
+
141
+ ### Subscriber errors
142
+
143
+ When a subscriber handler fails, the SubscriberProvider should retry or fail the message.
144
+
145
+ Retries should occur when
146
+
147
+ - The user-provided handler throws an exception
148
+ - The handler returns MessageResult.Retry
149
+
150
+ It is up to the provider to obey the `retries` and `retryDelay` configuration properties.
151
+
152
+ ### Publisher errors
153
+
154
+ When a message publish fails, it is up to the calling code to handle exceptions.
@@ -0,0 +1,21 @@
1
+ import { MessageContext, PubSubConfiguration } from "../interfaces";
2
+ export interface BullMqQueueConfiguration extends PubSubConfiguration {
3
+ /**
4
+ * The name of the queue
5
+ */
6
+ name: string;
7
+ /**
8
+ * The name of the job to use
9
+ */
10
+ job?: string;
11
+ }
12
+ export interface BullMqMessageContext extends MessageContext {
13
+ /**
14
+ * name of the bull mq job
15
+ */
16
+ job: string;
17
+ /**
18
+ * Provide an optional reply for the job here
19
+ */
20
+ reply?: unknown;
21
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,2 @@
1
+ export declare const BULLMQ_TRANSPORT = "bullmq";
2
+ export declare const BULLMQ_DEFAULTJOB = "pubsub";
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BULLMQ_DEFAULTJOB = exports.BULLMQ_TRANSPORT = void 0;
4
+ exports.BULLMQ_TRANSPORT = "bullmq";
5
+ exports.BULLMQ_DEFAULTJOB = "pubsub";
@@ -0,0 +1,6 @@
1
+ export * from "./config.js";
2
+ export * from "./connection.js";
3
+ export * from "./publisher.js";
4
+ export * from "./subscriber.js";
5
+ export * from "./pubsub.js";
6
+ export type { ConnectionOptions } from "bullmq";
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./config.js"), exports);
18
+ __exportStar(require("./connection.js"), exports);
19
+ __exportStar(require("./publisher.js"), exports);
20
+ __exportStar(require("./subscriber.js"), exports);
21
+ __exportStar(require("./pubsub.js"), exports);
@@ -0,0 +1,13 @@
1
+ import type * as bullmq from "bullmq";
2
+ import { Logger, PublisherProvider } from "../interfaces";
3
+ import { BullMqQueueConfiguration } from "./config";
4
+ export declare class BullMqPublisher implements PublisherProvider {
5
+ private readonly connection;
6
+ private readonly logger;
7
+ private queues;
8
+ constructor(connection: bullmq.ConnectionOptions, logger: Logger);
9
+ readonly transport: string;
10
+ private getQueue;
11
+ publish(config: BullMqQueueConfiguration, message: string): Promise<void>;
12
+ close(): Promise<void>;
13
+ }
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.BullMqPublisher = void 0;
13
+ const connection_1 = require("./connection");
14
+ const lazy_load_1 = require("../lazy-load");
15
+ class BullMqPublisher {
16
+ constructor(connection, logger) {
17
+ this.connection = connection;
18
+ this.logger = logger;
19
+ this.queues = new Map();
20
+ this.transport = connection_1.BULLMQ_TRANSPORT;
21
+ }
22
+ getQueue(config) {
23
+ return __awaiter(this, void 0, void 0, function* () {
24
+ let queue = this.queues.get(config);
25
+ if (queue) {
26
+ return queue;
27
+ }
28
+ const BullMqPackage = yield (0, lazy_load_1.lazyLoad)({
29
+ packageName: "bullmq",
30
+ context: "BullMqPublisher",
31
+ });
32
+ queue = new BullMqPackage.Queue(config.name, {
33
+ connection: this.connection,
34
+ });
35
+ this.queues.set(config, queue);
36
+ return queue;
37
+ });
38
+ }
39
+ publish(config, message) {
40
+ return __awaiter(this, void 0, void 0, function* () {
41
+ var _a, _b;
42
+ const queue = yield this.getQueue(config);
43
+ (_b = (_a = this.logger).debug) === null || _b === void 0 ? void 0 : _b.call(_a, `Publishing message to ${queue.name} - ${message}`);
44
+ yield queue.add(config.job || connection_1.BULLMQ_DEFAULTJOB, message, {
45
+ attempts: config.retries,
46
+ backoff: {
47
+ type: "fixed",
48
+ delay: config.retryDelay || 30000,
49
+ },
50
+ });
51
+ });
52
+ }
53
+ close() {
54
+ return __awaiter(this, void 0, void 0, function* () {
55
+ for (const queue of this.queues.values()) {
56
+ yield queue.close();
57
+ }
58
+ this.queues.clear();
59
+ });
60
+ }
61
+ }
62
+ exports.BullMqPublisher = BullMqPublisher;
@@ -0,0 +1,12 @@
1
+ import { Logger, MessageContext, MessageResult, PubSubProvider, StopSubscribe } from "../interfaces";
2
+ import { BullMqQueueConfiguration } from "./config";
3
+ import type { ConnectionOptions } from "bullmq";
4
+ export declare class BullMqPubSubProvider implements PubSubProvider {
5
+ private readonly publisher;
6
+ private readonly subscriber;
7
+ constructor(connection: ConnectionOptions, logger: Logger);
8
+ readonly transport: string;
9
+ publish(config: BullMqQueueConfiguration, message: string): Promise<void>;
10
+ startSubscribe(config: BullMqQueueConfiguration, onMessage: (s: string, context: MessageContext) => Promise<MessageResult> | MessageResult): Promise<StopSubscribe>;
11
+ close(): Promise<void>;
12
+ }
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.BullMqPubSubProvider = void 0;
13
+ const connection_1 = require("./connection");
14
+ const publisher_1 = require("./publisher");
15
+ const subscriber_1 = require("./subscriber");
16
+ class BullMqPubSubProvider {
17
+ constructor(connection, logger) {
18
+ this.transport = connection_1.BULLMQ_TRANSPORT;
19
+ this.publisher = new publisher_1.BullMqPublisher(connection, logger);
20
+ this.subscriber = new subscriber_1.BullMqSubscriber(connection, logger);
21
+ }
22
+ publish(config, message) {
23
+ return this.publisher.publish(config, message);
24
+ }
25
+ startSubscribe(config, onMessage) {
26
+ return this.subscriber.startSubscribe(config, onMessage);
27
+ }
28
+ close() {
29
+ return __awaiter(this, void 0, void 0, function* () {
30
+ yield this.subscriber.close();
31
+ yield this.publisher.close();
32
+ });
33
+ }
34
+ }
35
+ exports.BullMqPubSubProvider = BullMqPubSubProvider;
@@ -0,0 +1,27 @@
1
+ import type * as bullmq from "bullmq";
2
+ import { Logger, MessageResult, StopSubscribe, SubscriberProvider } from "../interfaces";
3
+ import { BullMqMessageContext, BullMqQueueConfiguration } from "./config";
4
+ declare class SubscribedMessage {
5
+ private readonly owner;
6
+ private readonly worker;
7
+ private readonly logger;
8
+ constructor(owner: BullMqSubscriber, worker: bullmq.Worker, logger: Logger);
9
+ stopSubscribe(): Promise<void>;
10
+ }
11
+ export declare class MessageFailError extends Error {
12
+ constructor();
13
+ }
14
+ export declare class MessageRetryError extends Error {
15
+ constructor();
16
+ }
17
+ export declare class BullMqSubscriber implements SubscriberProvider {
18
+ private readonly connection;
19
+ private readonly logger;
20
+ private readonly stops;
21
+ constructor(connection: bullmq.ConnectionOptions, logger: Logger);
22
+ readonly transport: string;
23
+ removeSubscriber(subscribedMessage: SubscribedMessage): void;
24
+ startSubscribe(config: BullMqQueueConfiguration, onMessage: (s: string, context: BullMqMessageContext) => Promise<MessageResult> | MessageResult): Promise<StopSubscribe>;
25
+ close(): Promise<void>;
26
+ }
27
+ export {};
@@ -0,0 +1,118 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.BullMqSubscriber = exports.MessageRetryError = exports.MessageFailError = void 0;
13
+ const interfaces_1 = require("../interfaces");
14
+ const connection_1 = require("./connection");
15
+ const lazy_load_1 = require("../lazy-load");
16
+ class SubscribedMessage {
17
+ constructor(owner, worker, logger) {
18
+ this.owner = owner;
19
+ this.worker = worker;
20
+ this.logger = logger;
21
+ }
22
+ stopSubscribe() {
23
+ return __awaiter(this, void 0, void 0, function* () {
24
+ var _a, _b;
25
+ (_b = (_a = this.logger).debug) === null || _b === void 0 ? void 0 : _b.call(_a, `BullMq closing worker for ${this.worker.name}`);
26
+ yield this.worker.close();
27
+ this.owner.removeSubscriber(this);
28
+ });
29
+ }
30
+ }
31
+ class MessageFailError extends Error {
32
+ constructor() {
33
+ super("Handler asked to fail this job");
34
+ }
35
+ }
36
+ exports.MessageFailError = MessageFailError;
37
+ class MessageRetryError extends Error {
38
+ constructor() {
39
+ super("Handler asked to retry this job");
40
+ }
41
+ }
42
+ exports.MessageRetryError = MessageRetryError;
43
+ class BullMqSubscriber {
44
+ constructor(connection, logger) {
45
+ this.connection = connection;
46
+ this.logger = logger;
47
+ this.stops = new Map();
48
+ this.transport = connection_1.BULLMQ_TRANSPORT;
49
+ }
50
+ removeSubscriber(subscribedMessage) {
51
+ for (const [key, value] of this.stops) {
52
+ if (value === subscribedMessage) {
53
+ this.stops.delete(key);
54
+ break;
55
+ }
56
+ }
57
+ }
58
+ startSubscribe(config, onMessage) {
59
+ return __awaiter(this, void 0, void 0, function* () {
60
+ var _a, _b, _c, _d;
61
+ const BullMqPackage = yield (0, lazy_load_1.lazyLoad)({
62
+ packageName: "bullmq",
63
+ context: "BullMqSubscriber",
64
+ });
65
+ const worker = new BullMqPackage.Worker(config.name, (job) => __awaiter(this, void 0, void 0, function* () {
66
+ const context = {
67
+ job: job.name,
68
+ retries: job.attemptsMade,
69
+ firstSent: new Date(job.timestamp),
70
+ // lastSent: new Date(job.attemptsStarted),
71
+ };
72
+ const result = yield onMessage(job.data, context);
73
+ if (result === interfaces_1.MessageResult.Ok) {
74
+ return context.reply;
75
+ }
76
+ if (result === interfaces_1.MessageResult.Retry) {
77
+ throw new MessageRetryError();
78
+ }
79
+ throw new BullMqPackage.UnrecoverableError("Handler asked to fail this job");
80
+ }), {
81
+ connection: this.connection,
82
+ autorun: false,
83
+ });
84
+ worker.on("failed", (job, err) => {
85
+ if (!job) {
86
+ return;
87
+ }
88
+ this.logger.log(`Job failed ${err}`);
89
+ });
90
+ worker.on("error", (err) => {
91
+ this.logger.error(`BullMq PubSub handler exception: ${err}`);
92
+ });
93
+ (_b = (_a = this.logger).debug) === null || _b === void 0 ? void 0 : _b.call(_a, `BullMq PubSub subscriber starting for ${worker.name}`);
94
+ worker
95
+ .run()
96
+ .then(() => {
97
+ var _a, _b;
98
+ (_b = (_a = this.logger).debug) === null || _b === void 0 ? void 0 : _b.call(_a, `BullMq PubSub subscriber stopped for ${worker.name}`);
99
+ })
100
+ .catch((err) => {
101
+ this.logger.error(`BullMq PubSub subscriber crashed for ${worker.name}`, err);
102
+ });
103
+ const subscribedMessage = new SubscribedMessage(this, worker, this.logger);
104
+ this.stops.set(config, subscribedMessage);
105
+ (_d = (_c = this.logger).debug) === null || _d === void 0 ? void 0 : _d.call(_c, `BullMq PubSub subscriber started for ${worker.name}`);
106
+ return () => subscribedMessage.stopSubscribe();
107
+ });
108
+ }
109
+ close() {
110
+ return __awaiter(this, void 0, void 0, function* () {
111
+ for (const sub of this.stops.values()) {
112
+ yield sub.stopSubscribe();
113
+ }
114
+ this.stops.clear();
115
+ });
116
+ }
117
+ }
118
+ exports.BullMqSubscriber = BullMqSubscriber;
@@ -0,0 +1,17 @@
1
+ export declare class AlreadySubscribingError extends Error {
2
+ name: string;
3
+ constructor(name: string);
4
+ static isAlreadySubscribingError(err: unknown): err is AlreadySubscribingError;
5
+ }
6
+ export declare class ConfigurationError extends Error {
7
+ static isConfigurationError(err: unknown): err is ConfigurationError;
8
+ }
9
+ export declare class MissingPubSubProviderError extends Error {
10
+ static isMissingPubSubProviderError(err: unknown): err is MissingPubSubProviderError;
11
+ }
12
+ export declare class PublishError extends Error {
13
+ static isPublishError(err: unknown): err is PublishError;
14
+ }
15
+ export declare class SchemaValidationError extends Error {
16
+ static isSchemaValidationError(err: unknown): err is SchemaValidationError;
17
+ }
package/dist/errors.js ADDED
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SchemaValidationError = exports.PublishError = exports.MissingPubSubProviderError = exports.ConfigurationError = exports.AlreadySubscribingError = void 0;
4
+ class AlreadySubscribingError extends Error {
5
+ constructor(name) {
6
+ super(`Subscription for ${name} already started`);
7
+ this.name = name;
8
+ }
9
+ static isAlreadySubscribingError(err) {
10
+ return err instanceof AlreadySubscribingError;
11
+ }
12
+ }
13
+ exports.AlreadySubscribingError = AlreadySubscribingError;
14
+ class ConfigurationError extends Error {
15
+ static isConfigurationError(err) {
16
+ return err instanceof ConfigurationError;
17
+ }
18
+ }
19
+ exports.ConfigurationError = ConfigurationError;
20
+ class MissingPubSubProviderError extends Error {
21
+ static isMissingPubSubProviderError(err) {
22
+ return err instanceof MissingPubSubProviderError;
23
+ }
24
+ }
25
+ exports.MissingPubSubProviderError = MissingPubSubProviderError;
26
+ class PublishError extends Error {
27
+ static isPublishError(err) {
28
+ return err instanceof PublishError;
29
+ }
30
+ }
31
+ exports.PublishError = PublishError;
32
+ class SchemaValidationError extends Error {
33
+ static isSchemaValidationError(err) {
34
+ return err instanceof SchemaValidationError;
35
+ }
36
+ }
37
+ exports.SchemaValidationError = SchemaValidationError;
@@ -0,0 +1,120 @@
1
+ import { z as z4 } from "zod/v4";
2
+ export declare const MetaSchema: z4.ZodObject<{
3
+ createdAt: z4.ZodISODateTime;
4
+ schemaId: z4.ZodString;
5
+ publishedBy: z4.ZodString;
6
+ }, z4.core.$strip>;
7
+ export declare const IdMetaSchema: z4.ZodObject<{
8
+ id: z4.ZodOptional<z4.ZodString>;
9
+ meta: z4.ZodOptional<z4.ZodObject<{
10
+ createdAt: z4.ZodISODateTime;
11
+ schemaId: z4.ZodString;
12
+ publishedBy: z4.ZodString;
13
+ }, z4.core.$strip>>;
14
+ }, z4.core.$strip>;
15
+ export type Meta = z4.infer<typeof MetaSchema>;
16
+ /**
17
+ * All messages should be based on this schema
18
+ */
19
+ export type BaseMessage = z4.infer<typeof IdMetaSchema>;
20
+ /**
21
+ * All pubsub publishers must implement this interface
22
+ */
23
+ export interface PublisherProvider {
24
+ transport: string;
25
+ publish(config: PubSubConfiguration, message: string): Promise<void> | void;
26
+ close(): Promise<void> | void;
27
+ }
28
+ /**
29
+ * Minimal configuration needed to publish or subscribe to a message
30
+ */
31
+ export interface PubSubConfiguration {
32
+ /**
33
+ * The name of the message
34
+ */
35
+ name: string;
36
+ /**
37
+ * The schema for the message - the message is verfied during publish and subscribe
38
+ */
39
+ schema: z4.ZodType;
40
+ /**
41
+ * The message transport to use (defined by the event-pubsub implementations)
42
+ */
43
+ transport: string;
44
+ /**
45
+ * Maximum number of times to retry a message
46
+ */
47
+ retries?: number;
48
+ /**
49
+ * Minimum amount of time to wait, in milliseconds, before retrying a message
50
+ */
51
+ retryDelay?: number;
52
+ }
53
+ export declare enum MessageResult {
54
+ /**
55
+ * the message was handled successfully or can otherwise be ignored
56
+ */
57
+ Ok = "ok",
58
+ /**
59
+ * The message should be retried
60
+ */
61
+ Retry = "retry",
62
+ /**
63
+ * The message failed and is either discarded or stored in a dead-letter queue
64
+ */
65
+ Fail = "fail"
66
+ }
67
+ /**
68
+ * Simple interface for logging, should match console/NestJS LoggerService/etc.
69
+ */
70
+ export interface Logger {
71
+ /**
72
+ * Write a 'log' level log.
73
+ */
74
+ log(message: unknown, ...optionalParams: unknown[]): unknown;
75
+ /**
76
+ * Write an 'error' level log.
77
+ */
78
+ error(message: unknown, ...optionalParams: unknown[]): unknown;
79
+ /**
80
+ * Write a 'warn' level log.
81
+ */
82
+ warn(message: unknown, ...optionalParams: unknown[]): unknown;
83
+ /**
84
+ * Write a 'debug' level log.
85
+ */
86
+ debug?(message: unknown, ...optionalParams: unknown[]): unknown;
87
+ /**
88
+ * Write a 'verbose' level log.
89
+ */
90
+ verbose?(message: unknown, ...optionalParams: unknown[]): unknown;
91
+ /**
92
+ * Write a 'fatal' level log.
93
+ */
94
+ fatal?(message: unknown, ...optionalParams: unknown[]): unknown;
95
+ }
96
+ /**
97
+ * A callback the stops the subscriber
98
+ */
99
+ export type StopSubscribe = () => Promise<void>;
100
+ /**
101
+ * All pubsub subscribers must implement this interface
102
+ */
103
+ export interface SubscriberProvider {
104
+ transport: string;
105
+ startSubscribe(config: PubSubConfiguration, onMessage: (s: string, context: MessageContext) => Promise<MessageResult> | MessageResult): Promise<StopSubscribe> | StopSubscribe;
106
+ close(): Promise<void> | void;
107
+ }
108
+ /**
109
+ * A class that implements both the publisher and subscriber
110
+ */
111
+ export type PubSubProvider = PublisherProvider & SubscriberProvider;
112
+ /**
113
+ * A class that implements either a publisher, subscriber or both
114
+ */
115
+ export type PubOrSubProvider = PubSubProvider | PublisherProvider | SubscriberProvider;
116
+ export interface MessageContext {
117
+ firstSent?: Date;
118
+ lastSent?: Date;
119
+ retries?: number;
120
+ }