@flusys/nestjs-core 2.0.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # Core Package Guide
2
2
 
3
3
  > **Package:** `@flusys/nestjs-core`
4
+ > **Version:** 3.0.0
4
5
  > **Type:** Pure TypeScript foundation (zero NestJS dependencies)
5
6
 
6
7
  Foundation layer providing type-safe configuration, database utilities, migration CLI, seeders with intelligent pattern detection, and Swagger setup.
@@ -29,7 +30,7 @@ nestjs-core/src/
29
30
  ├── interfaces/
30
31
  │ ├── app-config.interfaces.ts # IBootstrapAppConfig, IDynamicModuleConfig
31
32
  │ ├── base-entity.interface.ts # IBaseEntity, ISoftDeletable, ITimestampable
32
- │ ├── database.interface.ts # IDatabaseConfig, ITenantDatabaseConfig
33
+ │ ├── database.interface.ts # IDatabaseConfig, ITenantDatabaseConfig, IDataSourceBuildOptions
33
34
  │ └── migration.interface.ts # IMigrationConfig, IMigrationResult
34
35
  ├── utils/
35
36
  │ └── datasource-config.builder.ts # DataSource utilities
@@ -45,8 +46,7 @@ nestjs-core/src/
45
46
  │ ├── seed-config.ts # Global seed configuration
46
47
  │ ├── entity-reader.ts # TypeORM metadata extraction
47
48
  │ ├── data-generator.ts # Faker.js data generation
48
- ├── field-patterns.ts # Intelligent field pattern detection
49
- │ └── template-generator.ts # Seeder template generation
49
+ └── field-patterns.ts # Intelligent field pattern detection
50
50
  ├── docs/
51
51
  │ └── docs.config.ts # Swagger setup utilities
52
52
  └── index.ts
@@ -64,8 +64,7 @@ import { envConfig } from '@flusys/nestjs-core/config';
64
64
 
65
65
  | Method | Description |
66
66
  |--------|-------------|
67
- | `tryGetValue(key)` | Get env value (throws for restricted keys) |
68
- | `getValue(key, throwOnMissing?)` | Raw string access |
67
+ | `tryGetValue(key, throwOnMissing?)` | Get env value (throws for restricted keys) |
69
68
  | `getNumber(key, throwOnMissing?)` | Get env value as number |
70
69
  | `getBoolean(key, throwOnMissing?)` | Get env value as boolean |
71
70
  | `getPort()` | Get PORT (default: 3000) |
@@ -73,13 +72,13 @@ import { envConfig } from '@flusys/nestjs-core/config';
73
72
  | `getFrontendUrl()` | Get FRONTEND_URL |
74
73
  | `getOrigins()` | Get ALLOW_ORIGINS as comma-separated array |
75
74
  | `getTypeOrmConfig()` | Get database config |
