@nestjs-transactional/core 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 (75) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +265 -0
  3. package/dist/bootstrap/transactional-methods.bootstrap.d.ts +42 -0
  4. package/dist/bootstrap/transactional-methods.bootstrap.js +129 -0
  5. package/dist/bootstrap/transactional-methods.bootstrap.js.map +1 -0
  6. package/dist/context/transaction-context-view.d.ts +38 -0
  7. package/dist/context/transaction-context-view.js +48 -0
  8. package/dist/context/transaction-context-view.js.map +1 -0
  9. package/dist/context/transaction.context.d.ts +114 -0
  10. package/dist/context/transaction.context.js +112 -0
  11. package/dist/context/transaction.context.js.map +1 -0
  12. package/dist/decorators/inject-decorators.d.ts +36 -0
  13. package/dist/decorators/inject-decorators.js +45 -0
  14. package/dist/decorators/inject-decorators.js.map +1 -0
  15. package/dist/decorators/transactional.decorator.d.ts +64 -0
  16. package/dist/decorators/transactional.decorator.js +82 -0
  17. package/dist/decorators/transactional.decorator.js.map +1 -0
  18. package/dist/index.d.ts +19 -0
  19. package/dist/index.js +35 -0
  20. package/dist/index.js.map +1 -0
  21. package/dist/interceptor/transactional.interceptor.d.ts +28 -0
  22. package/dist/interceptor/transactional.interceptor.js +56 -0
  23. package/dist/interceptor/transactional.interceptor.js.map +1 -0
  24. package/dist/internal/markers.d.ts +15 -0
  25. package/dist/internal/markers.js +18 -0
  26. package/dist/internal/markers.js.map +1 -0
  27. package/dist/manager/adapter.registry.d.ts +103 -0
  28. package/dist/manager/adapter.registry.js +179 -0
  29. package/dist/manager/adapter.registry.js.map +1 -0
  30. package/dist/manager/transaction.manager.d.ts +129 -0
  31. package/dist/manager/transaction.manager.js +412 -0
  32. package/dist/manager/transaction.manager.js.map +1 -0
  33. package/dist/module/transactional.module.d.ts +242 -0
  34. package/dist/module/transactional.module.js +374 -0
  35. package/dist/module/transactional.module.js.map +1 -0
  36. package/dist/observability/transaction-observer.d.ts +78 -0
  37. package/dist/observability/transaction-observer.js +18 -0
  38. package/dist/observability/transaction-observer.js.map +1 -0
  39. package/dist/testing/in-memory.adapter.d.ts +66 -0
  40. package/dist/testing/in-memory.adapter.js +83 -0
  41. package/dist/testing/in-memory.adapter.js.map +1 -0
  42. package/dist/testing/index.d.ts +2 -0
  43. package/dist/testing/index.js +18 -0
  44. package/dist/testing/index.js.map +1 -0
  45. package/dist/tokens/constants.d.ts +14 -0
  46. package/dist/tokens/constants.js +17 -0
  47. package/dist/tokens/constants.js.map +1 -0
  48. package/dist/tokens/index.d.ts +3 -0
  49. package/dist/tokens/index.js +11 -0
  50. package/dist/tokens/index.js.map +1 -0
  51. package/dist/tokens/token-utils.d.ts +52 -0
  52. package/dist/tokens/token-utils.js +67 -0
  53. package/dist/tokens/token-utils.js.map +1 -0
  54. package/dist/types/domain-event.d.ts +18 -0
  55. package/dist/types/domain-event.js +3 -0
  56. package/dist/types/domain-event.js.map +1 -0
  57. package/dist/types/errors.d.ts +50 -0
  58. package/dist/types/errors.js +61 -0
  59. package/dist/types/errors.js.map +1 -0
  60. package/dist/types/isolation.d.ts +11 -0
  61. package/dist/types/isolation.js +3 -0
  62. package/dist/types/isolation.js.map +1 -0
  63. package/dist/types/propagation.d.ts +63 -0
  64. package/dist/types/propagation.js +67 -0
  65. package/dist/types/propagation.js.map +1 -0
  66. package/dist/types/transaction-adapter.d.ts +72 -0
  67. package/dist/types/transaction-adapter.js +3 -0
  68. package/dist/types/transaction-adapter.js.map +1 -0
  69. package/dist/types/transaction-handle.d.ts +23 -0
  70. package/dist/types/transaction-handle.js +3 -0
  71. package/dist/types/transaction-handle.js.map +1 -0
  72. package/dist/types/transaction-options.d.ts +88 -0
  73. package/dist/types/transaction-options.js +3 -0
  74. package/dist/types/transaction-options.js.map +1 -0
  75. package/package.json +74 -0
