@flusys/nestjs-shared 3.0.1 → 4.0.0-lts

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/README.md +159 -79
  2. package/cjs/classes/api-controller.class.js +26 -8
  3. package/cjs/classes/api-service.class.js +100 -17
  4. package/cjs/classes/winston-logger-adapter.class.js +15 -20
  5. package/cjs/classes/winston.logger.class.js +103 -70
  6. package/cjs/constants/index.js +1 -0
  7. package/cjs/constants/message-keys.js +80 -0
  8. package/cjs/constants/permissions.js +32 -1
  9. package/cjs/decorators/index.js +1 -0
  10. package/cjs/decorators/log-action.decorator.js +149 -0
  11. package/cjs/dtos/response-payload.dto.js +72 -0
  12. package/cjs/exceptions/base-app.exception.js +145 -0
  13. package/cjs/exceptions/index.js +1 -0
  14. package/cjs/exceptions/permission.exception.js +12 -8
  15. package/cjs/filters/global-exception.filter.js +167 -0
  16. package/cjs/filters/index.js +18 -0
  17. package/cjs/guards/jwt-auth.guard.js +4 -1
  18. package/cjs/guards/permission.guard.js +6 -13
  19. package/cjs/index.js +1 -0
  20. package/cjs/interceptors/idempotency.interceptor.js +1 -1
  21. package/cjs/interceptors/index.js +0 -1
  22. package/cjs/interfaces/logger.interface.js +1 -4
  23. package/cjs/middlewares/logger.middleware.js +83 -26
  24. package/cjs/modules/datasource/multi-tenant-datasource.service.js +33 -11
  25. package/cjs/modules/utils/utils.service.js +4 -20
  26. package/cjs/utils/index.js +0 -1
  27. package/cjs/utils/query-helpers.util.js +8 -1
  28. package/classes/api-controller.class.d.ts +1 -0
  29. package/classes/api-service.class.d.ts +5 -10
  30. package/classes/winston-logger-adapter.class.d.ts +12 -11
  31. package/classes/winston.logger.class.d.ts +1 -0
  32. package/constants/index.d.ts +1 -0
  33. package/constants/message-keys.d.ts +81 -0
  34. package/constants/permissions.d.ts +36 -0
  35. package/decorators/index.d.ts +1 -0
  36. package/decorators/log-action.decorator.d.ts +8 -0
  37. package/dtos/response-payload.dto.d.ts +8 -0
  38. package/exceptions/base-app.exception.d.ts +41 -0
  39. package/exceptions/index.d.ts +1 -0
  40. package/exceptions/permission.exception.d.ts +1 -1
  41. package/fesm/classes/api-controller.class.js +26 -8
  42. package/fesm/classes/api-service.class.js +101 -18
  43. package/fesm/classes/winston-logger-adapter.class.js +18 -44
  44. package/fesm/classes/winston.logger.class.js +100 -68
  45. package/fesm/constants/index.js +2 -0
  46. package/fesm/constants/message-keys.js +59 -0
  47. package/fesm/constants/permissions.js +24 -1
  48. package/fesm/decorators/index.js +1 -0
  49. package/fesm/decorators/log-action.decorator.js +139 -0
  50. package/fesm/dtos/response-payload.dto.js +72 -0
  51. package/fesm/exceptions/base-app.exception.js +109 -0
  52. package/fesm/exceptions/index.js +1 -0
  53. package/fesm/exceptions/permission.exception.js +15 -17
  54. package/fesm/filters/global-exception.filter.js +157 -0
  55. package/fesm/filters/index.js +1 -0
  56. package/fesm/guards/jwt-auth.guard.js +5 -2
  57. package/fesm/guards/permission.guard.js +8 -15
  58. package/fesm/index.js +1 -0
  59. package/fesm/interceptors/idempotency.interceptor.js +2 -2
  60. package/fesm/interceptors/index.js +0 -1
  61. package/fesm/interfaces/logger.interface.js +1 -4
  62. package/fesm/middlewares/logger.middleware.js +83 -26
  63. package/fesm/modules/datasource/multi-tenant-datasource.service.js +34 -12
  64. package/fesm/modules/utils/utils.service.js +5 -21
  65. package/fesm/utils/index.js +0 -1
  66. package/fesm/utils/query-helpers.util.js +8 -1
  67. package/filters/global-exception.filter.d.ts +10 -0
  68. package/filters/index.d.ts +1 -0
  69. package/guards/permission.guard.d.ts +1 -3
  70. package/index.d.ts +1 -0
  71. package/interceptors/index.d.ts +0 -1
  72. package/interfaces/logger.interface.d.ts +5 -5
  73. package/modules/datasource/multi-tenant-datasource.service.d.ts +1 -2
  74. package/modules/utils/utils.service.d.ts +0 -1
  75. package/package.json +5 -3
  76. package/utils/index.d.ts +0 -1
  77. package/cjs/interceptors/query-performance.interceptor.js +0 -66
  78. package/cjs/utils/error-handler.util.js +0 -90
  79. package/fesm/interceptors/query-performance.interceptor.js +0 -56
  80. package/fesm/utils/error-handler.util.js +0 -82
  81. package/interceptors/query-performance.interceptor.d.ts +0 -8
  82. package/utils/error-handler.util.d.ts +0 -19
