@flusys/nestjs-auth 3.0.0 → 4.0.0-rc

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 +3 -3
  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
@@ -8,11 +8,13 @@ Object.defineProperty(exports, "AuthEmailService", {
8
8
  return AuthEmailService;
9
9
  }
10
10
  });
11
+ const _constants = require("@flusys/nestjs-shared/constants");
12
+ const _nestjsshared = require("@flusys/nestjs-shared");
13
+ const _config = require("../config");
11
14
  const _common = require("@nestjs/common");
12
15
  const _bcrypt = /*#__PURE__*/ _interop_require_wildcard(require("bcrypt"));
13
16
  const _crypto = /*#__PURE__*/ _interop_require_wildcard(require("crypto"));
14
17
  const _typeorm = require("typeorm");
15
- const _config = require("../config");
16
18
  const _pendingregistrationentity = require("../entities/pending-registration.entity");
17
19
  const _usertokenentity = require("../entities/user-token.entity");
18
20
  const _userentity = require("../entities/user.entity");
@@ -92,7 +94,13 @@ let AuthEmailService = class AuthEmailService {
92
94
  }
93
95
  async getRepository(entity) {
94
96
  if (!this.dataSourceProvider) {
95
- throw new _common.InternalServerErrorException(`${String(entity)} repository not available`);
97
+ throw new _common.InternalServerErrorException({
98
+ message: `${String(entity)} repository not available`,
99
+ messageKey: _constants.SYSTEM_MESSAGES.REPOSITORY_NOT_AVAILABLE,
100
+ messageParams: {
101
+ entity: String(entity)
102
+ }
103
+ });
96
104
  }
97
105
  return this.dataSourceProvider.getRepository(entity);
98
106
  }
