@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.
- package/README.md +159 -79
- package/cjs/classes/api-controller.class.js +26 -8
- package/cjs/classes/api-service.class.js +100 -17
- package/cjs/classes/winston-logger-adapter.class.js +15 -20
- package/cjs/classes/winston.logger.class.js +103 -70
- package/cjs/constants/index.js +1 -0
- package/cjs/constants/message-keys.js +80 -0
- package/cjs/constants/permissions.js +32 -1
- package/cjs/decorators/index.js +1 -0
- package/cjs/decorators/log-action.decorator.js +149 -0
- package/cjs/dtos/response-payload.dto.js +72 -0
- package/cjs/exceptions/base-app.exception.js +145 -0
- package/cjs/exceptions/index.js +1 -0
- package/cjs/exceptions/permission.exception.js +12 -8
- package/cjs/filters/global-exception.filter.js +167 -0
- package/cjs/filters/index.js +18 -0
- package/cjs/guards/jwt-auth.guard.js +4 -1
- package/cjs/guards/permission.guard.js +6 -13
- package/cjs/index.js +1 -0
- package/cjs/interceptors/idempotency.interceptor.js +1 -1
- package/cjs/interceptors/index.js +0 -1
- package/cjs/interfaces/logger.interface.js +1 -4
- package/cjs/middlewares/logger.middleware.js +83 -26
- package/cjs/modules/datasource/multi-tenant-datasource.service.js +33 -11
- package/cjs/modules/utils/utils.service.js +4 -20
- package/cjs/utils/index.js +0 -1
- package/cjs/utils/query-helpers.util.js +8 -1
- package/classes/api-controller.class.d.ts +1 -0
- package/classes/api-service.class.d.ts +5 -10
- package/classes/winston-logger-adapter.class.d.ts +12 -11
- package/classes/winston.logger.class.d.ts +1 -0
- package/constants/index.d.ts +1 -0
- package/constants/message-keys.d.ts +81 -0
- package/constants/permissions.d.ts +36 -0
- package/decorators/index.d.ts +1 -0
- package/decorators/log-action.decorator.d.ts +8 -0
- package/dtos/response-payload.dto.d.ts +8 -0
- package/exceptions/base-app.exception.d.ts +41 -0
- package/exceptions/index.d.ts +1 -0
- package/exceptions/permission.exception.d.ts +1 -1
- package/fesm/classes/api-controller.class.js +26 -8
- package/fesm/classes/api-service.class.js +101 -18
- package/fesm/classes/winston-logger-adapter.class.js +18 -44
- package/fesm/classes/winston.logger.class.js +100 -68
- package/fesm/constants/index.js +2 -0
- package/fesm/constants/message-keys.js +59 -0
- package/fesm/constants/permissions.js +24 -1
- package/fesm/decorators/index.js +1 -0
- package/fesm/decorators/log-action.decorator.js +139 -0
- package/fesm/dtos/response-payload.dto.js +72 -0
- package/fesm/exceptions/base-app.exception.js +109 -0
- package/fesm/exceptions/index.js +1 -0
- package/fesm/exceptions/permission.exception.js +15 -17
- package/fesm/filters/global-exception.filter.js +157 -0
- package/fesm/filters/index.js +1 -0
- package/fesm/guards/jwt-auth.guard.js +5 -2
- package/fesm/guards/permission.guard.js +8 -15
- package/fesm/index.js +1 -0
- package/fesm/interceptors/idempotency.interceptor.js +2 -2
- package/fesm/interceptors/index.js +0 -1
- package/fesm/interfaces/logger.interface.js +1 -4
- package/fesm/middlewares/logger.middleware.js +83 -26
- package/fesm/modules/datasource/multi-tenant-datasource.service.js +34 -12
- package/fesm/modules/utils/utils.service.js +5 -21
- package/fesm/utils/index.js +0 -1
- package/fesm/utils/query-helpers.util.js +8 -1
- package/filters/global-exception.filter.d.ts +10 -0
- package/filters/index.d.ts +1 -0
- package/guards/permission.guard.d.ts +1 -3
- package/index.d.ts +1 -0
- package/interceptors/index.d.ts +0 -1
- package/interfaces/logger.interface.d.ts +5 -5
- package/modules/datasource/multi-tenant-datasource.service.d.ts +1 -2
- package/modules/utils/utils.service.d.ts +0 -1
- package/package.json +5 -3
- package/utils/index.d.ts +0 -1
- package/cjs/interceptors/query-performance.interceptor.js +0 -66
- package/cjs/utils/error-handler.util.js +0 -90
- package/fesm/interceptors/query-performance.interceptor.js +0 -56
- package/fesm/utils/error-handler.util.js +0 -82
- package/interceptors/query-performance.interceptor.d.ts +0 -8
- 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
|
};
|
package/fesm/decorators/index.js
CHANGED
|
@@ -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
|
+
}
|
package/fesm/exceptions/index.js
CHANGED
|
@@ -1,37 +1,35 @@
|
|
|
1
1
|
import { ForbiddenException, InternalServerErrorException } from '@nestjs/common';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
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
|
-
|
|
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
|
|
14
|
+
const messageKey = operator === 'OR' ? ERROR_MESSAGES.INSUFFICIENT_PERMISSIONS_OR : ERROR_MESSAGES.INSUFFICIENT_PERMISSIONS;
|
|
18
15
|
super({
|
|
19
16
|
success: false,
|
|
20
|
-
message,
|
|
21
|
-
|
|
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
|
|
34
|
-
|
|
31
|
+
message: 'No permissions found',
|
|
32
|
+
messageKey: ERROR_MESSAGES.NO_PERMISSIONS_FOUND
|
|
35
33
|
});
|
|
36
34
|
}
|
|
37
35
|
}
|