UNPKG

@lodestar/utils

Version:

Utilities required across multiple lodestar packages

102 lines 3.62 kB
/** * 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