@@ -0,0 +1,59 @@
1
+ // ==================== SHARED/SYSTEM MESSAGE KEYS ====================
2
+ // Package-specific messages are now in their respective packages:
3
+ // - nestjs-auth/src/config/message-keys.ts
4
+ // - nestjs-iam/src/config/message-keys.ts
5
+ // - nestjs-storage/src/config/message-keys.ts
6
+ // - nestjs-email/src/config/message-keys.ts
7
+ // - nestjs-form-builder/src/config/message-keys.ts
8
+ // - nestjs-event-manager/src/config/message-keys.ts
9
+ // - nestjs-notification/src/config/message-keys.ts
10
+ // - nestjs-localization/src/config/message-keys.ts
11
+ // ==================== AUTH (Shared across guards/interceptors) ====================
12
+ // These are duplicated in nestjs-auth but needed here to avoid circular dependencies
13
+ export const AUTH_MESSAGES = {
14
+ TOKEN_REQUIRED: 'auth.token.required',
15
+ TOKEN_INVALID: 'auth.token.invalid',
16
+ TOKEN_EXPIRED: 'auth.token.expired',
17
+ COMPANY_NO_ACCESS: 'auth.company.no.access'
18
+ };
19
+ // ==================== ERROR (HTTP Exceptions) ====================
20
+ export const ERROR_MESSAGES = {
21
+ NOT_FOUND: 'error.not.found',
22
+ VALIDATION: 'error.validation',
23
+ UNAUTHORIZED: 'error.unauthorized',
24
+ FORBIDDEN: 'error.forbidden',
25
+ CONFLICT: 'error.conflict',
26
+ INTERNAL: 'error.internal',
27
+ SERVICE_UNAVAILABLE: 'error.service.unavailable',
28
+ UNKNOWN: 'error.unknown',
29
+ HTTP: 'error.http',
30
+ GENERIC: 'error.generic',
31
+ PERMISSION_SYSTEM_UNAVAILABLE: 'error.permission.system.unavailable',
32
+ INSUFFICIENT_PERMISSIONS: 'error.insufficient.permissions',
33
+ INSUFFICIENT_PERMISSIONS_OR: 'error.insufficient.permissions.or',
34
+ NO_PERMISSIONS_FOUND: 'error.no.permissions.found'
35
+ };
36
+ // ==================== SYSTEM (Infrastructure) ====================
37
+ export const SYSTEM_MESSAGES = {
38
+ REPOSITORY_NOT_AVAILABLE: 'system.repository.not.available',
39
+ DATASOURCE_NOT_AVAILABLE: 'system.datasource.not.available',
40
+ DATABASE_CONFIG_NOT_AVAILABLE: 'system.database.config.not.available',
41
+ SERVICE_NOT_AVAILABLE: 'system.service.not.available',
42
+ CONFIG_REQUIRED: 'system.config.required',
43
+ INTERNAL_ERROR: 'system.internal.error',
44
+ NOT_FOUND: 'system.not.found',
45
+ DUPLICATE_REQUEST: 'system.duplicate.request',
46
+ INVALID_TENANT_ID: 'system.invalid.tenant.id',
47
+ TENANT_NOT_FOUND: 'system.tenant.not.found',
48
+ TENANT_HEADER_REQUIRED: 'system.tenant.header.required',
49
+ MISSING_PARAMETER: 'system.missing.parameter',
50
+ SDK_NOT_INSTALLED: 'system.sdk.not.installed',
51
+ PATH_TRAVERSAL_DETECTED: 'system.path.traversal.detected',
52
+ INVALID_FILE_KEY: 'system.invalid.file.key'
53
+ };
54
+ // ==================== AGGREGATED EXPORTS ====================
55
+ export const MESSAGE_KEYS = {
56
+ AUTH: AUTH_MESSAGES,
57
+ ERROR: ERROR_MESSAGES,
58
+ SYSTEM: SYSTEM_MESSAGES
59
+ };
@@ -111,6 +111,25 @@ export const NOTIFICATION_PERMISSIONS = {
111
111
  UPDATE: 'notification.update',
112
112
  DELETE: 'notification.delete'
113
113
  };
