@riktajs/core 0.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/LICENSE +21 -0
- package/README.md +205 -0
- package/dist/core/application.d.ts +28 -0
- package/dist/core/application.d.ts.map +1 -0
- package/dist/core/application.js +321 -0
- package/dist/core/application.js.map +1 -0
- package/dist/core/constants.d.ts +70 -0
- package/dist/core/constants.d.ts.map +1 -0
- package/dist/core/constants.js +77 -0
- package/dist/core/constants.js.map +1 -0
- package/dist/core/container/container.d.ts +101 -0
- package/dist/core/container/container.d.ts.map +1 -0
- package/dist/core/container/container.js +327 -0
- package/dist/core/container/container.js.map +1 -0
- package/dist/core/container/index.d.ts +3 -0
- package/dist/core/container/index.d.ts.map +1 -0
- package/dist/core/container/index.js +19 -0
- package/dist/core/container/index.js.map +1 -0
- package/dist/core/container/injection-token.d.ts +58 -0
- package/dist/core/container/injection-token.d.ts.map +1 -0
- package/dist/core/container/injection-token.js +37 -0
- package/dist/core/container/injection-token.js.map +1 -0
- package/dist/core/decorators/autowired.decorator.d.ts +72 -0
- package/dist/core/decorators/autowired.decorator.d.ts.map +1 -0
- package/dist/core/decorators/autowired.decorator.js +143 -0
- package/dist/core/decorators/autowired.decorator.js.map +1 -0
- package/dist/core/decorators/controller.decorator.d.ts +33 -0
- package/dist/core/decorators/controller.decorator.d.ts.map +1 -0
- package/dist/core/decorators/controller.decorator.js +50 -0
- package/dist/core/decorators/controller.decorator.js.map +1 -0
- package/dist/core/decorators/index.d.ts +7 -0
- package/dist/core/decorators/index.d.ts.map +1 -0
- package/dist/core/decorators/index.js +24 -0
- package/dist/core/decorators/index.js.map +1 -0
- package/dist/core/decorators/injectable.decorator.d.ts +26 -0
- package/dist/core/decorators/injectable.decorator.d.ts.map +1 -0
- package/dist/core/decorators/injectable.decorator.js +40 -0
- package/dist/core/decorators/injectable.decorator.js.map +1 -0
- package/dist/core/decorators/param.decorator.d.ts +72 -0
- package/dist/core/decorators/param.decorator.d.ts.map +1 -0
- package/dist/core/decorators/param.decorator.js +88 -0
- package/dist/core/decorators/param.decorator.js.map +1 -0
- package/dist/core/decorators/provider.decorator.d.ts +64 -0
- package/dist/core/decorators/provider.decorator.d.ts.map +1 -0
- package/dist/core/decorators/provider.decorator.js +69 -0
- package/dist/core/decorators/provider.decorator.js.map +1 -0
- package/dist/core/decorators/route.decorator.d.ts +53 -0
- package/dist/core/decorators/route.decorator.d.ts.map +1 -0
- package/dist/core/decorators/route.decorator.js +85 -0
- package/dist/core/decorators/route.decorator.js.map +1 -0
- package/dist/core/discovery.d.ts +24 -0
- package/dist/core/discovery.d.ts.map +1 -0
- package/dist/core/discovery.js +168 -0
- package/dist/core/discovery.js.map +1 -0
- package/dist/core/exceptions/catch.decorator.d.ts +71 -0
- package/dist/core/exceptions/catch.decorator.d.ts.map +1 -0
- package/dist/core/exceptions/catch.decorator.js +77 -0
- package/dist/core/exceptions/catch.decorator.js.map +1 -0
- package/dist/core/exceptions/exception-filter.d.ts +134 -0
- package/dist/core/exceptions/exception-filter.d.ts.map +1 -0
- package/dist/core/exceptions/exception-filter.js +161 -0
- package/dist/core/exceptions/exception-filter.js.map +1 -0
- package/dist/core/exceptions/exceptions.d.ts +212 -0
- package/dist/core/exceptions/exceptions.d.ts.map +1 -0
- package/dist/core/exceptions/exceptions.js +275 -0
- package/dist/core/exceptions/exceptions.js.map +1 -0
- package/dist/core/exceptions/http-exception.d.ts +79 -0
- package/dist/core/exceptions/http-exception.d.ts.map +1 -0
- package/dist/core/exceptions/http-exception.js +106 -0
- package/dist/core/exceptions/http-exception.js.map +1 -0
- package/dist/core/exceptions/index.d.ts +5 -0
- package/dist/core/exceptions/index.d.ts.map +1 -0
- package/dist/core/exceptions/index.js +38 -0
- package/dist/core/exceptions/index.js.map +1 -0
- package/dist/core/index.d.ts +11 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +28 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/lifecycle/event-bus.d.ts +96 -0
- package/dist/core/lifecycle/event-bus.d.ts.map +1 -0
- package/dist/core/lifecycle/event-bus.js +91 -0
- package/dist/core/lifecycle/event-bus.js.map +1 -0
- package/dist/core/lifecycle/index.d.ts +4 -0
- package/dist/core/lifecycle/index.d.ts.map +1 -0
- package/dist/core/lifecycle/index.js +21 -0
- package/dist/core/lifecycle/index.js.map +1 -0
- package/dist/core/lifecycle/interfaces.d.ts +106 -0
- package/dist/core/lifecycle/interfaces.d.ts.map +1 -0
- package/dist/core/lifecycle/interfaces.js +10 -0
- package/dist/core/lifecycle/interfaces.js.map +1 -0
- package/dist/core/lifecycle/on.decorator.d.ts +62 -0
- package/dist/core/lifecycle/on.decorator.d.ts.map +1 -0
- package/dist/core/lifecycle/on.decorator.js +65 -0
- package/dist/core/lifecycle/on.decorator.js.map +1 -0
- package/dist/core/registry.d.ts +64 -0
- package/dist/core/registry.d.ts.map +1 -0
- package/dist/core/registry.js +91 -0
- package/dist/core/registry.js.map +1 -0
- package/dist/core/router/router.d.ts +39 -0
- package/dist/core/router/router.d.ts.map +1 -0
- package/dist/core/router/router.js +150 -0
- package/dist/core/router/router.js.map +1 -0
- package/dist/core/types.d.ts +161 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +3 -0
- package/dist/core/types.js.map +1 -0
- package/dist/index.d.ts +44 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +64 -0
- package/dist/index.js.map +1 -0
- package/package.json +47 -0
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import type { FastifyRequest, FastifyReply, FastifyError } from 'fastify';
|
|
2
|
+
/**
|
|
3
|
+
* Exception context passed to filters
|
|
4
|
+
*/
|
|
5
|
+
export interface ExceptionContext {
|
|
6
|
+
/** The caught exception */
|
|
7
|
+
exception: Error;
|
|
8
|
+
/** Fastify request object */
|
|
9
|
+
request: FastifyRequest;
|
|
10
|
+
/** Fastify reply object */
|
|
11
|
+
reply: FastifyReply;
|
|
12
|
+
/** Request path */
|
|
13
|
+
path: string;
|
|
14
|
+
/** HTTP method */
|
|
15
|
+
method: string;
|
|
16
|
+
/** Request ID (if available) */
|
|
17
|
+
requestId?: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Exception Filter Interface
|
|
21
|
+
*
|
|
22
|
+
* Implement this interface to create custom exception handlers.
|
|
23
|
+
* Filters can catch specific exception types or handle all exceptions.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```typescript
|
|
27
|
+
* @Catch(ValidationException)
|
|
28
|
+
* class ValidationExceptionFilter implements ExceptionFilter {
|
|
29
|
+
* catch(exception: ValidationException, context: ExceptionContext) {
|
|
30
|
+
* const { reply } = context;
|
|
31
|
+
* reply.status(422).send({
|
|
32
|
+
* statusCode: 422,
|
|
33
|
+
* errors: exception.errors,
|
|
34
|
+
* timestamp: new Date().toISOString()
|
|
35
|
+
* });
|
|
36
|
+
* }
|
|
37
|
+
* }
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export interface ExceptionFilter<T extends Error = Error> {
|
|
41
|
+
/**
|
|
42
|
+
* Handle the caught exception
|
|
43
|
+
*
|
|
44
|
+
* @param exception - The caught exception
|
|
45
|
+
* @param context - Exception context with request/reply
|
|
46
|
+
*/
|
|
47
|
+
catch(exception: T, context: ExceptionContext): void | Promise<void>;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Standard error response format
|
|
51
|
+
*/
|
|
52
|
+
export interface ErrorResponse {
|
|
53
|
+
/** HTTP status code */
|
|
54
|
+
statusCode: number;
|
|
55
|
+
/** Error message */
|
|
56
|
+
message: string;
|
|
57
|
+
/** Error type/name (e.g., "Bad Request", "Not Found") */
|
|
58
|
+
error: string;
|
|
59
|
+
/** ISO timestamp when the error occurred */
|
|
60
|
+
timestamp: string;
|
|
61
|
+
/** Request path that caused the error */
|
|
62
|
+
path: string;
|
|
63
|
+
/** Request ID for tracing (optional) */
|
|
64
|
+
requestId?: string;
|
|
65
|
+
/** Additional error details (optional) */
|
|
66
|
+
details?: unknown;
|
|
67
|
+
/** Application-specific error code (optional) */
|
|
68
|
+
code?: string;
|
|
69
|
+
/** Stack trace (only in development mode) */
|
|
70
|
+
stack?: string;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Global Exception Filter
|
|
74
|
+
*
|
|
75
|
+
* Default exception handler that catches all errors and returns
|
|
76
|
+
* a standardized JSON response.
|
|
77
|
+
*
|
|
78
|
+
* Features:
|
|
79
|
+
* - Handles HttpException with proper status codes
|
|
80
|
+
* - Handles Fastify validation errors
|
|
81
|
+
* - Handles unknown errors as 500 Internal Server Error
|
|
82
|
+
* - Includes stack traces in development mode
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* ```typescript
|
|
86
|
+
* // The filter is automatically registered by Rikta
|
|
87
|
+
* // But you can customize behavior via options:
|
|
88
|
+
* const app = await Rikta.create({
|
|
89
|
+
* exceptionFilter: {
|
|
90
|
+
* includeStack: process.env.NODE_ENV !== 'production',
|
|
91
|
+
* logErrors: true
|
|
92
|
+
* }
|
|
93
|
+
* });
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
export declare class GlobalExceptionFilter implements ExceptionFilter {
|
|
97
|
+
private readonly includeStack;
|
|
98
|
+
private readonly logErrors;
|
|
99
|
+
constructor(options?: GlobalExceptionFilterOptions);
|
|
100
|
+
/**
|
|
101
|
+
* Handle any exception and send standardized response
|
|
102
|
+
*/
|
|
103
|
+
catch(exception: Error, context: ExceptionContext): void;
|
|
104
|
+
/**
|
|
105
|
+
* Build standardized error response
|
|
106
|
+
*/
|
|
107
|
+
private buildResponse;
|
|
108
|
+
/**
|
|
109
|
+
* Check if error is a Fastify validation error
|
|
110
|
+
*/
|
|
111
|
+
private isFastifyValidationError;
|
|
112
|
+
/**
|
|
113
|
+
* Check if error is a Fastify error with statusCode
|
|
114
|
+
*/
|
|
115
|
+
private isFastifyError;
|
|
116
|
+
/**
|
|
117
|
+
* Log error to console
|
|
118
|
+
*/
|
|
119
|
+
private logError;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Options for GlobalExceptionFilter
|
|
123
|
+
*/
|
|
124
|
+
export interface GlobalExceptionFilterOptions {
|
|
125
|
+
/** Include stack trace in response (default: true in development) */
|
|
126
|
+
includeStack?: boolean;
|
|
127
|
+
/** Log errors to console (default: true) */
|
|
128
|
+
logErrors?: boolean;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Create exception handler function for Fastify
|
|
132
|
+
*/
|
|
133
|
+
export declare function createExceptionHandler(filter: ExceptionFilter, customFilters?: Map<Function, ExceptionFilter>): (error: FastifyError | Error, request: FastifyRequest, reply: FastifyReply) => Promise<void>;
|
|
134
|
+
//# sourceMappingURL=exception-filter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exception-filter.d.ts","sourceRoot":"","sources":["../../../src/core/exceptions/exception-filter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAG1E;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,2BAA2B;IAC3B,SAAS,EAAE,KAAK,CAAC;IAEjB,6BAA6B;IAC7B,OAAO,EAAE,cAAc,CAAC;IAExB,2BAA2B;IAC3B,KAAK,EAAE,YAAY,CAAC;IAEpB,mBAAmB;IACnB,IAAI,EAAE,MAAM,CAAC;IAEb,kBAAkB;IAClB,MAAM,EAAE,MAAM,CAAC;IAEf,gCAAgC;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,WAAW,eAAe,CAAC,CAAC,SAAS,KAAK,GAAG,KAAK;IACtD;;;;;OAKG;IACH,KAAK,CAAC,SAAS,EAAE,CAAC,EAAE,OAAO,EAAE,gBAAgB,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACtE;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,uBAAuB;IACvB,UAAU,EAAE,MAAM,CAAC;IAEnB,oBAAoB;IACpB,OAAO,EAAE,MAAM,CAAC;IAEhB,yDAAyD;IACzD,KAAK,EAAE,MAAM,CAAC;IAEd,4CAA4C;IAC5C,SAAS,EAAE,MAAM,CAAC;IAElB,yCAAyC;IACzC,IAAI,EAAE,MAAM,CAAC;IAEb,wCAAwC;IACxC,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,0CAA0C;IAC1C,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB,iDAAiD;IACjD,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,6CAA6C;IAC7C,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,qBAAa,qBAAsB,YAAW,eAAe;IAC3D,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAU;IACvC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAU;gBAExB,OAAO,GAAE,4BAAiC;IAKtD;;OAEG;IACH,KAAK,CAAC,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,gBAAgB,GAAG,IAAI;IAgBxD;;OAEG;IACH,OAAO,CAAC,aAAa;IA6DrB;;OAEG;IACH,OAAO,CAAC,wBAAwB;IAIhC;;OAEG;IACH,OAAO,CAAC,cAAc;IAItB;;OAEG;IACH,OAAO,CAAC,QAAQ;CAuBjB;AAED;;GAEG;AACH,MAAM,WAAW,4BAA4B;IAC3C,qEAAqE;IACrE,YAAY,CAAC,EAAE,OAAO,CAAC;IAEvB,4CAA4C;IAC5C,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,eAAe,EACvB,aAAa,GAAE,GAAG,CAAC,QAAQ,EAAE,eAAe,CAAa,IAGvD,OAAO,YAAY,GAAG,KAAK,EAC3B,SAAS,cAAc,EACvB,OAAO,YAAY,mBAqBtB"}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.GlobalExceptionFilter = void 0;
|
|
4
|
+
exports.createExceptionHandler = createExceptionHandler;
|
|
5
|
+
const http_exception_1 = require("./http-exception");
|
|
6
|
+
/**
|
|
7
|
+
* Global Exception Filter
|
|
8
|
+
*
|
|
9
|
+
* Default exception handler that catches all errors and returns
|
|
10
|
+
* a standardized JSON response.
|
|
11
|
+
*
|
|
12
|
+
* Features:
|
|
13
|
+
* - Handles HttpException with proper status codes
|
|
14
|
+
* - Handles Fastify validation errors
|
|
15
|
+
* - Handles unknown errors as 500 Internal Server Error
|
|
16
|
+
* - Includes stack traces in development mode
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```typescript
|
|
20
|
+
* // The filter is automatically registered by Rikta
|
|
21
|
+
* // But you can customize behavior via options:
|
|
22
|
+
* const app = await Rikta.create({
|
|
23
|
+
* exceptionFilter: {
|
|
24
|
+
* includeStack: process.env.NODE_ENV !== 'production',
|
|
25
|
+
* logErrors: true
|
|
26
|
+
* }
|
|
27
|
+
* });
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
class GlobalExceptionFilter {
|
|
31
|
+
includeStack;
|
|
32
|
+
logErrors;
|
|
33
|
+
constructor(options = {}) {
|
|
34
|
+
this.includeStack = options.includeStack ?? process.env.NODE_ENV !== 'production';
|
|
35
|
+
this.logErrors = options.logErrors ?? true;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Handle any exception and send standardized response
|
|
39
|
+
*/
|
|
40
|
+
catch(exception, context) {
|
|
41
|
+
const { request, reply, path, method } = context;
|
|
42
|
+
const requestId = request.id ?? undefined;
|
|
43
|
+
// Log the error
|
|
44
|
+
if (this.logErrors) {
|
|
45
|
+
this.logError(exception, method, path, requestId);
|
|
46
|
+
}
|
|
47
|
+
// Build error response
|
|
48
|
+
const response = this.buildResponse(exception, path, requestId);
|
|
49
|
+
// Send response
|
|
50
|
+
reply.status(response.statusCode).send(response);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Build standardized error response
|
|
54
|
+
*/
|
|
55
|
+
buildResponse(exception, path, requestId) {
|
|
56
|
+
// Handle HttpException
|
|
57
|
+
if (exception instanceof http_exception_1.HttpException) {
|
|
58
|
+
const httpResponse = exception.getResponse();
|
|
59
|
+
return {
|
|
60
|
+
statusCode: httpResponse.statusCode,
|
|
61
|
+
message: httpResponse.message,
|
|
62
|
+
error: httpResponse.error,
|
|
63
|
+
timestamp: httpResponse.timestamp,
|
|
64
|
+
path,
|
|
65
|
+
...(requestId ? { requestId } : {}),
|
|
66
|
+
...(httpResponse.details ? { details: httpResponse.details } : {}),
|
|
67
|
+
...(httpResponse.code ? { code: httpResponse.code } : {}),
|
|
68
|
+
...(this.includeStack ? { stack: exception.stack } : {}),
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
// Handle Fastify validation errors
|
|
72
|
+
if (this.isFastifyValidationError(exception)) {
|
|
73
|
+
return {
|
|
74
|
+
statusCode: 400,
|
|
75
|
+
message: 'Validation failed',
|
|
76
|
+
error: 'Bad Request',
|
|
77
|
+
timestamp: new Date().toISOString(),
|
|
78
|
+
path,
|
|
79
|
+
...(requestId && { requestId }),
|
|
80
|
+
details: exception.validation,
|
|
81
|
+
...(this.includeStack && { stack: exception.stack }),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
// Handle Fastify errors with statusCode
|
|
85
|
+
if (this.isFastifyError(exception)) {
|
|
86
|
+
const fastifyError = exception;
|
|
87
|
+
return {
|
|
88
|
+
statusCode: fastifyError.statusCode ?? 500,
|
|
89
|
+
message: fastifyError.message,
|
|
90
|
+
error: fastifyError.code ?? 'Error',
|
|
91
|
+
timestamp: new Date().toISOString(),
|
|
92
|
+
path,
|
|
93
|
+
...(requestId && { requestId }),
|
|
94
|
+
...(this.includeStack && { stack: exception.stack }),
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
// Handle unknown errors as 500
|
|
98
|
+
return {
|
|
99
|
+
statusCode: 500,
|
|
100
|
+
message: this.includeStack ? exception.message : 'Internal Server Error',
|
|
101
|
+
error: 'Internal Server Error',
|
|
102
|
+
timestamp: new Date().toISOString(),
|
|
103
|
+
path,
|
|
104
|
+
...(requestId && { requestId }),
|
|
105
|
+
...(this.includeStack && { stack: exception.stack }),
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Check if error is a Fastify validation error
|
|
110
|
+
*/
|
|
111
|
+
isFastifyValidationError(error) {
|
|
112
|
+
return 'validation' in error && Array.isArray(error.validation);
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Check if error is a Fastify error with statusCode
|
|
116
|
+
*/
|
|
117
|
+
isFastifyError(error) {
|
|
118
|
+
return 'statusCode' in error;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Log error to console
|
|
122
|
+
*/
|
|
123
|
+
logError(exception, method, path, requestId) {
|
|
124
|
+
const timestamp = new Date().toISOString();
|
|
125
|
+
const status = exception instanceof http_exception_1.HttpException
|
|
126
|
+
? exception.getStatus()
|
|
127
|
+
: 500;
|
|
128
|
+
const prefix = status >= 500 ? '❌' : '⚠️';
|
|
129
|
+
const reqIdStr = requestId ? ` [${requestId}]` : '';
|
|
130
|
+
console.error(`${prefix} [${timestamp}]${reqIdStr} ${method} ${path} - ${status} ${exception.message}`);
|
|
131
|
+
// Log stack trace for 5xx errors in development
|
|
132
|
+
if (status >= 500 && this.includeStack && exception.stack) {
|
|
133
|
+
console.error(exception.stack);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
exports.GlobalExceptionFilter = GlobalExceptionFilter;
|
|
138
|
+
/**
|
|
139
|
+
* Create exception handler function for Fastify
|
|
140
|
+
*/
|
|
141
|
+
function createExceptionHandler(filter, customFilters = new Map()) {
|
|
142
|
+
return async (error, request, reply) => {
|
|
143
|
+
const context = {
|
|
144
|
+
exception: error,
|
|
145
|
+
request,
|
|
146
|
+
reply,
|
|
147
|
+
path: request.url,
|
|
148
|
+
method: request.method,
|
|
149
|
+
requestId: request.id,
|
|
150
|
+
};
|
|
151
|
+
// Try to find a custom filter for this exception type
|
|
152
|
+
for (const [ExceptionType, customFilter] of customFilters) {
|
|
153
|
+
if (error instanceof ExceptionType) {
|
|
154
|
+
return customFilter.catch(error, context);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
// Use global filter
|
|
158
|
+
return filter.catch(error, context);
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
//# sourceMappingURL=exception-filter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exception-filter.js","sourceRoot":"","sources":["../../../src/core/exceptions/exception-filter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import { HttpException, HttpExceptionBody } from './http-exception';
|
|
2
|
+
/**
|
|
3
|
+
* 400 Bad Request
|
|
4
|
+
*
|
|
5
|
+
* The server cannot process the request due to client error.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* throw new BadRequestException('Invalid input data');
|
|
10
|
+
*
|
|
11
|
+
* throw new BadRequestException({
|
|
12
|
+
* message: 'Validation failed',
|
|
13
|
+
* details: { email: 'Invalid format' }
|
|
14
|
+
* });
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export declare class BadRequestException extends HttpException {
|
|
18
|
+
constructor(response?: string | HttpExceptionBody);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* 401 Unauthorized
|
|
22
|
+
*
|
|
23
|
+
* Authentication is required and has failed or not been provided.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```typescript
|
|
27
|
+
* throw new UnauthorizedException('Invalid credentials');
|
|
28
|
+
* throw new UnauthorizedException('Token expired');
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export declare class UnauthorizedException extends HttpException {
|
|
32
|
+
constructor(response?: string | HttpExceptionBody);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* 403 Forbidden
|
|
36
|
+
*
|
|
37
|
+
* The server understood the request but refuses to authorize it.
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```typescript
|
|
41
|
+
* throw new ForbiddenException('Access denied');
|
|
42
|
+
* throw new ForbiddenException('Insufficient permissions');
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export declare class ForbiddenException extends HttpException {
|
|
46
|
+
constructor(response?: string | HttpExceptionBody);
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* 404 Not Found
|
|
50
|
+
*
|
|
51
|
+
* The requested resource could not be found.
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```typescript
|
|
55
|
+
* throw new NotFoundException('User not found');
|
|
56
|
+
* throw new NotFoundException(`Resource ${id} not found`);
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
export declare class NotFoundException extends HttpException {
|
|
60
|
+
constructor(response?: string | HttpExceptionBody);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* 405 Method Not Allowed
|
|
64
|
+
*
|
|
65
|
+
* The request method is not supported for the requested resource.
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```typescript
|
|
69
|
+
* throw new MethodNotAllowedException('POST not allowed on this endpoint');
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
export declare class MethodNotAllowedException extends HttpException {
|
|
73
|
+
constructor(response?: string | HttpExceptionBody);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* 406 Not Acceptable
|
|
77
|
+
*
|
|
78
|
+
* The requested resource is not capable of generating content acceptable
|
|
79
|
+
* according to the Accept headers sent in the request.
|
|
80
|
+
*/
|
|
81
|
+
export declare class NotAcceptableException extends HttpException {
|
|
82
|
+
constructor(response?: string | HttpExceptionBody);
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* 408 Request Timeout
|
|
86
|
+
*
|
|
87
|
+
* The server timed out waiting for the request.
|
|
88
|
+
*/
|
|
89
|
+
export declare class RequestTimeoutException extends HttpException {
|
|
90
|
+
constructor(response?: string | HttpExceptionBody);
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* 409 Conflict
|
|
94
|
+
*
|
|
95
|
+
* The request conflicts with the current state of the server.
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* ```typescript
|
|
99
|
+
* throw new ConflictException('Email already exists');
|
|
100
|
+
* throw new ConflictException('Version conflict');
|
|
101
|
+
* ```
|
|
102
|
+
*/
|
|
103
|
+
export declare class ConflictException extends HttpException {
|
|
104
|
+
constructor(response?: string | HttpExceptionBody);
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* 410 Gone
|
|
108
|
+
*
|
|
109
|
+
* The resource is no longer available and will not be available again.
|
|
110
|
+
*/
|
|
111
|
+
export declare class GoneException extends HttpException {
|
|
112
|
+
constructor(response?: string | HttpExceptionBody);
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* 413 Payload Too Large
|
|
116
|
+
*
|
|
117
|
+
* The request entity is larger than limits defined by the server.
|
|
118
|
+
*/
|
|
119
|
+
export declare class PayloadTooLargeException extends HttpException {
|
|
120
|
+
constructor(response?: string | HttpExceptionBody);
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* 415 Unsupported Media Type
|
|
124
|
+
*
|
|
125
|
+
* The media format of the requested data is not supported by the server.
|
|
126
|
+
*/
|
|
127
|
+
export declare class UnsupportedMediaTypeException extends HttpException {
|
|
128
|
+
constructor(response?: string | HttpExceptionBody);
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* 422 Unprocessable Entity
|
|
132
|
+
*
|
|
133
|
+
* The server understands the content type, but was unable to process the contained instructions.
|
|
134
|
+
*
|
|
135
|
+
* @example
|
|
136
|
+
* ```typescript
|
|
137
|
+
* throw new UnprocessableEntityException({
|
|
138
|
+
* message: 'Validation failed',
|
|
139
|
+
* details: [
|
|
140
|
+
* { field: 'email', message: 'Invalid email format' },
|
|
141
|
+
* { field: 'age', message: 'Must be a positive number' }
|
|
142
|
+
* ]
|
|
143
|
+
* });
|
|
144
|
+
* ```
|
|
145
|
+
*/
|
|
146
|
+
export declare class UnprocessableEntityException extends HttpException {
|
|
147
|
+
constructor(response?: string | HttpExceptionBody);
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* 429 Too Many Requests
|
|
151
|
+
*
|
|
152
|
+
* The user has sent too many requests in a given amount of time.
|
|
153
|
+
*
|
|
154
|
+
* @example
|
|
155
|
+
* ```typescript
|
|
156
|
+
* throw new TooManyRequestsException('Rate limit exceeded. Try again in 60 seconds.');
|
|
157
|
+
* ```
|
|
158
|
+
*/
|
|
159
|
+
export declare class TooManyRequestsException extends HttpException {
|
|
160
|
+
constructor(response?: string | HttpExceptionBody);
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* 500 Internal Server Error
|
|
164
|
+
*
|
|
165
|
+
* A generic server error occurred.
|
|
166
|
+
*
|
|
167
|
+
* @example
|
|
168
|
+
* ```typescript
|
|
169
|
+
* throw new InternalServerErrorException('An unexpected error occurred');
|
|
170
|
+
* ```
|
|
171
|
+
*/
|
|
172
|
+
export declare class InternalServerErrorException extends HttpException {
|
|
173
|
+
constructor(response?: string | HttpExceptionBody);
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* 501 Not Implemented
|
|
177
|
+
*
|
|
178
|
+
* The server does not support the functionality required to fulfill the request.
|
|
179
|
+
*/
|
|
180
|
+
export declare class NotImplementedException extends HttpException {
|
|
181
|
+
constructor(response?: string | HttpExceptionBody);
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* 502 Bad Gateway
|
|
185
|
+
*
|
|
186
|
+
* The server received an invalid response from an upstream server.
|
|
187
|
+
*/
|
|
188
|
+
export declare class BadGatewayException extends HttpException {
|
|
189
|
+
constructor(response?: string | HttpExceptionBody);
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* 503 Service Unavailable
|
|
193
|
+
*
|
|
194
|
+
* The server is not ready to handle the request.
|
|
195
|
+
*
|
|
196
|
+
* @example
|
|
197
|
+
* ```typescript
|
|
198
|
+
* throw new ServiceUnavailableException('Service is under maintenance');
|
|
199
|
+
* ```
|
|
200
|
+
*/
|
|
201
|
+
export declare class ServiceUnavailableException extends HttpException {
|
|
202
|
+
constructor(response?: string | HttpExceptionBody);
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* 504 Gateway Timeout
|
|
206
|
+
*
|
|
207
|
+
* The server did not receive a timely response from an upstream server.
|
|
208
|
+
*/
|
|
209
|
+
export declare class GatewayTimeoutException extends HttpException {
|
|
210
|
+
constructor(response?: string | HttpExceptionBody);
|
|
211
|
+
}
|
|
212
|
+
//# sourceMappingURL=exceptions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exceptions.d.ts","sourceRoot":"","sources":["../../../src/core/exceptions/exceptions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAMpE;;;;;;;;;;;;;;GAcG;AACH,qBAAa,mBAAoB,SAAQ,aAAa;gBACxC,QAAQ,GAAE,MAAM,GAAG,iBAAiC;CAGjE;AAED;;;;;;;;;;GAUG;AACH,qBAAa,qBAAsB,SAAQ,aAAa;gBAC1C,QAAQ,GAAE,MAAM,GAAG,iBAAkC;CAGlE;AAED;;;;;;;;;;GAUG;AACH,qBAAa,kBAAmB,SAAQ,aAAa;gBACvC,QAAQ,GAAE,MAAM,GAAG,iBAA+B;CAG/D;AAED;;;;;;;;;;GAUG;AACH,qBAAa,iBAAkB,SAAQ,aAAa;gBACtC,QAAQ,GAAE,MAAM,GAAG,iBAA+B;CAG/D;AAED;;;;;;;;;GASG;AACH,qBAAa,yBAA0B,SAAQ,aAAa;gBAC9C,QAAQ,GAAE,MAAM,GAAG,iBAAwC;CAGxE;AAED;;;;;GAKG;AACH,qBAAa,sBAAuB,SAAQ,aAAa;gBAC3C,QAAQ,GAAE,MAAM,GAAG,iBAAoC;CAGpE;AAED;;;;GAIG;AACH,qBAAa,uBAAwB,SAAQ,aAAa;gBAC5C,QAAQ,GAAE,MAAM,GAAG,iBAAqC;CAGrE;AAED;;;;;;;;;;GAUG;AACH,qBAAa,iBAAkB,SAAQ,aAAa;gBACtC,QAAQ,GAAE,MAAM,GAAG,iBAA8B;CAG9D;AAED;;;;GAIG;AACH,qBAAa,aAAc,SAAQ,aAAa;gBAClC,QAAQ,GAAE,MAAM,GAAG,iBAA0B;CAG1D;AAED;;;;GAIG;AACH,qBAAa,wBAAyB,SAAQ,aAAa;gBAC7C,QAAQ,GAAE,MAAM,GAAG,iBAAuC;CAGvE;AAED;;;;GAIG;AACH,qBAAa,6BAA8B,SAAQ,aAAa;gBAClD,QAAQ,GAAE,MAAM,GAAG,iBAA4C;CAG5E;AAED;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,4BAA6B,SAAQ,aAAa;gBACjD,QAAQ,GAAE,MAAM,GAAG,iBAA0C;CAG1E;AAED;;;;;;;;;GASG;AACH,qBAAa,wBAAyB,SAAQ,aAAa;gBAC7C,QAAQ,GAAE,MAAM,GAAG,iBAAuC;CAGvE;AAMD;;;;;;;;;GASG;AACH,qBAAa,4BAA6B,SAAQ,aAAa;gBACjD,QAAQ,GAAE,MAAM,GAAG,iBAA2C;CAG3E;AAED;;;;GAIG;AACH,qBAAa,uBAAwB,SAAQ,aAAa;gBAC5C,QAAQ,GAAE,MAAM,GAAG,iBAAqC;CAGrE;AAED;;;;GAIG;AACH,qBAAa,mBAAoB,SAAQ,aAAa;gBACxC,QAAQ,GAAE,MAAM,GAAG,iBAAiC;CAGjE;AAED;;;;;;;;;GASG;AACH,qBAAa,2BAA4B,SAAQ,aAAa;gBAChD,QAAQ,GAAE,MAAM,GAAG,iBAAyC;CAGzE;AAED;;;;GAIG;AACH,qBAAa,uBAAwB,SAAQ,aAAa;gBAC5C,QAAQ,GAAE,MAAM,GAAG,iBAAqC;CAGrE"}
|