76
- | `getJwtConfig()` | Get JWT secret + expiration |
75
+ | `getJwtConfig()` | Get JWT config (secret, expiration, refreshSecret, refreshExpiration) |
77
76
  | `getRedisUrl()` | Get Redis connection URL (default: redis://localhost:6379) |
78
77
  | `getMailConfig()` | Get mail configuration (MAIL_FROM, MAIL_APP_PASSWORD) |
79
78
  | `getTenantId()` | Get TENANT_ID |
80
79
  | `useTenantMode()` | Check USE_TENANT_MODE |
81
- | `getLogConfig()` | Get logging configuration |
82
- | `getEnv()` | Get all env vars as Record |
80
+ | `getLogConfig()` | Get logging config `{ dir, level, maxSize, maxFiles }` |
81
+ | `getEnv()` | Get all env vars as `Record<string, string>` |
83
82
 
84
83
  ### Restricted Keys
85
84
 
@@ -121,6 +120,7 @@ interface ITenantDatabaseConfig {
121
120
  username?: string;
122
121
  password?: string;
123
122
  enableCompanyFeature?: boolean;
123
+ enableEmailVerification?: boolean;
124
124
  permissionMode?: 'FULL' | 'RBAC' | 'DIRECT';
125
125
  }
126
126
 
@@ -128,6 +128,21 @@ interface IBootstrapAppConfig {
128
128
  databaseMode: 'single' | 'multi-tenant';
129
129
  enableCompanyFeature: boolean;
130
130
  permissionMode?: 'FULL' | 'RBAC' | 'DIRECT';
131
+ enableEmailVerification?: boolean;
132
+ }
133
+
134
+ interface IDataSourceBuildOptions {
135
+ type: string;
136
+ host?: string;
137
+ port?: number;
138
+ username?: string;
139
+ password?: string;
140
+ database: string;
141
+ entities: any[];
142
+ migrations: string[];
143
+ migrationsTableName: string;
144
+ synchronize: boolean;
145
+ namingStrategy?: any;
131
146
  }
132
147
  ```
133
148
 
@@ -151,7 +166,7 @@ interface ITimestampable {
151
166
  }
152
167
 
153
168
  interface IOrderable {
154
- serial?: number;
169
+ serial?: number | null;
155
170
  }
156
171
 
157
172
  interface IMetadata {
@@ -289,13 +304,17 @@ import { SeedRunner, ISeedOptions, ISeedResult } from '@flusys/nestjs-core/seede
289
304
 
290
305
  const runner = new SeedRunner(dataSource, logger?);
291
306
 
292
- // Register custom seeders (take precedence over generic)
293
- runner.registerCustomSeeder('User', new UserSeeder(dataSource));
307
+ // Custom seeder management
308
+ runner.registerCustomSeeder('User', new UserSeeder(dataSource)); // Register
309
+ runner.unregisterCustomSeeder('User'); // Unregister
310
+ runner.hasCustomSeeder('User'); // Check: boolean
294
311
 
295
312
  // Run all entities in dependency order
296
313
  const results: ISeedResult[] = await runner.runAll({
297
314
  count: 50, // Records per entity
298
315
  clear: true, // Clear before seeding
316
+ entity: 'User', // Seed specific entity only
317
+ respectSoftDelete: true, // Use soft delete when clearing
299
318
  skipIfExists: false, // Skip if data exists
300
319
  dryRun: false, // Preview without executing
301
320
  continueOnError: true, // Continue on failures
@@ -316,9 +335,21 @@ const status = await runner.getStatus();
316
335
 
317
336
  ### Custom Seeders
318
337
 
338
+ Extend `BaseSeeder<T>` for entity-specific seeding logic:
339
+
319
340
  ```typescript
320
341
  import { BaseSeeder, DataGenerator } from '@flusys/nestjs-core/seeders';
321
342
 
343
+ // BaseSeeder provides:
344
+ // - repository: Repository<T> - TypeORM repository
345
+ // - metadata: EntityMetadata - Entity metadata
346
+ // - generate(count): Promise<T[]> - Abstract (must implement)
347
+ // - clear(hard?): Promise<void> - Clear entity data
348
+ // - count(includeDeleted?): Promise<number>
349
+ // - isEmpty(): Promise<boolean>
350
+ // - getEntityName(): string
351
+ // - withTransaction(fn): Promise<R>
352
+
322
353
  class UserSeeder extends BaseSeeder<User> {
323
354
  private generator: DataGenerator;
324
355
 
@@ -346,6 +377,51 @@ runner.registerCustomSeeder('User', new UserSeeder(dataSource));
346
377
  await runner.runAll({ count: 50, clear: true });
347
378
  ```
348
379
 
380
+ ### Seeder Interfaces
381
+
382
+ ```typescript
383
+ interface ISeedResult {
384
+ entity: string;
385
+ success: boolean;
386
+ count: number;
387
+ error?: string;
388
+ dryRun?: boolean;
389
+ skipped?: boolean;
390
+ }
391
+
392
+ interface IEntityInfo {
393
+ name: string;
394
+ tableName: string;
395
+ columns: IColumnInfo[];
396
+ relations: IRelationInfo[];
397
+ hasSoftDelete: boolean;
398
+ hasCompany: boolean;
399
+ }
400
+
401
+ interface IColumnInfo {
402
+ name: string;
403
+ propertyName: string;
404
+ type: string;
405
+ length?: number | string;
406
+ isNullable: boolean;
407
+ isUnique: boolean;
408
+ isPrimary: boolean;
409
+ isGenerated: boolean;
410
+ default?: any;
411
+ enum?: any[];
412
+ precision?: number;
413
+ scale?: number;
414
+ }
415
+
416
+ interface IRelationInfo {
417
+ propertyName: string;
418
+ type: 'one-to-one' | 'one-to-many' | 'many-to-one' | 'many-to-many';
419
+ targetEntity: string;
420
+ isNullable: boolean;
421
+ joinColumnName?: string;
422
+ }
423
+ ```
424
+
349
425
  ### EntityReader
350
426
 
351
427
  Extracts TypeORM metadata for intelligent seeding:
@@ -360,7 +436,6 @@ const entities = reader.getAllEntities();
360
436
 
361
437
  // Get detailed entity info
362
438
  const info: IEntityInfo = reader.getEntityInfo('User');
363
- // Returns: { name, tableName, columns, relations, hasSoftDelete, hasCompany }
364
439
 
365
440
  // Get seeding order (topological sort by FK dependencies)
366
441
  const order: string[] = reader.getSeedingOrder(skipEntities?);
@@ -396,11 +471,14 @@ Intelligent field pattern detection for realistic data generation.
396
471
  ### Supported Patterns
397
472
 
398
473
  ```typescript
399
- import { detectFieldPattern, FieldPatternType } from '@flusys/nestjs-core/seeders';
474
+ import { detectFieldPattern } from '@flusys/nestjs-core/seeders';
400
475
 
401
- // Pattern detection returns one of 58 patterns:
476
+ // Pattern detection returns one of 30 patterns:
402
477
  type FieldPatternType =
403
- | 'skip' | 'null' | 'boolean' | 'token'
478
+ | 'skip' // System fields (id, createdAt, etc.)
479
+ | 'null' // Audit fields (createdById, etc.)
480
+ | 'boolean' // Boolean fields with keywords
481
+ | 'token' // Token fields
404
482
  | 'firstName' | 'lastName' | 'fullName'
405
483
  | 'email' | 'phone'
406
484
  | 'address' | 'street' | 'city' | 'state' | 'country' | 'zipCode'
@@ -409,7 +487,8 @@ type FieldPatternType =
409
487
  | 'username' | 'password'
410
488
  | 'birthdate' | 'futureDate' | 'recentDateOrNull'
411
489
  | 'serial' | 'company'
412
- | /* ...more */;
490
+ | 'emailProvider' // smtp, sendgrid, mailgun, ses, postmark
491
+ | 'formAccessType'; // public, authenticated, permission
413
492
 
414
493
  // Detect pattern for a column
415
494
  const pattern = detectFieldPattern(column);
@@ -417,28 +496,34 @@ const pattern = detectFieldPattern(column);
417
496
 
418
497
  ### System Fields
419
498
 
420
- Automatically handled fields:
499
+ Automatically handled fields (public API exports `SYSTEM_FIELDS` only):
421
500
 
422
501
  ```typescript
423
- import { SYSTEM_FIELDS, AUDIT_FIELDS, IDENTITY_FIELDS, BOOLEAN_KEYWORDS } from '@flusys/nestjs-core/seeders';
502
+ import { SYSTEM_FIELDS, isSystemField } from '@flusys/nestjs-core/seeders';
503
+
504
+ // Exported constant
505
+ SYSTEM_FIELDS = ['id', 'createdAt', 'updatedAt', 'deletedAt', 'createdById', 'updatedById', 'deletedById'];
506
+
507
+ // Check if a field is a system field
508
+ isSystemField('createdAt'); // true
424
509
 
425
- SYSTEM_FIELDS = ['id', 'createdAt', 'updatedAt', 'deletedAt', ...];
426
- AUDIT_FIELDS = ['createdbyid', 'updatedbyid', 'deletedbyid'];
427
- IDENTITY_FIELDS = ['id', 'createdat', 'updatedat', 'deletedat'];
428
- BOOLEAN_KEYWORDS = ['verified', 'active', 'enabled', 'public', 'readonly', 'valid'];
510
+ // Internal constants (not exported, for reference only):
511
+ // AUDIT_FIELDS = ['createdbyid', 'updatedbyid', 'deletedbyid'];
512
+ // IDENTITY_FIELDS = ['id', 'createdat', 'updatedat', 'deletedat'];
513
+ // BOOLEAN_KEYWORDS = ['verified', 'active', 'enabled', 'public', 'readonly', 'valid'];
429
514
  ```
430
515
 
431
516
  ### Type Category Detection
432
517
 
433
518
  ```typescript
434
- import { detectTypeCategory, getStringLengthCategory } from '@flusys/nestjs-core/seeders';
519
+ import { detectTypeCategory } from '@flusys/nestjs-core/seeders';
435
520
 
436
521
  // Categorize database type
437
522
  const category = detectTypeCategory('varchar'); // 'string'
438
523
  // Categories: string | integer | decimal | boolean | date | timestamp | time | uuid | json | array | unknown
439
524
 
440
- // String length categorization
441
- const lengthCategory = getStringLengthCategory(255); // 'sentence'
525
+ // Internal utility (not exported): getStringLengthCategory()
526
+ // String length categorization:
442
527
  // ≤ 50 chars → 'word'
443
528
  // ≤ 255 chars → 'sentence'
444
529
  // > 255 chars → 'paragraph'
@@ -490,6 +575,19 @@ interface IQueryParameterExclusion {
490
575
  method?: string; // Optional: 'post', 'get', etc.
491
576
  parameters: string[];
492
577
  }
578
+
579
+ interface ISwaggerGlobalHeader {
580
+ name: string;
581
+ description: string;
582
+ required?: boolean;
583
+ example?: string;
584
+ }
585
+
586
+ interface IExampleExclusion {
587
+ pathPattern: string; // Supports wildcards: /auth/*
588
+ method?: string; // Optional: 'post', 'get', etc.
589
+ examples: string[]; // Example names to exclude
590
+ }
493
591
  ```
494
592
 
495
593
  ### Conditional Schema Exclusion
@@ -515,15 +613,21 @@ setupModuleSwaggerDocs(app, [{
515
613
 
516
614
  ```typescript
517
615
  import {
616
+ // Database
518
617
  IDatabaseConfig,
519
618
  ITenantDatabaseConfig,
619
+ IDataSourceBuildOptions,
620
+ // App Config
520
621
  IBootstrapAppConfig,
521
622
  IDynamicModuleConfig,
522
623
  IDataSourceServiceOptions,
523
624
  IModuleOptionsFactory,
524
625
  IAsyncModuleOptions,
626
+ // Migration
525
627
  IMigrationConfig,
526
628
  IMigrationResult,
629
+ EntityResolver,
630
+ // Entity Contracts
527
631
  IBaseEntity,
528
632
  ISoftDeletable,
529
633
  ITimestampable,
@@ -578,39 +682,38 @@ import {
578
682
 
579
683
  ```typescript
580
684
  import {
685
+ // Classes
581
686
  BaseSeeder,
582
687
  SeedRunner,
583
688
  EntityReader,
584
689
  DataGenerator,
585
- TemplateGenerator,
586
- seedConfig,
587
- ISeedConfig,
588
- configureSeedConfig,
589
- runSeedCli,
590
- getEntityCount,
591
- shouldSkipEntity,
592
- getSeedingOrder,
690
+ // Interfaces
593
691
  ISeedResult,
594
692
  ISeedOptions,
595
693
  ISeederLogger,
596
- defaultLogger,
597
694
  IEntityInfo,
598
695
  IColumnInfo,
599
696
  IRelationInfo,
600
- // Field patterns
697
+ ISeedConfig,
698
+ // Functions
699
+ defaultLogger,
700
+ seedConfig,
701
+ configureSeedConfig,
702
+ runSeedCli,
703
+ getEntityCount,
704
+ shouldSkipEntity,
705
+ getSeedingOrder,
706
+ // Field pattern functions
601
707
  detectFieldPattern,
602
708
  detectTypeCategory,
603
- getStringLengthCategory,
604
709
  isSystemField,
605
- getTokenLength,
606
- FieldPatternType,
710
+ // Constants
607
711
  SYSTEM_FIELDS,
608
- AUDIT_FIELDS,
609
- IDENTITY_FIELDS,
610
- BOOLEAN_KEYWORDS,
611
712
  } from '@flusys/nestjs-core/seeders';
612
713
  ```
613
714
 
715
+ > **Note:** The following are internal utilities in `field-patterns.ts` not exported from the public API: `FieldPatternType` (type), `ColumnTypeCategory` (type), `AUDIT_FIELDS`, `IDENTITY_FIELDS`, `BOOLEAN_KEYWORDS`, `getStringLengthCategory`, `getTokenLength`.
716
+
614
717
  ### Swagger
615
718
 
616
719
  ```typescript
@@ -636,4 +739,4 @@ import {
636
739
 
637
740
  ---
638
741
 
639
- **Last Updated:** 2026-02-21
742
+ **Last Updated:** 2026-02-25
@@ -111,6 +111,20 @@ let DataGenerator = class DataGenerator {
111
111
  });
112
112
  case 'company':
113
113
  return _faker.faker.company.name();
114
+ case 'emailProvider':
115
+ return _faker.faker.helpers.arrayElement([
116
+ 'smtp',
117
+ 'sendgrid',
118
+ 'mailgun',
119
+ 'ses',
120
+ 'postmark'
121
+ ]);
122
+ case 'formAccessType':
123
+ return _faker.faker.helpers.arrayElement([
124
+ 'public',
125
+ 'authenticated',
126
+ 'permission'
127
+ ]);
114
128
  default:
115
129
  return undefined;
116
130
  }
@@ -116,6 +116,10 @@ function detectFieldPattern(column) {
116
116
  if (nameLower.includes('serial') || nameLower.includes('order')) return 'serial';
117
117
  // Company
118
118
  if (nameLower.includes('company') && !nameLower.includes('id')) return 'company';
119
+ // Email provider type
120
+ if (nameLower === 'provider' || nameLower === 'emailprovider') return 'emailProvider';
121
+ // Form access type
122
+ if (nameLower === 'accesstype' || nameLower === 'access_type') return 'formAccessType';
119
123
  return undefined;
120
124
  }
121
125
  function detectTypeCategory(type) {
@@ -106,6 +106,20 @@ import { detectFieldPattern, detectTypeCategory, getStringLengthCategory, getTok
106
106
  });
107
107
  case 'company':
108
108
  return faker.company.name();
109
+ case 'emailProvider':
110
+ return faker.helpers.arrayElement([
111
+ 'smtp',
112
+ 'sendgrid',
113
+ 'mailgun',
114
+ 'ses',
115
+ 'postmark'
116
+ ]);
117
+ case 'formAccessType':
118
+ return faker.helpers.arrayElement([
119
+ 'public',
120
+ 'authenticated',
121
+ 'permission'
122
+ ]);
109
123
  default:
110
124
  return undefined;
111
125
  }
@@ -79,6 +79,10 @@
79
79
  if (nameLower.includes('serial') || nameLower.includes('order')) return 'serial';
80
80
  // Company
81
81
  if (nameLower.includes('company') && !nameLower.includes('id')) return 'company';
82
+ // Email provider type
83
+ if (nameLower === 'provider' || nameLower === 'emailprovider') return 'emailProvider';
84
+ // Form access type
85
+ if (nameLower === 'accesstype' || nameLower === 'access_type') return 'formAccessType';
82
86
  return undefined;
83
87
  }
84
88
  /**
@@ -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;
@@ -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 {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flusys/nestjs-core",
3
- "version": "2.0.0",
3
+ "version": "3.0.0",
4
4
  "description": "Core types, interfaces, and constants for Flusys NestJS packages",
5
5
  "main": "cjs/index.js",
6
6
  "module": "fesm/index.js",
@@ -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';
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';
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;