114
+ // ==================== LOCALIZATION MODULE ====================
115
+ export const LANGUAGE_PERMISSIONS = {
116
+ CREATE: 'language.create',
117
+ READ: 'language.read',
118
+ UPDATE: 'language.update',
119
+ DELETE: 'language.delete'
120
+ };
121
+ export const TRANSLATION_KEY_PERMISSIONS = {
122
+ CREATE: 'translation-key.create',
123
+ READ: 'translation-key.read',
124
+ UPDATE: 'translation-key.update',
125
+ DELETE: 'translation-key.delete'
126
+ };
127
+ export const TRANSLATION_PERMISSIONS = {
128
+ CREATE: 'translation.create',
129
+ READ: 'translation.read',
130
+ UPDATE: 'translation.update',
131
+ DELETE: 'translation.delete'
132
+ };
114
133
  // ==================== AGGREGATED EXPORTS ====================
115
134
  export const PERMISSIONS = {
116
135
  // Auth
@@ -138,5 +157,9 @@ export const PERMISSIONS = {
138
157
  EVENT: EVENT_PERMISSIONS,
139
158
  EVENT_PARTICIPANT: EVENT_PARTICIPANT_PERMISSIONS,
140
159
  // Notification
141
- NOTIFICATION: NOTIFICATION_PERMISSIONS
160
+ NOTIFICATION: NOTIFICATION_PERMISSIONS,
161
+ // Localization
162
+ LANGUAGE: LANGUAGE_PERMISSIONS,
163
+ TRANSLATION_KEY: TRANSLATION_KEY_PERMISSIONS,
164
+ TRANSLATION: TRANSLATION_PERMISSIONS
142
165
  };
@@ -1,5 +1,6 @@
1
1
  export * from './api-response.decorator';
2
2
  export * from './current-user.decorator';
3
+ export * from './log-action.decorator';
3
4
  export * from './public.decorator';
4
5
  export * from './require-permission.decorator';
5
6
  export * from './sanitize-html.decorator';
@@ -0,0 +1,139 @@
1
+ import { Logger } from '@nestjs/common';
2
+ import { createModuleLogger } from '../classes/winston.logger.class';
3
+ import { getRequestId, getUserId, getTenantId, getCompanyId } from '../middlewares/logger.middleware';
4
+ function createLoggerAdapter(className, moduleName) {
5
+ if (moduleName) {
6
+ const winstonLogger = createModuleLogger(moduleName);
7
+ return {
8
+ log: (level, message, meta)=>{
9
+ winstonLogger.log(level, message, {
10
+ context: className,
11
+ ...meta
12
+ });
13
+ },
14
+ error: (message, stack, meta)=>{
15
+ winstonLogger.error(message, {
16
+ context: className,
17
+ stack,
18
+ ...meta
19
+ });
20
+ }
21
+ };
22
+ }
23
+ const nestLogger = new Logger(className);
24
+ return {
25
+ log: (level, message, meta)=>{
26
+ nestLogger[level](message, meta);
27
+ },
28
+ error: (message, stack, meta)=>{
29
+ nestLogger.error(message, stack, meta);
30
+ }
31
+ };
32
+ }
33
+ export function LogAction(options = {}) {
34
+ return function(target, propertyKey, descriptor) {
35
+ const originalMethod = descriptor.value;
36
+ const className = target.constructor.name;
37
+ const methodName = String(propertyKey);
38
+ descriptor.value = async function(...args) {
39
+ const startTime = Date.now();
40
+ // Resolve module: decorator option > instance property > undefined
41
+ const moduleName = options.module || this.moduleName;
42
+ const logger = createLoggerAdapter(className, moduleName);
43
+ const action = options.action || `${this.entityName || className}.${methodName}`;
44
+ const logLevel = options.logLevel || 'debug';
45
+ const context = {
46
+ requestId: getRequestId(),
47
+ userId: getUserId(),
48
+ tenantId: getTenantId(),
49
+ companyId: getCompanyId(),
50
+ method: methodName,
51
+ module: moduleName
52
+ };
53
+ const startMessage = `Executing action method "${action}"`;
54
+ const startContext = options.includeParams ? {
55
+ ...context,
56
+ params: sanitizeParams(args)
57
+ } : context;
58
+ logger.log(logLevel, startMessage, startContext);
59
+ try {
60
+ const result = await originalMethod.apply(this, args);
61
+ const duration = Date.now() - startTime;
62
+ const resultType = getResultType(result);
63
+ const successMessage = `Executed action method "${action}", returned result "${resultType}" in ${duration.toFixed(2)}ms.`;
64
+ const successContext = options.includeResult && result ? {
65
+ ...context,
66
+ duration: `${duration}ms`,
67
+ resultType,
68
+ resultPreview: getResultPreview(result)
69
+ } : {
70
+ ...context,
71
+ duration: `${duration}ms`,
72
+ resultType
73
+ };
74
+ logger.log(logLevel, successMessage, successContext);
75
+ return result;
76
+ } catch (error) {
77
+ const duration = Date.now() - startTime;
78
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
79
+ logger.error(`Failed action method "${action}" after ${duration.toFixed(2)}ms: ${errorMessage}`, error instanceof Error ? error.stack : undefined, {
80
+ ...context,
81
+ duration: `${duration}ms`,
82
+ error: errorMessage
83
+ });
84
+ throw error;
85
+ }
86
+ };
87
+ return descriptor;
88
+ };
89
+ }
90
+ function sanitizeParams(args) {
91
+ return args.map((arg)=>{
92
+ if (arg === null || arg === undefined) return arg;
93
+ if (typeof arg === 'object') {
94
+ const sanitized = {
95
+ ...arg
96
+ };
97
+ const sensitiveKeys = [
98
+ 'password',
99
+ 'secret',
100
+ 'token',
101
+ 'apiKey',
102
+ 'authorization'
103
+ ];
104
+ for (const key of Object.keys(sanitized)){
105
+ if (sensitiveKeys.some((sk)=>key.toLowerCase().includes(sk))) {
106
+ sanitized[key] = '[REDACTED]';
107
+ }
108
+ }
109
+ return sanitized;
110
+ }
111
+ return arg;
112
+ });
113
+ }
114
+ function getResultType(result) {
115
+ if (result === null) return 'null';
116
+ if (result === undefined) return 'undefined';
117
+ if (Array.isArray(result)) return `Array<${result.length} items>`;
118
+ if (typeof result === 'object') {
119
+ const name = result.constructor?.name;
120
+ return name && name !== 'Object' ? name : 'Object';
121
+ }
122
+ return typeof result;
123
+ }
124
+ function getResultPreview(result) {
125
+ if (Array.isArray(result)) {
126
+ return {
127
+ count: result.length,
128
+ sample: result.slice(0, 2)
129
+ };
130
+ }
131
+ if (typeof result === 'object' && result !== null) {
132
+ const keys = Object.keys(result).slice(0, 5);
133
+ return {
134
+ keys,
135
+ hasMore: Object.keys(result).length > 5
136
+ };
137
+ }
138
+ return result;
139
+ }
@@ -50,6 +50,8 @@ export class SingleResponseDto {
50
50
  constructor(){
51
51
  _define_property(this, "success", void 0);
52
52
  _define_property(this, "message", void 0);
53
+ _define_property(this, "messageKey", void 0);
54
+ _define_property(this, "messageVariables", void 0);
53
55
  _define_property(this, "data", void 0);
54
56
  _define_property(this, "_meta", void 0);
55
57
  }
@@ -66,6 +68,22 @@ _ts_decorate([
66
68
  }),
67
69
  _ts_metadata("design:type", String)
68
70
  ], SingleResponseDto.prototype, "message", void 0);
