diff --git a/README.md b/README.md index 0b377cff988..199eb689d94 100644 --- a/README.md +++ b/README.md @@ -201,8 +201,8 @@ linkStyle default opacity:0.5 chain_agnostic_permission --> permission_controller; composable_controller --> base_controller; composable_controller --> json_rpc_engine; - core_backend --> base_controller; core_backend --> controller_utils; + core_backend --> messenger; core_backend --> profile_sync_controller; core_backend --> accounts_controller; core_backend --> keyring_controller; @@ -216,6 +216,7 @@ linkStyle default opacity:0.5 earn_controller --> transaction_controller; eip_5792_middleware --> transaction_controller; eip_5792_middleware --> keyring_controller; + eip_7702_internal_rpc_middleware --> controller_utils; eip1193_permission_middleware --> chain_agnostic_permission; eip1193_permission_middleware --> controller_utils; eip1193_permission_middleware --> json_rpc_engine; diff --git a/packages/core-backend/CHANGELOG.md b/packages/core-backend/CHANGELOG.md index 93e788924bc..455dc85b44e 100644 --- a/packages/core-backend/CHANGELOG.md +++ b/packages/core-backend/CHANGELOG.md @@ -9,6 +9,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- **BREAKING:** Use new `Messenger` from `@metamask/messenger` ([#6823](https://github.com/MetaMask/core/pull/6823)) + - Previously, `AccountActivityService` and `BackendWebSocketService` accepted a `RestrictedMessenger` instance from `@metamask/base-controller`. +- **BREAKING:** Metadata property `anonymous` renamed to `includeInDebugSnapshot` ([#6823](https://github.com/MetaMask/core/pull/6823)) + +### Removed + +- **BREAKING:** Remove exported type aliases and constants that were specific to controller messenger integration ([#6823](https://github.com/MetaMask/core/pull/6823)) + - Removed type exports: `BackendWebSocketServiceAllowedActions`, `BackendWebSocketServiceAllowedEvents`, `AccountActivityServiceAllowedActions`, `AccountActivityServiceAllowedEvents` + - Removed constant exports: `ACCOUNT_ACTIVITY_SERVICE_ALLOWED_ACTIONS`, `ACCOUNT_ACTIVITY_SERVICE_ALLOWED_EVENTS` + - These types and constants were internal implementation details that should not have been exposed. Consumers should use the service-specific messenger types directly. - Bump `@metamask/profile-sync-controller` from `^25.1.1` to `^25.1.2` ([#6940](https://github.com/MetaMask/core/pull/6940)) ## [3.0.0] diff --git a/packages/core-backend/package.json b/packages/core-backend/package.json index 9ee949273e0..a0759dfd0ec 100644 --- a/packages/core-backend/package.json +++ b/packages/core-backend/package.json @@ -47,8 +47,8 @@ "test:watch": "NODE_OPTIONS=--experimental-vm-modules jest --watch" }, "dependencies": { - "@metamask/base-controller": "^8.4.2", "@metamask/controller-utils": "^11.14.1", + "@metamask/messenger": "^0.3.0", "@metamask/profile-sync-controller": "^25.1.2", "@metamask/utils": "^11.8.1", "uuid": "^8.3.2" diff --git a/packages/core-backend/src/AccountActivityService.test.ts b/packages/core-backend/src/AccountActivityService.test.ts index c60fe7bdeb9..00e83d7a9d1 100644 --- a/packages/core-backend/src/AccountActivityService.test.ts +++ b/packages/core-backend/src/AccountActivityService.test.ts @@ -1,17 +1,17 @@ -import { Messenger } from '@metamask/base-controller'; import type { InternalAccount } from '@metamask/keyring-internal-api'; +import { + Messenger, + MOCK_ANY_NAMESPACE, + type MessengerActions, + type MessengerEvents, + type MockAnyNamespace, +} from '@metamask/messenger'; import type { Hex } from '@metamask/utils'; -import type { - AccountActivityServiceAllowedEvents, - AccountActivityServiceAllowedActions, -} from './AccountActivityService'; import { AccountActivityService, type AccountActivityServiceMessenger, type SubscriptionOptions, - ACCOUNT_ACTIVITY_SERVICE_ALLOWED_ACTIONS, - ACCOUNT_ACTIVITY_SERVICE_ALLOWED_EVENTS, } from './AccountActivityService'; import type { ServerNotificationMessage } from './BackendWebSocketService'; import { WebSocketState } from './BackendWebSocketService'; @@ -19,6 +19,18 @@ import type { Transaction, BalanceUpdate } from './types'; import type { AccountActivityMessage } from './types'; import { flushPromises } from '../../../tests/helpers'; +type AllAccountActivityServiceActions = + MessengerActions; + +type AllAccountActivityServiceEvents = + MessengerEvents; + +type RootMessenger = Messenger< + MockAnyNamespace, + AllAccountActivityServiceActions, + AllAccountActivityServiceEvents +>; + // Helper function for completing async operations const completeAsyncOperations = async (timeoutMs = 0) => { await flushPromises(); @@ -48,25 +60,70 @@ const createMockInternalAccount = (options: { scopes: ['eip155:1'], // Required scopes property }); +/** + * Creates and returns a root messenger for testing + * + * @returns A messenger instance + */ +function getRootMessenger(): RootMessenger { + return new Messenger({ + namespace: MOCK_ANY_NAMESPACE, + }); +} + /** * Creates a real messenger with registered mock actions for testing * Each call creates a completely independent messenger to ensure test isolation * * @returns Object containing the messenger and mock action functions */ -const getMessenger = () => { +const getMessenger = (): { + rootMessenger: RootMessenger; + messenger: AccountActivityServiceMessenger; + mocks: { + getSelectedAccount: jest.Mock; + connect: jest.Mock; + subscribe: jest.Mock; + channelHasSubscription: jest.Mock; + getSubscriptionsByChannel: jest.Mock; + findSubscriptionsByChannelPrefix: jest.Mock; + forceReconnection: jest.Mock; + addChannelCallback: jest.Mock; + removeChannelCallback: jest.Mock; + }; +} => { // Use any types for the root messenger to avoid complex type constraints in tests // Create a unique root messenger for each test - const rootMessenger = new Messenger< - AccountActivityServiceAllowedActions, - AccountActivityServiceAllowedEvents - >(); - const messenger: AccountActivityServiceMessenger = - rootMessenger.getRestricted({ - name: 'AccountActivityService', - allowedActions: [...ACCOUNT_ACTIVITY_SERVICE_ALLOWED_ACTIONS], - allowedEvents: [...ACCOUNT_ACTIVITY_SERVICE_ALLOWED_EVENTS], - }); + const rootMessenger = getRootMessenger(); + const messenger: AccountActivityServiceMessenger = new Messenger< + 'AccountActivityService', + AllAccountActivityServiceActions, + AllAccountActivityServiceEvents, + RootMessenger + >({ + namespace: 'AccountActivityService', + parent: rootMessenger, + }); + + rootMessenger.delegate({ + actions: [ + 'AccountsController:getSelectedAccount', + 'BackendWebSocketService:connect', + 'BackendWebSocketService:forceReconnection', + 'BackendWebSocketService:subscribe', + 'BackendWebSocketService:getConnectionInfo', + 'BackendWebSocketService:channelHasSubscription', + 'BackendWebSocketService:getSubscriptionsByChannel', + 'BackendWebSocketService:findSubscriptionsByChannelPrefix', + 'BackendWebSocketService:addChannelCallback', + 'BackendWebSocketService:removeChannelCallback', + ], + events: [ + 'AccountsController:selectedAccountChange', + 'BackendWebSocketService:connectionStateChanged', + ], + messenger, + }); // Create mock action handlers const mockGetSelectedAccount = jest.fn(); @@ -215,10 +272,7 @@ type WithServiceOptions = { type WithServiceCallback = (payload: { service: AccountActivityService; messenger: AccountActivityServiceMessenger; - rootMessenger: Messenger< - AccountActivityServiceAllowedActions, - AccountActivityServiceAllowedEvents - >; + rootMessenger: RootMessenger; mocks: { getSelectedAccount: jest.Mock; connect: jest.Mock; @@ -633,7 +687,7 @@ describe('AccountActivityService', () => { }); // Publish WebSocket ERROR state event - should flush tracked chains as down - await rootMessenger.publish( + rootMessenger.publish( 'BackendWebSocketService:connectionStateChanged', { state: WebSocketState.ERROR, @@ -667,7 +721,7 @@ describe('AccountActivityService', () => { mocks.getSelectedAccount.mockReturnValue(null); // Publish WebSocket ERROR state event without any tracked chains - await rootMessenger.publish( + rootMessenger.publish( 'BackendWebSocketService:connectionStateChanged', { state: WebSocketState.ERROR, @@ -718,7 +772,7 @@ describe('AccountActivityService', () => { }); // Publish account change event - will be picked up by controller subscription - await rootMessenger.publish( + rootMessenger.publish( 'AccountsController:selectedAccountChange', solanaAccount, ); @@ -748,7 +802,7 @@ describe('AccountActivityService', () => { }); // Publish account change event - will be picked up by controller subscription - await rootMessenger.publish( + rootMessenger.publish( 'AccountsController:selectedAccountChange', unknownAccount, ); @@ -770,7 +824,7 @@ describe('AccountActivityService', () => { mocks.getSelectedAccount.mockReturnValue(null); // Publish WebSocket connection event - will be picked up by controller subscription - await rootMessenger.publish( + rootMessenger.publish( 'BackendWebSocketService:connectionStateChanged', { state: WebSocketState.CONNECTED, @@ -810,7 +864,7 @@ describe('AccountActivityService', () => { }); // Publish account change event on root messenger - await rootMessenger.publish( + rootMessenger.publish( 'AccountsController:selectedAccountChange', newAccount, ); @@ -848,7 +902,7 @@ describe('AccountActivityService', () => { }); // Publish account change event on root messenger - await rootMessenger.publish( + rootMessenger.publish( 'AccountsController:selectedAccountChange', newAccount, ); diff --git a/packages/core-backend/src/AccountActivityService.ts b/packages/core-backend/src/AccountActivityService.ts index 30c8b95d98c..e434a2d2c86 100644 --- a/packages/core-backend/src/AccountActivityService.ts +++ b/packages/core-backend/src/AccountActivityService.ts @@ -9,9 +9,9 @@ import type { AccountsControllerGetSelectedAccountAction, AccountsControllerSelectedAccountChangeEvent, } from '@metamask/accounts-controller'; -import type { RestrictedMessenger } from '@metamask/base-controller'; import type { TraceCallback } from '@metamask/controller-utils'; import type { InternalAccount } from '@metamask/keyring-internal-api'; +import type { Messenger } from '@metamask/messenger'; import type { AccountActivityServiceMethodActions } from './AccountActivityService-method-action-types'; import type { @@ -96,7 +96,7 @@ export const ACCOUNT_ACTIVITY_SERVICE_ALLOWED_EVENTS = [ 'BackendWebSocketService:connectionStateChanged', ] as const; -export type AccountActivityServiceAllowedActions = +export type AllowedActions = | AccountsControllerGetSelectedAccountAction | BackendWebSocketServiceMethodActions; @@ -134,16 +134,14 @@ export type AccountActivityServiceEvents = | AccountActivityServiceSubscriptionErrorEvent | AccountActivityServiceStatusChangedEvent; -export type AccountActivityServiceAllowedEvents = +export type AllowedEvents = | AccountsControllerSelectedAccountChangeEvent | BackendWebSocketServiceConnectionStateChangedEvent; -export type AccountActivityServiceMessenger = RestrictedMessenger< +export type AccountActivityServiceMessenger = Messenger< typeof SERVICE_NAME, - AccountActivityServiceActions | AccountActivityServiceAllowedActions, - AccountActivityServiceEvents | AccountActivityServiceAllowedEvents, - AccountActivityServiceAllowedActions['type'], - AccountActivityServiceAllowedEvents['type'] + AccountActivityServiceActions | AllowedActions, + AccountActivityServiceEvents | AllowedEvents >; // ============================================================================= diff --git a/packages/core-backend/src/BackendWebSocketService.test.ts b/packages/core-backend/src/BackendWebSocketService.test.ts index 987d2add4b5..55e34688c40 100644 --- a/packages/core-backend/src/BackendWebSocketService.test.ts +++ b/packages/core-backend/src/BackendWebSocketService.test.ts @@ -1,4 +1,10 @@ -import { Messenger } from '@metamask/base-controller'; +import { + Messenger, + MOCK_ANY_NAMESPACE, + type MessengerActions, + type MessengerEvents, + type MockAnyNamespace, +} from '@metamask/messenger'; import { BackendWebSocketService, @@ -6,10 +12,6 @@ import { WebSocketState, type BackendWebSocketServiceOptions, type BackendWebSocketServiceMessenger, - type BackendWebSocketServiceActions, - type BackendWebSocketServiceAllowedActions, - type BackendWebSocketServiceEvents, - type BackendWebSocketServiceAllowedEvents, } from './BackendWebSocketService'; import { flushPromises } from '../../../tests/helpers'; @@ -20,6 +22,18 @@ import { flushPromises } from '../../../tests/helpers'; // Type for global object with WebSocket mock type GlobalWithWebSocket = typeof global & { lastWebSocket: MockWebSocket }; +type AllBackendWebSocketServiceActions = + MessengerActions; + +type AllBackendWebSocketServiceEvents = + MessengerEvents; + +type RootMessenger = Messenger< + MockAnyNamespace, + AllBackendWebSocketServiceActions, + AllBackendWebSocketServiceEvents +>; + // ===================================================== // MOCK WEBSOCKET CLASS // ===================================================== @@ -163,6 +177,17 @@ class MockWebSocket extends EventTarget { // TEST UTILITIES & MOCKS // ===================================================== +/** + * Creates and returns a root messenger for testing + * + * @returns A messenger instance + */ +function getRootMessenger(): RootMessenger { + return new Messenger({ + namespace: MOCK_ANY_NAMESPACE, + }); +} + /** * Creates a real messenger with registered mock actions for testing * Each call creates a completely independent messenger to ensure test isolation @@ -171,19 +196,25 @@ class MockWebSocket extends EventTarget { */ const getMessenger = () => { // Create a unique root messenger for each test - const rootMessenger = new Messenger< - BackendWebSocketServiceActions | BackendWebSocketServiceAllowedActions, - BackendWebSocketServiceEvents | BackendWebSocketServiceAllowedEvents - >(); - const messenger = rootMessenger.getRestricted({ - name: 'BackendWebSocketService', - allowedActions: ['AuthenticationController:getBearerToken'], - allowedEvents: [ + const rootMessenger = getRootMessenger(); + const messenger = new Messenger< + 'BackendWebSocketService', + AllBackendWebSocketServiceActions, + AllBackendWebSocketServiceEvents, + RootMessenger + >({ + namespace: 'BackendWebSocketService', + parent: rootMessenger, + }); + rootMessenger.delegate({ + actions: ['AuthenticationController:getBearerToken'], + events: [ 'AuthenticationController:stateChange', 'KeyringController:lock', 'KeyringController:unlock', ], - }) as unknown as BackendWebSocketServiceMessenger; + messenger, + }); // Create mock action handlers const mockGetBearerToken = jest.fn().mockResolvedValue('valid-default-token'); @@ -252,10 +283,7 @@ type TestSetupOptions = { type TestSetup = { service: BackendWebSocketService; messenger: BackendWebSocketServiceMessenger; - rootMessenger: Messenger< - BackendWebSocketServiceActions | BackendWebSocketServiceAllowedActions, - BackendWebSocketServiceEvents | BackendWebSocketServiceAllowedEvents - >; + rootMessenger: RootMessenger; mocks: { getBearerToken: jest.Mock; }; @@ -270,10 +298,7 @@ type TestSetup = { type WithServiceCallback = (payload: { service: BackendWebSocketService; messenger: BackendWebSocketServiceMessenger; - rootMessenger: Messenger< - BackendWebSocketServiceActions | BackendWebSocketServiceAllowedActions, - BackendWebSocketServiceEvents | BackendWebSocketServiceAllowedEvents - >; + rootMessenger: RootMessenger; mocks: { getBearerToken: jest.Mock; }; diff --git a/packages/core-backend/src/BackendWebSocketService.ts b/packages/core-backend/src/BackendWebSocketService.ts index 3bbfd48a0bd..a8c9066dc25 100644 --- a/packages/core-backend/src/BackendWebSocketService.ts +++ b/packages/core-backend/src/BackendWebSocketService.ts @@ -1,10 +1,10 @@ -import type { RestrictedMessenger } from '@metamask/base-controller'; import type { TraceCallback } from '@metamask/controller-utils'; import { ExponentialBackoff } from '@metamask/controller-utils'; import type { KeyringControllerLockEvent, KeyringControllerUnlockEvent, } from '@metamask/keyring-controller'; +import type { Messenger } from '@metamask/messenger'; import type { AuthenticationController } from '@metamask/profile-sync-controller'; import { getErrorMessage } from '@metamask/utils'; import { v4 as uuidV4 } from 'uuid'; @@ -228,29 +228,27 @@ export type WebSocketConnectionInfo = { export type BackendWebSocketServiceActions = BackendWebSocketServiceMethodActions; -export type BackendWebSocketServiceAllowedActions = +type AllowedActions = AuthenticationController.AuthenticationControllerGetBearerToken; -export type BackendWebSocketServiceAllowedEvents = - | AuthenticationController.AuthenticationControllerStateChangeEvent - | KeyringControllerLockEvent - | KeyringControllerUnlockEvent; - // Event types for WebSocket connection state changes export type BackendWebSocketServiceConnectionStateChangedEvent = { type: 'BackendWebSocketService:connectionStateChanged'; payload: [WebSocketConnectionInfo]; }; +type AllowedEvents = + | AuthenticationController.AuthenticationControllerStateChangeEvent + | KeyringControllerLockEvent + | KeyringControllerUnlockEvent; + export type BackendWebSocketServiceEvents = BackendWebSocketServiceConnectionStateChangedEvent; -export type BackendWebSocketServiceMessenger = RestrictedMessenger< +export type BackendWebSocketServiceMessenger = Messenger< typeof SERVICE_NAME, - BackendWebSocketServiceActions | BackendWebSocketServiceAllowedActions, - BackendWebSocketServiceEvents | BackendWebSocketServiceAllowedEvents, - BackendWebSocketServiceAllowedActions['type'], - BackendWebSocketServiceAllowedEvents['type'] + BackendWebSocketServiceActions | AllowedActions, + BackendWebSocketServiceEvents | AllowedEvents >; /** diff --git a/packages/core-backend/src/index.ts b/packages/core-backend/src/index.ts index 4831e4569f2..e77bc517a75 100644 --- a/packages/core-backend/src/index.ts +++ b/packages/core-backend/src/index.ts @@ -19,8 +19,6 @@ export type { WebSocketConnectionInfo, WebSocketSubscription, BackendWebSocketServiceActions, - BackendWebSocketServiceAllowedActions, - BackendWebSocketServiceAllowedEvents, BackendWebSocketServiceMessenger, BackendWebSocketServiceEvents, BackendWebSocketServiceConnectionStateChangedEvent, @@ -34,8 +32,6 @@ export type { SubscriptionOptions, AccountActivityServiceOptions, AccountActivityServiceActions, - AccountActivityServiceAllowedActions, - AccountActivityServiceAllowedEvents, AccountActivityServiceTransactionUpdatedEvent, AccountActivityServiceBalanceUpdatedEvent, AccountActivityServiceSubscriptionErrorEvent, @@ -43,8 +39,4 @@ export type { AccountActivityServiceEvents, AccountActivityServiceMessenger, } from './AccountActivityService'; -export { - ACCOUNT_ACTIVITY_SERVICE_ALLOWED_ACTIONS, - ACCOUNT_ACTIVITY_SERVICE_ALLOWED_EVENTS, -} from './AccountActivityService'; export { AccountActivityService } from './AccountActivityService'; diff --git a/packages/core-backend/tsconfig.build.json b/packages/core-backend/tsconfig.build.json index 4f4a385017b..e386c7a5ecc 100644 --- a/packages/core-backend/tsconfig.build.json +++ b/packages/core-backend/tsconfig.build.json @@ -7,9 +7,9 @@ }, "references": [ { "path": "../accounts-controller/tsconfig.build.json" }, - { "path": "../base-controller/tsconfig.build.json" }, { "path": "../controller-utils/tsconfig.build.json" }, { "path": "../keyring-controller/tsconfig.build.json" }, + { "path": "../messenger/tsconfig.build.json" }, { "path": "../profile-sync-controller/tsconfig.build.json" } ], "include": ["../../types", "./src"] diff --git a/packages/core-backend/tsconfig.json b/packages/core-backend/tsconfig.json index 6d40debda24..b44a91d630c 100644 --- a/packages/core-backend/tsconfig.json +++ b/packages/core-backend/tsconfig.json @@ -9,15 +9,15 @@ { "path": "../accounts-controller" }, - { - "path": "../base-controller" - }, { "path": "../controller-utils" }, { "path": "../keyring-controller" }, + { + "path": "../messenger" + }, { "path": "../profile-sync-controller" } diff --git a/yarn.lock b/yarn.lock index f67c9bc6cb0..1c5cf650f24 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3089,9 +3089,9 @@ __metadata: dependencies: "@metamask/accounts-controller": "npm:^33.2.0" "@metamask/auto-changelog": "npm:^3.4.4" - "@metamask/base-controller": "npm:^8.4.2" "@metamask/controller-utils": "npm:^11.14.1" "@metamask/keyring-controller": "npm:^23.2.0" + "@metamask/messenger": "npm:^0.3.0" "@metamask/profile-sync-controller": "npm:^25.1.2" "@metamask/utils": "npm:^11.8.1" "@ts-bridge/cli": "npm:^0.6.1"