@flusys/nestjs-auth 7.0.2 → 8.0.0-beta.1

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 (237) hide show
  1. package/README.md +68 -1
  2. package/config/auth.constants.d.ts +2 -0
  3. package/config/event-actions.d.ts +2 -0
  4. package/config/index.d.ts +3 -3
  5. package/config/message-keys.d.ts +23 -0
  6. package/controllers/authentication.controller.d.ts +5 -5
  7. package/controllers/branch.controller.d.ts +2 -2
  8. package/controllers/company-selection.controller.d.ts +4 -4
  9. package/controllers/company.controller.d.ts +2 -2
  10. package/controllers/email-verification.controller.d.ts +6 -6
  11. package/controllers/index.d.ts +9 -7
  12. package/controllers/social-auth-config.controller.d.ts +22 -0
  13. package/controllers/social-auth.controller.d.ts +11 -0
  14. package/controllers/user-permission.controller.d.ts +5 -4
  15. package/controllers/user.controller.d.ts +7 -7
  16. package/docs/auth-swagger.config.d.ts +2 -2
  17. package/docs/index.d.ts +1 -1
  18. package/dtos/index.d.ts +6 -5
  19. package/dtos/social-auth.dto.d.ts +42 -0
  20. package/entities/company-branch.entity.d.ts +1 -1
  21. package/entities/company.entity.d.ts +1 -1
  22. package/entities/index.d.ts +15 -13
  23. package/entities/pending-registration.entity.d.ts +1 -1
  24. package/entities/social-auth-config.entity.d.ts +9 -0
  25. package/entities/user-company-permission.entity.d.ts +4 -4
  26. package/enums/index.d.ts +2 -1
  27. package/enums/social-provider-type.enum.d.ts +6 -0
  28. package/fesm/118.js +1230 -0
  29. package/fesm/120.js +2197 -0
  30. package/fesm/24.js +4389 -0
  31. package/fesm/370.js +1163 -0
  32. package/fesm/446.js +877 -0
  33. package/fesm/chunks/117.js +69 -0
  34. package/fesm/config/index.js +244 -3
  35. package/fesm/controllers/index.js +27 -7
  36. package/fesm/docs/index.js +479 -1
  37. package/fesm/dtos/index.js +123 -5
  38. package/fesm/entities/index.js +68 -19
  39. package/fesm/enums/index.js +53 -1
  40. package/fesm/helpers/index.js +115 -2
  41. package/fesm/index.js +1437 -12
  42. package/fesm/interceptors/index.js +508 -2
  43. package/fesm/interfaces/index.js +75 -7
  44. package/fesm/modules/index.js +546 -1
  45. package/fesm/runtime.js +134 -0
  46. package/fesm/services/index.js +67 -9
  47. package/helpers/auth-response.mapper.d.ts +3 -3
  48. package/helpers/index.d.ts +2 -2
  49. package/helpers/token.helper.d.ts +2 -2
  50. package/index.d.ts +13 -12
  51. package/interceptors/clear-token.interceptor.d.ts +2 -2
  52. package/interceptors/index.d.ts +2 -2
  53. package/interceptors/set-token.interceptor.d.ts +2 -2
  54. package/interfaces/auth-module-options.interface.d.ts +3 -3
  55. package/interfaces/authentication.interface.d.ts +3 -3
  56. package/interfaces/company-branch.interface.d.ts +2 -2
  57. package/interfaces/company.interface.d.ts +1 -1
  58. package/interfaces/index.d.ts +8 -7
  59. package/interfaces/social-auth.interface.d.ts +43 -0
  60. package/interfaces/user-enricher.interface.d.ts +3 -3
  61. package/modules/auth.module.d.ts +4 -4
  62. package/modules/index.d.ts +1 -1
  63. package/package.json +32 -39
  64. package/providers/facebook.social-provider.d.ts +10 -0
  65. package/providers/google.social-provider.d.ts +10 -0
  66. package/providers/index.d.ts +1 -0
  67. package/providers/linkedin.social-provider.d.ts +10 -0
  68. package/providers/microsoft.social-provider.d.ts +10 -0
  69. package/providers/oauth-http.util.d.ts +10 -0
  70. package/providers/social-provider.registry.d.ts +3 -0
  71. package/services/auth-config.service.d.ts +4 -3
  72. package/services/auth-datasource.provider.d.ts +4 -3
  73. package/services/auth-email.service.d.ts +3 -3
  74. package/services/authentication.service.d.ts +15 -11
  75. package/services/branch.service.d.ts +7 -7
  76. package/services/company.service.d.ts +6 -6
  77. package/services/index.d.ts +11 -9
  78. package/services/social-auth-config.service.d.ts +21 -0
  79. package/services/social-auth.service.d.ts +24 -0
  80. package/services/user-permission.service.d.ts +8 -4
  81. package/services/user.service.d.ts +7 -7
  82. package/strategies/jwt.strategy.d.ts +4 -4
  83. package/validators/password.validator.d.ts +1 -1
  84. package/cjs/config/auth.constants.js +0 -41
  85. package/cjs/config/event-actions.js +0 -45
  86. package/cjs/config/index.js +0 -20
  87. package/cjs/config/message-keys.js +0 -108
  88. package/cjs/controllers/authentication.controller.js +0 -427
  89. package/cjs/controllers/authentication.controller.spec.js +0 -219
  90. package/cjs/controllers/branch.controller.js +0 -102
  91. package/cjs/controllers/branch.controller.spec.js +0 -134
  92. package/cjs/controllers/company-selection.controller.js +0 -198
  93. package/cjs/controllers/company-selection.controller.spec.js +0 -84
  94. package/cjs/controllers/company.controller.js +0 -102
  95. package/cjs/controllers/company.controller.spec.js +0 -131
  96. package/cjs/controllers/email-verification.controller.js +0 -224
  97. package/cjs/controllers/email-verification.controller.spec.js +0 -142
  98. package/cjs/controllers/index.js +0 -24
  99. package/cjs/controllers/user-permission.controller.js +0 -223
  100. package/cjs/controllers/user-permission.controller.spec.js +0 -138
  101. package/cjs/controllers/user.controller.js +0 -438
  102. package/cjs/controllers/user.controller.spec.js +0 -204
  103. package/cjs/docs/auth-swagger.config.js +0 -453
  104. package/cjs/docs/auth-swagger.config.spec.js +0 -130
  105. package/cjs/docs/index.js +0 -18
  106. package/cjs/dtos/authentication.dto.js +0 -755
  107. package/cjs/dtos/company-branch.dto.js +0 -294
  108. package/cjs/dtos/company.dto.js +0 -298
  109. package/cjs/dtos/index.js +0 -22
  110. package/cjs/dtos/user-permission.dto.js +0 -358
  111. package/cjs/dtos/user.dto.js +0 -413
  112. package/cjs/entities/app-user.entity.js +0 -25
  113. package/cjs/entities/company-branch.entity.js +0 -163
  114. package/cjs/entities/company.entity.js +0 -146
  115. package/cjs/entities/index.js +0 -65
  116. package/cjs/entities/index.spec.js +0 -73
  117. package/cjs/entities/pending-registration.entity.js +0 -135
  118. package/cjs/entities/user-company-permission.entity.js +0 -153
  119. package/cjs/entities/user-token.entity.js +0 -120
  120. package/cjs/enums/index.js +0 -18
  121. package/cjs/enums/user-org-permission-type.enum.js +0 -15
  122. package/cjs/helpers/auth-response.mapper.js +0 -46
  123. package/cjs/helpers/auth-response.mapper.spec.js +0 -139
  124. package/cjs/helpers/index.js +0 -19
  125. package/cjs/helpers/token.helper.js +0 -58
  126. package/cjs/helpers/token.helper.spec.js +0 -86
  127. package/cjs/index.js +0 -29
  128. package/cjs/interceptors/clear-token.interceptor.js +0 -73
  129. package/cjs/interceptors/clear-token.interceptor.spec.js +0 -107
  130. package/cjs/interceptors/index.js +0 -19
  131. package/cjs/interceptors/set-token.interceptor.js +0 -107
  132. package/cjs/interceptors/set-token.interceptor.spec.js +0 -165
  133. package/cjs/interfaces/auth-email-provider.interface.js +0 -45
  134. package/cjs/interfaces/auth-module-options.interface.js +0 -4
  135. package/cjs/interfaces/authentication.interface.js +0 -4
  136. package/cjs/interfaces/company-branch.interface.js +0 -4
  137. package/cjs/interfaces/company.interface.js +0 -4
  138. package/cjs/interfaces/index.js +0 -24
  139. package/cjs/interfaces/user-enricher.interface.js +0 -4
  140. package/cjs/interfaces/user.interface.js +0 -4
  141. package/cjs/modules/auth.module.js +0 -202
  142. package/cjs/modules/auth.module.spec.js +0 -243
  143. package/cjs/modules/index.js +0 -18
  144. package/cjs/services/auth-config.service.js +0 -110
  145. package/cjs/services/auth-config.service.spec.js +0 -97
  146. package/cjs/services/auth-datasource.provider.js +0 -134
  147. package/cjs/services/auth-datasource.provider.spec.js +0 -161
  148. package/cjs/services/auth-email.service.js +0 -539
  149. package/cjs/services/auth-email.service.spec.js +0 -456
  150. package/cjs/services/authentication.service.js +0 -1173
  151. package/cjs/services/authentication.service.spec.js +0 -962
  152. package/cjs/services/branch.service.js +0 -153
  153. package/cjs/services/branch.service.spec.js +0 -169
  154. package/cjs/services/company-selection-session.service.js +0 -121
  155. package/cjs/services/company-selection-session.service.spec.js +0 -90
  156. package/cjs/services/company.service.js +0 -140
  157. package/cjs/services/company.service.spec.js +0 -127
  158. package/cjs/services/index.js +0 -26
  159. package/cjs/services/user-permission.service.js +0 -236
  160. package/cjs/services/user-permission.service.spec.js +0 -254
  161. package/cjs/services/user.service.js +0 -671
  162. package/cjs/services/user.service.spec.js +0 -718
  163. package/cjs/strategies/jwt.strategy.js +0 -140
  164. package/cjs/strategies/jwt.strategy.spec.js +0 -166
  165. package/cjs/validators/password.validator.js +0 -45
  166. package/cjs/validators/password.validator.spec.js +0 -161
  167. package/fesm/config/auth.constants.js +0 -11
  168. package/fesm/config/event-actions.js +0 -24
  169. package/fesm/config/message-keys.js +0 -78
  170. package/fesm/controllers/authentication.controller.js +0 -417
  171. package/fesm/controllers/authentication.controller.spec.js +0 -215
  172. package/fesm/controllers/branch.controller.js +0 -92
  173. package/fesm/controllers/branch.controller.spec.js +0 -130
  174. package/fesm/controllers/company-selection.controller.js +0 -188
  175. package/fesm/controllers/company-selection.controller.spec.js +0 -80
  176. package/fesm/controllers/company.controller.js +0 -92
  177. package/fesm/controllers/company.controller.spec.js +0 -127
  178. package/fesm/controllers/email-verification.controller.js +0 -214
  179. package/fesm/controllers/email-verification.controller.spec.js +0 -138
  180. package/fesm/controllers/user-permission.controller.js +0 -213
  181. package/fesm/controllers/user-permission.controller.spec.js +0 -134
  182. package/fesm/controllers/user.controller.js +0 -428
  183. package/fesm/controllers/user.controller.spec.js +0 -200
  184. package/fesm/docs/auth-swagger.config.js +0 -446
  185. package/fesm/docs/auth-swagger.config.spec.js +0 -126
  186. package/fesm/dtos/authentication.dto.js +0 -683
  187. package/fesm/dtos/company-branch.dto.js +0 -279
  188. package/fesm/dtos/company.dto.js +0 -283
  189. package/fesm/dtos/user-permission.dto.js +0 -339
  190. package/fesm/dtos/user.dto.js +0 -391
  191. package/fesm/entities/app-user.entity.js +0 -15
  192. package/fesm/entities/company-branch.entity.js +0 -153
  193. package/fesm/entities/company.entity.js +0 -136
  194. package/fesm/entities/index.spec.js +0 -69
  195. package/fesm/entities/pending-registration.entity.js +0 -125
  196. package/fesm/entities/user-company-permission.entity.js +0 -136
  197. package/fesm/entities/user-token.entity.js +0 -104
  198. package/fesm/enums/user-org-permission-type.enum.js +0 -5
  199. package/fesm/helpers/auth-response.mapper.js +0 -25
  200. package/fesm/helpers/auth-response.mapper.spec.js +0 -135
  201. package/fesm/helpers/token.helper.js +0 -40
  202. package/fesm/helpers/token.helper.spec.js +0 -82
  203. package/fesm/interceptors/clear-token.interceptor.js +0 -63
  204. package/fesm/interceptors/clear-token.interceptor.spec.js +0 -103
  205. package/fesm/interceptors/set-token.interceptor.js +0 -98
  206. package/fesm/interceptors/set-token.interceptor.spec.js +0 -161
  207. package/fesm/interfaces/auth-email-provider.interface.js +0 -38
  208. package/fesm/interfaces/auth-module-options.interface.js +0 -3
  209. package/fesm/interfaces/authentication.interface.js +0 -1
  210. package/fesm/interfaces/company-branch.interface.js +0 -1
  211. package/fesm/interfaces/company.interface.js +0 -1
  212. package/fesm/interfaces/user-enricher.interface.js +0 -4
  213. package/fesm/interfaces/user.interface.js +0 -1
  214. package/fesm/modules/auth.module.js +0 -192
  215. package/fesm/modules/auth.module.spec.js +0 -239
  216. package/fesm/services/auth-config.service.js +0 -100
  217. package/fesm/services/auth-config.service.spec.js +0 -93
  218. package/fesm/services/auth-datasource.provider.js +0 -83
  219. package/fesm/services/auth-datasource.provider.spec.js +0 -157
  220. package/fesm/services/auth-email.service.js +0 -488
  221. package/fesm/services/auth-email.service.spec.js +0 -411
  222. package/fesm/services/authentication.service.js +0 -1122
  223. package/fesm/services/authentication.service.spec.js +0 -917
  224. package/fesm/services/branch.service.js +0 -143
  225. package/fesm/services/branch.service.spec.js +0 -165
  226. package/fesm/services/company-selection-session.service.js +0 -111
  227. package/fesm/services/company-selection-session.service.spec.js +0 -86
  228. package/fesm/services/company.service.js +0 -130
  229. package/fesm/services/company.service.spec.js +0 -123
  230. package/fesm/services/user-permission.service.js +0 -226
  231. package/fesm/services/user-permission.service.spec.js +0 -250
  232. package/fesm/services/user.service.js +0 -620
  233. package/fesm/services/user.service.spec.js +0 -673
  234. package/fesm/strategies/jwt.strategy.js +0 -130
  235. package/fesm/strategies/jwt.strategy.spec.js +0 -162
  236. package/fesm/validators/password.validator.js +0 -48
  237. package/fesm/validators/password.validator.spec.js +0 -157
