Skip to content

feat(platform-api-docs): add root-messenger strategy - #9913

Open
cryptodev-2s wants to merge 5 commits into
mainfrom
feat/platform-api-docs-root-messenger-strategy
Open

feat(platform-api-docs): add root-messenger strategy#9913
cryptodev-2s wants to merge 5 commits into
mainfrom
feat/platform-api-docs-root-messenger-strategy

Conversation

@cryptodev-2s

@cryptodev-2s cryptodev-2s commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Explanation

@metamask/platform-api-docs documents 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, and node_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-mobile and ~4,500 in metamask-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.

--strategy

  • scan (default) — unchanged behaviour, and the only option for a project with no single aggregating messenger.
  • root-messenger — resolves the two types named by --root-actions and --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 other
bad 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-mobile writes GlobalActions by hand as a union of type references. A syntactic walk would work.
  • metamask-extension derives RootMessengerActions from a registry of messenger factories via
    MessengerActions<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 to scan. The new module is a discovery front-end, not a second extractor.

Two details worth knowing:

  • A capability declared as a type alias carries its name and JSDoc on the alias symbol; the plain symbol points at the anonymous object type. An interface has no alias symbol, being its own declaration, so both are
    consulted. Missing the interface case silently dropped 61 actions and 8 events on mobile before it was fixed.
  • For a lone generic instantiation (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. writeOutput deletes docs/ before writing, so a root union that resolves to nothing — a renamed type, or imports that don't resolve — would previously have replaced a
published 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

escapeJsDocTextForMdx escaped { and } but not <, which MDX reads as the start of a JSX tag. A @returns comment such as Promise<PointsBoostDto[]> therefore failed the site build rather than rendering:

Unexpected character `[` (U+005B) in name, expected a name character…

This is pre-existing and independent of the new strategy — scan produces the byte-identical line — but it blocked --build and --serve for both clients, so it is fixed here. Affects description, @param, and @returns text; handler and payload signatures were already safe inside fenced code blocks.


Benchmarks

Measured on a warm checkout, doc generation only.

Project scan root-messenger Speedup
metamask-extension 47.9s 4.7s ~10×
metamask-mobile 96.9s 5.7s ~17×

scan parses ~5,600 app/**/*.ts plus ~6,026 .d.cts in mobile, and ~4,472 .d.cts in the extension. root-messenger opens the entry file and lets the checker pull in only what the union references.

Strategy comparison

metamask-mobile

scan root-messenger
Namespaces 112 103
Actions 1184 1157
Events 181 171
Unique capabilities 1365 1328 (97.3%)

The 37 not documented are mostly controllers genuinely not on the root messengerPasskeyController alone accounts for 17, plus RatesController (4), the sample controllers, and the decrypt/encrypt message managers. Nothing is found by root-messenger that scan misses.

metamask-extension

scan root-messenger
Namespaces 119 115
Actions 1209 1085
Events 183 176
Unique capabilities 1392 1261 (90.6%)

99 of the 131-capability gap is PerpsController, and the cause is worth flagging to the extension team rather than treating as a tool limitation:

export type PerpsControllerMessenger = Messenger<
  'PerpsController',
  AllowedActions,   // actions Perps may CALL
  AllowedEvents
>;

RootMessengerActions is MessengerActions<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. PerpsController is registered in
MESSENGER_FACTORIES yet contributes zero constituents.

root-messenger documents 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-messenger finds 6 capabilities scan misses(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:

--project-label Extension
--root-actions 'app/scripts/lib/messenger.ts#RootMessengerActions'
--root-events  'app/scripts/lib/messenger.ts#RootMessengerEvents'

Notes for consumers:

  • Keep the # inside quotes — unquoted, most shells treat it as a comment and silently truncate the argument.
  • --root-actions / --root-events are relative to the project path, not the shell's working directory.
  • Output defaults to <project-path>/.platform-api-docs; gitignore it.
  • metamask-extension additionally needs its postcss-loader/jiti resolution narrowed to postcss-loader@^8.2.1/jiti. The unversioned form also stubs the postcss-loader@^7.3.4 that @docusaurus/bundler depends on, replacing jiti with an empty package and breaking the site build. Narrowing preserves the stub's original intent for the extension's own postcss-loader@8.2.1.

References

Fixes: https://consensyssoftware.atlassian.net/browse/WPC-1202

Checklist

  • I've updated the test suite for new or updated code as appropriate
  • I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate
  • I've communicated my changes to consumers by updating changelogs for packages I've changed
  • I've introduced breaking changes in this PR and have prepared draft pull requests for clients and consumer packages to resolve them

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-messenger docs generation path alongside the existing scan default. Clients can point at their root action/event unions via --root-actions and --root-events (<file>#<TypeName>); the CLI validates strategy-specific flags so mixed invocations fail loudly.

root-messenger uses the TypeScript checker to expand those unions (including computed unions like MessengerActions<…>), then reuses the shared extractor so output matches scan. Skipped inline or unextractable capabilities get named warnings; resolving to nothing or any/unknown throws 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.

@cryptodev-2s
cryptodev-2s requested a review from a team as a code owner August 19, 2026 21:30
@cryptodev-2s
cryptodev-2s deployed to default-branch August 19, 2026 21:31 — with GitHub Actions Active
Comment thread packages/platform-api-docs/src/root-messenger-discovery.ts
@cryptodev-2s
cryptodev-2s force-pushed the feat/platform-api-docs-root-messenger-strategy branch from 8db1696 to 81fb650 Compare August 19, 2026 21:35
Comment thread packages/platform-api-docs/src/root-messenger-discovery.ts Outdated
@cryptodev-2s

Copy link
Copy Markdown
Contributor Author

@metamaskbot publish-preview

@cryptodev-2s
cryptodev-2s requested a review from mcmire August 19, 2026 21:42
@cryptodev-2s cryptodev-2s self-assigned this Aug 19, 2026
@cryptodev-2s

Copy link
Copy Markdown
Contributor Author

@metamaskbot publish-preview

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ 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.

Comment thread packages/platform-api-docs/src/root-messenger-discovery.ts Outdated
@cryptodev-2s

Copy link
Copy Markdown
Contributor Author

@metamaskbot publish-preview

@cryptodev-2s
cryptodev-2s force-pushed the feat/platform-api-docs-root-messenger-strategy branch from e514f29 to 3c77cf4 Compare August 20, 2026 12:41
@cryptodev-2s

Copy link
Copy Markdown
Contributor Author

@metamaskbot publish-preview

@github-actions

Copy link
Copy Markdown
Contributor

Preview builds have been published. Learn how to use preview builds in other projects.

Expand for full list of packages and versions.
@metamask-previews/account-tree-controller@8.0.0-preview-3c77cf4
@metamask-previews/accounts-controller@39.1.0-preview-3c77cf4
@metamask-previews/address-book-controller@7.1.2-preview-3c77cf4
@metamask-previews/ai-controllers@0.8.0-preview-3c77cf4
@metamask-previews/analytics-controller@2.0.0-preview-3c77cf4
@metamask-previews/analytics-data-regulation-controller@0.0.0-preview-3c77cf4
@metamask-previews/announcement-controller@8.1.0-preview-3c77cf4
@metamask-previews/app-metadata-controller@2.0.1-preview-3c77cf4
@metamask-previews/approval-controller@9.0.2-preview-3c77cf4
@metamask-previews/assets-controller@13.1.4-preview-3c77cf4
@metamask-previews/assets-controllers@111.1.1-preview-3c77cf4
@metamask-previews/authenticated-user-storage@3.0.1-preview-3c77cf4
@metamask-previews/base-controller@9.1.0-preview-3c77cf4
@metamask-previews/base-data-service@0.1.3-preview-3c77cf4
@metamask-previews/bitcoin-regtest-up@1.0.0-preview-3c77cf4
@metamask-previews/bridge-controller@79.2.0-preview-3c77cf4
@metamask-previews/bridge-status-controller@75.1.0-preview-3c77cf4
@metamask-previews/build-utils@3.0.4-preview-3c77cf4
@metamask-previews/chain-agnostic-permission@1.7.0-preview-3c77cf4
@metamask-previews/chomp-api-service@4.0.0-preview-3c77cf4
@metamask-previews/claims-controller@0.6.0-preview-3c77cf4
@metamask-previews/client-controller@1.0.1-preview-3c77cf4
@metamask-previews/client-utils@2.0.2-preview-3c77cf4
@metamask-previews/compliance-controller@2.1.0-preview-3c77cf4
@metamask-previews/composable-controller@12.0.1-preview-3c77cf4
@metamask-previews/config-registry-controller@2.0.1-preview-3c77cf4
@metamask-previews/connectivity-controller@0.3.0-preview-3c77cf4
@metamask-previews/controller-utils@12.3.0-preview-3c77cf4
@metamask-previews/core-backend@8.1.2-preview-3c77cf4
@metamask-previews/delegation-controller@3.0.2-preview-3c77cf4
@metamask-previews/earn-controller@12.2.5-preview-3c77cf4
@metamask-previews/eip-5792-middleware@3.0.5-preview-3c77cf4
@metamask-previews/eip-7702-internal-rpc-middleware@0.1.1-preview-3c77cf4
@metamask-previews/eip1193-permission-middleware@2.0.1-preview-3c77cf4
@metamask-previews/eth-block-tracker@15.0.1-preview-3c77cf4
@metamask-previews/eth-json-rpc-middleware@24.0.0-preview-3c77cf4
@metamask-previews/eth-json-rpc-provider@6.0.1-preview-3c77cf4
@metamask-previews/foundryup@1.0.1-preview-3c77cf4
@metamask-previews/gas-fee-controller@26.3.1-preview-3c77cf4
@metamask-previews/gator-permissions-controller@5.0.1-preview-3c77cf4
@metamask-previews/geolocation-controller@1.0.0-preview-3c77cf4
@metamask-previews/java-tron-up@1.0.0-preview-3c77cf4
@metamask-previews/json-rpc-engine@10.5.0-preview-3c77cf4
@metamask-previews/json-rpc-middleware-stream@8.0.8-preview-3c77cf4
@metamask-previews/keyring-controller@27.1.1-preview-3c77cf4
@metamask-previews/kyc-controller@0.0.0-preview-3c77cf4
@metamask-previews/local-node-utils@1.0.0-preview-3c77cf4
@metamask-previews/logging-controller@9.0.0-preview-3c77cf4
@metamask-previews/message-manager@14.1.2-preview-3c77cf4
@metamask-previews/messenger@2.0.0-preview-3c77cf4
@metamask-previews/messenger-cli@0.2.0-preview-3c77cf4
@metamask-previews/money-account-api-data-service@0.4.0-preview-3c77cf4
@metamask-previews/money-account-balance-service@2.4.1-preview-3c77cf4
@metamask-previews/money-account-controller@1.0.0-preview-3c77cf4
@metamask-previews/money-account-upgrade-controller@3.0.1-preview-3c77cf4
@metamask-previews/money-account-utils@1.1.0-preview-3c77cf4
@metamask-previews/multichain-account-service@13.0.2-preview-3c77cf4
@metamask-previews/multichain-api-middleware@4.0.2-preview-3c77cf4
@metamask-previews/multichain-network-controller@3.2.3-preview-3c77cf4
@metamask-previews/multichain-transactions-controller@7.1.2-preview-3c77cf4
@metamask-previews/name-controller@9.1.2-preview-3c77cf4
@metamask-previews/network-connection-banner-controller@0.2.0-preview-3c77cf4
@metamask-previews/network-controller@35.0.1-preview-3c77cf4
@metamask-previews/network-enablement-controller@6.0.3-preview-3c77cf4
@metamask-previews/notification-services-controller@26.0.1-preview-3c77cf4
@metamask-previews/passkey-controller@3.0.0-preview-3c77cf4
@metamask-previews/permission-controller@13.1.1-preview-3c77cf4
@metamask-previews/permission-log-controller@5.1.0-preview-3c77cf4
@metamask-previews/perps-controller@12.1.0-preview-3c77cf4
@metamask-previews/phishing-controller@17.3.1-preview-3c77cf4
@metamask-previews/platform-api-docs@0.0.0-preview-3c77cf4
@metamask-previews/polling-controller@16.0.9-preview-3c77cf4
@metamask-previews/preferences-controller@23.1.0-preview-3c77cf4
@metamask-previews/profile-metrics-controller@4.0.3-preview-3c77cf4
@metamask-previews/profile-sync-controller@29.0.0-preview-3c77cf4
@metamask-previews/ramps-controller@20.0.0-preview-3c77cf4
@metamask-previews/rate-limit-controller@7.0.1-preview-3c77cf4
@metamask-previews/react-data-query@0.2.2-preview-3c77cf4
@metamask-previews/remote-feature-flag-controller@5.0.0-preview-3c77cf4
@metamask-previews/sample-controllers@5.0.4-preview-3c77cf4
@metamask-previews/seedless-onboarding-controller@10.1.1-preview-3c77cf4
@metamask-previews/selected-network-controller@26.1.6-preview-3c77cf4
@metamask-previews/sentinel-api-service@1.0.0-preview-3c77cf4
@metamask-previews/shield-controller@6.0.0-preview-3c77cf4
@metamask-previews/signature-controller@39.2.9-preview-3c77cf4
@metamask-previews/smart-transactions-controller@25.1.0-preview-3c77cf4
@metamask-previews/snap-account-service@2.1.2-preview-3c77cf4
@metamask-previews/social-controllers@2.7.1-preview-3c77cf4
@metamask-previews/solana-test-validator-up@1.0.0-preview-3c77cf4
@metamask-previews/stellar-quickstart-up@0.0.0-preview-3c77cf4
@metamask-previews/storage-service@1.0.2-preview-3c77cf4
@metamask-previews/subscription-controller@8.0.0-preview-3c77cf4
@metamask-previews/transaction-controller@69.5.2-preview-3c77cf4
@metamask-previews/transaction-pay-controller@26.4.0-preview-3c77cf4
@metamask-previews/user-operation-controller@41.2.8-preview-3c77cf4
@metamask-previews/wallet@11.0.0-preview-3c77cf4
@metamask-previews/wallet-cli@0.0.0-preview-3c77cf4

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant