@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,69 @@
1
+ import { type EventExternalizer } from '../externalization/event-externalizer';
2
+ import { ExternalizationRegistry } from '../externalization/externalization-registry';
3
+ import { EventPublicationRegistry } from '../registry/event-publication-registry';
4
+ import { OutboxListenerRegistry } from '../registry/listener-registry';
5
+ import type { EventPublicationProcessorOptions } from './processor-options';
6
+ /**
7
+ * Async worker that drains the event publication queue:
8
+ *
9
+ * 1. Pulls up to `batchSize` publications in `PUBLISHED` / `RESUBMITTED`
10
+ * state from the {@link EventPublicationRegistry};
11
+ * 2. atomically claims each one (`PUBLISHED/RESUBMITTED → PROCESSING`)
12
+ * so concurrent workers cannot double-dispatch;
13
+ * 3. looks up the corresponding listener in the
14
+ * {@link OutboxListenerRegistry} and invokes it with the
15
+ * deserialized event;
16
+ * 4. finalizes the publication — `COMPLETED` with the configured
17
+ * completion mode on success, `FAILED` with the error message
18
+ * otherwise.
19
+ *
20
+ * Up to `maxConcurrent` invocations run in parallel inside one batch.
21
+ * Listener errors never bubble out: they are caught, logged, and
22
+ * recorded on the publication row.
23
+ */
24
+ export declare class EventPublicationProcessor {
25
+ private readonly registry;
26
+ private readonly listenerRegistry;
27
+ private readonly options;
28
+ private readonly externalizer?;
29
+ private readonly externalizationRegistry?;
30
+ private readonly logger;
31
+ private running;
32
+ private processingLoop;
33
+ constructor(registry: EventPublicationRegistry, listenerRegistry: OutboxListenerRegistry, options: EventPublicationProcessorOptions, externalizer?: EventExternalizer | undefined, externalizationRegistry?: ExternalizationRegistry | undefined);
34
+ /** Start the periodic polling loop. Idempotent. */
35
+ start(): void;
36
+ /** Stop the polling loop and cancel any pending scheduled tick. */
37
+ stop(): void;
38
+ /**
39
+ * Process a single batch of pending publications. Safe to call
40
+ * directly from tests and one-shot tooling; `start()` triggers it
41
+ * periodically.
42
+ *
43
+ * Internal errors (e.g. DB unreachable) are caught and logged —
44
+ * this method never rejects.
45
+ */
46
+ processBatch(): Promise<void>;
47
+ private scheduleNext;
48
+ private processOne;
49
+ /**
50
+ * Externalize the event after the local listener has succeeded.
51
+ *
52
+ * Returns immediately (no-op) when:
53
+ * - no {@link EventExternalizer} is bound (DD-018 — externalization
54
+ * is optional);
55
+ * - no {@link ExternalizationRegistry} is bound (defensive — the
56
+ * `OutboxModule` always provides one, but direct `new`
57
+ * instantiation in tests may omit it);
58
+ * - the event type carries no `@Externalized` mapping.
59
+ *
60
+ * Otherwise resolves the per-publication {@link ExternalizationMetadata}
61
+ * from the registry and invokes the externalizer. Any rejection is
62
+ * wrapped in {@link ExternalizationError} and re-thrown so the outer
63
+ * try / catch in `processOne` records the publication as `FAILED`,
64
+ * which preserves the single-unit atomicity contract from DD-019.
65
+ */
66
+ private tryExternalize;
67
+ private chunk;
68
+ }
69
+ //# sourceMappingURL=event-publication-processor.d.ts.map
@@ -0,0 +1,192 @@
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 EventPublicationProcessor_1;
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.EventPublicationProcessor = void 0;
17
+ const common_1 = require("@nestjs/common");
18
+ const errors_1 = require("../externalization/errors");
19
+ const event_externalizer_1 = require("../externalization/event-externalizer");
20
+ const externalization_registry_1 = require("../externalization/externalization-registry");
21
+ const event_publication_registry_1 = require("../registry/event-publication-registry");
22
+ const listener_registry_1 = require("../registry/listener-registry");
23
+ /**
24
+ * Async worker that drains the event publication queue:
25
+ *
26
+ * 1. Pulls up to `batchSize` publications in `PUBLISHED` / `RESUBMITTED`
27
+ * state from the {@link EventPublicationRegistry};
28
+ * 2. atomically claims each one (`PUBLISHED/RESUBMITTED → PROCESSING`)
29
+ * so concurrent workers cannot double-dispatch;
30
+ * 3. looks up the corresponding listener in the
31
+ * {@link OutboxListenerRegistry} and invokes it with the
32
+ * deserialized event;
33
+ * 4. finalizes the publication — `COMPLETED` with the configured
34
+ * completion mode on success, `FAILED` with the error message
35
+ * otherwise.
36
+ *
37
+ * Up to `maxConcurrent` invocations run in parallel inside one batch.
38
+ * Listener errors never bubble out: they are caught, logged, and
39
+ * recorded on the publication row.
40
+ */
41
+ let EventPublicationProcessor = EventPublicationProcessor_1 = class EventPublicationProcessor {
42
+ registry;
43
+ listenerRegistry;
44
+ options;
45
+ externalizer;
46
+ externalizationRegistry;
47
+ logger = new common_1.Logger(EventPublicationProcessor_1.name);
48
+ running = false;
49
+ processingLoop = null;
50
+ constructor(registry, listenerRegistry, options, externalizer, externalizationRegistry) {
51
+ this.registry = registry;
52
+ this.listenerRegistry = listenerRegistry;
53
+ this.options = options;
54
+ this.externalizer = externalizer;
55
+ this.externalizationRegistry = externalizationRegistry;
56
+ }
57
+ /** Start the periodic polling loop. Idempotent. */
58
+ start() {
59
+ if (this.running) {
60
+ return;
61
+ }
62
+ this.running = true;
63
+ this.scheduleNext();
64
+ this.logger.log('EventPublicationProcessor started');
65
+ }
66
+ /** Stop the polling loop and cancel any pending scheduled tick. */
67
+ stop() {
68
+ this.running = false;
69
+ if (this.processingLoop !== null) {
70
+ clearTimeout(this.processingLoop);
71
+ this.processingLoop = null;
72
+ }
73
+ this.logger.log('EventPublicationProcessor stopped');
74
+ }
75
+ /**
76
+ * Process a single batch of pending publications. Safe to call
77
+ * directly from tests and one-shot tooling; `start()` triggers it
78
+ * periodically.
79
+ *
80
+ * Internal errors (e.g. DB unreachable) are caught and logged —
81
+ * this method never rejects.
82
+ */
83
+ async processBatch() {
84
+ try {
85
+ const publications = await this.registry.findReadyForProcessing(this.options.batchSize);
86
+ if (publications.length === 0) {
87
+ return;
88
+ }
89
+ this.logger.debug(`Processing batch of ${publications.length} publications`);
90
+ const chunks = this.chunk(publications, this.options.maxConcurrent);
91
+ for (const chunk of chunks) {
92
+ await Promise.all(chunk.map((pub) => this.processOne(pub)));
93
+ }
94
+ }
95
+ catch (err) {
96
+ this.logger.error('Batch processing failed', err instanceof Error ? err.stack : String(err));
97
+ }
98
+ }
99
+ scheduleNext() {
100
+ if (!this.running) {
101
+ return;
102
+ }
103
+ this.processingLoop = setTimeout(() => {
104
+ void this.processBatch().finally(() => this.scheduleNext());
105
+ }, this.options.pollingInterval);
106
+ }
107
+ async processOne(publication) {
108
+ try {
109
+ const claimed = await this.registry.tryClaim(publication.id);
110
+ if (!claimed) {
111
+ return;
112
+ }
113
+ const listener = this.listenerRegistry.getById(publication.listenerId);
114
+ if (listener === undefined) {
115
+ await this.registry.markFailed(publication.id, `Listener '${publication.listenerId}' is not registered`);
116
+ this.logger.warn(`Listener '${publication.listenerId}' not found for publication ${publication.id}`);
117
+ return;
118
+ }
119
+ try {
120
+ const event = this.registry.deserialize(publication);
121
+ // Local listener invocation runs first so cheap, in-process
122
+ // failures fail fast before we touch a broker (DD-019).
123
+ await listener.invoke(event);
124
+ // Externalization is optional and gated by the registry
125
+ // resolution wired in 11.2 — `tryExternalize` is a no-op until
126
+ // ExternalizationRegistry lookup lands.
127
+ await this.tryExternalize(event, publication);
128
+ await this.registry.markCompleted(publication.id, this.options.completionMode);
129
+ }
130
+ catch (err) {
131
+ const reason = err instanceof Error ? err.message : String(err);
132
+ await this.registry.markFailed(publication.id, reason);
133
+ this.logger.error(`Listener '${publication.listenerId}' failed for publication ${publication.id}: ${reason}`, err instanceof Error ? err.stack : undefined);
134
+ }
135
+ }
136
+ catch (err) {
137
+ this.logger.error(`Error processing publication ${publication.id}`, err instanceof Error ? err.stack : String(err));
138
+ }
139
+ }
140
+ /**
141
+ * Externalize the event after the local listener has succeeded.
142
+ *
143
+ * Returns immediately (no-op) when:
144
+ * - no {@link EventExternalizer} is bound (DD-018 — externalization
145
+ * is optional);
146
+ * - no {@link ExternalizationRegistry} is bound (defensive — the
147
+ * `OutboxModule` always provides one, but direct `new`
148
+ * instantiation in tests may omit it);
149
+ * - the event type carries no `@Externalized` mapping.
150
+ *
151
+ * Otherwise resolves the per-publication {@link ExternalizationMetadata}
152
+ * from the registry and invokes the externalizer. Any rejection is
153
+ * wrapped in {@link ExternalizationError} and re-thrown so the outer
154
+ * try / catch in `processOne` records the publication as `FAILED`,
155
+ * which preserves the single-unit atomicity contract from DD-019.
156
+ */
157
+ async tryExternalize(event, publication) {
158
+ if (this.externalizer === undefined || this.externalizationRegistry === undefined) {
159
+ return;
160
+ }
161
+ const metadata = this.externalizationRegistry.buildMetadata(publication.eventType, event);
162
+ if (metadata === undefined) {
163
+ return;
164
+ }
165
+ try {
166
+ await this.externalizer.externalize(event, metadata);
167
+ this.logger.debug(`Externalized ${publication.eventType} → ${metadata.target}`);
168
+ }
169
+ catch (err) {
170
+ const cause = err instanceof Error ? err : undefined;
171
+ const message = err instanceof Error ? err.message : String(err);
172
+ throw new errors_1.ExternalizationError(`Externalization failed for ${publication.eventType}: ${message}`, publication.eventType, metadata.target, cause);
173
+ }
174
+ }
175
+ chunk(arr, size) {
176
+ const chunks = [];
177
+ for (let i = 0; i < arr.length; i += size) {
178
+ chunks.push(arr.slice(i, i + size));
179
+ }
180
+ return chunks;
181
+ }
182
+ };
183
+ exports.EventPublicationProcessor = EventPublicationProcessor;
184
+ exports.EventPublicationProcessor = EventPublicationProcessor = EventPublicationProcessor_1 = __decorate([
185
+ (0, common_1.Injectable)(),
186
+ __param(3, (0, common_1.Optional)()),
187
+ __param(3, (0, common_1.Inject)(event_externalizer_1.EVENT_EXTERNALIZER)),
188
+ __param(4, (0, common_1.Optional)()),
189
+ __metadata("design:paramtypes", [event_publication_registry_1.EventPublicationRegistry,
190
+ listener_registry_1.OutboxListenerRegistry, Object, Object, externalization_registry_1.ExternalizationRegistry])
191
+ ], EventPublicationProcessor);
192
+ //# sourceMappingURL=event-publication-processor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-publication-processor.js","sourceRoot":"","sources":["../../src/dispatcher/event-publication-processor.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2CAAsE;AAEtE,sDAAiE;AACjE,8EAG+C;AAC/C,0FAAsF;AACtF,uFAAkF;AAClF,qEAAuE;AAKvE;;;;;;;;;;;;;;;;;GAiBG;AAEI,IAAM,yBAAyB,iCAA/B,MAAM,yBAAyB;IAMjB;IACA;IACA;IAGA;IAEA;IAZF,MAAM,GAAG,IAAI,eAAM,CAAC,2BAAyB,CAAC,IAAI,CAAC,CAAC;IAC7D,OAAO,GAAG,KAAK,CAAC;IAChB,cAAc,GAA0B,IAAI,CAAC;IAErD,YACmB,QAAkC,EAClC,gBAAwC,EACxC,OAAyC,EAGzC,YAAgC,EAEhC,uBAAiD;QAPjD,aAAQ,GAAR,QAAQ,CAA0B;QAClC,qBAAgB,GAAhB,gBAAgB,CAAwB;QACxC,YAAO,GAAP,OAAO,CAAkC;QAGzC,iBAAY,GAAZ,YAAY,CAAoB;QAEhC,4BAAuB,GAAvB,uBAAuB,CAA0B;IACjE,CAAC;IAEJ,mDAAmD;IACnD,KAAK;QACH,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,OAAO;QACT,CAAC;QACD,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,IAAI,CAAC,YAAY,EAAE,CAAC;QACpB,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAC;IACvD,CAAC;IAED,mEAAmE;IACnE,IAAI;QACF,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;QACrB,IAAI,IAAI,CAAC,cAAc,KAAK,IAAI,EAAE,CAAC;YACjC,YAAY,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;YAClC,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC;QAC7B,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAC;IACvD,CAAC;IAED;;;;;;;OAOG;IACH,KAAK,CAAC,YAAY;QAChB,IAAI,CAAC;YACH,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,sBAAsB,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;YACxF,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC9B,OAAO;YACT,CAAC;YAED,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,uBAAuB,YAAY,CAAC,MAAM,eAAe,CAAC,CAAC;YAE7E,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,EAAE,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;YACpE,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;gBAC3B,MAAM,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YAC9D,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,MAAM,CAAC,KAAK,CACf,yBAAyB,EACzB,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAC/C,CAAC;QACJ,CAAC;IACH,CAAC;IAEO,YAAY;QAClB,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YAClB,OAAO;QACT,CAAC;QACD,IAAI,CAAC,cAAc,GAAG,UAAU,CAAC,GAAG,EAAE;YACpC,KAAK,IAAI,CAAC,YAAY,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC;QAC9D,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;IACnC,CAAC;IAEO,KAAK,CAAC,UAAU,CAAC,WAA6B;QACpD,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;YAC7D,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,OAAO;YACT,CAAC;YAED,MAAM,QAAQ,GAAG,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;YACvE,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;gBAC3B,MAAM,IAAI,CAAC,QAAQ,CAAC,UAAU,CAC5B,WAAW,CAAC,EAAE,EACd,aAAa,WAAW,CAAC,UAAU,qBAAqB,CACzD,CAAC;gBACF,IAAI,CAAC,MAAM,CAAC,IAAI,CACd,aAAa,WAAW,CAAC,UAAU,+BAA+B,WAAW,CAAC,EAAE,EAAE,CACnF,CAAC;gBACF,OAAO;YACT,CAAC;YAED,IAAI,CAAC;gBACH,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC;gBACrD,4DAA4D;gBAC5D,wDAAwD;gBACxD,MAAM,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;gBAC7B,wDAAwD;gBACxD,+DAA+D;gBAC/D,wCAAwC;gBACxC,MAAM,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;gBAC9C,MAAM,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,WAAW,CAAC,EAAE,EAAE,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;YACjF,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,MAAM,MAAM,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBAChE,MAAM,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;gBACvD,IAAI,CAAC,MAAM,CAAC,KAAK,CACf,aAAa,WAAW,CAAC,UAAU,4BAA4B,WAAW,CAAC,EAAE,KAAK,MAAM,EAAE,EAC1F,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAC7C,CAAC;YACJ,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,MAAM,CAAC,KAAK,CACf,gCAAgC,WAAW,CAAC,EAAE,EAAE,EAChD,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAC/C,CAAC;QACJ,CAAC;IACH,CAAC;IAED;;;;;;;;;;;;;;;;OAgBG;IACK,KAAK,CAAC,cAAc,CAC1B,KAAc,EACd,WAA6B;QAE7B,IAAI,IAAI,CAAC,YAAY,KAAK,SAAS,IAAI,IAAI,CAAC,uBAAuB,KAAK,SAAS,EAAE,CAAC;YAClF,OAAO;QACT,CAAC;QAED,MAAM,QAAQ,GAAG,IAAI,CAAC,uBAAuB,CAAC,aAAa,CACzD,WAAW,CAAC,SAAS,EACrB,KAAK,CACN,CAAC;QACF,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YAC3B,OAAO;QACT,CAAC;QAED,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;YACrD,IAAI,CAAC,MAAM,CAAC,KAAK,CACf,gBAAgB,WAAW,CAAC,SAAS,MAAM,QAAQ,CAAC,MAAM,EAAE,CAC7D,CAAC;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,KAAK,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC;YACrD,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACjE,MAAM,IAAI,6BAAoB,CAC5B,8BAA8B,WAAW,CAAC,SAAS,KAAK,OAAO,EAAE,EACjE,WAAW,CAAC,SAAS,EACrB,QAAQ,CAAC,MAAM,EACf,KAAK,CACN,CAAC;QACJ,CAAC;IACH,CAAC;IAEO,KAAK,CAAI,GAAQ,EAAE,IAAY;QACrC,MAAM,MAAM,GAAU,EAAE,CAAC;QACzB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC;YAC1C,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;QACtC,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;CACF,CAAA;AAhLY,8DAAyB;oCAAzB,yBAAyB;IADrC,IAAA,mBAAU,GAAE;IAUR,WAAA,IAAA,iBAAQ,GAAE,CAAA;IACV,WAAA,IAAA,eAAM,EAAC,uCAAkB,CAAC,CAAA;IAE1B,WAAA,IAAA,iBAAQ,GAAE,CAAA;qCANgB,qDAAwB;QAChB,0CAAsB,kBAMd,kDAAuB;GAbzD,yBAAyB,CAgLrC"}
@@ -0,0 +1,129 @@
1
+ import { type OnModuleInit } from '@nestjs/common';
2
+ import { ModuleRef } from '@nestjs/core';
3
+ /**
4
+ * Optional override accepted by the facade `OutboxEventPublisher`'s
5
+ * publish methods to target a specific dataSource explicitly.
6
+ *
7
+ * When omitted, the facade routes by event-type registration: the
8
+ * event class is looked up in each per-dataSource
9
+ * {@link EventTypeRegistry}, and the dataSource that registered it
10
+ * owns the publication.
11
+ */
12
+ export interface OutboxPublishOptions {
13
+ /**
14
+ * Public dataSource name to publish to. Always wins over event-type
15
+ * routing when set. Useful for events that are registered in
16
+ * multiple dataSources, or for explicit cross-dataSource routing.
17
+ */
18
+ readonly dataSource?: string;
19
+ }
20
+ /**
21
+ * High-level smart-facade publisher (DD-024). The single user-facing
22
+ * publisher class — application code injects `OutboxEventPublisher`
23
+ * and the facade routes publications to the per-dataSource
24
+ * {@link DataSourceOutboxPublisher} that owns the event class.
25
+ *
26
+ * **Routing algorithm** (in order):
27
+ * 1. If `options.dataSource` is provided, route to that dataSource.
28
+ * 2. Else, look up `event.constructor.name` in each registered
29
+ * per-dataSource {@link EventTypeRegistry}; the registry that
30
+ * contains the event determines the destination.
31
+ * 3. If no registry contains the event, throw {@link OutboxError}.
32
+ *
33
+ * **Cross-dataSource publishing** is allowed: the routing decision is
34
+ * about the event's *registered* dataSource, NOT about which
35
+ * transactions are currently active. With Phase 14.2's cross-DS
36
+ * simultaneous transactions, a billing event published from inside an
37
+ * outer-billing / inner-inventory async stack still routes to billing
38
+ * (because that's where the event class is registered) and validates
39
+ * its atomicity against the billing transaction.
40
+ *
41
+ * **Single-dataSource deployments** see no behavioural change: there
42
+ * is one per-DS publisher (named `'default'`), one event-type
43
+ * registry, and the facade transparently delegates to it.
44
+ *
45
+ * Replaces the pre-Phase-14.3 publisher whose internal
46
+ * `findCurrentTransaction()` returned an arbitrary first-active
47
+ * transaction — non-deterministic with multiple active transactions.
48
+ * No backwards-compatibility shim: callers always inject
49
+ * `OutboxEventPublisher` and receive routing semantics consistent
50
+ * with the registered event-type ownership.
51
+ */
52
+ /** @internal — DI token carrying the live Map of registered dataSources. */
53
+ export declare const OUTBOX_DATA_SOURCE_NAMES: unique symbol;
54
+ /** @internal — Read-only view of the shared registration list. */
55
+ export type OutboxDataSourceNames = ReadonlySet<string> | {
56
+ keys(): IterableIterator<string>;
57
+ };
58
+ export declare class OutboxEventPublisher implements OnModuleInit {
59
+ private readonly moduleRef;
60
+ /**
61
+ * Live reference to {@link OutboxModule.registrations} (passed via
62
+ * `useValue` so its `keys()` enumeration sees every dataSource
63
+ * registered across all `forRoot` calls — `useValue` captures the
64
+ * Map by reference, so later forRoot pushes are visible at
65
+ * `OnModuleInit` time).
66
+ */
67
+ private readonly dataSourceNames;
68
+ private readonly logger;
69
+ private readonly publishers;
70
+ private readonly eventTypeRegistries;
71
+ constructor(moduleRef: ModuleRef,
72
+ /**
73
+ * Live reference to {@link OutboxModule.registrations} (passed via
74
+ * `useValue` so its `keys()` enumeration sees every dataSource
75
+ * registered across all `forRoot` calls — `useValue` captures the
76
+ * Map by reference, so later forRoot pushes are visible at
77
+ * `OnModuleInit` time).
78
+ */
79
+ dataSourceNames: OutboxDataSourceNames);
80
+ /**
81
+ * Late-bind per-DS publishers and event-type registries via
82
+ * `ModuleRef`. Lifecycle hook chosen because it fires AFTER every
83
+ * provider has been instantiated — by then every per-DS publisher
84
+ * exists and is resolvable, regardless of the order in which the
85
+ * facade's `forRoot` and per-DS `forRoot`s appear in the import
86
+ * tree.
87
+ */
88
+ onModuleInit(): void;
89
+ /**
90
+ * Publish a single event. Routing per the class JSDoc:
91
+ * `options.dataSource` (explicit) > event-type registration
92
+ * (implicit) > {@link OutboxError}.
93
+ *
94
+ * Must be called inside an active transaction *for the resolved
95
+ * dataSource* — `DataSourceOutboxPublisher.publish` enforces this
96
+ * with a clear error message naming the dataSource.
97
+ */
98
+ publish(event: unknown, options?: OutboxPublishOptions): Promise<void>;
99
+ /**
100
+ * Publish a batch of events. Each event is routed independently, so
101
+ * a mixed-dataSource batch (e.g. one billing event and one
102
+ * inventory event in the same call) routes each to its own
103
+ * dataSource publisher.
104
+ */
105
+ publishAll(events: readonly unknown[], options?: OutboxPublishOptions): Promise<void>;
106
+ /**
107
+ * Synchronous scheduling sibling of {@link publish}. Designed for
108
+ * sync callers such as `@nestjs/cqrs`'s `AggregateRoot.commit()`
109
+ * pathway. Same routing rules apply.
110
+ *
111
+ * Inside the resolved dataSource's active transaction: events are
112
+ * buffered and flushed in a `beforeCommit` hook
113
+ * (see {@link DataSourceOutboxPublisher.scheduleForPublication}).
114
+ * Outside any transaction: fire-and-forget {@link publish}, errors
115
+ * logged because there is no caller to propagate to.
116
+ *
117
+ * If the event cannot be routed (no matching registration), the
118
+ * call is logged-and-dropped — sync paths cannot raise.
119
+ */
120
+ scheduleForPublication(event: unknown, options?: OutboxPublishOptions): void;
121
+ /**
122
+ * Read-only snapshot of the dataSources this facade routes to.
123
+ * Useful for diagnostics and tests.
124
+ */
125
+ getRegisteredDataSources(): readonly string[];
126
+ private resolveDataSource;
127
+ private requirePublisher;
128
+ }
129
+ //# sourceMappingURL=outbox-event-publisher.d.ts.map
@@ -0,0 +1,172 @@
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 OutboxEventPublisher_1;
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.OutboxEventPublisher = exports.OUTBOX_DATA_SOURCE_NAMES = void 0;
17
+ const common_1 = require("@nestjs/common");
18
+ const core_1 = require("@nestjs/core");
19
+ const event_type_resolver_1 = require("../serialization/event-type-resolver");
20
+ const token_utils_1 = require("../tokens/token-utils");
21
+ const errors_1 = require("../types/errors");
22
+ /**
23
+ * High-level smart-facade publisher (DD-024). The single user-facing
24
+ * publisher class — application code injects `OutboxEventPublisher`
25
+ * and the facade routes publications to the per-dataSource
26
+ * {@link DataSourceOutboxPublisher} that owns the event class.
27
+ *
28
+ * **Routing algorithm** (in order):
29
+ * 1. If `options.dataSource` is provided, route to that dataSource.
30
+ * 2. Else, look up `event.constructor.name` in each registered
31
+ * per-dataSource {@link EventTypeRegistry}; the registry that
32
+ * contains the event determines the destination.
33
+ * 3. If no registry contains the event, throw {@link OutboxError}.
34
+ *
35
+ * **Cross-dataSource publishing** is allowed: the routing decision is
36
+ * about the event's *registered* dataSource, NOT about which
37
+ * transactions are currently active. With Phase 14.2's cross-DS
38
+ * simultaneous transactions, a billing event published from inside an
39
+ * outer-billing / inner-inventory async stack still routes to billing
40
+ * (because that's where the event class is registered) and validates
41
+ * its atomicity against the billing transaction.
42
+ *
43
+ * **Single-dataSource deployments** see no behavioural change: there
44
+ * is one per-DS publisher (named `'default'`), one event-type
45
+ * registry, and the facade transparently delegates to it.
46
+ *
47
+ * Replaces the pre-Phase-14.3 publisher whose internal
48
+ * `findCurrentTransaction()` returned an arbitrary first-active
49
+ * transaction — non-deterministic with multiple active transactions.
50
+ * No backwards-compatibility shim: callers always inject
51
+ * `OutboxEventPublisher` and receive routing semantics consistent
52
+ * with the registered event-type ownership.
53
+ */
54
+ /** @internal — DI token carrying the live Map of registered dataSources. */
55
+ exports.OUTBOX_DATA_SOURCE_NAMES = Symbol('OUTBOX_DATA_SOURCE_NAMES');
56
+ let OutboxEventPublisher = OutboxEventPublisher_1 = class OutboxEventPublisher {
57
+ moduleRef;
58
+ dataSourceNames;
59
+ logger = new common_1.Logger(OutboxEventPublisher_1.name);
60
+ publishers = new Map();
61
+ eventTypeRegistries = new Map();
62
+ constructor(moduleRef, dataSourceNames) {
63
+ this.moduleRef = moduleRef;
64
+ this.dataSourceNames = dataSourceNames;
65
+ }
66
+ /**
67
+ * Late-bind per-DS publishers and event-type registries via
68
+ * `ModuleRef`. Lifecycle hook chosen because it fires AFTER every
69
+ * provider has been instantiated — by then every per-DS publisher
70
+ * exists and is resolvable, regardless of the order in which the
71
+ * facade's `forRoot` and per-DS `forRoot`s appear in the import
72
+ * tree.
73
+ */
74
+ onModuleInit() {
75
+ for (const ds of this.dataSourceNames.keys()) {
76
+ this.publishers.set(ds, this.moduleRef.get((0, token_utils_1.getOutboxPublisherToken)(ds), {
77
+ strict: false,
78
+ }));
79
+ this.eventTypeRegistries.set(ds, this.moduleRef.get((0, token_utils_1.getEventTypeRegistryToken)(ds), {
80
+ strict: false,
81
+ }));
82
+ }
83
+ }
84
+ /**
85
+ * Publish a single event. Routing per the class JSDoc:
86
+ * `options.dataSource` (explicit) > event-type registration
87
+ * (implicit) > {@link OutboxError}.
88
+ *
89
+ * Must be called inside an active transaction *for the resolved
90
+ * dataSource* — `DataSourceOutboxPublisher.publish` enforces this
91
+ * with a clear error message naming the dataSource.
92
+ */
93
+ async publish(event, options = {}) {
94
+ const dataSource = this.resolveDataSource(event, options);
95
+ const publisher = this.requirePublisher(dataSource);
96
+ await publisher.publish(event);
97
+ }
98
+ /**
99
+ * Publish a batch of events. Each event is routed independently, so
100
+ * a mixed-dataSource batch (e.g. one billing event and one
101
+ * inventory event in the same call) routes each to its own
102
+ * dataSource publisher.
103
+ */
104
+ async publishAll(events, options = {}) {
105
+ for (const event of events) {
106
+ await this.publish(event, options);
107
+ }
108
+ }
109
+ /**
110
+ * Synchronous scheduling sibling of {@link publish}. Designed for
111
+ * sync callers such as `@nestjs/cqrs`'s `AggregateRoot.commit()`
112
+ * pathway. Same routing rules apply.
113
+ *
114
+ * Inside the resolved dataSource's active transaction: events are
115
+ * buffered and flushed in a `beforeCommit` hook
116
+ * (see {@link DataSourceOutboxPublisher.scheduleForPublication}).
117
+ * Outside any transaction: fire-and-forget {@link publish}, errors
118
+ * logged because there is no caller to propagate to.
119
+ *
120
+ * If the event cannot be routed (no matching registration), the
121
+ * call is logged-and-dropped — sync paths cannot raise.
122
+ */
123
+ scheduleForPublication(event, options = {}) {
124
+ let dataSource;
125
+ try {
126
+ dataSource = this.resolveDataSource(event, options);
127
+ }
128
+ catch (err) {
129
+ this.logger.error(`scheduleForPublication: ${err instanceof Error ? err.message : String(err)}`);
130
+ return;
131
+ }
132
+ const publisher = this.publishers.get(dataSource);
133
+ if (publisher === undefined) {
134
+ this.logger.error(`scheduleForPublication: no outbox publisher registered for dataSource '${dataSource}'`);
135
+ return;
136
+ }
137
+ publisher.scheduleForPublication(event);
138
+ }
139
+ /**
140
+ * Read-only snapshot of the dataSources this facade routes to.
141
+ * Useful for diagnostics and tests.
142
+ */
143
+ getRegisteredDataSources() {
144
+ return Array.from(this.publishers.keys());
145
+ }
146
+ resolveDataSource(event, options) {
147
+ if (options.dataSource !== undefined) {
148
+ return options.dataSource;
149
+ }
150
+ // Phase 14.3.1 — same helper used by `OutboxListenerScanner` and
151
+ // `MultiDsOutboxListenerRegistrar` so the routing policy (one
152
+ // owning DS per event class, throw on 0 or many matches) stays
153
+ // consistent across publish and listener-registration paths.
154
+ const eventType = event.constructor.name;
155
+ return (0, event_type_resolver_1.resolveDataSourceByEventTypeName)(eventType, this.eventTypeRegistries);
156
+ }
157
+ requirePublisher(dataSource) {
158
+ const publisher = this.publishers.get(dataSource);
159
+ if (publisher === undefined) {
160
+ throw new errors_1.OutboxError(`No outbox configured for dataSource '${dataSource}'. ` +
161
+ `Add 'OutboxModule.forRoot({ dataSource: '${dataSource}' })' to the module imports.`);
162
+ }
163
+ return publisher;
164
+ }
165
+ };
166
+ exports.OutboxEventPublisher = OutboxEventPublisher;
167
+ exports.OutboxEventPublisher = OutboxEventPublisher = OutboxEventPublisher_1 = __decorate([
168
+ (0, common_1.Injectable)(),
169
+ __param(1, (0, common_1.Inject)(exports.OUTBOX_DATA_SOURCE_NAMES)),
170
+ __metadata("design:paramtypes", [core_1.ModuleRef, Object])
171
+ ], OutboxEventPublisher);
172
+ //# sourceMappingURL=outbox-event-publisher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"outbox-event-publisher.js","sourceRoot":"","sources":["../../src/dispatcher/outbox-event-publisher.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import { CompletionMode } from '../types/completion-mode';
2
+ /**
3
+ * Tunables for the {@link EventPublicationProcessor} polling loop.
4
+ *
5
+ * Values are enforced at injection time — provide a fully-populated
6
+ * object (merge with {@link DEFAULT_PROCESSOR_OPTIONS} if you only
7
+ * want to override a subset).
8
+ */
9
+ export interface EventPublicationProcessorOptions {
10
+ /** Milliseconds to wait between polling cycles. */
11
+ readonly pollingInterval: number;
12
+ /** Maximum publications fetched per poll. */
13
+ readonly batchSize: number;
14
+ /** Maximum listener invocations that may run in parallel inside one batch. */
15
+ readonly maxConcurrent: number;
16
+ /** How a successfully-delivered publication is finalized. */
17
+ readonly completionMode: CompletionMode;
18
+ }
19
+ /**
20
+ * Reasonable defaults for local development — a 1-second poll, 100 rows
21
+ * per batch, 10 parallel listener invocations, and `UPDATE` completion.
22
+ */
23
+ export declare const DEFAULT_PROCESSOR_OPTIONS: EventPublicationProcessorOptions;
24
+ //# sourceMappingURL=processor-options.d.ts.map
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DEFAULT_PROCESSOR_OPTIONS = void 0;
4
+ const completion_mode_1 = require("../types/completion-mode");
5
+ /**
6
+ * Reasonable defaults for local development — a 1-second poll, 100 rows
7
+ * per batch, 10 parallel listener invocations, and `UPDATE` completion.
8
+ */
9
+ exports.DEFAULT_PROCESSOR_OPTIONS = {
10
+ pollingInterval: 1000,
11
+ batchSize: 100,
12
+ maxConcurrent: 10,
13
+ completionMode: completion_mode_1.CompletionMode.UPDATE,
14
+ };
15
+ //# sourceMappingURL=processor-options.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"processor-options.js","sourceRoot":"","sources":["../../src/dispatcher/processor-options.ts"],"names":[],"mappings":";;;AAAA,8DAA0D;AAoB1D;;;GAGG;AACU,QAAA,yBAAyB,GAAqC;IACzE,eAAe,EAAE,IAAI;IACrB,SAAS,EAAE,GAAG;IACd,aAAa,EAAE,EAAE;IACjB,cAAc,EAAE,gCAAc,CAAC,MAAM;CACtC,CAAC"}
@@ -0,0 +1,21 @@
1
+ import { OutboxError } from '../types/errors';
2
+ /**
3
+ * Raised when an {@link EventExternalizer} fails to deliver a
4
+ * publication to its external broker target. Carries diagnostic
5
+ * context (event type, broker target, optional underlying cause) so
6
+ * operators can correlate a `FAILED` publication row with the broker
7
+ * issue without parsing free-form messages.
8
+ *
9
+ * Implementations are encouraged to wrap transport-specific failures
10
+ * in this error, but the `EventPublicationProcessor` does not
11
+ * require it — any rejection from `externalize()` is recorded on the
12
+ * publication.
13
+ */
14
+ export declare class ExternalizationError extends OutboxError {
15
+ readonly eventType: string;
16
+ readonly target: string;
17
+ readonly cause?: Error | undefined;
18
+ readonly code = "EXTERNALIZATION_ERROR";
19
+ constructor(message: string, eventType: string, target: string, cause?: Error | undefined);
20
+ }
21
+ //# sourceMappingURL=errors.d.ts.map