@flusys/nestjs-auth 1.0.0-rc → 2.0.0-rc.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 (58) hide show
  1. package/README.md +530 -396
  2. package/cjs/controllers/authentication.controller.js +160 -28
  3. package/cjs/controllers/user-permission.controller.js +49 -136
  4. package/cjs/docs/auth-swagger.config.js +14 -7
  5. package/cjs/dtos/authentication.dto.js +0 -30
  6. package/cjs/dtos/index.js +0 -1
  7. package/cjs/interceptors/clear-token.interceptor.js +8 -18
  8. package/cjs/interceptors/set-token.interceptor.js +8 -55
  9. package/cjs/interfaces/auth-email-provider.interface.js +1 -1
  10. package/cjs/modules/auth.module.js +63 -129
  11. package/cjs/services/auth-config.service.js +6 -29
  12. package/cjs/services/auth-datasource.provider.js +8 -20
  13. package/cjs/services/auth-email.service.js +72 -87
  14. package/cjs/services/authentication.service.js +211 -355
  15. package/cjs/services/branch.service.js +9 -5
  16. package/cjs/services/user-permission.service.js +43 -71
  17. package/cjs/services/user.service.js +18 -47
  18. package/cjs/strategies/jwt.strategy.js +44 -44
  19. package/controllers/authentication.controller.d.ts +5 -3
  20. package/controllers/user-permission.controller.d.ts +5 -4
  21. package/dtos/authentication.dto.d.ts +0 -4
  22. package/dtos/index.d.ts +0 -1
  23. package/entities/index.d.ts +3 -3
  24. package/fesm/controllers/authentication.controller.js +162 -30
  25. package/fesm/controllers/user-permission.controller.js +50 -137
  26. package/fesm/docs/auth-swagger.config.js +14 -7
  27. package/fesm/dtos/authentication.dto.js +0 -30
  28. package/fesm/dtos/index.js +0 -1
  29. package/fesm/interceptors/clear-token.interceptor.js +8 -18
  30. package/fesm/interceptors/set-token.interceptor.js +8 -55
  31. package/fesm/interfaces/auth-email-provider.interface.js +1 -1
  32. package/fesm/modules/auth.module.js +63 -129
  33. package/fesm/services/auth-config.service.js +6 -29
  34. package/fesm/services/auth-datasource.provider.js +8 -20
  35. package/fesm/services/auth-email.service.js +72 -87
  36. package/fesm/services/authentication.service.js +211 -355
  37. package/fesm/services/branch.service.js +9 -5
  38. package/fesm/services/user-permission.service.js +44 -72
  39. package/fesm/services/user.service.js +18 -47
  40. package/fesm/strategies/jwt.strategy.js +44 -44
  41. package/interceptors/clear-token.interceptor.d.ts +0 -1
  42. package/interceptors/set-token.interceptor.d.ts +1 -2
  43. package/interfaces/authentication.interface.d.ts +0 -4
  44. package/modules/auth.module.d.ts +6 -2
  45. package/package.json +3 -3
  46. package/services/auth-config.service.d.ts +2 -7
  47. package/services/auth-datasource.provider.d.ts +2 -4
  48. package/services/auth-email.service.d.ts +7 -4
  49. package/services/authentication.service.d.ts +14 -8
  50. package/services/user-permission.service.d.ts +6 -8
  51. package/services/user.service.d.ts +1 -1
  52. package/strategies/jwt.strategy.d.ts +4 -1
  53. package/cjs/dtos/user-company-permission.dto.js +0 -110
  54. package/cjs/guards/auth-throttler.guard.js +0 -53
  55. package/dtos/user-company-permission.dto.d.ts +0 -10
  56. package/fesm/dtos/user-company-permission.dto.js +0 -98
  57. package/fesm/guards/auth-throttler.guard.js +0 -43
  58. package/guards/auth-throttler.guard.d.ts +0 -7
