@zdavison/matador-nest 2.0.1

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 (74) hide show
  1. package/dist/constants.d.ts +13 -0
  2. package/dist/constants.d.ts.map +1 -0
  3. package/dist/constants.js +12 -0
  4. package/dist/decorators/index.d.ts +3 -0
  5. package/dist/decorators/index.d.ts.map +1 -0
  6. package/dist/decorators/index.js +2 -0
  7. package/dist/decorators/matador-subscriber.decorator.d.ts +20 -0
  8. package/dist/decorators/matador-subscriber.decorator.d.ts.map +1 -0
  9. package/dist/decorators/matador-subscriber.decorator.js +26 -0
  10. package/dist/decorators/on-matador-event.decorator.d.ts +24 -0
  11. package/dist/decorators/on-matador-event.decorator.d.ts.map +1 -0
  12. package/dist/decorators/on-matador-event.decorator.js +38 -0
  13. package/dist/discovery/index.d.ts +2 -0
  14. package/dist/discovery/index.d.ts.map +1 -0
  15. package/dist/discovery/index.js +1 -0
  16. package/dist/discovery/subscriber-discovery.service.d.ts +37 -0
  17. package/dist/discovery/subscriber-discovery.service.d.ts.map +1 -0
  18. package/dist/discovery/subscriber-discovery.service.js +144 -0
  19. package/dist/index.cjs +495 -0
  20. package/dist/index.cjs.map +1 -0
  21. package/dist/index.d.cts +7 -0
  22. package/dist/index.d.ts +7 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.js +10 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/module/index.d.ts +2 -0
  27. package/dist/module/index.d.ts.map +1 -0
  28. package/dist/module/index.js +1 -0
  29. package/dist/module/matador.module.d.ts +71 -0
  30. package/dist/module/matador.module.d.ts.map +1 -0
  31. package/dist/module/matador.module.js +146 -0
  32. package/dist/services/index.d.ts +2 -0
  33. package/dist/services/index.d.ts.map +1 -0
  34. package/dist/services/index.js +1 -0
  35. package/dist/services/matador.service.d.ts +105 -0
  36. package/dist/services/matador.service.d.ts.map +1 -0
  37. package/dist/services/matador.service.js +209 -0
  38. package/dist/testing/index.d.ts +2 -0
  39. package/dist/testing/index.d.ts.map +1 -0
  40. package/dist/testing/index.js +1 -0
  41. package/dist/testing/matador-testing.module.d.ts +53 -0
  42. package/dist/testing/matador-testing.module.d.ts.map +1 -0
  43. package/dist/testing/matador-testing.module.js +77 -0
  44. package/dist/testing.cjs +498 -0
  45. package/dist/testing.cjs.map +1 -0
  46. package/dist/testing.d.cts +2 -0
  47. package/dist/testing.d.ts +2 -0
  48. package/dist/testing.d.ts.map +1 -0
  49. package/dist/testing.js +2 -0
  50. package/dist/testing.js.map +1 -0
  51. package/dist/types.d.ts +88 -0
  52. package/dist/types.d.ts.map +1 -0
  53. package/dist/types.js +1 -0
  54. package/package.json +61 -0
  55. package/src/constants.ts +14 -0
  56. package/src/decorators/index.ts +2 -0
  57. package/src/decorators/matador-subscriber.decorator.ts +27 -0
  58. package/src/decorators/on-matador-event.decorator.ts +68 -0
  59. package/src/discovery/index.ts +1 -0
  60. package/src/discovery/subscriber-discovery.service.ts +181 -0
  61. package/src/index.ts +28 -0
  62. package/src/module/index.ts +1 -0
  63. package/src/module/matador.module.ts +162 -0
  64. package/src/services/index.ts +1 -0
  65. package/src/services/matador.service.ts +283 -0
  66. package/src/testing/index.ts +1 -0
  67. package/src/testing/matador-testing.module.ts +71 -0
  68. package/src/testing.ts +2 -0
  69. package/src/types.ts +119 -0
  70. package/test/decorators.test.ts +132 -0
  71. package/test/discovery.test.ts +278 -0
  72. package/tsconfig.json +32 -0
  73. package/tsconfig.tsbuildinfo +1 -0
  74. package/tsup.config.ts +23 -0
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Metadata key for storing event handler metadata on methods.
3
+ */
4
+ export declare const MATADOR_EVENT_HANDLER: unique symbol;
5
+ /**
6
+ * Metadata key for storing a list of all event handlers on a class.
7
+ */
8
+ export declare const MATADOR_EVENT_HANDLERS: unique symbol;
9
+ /**
10
+ * Injection token for module options.
11
+ */
12
+ export declare const MATADOR_OPTIONS: unique symbol;
13
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,eAAO,MAAM,qBAAqB,eAAkC,CAAC;AAErE;;GAEG;AACH,eAAO,MAAM,sBAAsB,eAAmC,CAAC;AAEvE;;GAEG;AACH,eAAO,MAAM,eAAe,eAA4B,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Metadata key for storing event handler metadata on methods.
3
+ */
4
+ export const MATADOR_EVENT_HANDLER = Symbol('MATADOR_EVENT_HANDLER');
5
+ /**
6
+ * Metadata key for storing a list of all event handlers on a class.
7
+ */
8
+ export const MATADOR_EVENT_HANDLERS = Symbol('MATADOR_EVENT_HANDLERS');
9
+ /**
10
+ * Injection token for module options.
11
+ */
12
+ export const MATADOR_OPTIONS = Symbol('MATADOR_OPTIONS');
@@ -0,0 +1,3 @@
1
+ export { OnMatadorEvent } from './on-matador-event.decorator.js';
2
+ export { MatadorSubscriber } from './matador-subscriber.decorator.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/decorators/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { OnMatadorEvent } from './on-matador-event.decorator.js';
2
+ export { MatadorSubscriber } from './matador-subscriber.decorator.js';
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Optional class decorator that marks a class as a Matador subscriber.
3
+ * Classes with @OnMatadorEvent methods are auto-discovered, so this decorator
4
+ * is optional. Use it for explicit documentation or when you want to ensure
5
+ * a class is treated as a subscriber even if it has no decorated methods yet.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * @MatadorSubscriber()
10
+ * @Injectable()
11
+ * export class NotificationService {
12
+ * @OnMatadorEvent(UserCreatedEvent, { description: '...' })
13
+ * async onUserCreated(envelope: Envelope<...>) {
14
+ * // ...
15
+ * }
16
+ * }
17
+ * ```
18
+ */
19
+ export declare function MatadorSubscriber(): ClassDecorator;
20
+ //# sourceMappingURL=matador-subscriber.decorator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"matador-subscriber.decorator.d.ts","sourceRoot":"","sources":["../../src/decorators/matador-subscriber.decorator.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,iBAAiB,IAAI,cAAc,CAMlD"}
@@ -0,0 +1,26 @@
1
+ import { Injectable } from '@nestjs/common';
2
+ /**
3
+ * Optional class decorator that marks a class as a Matador subscriber.
4
+ * Classes with @OnMatadorEvent methods are auto-discovered, so this decorator
5
+ * is optional. Use it for explicit documentation or when you want to ensure
6
+ * a class is treated as a subscriber even if it has no decorated methods yet.
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * @MatadorSubscriber()
11
+ * @Injectable()
12
+ * export class NotificationService {
13
+ * @OnMatadorEvent(UserCreatedEvent, { description: '...' })
14
+ * async onUserCreated(envelope: Envelope<...>) {
15
+ * // ...
16
+ * }
17
+ * }
18
+ * ```
19
+ */
20
+ export function MatadorSubscriber() {
21
+ return (target) => {
22
+ // Ensure the class is injectable (apply @Injectable if not already)
23
+ // This is a no-op if @Injectable was already applied
24
+ Injectable()(target);
25
+ };
26
+ }
@@ -0,0 +1,24 @@
1
+ import type { EventClass } from '@zdavison/matador';
2
+ import type { OnMatadorEventOptions } from '../types.js';
3
+ /**
4
+ * Method decorator that marks a method as a Matador event subscriber.
5
+ *
6
+ * @param eventClass - The event class to subscribe to
7
+ * @param options - Subscriber options (description is required)
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * @Injectable()
12
+ * export class NotificationService {
13
+ * @OnMatadorEvent(UserCreatedEvent, {
14
+ * description: 'Sends welcome email to new users',
15
+ * idempotent: 'yes',
16
+ * })
17
+ * async onUserCreated(envelope: Envelope<UserCreatedEvent['data']>) {
18
+ * await this.emailService.sendWelcome(envelope.data.email);
19
+ * }
20
+ * }
21
+ * ```
22
+ */
23
+ export declare function OnMatadorEvent<T>(eventClass: EventClass<T>, options: OnMatadorEventOptions): (target: object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => PropertyDescriptor;
24
+ //# sourceMappingURL=on-matador-event.decorator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"on-matador-event.decorator.d.ts","sourceRoot":"","sources":["../../src/decorators/on-matador-event.decorator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpD,OAAO,KAAK,EAEV,qBAAqB,EACtB,MAAM,aAAa,CAAC;AAErB;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAC9B,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,EACzB,OAAO,EAAE,qBAAqB,GAC7B,CACD,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,GAAG,MAAM,EAC5B,UAAU,EAAE,kBAAkB,KAC3B,kBAAkB,CAiCtB"}
@@ -0,0 +1,38 @@
1
+ import { MATADOR_EVENT_HANDLER, MATADOR_EVENT_HANDLERS } from '../constants.js';
2
+ /**
3
+ * Method decorator that marks a method as a Matador event subscriber.
4
+ *
5
+ * @param eventClass - The event class to subscribe to
6
+ * @param options - Subscriber options (description is required)
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * @Injectable()
11
+ * export class NotificationService {
12
+ * @OnMatadorEvent(UserCreatedEvent, {
13
+ * description: 'Sends welcome email to new users',
14
+ * idempotent: 'yes',
15
+ * })
16
+ * async onUserCreated(envelope: Envelope<UserCreatedEvent['data']>) {
17
+ * await this.emailService.sendWelcome(envelope.data.email);
18
+ * }
19
+ * }
20
+ * ```
21
+ */
22
+ export function OnMatadorEvent(eventClass, options) {
23
+ return (target, propertyKey, descriptor) => {
24
+ const metadata = {
25
+ eventClass: eventClass,
26
+ options,
27
+ methodName: String(propertyKey),
28
+ };
29
+ // Store metadata on the method itself
30
+ if (descriptor.value != null) {
31
+ Reflect.defineMetadata(MATADOR_EVENT_HANDLER, metadata, descriptor.value);
32
+ }
33
+ // Maintain a list of all handlers on the class for discovery
34
+ const existingHandlers = Reflect.getMetadata(MATADOR_EVENT_HANDLERS, target.constructor) ?? [];
35
+ Reflect.defineMetadata(MATADOR_EVENT_HANDLERS, [...existingHandlers, metadata], target.constructor);
36
+ return descriptor;
37
+ };
38
+ }
@@ -0,0 +1,2 @@
1
+ export { SubscriberDiscoveryService } from './subscriber-discovery.service.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/discovery/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,EAAE,MAAM,mCAAmC,CAAC"}
@@ -0,0 +1 @@
1
+ export { SubscriberDiscoveryService } from './subscriber-discovery.service.js';
@@ -0,0 +1,37 @@
1
+ import { type OnModuleInit } from '@nestjs/common';
2
+ import { DiscoveryService } from '@nestjs/core';
3
+ import { type MatadorSchema } from '@zdavison/matador';
4
+ import type { MatadorModuleOptions } from '../types.js';
5
+ /**
6
+ * Service that discovers all @OnMatadorEvent decorated methods in the application
7
+ * and builds a Matador schema from them.
8
+ */
9
+ export declare class SubscriberDiscoveryService implements OnModuleInit {
10
+ private readonly discoveryService;
11
+ private schema;
12
+ private discovered;
13
+ constructor(discoveryService: DiscoveryService);
14
+ onModuleInit(): void;
15
+ /**
16
+ * Discovers all @OnMatadorEvent decorated methods and builds the schema.
17
+ */
18
+ private discoverSubscribers;
19
+ /**
20
+ * Registers a single handler method as a subscriber.
21
+ */
22
+ private registerHandler;
23
+ /**
24
+ * Adds a subscriber to the schema for an event.
25
+ */
26
+ private addToSchema;
27
+ /**
28
+ * Gets the discovered schema.
29
+ * Must be called after onModuleInit has run.
30
+ */
31
+ getSchema(): MatadorSchema;
32
+ /**
33
+ * Gets the schema merged with additional events from options.
34
+ */
35
+ getMergedSchema(options: MatadorModuleOptions): MatadorSchema;
36
+ }
37
+ //# sourceMappingURL=subscriber-discovery.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subscriber-discovery.service.d.ts","sourceRoot":"","sources":["../../src/discovery/subscriber-discovery.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAIL,KAAK,aAAa,EAGnB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,KAAK,EAEV,oBAAoB,EACrB,MAAM,aAAa,CAAC;AAYrB;;;GAGG;AACH,qBACa,0BAA2B,YAAW,YAAY;IAIjD,OAAO,CAAC,QAAQ,CAAC,gBAAgB;IAH7C,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,UAAU,CAAS;gBAEE,gBAAgB,EAAE,gBAAgB;IAE/D,YAAY,IAAI,IAAI;IAIpB;;OAEG;IACH,OAAO,CAAC,mBAAmB;IA4B3B;;OAEG;IACH,OAAO,CAAC,eAAe;IAmDvB;;OAEG;IACH,OAAO,CAAC,WAAW;IAoBnB;;;OAGG;IACH,SAAS,IAAI,aAAa;IAI1B;;OAEG;IACH,eAAe,CAAC,OAAO,EAAE,oBAAoB,GAAG,aAAa;CAoB9D"}
@@ -0,0 +1,144 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ import { Injectable } from '@nestjs/common';
11
+ import { DiscoveryService } from '@nestjs/core';
12
+ import { createSubscriber, } from '@zdavison/matador';
13
+ import { MATADOR_EVENT_HANDLERS } from '../constants.js';
14
+ /**
15
+ * Service that discovers all @OnMatadorEvent decorated methods in the application
16
+ * and builds a Matador schema from them.
17
+ */
18
+ let SubscriberDiscoveryService = class SubscriberDiscoveryService {
19
+ discoveryService;
20
+ schema = {};
21
+ discovered = false;
22
+ constructor(discoveryService) {
23
+ this.discoveryService = discoveryService;
24
+ }
25
+ onModuleInit() {
26
+ this.discoverSubscribers();
27
+ }
28
+ /**
29
+ * Discovers all @OnMatadorEvent decorated methods and builds the schema.
30
+ */
31
+ discoverSubscribers() {
32
+ if (this.discovered) {
33
+ return;
34
+ }
35
+ const providers = this.discoveryService.getProviders();
36
+ for (const wrapper of providers) {
37
+ const { instance } = wrapper;
38
+ if (!instance || typeof instance !== 'object') {
39
+ continue;
40
+ }
41
+ const handlers = Reflect.getMetadata(MATADOR_EVENT_HANDLERS, instance.constructor);
42
+ if (!handlers || handlers.length === 0) {
43
+ continue;
44
+ }
45
+ for (const handler of handlers) {
46
+ this.registerHandler(instance, handler);
47
+ }
48
+ }
49
+ this.discovered = true;
50
+ }
51
+ /**
52
+ * Registers a single handler method as a subscriber.
53
+ */
54
+ registerHandler(instance, metadata) {
55
+ const { eventClass, options, methodName } = metadata;
56
+ const className = instance.constructor.name;
57
+ // Auto-generate name if not provided: ClassName.methodName
58
+ const subscriberName = options.name ?? `${className}.${methodName}`;
59
+ // Determine if this is a resumable subscriber
60
+ const isResumable = options.idempotent === 'resumable';
61
+ // Create the callback that calls the instance method
62
+ // biome-ignore lint/suspicious/noExplicitAny: Instance methods may have various signatures
63
+ const boundMethod = instance[methodName].bind(instance);
64
+ // Create a subscriber that calls the instance method
65
+ const subscriber = isResumable
66
+ ? createSubscriber({
67
+ name: subscriberName,
68
+ description: options.description,
69
+ idempotent: 'resumable',
70
+ importance: options.importance,
71
+ targetQueue: options.targetQueue,
72
+ enabled: options.enabled,
73
+ callback: async (envelope, context) => {
74
+ await boundMethod(envelope, context);
75
+ },
76
+ })
77
+ : createSubscriber({
78
+ name: subscriberName,
79
+ description: options.description,
80
+ idempotent: options.idempotent,
81
+ importance: options.importance,
82
+ targetQueue: options.targetQueue,
83
+ enabled: options.enabled,
84
+ callback: async (envelope) => {
85
+ await boundMethod(envelope);
86
+ },
87
+ });
88
+ // Add to schema
89
+ this.addToSchema(eventClass, subscriber);
90
+ }
91
+ /**
92
+ * Adds a subscriber to the schema for an event.
93
+ */
94
+ addToSchema(eventClass, subscriber) {
95
+ const eventKey = eventClass.key;
96
+ const existing = this.schema[eventKey];
97
+ if (existing) {
98
+ // Add subscriber to existing event entry
99
+ const [existingEventClass, existingSubscribers] = existing;
100
+ this.schema[eventKey] = [
101
+ existingEventClass,
102
+ [...existingSubscribers, subscriber],
103
+ ];
104
+ }
105
+ else {
106
+ // Create new entry
107
+ this.schema[eventKey] = [eventClass, [subscriber]];
108
+ }
109
+ }
110
+ /**
111
+ * Gets the discovered schema.
112
+ * Must be called after onModuleInit has run.
113
+ */
114
+ getSchema() {
115
+ return this.schema;
116
+ }
117
+ /**
118
+ * Gets the schema merged with additional events from options.
119
+ */
120
+ getMergedSchema(options) {
121
+ const mergedSchema = { ...this.schema };
122
+ if (options.additionalEvents) {
123
+ for (const [eventClass, subscribers] of options.additionalEvents) {
124
+ const existing = mergedSchema[eventClass.key];
125
+ if (existing) {
126
+ const [existingEventClass, existingSubscribers] = existing;
127
+ mergedSchema[eventClass.key] = [
128
+ existingEventClass,
129
+ [...existingSubscribers, ...subscribers],
130
+ ];
131
+ }
132
+ else {
133
+ mergedSchema[eventClass.key] = [eventClass, subscribers];
134
+ }
135
+ }
136
+ }
137
+ return mergedSchema;
138
+ }
139
+ };
140
+ SubscriberDiscoveryService = __decorate([
141
+ Injectable(),
142
+ __metadata("design:paramtypes", [DiscoveryService])
143
+ ], SubscriberDiscoveryService);
144
+ export { SubscriberDiscoveryService };