@flusys/nestjs-auth 1.1.0-beta → 1.1.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.
Files changed (94) hide show
  1. package/README.md +633 -468
  2. package/cjs/config/auth.constants.js +8 -0
  3. package/cjs/controllers/authentication.controller.js +175 -167
  4. package/cjs/controllers/branch.controller.js +44 -1
  5. package/cjs/controllers/company-selection.controller.js +27 -20
  6. package/cjs/controllers/company.controller.js +44 -1
  7. package/cjs/controllers/email-verification.controller.js +220 -0
  8. package/cjs/controllers/index.js +1 -0
  9. package/cjs/controllers/user-permission.controller.js +82 -154
  10. package/cjs/controllers/user.controller.js +68 -15
  11. package/cjs/docs/auth-swagger.config.js +14 -7
  12. package/cjs/dtos/authentication.dto.js +16 -43
  13. package/cjs/dtos/index.js +0 -1
  14. package/cjs/dtos/user-permission.dto.js +28 -0
  15. package/cjs/dtos/user.dto.js +19 -4
  16. package/cjs/entities/index.js +16 -17
  17. package/cjs/entities/user-company-permission.entity.js +3 -9
  18. package/cjs/interceptors/clear-token.interceptor.js +10 -23
  19. package/cjs/interceptors/set-token.interceptor.js +15 -55
  20. package/cjs/interfaces/auth-email-provider.interface.js +1 -1
  21. package/cjs/modules/auth.module.js +79 -154
  22. package/cjs/services/auth-config.service.js +33 -35
  23. package/cjs/services/auth-datasource.provider.js +18 -42
  24. package/cjs/services/auth-email.service.js +89 -85
  25. package/cjs/services/authentication.service.js +248 -414
  26. package/cjs/services/branch.service.js +9 -4
  27. package/cjs/services/company-selection-session.service.js +1 -1
  28. package/cjs/services/user-permission.service.js +43 -73
  29. package/cjs/services/user.service.js +78 -64
  30. package/cjs/strategies/jwt.strategy.js +44 -44
  31. package/cjs/validators/password.validator.js +45 -0
  32. package/config/auth.constants.d.ts +2 -0
  33. package/controllers/authentication.controller.d.ts +4 -10
  34. package/controllers/company-selection.controller.d.ts +6 -2
  35. package/controllers/email-verification.controller.d.ts +20 -0
  36. package/controllers/index.d.ts +1 -0
  37. package/controllers/user-permission.controller.d.ts +5 -4
  38. package/controllers/user.controller.d.ts +6 -0
  39. package/dtos/authentication.dto.d.ts +0 -4
  40. package/dtos/company-branch.dto.d.ts +0 -1
  41. package/dtos/company.dto.d.ts +0 -1
  42. package/dtos/index.d.ts +0 -1
  43. package/dtos/user-permission.dto.d.ts +4 -0
  44. package/dtos/user.dto.d.ts +1 -3
  45. package/entities/index.d.ts +5 -10
  46. package/entities/user-company-permission.entity.d.ts +1 -3
  47. package/fesm/config/auth.constants.js +6 -13
  48. package/fesm/controllers/authentication.controller.js +178 -170
  49. package/fesm/controllers/branch.controller.js +45 -2
  50. package/fesm/controllers/company-selection.controller.js +28 -21
  51. package/fesm/controllers/company.controller.js +45 -2
  52. package/fesm/controllers/email-verification.controller.js +210 -0
  53. package/fesm/controllers/index.js +1 -0
  54. package/fesm/controllers/user-permission.controller.js +84 -156
  55. package/fesm/controllers/user.controller.js +71 -18
  56. package/fesm/docs/auth-swagger.config.js +14 -7
  57. package/fesm/dtos/authentication.dto.js +17 -44
  58. package/fesm/dtos/index.js +0 -1
  59. package/fesm/dtos/user-permission.dto.js +28 -0
  60. package/fesm/dtos/user.dto.js +20 -5
  61. package/fesm/entities/index.js +17 -9
  62. package/fesm/entities/user-company-permission.entity.js +3 -9
  63. package/fesm/interceptors/clear-token.interceptor.js +9 -22
  64. package/fesm/interceptors/set-token.interceptor.js +14 -54
  65. package/fesm/interfaces/auth-email-provider.interface.js +1 -1
  66. package/fesm/modules/auth.module.js +82 -157
  67. package/fesm/services/auth-config.service.js +34 -36
  68. package/fesm/services/auth-datasource.provider.js +19 -43
  69. package/fesm/services/auth-email.service.js +90 -86
  70. package/fesm/services/authentication.service.js +248 -414
  71. package/fesm/services/branch.service.js +9 -4
  72. package/fesm/services/company-selection-session.service.js +1 -1
  73. package/fesm/services/user-permission.service.js +44 -74
  74. package/fesm/services/user.service.js +79 -65
  75. package/fesm/strategies/jwt.strategy.js +44 -44
  76. package/fesm/validators/password.validator.js +48 -0
  77. package/interceptors/clear-token.interceptor.d.ts +0 -1
  78. package/interceptors/set-token.interceptor.d.ts +1 -1
  79. package/interfaces/authentication.interface.d.ts +0 -4
  80. package/interfaces/user-enricher.interface.d.ts +1 -4
  81. package/modules/auth.module.d.ts +9 -4
  82. package/package.json +4 -4
  83. package/services/auth-config.service.d.ts +7 -8
  84. package/services/auth-datasource.provider.d.ts +3 -4
  85. package/services/auth-email.service.d.ts +8 -4
  86. package/services/authentication.service.d.ts +16 -16
  87. package/services/company-selection-session.service.d.ts +1 -1
  88. package/services/user-permission.service.d.ts +6 -9
  89. package/services/user.service.d.ts +3 -0
  90. package/strategies/jwt.strategy.d.ts +4 -1
  91. package/validators/password.validator.d.ts +10 -0
  92. package/cjs/dtos/user-company-permission.dto.js +0 -110
  93. package/dtos/user-company-permission.dto.d.ts +0 -10
  94. package/fesm/dtos/user-company-permission.dto.js +0 -98
