@flusys/nestjs-auth 3.0.0 → 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 (63) hide show
  1. package/README.md +1 -1
  2. package/cjs/config/index.js +1 -0
  3. package/cjs/config/message-keys.js +150 -0
  4. package/cjs/controllers/authentication.controller.js +9 -4
  5. package/cjs/controllers/branch.controller.js +1 -0
  6. package/cjs/controllers/company-selection.controller.js +3 -0
  7. package/cjs/controllers/company.controller.js +1 -0
  8. package/cjs/controllers/email-verification.controller.js +7 -2
  9. package/cjs/controllers/user-permission.controller.js +9 -1
  10. package/cjs/controllers/user.controller.js +16 -4
  11. package/cjs/dtos/authentication.dto.js +8 -0
  12. package/cjs/dtos/user-permission.dto.js +14 -0
  13. package/cjs/interceptors/set-token.interceptor.js +14 -5
  14. package/cjs/services/auth-config.service.js +9 -8
  15. package/cjs/services/auth-datasource.provider.js +7 -4
  16. package/cjs/services/auth-email.service.js +155 -45
  17. package/cjs/services/authentication.service.js +306 -71
  18. package/cjs/services/branch.service.js +1 -1
  19. package/cjs/services/company-selection-session.service.js +25 -6
  20. package/cjs/services/company.service.js +1 -1
  21. package/cjs/services/user-permission.service.js +52 -4
  22. package/cjs/services/user.service.js +122 -26
  23. package/cjs/strategies/jwt.strategy.js +18 -4
  24. package/config/index.d.ts +1 -0
  25. package/config/message-keys.d.ts +218 -0
  26. package/controllers/company-selection.controller.d.ts +2 -0
  27. package/controllers/user-permission.controller.d.ts +4 -0
  28. package/controllers/user.controller.d.ts +10 -0
  29. package/dtos/authentication.dto.d.ts +1 -0
  30. package/dtos/user-permission.dto.d.ts +2 -0
  31. package/entities/index.d.ts +10 -1
  32. package/fesm/config/index.js +1 -0
  33. package/fesm/config/message-keys.js +118 -0
  34. package/fesm/controllers/authentication.controller.js +9 -3
  35. package/fesm/controllers/branch.controller.js +1 -0
  36. package/fesm/controllers/company-selection.controller.js +3 -0
  37. package/fesm/controllers/company.controller.js +1 -0
  38. package/fesm/controllers/email-verification.controller.js +7 -2
  39. package/fesm/controllers/user-permission.controller.js +9 -1
  40. package/fesm/controllers/user.controller.js +16 -4
  41. package/fesm/dtos/authentication.dto.js +8 -0
  42. package/fesm/dtos/user-permission.dto.js +14 -0
  43. package/fesm/interceptors/set-token.interceptor.js +14 -4
  44. package/fesm/services/auth-config.service.js +10 -9
  45. package/fesm/services/auth-datasource.provider.js +7 -4
  46. package/fesm/services/auth-email.service.js +156 -45
  47. package/fesm/services/authentication.service.js +297 -61
  48. package/fesm/services/branch.service.js +1 -1
  49. package/fesm/services/company-selection-session.service.js +25 -6
  50. package/fesm/services/company.service.js +1 -1
  51. package/fesm/services/user-permission.service.js +52 -4
  52. package/fesm/services/user.service.js +122 -25
  53. package/fesm/strategies/jwt.strategy.js +18 -4
  54. package/interfaces/auth-module-options.interface.d.ts +2 -2
  55. package/interfaces/authentication.interface.d.ts +1 -0
  56. package/modules/auth.module.d.ts +2 -1
  57. package/package.json +6 -4
  58. package/services/auth-config.service.d.ts +0 -2
  59. package/services/auth-datasource.provider.d.ts +1 -3
  60. package/services/auth-email.service.d.ts +6 -3
  61. package/services/authentication.service.d.ts +5 -2
  62. package/services/branch.service.d.ts +2 -1
  63. package/services/user.service.d.ts +7 -7
