UNPKG

eth-rpc-cache

Version:

A simple cache for Ethereum RPC requests extensible with different caching strategies

78 lines (77 loc) 3.58 kB
var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; import pMemoize from 'promise-mem'; import { errors } from './error'; import { perBlockStrategy } from './strategies/per-block'; import { permanentStrategy } from './strategies/permanent'; import { getKey } from './utils/cache-key'; export var createEthRpcCache = function (rpc, options) { if (options === void 0) { options = {}; } var _a = options.allowOthers, allowOthers = _a === void 0 ? true : _a, _b = options.cache, cache = _b === void 0 ? new Map() : _b, _c = options.strategies, strategies = _c === void 0 ? [perBlockStrategy, permanentStrategy] : _c; // Each strategy resolves to a cache if it has a maxAge defined. // Index all caches into the object by strategy name var cachesByStrategy = strategies .filter(function (_a) { var maxAge = _a.maxAge; return maxAge !== undefined; }) .map(function (_a) { var _b; var maxAge = _a.maxAge, name = _a.name; return (_b = {}, _b[name] = pMemoize(rpc, __assign({ cache: cache, maxAge: maxAge, resolver: getKey }, options)), _b); }) .reduce(function (acc, curr) { return (__assign(__assign({}, acc), curr)); }, {}); // This object indexed by method holds a function that returns which strategy (and cache) // should be used. By default, each strategy resolves to use its own cache, but some strategies // may resolve to other strategies' caches, depending on the method var strategyResolver = strategies .flatMap(function (_a) { var methods = _a.methods, name = _a.name, _b = _a.resolver, resolver = _b === void 0 ? function () { return name; } : _b; return methods.map(function (method) { var _a; return (_a = {}, _a[method] = resolver, _a); }); }) .reduce(function (acc, curr) { return (__assign(__assign({}, acc), curr)); }, {}); // Return the cached `rpc` function. // // If an strategy defined an RPC function for the incoming method, use that. // Otherwise call the method directly if allowed or return proper errors. // // To prevent user code to mutate the cached results, the cached RPC functions // will always return a clone of the result and not the result object itself. return function (method, params) { var _a; try { var strategyName = (_a = strategyResolver[method]) === null || _a === void 0 ? void 0 : _a.call(strategyResolver, method, params); if (strategyName) { return cachesByStrategy[strategyName](method, params).then(function (c) { // can't inline on .then(structuredClone), TS fails to infer return structuredClone(c); }); } if (allowOthers) { // not configured to be cached, call the method directly return rpc(method, params); } return Promise.reject(errors.methodNotFound()); } catch (err) { // @ts-expect-error error is typed as unknown by default return Promise.reject(errors.internalServerError(err)); } }; };