@flusys/nestjs-core 3.0.1 → 4.0.0-rc

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.
@@ -133,7 +133,8 @@ let EnvConfigService = class EnvConfigService {
133
133
  dir: this.getValue('LOG_DIR', false) || 'logs',
134
134
  level: this.getValue('LOG_LEVEL', false) || (this.isProduction() ? 'info' : 'debug'),
135
135
  maxSize: this.getValue('LOG_MAX_SIZE', false) || '20m',
136
- maxFiles: this.getValue('LOG_MAX_FILES', false) || '14d'
136
+ maxFiles: this.getValue('LOG_MAX_FILES', false) || '14d',
137
+ disableHttpLogging: this.getValue('DISABLE_HTTP_LOGGING', false).toLowerCase() === 'true'
137
138
  };
138
139
  }
139
140
  getEnv() {
@@ -17,9 +17,7 @@ _export(exports, {
17
17
  }
18
18
  });
19
19
  const _swagger = require("@nestjs/swagger");
20
- /**
21
- * Filter OpenAPI document to exclude schema properties
22
- */ function filterSchemaProperties(document, exclusions) {
20
+ function filterSchemaProperties(document, exclusions) {
23
21
  if (!exclusions?.length || !document.components?.schemas) {
24
22
  return document;
25
23
  }
@@ -54,9 +52,7 @@ const _swagger = require("@nestjs/swagger");
54
52
  }
55
53
  };
56
54
  }
57
- /**
58
- * Filter OpenAPI document to exclude query parameters from specific endpoints
59
- */ function filterQueryParameters(document, exclusions) {
55
+ function filterQueryParameters(document, exclusions) {
60
56
  if (!exclusions?.length || !document.paths) {
61
57
  return document;
62
58
  }
@@ -102,9 +98,7 @@ const _swagger = require("@nestjs/swagger");
102
98
  paths: filteredPaths
103
99
  };
104
100
  }
105
- /**
106
- * Filter OpenAPI document to exclude examples from endpoint responses
107
- */ function filterExamples(document, exclusions) {
101
+ function filterExamples(document, exclusions) {
108
102
  if (!exclusions?.length || !document.paths) {
109
103
  return document;
110
104
  }
@@ -161,18 +155,14 @@ const _swagger = require("@nestjs/swagger");
161
155
  paths: filteredPaths
162
156
  };
163
157
  }
