@flusys/nestjs-auth 0.1.0-beta.3 → 1.1.0-beta

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 (73) hide show
  1. package/README.md +1 -11
  2. package/cjs/config/auth.constants.js +14 -4
  3. package/cjs/controllers/authentication.controller.js +173 -36
  4. package/cjs/controllers/branch.controller.js +3 -4
  5. package/cjs/controllers/company.controller.js +3 -4
  6. package/cjs/controllers/user-permission.controller.js +6 -18
  7. package/cjs/controllers/user.controller.js +168 -22
  8. package/cjs/dtos/authentication.dto.js +106 -3
  9. package/cjs/entities/index.js +5 -1
  10. package/cjs/entities/pending-registration.entity.js +125 -0
  11. package/cjs/entities/user-token.entity.js +129 -0
  12. package/cjs/interfaces/auth-email-provider.interface.js +45 -0
  13. package/cjs/interfaces/authentication.interface.js +0 -3
  14. package/cjs/interfaces/index.js +2 -0
  15. package/cjs/interfaces/user-enricher.interface.js +4 -0
  16. package/cjs/modules/auth.module.js +8 -2
  17. package/cjs/services/auth-config.service.js +22 -44
  18. package/cjs/services/auth-datasource.provider.js +17 -33
  19. package/cjs/services/auth-email.service.js +452 -0
  20. package/cjs/services/authentication.service.js +229 -115
  21. package/cjs/services/branch.service.js +10 -44
  22. package/cjs/services/company.service.js +7 -36
  23. package/cjs/services/index.js +1 -0
  24. package/cjs/services/user-permission.service.js +9 -27
  25. package/cjs/services/user.service.js +177 -99
  26. package/cjs/strategies/jwt.strategy.js +14 -1
  27. package/config/auth.constants.d.ts +3 -0
  28. package/controllers/authentication.controller.d.ts +13 -9
  29. package/controllers/user.controller.d.ts +27 -0
  30. package/dtos/authentication.dto.d.ts +21 -3
  31. package/dtos/user.dto.d.ts +1 -0
  32. package/entities/index.d.ts +7 -3
  33. package/entities/pending-registration.entity.d.ts +17 -0
  34. package/entities/user-token.entity.d.ts +15 -0
  35. package/fesm/config/auth.constants.js +18 -8
  36. package/fesm/controllers/authentication.controller.js +174 -37
  37. package/fesm/controllers/branch.controller.js +5 -6
  38. package/fesm/controllers/company.controller.js +5 -6
  39. package/fesm/controllers/user-permission.controller.js +6 -18
  40. package/fesm/controllers/user.controller.js +168 -22
  41. package/fesm/dtos/authentication.dto.js +109 -100
  42. package/fesm/entities/index.js +7 -1
  43. package/fesm/entities/pending-registration.entity.js +115 -0
  44. package/fesm/entities/user-token.entity.js +113 -0
  45. package/fesm/interfaces/auth-email-provider.interface.js +38 -0
  46. package/fesm/interfaces/authentication.interface.js +1 -7
  47. package/fesm/interfaces/index.js +2 -0
  48. package/fesm/interfaces/user-enricher.interface.js +26 -0
  49. package/fesm/modules/auth.module.js +9 -3
  50. package/fesm/services/auth-config.service.js +22 -44
  51. package/fesm/services/auth-datasource.provider.js +17 -33
  52. package/fesm/services/auth-email.service.js +401 -0
  53. package/fesm/services/authentication.service.js +227 -113
  54. package/fesm/services/branch.service.js +11 -45
  55. package/fesm/services/company.service.js +8 -37
  56. package/fesm/services/index.js +1 -0
  57. package/fesm/services/user-permission.service.js +9 -27
  58. package/fesm/services/user.service.js +178 -100
  59. package/fesm/strategies/jwt.strategy.js +14 -1
  60. package/interfaces/auth-email-provider.interface.d.ts +6 -0
  61. package/interfaces/auth-module-options.interface.d.ts +4 -1
  62. package/interfaces/authentication.interface.d.ts +14 -0
  63. package/interfaces/index.d.ts +2 -0
  64. package/interfaces/user-enricher.interface.d.ts +67 -0
  65. package/interfaces/user.interface.d.ts +1 -0
  66. package/package.json +3 -3
  67. package/services/auth-config.service.d.ts +1 -0
  68. package/services/auth-email.service.d.ts +50 -0
  69. package/services/authentication.service.d.ts +21 -5
  70. package/services/branch.service.d.ts +2 -5
  71. package/services/company.service.d.ts +1 -4
  72. package/services/index.d.ts +1 -0
  73. package/services/user.service.d.ts +17 -6
