diff --git a/packages/examples/packages/browserify-plugin/snap.manifest.json b/packages/examples/packages/browserify-plugin/snap.manifest.json index 2835f676c3..bb85919513 100644 --- a/packages/examples/packages/browserify-plugin/snap.manifest.json +++ b/packages/examples/packages/browserify-plugin/snap.manifest.json @@ -7,7 +7,7 @@ "url": "https://github.com/MetaMask/snaps.git" }, "source": { - "shasum": "D5uPpprRmrMeqwvti5+Sy5PxuCdyFlMw8PA+7OlP/WY=", + "shasum": "LciQX9cjRXeSErEsKRm9OEFW8jAq9doqaa9b/TfGN3Y=", "location": { "npm": { "filePath": "dist/bundle.js", diff --git a/packages/examples/packages/browserify/snap.manifest.json b/packages/examples/packages/browserify/snap.manifest.json index d92a96e851..f3ae515fcb 100644 --- a/packages/examples/packages/browserify/snap.manifest.json +++ b/packages/examples/packages/browserify/snap.manifest.json @@ -7,7 +7,7 @@ "url": "https://github.com/MetaMask/snaps.git" }, "source": { - "shasum": "87AZ5qZxOtBTdc4cRBbCRTX5vYhIlhSSJgyUc8WWi1A=", + "shasum": "83SohbQ4Vp/wI2lFXL6tyuvWy7bLcRSL3yZikZEZrAg=", "location": { "npm": { "filePath": "dist/bundle.js", diff --git a/packages/snaps-controllers/coverage.json b/packages/snaps-controllers/coverage.json index c10c3a0f6a..4709341243 100644 --- a/packages/snaps-controllers/coverage.json +++ b/packages/snaps-controllers/coverage.json @@ -1,6 +1,6 @@ { - "branches": 92.73, - "functions": 96.65, - "lines": 97.99, - "statements": 97.69 + "branches": 92.85, + "functions": 96.71, + "lines": 98, + "statements": 97.7 } diff --git a/packages/snaps-controllers/src/interface/SnapInterfaceController.test.tsx b/packages/snaps-controllers/src/interface/SnapInterfaceController.test.tsx index a3561840df..fb88438897 100644 --- a/packages/snaps-controllers/src/interface/SnapInterfaceController.test.tsx +++ b/packages/snaps-controllers/src/interface/SnapInterfaceController.test.tsx @@ -1,5 +1,13 @@ +import { getPersistentState } from '@metamask/base-controller'; import type { SnapId } from '@metamask/snaps-sdk'; -import { form, image, input, panel, text } from '@metamask/snaps-sdk'; +import { + form, + image, + input, + panel, + text, + ContentType, +} from '@metamask/snaps-sdk'; import { Box, Field, @@ -29,13 +37,89 @@ jest.mock('@metamask/snaps-utils', () => ({ })); describe('SnapInterfaceController', () => { + it('handles a notificationsListUpdated event where only stale notifications are deleted', async () => { + const rootMessenger = getRootSnapInterfaceControllerMessenger(); + const controllerMessenger = + getRestrictedSnapInterfaceControllerMessenger(rootMessenger); + + const controller = new SnapInterfaceController({ + messenger: controllerMessenger, + state: { + interfaces: { + // @ts-expect-error missing properties + '1': { + contentType: ContentType.Notification, + }, + // @ts-expect-error missing properties + '2': { + contentType: ContentType.Dialog, + }, + // @ts-expect-error missing properties + '3': { + contentType: ContentType.Notification, + }, + }, + }, + }); + + rootMessenger.publish( + 'NotificationServicesController:notificationsListUpdated', + [{ type: 'snap', data: { detailedView: { interfaceId: '3' } } }], + ); + + expect(controller.state).toStrictEqual({ + interfaces: { + '2': { + contentType: ContentType.Dialog, + }, + '3': { + contentType: ContentType.Notification, + }, + }, + }); + }); + + describe('constructor', () => { + it('persists notification interfaces', () => { + const rootMessenger = getRootSnapInterfaceControllerMessenger(); + const controllerMessenger = + getRestrictedSnapInterfaceControllerMessenger(rootMessenger); + + const controller = new SnapInterfaceController({ + messenger: controllerMessenger, + state: { + interfaces: { + // @ts-expect-error missing properties + '1': { + contentType: ContentType.Notification, + }, + // @ts-expect-error missing properties + '2': { + contentType: ContentType.Dialog, + }, + }, + }, + }); + + expect( + getPersistentState(controller.state, controller.metadata), + ).toStrictEqual({ + interfaces: { + '1': { + contentType: ContentType.Notification, + }, + }, + }); + }); + }); + describe('createInterface', () => { it('can create a new interface', async () => { const rootMessenger = getRootSnapInterfaceControllerMessenger(); const controllerMessenger = getRestrictedSnapInterfaceControllerMessenger(rootMessenger); - /* eslint-disable-next-line no-new */ + // eslint-disable-next-line no-new new SnapInterfaceController({ messenger: controllerMessenger, }); @@ -80,7 +164,7 @@ describe('SnapInterfaceController', () => { const controllerMessenger = getRestrictedSnapInterfaceControllerMessenger(rootMessenger); - /* eslint-disable-next-line no-new */ + // eslint-disable-next-line no-new new SnapInterfaceController({ messenger: controllerMessenger, }); @@ -130,7 +214,7 @@ describe('SnapInterfaceController', () => { const controllerMessenger = getRestrictedSnapInterfaceControllerMessenger(rootMessenger); - /* eslint-disable-next-line no-new */ + // eslint-disable-next-line no-new new SnapInterfaceController({ messenger: controllerMessenger, }); @@ -160,6 +244,41 @@ describe('SnapInterfaceController', () => { expect(context).toStrictEqual({ foo: 'bar' }); }); + it('supports providing an interface content type', async () => { + const rootMessenger = getRootSnapInterfaceControllerMessenger(); + const controllerMessenger = + getRestrictedSnapInterfaceControllerMessenger(rootMessenger); + + // eslint-disable-next-line no-new + new SnapInterfaceController({ + messenger: controllerMessenger, + }); + + const element = ( + + + foo + + + ); + + const id = await rootMessenger.call( + 'SnapInterfaceController:createInterface', + MOCK_SNAP_ID, + element, + { foo: 'bar' }, + ContentType.Notification, + ); + + const { contentType } = rootMessenger.call( + 'SnapInterfaceController:getInterface', + MOCK_SNAP_ID, + id, + ); + + expect(contentType).toStrictEqual(ContentType.Notification); + }); + it('throws if interface context is too large', async () => { const rootMessenger = getRootSnapInterfaceControllerMessenger(); const controllerMessenger = @@ -170,7 +289,7 @@ describe('SnapInterfaceController', () => { .mockReturnValueOnce(1) .mockReturnValueOnce(10_000_000); - /* eslint-disable-next-line no-new */ + // eslint-disable-next-line no-new new SnapInterfaceController({ messenger: controllerMessenger, }); @@ -210,7 +329,7 @@ describe('SnapInterfaceController', () => { () => ({ result: true, type: 'all' }), ); - /* eslint-disable-next-line no-new */ + // eslint-disable-next-line no-new new SnapInterfaceController({ messenger: controllerMessenger, }); @@ -260,7 +379,7 @@ describe('SnapInterfaceController', () => { () => ({ result: true, type: 'all' }), ); - /* eslint-disable-next-line no-new */ + // eslint-disable-next-line no-new new SnapInterfaceController({ messenger: controllerMessenger, }); @@ -302,7 +421,7 @@ describe('SnapInterfaceController', () => { jest.mocked(getJsonSizeUnsafe).mockReturnValueOnce(11_000_000); - /* eslint-disable-next-line no-new */ + // eslint-disable-next-line no-new new SnapInterfaceController({ messenger: controllerMessenger, }); @@ -327,7 +446,7 @@ describe('SnapInterfaceController', () => { jest.mocked(getJsonSizeUnsafe).mockReturnValueOnce(11_000_000); - /* eslint-disable-next-line no-new */ + // eslint-disable-next-line no-new new SnapInterfaceController({ messenger: controllerMessenger, }); @@ -354,7 +473,7 @@ describe('SnapInterfaceController', () => { false, ); - /* eslint-disable-next-line no-new */ + // eslint-disable-next-line no-new new SnapInterfaceController({ messenger: controllerMessenger, }); @@ -377,7 +496,7 @@ describe('SnapInterfaceController', () => { const controllerMessenger = getRestrictedSnapInterfaceControllerMessenger(rootMessenger); - /* eslint-disable-next-line no-new */ + // eslint-disable-next-line no-new new SnapInterfaceController({ messenger: controllerMessenger, }); @@ -407,7 +526,7 @@ describe('SnapInterfaceController', () => { const controllerMessenger = getRestrictedSnapInterfaceControllerMessenger(rootMessenger); - /* eslint-disable-next-line no-new */ + // eslint-disable-next-line no-new new SnapInterfaceController({ messenger: controllerMessenger, }); @@ -437,7 +556,7 @@ describe('SnapInterfaceController', () => { const controllerMessenger = getRestrictedSnapInterfaceControllerMessenger(rootMessenger); - /* eslint-disable-next-line no-new */ + // eslint-disable-next-line no-new new SnapInterfaceController({ messenger: controllerMessenger, }); @@ -458,7 +577,7 @@ describe('SnapInterfaceController', () => { const controllerMessenger = getRestrictedSnapInterfaceControllerMessenger(rootMessenger); - /* eslint-disable-next-line no-new */ + // eslint-disable-next-line no-new new SnapInterfaceController({ messenger: controllerMessenger, }); @@ -501,7 +620,7 @@ describe('SnapInterfaceController', () => { const controllerMessenger = getRestrictedSnapInterfaceControllerMessenger(rootMessenger); - /* eslint-disable-next-line no-new */ + // eslint-disable-next-line no-new new SnapInterfaceController({ messenger: controllerMessenger, }); @@ -550,7 +669,7 @@ describe('SnapInterfaceController', () => { const controllerMessenger = getRestrictedSnapInterfaceControllerMessenger(rootMessenger); - /* eslint-disable-next-line no-new */ + // eslint-disable-next-line no-new new SnapInterfaceController({ messenger: controllerMessenger, }); @@ -604,7 +723,7 @@ describe('SnapInterfaceController', () => { const controllerMessenger = getRestrictedSnapInterfaceControllerMessenger(rootMessenger); - /* eslint-disable-next-line no-new */ + // eslint-disable-next-line no-new new SnapInterfaceController({ messenger: controllerMessenger, }); @@ -667,7 +786,7 @@ describe('SnapInterfaceController', () => { () => ({ result: true, type: 'all' }), ); - /* eslint-disable-next-line no-new */ + // eslint-disable-next-line no-new new SnapInterfaceController({ messenger: controllerMessenger, }); @@ -729,7 +848,7 @@ describe('SnapInterfaceController', () => { () => ({ result: true, type: 'all' }), ); - /* eslint-disable-next-line no-new */ + // eslint-disable-next-line no-new new SnapInterfaceController({ messenger: controllerMessenger, }); @@ -788,7 +907,7 @@ describe('SnapInterfaceController', () => { .mockReturnValueOnce(1) .mockReturnValueOnce(11_000_000); - /* eslint-disable-next-line no-new */ + // eslint-disable-next-line no-new new SnapInterfaceController({ messenger: controllerMessenger, }); @@ -826,7 +945,7 @@ describe('SnapInterfaceController', () => { .mockReturnValueOnce(1) .mockReturnValueOnce(11_000_000); - /* eslint-disable-next-line no-new */ + // eslint-disable-next-line no-new new SnapInterfaceController({ messenger: controllerMessenger, }); @@ -866,7 +985,7 @@ describe('SnapInterfaceController', () => { const controllerMessenger = getRestrictedSnapInterfaceControllerMessenger(rootMessenger); - /* eslint-disable-next-line no-new */ + // eslint-disable-next-line no-new new SnapInterfaceController({ messenger: controllerMessenger, }); @@ -899,7 +1018,7 @@ describe('SnapInterfaceController', () => { const controllerMessenger = getRestrictedSnapInterfaceControllerMessenger(rootMessenger); - /* eslint-disable-next-line no-new */ + // eslint-disable-next-line no-new new SnapInterfaceController({ messenger: controllerMessenger, }); @@ -921,7 +1040,7 @@ describe('SnapInterfaceController', () => { const controllerMessenger = getRestrictedSnapInterfaceControllerMessenger(rootMessenger); - /* eslint-disable-next-line no-new */ + // eslint-disable-next-line no-new new SnapInterfaceController({ messenger: controllerMessenger, }); @@ -956,7 +1075,7 @@ describe('SnapInterfaceController', () => { const controllerMessenger = getRestrictedSnapInterfaceControllerMessenger(rootMessenger); - /* eslint-disable-next-line no-new */ + // eslint-disable-next-line no-new new SnapInterfaceController({ messenger: controllerMessenger, }); @@ -991,7 +1110,7 @@ describe('SnapInterfaceController', () => { const controllerMessenger = getRestrictedSnapInterfaceControllerMessenger(rootMessenger); - /* eslint-disable-next-line no-new */ + // eslint-disable-next-line no-new new SnapInterfaceController({ messenger: controllerMessenger, }); @@ -1043,7 +1162,7 @@ describe('SnapInterfaceController', () => { const controllerMessenger = getRestrictedSnapInterfaceControllerMessenger(rootMessenger); - /* eslint-disable-next-line no-new */ + // eslint-disable-next-line no-new new SnapInterfaceController({ messenger: controllerMessenger, }); @@ -1074,7 +1193,7 @@ describe('SnapInterfaceController', () => { const controllerMessenger = getRestrictedSnapInterfaceControllerMessenger(rootMessenger); - /* eslint-disable-next-line no-new */ + // eslint-disable-next-line no-new new SnapInterfaceController({ messenger: controllerMessenger, }); @@ -1118,7 +1237,7 @@ describe('SnapInterfaceController', () => { const controllerMessenger = getRestrictedSnapInterfaceControllerMessenger(rootMessenger); - /* eslint-disable-next-line no-new */ + // eslint-disable-next-line no-new new SnapInterfaceController({ messenger: controllerMessenger, }); @@ -1150,7 +1269,7 @@ describe('SnapInterfaceController', () => { const controllerMessenger = getRestrictedSnapInterfaceControllerMessenger(rootMessenger); - /* eslint-disable-next-line no-new */ + // eslint-disable-next-line no-new new SnapInterfaceController({ messenger: controllerMessenger, }); @@ -1195,7 +1314,7 @@ describe('SnapInterfaceController', () => { const controllerMessenger = getRestrictedSnapInterfaceControllerMessenger(rootMessenger); - /* eslint-disable-next-line no-new */ + // eslint-disable-next-line no-new new SnapInterfaceController({ messenger: controllerMessenger, }); diff --git a/packages/snaps-controllers/src/interface/SnapInterfaceController.ts b/packages/snaps-controllers/src/interface/SnapInterfaceController.ts index cca147b9d8..e12bc3ab14 100644 --- a/packages/snaps-controllers/src/interface/SnapInterfaceController.ts +++ b/packages/snaps-controllers/src/interface/SnapInterfaceController.ts @@ -18,10 +18,11 @@ import type { ComponentOrElement, InterfaceContext, } from '@metamask/snaps-sdk'; +import { ContentType } from '@metamask/snaps-sdk'; import type { JSXElement } from '@metamask/snaps-sdk/jsx'; import { getJsonSizeUnsafe, validateJsxLinks } from '@metamask/snaps-utils'; import type { Json } from '@metamask/utils'; -import { assert } from '@metamask/utils'; +import { assert, hasProperty } from '@metamask/utils'; import { castDraft } from 'immer'; import { nanoid } from 'nanoid'; @@ -93,8 +94,38 @@ export type SnapInterfaceControllerStateChangeEvent = SnapInterfaceControllerState >; +type OtherNotification = { type: string; [key: string]: unknown }; + +export type ExpandedView = { + title: string; + interfaceId: string; + footerLink?: { href: string; text: string }; +}; + +type NormalSnapNotificationData = { message: string; origin: string }; + +type ExpandedSnapNotificationData = { + message: string; + origin: string; + detailedView: ExpandedView; +}; + +type SnapNotification = { + type: 'snap'; + data: NormalSnapNotificationData | ExpandedSnapNotificationData; + readDate: string | null; +}; + +type Notification = OtherNotification | SnapNotification; + +type NotificationListUpdatedEvent = { + type: 'NotificationServicesController:notificationsListUpdated'; + payload: [Notification[]]; +}; + export type SnapInterfaceControllerEvents = - SnapInterfaceControllerStateChangeEvent; + | SnapInterfaceControllerStateChangeEvent + | NotificationListUpdatedEvent; export type SnapInterfaceControllerMessenger = RestrictedControllerMessenger< typeof controllerName, @@ -109,6 +140,7 @@ export type StoredInterface = { content: JSXElement; state: InterfaceState; context: InterfaceContext | null; + contentType: ContentType | null; }; export type SnapInterfaceControllerState = { @@ -132,12 +164,32 @@ export class SnapInterfaceController extends BaseController< super({ messenger, metadata: { - interfaces: { persist: false, anonymous: false }, + interfaces: { + persist: (interfaces: Record) => { + return Object.entries(interfaces).reduce< + Record + >((persistedInterfaces, [id, snapInterface]) => { + switch (snapInterface.contentType) { + case ContentType.Notification: + persistedInterfaces[id] = snapInterface; + return persistedInterfaces; + default: + return persistedInterfaces; + } + }, {}); + }, + anonymous: false, + }, }, name: controllerName, state: { interfaces: {}, ...state }, }); + this.messagingSystem.subscribe( + 'NotificationServicesController:notificationsListUpdated', + this.#onNotificationsListUpdated.bind(this), + ); + this.#registerMessageHandlers(); } @@ -183,12 +235,14 @@ export class SnapInterfaceController extends BaseController< * @param snapId - The snap id that created the interface. * @param content - The interface content. * @param context - An optional interface context object. + * @param contentType - The type of content. * @returns The newly interface id. */ async createInterface( snapId: SnapId, content: ComponentOrElement, context?: InterfaceContext, + contentType?: ContentType, ) { const element = getJsxInterface(content); await this.#validateContent(element); @@ -205,6 +259,7 @@ export class SnapInterfaceController extends BaseController< content: castDraft(element), state: componentState, context: context ?? null, + contentType: contentType ?? null, }; }); @@ -393,4 +448,36 @@ export class SnapInterfaceController extends BaseController< (id: string) => this.messagingSystem.call('SnapController:get', id), ); } + + #onNotificationsListUpdated(notificationsList: Notification[]) { + const snapNotificationsWithInterface = notificationsList.filter( + (notification) => { + return ( + notification.type === 'snap' && + hasProperty((notification as SnapNotification).data, 'detailedView') + ); + }, + ); + + const interfaceIdSet = new Set( + snapNotificationsWithInterface.map( + (notification) => + ( + (notification as SnapNotification) + .data as ExpandedSnapNotificationData + ).detailedView.interfaceId, + ), + ); + + this.update((state) => { + Object.entries(state.interfaces).forEach(([id, snapInterface]) => { + if ( + snapInterface.contentType === ContentType.Notification && + !interfaceIdSet.has(id) + ) { + delete state.interfaces[id]; + } + }); + }); + } } diff --git a/packages/snaps-controllers/src/snaps/SnapController.ts b/packages/snaps-controllers/src/snaps/SnapController.ts index f7e24db998..4fcea6f3fb 100644 --- a/packages/snaps-controllers/src/snaps/SnapController.ts +++ b/packages/snaps-controllers/src/snaps/SnapController.ts @@ -46,6 +46,7 @@ import type { RequestSnapsResult, SnapId, ComponentOrElement, + ContentType, } from '@metamask/snaps-sdk'; import { AuxiliaryFileEncoding, getErrorMessage } from '@metamask/snaps-sdk'; import type { @@ -3369,16 +3370,20 @@ export class SnapController extends BaseController< * * @param snapId - The snap ID. * @param content - The initial interface content. + * @param contentType - The type of content. * @returns An identifier that can be used to identify the interface. */ async #createInterface( snapId: SnapId, content: ComponentOrElement, + contentType?: ContentType, ): Promise { return this.messagingSystem.call( 'SnapInterfaceController:createInterface', snapId, content, + undefined, + contentType, ); } @@ -3416,7 +3421,6 @@ export class SnapController extends BaseController< // If a handler returns static content, we turn it into a dynamic UI if (castResult && hasProperty(castResult, 'content')) { const { content, ...rest } = castResult; - const id = await this.#createInterface( snapId, content as ComponentOrElement, diff --git a/packages/snaps-controllers/src/test-utils/controller.ts b/packages/snaps-controllers/src/test-utils/controller.ts index 52978aacaf..4bea263330 100644 --- a/packages/snaps-controllers/src/test-utils/controller.ts +++ b/packages/snaps-controllers/src/test-utils/controller.ts @@ -45,6 +45,7 @@ import type { import type { SnapInterfaceControllerActions, SnapInterfaceControllerAllowedActions, + SnapInterfaceControllerEvents, StoredInterface, } from '../interface/SnapInterfaceController'; import type { @@ -739,7 +740,7 @@ export const getRestrictedSnapsRegistryControllerMessenger = ( export const getRootSnapInterfaceControllerMessenger = () => { const messenger = new MockControllerMessenger< SnapInterfaceControllerActions | SnapInterfaceControllerAllowedActions, - never + SnapInterfaceControllerEvents >(); jest.spyOn(messenger, 'call'); @@ -756,7 +757,7 @@ export const getRestrictedSnapInterfaceControllerMessenger = ( const snapInterfaceControllerMessenger = messenger.getRestricted< 'SnapInterfaceController', SnapInterfaceControllerAllowedActions['type'], - never + SnapInterfaceControllerEvents['type'] >({ name: 'SnapInterfaceController', allowedActions: [ @@ -765,7 +766,10 @@ export const getRestrictedSnapInterfaceControllerMessenger = ( 'ApprovalController:hasRequest', 'ApprovalController:acceptRequest', ], - allowedEvents: [], + allowedEvents: [ + 'NotificationServicesController:notificationsListUpdated', + 'SnapInterfaceController:stateChange', + ], }); if (mocked) { diff --git a/packages/snaps-rpc-methods/src/permitted/createInterface.ts b/packages/snaps-rpc-methods/src/permitted/createInterface.ts index 6dc66c53fb..1dd983036f 100644 --- a/packages/snaps-rpc-methods/src/permitted/createInterface.ts +++ b/packages/snaps-rpc-methods/src/permitted/createInterface.ts @@ -7,6 +7,7 @@ import type { JsonRpcRequest, ComponentOrElement, InterfaceContext, + ContentType, } from '@metamask/snaps-sdk'; import { ComponentOrElementStruct, @@ -30,6 +31,7 @@ export type CreateInterfaceMethodHooks = { createInterface: ( ui: ComponentOrElement, context?: InterfaceContext, + contentType?: ContentType, ) => Promise; }; diff --git a/packages/snaps-rpc-methods/src/restricted/dialog.ts b/packages/snaps-rpc-methods/src/restricted/dialog.ts index d4b5fb6f78..f9091b6c78 100644 --- a/packages/snaps-rpc-methods/src/restricted/dialog.ts +++ b/packages/snaps-rpc-methods/src/restricted/dialog.ts @@ -18,6 +18,8 @@ import type { SnapId, PromptDialog, ComponentOrElement, + InterfaceContext, + ContentType, } from '@metamask/snaps-sdk'; import type { InferMatching } from '@metamask/snaps-utils'; import type { Infer } from '@metamask/superstruct'; @@ -61,6 +63,8 @@ type RequestUserApproval = ( type CreateInterface = ( snapId: string, content: ComponentOrElement, + context?: InterfaceContext, + contentType?: ContentType, ) => Promise; type GetInterface = ( diff --git a/packages/snaps-sdk/src/types/interface.ts b/packages/snaps-sdk/src/types/interface.ts index 3e8290cb3c..a587a0283c 100644 --- a/packages/snaps-sdk/src/types/interface.ts +++ b/packages/snaps-sdk/src/types/interface.ts @@ -45,3 +45,10 @@ export const ComponentOrElementStruct = selectiveUnion((value) => { export const InterfaceContextStruct = record(string(), JsonStruct); export type InterfaceContext = Infer; + +export enum ContentType { + Insight = 'Insight', + Dialog = 'Dialog', + Notification = 'Notification', + HomePage = 'HomePage', +} diff --git a/packages/snaps-simulation/src/controllers.ts b/packages/snaps-simulation/src/controllers.ts index 804279c36d..0877480b7d 100644 --- a/packages/snaps-simulation/src/controllers.ts +++ b/packages/snaps-simulation/src/controllers.ts @@ -85,7 +85,9 @@ export function getControllers(options: GetControllersOptions): Controllers { 'ApprovalController:hasRequest', 'ApprovalController:acceptRequest', ], - allowedEvents: [], + allowedEvents: [ + 'NotificationServicesController:notificationsListUpdated', + ], }), }); diff --git a/packages/snaps-simulation/src/methods/hooks/interface.test.ts b/packages/snaps-simulation/src/methods/hooks/interface.test.ts index ffad7cdaee..59bbe419d7 100644 --- a/packages/snaps-simulation/src/methods/hooks/interface.test.ts +++ b/packages/snaps-simulation/src/methods/hooks/interface.test.ts @@ -36,6 +36,7 @@ describe('getCreateInterfaceImplementation', () => { MOCK_SNAP_ID, content, undefined, + undefined, ); expect(result.content).toStrictEqual(getJsxElementFromComponent(content)); @@ -71,6 +72,7 @@ describe('getGetInterfaceImplementation', () => { state: {}, snapId: MOCK_SNAP_ID, context: null, + contentType: null, }); }); }); diff --git a/packages/snaps-simulation/src/methods/hooks/interface.ts b/packages/snaps-simulation/src/methods/hooks/interface.ts index 50a1343117..228742a338 100644 --- a/packages/snaps-simulation/src/methods/hooks/interface.ts +++ b/packages/snaps-simulation/src/methods/hooks/interface.ts @@ -1,4 +1,9 @@ -import type { Component, InterfaceContext, SnapId } from '@metamask/snaps-sdk'; +import type { + Component, + ContentType, + InterfaceContext, + SnapId, +} from '@metamask/snaps-sdk'; import type { RootControllerMessenger } from '../../controllers'; @@ -15,12 +20,14 @@ export function getCreateInterfaceImplementation( snapId: SnapId, content: Component, context?: InterfaceContext, + contentType?: ContentType, ) => controllerMessenger.call( 'SnapInterfaceController:createInterface', snapId, content, context, + contentType, ); } diff --git a/packages/snaps-simulation/src/test-utils/controller.ts b/packages/snaps-simulation/src/test-utils/controller.ts index 6913a30eb6..ac264f7cff 100644 --- a/packages/snaps-simulation/src/test-utils/controller.ts +++ b/packages/snaps-simulation/src/test-utils/controller.ts @@ -1,5 +1,8 @@ import { PhishingDetectorResultType } from '@metamask/phishing-controller'; -import type { SnapInterfaceControllerAllowedActions } from '@metamask/snaps-controllers'; +import type { + SnapInterfaceControllerAllowedActions, + SnapInterfaceControllerEvents, +} from '@metamask/snaps-controllers'; import { MockControllerMessenger } from '@metamask/snaps-utils/test-utils'; import type { RootControllerAllowedActions } from '../controllers'; @@ -47,7 +50,8 @@ export const getRestrictedSnapInterfaceControllerMessenger = ( ) => { const snapInterfaceControllerMessenger = messenger.getRestricted< 'SnapInterfaceController', - SnapInterfaceControllerAllowedActions['type'] + SnapInterfaceControllerAllowedActions['type'], + SnapInterfaceControllerEvents['type'] >({ name: 'SnapInterfaceController', allowedActions: [ @@ -56,7 +60,7 @@ export const getRestrictedSnapInterfaceControllerMessenger = ( 'ApprovalController:hasRequest', 'ApprovalController:acceptRequest', ], - allowedEvents: [], + allowedEvents: ['NotificationServicesController:notificationsListUpdated'], }); return snapInterfaceControllerMessenger; diff --git a/packages/snaps-simulator/src/features/simulation/hooks.test.ts b/packages/snaps-simulator/src/features/simulation/hooks.test.ts index 3efee20f20..a7afbe0434 100644 --- a/packages/snaps-simulator/src/features/simulation/hooks.test.ts +++ b/packages/snaps-simulator/src/features/simulation/hooks.test.ts @@ -336,6 +336,7 @@ describe('updateInterface', () => { snapId: snapId as SnapId, content: Box({ children: Text({ children: 'foo' }) }), context: null, + contentType: null, }), ) .silentRun(); diff --git a/packages/snaps-simulator/src/features/simulation/sagas.ts b/packages/snaps-simulator/src/features/simulation/sagas.ts index 8b0f64d7a4..f3184ae0ef 100644 --- a/packages/snaps-simulator/src/features/simulation/sagas.ts +++ b/packages/snaps-simulator/src/features/simulation/sagas.ts @@ -194,7 +194,9 @@ export function* initSaga({ payload }: PayloadAction) { `PhishingController:testOrigin`, `PhishingController:maybeUpdateState`, ], - allowedEvents: [], + allowedEvents: [ + 'NotificationServicesController:notificationsListUpdated', + ], }), }); diff --git a/packages/snaps-simulator/src/features/simulation/test/controllers.ts b/packages/snaps-simulator/src/features/simulation/test/controllers.ts index a28673c866..fd0e581bdd 100644 --- a/packages/snaps-simulator/src/features/simulation/test/controllers.ts +++ b/packages/snaps-simulator/src/features/simulation/test/controllers.ts @@ -20,7 +20,9 @@ export function getSnapInterfaceController() { 'PhishingController:maybeUpdateState', 'PhishingController:testOrigin', ], - allowedEvents: [], + allowedEvents: [ + 'NotificationServicesController:notificationsListUpdated', + ], }), }); }