@@ -5,98 +5,63 @@ function _ts_decorate(decorators, target, key, desc) {
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  }
7
7
  import { CacheModule, UtilsModule } from '@flusys/nestjs-shared/modules';
8
- import { Module, Scope } from '@nestjs/common';
8
+ import { Module } from '@nestjs/common';
9
9
  import { JwtModule } from '@nestjs/jwt';
10
10
  import { PassportModule } from '@nestjs/passport';
11
- import { getRepositoryToken } from '@nestjs/typeorm';
12
- import { AuthConfigService } from '../services/auth-config.service';
13
- import { AuthDataSourceProvider } from '../services/auth-datasource.provider';
14
- import { AUTH_MODULE_OPTIONS } from '../config/auth.constants';
15
- import { AuthenticationController, BranchController, CompanyController, CompanySelectionController, UserController, UserPermissionController } from '../controllers';
16
- import { Company, CompanyBranch, User, UserCompanyPermission } from '../entities';
17
11
  import { JwtAuthGuard } from '@flusys/nestjs-shared/guards';
12
+ import { AUTH_MODULE_OPTIONS } from '../config/auth.constants';
13
+ import { AuthenticationController, BranchController, CompanyController, CompanySelectionController, EmailVerificationController, UserController, UserPermissionController } from '../controllers';
14
+ import { getEntitiesByConfig } from '../entities';
18
15
  import { ClearToken } from '../interceptors/clear-token.interceptor';
19
16
  import { SetToken } from '../interceptors/set-token.interceptor';
20
17
  import { AuthEmailService, AuthenticationService, BranchService, CompanySelectionSessionService, CompanyService, UserPermissionService, UserService } from '../services';
18
+ import { AuthConfigService } from '../services/auth-config.service';
19
+ import { AuthDataSourceProvider } from '../services/auth-datasource.provider';
21
20
  import { JwtStrategy } from '../strategies/jwt.strategy';
