@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/es/GhostError.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
|
+
var __publicField = (obj, key, value) => {
|
|
4
|
+
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
5
|
+
return value;
|
|
6
|
+
};
|
|
7
|
+
import { v1 as uuidv1 } from "uuid";
|
|
8
|
+
import { wrapStack } from "./wrap-stack";
|
|
9
|
+
class GhostError extends Error {
|
|
10
|
+
constructor(options = {}) {
|
|
11
|
+
super();
|
|
12
|
+
__publicField(this, "statusCode");
|
|
13
|
+
__publicField(this, "errorType");
|
|
14
|
+
__publicField(this, "level");
|
|
15
|
+
__publicField(this, "id");
|
|
16
|
+
__publicField(this, "context");
|
|
17
|
+
__publicField(this, "help");
|
|
18
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
19
|
+
__publicField(this, "errorDetails");
|
|
20
|
+
__publicField(this, "code");
|
|
21
|
+
__publicField(this, "property");
|
|
22
|
+
__publicField(this, "redirect");
|
|
23
|
+
__publicField(this, "hideStack");
|
|
24
|
+
this.statusCode = 500;
|
|
25
|
+
this.errorType = "InternalServerError";
|
|
26
|
+
this.level = "normal";
|
|
27
|
+
this.message = "The server has encountered an error.";
|
|
28
|
+
this.id = uuidv1();
|
|
29
|
+
this.id = options.id || this.id;
|
|
30
|
+
this.statusCode = options.statusCode || this.statusCode;
|
|
31
|
+
this.level = options.level || this.level;
|
|
32
|
+
this.context = options.context;
|
|
33
|
+
this.help = options.help;
|
|
34
|
+
this.errorType = this.name = options.errorType || this.errorType;
|
|
35
|
+
this.errorDetails = options.errorDetails;
|
|
36
|
+
this.code = options.code || null;
|
|
37
|
+
this.property = options.property || null;
|
|
38
|
+
this.redirect = options.redirect || null;
|
|
39
|
+
this.message = options.message || this.message;
|
|
40
|
+
this.hideStack = options.hideStack || false;
|
|
41
|
+
if (options.err) {
|
|
42
|
+
if (typeof options.err === "string") {
|
|
43
|
+
options.err = new Error(options.err);
|
|
44
|
+
}
|
|
45
|
+
Object.getOwnPropertyNames(options.err).forEach((property) => {
|
|
46
|
+
if (["errorType", "name", "statusCode", "message", "level"].indexOf(property) !== -1) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
if (property === "code") {
|
|
50
|
+
this[property] = this[property] || options.err[property];
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
if (property === "stack" && !this.hideStack) {
|
|
54
|
+
this[property] = wrapStack(this, options.err);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
this[property] = options.err[property] || this[property];
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
export {
|
|
63
|
+
GhostError
|
|
64
|
+
};
|
package/es/errors.js
ADDED
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
import { GhostError } from "./GhostError";
|
|
2
|
+
const mergeOptions = (options, defaults) => {
|
|
3
|
+
const result = { ...defaults };
|
|
4
|
+
Object.keys(options).forEach((key) => {
|
|
5
|
+
if (options[key] !== void 0) {
|
|
6
|
+
result[key] = options[key];
|
|
7
|
+
}
|
|
8
|
+
});
|
|
9
|
+
return result;
|
|
10
|
+
};
|
|
11
|
+
class InternalServerError extends GhostError {
|
|
12
|
+
constructor(options = {}) {
|
|
13
|
+
super(mergeOptions(options, {
|
|
14
|
+
statusCode: 500,
|
|
15
|
+
level: "critical",
|
|
16
|
+
errorType: "InternalServerError",
|
|
17
|
+
message: "The server has encountered an error."
|
|
18
|
+
}));
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
class IncorrectUsageError extends GhostError {
|
|
22
|
+
constructor(options = {}) {
|
|
23
|
+
super(mergeOptions(options, {
|
|
24
|
+
statusCode: 400,
|
|
25
|
+
level: "critical",
|
|
26
|
+
errorType: "IncorrectUsageError",
|
|
27
|
+
message: "We detected a misuse. Please read the stack trace."
|
|
28
|
+
}));
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
class NotFoundError extends GhostError {
|
|
32
|
+
constructor(options = {}) {
|
|
33
|
+
super(mergeOptions(options, {
|
|
34
|
+
statusCode: 404,
|
|
35
|
+
errorType: "NotFoundError",
|
|
36
|
+
message: "Resource could not be found.",
|
|
37
|
+
hideStack: true
|
|
38
|
+
}));
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
class BadRequestError extends GhostError {
|
|
42
|
+
constructor(options = {}) {
|
|
43
|
+
super(mergeOptions(options, {
|
|
44
|
+
statusCode: 400,
|
|
45
|
+
errorType: "BadRequestError",
|
|
46
|
+
message: "The request could not be understood."
|
|
47
|
+
}));
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
class UnauthorizedError extends GhostError {
|
|
51
|
+
constructor(options = {}) {
|
|
52
|
+
super(mergeOptions(options, {
|
|
53
|
+
statusCode: 401,
|
|
54
|
+
errorType: "UnauthorizedError",
|
|
55
|
+
message: "You are not authorised to make this request."
|
|
56
|
+
}));
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
class NoPermissionError extends GhostError {
|
|
60
|
+
constructor(options = {}) {
|
|
61
|
+
super(mergeOptions(options, {
|
|
62
|
+
statusCode: 403,
|
|
63
|
+
errorType: "NoPermissionError",
|
|
64
|
+
message: "You do not have permission to perform this request."
|
|
65
|
+
}));
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
class ValidationError extends GhostError {
|
|
69
|
+
constructor(options = {}) {
|
|
70
|
+
super(mergeOptions(options, {
|
|
71
|
+
statusCode: 422,
|
|
72
|
+
errorType: "ValidationError",
|
|
73
|
+
message: "The request failed validation."
|
|
74
|
+
}));
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
class UnsupportedMediaTypeError extends GhostError {
|
|
78
|
+
constructor(options = {}) {
|
|
79
|
+
super(mergeOptions(options, {
|
|
80
|
+
statusCode: 415,
|
|
81
|
+
errorType: "UnsupportedMediaTypeError",
|
|
82
|
+
message: "The media in the request is not supported by the server."
|
|
83
|
+
}));
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
class TooManyRequestsError extends GhostError {
|
|
87
|
+
constructor(options = {}) {
|
|
88
|
+
super(mergeOptions(options, {
|
|
89
|
+
statusCode: 429,
|
|
90
|
+
errorType: "TooManyRequestsError",
|
|
91
|
+
message: "Server has received too many similar requests in a short space of time."
|
|
92
|
+
}));
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
class MaintenanceError extends GhostError {
|
|
96
|
+
constructor(options = {}) {
|
|
97
|
+
super(mergeOptions(options, {
|
|
98
|
+
statusCode: 503,
|
|
99
|
+
errorType: "MaintenanceError",
|
|
100
|
+
message: "The server is temporarily down for maintenance."
|
|
101
|
+
}));
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
class MethodNotAllowedError extends GhostError {
|
|
105
|
+
constructor(options = {}) {
|
|
106
|
+
super(mergeOptions(options, {
|
|
107
|
+
statusCode: 405,
|
|
108
|
+
errorType: "MethodNotAllowedError",
|
|
109
|
+
message: "Method not allowed for resource."
|
|
110
|
+
}));
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
class RequestNotAcceptableError extends GhostError {
|
|
114
|
+
constructor(options = {}) {
|
|
115
|
+
super(mergeOptions(options, {
|
|
116
|
+
statusCode: 406,
|
|
117
|
+
errorType: "RequestNotAcceptableError",
|
|
118
|
+
message: "Request not acceptable for provided Accept-Version header.",
|
|
119
|
+
hideStack: true
|
|
120
|
+
}));
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
class RangeNotSatisfiableError extends GhostError {
|
|
124
|
+
constructor(options = {}) {
|
|
125
|
+
super(mergeOptions(options, {
|
|
126
|
+
statusCode: 416,
|
|
127
|
+
errorType: "RangeNotSatisfiableError",
|
|
128
|
+
message: "Range not satisfiable for provided Range header.",
|
|
129
|
+
hideStack: true
|
|
130
|
+
}));
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
class RequestEntityTooLargeError extends GhostError {
|
|
134
|
+
constructor(options = {}) {
|
|
135
|
+
super(mergeOptions(options, {
|
|
136
|
+
statusCode: 413,
|
|
137
|
+
errorType: "RequestEntityTooLargeError",
|
|
138
|
+
message: "Request was too big for the server to handle."
|
|
139
|
+
}));
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
class TokenRevocationError extends GhostError {
|
|
143
|
+
constructor(options = {}) {
|
|
144
|
+
super(mergeOptions(options, {
|
|
145
|
+
statusCode: 503,
|
|
146
|
+
errorType: "TokenRevocationError",
|
|
147
|
+
message: "Token is no longer available."
|
|
148
|
+
}));
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
class VersionMismatchError extends GhostError {
|
|
152
|
+
constructor(options = {}) {
|
|
153
|
+
super(mergeOptions(options, {
|
|
154
|
+
statusCode: 400,
|
|
155
|
+
errorType: "VersionMismatchError",
|
|
156
|
+
message: "Requested version does not match server version."
|
|
157
|
+
}));
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
class DataExportError extends GhostError {
|
|
161
|
+
constructor(options = {}) {
|
|
162
|
+
super(mergeOptions(options, {
|
|
163
|
+
statusCode: 500,
|
|
164
|
+
errorType: "DataExportError",
|
|
165
|
+
message: "The server encountered an error whilst exporting data."
|
|
166
|
+
}));
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
class DataImportError extends GhostError {
|
|
170
|
+
constructor(options = {}) {
|
|
171
|
+
super(mergeOptions(options, {
|
|
172
|
+
statusCode: 500,
|
|
173
|
+
errorType: "DataImportError",
|
|
174
|
+
message: "The server encountered an error whilst importing data."
|
|
175
|
+
}));
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
class EmailError extends GhostError {
|
|
179
|
+
constructor(options = {}) {
|
|
180
|
+
super(mergeOptions(options, {
|
|
181
|
+
statusCode: 500,
|
|
182
|
+
errorType: "EmailError",
|
|
183
|
+
message: "The server encountered an error whilst sending email."
|
|
184
|
+
}));
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
class ThemeValidationError extends GhostError {
|
|
188
|
+
constructor(options = {}) {
|
|
189
|
+
super(mergeOptions(options, {
|
|
190
|
+
statusCode: 422,
|
|
191
|
+
errorType: "ThemeValidationError",
|
|
192
|
+
message: "The theme has a validation error.",
|
|
193
|
+
errorDetails: {}
|
|
194
|
+
}));
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
class DisabledFeatureError extends GhostError {
|
|
198
|
+
constructor(options = {}) {
|
|
199
|
+
super(mergeOptions(options, {
|
|
200
|
+
statusCode: 409,
|
|
201
|
+
errorType: "DisabledFeatureError",
|
|
202
|
+
message: "Unable to complete the request, this feature is disabled."
|
|
203
|
+
}));
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
class UpdateCollisionError extends GhostError {
|
|
207
|
+
constructor(options = {}) {
|
|
208
|
+
super(mergeOptions(options, {
|
|
209
|
+
statusCode: 409,
|
|
210
|
+
errorType: "UpdateCollisionError",
|
|
211
|
+
message: "Unable to complete the request, there was a conflict."
|
|
212
|
+
}));
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
class HostLimitError extends GhostError {
|
|
216
|
+
constructor(options = {}) {
|
|
217
|
+
super(mergeOptions(options, {
|
|
218
|
+
errorType: "HostLimitError",
|
|
219
|
+
hideStack: true,
|
|
220
|
+
statusCode: 403,
|
|
221
|
+
message: "Unable to complete the request, this resource is limited."
|
|
222
|
+
}));
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
class HelperWarning extends GhostError {
|
|
226
|
+
constructor(options = {}) {
|
|
227
|
+
super(mergeOptions(options, {
|
|
228
|
+
errorType: "HelperWarning",
|
|
229
|
+
hideStack: true,
|
|
230
|
+
statusCode: 400,
|
|
231
|
+
message: "A theme helper has done something unexpected."
|
|
232
|
+
}));
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
class PasswordResetRequiredError extends GhostError {
|
|
236
|
+
constructor(options = {}) {
|
|
237
|
+
super(mergeOptions(options, {
|
|
238
|
+
errorType: "PasswordResetRequiredError",
|
|
239
|
+
statusCode: 401,
|
|
240
|
+
message: "For security, you need to create a new password. An email has been sent to you with instructions!"
|
|
241
|
+
}));
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
class UnhandledJobError extends GhostError {
|
|
245
|
+
constructor(options = {}) {
|
|
246
|
+
super(mergeOptions(options, {
|
|
247
|
+
errorType: "UnhandledJobError",
|
|
248
|
+
message: "Processed job threw an unhandled error",
|
|
249
|
+
level: "critical"
|
|
250
|
+
}));
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
class NoContentError extends GhostError {
|
|
254
|
+
constructor(options = {}) {
|
|
255
|
+
super(mergeOptions(options, {
|
|
256
|
+
errorType: "NoContentError",
|
|
257
|
+
statusCode: 204,
|
|
258
|
+
hideStack: true
|
|
259
|
+
}));
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
class ConflictError extends GhostError {
|
|
263
|
+
constructor(options = {}) {
|
|
264
|
+
super(mergeOptions(options, {
|
|
265
|
+
errorType: "ConflictError",
|
|
266
|
+
statusCode: 409,
|
|
267
|
+
message: "The server has encountered an conflict."
|
|
268
|
+
}));
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
class MigrationError extends GhostError {
|
|
272
|
+
constructor(options = {}) {
|
|
273
|
+
super(mergeOptions(options, {
|
|
274
|
+
errorType: "MigrationError",
|
|
275
|
+
message: "An error has occurred applying a database migration.",
|
|
276
|
+
level: "critical"
|
|
277
|
+
}));
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
export {
|
|
281
|
+
BadRequestError,
|
|
282
|
+
ConflictError,
|
|
283
|
+
DataExportError,
|
|
284
|
+
DataImportError,
|
|
285
|
+
DisabledFeatureError,
|
|
286
|
+
EmailError,
|
|
287
|
+
HelperWarning,
|
|
288
|
+
HostLimitError,
|
|
289
|
+
IncorrectUsageError,
|
|
290
|
+
InternalServerError,
|
|
291
|
+
MaintenanceError,
|
|
292
|
+
MethodNotAllowedError,
|
|
293
|
+
MigrationError,
|
|
294
|
+
NoContentError,
|
|
295
|
+
NoPermissionError,
|
|
296
|
+
NotFoundError,
|
|
297
|
+
PasswordResetRequiredError,
|
|
298
|
+
RangeNotSatisfiableError,
|
|
299
|
+
RequestEntityTooLargeError,
|
|
300
|
+
RequestNotAcceptableError,
|
|
301
|
+
ThemeValidationError,
|
|
302
|
+
TokenRevocationError,
|
|
303
|
+
TooManyRequestsError,
|
|
304
|
+
UnauthorizedError,
|
|
305
|
+
UnhandledJobError,
|
|
306
|
+
UnsupportedMediaTypeError,
|
|
307
|
+
UpdateCollisionError,
|
|
308
|
+
ValidationError,
|
|
309
|
+
VersionMismatchError
|
|
310
|
+
};
|
package/es/index.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import * as ghostErrors from "./errors";
|
|
2
|
+
import { deserialize, isGhostError, prepareStackForUser, serialize } from "./utils";
|
|
3
|
+
export * from "./errors";
|
|
4
|
+
var src_default = ghostErrors;
|
|
5
|
+
const utils = {
|
|
6
|
+
serialize,
|
|
7
|
+
deserialize,
|
|
8
|
+
isGhostError,
|
|
9
|
+
prepareStackForUser
|
|
10
|
+
};
|
|
11
|
+
export {
|
|
12
|
+
src_default as default,
|
|
13
|
+
utils
|
|
14
|
+
};
|
package/es/utils.js
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import deepCopy from "@stdlib/utils-copy";
|
|
2
|
+
import { GhostError } from "./GhostError";
|
|
3
|
+
import * as errors from "./errors";
|
|
4
|
+
const errorsWithBase = { ...errors, GhostError };
|
|
5
|
+
const _private = {
|
|
6
|
+
serialize(err) {
|
|
7
|
+
try {
|
|
8
|
+
return {
|
|
9
|
+
id: err.id,
|
|
10
|
+
status: err.statusCode,
|
|
11
|
+
code: err.code || err.errorType,
|
|
12
|
+
title: err.name,
|
|
13
|
+
detail: err.message,
|
|
14
|
+
meta: {
|
|
15
|
+
context: err.context,
|
|
16
|
+
help: err.help,
|
|
17
|
+
errorDetails: err.errorDetails,
|
|
18
|
+
level: err.level,
|
|
19
|
+
errorType: err.errorType
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
} catch (error) {
|
|
23
|
+
return {
|
|
24
|
+
detail: "Something went wrong."
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
deserialize(obj) {
|
|
29
|
+
return {
|
|
30
|
+
id: obj.id,
|
|
31
|
+
message: obj.detail || obj.error_description || obj.message,
|
|
32
|
+
statusCode: obj.status,
|
|
33
|
+
code: obj.code || obj.error,
|
|
34
|
+
level: obj.meta && obj.meta.level,
|
|
35
|
+
help: obj.meta && obj.meta.help,
|
|
36
|
+
context: obj.meta && obj.meta.context
|
|
37
|
+
};
|
|
38
|
+
},
|
|
39
|
+
/**
|
|
40
|
+
* @description Serialize error instance into oauth format.
|
|
41
|
+
*
|
|
42
|
+
* @see https://tools.ietf.org/html/rfc6749#page-45
|
|
43
|
+
*
|
|
44
|
+
* To not loose any error data when sending errors between internal services, we use the suggested OAuth properties and add ours as well.
|
|
45
|
+
*/
|
|
46
|
+
OAuthSerialize(err) {
|
|
47
|
+
const matchTable = {
|
|
48
|
+
[errors.NoPermissionError.name]: "access_denied",
|
|
49
|
+
[errors.MaintenanceError.name]: "temporarily_unavailable",
|
|
50
|
+
[errors.BadRequestError.name]: "invalid_request",
|
|
51
|
+
[errors.ValidationError.name]: "invalid_request",
|
|
52
|
+
default: "server_error"
|
|
53
|
+
};
|
|
54
|
+
const { detail, code, ...properties } = _private.serialize(err);
|
|
55
|
+
return {
|
|
56
|
+
error: err.code || matchTable[err.name] || "server_error",
|
|
57
|
+
error_description: err.message,
|
|
58
|
+
...properties
|
|
59
|
+
};
|
|
60
|
+
},
|
|
61
|
+
/**
|
|
62
|
+
* @description Deserialize oauth error format into GhostError instance.
|
|
63
|
+
* @constructor
|
|
64
|
+
*/
|
|
65
|
+
OAuthDeserialize(errorFormat) {
|
|
66
|
+
try {
|
|
67
|
+
return new errorsWithBase[errorFormat.title || errorFormat.name || errors.InternalServerError.name](_private.deserialize(errorFormat));
|
|
68
|
+
} catch (err) {
|
|
69
|
+
return new errors.InternalServerError({
|
|
70
|
+
errorType: errorFormat.title || errorFormat.name,
|
|
71
|
+
..._private.deserialize(errorFormat)
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
/**
|
|
76
|
+
* @description Serialize GhostError instance into jsonapi.org format.
|
|
77
|
+
* @param err
|
|
78
|
+
* @return {Object}
|
|
79
|
+
*/
|
|
80
|
+
JSONAPISerialize(err) {
|
|
81
|
+
const errorFormat = {
|
|
82
|
+
errors: [_private.serialize(err)]
|
|
83
|
+
};
|
|
84
|
+
errorFormat.errors[0].source = {};
|
|
85
|
+
if (err.property) {
|
|
86
|
+
errorFormat.errors[0].source.pointer = "/data/attributes/" + err.property;
|
|
87
|
+
}
|
|
88
|
+
return errorFormat;
|
|
89
|
+
},
|
|
90
|
+
/**
|
|
91
|
+
* @description Deserialize JSON api format into GhostError instance.
|
|
92
|
+
*/
|
|
93
|
+
JSONAPIDeserialize(errorFormat) {
|
|
94
|
+
errorFormat = errorFormat.errors && errorFormat.errors[0] || {};
|
|
95
|
+
let internalError;
|
|
96
|
+
try {
|
|
97
|
+
internalError = new errorsWithBase[errorFormat.title || errorFormat.name || errors.InternalServerError.name](_private.deserialize(errorFormat));
|
|
98
|
+
} catch (err) {
|
|
99
|
+
internalError = new errors.InternalServerError({
|
|
100
|
+
errorType: errorFormat.title || errorFormat.name,
|
|
101
|
+
..._private.deserialize(errorFormat)
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
if (errorFormat.source && errorFormat.source.pointer) {
|
|
105
|
+
internalError.property = errorFormat.source.pointer.split("/")[3];
|
|
106
|
+
}
|
|
107
|
+
return internalError;
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
function serialize(err, options) {
|
|
111
|
+
options = options || { format: "jsonapi" };
|
|
112
|
+
let errorFormat = {};
|
|
113
|
+
try {
|
|
114
|
+
if (options.format === "jsonapi") {
|
|
115
|
+
errorFormat = _private.JSONAPISerialize(err);
|
|
116
|
+
} else {
|
|
117
|
+
errorFormat = _private.OAuthSerialize(err);
|
|
118
|
+
}
|
|
119
|
+
} catch (error) {
|
|
120
|
+
errorFormat.message = "Something went wrong.";
|
|
121
|
+
}
|
|
122
|
+
return errorFormat;
|
|
123
|
+
}
|
|
124
|
+
;
|
|
125
|
+
function deserialize(errorFormat) {
|
|
126
|
+
let internalError = {};
|
|
127
|
+
if (errorFormat.errors) {
|
|
128
|
+
internalError = _private.JSONAPIDeserialize(errorFormat);
|
|
129
|
+
} else {
|
|
130
|
+
internalError = _private.OAuthDeserialize(errorFormat);
|
|
131
|
+
}
|
|
132
|
+
return internalError;
|
|
133
|
+
}
|
|
134
|
+
;
|
|
135
|
+
function prepareStackForUser(error) {
|
|
136
|
+
const stackbits = error.stack?.split(/\n/) || [];
|
|
137
|
+
const hideStack = "hideStack" in error && error.hideStack;
|
|
138
|
+
if (hideStack) {
|
|
139
|
+
stackbits.splice(1, stackbits.length - 1);
|
|
140
|
+
} else {
|
|
141
|
+
stackbits.splice(1, 0, `Stack Trace:`);
|
|
142
|
+
}
|
|
143
|
+
if ("help" in error && error.help) {
|
|
144
|
+
stackbits.splice(1, 0, `${error.help}`);
|
|
145
|
+
}
|
|
146
|
+
if ("context" in error && error.context) {
|
|
147
|
+
stackbits.splice(1, 0, `${error.context}`);
|
|
148
|
+
}
|
|
149
|
+
const errorClone = deepCopy(error);
|
|
150
|
+
errorClone.stack = stackbits.join("\n");
|
|
151
|
+
return errorClone;
|
|
152
|
+
}
|
|
153
|
+
;
|
|
154
|
+
function isGhostError(err) {
|
|
155
|
+
const errorName = GhostError.name;
|
|
156
|
+
const legacyErrorName = "IgnitionError";
|
|
157
|
+
const recursiveIsGhostError = function recursiveIsGhostError2(obj) {
|
|
158
|
+
if (!obj || !obj.name) {
|
|
159
|
+
return false;
|
|
160
|
+
}
|
|
161
|
+
if (obj.name === errorName || obj.name === legacyErrorName) {
|
|
162
|
+
return true;
|
|
163
|
+
}
|
|
164
|
+
return recursiveIsGhostError2(Object.getPrototypeOf(obj));
|
|
165
|
+
};
|
|
166
|
+
return recursiveIsGhostError(err.constructor);
|
|
167
|
+
}
|
|
168
|
+
;
|
|
169
|
+
export {
|
|
170
|
+
deserialize,
|
|
171
|
+
isGhostError,
|
|
172
|
+
prepareStackForUser,
|
|
173
|
+
serialize
|
|
174
|
+
};
|
package/es/wrap-stack.js
ADDED
package/package.json
CHANGED
|
@@ -1,33 +1,50 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tryghost/errors",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.1",
|
|
4
4
|
"repository": "https://github.com/TryGhost/framework/tree/main/packages/errors",
|
|
5
5
|
"author": "Ghost Foundation",
|
|
6
6
|
"license": "MIT",
|
|
7
|
-
"main": "index.js",
|
|
7
|
+
"main": "cjs/index.js",
|
|
8
|
+
"module": "es/index.js",
|
|
9
|
+
"types": "types/index.d.ts",
|
|
10
|
+
"source": "src/index.ts",
|
|
11
|
+
"sideEffects": false,
|
|
8
12
|
"scripts": {
|
|
9
13
|
"dev": "echo \"Implement me!\"",
|
|
10
|
-
"
|
|
14
|
+
"prepare": "NODE_ENV=production yarn build",
|
|
15
|
+
"pretest": "NODE_ENV=production yarn build",
|
|
16
|
+
"build": "yarn build:cjs && yarn build:es && yarn build:types",
|
|
17
|
+
"build:cjs": "esbuild src/*.ts --target=es2020 --outdir=cjs --format=cjs",
|
|
18
|
+
"build:es": "esbuild src/*.ts --target=es2020 --outdir=es --format=esm",
|
|
19
|
+
"build:types": "tsc --emitDeclarationOnly --declaration --declarationMap --outDir types",
|
|
20
|
+
"test": "TS_NODE_COMPILER_OPTIONS='{\"module\": \"commonjs\" }' NODE_ENV=testing c8 --check-coverage --all -n src --reporter text --reporter cobertura mocha -r ts-node/register './test/**/*.test.ts'",
|
|
11
21
|
"lint": "eslint . --ext .js --cache",
|
|
12
22
|
"posttest": "yarn lint"
|
|
13
23
|
},
|
|
14
24
|
"files": [
|
|
15
|
-
"
|
|
16
|
-
"
|
|
25
|
+
"cjs",
|
|
26
|
+
"es",
|
|
27
|
+
"types",
|
|
28
|
+
"src"
|
|
17
29
|
],
|
|
18
30
|
"publishConfig": {
|
|
19
31
|
"access": "public"
|
|
20
32
|
},
|
|
21
33
|
"devDependencies": {
|
|
22
|
-
"
|
|
23
|
-
"mocha": "10.
|
|
34
|
+
"@types/lodash": "^4.14.200",
|
|
35
|
+
"@types/mocha": "^10.0.3",
|
|
36
|
+
"@types/uuid": "^9.0.6",
|
|
37
|
+
"c8": "9.1.0",
|
|
38
|
+
"esbuild": "^0.19.5",
|
|
39
|
+
"lodash": "^4.17.21",
|
|
40
|
+
"mocha": "10.3.0",
|
|
24
41
|
"should": "13.2.3",
|
|
25
|
-
"
|
|
42
|
+
"ts-node": "^10.9.1",
|
|
43
|
+
"typescript": "5.2.2"
|
|
26
44
|
},
|
|
27
45
|
"dependencies": {
|
|
28
46
|
"@stdlib/utils-copy": "^0.0.7",
|
|
29
|
-
"lodash": "^4.17.21",
|
|
30
47
|
"uuid": "^9.0.0"
|
|
31
48
|
},
|
|
32
|
-
"gitHead": "
|
|
49
|
+
"gitHead": "46cfa9c0bc277226048af7c1b98c797bccc05db5"
|
|
33
50
|
}
|