You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat: Migrate controller guidelines and examples to new Messenger (#6335)
## Explanation
Migrate the controller guidelines and the `sample-controllers` package
to the `next` export of the `@metamask/base-controller` package and the
new `Messenger` class from `@metamask/messenger`.
## References
Relates to #5626
## Checklist
- [x] I've updated the test suite for new or updated code as appropriate
- [x] I've updated documentation (JSDoc, Markdown, etc.) for new or
updated code as appropriate
- [x] I've communicated my changes to consumers by [updating changelogs
for packages I've
changed](https://github.com/MetaMask/core/tree/main/docs/contributing.md#updating-changelogs),
highlighting breaking changes as necessary
- [x] I've prepared draft pull requests for clients and consumer
packages to resolve any breaking changes
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> Migrate controller docs and sample-controllers to the new
@metamask/messenger Messenger and @metamask/base-controller/next,
updating APIs, metadata, tests, and dependencies.
>
> - **Docs**
> - Rewrite guidelines and data-services to use `@metamask/messenger`
`Messenger` instead of `RestrictedMessenger`; update examples for
actions/events typing, root/child messenger setup, delegation, and
selector utilities (`MessengerActions`/`MessengerEvents`).
> - Replace references to “messaging system” with “messenger”; update
code samples to
`messenger.call/subscribe/publish/registerMethodActionHandlers`.
> - **Sample Controllers** (`@metamask/sample-controllers`)
> - Migrate to `@metamask/base-controller/next` and
`@metamask/messenger`.
> - Replace `messagingSystem.*` with `messenger.*`; update
controller/service messenger types to `Messenger<...>` and constructor
usage.
> - Update state metadata (`anonymous` → `includeInDebugSnapshot`).
> - Revise tests to use new `Messenger`, mock namespace utilities, and
`MessengerActions/MessengerEvents`.
> - Add dependency on `@metamask/messenger`; update TS project
references.
> - Changelog: mark BREAKING changes for Messenger migration and
metadata rename.
> - **Repo/README**
> - Dependency graph: add `sample_controllers --> messenger`; add
middleware/controller edge; list `@metamask/messenger` package.
>
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
c1ad7a4. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
---------
Co-authored-by: Elliot Winkler <[email protected]>
Co-authored-by: Michele Esposito <[email protected]>
Copy file name to clipboardExpand all lines: docs/data-services.md
+53-35Lines changed: 53 additions & 35 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -2,14 +2,14 @@
2
2
3
3
## What is a data service?
4
4
5
-
A **data service** is a pattern for making interactions with an external API (fetching token prices, storing accounts, etc.). It is implemented as a plain TypeScript class with methods that are exposed through the messaging system.
5
+
A **data service** is a pattern for making interactions with an external API (fetching token prices, storing accounts, etc.). It is implemented as a plain TypeScript class with methods that are exposed through a messenger.
6
6
7
7
## Why use this pattern?
8
8
9
9
If you want to talk to an API, it might be tempting to define a method in the controller or a function in a separate file. However, implementing the data service pattern is advantageous for the following reasons:
10
10
11
11
1. The pattern provides an abstraction that allows for implementing and reusing strategies that are common when working with external APIs, such as batching, automatic retries with exponential backoff, etc.
12
-
2. By integrating with the messaging system, other parts of the application can make use of the data service without needing to go through the controller, or in fact, without needing a reference to the data service at all.
12
+
2. By integrating with a messenger, other parts of the application can make use of the data service without needing to go through the controller, or in fact, without needing a reference to the data service at all.
13
13
14
14
## How to create a data service
15
15
@@ -78,7 +78,7 @@ Next we'll define the messenger. We give the messenger a namespace, and we expos
Note that we need to add `@metamask/base-controller` as a direct dependency of the package to bring in the `RestrictedMessenger` type (here we assume that our package is called `@metamask/gas-prices-controller`):
107
+
Note that we need to add `@metamask/messenger` as a direct dependency of the package to bring in the `Messenger` type (here we assume that our package is called `@metamask/gas-prices-controller`):
function buildMessenger():GasPricesServiceMessenger {
378
-
returnnewMessenger().getRestricted({
379
-
name: 'GasPricesService',
380
-
allowedActions: [],
381
-
allowedEvents: [],
380
+
returnnewMessenger<
381
+
'GasPricesService',
382
+
GasPricesServiceActions,
383
+
GasPricesServiceEvents
384
+
>({
385
+
namespace: 'GasPricesService',
382
386
});
383
387
}
384
388
```
@@ -387,30 +391,37 @@ function buildMessenger(): GasPricesServiceMessenger {
387
391
388
392
## How to use a data service
389
393
390
-
Let's say that we wanted to use our data service that we built above. To do this, we will instantiate the messenger for the data service — which itself relies on a global messenger — and then the data service itself.
394
+
Let's say that we wanted to use our data service that we built above. To do this, we will instantiate the messenger for the data service — which itself relies on a root messenger — and then the data service itself.
Now we instantiate the data service to register the action handler on the global messenger. We assume we have a global `fetch` function available:
424
+
Now we instantiate the data service to register the action handler on the root messenger. We assume we have a global `fetch` function available:
414
425
415
426
```typescript
416
427
const gasPricesService =newGasPricesService({
@@ -421,7 +432,7 @@ const gasPricesService = new GasPricesService({
421
432
422
433
Great! Now that we've set up the data service and its messenger action, we can use it somewhere else.
423
434
424
-
Let's say we wanted to use it in a controller. We'd just need to allow that controller's messenger access to `GasPricesService:fetchGasPrices`by passing it via the `allowedActions` option.
435
+
Let's say we wanted to use `GasPricesService:fetchGasPrices` in a controller. First, that controller's messenger would need to include `GasPricesService:fetchGasPrices`in its type defintion.
425
436
426
437
This code would probably be in the controller package itself. For instance, if we had a file `packages/send-controller/send-controller.ts`, we might have:
427
438
@@ -436,23 +447,30 @@ type SendControllerEvents = ...;
436
447
437
448
type AllowedEvents =...;
438
449
439
-
type SendControllerMessenger =RestrictedMessenger<
450
+
type SendControllerMessenger =Messenger<
440
451
'SendController',
441
452
SendControllerActions| AllowedActions,
442
453
SendControllerEvents| AllowedEvents,
443
-
AllowedActions['type'],
444
-
AllowedEvents['type']
445
454
>;
446
455
```
447
456
457
+
Then we'll need to allow that controller's messenger access to `GasPricesService:fetchGasPrices` by delegating it from the root messenger:
0 commit comments