@bool-ts/core 1.0.10 → 1.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/dist/hooks/factory.d.ts +11 -1
- package/dist/hooks/factory.js +22 -17
- package/dist/http/clientError.d.ts +40 -0
- package/dist/http/clientError.js +42 -0
- package/dist/http/index.d.ts +4 -0
- package/dist/http/index.js +58 -0
- package/dist/http/serverError.d.ts +22 -0
- package/dist/http/serverError.js +24 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/package.json +1 -1
- package/src/hooks/factory.ts +36 -17
- package/src/http/clientError.ts +57 -0
- package/src/http/index.ts +68 -0
- package/src/http/serverError.ts +39 -0
- package/src/index.ts +1 -0
package/dist/hooks/factory.d.ts
CHANGED
|
@@ -1,8 +1,18 @@
|
|
|
1
1
|
import "reflect-metadata";
|
|
2
2
|
import "colors";
|
|
3
|
+
export type TBoolFactoryOptions = Partial<{
|
|
4
|
+
debug: boolean;
|
|
5
|
+
log: Partial<{
|
|
6
|
+
methods: Array<"GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "OPTIONS">;
|
|
7
|
+
}>;
|
|
8
|
+
queryParser: Partial<{
|
|
9
|
+
depth: 10;
|
|
10
|
+
arrayLimit: 50;
|
|
11
|
+
}>;
|
|
12
|
+
}>;
|
|
3
13
|
/**
|
|
4
14
|
*
|
|
5
15
|
* @param target
|
|
6
16
|
*/
|
|
7
|
-
export declare const BoolFactory: (target: new (...args: any[]) => unknown) => import("express-serve-static-core").Express;
|
|
17
|
+
export declare const BoolFactory: (target: new (...args: any[]) => unknown, options?: TBoolFactoryOptions) => import("express-serve-static-core").Express;
|
|
8
18
|
export default BoolFactory;
|
package/dist/hooks/factory.js
CHANGED
|
@@ -5,6 +5,7 @@ import * as ResponseTime from "response-time";
|
|
|
5
5
|
import { controllerKey, controllerRoutesKey, moduleKey } from "../decorators";
|
|
6
6
|
import { default as ExpressApp, Router, json, urlencoded } from "express";
|
|
7
7
|
import { Injector } from "./injector";
|
|
8
|
+
import { errorInfer } from "../http";
|
|
8
9
|
/**
|
|
9
10
|
*
|
|
10
11
|
* @param target
|
|
@@ -46,7 +47,7 @@ const controllerCreator = (target, router = Router()) => {
|
|
|
46
47
|
*
|
|
47
48
|
* @param target
|
|
48
49
|
*/
|
|
49
|
-
export const BoolFactory = (target) => {
|
|
50
|
+
export const BoolFactory = (target, options) => {
|
|
50
51
|
if (!Reflect.getOwnMetadataKeys(target).includes(moduleKey)) {
|
|
51
52
|
throw Error(`${target.name} is not a module.`);
|
|
52
53
|
}
|
|
@@ -58,19 +59,13 @@ export const BoolFactory = (target) => {
|
|
|
58
59
|
const allowMethods = !metadata?.allowMethods ?
|
|
59
60
|
["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"] : metadata.allowMethods;
|
|
60
61
|
const app = ExpressApp();
|
|
61
|
-
const
|
|
62
|
-
allowLogsMethods: [
|
|
63
|
-
"GET",
|
|
64
|
-
"POST",
|
|
65
|
-
"PUT",
|
|
66
|
-
"PATCH",
|
|
67
|
-
"DELETE"
|
|
68
|
-
]
|
|
62
|
+
const factoryOptions = Object.freeze({
|
|
63
|
+
allowLogsMethods: !options?.log?.methods ? ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"] : options.log.methods
|
|
69
64
|
});
|
|
70
65
|
app.set("etag", "strong");
|
|
71
66
|
app.set("query parser", (query) => Qs.parse(query, {
|
|
72
|
-
|
|
73
|
-
|
|
67
|
+
depth: !options?.queryParser?.depth || options.queryParser.depth < 0 ? 10 : options.queryParser.depth,
|
|
68
|
+
arrayLimit: !options?.queryParser?.arrayLimit || options.queryParser.arrayLimit < 0 ? 50 : options.queryParser.arrayLimit
|
|
74
69
|
}));
|
|
75
70
|
app.use(urlencoded({
|
|
76
71
|
extended: true,
|
|
@@ -103,13 +98,16 @@ export const BoolFactory = (target) => {
|
|
|
103
98
|
},
|
|
104
99
|
// Error catcher
|
|
105
100
|
(err, req, res, next) => {
|
|
106
|
-
|
|
107
|
-
|
|
101
|
+
errorInfer(res, err);
|
|
102
|
+
if (!options?.debug) {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
console.error("Headers:", JSON.stringify(req.headers), "\nBody:", JSON.stringify(req.body), "\nError:", JSON.stringify(err));
|
|
108
106
|
},
|
|
109
107
|
// Response time log
|
|
110
108
|
ResponseTime.default((req, res, time) => {
|
|
111
109
|
const requestMethod = req.method.toUpperCase();
|
|
112
|
-
if (!
|
|
110
|
+
if (!factoryOptions.allowLogsMethods.includes(requestMethod)) {
|
|
113
111
|
return;
|
|
114
112
|
}
|
|
115
113
|
const convertedMethod = `${requestMethod.yellow}`.bgBlue;
|
|
@@ -122,8 +120,13 @@ export const BoolFactory = (target) => {
|
|
|
122
120
|
if (!allowOrigins.includes("*")) {
|
|
123
121
|
if (!allowOrigins.includes(req.headers.origin || "*")) {
|
|
124
122
|
return res.status(403).json({
|
|
125
|
-
|
|
126
|
-
|
|
123
|
+
httpCode: 403,
|
|
124
|
+
data: {
|
|
125
|
+
origin: {
|
|
126
|
+
code: "origin:invalid:0x00001",
|
|
127
|
+
message: "Invalid origin."
|
|
128
|
+
}
|
|
129
|
+
}
|
|
127
130
|
});
|
|
128
131
|
}
|
|
129
132
|
}
|
|
@@ -133,7 +136,9 @@ export const BoolFactory = (target) => {
|
|
|
133
136
|
res.header("Access-Control-Allow-Methods", allowMethods.join(", "));
|
|
134
137
|
next();
|
|
135
138
|
});
|
|
136
|
-
|
|
139
|
+
if (routers.length > 0) {
|
|
140
|
+
app.use(routers);
|
|
141
|
+
}
|
|
137
142
|
return app;
|
|
138
143
|
};
|
|
139
144
|
export default BoolFactory;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export declare const httpClientErrors: Readonly<{
|
|
2
|
+
400: "BAD_REQUEST";
|
|
3
|
+
401: "UNAUTHORIZED";
|
|
4
|
+
402: "PAYMENT_REQUIRED";
|
|
5
|
+
403: "FORBIDDEN";
|
|
6
|
+
404: "NOT_FOUND";
|
|
7
|
+
405: "METHOD_NOT_ALLOWED";
|
|
8
|
+
406: "NOT_ACCEPTABLE";
|
|
9
|
+
407: "PROXY_AUTHENCATION_REQUIRED";
|
|
10
|
+
408: "REQUEST_TIMEOUT";
|
|
11
|
+
409: "CONFLICT";
|
|
12
|
+
410: "GONE";
|
|
13
|
+
411: "LENGTH_REQUIRED";
|
|
14
|
+
412: "PRECONDITION_FAILED";
|
|
15
|
+
413: "PAYLOAD_TOO_LARGE";
|
|
16
|
+
414: "URI_TOO_LONG";
|
|
17
|
+
415: "UNSUPPORTED_MEDIA_TYPE";
|
|
18
|
+
416: "RANGE_NOT_SATISFIABLE";
|
|
19
|
+
417: "EXPECTATION_FAILED";
|
|
20
|
+
418: "IM_A_TEAPOT";
|
|
21
|
+
421: "MISDIRECTED_REQUEST";
|
|
22
|
+
422: "UNPROCESSABLE_ENTITY";
|
|
23
|
+
423: "LOCKED";
|
|
24
|
+
424: "FAILED_DEPENDENCY";
|
|
25
|
+
425: "TOO_EARLY_";
|
|
26
|
+
426: "UPGRAGE_REQUIRED";
|
|
27
|
+
428: "PRECONDITION_REQUIRED";
|
|
28
|
+
429: "TOO_MANY_REQUESTS";
|
|
29
|
+
431: "REQUEST_HEADER_FIELDS_TOO_LARGE";
|
|
30
|
+
451: "UNAVAILABLE_FOR_LEGAL_REASONS";
|
|
31
|
+
}>;
|
|
32
|
+
export declare class HttpClientError<T extends keyof typeof httpClientErrors = keyof typeof httpClientErrors, K = any> extends Error {
|
|
33
|
+
readonly httpCode: T;
|
|
34
|
+
readonly message: typeof httpClientErrors[T];
|
|
35
|
+
readonly data: K;
|
|
36
|
+
constructor({ httpCode, data }: {
|
|
37
|
+
["httpCode"]: T;
|
|
38
|
+
["data"]: K;
|
|
39
|
+
});
|
|
40
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export const httpClientErrors = Object.freeze({
|
|
2
|
+
400: "BAD_REQUEST",
|
|
3
|
+
401: "UNAUTHORIZED",
|
|
4
|
+
402: "PAYMENT_REQUIRED",
|
|
5
|
+
403: "FORBIDDEN",
|
|
6
|
+
404: "NOT_FOUND",
|
|
7
|
+
405: "METHOD_NOT_ALLOWED",
|
|
8
|
+
406: "NOT_ACCEPTABLE",
|
|
9
|
+
407: "PROXY_AUTHENCATION_REQUIRED",
|
|
10
|
+
408: "REQUEST_TIMEOUT",
|
|
11
|
+
409: "CONFLICT",
|
|
12
|
+
410: "GONE",
|
|
13
|
+
411: "LENGTH_REQUIRED",
|
|
14
|
+
412: "PRECONDITION_FAILED",
|
|
15
|
+
413: "PAYLOAD_TOO_LARGE",
|
|
16
|
+
414: "URI_TOO_LONG",
|
|
17
|
+
415: "UNSUPPORTED_MEDIA_TYPE",
|
|
18
|
+
416: "RANGE_NOT_SATISFIABLE",
|
|
19
|
+
417: "EXPECTATION_FAILED",
|
|
20
|
+
418: "IM_A_TEAPOT",
|
|
21
|
+
421: "MISDIRECTED_REQUEST",
|
|
22
|
+
422: "UNPROCESSABLE_ENTITY",
|
|
23
|
+
423: "LOCKED",
|
|
24
|
+
424: "FAILED_DEPENDENCY",
|
|
25
|
+
425: "TOO_EARLY_",
|
|
26
|
+
426: "UPGRAGE_REQUIRED",
|
|
27
|
+
428: "PRECONDITION_REQUIRED",
|
|
28
|
+
429: "TOO_MANY_REQUESTS",
|
|
29
|
+
431: "REQUEST_HEADER_FIELDS_TOO_LARGE",
|
|
30
|
+
451: "UNAVAILABLE_FOR_LEGAL_REASONS"
|
|
31
|
+
});
|
|
32
|
+
export class HttpClientError extends Error {
|
|
33
|
+
httpCode;
|
|
34
|
+
message;
|
|
35
|
+
data;
|
|
36
|
+
constructor({ httpCode, data }) {
|
|
37
|
+
super();
|
|
38
|
+
this.httpCode = httpCode;
|
|
39
|
+
this.message = httpClientErrors[httpCode];
|
|
40
|
+
this.data = data;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { HttpClientError } from "./clientError";
|
|
2
|
+
import { HttpServerError } from "./serverError";
|
|
3
|
+
export const errorInfer = (res, data) => {
|
|
4
|
+
if (res.headersSent) {
|
|
5
|
+
return;
|
|
6
|
+
}
|
|
7
|
+
try {
|
|
8
|
+
if (data instanceof HttpClientError) {
|
|
9
|
+
res.status(data.httpCode).json(data);
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
if (data instanceof HttpServerError) {
|
|
13
|
+
res.status(data.httpCode).json(data);
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
if (typeof data === "object") {
|
|
17
|
+
res.status(500).json({
|
|
18
|
+
httpCode: 500,
|
|
19
|
+
message: "INTERNAL SERVER ERROR",
|
|
20
|
+
data: data
|
|
21
|
+
});
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
switch (typeof data) {
|
|
25
|
+
case "string":
|
|
26
|
+
res.status(500).json({
|
|
27
|
+
httpCode: 500,
|
|
28
|
+
message: "INTERNAL SERVER ERROR",
|
|
29
|
+
data: {
|
|
30
|
+
message: data
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
return;
|
|
34
|
+
case "number":
|
|
35
|
+
res.status(500).json({
|
|
36
|
+
httpCode: 500,
|
|
37
|
+
message: "INTERNAL SERVER ERROR",
|
|
38
|
+
data: {
|
|
39
|
+
code: data
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
return;
|
|
43
|
+
default:
|
|
44
|
+
res.status(500).json({
|
|
45
|
+
httpCode: 500,
|
|
46
|
+
message: "INTERNAL SERVER ERROR",
|
|
47
|
+
data: undefined
|
|
48
|
+
});
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
console.error(error);
|
|
54
|
+
res.end();
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
export * from "./clientError";
|
|
58
|
+
export * from "./serverError";
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export declare const httpServerErrors: Readonly<{
|
|
2
|
+
500: "INTERNAL_SERVER_ERROR";
|
|
3
|
+
501: "NOT_IMPLEMENTED";
|
|
4
|
+
502: "BAD_GATEWAY";
|
|
5
|
+
503: "SERVICE_UNAVAILABLE";
|
|
6
|
+
504: "GATEWAY_TIMEOUT";
|
|
7
|
+
505: "HTTP_VERSION_NOT_SUPPORTED";
|
|
8
|
+
506: "VARIANT_ALSO_NEGOTIATES";
|
|
9
|
+
507: "INSUFFICIENT_STORAGE";
|
|
10
|
+
508: "LOOP_DETECTED";
|
|
11
|
+
510: "NOT_EXTENDED";
|
|
12
|
+
511: "NETWORK_AUTHENTICATION_REQUIRED";
|
|
13
|
+
}>;
|
|
14
|
+
export declare class HttpServerError<T extends keyof typeof httpServerErrors = keyof typeof httpServerErrors, K = any> extends Error {
|
|
15
|
+
readonly httpCode: T;
|
|
16
|
+
readonly message: typeof httpServerErrors[T];
|
|
17
|
+
readonly data: K;
|
|
18
|
+
constructor({ httpCode, data }: {
|
|
19
|
+
["httpCode"]: T;
|
|
20
|
+
["data"]: K;
|
|
21
|
+
});
|
|
22
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export const httpServerErrors = Object.freeze({
|
|
2
|
+
500: "INTERNAL_SERVER_ERROR",
|
|
3
|
+
501: "NOT_IMPLEMENTED",
|
|
4
|
+
502: "BAD_GATEWAY",
|
|
5
|
+
503: "SERVICE_UNAVAILABLE",
|
|
6
|
+
504: "GATEWAY_TIMEOUT",
|
|
7
|
+
505: "HTTP_VERSION_NOT_SUPPORTED",
|
|
8
|
+
506: "VARIANT_ALSO_NEGOTIATES",
|
|
9
|
+
507: "INSUFFICIENT_STORAGE",
|
|
10
|
+
508: "LOOP_DETECTED",
|
|
11
|
+
510: "NOT_EXTENDED",
|
|
12
|
+
511: "NETWORK_AUTHENTICATION_REQUIRED"
|
|
13
|
+
});
|
|
14
|
+
export class HttpServerError extends Error {
|
|
15
|
+
httpCode;
|
|
16
|
+
message;
|
|
17
|
+
data;
|
|
18
|
+
constructor({ httpCode, data }) {
|
|
19
|
+
super();
|
|
20
|
+
this.httpCode = httpCode;
|
|
21
|
+
this.message = httpServerErrors[httpCode];
|
|
22
|
+
this.data = data;
|
|
23
|
+
}
|
|
24
|
+
}
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
package/package.json
CHANGED
package/src/hooks/factory.ts
CHANGED
|
@@ -7,6 +7,19 @@ import * as ResponseTime from "response-time";
|
|
|
7
7
|
import { type IControllerRoute, type TModuleOptions, controllerKey, controllerRoutesKey, moduleKey } from "../decorators";
|
|
8
8
|
import { default as ExpressApp, Router, json, urlencoded, Request, Response, NextFunction, Errback } from "express";
|
|
9
9
|
import { Injector } from "./injector";
|
|
10
|
+
import { errorInfer } from "../http";
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
export type TBoolFactoryOptions = Partial<{
|
|
14
|
+
debug: boolean;
|
|
15
|
+
log: Partial<{
|
|
16
|
+
methods: Array<"GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "OPTIONS">;
|
|
17
|
+
}>;
|
|
18
|
+
queryParser: Partial<{
|
|
19
|
+
depth: 10,
|
|
20
|
+
arrayLimit: 50
|
|
21
|
+
}>;
|
|
22
|
+
}>;
|
|
10
23
|
|
|
11
24
|
|
|
12
25
|
/**
|
|
@@ -62,7 +75,8 @@ const controllerCreator = (
|
|
|
62
75
|
* @param target
|
|
63
76
|
*/
|
|
64
77
|
export const BoolFactory = (
|
|
65
|
-
target: new (...args: any[]) => unknown
|
|
78
|
+
target: new (...args: any[]) => unknown,
|
|
79
|
+
options?: TBoolFactoryOptions
|
|
66
80
|
) => {
|
|
67
81
|
if (!Reflect.getOwnMetadataKeys(target).includes(moduleKey)) {
|
|
68
82
|
throw Error(`${target.name} is not a module.`);
|
|
@@ -76,20 +90,14 @@ export const BoolFactory = (
|
|
|
76
90
|
const allowMethods = !metadata?.allowMethods ?
|
|
77
91
|
["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"] : metadata.allowMethods;
|
|
78
92
|
const app = ExpressApp();
|
|
79
|
-
const
|
|
80
|
-
allowLogsMethods: [
|
|
81
|
-
"GET",
|
|
82
|
-
"POST",
|
|
83
|
-
"PUT",
|
|
84
|
-
"PATCH",
|
|
85
|
-
"DELETE"
|
|
86
|
-
]
|
|
93
|
+
const factoryOptions = Object.freeze({
|
|
94
|
+
allowLogsMethods: !options?.log?.methods ? ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"] : options.log.methods
|
|
87
95
|
});
|
|
88
96
|
|
|
89
97
|
app.set("etag", "strong");
|
|
90
98
|
app.set("query parser", (query: string) => Qs.parse(query, {
|
|
91
|
-
|
|
92
|
-
|
|
99
|
+
depth: !options?.queryParser?.depth || options.queryParser.depth < 0 ? 10 : options.queryParser.depth,
|
|
100
|
+
arrayLimit: !options?.queryParser?.arrayLimit || options.queryParser.arrayLimit < 0 ? 50 : options.queryParser.arrayLimit
|
|
93
101
|
}));
|
|
94
102
|
|
|
95
103
|
app.use(
|
|
@@ -127,15 +135,19 @@ export const BoolFactory = (
|
|
|
127
135
|
},
|
|
128
136
|
// Error catcher
|
|
129
137
|
(err: Errback, req: Request, res: Response, next: NextFunction) => {
|
|
130
|
-
|
|
138
|
+
errorInfer(res, err);
|
|
131
139
|
|
|
132
|
-
|
|
140
|
+
if (!options?.debug) {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
console.error("Headers:", JSON.stringify(req.headers), "\nBody:", JSON.stringify(req.body), "\nError:", JSON.stringify(err));
|
|
133
145
|
},
|
|
134
146
|
// Response time log
|
|
135
147
|
ResponseTime.default((req: Request, res: Response, time: number) => {
|
|
136
148
|
const requestMethod = req.method.toUpperCase();
|
|
137
149
|
|
|
138
|
-
if (!
|
|
150
|
+
if (!factoryOptions.allowLogsMethods.includes(requestMethod)) {
|
|
139
151
|
return;
|
|
140
152
|
}
|
|
141
153
|
|
|
@@ -152,8 +164,13 @@ export const BoolFactory = (
|
|
|
152
164
|
if (!allowOrigins.includes("*")) {
|
|
153
165
|
if (!allowOrigins.includes(req.headers.origin || "*")) {
|
|
154
166
|
return res.status(403).json({
|
|
155
|
-
|
|
156
|
-
|
|
167
|
+
httpCode: 403,
|
|
168
|
+
data: {
|
|
169
|
+
origin: {
|
|
170
|
+
code: "origin:invalid:0x00001",
|
|
171
|
+
message: "Invalid origin."
|
|
172
|
+
}
|
|
173
|
+
}
|
|
157
174
|
});
|
|
158
175
|
}
|
|
159
176
|
}
|
|
@@ -166,7 +183,9 @@ export const BoolFactory = (
|
|
|
166
183
|
next();
|
|
167
184
|
});
|
|
168
185
|
|
|
169
|
-
|
|
186
|
+
if (routers.length > 0) {
|
|
187
|
+
app.use(routers);
|
|
188
|
+
}
|
|
170
189
|
|
|
171
190
|
return app;
|
|
172
191
|
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import * as ExpressJS from "express";
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
export const httpClientErrors = Object.freeze({
|
|
5
|
+
400: "BAD_REQUEST",
|
|
6
|
+
401: "UNAUTHORIZED",
|
|
7
|
+
402: "PAYMENT_REQUIRED",
|
|
8
|
+
403: "FORBIDDEN",
|
|
9
|
+
404: "NOT_FOUND",
|
|
10
|
+
405: "METHOD_NOT_ALLOWED",
|
|
11
|
+
406: "NOT_ACCEPTABLE",
|
|
12
|
+
407: "PROXY_AUTHENCATION_REQUIRED",
|
|
13
|
+
408: "REQUEST_TIMEOUT",
|
|
14
|
+
409: "CONFLICT",
|
|
15
|
+
410: "GONE",
|
|
16
|
+
411: "LENGTH_REQUIRED",
|
|
17
|
+
412: "PRECONDITION_FAILED",
|
|
18
|
+
413: "PAYLOAD_TOO_LARGE",
|
|
19
|
+
414: "URI_TOO_LONG",
|
|
20
|
+
415: "UNSUPPORTED_MEDIA_TYPE",
|
|
21
|
+
416: "RANGE_NOT_SATISFIABLE",
|
|
22
|
+
417: "EXPECTATION_FAILED",
|
|
23
|
+
418: "IM_A_TEAPOT",
|
|
24
|
+
421: "MISDIRECTED_REQUEST",
|
|
25
|
+
422: "UNPROCESSABLE_ENTITY",
|
|
26
|
+
423: "LOCKED",
|
|
27
|
+
424: "FAILED_DEPENDENCY",
|
|
28
|
+
425: "TOO_EARLY_",
|
|
29
|
+
426: "UPGRAGE_REQUIRED",
|
|
30
|
+
428: "PRECONDITION_REQUIRED",
|
|
31
|
+
429: "TOO_MANY_REQUESTS",
|
|
32
|
+
431: "REQUEST_HEADER_FIELDS_TOO_LARGE",
|
|
33
|
+
451: "UNAVAILABLE_FOR_LEGAL_REASONS"
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
export class HttpClientError<
|
|
37
|
+
T extends keyof typeof httpClientErrors = keyof typeof httpClientErrors,
|
|
38
|
+
K = any
|
|
39
|
+
> extends Error {
|
|
40
|
+
public readonly httpCode: T;
|
|
41
|
+
public readonly message: typeof httpClientErrors[T];
|
|
42
|
+
public readonly data: K;
|
|
43
|
+
|
|
44
|
+
constructor({
|
|
45
|
+
httpCode,
|
|
46
|
+
data
|
|
47
|
+
}: {
|
|
48
|
+
["httpCode"]: T;
|
|
49
|
+
["data"]: K;
|
|
50
|
+
}) {
|
|
51
|
+
super();
|
|
52
|
+
|
|
53
|
+
this.httpCode = httpCode;
|
|
54
|
+
this.message = httpClientErrors[httpCode];
|
|
55
|
+
this.data = data;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { Response } from "express";
|
|
2
|
+
import { HttpClientError } from "./clientError";
|
|
3
|
+
import { HttpServerError } from "./serverError";
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
export const errorInfer = (res: Response, data: any) => {
|
|
7
|
+
if (res.headersSent) {
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
try {
|
|
12
|
+
if (data instanceof HttpClientError) {
|
|
13
|
+
res.status(data.httpCode).json(data);
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if (data instanceof HttpServerError) {
|
|
18
|
+
res.status(data.httpCode).json(data);
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (typeof data === "object") {
|
|
23
|
+
res.status(500).json({
|
|
24
|
+
httpCode: 500,
|
|
25
|
+
message: "INTERNAL SERVER ERROR",
|
|
26
|
+
data: data
|
|
27
|
+
});
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
switch (typeof data) {
|
|
32
|
+
case "string":
|
|
33
|
+
res.status(500).json({
|
|
34
|
+
httpCode: 500,
|
|
35
|
+
message: "INTERNAL SERVER ERROR",
|
|
36
|
+
data: {
|
|
37
|
+
message: data
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
return;
|
|
41
|
+
|
|
42
|
+
case "number":
|
|
43
|
+
res.status(500).json({
|
|
44
|
+
httpCode: 500,
|
|
45
|
+
message: "INTERNAL SERVER ERROR",
|
|
46
|
+
data: {
|
|
47
|
+
code: data
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
return;
|
|
51
|
+
|
|
52
|
+
default:
|
|
53
|
+
res.status(500).json({
|
|
54
|
+
httpCode: 500,
|
|
55
|
+
message: "INTERNAL SERVER ERROR",
|
|
56
|
+
data: undefined
|
|
57
|
+
});
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
console.error(error);
|
|
63
|
+
res.end();
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export * from "./clientError";
|
|
68
|
+
export * from "./serverError";
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import * as ExpressJS from "express";
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
export const httpServerErrors = Object.freeze({
|
|
5
|
+
500: "INTERNAL_SERVER_ERROR",
|
|
6
|
+
501: "NOT_IMPLEMENTED",
|
|
7
|
+
502: "BAD_GATEWAY",
|
|
8
|
+
503: "SERVICE_UNAVAILABLE",
|
|
9
|
+
504: "GATEWAY_TIMEOUT",
|
|
10
|
+
505: "HTTP_VERSION_NOT_SUPPORTED",
|
|
11
|
+
506: "VARIANT_ALSO_NEGOTIATES",
|
|
12
|
+
507: "INSUFFICIENT_STORAGE",
|
|
13
|
+
508: "LOOP_DETECTED",
|
|
14
|
+
510: "NOT_EXTENDED",
|
|
15
|
+
511: "NETWORK_AUTHENTICATION_REQUIRED"
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
export class HttpServerError<
|
|
19
|
+
T extends keyof typeof httpServerErrors = keyof typeof httpServerErrors,
|
|
20
|
+
K = any
|
|
21
|
+
> extends Error {
|
|
22
|
+
public readonly httpCode: T;
|
|
23
|
+
public readonly message: typeof httpServerErrors[T];
|
|
24
|
+
public readonly data: K;
|
|
25
|
+
|
|
26
|
+
constructor({
|
|
27
|
+
httpCode,
|
|
28
|
+
data
|
|
29
|
+
}: {
|
|
30
|
+
["httpCode"]: T;
|
|
31
|
+
["data"]: K;
|
|
32
|
+
}) {
|
|
33
|
+
super();
|
|
34
|
+
|
|
35
|
+
this.httpCode = httpCode;
|
|
36
|
+
this.message = httpServerErrors[httpCode];
|
|
37
|
+
this.data = data;
|
|
38
|
+
}
|
|
39
|
+
}
|
package/src/index.ts
CHANGED