@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.
Files changed (51) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +431 -0
  3. package/dist/decorators/integration-events-handler.decorator.d.ts +125 -0
  4. package/dist/decorators/integration-events-handler.decorator.js +57 -0
  5. package/dist/decorators/integration-events-handler.decorator.js.map +1 -0
  6. package/dist/decorators/transactional-events-handler.decorator.d.ts +138 -0
  7. package/dist/decorators/transactional-events-handler.decorator.js +65 -0
  8. package/dist/decorators/transactional-events-handler.decorator.js.map +1 -0
  9. package/dist/event-dispatcher/event-dispatcher.d.ts +100 -0
  10. package/dist/event-dispatcher/event-dispatcher.js +229 -0
  11. package/dist/event-dispatcher/event-dispatcher.js.map +1 -0
  12. package/dist/event-publisher/hybrid-event-publisher.d.ts +76 -0
  13. package/dist/event-publisher/hybrid-event-publisher.js +86 -0
  14. package/dist/event-publisher/hybrid-event-publisher.js.map +1 -0
  15. package/dist/event-publisher/transactional-event-publisher-adapter.d.ts +32 -0
  16. package/dist/event-publisher/transactional-event-publisher-adapter.js +72 -0
  17. package/dist/event-publisher/transactional-event-publisher-adapter.js.map +1 -0
  18. package/dist/event-publisher/transactional-event-publisher.d.ts +33 -0
  19. package/dist/event-publisher/transactional-event-publisher.js +58 -0
  20. package/dist/event-publisher/transactional-event-publisher.js.map +1 -0
  21. package/dist/handlers/bootstrap.d.ts +18 -0
  22. package/dist/handlers/bootstrap.js +39 -0
  23. package/dist/handlers/bootstrap.js.map +1 -0
  24. package/dist/handlers/handler-wrapper.d.ts +77 -0
  25. package/dist/handlers/handler-wrapper.js +183 -0
  26. package/dist/handlers/handler-wrapper.js.map +1 -0
  27. package/dist/handlers/integration-events-handler-scanner.d.ts +37 -0
  28. package/dist/handlers/integration-events-handler-scanner.js +144 -0
  29. package/dist/handlers/integration-events-handler-scanner.js.map +1 -0
  30. package/dist/handlers/listener-scanner.d.ts +33 -0
  31. package/dist/handlers/listener-scanner.js +86 -0
  32. package/dist/handlers/listener-scanner.js.map +1 -0
  33. package/dist/handlers/outbox-listener-registrar.d.ts +49 -0
  34. package/dist/handlers/outbox-listener-registrar.js +17 -0
  35. package/dist/handlers/outbox-listener-registrar.js.map +1 -0
  36. package/dist/index.d.ts +16 -0
  37. package/dist/index.js +37 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/interfaces/integration-event-handler.interface.d.ts +35 -0
  40. package/dist/interfaces/integration-event-handler.interface.js +3 -0
  41. package/dist/interfaces/integration-event-handler.interface.js.map +1 -0
  42. package/dist/interfaces/transactional-event-handler.interface.d.ts +31 -0
  43. package/dist/interfaces/transactional-event-handler.interface.js +3 -0
  44. package/dist/interfaces/transactional-event-handler.interface.js.map +1 -0
  45. package/dist/module/cqrs-transactional.module.d.ts +92 -0
  46. package/dist/module/cqrs-transactional.module.js +137 -0
  47. package/dist/module/cqrs-transactional.module.js.map +1 -0
  48. package/dist/types/transactional-listener.types.d.ts +21 -0
  49. package/dist/types/transactional-listener.types.js +25 -0
  50. package/dist/types/transactional-listener.types.js.map +1 -0
  51. package/package.json +73 -0
