@bool-ts/core 1.0.11 → 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.
@@ -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;
@@ -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 configs = Object.freeze({
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
- depth: 10,
73
- arrayLimit: 50
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
- console.error(err);
107
- next();
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 (!configs.allowLogsMethods.includes(requestMethod)) {
110
+ if (!factoryOptions.allowLogsMethods.includes(requestMethod)) {
113
111
  return;
114
112
  }
115
113
  const convertedMethod = `${requestMethod.yellow}`.bgBlue;
@@ -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,4 @@
1
+ import { Response } from "express";
2
+ export declare const errorInfer: (res: Response, data: any) => void;
3
+ export * from "./clientError";
4
+ export * from "./serverError";
@@ -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
@@ -2,3 +2,4 @@ import "reflect-metadata";
2
2
  export * from "./interfaces";
3
3
  export * from "./hooks";
4
4
  export * from "./decorators";
5
+ export * from "./http";
package/dist/index.js CHANGED
@@ -2,3 +2,4 @@ import "reflect-metadata";
2
2
  export * from "./interfaces";
3
3
  export * from "./hooks";
4
4
  export * from "./decorators";
5
+ export * from "./http";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bool-ts/core",
3
- "version": "1.0.11",
3
+ "version": "1.1.0",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
@@ -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 configs = Object.freeze({
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
- depth: 10,
92
- arrayLimit: 50
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
- console.error(err);
138
+ errorInfer(res, err);
131
139
 
132
- next();
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 (!configs.allowLogsMethods.includes(requestMethod)) {
150
+ if (!factoryOptions.allowLogsMethods.includes(requestMethod)) {
139
151
  return;
140
152
  }
141
153
 
@@ -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
@@ -3,3 +3,4 @@ import "reflect-metadata";
3
3
  export * from "./interfaces";
4
4
  export * from "./hooks";
5
5
  export * from "./decorators";
6
+ export * from "./http";