nestjs-exception-handler 1.0.1 → 4.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/dist/index.d.mts DELETED
@@ -1,96 +0,0 @@
1
- import { ExceptionFilter, ArgumentsHost, DynamicModule } from '@nestjs/common';
2
-
3
- interface ErrorMessage {
4
- path: string;
5
- message: string;
6
- }
7
- interface StandardErrorResponse {
8
- success: boolean;
9
- message: string;
10
- errorMessages: ErrorMessage[];
11
- }
12
-
13
- interface ExceptionFormatter {
14
- supports(exception: unknown): boolean;
15
- format(exception: unknown): ErrorMessage[];
16
- message(exception: unknown): string;
17
- }
18
-
19
- interface ExceptionHandlerConfig {
20
- enableLogging?: boolean;
21
- hideStackTrace?: boolean;
22
- }
23
-
24
- declare const DEFAULT_ERROR_MESSAGES: {
25
- UNKNOWN_ERROR: string;
26
- VALIDATION_ERROR: string;
27
- DATABASE_ERROR: string;
28
- NOT_FOUND: string;
29
- UNAUTHORIZED: string;
30
- FORBIDDEN: string;
31
- CONFLICT: string;
32
- BAD_REQUEST: string;
33
- };
34
- declare const PRISMA_ERROR_MESSAGES: Record<string, string>;
35
- declare const DEFAULT_PATH = "unknown";
36
-
37
- declare function isPrismaError(exception: unknown): boolean;
38
-
39
- declare class PrismaExceptionFormatter implements ExceptionFormatter {
40
- supports(exception: unknown): boolean;
41
- format(exception: unknown): ErrorMessage[];
42
- message(exception: unknown): string;
43
- }
44
-
45
- declare class DtoExceptionFormatter implements ExceptionFormatter {
46
- supports(exception: unknown): boolean;
47
- format(exception: unknown): ErrorMessage[];
48
- message(exception: unknown): string;
49
- private formatValidationErrors;
50
- private formatChildrenErrors;
51
- }
52
-
53
- declare class HttpExceptionFormatter implements ExceptionFormatter {
54
- supports(exception: unknown): boolean;
55
- format(exception: unknown): ErrorMessage[];
56
- message(exception: unknown): string;
57
- }
58
-
59
- declare class UnknownExceptionFormatter implements ExceptionFormatter {
60
- supports(_exception: unknown): boolean;
61
- format(_exception: unknown): ErrorMessage[];
62
- message(_exception: unknown): string;
63
- }
64
-
65
- declare class ExceptionHandlerService {
66
- private formatters;
67
- private defaultFormatter;
68
- constructor();
69
- registerFormatter(formatter: ExceptionFormatter): void;
70
- getFormatter(exception: unknown): ExceptionFormatter;
71
- formatException(exception: unknown): {
72
- errors: ErrorMessage[];
73
- message: string;
74
- };
75
- formatErrors(exception: unknown): ErrorMessage[];
76
- getErrorMessage(exception: unknown): string;
77
- getAllFormatters(): ExceptionFormatter[];
78
- }
79
-
80
- declare class GlobalExceptionFilter implements ExceptionFilter {
81
- private exceptionHandlerService;
82
- private readonly logger;
83
- private config;
84
- constructor(exceptionHandlerService: ExceptionHandlerService, config?: ExceptionHandlerConfig);
85
- catch(exception: unknown, host: ArgumentsHost): void;
86
- private getStatusCode;
87
- private logError;
88
- }
89
-
90
- declare class ExceptionHandlerModule {
91
- static forRoot(config?: ExceptionHandlerConfig): DynamicModule;
92
- static forFeature(config?: ExceptionHandlerConfig): DynamicModule;
93
- }
94
- declare function initializeFormatters(service: ExceptionHandlerService): void;
95
-
96
- export { DEFAULT_ERROR_MESSAGES, DEFAULT_PATH, DtoExceptionFormatter, ErrorMessage, ExceptionFormatter, ExceptionHandlerConfig, ExceptionHandlerModule, ExceptionHandlerService, GlobalExceptionFilter, HttpExceptionFormatter, PRISMA_ERROR_MESSAGES, PrismaExceptionFormatter, StandardErrorResponse, UnknownExceptionFormatter, initializeFormatters, isPrismaError };
package/dist/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/index.ts","../src/constants/default-messages.ts","../src/utils/is-prisma-error.ts","../src/formatters/prisma-exception.formatter.ts","../src/formatters/dto-exception.formatter.ts","../src/formatters/http-exception.formatter.ts","../src/formatters/unknown-exception.formatter.ts","../src/services/exception-handler.service.ts","../src/filter/global-exception.filter.ts","../src/module/exception-handler.module.ts"],"sourcesContent":["// Interfaces\nexport * from './interfaces';\n\n// Constants\nexport * from './constants';\n\n// Utilities\nexport * from './utils/is-prisma-error';\n\n// Formatters\nexport * from './formatters';\n\n// Services\nexport * from './services/exception-handler.service';\n\n// Filters\nexport * from './filter/global-exception.filter';\n\n// Module\nexport * from './module/exception-handler.module';\n","export const DEFAULT_ERROR_MESSAGES = {\n UNKNOWN_ERROR: 'An unexpected error occurred',\n VALIDATION_ERROR: 'Validation failed',\n DATABASE_ERROR: 'Database error',\n NOT_FOUND: 'Resource not found',\n UNAUTHORIZED: 'Unauthorized access',\n FORBIDDEN: 'Access forbidden',\n CONFLICT: 'Conflict occurred',\n BAD_REQUEST: 'Bad request',\n};\n\nexport const PRISMA_ERROR_MESSAGES: Record<string, string> = {\n P2002: 'A record with this {field} already exists.',\n P2003: 'This {field} does not exist.',\n P2005: 'Invalid value for {field}.',\n P2006: 'Invalid format for {field}.',\n P2025: 'Record not found.',\n};\n\nexport const DEFAULT_PATH = 'unknown';\n","export function isPrismaError(exception: unknown): boolean {\n if (!exception || typeof exception !== 'object') {\n return false;\n }\n\n const error = exception as Record<string, unknown>;\n\n // Check for Prisma error characteristics\n const hasErrorCode = typeof error.code === 'string';\n const hasClientVersion = typeof error.clientVersion === 'string';\n const hasMeta = typeof error.meta === 'object';\n\n // Prisma errors typically have these properties\n return hasErrorCode && (hasClientVersion || hasMeta);\n}\n","import { ExceptionFormatter } from '../interfaces/exception-formatter.interface';\nimport { ErrorMessage } from '../interfaces/error-message.interface';\nimport { isPrismaError } from '../utils/is-prisma-error';\nimport { PRISMA_ERROR_MESSAGES } from '../constants/default-messages';\n\nexport class PrismaExceptionFormatter implements ExceptionFormatter {\n supports(exception: unknown): boolean {\n return isPrismaError(exception);\n }\n\n format(exception: unknown): ErrorMessage[] {\n const error = exception as Record<string, unknown>;\n const code = error.code as string;\n const meta = error.meta as Record<string, string> | undefined;\n const target = error.target as string[] | undefined;\n\n const messageTemplate = PRISMA_ERROR_MESSAGES[code] || 'Database operation failed';\n let path = 'unknown';\n let message = messageTemplate;\n\n if (code === 'P2002' && target && target.length > 0) {\n path = target[0];\n message = messageTemplate.replace('{field}', path);\n } else if (code === 'P2003' && meta?.field_name) {\n path = meta.field_name;\n message = messageTemplate.replace('{field}', path);\n } else if (code === 'P2005' && meta?.field_name) {\n path = meta.field_name;\n message = messageTemplate.replace('{field}', path);\n } else if (code === 'P2006' && meta?.field_name) {\n path = meta.field_name;\n message = messageTemplate.replace('{field}', path);\n } else if (code === 'P2025') {\n path = 'record';\n message = messageTemplate;\n }\n\n return [{ path, message }];\n }\n\n message(exception: unknown): string {\n const error = exception as Record<string, unknown>;\n const code = error.code as string;\n return PRISMA_ERROR_MESSAGES[code] || 'Database error';\n }\n}\n","import { ValidationError } from '@nestjs/common';\nimport { ExceptionFormatter } from '../interfaces/exception-formatter.interface';\nimport { ErrorMessage } from '../interfaces/error-message.interface';\n\nexport class DtoExceptionFormatter implements ExceptionFormatter {\n supports(exception: unknown): boolean {\n if (!exception || typeof exception !== 'object') {\n return false;\n }\n\n const error = exception as Record<string, unknown>;\n return (\n Array.isArray(error.validationErrors) ||\n (Array.isArray(error.children) && error.constraints !== undefined)\n );\n }\n\n format(exception: unknown): ErrorMessage[] {\n const error = exception as Record<string, unknown>;\n const validationErrors = error.validationErrors as ValidationError[] | undefined;\n const children = error.children as ValidationError[] | undefined;\n\n if (validationErrors) {\n return this.formatValidationErrors(validationErrors);\n }\n\n if (children) {\n return this.formatChildrenErrors(children);\n }\n\n return [{ path: 'unknown', message: 'Validation failed' }];\n }\n\n message(exception: unknown): string {\n const error = exception as Record<string, unknown>;\n const validationErrors = error.validationErrors as ValidationError[] | undefined;\n const children = error.children as ValidationError[] | undefined;\n\n if (validationErrors && validationErrors.length > 0) {\n const firstError = validationErrors[0];\n const constraints = firstError.constraints;\n if (constraints) {\n return Object.values(constraints)[0];\n }\n }\n\n if (children && children.length > 0) {\n return 'Validation failed for nested fields';\n }\n\n return 'Validation failed';\n }\n\n private formatValidationErrors(errors: ValidationError[]): ErrorMessage[] {\n return errors.flatMap((error) => {\n const constraints = error.constraints;\n if (constraints) {\n return Object.entries(constraints).map(([, value]) => ({\n path: error.property,\n message: value,\n }));\n }\n return [];\n });\n }\n\n private formatChildrenErrors(children: ValidationError[]): ErrorMessage[] {\n return children.flatMap((child) => {\n const constraints = child.constraints;\n if (constraints) {\n return Object.entries(constraints).map(([, value]) => ({\n path: child.property,\n message: value,\n }));\n }\n return [];\n });\n }\n}\n","import { HttpException } from '@nestjs/common';\nimport { ExceptionFormatter } from '../interfaces/exception-formatter.interface';\nimport { ErrorMessage } from '../interfaces/error-message.interface';\n\nexport class HttpExceptionFormatter implements ExceptionFormatter {\n supports(exception: unknown): boolean {\n return exception instanceof HttpException;\n }\n\n format(exception: unknown): ErrorMessage[] {\n const httpException = exception as HttpException;\n const response = httpException.getResponse();\n\n if (typeof response === 'string') {\n return [{ path: 'unknown', message: response }];\n }\n\n if (typeof response === 'object' && response !== null) {\n const responseObj = response as Record<string, unknown>;\n\n if (responseObj.message && Array.isArray(responseObj.message)) {\n // Handle validation errors from class-validator in HTTP exceptions\n return (responseObj.message as string[]).map((msg) => ({\n path: 'unknown',\n message: msg,\n }));\n }\n\n if (responseObj.message && typeof responseObj.message === 'string') {\n return [{ path: 'unknown', message: responseObj.message }];\n }\n\n if (responseObj.error && typeof responseObj.error === 'string') {\n return [{ path: 'unknown', message: responseObj.error }];\n }\n }\n\n return [{ path: 'unknown', message: 'An error occurred' }];\n }\n\n message(exception: unknown): string {\n const httpException = exception as HttpException;\n const response = httpException.getResponse();\n\n if (typeof response === 'string') {\n return response;\n }\n\n if (typeof response === 'object' && response !== null) {\n const responseObj = response as Record<string, unknown>;\n\n if (responseObj.message && typeof responseObj.message === 'string') {\n return responseObj.message;\n }\n\n if (responseObj.error && typeof responseObj.error === 'string') {\n return responseObj.error;\n }\n }\n\n return 'An error occurred';\n }\n}\n","import { ExceptionFormatter } from '../interfaces/exception-formatter.interface';\nimport { ErrorMessage } from '../interfaces/error-message.interface';\nimport { DEFAULT_PATH } from '../constants/default-messages';\n\nexport class UnknownExceptionFormatter implements ExceptionFormatter {\n supports(_exception: unknown): boolean {\n return true;\n }\n\n format(_exception: unknown): ErrorMessage[] {\n return [\n {\n path: DEFAULT_PATH,\n message: 'Internal server error',\n },\n ];\n }\n\n message(_exception: unknown): string {\n return 'Internal server error';\n }\n}\n","import { Injectable } from '@nestjs/common';\nimport { ExceptionFormatter } from '../interfaces/exception-formatter.interface';\nimport { ErrorMessage } from '../interfaces/error-message.interface';\nimport { UnknownExceptionFormatter } from '../formatters/unknown-exception.formatter';\n\n@Injectable()\nexport class ExceptionHandlerService {\n private formatters: ExceptionFormatter[] = [];\n private defaultFormatter: ExceptionFormatter;\n\n constructor() {\n this.defaultFormatter = new UnknownExceptionFormatter();\n }\n\n registerFormatter(formatter: ExceptionFormatter): void {\n this.formatters.push(formatter);\n }\n\n getFormatter(exception: unknown): ExceptionFormatter {\n for (const formatter of this.formatters) {\n if (formatter.supports(exception)) {\n return formatter;\n }\n }\n return this.defaultFormatter;\n }\n\n formatException(exception: unknown): { errors: ErrorMessage[]; message: string } {\n const formatter = this.getFormatter(exception);\n const errors = formatter.format(exception);\n const message = formatter.message(exception);\n\n return { errors, message };\n }\n\n formatErrors(exception: unknown): ErrorMessage[] {\n const formatter = this.getFormatter(exception);\n return formatter.format(exception);\n }\n\n getErrorMessage(exception: unknown): string {\n const formatter = this.getFormatter(exception);\n return formatter.message(exception);\n }\n\n getAllFormatters(): ExceptionFormatter[] {\n return [...this.formatters];\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 { ExceptionHandlerService } from '../services/exception-handler.service';\nimport { StandardErrorResponse } from '../interfaces/error-message.interface';\nimport { ExceptionHandlerConfig } from '../interfaces/exception-handler-config.interface';\n\n@Catch()\nexport class GlobalExceptionFilter implements ExceptionFilter {\n private readonly logger = new Logger(GlobalExceptionFilter.name);\n private config: ExceptionHandlerConfig;\n\n constructor(\n private exceptionHandlerService: ExceptionHandlerService,\n config?: ExceptionHandlerConfig,\n ) {\n this.config = config || { enableLogging: true, hideStackTrace: false };\n }\n\n catch(exception: unknown, host: ArgumentsHost): void {\n const ctx = host.switchToHttp();\n const response = ctx.getResponse<Response>();\n const request = ctx.getRequest<Request>();\n\n const { errors, message } = this.exceptionHandlerService.formatException(exception);\n const status = this.getStatusCode(exception);\n\n const errorResponse: StandardErrorResponse = {\n success: false,\n message,\n errorMessages: errors,\n };\n\n if (this.config.enableLogging) {\n this.logError(request, status, errors, exception);\n }\n\n response.status(status).json(errorResponse);\n }\n\n private getStatusCode(exception: unknown): number {\n if (exception instanceof HttpException) {\n return exception.getStatus();\n }\n return HttpStatus.INTERNAL_SERVER_ERROR;\n }\n\n private logError(\n request: Request,\n status: number,\n errorMessages: { path: string; message: string }[],\n exception: unknown,\n ): void {\n const method = request.method;\n const url = request.url;\n const timestamp = new Date().toISOString();\n\n const logData = {\n timestamp,\n method,\n url,\n status,\n errorMessages,\n stack: this.config.hideStackTrace ? undefined : (exception as Error)?.stack,\n };\n\n this.logger.error(`${method} ${url} - ${status}`, JSON.stringify(logData));\n }\n}\n","import { DynamicModule, Module } from '@nestjs/common';\nimport { ExceptionHandlerService } from '../services/exception-handler.service';\nimport { GlobalExceptionFilter } from '../filter/global-exception.filter';\nimport { ExceptionHandlerConfig } from '../interfaces/exception-handler-config.interface';\nimport { PrismaExceptionFormatter } from '../formatters/prisma-exception.formatter';\nimport { DtoExceptionFormatter } from '../formatters/dto-exception.formatter';\nimport { HttpExceptionFormatter } from '../formatters/http-exception.formatter';\nimport { UnknownExceptionFormatter } from '../formatters/unknown-exception.formatter';\n\n@Module({})\nexport class ExceptionHandlerModule {\n static forRoot(config?: ExceptionHandlerConfig): DynamicModule {\n const providers = [\n ExceptionHandlerService,\n {\n provide: GlobalExceptionFilter,\n useFactory: (service: ExceptionHandlerService) => {\n return new GlobalExceptionFilter(service, config);\n },\n inject: [ExceptionHandlerService],\n },\n ];\n\n return {\n module: ExceptionHandlerModule,\n providers,\n exports: [ExceptionHandlerService, GlobalExceptionFilter],\n global: true,\n };\n }\n\n static forFeature(config?: ExceptionHandlerConfig): DynamicModule {\n return this.forRoot(config);\n }\n}\n\n// Initialize formatters\nexport function initializeFormatters(service: ExceptionHandlerService): void {\n service.registerFormatter(new PrismaExceptionFormatter());\n service.registerFormatter(new DtoExceptionFormatter());\n service.registerFormatter(new HttpExceptionFormatter());\n service.registerFormatter(new UnknownExceptionFormatter());\n}\n"],"mappings":"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","names":["import_common","import_common","import_common"]}
package/dist/index.mjs DELETED
@@ -1,354 +0,0 @@
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/constants/default-messages.ts
14
- var DEFAULT_ERROR_MESSAGES = {
15
- UNKNOWN_ERROR: "An unexpected error occurred",
16
- VALIDATION_ERROR: "Validation failed",
17
- DATABASE_ERROR: "Database error",
18
- NOT_FOUND: "Resource not found",
19
- UNAUTHORIZED: "Unauthorized access",
20
- FORBIDDEN: "Access forbidden",
21
- CONFLICT: "Conflict occurred",
22
- BAD_REQUEST: "Bad request"
23
- };
24
- var PRISMA_ERROR_MESSAGES = {
25
- P2002: "A record with this {field} already exists.",
26
- P2003: "This {field} does not exist.",
27
- P2005: "Invalid value for {field}.",
28
- P2006: "Invalid format for {field}.",
29
- P2025: "Record not found."
30
- };
31
- var DEFAULT_PATH = "unknown";
32
-
33
- // src/utils/is-prisma-error.ts
34
- function isPrismaError(exception) {
35
- if (!exception || typeof exception !== "object") {
36
- return false;
37
- }
38
- const error = exception;
39
- const hasErrorCode = typeof error.code === "string";
40
- const hasClientVersion = typeof error.clientVersion === "string";
41
- const hasMeta = typeof error.meta === "object";
42
- return hasErrorCode && (hasClientVersion || hasMeta);
43
- }
44
-
45
- // src/formatters/prisma-exception.formatter.ts
46
- var PrismaExceptionFormatter = class {
47
- supports(exception) {
48
- return isPrismaError(exception);
49
- }
50
- format(exception) {
51
- const error = exception;
52
- const code = error.code;
53
- const meta = error.meta;
54
- const target = error.target;
55
- const messageTemplate = PRISMA_ERROR_MESSAGES[code] || "Database operation failed";
56
- let path = "unknown";
57
- let message = messageTemplate;
58
- if (code === "P2002" && target && target.length > 0) {
59
- path = target[0];
60
- message = messageTemplate.replace("{field}", path);
61
- } else if (code === "P2003" && meta?.field_name) {
62
- path = meta.field_name;
63
- message = messageTemplate.replace("{field}", path);
64
- } else if (code === "P2005" && meta?.field_name) {
65
- path = meta.field_name;
66
- message = messageTemplate.replace("{field}", path);
67
- } else if (code === "P2006" && meta?.field_name) {
68
- path = meta.field_name;
69
- message = messageTemplate.replace("{field}", path);
70
- } else if (code === "P2025") {
71
- path = "record";
72
- message = messageTemplate;
73
- }
74
- return [{ path, message }];
75
- }
76
- message(exception) {
77
- const error = exception;
78
- const code = error.code;
79
- return PRISMA_ERROR_MESSAGES[code] || "Database error";
80
- }
81
- };
82
-
83
- // src/formatters/dto-exception.formatter.ts
84
- var DtoExceptionFormatter = class {
85
- supports(exception) {
86
- if (!exception || typeof exception !== "object") {
87
- return false;
88
- }
89
- const error = exception;
90
- return Array.isArray(error.validationErrors) || Array.isArray(error.children) && error.constraints !== void 0;
91
- }
92
- format(exception) {
93
- const error = exception;
94
- const validationErrors = error.validationErrors;
95
- const children = error.children;
96
- if (validationErrors) {
97
- return this.formatValidationErrors(validationErrors);
98
- }
99
- if (children) {
100
- return this.formatChildrenErrors(children);
101
- }
102
- return [{ path: "unknown", message: "Validation failed" }];
103
- }
104
- message(exception) {
105
- const error = exception;
106
- const validationErrors = error.validationErrors;
107
- const children = error.children;
108
- if (validationErrors && validationErrors.length > 0) {
109
- const firstError = validationErrors[0];
110
- const constraints = firstError.constraints;
111
- if (constraints) {
112
- return Object.values(constraints)[0];
113
- }
114
- }
115
- if (children && children.length > 0) {
116
- return "Validation failed for nested fields";
117
- }
118
- return "Validation failed";
119
- }
120
- formatValidationErrors(errors) {
121
- return errors.flatMap((error) => {
122
- const constraints = error.constraints;
123
- if (constraints) {
124
- return Object.entries(constraints).map(([, value]) => ({
125
- path: error.property,
126
- message: value
127
- }));
128
- }
129
- return [];
130
- });
131
- }
132
- formatChildrenErrors(children) {
133
- return children.flatMap((child) => {
134
- const constraints = child.constraints;
135
- if (constraints) {
136
- return Object.entries(constraints).map(([, value]) => ({
137
- path: child.property,
138
- message: value
139
- }));
140
- }
141
- return [];
142
- });
143
- }
144
- };
145
-
146
- // src/formatters/http-exception.formatter.ts
147
- import { HttpException } from "@nestjs/common";
148
- var HttpExceptionFormatter = class {
149
- supports(exception) {
150
- return exception instanceof HttpException;
151
- }
152
- format(exception) {
153
- const httpException = exception;
154
- const response = httpException.getResponse();
155
- if (typeof response === "string") {
156
- return [{ path: "unknown", message: response }];
157
- }
158
- if (typeof response === "object" && response !== null) {
159
- const responseObj = response;
160
- if (responseObj.message && Array.isArray(responseObj.message)) {
161
- return responseObj.message.map((msg) => ({
162
- path: "unknown",
163
- message: msg
164
- }));
165
- }
166
- if (responseObj.message && typeof responseObj.message === "string") {
167
- return [{ path: "unknown", message: responseObj.message }];
168
- }
169
- if (responseObj.error && typeof responseObj.error === "string") {
170
- return [{ path: "unknown", message: responseObj.error }];
171
- }
172
- }
173
- return [{ path: "unknown", message: "An error occurred" }];
174
- }
175
- message(exception) {
176
- const httpException = exception;
177
- const response = httpException.getResponse();
178
- if (typeof response === "string") {
179
- return response;
180
- }
181
- if (typeof response === "object" && response !== null) {
182
- const responseObj = response;
183
- if (responseObj.message && typeof responseObj.message === "string") {
184
- return responseObj.message;
185
- }
186
- if (responseObj.error && typeof responseObj.error === "string") {
187
- return responseObj.error;
188
- }
189
- }
190
- return "An error occurred";
191
- }
192
- };
193
-
194
- // src/formatters/unknown-exception.formatter.ts
195
- var UnknownExceptionFormatter = class {
196
- supports(_exception) {
197
- return true;
198
- }
199
- format(_exception) {
200
- return [
201
- {
202
- path: DEFAULT_PATH,
203
- message: "Internal server error"
204
- }
205
- ];
206
- }
207
- message(_exception) {
208
- return "Internal server error";
209
- }
210
- };
211
-
212
- // src/services/exception-handler.service.ts
213
- import { Injectable } from "@nestjs/common";
214
- var ExceptionHandlerService = class {
215
- constructor() {
216
- this.formatters = [];
217
- this.defaultFormatter = new UnknownExceptionFormatter();
218
- }
219
- registerFormatter(formatter) {
220
- this.formatters.push(formatter);
221
- }
222
- getFormatter(exception) {
223
- for (const formatter of this.formatters) {
224
- if (formatter.supports(exception)) {
225
- return formatter;
226
- }
227
- }
228
- return this.defaultFormatter;
229
- }
230
- formatException(exception) {
231
- const formatter = this.getFormatter(exception);
232
- const errors = formatter.format(exception);
233
- const message = formatter.message(exception);
234
- return { errors, message };
235
- }
236
- formatErrors(exception) {
237
- const formatter = this.getFormatter(exception);
238
- return formatter.format(exception);
239
- }
240
- getErrorMessage(exception) {
241
- const formatter = this.getFormatter(exception);
242
- return formatter.message(exception);
243
- }
244
- getAllFormatters() {
245
- return [...this.formatters];
246
- }
247
- };
248
- ExceptionHandlerService = __decorateClass([
249
- Injectable()
250
- ], ExceptionHandlerService);
251
-
252
- // src/filter/global-exception.filter.ts
253
- import {
254
- Catch,
255
- HttpException as HttpException2,
256
- HttpStatus,
257
- Logger
258
- } from "@nestjs/common";
259
- var GlobalExceptionFilter = class {
260
- constructor(exceptionHandlerService, config) {
261
- this.exceptionHandlerService = exceptionHandlerService;
262
- this.logger = new Logger(GlobalExceptionFilter.name);
263
- this.config = config || { enableLogging: true, hideStackTrace: false };
264
- }
265
- catch(exception, host) {
266
- const ctx = host.switchToHttp();
267
- const response = ctx.getResponse();
268
- const request = ctx.getRequest();
269
- const { errors, message } = this.exceptionHandlerService.formatException(exception);
270
- const status = this.getStatusCode(exception);
271
- const errorResponse = {
272
- success: false,
273
- message,
274
- errorMessages: errors
275
- };
276
- if (this.config.enableLogging) {
277
- this.logError(request, status, errors, exception);
278
- }
279
- response.status(status).json(errorResponse);
280
- }
281
- getStatusCode(exception) {
282
- if (exception instanceof HttpException2) {
283
- return exception.getStatus();
284
- }
285
- return HttpStatus.INTERNAL_SERVER_ERROR;
286
- }
287
- logError(request, status, errorMessages, exception) {
288
- const method = request.method;
289
- const url = request.url;
290
- const timestamp = (/* @__PURE__ */ new Date()).toISOString();
291
- const logData = {
292
- timestamp,
293
- method,
294
- url,
295
- status,
296
- errorMessages,
297
- stack: this.config.hideStackTrace ? void 0 : exception?.stack
298
- };
299
- this.logger.error(`${method} ${url} - ${status}`, JSON.stringify(logData));
300
- }
301
- };
302
- GlobalExceptionFilter = __decorateClass([
303
- Catch()
304
- ], GlobalExceptionFilter);
305
-
306
- // src/module/exception-handler.module.ts
307
- import { Module } from "@nestjs/common";
308
- var ExceptionHandlerModule = class {
309
- static forRoot(config) {
310
- const providers = [
311
- ExceptionHandlerService,
312
- {
313
- provide: GlobalExceptionFilter,
314
- useFactory: (service) => {
315
- return new GlobalExceptionFilter(service, config);
316
- },
317
- inject: [ExceptionHandlerService]
318
- }
319
- ];
320
- return {
321
- module: ExceptionHandlerModule,
322
- providers,
323
- exports: [ExceptionHandlerService, GlobalExceptionFilter],
324
- global: true
325
- };
326
- }
327
- static forFeature(config) {
328
- return this.forRoot(config);
329
- }
330
- };
331
- ExceptionHandlerModule = __decorateClass([
332
- Module({})
333
- ], ExceptionHandlerModule);
334
- function initializeFormatters(service) {
335
- service.registerFormatter(new PrismaExceptionFormatter());
336
- service.registerFormatter(new DtoExceptionFormatter());
337
- service.registerFormatter(new HttpExceptionFormatter());
338
- service.registerFormatter(new UnknownExceptionFormatter());
339
- }
340
- export {
341
- DEFAULT_ERROR_MESSAGES,
342
- DEFAULT_PATH,
343
- DtoExceptionFormatter,
344
- ExceptionHandlerModule,
345
- ExceptionHandlerService,
346
- GlobalExceptionFilter,
347
- HttpExceptionFormatter,
348
- PRISMA_ERROR_MESSAGES,
349
- PrismaExceptionFormatter,
350
- UnknownExceptionFormatter,
351
- initializeFormatters,
352
- isPrismaError
353
- };
354
- //# sourceMappingURL=index.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/constants/default-messages.ts","../src/utils/is-prisma-error.ts","../src/formatters/prisma-exception.formatter.ts","../src/formatters/dto-exception.formatter.ts","../src/formatters/http-exception.formatter.ts","../src/formatters/unknown-exception.formatter.ts","../src/services/exception-handler.service.ts","../src/filter/global-exception.filter.ts","../src/module/exception-handler.module.ts"],"sourcesContent":["export const DEFAULT_ERROR_MESSAGES = {\n UNKNOWN_ERROR: 'An unexpected error occurred',\n VALIDATION_ERROR: 'Validation failed',\n DATABASE_ERROR: 'Database error',\n NOT_FOUND: 'Resource not found',\n UNAUTHORIZED: 'Unauthorized access',\n FORBIDDEN: 'Access forbidden',\n CONFLICT: 'Conflict occurred',\n BAD_REQUEST: 'Bad request',\n};\n\nexport const PRISMA_ERROR_MESSAGES: Record<string, string> = {\n P2002: 'A record with this {field} already exists.',\n P2003: 'This {field} does not exist.',\n P2005: 'Invalid value for {field}.',\n P2006: 'Invalid format for {field}.',\n P2025: 'Record not found.',\n};\n\nexport const DEFAULT_PATH = 'unknown';\n","export function isPrismaError(exception: unknown): boolean {\n if (!exception || typeof exception !== 'object') {\n return false;\n }\n\n const error = exception as Record<string, unknown>;\n\n // Check for Prisma error characteristics\n const hasErrorCode = typeof error.code === 'string';\n const hasClientVersion = typeof error.clientVersion === 'string';\n const hasMeta = typeof error.meta === 'object';\n\n // Prisma errors typically have these properties\n return hasErrorCode && (hasClientVersion || hasMeta);\n}\n","import { ExceptionFormatter } from '../interfaces/exception-formatter.interface';\nimport { ErrorMessage } from '../interfaces/error-message.interface';\nimport { isPrismaError } from '../utils/is-prisma-error';\nimport { PRISMA_ERROR_MESSAGES } from '../constants/default-messages';\n\nexport class PrismaExceptionFormatter implements ExceptionFormatter {\n supports(exception: unknown): boolean {\n return isPrismaError(exception);\n }\n\n format(exception: unknown): ErrorMessage[] {\n const error = exception as Record<string, unknown>;\n const code = error.code as string;\n const meta = error.meta as Record<string, string> | undefined;\n const target = error.target as string[] | undefined;\n\n const messageTemplate = PRISMA_ERROR_MESSAGES[code] || 'Database operation failed';\n let path = 'unknown';\n let message = messageTemplate;\n\n if (code === 'P2002' && target && target.length > 0) {\n path = target[0];\n message = messageTemplate.replace('{field}', path);\n } else if (code === 'P2003' && meta?.field_name) {\n path = meta.field_name;\n message = messageTemplate.replace('{field}', path);\n } else if (code === 'P2005' && meta?.field_name) {\n path = meta.field_name;\n message = messageTemplate.replace('{field}', path);\n } else if (code === 'P2006' && meta?.field_name) {\n path = meta.field_name;\n message = messageTemplate.replace('{field}', path);\n } else if (code === 'P2025') {\n path = 'record';\n message = messageTemplate;\n }\n\n return [{ path, message }];\n }\n\n message(exception: unknown): string {\n const error = exception as Record<string, unknown>;\n const code = error.code as string;\n return PRISMA_ERROR_MESSAGES[code] || 'Database error';\n }\n}\n","import { ValidationError } from '@nestjs/common';\nimport { ExceptionFormatter } from '../interfaces/exception-formatter.interface';\nimport { ErrorMessage } from '../interfaces/error-message.interface';\n\nexport class DtoExceptionFormatter implements ExceptionFormatter {\n supports(exception: unknown): boolean {\n if (!exception || typeof exception !== 'object') {\n return false;\n }\n\n const error = exception as Record<string, unknown>;\n return (\n Array.isArray(error.validationErrors) ||\n (Array.isArray(error.children) && error.constraints !== undefined)\n );\n }\n\n format(exception: unknown): ErrorMessage[] {\n const error = exception as Record<string, unknown>;\n const validationErrors = error.validationErrors as ValidationError[] | undefined;\n const children = error.children as ValidationError[] | undefined;\n\n if (validationErrors) {\n return this.formatValidationErrors(validationErrors);\n }\n\n if (children) {\n return this.formatChildrenErrors(children);\n }\n\n return [{ path: 'unknown', message: 'Validation failed' }];\n }\n\n message(exception: unknown): string {\n const error = exception as Record<string, unknown>;\n const validationErrors = error.validationErrors as ValidationError[] | undefined;\n const children = error.children as ValidationError[] | undefined;\n\n if (validationErrors && validationErrors.length > 0) {\n const firstError = validationErrors[0];\n const constraints = firstError.constraints;\n if (constraints) {\n return Object.values(constraints)[0];\n }\n }\n\n if (children && children.length > 0) {\n return 'Validation failed for nested fields';\n }\n\n return 'Validation failed';\n }\n\n private formatValidationErrors(errors: ValidationError[]): ErrorMessage[] {\n return errors.flatMap((error) => {\n const constraints = error.constraints;\n if (constraints) {\n return Object.entries(constraints).map(([, value]) => ({\n path: error.property,\n message: value,\n }));\n }\n return [];\n });\n }\n\n private formatChildrenErrors(children: ValidationError[]): ErrorMessage[] {\n return children.flatMap((child) => {\n const constraints = child.constraints;\n if (constraints) {\n return Object.entries(constraints).map(([, value]) => ({\n path: child.property,\n message: value,\n }));\n }\n return [];\n });\n }\n}\n","import { HttpException } from '@nestjs/common';\nimport { ExceptionFormatter } from '../interfaces/exception-formatter.interface';\nimport { ErrorMessage } from '../interfaces/error-message.interface';\n\nexport class HttpExceptionFormatter implements ExceptionFormatter {\n supports(exception: unknown): boolean {\n return exception instanceof HttpException;\n }\n\n format(exception: unknown): ErrorMessage[] {\n const httpException = exception as HttpException;\n const response = httpException.getResponse();\n\n if (typeof response === 'string') {\n return [{ path: 'unknown', message: response }];\n }\n\n if (typeof response === 'object' && response !== null) {\n const responseObj = response as Record<string, unknown>;\n\n if (responseObj.message && Array.isArray(responseObj.message)) {\n // Handle validation errors from class-validator in HTTP exceptions\n return (responseObj.message as string[]).map((msg) => ({\n path: 'unknown',\n message: msg,\n }));\n }\n\n if (responseObj.message && typeof responseObj.message === 'string') {\n return [{ path: 'unknown', message: responseObj.message }];\n }\n\n if (responseObj.error && typeof responseObj.error === 'string') {\n return [{ path: 'unknown', message: responseObj.error }];\n }\n }\n\n return [{ path: 'unknown', message: 'An error occurred' }];\n }\n\n message(exception: unknown): string {\n const httpException = exception as HttpException;\n const response = httpException.getResponse();\n\n if (typeof response === 'string') {\n return response;\n }\n\n if (typeof response === 'object' && response !== null) {\n const responseObj = response as Record<string, unknown>;\n\n if (responseObj.message && typeof responseObj.message === 'string') {\n return responseObj.message;\n }\n\n if (responseObj.error && typeof responseObj.error === 'string') {\n return responseObj.error;\n }\n }\n\n return 'An error occurred';\n }\n}\n","import { ExceptionFormatter } from '../interfaces/exception-formatter.interface';\nimport { ErrorMessage } from '../interfaces/error-message.interface';\nimport { DEFAULT_PATH } from '../constants/default-messages';\n\nexport class UnknownExceptionFormatter implements ExceptionFormatter {\n supports(_exception: unknown): boolean {\n return true;\n }\n\n format(_exception: unknown): ErrorMessage[] {\n return [\n {\n path: DEFAULT_PATH,\n message: 'Internal server error',\n },\n ];\n }\n\n message(_exception: unknown): string {\n return 'Internal server error';\n }\n}\n","import { Injectable } from '@nestjs/common';\nimport { ExceptionFormatter } from '../interfaces/exception-formatter.interface';\nimport { ErrorMessage } from '../interfaces/error-message.interface';\nimport { UnknownExceptionFormatter } from '../formatters/unknown-exception.formatter';\n\n@Injectable()\nexport class ExceptionHandlerService {\n private formatters: ExceptionFormatter[] = [];\n private defaultFormatter: ExceptionFormatter;\n\n constructor() {\n this.defaultFormatter = new UnknownExceptionFormatter();\n }\n\n registerFormatter(formatter: ExceptionFormatter): void {\n this.formatters.push(formatter);\n }\n\n getFormatter(exception: unknown): ExceptionFormatter {\n for (const formatter of this.formatters) {\n if (formatter.supports(exception)) {\n return formatter;\n }\n }\n return this.defaultFormatter;\n }\n\n formatException(exception: unknown): { errors: ErrorMessage[]; message: string } {\n const formatter = this.getFormatter(exception);\n const errors = formatter.format(exception);\n const message = formatter.message(exception);\n\n return { errors, message };\n }\n\n formatErrors(exception: unknown): ErrorMessage[] {\n const formatter = this.getFormatter(exception);\n return formatter.format(exception);\n }\n\n getErrorMessage(exception: unknown): string {\n const formatter = this.getFormatter(exception);\n return formatter.message(exception);\n }\n\n getAllFormatters(): ExceptionFormatter[] {\n return [...this.formatters];\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 { ExceptionHandlerService } from '../services/exception-handler.service';\nimport { StandardErrorResponse } from '../interfaces/error-message.interface';\nimport { ExceptionHandlerConfig } from '../interfaces/exception-handler-config.interface';\n\n@Catch()\nexport class GlobalExceptionFilter implements ExceptionFilter {\n private readonly logger = new Logger(GlobalExceptionFilter.name);\n private config: ExceptionHandlerConfig;\n\n constructor(\n private exceptionHandlerService: ExceptionHandlerService,\n config?: ExceptionHandlerConfig,\n ) {\n this.config = config || { enableLogging: true, hideStackTrace: false };\n }\n\n catch(exception: unknown, host: ArgumentsHost): void {\n const ctx = host.switchToHttp();\n const response = ctx.getResponse<Response>();\n const request = ctx.getRequest<Request>();\n\n const { errors, message } = this.exceptionHandlerService.formatException(exception);\n const status = this.getStatusCode(exception);\n\n const errorResponse: StandardErrorResponse = {\n success: false,\n message,\n errorMessages: errors,\n };\n\n if (this.config.enableLogging) {\n this.logError(request, status, errors, exception);\n }\n\n response.status(status).json(errorResponse);\n }\n\n private getStatusCode(exception: unknown): number {\n if (exception instanceof HttpException) {\n return exception.getStatus();\n }\n return HttpStatus.INTERNAL_SERVER_ERROR;\n }\n\n private logError(\n request: Request,\n status: number,\n errorMessages: { path: string; message: string }[],\n exception: unknown,\n ): void {\n const method = request.method;\n const url = request.url;\n const timestamp = new Date().toISOString();\n\n const logData = {\n timestamp,\n method,\n url,\n status,\n errorMessages,\n stack: this.config.hideStackTrace ? undefined : (exception as Error)?.stack,\n };\n\n this.logger.error(`${method} ${url} - ${status}`, JSON.stringify(logData));\n }\n}\n","import { DynamicModule, Module } from '@nestjs/common';\nimport { ExceptionHandlerService } from '../services/exception-handler.service';\nimport { GlobalExceptionFilter } from '../filter/global-exception.filter';\nimport { ExceptionHandlerConfig } from '../interfaces/exception-handler-config.interface';\nimport { PrismaExceptionFormatter } from '../formatters/prisma-exception.formatter';\nimport { DtoExceptionFormatter } from '../formatters/dto-exception.formatter';\nimport { HttpExceptionFormatter } from '../formatters/http-exception.formatter';\nimport { UnknownExceptionFormatter } from '../formatters/unknown-exception.formatter';\n\n@Module({})\nexport class ExceptionHandlerModule {\n static forRoot(config?: ExceptionHandlerConfig): DynamicModule {\n const providers = [\n ExceptionHandlerService,\n {\n provide: GlobalExceptionFilter,\n useFactory: (service: ExceptionHandlerService) => {\n return new GlobalExceptionFilter(service, config);\n },\n inject: [ExceptionHandlerService],\n },\n ];\n\n return {\n module: ExceptionHandlerModule,\n providers,\n exports: [ExceptionHandlerService, GlobalExceptionFilter],\n global: true,\n };\n }\n\n static forFeature(config?: ExceptionHandlerConfig): DynamicModule {\n return this.forRoot(config);\n }\n}\n\n// Initialize formatters\nexport function initializeFormatters(service: ExceptionHandlerService): void {\n service.registerFormatter(new PrismaExceptionFormatter());\n service.registerFormatter(new DtoExceptionFormatter());\n service.registerFormatter(new HttpExceptionFormatter());\n service.registerFormatter(new UnknownExceptionFormatter());\n}\n"],"mappings":"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","names":["HttpException","HttpException"]}