@flusys/nestjs-auth 3.0.1 → 4.0.0-lts

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 (62) hide show
  1. package/cjs/config/index.js +1 -0
  2. package/cjs/config/message-keys.js +150 -0
  3. package/cjs/controllers/authentication.controller.js +9 -4
  4. package/cjs/controllers/branch.controller.js +1 -0
  5. package/cjs/controllers/company-selection.controller.js +3 -0
  6. package/cjs/controllers/company.controller.js +1 -0
  7. package/cjs/controllers/email-verification.controller.js +7 -2
  8. package/cjs/controllers/user-permission.controller.js +9 -1
  9. package/cjs/controllers/user.controller.js +16 -4
  10. package/cjs/dtos/authentication.dto.js +8 -0
  11. package/cjs/dtos/user-permission.dto.js +14 -0
  12. package/cjs/interceptors/set-token.interceptor.js +14 -5
  13. package/cjs/services/auth-config.service.js +9 -8
  14. package/cjs/services/auth-datasource.provider.js +7 -4
  15. package/cjs/services/auth-email.service.js +155 -45
  16. package/cjs/services/authentication.service.js +274 -60
  17. package/cjs/services/branch.service.js +1 -1
  18. package/cjs/services/company-selection-session.service.js +25 -6
  19. package/cjs/services/company.service.js +1 -1
  20. package/cjs/services/user-permission.service.js +52 -4
  21. package/cjs/services/user.service.js +122 -26
  22. package/cjs/strategies/jwt.strategy.js +18 -4
  23. package/config/index.d.ts +1 -0
  24. package/config/message-keys.d.ts +218 -0
  25. package/controllers/company-selection.controller.d.ts +2 -0
  26. package/controllers/user-permission.controller.d.ts +4 -0
  27. package/controllers/user.controller.d.ts +10 -0
  28. package/dtos/authentication.dto.d.ts +1 -0
  29. package/dtos/user-permission.dto.d.ts +2 -0
  30. package/entities/index.d.ts +10 -1
  31. package/fesm/config/index.js +1 -0
  32. package/fesm/config/message-keys.js +118 -0
  33. package/fesm/controllers/authentication.controller.js +9 -3
  34. package/fesm/controllers/branch.controller.js +1 -0
  35. package/fesm/controllers/company-selection.controller.js +3 -0
  36. package/fesm/controllers/company.controller.js +1 -0
  37. package/fesm/controllers/email-verification.controller.js +7 -2
  38. package/fesm/controllers/user-permission.controller.js +9 -1
  39. package/fesm/controllers/user.controller.js +16 -4
  40. package/fesm/dtos/authentication.dto.js +8 -0
  41. package/fesm/dtos/user-permission.dto.js +14 -0
  42. package/fesm/interceptors/set-token.interceptor.js +14 -4
  43. package/fesm/services/auth-config.service.js +10 -9
  44. package/fesm/services/auth-datasource.provider.js +7 -4
  45. package/fesm/services/auth-email.service.js +156 -45
  46. package/fesm/services/authentication.service.js +276 -61
  47. package/fesm/services/branch.service.js +1 -1
  48. package/fesm/services/company-selection-session.service.js +25 -6
  49. package/fesm/services/company.service.js +1 -1
  50. package/fesm/services/user-permission.service.js +52 -4
  51. package/fesm/services/user.service.js +122 -25
  52. package/fesm/strategies/jwt.strategy.js +18 -4
  53. package/interfaces/auth-module-options.interface.d.ts +2 -2
  54. package/interfaces/authentication.interface.d.ts +1 -0
  55. package/modules/auth.module.d.ts +2 -1
  56. package/package.json +6 -4
  57. package/services/auth-config.service.d.ts +0 -2
  58. package/services/auth-datasource.provider.d.ts +1 -3
  59. package/services/auth-email.service.d.ts +6 -3
  60. package/services/authentication.service.d.ts +1 -1
  61. package/services/branch.service.d.ts +2 -1
  62. package/services/user.service.d.ts +7 -7
@@ -26,16 +26,21 @@ function _ts_param(paramIndex, decorator) {
26
26
  };
27
27
  }
28
28
  import { HybridCache } from '@flusys/nestjs-shared/classes';
29
+ import { SYSTEM_MESSAGES } from '@flusys/nestjs-shared/constants';
30
+ import { LogAction } from '@flusys/nestjs-shared';
31
+ import { AUTH_MESSAGES, EMAIL_VERIFICATION_MESSAGES, USER_MESSAGES } from '../config';
29
32
  import { INotificationAdapter, NOTIFICATION_ADAPTER } from '@flusys/nestjs-shared/interfaces';
