@nestjs-transactional/outbox 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 (126) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +396 -0
  3. package/dist/api/completed-event-publications.d.ts +31 -0
  4. package/dist/api/completed-event-publications.js +58 -0
  5. package/dist/api/completed-event-publications.js.map +1 -0
  6. package/dist/api/failed-event-publications.d.ts +36 -0
  7. package/dist/api/failed-event-publications.js +75 -0
  8. package/dist/api/failed-event-publications.js.map +1 -0
  9. package/dist/api/incomplete-event-publications.d.ts +28 -0
  10. package/dist/api/incomplete-event-publications.js +72 -0
  11. package/dist/api/incomplete-event-publications.js.map +1 -0
  12. package/dist/decorators/inject-decorators.d.ts +85 -0
  13. package/dist/decorators/inject-decorators.js +100 -0
  14. package/dist/decorators/inject-decorators.js.map +1 -0
  15. package/dist/decorators/outbox-events-handler.decorator.d.ts +97 -0
  16. package/dist/decorators/outbox-events-handler.decorator.js +58 -0
  17. package/dist/decorators/outbox-events-handler.decorator.js.map +1 -0
  18. package/dist/dispatcher/data-source-outbox-publisher.d.ts +69 -0
  19. package/dist/dispatcher/data-source-outbox-publisher.js +127 -0
  20. package/dist/dispatcher/data-source-outbox-publisher.js.map +1 -0
  21. package/dist/dispatcher/event-publication-processor.d.ts +69 -0
  22. package/dist/dispatcher/event-publication-processor.js +192 -0
  23. package/dist/dispatcher/event-publication-processor.js.map +1 -0
  24. package/dist/dispatcher/outbox-event-publisher.d.ts +129 -0
  25. package/dist/dispatcher/outbox-event-publisher.js +172 -0
  26. package/dist/dispatcher/outbox-event-publisher.js.map +1 -0
  27. package/dist/dispatcher/processor-options.d.ts +24 -0
  28. package/dist/dispatcher/processor-options.js +15 -0
  29. package/dist/dispatcher/processor-options.js.map +1 -0
  30. package/dist/externalization/errors.d.ts +21 -0
  31. package/dist/externalization/errors.js +30 -0
  32. package/dist/externalization/errors.js.map +1 -0
  33. package/dist/externalization/event-externalizer.d.ts +49 -0
  34. package/dist/externalization/event-externalizer.js +14 -0
  35. package/dist/externalization/event-externalizer.js.map +1 -0
  36. package/dist/externalization/externalization-registry.d.ts +56 -0
  37. package/dist/externalization/externalization-registry.js +103 -0
  38. package/dist/externalization/externalization-registry.js.map +1 -0
  39. package/dist/externalization/externalized.decorator.d.ts +121 -0
  40. package/dist/externalization/externalized.decorator.js +87 -0
  41. package/dist/externalization/externalized.decorator.js.map +1 -0
  42. package/dist/externalization/types.d.ts +39 -0
  43. package/dist/externalization/types.js +3 -0
  44. package/dist/externalization/types.js.map +1 -0
  45. package/dist/index.d.ts +38 -0
  46. package/dist/index.js +58 -0
  47. package/dist/index.js.map +1 -0
  48. package/dist/interfaces/outbox-event-handler.interface.d.ts +32 -0
  49. package/dist/interfaces/outbox-event-handler.interface.js +3 -0
  50. package/dist/interfaces/outbox-event-handler.interface.js.map +1 -0
  51. package/dist/module/outbox-processing.module.d.ts +29 -0
  52. package/dist/module/outbox-processing.module.js +66 -0
  53. package/dist/module/outbox-processing.module.js.map +1 -0
  54. package/dist/module/outbox.module.d.ts +196 -0
  55. package/dist/module/outbox.module.js +604 -0
  56. package/dist/module/outbox.module.js.map +1 -0
  57. package/dist/recovery/staleness-monitor.d.ts +39 -0
  58. package/dist/recovery/staleness-monitor.js +118 -0
  59. package/dist/recovery/staleness-monitor.js.map +1 -0
  60. package/dist/recovery/startup-recovery.d.ts +37 -0
  61. package/dist/recovery/startup-recovery.js +55 -0
  62. package/dist/recovery/startup-recovery.js.map +1 -0
  63. package/dist/registry/event-publication-registry.d.ts +70 -0
  64. package/dist/registry/event-publication-registry.js +138 -0
  65. package/dist/registry/event-publication-registry.js.map +1 -0
  66. package/dist/registry/listener-registry.d.ts +52 -0
  67. package/dist/registry/listener-registry.js +67 -0
  68. package/dist/registry/listener-registry.js.map +1 -0
  69. package/dist/registry/multi-ds-listener-registrar.d.ts +78 -0
  70. package/dist/registry/multi-ds-listener-registrar.js +112 -0
  71. package/dist/registry/multi-ds-listener-registrar.js.map +1 -0
  72. package/dist/registry/outbox-listener-scanner.d.ts +66 -0
  73. package/dist/registry/outbox-listener-scanner.js +192 -0
  74. package/dist/registry/outbox-listener-scanner.js.map +1 -0
  75. package/dist/repository/event-publication-repository.d.ts +112 -0
  76. package/dist/repository/event-publication-repository.js +6 -0
  77. package/dist/repository/event-publication-repository.js.map +1 -0
  78. package/dist/serialization/event-serializer.d.ts +28 -0
  79. package/dist/serialization/event-serializer.js +6 -0
  80. package/dist/serialization/event-serializer.js.map +1 -0
  81. package/dist/serialization/event-type-registry.d.ts +41 -0
  82. package/dist/serialization/event-type-registry.js +79 -0
  83. package/dist/serialization/event-type-registry.js.map +1 -0
  84. package/dist/serialization/event-type-resolver.d.ts +43 -0
  85. package/dist/serialization/event-type-resolver.js +66 -0
  86. package/dist/serialization/event-type-resolver.js.map +1 -0
  87. package/dist/serialization/json-event-serializer.d.ts +20 -0
  88. package/dist/serialization/json-event-serializer.js +64 -0
  89. package/dist/serialization/json-event-serializer.js.map +1 -0
  90. package/dist/testing/assertable-published-events.d.ts +71 -0
  91. package/dist/testing/assertable-published-events.js +124 -0
  92. package/dist/testing/assertable-published-events.js.map +1 -0
  93. package/dist/testing/in-memory-repository.d.ts +52 -0
  94. package/dist/testing/in-memory-repository.js +230 -0
  95. package/dist/testing/in-memory-repository.js.map +1 -0
  96. package/dist/testing/index.d.ts +4 -0
  97. package/dist/testing/index.js +20 -0
  98. package/dist/testing/index.js.map +1 -0
  99. package/dist/testing/published-events.d.ts +62 -0
  100. package/dist/testing/published-events.js +110 -0
  101. package/dist/testing/published-events.js.map +1 -0
  102. package/dist/tokens/index.d.ts +2 -0
  103. package/dist/tokens/index.js +14 -0
  104. package/dist/tokens/index.js.map +1 -0
  105. package/dist/tokens/token-utils.d.ts +68 -0
  106. package/dist/tokens/token-utils.js +98 -0
  107. package/dist/tokens/token-utils.js.map +1 -0
  108. package/dist/types/completion-mode.d.ts +16 -0
  109. package/dist/types/completion-mode.js +20 -0
  110. package/dist/types/completion-mode.js.map +1 -0
  111. package/dist/types/errors.d.ts +50 -0
  112. package/dist/types/errors.js +64 -0
  113. package/dist/types/errors.js.map +1 -0
  114. package/dist/types/event-publication.d.ts +47 -0
  115. package/dist/types/event-publication.js +3 -0
  116. package/dist/types/event-publication.js.map +1 -0
  117. package/dist/types/publication-status.d.ts +26 -0
  118. package/dist/types/publication-status.js +30 -0
  119. package/dist/types/publication-status.js.map +1 -0
  120. package/dist/types/resubmission-options.d.ts +37 -0
  121. package/dist/types/resubmission-options.js +62 -0
  122. package/dist/types/resubmission-options.js.map +1 -0
  123. package/dist/types/staleness-config.d.ts +18 -0
  124. package/dist/types/staleness-config.js +10 -0
  125. package/dist/types/staleness-config.js.map +1 -0
  126. package/package.json +77 -0
