-
-
Notifications
You must be signed in to change notification settings - Fork 242
feat: Add messenger delegate
and revoke
methods
#6132
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
4876850
to
e3899db
Compare
776c9b8
to
c249e17
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had some comments, mostly around documentation, but I was also curious about some behavior in delegate
which seems to be replicated in #registerInitialEventPayload
.
constructor({ namespace }: { namespace: Namespace }) { | ||
this.#namespace = namespace; | ||
} | ||
|
||
/** | ||
* Register an action handler. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To better distinguish this method from registerDelegatedActionHandler
, should we clarify that the action here is one that the messenger "owns"?
* Register an action handler. | |
* Register a handler for an action under this messenger's namespace. |
Or, perhaps literally:
* Register an action handler. | |
* Register an action owned by this messenger. |
@@ -160,7 +196,42 @@ export class Messenger< | |||
* @throws Will throw when a handler has been registered for this action type already. | |||
* @template ActionType - A type union of Action type strings. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe this should say:
* @template ActionType - A type union of Action type strings. | |
* @template ActionType - A union of type strings for actions under this messenger's namespace. |
* Register a delegated action handler. | ||
* | ||
* This will make the registered function available to call via the `call` method. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it worth expanding this description slightly to clarify what "delegated" means? My thought is that it might seem odd that we are defining a method that is very similar to registerActionHandler
, but doesn't require that the action has this messenger's namespace or that the action is one that this messenger recognizes.
* Register a delegated action handler. | |
* | |
* This will make the registered function available to call via the `call` method. | |
* Register a delegated action handler (that is, a handler which comes from another messenger | |
* that this messenger is permitted to call). | |
* | |
* This will make the registered function available to call via the `call` method. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess if we make this change, we may have to clarify what "delegated" means for other methods that handle delegation, so there is that.
Alternatively, we could tell people to read the docs for delegate
if they want more context. I know we mention this method in the @deprecate
tag, but it might be missed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The idea was that these delegated____
methods are internal-only (i.e. called only from within this class). I wasn't too concerned with making the intended usage clear, so long as we understand the intended usage. Everyone else just needs to understand not to call this, ever.
Maybe there is something better than deprecating we can do to achieve this though, e.g. move it under a namespace or something.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The idea was that these
delegated____
methods are internal-only (i.e. called only from within this class). I wasn't too concerned with making the intended usage clear, so long as we understand the intended usage. Everyone else just needs to understand not to call this, ever.
Yeah, that's fair.
Maybe there is something better than deprecating we can do to achieve this though, e.g. move it under a namespace or something.
Maybe we could prefix the methods with something ugly like __INTERNAL__
or __PRIVATE__
or just _
? But then again, VSCode will highlight the usage of the method as deprecated with an underline, so if you were to use it, I feel like you would know. Maybe the @deprecated
is good enough.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll try something different out, I wasn't totally happy with relying on just the method name prefix + @deprecated
tag. I'll attempt to revise the description as well.
@@ -180,7 +251,7 @@ export class Messenger< | |||
* handlers | |||
*/ | |||
registerMethodActionHandlers< | |||
MessengerClient extends { name: string }, | |||
MessengerClient extends { name: Namespace }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, good catch.
handler: | ||
| ActionHandler<Action, ActionType> | ||
| ActionHandler<ActionConstraint, ActionType>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems to allow any kind of action handler, but if ActionType
must refer to an action that this messenger recognizes, then shouldn't the handler be connected to that action?
handler: | |
| ActionHandler<Action, ActionType> | |
| ActionHandler<ActionConstraint, ActionType>, | |
handler: ActionHandler<Action, ActionType>, |
} | ||
|
||
/** | ||
* Publish a delegated event. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar as above — is it worth adding more language here?
* Publish a delegated event. | |
* Publish a delegated event (that is, an event published by another messenger that this | |
* messenger is permitted to subscribe to). |
* @template AllowedEvent - A type union of the 'type' string for any allowed events. | ||
* This must not include internal events that are in the messenger's namespace. | ||
* @returns The restricted messenger. | ||
* Delegate actions and/or events to another messenger. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it worth explaining what this does?
* Delegate actions and/or events to another messenger. | |
* Delegate actions and/or events to another messenger. | |
* | |
* - For all actions specified, this method will register an action handler | |
* on the given messenger that calls the same action within this messenger. | |
* - For all events specified, this method will register an event handler | |
* on this messenger that publishes the same event within that messenger. | |
* | |
* In other words: | |
* | |
* - The delegated messenger is able to call any of the specified actions | |
* known to this messenger as though they had been registered directly; when | |
* they are called there, they are called here. | |
* - The delegated messenger is able to subscribe to any of the specified | |
* events known to this messenger; when they are published here they will | |
* be published there as well. | |
* | |
* Note that to delegate an action to a messenger, it needs to be already | |
* present in the type union of all Action types for that messenger; and | |
* similarly for an event. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Also, if any of that is wrong, feel free to correct me)
const getPayload = this.#initialEventPayloadGetters.get(eventType); | ||
if (getPayload) { | ||
messenger.registerDelegatedInitialEventPayload({ | ||
eventType, | ||
getPayload, | ||
}); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems like we are already calling registerDelegatedInitialEventPayload
for all delegation targets within #registerInitialEventPayload
. Do we need this?
const getPayload = this.#initialEventPayloadGetters.get(eventType); | |
if (getPayload) { | |
messenger.registerDelegatedInitialEventPayload({ | |
eventType, | |
getPayload, | |
}); | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes; this is for the case where the initial payload is registered before the delegation. My intent was to support both scenarios (see the correctly registers initial event payload when delegated before payload is set
and correctly registers initial event payload when delegated after payload is set
tests)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice!
|
||
- **BREAKING:** Add `Namespace` type parameter and required `namespace` constructor parameter ([#6132](https://github.com/MetaMask/core/pull/6132)) | ||
- All published events and registered actions should fall under the given namespace. Typically the namespace is the controller or service name. This is the equivalent to the `Namespace` parameter from the old `RestrictedMessenger` class. | ||
- **BREAKING:** Remove `RestrictedMessenger` class ([#6132](https://github.com/MetaMask/core/pull/6132)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be in "Removed"?
Action extends ActionConstraint, | ||
Event extends EventConstraint, | ||
> = Pick< | ||
Messenger<string, Action | ActionConstraint, Event | EventConstraint>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar question to https://github.com/MetaMask/core/pull/6132/files#r2226392393 — why do we need to allow any kind of action or event?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good question. I ran into problems with covariance/contravariance here (see https://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science)), but I can't recall the specifics. I'll investigate.
The methods `delegate` and `revoke` have been added to the Messenger class. These methods replace the need for the `RestrictedMessenger`. The `getRestricted` method, and the `RestrictedMessenger` class, have been removed as obsolete. See this ADR PR for details: MetaMask/decisions#53
2dd241a
to
6729773
Compare
Explanation
The methods
delegate
andrevoke
have been added to the Messenger class. These methods replace the need for theRestrictedMessenger
. ThegetRestricted
method, and theRestrictedMessenger
class, have been removed as obsolete.Note that the
parent
constructor parameter described in the ADR is not implemented yet, that will come in the next PR.References
See this ADR PR for details: MetaMask/decisions#53
Relates to #5626
Checklist