22
21
  export class AuthModule {
23
22
  static forRoot(options) {
24
- return this.buildDynamicModule(options);
23
+ const optionsProvider = {
24
+ provide: AUTH_MODULE_OPTIONS,
25
+ useValue: options
26
+ };
27
+ return this.buildModule(options, [
28
+ optionsProvider,
29
+ ...options.providers ?? []
30
+ ]);
25
31
  }
26
- static forRootAsync(asyncOptions) {
27
- const { global = false, includeController = true, bootstrapAppConfig: { enableCompanyFeature } = {}, imports: externalImports = [], providers: additionalProviders = [] } = asyncOptions;
28
- const asyncProviders = this.createAsyncProviders(asyncOptions);
29
- // Build imports
30
- const imports = [
31
- ...externalImports,
32
- PassportModule.register({
33
- defaultStrategy: 'jwt'
34
- }),
35
- JwtModule.register({}),
36
- CacheModule,
37
- UtilsModule
38
- ];
39
- // Build controllers based on configuration
40
- const controllers = [];
41
- if (includeController) {
42
- // Core authentication controller (always included)
43
- controllers.push(AuthenticationController);
44
- // User controller (always included)
45
- controllers.push(UserController);
46
- // Company feature controllers (conditional)
47
- if (enableCompanyFeature) {
48
- controllers.push(CompanySelectionController, CompanyController, BranchController, UserPermissionController);
49
- }
50
- }
51
- // Build providers
52
- const providers = [
32
+ static forRootAsync(options) {
33
+ const asyncProviders = this.createAsyncProviders(options);
34
+ return this.buildModule(options, [
53
35
  ...asyncProviders,
54
- ...additionalProviders,
55
- // Config & Infrastructure
56
- AuthConfigService,
57
- AuthDataSourceProvider,
58
- // Auth core
59
- JwtStrategy,
60
- JwtAuthGuard,
61
- AuthenticationService,
62
- AuthEmailService,
63
- // Interceptors
64
- SetToken,
65
- ClearToken,
66
- // Core services (always included)
67
- UserService
68
- ];
69
- // Company feature services (conditional)
70
- if (enableCompanyFeature) {
71
- providers.push(CompanySelectionSessionService, CompanyService, BranchService, UserPermissionService);
72
- }
73
- // Build exports
74
- const exports = [
75
- PassportModule,
76
- AUTH_MODULE_OPTIONS,
77
- AuthConfigService,
78
- AuthDataSourceProvider,
79
- JwtStrategy,
80
- JwtAuthGuard,
81
- AuthenticationService,
82
- AuthEmailService,
83
- UserService
84
- ];
85
- if (enableCompanyFeature) {
86
- exports.push(CompanySelectionSessionService, CompanyService, BranchService, UserPermissionService);
87
- }
36
+ ...options.providers ?? []
37
+ ], options.imports);
38
+ }
39
+ static buildModule(options, providers, externalImports = []) {
40
+ const { global = false, includeController = true, bootstrapAppConfig } = options;
41
+ const featureFlags = this.getFeatureFlags(bootstrapAppConfig);
88
42
  return {
89
43
  module: AuthModule,
90
44
  global,
91
- imports,
92
- controllers,
93
- providers,
94
- exports
45
+ imports: [
46
+ ...externalImports,
47
+ ...this.buildImports()
48
+ ],
49
+ controllers: this.buildControllers(includeController, featureFlags),
50
+ providers: [
51
+ ...providers,
52
+ ...this.buildProviders(featureFlags)
53
+ ],
54
+ exports: this.buildExports(featureFlags)
55
+ };
56
+ }
57
+ static getFeatureFlags(bootstrapAppConfig) {
58
+ return {
59
+ enableCompanyFeature: bootstrapAppConfig?.enableCompanyFeature ?? false,
60
+ enableEmailVerification: bootstrapAppConfig?.enableEmailVerification ?? true
95
61
  };
96
62
  }
97
- static buildDynamicModule(options) {
98
- const { bootstrapAppConfig: { enableCompanyFeature } = {}, includeController = true, global = false, providers: additionalProviders = [] } = options;
99
- const imports = [
63
+ static buildImports() {
64
+ return [
100
65
  PassportModule.register({
101
66
  defaultStrategy: 'jwt'
102
67
  }),
@@ -104,42 +69,41 @@ export class AuthModule {
104
69
  CacheModule,
105
70
  UtilsModule
106
71
  ];
107
- // Build controllers based on configuration
108
- const controllers = [];
109
- if (includeController) {
110
- // Core authentication controller (always included)
111
- controllers.push(AuthenticationController);
112
- // User controller (always included)
113
- controllers.push(UserController);
114
- // Company feature controllers (conditional)
115
- if (enableCompanyFeature) {
116
- controllers.push(CompanySelectionController, CompanyController, BranchController, UserPermissionController);
117
- }
72
+ }
73
+ static buildControllers(includeController, flags) {
74
+ if (!includeController) return [];
75
+ const controllers = [
76
+ AuthenticationController,
77
+ UserController
78
+ ];
79
+ if (flags.enableEmailVerification) {
80
+ controllers.push(EmailVerificationController);
118
81
  }
82
+ if (flags.enableCompanyFeature) {
83
+ controllers.push(CompanySelectionController, CompanyController, BranchController, UserPermissionController);
84
+ }
85
+ return controllers;
86
+ }
87
+ static buildProviders(flags) {
119
88
  const providers = [
120
- {
121
- provide: AUTH_MODULE_OPTIONS,
122
- useValue: options
123
- },
124
- ...additionalProviders,
125
- // Config & Infrastructure
126
89
  AuthConfigService,
127
90
  AuthDataSourceProvider,
128
- // Auth core
129
91
  JwtStrategy,
130
92
  JwtAuthGuard,
131
93
  AuthenticationService,
132
- AuthEmailService,
133
- // Interceptors
134
94
  SetToken,
135
95
  ClearToken,
136
- // Core services (always included)
137
96
  UserService
138
97
  ];
139
- // Company feature services (conditional)
140
- if (enableCompanyFeature) {
98
+ if (flags.enableEmailVerification) {
99
+ providers.push(AuthEmailService);
100
+ }
101
+ if (flags.enableCompanyFeature) {
141
102
  providers.push(CompanySelectionSessionService, CompanyService, BranchService, UserPermissionService);
142
103
  }
104
+ return providers;
105
+ }
106
+ static buildExports(flags) {
143
107
  const exports = [
144
108
  PassportModule,
145
109
  AUTH_MODULE_OPTIONS,
@@ -148,20 +112,15 @@ export class AuthModule {
148
112
  JwtStrategy,
149
113
  JwtAuthGuard,
150
114
  AuthenticationService,
151
- AuthEmailService,
152
115
  UserService
153
116
  ];
154
- if (enableCompanyFeature) {
117
+ if (flags.enableEmailVerification) {
118
+ exports.push(AuthEmailService);
119
+ }
120
+ if (flags.enableCompanyFeature) {
155
121
  exports.push(CompanySelectionSessionService, CompanyService, BranchService, UserPermissionService);
156
122
  }
157
- return {
158
- module: AuthModule,
159
- global,
160
- imports,
161
- controllers,
162
- providers,
163
- exports
164
- };
123
+ return exports;
165
124
  }
166
125
  static createAsyncProviders(options) {
167
126
  const staticOptions = {
@@ -173,13 +132,10 @@ export class AuthModule {
173
132
  return [
174
133
  {
175
134
  provide: AUTH_MODULE_OPTIONS,
176
- useFactory: async (...args)=>{
177
- const config = await options.useFactory(...args);
178
- return {
135
+ useFactory: async (...args)=>({
179
136
  ...staticOptions,
180
- config
181
- };
182
- },
137
+ config: await options.useFactory(...args)
138
+ }),
183
139
  inject: options.inject || []
184
140
  }
185
141
  ];
@@ -192,13 +148,10 @@ export class AuthModule {
192
148
  },
193
149
  {
194
150
  provide: AUTH_MODULE_OPTIONS,
195
- useFactory: async (factory)=>{
196
- const config = await factory.createAuthOptions();
197
- return {
151
+ useFactory: async (factory)=>({
198
152
  ...staticOptions,
199
- config
200
- };
201
- },
153
+ config: await factory.createAuthOptions()
154
+ }),
202
155
  inject: [
203
156
  options.useClass
204
157
  ]
@@ -209,13 +162,10 @@ export class AuthModule {
209
162
  return [
210
163
  {
211
164
  provide: AUTH_MODULE_OPTIONS,
212
- useFactory: async (factory)=>{
213
- const config = await factory.createAuthOptions();
214
- return {
165
+ useFactory: async (factory)=>({
215
166
  ...staticOptions,
216
- config
217
- };
218
- },
167
+ config: await factory.createAuthOptions()
168
+ }),
219
169
  inject: [
220
170
  options.useExisting
221
171
  ]
@@ -229,36 +179,11 @@ export class AuthModule {
229
179
  }
230
180
  ];
231
181
  }
232
- /**
233
- * Create repository providers that use AuthDataSourceProvider
234
- * This replaces TypeOrmModule.forFeature() functionality
235
- * Note: Must be REQUEST-scoped since AuthDataSourceProvider is REQUEST-scoped
236
- */ static getRepositoryProviders(enableCompanyFeature) {
237
- const entities = this.getEntities(enableCompanyFeature);
238
- return entities.map((entity)=>({
239
- provide: getRepositoryToken(entity),
240
- scope: Scope.REQUEST,
241
- useFactory: async (dataSourceProvider)=>{
242
- return await dataSourceProvider.getRepository(entity);
243
- },
244
- inject: [
245
- AuthDataSourceProvider
246
- ]
247
- }));
248
- }
249
- static getEntities(enableCompanyFeature = false) {
250
- const coreEntities = [
251
- User
252
- ];
253
- const companyEntities = enableCompanyFeature ? [
254
- Company,
255
- CompanyBranch,
256
- UserCompanyPermission
257
- ] : [];
258
- return [
259
- ...coreEntities,
260
- ...companyEntities
261
- ];
182
+ static getEntities(config) {
183
+ return getEntitiesByConfig({
184
+ enableCompanyFeature: config.enableCompanyFeature ?? false,
185
+ enableEmailVerification: config.enableEmailVerification ?? true
186
+ });
262
187
  }
263
188
  }
264
189
  AuthModule = _ts_decorate([
@@ -25,65 +25,63 @@ function _ts_param(paramIndex, decorator) {
25
25
  decorator(target, key, paramIndex);
26
26
  };
27
27
  }
28
- import { Inject, Injectable, Optional } from '@nestjs/common';
29
- import { AuthModuleOptions } from '../interfaces/auth-module-options.interface';
28
+ import { envConfig } from '@flusys/nestjs-core/config';
29
+ import { Inject, Injectable, InternalServerErrorException, Logger, Optional } from '@nestjs/common';
30
30
  import { AUTH_MODULE_OPTIONS } from '../config/auth.constants';
31
+ import { AuthModuleOptions } from '../interfaces/auth-module-options.interface';
31
32
  export class AuthConfigService {
32
- // Database Mode
33
- /** Get database mode (single or multi-tenant) */ getDatabaseMode() {
33
+ // Database Mode (required by IModuleConfigService)
34
+ getDatabaseMode() {
34
35
  return this.options.bootstrapAppConfig?.databaseMode ?? 'single';
35
36
  }
36
- /** Check if running in multi-tenant mode */ isMultiTenant() {
37
+ isMultiTenant() {
37
38
  return this.getDatabaseMode() === 'multi-tenant';
38
39
  }
39
40
  // Feature Flags
40
- /** Check if company feature is enabled */ isCompanyFeatureEnabled() {
41
+ isCompanyFeatureEnabled() {
41
42
  return this.options.bootstrapAppConfig?.enableCompanyFeature ?? false;
42
43
  }
44
+ isEmailVerificationEnabled() {
45
+ return this.options.bootstrapAppConfig?.enableEmailVerification ?? true;
46
+ }
43
47
  // JWT Configuration
44
- /** Get JWT secret key */ getJwtSecret() {
45
- return this.config.jwtSecret ?? 'default-secret-change-in-production';
48
+ getJwtSecret() {
49
+ if (!this.config.jwtSecret) {
50
+ throw new InternalServerErrorException('[AuthModule] JWT_SECRET is required - set via environment or module config');
51
+ }
52
+ return this.config.jwtSecret;
46
53
  }
47
- /** Get JWT expiration time */ getJwtExpiration() {
54
+ getJwtExpiration() {
48
55
  return this.config.jwtExpiration ?? '1h';
49
56
  }
50
- /** Get refresh token secret key */ getRefreshTokenSecret() {
51
- return this.config.refreshTokenSecret ?? this.getJwtSecret();
52
- }
53
- /** Get refresh token expiration time */ getRefreshTokenExpiration() {
57
+ getRefreshTokenSecret() {
58
+ if (this.config.refreshTokenSecret) {
59
+ return this.config.refreshTokenSecret;
60
+ }
61
+ if (envConfig.isProduction()) {
62
+ throw new InternalServerErrorException('[AuthModule] REFRESH_TOKEN_SECRET is required in production - ' + 'using the same secret for access and refresh tokens is a security risk');
63
+ }
64
+ if (!this.refreshTokenSecretWarned) {
65
+ this.refreshTokenSecretWarned = true;
66
+ this.logger.warn('REFRESH_TOKEN_SECRET not configured - using JWT_SECRET as fallback. ' + 'For better security, configure a separate refresh token secret.');
67
+ }
68
+ return this.getJwtSecret();
69
+ }
70
+ getRefreshTokenExpiration() {
54
71
  return this.config.refreshTokenExpiration ?? '7d';
55
72
  }
56
- /** Get refresh token cookie name */ getRefreshTokenCookieName() {
73
+ getRefreshTokenCookieName() {
57
74
  return this.config.refreshTokenCookieName ?? 'fsn_refresh_token';
58
75
  }
59
76
  // Frontend Configuration
60
- /** Get frontend URL for email links */ getFrontendUrl() {
77
+ getFrontendUrl() {
61
78
  return this.config.frontendUrl;
62
79
  }
63
- // Database Configuration
64
- /** Get default database config */ getDefaultDatabaseConfig() {
65
- return this.config.defaultDatabaseConfig ?? this.config.tenantDefaultDatabaseConfig;
66
- }
67
- /** Get tenant default database config (for multi-tenant) */ getTenantDefaultDatabaseConfig() {
68
- return this.config.tenantDefaultDatabaseConfig;
69
- }
70
- /** Get registered tenants */ getTenants() {
71
- return this.config.tenants ?? [];
72
- }
73
- // Raw Options
74
- /** Get full module options */ getOptions() {
75
- return {
76
- ...this.options
77
- };
78
- }
79
- /** Get runtime config */ getConfig() {
80
- return {
81
- ...this.config
82
- };
83
- }
84
80
  constructor(injectedOptions){
81
+ _define_property(this, "logger", new Logger(AuthConfigService.name));
85
82
  _define_property(this, "options", void 0);
86
83
  _define_property(this, "config", void 0);
84
+ _define_property(this, "refreshTokenSecretWarned", false);
87
85
  this.options = injectedOptions ?? {
88
86
  global: false,
89
87
  includeController: true
@@ -26,14 +26,13 @@ function _ts_param(paramIndex, decorator) {
26
26
  };
27
27
  }
28
28
  import { MultiTenantDataSourceService } from '@flusys/nestjs-shared/modules';
29
- import { Inject, Injectable, Logger, Optional, Scope } from '@nestjs/common';
29
+ import { Inject, Injectable, InternalServerErrorException, Logger, Optional, Scope } from '@nestjs/common';
30
30
  import { REQUEST } from '@nestjs/core';
31
31
  import { Request } from 'express';
32
32
  import { AuthModuleOptions } from '../interfaces/auth-module-options.interface';
33
33
  import { AUTH_MODULE_OPTIONS } from '../config/auth.constants';
34
34
  export class AuthDataSourceProvider extends MultiTenantDataSourceService {
35
- // Override Static Cache Access Methods
36
- /** Override to access Auth-specific static properties */ async getSingleDataSource() {
35
+ async getSingleDataSource() {
37
36
  if (!AuthDataSourceProvider.singleDataSource) {
38
37
  if (AuthDataSourceProvider.singleConnectionLock) {
39
38
  return AuthDataSourceProvider.singleConnectionLock;
@@ -41,7 +40,7 @@ export class AuthDataSourceProvider extends MultiTenantDataSourceService {
41
40
  const lockPromise = (async ()=>{
42
41
  const config = this.getDefaultDatabaseConfig();
43
42
  if (!config) {
44
- throw new Error('Default database config is not available');
43
+ throw new InternalServerErrorException('Default database config is not available');
45
44
  }
46
45
  const ds = await this.createDataSourceFromConfig(config);
47
46
  AuthDataSourceProvider.singleDataSource = ds;
@@ -57,18 +56,15 @@ export class AuthDataSourceProvider extends MultiTenantDataSourceService {
57
56
  }
58
57
  return AuthDataSourceProvider.singleDataSource;
59
58
  }
60
- /** Override to use Auth-specific static cache for tenant connections */ async getOrCreateTenantConnection(tenant) {
61
- // Return existing initialized connection from Auth-specific cache
59
+ async getOrCreateTenantConnection(tenant) {
62
60
  const existing = AuthDataSourceProvider.tenantConnections.get(tenant.id);
63
61
  if (existing?.isInitialized) {
64
62
  return existing;
65
63
  }
66
- // If another request is creating this tenant's connection, wait for it
67
64
  const pendingConnection = AuthDataSourceProvider.connectionLocks.get(tenant.id);
68
65
  if (pendingConnection) {
69
66
  return pendingConnection;
70
67
  }
71
- // Create connection with lock to prevent race conditions
72
68
  const config = this.buildTenantDatabaseConfig(tenant);
73
69
  const connectionPromise = this.createDataSourceFromConfig(config);
74
70
  AuthDataSourceProvider.connectionLocks.set(tenant.id, connectionPromise);
@@ -80,8 +76,7 @@ export class AuthDataSourceProvider extends MultiTenantDataSourceService {
80
76
  AuthDataSourceProvider.connectionLocks.delete(tenant.id);
81
77
  }
82
78
  }
83
- // Factory Methods
84
- /** Build parent options from AuthModuleOptions */ static buildParentOptions(options) {
79
+ static buildParentOptions(options) {
85
80
  return {
86
81
  bootstrapAppConfig: options.bootstrapAppConfig,
87
82
  defaultDatabaseConfig: options.config?.defaultDatabaseConfig,
@@ -89,47 +84,28 @@ export class AuthDataSourceProvider extends MultiTenantDataSourceService {
89
84
  tenants: options.config?.tenants
90
85
  };
91
86
  }
92
- // Feature Flags
93
- /** Get global enable company feature flag */ getEnableCompanyFeature() {
94
- return this.authOptions.bootstrapAppConfig?.enableCompanyFeature ?? false;
87
+ isCompanyFeatureEnabled(tenant) {
88
+ const effectiveTenant = tenant ?? this.getCurrentTenant();
89
+ return effectiveTenant?.enableCompanyFeature ?? this.authOptions.bootstrapAppConfig?.enableCompanyFeature ?? false;
95
90
  }
96
- /** Get enable company feature for specific tenant. Falls back to global setting. */ getEnableCompanyFeatureForTenant(tenant) {
97
- return tenant?.enableCompanyFeature ?? this.getEnableCompanyFeature();
91
+ isEmailVerificationEnabled(tenant) {
92
+ const effectiveTenant = tenant ?? this.getCurrentTenant();
93
+ return effectiveTenant?.enableEmailVerification ?? this.authOptions.bootstrapAppConfig?.enableEmailVerification ?? true;
98
94
  }
99
- /** Get enable company feature for current request context */ getEnableCompanyFeatureForCurrentTenant() {
100
- return this.getEnableCompanyFeatureForTenant(this.getCurrentTenant() ?? undefined);
101
- }
102
- // Entity Management
103
- /** Get auth entities based on company feature flag */ async getAuthEntities(enableCompanyFeature) {
104
- const enable = enableCompanyFeature ?? this.getEnableCompanyFeature();
105
- const { Company, CompanyBranch, User, UserCompanyPermission, UserToken, PendingRegistration } = await import('../entities');
106
- const coreEntities = [
107
- User,
108
- UserToken,
109
- PendingRegistration
110
- ];
111
- const companyEntities = enable ? [
112
- Company,
113
- CompanyBranch,
114
- UserCompanyPermission
115
- ] : [];
116
- return [
117
- ...coreEntities,
118
- ...companyEntities
119
- ];
95
+ async getAuthEntities() {
96
+ const { getEntitiesByConfig } = await import('../entities');
97
+ return getEntitiesByConfig({
98
+ enableCompanyFeature: this.isCompanyFeatureEnabled(),
99
+ enableEmailVerification: this.isEmailVerificationEnabled()
100
+ });
120
101
  }
121
- // Overrides
122
- /** Override to dynamically set entities based on tenant config */ async createDataSourceFromConfig(config) {
123
- const currentTenant = this.getCurrentTenant();
124
- const enableCompanyFeature = this.getEnableCompanyFeatureForTenant(currentTenant ?? undefined);
125
- const entities = await this.getAuthEntities(enableCompanyFeature);
126
- return super.createDataSourceFromConfig(config, entities);
102
+ async createDataSourceFromConfig(config) {
103
+ return super.createDataSourceFromConfig(config, await this.getAuthEntities());
127
104
  }
128
105
  constructor(authOptions, request){
129
106
  super(AuthDataSourceProvider.buildParentOptions(authOptions), request), _define_property(this, "authOptions", void 0), _define_property(this, "logger", void 0), this.authOptions = authOptions, this.logger = new Logger(AuthDataSourceProvider.name);
130
107
  }
131
108
  }
132
- // Override parent's static properties to have Auth-specific cache (isolated from IAM/Storage)
133
109
  _define_property(AuthDataSourceProvider, "tenantConnections", new Map());
134
110
  _define_property(AuthDataSourceProvider, "singleDataSource", null);
135
111
  _define_property(AuthDataSourceProvider, "tenantsRegistry", new Map());