@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
@@ -25,75 +25,77 @@ function _ts_param(paramIndex, decorator) {
25
25
  decorator(target, key, paramIndex);
26
26
  };
27
27
  }
28
+ import { HybridCache } from '@flusys/nestjs-shared/classes';
29
+ import { ErrorHandler, generateUniqueSlug } from '@flusys/nestjs-shared/utils';
28
30
  import { BadRequestException, Inject, Injectable, Logger, NotFoundException, Optional, Scope, UnauthorizedException } from '@nestjs/common';
29
31
  import { JwtService } from '@nestjs/jwt';
30
- import { InjectRepository } from '@nestjs/typeorm';
31
32
  import * as bcrypt from 'bcrypt';
32
- import { Repository } from 'typeorm';
33
- import { ErrorHandler } from '@flusys/nestjs-shared/utils';
34
- import { AuthConfigService } from './auth-config.service';
35
- import { AuthDataSourceProvider } from './auth-datasource.provider';
36
- import { PermissionType } from '../enums';
37
33
  import { BCRYPT_SALT_ROUNDS, TOKEN_REVOKED_PREFIX } from '../config';
38
- import { HybridCache } from '@flusys/nestjs-shared/classes';
39
- import { AuthEmailService } from './auth-email.service';
40
34
  import { CompanyBranch } from '../entities/company-branch.entity';
41
35
  import { Company } from '../entities/company.entity';
42
36
  import { UserCompanyPermission } from '../entities/user-company-permission.entity';
43
37
  import { User } from '../entities/user.entity';
38
+ import { PermissionType } from '../enums';
39
+ import { AuthConfigService } from './auth-config.service';
40
+ import { AuthDataSourceProvider } from './auth-datasource.provider';
41
+ import { AuthEmailService } from './auth-email.service';
44
42
  import { CompanySelectionSessionService } from './company-selection-session.service';
