Skip to content

Commit 1f4fc7a

Browse files
feat: Add WebSockets support (#3450)
Implements the rewritten SIP-20 to enable WebSocket support in Snaps. WebSockets are supported via the `WebSocketService` which runs in the client and handles open WebSocket connections for the Snap. The Snap is notified of WebSocket events via `onWebSocketEvent` and is notified of `open`, `close` and `message`. Messages can also be sent from the Snap using `snap_sendWebSocketMessage`. Both string and binary payloads are allowed. All of the new RPC methods are gated on `endowment:network-access`, which is also the permission required to expose `onWebSocketEvent`.
1 parent fece6fe commit 1f4fc7a

39 files changed

+2171
-21
lines changed
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
2-
"branches": 95.29,
3-
"functions": 98.65,
4-
"lines": 98.83,
5-
"statements": 98.66
2+
"branches": 95.21,
3+
"functions": 98.71,
4+
"lines": 98.87,
5+
"statements": 98.7
66
}

packages/snaps-controllers/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ export * from './cronjob';
66
export * from './interface';
77
export * from './insights';
88
export * from './multichain';
9+
export * from './websocket';

packages/snaps-controllers/src/snaps/SnapController.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6940,7 +6940,7 @@ describe('SnapController', () => {
69406940
[MOCK_SNAP_ID]: {},
69416941
}),
69426942
).rejects.toThrow(
6943-
'A snap must request at least one of the following permissions: endowment:rpc, endowment:transaction-insight, endowment:cronjob, endowment:name-lookup, endowment:lifecycle-hooks, endowment:keyring, endowment:page-home, endowment:page-settings, endowment:signature-insight, endowment:assets, endowment:protocol.',
6943+
'A snap must request at least one of the following permissions: endowment:rpc, endowment:transaction-insight, endowment:cronjob, endowment:name-lookup, endowment:lifecycle-hooks, endowment:keyring, endowment:page-home, endowment:page-settings, endowment:signature-insight, endowment:assets, endowment:protocol, endowment:network-access.',
69446944
);
69456945

69466946
controller.destroy();

packages/snaps-controllers/src/snaps/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,5 @@ export const CLIENT_ONLY_HANDLERS = Object.freeze([
4343
HandlerType.OnAssetsLookup,
4444
HandlerType.OnAssetsConversion,
4545
HandlerType.OnAssetHistoricalPrice,
46+
HandlerType.OnWebSocketEvent,
4647
]);

packages/snaps-controllers/src/snaps/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
export * from './constants';
12
export * from './location';
23
export * from './SnapController';
34
export * from './selectors';

packages/snaps-controllers/src/test-utils/controller.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,11 @@ import type {
7171
SnapsRegistryEvents,
7272
} from '../snaps';
7373
import type { KeyDerivationOptions } from '../types';
74+
import type {
75+
WebSocketServiceActions,
76+
WebSocketServiceAllowedActions,
77+
WebSocketServiceEvents,
78+
} from '../websocket';
7479

7580
const asyncNoOp = async () => Promise.resolve();
7681

@@ -962,3 +967,37 @@ export const getRestrictedMultichainRouterMessenger = (
962967

963968
return controllerMessenger;
964969
};
970+
971+
// Mock controller messenger for WebSocketService
972+
export const getRootWebSocketServiceMessenger = () => {
973+
const messenger = new MockControllerMessenger<
974+
WebSocketServiceActions | WebSocketServiceAllowedActions,
975+
WebSocketServiceEvents
976+
>();
977+
978+
jest.spyOn(messenger, 'call');
979+
980+
return messenger;
981+
};
982+
983+
export const getRestrictedWebSocketServiceMessenger = (
984+
messenger: ReturnType<
985+
typeof getRootWebSocketServiceMessenger
986+
> = getRootWebSocketServiceMessenger(),
987+
) => {
988+
const controllerMessenger = messenger.getRestricted<
989+
'WebSocketService',
990+
WebSocketServiceAllowedActions['type'],
991+
WebSocketServiceEvents['type']
992+
>({
993+
name: 'WebSocketService',
994+
allowedEvents: [
995+
'SnapController:snapInstalled',
996+
'SnapController:snapUpdated',
997+
'SnapController:snapUninstalled',
998+
],
999+
allowedActions: ['SnapController:handleRequest'],
1000+
});
1001+
1002+
return controllerMessenger;
1003+
};

0 commit comments

Comments
 (0)