@lodestar/utils
Version:
Utilities required across multiple lodestar packages
102 lines • 3.62 kB
JavaScript
/**
* Native fetch with transparent and consistent error handling
*
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/fetch)
*/
async function wrappedFetch(url, init) {
try {
// This function wraps global `fetch` which should only be directly called here
// biome-ignore lint/style/noRestrictedGlobals: We need to use global `fetch`
return await fetch(url, init);
}
catch (e) {
throw new FetchError(url, e);
}
}
export { wrappedFetch as fetch };
export function isFetchError(e) {
return e instanceof FetchError;
}
export class FetchError extends Error {
type;
code;
cause;
constructor(url, e) {
if (isNativeFetchFailedError(e)) {
super(`Request to ${url.toString()} failed, reason: ${e.cause.message}`);
this.type = "failed";
this.code = e.cause.code || "ERR_FETCH_FAILED";
this.cause = e.cause;
}
else if (isNativeFetchInputError(e)) {
// For input errors the e.message is more detailed
super(e.message);
this.type = "input";
this.code = e.cause.code || "ERR_INVALID_INPUT";
this.cause = e.cause;
}
else if (isNativeFetchAbortError(e)) {
super(`Request to ${url.toString()} was aborted`);
this.type = "aborted";
this.code = "ERR_ABORTED";
}
else if (isNativeFetchTimeoutError(e)) {
super(`Request to ${url.toString()} timed out`);
this.type = "timeout";
this.code = "ERR_TIMEOUT";
}
// There are few incompatibilities related to `fetch` with NodeJS
// So we have to wrap those cases here explicitly
// https://github.com/oven-sh/bun/issues/20486
else if (isBunError(e) && e.code === "ConnectionRefused") {
super("TypeError: fetch failed");
this.type = "failed";
this.code = "ENOTFOUND";
this.cause = e;
}
else if (isBunError(e) && e.code === "ECONNRESET") {
super("TypeError: fetch failed");
this.type = "failed";
this.code = "UND_ERR_SOCKET";
this.cause = e;
}
else if (isBun && e.message.includes("protocol must be")) {
super("fetch failed");
this.type = "failed";
this.code = "ERR_FETCH_FAILED";
this.cause = e;
}
else if (e.message.includes("URL is invalid")) {
super("Failed to parse URL from invalid-url");
this.type = "input";
this.code = "ERR_INVALID_URL";
this.cause = e;
}
else {
super(e.message);
this.type = "unknown";
this.code = "ERR_UNKNOWN";
}
this.name = this.constructor.name;
}
}
function isNativeFetchError(e) {
return e instanceof TypeError && e.cause instanceof Error;
}
function isNativeFetchFailedError(e) {
return isNativeFetchError(e) && e.message === "fetch failed";
}
function isNativeFetchInputError(e) {
return isNativeFetchError(e) && e.cause.input !== undefined;
}
function isNativeFetchAbortError(e) {
return e instanceof DOMException && e.name === "AbortError";
}
function isNativeFetchTimeoutError(e) {
return e instanceof DOMException && e.name === "TimeoutError";
}
const isBun = "bun" in process.versions;
function isBunError(e) {
return isBun && typeof e === "object" && e !== null && "code" in e && "path" in e && "errno" in e && "message" in e;
}
//# sourceMappingURL=fetch.js.map