nestjs-exception-handler 4.2.0 → 4.4.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.mjs CHANGED
@@ -10,6 +10,40 @@ var __decorateClass = (decorators, target, key, kind) => {
10
10
  return result;
11
11
  };
12
12
 
13
+ // src/formatters/validation-error.formatter.ts
14
+ var ValidationErrorFormatter = class {
15
+ formatValidationErrors(exception) {
16
+ const response = exception.getResponse();
17
+ if (typeof response === "object" && response !== null) {
18
+ const responseObj = response;
19
+ if (Array.isArray(responseObj.message)) {
20
+ const messages = responseObj.message;
21
+ if (messages.length > 0 && typeof messages[0] === "object" && "property" in messages[0]) {
22
+ return this.formatNestedValidationErrors(messages);
23
+ }
24
+ return [
25
+ {
26
+ path: "http_error",
27
+ message: messages
28
+ }
29
+ ];
30
+ }
31
+ }
32
+ return [
33
+ {
34
+ path: "http_error",
35
+ message: ["Validation failed"]
36
+ }
37
+ ];
38
+ }
39
+ formatNestedValidationErrors(errors) {
40
+ return errors.map((error) => ({
41
+ path: error.property,
42
+ message: error.constraints ? Object.values(error.constraints) : ["Validation error"]
43
+ }));
44
+ }
45
+ };
46
+
13
47
  // src/formatters/prisma-exception.formatter.ts
14
48
  import { Injectable } from "@nestjs/common";
15
49
  import {
@@ -50,7 +84,7 @@ var PrismaExceptionFormatter = class {
50
84
  return [
51
85
  {
52
86
  path: field,
53
- message: `A record with this ${field} already exists.`
87
+ message: [`A record with this ${field} already exists.`]
54
88
  }
55
89
  ];
56
90
  }
@@ -59,7 +93,7 @@ var PrismaExceptionFormatter = class {
59
93
  return [
60
94
  {
61
95
  path: fieldName || "field",
62
- message: `The referenced ${fieldName || "record"} does not exist.`
96
+ message: [`The referenced ${fieldName || "record"} does not exist.`]
63
97
  }
64
98
  ];
65
99
  }
@@ -68,7 +102,7 @@ var PrismaExceptionFormatter = class {
68
102
  return [
69
103
  {
70
104
  path: fieldName || "field",
71
- message: `The value for ${fieldName || "field"} is invalid.`
105
+ message: [`The value for ${fieldName || "field"} is invalid.`]
72
106
  }
73
107
  ];
74
108
  }
@@ -77,7 +111,7 @@ var PrismaExceptionFormatter = class {
77
111
  return [
78
112
  {
79
113
  path: fieldName || "field",
80
- message: `The ${fieldName || "field"} field is required.`
114
+ message: [`The ${fieldName || "field"} field is required.`]
81
115
  }
82
116
  ];
83
117
  }
@@ -85,7 +119,7 @@ var PrismaExceptionFormatter = class {
85
119
  return [
86
120
  {
87
121
  path: "record",
88
- message: "The requested record does not exist."
122
+ message: ["The requested record does not exist."]
89
123
  }
90
124
  ];
91
125
  }
@@ -93,7 +127,7 @@ var PrismaExceptionFormatter = class {
93
127
  return [
94
128
  {
95
129
  path: "database",
96
- message: "Database operation failed."
130
+ message: ["Database operation failed."]
97
131
  }
98
132
  ];
99
133
  }
@@ -106,7 +140,7 @@ var PrismaExceptionFormatter = class {
106
140
  return [
107
141
  {
108
142
  path: "database",
109
- message
143
+ message: [message]
110
144
  }
111
145
  ];
112
146
  }
@@ -114,7 +148,7 @@ var PrismaExceptionFormatter = class {
114
148
  return [
115
149
  {
116
150
  path: "database",
117
- message: `Database initialization error: ${exception.message}`
151
+ message: [`Database initialization error: ${exception.message}`]
118
152
  }
119
153
  ];
120
154
  }
@@ -122,7 +156,7 @@ var PrismaExceptionFormatter = class {
122
156
  return [
123
157
  {
124
158
  path: "unknown",
125
- message: exception instanceof Error ? exception.message : "An unexpected database error occurred."
159
+ message: exception instanceof Error ? [exception.message] : ["An unexpected database error occurred."]
126
160
  }
127
161
  ];
128
162
  }
@@ -143,14 +177,22 @@ var DtoValidationFormatter = class {
143
177
  const validationErrors = messages;
144
178
  return validationErrors.map((error) => ({
145
179
  path: error.property,
146
- message: error.constraints ? Object.values(error.constraints).join(", ") : "Validation error"
180
+ message: error.constraints ? Object.values(error.constraints) : ["Validation error"]
147
181
  }));
148
182
  }
183
+ if (typeof firstMessage === "string") {
184
+ return [
185
+ {
186
+ path: "http_error",
187
+ message: messages
188
+ }
189
+ ];
190
+ }
149
191
  }
