@prodforcode/event-forge-typeorm 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/README.md +320 -0
  2. package/bin/event-forge.js +10 -0
  3. package/dist/cli/index.d.ts +3 -0
  4. package/dist/cli/index.d.ts.map +1 -0
  5. package/dist/cli/index.js +16 -0
  6. package/dist/cli/index.js.map +1 -0
  7. package/dist/cli/migration-command.d.ts +11 -0
  8. package/dist/cli/migration-command.d.ts.map +1 -0
  9. package/dist/cli/migration-command.js +139 -0
  10. package/dist/cli/migration-command.js.map +1 -0
  11. package/dist/entities/inbox-message.entity.d.ts +14 -0
  12. package/dist/entities/inbox-message.entity.d.ts.map +1 -0
  13. package/dist/entities/inbox-message.entity.js +80 -0
  14. package/dist/entities/inbox-message.entity.js.map +1 -0
  15. package/dist/entities/index.d.ts +3 -0
  16. package/dist/entities/index.d.ts.map +1 -0
  17. package/dist/entities/index.js +19 -0
  18. package/dist/entities/index.js.map +1 -0
  19. package/dist/entities/outbox-message.entity.d.ts +19 -0
  20. package/dist/entities/outbox-message.entity.d.ts.map +1 -0
  21. package/dist/entities/outbox-message.entity.js +106 -0
  22. package/dist/entities/outbox-message.entity.js.map +1 -0
  23. package/dist/index.d.ts +4 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +20 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/migrations/index.d.ts +4 -0
  28. package/dist/migrations/index.d.ts.map +1 -0
  29. package/dist/migrations/index.js +17 -0
  30. package/dist/migrations/index.js.map +1 -0
  31. package/dist/migrations/sql-generator.d.ts +6 -0
  32. package/dist/migrations/sql-generator.d.ts.map +1 -0
  33. package/dist/migrations/sql-generator.js +86 -0
  34. package/dist/migrations/sql-generator.js.map +1 -0
  35. package/dist/migrations/templates.d.ts +13 -0
  36. package/dist/migrations/templates.d.ts.map +1 -0
  37. package/dist/migrations/templates.js +126 -0
  38. package/dist/migrations/templates.js.map +1 -0
  39. package/dist/repositories/index.d.ts +3 -0
  40. package/dist/repositories/index.d.ts.map +1 -0
  41. package/dist/repositories/index.js +19 -0
  42. package/dist/repositories/index.js.map +1 -0
  43. package/dist/repositories/typeorm-inbox.repository.d.ts +13 -0
  44. package/dist/repositories/typeorm-inbox.repository.d.ts.map +1 -0
  45. package/dist/repositories/typeorm-inbox.repository.js +93 -0
  46. package/dist/repositories/typeorm-inbox.repository.js.map +1 -0
  47. package/dist/repositories/typeorm-outbox.repository.d.ts +16 -0
  48. package/dist/repositories/typeorm-outbox.repository.d.ts.map +1 -0
  49. package/dist/repositories/typeorm-outbox.repository.js +115 -0
  50. package/dist/repositories/typeorm-outbox.repository.js.map +1 -0
  51. package/package.json +8 -3
