UNPKG

2.98 kBJavaScriptView Raw
1import { isNil } from "./lodash.js";
2
3export class AppError extends Error {
4 /**
5 * @param {string} key
6 * @param {number} status
7 * @param {object} [info={}]
8 * @param {Error} [originalError]
9 */
10 constructor(key, status, info, originalError) {
11 super();
12
13 this.key = key;
14 this.status = status;
15 this.info = info || {};
16 this.originalError = originalError;
17
18 Object.setPrototypeOf(this, AppError.prototype);
19
20 if (
21 isNil(key) ||
22 isNil(status) ||
23 typeof status !== "number" ||
24 typeof key !== "string"
25 ) {
26 return AppError.serverError(
27 {
28 appErrorConstructParams: {
29 key,
30 status,
31 },
32 },
33 this,
34 );
35 }
36 }
37
38 /**
39 * @param {*} value
40 * @returns {boolean}
41 */
42 static instanceOf(value) {
43 return (
44 value &&
45 typeof value.key === "string" &&
46 typeof value.status === "number" &&
47 !!value.info
48 );
49 }
50
51 /**
52 * @param {object} [info={}]
53 * @param {Error} [error]
54 * @returns {AppError}
55 */
56 static notFound(info = {}, error = undefined) {
57 return new AppError("error.server.notFound", 404, info, error);
58 }
59
60 /**
61 * @param {object} [info={}]
62 * @param {Error} [error]
63 * @returns {AppError}
64 */
65 static notImplemented(info = {}, error = undefined) {
66 return new AppError("error.server.notImplemented", 405, info, error);
67 }
68
69 /**
70 * @param {object} [info={}]
71 * @param {Error} [error]
72 * @returns {AppError}
73 */
74 static serverError(info = {}, error = undefined) {
75 return new AppError("error.server.internal", 500, info, error);
76 }
77
78 /**
79 * @param {string} key
80 * @param {object} [info={}]
81 * @param {Error} [error]
82 * @returns {AppError}
83 */
84 static validationError(key, info = {}, error = undefined) {
85 return new AppError(key, 400, info, error);
86 }
87
88 /**
89 * Format any error skipping the stack automatically for nested errors
90 *
91 * @param {AppError|Error} e
92 * @param {boolean} [skipStack=false]
93 * @returns {{ name: string, message: string, stack: string[] }|{ key: string, status:
94 * number, info: *, stack: string[], originalError: object }}
95 */
96 static format(e, skipStack = false) {
97 const stack = (e?.stack ?? "").split("\n").map((it) => it.trim());
98 // Remove first element as this is the Error name
99 stack.shift();
100
101 if (AppError.instanceOf(e)) {
102 return {
103 key: e.key,
104 status: e.status,
105 info: e.info,
106 stack: skipStack ? [] : stack,
107 originalError: e.originalError
108 ? !AppError.instanceOf(e.originalError)
109 ? typeof e.originalError.toJSON === "function"
110 ? e.originalError.toJSON()
111 : AppError.format(e.originalError, true)
112 : AppError.format(e.originalError, true)
113 : undefined,
114 };
115 }
116
117 return {
118 name: e.name,
119 message: e.message,
120 stack: skipStack ? [] : stack,
121 };
122 }
123}