@flusys/nestjs-core 1.1.0-beta → 1.2.0-rc.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 (61) hide show
  1. package/README.md +136 -162
  2. package/cjs/config/env-config.service.js +14 -10
  3. package/cjs/docs/docs.config.js +99 -15
  4. package/cjs/docs/index.js +0 -1
  5. package/cjs/index.js +0 -1
  6. package/cjs/interfaces/base-entity.interface.js +5 -3
  7. package/cjs/interfaces/database.interface.js +1 -3
  8. package/cjs/migration/datasource.factory.js +1 -3
  9. package/cjs/migration/index.js +0 -12
  10. package/cjs/migration/migration.cli.js +1 -17
  11. package/cjs/migration/migration.runner.js +37 -65
  12. package/cjs/utils/datasource-config.builder.js +2 -14
  13. package/config/env-config.service.d.ts +3 -1
  14. package/docs/docs.config.d.ts +8 -0
  15. package/docs/index.d.ts +0 -1
  16. package/fesm/config/env-config.service.js +14 -10
  17. package/fesm/docs/docs.config.js +89 -15
  18. package/fesm/docs/index.js +0 -1
  19. package/fesm/index.js +0 -2
  20. package/fesm/interfaces/app-config.interfaces.js +1 -3
  21. package/fesm/interfaces/base-entity.interface.js +5 -5
  22. package/fesm/interfaces/database.interface.js +1 -5
  23. package/fesm/migration/cli.js +1 -20
  24. package/fesm/migration/datasource.factory.js +3 -20
  25. package/fesm/migration/index.js +0 -14
  26. package/fesm/migration/migration.cli.js +1 -17
  27. package/fesm/migration/migration.runner.js +43 -132
  28. package/fesm/utils/datasource-config.builder.js +2 -13
  29. package/index.d.ts +0 -1
  30. package/interfaces/app-config.interfaces.d.ts +1 -0
  31. package/interfaces/base-entity.interface.d.ts +2 -2
  32. package/interfaces/database.interface.d.ts +2 -1
  33. package/package.json +9 -9
  34. package/utils/datasource-config.builder.d.ts +0 -1
  35. package/cjs/docs/docs.setup.js +0 -14
  36. package/cjs/seeders/base-seeder.js +0 -95
  37. package/cjs/seeders/cli.js +0 -398
  38. package/cjs/seeders/data-generator.js +0 -247
  39. package/cjs/seeders/entity-reader.js +0 -168
  40. package/cjs/seeders/index.js +0 -77
  41. package/cjs/seeders/seed-config.js +0 -101
  42. package/cjs/seeders/seed-runner.js +0 -320
  43. package/cjs/seeders/template-generator.js +0 -297
  44. package/docs/docs.setup.d.ts +0 -3
  45. package/fesm/docs/docs.setup.js +0 -4
  46. package/fesm/seeders/base-seeder.js +0 -110
  47. package/fesm/seeders/cli.js +0 -366
  48. package/fesm/seeders/data-generator.js +0 -249
  49. package/fesm/seeders/entity-reader.js +0 -170
  50. package/fesm/seeders/index.js +0 -11
  51. package/fesm/seeders/seed-config.js +0 -85
  52. package/fesm/seeders/seed-runner.js +0 -323
  53. package/fesm/seeders/template-generator.js +0 -257
  54. package/seeders/base-seeder.d.ts +0 -14
  55. package/seeders/cli.d.ts +0 -3
  56. package/seeders/data-generator.d.ts +0 -15
  57. package/seeders/entity-reader.d.ts +0 -45
  58. package/seeders/index.d.ts +0 -7
  59. package/seeders/seed-config.d.ts +0 -11
  60. package/seeders/seed-runner.d.ts +0 -47
  61. package/seeders/template-generator.d.ts +0 -16
@@ -75,6 +75,36 @@ function _interop_require_wildcard(obj, nodeInterop) {
75
75
  }
76
76
  return newObj;
77
77
  }
