@tryghost/errors 1.2.27 → 1.3.1
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/cjs/GhostError.js +83 -0
- package/cjs/errors.js +330 -0
- package/cjs/index.js +45 -0
- package/cjs/utils.js +204 -0
- package/cjs/wrap-stack.js +29 -0
- package/es/GhostError.js +64 -0
- package/es/errors.js +310 -0
- package/es/index.js +14 -0
- package/es/utils.js +174 -0
- package/es/wrap-stack.js +9 -0
- package/package.json +27 -10
- package/src/GhostError.ts +96 -0
- package/src/errors.ts +312 -0
- package/src/index.ts +14 -0
- package/src/utils.ts +238 -0
- package/src/wrap-stack.ts +5 -0
- package/types/GhostError.d.ts +30 -0
- package/types/GhostError.d.ts.map +1 -0
- package/types/errors.d.ts +89 -0
- package/types/errors.d.ts.map +1 -0
- package/types/index.d.ts +13 -0
- package/types/index.d.ts.map +1 -0
- package/types/utils.d.ts +33 -0
- package/types/utils.d.ts.map +1 -0
- package/types/wrap-stack.d.ts +2 -0
- package/types/wrap-stack.d.ts.map +1 -0
- package/index.js +0 -1
- package/lib/errors.js +0 -339
- package/lib/utils.js +0 -237
package/lib/utils.js
DELETED
|
@@ -1,237 +0,0 @@
|
|
|
1
|
-
const omit = require('lodash/omit');
|
|
2
|
-
const merge = require('lodash/merge');
|
|
3
|
-
const extend = require('lodash/extend');
|
|
4
|
-
const deepCopy = require('@stdlib/utils-copy');
|
|
5
|
-
const _private = {};
|
|
6
|
-
|
|
7
|
-
_private.serialize = function serialize(err) {
|
|
8
|
-
try {
|
|
9
|
-
return {
|
|
10
|
-
id: err.id,
|
|
11
|
-
status: err.statusCode,
|
|
12
|
-
code: err.code || err.errorType,
|
|
13
|
-
title: err.name,
|
|
14
|
-
detail: err.message,
|
|
15
|
-
meta: {
|
|
16
|
-
context: err.context,
|
|
17
|
-
help: err.help,
|
|
18
|
-
errorDetails: err.errorDetails,
|
|
19
|
-
level: err.level,
|
|
20
|
-
errorType: err.errorType
|
|
21
|
-
}
|
|
22
|
-
};
|
|
23
|
-
} catch (error) {
|
|
24
|
-
return {
|
|
25
|
-
detail: 'Something went wrong.'
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
_private.deserialize = function deserialize(obj) {
|
|
31
|
-
return {
|
|
32
|
-
id: obj.id,
|
|
33
|
-
message: obj.detail || obj.error_description || obj.message,
|
|
34
|
-
statusCode: obj.status,
|
|
35
|
-
code: obj.code || obj.error,
|
|
36
|
-
level: obj.meta && obj.meta.level,
|
|
37
|
-
help: obj.meta && obj.meta.help,
|
|
38
|
-
context: obj.meta && obj.meta.context
|
|
39
|
-
};
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* @description Serialize error instance into oauth format.
|
|
44
|
-
*
|
|
45
|
-
* @see https://tools.ietf.org/html/rfc6749#page-45
|
|
46
|
-
*
|
|
47
|
-
* To not loose any error data when sending errors between internal services, we use the suggested OAuth properties and add ours as well.
|
|
48
|
-
*/
|
|
49
|
-
_private.OAuthSerialize = function OAuthSerialize(err) {
|
|
50
|
-
const matchTable = {};
|
|
51
|
-
|
|
52
|
-
matchTable[this.NoPermissionError.name] = 'access_denied';
|
|
53
|
-
matchTable[this.MaintenanceError.name] = 'temporarily_unavailable';
|
|
54
|
-
matchTable[this.BadRequestError.name] = matchTable[this.ValidationError.name] = 'invalid_request';
|
|
55
|
-
matchTable.default = 'server_error';
|
|
56
|
-
|
|
57
|
-
return merge({
|
|
58
|
-
error: err.code || matchTable[err.name] || 'server_error',
|
|
59
|
-
error_description: err.message
|
|
60
|
-
}, omit(_private.serialize(err), ['detail', 'code']));
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* @description Deserialize oauth error format into GhostError instance.
|
|
65
|
-
* @param {Object} errorFormat
|
|
66
|
-
* @return {Error}
|
|
67
|
-
* @constructor
|
|
68
|
-
*/
|
|
69
|
-
_private.OAuthDeserialize = function OAuthDeserialize(errorFormat) {
|
|
70
|
-
try {
|
|
71
|
-
return new this[errorFormat.title || errorFormat.name || this.InternalServerError.name](_private.deserialize(errorFormat));
|
|
72
|
-
} catch (err) {
|
|
73
|
-
// CASE: you receive an OAuth formatted error, but the error prototype is unknown
|
|
74
|
-
return new this.InternalServerError(extend({
|
|
75
|
-
errorType: errorFormat.title || errorFormat.name
|
|
76
|
-
}, _private.deserialize(errorFormat)));
|
|
77
|
-
}
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* @description Serialize GhostError instance into jsonapi.org format.
|
|
82
|
-
* @param {Error} err
|
|
83
|
-
* @return {Object}
|
|
84
|
-
*/
|
|
85
|
-
_private.JSONAPISerialize = function JSONAPISerialize(err) {
|
|
86
|
-
const errorFormat = {
|
|
87
|
-
errors: [_private.serialize(err)]
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
errorFormat.errors[0].source = {};
|
|
91
|
-
|
|
92
|
-
if (err.property) {
|
|
93
|
-
errorFormat.errors[0].source.pointer = '/data/attributes/' + err.property;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
return errorFormat;
|
|
97
|
-
};
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* @description Deserialize JSON api format into GhostError instance.
|
|
101
|
-
* @param {Object} errorFormat
|
|
102
|
-
* @return {Error}
|
|
103
|
-
*/
|
|
104
|
-
_private.JSONAPIDeserialize = function JSONAPIDeserialize(errorFormat) {
|
|
105
|
-
errorFormat = errorFormat.errors && errorFormat.errors[0] || {};
|
|
106
|
-
|
|
107
|
-
let internalError;
|
|
108
|
-
|
|
109
|
-
try {
|
|
110
|
-
internalError = new this[errorFormat.title || errorFormat.name || this.InternalServerError.name](_private.deserialize(errorFormat));
|
|
111
|
-
} catch (err) {
|
|
112
|
-
// CASE: you receive a JSON format error, but the error prototype is unknown
|
|
113
|
-
internalError = new this.InternalServerError(extend({
|
|
114
|
-
errorType: errorFormat.title || errorFormat.name
|
|
115
|
-
}, _private.deserialize(errorFormat)));
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
if (errorFormat.source && errorFormat.source.pointer) {
|
|
119
|
-
internalError.property = errorFormat.source.pointer.split('/')[3];
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
return internalError;
|
|
123
|
-
};
|
|
124
|
-
|
|
125
|
-
exports.wrapStack = function wrapStack(err, internalErr) {
|
|
126
|
-
const extraLine = err.stack.split(/\n/g)[1];
|
|
127
|
-
const [firstLine, ...rest] = internalErr.stack.split(/\n/g);
|
|
128
|
-
return [firstLine, extraLine, ...rest].join('\n');
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* @description Serialize GhostError instance to error JSON format
|
|
133
|
-
*
|
|
134
|
-
* jsonapi.org error format:
|
|
135
|
-
*
|
|
136
|
-
* source: {
|
|
137
|
-
* parameter: URL query parameter (no support yet)
|
|
138
|
-
* pointer: HTTP body attribute
|
|
139
|
-
* }
|
|
140
|
-
*
|
|
141
|
-
* @see http://jsonapi.org/format/#errors
|
|
142
|
-
*
|
|
143
|
-
* @param {Error} err
|
|
144
|
-
* @param {Object} options { format: [String] (jsonapi || oauth) }
|
|
145
|
-
*/
|
|
146
|
-
exports.serialize = function serialize(err, options) {
|
|
147
|
-
options = options || {format: 'jsonapi'};
|
|
148
|
-
|
|
149
|
-
let errorFormat = {};
|
|
150
|
-
|
|
151
|
-
try {
|
|
152
|
-
if (options.format === 'jsonapi') {
|
|
153
|
-
errorFormat = _private.JSONAPISerialize.bind(this)(err);
|
|
154
|
-
} else {
|
|
155
|
-
errorFormat = _private.OAuthSerialize.bind(this)(err);
|
|
156
|
-
}
|
|
157
|
-
} catch (error) {
|
|
158
|
-
errorFormat.message = 'Something went wrong.';
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
// no need to sanitize the undefined values, on response send JSON.stringify get's called
|
|
162
|
-
return errorFormat;
|
|
163
|
-
};
|
|
164
|
-
|
|
165
|
-
/**
|
|
166
|
-
* @description Deserialize from error JSON format to GhostError instance
|
|
167
|
-
* @param {Object} errorFormat
|
|
168
|
-
*/
|
|
169
|
-
exports.deserialize = function deserialize(errorFormat) {
|
|
170
|
-
let internalError = {};
|
|
171
|
-
|
|
172
|
-
if (errorFormat.errors) {
|
|
173
|
-
internalError = _private.JSONAPIDeserialize.bind(this)(errorFormat);
|
|
174
|
-
} else {
|
|
175
|
-
internalError = _private.OAuthDeserialize.bind(this)(errorFormat);
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
return internalError;
|
|
179
|
-
};
|
|
180
|
-
|
|
181
|
-
/**
|
|
182
|
-
* @description Replace the stack with a user-facing one
|
|
183
|
-
* @params {Error} err
|
|
184
|
-
* @returns {Error} Clone of the original error with a user-facing stack
|
|
185
|
-
*/
|
|
186
|
-
exports.prepareStackForUser = function prepareStackForUser(error) {
|
|
187
|
-
let stackbits = error.stack.split(/\n/);
|
|
188
|
-
|
|
189
|
-
// We build this up backwards, so we always insert at position 1
|
|
190
|
-
|
|
191
|
-
if (process.env.NODE_ENV === 'production' || error.hideStack) {
|
|
192
|
-
stackbits.splice(1, stackbits.length - 1);
|
|
193
|
-
} else {
|
|
194
|
-
// Clearly mark the strack trace
|
|
195
|
-
stackbits.splice(1, 0, `Stack Trace:`);
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
// Add in our custom context and help methods
|
|
199
|
-
if (error.help) {
|
|
200
|
-
stackbits.splice(1, 0, `${error.help}`);
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
if (error.context) {
|
|
204
|
-
stackbits.splice(1, 0, `${error.context}`);
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
// @NOTE: would be a good idea to swap out the cloning implementation with native
|
|
208
|
-
// `structuredClone` one once we use Node v17 or higher. Before making an
|
|
209
|
-
// upgrade make sure structuredClone does a full copy of all properties
|
|
210
|
-
// present on a custom error (see issue: https://github.com/ungap/structured-clone/issues/12)
|
|
211
|
-
const errorClone = deepCopy(error);
|
|
212
|
-
errorClone.stack = stackbits.join('\n');
|
|
213
|
-
return errorClone;
|
|
214
|
-
};
|
|
215
|
-
|
|
216
|
-
/**
|
|
217
|
-
* @description Check whether an error instance is a GhostError.
|
|
218
|
-
*/
|
|
219
|
-
exports.isGhostError = function isGhostError(err) {
|
|
220
|
-
const errorName = this.GhostError.name;
|
|
221
|
-
const legacyErrorName = 'IgnitionError';
|
|
222
|
-
|
|
223
|
-
const recursiveIsGhostError = function recursiveIsGhostError(obj) {
|
|
224
|
-
// no super constructor available anymore
|
|
225
|
-
if (!obj || !obj.name) {
|
|
226
|
-
return false;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
if (obj.name === errorName || obj.name === legacyErrorName) {
|
|
230
|
-
return true;
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
return recursiveIsGhostError(Object.getPrototypeOf(obj));
|
|
234
|
-
};
|
|
235
|
-
|
|
236
|
-
return recursiveIsGhostError(err.constructor);
|
|
237
|
-
};
|