@@ -25,6 +25,7 @@ function _ts_param(paramIndex, decorator) {
25
25
  decorator(target, key, paramIndex);
26
26
  };
27
27
  }
28
+ import { buildCookieOptions, isBrowserRequest } from '@flusys/nestjs-shared/utils';
28
29
  import { Injectable, Optional } from '@nestjs/common';
29
30
  import { map } from 'rxjs';
30
31
  import { DEFAULT_COOKIE_NAME } from '../config';
@@ -37,27 +38,16 @@ export class ClearToken {
37
38
  const req = context.switchToHttp().getRequest();
38
39
  const res = context.switchToHttp().getResponse();
39
40
  return next.handle().pipe(map((value)=>{
40
- this.clearRefreshTokenCookie(req, res);
41
+ if (isBrowserRequest(req)) {
42
+ res.clearCookie(this.cookieName, {
43
+ httpOnly: true,
44
+ path: '/',
45
+ ...buildCookieOptions(req)
46
+ });
47
+ }
41
48
  return value;
42
49
  }));
43
50
  }
44
- clearRefreshTokenCookie(req, res) {
45
- const origin = req.headers.origin || '';
46
- const hostname = req.hostname || '';
47
- const isHttps = origin.startsWith('https://') || req.secure;
48
- let cookieDomain = hostname;
49
- const domainParts = hostname.split('.');
50
- if (domainParts.length > 2) {
51
- cookieDomain = '.' + domainParts.slice(-2).join('.');
52
- }
53
- res.clearCookie(this.cookieName, {
54
- httpOnly: true,
55
- secure: isHttps,
56
- sameSite: isHttps ? 'strict' : 'lax',
57
- domain: cookieDomain,
58
- path: '/'
59
- });
60
- }
61
51
  constructor(authConfig){
62
52
  _define_property(this, "authConfig", void 0);
63
53
  this.authConfig = authConfig;
@@ -25,6 +25,7 @@ function _ts_param(paramIndex, decorator) {
25
25
  decorator(target, key, paramIndex);
26
26
  };
27
27
  }
28
+ import { buildCookieOptions, isBrowserRequest, parseDurationToMs } from '@flusys/nestjs-shared/utils';
28
29
  import { Inject, Injectable, Optional, PayloadTooLargeException } from '@nestjs/common';
29
30
  import { Buffer } from 'buffer';
30
31
  import { catchError, map, throwError } from 'rxjs';
