@flusys/nestjs-auth 1.1.0-beta → 2.0.0

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 (86) hide show
  1. package/README.md +590 -473
  2. package/cjs/config/auth.constants.js +8 -0
  3. package/cjs/controllers/authentication.controller.js +218 -39
  4. package/cjs/controllers/branch.controller.js +44 -1
  5. package/cjs/controllers/company-selection.controller.js +27 -20
  6. package/cjs/controllers/company.controller.js +44 -1
  7. package/cjs/controllers/user-permission.controller.js +82 -154
  8. package/cjs/controllers/user.controller.js +68 -15
  9. package/cjs/docs/auth-swagger.config.js +14 -7
  10. package/cjs/dtos/authentication.dto.js +16 -43
  11. package/cjs/dtos/index.js +0 -1
  12. package/cjs/dtos/user-permission.dto.js +28 -0
  13. package/cjs/dtos/user.dto.js +19 -4
  14. package/cjs/entities/user-company-permission.entity.js +0 -6
  15. package/cjs/interceptors/clear-token.interceptor.js +10 -23
  16. package/cjs/interceptors/set-token.interceptor.js +15 -55
  17. package/cjs/interfaces/auth-email-provider.interface.js +1 -1
  18. package/cjs/modules/auth.module.js +63 -147
  19. package/cjs/services/auth-config.service.js +22 -28
  20. package/cjs/services/auth-datasource.provider.js +9 -21
  21. package/cjs/services/auth-email.service.js +89 -85
  22. package/cjs/services/authentication.service.js +225 -396
  23. package/cjs/services/branch.service.js +9 -4
  24. package/cjs/services/company-selection-session.service.js +1 -1
  25. package/cjs/services/user-permission.service.js +43 -73
  26. package/cjs/services/user.service.js +78 -64
  27. package/cjs/strategies/jwt.strategy.js +44 -44
  28. package/cjs/validators/password.validator.js +45 -0
  29. package/config/auth.constants.d.ts +2 -0
  30. package/controllers/authentication.controller.d.ts +5 -3
  31. package/controllers/company-selection.controller.d.ts +6 -2
  32. package/controllers/user-permission.controller.d.ts +5 -4
  33. package/controllers/user.controller.d.ts +6 -0
  34. package/dtos/authentication.dto.d.ts +0 -4
  35. package/dtos/company-branch.dto.d.ts +0 -1
  36. package/dtos/company.dto.d.ts +0 -1
  37. package/dtos/index.d.ts +0 -1
  38. package/dtos/user-permission.dto.d.ts +4 -0
  39. package/dtos/user.dto.d.ts +1 -3
  40. package/entities/index.d.ts +3 -3
  41. package/entities/user-company-permission.entity.d.ts +0 -2
  42. package/fesm/config/auth.constants.js +6 -13
  43. package/fesm/controllers/authentication.controller.js +221 -42
  44. package/fesm/controllers/branch.controller.js +45 -2
  45. package/fesm/controllers/company-selection.controller.js +28 -21
  46. package/fesm/controllers/company.controller.js +45 -2
  47. package/fesm/controllers/user-permission.controller.js +84 -156
  48. package/fesm/controllers/user.controller.js +71 -18
  49. package/fesm/docs/auth-swagger.config.js +14 -7
  50. package/fesm/dtos/authentication.dto.js +17 -44
  51. package/fesm/dtos/index.js +0 -1
  52. package/fesm/dtos/user-permission.dto.js +28 -0
  53. package/fesm/dtos/user.dto.js +20 -5
  54. package/fesm/entities/user-company-permission.entity.js +0 -6
  55. package/fesm/interceptors/clear-token.interceptor.js +9 -22
  56. package/fesm/interceptors/set-token.interceptor.js +14 -54
  57. package/fesm/interfaces/auth-email-provider.interface.js +1 -1
  58. package/fesm/modules/auth.module.js +64 -148
  59. package/fesm/services/auth-config.service.js +23 -29
  60. package/fesm/services/auth-datasource.provider.js +10 -22
  61. package/fesm/services/auth-email.service.js +90 -86
  62. package/fesm/services/authentication.service.js +225 -396
  63. package/fesm/services/branch.service.js +9 -4
  64. package/fesm/services/company-selection-session.service.js +1 -1
  65. package/fesm/services/user-permission.service.js +44 -74
  66. package/fesm/services/user.service.js +79 -65
  67. package/fesm/strategies/jwt.strategy.js +44 -44
  68. package/fesm/validators/password.validator.js +48 -0
  69. package/interceptors/clear-token.interceptor.d.ts +0 -1
  70. package/interceptors/set-token.interceptor.d.ts +1 -1
  71. package/interfaces/authentication.interface.d.ts +0 -4
  72. package/interfaces/user-enricher.interface.d.ts +1 -4
  73. package/modules/auth.module.d.ts +6 -3
  74. package/package.json +4 -4
  75. package/services/auth-config.service.d.ts +6 -8
  76. package/services/auth-datasource.provider.d.ts +2 -4
  77. package/services/auth-email.service.d.ts +8 -4
  78. package/services/authentication.service.d.ts +15 -16
  79. package/services/company-selection-session.service.d.ts +1 -1
  80. package/services/user-permission.service.d.ts +6 -9
  81. package/services/user.service.d.ts +3 -0
  82. package/strategies/jwt.strategy.d.ts +4 -1
  83. package/validators/password.validator.d.ts +10 -0
  84. package/cjs/dtos/user-company-permission.dto.js +0 -110
  85. package/dtos/user-company-permission.dto.d.ts +0 -10
  86. package/fesm/dtos/user-company-permission.dto.js +0 -98
