From c29239615114533eee273c61d45b4533d1a53a58 Mon Sep 17 00:00:00 2001 From: Frederik Bolding Date: Fri, 17 Apr 2026 12:59:14 +0200 Subject: [PATCH 1/9] feat: Add createMethodMiddleware function --- packages/json-rpc-engine/package.json | 1 + .../src/v2/createMethodMiddleware.test.ts | 48 +++++++++ .../src/v2/createMethodMiddleware.ts | 102 ++++++++++++++++++ packages/json-rpc-engine/src/v2/index.test.ts | 2 + packages/json-rpc-engine/src/v2/index.ts | 1 + packages/json-rpc-engine/tsconfig.build.json | 5 + packages/json-rpc-engine/tsconfig.json | 5 + yarn.lock | 1 + 8 files changed, 165 insertions(+) create mode 100644 packages/json-rpc-engine/src/v2/createMethodMiddleware.test.ts create mode 100644 packages/json-rpc-engine/src/v2/createMethodMiddleware.ts diff --git a/packages/json-rpc-engine/package.json b/packages/json-rpc-engine/package.json index 343ceabf715..f6b5e89cb03 100644 --- a/packages/json-rpc-engine/package.json +++ b/packages/json-rpc-engine/package.json @@ -70,6 +70,7 @@ "test:watch": "NODE_OPTIONS=--experimental-vm-modules jest --watch" }, "dependencies": { + "@metamask/messenger": "^1.1.1", "@metamask/rpc-errors": "^7.0.2", "@metamask/safe-event-emitter": "^3.0.0", "@metamask/utils": "^11.9.0", diff --git a/packages/json-rpc-engine/src/v2/createMethodMiddleware.test.ts b/packages/json-rpc-engine/src/v2/createMethodMiddleware.test.ts new file mode 100644 index 00000000000..d6df31da844 --- /dev/null +++ b/packages/json-rpc-engine/src/v2/createMethodMiddleware.test.ts @@ -0,0 +1,48 @@ +import { Messenger, MOCK_ANY_NAMESPACE } from '@metamask/messenger'; + +import { makeRequest } from '../../tests/utils'; +import { + createMethodMiddleware, + MethodHandler, +} from './createMethodMiddleware'; +import { JsonRpcEngineV2 } from './JsonRpcEngineV2'; + +const getValueA = { + hookNames: { testHook: true }, + implementation: ({ hooks }) => hooks.testHook(), +} satisfies MethodHandler; + +const getValueB = { + actionNames: ['Example:TestAction'], + implementation: ({ messenger }) => messenger.call('Example:TestAction'), +} satisfies MethodHandler; + +const messenger = new Messenger({ namespace: MOCK_ANY_NAMESPACE }); + +messenger.registerActionHandler('Example:TestAction', async () => 'B'); + +const middleware = createMethodMiddleware({ + handlers: { getValueA, getValueB }, + hooks: { testHook: async () => 'A' }, + messenger, +}); + +const engine = JsonRpcEngineV2.create({ middleware: [middleware] }); + +describe('createMethodMiddleware', () => { + it('passes in the requested hooks', async () => { + const result = await engine.handle(makeRequest({ method: 'getValueA' })); + expect(result).toBe('A'); + }); + + it('passes in a delegated messenger', async () => { + const result = await engine.handle(makeRequest({ method: 'getValueB' })); + expect(result).toBe('B'); + }); + + it('skips unrecognized methods', async () => { + await expect( + engine.handle(makeRequest({ method: 'getValueC' })), + ).rejects.toThrow('Nothing ended request'); + }); +}); diff --git a/packages/json-rpc-engine/src/v2/createMethodMiddleware.ts b/packages/json-rpc-engine/src/v2/createMethodMiddleware.ts new file mode 100644 index 00000000000..39c3a80fb0c --- /dev/null +++ b/packages/json-rpc-engine/src/v2/createMethodMiddleware.ts @@ -0,0 +1,102 @@ +import { Messenger } from '@metamask/messenger'; + +import { JsonRpcMiddleware, Next } from './JsonRpcEngineV2'; +import { ContextConstraint } from './MiddlewareContext'; +import { Json, JsonRpcRequest } from './utils'; + +export type MethodHandlerImplementation = (options: { + request: Readonly; + context: any; + next: Next; + messenger: Messenger; + hooks: any; +}) => Json; + +export type MethodHandler = { + implementation: MethodHandlerImplementation; + hookNames?: Record; + actionNames?: string[]; +}; + +export type CreateMethodMiddlewareOptions = { + handlers: Record; + messenger: Messenger; + hooks: Record; +}; + +type ResolvedHandler = { + implementation: MethodHandlerImplementation; + hooks: Record; + messenger: Messenger; +}; + +export function createMethodMiddleware( + options: CreateMethodMiddlewareOptions, +): JsonRpcMiddleware { + const { messenger: rootMessenger, hooks: allHooks } = options; + + const handlers = Object.entries(options.handlers).reduce< + Record + >((accumulator, [handlerName, handler]) => { + const handlerHooks = selectHooks(allHooks, handler.hookNames) ?? {}; + const handlerMessenger = new Messenger({ + namespace: handlerName, + parent: rootMessenger, + }); + + rootMessenger.delegate({ + actions: handler.actionNames ?? [], + messenger: handlerMessenger, + }); + + accumulator[handlerName] = { + implementation: handler.implementation, + hooks: handlerHooks, + messenger: handlerMessenger, + }; + return accumulator; + }, {}); + + return ({ request, context, next }) => { + const handler = handlers[request.method]; + if (handler === undefined) { + return next(); + } + + const { implementation, hooks, messenger } = handler; + + return implementation({ request, context, next, hooks, messenger }); + }; +} + +/** + * Returns the subset of the specified `hooks` that are included in the + * `hookNames` object. This is a Principle of Least Authority (POLA) measure + * to ensure that each RPC method implementation only has access to the + * API "hooks" it needs to do its job. + * + * @param hooks - The hooks to select from. + * @param hookNames - The names of the hooks to select. + * @returns The selected hooks. + * @template Hooks - The hooks to select from. + * @template HookName - The names of the hooks to select. + */ +export function selectHooks< + Hooks extends Record, + HookName extends keyof Hooks, +>( + hooks: Hooks, + hookNames?: Record, +): Pick | undefined { + if (hookNames) { + return Object.keys(hookNames).reduce>>( + (hookSubset, _hookName) => { + const hookName = _hookName as HookName; + hookSubset[hookName] = hooks[hookName]; + return hookSubset; + }, + {}, + ) as Pick; + } + return undefined; +} diff --git a/packages/json-rpc-engine/src/v2/index.test.ts b/packages/json-rpc-engine/src/v2/index.test.ts index a36b0ef1b99..cd406ad8a88 100644 --- a/packages/json-rpc-engine/src/v2/index.test.ts +++ b/packages/json-rpc-engine/src/v2/index.test.ts @@ -9,10 +9,12 @@ describe('@metamask/json-rpc-engine/v2', () => { "JsonRpcServer", "MiddlewareContext", "asLegacyMiddleware", + "createMethodMiddleware", "createScaffoldMiddleware", "getUniqueId", "isNotification", "isRequest", + "selectHooks", ] `); }); diff --git a/packages/json-rpc-engine/src/v2/index.ts b/packages/json-rpc-engine/src/v2/index.ts index 393b4244bd6..26f4976b496 100644 --- a/packages/json-rpc-engine/src/v2/index.ts +++ b/packages/json-rpc-engine/src/v2/index.ts @@ -1,5 +1,6 @@ export { asLegacyMiddleware } from './asLegacyMiddleware'; export { getUniqueId } from '../getUniqueId'; +export { selectHooks, createMethodMiddleware } from './createMethodMiddleware'; export { createScaffoldMiddleware } from './createScaffoldMiddleware'; export { JsonRpcEngineV2 } from './JsonRpcEngineV2'; export type { diff --git a/packages/json-rpc-engine/tsconfig.build.json b/packages/json-rpc-engine/tsconfig.build.json index 0df910b2151..6b68c1d0498 100644 --- a/packages/json-rpc-engine/tsconfig.build.json +++ b/packages/json-rpc-engine/tsconfig.build.json @@ -5,5 +5,10 @@ "outDir": "./dist", "rootDir": "./src" }, + "references": [ + { + "path": "../messenger/tsconfig.build.json" + } + ], "include": ["../../types", "./src"] } diff --git a/packages/json-rpc-engine/tsconfig.json b/packages/json-rpc-engine/tsconfig.json index 4e929aca4ee..b6e79d715bd 100644 --- a/packages/json-rpc-engine/tsconfig.json +++ b/packages/json-rpc-engine/tsconfig.json @@ -9,5 +9,10 @@ "noUncheckedIndexedAccess": true, "target": "es2020" }, + "references": [ + { + "path": "../messenger/tsconfig.json" + } + ], "include": ["../../types", "../../tests", "./src", "./tests"] } diff --git a/yarn.lock b/yarn.lock index b5a994e4dbf..f31b52556b2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4106,6 +4106,7 @@ __metadata: "@lavamoat/allow-scripts": "npm:^3.0.4" "@lavamoat/preinstall-always-fail": "npm:^2.1.0" "@metamask/auto-changelog": "npm:^6.1.0" + "@metamask/messenger": "npm:^1.1.1" "@metamask/rpc-errors": "npm:^7.0.2" "@metamask/safe-event-emitter": "npm:^3.0.0" "@metamask/utils": "npm:^11.9.0" From fa6a271c71fbac6a279ab0fd1094a8a851471c1c Mon Sep 17 00:00:00 2001 From: Frederik Bolding Date: Fri, 17 Apr 2026 13:41:50 +0200 Subject: [PATCH 2/9] Attempt to improve typing --- .../src/v2/createMethodMiddleware.test.ts | 14 +++- .../src/v2/createMethodMiddleware.ts | 71 ++++++++++++++----- 2 files changed, 63 insertions(+), 22 deletions(-) diff --git a/packages/json-rpc-engine/src/v2/createMethodMiddleware.test.ts b/packages/json-rpc-engine/src/v2/createMethodMiddleware.test.ts index d6df31da844..159de7861c9 100644 --- a/packages/json-rpc-engine/src/v2/createMethodMiddleware.test.ts +++ b/packages/json-rpc-engine/src/v2/createMethodMiddleware.test.ts @@ -1,4 +1,5 @@ import { Messenger, MOCK_ANY_NAMESPACE } from '@metamask/messenger'; +import { JsonRpcParams } from '@metamask/utils'; import { makeRequest } from '../../tests/utils'; import { @@ -7,17 +8,24 @@ import { } from './createMethodMiddleware'; import { JsonRpcEngineV2 } from './JsonRpcEngineV2'; +type TestAction = { + type: 'Example:TestAction'; + handler: () => Promise; +}; + const getValueA = { hookNames: { testHook: true }, implementation: ({ hooks }) => hooks.testHook(), -} satisfies MethodHandler; +} satisfies MethodHandler<{ testHook: () => Promise }>; const getValueB = { actionNames: ['Example:TestAction'], implementation: ({ messenger }) => messenger.call('Example:TestAction'), -} satisfies MethodHandler; +} satisfies MethodHandler; -const messenger = new Messenger({ namespace: MOCK_ANY_NAMESPACE }); +const messenger = new Messenger({ + namespace: MOCK_ANY_NAMESPACE, +}); messenger.registerActionHandler('Example:TestAction', async () => 'B'); diff --git a/packages/json-rpc-engine/src/v2/createMethodMiddleware.ts b/packages/json-rpc-engine/src/v2/createMethodMiddleware.ts index 39c3a80fb0c..278e7472d86 100644 --- a/packages/json-rpc-engine/src/v2/createMethodMiddleware.ts +++ b/packages/json-rpc-engine/src/v2/createMethodMiddleware.ts @@ -1,37 +1,70 @@ -import { Messenger } from '@metamask/messenger'; +import { ActionConstraint, Messenger } from '@metamask/messenger'; import { JsonRpcMiddleware, Next } from './JsonRpcEngineV2'; import { ContextConstraint } from './MiddlewareContext'; -import { Json, JsonRpcRequest } from './utils'; +import { Json, JsonRpcParams, JsonRpcRequest } from './utils'; -export type MethodHandlerImplementation = (options: { - request: Readonly; - context: any; +type HandlerActions = + Handler extends MethodHandler ? Actions : never; + +export type MethodHandlerImplementation< + Hooks extends Record = Record, + Parameters extends JsonRpcParams = JsonRpcParams, + MessengerActions extends ActionConstraint = never, + Context extends ContextConstraint = ContextConstraint, +> = (options: { + request: Readonly>; + context: Context; next: Next; - messenger: Messenger; - hooks: any; -}) => Json; + messenger: Messenger; + hooks: Hooks; +}) => Promise | Json; -export type MethodHandler = { - implementation: MethodHandlerImplementation; - hookNames?: Record; - actionNames?: string[]; +export type MethodHandler< + Hooks extends Record = Record, + Parameters extends JsonRpcParams = JsonRpcParams, + MessengerActions extends ActionConstraint = never, + Context extends ContextConstraint = ContextConstraint, +> = { + implementation: MethodHandlerImplementation< + Hooks, + Parameters, + MessengerActions, + Context + >; + hookNames?: { [Key in keyof Hooks]: true }; + actionNames?: MessengerActions['type'][]; }; -export type CreateMethodMiddlewareOptions = { +export type CreateMethodMiddlewareOptions< + Handlers extends Record, +> = { handlers: Record; - messenger: Messenger; + messenger: Messenger>; hooks: Record; }; -type ResolvedHandler = { - implementation: MethodHandlerImplementation; +type ResolvedHandler< + Hooks extends Record = Record, + Parameters extends JsonRpcParams = JsonRpcParams, + MessengerActions extends ActionConstraint = never, + Context extends ContextConstraint = ContextConstraint, +> = { + implementation: MethodHandlerImplementation< + Hooks, + Parameters, + MessengerActions, + Context + >; hooks: Record; - messenger: Messenger; + messenger: Messenger; }; -export function createMethodMiddleware( - options: CreateMethodMiddlewareOptions, +export function createMethodMiddleware< + Handlers extends Record, + Context extends ContextConstraint, +>( + options: CreateMethodMiddlewareOptions, ): JsonRpcMiddleware { const { messenger: rootMessenger, hooks: allHooks } = options; From 9420d624fa5ebcdf5aafc801d523e7bd0a8eebe7 Mon Sep 17 00:00:00 2001 From: Frederik Bolding Date: Fri, 17 Apr 2026 13:42:08 +0200 Subject: [PATCH 3/9] Update README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 83f276c0a04..918e9a8b984 100644 --- a/README.md +++ b/README.md @@ -345,6 +345,7 @@ linkStyle default opacity:0.5 geolocation_controller --> base_controller; geolocation_controller --> controller_utils; geolocation_controller --> messenger; + json_rpc_engine --> messenger; json_rpc_middleware_stream --> json_rpc_engine; keyring_controller --> base_controller; keyring_controller --> messenger; From 6ac9eb98e5b18bb179f0ce5262e3d33f79dfa123 Mon Sep 17 00:00:00 2001 From: Frederik Bolding Date: Fri, 17 Apr 2026 15:06:35 +0200 Subject: [PATCH 4/9] More type improvements --- .../src/v2/createMethodMiddleware.test.ts | 8 +++--- .../src/v2/createMethodMiddleware.ts | 26 ++++++++++++------- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/packages/json-rpc-engine/src/v2/createMethodMiddleware.test.ts b/packages/json-rpc-engine/src/v2/createMethodMiddleware.test.ts index 159de7861c9..5b0a8af573a 100644 --- a/packages/json-rpc-engine/src/v2/createMethodMiddleware.test.ts +++ b/packages/json-rpc-engine/src/v2/createMethodMiddleware.test.ts @@ -1,5 +1,4 @@ import { Messenger, MOCK_ANY_NAMESPACE } from '@metamask/messenger'; -import { JsonRpcParams } from '@metamask/utils'; import { makeRequest } from '../../tests/utils'; import { @@ -15,13 +14,14 @@ type TestAction = { const getValueA = { hookNames: { testHook: true }, - implementation: ({ hooks }) => hooks.testHook(), + implementation: ({ hooks }): Promise => hooks.testHook(), } satisfies MethodHandler<{ testHook: () => Promise }>; const getValueB = { actionNames: ['Example:TestAction'], - implementation: ({ messenger }) => messenger.call('Example:TestAction'), -} satisfies MethodHandler; + implementation: ({ messenger }): Promise => + messenger.call('Example:TestAction'), +} satisfies MethodHandler; const messenger = new Messenger({ namespace: MOCK_ANY_NAMESPACE, diff --git a/packages/json-rpc-engine/src/v2/createMethodMiddleware.ts b/packages/json-rpc-engine/src/v2/createMethodMiddleware.ts index 278e7472d86..493fe23a08b 100644 --- a/packages/json-rpc-engine/src/v2/createMethodMiddleware.ts +++ b/packages/json-rpc-engine/src/v2/createMethodMiddleware.ts @@ -5,12 +5,16 @@ import { ContextConstraint } from './MiddlewareContext'; import { Json, JsonRpcParams, JsonRpcRequest } from './utils'; type HandlerActions = - Handler extends MethodHandler ? Actions : never; + Handler extends MethodHandler, infer Actions> ? Actions : never; + +type HandlerHooks = + Handler extends MethodHandler ? Hooks : never; export type MethodHandlerImplementation< Hooks extends Record = Record, - Parameters extends JsonRpcParams = JsonRpcParams, MessengerActions extends ActionConstraint = never, + Parameters extends JsonRpcParams = JsonRpcParams, + Result extends Json = Json, Context extends ContextConstraint = ContextConstraint, > = (options: { request: Readonly>; @@ -18,18 +22,20 @@ export type MethodHandlerImplementation< next: Next; messenger: Messenger; hooks: Hooks; -}) => Promise | Json; +}) => Promise | Result; export type MethodHandler< Hooks extends Record = Record, - Parameters extends JsonRpcParams = JsonRpcParams, MessengerActions extends ActionConstraint = never, + Parameters extends JsonRpcParams = JsonRpcParams, + Result extends Json = Json, Context extends ContextConstraint = ContextConstraint, > = { implementation: MethodHandlerImplementation< Hooks, - Parameters, MessengerActions, + Parameters, + Result, Context >; hookNames?: { [Key in keyof Hooks]: true }; @@ -39,21 +45,23 @@ export type MethodHandler< export type CreateMethodMiddlewareOptions< Handlers extends Record, > = { - handlers: Record; + handlers: Handlers; messenger: Messenger>; - hooks: Record; + hooks: HandlerHooks; }; type ResolvedHandler< Hooks extends Record = Record, - Parameters extends JsonRpcParams = JsonRpcParams, MessengerActions extends ActionConstraint = never, + Parameters extends JsonRpcParams = JsonRpcParams, + Result extends Json = Json, Context extends ContextConstraint = ContextConstraint, > = { implementation: MethodHandlerImplementation< Hooks, - Parameters, MessengerActions, + Parameters, + Result, Context >; hooks: Record; From 29ad6550497335a5a49319fb936246cfff5112d3 Mon Sep 17 00:00:00 2001 From: Frederik Bolding Date: Mon, 20 Apr 2026 11:54:07 +0200 Subject: [PATCH 5/9] More typing --- .../src/v2/createMethodMiddleware.ts | 98 ++++++++++--------- 1 file changed, 53 insertions(+), 45 deletions(-) diff --git a/packages/json-rpc-engine/src/v2/createMethodMiddleware.ts b/packages/json-rpc-engine/src/v2/createMethodMiddleware.ts index 493fe23a08b..b8112ad0295 100644 --- a/packages/json-rpc-engine/src/v2/createMethodMiddleware.ts +++ b/packages/json-rpc-engine/src/v2/createMethodMiddleware.ts @@ -4,25 +4,22 @@ import { JsonRpcMiddleware, Next } from './JsonRpcEngineV2'; import { ContextConstraint } from './MiddlewareContext'; import { Json, JsonRpcParams, JsonRpcRequest } from './utils'; -type HandlerActions = - Handler extends MethodHandler, infer Actions> ? Actions : never; - -type HandlerHooks = - Handler extends MethodHandler ? Hooks : never; +// The helpers below seem excessive, but they are required for inference of hooks/actions. +type HandlerActions = Handler extends { + implementation: (options: infer Options) => unknown; +} + ? Options extends { messenger: Messenger } + ? Actions + : never + : never; -export type MethodHandlerImplementation< - Hooks extends Record = Record, - MessengerActions extends ActionConstraint = never, - Parameters extends JsonRpcParams = JsonRpcParams, - Result extends Json = Json, - Context extends ContextConstraint = ContextConstraint, -> = (options: { - request: Readonly>; - context: Context; - next: Next; - messenger: Messenger; - hooks: Hooks; -}) => Promise | Result; +type HandlerHooks = Handler extends { + implementation: (options: infer Options) => unknown; +} + ? Options extends { hooks: infer Hooks } + ? Hooks + : never + : never; export type MethodHandler< Hooks extends Record = Record, @@ -31,62 +28,73 @@ export type MethodHandler< Result extends Json = Json, Context extends ContextConstraint = ContextConstraint, > = { - implementation: MethodHandlerImplementation< - Hooks, - MessengerActions, - Parameters, - Result, - Context - >; + implementation: (options: { + request: Readonly>; + context: Context; + next: Next; + messenger: Messenger; + hooks: Hooks; + }) => Promise | Result; hookNames?: { [Key in keyof Hooks]: true }; actionNames?: MessengerActions['type'][]; }; +type AnyMethodHandler = { + implementation( + this: void, + options: { + request: Readonly; + context: ContextConstraint; + next: Next; + messenger: unknown; + hooks: unknown; + }, + ): Promise | Json; + hookNames?: Record; + actionNames?: readonly string[]; +}; + export type CreateMethodMiddlewareOptions< - Handlers extends Record, + Handlers extends Record, > = { handlers: Handlers; messenger: Messenger>; hooks: HandlerHooks; }; -type ResolvedHandler< - Hooks extends Record = Record, - MessengerActions extends ActionConstraint = never, - Parameters extends JsonRpcParams = JsonRpcParams, - Result extends Json = Json, - Context extends ContextConstraint = ContextConstraint, -> = { - implementation: MethodHandlerImplementation< - Hooks, - MessengerActions, - Parameters, - Result, - Context - >; +type ResolvedHandler = { + implementation: AnyMethodHandler['implementation']; hooks: Record; - messenger: Messenger; + messenger: Messenger; }; export function createMethodMiddleware< - Handlers extends Record, + Handlers extends Record, Context extends ContextConstraint, >( options: CreateMethodMiddlewareOptions, ): JsonRpcMiddleware { - const { messenger: rootMessenger, hooks: allHooks } = options; + const { messenger: rootMessenger } = options; + const allHooks = options.hooks as Record; const handlers = Object.entries(options.handlers).reduce< Record >((accumulator, [handlerName, handler]) => { const handlerHooks = selectHooks(allHooks, handler.hookNames) ?? {}; - const handlerMessenger = new Messenger({ + const handlerMessenger = new Messenger< + string, + HandlerActions, + never, + typeof rootMessenger + >({ namespace: handlerName, parent: rootMessenger, }); rootMessenger.delegate({ - actions: handler.actionNames ?? [], + actions: (handler.actionNames ?? []) as HandlerActions< + Handlers[keyof Handlers] + >['type'][], messenger: handlerMessenger, }); From 34ff78d3f8a705708a65aba6f5efac8739ad9241 Mon Sep 17 00:00:00 2001 From: Frederik Bolding Date: Mon, 20 Apr 2026 12:01:24 +0200 Subject: [PATCH 6/9] Update CHANGELOG --- packages/json-rpc-engine/CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/json-rpc-engine/CHANGELOG.md b/packages/json-rpc-engine/CHANGELOG.md index 19f9bd77b2f..14411f2039e 100644 --- a/packages/json-rpc-engine/CHANGELOG.md +++ b/packages/json-rpc-engine/CHANGELOG.md @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- Add `createMethodMiddleware` ([#8506](https://github.com/MetaMask/core/pull/8506)) + - This utility allows JSON-RPC method implementations to use both the hooks pattern and the messenger. + ## [10.2.4] ### Fixed From 7f288dc32b8c08df4aefd1174e647527ae228b75 Mon Sep 17 00:00:00 2001 From: Frederik Bolding Date: Mon, 20 Apr 2026 12:05:31 +0200 Subject: [PATCH 7/9] Add JSDoc --- .../json-rpc-engine/src/v2/createMethodMiddleware.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/json-rpc-engine/src/v2/createMethodMiddleware.ts b/packages/json-rpc-engine/src/v2/createMethodMiddleware.ts index b8112ad0295..f4e570c4337 100644 --- a/packages/json-rpc-engine/src/v2/createMethodMiddleware.ts +++ b/packages/json-rpc-engine/src/v2/createMethodMiddleware.ts @@ -68,6 +68,15 @@ type ResolvedHandler = { messenger: Messenger; }; +/** + * Create a JSON-RPC middleware that handles the passed JSON-RPC method handlers using the messenger and hooks. + * + * @param options The options. + * @param options.handlers - The JSON-RPC method handler implementations. + * @param options.messenger - The messenger to be used by the handlers. + * @param options.hooks - The hooks to be used by the handlers. + * @returns A JsonRpcEngineV2 middleware. + */ export function createMethodMiddleware< Handlers extends Record, Context extends ContextConstraint, From 9ad6497d3990d429ae0a4477ad7917446b9ab02d Mon Sep 17 00:00:00 2001 From: Frederik Bolding Date: Mon, 20 Apr 2026 12:08:42 +0200 Subject: [PATCH 8/9] Fix lint --- packages/json-rpc-engine/src/v2/createMethodMiddleware.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/json-rpc-engine/src/v2/createMethodMiddleware.ts b/packages/json-rpc-engine/src/v2/createMethodMiddleware.ts index f4e570c4337..230a1910138 100644 --- a/packages/json-rpc-engine/src/v2/createMethodMiddleware.ts +++ b/packages/json-rpc-engine/src/v2/createMethodMiddleware.ts @@ -70,11 +70,11 @@ type ResolvedHandler = { /** * Create a JSON-RPC middleware that handles the passed JSON-RPC method handlers using the messenger and hooks. - * + * * @param options The options. * @param options.handlers - The JSON-RPC method handler implementations. * @param options.messenger - The messenger to be used by the handlers. - * @param options.hooks - The hooks to be used by the handlers. + * @param options.hooks - The hooks to be used by the handlers. * @returns A JsonRpcEngineV2 middleware. */ export function createMethodMiddleware< From fb74b9fe082847ca4280478dc23613d10ce3d288 Mon Sep 17 00:00:00 2001 From: Frederik Bolding Date: Mon, 20 Apr 2026 12:55:34 +0200 Subject: [PATCH 9/9] Fix BugBot comments --- .../json-rpc-engine/src/v2/createMethodMiddleware.ts | 9 +++++++-- packages/json-rpc-engine/src/v2/index.ts | 1 + 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/json-rpc-engine/src/v2/createMethodMiddleware.ts b/packages/json-rpc-engine/src/v2/createMethodMiddleware.ts index 230a1910138..1e9bd87f97e 100644 --- a/packages/json-rpc-engine/src/v2/createMethodMiddleware.ts +++ b/packages/json-rpc-engine/src/v2/createMethodMiddleware.ts @@ -2,7 +2,12 @@ import { ActionConstraint, Messenger } from '@metamask/messenger'; import { JsonRpcMiddleware, Next } from './JsonRpcEngineV2'; import { ContextConstraint } from './MiddlewareContext'; -import { Json, JsonRpcParams, JsonRpcRequest } from './utils'; +import { + Json, + JsonRpcParams, + JsonRpcRequest, + UnionToIntersection, +} from './utils'; // The helpers below seem excessive, but they are required for inference of hooks/actions. type HandlerActions = Handler extends { @@ -59,7 +64,7 @@ export type CreateMethodMiddlewareOptions< > = { handlers: Handlers; messenger: Messenger>; - hooks: HandlerHooks; + hooks: UnionToIntersection>; }; type ResolvedHandler = { diff --git a/packages/json-rpc-engine/src/v2/index.ts b/packages/json-rpc-engine/src/v2/index.ts index 26f4976b496..a5046e591d5 100644 --- a/packages/json-rpc-engine/src/v2/index.ts +++ b/packages/json-rpc-engine/src/v2/index.ts @@ -1,6 +1,7 @@ export { asLegacyMiddleware } from './asLegacyMiddleware'; export { getUniqueId } from '../getUniqueId'; export { selectHooks, createMethodMiddleware } from './createMethodMiddleware'; +export type { MethodHandler } from './createMethodMiddleware'; export { createScaffoldMiddleware } from './createScaffoldMiddleware'; export { JsonRpcEngineV2 } from './JsonRpcEngineV2'; export type {