Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions packages/core-backend/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### 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`.

### 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.

## [2.1.0]

### Added
Expand Down
2 changes: 1 addition & 1 deletion packages/core-backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@
"test:watch": "NODE_OPTIONS=--experimental-vm-modules jest --watch"
},
"dependencies": {
"@metamask/base-controller": "^8.4.1",
"@metamask/controller-utils": "^11.14.1",
"@metamask/messenger": "^0.3.0",
"@metamask/profile-sync-controller": "^25.1.1",
"@metamask/utils": "^11.8.1",
"uuid": "^8.3.2"
Expand Down
112 changes: 83 additions & 29 deletions packages/core-backend/src/AccountActivityService.test.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,36 @@
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';
import type { Transaction, BalanceUpdate } from './types';
import type { AccountActivityMessage } from './types';
import { flushPromises } from '../../../tests/helpers';

type AllAccountActivityServiceActions =
MessengerActions<AccountActivityServiceMessenger>;

type AllAccountActivityServiceEvents =
MessengerEvents<AccountActivityServiceMessenger>;

type RootMessenger = Messenger<
MockAnyNamespace,
AllAccountActivityServiceActions,
AllAccountActivityServiceEvents
>;

// Helper function for completing async operations
const completeAsyncOperations = async (timeoutMs = 0) => {
await flushPromises();
Expand Down Expand Up @@ -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;
disconnect: jest.Mock;
subscribe: jest.Mock;
channelHasSubscription: jest.Mock;
getSubscriptionsByChannel: jest.Mock;
findSubscriptionsByChannelPrefix: 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:disconnect',
'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();
Expand Down Expand Up @@ -215,10 +272,7 @@ type WithServiceOptions = {
type WithServiceCallback<ReturnValue> = (payload: {
service: AccountActivityService;
messenger: AccountActivityServiceMessenger;
rootMessenger: Messenger<
AccountActivityServiceAllowedActions,
AccountActivityServiceAllowedEvents
>;
rootMessenger: RootMessenger;
mocks: {
getSelectedAccount: jest.Mock;
connect: jest.Mock;
Expand Down Expand Up @@ -645,7 +699,7 @@ describe('AccountActivityService', () => {
});

// Publish WebSocket ERROR state event - should flush tracked chains as down
await rootMessenger.publish(
rootMessenger.publish(
'BackendWebSocketService:connectionStateChanged',
{
state: WebSocketState.ERROR,
Expand Down Expand Up @@ -679,7 +733,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,
Expand Down Expand Up @@ -730,7 +784,7 @@ describe('AccountActivityService', () => {
});

// Publish account change event - will be picked up by controller subscription
await rootMessenger.publish(
rootMessenger.publish(
'AccountsController:selectedAccountChange',
solanaAccount,
);
Expand Down Expand Up @@ -760,7 +814,7 @@ describe('AccountActivityService', () => {
});

// Publish account change event - will be picked up by controller subscription
await rootMessenger.publish(
rootMessenger.publish(
'AccountsController:selectedAccountChange',
unknownAccount,
);
Expand All @@ -782,7 +836,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,
Expand Down Expand Up @@ -822,7 +876,7 @@ describe('AccountActivityService', () => {
});

// Publish account change event on root messenger
await rootMessenger.publish(
rootMessenger.publish(
'AccountsController:selectedAccountChange',
newAccount,
);
Expand Down Expand Up @@ -860,7 +914,7 @@ describe('AccountActivityService', () => {
});

// Publish account change event on root messenger
await rootMessenger.publish(
rootMessenger.publish(
'AccountsController:selectedAccountChange',
newAccount,
);
Expand Down
34 changes: 6 additions & 28 deletions packages/core-backend/src/AccountActivityService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -76,27 +76,7 @@ export type AccountActivityServiceOptions = {
// Action types for the messaging system - using generated method actions
export type AccountActivityServiceActions = AccountActivityServiceMethodActions;

// Allowed actions that AccountActivityService can call on other controllers
export const ACCOUNT_ACTIVITY_SERVICE_ALLOWED_ACTIONS = [
'AccountsController:getSelectedAccount',
'BackendWebSocketService:connect',
'BackendWebSocketService:disconnect',
'BackendWebSocketService:subscribe',
'BackendWebSocketService:getConnectionInfo',
'BackendWebSocketService:channelHasSubscription',
'BackendWebSocketService:getSubscriptionsByChannel',
'BackendWebSocketService:findSubscriptionsByChannelPrefix',
'BackendWebSocketService:addChannelCallback',
'BackendWebSocketService:removeChannelCallback',
] as const;

// Allowed events that AccountActivityService can listen to
export const ACCOUNT_ACTIVITY_SERVICE_ALLOWED_EVENTS = [
'AccountsController:selectedAccountChange',
'BackendWebSocketService:connectionStateChanged',
] as const;

export type AccountActivityServiceAllowedActions =
type AllowedActions =
| AccountsControllerGetSelectedAccountAction
| BackendWebSocketServiceMethodActions;

Expand Down Expand Up @@ -134,16 +114,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
>;

// =============================================================================
Expand Down
Loading
Loading