30
33
  import { NotificationType } from '@flusys/nestjs-shared/enums';
31
- import { ErrorHandler, generateUniqueSlug } from '@flusys/nestjs-shared/utils';
32
- import { BadRequestException, Inject, Injectable, Logger, NotFoundException, Optional, Scope, UnauthorizedException } from '@nestjs/common';
34
+ import { generateUniqueSlug } from '@flusys/nestjs-shared/utils';
35
+ import { BadRequestException, Inject, Injectable, InternalServerErrorException, NotFoundException, Optional, Scope, UnauthorizedException } from '@nestjs/common';
33
36
  import { JwtService } from '@nestjs/jwt';
34
37
  import * as bcrypt from 'bcrypt';
35
38
  import { BCRYPT_SALT_ROUNDS, TOKEN_REVOKED_PREFIX, USER_ENRICHER } from '../config';
36
39
  import { IUserEnricher } from '../interfaces/user-enricher.interface';
40
+ import { RegistrationDto } from '../dtos/authentication.dto';
37
41
  import { CompanyBranch } from '../entities/company-branch.entity';
38
42
  import { Company } from '../entities/company.entity';
43
+ import { PendingRegistration } from '../entities/pending-registration.entity';
39
44
  import { UserCompanyPermission } from '../entities/user-company-permission.entity';
40
45
  import { User } from '../entities/user.entity';
41
46
  import { PermissionType } from '../enums';
@@ -54,7 +59,10 @@ export class AuthenticationService {
54
59
  }
55
60
  async getUserRepository() {
56
61
  if (!this.dataSourceProvider) {
57
- throw new Error('User repository not available');
62
+ throw new InternalServerErrorException({
63
+ message: 'User repository not available',
64
+ messageKey: SYSTEM_MESSAGES.REPOSITORY_NOT_AVAILABLE
65
+ });
58
66
  }
59
67
  return this.dataSourceProvider.getRepository(User);
60
68
  }
@@ -75,24 +83,29 @@ export class AuthenticationService {
75
83
  return {
76
84
  requiresEmailVerification: true,
77
85
  email,
78
- message: 'Please verify your email address to complete registration.'
86
+ message: 'Please verify your email address to complete registration.',
87
+ messageKey: EMAIL_VERIFICATION_MESSAGES.VERIFICATION_SENT
79
88
  };
80
89
  }
81
90
  const user = await this.validateUser(email, password);
82
91
  if (!user.isActive) {
83
- throw new UnauthorizedException('User account is deactivated');
92
+ throw new UnauthorizedException({
93
+ message: 'User account is deactivated',
94
+ messageKey: AUTH_MESSAGES.LOGIN_ACCOUNT_DEACTIVATED
95
+ });
84
96
  }
85
97
  if (this.isEmailVerificationEnabled() && !user.emailVerified) {
86
98
  return {
87
99
  requiresEmailVerification: true,
88
100
  email: user.email,
89
- message: 'Please verify your email address before logging in.'
101
+ message: 'Please verify your email address before logging in.',
102
+ messageKey: AUTH_MESSAGES.LOGIN_EMAIL_NOT_VERIFIED
90
103
  };
91
104
  }
92
105
  if (!this.isCompanyFeatureEnabled()) {
93
106
  return this.generateLoginResponse(user);
94
107
  }
95
- return this.handleCompanyBasedLogin(user);
108
+ return await this.handleCompanyBasedLogin(user);
96
109
  }
97
110
  async handleCompanyBasedLogin(user) {
98
111
  const permissionRepository = await this.getPermissionRepository();
@@ -144,10 +157,13 @@ export class AuthenticationService {
144
157
  }
145
158
  });
146
159
  if (existingUser && this.isCompanyFeatureEnabled()) {
147
- return this.handleExistingUserCompanyRegistration(existingUser, dto);
160
+ return await this.handleExistingUserCompanyRegistration(existingUser, dto);
148
161
  }
149
162
  if (existingUser) {
150
- throw new BadRequestException('Registration failed due to email exists. Please try again or contact support.');
163
+ throw new BadRequestException({
164
+ message: 'Registration failed due to email exists. Please try again or contact support.',
165
+ messageKey: AUTH_MESSAGES.REGISTER_EMAIL_EXISTS
166
+ });
151
167
  }