@@ -1,1122 +0,0 @@
1
- function _define_property(obj, key, value) {
2
- if (key in obj) {
3
- Object.defineProperty(obj, key, {
4
- value: value,
5
- enumerable: true,
6
- configurable: true,
7
- writable: true
8
- });
9
- } else {
10
- obj[key] = value;
11
- }
12
- return obj;
13
- }
14
- function _ts_decorate(decorators, target, key, desc) {
15
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
16
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
17
- else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
18
- return c > 3 && r && Object.defineProperty(target, key, r), r;
19
- }
20
- function _ts_metadata(k, v) {
21
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
22
- }
23
- function _ts_param(paramIndex, decorator) {
24
- return function(target, key) {
25
- decorator(target, key, paramIndex);
26
- };
27
- }
28
- import { LogAction } from '@flusys/nestjs-shared';
29
- import { HybridCache, publishDomainEvent } from '@flusys/nestjs-shared/classes';
30
- import { SYSTEM_MESSAGES } from '@flusys/nestjs-shared/constants';
31
- import { NotificationType } from '@flusys/nestjs-shared/enums';
32
- import { INotificationAdapter, NOTIFICATION_ADAPTER } from '@flusys/nestjs-shared/interfaces';
33
- import { generateUniqueSlug } from '@flusys/nestjs-shared/utils';
34
- import { BadRequestException, ForbiddenException, Inject, Injectable, InternalServerErrorException, NotFoundException, Optional, Scope, UnauthorizedException } from '@nestjs/common';
35
- import { JwtService } from '@nestjs/jwt';
36
- import * as bcrypt from 'bcrypt';
37
- import { AUTH_EVENT_ACTIONS, AUTH_EVENT_ENTITIES, AUTH_EVENT_MODULE, AUTH_MESSAGES, BCRYPT_SALT_ROUNDS, EMAIL_VERIFICATION_MESSAGES, TOKEN_REVOKED_PREFIX, USER_ENRICHER, USER_MESSAGES } from '../config';
38
- import { RegistrationDto } from '../dtos/authentication.dto';
39
- import { AppUser } from '../entities/app-user.entity';
40
- import { CompanyBranch } from '../entities/company-branch.entity';
41
- import { Company } from '../entities/company.entity';
42
- import { PendingRegistration } from '../entities/pending-registration.entity';
43
- import { UserCompanyPermission } from '../entities/user-company-permission.entity';
44
- import { PermissionType } from '../enums';
45
- import { generateTokens, parseExpiryToMs, toBranchInfo, toCompanyInfo, toUserInfo } from '../helpers';
46
- import { IUserEnricher } from '../interfaces/user-enricher.interface';
47
- import { AuthConfigService } from './auth-config.service';
48
- import { AuthDataSourceProvider } from './auth-datasource.provider';
49
- import { AuthEmailService } from './auth-email.service';
50
- import { CompanySelectionSessionService } from './company-selection-session.service';
51
- export class AuthenticationService {
52
- isCompanyFeatureEnabled() {
53
- return this.dataSourceProvider?.isCompanyFeatureEnabled() ?? this.authConfig.isCompanyFeatureEnabled();
54
- }
55
- isEmailVerificationEnabled() {
56
- const featureEnabled = this.dataSourceProvider?.isEmailVerificationEnabled() ?? this.authConfig.isEmailVerificationEnabled();
57
- const providerAvailable = this.authEmailService?.isEmailEnabled() ?? false;
58
- return featureEnabled && providerAvailable;
59
- }
60
- async getUserRepository() {
61
- if (!this.dataSourceProvider) {
62
- throw new InternalServerErrorException({
63
- message: 'User repository not available',
64
- messageKey: SYSTEM_MESSAGES.REPOSITORY_NOT_AVAILABLE,
65
- messageVariables: {
66
- entity: 'AppUser'
67
- }
68
- });
69
- }
70
- return this.dataSourceProvider.getRepository(AppUser);
71
- }
72
- async getCompanyScopedRepository(entity) {
73
- if (!this.isCompanyFeatureEnabled() || !this.dataSourceProvider) return null;
74
- return this.dataSourceProvider.getRepository(entity);
75
- }
76
- async login(email, password) {
77
- if (this.isEmailVerificationEnabled() && await this.authEmailService.hasPendingRegistration(email)) {
78
- return {
79
- requiresEmailVerification: true,
80
- email,
81
- message: 'Please verify your email address to complete registration.',
82
- messageKey: EMAIL_VERIFICATION_MESSAGES.VERIFICATION_SENT
83
- };
84
- }
85
- const user = await this.validateUser(email, password);
86
- if (!user.isActive) {
87
- throw new ForbiddenException({
88
- message: 'User account is deactivated',
89
- messageKey: AUTH_MESSAGES.LOGIN_ACCOUNT_DEACTIVATED
90
- });
91
- }
92
- if (this.isEmailVerificationEnabled() && !user.emailVerified) {
93
- return {
94
- requiresEmailVerification: true,
95
- email: user.email,
96
- message: 'Please verify your email address before logging in.',
97
- messageKey: AUTH_MESSAGES.LOGIN_EMAIL_NOT_VERIFIED
98
- };
99
- }
100
- if (!this.isCompanyFeatureEnabled()) {
101
- return this.generateLoginResponse(user);
102
- }
103
- return await this.handleCompanyBasedLogin(user);
104
- }
105
- async handleCompanyBasedLogin(user) {
106
- const permissionRepository = await this.getCompanyScopedRepository(UserCompanyPermission);
107
- const branchRepository = await this.getCompanyScopedRepository(CompanyBranch);
108
- if (!permissionRepository || !branchRepository) {
109
- return this.generateLoginResponse(user);
110
- }
111
- const companyPermissions = await permissionRepository.find({
112
- where: {
113
- userId: user.id,
114
- permissionType: PermissionType.COMPANY
115
- }
116
- });
117
- const companyRepository = await this.getCompanyScopedRepository(Company);
118
- if (!companyRepository) {
119
- return this.generateLoginResponse(user);
120
- }
121
- const companyIds = companyPermissions.map((p)=>p.targetId);
122
- const companies = companyIds.length > 0 ? await companyRepository.createQueryBuilder('c').where('c.id IN (:...ids)', {
123
- ids: companyIds
124
- }).andWhere('c.is_active = :active', {
125
- active: true
126
- }).getMany() : [];
127
- if (companies.length === 0) {
128
- return this.generateLoginResponse(user);
129
- }
130
- const branchPermissions = await permissionRepository.find({
131
- where: {
132
- userId: user.id,
133
- permissionType: PermissionType.BRANCH
134
- }
135
- });
136
- const branchIds = branchPermissions.map((p)=>p.targetId);
137
- const branches = branchIds.length > 0 ? await branchRepository.createQueryBuilder('b').leftJoinAndSelect('b.company', 'company').where('b.id IN (:...ids)', {
138
- ids: branchIds
139
- }).andWhere('b.is_active = :active', {
140
- active: true
141
- }).getMany() : [];
142
- if (companies.length === 1 && branches.length === 1) {
143
- return this.generateLoginResponseWithCompany(user, companies[0], branches[0]);
144
- }
145
- return await this.generateCompanySelectionResponse(user, companies, branches);
146
- }
147
- async register(dto, verifyUrlBase) {
148
- const userRepository = await this.getUserRepository();
149
- const existingUser = await userRepository.findOne({
150
- where: {
151
- email: dto.email
152
- }
153
- });
154
- if (existingUser && this.isCompanyFeatureEnabled()) {
155
- return await this.handleExistingUserCompanyRegistration(existingUser, dto);
156
- }
157
- if (existingUser) {
158
- throw new BadRequestException({
159
- message: 'Registration failed due to email exists. Please try again or contact support.',
160
- messageKey: AUTH_MESSAGES.REGISTER_EMAIL_EXISTS
161
- });
162
- }
163
- if (this.isEmailVerificationEnabled() && verifyUrlBase) {
164
- const companyData = this.isCompanyFeatureEnabled() ? {
165
- companySlug: dto.companySlug,
166
- branchSlug: dto.branchSlug,
167
- newCompanyName: dto.newCompanyName,
168
- newCompanyPhone: dto.newCompanyPhone,
169
- newCompanyAddress: dto.newCompanyAddress
170
- } : undefined;
171
- const result = await this.authEmailService.createPendingRegistration({
172
- email: dto.email,
173
- name: dto.name,
174
- phone: dto.phone,
175
- password: dto.password,
176
- companyData,
177
- additionalFields: dto.additionalFields,
178
- verifyUrlBase
179
- });
180
- return {
181
- requiresEmailVerification: true,
182
- message: result.message,
183
- messageKey: EMAIL_VERIFICATION_MESSAGES.VERIFICATION_SENT
184
- };
185
- }
186
- return await this.createUserDirectly(dto);
187
- }
188
- async handleExistingUserCompanyRegistration(existingUser, dto) {
189
- if (!dto.companySlug && !dto.newCompanyName) {
190
- throw new BadRequestException({
191
- message: 'Email already registered. Please login or provide a company to join/create.',
192
- messageKey: AUTH_MESSAGES.REGISTER_EMAIL_EXISTS
193
- });
194
- }
195
- const permissionRepository = await this.getCompanyScopedRepository(UserCompanyPermission);
196
- const companyRepository = await this.getCompanyScopedRepository(Company);
197
- if (!permissionRepository || !companyRepository) {
198
- throw new BadRequestException({
199
- message: 'Company feature repositories not available',
200
- messageKey: SYSTEM_MESSAGES.REPOSITORY_NOT_AVAILABLE,
201
- messageVariables: {
202
- entity: 'Company feature'
203
- }
204
- });
205
- }
206
- if (dto.companySlug) {
207
- const company = await companyRepository.findOne({
208
- where: {
209
- slug: dto.companySlug,
210
- isActive: true
211
- }
212
- });
213
- if (company) {
214
- const existingPermission = await permissionRepository.findOne({
215
- where: {
216
- userId: existingUser.id,
217
- permissionType: PermissionType.COMPANY,
218
- targetId: company.id
219
- }
220
- });
221
- if (existingPermission) {
222
- throw new BadRequestException({
223
- message: 'You are already assigned to this company. Please login.',
224
- messageKey: AUTH_MESSAGES.REGISTER_COMPANY_ALREADY_ASSIGNED
225
- });
226
- }
227
- }
228
- }
229
- return await this.processCompanyRegistration(existingUser, dto, true);
230
- }
231
- async createUserDirectly(dto) {
232
- if (!this.dataSourceProvider) {
233
- throw new BadRequestException({
234
- message: 'Data source not available',
235
- messageKey: SYSTEM_MESSAGES.DATASOURCE_NOT_AVAILABLE
236
- });
237
- }
238
- const dataSource = await this.dataSourceProvider.getDataSource();
239
- const queryRunner = dataSource.createQueryRunner();
240
- await queryRunner.connect();
241
- await queryRunner.startTransaction();
242
- try {
243
- const hashedPassword = await bcrypt.hash(dto.password, BCRYPT_SALT_ROUNDS);
244
- const user = queryRunner.manager.create(AppUser, {
245
- name: dto.name,
246
- email: dto.email,
247
- phone: dto.phone,
248
- password: hashedPassword,
249
- isActive: true,
250
- emailVerified: false,
251
- phoneVerified: false
252
- });
253
- await queryRunner.manager.save(AppUser, user);
254
- if (this.userEnricher?.onUserCreated) {
255
- await this.userEnricher.onUserCreated(user.id, dto.additionalFields ?? null, queryRunner);
256
- }
257
- await queryRunner.commitTransaction();
258
- if (!this.isCompanyFeatureEnabled()) {
259
- return this.generateRegistrationResponse(user);
260
- }
261
- return await this.processCompanyRegistration(user, dto);
262
- } catch (error) {
263
- await queryRunner.rollbackTransaction();
264
- if (error instanceof BadRequestException) {
265
- throw error;
266
- }
267
- throw new BadRequestException({
268
- message: 'Registration failed. Please try again.',
269
- messageKey: AUTH_MESSAGES.REGISTER_FAILED
270
- });
271
- } finally{
272
- await queryRunner.release();
273
- }
274
- }
275
- async createUserFromPendingRegistration(pending) {
276
- if (!this.dataSourceProvider) {
277
- throw new BadRequestException({
278
- message: 'Data source not available',
279
- messageKey: SYSTEM_MESSAGES.DATASOURCE_NOT_AVAILABLE
280
- });
281
- }
282
- const dataSource = await this.dataSourceProvider.getDataSource();
283
- const queryRunner = dataSource.createQueryRunner();
284
- await queryRunner.connect();
285
- await queryRunner.startTransaction();
286
- try {
287
- const existingUser = await queryRunner.manager.findOne(AppUser, {
288
- where: {
289
- email: pending.email
290
- }
291
- });
292
- if (existingUser) {
293
- throw new BadRequestException({
294
- message: 'This email has already been registered.',
295
- messageKey: AUTH_MESSAGES.REGISTER_EMAIL_EXISTS
296
- });
297
- }
298
- const user = queryRunner.manager.create(AppUser, {
299
- name: pending.name,
300
- email: pending.email,
301
- phone: pending.phone,
302
- password: pending.passwordHash,
303
- isActive: true,
304
- emailVerified: true,
305
- phoneVerified: false
306
- });
307
- await queryRunner.manager.save(AppUser, user);
308
- if (this.userEnricher?.onUserCreated) {
309
- await this.userEnricher.onUserCreated(user.id, pending.additionalFields ?? null, queryRunner);
310
- }
311
- await queryRunner.commitTransaction();
312
- if (this.isCompanyFeatureEnabled() && pending.companyData) {
313
- return await this.processCompanyRegistration(user, pending.companyData);
314
- }
315
- return this.generateRegistrationResponse(user);
316
- } catch (error) {
317
- await queryRunner.rollbackTransaction();
318
- if (error instanceof BadRequestException) {
319
- throw error;
320
- }
321
- throw new BadRequestException({
322
- message: 'Registration failed. Please try again.',
323
- messageKey: AUTH_MESSAGES.REGISTER_FAILED
324
- });
325
- } finally{
326
- await queryRunner.release();
327
- }
328
- }
329
- async processCompanyRegistration(user, data, throwOnUnavailable = false) {
330
- const companyRepository = await this.getCompanyScopedRepository(Company);
331
- const branchRepository = await this.getCompanyScopedRepository(CompanyBranch);
332
- const permissionRepository = await this.getCompanyScopedRepository(UserCompanyPermission);
333
- if (!companyRepository || !branchRepository || !permissionRepository) {
334
- if (throwOnUnavailable) throw new BadRequestException({
335
- message: 'Company feature repositories not available',
336
- messageKey: SYSTEM_MESSAGES.REPOSITORY_NOT_AVAILABLE,
337
- messageVariables: {
338
- entity: 'Company feature'
339
- }
340
- });
341
- return this.generateRegistrationResponse(user);
342
- }
343
- const { company, branch } = await this.findOrCreateCompanyAndBranch(data, companyRepository, branchRepository);
344
- if (company) {
345
- await this.assignUserPermissions(user.id, company.id, branch?.id, permissionRepository);
346
- return this.generateRegistrationResponseWithCompany(user, company, branch ?? undefined);
347
- }
348
- return this.generateRegistrationResponse(user);
349
- }
350
- async findOrCreateCompanyAndBranch(data, companyRepo, branchRepo) {
351
- if (data.companySlug) {
352
- const company = await companyRepo.findOne({
353
- where: {
354
- slug: data.companySlug,
355
- isActive: true
356
- }
357
- });
358
- if (!company) throw new BadRequestException({
359
- message: 'Company not found or inactive',
360
- messageKey: AUTH_MESSAGES.COMPANY_NOT_FOUND
361
- });
362
- const branch = data.branchSlug ? await branchRepo.findOne({
363
- where: {
364
- slug: data.branchSlug,
365
- companyId: company.id,
366
- isActive: true
367
- }
368
- }) : await branchRepo.findOne({
369
- where: {
370
- companyId: company.id,
371
- isActive: true
372
- },
373
- order: {
374
- serial: 'ASC',
375
- createdAt: 'ASC'
376
- }
377
- });
378
- if (data.branchSlug && !branch) throw new BadRequestException({
379
- message: 'Branch not found or inactive',
380
- messageKey: AUTH_MESSAGES.BRANCH_NOT_FOUND
381
- });
382
- return {
383
- company,
384
- branch
385
- };
386
- }
387
- if (data.newCompanyName) {
388
- const slug = await generateUniqueSlug(data.newCompanyName, async (baseSlug)=>{
389
- const rows = await companyRepo.createQueryBuilder('c').select('c.slug').where('c.slug = :base OR c.slug LIKE :pattern', {
390
- base: baseSlug,
391
- pattern: `${baseSlug}-%`
392
- }).getMany();
393
- return rows.map((r)=>r.slug);
394
- });
395
- const company = companyRepo.create({
396
- name: data.newCompanyName,
397
- slug,
398
- phone: data.newCompanyPhone,
399
- address: data.newCompanyAddress,
400
- isActive: true
401
- });
402
- await companyRepo.save(company);
403
- const branch = branchRepo.create({
404
- name: 'Main Branch',
405
- slug: 'main-branch',
406
- companyId: company.id,
407
- isActive: true
408
- });
409
- await branchRepo.save(branch);
410
- return {
411
- company,
412
- branch
413
- };
414
- }
415
- return {
416
- company: null,
417
- branch: null
418
- };
419
- }
420
- async assignUserPermissions(userId, companyId, branchId, permissionRepo) {
421
- await permissionRepo.save(permissionRepo.create({
422
- userId,
423
- permissionType: PermissionType.COMPANY,
424
- targetId: companyId
425
- }));
426
- if (branchId) {
427
- await permissionRepo.save(permissionRepo.create({
428
- userId,
429
- permissionType: PermissionType.BRANCH,
430
- targetId: branchId
431
- }));
432
- }
433
- }
434
- async select(sessionId, companyId, branchId) {
435
- this.ensureCompanyFeatureEnabled();
436
- if (!this.sessionService) {
437
- throw new BadRequestException({
438
- message: 'Session service not available',
439
- messageKey: AUTH_MESSAGES.SESSION_NOT_AVAILABLE
440
- });
441
- }
442
- const session = await this.sessionService.consumeSession(sessionId);
443
- if (!session) {
444
- throw new UnauthorizedException({
445
- message: 'Invalid or expired session',
446
- messageKey: AUTH_MESSAGES.SESSION_INVALID
447
- });
448
- }
449
- return await this.validateAndLoginWithCompany(session.userId, companyId, branchId);
450
- }
451
- async switchCompany(userId, companyId, branchId) {
452
- this.ensureCompanyFeatureEnabled();
453
- return await this.validateAndLoginWithCompany(userId, companyId, branchId);
454
- }
455
- async validateAndLoginWithCompany(userId, companyId, branchId) {
456
- const userRepository = await this.getUserRepository();
457
- const user = await userRepository.findOne({
458
- where: {
459
- id: userId
460
- }
461
- });
462
- if (!user) {
463
- throw new NotFoundException({
464
- message: 'User not found',
465
- messageKey: USER_MESSAGES.NOT_FOUND
466
- });
467
- }
468
- const permissionRepository = await this.getCompanyScopedRepository(UserCompanyPermission);
469
- const companyRepository = await this.getCompanyScopedRepository(Company);
470
- const branchRepository = await this.getCompanyScopedRepository(CompanyBranch);
471
- if (!permissionRepository || !companyRepository || !branchRepository) {
472
- throw new BadRequestException({
473
- message: 'Repositories not available',
474
- messageKey: SYSTEM_MESSAGES.REPOSITORY_NOT_AVAILABLE,
475
- messageVariables: {
476
- entity: 'Some'
477
- }
478
- });
479
- }
480
- const hasCompanyAccess = await permissionRepository.findOne({
481
- where: {
482
- userId,
483
- permissionType: PermissionType.COMPANY,
484
- targetId: companyId
485
- }
486
- });
487
- if (!hasCompanyAccess) {
488
- throw new ForbiddenException({
489
- message: 'No access to this company',
490
- messageKey: AUTH_MESSAGES.COMPANY_NO_ACCESS
491
- });
492
- }
493
- const company = await companyRepository.findOne({
494
- where: {
495
- id: companyId,
496
- isActive: true
497
- }
498
- });
499
- if (!company) {
500
- throw new NotFoundException({
501
- message: 'Company not found or inactive',
502
- messageKey: AUTH_MESSAGES.COMPANY_NOT_FOUND
503
- });
504
- }
505
- const hasBranchAccess = await permissionRepository.findOne({
506
- where: {
507
- userId,
508
- permissionType: PermissionType.BRANCH,
509
- targetId: branchId
510
- }
511
- });
512
- if (!hasBranchAccess) {
513
- throw new ForbiddenException({
514
- message: 'No access to this branch',
515
- messageKey: AUTH_MESSAGES.BRANCH_NO_ACCESS
516
- });
517
- }
518
- const branch = await branchRepository.findOne({
519
- where: {
520
- id: branchId,
521
- companyId,
522
- isActive: true
523
- }
524
- });
525
- if (!branch) {
526
- throw new NotFoundException({
527
- message: 'Branch not found or inactive',
528
- messageKey: AUTH_MESSAGES.BRANCH_NOT_FOUND
529
- });
530
- }
531
- const response = this.generateLoginResponseWithCompany(user, company, branch);
532
- this.publishAuthEvent(AUTH_EVENT_ENTITIES.SESSION, AUTH_EVENT_ACTIONS.COMPANY_SWITCHED, user, {
533
- companyId: company.id,
534
- branchId: branch.id
535
- });
536
- return response;
537
- }
538
- async refreshToken(refreshToken) {
539
- try {
540
- const payload = this.jwtService.verify(refreshToken, {
541
- secret: this.authConfig.getRefreshTokenSecret(),
542
- algorithms: [
543
- 'HS256'
544
- ]
545
- });
546
- if (await this.isTokenRevoked(payload.id, payload.iat)) {
547
- throw new UnauthorizedException({
548
- message: 'Token has been revoked',
549
- messageKey: AUTH_MESSAGES.TOKEN_REVOKED
550
- });
551
- }
552
- const userRepository = await this.getUserRepository();
553
- const user = await userRepository.findOne({
554
- where: {
555
- id: payload.id
556
- }
557
- });
558
- if (!user || !user.isActive) {
559
- throw new UnauthorizedException({
560
- message: 'Invalid refresh token',
561
- messageKey: AUTH_MESSAGES.TOKEN_INVALID
562
- });
563
- }
564
- if (payload.companyId) {
565
- const companyRepository = await this.getCompanyScopedRepository(Company);
566
- const permissionRepository = await this.getCompanyScopedRepository(UserCompanyPermission);
567
- if (companyRepository) {
568
- const company = await companyRepository.findOne({
569
- where: {
570
- id: payload.companyId,
571
- isActive: true
572
- }
573
- });
574
- if (!company) {
575
- throw new UnauthorizedException({
576
- message: 'Company not found or inactive',
577
- messageKey: AUTH_MESSAGES.COMPANY_NOT_FOUND
578
- });
579
- }
580
- }
581
- if (permissionRepository) {
582
- const hasCompanyAccess = await permissionRepository.findOne({
583
- where: {
584
- userId: user.id,
585
- permissionType: PermissionType.COMPANY,
586
- targetId: payload.companyId
587
- }
588
- });
589
- if (!hasCompanyAccess) {
590
- throw new UnauthorizedException({
591
- message: 'No access to this company',
592
- messageKey: AUTH_MESSAGES.COMPANY_NO_ACCESS
593
- });
594
- }
595
- }
596
- if (payload.branchId) {
597
- const branchRepository = await this.getCompanyScopedRepository(CompanyBranch);
598
- if (branchRepository) {
599
- const branch = await branchRepository.findOne({
600
- where: {
601
- id: payload.branchId,
602
- companyId: payload.companyId,
603
- isActive: true
604
- }
605
- });
606
- if (!branch) {
607
- throw new UnauthorizedException({
608
- message: 'Branch not found or inactive',
609
- messageKey: AUTH_MESSAGES.BRANCH_NOT_FOUND
610
- });
611
- }
612
- }
613
- if (permissionRepository) {
614
- const hasBranchAccess = await permissionRepository.findOne({
615
- where: {
616
- userId: user.id,
617
- permissionType: PermissionType.BRANCH,
618
- targetId: payload.branchId
619
- }
620
- });
621
- if (!hasBranchAccess) {
622
- throw new UnauthorizedException({
623
- message: 'No access to this branch',
624
- messageKey: AUTH_MESSAGES.BRANCH_NO_ACCESS
625
- });
626
- }
627
- }
628
- }
629
- }
630
- const tokens = generateTokens(this.jwtService, this.authConfig, {
631
- id: user.id,
632
- email: user.email,
633
- type: 'access',
634
- profilePictureId: user.profilePictureId ?? undefined,
635
- ...payload.companyId && {
636
- companyId: payload.companyId
637
- },
638
- ...payload.branchId && {
639
- branchId: payload.branchId
640
- }
641
- });
642
- this.publishAuthEvent(AUTH_EVENT_ENTITIES.SESSION, AUTH_EVENT_ACTIONS.TOKEN_REFRESHED, user, {
643
- companyId: payload.companyId ?? null,
644
- branchId: payload.branchId ?? null
645
- });
646
- return tokens;
647
- } catch {
648
- throw new UnauthorizedException({
649
- message: 'Invalid or expired refresh token',
650
- messageKey: AUTH_MESSAGES.TOKEN_EXPIRED
651
- });
652
- }
653
- }
654
- async changePassword(userId, currentPassword, newPassword) {
655
- const userRepository = await this.getUserRepository();
656
- const user = await userRepository.findOne({
657
- where: {
658
- id: userId
659
- }
660
- });
661
- if (!user) throw new UnauthorizedException({
662
- message: 'User not found',
663
- messageKey: USER_MESSAGES.NOT_FOUND
664
- });
665
- if (!await bcrypt.compare(currentPassword, user.password || '')) {
666
- throw new UnauthorizedException({
667
- message: 'Current password is incorrect',
668
- messageKey: AUTH_MESSAGES.PASSWORD_CHANGE_INVALID_CURRENT
669
- });
670
- }
671
- user.password = await bcrypt.hash(newPassword, BCRYPT_SALT_ROUNDS);
672
- await userRepository.save(user);
673
- this.publishAuthEvent(AUTH_EVENT_ENTITIES.USER, AUTH_EVENT_ACTIONS.PASSWORD_CHANGED, user);
674
- }
675
- async logout(userId) {
676
- if (!this.cacheManager) {
677
- throw new BadRequestException({
678
- message: 'Logout service temporarily unavailable. Please try again later.',
679
- messageKey: AUTH_MESSAGES.LOGOUT_SERVICE_UNAVAILABLE
680
- });
681
- }
682
- const revokedAt = Math.floor(Date.now() / 1000);
683
- const cacheKey = `${TOKEN_REVOKED_PREFIX}:${userId}`;
684
- const refreshTokenExpiry = this.authConfig.getRefreshTokenExpiration();
685
- const ttlMs = parseExpiryToMs(refreshTokenExpiry);
686
- await this.cacheManager.set(cacheKey, revokedAt, ttlMs);
687
- await publishDomainEvent({
688
- module: AUTH_EVENT_MODULE,
689
- entity: AUTH_EVENT_ENTITIES.SESSION,
690
- action: AUTH_EVENT_ACTIONS.LOGGED_OUT,
691
- ids: [
692
- userId
693
- ],
694
- user: {
695
- id: userId
696
- }
697
- });
698
- }
699
- async isTokenRevoked(userId, tokenIssuedAt) {
700
- if (!this.cacheManager || !tokenIssuedAt) {
701
- return false;
702
- }
703
- const cacheKey = `${TOKEN_REVOKED_PREFIX}:${userId}`;
704
- const revokedAt = await this.cacheManager.get(cacheKey);
705
- if (!revokedAt) {
706
- return false;
707
- }
708
- return tokenIssuedAt < revokedAt;
709
- }
710
- async getUserCompanies(userId) {
711
- this.ensureCompanyFeatureEnabled();
712
- const permissionRepository = await this.getCompanyScopedRepository(UserCompanyPermission);
713
- const companyRepository = await this.getCompanyScopedRepository(Company);
714
- if (!permissionRepository || !companyRepository) {
715
- throw new BadRequestException({
716
- message: 'Repositories not available',
717
- messageKey: SYSTEM_MESSAGES.REPOSITORY_NOT_AVAILABLE,
718
- messageVariables: {
719
- entity: 'Some'
720
- }
721
- });
722
- }
723
- const permissions = await permissionRepository.find({
724
- where: {
725
- userId,
726
- permissionType: PermissionType.COMPANY
727
- }
728
- });
729
- const companyIds = permissions.map((p)=>p.targetId);
730
- if (companyIds.length === 0) return [];
731
- return companyRepository.createQueryBuilder('c').where('c.id IN (:...ids)', {
732
- ids: companyIds
733
- }).andWhere('c.is_active = :active', {
734
- active: true
735
- }).orderBy('c.name', 'ASC').getMany();
736
- }
737
- async getUserBranches(userId, companyId) {
738
- this.ensureCompanyFeatureEnabled();
739
- const permissionRepository = await this.getCompanyScopedRepository(UserCompanyPermission);
740
- const branchRepository = await this.getCompanyScopedRepository(CompanyBranch);
741
- if (!permissionRepository || !branchRepository) {
742
- throw new BadRequestException({
743
- message: 'Repositories not available',
744
- messageKey: SYSTEM_MESSAGES.REPOSITORY_NOT_AVAILABLE,
745
- messageVariables: {
746
- entity: 'Some'
747
- }
748
- });
749
- }
750
- const companyPermission = await permissionRepository.findOne({
751
- where: {
752
- userId,
753
- permissionType: PermissionType.COMPANY,
754
- targetId: companyId
755
- }
756
- });
757
- if (!companyPermission) {
758
- throw new UnauthorizedException({
759
- message: 'No access to this company',
760
- messageKey: AUTH_MESSAGES.COMPANY_NO_ACCESS
761
- });
762
- }
763
- const branchPermissions = await permissionRepository.find({
764
- where: {
765
- userId,
766
- permissionType: PermissionType.BRANCH
767
- }
768
- });
769
- const branchIds = branchPermissions.map((p)=>p.targetId);
770
- if (branchIds.length === 0) return [];
771
- return branchRepository.createQueryBuilder('b').where('b.id IN (:...ids)', {
772
- ids: branchIds
773
- }).andWhere('b.company_id = :companyId', {
774
- companyId
775
- }).andWhere('b.is_active = :active', {
776
- active: true
777
- }).orderBy('b.serial', 'ASC').addOrderBy('b.name', 'ASC').getMany();
778
- }
779
- async getCompanyById(companyId) {
780
- const companyRepository = await this.getCompanyScopedRepository(Company);
781
- if (!companyRepository) {
782
- return null;
783
- }
784
- return companyRepository.findOne({
785
- where: {
786
- id: companyId
787
- }
788
- });
789
- }
790
- async getBranchById(branchId) {
791
- const branchRepository = await this.getCompanyScopedRepository(CompanyBranch);
792
- if (!branchRepository) {
793
- return null;
794
- }
795
- return branchRepository.findOne({
796
- where: {
797
- id: branchId
798
- }
799
- });
800
- }
801
- async getUserInfo(userId, companyId, branchId) {
802
- const userRepository = await this.getUserRepository();
803
- const user = await userRepository.findOne({
804
- where: {
805
- id: userId
806
- }
807
- });
808
- if (!user) throw new UnauthorizedException({
809
- message: 'User not found',
810
- messageKey: USER_MESSAGES.NOT_FOUND
811
- });
812
- const response = {
813
- user: toUserInfo(user)
814
- };
815
- if (this.isCompanyFeatureEnabled()) {
816
- if (!companyId) {
817
- throw new UnauthorizedException({
818
- message: 'Company feature is enabled but user has no company assigned.',
819
- messageKey: AUTH_MESSAGES.COMPANY_REQUIRED
820
- });
821
- }
822
- const company = await this.getCompanyById(companyId);
823
- if (!company) throw new UnauthorizedException({
824
- message: 'Company not found.',
825
- messageKey: AUTH_MESSAGES.COMPANY_NOT_FOUND
826
- });
827
- response.company = toCompanyInfo(company);
828
- if (branchId) {
829
- const branch = await this.getBranchById(branchId);
830
- if (!branch) throw new UnauthorizedException({
831
- message: 'Branch not found.',
832
- messageKey: AUTH_MESSAGES.BRANCH_NOT_FOUND
833
- });
834
- response.branch = toBranchInfo(branch);
835
- }
836
- }
837
- return response;
838
- }
839
- ensureCompanyFeatureEnabled() {
840
- if (!this.isCompanyFeatureEnabled()) {
841
- throw new BadRequestException({
842
- message: 'Company feature is not enabled',
843
- messageKey: AUTH_MESSAGES.COMPANY_FEATURE_NOT_ENABLED
844
- });
845
- }
846
- }
847
- async validateUser(email, password) {
848
- const userRepository = await this.getUserRepository();
849
- const user = await userRepository.findOne({
850
- where: {
851
- email
852
- }
853
- });
854
- if (!user || !await bcrypt.compare(password, user.password || '')) {
855
- throw new UnauthorizedException({
856
- message: 'Invalid credentials',
857
- messageKey: AUTH_MESSAGES.LOGIN_INVALID_CREDENTIALS
858
- });
859
- }
860
- user.lastLoginAt = new Date();
861
- await userRepository.save(user);
862
- return user;
863
- }
864
- generateLoginResponse(user) {
865
- const { accessToken, refreshToken } = generateTokens(this.jwtService, this.authConfig, {
866
- id: user.id,
867
- email: user.email,
868
- type: 'access'
869
- });
870
- this.sendLoginNotification(user.id);
871
- this.publishAuthEvent(AUTH_EVENT_ENTITIES.SESSION, AUTH_EVENT_ACTIONS.LOGGED_IN, user);
872
- return {
873
- accessToken,
874
- refreshToken,
875
- user: toUserInfo(user)
876
- };
877
- }
878
- generateLoginResponseWithCompany(user, company, branch) {
879
- const { accessToken, refreshToken } = generateTokens(this.jwtService, this.authConfig, {
880
- id: user.id,
881
- email: user.email,
882
- type: 'access',
883
- companyId: company.id,
884
- branchId: branch?.id
885
- });
886
- this.sendLoginNotification(user.id, company.id);
887
- this.publishAuthEvent(AUTH_EVENT_ENTITIES.SESSION, AUTH_EVENT_ACTIONS.LOGGED_IN, user, {
888
- companyId: company.id,
889
- branchId: branch?.id ?? null
890
- });
891
- return {
892
- accessToken,
893
- refreshToken,
894
- user: toUserInfo(user),
895
- company: toCompanyInfo(company),
896
- branch: branch ? toBranchInfo(branch) : undefined
897
- };
898
- }
899
- sendLoginNotification(userId, companyId) {
900
- if (!this.notificationAdapter) return;
901
- this.notificationAdapter.send({
902
- userId,
903
- title: 'Login successful',
904
- message: 'You have successfully logged in to your account.',
905
- type: NotificationType.INFO,
906
- companyId,
907
- realtime: false
908
- }).catch(()=>{
909
- // Silent failure - notification is non-critical
910
- });
911
- }
912
- async generateCompanySelectionResponse(user, companies, branches) {
913
- if (!this.sessionService) {
914
- throw new BadRequestException({
915
- message: 'Session service not available',
916
- messageKey: AUTH_MESSAGES.SESSION_NOT_AVAILABLE
917
- });
918
- }
919
- const sessionId = await this.sessionService.createSession(user.id);
920
- const companiesWithBranches = companies.map((company)=>({
921
- ...toCompanyInfo(company),
922
- isActive: company.isActive,
923
- branches: branches.filter((b)=>b.companyId === company.id).map((b)=>({
924
- ...toBranchInfo(b),
925
- isActive: b.isActive
926
- }))
927
- }));
928
- return {
929
- requiresSelection: true,
930
- sessionId,
931
- expiresAt: new Date(Date.now() + 5 * 60 * 1000),
932
- user: toUserInfo(user),
933
- companies: companiesWithBranches
934
- };
935
- }
936
- generateRegistrationResponse(user) {
937
- const response = {
938
- ...this.generateLoginResponse(user),
939
- requiresEmailVerification: false
940
- };
941
- this.publishAuthEvent(AUTH_EVENT_ENTITIES.USER, AUTH_EVENT_ACTIONS.REGISTERED, user);
942
- return response;
943
- }
944
- generateRegistrationResponseWithCompany(user, company, branch) {
945
- const response = {
946
- ...this.generateLoginResponseWithCompany(user, company, branch),
947
- requiresEmailVerification: false
948
- };
949
- this.publishAuthEvent(AUTH_EVENT_ENTITIES.USER, AUTH_EVENT_ACTIONS.REGISTERED, user, {
950
- companyId: company.id,
951
- branchId: branch?.id ?? null
952
- });
953
- return response;
954
- }
955
- /** Never awaited - a login must not wait on, or fail because of, the event bus */ publishAuthEvent(entity, action, user, metadata = {}) {
956
- void publishDomainEvent({
957
- module: AUTH_EVENT_MODULE,
958
- entity,
959
- action,
960
- ids: [
961
- user.id
962
- ],
963
- metadata: {
964
- email: user.email,
965
- ...metadata
966
- },
967
- user: {
968
- id: user.id,
969
- email: user.email
970
- }
971
- });
972
- }
973
- // NOTE: @Inject() required for bundled code - type metadata may be lost during esbuild
974
- constructor(jwtService, authConfig, cacheManager, dataSourceProvider, sessionService, authEmailService, userEnricher, notificationAdapter){
975
- _define_property(this, "jwtService", void 0);
976
- _define_property(this, "authConfig", void 0);
977
- _define_property(this, "cacheManager", void 0);
978
- _define_property(this, "dataSourceProvider", void 0);
979
- _define_property(this, "sessionService", void 0);
980
- _define_property(this, "authEmailService", void 0);
981
- _define_property(this, "userEnricher", void 0);
982
- _define_property(this, "notificationAdapter", void 0);
983
- this.jwtService = jwtService;
984
- this.authConfig = authConfig;
985
- this.cacheManager = cacheManager;
986
- this.dataSourceProvider = dataSourceProvider;
987
- this.sessionService = sessionService;
988
- this.authEmailService = authEmailService;
989
- this.userEnricher = userEnricher;
990
- this.notificationAdapter = notificationAdapter;
991
- }
992
- }
993
- _ts_decorate([
994
- LogAction({
995
- action: 'auth.login',
996
- module: 'auth',
997
- includeParams: false
998
- }),
999
- _ts_metadata("design:type", Function),
1000
- _ts_metadata("design:paramtypes", [
1001
- String,
1002
- String
1003
- ]),
1004
- _ts_metadata("design:returntype", Promise)
1005
- ], AuthenticationService.prototype, "login", null);
1006
- _ts_decorate([
1007
- LogAction({
1008
- action: 'auth.register',
1009
- module: 'auth',
1010
- includeParams: false
1011
- }),
1012
- _ts_metadata("design:type", Function),
1013
- _ts_metadata("design:paramtypes", [
1014
- typeof RegistrationDto === "undefined" ? Object : RegistrationDto,
1015
- String
1016
- ]),
1017
- _ts_metadata("design:returntype", Promise)
1018
- ], AuthenticationService.prototype, "register", null);
1019
- _ts_decorate([
1020
- LogAction({
1021
- action: 'auth.createUser',
1022
- module: 'auth',
1023
- includeParams: false
1024
- }),
1025
- _ts_metadata("design:type", Function),
1026
- _ts_metadata("design:paramtypes", [
1027
- typeof RegistrationDto === "undefined" ? Object : RegistrationDto
1028
- ]),
1029
- _ts_metadata("design:returntype", Promise)
1030
- ], AuthenticationService.prototype, "createUserDirectly", null);
1031
- _ts_decorate([
1032
- LogAction({
1033
- action: 'auth.createUserFromPending',
1034
- module: 'auth',
1035
- includeParams: false
1036
- }),
1037
- _ts_metadata("design:type", Function),
1038
- _ts_metadata("design:paramtypes", [
1039
- typeof PendingRegistration === "undefined" ? Object : PendingRegistration
1040
- ]),
1041
- _ts_metadata("design:returntype", Promise)
1042
- ], AuthenticationService.prototype, "createUserFromPendingRegistration", null);
1043
- _ts_decorate([
1044
- LogAction({
1045
- action: 'auth.companySwitch',
1046
- module: 'auth'
1047
- }),
1048
- _ts_metadata("design:type", Function),
1049
- _ts_metadata("design:paramtypes", [
1050
- String,
1051
- String,
1052
- String
1053
- ]),
1054
- _ts_metadata("design:returntype", Promise)
1055
- ], AuthenticationService.prototype, "validateAndLoginWithCompany", null);
1056
- _ts_decorate([
1057
- LogAction({
1058
- action: 'auth.refreshToken',
1059
- module: 'auth',
1060
- includeParams: false
1061
- }),
1062
- _ts_metadata("design:type", Function),
1063
- _ts_metadata("design:paramtypes", [
1064
- String
1065
- ]),
1066
- _ts_metadata("design:returntype", Promise)
1067
- ], AuthenticationService.prototype, "refreshToken", null);
1068
- _ts_decorate([
1069
- LogAction({
1070
- action: 'auth.changePassword',
1071
- module: 'auth',
1072
- includeParams: false
1073
- }),
1074
- _ts_metadata("design:type", Function),
1075
- _ts_metadata("design:paramtypes", [
1076
- String,
1077
- String,
1078
- String
1079
- ]),
1080
- _ts_metadata("design:returntype", Promise)
1081
- ], AuthenticationService.prototype, "changePassword", null);
1082
- _ts_decorate([
1083
- LogAction({
1084
- action: 'auth.logout',
1085
- module: 'auth'
1086
- }),
1087
- _ts_metadata("design:type", Function),
1088
- _ts_metadata("design:paramtypes", [
1089
- String
1090
- ]),
1091
- _ts_metadata("design:returntype", Promise)
1092
- ], AuthenticationService.prototype, "logout", null);
1093
- AuthenticationService = _ts_decorate([
1094
- Injectable({
1095
- scope: Scope.REQUEST
1096
- }),
1097
- _ts_param(0, Inject(JwtService)),
1098
- _ts_param(1, Inject(AuthConfigService)),
1099
- _ts_param(2, Optional()),
1100
- _ts_param(2, Inject('CACHE_INSTANCE')),
1101
- _ts_param(3, Optional()),
1102
- _ts_param(3, Inject(AuthDataSourceProvider)),
1103
- _ts_param(4, Optional()),
1104
- _ts_param(4, Inject(CompanySelectionSessionService)),
1105
- _ts_param(5, Optional()),
1106
- _ts_param(5, Inject(AuthEmailService)),
1107
- _ts_param(6, Optional()),
1108
- _ts_param(6, Inject(USER_ENRICHER)),
1109
- _ts_param(7, Optional()),
1110
- _ts_param(7, Inject(NOTIFICATION_ADAPTER)),
1111
- _ts_metadata("design:type", Function),
1112
- _ts_metadata("design:paramtypes", [
1113
- typeof JwtService === "undefined" ? Object : JwtService,
1114
- typeof AuthConfigService === "undefined" ? Object : AuthConfigService,
1115
- typeof HybridCache === "undefined" ? Object : HybridCache,
1116
- typeof AuthDataSourceProvider === "undefined" ? Object : AuthDataSourceProvider,
1117
- typeof CompanySelectionSessionService === "undefined" ? Object : CompanySelectionSessionService,
1118
- typeof AuthEmailService === "undefined" ? Object : AuthEmailService,
1119
- typeof IUserEnricher === "undefined" ? Object : IUserEnricher,
1120
- typeof INotificationAdapter === "undefined" ? Object : INotificationAdapter
1121
- ])
1122
- ], AuthenticationService);