package/README.md ADDED
@@ -0,0 +1,320 @@
1
+ # @prodforcode/event-forge-typeorm
2
+
3
+ TypeORM adapter for Event-Forge - Universal Inbox-Outbox Pattern implementation for PostgreSQL.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @prodforcode/event-forge-typeorm typeorm
9
+ ```
10
+
11
+ ## Features
12
+
13
+ - ✅ PostgreSQL 12+ compatible
14
+ - ✅ TypeORM entity definitions for outbox and inbox messages
15
+ - ✅ Optimized repository implementations with SELECT FOR UPDATE SKIP LOCKED
16
+ - ✅ Automatic database migration generation
17
+ - ✅ CLI tool for migration management
18
+ - ✅ Full TypeScript support
19
+
20
+ ## Quick Start
21
+
22
+ ### 1. Generate Database Migration
23
+
24
+ Event-Forge provides a CLI tool to generate database migrations without requiring an active TypeORM connection.
25
+
26
+ #### Generate SQL to stdout
27
+
28
+ ```bash
29
+ npx event-forge migration:generate
30
+ ```
31
+
32
+ #### Generate SQL file
33
+
34
+ ```bash
35
+ npx event-forge migration:generate --format=sql --output=./migrations
36
+ ```
37
+
38
+ #### Generate TypeORM migration class
39
+
40
+ ```bash
41
+ npx event-forge migration:generate --format=typeorm --output=./migrations
42
+ ```
43
+
44
+ #### Custom table names and schema
45
+
46
+ ```bash
47
+ npx event-forge migration:generate \
48
+ --format=sql \
49
+ --output=./migrations \
50
+ --schema=messaging \
51
+ --outbox-table=my_outbox \
52
+ --inbox-table=my_inbox
53
+ ```
54
+
55
+ ### 2. Apply Migration
56
+
57
+ After generating the migration, apply it to your database:
58
+
59
+ #### Using raw SQL
60
+
61
+ ```bash
62
+ psql -d your_database -f migrations/20260109-event-forge-migration.sql
63
+ ```
64
+
65
+ #### Using TypeORM migrations
66
+
67
+ ```bash
68
+ npm run typeorm migration:run
69
+ ```
70
+
71
+ ### 3. Use in Your Application
72
+
73
+ ```typescript
74
+ import { DataSource } from 'typeorm';
75
+ import {
76
+ OutboxMessageEntity,
77
+ InboxMessageEntity,
78
+ TypeORMOutboxRepository,
79
+ TypeORMInboxRepository,
80
+ } from '@prodforcode/event-forge-typeorm';
81
+ import { OutboxService, InboxService } from '@prodforcode/event-forge-core';
82
+
83
+ // Initialize TypeORM DataSource
84
+ const dataSource = new DataSource({
85
+ type: 'postgres',
86
+ host: 'localhost',
87
+ port: 5432,
88
+ username: 'postgres',
89
+ password: 'postgres',
90
+ database: 'myapp',
91
+ entities: [OutboxMessageEntity, InboxMessageEntity],
92
+ synchronize: false, // Use migrations instead
93
+ });
94
+
95
+ await dataSource.initialize();
96
+
97
+ // Create repositories
98
+ const outboxRepo = new TypeORMOutboxRepository(
99
+ dataSource.getRepository(OutboxMessageEntity),
100
+ );
101
+
102
+ const inboxRepo = new TypeORMInboxRepository(
103
+ dataSource.getRepository(InboxMessageEntity),
104
+ );
105
+
106
+ // Create services
107
+ const outboxService = new OutboxService(outboxRepo, publisher);
108
+ const inboxService = new InboxService(inboxRepo);
109
+
110
+ // Use in your business logic
111
+ await dataSource.transaction(async (manager) => {
112
+ // Your business logic here
113
+ await manager.save(order);
114
+
115
+ // Create outbox message within same transaction
116
+ await outboxService.createMessage(
117
+ {
118
+ aggregateType: 'Order',
119
+ aggregateId: order.id,
120
+ eventType: 'OrderCreated',
121
+ payload: { orderId: order.id, amount: order.total },
122
+ },
123
+ manager, // Pass transaction manager for transactional outbox
124
+ );
125
+ });
126
+ ```
127
+
128
+ ## Programmatic Migration Generation
129
+
130
+ You can also generate migrations programmatically:
131
+
132
+ ```typescript
133
+ import {
134
+ getEventForgeUpSQL,
135
+ getEventForgeDownSQL,
136
+ generateMigrationClass,
137
+ generateRawSQLFile,
138
+ } from '@prodforcode/event-forge-typeorm';
139
+
140
+ // Generate UP migration SQL
141
+ const upSQL = getEventForgeUpSQL({
142
+ schema: 'messaging',
143
+ outboxTable: 'outbox_messages',
144
+ inboxTable: 'inbox_messages',
145
+ });
146
+
147
+ // Generate DOWN migration SQL
148
+ const downSQL = getEventForgeDownSQL({
149
+ schema: 'messaging',
150
+ outboxTable: 'outbox_messages',
151
+ inboxTable: 'inbox_messages',
152
+ });
153
+
154
+ // Generate TypeORM migration class
155
+ const migrationClass = generateMigrationClass({
156
+ schema: 'messaging',
157
+ });
158
+
159
+ // Generate complete SQL file with comments
160
+ const sqlFile = generateRawSQLFile({
161
+ schema: 'messaging',
162
+ });
163
+
164
+ // Write to file
165
+ import * as fs from 'fs';
166
+ fs.writeFileSync('migration.sql', sqlFile);
167
+ ```
168
+
169
+ ## CLI Reference
170
+
171
+ ### `event-forge migration:generate`
172
+
173
+ Generate Event-Forge database migration.
174
+
175
+ **Options:**
176
+
177
+ - `-f, --format <format>` - Output format: `sql`, `typeorm`, or `stdout` (default: `stdout`)
178
+ - `-o, --output <dir>` - Output directory (required for sql/typeorm formats)
179
+ - `--filename <name>` - Custom output filename (optional)
180
+ - `--schema <name>` - Database schema name (default: `public`)
181
+ - `--outbox-table <name>` - Outbox table name (default: `outbox_messages`)
182
+ - `--inbox-table <name>` - Inbox table name (default: `inbox_messages`)
183
+
184
+ **Examples:**
185
+
186
+ ```bash
187
+ # Generate to stdout
188
+ npx event-forge migration:generate
189
+
190
+ # Generate SQL file with custom options
191
+ npx event-forge migration:generate \
192
+ --format=sql \
193
+ --output=./migrations \
194
+ --schema=events \
195
+ --outbox-table=event_outbox
196
+
197
+ # Generate TypeORM migration class
198
+ npx event-forge migration:generate \
199
+ --format=typeorm \
200
+ --output=./src/migrations \
201
+ --filename=1704657600000-EventForge.ts
202
+ ```
203
+
204
+ ## Database Schema
205
+
206
+ ### Outbox Messages Table
207
+
208
+ ```sql
209
+ CREATE TABLE outbox_messages (
210
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
211
+ aggregate_type VARCHAR(255) NOT NULL,
212
+ aggregate_id VARCHAR(255) NOT NULL,
213
+ event_type VARCHAR(255) NOT NULL,
214
+ payload JSONB NOT NULL,
215
+ metadata JSONB,
216
+ status outbox_message_status NOT NULL DEFAULT 'pending',
217
+ retry_count INTEGER NOT NULL DEFAULT 0,
218
+ max_retries INTEGER NOT NULL DEFAULT 5,
219
+ error_message TEXT,
220
+ scheduled_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
221
+ locked_by VARCHAR(255),
222
+ locked_at TIMESTAMP WITH TIME ZONE,
223
+ created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
224
+ updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
225
+ );
226
+ ```
227
+
228
+ **Indexes:**
229
+
230
+ - Partial index on `(status, scheduled_at, created_at)` for pending/failed messages
231
+ - Index on `(aggregate_type, aggregate_id)` for aggregate lookups
232
+ - Index on `(event_type)` for event type filtering
233
+ - Index on `(created_at)` for time-based queries
234
+
235
+ ### Inbox Messages Table
236
+
237
+ ```sql
238
+ CREATE TABLE inbox_messages (
239
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
240
+ message_id VARCHAR(255) NOT NULL,
241
+ source VARCHAR(255) NOT NULL,
242
+ event_type VARCHAR(255) NOT NULL,
243
+ payload JSONB NOT NULL,
244
+ status inbox_message_status NOT NULL DEFAULT 'received',
245
+ processed_at TIMESTAMP WITH TIME ZONE,
246
+ error_message TEXT,
247
+ created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
248
+ received_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
249
+ UNIQUE(message_id, source)
250
+ );
251
+ ```
252
+
253
+ **Indexes:**
254
+
255
+ - Unique constraint on `(message_id, source)` for deduplication
256
+ - Index on `(event_type)` for event type filtering
257
+ - Index on `(status)` for status filtering
258
+ - Index on `(created_at)` for time-based queries
259
+ - Index on `(received_at)` for received time queries
260
+
261
+ ## API Reference
262
+
263
+ ### Migration Generation Functions
264
+
265
+ #### `getEventForgeUpSQL(options?): string`
266
+
267
+ Generates complete UP migration SQL (CREATE statements).
268
+
269
+ **Parameters:**
270
+
271
+ - `options.schema` - Database schema name (default: `'public'`)
272
+ - `options.outboxTable` - Outbox table name (default: `'outbox_messages'`)
273
+ - `options.inboxTable` - Inbox table name (default: `'inbox_messages'`)
274
+
275
+ **Returns:** SQL string with CREATE statements for types, tables, and indexes
276
+
277
+ #### `getEventForgeDownSQL(options?): string`
278
+
279
+ Generates complete DOWN migration SQL (DROP statements).
280
+
281
+ **Parameters:** Same as `getEventForgeUpSQL`
282
+
283
+ **Returns:** SQL string with DROP statements for tables and types
284
+
285
+ #### `generateMigrationClass(options?): string`
286
+
287
+ Generates TypeORM migration class file content.
288
+
289
+ **Parameters:** Same as `getEventForgeUpSQL`
290
+
291
+ **Returns:** TypeScript code for TypeORM migration class
292
+
293
+ #### `generateRawSQLFile(options?): string`
294
+
295
+ Generates raw SQL file content with both UP and DOWN migrations.
296
+
297
+ **Parameters:** Same as `getEventForgeUpSQL`
298
+
299
+ **Returns:** SQL string with commented sections for UP and DOWN migrations
300
+
301
+ ## Requirements
302
+
303
+ - PostgreSQL 12 or higher
304
+ - TypeORM 0.3.0 or higher
305
+ - Node.js 18 or higher
306
+
307
+ ## License
308
+
309
+ MIT
310
+
311
+ ## Related Packages
312
+
313
+ - [@prodforcode/event-forge-core](../core) - Core interfaces and services
314
+ - [@prodforcode/event-forge-mongoose](../adapter-mongoose) - MongoDB adapter
315
+ - [@prodforcode/event-forge-rabbitmq](../publisher-rabbitmq) - RabbitMQ publisher
316
+ - [@prodforcode/event-forge-nestjs](../nestjs) - NestJS integration
317
+
318
+ ## Support
319
+
320
+ For issues and questions, please visit [GitHub Issues](https://github.com/your-org/event-forge/issues).
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Event-Forge CLI Executable
5
+ *
6
+ * This is the entry point for the event-forge CLI tool.
7
+ * It loads and executes the compiled CLI code.
8
+ */
9
+
10
+ require('../dist/cli/index.js');
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":""}
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const fs_1 = require("fs");
5
+ const path_1 = require("path");
6
+ const commander_1 = require("commander");
7
+ const migration_command_1 = require("./migration-command");
8
+ const packageJson = JSON.parse((0, fs_1.readFileSync)((0, path_1.join)(__dirname, '../../package.json'), 'utf-8'));
9
+ const program = new commander_1.Command();
10
+ program
11
+ .name('event-forge')
12
+ .description('Event-Forge TypeORM Adapter CLI')
13
+ .version(packageJson.version);
14
+ program.addCommand((0, migration_command_1.createMigrationCommand)());
15
+ program.parse(process.argv);
16
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";;;AAQA,2BAAkC;AAClC,+BAA4B;AAE5B,yCAAoC;AAEpC,2DAA6D;AAO7D,MAAM,WAAW,GAAgB,IAAI,CAAC,KAAK,CACzC,IAAA,iBAAY,EAAC,IAAA,WAAI,EAAC,SAAS,EAAE,oBAAoB,CAAC,EAAE,OAAO,CAAC,CAC9C,CAAC;AAEjB,MAAM,OAAO,GAAG,IAAI,mBAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,aAAa,CAAC;KACnB,WAAW,CAAC,iCAAiC,CAAC;KAC9C,OAAO,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;AAGhC,OAAO,CAAC,UAAU,CAAC,IAAA,0CAAsB,GAAE,CAAC,CAAC;AAG7C,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC"}
@@ -0,0 +1,11 @@
1
+ import { Command } from 'commander';
2
+ import type { MigrationOptions } from '../migrations/templates';
3
+ export type OutputFormat = 'sql' | 'typeorm' | 'stdout';
4
+ export interface CLIOptions extends MigrationOptions {
5
+ format?: OutputFormat;
6
+ output?: string;
7
+ filename?: string;
8
+ }
9
+ export declare function executeMigrationGenerate(options: CLIOptions): void;
10
+ export declare function createMigrationCommand(): Command;
11
+ //# sourceMappingURL=migration-command.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration-command.d.ts","sourceRoot":"","sources":["../../src/cli/migration-command.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMpC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAEhE,MAAM,MAAM,YAAY,GAAG,KAAK,GAAG,SAAS,GAAG,QAAQ,CAAC;AAExD,MAAM,WAAW,UAAW,SAAQ,gBAAgB;IAElD,MAAM,CAAC,EAAE,YAAY,CAAC;IAEtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AA8GD,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,UAAU,GAAG,IAAI,CAsClE;AAKD,wBAAgB,sBAAsB,IAAI,OAAO,CAoBhD"}
@@ -0,0 +1,139 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.executeMigrationGenerate = executeMigrationGenerate;
37
+ exports.createMigrationCommand = createMigrationCommand;
38
+ const fs = __importStar(require("fs"));
39
+ const path = __importStar(require("path"));
40
+ const commander_1 = require("commander");
41
+ const sql_generator_1 = require("../migrations/sql-generator");
42
+ function generateFilename(format) {
43
+ const timestamp = Date.now();
44
+ const date = new Date().toISOString().split('T')[0].replace(/-/g, '');
45
+ switch (format) {
46
+ case 'typeorm':
47
+ return `${timestamp}-EventForgeMigration.ts`;
48
+ case 'sql':
49
+ return `${date}-event-forge-migration.sql`;
50
+ default:
51
+ return `migration.sql`;
52
+ }
53
+ }
54
+ function generateMigrationContent(format, options) {
55
+ switch (format) {
56
+ case 'typeorm':
57
+ return (0, sql_generator_1.generateMigrationClass)(options);
58
+ case 'sql':
59
+ case 'stdout':
60
+ return (0, sql_generator_1.generateRawSQLFile)(options);
61
+ default: {
62
+ const exhaustiveCheck = format;
63
+ throw new Error(`Unsupported format: ${String(exhaustiveCheck)}`);
64
+ }
65
+ }
66
+ }
67
+ function writeMigration(content, format, outputDir, filename) {
68
+ if (format === 'stdout') {
69
+ console.log(content);
70
+ return;
71
+ }
72
+ if (!outputDir) {
73
+ throw new Error('Output directory is required for file output formats');
74
+ }
75
+ if (!fs.existsSync(outputDir)) {
76
+ fs.mkdirSync(outputDir, { recursive: true });
77
+ }
78
+ const outputFilename = filename || generateFilename(format);
79
+ const outputPath = path.join(outputDir, outputFilename);
80
+ fs.writeFileSync(outputPath, content, 'utf-8');
81
+ console.log(`✅ Migration generated: ${outputPath}`);
82
+ }
83
+ function validateOptions(options) {
84
+ if (options.format !== 'stdout' && !options.output) {
85
+ throw new Error('Output directory (--output) is required when format is not stdout');
86
+ }
87
+ if (options.schema && !/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(options.schema)) {
88
+ throw new Error(`Invalid schema name: ${options.schema}. Must be a valid PostgreSQL identifier.`);
89
+ }
90
+ if (options.outboxTable &&
91
+ !/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(options.outboxTable)) {
92
+ throw new Error(`Invalid outbox table name: ${options.outboxTable}. Must be a valid PostgreSQL identifier.`);
93
+ }
94
+ if (options.inboxTable &&
95
+ !/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(options.inboxTable)) {
96
+ throw new Error(`Invalid inbox table name: ${options.inboxTable}. Must be a valid PostgreSQL identifier.`);
97
+ }
98
+ }
99
+ function executeMigrationGenerate(options) {
100
+ try {
101
+ validateOptions(options);
102
+ const format = options.format || 'stdout';
103
+ const migrationOptions = {
104
+ schema: options.schema,
105
+ outboxTable: options.outboxTable,
106
+ inboxTable: options.inboxTable,
107
+ };
108
+ const content = generateMigrationContent(format, migrationOptions);
109
+ writeMigration(content, format, options.output, options.filename);
110
+ if (format !== 'stdout') {
111
+ console.log('\n📋 Migration Summary:');
112
+ console.log(` Format: ${format}`);
113
+ console.log(` Schema: ${migrationOptions.schema || 'public'}`);
114
+ console.log(` Outbox Table: ${migrationOptions.outboxTable || 'outbox_messages'}`);
115
+ console.log(` Inbox Table: ${migrationOptions.inboxTable || 'inbox_messages'}`);
116
+ }
117
+ }
118
+ catch (error) {
119
+ console.error('❌ Migration generation failed:');
120
+ console.error(error instanceof Error ? error.message : 'Unknown error occurred');
121
+ process.exit(1);
122
+ }
123
+ }
124
+ function createMigrationCommand() {
125
+ const command = new commander_1.Command('migration:generate');
126
+ command
127
+ .description('Generate Event-Forge database migration')
128
+ .option('-f, --format <format>', 'Output format: sql, typeorm, or stdout', 'stdout')
129
+ .option('-o, --output <dir>', 'Output directory (required for sql/typeorm)')
130
+ .option('--filename <name>', 'Output filename (optional)')
131
+ .option('--schema <name>', 'Database schema name', 'public')
132
+ .option('--outbox-table <name>', 'Outbox table name', 'outbox_messages')
133
+ .option('--inbox-table <name>', 'Inbox table name', 'inbox_messages')
134
+ .action((options) => {
135
+ executeMigrationGenerate(options);
136
+ });
137
+ return command;
138
+ }
139
+ //# sourceMappingURL=migration-command.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration-command.js","sourceRoot":"","sources":["../../src/cli/migration-command.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import { InboxMessage, InboxMessageStatus } from '@prodforcode/event-forge-core';
2
+ export declare class InboxMessageEntity implements InboxMessage {
3
+ id: string;
4
+ messageId: string;
5
+ source: string;
6
+ eventType: string;
7
+ payload: Record<string, unknown>;
8
+ status: InboxMessageStatus;
9
+ processedAt?: Date;
10
+ errorMessage?: string;
11
+ createdAt: Date;
12
+ receivedAt: Date;
13
+ }
14
+ //# sourceMappingURL=inbox-message.entity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inbox-message.entity.d.ts","sourceRoot":"","sources":["../../src/entities/inbox-message.entity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAcjF,qBAMa,kBAAmB,YAAW,YAAY;IAErD,EAAE,EAAE,MAAM,CAAC;IAGX,SAAS,EAAE,MAAM,CAAC;IAGlB,MAAM,EAAE,MAAM,CAAC;IAGf,SAAS,EAAE,MAAM,CAAC;IAGlB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAOjC,MAAM,EAAE,kBAAkB,CAAC;IAG3B,WAAW,CAAC,EAAE,IAAI,CAAC;IAGnB,YAAY,CAAC,EAAE,MAAM,CAAC;IAGtB,SAAS,EAAE,IAAI,CAAC;IAGhB,UAAU,EAAE,IAAI,CAAC;CAClB"}
@@ -0,0 +1,80 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.InboxMessageEntity = void 0;
13
+ const event_forge_core_1 = require("@prodforcode/event-forge-core");
14
+ const typeorm_1 = require("typeorm");
15
+ let InboxMessageEntity = class InboxMessageEntity {
16
+ id;
17
+ messageId;
18
+ source;
19
+ eventType;
20
+ payload;
21
+ status;
22
+ processedAt;
23
+ errorMessage;
24
+ createdAt;
25
+ receivedAt;
26
+ };
27
+ exports.InboxMessageEntity = InboxMessageEntity;
28
+ __decorate([
29
+ (0, typeorm_1.PrimaryGeneratedColumn)('uuid'),
30
+ __metadata("design:type", String)
31
+ ], InboxMessageEntity.prototype, "id", void 0);
32
+ __decorate([
33
+ (0, typeorm_1.Column)({ type: 'varchar', length: 255 }),
34
+ __metadata("design:type", String)
35
+ ], InboxMessageEntity.prototype, "messageId", void 0);
36
+ __decorate([
37
+ (0, typeorm_1.Column)({ type: 'varchar', length: 255 }),
38
+ __metadata("design:type", String)
39
+ ], InboxMessageEntity.prototype, "source", void 0);
40
+ __decorate([
41
+ (0, typeorm_1.Column)({ type: 'varchar', length: 255 }),
42
+ __metadata("design:type", String)
43
+ ], InboxMessageEntity.prototype, "eventType", void 0);
44
+ __decorate([
45
+ (0, typeorm_1.Column)({ type: 'simple-json' }),
46
+ __metadata("design:type", Object)
47
+ ], InboxMessageEntity.prototype, "payload", void 0);
48
+ __decorate([
49
+ (0, typeorm_1.Column)({
50
+ type: 'enum',
51
+ enum: event_forge_core_1.InboxMessageStatus,
52
+ default: event_forge_core_1.InboxMessageStatus.RECEIVED,
53
+ }),
54
+ __metadata("design:type", String)
55
+ ], InboxMessageEntity.prototype, "status", void 0);
56
+ __decorate([
57
+ (0, typeorm_1.Column)({ type: 'timestamp', nullable: true }),
58
+ __metadata("design:type", Date)
59
+ ], InboxMessageEntity.prototype, "processedAt", void 0);
60
+ __decorate([
61
+ (0, typeorm_1.Column)({ type: 'text', nullable: true }),
62
+ __metadata("design:type", String)
63
+ ], InboxMessageEntity.prototype, "errorMessage", void 0);
64
+ __decorate([
65
+ (0, typeorm_1.CreateDateColumn)(),
66
+ __metadata("design:type", Date)
67
+ ], InboxMessageEntity.prototype, "createdAt", void 0);
68
+ __decorate([
69
+ (0, typeorm_1.CreateDateColumn)(),
70
+ __metadata("design:type", Date)
71
+ ], InboxMessageEntity.prototype, "receivedAt", void 0);
72
+ exports.InboxMessageEntity = InboxMessageEntity = __decorate([
73
+ (0, typeorm_1.Entity)('inbox_messages'),
74
+ (0, typeorm_1.Index)(['messageId', 'source'], { unique: true }),
75
+ (0, typeorm_1.Index)(['eventType']),
76
+ (0, typeorm_1.Index)(['status']),
77
+ (0, typeorm_1.Index)(['createdAt']),
78
+ (0, typeorm_1.Index)(['receivedAt'])
79
+ ], InboxMessageEntity);
80
+ //# sourceMappingURL=inbox-message.entity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inbox-message.entity.js","sourceRoot":"","sources":["../../src/entities/inbox-message.entity.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,oEAAiF;AACjF,qCAMiB;AAaV,IAAM,kBAAkB,GAAxB,MAAM,kBAAkB;IAE7B,EAAE,CAAS;IAGX,SAAS,CAAS;IAGlB,MAAM,CAAS;IAGf,SAAS,CAAS;IAGlB,OAAO,CAA0B;IAOjC,MAAM,CAAqB;IAG3B,WAAW,CAAQ;IAGnB,YAAY,CAAU;IAGtB,SAAS,CAAO;IAGhB,UAAU,CAAO;CAClB,CAAA;AAlCY,gDAAkB;AAE7B;IADC,IAAA,gCAAsB,EAAC,MAAM,CAAC;;8CACpB;AAGX;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;;qDACvB;AAGlB;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;;kDAC1B;AAGf;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;;qDACvB;AAGlB;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC;;mDACC;AAOjC;IALC,IAAA,gBAAM,EAAC;QACN,IAAI,EAAE,MAAM;QACZ,IAAI,EAAE,qCAAkB;QACxB,OAAO,EAAE,qCAAkB,CAAC,QAAQ;KACrC,CAAC;;kDACyB;AAG3B;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;8BAChC,IAAI;uDAAC;AAGnB;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;wDACnB;AAGtB;IADC,IAAA,0BAAgB,GAAE;8BACR,IAAI;qDAAC;AAGhB;IADC,IAAA,0BAAgB,GAAE;8BACP,IAAI;sDAAC;6BAjCN,kBAAkB;IAN9B,IAAA,gBAAM,EAAC,gBAAgB,CAAC;IACxB,IAAA,eAAK,EAAC,CAAC,WAAW,EAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;IAChD,IAAA,eAAK,EAAC,CAAC,WAAW,CAAC,CAAC;IACpB,IAAA,eAAK,EAAC,CAAC,QAAQ,CAAC,CAAC;IACjB,IAAA,eAAK,EAAC,CAAC,WAAW,CAAC,CAAC;IACpB,IAAA,eAAK,EAAC,CAAC,YAAY,CAAC,CAAC;GACT,kBAAkB,CAkC9B"}
@@ -0,0 +1,3 @@
1
+ export * from './inbox-message.entity';
2
+ export * from './outbox-message.entity';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/entities/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC"}
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./inbox-message.entity"), exports);
18
+ __exportStar(require("./outbox-message.entity"), exports);
19
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/entities/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,yDAAuC;AACvC,0DAAwC"}