152
168
  if (this.isEmailVerificationEnabled() && verifyUrlBase) {
153
169
  const companyData = this.isCompanyFeatureEnabled() ? {
@@ -168,19 +184,26 @@ export class AuthenticationService {
168
184
  });
169
185
  return {
170
186
  requiresEmailVerification: true,
171
- message: result.message
187
+ message: result.message,
188
+ messageKey: EMAIL_VERIFICATION_MESSAGES.VERIFICATION_SENT
172
189
  };
173
190
  }
174
- return this.createUserDirectly(dto);
191
+ return await this.createUserDirectly(dto);
175
192
  }
176
193
  async handleExistingUserCompanyRegistration(existingUser, dto) {
177
194
  if (!dto.companySlug && !dto.newCompanyName) {
178
- throw new BadRequestException('Email already registered. Please login or provide a company to join/create.');
195
+ throw new BadRequestException({
196
+ message: 'Email already registered. Please login or provide a company to join/create.',
197
+ messageKey: AUTH_MESSAGES.REGISTER_EMAIL_EXISTS
198
+ });
179
199
  }
180
200
  const permissionRepository = await this.getPermissionRepository();
181
201
  const companyRepository = await this.getCompanyRepository();
182
202
  if (!permissionRepository || !companyRepository) {
183
- throw new BadRequestException('Company feature repositories not available');
203
+ throw new BadRequestException({
204
+ message: 'Company feature repositories not available',
205
+ messageKey: SYSTEM_MESSAGES.REPOSITORY_NOT_AVAILABLE
206
+ });
184
207
  }
185
208
  if (dto.companySlug) {
186
209
  const company = await companyRepository.findOne({
@@ -198,15 +221,21 @@ export class AuthenticationService {
198
221
  }
199
222
  });
200
223
  if (existingPermission) {
201
- throw new BadRequestException('You are already assigned to this company. Please login.');
224
+ throw new BadRequestException({
225
+ message: 'You are already assigned to this company. Please login.',
226
+ messageKey: AUTH_MESSAGES.REGISTER_COMPANY_ALREADY_ASSIGNED
227
+ });
202
228
  }
203
229
  }
204
230
  }
205
- return this.processCompanyRegistration(existingUser, dto, true);
231
+ return await this.processCompanyRegistration(existingUser, dto, true);
206
232
  }
207
233
  async createUserDirectly(dto) {
208
234
  if (!this.dataSourceProvider) {
209
- throw new BadRequestException('Data source not available');
235
+ throw new BadRequestException({
236
+ message: 'Data source not available',
237
+ messageKey: SYSTEM_MESSAGES.DATASOURCE_NOT_AVAILABLE
238
+ });
210
239
  }
211
240
  const dataSource = await this.dataSourceProvider.getDataSource();
212
241
  const queryRunner = dataSource.createQueryRunner();
@@ -231,21 +260,26 @@ export class AuthenticationService {
231
260
  if (!this.isCompanyFeatureEnabled()) {
232
261
  return this.generateRegistrationResponse(user);
233
262
  }
234
- return this.processCompanyRegistration(user, dto);
263
+ return await this.processCompanyRegistration(user, dto);
235
264
  } catch (error) {
236
265
  await queryRunner.rollbackTransaction();
237
266
  if (error instanceof BadRequestException) {
238
267
  throw error;
239
268
  }
240
- ErrorHandler.logError(this.logger, error, 'createUserDirectly');
241
- throw new BadRequestException('Registration failed. Please try again.');
269
+ throw new BadRequestException({
270
+ message: 'Registration failed. Please try again.',
271
+ messageKey: AUTH_MESSAGES.REGISTER_FAILED
272
+ });
242
273
  } finally{
243
274
  await queryRunner.release();
244
275
  }
245
276
  }
246
277
  async createUserFromPendingRegistration(pending) {
247
278
  if (!this.dataSourceProvider) {
248
- throw new BadRequestException('Data source not available');
279
+ throw new BadRequestException({
280
+ message: 'Data source not available',
281
+ messageKey: SYSTEM_MESSAGES.DATASOURCE_NOT_AVAILABLE
282
+ });
249
283
  }
250
284
  const dataSource = await this.dataSourceProvider.getDataSource();
251
285
  const queryRunner = dataSource.createQueryRunner();
@@ -258,7 +292,10 @@ export class AuthenticationService {
258
292
  }
259
293
  });
260
294
  if (existingUser) {
261
- throw new BadRequestException('This email has already been registered.');
295
+ throw new BadRequestException({
296
+ message: 'This email has already been registered.',
297
+ messageKey: AUTH_MESSAGES.REGISTER_EMAIL_EXISTS
298
+ });
262
299
  }
