@myko.pk/response 1.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.
- package/LICENSE +21 -0
- package/README.md +256 -0
- package/dist/builders/response.builder.cjs +315 -0
- package/dist/builders/response.builder.cjs.map +1 -0
- package/dist/builders/response.builder.d.cts +1 -0
- package/dist/builders/response.builder.d.ts +1 -0
- package/dist/builders/response.builder.js +313 -0
- package/dist/builders/response.builder.js.map +1 -0
- package/dist/filters/index.cjs +391 -0
- package/dist/filters/index.cjs.map +1 -0
- package/dist/filters/index.d.cts +62 -0
- package/dist/filters/index.d.ts +62 -0
- package/dist/filters/index.js +391 -0
- package/dist/filters/index.js.map +1 -0
- package/dist/index.cjs +899 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +89 -0
- package/dist/index.d.ts +89 -0
- package/dist/index.js +883 -0
- package/dist/index.js.map +1 -0
- package/dist/response.builder-BX9d7Taz.d.cts +180 -0
- package/dist/response.builder-BX9d7Taz.d.ts +180 -0
- package/dist/views/views/error.hbs +111 -0
- package/package.json +100 -0
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
import { Catch, BadRequestException, HttpException, UnauthorizedException, ForbiddenException, HttpStatus } from '@nestjs/common';
|
|
2
|
+
import { Logger } from '@myko.pk/logger';
|
|
3
|
+
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
7
|
+
var __decorateClass = (decorators, target, key, kind) => {
|
|
8
|
+
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
|
|
9
|
+
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
|
10
|
+
if (decorator = decorators[i])
|
|
11
|
+
result = (decorator(result)) || result;
|
|
12
|
+
return result;
|
|
13
|
+
};
|
|
14
|
+
var ERROR_TITLES = {
|
|
15
|
+
400: "Bad Request",
|
|
16
|
+
401: "Unauthorized",
|
|
17
|
+
403: "Forbidden",
|
|
18
|
+
404: "Page Not Found",
|
|
19
|
+
405: "Method Not Allowed",
|
|
20
|
+
408: "Request Timeout",
|
|
21
|
+
409: "Conflict",
|
|
22
|
+
410: "Gone",
|
|
23
|
+
422: "Unprocessable Entity",
|
|
24
|
+
429: "Too Many Requests",
|
|
25
|
+
500: "Internal Server Error",
|
|
26
|
+
502: "Bad Gateway",
|
|
27
|
+
503: "Service Unavailable",
|
|
28
|
+
504: "Gateway Timeout"
|
|
29
|
+
};
|
|
30
|
+
var ERROR_DESCRIPTIONS = {
|
|
31
|
+
400: "The request could not be processed due to invalid data. Please check your input and try again.",
|
|
32
|
+
401: "You need to be signed in to access this page. Please sign in and try again.",
|
|
33
|
+
403: "You don't have permission to access this page. If you believe this is a mistake, contact support.",
|
|
34
|
+
404: "The page you're looking for doesn't exist or has been moved. Check the URL and try again.",
|
|
35
|
+
405: "This page does not support the request method used.",
|
|
36
|
+
408: "The server timed out waiting for your request. Please try again.",
|
|
37
|
+
409: "The request could not be completed due to a conflict with the current state of the resource.",
|
|
38
|
+
422: "The submitted data could not be processed. Please review your input and try again.",
|
|
39
|
+
429: "Too many requests. Please wait a moment before trying again.",
|
|
40
|
+
500: "Something went wrong on our end. Please try again later.",
|
|
41
|
+
502: "The server received an invalid response from an upstream server. Please try again later.",
|
|
42
|
+
503: "The server is temporarily unavailable. Please try again later.",
|
|
43
|
+
504: "The server timed out waiting for an upstream server. Please try again later."
|
|
44
|
+
};
|
|
45
|
+
function getErrorTitle(statusCode) {
|
|
46
|
+
return ERROR_TITLES[statusCode] || "Something Went Wrong";
|
|
47
|
+
}
|
|
48
|
+
__name(getErrorTitle, "getErrorTitle");
|
|
49
|
+
function getErrorDescription(statusCode) {
|
|
50
|
+
return ERROR_DESCRIPTIONS[statusCode] || "An unexpected error occurred. Please try again later.";
|
|
51
|
+
}
|
|
52
|
+
__name(getErrorDescription, "getErrorDescription");
|
|
53
|
+
function isBrowserRequest(request) {
|
|
54
|
+
const accept = request.headers?.accept;
|
|
55
|
+
return typeof accept === "string" && accept.includes("text/html");
|
|
56
|
+
}
|
|
57
|
+
__name(isBrowserRequest, "isBrowserRequest");
|
|
58
|
+
var GlobalExceptionFilter = class {
|
|
59
|
+
logger = new Logger(GlobalExceptionFilter.name);
|
|
60
|
+
catch(exception, host) {
|
|
61
|
+
const ctx = host.switchToHttp();
|
|
62
|
+
const response = ctx.getResponse();
|
|
63
|
+
const request = ctx.getRequest();
|
|
64
|
+
const requestId = request.headers["x-request-id"];
|
|
65
|
+
let statusCode = HttpStatus.INTERNAL_SERVER_ERROR;
|
|
66
|
+
let message = "Internal server error";
|
|
67
|
+
let errorCode = "INTERNAL_ERROR";
|
|
68
|
+
let details = void 0;
|
|
69
|
+
if (exception instanceof HttpException) {
|
|
70
|
+
statusCode = exception.getStatus();
|
|
71
|
+
const exceptionResponse = exception.getResponse();
|
|
72
|
+
if (typeof exceptionResponse === "object") {
|
|
73
|
+
const responseObj = exceptionResponse;
|
|
74
|
+
message = responseObj.message || exception.message;
|
|
75
|
+
details = responseObj.error || responseObj.errors;
|
|
76
|
+
errorCode = responseObj.code || exception.constructor.name.replace("Exception", "").toUpperCase();
|
|
77
|
+
if (exception instanceof BadRequestException && !responseObj.code) {
|
|
78
|
+
errorCode = "VALIDATION_ERROR";
|
|
79
|
+
message = "Validation failed";
|
|
80
|
+
}
|
|
81
|
+
} else {
|
|
82
|
+
message = exceptionResponse;
|
|
83
|
+
errorCode = exception.constructor.name.replace("Exception", "").toUpperCase();
|
|
84
|
+
}
|
|
85
|
+
} else if (exception instanceof Error) {
|
|
86
|
+
message = exception.message;
|
|
87
|
+
errorCode = exception.name || "ERROR";
|
|
88
|
+
}
|
|
89
|
+
const errorResponse = {
|
|
90
|
+
success: false,
|
|
91
|
+
statusCode,
|
|
92
|
+
message,
|
|
93
|
+
error: {
|
|
94
|
+
code: errorCode,
|
|
95
|
+
details
|
|
96
|
+
},
|
|
97
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
98
|
+
requestId
|
|
99
|
+
};
|
|
100
|
+
const logContext = {
|
|
101
|
+
statusCode,
|
|
102
|
+
message,
|
|
103
|
+
method: request.method,
|
|
104
|
+
url: request.url,
|
|
105
|
+
ip: request.ip,
|
|
106
|
+
userAgent: request.headers["user-agent"],
|
|
107
|
+
errorCode
|
|
108
|
+
};
|
|
109
|
+
if (statusCode >= 500) {
|
|
110
|
+
this.logger.error(`[${requestId}] ${errorCode}:`, logContext);
|
|
111
|
+
} else if (statusCode >= 400) {
|
|
112
|
+
this.logger.warn(`[${requestId}] ${errorCode}:`, logContext);
|
|
113
|
+
} else {
|
|
114
|
+
this.logger.debug(`[${requestId}] ${errorCode}:`, logContext);
|
|
115
|
+
}
|
|
116
|
+
if (response.headersSent) return;
|
|
117
|
+
if (isBrowserRequest(request)) {
|
|
118
|
+
const showMessage = statusCode < 500 || process.env.NODE_ENV !== "production";
|
|
119
|
+
const renderOptions = {
|
|
120
|
+
statusCode,
|
|
121
|
+
title: getErrorTitle(statusCode),
|
|
122
|
+
description: getErrorDescription(statusCode),
|
|
123
|
+
message: showMessage ? message : "Something went wrong. Please try again later.",
|
|
124
|
+
errorCode,
|
|
125
|
+
showMessage
|
|
126
|
+
};
|
|
127
|
+
response.setHeader(
|
|
128
|
+
"Content-Security-Policy",
|
|
129
|
+
"default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self'; connect-src 'self'"
|
|
130
|
+
);
|
|
131
|
+
response.status(statusCode);
|
|
132
|
+
response.render("error", renderOptions, (renderErr, html) => {
|
|
133
|
+
if (renderErr) {
|
|
134
|
+
this.logger.error(`[${requestId}] Failed to render error page:`, renderErr);
|
|
135
|
+
return response.json(errorResponse);
|
|
136
|
+
}
|
|
137
|
+
response.send(html);
|
|
138
|
+
});
|
|
139
|
+
} else {
|
|
140
|
+
response.status(statusCode).json(errorResponse);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
__name(GlobalExceptionFilter, "GlobalExceptionFilter");
|
|
145
|
+
GlobalExceptionFilter = __decorateClass([
|
|
146
|
+
Catch()
|
|
147
|
+
], GlobalExceptionFilter);
|
|
148
|
+
var ValidationExceptionFilter = class {
|
|
149
|
+
logger = new Logger(ValidationExceptionFilter.name);
|
|
150
|
+
catch(exception, host) {
|
|
151
|
+
const ctx = host.switchToHttp();
|
|
152
|
+
const response = ctx.getResponse();
|
|
153
|
+
const request = ctx.getRequest();
|
|
154
|
+
const requestId = request.headers["x-request-id"];
|
|
155
|
+
const exceptionResponse = exception.getResponse();
|
|
156
|
+
const rawErrors = exceptionResponse.message;
|
|
157
|
+
const errors = Array.isArray(rawErrors) ? rawErrors : typeof rawErrors === "string" ? [rawErrors] : [];
|
|
158
|
+
const formattedErrors = this.formatValidationErrors(errors);
|
|
159
|
+
const errorResponse = {
|
|
160
|
+
success: false,
|
|
161
|
+
statusCode: 400,
|
|
162
|
+
message: "Validation failed",
|
|
163
|
+
error: {
|
|
164
|
+
code: "VALIDATION_ERROR",
|
|
165
|
+
details: formattedErrors
|
|
166
|
+
},
|
|
167
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
168
|
+
requestId
|
|
169
|
+
};
|
|
170
|
+
this.logger.warn(`[${requestId}] Validation error:`, {
|
|
171
|
+
method: request.method,
|
|
172
|
+
url: request.url,
|
|
173
|
+
errors: formattedErrors
|
|
174
|
+
});
|
|
175
|
+
response.status(400).json(errorResponse);
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Format validation errors from class-validator
|
|
179
|
+
*/
|
|
180
|
+
formatValidationErrors(errors) {
|
|
181
|
+
const messages = [];
|
|
182
|
+
if (Array.isArray(errors)) {
|
|
183
|
+
errors.forEach((error) => {
|
|
184
|
+
if (typeof error === "string") {
|
|
185
|
+
messages.push(error);
|
|
186
|
+
} else if (error?.constraints) {
|
|
187
|
+
messages.push(...Object.values(error.constraints));
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
return messages;
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
__name(ValidationExceptionFilter, "ValidationExceptionFilter");
|
|
195
|
+
ValidationExceptionFilter = __decorateClass([
|
|
196
|
+
Catch(BadRequestException)
|
|
197
|
+
], ValidationExceptionFilter);
|
|
198
|
+
var HttpExceptionFilter = class {
|
|
199
|
+
logger = new Logger(HttpExceptionFilter.name);
|
|
200
|
+
catch(exception, host) {
|
|
201
|
+
const ctx = host.switchToHttp();
|
|
202
|
+
const response = ctx.getResponse();
|
|
203
|
+
const request = ctx.getRequest();
|
|
204
|
+
const requestId = request.headers["x-request-id"];
|
|
205
|
+
const statusCode = exception.getStatus();
|
|
206
|
+
const exceptionResponse = exception.getResponse();
|
|
207
|
+
const message = typeof exceptionResponse === "string" ? exceptionResponse : exceptionResponse.message || exception.message;
|
|
208
|
+
const errorCode = this.getErrorCode(exception, statusCode);
|
|
209
|
+
const errorResponse = {
|
|
210
|
+
success: false,
|
|
211
|
+
statusCode,
|
|
212
|
+
message,
|
|
213
|
+
error: {
|
|
214
|
+
code: errorCode,
|
|
215
|
+
details: exceptionResponse.error || exceptionResponse.errors
|
|
216
|
+
},
|
|
217
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
218
|
+
requestId
|
|
219
|
+
};
|
|
220
|
+
const logContext = {
|
|
221
|
+
statusCode,
|
|
222
|
+
message,
|
|
223
|
+
method: request.method,
|
|
224
|
+
url: request.url,
|
|
225
|
+
ip: request.ip
|
|
226
|
+
};
|
|
227
|
+
if (statusCode >= 500) {
|
|
228
|
+
this.logger.error(`[${requestId}] ${errorCode}:`, logContext);
|
|
229
|
+
} else if (statusCode >= 400) {
|
|
230
|
+
this.logger.warn(`[${requestId}] ${errorCode}:`, logContext);
|
|
231
|
+
}
|
|
232
|
+
response.status(statusCode).json(errorResponse);
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Get error code from exception type
|
|
236
|
+
*/
|
|
237
|
+
getErrorCode(exception, statusCode) {
|
|
238
|
+
const exceptionName = exception.constructor.name;
|
|
239
|
+
const errorCodeMap = {
|
|
240
|
+
400: "BAD_REQUEST",
|
|
241
|
+
401: "UNAUTHORIZED",
|
|
242
|
+
403: "FORBIDDEN",
|
|
243
|
+
404: "NOT_FOUND",
|
|
244
|
+
409: "CONFLICT",
|
|
245
|
+
422: "UNPROCESSABLE_ENTITY",
|
|
246
|
+
429: "TOO_MANY_REQUESTS",
|
|
247
|
+
500: "INTERNAL_SERVER_ERROR",
|
|
248
|
+
502: "BAD_GATEWAY",
|
|
249
|
+
503: "SERVICE_UNAVAILABLE"
|
|
250
|
+
};
|
|
251
|
+
return errorCodeMap[statusCode] || exceptionName.replace("Exception", "").toUpperCase();
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
__name(HttpExceptionFilter, "HttpExceptionFilter");
|
|
255
|
+
HttpExceptionFilter = __decorateClass([
|
|
256
|
+
Catch(HttpException)
|
|
257
|
+
], HttpExceptionFilter);
|
|
258
|
+
var DatabaseExceptionFilter = class {
|
|
259
|
+
logger = new Logger(DatabaseExceptionFilter.name);
|
|
260
|
+
catch(exception, host) {
|
|
261
|
+
const ctx = host.switchToHttp();
|
|
262
|
+
const response = ctx.getResponse();
|
|
263
|
+
const request = ctx.getRequest();
|
|
264
|
+
const requestId = request.headers["x-request-id"];
|
|
265
|
+
if (!this.isDatabaseError(exception)) {
|
|
266
|
+
throw exception;
|
|
267
|
+
}
|
|
268
|
+
const { statusCode, message, errorCode } = this.parseError(exception);
|
|
269
|
+
const errorResponse = {
|
|
270
|
+
success: false,
|
|
271
|
+
statusCode,
|
|
272
|
+
message,
|
|
273
|
+
error: {
|
|
274
|
+
code: errorCode
|
|
275
|
+
},
|
|
276
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
277
|
+
requestId
|
|
278
|
+
};
|
|
279
|
+
this.logger.error(`[${requestId}] Database error:`, {
|
|
280
|
+
statusCode,
|
|
281
|
+
message,
|
|
282
|
+
errorCode,
|
|
283
|
+
method: request.method,
|
|
284
|
+
url: request.url,
|
|
285
|
+
// Log full error details in development only
|
|
286
|
+
...process.env.NODE_ENV !== "production" && { details: exception.message }
|
|
287
|
+
});
|
|
288
|
+
response.status(statusCode).json(errorResponse);
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Check if exception is a database error
|
|
292
|
+
*/
|
|
293
|
+
isDatabaseError(exception) {
|
|
294
|
+
const errorName = exception.constructor.name;
|
|
295
|
+
const errorMessage = exception.message || "";
|
|
296
|
+
if (errorName.includes("QueryFailedError") || errorName.includes("EntityNotFound")) {
|
|
297
|
+
return true;
|
|
298
|
+
}
|
|
299
|
+
if (errorName.includes("PrismaClientKnownRequestError") || errorName.includes("PrismaClientValidationError")) {
|
|
300
|
+
return true;
|
|
301
|
+
}
|
|
302
|
+
if (errorMessage.includes("UNIQUE constraint failed") || errorMessage.includes("Foreign key constraint") || errorMessage.includes("Duplicate entry") || errorMessage.includes("violates unique constraint")) {
|
|
303
|
+
return true;
|
|
304
|
+
}
|
|
305
|
+
return false;
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Parse database error and return user-friendly message
|
|
309
|
+
*/
|
|
310
|
+
parseError(exception) {
|
|
311
|
+
const errorMessage = exception.message || "";
|
|
312
|
+
const errorCode = exception.code || "DATABASE_ERROR";
|
|
313
|
+
if (errorMessage.includes("UNIQUE constraint failed") || errorMessage.includes("Duplicate entry") || errorMessage.includes("violates unique constraint") || errorCode === "P2002") {
|
|
314
|
+
return {
|
|
315
|
+
statusCode: 409,
|
|
316
|
+
message: "This record already exists",
|
|
317
|
+
errorCode: "DUPLICATE_ENTRY"
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
if (errorMessage.includes("Foreign key constraint") || errorMessage.includes("FOREIGN KEY constraint failed") || errorCode === "P2003") {
|
|
321
|
+
return {
|
|
322
|
+
statusCode: 400,
|
|
323
|
+
message: "Invalid reference to related record",
|
|
324
|
+
errorCode: "INVALID_REFERENCE"
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
if (errorMessage.includes("No entity found") || errorCode === "P2025") {
|
|
328
|
+
return {
|
|
329
|
+
statusCode: 404,
|
|
330
|
+
message: "Record not found",
|
|
331
|
+
errorCode: "NOT_FOUND"
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
if (errorMessage.includes("Validation failed") || errorCode === "P2007") {
|
|
335
|
+
return {
|
|
336
|
+
statusCode: 400,
|
|
337
|
+
message: "Invalid data provided",
|
|
338
|
+
errorCode: "VALIDATION_ERROR"
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
return {
|
|
342
|
+
statusCode: 500,
|
|
343
|
+
message: "Database operation failed",
|
|
344
|
+
errorCode: "DATABASE_ERROR"
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
};
|
|
348
|
+
__name(DatabaseExceptionFilter, "DatabaseExceptionFilter");
|
|
349
|
+
DatabaseExceptionFilter = __decorateClass([
|
|
350
|
+
Catch()
|
|
351
|
+
], DatabaseExceptionFilter);
|
|
352
|
+
var AuthExceptionFilter = class {
|
|
353
|
+
logger = new Logger(AuthExceptionFilter.name);
|
|
354
|
+
catch(exception, host) {
|
|
355
|
+
const ctx = host.switchToHttp();
|
|
356
|
+
const response = ctx.getResponse();
|
|
357
|
+
const request = ctx.getRequest();
|
|
358
|
+
const requestId = request.headers["x-request-id"];
|
|
359
|
+
const statusCode = exception.getStatus();
|
|
360
|
+
const exceptionResponse = exception.getResponse();
|
|
361
|
+
const message = typeof exceptionResponse === "string" ? exceptionResponse : exceptionResponse.message || exception.message;
|
|
362
|
+
const errorCode = statusCode === 401 ? "UNAUTHORIZED" : "FORBIDDEN";
|
|
363
|
+
const errorResponse = {
|
|
364
|
+
success: false,
|
|
365
|
+
statusCode,
|
|
366
|
+
message,
|
|
367
|
+
error: {
|
|
368
|
+
code: errorCode
|
|
369
|
+
},
|
|
370
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
371
|
+
requestId
|
|
372
|
+
};
|
|
373
|
+
this.logger.warn(`[${requestId}] Auth error:`, {
|
|
374
|
+
statusCode,
|
|
375
|
+
message,
|
|
376
|
+
errorCode,
|
|
377
|
+
method: request.method,
|
|
378
|
+
url: request.url,
|
|
379
|
+
ip: request.ip
|
|
380
|
+
});
|
|
381
|
+
response.status(statusCode).json(errorResponse);
|
|
382
|
+
}
|
|
383
|
+
};
|
|
384
|
+
__name(AuthExceptionFilter, "AuthExceptionFilter");
|
|
385
|
+
AuthExceptionFilter = __decorateClass([
|
|
386
|
+
Catch(UnauthorizedException, ForbiddenException)
|
|
387
|
+
], AuthExceptionFilter);
|
|
388
|
+
|
|
389
|
+
export { AuthExceptionFilter, DatabaseExceptionFilter, GlobalExceptionFilter, HttpExceptionFilter, ValidationExceptionFilter };
|
|
390
|
+
//# sourceMappingURL=index.js.map
|
|
391
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/filters/global-exception.filter.ts","../../src/filters/validation.filter.ts","../../src/filters/http-exception.filter.ts","../../src/filters/database.filter.ts","../../src/filters/auth.filter.ts"],"names":["Logger","Catch","BadRequestException","HttpException"],"mappings":"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","file":"index.js","sourcesContent":["import { ExceptionFilter, Catch, ArgumentsHost, HttpException, HttpStatus, BadRequestException } from '@nestjs/common';\nimport { Logger } from '@myko.pk/logger';\nimport { Request, Response } from 'express';\n\nconst ERROR_TITLES: Record<number, string> = {\n 400: 'Bad Request',\n 401: 'Unauthorized',\n 403: 'Forbidden',\n 404: 'Page Not Found',\n 405: 'Method Not Allowed',\n 408: 'Request Timeout',\n 409: 'Conflict',\n 410: 'Gone',\n 422: 'Unprocessable Entity',\n 429: 'Too Many Requests',\n 500: 'Internal Server Error',\n 502: 'Bad Gateway',\n 503: 'Service Unavailable',\n 504: 'Gateway Timeout',\n};\n\nconst ERROR_DESCRIPTIONS: Record<number, string> = {\n 400: 'The request could not be processed due to invalid data. Please check your input and try again.',\n 401: 'You need to be signed in to access this page. Please sign in and try again.',\n 403: \"You don't have permission to access this page. If you believe this is a mistake, contact support.\",\n 404: \"The page you're looking for doesn't exist or has been moved. Check the URL and try again.\",\n 405: 'This page does not support the request method used.',\n 408: 'The server timed out waiting for your request. Please try again.',\n 409: 'The request could not be completed due to a conflict with the current state of the resource.',\n 422: 'The submitted data could not be processed. Please review your input and try again.',\n 429: 'Too many requests. Please wait a moment before trying again.',\n 500: 'Something went wrong on our end. Please try again later.',\n 502: 'The server received an invalid response from an upstream server. Please try again later.',\n 503: 'The server is temporarily unavailable. Please try again later.',\n 504: 'The server timed out waiting for an upstream server. Please try again later.',\n};\n\nfunction getErrorTitle(statusCode: number): string {\n return ERROR_TITLES[statusCode] || 'Something Went Wrong';\n}\n\nfunction getErrorDescription(statusCode: number): string {\n return ERROR_DESCRIPTIONS[statusCode] || 'An unexpected error occurred. Please try again later.';\n}\n\nfunction isBrowserRequest(request: Request): boolean {\n const accept = request.headers?.accept;\n return typeof accept === 'string' && accept.includes('text/html');\n}\n\n@Catch()\nexport class GlobalExceptionFilter implements ExceptionFilter {\n private readonly logger = new Logger(GlobalExceptionFilter.name);\n\n catch(exception: any, host: ArgumentsHost) {\n const ctx = host.switchToHttp();\n const response = ctx.getResponse<Response>();\n const request = ctx.getRequest<Request>();\n const requestId = request.headers['x-request-id'] as string | undefined;\n\n let statusCode = HttpStatus.INTERNAL_SERVER_ERROR;\n let message = 'Internal server error';\n let errorCode = 'INTERNAL_ERROR';\n let details: any = undefined;\n\n if (exception instanceof HttpException) {\n statusCode = exception.getStatus();\n const exceptionResponse = exception.getResponse();\n\n if (typeof exceptionResponse === 'object') {\n const responseObj = exceptionResponse as any;\n message = responseObj.message || exception.message;\n details = responseObj.error || responseObj.errors;\n errorCode = responseObj.code || exception.constructor.name.replace('Exception', '').toUpperCase();\n\n if (exception instanceof BadRequestException && !responseObj.code) {\n errorCode = 'VALIDATION_ERROR';\n message = 'Validation failed';\n }\n } else {\n message = exceptionResponse as string;\n errorCode = exception.constructor.name.replace('Exception', '').toUpperCase();\n }\n } else if (exception instanceof Error) {\n message = exception.message;\n errorCode = exception.name || 'ERROR';\n }\n\n const errorResponse = {\n success: false,\n statusCode,\n message,\n error: {\n code: errorCode,\n details: details,\n },\n timestamp: new Date().toISOString(),\n requestId,\n };\n\n // Log error with appropriate level\n const logContext = {\n statusCode,\n message,\n method: request.method,\n url: request.url,\n ip: request.ip,\n userAgent: request.headers['user-agent'],\n errorCode,\n };\n\n if (statusCode >= 500) {\n this.logger.error(`[${requestId}] ${errorCode}:`, logContext);\n } else if (statusCode >= 400) {\n this.logger.warn(`[${requestId}] ${errorCode}:`, logContext);\n } else {\n this.logger.debug(`[${requestId}] ${errorCode}:`, logContext);\n }\n\n if (response.headersSent) return;\n\n // Render error page for browser requests, JSON for API requests\n if (isBrowserRequest(request)) {\n const showMessage = statusCode < 500 || process.env.NODE_ENV !== 'production';\n const renderOptions = {\n statusCode,\n title: getErrorTitle(statusCode),\n description: getErrorDescription(statusCode),\n message: showMessage ? message : 'Something went wrong. Please try again later.',\n errorCode,\n showMessage,\n };\n\n response.setHeader('Content-Security-Policy',\n \"default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self'; connect-src 'self'\",\n );\n\n response.status(statusCode);\n response.render('error', renderOptions, (renderErr: any, html: string) => {\n if (renderErr) {\n this.logger.error(`[${requestId}] Failed to render error page:`, renderErr);\n return response.json(errorResponse);\n }\n response.send(html);\n });\n } else {\n response.status(statusCode).json(errorResponse);\n }\n }\n}\n","import { ExceptionFilter, Catch, ArgumentsHost, BadRequestException } from '@nestjs/common';\nimport { Logger } from '@myko.pk/logger';\nimport { Response } from 'express';\n\n/**\n * Validation Exception Filter\n * Handles validation errors from class-validator and pipes\n * Formats validation errors in a user-friendly way\n */\n@Catch(BadRequestException)\nexport class ValidationExceptionFilter implements ExceptionFilter {\n private readonly logger = new Logger(ValidationExceptionFilter.name);\n\n catch(exception: BadRequestException, host: ArgumentsHost) {\n const ctx = host.switchToHttp();\n const response = ctx.getResponse<Response>();\n const request = ctx.getRequest();\n const requestId = request.headers['x-request-id'];\n\n const exceptionResponse = exception.getResponse() as any;\n const rawErrors = exceptionResponse.message;\n const errors = Array.isArray(rawErrors) ? rawErrors : typeof rawErrors === 'string' ? [rawErrors] : [];\n\n // Format validation errors\n const formattedErrors = this.formatValidationErrors(errors);\n\n const errorResponse = {\n success: false,\n statusCode: 400,\n message: 'Validation failed',\n error: {\n code: 'VALIDATION_ERROR',\n details: formattedErrors,\n },\n timestamp: new Date().toISOString(),\n requestId,\n };\n\n this.logger.warn(`[${requestId}] Validation error:`, {\n method: request.method,\n url: request.url,\n errors: formattedErrors,\n });\n\n response.status(400).json(errorResponse);\n }\n\n /**\n * Format validation errors from class-validator\n */\n private formatValidationErrors(errors: any[]): string[] {\n const messages: string[] = [];\n\n if (Array.isArray(errors)) {\n errors.forEach((error) => {\n if (typeof error === 'string') {\n messages.push(error);\n } else if (error?.constraints) {\n messages.push(...Object.values(error.constraints) as string[]);\n }\n });\n }\n\n return messages;\n }\n}\n","import { ExceptionFilter, Catch, ArgumentsHost, HttpException } from '@nestjs/common';\nimport { Logger } from '@myko.pk/logger';\nimport { Response } from 'express';\n\n/**\n * HTTP Exception Filter\n * Handles all HTTP exceptions with consistent formatting\n */\n@Catch(HttpException)\nexport class HttpExceptionFilter implements ExceptionFilter {\n private readonly logger = new Logger(HttpExceptionFilter.name);\n\n catch(exception: HttpException, host: ArgumentsHost) {\n const ctx = host.switchToHttp();\n const response = ctx.getResponse<Response>();\n const request = ctx.getRequest();\n const requestId = request.headers['x-request-id'];\n\n const statusCode = exception.getStatus();\n const exceptionResponse = exception.getResponse() as any;\n\n const message = typeof exceptionResponse === 'string' \n ? exceptionResponse \n : exceptionResponse.message || exception.message;\n\n const errorCode = this.getErrorCode(exception, statusCode);\n\n const errorResponse = {\n success: false,\n statusCode,\n message,\n error: {\n code: errorCode,\n details: exceptionResponse.error || exceptionResponse.errors,\n },\n timestamp: new Date().toISOString(),\n requestId,\n };\n\n // Log based on status code\n const logContext = {\n statusCode,\n message,\n method: request.method,\n url: request.url,\n ip: request.ip,\n };\n\n if (statusCode >= 500) {\n this.logger.error(`[${requestId}] ${errorCode}:`, logContext);\n } else if (statusCode >= 400) {\n this.logger.warn(`[${requestId}] ${errorCode}:`, logContext);\n }\n\n response.status(statusCode).json(errorResponse);\n }\n\n /**\n * Get error code from exception type\n */\n private getErrorCode(exception: HttpException, statusCode: number): string {\n const exceptionName = exception.constructor.name;\n \n // Map common exceptions to error codes\n const errorCodeMap: Record<number, string> = {\n 400: 'BAD_REQUEST',\n 401: 'UNAUTHORIZED',\n 403: 'FORBIDDEN',\n 404: 'NOT_FOUND',\n 409: 'CONFLICT',\n 422: 'UNPROCESSABLE_ENTITY',\n 429: 'TOO_MANY_REQUESTS',\n 500: 'INTERNAL_SERVER_ERROR',\n 502: 'BAD_GATEWAY',\n 503: 'SERVICE_UNAVAILABLE',\n };\n\n return errorCodeMap[statusCode] || exceptionName.replace('Exception', '').toUpperCase();\n }\n}\n","import { ExceptionFilter, Catch, ArgumentsHost } from '@nestjs/common';\nimport { Logger } from '@myko.pk/logger';\nimport { Response } from 'express';\n\n/**\n * Database Exception Filter\n * Handles database errors (TypeORM, Prisma, etc.)\n * Prevents sensitive database information from leaking\n */\n@Catch()\nexport class DatabaseExceptionFilter implements ExceptionFilter {\n private readonly logger = new Logger(DatabaseExceptionFilter.name);\n\n catch(exception: any, host: ArgumentsHost) {\n const ctx = host.switchToHttp();\n const response = ctx.getResponse<Response>();\n const request = ctx.getRequest();\n const requestId = request.headers['x-request-id'];\n\n // Check if it's a database error\n if (!this.isDatabaseError(exception)) {\n throw exception; // Let other filters handle it\n }\n\n const { statusCode, message, errorCode } = this.parseError(exception);\n\n const errorResponse = {\n success: false,\n statusCode,\n message,\n error: {\n code: errorCode,\n },\n timestamp: new Date().toISOString(),\n requestId,\n };\n\n this.logger.error(`[${requestId}] Database error:`, {\n statusCode,\n message,\n errorCode,\n method: request.method,\n url: request.url,\n // Log full error details in development only\n ...(process.env.NODE_ENV !== 'production' && { details: exception.message }),\n });\n\n response.status(statusCode).json(errorResponse);\n }\n\n /**\n * Check if exception is a database error\n */\n private isDatabaseError(exception: any): boolean {\n const errorName = exception.constructor.name;\n const errorMessage = exception.message || '';\n\n // TypeORM errors\n if (errorName.includes('QueryFailedError') || errorName.includes('EntityNotFound')) {\n return true;\n }\n\n // Prisma errors\n if (errorName.includes('PrismaClientKnownRequestError') || errorName.includes('PrismaClientValidationError')) {\n return true;\n }\n\n // Generic database error indicators\n if (\n errorMessage.includes('UNIQUE constraint failed') ||\n errorMessage.includes('Foreign key constraint') ||\n errorMessage.includes('Duplicate entry') ||\n errorMessage.includes('violates unique constraint')\n ) {\n return true;\n }\n\n return false;\n }\n\n /**\n * Parse database error and return user-friendly message\n */\n private parseError(exception: any): { statusCode: number; message: string; errorCode: string } {\n const errorMessage = exception.message || '';\n const errorCode = exception.code || 'DATABASE_ERROR';\n\n // Unique constraint violation\n if (\n errorMessage.includes('UNIQUE constraint failed') ||\n errorMessage.includes('Duplicate entry') ||\n errorMessage.includes('violates unique constraint') ||\n errorCode === 'P2002'\n ) {\n return {\n statusCode: 409,\n message: 'This record already exists',\n errorCode: 'DUPLICATE_ENTRY',\n };\n }\n\n // Foreign key constraint\n if (\n errorMessage.includes('Foreign key constraint') ||\n errorMessage.includes('FOREIGN KEY constraint failed') ||\n errorCode === 'P2003'\n ) {\n return {\n statusCode: 400,\n message: 'Invalid reference to related record',\n errorCode: 'INVALID_REFERENCE',\n };\n }\n\n // Record not found\n if (errorMessage.includes('No entity found') || errorCode === 'P2025') {\n return {\n statusCode: 404,\n message: 'Record not found',\n errorCode: 'NOT_FOUND',\n };\n }\n\n // Validation error\n if (errorMessage.includes('Validation failed') || errorCode === 'P2007') {\n return {\n statusCode: 400,\n message: 'Invalid data provided',\n errorCode: 'VALIDATION_ERROR',\n };\n }\n\n // Generic database error\n return {\n statusCode: 500,\n message: 'Database operation failed',\n errorCode: 'DATABASE_ERROR',\n };\n }\n}\n","import { ExceptionFilter, Catch, ArgumentsHost, UnauthorizedException, ForbiddenException } from '@nestjs/common';\nimport { Logger } from '@myko.pk/logger';\nimport { Response } from 'express';\n\n/**\n * Authentication & Authorization Exception Filter\n * Handles auth-related errors with appropriate responses\n */\n@Catch(UnauthorizedException, ForbiddenException)\nexport class AuthExceptionFilter implements ExceptionFilter {\n private readonly logger = new Logger(AuthExceptionFilter.name);\n\n catch(exception: UnauthorizedException | ForbiddenException, host: ArgumentsHost) {\n const ctx = host.switchToHttp();\n const response = ctx.getResponse<Response>();\n const request = ctx.getRequest();\n const requestId = request.headers['x-request-id'];\n\n const statusCode = exception.getStatus();\n const exceptionResponse = exception.getResponse() as any;\n const message = typeof exceptionResponse === 'string' \n ? exceptionResponse \n : exceptionResponse.message || exception.message;\n\n const errorCode = statusCode === 401 ? 'UNAUTHORIZED' : 'FORBIDDEN';\n\n const errorResponse = {\n success: false,\n statusCode,\n message,\n error: {\n code: errorCode,\n },\n timestamp: new Date().toISOString(),\n requestId,\n };\n\n this.logger.warn(`[${requestId}] Auth error:`, {\n statusCode,\n message,\n errorCode,\n method: request.method,\n url: request.url,\n ip: request.ip,\n });\n\n response.status(statusCode).json(errorResponse);\n }\n}\n"]}
|