@@ -34,67 +35,23 @@ export class SetToken {
34
35
  get cookieName() {
35
36
  return this.authConfig?.getRefreshTokenCookieName() ?? DEFAULT_COOKIE_NAME;
36
37
  }
37
- /** Convert expiration string (e.g., '7d', '24h') to milliseconds */ getMaxAgeMs() {
38
- const expiry = this.authConfig?.getRefreshTokenExpiration() ?? '7d';
39
- const match = expiry.match(/^(\d+)(s|m|h|d|w)$/);
40
- if (!match) {
41
- return 7 * 24 * 60 * 60 * 1000; // Default 7 days
42
- }
43
- const value = parseInt(match[1], 10);
44
- const unit = match[2];
45
- const multipliers = {
46
- s: 1000,
47
- m: 60 * 1000,
48
- h: 60 * 60 * 1000,
49
- d: 24 * 60 * 60 * 1000,
50
- w: 7 * 24 * 60 * 60 * 1000
51
- };
52
- return value * (multipliers[unit] || multipliers['d']);
38
+ get maxAgeMs() {
39
+ return parseDurationToMs(this.authConfig?.getRefreshTokenExpiration() ?? '7d');
53
40
  }
54
41
  intercept(context, next) {
55
42
  const req = context.switchToHttp().getRequest();
56
43
  const res = context.switchToHttp().getResponse();
57
44
  return next.handle().pipe(map((value)=>{
58
- if (!value || !value.refreshToken) {
59
- return value;
60
- }
61
- const isBrowser = this.isBrowserRequest(req);
62
- const tokenValue = value.refreshToken;
63
- if (isBrowser) {
64
- this.setRefreshTokenCookie(req, res, tokenValue);
45
+ if (!value?.refreshToken) return value;
46
+ if (isBrowserRequest(req)) {
47
+ this.setRefreshTokenCookie(req, res, value.refreshToken);
65
48
  const { refreshToken, ...responseWithoutToken } = value;
66
49
  return responseWithoutToken;
67
50
  }
68
51
  return value;
69
52
  }), catchError((err)=>throwError(()=>err)));
70
53
  }
71
- isBrowserRequest(req) {
72
- const clientType = req.headers['x-client-type'];
73
- if (clientType) {
74
- return clientType.toLowerCase() === 'browser' || clientType.toLowerCase() === 'web';
75
- }
76
- const accept = req.headers['accept'] || '';
77
- if (accept.includes('text/html')) {
78
- return true;
79
- }
80
- const userAgent = req.headers['user-agent'] || '';
81
- const browserPatterns = /mozilla|chrome|safari|firefox|edge|opera|msie/i;
82
- return browserPatterns.test(userAgent) && !userAgent.includes('Postman');
83
- }
84
54
  setRefreshTokenCookie(req, res, tokenValue) {
85
- const hostname = req.hostname || '';
86
- // Determine if we're in production - always use secure cookies in production
87
- // This handles TLS-terminating proxies correctly (they set x-forwarded-proto)
88
- const isProduction = process.env.NODE_ENV === 'production';
89
- const forwardedProto = req.headers['x-forwarded-proto'];
90
- const isHttps = isProduction || forwardedProto === 'https' || req.secure;
91
- // Set cookie domain - only for subdomains with 3+ parts
92
- // For security, limit to same domain unless explicitly configured
93
- let cookieDomain;
94
- const domainParts = hostname.split('.');
95
- if (domainParts.length > 2 && !hostname.includes('localhost')) {
96
- cookieDomain = '.' + domainParts.slice(-2).join('.');
97
- }
98
55
  const rawCookieString = `${this.cookieName}=${tokenValue}; HttpOnly`;
99
56
  const estimatedBytes = Buffer.byteLength(rawCookieString, 'utf8');
100
57
  if (estimatedBytes > MAX_COOKIE_BYTES) {
@@ -102,13 +59,9 @@ export class SetToken {
102
59
  }
103
60
  res.cookie(this.cookieName, tokenValue, {
104
61
  httpOnly: true,
105
- secure: isHttps,
106
- sameSite: isHttps ? 'strict' : 'lax',
107
- ...cookieDomain && {
108
- domain: cookieDomain
109
- },
110
62
  path: '/',
111
- maxAge: this.getMaxAgeMs()
63
+ maxAge: this.maxAgeMs,
64
+ ...buildCookieOptions(req)
112
65
  });
113
66
  }
114
67
  constructor(authConfig){
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Auth Email Provider Interface
2
+ * Auth Email Provider Interface
3
3
  *
4
4
  * This interface defines the contract for email sending in the auth module.
5
5
  * It allows auth to work independently of the email module.
@@ -8,94 +8,54 @@ import { CacheModule, UtilsModule } from '@flusys/nestjs-shared/modules';
8
8
  import { Module } from '@nestjs/common';
9
9
  import { JwtModule } from '@nestjs/jwt';
10
10
  import { PassportModule } from '@nestjs/passport';
11
- import { AuthConfigService } from '../services/auth-config.service';
12
- import { AuthDataSourceProvider } from '../services/auth-datasource.provider';
11
+ import { JwtAuthGuard } from '@flusys/nestjs-shared/guards';
13
12
  import { AUTH_MODULE_OPTIONS } from '../config/auth.constants';
14
13
  import { AuthenticationController, BranchController, CompanyController, CompanySelectionController, UserController, UserPermissionController } from '../controllers';
15
14
  import { Company, CompanyBranch, User, UserCompanyPermission } from '../entities';
16
- import { JwtAuthGuard } from '@flusys/nestjs-shared/guards';
17
15
  import { ClearToken } from '../interceptors/clear-token.interceptor';
18
16
  import { SetToken } from '../interceptors/set-token.interceptor';
19
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';
20
20
  import { JwtStrategy } from '../strategies/jwt.strategy';
21
21
  export class AuthModule {
22
22
  static forRoot(options) {
23
- 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
+ ]);
24
31
  }
25
- static forRootAsync(asyncOptions) {
26
- const { global = false, includeController = true, bootstrapAppConfig: { enableCompanyFeature } = {}, imports: externalImports = [], providers: additionalProviders = [] } = asyncOptions;
27
- const asyncProviders = this.createAsyncProviders(asyncOptions);
28
- // Build imports
29
- const imports = [
30
- ...externalImports,
31
- PassportModule.register({
32
- defaultStrategy: 'jwt'
33
- }),
34
- JwtModule.register({}),
35
- CacheModule,
36
- UtilsModule
37
- ];
38
- // Build controllers based on configuration
39
- const controllers = [];
40
- if (includeController) {
41
- // Core authentication controller (always included)
42
- controllers.push(AuthenticationController);
43
- // User controller (always included)
44
- controllers.push(UserController);
45
- // Company feature controllers (conditional)
46
- if (enableCompanyFeature) {
47
- controllers.push(CompanySelectionController, CompanyController, BranchController, UserPermissionController);
48
- }
49
- }
50
- // Build providers
51
- const providers = [
32
+ static forRootAsync(options) {
33
+ const asyncProviders = this.createAsyncProviders(options);
34
+ return this.buildModule(options, [
52
35
  ...asyncProviders,
53
- ...additionalProviders,
54
- // Config & Infrastructure
55
- AuthConfigService,
56
- AuthDataSourceProvider,
57
- // Auth core
58
- JwtStrategy,
59
- JwtAuthGuard,
60
- AuthenticationService,
61
- AuthEmailService,
62
- // Interceptors
63
- SetToken,
64
- ClearToken,
65
- // Core services (always included)
66
- UserService
67
- ];
68
- // Company feature services (conditional)
69
- if (enableCompanyFeature) {
70
- providers.push(CompanySelectionSessionService, CompanyService, BranchService, UserPermissionService);
71
- }
72
- // Build exports
73
- const exports = [
74
- PassportModule,
75
- AUTH_MODULE_OPTIONS,
76
- AuthConfigService,
77
- AuthDataSourceProvider,
78
- JwtStrategy,
79
- JwtAuthGuard,
80
- AuthenticationService,
81
- AuthEmailService,
82
- UserService
83
- ];
84
- if (enableCompanyFeature) {
85
- exports.push(CompanySelectionSessionService, CompanyService, BranchService, UserPermissionService);
86
- }
36
+ ...options.providers ?? []
37
+ ], options.imports);
38
+ }
39
+ /** Build the dynamic module with shared logic */ static buildModule(options, providers, externalImports = []) {
40
+ const { global = false, includeController = true, bootstrapAppConfig } = options;
41
+ const enableCompanyFeature = bootstrapAppConfig?.enableCompanyFeature ?? false;
87
42
  return {
88
43
  module: AuthModule,
89
44
  global,
90
- imports,
91
- controllers,
92
- providers,
93
- exports
45
+ imports: [
46
+ ...externalImports,
47
+ ...this.buildImports()
48
+ ],
49
+ controllers: this.buildControllers(includeController, enableCompanyFeature),
50
+ providers: [
51
+ ...providers,
52
+ ...this.buildProviders(enableCompanyFeature)
53
+ ],
54
+ exports: this.buildExports(enableCompanyFeature)
94
55
  };
95
56
  }
96
- static buildDynamicModule(options) {
97
- const { bootstrapAppConfig: { enableCompanyFeature } = {}, includeController = true, global = false, providers: additionalProviders = [] } = options;
98
- const imports = [
57
+ /** Common module imports */ static buildImports() {
58
+ return [
99
59
  PassportModule.register({
100
60
  defaultStrategy: 'jwt'
101
61
  }),
@@ -103,42 +63,36 @@ export class AuthModule {
103
63
  CacheModule,
104
64
  UtilsModule
105
65
  ];
106
- // Build controllers based on configuration
107
- const controllers = [];
108
- if (includeController) {
109
- // Core authentication controller (always included)
110
- controllers.push(AuthenticationController);
111
- // User controller (always included)
112
- controllers.push(UserController);
113
- // Company feature controllers (conditional)
114
- if (enableCompanyFeature) {
115
- controllers.push(CompanySelectionController, CompanyController, BranchController, UserPermissionController);
116
- }
66
+ }
67
+ /** Build controllers based on feature flags */ static buildControllers(includeController, enableCompanyFeature) {
68
+ if (!includeController) return [];
69
+ const controllers = [
70
+ AuthenticationController,
71
+ UserController
72
+ ];
73
+ if (enableCompanyFeature) {
74
+ controllers.push(CompanySelectionController, CompanyController, BranchController, UserPermissionController);
117
75
  }
76
+ return controllers;
77
+ }
78
+ /** Core providers (without AUTH_MODULE_OPTIONS - that's added separately) */ static buildProviders(enableCompanyFeature) {
118
79
  const providers = [
119
- {
120
- provide: AUTH_MODULE_OPTIONS,
121
- useValue: options
122
- },
123
- ...additionalProviders,
124
- // Config & Infrastructure
125
80
  AuthConfigService,
126
81
  AuthDataSourceProvider,
127
- // Auth core
128
82
  JwtStrategy,
129
83
  JwtAuthGuard,
130
84
  AuthenticationService,
131
85
  AuthEmailService,
132
- // Interceptors
133
86
  SetToken,
134
87
  ClearToken,
135
- // Core services (always included)
136
88
  UserService
137
89
  ];
138
- // Company feature services (conditional)
139
90
  if (enableCompanyFeature) {
140
91
  providers.push(CompanySelectionSessionService, CompanyService, BranchService, UserPermissionService);
141
92
  }
93
+ return providers;
94
+ }
95
+ /** Build module exports */ static buildExports(enableCompanyFeature) {
142
96
  const exports = [
143
97
  PassportModule,
144
98
  AUTH_MODULE_OPTIONS,
@@ -153,16 +107,9 @@ export class AuthModule {
153
107
  if (enableCompanyFeature) {
154
108
  exports.push(CompanySelectionSessionService, CompanyService, BranchService, UserPermissionService);
155
109
  }
156
- return {
157
- module: AuthModule,
158
- global,
159
- imports,
160
- controllers,
161
- providers,
162
- exports
163
- };
110
+ return exports;
164
111
  }
165
- static createAsyncProviders(options) {
112
+ /** Create async providers for forRootAsync */ static createAsyncProviders(options) {
166
113
  const staticOptions = {
167
114
  global: options.global,
168
115
  includeController: options.includeController,
@@ -172,13 +119,10 @@ export class AuthModule {
172
119
  return [
173
120
  {
174
121
  provide: AUTH_MODULE_OPTIONS,
175
- useFactory: async (...args)=>{
176
- const config = await options.useFactory(...args);
177
- return {
122
+ useFactory: async (...args)=>({
178
123
  ...staticOptions,
179
- config
180
- };
181
- },
124
+ config: await options.useFactory(...args)
125
+ }),
182
126
  inject: options.inject || []
183
127
  }
184
128
  ];
@@ -191,13 +135,10 @@ export class AuthModule {
191
135
  },
192
136
  {
193
137
  provide: AUTH_MODULE_OPTIONS,
194
- useFactory: async (factory)=>{
195
- const config = await factory.createAuthOptions();
196
- return {
138
+ useFactory: async (factory)=>({
197
139
  ...staticOptions,
198
- config
199
- };
200
- },
140
+ config: await factory.createAuthOptions()
141
+ }),
201
142
  inject: [
202
143
  options.useClass
203
144
  ]
@@ -208,13 +149,10 @@ export class AuthModule {
208
149
  return [
209
150
  {
210
151
  provide: AUTH_MODULE_OPTIONS,
211
- useFactory: async (factory)=>{
212
- const config = await factory.createAuthOptions();
213
- return {
152
+ useFactory: async (factory)=>({
214
153
  ...staticOptions,
215
- config
216
- };
217
- },
154
+ config: await factory.createAuthOptions()
155
+ }),
218
156
  inject: [
219
157
  options.useExisting
220
158
  ]
@@ -228,18 +166,14 @@ export class AuthModule {
228
166
  }
229
167
  ];
230
168
  }
231
- static getEntities(enableCompanyFeature = false) {
232
- const coreEntities = [
233
- User
234
- ];
235
- const companyEntities = enableCompanyFeature ? [
169
+ /** Get auth entities based on feature flags */ static getEntities(enableCompanyFeature = false) {
170
+ return enableCompanyFeature ? [
171
+ User,
236
172
  Company,
237
173
  CompanyBranch,
238
174
  UserCompanyPermission
239
- ] : [];
240
- return [
241
- ...coreEntities,
242
- ...companyEntities
175
+ ] : [
176
+ User
243
177
  ];
244
178
  }
245
179
  }
@@ -26,18 +26,18 @@ function _ts_param(paramIndex, decorator) {
26
26
  };
27
27
  }
28
28
  import { Inject, Injectable, InternalServerErrorException, Logger, Optional } from '@nestjs/common';
29
- import { AuthModuleOptions } from '../interfaces/auth-module-options.interface';
30
29
  import { AUTH_MODULE_OPTIONS } from '../config/auth.constants';
30
+ import { AuthModuleOptions } from '../interfaces/auth-module-options.interface';
31
31
  export class AuthConfigService {
32
- // Database Mode
33
- /** Get database mode (single or multi-tenant) */ getDatabaseMode() {
32
+ // Database Mode (required by IModuleConfigService)
33
+ getDatabaseMode() {
34
34
  return this.options.bootstrapAppConfig?.databaseMode ?? 'single';
35
35
  }
36
- /** Check if running in multi-tenant mode */ isMultiTenant() {
36
+ isMultiTenant() {
37
37
  return this.getDatabaseMode() === 'multi-tenant';
38
38
  }
39
39
  // Feature Flags
40
- /** Check if company feature is enabled */ isCompanyFeatureEnabled() {
40
+ isCompanyFeatureEnabled() {
41
41
  return this.options.bootstrapAppConfig?.enableCompanyFeature ?? false;
42
42
  }
43
43
  // JWT Configuration
@@ -54,16 +54,14 @@ export class AuthConfigService {
54
54
  if (this.config.refreshTokenSecret) {
55
55
  return this.config.refreshTokenSecret;
56
56
  }
57
- // Production: require separate refresh token secret for security
58
57
  if (process.env.NODE_ENV === 'production') {
59
58
  throw new InternalServerErrorException('[AuthModule] REFRESH_TOKEN_SECRET is required in production - ' + 'using the same secret for access and refresh tokens is a security risk');
60
59
  }
61
- // Development: warn once about fallback to JWT secret
62
60
  if (!this.refreshTokenSecretWarned) {
63
61
  this.refreshTokenSecretWarned = true;
64
62
  this.logger.warn('REFRESH_TOKEN_SECRET not configured - using JWT_SECRET as fallback. ' + 'For better security, configure a separate refresh token secret.');
65
63
  }
66
- return this.config.jwtSecret ?? this.getJwtSecret();
64
+ return this.getJwtSecret();
67
65
  }
68
66
  /** Get refresh token expiration time */ getRefreshTokenExpiration() {
69
67
  return this.config.refreshTokenExpiration ?? '7d';
@@ -75,27 +73,6 @@ export class AuthConfigService {
75
73
  /** Get frontend URL for email links */ getFrontendUrl() {
76
74
  return this.config.frontendUrl;
77
75
  }
78
- // Database Configuration
79
- /** Get default database config */ getDefaultDatabaseConfig() {
80
- return this.config.defaultDatabaseConfig ?? this.config.tenantDefaultDatabaseConfig;
81
- }
82
- /** Get tenant default database config (for multi-tenant) */ getTenantDefaultDatabaseConfig() {
83
- return this.config.tenantDefaultDatabaseConfig;
84
- }
85
- /** Get registered tenants */ getTenants() {
86
- return this.config.tenants ?? [];
87
- }
88
- // Raw Options
89
- /** Get full module options */ getOptions() {
90
- return {
91
- ...this.options
92
- };
93
- }
94
- /** Get runtime config */ getConfig() {
95
- return {
96
- ...this.config
97
- };
98
- }
99
76
  constructor(injectedOptions){
100
77
  _define_property(this, "logger", new Logger(AuthConfigService.name));
101
78
  _define_property(this, "options", void 0);
@@ -90,40 +90,28 @@ export class AuthDataSourceProvider extends MultiTenantDataSourceService {
90
90
  };
91
91
  }
92
92
  // Feature Flags
93
- /** Get global enable company feature flag */ getEnableCompanyFeature() {
94
- return this.authOptions.bootstrapAppConfig?.enableCompanyFeature ?? false;
95
- }
96
- /** Get enable company feature for specific tenant. Falls back to global setting. */ getEnableCompanyFeatureForTenant(tenant) {
97
- return tenant?.enableCompanyFeature ?? this.getEnableCompanyFeature();
98
- }
99
- /** Get enable company feature for current request context */ getEnableCompanyFeatureForCurrentTenant() {
100
- return this.getEnableCompanyFeatureForTenant(this.getCurrentTenant() ?? undefined);
93
+ /** Check if company feature is enabled (tenant-specific or global fallback) */ isCompanyFeatureEnabled(tenant) {
94
+ const effectiveTenant = tenant ?? this.getCurrentTenant();
95
+ return effectiveTenant?.enableCompanyFeature ?? this.authOptions.bootstrapAppConfig?.enableCompanyFeature ?? false;
101
96
  }
102
97
  // Entity Management
103
- /** Get auth entities based on company feature flag */ async getAuthEntities(enableCompanyFeature) {
104
- const enable = enableCompanyFeature ?? this.getEnableCompanyFeature();
98
+ /** Get auth entities based on company feature flag */ async getAuthEntities() {
105
99
  const { Company, CompanyBranch, User, UserCompanyPermission, UserToken, PendingRegistration } = await import('../entities');
106
100
  const coreEntities = [
107
101
  User,
108
102
  UserToken,
109
103
  PendingRegistration
110
104
  ];
111
- const companyEntities = enable ? [
105
+ return this.isCompanyFeatureEnabled() ? [
106
+ ...coreEntities,
112
107
  Company,
113
108
  CompanyBranch,
114
109
  UserCompanyPermission
115
- ] : [];
116
- return [
117
- ...coreEntities,
118
- ...companyEntities
119
- ];
110
+ ] : coreEntities;
120
111
  }
121
112
  // Overrides
122
113
  /** 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);
114
+ return super.createDataSourceFromConfig(config, await this.getAuthEntities());
127
115
  }
128
116
  constructor(authOptions, request){
129
117
  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);