feat(platform-api-docs): add root-messenger strategy - #9913
Open
cryptodev-2s wants to merge 5 commits into
Open
Conversation
cryptodev-2s
force-pushed
the
feat/platform-api-docs-root-messenger-strategy
branch
from
August 19, 2026 21:35
8db1696 to
81fb650
Compare
Contributor
Author
|
@metamaskbot publish-preview |
Contributor
Author
|
@metamaskbot publish-preview |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 5fe1f30. Configure here.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Explanation
@metamask/platform-api-docsdocuments the platform API — every messenger action and event a project exposes. Until now it had one way of finding them: parse every TypeScript source and declaration file it can reach (the scan directories,packages/*/src, andnode_modules/@metamask/*/dist/**/*.d.cts) and walk every type alias named*Messenger.That is the right approach for this monorepo, which has no single messenger aggregating every capability. It is a poor fit for a client, which already declares the complete set on its root messenger. Re-deriving that from the whole dependency tree means parsing ~11,600 files in
metamask-mobileand ~4,500 inmetamask-extension, to rediscover something the client has written down in one place.This PR adds a second strategy that reads what the client already declares.
--strategyscan(default) — unchanged behaviour, and the only option for a project with no single aggregating messenger.root-messenger— resolves the two types named by--root-actionsand--root-events(each written<file>#<TypeName>) and lets the TypeScript type checker enumerate them. Only the named files are opened; the checker pulls in the rest.Flags belonging to the strategy that wasn't selected are rejected rather than ignored, via a yargs
.check, so a mistaken invocation fails loudly instead of quietly producing docs built the wrong way. The<file>#<TypeName>references are parsed in a yargs.coerce, so a malformed one is reported like any otherbad argument before work begins.
Why the type checker rather than the AST
This is the non-obvious part. The two clients declare their root unions differently:
metamask-mobilewritesGlobalActionsby hand as a union of type references. A syntactic walk would work.metamask-extensionderivesRootMessengerActionsfrom a registry of messenger factories viaMessengerActions<ReturnType<(typeof MESSENGER_FACTORIES)[…]['getMessenger']>>.There is no syntactic union to walk — only the type checker can say what it contains.
Going through the checker handles both shapes with one code path. Once it reports which capability types are in the union, each declaration is handed to the existing extractor in
extraction.ts, so JSDoc, handler/payload signatures, source links, and deprecation flags come out identical toscan. The new module is a discovery front-end, not a second extractor.Two details worth knowing:
consulted. Missing the interface case silently dropped 61 actions and 8 events on mobile before it was fixed.
type Actions = Foo<Bar>) the checker attributes the alias to the root union itself, which would hand the extractor the wrong declaration. That case is guarded.Failure behaviour
Generation now fails loudly instead of producing an empty site.
writeOutputdeletesdocs/before writing, so a root union that resolves to nothing — a renamed type, or imports that don't resolve — would previously have replaced apublished docs directory with an empty one and exited
0. It now throws, naming both references.Capability types that can't be documented are reported with their names rather than counted, in three buckets: declared inline (no name or JSDoc), unresolved (
any/unknown, usually a failed import), and unextractable (a shape the extractor rejects). A count alone isn't actionable at this scale.Also fixed: MDX escaping
escapeJsDocTextForMdxescaped{and}but not<, which MDX reads as the start of a JSX tag. A@returnscomment such asPromise<PointsBoostDto[]>therefore failed the site build rather than rendering:This is pre-existing and independent of the new strategy —
scanproduces the byte-identical line — but it blocked--buildand--servefor both clients, so it is fixed here. Affects description,@param, and@returnstext; handler and payload signatures were already safe inside fenced code blocks.Benchmarks
Measured on a warm checkout, doc generation only.
scanroot-messengermetamask-extensionmetamask-mobilescanparses ~5,600app/**/*.tsplus ~6,026.d.ctsin mobile, and ~4,472.d.ctsin the extension.root-messengeropens the entry file and lets the checker pull in only what the union references.Strategy comparison
metamask-mobilescanroot-messengerThe 37 not documented are mostly controllers genuinely not on the root messenger —
PasskeyControlleralone accounts for 17, plusRatesController(4), the sample controllers, and the decrypt/encrypt message managers. Nothing is found byroot-messengerthatscanmisses.metamask-extensionscanroot-messenger99 of the 131-capability gap is
PerpsController, and the cause is worth flagging to the extension team rather than treating as a tool limitation:RootMessengerActionsisMessengerActions<ChildMessengers>— the union of what each child messenger is allowed to call, not what each controller provides. A controller whose actions are only invoked from the UI, never from another controller's messenger, never appears.PerpsControlleris registered inMESSENGER_FACTORIESyet contributes zero constituents.root-messengerdocuments exactly what the named types contain. Full coverage in. the extension needs an aggregate of provided actions, which is an extension-side change.Conversely,
root-messengerfinds 6 capabilitiesscanmisses(MultichainRoutingService×4,PPOMController×2).Reported-but-skipped, current run: mobile 39 unextractable; extension 2 inline + 33 unextractable.
Usage in clients
Once published, add the dependency and two scripts. For
metamask-mobile:{ "scripts": { "docs:platform-api:build": "platform-api-docs --build --project-label Mobile --strategy root-messenger --root-actions 'app/core/Engine/types.ts#GlobalActions' --root-events 'app/core/Engine/types.ts#GlobalEvents'", "docs:platform-api:serve": "platform-api-docs --serve --project-label Mobile --site-base-url / --strategy root-messenger --root-actions 'app/core/Engine/types.ts#GlobalActions' --root-events 'app/core/Engine/types.ts#GlobalEvents'" } }For
metamask-extension, the label and references change:Notes for consumers:
#inside quotes — unquoted, most shells treat it as a comment and silently truncate the argument.--root-actions/--root-eventsare relative to the project path, not the shell's working directory.<project-path>/.platform-api-docs; gitignore it.metamask-extensionadditionally needs itspostcss-loader/jitiresolution narrowed topostcss-loader@^8.2.1/jiti. The unversioned form also stubs thepostcss-loader@^7.3.4that@docusaurus/bundlerdepends on, replacingjitiwith an empty package and breaking the site build. Narrowing preserves the stub's original intent for the extension's ownpostcss-loader@8.2.1.References
Fixes: https://consensyssoftware.atlassian.net/browse/WPC-1202
jitiresolution fix): feat: wire up @metamask/platform-api-docs metamask-extension#40352Checklist
Note
Medium Risk
Large new discovery path and stricter generate failure modes could break client doc CI if root types or imports are wrong; changes are confined to the docs tool, not runtime wallet logic.
Overview
Adds a
root-messengerdocs generation path alongside the existingscandefault. Clients can point at their root action/event unions via--root-actionsand--root-events(<file>#<TypeName>); the CLI validates strategy-specific flags so mixed invocations fail loudly.root-messengeruses the TypeScript checker to expand those unions (including computed unions likeMessengerActions<…>), then reuses the shared extractor so output matchesscan. Skipped inline or unextractable capabilities get named warnings; resolving to nothing orany/unknownthrows instead of writing an empty docs tree.Also escapes
<in JSDoc for MDX (fixes site builds on generic return/param text) and documents the new options in the README.Reviewed by Cursor Bugbot for commit 11c0860. Bugbot is set up for automated code reviews on this repo. Configure here.