@@ -16,6 +16,12 @@ _export(exports, {
16
16
  get BCRYPT_SALT_ROUNDS () {
17
17
  return BCRYPT_SALT_ROUNDS;
18
18
  },
19
+ get DEFAULT_COOKIE_NAME () {
20
+ return DEFAULT_COOKIE_NAME;
21
+ },
22
+ get MAX_COOKIE_BYTES () {
23
+ return MAX_COOKIE_BYTES;
24
+ },
19
25
  get SESSION_CACHE_PREFIX () {
20
26
  return SESSION_CACHE_PREFIX;
21
27
  },
@@ -29,5 +35,7 @@ _export(exports, {
29
35
  const AUTH_MODULE_OPTIONS = 'AUTH_MODULE_OPTIONS';
30
36
  const USER_ENRICHER = 'USER_ENRICHER';
31
37
  const BCRYPT_SALT_ROUNDS = 12;
38
+ const DEFAULT_COOKIE_NAME = 'fsn_refresh_token';
39
+ const MAX_COOKIE_BYTES = 3500;
32
40
  const SESSION_CACHE_PREFIX = 'auth:session';
33
41
  const TOKEN_REVOKED_PREFIX = 'auth:revoked';
@@ -9,13 +9,15 @@ Object.defineProperty(exports, "AuthenticationController", {
9
9
  }
10
10
  });
11
11
  const _decorators = require("@flusys/nestjs-shared/decorators");
12
+ const _dtos = require("@flusys/nestjs-shared/dtos");
12
13
  const _guards = require("@flusys/nestjs-shared/guards");
13
14
  const _interfaces = require("@flusys/nestjs-shared/interfaces");
14
15
  const _common = require("@nestjs/common");
15
16
  const _swagger = require("@nestjs/swagger");
17
+ const _throttler = require("@nestjs/throttler");
16
18
  const _express = require("express");
19
+ const _config = require("../config");
17
20
  const _authenticationdto = require("../dtos/authentication.dto");
18
- const _dtos = require("@flusys/nestjs-shared/dtos");
19
21
  const _cleartokeninterceptor = require("../interceptors/clear-token.interceptor");
20
22
  const _settokeninterceptor = require("../interceptors/set-token.interceptor");
21
23
  const _authconfigservice = require("../services/auth-config.service");
@@ -49,13 +51,24 @@ function _ts_param(paramIndex, decorator) {
49
51
  };
50
52
  }
51
53
  let AuthenticationController = class AuthenticationController {
52
- /** Build auth URL for email links */ buildAuthUrl(req, path) {
54
+ buildAuthUrl(req, path) {
53
55
  const frontendUrl = this.authConfig?.getFrontendUrl();
54
56
  return frontendUrl ? `${frontendUrl}${path}` : `${req.protocol}://${req.get('host')}${path}`;
55
57
  }
56
- // Core Endpoints
57
- /** Login - Returns tokens or company/branch selection requirement */ async login(loginDto) {
58
+ get emailService() {
59
+ if (!this.authEmailService) {
60
+ throw new Error('Email service is not configured');
61
+ }
62
+ return this.authEmailService;
63
+ }
64
+ get isEmailEnabled() {
65
+ return !!this.authEmailService;
66
+ }
67
+ async login(loginDto) {
58
68
  const result = await this.authService.login(loginDto.email, loginDto.password);
69
+ if ('requiresEmailVerification' in result) {
70
+ return result;
71
+ }
59
72
  if ('requiresSelection' in result) {
60
73
  return result;
61
74
  }
@@ -64,14 +77,15 @@ let AuthenticationController = class AuthenticationController {
64
77
  /** Register new user. If company feature enabled, can join/create company. */ async register(req, registrationDto) {
65
78
  const verifyUrlBase = this.buildAuthUrl(req, '/auth/verify-email');
66
79
  const result = await this.authService.register(registrationDto, verifyUrlBase);
67
- return {
68
- ...result,
69
- companyFeatureEnabled: this.authConfig?.isCompanyFeatureEnabled() ?? false
70
- };
80
+ return result;
71
81
  }
72
- /** Refresh access token. Browser uses HTTP-only cookie, API/Mobile uses request body. */ async refreshToken(req, refreshTokenDto) {
73
- // Get refresh token from cookie (browser) or body (API/mobile)
74
- const cookieName = this.authConfig?.getRefreshTokenCookieName() ?? 'fsn_refresh_token';
82
+ /**
83
+ * Refresh access token.
84
+ * - **Browser**: Prefers HTTP-only cookie, falls back to body if cookie missing.
85
+ * - **API/Mobile**: Must send `refreshToken` in request body. Set header `x-client-type: mobile` or `x-client-type: api`.
86
+ */ async refreshToken(req, refreshTokenDto) {
87
+ const cookieName = this.authConfig?.getRefreshTokenCookieName() ?? _config.DEFAULT_COOKIE_NAME;
88
+ // Always check cookie first, then body - handles Browser, SSR, and Mobile/API
75
89
  const refreshToken = req.cookies?.[cookieName] || refreshTokenDto.refreshToken;
76
90
  if (!refreshToken) {
77
91
  throw new _common.UnauthorizedException('Refresh token is required');
@@ -88,63 +102,56 @@ let AuthenticationController = class AuthenticationController {
88
102
  message: 'Logged out successfully'
89
103
  };
90
104
  }
91
- /** Change password */ async changePassword(userId, dto) {
105
+ async changePassword(userId, dto) {
92
106
  await this.authService.changePassword(userId, dto.currentPassword, dto.newPassword);
93
107
  return {
94
108
  success: true,
95
109
  message: 'Password changed successfully'
96
110
  };
97
111
  }
98
- // Email Auth Endpoints
99
- /** Forgot password - Request password reset email */ async forgotPassword(req, dto) {
100
- if (!this.authEmailService) {
112
+ async forgotPassword(req, dto) {
113
+ if (!this.isEmailEnabled) {
101
114
  return {
102
115
  success: false,
103
116
  message: 'Email service is not configured'
104
117
  };
105
118
  }
106
- return this.authEmailService.forgotPassword(dto.email, this.buildAuthUrl(req, '/auth/reset-password'));
119
+ return this.emailService.forgotPassword(dto.email, this.buildAuthUrl(req, '/auth/reset-password'));
107
120
  }
108
- /** Reset password - Reset password using token */ async resetPassword(dto) {
109
- if (!this.authEmailService) {
121
+ async resetPassword(dto) {
122
+ if (!this.isEmailEnabled) {
110
123
  return {
111
124
  success: false,
112
125
  message: 'Email service is not configured'
113
126
  };
114
127
  }
115
- return this.authEmailService.resetPassword(dto.token, dto.newPassword);
128
+ return this.emailService.resetPassword(dto.token, dto.newPassword);
116
129
  }
117
- /** Resend verification email - For unauthenticated users (handles both pending registration and existing users) */ async resendVerification(req, dto) {
118
- if (!this.authEmailService) {
130
+ async resendVerification(req, dto) {
131
+ if (!this.isEmailEnabled) {
119
132
  return {
120
133
  success: false,
121
134
  message: 'Email service is not configured'
122
135
  };
123
136
  }
124
- return this.authEmailService.resendVerificationEmail(dto.email, this.buildAuthUrl(req, '/auth/verify-email'));
137
+ return this.emailService.resendVerificationEmail(dto.email, this.buildAuthUrl(req, '/auth/verify-email'));
125
138
  }
126
139
  /** Verify email - Verify email using token. Handles both pending registration and existing user verification. */ async verifyEmail(dto) {
127
- if (!this.authEmailService) {
140
+ if (!this.isEmailEnabled) {
128
141
  return {
129
142
  success: false,
130
143
  message: 'Email service is not configured'
131
144
  };
132
145
  }
133
- const result = await this.authEmailService.verifyEmail(dto.token);
146
+ const result = await this.emailService.verifyEmail(dto.token);
134
147
  if (result.type === 'pending') {
135
- // Create user from pending registration
136
- const registrationResult = await this.authService.createUserFromPendingRegistration(result.pending);
137
- return {
138
- ...registrationResult,
139
- companyFeatureEnabled: this.authConfig?.isCompanyFeatureEnabled() ?? false
140
- };
148
+ return this.authService.createUserFromPendingRegistration(result.pending);
141
149
  }
142
150
  return {
143
151
  success: true,
144
152
  message: result.message
145
153
  };
146
154
  }
147
- // NOTE: @Inject() required for bundled code - type metadata may be lost during esbuild
148
155
  constructor(authService, authConfig, authEmailService){
149
156
  _define_property(this, "authService", void 0);
150
157
  _define_property(this, "authConfig", void 0);
@@ -157,6 +164,12 @@ let AuthenticationController = class AuthenticationController {
157
164
  _ts_decorate([
158
165
  (0, _common.Post)('login'),
159
166
  (0, _common.HttpCode)(_common.HttpStatus.OK),
167
+ (0, _throttler.Throttle)({
168
+ default: {
169
+ limit: 5,
170
+ ttl: 60000
171
+ }
172
+ }),
160
173
  (0, _common.UseInterceptors)(_settokeninterceptor.SetToken),
161
174
  (0, _swagger.ApiOperation)({
162
175
  summary: 'User login'
@@ -164,13 +177,102 @@ _ts_decorate([
164
177
  (0, _swagger.ApiBody)({
165
178
  type: _authenticationdto.LoginDto
166
179
  }),
180
+ (0, _swagger.ApiExtraModels)(_authenticationdto.LoginResponseDto, _authenticationdto.CompanySelectionResponseDto, _authenticationdto.LoginResponseRequiresEmailVerificationDto),
167
181
  (0, _swagger.ApiResponse)({
168
182
  status: 200,
169
- type: _authenticationdto.LoginResponseDto
170
- }),
171
- (0, _swagger.ApiResponse)({
172
- status: 200,
173
- type: _authenticationdto.CompanySelectionResponseDto
183
+ description: 'Login successful, requires company selection, or requires email verification',
184
+ content: {
185
+ 'application/json': {
186
+ schema: {
187
+ oneOf: [
188
+ {
189
+ $ref: (0, _swagger.getSchemaPath)(_authenticationdto.LoginResponseDto)
190
+ },
191
+ {
192
+ $ref: (0, _swagger.getSchemaPath)(_authenticationdto.CompanySelectionResponseDto)
193
+ },
194
+ {
195
+ $ref: (0, _swagger.getSchemaPath)(_authenticationdto.LoginResponseRequiresEmailVerificationDto)
196
+ }
197
+ ]
198
+ },
199
+ examples: {
200
+ loginSuccess: {
201
+ summary: 'Login Success',
202
+ description: 'Successful login with tokens (company/branch included when company feature enabled)',
203
+ value: {
204
+ accessToken: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
205
+ refreshToken: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
206
+ user: {
207
+ id: '550e8400-e29b-41d4-a716-446655440000',
208
+ email: 'john@example.com',
209
+ name: 'John Doe'
210
+ }
211
+ }
212
+ },
213
+ loginSuccessWithCompany: {
214
+ summary: 'Login Success (Company Feature)',
215
+ description: 'Login with company/branch - only when company feature is enabled',
216
+ value: {
217
+ accessToken: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
218
+ refreshToken: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
219
+ user: {
220
+ id: '550e8400-e29b-41d4-a716-446655440000',
221
+ email: 'john@example.com',
222
+ name: 'John Doe'
223
+ },
224
+ company: {
225
+ id: '550e8400-e29b-41d4-a716-446655440001',
226
+ name: 'Acme Corporation',
227
+ slug: 'acme-corp'
228
+ },
229
+ branch: {
230
+ id: '550e8400-e29b-41d4-a716-446655440002',
231
+ name: 'Main Branch',
232
+ slug: 'main-branch'
233
+ }
234
+ }
235
+ },
236
+ companySelection: {
237
+ summary: 'Company Selection Required (Company Feature)',
238
+ description: 'User has multiple companies/branches - only when company feature is enabled',
239
+ value: {
240
+ requiresSelection: true,
241
+ sessionId: 'sess_abc123def456',
242
+ expiresAt: '2024-12-18T15:30:00.000Z',
243
+ user: {
244
+ id: '550e8400-e29b-41d4-a716-446655440000',
245
+ email: 'john@example.com',
246
+ name: 'John Doe'
247
+ },
248
+ companies: [
249
+ {
250
+ id: '550e8400-e29b-41d4-a716-446655440001',
251
+ name: 'Company A',
252
+ slug: 'company-a',
253
+ branches: [
254
+ {
255
+ id: '550e8400-e29b-41d4-a716-446655440010',
256
+ name: 'Branch 1',
257
+ slug: 'branch-1'
258
+ }
259
+ ]
260
+ }
261
+ ]
262
+ }
263
+ },
264
+ emailVerification: {
265
+ summary: 'Email Verification Required',
266
+ description: 'User must verify email before logging in',
267
+ value: {
268
+ requiresEmailVerification: true,
269
+ email: 'john@example.com',
270
+ message: 'Please verify your email address before logging in.'
271
+ }
272
+ }
273
+ }
274
+ }
275
+ }
174
276
  }),
175
277
  _ts_param(0, (0, _common.Body)()),
176
278
  _ts_metadata("design:type", Function),
@@ -182,6 +284,12 @@ _ts_decorate([
182
284
  _ts_decorate([
183
285
  (0, _common.Post)('register'),
184
286
  (0, _common.HttpCode)(_common.HttpStatus.CREATED),
287
+ (0, _throttler.Throttle)({
288
+ default: {
289
+ limit: 3,
290
+ ttl: 60000
291
+ }
292
+ }),
185
293
  (0, _common.UseInterceptors)(_settokeninterceptor.SetToken),
186
294
  (0, _swagger.ApiOperation)({
187
295
  summary: 'Register new user'
@@ -205,11 +313,50 @@ _ts_decorate([
205
313
  _ts_decorate([
206
314
  (0, _common.Post)('refresh'),
207
315
  (0, _common.HttpCode)(_common.HttpStatus.OK),
316
+ (0, _throttler.Throttle)({
317
+ default: {
318
+ limit: 30,
319
+ ttl: 60000
320
+ }
321
+ }),
208
322
  (0, _swagger.ApiOperation)({
209
- summary: 'Refresh access token'
323
+ summary: 'Refresh access token',
324
+ description: `
325
+ **Browser clients**: Refresh token is read from HTTP-only cookie (automatically set on login/register).
326
+ Falls back to request body if cookie is not available.
327
+
328
+ **API/Mobile clients**: Must send \`refreshToken\` in request body.
329
+ Set header \`x-client-type: mobile\` or \`x-client-type: api\` to identify as non-browser client.
330
+
331
+ **Client detection**: Uses \`x-client-type\` header first, then falls back to User-Agent detection.
332
+ `
333
+ }),
334
+ (0, _swagger.ApiHeader)({
335
+ name: 'x-client-type',
336
+ required: false,
337
+ description: 'Client type: "browser"/"web" for cookie-based auth, "mobile"/"api" for body-based auth',
338
+ example: 'mobile'
210
339
  }),
211
340
  (0, _swagger.ApiBody)({
212
- type: _authenticationdto.RefreshTokenDto
341
+ type: _authenticationdto.RefreshTokenDto,
342
+ description: 'Required for API/Mobile clients. Browser clients prefer HTTP-only cookie with body fallback.'
343
+ }),
344
+ (0, _swagger.ApiResponse)({
345
+ status: 200,
346
+ description: 'New access token',
347
+ schema: {
348
+ type: 'object',
349
+ properties: {
350
+ accessToken: {
351
+ type: 'string',
352
+ example: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
353
+ }
354
+ }
355
+ }
356
+ }),
357
+ (0, _swagger.ApiResponse)({
358
+ status: 401,
359
+ description: 'Invalid or missing refresh token'
213
360
  }),
214
361
  _ts_param(0, (0, _common.Req)()),
215
362
  _ts_param(1, (0, _common.Body)()),
@@ -222,7 +369,8 @@ _ts_decorate([
222
369
  ], AuthenticationController.prototype, "refreshToken", null);
223
370
  _ts_decorate([
224
371
  (0, _common.UseGuards)(_guards.JwtAuthGuard),
225
- (0, _common.Get)('me'),
372
+ (0, _common.Post)('me'),
373
+ (0, _throttler.SkipThrottle)(),
226
374
  (0, _swagger.ApiBearerAuth)(),
227
375
  (0, _swagger.ApiOperation)({
228
376
  summary: 'Get current user info'
@@ -242,6 +390,7 @@ _ts_decorate([
242
390
  (0, _common.UseGuards)(_guards.JwtAuthGuard),
243
391
  (0, _common.Post)('logout'),
244
392
  (0, _common.HttpCode)(_common.HttpStatus.OK),
393
+ (0, _throttler.SkipThrottle)(),
245
394
  (0, _common.UseInterceptors)(_cleartokeninterceptor.ClearToken),
246
395
  (0, _swagger.ApiBearerAuth)(),
247
396
  (0, _swagger.ApiOperation)({
@@ -262,6 +411,12 @@ _ts_decorate([
262
411
  (0, _common.UseGuards)(_guards.JwtAuthGuard),
263
412
  (0, _common.Post)('change-password'),
264
413
  (0, _common.HttpCode)(_common.HttpStatus.OK),
414
+ (0, _throttler.Throttle)({
415
+ default: {
416
+ limit: 5,
417
+ ttl: 60000
418
+ }
419
+ }),
265
420
  (0, _swagger.ApiBearerAuth)(),
266
421
  (0, _swagger.ApiOperation)({
267
422
  summary: 'Change password'
@@ -285,6 +440,12 @@ _ts_decorate([
285
440
  _ts_decorate([
286
441
  (0, _common.Post)('forgot-password'),
287
442
  (0, _common.HttpCode)(_common.HttpStatus.OK),
443
+ (0, _throttler.Throttle)({
444
+ default: {
445
+ limit: 3,
446
+ ttl: 300000
447
+ }
448
+ }),
288
449
  (0, _swagger.ApiOperation)({
289
450
  summary: 'Request password reset email'
290
451
  }),
@@ -307,6 +468,12 @@ _ts_decorate([
307
468
  _ts_decorate([
308
469
  (0, _common.Post)('reset-password'),
309
470
  (0, _common.HttpCode)(_common.HttpStatus.OK),
471
+ (0, _throttler.Throttle)({
472
+ default: {
473
+ limit: 5,
474
+ ttl: 900000
475
+ }
476
+ }),
310
477
  (0, _swagger.ApiOperation)({
311
478
  summary: 'Reset password using token'
312
479
  }),
@@ -327,6 +494,12 @@ _ts_decorate([
327
494
  _ts_decorate([
328
495
  (0, _common.Post)('resend-verification'),
329
496
  (0, _common.HttpCode)(_common.HttpStatus.OK),
497
+ (0, _throttler.Throttle)({
498
+ default: {
499
+ limit: 3,
500
+ ttl: 300000
501
+ }
502
+ }),
330
503
  (0, _swagger.ApiOperation)({
331
504
  summary: 'Resend email verification link'
332
505
  }),
@@ -349,6 +522,12 @@ _ts_decorate([
349
522
  _ts_decorate([
350
523
  (0, _common.Post)('verify-email'),
351
524
  (0, _common.HttpCode)(_common.HttpStatus.OK),
525
+ (0, _throttler.Throttle)({
526
+ default: {
527
+ limit: 10,
528
+ ttl: 60000
529
+ }
530
+ }),
352
531
  (0, _common.UseInterceptors)(_settokeninterceptor.SetToken),
353
532
  (0, _swagger.ApiOperation)({
354
533
  summary: 'Verify email using token'
@@ -41,7 +41,50 @@ function _ts_param(paramIndex, decorator) {
41
41
  };
42
42
  }
43
43
  let BranchController = class BranchController extends (0, _classes.createApiController)(_companybranchdto.CreateCompanyBranchDto, _companybranchdto.UpdateCompanyBranchDto, _companybranchdto.CompanyBranchResponseDto, {
44
- security: 'jwt'
44
+ security: {
45
+ insert: {
46
+ level: 'permission',
47
+ permissions: [
48
+ _classes.BRANCH_PERMISSIONS.CREATE
49
+ ]
50
+ },
51
+ insertMany: {
52
+ level: 'permission',
53
+ permissions: [
54
+ _classes.BRANCH_PERMISSIONS.CREATE
55
+ ]
56
+ },
57
+ getById: {
58
+ level: 'permission',
59
+ permissions: [
60
+ _classes.BRANCH_PERMISSIONS.READ
61
+ ]
62
+ },
63
+ getAll: {
64
+ level: 'permission',
65
+ permissions: [
66
+ _classes.BRANCH_PERMISSIONS.READ
67
+ ]
68
+ },
69
+ update: {
70
+ level: 'permission',
71
+ permissions: [
72
+ _classes.BRANCH_PERMISSIONS.UPDATE
73
+ ]
74
+ },
75
+ updateMany: {
76
+ level: 'permission',
77
+ permissions: [
78
+ _classes.BRANCH_PERMISSIONS.UPDATE
79
+ ]
80
+ },
81
+ delete: {
82
+ level: 'permission',
83
+ permissions: [
84
+ _classes.BRANCH_PERMISSIONS.DELETE
85
+ ]
86
+ }
87
+ }
45
88
  }) {
46
89
  constructor(branchService){
47
90
  super(branchService), _define_property(this, "branchService", void 0), this.branchService = branchService;
@@ -43,35 +43,28 @@ function _ts_param(paramIndex, decorator) {
43
43
  };
44
44
  }
45
45
  let CompanySelectionController = class CompanySelectionController {
46
- /**
47
- * Select Company & Branch
48
- * Used after login when user needs to select company and branch
49
- */ async select(dto) {
46
+ async select(dto) {
50
47
  return this.authService.select(dto.sessionId, dto.companyId, dto.branchId);
51
48
  }
52
- /**
53
- * Switch Company/Branch
54
- * Used to switch company/branch after already logged in
55
- */ async switchCompany(userId, dto) {
49
+ async switchCompany(userId, dto) {
56
50
  return this.authService.switchCompany(userId, dto.companyId, dto.branchId);
57
51
  }
58
- /**
59
- * Get user's companies
60
- */ async getUserCompanies(userId) {
52
+ async getUserCompanies(userId) {
61
53
  const companies = await this.authService.getUserCompanies(userId);
62
54
  return {
63
- companies
55
+ success: true,
56
+ message: 'User companies retrieved successfully',
57
+ data: companies
64
58
  };
65
59
  }
66
- /**
67
- * Get branches for a specific company
68
- */ async getUserBranches(userId, companyId) {
60
+ async getUserBranches(userId, companyId) {
69
61
  const branches = await this.authService.getUserBranches(userId, companyId);
70
62
  return {
71
- branches
63
+ success: true,
64
+ message: 'Company branches retrieved successfully',
65
+ data: branches
72
66
  };
73
67
  }
74
- // NOTE: @Inject() required for bundled code - type metadata may be lost during esbuild
75
68
  constructor(authService){
76
69
  _define_property(this, "authService", void 0);
77
70
  this.authService = authService;
@@ -127,7 +120,8 @@ _ts_decorate([
127
120
  ], CompanySelectionController.prototype, "switchCompany", null);
128
121
  _ts_decorate([
129
122
  (0, _common.UseGuards)(_guards.JwtAuthGuard),
130
- (0, _common.Get)('companies'),
123
+ (0, _common.Post)('get-companies'),
124
+ (0, _common.HttpCode)(_common.HttpStatus.OK),
131
125
  (0, _swagger.ApiBearerAuth)(),
132
126
  (0, _swagger.ApiOperation)({
133
127
  summary: "Get user's available companies",
@@ -142,14 +136,27 @@ _ts_decorate([
142
136
  ], CompanySelectionController.prototype, "getUserCompanies", null);
143
137
  _ts_decorate([
144
138
  (0, _common.UseGuards)(_guards.JwtAuthGuard),
145
- (0, _common.Get)('companies/:companyId/branches'),
139
+ (0, _common.Post)('get-company-branches'),
140
+ (0, _common.HttpCode)(_common.HttpStatus.OK),
146
141
  (0, _swagger.ApiBearerAuth)(),
147
142
  (0, _swagger.ApiOperation)({
148
143
  summary: 'Get branches for a company',
149
144
  description: 'Get list of branches for a specific company that the user has access to'
150
145
  }),
146
+ (0, _swagger.ApiBody)({
147
+ schema: {
148
+ properties: {
149
+ companyId: {
150
+ type: 'string'
151
+ }
152
+ },
153
+ required: [
154
+ 'companyId'
155
+ ]
156
+ }
157
+ }),
151
158
  _ts_param(0, (0, _decorators.CurrentUser)('id')),
152
- _ts_param(1, (0, _common.Param)('companyId')),
159
+ _ts_param(1, (0, _common.Body)('companyId')),
153
160
  _ts_metadata("design:type", Function),
154
161
  _ts_metadata("design:paramtypes", [
155
162
  String,
@@ -41,7 +41,50 @@ function _ts_param(paramIndex, decorator) {
41
41
  };
42
42
  }
43
43
  let CompanyController = class CompanyController extends (0, _classes.createApiController)(_companydto.CreateCompanyDto, _companydto.UpdateCompanyDto, _companydto.CompanyResponseDto, {
44
- security: 'jwt'
44
+ security: {
45
+ insert: {
46
+ level: 'permission',
47
+ permissions: [
48
+ _classes.COMPANY_PERMISSIONS.CREATE
49
+ ]
50
+ },
51
+ insertMany: {
52
+ level: 'permission',
53
+ permissions: [
54
+ _classes.COMPANY_PERMISSIONS.CREATE
55
+ ]
56
+ },
57
+ getById: {
58
+ level: 'permission',
59
+ permissions: [
60
+ _classes.COMPANY_PERMISSIONS.READ
61
+ ]
62
+ },
63
+ getAll: {
64
+ level: 'permission',
65
+ permissions: [
66
+ _classes.COMPANY_PERMISSIONS.READ
67
+ ]
68
+ },
69
+ update: {
70
+ level: 'permission',
71
+ permissions: [
72
+ _classes.COMPANY_PERMISSIONS.UPDATE
73
+ ]
74
+ },
75
+ updateMany: {
76
+ level: 'permission',
77
+ permissions: [
78
+ _classes.COMPANY_PERMISSIONS.UPDATE
79
+ ]
80
+ },
81
+ delete: {
82
+ level: 'permission',
83
+ permissions: [
84
+ _classes.COMPANY_PERMISSIONS.DELETE
85
+ ]
86
+ }
87
+ }
45
88
  }) {
46
89
  constructor(companyService){
47
90
  super(companyService), _define_property(this, "companyService", void 0), this.companyService = companyService;