@nestjs-transactional/cqrs 1.0.0-alpha.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/LICENSE +21 -0
- package/README.md +431 -0
- package/dist/decorators/integration-events-handler.decorator.d.ts +125 -0
- package/dist/decorators/integration-events-handler.decorator.js +57 -0
- package/dist/decorators/integration-events-handler.decorator.js.map +1 -0
- package/dist/decorators/transactional-events-handler.decorator.d.ts +138 -0
- package/dist/decorators/transactional-events-handler.decorator.js +65 -0
- package/dist/decorators/transactional-events-handler.decorator.js.map +1 -0
- package/dist/event-dispatcher/event-dispatcher.d.ts +100 -0
- package/dist/event-dispatcher/event-dispatcher.js +229 -0
- package/dist/event-dispatcher/event-dispatcher.js.map +1 -0
- package/dist/event-publisher/hybrid-event-publisher.d.ts +76 -0
- package/dist/event-publisher/hybrid-event-publisher.js +86 -0
- package/dist/event-publisher/hybrid-event-publisher.js.map +1 -0
- package/dist/event-publisher/transactional-event-publisher-adapter.d.ts +32 -0
- package/dist/event-publisher/transactional-event-publisher-adapter.js +72 -0
- package/dist/event-publisher/transactional-event-publisher-adapter.js.map +1 -0
- package/dist/event-publisher/transactional-event-publisher.d.ts +33 -0
- package/dist/event-publisher/transactional-event-publisher.js +58 -0
- package/dist/event-publisher/transactional-event-publisher.js.map +1 -0
- package/dist/handlers/bootstrap.d.ts +18 -0
- package/dist/handlers/bootstrap.js +39 -0
- package/dist/handlers/bootstrap.js.map +1 -0
- package/dist/handlers/handler-wrapper.d.ts +77 -0
- package/dist/handlers/handler-wrapper.js +183 -0
- package/dist/handlers/handler-wrapper.js.map +1 -0
- package/dist/handlers/integration-events-handler-scanner.d.ts +37 -0
- package/dist/handlers/integration-events-handler-scanner.js +144 -0
- package/dist/handlers/integration-events-handler-scanner.js.map +1 -0
- package/dist/handlers/listener-scanner.d.ts +33 -0
- package/dist/handlers/listener-scanner.js +86 -0
- package/dist/handlers/listener-scanner.js.map +1 -0
- package/dist/handlers/outbox-listener-registrar.d.ts +49 -0
- package/dist/handlers/outbox-listener-registrar.js +17 -0
- package/dist/handlers/outbox-listener-registrar.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +37 -0
- package/dist/index.js.map +1 -0
- package/dist/interfaces/integration-event-handler.interface.d.ts +35 -0
- package/dist/interfaces/integration-event-handler.interface.js +3 -0
- package/dist/interfaces/integration-event-handler.interface.js.map +1 -0
- package/dist/interfaces/transactional-event-handler.interface.d.ts +31 -0
- package/dist/interfaces/transactional-event-handler.interface.js +3 -0
- package/dist/interfaces/transactional-event-handler.interface.js.map +1 -0
- package/dist/module/cqrs-transactional.module.d.ts +92 -0
- package/dist/module/cqrs-transactional.module.js +137 -0
- package/dist/module/cqrs-transactional.module.js.map +1 -0
- package/dist/types/transactional-listener.types.d.ts +21 -0
- package/dist/types/transactional-listener.types.js +25 -0
- package/dist/types/transactional-listener.types.js.map +1 -0
- package/package.json +73 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { type OnModuleInit } from '@nestjs/common';
|
|
2
|
+
import { DiscoveryService } from '@nestjs/core';
|
|
3
|
+
import { TransactionManager } from '@nestjs-transactional/core';
|
|
4
|
+
import { TransactionalEventDispatcher } from '../event-dispatcher/event-dispatcher';
|
|
5
|
+
import { type OutboxListenerRegistrar } from './outbox-listener-registrar';
|
|
6
|
+
/**
|
|
7
|
+
* Bootstrap-time scanner for `@IntegrationEventsHandler`-annotated
|
|
8
|
+
* classes. Decides at startup which delivery path to wire based on
|
|
9
|
+
* whether an {@link OutboxListenerRegistrar} is bound:
|
|
10
|
+
*
|
|
11
|
+
* - **Outbox bound** (typically via `OutboxModule` from
|
|
12
|
+
* `@nestjs-transactional/outbox`): the handler's `handle`
|
|
13
|
+
* method is registered with the outbox registry, wrapped in a
|
|
14
|
+
* `REQUIRES_NEW` transaction. Delivery is durable, at-least-once,
|
|
15
|
+
* retried on failure, survives restarts.
|
|
16
|
+
*
|
|
17
|
+
* - **Outbox not bound**: the handler is registered with
|
|
18
|
+
* {@link TransactionalEventDispatcher} for `AFTER_COMMIT` phase,
|
|
19
|
+
* `async: true` — and the scanner itself wraps the invocation in a
|
|
20
|
+
* fresh transaction so downstream writes commit or roll back
|
|
21
|
+
* independently, matching the outbox path as closely as in-memory
|
|
22
|
+
* dispatch allows (minus persistence).
|
|
23
|
+
*
|
|
24
|
+
* Consumer code is identical either way; only module wiring decides.
|
|
25
|
+
*/
|
|
26
|
+
export declare class IntegrationEventsHandlerScanner implements OnModuleInit {
|
|
27
|
+
private readonly discovery;
|
|
28
|
+
private readonly dispatcher;
|
|
29
|
+
private readonly manager;
|
|
30
|
+
private readonly registrar?;
|
|
31
|
+
private readonly logger;
|
|
32
|
+
constructor(discovery: DiscoveryService, dispatcher: TransactionalEventDispatcher, manager: TransactionManager, registrar?: OutboxListenerRegistrar | undefined);
|
|
33
|
+
onModuleInit(): void;
|
|
34
|
+
private registerToOutbox;
|
|
35
|
+
private registerToDispatcher;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=integration-events-handler-scanner.d.ts.map
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
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;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
12
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
13
|
+
};
|
|
14
|
+
var IntegrationEventsHandlerScanner_1;
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
exports.IntegrationEventsHandlerScanner = void 0;
|
|
17
|
+
const common_1 = require("@nestjs/common");
|
|
18
|
+
const core_1 = require("@nestjs/core");
|
|
19
|
+
const core_2 = require("@nestjs-transactional/core");
|
|
20
|
+
const integration_events_handler_decorator_1 = require("../decorators/integration-events-handler.decorator");
|
|
21
|
+
const event_dispatcher_1 = require("../event-dispatcher/event-dispatcher");
|
|
22
|
+
const transactional_listener_types_1 = require("../types/transactional-listener.types");
|
|
23
|
+
const outbox_listener_registrar_1 = require("./outbox-listener-registrar");
|
|
24
|
+
/**
|
|
25
|
+
* Bootstrap-time scanner for `@IntegrationEventsHandler`-annotated
|
|
26
|
+
* classes. Decides at startup which delivery path to wire based on
|
|
27
|
+
* whether an {@link OutboxListenerRegistrar} is bound:
|
|
28
|
+
*
|
|
29
|
+
* - **Outbox bound** (typically via `OutboxModule` from
|
|
30
|
+
* `@nestjs-transactional/outbox`): the handler's `handle`
|
|
31
|
+
* method is registered with the outbox registry, wrapped in a
|
|
32
|
+
* `REQUIRES_NEW` transaction. Delivery is durable, at-least-once,
|
|
33
|
+
* retried on failure, survives restarts.
|
|
34
|
+
*
|
|
35
|
+
* - **Outbox not bound**: the handler is registered with
|
|
36
|
+
* {@link TransactionalEventDispatcher} for `AFTER_COMMIT` phase,
|
|
37
|
+
* `async: true` — and the scanner itself wraps the invocation in a
|
|
38
|
+
* fresh transaction so downstream writes commit or roll back
|
|
39
|
+
* independently, matching the outbox path as closely as in-memory
|
|
40
|
+
* dispatch allows (minus persistence).
|
|
41
|
+
*
|
|
42
|
+
* Consumer code is identical either way; only module wiring decides.
|
|
43
|
+
*/
|
|
44
|
+
let IntegrationEventsHandlerScanner = IntegrationEventsHandlerScanner_1 = class IntegrationEventsHandlerScanner {
|
|
45
|
+
discovery;
|
|
46
|
+
dispatcher;
|
|
47
|
+
manager;
|
|
48
|
+
registrar;
|
|
49
|
+
logger = new common_1.Logger(IntegrationEventsHandlerScanner_1.name);
|
|
50
|
+
constructor(discovery, dispatcher, manager, registrar) {
|
|
51
|
+
this.discovery = discovery;
|
|
52
|
+
this.dispatcher = dispatcher;
|
|
53
|
+
this.manager = manager;
|
|
54
|
+
this.registrar = registrar;
|
|
55
|
+
}
|
|
56
|
+
onModuleInit() {
|
|
57
|
+
const providers = this.discovery.getProviders();
|
|
58
|
+
for (const wrapper of providers) {
|
|
59
|
+
if (wrapper.metatype === null ||
|
|
60
|
+
typeof wrapper.metatype !== 'function' ||
|
|
61
|
+
wrapper.instance === null ||
|
|
62
|
+
wrapper.instance === undefined) {
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
const metadata = (0, integration_events_handler_decorator_1.getIntegrationEventsHandlerMetadata)(wrapper.metatype);
|
|
66
|
+
if (metadata === undefined) {
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
const instance = wrapper.instance;
|
|
70
|
+
const rawHandle = instance.handle;
|
|
71
|
+
if (typeof rawHandle !== 'function') {
|
|
72
|
+
const className = wrapper.metatype.name ?? 'anonymous';
|
|
73
|
+
this.logger.warn(`@IntegrationEventsHandler on ${className}: missing \`handle(event)\` method — skipping`);
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
const boundHandle = rawHandle.bind(instance);
|
|
77
|
+
if (this.registrar !== undefined) {
|
|
78
|
+
this.registerToOutbox(instance, metadata, boundHandle, this.registrar);
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
this.registerToDispatcher(instance, metadata, boundHandle);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
registerToOutbox(instance, metadata, boundHandle, registrar) {
|
|
86
|
+
const manager = this.manager;
|
|
87
|
+
const invoke = async (event) => {
|
|
88
|
+
await manager.run({ propagation: core_2.PropagationMode.REQUIRES_NEW }, async () => {
|
|
89
|
+
await boundHandle(event);
|
|
90
|
+
});
|
|
91
|
+
};
|
|
92
|
+
const baseId = metadata.id ?? instance.constructor.name;
|
|
93
|
+
for (const eventType of metadata.eventTypes) {
|
|
94
|
+
const listenerId = composeListenerId(baseId, eventType);
|
|
95
|
+
registrar.register({
|
|
96
|
+
id: listenerId,
|
|
97
|
+
eventType: eventType.name,
|
|
98
|
+
invoke,
|
|
99
|
+
});
|
|
100
|
+
this.logger.debug(`Registered ${instance.constructor.name}.handle for ${eventType.name} via outbox (id=${listenerId})`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
registerToDispatcher(instance, metadata, boundHandle) {
|
|
104
|
+
const manager = this.manager;
|
|
105
|
+
// Proxy preserves the original class name for dispatcher logs
|
|
106
|
+
// while exposing a `handle` that opens a fresh transaction per
|
|
107
|
+
// invocation — AFTER_COMMIT + async + a new tx, matching the
|
|
108
|
+
// outbox semantics as closely as in-memory dispatch permits.
|
|
109
|
+
const ctor = instance.constructor;
|
|
110
|
+
const proxy = Object.create(ctor.prototype);
|
|
111
|
+
proxy.handle = async (event) => {
|
|
112
|
+
await manager.run({}, async () => {
|
|
113
|
+
await boundHandle(event);
|
|
114
|
+
});
|
|
115
|
+
};
|
|
116
|
+
for (const eventType of metadata.eventTypes) {
|
|
117
|
+
this.dispatcher.registerListener(proxy, 'handle', {
|
|
118
|
+
eventType,
|
|
119
|
+
phase: transactional_listener_types_1.TransactionPhase.AFTER_COMMIT,
|
|
120
|
+
async: true,
|
|
121
|
+
fallbackExecution: false,
|
|
122
|
+
dataSource: metadata.dataSource,
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
exports.IntegrationEventsHandlerScanner = IntegrationEventsHandlerScanner;
|
|
128
|
+
exports.IntegrationEventsHandlerScanner = IntegrationEventsHandlerScanner = IntegrationEventsHandlerScanner_1 = __decorate([
|
|
129
|
+
(0, common_1.Injectable)(),
|
|
130
|
+
__param(3, (0, common_1.Optional)()),
|
|
131
|
+
__param(3, (0, common_1.Inject)(outbox_listener_registrar_1.OUTBOX_LISTENER_REGISTRAR)),
|
|
132
|
+
__metadata("design:paramtypes", [core_1.DiscoveryService,
|
|
133
|
+
event_dispatcher_1.TransactionalEventDispatcher,
|
|
134
|
+
core_2.TransactionManager, Object])
|
|
135
|
+
], IntegrationEventsHandlerScanner);
|
|
136
|
+
/**
|
|
137
|
+
* Compose the stable listener id. Always ends with `#${EventName}`
|
|
138
|
+
* so a single class handling multiple event types gets distinct ids
|
|
139
|
+
* — the registry requires globally-unique ids.
|
|
140
|
+
*/
|
|
141
|
+
function composeListenerId(baseId, eventType) {
|
|
142
|
+
return `${baseId}#${eventType.name}`;
|
|
143
|
+
}
|
|
144
|
+
//# sourceMappingURL=integration-events-handler-scanner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"integration-events-handler-scanner.js","sourceRoot":"","sources":["../../src/handlers/integration-events-handler-scanner.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2CAOwB;AACxB,uCAAgD;AAChD,qDAAiF;AAEjF,6GAG4D;AAC5D,2EAAoF;AACpF,wFAAyE;AAEzE,2EAGqC;AAIrC;;;;;;;;;;;;;;;;;;;GAmBG;AAEI,IAAM,+BAA+B,uCAArC,MAAM,+BAA+B;IAIvB;IACA;IACA;IAGA;IARF,MAAM,GAAG,IAAI,eAAM,CAAC,iCAA+B,CAAC,IAAI,CAAC,CAAC;IAE3E,YACmB,SAA2B,EAC3B,UAAwC,EACxC,OAA2B,EAG3B,SAAmC;QALnC,cAAS,GAAT,SAAS,CAAkB;QAC3B,eAAU,GAAV,UAAU,CAA8B;QACxC,YAAO,GAAP,OAAO,CAAoB;QAG3B,cAAS,GAAT,SAAS,CAA0B;IACnD,CAAC;IAEJ,YAAY;QACV,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,YAAY,EAAE,CAAC;QAEhD,KAAK,MAAM,OAAO,IAAI,SAAS,EAAE,CAAC;YAChC,IACE,OAAO,CAAC,QAAQ,KAAK,IAAI;gBACzB,OAAO,OAAO,CAAC,QAAQ,KAAK,UAAU;gBACtC,OAAO,CAAC,QAAQ,KAAK,IAAI;gBACzB,OAAO,CAAC,QAAQ,KAAK,SAAS,EAC9B,CAAC;gBACD,SAAS;YACX,CAAC;YAED,MAAM,QAAQ,GAAG,IAAA,0EAAmC,EAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;YACvE,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;gBAC3B,SAAS;YACX,CAAC;YAED,MAAM,QAAQ,GAAW,OAAO,CAAC,QAAkB,CAAC;YACpD,MAAM,SAAS,GAAI,QAAoC,CAAC,MAAM,CAAC;YAC/D,IAAI,OAAO,SAAS,KAAK,UAAU,EAAE,CAAC;gBACpC,MAAM,SAAS,GAAI,OAAO,CAAC,QAA8B,CAAC,IAAI,IAAI,WAAW,CAAC;gBAC9E,IAAI,CAAC,MAAM,CAAC,IAAI,CACd,gCAAgC,SAAS,+CAA+C,CACzF,CAAC;gBACF,SAAS;YACX,CAAC;YAED,MAAM,WAAW,GAAI,SAA2B,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAEhE,IAAI,IAAI,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;gBACjC,IAAI,CAAC,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;YACzE,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,oBAAoB,CAAC,QAAQ,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC;YAC7D,CAAC;QACH,CAAC;IACH,CAAC;IAEO,gBAAgB,CACtB,QAAgB,EAChB,QAA0C,EAC1C,WAA0B,EAC1B,SAAkC;QAElC,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;QAC7B,MAAM,MAAM,GAAG,KAAK,EAAE,KAAc,EAAiB,EAAE;YACrD,MAAM,OAAO,CAAC,GAAG,CAAC,EAAE,WAAW,EAAE,sBAAe,CAAC,YAAY,EAAE,EAAE,KAAK,IAAI,EAAE;gBAC1E,MAAM,WAAW,CAAC,KAAK,CAAC,CAAC;YAC3B,CAAC,CAAC,CAAC;QACL,CAAC,CAAC;QAEF,MAAM,MAAM,GAAG,QAAQ,CAAC,EAAE,IAAI,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC;QAExD,KAAK,MAAM,SAAS,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC;YAC5C,MAAM,UAAU,GAAG,iBAAiB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;YACxD,SAAS,CAAC,QAAQ,CAAC;gBACjB,EAAE,EAAE,UAAU;gBACd,SAAS,EAAE,SAAS,CAAC,IAAI;gBACzB,MAAM;aACP,CAAC,CAAC;YACH,IAAI,CAAC,MAAM,CAAC,KAAK,CACf,cAAc,QAAQ,CAAC,WAAW,CAAC,IAAI,eAAe,SAAS,CAAC,IAAI,mBAAmB,UAAU,GAAG,CACrG,CAAC;QACJ,CAAC;IACH,CAAC;IAEO,oBAAoB,CAC1B,QAAgB,EAChB,QAA0C,EAC1C,WAA0B;QAE1B,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;QAC7B,8DAA8D;QAC9D,+DAA+D;QAC/D,6DAA6D;QAC7D,6DAA6D;QAC7D,MAAM,IAAI,GAAG,QAAQ,CAAC,WAA2C,CAAC;QAClE,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAA4B,CAAC;QACvE,KAAK,CAAC,MAAM,GAAG,KAAK,EAAE,KAAc,EAAiB,EAAE;YACrD,MAAM,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,KAAK,IAAI,EAAE;gBAC/B,MAAM,WAAW,CAAC,KAAK,CAAC,CAAC;YAC3B,CAAC,CAAC,CAAC;QACL,CAAC,CAAC;QAEF,KAAK,MAAM,SAAS,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC;YAC5C,IAAI,CAAC,UAAU,CAAC,gBAAgB,CAAC,KAAK,EAAE,QAAQ,EAAE;gBAChD,SAAS;gBACT,KAAK,EAAE,+CAAgB,CAAC,YAAY;gBACpC,KAAK,EAAE,IAAI;gBACX,iBAAiB,EAAE,KAAK;gBACxB,UAAU,EAAE,QAAQ,CAAC,UAAU;aAChC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;CACF,CAAA;AA1GY,0EAA+B;0CAA/B,+BAA+B;IAD3C,IAAA,mBAAU,GAAE;IAQR,WAAA,IAAA,iBAAQ,GAAE,CAAA;IACV,WAAA,IAAA,eAAM,EAAC,qDAAyB,CAAC,CAAA;qCAJN,uBAAgB;QACf,+CAA4B;QAC/B,yBAAkB;GANnC,+BAA+B,CA0G3C;AAED;;;;GAIG;AACH,SAAS,iBAAiB,CAAC,MAAc,EAAE,SAAe;IACxD,OAAO,GAAG,MAAM,IAAI,SAAS,CAAC,IAAI,EAAE,CAAC;AACvC,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { type OnModuleInit } from '@nestjs/common';
|
|
2
|
+
import { DiscoveryService } from '@nestjs/core';
|
|
3
|
+
import { TransactionalEventDispatcher } from '../event-dispatcher/event-dispatcher';
|
|
4
|
+
/**
|
|
5
|
+
* Bootstrap-time scanner that walks every provider in the running
|
|
6
|
+
* Nest application, finds every class decorated with
|
|
7
|
+
* `@TransactionalEventsHandler`, and registers its `handle` method
|
|
8
|
+
* with the {@link TransactionalEventDispatcher} — one registration
|
|
9
|
+
* per event type listed in the decorator metadata.
|
|
10
|
+
*
|
|
11
|
+
* Scanning is class-level only. The handler class must expose a
|
|
12
|
+
* `handle(event): void | Promise<void>` method (enforce this at the
|
|
13
|
+
* type level by implementing `ITransactionalEventHandler`).
|
|
14
|
+
*
|
|
15
|
+
* `@IntegrationEventsHandler` is NOT processed here —
|
|
16
|
+
* `IntegrationEventsHandlerScanner` owns it, with smart routing to
|
|
17
|
+
* the outbox or this dispatcher depending on which provider is bound.
|
|
18
|
+
*
|
|
19
|
+
* Registration happens in `onModuleInit` so all providers have been
|
|
20
|
+
* instantiated by the time the scan runs. Providers with no instance
|
|
21
|
+
* or no metatype are skipped silently.
|
|
22
|
+
*
|
|
23
|
+
* Wired into the application by `CqrsTransactionalModule`. Not
|
|
24
|
+
* exported for direct consumer instantiation.
|
|
25
|
+
*/
|
|
26
|
+
export declare class TransactionalListenerScanner implements OnModuleInit {
|
|
27
|
+
private readonly discovery;
|
|
28
|
+
private readonly dispatcher;
|
|
29
|
+
private readonly logger;
|
|
30
|
+
constructor(discovery: DiscoveryService, dispatcher: TransactionalEventDispatcher);
|
|
31
|
+
onModuleInit(): void;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=listener-scanner.d.ts.map
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
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;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
var TransactionalListenerScanner_1;
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.TransactionalListenerScanner = void 0;
|
|
14
|
+
const common_1 = require("@nestjs/common");
|
|
15
|
+
const core_1 = require("@nestjs/core");
|
|
16
|
+
const transactional_events_handler_decorator_1 = require("../decorators/transactional-events-handler.decorator");
|
|
17
|
+
const event_dispatcher_1 = require("../event-dispatcher/event-dispatcher");
|
|
18
|
+
/**
|
|
19
|
+
* Bootstrap-time scanner that walks every provider in the running
|
|
20
|
+
* Nest application, finds every class decorated with
|
|
21
|
+
* `@TransactionalEventsHandler`, and registers its `handle` method
|
|
22
|
+
* with the {@link TransactionalEventDispatcher} — one registration
|
|
23
|
+
* per event type listed in the decorator metadata.
|
|
24
|
+
*
|
|
25
|
+
* Scanning is class-level only. The handler class must expose a
|
|
26
|
+
* `handle(event): void | Promise<void>` method (enforce this at the
|
|
27
|
+
* type level by implementing `ITransactionalEventHandler`).
|
|
28
|
+
*
|
|
29
|
+
* `@IntegrationEventsHandler` is NOT processed here —
|
|
30
|
+
* `IntegrationEventsHandlerScanner` owns it, with smart routing to
|
|
31
|
+
* the outbox or this dispatcher depending on which provider is bound.
|
|
32
|
+
*
|
|
33
|
+
* Registration happens in `onModuleInit` so all providers have been
|
|
34
|
+
* instantiated by the time the scan runs. Providers with no instance
|
|
35
|
+
* or no metatype are skipped silently.
|
|
36
|
+
*
|
|
37
|
+
* Wired into the application by `CqrsTransactionalModule`. Not
|
|
38
|
+
* exported for direct consumer instantiation.
|
|
39
|
+
*/
|
|
40
|
+
let TransactionalListenerScanner = TransactionalListenerScanner_1 = class TransactionalListenerScanner {
|
|
41
|
+
discovery;
|
|
42
|
+
dispatcher;
|
|
43
|
+
logger = new common_1.Logger(TransactionalListenerScanner_1.name);
|
|
44
|
+
constructor(discovery, dispatcher) {
|
|
45
|
+
this.discovery = discovery;
|
|
46
|
+
this.dispatcher = dispatcher;
|
|
47
|
+
}
|
|
48
|
+
onModuleInit() {
|
|
49
|
+
const providers = this.discovery.getProviders();
|
|
50
|
+
for (const wrapper of providers) {
|
|
51
|
+
if (wrapper.metatype === null ||
|
|
52
|
+
typeof wrapper.metatype !== 'function' ||
|
|
53
|
+
wrapper.instance === null ||
|
|
54
|
+
wrapper.instance === undefined) {
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
const metadata = (0, transactional_events_handler_decorator_1.getTransactionalEventsHandlerMetadata)(wrapper.metatype);
|
|
58
|
+
if (metadata === undefined) {
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
const instance = wrapper.instance;
|
|
62
|
+
const handleMethod = instance.handle;
|
|
63
|
+
if (typeof handleMethod !== 'function') {
|
|
64
|
+
const className = wrapper.metatype.name ?? 'anonymous';
|
|
65
|
+
this.logger.warn(`@TransactionalEventsHandler on ${className}: missing \`handle(event)\` method — skipping`);
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
for (const eventType of metadata.eventTypes) {
|
|
69
|
+
this.dispatcher.registerListener(instance, 'handle', {
|
|
70
|
+
eventType,
|
|
71
|
+
phase: metadata.phase,
|
|
72
|
+
async: metadata.async,
|
|
73
|
+
fallbackExecution: metadata.fallbackExecution,
|
|
74
|
+
dataSource: metadata.dataSource,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
exports.TransactionalListenerScanner = TransactionalListenerScanner;
|
|
81
|
+
exports.TransactionalListenerScanner = TransactionalListenerScanner = TransactionalListenerScanner_1 = __decorate([
|
|
82
|
+
(0, common_1.Injectable)(),
|
|
83
|
+
__metadata("design:paramtypes", [core_1.DiscoveryService,
|
|
84
|
+
event_dispatcher_1.TransactionalEventDispatcher])
|
|
85
|
+
], TransactionalListenerScanner);
|
|
86
|
+
//# sourceMappingURL=listener-scanner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"listener-scanner.js","sourceRoot":"","sources":["../../src/handlers/listener-scanner.ts"],"names":[],"mappings":";;;;;;;;;;;;;AAAA,2CAAuE;AACvE,uCAAgD;AAEhD,iHAA6G;AAC7G,2EAAoF;AAEpF;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEI,IAAM,4BAA4B,oCAAlC,MAAM,4BAA4B;IAIpB;IACA;IAJF,MAAM,GAAG,IAAI,eAAM,CAAC,8BAA4B,CAAC,IAAI,CAAC,CAAC;IAExE,YACmB,SAA2B,EAC3B,UAAwC;QADxC,cAAS,GAAT,SAAS,CAAkB;QAC3B,eAAU,GAAV,UAAU,CAA8B;IACxD,CAAC;IAEJ,YAAY;QACV,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,YAAY,EAAE,CAAC;QAEhD,KAAK,MAAM,OAAO,IAAI,SAAS,EAAE,CAAC;YAChC,IACE,OAAO,CAAC,QAAQ,KAAK,IAAI;gBACzB,OAAO,OAAO,CAAC,QAAQ,KAAK,UAAU;gBACtC,OAAO,CAAC,QAAQ,KAAK,IAAI;gBACzB,OAAO,CAAC,QAAQ,KAAK,SAAS,EAC9B,CAAC;gBACD,SAAS;YACX,CAAC;YAED,MAAM,QAAQ,GAAG,IAAA,8EAAqC,EAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;YACzE,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;gBAC3B,SAAS;YACX,CAAC;YAED,MAAM,QAAQ,GAAW,OAAO,CAAC,QAAkB,CAAC;YACpD,MAAM,YAAY,GAAI,QAAoC,CAAC,MAAM,CAAC;YAClE,IAAI,OAAO,YAAY,KAAK,UAAU,EAAE,CAAC;gBACvC,MAAM,SAAS,GAAI,OAAO,CAAC,QAA8B,CAAC,IAAI,IAAI,WAAW,CAAC;gBAC9E,IAAI,CAAC,MAAM,CAAC,IAAI,CACd,kCAAkC,SAAS,+CAA+C,CAC3F,CAAC;gBACF,SAAS;YACX,CAAC;YAED,KAAK,MAAM,SAAS,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC;gBAC5C,IAAI,CAAC,UAAU,CAAC,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,EAAE;oBACnD,SAAS;oBACT,KAAK,EAAE,QAAQ,CAAC,KAAK;oBACrB,KAAK,EAAE,QAAQ,CAAC,KAAK;oBACrB,iBAAiB,EAAE,QAAQ,CAAC,iBAAiB;oBAC7C,UAAU,EAAE,QAAQ,CAAC,UAAU;iBAChC,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;CACF,CAAA;AA/CY,oEAA4B;uCAA5B,4BAA4B;IADxC,IAAA,mBAAU,GAAE;qCAKmB,uBAAgB;QACf,+CAA4B;GALhD,4BAA4B,CA+CxC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal structural contract for an outbox listener registrar,
|
|
3
|
+
* declared here (and injected via {@link OUTBOX_LISTENER_REGISTRAR})
|
|
4
|
+
* rather than imported from `@nestjs-transactional/outbox`
|
|
5
|
+
* directly — keeps the cqrs package usable without the outbox stack.
|
|
6
|
+
*
|
|
7
|
+
* `@nestjs-transactional/outbox`'s `OutboxListenerRegistry`
|
|
8
|
+
* satisfies this interface structurally (its `register` method
|
|
9
|
+
* accepts exactly this shape). The outbox package's
|
|
10
|
+
* `MultiDsOutboxListenerRegistrar` (Phase 14.3.1) is a smarter
|
|
11
|
+
* implementation that walks every per-dataSource event-type registry
|
|
12
|
+
* to resolve which dataSource owns each listener's event class and
|
|
13
|
+
* routes the registration to the matching per-DS registry — so a
|
|
14
|
+
* single binding handles arbitrary multi-dataSource deployments.
|
|
15
|
+
*
|
|
16
|
+
* **Auto-binding (Phase 14.3.1).** `OutboxModule.forRoot` binds this
|
|
17
|
+
* token to `MultiDsOutboxListenerRegistrar` automatically on the
|
|
18
|
+
* first `forRoot` call. Consumers do NOT need to declare the binding
|
|
19
|
+
* themselves; the registrar is in place by the time the cqrs
|
|
20
|
+
* `IntegrationEventsHandlerScanner` runs its `onModuleInit`. Manual
|
|
21
|
+
* binding remains supported for advanced cases (custom routing
|
|
22
|
+
* policy, structural decoupling tests).
|
|
23
|
+
*
|
|
24
|
+
* Cross-package token identity is via `Symbol.for(...)` so the cqrs
|
|
25
|
+
* declaration and the outbox auto-binding refer to the same Symbol
|
|
26
|
+
* without either package importing from the other (Convention #8 —
|
|
27
|
+
* mirrors `WRAPPED_MARKER`).
|
|
28
|
+
*/
|
|
29
|
+
export interface OutboxListenerRegistrar {
|
|
30
|
+
register(listener: {
|
|
31
|
+
readonly id: string;
|
|
32
|
+
readonly eventType: string;
|
|
33
|
+
readonly invoke: (event: unknown) => Promise<void>;
|
|
34
|
+
}): void;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* DI token for the optional {@link OutboxListenerRegistrar} injected
|
|
38
|
+
* into `IntegrationEventsHandlerScanner`. When unbound, the scanner
|
|
39
|
+
* falls back to in-memory registration via
|
|
40
|
+
* {@link TransactionalEventDispatcher}.
|
|
41
|
+
*
|
|
42
|
+
* `Symbol.for(...)` (not `Symbol(...)`) — Phase 14.3.1: the outbox
|
|
43
|
+
* package auto-binds this token to its `MultiDsOutboxListenerRegistrar`
|
|
44
|
+
* via `Symbol.for` lookup on the same key. Both packages thereby
|
|
45
|
+
* refer to the same Symbol identity without a direct import in
|
|
46
|
+
* either direction.
|
|
47
|
+
*/
|
|
48
|
+
export declare const OUTBOX_LISTENER_REGISTRAR: unique symbol;
|
|
49
|
+
//# sourceMappingURL=outbox-listener-registrar.d.ts.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.OUTBOX_LISTENER_REGISTRAR = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* DI token for the optional {@link OutboxListenerRegistrar} injected
|
|
6
|
+
* into `IntegrationEventsHandlerScanner`. When unbound, the scanner
|
|
7
|
+
* falls back to in-memory registration via
|
|
8
|
+
* {@link TransactionalEventDispatcher}.
|
|
9
|
+
*
|
|
10
|
+
* `Symbol.for(...)` (not `Symbol(...)`) — Phase 14.3.1: the outbox
|
|
11
|
+
* package auto-binds this token to its `MultiDsOutboxListenerRegistrar`
|
|
12
|
+
* via `Symbol.for` lookup on the same key. Both packages thereby
|
|
13
|
+
* refer to the same Symbol identity without a direct import in
|
|
14
|
+
* either direction.
|
|
15
|
+
*/
|
|
16
|
+
exports.OUTBOX_LISTENER_REGISTRAR = Symbol.for('@nestjs-transactional/cqrs/outbox-listener-registrar');
|
|
17
|
+
//# sourceMappingURL=outbox-listener-registrar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"outbox-listener-registrar.js","sourceRoot":"","sources":["../../src/handlers/outbox-listener-registrar.ts"],"names":[],"mappings":";;;AAoCA;;;;;;;;;;;GAWG;AACU,QAAA,yBAAyB,GAAG,MAAM,CAAC,GAAG,CACjD,sDAAsD,CACvD,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export { TransactionPhase } from './types/transactional-listener.types';
|
|
2
|
+
export { TRANSACTIONAL_EVENTS_HANDLER_METADATA, TransactionalEventsHandler, getTransactionalEventsHandlerMetadata, type TransactionalEventsHandlerMetadata, type TransactionalEventsHandlerOptions, } from './decorators/transactional-events-handler.decorator';
|
|
3
|
+
export { INTEGRATION_EVENTS_HANDLER_METADATA, IntegrationEventsHandler, getIntegrationEventsHandlerMetadata, type IntegrationEventsHandlerMetadata, type IntegrationEventsHandlerOptions, } from './decorators/integration-events-handler.decorator';
|
|
4
|
+
export type { ITransactionalEventHandler } from './interfaces/transactional-event-handler.interface';
|
|
5
|
+
export type { IIntegrationEventHandler } from './interfaces/integration-event-handler.interface';
|
|
6
|
+
export { TransactionalEventDispatcher, type DispatcherListenerMetadata, } from './event-dispatcher/event-dispatcher';
|
|
7
|
+
export { TransactionalListenerScanner } from './handlers/listener-scanner';
|
|
8
|
+
export { IntegrationEventsHandlerScanner } from './handlers/integration-events-handler-scanner';
|
|
9
|
+
export { OUTBOX_LISTENER_REGISTRAR, type OutboxListenerRegistrar, } from './handlers/outbox-listener-registrar';
|
|
10
|
+
export { CQRS_HANDLER_WRAPPER_OPTIONS, CqrsHandlerWrapper, type HandlerWrapperOptions, } from './handlers/handler-wrapper';
|
|
11
|
+
export { CqrsTransactionalBootstrap } from './handlers/bootstrap';
|
|
12
|
+
export { TransactionalEventPublisher } from './event-publisher/transactional-event-publisher';
|
|
13
|
+
export { TransactionalEventPublisherAdapter } from './event-publisher/transactional-event-publisher-adapter';
|
|
14
|
+
export { HybridEventPublisher, OUTBOX_PUBLICATION_SCHEDULER, type OutboxPublicationScheduler, } from './event-publisher/hybrid-event-publisher';
|
|
15
|
+
export { CQRS_TRANSACTIONAL_OPTIONS, CqrsTransactionalModule, type CqrsTransactionalOptions, } from './module/cqrs-transactional.module';
|
|
16
|
+
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CqrsTransactionalModule = exports.CQRS_TRANSACTIONAL_OPTIONS = exports.OUTBOX_PUBLICATION_SCHEDULER = exports.HybridEventPublisher = exports.TransactionalEventPublisherAdapter = exports.TransactionalEventPublisher = exports.CqrsTransactionalBootstrap = exports.CqrsHandlerWrapper = exports.CQRS_HANDLER_WRAPPER_OPTIONS = exports.OUTBOX_LISTENER_REGISTRAR = exports.IntegrationEventsHandlerScanner = exports.TransactionalListenerScanner = exports.TransactionalEventDispatcher = exports.getIntegrationEventsHandlerMetadata = exports.IntegrationEventsHandler = exports.INTEGRATION_EVENTS_HANDLER_METADATA = exports.getTransactionalEventsHandlerMetadata = exports.TransactionalEventsHandler = exports.TRANSACTIONAL_EVENTS_HANDLER_METADATA = exports.TransactionPhase = void 0;
|
|
4
|
+
var transactional_listener_types_1 = require("./types/transactional-listener.types");
|
|
5
|
+
Object.defineProperty(exports, "TransactionPhase", { enumerable: true, get: function () { return transactional_listener_types_1.TransactionPhase; } });
|
|
6
|
+
var transactional_events_handler_decorator_1 = require("./decorators/transactional-events-handler.decorator");
|
|
7
|
+
Object.defineProperty(exports, "TRANSACTIONAL_EVENTS_HANDLER_METADATA", { enumerable: true, get: function () { return transactional_events_handler_decorator_1.TRANSACTIONAL_EVENTS_HANDLER_METADATA; } });
|
|
8
|
+
Object.defineProperty(exports, "TransactionalEventsHandler", { enumerable: true, get: function () { return transactional_events_handler_decorator_1.TransactionalEventsHandler; } });
|
|
9
|
+
Object.defineProperty(exports, "getTransactionalEventsHandlerMetadata", { enumerable: true, get: function () { return transactional_events_handler_decorator_1.getTransactionalEventsHandlerMetadata; } });
|
|
10
|
+
var integration_events_handler_decorator_1 = require("./decorators/integration-events-handler.decorator");
|
|
11
|
+
Object.defineProperty(exports, "INTEGRATION_EVENTS_HANDLER_METADATA", { enumerable: true, get: function () { return integration_events_handler_decorator_1.INTEGRATION_EVENTS_HANDLER_METADATA; } });
|
|
12
|
+
Object.defineProperty(exports, "IntegrationEventsHandler", { enumerable: true, get: function () { return integration_events_handler_decorator_1.IntegrationEventsHandler; } });
|
|
13
|
+
Object.defineProperty(exports, "getIntegrationEventsHandlerMetadata", { enumerable: true, get: function () { return integration_events_handler_decorator_1.getIntegrationEventsHandlerMetadata; } });
|
|
14
|
+
var event_dispatcher_1 = require("./event-dispatcher/event-dispatcher");
|
|
15
|
+
Object.defineProperty(exports, "TransactionalEventDispatcher", { enumerable: true, get: function () { return event_dispatcher_1.TransactionalEventDispatcher; } });
|
|
16
|
+
var listener_scanner_1 = require("./handlers/listener-scanner");
|
|
17
|
+
Object.defineProperty(exports, "TransactionalListenerScanner", { enumerable: true, get: function () { return listener_scanner_1.TransactionalListenerScanner; } });
|
|
18
|
+
var integration_events_handler_scanner_1 = require("./handlers/integration-events-handler-scanner");
|
|
19
|
+
Object.defineProperty(exports, "IntegrationEventsHandlerScanner", { enumerable: true, get: function () { return integration_events_handler_scanner_1.IntegrationEventsHandlerScanner; } });
|
|
20
|
+
var outbox_listener_registrar_1 = require("./handlers/outbox-listener-registrar");
|
|
21
|
+
Object.defineProperty(exports, "OUTBOX_LISTENER_REGISTRAR", { enumerable: true, get: function () { return outbox_listener_registrar_1.OUTBOX_LISTENER_REGISTRAR; } });
|
|
22
|
+
var handler_wrapper_1 = require("./handlers/handler-wrapper");
|
|
23
|
+
Object.defineProperty(exports, "CQRS_HANDLER_WRAPPER_OPTIONS", { enumerable: true, get: function () { return handler_wrapper_1.CQRS_HANDLER_WRAPPER_OPTIONS; } });
|
|
24
|
+
Object.defineProperty(exports, "CqrsHandlerWrapper", { enumerable: true, get: function () { return handler_wrapper_1.CqrsHandlerWrapper; } });
|
|
25
|
+
var bootstrap_1 = require("./handlers/bootstrap");
|
|
26
|
+
Object.defineProperty(exports, "CqrsTransactionalBootstrap", { enumerable: true, get: function () { return bootstrap_1.CqrsTransactionalBootstrap; } });
|
|
27
|
+
var transactional_event_publisher_1 = require("./event-publisher/transactional-event-publisher");
|
|
28
|
+
Object.defineProperty(exports, "TransactionalEventPublisher", { enumerable: true, get: function () { return transactional_event_publisher_1.TransactionalEventPublisher; } });
|
|
29
|
+
var transactional_event_publisher_adapter_1 = require("./event-publisher/transactional-event-publisher-adapter");
|
|
30
|
+
Object.defineProperty(exports, "TransactionalEventPublisherAdapter", { enumerable: true, get: function () { return transactional_event_publisher_adapter_1.TransactionalEventPublisherAdapter; } });
|
|
31
|
+
var hybrid_event_publisher_1 = require("./event-publisher/hybrid-event-publisher");
|
|
32
|
+
Object.defineProperty(exports, "HybridEventPublisher", { enumerable: true, get: function () { return hybrid_event_publisher_1.HybridEventPublisher; } });
|
|
33
|
+
Object.defineProperty(exports, "OUTBOX_PUBLICATION_SCHEDULER", { enumerable: true, get: function () { return hybrid_event_publisher_1.OUTBOX_PUBLICATION_SCHEDULER; } });
|
|
34
|
+
var cqrs_transactional_module_1 = require("./module/cqrs-transactional.module");
|
|
35
|
+
Object.defineProperty(exports, "CQRS_TRANSACTIONAL_OPTIONS", { enumerable: true, get: function () { return cqrs_transactional_module_1.CQRS_TRANSACTIONAL_OPTIONS; } });
|
|
36
|
+
Object.defineProperty(exports, "CqrsTransactionalModule", { enumerable: true, get: function () { return cqrs_transactional_module_1.CqrsTransactionalModule; } });
|
|
37
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,qFAAwE;AAA/D,gIAAA,gBAAgB,OAAA;AAEzB,8GAM6D;AAL3D,+JAAA,qCAAqC,OAAA;AACrC,oJAAA,0BAA0B,OAAA;AAC1B,+JAAA,qCAAqC,OAAA;AAKvC,0GAM2D;AALzD,2JAAA,mCAAmC,OAAA;AACnC,gJAAA,wBAAwB,OAAA;AACxB,2JAAA,mCAAmC,OAAA;AAQrC,wEAG6C;AAF3C,gIAAA,4BAA4B,OAAA;AAI9B,gEAA2E;AAAlE,gIAAA,4BAA4B,OAAA;AACrC,oGAAgG;AAAvF,qJAAA,+BAA+B,OAAA;AACxC,kFAG8C;AAF5C,sIAAA,yBAAyB,OAAA;AAI3B,8DAIoC;AAHlC,+HAAA,4BAA4B,OAAA;AAC5B,qHAAA,kBAAkB,OAAA;AAIpB,kDAAkE;AAAzD,uHAAA,0BAA0B,OAAA;AAEnC,iGAA8F;AAArF,4IAAA,2BAA2B,OAAA;AACpC,iHAA6G;AAApG,2JAAA,kCAAkC,OAAA;AAC3C,mFAIkD;AAHhD,8HAAA,oBAAoB,OAAA;AACpB,sIAAA,4BAA4B,OAAA;AAI9B,gFAI4C;AAH1C,uIAAA,0BAA0B,OAAA;AAC1B,oIAAA,uBAAuB,OAAA"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Contract implemented by classes annotated with
|
|
3
|
+
* `@IntegrationEventsHandler` — the smart-default decorator for
|
|
4
|
+
* cross-module / cross-service event handlers.
|
|
5
|
+
*
|
|
6
|
+
* The Spring Modulith equivalent is `@ApplicationModuleListener`.
|
|
7
|
+
* The name `@IntegrationEventsHandler` is preferred in the NestJS
|
|
8
|
+
* ecosystem because "Application Module" overlaps with NestJS's own
|
|
9
|
+
* `@Module()` (a DI concept), and "Integration events" is the
|
|
10
|
+
* established DDD/microservices term for the role this decorator
|
|
11
|
+
* plays.
|
|
12
|
+
*
|
|
13
|
+
* Shape is identical to {@link ITransactionalEventHandler}; the two
|
|
14
|
+
* interfaces exist separately as marker types so code can
|
|
15
|
+
* discriminate by intent (cross-module integration handler vs.
|
|
16
|
+
* intra-module transactional listener) even though both share the
|
|
17
|
+
* `handle(event)` contract.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```ts
|
|
21
|
+
* @IntegrationEventsHandler(OrderPlacedEvent)
|
|
22
|
+
* export class InventoryReservationHandler
|
|
23
|
+
* implements IIntegrationEventHandler<OrderPlacedEvent>
|
|
24
|
+
* {
|
|
25
|
+
* async handle(event: OrderPlacedEvent): Promise<void> {
|
|
26
|
+
* // durable when the outbox is wired, in-memory AFTER_COMMIT
|
|
27
|
+
* // fallback otherwise.
|
|
28
|
+
* }
|
|
29
|
+
* }
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export interface IIntegrationEventHandler<T = any> {
|
|
33
|
+
handle(event: T): Promise<void> | void;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=integration-event-handler.interface.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"integration-event-handler.interface.js","sourceRoot":"","sources":["../../src/interfaces/integration-event-handler.interface.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Contract implemented by classes annotated with
|
|
3
|
+
* `@TransactionalEventsHandler`.
|
|
4
|
+
*
|
|
5
|
+
* The single `handle` method is invoked for each event of a type the
|
|
6
|
+
* class is registered for. When a handler listens to several event
|
|
7
|
+
* types, narrow the generic parameter to their union (e.g.
|
|
8
|
+
* `ITransactionalEventHandler<OrderPlaced | OrderCancelled>`) or
|
|
9
|
+
* leave it unbound for the most permissive shape.
|
|
10
|
+
*
|
|
11
|
+
* Mirrors the ergonomics of `IEventHandler` from `@nestjs/cqrs` —
|
|
12
|
+
* `any` as the default generic parameter is deliberate so that
|
|
13
|
+
* `implements ITransactionalEventHandler` without a type argument
|
|
14
|
+
* type-checks against any concrete event shape.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```ts
|
|
18
|
+
* @TransactionalEventsHandler(OrderPlacedEvent)
|
|
19
|
+
* export class OrderPlacedNotifier
|
|
20
|
+
* implements ITransactionalEventHandler<OrderPlacedEvent>
|
|
21
|
+
* {
|
|
22
|
+
* async handle(event: OrderPlacedEvent): Promise<void> {
|
|
23
|
+
* // ...
|
|
24
|
+
* }
|
|
25
|
+
* }
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export interface ITransactionalEventHandler<T = any> {
|
|
29
|
+
handle(event: T): Promise<void> | void;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=transactional-event-handler.interface.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transactional-event-handler.interface.js","sourceRoot":"","sources":["../../src/interfaces/transactional-event-handler.interface.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { type DynamicModule } from '@nestjs/common';
|
|
2
|
+
import { type HandlerWrapperOptions } from '../handlers/handler-wrapper';
|
|
3
|
+
/**
|
|
4
|
+
* DI token for the resolved {@link CqrsTransactionalOptions} object.
|
|
5
|
+
* Consumers normally do not inject this directly — it is used by the
|
|
6
|
+
* module's internal factory to pass options to {@link CqrsHandlerWrapper}.
|
|
7
|
+
*/
|
|
8
|
+
export declare const CQRS_TRANSACTIONAL_OPTIONS = "CQRS_TRANSACTIONAL_OPTIONS";
|
|
9
|
+
/**
|
|
10
|
+
* Options accepted by {@link CqrsTransactionalModule.forRoot}. Extends
|
|
11
|
+
* {@link HandlerWrapperOptions} with the flag controlling whether
|
|
12
|
+
* `@nestjs/cqrs`'s `EventPublisher` is overridden with
|
|
13
|
+
* {@link TransactionalEventPublisherAdapter}.
|
|
14
|
+
*
|
|
15
|
+
* Defaults:
|
|
16
|
+
* - `wrapCommandHandlers`: `true`
|
|
17
|
+
* - `wrapQueryHandlers`: `true`
|
|
18
|
+
* - `wrapEventHandlers`: `true`
|
|
19
|
+
* - `defaultQueryOptions`: `{ readOnly: true }`
|
|
20
|
+
* - `useTransactionalEventPublisher`: `true`
|
|
21
|
+
*/
|
|
22
|
+
export interface CqrsTransactionalOptions extends HandlerWrapperOptions {
|
|
23
|
+
/**
|
|
24
|
+
* If `true` (default), overrides `@nestjs/cqrs`'s `EventPublisher`
|
|
25
|
+
* DI token with {@link TransactionalEventPublisherAdapter} so
|
|
26
|
+
* `AggregateRoot.commit()` routes events through the transactional
|
|
27
|
+
* dispatcher (phase-aware handlers). Set to `false` to leave the
|
|
28
|
+
* standard `EventPublisher` in place — useful when integrating
|
|
29
|
+
* progressively into an existing codebase.
|
|
30
|
+
*/
|
|
31
|
+
readonly useTransactionalEventPublisher?: boolean;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* NestJS module that wires the `@nestjs-transactional/cqrs` runtime:
|
|
35
|
+
*
|
|
36
|
+
* - {@link TransactionalEventDispatcher} for phase-aware event
|
|
37
|
+
* routing.
|
|
38
|
+
* - {@link TransactionalListenerScanner} for auto-registration of
|
|
39
|
+
* `@TransactionalEventsHandler`-decorated classes at module init.
|
|
40
|
+
* - {@link IntegrationEventsHandlerScanner} for
|
|
41
|
+
* `@IntegrationEventsHandler`-decorated classes, with smart routing
|
|
42
|
+
* to the outbox (when bound) or the dispatcher (otherwise).
|
|
43
|
+
* - {@link CqrsHandlerWrapper} + {@link CqrsTransactionalBootstrap}
|
|
44
|
+
* to wrap `@CommandHandler` / `@QueryHandler` / `@EventsHandler`
|
|
45
|
+
* execute/handle methods at application bootstrap.
|
|
46
|
+
* - {@link TransactionalEventPublisher} +
|
|
47
|
+
* {@link TransactionalEventPublisherAdapter} as the `EventPublisher`
|
|
48
|
+
* DI override so `AggregateRoot.commit()` flows through the
|
|
49
|
+
* dispatcher.
|
|
50
|
+
*
|
|
51
|
+
* Pair with `TransactionalModule.forRoot({ isGlobal: true })` at the
|
|
52
|
+
* application root. For TypeORM-backed applications, also register
|
|
53
|
+
* adapters with `TypeOrmTransactionalModule.forFeature(...)`.
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* ```ts
|
|
57
|
+
* @Module({
|
|
58
|
+
* imports: [
|
|
59
|
+
* TransactionalModule.forRoot({ isGlobal: true }),
|
|
60
|
+
* TypeOrmTransactionalModule.forFeature({ dataSource: myDs }),
|
|
61
|
+
* CqrsModule,
|
|
62
|
+
* CqrsTransactionalModule.forRoot(),
|
|
63
|
+
* ],
|
|
64
|
+
* })
|
|
65
|
+
* export class AppModule {}
|
|
66
|
+
* ```
|
|
67
|
+
*
|
|
68
|
+
* **Multi-dataSource setups** (Phase 14.7): the cqrs runtime is
|
|
69
|
+
* dataSource-agnostic by design. There is exactly one
|
|
70
|
+
* `CqrsTransactionalModule.forRoot()` per application regardless of
|
|
71
|
+
* how many dataSources are configured — multi-DS routing emerges
|
|
72
|
+
* from the structural-port wiring, not from a per-DS module instance.
|
|
73
|
+
*
|
|
74
|
+
* Wire {@link OUTBOX_PUBLICATION_SCHEDULER} and
|
|
75
|
+
* {@link OUTBOX_LISTENER_REGISTRAR} to the outbox stack you want
|
|
76
|
+
* cqrs to delegate to (`useExisting: OutboxEventPublisher` /
|
|
77
|
+
* `useExisting: OutboxListenerRegistry`). Apps with multiple outbox
|
|
78
|
+
* stacks (one `OutboxModule.forRoot()` per dataSource — ADR-019)
|
|
79
|
+
* choose which one cqrs bridges to via the `useExisting` target.
|
|
80
|
+
*
|
|
81
|
+
* Known limitation in multi-DS deployments: the in-memory
|
|
82
|
+
* dispatcher's hook-attachment goes through
|
|
83
|
+
* `TransactionManager.registerBeforeCommit` / `registerAfterCommit`,
|
|
84
|
+
* which target the first-active transaction on the current async
|
|
85
|
+
* context (non-deterministic across simultaneously-active
|
|
86
|
+
* cross-dataSource transactions). For cross-DS event handling
|
|
87
|
+
* prefer the outbox path — see `docs/known-limitations.md`.
|
|
88
|
+
*/
|
|
89
|
+
export declare class CqrsTransactionalModule {
|
|
90
|
+
static forRoot(options?: CqrsTransactionalOptions): DynamicModule;
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=cqrs-transactional.module.d.ts.map
|