@metamask-previews/json-rpc-engine 10.1.1-preview-317c0a9f → 10.1.1-preview-c96ff8f
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.
- package/CHANGELOG.md +2 -3
- package/README.md +27 -0
- package/dist/asV2Middleware.cjs +8 -3
- package/dist/asV2Middleware.cjs.map +1 -1
- package/dist/asV2Middleware.d.cts +1 -1
- package/dist/asV2Middleware.d.cts.map +1 -1
- package/dist/asV2Middleware.d.mts +1 -1
- package/dist/asV2Middleware.d.mts.map +1 -1
- package/dist/asV2Middleware.mjs +9 -4
- package/dist/asV2Middleware.mjs.map +1 -1
- package/dist/v2/JsonRpcEngineV2.cjs +5 -2
- package/dist/v2/JsonRpcEngineV2.cjs.map +1 -1
- package/dist/v2/JsonRpcEngineV2.d.cts +18 -5
- package/dist/v2/JsonRpcEngineV2.d.cts.map +1 -1
- package/dist/v2/JsonRpcEngineV2.d.mts +18 -5
- package/dist/v2/JsonRpcEngineV2.d.mts.map +1 -1
- package/dist/v2/JsonRpcEngineV2.mjs +5 -2
- package/dist/v2/JsonRpcEngineV2.mjs.map +1 -1
- package/dist/v2/JsonRpcServer.cjs +5 -6
- package/dist/v2/JsonRpcServer.cjs.map +1 -1
- package/dist/v2/JsonRpcServer.d.cts +12 -6
- package/dist/v2/JsonRpcServer.d.cts.map +1 -1
- package/dist/v2/JsonRpcServer.d.mts +12 -6
- package/dist/v2/JsonRpcServer.d.mts.map +1 -1
- package/dist/v2/JsonRpcServer.mjs +5 -6
- package/dist/v2/JsonRpcServer.mjs.map +1 -1
- package/dist/v2/MiddlewareContext.cjs +42 -1
- package/dist/v2/MiddlewareContext.cjs.map +1 -1
- package/dist/v2/MiddlewareContext.d.cts +15 -2
- package/dist/v2/MiddlewareContext.d.cts.map +1 -1
- package/dist/v2/MiddlewareContext.d.mts +15 -2
- package/dist/v2/MiddlewareContext.d.mts.map +1 -1
- package/dist/v2/MiddlewareContext.mjs +42 -1
- package/dist/v2/MiddlewareContext.mjs.map +1 -1
- package/dist/v2/compatibility-utils.cjs +3 -3
- package/dist/v2/compatibility-utils.cjs.map +1 -1
- package/dist/v2/compatibility-utils.d.cts +1 -1
- package/dist/v2/compatibility-utils.d.mts +1 -1
- package/dist/v2/compatibility-utils.mjs +1 -1
- package/dist/v2/compatibility-utils.mjs.map +1 -1
- package/dist/v2/createScaffoldMiddleware.cjs.map +1 -1
- package/dist/v2/createScaffoldMiddleware.d.cts +12 -3
- package/dist/v2/createScaffoldMiddleware.d.cts.map +1 -1
- package/dist/v2/createScaffoldMiddleware.d.mts +12 -3
- package/dist/v2/createScaffoldMiddleware.d.mts.map +1 -1
- package/dist/v2/createScaffoldMiddleware.mjs.map +1 -1
- package/dist/v2/index.cjs.map +1 -1
- package/dist/v2/index.d.cts +2 -2
- package/dist/v2/index.d.cts.map +1 -1
- package/dist/v2/index.d.mts +2 -2
- package/dist/v2/index.d.mts.map +1 -1
- package/dist/v2/index.mjs.map +1 -1
- package/dist/v2/utils.cjs +2 -2
- package/dist/v2/utils.cjs.map +1 -1
- package/dist/v2/utils.d.cts.map +1 -1
- package/dist/v2/utils.d.mts.map +1 -1
- package/dist/v2/utils.mjs +2 -2
- package/dist/v2/utils.mjs.map +1 -1
- package/package.json +3 -1
package/CHANGELOG.md
CHANGED
|
@@ -9,9 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
9
9
|
|
|
10
10
|
### Added
|
|
11
11
|
|
|
12
|
-
- `JsonRpcEngineV2` ([#6176](https://github.com/MetaMask/core/pull/6176), [#6971](https://github.com/MetaMask/core/pull/6971), [#6975](https://github.com/MetaMask/core/pull/6975), [#6990](https://github.com/MetaMask/core/pull/6990), [#6991](https://github.com/MetaMask/core/pull/6991), [#7032](https://github.com/MetaMask/core/pull/7032))
|
|
13
|
-
- This is a complete rewrite of `JsonRpcEngine`, intended to replace the original implementation.
|
|
14
|
-
See the readme for details.
|
|
12
|
+
- Add `JsonRpcEngineV2` ([#6176](https://github.com/MetaMask/core/pull/6176), [#6971](https://github.com/MetaMask/core/pull/6971), [#6975](https://github.com/MetaMask/core/pull/6975), [#6990](https://github.com/MetaMask/core/pull/6990), [#6991](https://github.com/MetaMask/core/pull/6991), [#7032](https://github.com/MetaMask/core/pull/7032), [#7001](https://github.com/MetaMask/core/pull/7001), [#7061](https://github.com/MetaMask/core/pull/7061))
|
|
13
|
+
- This is a complete rewrite of `JsonRpcEngine`, intended to replace the original implementation. See the readme for details.
|
|
15
14
|
|
|
16
15
|
## [10.1.1]
|
|
17
16
|
|
package/README.md
CHANGED
|
@@ -444,6 +444,33 @@ const engine = JsonRpcEngineV2.create({
|
|
|
444
444
|
});
|
|
445
445
|
```
|
|
446
446
|
|
|
447
|
+
#### Passing the context to `handle()`
|
|
448
|
+
|
|
449
|
+
You can pass a `MiddlewareContext` instance directly to `handle()`:
|
|
450
|
+
|
|
451
|
+
```ts
|
|
452
|
+
const context = new MiddlewareContext();
|
|
453
|
+
context.set('foo', 'bar');
|
|
454
|
+
const result = await engine.handle(
|
|
455
|
+
{ id: '1', jsonrpc: '2.0', method: 'hello' },
|
|
456
|
+
{ context },
|
|
457
|
+
);
|
|
458
|
+
console.log(result); // 'bar'
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
You can also pass a plain object as a shorthand for a `MiddlewareContext` instance:
|
|
462
|
+
|
|
463
|
+
```ts
|
|
464
|
+
const context = { foo: 'bar' };
|
|
465
|
+
const result = await engine.handle(
|
|
466
|
+
{ id: '1', jsonrpc: '2.0', method: 'hello' },
|
|
467
|
+
{ context },
|
|
468
|
+
);
|
|
469
|
+
console.log(result); // 'bar'
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
This works the same way for `JsonRpcServer.handle()`.
|
|
473
|
+
|
|
447
474
|
#### Constraining context keys and values
|
|
448
475
|
|
|
449
476
|
The context exposes a generic parameter `KeyValues`, which determines the keys and values
|
package/dist/asV2Middleware.cjs
CHANGED
|
@@ -14,7 +14,9 @@ const compatibility_utils_1 = require("./v2/compatibility-utils.cjs");
|
|
|
14
14
|
*/
|
|
15
15
|
function asV2Middleware(engineOrMiddleware, ...rest) {
|
|
16
16
|
const legacyMiddleware = typeof engineOrMiddleware === 'function'
|
|
17
|
-
?
|
|
17
|
+
? // mergeMiddleware uses .asMiddleware() internally, which is necessary for our purposes.
|
|
18
|
+
// See comment on this below.
|
|
19
|
+
(0, mergeMiddleware_1.mergeMiddleware)([engineOrMiddleware, ...rest])
|
|
18
20
|
: engineOrMiddleware.asMiddleware();
|
|
19
21
|
return async ({ request, context, next }) => {
|
|
20
22
|
const req = (0, compatibility_utils_1.deepClone)(request);
|
|
@@ -39,8 +41,11 @@ function asV2Middleware(engineOrMiddleware, ...rest) {
|
|
|
39
41
|
legacyMiddleware(req, res, legacyNext, end);
|
|
40
42
|
});
|
|
41
43
|
(0, compatibility_utils_1.propagateToContext)(req, context);
|
|
42
|
-
|
|
43
|
-
|
|
44
|
+
// Mimic the behavior of JsonRpcEngine.#handle(), which only treats truthy errors as errors.
|
|
45
|
+
// Legacy middleware may violate the invariant that response objects have either a result or an
|
|
46
|
+
// error property. In practice, we may see response objects with results and `{ error: undefined }`.
|
|
47
|
+
if ((0, utils_1.hasProperty)(response, 'error') && response.error) {
|
|
48
|
+
throw (0, compatibility_utils_1.deserializeError)(response.error);
|
|
44
49
|
}
|
|
45
50
|
else if ((0, utils_1.hasProperty)(response, 'result')) {
|
|
46
51
|
return response.result;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"asV2Middleware.cjs","sourceRoot":"","sources":["../src/asV2Middleware.ts"],"names":[],"mappings":";;;AAAA,qDAAsD;AAEtD,2CAKyB;AAQzB,2DAAoD;AACpD,sEAMkC;
|
|
1
|
+
{"version":3,"file":"asV2Middleware.cjs","sourceRoot":"","sources":["../src/asV2Middleware.ts"],"names":[],"mappings":";;;AAAA,qDAAsD;AAEtD,2CAKyB;AAQzB,2DAAoD;AACpD,sEAMkC;AAkClC;;;;;;GAMG;AACH,SAAgB,cAAc,CAI5B,kBAAyE,EACzE,GAAG,IAA6C;IAEhD,MAAM,gBAAgB,GACpB,OAAO,kBAAkB,KAAK,UAAU;QACtC,CAAC,CAAC,wFAAwF;YACxF,6BAA6B;YAC7B,IAAA,iCAAe,EAAC,CAAC,kBAAkB,EAAE,GAAG,IAAI,CAAC,CAAC;QAChD,CAAC,CAAC,kBAAkB,CAAC,YAAY,EAAE,CAAC;IAExC,OAAO,KAAK,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE;QAC1C,MAAM,GAAG,GAAG,IAAA,+BAAS,EAAC,OAAO,CAA2B,CAAC;QACzD,IAAA,wCAAkB,EAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QAEjC,MAAM,QAAQ,GAAG,MAAM,IAAI,OAAO,CAAkB,CAAC,OAAO,EAAE,EAAE;YAC9D,gEAAgE;YAChE,cAAc;YACd,MAAM,GAAG,GAAG;gBACV,OAAO,EAAE,KAAc;gBACvB,EAAE,EAAE,GAAG,CAAC,EAAE;aACQ,CAAC;YAErB,MAAM,GAAG,GAA6B,CAAC,KAAK,EAAE,EAAE;gBAC9C,IAAI,KAAK,KAAK,SAAS,EAAE;oBACtB,GAAsB,CAAC,KAAK,GAAG,IAAA,2BAAc,EAAC,KAAK,CAAC,CAAC;iBACvD;gBACD,OAAO,CAAC,GAAG,CAAC,CAAC;YACf,CAAC,CAAC;YAEF,uEAAuE;YACvE,kEAAkE;YAClE,aAAa;YACb,MAAM,UAAU,GAAG,CAAC,CAAC,EAA4B,EAAE,EAAE,CACnD,EAAE,CAAC,GAAG,CAAC,CAA8B,CAAC;YAExC,gBAAgB,CAAC,GAAG,EAAE,GAAG,EAAE,UAAU,EAAE,GAAG,CAAC,CAAC;QAC9C,CAAC,CAAC,CAAC;QACH,IAAA,wCAAkB,EAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QAEjC,4FAA4F;QAC5F,+FAA+F;QAC/F,oGAAoG;QACpG,IAAI,IAAA,mBAAW,EAAC,QAAQ,EAAE,OAAO,CAAC,IAAI,QAAQ,CAAC,KAAK,EAAE;YACpD,MAAM,IAAA,sCAAgB,EAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;SACxC;aAAM,IAAI,IAAA,mBAAW,EAAC,QAAQ,EAAE,QAAQ,CAAC,EAAE;YAC1C,OAAO,QAAQ,CAAC,MAAmC,CAAC;SACrD;QACD,OAAO,IAAI,CAAC,IAAA,uCAAiB,EAAC,GAAc,CAAC,CAAC,CAAC;IACjD,CAAC,CAAC;AACJ,CAAC;AArDD,wCAqDC","sourcesContent":["import { serializeError } from '@metamask/rpc-errors';\nimport type { JsonRpcFailure, JsonRpcResponse } from '@metamask/utils';\nimport {\n hasProperty,\n type Json,\n type JsonRpcParams,\n type JsonRpcRequest,\n} from '@metamask/utils';\n\nimport type {\n JsonRpcEngine,\n JsonRpcEngineEndCallback,\n JsonRpcEngineNextCallback,\n} from './JsonRpcEngine';\nimport { type JsonRpcMiddleware as LegacyMiddleware } from './JsonRpcEngine';\nimport { mergeMiddleware } from './mergeMiddleware';\nimport {\n deepClone,\n fromLegacyRequest,\n propagateToContext,\n propagateToRequest,\n deserializeError,\n} from './v2/compatibility-utils';\nimport type {\n // Used in docs.\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n JsonRpcEngineV2,\n JsonRpcMiddleware,\n ResultConstraint,\n} from './v2/JsonRpcEngineV2';\n\n/**\n * Convert a legacy {@link JsonRpcEngine} into a {@link JsonRpcEngineV2} middleware.\n *\n * @param engine - The legacy engine to convert.\n * @returns The {@link JsonRpcEngineV2} middleware.\n */\nexport function asV2Middleware<\n Params extends JsonRpcParams,\n Request extends JsonRpcRequest<Params>,\n>(engine: JsonRpcEngine): JsonRpcMiddleware<Request>;\n\n/**\n * Convert one or more legacy middleware into a {@link JsonRpcEngineV2} middleware.\n *\n * @param middleware - The legacy middleware to convert.\n * @returns The {@link JsonRpcEngineV2} middleware.\n */\nexport function asV2Middleware<\n Params extends JsonRpcParams,\n Request extends JsonRpcRequest<Params>,\n Result extends Json,\n>(\n ...middleware: LegacyMiddleware<Params, Result>[]\n): JsonRpcMiddleware<Request>;\n\n/**\n * The asV2Middleware implementation.\n *\n * @param engineOrMiddleware - A legacy engine or legacy middleware.\n * @param rest - Any additional legacy middleware when the first argument is a middleware.\n * @returns The {@link JsonRpcEngineV2} middleware.\n */\nexport function asV2Middleware<\n Params extends JsonRpcParams,\n Request extends JsonRpcRequest<Params>,\n>(\n engineOrMiddleware: JsonRpcEngine | LegacyMiddleware<JsonRpcParams, Json>,\n ...rest: LegacyMiddleware<JsonRpcParams, Json>[]\n): JsonRpcMiddleware<Request> {\n const legacyMiddleware =\n typeof engineOrMiddleware === 'function'\n ? // mergeMiddleware uses .asMiddleware() internally, which is necessary for our purposes.\n // See comment on this below.\n mergeMiddleware([engineOrMiddleware, ...rest])\n : engineOrMiddleware.asMiddleware();\n\n return async ({ request, context, next }) => {\n const req = deepClone(request) as JsonRpcRequest<Params>;\n propagateToRequest(req, context);\n\n const response = await new Promise<JsonRpcResponse>((resolve) => {\n // The result or error property will be set by the legacy engine\n // middleware.\n const res = {\n jsonrpc: '2.0' as const,\n id: req.id,\n } as JsonRpcResponse;\n\n const end: JsonRpcEngineEndCallback = (error) => {\n if (error !== undefined) {\n (res as JsonRpcFailure).error = serializeError(error);\n }\n resolve(res);\n };\n\n // We know from the implementation of JsonRpcEngine.asMiddleware() that\n // legacyNext will always be passed a callback, so cb can never be\n // undefined.\n const legacyNext = ((cb: JsonRpcEngineEndCallback) =>\n cb(end)) as JsonRpcEngineNextCallback;\n\n legacyMiddleware(req, res, legacyNext, end);\n });\n propagateToContext(req, context);\n\n // Mimic the behavior of JsonRpcEngine.#handle(), which only treats truthy errors as errors.\n // Legacy middleware may violate the invariant that response objects have either a result or an\n // error property. In practice, we may see response objects with results and `{ error: undefined }`.\n if (hasProperty(response, 'error') && response.error) {\n throw deserializeError(response.error);\n } else if (hasProperty(response, 'result')) {\n return response.result as ResultConstraint<Request>;\n }\n return next(fromLegacyRequest(req as Request));\n };\n}\n"]}
|
|
@@ -15,5 +15,5 @@ export declare function asV2Middleware<Params extends JsonRpcParams, Request ext
|
|
|
15
15
|
* @param middleware - The legacy middleware to convert.
|
|
16
16
|
* @returns The {@link JsonRpcEngineV2} middleware.
|
|
17
17
|
*/
|
|
18
|
-
export declare function asV2Middleware<Params extends JsonRpcParams, Request extends JsonRpcRequest<Params
|
|
18
|
+
export declare function asV2Middleware<Params extends JsonRpcParams, Request extends JsonRpcRequest<Params>, Result extends Json>(...middleware: LegacyMiddleware<Params, Result>[]): JsonRpcMiddleware<Request>;
|
|
19
19
|
//# sourceMappingURL=asV2Middleware.d.cts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"asV2Middleware.d.cts","sourceRoot":"","sources":["../src/asV2Middleware.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,IAAI,EACT,KAAK,aAAa,EAClB,KAAK,cAAc,EACpB,wBAAwB;AAEzB,OAAO,KAAK,EACV,aAAa,EAGd,4BAAwB;AACzB,OAAO,EAAE,KAAK,iBAAiB,IAAI,gBAAgB,EAAE,4BAAwB;AAS7E,OAAO,KAAK,EAIV,iBAAiB,EAElB,iCAA6B;AAE9B;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,MAAM,SAAS,aAAa,EAC5B,OAAO,SAAS,cAAc,CAAC,MAAM,CAAC,EACtC,MAAM,EAAE,aAAa,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;AAErD;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,MAAM,SAAS,aAAa,EAC5B,OAAO,SAAS,cAAc,CAAC,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"asV2Middleware.d.cts","sourceRoot":"","sources":["../src/asV2Middleware.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,IAAI,EACT,KAAK,aAAa,EAClB,KAAK,cAAc,EACpB,wBAAwB;AAEzB,OAAO,KAAK,EACV,aAAa,EAGd,4BAAwB;AACzB,OAAO,EAAE,KAAK,iBAAiB,IAAI,gBAAgB,EAAE,4BAAwB;AAS7E,OAAO,KAAK,EAIV,iBAAiB,EAElB,iCAA6B;AAE9B;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,MAAM,SAAS,aAAa,EAC5B,OAAO,SAAS,cAAc,CAAC,MAAM,CAAC,EACtC,MAAM,EAAE,aAAa,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;AAErD;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,MAAM,SAAS,aAAa,EAC5B,OAAO,SAAS,cAAc,CAAC,MAAM,CAAC,EACtC,MAAM,SAAS,IAAI,EAEnB,GAAG,UAAU,EAAE,gBAAgB,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,GAChD,iBAAiB,CAAC,OAAO,CAAC,CAAC"}
|
|
@@ -15,5 +15,5 @@ export declare function asV2Middleware<Params extends JsonRpcParams, Request ext
|
|
|
15
15
|
* @param middleware - The legacy middleware to convert.
|
|
16
16
|
* @returns The {@link JsonRpcEngineV2} middleware.
|
|
17
17
|
*/
|
|
18
|
-
export declare function asV2Middleware<Params extends JsonRpcParams, Request extends JsonRpcRequest<Params
|
|
18
|
+
export declare function asV2Middleware<Params extends JsonRpcParams, Request extends JsonRpcRequest<Params>, Result extends Json>(...middleware: LegacyMiddleware<Params, Result>[]): JsonRpcMiddleware<Request>;
|
|
19
19
|
//# sourceMappingURL=asV2Middleware.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"asV2Middleware.d.mts","sourceRoot":"","sources":["../src/asV2Middleware.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,IAAI,EACT,KAAK,aAAa,EAClB,KAAK,cAAc,EACpB,wBAAwB;AAEzB,OAAO,KAAK,EACV,aAAa,EAGd,4BAAwB;AACzB,OAAO,EAAE,KAAK,iBAAiB,IAAI,gBAAgB,EAAE,4BAAwB;AAS7E,OAAO,KAAK,EAIV,iBAAiB,EAElB,iCAA6B;AAE9B;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,MAAM,SAAS,aAAa,EAC5B,OAAO,SAAS,cAAc,CAAC,MAAM,CAAC,EACtC,MAAM,EAAE,aAAa,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;AAErD;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,MAAM,SAAS,aAAa,EAC5B,OAAO,SAAS,cAAc,CAAC,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"asV2Middleware.d.mts","sourceRoot":"","sources":["../src/asV2Middleware.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,IAAI,EACT,KAAK,aAAa,EAClB,KAAK,cAAc,EACpB,wBAAwB;AAEzB,OAAO,KAAK,EACV,aAAa,EAGd,4BAAwB;AACzB,OAAO,EAAE,KAAK,iBAAiB,IAAI,gBAAgB,EAAE,4BAAwB;AAS7E,OAAO,KAAK,EAIV,iBAAiB,EAElB,iCAA6B;AAE9B;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,MAAM,SAAS,aAAa,EAC5B,OAAO,SAAS,cAAc,CAAC,MAAM,CAAC,EACtC,MAAM,EAAE,aAAa,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;AAErD;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,MAAM,SAAS,aAAa,EAC5B,OAAO,SAAS,cAAc,CAAC,MAAM,CAAC,EACtC,MAAM,SAAS,IAAI,EAEnB,GAAG,UAAU,EAAE,gBAAgB,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,GAChD,iBAAiB,CAAC,OAAO,CAAC,CAAC"}
|
package/dist/asV2Middleware.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { serializeError } from "@metamask/rpc-errors";
|
|
2
2
|
import { hasProperty } from "@metamask/utils";
|
|
3
3
|
import { mergeMiddleware } from "./mergeMiddleware.mjs";
|
|
4
|
-
import { deepClone, fromLegacyRequest, propagateToContext, propagateToRequest,
|
|
4
|
+
import { deepClone, fromLegacyRequest, propagateToContext, propagateToRequest, deserializeError } from "./v2/compatibility-utils.mjs";
|
|
5
5
|
/**
|
|
6
6
|
* The asV2Middleware implementation.
|
|
7
7
|
*
|
|
@@ -11,7 +11,9 @@ import { deepClone, fromLegacyRequest, propagateToContext, propagateToRequest, u
|
|
|
11
11
|
*/
|
|
12
12
|
export function asV2Middleware(engineOrMiddleware, ...rest) {
|
|
13
13
|
const legacyMiddleware = typeof engineOrMiddleware === 'function'
|
|
14
|
-
? mergeMiddleware(
|
|
14
|
+
? // mergeMiddleware uses .asMiddleware() internally, which is necessary for our purposes.
|
|
15
|
+
// See comment on this below.
|
|
16
|
+
mergeMiddleware([engineOrMiddleware, ...rest])
|
|
15
17
|
: engineOrMiddleware.asMiddleware();
|
|
16
18
|
return async ({ request, context, next }) => {
|
|
17
19
|
const req = deepClone(request);
|
|
@@ -36,8 +38,11 @@ export function asV2Middleware(engineOrMiddleware, ...rest) {
|
|
|
36
38
|
legacyMiddleware(req, res, legacyNext, end);
|
|
37
39
|
});
|
|
38
40
|
propagateToContext(req, context);
|
|
39
|
-
|
|
40
|
-
|
|
41
|
+
// Mimic the behavior of JsonRpcEngine.#handle(), which only treats truthy errors as errors.
|
|
42
|
+
// Legacy middleware may violate the invariant that response objects have either a result or an
|
|
43
|
+
// error property. In practice, we may see response objects with results and `{ error: undefined }`.
|
|
44
|
+
if (hasProperty(response, 'error') && response.error) {
|
|
45
|
+
throw deserializeError(response.error);
|
|
41
46
|
}
|
|
42
47
|
else if (hasProperty(response, 'result')) {
|
|
43
48
|
return response.result;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"asV2Middleware.mjs","sourceRoot":"","sources":["../src/asV2Middleware.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,6BAA6B;AAEtD,OAAO,EACL,WAAW,EAIZ,wBAAwB;AAQzB,OAAO,EAAE,eAAe,EAAE,8BAA0B;AACpD,OAAO,EACL,SAAS,EACT,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,EACjB,qCAAiC;
|
|
1
|
+
{"version":3,"file":"asV2Middleware.mjs","sourceRoot":"","sources":["../src/asV2Middleware.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,6BAA6B;AAEtD,OAAO,EACL,WAAW,EAIZ,wBAAwB;AAQzB,OAAO,EAAE,eAAe,EAAE,8BAA0B;AACpD,OAAO,EACL,SAAS,EACT,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,EACjB,qCAAiC;AAkClC;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAI5B,kBAAyE,EACzE,GAAG,IAA6C;IAEhD,MAAM,gBAAgB,GACpB,OAAO,kBAAkB,KAAK,UAAU;QACtC,CAAC,CAAC,wFAAwF;YACxF,6BAA6B;YAC7B,eAAe,CAAC,CAAC,kBAAkB,EAAE,GAAG,IAAI,CAAC,CAAC;QAChD,CAAC,CAAC,kBAAkB,CAAC,YAAY,EAAE,CAAC;IAExC,OAAO,KAAK,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE;QAC1C,MAAM,GAAG,GAAG,SAAS,CAAC,OAAO,CAA2B,CAAC;QACzD,kBAAkB,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QAEjC,MAAM,QAAQ,GAAG,MAAM,IAAI,OAAO,CAAkB,CAAC,OAAO,EAAE,EAAE;YAC9D,gEAAgE;YAChE,cAAc;YACd,MAAM,GAAG,GAAG;gBACV,OAAO,EAAE,KAAc;gBACvB,EAAE,EAAE,GAAG,CAAC,EAAE;aACQ,CAAC;YAErB,MAAM,GAAG,GAA6B,CAAC,KAAK,EAAE,EAAE;gBAC9C,IAAI,KAAK,KAAK,SAAS,EAAE;oBACtB,GAAsB,CAAC,KAAK,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;iBACvD;gBACD,OAAO,CAAC,GAAG,CAAC,CAAC;YACf,CAAC,CAAC;YAEF,uEAAuE;YACvE,kEAAkE;YAClE,aAAa;YACb,MAAM,UAAU,GAAG,CAAC,CAAC,EAA4B,EAAE,EAAE,CACnD,EAAE,CAAC,GAAG,CAAC,CAA8B,CAAC;YAExC,gBAAgB,CAAC,GAAG,EAAE,GAAG,EAAE,UAAU,EAAE,GAAG,CAAC,CAAC;QAC9C,CAAC,CAAC,CAAC;QACH,kBAAkB,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QAEjC,4FAA4F;QAC5F,+FAA+F;QAC/F,oGAAoG;QACpG,IAAI,WAAW,CAAC,QAAQ,EAAE,OAAO,CAAC,IAAI,QAAQ,CAAC,KAAK,EAAE;YACpD,MAAM,gBAAgB,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;SACxC;aAAM,IAAI,WAAW,CAAC,QAAQ,EAAE,QAAQ,CAAC,EAAE;YAC1C,OAAO,QAAQ,CAAC,MAAmC,CAAC;SACrD;QACD,OAAO,IAAI,CAAC,iBAAiB,CAAC,GAAc,CAAC,CAAC,CAAC;IACjD,CAAC,CAAC;AACJ,CAAC","sourcesContent":["import { serializeError } from '@metamask/rpc-errors';\nimport type { JsonRpcFailure, JsonRpcResponse } from '@metamask/utils';\nimport {\n hasProperty,\n type Json,\n type JsonRpcParams,\n type JsonRpcRequest,\n} from '@metamask/utils';\n\nimport type {\n JsonRpcEngine,\n JsonRpcEngineEndCallback,\n JsonRpcEngineNextCallback,\n} from './JsonRpcEngine';\nimport { type JsonRpcMiddleware as LegacyMiddleware } from './JsonRpcEngine';\nimport { mergeMiddleware } from './mergeMiddleware';\nimport {\n deepClone,\n fromLegacyRequest,\n propagateToContext,\n propagateToRequest,\n deserializeError,\n} from './v2/compatibility-utils';\nimport type {\n // Used in docs.\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n JsonRpcEngineV2,\n JsonRpcMiddleware,\n ResultConstraint,\n} from './v2/JsonRpcEngineV2';\n\n/**\n * Convert a legacy {@link JsonRpcEngine} into a {@link JsonRpcEngineV2} middleware.\n *\n * @param engine - The legacy engine to convert.\n * @returns The {@link JsonRpcEngineV2} middleware.\n */\nexport function asV2Middleware<\n Params extends JsonRpcParams,\n Request extends JsonRpcRequest<Params>,\n>(engine: JsonRpcEngine): JsonRpcMiddleware<Request>;\n\n/**\n * Convert one or more legacy middleware into a {@link JsonRpcEngineV2} middleware.\n *\n * @param middleware - The legacy middleware to convert.\n * @returns The {@link JsonRpcEngineV2} middleware.\n */\nexport function asV2Middleware<\n Params extends JsonRpcParams,\n Request extends JsonRpcRequest<Params>,\n Result extends Json,\n>(\n ...middleware: LegacyMiddleware<Params, Result>[]\n): JsonRpcMiddleware<Request>;\n\n/**\n * The asV2Middleware implementation.\n *\n * @param engineOrMiddleware - A legacy engine or legacy middleware.\n * @param rest - Any additional legacy middleware when the first argument is a middleware.\n * @returns The {@link JsonRpcEngineV2} middleware.\n */\nexport function asV2Middleware<\n Params extends JsonRpcParams,\n Request extends JsonRpcRequest<Params>,\n>(\n engineOrMiddleware: JsonRpcEngine | LegacyMiddleware<JsonRpcParams, Json>,\n ...rest: LegacyMiddleware<JsonRpcParams, Json>[]\n): JsonRpcMiddleware<Request> {\n const legacyMiddleware =\n typeof engineOrMiddleware === 'function'\n ? // mergeMiddleware uses .asMiddleware() internally, which is necessary for our purposes.\n // See comment on this below.\n mergeMiddleware([engineOrMiddleware, ...rest])\n : engineOrMiddleware.asMiddleware();\n\n return async ({ request, context, next }) => {\n const req = deepClone(request) as JsonRpcRequest<Params>;\n propagateToRequest(req, context);\n\n const response = await new Promise<JsonRpcResponse>((resolve) => {\n // The result or error property will be set by the legacy engine\n // middleware.\n const res = {\n jsonrpc: '2.0' as const,\n id: req.id,\n } as JsonRpcResponse;\n\n const end: JsonRpcEngineEndCallback = (error) => {\n if (error !== undefined) {\n (res as JsonRpcFailure).error = serializeError(error);\n }\n resolve(res);\n };\n\n // We know from the implementation of JsonRpcEngine.asMiddleware() that\n // legacyNext will always be passed a callback, so cb can never be\n // undefined.\n const legacyNext = ((cb: JsonRpcEngineEndCallback) =>\n cb(end)) as JsonRpcEngineNextCallback;\n\n legacyMiddleware(req, res, legacyNext, end);\n });\n propagateToContext(req, context);\n\n // Mimic the behavior of JsonRpcEngine.#handle(), which only treats truthy errors as errors.\n // Legacy middleware may violate the invariant that response objects have either a result or an\n // error property. In practice, we may see response objects with results and `{ error: undefined }`.\n if (hasProperty(response, 'error') && response.error) {\n throw deserializeError(response.error);\n } else if (hasProperty(response, 'result')) {\n return response.result as ResultConstraint<Request>;\n }\n return next(fromLegacyRequest(req as Request));\n };\n}\n"]}
|
|
@@ -134,10 +134,10 @@ _JsonRpcEngineV2_middleware = new WeakMap(), _JsonRpcEngineV2_isDestroyed = new
|
|
|
134
134
|
* operation. Permits returning an `undefined` result.
|
|
135
135
|
*
|
|
136
136
|
* @param originalRequest - The JSON-RPC request to handle.
|
|
137
|
-
* @param
|
|
137
|
+
* @param rawContext - The context to pass to the middleware.
|
|
138
138
|
* @returns The result from the middleware.
|
|
139
139
|
*/
|
|
140
|
-
async function _JsonRpcEngineV2_handle(originalRequest,
|
|
140
|
+
async function _JsonRpcEngineV2_handle(originalRequest, rawContext = new MiddlewareContext_1.MiddlewareContext()) {
|
|
141
141
|
__classPrivateFieldGet(this, _JsonRpcEngineV2_instances, "m", _JsonRpcEngineV2_assertIsNotDestroyed).call(this);
|
|
142
142
|
(0, deep_freeze_strict_1.default)(originalRequest);
|
|
143
143
|
const state = {
|
|
@@ -146,6 +146,9 @@ async function _JsonRpcEngineV2_handle(originalRequest, context = new Middleware
|
|
|
146
146
|
};
|
|
147
147
|
const middlewareIterator = __classPrivateFieldGet(this, _JsonRpcEngineV2_instances, "m", _JsonRpcEngineV2_makeMiddlewareIterator).call(this);
|
|
148
148
|
const firstMiddleware = middlewareIterator.next().value;
|
|
149
|
+
const context = MiddlewareContext_1.MiddlewareContext.isInstance(rawContext)
|
|
150
|
+
? rawContext
|
|
151
|
+
: new MiddlewareContext_1.MiddlewareContext(rawContext);
|
|
149
152
|
const makeNext = __classPrivateFieldGet(this, _JsonRpcEngineV2_instances, "m", _JsonRpcEngineV2_makeNextFactory).call(this, middlewareIterator, state, context);
|
|
150
153
|
const result = await firstMiddleware({
|
|
151
154
|
request: originalRequest,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"JsonRpcEngineV2.cjs","sourceRoot":"","sources":["../../src/v2/JsonRpcEngineV2.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type Json,\n type JsonRpcRequest,\n type JsonRpcNotification,\n type NonEmptyArray,\n hasProperty,\n} from '@metamask/utils';\nimport deepFreeze from 'deep-freeze-strict';\n\nimport type { ContextConstraint, MergeContexts } from './MiddlewareContext';\nimport { MiddlewareContext } from './MiddlewareContext';\nimport {\n isNotification,\n isRequest,\n JsonRpcEngineError,\n stringify,\n} from './utils';\nimport type { JsonRpcCall } from './utils';\n\n// Helper to forbid `id` on notifications\ntype WithoutId<Request extends JsonRpcCall> = Request & { id?: never };\n\n// Helper to enable JsonRpcCall overload of handle()\ntype MixedParam<Request extends JsonRpcCall> = [\n Extract<Request, JsonRpcRequest>,\n] extends [never]\n ? never\n : [Extract<Request, JsonRpcNotification>] extends [never]\n ? never\n :\n | Extract<Request, JsonRpcRequest>\n | WithoutId<Extract<Request, JsonRpcNotification>>;\n\nexport type ResultConstraint<Request extends JsonRpcCall> =\n Request extends JsonRpcRequest ? Json : void;\n\nexport type Next<Request extends JsonRpcCall> = (\n request?: Readonly<Request>,\n) => Promise<Readonly<ResultConstraint<Request>> | undefined>;\n\nexport type MiddlewareParams<\n Request extends JsonRpcCall = JsonRpcCall,\n Context extends MiddlewareContext = MiddlewareContext,\n> = {\n request: Readonly<Request>;\n context: Context;\n next: Next<Request>;\n};\n\nexport type JsonRpcMiddleware<\n Request extends JsonRpcCall = JsonRpcCall,\n Result extends ResultConstraint<Request> = ResultConstraint<Request>,\n Context extends ContextConstraint = MiddlewareContext,\n> = (\n params: MiddlewareParams<Request, Context>,\n) => Readonly<Result> | undefined | Promise<Readonly<Result> | undefined>;\n\ntype RequestState<Request extends JsonRpcCall> = {\n request: Request;\n result: Readonly<ResultConstraint<Request>> | undefined;\n};\n\ntype HandleOptions<Context extends MiddlewareContext> = {\n context?: Context;\n};\n\ntype ConstructorOptions<\n Request extends JsonRpcCall,\n Context extends MiddlewareContext,\n> = {\n middleware: NonEmptyArray<\n JsonRpcMiddleware<Request, ResultConstraint<Request>, Context>\n >;\n};\n\nexport type RequestOf<Middleware> =\n Middleware extends JsonRpcMiddleware<\n infer Request,\n ResultConstraint<infer Request>,\n // Non-polluting `any` constraint.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n any\n >\n ? Request\n : never;\n\ntype ContextOf<Middleware> =\n // Non-polluting `any` constraint.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n Middleware extends JsonRpcMiddleware<any, ResultConstraint<any>, infer C>\n ? C\n : never;\n\nexport type MergedContextOf<\n // Non-polluting `any` constraint.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n Middleware extends JsonRpcMiddleware<any, any, any>,\n> = MergeContexts<ContextOf<Middleware>>;\n\nconst INVALID_ENGINE = Symbol('Invalid engine');\n\n/**\n * An internal type for invalid engines that explains why the engine is invalid.\n *\n * @template Message - The message explaining why the engine is invalid.\n */\ntype InvalidEngine<Message extends string> = { [INVALID_ENGINE]: Message };\n\n/**\n * A JSON-RPC request and response processor.\n *\n * Give it a stack of middleware, pass it requests, and get back responses.\n *\n * #### Requests vs. notifications\n *\n * JSON-RPC requests come in two flavors:\n *\n * - [Requests](https://www.jsonrpc.org/specification#request_object), i.e. request objects _with_ an `id`\n * - [Notifications](https://www.jsonrpc.org/specification#notification), i.e. request objects _without_ an `id`\n *\n * For requests, one of the engine's middleware must \"end\" the request by returning a non-`undefined` result,\n * or {@link handle} will throw an error:\n *\n * For notifications, on the other hand, one of the engine's middleware must return `undefined` to end the request,\n * and any non-`undefined` return values will cause an error:\n *\n * @template Request - The type of request to handle.\n * @template Result - The type of result to return.\n *\n * @example\n * ```ts\n * const engine = JsonRpcEngineV2.create({\n * middleware,\n * });\n *\n * try {\n * const result = await engine.handle(request);\n * // Handle result\n * } catch (error) {\n * // Handle error\n * }\n * ```\n */\nexport class JsonRpcEngineV2<\n Request extends JsonRpcCall = JsonRpcCall,\n Context extends ContextConstraint = MiddlewareContext,\n> {\n #middleware: Readonly<\n NonEmptyArray<\n JsonRpcMiddleware<Request, ResultConstraint<Request>, Context>\n >\n >;\n\n #isDestroyed = false;\n\n // See .create() for why this is private.\n private constructor({ middleware }: ConstructorOptions<Request, Context>) {\n this.#middleware = [...middleware];\n }\n\n // We use a static factory method in order to construct a supertype of all middleware contexts,\n // which enables us to instantiate an engine despite different middleware expecting different\n // context types.\n /**\n * Create a new JSON-RPC engine.\n *\n * @throws If the middleware array is empty.\n * @param options - The options for the engine.\n * @param options.middleware - The middleware to use.\n * @returns The JSON-RPC engine.\n */\n static create<\n Middleware extends JsonRpcMiddleware<\n // Non-polluting `any` constraint.\n /* eslint-disable @typescript-eslint/no-explicit-any */\n any,\n ResultConstraint<any>,\n any\n /* eslint-enable @typescript-eslint/no-explicit-any */\n > = JsonRpcMiddleware,\n >({ middleware }: { middleware: Middleware[] }) {\n // We can't use NonEmptyArray for the params because it ruins type inference.\n if (middleware.length === 0) {\n throw new JsonRpcEngineError('Middleware array cannot be empty');\n }\n\n type MergedContext = MergedContextOf<Middleware>;\n type InputRequest = RequestOf<Middleware>;\n const mw = middleware as unknown as NonEmptyArray<\n JsonRpcMiddleware<\n InputRequest,\n ResultConstraint<InputRequest>,\n MergedContext\n >\n >;\n return new JsonRpcEngineV2<InputRequest, MergedContext>({\n middleware: mw,\n }) as MergedContext extends never\n ? InvalidEngine<'Some middleware have incompatible context types'>\n : JsonRpcEngineV2<InputRequest, MergedContext>;\n }\n\n /**\n * Handle a JSON-RPC request.\n *\n * @param request - The JSON-RPC request to handle.\n * @param options - The options for the handle operation.\n * @param options.context - The context to pass to the middleware.\n * @returns The JSON-RPC response.\n */\n async handle(\n request: Extract<Request, JsonRpcRequest> extends never\n ? never\n : Extract<Request, JsonRpcRequest>,\n options?: HandleOptions<Context>,\n ): Promise<\n Extract<Request, JsonRpcRequest> extends never\n ? never\n : ResultConstraint<Request>\n >;\n\n /**\n * Handle a JSON-RPC notification. Notifications do not return a result.\n *\n * @param notification - The JSON-RPC notification to handle.\n * @param options - The options for the handle operation.\n * @param options.context - The context to pass to the middleware.\n */\n async handle(\n notification: Extract<Request, JsonRpcNotification> extends never\n ? never\n : WithoutId<Extract<Request, JsonRpcNotification>>,\n options?: HandleOptions<Context>,\n ): Promise<\n Extract<Request, JsonRpcNotification> extends never\n ? never\n : ResultConstraint<Request>\n >;\n\n /**\n * Handle a JSON-RPC call, i.e. request or notification. Requests return a\n * result, notifications do not.\n *\n * @param call - The JSON-RPC call to handle.\n * @param options - The options for the handle operation.\n * @param options.context - The context to pass to the middleware.\n * @returns The JSON-RPC response, or `undefined` if the call is a notification.\n */\n async handle(\n call: MixedParam<Request>,\n options?: HandleOptions<Context>,\n ): Promise<ResultConstraint<Request> | void>;\n\n async handle(\n request: Request,\n { context }: HandleOptions<Context> = {},\n ): Promise<Readonly<ResultConstraint<Request>> | void> {\n const isReq = isRequest(request);\n const { result } = await this.#handle(request, context);\n\n if (isReq && result === undefined) {\n throw new JsonRpcEngineError(\n `Nothing ended request: ${stringify(request)}`,\n );\n }\n return result;\n }\n\n /**\n * Handle a JSON-RPC request. Throws if a middleware performs an invalid\n * operation. Permits returning an `undefined` result.\n *\n * @param originalRequest - The JSON-RPC request to handle.\n * @param context - The context to pass to the middleware.\n * @returns The result from the middleware.\n */\n async #handle(\n originalRequest: Request,\n context: Context = new MiddlewareContext() as Context,\n ): Promise<RequestState<Request>> {\n this.#assertIsNotDestroyed();\n\n deepFreeze(originalRequest);\n\n const state: RequestState<Request> = {\n request: originalRequest,\n result: undefined,\n };\n const middlewareIterator = this.#makeMiddlewareIterator();\n const firstMiddleware = middlewareIterator.next().value;\n\n const makeNext = this.#makeNextFactory(middlewareIterator, state, context);\n\n const result = await firstMiddleware({\n request: originalRequest,\n context,\n next: makeNext(),\n });\n this.#updateResult(result, state);\n\n return state;\n }\n\n /**\n * Create a factory of `next()` functions for use with a particular request.\n * The factory is recursive, and a new `next()` is created for each middleware\n * invocation.\n *\n * @param middlewareIterator - The iterator of middleware for the current\n * request.\n * @param state - The current values of the request and result.\n * @param context - The context to pass to the middleware.\n * @returns The `next()` function factory.\n */\n #makeNextFactory(\n middlewareIterator: Iterator<\n JsonRpcMiddleware<Request, ResultConstraint<Request>, Context>\n >,\n state: RequestState<Request>,\n context: Context,\n ): () => Next<Request> {\n const makeNext = (): Next<Request> => {\n let wasCalled = false;\n\n const next = async (\n request: Request = state.request,\n ): Promise<Readonly<ResultConstraint<Request>> | undefined> => {\n if (wasCalled) {\n throw new JsonRpcEngineError(\n `Middleware attempted to call next() multiple times for request: ${stringify(request)}`,\n );\n }\n wasCalled = true;\n\n if (request !== state.request) {\n this.#assertValidNextRequest(state.request, request);\n state.request = deepFreeze(request);\n }\n\n const { value: nextMiddleware, done } = middlewareIterator.next();\n if (done) {\n // This will cause the last middleware to return `undefined`. See the class\n // JSDoc or package README for more details.\n return undefined;\n }\n\n const result = await nextMiddleware({\n request,\n context,\n next: makeNext(),\n });\n this.#updateResult(result, state);\n\n return state.result;\n };\n return next;\n };\n\n return makeNext;\n }\n\n #makeMiddlewareIterator(): Iterator<\n JsonRpcMiddleware<Request, ResultConstraint<Request>, Context>\n > {\n return this.#middleware[Symbol.iterator]();\n }\n\n /**\n * Validate the result from a middleware and, if it's a new value, update the\n * current result.\n *\n * @param result - The result from the middleware.\n * @param state - The current values of the request and result.\n */\n #updateResult(\n result:\n | Readonly<ResultConstraint<Request>>\n | ResultConstraint<Request>\n | void,\n state: RequestState<Request>,\n ): void {\n if (isNotification(state.request) && result !== undefined) {\n throw new JsonRpcEngineError(\n `Result returned for notification: ${stringify(state.request)}`,\n );\n }\n\n if (result !== undefined && result !== state.result) {\n if (typeof result === 'object' && result !== null) {\n deepFreeze(result);\n }\n state.result = result;\n }\n }\n\n /**\n * Assert that a request modified by a middleware is valid.\n *\n * @param currentRequest - The current request.\n * @param nextRequest - The next request.\n */\n #assertValidNextRequest(currentRequest: Request, nextRequest: Request): void {\n if (nextRequest.jsonrpc !== currentRequest.jsonrpc) {\n throw new JsonRpcEngineError(\n `Middleware attempted to modify readonly property \"jsonrpc\" for request: ${stringify(currentRequest)}`,\n );\n }\n if (\n hasProperty(nextRequest, 'id') !== hasProperty(currentRequest, 'id') ||\n // @ts-expect-error - \"id\" does not exist on notifications, but we can still\n // check the value of the property at runtime.\n nextRequest.id !== currentRequest.id\n ) {\n throw new JsonRpcEngineError(\n `Middleware attempted to modify readonly property \"id\" for request: ${stringify(currentRequest)}`,\n );\n }\n }\n\n /**\n * Convert the engine into a JSON-RPC middleware.\n *\n * @returns The JSON-RPC middleware.\n */\n asMiddleware(): JsonRpcMiddleware<\n Request,\n ResultConstraint<Request>,\n Context\n > {\n this.#assertIsNotDestroyed();\n\n return async ({ request, context, next }) => {\n const { result, request: finalRequest } = await this.#handle(\n request,\n context,\n );\n return result === undefined ? await next(finalRequest) : result;\n };\n }\n\n /**\n * Destroy the engine. Calls the `destroy()` method of any middleware that has\n * one. Attempting to use the engine after destroying it will throw an error.\n */\n async destroy(): Promise<void> {\n if (this.#isDestroyed) {\n return;\n }\n this.#isDestroyed = true;\n\n const destructionPromise = Promise.all(\n this.#middleware.map(async (middleware) => {\n if (\n // Intentionally using `in` to walk the prototype chain.\n 'destroy' in middleware &&\n typeof middleware.destroy === 'function'\n ) {\n return middleware.destroy();\n }\n return undefined;\n }),\n );\n this.#middleware = [] as never;\n await destructionPromise;\n }\n\n #assertIsNotDestroyed(): void {\n if (this.#isDestroyed) {\n throw new JsonRpcEngineError('Engine is destroyed');\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"JsonRpcEngineV2.cjs","sourceRoot":"","sources":["../../src/v2/JsonRpcEngineV2.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type Json,\n type JsonRpcRequest,\n type JsonRpcNotification,\n type NonEmptyArray,\n hasProperty,\n} from '@metamask/utils';\nimport deepFreeze from 'deep-freeze-strict';\n\nimport type {\n ContextConstraint,\n InferKeyValues,\n MergeContexts,\n} from './MiddlewareContext';\nimport { MiddlewareContext } from './MiddlewareContext';\nimport {\n isNotification,\n isRequest,\n JsonRpcEngineError,\n stringify,\n} from './utils';\nimport type { JsonRpcCall } from './utils';\n\n// Helper to forbid `id` on notifications\ntype WithoutId<Request extends JsonRpcCall> = Request & { id?: never };\n\n// Helper to enable JsonRpcCall overload of handle()\ntype MixedParam<Request extends JsonRpcCall> = [\n Extract<Request, JsonRpcRequest>,\n] extends [never]\n ? never\n : [Extract<Request, JsonRpcNotification>] extends [never]\n ? never\n :\n | Extract<Request, JsonRpcRequest>\n | WithoutId<Extract<Request, JsonRpcNotification>>;\n\nexport type ResultConstraint<Request extends JsonRpcCall> =\n Request extends JsonRpcRequest ? Json : void;\n\nexport type Next<Request extends JsonRpcCall> = (\n request?: Readonly<Request>,\n) => Promise<Readonly<ResultConstraint<Request>> | undefined>;\n\nexport type MiddlewareParams<\n Request extends JsonRpcCall = JsonRpcCall,\n Context extends ContextConstraint = MiddlewareContext,\n> = {\n request: Readonly<Request>;\n context: Context;\n next: Next<Request>;\n};\n\nexport type JsonRpcMiddleware<\n Request extends JsonRpcCall = JsonRpcCall,\n Result extends ResultConstraint<Request> = ResultConstraint<Request>,\n Context extends ContextConstraint = MiddlewareContext,\n> = (\n params: MiddlewareParams<Request, Context>,\n) => Readonly<Result> | undefined | Promise<Readonly<Result> | undefined>;\n\ntype RequestState<Request extends JsonRpcCall> = {\n request: Request;\n result: Readonly<ResultConstraint<Request>> | undefined;\n};\n\n/**\n * The options for the JSON-RPC request/notification handling operation.\n */\nexport type HandleOptions<Context extends ContextConstraint> = {\n context?: Context | InferKeyValues<Context>;\n};\n\ntype ConstructorOptions<\n Request extends JsonRpcCall,\n Context extends MiddlewareContext,\n> = {\n middleware: NonEmptyArray<\n JsonRpcMiddleware<Request, ResultConstraint<Request>, Context>\n >;\n};\n\n/**\n * The request type of a middleware.\n */\nexport type RequestOf<Middleware> =\n Middleware extends JsonRpcMiddleware<\n infer Request,\n ResultConstraint<infer Request>,\n // Non-polluting `any` constraint.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n any\n >\n ? Request\n : never;\n\ntype ContextOf<Middleware> =\n // Non-polluting `any` constraint.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n Middleware extends JsonRpcMiddleware<any, ResultConstraint<any>, infer C>\n ? C\n : never;\n\n/**\n * A constraint for {@link JsonRpcMiddleware} generic parameters.\n */\n// Non-polluting `any` constraint.\n/* eslint-disable @typescript-eslint/no-explicit-any */\nexport type MiddlewareConstraint = JsonRpcMiddleware<\n any,\n ResultConstraint<any>,\n MiddlewareContext<any>\n>;\n/* eslint-enable @typescript-eslint/no-explicit-any */\n\n/**\n * The context supertype of a middleware type.\n */\nexport type MergedContextOf<Middleware extends MiddlewareConstraint> =\n MergeContexts<ContextOf<Middleware>>;\n\nconst INVALID_ENGINE = Symbol('Invalid engine');\n\n/**\n * An internal type for invalid engines that explains why the engine is invalid.\n *\n * @template Message - The message explaining why the engine is invalid.\n */\ntype InvalidEngine<Message extends string> = { [INVALID_ENGINE]: Message };\n\n/**\n * A JSON-RPC request and response processor.\n *\n * Give it a stack of middleware, pass it requests, and get back responses.\n *\n * #### Requests vs. notifications\n *\n * JSON-RPC requests come in two flavors:\n *\n * - [Requests](https://www.jsonrpc.org/specification#request_object), i.e. request objects _with_ an `id`\n * - [Notifications](https://www.jsonrpc.org/specification#notification), i.e. request objects _without_ an `id`\n *\n * For requests, one of the engine's middleware must \"end\" the request by returning a non-`undefined` result,\n * or {@link handle} will throw an error:\n *\n * For notifications, on the other hand, one of the engine's middleware must return `undefined` to end the request,\n * and any non-`undefined` return values will cause an error:\n *\n * @template Request - The type of request to handle.\n * @template Result - The type of result to return.\n *\n * @example\n * ```ts\n * const engine = JsonRpcEngineV2.create({\n * middleware,\n * });\n *\n * try {\n * const result = await engine.handle(request);\n * // Handle result\n * } catch (error) {\n * // Handle error\n * }\n * ```\n */\nexport class JsonRpcEngineV2<\n Request extends JsonRpcCall = JsonRpcCall,\n Context extends ContextConstraint = MiddlewareContext,\n> {\n #middleware: Readonly<\n NonEmptyArray<\n JsonRpcMiddleware<Request, ResultConstraint<Request>, Context>\n >\n >;\n\n #isDestroyed = false;\n\n // See .create() for why this is private.\n private constructor({ middleware }: ConstructorOptions<Request, Context>) {\n this.#middleware = [...middleware];\n }\n\n // We use a static factory method in order to construct a supertype of all middleware contexts,\n // which enables us to instantiate an engine despite different middleware expecting different\n // context types.\n /**\n * Create a new JSON-RPC engine.\n *\n * @throws If the middleware array is empty.\n * @param options - The options for the engine.\n * @param options.middleware - The middleware to use.\n * @returns The JSON-RPC engine.\n */\n static create<\n Middleware extends JsonRpcMiddleware<\n // Non-polluting `any` constraint.\n /* eslint-disable @typescript-eslint/no-explicit-any */\n any,\n ResultConstraint<any>,\n any\n /* eslint-enable @typescript-eslint/no-explicit-any */\n > = JsonRpcMiddleware,\n >({ middleware }: { middleware: Middleware[] }) {\n // We can't use NonEmptyArray for the params because it ruins type inference.\n if (middleware.length === 0) {\n throw new JsonRpcEngineError('Middleware array cannot be empty');\n }\n\n type MergedContext = MergedContextOf<Middleware>;\n type InputRequest = RequestOf<Middleware>;\n const mw = middleware as unknown as NonEmptyArray<\n JsonRpcMiddleware<\n InputRequest,\n ResultConstraint<InputRequest>,\n MergedContext\n >\n >;\n return new JsonRpcEngineV2<InputRequest, MergedContext>({\n middleware: mw,\n }) as MergedContext extends never\n ? InvalidEngine<'Some middleware have incompatible context types'>\n : JsonRpcEngineV2<InputRequest, MergedContext>;\n }\n\n /**\n * Handle a JSON-RPC request.\n *\n * @param request - The JSON-RPC request to handle.\n * @param options - The options for the handle operation.\n * @param options.context - The context to pass to the middleware.\n * @returns The JSON-RPC response.\n */\n async handle(\n request: Extract<Request, JsonRpcRequest> extends never\n ? never\n : Extract<Request, JsonRpcRequest>,\n options?: HandleOptions<Context>,\n ): Promise<\n Extract<Request, JsonRpcRequest> extends never\n ? never\n : ResultConstraint<Request>\n >;\n\n /**\n * Handle a JSON-RPC notification. Notifications do not return a result.\n *\n * @param notification - The JSON-RPC notification to handle.\n * @param options - The options for the handle operation.\n * @param options.context - The context to pass to the middleware.\n */\n async handle(\n notification: Extract<Request, JsonRpcNotification> extends never\n ? never\n : WithoutId<Extract<Request, JsonRpcNotification>>,\n options?: HandleOptions<Context>,\n ): Promise<\n Extract<Request, JsonRpcNotification> extends never\n ? never\n : ResultConstraint<Request>\n >;\n\n /**\n * Handle a JSON-RPC call, i.e. request or notification. Requests return a\n * result, notifications do not.\n *\n * @param call - The JSON-RPC call to handle.\n * @param options - The options for the handle operation.\n * @param options.context - The context to pass to the middleware.\n * @returns The JSON-RPC response, or `undefined` if the call is a notification.\n */\n async handle(\n call: MixedParam<Request>,\n options?: HandleOptions<Context>,\n ): Promise<ResultConstraint<Request> | void>;\n\n async handle(\n request: Request,\n { context }: HandleOptions<Context> = {},\n ): Promise<Readonly<ResultConstraint<Request>> | void> {\n const isReq = isRequest(request);\n const { result } = await this.#handle(request, context);\n\n if (isReq && result === undefined) {\n throw new JsonRpcEngineError(\n `Nothing ended request: ${stringify(request)}`,\n );\n }\n return result;\n }\n\n /**\n * Handle a JSON-RPC request. Throws if a middleware performs an invalid\n * operation. Permits returning an `undefined` result.\n *\n * @param originalRequest - The JSON-RPC request to handle.\n * @param rawContext - The context to pass to the middleware.\n * @returns The result from the middleware.\n */\n async #handle(\n originalRequest: Request,\n rawContext:\n | Context\n | InferKeyValues<Context> = new MiddlewareContext() as Context,\n ): Promise<RequestState<Request>> {\n this.#assertIsNotDestroyed();\n\n deepFreeze(originalRequest);\n\n const state: RequestState<Request> = {\n request: originalRequest,\n result: undefined,\n };\n const middlewareIterator = this.#makeMiddlewareIterator();\n const firstMiddleware = middlewareIterator.next().value;\n const context = MiddlewareContext.isInstance(rawContext)\n ? rawContext\n : (new MiddlewareContext(rawContext) as Context);\n\n const makeNext = this.#makeNextFactory(middlewareIterator, state, context);\n\n const result = await firstMiddleware({\n request: originalRequest,\n context,\n next: makeNext(),\n });\n this.#updateResult(result, state);\n\n return state;\n }\n\n /**\n * Create a factory of `next()` functions for use with a particular request.\n * The factory is recursive, and a new `next()` is created for each middleware\n * invocation.\n *\n * @param middlewareIterator - The iterator of middleware for the current\n * request.\n * @param state - The current values of the request and result.\n * @param context - The context to pass to the middleware.\n * @returns The `next()` function factory.\n */\n #makeNextFactory(\n middlewareIterator: Iterator<\n JsonRpcMiddleware<Request, ResultConstraint<Request>, Context>\n >,\n state: RequestState<Request>,\n context: Context,\n ): () => Next<Request> {\n const makeNext = (): Next<Request> => {\n let wasCalled = false;\n\n const next = async (\n request: Request = state.request,\n ): Promise<Readonly<ResultConstraint<Request>> | undefined> => {\n if (wasCalled) {\n throw new JsonRpcEngineError(\n `Middleware attempted to call next() multiple times for request: ${stringify(request)}`,\n );\n }\n wasCalled = true;\n\n if (request !== state.request) {\n this.#assertValidNextRequest(state.request, request);\n state.request = deepFreeze(request);\n }\n\n const { value: nextMiddleware, done } = middlewareIterator.next();\n if (done) {\n // This will cause the last middleware to return `undefined`. See the class\n // JSDoc or package README for more details.\n return undefined;\n }\n\n const result = await nextMiddleware({\n request,\n context,\n next: makeNext(),\n });\n this.#updateResult(result, state);\n\n return state.result;\n };\n return next;\n };\n\n return makeNext;\n }\n\n #makeMiddlewareIterator(): Iterator<\n JsonRpcMiddleware<Request, ResultConstraint<Request>, Context>\n > {\n return this.#middleware[Symbol.iterator]();\n }\n\n /**\n * Validate the result from a middleware and, if it's a new value, update the\n * current result.\n *\n * @param result - The result from the middleware.\n * @param state - The current values of the request and result.\n */\n #updateResult(\n result:\n | Readonly<ResultConstraint<Request>>\n | ResultConstraint<Request>\n | void,\n state: RequestState<Request>,\n ): void {\n if (isNotification(state.request) && result !== undefined) {\n throw new JsonRpcEngineError(\n `Result returned for notification: ${stringify(state.request)}`,\n );\n }\n\n if (result !== undefined && result !== state.result) {\n if (typeof result === 'object' && result !== null) {\n deepFreeze(result);\n }\n state.result = result;\n }\n }\n\n /**\n * Assert that a request modified by a middleware is valid.\n *\n * @param currentRequest - The current request.\n * @param nextRequest - The next request.\n */\n #assertValidNextRequest(currentRequest: Request, nextRequest: Request): void {\n if (nextRequest.jsonrpc !== currentRequest.jsonrpc) {\n throw new JsonRpcEngineError(\n `Middleware attempted to modify readonly property \"jsonrpc\" for request: ${stringify(currentRequest)}`,\n );\n }\n if (\n hasProperty(nextRequest, 'id') !== hasProperty(currentRequest, 'id') ||\n // @ts-expect-error - \"id\" does not exist on notifications, but we can still\n // check the value of the property at runtime.\n nextRequest.id !== currentRequest.id\n ) {\n throw new JsonRpcEngineError(\n `Middleware attempted to modify readonly property \"id\" for request: ${stringify(currentRequest)}`,\n );\n }\n }\n\n /**\n * Convert the engine into a JSON-RPC middleware.\n *\n * @returns The JSON-RPC middleware.\n */\n asMiddleware(): JsonRpcMiddleware<\n Request,\n ResultConstraint<Request>,\n Context\n > {\n this.#assertIsNotDestroyed();\n\n return async ({ request, context, next }) => {\n const { result, request: finalRequest } = await this.#handle(\n request,\n context,\n );\n return result === undefined ? await next(finalRequest) : result;\n };\n }\n\n /**\n * Destroy the engine. Calls the `destroy()` method of any middleware that has\n * one. Attempting to use the engine after destroying it will throw an error.\n */\n async destroy(): Promise<void> {\n if (this.#isDestroyed) {\n return;\n }\n this.#isDestroyed = true;\n\n const destructionPromise = Promise.all(\n this.#middleware.map(async (middleware) => {\n if (\n // Intentionally using `in` to walk the prototype chain.\n 'destroy' in middleware &&\n typeof middleware.destroy === 'function'\n ) {\n return middleware.destroy();\n }\n return undefined;\n }),\n );\n this.#middleware = [] as never;\n await destructionPromise;\n }\n\n #assertIsNotDestroyed(): void {\n if (this.#isDestroyed) {\n throw new JsonRpcEngineError('Engine is destroyed');\n }\n }\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type Json, type JsonRpcRequest, type JsonRpcNotification } from "@metamask/utils";
|
|
2
|
-
import type { ContextConstraint, MergeContexts } from "./MiddlewareContext.cjs";
|
|
2
|
+
import type { ContextConstraint, InferKeyValues, MergeContexts } from "./MiddlewareContext.cjs";
|
|
3
3
|
import { MiddlewareContext } from "./MiddlewareContext.cjs";
|
|
4
4
|
import type { JsonRpcCall } from "./utils.cjs";
|
|
5
5
|
type WithoutId<Request extends JsonRpcCall> = Request & {
|
|
@@ -10,18 +10,31 @@ type MixedParam<Request extends JsonRpcCall> = [
|
|
|
10
10
|
] extends [never] ? never : [Extract<Request, JsonRpcNotification>] extends [never] ? never : Extract<Request, JsonRpcRequest> | WithoutId<Extract<Request, JsonRpcNotification>>;
|
|
11
11
|
export type ResultConstraint<Request extends JsonRpcCall> = Request extends JsonRpcRequest ? Json : void;
|
|
12
12
|
export type Next<Request extends JsonRpcCall> = (request?: Readonly<Request>) => Promise<Readonly<ResultConstraint<Request>> | undefined>;
|
|
13
|
-
export type MiddlewareParams<Request extends JsonRpcCall = JsonRpcCall, Context extends
|
|
13
|
+
export type MiddlewareParams<Request extends JsonRpcCall = JsonRpcCall, Context extends ContextConstraint = MiddlewareContext> = {
|
|
14
14
|
request: Readonly<Request>;
|
|
15
15
|
context: Context;
|
|
16
16
|
next: Next<Request>;
|
|
17
17
|
};
|
|
18
18
|
export type JsonRpcMiddleware<Request extends JsonRpcCall = JsonRpcCall, Result extends ResultConstraint<Request> = ResultConstraint<Request>, Context extends ContextConstraint = MiddlewareContext> = (params: MiddlewareParams<Request, Context>) => Readonly<Result> | undefined | Promise<Readonly<Result> | undefined>;
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
/**
|
|
20
|
+
* The options for the JSON-RPC request/notification handling operation.
|
|
21
|
+
*/
|
|
22
|
+
export type HandleOptions<Context extends ContextConstraint> = {
|
|
23
|
+
context?: Context | InferKeyValues<Context>;
|
|
21
24
|
};
|
|
25
|
+
/**
|
|
26
|
+
* The request type of a middleware.
|
|
27
|
+
*/
|
|
22
28
|
export type RequestOf<Middleware> = Middleware extends JsonRpcMiddleware<infer Request, ResultConstraint<infer Request>, any> ? Request : never;
|
|
23
29
|
type ContextOf<Middleware> = Middleware extends JsonRpcMiddleware<any, ResultConstraint<any>, infer C> ? C : never;
|
|
24
|
-
|
|
30
|
+
/**
|
|
31
|
+
* A constraint for {@link JsonRpcMiddleware} generic parameters.
|
|
32
|
+
*/
|
|
33
|
+
export type MiddlewareConstraint = JsonRpcMiddleware<any, ResultConstraint<any>, MiddlewareContext<any>>;
|
|
34
|
+
/**
|
|
35
|
+
* The context supertype of a middleware type.
|
|
36
|
+
*/
|
|
37
|
+
export type MergedContextOf<Middleware extends MiddlewareConstraint> = MergeContexts<ContextOf<Middleware>>;
|
|
25
38
|
declare const INVALID_ENGINE: unique symbol;
|
|
26
39
|
/**
|
|
27
40
|
* An internal type for invalid engines that explains why the engine is invalid.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"JsonRpcEngineV2.d.cts","sourceRoot":"","sources":["../../src/v2/JsonRpcEngineV2.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,IAAI,EACT,KAAK,cAAc,EACnB,KAAK,mBAAmB,EAGzB,wBAAwB;AAGzB,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"JsonRpcEngineV2.d.cts","sourceRoot":"","sources":["../../src/v2/JsonRpcEngineV2.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type Json, type JsonRpcRequest, type JsonRpcNotification } from "@metamask/utils";
|
|
2
|
-
import type { ContextConstraint, MergeContexts } from "./MiddlewareContext.mjs";
|
|
2
|
+
import type { ContextConstraint, InferKeyValues, MergeContexts } from "./MiddlewareContext.mjs";
|
|
3
3
|
import { MiddlewareContext } from "./MiddlewareContext.mjs";
|
|
4
4
|
import type { JsonRpcCall } from "./utils.mjs";
|
|
5
5
|
type WithoutId<Request extends JsonRpcCall> = Request & {
|
|
@@ -10,18 +10,31 @@ type MixedParam<Request extends JsonRpcCall> = [
|
|
|
10
10
|
] extends [never] ? never : [Extract<Request, JsonRpcNotification>] extends [never] ? never : Extract<Request, JsonRpcRequest> | WithoutId<Extract<Request, JsonRpcNotification>>;
|
|
11
11
|
export type ResultConstraint<Request extends JsonRpcCall> = Request extends JsonRpcRequest ? Json : void;
|
|
12
12
|
export type Next<Request extends JsonRpcCall> = (request?: Readonly<Request>) => Promise<Readonly<ResultConstraint<Request>> | undefined>;
|
|
13
|
-
export type MiddlewareParams<Request extends JsonRpcCall = JsonRpcCall, Context extends
|
|
13
|
+
export type MiddlewareParams<Request extends JsonRpcCall = JsonRpcCall, Context extends ContextConstraint = MiddlewareContext> = {
|
|
14
14
|
request: Readonly<Request>;
|
|
15
15
|
context: Context;
|
|
16
16
|
next: Next<Request>;
|
|
17
17
|
};
|
|
18
18
|
export type JsonRpcMiddleware<Request extends JsonRpcCall = JsonRpcCall, Result extends ResultConstraint<Request> = ResultConstraint<Request>, Context extends ContextConstraint = MiddlewareContext> = (params: MiddlewareParams<Request, Context>) => Readonly<Result> | undefined | Promise<Readonly<Result> | undefined>;
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
/**
|
|
20
|
+
* The options for the JSON-RPC request/notification handling operation.
|
|
21
|
+
*/
|
|
22
|
+
export type HandleOptions<Context extends ContextConstraint> = {
|
|
23
|
+
context?: Context | InferKeyValues<Context>;
|
|
21
24
|
};
|
|
25
|
+
/**
|
|
26
|
+
* The request type of a middleware.
|
|
27
|
+
*/
|
|
22
28
|
export type RequestOf<Middleware> = Middleware extends JsonRpcMiddleware<infer Request, ResultConstraint<infer Request>, any> ? Request : never;
|
|
23
29
|
type ContextOf<Middleware> = Middleware extends JsonRpcMiddleware<any, ResultConstraint<any>, infer C> ? C : never;
|
|
24
|
-
|
|
30
|
+
/**
|
|
31
|
+
* A constraint for {@link JsonRpcMiddleware} generic parameters.
|
|
32
|
+
*/
|
|
33
|
+
export type MiddlewareConstraint = JsonRpcMiddleware<any, ResultConstraint<any>, MiddlewareContext<any>>;
|
|
34
|
+
/**
|
|
35
|
+
* The context supertype of a middleware type.
|
|
36
|
+
*/
|
|
37
|
+
export type MergedContextOf<Middleware extends MiddlewareConstraint> = MergeContexts<ContextOf<Middleware>>;
|
|
25
38
|
declare const INVALID_ENGINE: unique symbol;
|
|
26
39
|
/**
|
|
27
40
|
* An internal type for invalid engines that explains why the engine is invalid.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"JsonRpcEngineV2.d.mts","sourceRoot":"","sources":["../../src/v2/JsonRpcEngineV2.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,IAAI,EACT,KAAK,cAAc,EACnB,KAAK,mBAAmB,EAGzB,wBAAwB;AAGzB,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"JsonRpcEngineV2.d.mts","sourceRoot":"","sources":["../../src/v2/JsonRpcEngineV2.ts"],"names":[],"mappings":"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"}
|
|
@@ -134,10 +134,10 @@ _JsonRpcEngineV2_middleware = new WeakMap(), _JsonRpcEngineV2_isDestroyed = new
|
|
|
134
134
|
* operation. Permits returning an `undefined` result.
|
|
135
135
|
*
|
|
136
136
|
* @param originalRequest - The JSON-RPC request to handle.
|
|
137
|
-
* @param
|
|
137
|
+
* @param rawContext - The context to pass to the middleware.
|
|
138
138
|
* @returns The result from the middleware.
|
|
139
139
|
*/
|
|
140
|
-
async function _JsonRpcEngineV2_handle(originalRequest,
|
|
140
|
+
async function _JsonRpcEngineV2_handle(originalRequest, rawContext = new MiddlewareContext()) {
|
|
141
141
|
__classPrivateFieldGet(this, _JsonRpcEngineV2_instances, "m", _JsonRpcEngineV2_assertIsNotDestroyed).call(this);
|
|
142
142
|
deepFreeze(originalRequest);
|
|
143
143
|
const state = {
|
|
@@ -146,6 +146,9 @@ async function _JsonRpcEngineV2_handle(originalRequest, context = new Middleware
|
|
|
146
146
|
};
|
|
147
147
|
const middlewareIterator = __classPrivateFieldGet(this, _JsonRpcEngineV2_instances, "m", _JsonRpcEngineV2_makeMiddlewareIterator).call(this);
|
|
148
148
|
const firstMiddleware = middlewareIterator.next().value;
|
|
149
|
+
const context = MiddlewareContext.isInstance(rawContext)
|
|
150
|
+
? rawContext
|
|
151
|
+
: new MiddlewareContext(rawContext);
|
|
149
152
|
const makeNext = __classPrivateFieldGet(this, _JsonRpcEngineV2_instances, "m", _JsonRpcEngineV2_makeNextFactory).call(this, middlewareIterator, state, context);
|
|
150
153
|
const result = await firstMiddleware({
|
|
151
154
|
request: originalRequest,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"JsonRpcEngineV2.mjs","sourceRoot":"","sources":["../../src/v2/JsonRpcEngineV2.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type Json,\n type JsonRpcRequest,\n type JsonRpcNotification,\n type NonEmptyArray,\n hasProperty,\n} from '@metamask/utils';\nimport deepFreeze from 'deep-freeze-strict';\n\nimport type { ContextConstraint, MergeContexts } from './MiddlewareContext';\nimport { MiddlewareContext } from './MiddlewareContext';\nimport {\n isNotification,\n isRequest,\n JsonRpcEngineError,\n stringify,\n} from './utils';\nimport type { JsonRpcCall } from './utils';\n\n// Helper to forbid `id` on notifications\ntype WithoutId<Request extends JsonRpcCall> = Request & { id?: never };\n\n// Helper to enable JsonRpcCall overload of handle()\ntype MixedParam<Request extends JsonRpcCall> = [\n Extract<Request, JsonRpcRequest>,\n] extends [never]\n ? never\n : [Extract<Request, JsonRpcNotification>] extends [never]\n ? never\n :\n | Extract<Request, JsonRpcRequest>\n | WithoutId<Extract<Request, JsonRpcNotification>>;\n\nexport type ResultConstraint<Request extends JsonRpcCall> =\n Request extends JsonRpcRequest ? Json : void;\n\nexport type Next<Request extends JsonRpcCall> = (\n request?: Readonly<Request>,\n) => Promise<Readonly<ResultConstraint<Request>> | undefined>;\n\nexport type MiddlewareParams<\n Request extends JsonRpcCall = JsonRpcCall,\n Context extends MiddlewareContext = MiddlewareContext,\n> = {\n request: Readonly<Request>;\n context: Context;\n next: Next<Request>;\n};\n\nexport type JsonRpcMiddleware<\n Request extends JsonRpcCall = JsonRpcCall,\n Result extends ResultConstraint<Request> = ResultConstraint<Request>,\n Context extends ContextConstraint = MiddlewareContext,\n> = (\n params: MiddlewareParams<Request, Context>,\n) => Readonly<Result> | undefined | Promise<Readonly<Result> | undefined>;\n\ntype RequestState<Request extends JsonRpcCall> = {\n request: Request;\n result: Readonly<ResultConstraint<Request>> | undefined;\n};\n\ntype HandleOptions<Context extends MiddlewareContext> = {\n context?: Context;\n};\n\ntype ConstructorOptions<\n Request extends JsonRpcCall,\n Context extends MiddlewareContext,\n> = {\n middleware: NonEmptyArray<\n JsonRpcMiddleware<Request, ResultConstraint<Request>, Context>\n >;\n};\n\nexport type RequestOf<Middleware> =\n Middleware extends JsonRpcMiddleware<\n infer Request,\n ResultConstraint<infer Request>,\n // Non-polluting `any` constraint.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n any\n >\n ? Request\n : never;\n\ntype ContextOf<Middleware> =\n // Non-polluting `any` constraint.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n Middleware extends JsonRpcMiddleware<any, ResultConstraint<any>, infer C>\n ? C\n : never;\n\nexport type MergedContextOf<\n // Non-polluting `any` constraint.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n Middleware extends JsonRpcMiddleware<any, any, any>,\n> = MergeContexts<ContextOf<Middleware>>;\n\nconst INVALID_ENGINE = Symbol('Invalid engine');\n\n/**\n * An internal type for invalid engines that explains why the engine is invalid.\n *\n * @template Message - The message explaining why the engine is invalid.\n */\ntype InvalidEngine<Message extends string> = { [INVALID_ENGINE]: Message };\n\n/**\n * A JSON-RPC request and response processor.\n *\n * Give it a stack of middleware, pass it requests, and get back responses.\n *\n * #### Requests vs. notifications\n *\n * JSON-RPC requests come in two flavors:\n *\n * - [Requests](https://www.jsonrpc.org/specification#request_object), i.e. request objects _with_ an `id`\n * - [Notifications](https://www.jsonrpc.org/specification#notification), i.e. request objects _without_ an `id`\n *\n * For requests, one of the engine's middleware must \"end\" the request by returning a non-`undefined` result,\n * or {@link handle} will throw an error:\n *\n * For notifications, on the other hand, one of the engine's middleware must return `undefined` to end the request,\n * and any non-`undefined` return values will cause an error:\n *\n * @template Request - The type of request to handle.\n * @template Result - The type of result to return.\n *\n * @example\n * ```ts\n * const engine = JsonRpcEngineV2.create({\n * middleware,\n * });\n *\n * try {\n * const result = await engine.handle(request);\n * // Handle result\n * } catch (error) {\n * // Handle error\n * }\n * ```\n */\nexport class JsonRpcEngineV2<\n Request extends JsonRpcCall = JsonRpcCall,\n Context extends ContextConstraint = MiddlewareContext,\n> {\n #middleware: Readonly<\n NonEmptyArray<\n JsonRpcMiddleware<Request, ResultConstraint<Request>, Context>\n >\n >;\n\n #isDestroyed = false;\n\n // See .create() for why this is private.\n private constructor({ middleware }: ConstructorOptions<Request, Context>) {\n this.#middleware = [...middleware];\n }\n\n // We use a static factory method in order to construct a supertype of all middleware contexts,\n // which enables us to instantiate an engine despite different middleware expecting different\n // context types.\n /**\n * Create a new JSON-RPC engine.\n *\n * @throws If the middleware array is empty.\n * @param options - The options for the engine.\n * @param options.middleware - The middleware to use.\n * @returns The JSON-RPC engine.\n */\n static create<\n Middleware extends JsonRpcMiddleware<\n // Non-polluting `any` constraint.\n /* eslint-disable @typescript-eslint/no-explicit-any */\n any,\n ResultConstraint<any>,\n any\n /* eslint-enable @typescript-eslint/no-explicit-any */\n > = JsonRpcMiddleware,\n >({ middleware }: { middleware: Middleware[] }) {\n // We can't use NonEmptyArray for the params because it ruins type inference.\n if (middleware.length === 0) {\n throw new JsonRpcEngineError('Middleware array cannot be empty');\n }\n\n type MergedContext = MergedContextOf<Middleware>;\n type InputRequest = RequestOf<Middleware>;\n const mw = middleware as unknown as NonEmptyArray<\n JsonRpcMiddleware<\n InputRequest,\n ResultConstraint<InputRequest>,\n MergedContext\n >\n >;\n return new JsonRpcEngineV2<InputRequest, MergedContext>({\n middleware: mw,\n }) as MergedContext extends never\n ? InvalidEngine<'Some middleware have incompatible context types'>\n : JsonRpcEngineV2<InputRequest, MergedContext>;\n }\n\n /**\n * Handle a JSON-RPC request.\n *\n * @param request - The JSON-RPC request to handle.\n * @param options - The options for the handle operation.\n * @param options.context - The context to pass to the middleware.\n * @returns The JSON-RPC response.\n */\n async handle(\n request: Extract<Request, JsonRpcRequest> extends never\n ? never\n : Extract<Request, JsonRpcRequest>,\n options?: HandleOptions<Context>,\n ): Promise<\n Extract<Request, JsonRpcRequest> extends never\n ? never\n : ResultConstraint<Request>\n >;\n\n /**\n * Handle a JSON-RPC notification. Notifications do not return a result.\n *\n * @param notification - The JSON-RPC notification to handle.\n * @param options - The options for the handle operation.\n * @param options.context - The context to pass to the middleware.\n */\n async handle(\n notification: Extract<Request, JsonRpcNotification> extends never\n ? never\n : WithoutId<Extract<Request, JsonRpcNotification>>,\n options?: HandleOptions<Context>,\n ): Promise<\n Extract<Request, JsonRpcNotification> extends never\n ? never\n : ResultConstraint<Request>\n >;\n\n /**\n * Handle a JSON-RPC call, i.e. request or notification. Requests return a\n * result, notifications do not.\n *\n * @param call - The JSON-RPC call to handle.\n * @param options - The options for the handle operation.\n * @param options.context - The context to pass to the middleware.\n * @returns The JSON-RPC response, or `undefined` if the call is a notification.\n */\n async handle(\n call: MixedParam<Request>,\n options?: HandleOptions<Context>,\n ): Promise<ResultConstraint<Request> | void>;\n\n async handle(\n request: Request,\n { context }: HandleOptions<Context> = {},\n ): Promise<Readonly<ResultConstraint<Request>> | void> {\n const isReq = isRequest(request);\n const { result } = await this.#handle(request, context);\n\n if (isReq && result === undefined) {\n throw new JsonRpcEngineError(\n `Nothing ended request: ${stringify(request)}`,\n );\n }\n return result;\n }\n\n /**\n * Handle a JSON-RPC request. Throws if a middleware performs an invalid\n * operation. Permits returning an `undefined` result.\n *\n * @param originalRequest - The JSON-RPC request to handle.\n * @param context - The context to pass to the middleware.\n * @returns The result from the middleware.\n */\n async #handle(\n originalRequest: Request,\n context: Context = new MiddlewareContext() as Context,\n ): Promise<RequestState<Request>> {\n this.#assertIsNotDestroyed();\n\n deepFreeze(originalRequest);\n\n const state: RequestState<Request> = {\n request: originalRequest,\n result: undefined,\n };\n const middlewareIterator = this.#makeMiddlewareIterator();\n const firstMiddleware = middlewareIterator.next().value;\n\n const makeNext = this.#makeNextFactory(middlewareIterator, state, context);\n\n const result = await firstMiddleware({\n request: originalRequest,\n context,\n next: makeNext(),\n });\n this.#updateResult(result, state);\n\n return state;\n }\n\n /**\n * Create a factory of `next()` functions for use with a particular request.\n * The factory is recursive, and a new `next()` is created for each middleware\n * invocation.\n *\n * @param middlewareIterator - The iterator of middleware for the current\n * request.\n * @param state - The current values of the request and result.\n * @param context - The context to pass to the middleware.\n * @returns The `next()` function factory.\n */\n #makeNextFactory(\n middlewareIterator: Iterator<\n JsonRpcMiddleware<Request, ResultConstraint<Request>, Context>\n >,\n state: RequestState<Request>,\n context: Context,\n ): () => Next<Request> {\n const makeNext = (): Next<Request> => {\n let wasCalled = false;\n\n const next = async (\n request: Request = state.request,\n ): Promise<Readonly<ResultConstraint<Request>> | undefined> => {\n if (wasCalled) {\n throw new JsonRpcEngineError(\n `Middleware attempted to call next() multiple times for request: ${stringify(request)}`,\n );\n }\n wasCalled = true;\n\n if (request !== state.request) {\n this.#assertValidNextRequest(state.request, request);\n state.request = deepFreeze(request);\n }\n\n const { value: nextMiddleware, done } = middlewareIterator.next();\n if (done) {\n // This will cause the last middleware to return `undefined`. See the class\n // JSDoc or package README for more details.\n return undefined;\n }\n\n const result = await nextMiddleware({\n request,\n context,\n next: makeNext(),\n });\n this.#updateResult(result, state);\n\n return state.result;\n };\n return next;\n };\n\n return makeNext;\n }\n\n #makeMiddlewareIterator(): Iterator<\n JsonRpcMiddleware<Request, ResultConstraint<Request>, Context>\n > {\n return this.#middleware[Symbol.iterator]();\n }\n\n /**\n * Validate the result from a middleware and, if it's a new value, update the\n * current result.\n *\n * @param result - The result from the middleware.\n * @param state - The current values of the request and result.\n */\n #updateResult(\n result:\n | Readonly<ResultConstraint<Request>>\n | ResultConstraint<Request>\n | void,\n state: RequestState<Request>,\n ): void {\n if (isNotification(state.request) && result !== undefined) {\n throw new JsonRpcEngineError(\n `Result returned for notification: ${stringify(state.request)}`,\n );\n }\n\n if (result !== undefined && result !== state.result) {\n if (typeof result === 'object' && result !== null) {\n deepFreeze(result);\n }\n state.result = result;\n }\n }\n\n /**\n * Assert that a request modified by a middleware is valid.\n *\n * @param currentRequest - The current request.\n * @param nextRequest - The next request.\n */\n #assertValidNextRequest(currentRequest: Request, nextRequest: Request): void {\n if (nextRequest.jsonrpc !== currentRequest.jsonrpc) {\n throw new JsonRpcEngineError(\n `Middleware attempted to modify readonly property \"jsonrpc\" for request: ${stringify(currentRequest)}`,\n );\n }\n if (\n hasProperty(nextRequest, 'id') !== hasProperty(currentRequest, 'id') ||\n // @ts-expect-error - \"id\" does not exist on notifications, but we can still\n // check the value of the property at runtime.\n nextRequest.id !== currentRequest.id\n ) {\n throw new JsonRpcEngineError(\n `Middleware attempted to modify readonly property \"id\" for request: ${stringify(currentRequest)}`,\n );\n }\n }\n\n /**\n * Convert the engine into a JSON-RPC middleware.\n *\n * @returns The JSON-RPC middleware.\n */\n asMiddleware(): JsonRpcMiddleware<\n Request,\n ResultConstraint<Request>,\n Context\n > {\n this.#assertIsNotDestroyed();\n\n return async ({ request, context, next }) => {\n const { result, request: finalRequest } = await this.#handle(\n request,\n context,\n );\n return result === undefined ? await next(finalRequest) : result;\n };\n }\n\n /**\n * Destroy the engine. Calls the `destroy()` method of any middleware that has\n * one. Attempting to use the engine after destroying it will throw an error.\n */\n async destroy(): Promise<void> {\n if (this.#isDestroyed) {\n return;\n }\n this.#isDestroyed = true;\n\n const destructionPromise = Promise.all(\n this.#middleware.map(async (middleware) => {\n if (\n // Intentionally using `in` to walk the prototype chain.\n 'destroy' in middleware &&\n typeof middleware.destroy === 'function'\n ) {\n return middleware.destroy();\n }\n return undefined;\n }),\n );\n this.#middleware = [] as never;\n await destructionPromise;\n }\n\n #assertIsNotDestroyed(): void {\n if (this.#isDestroyed) {\n throw new JsonRpcEngineError('Engine is destroyed');\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"JsonRpcEngineV2.mjs","sourceRoot":"","sources":["../../src/v2/JsonRpcEngineV2.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AAAA,OAAO,EAKL,WAAW,EACZ,wBAAwB;AACzB,OAAO,WAAU,2BAA2B;;AAO5C,OAAO,EAAE,iBAAiB,EAAE,gCAA4B;AACxD,OAAO,EACL,cAAc,EACd,SAAS,EACT,kBAAkB,EAClB,SAAS,EACV,oBAAgB;AAqGjB,MAAM,cAAc,GAAG,MAAM,CAAC,gBAAgB,CAAC,CAAC;AAShD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,MAAM,OAAO,eAAe;IAY1B,yCAAyC;IACzC,YAAoB,EAAE,UAAU,EAAwC;;QATxE,8CAIE;QAEF,uCAAe,KAAK,EAAC;QAInB,uBAAA,IAAI,+BAAe,CAAC,GAAG,UAAU,CAAC,MAAA,CAAC;IACrC,CAAC;IAED,+FAA+F;IAC/F,6FAA6F;IAC7F,iBAAiB;IACjB;;;;;;;OAOG;IACH,MAAM,CAAC,MAAM,CASX,EAAE,UAAU,EAAgC;QAC5C,6EAA6E;QAC7E,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE;YAC3B,MAAM,IAAI,kBAAkB,CAAC,kCAAkC,CAAC,CAAC;SAClE;QAID,MAAM,EAAE,GAAG,UAMV,CAAC;QACF,OAAO,IAAI,eAAe,CAA8B;YACtD,UAAU,EAAE,EAAE;SACf,CAE+C,CAAC;IACnD,CAAC;IAqDD,KAAK,CAAC,MAAM,CACV,OAAgB,EAChB,EAAE,OAAO,KAA6B,EAAE;QAExC,MAAM,KAAK,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC;QACjC,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,uBAAA,IAAI,2DAAQ,MAAZ,IAAI,EAAS,OAAO,EAAE,OAAO,CAAC,CAAC;QAExD,IAAI,KAAK,IAAI,MAAM,KAAK,SAAS,EAAE;YACjC,MAAM,IAAI,kBAAkB,CAC1B,0BAA0B,SAAS,CAAC,OAAO,CAAC,EAAE,CAC/C,CAAC;SACH;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IA8JD;;;;OAIG;IACH,YAAY;QAKV,uBAAA,IAAI,yEAAsB,MAA1B,IAAI,CAAwB,CAAC;QAE7B,OAAO,KAAK,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE;YAC1C,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,GAAG,MAAM,uBAAA,IAAI,2DAAQ,MAAZ,IAAI,EAClD,OAAO,EACP,OAAO,CACR,CAAC;YACF,OAAO,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;QAClE,CAAC,CAAC;IACJ,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,OAAO;QACX,IAAI,uBAAA,IAAI,oCAAa,EAAE;YACrB,OAAO;SACR;QACD,uBAAA,IAAI,gCAAgB,IAAI,MAAA,CAAC;QAEzB,MAAM,kBAAkB,GAAG,OAAO,CAAC,GAAG,CACpC,uBAAA,IAAI,mCAAY,CAAC,GAAG,CAAC,KAAK,EAAE,UAAU,EAAE,EAAE;YACxC;YACE,wDAAwD;YACxD,SAAS,IAAI,UAAU;gBACvB,OAAO,UAAU,CAAC,OAAO,KAAK,UAAU,EACxC;gBACA,OAAO,UAAU,CAAC,OAAO,EAAE,CAAC;aAC7B;YACD,OAAO,SAAS,CAAC;QACnB,CAAC,CAAC,CACH,CAAC;QACF,uBAAA,IAAI,+BAAe,EAAW,MAAA,CAAC;QAC/B,MAAM,kBAAkB,CAAC;IAC3B,CAAC;CAOF;;AAhNC;;;;;;;GAOG;AACH,KAAK,kCACH,eAAwB,EACxB,aAE8B,IAAI,iBAAiB,EAAa;IAEhE,uBAAA,IAAI,yEAAsB,MAA1B,IAAI,CAAwB,CAAC;IAE7B,UAAU,CAAC,eAAe,CAAC,CAAC;IAE5B,MAAM,KAAK,GAA0B;QACnC,OAAO,EAAE,eAAe;QACxB,MAAM,EAAE,SAAS;KAClB,CAAC;IACF,MAAM,kBAAkB,GAAG,uBAAA,IAAI,2EAAwB,MAA5B,IAAI,CAA0B,CAAC;IAC1D,MAAM,eAAe,GAAG,kBAAkB,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC;IACxD,MAAM,OAAO,GAAG,iBAAiB,CAAC,UAAU,CAAC,UAAU,CAAC;QACtD,CAAC,CAAC,UAAU;QACZ,CAAC,CAAE,IAAI,iBAAiB,CAAC,UAAU,CAAa,CAAC;IAEnD,MAAM,QAAQ,GAAG,uBAAA,IAAI,oEAAiB,MAArB,IAAI,EAAkB,kBAAkB,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;IAE3E,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC;QACnC,OAAO,EAAE,eAAe;QACxB,OAAO;QACP,IAAI,EAAE,QAAQ,EAAE;KACjB,CAAC,CAAC;IACH,uBAAA,IAAI,iEAAc,MAAlB,IAAI,EAAe,MAAM,EAAE,KAAK,CAAC,CAAC;IAElC,OAAO,KAAK,CAAC;AACf,CAAC,+EAcC,kBAEC,EACD,KAA4B,EAC5B,OAAgB;IAEhB,MAAM,QAAQ,GAAG,GAAkB,EAAE;QACnC,IAAI,SAAS,GAAG,KAAK,CAAC;QAEtB,MAAM,IAAI,GAAG,KAAK,EAChB,UAAmB,KAAK,CAAC,OAAO,EAC0B,EAAE;YAC5D,IAAI,SAAS,EAAE;gBACb,MAAM,IAAI,kBAAkB,CAC1B,mEAAmE,SAAS,CAAC,OAAO,CAAC,EAAE,CACxF,CAAC;aACH;YACD,SAAS,GAAG,IAAI,CAAC;YAEjB,IAAI,OAAO,KAAK,KAAK,CAAC,OAAO,EAAE;gBAC7B,uBAAA,IAAI,2EAAwB,MAA5B,IAAI,EAAyB,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;gBACrD,KAAK,CAAC,OAAO,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;aACrC;YAED,MAAM,EAAE,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,GAAG,kBAAkB,CAAC,IAAI,EAAE,CAAC;YAClE,IAAI,IAAI,EAAE;gBACR,2EAA2E;gBAC3E,4CAA4C;gBAC5C,OAAO,SAAS,CAAC;aAClB;YAED,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC;gBAClC,OAAO;gBACP,OAAO;gBACP,IAAI,EAAE,QAAQ,EAAE;aACjB,CAAC,CAAC;YACH,uBAAA,IAAI,iEAAc,MAAlB,IAAI,EAAe,MAAM,EAAE,KAAK,CAAC,CAAC;YAElC,OAAO,KAAK,CAAC,MAAM,CAAC;QACtB,CAAC,CAAC;QACF,OAAO,IAAI,CAAC;IACd,CAAC,CAAC;IAEF,OAAO,QAAQ,CAAC;AAClB,CAAC;IAKC,OAAO,uBAAA,IAAI,mCAAY,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;AAC7C,CAAC,yEAUC,MAGQ,EACR,KAA4B;IAE5B,IAAI,cAAc,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,MAAM,KAAK,SAAS,EAAE;QACzD,MAAM,IAAI,kBAAkB,CAC1B,qCAAqC,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAChE,CAAC;KACH;IAED,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,KAAK,KAAK,CAAC,MAAM,EAAE;QACnD,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,EAAE;YACjD,UAAU,CAAC,MAAM,CAAC,CAAC;SACpB;QACD,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC;KACvB;AACH,CAAC,6FAQuB,cAAuB,EAAE,WAAoB;IACnE,IAAI,WAAW,CAAC,OAAO,KAAK,cAAc,CAAC,OAAO,EAAE;QAClD,MAAM,IAAI,kBAAkB,CAC1B,2EAA2E,SAAS,CAAC,cAAc,CAAC,EAAE,CACvG,CAAC;KACH;IACD,IACE,WAAW,CAAC,WAAW,EAAE,IAAI,CAAC,KAAK,WAAW,CAAC,cAAc,EAAE,IAAI,CAAC;QACpE,4EAA4E;QAC5E,8CAA8C;QAC9C,WAAW,CAAC,EAAE,KAAK,cAAc,CAAC,EAAE,EACpC;QACA,MAAM,IAAI,kBAAkB,CAC1B,sEAAsE,SAAS,CAAC,cAAc,CAAC,EAAE,CAClG,CAAC;KACH;AACH,CAAC;IAkDC,IAAI,uBAAA,IAAI,oCAAa,EAAE;QACrB,MAAM,IAAI,kBAAkB,CAAC,qBAAqB,CAAC,CAAC;KACrD;AACH,CAAC","sourcesContent":["import {\n type Json,\n type JsonRpcRequest,\n type JsonRpcNotification,\n type NonEmptyArray,\n hasProperty,\n} from '@metamask/utils';\nimport deepFreeze from 'deep-freeze-strict';\n\nimport type {\n ContextConstraint,\n InferKeyValues,\n MergeContexts,\n} from './MiddlewareContext';\nimport { MiddlewareContext } from './MiddlewareContext';\nimport {\n isNotification,\n isRequest,\n JsonRpcEngineError,\n stringify,\n} from './utils';\nimport type { JsonRpcCall } from './utils';\n\n// Helper to forbid `id` on notifications\ntype WithoutId<Request extends JsonRpcCall> = Request & { id?: never };\n\n// Helper to enable JsonRpcCall overload of handle()\ntype MixedParam<Request extends JsonRpcCall> = [\n Extract<Request, JsonRpcRequest>,\n] extends [never]\n ? never\n : [Extract<Request, JsonRpcNotification>] extends [never]\n ? never\n :\n | Extract<Request, JsonRpcRequest>\n | WithoutId<Extract<Request, JsonRpcNotification>>;\n\nexport type ResultConstraint<Request extends JsonRpcCall> =\n Request extends JsonRpcRequest ? Json : void;\n\nexport type Next<Request extends JsonRpcCall> = (\n request?: Readonly<Request>,\n) => Promise<Readonly<ResultConstraint<Request>> | undefined>;\n\nexport type MiddlewareParams<\n Request extends JsonRpcCall = JsonRpcCall,\n Context extends ContextConstraint = MiddlewareContext,\n> = {\n request: Readonly<Request>;\n context: Context;\n next: Next<Request>;\n};\n\nexport type JsonRpcMiddleware<\n Request extends JsonRpcCall = JsonRpcCall,\n Result extends ResultConstraint<Request> = ResultConstraint<Request>,\n Context extends ContextConstraint = MiddlewareContext,\n> = (\n params: MiddlewareParams<Request, Context>,\n) => Readonly<Result> | undefined | Promise<Readonly<Result> | undefined>;\n\ntype RequestState<Request extends JsonRpcCall> = {\n request: Request;\n result: Readonly<ResultConstraint<Request>> | undefined;\n};\n\n/**\n * The options for the JSON-RPC request/notification handling operation.\n */\nexport type HandleOptions<Context extends ContextConstraint> = {\n context?: Context | InferKeyValues<Context>;\n};\n\ntype ConstructorOptions<\n Request extends JsonRpcCall,\n Context extends MiddlewareContext,\n> = {\n middleware: NonEmptyArray<\n JsonRpcMiddleware<Request, ResultConstraint<Request>, Context>\n >;\n};\n\n/**\n * The request type of a middleware.\n */\nexport type RequestOf<Middleware> =\n Middleware extends JsonRpcMiddleware<\n infer Request,\n ResultConstraint<infer Request>,\n // Non-polluting `any` constraint.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n any\n >\n ? Request\n : never;\n\ntype ContextOf<Middleware> =\n // Non-polluting `any` constraint.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n Middleware extends JsonRpcMiddleware<any, ResultConstraint<any>, infer C>\n ? C\n : never;\n\n/**\n * A constraint for {@link JsonRpcMiddleware} generic parameters.\n */\n// Non-polluting `any` constraint.\n/* eslint-disable @typescript-eslint/no-explicit-any */\nexport type MiddlewareConstraint = JsonRpcMiddleware<\n any,\n ResultConstraint<any>,\n MiddlewareContext<any>\n>;\n/* eslint-enable @typescript-eslint/no-explicit-any */\n\n/**\n * The context supertype of a middleware type.\n */\nexport type MergedContextOf<Middleware extends MiddlewareConstraint> =\n MergeContexts<ContextOf<Middleware>>;\n\nconst INVALID_ENGINE = Symbol('Invalid engine');\n\n/**\n * An internal type for invalid engines that explains why the engine is invalid.\n *\n * @template Message - The message explaining why the engine is invalid.\n */\ntype InvalidEngine<Message extends string> = { [INVALID_ENGINE]: Message };\n\n/**\n * A JSON-RPC request and response processor.\n *\n * Give it a stack of middleware, pass it requests, and get back responses.\n *\n * #### Requests vs. notifications\n *\n * JSON-RPC requests come in two flavors:\n *\n * - [Requests](https://www.jsonrpc.org/specification#request_object), i.e. request objects _with_ an `id`\n * - [Notifications](https://www.jsonrpc.org/specification#notification), i.e. request objects _without_ an `id`\n *\n * For requests, one of the engine's middleware must \"end\" the request by returning a non-`undefined` result,\n * or {@link handle} will throw an error:\n *\n * For notifications, on the other hand, one of the engine's middleware must return `undefined` to end the request,\n * and any non-`undefined` return values will cause an error:\n *\n * @template Request - The type of request to handle.\n * @template Result - The type of result to return.\n *\n * @example\n * ```ts\n * const engine = JsonRpcEngineV2.create({\n * middleware,\n * });\n *\n * try {\n * const result = await engine.handle(request);\n * // Handle result\n * } catch (error) {\n * // Handle error\n * }\n * ```\n */\nexport class JsonRpcEngineV2<\n Request extends JsonRpcCall = JsonRpcCall,\n Context extends ContextConstraint = MiddlewareContext,\n> {\n #middleware: Readonly<\n NonEmptyArray<\n JsonRpcMiddleware<Request, ResultConstraint<Request>, Context>\n >\n >;\n\n #isDestroyed = false;\n\n // See .create() for why this is private.\n private constructor({ middleware }: ConstructorOptions<Request, Context>) {\n this.#middleware = [...middleware];\n }\n\n // We use a static factory method in order to construct a supertype of all middleware contexts,\n // which enables us to instantiate an engine despite different middleware expecting different\n // context types.\n /**\n * Create a new JSON-RPC engine.\n *\n * @throws If the middleware array is empty.\n * @param options - The options for the engine.\n * @param options.middleware - The middleware to use.\n * @returns The JSON-RPC engine.\n */\n static create<\n Middleware extends JsonRpcMiddleware<\n // Non-polluting `any` constraint.\n /* eslint-disable @typescript-eslint/no-explicit-any */\n any,\n ResultConstraint<any>,\n any\n /* eslint-enable @typescript-eslint/no-explicit-any */\n > = JsonRpcMiddleware,\n >({ middleware }: { middleware: Middleware[] }) {\n // We can't use NonEmptyArray for the params because it ruins type inference.\n if (middleware.length === 0) {\n throw new JsonRpcEngineError('Middleware array cannot be empty');\n }\n\n type MergedContext = MergedContextOf<Middleware>;\n type InputRequest = RequestOf<Middleware>;\n const mw = middleware as unknown as NonEmptyArray<\n JsonRpcMiddleware<\n InputRequest,\n ResultConstraint<InputRequest>,\n MergedContext\n >\n >;\n return new JsonRpcEngineV2<InputRequest, MergedContext>({\n middleware: mw,\n }) as MergedContext extends never\n ? InvalidEngine<'Some middleware have incompatible context types'>\n : JsonRpcEngineV2<InputRequest, MergedContext>;\n }\n\n /**\n * Handle a JSON-RPC request.\n *\n * @param request - The JSON-RPC request to handle.\n * @param options - The options for the handle operation.\n * @param options.context - The context to pass to the middleware.\n * @returns The JSON-RPC response.\n */\n async handle(\n request: Extract<Request, JsonRpcRequest> extends never\n ? never\n : Extract<Request, JsonRpcRequest>,\n options?: HandleOptions<Context>,\n ): Promise<\n Extract<Request, JsonRpcRequest> extends never\n ? never\n : ResultConstraint<Request>\n >;\n\n /**\n * Handle a JSON-RPC notification. Notifications do not return a result.\n *\n * @param notification - The JSON-RPC notification to handle.\n * @param options - The options for the handle operation.\n * @param options.context - The context to pass to the middleware.\n */\n async handle(\n notification: Extract<Request, JsonRpcNotification> extends never\n ? never\n : WithoutId<Extract<Request, JsonRpcNotification>>,\n options?: HandleOptions<Context>,\n ): Promise<\n Extract<Request, JsonRpcNotification> extends never\n ? never\n : ResultConstraint<Request>\n >;\n\n /**\n * Handle a JSON-RPC call, i.e. request or notification. Requests return a\n * result, notifications do not.\n *\n * @param call - The JSON-RPC call to handle.\n * @param options - The options for the handle operation.\n * @param options.context - The context to pass to the middleware.\n * @returns The JSON-RPC response, or `undefined` if the call is a notification.\n */\n async handle(\n call: MixedParam<Request>,\n options?: HandleOptions<Context>,\n ): Promise<ResultConstraint<Request> | void>;\n\n async handle(\n request: Request,\n { context }: HandleOptions<Context> = {},\n ): Promise<Readonly<ResultConstraint<Request>> | void> {\n const isReq = isRequest(request);\n const { result } = await this.#handle(request, context);\n\n if (isReq && result === undefined) {\n throw new JsonRpcEngineError(\n `Nothing ended request: ${stringify(request)}`,\n );\n }\n return result;\n }\n\n /**\n * Handle a JSON-RPC request. Throws if a middleware performs an invalid\n * operation. Permits returning an `undefined` result.\n *\n * @param originalRequest - The JSON-RPC request to handle.\n * @param rawContext - The context to pass to the middleware.\n * @returns The result from the middleware.\n */\n async #handle(\n originalRequest: Request,\n rawContext:\n | Context\n | InferKeyValues<Context> = new MiddlewareContext() as Context,\n ): Promise<RequestState<Request>> {\n this.#assertIsNotDestroyed();\n\n deepFreeze(originalRequest);\n\n const state: RequestState<Request> = {\n request: originalRequest,\n result: undefined,\n };\n const middlewareIterator = this.#makeMiddlewareIterator();\n const firstMiddleware = middlewareIterator.next().value;\n const context = MiddlewareContext.isInstance(rawContext)\n ? rawContext\n : (new MiddlewareContext(rawContext) as Context);\n\n const makeNext = this.#makeNextFactory(middlewareIterator, state, context);\n\n const result = await firstMiddleware({\n request: originalRequest,\n context,\n next: makeNext(),\n });\n this.#updateResult(result, state);\n\n return state;\n }\n\n /**\n * Create a factory of `next()` functions for use with a particular request.\n * The factory is recursive, and a new `next()` is created for each middleware\n * invocation.\n *\n * @param middlewareIterator - The iterator of middleware for the current\n * request.\n * @param state - The current values of the request and result.\n * @param context - The context to pass to the middleware.\n * @returns The `next()` function factory.\n */\n #makeNextFactory(\n middlewareIterator: Iterator<\n JsonRpcMiddleware<Request, ResultConstraint<Request>, Context>\n >,\n state: RequestState<Request>,\n context: Context,\n ): () => Next<Request> {\n const makeNext = (): Next<Request> => {\n let wasCalled = false;\n\n const next = async (\n request: Request = state.request,\n ): Promise<Readonly<ResultConstraint<Request>> | undefined> => {\n if (wasCalled) {\n throw new JsonRpcEngineError(\n `Middleware attempted to call next() multiple times for request: ${stringify(request)}`,\n );\n }\n wasCalled = true;\n\n if (request !== state.request) {\n this.#assertValidNextRequest(state.request, request);\n state.request = deepFreeze(request);\n }\n\n const { value: nextMiddleware, done } = middlewareIterator.next();\n if (done) {\n // This will cause the last middleware to return `undefined`. See the class\n // JSDoc or package README for more details.\n return undefined;\n }\n\n const result = await nextMiddleware({\n request,\n context,\n next: makeNext(),\n });\n this.#updateResult(result, state);\n\n return state.result;\n };\n return next;\n };\n\n return makeNext;\n }\n\n #makeMiddlewareIterator(): Iterator<\n JsonRpcMiddleware<Request, ResultConstraint<Request>, Context>\n > {\n return this.#middleware[Symbol.iterator]();\n }\n\n /**\n * Validate the result from a middleware and, if it's a new value, update the\n * current result.\n *\n * @param result - The result from the middleware.\n * @param state - The current values of the request and result.\n */\n #updateResult(\n result:\n | Readonly<ResultConstraint<Request>>\n | ResultConstraint<Request>\n | void,\n state: RequestState<Request>,\n ): void {\n if (isNotification(state.request) && result !== undefined) {\n throw new JsonRpcEngineError(\n `Result returned for notification: ${stringify(state.request)}`,\n );\n }\n\n if (result !== undefined && result !== state.result) {\n if (typeof result === 'object' && result !== null) {\n deepFreeze(result);\n }\n state.result = result;\n }\n }\n\n /**\n * Assert that a request modified by a middleware is valid.\n *\n * @param currentRequest - The current request.\n * @param nextRequest - The next request.\n */\n #assertValidNextRequest(currentRequest: Request, nextRequest: Request): void {\n if (nextRequest.jsonrpc !== currentRequest.jsonrpc) {\n throw new JsonRpcEngineError(\n `Middleware attempted to modify readonly property \"jsonrpc\" for request: ${stringify(currentRequest)}`,\n );\n }\n if (\n hasProperty(nextRequest, 'id') !== hasProperty(currentRequest, 'id') ||\n // @ts-expect-error - \"id\" does not exist on notifications, but we can still\n // check the value of the property at runtime.\n nextRequest.id !== currentRequest.id\n ) {\n throw new JsonRpcEngineError(\n `Middleware attempted to modify readonly property \"id\" for request: ${stringify(currentRequest)}`,\n );\n }\n }\n\n /**\n * Convert the engine into a JSON-RPC middleware.\n *\n * @returns The JSON-RPC middleware.\n */\n asMiddleware(): JsonRpcMiddleware<\n Request,\n ResultConstraint<Request>,\n Context\n > {\n this.#assertIsNotDestroyed();\n\n return async ({ request, context, next }) => {\n const { result, request: finalRequest } = await this.#handle(\n request,\n context,\n );\n return result === undefined ? await next(finalRequest) : result;\n };\n }\n\n /**\n * Destroy the engine. Calls the `destroy()` method of any middleware that has\n * one. Attempting to use the engine after destroying it will throw an error.\n */\n async destroy(): Promise<void> {\n if (this.#isDestroyed) {\n return;\n }\n this.#isDestroyed = true;\n\n const destructionPromise = Promise.all(\n this.#middleware.map(async (middleware) => {\n if (\n // Intentionally using `in` to walk the prototype chain.\n 'destroy' in middleware &&\n typeof middleware.destroy === 'function'\n ) {\n return middleware.destroy();\n }\n return undefined;\n }),\n );\n this.#middleware = [] as never;\n await destructionPromise;\n }\n\n #assertIsNotDestroyed(): void {\n if (this.#isDestroyed) {\n throw new JsonRpcEngineError('Engine is destroyed');\n }\n }\n}\n"]}
|