@metamask-previews/eth-json-rpc-middleware 21.0.0-preview-e98a6769 → 21.0.0-preview-772b5970

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,17 +3,23 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createBlockRefRewriteMiddleware = void 0;
4
4
  const json_rpc_engine_1 = require("@metamask/json-rpc-engine");
5
5
  const cache_1 = require("./utils/cache.cjs");
6
+ /**
7
+ * Creates a middleware that rewrites "latest" block references to the known
8
+ * latest block number from a block tracker.
9
+ *
10
+ * @param options - The options for the middleware.
11
+ * @param options.blockTracker - The block tracker to use.
12
+ * @returns The middleware.
13
+ */
6
14
  function createBlockRefRewriteMiddleware({ blockTracker, } = {}) {
7
15
  if (!blockTracker) {
8
16
  throw Error('BlockRefRewriteMiddleware - mandatory "blockTracker" option is missing.');
9
17
  }
10
18
  return (0, json_rpc_engine_1.createAsyncMiddleware)(async (req, _res, next) => {
11
19
  const blockRefIndex = (0, cache_1.blockTagParamIndex)(req.method);
12
- // skip if method does not include blockRef
13
20
  if (blockRefIndex === undefined) {
14
21
  return next();
15
22
  }
16
- // skip if not "latest"
17
23
  const blockRef = Array.isArray(req.params) && req.params[blockRefIndex]
18
24
  ? req.params[blockRefIndex]
19
25
  : // omitted blockRef implies "latest"
@@ -1 +1 @@
1
- {"version":3,"file":"block-ref-rewrite.cjs","sourceRoot":"","sources":["../src/block-ref-rewrite.ts"],"names":[],"mappings":";;;AAEA,+DAAkE;AAGlE,6CAAmD;AAMnD,SAAgB,+BAA+B,CAAC,EAC9C,YAAY,MACwB,EAAE;IAItC,IAAI,CAAC,YAAY,EAAE;QACjB,MAAM,KAAK,CACT,yEAAyE,CAC1E,CAAC;KACH;IAED,OAAO,IAAA,uCAAqB,EAAC,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE;QACrD,MAAM,aAAa,GAAuB,IAAA,0BAAkB,EAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACzE,2CAA2C;QAC3C,IAAI,aAAa,KAAK,SAAS,EAAE;YAC/B,OAAO,IAAI,EAAE,CAAC;SACf;QACD,uBAAuB;QACvB,MAAM,QAAQ,GACZ,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,aAAa,CAAC;YACpD,CAAC,CAAE,GAAG,CAAC,MAAM,CAAC,aAAa,CAAY;YACvC,CAAC,CAAC,oCAAoC;gBACpC,QAAQ,CAAC;QAEf,IAAI,QAAQ,KAAK,QAAQ,EAAE;YACzB,OAAO,IAAI,EAAE,CAAC;SACf;QACD,mDAAmD;QACnD,MAAM,iBAAiB,GAAG,MAAM,YAAY,CAAC,cAAc,EAAE,CAAC;QAC9D,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE;YAC7B,GAAG,CAAC,MAAM,CAAC,aAAa,CAAC,GAAG,iBAAiB,CAAC;SAC/C;QACD,OAAO,IAAI,EAAE,CAAC;IAChB,CAAC,CAAC,CAAC;AACL,CAAC;AAnCD,0EAmCC","sourcesContent":["import type { PollingBlockTracker } from '@metamask/eth-block-tracker';\nimport type { JsonRpcMiddleware } from '@metamask/json-rpc-engine';\nimport { createAsyncMiddleware } from '@metamask/json-rpc-engine';\nimport type { Json, JsonRpcParams } from '@metamask/utils';\n\nimport { blockTagParamIndex } from './utils/cache';\n\ntype BlockRefRewriteMiddlewareOptions = {\n blockTracker?: PollingBlockTracker;\n};\n\nexport function createBlockRefRewriteMiddleware({\n blockTracker,\n}: BlockRefRewriteMiddlewareOptions = {}): JsonRpcMiddleware<\n JsonRpcParams,\n Json\n> {\n if (!blockTracker) {\n throw Error(\n 'BlockRefRewriteMiddleware - mandatory \"blockTracker\" option is missing.',\n );\n }\n\n return createAsyncMiddleware(async (req, _res, next) => {\n const blockRefIndex: number | undefined = blockTagParamIndex(req.method);\n // skip if method does not include blockRef\n if (blockRefIndex === undefined) {\n return next();\n }\n // skip if not \"latest\"\n const blockRef: string | undefined =\n Array.isArray(req.params) && req.params[blockRefIndex]\n ? (req.params[blockRefIndex] as string)\n : // omitted blockRef implies \"latest\"\n 'latest';\n\n if (blockRef !== 'latest') {\n return next();\n }\n // rewrite blockRef to block-tracker's block number\n const latestBlockNumber = await blockTracker.getLatestBlock();\n if (Array.isArray(req.params)) {\n req.params[blockRefIndex] = latestBlockNumber;\n }\n return next();\n });\n}\n"]}
1
+ {"version":3,"file":"block-ref-rewrite.cjs","sourceRoot":"","sources":["../src/block-ref-rewrite.ts"],"names":[],"mappings":";;;AAEA,+DAAkE;AAGlE,6CAAmD;AAMnD;;;;;;;GAOG;AACH,SAAgB,+BAA+B,CAAC,EAC9C,YAAY,MACwB,EAAE;IAItC,IAAI,CAAC,YAAY,EAAE;QACjB,MAAM,KAAK,CACT,yEAAyE,CAC1E,CAAC;KACH;IAED,OAAO,IAAA,uCAAqB,EAAC,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE;QACrD,MAAM,aAAa,GAAuB,IAAA,0BAAkB,EAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACzE,IAAI,aAAa,KAAK,SAAS,EAAE;YAC/B,OAAO,IAAI,EAAE,CAAC;SACf;QAED,MAAM,QAAQ,GACZ,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,aAAa,CAAC;YACpD,CAAC,CAAE,GAAG,CAAC,MAAM,CAAC,aAAa,CAAY;YACvC,CAAC,CAAC,oCAAoC;gBACpC,QAAQ,CAAC;QAEf,IAAI,QAAQ,KAAK,QAAQ,EAAE;YACzB,OAAO,IAAI,EAAE,CAAC;SACf;QAED,mDAAmD;QACnD,MAAM,iBAAiB,GAAG,MAAM,YAAY,CAAC,cAAc,EAAE,CAAC;QAC9D,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE;YAC7B,GAAG,CAAC,MAAM,CAAC,aAAa,CAAC,GAAG,iBAAiB,CAAC;SAC/C;QACD,OAAO,IAAI,EAAE,CAAC;IAChB,CAAC,CAAC,CAAC;AACL,CAAC;AAnCD,0EAmCC","sourcesContent":["import type { PollingBlockTracker } from '@metamask/eth-block-tracker';\nimport type { JsonRpcMiddleware } from '@metamask/json-rpc-engine';\nimport { createAsyncMiddleware } from '@metamask/json-rpc-engine';\nimport type { Json, JsonRpcParams } from '@metamask/utils';\n\nimport { blockTagParamIndex } from './utils/cache';\n\ntype BlockRefRewriteMiddlewareOptions = {\n blockTracker?: PollingBlockTracker;\n};\n\n/**\n * Creates a middleware that rewrites \"latest\" block references to the known\n * latest block number from a block tracker.\n *\n * @param options - The options for the middleware.\n * @param options.blockTracker - The block tracker to use.\n * @returns The middleware.\n */\nexport function createBlockRefRewriteMiddleware({\n blockTracker,\n}: BlockRefRewriteMiddlewareOptions = {}): JsonRpcMiddleware<\n JsonRpcParams,\n Json\n> {\n if (!blockTracker) {\n throw Error(\n 'BlockRefRewriteMiddleware - mandatory \"blockTracker\" option is missing.',\n );\n }\n\n return createAsyncMiddleware(async (req, _res, next) => {\n const blockRefIndex: number | undefined = blockTagParamIndex(req.method);\n if (blockRefIndex === undefined) {\n return next();\n }\n\n const blockRef: string | undefined =\n Array.isArray(req.params) && req.params[blockRefIndex]\n ? (req.params[blockRefIndex] as string)\n : // omitted blockRef implies \"latest\"\n 'latest';\n\n if (blockRef !== 'latest') {\n return next();\n }\n\n // rewrite blockRef to block-tracker's block number\n const latestBlockNumber = await blockTracker.getLatestBlock();\n if (Array.isArray(req.params)) {\n req.params[blockRefIndex] = latestBlockNumber;\n }\n return next();\n });\n}\n"]}
@@ -4,6 +4,14 @@ import type { Json, JsonRpcParams } from "@metamask/utils";
4
4
  type BlockRefRewriteMiddlewareOptions = {
5
5
  blockTracker?: PollingBlockTracker;
6
6
  };
7
+ /**
8
+ * Creates a middleware that rewrites "latest" block references to the known
9
+ * latest block number from a block tracker.
10
+ *
11
+ * @param options - The options for the middleware.
12
+ * @param options.blockTracker - The block tracker to use.
13
+ * @returns The middleware.
14
+ */
7
15
  export declare function createBlockRefRewriteMiddleware({ blockTracker, }?: BlockRefRewriteMiddlewareOptions): JsonRpcMiddleware<JsonRpcParams, Json>;
8
16
  export {};
9
17
  //# sourceMappingURL=block-ref-rewrite.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"block-ref-rewrite.d.cts","sourceRoot":"","sources":["../src/block-ref-rewrite.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,oCAAoC;AACvE,OAAO,KAAK,EAAE,iBAAiB,EAAE,kCAAkC;AAEnE,OAAO,KAAK,EAAE,IAAI,EAAE,aAAa,EAAE,wBAAwB;AAI3D,KAAK,gCAAgC,GAAG;IACtC,YAAY,CAAC,EAAE,mBAAmB,CAAC;CACpC,CAAC;AAEF,wBAAgB,+BAA+B,CAAC,EAC9C,YAAY,GACb,GAAE,gCAAqC,GAAG,iBAAiB,CAC1D,aAAa,EACb,IAAI,CACL,CA8BA"}
1
+ {"version":3,"file":"block-ref-rewrite.d.cts","sourceRoot":"","sources":["../src/block-ref-rewrite.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,oCAAoC;AACvE,OAAO,KAAK,EAAE,iBAAiB,EAAE,kCAAkC;AAEnE,OAAO,KAAK,EAAE,IAAI,EAAE,aAAa,EAAE,wBAAwB;AAI3D,KAAK,gCAAgC,GAAG;IACtC,YAAY,CAAC,EAAE,mBAAmB,CAAC;CACpC,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,+BAA+B,CAAC,EAC9C,YAAY,GACb,GAAE,gCAAqC,GAAG,iBAAiB,CAC1D,aAAa,EACb,IAAI,CACL,CA8BA"}
@@ -4,6 +4,14 @@ import type { Json, JsonRpcParams } from "@metamask/utils";
4
4
  type BlockRefRewriteMiddlewareOptions = {
5
5
  blockTracker?: PollingBlockTracker;
6
6
  };
7
+ /**
8
+ * Creates a middleware that rewrites "latest" block references to the known
9
+ * latest block number from a block tracker.
10
+ *
11
+ * @param options - The options for the middleware.
12
+ * @param options.blockTracker - The block tracker to use.
13
+ * @returns The middleware.
14
+ */
7
15
  export declare function createBlockRefRewriteMiddleware({ blockTracker, }?: BlockRefRewriteMiddlewareOptions): JsonRpcMiddleware<JsonRpcParams, Json>;
8
16
  export {};
9
17
  //# sourceMappingURL=block-ref-rewrite.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"block-ref-rewrite.d.mts","sourceRoot":"","sources":["../src/block-ref-rewrite.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,oCAAoC;AACvE,OAAO,KAAK,EAAE,iBAAiB,EAAE,kCAAkC;AAEnE,OAAO,KAAK,EAAE,IAAI,EAAE,aAAa,EAAE,wBAAwB;AAI3D,KAAK,gCAAgC,GAAG;IACtC,YAAY,CAAC,EAAE,mBAAmB,CAAC;CACpC,CAAC;AAEF,wBAAgB,+BAA+B,CAAC,EAC9C,YAAY,GACb,GAAE,gCAAqC,GAAG,iBAAiB,CAC1D,aAAa,EACb,IAAI,CACL,CA8BA"}
1
+ {"version":3,"file":"block-ref-rewrite.d.mts","sourceRoot":"","sources":["../src/block-ref-rewrite.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,oCAAoC;AACvE,OAAO,KAAK,EAAE,iBAAiB,EAAE,kCAAkC;AAEnE,OAAO,KAAK,EAAE,IAAI,EAAE,aAAa,EAAE,wBAAwB;AAI3D,KAAK,gCAAgC,GAAG;IACtC,YAAY,CAAC,EAAE,mBAAmB,CAAC;CACpC,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,+BAA+B,CAAC,EAC9C,YAAY,GACb,GAAE,gCAAqC,GAAG,iBAAiB,CAC1D,aAAa,EACb,IAAI,CACL,CA8BA"}
@@ -1,16 +1,22 @@
1
1
  import { createAsyncMiddleware } from "@metamask/json-rpc-engine";
2
2
  import { blockTagParamIndex } from "./utils/cache.mjs";
3
+ /**
4
+ * Creates a middleware that rewrites "latest" block references to the known
5
+ * latest block number from a block tracker.
6
+ *
7
+ * @param options - The options for the middleware.
8
+ * @param options.blockTracker - The block tracker to use.
9
+ * @returns The middleware.
10
+ */
3
11
  export function createBlockRefRewriteMiddleware({ blockTracker, } = {}) {
4
12
  if (!blockTracker) {
5
13
  throw Error('BlockRefRewriteMiddleware - mandatory "blockTracker" option is missing.');
6
14
  }
7
15
  return createAsyncMiddleware(async (req, _res, next) => {
8
16
  const blockRefIndex = blockTagParamIndex(req.method);
9
- // skip if method does not include blockRef
10
17
  if (blockRefIndex === undefined) {
11
18
  return next();
12
19
  }
13
- // skip if not "latest"
14
20
  const blockRef = Array.isArray(req.params) && req.params[blockRefIndex]
15
21
  ? req.params[blockRefIndex]
16
22
  : // omitted blockRef implies "latest"
@@ -1 +1 @@
1
- {"version":3,"file":"block-ref-rewrite.mjs","sourceRoot":"","sources":["../src/block-ref-rewrite.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,qBAAqB,EAAE,kCAAkC;AAGlE,OAAO,EAAE,kBAAkB,EAAE,0BAAsB;AAMnD,MAAM,UAAU,+BAA+B,CAAC,EAC9C,YAAY,MACwB,EAAE;IAItC,IAAI,CAAC,YAAY,EAAE;QACjB,MAAM,KAAK,CACT,yEAAyE,CAC1E,CAAC;KACH;IAED,OAAO,qBAAqB,CAAC,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE;QACrD,MAAM,aAAa,GAAuB,kBAAkB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACzE,2CAA2C;QAC3C,IAAI,aAAa,KAAK,SAAS,EAAE;YAC/B,OAAO,IAAI,EAAE,CAAC;SACf;QACD,uBAAuB;QACvB,MAAM,QAAQ,GACZ,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,aAAa,CAAC;YACpD,CAAC,CAAE,GAAG,CAAC,MAAM,CAAC,aAAa,CAAY;YACvC,CAAC,CAAC,oCAAoC;gBACpC,QAAQ,CAAC;QAEf,IAAI,QAAQ,KAAK,QAAQ,EAAE;YACzB,OAAO,IAAI,EAAE,CAAC;SACf;QACD,mDAAmD;QACnD,MAAM,iBAAiB,GAAG,MAAM,YAAY,CAAC,cAAc,EAAE,CAAC;QAC9D,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE;YAC7B,GAAG,CAAC,MAAM,CAAC,aAAa,CAAC,GAAG,iBAAiB,CAAC;SAC/C;QACD,OAAO,IAAI,EAAE,CAAC;IAChB,CAAC,CAAC,CAAC;AACL,CAAC","sourcesContent":["import type { PollingBlockTracker } from '@metamask/eth-block-tracker';\nimport type { JsonRpcMiddleware } from '@metamask/json-rpc-engine';\nimport { createAsyncMiddleware } from '@metamask/json-rpc-engine';\nimport type { Json, JsonRpcParams } from '@metamask/utils';\n\nimport { blockTagParamIndex } from './utils/cache';\n\ntype BlockRefRewriteMiddlewareOptions = {\n blockTracker?: PollingBlockTracker;\n};\n\nexport function createBlockRefRewriteMiddleware({\n blockTracker,\n}: BlockRefRewriteMiddlewareOptions = {}): JsonRpcMiddleware<\n JsonRpcParams,\n Json\n> {\n if (!blockTracker) {\n throw Error(\n 'BlockRefRewriteMiddleware - mandatory \"blockTracker\" option is missing.',\n );\n }\n\n return createAsyncMiddleware(async (req, _res, next) => {\n const blockRefIndex: number | undefined = blockTagParamIndex(req.method);\n // skip if method does not include blockRef\n if (blockRefIndex === undefined) {\n return next();\n }\n // skip if not \"latest\"\n const blockRef: string | undefined =\n Array.isArray(req.params) && req.params[blockRefIndex]\n ? (req.params[blockRefIndex] as string)\n : // omitted blockRef implies \"latest\"\n 'latest';\n\n if (blockRef !== 'latest') {\n return next();\n }\n // rewrite blockRef to block-tracker's block number\n const latestBlockNumber = await blockTracker.getLatestBlock();\n if (Array.isArray(req.params)) {\n req.params[blockRefIndex] = latestBlockNumber;\n }\n return next();\n });\n}\n"]}
1
+ {"version":3,"file":"block-ref-rewrite.mjs","sourceRoot":"","sources":["../src/block-ref-rewrite.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,qBAAqB,EAAE,kCAAkC;AAGlE,OAAO,EAAE,kBAAkB,EAAE,0BAAsB;AAMnD;;;;;;;GAOG;AACH,MAAM,UAAU,+BAA+B,CAAC,EAC9C,YAAY,MACwB,EAAE;IAItC,IAAI,CAAC,YAAY,EAAE;QACjB,MAAM,KAAK,CACT,yEAAyE,CAC1E,CAAC;KACH;IAED,OAAO,qBAAqB,CAAC,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE;QACrD,MAAM,aAAa,GAAuB,kBAAkB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACzE,IAAI,aAAa,KAAK,SAAS,EAAE;YAC/B,OAAO,IAAI,EAAE,CAAC;SACf;QAED,MAAM,QAAQ,GACZ,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,aAAa,CAAC;YACpD,CAAC,CAAE,GAAG,CAAC,MAAM,CAAC,aAAa,CAAY;YACvC,CAAC,CAAC,oCAAoC;gBACpC,QAAQ,CAAC;QAEf,IAAI,QAAQ,KAAK,QAAQ,EAAE;YACzB,OAAO,IAAI,EAAE,CAAC;SACf;QAED,mDAAmD;QACnD,MAAM,iBAAiB,GAAG,MAAM,YAAY,CAAC,cAAc,EAAE,CAAC;QAC9D,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE;YAC7B,GAAG,CAAC,MAAM,CAAC,aAAa,CAAC,GAAG,iBAAiB,CAAC;SAC/C;QACD,OAAO,IAAI,EAAE,CAAC;IAChB,CAAC,CAAC,CAAC;AACL,CAAC","sourcesContent":["import type { PollingBlockTracker } from '@metamask/eth-block-tracker';\nimport type { JsonRpcMiddleware } from '@metamask/json-rpc-engine';\nimport { createAsyncMiddleware } from '@metamask/json-rpc-engine';\nimport type { Json, JsonRpcParams } from '@metamask/utils';\n\nimport { blockTagParamIndex } from './utils/cache';\n\ntype BlockRefRewriteMiddlewareOptions = {\n blockTracker?: PollingBlockTracker;\n};\n\n/**\n * Creates a middleware that rewrites \"latest\" block references to the known\n * latest block number from a block tracker.\n *\n * @param options - The options for the middleware.\n * @param options.blockTracker - The block tracker to use.\n * @returns The middleware.\n */\nexport function createBlockRefRewriteMiddleware({\n blockTracker,\n}: BlockRefRewriteMiddlewareOptions = {}): JsonRpcMiddleware<\n JsonRpcParams,\n Json\n> {\n if (!blockTracker) {\n throw Error(\n 'BlockRefRewriteMiddleware - mandatory \"blockTracker\" option is missing.',\n );\n }\n\n return createAsyncMiddleware(async (req, _res, next) => {\n const blockRefIndex: number | undefined = blockTagParamIndex(req.method);\n if (blockRefIndex === undefined) {\n return next();\n }\n\n const blockRef: string | undefined =\n Array.isArray(req.params) && req.params[blockRefIndex]\n ? (req.params[blockRefIndex] as string)\n : // omitted blockRef implies \"latest\"\n 'latest';\n\n if (blockRef !== 'latest') {\n return next();\n }\n\n // rewrite blockRef to block-tracker's block number\n const latestBlockNumber = await blockTracker.getLatestBlock();\n if (Array.isArray(req.params)) {\n req.params[blockRefIndex] = latestBlockNumber;\n }\n return next();\n });\n}\n"]}
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createBlockTrackerInspectorMiddleware = void 0;
4
4
  const json_rpc_engine_1 = require("@metamask/json-rpc-engine");
5
+ const utils_1 = require("@metamask/utils");
5
6
  const logging_utils_1 = require("./logging-utils.cjs");
6
7
  const log = (0, logging_utils_1.createModuleLogger)(logging_utils_1.projectLogger, 'block-tracker-inspector');
7
8
  const futureBlockRefRequests = [
@@ -9,44 +10,29 @@ const futureBlockRefRequests = [
9
10
  'eth_getTransactionReceipt',
10
11
  ];
11
12
  /**
12
- * Determines whether the given object has the given property.
13
+ * Creates a middleware that checks whether response block references are higher than the current block.
14
+ * If the block reference is higher, the middleware will make the block tracker check for a new block.
13
15
  *
14
- * @param objectToCheck - The object to check.
15
- * @param property - The property to look for.
16
- * @returns Whether the object has the property.
16
+ * @param options - The options for the middleware.
17
+ * @param options.blockTracker - The block tracker to use.
18
+ * @returns The middleware.
17
19
  */
18
- function hasProperty(objectToCheck, property) {
19
- return Object.hasOwnProperty.call(objectToCheck, property);
20
- }
21
- function getResultBlockNumber(response) {
22
- const { result } = response;
23
- if (!result ||
24
- typeof result !== 'object' ||
25
- !hasProperty(result, 'blockNumber')) {
26
- return undefined;
27
- }
28
- if (typeof result.blockNumber === 'string') {
29
- return result.blockNumber;
30
- }
31
- return undefined;
32
- }
33
- // inspect if response contains a block ref higher than our latest block
34
20
  function createBlockTrackerInspectorMiddleware({ blockTracker, }) {
35
21
  return (0, json_rpc_engine_1.createAsyncMiddleware)(async (req, res, next) => {
36
22
  if (!futureBlockRefRequests.includes(req.method)) {
37
23
  return next();
38
24
  }
39
25
  await next();
40
- // abort if no result or no block number
41
26
  const responseBlockNumber = getResultBlockNumber(res);
42
27
  if (!responseBlockNumber) {
43
28
  return undefined;
44
29
  }
45
30
  log('res.result.blockNumber exists, proceeding. res = %o', res);
46
- // if number is higher, suggest block-tracker check for a new block
31
+ // If number is higher, suggest block-tracker check for a new block
47
32
  const blockNumber = Number.parseInt(responseBlockNumber, 16);
33
+ const currentBlockNumber = Number.parseInt(
48
34
  // Typecast: If getCurrentBlock returns null, currentBlockNumber will be NaN, which is fine.
49
- const currentBlockNumber = Number.parseInt(blockTracker.getCurrentBlock(), 16);
35
+ blockTracker.getCurrentBlock(), 16);
50
36
  if (blockNumber > currentBlockNumber) {
51
37
  log('blockNumber from response is greater than current block number, refreshing current block number');
52
38
  await blockTracker.checkForLatestBlock();
@@ -55,4 +41,16 @@ function createBlockTrackerInspectorMiddleware({ blockTracker, }) {
55
41
  });
56
42
  }
57
43
  exports.createBlockTrackerInspectorMiddleware = createBlockTrackerInspectorMiddleware;
44
+ function getResultBlockNumber(response) {
45
+ const { result } = response;
46
+ if (!result ||
47
+ typeof result !== 'object' ||
48
+ !(0, utils_1.hasProperty)(result, 'blockNumber')) {
49
+ return undefined;
50
+ }
51
+ if (typeof result.blockNumber === 'string') {
52
+ return result.blockNumber;
53
+ }
54
+ return undefined;
55
+ }
58
56
  //# sourceMappingURL=block-tracker-inspector.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"block-tracker-inspector.cjs","sourceRoot":"","sources":["../src/block-tracker-inspector.ts"],"names":[],"mappings":";;;AAEA,+DAAkE;AAOlE,uDAAoE;AAEpE,MAAM,GAAG,GAAG,IAAA,kCAAkB,EAAC,6BAAa,EAAE,yBAAyB,CAAC,CAAC;AACzE,MAAM,sBAAsB,GAAa;IACvC,0BAA0B;IAC1B,2BAA2B;CAC5B,CAAC;AAWF;;;;;;GAMG;AACH,SAAS,WAAW,CAClB,aAA4B,EAC5B,QAAkB;IAElB,OAAO,MAAM,CAAC,cAAc,CAAC,IAAI,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAC;AAC7D,CAAC;AAED,SAAS,oBAAoB,CAC3B,QAAgC;IAEhC,MAAM,EAAE,MAAM,EAAE,GAAG,QAAQ,CAAC;IAC5B,IACE,CAAC,MAAM;QACP,OAAO,MAAM,KAAK,QAAQ;QAC1B,CAAC,WAAW,CAAC,MAAM,EAAE,aAAa,CAAC,EACnC;QACA,OAAO,SAAS,CAAC;KAClB;IAED,IAAI,OAAO,MAAM,CAAC,WAAW,KAAK,QAAQ,EAAE;QAC1C,OAAO,MAAM,CAAC,WAAW,CAAC;KAC3B;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,wEAAwE;AACxE,SAAgB,qCAAqC,CAAC,EACpD,YAAY,GAC2B;IAIvC,OAAO,IAAA,uCAAqB,EAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QACpD,IAAI,CAAC,sBAAsB,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE;YAChD,OAAO,IAAI,EAAE,CAAC;SACf;QACD,MAAM,IAAI,EAAE,CAAC;QAEb,wCAAwC;QACxC,MAAM,mBAAmB,GAAG,oBAAoB,CAAC,GAAG,CAAC,CAAC;QACtD,IAAI,CAAC,mBAAmB,EAAE;YACxB,OAAO,SAAS,CAAC;SAClB;QAED,GAAG,CAAC,qDAAqD,EAAE,GAAG,CAAC,CAAC;QAEhE,mEAAmE;QACnE,MAAM,WAAW,GAAW,MAAM,CAAC,QAAQ,CAAC,mBAAmB,EAAE,EAAE,CAAC,CAAC;QACrE,4FAA4F;QAC5F,MAAM,kBAAkB,GAAW,MAAM,CAAC,QAAQ,CAChD,YAAY,CAAC,eAAe,EAAS,EACrC,EAAE,CACH,CAAC;QACF,IAAI,WAAW,GAAG,kBAAkB,EAAE;YACpC,GAAG,CACD,iGAAiG,CAClG,CAAC;YACF,MAAM,YAAY,CAAC,mBAAmB,EAAE,CAAC;SAC1C;QACD,OAAO,SAAS,CAAC;IACnB,CAAC,CAAC,CAAC;AACL,CAAC;AAnCD,sFAmCC","sourcesContent":["import type { PollingBlockTracker } from '@metamask/eth-block-tracker';\nimport type { JsonRpcMiddleware } from '@metamask/json-rpc-engine';\nimport { createAsyncMiddleware } from '@metamask/json-rpc-engine';\nimport type {\n Json,\n JsonRpcParams,\n PendingJsonRpcResponse,\n} from '@metamask/utils';\n\nimport { projectLogger, createModuleLogger } from './logging-utils';\n\nconst log = createModuleLogger(projectLogger, 'block-tracker-inspector');\nconst futureBlockRefRequests: string[] = [\n 'eth_getTransactionByHash',\n 'eth_getTransactionReceipt',\n];\n\ntype BlockTrackerInspectorMiddlewareOptions = {\n blockTracker: PollingBlockTracker;\n};\n\n/**\n * Any type that can be used as the name of an object property.\n */\ntype ValidPropertyType = string | number | symbol;\n\n/**\n * Determines whether the given object has the given property.\n *\n * @param objectToCheck - The object to check.\n * @param property - The property to look for.\n * @returns Whether the object has the property.\n */\nfunction hasProperty<ObjectToCheck, Property extends ValidPropertyType>(\n objectToCheck: ObjectToCheck,\n property: Property,\n): objectToCheck is ObjectToCheck & Record<Property, unknown> {\n return Object.hasOwnProperty.call(objectToCheck, property);\n}\n\nfunction getResultBlockNumber(\n response: PendingJsonRpcResponse,\n): string | undefined {\n const { result } = response;\n if (\n !result ||\n typeof result !== 'object' ||\n !hasProperty(result, 'blockNumber')\n ) {\n return undefined;\n }\n\n if (typeof result.blockNumber === 'string') {\n return result.blockNumber;\n }\n return undefined;\n}\n\n// inspect if response contains a block ref higher than our latest block\nexport function createBlockTrackerInspectorMiddleware({\n blockTracker,\n}: BlockTrackerInspectorMiddlewareOptions): JsonRpcMiddleware<\n JsonRpcParams,\n Json\n> {\n return createAsyncMiddleware(async (req, res, next) => {\n if (!futureBlockRefRequests.includes(req.method)) {\n return next();\n }\n await next();\n\n // abort if no result or no block number\n const responseBlockNumber = getResultBlockNumber(res);\n if (!responseBlockNumber) {\n return undefined;\n }\n\n log('res.result.blockNumber exists, proceeding. res = %o', res);\n\n // if number is higher, suggest block-tracker check for a new block\n const blockNumber: number = Number.parseInt(responseBlockNumber, 16);\n // Typecast: If getCurrentBlock returns null, currentBlockNumber will be NaN, which is fine.\n const currentBlockNumber: number = Number.parseInt(\n blockTracker.getCurrentBlock() as any,\n 16,\n );\n if (blockNumber > currentBlockNumber) {\n log(\n 'blockNumber from response is greater than current block number, refreshing current block number',\n );\n await blockTracker.checkForLatestBlock();\n }\n return undefined;\n });\n}\n"]}
1
+ {"version":3,"file":"block-tracker-inspector.cjs","sourceRoot":"","sources":["../src/block-tracker-inspector.ts"],"names":[],"mappings":";;;AAEA,+DAAkE;AAClE,2CAA8C;AAO9C,uDAAoE;AAEpE,MAAM,GAAG,GAAG,IAAA,kCAAkB,EAAC,6BAAa,EAAE,yBAAyB,CAAC,CAAC;AACzE,MAAM,sBAAsB,GAAsB;IAChD,0BAA0B;IAC1B,2BAA2B;CAC5B,CAAC;AAEF;;;;;;;GAOG;AACH,SAAgB,qCAAqC,CAAC,EACpD,YAAY,GAGb;IACC,OAAO,IAAA,uCAAqB,EAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QACpD,IAAI,CAAC,sBAAsB,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE;YAChD,OAAO,IAAI,EAAE,CAAC;SACf;QACD,MAAM,IAAI,EAAE,CAAC;QAEb,MAAM,mBAAmB,GAAG,oBAAoB,CAAC,GAAG,CAAC,CAAC;QACtD,IAAI,CAAC,mBAAmB,EAAE;YACxB,OAAO,SAAS,CAAC;SAClB;QAED,GAAG,CAAC,qDAAqD,EAAE,GAAG,CAAC,CAAC;QAEhE,mEAAmE;QACnE,MAAM,WAAW,GAAW,MAAM,CAAC,QAAQ,CAAC,mBAAmB,EAAE,EAAE,CAAC,CAAC;QACrE,MAAM,kBAAkB,GAAW,MAAM,CAAC,QAAQ;QAChD,4FAA4F;QAC5F,YAAY,CAAC,eAAe,EAAY,EACxC,EAAE,CACH,CAAC;QACF,IAAI,WAAW,GAAG,kBAAkB,EAAE;YACpC,GAAG,CACD,iGAAiG,CAClG,CAAC;YACF,MAAM,YAAY,CAAC,mBAAmB,EAAE,CAAC;SAC1C;QACD,OAAO,SAAS,CAAC;IACnB,CAAC,CAAC,CAAC;AACL,CAAC;AAjCD,sFAiCC;AAED,SAAS,oBAAoB,CAC3B,QAAgC;IAEhC,MAAM,EAAE,MAAM,EAAE,GAAG,QAAQ,CAAC;IAC5B,IACE,CAAC,MAAM;QACP,OAAO,MAAM,KAAK,QAAQ;QAC1B,CAAC,IAAA,mBAAW,EAAC,MAAM,EAAE,aAAa,CAAC,EACnC;QACA,OAAO,SAAS,CAAC;KAClB;IAED,IAAI,OAAO,MAAM,CAAC,WAAW,KAAK,QAAQ,EAAE;QAC1C,OAAO,MAAM,CAAC,WAAW,CAAC;KAC3B;IACD,OAAO,SAAS,CAAC;AACnB,CAAC","sourcesContent":["import type { PollingBlockTracker } from '@metamask/eth-block-tracker';\nimport type { JsonRpcMiddleware } from '@metamask/json-rpc-engine';\nimport { createAsyncMiddleware } from '@metamask/json-rpc-engine';\nimport { hasProperty } from '@metamask/utils';\nimport type {\n Json,\n JsonRpcParams,\n PendingJsonRpcResponse,\n} from '@metamask/utils';\n\nimport { projectLogger, createModuleLogger } from './logging-utils';\n\nconst log = createModuleLogger(projectLogger, 'block-tracker-inspector');\nconst futureBlockRefRequests: readonly string[] = [\n 'eth_getTransactionByHash',\n 'eth_getTransactionReceipt',\n];\n\n/**\n * Creates a middleware that checks whether response block references are higher than the current block.\n * If the block reference is higher, the middleware will make the block tracker check for a new block.\n *\n * @param options - The options for the middleware.\n * @param options.blockTracker - The block tracker to use.\n * @returns The middleware.\n */\nexport function createBlockTrackerInspectorMiddleware({\n blockTracker,\n}: {\n blockTracker: PollingBlockTracker;\n}): JsonRpcMiddleware<JsonRpcParams, Json> {\n return createAsyncMiddleware(async (req, res, next) => {\n if (!futureBlockRefRequests.includes(req.method)) {\n return next();\n }\n await next();\n\n const responseBlockNumber = getResultBlockNumber(res);\n if (!responseBlockNumber) {\n return undefined;\n }\n\n log('res.result.blockNumber exists, proceeding. res = %o', res);\n\n // If number is higher, suggest block-tracker check for a new block\n const blockNumber: number = Number.parseInt(responseBlockNumber, 16);\n const currentBlockNumber: number = Number.parseInt(\n // Typecast: If getCurrentBlock returns null, currentBlockNumber will be NaN, which is fine.\n blockTracker.getCurrentBlock() as string,\n 16,\n );\n if (blockNumber > currentBlockNumber) {\n log(\n 'blockNumber from response is greater than current block number, refreshing current block number',\n );\n await blockTracker.checkForLatestBlock();\n }\n return undefined;\n });\n}\n\nfunction getResultBlockNumber(\n response: PendingJsonRpcResponse,\n): string | undefined {\n const { result } = response;\n if (\n !result ||\n typeof result !== 'object' ||\n !hasProperty(result, 'blockNumber')\n ) {\n return undefined;\n }\n\n if (typeof result.blockNumber === 'string') {\n return result.blockNumber;\n }\n return undefined;\n}\n"]}
@@ -1,9 +1,15 @@
1
1
  import type { PollingBlockTracker } from "@metamask/eth-block-tracker";
2
2
  import type { JsonRpcMiddleware } from "@metamask/json-rpc-engine";
3
3
  import type { Json, JsonRpcParams } from "@metamask/utils";
4
- type BlockTrackerInspectorMiddlewareOptions = {
4
+ /**
5
+ * Creates a middleware that checks whether response block references are higher than the current block.
6
+ * If the block reference is higher, the middleware will make the block tracker check for a new block.
7
+ *
8
+ * @param options - The options for the middleware.
9
+ * @param options.blockTracker - The block tracker to use.
10
+ * @returns The middleware.
11
+ */
12
+ export declare function createBlockTrackerInspectorMiddleware({ blockTracker, }: {
5
13
  blockTracker: PollingBlockTracker;
6
- };
7
- export declare function createBlockTrackerInspectorMiddleware({ blockTracker, }: BlockTrackerInspectorMiddlewareOptions): JsonRpcMiddleware<JsonRpcParams, Json>;
8
- export {};
14
+ }): JsonRpcMiddleware<JsonRpcParams, Json>;
9
15
  //# sourceMappingURL=block-tracker-inspector.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"block-tracker-inspector.d.cts","sourceRoot":"","sources":["../src/block-tracker-inspector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,oCAAoC;AACvE,OAAO,KAAK,EAAE,iBAAiB,EAAE,kCAAkC;AAEnE,OAAO,KAAK,EACV,IAAI,EACJ,aAAa,EAEd,wBAAwB;AAUzB,KAAK,sCAAsC,GAAG;IAC5C,YAAY,EAAE,mBAAmB,CAAC;CACnC,CAAC;AAwCF,wBAAgB,qCAAqC,CAAC,EACpD,YAAY,GACb,EAAE,sCAAsC,GAAG,iBAAiB,CAC3D,aAAa,EACb,IAAI,CACL,CA8BA"}
1
+ {"version":3,"file":"block-tracker-inspector.d.cts","sourceRoot":"","sources":["../src/block-tracker-inspector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,oCAAoC;AACvE,OAAO,KAAK,EAAE,iBAAiB,EAAE,kCAAkC;AAGnE,OAAO,KAAK,EACV,IAAI,EACJ,aAAa,EAEd,wBAAwB;AAUzB;;;;;;;GAOG;AACH,wBAAgB,qCAAqC,CAAC,EACpD,YAAY,GACb,EAAE;IACD,YAAY,EAAE,mBAAmB,CAAC;CACnC,GAAG,iBAAiB,CAAC,aAAa,EAAE,IAAI,CAAC,CA6BzC"}
@@ -1,9 +1,15 @@
1
1
  import type { PollingBlockTracker } from "@metamask/eth-block-tracker";
2
2
  import type { JsonRpcMiddleware } from "@metamask/json-rpc-engine";
3
3
  import type { Json, JsonRpcParams } from "@metamask/utils";
4
- type BlockTrackerInspectorMiddlewareOptions = {
4
+ /**
5
+ * Creates a middleware that checks whether response block references are higher than the current block.
6
+ * If the block reference is higher, the middleware will make the block tracker check for a new block.
7
+ *
8
+ * @param options - The options for the middleware.
9
+ * @param options.blockTracker - The block tracker to use.
10
+ * @returns The middleware.
11
+ */
12
+ export declare function createBlockTrackerInspectorMiddleware({ blockTracker, }: {
5
13
  blockTracker: PollingBlockTracker;
6
- };
7
- export declare function createBlockTrackerInspectorMiddleware({ blockTracker, }: BlockTrackerInspectorMiddlewareOptions): JsonRpcMiddleware<JsonRpcParams, Json>;
8
- export {};
14
+ }): JsonRpcMiddleware<JsonRpcParams, Json>;
9
15
  //# sourceMappingURL=block-tracker-inspector.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"block-tracker-inspector.d.mts","sourceRoot":"","sources":["../src/block-tracker-inspector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,oCAAoC;AACvE,OAAO,KAAK,EAAE,iBAAiB,EAAE,kCAAkC;AAEnE,OAAO,KAAK,EACV,IAAI,EACJ,aAAa,EAEd,wBAAwB;AAUzB,KAAK,sCAAsC,GAAG;IAC5C,YAAY,EAAE,mBAAmB,CAAC;CACnC,CAAC;AAwCF,wBAAgB,qCAAqC,CAAC,EACpD,YAAY,GACb,EAAE,sCAAsC,GAAG,iBAAiB,CAC3D,aAAa,EACb,IAAI,CACL,CA8BA"}
1
+ {"version":3,"file":"block-tracker-inspector.d.mts","sourceRoot":"","sources":["../src/block-tracker-inspector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,oCAAoC;AACvE,OAAO,KAAK,EAAE,iBAAiB,EAAE,kCAAkC;AAGnE,OAAO,KAAK,EACV,IAAI,EACJ,aAAa,EAEd,wBAAwB;AAUzB;;;;;;;GAOG;AACH,wBAAgB,qCAAqC,CAAC,EACpD,YAAY,GACb,EAAE;IACD,YAAY,EAAE,mBAAmB,CAAC;CACnC,GAAG,iBAAiB,CAAC,aAAa,EAAE,IAAI,CAAC,CA6BzC"}
@@ -1,4 +1,5 @@
1
1
  import { createAsyncMiddleware } from "@metamask/json-rpc-engine";
2
+ import { hasProperty } from "@metamask/utils";
2
3
  import { projectLogger, createModuleLogger } from "./logging-utils.mjs";
3
4
  const log = createModuleLogger(projectLogger, 'block-tracker-inspector');
4
5
  const futureBlockRefRequests = [
@@ -6,44 +7,29 @@ const futureBlockRefRequests = [
6
7
  'eth_getTransactionReceipt',
7
8
  ];
8
9
  /**
9
- * Determines whether the given object has the given property.
10
+ * Creates a middleware that checks whether response block references are higher than the current block.
11
+ * If the block reference is higher, the middleware will make the block tracker check for a new block.
10
12
  *
11
- * @param objectToCheck - The object to check.
12
- * @param property - The property to look for.
13
- * @returns Whether the object has the property.
13
+ * @param options - The options for the middleware.
14
+ * @param options.blockTracker - The block tracker to use.
15
+ * @returns The middleware.
14
16
  */
15
- function hasProperty(objectToCheck, property) {
16
- return Object.hasOwnProperty.call(objectToCheck, property);
17
- }
18
- function getResultBlockNumber(response) {
19
- const { result } = response;
20
- if (!result ||
21
- typeof result !== 'object' ||
22
- !hasProperty(result, 'blockNumber')) {
23
- return undefined;
24
- }
25
- if (typeof result.blockNumber === 'string') {
26
- return result.blockNumber;
27
- }
28
- return undefined;
29
- }
30
- // inspect if response contains a block ref higher than our latest block
31
17
  export function createBlockTrackerInspectorMiddleware({ blockTracker, }) {
32
18
  return createAsyncMiddleware(async (req, res, next) => {
33
19
  if (!futureBlockRefRequests.includes(req.method)) {
34
20
  return next();
35
21
  }
36
22
  await next();
37
- // abort if no result or no block number
38
23
  const responseBlockNumber = getResultBlockNumber(res);
39
24
  if (!responseBlockNumber) {
40
25
  return undefined;
41
26
  }
42
27
  log('res.result.blockNumber exists, proceeding. res = %o', res);
43
- // if number is higher, suggest block-tracker check for a new block
28
+ // If number is higher, suggest block-tracker check for a new block
44
29
  const blockNumber = Number.parseInt(responseBlockNumber, 16);
30
+ const currentBlockNumber = Number.parseInt(
45
31
  // Typecast: If getCurrentBlock returns null, currentBlockNumber will be NaN, which is fine.
46
- const currentBlockNumber = Number.parseInt(blockTracker.getCurrentBlock(), 16);
32
+ blockTracker.getCurrentBlock(), 16);
47
33
  if (blockNumber > currentBlockNumber) {
48
34
  log('blockNumber from response is greater than current block number, refreshing current block number');
49
35
  await blockTracker.checkForLatestBlock();
@@ -51,4 +37,16 @@ export function createBlockTrackerInspectorMiddleware({ blockTracker, }) {
51
37
  return undefined;
52
38
  });
53
39
  }
40
+ function getResultBlockNumber(response) {
41
+ const { result } = response;
42
+ if (!result ||
43
+ typeof result !== 'object' ||
44
+ !hasProperty(result, 'blockNumber')) {
45
+ return undefined;
46
+ }
47
+ if (typeof result.blockNumber === 'string') {
48
+ return result.blockNumber;
49
+ }
50
+ return undefined;
51
+ }
54
52
  //# sourceMappingURL=block-tracker-inspector.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"block-tracker-inspector.mjs","sourceRoot":"","sources":["../src/block-tracker-inspector.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,qBAAqB,EAAE,kCAAkC;AAOlE,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,4BAAwB;AAEpE,MAAM,GAAG,GAAG,kBAAkB,CAAC,aAAa,EAAE,yBAAyB,CAAC,CAAC;AACzE,MAAM,sBAAsB,GAAa;IACvC,0BAA0B;IAC1B,2BAA2B;CAC5B,CAAC;AAWF;;;;;;GAMG;AACH,SAAS,WAAW,CAClB,aAA4B,EAC5B,QAAkB;IAElB,OAAO,MAAM,CAAC,cAAc,CAAC,IAAI,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAC;AAC7D,CAAC;AAED,SAAS,oBAAoB,CAC3B,QAAgC;IAEhC,MAAM,EAAE,MAAM,EAAE,GAAG,QAAQ,CAAC;IAC5B,IACE,CAAC,MAAM;QACP,OAAO,MAAM,KAAK,QAAQ;QAC1B,CAAC,WAAW,CAAC,MAAM,EAAE,aAAa,CAAC,EACnC;QACA,OAAO,SAAS,CAAC;KAClB;IAED,IAAI,OAAO,MAAM,CAAC,WAAW,KAAK,QAAQ,EAAE;QAC1C,OAAO,MAAM,CAAC,WAAW,CAAC;KAC3B;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,wEAAwE;AACxE,MAAM,UAAU,qCAAqC,CAAC,EACpD,YAAY,GAC2B;IAIvC,OAAO,qBAAqB,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QACpD,IAAI,CAAC,sBAAsB,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE;YAChD,OAAO,IAAI,EAAE,CAAC;SACf;QACD,MAAM,IAAI,EAAE,CAAC;QAEb,wCAAwC;QACxC,MAAM,mBAAmB,GAAG,oBAAoB,CAAC,GAAG,CAAC,CAAC;QACtD,IAAI,CAAC,mBAAmB,EAAE;YACxB,OAAO,SAAS,CAAC;SAClB;QAED,GAAG,CAAC,qDAAqD,EAAE,GAAG,CAAC,CAAC;QAEhE,mEAAmE;QACnE,MAAM,WAAW,GAAW,MAAM,CAAC,QAAQ,CAAC,mBAAmB,EAAE,EAAE,CAAC,CAAC;QACrE,4FAA4F;QAC5F,MAAM,kBAAkB,GAAW,MAAM,CAAC,QAAQ,CAChD,YAAY,CAAC,eAAe,EAAS,EACrC,EAAE,CACH,CAAC;QACF,IAAI,WAAW,GAAG,kBAAkB,EAAE;YACpC,GAAG,CACD,iGAAiG,CAClG,CAAC;YACF,MAAM,YAAY,CAAC,mBAAmB,EAAE,CAAC;SAC1C;QACD,OAAO,SAAS,CAAC;IACnB,CAAC,CAAC,CAAC;AACL,CAAC","sourcesContent":["import type { PollingBlockTracker } from '@metamask/eth-block-tracker';\nimport type { JsonRpcMiddleware } from '@metamask/json-rpc-engine';\nimport { createAsyncMiddleware } from '@metamask/json-rpc-engine';\nimport type {\n Json,\n JsonRpcParams,\n PendingJsonRpcResponse,\n} from '@metamask/utils';\n\nimport { projectLogger, createModuleLogger } from './logging-utils';\n\nconst log = createModuleLogger(projectLogger, 'block-tracker-inspector');\nconst futureBlockRefRequests: string[] = [\n 'eth_getTransactionByHash',\n 'eth_getTransactionReceipt',\n];\n\ntype BlockTrackerInspectorMiddlewareOptions = {\n blockTracker: PollingBlockTracker;\n};\n\n/**\n * Any type that can be used as the name of an object property.\n */\ntype ValidPropertyType = string | number | symbol;\n\n/**\n * Determines whether the given object has the given property.\n *\n * @param objectToCheck - The object to check.\n * @param property - The property to look for.\n * @returns Whether the object has the property.\n */\nfunction hasProperty<ObjectToCheck, Property extends ValidPropertyType>(\n objectToCheck: ObjectToCheck,\n property: Property,\n): objectToCheck is ObjectToCheck & Record<Property, unknown> {\n return Object.hasOwnProperty.call(objectToCheck, property);\n}\n\nfunction getResultBlockNumber(\n response: PendingJsonRpcResponse,\n): string | undefined {\n const { result } = response;\n if (\n !result ||\n typeof result !== 'object' ||\n !hasProperty(result, 'blockNumber')\n ) {\n return undefined;\n }\n\n if (typeof result.blockNumber === 'string') {\n return result.blockNumber;\n }\n return undefined;\n}\n\n// inspect if response contains a block ref higher than our latest block\nexport function createBlockTrackerInspectorMiddleware({\n blockTracker,\n}: BlockTrackerInspectorMiddlewareOptions): JsonRpcMiddleware<\n JsonRpcParams,\n Json\n> {\n return createAsyncMiddleware(async (req, res, next) => {\n if (!futureBlockRefRequests.includes(req.method)) {\n return next();\n }\n await next();\n\n // abort if no result or no block number\n const responseBlockNumber = getResultBlockNumber(res);\n if (!responseBlockNumber) {\n return undefined;\n }\n\n log('res.result.blockNumber exists, proceeding. res = %o', res);\n\n // if number is higher, suggest block-tracker check for a new block\n const blockNumber: number = Number.parseInt(responseBlockNumber, 16);\n // Typecast: If getCurrentBlock returns null, currentBlockNumber will be NaN, which is fine.\n const currentBlockNumber: number = Number.parseInt(\n blockTracker.getCurrentBlock() as any,\n 16,\n );\n if (blockNumber > currentBlockNumber) {\n log(\n 'blockNumber from response is greater than current block number, refreshing current block number',\n );\n await blockTracker.checkForLatestBlock();\n }\n return undefined;\n });\n}\n"]}
1
+ {"version":3,"file":"block-tracker-inspector.mjs","sourceRoot":"","sources":["../src/block-tracker-inspector.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,qBAAqB,EAAE,kCAAkC;AAClE,OAAO,EAAE,WAAW,EAAE,wBAAwB;AAO9C,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,4BAAwB;AAEpE,MAAM,GAAG,GAAG,kBAAkB,CAAC,aAAa,EAAE,yBAAyB,CAAC,CAAC;AACzE,MAAM,sBAAsB,GAAsB;IAChD,0BAA0B;IAC1B,2BAA2B;CAC5B,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,UAAU,qCAAqC,CAAC,EACpD,YAAY,GAGb;IACC,OAAO,qBAAqB,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QACpD,IAAI,CAAC,sBAAsB,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE;YAChD,OAAO,IAAI,EAAE,CAAC;SACf;QACD,MAAM,IAAI,EAAE,CAAC;QAEb,MAAM,mBAAmB,GAAG,oBAAoB,CAAC,GAAG,CAAC,CAAC;QACtD,IAAI,CAAC,mBAAmB,EAAE;YACxB,OAAO,SAAS,CAAC;SAClB;QAED,GAAG,CAAC,qDAAqD,EAAE,GAAG,CAAC,CAAC;QAEhE,mEAAmE;QACnE,MAAM,WAAW,GAAW,MAAM,CAAC,QAAQ,CAAC,mBAAmB,EAAE,EAAE,CAAC,CAAC;QACrE,MAAM,kBAAkB,GAAW,MAAM,CAAC,QAAQ;QAChD,4FAA4F;QAC5F,YAAY,CAAC,eAAe,EAAY,EACxC,EAAE,CACH,CAAC;QACF,IAAI,WAAW,GAAG,kBAAkB,EAAE;YACpC,GAAG,CACD,iGAAiG,CAClG,CAAC;YACF,MAAM,YAAY,CAAC,mBAAmB,EAAE,CAAC;SAC1C;QACD,OAAO,SAAS,CAAC;IACnB,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,oBAAoB,CAC3B,QAAgC;IAEhC,MAAM,EAAE,MAAM,EAAE,GAAG,QAAQ,CAAC;IAC5B,IACE,CAAC,MAAM;QACP,OAAO,MAAM,KAAK,QAAQ;QAC1B,CAAC,WAAW,CAAC,MAAM,EAAE,aAAa,CAAC,EACnC;QACA,OAAO,SAAS,CAAC;KAClB;IAED,IAAI,OAAO,MAAM,CAAC,WAAW,KAAK,QAAQ,EAAE;QAC1C,OAAO,MAAM,CAAC,WAAW,CAAC;KAC3B;IACD,OAAO,SAAS,CAAC;AACnB,CAAC","sourcesContent":["import type { PollingBlockTracker } from '@metamask/eth-block-tracker';\nimport type { JsonRpcMiddleware } from '@metamask/json-rpc-engine';\nimport { createAsyncMiddleware } from '@metamask/json-rpc-engine';\nimport { hasProperty } from '@metamask/utils';\nimport type {\n Json,\n JsonRpcParams,\n PendingJsonRpcResponse,\n} from '@metamask/utils';\n\nimport { projectLogger, createModuleLogger } from './logging-utils';\n\nconst log = createModuleLogger(projectLogger, 'block-tracker-inspector');\nconst futureBlockRefRequests: readonly string[] = [\n 'eth_getTransactionByHash',\n 'eth_getTransactionReceipt',\n];\n\n/**\n * Creates a middleware that checks whether response block references are higher than the current block.\n * If the block reference is higher, the middleware will make the block tracker check for a new block.\n *\n * @param options - The options for the middleware.\n * @param options.blockTracker - The block tracker to use.\n * @returns The middleware.\n */\nexport function createBlockTrackerInspectorMiddleware({\n blockTracker,\n}: {\n blockTracker: PollingBlockTracker;\n}): JsonRpcMiddleware<JsonRpcParams, Json> {\n return createAsyncMiddleware(async (req, res, next) => {\n if (!futureBlockRefRequests.includes(req.method)) {\n return next();\n }\n await next();\n\n const responseBlockNumber = getResultBlockNumber(res);\n if (!responseBlockNumber) {\n return undefined;\n }\n\n log('res.result.blockNumber exists, proceeding. res = %o', res);\n\n // If number is higher, suggest block-tracker check for a new block\n const blockNumber: number = Number.parseInt(responseBlockNumber, 16);\n const currentBlockNumber: number = Number.parseInt(\n // Typecast: If getCurrentBlock returns null, currentBlockNumber will be NaN, which is fine.\n blockTracker.getCurrentBlock() as string,\n 16,\n );\n if (blockNumber > currentBlockNumber) {\n log(\n 'blockNumber from response is greater than current block number, refreshing current block number',\n );\n await blockTracker.checkForLatestBlock();\n }\n return undefined;\n });\n}\n\nfunction getResultBlockNumber(\n response: PendingJsonRpcResponse,\n): string | undefined {\n const { result } = response;\n if (\n !result ||\n typeof result !== 'object' ||\n !hasProperty(result, 'blockNumber')\n ) {\n return undefined;\n }\n\n if (typeof result.blockNumber === 'string') {\n return result.blockNumber;\n }\n return undefined;\n}\n"]}
@@ -21,6 +21,14 @@ const emptyValues = [
21
21
  null,
22
22
  '\u003cnil\u003e',
23
23
  ];
24
+ /**
25
+ * Creates a middleware that retries requests with empty responses.
26
+ *
27
+ * @param options - The options for the middleware.
28
+ * @param options.provider - The provider to use.
29
+ * @param options.blockTracker - The block tracker to use.
30
+ * @returns The middleware.
31
+ */
24
32
  function createRetryOnEmptyMiddleware({ provider, blockTracker, } = {}) {
25
33
  if (!provider) {
26
34
  throw Error('RetryOnEmptyMiddleware - mandatory "provider" option is missing.');
@@ -81,6 +89,13 @@ function createRetryOnEmptyMiddleware({ provider, blockTracker, } = {}) {
81
89
  });
82
90
  }
83
91
  exports.createRetryOnEmptyMiddleware = createRetryOnEmptyMiddleware;
92
+ /**
93
+ * Retries an asynchronous function up to a maximum number of times.
94
+ *
95
+ * @param maxRetries - The maximum number of retries.
96
+ * @param asyncFn - The asynchronous function to retry.
97
+ * @returns The result of the asynchronous function.
98
+ */
84
99
  async function retry(maxRetries, asyncFn) {
85
100
  for (let index = 0; index < maxRetries; index++) {
86
101
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"retryOnEmpty.cjs","sourceRoot":"","sources":["../src/retryOnEmpty.ts"],"names":[],"mappings":"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","sourcesContent":["import type { PollingBlockTracker } from '@metamask/eth-block-tracker';\nimport type { SafeEventEmitterProvider } from '@metamask/eth-json-rpc-provider';\nimport type { JsonRpcMiddleware } from '@metamask/json-rpc-engine';\nimport { createAsyncMiddleware } from '@metamask/json-rpc-engine';\nimport type { Json, JsonRpcParams } from '@metamask/utils';\nimport { klona } from 'klona/full';\n\nimport { projectLogger, createModuleLogger } from './logging-utils';\nimport type { Block } from './types';\nimport { blockTagParamIndex } from './utils/cache';\nimport { isExecutionRevertedError } from './utils/error';\nimport { timeout } from './utils/timeout';\n\n//\n// RetryOnEmptyMiddleware will retry any request with an empty response that has\n// a numbered block reference at or lower than the blockTracker's latest block.\n// Its useful for dealing with load-balanced ethereum JSON RPC\n// nodes that are not always in sync with each other.\n//\n\nconst log = createModuleLogger(projectLogger, 'retry-on-empty');\n// empty values used to determine if a request should be retried\n// `<nil>` comes from https://github.com/ethereum/go-ethereum/issues/16925\nconst emptyValues: (string | null | undefined)[] = [\n undefined,\n null,\n '\\u003cnil\\u003e',\n];\n\ntype RetryOnEmptyMiddlewareOptions = {\n provider?: SafeEventEmitterProvider;\n blockTracker?: PollingBlockTracker;\n};\n\nexport function createRetryOnEmptyMiddleware({\n provider,\n blockTracker,\n}: RetryOnEmptyMiddlewareOptions = {}): JsonRpcMiddleware<JsonRpcParams, Json> {\n if (!provider) {\n throw Error(\n 'RetryOnEmptyMiddleware - mandatory \"provider\" option is missing.',\n );\n }\n\n if (!blockTracker) {\n throw Error(\n 'RetryOnEmptyMiddleware - mandatory \"blockTracker\" option is missing.',\n );\n }\n\n return createAsyncMiddleware(async (req, res, next) => {\n const blockRefIndex: number | undefined = blockTagParamIndex(req.method);\n // skip if method does not include blockRef\n if (blockRefIndex === undefined) {\n return next();\n }\n // skip if not exact block references\n let blockRef: string | undefined =\n Array.isArray(req.params) && req.params[blockRefIndex]\n ? (req.params[blockRefIndex] as string)\n : undefined;\n // omitted blockRef implies \"latest\"\n if (blockRef === undefined) {\n blockRef = 'latest';\n }\n\n // skip if non-number block reference\n if (['latest', 'pending'].includes(blockRef)) {\n return next();\n }\n // skip if block refernce is not a valid number\n const blockRefNumber: number = Number.parseInt(blockRef.slice(2), 16);\n if (Number.isNaN(blockRefNumber)) {\n return next();\n }\n // lookup latest block\n const latestBlockNumberHex: string = await blockTracker.getLatestBlock();\n const latestBlockNumber: number = Number.parseInt(\n latestBlockNumberHex.slice(2),\n 16,\n );\n // skip if request block number is higher than current\n if (blockRefNumber > latestBlockNumber) {\n log(\n 'Requested block number %o is higher than latest block number %o, falling through to original request',\n blockRefNumber,\n latestBlockNumber,\n );\n return next();\n }\n\n log(\n 'Requested block number %o is not higher than latest block number %o, trying request until non-empty response is received',\n blockRefNumber,\n latestBlockNumber,\n );\n\n // create child request with specific block-ref\n const childRequest = klona(req);\n // attempt child request until non-empty response is received\n const childResult = await retry(10, async () => {\n log('Performing request %o', childRequest);\n const attemptResult = await provider.request<JsonRpcParams, Block>(\n childRequest,\n );\n log('Result is %o', attemptResult);\n // verify result\n const allEmptyValues: unknown[] = emptyValues;\n if (allEmptyValues.includes(attemptResult)) {\n throw new Error(\n `RetryOnEmptyMiddleware - empty result \"${JSON.stringify(\n attemptResult,\n )}\" for request \"${JSON.stringify(childRequest)}\"`,\n );\n }\n return attemptResult;\n });\n log('Copying result %o', childResult);\n // copy child result onto original response\n res.result = childResult;\n return undefined;\n });\n}\n\nasync function retry<Result>(\n maxRetries: number,\n asyncFn: () => Promise<Result>,\n): Promise<Result> {\n for (let index = 0; index < maxRetries; index++) {\n try {\n return await asyncFn();\n } catch (err: unknown) {\n if (isExecutionRevertedError(err)) {\n throw err as unknown;\n }\n log('(call %i) Request failed, waiting 1s to retry again...', index + 1);\n await timeout(1000);\n }\n }\n log('Retries exhausted');\n throw new Error('RetryOnEmptyMiddleware - retries exhausted');\n}\n"]}
1
+ {"version":3,"file":"retryOnEmpty.cjs","sourceRoot":"","sources":["../src/retryOnEmpty.ts"],"names":[],"mappings":"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","sourcesContent":["import type { PollingBlockTracker } from '@metamask/eth-block-tracker';\nimport type { SafeEventEmitterProvider } from '@metamask/eth-json-rpc-provider';\nimport type { JsonRpcMiddleware } from '@metamask/json-rpc-engine';\nimport { createAsyncMiddleware } from '@metamask/json-rpc-engine';\nimport type { Json, JsonRpcParams } from '@metamask/utils';\nimport { klona } from 'klona/full';\n\nimport { projectLogger, createModuleLogger } from './logging-utils';\nimport type { Block } from './types';\nimport { blockTagParamIndex } from './utils/cache';\nimport { isExecutionRevertedError } from './utils/error';\nimport { timeout } from './utils/timeout';\n\n//\n// RetryOnEmptyMiddleware will retry any request with an empty response that has\n// a numbered block reference at or lower than the blockTracker's latest block.\n// Its useful for dealing with load-balanced ethereum JSON RPC\n// nodes that are not always in sync with each other.\n//\n\nconst log = createModuleLogger(projectLogger, 'retry-on-empty');\n// empty values used to determine if a request should be retried\n// `<nil>` comes from https://github.com/ethereum/go-ethereum/issues/16925\nconst emptyValues: (string | null | undefined)[] = [\n undefined,\n null,\n '\\u003cnil\\u003e',\n];\n\n/**\n * Creates a middleware that retries requests with empty responses.\n *\n * @param options - The options for the middleware.\n * @param options.provider - The provider to use.\n * @param options.blockTracker - The block tracker to use.\n * @returns The middleware.\n */\nexport function createRetryOnEmptyMiddleware({\n provider,\n blockTracker,\n}: {\n provider?: SafeEventEmitterProvider;\n blockTracker?: PollingBlockTracker;\n} = {}): JsonRpcMiddleware<JsonRpcParams, Json> {\n if (!provider) {\n throw Error(\n 'RetryOnEmptyMiddleware - mandatory \"provider\" option is missing.',\n );\n }\n\n if (!blockTracker) {\n throw Error(\n 'RetryOnEmptyMiddleware - mandatory \"blockTracker\" option is missing.',\n );\n }\n\n return createAsyncMiddleware(async (req, res, next) => {\n const blockRefIndex: number | undefined = blockTagParamIndex(req.method);\n // skip if method does not include blockRef\n if (blockRefIndex === undefined) {\n return next();\n }\n // skip if not exact block references\n let blockRef: string | undefined =\n Array.isArray(req.params) && req.params[blockRefIndex]\n ? (req.params[blockRefIndex] as string)\n : undefined;\n // omitted blockRef implies \"latest\"\n if (blockRef === undefined) {\n blockRef = 'latest';\n }\n\n // skip if non-number block reference\n if (['latest', 'pending'].includes(blockRef)) {\n return next();\n }\n // skip if block refernce is not a valid number\n const blockRefNumber: number = Number.parseInt(blockRef.slice(2), 16);\n if (Number.isNaN(blockRefNumber)) {\n return next();\n }\n // lookup latest block\n const latestBlockNumberHex: string = await blockTracker.getLatestBlock();\n const latestBlockNumber: number = Number.parseInt(\n latestBlockNumberHex.slice(2),\n 16,\n );\n // skip if request block number is higher than current\n if (blockRefNumber > latestBlockNumber) {\n log(\n 'Requested block number %o is higher than latest block number %o, falling through to original request',\n blockRefNumber,\n latestBlockNumber,\n );\n return next();\n }\n\n log(\n 'Requested block number %o is not higher than latest block number %o, trying request until non-empty response is received',\n blockRefNumber,\n latestBlockNumber,\n );\n\n // create child request with specific block-ref\n const childRequest = klona(req);\n // attempt child request until non-empty response is received\n const childResult = await retry(10, async () => {\n log('Performing request %o', childRequest);\n const attemptResult = await provider.request<JsonRpcParams, Block>(\n childRequest,\n );\n log('Result is %o', attemptResult);\n // verify result\n const allEmptyValues: unknown[] = emptyValues;\n if (allEmptyValues.includes(attemptResult)) {\n throw new Error(\n `RetryOnEmptyMiddleware - empty result \"${JSON.stringify(\n attemptResult,\n )}\" for request \"${JSON.stringify(childRequest)}\"`,\n );\n }\n return attemptResult;\n });\n log('Copying result %o', childResult);\n // copy child result onto original response\n res.result = childResult;\n return undefined;\n });\n}\n\n/**\n * Retries an asynchronous function up to a maximum number of times.\n *\n * @param maxRetries - The maximum number of retries.\n * @param asyncFn - The asynchronous function to retry.\n * @returns The result of the asynchronous function.\n */\nasync function retry<Result>(\n maxRetries: number,\n asyncFn: () => Promise<Result>,\n): Promise<Result> {\n for (let index = 0; index < maxRetries; index++) {\n try {\n return await asyncFn();\n } catch (err: unknown) {\n if (isExecutionRevertedError(err)) {\n throw err as unknown;\n }\n log('(call %i) Request failed, waiting 1s to retry again...', index + 1);\n await timeout(1000);\n }\n }\n log('Retries exhausted');\n throw new Error('RetryOnEmptyMiddleware - retries exhausted');\n}\n"]}
@@ -2,10 +2,16 @@ import type { PollingBlockTracker } from "@metamask/eth-block-tracker";
2
2
  import type { SafeEventEmitterProvider } from "@metamask/eth-json-rpc-provider";
3
3
  import type { JsonRpcMiddleware } from "@metamask/json-rpc-engine";
4
4
  import type { Json, JsonRpcParams } from "@metamask/utils";
5
- type RetryOnEmptyMiddlewareOptions = {
5
+ /**
6
+ * Creates a middleware that retries requests with empty responses.
7
+ *
8
+ * @param options - The options for the middleware.
9
+ * @param options.provider - The provider to use.
10
+ * @param options.blockTracker - The block tracker to use.
11
+ * @returns The middleware.
12
+ */
13
+ export declare function createRetryOnEmptyMiddleware({ provider, blockTracker, }?: {
6
14
  provider?: SafeEventEmitterProvider;
7
15
  blockTracker?: PollingBlockTracker;
8
- };
9
- export declare function createRetryOnEmptyMiddleware({ provider, blockTracker, }?: RetryOnEmptyMiddlewareOptions): JsonRpcMiddleware<JsonRpcParams, Json>;
10
- export {};
16
+ }): JsonRpcMiddleware<JsonRpcParams, Json>;
11
17
  //# sourceMappingURL=retryOnEmpty.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"retryOnEmpty.d.cts","sourceRoot":"","sources":["../src/retryOnEmpty.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,oCAAoC;AACvE,OAAO,KAAK,EAAE,wBAAwB,EAAE,wCAAwC;AAChF,OAAO,KAAK,EAAE,iBAAiB,EAAE,kCAAkC;AAEnE,OAAO,KAAK,EAAE,IAAI,EAAE,aAAa,EAAE,wBAAwB;AAyB3D,KAAK,6BAA6B,GAAG;IACnC,QAAQ,CAAC,EAAE,wBAAwB,CAAC;IACpC,YAAY,CAAC,EAAE,mBAAmB,CAAC;CACpC,CAAC;AAEF,wBAAgB,4BAA4B,CAAC,EAC3C,QAAQ,EACR,YAAY,GACb,GAAE,6BAAkC,GAAG,iBAAiB,CAAC,aAAa,EAAE,IAAI,CAAC,CAqF7E"}
1
+ {"version":3,"file":"retryOnEmpty.d.cts","sourceRoot":"","sources":["../src/retryOnEmpty.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,oCAAoC;AACvE,OAAO,KAAK,EAAE,wBAAwB,EAAE,wCAAwC;AAChF,OAAO,KAAK,EAAE,iBAAiB,EAAE,kCAAkC;AAEnE,OAAO,KAAK,EAAE,IAAI,EAAE,aAAa,EAAE,wBAAwB;AAyB3D;;;;;;;GAOG;AACH,wBAAgB,4BAA4B,CAAC,EAC3C,QAAQ,EACR,YAAY,GACb,GAAE;IACD,QAAQ,CAAC,EAAE,wBAAwB,CAAC;IACpC,YAAY,CAAC,EAAE,mBAAmB,CAAC;CAC/B,GAAG,iBAAiB,CAAC,aAAa,EAAE,IAAI,CAAC,CAqF9C"}
@@ -2,10 +2,16 @@ import type { PollingBlockTracker } from "@metamask/eth-block-tracker";
2
2
  import type { SafeEventEmitterProvider } from "@metamask/eth-json-rpc-provider";
3
3
  import type { JsonRpcMiddleware } from "@metamask/json-rpc-engine";
4
4
  import type { Json, JsonRpcParams } from "@metamask/utils";
5
- type RetryOnEmptyMiddlewareOptions = {
5
+ /**
6
+ * Creates a middleware that retries requests with empty responses.
7
+ *
8
+ * @param options - The options for the middleware.
9
+ * @param options.provider - The provider to use.
10
+ * @param options.blockTracker - The block tracker to use.
11
+ * @returns The middleware.
12
+ */
13
+ export declare function createRetryOnEmptyMiddleware({ provider, blockTracker, }?: {
6
14
  provider?: SafeEventEmitterProvider;
7
15
  blockTracker?: PollingBlockTracker;
8
- };
9
- export declare function createRetryOnEmptyMiddleware({ provider, blockTracker, }?: RetryOnEmptyMiddlewareOptions): JsonRpcMiddleware<JsonRpcParams, Json>;
10
- export {};
16
+ }): JsonRpcMiddleware<JsonRpcParams, Json>;
11
17
  //# sourceMappingURL=retryOnEmpty.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"retryOnEmpty.d.mts","sourceRoot":"","sources":["../src/retryOnEmpty.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,oCAAoC;AACvE,OAAO,KAAK,EAAE,wBAAwB,EAAE,wCAAwC;AAChF,OAAO,KAAK,EAAE,iBAAiB,EAAE,kCAAkC;AAEnE,OAAO,KAAK,EAAE,IAAI,EAAE,aAAa,EAAE,wBAAwB;AAyB3D,KAAK,6BAA6B,GAAG;IACnC,QAAQ,CAAC,EAAE,wBAAwB,CAAC;IACpC,YAAY,CAAC,EAAE,mBAAmB,CAAC;CACpC,CAAC;AAEF,wBAAgB,4BAA4B,CAAC,EAC3C,QAAQ,EACR,YAAY,GACb,GAAE,6BAAkC,GAAG,iBAAiB,CAAC,aAAa,EAAE,IAAI,CAAC,CAqF7E"}
1
+ {"version":3,"file":"retryOnEmpty.d.mts","sourceRoot":"","sources":["../src/retryOnEmpty.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,oCAAoC;AACvE,OAAO,KAAK,EAAE,wBAAwB,EAAE,wCAAwC;AAChF,OAAO,KAAK,EAAE,iBAAiB,EAAE,kCAAkC;AAEnE,OAAO,KAAK,EAAE,IAAI,EAAE,aAAa,EAAE,wBAAwB;AAyB3D;;;;;;;GAOG;AACH,wBAAgB,4BAA4B,CAAC,EAC3C,QAAQ,EACR,YAAY,GACb,GAAE;IACD,QAAQ,CAAC,EAAE,wBAAwB,CAAC;IACpC,YAAY,CAAC,EAAE,mBAAmB,CAAC;CAC/B,GAAG,iBAAiB,CAAC,aAAa,EAAE,IAAI,CAAC,CAqF9C"}
@@ -18,6 +18,14 @@ const emptyValues = [
18
18
  null,
19
19
  '\u003cnil\u003e',
20
20
  ];
21
+ /**
22
+ * Creates a middleware that retries requests with empty responses.
23
+ *
24
+ * @param options - The options for the middleware.
25
+ * @param options.provider - The provider to use.
26
+ * @param options.blockTracker - The block tracker to use.
27
+ * @returns The middleware.
28
+ */
21
29
  export function createRetryOnEmptyMiddleware({ provider, blockTracker, } = {}) {
22
30
  if (!provider) {
23
31
  throw Error('RetryOnEmptyMiddleware - mandatory "provider" option is missing.');
@@ -77,6 +85,13 @@ export function createRetryOnEmptyMiddleware({ provider, blockTracker, } = {}) {
77
85
  return undefined;
78
86
  });
79
87
  }
88
+ /**
89
+ * Retries an asynchronous function up to a maximum number of times.
90
+ *
91
+ * @param maxRetries - The maximum number of retries.
92
+ * @param asyncFn - The asynchronous function to retry.
93
+ * @returns The result of the asynchronous function.
94
+ */
80
95
  async function retry(maxRetries, asyncFn) {
81
96
  for (let index = 0; index < maxRetries; index++) {
82
97
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"retryOnEmpty.mjs","sourceRoot":"","sources":["../src/retryOnEmpty.ts"],"names":[],"mappings":"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","sourcesContent":["import type { PollingBlockTracker } from '@metamask/eth-block-tracker';\nimport type { SafeEventEmitterProvider } from '@metamask/eth-json-rpc-provider';\nimport type { JsonRpcMiddleware } from '@metamask/json-rpc-engine';\nimport { createAsyncMiddleware } from '@metamask/json-rpc-engine';\nimport type { Json, JsonRpcParams } from '@metamask/utils';\nimport { klona } from 'klona/full';\n\nimport { projectLogger, createModuleLogger } from './logging-utils';\nimport type { Block } from './types';\nimport { blockTagParamIndex } from './utils/cache';\nimport { isExecutionRevertedError } from './utils/error';\nimport { timeout } from './utils/timeout';\n\n//\n// RetryOnEmptyMiddleware will retry any request with an empty response that has\n// a numbered block reference at or lower than the blockTracker's latest block.\n// Its useful for dealing with load-balanced ethereum JSON RPC\n// nodes that are not always in sync with each other.\n//\n\nconst log = createModuleLogger(projectLogger, 'retry-on-empty');\n// empty values used to determine if a request should be retried\n// `<nil>` comes from https://github.com/ethereum/go-ethereum/issues/16925\nconst emptyValues: (string | null | undefined)[] = [\n undefined,\n null,\n '\\u003cnil\\u003e',\n];\n\ntype RetryOnEmptyMiddlewareOptions = {\n provider?: SafeEventEmitterProvider;\n blockTracker?: PollingBlockTracker;\n};\n\nexport function createRetryOnEmptyMiddleware({\n provider,\n blockTracker,\n}: RetryOnEmptyMiddlewareOptions = {}): JsonRpcMiddleware<JsonRpcParams, Json> {\n if (!provider) {\n throw Error(\n 'RetryOnEmptyMiddleware - mandatory \"provider\" option is missing.',\n );\n }\n\n if (!blockTracker) {\n throw Error(\n 'RetryOnEmptyMiddleware - mandatory \"blockTracker\" option is missing.',\n );\n }\n\n return createAsyncMiddleware(async (req, res, next) => {\n const blockRefIndex: number | undefined = blockTagParamIndex(req.method);\n // skip if method does not include blockRef\n if (blockRefIndex === undefined) {\n return next();\n }\n // skip if not exact block references\n let blockRef: string | undefined =\n Array.isArray(req.params) && req.params[blockRefIndex]\n ? (req.params[blockRefIndex] as string)\n : undefined;\n // omitted blockRef implies \"latest\"\n if (blockRef === undefined) {\n blockRef = 'latest';\n }\n\n // skip if non-number block reference\n if (['latest', 'pending'].includes(blockRef)) {\n return next();\n }\n // skip if block refernce is not a valid number\n const blockRefNumber: number = Number.parseInt(blockRef.slice(2), 16);\n if (Number.isNaN(blockRefNumber)) {\n return next();\n }\n // lookup latest block\n const latestBlockNumberHex: string = await blockTracker.getLatestBlock();\n const latestBlockNumber: number = Number.parseInt(\n latestBlockNumberHex.slice(2),\n 16,\n );\n // skip if request block number is higher than current\n if (blockRefNumber > latestBlockNumber) {\n log(\n 'Requested block number %o is higher than latest block number %o, falling through to original request',\n blockRefNumber,\n latestBlockNumber,\n );\n return next();\n }\n\n log(\n 'Requested block number %o is not higher than latest block number %o, trying request until non-empty response is received',\n blockRefNumber,\n latestBlockNumber,\n );\n\n // create child request with specific block-ref\n const childRequest = klona(req);\n // attempt child request until non-empty response is received\n const childResult = await retry(10, async () => {\n log('Performing request %o', childRequest);\n const attemptResult = await provider.request<JsonRpcParams, Block>(\n childRequest,\n );\n log('Result is %o', attemptResult);\n // verify result\n const allEmptyValues: unknown[] = emptyValues;\n if (allEmptyValues.includes(attemptResult)) {\n throw new Error(\n `RetryOnEmptyMiddleware - empty result \"${JSON.stringify(\n attemptResult,\n )}\" for request \"${JSON.stringify(childRequest)}\"`,\n );\n }\n return attemptResult;\n });\n log('Copying result %o', childResult);\n // copy child result onto original response\n res.result = childResult;\n return undefined;\n });\n}\n\nasync function retry<Result>(\n maxRetries: number,\n asyncFn: () => Promise<Result>,\n): Promise<Result> {\n for (let index = 0; index < maxRetries; index++) {\n try {\n return await asyncFn();\n } catch (err: unknown) {\n if (isExecutionRevertedError(err)) {\n throw err as unknown;\n }\n log('(call %i) Request failed, waiting 1s to retry again...', index + 1);\n await timeout(1000);\n }\n }\n log('Retries exhausted');\n throw new Error('RetryOnEmptyMiddleware - retries exhausted');\n}\n"]}
1
+ {"version":3,"file":"retryOnEmpty.mjs","sourceRoot":"","sources":["../src/retryOnEmpty.ts"],"names":[],"mappings":"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","sourcesContent":["import type { PollingBlockTracker } from '@metamask/eth-block-tracker';\nimport type { SafeEventEmitterProvider } from '@metamask/eth-json-rpc-provider';\nimport type { JsonRpcMiddleware } from '@metamask/json-rpc-engine';\nimport { createAsyncMiddleware } from '@metamask/json-rpc-engine';\nimport type { Json, JsonRpcParams } from '@metamask/utils';\nimport { klona } from 'klona/full';\n\nimport { projectLogger, createModuleLogger } from './logging-utils';\nimport type { Block } from './types';\nimport { blockTagParamIndex } from './utils/cache';\nimport { isExecutionRevertedError } from './utils/error';\nimport { timeout } from './utils/timeout';\n\n//\n// RetryOnEmptyMiddleware will retry any request with an empty response that has\n// a numbered block reference at or lower than the blockTracker's latest block.\n// Its useful for dealing with load-balanced ethereum JSON RPC\n// nodes that are not always in sync with each other.\n//\n\nconst log = createModuleLogger(projectLogger, 'retry-on-empty');\n// empty values used to determine if a request should be retried\n// `<nil>` comes from https://github.com/ethereum/go-ethereum/issues/16925\nconst emptyValues: (string | null | undefined)[] = [\n undefined,\n null,\n '\\u003cnil\\u003e',\n];\n\n/**\n * Creates a middleware that retries requests with empty responses.\n *\n * @param options - The options for the middleware.\n * @param options.provider - The provider to use.\n * @param options.blockTracker - The block tracker to use.\n * @returns The middleware.\n */\nexport function createRetryOnEmptyMiddleware({\n provider,\n blockTracker,\n}: {\n provider?: SafeEventEmitterProvider;\n blockTracker?: PollingBlockTracker;\n} = {}): JsonRpcMiddleware<JsonRpcParams, Json> {\n if (!provider) {\n throw Error(\n 'RetryOnEmptyMiddleware - mandatory \"provider\" option is missing.',\n );\n }\n\n if (!blockTracker) {\n throw Error(\n 'RetryOnEmptyMiddleware - mandatory \"blockTracker\" option is missing.',\n );\n }\n\n return createAsyncMiddleware(async (req, res, next) => {\n const blockRefIndex: number | undefined = blockTagParamIndex(req.method);\n // skip if method does not include blockRef\n if (blockRefIndex === undefined) {\n return next();\n }\n // skip if not exact block references\n let blockRef: string | undefined =\n Array.isArray(req.params) && req.params[blockRefIndex]\n ? (req.params[blockRefIndex] as string)\n : undefined;\n // omitted blockRef implies \"latest\"\n if (blockRef === undefined) {\n blockRef = 'latest';\n }\n\n // skip if non-number block reference\n if (['latest', 'pending'].includes(blockRef)) {\n return next();\n }\n // skip if block refernce is not a valid number\n const blockRefNumber: number = Number.parseInt(blockRef.slice(2), 16);\n if (Number.isNaN(blockRefNumber)) {\n return next();\n }\n // lookup latest block\n const latestBlockNumberHex: string = await blockTracker.getLatestBlock();\n const latestBlockNumber: number = Number.parseInt(\n latestBlockNumberHex.slice(2),\n 16,\n );\n // skip if request block number is higher than current\n if (blockRefNumber > latestBlockNumber) {\n log(\n 'Requested block number %o is higher than latest block number %o, falling through to original request',\n blockRefNumber,\n latestBlockNumber,\n );\n return next();\n }\n\n log(\n 'Requested block number %o is not higher than latest block number %o, trying request until non-empty response is received',\n blockRefNumber,\n latestBlockNumber,\n );\n\n // create child request with specific block-ref\n const childRequest = klona(req);\n // attempt child request until non-empty response is received\n const childResult = await retry(10, async () => {\n log('Performing request %o', childRequest);\n const attemptResult = await provider.request<JsonRpcParams, Block>(\n childRequest,\n );\n log('Result is %o', attemptResult);\n // verify result\n const allEmptyValues: unknown[] = emptyValues;\n if (allEmptyValues.includes(attemptResult)) {\n throw new Error(\n `RetryOnEmptyMiddleware - empty result \"${JSON.stringify(\n attemptResult,\n )}\" for request \"${JSON.stringify(childRequest)}\"`,\n );\n }\n return attemptResult;\n });\n log('Copying result %o', childResult);\n // copy child result onto original response\n res.result = childResult;\n return undefined;\n });\n}\n\n/**\n * Retries an asynchronous function up to a maximum number of times.\n *\n * @param maxRetries - The maximum number of retries.\n * @param asyncFn - The asynchronous function to retry.\n * @returns The result of the asynchronous function.\n */\nasync function retry<Result>(\n maxRetries: number,\n asyncFn: () => Promise<Result>,\n): Promise<Result> {\n for (let index = 0; index < maxRetries; index++) {\n try {\n return await asyncFn();\n } catch (err: unknown) {\n if (isExecutionRevertedError(err)) {\n throw err as unknown;\n }\n log('(call %i) Request failed, waiting 1s to retry again...', index + 1);\n await timeout(1000);\n }\n }\n log('Retries exhausted');\n throw new Error('RetryOnEmptyMiddleware - retries exhausted');\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metamask-previews/eth-json-rpc-middleware",
3
- "version": "21.0.0-preview-e98a6769",
3
+ "version": "21.0.0-preview-772b5970",
4
4
  "description": "Ethereum-related json-rpc-engine middleware",
5
5
  "keywords": [
6
6
  "MetaMask",