@@ -0,0 +1,138 @@
1
+ import 'reflect-metadata';
2
+ import { type Type } from '@nestjs/common';
3
+ import { TransactionPhase } from '../types/transactional-listener.types';
4
+ /**
5
+ * Metadata key under which {@link TransactionalEventsHandlerMetadata} is
6
+ * stored on classes decorated with {@link TransactionalEventsHandler}.
7
+ *
8
+ * The key is a fresh `Symbol` (not `Symbol.for`) — this metadata is
9
+ * private to the cqrs package and does not need to be shared across
10
+ * package boundaries.
11
+ */
12
+ export declare const TRANSACTIONAL_EVENTS_HANDLER_METADATA: unique symbol;
13
+ /**
14
+ * Options accepted by the long form of {@link TransactionalEventsHandler}.
15
+ *
16
+ * Use this form when the handler needs any non-default behaviour (a
17
+ * different `phase`, `async` delivery, or `fallbackExecution` outside a
18
+ * transaction). When defaults are acceptable, prefer the rest-params
19
+ * short form: `@TransactionalEventsHandler(EventA, EventB)`.
20
+ */
21
+ export interface TransactionalEventsHandlerOptions {
22
+ /** Domain event classes the handler subscribes to. Must be non-empty. */
23
+ readonly events: Type[];
24
+ /**
25
+ * Transaction phase to attach the handler to. Defaults to
26
+ * {@link TransactionPhase.AFTER_COMMIT} — the canonical "publish
27
+ * domain event" phase.
28
+ */
29
+ readonly phase?: TransactionPhase;
30
+ /**
31
+ * When `true`, the handler is invoked on a microtask and its failures
32
+ * never reach the surrounding transaction — including BEFORE_COMMIT,
33
+ * which therefore cannot cause a rollback. Defaults to `false`.
34
+ */
35
+ readonly async?: boolean;
36
+ /**
37
+ * When `true`, the handler fires even for events published outside
38
+ * any active transaction (direct `eventBus.publish(event)` calls).
39
+ * When `false` (default), such events are dropped with a warning.
40
+ */
41
+ readonly fallbackExecution?: boolean;
42
+ /**
43
+ * dataSource the handler's phase hooks attach to (Phase 14.3.1).
44
+ * Defaults to {@link DEFAULT_DATA_SOURCE_NAME} (`'default'`) —
45
+ * single-dataSource apps can omit it.
46
+ *
47
+ * Multi-dataSource apps with handlers belonging to a non-default
48
+ * dataSource MUST set this — the dispatcher uses it to find the
49
+ * matching active transaction via
50
+ * `TransactionContext.getActiveTransactionByDataSource(dataSource)`
51
+ * and pushes phase hooks directly onto that transaction's hook
52
+ * lists. Without it, the dispatcher falls back to `'default'` and
53
+ * the handler may attach to the wrong transaction (or none at all
54
+ * if the default-DS has no active tx in the current async context).
55
+ *
56
+ * Unlike `@OutboxEventsHandler` and `@IntegrationEventsHandler`'s
57
+ * outbox path — both of which auto-resolve the dataSource by
58
+ * walking per-DS event-type registries — the in-memory dispatcher
59
+ * has no event-type registry to consult. The cqrs package is
60
+ * decoupled from outbox by design (Phase 14.7), so the dataSource
61
+ * is declared explicitly on the decorator.
62
+ */
63
+ readonly dataSource?: string;
64
+ }
65
+ /**
66
+ * Resolved metadata attached to a handler class. All option fields are
67
+ * required (the decorator fills in defaults). `eventTypes` is the
68
+ * normalised list of event constructors the handler is registered for.
69
+ */
70
+ export interface TransactionalEventsHandlerMetadata {
71
+ readonly eventTypes: Type[];
72
+ readonly phase: TransactionPhase;
73
+ readonly async: boolean;
74
+ readonly fallbackExecution: boolean;
75
+ readonly dataSource: string;
76
+ }
77
+ /**
78
+ * Mark a class as a transactional event handler. The class must
79
+ * expose a `handle(event): void | Promise<void>` method (enforce this
80
+ * at the type level by implementing {@link ITransactionalEventHandler}).
81
+ *
82
+ * Two forms:
83
+ *
84
+ * ```ts
85
+ * // Short form — defaults (AFTER_COMMIT, sync, no fallback):
86
+ * @TransactionalEventsHandler(OrderPlacedEvent, OrderCancelledEvent)
87
+ *
88
+ * // Long form — explicit options:
89
+ * @TransactionalEventsHandler({
90
+ * events: [OrderPlacedEvent],
91
+ * phase: TransactionPhase.BEFORE_COMMIT,
92
+ * async: false,
93
+ * })
94
+ * ```
95
+ *
96
+ * Class-level only — this decorator does not accept methods. Multiple
97
+ * handlers may subscribe to the same event type; each is an independent
98
+ * class and runs in registration order.
99
+ *
100
+ * The metadata is written by `Reflect.defineMetadata`. The actual
101
+ * dispatcher registration happens at application bootstrap via
102
+ * `TransactionalListenerScanner`.
103
+ *
104
+ * **Multi-dataSource semantics (Phase 14.3.1).** The dispatcher pushes
105
+ * phase hooks directly onto the per-dataSource active transaction
106
+ * resolved via
107
+ * `TransactionContext.getActiveTransactionByDataSource(dataSource)`,
108
+ * bypassing `TransactionManager.registerBeforeCommit`'s first-active-tx
109
+ * semantics. The dataSource defaults to `'default'`; multi-DS apps
110
+ * pass `dataSource: 'billing'` (or similar) on the long form to attach
111
+ * the handler to a specific dataSource's transaction:
112
+ *
113
+ * ```ts
114
+ * @TransactionalEventsHandler({
115
+ * events: [BillingEvent],
116
+ * dataSource: 'billing',
117
+ * })
118
+ * class BillingHandler { handle(event: BillingEvent) {} }
119
+ * ```
120
+ *
121
+ * Unlike `@OutboxEventsHandler` (which auto-resolves the dataSource
122
+ * by walking per-DS event-type registries), the in-memory dispatcher
123
+ * has no event-type registry — the dataSource is declared explicitly
124
+ * on the decorator.
125
+ *
126
+ * @throws {Error} If no event types are supplied.
127
+ */
128
+ export declare function TransactionalEventsHandler(...events: Type[]): ClassDecorator;
129
+ export declare function TransactionalEventsHandler(options: TransactionalEventsHandlerOptions): ClassDecorator;
130
+ /**
131
+ * Read the {@link TransactionalEventsHandlerMetadata} attached to
132
+ * `target` by {@link TransactionalEventsHandler}. Returns `undefined`
133
+ * when the class was not decorated.
134
+ *
135
+ * @param target - The class constructor.
136
+ */
137
+ export declare function getTransactionalEventsHandlerMetadata(target: object): TransactionalEventsHandlerMetadata | undefined;
138
+ //# sourceMappingURL=transactional-events-handler.decorator.d.ts.map
@@ -0,0 +1,65 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TRANSACTIONAL_EVENTS_HANDLER_METADATA = void 0;
4
+ exports.TransactionalEventsHandler = TransactionalEventsHandler;
5
+ exports.getTransactionalEventsHandlerMetadata = getTransactionalEventsHandlerMetadata;
6
+ require("reflect-metadata");
7
+ const core_1 = require("@nestjs-transactional/core");
8
+ const transactional_listener_types_1 = require("../types/transactional-listener.types");
9
+ /**
10
+ * Metadata key under which {@link TransactionalEventsHandlerMetadata} is
11
+ * stored on classes decorated with {@link TransactionalEventsHandler}.
12
+ *
13
+ * The key is a fresh `Symbol` (not `Symbol.for`) — this metadata is
14
+ * private to the cqrs package and does not need to be shared across
15
+ * package boundaries.
16
+ */
17
+ exports.TRANSACTIONAL_EVENTS_HANDLER_METADATA = Symbol('TRANSACTIONAL_EVENTS_HANDLER_METADATA');
18
+ function TransactionalEventsHandler(...args) {
19
+ const metadata = resolveMetadata(args);
20
+ if (metadata.eventTypes.length === 0) {
21
+ throw new Error('@TransactionalEventsHandler requires at least one event type. ' +
22
+ 'Pass class constructors as rest arguments or via the `events` option.');
23
+ }
24
+ return (target) => {
25
+ Reflect.defineMetadata(exports.TRANSACTIONAL_EVENTS_HANDLER_METADATA, metadata, target);
26
+ };
27
+ }
28
+ function resolveMetadata(args) {
29
+ if (args.length === 1 && isOptionsObject(args[0])) {
30
+ const options = args[0];
31
+ return {
32
+ eventTypes: [...options.events],
33
+ phase: options.phase ?? transactional_listener_types_1.TransactionPhase.AFTER_COMMIT,
34
+ async: options.async ?? false,
35
+ fallbackExecution: options.fallbackExecution ?? false,
36
+ dataSource: options.dataSource ?? core_1.DEFAULT_DATA_SOURCE_NAME,
37
+ };
38
+ }
39
+ return {
40
+ eventTypes: args,
41
+ phase: transactional_listener_types_1.TransactionPhase.AFTER_COMMIT,
42
+ async: false,
43
+ fallbackExecution: false,
44
+ dataSource: core_1.DEFAULT_DATA_SOURCE_NAME,
45
+ };
46
+ }
47
+ function isOptionsObject(candidate) {
48
+ return (candidate !== null &&
49
+ typeof candidate === 'object' &&
50
+ !Array.isArray(candidate) &&
51
+ typeof candidate !== 'function' &&
52
+ 'events' in candidate);
53
+ }
54
+ /**
55
+ * Read the {@link TransactionalEventsHandlerMetadata} attached to
56
+ * `target` by {@link TransactionalEventsHandler}. Returns `undefined`
57
+ * when the class was not decorated.
58
+ *
59
+ * @param target - The class constructor.
60
+ */
61
+ function getTransactionalEventsHandlerMetadata(target) {
62
+ const value = Reflect.getMetadata(exports.TRANSACTIONAL_EVENTS_HANDLER_METADATA, target);
63
+ return value;
64
+ }
65
+ //# sourceMappingURL=transactional-events-handler.decorator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transactional-events-handler.decorator.js","sourceRoot":"","sources":["../../src/decorators/transactional-events-handler.decorator.ts"],"names":[],"mappings":";;;AA4IA,gEAeC;AA4CD,sFAKC;AA5MD,4BAA0B;AAG1B,qDAAsE;AAEtE,wFAAyE;AAEzE;;;;;;;GAOG;AACU,QAAA,qCAAqC,GAAG,MAAM,CACzD,uCAAuC,CACxC,CAAC;AA2HF,SAAgB,0BAA0B,CACxC,GAAG,IAAkD;IAErD,MAAM,QAAQ,GAAuC,eAAe,CAAC,IAAI,CAAC,CAAC;IAE3E,IAAI,QAAQ,CAAC,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACrC,MAAM,IAAI,KAAK,CACb,gEAAgE;YAC9D,uEAAuE,CAC1E,CAAC;IACJ,CAAC;IAED,OAAO,CAAC,MAAc,EAAQ,EAAE;QAC9B,OAAO,CAAC,cAAc,CAAC,6CAAqC,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;IAClF,CAAC,CAAC;AACJ,CAAC;AAED,SAAS,eAAe,CACtB,IAAkD;IAElD,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAClD,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACxB,OAAO;YACL,UAAU,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC;YAC/B,KAAK,EAAE,OAAO,CAAC,KAAK,IAAI,+CAAgB,CAAC,YAAY;YACrD,KAAK,EAAE,OAAO,CAAC,KAAK,IAAI,KAAK;YAC7B,iBAAiB,EAAE,OAAO,CAAC,iBAAiB,IAAI,KAAK;YACrD,UAAU,EAAE,OAAO,CAAC,UAAU,IAAI,+BAAwB;SAC3D,CAAC;IACJ,CAAC;IAED,OAAO;QACL,UAAU,EAAE,IAAc;QAC1B,KAAK,EAAE,+CAAgB,CAAC,YAAY;QACpC,KAAK,EAAE,KAAK;QACZ,iBAAiB,EAAE,KAAK;QACxB,UAAU,EAAE,+BAAwB;KACrC,CAAC;AACJ,CAAC;AAED,SAAS,eAAe,CACtB,SAAkB;IAElB,OAAO,CACL,SAAS,KAAK,IAAI;QAClB,OAAO,SAAS,KAAK,QAAQ;QAC7B,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC;QACzB,OAAO,SAAS,KAAK,UAAU;QAC/B,QAAQ,IAAI,SAAS,CACtB,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,qCAAqC,CACnD,MAAc;IAEd,MAAM,KAAK,GAAY,OAAO,CAAC,WAAW,CAAC,6CAAqC,EAAE,MAAM,CAAC,CAAC;IAC1F,OAAO,KAAuD,CAAC;AACjE,CAAC"}
@@ -0,0 +1,100 @@
1
+ import { type Type } from '@nestjs/common';
2
+ import { TransactionManager } from '@nestjs-transactional/core';
3
+ import { TransactionPhase } from '../types/transactional-listener.types';
4
+ /**
5
+ * Resolved per-event-type listener configuration used by
6
+ * {@link TransactionalEventDispatcher.registerListener}. Scanners flatten
7
+ * class-level `@TransactionalEventsHandler` metadata (which lists many
8
+ * event types per class) into one of these entries per event type.
9
+ */
10
+ export interface DispatcherListenerMetadata {
11
+ readonly eventType: Type;
12
+ readonly phase: TransactionPhase;
13
+ readonly fallbackExecution: boolean;
14
+ readonly async: boolean;
15
+ /**
16
+ * dataSource the listener's phase hooks attach to (Phase 14.3.1).
17
+ * Optional for backward compatibility — when omitted, defaults to
18
+ * `'default'`. Scanners normalise from decorator metadata before
19
+ * calling {@link TransactionalEventDispatcher.registerListener}.
20
+ */
21
+ readonly dataSource?: string;
22
+ }
23
+ /**
24
+ * Routes domain events to methods registered by scanners for
25
+ * `@TransactionalEventsHandler`-annotated classes, honouring the
26
+ * requested {@link TransactionPhase}:
27
+ *
28
+ * - Inside an active transaction, the listener is attached to the
29
+ * transaction as a before-commit / after-commit / after-rollback
30
+ * hook via {@link TransactionManager}. Phase AFTER_COMPLETION
31
+ * attaches to both after-commit and after-rollback.
32
+ * - Outside any transaction, listeners with `fallbackExecution: true`
33
+ * are invoked via `queueMicrotask`; others are dropped with a
34
+ * warning.
35
+ *
36
+ * Error propagation:
37
+ * - Errors thrown from a BEFORE_COMMIT listener propagate through the
38
+ * manager's commit path and trigger rollback (matches Spring).
39
+ * - Errors thrown from an AFTER_COMMIT / AFTER_ROLLBACK /
40
+ * AFTER_COMPLETION listener are logged and swallowed by
41
+ * {@link TransactionManager}'s hook runner — the transaction
42
+ * outcome is already decided.
43
+ * - `async: true` listeners are fire-and-forget via `queueMicrotask`:
44
+ * their failures are logged but never reach the enclosing
45
+ * transaction, even in BEFORE_COMMIT phase.
46
+ *
47
+ * **Multi-dataSource (Phase 14.3.1).** Hook attachment is per-dataSource:
48
+ * the dispatcher resolves the listener's bound dataSource via
49
+ * `TransactionContext.getActiveTransactionByDataSource(dataSource)`
50
+ * and pushes hooks directly onto that transaction's hook list,
51
+ * bypassing `TransactionManager.registerBeforeCommit`'s first-active-tx
52
+ * semantics. The dataSource comes from the listener metadata (defaults
53
+ * to `'default'`); scanners populate it from the
54
+ * `@TransactionalEventsHandler({ dataSource })` /
55
+ * `@IntegrationEventsHandler({ dataSource })` option. Cross-DS
56
+ * simultaneous transactions therefore route deterministically — a
57
+ * billing-bound handler attaches to the billing transaction's hooks
58
+ * even when an inventory transaction is also active on the same
59
+ * async stack.
60
+ */
61
+ export declare class TransactionalEventDispatcher {
62
+ private readonly manager;
63
+ private readonly logger;
64
+ private readonly listenersByType;
65
+ /**
66
+ * `manager` is no longer consulted after Phase 14.3.1 — the
67
+ * dispatcher pushes hooks directly onto the per-dataSource
68
+ * `ActiveTransaction` resolved via `TransactionContext`. The
69
+ * parameter is preserved as a constructor argument so existing
70
+ * `new TransactionalEventDispatcher(manager)` callsites in tests
71
+ * keep compiling. NestJS DI continues to inject the manager
72
+ * automatically. A future cleanup phase may drop it.
73
+ */
74
+ constructor(manager: TransactionManager);
75
+ /**
76
+ * Register a handler method discovered on `instance`. The lookup key
77
+ * is `metadata.eventType.name` — see {@link scheduleDispatch} for
78
+ * matching semantics. Multiple handlers for the same event are
79
+ * invoked in registration order within the hook runner.
80
+ *
81
+ * @throws {TypeError} If `instance[methodName]` is not a function.
82
+ * This is a caller contract violation — the scanner must only pass
83
+ * method names that actually resolve to methods on the instance.
84
+ */
85
+ registerListener(instance: object, methodName: string, metadata: DispatcherListenerMetadata): void;
86
+ /**
87
+ * Route `event` to every listener registered for its exact
88
+ * constructor name. Listener matching is nominal and non-inheriting:
89
+ * a listener registered for `Parent` is NOT invoked for a `Child
90
+ * extends Parent` event, because the lookup uses
91
+ * `event.constructor.name`.
92
+ */
93
+ scheduleDispatch(event: object): void;
94
+ private attachHookToTransaction;
95
+ private invokeListener;
96
+ private scheduleFallback;
97
+ private callListener;
98
+ private logListenerFailure;
99
+ }
100
+ //# sourceMappingURL=event-dispatcher.d.ts.map
@@ -0,0 +1,229 @@
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 TransactionalEventDispatcher_1;
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.TransactionalEventDispatcher = void 0;
14
+ const common_1 = require("@nestjs/common");
15
+ const core_1 = require("@nestjs-transactional/core");
16
+ const transactional_listener_types_1 = require("../types/transactional-listener.types");
17
+ /**
18
+ * Routes domain events to methods registered by scanners for
19
+ * `@TransactionalEventsHandler`-annotated classes, honouring the
20
+ * requested {@link TransactionPhase}:
21
+ *
22
+ * - Inside an active transaction, the listener is attached to the
23
+ * transaction as a before-commit / after-commit / after-rollback
24
+ * hook via {@link TransactionManager}. Phase AFTER_COMPLETION
25
+ * attaches to both after-commit and after-rollback.
26
+ * - Outside any transaction, listeners with `fallbackExecution: true`
27
+ * are invoked via `queueMicrotask`; others are dropped with a
28
+ * warning.
29
+ *
30
+ * Error propagation:
31
+ * - Errors thrown from a BEFORE_COMMIT listener propagate through the
32
+ * manager's commit path and trigger rollback (matches Spring).
33
+ * - Errors thrown from an AFTER_COMMIT / AFTER_ROLLBACK /
34
+ * AFTER_COMPLETION listener are logged and swallowed by
35
+ * {@link TransactionManager}'s hook runner — the transaction
36
+ * outcome is already decided.
37
+ * - `async: true` listeners are fire-and-forget via `queueMicrotask`:
38
+ * their failures are logged but never reach the enclosing
39
+ * transaction, even in BEFORE_COMMIT phase.
40
+ *
41
+ * **Multi-dataSource (Phase 14.3.1).** Hook attachment is per-dataSource:
42
+ * the dispatcher resolves the listener's bound dataSource via
43
+ * `TransactionContext.getActiveTransactionByDataSource(dataSource)`
44
+ * and pushes hooks directly onto that transaction's hook list,
45
+ * bypassing `TransactionManager.registerBeforeCommit`'s first-active-tx
46
+ * semantics. The dataSource comes from the listener metadata (defaults
47
+ * to `'default'`); scanners populate it from the
48
+ * `@TransactionalEventsHandler({ dataSource })` /
49
+ * `@IntegrationEventsHandler({ dataSource })` option. Cross-DS
50
+ * simultaneous transactions therefore route deterministically — a
51
+ * billing-bound handler attaches to the billing transaction's hooks
52
+ * even when an inventory transaction is also active on the same
53
+ * async stack.
54
+ */
55
+ let TransactionalEventDispatcher = TransactionalEventDispatcher_1 = class TransactionalEventDispatcher {
56
+ manager;
57
+ logger = new common_1.Logger(TransactionalEventDispatcher_1.name);
58
+ listenersByType = new Map();
59
+ /**
60
+ * `manager` is no longer consulted after Phase 14.3.1 — the
61
+ * dispatcher pushes hooks directly onto the per-dataSource
62
+ * `ActiveTransaction` resolved via `TransactionContext`. The
63
+ * parameter is preserved as a constructor argument so existing
64
+ * `new TransactionalEventDispatcher(manager)` callsites in tests
65
+ * keep compiling. NestJS DI continues to inject the manager
66
+ * automatically. A future cleanup phase may drop it.
67
+ */
68
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
69
+ constructor(manager) {
70
+ this.manager = manager;
71
+ }
72
+ /**
73
+ * Register a handler method discovered on `instance`. The lookup key
74
+ * is `metadata.eventType.name` — see {@link scheduleDispatch} for
75
+ * matching semantics. Multiple handlers for the same event are
76
+ * invoked in registration order within the hook runner.
77
+ *
78
+ * @throws {TypeError} If `instance[methodName]` is not a function.
79
+ * This is a caller contract violation — the scanner must only pass
80
+ * method names that actually resolve to methods on the instance.
81
+ */
82
+ registerListener(instance, methodName, metadata) {
83
+ const rawMethod = instance[methodName];
84
+ if (typeof rawMethod !== 'function') {
85
+ throw new TypeError(`Transactional event handler target ${instance.constructor.name}.${methodName} ` +
86
+ `is not a function — cannot register as a listener`);
87
+ }
88
+ const typeName = metadata.eventType.name;
89
+ const instanceLabel = instance.constructor.name;
90
+ const entry = {
91
+ handler: rawMethod.bind(instance),
92
+ instanceLabel,
93
+ methodName,
94
+ metadata,
95
+ };
96
+ const listeners = this.listenersByType.get(typeName);
97
+ if (listeners === undefined) {
98
+ this.listenersByType.set(typeName, [entry]);
99
+ }
100
+ else {
101
+ listeners.push(entry);
102
+ }
103
+ this.logger.debug(`Registered handler ${instanceLabel}.${methodName} for ${typeName} phase=${metadata.phase}`);
104
+ }
105
+ /**
106
+ * Route `event` to every listener registered for its exact
107
+ * constructor name. Listener matching is nominal and non-inheriting:
108
+ * a listener registered for `Parent` is NOT invoked for a `Child
109
+ * extends Parent` event, because the lookup uses
110
+ * `event.constructor.name`.
111
+ */
112
+ scheduleDispatch(event) {
113
+ const typeName = event.constructor.name;
114
+ const listeners = this.listenersByType.get(typeName);
115
+ if (listeners === undefined || listeners.length === 0) {
116
+ return;
117
+ }
118
+ const store = core_1.TransactionContext.getStore();
119
+ const anyTxActive = store !== undefined && store.activeTransactions.size > 0;
120
+ for (const listener of listeners) {
121
+ const dataSource = listener.metadata.dataSource ?? core_1.DEFAULT_DATA_SOURCE_NAME;
122
+ const tx = core_1.TransactionContext.getActiveTransactionByDataSource(dataSource);
123
+ if (tx === undefined) {
124
+ // No active transaction for this listener's dataSource. Two
125
+ // sub-cases:
126
+ // - There IS at least one active tx (just not for this DS):
127
+ // the event is "in a transaction" only for some other DS.
128
+ // A listener bound to a different DS has no business
129
+ // firing — skip silently. This preserves DD-023's
130
+ // independent-context semantics (cross-dataSource calls
131
+ // do not silently enrol).
132
+ // - No active tx anywhere: classic out-of-transaction case —
133
+ // fallbackExecution: true fires immediately, others warn
134
+ // and drop.
135
+ if (!anyTxActive && listener.metadata.fallbackExecution) {
136
+ this.scheduleFallback(listener, event);
137
+ }
138
+ else if (!anyTxActive) {
139
+ this.logger.warn(`Event ${typeName} published outside a transaction; handler ` +
140
+ `${listener.instanceLabel}.${listener.methodName} has no ` +
141
+ `fallbackExecution=true — skipping.`);
142
+ }
143
+ else {
144
+ this.logger.debug(`Event ${typeName}: handler ${listener.instanceLabel}.${listener.methodName} ` +
145
+ `bound to dataSource '${dataSource}' has no matching active transaction — skipping.`);
146
+ }
147
+ continue;
148
+ }
149
+ this.attachHookToTransaction(listener, event, tx);
150
+ }
151
+ }
152
+ attachHookToTransaction(listener, event, tx) {
153
+ const invoke = () => this.invokeListener(listener, event);
154
+ const invokeWithError = (error) => this.invokeListener(listener, event, error);
155
+ // Push hooks directly onto THIS specific transaction's hook lists,
156
+ // bypassing TransactionManager.registerBeforeCommit's
157
+ // first-active-tx resolution. Same pattern as
158
+ // DataSourceOutboxPublisher.scheduleForPublication (Phase 14.3).
159
+ switch (listener.metadata.phase) {
160
+ case transactional_listener_types_1.TransactionPhase.BEFORE_COMMIT:
161
+ tx.beforeCommitHooks.push(invoke);
162
+ return;
163
+ case transactional_listener_types_1.TransactionPhase.AFTER_COMMIT:
164
+ tx.afterCommitHooks.push(invoke);
165
+ return;
166
+ case transactional_listener_types_1.TransactionPhase.AFTER_ROLLBACK:
167
+ tx.afterRollbackHooks.push(invokeWithError);
168
+ return;
169
+ case transactional_listener_types_1.TransactionPhase.AFTER_COMPLETION:
170
+ tx.afterCommitHooks.push(invoke);
171
+ tx.afterRollbackHooks.push(invokeWithError);
172
+ return;
173
+ }
174
+ }
175
+ async invokeListener(listener, event, error) {
176
+ if (listener.metadata.async) {
177
+ queueMicrotask(() => {
178
+ try {
179
+ const result = this.callListener(listener, event, error);
180
+ if (result instanceof Promise) {
181
+ result.catch((err) => this.logListenerFailure(listener, err));
182
+ }
183
+ }
184
+ catch (err) {
185
+ this.logListenerFailure(listener, err);
186
+ }
187
+ });
188
+ return;
189
+ }
190
+ try {
191
+ const result = this.callListener(listener, event, error);
192
+ if (result instanceof Promise) {
193
+ await result;
194
+ }
195
+ }
196
+ catch (err) {
197
+ this.logListenerFailure(listener, err);
198
+ // Rethrow so BEFORE_COMMIT failures reach the manager's rollback path.
199
+ // For AFTER_COMMIT/AFTER_ROLLBACK/AFTER_COMPLETION the manager's
200
+ // hook runner swallows the error after a warn-level log.
201
+ throw err;
202
+ }
203
+ }
204
+ scheduleFallback(listener, event) {
205
+ queueMicrotask(() => {
206
+ try {
207
+ const result = this.callListener(listener, event);
208
+ if (result instanceof Promise) {
209
+ result.catch((err) => this.logListenerFailure(listener, err));
210
+ }
211
+ }
212
+ catch (err) {
213
+ this.logListenerFailure(listener, err);
214
+ }
215
+ });
216
+ }
217
+ callListener(listener, event, error) {
218
+ return listener.handler(event, error);
219
+ }
220
+ logListenerFailure(listener, err) {
221
+ this.logger.error(`Transactional event handler ${listener.instanceLabel}.${listener.methodName} failed`, err instanceof Error ? err.stack : String(err));
222
+ }
223
+ };
224
+ exports.TransactionalEventDispatcher = TransactionalEventDispatcher;
225
+ exports.TransactionalEventDispatcher = TransactionalEventDispatcher = TransactionalEventDispatcher_1 = __decorate([
226
+ (0, common_1.Injectable)(),
227
+ __metadata("design:paramtypes", [core_1.TransactionManager])
228
+ ], TransactionalEventDispatcher);
229
+ //# sourceMappingURL=event-dispatcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-dispatcher.js","sourceRoot":"","sources":["../../src/event-dispatcher/event-dispatcher.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,76 @@
1
+ import type { IEvent, IEventPublisher } from '@nestjs/cqrs';
2
+ import { TransactionalEventDispatcher } from '../event-dispatcher/event-dispatcher';
3
+ /**
4
+ * Minimal structural contract for the outbox-side publisher. Declared
5
+ * here (and injected via the {@link OUTBOX_PUBLICATION_SCHEDULER}
6
+ * token) rather than importing from
7
+ * `@nestjs-transactional/outbox` directly — keeps `cqrs` usable
8
+ * without pulling in the outbox stack.
9
+ *
10
+ * `@nestjs-transactional/outbox`'s `OutboxEventPublisher`
11
+ * satisfies this interface structurally (it exposes
12
+ * `scheduleForPublication`). Wire the token in the host application
13
+ * when the outbox is enabled:
14
+ *
15
+ * ```ts
16
+ * providers: [
17
+ * {
18
+ * provide: OUTBOX_PUBLICATION_SCHEDULER,
19
+ * useExisting: OutboxEventPublisher,
20
+ * },
21
+ * ]
22
+ * ```
23
+ */
24
+ export interface OutboxPublicationScheduler {
25
+ scheduleForPublication(event: unknown): void;
26
+ }
27
+ /**
28
+ * DI token for the optional outbox scheduler injected into
29
+ * {@link HybridEventPublisher}. When unbound, the hybrid publisher
30
+ * delegates only to the in-memory dispatcher.
31
+ */
32
+ export declare const OUTBOX_PUBLICATION_SCHEDULER: unique symbol;
33
+ /**
34
+ * `IEventPublisher` implementation that routes aggregate-emitted
35
+ * events through BOTH the in-memory transactional dispatcher
36
+ * (`@TransactionalEventsHandler`) AND — when wired — the outbox
37
+ * (`@OutboxEventsHandler`, introduced in a later phase). Both paths
38
+ * run inside the surrounding transaction:
39
+ *
40
+ * - In-memory: the dispatcher attaches hooks to the current
41
+ * transaction so listeners fire at the configured phase
42
+ * (`AFTER_COMMIT` by default). No database rows are written.
43
+ * - Outbox: {@link OutboxPublicationScheduler.scheduleForPublication}
44
+ * buffers the event and flushes the buffer via one `beforeCommit`
45
+ * hook per transaction. Publication rows commit atomically with
46
+ * the business write; rollback skips the flush.
47
+ *
48
+ * When no outbox scheduler is bound, behaves identically to
49
+ * {@link TransactionalEventPublisher}. Callers get outbox semantics
50
+ * automatically as soon as the scheduler is wired — no code change
51
+ * at the call site.
52
+ *
53
+ * Important: the outbox path is best-effort from the perspective of
54
+ * `AggregateRoot.commit()`. `commit()` is synchronous, so we cannot
55
+ * await the DB write here. Errors raised while the `beforeCommit`
56
+ * hook flushes the buffer DO bubble up — they cause the transaction
57
+ * to roll back, which is the intended behavior.
58
+ *
59
+ * **Multi-dataSource (Phase 14.7).** The outbox scheduler is the
60
+ * smart-facade `OutboxEventPublisher` (DD-024). When wired,
61
+ * AggregateRoot events are routed to the per-dataSource publisher
62
+ * that owns the event class — the same routing semantics as
63
+ * `OutboxEventPublisher.publish()`. Multi-DS apps with multiple
64
+ * outbox stacks (one `OutboxModule.forRoot()` per dataSource per
65
+ * ADR-019) bind `OUTBOX_PUBLICATION_SCHEDULER` to the smart facade
66
+ * via `useExisting: OutboxEventPublisher`; the facade's internal
67
+ * Map fans out to the correct per-DS publisher.
68
+ */
69
+ export declare class HybridEventPublisher implements IEventPublisher {
70
+ private readonly dispatcher;
71
+ private readonly outbox?;
72
+ constructor(dispatcher: TransactionalEventDispatcher, outbox?: OutboxPublicationScheduler | undefined);
73
+ publish<T extends IEvent>(event: T): void;
74
+ publishAll<T extends IEvent>(events: T[]): void;
75
+ }
76
+ //# sourceMappingURL=hybrid-event-publisher.d.ts.map