UNPKG

9.76 kBSource Map (JSON)View Raw
1{"version":3,"file":"fetch.js","sourceRoot":"","sources":["../src/fetch.ts"],"names":[],"mappings":"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","sourcesContent":["import { createAsyncMiddleware, JsonRpcMiddleware } from 'json-rpc-engine';\nimport { EthereumRpcError, ethErrors } from 'eth-rpc-errors';\nimport { Payload, Block } from './utils/cache';\n\n/* eslint-disable node/global-require,@typescript-eslint/no-require-imports */\nconst fetch = global.fetch || require('node-fetch');\nconst btoa = global.btoa || require('btoa');\n/* eslint-enable node/global-require,@typescript-eslint/no-require-imports */\n\nconst RETRIABLE_ERRORS: string[] = [\n // ignore server overload errors\n 'Gateway timeout',\n 'ETIMEDOUT',\n // ignore server sent html error pages\n // or truncated json responses\n 'failed to parse response body',\n // ignore errors where http req failed to establish\n 'Failed to fetch',\n];\n\ninterface PayloadwithOrgin extends Payload {\n origin?: string;\n}\ninterface Request {\n method: string;\n headers: Record<string, string>;\n body: string;\n}\ninterface FetchConfig {\n fetchUrl: string;\n fetchParams: Request;\n}\ninterface FetchMiddlewareOptions {\n rpcUrl: string;\n originHttpHeaderKey?: string;\n}\n\ninterface FetchMiddlewareFromReqOptions extends FetchMiddlewareOptions {\n req: PayloadwithOrgin;\n}\n\nexport function createFetchMiddleware({\n rpcUrl,\n originHttpHeaderKey,\n}: FetchMiddlewareOptions): JsonRpcMiddleware<string[], Block> {\n return createAsyncMiddleware(async (req, res, _next) => {\n const { fetchUrl, fetchParams } = createFetchConfigFromReq({\n req,\n rpcUrl,\n originHttpHeaderKey,\n });\n\n // attempt request multiple times\n const maxAttempts = 5;\n const retryInterval = 1000;\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n try {\n const fetchRes: Response = await fetch(fetchUrl, fetchParams);\n // check for http errrors\n checkForHttpErrors(fetchRes);\n // parse response body\n const rawBody: string = await fetchRes.text();\n let fetchBody: Record<string, Block>;\n try {\n fetchBody = JSON.parse(rawBody);\n } catch (_) {\n throw new Error(\n `FetchMiddleware - failed to parse response body: \"${rawBody}\"`,\n );\n }\n const result: Block = parseResponse(fetchRes, fetchBody);\n // set result and exit retry loop\n res.result = result;\n return;\n } catch (err) {\n const errMsg: string = err.toString();\n const isRetriable: boolean = RETRIABLE_ERRORS.some((phrase) => errMsg.includes(phrase));\n // re-throw error if not retriable\n if (!isRetriable) {\n throw err;\n }\n }\n // delay before retrying\n await timeout(retryInterval);\n }\n });\n}\n\nfunction checkForHttpErrors(fetchRes: Response): void {\n // check for errors\n switch (fetchRes.status) {\n case 405:\n throw ethErrors.rpc.methodNotFound();\n\n case 418:\n throw createRatelimitError();\n\n case 503:\n case 504:\n throw createTimeoutError();\n\n default:\n break;\n }\n}\n\nfunction parseResponse(fetchRes: Response, body: Record<string, Block>): Block {\n // check for error code\n if (fetchRes.status !== 200) {\n throw ethErrors.rpc.internal({\n message: `Non-200 status code: '${fetchRes.status}'`,\n data: body,\n });\n }\n // check for rpc error\n if (body.error) {\n throw ethErrors.rpc.internal({\n data: body.error,\n });\n }\n // return successful result\n return body.result;\n}\n\nexport function createFetchConfigFromReq({\n req,\n rpcUrl,\n originHttpHeaderKey,\n}: FetchMiddlewareFromReqOptions): FetchConfig {\n const parsedUrl: URL = new URL(rpcUrl);\n const fetchUrl: string = normalizeUrlFromParsed(parsedUrl);\n\n // prepare payload\n // copy only canonical json rpc properties\n const payload: Payload = {\n id: req.id,\n jsonrpc: req.jsonrpc,\n method: req.method,\n params: req.params,\n };\n\n // extract 'origin' parameter from request\n const originDomain: string | undefined = req.origin;\n\n // serialize request body\n const serializedPayload: string = JSON.stringify(payload);\n\n // configure fetch params\n const fetchParams: Request = {\n method: 'POST',\n headers: {\n Accept: 'application/json',\n 'Content-Type': 'application/json',\n },\n body: serializedPayload,\n };\n\n // encoded auth details as header (not allowed in fetch url)\n if (parsedUrl.username && parsedUrl.password) {\n const authString = `${parsedUrl.username}:${parsedUrl.password}`;\n const encodedAuth = btoa(authString);\n fetchParams.headers.Authorization = `Basic ${encodedAuth}`;\n }\n\n // optional: add request origin as header\n if (originHttpHeaderKey && originDomain) {\n fetchParams.headers[originHttpHeaderKey] = originDomain;\n }\n\n return { fetchUrl, fetchParams };\n}\n\nfunction normalizeUrlFromParsed(parsedUrl: URL): string {\n let result = '';\n result += parsedUrl.protocol;\n result += `//${parsedUrl.hostname}`;\n if (parsedUrl.port) {\n result += `:${parsedUrl.port}`;\n }\n result += `${parsedUrl.pathname}`;\n return result;\n}\n\nfunction createRatelimitError(): EthereumRpcError<unknown> {\n return ethErrors.rpc.internal({ message: `Request is being rate limited.` });\n}\n\nfunction createTimeoutError(): EthereumRpcError<unknown> {\n let msg = `Gateway timeout. The request took too long to process. `;\n msg += `This can happen when querying logs over too wide a block range.`;\n return ethErrors.rpc.internal({ message: msg });\n}\n\nfunction timeout(duration: number): Promise<NodeJS.Timeout> {\n return new Promise((resolve) => setTimeout(resolve, duration));\n}\n"]}
\No newline at end of file