71
+ _ts_decorate([
72
+ ApiPropertyOptional({
73
+ example: 'user.create.success',
74
+ description: 'Translation key for localization'
75
+ }),
76
+ _ts_metadata("design:type", String)
77
+ ], SingleResponseDto.prototype, "messageKey", void 0);
78
+ _ts_decorate([
79
+ ApiPropertyOptional({
80
+ example: {
81
+ name: 'John'
82
+ },
83
+ description: 'Variables for message interpolation'
84
+ }),
85
+ _ts_metadata("design:type", typeof Record === "undefined" ? Object : Record)
86
+ ], SingleResponseDto.prototype, "messageVariables", void 0);
69
87
  _ts_decorate([
70
88
  ApiPropertyOptional(),
71
89
  _ts_metadata("design:type", typeof T === "undefined" ? Object : T)
@@ -129,6 +147,8 @@ export class ListResponseDto {
129
147
  constructor(){
130
148
  _define_property(this, "success", void 0);
131
149
  _define_property(this, "message", void 0);
150
+ _define_property(this, "messageKey", void 0);
151
+ _define_property(this, "messageVariables", void 0);
132
152
  _define_property(this, "data", void 0);
133
153
  _define_property(this, "meta", void 0);
134
154
  _define_property(this, "_meta", void 0);
@@ -146,6 +166,22 @@ _ts_decorate([
146
166
  }),
147
167
  _ts_metadata("design:type", String)
148
168
  ], ListResponseDto.prototype, "message", void 0);
169
+ _ts_decorate([
170
+ ApiPropertyOptional({
171
+ example: 'user.list.success',
172
+ description: 'Translation key for localization'
173
+ }),
174
+ _ts_metadata("design:type", String)
175
+ ], ListResponseDto.prototype, "messageKey", void 0);
176
+ _ts_decorate([
177
+ ApiPropertyOptional({
178
+ example: {
179
+ count: 10
180
+ },
181
+ description: 'Variables for message interpolation'
182
+ }),
183
+ _ts_metadata("design:type", typeof Record === "undefined" ? Object : Record)
184
+ ], ListResponseDto.prototype, "messageVariables", void 0);
149
185
  _ts_decorate([
150
186
  ApiPropertyOptional({
151
187
  isArray: true
@@ -196,6 +232,8 @@ export class BulkResponseDto {
196
232
  constructor(){
197
233
  _define_property(this, "success", void 0);
198
234
  _define_property(this, "message", void 0);
235
+ _define_property(this, "messageKey", void 0);
236
+ _define_property(this, "messageVariables", void 0);
199
237
  _define_property(this, "data", void 0);
200
238
  _define_property(this, "meta", void 0);
201
239
  _define_property(this, "_meta", void 0);
@@ -213,6 +251,22 @@ _ts_decorate([
213
251
  }),
214
252
  _ts_metadata("design:type", String)
215
253
  ], BulkResponseDto.prototype, "message", void 0);
254
+ _ts_decorate([
255
+ ApiPropertyOptional({
256
+ example: 'user.bulk.success',
257
+ description: 'Translation key for localization'
258
+ }),
259
+ _ts_metadata("design:type", String)
260
+ ], BulkResponseDto.prototype, "messageKey", void 0);
261
+ _ts_decorate([
262
+ ApiPropertyOptional({
263
+ example: {
264
+ count: 5
265
+ },
266
+ description: 'Variables for message interpolation'
267
+ }),
268
+ _ts_metadata("design:type", typeof Record === "undefined" ? Object : Record)
269
+ ], BulkResponseDto.prototype, "messageVariables", void 0);
216
270
  _ts_decorate([
217
271
  ApiPropertyOptional({
218
272
  isArray: true
@@ -238,6 +292,8 @@ export class MessageResponseDto {
238
292
  constructor(){
239
293
  _define_property(this, "success", void 0);
240
294
  _define_property(this, "message", void 0);
295
+ _define_property(this, "messageKey", void 0);
296
+ _define_property(this, "messageVariables", void 0);
241
297
  _define_property(this, "_meta", void 0);
242
298
  }
243
299
  }
@@ -253,6 +309,22 @@ _ts_decorate([
253
309
  }),
254
310
  _ts_metadata("design:type", String)
255
311
  ], MessageResponseDto.prototype, "message", void 0);
312
+ _ts_decorate([
313
+ ApiPropertyOptional({
314
+ example: 'user.delete.success',
315
+ description: 'Translation key for localization'
316
+ }),
317
+ _ts_metadata("design:type", String)
318
+ ], MessageResponseDto.prototype, "messageKey", void 0);
319
+ _ts_decorate([
320
+ ApiPropertyOptional({
321
+ example: {
322
+ count: 3
323
+ },
324
+ description: 'Variables for message interpolation'
325
+ }),
326
+ _ts_metadata("design:type", typeof Record === "undefined" ? Object : Record)
327
+ ], MessageResponseDto.prototype, "messageVariables", void 0);
256
328
  _ts_decorate([
257
329
  ApiPropertyOptional({
258
330
  type: RequestMetaDto
@@ -0,0 +1,109 @@
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
+ import { HttpException, HttpStatus } from '@nestjs/common';
15
+ import { ERROR_MESSAGES } from '../constants/message-keys';
16
+ export class BaseAppException extends HttpException {
17
+ constructor(options){
18
+ const status = options.status || HttpStatus.BAD_REQUEST;
19
+ super({
20
+ success: false,
21
+ message: options.message,
22
+ messageKey: options.messageKey || ERROR_MESSAGES.GENERIC,
23
+ messageParams: options.messageParams,
24
+ errors: options.errors
25
+ }, status), _define_property(this, "messageKey", void 0), _define_property(this, "messageParams", void 0), _define_property(this, "errors", void 0), _define_property(this, "metadata", void 0);
26
+ this.messageKey = options.messageKey || ERROR_MESSAGES.GENERIC;
27
+ this.messageParams = options.messageParams;
28
+ this.errors = options.errors;
29
+ this.metadata = options.metadata;
30
+ }
31
+ }
32
+ export class NotFoundException extends BaseAppException {
33
+ constructor(entity, id){
34
+ super({
35
+ message: id ? `${entity} with id "${id}" not found` : `${entity} not found`,
36
+ messageKey: ERROR_MESSAGES.NOT_FOUND,
37
+ status: HttpStatus.NOT_FOUND,
38
+ metadata: {
39
+ entity,
40
+ id
41
+ }
42
+ });
43
+ }
44
+ }
45
+ export class ValidationException extends BaseAppException {
46
+ constructor(errors){
47
+ super({
48
+ message: 'Validation failed',
49
+ messageKey: ERROR_MESSAGES.VALIDATION,
50
+ status: HttpStatus.BAD_REQUEST,
51
+ errors
52
+ });
53
+ }
54
+ }
55
+ export class UnauthorizedException extends BaseAppException {
56
+ constructor(message = 'Unauthorized access'){
57
+ super({
58
+ message,
59
+ messageKey: ERROR_MESSAGES.UNAUTHORIZED,
60
+ status: HttpStatus.UNAUTHORIZED
61
+ });
62
+ }
63
+ }
64
+ export class ForbiddenException extends BaseAppException {
65
+ constructor(message = 'Access forbidden'){
66
+ super({
67
+ message,
68
+ messageKey: ERROR_MESSAGES.FORBIDDEN,
69
+ status: HttpStatus.FORBIDDEN
70
+ });
71
+ }
72
+ }
73
+ export class ConflictException extends BaseAppException {
74
+ constructor(entity, field){
75
+ super({
76
+ message: field ? `${entity} with this ${field} already exists` : `${entity} already exists`,
77
+ messageKey: ERROR_MESSAGES.CONFLICT,
78
+ status: HttpStatus.CONFLICT,
79
+ metadata: {
80
+ entity,
81
+ field
82
+ }
83
+ });
84
+ }
85
+ }
86
+ export class InternalServerException extends BaseAppException {
87
+ constructor(message = 'Internal server error'){
88
+ super({
89
+ message,
90
+ messageKey: ERROR_MESSAGES.INTERNAL,
91
+ status: HttpStatus.INTERNAL_SERVER_ERROR
92
+ });
93
+ }
94
+ }
95
+ export class ServiceUnavailableException extends BaseAppException {
96
+ constructor(service){
97
+ super({
98
+ message: `${service} is temporarily unavailable`,
99
+ messageKey: ERROR_MESSAGES.SERVICE_UNAVAILABLE,
100
+ messageParams: {
101
+ service
102
+ },
103
+ status: HttpStatus.SERVICE_UNAVAILABLE,
104
+ metadata: {
105
+ service
106
+ }
107
+ });
108
+ }
109
+ }
@@ -1 +1,2 @@
1
+ export * from './base-app.exception';
1
2
  export * from './permission.exception';
@@ -1,37 +1,35 @@
1
1
  import { ForbiddenException, InternalServerErrorException } from '@nestjs/common';
2
- /**
3
- * Exception thrown when permission system is unavailable
4
- */ export class PermissionSystemUnavailableException extends InternalServerErrorException {
5
- constructor(message = 'Permission system temporarily unavailable. Please try again later.'){
2
+ import { ERROR_MESSAGES } from '../constants/message-keys';
3
+ export class PermissionSystemUnavailableException extends InternalServerErrorException {
4
+ constructor(){
6
5
  super({
7
6
  success: false,
8
- message,
9
- code: 'PERMISSION_SYSTEM_UNAVAILABLE'
7
+ message: 'Permission system temporarily unavailable',
8
+ messageKey: ERROR_MESSAGES.PERMISSION_SYSTEM_UNAVAILABLE
10
9
  });
11
10
  }
12
11
  }
13
- /**
14
- * Exception thrown when user lacks required permissions
15
- */ export class InsufficientPermissionsException extends ForbiddenException {
12
+ export class InsufficientPermissionsException extends ForbiddenException {
16
13
  constructor(missingPermissions, operator = 'AND'){
17
- const message = operator === 'OR' ? `Requires at least one of: ${missingPermissions.join(', ')}` : `Missing required permissions: ${missingPermissions.join(', ')}`;
14
+ const messageKey = operator === 'OR' ? ERROR_MESSAGES.INSUFFICIENT_PERMISSIONS_OR : ERROR_MESSAGES.INSUFFICIENT_PERMISSIONS;
18
15
  super({
19
16
  success: false,
20
- message,
21
- code: 'INSUFFICIENT_PERMISSIONS',
17
+ message: 'Insufficient permissions',
18
+ messageKey,
19
+ messageParams: {
20
+ permissions: missingPermissions.join(', ')
21
+ },
22
22
  missingPermissions,
23
23
  operator
24
24
  });
25
25
  }
26
26
  }
27
- /**
28
- * Exception thrown when no permissions found for user
29
- */ export class NoPermissionsFoundException extends ForbiddenException {
27
+ export class NoPermissionsFoundException extends ForbiddenException {
30
28
  constructor(){
31
29
  super({
32
30
  success: false,
33
- message: 'No permissions found. Please contact administrator.',
34
- code: 'NO_PERMISSIONS_FOUND'
31
+ message: 'No permissions found',
32
+ messageKey: ERROR_MESSAGES.NO_PERMISSIONS_FOUND
35
33
  });
36
34
  }
37
35
  }