@@ -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([
@@ -25,15 +25,14 @@ function _ts_param(paramIndex, decorator) {
25
25
  decorator(target, key, paramIndex);
26
26
  };
27
27
  }
28
+ import { LogAction } from '@flusys/nestjs-shared';
28
29
  import { HybridCache } from '@flusys/nestjs-shared/classes';
29
30
  import { Inject, Injectable } from '@nestjs/common';
30
31
  import { randomUUID } from 'crypto';
31
32
  import { SESSION_CACHE_PREFIX } from '../config/auth.constants';
32
33
  const SESSION_TTL_MS = 5 * 60 * 1000; // 5 minutes
33
34
  export class CompanySelectionSessionService {
34
- /**
35
- * Create a new session for company/branch selection
36
- */ async createSession(userId) {
35
+ async createSession(userId) {
37
36
  const sessionId = randomUUID();
38
37
  const now = new Date();
39
38
  const expiresAt = new Date(now.getTime() + SESSION_TTL_MS);
@@ -58,9 +57,7 @@ export class CompanySelectionSessionService {
58
57
  }
59
58
  return session;
60
59
  }
61
- /**
62
- * Get and delete session (one-time use)
63
- */ async consumeSession(sessionId) {
60
+ async consumeSession(sessionId) {
64
61
  const session = await this.getSession(sessionId);
65
62
  if (session) {
66
63
  await this.deleteSession(sessionId);
@@ -82,6 +79,28 @@ export class CompanySelectionSessionService {
82
79
  this.cacheManager = cacheManager;
83
80
  }
84
81
  }
82
+ _ts_decorate([
83
+ LogAction({
84
+ action: 'session.create',
85
+ module: 'auth'
86
+ }),
87
+ _ts_metadata("design:type", Function),
88
+ _ts_metadata("design:paramtypes", [
89
+ String
90
+ ]),
91
+ _ts_metadata("design:returntype", Promise)
92
+ ], CompanySelectionSessionService.prototype, "createSession", null);
93
+ _ts_decorate([
94
+ LogAction({
95
+ action: 'session.consume',
96
+ module: 'auth'
97
+ }),
98
+ _ts_metadata("design:type", Function),
99
+ _ts_metadata("design:paramtypes", [
100
+ String
101
+ ]),
102
+ _ts_metadata("design:returntype", Promise)
103
+ ], CompanySelectionSessionService.prototype, "consumeSession", null);
85
104
  CompanySelectionSessionService = _ts_decorate([
86
105
  Injectable(),
87
106
  _ts_param(0, Inject('CACHE_INSTANCE')),
@@ -64,7 +64,7 @@ export class CompanyService extends RequestScopedApiService {
64
64
  };
65
65
  }
66
66
  constructor(cacheManager, utilsService, dataSourceProvider){
67
- super('company', null, cacheManager, utilsService, CompanyService.name, true), _define_property(this, "cacheManager", void 0), _define_property(this, "utilsService", void 0), _define_property(this, "dataSourceProvider", void 0), this.cacheManager = cacheManager, this.utilsService = utilsService, this.dataSourceProvider = dataSourceProvider;
67
+ super('company', null, cacheManager, utilsService, CompanyService.name, true, 'auth'), _define_property(this, "cacheManager", void 0), _define_property(this, "utilsService", void 0), _define_property(this, "dataSourceProvider", void 0), this.cacheManager = cacheManager, this.utilsService = utilsService, this.dataSourceProvider = dataSourceProvider;
68
68
  }
69
69
  }
70
70
  CompanyService = _ts_decorate([
@@ -25,7 +25,9 @@ function _ts_param(paramIndex, decorator) {
25
25
  decorator(target, key, paramIndex);
26
26
  };
27
27
  }
28
+ import { LogAction } from '@flusys/nestjs-shared';
28
29
  import { ConflictException, Inject, Injectable, NotFoundException, Scope } from '@nestjs/common';
30
+ import { USER_PERMISSION_MESSAGES } from '../config';
29
31
  import { PermissionType, UserCompanyPermission } from '../entities/user-company-permission.entity';
30
32
  import { AuthDataSourceProvider } from './auth-datasource.provider';
31
33
  export class UserPermissionService {
@@ -62,7 +64,13 @@ export class UserPermissionService {
62
64
  }
63
65
  });
64
66
  if (existing) {
65
- throw new ConflictException(`User already assigned to this ${typeName}`);
67
+ throw new ConflictException({
68
+ message: `User already assigned to this ${typeName}`,
69
+ messageKey: USER_PERMISSION_MESSAGES.ALREADY_ASSIGNED,
70
+ messageParams: {
71
+ type: typeName
72
+ }
73
+ });
66
74
  }
67
75
  try {
68
76
  await repository.save(repository.create({
@@ -72,8 +80,15 @@ export class UserPermissionService {
72
80
  metadata
73
81
  }));
74
82
  } catch (error) {
75
- if (error?.code === 'ER_DUP_ENTRY' || error?.message?.includes('Duplicate entry')) {
76
- throw new ConflictException(`User already assigned to this ${typeName}. Please refresh and try again.`);
83
+ const err = error;
84
+ if (err?.code === 'ER_DUP_ENTRY' || String(err?.message).includes('Duplicate entry')) {
85
+ throw new ConflictException({
86
+ message: `User already assigned to this ${typeName}. Please refresh and try again.`,
87
+ messageKey: USER_PERMISSION_MESSAGES.ALREADY_ASSIGNED,
88
+ messageParams: {
89
+ type: typeName
90
+ }
91
+ });
77
92
  }
78
93
  throw error;
79
94
  }
@@ -89,7 +104,13 @@ export class UserPermissionService {
89
104
  }
90
105
  });
91
106
  if (!permission) {
92
- throw new NotFoundException(`${typeName.charAt(0).toUpperCase() + typeName.slice(1)} permission not found`);
107
+ throw new NotFoundException({
108
+ message: `${typeName.charAt(0).toUpperCase() + typeName.slice(1)} permission not found`,
109
+ messageKey: USER_PERMISSION_MESSAGES.PERMISSION_NOT_FOUND,
110
+ messageParams: {
111
+ type: typeName.charAt(0).toUpperCase() + typeName.slice(1)
112
+ }
113
+ });
93
114
  }
94
115
  await repository.remove(permission);
95
116
  }
@@ -117,6 +138,33 @@ export class UserPermissionService {
117
138
  this.findUserCompanies = (userId)=>this.findUserPermissions(userId, PermissionType.COMPANY);
118
139
  }
119
140
  }
141
+ _ts_decorate([
142
+ LogAction({
143
+ action: 'user.assignPermission',
144
+ module: 'auth'
145
+ }),
146
+ _ts_metadata("design:type", Function),
147
+ _ts_metadata("design:paramtypes", [
148
+ String,
149
+ String,
150
+ typeof PermissionType === "undefined" ? Object : PermissionType,
151
+ typeof Record === "undefined" ? Object : Record
152
+ ]),
153
+ _ts_metadata("design:returntype", Promise)
154
+ ], UserPermissionService.prototype, "assignPermission", null);
155
+ _ts_decorate([
156
+ LogAction({
157
+ action: 'user.revokePermission',
158
+ module: 'auth'
159
+ }),
160
+ _ts_metadata("design:type", Function),
161
+ _ts_metadata("design:paramtypes", [
162
+ String,
163
+ String,
164
+ typeof PermissionType === "undefined" ? Object : PermissionType
165
+ ]),
166
+ _ts_metadata("design:returntype", Promise)
167
+ ], UserPermissionService.prototype, "revokePermission", null);
120
168
  UserPermissionService = _ts_decorate([
121
169
  Injectable({
122
170
  scope: Scope.REQUEST
@@ -26,13 +26,17 @@ function _ts_param(paramIndex, decorator) {
26
26
  };
27
27
  }
28
28
  import { RequestScopedApiService, HybridCache } from '@flusys/nestjs-shared/classes';
29
+ import { LogAction } from '@flusys/nestjs-shared';
30
+ import { ILoggedUserInfo } from '@flusys/nestjs-shared/interfaces';
29
31
  import { UtilsService } from '@flusys/nestjs-shared/modules';
30
- import { ErrorHandler } from '@flusys/nestjs-shared/utils';
31
32
  import { BadRequestException, ForbiddenException, Inject, Injectable, NotFoundException, Optional, Scope } from '@nestjs/common';
33
+ import { SYSTEM_MESSAGES } from '@flusys/nestjs-shared/constants';
34
+ import { AUTH_MESSAGES, USER_MESSAGES, USER_PERMISSION_MESSAGES } from '../config';
32
35
  import * as bcrypt from 'bcrypt';
33
36
  import { AuthConfigService } from './auth-config.service';
34
37
  import { AuthDataSourceProvider } from './auth-datasource.provider';
35
38
  import { BCRYPT_SALT_ROUNDS, USER_ENRICHER } from '../config';
39
+ import { CreateUserDto } from '../dtos/user.dto';
36
40
  import { PermissionType } from '../enums';
37
41
  import { IUserEnricher } from '../interfaces/user-enricher.interface';
38
42
  import { UserCompanyPermission } from '../entities/user-company-permission.entity';
@@ -58,7 +62,10 @@ export class UserService extends RequestScopedApiService {
58
62
  }
59
63
  async getUserForProfile(userId, user) {
60
64
  if (userId !== user.id) {
61
- throw new ForbiddenException('Cannot access another user\'s profile');
65
+ throw new ForbiddenException({
66
+ message: 'Cannot access another user\'s profile',
67
+ messageKey: AUTH_MESSAGES.PROFILE_ACCESS_DENIED
68
+ });
62
69
  }
63
70
  await this.ensureRepositoryInitialized();
64
71
  const userEntity = await this.repository.findOne({
@@ -67,7 +74,10 @@ export class UserService extends RequestScopedApiService {
67
74
  }
68
75
  });
69
76
  if (!userEntity) {
70
- throw new NotFoundException('User not found');
77
+ throw new NotFoundException({
78
+ message: 'User not found',
79
+ messageKey: USER_MESSAGES.NOT_FOUND
80
+ });
71
81
  }
72
82
  return userEntity;
73
83
  }
@@ -105,7 +115,10 @@ export class UserService extends RequestScopedApiService {
105
115
  }
106
116
  });
107
117
  if (!permission) {
108
- throw new NotFoundException('User company permission not found');
118
+ throw new NotFoundException({
119
+ message: 'User company permission not found',
120
+ messageKey: USER_PERMISSION_MESSAGES.PERMISSION_NOT_FOUND
121
+ });
109
122
  }
110
123
  permission.isActive = isActive;
111
124
  await this.permissionRepository.save(permission);
@@ -235,7 +248,7 @@ export class UserService extends RequestScopedApiService {
235
248
  async insert(dto, user) {
236
249
  const isCompanyFeatureEnabled = this.authConfig.isCompanyFeatureEnabled();
237
250
  if (!isCompanyFeatureEnabled || !this.dataSource || !user?.companyId || !this.permissionRepository) {
238
- return super.insert(dto, user);
251
+ return await super.insert(dto, user);
239
252
  }
240
253
  const queryRunner = this.dataSource.createQueryRunner();
241
254
  await queryRunner.connect();
@@ -284,10 +297,7 @@ export class UserService extends RequestScopedApiService {
284
297
  return this.convertEntityToResponseDto(savedUser, false);
285
298
  } catch (error) {
286
299
  await queryRunner.rollbackTransaction();
287
- ErrorHandler.logError(this.logger, error, 'insert', {
288
- entity: this.entityName
289
- });
290
- ErrorHandler.rethrowError(error);
300
+ throw error;
291
301
  } finally{
292
302
  await queryRunner.release();
293
303
  }
@@ -334,10 +344,16 @@ export class UserService extends RequestScopedApiService {
334
344
  async updateProfileSection(userId, sectionId, data, user) {
335
345
  const userEntity = await this.getUserForProfile(userId, user);
336
346
  if (!this.dataSource) {
337
- throw new BadRequestException('DataSource not available');
347
+ throw new BadRequestException({
348
+ message: 'DataSource not available',
349
+ messageKey: SYSTEM_MESSAGES.DATASOURCE_NOT_AVAILABLE
350
+ });
338
351
  }
339
352
  if (!this.userEnricher?.updateProfileSection) {
340
- throw new BadRequestException('Profile sections not supported');
353
+ throw new BadRequestException({
354
+ message: 'Profile sections not supported',
355
+ messageKey: AUTH_MESSAGES.PROFILE_SECTIONS_NOT_SUPPORTED
356
+ });
341
357
  }
342
358
  const queryRunner = this.dataSource.createQueryRunner();
343
359
  await queryRunner.connect();
@@ -350,11 +366,7 @@ export class UserService extends RequestScopedApiService {
350
366
  ]);
351
367
  } catch (error) {
352
368
  await queryRunner.rollbackTransaction();
353
- ErrorHandler.logError(this.logger, error, 'updateProfileSection', {
354
- entity: this.entityName,
355
- sectionId
356
- });
357
- ErrorHandler.rethrowError(error);
369
+ throw error;
358
370
  } finally{
359
371
  await queryRunner.release();
360
372
  }
@@ -369,7 +381,10 @@ export class UserService extends RequestScopedApiService {
369
381
  async profile(dto, user) {
370
382
  await this.ensureRepositoryInitialized();
371
383
  if (!this.dataSource) {
372
- throw new BadRequestException('DataSource not available');
384
+ throw new BadRequestException({
385
+ message: 'DataSource not available',
386
+ messageKey: SYSTEM_MESSAGES.DATASOURCE_NOT_AVAILABLE
387
+ });
373
388
  }
374
389
  const userId = dto.id ?? user.id;
375
390
  if (dto.extras && this.userEnricher?.validateProfileExtras) {
@@ -385,17 +400,26 @@ export class UserService extends RequestScopedApiService {
385
400
  }
386
401
  });
387
402
  if (!findUser) {
388
- throw new NotFoundException('User not found');
403
+ throw new NotFoundException({
404
+ message: 'User not found',
405
+ messageKey: USER_MESSAGES.NOT_FOUND
406
+ });
389
407
  }
390
408
  if (dto.password) {
391
409
  const isOwnProfile = !dto.id || dto.id === user.id;
392
410
  if (isOwnProfile) {
393
411
  if (!dto.oldPassword) {
394
- throw new BadRequestException('Current password is required to change your password');
412
+ throw new BadRequestException({
413
+ message: 'Current password is required to change your password',
414
+ messageKey: AUTH_MESSAGES.PASSWORD_CHANGE_CURRENT_REQUIRED
415
+ });
395
416
  }
396
417
  const isPasswordValid = await bcrypt.compare(dto.oldPassword, findUser.password);
397
418
  if (!isPasswordValid) {
398
- throw new BadRequestException('Current password is incorrect');
419
+ throw new BadRequestException({
420
+ message: 'Current password is incorrect',
421
+ messageKey: AUTH_MESSAGES.PASSWORD_CHANGE_INVALID_CURRENT
422
+ });
399
423
  }
400
424
  }
401
425
  findUser.password = await bcrypt.hash(dto.password, BCRYPT_SALT_ROUNDS);
@@ -413,18 +437,91 @@ export class UserService extends RequestScopedApiService {
413
437
  return findUser.id;
414
438
  } catch (error) {
415
439
  await queryRunner.rollbackTransaction();
416
- ErrorHandler.logError(this.logger, error, 'profile', {
417
- entity: this.entityName
418
- });
419
- ErrorHandler.rethrowError(error);
440
+ throw error;
420
441
  } finally{
421
442
  await queryRunner.release();
422
443
  }
423
444
  }
424
445
  constructor(cacheManager, utilsService, dataSourceProvider, authConfig, userEnricher){
425
- super('user', null, cacheManager, utilsService, UserService.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), _define_property(this, "userEnricher", void 0), _define_property(this, "permissionRepository", void 0), _define_property(this, "dataSource", void 0), this.cacheManager = cacheManager, this.utilsService = utilsService, this.dataSourceProvider = dataSourceProvider, this.authConfig = authConfig, this.userEnricher = userEnricher;
446
+ super('user', null, cacheManager, utilsService, UserService.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), _define_property(this, "userEnricher", void 0), _define_property(this, "permissionRepository", void 0), _define_property(this, "dataSource", void 0), this.cacheManager = cacheManager, this.utilsService = utilsService, this.dataSourceProvider = dataSourceProvider, this.authConfig = authConfig, this.userEnricher = userEnricher;
426
447
  }
427
448
  }
449
+ _ts_decorate([
450
+ LogAction({
451
+ action: 'user.verifyEmail',
452
+ module: 'auth'
453
+ }),
454
+ _ts_metadata("design:type", Function),
455
+ _ts_metadata("design:paramtypes", [
456
+ String
457
+ ]),
458
+ _ts_metadata("design:returntype", Promise)
459
+ ], UserService.prototype, "verifyEmail", null);
460
+ _ts_decorate([
461
+ LogAction({
462
+ action: 'user.verifyPhone',
463
+ module: 'auth'
464
+ }),
465
+ _ts_metadata("design:type", Function),
466
+ _ts_metadata("design:paramtypes", [
467
+ String
468
+ ]),
469
+ _ts_metadata("design:returntype", Promise)
470
+ ], UserService.prototype, "verifyPhone", null);
471
+ _ts_decorate([
472
+ LogAction({
473
+ action: 'user.updateStatus',
474
+ module: 'auth'
475
+ }),
476
+ _ts_metadata("design:type", Function),
477
+ _ts_metadata("design:paramtypes", [
478
+ String,
479
+ Boolean,
480
+ Object
481
+ ]),
482
+ _ts_metadata("design:returntype", Promise)
483
+ ], UserService.prototype, "updateStatus", null);
484
+ _ts_decorate([
485
+ LogAction({
486
+ action: 'user.create',
487
+ module: 'auth',
488
+ includeParams: false
489
+ }),
490
+ _ts_metadata("design:type", Function),
491
+ _ts_metadata("design:paramtypes", [
492
+ typeof CreateUserDto === "undefined" ? Object : CreateUserDto,
493
+ Object
494
+ ]),
495
+ _ts_metadata("design:returntype", Promise)
496
+ ], UserService.prototype, "insert", null);
497
+ _ts_decorate([
498
+ LogAction({
499
+ action: 'user.updateProfileSection',
500
+ module: 'auth',
501
+ includeParams: false
502
+ }),
503
+ _ts_metadata("design:type", Function),
504
+ _ts_metadata("design:paramtypes", [
505
+ String,
506
+ String,
507
+ typeof Record === "undefined" ? Object : Record,
508
+ typeof ILoggedUserInfo === "undefined" ? Object : ILoggedUserInfo
509
+ ]),
510
+ _ts_metadata("design:returntype", Promise)
511
+ ], UserService.prototype, "updateProfileSection", null);
512
+ _ts_decorate([
513
+ LogAction({
514
+ action: 'user.updateProfile',
515
+ module: 'auth',
516
+ includeParams: false
517
+ }),
518
+ _ts_metadata("design:type", Function),
519
+ _ts_metadata("design:paramtypes", [
520
+ Object,
521
+ typeof ILoggedUserInfo === "undefined" ? Object : ILoggedUserInfo
522
+ ]),
523
+ _ts_metadata("design:returntype", Promise)
524
+ ], UserService.prototype, "profile", null);
428
525
  UserService = _ts_decorate([
429
526
  Injectable({
430
527
  scope: Scope.REQUEST
@@ -20,7 +20,9 @@ function _ts_decorate(decorators, target, key, desc) {
20
20
  function _ts_metadata(k, v) {
21
21
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
22
22
  }
23
+ import { SYSTEM_MESSAGES } from '@flusys/nestjs-shared/constants';
23
24
  import { Injectable, UnauthorizedException } from '@nestjs/common';
25
+ import { AUTH_MESSAGES, USER_MESSAGES } from '../config';
24
26
  import { ModuleRef } from '@nestjs/core';
25
27
  import { PassportStrategy } from '@nestjs/passport';
26
28
  import { ExtractJwt, Strategy } from 'passport-jwt';
@@ -42,7 +44,10 @@ export class JwtStrategy extends PassportStrategy(Strategy, 'jwt') {
42
44
  }
43
45
  });
44
46
  if (!user) {
45
- throw new UnauthorizedException('User not found or inactive');
47
+ throw new UnauthorizedException({
48
+ message: 'User not found or inactive',
49
+ messageKey: USER_MESSAGES.NOT_FOUND
50
+ });
46
51
  }
47
52
  return this.buildUserInfo(payload);
48
53
  }
@@ -55,9 +60,15 @@ export class JwtStrategy extends PassportStrategy(Strategy, 'jwt') {
55
60
  return provider.getRepository(User);
56
61
  }
57
62
  } catch {
58
- throw new UnauthorizedException('Unable to access user data');
63
+ throw new UnauthorizedException({
64
+ message: 'Unable to access user data',
65
+ messageKey: SYSTEM_MESSAGES.SERVICE_NOT_AVAILABLE
66
+ });
59
67
  }
60
- throw new UnauthorizedException('User repository not available');
68
+ throw new UnauthorizedException({
69
+ message: 'User repository not available',
70
+ messageKey: SYSTEM_MESSAGES.REPOSITORY_NOT_AVAILABLE
71
+ });
61
72
  }
62
73
  async checkTokenRevocation(payload) {
63
74
  if (!payload.iat) return;
@@ -66,7 +77,10 @@ export class JwtStrategy extends PassportStrategy(Strategy, 'jwt') {
66
77
  strict: false
67
78
  });
68
79
  if (authService && await authService.isTokenRevoked(payload.id, payload.iat)) {
69
- throw new UnauthorizedException('Token has been revoked');
80
+ throw new UnauthorizedException({
81
+ message: 'Token has been revoked',
82
+ messageKey: AUTH_MESSAGES.TOKEN_REVOKED
83
+ });
70
84
  }
71
85
  } catch (err) {
72
86
  if (err instanceof UnauthorizedException) throw err;
@@ -19,8 +19,8 @@ export interface AuthOptionsFactory extends IModuleOptionsFactory<IAuthModuleCon
19
19
  }
20
20
  export interface AuthModuleAsyncOptions extends Pick<ModuleMetadata, 'imports'>, IDynamicModuleConfig {
21
21
  bootstrapAppConfig: IBootstrapAppConfig;
22
- useFactory?: (...args: any[]) => Promise<IAuthModuleConfig> | IAuthModuleConfig;
23
- inject?: any[];
22
+ useFactory?: (...args: unknown[]) => Promise<IAuthModuleConfig> | IAuthModuleConfig;
23
+ inject?: unknown[];
24
24
  useClass?: Type<AuthOptionsFactory>;
25
25
  useExisting?: Type<AuthOptionsFactory>;
26
26
  providers?: Provider[];
@@ -60,4 +60,5 @@ export interface LoginResponseRequiresEmailVerification {
60
60
  requiresEmailVerification: true;
61
61
  email: string;
62
62
  message: string;
63
+ messageKey: string;
63
64
  }
@@ -1,5 +1,6 @@
1
1
  import { IBootstrapAppConfig } from '@flusys/nestjs-core';
2
2
  import { DynamicModule } from '@nestjs/common';
3
+ import { getEntitiesByConfig } from '../entities';
3
4
  import { AuthModuleAsyncOptions, AuthModuleOptions } from '../interfaces/auth-module-options.interface';
4
5
  export declare class AuthModule {
5
6
  static forRoot(options: AuthModuleOptions): DynamicModule;
@@ -11,5 +12,5 @@ export declare class AuthModule {
11
12
  private static buildProviders;
12
13
  private static buildExports;
13
14
  private static createAsyncProviders;
14
- static getEntities(config: IBootstrapAppConfig): any[];
15
+ static getEntities(config: IBootstrapAppConfig): ReturnType<typeof getEntitiesByConfig>;
15
16
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flusys/nestjs-auth",
3
- "version": "3.0.0",
3
+ "version": "4.0.0-lts",
4
4
  "description": "Authentication and authorization infrastructure for NestJS applications",
5
5
  "main": "cjs/index.js",
6
6
  "module": "fesm/index.js",
@@ -88,10 +88,12 @@
88
88
  "passport": "^0.7.0",
89
89
  "passport-jwt": "^4.0.0",
90
90
  "passport-local": "^1.0.0",
91
- "typeorm": "^0.3.0"
91
+ "typeorm": "^0.3.0",
92
+ "express": "^4.18.0",
93
+ "rxjs": "^7.8.0"
92
94
  },
93
95
  "dependencies": {
94
- "@flusys/nestjs-core": "3.0.0",
95
- "@flusys/nestjs-shared": "3.0.0"
96
+ "@flusys/nestjs-core": "4.0.0-lts",
97
+ "@flusys/nestjs-shared": "4.0.0-lts"
96
98
  }
97
99
  }
@@ -2,10 +2,8 @@ import { DatabaseMode } from '@flusys/nestjs-core';
2
2
  import { IModuleConfigService } from '@flusys/nestjs-shared/interfaces';
3
3
  import { AuthModuleOptions } from '../interfaces/auth-module-options.interface';
4
4
  export declare class AuthConfigService implements IModuleConfigService {
5
- private readonly logger;
6
5
  private readonly options;
7
6
  private readonly config;
8
- private refreshTokenSecretWarned;
9
7
  constructor(injectedOptions?: AuthModuleOptions);
10
8
  getDatabaseMode(): DatabaseMode;
11
9
  isMultiTenant(): boolean;
@@ -1,12 +1,10 @@
1
- import { MultiTenantDataSourceService } from '@flusys/nestjs-shared/modules';
1
+ import { MultiTenantDataSourceService } from '@flusys/nestjs-shared';
2
2
  import { IDatabaseConfig, ITenantDatabaseConfig } from '@flusys/nestjs-core';
3
- import { Logger } from '@nestjs/common';
4
3
  import { Request } from 'express';
5
4
  import { DataSource } from 'typeorm';
6
5
  import { AuthModuleOptions } from '../interfaces/auth-module-options.interface';
7
6
  export declare class AuthDataSourceProvider extends MultiTenantDataSourceService {
8
7
  private readonly authOptions;
9
- protected readonly logger: Logger;
10
8
  protected static readonly tenantConnections: Map<string, DataSource>;
11
9
  protected static singleDataSource: DataSource | null;
12
10
  protected static readonly tenantsRegistry: Map<string, ITenantDatabaseConfig>;
@@ -4,7 +4,6 @@ import { AuthDataSourceProvider } from './auth-datasource.provider';
4
4
  export declare class AuthEmailService {
5
5
  private readonly dataSourceProvider?;
6
6
  private readonly emailProvider?;
7
- private readonly logger;
8
7
  private readonly PASSWORD_RESET_EXPIRY;
9
8
  private readonly EMAIL_VERIFICATION_EXPIRY;
10
9
  constructor(dataSourceProvider?: AuthDataSourceProvider, emailProvider?: IAuthEmailProvider);
@@ -12,7 +11,6 @@ export declare class AuthEmailService {
12
11
  private getRepository;
13
12
  private generateToken;
14
13
  private hashToken;
15
- private getErrorMessage;
16
14
  private assertEmailEnabled;
17
15
  private sendVerificationEmailSafe;
18
16
  private validateTokenNotExpiredOrUsed;
@@ -23,19 +21,22 @@ export declare class AuthEmailService {
23
21
  phone?: string;
24
22
  password: string;
25
23
  companyData?: PendingRegistration['companyData'];
26
- additionalFields?: Record<string, any>;
24
+ additionalFields?: Record<string, unknown>;
27
25
  verifyUrlBase: string;
28
26
  }): Promise<{
29
27
  success: boolean;
30
28
  message: string;
29
+ messageKey: string;
31
30
  }>;
32
31
  forgotPassword(email: string, resetUrlBase: string): Promise<{
33
32
  success: boolean;
34
33
  message: string;
34
+ messageKey: string;
35
35
  }>;
36
36
  resetPassword(token: string, newPassword: string): Promise<{
37
37
  success: boolean;
38
38
  message: string;
39
+ messageKey: string;
39
40
  }>;
40
41
  verifyEmail(token: string): Promise<{
41
42
  type: 'pending';
@@ -43,10 +44,12 @@ export declare class AuthEmailService {
43
44
  } | {
44
45
  type: 'verified';
45
46
  message: string;
47
+ messageKey: string;
46
48
  }>;
47
49
  resendVerificationEmail(email: string, verifyUrlBase: string): Promise<{
48
50
  success: boolean;
49
51
  message: string;
52
+ messageKey: string;
50
53
  }>;
51
54
  cleanupExpired(): Promise<{
52
55
  deletedTokens: number;
@@ -1,4 +1,5 @@
1
1
  import { HybridCache } from '@flusys/nestjs-shared/classes';
2
+ import { INotificationAdapter } from '@flusys/nestjs-shared/interfaces';
2
3
  import { JwtService } from '@nestjs/jwt';
3
4
  import { IUserEnricher } from '../interfaces/user-enricher.interface';
4
5
  import { RegistrationDto } from '../dtos/authentication.dto';
@@ -18,8 +19,8 @@ export declare class AuthenticationService {
18
19
  private readonly sessionService?;
19
20
  private readonly authEmailService?;
20
21
  private readonly userEnricher?;
21
- private readonly logger;
22
- constructor(jwtService: JwtService, authConfig: AuthConfigService, cacheManager?: HybridCache, dataSourceProvider?: AuthDataSourceProvider, sessionService?: CompanySelectionSessionService, authEmailService?: AuthEmailService, userEnricher?: IUserEnricher);
22
+ private readonly notificationAdapter?;
23
+ constructor(jwtService: JwtService, authConfig: AuthConfigService, cacheManager?: HybridCache, dataSourceProvider?: AuthDataSourceProvider, sessionService?: CompanySelectionSessionService, authEmailService?: AuthEmailService, userEnricher?: IUserEnricher, notificationAdapter?: INotificationAdapter);
23
24
  private isCompanyFeatureEnabled;
24
25
  private isEmailVerificationEnabled;
25
26
  private getUserRepository;
@@ -31,6 +32,7 @@ export declare class AuthenticationService {
31
32
  register(dto: RegistrationDto, verifyUrlBase?: string): Promise<RegistrationResponse | {
32
33
  requiresEmailVerification: true;
33
34
  message: string;
35
+ messageKey: string;
34
36
  }>;
35
37
  private handleExistingUserCompanyRegistration;
36
38
  private createUserDirectly;
@@ -62,6 +64,7 @@ export declare class AuthenticationService {
62
64
  private generateTokens;
63
65
  private generateLoginResponse;
64
66
  private generateLoginResponseWithCompany;
67
+ private sendLoginNotification;
65
68
  private generateCompanySelectionResponse;
66
69
  private generateRegistrationResponse;
67
70
  private generateRegistrationResponseWithCompany;
@@ -1,4 +1,5 @@
1
1
  import { RequestScopedApiService, HybridCache } from '@flusys/nestjs-shared/classes';
2
+ import { FilterAndPaginationDto } from '@flusys/nestjs-shared/dtos';
2
3
  import { ILoggedUserInfo } from '@flusys/nestjs-shared/interfaces';
3
4
  import { UtilsService } from '@flusys/nestjs-shared/modules';
4
5
  import { EntityTarget, Repository, SelectQueryBuilder } from 'typeorm';
@@ -23,7 +24,7 @@ export declare class BranchService extends RequestScopedApiService<CreateCompany
23
24
  query: SelectQueryBuilder<CompanyBranch>;
24
25
  isRaw: boolean;
25
26
  }>;
26
- protected getExtraManipulateQuery(query: SelectQueryBuilder<CompanyBranch>, filterDto: any, user: ILoggedUserInfo | null): Promise<{
27
+ protected getExtraManipulateQuery(query: SelectQueryBuilder<CompanyBranch>, filterDto: FilterAndPaginationDto, user: ILoggedUserInfo | null): Promise<{
27
28
  query: SelectQueryBuilder<CompanyBranch>;
28
29
  isRaw: boolean;
29
30
  }>;