@@ -102,29 +110,36 @@ let AuthEmailService = class AuthEmailService {
102
110
  hashToken(token) {
103
111
  return _crypto.createHash('sha256').update(token).digest('hex');
104
112
  }
105
- getErrorMessage(error) {
106
- return error instanceof Error ? error.message : 'Unknown error';
107
- }
108
113
  assertEmailEnabled() {
109
114
  if (!this.emailProvider) {
110
- throw new _common.BadRequestException('Email service is not configured');
115
+ throw new _common.BadRequestException({
116
+ message: 'Email service is not configured',
117
+ messageKey: _config.AUTH_MESSAGES.EMAIL_NOT_CONFIGURED
118
+ });
111
119
  }
112
120
  }
113
- async sendVerificationEmailSafe(email, token, verifyUrl, logContext) {
121
+ async sendVerificationEmailSafe(email, token, verifyUrl) {
114
122
  try {
115
123
  await this.emailProvider.sendVerificationEmail(email, token, verifyUrl);
116
- this.logger.log(`${logContext} verification email sent to: ${email}`);
117
- } catch (error) {
118
- this.logger.error(`Failed to send verification email: ${this.getErrorMessage(error)}`);
119
- throw new _common.BadRequestException('Failed to send verification email. Please try again.');
124
+ } catch {
125
+ throw new _common.BadRequestException({
126
+ message: 'Failed to send verification email. Please try again.',
127
+ messageKey: _config.AUTH_MESSAGES.EMAIL_SEND_FAILED
128
+ });
120
129
  }
121
130
  }
122
- validateTokenNotExpiredOrUsed(token, expiredMessage, usedMessage) {
131
+ validateTokenNotExpiredOrUsed(token, expiredMessage, expiredMessageKey, usedMessage, usedMessageKey) {
123
132
  if (token.expiresAt < new Date()) {
124
- throw new _common.BadRequestException(expiredMessage);
133
+ throw new _common.BadRequestException({
134
+ message: expiredMessage,
135
+ messageKey: expiredMessageKey
136
+ });
125
137
  }
126
- if (usedMessage && token.usedAt) {
127
- throw new _common.BadRequestException(usedMessage);
138
+ if (usedMessage && usedMessageKey && token.usedAt) {
139
+ throw new _common.BadRequestException({
140
+ message: usedMessage,
141
+ messageKey: usedMessageKey
142
+ });
128
143
  }
129
144
  }
130
145
  async hasPendingRegistration(email) {
@@ -148,7 +163,10 @@ let AuthEmailService = class AuthEmailService {
148
163
  }
149
164
  });
150
165
  if (existingUser) {
151
- throw new _common.BadRequestException('Registration failed. Please try again or contact support.');
166
+ throw new _common.BadRequestException({
167
+ message: 'Registration failed. Please try again or contact support.',
168
+ messageKey: _config.AUTH_MESSAGES.REGISTER_FAILED
169
+ });
152
170
  }
153
171
  // Delete any existing pending registration for this email
154
172
  await pendingRepository.delete({
@@ -172,10 +190,11 @@ let AuthEmailService = class AuthEmailService {
172
190
  await pendingRepository.save(pending);
173
191
  // Send verification email with raw token (user receives this)
174
192
  const verifyUrl = `${data.verifyUrlBase}?token=${token}`;
175
- await this.sendVerificationEmailSafe(data.email, token, verifyUrl, 'Registration');
193
+ await this.sendVerificationEmailSafe(data.email, token, verifyUrl);
176
194
  return {
177
195
  success: true,
178
- message: 'Please check your email to verify your registration.'
196
+ message: 'Please check your email to verify your registration.',
197
+ messageKey: _config.EMAIL_VERIFICATION_MESSAGES.VERIFICATION_SENT
179
198
  };
180
199
  }
181
200
  async forgotPassword(email, resetUrlBase) {
@@ -189,10 +208,10 @@ let AuthEmailService = class AuthEmailService {
189
208
  });
190
209
  // Always return success to prevent email enumeration
191
210
  if (!user || !user.isActive) {
192
- this.logger.warn(`Password reset requested for non-existent/inactive email: ${email}`);
193
211
  return {
194
212
  success: true,
195
- message: 'If the email exists, a password reset link has been sent.'
213
+ message: 'If the email exists, a password reset link has been sent.',
214
+ messageKey: _config.AUTH_MESSAGES.PASSWORD_RESET_EMAIL_SENT
196
215
  };
197
216
  }
198
217
  // Invalidate existing password reset tokens for this user
@@ -214,14 +233,16 @@ let AuthEmailService = class AuthEmailService {
214
233
  const resetUrl = `${resetUrlBase}?token=${token}`;
215
234
  try {
216
235
  await this.emailProvider.sendPasswordResetEmail(email, token, resetUrl);
217
- this.logger.log(`Password reset email sent to: ${email}`);
218
- } catch (error) {
219
- this.logger.error(`Failed to send password reset email: ${this.getErrorMessage(error)}`);
220
- throw new _common.BadRequestException('Failed to process request. Please try again later.');
236
+ } catch {
237
+ throw new _common.BadRequestException({
238
+ message: 'Failed to process request. Please try again later.',
239
+ messageKey: _constants.SYSTEM_MESSAGES.INTERNAL_ERROR
240
+ });
221
241
  }
222
242
  return {
223
243
  success: true,
224
- message: 'If the email exists, a password reset link has been sent.'
244
+ message: 'If the email exists, a password reset link has been sent.',
245
+ messageKey: _config.AUTH_MESSAGES.PASSWORD_RESET_EMAIL_SENT
225
246
  };
226
247
  }
227
248
  async resetPassword(token, newPassword) {
@@ -236,16 +257,22 @@ let AuthEmailService = class AuthEmailService {
236
257
  }
237
258
  });
238
259
  if (!userToken) {
239
- throw new _common.BadRequestException('Invalid or expired reset token');
260
+ throw new _common.BadRequestException({
261
+ message: 'Invalid or expired reset token',
262
+ messageKey: _config.EMAIL_VERIFICATION_MESSAGES.VERIFICATION_TOKEN_INVALID
263
+ });
240
264
  }
241
- this.validateTokenNotExpiredOrUsed(userToken, 'Reset token has expired. Please request a new one.', 'This reset token has already been used.');
265
+ this.validateTokenNotExpiredOrUsed(userToken, 'Reset token has expired. Please request a new one.', _config.AUTH_MESSAGES.PASSWORD_RESET_TOKEN_EXPIRED, 'This reset token has already been used.', _config.AUTH_MESSAGES.PASSWORD_RESET_TOKEN_USED);
242
266
  const user = await userRepository.findOne({
243
267
  where: {
244
268
  id: userToken.userId
245
269
  }
246
270
  });
247
271
  if (!user) {
248
- throw new _common.BadRequestException('User not found');
272
+ throw new _common.BadRequestException({
273
+ message: 'User not found',
274
+ messageKey: _config.USER_MESSAGES.NOT_FOUND
275
+ });
249
276
  }
250
277
  // Update password
251
278
  user.password = await _bcrypt.hash(newPassword, _config.BCRYPT_SALT_ROUNDS);
@@ -253,10 +280,10 @@ let AuthEmailService = class AuthEmailService {
253
280
  // Mark token as used
254
281
  userToken.usedAt = new Date();
255
282
  await tokenRepository.save(userToken);
256
- this.logger.log(`Password reset successful for user: ${user.email}`);
257
283
  return {
258
284
  success: true,
259
- message: 'Password has been reset successfully.'
285
+ message: 'Password has been reset successfully.',
286
+ messageKey: _config.AUTH_MESSAGES.PASSWORD_RESET_SUCCESS
260
287
  };
261
288
  }
262
289
  async verifyEmail(token) {
@@ -276,7 +303,10 @@ let AuthEmailService = class AuthEmailService {
276
303
  await pendingRepository.delete({
277
304
  id: pending.id
278
305
  });
279
- throw new _common.BadRequestException('Verification token has expired. Please register again.');
306
+ throw new _common.BadRequestException({
307
+ message: 'Verification token has expired. Please register again.',
308
+ messageKey: _config.EMAIL_VERIFICATION_MESSAGES.VERIFICATION_TOKEN_EXPIRED
309
+ });
280
310
  }
281
311
  // Delete pending registration (will be consumed by caller to create user)
282
312
  await pendingRepository.delete({
@@ -295,18 +325,25 @@ let AuthEmailService = class AuthEmailService {
295
325
  }
296
326
  });
297
327
  if (!userToken) {
298
- throw new _common.BadRequestException('Invalid or expired verification token');
328
+ throw new _common.BadRequestException({
329
+ message: 'Invalid or expired verification token',
330
+ messageKey: _config.EMAIL_VERIFICATION_MESSAGES.VERIFICATION_TOKEN_INVALID
331
+ });
299
332
  }
300
333
  if (userToken.expiresAt < new Date()) {
301
334
  await tokenRepository.delete({
302
335
  id: userToken.id
303
336
  });
304
- throw new _common.BadRequestException('Verification token has expired. Please request a new one.');
337
+ throw new _common.BadRequestException({
338
+ message: 'Verification token has expired. Please request a new one.',
339
+ messageKey: _config.EMAIL_VERIFICATION_MESSAGES.VERIFICATION_TOKEN_EXPIRED
340
+ });
305
341
  }
306
342
  if (userToken.usedAt) {
307
343
  return {
308
344
  type: 'verified',
309
- message: 'Email has already been verified.'
345
+ message: 'Email has already been verified.',
346
+ messageKey: _config.EMAIL_VERIFICATION_MESSAGES.VERIFICATION_SUCCESS
310
347
  };
311
348
  }
312
349
  const user = await userRepository.findOne({
@@ -315,7 +352,10 @@ let AuthEmailService = class AuthEmailService {
315
352
  }
316
353
  });
317
354
  if (!user) {
318
- throw new _common.BadRequestException('User not found');
355
+ throw new _common.BadRequestException({
356
+ message: 'User not found',
357
+ messageKey: _config.USER_MESSAGES.NOT_FOUND
358
+ });
319
359
  }
320
360
  // Mark email as verified
321
361
  user.emailVerified = true;
@@ -323,10 +363,10 @@ let AuthEmailService = class AuthEmailService {
323
363
  // Mark token as used
324
364
  userToken.usedAt = new Date();
325
365
  await tokenRepository.save(userToken);
326
- this.logger.log(`Email verified for user: ${user.email}`);
327
366
  return {
328
367
  type: 'verified',
329
- message: 'Email has been verified successfully.'
368
+ message: 'Email has been verified successfully.',
369
+ messageKey: _config.EMAIL_VERIFICATION_MESSAGES.VERIFICATION_SUCCESS
330
370
  };
331
371
  }
332
372
  async resendVerificationEmail(email, verifyUrlBase) {
@@ -346,10 +386,11 @@ let AuthEmailService = class AuthEmailService {
346
386
  pending.expiresAt = new Date(Date.now() + this.EMAIL_VERIFICATION_EXPIRY);
347
387
  await pendingRepository.save(pending);
348
388
  const verifyUrl = `${verifyUrlBase}?token=${token}`;
349
- await this.sendVerificationEmailSafe(email, token, verifyUrl, 'Re-sent registration');
389
+ await this.sendVerificationEmailSafe(email, token, verifyUrl);
350
390
  return {
351
391
  success: true,
352
- message: 'If the email requires verification, a link has been sent.'
392
+ message: 'If the email requires verification, a link has been sent.',
393
+ messageKey: _config.EMAIL_VERIFICATION_MESSAGES.RESEND_SUCCESS
353
394
  };
354
395
  }
355
396
  // Check existing user
@@ -361,7 +402,8 @@ let AuthEmailService = class AuthEmailService {
361
402
  if (!user || user.emailVerified) {
362
403
  return {
363
404
  success: true,
364
- message: 'If the email requires verification, a link has been sent.'
405
+ message: 'If the email requires verification, a link has been sent.',
406
+ messageKey: _config.EMAIL_VERIFICATION_MESSAGES.RESEND_SUCCESS
365
407
  };
366
408
  }
367
409
  // Invalidate existing tokens and create new one
@@ -378,10 +420,11 @@ let AuthEmailService = class AuthEmailService {
378
420
  });
379
421
  await tokenRepository.save(userToken);
380
422
  const verifyUrl = `${verifyUrlBase}?token=${token}`;
381
- await this.sendVerificationEmailSafe(user.email, token, verifyUrl, 'Verification');
423
+ await this.sendVerificationEmailSafe(user.email, token, verifyUrl);
382
424
  return {
383
425
  success: true,
384
- message: 'If the email requires verification, a link has been sent.'
426
+ message: 'If the email requires verification, a link has been sent.',
427
+ messageKey: _config.EMAIL_VERIFICATION_MESSAGES.RESEND_SUCCESS
385
428
  };
386
429
  }
387
430
  async cleanupExpired() {
@@ -396,7 +439,6 @@ let AuthEmailService = class AuthEmailService {
396
439
  });
397
440
  const deletedTokens = tokenResult.affected ?? 0;
398
441
  const deletedPending = pendingResult.affected ?? 0;
399
- this.logger.log(`Cleaned up ${deletedTokens} expired tokens and ${deletedPending} expired pending registrations`);
400
442
  return {
401
443
  deletedTokens,
402
444
  deletedPending
@@ -405,16 +447,84 @@ let AuthEmailService = class AuthEmailService {
405
447
  constructor(dataSourceProvider, emailProvider){
406
448
  _define_property(this, "dataSourceProvider", void 0);
407
449
  _define_property(this, "emailProvider", void 0);
408
- _define_property(this, "logger", void 0);
409
450
  _define_property(this, "PASSWORD_RESET_EXPIRY", void 0); // 1 hour
410
451
  _define_property(this, "EMAIL_VERIFICATION_EXPIRY", void 0); // 24 hours
411
452
  this.dataSourceProvider = dataSourceProvider;
412
453
  this.emailProvider = emailProvider;
413
- this.logger = new _common.Logger(AuthEmailService.name);
414
454
  this.PASSWORD_RESET_EXPIRY = 60 * 60 * 1000;
415
455
  this.EMAIL_VERIFICATION_EXPIRY = 24 * 60 * 60 * 1000;
416
456
  }
417
457
  };
458
+ _ts_decorate([
459
+ (0, _nestjsshared.LogAction)({
460
+ action: 'auth.createPendingRegistration',
461
+ module: 'auth',
462
+ includeParams: false
463
+ }),
464
+ _ts_metadata("design:type", Function),
465
+ _ts_metadata("design:paramtypes", [
466
+ Object
467
+ ]),
468
+ _ts_metadata("design:returntype", Promise)
469
+ ], AuthEmailService.prototype, "createPendingRegistration", null);
470
+ _ts_decorate([
471
+ (0, _nestjsshared.LogAction)({
472
+ action: 'auth.forgotPassword',
473
+ module: 'auth',
474
+ includeParams: false
475
+ }),
476
+ _ts_metadata("design:type", Function),
477
+ _ts_metadata("design:paramtypes", [
478
+ String,
479
+ String
480
+ ]),
481
+ _ts_metadata("design:returntype", Promise)
482
+ ], AuthEmailService.prototype, "forgotPassword", null);
483
+ _ts_decorate([
484
+ (0, _nestjsshared.LogAction)({
485
+ action: 'auth.resetPassword',
486
+ module: 'auth',
487
+ includeParams: false
488
+ }),
489
+ _ts_metadata("design:type", Function),
490
+ _ts_metadata("design:paramtypes", [
491
+ String,
492
+ String
493
+ ]),
494
+ _ts_metadata("design:returntype", Promise)
495
+ ], AuthEmailService.prototype, "resetPassword", null);
496
+ _ts_decorate([
497
+ (0, _nestjsshared.LogAction)({
498
+ action: 'auth.verifyEmailToken',
499
+ module: 'auth'
500
+ }),
501
+ _ts_metadata("design:type", Function),
502
+ _ts_metadata("design:paramtypes", [
503
+ String
504
+ ]),
505
+ _ts_metadata("design:returntype", Promise)
506
+ ], AuthEmailService.prototype, "verifyEmail", null);
507
+ _ts_decorate([
508
+ (0, _nestjsshared.LogAction)({
509
+ action: 'auth.sendVerificationEmail',
510
+ module: 'auth'
511
+ }),
512
+ _ts_metadata("design:type", Function),
513
+ _ts_metadata("design:paramtypes", [
514
+ String,
515
+ String
516
+ ]),
517
+ _ts_metadata("design:returntype", Promise)
518
+ ], AuthEmailService.prototype, "resendVerificationEmail", null);
519
+ _ts_decorate([
520
+ (0, _nestjsshared.LogAction)({
521
+ action: 'auth.cleanupExpiredTokens',
522
+ module: 'auth'
523
+ }),
524
+ _ts_metadata("design:type", Function),
525
+ _ts_metadata("design:paramtypes", []),
526
+ _ts_metadata("design:returntype", Promise)
527
+ ], AuthEmailService.prototype, "cleanupExpired", null);
418
528
  AuthEmailService = _ts_decorate([
419
529
  (0, _common.Injectable)({
420
530
  scope: _common.Scope.REQUEST