-
Notifications
You must be signed in to change notification settings - Fork 24
/
Copy patherrors.ts
112 lines (102 loc) · 3.64 KB
/
errors.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
import { HTTPError } from 'got';
import { GotError, ErrorType } from '../types';
export class SignatureVerificationError extends Error {
detail: { webhookPayload: unknown; signatureHeader: string } | undefined;
constructor(
message: string,
detail?: {
signatureHeader: string;
webhookPayload: unknown;
},
) {
super(message);
this.name = 'SignatureVerificationError';
this.message = message;
this.detail = detail;
Object.setPrototypeOf(this, SignatureVerificationError.prototype);
}
}
export class BlockfrostServerError extends Error {
status_code: number;
error: string;
url: string;
body: unknown;
constructor(error: Extract<ErrorType, { status_code: number }>) {
super(error.message);
this.name = 'BlockfrostServerError';
this.status_code = error.status_code;
this.message = error.message;
this.error = error.error;
this.url = error.url;
this.body = error.body;
Object.setPrototypeOf(this, BlockfrostServerError.prototype);
}
}
export class BlockfrostClientError extends Error {
code: string;
url: string | undefined;
constructor(error: Extract<ErrorType, { code: string }>) {
super(error.message);
this.name = 'BlockfrostClientError';
this.code = error.code;
this.message = error.message;
this.url = error.url;
Object.setPrototypeOf(this, BlockfrostClientError.prototype);
}
}
const hasProp = <K extends PropertyKey>(
// eslint-disable-next-line @typescript-eslint/ban-types
data: object,
prop: K,
): data is Record<K, unknown> => {
return prop in data;
};
export const isBlockfrostErrorResponse = (
data: unknown,
): data is Extract<ErrorType, { status_code: number }> => {
// type guard for narrowing response body to an error object that should be returned by Blockfrost API
return (
typeof data === 'object' &&
data !== null &&
hasProp(data, 'status_code') &&
hasProp(data, 'message') &&
hasProp(data, 'error')
);
};
export const handleError = (
error: GotError,
): BlockfrostServerError | BlockfrostClientError => {
if (error instanceof HTTPError) {
let errorInstance: BlockfrostServerError;
const url = error.request.requestUrl;
const responseBody = error.response.body;
if (isBlockfrostErrorResponse(responseBody)) {
errorInstance = new BlockfrostServerError({ ...responseBody, url });
} else {
// response.body may contain html output (eg. errors returned by nginx)
const { statusCode } = error.response;
const statusText = error.response.statusMessage ?? error.message;
errorInstance = new BlockfrostServerError({
status_code: statusCode,
message: `${statusCode}: ${statusText}`,
error: statusText,
url,
// Sometimes original body can be helpful so let's forward it
// Eg. communicating directly with Cardano Submit API which returns 400 with the error from cardano-node in the body of the request)
body: error.response.body ? error.response.body : undefined,
});
}
// remove undefined body prop so it doesn't pollute string representation of the error
if (errorInstance.body === undefined) {
delete errorInstance.body;
}
return errorInstance;
}
// system errors such as -3008 ENOTFOUND and various got errors like ReadError, CacheError, MaxRedirectsError, TimeoutError,...
// https://github.com/sindresorhus/got/blob/main/documentation/8-errors.md
return new BlockfrostClientError({
code: error.code ?? 'ERR_GOT_REQUEST_ERROR', // ENOTFOUND, ETIMEDOUT...
message: error.message, // getaddrinfo ENOTFOUND cardano-testnet.blockfrost.io'
url: error.request?.requestUrl,
});
};