263
300
  const user = queryRunner.manager.create(User, {
264
301
  name: pending.name,
@@ -275,7 +312,7 @@ export class AuthenticationService {
275
312
  }
276
313
  await queryRunner.commitTransaction();
277
314
  if (this.isCompanyFeatureEnabled() && pending.companyData) {
278
- return this.processCompanyRegistration(user, pending.companyData);
315
+ return await this.processCompanyRegistration(user, pending.companyData);
279
316
  }
280
317
  return this.generateRegistrationResponse(user);
281
318
  } catch (error) {
@@ -283,8 +320,10 @@ export class AuthenticationService {
283
320
  if (error instanceof BadRequestException) {
284
321
  throw error;
285
322
  }
286
- ErrorHandler.logError(this.logger, error, 'createUserFromPendingRegistration');
287
- throw new BadRequestException('Registration failed. Please try again.');
323
+ throw new BadRequestException({
324
+ message: 'Registration failed. Please try again.',
325
+ messageKey: AUTH_MESSAGES.REGISTER_FAILED
326
+ });
288
327
  } finally{
289
328
  await queryRunner.release();
290
329
  }
@@ -294,7 +333,10 @@ export class AuthenticationService {
294
333
  const branchRepository = await this.getBranchRepository();
295
334
  const permissionRepository = await this.getPermissionRepository();
296
335
  if (!companyRepository || !branchRepository || !permissionRepository) {
297
- if (throwOnUnavailable) throw new BadRequestException('Company feature repositories not available');
336
+ if (throwOnUnavailable) throw new BadRequestException({
337
+ message: 'Company feature repositories not available',
338
+ messageKey: SYSTEM_MESSAGES.REPOSITORY_NOT_AVAILABLE
339
+ });
298
340
  return this.generateRegistrationResponse(user);
299
341
  }
300
342
  const { company, branch } = await this.findOrCreateCompanyAndBranch(data, companyRepository, branchRepository);
@@ -312,7 +354,10 @@ export class AuthenticationService {
312
354
  isActive: true
313
355
  }
314
356
  });
315
- if (!company) throw new BadRequestException('Company not found or inactive');
357
+ if (!company) throw new BadRequestException({
358
+ message: 'Company not found or inactive',
359
+ messageKey: AUTH_MESSAGES.COMPANY_NOT_FOUND
360
+ });
316
361
  const branch = data.branchSlug ? await branchRepo.findOne({
317
362
  where: {
318
363
  slug: data.branchSlug,
@@ -329,7 +374,10 @@ export class AuthenticationService {
329
374
  createdAt: 'ASC'
330
375
  }
331
376
  });
332
- if (data.branchSlug && !branch) throw new BadRequestException('Branch not found or inactive');
377
+ if (data.branchSlug && !branch) throw new BadRequestException({
378
+ message: 'Branch not found or inactive',
379
+ messageKey: AUTH_MESSAGES.BRANCH_NOT_FOUND
380
+ });
333
381
  return {
334
382
  company,
335
383
  branch
@@ -385,17 +433,23 @@ export class AuthenticationService {
385
433
  async select(sessionId, companyId, branchId) {
386
434
  this.ensureCompanyFeatureEnabled();
387
435
  if (!this.sessionService) {
388
- throw new BadRequestException('Session service not available');
436
+ throw new BadRequestException({
437
+ message: 'Session service not available',
438
+ messageKey: AUTH_MESSAGES.SESSION_NOT_AVAILABLE
439
+ });
389
440
  }
390
441
  const session = await this.sessionService.consumeSession(sessionId);
391
442
  if (!session) {
392
- throw new UnauthorizedException('Invalid or expired session');
443
+ throw new UnauthorizedException({
444
+ message: 'Invalid or expired session',
445
+ messageKey: AUTH_MESSAGES.SESSION_INVALID
446
+ });
393
447
  }
394
- return this.validateAndLoginWithCompany(session.userId, companyId, branchId);
448
+ return await this.validateAndLoginWithCompany(session.userId, companyId, branchId);
395
449
  }
396
450
  async switchCompany(userId, companyId, branchId) {
397
451
  this.ensureCompanyFeatureEnabled();
398
- return this.validateAndLoginWithCompany(userId, companyId, branchId);
452
+ return await this.validateAndLoginWithCompany(userId, companyId, branchId);
399
453
  }
400
454
  async validateAndLoginWithCompany(userId, companyId, branchId) {
401
455
  const userRepository = await this.getUserRepository();
@@ -405,13 +459,19 @@ export class AuthenticationService {
405
459
  }
406
460
  });
407
461
  if (!user) {
408
- throw new NotFoundException('User not found');
462
+ throw new NotFoundException({
463
+ message: 'User not found',
464
+ messageKey: USER_MESSAGES.NOT_FOUND
465
+ });
409
466
  }
410
467
  const permissionRepository = await this.getPermissionRepository();
411
468
  const companyRepository = await this.getCompanyRepository();
412
469
  const branchRepository = await this.getBranchRepository();
413
470
  if (!permissionRepository || !companyRepository || !branchRepository) {
414
- throw new BadRequestException('Repositories not available');
471
+ throw new BadRequestException({
472
+ message: 'Repositories not available',
473
+ messageKey: SYSTEM_MESSAGES.REPOSITORY_NOT_AVAILABLE
474
+ });
415
475
  }
416
476
  const hasCompanyAccess = await permissionRepository.findOne({
417
477
  where: {
@@ -421,7 +481,10 @@ export class AuthenticationService {
421
481
  }
422
482
  });
423
483
  if (!hasCompanyAccess) {
424
- throw new UnauthorizedException('No access to this company');
484
+ throw new UnauthorizedException({
485
+ message: 'No access to this company',
486
+ messageKey: AUTH_MESSAGES.COMPANY_NO_ACCESS
487
+ });
425
488
  }
426
489
  const company = await companyRepository.findOne({
427
490
  where: {
@@ -430,7 +493,10 @@ export class AuthenticationService {
430
493
  }
431
494
  });
432
495
  if (!company) {
433
- throw new UnauthorizedException('Company not found or inactive');
496
+ throw new UnauthorizedException({
497
+ message: 'Company not found or inactive',
498
+ messageKey: AUTH_MESSAGES.COMPANY_NOT_FOUND
499
+ });
434
500
  }
435
501
  const hasBranchAccess = await permissionRepository.findOne({
436
502
  where: {
@@ -440,7 +506,10 @@ export class AuthenticationService {
440
506
  }
441
507
  });
442
508
  if (!hasBranchAccess) {
443
- throw new UnauthorizedException('No access to this branch');
509
+ throw new UnauthorizedException({
510
+ message: 'No access to this branch',
511
+ messageKey: AUTH_MESSAGES.BRANCH_NO_ACCESS
512
+ });
444
513
  }
445
514
  const branch = await branchRepository.findOne({
446
515
  where: {
@@ -450,7 +519,10 @@ export class AuthenticationService {
450
519
  }
451
520
  });
452
521
  if (!branch) {
453
- throw new UnauthorizedException('Branch not found or inactive');
522
+ throw new UnauthorizedException({
523
+ message: 'Branch not found or inactive',
524
+ messageKey: AUTH_MESSAGES.BRANCH_NOT_FOUND
525
+ });
454
526
  }
455
527
  return this.generateLoginResponseWithCompany(user, company, branch);
456
528
  }
@@ -460,7 +532,10 @@ export class AuthenticationService {
460
532
  secret: this.authConfig.getRefreshTokenSecret()
461
533
  });
462
534
  if (await this.isTokenRevoked(payload.id, payload.iat)) {
463
- throw new UnauthorizedException('Token has been revoked');
535
+ throw new UnauthorizedException({
536
+ message: 'Token has been revoked',
537
+ messageKey: AUTH_MESSAGES.TOKEN_REVOKED
538
+ });
464
539
  }
465
540
  const userRepository = await this.getUserRepository();
466
541
  const user = await userRepository.findOne({
@@ -469,7 +544,10 @@ export class AuthenticationService {
469
544
  }
470
545
  });
471
546
  if (!user || !user.isActive) {
472
- throw new UnauthorizedException('Invalid refresh token');
547
+ throw new UnauthorizedException({
548
+ message: 'Invalid refresh token',
549
+ messageKey: AUTH_MESSAGES.TOKEN_INVALID
550
+ });
473
551
  }
474
552
  return this.generateTokens({
475
553
  id: user.id,
@@ -483,9 +561,11 @@ export class AuthenticationService {
483
561
  branchId: payload.branchId
484
562
  }
485
563
  });
486
- } catch (error) {
487
- ErrorHandler.logError(this.logger, error, 'refreshToken');
488
- throw new UnauthorizedException('Invalid or expired refresh token');
564
+ } catch {
565
+ throw new UnauthorizedException({
566
+ message: 'Invalid or expired refresh token',
567
+ messageKey: AUTH_MESSAGES.TOKEN_EXPIRED
568
+ });
489
569
  }
490
570
  }
491
571
  async changePassword(userId, currentPassword, newPassword) {
@@ -495,24 +575,31 @@ export class AuthenticationService {
495
575
  id: userId
496
576
  }
497
577
  });
498
- if (!user) throw new UnauthorizedException('User not found');
578
+ if (!user) throw new UnauthorizedException({
579
+ message: 'User not found',
580
+ messageKey: USER_MESSAGES.NOT_FOUND
581
+ });
499
582
  if (!await bcrypt.compare(currentPassword, user.password || '')) {
500
- throw new UnauthorizedException('Current password is incorrect');
583
+ throw new UnauthorizedException({
584
+ message: 'Current password is incorrect',
585
+ messageKey: AUTH_MESSAGES.PASSWORD_CHANGE_INVALID_CURRENT
586
+ });
501
587
  }
502
588
  user.password = await bcrypt.hash(newPassword, BCRYPT_SALT_ROUNDS);
503
589
  await userRepository.save(user);
504
590
  }
505
591
  async logout(userId) {
506
592
  if (!this.cacheManager) {
507
- 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.');
508
- throw new BadRequestException('Logout service temporarily unavailable. Please try again later.');
593
+ throw new BadRequestException({
594
+ message: 'Logout service temporarily unavailable. Please try again later.',
595
+ messageKey: AUTH_MESSAGES.LOGOUT_SERVICE_UNAVAILABLE
596
+ });
509
597
  }
510
598
  const revokedAt = Math.floor(Date.now() / 1000);
511
599
  const cacheKey = `${TOKEN_REVOKED_PREFIX}:${userId}`;
512
600
  const refreshTokenExpiry = this.authConfig.getRefreshTokenExpiration();
513
601
  const ttlMs = this.parseExpiryToMs(refreshTokenExpiry);
514
602
  await this.cacheManager.set(cacheKey, revokedAt, ttlMs);
515
- this.logger.log(`User ${userId} logged out - all tokens revoked`);
516
603
  }
517
604
  async isTokenRevoked(userId, tokenIssuedAt) {
518
605
  if (!this.cacheManager || !tokenIssuedAt) {
@@ -548,7 +635,10 @@ export class AuthenticationService {
548
635
  const permissionRepository = await this.getPermissionRepository();
549
636
  const companyRepository = await this.getCompanyRepository();
550
637
  if (!permissionRepository || !companyRepository) {
551
- throw new BadRequestException('Repositories not available');
638
+ throw new BadRequestException({
639
+ message: 'Repositories not available',
640
+ messageKey: SYSTEM_MESSAGES.REPOSITORY_NOT_AVAILABLE
641
+ });
552
642
  }
553
643
  const permissions = await permissionRepository.find({
554
644
  where: {
@@ -569,7 +659,10 @@ export class AuthenticationService {
569
659
  const permissionRepository = await this.getPermissionRepository();
570
660
  const branchRepository = await this.getBranchRepository();
571
661
  if (!permissionRepository || !branchRepository) {
572
- throw new BadRequestException('Repositories not available');
662
+ throw new BadRequestException({
663
+ message: 'Repositories not available',
664
+ messageKey: SYSTEM_MESSAGES.REPOSITORY_NOT_AVAILABLE
665
+ });
573
666
  }
574
667
  const companyPermission = await permissionRepository.findOne({
575
668
  where: {
@@ -579,7 +672,10 @@ export class AuthenticationService {
579
672
  }
580
673
  });
581
674
  if (!companyPermission) {
582
- throw new UnauthorizedException('No access to this company');
675
+ throw new UnauthorizedException({
676
+ message: 'No access to this company',
677
+ messageKey: AUTH_MESSAGES.COMPANY_NO_ACCESS
678
+ });
583
679
  }
584
680
  const branchPermissions = await permissionRepository.find({
585
681
  where: {
@@ -626,20 +722,32 @@ export class AuthenticationService {
626
722
  id: userId
627
723
  }
628
724
  });
629
- if (!user) throw new UnauthorizedException('User not found');
725
+ if (!user) throw new UnauthorizedException({
726
+ message: 'User not found',
727
+ messageKey: USER_MESSAGES.NOT_FOUND
728
+ });
630
729
  const response = {
631
730
  user: this.toUserInfo(user)
632
731
  };
633
732
  if (this.isCompanyFeatureEnabled()) {
634
733
  if (!companyId) {
635
- throw new UnauthorizedException('Company feature is enabled but user has no company assigned.');
734
+ throw new UnauthorizedException({
735
+ message: 'Company feature is enabled but user has no company assigned.',
736
+ messageKey: AUTH_MESSAGES.COMPANY_REQUIRED
737
+ });
636
738
  }
637
739
  const company = await this.getCompanyById(companyId);
638
- if (!company) throw new UnauthorizedException('Company not found.');
740
+ if (!company) throw new UnauthorizedException({
741
+ message: 'Company not found.',
742
+ messageKey: AUTH_MESSAGES.COMPANY_NOT_FOUND
743
+ });
639
744
  response.company = this.toCompanyInfo(company);
640
745
  if (branchId) {
641
746
  const branch = await this.getBranchById(branchId);
642
- if (!branch) throw new UnauthorizedException('Branch not found.');
747
+ if (!branch) throw new UnauthorizedException({
748
+ message: 'Branch not found.',
749
+ messageKey: AUTH_MESSAGES.BRANCH_NOT_FOUND
750
+ });
643
751
  response.branch = this.toBranchInfo(branch);
644
752
  }
645
753
  }
@@ -647,7 +755,10 @@ export class AuthenticationService {
647
755
  }
648
756
  ensureCompanyFeatureEnabled() {
649
757
  if (!this.isCompanyFeatureEnabled()) {
650
- throw new BadRequestException('Company feature is not enabled');
758
+ throw new BadRequestException({
759
+ message: 'Company feature is not enabled',
760
+ messageKey: AUTH_MESSAGES.COMPANY_FEATURE_NOT_ENABLED
761
+ });
651
762
  }
652
763
  }
653
764
  async validateUser(email, password) {
@@ -658,7 +769,10 @@ export class AuthenticationService {
658
769
  }
659
770
  });
660
771
  if (!user || !await bcrypt.compare(password, user.password || '')) {
661
- throw new UnauthorizedException('Invalid credentials');
772
+ throw new UnauthorizedException({
773
+ message: 'Invalid credentials',
774
+ messageKey: AUTH_MESSAGES.LOGIN_INVALID_CREDENTIALS
775
+ });
662
776
  }
663
777
  user.lastLoginAt = new Date();
664
778
  await userRepository.save(user);
@@ -747,13 +861,16 @@ export class AuthenticationService {
747
861
  message: 'You have successfully logged in to your account.',
748
862
  type: NotificationType.INFO,
749
863
  companyId
750
- }).catch((error)=>{
751
- this.logger.warn(`Failed to send login notification: ${error.message}`);
864
+ }).catch(()=>{
865
+ // Silent failure - notification is non-critical
752
866
  });
753
867
  }
754
868
  async generateCompanySelectionResponse(user, companies, branches) {
755
869
  if (!this.sessionService) {
756
- throw new BadRequestException('Session service not available');
870
+ throw new BadRequestException({
871
+ message: 'Session service not available',
872
+ messageKey: AUTH_MESSAGES.SESSION_NOT_AVAILABLE
873
+ });
757
874
  }
758
875
  const sessionId = await this.sessionService.createSession(user.id);
759
876
  const companiesWithBranches = companies.map((company)=>({
@@ -794,7 +911,6 @@ export class AuthenticationService {
794
911
  _define_property(this, "authEmailService", void 0);
795
912
  _define_property(this, "userEnricher", void 0);
796
913
  _define_property(this, "notificationAdapter", void 0);
797
- _define_property(this, "logger", void 0);
798
914
  this.jwtService = jwtService;
799
915
  this.authConfig = authConfig;
800
916
  this.cacheManager = cacheManager;
@@ -803,9 +919,108 @@ export class AuthenticationService {
803
919
  this.authEmailService = authEmailService;
804
920
  this.userEnricher = userEnricher;
805
921
  this.notificationAdapter = notificationAdapter;
806
- this.logger = new Logger(AuthenticationService.name);
807
922
  }
808
923
  }
924
+ _ts_decorate([
925
+ LogAction({
926
+ action: 'auth.login',
927
+ module: 'auth',
928
+ includeParams: false
929
+ }),
930
+ _ts_metadata("design:type", Function),
931
+ _ts_metadata("design:paramtypes", [
932
+ String,
933
+ String
934
+ ]),
935
+ _ts_metadata("design:returntype", Promise)
936
+ ], AuthenticationService.prototype, "login", null);
937
+ _ts_decorate([
938
+ LogAction({
939
+ action: 'auth.register',
940
+ module: 'auth',
941
+ includeParams: false
942
+ }),
943
+ _ts_metadata("design:type", Function),
944
+ _ts_metadata("design:paramtypes", [
945
+ typeof RegistrationDto === "undefined" ? Object : RegistrationDto,
946
+ String
947
+ ]),
948
+ _ts_metadata("design:returntype", Promise)
949
+ ], AuthenticationService.prototype, "register", null);
950
+ _ts_decorate([
951
+ LogAction({
952
+ action: 'auth.createUser',
953
+ module: 'auth',
954
+ includeParams: false
955
+ }),
956
+ _ts_metadata("design:type", Function),
957
+ _ts_metadata("design:paramtypes", [
958
+ typeof RegistrationDto === "undefined" ? Object : RegistrationDto
959
+ ]),
960
+ _ts_metadata("design:returntype", Promise)
961
+ ], AuthenticationService.prototype, "createUserDirectly", null);
962
+ _ts_decorate([
963
+ LogAction({
964
+ action: 'auth.createUserFromPending',
965
+ module: 'auth',
966
+ includeParams: false
967
+ }),
968
+ _ts_metadata("design:type", Function),
969
+ _ts_metadata("design:paramtypes", [
970
+ typeof PendingRegistration === "undefined" ? Object : PendingRegistration
971
+ ]),
972
+ _ts_metadata("design:returntype", Promise)
973
+ ], AuthenticationService.prototype, "createUserFromPendingRegistration", null);
974
+ _ts_decorate([
975
+ LogAction({
976
+ action: 'auth.companySwitch',
977
+ module: 'auth'
978
+ }),
979
+ _ts_metadata("design:type", Function),
980
+ _ts_metadata("design:paramtypes", [
981
+ String,
982
+ String,
983
+ String
984
+ ]),
985
+ _ts_metadata("design:returntype", Promise)
986
+ ], AuthenticationService.prototype, "validateAndLoginWithCompany", null);
987
+ _ts_decorate([
988
+ LogAction({
989
+ action: 'auth.refreshToken',
990
+ module: 'auth',
991
+ includeParams: false
992
+ }),
993
+ _ts_metadata("design:type", Function),
994
+ _ts_metadata("design:paramtypes", [
995
+ String
996
+ ]),
997
+ _ts_metadata("design:returntype", Promise)
998
+ ], AuthenticationService.prototype, "refreshToken", null);
999
+ _ts_decorate([
1000
+ LogAction({
1001
+ action: 'auth.changePassword',
1002
+ module: 'auth',
1003
+ includeParams: false
1004
+ }),
1005
+ _ts_metadata("design:type", Function),
1006
+ _ts_metadata("design:paramtypes", [
1007
+ String,
1008
+ String,
1009
+ String
1010
+ ]),
1011
+ _ts_metadata("design:returntype", Promise)
1012
+ ], AuthenticationService.prototype, "changePassword", null);
1013
+ _ts_decorate([
1014
+ LogAction({
1015
+ action: 'auth.logout',
1016
+ module: 'auth'
1017
+ }),
1018
+ _ts_metadata("design:type", Function),
1019
+ _ts_metadata("design:paramtypes", [
1020
+ String
1021
+ ]),
1022
+ _ts_metadata("design:returntype", Promise)
1023
+ ], AuthenticationService.prototype, "logout", null);
809
1024
  AuthenticationService = _ts_decorate([
810
1025
  Injectable({
811
1026
  scope: Scope.REQUEST
@@ -79,7 +79,7 @@ export class BranchService extends RequestScopedApiService {
79
79
  return result;
80
80
  }
81
81
  constructor(cacheManager, utilsService, dataSourceProvider, authConfig){
82
- super('company_branch', null, cacheManager, utilsService, BranchService.name, true), _define_property(this, "cacheManager", void 0), _define_property(this, "utilsService", void 0), _define_property(this, "dataSourceProvider", void 0), _define_property(this, "authConfig", void 0), this.cacheManager = cacheManager, this.utilsService = utilsService, this.dataSourceProvider = dataSourceProvider, this.authConfig = authConfig;
82
+ super('company_branch', null, cacheManager, utilsService, BranchService.name, true, 'auth'), _define_property(this, "cacheManager", void 0), _define_property(this, "utilsService", void 0), _define_property(this, "dataSourceProvider", void 0), _define_property(this, "authConfig", void 0), this.cacheManager = cacheManager, this.utilsService = utilsService, this.dataSourceProvider = dataSourceProvider, this.authConfig = authConfig;
83
83
  }
84
84
  }
85
85
  BranchService = _ts_decorate([