@@ -17,6 +17,9 @@ const _utils = require("@flusys/nestjs-shared/utils");
17
17
  const _authconfigservice = require("./auth-config.service");
18
18
  const _authdatasourceprovider = require("./auth-datasource.provider");
19
19
  const _enums = require("../enums");
20
+ const _config = require("../config");
21
+ const _classes = require("@flusys/nestjs-shared/classes");
22
+ const _authemailservice = require("./auth-email.service");
20
23
  const _companybranchentity = require("../entities/company-branch.entity");
21
24
  const _companyentity = require("../entities/company.entity");
22
25
  const _usercompanypermissionentity = require("../entities/user-company-permission.entity");
@@ -90,12 +93,8 @@ function _ts_param(paramIndex, decorator) {
90
93
  decorator(target, key, paramIndex);
91
94
  };
92
95
  }
93
- // Password hashing configuration
94
- const BCRYPT_SALT_ROUNDS = 12; // Increased from 10 for better security
95
96
  let AuthenticationService = class AuthenticationService {
96
- // ==========================================================================
97
- // REPOSITORY GETTERS
98
- // ==========================================================================
97
+ // Repository Getters
99
98
  async getUserRepository() {
100
99
  if (this.dataSourceProvider) {
101
100
  return this.dataSourceProvider.getRepository(_userentity.User);
@@ -126,26 +125,26 @@ let AuthenticationService = class AuthenticationService {
126
125
  }
127
126
  return this.injectedBranchRepository ?? null;
128
127
  }
129
- // ==========================================================================
130
- // LOGIN
131
- // ==========================================================================
132
- /**
133
- * Login with email and password
134
- * Returns either tokens directly or requires company/branch selection
135
- */ async login(email, password) {
128
+ // Login
129
+ /** Login with email and password. Returns tokens or requires company/branch selection. */ async login(email, password) {
136
130
  const user = await this.validateUser(email, password);
137
131
  if (!user.isActive) {
138
132
  throw new _common.UnauthorizedException('User account is deactivated');
139
133
  }
140
- // If company feature not enabled, return simple token
134
+ // Check email verification if email service is enabled
135
+ if (this.authEmailService?.isEmailEnabled() && !user.emailVerified) {
136
+ return {
137
+ requiresEmailVerification: true,
138
+ email: user.email,
139
+ message: 'Please verify your email address before logging in.'
140
+ };
141
+ }
141
142
  if (!this.authConfig.isCompanyFeatureEnabled()) {
142
143
  return this.generateLoginResponse(user);
143
144
  }
144
145
  return this.handleCompanyBasedLogin(user);
145
146
  }
146
- /**
147
- * Handle login when company feature is enabled
148
- */ async handleCompanyBasedLogin(user) {
147
+ /** Handle login when company feature is enabled */ async handleCompanyBasedLogin(user) {
149
148
  const permissionRepository = await this.getPermissionRepository();
150
149
  const branchRepository = await this.getBranchRepository();
151
150
  if (!permissionRepository || !branchRepository) {
@@ -195,16 +194,9 @@ let AuthenticationService = class AuthenticationService {
195
194
  // Returns all companies with their branches for frontend to display
196
195
  return await this.generateCompanySelectionResponse(user, companies, branches);
197
196
  }
198
- // ==========================================================================
199
- // REGISTRATION
200
- // ==========================================================================
201
- /**
202
- * Register a new user
203
- * If company feature enabled, optionally join/create company
204
- */ async register(dto) {
197
+ // Registration
198
+ /** Register a new user. If email enabled, creates pending registration. Otherwise creates user directly. */ async register(dto, verifyUrlBase) {
205
199
  const userRepository = await this.getUserRepository();
206
- // Check if user exists
207
- // Note: Generic error message to prevent email enumeration attacks
208
200
  const existingUser = await userRepository.findOne({
209
201
  where: {
210
202
  email: dto.email
@@ -213,8 +205,34 @@ let AuthenticationService = class AuthenticationService {
213
205
  if (existingUser) {
214
206
  throw new _common.BadRequestException('Registration failed. Please try again or contact support.');
215
207
  }
216
- // Create user
217
- const hashedPassword = await _bcrypt.hash(dto.password, BCRYPT_SALT_ROUNDS);
208
+ // If email verification is enabled, create pending registration instead of user
209
+ if (this.authEmailService?.isEmailEnabled() && verifyUrlBase) {
210
+ const companyData = this.authConfig.isCompanyFeatureEnabled() ? {
211
+ companySlug: dto.companySlug,
212
+ branchSlug: dto.branchSlug,
213
+ newCompanyName: dto.newCompanyName,
214
+ newCompanyPhone: dto.newCompanyPhone,
215
+ newCompanyAddress: dto.newCompanyAddress
216
+ } : undefined;
217
+ const result = await this.authEmailService.createPendingRegistration({
218
+ email: dto.email,
219
+ name: dto.name,
220
+ phone: dto.phone,
221
+ password: dto.password,
222
+ companyData,
223
+ verifyUrlBase
224
+ });
225
+ return {
226
+ requiresEmailVerification: true,
227
+ message: result.message
228
+ };
229
+ }
230
+ // No email verification - create user directly
231
+ return this.createUserDirectly(dto);
232
+ }
233
+ /** Create user directly (no email verification) */ async createUserDirectly(dto) {
234
+ const userRepository = await this.getUserRepository();
235
+ const hashedPassword = await _bcrypt.hash(dto.password, _config.BCRYPT_SALT_ROUNDS);
218
236
  const user = userRepository.create({
219
237
  name: dto.name,
220
238
  email: dto.email,
@@ -225,40 +243,68 @@ let AuthenticationService = class AuthenticationService {
225
243
  phoneVerified: false
226
244
  });
227
245
  await userRepository.save(user);
228
- // If company feature not enabled, return simple response
229
246
  if (!this.authConfig.isCompanyFeatureEnabled()) {
230
- return this.generateLoginResponse(user, false);
247
+ return this.generateRegistrationResponse(user, false, false);
248
+ }
249
+ return this.handleCompanyRegistration(user, dto, false);
250
+ }
251
+ /** Create user from pending registration (after email verification) */ async createUserFromPendingRegistration(pending) {
252
+ const userRepository = await this.getUserRepository();
253
+ // Check if user already exists (race condition protection)
254
+ const existingUser = await userRepository.findOne({
255
+ where: {
256
+ email: pending.email
257
+ }
258
+ });
259
+ if (existingUser) {
260
+ throw new _common.BadRequestException('This email has already been registered.');
231
261
  }
232
- // Handle company feature
233
- return this.handleCompanyRegistration(user, dto);
262
+ // Create user with verified email
263
+ const user = userRepository.create({
264
+ name: pending.name,
265
+ email: pending.email,
266
+ phone: pending.phone,
267
+ password: pending.passwordHash,
268
+ isActive: true,
269
+ emailVerified: true,
270
+ phoneVerified: false
271
+ });
272
+ await userRepository.save(user);
273
+ // Handle company feature if enabled
274
+ if (this.authConfig.isCompanyFeatureEnabled() && pending.companyData) {
275
+ return this.handleCompanyRegistrationFromPending(user, pending.companyData);
276
+ }
277
+ return this.generateRegistrationResponse(user, this.authConfig.isCompanyFeatureEnabled(), false);
278
+ }
279
+ /** Handle company registration from pending registration data */ async handleCompanyRegistrationFromPending(user, companyData) {
280
+ return this.processCompanyRegistration(user, companyData, false);
281
+ }
282
+ /** Handle company-related registration logic */ async handleCompanyRegistration(user, dto, requiresEmailVerification) {
283
+ return this.processCompanyRegistration(user, dto, requiresEmailVerification);
234
284
  }
235
- /**
236
- * Handle company-related registration logic
237
- */ async handleCompanyRegistration(user, dto) {
285
+ /** Shared logic for company registration (join existing or create new) */ async processCompanyRegistration(user, data, requiresEmailVerification) {
238
286
  const companyRepository = await this.getCompanyRepository();
239
287
  const branchRepository = await this.getBranchRepository();
240
288
  const permissionRepository = await this.getPermissionRepository();
241
289
  if (!companyRepository || !branchRepository || !permissionRepository) {
242
- return this.generateLoginResponse(user, true);
290
+ return this.generateRegistrationResponse(user, true, requiresEmailVerification);
243
291
  }
244
292
  let company = null;
245
293
  let branch = null;
246
- // Case 1: Join existing company by slug
247
- if (dto.companySlug) {
294
+ if (data.companySlug) {
248
295
  company = await companyRepository.findOne({
249
296
  where: {
250
- slug: dto.companySlug,
297
+ slug: data.companySlug,
251
298
  isActive: true
252
299
  }
253
300
  });
254
301
  if (!company) {
255
302
  throw new _common.BadRequestException('Company not found or inactive');
256
303
  }
257
- // Find branch by slug or get default
258
- if (dto.branchSlug) {
304
+ if (data.branchSlug) {
259
305
  branch = await branchRepository.findOne({
260
306
  where: {
261
- slug: dto.branchSlug,
307
+ slug: data.branchSlug,
262
308
  companyId: company.id,
263
309
  isActive: true
264
310
  }
@@ -267,7 +313,6 @@ let AuthenticationService = class AuthenticationService {
267
313
  throw new _common.BadRequestException('Branch not found or inactive');
268
314
  }
269
315
  } else {
270
- // Get first active branch
271
316
  branch = await branchRepository.findOne({
272
317
  where: {
273
318
  companyId: company.id,
@@ -279,9 +324,8 @@ let AuthenticationService = class AuthenticationService {
279
324
  }
280
325
  });
281
326
  }
282
- } else if (dto.newCompanyName) {
283
- const slug = this.generateSlug(dto.newCompanyName);
284
- // Check if slug exists
327
+ } else if (data.newCompanyName) {
328
+ const slug = this.generateSlug(data.newCompanyName);
285
329
  const existingCompany = await companyRepository.findOne({
286
330
  where: {
287
331
  slug
@@ -290,16 +334,14 @@ let AuthenticationService = class AuthenticationService {
290
334
  if (existingCompany) {
291
335
  throw new _common.BadRequestException('Company creation failed. Please try a different name.');
292
336
  }
293
- // Create company
294
337
  company = companyRepository.create({
295
- name: dto.newCompanyName,
338
+ name: data.newCompanyName,
296
339
  slug,
297
- phone: dto.newCompanyPhone,
298
- address: dto.newCompanyAddress,
340
+ phone: data.newCompanyPhone,
341
+ address: data.newCompanyAddress,
299
342
  isActive: true
300
343
  });
301
344
  await companyRepository.save(company);
302
- // Create default branch
303
345
  branch = branchRepository.create({
304
346
  name: 'Main Branch',
305
347
  slug: 'main-branch',
@@ -308,16 +350,13 @@ let AuthenticationService = class AuthenticationService {
308
350
  });
309
351
  await branchRepository.save(branch);
310
352
  }
311
- // Create permissions if company exists
312
353
  if (company) {
313
- // Create company permission
314
354
  const companyPermission = permissionRepository.create({
315
355
  userId: user.id,
316
356
  permissionType: _enums.PermissionType.COMPANY,
317
357
  targetId: company.id
318
358
  });
319
359
  await permissionRepository.save(companyPermission);
320
- // Create branch permission if branch exists
321
360
  if (branch) {
322
361
  const branchPermission = permissionRepository.create({
323
362
  userId: user.id,
@@ -326,23 +365,15 @@ let AuthenticationService = class AuthenticationService {
326
365
  });
327
366
  await permissionRepository.save(branchPermission);
328
367
  }
329
- return this.generateLoginResponseWithCompany(user, company, branch ?? undefined);
368
+ return this.generateRegistrationResponseWithCompany(user, company, branch ?? undefined, requiresEmailVerification);
330
369
  }
331
- // No company assigned
332
- return this.generateLoginResponse(user, true);
370
+ return this.generateRegistrationResponse(user, true, requiresEmailVerification);
333
371
  }
334
- /**
335
- * Generate URL-friendly slug from name
336
- */ generateSlug(name) {
372
+ /** Generate URL-friendly slug from name */ generateSlug(name) {
337
373
  return name.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '').substring(0, 100);
338
374
  }
339
- // ==========================================================================
340
- // COMPANY/BRANCH SELECTION
341
- // ==========================================================================
342
- /**
343
- * Select company and branch (step 2 of login)
344
- * Frontend receives all options and user selects both together
345
- */ async select(sessionId, companyId, branchId) {
375
+ // Company/Branch Selection
376
+ /** Select company and branch (step 2 of login). Frontend receives all options and user selects both. */ async select(sessionId, companyId, branchId) {
346
377
  this.ensureCompanyFeatureEnabled();
347
378
  if (!this.sessionService) {
348
379
  throw new _common.BadRequestException('Session service not available');
@@ -409,9 +440,7 @@ let AuthenticationService = class AuthenticationService {
409
440
  }
410
441
  return this.generateLoginResponseWithCompany(user, company, branch);
411
442
  }
412
- /**
413
- * Switch company/branch after login
414
- */ async switchCompany(userId, companyId, branchId) {
443
+ /** Switch company/branch after login */ async switchCompany(userId, companyId, branchId) {
415
444
  this.ensureCompanyFeatureEnabled();
416
445
  const userRepository = await this.getUserRepository();
417
446
  const user = await userRepository.findOne({
@@ -470,13 +499,8 @@ let AuthenticationService = class AuthenticationService {
470
499
  }
471
500
  return this.generateLoginResponseWithCompany(user, company, branch);
472
501
  }
473
- // ==========================================================================
474
- // TOKEN MANAGEMENT
475
- // ==========================================================================
476
- /**
477
- * Refresh access token (with token rotation)
478
- * Returns new access token and new refresh token
479
- */ async refreshToken(refreshToken) {
502
+ // Token Management
503
+ /** Refresh access token (with token rotation). Returns new access token and new refresh token. */ async refreshToken(refreshToken) {
480
504
  try {
481
505
  const payload = this.jwtService.verify(refreshToken, {
482
506
  secret: this.authConfig.getRefreshTokenSecret()
@@ -542,9 +566,7 @@ let AuthenticationService = class AuthenticationService {
542
566
  throw new _common.UnauthorizedException('Invalid or expired refresh token');
543
567
  }
544
568
  }
545
- /**
546
- * Change password
547
- */ async changePassword(userId, currentPassword, newPassword) {
569
+ /** Change password */ async changePassword(userId, currentPassword, newPassword) {
548
570
  const userRepository = await this.getUserRepository();
549
571
  const user = await userRepository.findOne({
550
572
  where: {
@@ -558,18 +580,53 @@ let AuthenticationService = class AuthenticationService {
558
580
  if (!isPasswordValid) {
559
581
  throw new _common.UnauthorizedException('Current password is incorrect');
560
582
  }
561
- user.password = await _bcrypt.hash(newPassword, BCRYPT_SALT_ROUNDS);
583
+ user.password = await _bcrypt.hash(newPassword, _config.BCRYPT_SALT_ROUNDS);
562
584
  await userRepository.save(user);
563
585
  }
564
- /**
565
- * Logout (placeholder for token blacklisting if needed)
566
- */ async logout(_userId) {}
567
- // ==========================================================================
568
- // QUERY METHODS
569
- // ==========================================================================
570
- /**
571
- * Get user's companies
572
- */ async getUserCompanies(userId) {
586
+ /** Logout - Revokes all tokens. Stores revocation timestamp in cache. */ async logout(userId) {
587
+ if (!this.cacheManager) {
588
+ // Cache not available - graceful degradation (client-side logout only)
589
+ return;
590
+ }
591
+ const revokedAt = Math.floor(Date.now() / 1000); // Unix timestamp in seconds
592
+ const cacheKey = `${_config.TOKEN_REVOKED_PREFIX}:${userId}`;
593
+ // TTL matches refresh token expiry (tokens older than this are already expired)
594
+ const refreshTokenExpiry = this.authConfig.getRefreshTokenExpiration();
595
+ const ttlMs = this.parseExpiryToMs(refreshTokenExpiry);
596
+ await this.cacheManager.set(cacheKey, revokedAt, ttlMs);
597
+ }
598
+ /** Check if a token is revoked (issued before user's revocation timestamp) */ async isTokenRevoked(userId, tokenIssuedAt) {
599
+ if (!this.cacheManager || !tokenIssuedAt) {
600
+ return false;
601
+ }
602
+ const cacheKey = `${_config.TOKEN_REVOKED_PREFIX}:${userId}`;
603
+ const revokedAt = await this.cacheManager.get(cacheKey);
604
+ if (!revokedAt) {
605
+ return false;
606
+ }
607
+ // Token is revoked if it was issued before the revocation timestamp
608
+ return tokenIssuedAt < revokedAt;
609
+ }
610
+ /** Parse JWT expiry string to milliseconds */ parseExpiryToMs(expiry) {
611
+ const match = expiry.match(/^(\d+)([smhd])$/);
612
+ if (!match) return 7 * 24 * 60 * 60 * 1000; // Default 7 days
613
+ const value = parseInt(match[1], 10);
614
+ const unit = match[2];
615
+ switch(unit){
616
+ case 's':
617
+ return value * 1000;
618
+ case 'm':
619
+ return value * 60 * 1000;
620
+ case 'h':
621
+ return value * 60 * 60 * 1000;
622
+ case 'd':
623
+ return value * 24 * 60 * 60 * 1000;
624
+ default:
625
+ return 7 * 24 * 60 * 60 * 1000;
626
+ }
627
+ }
628
+ // Query Methods
629
+ /** Get user's companies */ async getUserCompanies(userId) {
573
630
  this.ensureCompanyFeatureEnabled();
574
631
  const permissionRepository = await this.getPermissionRepository();
575
632
  const companyRepository = await this.getCompanyRepository();
@@ -590,9 +647,7 @@ let AuthenticationService = class AuthenticationService {
590
647
  active: true
591
648
  }).orderBy('c.name', 'ASC').getMany();
592
649
  }
593
- /**
594
- * Get branches for a company that user has access to
595
- */ async getUserBranches(userId, companyId) {
650
+ /** Get branches for a company that user has access to */ async getUserBranches(userId, companyId) {
596
651
  this.ensureCompanyFeatureEnabled();
597
652
  const permissionRepository = await this.getPermissionRepository();
598
653
  const branchRepository = await this.getBranchRepository();
@@ -627,9 +682,7 @@ let AuthenticationService = class AuthenticationService {
627
682
  active: true
628
683
  }).orderBy('b.serial', 'ASC').addOrderBy('b.name', 'ASC').getMany();
629
684
  }
630
- /**
631
- * Get company by ID
632
- */ async getCompanyById(companyId) {
685
+ /** Get company by ID */ async getCompanyById(companyId) {
633
686
  const companyRepository = await this.getCompanyRepository();
634
687
  if (!companyRepository) {
635
688
  return null;
@@ -640,9 +693,7 @@ let AuthenticationService = class AuthenticationService {
640
693
  }
641
694
  });
642
695
  }
643
- /**
644
- * Get branch by ID
645
- */ async getBranchById(branchId) {
696
+ /** Get branch by ID */ async getBranchById(branchId) {
646
697
  const branchRepository = await this.getBranchRepository();
647
698
  if (!branchRepository) {
648
699
  return null;
@@ -653,10 +704,7 @@ let AuthenticationService = class AuthenticationService {
653
704
  }
654
705
  });
655
706
  }
656
- /**
657
- * Get user info for /auth/me endpoint
658
- * Returns only user, company, and branch information (no tokens)
659
- */ async getUserInfo(userId, companyId, branchId) {
707
+ /** Get user info for /auth/me endpoint. Returns user, company, and branch info (no tokens). */ async getUserInfo(userId, companyId, branchId) {
660
708
  const userRepository = await this.getUserRepository();
661
709
  const user = await userRepository.findOne({
662
710
  where: {
@@ -672,6 +720,7 @@ let AuthenticationService = class AuthenticationService {
672
720
  id: user.id,
673
721
  email: user.email,
674
722
  name: user.name ?? undefined,
723
+ phone: user.phone ?? undefined,
675
724
  profilePictureId: user.profilePictureId ?? undefined
676
725
  }
677
726
  };
@@ -707,9 +756,7 @@ let AuthenticationService = class AuthenticationService {
707
756
  }
708
757
  return response;
709
758
  }
710
- // ==========================================================================
711
- // HELPER METHODS
712
- // ==========================================================================
759
+ // Helper Methods
713
760
  ensureCompanyFeatureEnabled() {
714
761
  if (!this.authConfig.isCompanyFeatureEnabled()) {
715
762
  throw new _common.BadRequestException('Company feature is not enabled');
@@ -733,9 +780,7 @@ let AuthenticationService = class AuthenticationService {
733
780
  await userRepository.save(user);
734
781
  return user;
735
782
  }
736
- // ==========================================================================
737
- // RESPONSE GENERATORS
738
- // ==========================================================================
783
+ // Response Generators
739
784
  generateLoginResponse(user, companyFeatureEnabled = false) {
740
785
  const payload = {
741
786
  id: user.id,
@@ -762,6 +807,7 @@ let AuthenticationService = class AuthenticationService {
762
807
  id: user.id,
763
808
  email: user.email,
764
809
  name: user.name ?? undefined,
810
+ phone: user.phone ?? null,
765
811
  profilePictureId: user.profilePictureId ?? null
766
812
  },
767
813
  companyFeatureEnabled
@@ -797,6 +843,7 @@ let AuthenticationService = class AuthenticationService {
797
843
  id: user.id,
798
844
  email: user.email,
799
845
  name: user.name ?? undefined,
846
+ phone: user.phone ?? null,
800
847
  profilePictureId: user.profilePictureId ?? null
801
848
  },
802
849
  company: {
@@ -842,17 +889,76 @@ let AuthenticationService = class AuthenticationService {
842
889
  id: user.id,
843
890
  email: user.email,
844
891
  name: user.name ?? undefined,
892
+ phone: user.phone ?? null,
845
893
  profilePictureId: user.profilePictureId ?? null
846
894
  },
847
895
  companies: companiesWithBranches
848
896
  };
849
897
  }
898
+ /** Generate registration response - tokens included only if email verification not required */ generateRegistrationResponse(user, companyFeatureEnabled, requiresEmailVerification) {
899
+ const userInfo = {
900
+ id: user.id,
901
+ email: user.email,
902
+ name: user.name ?? undefined,
903
+ phone: user.phone ?? null,
904
+ profilePictureId: user.profilePictureId ?? null
905
+ };
906
+ if (requiresEmailVerification) {
907
+ return {
908
+ user: userInfo,
909
+ companyFeatureEnabled,
910
+ requiresEmailVerification: true
911
+ };
912
+ }
913
+ const loginResponse = this.generateLoginResponse(user, companyFeatureEnabled);
914
+ return {
915
+ ...loginResponse,
916
+ requiresEmailVerification: false
917
+ };
918
+ }
919
+ /** Generate registration response with company - tokens included only if email verification not required */ generateRegistrationResponseWithCompany(user, company, branch, requiresEmailVerification = false) {
920
+ const userInfo = {
921
+ id: user.id,
922
+ email: user.email,
923
+ name: user.name ?? undefined,
924
+ phone: user.phone ?? null,
925
+ profilePictureId: user.profilePictureId ?? null
926
+ };
927
+ const companyInfo = {
928
+ id: company.id,
929
+ name: company.name,
930
+ slug: company.slug,
931
+ logoId: company.logoId ?? null
932
+ };
933
+ const branchInfo = branch ? {
934
+ id: branch.id,
935
+ name: branch.name,
936
+ slug: branch.slug,
937
+ logoId: branch.logoId ?? null
938
+ } : undefined;
939
+ if (requiresEmailVerification) {
940
+ return {
941
+ user: userInfo,
942
+ company: companyInfo,
943
+ branch: branchInfo,
944
+ companyFeatureEnabled: true,
945
+ requiresEmailVerification: true
946
+ };
947
+ }
948
+ const loginResponse = this.generateLoginResponseWithCompany(user, company, branch);
949
+ return {
950
+ ...loginResponse,
951
+ requiresEmailVerification: false
952
+ };
953
+ }
850
954
  // NOTE: @Inject() required for bundled code - type metadata may be lost during esbuild
851
- constructor(jwtService, authConfig, dataSourceProvider, sessionService, injectedUserRepository, injectedPermissionRepository, injectedCompanyRepository, injectedBranchRepository){
955
+ constructor(jwtService, authConfig, cacheManager, dataSourceProvider, sessionService, authEmailService, injectedUserRepository, injectedPermissionRepository, injectedCompanyRepository, injectedBranchRepository){
852
956
  _define_property(this, "jwtService", void 0);
853
957
  _define_property(this, "authConfig", void 0);
958
+ _define_property(this, "cacheManager", void 0);
854
959
  _define_property(this, "dataSourceProvider", void 0);
855
960
  _define_property(this, "sessionService", void 0);
961
+ _define_property(this, "authEmailService", void 0);
856
962
  _define_property(this, "injectedUserRepository", void 0);
857
963
  _define_property(this, "injectedPermissionRepository", void 0);
858
964
  _define_property(this, "injectedCompanyRepository", void 0);
@@ -860,8 +966,10 @@ let AuthenticationService = class AuthenticationService {
860
966
  _define_property(this, "logger", void 0);
861
967
  this.jwtService = jwtService;
862
968
  this.authConfig = authConfig;
969
+ this.cacheManager = cacheManager;
863
970
  this.dataSourceProvider = dataSourceProvider;
864
971
  this.sessionService = sessionService;
972
+ this.authEmailService = authEmailService;
865
973
  this.injectedUserRepository = injectedUserRepository;
866
974
  this.injectedPermissionRepository = injectedPermissionRepository;
867
975
  this.injectedCompanyRepository = injectedCompanyRepository;
@@ -876,23 +984,29 @@ AuthenticationService = _ts_decorate([
876
984
  _ts_param(0, (0, _common.Inject)(_jwt.JwtService)),
877
985
  _ts_param(1, (0, _common.Inject)(_authconfigservice.AuthConfigService)),
878
986
  _ts_param(2, (0, _common.Optional)()),
879
- _ts_param(2, (0, _common.Inject)(_authdatasourceprovider.AuthDataSourceProvider)),
987
+ _ts_param(2, (0, _common.Inject)('CACHE_INSTANCE')),
880
988
  _ts_param(3, (0, _common.Optional)()),
881
- _ts_param(3, (0, _common.Inject)(_companyselectionsessionservice.CompanySelectionSessionService)),
989
+ _ts_param(3, (0, _common.Inject)(_authdatasourceprovider.AuthDataSourceProvider)),
882
990
  _ts_param(4, (0, _common.Optional)()),
883
- _ts_param(4, (0, _typeorm.InjectRepository)(_userentity.User)),
991
+ _ts_param(4, (0, _common.Inject)(_companyselectionsessionservice.CompanySelectionSessionService)),
884
992
  _ts_param(5, (0, _common.Optional)()),
885
- _ts_param(5, (0, _typeorm.InjectRepository)(_usercompanypermissionentity.UserCompanyPermission)),
993
+ _ts_param(5, (0, _common.Inject)(_authemailservice.AuthEmailService)),
886
994
  _ts_param(6, (0, _common.Optional)()),
887
- _ts_param(6, (0, _typeorm.InjectRepository)(_companyentity.Company)),
995
+ _ts_param(6, (0, _typeorm.InjectRepository)(_userentity.User)),
888
996
  _ts_param(7, (0, _common.Optional)()),
889
- _ts_param(7, (0, _typeorm.InjectRepository)(_companybranchentity.CompanyBranch)),
997
+ _ts_param(7, (0, _typeorm.InjectRepository)(_usercompanypermissionentity.UserCompanyPermission)),
998
+ _ts_param(8, (0, _common.Optional)()),
999
+ _ts_param(8, (0, _typeorm.InjectRepository)(_companyentity.Company)),
1000
+ _ts_param(9, (0, _common.Optional)()),
1001
+ _ts_param(9, (0, _typeorm.InjectRepository)(_companybranchentity.CompanyBranch)),
890
1002
  _ts_metadata("design:type", Function),
891
1003
  _ts_metadata("design:paramtypes", [
892
1004
  typeof _jwt.JwtService === "undefined" ? Object : _jwt.JwtService,
893
1005
  typeof _authconfigservice.AuthConfigService === "undefined" ? Object : _authconfigservice.AuthConfigService,
1006
+ typeof _classes.HybridCache === "undefined" ? Object : _classes.HybridCache,
894
1007
  typeof _authdatasourceprovider.AuthDataSourceProvider === "undefined" ? Object : _authdatasourceprovider.AuthDataSourceProvider,
895
1008
  typeof _companyselectionsessionservice.CompanySelectionSessionService === "undefined" ? Object : _companyselectionsessionservice.CompanySelectionSessionService,
1009
+ typeof _authemailservice.AuthEmailService === "undefined" ? Object : _authemailservice.AuthEmailService,
896
1010
  typeof _typeorm1.Repository === "undefined" ? Object : _typeorm1.Repository,
897
1011
  typeof _typeorm1.Repository === "undefined" ? Object : _typeorm1.Repository,
898
1012
  typeof _typeorm1.Repository === "undefined" ? Object : _typeorm1.Repository,