@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
@@ -4,26 +4,37 @@ import * as path from 'path';
4
4
  import { envConfig } from '../config';
5
5
  import { getActiveTenants, getDatabaseForTenant, getMigrationsFolderPath } from '../utils';
6
6
  import { initializeDataSource } from './datasource.factory';
7
- /**
8
- * Migration Runner Functions
9
- *
10
- * Core functions for executing migration operations.
11
- * Supports both single and multi-tenant database configurations.
12
- *
13
- * Functions:
14
- * - ensureMigrationsFolder: Create migrations directory
15
- * - generateMigration: Create new migration file
16
- * - runMigrations: Execute pending migrations
17
- * - revertMigration: Rollback last migration
18
- * - migrationStatus: Check migration status
19
- * - runForAllTenants: Batch operations for all tenants
20
- */ /**
21
- * Ensure migrations folder exists
22
- *
23
- * @param basePath - Base migrations path
24
- * @param tenantId - Optional tenant ID
25
- * @returns Full path to migrations folder
26
- */ export function ensureMigrationsFolder(basePath, tenantId) {
7
+ function getLabel(tenantId) {
8
+ return tenantId ? `[${tenantId}]` : '[default]';
9
+ }
10
+ async function withDataSource(config, tenantId, operation) {
11
+ const { database } = getDatabaseForTenant(config, tenantId);
12
+ const label = getLabel(tenantId);
13
+ try {
14
+ const ds = await initializeDataSource({
15
+ config,
16
+ tenantId
17
+ });
18
+ const partial = await operation(ds, label);
19
+ await ds.destroy();
20
+ return {
21
+ tenantId,
22
+ database,
23
+ success: true,
24
+ ...partial
25
+ };
26
+ } catch (error) {
27
+ const errorMessage = error instanceof Error ? error.message : String(error);
28
+ console.error(`${label} ✗ Failed: ${errorMessage}`);
29
+ return {
30
+ tenantId,
31
+ database,
32
+ success: false,
33
+ error: errorMessage
34
+ };
35
+ }
36
+ }
37
+ export function ensureMigrationsFolder(basePath, tenantId) {
27
38
  const folder = getMigrationsFolderPath(basePath, tenantId);
28
39
  if (!fs.existsSync(folder)) {
29
40
  fs.mkdirSync(folder, {
@@ -33,16 +44,7 @@ import { initializeDataSource } from './datasource.factory';
33
44
  }
34
45
  return folder;
35
46
  }
36
- /**
37
- * Generate a new migration file
38
- *
39
- * Uses TypeORM CLI to generate migration based on entity changes.
40
- *
41
- * @param config - Migration configuration
42
- * @param name - Migration name (e.g., "CreateUsers")
43
- * @param tenantId - Optional tenant ID for multi-tenant mode
44
- * @param datasourcePath - Optional path to datasource file
45
- */ export async function generateMigration(config, name, tenantId, datasourcePath) {
47
+ export async function generateMigration(config, name, tenantId, datasourcePath) {
46
48
  const label = tenantId ? `[${tenantId}]` : '[default]';
47
49
  const folder = ensureMigrationsFolder(config.migrationsPath, tenantId);
48
50
  console.log(`${label} Generating migration: ${name}`);
@@ -72,24 +74,9 @@ function findDatasourcePath() {
72
74
  }
73
75
  throw new Error('Could not find datasource file. Specify with --datasource=<path>');
74
76
  }
75
- /**
76
- * Run pending migrations
77
- *
78
- * Executes all pending migrations for the specified tenant or default database.
79
- *
80
- * @param config - Migration configuration
81
- * @param tenantId - Optional tenant ID for multi-tenant mode
82
- * @returns Migration result with success status
83
- */ export async function runMigrations(config, tenantId) {
84
- const { database } = getDatabaseForTenant(config, tenantId);
85
- const label = tenantId ? `[${tenantId}]` : '[default]';
86
- try {
87
- const ds = await initializeDataSource({
88
- config,
89
- tenantId
90
- });
77
+ export async function runMigrations(config, tenantId) {
78
+ return withDataSource(config, tenantId, async (ds, label)=>{
91
79
  const migrations = await ds.runMigrations();
92
- await ds.destroy();
93
80
  if (migrations.length === 0) {
94
81
  console.log(`${label} No pending migrations.`);
95
82
  } else {
@@ -97,105 +84,29 @@ function findDatasourcePath() {
97
84
  migrations.forEach((m)=>console.log(` - ${m.name}`));
98
85
  }
99
86
  return {
100
- tenantId,
101
- database,
102
- success: true,
103
87
  migrationsRun: migrations.map((m)=>m.name)
104
88
  };
105
- } catch (error) {
106
- const errorMessage = error instanceof Error ? error.message : String(error);
107
- console.error(`${label} ✗ Failed: ${errorMessage}`);
108
- return {
109
- tenantId,
110
- database,
111
- success: false,
112
- error: errorMessage
113
- };
114
- }
89
+ });
115
90
  }
116
- /**
117
- * Revert last migration
118
- *
119
- * Rolls back the most recently executed migration.
120
- *
121
- * @param config - Migration configuration
122
- * @param tenantId - Optional tenant ID for multi-tenant mode
123
- * @returns Migration result with success status
124
- */ export async function revertMigration(config, tenantId) {
125
- const { database } = getDatabaseForTenant(config, tenantId);
126
- const label = tenantId ? `[${tenantId}]` : '[default]';
127
- try {
128
- const ds = await initializeDataSource({
129
- config,
130
- tenantId
131
- });
91
+ export async function revertMigration(config, tenantId) {
92
+ return withDataSource(config, tenantId, async (ds, label)=>{
132
93
  await ds.undoLastMigration();
133
- await ds.destroy();
134
94
  console.log(`${label} ✓ Reverted!`);
135
- return {
136
- tenantId,
137
- database,
138
- success: true
139
- };
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
- }
95
+ return {};
96
+ });
150
97
  }
151
- /**
152
- * Check migration status
153
- *
154
- * Shows whether there are pending migrations to run.
155
- *
156
- * @param config - Migration configuration
157
- * @param tenantId - Optional tenant ID for multi-tenant mode
158
- * @returns Migration result with status information
159
- */ export async function migrationStatus(config, tenantId) {
160
- const { database } = getDatabaseForTenant(config, tenantId);
161
- const label = tenantId ? `[${tenantId}]` : '[default]';
162
- try {
163
- const ds = await initializeDataSource({
164
- config,
165
- tenantId
166
- });
98
+ export async function migrationStatus(config, tenantId) {
99
+ return withDataSource(config, tenantId, async (ds, label)=>{
167
100
  const hasPending = await ds.showMigrations();
168
- await ds.destroy();
169
101
  console.log(`${label} Pending: ${hasPending ? 'Yes' : 'No'}`);
170
102
  return {
171
- tenantId,
172
- database,
173
- success: true,
174
103
  migrationsRun: [
175
104
  hasPending ? 'Has pending' : 'Up to date'
176
105
  ]
177
106
  };
178
- } catch (error) {
179
- const errorMessage = error instanceof Error ? error.message : String(error);
180
- console.error(`${label} ✗ Failed: ${errorMessage}`);
181
- return {
182
- tenantId,
183
- database,
184
- success: false,
185
- error: errorMessage
186
- };
187
- }
107
+ });
188
108
  }
189
- /**
190
- * Run migration command for all tenants
191
- *
192
- * Executes the specified command for all active tenants in batch mode.
193
- * Only works in multi-tenant database mode.
194
- *
195
- * @param config - Migration configuration
196
- * @param command - Command to run: 'run', 'revert', or 'status'
197
- * @returns Array of migration results for each tenant
198
- */ export async function runForAllTenants(config, command) {
109
+ export async function runForAllTenants(config, command) {
199
110
  const tenants = getActiveTenants(config);
200
111
  console.log(`\n🔄 Running '${command}' for ${tenants.length} tenant(s)...\n`);
201
112
  const results = [];
@@ -45,7 +45,8 @@
45
45
  const defaultTenantConfig = {
46
46
  id: 'default',
47
47
  database: config.defaultDatabaseConfig.database || 'default',
48
- enableCompanyFeature: config.bootstrapAppConfig?.enableCompanyFeature ?? false
48
+ enableCompanyFeature: config.bootstrapAppConfig?.enableCompanyFeature ?? false,
49
+ permissionMode: config.bootstrapAppConfig?.permissionMode ?? 'FULL'
49
50
  };
50
51
  return {
51
52
  database: defaultTenantConfig.database,
@@ -60,18 +61,6 @@
60
61
  }
61
62
  return config.entities;
62
63
  }
63
- /**
64
- * Build full database config for a tenant
65
- */ export function buildTenantDatabaseConfig(baseConfig, tenant) {
66
- return {
67
- type: baseConfig.type,
68
- host: tenant.host ?? baseConfig.host,
69
- port: tenant.port ?? baseConfig.port,
70
- username: tenant.username ?? baseConfig.username,
71
- password: tenant.password ?? baseConfig.password,
72
- database: tenant.database
73
- };
74
- }
75
64
  /**
76
65
  * Get active tenants from config
77
66
  */ export function getActiveTenants(config) {
package/index.d.ts CHANGED
@@ -2,5 +2,4 @@ export * from './interfaces';
2
2
  export * from './constants';
3
3
  export * from './utils';
4
4
  export * from './migration';
5
- export * from './seeders';
6
5
  export * from './config';
@@ -3,6 +3,7 @@ export interface IBootstrapAppConfig {
3
3
  databaseMode: DatabaseMode;
4
4
  enableCompanyFeature: boolean;
5
5
  permissionMode?: 'FULL' | 'RBAC' | 'DIRECT';
6
+ enableEmailVerification?: boolean;
6
7
  }
7
8
  export interface IDynamicModuleConfig {
8
9
  global?: boolean;
@@ -14,6 +14,6 @@ export interface ITimestampable {
14
14
  export interface IOrderable {
15
15
  serial?: number | null;
16
16
  }
17
- export interface IMetadata {
18
- metadata?: Record<string, any> | null;
17
+ export interface ICompanyOwned {
18
+ companyId?: string | null;
19
19
  }
@@ -17,6 +17,7 @@ export interface ITenantDatabaseConfig {
17
17
  password?: string;
18
18
  database: string;
19
19
  enableCompanyFeature?: boolean;
20
+ enableEmailVerification?: boolean;
20
21
  permissionMode?: 'FULL' | 'RBAC' | 'DIRECT';
21
22
  }
22
23
  export interface IDataSourceBuildOptions {
@@ -30,5 +31,5 @@ export interface IDataSourceBuildOptions {
30
31
  migrations: string[];
31
32
  migrationsTableName: string;
32
33
  synchronize: boolean;
33
- namingStrategy?: any;
34
+ namingStrategy?: unknown;
34
35
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flusys/nestjs-core",
3
- "version": "1.1.0-beta",
3
+ "version": "1.2.0-rc.1",
4
4
  "description": "Core types, interfaces, and constants for Flusys NestJS packages",
5
5
  "main": "cjs/index.js",
6
6
  "module": "fesm/index.js",
@@ -61,15 +61,15 @@
61
61
  }
62
62
  },
63
63
  "peerDependencies": {
64
- "@faker-js/faker": "^9.0.0",
65
- "@nestjs/common": "^10.0.0 || ^11.0.0",
66
- "@nestjs/config": "^3.0.0 || ^4.0.0",
67
- "@nestjs/core": "^10.0.0 || ^11.0.0",
68
- "@nestjs/swagger": "^7.0.0 || ^11.0.0",
69
- "@nestjs/typeorm": "^10.0.0 || ^11.0.0",
70
- "dotenv": "^16.0.0",
64
+ "@faker-js/faker": "^10.0.0",
65
+ "@nestjs/common": "^11.0.0",
66
+ "@nestjs/config": "^4.0.0",
67
+ "@nestjs/core": "^11.0.0",
68
+ "@nestjs/swagger": "^11.0.0",
69
+ "@nestjs/typeorm": "^11.0.0",
70
+ "dotenv": "^17.0.0",
71
71
  "typeorm": "^0.3.0",
72
- "typeorm-naming-strategies": "^4.0.0"
72
+ "typeorm-naming-strategies": "^4.1.0"
73
73
  },
74
74
  "dependencies": {}
75
75
  }
@@ -9,5 +9,4 @@ export declare function getDatabaseForTenant(config: IMigrationConfig, tenantId?
9
9
  tenantConfig: ITenantDatabaseConfig;
10
10
  };
11
11
  export declare function resolveEntities(config: IMigrationConfig, tenantConfig?: ITenantDatabaseConfig): any[];
12
- export declare function buildTenantDatabaseConfig(baseConfig: IDatabaseConfig, tenant: ITenantDatabaseConfig): IDatabaseConfig;
13
12
  export declare function getActiveTenants(config: IMigrationConfig): ITenantDatabaseConfig[];
@@ -1,14 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", {
3
- value: true
4
- });
5
- Object.defineProperty(exports, "setupSwaggerDocs", {
6
- enumerable: true,
7
- get: function() {
8
- return setupSwaggerDocs;
9
- }
10
- });
11
- const _docsconfig = require("./docs.config");
12
- function setupSwaggerDocs(app, ...modules) {
13
- (0, _docsconfig.setupModuleSwaggerDocs)(app, modules);
14
- }
@@ -1,95 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", {
3
- value: true
4
- });
5
- Object.defineProperty(exports, "BaseSeeder", {
6
- enumerable: true,
7
- get: function() {
8
- return BaseSeeder;
9
- }
10
- });
11
- function _define_property(obj, key, value) {
12
- if (key in obj) {
13
- Object.defineProperty(obj, key, {
14
- value: value,
15
- enumerable: true,
16
- configurable: true,
17
- writable: true
18
- });
19
- } else {
20
- obj[key] = value;
21
- }
22
- return obj;
23
- }
24
- let BaseSeeder = class BaseSeeder {
25
- /**
26
- * Clear all records from the entity table
27
- * Respects soft delete if entity has deletedAt column
28
- * @param hard If true, perform hard delete (ignore soft delete)
29
- */ async clear(hard = false) {
30
- const hasSoftDelete = this.metadata.deleteDateColumn !== undefined;
31
- if (hard || !hasSoftDelete) {
32
- // Hard delete - remove all records
33
- await this.repository.clear();
34
- } else {
35
- // Soft delete - set deletedAt
36
- await this.repository.createQueryBuilder().softDelete().where('id IS NOT NULL').execute();
37
- }
38
- }
39
- /**
40
- * Get count of existing records
41
- * @param includeDeleted If true, count soft-deleted records
42
- * @returns Total record count
43
- */ async count(includeDeleted = false) {
44
- const hasSoftDelete = this.metadata.deleteDateColumn !== undefined;
45
- if (hasSoftDelete && !includeDeleted) {
46
- return this.repository.count({
47
- where: {
48
- deletedAt: null
49
- }
50
- });
51
- }
52
- return this.repository.count();
53
- }
54
- /**
55
- * Check if entity has any records
56
- * @returns True if no records exist
57
- */ async isEmpty() {
58
- const total = await this.count();
59
- return total === 0;
60
- }
61
- /**
62
- * Get entity name for logging
63
- */ getEntityName() {
64
- return this.metadata.tableName;
65
- }
66
- /**
67
- * Wrap operation in transaction
68
- * @param operation Function to execute in transaction
69
- */ async withTransaction(operation) {
70
- const queryRunner = this.dataSource.createQueryRunner();
71
- await queryRunner.connect();
72
- await queryRunner.startTransaction();
73
- try {
74
- const transactionalRepo = queryRunner.manager.getRepository(this.entity);
75
- const result = await operation(transactionalRepo);
76
- await queryRunner.commitTransaction();
77
- return result;
78
- } catch (error) {
79
- await queryRunner.rollbackTransaction();
80
- throw error;
81
- } finally{
82
- await queryRunner.release();
83
- }
84
- }
85
- constructor(dataSource, entity){
86
- _define_property(this, "dataSource", void 0);
87
- _define_property(this, "entity", void 0);
88
- _define_property(this, "repository", void 0);
89
- _define_property(this, "metadata", void 0);
90
- this.dataSource = dataSource;
91
- this.entity = entity;
92
- this.repository = dataSource.getRepository(entity);
93
- this.metadata = this.repository.metadata;
94
- }
95
- };