164
- /**
165
- * Check if a path matches a pattern (supports wildcards)
166
- */ function pathMatchesPattern(path, pattern) {
158
+ function pathMatchesPattern(path, pattern) {
167
159
  // Convert wildcard pattern to regex
168
160
  const regexPattern = pattern.replace(/\*/g, '[^/]+') // * matches any characters except /
169
161
  .replace(/\*\*/g, '.*'); // ** matches any characters including /
170
162
  const regex = new RegExp(`^${regexPattern}$`);
171
163
  return regex.test(path);
172
164
  }
173
- /**
174
- * Filter OpenAPI document to exclude paths and tags based on excludeTags
175
- */ function filterDocumentByTags(document, excludeTags) {
165
+ function filterDocumentByTags(document, excludeTags) {
176
166
  if (!excludeTags?.length) {
177
167
  return document;
178
168
  }
@@ -11,9 +11,7 @@ Object.defineProperty(exports, "DataGenerator", {
11
11
  const _faker = require("@faker-js/faker");
12
12
  const _fieldpatterns = require("./field-patterns");
13
13
  let DataGenerator = class DataGenerator {
14
- /**
15
- * Generate value for a single column based on its metadata
16
- */ generateValue(column) {
14
+ generateValue(column) {
17
15
  if (column.isGenerated) return undefined;
18
16
  // Handle nullable fields (50% chance of null)
19
17
  if (column.isNullable && _faker.faker.datatype.boolean()) return null;
@@ -30,9 +28,7 @@ let DataGenerator = class DataGenerator {
30
28
  // Generate based on column type
31
29
  return this.generateByType(column);
32
30
  }
33
- /**
34
- * Generate entity object from column definitions
35
- */ generateEntity(columns) {
31
+ generateEntity(columns) {
36
32
  const entity = {};
37
33
  for (const column of columns){
38
34
  const value = this.generateValue(column);
@@ -42,9 +38,7 @@ let DataGenerator = class DataGenerator {
42
38
  }
43
39
  return entity;
44
40
  }
45
- /**
46
- * Generate value based on detected field pattern
47
- */ generateByPattern(pattern, column) {
41
+ generateByPattern(pattern, column) {
48
42
  switch(pattern){
49
43
  case 'skip':
50
44
  return undefined;
@@ -125,13 +119,36 @@ let DataGenerator = class DataGenerator {
125
119
  'authenticated',
126
120
  'permission'
127
121
  ]);
122
+ case 'notificationType':
123
+ return _faker.faker.helpers.arrayElement([
124
+ 'INFO',
125
+ 'SUCCESS',
126
+ 'WARNING',
127
+ 'ERROR'
128
+ ]);
129
+ case 'languageCode':
130
+ return _faker.faker.helpers.arrayElement([
131
+ 'en',
132
+ 'ar',
133
+ 'bn',
134
+ 'es',
135
+ 'fr',
136
+ 'de',
137
+ 'zh',
138
+ 'ja',
139
+ 'ko',
140
+ 'hi'
141
+ ]);
142
+ case 'languageDirection':
143
+ return _faker.faker.helpers.arrayElement([
144
+ 'ltr',
145
+ 'rtl'
146
+ ]);
128
147
  default:
129
148
  return undefined;
130
149
  }
131
150
  }
132
- /**
133
- * Generate value based on column type
134
- */ generateByType(column) {
151
+ generateByType(column) {
135
152
  const category = (0, _fieldpatterns.detectTypeCategory)(column.type);
136
153
  switch(category){
137
154
  case 'string':
@@ -175,9 +192,7 @@ let DataGenerator = class DataGenerator {
175
192
  return _faker.faker.lorem.word();
176
193
  }
177
194
  }
178
- /**
179
- * Generate string value respecting length constraints
180
- */ generateString(column) {
195
+ generateString(column) {
181
196
  const maxLength = typeof column.length === 'number' ? column.length : 255;
182
197
  const category = (0, _fieldpatterns.getStringLengthCategory)(column.length);
183
198
  switch(category){
@@ -189,15 +204,11 @@ let DataGenerator = class DataGenerator {
189
204
  return _faker.faker.lorem.paragraph().substring(0, maxLength);
190
205
  }
191
206
  }
192
- /**
193
- * Generate related entity ID (for foreign keys)
194
- */ generateRelationId(relatedEntities) {
207
+ generateRelationId(relatedEntities) {
195
208
  if (relatedEntities.length === 0) return null;
196
209
  return _faker.faker.helpers.arrayElement(relatedEntities).id;
197
210
  }
198
- /**
199
- * Generate multiple related entity IDs (for many-to-many)
200
- */ generateRelationIds(relatedEntities, min = 1, max = 3) {
211
+ generateRelationIds(relatedEntities, min = 1, max = 3) {
201
212
  if (relatedEntities.length === 0) return [];
202
213
  const count = _faker.faker.number.int({
203
214
  min,
@@ -22,15 +22,10 @@ function _define_property(obj, key, value) {
22
22
  return obj;
23
23
  }
24
24
  let EntityReader = class EntityReader {
25
- /**
26
- * Get all entity metadata from DataSource
27
- */ getAllEntities() {
25
+ getAllEntities() {
28
26
  return this.dataSource.entityMetadatas;
29
27
  }
30
- /**
31
- * Get detailed entity information
32
- * @param entityName Entity class name or table name
33
- */ getEntityInfo(entityName) {
28
+ getEntityInfo(entityName) {
34
29
  const metadata = this.findEntityMetadata(entityName);
35
30
  if (!metadata) {
36
31
  throw new Error(`Entity ${entityName} not found in DataSource`);
@@ -44,29 +39,22 @@ let EntityReader = class EntityReader {
44
39
  hasCompany: this.hasCompanyColumn(metadata)
45
40
  };
46
41
  }
47
- /**
48
- * Get seeding order based on foreign key dependencies
49
- * Returns entity names sorted by dependency (independent entities first)
50
- */ getSeedingOrder(skipEntities = []) {
42
+ getSeedingOrder(skipEntities = []) {
51
43
  const entities = this.getAllEntities().filter((e)=>!skipEntities.includes(e.name) && !skipEntities.includes(e.tableName));
52
44
  const graph = this.buildDependencyGraph(entities);
53
45
  return this.topologicalSort(graph);
54
46
  }
55
- /**
56
- * Find entity metadata by name or table name
57
- */ findEntityMetadata(entityName) {
47
+ findEntityMetadata(entityName) {
58
48
  return this.getAllEntities().find((e)=>e.name === entityName || e.tableName === entityName);
59
49
  }
60
- /**
61
- * Extract column information from entity metadata
62
- */ extractColumns(metadata) {
50
+ extractColumns(metadata) {
63
51
  return metadata.columns.map((col)=>({
64
52
  name: col.databaseName,
65
53
  propertyName: col.propertyName,
66
54
  type: this.getColumnTypeString(col.type),
67
55
  length: col.length,
68
56
  isNullable: col.isNullable,
69
- isUnique: col.isUnique === true || false,
57
+ isUnique: 'isUnique' in col ? col.isUnique === true : false,
70
58
  isPrimary: col.isPrimary,
71
59
  isGenerated: col.isGenerated,
72
60
  default: col.default,
@@ -75,9 +63,7 @@ let EntityReader = class EntityReader {
75
63
  scale: col.scale ?? undefined
76
64
  }));
77
65
  }
78
- /**
79
- * Extract relation information from entity metadata
80
- */ extractRelations(metadata) {
66
+ extractRelations(metadata) {
81
67
  return metadata.relations.map((rel)=>({
82
68
  propertyName: rel.propertyName,
83
69
  type: rel.relationType,
@@ -86,14 +72,10 @@ let EntityReader = class EntityReader {
86
72
  joinColumnName: rel.joinColumns?.[0]?.databaseName
87
73
  }));
88
74
  }
89
- /**
90
- * Check if entity has company-related columns
91
- */ hasCompanyColumn(metadata) {
75
+ hasCompanyColumn(metadata) {
92
76
  return metadata.columns.some((col)=>col.propertyName === 'companyId' || col.databaseName === 'company_id');
93
77
  }
94
- /**
95
- * Convert TypeORM column type to string
96
- */ getColumnTypeString(type) {
78
+ getColumnTypeString(type) {
97
79
  if (typeof type === 'string') {
98
80
  return type;
99
81
  }
@@ -102,9 +84,7 @@ let EntityReader = class EntityReader {
102
84
  }
103
85
  return 'unknown';
104
86
  }
105
- /**
106
- * Build dependency graph for entities
107
- */ buildDependencyGraph(entities) {
87
+ buildDependencyGraph(entities) {
108
88
  const graph = new Map();
109
89
  for (const entity of entities){
110
90
  const dependencies = [];
@@ -117,9 +97,7 @@ let EntityReader = class EntityReader {
117
97
  }
118
98
  return graph;
119
99
  }
120
- /**
121
- * Topological sort for dependency resolution
122
- */ topologicalSort(graph) {
100
+ topologicalSort(graph) {
123
101
  const sorted = [];
124
102
  const visited = new Set();
125
103
  const visiting = new Set();
@@ -120,6 +120,12 @@ function detectFieldPattern(column) {
120
120
  if (nameLower === 'provider' || nameLower === 'emailprovider') return 'emailProvider';
121
121
  // Form access type
122
122
  if (nameLower === 'accesstype' || nameLower === 'access_type') return 'formAccessType';
123
+ // Notification type (short varchar for type fields)
124
+ if (nameLower === 'type') return 'notificationType';
125
+ // Language code (short varchar for language codes like 'en', 'ar', 'bn')
126
+ if (nameLower === 'code') return 'languageCode';
127
+ // Language direction (ltr/rtl)
128
+ if (nameLower === 'direction') return 'languageDirection';
123
129
  return undefined;
124
130
  }
125
131
  function detectTypeCategory(type) {
@@ -38,24 +38,13 @@ const defaultLogger = {
38
38
  error: (message)=>console.error(message)
39
39
  };
40
40
  let SeedRunner = class SeedRunner {
41
- /**
42
- * Register a custom seeder for specific entity
43
- * Custom seeders take precedence over generic seeders
44
- * @param entityName Entity name
45
- * @param seeder Custom seeder instance
46
- */ registerCustomSeeder(entityName, seeder) {
41
+ registerCustomSeeder(entityName, seeder) {
47
42
  this.customSeeders.set(entityName, seeder);
48
43
  }
49
- /**
50
- * Unregister a custom seeder
51
- * @param entityName Entity name
52
- */ unregisterCustomSeeder(entityName) {
44
+ unregisterCustomSeeder(entityName) {
53
45
  this.customSeeders.delete(entityName);
54
46
  }
55
- /**
56
- * Check if entity has custom seeder registered
57
- * @param entityName Entity name
58
- */ hasCustomSeeder(entityName) {
47
+ hasCustomSeeder(entityName) {
59
48
  return this.customSeeders.has(entityName);
60
49
  }
61
50
  getSeeder(entityName, entity, dataSource, entityInfo, batchSize) {
@@ -64,11 +53,7 @@ let SeedRunner = class SeedRunner {
64
53
  }
65
54
  return new GenericSeeder(dataSource, entity, this.dataGenerator, entityInfo, batchSize);
66
55
  }
67
- /**
68
- * Run seeds for all entities
69
- * @param options Seeding options
70
- * @returns Array of seed results
71
- */ async runAll(options = {}) {
56
+ async runAll(options = {}) {
72
57
  const results = [];
73
58
  const continueOnError = options.continueOnError ?? true;
74
59
  // Get all entities
@@ -111,12 +96,7 @@ let SeedRunner = class SeedRunner {
111
96
  }
112
97
  return results;
113
98
  }
114
- /**
115
- * Run seed for a single entity
116
- * @param entityName Entity name to seed
117
- * @param options Seeding options
118
- * @returns Seed result
119
- */ async runSingle(entityName, options = {}) {
99
+ async runSingle(entityName, options = {}) {
120
100
  const queryRunner = this.dataSource.createQueryRunner();
121
101
  await queryRunner.connect();
122
102
  await queryRunner.startTransaction();
@@ -180,12 +160,7 @@ let SeedRunner = class SeedRunner {
180
160
  await queryRunner.release();
181
161
  }
182
162
  }
183
- /**
184
- * Clear all seeded data
185
- * @param hard If true, hard delete (ignore soft delete)
186
- * @param continueOnError If true, continue even if an entity fails (default: true)
187
- * @returns Array of clear results
188
- */ async clearAll(hard = false, continueOnError = true) {
163
+ async clearAll(hard = false, continueOnError = true) {
189
164
  const results = [];
190
165
  // Get all entities
191
166
  const allEntities = this.entityReader.getAllEntities();
@@ -245,10 +220,7 @@ let SeedRunner = class SeedRunner {
245
220
  }
246
221
  return results;
247
222
  }
248
- /**
249
- * Get status for all entities
250
- * @returns Array of entity status
251
- */ async getStatus() {
223
+ async getStatus() {
252
224
  const allEntities = this.entityReader.getAllEntities();
253
225
  const status = [];
254
226
  for (const metadata of allEntities){
@@ -282,12 +254,7 @@ let SeedRunner = class SeedRunner {
282
254
  this.logger = logger ?? defaultLogger;
283
255
  }
284
256
  };
285
- /**
286
- * Generic Seeder Implementation
287
- *
288
- * Used by SeedRunner for entities without custom seeders.
289
- * Generates data based on entity metadata with batch processing support.
290
- */ let GenericSeeder = class GenericSeeder extends _baseseeder.BaseSeeder {
257
+ let GenericSeeder = class GenericSeeder extends _baseseeder.BaseSeeder {
291
258
  async generate(count) {
292
259
  const allSaved = [];
293
260
  // Process in batches to optimize memory usage for large datasets
@@ -36,6 +36,7 @@ declare class EnvConfigService {
36
36
  level: string;
37
37
  maxSize: string;
38
38
  maxFiles: string;
39
+ disableHttpLogging: boolean;
39
40
  };
40
41
  getEnv(): Record<string, string>;
41
42
  }
@@ -82,7 +82,8 @@ let EnvConfigService = class EnvConfigService {
82
82
  dir: this.getValue('LOG_DIR', false) || 'logs',
83
83
  level: this.getValue('LOG_LEVEL', false) || (this.isProduction() ? 'info' : 'debug'),
84
84
  maxSize: this.getValue('LOG_MAX_SIZE', false) || '20m',
85
- maxFiles: this.getValue('LOG_MAX_FILES', false) || '14d'
85
+ maxFiles: this.getValue('LOG_MAX_FILES', false) || '14d',
86
+ disableHttpLogging: this.getValue('DISABLE_HTTP_LOGGING', false).toLowerCase() === 'true'
86
87
  };
87
88
  }
88
89
  getEnv() {
@@ -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,9 +80,7 @@ import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
84
80
  paths: filteredPaths
85
81
  };
86
82
  }
87
- /**
88
- * Filter OpenAPI document to exclude examples from endpoint responses
89
- */ function filterExamples(document, exclusions) {
83
+ function filterExamples(document, exclusions) {
90
84
  if (!exclusions?.length || !document.paths) {
91
85
  return document;
92
86
  }
@@ -143,18 +137,14 @@ import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
143
137
  paths: filteredPaths
144
138
  };
145
139
  }
146
- /**
147
- * Check if a path matches a pattern (supports wildcards)
148
- */ function pathMatchesPattern(path, pattern) {
140
+ function pathMatchesPattern(path, pattern) {
149
141
  // Convert wildcard pattern to regex
150
142
  const regexPattern = pattern.replace(/\*/g, '[^/]+') // * matches any characters except /
151
143
  .replace(/\*\*/g, '.*'); // ** matches any characters including /
152
144
  const regex = new RegExp(`^${regexPattern}$`);
153
145
  return regex.test(path);
154
146
  }
155
- /**
156
- * Filter OpenAPI document to exclude paths and tags based on excludeTags
157
- */ function filterDocumentByTags(document, excludeTags) {
147
+ function filterDocumentByTags(document, excludeTags) {
158
148
  if (!excludeTags?.length) {
159
149
  return document;
160
150
  }
@@ -197,9 +187,7 @@ import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
197
187
  tags: filteredTags
198
188
  };
199
189
  }
200
- /**
201
- * Setup Swagger documentation for multiple modules
202
- */ export function setupModuleSwaggerDocs(app, configs) {
190
+ export function setupModuleSwaggerDocs(app, configs) {
203
191
  configs.forEach((config)=>{
204
192
  const builder = new DocumentBuilder().setTitle(config.title).setDescription(config.description).setVersion(config.version || '1.0');
205
193
  // Add bearer auth
@@ -245,8 +233,6 @@ import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
245
233
  SwaggerModule.setup(config.path, app, document);
246
234
  });
247
235
  }
248
- /**
249
- * Setup Swagger docs with variadic module configs
250
- */ export function setupSwaggerDocs(app, ...modules) {
236
+ export function setupSwaggerDocs(app, ...modules) {
251
237
  setupModuleSwaggerDocs(app, modules);
252
238
  }
@@ -1,14 +1,7 @@
1
1
  import { faker } from '@faker-js/faker';
2
2
  import { detectFieldPattern, detectTypeCategory, getStringLengthCategory, getTokenLength } from './field-patterns';
3
- /**
4
- * Data Generator Service
5
- *
6
- * Generates realistic sample data based on column metadata.
7
- * Uses @faker-js/faker for data generation with intelligent field detection.
8
- */ export class DataGenerator {
9
- /**
10
- * Generate value for a single column based on its metadata
11
- */ generateValue(column) {
3
+ export class DataGenerator {
4
+ generateValue(column) {
12
5
  if (column.isGenerated) return undefined;
13
6
  // Handle nullable fields (50% chance of null)
14
7
  if (column.isNullable && faker.datatype.boolean()) return null;
@@ -25,9 +18,7 @@ import { detectFieldPattern, detectTypeCategory, getStringLengthCategory, getTok
25
18
  // Generate based on column type
26
19
  return this.generateByType(column);
27
20
  }
28
- /**
29
- * Generate entity object from column definitions
30
- */ generateEntity(columns) {
21
+ generateEntity(columns) {
31
22
  const entity = {};
32
23
  for (const column of columns){
33
24
  const value = this.generateValue(column);
@@ -37,9 +28,7 @@ import { detectFieldPattern, detectTypeCategory, getStringLengthCategory, getTok
37
28
  }
38
29
  return entity;
39
30
  }
40
- /**
41
- * Generate value based on detected field pattern
42
- */ generateByPattern(pattern, column) {
31
+ generateByPattern(pattern, column) {
43
32
  switch(pattern){
44
33
  case 'skip':
45
34
  return undefined;
@@ -120,13 +109,36 @@ import { detectFieldPattern, detectTypeCategory, getStringLengthCategory, getTok
120
109
  'authenticated',
121
110
  'permission'
122
111
  ]);
112
+ case 'notificationType':
113
+ return faker.helpers.arrayElement([
114
+ 'INFO',
115
+ 'SUCCESS',
116
+ 'WARNING',
117
+ 'ERROR'
118
+ ]);
119
+ case 'languageCode':
120
+ return faker.helpers.arrayElement([
121
+ 'en',
122
+ 'ar',
123
+ 'bn',
124
+ 'es',
125
+ 'fr',
126
+ 'de',
127
+ 'zh',
128
+ 'ja',
129
+ 'ko',
130
+ 'hi'
131
+ ]);
132
+ case 'languageDirection':
133
+ return faker.helpers.arrayElement([
134
+ 'ltr',
135
+ 'rtl'
136
+ ]);
123
137
  default:
124
138
  return undefined;
125
139
  }
126
140
  }
127
- /**
128
- * Generate value based on column type
129
- */ generateByType(column) {
141
+ generateByType(column) {
130
142
  const category = detectTypeCategory(column.type);
131
143
  switch(category){
132
144
  case 'string':
@@ -170,9 +182,7 @@ import { detectFieldPattern, detectTypeCategory, getStringLengthCategory, getTok
170
182
  return faker.lorem.word();
171
183
  }
172
184
  }
173
- /**
174
- * Generate string value respecting length constraints
175
- */ generateString(column) {
185
+ generateString(column) {
176
186
  const maxLength = typeof column.length === 'number' ? column.length : 255;
177
187
  const category = getStringLengthCategory(column.length);
178
188
  switch(category){
@@ -184,15 +194,11 @@ import { detectFieldPattern, detectTypeCategory, getStringLengthCategory, getTok
184
194
  return faker.lorem.paragraph().substring(0, maxLength);
185
195
  }
186
196
  }
187
- /**
188
- * Generate related entity ID (for foreign keys)
189
- */ generateRelationId(relatedEntities) {
197
+ generateRelationId(relatedEntities) {
190
198
  if (relatedEntities.length === 0) return null;
191
199
  return faker.helpers.arrayElement(relatedEntities).id;
192
200
  }
193
- /**
194
- * Generate multiple related entity IDs (for many-to-many)
195
- */ generateRelationIds(relatedEntities, min = 1, max = 3) {
201
+ generateRelationIds(relatedEntities, min = 1, max = 3) {
196
202
  if (relatedEntities.length === 0) return [];
197
203
  const count = faker.number.int({
198
204
  min,
@@ -11,28 +11,11 @@ function _define_property(obj, key, value) {
11
11
  }
12
12
  return obj;
13
13
  }
14
- /**
15
- * Entity Reader Service
16
- *
17
- * Extracts metadata from TypeORM entities for seed data generation.
18
- * Discovers columns, types, constraints, and relationships.
19
- *
20
- * Usage:
21
- * ```typescript
22
- * const reader = new EntityReader(dataSource);
23
- * const entities = reader.getAllEntities();
24
- * const userInfo = reader.getEntityInfo('User');
25
- * ```
26
- */ export class EntityReader {
27
- /**
28
- * Get all entity metadata from DataSource
29
- */ getAllEntities() {
14
+ export class EntityReader {
15
+ getAllEntities() {
30
16
  return this.dataSource.entityMetadatas;
31
17
  }
32
- /**
33
- * Get detailed entity information
34
- * @param entityName Entity class name or table name
35
- */ getEntityInfo(entityName) {
18
+ getEntityInfo(entityName) {
36
19
  const metadata = this.findEntityMetadata(entityName);
37
20
  if (!metadata) {
38
21
  throw new Error(`Entity ${entityName} not found in DataSource`);
@@ -46,29 +29,22 @@ function _define_property(obj, key, value) {
46
29
  hasCompany: this.hasCompanyColumn(metadata)
47
30
  };
48
31
  }
49
- /**
50
- * Get seeding order based on foreign key dependencies
51
- * Returns entity names sorted by dependency (independent entities first)
52
- */ getSeedingOrder(skipEntities = []) {
32
+ getSeedingOrder(skipEntities = []) {
53
33
  const entities = this.getAllEntities().filter((e)=>!skipEntities.includes(e.name) && !skipEntities.includes(e.tableName));
54
34
  const graph = this.buildDependencyGraph(entities);
55
35
  return this.topologicalSort(graph);
56
36
  }
57
- /**
58
- * Find entity metadata by name or table name
59
- */ findEntityMetadata(entityName) {
37
+ findEntityMetadata(entityName) {
60
38
  return this.getAllEntities().find((e)=>e.name === entityName || e.tableName === entityName);
61
39
  }
62
- /**
63
- * Extract column information from entity metadata
64
- */ extractColumns(metadata) {
40
+ extractColumns(metadata) {
65
41
  return metadata.columns.map((col)=>({
66
42
  name: col.databaseName,
67
43
  propertyName: col.propertyName,
68
44
  type: this.getColumnTypeString(col.type),
69
45
  length: col.length,
70
46
  isNullable: col.isNullable,
71
- isUnique: col.isUnique === true || false,
47
+ isUnique: 'isUnique' in col ? col.isUnique === true : false,
72
48
  isPrimary: col.isPrimary,
73
49
  isGenerated: col.isGenerated,
74
50
  default: col.default,
@@ -77,9 +53,7 @@ function _define_property(obj, key, value) {
77
53
  scale: col.scale ?? undefined
78
54
  }));
79
55
  }
80
- /**
81
- * Extract relation information from entity metadata
82
- */ extractRelations(metadata) {
56
+ extractRelations(metadata) {
83
57
  return metadata.relations.map((rel)=>({
84
58
  propertyName: rel.propertyName,
85
59
  type: rel.relationType,
@@ -88,14 +62,10 @@ function _define_property(obj, key, value) {
88
62
  joinColumnName: rel.joinColumns?.[0]?.databaseName
89
63
  }));
90
64
  }
91
- /**
92
- * Check if entity has company-related columns
93
- */ hasCompanyColumn(metadata) {
65
+ hasCompanyColumn(metadata) {
94
66
  return metadata.columns.some((col)=>col.propertyName === 'companyId' || col.databaseName === 'company_id');
95
67
  }
96
- /**
97
- * Convert TypeORM column type to string
98
- */ getColumnTypeString(type) {
68
+ getColumnTypeString(type) {
99
69
  if (typeof type === 'string') {
100
70
  return type;
101
71
  }
@@ -104,9 +74,7 @@ function _define_property(obj, key, value) {
104
74
  }
105
75
  return 'unknown';
106
76
  }
107
- /**
108
- * Build dependency graph for entities
109
- */ buildDependencyGraph(entities) {
77
+ buildDependencyGraph(entities) {
110
78
  const graph = new Map();
111
79
  for (const entity of entities){
112
80
  const dependencies = [];
@@ -119,9 +87,7 @@ function _define_property(obj, key, value) {
119
87
  }
120
88
  return graph;
121
89
  }
122
- /**
123
- * Topological sort for dependency resolution
124
- */ topologicalSort(graph) {
90
+ topologicalSort(graph) {
125
91
  const sorted = [];
126
92
  const visited = new Set();
127
93
  const visiting = new Set();
@@ -1,4 +1,4 @@
1
- /** System fields that should be skipped during generation */ export const SYSTEM_FIELDS = [
1
+ export const SYSTEM_FIELDS = [
2
2
  'id',
3
3
  'createdAt',
4
4
  'updatedAt',
@@ -7,18 +7,18 @@
7
7
  'updatedById',
8
8
  'deletedById'
9
9
  ];
10
- /** Audit fields that return null */ export const AUDIT_FIELDS = [
10
+ export const AUDIT_FIELDS = [
11
11
  'createdbyid',
12
12
  'updatedbyid',
13
13
  'deletedbyid'
14
14
  ];
15
- /** Identity fields that are skipped */ export const IDENTITY_FIELDS = [
15
+ export const IDENTITY_FIELDS = [
16
16
  'id',
17
17
  'createdat',
18
18
  'updatedat',
19
19
  'deletedat'
20
20
  ];
21
- /** Boolean indicator keywords */ export const BOOLEAN_KEYWORDS = [
21
+ export const BOOLEAN_KEYWORDS = [
22
22
  'verified',
23
23
  'active',
24
24
  'enabled',
@@ -26,9 +26,7 @@
26
26
  'readonly',
27
27
  'valid'
28
28
  ];
29
- /**
30
- * Detect field pattern from column name
31
- */ export function detectFieldPattern(column) {
29
+ export function detectFieldPattern(column) {
32
30
  const nameLower = column.propertyName.toLowerCase();
33
31
  const typeLower = column.type.toLowerCase();
34
32
  // Identity fields (skip)
@@ -83,11 +81,15 @@
83
81
  if (nameLower === 'provider' || nameLower === 'emailprovider') return 'emailProvider';
84
82
  // Form access type
85
83
  if (nameLower === 'accesstype' || nameLower === 'access_type') return 'formAccessType';
84
+ // Notification type (short varchar for type fields)
85
+ if (nameLower === 'type') return 'notificationType';
86
+ // Language code (short varchar for language codes like 'en', 'ar', 'bn')
87
+ if (nameLower === 'code') return 'languageCode';
88
+ // Language direction (ltr/rtl)
89
+ if (nameLower === 'direction') return 'languageDirection';
86
90
  return undefined;
87
91
  }
88
- /**
89
- * Detect column type category
90
- */ export function detectTypeCategory(type) {
92
+ export function detectTypeCategory(type) {
91
93
  const typeLower = type.toLowerCase();
92
94
  if ([
93
95
  'varchar',
@@ -126,22 +128,16 @@
126
128
  if (typeLower === 'array') return 'array';
127
129
  return 'unknown';
128
130
  }
129
- /**
130
- * Get string length category for faker generation
131
- */ export function getStringLengthCategory(length) {
131
+ export function getStringLengthCategory(length) {
132
132
  const maxLength = typeof length === 'number' ? length : 255;
133
133
  if (maxLength <= 50) return 'word';
134
134
  if (maxLength <= 255) return 'sentence';
135
135
  return 'paragraph';
136
136
  }
137
- /**
138
- * Check if field is a system field
139
- */ export function isSystemField(fieldName) {
137
+ export function isSystemField(fieldName) {
140
138
  return SYSTEM_FIELDS.includes(fieldName);
141
139
  }
142
- /**
143
- * Get token max length respecting column constraints
144
- */ export function getTokenLength(column) {
140
+ export function getTokenLength(column) {
145
141
  const maxLength = typeof column.length === 'number' ? column.length : 64;
146
142
  return Math.min(maxLength, 32);
147
143
  }
@@ -15,50 +15,18 @@ import { EntityReader } from './entity-reader';
15
15
  import { DataGenerator } from './data-generator';
16
16
  import { BaseSeeder } from './base-seeder';
17
17
  import { seedConfig, getEntityCount, shouldSkipEntity, getSeedingOrder } from './seed-config';
18
- /**
19
- * Default console logger implementation
20
- */ export const defaultLogger = {
18
+ export const defaultLogger = {
21
19
  log: (message)=>console.log(message),
22
20
  error: (message)=>console.error(message)
23
21
  };
24
- /**
25
- * Seed Runner Service
26
- *
27
- * Orchestrates seed data generation across all entities.
28
- * Handles dependency order, transactions, and error reporting.
29
- *
30
- * Usage:
31
- * ```typescript
32
- * const runner = new SeedRunner(dataSource);
33
- * await runner.runAll();
34
- * await runner.runSingle('User', { count: 50 });
35
- * await runner.clearAll();
36
- *
37
- * // With custom logger
38
- * const runner = new SeedRunner(dataSource, customLogger);
39
- *
40
- * // With custom seeder
41
- * runner.registerCustomSeeder('User', new UserSeeder(dataSource));
42
- * ```
43
- */ export class SeedRunner {
44
- /**
45
- * Register a custom seeder for specific entity
46
- * Custom seeders take precedence over generic seeders
47
- * @param entityName Entity name
48
- * @param seeder Custom seeder instance
49
- */ registerCustomSeeder(entityName, seeder) {
22
+ export class SeedRunner {
23
+ registerCustomSeeder(entityName, seeder) {
50
24
  this.customSeeders.set(entityName, seeder);
51
25
  }
52
- /**
53
- * Unregister a custom seeder
54
- * @param entityName Entity name
55
- */ unregisterCustomSeeder(entityName) {
26
+ unregisterCustomSeeder(entityName) {
56
27
  this.customSeeders.delete(entityName);
57
28
  }
58
- /**
59
- * Check if entity has custom seeder registered
60
- * @param entityName Entity name
61
- */ hasCustomSeeder(entityName) {
29
+ hasCustomSeeder(entityName) {
62
30
  return this.customSeeders.has(entityName);
63
31
  }
64
32
  getSeeder(entityName, entity, dataSource, entityInfo, batchSize) {
@@ -67,11 +35,7 @@ import { seedConfig, getEntityCount, shouldSkipEntity, getSeedingOrder } from '.
67
35
  }
68
36
  return new GenericSeeder(dataSource, entity, this.dataGenerator, entityInfo, batchSize);
69
37
  }
70
- /**
71
- * Run seeds for all entities
72
- * @param options Seeding options
73
- * @returns Array of seed results
74
- */ async runAll(options = {}) {
38
+ async runAll(options = {}) {
75
39
  const results = [];
76
40
  const continueOnError = options.continueOnError ?? true;
77
41
  // Get all entities
@@ -114,12 +78,7 @@ import { seedConfig, getEntityCount, shouldSkipEntity, getSeedingOrder } from '.
114
78
  }
115
79
  return results;
116
80
  }
117
- /**
118
- * Run seed for a single entity
119
- * @param entityName Entity name to seed
120
- * @param options Seeding options
121
- * @returns Seed result
122
- */ async runSingle(entityName, options = {}) {
81
+ async runSingle(entityName, options = {}) {
123
82
  const queryRunner = this.dataSource.createQueryRunner();
124
83
  await queryRunner.connect();
125
84
  await queryRunner.startTransaction();
@@ -183,12 +142,7 @@ import { seedConfig, getEntityCount, shouldSkipEntity, getSeedingOrder } from '.
183
142
  await queryRunner.release();
184
143
  }
185
144
  }
186
- /**
187
- * Clear all seeded data
188
- * @param hard If true, hard delete (ignore soft delete)
189
- * @param continueOnError If true, continue even if an entity fails (default: true)
190
- * @returns Array of clear results
191
- */ async clearAll(hard = false, continueOnError = true) {
145
+ async clearAll(hard = false, continueOnError = true) {
192
146
  const results = [];
193
147
  // Get all entities
194
148
  const allEntities = this.entityReader.getAllEntities();
@@ -248,10 +202,7 @@ import { seedConfig, getEntityCount, shouldSkipEntity, getSeedingOrder } from '.
248
202
  }
249
203
  return results;
250
204
  }
251
- /**
252
- * Get status for all entities
253
- * @returns Array of entity status
254
- */ async getStatus() {
205
+ async getStatus() {
255
206
  const allEntities = this.entityReader.getAllEntities();
256
207
  const status = [];
257
208
  for (const metadata of allEntities){
@@ -285,12 +236,7 @@ import { seedConfig, getEntityCount, shouldSkipEntity, getSeedingOrder } from '.
285
236
  this.logger = logger ?? defaultLogger;
286
237
  }
287
238
  }
288
- /**
289
- * Generic Seeder Implementation
290
- *
291
- * Used by SeedRunner for entities without custom seeders.
292
- * Generates data based on entity metadata with batch processing support.
293
- */ let GenericSeeder = class GenericSeeder extends BaseSeeder {
239
+ let GenericSeeder = class GenericSeeder extends BaseSeeder {
294
240
  async generate(count) {
295
241
  const allSaved = [];
296
242
  // Process in batches to optimize memory usage for large datasets
@@ -31,5 +31,5 @@ export interface IDataSourceBuildOptions {
31
31
  migrations: string[];
32
32
  migrationsTableName: string;
33
33
  synchronize: boolean;
34
- namingStrategy?: any;
34
+ namingStrategy?: unknown;
35
35
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flusys/nestjs-core",
3
- "version": "3.0.1",
3
+ "version": "4.0.0-rc",
4
4
  "description": "Core types, interfaces, and constants for Flusys NestJS packages",
5
5
  "main": "cjs/index.js",
6
6
  "module": "fesm/index.js",
@@ -1,8 +1,8 @@
1
1
  import { IColumnInfo } from './entity-reader';
2
2
  export declare class DataGenerator {
3
3
  constructor(locale?: string);
4
- generateValue(column: IColumnInfo): any;
5
- generateEntity(columns: IColumnInfo[]): Record<string, any>;
4
+ generateValue(column: IColumnInfo): unknown;
5
+ generateEntity(columns: IColumnInfo[]): Record<string, unknown>;
6
6
  private generateByPattern;
7
7
  private generateByType;
8
8
  private generateString;
@@ -8,8 +8,8 @@ export interface IColumnInfo {
8
8
  isUnique: boolean;
9
9
  isPrimary: boolean;
10
10
  isGenerated: boolean;
11
- default?: any;
12
- enum?: any[];
11
+ default?: unknown;
12
+ enum?: unknown[];
13
13
  precision?: number;
14
14
  scale?: number;
15
15
  }
@@ -3,7 +3,7 @@ export declare const SYSTEM_FIELDS: string[];
3
3
  export declare const AUDIT_FIELDS: string[];
4
4
  export declare const IDENTITY_FIELDS: string[];
5
5
  export declare const BOOLEAN_KEYWORDS: string[];
6
- export type FieldPatternType = 'skip' | 'null' | 'boolean' | 'token' | 'firstName' | 'lastName' | 'fullName' | 'email' | 'phone' | 'address' | 'street' | 'city' | 'state' | 'country' | 'zipCode' | 'url' | 'domain' | 'slug' | 'description' | 'summary' | 'content' | 'title' | 'username' | 'password' | 'birthdate' | 'futureDate' | 'recentDateOrNull' | 'serial' | 'company' | 'emailProvider' | 'formAccessType';
6
+ export type FieldPatternType = 'skip' | 'null' | 'boolean' | 'token' | 'firstName' | 'lastName' | 'fullName' | 'email' | 'phone' | 'address' | 'street' | 'city' | 'state' | 'country' | 'zipCode' | 'url' | 'domain' | 'slug' | 'description' | 'summary' | 'content' | 'title' | 'username' | 'password' | 'birthdate' | 'futureDate' | 'recentDateOrNull' | 'serial' | 'company' | 'emailProvider' | 'formAccessType' | 'notificationType' | 'languageCode' | 'languageDirection';
7
7
  export type ColumnTypeCategory = 'string' | 'integer' | 'decimal' | 'boolean' | 'date' | 'timestamp' | 'time' | 'uuid' | 'json' | 'array' | 'unknown';
8
8
  export declare function detectFieldPattern(column: IColumnInfo): FieldPatternType | undefined;
9
9
  export declare function detectTypeCategory(type: string): ColumnTypeCategory;
@@ -1,4 +1,4 @@
1
- import { DataSource } from 'typeorm';
1
+ import { DataSource, ObjectLiteral } from 'typeorm';
2
2
  import { BaseSeeder } from './base-seeder';
3
3
  export interface ISeederLogger {
4
4
  log(message: string): void;
@@ -31,7 +31,7 @@ export declare class SeedRunner {
31
31
  private logger;
32
32
  private customSeeders;
33
33
  constructor(dataSource: DataSource, logger?: ISeederLogger);
34
- registerCustomSeeder(entityName: string, seeder: BaseSeeder<any>): void;
34
+ registerCustomSeeder(entityName: string, seeder: BaseSeeder<ObjectLiteral>): void;
35
35
  unregisterCustomSeeder(entityName: string): void;
36
36
  hasCustomSeeder(entityName: string): boolean;
37
37
  private getSeeder;