nestjs-exception-handler 3.0.0 → 4.1.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/README.md +184 -126
- package/dist/index.d.mts +56 -0
- package/dist/index.d.ts +56 -3
- package/dist/index.js +272 -18
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +261 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +38 -41
- package/dist/default-formatters/index.d.ts +0 -4
- package/dist/default-formatters/index.js +0 -11
- package/dist/default-formatters/initialization.d.ts +0 -3
- package/dist/default-formatters/initialization.js +0 -11
- package/dist/default-formatters/known.d.ts +0 -3
- package/dist/default-formatters/known.js +0 -43
- package/dist/default-formatters/unknown.d.ts +0 -2
- package/dist/default-formatters/unknown.js +0 -14
- package/dist/default-formatters/validation.d.ts +0 -3
- package/dist/default-formatters/validation.js +0 -15
- package/dist/formatter.d.ts +0 -24
- package/dist/formatter.js +0 -47
- package/dist/global-exception-filter.d.ts +0 -23
- package/dist/global-exception-filter.js +0 -249
- package/dist/helpers/index.d.ts +0 -3
- package/dist/helpers/index.js +0 -19
- package/dist/helpers/parse-http-exception.d.ts +0 -16
- package/dist/helpers/parse-http-exception.js +0 -99
- package/dist/helpers/parse-prisma-errors.d.ts +0 -5
- package/dist/helpers/parse-prisma-errors.js +0 -292
- package/dist/helpers/parse-validation-errors.d.ts +0 -10
- package/dist/helpers/parse-validation-errors.js +0 -19
package/dist/index.js
CHANGED
|
@@ -1,19 +1,273 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var __decorateClass = (decorators, target, key, kind) => {
|
|
20
|
+
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
|
|
21
|
+
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
|
22
|
+
if (decorator = decorators[i])
|
|
23
|
+
result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
24
|
+
if (kind && result)
|
|
25
|
+
__defProp(target, key, result);
|
|
26
|
+
return result;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
// src/index.ts
|
|
30
|
+
var src_exports = {};
|
|
31
|
+
__export(src_exports, {
|
|
32
|
+
DtoValidationFormatter: () => DtoValidationFormatter,
|
|
33
|
+
ExceptionHandlerModule: () => ExceptionHandlerModule,
|
|
34
|
+
GlobalExceptionFilter: () => GlobalExceptionFilter,
|
|
35
|
+
OtherExceptionFormatter: () => OtherExceptionFormatter,
|
|
36
|
+
PrismaExceptionFormatter: () => PrismaExceptionFormatter
|
|
37
|
+
});
|
|
38
|
+
module.exports = __toCommonJS(src_exports);
|
|
39
|
+
|
|
40
|
+
// src/formatters/prisma-exception.formatter.ts
|
|
41
|
+
var import_common = require("@nestjs/common");
|
|
42
|
+
var import_library = require("@prisma/client/runtime/library");
|
|
43
|
+
var PrismaExceptionFormatter = class {
|
|
44
|
+
formatError(exception) {
|
|
45
|
+
if (exception instanceof import_library.PrismaClientKnownRequestError) {
|
|
46
|
+
return this.formatPrismaError(exception);
|
|
47
|
+
}
|
|
48
|
+
if (exception instanceof import_library.PrismaClientValidationError || exception instanceof import_library.PrismaClientRustPanicError) {
|
|
49
|
+
return this.formatQueryError(exception);
|
|
50
|
+
}
|
|
51
|
+
if (exception instanceof import_library.PrismaClientInitializationError) {
|
|
52
|
+
return this.formatInitializationError(exception);
|
|
53
|
+
}
|
|
54
|
+
return this.formatUnknownError(exception);
|
|
55
|
+
}
|
|
56
|
+
formatPrismaError(exception) {
|
|
57
|
+
const code = exception.code;
|
|
58
|
+
const meta = exception.meta;
|
|
59
|
+
switch (code) {
|
|
60
|
+
case "P2002": {
|
|
61
|
+
const target = meta?.target;
|
|
62
|
+
const field = target?.[0] || "field";
|
|
63
|
+
return [
|
|
64
|
+
{
|
|
65
|
+
path: field,
|
|
66
|
+
message: `A record with this ${field} already exists.`
|
|
67
|
+
}
|
|
68
|
+
];
|
|
69
|
+
}
|
|
70
|
+
case "P2003": {
|
|
71
|
+
const fieldName = meta?.field_name;
|
|
72
|
+
return [
|
|
73
|
+
{
|
|
74
|
+
path: fieldName || "field",
|
|
75
|
+
message: `The referenced ${fieldName || "record"} does not exist.`
|
|
76
|
+
}
|
|
77
|
+
];
|
|
78
|
+
}
|
|
79
|
+
case "P2005": {
|
|
80
|
+
const fieldName = meta?.field_name;
|
|
81
|
+
return [
|
|
82
|
+
{
|
|
83
|
+
path: fieldName || "field",
|
|
84
|
+
message: `The value for ${fieldName || "field"} is invalid.`
|
|
85
|
+
}
|
|
86
|
+
];
|
|
87
|
+
}
|
|
88
|
+
case "P2006": {
|
|
89
|
+
const fieldName = meta?.field_name;
|
|
90
|
+
return [
|
|
91
|
+
{
|
|
92
|
+
path: fieldName || "field",
|
|
93
|
+
message: `The ${fieldName || "field"} field is required.`
|
|
94
|
+
}
|
|
95
|
+
];
|
|
96
|
+
}
|
|
97
|
+
case "P2025": {
|
|
98
|
+
return [
|
|
99
|
+
{
|
|
100
|
+
path: "record",
|
|
101
|
+
message: "The requested record does not exist."
|
|
102
|
+
}
|
|
103
|
+
];
|
|
104
|
+
}
|
|
105
|
+
default:
|
|
106
|
+
return [
|
|
107
|
+
{
|
|
108
|
+
path: "database",
|
|
109
|
+
message: "Database operation failed."
|
|
110
|
+
}
|
|
111
|
+
];
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
formatQueryError(exception) {
|
|
115
|
+
let message = "Invalid database query.";
|
|
116
|
+
if (exception instanceof import_library.PrismaClientRustPanicError) {
|
|
117
|
+
message = "Database engine panic occurred.";
|
|
118
|
+
}
|
|
119
|
+
return [
|
|
120
|
+
{
|
|
121
|
+
path: "database",
|
|
122
|
+
message
|
|
123
|
+
}
|
|
124
|
+
];
|
|
125
|
+
}
|
|
126
|
+
formatInitializationError(exception) {
|
|
127
|
+
return [
|
|
128
|
+
{
|
|
129
|
+
path: "database",
|
|
130
|
+
message: `Database initialization error: ${exception.message}`
|
|
131
|
+
}
|
|
132
|
+
];
|
|
133
|
+
}
|
|
134
|
+
formatUnknownError(exception) {
|
|
135
|
+
return [
|
|
136
|
+
{
|
|
137
|
+
path: "unknown",
|
|
138
|
+
message: exception instanceof Error ? exception.message : "An unexpected database error occurred."
|
|
139
|
+
}
|
|
140
|
+
];
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
PrismaExceptionFormatter = __decorateClass([
|
|
144
|
+
(0, import_common.Injectable)()
|
|
145
|
+
], PrismaExceptionFormatter);
|
|
146
|
+
|
|
147
|
+
// src/formatters/dto-validation.formatter.ts
|
|
148
|
+
var import_common2 = require("@nestjs/common");
|
|
149
|
+
var DtoValidationFormatter = class {
|
|
150
|
+
formatDtoValidationException(exception) {
|
|
151
|
+
const responseBody = exception.getResponse();
|
|
152
|
+
if (typeof responseBody === "object" && responseBody !== null && "message" in responseBody && Array.isArray(responseBody.message)) {
|
|
153
|
+
const messages = responseBody.message;
|
|
154
|
+
const firstMessage = messages[0];
|
|
155
|
+
if (firstMessage && typeof firstMessage === "object" && firstMessage !== null && "property" in firstMessage) {
|
|
156
|
+
const validationErrors = messages;
|
|
157
|
+
return validationErrors.map((error) => ({
|
|
158
|
+
path: error.property,
|
|
159
|
+
message: error.constraints ? Object.values(error.constraints).join(", ") : "Validation error"
|
|
160
|
+
}));
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return [
|
|
164
|
+
{
|
|
165
|
+
path: "http_error",
|
|
166
|
+
message: typeof responseBody === "object" && responseBody !== null && "message" in responseBody ? String(responseBody.message) : "An HTTP error occurred"
|
|
167
|
+
}
|
|
168
|
+
];
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
DtoValidationFormatter = __decorateClass([
|
|
172
|
+
(0, import_common2.Injectable)()
|
|
173
|
+
], DtoValidationFormatter);
|
|
174
|
+
|
|
175
|
+
// src/formatters/other-exception.formatter.ts
|
|
176
|
+
var import_common3 = require("@nestjs/common");
|
|
177
|
+
var OtherExceptionFormatter = class {
|
|
178
|
+
formatOtherError(exception) {
|
|
179
|
+
if (exception && typeof exception === "object" && "path" in exception && "message" in exception) {
|
|
180
|
+
return [
|
|
181
|
+
{
|
|
182
|
+
path: String(exception.path),
|
|
183
|
+
message: String(exception.message)
|
|
184
|
+
}
|
|
185
|
+
];
|
|
186
|
+
}
|
|
187
|
+
const message = exception && typeof exception === "object" && "message" in exception ? String(exception.message) : "An unexpected error occurred";
|
|
188
|
+
return [
|
|
189
|
+
{
|
|
190
|
+
path: "unknown",
|
|
191
|
+
message
|
|
192
|
+
}
|
|
193
|
+
];
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
OtherExceptionFormatter = __decorateClass([
|
|
197
|
+
(0, import_common3.Injectable)()
|
|
198
|
+
], OtherExceptionFormatter);
|
|
199
|
+
|
|
200
|
+
// src/exception-filter/global-exception.filter.ts
|
|
201
|
+
var import_common4 = require("@nestjs/common");
|
|
202
|
+
var import_library2 = require("@prisma/client/runtime/library");
|
|
203
|
+
var GlobalExceptionFilter = class {
|
|
204
|
+
constructor(prismaExceptionFormatter, dtoValidationFormatter, otherValidationFormatter) {
|
|
205
|
+
this.prismaExceptionFormatter = prismaExceptionFormatter;
|
|
206
|
+
this.dtoValidationFormatter = dtoValidationFormatter;
|
|
207
|
+
this.otherValidationFormatter = otherValidationFormatter;
|
|
208
|
+
this.logger = new import_common4.Logger(GlobalExceptionFilter.name);
|
|
209
|
+
}
|
|
210
|
+
getErrorMessage(exception) {
|
|
211
|
+
if (exception instanceof import_library2.PrismaClientKnownRequestError || exception instanceof import_library2.PrismaClientValidationError || exception instanceof import_library2.PrismaClientRustPanicError || exception instanceof import_library2.PrismaClientUnknownRequestError || exception instanceof import_library2.PrismaClientInitializationError) {
|
|
212
|
+
return "Database error";
|
|
213
|
+
}
|
|
214
|
+
if (exception instanceof import_common4.HttpException) {
|
|
215
|
+
return exception.message || "HTTP error";
|
|
216
|
+
}
|
|
217
|
+
return "Internal server error";
|
|
218
|
+
}
|
|
219
|
+
catch(exception, host) {
|
|
220
|
+
const ctx = host.switchToHttp();
|
|
221
|
+
const response = ctx.getResponse();
|
|
222
|
+
const request = ctx.getRequest();
|
|
223
|
+
const status = exception instanceof import_common4.HttpException ? exception.getStatus() : import_common4.HttpStatus.INTERNAL_SERVER_ERROR;
|
|
224
|
+
let errorMessages = [{ path: "unknown", message: "Internal server error" }];
|
|
225
|
+
if (exception instanceof import_library2.PrismaClientKnownRequestError || exception instanceof import_library2.PrismaClientValidationError || exception instanceof import_library2.PrismaClientRustPanicError || exception instanceof import_library2.PrismaClientUnknownRequestError || exception instanceof import_library2.PrismaClientInitializationError) {
|
|
226
|
+
errorMessages = this.prismaExceptionFormatter.formatError(exception);
|
|
227
|
+
} else if (exception instanceof import_common4.HttpException) {
|
|
228
|
+
errorMessages = this.dtoValidationFormatter.formatDtoValidationException(
|
|
229
|
+
exception
|
|
230
|
+
);
|
|
231
|
+
} else {
|
|
232
|
+
errorMessages = this.otherValidationFormatter.formatOtherError(exception);
|
|
233
|
+
}
|
|
234
|
+
this.logger.error(
|
|
235
|
+
`${request.method} ${request.url}`,
|
|
236
|
+
JSON.stringify(errorMessages),
|
|
237
|
+
"ExceptionFilter"
|
|
238
|
+
);
|
|
239
|
+
response.status(status).json({
|
|
240
|
+
success: false,
|
|
241
|
+
message: this.getErrorMessage(exception),
|
|
242
|
+
errorMessages
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
};
|
|
246
|
+
GlobalExceptionFilter = __decorateClass([
|
|
247
|
+
(0, import_common4.Catch)()
|
|
248
|
+
], GlobalExceptionFilter);
|
|
249
|
+
|
|
250
|
+
// src/exception-handler.module.ts
|
|
251
|
+
var import_common5 = require("@nestjs/common");
|
|
252
|
+
var ExceptionHandlerModule = class {
|
|
253
|
+
};
|
|
254
|
+
ExceptionHandlerModule = __decorateClass([
|
|
255
|
+
(0, import_common5.Module)({
|
|
256
|
+
providers: [
|
|
257
|
+
GlobalExceptionFilter,
|
|
258
|
+
PrismaExceptionFormatter,
|
|
259
|
+
DtoValidationFormatter,
|
|
260
|
+
OtherExceptionFormatter
|
|
261
|
+
],
|
|
262
|
+
exports: [GlobalExceptionFilter]
|
|
263
|
+
})
|
|
264
|
+
], ExceptionHandlerModule);
|
|
265
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
266
|
+
0 && (module.exports = {
|
|
267
|
+
DtoValidationFormatter,
|
|
268
|
+
ExceptionHandlerModule,
|
|
269
|
+
GlobalExceptionFilter,
|
|
270
|
+
OtherExceptionFormatter,
|
|
271
|
+
PrismaExceptionFormatter
|
|
272
|
+
});
|
|
273
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/formatters/prisma-exception.formatter.ts","../src/formatters/dto-validation.formatter.ts","../src/formatters/other-exception.formatter.ts","../src/exception-filter/global-exception.filter.ts","../src/exception-handler.module.ts"],"sourcesContent":["// Interfaces\nexport * from './interfaces';\n\n// Formatters\nexport * from './formatters/prisma-exception.formatter';\nexport * from './formatters/dto-validation.formatter';\nexport * from './formatters/other-exception.formatter';\n\n// Filters\nexport * from './exception-filter/global-exception.filter';\n\n// Module\nexport * from './exception-handler.module';\n","import { Injectable } from '@nestjs/common';\nimport {\n PrismaClientKnownRequestError,\n PrismaClientValidationError,\n PrismaClientRustPanicError,\n PrismaClientInitializationError,\n} from '@prisma/client/runtime/library';\nimport { IErrorMessage } from '../interfaces/error-message.interface';\n\ntype PrismaError =\n | PrismaClientKnownRequestError\n | PrismaClientValidationError\n | PrismaClientRustPanicError\n | PrismaClientInitializationError\n | unknown;\n\n@Injectable()\nexport class PrismaExceptionFormatter {\n formatError(exception: PrismaError): IErrorMessage[] {\n if (exception instanceof PrismaClientKnownRequestError) {\n return this.formatPrismaError(exception);\n }\n\n if (\n exception instanceof PrismaClientValidationError ||\n exception instanceof PrismaClientRustPanicError\n ) {\n return this.formatQueryError(exception);\n }\n\n if (exception instanceof PrismaClientInitializationError) {\n return this.formatInitializationError(exception);\n }\n\n return this.formatUnknownError(exception);\n }\n\n private formatPrismaError(exception: PrismaClientKnownRequestError): IErrorMessage[] {\n const code = exception.code;\n const meta = exception.meta as Record<string, unknown> | undefined;\n\n switch (code) {\n case 'P2002': {\n const target = meta?.target as string[] | undefined;\n const field = target?.[0] || 'field';\n return [\n {\n path: field,\n message: `A record with this ${field} already exists.`,\n },\n ];\n }\n case 'P2003': {\n const fieldName = meta?.field_name as string | undefined;\n return [\n {\n path: fieldName || 'field',\n message: `The referenced ${fieldName || 'record'} does not exist.`,\n },\n ];\n }\n case 'P2005': {\n const fieldName = meta?.field_name as string | undefined;\n return [\n {\n path: fieldName || 'field',\n message: `The value for ${fieldName || 'field'} is invalid.`,\n },\n ];\n }\n case 'P2006': {\n const fieldName = meta?.field_name as string | undefined;\n return [\n {\n path: fieldName || 'field',\n message: `The ${fieldName || 'field'} field is required.`,\n },\n ];\n }\n case 'P2025': {\n return [\n {\n path: 'record',\n message: 'The requested record does not exist.',\n },\n ];\n }\n default:\n return [\n {\n path: 'database',\n message: 'Database operation failed.',\n },\n ];\n }\n }\n\n private formatQueryError(\n exception: PrismaClientValidationError | PrismaClientRustPanicError,\n ): IErrorMessage[] {\n let message = 'Invalid database query.';\n\n if (exception instanceof PrismaClientRustPanicError) {\n message = 'Database engine panic occurred.';\n }\n\n return [\n {\n path: 'database',\n message,\n },\n ];\n }\n\n private formatInitializationError(exception: PrismaClientInitializationError): IErrorMessage[] {\n return [\n {\n path: 'database',\n message: `Database initialization error: ${exception.message}`,\n },\n ];\n }\n\n private formatUnknownError(exception: unknown): IErrorMessage[] {\n return [\n {\n path: 'unknown',\n message:\n exception instanceof Error ? exception.message : 'An unexpected database error occurred.',\n },\n ];\n }\n}\n","import { Injectable } from '@nestjs/common';\nimport { HttpException } from '@nestjs/common';\nimport { IErrorMessage } from '../interfaces/error-message.interface';\n\ninterface ValidationError {\n property: string;\n constraints?: Record<string, string>;\n children?: ValidationError[];\n}\n\n@Injectable()\nexport class DtoValidationFormatter {\n formatDtoValidationException(exception: HttpException): IErrorMessage[] {\n const responseBody: unknown = exception.getResponse();\n\n if (\n typeof responseBody === 'object' &&\n responseBody !== null &&\n 'message' in responseBody &&\n Array.isArray((responseBody as Record<string, unknown>).message)\n ) {\n const messages = (responseBody as Record<string, unknown>).message as unknown[];\n const firstMessage = messages[0];\n\n if (\n firstMessage &&\n typeof firstMessage === 'object' &&\n firstMessage !== null &&\n 'property' in firstMessage\n ) {\n const validationErrors = messages as ValidationError[];\n return validationErrors.map((error: ValidationError) => ({\n path: error.property,\n message: error.constraints\n ? Object.values(error.constraints).join(', ')\n : 'Validation error',\n }));\n }\n }\n\n return [\n {\n path: 'http_error',\n message:\n typeof responseBody === 'object' && responseBody !== null && 'message' in responseBody\n ? String((responseBody as Record<string, unknown>).message)\n : 'An HTTP error occurred',\n },\n ];\n }\n}\n","import { Injectable } from '@nestjs/common';\nimport { IErrorMessage } from '../interfaces/error-message.interface';\n\n@Injectable()\nexport class OtherExceptionFormatter {\n formatOtherError(exception: unknown): IErrorMessage[] {\n if (\n exception &&\n typeof exception === 'object' &&\n 'path' in exception &&\n 'message' in exception\n ) {\n return [\n {\n path: String((exception as Record<string, unknown>).path),\n message: String((exception as Record<string, unknown>).message),\n },\n ];\n }\n\n const message =\n exception && typeof exception === 'object' && 'message' in exception\n ? String((exception as Record<string, unknown>).message)\n : 'An unexpected error occurred';\n\n return [\n {\n path: 'unknown',\n message,\n },\n ];\n }\n}\n","import {\n ExceptionFilter,\n Catch,\n ArgumentsHost,\n HttpException,\n HttpStatus,\n Logger,\n} from '@nestjs/common';\nimport { Request, Response } from 'express';\nimport {\n PrismaClientKnownRequestError,\n PrismaClientValidationError,\n PrismaClientRustPanicError,\n PrismaClientUnknownRequestError,\n PrismaClientInitializationError,\n} from '@prisma/client/runtime/library';\nimport { PrismaExceptionFormatter } from '../formatters/prisma-exception.formatter';\nimport { DtoValidationFormatter } from '../formatters/dto-validation.formatter';\nimport { OtherExceptionFormatter } from '../formatters/other-exception.formatter';\nimport { IErrorMessage } from '../interfaces/error-message.interface';\n\n@Catch()\nexport class GlobalExceptionFilter implements ExceptionFilter {\n constructor(\n private readonly prismaExceptionFormatter: PrismaExceptionFormatter,\n private readonly dtoValidationFormatter: DtoValidationFormatter,\n private readonly otherValidationFormatter: OtherExceptionFormatter,\n ) {}\n\n private readonly logger = new Logger(GlobalExceptionFilter.name);\n\n private getErrorMessage(exception: unknown): string {\n if (\n exception instanceof PrismaClientKnownRequestError ||\n exception instanceof PrismaClientValidationError ||\n exception instanceof PrismaClientRustPanicError ||\n exception instanceof PrismaClientUnknownRequestError ||\n exception instanceof PrismaClientInitializationError\n ) {\n return 'Database error';\n }\n\n if (exception instanceof HttpException) {\n return (exception as HttpException).message || 'HTTP error';\n }\n\n return 'Internal server error';\n }\n\n catch(exception: unknown, host: ArgumentsHost): void {\n const ctx = host.switchToHttp();\n\n const response = ctx.getResponse<Response>();\n const request = ctx.getRequest<Request>();\n\n const status =\n exception instanceof HttpException ? exception.getStatus() : HttpStatus.INTERNAL_SERVER_ERROR;\n\n let errorMessages: IErrorMessage[] = [{ path: 'unknown', message: 'Internal server error' }];\n\n if (\n exception instanceof PrismaClientKnownRequestError ||\n exception instanceof PrismaClientValidationError ||\n exception instanceof PrismaClientRustPanicError ||\n exception instanceof PrismaClientUnknownRequestError ||\n exception instanceof PrismaClientInitializationError\n ) {\n errorMessages = this.prismaExceptionFormatter.formatError(exception);\n } else if (exception instanceof HttpException) {\n errorMessages = this.dtoValidationFormatter.formatDtoValidationException(\n exception as HttpException,\n );\n } else {\n errorMessages = this.otherValidationFormatter.formatOtherError(exception);\n }\n\n this.logger.error(\n `${request.method} ${request.url}`,\n JSON.stringify(errorMessages),\n 'ExceptionFilter',\n );\n\n response.status(status).json({\n success: false,\n message: this.getErrorMessage(exception),\n errorMessages,\n });\n }\n}\n","import { Module } from '@nestjs/common';\nimport { GlobalExceptionFilter } from './exception-filter/global-exception.filter';\nimport { PrismaExceptionFormatter } from './formatters/prisma-exception.formatter';\nimport { DtoValidationFormatter } from './formatters/dto-validation.formatter';\nimport { OtherExceptionFormatter } from './formatters/other-exception.formatter';\n\n@Module({\n providers: [\n GlobalExceptionFilter,\n PrismaExceptionFormatter,\n DtoValidationFormatter,\n OtherExceptionFormatter,\n ],\n exports: [GlobalExceptionFilter],\n})\nexport class ExceptionHandlerModule {}\n"],"mappings":"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","names":["import_common","import_common","import_common","import_library","import_common"]}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __decorateClass = (decorators, target, key, kind) => {
|
|
4
|
+
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
|
|
5
|
+
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
|
6
|
+
if (decorator = decorators[i])
|
|
7
|
+
result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
8
|
+
if (kind && result)
|
|
9
|
+
__defProp(target, key, result);
|
|
10
|
+
return result;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
// src/formatters/prisma-exception.formatter.ts
|
|
14
|
+
import { Injectable } from "@nestjs/common";
|
|
15
|
+
import {
|
|
16
|
+
PrismaClientKnownRequestError,
|
|
17
|
+
PrismaClientValidationError,
|
|
18
|
+
PrismaClientRustPanicError,
|
|
19
|
+
PrismaClientInitializationError
|
|
20
|
+
} from "@prisma/client/runtime/library";
|
|
21
|
+
var PrismaExceptionFormatter = class {
|
|
22
|
+
formatError(exception) {
|
|
23
|
+
if (exception instanceof PrismaClientKnownRequestError) {
|
|
24
|
+
return this.formatPrismaError(exception);
|
|
25
|
+
}
|
|
26
|
+
if (exception instanceof PrismaClientValidationError || exception instanceof PrismaClientRustPanicError) {
|
|
27
|
+
return this.formatQueryError(exception);
|
|
28
|
+
}
|
|
29
|
+
if (exception instanceof PrismaClientInitializationError) {
|
|
30
|
+
return this.formatInitializationError(exception);
|
|
31
|
+
}
|
|
32
|
+
return this.formatUnknownError(exception);
|
|
33
|
+
}
|
|
34
|
+
formatPrismaError(exception) {
|
|
35
|
+
const code = exception.code;
|
|
36
|
+
const meta = exception.meta;
|
|
37
|
+
switch (code) {
|
|
38
|
+
case "P2002": {
|
|
39
|
+
const target = meta?.target;
|
|
40
|
+
const field = target?.[0] || "field";
|
|
41
|
+
return [
|
|
42
|
+
{
|
|
43
|
+
path: field,
|
|
44
|
+
message: `A record with this ${field} already exists.`
|
|
45
|
+
}
|
|
46
|
+
];
|
|
47
|
+
}
|
|
48
|
+
case "P2003": {
|
|
49
|
+
const fieldName = meta?.field_name;
|
|
50
|
+
return [
|
|
51
|
+
{
|
|
52
|
+
path: fieldName || "field",
|
|
53
|
+
message: `The referenced ${fieldName || "record"} does not exist.`
|
|
54
|
+
}
|
|
55
|
+
];
|
|
56
|
+
}
|
|
57
|
+
case "P2005": {
|
|
58
|
+
const fieldName = meta?.field_name;
|
|
59
|
+
return [
|
|
60
|
+
{
|
|
61
|
+
path: fieldName || "field",
|
|
62
|
+
message: `The value for ${fieldName || "field"} is invalid.`
|
|
63
|
+
}
|
|
64
|
+
];
|
|
65
|
+
}
|
|
66
|
+
case "P2006": {
|
|
67
|
+
const fieldName = meta?.field_name;
|
|
68
|
+
return [
|
|
69
|
+
{
|
|
70
|
+
path: fieldName || "field",
|
|
71
|
+
message: `The ${fieldName || "field"} field is required.`
|
|
72
|
+
}
|
|
73
|
+
];
|
|
74
|
+
}
|
|
75
|
+
case "P2025": {
|
|
76
|
+
return [
|
|
77
|
+
{
|
|
78
|
+
path: "record",
|
|
79
|
+
message: "The requested record does not exist."
|
|
80
|
+
}
|
|
81
|
+
];
|
|
82
|
+
}
|
|
83
|
+
default:
|
|
84
|
+
return [
|
|
85
|
+
{
|
|
86
|
+
path: "database",
|
|
87
|
+
message: "Database operation failed."
|
|
88
|
+
}
|
|
89
|
+
];
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
formatQueryError(exception) {
|
|
93
|
+
let message = "Invalid database query.";
|
|
94
|
+
if (exception instanceof PrismaClientRustPanicError) {
|
|
95
|
+
message = "Database engine panic occurred.";
|
|
96
|
+
}
|
|
97
|
+
return [
|
|
98
|
+
{
|
|
99
|
+
path: "database",
|
|
100
|
+
message
|
|
101
|
+
}
|
|
102
|
+
];
|
|
103
|
+
}
|
|
104
|
+
formatInitializationError(exception) {
|
|
105
|
+
return [
|
|
106
|
+
{
|
|
107
|
+
path: "database",
|
|
108
|
+
message: `Database initialization error: ${exception.message}`
|
|
109
|
+
}
|
|
110
|
+
];
|
|
111
|
+
}
|
|
112
|
+
formatUnknownError(exception) {
|
|
113
|
+
return [
|
|
114
|
+
{
|
|
115
|
+
path: "unknown",
|
|
116
|
+
message: exception instanceof Error ? exception.message : "An unexpected database error occurred."
|
|
117
|
+
}
|
|
118
|
+
];
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
PrismaExceptionFormatter = __decorateClass([
|
|
122
|
+
Injectable()
|
|
123
|
+
], PrismaExceptionFormatter);
|
|
124
|
+
|
|
125
|
+
// src/formatters/dto-validation.formatter.ts
|
|
126
|
+
import { Injectable as Injectable2 } from "@nestjs/common";
|
|
127
|
+
var DtoValidationFormatter = class {
|
|
128
|
+
formatDtoValidationException(exception) {
|
|
129
|
+
const responseBody = exception.getResponse();
|
|
130
|
+
if (typeof responseBody === "object" && responseBody !== null && "message" in responseBody && Array.isArray(responseBody.message)) {
|
|
131
|
+
const messages = responseBody.message;
|
|
132
|
+
const firstMessage = messages[0];
|
|
133
|
+
if (firstMessage && typeof firstMessage === "object" && firstMessage !== null && "property" in firstMessage) {
|
|
134
|
+
const validationErrors = messages;
|
|
135
|
+
return validationErrors.map((error) => ({
|
|
136
|
+
path: error.property,
|
|
137
|
+
message: error.constraints ? Object.values(error.constraints).join(", ") : "Validation error"
|
|
138
|
+
}));
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return [
|
|
142
|
+
{
|
|
143
|
+
path: "http_error",
|
|
144
|
+
message: typeof responseBody === "object" && responseBody !== null && "message" in responseBody ? String(responseBody.message) : "An HTTP error occurred"
|
|
145
|
+
}
|
|
146
|
+
];
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
DtoValidationFormatter = __decorateClass([
|
|
150
|
+
Injectable2()
|
|
151
|
+
], DtoValidationFormatter);
|
|
152
|
+
|
|
153
|
+
// src/formatters/other-exception.formatter.ts
|
|
154
|
+
import { Injectable as Injectable3 } from "@nestjs/common";
|
|
155
|
+
var OtherExceptionFormatter = class {
|
|
156
|
+
formatOtherError(exception) {
|
|
157
|
+
if (exception && typeof exception === "object" && "path" in exception && "message" in exception) {
|
|
158
|
+
return [
|
|
159
|
+
{
|
|
160
|
+
path: String(exception.path),
|
|
161
|
+
message: String(exception.message)
|
|
162
|
+
}
|
|
163
|
+
];
|
|
164
|
+
}
|
|
165
|
+
const message = exception && typeof exception === "object" && "message" in exception ? String(exception.message) : "An unexpected error occurred";
|
|
166
|
+
return [
|
|
167
|
+
{
|
|
168
|
+
path: "unknown",
|
|
169
|
+
message
|
|
170
|
+
}
|
|
171
|
+
];
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
OtherExceptionFormatter = __decorateClass([
|
|
175
|
+
Injectable3()
|
|
176
|
+
], OtherExceptionFormatter);
|
|
177
|
+
|
|
178
|
+
// src/exception-filter/global-exception.filter.ts
|
|
179
|
+
import {
|
|
180
|
+
Catch,
|
|
181
|
+
HttpException,
|
|
182
|
+
HttpStatus,
|
|
183
|
+
Logger
|
|
184
|
+
} from "@nestjs/common";
|
|
185
|
+
import {
|
|
186
|
+
PrismaClientKnownRequestError as PrismaClientKnownRequestError2,
|
|
187
|
+
PrismaClientValidationError as PrismaClientValidationError2,
|
|
188
|
+
PrismaClientRustPanicError as PrismaClientRustPanicError2,
|
|
189
|
+
PrismaClientUnknownRequestError,
|
|
190
|
+
PrismaClientInitializationError as PrismaClientInitializationError2
|
|
191
|
+
} from "@prisma/client/runtime/library";
|
|
192
|
+
var GlobalExceptionFilter = class {
|
|
193
|
+
constructor(prismaExceptionFormatter, dtoValidationFormatter, otherValidationFormatter) {
|
|
194
|
+
this.prismaExceptionFormatter = prismaExceptionFormatter;
|
|
195
|
+
this.dtoValidationFormatter = dtoValidationFormatter;
|
|
196
|
+
this.otherValidationFormatter = otherValidationFormatter;
|
|
197
|
+
this.logger = new Logger(GlobalExceptionFilter.name);
|
|
198
|
+
}
|
|
199
|
+
getErrorMessage(exception) {
|
|
200
|
+
if (exception instanceof PrismaClientKnownRequestError2 || exception instanceof PrismaClientValidationError2 || exception instanceof PrismaClientRustPanicError2 || exception instanceof PrismaClientUnknownRequestError || exception instanceof PrismaClientInitializationError2) {
|
|
201
|
+
return "Database error";
|
|
202
|
+
}
|
|
203
|
+
if (exception instanceof HttpException) {
|
|
204
|
+
return exception.message || "HTTP error";
|
|
205
|
+
}
|
|
206
|
+
return "Internal server error";
|
|
207
|
+
}
|
|
208
|
+
catch(exception, host) {
|
|
209
|
+
const ctx = host.switchToHttp();
|
|
210
|
+
const response = ctx.getResponse();
|
|
211
|
+
const request = ctx.getRequest();
|
|
212
|
+
const status = exception instanceof HttpException ? exception.getStatus() : HttpStatus.INTERNAL_SERVER_ERROR;
|
|
213
|
+
let errorMessages = [{ path: "unknown", message: "Internal server error" }];
|
|
214
|
+
if (exception instanceof PrismaClientKnownRequestError2 || exception instanceof PrismaClientValidationError2 || exception instanceof PrismaClientRustPanicError2 || exception instanceof PrismaClientUnknownRequestError || exception instanceof PrismaClientInitializationError2) {
|
|
215
|
+
errorMessages = this.prismaExceptionFormatter.formatError(exception);
|
|
216
|
+
} else if (exception instanceof HttpException) {
|
|
217
|
+
errorMessages = this.dtoValidationFormatter.formatDtoValidationException(
|
|
218
|
+
exception
|
|
219
|
+
);
|
|
220
|
+
} else {
|
|
221
|
+
errorMessages = this.otherValidationFormatter.formatOtherError(exception);
|
|
222
|
+
}
|
|
223
|
+
this.logger.error(
|
|
224
|
+
`${request.method} ${request.url}`,
|
|
225
|
+
JSON.stringify(errorMessages),
|
|
226
|
+
"ExceptionFilter"
|
|
227
|
+
);
|
|
228
|
+
response.status(status).json({
|
|
229
|
+
success: false,
|
|
230
|
+
message: this.getErrorMessage(exception),
|
|
231
|
+
errorMessages
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
};
|
|
235
|
+
GlobalExceptionFilter = __decorateClass([
|
|
236
|
+
Catch()
|
|
237
|
+
], GlobalExceptionFilter);
|
|
238
|
+
|
|
239
|
+
// src/exception-handler.module.ts
|
|
240
|
+
import { Module } from "@nestjs/common";
|
|
241
|
+
var ExceptionHandlerModule = class {
|
|
242
|
+
};
|
|
243
|
+
ExceptionHandlerModule = __decorateClass([
|
|
244
|
+
Module({
|
|
245
|
+
providers: [
|
|
246
|
+
GlobalExceptionFilter,
|
|
247
|
+
PrismaExceptionFormatter,
|
|
248
|
+
DtoValidationFormatter,
|
|
249
|
+
OtherExceptionFormatter
|
|
250
|
+
],
|
|
251
|
+
exports: [GlobalExceptionFilter]
|
|
252
|
+
})
|
|
253
|
+
], ExceptionHandlerModule);
|
|
254
|
+
export {
|
|
255
|
+
DtoValidationFormatter,
|
|
256
|
+
ExceptionHandlerModule,
|
|
257
|
+
GlobalExceptionFilter,
|
|
258
|
+
OtherExceptionFormatter,
|
|
259
|
+
PrismaExceptionFormatter
|
|
260
|
+
};
|
|
261
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/formatters/prisma-exception.formatter.ts","../src/formatters/dto-validation.formatter.ts","../src/formatters/other-exception.formatter.ts","../src/exception-filter/global-exception.filter.ts","../src/exception-handler.module.ts"],"sourcesContent":["import { Injectable } from '@nestjs/common';\nimport {\n PrismaClientKnownRequestError,\n PrismaClientValidationError,\n PrismaClientRustPanicError,\n PrismaClientInitializationError,\n} from '@prisma/client/runtime/library';\nimport { IErrorMessage } from '../interfaces/error-message.interface';\n\ntype PrismaError =\n | PrismaClientKnownRequestError\n | PrismaClientValidationError\n | PrismaClientRustPanicError\n | PrismaClientInitializationError\n | unknown;\n\n@Injectable()\nexport class PrismaExceptionFormatter {\n formatError(exception: PrismaError): IErrorMessage[] {\n if (exception instanceof PrismaClientKnownRequestError) {\n return this.formatPrismaError(exception);\n }\n\n if (\n exception instanceof PrismaClientValidationError ||\n exception instanceof PrismaClientRustPanicError\n ) {\n return this.formatQueryError(exception);\n }\n\n if (exception instanceof PrismaClientInitializationError) {\n return this.formatInitializationError(exception);\n }\n\n return this.formatUnknownError(exception);\n }\n\n private formatPrismaError(exception: PrismaClientKnownRequestError): IErrorMessage[] {\n const code = exception.code;\n const meta = exception.meta as Record<string, unknown> | undefined;\n\n switch (code) {\n case 'P2002': {\n const target = meta?.target as string[] | undefined;\n const field = target?.[0] || 'field';\n return [\n {\n path: field,\n message: `A record with this ${field} already exists.`,\n },\n ];\n }\n case 'P2003': {\n const fieldName = meta?.field_name as string | undefined;\n return [\n {\n path: fieldName || 'field',\n message: `The referenced ${fieldName || 'record'} does not exist.`,\n },\n ];\n }\n case 'P2005': {\n const fieldName = meta?.field_name as string | undefined;\n return [\n {\n path: fieldName || 'field',\n message: `The value for ${fieldName || 'field'} is invalid.`,\n },\n ];\n }\n case 'P2006': {\n const fieldName = meta?.field_name as string | undefined;\n return [\n {\n path: fieldName || 'field',\n message: `The ${fieldName || 'field'} field is required.`,\n },\n ];\n }\n case 'P2025': {\n return [\n {\n path: 'record',\n message: 'The requested record does not exist.',\n },\n ];\n }\n default:\n return [\n {\n path: 'database',\n message: 'Database operation failed.',\n },\n ];\n }\n }\n\n private formatQueryError(\n exception: PrismaClientValidationError | PrismaClientRustPanicError,\n ): IErrorMessage[] {\n let message = 'Invalid database query.';\n\n if (exception instanceof PrismaClientRustPanicError) {\n message = 'Database engine panic occurred.';\n }\n\n return [\n {\n path: 'database',\n message,\n },\n ];\n }\n\n private formatInitializationError(exception: PrismaClientInitializationError): IErrorMessage[] {\n return [\n {\n path: 'database',\n message: `Database initialization error: ${exception.message}`,\n },\n ];\n }\n\n private formatUnknownError(exception: unknown): IErrorMessage[] {\n return [\n {\n path: 'unknown',\n message:\n exception instanceof Error ? exception.message : 'An unexpected database error occurred.',\n },\n ];\n }\n}\n","import { Injectable } from '@nestjs/common';\nimport { HttpException } from '@nestjs/common';\nimport { IErrorMessage } from '../interfaces/error-message.interface';\n\ninterface ValidationError {\n property: string;\n constraints?: Record<string, string>;\n children?: ValidationError[];\n}\n\n@Injectable()\nexport class DtoValidationFormatter {\n formatDtoValidationException(exception: HttpException): IErrorMessage[] {\n const responseBody: unknown = exception.getResponse();\n\n if (\n typeof responseBody === 'object' &&\n responseBody !== null &&\n 'message' in responseBody &&\n Array.isArray((responseBody as Record<string, unknown>).message)\n ) {\n const messages = (responseBody as Record<string, unknown>).message as unknown[];\n const firstMessage = messages[0];\n\n if (\n firstMessage &&\n typeof firstMessage === 'object' &&\n firstMessage !== null &&\n 'property' in firstMessage\n ) {\n const validationErrors = messages as ValidationError[];\n return validationErrors.map((error: ValidationError) => ({\n path: error.property,\n message: error.constraints\n ? Object.values(error.constraints).join(', ')\n : 'Validation error',\n }));\n }\n }\n\n return [\n {\n path: 'http_error',\n message:\n typeof responseBody === 'object' && responseBody !== null && 'message' in responseBody\n ? String((responseBody as Record<string, unknown>).message)\n : 'An HTTP error occurred',\n },\n ];\n }\n}\n","import { Injectable } from '@nestjs/common';\nimport { IErrorMessage } from '../interfaces/error-message.interface';\n\n@Injectable()\nexport class OtherExceptionFormatter {\n formatOtherError(exception: unknown): IErrorMessage[] {\n if (\n exception &&\n typeof exception === 'object' &&\n 'path' in exception &&\n 'message' in exception\n ) {\n return [\n {\n path: String((exception as Record<string, unknown>).path),\n message: String((exception as Record<string, unknown>).message),\n },\n ];\n }\n\n const message =\n exception && typeof exception === 'object' && 'message' in exception\n ? String((exception as Record<string, unknown>).message)\n : 'An unexpected error occurred';\n\n return [\n {\n path: 'unknown',\n message,\n },\n ];\n }\n}\n","import {\n ExceptionFilter,\n Catch,\n ArgumentsHost,\n HttpException,\n HttpStatus,\n Logger,\n} from '@nestjs/common';\nimport { Request, Response } from 'express';\nimport {\n PrismaClientKnownRequestError,\n PrismaClientValidationError,\n PrismaClientRustPanicError,\n PrismaClientUnknownRequestError,\n PrismaClientInitializationError,\n} from '@prisma/client/runtime/library';\nimport { PrismaExceptionFormatter } from '../formatters/prisma-exception.formatter';\nimport { DtoValidationFormatter } from '../formatters/dto-validation.formatter';\nimport { OtherExceptionFormatter } from '../formatters/other-exception.formatter';\nimport { IErrorMessage } from '../interfaces/error-message.interface';\n\n@Catch()\nexport class GlobalExceptionFilter implements ExceptionFilter {\n constructor(\n private readonly prismaExceptionFormatter: PrismaExceptionFormatter,\n private readonly dtoValidationFormatter: DtoValidationFormatter,\n private readonly otherValidationFormatter: OtherExceptionFormatter,\n ) {}\n\n private readonly logger = new Logger(GlobalExceptionFilter.name);\n\n private getErrorMessage(exception: unknown): string {\n if (\n exception instanceof PrismaClientKnownRequestError ||\n exception instanceof PrismaClientValidationError ||\n exception instanceof PrismaClientRustPanicError ||\n exception instanceof PrismaClientUnknownRequestError ||\n exception instanceof PrismaClientInitializationError\n ) {\n return 'Database error';\n }\n\n if (exception instanceof HttpException) {\n return (exception as HttpException).message || 'HTTP error';\n }\n\n return 'Internal server error';\n }\n\n catch(exception: unknown, host: ArgumentsHost): void {\n const ctx = host.switchToHttp();\n\n const response = ctx.getResponse<Response>();\n const request = ctx.getRequest<Request>();\n\n const status =\n exception instanceof HttpException ? exception.getStatus() : HttpStatus.INTERNAL_SERVER_ERROR;\n\n let errorMessages: IErrorMessage[] = [{ path: 'unknown', message: 'Internal server error' }];\n\n if (\n exception instanceof PrismaClientKnownRequestError ||\n exception instanceof PrismaClientValidationError ||\n exception instanceof PrismaClientRustPanicError ||\n exception instanceof PrismaClientUnknownRequestError ||\n exception instanceof PrismaClientInitializationError\n ) {\n errorMessages = this.prismaExceptionFormatter.formatError(exception);\n } else if (exception instanceof HttpException) {\n errorMessages = this.dtoValidationFormatter.formatDtoValidationException(\n exception as HttpException,\n );\n } else {\n errorMessages = this.otherValidationFormatter.formatOtherError(exception);\n }\n\n this.logger.error(\n `${request.method} ${request.url}`,\n JSON.stringify(errorMessages),\n 'ExceptionFilter',\n );\n\n response.status(status).json({\n success: false,\n message: this.getErrorMessage(exception),\n errorMessages,\n });\n }\n}\n","import { Module } from '@nestjs/common';\nimport { GlobalExceptionFilter } from './exception-filter/global-exception.filter';\nimport { PrismaExceptionFormatter } from './formatters/prisma-exception.formatter';\nimport { DtoValidationFormatter } from './formatters/dto-validation.formatter';\nimport { OtherExceptionFormatter } from './formatters/other-exception.formatter';\n\n@Module({\n providers: [\n GlobalExceptionFilter,\n PrismaExceptionFormatter,\n DtoValidationFormatter,\n OtherExceptionFormatter,\n ],\n exports: [GlobalExceptionFilter],\n})\nexport class ExceptionHandlerModule {}\n"],"mappings":"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","names":["Injectable","Injectable","Injectable","Injectable","PrismaClientKnownRequestError","PrismaClientValidationError","PrismaClientRustPanicError","PrismaClientInitializationError","PrismaClientKnownRequestError","PrismaClientValidationError","PrismaClientRustPanicError","PrismaClientInitializationError"]}
|