78
+ function getLabel(tenantId) {
79
+ return tenantId ? `[${tenantId}]` : '[default]';
80
+ }
81
+ async function withDataSource(config, tenantId, operation) {
82
+ const { database } = (0, _utils.getDatabaseForTenant)(config, tenantId);
83
+ const label = getLabel(tenantId);
84
+ try {
85
+ const ds = await (0, _datasourcefactory.initializeDataSource)({
86
+ config,
87
+ tenantId
88
+ });
89
+ const partial = await operation(ds, label);
90
+ await ds.destroy();
91
+ return {
92
+ tenantId,
93
+ database,
94
+ success: true,
95
+ ...partial
96
+ };
97
+ } catch (error) {
98
+ const errorMessage = error instanceof Error ? error.message : String(error);
99
+ console.error(`${label} āœ— Failed: ${errorMessage}`);
100
+ return {
101
+ tenantId,
102
+ database,
103
+ success: false,
104
+ error: errorMessage
105
+ };
106
+ }
107
+ }
78
108
  function ensureMigrationsFolder(basePath, tenantId) {
79
109
  const folder = (0, _utils.getMigrationsFolderPath)(basePath, tenantId);
80
110
  if (!_fs.existsSync(folder)) {
@@ -116,15 +146,8 @@ function findDatasourcePath() {
116
146
  throw new Error('Could not find datasource file. Specify with --datasource=<path>');
117
147
  }
118
148
  async function runMigrations(config, tenantId) {
119
- const { database } = (0, _utils.getDatabaseForTenant)(config, tenantId);
120
- const label = tenantId ? `[${tenantId}]` : '[default]';
121
- try {
122
- const ds = await (0, _datasourcefactory.initializeDataSource)({
123
- config,
124
- tenantId
125
- });
149
+ return withDataSource(config, tenantId, async (ds, label)=>{
126
150
  const migrations = await ds.runMigrations();
127
- await ds.destroy();
128
151
  if (migrations.length === 0) {
129
152
  console.log(`${label} No pending migrations.`);
130
153
  } else {
@@ -132,78 +155,27 @@ async function runMigrations(config, tenantId) {
132
155
  migrations.forEach((m)=>console.log(` - ${m.name}`));
133
156
  }
134
157
  return {
135
- tenantId,
136
- database,
137
- success: true,
138
158
  migrationsRun: migrations.map((m)=>m.name)
139
159
  };
140
- } catch (error) {
141
- const errorMessage = error instanceof Error ? error.message : String(error);
142
- console.error(`${label} āœ— Failed: ${errorMessage}`);
143
- return {
144
- tenantId,
145
- database,
146
- success: false,
147
- error: errorMessage
148
- };
149
- }
160
+ });
150
161
  }
151
162
  async function revertMigration(config, tenantId) {
152
- const { database } = (0, _utils.getDatabaseForTenant)(config, tenantId);
153
- const label = tenantId ? `[${tenantId}]` : '[default]';
154
- try {
155
- const ds = await (0, _datasourcefactory.initializeDataSource)({
156
- config,
157
- tenantId
158
- });
163
+ return withDataSource(config, tenantId, async (ds, label)=>{
159
164
  await ds.undoLastMigration();
160
- await ds.destroy();
161
165
  console.log(`${label} āœ“ Reverted!`);
162
- return {
163
- tenantId,
164
- database,
165
- success: true
166
- };
167
- } catch (error) {
168
- const errorMessage = error instanceof Error ? error.message : String(error);
169
- console.error(`${label} āœ— Failed: ${errorMessage}`);
170
- return {
171
- tenantId,
172
- database,
173
- success: false,
174
- error: errorMessage
175
- };
176
- }
166
+ return {};
167
+ });
177
168
  }
178
169
  async function migrationStatus(config, tenantId) {
179
- const { database } = (0, _utils.getDatabaseForTenant)(config, tenantId);
180
- const label = tenantId ? `[${tenantId}]` : '[default]';
181
- try {
182
- const ds = await (0, _datasourcefactory.initializeDataSource)({
183
- config,
184
- tenantId
185
- });
170
+ return withDataSource(config, tenantId, async (ds, label)=>{
186
171
  const hasPending = await ds.showMigrations();
187
- await ds.destroy();
188
172
  console.log(`${label} Pending: ${hasPending ? 'Yes' : 'No'}`);
189
173
  return {
190
- tenantId,
191
- database,
192
- success: true,
193
174
  migrationsRun: [
194
175
  hasPending ? 'Has pending' : 'Up to date'
195
176
  ]
196
177
  };
197
- } catch (error) {
198
- const errorMessage = error instanceof Error ? error.message : String(error);
199
- console.error(`${label} āœ— Failed: ${errorMessage}`);
200
- return {
201
- tenantId,
202
- database,
203
- success: false,
204
- error: errorMessage
205
- };
206
- }
178
+ });
207
179
  }
208
180
  async function runForAllTenants(config, command) {
209
181
  const tenants = (0, _utils.getActiveTenants)(config);
@@ -12,9 +12,6 @@ _export(exports, {
12
12
  get buildDataSourceOptions () {
13
13
  return buildDataSourceOptions;
14
14
  },
15
- get buildTenantDatabaseConfig () {
16
- return buildTenantDatabaseConfig;
17
- },
18
15
  get getActiveTenants () {
19
16
  return getActiveTenants;
20
17
  },
@@ -70,7 +67,8 @@ function getDatabaseForTenant(config, tenantId) {
70
67
  const defaultTenantConfig = {
71
68
  id: 'default',
72
69
  database: config.defaultDatabaseConfig.database || 'default',
73
- enableCompanyFeature: config.bootstrapAppConfig?.enableCompanyFeature ?? false
70
+ enableCompanyFeature: config.bootstrapAppConfig?.enableCompanyFeature ?? false,
71
+ permissionMode: config.bootstrapAppConfig?.permissionMode ?? 'FULL'
74
72
  };
75
73
  return {
76
74
  database: defaultTenantConfig.database,
@@ -83,16 +81,6 @@ function resolveEntities(config, tenantConfig) {
83
81
  }
84
82
  return config.entities;
85
83
  }
86
- function buildTenantDatabaseConfig(baseConfig, tenant) {
87
- return {
88
- type: baseConfig.type,
89
- host: tenant.host ?? baseConfig.host,
90
- port: tenant.port ?? baseConfig.port,
91
- username: tenant.username ?? baseConfig.username,
92
- password: tenant.password ?? baseConfig.password,
93
- database: tenant.database
94
- };
95
- }
96
84
  function getActiveTenants(config) {
97
85
  return config.tenants || [];
98
86
  }
@@ -10,13 +10,14 @@ declare class EnvConfigService {
10
10
  getBoolean(key: string, throwOnMissing?: boolean): boolean;
11
11
  getPort(): number;
12
12
  isProduction(): boolean;
13
- getFrontendUrl(): string;
14
13
  getOrigins(): string[];
15
14
  getTypeOrmConfig(): {
15
+ type: "mysql" | "postgres" | "mariadb" | "sqlite" | "mssql";
16
16
  host: string;
17
17
  port: number;
18
18
  username: string;
19
19
  password: string;
20
+ database: string;
20
21
  };
21
22
  getJwtConfig(): {
22
23
  secret: string;
@@ -36,6 +37,7 @@ declare class EnvConfigService {
36
37
  level: string;
37
38
  maxSize: string;
38
39
  maxFiles: string;
40
+ disableHttpLogging: boolean;
39
41
  };
40
42
  getEnv(): Record<string, string>;
41
43
  }
@@ -14,6 +14,11 @@ export interface IQueryParameterExclusion {
14
14
  method?: string;
15
15
  parameters: string[];
16
16
  }
17
+ export interface IExampleExclusion {
18
+ pathPattern: string;
19
+ method?: string;
20
+ examples: string[];
21
+ }
17
22
  export interface IModuleSwaggerOptions {
18
23
  modules?: Type<unknown>[];
19
24
  title: string;
@@ -25,5 +30,8 @@ export interface IModuleSwaggerOptions {
25
30
  excludeTags?: string[];
26
31
  excludeSchemaProperties?: ISchemaPropertyExclusion[];
27
32
  excludeQueryParameters?: IQueryParameterExclusion[];
33
+ excludeExamples?: IExampleExclusion[];
34
+ excludePaths?: string[];
28
35
  }
29
36
  export declare function setupModuleSwaggerDocs(app: INestApplication, configs: IModuleSwaggerOptions[]): void;
37
+ export declare function setupSwaggerDocs(app: INestApplication, ...modules: IModuleSwaggerOptions[]): void;
package/docs/index.d.ts CHANGED
@@ -1,2 +1 @@
1
1
  export * from './docs.config';
2
- export * from './docs.setup';
@@ -34,24 +34,25 @@ let EnvConfigService = class EnvConfigService {
34
34
  return this.getValue(key, throwOnMissing).toLowerCase() === 'true';
35
35
  }
36
36
  getPort() {
37
- return this.getNumber('PORT', false);
37
+ return this.getNumber('PORT', false) || 3000;
38
38
  }
39
39
  isProduction() {
40
40
  return this.getValue('MODE', false).toUpperCase() !== 'DEV';
41
41
  }
42
- getFrontendUrl() {
43
- return this.getValue('FRONTEND_URL');
44
- }
45
42
  getOrigins() {
46
43
  const origins = this.getValue('ALLOW_ORIGINS');
47
44
  return origins ? origins.split(',').map((o)=>o.trim()) : [];
48
45
  }
49
46
  getTypeOrmConfig() {
47
+ const type = this.getValue('DB_TYPE', false) || 'mysql';
48
+ const defaultPort = type === 'postgres' ? 5432 : 3306;
50
49
  return {
51
- host: this.getValue('DB_HOST'),
52
- port: this.getNumber('DB_PORT'),
53
- username: this.getValue('DB_USER'),
54
- password: this.getValue('DB_PASSWORD')
50
+ type,
51
+ host: this.getValue('DB_HOST', false) || 'localhost',
52
+ port: this.getNumber('DB_PORT', false) || defaultPort,
53
+ username: this.getValue('DB_USER', false) || 'root',
54
+ password: this.getValue('DB_PASSWORD', false) || '',
55
+ database: this.getValue('DB_NAME', false) || 'flusys_main'
55
56
  };
56
57
  }
57
58
  getJwtConfig() {
@@ -82,7 +83,8 @@ let EnvConfigService = class EnvConfigService {
82
83
  dir: this.getValue('LOG_DIR', false) || 'logs',
83
84
  level: this.getValue('LOG_LEVEL', false) || (this.isProduction() ? 'info' : 'debug'),
84
85
  maxSize: this.getValue('LOG_MAX_SIZE', false) || '20m',
85
- maxFiles: this.getValue('LOG_MAX_FILES', false) || '14d'
86
+ maxFiles: this.getValue('LOG_MAX_FILES', false) || '14d',
87
+ disableHttpLogging: this.getValue('DISABLE_HTTP_LOGGING', false).toLowerCase() === 'true'
86
88
  };
87
89
  }
88
90
  getEnv() {
@@ -97,10 +99,12 @@ let EnvConfigService = class EnvConfigService {
97
99
  ALLOW_ORIGINS: 'getOrigins',
98
100
  PORT: 'getPort',
99
101
  MODE: 'isProduction',
102
+ DB_TYPE: 'getTypeOrmConfig',
100
103
  DB_HOST: 'getTypeOrmConfig',
101
104
  DB_PORT: 'getTypeOrmConfig',
102
105
  DB_USER: 'getTypeOrmConfig',
103
- DB_PASSWORD: 'getTypeOrmConfig'
106
+ DB_PASSWORD: 'getTypeOrmConfig',
107
+ DB_NAME: 'getTypeOrmConfig'
104
108
  };
105
109
  }
106
110
  };
@@ -1,7 +1,5 @@
1
1
  import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
2
- /**
3
- * Filter OpenAPI document to exclude schema properties
4
- */ function filterSchemaProperties(document, exclusions) {
2
+ function filterSchemaProperties(document, exclusions) {
5
3
  if (!exclusions?.length || !document.components?.schemas) {
6
4
  return document;
7
5
  }
@@ -36,9 +34,7 @@ import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
36
34
  }
37
35
  };
38
36
  }
39
- /**
40
- * Filter OpenAPI document to exclude query parameters from specific endpoints
41
- */ function filterQueryParameters(document, exclusions) {
37
+ function filterQueryParameters(document, exclusions) {
42
38
  if (!exclusions?.length || !document.paths) {
43
39
  return document;
44
40
  }
@@ -84,18 +80,87 @@ import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
84
80
  paths: filteredPaths
85
81
  };
86
82
  }
87
- /**
88
- * Check if a path matches a pattern (supports wildcards)
89
- */ function pathMatchesPattern(path, pattern) {
83
+ function filterExamples(document, exclusions) {
84
+ if (!exclusions?.length || !document.paths) {
85
+ return document;
86
+ }
87
+ const filteredPaths = {};
88
+ for (const [path, pathItem] of Object.entries(document.paths)){
89
+ const filteredPathItem = {};
90
+ for (const [method, operation] of Object.entries(pathItem)){
91
+ // Skip non-operation properties
92
+ if (!operation || typeof operation !== 'object') {
93
+ filteredPathItem[method] = operation;
94
+ continue;
95
+ }
96
+ // Check if this endpoint matches any exclusion pattern
97
+ const matchingExclusions = exclusions.filter((exclusion)=>{
98
+ const pathMatches = pathMatchesPattern(path, exclusion.pathPattern);
99
+ const methodMatches = !exclusion.method || exclusion.method === method;
100
+ return pathMatches && methodMatches;
101
+ });
102
+ if (matchingExclusions.length > 0) {
103
+ // Collect all examples to exclude
104
+ const examplesToExclude = new Set();
105
+ matchingExclusions.forEach((exclusion)=>{
106
+ exclusion.examples.forEach((example)=>examplesToExclude.add(example));
107
+ });
108
+ // Deep clone the operation to avoid mutating original
109
+ const filteredOperation = JSON.parse(JSON.stringify(operation));
110
+ // Filter examples from responses
111
+ if (filteredOperation.responses) {
112
+ for (const [statusCode, response] of Object.entries(filteredOperation.responses)){
113
+ const responseObj = response;
114
+ if (responseObj?.content) {
115
+ const content = responseObj.content;
116
+ for (const [mediaType, mediaTypeObj] of Object.entries(content)){
117
+ const media = mediaTypeObj;
118
+ if (media?.examples && typeof media.examples === 'object') {
119
+ const examples = media.examples;
120
+ for (const exampleName of examplesToExclude){
121
+ delete examples[exampleName];
122
+ }
123
+ }
124
+ }
125
+ }
126
+ }
127
+ }
128
+ filteredPathItem[method] = filteredOperation;
129
+ } else {
130
+ filteredPathItem[method] = operation;
131
+ }
132
+ }
133
+ filteredPaths[path] = filteredPathItem;
134
+ }
135
+ return {
136
+ ...document,
137
+ paths: filteredPaths
138
+ };
139
+ }
140
+ function pathMatchesPattern(path, pattern) {
90
141
  // Convert wildcard pattern to regex
91
142
  const regexPattern = pattern.replace(/\*/g, '[^/]+') // * matches any characters except /
92
143
  .replace(/\*\*/g, '.*'); // ** matches any characters including /
93
144
  const regex = new RegExp(`^${regexPattern}$`);
94
145
  return regex.test(path);
95
146
  }
96
- /**
97
- * Filter OpenAPI document to exclude paths and tags based on excludeTags
98
- */ function filterDocumentByTags(document, excludeTags) {
147
+ function filterPaths(document, excludePaths) {
148
+ if (!excludePaths?.length || !document.paths) {
149
+ return document;
150
+ }
151
+ const filteredPaths = {};
152
+ for (const [path, pathItem] of Object.entries(document.paths)){
153
+ const isExcluded = excludePaths.some((pattern)=>pathMatchesPattern(path, pattern));
154
+ if (!isExcluded) {
155
+ filteredPaths[path] = pathItem;
156
+ }
157
+ }
158
+ return {
159
+ ...document,
160
+ paths: filteredPaths
161
+ };
162
+ }
163
+ function filterDocumentByTags(document, excludeTags) {
99
164
  if (!excludeTags?.length) {
100
165
  return document;
101
166
  }
@@ -138,9 +203,7 @@ import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
138
203
  tags: filteredTags
139
204
  };
140
205
  }
141
- /**
142
- * Setup Swagger documentation for multiple modules
143
- */ export function setupModuleSwaggerDocs(app, configs) {
206
+ export function setupModuleSwaggerDocs(app, configs) {
144
207
  configs.forEach((config)=>{
145
208
  const builder = new DocumentBuilder().setTitle(config.title).setDescription(config.description).setVersion(config.version || '1.0');
146
209
  // Add bearer auth
@@ -167,6 +230,10 @@ import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
167
230
  include: config.modules
168
231
  } : {};
169
232
  let document = SwaggerModule.createDocument(app, builder.build(), createDocOptions);
233
+ // Filter out excluded paths
234
+ if (config.excludePaths?.length) {
235
+ document = filterPaths(document, config.excludePaths);
236
+ }
170
237
  // Filter out excluded tags
171
238
  if (config.excludeTags?.length) {
172
239
  document = filterDocumentByTags(document, config.excludeTags);
@@ -179,6 +246,13 @@ import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
179
246
  if (config.excludeQueryParameters?.length) {
180
247
  document = filterQueryParameters(document, config.excludeQueryParameters);
181
248
  }
249
+ // Filter out excluded examples
250
+ if (config.excludeExamples?.length) {
251
+ document = filterExamples(document, config.excludeExamples);
252
+ }
182
253
  SwaggerModule.setup(config.path, app, document);
183
254
  });
184
255
  }
256
+ export function setupSwaggerDocs(app, ...modules) {
257
+ setupModuleSwaggerDocs(app, modules);
258
+ }
@@ -1,2 +1 @@
1
1
  export * from './docs.config';
2
- export * from './docs.setup';
package/fesm/index.js CHANGED
@@ -6,7 +6,5 @@ export * from './constants';
6
6
  export * from './utils';
7
7
  // Migration
8
8
  export * from './migration';
9
- // Seeders
10
- export * from './seeders';
11
9
  // Config
12
10
  export * from './config';
@@ -1,3 +1 @@
1
- /**
2
- * Async module options - common pattern for NestJS async module registration
3
- */ export { };
1
+ /** Async module options pattern */ export { };
@@ -1,6 +1,6 @@
1
1
  /**
2
- * Base Entity Interface
3
- * All entities should implement this for consistency
4
- */ /**
5
- * Entity with metadata
6
- */ export { };
2
+ * Entity Contract Interfaces
3
+ *
4
+ * These interfaces define the standard fields that entities should have.
5
+ * Use them as contracts when implementing new entities.
6
+ */ /** Base entity with UUID, timestamps, and soft delete */ /** Entity with company relation (for multi-company support) */ export { };
@@ -1,5 +1 @@
1
- /**
2
- * Supported database types
3
- */ /**
4
- * DataSource build options for TypeORM
5
- */ export { };
1
+ export { };
@@ -1,24 +1,5 @@
1
1
  #!/usr/bin/env node
2
- /**
3
- * Migration CLI Entry Point
4
- *
5
- * Main executable for running TypeORM migrations via npm scripts.
6
- *
7
- * Usage (via package.json scripts):
8
- * - npm run migration generate --name=CreateUsers
9
- * - npm run migration run
10
- * - npm run migration revert
11
- * - npm run migration status
12
- * - npm run migration run:all (multi-tenant)
13
- * - npm run migration revert:all (multi-tenant)
14
- * - npm run migration status:all (multi-tenant)
15
- *
16
- * Environment Variables:
17
- * - TENANT_ID: Target specific tenant (optional)
18
- *
19
- * This file is the executable entry point referenced in package.json.
20
- * The actual CLI logic is in migration.cli.ts (runMigrationCli function).
21
- */ import { runMigrationCli } from './migration.cli';
2
+ import { runMigrationCli } from './migration.cli';
22
3
  runMigrationCli().catch((err)=>{
23
4
  console.error('CLI Error:', err.message);
24
5
  process.exit(1);
@@ -1,20 +1,12 @@
1
1
  import { DataSource } from 'typeorm';
2
2
  import { SnakeNamingStrategy } from 'typeorm-naming-strategies';
3
3
  import { buildDataSourceOptions, getDatabaseForTenant, getMigrationsGlobPattern, resolveEntities } from '../utils/datasource-config.builder';
4
- /**
5
- * Create a DataSource for migrations
6
- *
7
- * @param options - Configuration options
8
- * @param options.config - Migration configuration
9
- * @param options.tenantId - Optional tenant ID for multi-tenant mode
10
- * @returns DataSource instance (not initialized)
11
- */ export function createMigrationDataSource(options) {
4
+ export function createMigrationDataSource(options) {
12
5
  const { config, tenantId } = options;
13
6
  const { database, tenant, tenantConfig } = getDatabaseForTenant(config, tenantId);
14
- // Log target info
15
7
  console.log(`\nšŸ“¦ Database: ${database}${tenant ? ` [${tenant.name}]` : ' [default]'}`);
16
8
  console.log(`šŸ“ Migrations: migrations/${tenantId || 'default'}/`);
17
- if (config.bootstrapAppConfig?.databaseMode == 'multi-tenant' && !tenantId && config.tenants && config.tenants.length > 0) {
9
+ if (config.bootstrapAppConfig?.databaseMode === 'multi-tenant' && !tenantId && config.tenants && config.tenants.length > 0) {
18
10
  console.log(`\nšŸ’” Multi-tenant mode. Available tenants:`);
19
11
  config.tenants.forEach((t)=>console.log(` - TENANT_ID=${t.id} → ${t.database}`));
20
12
  }
@@ -29,7 +21,6 @@ import { buildDataSourceOptions, getDatabaseForTenant, getMigrationsGlobPattern,
29
21
  ...config.defaultDatabaseConfig,
30
22
  database
31
23
  };
32
- // Resolve entities based on tenant config
33
24
  const entities = resolveEntities(config, tenantConfig);
34
25
  const dsOptions = buildDataSourceOptions(dbConfig, entities, getMigrationsGlobPattern(config.migrationsPath, tenantId), config.migrationsTableName);
35
26
  return new DataSource({
@@ -37,15 +28,7 @@ import { buildDataSourceOptions, getDatabaseForTenant, getMigrationsGlobPattern,
37
28
  namingStrategy: new SnakeNamingStrategy()
38
29
  });
39
30
  }
40
- /**
41
- * Initialize and return a DataSource
42
- *
43
- * Creates a DataSource and initializes the connection.
44
- * The connection should be destroyed after use with `ds.destroy()`.
45
- *
46
- * @param options - Configuration options
47
- * @returns Initialized DataSource instance
48
- */ export async function initializeDataSource(options) {
31
+ export async function initializeDataSource(options) {
49
32
  const ds = createMigrationDataSource(options);
50
33
  await ds.initialize();
51
34
  return ds;
@@ -1,17 +1,3 @@
1
- /**
2
- * Migration Module Exports
3
- *
4
- * Public API for TypeORM migration management in single and multi-tenant databases.
5
- *
6
- * Main exports:
7
- * - createMigrationDataSource: Create DataSource for migrations
8
- * - initializeDataSource: Create and initialize DataSource
9
- * - runMigrationCli: Programmatic CLI execution
10
- *
11
- * The CLI entry point is at ./cli.ts (used by npm scripts)
12
- */ // DataSource factory for migration config files
13
1
  export { createMigrationDataSource, initializeDataSource } from './datasource.factory';
14
- // CLI service for programmatic usage
15
2
  export { runMigrationCli } from './migration.cli';
16
- // Migration runner functions (optional, for advanced usage)
17
3
  export { generateMigration, runMigrations, revertMigration, migrationStatus, runForAllTenants, ensureMigrationsFolder } from './migration.runner';
@@ -2,23 +2,7 @@ import * as path from 'path';
2
2
  import { envConfig } from '../config';
3
3
  import { getDatabaseForTenant, getMigrationsFolderPath } from '../utils';
4
4
  import { generateMigration, migrationStatus, revertMigration, runForAllTenants, runMigrations } from './migration.runner';
5
- /**
6
- * Migration CLI Service
7
- *
8
- * Handles migration command execution for single and multi-tenant databases.
9
- *
10
- * Commands:
11
- * - generate: Create new migration
12
- * - run: Execute pending migrations
13
- * - revert: Rollback last migration
14
- * - status: Check migration status
15
- * - run:all/revert:all/status:all: Batch operations for all tenants
16
- *
17
- * Configuration:
18
- * - TENANT_ID: Target tenant (optional, defaults to default database)
19
- * - --config=<path>: Migration config file path
20
- * - --datasource=<path>: DataSource file path for TypeORM CLI
21
- */ function showHelp() {
5
+ function showHelp() {
22
6
  console.log(`
23
7
  Migration CLI
24
8