150
192
  return [
151
193
  {
152
194
  path: "http_error",
153
- message: typeof responseBody === "object" && responseBody !== null && "message" in responseBody ? String(responseBody.message) : "An HTTP error occurred"
195
+ message: typeof responseBody === "object" && responseBody !== null && "message" in responseBody ? [responseBody.message] : ["An HTTP error occurred"]
154
196
  }
155
197
  ];
156
198
  }
@@ -159,97 +201,134 @@ DtoValidationFormatter = __decorateClass([
159
201
  Injectable2()
160
202
  ], DtoValidationFormatter);
161
203
 
162
- // src/formatters/other-exception.formatter.ts
204
+ // src/filter/global-exception.filter.ts
205
+ import {
206
+ Catch,
207
+ HttpException as HttpException2,
208
+ HttpStatus,
209
+ Logger,
210
+ NotFoundException
211
+ } from "@nestjs/common";
212
+
213
+ // src/services/exception-handler.service.ts
163
214
  import { Injectable as Injectable3 } from "@nestjs/common";
164
- var OtherExceptionFormatter = class {
165
- formatOtherError(exception) {
166
- if (exception && typeof exception === "object" && "path" in exception && "message" in exception) {
167
- return [
168
- {
169
- path: String(exception.path),
170
- message: String(exception.message)
171
- }
172
- ];
215
+
216
+ // src/formatters/http-exception.formatter.ts
217
+ import { HttpException } from "@nestjs/common";
218
+ var HttpExceptionFormatter = class {
219
+ supports(exception) {
220
+ return exception instanceof HttpException;
221
+ }
222
+ format(exception) {
223
+ const httpException = exception;
224
+ const response = httpException.getResponse();
225
+ if (typeof response === "string") {
226
+ return [{ path: "http_error", message: [response] }];
173
227
  }
174
- const message = exception && typeof exception === "object" && "message" in exception ? String(exception.message) : "An unexpected error occurred";
175
- return [
176
- {
177
- path: "unknown",
178
- message
228
+ if (typeof response === "object" && response !== null) {
229
+ const responseObj = response;
230
+ if (responseObj.message && Array.isArray(responseObj.message)) {
231
+ return [
232
+ {
233
+ path: "http_error",
234
+ message: responseObj.message
235
+ }
236
+ ];
179
237
  }
180
- ];
238
+ if (responseObj.message && typeof responseObj.message === "string") {
239
+ return [{ path: "http_error", message: [responseObj.message] }];
240
+ }
241
+ if (responseObj.error && typeof responseObj.error === "string") {
242
+ return [{ path: "http_error", message: [responseObj.error] }];
243
+ }
244
+ }
245
+ return [{ path: "http_error", message: ["An error occurred"] }];
246
+ }
247
+ message(exception) {
248
+ const httpException = exception;
249
+ const response = httpException.getResponse();
250
+ if (typeof response === "string") {
251
+ return response;
252
+ }
253
+ if (typeof response === "object" && response !== null) {
254
+ const responseObj = response;
255
+ if (responseObj.message && typeof responseObj.message === "string") {
256
+ return responseObj.message;
257
+ }
258
+ if (responseObj.error && typeof responseObj.error === "string") {
259
+ return responseObj.error;
260
+ }
261
+ }
262
+ return "An error occurred";
181
263
  }
182
264
  };
183
- OtherExceptionFormatter = __decorateClass([
184
- Injectable3()
185
- ], OtherExceptionFormatter);
186
265
 
187
- // src/exception-filter/global-exception.filter.ts
188
- import {
189
- Catch,
190
- HttpException,
191
- HttpStatus,
192
- Logger
193
- } from "@nestjs/common";
194
- import {
195
- PrismaClientKnownRequestError as PrismaClientKnownRequestError2,
196
- PrismaClientValidationError as PrismaClientValidationError2,
197
- PrismaClientRustPanicError as PrismaClientRustPanicError2,
198
- PrismaClientUnknownRequestError,
199
- PrismaClientInitializationError as PrismaClientInitializationError2
200
- } from "@prisma/client/runtime/library";
201
- var GlobalExceptionFilter = class {
202
- constructor(prismaExceptionFormatter, dtoValidationFormatter, otherValidationFormatter) {
203
- this.prismaExceptionFormatter = prismaExceptionFormatter;
204
- this.dtoValidationFormatter = dtoValidationFormatter;
205
- this.otherValidationFormatter = otherValidationFormatter;
206
- this.logger = new Logger(GlobalExceptionFilter.name);
266
+ // src/formatters/dto-exception.formatter.ts
267
+ var DtoExceptionFormatter = class {
268
+ supports(exception) {
269
+ if (!exception || typeof exception !== "object") {
270
+ return false;
271
+ }
272
+ const error = exception;
273
+ return Array.isArray(error.validationErrors) || Array.isArray(error.children) && error.constraints !== void 0;
207
274
  }
208
- getErrorMessage(exception) {
209
- if (exception instanceof PrismaClientKnownRequestError2 || exception instanceof PrismaClientValidationError2 || exception instanceof PrismaClientRustPanicError2 || exception instanceof PrismaClientUnknownRequestError || exception instanceof PrismaClientInitializationError2) {
210
- return "Database error";
275
+ format(exception) {
276
+ const error = exception;
277
+ const validationErrors = error.validationErrors;
278
+ const children = error.children;
279
+ if (validationErrors) {
280
+ return this.formatValidationErrors(validationErrors);
211
281
  }
212
- if (exception instanceof HttpException) {
213
- return exception.message || "HTTP error";
282
+ if (children) {
283
+ return this.formatChildrenErrors(children);
214
284
  }
215
- return "Internal server error";
285
+ return [{ path: "unknown", message: ["Validation failed"] }];
216
286
  }
217
- catch(exception, host) {
218
- const ctx = host.switchToHttp();
219
- const response = ctx.getResponse();
220
- const request = ctx.getRequest();
221
- const status = exception instanceof HttpException ? exception.getStatus() : HttpStatus.INTERNAL_SERVER_ERROR;
222
- let errorMessages = [{ path: "unknown", message: "Internal server error" }];
223
- if (exception instanceof PrismaClientKnownRequestError2 || exception instanceof PrismaClientValidationError2 || exception instanceof PrismaClientRustPanicError2 || exception instanceof PrismaClientUnknownRequestError || exception instanceof PrismaClientInitializationError2) {
224
- errorMessages = this.prismaExceptionFormatter.formatError(exception);
225
- } else if (exception instanceof HttpException) {
226
- errorMessages = this.dtoValidationFormatter.formatDtoValidationException(
227
- exception
228
- );
229
- } else {
230
- errorMessages = this.otherValidationFormatter.formatOtherError(exception);
287
+ message(exception) {
288
+ const error = exception;
289
+ const validationErrors = error.validationErrors;
290
+ const children = error.children;
291
+ if (validationErrors && validationErrors.length > 0) {
292
+ const firstError = validationErrors[0];
293
+ const constraints = firstError.constraints;
294
+ if (constraints) {
295
+ return Object.values(constraints)[0];
296
+ }
231
297
  }
232
- this.logger.error(
233
- `${request.method} ${request.url}`,
234
- JSON.stringify(errorMessages),
235
- "ExceptionFilter"
236
- );
237
- response.status(status).json({
238
- success: false,
239
- message: this.getErrorMessage(exception),
240
- errorMessages
298
+ if (children && children.length > 0) {
299
+ return "Validation failed for nested fields";
300
+ }
301
+ return "Validation failed";
302
+ }
303
+ formatValidationErrors(errors) {
304
+ return errors.flatMap((error) => {
305
+ const constraints = error.constraints;
306
+ if (constraints) {
307
+ return [
308
+ {
309
+ path: error.property,
310
+ message: Object.values(constraints)
311
+ }
312
+ ];
313
+ }
314
+ return [];
315
+ });
316
+ }
317
+ formatChildrenErrors(children) {
318
+ return children.flatMap((child) => {
319
+ const constraints = child.constraints;
320
+ if (constraints) {
321
+ return [
322
+ {
323
+ path: child.property,
324
+ message: Object.values(constraints)
325
+ }
326
+ ];
327
+ }
328
+ return [];
241
329
  });
242
330
  }
243
331
  };
244
- GlobalExceptionFilter = __decorateClass([
245
- Catch()
246
- ], GlobalExceptionFilter);
247
-
248
- // src/module/exception-handler.module.ts
249
- import { Module } from "@nestjs/common";
250
-
251
- // src/services/exception-handler.service.ts
252
- import { Injectable as Injectable4 } from "@nestjs/common";
253
332
 
254
333
  // src/constants/default-messages.ts
255
334
  var DEFAULT_PATH = "unknown";
@@ -263,12 +342,12 @@ var UnknownExceptionFormatter = class {
263
342
  return [
264
343
  {
265
344
  path: DEFAULT_PATH,
266
- message: "Internal server error"
345
+ message: ["Something went wrong"]
267
346
  }
268
347
  ];
269
348
  }
270
349
  message(_exception) {
271
- return "Internal server error";
350
+ return "Internal Server Error";
272
351
  }
273
352
  };
274
353
 
@@ -277,6 +356,14 @@ var ExceptionHandlerService = class {
277
356
  constructor() {
278
357
  this.formatters = [];
279
358
  this.defaultFormatter = new UnknownExceptionFormatter();
359
+ this.registerFormatters();
360
+ }
361
+ registerFormatters() {
362
+ this.formatters = [
363
+ new PrismaExceptionFormatter(),
364
+ new HttpExceptionFormatter(),
365
+ new DtoExceptionFormatter()
366
+ ];
280
367
  }
281
368
  registerFormatter(formatter) {
282
369
  this.formatters.push(formatter);
@@ -308,35 +395,53 @@ var ExceptionHandlerService = class {
308
395
  }
309
396
  };
310
397
  ExceptionHandlerService = __decorateClass([
311
- Injectable4()
398
+ Injectable3()
312
399
  ], ExceptionHandlerService);
313
400
 
314
401
  // src/filter/global-exception.filter.ts
315
- import {
316
- Catch as Catch2,
317
- HttpException as HttpException2,
318
- HttpStatus as HttpStatus2,
319
- Logger as Logger2
320
- } from "@nestjs/common";
321
- var GlobalExceptionFilter2 = class {
402
+ var GlobalExceptionFilter = class {
322
403
  constructor(exceptionHandlerService, config) {
323
404
  this.exceptionHandlerService = exceptionHandlerService;
324
- this.logger = new Logger2(GlobalExceptionFilter2.name);
405
+ this.logger = new Logger(GlobalExceptionFilter.name);
325
406
  this.config = config || { enableLogging: true, hideStackTrace: false };
326
407
  }
408
+ getService() {
409
+ if (!this.exceptionHandlerService) {
410
+ this.exceptionHandlerService = new ExceptionHandlerService();
411
+ }
412
+ return this.exceptionHandlerService;
413
+ }
327
414
  catch(exception, host) {
328
415
  const ctx = host.switchToHttp();
329
416
  const response = ctx.getResponse();
330
417
  const request = ctx.getRequest();
331
- const { errors, message } = this.exceptionHandlerService.formatException(exception);
332
- const status = this.getStatusCode(exception);
418
+ const { errors, message } = this.getService().formatException(exception);
419
+ let status = this.getStatusCode(exception);
420
+ let finalErrors = errors;
421
+ let finalMessage = message;
422
+ if (exception instanceof NotFoundException) {
423
+ const exceptionResponse = exception.getResponse();
424
+ if (typeof exceptionResponse === "object" && exceptionResponse !== null && "message" in exceptionResponse) {
425
+ const msg = exceptionResponse.message;
426
+ if (typeof msg === "string" && msg.includes("Cannot")) {
427
+ status = HttpStatus.NOT_FOUND;
428
+ finalMessage = "Route Not Found";
429
+ finalErrors = [
430
+ {
431
+ path: "route",
432
+ message: [msg]
433
+ }
434
+ ];
435
+ }
436
+ }
437
+ }
333
438
  const errorResponse = {
334
439
  success: false,
335
- message,
336
- errorMessages: errors
440
+ message: finalMessage,
441
+ errorMessages: finalErrors
337
442
  };
338
443
  if (this.config.enableLogging) {
339
- this.logError(request, status, errors, exception);
444
+ this.logError(request, status, finalErrors, exception);
340
445
  }
341
446
  response.status(status).json(errorResponse);
342
447
  }
@@ -344,7 +449,7 @@ var GlobalExceptionFilter2 = class {
344
449
  if (exception instanceof HttpException2) {
345
450
  return exception.getStatus();
346
451
  }
347
- return HttpStatus2.INTERNAL_SERVER_ERROR;
452
+ return HttpStatus.INTERNAL_SERVER_ERROR;
348
453
  }
349
454
  logError(request, status, errorMessages, exception) {
350
455
  const method = request.method;
@@ -361,130 +466,20 @@ var GlobalExceptionFilter2 = class {
361
466
  this.logger.error(`${method} ${url} - ${status}`, JSON.stringify(logData));
362
467
  }
363
468
  };
364
- GlobalExceptionFilter2 = __decorateClass([
365
- Catch2()
366
- ], GlobalExceptionFilter2);
367
-
368
- // src/formatters/dto-exception.formatter.ts
369
- var DtoExceptionFormatter = class {
370
- supports(exception) {
371
- if (!exception || typeof exception !== "object") {
372
- return false;
373
- }
374
- const error = exception;
375
- return Array.isArray(error.validationErrors) || Array.isArray(error.children) && error.constraints !== void 0;
376
- }
377
- format(exception) {
378
- const error = exception;
379
- const validationErrors = error.validationErrors;
380
- const children = error.children;
381
- if (validationErrors) {
382
- return this.formatValidationErrors(validationErrors);
383
- }
384
- if (children) {
385
- return this.formatChildrenErrors(children);
386
- }
387
- return [{ path: "unknown", message: "Validation failed" }];
388
- }
389
- message(exception) {
390
- const error = exception;
391
- const validationErrors = error.validationErrors;
392
- const children = error.children;
393
- if (validationErrors && validationErrors.length > 0) {
394
- const firstError = validationErrors[0];
395
- const constraints = firstError.constraints;
396
- if (constraints) {
397
- return Object.values(constraints)[0];
398
- }
399
- }
400
- if (children && children.length > 0) {
401
- return "Validation failed for nested fields";
402
- }
403
- return "Validation failed";
404
- }
405
- formatValidationErrors(errors) {
406
- return errors.flatMap((error) => {
407
- const constraints = error.constraints;
408
- if (constraints) {
409
- return Object.entries(constraints).map(([, value]) => ({
410
- path: error.property,
411
- message: value
412
- }));
413
- }
414
- return [];
415
- });
416
- }
417
- formatChildrenErrors(children) {
418
- return children.flatMap((child) => {
419
- const constraints = child.constraints;
420
- if (constraints) {
421
- return Object.entries(constraints).map(([, value]) => ({
422
- path: child.property,
423
- message: value
424
- }));
425
- }
426
- return [];
427
- });
428
- }
429
- };
430
-
431
- // src/formatters/http-exception.formatter.ts
432
- import { HttpException as HttpException3 } from "@nestjs/common";
433
- var HttpExceptionFormatter = class {
434
- supports(exception) {
435
- return exception instanceof HttpException3;
436
- }
437
- format(exception) {
438
- const httpException = exception;
439
- const response = httpException.getResponse();
440
- if (typeof response === "string") {
441
- return [{ path: "unknown", message: response }];
442
- }
443
- if (typeof response === "object" && response !== null) {
444
- const responseObj = response;
445
- if (responseObj.message && Array.isArray(responseObj.message)) {
446
- return responseObj.message.map((msg) => ({
447
- path: "unknown",
448
- message: msg
449
- }));
450
- }
451
- if (responseObj.message && typeof responseObj.message === "string") {
452
- return [{ path: "unknown", message: responseObj.message }];
453
- }
454
- if (responseObj.error && typeof responseObj.error === "string") {
455
- return [{ path: "unknown", message: responseObj.error }];
456
- }
457
- }
458
- return [{ path: "unknown", message: "An error occurred" }];
459
- }
460
- message(exception) {
461
- const httpException = exception;
462
- const response = httpException.getResponse();
463
- if (typeof response === "string") {
464
- return response;
465
- }
466
- if (typeof response === "object" && response !== null) {
467
- const responseObj = response;
468
- if (responseObj.message && typeof responseObj.message === "string") {
469
- return responseObj.message;
470
- }
471
- if (responseObj.error && typeof responseObj.error === "string") {
472
- return responseObj.error;
473
- }
474
- }
475
- return "An error occurred";
476
- }
477
- };
469
+ GlobalExceptionFilter = __decorateClass([
470
+ Catch()
471
+ ], GlobalExceptionFilter);
478
472
 
479
473
  // src/module/exception-handler.module.ts
474
+ import { Module } from "@nestjs/common";
480
475
  var ExceptionHandlerModule = class {
481
476
  static forRoot(config) {
482
477
  const providers = [
483
478
  ExceptionHandlerService,
484
479
  {
485
- provide: GlobalExceptionFilter2,
480
+ provide: GlobalExceptionFilter,
486
481
  useFactory: (service) => {
487
- return new GlobalExceptionFilter2(service, config);
482
+ return new GlobalExceptionFilter(service, config);
488
483
  },
489
484
  inject: [ExceptionHandlerService]
490
485
  }
@@ -492,7 +487,7 @@ var ExceptionHandlerModule = class {
492
487
  return {
493
488
  module: ExceptionHandlerModule,
494
489
  providers,
495
- exports: [ExceptionHandlerService, GlobalExceptionFilter2],
490
+ exports: [ExceptionHandlerService, GlobalExceptionFilter],
496
491
  global: true
497
492
  };
498
493
  }
@@ -509,12 +504,58 @@ function initializeFormatters(service) {
509
504
  service.registerFormatter(new HttpExceptionFormatter());
510
505
  service.registerFormatter(new UnknownExceptionFormatter());
511
506
  }
507
+
508
+ // src/utils/http-error.formatter.ts
509
+ var HttpErrorFormatter = class {
510
+ formatHttpException(exception) {
511
+ const response = exception.getResponse();
512
+ if (typeof response === "string") {
513
+ return [{ path: "http_error", message: [response] }];
514
+ }
515
+ if (typeof response === "object" && response !== null) {
516
+ const responseObj = response;
517
+ if (Array.isArray(responseObj.message)) {
518
+ return [
519
+ {
520
+ path: "http_error",
521
+ message: responseObj.message
522
+ }
523
+ ];
524
+ }
525
+ if (typeof responseObj.message === "string") {
526
+ return [{ path: "http_error", message: [responseObj.message] }];
527
+ }
528
+ if (responseObj.error && typeof responseObj.error === "string") {
529
+ return [{ path: "http_error", message: [responseObj.error] }];
530
+ }
531
+ }
532
+ return [{ path: "http_error", message: ["An error occurred"] }];
533
+ }
534
+ getMessage(exception) {
535
+ const response = exception.getResponse();
536
+ if (typeof response === "string") {
537
+ return response;
538
+ }
539
+ if (typeof response === "object" && response !== null) {
540
+ const responseObj = response;
541
+ if (typeof responseObj.message === "string") {
542
+ return responseObj.message;
543
+ }
544
+ if (responseObj.error && typeof responseObj.error === "string") {
545
+ return responseObj.error;
546
+ }
547
+ }
548
+ return "An error occurred";
549
+ }
550
+ };
512
551
  export {
513
552
  DtoValidationFormatter,
514
553
  ExceptionHandlerModule,
554
+ ExceptionHandlerService,
515
555
  GlobalExceptionFilter,
516
- OtherExceptionFormatter,
556
+ HttpErrorFormatter,
517
557
  PrismaExceptionFormatter,
558
+ ValidationErrorFormatter,
518
559
  initializeFormatters
519
560
  };
520
561
  //# sourceMappingURL=index.mjs.map