@nestjs-transactional/outbox-typeorm 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 (30) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +347 -0
  3. package/dist/entity/event-publication-archive.entity.d.ts +24 -0
  4. package/dist/entity/event-publication-archive.entity.js +84 -0
  5. package/dist/entity/event-publication-archive.entity.js.map +1 -0
  6. package/dist/entity/event-publication.entity.d.ts +33 -0
  7. package/dist/entity/event-publication.entity.js +98 -0
  8. package/dist/entity/event-publication.entity.js.map +1 -0
  9. package/dist/index.d.ts +9 -0
  10. package/dist/index.js +25 -0
  11. package/dist/index.js.map +1 -0
  12. package/dist/migrations/1700000000000-create-event-publication.d.ts +18 -0
  13. package/dist/migrations/1700000000000-create-event-publication.js +26 -0
  14. package/dist/migrations/1700000000000-create-event-publication.js.map +1 -0
  15. package/dist/module/outbox-typeorm.module.d.ts +272 -0
  16. package/dist/module/outbox-typeorm.module.js +335 -0
  17. package/dist/module/outbox-typeorm.module.js.map +1 -0
  18. package/dist/repository/typeorm-event-publication.repository.d.ts +50 -0
  19. package/dist/repository/typeorm-event-publication.repository.js +237 -0
  20. package/dist/repository/typeorm-event-publication.repository.js.map +1 -0
  21. package/dist/schema/event-publication-schema.d.ts +30 -0
  22. package/dist/schema/event-publication-schema.js +124 -0
  23. package/dist/schema/event-publication-schema.js.map +1 -0
  24. package/dist/schema/schema-initialization-options.d.ts +24 -0
  25. package/dist/schema/schema-initialization-options.js +10 -0
  26. package/dist/schema/schema-initialization-options.js.map +1 -0
  27. package/dist/schema/schema-initializer.d.ts +31 -0
  28. package/dist/schema/schema-initializer.js +72 -0
  29. package/dist/schema/schema-initializer.js.map +1 -0
  30. package/package.json +86 -0