@@ -0,0 +1,412 @@
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 TransactionManager_1;
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.TransactionManager = void 0;
17
+ const node_crypto_1 = require("node:crypto");
18
+ const common_1 = require("@nestjs/common");
19
+ const transaction_context_1 = require("../context/transaction.context");
20
+ const transaction_observer_1 = require("../observability/transaction-observer");
21
+ const errors_1 = require("../types/errors");
22
+ const propagation_1 = require("../types/propagation");
23
+ const adapter_registry_1 = require("./adapter.registry");
24
+ /**
25
+ * Runtime that executes a callback inside a transaction, following the
26
+ * requested {@link PropagationMode}. Exposes registration points for
27
+ * before/after-commit and after-rollback hooks that the surrounding
28
+ * transaction fires at the appropriate phase.
29
+ *
30
+ * All seven Spring-compatible propagation modes are supported:
31
+ * `REQUIRED`, `REQUIRES_NEW`, `NESTED`, `SUPPORTS`, `NOT_SUPPORTED`,
32
+ * `NEVER`, `MANDATORY`. See {@link TransactionManager.run} for the
33
+ * per-mode behaviour.
34
+ */
35
+ let TransactionManager = TransactionManager_1 = class TransactionManager {
36
+ registry;
37
+ observers;
38
+ logger = new common_1.Logger(TransactionManager_1.name);
39
+ constructor(registry, observers = []) {
40
+ this.registry = registry;
41
+ this.observers = observers;
42
+ }
43
+ /**
44
+ * Execute `fn` inside a transaction managed by the adapter resolved from
45
+ * `options` (or defaults from {@link AdapterRegistry}).
46
+ *
47
+ * Behaviour by propagation mode:
48
+ * - `REQUIRED` (default): join the active transaction for this adapter
49
+ * instance if one exists; otherwise start a new transaction.
50
+ * - `REQUIRES_NEW`: always start a new, independent transaction. If an
51
+ * outer transaction is active, its {@link ActiveTransaction} entry is
52
+ * suspended out of the context Map for the duration of the inner call
53
+ * and restored afterwards.
54
+ * - `NESTED`: if an outer transaction is active, run inside a savepoint
55
+ * on that transaction (via {@link TransactionAdapter.runInSavepoint}).
56
+ * A savepoint rollback leaves the outer transaction intact. Lifecycle
57
+ * hooks registered inside a `NESTED` block attach to the outer
58
+ * transaction and fire on the outer commit/rollback. If no outer
59
+ * transaction is active, `NESTED` degrades to `REQUIRED`.
60
+ * - `SUPPORTS`: run `fn` in the outer transaction if present; otherwise
61
+ * run `fn` directly with no transaction and no lifecycle hooks.
62
+ * - `NOT_SUPPORTED`: suspend the outer transaction (remove its entry
63
+ * from the context Map) and run `fn` without transactional context.
64
+ * Restore on return. Note that the adapter-level connection/query
65
+ * runner is NOT actually suspended — this is a context-level opt-out.
66
+ * - `NEVER`: throw {@link IllegalTransactionStateError} if an outer
67
+ * transaction is active; otherwise run `fn` directly.
68
+ * - `MANDATORY`: throw {@link IllegalTransactionStateError} if no outer
69
+ * transaction is active; otherwise join it.
70
+ *
71
+ * Both inner and outer transactions share the surrounding
72
+ * {@link TransactionContext} store — same `correlationId`, same Map —
73
+ * only the Map slot at `instanceName` is swapped as propagation requires.
74
+ */
75
+ async run(options, fn) {
76
+ // dataSource takes precedence over adapter/adapterInstance (DD-020).
77
+ // Resolved up front so the rest of run() works in a single shape.
78
+ const { adapterName, instanceName } = this.resolveAdapterIdentifiers(options);
79
+ const propagation = options.propagation ?? propagation_1.PropagationMode.REQUIRED;
80
+ const key = TransactionManager_1.contextKey(adapterName, instanceName);
81
+ const existing = transaction_context_1.TransactionContext.getActiveTransaction(key);
82
+ switch (propagation) {
83
+ case propagation_1.PropagationMode.REQUIRED: {
84
+ if (existing !== undefined) {
85
+ return fn();
86
+ }
87
+ const adapter = this.registry.get(adapterName, instanceName);
88
+ return this.startNew(adapter, adapterName, instanceName, options, fn);
89
+ }
90
+ case propagation_1.PropagationMode.REQUIRES_NEW: {
91
+ const adapter = this.registry.get(adapterName, instanceName);
92
+ if (existing === undefined) {
93
+ return this.startNew(adapter, adapterName, instanceName, options, fn);
94
+ }
95
+ transaction_context_1.TransactionContext.removeActiveTransaction(key);
96
+ try {
97
+ return await this.startNew(adapter, adapterName, instanceName, options, fn);
98
+ }
99
+ finally {
100
+ transaction_context_1.TransactionContext.setActiveTransaction(key, existing);
101
+ }
102
+ }
103
+ case propagation_1.PropagationMode.NESTED: {
104
+ const adapter = this.registry.get(adapterName, instanceName);
105
+ if (existing === undefined) {
106
+ return this.startNew(adapter, adapterName, instanceName, options, fn);
107
+ }
108
+ return this.runNestedSavepoint(adapter, existing, options, fn);
109
+ }
110
+ case propagation_1.PropagationMode.SUPPORTS: {
111
+ return fn();
112
+ }
113
+ case propagation_1.PropagationMode.NOT_SUPPORTED: {
114
+ if (existing === undefined) {
115
+ return fn();
116
+ }
117
+ transaction_context_1.TransactionContext.removeActiveTransaction(key);
118
+ try {
119
+ return await fn();
120
+ }
121
+ finally {
122
+ transaction_context_1.TransactionContext.setActiveTransaction(key, existing);
123
+ }
124
+ }
125
+ case propagation_1.PropagationMode.NEVER: {
126
+ if (existing !== undefined) {
127
+ throw new errors_1.IllegalTransactionStateError(`Propagation NEVER cannot be invoked inside an active transaction ` +
128
+ `(adapter: '${adapterName}', instance: '${instanceName}')`);
129
+ }
130
+ return fn();
131
+ }
132
+ case propagation_1.PropagationMode.MANDATORY: {
133
+ if (existing === undefined) {
134
+ throw new errors_1.IllegalTransactionStateError(`Propagation MANDATORY requires an active transaction, but none is ` +
135
+ `active (adapter: '${adapterName}', instance: '${instanceName}')`);
136
+ }
137
+ return fn();
138
+ }
139
+ }
140
+ }
141
+ /**
142
+ * Compose the {@link TransactionContext} key for a given adapter
143
+ * (type name) + instance pair. Manager and helper packages must agree
144
+ * on this format so that `@nestjs-transactional/typeorm`'s
145
+ * `getCurrentEntityManager` can find the transaction registered here.
146
+ */
147
+ static contextKey(adapterName, instanceName) {
148
+ return `${adapterName}:${instanceName}`;
149
+ }
150
+ /**
151
+ * Translate the user-facing options into the internal `(adapterName,
152
+ * instanceName)` pair used to build the active-transaction Map key.
153
+ *
154
+ * Resolution order (DD-020):
155
+ * 1. `options.dataSource` set: lookup the unique adapter via the
156
+ * registry by dataSource name. The dataSource name becomes the
157
+ * `instanceName`; the registry hands back the adapter type.
158
+ * 2. Else: legacy path — `options.adapter` / `options.adapterInstance`
159
+ * fall back to the registry's defaults.
160
+ */
161
+ resolveAdapterIdentifiers(options) {
162
+ if (options.dataSource !== undefined) {
163
+ return {
164
+ adapterName: this.registry.getAdapterNameByDataSource(options.dataSource),
165
+ instanceName: options.dataSource,
166
+ };
167
+ }
168
+ return {
169
+ adapterName: options.adapter ?? this.registry.getDefaultAdapterName(),
170
+ instanceName: options.adapterInstance ?? this.registry.getDefaultInstanceName(),
171
+ };
172
+ }
173
+ /**
174
+ * Register a hook to fire after the current transaction commits
175
+ * successfully. Attaches to the first active transaction on the current
176
+ * async context — sufficient for single-adapter setups. Hook errors are
177
+ * swallowed with a warning and do not reject `run()`.
178
+ *
179
+ * @throws {IllegalTransactionStateError} If called outside an active transaction.
180
+ */
181
+ registerAfterCommit(hook) {
182
+ this.currentTransaction().afterCommitHooks.push(hook);
183
+ }
184
+ /**
185
+ * Register a hook to fire after the current transaction rolls back. The
186
+ * hook receives the error that caused the rollback.
187
+ *
188
+ * @throws {IllegalTransactionStateError} If called outside an active transaction.
189
+ */
190
+ registerAfterRollback(hook) {
191
+ this.currentTransaction().afterRollbackHooks.push(hook);
192
+ }
193
+ /**
194
+ * Register a hook to fire just before the transaction commits. A throwing
195
+ * hook triggers the adapter's rollback — the transaction does not commit.
196
+ *
197
+ * @throws {IllegalTransactionStateError} If called outside an active transaction.
198
+ */
199
+ registerBeforeCommit(hook) {
200
+ this.currentTransaction().beforeCommitHooks.push(hook);
201
+ }
202
+ async startNew(adapter, adapterName, instanceName, options, fn) {
203
+ const outerStore = transaction_context_1.TransactionContext.getStore();
204
+ const correlationId = outerStore?.correlationId ?? (0, node_crypto_1.randomUUID)();
205
+ let activeTx;
206
+ const startTime = Date.now();
207
+ const key = TransactionManager_1.contextKey(adapterName, instanceName);
208
+ const body = async () => {
209
+ let result;
210
+ try {
211
+ result = await adapter.runInTransaction(options, async (handle) => {
212
+ activeTx = {
213
+ handle,
214
+ adapterName,
215
+ adapterInstanceName: instanceName,
216
+ options,
217
+ startedAt: new Date(),
218
+ afterCommitHooks: [],
219
+ afterRollbackHooks: [],
220
+ beforeCommitHooks: [],
221
+ correlationId,
222
+ };
223
+ transaction_context_1.TransactionContext.setActiveTransaction(key, activeTx);
224
+ this.notifyStart({
225
+ transactionId: handle.id,
226
+ adapterName,
227
+ adapterInstanceName: instanceName,
228
+ correlationId,
229
+ options,
230
+ });
231
+ try {
232
+ try {
233
+ const innerValue = await fn();
234
+ // Before-commit hooks run inside the adapter callback so
235
+ // that a throwing hook still triggers the adapter's
236
+ // rollback path.
237
+ for (const hook of activeTx.beforeCommitHooks) {
238
+ await hook();
239
+ }
240
+ return { ok: true, value: innerValue };
241
+ }
242
+ catch (err) {
243
+ if (this.shouldRollback(err, options)) {
244
+ throw err; // let the adapter roll back
245
+ }
246
+ // Commit despite the error — the manager will re-raise it
247
+ // to the caller after the adapter's commit succeeds.
248
+ return { ok: false, error: err };
249
+ }
250
+ }
251
+ finally {
252
+ transaction_context_1.TransactionContext.removeActiveTransaction(key);
253
+ }
254
+ });
255
+ }
256
+ catch (rollbackError) {
257
+ if (activeTx !== undefined) {
258
+ this.notifyRollback({
259
+ transactionId: activeTx.handle.id,
260
+ adapterName,
261
+ adapterInstanceName: instanceName,
262
+ correlationId,
263
+ options,
264
+ durationMs: Date.now() - startTime,
265
+ error: rollbackError,
266
+ rollbackCount: activeTx.afterRollbackHooks.length,
267
+ });
268
+ await this.runHooks(activeTx.afterRollbackHooks, rollbackError);
269
+ }
270
+ throw rollbackError;
271
+ }
272
+ // Adapter has committed. Fire the observer event and afterCommit
273
+ // hooks regardless of whether we are about to re-raise a business
274
+ // error — the database state is what the subscribers care about,
275
+ // and it has been persisted.
276
+ if (activeTx !== undefined) {
277
+ this.notifyCommit({
278
+ transactionId: activeTx.handle.id,
279
+ adapterName,
280
+ adapterInstanceName: instanceName,
281
+ correlationId,
282
+ options,
283
+ durationMs: Date.now() - startTime,
284
+ commitCount: activeTx.afterCommitHooks.length,
285
+ });
286
+ await this.runHooks(activeTx.afterCommitHooks);
287
+ }
288
+ if (result.ok) {
289
+ return result.value;
290
+ }
291
+ throw result.error;
292
+ };
293
+ if (outerStore === undefined) {
294
+ return transaction_context_1.TransactionContext.run(correlationId, body);
295
+ }
296
+ return body();
297
+ }
298
+ notifyStart(ctx) {
299
+ for (const observer of this.observers) {
300
+ try {
301
+ observer.onTransactionStart?.(ctx);
302
+ }
303
+ catch (err) {
304
+ this.logger.warn(`TransactionObserver.onTransactionStart failed: ${String(err)}`, err instanceof Error ? err.stack : undefined);
305
+ }
306
+ }
307
+ }
308
+ notifyCommit(ctx) {
309
+ for (const observer of this.observers) {
310
+ try {
311
+ observer.onTransactionCommit?.(ctx);
312
+ }
313
+ catch (err) {
314
+ this.logger.warn(`TransactionObserver.onTransactionCommit failed: ${String(err)}`, err instanceof Error ? err.stack : undefined);
315
+ }
316
+ }
317
+ }
318
+ notifyRollback(ctx) {
319
+ for (const observer of this.observers) {
320
+ try {
321
+ observer.onTransactionRollback?.(ctx);
322
+ }
323
+ catch (err) {
324
+ this.logger.warn(`TransactionObserver.onTransactionRollback failed: ${String(err)}`, err instanceof Error ? err.stack : undefined);
325
+ }
326
+ }
327
+ }
328
+ /**
329
+ * Run `fn` inside a savepoint on `parent.handle`. Used by
330
+ * {@link PropagationMode.NESTED} when there is an active outer transaction.
331
+ *
332
+ * The manager intentionally does NOT create a new
333
+ * {@link ActiveTransaction} for the savepoint — hook registrations inside
334
+ * `fn` fall through {@link currentTransaction} to the outer transaction,
335
+ * which is the Spring-style semantic: nested events "promote" to the
336
+ * enclosing transaction and fire when that transaction commits.
337
+ *
338
+ * Rollback semantics follow `shouldRollback`: errors that match the
339
+ * rollback rules cause the adapter to roll back to the savepoint (the
340
+ * outer transaction is unaffected); errors that do NOT match lead to a
341
+ * savepoint release (commit-inside-savepoint) and the error is re-raised
342
+ * to the caller after the release.
343
+ */
344
+ async runNestedSavepoint(adapter, parent, options, fn) {
345
+ const result = await adapter.runInSavepoint(parent.handle, async () => {
346
+ try {
347
+ const value = await fn();
348
+ return { ok: true, value };
349
+ }
350
+ catch (err) {
351
+ if (this.shouldRollback(err, options)) {
352
+ throw err; // adapter rolls back to savepoint
353
+ }
354
+ return { ok: false, error: err };
355
+ }
356
+ });
357
+ if (result.ok) {
358
+ return result.value;
359
+ }
360
+ throw result.error;
361
+ }
362
+ currentTransaction() {
363
+ const store = transaction_context_1.TransactionContext.getStore();
364
+ if (store === undefined) {
365
+ throw new errors_1.IllegalTransactionStateError('Cannot register a transactional hook outside of TransactionManager.run()');
366
+ }
367
+ for (const tx of store.activeTransactions.values()) {
368
+ return tx;
369
+ }
370
+ throw new errors_1.IllegalTransactionStateError('Cannot register a transactional hook: no active transaction on the current context');
371
+ }
372
+ /**
373
+ * Spring-style decision on whether a thrown error should trigger rollback:
374
+ *
375
+ * 1. If `noRollbackFor` is set and matches, commit anyway (precedence).
376
+ * 2. Else if `rollbackFor` is set, roll back only when the error matches
377
+ * an entry — a non-match commits (explicit allow-list semantics).
378
+ * 3. Else (no rules set), any error triggers rollback — the default
379
+ * transactional behaviour.
380
+ */
381
+ shouldRollback(error, options) {
382
+ const { noRollbackFor, rollbackFor } = options;
383
+ if (noRollbackFor !== undefined && noRollbackFor.length > 0) {
384
+ if (noRollbackFor.some((cls) => error instanceof cls)) {
385
+ return false;
386
+ }
387
+ }
388
+ if (rollbackFor !== undefined && rollbackFor.length > 0) {
389
+ return rollbackFor.some((cls) => error instanceof cls);
390
+ }
391
+ return true;
392
+ }
393
+ async runHooks(hooks, error) {
394
+ for (const hook of hooks) {
395
+ try {
396
+ await hook(error);
397
+ }
398
+ catch (hookError) {
399
+ this.logger.warn(`Transaction lifecycle hook failed: ${String(hookError)}`, hookError instanceof Error ? hookError.stack : undefined);
400
+ }
401
+ }
402
+ }
403
+ };
404
+ exports.TransactionManager = TransactionManager;
405
+ exports.TransactionManager = TransactionManager = TransactionManager_1 = __decorate([
406
+ (0, common_1.Injectable)(),
407
+ __param(0, (0, common_1.Inject)(adapter_registry_1.ADAPTER_REGISTRY)),
408
+ __param(1, (0, common_1.Optional)()),
409
+ __param(1, (0, common_1.Inject)(transaction_observer_1.TRANSACTION_OBSERVERS)),
410
+ __metadata("design:paramtypes", [adapter_registry_1.AdapterRegistry, Array])
411
+ ], TransactionManager);
412
+ //# sourceMappingURL=transaction.manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transaction.manager.js","sourceRoot":"","sources":["../../src/manager/transaction.manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,242 @@
1
+ import { type DynamicModule, type InjectionToken, type ModuleMetadata } from '@nestjs/common';
2
+ import { type TransactionObserver } from '../observability/transaction-observer';
3
+ import type { TransactionAdapter } from '../types/transaction-adapter';
4
+ /**
5
+ * Synchronous options for {@link TransactionalModule.forRoot}.
6
+ *
7
+ * Multi-dataSource deployments call `forRoot` once per dataSource:
8
+ *
9
+ * ```ts
10
+ * TransactionalModule.forRoot({ adapter: defaultAdapter }), // default
11
+ * TransactionalModule.forRoot({ adapter: billingAdapter }), // billing
12
+ * TransactionalModule.forRoot({ adapter: inventoryAdapter }), // inventory
13
+ * ```
14
+ *
15
+ * Matches NestJS conventions (`TypeOrmModule`, `MongooseModule`,
16
+ * `ClientsModule`) and aligns with `OutboxModule.forRoot` from
17
+ * Phase 14.3.2 (ADR-019). Cross-call coordination of singletons
18
+ * (`AdapterRegistry`, `TransactionManager`, `APP_INTERCEPTOR`,
19
+ * `TransactionalMethodsBootstrap`, `TRANSACTION_OBSERVERS`) lives in
20
+ * static class storage on {@link TransactionalModule}, mirroring
21
+ * `@nestjs/typeorm`'s `EntitiesMetadataStorage` pattern.
22
+ *
23
+ * The `infrastructure-only` shorthand `TransactionalModule.forRoot({})`
24
+ * (no adapter) is preserved for setups where the adapter is contributed
25
+ * by an integration package's `forFeature` (e.g.
26
+ * `TypeOrmTransactionalModule.forFeature` calls `AdapterRegistry.register`
27
+ * imperatively at module-init time).
28
+ *
29
+ * Q5 invariants on multi-call:
30
+ * - Two calls with the same `adapter.dataSourceName` throw at module-
31
+ * definition time.
32
+ * - Two `forRoot({})` calls (both infrastructure-only) — the second
33
+ * throws because infrastructure has already been registered.
34
+ * - `forRoot({})` then `forRoot({ adapter })` works.
35
+ * - `forRoot({ adapter A })` then `forRoot({ adapter B })` (different
36
+ * dataSource) works.
37
+ * - `forRoot({ adapter })` then `forRoot({})` throws (infrastructure
38
+ * already registered).
39
+ *
40
+ * Tests that build multiple modules sequentially MUST call
41
+ * {@link TransactionalModule.resetForTesting} in `beforeEach`.
42
+ */
43
+ export interface TransactionalModuleOptions {
44
+ /**
45
+ * Adapter instance to register. The adapter's `dataSourceName`
46
+ * keys this registration; duplicate dataSource names across
47
+ * `forRoot` calls throw. When omitted, this call only registers
48
+ * the process-wide infrastructure — adapters are then expected
49
+ * from an integration package (e.g.
50
+ * `TypeOrmTransactionalModule.forFeature`).
51
+ */
52
+ readonly adapter?: TransactionAdapter;
53
+ /**
54
+ * When `true` (default — Phase 14.10), the module is registered as
55
+ * `@Global()` — its exports are available app-wide without being
56
+ * re-imported. Honored per call (each `forRoot` builds its own
57
+ * `DynamicModule` with its own `global` flag). Multi-call setups
58
+ * effectively require `isGlobal: true` on at least the first call
59
+ * for `TransactionManager` and `AdapterRegistry` to be visible
60
+ * across sibling DynamicModules; the default flip aligns the API
61
+ * with `OutboxModule` (also default-global) and removes a
62
+ * common-case footgun.
63
+ */
64
+ readonly isGlobal?: boolean;
65
+ /**
66
+ * When `true` (default), the FIRST `forRoot` call registers
67
+ * {@link TransactionalInterceptor} as `APP_INTERCEPTOR`. Honored
68
+ * only on the first call — the value passed to subsequent calls is
69
+ * ignored (the interceptor is process-wide).
70
+ */
71
+ readonly registerInterceptor?: boolean;
72
+ /**
73
+ * When `true` (default), the FIRST `forRoot` call registers
74
+ * {@link TransactionalMethodsBootstrap} — an
75
+ * `OnApplicationBootstrap` service that wraps every `@Transactional()`
76
+ * method on plain `@Injectable()` providers with
77
+ * `TransactionManager.run(...)`. Honored only on the first call;
78
+ * subsequent calls' value is ignored.
79
+ */
80
+ readonly registerMethodsBootstrap?: boolean;
81
+ /**
82
+ * Transaction observers registered under {@link TRANSACTION_OBSERVERS}.
83
+ * Honored only on the FIRST `forRoot` call (Q2 invariant) — passing
84
+ * `observers` to a subsequent call throws at module-definition time.
85
+ * Provide your own `TRANSACTION_OBSERVERS` provider via standard DI
86
+ * if your observers need DI resolution.
87
+ */
88
+ readonly observers?: readonly TransactionObserver[];
89
+ }
90
+ /**
91
+ * Result shape resolved by {@link TransactionalModuleAsyncOptions.useFactory}.
92
+ *
93
+ * Per-DS DI tokens (`getTransactionalAdapterToken(ds)`,
94
+ * `getTransactionContextToken(ds)`,
95
+ * `getTransactionManagerToken(ds)`) are NOT registered for
96
+ * `forRootAsync` because the dataSource name is only known after the
97
+ * async factory runs, while NestJS provider tokens must be declared
98
+ * statically. If per-DS injection matters, use sync
99
+ * `forRoot({ adapter })` instead — build the adapter configuration
100
+ * through your own async logic before reaching the module imports.
101
+ */
102
+ export interface TransactionalModuleAsyncFactoryResult {
103
+ readonly adapter?: TransactionAdapter;
104
+ readonly observers?: readonly TransactionObserver[];
105
+ }
106
+ /**
107
+ * Asynchronous options for {@link TransactionalModule.forRootAsync}.
108
+ * Mirrors the multi-call pattern of `forRoot`: each call registers one
109
+ * dataSource's adapter (resolved asynchronously). See
110
+ * {@link TransactionalModuleAsyncFactoryResult} for the per-DS-token
111
+ * limitation.
112
+ */
113
+ export interface TransactionalModuleAsyncOptions extends Pick<ModuleMetadata, 'imports'> {
114
+ readonly isGlobal?: boolean;
115
+ readonly registerInterceptor?: boolean;
116
+ readonly registerMethodsBootstrap?: boolean;
117
+ readonly useFactory: (...args: never[]) => Promise<TransactionalModuleAsyncFactoryResult> | TransactionalModuleAsyncFactoryResult;
118
+ readonly inject?: readonly InjectionToken[];
119
+ }
120
+ /**
121
+ * NestJS module that wires the core transactional runtime:
122
+ * {@link AdapterRegistry}, {@link TransactionManager}, and (by
123
+ * default) the global {@link TransactionalInterceptor}. ADR-018
124
+ * shape — multi-dataSource deployments call {@link forRoot} once per
125
+ * dataSource. Static class storage coordinates singletons across
126
+ * calls (mirrors Phase 14.3.2 `OutboxModule` per ADR-019).
127
+ *
128
+ * The first call registers the process-wide infrastructure; subsequent
129
+ * calls only contribute per-dataSource providers. Adapter-specific
130
+ * registration (TypeORM, Prisma, ...) is handled by the integration
131
+ * package's `forFeature` helper — this module only provides the
132
+ * adapter-agnostic infrastructure.
133
+ */
134
+ export declare class TransactionalModule {
135
+ /**
136
+ * @internal
137
+ * Process-wide map of adapter-bearing `forRoot` calls, keyed by
138
+ * `adapter.dataSourceName`. Used for dedup of duplicate dataSource
139
+ * registrations at module-definition time. The {@link AdapterRegistry}
140
+ * itself is populated imperatively by per-DS adapter providers
141
+ * (factory side effect) — this Map exists for `forRoot`-call-time
142
+ * coordination only.
143
+ *
144
+ * Tests that build multiple modules sequentially MUST call
145
+ * {@link resetForTesting} between cases.
146
+ */
147
+ private static readonly registrations;
148
+ /**
149
+ * @internal
150
+ * `true` once any `forRoot` (or `forRootAsync`) call has run.
151
+ * First-call-special providers (singletons, interceptor, methods
152
+ * bootstrap, observers) are only registered when this is `false` at
153
+ * the start of a call.
154
+ *
155
+ * Tracked separately from {@link registrations} because the
156
+ * shorthand `forRoot({})` (no adapter) still registers
157
+ * infrastructure but contributes nothing to the Map. Q5 invariant:
158
+ * a second `forRoot({})` after infrastructure is already registered
159
+ * throws — the first call already wired everything; the second has
160
+ * nothing to add.
161
+ */
162
+ private static infrastructureRegistered;
163
+ /**
164
+ * @internal
165
+ * Counter for `forRootAsync`-only token uniqueness. Not strictly
166
+ * needed for `Symbol()` (each call returns a unique symbol
167
+ * regardless of description), but keeping a numeric id makes
168
+ * provider names deterministic in error messages.
169
+ */
170
+ private static asyncCounter;
171
+ /**
172
+ * Test-only — drop every registration so a subsequent `forRoot`
173
+ * starts from a clean slate. Mirrors the pattern used with
174
+ * `OutboxModule.resetForTesting` and `EntitiesMetadataStorage` in
175
+ * `@nestjs/typeorm` test suites.
176
+ *
177
+ * Production code should never call this. Calling at runtime after
178
+ * the module has been initialised does NOT clear the provider tree
179
+ * NestJS already built — it only affects subsequent `forRoot` calls.
180
+ *
181
+ * @internal
182
+ */
183
+ static resetForTesting(): void;
184
+ /**
185
+ * Synchronous registration. Each call registers one dataSource's
186
+ * adapter (or, with `adapter` omitted, only the process-wide
187
+ * infrastructure for an integration package's `forFeature` to write
188
+ * into).
189
+ *
190
+ * @example Single-adapter
191
+ * ```ts
192
+ * TransactionalModule.forRoot({ isGlobal: true, adapter })
193
+ * ```
194
+ *
195
+ * @example Multi-adapter (multiple calls)
196
+ * ```ts
197
+ * TransactionalModule.forRoot({ isGlobal: true, adapter: defaultAdapter }),
198
+ * TransactionalModule.forRoot({ adapter: billingAdapter }),
199
+ * TransactionalModule.forRoot({ adapter: inventoryAdapter }),
200
+ * ```
201
+ *
202
+ * @example Infrastructure-only (TypeORM forFeature handles adapters)
203
+ * ```ts
204
+ * TransactionalModule.forRoot({ isGlobal: true }),
205
+ * TypeOrmTransactionalModule.forFeature({ dataSource }),
206
+ * ```
207
+ */
208
+ static forRoot(options?: TransactionalModuleOptions): DynamicModule;
209
+ /**
210
+ * Asynchronous registration. Each call registers one dataSource's
211
+ * adapter (resolved asynchronously via `useFactory`). Multi-DS
212
+ * deployments call `forRootAsync` once per dataSource.
213
+ *
214
+ * **Per-DS DI token limitation**: per-DS tokens
215
+ * (`getTransactionalAdapterToken(ds)`, etc.) are NOT registered
216
+ * for `forRootAsync` calls because the dataSource identifier is
217
+ * only known after the async factory runs, while NestJS provider
218
+ * tokens must be declared statically. If per-DS injection matters,
219
+ * use sync `forRoot({ adapter })` instead — build the adapter
220
+ * configuration through your own async logic before reaching the
221
+ * module imports.
222
+ *
223
+ * `forRootAsync` still works for `AdapterRegistry`-based access
224
+ * (`@Transactional({ dataSource })`,
225
+ * `getCurrentEntityManager(dataSource)`,
226
+ * `manager.run({ dataSource })`) — those route through the registry,
227
+ * which is populated by the async factory's side effect via
228
+ * `AdapterRegistry.register(...)`.
229
+ *
230
+ * @example
231
+ * ```ts
232
+ * TransactionalModule.forRootAsync({
233
+ * inject: [ConfigService],
234
+ * useFactory: (config: ConfigService) => ({
235
+ * adapter: buildAdapterFromConfig(config),
236
+ * }),
237
+ * });
238
+ * ```
239
+ */
240
+ static forRootAsync(options: TransactionalModuleAsyncOptions): DynamicModule;
241
+ }
242
+ //# sourceMappingURL=transactional.module.d.ts.map