@@ -0,0 +1,72 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.IncompleteEventPublications = void 0;
16
+ const common_1 = require("@nestjs/common");
17
+ const event_publication_repository_1 = require("../repository/event-publication-repository");
18
+ const publication_status_1 = require("../types/publication-status");
19
+ const resubmission_options_1 = require("../types/resubmission-options");
20
+ /**
21
+ * Operator-facing query + resubmit API for every publication that has
22
+ * not yet reached the terminal `COMPLETED` state. Equivalent to Spring
23
+ * Modulith's `IncompleteEventPublications`.
24
+ *
25
+ * Typical use case: startup / restart recovery — query the backlog,
26
+ * bulk-resubmit retriable rows, let the processor drain.
27
+ */
28
+ let IncompleteEventPublications = class IncompleteEventPublications {
29
+ repository;
30
+ constructor(repository) {
31
+ this.repository = repository;
32
+ }
33
+ /** Return every publication whose status is not `COMPLETED`. */
34
+ async findAll() {
35
+ return this.repository.findIncomplete();
36
+ }
37
+ /** How many publications are currently not `COMPLETED`. */
38
+ async count() {
39
+ const incomplete = await this.repository.findIncomplete();
40
+ return incomplete.length;
41
+ }
42
+ /**
43
+ * Scan every non-completed publication and transition retriable
44
+ * ones (`FAILED`, `PUBLISHED`) to `RESUBMITTED`. Publications
45
+ * currently `PROCESSING` or `RESUBMITTED` are left untouched —
46
+ * `PROCESSING` is owned by a worker and `RESUBMITTED` is already in
47
+ * the retry queue. Returns the number of rows transitioned.
48
+ */
49
+ async resubmitIncompletePublications(options = resubmission_options_1.ResubmissionOptions.defaults()) {
50
+ const incomplete = await this.repository.findIncomplete();
51
+ const filtered = options.filter !== null ? incomplete.filter(options.filter) : incomplete;
52
+ const toProcess = filtered.slice(0, options.batchSize);
53
+ let resubmitted = 0;
54
+ for (const pub of toProcess) {
55
+ if (pub.status === publication_status_1.PublicationStatus.FAILED ||
56
+ pub.status === publication_status_1.PublicationStatus.PUBLISHED) {
57
+ await this.repository.updateStatus(pub.id, publication_status_1.PublicationStatus.RESUBMITTED, {
58
+ lastResubmissionDate: new Date(),
59
+ });
60
+ resubmitted++;
61
+ }
62
+ }
63
+ return resubmitted;
64
+ }
65
+ };
66
+ exports.IncompleteEventPublications = IncompleteEventPublications;
67
+ exports.IncompleteEventPublications = IncompleteEventPublications = __decorate([
68
+ (0, common_1.Injectable)(),
69
+ __param(0, (0, common_1.Inject)(event_publication_repository_1.EVENT_PUBLICATION_REPOSITORY)),
70
+ __metadata("design:paramtypes", [Object])
71
+ ], IncompleteEventPublications);
72
+ //# sourceMappingURL=incomplete-event-publications.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"incomplete-event-publications.js","sourceRoot":"","sources":["../../src/api/incomplete-event-publications.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAAoD;AAEpD,6FAGoD;AAEpD,oEAAgE;AAChE,wEAAoE;AAGpE;;;;;;;GAOG;AAEI,IAAM,2BAA2B,GAAjC,MAAM,2BAA2B;IAGnB;IAFnB,YAEmB,UAAsC;QAAtC,eAAU,GAAV,UAAU,CAA4B;IACtD,CAAC;IAEJ,gEAAgE;IAChE,KAAK,CAAC,OAAO;QACX,OAAO,IAAI,CAAC,UAAU,CAAC,cAAc,EAAE,CAAC;IAC1C,CAAC;IAED,2DAA2D;IAC3D,KAAK,CAAC,KAAK;QACT,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,cAAc,EAAE,CAAC;QAC1D,OAAO,UAAU,CAAC,MAAM,CAAC;IAC3B,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,8BAA8B,CAClC,UAA+B,0CAAmB,CAAC,QAAQ,EAAE;QAE7D,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,cAAc,EAAE,CAAC;QAE1D,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC;QAC1F,MAAM,SAAS,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;QAEvD,IAAI,WAAW,GAAG,CAAC,CAAC;QACpB,KAAK,MAAM,GAAG,IAAI,SAAS,EAAE,CAAC;YAC5B,IACE,GAAG,CAAC,MAAM,KAAK,sCAAiB,CAAC,MAAM;gBACvC,GAAG,CAAC,MAAM,KAAK,sCAAiB,CAAC,SAAS,EAC1C,CAAC;gBACD,MAAM,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,GAAG,CAAC,EAAE,EAAE,sCAAiB,CAAC,WAAW,EAAE;oBACxE,oBAAoB,EAAE,IAAI,IAAI,EAAE;iBACjC,CAAC,CAAC;gBACH,WAAW,EAAE,CAAC;YAChB,CAAC;QACH,CAAC;QAED,OAAO,WAAW,CAAC;IACrB,CAAC;CACF,CAAA;AA/CY,kEAA2B;sCAA3B,2BAA2B;IADvC,IAAA,mBAAU,GAAE;IAGR,WAAA,IAAA,eAAM,EAAC,2DAA4B,CAAC,CAAA;;GAF5B,2BAA2B,CA+CvC"}
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Inject decorators for the outbox-side per-dataSource components
3
+ * (DD-022). Each decorator below is sugar over
4
+ * `@Inject(getXxxToken(dataSource))` with a default dataSource of
5
+ * `'default'` — matches the `@InjectRepository(Entity, dataSource?)`
6
+ * ergonomics from `@nestjs/typeorm`.
7
+ *
8
+ * Single-adapter consumers omit the argument; multi-adapter
9
+ * consumers pass the dataSource name they registered with
10
+ * `OutboxModule.forRoot({ dataSource })`.
11
+ */
12
+ /**
13
+ * Inject the per-dataSource `OutboxEventPublisher`. The
14
+ * default-injected publisher is the smart facade (DD-024) that
15
+ * detects the active transaction context and routes accordingly;
16
+ * this decorator binds the underlying per-dataSource publisher
17
+ * directly when explicit selection is needed.
18
+ *
19
+ * @example
20
+ * ```ts
21
+ * class BillingService {
22
+ * constructor(
23
+ * @InjectOutboxPublisher('billing')
24
+ * private readonly publisher: OutboxEventPublisher,
25
+ * ) {}
26
+ * }
27
+ * ```
28
+ */
29
+ export declare const InjectOutboxPublisher: (dataSource?: string) => ParameterDecorator;
30
+ /**
31
+ * Inject the per-dataSource `EventTypeRegistry`. The registry is
32
+ * populated by the `OutboxModule.forFeature([...])` calls made
33
+ * against the same dataSource — registrations do not bleed across
34
+ * dataSources.
35
+ */
36
+ export declare const InjectEventTypeRegistry: (dataSource?: string) => ParameterDecorator;
37
+ /**
38
+ * Inject the per-dataSource `EventPublicationRegistry` — the
39
+ * lifecycle coordinator that owns publication state transitions
40
+ * (`PUBLISHED` → `PROCESSING` → `COMPLETED` / `FAILED`).
41
+ */
42
+ export declare const InjectEventPublicationRegistry: (dataSource?: string) => ParameterDecorator;
43
+ /**
44
+ * Inject the per-dataSource `EventPublicationProcessor` — the async
45
+ * worker that drains publications, dispatches them to listeners,
46
+ * and invokes the externalizer (when bound). Typically only needed
47
+ * by tests that drive the loop manually with `processBatch()`.
48
+ */
49
+ export declare const InjectEventPublicationProcessor: (dataSource?: string) => ParameterDecorator;
50
+ /**
51
+ * Inject the per-dataSource `OutboxListenerRegistry` — registry of
52
+ * listener entries scanned from `@OutboxEventsHandler` classes (and,
53
+ * when wired, `@IntegrationEventsHandler` classes routed via the
54
+ * outbox).
55
+ */
56
+ export declare const InjectOutboxListenerRegistry: (dataSource?: string) => ParameterDecorator;
57
+ /**
58
+ * Inject the per-dataSource `ExternalizationRegistry` — maps event
59
+ * type names to their `@Externalized` metadata. Consumed by the
60
+ * processor at dispatch time; rarely needed by application code.
61
+ */
62
+ export declare const InjectExternalizationRegistry: (dataSource?: string) => ParameterDecorator;
63
+ /**
64
+ * Inject the per-dataSource `EventPublicationRepository`. Adapter
65
+ * packages (`outbox-typeorm`, future `outbox-prisma`, ...) register
66
+ * their concrete repository under this token. Most application
67
+ * code injects the higher-level `OutboxEventPublisher` instead.
68
+ */
69
+ export declare const InjectEventPublicationRepository: (dataSource?: string) => ParameterDecorator;
70
+ /**
71
+ * Inject the per-dataSource `EventExternalizer`. Multi-adapter
72
+ * processes can wire externalization independently per outbox stack
73
+ * — e.g. the `'billing'` outbox emits to Kafka, the `'audit'` outbox
74
+ * is internal-only and binds no externalizer.
75
+ */
76
+ export declare const InjectEventExternalizer: (dataSource?: string) => ParameterDecorator;
77
+ /**
78
+ * Inject the per-dataSource `EventSerializer` used by the outbox to
79
+ * marshal events into the stored JSON payload and revive them at
80
+ * dispatch time. Distinct dataSources may use distinct
81
+ * serialization strategies (e.g. one JSON, another schema-validated)
82
+ * without forcing one strategy process-wide.
83
+ */
84
+ export declare const InjectOutboxEventSerializer: (dataSource?: string) => ParameterDecorator;
85
+ //# sourceMappingURL=inject-decorators.d.ts.map
@@ -0,0 +1,100 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.InjectOutboxEventSerializer = exports.InjectEventExternalizer = exports.InjectEventPublicationRepository = exports.InjectExternalizationRegistry = exports.InjectOutboxListenerRegistry = exports.InjectEventPublicationProcessor = exports.InjectEventPublicationRegistry = exports.InjectEventTypeRegistry = exports.InjectOutboxPublisher = void 0;
4
+ const common_1 = require("@nestjs/common");
5
+ const core_1 = require("@nestjs-transactional/core");
6
+ const token_utils_1 = require("../tokens/token-utils");
7
+ /**
8
+ * Inject decorators for the outbox-side per-dataSource components
9
+ * (DD-022). Each decorator below is sugar over
10
+ * `@Inject(getXxxToken(dataSource))` with a default dataSource of
11
+ * `'default'` — matches the `@InjectRepository(Entity, dataSource?)`
12
+ * ergonomics from `@nestjs/typeorm`.
13
+ *
14
+ * Single-adapter consumers omit the argument; multi-adapter
15
+ * consumers pass the dataSource name they registered with
16
+ * `OutboxModule.forRoot({ dataSource })`.
17
+ */
18
+ /**
19
+ * Inject the per-dataSource `OutboxEventPublisher`. The
20
+ * default-injected publisher is the smart facade (DD-024) that
21
+ * detects the active transaction context and routes accordingly;
22
+ * this decorator binds the underlying per-dataSource publisher
23
+ * directly when explicit selection is needed.
24
+ *
25
+ * @example
26
+ * ```ts
27
+ * class BillingService {
28
+ * constructor(
29
+ * @InjectOutboxPublisher('billing')
30
+ * private readonly publisher: OutboxEventPublisher,
31
+ * ) {}
32
+ * }
33
+ * ```
34
+ */
35
+ const InjectOutboxPublisher = (dataSource = core_1.DEFAULT_DATA_SOURCE_NAME) => (0, common_1.Inject)((0, token_utils_1.getOutboxPublisherToken)(dataSource));
36
+ exports.InjectOutboxPublisher = InjectOutboxPublisher;
37
+ /**
38
+ * Inject the per-dataSource `EventTypeRegistry`. The registry is
39
+ * populated by the `OutboxModule.forFeature([...])` calls made
40
+ * against the same dataSource — registrations do not bleed across
41
+ * dataSources.
42
+ */
43
+ const InjectEventTypeRegistry = (dataSource = core_1.DEFAULT_DATA_SOURCE_NAME) => (0, common_1.Inject)((0, token_utils_1.getEventTypeRegistryToken)(dataSource));
44
+ exports.InjectEventTypeRegistry = InjectEventTypeRegistry;
45
+ /**
46
+ * Inject the per-dataSource `EventPublicationRegistry` — the
47
+ * lifecycle coordinator that owns publication state transitions
48
+ * (`PUBLISHED` → `PROCESSING` → `COMPLETED` / `FAILED`).
49
+ */
50
+ const InjectEventPublicationRegistry = (dataSource = core_1.DEFAULT_DATA_SOURCE_NAME) => (0, common_1.Inject)((0, token_utils_1.getEventPublicationRegistryToken)(dataSource));
51
+ exports.InjectEventPublicationRegistry = InjectEventPublicationRegistry;
52
+ /**
53
+ * Inject the per-dataSource `EventPublicationProcessor` — the async
54
+ * worker that drains publications, dispatches them to listeners,
55
+ * and invokes the externalizer (when bound). Typically only needed
56
+ * by tests that drive the loop manually with `processBatch()`.
57
+ */
58
+ const InjectEventPublicationProcessor = (dataSource = core_1.DEFAULT_DATA_SOURCE_NAME) => (0, common_1.Inject)((0, token_utils_1.getEventPublicationProcessorToken)(dataSource));
59
+ exports.InjectEventPublicationProcessor = InjectEventPublicationProcessor;
60
+ /**
61
+ * Inject the per-dataSource `OutboxListenerRegistry` — registry of
62
+ * listener entries scanned from `@OutboxEventsHandler` classes (and,
63
+ * when wired, `@IntegrationEventsHandler` classes routed via the
64
+ * outbox).
65
+ */
66
+ const InjectOutboxListenerRegistry = (dataSource = core_1.DEFAULT_DATA_SOURCE_NAME) => (0, common_1.Inject)((0, token_utils_1.getOutboxListenerRegistryToken)(dataSource));
67
+ exports.InjectOutboxListenerRegistry = InjectOutboxListenerRegistry;
68
+ /**
69
+ * Inject the per-dataSource `ExternalizationRegistry` — maps event
70
+ * type names to their `@Externalized` metadata. Consumed by the
71
+ * processor at dispatch time; rarely needed by application code.
72
+ */
73
+ const InjectExternalizationRegistry = (dataSource = core_1.DEFAULT_DATA_SOURCE_NAME) => (0, common_1.Inject)((0, token_utils_1.getExternalizationRegistryToken)(dataSource));
74
+ exports.InjectExternalizationRegistry = InjectExternalizationRegistry;
75
+ /**
76
+ * Inject the per-dataSource `EventPublicationRepository`. Adapter
77
+ * packages (`outbox-typeorm`, future `outbox-prisma`, ...) register
78
+ * their concrete repository under this token. Most application
79
+ * code injects the higher-level `OutboxEventPublisher` instead.
80
+ */
81
+ const InjectEventPublicationRepository = (dataSource = core_1.DEFAULT_DATA_SOURCE_NAME) => (0, common_1.Inject)((0, token_utils_1.getEventPublicationRepositoryToken)(dataSource));
82
+ exports.InjectEventPublicationRepository = InjectEventPublicationRepository;
83
+ /**
84
+ * Inject the per-dataSource `EventExternalizer`. Multi-adapter
85
+ * processes can wire externalization independently per outbox stack
86
+ * — e.g. the `'billing'` outbox emits to Kafka, the `'audit'` outbox
87
+ * is internal-only and binds no externalizer.
88
+ */
89
+ const InjectEventExternalizer = (dataSource = core_1.DEFAULT_DATA_SOURCE_NAME) => (0, common_1.Inject)((0, token_utils_1.getEventExternalizerToken)(dataSource));
90
+ exports.InjectEventExternalizer = InjectEventExternalizer;
91
+ /**
92
+ * Inject the per-dataSource `EventSerializer` used by the outbox to
93
+ * marshal events into the stored JSON payload and revive them at
94
+ * dispatch time. Distinct dataSources may use distinct
95
+ * serialization strategies (e.g. one JSON, another schema-validated)
96
+ * without forcing one strategy process-wide.
97
+ */
98
+ const InjectOutboxEventSerializer = (dataSource = core_1.DEFAULT_DATA_SOURCE_NAME) => (0, common_1.Inject)((0, token_utils_1.getOutboxEventSerializerToken)(dataSource));
99
+ exports.InjectOutboxEventSerializer = InjectOutboxEventSerializer;
100
+ //# sourceMappingURL=inject-decorators.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inject-decorators.js","sourceRoot":"","sources":["../../src/decorators/inject-decorators.ts"],"names":[],"mappings":";;;AAAA,2CAAwC;AACxC,qDAAsE;AAEtE,uDAU+B;AAE/B;;;;;;;;;;GAUG;AAEH;;;;;;;;;;;;;;;;GAgBG;AACI,MAAM,qBAAqB,GAAG,CACnC,aAAqB,+BAAwB,EACzB,EAAE,CAAC,IAAA,eAAM,EAAC,IAAA,qCAAuB,EAAC,UAAU,CAAC,CAAC,CAAC;AAFxD,QAAA,qBAAqB,yBAEmC;AAErE;;;;;GAKG;AACI,MAAM,uBAAuB,GAAG,CACrC,aAAqB,+BAAwB,EACzB,EAAE,CAAC,IAAA,eAAM,EAAC,IAAA,uCAAyB,EAAC,UAAU,CAAC,CAAC,CAAC;AAF1D,QAAA,uBAAuB,2BAEmC;AAEvE;;;;GAIG;AACI,MAAM,8BAA8B,GAAG,CAC5C,aAAqB,+BAAwB,EACzB,EAAE,CAAC,IAAA,eAAM,EAAC,IAAA,8CAAgC,EAAC,UAAU,CAAC,CAAC,CAAC;AAFjE,QAAA,8BAA8B,kCAEmC;AAE9E;;;;;GAKG;AACI,MAAM,+BAA+B,GAAG,CAC7C,aAAqB,+BAAwB,EACzB,EAAE,CAAC,IAAA,eAAM,EAAC,IAAA,+CAAiC,EAAC,UAAU,CAAC,CAAC,CAAC;AAFlE,QAAA,+BAA+B,mCAEmC;AAE/E;;;;;GAKG;AACI,MAAM,4BAA4B,GAAG,CAC1C,aAAqB,+BAAwB,EACzB,EAAE,CAAC,IAAA,eAAM,EAAC,IAAA,4CAA8B,EAAC,UAAU,CAAC,CAAC,CAAC;AAF/D,QAAA,4BAA4B,gCAEmC;AAE5E;;;;GAIG;AACI,MAAM,6BAA6B,GAAG,CAC3C,aAAqB,+BAAwB,EACzB,EAAE,CAAC,IAAA,eAAM,EAAC,IAAA,6CAA+B,EAAC,UAAU,CAAC,CAAC,CAAC;AAFhE,QAAA,6BAA6B,iCAEmC;AAE7E;;;;;GAKG;AACI,MAAM,gCAAgC,GAAG,CAC9C,aAAqB,+BAAwB,EACzB,EAAE,CAAC,IAAA,eAAM,EAAC,IAAA,gDAAkC,EAAC,UAAU,CAAC,CAAC,CAAC;AAFnE,QAAA,gCAAgC,oCAEmC;AAEhF;;;;;GAKG;AACI,MAAM,uBAAuB,GAAG,CACrC,aAAqB,+BAAwB,EACzB,EAAE,CAAC,IAAA,eAAM,EAAC,IAAA,uCAAyB,EAAC,UAAU,CAAC,CAAC,CAAC;AAF1D,QAAA,uBAAuB,2BAEmC;AAEvE;;;;;;GAMG;AACI,MAAM,2BAA2B,GAAG,CACzC,aAAqB,+BAAwB,EACzB,EAAE,CAAC,IAAA,eAAM,EAAC,IAAA,2CAA6B,EAAC,UAAU,CAAC,CAAC,CAAC;AAF9D,QAAA,2BAA2B,+BAEmC"}
@@ -0,0 +1,97 @@
1
+ import 'reflect-metadata';
2
+ import { type Type } from '@nestjs/common';
3
+ /**
4
+ * Metadata key under which {@link OutboxEventsHandlerMetadata} is
5
+ * stored on classes decorated with {@link OutboxEventsHandler}.
6
+ *
7
+ * Fresh `Symbol` (not `Symbol.for`) — this metadata is read only by
8
+ * outbox's own `OutboxListenerScanner`. Cross-package sharing is
9
+ * not required because `@IntegrationEventsHandler` in the cqrs
10
+ * package uses the `OUTBOX_LISTENER_REGISTRAR` structural port, not
11
+ * metadata introspection, to route handlers to the outbox.
12
+ */
13
+ export declare const OUTBOX_EVENTS_HANDLER_METADATA: unique symbol;
14
+ /**
15
+ * Options accepted by the long form of {@link OutboxEventsHandler}.
16
+ */
17
+ export interface OutboxEventsHandlerOptions {
18
+ /** Domain event classes the handler subscribes to. Must be non-empty. */
19
+ readonly events: Type[];
20
+ /**
21
+ * Stable, globally-unique listener id base. When set, the scanner
22
+ * derives the per-event-type id as `${id}#${EventName}`. When
23
+ * omitted, the base id is `${ClassName}` — a rename of the class
24
+ * therefore breaks resume of already-stored publications.
25
+ *
26
+ * The id (after the suffix is appended) is persisted on every
27
+ * `event_publication` row — supply an explicit id to protect
28
+ * against renames in production.
29
+ */
30
+ readonly id?: string;
31
+ /**
32
+ * Run the handler in its own new transaction (`REQUIRES_NEW`
33
+ * semantics). Default: `true` — matches Spring Modulith's
34
+ * `@ApplicationModuleListener` behaviour. Set to `false` to run
35
+ * the handler without opening a transaction (e.g. the handler
36
+ * only calls an idempotent external API).
37
+ */
38
+ readonly newTransaction?: boolean;
39
+ }
40
+ /**
41
+ * Resolved metadata attached to a handler class.
42
+ */
43
+ export interface OutboxEventsHandlerMetadata {
44
+ readonly eventTypes: Type[];
45
+ readonly id?: string;
46
+ readonly newTransaction: boolean;
47
+ }
48
+ /**
49
+ * Mark a class as a persistent outbox handler. The class must
50
+ * implement {@link IOutboxEventHandler} — expose a
51
+ * `handle(event): Promise<void>` method.
52
+ *
53
+ * Distinct from `@TransactionalEventsHandler` (cqrs package), which
54
+ * is in-memory and phase-based: `@OutboxEventsHandler` is
55
+ * persistent, always after-commit, and supports retry / recovery on
56
+ * restart. Also distinct from `@IntegrationEventsHandler`, which
57
+ * switches between durable and in-memory delivery based on module
58
+ * wiring — this decorator ALWAYS routes to the outbox (and will
59
+ * fail bootstrap without an outbox registry).
60
+ *
61
+ * Two forms:
62
+ *
63
+ * ```ts
64
+ * // Short form — defaults (newTransaction: true):
65
+ * @OutboxEventsHandler(OrderPlacedEvent, OrderCancelledEvent)
66
+ *
67
+ * // Long form — explicit options:
68
+ * @OutboxEventsHandler({
69
+ * events: [OrderPlacedEvent],
70
+ * id: 'inventory.reservation',
71
+ * newTransaction: false,
72
+ * })
73
+ * ```
74
+ *
75
+ * Class-level only; the metadata is written by
76
+ * `Reflect.defineMetadata`. The actual registration happens at
77
+ * application bootstrap via `OutboxListenerScanner`.
78
+ *
79
+ * **Multi-dataSource (Phase 14.3.1).** The scanner walks every
80
+ * per-dataSource `EventTypeRegistry` and routes the handler to the
81
+ * `OutboxListenerRegistry` whose dataSource owns the decorated
82
+ * events — automatic, no decorator option required. A handler
83
+ * subscribing to events spanning multiple dataSources is rejected
84
+ * at bootstrap with an actionable message; handlers must be
85
+ * dataSource-scoped.
86
+ *
87
+ * @throws {Error} If no event types are supplied.
88
+ */
89
+ export declare function OutboxEventsHandler(...events: Type[]): ClassDecorator;
90
+ export declare function OutboxEventsHandler(options: OutboxEventsHandlerOptions): ClassDecorator;
91
+ /**
92
+ * Read the {@link OutboxEventsHandlerMetadata} attached to `target`
93
+ * by {@link OutboxEventsHandler}. Returns `undefined` when the
94
+ * class was not decorated.
95
+ */
96
+ export declare function getOutboxEventsHandlerMetadata(target: object): OutboxEventsHandlerMetadata | undefined;
97
+ //# sourceMappingURL=outbox-events-handler.decorator.d.ts.map
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.OUTBOX_EVENTS_HANDLER_METADATA = void 0;
4
+ exports.OutboxEventsHandler = OutboxEventsHandler;
5
+ exports.getOutboxEventsHandlerMetadata = getOutboxEventsHandlerMetadata;
6
+ require("reflect-metadata");
7
+ /**
8
+ * Metadata key under which {@link OutboxEventsHandlerMetadata} is
9
+ * stored on classes decorated with {@link OutboxEventsHandler}.
10
+ *
11
+ * Fresh `Symbol` (not `Symbol.for`) — this metadata is read only by
12
+ * outbox's own `OutboxListenerScanner`. Cross-package sharing is
13
+ * not required because `@IntegrationEventsHandler` in the cqrs
14
+ * package uses the `OUTBOX_LISTENER_REGISTRAR` structural port, not
15
+ * metadata introspection, to route handlers to the outbox.
16
+ */
17
+ exports.OUTBOX_EVENTS_HANDLER_METADATA = Symbol('OUTBOX_EVENTS_HANDLER_METADATA');
18
+ function OutboxEventsHandler(...args) {
19
+ const metadata = resolveMetadata(args);
20
+ if (metadata.eventTypes.length === 0) {
21
+ throw new Error('@OutboxEventsHandler 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.OUTBOX_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
+ id: options.id,
34
+ newTransaction: options.newTransaction ?? true,
35
+ };
36
+ }
37
+ return {
38
+ eventTypes: args,
39
+ newTransaction: true,
40
+ };
41
+ }
42
+ function isOptionsObject(candidate) {
43
+ return (candidate !== null &&
44
+ typeof candidate === 'object' &&
45
+ !Array.isArray(candidate) &&
46
+ typeof candidate !== 'function' &&
47
+ 'events' in candidate);
48
+ }
49
+ /**
50
+ * Read the {@link OutboxEventsHandlerMetadata} attached to `target`
51
+ * by {@link OutboxEventsHandler}. Returns `undefined` when the
52
+ * class was not decorated.
53
+ */
54
+ function getOutboxEventsHandlerMetadata(target) {
55
+ const value = Reflect.getMetadata(exports.OUTBOX_EVENTS_HANDLER_METADATA, target);
56
+ return value;
57
+ }
58
+ //# sourceMappingURL=outbox-events-handler.decorator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"outbox-events-handler.decorator.js","sourceRoot":"","sources":["../../src/decorators/outbox-events-handler.decorator.ts"],"names":[],"mappings":";;;AA+FA,kDAeC;AAmCD,wEAKC;AAtJD,4BAA0B;AAI1B;;;;;;;;;GASG;AACU,QAAA,8BAA8B,GAAG,MAAM,CAAC,gCAAgC,CAAC,CAAC;AAiFvF,SAAgB,mBAAmB,CACjC,GAAG,IAA2C;IAE9C,MAAM,QAAQ,GAAgC,eAAe,CAAC,IAAI,CAAC,CAAC;IAEpE,IAAI,QAAQ,CAAC,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACrC,MAAM,IAAI,KAAK,CACb,yDAAyD;YACvD,uEAAuE,CAC1E,CAAC;IACJ,CAAC;IAED,OAAO,CAAC,MAAc,EAAQ,EAAE;QAC9B,OAAO,CAAC,cAAc,CAAC,sCAA8B,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;IAC3E,CAAC,CAAC;AACJ,CAAC;AAED,SAAS,eAAe,CACtB,IAA2C;IAE3C,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,EAAE,EAAE,OAAO,CAAC,EAAE;YACd,cAAc,EAAE,OAAO,CAAC,cAAc,IAAI,IAAI;SAC/C,CAAC;IACJ,CAAC;IAED,OAAO;QACL,UAAU,EAAE,IAAc;QAC1B,cAAc,EAAE,IAAI;KACrB,CAAC;AACJ,CAAC;AAED,SAAS,eAAe,CAAC,SAAkB;IACzC,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;;;;GAIG;AACH,SAAgB,8BAA8B,CAC5C,MAAc;IAEd,MAAM,KAAK,GAAY,OAAO,CAAC,WAAW,CAAC,sCAA8B,EAAE,MAAM,CAAC,CAAC;IACnF,OAAO,KAAgD,CAAC;AAC1D,CAAC"}
@@ -0,0 +1,69 @@
1
+ import type { EventPublicationRegistry } from '../registry/event-publication-registry';
2
+ import type { OutboxListenerRegistry } from '../registry/listener-registry';
3
+ /**
4
+ * Per-dataSource publisher (Phase 14.3). Owns the per-transaction
5
+ * buffer, lifecycle hook registration, and delegate calls into the
6
+ * `EventPublicationRegistry` bound to a single dataSource.
7
+ *
8
+ * Not user-facing — application code injects the smart facade
9
+ * {@link OutboxEventPublisher}, which routes events to the
10
+ * `DataSourceOutboxPublisher` whose dataSource owns the event class.
11
+ * Exported nonetheless because:
12
+ * - tests may want to drive a per-DS publisher directly
13
+ * - advanced consumers (e.g. cross-DS bridges) may need the
14
+ * dataSource-bound surface
15
+ *
16
+ * Single-DS deployments still resolve `OutboxEventPublisher` from DI
17
+ * — the facade transparently delegates to the only registered
18
+ * `DataSourceOutboxPublisher`.
19
+ */
20
+ export declare class DataSourceOutboxPublisher {
21
+ readonly dataSource: string;
22
+ private readonly registry;
23
+ private readonly listenerRegistry;
24
+ private readonly logger;
25
+ private readonly pending;
26
+ /**
27
+ * @param dataSource Public dataSource name this publisher binds to.
28
+ * Used as the lookup key for the active transaction (DD-023) and
29
+ * surfaced in error messages.
30
+ * @param registry Per-DS {@link EventPublicationRegistry}.
31
+ * @param listenerRegistry Per-DS {@link OutboxListenerRegistry}.
32
+ */
33
+ constructor(dataSource: string, registry: EventPublicationRegistry, listenerRegistry: OutboxListenerRegistry);
34
+ /**
35
+ * Publish a single event into this dataSource's outbox. Must be
36
+ * called inside an active transaction *for this dataSource*. Throws
37
+ * {@link IllegalTransactionStateError} otherwise — the publication
38
+ * row must commit atomically with the business write, and the
39
+ * specific dataSource's transaction is the only context that can
40
+ * provide that atomicity.
41
+ *
42
+ * Creates one publication entry per listener registered for the
43
+ * event type. Zero listeners is a silent no-op (but the
44
+ * active-transaction check still applies).
45
+ */
46
+ publish(event: unknown): Promise<void>;
47
+ /**
48
+ * Publish a batch of events through this dataSource — same semantics
49
+ * and same active-transaction check applied per event.
50
+ */
51
+ publishAll(events: readonly unknown[]): Promise<void>;
52
+ /**
53
+ * Synchronous scheduling for sync callers (e.g. `@nestjs/cqrs`'s
54
+ * `AggregateRoot.commit()`). Inside a transaction *for this
55
+ * dataSource*: events are buffered and flushed in a `beforeCommit`
56
+ * hook. Outside any transaction (or no transaction for this DS):
57
+ * fire-and-forget {@link publish}, errors logged.
58
+ *
59
+ * The hook is attached directly to this dataSource's `ActiveTransaction.beforeCommitHooks`
60
+ * — `transactionManager.registerBeforeCommit` is NOT used because it
61
+ * always targets "the first active transaction on the context",
62
+ * which is the wrong target when multiple dataSources have live
63
+ * transactions in the same async stack (Phase 14.2 cross-DS
64
+ * simultaneous scenario).
65
+ */
66
+ scheduleForPublication(event: unknown): void;
67
+ private ensureActiveTransaction;
68
+ }
69
+ //# sourceMappingURL=data-source-outbox-publisher.d.ts.map
@@ -0,0 +1,127 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DataSourceOutboxPublisher = void 0;
4
+ const common_1 = require("@nestjs/common");
5
+ const core_1 = require("@nestjs-transactional/core");
6
+ /**
7
+ * Per-dataSource publisher (Phase 14.3). Owns the per-transaction
8
+ * buffer, lifecycle hook registration, and delegate calls into the
9
+ * `EventPublicationRegistry` bound to a single dataSource.
10
+ *
11
+ * Not user-facing — application code injects the smart facade
12
+ * {@link OutboxEventPublisher}, which routes events to the
13
+ * `DataSourceOutboxPublisher` whose dataSource owns the event class.
14
+ * Exported nonetheless because:
15
+ * - tests may want to drive a per-DS publisher directly
16
+ * - advanced consumers (e.g. cross-DS bridges) may need the
17
+ * dataSource-bound surface
18
+ *
19
+ * Single-DS deployments still resolve `OutboxEventPublisher` from DI
20
+ * — the facade transparently delegates to the only registered
21
+ * `DataSourceOutboxPublisher`.
22
+ */
23
+ class DataSourceOutboxPublisher {
24
+ dataSource;
25
+ registry;
26
+ listenerRegistry;
27
+ logger;
28
+ // Per-transaction buffer of events awaiting flush. Keyed by the
29
+ // ActiveTransaction object itself so the entry is GC'd with the
30
+ // transaction — no cleanup code to maintain, and no risk of
31
+ // cross-transaction leakage.
32
+ pending = new WeakMap();
33
+ /**
34
+ * @param dataSource Public dataSource name this publisher binds to.
35
+ * Used as the lookup key for the active transaction (DD-023) and
36
+ * surfaced in error messages.
37
+ * @param registry Per-DS {@link EventPublicationRegistry}.
38
+ * @param listenerRegistry Per-DS {@link OutboxListenerRegistry}.
39
+ */
40
+ constructor(dataSource, registry, listenerRegistry) {
41
+ this.dataSource = dataSource;
42
+ this.registry = registry;
43
+ this.listenerRegistry = listenerRegistry;
44
+ this.logger = new common_1.Logger(`DataSourceOutboxPublisher[${dataSource}]`);
45
+ }
46
+ /**
47
+ * Publish a single event into this dataSource's outbox. Must be
48
+ * called inside an active transaction *for this dataSource*. Throws
49
+ * {@link IllegalTransactionStateError} otherwise — the publication
50
+ * row must commit atomically with the business write, and the
51
+ * specific dataSource's transaction is the only context that can
52
+ * provide that atomicity.
53
+ *
54
+ * Creates one publication entry per listener registered for the
55
+ * event type. Zero listeners is a silent no-op (but the
56
+ * active-transaction check still applies).
57
+ */
58
+ async publish(event) {
59
+ this.ensureActiveTransaction();
60
+ const eventType = event.constructor.name;
61
+ const listeners = this.listenerRegistry.getByEventType(eventType);
62
+ if (listeners.length === 0) {
63
+ return;
64
+ }
65
+ const listenerIds = listeners.map((l) => l.id);
66
+ await this.registry.publish(event, listenerIds);
67
+ }
68
+ /**
69
+ * Publish a batch of events through this dataSource — same semantics
70
+ * and same active-transaction check applied per event.
71
+ */
72
+ async publishAll(events) {
73
+ for (const event of events) {
74
+ await this.publish(event);
75
+ }
76
+ }
77
+ /**
78
+ * Synchronous scheduling for sync callers (e.g. `@nestjs/cqrs`'s
79
+ * `AggregateRoot.commit()`). Inside a transaction *for this
80
+ * dataSource*: events are buffered and flushed in a `beforeCommit`
81
+ * hook. Outside any transaction (or no transaction for this DS):
82
+ * fire-and-forget {@link publish}, errors logged.
83
+ *
84
+ * The hook is attached directly to this dataSource's `ActiveTransaction.beforeCommitHooks`
85
+ * — `transactionManager.registerBeforeCommit` is NOT used because it
86
+ * always targets "the first active transaction on the context",
87
+ * which is the wrong target when multiple dataSources have live
88
+ * transactions in the same async stack (Phase 14.2 cross-DS
89
+ * simultaneous scenario).
90
+ */
91
+ scheduleForPublication(event) {
92
+ const tx = core_1.TransactionContext.getActiveTransactionByDataSource(this.dataSource);
93
+ if (tx === undefined) {
94
+ void this.publish(event).catch((err) => {
95
+ this.logger.error(`scheduleForPublication outside an active '${this.dataSource}' transaction failed: ${err instanceof Error ? err.message : String(err)}`, err instanceof Error ? err.stack : undefined);
96
+ });
97
+ return;
98
+ }
99
+ let buffer = this.pending.get(tx);
100
+ if (buffer === undefined) {
101
+ buffer = [];
102
+ this.pending.set(tx, buffer);
103
+ // Push the hook onto THIS specific transaction's hook list —
104
+ // not via transactionManager.registerBeforeCommit which targets
105
+ // the first-active transaction (wrong with multi-DS).
106
+ tx.beforeCommitHooks.push(async () => {
107
+ const toFlush = this.pending.get(tx);
108
+ this.pending.delete(tx);
109
+ if (toFlush !== undefined && toFlush.length > 0) {
110
+ await this.publishAll(toFlush);
111
+ }
112
+ });
113
+ }
114
+ buffer.push(event);
115
+ }
116
+ ensureActiveTransaction() {
117
+ const tx = core_1.TransactionContext.getActiveTransactionByDataSource(this.dataSource);
118
+ if (tx === undefined) {
119
+ throw new core_1.IllegalTransactionStateError(`OutboxEventPublisher.publish for dataSource '${this.dataSource}' must be ` +
120
+ `called inside an active transaction for that dataSource. Wrap the call ` +
121
+ `in @Transactional({ dataSource: '${this.dataSource}' }) so the publication ` +
122
+ `row commits atomically with the business write.`);
123
+ }
124
+ }
125
+ }
126
+ exports.DataSourceOutboxPublisher = DataSourceOutboxPublisher;
127
+ //# sourceMappingURL=data-source-outbox-publisher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data-source-outbox-publisher.js","sourceRoot":"","sources":["../../src/dispatcher/data-source-outbox-publisher.ts"],"names":[],"mappings":"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"}