45
43
  export class AuthenticationService {
44
+ // Feature Flags
45
+ isCompanyFeatureEnabled() {
46
+ return this.dataSourceProvider?.isCompanyFeatureEnabled() ?? this.authConfig.isCompanyFeatureEnabled();
47
+ }
48
+ isEmailVerificationEnabled() {
49
+ const featureEnabled = this.dataSourceProvider?.isEmailVerificationEnabled() ?? this.authConfig.isEmailVerificationEnabled();
50
+ const providerAvailable = this.authEmailService?.isEmailEnabled() ?? false;
51
+ return featureEnabled && providerAvailable;
52
+ }
46
53
  // Repository Getters
47
54
  async getUserRepository() {
48
- if (this.dataSourceProvider) {
49
- return this.dataSourceProvider.getRepository(User);
55
+ if (!this.dataSourceProvider) {
56
+ throw new Error('User repository not available');
50
57
  }
51
- if (this.injectedUserRepository) {
52
- return this.injectedUserRepository;
53
- }
54
- throw new Error('User repository not available');
58
+ return this.dataSourceProvider.getRepository(User);
55
59
  }
56
60
  async getPermissionRepository() {
57
- if (!this.authConfig.isCompanyFeatureEnabled()) return null;
58
- if (this.dataSourceProvider) {
59
- return this.dataSourceProvider.getRepository(UserCompanyPermission);
60
- }
61
- return this.injectedPermissionRepository ?? null;
61
+ if (!this.isCompanyFeatureEnabled() || !this.dataSourceProvider) return null;
62
+ return this.dataSourceProvider.getRepository(UserCompanyPermission);
62
63
  }
63
64
  async getCompanyRepository() {
64
- if (!this.authConfig.isCompanyFeatureEnabled()) return null;
65
- if (this.dataSourceProvider) {
66
- return this.dataSourceProvider.getRepository(Company);
67
- }
68
- return this.injectedCompanyRepository ?? null;
65
+ if (!this.isCompanyFeatureEnabled() || !this.dataSourceProvider) return null;
66
+ return this.dataSourceProvider.getRepository(Company);
69
67
  }
70
68
  async getBranchRepository() {
71
- if (!this.authConfig.isCompanyFeatureEnabled()) return null;
72
- if (this.dataSourceProvider) {
73
- return this.dataSourceProvider.getRepository(CompanyBranch);
74
- }
75
- return this.injectedBranchRepository ?? null;
69
+ if (!this.isCompanyFeatureEnabled() || !this.dataSourceProvider) return null;
70
+ return this.dataSourceProvider.getRepository(CompanyBranch);
76
71
  }
77
72
  // Login
78
- /** Login with email and password. Returns tokens or requires company/branch selection. */ async login(email, password) {
73
+ async login(email, password) {
74
+ // Check for pending registration first (user registered but hasn't verified email yet)
75
+ if (this.isEmailVerificationEnabled() && await this.authEmailService.hasPendingRegistration(email)) {
76
+ return {
77
+ requiresEmailVerification: true,
78
+ email,
79
+ message: 'Please verify your email address to complete registration.'
80
+ };
81
+ }
79
82
  const user = await this.validateUser(email, password);
80
83
  if (!user.isActive) {
81
84
  throw new UnauthorizedException('User account is deactivated');
82
85
  }
83
- // Check email verification if email service is enabled
84
- if (this.authEmailService?.isEmailEnabled() && !user.emailVerified) {
86
+ if (this.isEmailVerificationEnabled() && !user.emailVerified) {
85
87
  return {
86
88
  requiresEmailVerification: true,
87
89
  email: user.email,
88
90
  message: 'Please verify your email address before logging in.'
89
91
  };
90
92
  }
91
- if (!this.authConfig.isCompanyFeatureEnabled()) {
93
+ if (!this.isCompanyFeatureEnabled()) {
92
94
  return this.generateLoginResponse(user);
93
95
  }
94
96
  return this.handleCompanyBasedLogin(user);
95
97
  }
96
- /** Handle login when company feature is enabled */ async handleCompanyBasedLogin(user) {
98
+ async handleCompanyBasedLogin(user) {
97
99
  const permissionRepository = await this.getPermissionRepository();
98
100
  const branchRepository = await this.getBranchRepository();
99
101
  if (!permissionRepository || !branchRepository) {
@@ -120,7 +122,7 @@ export class AuthenticationService {
120
122
  // If user has no company assignments yet, return simple login response
121
123
  // This allows users to login and be assigned to companies later
122
124
  if (companies.length === 0) {
123
- return this.generateLoginResponse(user, true);
125
+ return this.generateLoginResponse(user);
124
126
  }
125
127
  // Get branch permissions
126
128
  const branchPermissions = await permissionRepository.find({
@@ -144,19 +146,24 @@ export class AuthenticationService {
144
146
  return await this.generateCompanySelectionResponse(user, companies, branches);
145
147
  }
146
148
  // Registration
147
- /** Register a new user. If email enabled, creates pending registration. Otherwise creates user directly. */ async register(dto, verifyUrlBase) {
149
+ async register(dto, verifyUrlBase) {
148
150
  const userRepository = await this.getUserRepository();
149
151
  const existingUser = await userRepository.findOne({
150
152
  where: {
151
153
  email: dto.email
152
154
  }
153
155
  });
156
+ // When company feature is enabled and user exists, allow joining/creating company
157
+ if (existingUser && this.isCompanyFeatureEnabled()) {
158
+ return this.handleExistingUserCompanyRegistration(existingUser, dto);
159
+ }
160
+ // User exists but company feature is off - email must be unique
154
161
  if (existingUser) {
155
- throw new BadRequestException('Registration failed. Please try again or contact support.');
162
+ throw new BadRequestException('Registration failed due to email exists. Please try again or contact support.');
156
163
  }
157
164
  // If email verification is enabled, create pending registration instead of user
158
- if (this.authEmailService?.isEmailEnabled() && verifyUrlBase) {
159
- const companyData = this.authConfig.isCompanyFeatureEnabled() ? {
165
+ if (this.isEmailVerificationEnabled() && verifyUrlBase) {
166
+ const companyData = this.isCompanyFeatureEnabled() ? {
160
167
  companySlug: dto.companySlug,
161
168
  branchSlug: dto.branchSlug,
162
169
  newCompanyName: dto.newCompanyName,
@@ -179,7 +186,39 @@ export class AuthenticationService {
179
186
  // No email verification - create user directly
180
187
  return this.createUserDirectly(dto);
181
188
  }
182
- /** Create user directly (no email verification) */ async createUserDirectly(dto) {
189
+ async handleExistingUserCompanyRegistration(existingUser, dto) {
190
+ if (!dto.companySlug && !dto.newCompanyName) {
191
+ throw new BadRequestException('Email already registered. Please login or provide a company to join/create.');
192
+ }
193
+ const permissionRepository = await this.getPermissionRepository();
194
+ const companyRepository = await this.getCompanyRepository();
195
+ if (!permissionRepository || !companyRepository) {
196
+ throw new BadRequestException('Company feature repositories not available');
197
+ }
198
+ // For existing users joining a company, check if already assigned
199
+ if (dto.companySlug) {
200
+ const company = await companyRepository.findOne({
201
+ where: {
202
+ slug: dto.companySlug,
203
+ isActive: true
204
+ }
205
+ });
206
+ if (company) {
207
+ const existingPermission = await permissionRepository.findOne({
208
+ where: {
209
+ userId: existingUser.id,
210
+ permissionType: PermissionType.COMPANY,
211
+ targetId: company.id
212
+ }
213
+ });
214
+ if (existingPermission) {
215
+ throw new BadRequestException('You are already assigned to this company. Please login.');
216
+ }
217
+ }
218
+ }
219
+ return this.processCompanyRegistration(existingUser, dto, true);
220
+ }
221
+ async createUserDirectly(dto) {
183
222
  const userRepository = await this.getUserRepository();
184
223
  const hashedPassword = await bcrypt.hash(dto.password, BCRYPT_SALT_ROUNDS);
185
224
  const user = userRepository.create({
@@ -192,14 +231,13 @@ export class AuthenticationService {
192
231
  phoneVerified: false
193
232
  });
194
233
  await userRepository.save(user);
195
- if (!this.authConfig.isCompanyFeatureEnabled()) {
196
- return this.generateRegistrationResponse(user, false, false);
234
+ if (!this.isCompanyFeatureEnabled()) {
235
+ return this.generateRegistrationResponse(user);
197
236
  }
198
- return this.handleCompanyRegistration(user, dto, false);
237
+ return this.processCompanyRegistration(user, dto);
199
238
  }
200
- /** Create user from pending registration (after email verification) */ async createUserFromPendingRegistration(pending) {
239
+ async createUserFromPendingRegistration(pending) {
201
240
  const userRepository = await this.getUserRepository();
202
- // Check if user already exists (race condition protection)
203
241
  const existingUser = await userRepository.findOne({
204
242
  where: {
205
243
  email: pending.email
@@ -208,7 +246,6 @@ export class AuthenticationService {
208
246
  if (existingUser) {
209
247
  throw new BadRequestException('This email has already been registered.');
210
248
  }
211
- // Create user with verified email
212
249
  const user = userRepository.create({
213
250
  name: pending.name,
214
251
  email: pending.email,
@@ -219,110 +256,106 @@ export class AuthenticationService {
219
256
  phoneVerified: false
220
257
  });
221
258
  await userRepository.save(user);
222
- // Handle company feature if enabled
223
- if (this.authConfig.isCompanyFeatureEnabled() && pending.companyData) {
224
- return this.handleCompanyRegistrationFromPending(user, pending.companyData);
259
+ if (this.isCompanyFeatureEnabled() && pending.companyData) {
260
+ return this.processCompanyRegistration(user, pending.companyData);
225
261
  }
226
- return this.generateRegistrationResponse(user, this.authConfig.isCompanyFeatureEnabled(), false);
227
- }
228
- /** Handle company registration from pending registration data */ async handleCompanyRegistrationFromPending(user, companyData) {
229
- return this.processCompanyRegistration(user, companyData, false);
262
+ return this.generateRegistrationResponse(user);
230
263
  }
231
- /** Handle company-related registration logic */ async handleCompanyRegistration(user, dto, requiresEmailVerification) {
232
- return this.processCompanyRegistration(user, dto, requiresEmailVerification);
233
- }
234
- /** Shared logic for company registration (join existing or create new) */ async processCompanyRegistration(user, data, requiresEmailVerification) {
264
+ async processCompanyRegistration(user, data, throwOnUnavailable = false) {
235
265
  const companyRepository = await this.getCompanyRepository();
236
266
  const branchRepository = await this.getBranchRepository();
237
267
  const permissionRepository = await this.getPermissionRepository();
238
268
  if (!companyRepository || !branchRepository || !permissionRepository) {
239
- return this.generateRegistrationResponse(user, true, requiresEmailVerification);
269
+ if (throwOnUnavailable) throw new BadRequestException('Company feature repositories not available');
270
+ return this.generateRegistrationResponse(user);
271
+ }
272
+ const { company, branch } = await this.findOrCreateCompanyAndBranch(data, companyRepository, branchRepository);
273
+ if (company) {
274
+ await this.assignUserPermissions(user.id, company.id, branch?.id, permissionRepository);
275
+ return this.generateRegistrationResponseWithCompany(user, company, branch ?? undefined);
240
276
  }
241
- let company = null;
242
- let branch = null;
277
+ return this.generateRegistrationResponse(user);
278
+ }
279
+ async findOrCreateCompanyAndBranch(data, companyRepo, branchRepo) {
243
280
  if (data.companySlug) {
244
- company = await companyRepository.findOne({
281
+ const company = await companyRepo.findOne({
245
282
  where: {
246
283
  slug: data.companySlug,
247
284
  isActive: true
248
285
  }
249
286
  });
250
- if (!company) {
251
- throw new BadRequestException('Company not found or inactive');
252
- }
253
- if (data.branchSlug) {
254
- branch = await branchRepository.findOne({
255
- where: {
256
- slug: data.branchSlug,
257
- companyId: company.id,
258
- isActive: true
259
- }
260
- });
261
- if (!branch) {
262
- throw new BadRequestException('Branch not found or inactive');
287
+ if (!company) throw new BadRequestException('Company not found or inactive');
288
+ const branch = data.branchSlug ? await branchRepo.findOne({
289
+ where: {
290
+ slug: data.branchSlug,
291
+ companyId: company.id,
292
+ isActive: true
263
293
  }
264
- } else {
265
- branch = await branchRepository.findOne({
266
- where: {
267
- companyId: company.id,
268
- isActive: true
269
- },
270
- order: {
271
- serial: 'ASC',
272
- createdAt: 'ASC'
273
- }
274
- });
275
- }
276
- } else if (data.newCompanyName) {
277
- const slug = this.generateSlug(data.newCompanyName);
278
- const existingCompany = await companyRepository.findOne({
294
+ }) : await branchRepo.findOne({
279
295
  where: {
280
- slug
296
+ companyId: company.id,
297
+ isActive: true
298
+ },
299
+ order: {
300
+ serial: 'ASC',
301
+ createdAt: 'ASC'
281
302
  }
282
303
  });
283
- if (existingCompany) {
284
- throw new BadRequestException('Company creation failed. Please try a different name.');
285
- }
286
- company = companyRepository.create({
304
+ if (data.branchSlug && !branch) throw new BadRequestException('Branch not found or inactive');
305
+ return {
306
+ company,
307
+ branch
308
+ };
309
+ }
310
+ if (data.newCompanyName) {
311
+ const slug = await generateUniqueSlug(data.newCompanyName, async (baseSlug)=>{
312
+ const rows = await companyRepo.createQueryBuilder('c').select('c.slug').where('c.slug = :base OR c.slug LIKE :pattern', {
313
+ base: baseSlug,
314
+ pattern: `${baseSlug}-%`
315
+ }).getMany();
316
+ return rows.map((r)=>r.slug);
317
+ });
318
+ const company = companyRepo.create({
287
319
  name: data.newCompanyName,
288
320
  slug,
289
321
  phone: data.newCompanyPhone,
290
322
  address: data.newCompanyAddress,
291
323
  isActive: true
292
324
  });
293
- await companyRepository.save(company);
294
- branch = branchRepository.create({
325
+ await companyRepo.save(company);
326
+ const branch = branchRepo.create({
295
327
  name: 'Main Branch',
296
328
  slug: 'main-branch',
297
329
  companyId: company.id,
298
330
  isActive: true
299
331
  });
300
- await branchRepository.save(branch);
301
- }
302
- if (company) {
303
- const companyPermission = permissionRepository.create({
304
- userId: user.id,
305
- permissionType: PermissionType.COMPANY,
306
- targetId: company.id
307
- });
308
- await permissionRepository.save(companyPermission);
309
- if (branch) {
310
- const branchPermission = permissionRepository.create({
311
- userId: user.id,
312
- permissionType: PermissionType.BRANCH,
313
- targetId: branch.id
314
- });
315
- await permissionRepository.save(branchPermission);
316
- }
317
- return this.generateRegistrationResponseWithCompany(user, company, branch ?? undefined, requiresEmailVerification);
332
+ await branchRepo.save(branch);
333
+ return {
334
+ company,
335
+ branch
336
+ };
318
337
  }
319
- return this.generateRegistrationResponse(user, true, requiresEmailVerification);
338
+ return {
339
+ company: null,
340
+ branch: null
341
+ };
320
342
  }
321
- /** Generate URL-friendly slug from name */ generateSlug(name) {
322
- return name.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '').substring(0, 100);
343
+ async assignUserPermissions(userId, companyId, branchId, permissionRepo) {
344
+ await permissionRepo.save(permissionRepo.create({
345
+ userId,
346
+ permissionType: PermissionType.COMPANY,
347
+ targetId: companyId
348
+ }));
349
+ if (branchId) {
350
+ await permissionRepo.save(permissionRepo.create({
351
+ userId,
352
+ permissionType: PermissionType.BRANCH,
353
+ targetId: branchId
354
+ }));
355
+ }
323
356
  }
324
357
  // Company/Branch Selection
325
- /** Select company and branch (step 2 of login). Frontend receives all options and user selects both. */ async select(sessionId, companyId, branchId) {
358
+ async select(sessionId, companyId, branchId) {
326
359
  this.ensureCompanyFeatureEnabled();
327
360
  if (!this.sessionService) {
328
361
  throw new BadRequestException('Session service not available');
@@ -331,66 +364,13 @@ export class AuthenticationService {
331
364
  if (!session) {
332
365
  throw new UnauthorizedException('Invalid or expired session');
333
366
  }
334
- const userRepository = await this.getUserRepository();
335
- const user = await userRepository.findOne({
336
- where: {
337
- id: session.userId
338
- }
339
- });
340
- if (!user) {
341
- throw new NotFoundException('User not found');
342
- }
343
- const permissionRepository = await this.getPermissionRepository();
344
- const companyRepository = await this.getCompanyRepository();
345
- const branchRepository = await this.getBranchRepository();
346
- if (!permissionRepository || !companyRepository || !branchRepository) {
347
- throw new BadRequestException('Repositories not available');
348
- }
349
- // Validate company access
350
- const companyPermission = await permissionRepository.findOne({
351
- where: {
352
- userId: user.id,
353
- permissionType: PermissionType.COMPANY,
354
- targetId: companyId
355
- }
356
- });
357
- if (!companyPermission) {
358
- throw new UnauthorizedException('No access to this company');
359
- }
360
- const company = await companyRepository.findOne({
361
- where: {
362
- id: companyId,
363
- isActive: true
364
- }
365
- });
366
- if (!company) {
367
- throw new UnauthorizedException('Company not found or inactive');
368
- }
369
- // Validate branch access
370
- const branchPermission = await permissionRepository.findOne({
371
- where: {
372
- userId: user.id,
373
- permissionType: PermissionType.BRANCH,
374
- targetId: branchId
375
- }
376
- });
377
- if (!branchPermission) {
378
- throw new UnauthorizedException('No access to this branch');
379
- }
380
- const branch = await branchRepository.findOne({
381
- where: {
382
- id: branchId,
383
- companyId,
384
- isActive: true
385
- }
386
- });
387
- if (!branch) {
388
- throw new UnauthorizedException('Branch not found or inactive');
389
- }
390
- return this.generateLoginResponseWithCompany(user, company, branch);
367
+ return this.validateAndLoginWithCompany(session.userId, companyId, branchId);
391
368
  }
392
- /** Switch company/branch after login */ async switchCompany(userId, companyId, branchId) {
369
+ async switchCompany(userId, companyId, branchId) {
393
370
  this.ensureCompanyFeatureEnabled();
371
+ return this.validateAndLoginWithCompany(userId, companyId, branchId);
372
+ }
373
+ async validateAndLoginWithCompany(userId, companyId, branchId) {
394
374
  const userRepository = await this.getUserRepository();
395
375
  const user = await userRepository.findOne({
396
376
  where: {
@@ -407,14 +387,14 @@ export class AuthenticationService {
407
387
  throw new BadRequestException('Repositories not available');
408
388
  }
409
389
  // Validate company access
410
- const companyPermission = await permissionRepository.findOne({
390
+ const hasCompanyAccess = await permissionRepository.findOne({
411
391
  where: {
412
392
  userId,
413
393
  permissionType: PermissionType.COMPANY,
414
394
  targetId: companyId
415
395
  }
416
396
  });
417
- if (!companyPermission) {
397
+ if (!hasCompanyAccess) {
418
398
  throw new UnauthorizedException('No access to this company');
419
399
  }
420
400
  const company = await companyRepository.findOne({
@@ -426,14 +406,15 @@ export class AuthenticationService {
426
406
  if (!company) {
427
407
  throw new UnauthorizedException('Company not found or inactive');
428
408
  }
429
- const branchPermission = await permissionRepository.findOne({
409
+ // Validate branch access
410
+ const hasBranchAccess = await permissionRepository.findOne({
430
411
  where: {
431
412
  userId,
432
413
  permissionType: PermissionType.BRANCH,
433
414
  targetId: branchId
434
415
  }
435
416
  });
436
- if (!branchPermission) {
417
+ if (!hasBranchAccess) {
437
418
  throw new UnauthorizedException('No access to this branch');
438
419
  }
439
420
  const branch = await branchRepository.findOne({
@@ -449,11 +430,14 @@ export class AuthenticationService {
449
430
  return this.generateLoginResponseWithCompany(user, company, branch);
450
431
  }
451
432
  // Token Management
452
- /** Refresh access token (with token rotation). Returns new access token and new refresh token. */ async refreshToken(refreshToken) {
433
+ async refreshToken(refreshToken) {
453
434
  try {
454
435
  const payload = this.jwtService.verify(refreshToken, {
455
436
  secret: this.authConfig.getRefreshTokenSecret()
456
437
  });
438
+ if (await this.isTokenRevoked(payload.id, payload.iat)) {
439
+ throw new UnauthorizedException('Token has been revoked');
440
+ }
457
441
  const userRepository = await this.getUserRepository();
458
442
  const user = await userRepository.findOne({
459
443
  where: {
@@ -463,7 +447,7 @@ export class AuthenticationService {
463
447
  if (!user || !user.isActive) {
464
448
  throw new UnauthorizedException('Invalid refresh token');
465
449
  }
466
- const accessPayload = {
450
+ return this.generateTokens({
467
451
  id: user.id,
468
452
  email: user.email,
469
453
  type: 'access',
@@ -473,69 +457,32 @@ export class AuthenticationService {
473
457
  },
474
458
  ...payload.branchId && {
475
459
  branchId: payload.branchId
476
- },
477
- ...payload.companyLogoId && {
478
- companyLogoId: payload.companyLogoId
479
- },
480
- ...payload.branchLogoId && {
481
- branchLogoId: payload.branchLogoId
482
460
  }
483
- };
484
- const refreshPayload = {
485
- id: user.id,
486
- email: user.email,
487
- type: 'refresh',
488
- profilePictureId: user.profilePictureId ?? undefined,
489
- ...payload.companyId && {
490
- companyId: payload.companyId
491
- },
492
- ...payload.branchId && {
493
- branchId: payload.branchId
494
- },
495
- ...payload.companyLogoId && {
496
- companyLogoId: payload.companyLogoId
497
- },
498
- ...payload.branchLogoId && {
499
- branchLogoId: payload.branchLogoId
500
- }
501
- };
502
- return {
503
- accessToken: this.jwtService.sign(accessPayload, {
504
- secret: this.authConfig.getJwtSecret(),
505
- expiresIn: this.authConfig.getJwtExpiration()
506
- }),
507
- refreshToken: this.jwtService.sign(refreshPayload, {
508
- secret: this.authConfig.getRefreshTokenSecret(),
509
- expiresIn: this.authConfig.getRefreshTokenExpiration()
510
- })
511
- };
461
+ });
512
462
  } catch (error) {
513
- // Log error details for debugging (not exposed to client)
514
463
  ErrorHandler.logError(this.logger, error, 'refreshToken');
515
464
  throw new UnauthorizedException('Invalid or expired refresh token');
516
465
  }
517
466
  }
518
- /** Change password */ async changePassword(userId, currentPassword, newPassword) {
467
+ async changePassword(userId, currentPassword, newPassword) {
519
468
  const userRepository = await this.getUserRepository();
520
469
  const user = await userRepository.findOne({
521
470
  where: {
522
471
  id: userId
523
472
  }
524
473
  });
525
- if (!user) {
526
- throw new UnauthorizedException('User not found');
527
- }
528
- const isPasswordValid = await bcrypt.compare(currentPassword, user.password || '');
529
- if (!isPasswordValid) {
474
+ if (!user) throw new UnauthorizedException('User not found');
475
+ if (!await bcrypt.compare(currentPassword, user.password || '')) {
530
476
  throw new UnauthorizedException('Current password is incorrect');
531
477
  }
532
478
  user.password = await bcrypt.hash(newPassword, BCRYPT_SALT_ROUNDS);
533
479
  await userRepository.save(user);
534
480
  }
535
- /** Logout - Revokes all tokens. Stores revocation timestamp in cache. */ async logout(userId) {
481
+ async logout(userId) {
536
482
  if (!this.cacheManager) {
537
- // Cache not available - graceful degradation (client-side logout only)
538
- return;
483
+ // Cache is required for secure logout - tokens cannot be revoked without it
484
+ this.logger.error(`SECURITY: Cache not available for logout (userId: ${userId}). ` + 'Token revocation failed - tokens will remain valid until expiry. ' + 'Configure cache (Redis) to enable proper token revocation.');
485
+ throw new BadRequestException('Logout service temporarily unavailable. Please try again later.');
539
486
  }
540
487
  const revokedAt = Math.floor(Date.now() / 1000); // Unix timestamp in seconds
541
488
  const cacheKey = `${TOKEN_REVOKED_PREFIX}:${userId}`;
@@ -543,8 +490,9 @@ export class AuthenticationService {
543
490
  const refreshTokenExpiry = this.authConfig.getRefreshTokenExpiration();
544
491
  const ttlMs = this.parseExpiryToMs(refreshTokenExpiry);
545
492
  await this.cacheManager.set(cacheKey, revokedAt, ttlMs);
493
+ this.logger.log(`User ${userId} logged out - all tokens revoked`);
546
494
  }
547
- /** Check if a token is revoked (issued before user's revocation timestamp) */ async isTokenRevoked(userId, tokenIssuedAt) {
495
+ async isTokenRevoked(userId, tokenIssuedAt) {
548
496
  if (!this.cacheManager || !tokenIssuedAt) {
549
497
  return false;
550
498
  }
@@ -556,7 +504,7 @@ export class AuthenticationService {
556
504
  // Token is revoked if it was issued before the revocation timestamp
557
505
  return tokenIssuedAt < revokedAt;
558
506
  }
559
- /** Parse JWT expiry string to milliseconds */ parseExpiryToMs(expiry) {
507
+ parseExpiryToMs(expiry) {
560
508
  const match = expiry.match(/^(\d+)([smhd])$/);
561
509
  if (!match) return 7 * 24 * 60 * 60 * 1000; // Default 7 days
562
510
  const value = parseInt(match[1], 10);
@@ -575,7 +523,7 @@ export class AuthenticationService {
575
523
  }
576
524
  }
577
525
  // Query Methods
578
- /** Get user's companies */ async getUserCompanies(userId) {
526
+ async getUserCompanies(userId) {
579
527
  this.ensureCompanyFeatureEnabled();
580
528
  const permissionRepository = await this.getPermissionRepository();
581
529
  const companyRepository = await this.getCompanyRepository();
@@ -596,7 +544,7 @@ export class AuthenticationService {
596
544
  active: true
597
545
  }).orderBy('c.name', 'ASC').getMany();
598
546
  }
599
- /** Get branches for a company that user has access to */ async getUserBranches(userId, companyId) {
547
+ async getUserBranches(userId, companyId) {
600
548
  this.ensureCompanyFeatureEnabled();
601
549
  const permissionRepository = await this.getPermissionRepository();
602
550
  const branchRepository = await this.getBranchRepository();
@@ -631,7 +579,7 @@ export class AuthenticationService {
631
579
  active: true
632
580
  }).orderBy('b.serial', 'ASC').addOrderBy('b.name', 'ASC').getMany();
633
581
  }
634
- /** Get company by ID */ async getCompanyById(companyId) {
582
+ async getCompanyById(companyId) {
635
583
  const companyRepository = await this.getCompanyRepository();
636
584
  if (!companyRepository) {
637
585
  return null;
@@ -642,7 +590,7 @@ export class AuthenticationService {
642
590
  }
643
591
  });
644
592
  }
645
- /** Get branch by ID */ async getBranchById(branchId) {
593
+ async getBranchById(branchId) {
646
594
  const branchRepository = await this.getBranchRepository();
647
595
  if (!branchRepository) {
648
596
  return null;
@@ -653,61 +601,35 @@ export class AuthenticationService {
653
601
  }
654
602
  });
655
603
  }
656
- /** Get user info for /auth/me endpoint. Returns user, company, and branch info (no tokens). */ async getUserInfo(userId, companyId, branchId) {
604
+ async getUserInfo(userId, companyId, branchId) {
657
605
  const userRepository = await this.getUserRepository();
658
606
  const user = await userRepository.findOne({
659
607
  where: {
660
608
  id: userId
661
609
  }
662
610
  });
663
- if (!user) {
664
- throw new UnauthorizedException('User not found');
665
- }
666
- // Build response (no tokens)
611
+ if (!user) throw new UnauthorizedException('User not found');
667
612
  const response = {
668
- user: {
669
- id: user.id,
670
- email: user.email,
671
- name: user.name ?? undefined,
672
- phone: user.phone ?? undefined,
673
- profilePictureId: user.profilePictureId ?? undefined
674
- }
613
+ user: this.toUserInfo(user)
675
614
  };
676
- // Add company/branch if available (when company feature is enabled)
677
- if (this.authConfig.isCompanyFeatureEnabled()) {
678
- // When company feature is enabled, companyId MUST be present
615
+ if (this.isCompanyFeatureEnabled()) {
679
616
  if (!companyId) {
680
- throw new UnauthorizedException('Company feature is enabled but user has no company assigned. Please select a company.');
617
+ throw new UnauthorizedException('Company feature is enabled but user has no company assigned.');
681
618
  }
682
619
  const company = await this.getCompanyById(companyId);
683
- if (!company) {
684
- throw new UnauthorizedException(`Company with ID ${companyId} not found. Please select a valid company.`);
685
- }
686
- response.company = {
687
- id: company.id,
688
- name: company.name,
689
- slug: company.slug,
690
- logoId: company.logoId ?? null
691
- };
692
- // Branch is optional in some configurations, but if provided it must exist
620
+ if (!company) throw new UnauthorizedException('Company not found.');
621
+ response.company = this.toCompanyInfo(company);
693
622
  if (branchId) {
694
623
  const branch = await this.getBranchById(branchId);
695
- if (!branch) {
696
- throw new UnauthorizedException(`Branch with ID ${branchId} not found. Please select a valid branch.`);
697
- }
698
- response.branch = {
699
- id: branch.id,
700
- name: branch.name,
701
- slug: branch.slug,
702
- logoId: branch.logoId ?? null
703
- };
624
+ if (!branch) throw new UnauthorizedException('Branch not found.');
625
+ response.branch = this.toBranchInfo(branch);
704
626
  }
705
627
  }
706
628
  return response;
707
629
  }
708
630
  // Helper Methods
709
631
  ensureCompanyFeatureEnabled() {
710
- if (!this.authConfig.isCompanyFeatureEnabled()) {
632
+ if (!this.isCompanyFeatureEnabled()) {
711
633
  throw new BadRequestException('Company feature is not enabled');
712
634
  }
713
635
  }
@@ -718,11 +640,7 @@ export class AuthenticationService {
718
640
  email
719
641
  }
720
642
  });
721
- if (!user) {
722
- throw new UnauthorizedException('Invalid credentials');
723
- }
724
- const isPasswordValid = await bcrypt.compare(password, user.password || '');
725
- if (!isPasswordValid) {
643
+ if (!user || !await bcrypt.compare(password, user.password || '')) {
726
644
  throw new UnauthorizedException('Invalid credentials');
727
645
  }
728
646
  user.lastLoginAt = new Date();
@@ -730,84 +648,77 @@ export class AuthenticationService {
730
648
  return user;
731
649
  }
732
650
  // Response Generators
733
- generateLoginResponse(user, companyFeatureEnabled = false) {
734
- const payload = {
651
+ toUserInfo(user) {
652
+ return {
735
653
  id: user.id,
736
654
  email: user.email,
737
- type: 'access'
655
+ name: user.name ?? undefined,
656
+ phone: user.phone ?? null,
657
+ profilePictureId: user.profilePictureId ?? null
738
658
  };
739
- const accessToken = this.jwtService.sign(payload, {
659
+ }
660
+ toCompanyInfo(company) {
661
+ return {
662
+ id: company.id,
663
+ name: company.name,
664
+ slug: company.slug,
665
+ logoId: company.logoId ?? null
666
+ };
667
+ }
668
+ toBranchInfo(branch) {
669
+ return {
670
+ id: branch.id,
671
+ name: branch.name,
672
+ slug: branch.slug,
673
+ logoId: branch.logoId ?? null
674
+ };
675
+ }
676
+ generateTokens(payload) {
677
+ const accessToken = this.jwtService.sign({
678
+ ...payload,
679
+ type: 'access'
680
+ }, {
740
681
  secret: this.authConfig.getJwtSecret(),
741
682
  expiresIn: this.authConfig.getJwtExpiration()
742
683
  });
743
- const refreshPayload = {
744
- id: user.id,
745
- email: user.email,
684
+ const refreshToken = this.jwtService.sign({
685
+ ...payload,
746
686
  type: 'refresh'
747
- };
748
- const refreshToken = this.jwtService.sign(refreshPayload, {
687
+ }, {
749
688
  secret: this.authConfig.getRefreshTokenSecret(),
750
689
  expiresIn: this.authConfig.getRefreshTokenExpiration()
751
690
  });
752
691
  return {
753
692
  accessToken,
754
- refreshToken,
755
- user: {
756
- id: user.id,
757
- email: user.email,
758
- name: user.name ?? undefined,
759
- phone: user.phone ?? null,
760
- profilePictureId: user.profilePictureId ?? null
761
- },
762
- companyFeatureEnabled
693
+ refreshToken
763
694
  };
764
695
  }
765
- generateLoginResponseWithCompany(user, company, branch) {
766
- const payload = {
696
+ generateLoginResponse(user) {
697
+ const { accessToken, refreshToken } = this.generateTokens({
767
698
  id: user.id,
768
699
  email: user.email,
769
- type: 'access',
770
- companyId: company.id,
771
- branchId: branch?.id
772
- };
773
- const accessToken = this.jwtService.sign(payload, {
774
- secret: this.authConfig.getJwtSecret(),
775
- expiresIn: this.authConfig.getJwtExpiration()
700
+ type: 'access'
776
701
  });
777
- const refreshPayload = {
702
+ return {
703
+ accessToken,
704
+ refreshToken,
705
+ user: this.toUserInfo(user)
706
+ };
707
+ }
708
+ generateLoginResponseWithCompany(user, company, branch) {
709
+ const { accessToken, refreshToken } = this.generateTokens({
778
710
  id: user.id,
779
711
  email: user.email,
780
- type: 'refresh',
712
+ type: 'access',
781
713
  companyId: company.id,
782
714
  branchId: branch?.id
783
- };
784
- const refreshToken = this.jwtService.sign(refreshPayload, {
785
- secret: this.authConfig.getRefreshTokenSecret(),
786
- expiresIn: this.authConfig.getRefreshTokenExpiration()
787
715
  });
788
716
  return {
789
717
  accessToken,
790
718
  refreshToken,
791
- user: {
792
- id: user.id,
793
- email: user.email,
794
- name: user.name ?? undefined,
795
- phone: user.phone ?? null,
796
- profilePictureId: user.profilePictureId ?? null
797
- },
798
- company: {
799
- id: company.id,
800
- name: company.name,
801
- slug: company.slug,
802
- logoId: company.logoId ?? null
803
- },
804
- branch: branch ? {
805
- id: branch.id,
806
- name: branch.name,
807
- slug: branch.slug,
808
- logoId: branch.logoId ?? null
809
- } : undefined,
810
- companyFeatureEnabled: true
719
+ user: this.toUserInfo(user),
720
+ company: this.toCompanyInfo(company),
721
+ branch: branch ? this.toBranchInfo(branch) : undefined
811
722
  };
812
723
  }
813
724
  async generateCompanySelectionResponse(user, companies, branches) {
@@ -815,103 +726,42 @@ export class AuthenticationService {
815
726
  throw new BadRequestException('Session service not available');
816
727
  }
817
728
  const sessionId = await this.sessionService.createSession(user.id);
818
- // Build companies with their branches
819
729
  const companiesWithBranches = companies.map((company)=>({
820
- id: company.id,
821
- name: company.name,
822
- slug: company.slug,
730
+ ...this.toCompanyInfo(company),
823
731
  isActive: company.isActive,
824
- logoId: company.logoId ?? null,
825
732
  branches: branches.filter((b)=>b.companyId === company.id).map((b)=>({
826
- id: b.id,
827
- name: b.name,
828
- slug: b.slug,
829
- isActive: b.isActive,
830
- logoId: b.logoId ?? null
733
+ ...this.toBranchInfo(b),
734
+ isActive: b.isActive
831
735
  }))
832
736
  }));
833
737
  return {
834
738
  requiresSelection: true,
835
739
  sessionId,
836
740
  expiresAt: new Date(Date.now() + 5 * 60 * 1000),
837
- user: {
838
- id: user.id,
839
- email: user.email,
840
- name: user.name ?? undefined,
841
- phone: user.phone ?? null,
842
- profilePictureId: user.profilePictureId ?? null
843
- },
741
+ user: this.toUserInfo(user),
844
742
  companies: companiesWithBranches
845
743
  };
846
744
  }
847
- /** Generate registration response - tokens included only if email verification not required */ generateRegistrationResponse(user, companyFeatureEnabled, requiresEmailVerification) {
848
- const userInfo = {
849
- id: user.id,
850
- email: user.email,
851
- name: user.name ?? undefined,
852
- phone: user.phone ?? null,
853
- profilePictureId: user.profilePictureId ?? null
854
- };
855
- if (requiresEmailVerification) {
856
- return {
857
- user: userInfo,
858
- companyFeatureEnabled,
859
- requiresEmailVerification: true
860
- };
861
- }
862
- const loginResponse = this.generateLoginResponse(user, companyFeatureEnabled);
745
+ generateRegistrationResponse(user) {
863
746
  return {
864
- ...loginResponse,
747
+ ...this.generateLoginResponse(user),
865
748
  requiresEmailVerification: false
866
749
  };
867
750
  }
868
- /** Generate registration response with company - tokens included only if email verification not required */ generateRegistrationResponseWithCompany(user, company, branch, requiresEmailVerification = false) {
869
- const userInfo = {
870
- id: user.id,
871
- email: user.email,
872
- name: user.name ?? undefined,
873
- phone: user.phone ?? null,
874
- profilePictureId: user.profilePictureId ?? null
875
- };
876
- const companyInfo = {
877
- id: company.id,
878
- name: company.name,
879
- slug: company.slug,
880
- logoId: company.logoId ?? null
881
- };
882
- const branchInfo = branch ? {
883
- id: branch.id,
884
- name: branch.name,
885
- slug: branch.slug,
886
- logoId: branch.logoId ?? null
887
- } : undefined;
888
- if (requiresEmailVerification) {
889
- return {
890
- user: userInfo,
891
- company: companyInfo,
892
- branch: branchInfo,
893
- companyFeatureEnabled: true,
894
- requiresEmailVerification: true
895
- };
896
- }
897
- const loginResponse = this.generateLoginResponseWithCompany(user, company, branch);
751
+ generateRegistrationResponseWithCompany(user, company, branch) {
898
752
  return {
899
- ...loginResponse,
753
+ ...this.generateLoginResponseWithCompany(user, company, branch),
900
754
  requiresEmailVerification: false
901
755
  };
902
756
  }
903
757
  // NOTE: @Inject() required for bundled code - type metadata may be lost during esbuild
904
- constructor(jwtService, authConfig, cacheManager, dataSourceProvider, sessionService, authEmailService, injectedUserRepository, injectedPermissionRepository, injectedCompanyRepository, injectedBranchRepository){
758
+ constructor(jwtService, authConfig, cacheManager, dataSourceProvider, sessionService, authEmailService){
905
759
  _define_property(this, "jwtService", void 0);
906
760
  _define_property(this, "authConfig", void 0);
907
761
  _define_property(this, "cacheManager", void 0);
908
762
  _define_property(this, "dataSourceProvider", void 0);
909
763
  _define_property(this, "sessionService", void 0);
910
764
  _define_property(this, "authEmailService", void 0);
911
- _define_property(this, "injectedUserRepository", void 0);
912
- _define_property(this, "injectedPermissionRepository", void 0);
913
- _define_property(this, "injectedCompanyRepository", void 0);
914
- _define_property(this, "injectedBranchRepository", void 0);
915
765
  _define_property(this, "logger", void 0);
916
766
  this.jwtService = jwtService;
917
767
  this.authConfig = authConfig;
@@ -919,10 +769,6 @@ export class AuthenticationService {
919
769
  this.dataSourceProvider = dataSourceProvider;
920
770
  this.sessionService = sessionService;
921
771
  this.authEmailService = authEmailService;
922
- this.injectedUserRepository = injectedUserRepository;
923
- this.injectedPermissionRepository = injectedPermissionRepository;
924
- this.injectedCompanyRepository = injectedCompanyRepository;
925
- this.injectedBranchRepository = injectedBranchRepository;
926
772
  this.logger = new Logger(AuthenticationService.name);
927
773
  }
928
774
  }
@@ -940,14 +786,6 @@ AuthenticationService = _ts_decorate([
940
786
  _ts_param(4, Inject(CompanySelectionSessionService)),
941
787
  _ts_param(5, Optional()),
942
788
  _ts_param(5, Inject(AuthEmailService)),
943
- _ts_param(6, Optional()),
944
- _ts_param(6, InjectRepository(User)),
945
- _ts_param(7, Optional()),
946
- _ts_param(7, InjectRepository(UserCompanyPermission)),
947
- _ts_param(8, Optional()),
948
- _ts_param(8, InjectRepository(Company)),
949
- _ts_param(9, Optional()),
950
- _ts_param(9, InjectRepository(CompanyBranch)),
951
789
  _ts_metadata("design:type", Function),
952
790
  _ts_metadata("design:paramtypes", [
953
791
  typeof JwtService === "undefined" ? Object : JwtService,
@@ -955,10 +793,6 @@ AuthenticationService = _ts_decorate([
955
793
  typeof HybridCache === "undefined" ? Object : HybridCache,
956
794
  typeof AuthDataSourceProvider === "undefined" ? Object : AuthDataSourceProvider,
957
795
  typeof CompanySelectionSessionService === "undefined" ? Object : CompanySelectionSessionService,
958
- typeof AuthEmailService === "undefined" ? Object : AuthEmailService,
959
- typeof Repository === "undefined" ? Object : Repository,
960
- typeof Repository === "undefined" ? Object : Repository,
961
- typeof Repository === "undefined" ? Object : Repository,
962
- typeof Repository === "undefined" ? Object : Repository
796
+ typeof AuthEmailService === "undefined" ? Object : AuthEmailService
963
797
  ])
964
798
  ], AuthenticationService);