@@ -0,0 +1,18 @@
1
+ import type { MigrationInterface, QueryRunner } from 'typeorm';
2
+ /**
3
+ * Initial schema for the Event Publication Registry. Creates both the
4
+ * hot queue (`event_publication`) and the archive table
5
+ * (`event_publication_archive`), along with the indexes needed by the
6
+ * worker, operator queries, and the cleanup routines.
7
+ *
8
+ * The timestamp `1700000000000` is a placeholder chosen so this
9
+ * migration sorts before any application-owned migrations a user might
10
+ * add in their project. Teams integrating the package can copy the
11
+ * file into their own migrations directory and rename it to match
12
+ * their migration timestamp convention.
13
+ */
14
+ export declare class CreateEventPublication1700000000000 implements MigrationInterface {
15
+ up(queryRunner: QueryRunner): Promise<void>;
16
+ down(queryRunner: QueryRunner): Promise<void>;
17
+ }
18
+ //# sourceMappingURL=1700000000000-create-event-publication.d.ts.map
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CreateEventPublication1700000000000 = void 0;
4
+ const event_publication_schema_1 = require("../schema/event-publication-schema");
5
+ /**
6
+ * Initial schema for the Event Publication Registry. Creates both the
7
+ * hot queue (`event_publication`) and the archive table
8
+ * (`event_publication_archive`), along with the indexes needed by the
9
+ * worker, operator queries, and the cleanup routines.
10
+ *
11
+ * The timestamp `1700000000000` is a placeholder chosen so this
12
+ * migration sorts before any application-owned migrations a user might
13
+ * add in their project. Teams integrating the package can copy the
14
+ * file into their own migrations directory and rename it to match
15
+ * their migration timestamp convention.
16
+ */
17
+ class CreateEventPublication1700000000000 {
18
+ async up(queryRunner) {
19
+ await (0, event_publication_schema_1.applyEventPublicationSchema)(queryRunner);
20
+ }
21
+ async down(queryRunner) {
22
+ await (0, event_publication_schema_1.revertEventPublicationSchema)(queryRunner);
23
+ }
24
+ }
25
+ exports.CreateEventPublication1700000000000 = CreateEventPublication1700000000000;
26
+ //# sourceMappingURL=1700000000000-create-event-publication.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"1700000000000-create-event-publication.js","sourceRoot":"","sources":["../../src/migrations/1700000000000-create-event-publication.ts"],"names":[],"mappings":";;;AAEA,iFAG4C;AAE5C;;;;;;;;;;;GAWG;AACH,MAAa,mCAAmC;IAC9C,KAAK,CAAC,EAAE,CAAC,WAAwB;QAC/B,MAAM,IAAA,sDAA2B,EAAC,WAAW,CAAC,CAAC;IACjD,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,WAAwB;QACjC,MAAM,IAAA,uDAA4B,EAAC,WAAW,CAAC,CAAC;IAClD,CAAC;CACF;AARD,kFAQC"}
@@ -0,0 +1,272 @@
1
+ import { type DynamicModule, type InjectionToken, type ModuleMetadata, type Provider } from '@nestjs/common';
2
+ import { type SchemaInitializationOptions } from '../schema/schema-initialization-options';
3
+ /**
4
+ * Options accepted by {@link OutboxTypeOrmModule.forRoot} (Phase 14.21).
5
+ *
6
+ * The dataSource identifier is now a *string name only*. The actual
7
+ * `DataSource` instance is resolved from DI under
8
+ * `getDataSourceToken(name)` — the same convention `@nestjs/typeorm`
9
+ * uses for `@InjectRepository(E, dataSource)`. Mirrors the Phase 14.20
10
+ * shape of `TypeOrmTransactionalModule.forRoot`.
11
+ */
12
+ export interface OutboxTypeOrmOptions {
13
+ /**
14
+ * Identifier of the dataSource the repository binds to. Aligns with
15
+ * `TypeOrmTransactionalModule.forRoot({ dataSource })` and the
16
+ * `@Transactional({ dataSource })` decorator option. Defaults to
17
+ * `'default'`.
18
+ *
19
+ * Multi-dataSource deployments call `forRoot` once per dataSource;
20
+ * each call registers its own `TypeOrmEventPublicationRepository`
21
+ * instance under {@link getTypeOrmRepositoryProviderToken} so the
22
+ * outbox-side per-DS tokens (Phase 14.3) can resolve them via the
23
+ * provider returned by {@link typeOrmEventPublicationRepositoryProvider}.
24
+ */
25
+ readonly dataSource?: string;
26
+ /**
27
+ * Development-only auto-schema-creation config. Defaults to
28
+ * `{ enabled: false }`. When enabled, {@link SchemaInitializer} will
29
+ * create `event_publication` and `event_publication_archive` on
30
+ * application bootstrap if they are missing. Production deployments
31
+ * should apply the shipped TypeORM migration instead.
32
+ */
33
+ readonly schemaInitialization?: SchemaInitializationOptions;
34
+ /**
35
+ * Register as a `@Global()` module so exports are visible to
36
+ * `OutboxModule` and the rest of the application without an explicit
37
+ * import chain. Defaults to `true` — the typical deployment imports
38
+ * `OutboxTypeOrmModule.forRoot` once in the root module and
39
+ * expects the repository to be globally resolvable.
40
+ */
41
+ readonly isGlobal?: boolean;
42
+ }
43
+ /**
44
+ * Asynchronous flavour of {@link OutboxTypeOrmOptions}. Mirrors the
45
+ * shape of `TypeOrmTransactionalModule.forRootAsync` (Phase 14.20).
46
+ *
47
+ * **dataSource name limitation**: the `dataSource` field on this
48
+ * interface is *statically declared* (not async-resolved). NestJS
49
+ * provider tokens must be declared at module-build time, and
50
+ * per-DS tokens like `getTypeOrmRepositoryProviderToken(name)`
51
+ * require the name synchronously. The async factory resolves only
52
+ * the remaining config (`schemaInitialization`, `isGlobal`). If
53
+ * fully-async dataSource-name resolution is required, pre-resolve
54
+ * the name in your own bootstrap code and call sync `forRoot`
55
+ * with the result.
56
+ */
57
+ export interface OutboxTypeOrmAsyncOptions extends Pick<ModuleMetadata, 'imports'> {
58
+ /**
59
+ * Statically-known dataSource name (see {@link OutboxTypeOrmAsyncOptions}
60
+ * JSDoc for the rationale). Defaults to `'default'`.
61
+ */
62
+ readonly dataSource?: string;
63
+ /**
64
+ * Async factory resolving the *remaining* options (excluding
65
+ * `dataSource` which must be static).
66
+ */
67
+ readonly useFactory: (...args: never[]) => Promise<Omit<OutboxTypeOrmOptions, 'dataSource'>> | Omit<OutboxTypeOrmOptions, 'dataSource'>;
68
+ readonly inject?: readonly InjectionToken[];
69
+ }
70
+ /**
71
+ * Private per-dataSource token under which {@link OutboxTypeOrmModule}
72
+ * registers the `TypeOrmEventPublicationRepository` instance for a
73
+ * given dataSource. Internal — consumed only by
74
+ * {@link typeOrmEventPublicationRepositoryProvider} via `useExisting`,
75
+ * which the user feeds into `OutboxModule.forRoot({ repository })` (one
76
+ * `forRoot` call per dataSource — ADR-019 multi-forRoot pattern).
77
+ */
78
+ export declare function getTypeOrmRepositoryProviderToken(dataSourceName: string): string;
79
+ /**
80
+ * NestJS module that wires the TypeORM persistence backend for the
81
+ * Event Publication Registry (Phase 14.21 reshape, mirrors Phase
82
+ * 14.20's `TypeOrmTransactionalModule.forRoot`). Multi-dataSource
83
+ * setups call {@link forRoot} once per dataSource — each call
84
+ * registers an independent {@link TypeOrmEventPublicationRepository}
85
+ * instance under a private per-dataSource token. The
86
+ * {@link typeOrmEventPublicationRepositoryProvider} factory returns
87
+ * a `Provider` that aliases the outbox-side per-DS repository token
88
+ * to that private token.
89
+ *
90
+ * The actual `DataSource` is resolved via `@nestjs/typeorm`'s
91
+ * `getDataSourceToken(name)` — `TypeOrmModule.forRoot(...)` registers
92
+ * it globally, so this module just looks it up in DI.
93
+ *
94
+ * Single-dataSource wiring:
95
+ *
96
+ * ```ts
97
+ * @Module({
98
+ * imports: [
99
+ * TypeOrmModule.forRoot({ ... }),
100
+ *
101
+ * TransactionalModule.forRoot({ isGlobal: true }),
102
+ * TypeOrmTransactionalModule.forRoot(),
103
+ *
104
+ * OutboxModule.forRoot({
105
+ * repository: typeOrmEventPublicationRepositoryProvider(),
106
+ * }),
107
+ * OutboxTypeOrmModule.forRoot(),
108
+ * OutboxModule.forFeature([OrderPlacedEvent]),
109
+ * ],
110
+ * })
111
+ * export class AppModule {}
112
+ * ```
113
+ *
114
+ * Multi-dataSource wiring:
115
+ *
116
+ * ```ts
117
+ * @Module({
118
+ * imports: [
119
+ * TypeOrmModule.forRoot({ ... }),
120
+ * TypeOrmModule.forRoot({ name: 'billing', ... }),
121
+ *
122
+ * TransactionalModule.forRoot({ isGlobal: true }),
123
+ * TypeOrmTransactionalModule.forRoot(),
124
+ * TypeOrmTransactionalModule.forRoot({ dataSource: 'billing' }),
125
+ *
126
+ * OutboxModule.forRoot({
127
+ * repository: typeOrmEventPublicationRepositoryProvider(),
128
+ * }),
129
+ * OutboxModule.forRoot({
130
+ * dataSource: 'billing',
131
+ * repository: typeOrmEventPublicationRepositoryProvider('billing'),
132
+ * }),
133
+ *
134
+ * OutboxTypeOrmModule.forRoot(),
135
+ * OutboxTypeOrmModule.forRoot({ dataSource: 'billing' }),
136
+ *
137
+ * OutboxModule.forFeature([DefaultEvent], { dataSource: 'default' }),
138
+ * OutboxModule.forFeature([BillingEvent], { dataSource: 'billing' }),
139
+ * ],
140
+ * })
141
+ * export class AppModule {}
142
+ * ```
143
+ */
144
+ export declare class OutboxTypeOrmModule {
145
+ /**
146
+ * @internal
147
+ * Counter for `forRootAsync`-only token uniqueness. Mirrors the
148
+ * pattern used in `TypeOrmTransactionalModule.forRootAsync`
149
+ * (Phase 14.20) — every async call gets a unique provider symbol
150
+ * so consecutive calls don't collide.
151
+ */
152
+ private static asyncCounter;
153
+ /**
154
+ * Test-only — reset the async-counter so tests building multiple
155
+ * modules sequentially don't accumulate symbol IDs in a single
156
+ * Jest worker. Production code should never call this.
157
+ *
158
+ * @internal
159
+ */
160
+ static resetForTesting(): void;
161
+ /**
162
+ * Synchronous registration. Each call binds one DataSource (by
163
+ * name) to the outbox-typeorm infrastructure: registers the
164
+ * repository under the private per-DS token, registers the
165
+ * per-DS `SchemaInitializer`, and resolves the actual `DataSource`
166
+ * via `@nestjs/typeorm`'s `getDataSourceToken(name)`.
167
+ *
168
+ * @example Default DataSource
169
+ * ```ts
170
+ * OutboxTypeOrmModule.forRoot()
171
+ * ```
172
+ *
173
+ * @example Named DataSource
174
+ * ```ts
175
+ * OutboxTypeOrmModule.forRoot({ dataSource: 'billing' })
176
+ * ```
177
+ */
178
+ static forRoot(options?: OutboxTypeOrmOptions): DynamicModule;
179
+ /**
180
+ * Asynchronous registration. The `dataSource` name is statically
181
+ * declared (see {@link OutboxTypeOrmAsyncOptions} for the
182
+ * rationale); the `useFactory` resolves the remaining options
183
+ * (`schemaInitialization`, `isGlobal`) through a NestJS-style
184
+ * async factory.
185
+ *
186
+ * @example
187
+ * ```ts
188
+ * OutboxTypeOrmModule.forRootAsync({
189
+ * dataSource: 'billing',
190
+ * imports: [ConfigModule],
191
+ * inject: [ConfigService],
192
+ * useFactory: (cfg: ConfigService) => ({
193
+ * schemaInitialization: { enabled: cfg.get('NODE_ENV') !== 'production' },
194
+ * }),
195
+ * });
196
+ * ```
197
+ */
198
+ static forRootAsync(options: OutboxTypeOrmAsyncOptions): DynamicModule;
199
+ }
200
+ /**
201
+ * Factory returning a `Provider` that aliases the outbox-side per-DS
202
+ * repository token (`getEventPublicationRepositoryToken(dataSourceName)`)
203
+ * to the `TypeOrmEventPublicationRepository` instance registered by
204
+ * {@link OutboxTypeOrmModule.forRoot} for the same dataSource.
205
+ *
206
+ * **Why this bridge function exists** (frequently-asked question, full
207
+ * explanation):
208
+ *
209
+ * `OutboxModule.forRoot` ALWAYS registers something under the per-DS
210
+ * `getEventPublicationRepositoryToken(dataSourceName)` token — when no
211
+ * `repository` option is passed, it defaults to
212
+ * `InMemoryEventPublicationRepository`. `OutboxTypeOrmModule.forRoot`
213
+ * cannot register under THE SAME token directly because both modules
214
+ * are `@Global()` and a duplicate `@Global()` provider for the same
215
+ * token causes NestJS DI conflicts.
216
+ *
217
+ * The bridge function side-steps the conflict by registering an
218
+ * `useExisting` alias provider in `OutboxModule`'s scope:
219
+ * `OutboxModule.forRoot({ repository: typeOrmEventPublicationRepositoryProvider() })`
220
+ * tells `OutboxModule` "for this dataSource's repository, alias to the
221
+ * private token under which `OutboxTypeOrmModule.forRoot` registered
222
+ * its `TypeOrmEventPublicationRepository` instance". `OutboxModule`'s
223
+ * `reBindProvider` machinery overwrites the placeholder `provide`
224
+ * field with the per-DS expected token; the `useExisting` clause
225
+ * carries the actual aliasing.
226
+ *
227
+ * Net flow at runtime:
228
+ *
229
+ * ```
230
+ * @InjectEventPublicationRepository → getEventPublicationRepositoryToken('billing')
231
+ * → useExisting → getTypeOrmRepositoryProviderToken('billing') // private
232
+ * → TypeOrmEventPublicationRepository instance
233
+ * ```
234
+ *
235
+ * Phase 14.21 considered removing this bridge function (delete it,
236
+ * have `OutboxTypeOrmModule.forRoot` register directly under the
237
+ * official outbox-side token), but the change would require
238
+ * `OutboxModule.forRoot` to drop its in-memory default — which would
239
+ * break 14+ outbox unit tests that rely on `OutboxModule.forRoot({})`
240
+ * defaulting to in-memory. The bridge function is small and
241
+ * well-documented; keeping it preserves the architectural separation
242
+ * (outbox-core does not import outbox-typeorm) and saves the test
243
+ * migration burden.
244
+ *
245
+ * Usage — pass to `OutboxModule.forRoot({ repository })`. Multi-DS
246
+ * setups call `forRoot` once per dataSource (ADR-019 multi-forRoot
247
+ * pattern) with the corresponding alias-provider call:
248
+ *
249
+ * ```ts
250
+ * // Single-DS
251
+ * OutboxModule.forRoot({
252
+ * repository: typeOrmEventPublicationRepositoryProvider(),
253
+ * })
254
+ *
255
+ * // Multi-DS — one forRoot per dataSource
256
+ * OutboxModule.forRoot({
257
+ * repository: typeOrmEventPublicationRepositoryProvider(),
258
+ * })
259
+ * OutboxModule.forRoot({
260
+ * dataSource: 'billing',
261
+ * repository: typeOrmEventPublicationRepositoryProvider('billing'),
262
+ * })
263
+ * ```
264
+ *
265
+ * The returned provider's `provide` field is a placeholder
266
+ * (`EVENT_PUBLICATION_REPOSITORY`) — outbox's `reBindProvider`
267
+ * overwrites it with the per-DS token. The substantive part is the
268
+ * `useExisting` clause, which resolves to the private per-DS token
269
+ * registered by `forRoot`.
270
+ */
271
+ export declare function typeOrmEventPublicationRepositoryProvider(dataSourceName?: string): Provider;
272
+ //# sourceMappingURL=outbox-typeorm.module.d.ts.map
@@ -0,0 +1,335 @@
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 OutboxTypeOrmModule_1;
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.OutboxTypeOrmModule = void 0;
11
+ exports.getTypeOrmRepositoryProviderToken = getTypeOrmRepositoryProviderToken;
12
+ exports.typeOrmEventPublicationRepositoryProvider = typeOrmEventPublicationRepositoryProvider;
13
+ const common_1 = require("@nestjs/common");
14
+ const typeorm_1 = require("@nestjs/typeorm");
15
+ const outbox_1 = require("@nestjs-transactional/outbox");
16
+ const typeorm_event_publication_repository_1 = require("../repository/typeorm-event-publication.repository");
17
+ const schema_initialization_options_1 = require("../schema/schema-initialization-options");
18
+ const schema_initializer_1 = require("../schema/schema-initializer");
19
+ /**
20
+ * Private per-dataSource token under which {@link OutboxTypeOrmModule}
21
+ * registers the `TypeOrmEventPublicationRepository` instance for a
22
+ * given dataSource. Internal — consumed only by
23
+ * {@link typeOrmEventPublicationRepositoryProvider} via `useExisting`,
24
+ * which the user feeds into `OutboxModule.forRoot({ repository })` (one
25
+ * `forRoot` call per dataSource — ADR-019 multi-forRoot pattern).
26
+ */
27
+ function getTypeOrmRepositoryProviderToken(dataSourceName) {
28
+ return `OUTBOX_TYPEORM_REPOSITORY_${dataSourceName}`;
29
+ }
30
+ /**
31
+ * Internal per-dataSource token for the {@link SchemaInitializer}
32
+ * instance bound to a given dataSource. Each `forRoot` call
33
+ * instantiates its own initializer (NestJS lifecycle invokes
34
+ * `onApplicationBootstrap` on every registered instance) so the
35
+ * `event_publication` schema is created in each configured dataSource
36
+ * independently.
37
+ */
38
+ function getOutboxTypeOrmSchemaInitializerToken(dataSourceName) {
39
+ return `OUTBOX_TYPEORM_SCHEMA_INITIALIZER_${dataSourceName}`;
40
+ }
41
+ /**
42
+ * Internal per-dataSource token carrying the resolved
43
+ * {@link SchemaInitializationOptions} the matching
44
+ * {@link SchemaInitializer} reads on bootstrap. Distinct from the
45
+ * package-level `SCHEMA_INITIALIZATION_OPTIONS` symbol exported by
46
+ * `../schema/schema-initialization-options` — that symbol stays
47
+ * exported for users who wire `SchemaInitializer` manually outside
48
+ * `OutboxTypeOrmModule.forRoot`.
49
+ */
50
+ function getOutboxTypeOrmSchemaOptionsToken(dataSourceName) {
51
+ return `OUTBOX_TYPEORM_SCHEMA_OPTIONS_${dataSourceName}`;
52
+ }
53
+ const ASYNC_OPTIONS_TOKEN = (id) => Symbol(`OUTBOX_TYPEORM_ASYNC_OPTIONS[${id}]`);
54
+ /**
55
+ * NestJS module that wires the TypeORM persistence backend for the
56
+ * Event Publication Registry (Phase 14.21 reshape, mirrors Phase
57
+ * 14.20's `TypeOrmTransactionalModule.forRoot`). Multi-dataSource
58
+ * setups call {@link forRoot} once per dataSource — each call
59
+ * registers an independent {@link TypeOrmEventPublicationRepository}
60
+ * instance under a private per-dataSource token. The
61
+ * {@link typeOrmEventPublicationRepositoryProvider} factory returns
62
+ * a `Provider` that aliases the outbox-side per-DS repository token
63
+ * to that private token.
64
+ *
65
+ * The actual `DataSource` is resolved via `@nestjs/typeorm`'s
66
+ * `getDataSourceToken(name)` — `TypeOrmModule.forRoot(...)` registers
67
+ * it globally, so this module just looks it up in DI.
68
+ *
69
+ * Single-dataSource wiring:
70
+ *
71
+ * ```ts
72
+ * @Module({
73
+ * imports: [
74
+ * TypeOrmModule.forRoot({ ... }),
75
+ *
76
+ * TransactionalModule.forRoot({ isGlobal: true }),
77
+ * TypeOrmTransactionalModule.forRoot(),
78
+ *
79
+ * OutboxModule.forRoot({
80
+ * repository: typeOrmEventPublicationRepositoryProvider(),
81
+ * }),
82
+ * OutboxTypeOrmModule.forRoot(),
83
+ * OutboxModule.forFeature([OrderPlacedEvent]),
84
+ * ],
85
+ * })
86
+ * export class AppModule {}
87
+ * ```
88
+ *
89
+ * Multi-dataSource wiring:
90
+ *
91
+ * ```ts
92
+ * @Module({
93
+ * imports: [
94
+ * TypeOrmModule.forRoot({ ... }),
95
+ * TypeOrmModule.forRoot({ name: 'billing', ... }),
96
+ *
97
+ * TransactionalModule.forRoot({ isGlobal: true }),
98
+ * TypeOrmTransactionalModule.forRoot(),
99
+ * TypeOrmTransactionalModule.forRoot({ dataSource: 'billing' }),
100
+ *
101
+ * OutboxModule.forRoot({
102
+ * repository: typeOrmEventPublicationRepositoryProvider(),
103
+ * }),
104
+ * OutboxModule.forRoot({
105
+ * dataSource: 'billing',
106
+ * repository: typeOrmEventPublicationRepositoryProvider('billing'),
107
+ * }),
108
+ *
109
+ * OutboxTypeOrmModule.forRoot(),
110
+ * OutboxTypeOrmModule.forRoot({ dataSource: 'billing' }),
111
+ *
112
+ * OutboxModule.forFeature([DefaultEvent], { dataSource: 'default' }),
113
+ * OutboxModule.forFeature([BillingEvent], { dataSource: 'billing' }),
114
+ * ],
115
+ * })
116
+ * export class AppModule {}
117
+ * ```
118
+ */
119
+ let OutboxTypeOrmModule = class OutboxTypeOrmModule {
120
+ static { OutboxTypeOrmModule_1 = this; }
121
+ /**
122
+ * @internal
123
+ * Counter for `forRootAsync`-only token uniqueness. Mirrors the
124
+ * pattern used in `TypeOrmTransactionalModule.forRootAsync`
125
+ * (Phase 14.20) — every async call gets a unique provider symbol
126
+ * so consecutive calls don't collide.
127
+ */
128
+ static asyncCounter = 0;
129
+ /**
130
+ * Test-only — reset the async-counter so tests building multiple
131
+ * modules sequentially don't accumulate symbol IDs in a single
132
+ * Jest worker. Production code should never call this.
133
+ *
134
+ * @internal
135
+ */
136
+ static resetForTesting() {
137
+ this.asyncCounter = 0;
138
+ }
139
+ /**
140
+ * Synchronous registration. Each call binds one DataSource (by
141
+ * name) to the outbox-typeorm infrastructure: registers the
142
+ * repository under the private per-DS token, registers the
143
+ * per-DS `SchemaInitializer`, and resolves the actual `DataSource`
144
+ * via `@nestjs/typeorm`'s `getDataSourceToken(name)`.
145
+ *
146
+ * @example Default DataSource
147
+ * ```ts
148
+ * OutboxTypeOrmModule.forRoot()
149
+ * ```
150
+ *
151
+ * @example Named DataSource
152
+ * ```ts
153
+ * OutboxTypeOrmModule.forRoot({ dataSource: 'billing' })
154
+ * ```
155
+ */
156
+ static forRoot(options = {}) {
157
+ const dataSourceName = options.dataSource ?? 'default';
158
+ const providers = buildPerDataSourceProviders(dataSourceName, {
159
+ schemaInitializationProvider: {
160
+ provide: getOutboxTypeOrmSchemaOptionsToken(dataSourceName),
161
+ useValue: options.schemaInitialization ?? schema_initialization_options_1.DEFAULT_SCHEMA_INITIALIZATION_OPTIONS,
162
+ },
163
+ });
164
+ return {
165
+ module: OutboxTypeOrmModule_1,
166
+ global: options.isGlobal ?? true,
167
+ providers,
168
+ exports: buildPerDataSourceExports(dataSourceName),
169
+ };
170
+ }
171
+ /**
172
+ * Asynchronous registration. The `dataSource` name is statically
173
+ * declared (see {@link OutboxTypeOrmAsyncOptions} for the
174
+ * rationale); the `useFactory` resolves the remaining options
175
+ * (`schemaInitialization`, `isGlobal`) through a NestJS-style
176
+ * async factory.
177
+ *
178
+ * @example
179
+ * ```ts
180
+ * OutboxTypeOrmModule.forRootAsync({
181
+ * dataSource: 'billing',
182
+ * imports: [ConfigModule],
183
+ * inject: [ConfigService],
184
+ * useFactory: (cfg: ConfigService) => ({
185
+ * schemaInitialization: { enabled: cfg.get('NODE_ENV') !== 'production' },
186
+ * }),
187
+ * });
188
+ * ```
189
+ */
190
+ static forRootAsync(options) {
191
+ const dataSourceName = options.dataSource ?? 'default';
192
+ const id = this.asyncCounter++;
193
+ const asyncOptionsToken = ASYNC_OPTIONS_TOKEN(id);
194
+ const asyncOptionsProvider = {
195
+ provide: asyncOptionsToken,
196
+ useFactory: options.useFactory,
197
+ inject: options.inject ? [...options.inject] : undefined,
198
+ };
199
+ const schemaOptionsProvider = {
200
+ provide: getOutboxTypeOrmSchemaOptionsToken(dataSourceName),
201
+ useFactory: (resolved) => resolved.schemaInitialization ?? schema_initialization_options_1.DEFAULT_SCHEMA_INITIALIZATION_OPTIONS,
202
+ inject: [asyncOptionsToken],
203
+ };
204
+ const providers = [
205
+ asyncOptionsProvider,
206
+ ...buildPerDataSourceProviders(dataSourceName, {
207
+ schemaInitializationProvider: schemaOptionsProvider,
208
+ }),
209
+ ];
210
+ return {
211
+ module: OutboxTypeOrmModule_1,
212
+ global: true,
213
+ imports: options.imports ?? [],
214
+ providers,
215
+ exports: buildPerDataSourceExports(dataSourceName),
216
+ };
217
+ }
218
+ };
219
+ exports.OutboxTypeOrmModule = OutboxTypeOrmModule;
220
+ exports.OutboxTypeOrmModule = OutboxTypeOrmModule = OutboxTypeOrmModule_1 = __decorate([
221
+ (0, common_1.Module)({})
222
+ ], OutboxTypeOrmModule);
223
+ /**
224
+ * Common per-dataSource provider construction shared between
225
+ * `forRoot` (sync schema-options provider) and `forRootAsync`
226
+ * (async-resolved schema-options provider). The repository and
227
+ * SchemaInitializer providers are shape-identical between the two
228
+ * paths; only the schema-options provider's mechanics differ
229
+ * (sync `useValue` vs async `useFactory`), which is why it's
230
+ * passed in.
231
+ */
232
+ function buildPerDataSourceProviders(dataSourceName, args) {
233
+ const dataSourceToken = (0, typeorm_1.getDataSourceToken)(dataSourceName);
234
+ const repositoryToken = getTypeOrmRepositoryProviderToken(dataSourceName);
235
+ const schemaInitializerToken = getOutboxTypeOrmSchemaInitializerToken(dataSourceName);
236
+ const schemaOptionsToken = getOutboxTypeOrmSchemaOptionsToken(dataSourceName);
237
+ return [
238
+ {
239
+ provide: repositoryToken,
240
+ useFactory: (ds) => new typeorm_event_publication_repository_1.TypeOrmEventPublicationRepository(ds, dataSourceName),
241
+ inject: [dataSourceToken],
242
+ },
243
+ args.schemaInitializationProvider,
244
+ {
245
+ provide: schemaInitializerToken,
246
+ useFactory: (ds, opts) => new schema_initializer_1.SchemaInitializer(ds, opts),
247
+ inject: [dataSourceToken, schemaOptionsToken],
248
+ },
249
+ ];
250
+ }
251
+ function buildPerDataSourceExports(dataSourceName) {
252
+ return [
253
+ getTypeOrmRepositoryProviderToken(dataSourceName),
254
+ getOutboxTypeOrmSchemaInitializerToken(dataSourceName),
255
+ getOutboxTypeOrmSchemaOptionsToken(dataSourceName),
256
+ ];
257
+ }
258
+ /**
259
+ * Factory returning a `Provider` that aliases the outbox-side per-DS
260
+ * repository token (`getEventPublicationRepositoryToken(dataSourceName)`)
261
+ * to the `TypeOrmEventPublicationRepository` instance registered by
262
+ * {@link OutboxTypeOrmModule.forRoot} for the same dataSource.
263
+ *
264
+ * **Why this bridge function exists** (frequently-asked question, full
265
+ * explanation):
266
+ *
267
+ * `OutboxModule.forRoot` ALWAYS registers something under the per-DS
268
+ * `getEventPublicationRepositoryToken(dataSourceName)` token — when no
269
+ * `repository` option is passed, it defaults to
270
+ * `InMemoryEventPublicationRepository`. `OutboxTypeOrmModule.forRoot`
271
+ * cannot register under THE SAME token directly because both modules
272
+ * are `@Global()` and a duplicate `@Global()` provider for the same
273
+ * token causes NestJS DI conflicts.
274
+ *
275
+ * The bridge function side-steps the conflict by registering an
276
+ * `useExisting` alias provider in `OutboxModule`'s scope:
277
+ * `OutboxModule.forRoot({ repository: typeOrmEventPublicationRepositoryProvider() })`
278
+ * tells `OutboxModule` "for this dataSource's repository, alias to the
279
+ * private token under which `OutboxTypeOrmModule.forRoot` registered
280
+ * its `TypeOrmEventPublicationRepository` instance". `OutboxModule`'s
281
+ * `reBindProvider` machinery overwrites the placeholder `provide`
282
+ * field with the per-DS expected token; the `useExisting` clause
283
+ * carries the actual aliasing.
284
+ *
285
+ * Net flow at runtime:
286
+ *
287
+ * ```
288
+ * @InjectEventPublicationRepository → getEventPublicationRepositoryToken('billing')
289
+ * → useExisting → getTypeOrmRepositoryProviderToken('billing') // private
290
+ * → TypeOrmEventPublicationRepository instance
291
+ * ```
292
+ *
293
+ * Phase 14.21 considered removing this bridge function (delete it,
294
+ * have `OutboxTypeOrmModule.forRoot` register directly under the
295
+ * official outbox-side token), but the change would require
296
+ * `OutboxModule.forRoot` to drop its in-memory default — which would
297
+ * break 14+ outbox unit tests that rely on `OutboxModule.forRoot({})`
298
+ * defaulting to in-memory. The bridge function is small and
299
+ * well-documented; keeping it preserves the architectural separation
300
+ * (outbox-core does not import outbox-typeorm) and saves the test
301
+ * migration burden.
302
+ *
303
+ * Usage — pass to `OutboxModule.forRoot({ repository })`. Multi-DS
304
+ * setups call `forRoot` once per dataSource (ADR-019 multi-forRoot
305
+ * pattern) with the corresponding alias-provider call:
306
+ *
307
+ * ```ts
308
+ * // Single-DS
309
+ * OutboxModule.forRoot({
310
+ * repository: typeOrmEventPublicationRepositoryProvider(),
311
+ * })
312
+ *
313
+ * // Multi-DS — one forRoot per dataSource
314
+ * OutboxModule.forRoot({
315
+ * repository: typeOrmEventPublicationRepositoryProvider(),
316
+ * })
317
+ * OutboxModule.forRoot({
318
+ * dataSource: 'billing',
319
+ * repository: typeOrmEventPublicationRepositoryProvider('billing'),
320
+ * })
321
+ * ```
322
+ *
323
+ * The returned provider's `provide` field is a placeholder
324
+ * (`EVENT_PUBLICATION_REPOSITORY`) — outbox's `reBindProvider`
325
+ * overwrites it with the per-DS token. The substantive part is the
326
+ * `useExisting` clause, which resolves to the private per-DS token
327
+ * registered by `forRoot`.
328
+ */
329
+ function typeOrmEventPublicationRepositoryProvider(dataSourceName = 'default') {
330
+ return {
331
+ provide: outbox_1.EVENT_PUBLICATION_REPOSITORY,
332
+ useExisting: getTypeOrmRepositoryProviderToken(dataSourceName),
333
+ };
334
+ }
335
+ //# sourceMappingURL=outbox-typeorm.module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"outbox-typeorm.module.js","sourceRoot":"","sources":["../../src/module/outbox-typeorm.module.ts"],"names":[],"mappings":"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"}