@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/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
- };