Skip to content

feat: add Universal dev mode feature flag#30055

Open
Jwhiles wants to merge 7 commits into
mainfrom
universal-dev-mode-feature-flag
Open

feat: add Universal dev mode feature flag#30055
Jwhiles wants to merge 7 commits into
mainfrom
universal-dev-mode-feature-flag

Conversation

@Jwhiles
Copy link
Copy Markdown
Contributor

@Jwhiles Jwhiles commented May 12, 2026

Description

It's currently very awkward to point the mobile app at non-prod backends. AuthenticationController is pinned to Env.PRD, so to test against dev you have to hand-edit its init, plus every downstream service's URL. Any that you don't update will throw errors for all upstream requests.

This PR adds a build time switch — MM_DEV_API_ENV=dev | prod in .js.env that the auth controller reads at init time.

I've attempted to wire up all the consumers of the auth controller with this flag when it easy to do so - but there are a few which have proven difficult to wire up. They are the following:

  • TokenBalancesController — accounts-API URL sealed in @metamask/assets-controllers.
  • AssetsController via createApiPlatformClientAPI_URLS sealed in @metamask/core-backend.
  • NotificationServicesPushController — its config.env is Firebase env, not backend env.

TODO

  1. Verify dev-api hostnames for Sentinel and Perps. Both currently assume
    the *.api.cx.metamask.io*.dev-api.cx.metamask.io convention; if
    either deviates, swap apiUrl() for an explicit map (TODO comments
    mark the call sites).
  2. Potentially Retire BRIDGE_USE_DEV_APIS. It's redundant with MM_DEV_API_ENV=dev but is referenced by scripts/verify-build-config.js, scripts/apply-build-config.js, scripts/build-announce/env-validation-section.ts, builds.yml, bitrise.yml, the E2E GitHub workflows, and .js.env.example.
  3. Either
    1. Make upstream updates to TokenBalancesController, AssetsController, and NotificationServicesPushController
    2. Or accept that these services will fail with this dev flag set

Changelog

CHANGELOG entry: Add dev API testing feature flag

Related issues

Fixes:

Manual testing steps

echo 'export MM_DEV_API_ENV="dev"' >> .js.env
yarn watch:clean && yarn start:ios

Sign in, then confirm that outbund requests target
*.dev-api.cx.metamask.io - and that the JWT issuer claim (iss) should be
https://oidc.dev-api.cx.metamask.io.

Feature: my feature name

  Scenario: user [verb for user action]
    Given [describe expected initial app state]

    When user [verb for user action]
    Then [describe expected outcome]

Screenshots/Recordings

Before

After

Pre-merge author checklist

Performance checks (if applicable)

  • I've tested on Android
    • Ideally on a mid-range device; emulator is acceptable
  • I've tested with a power user scenario
    • Use these power-user SRPs to import wallets with many accounts and tokens
  • I've instrumented key operations with Sentry traces for production performance metrics

For performance guidelines and tooling, see the Performance Guide.

Pre-merge reviewer checklist

  • I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed).
  • I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots.

Note

Medium Risk
Broadly changes how multiple backend clients choose their base URLs and authentication env, including identity/JWT minting and websocket endpoints. Default remains prod, but misconfiguration or incomplete coverage could cause 401/403s or unexpected traffic routing in non-prod builds.

Overview
Introduces a build-time MM_DEV_API_ENV switch (default prod) via new app/core/devApiEnv.ts to keep AuthenticationController JWT minting and downstream JWT-consuming services targeting the same backend environment.

Updates multiple services/controllers (e.g., identity auth + user storage, authenticated user storage, profile metrics, chomp, bridge, social, perps data lake, sentinel, notifications, backend websocket) to derive their env/base URLs from this shared switch (often by rewriting *.api.cx.metamask.io*.dev-api.cx.metamask.io), and adds an Identity section in Developer Options to display the current env and clear the persisted auth session.

Adds patch-package patches for dependencies that don’t expose env/base-url configuration (@metamask/core-backend API host constants and @metamask/assets-controllers accounts domain) and updates tests/config to validate the new env-driven behavior.

Reviewed by Cursor Bugbot for commit 06b0172. Bugbot is set up for automated code reviews on this repo. Configure here.

@Jwhiles Jwhiles requested review from a team as code owners May 12, 2026 16:57
@github-actions
Copy link
Copy Markdown
Contributor

CLA Signature Action: All authors have signed the CLA. You may need to manually re-run the blocking PR check if it doesn't pass in a few minutes.

@github-actions github-actions Bot added pr-not-ready-for-e2e Skip E2E and block merging. Remove this label once the PR is ready to run the E2E tests. size-M labels May 12, 2026
// TODO: Verify the dev-api Sentinel hostname follows the standard
// `*.api.cx.metamask.io` -> `*.dev-api.cx.metamask.io` rewrite. If Sentinel
// uses a different dev hostname, switch off `devApiEnv()` directly instead.
const BASE_URL = apiUrl('https://tx-sentinel-{0}.api.cx.metamask.io/');
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Sentinel URL template rewritten at module load time

Low Severity

BASE_URL and OrdersEndpoint evaluate apiUrl() at module scope, freezing the result at import time. The devApiEnv() function was explicitly designed to be "read at call time (not module load) so tests can set/unset process.env.MM_DEV_API_ENV without juggling the module cache." Calling it via apiUrl() at module scope defeats this design: any test that sets the env var after module load will silently operate against the wrong URL. These constants could be converted to getter functions or computed lazily to match the intent documented in devApiEnv.ts.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 1978b9c. Configure here.

@codecov-commenter
Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 88.88889% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 81.57%. Comparing base (3751d9a) to head (1978b9c).
⚠️ Report is 37 commits behind head on main.

Files with missing lines Patch % Lines
app/constants/bridge.ts 0.00% 0 Missing and 1 partial ⚠️
...ers/core-backend/backend-websocket-service-init.ts 66.66% 0 Missing and 1 partial ⚠️
app/core/devApiEnv.ts 87.50% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #30055      +/-   ##
==========================================
+ Coverage   81.54%   81.57%   +0.03%     
==========================================
  Files        5343     5359      +16     
  Lines      142128   142546     +418     
  Branches    32411    32530     +119     
==========================================
+ Hits       115899   116289     +390     
+ Misses      18299    18295       -4     
- Partials     7930     7962      +32     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Copy Markdown
Member

@MoMannn MoMannn left a comment

Choose a reason for hiding this comment

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

One problem is that when you switch this "ON" the JWT being returned is still PROD since its in a persistant storage until it get invalidated. I think we will also need to update AuthenticationController so that it clears storage if MM_DEV_API_ENV is on or something like this. Or like a button to clear persistant storage.

@Jwhiles Jwhiles force-pushed the universal-dev-mode-feature-flag branch 2 times, most recently from bdbc8f2 to e715e9b Compare May 15, 2026 09:42
@Jwhiles Jwhiles force-pushed the universal-dev-mode-feature-flag branch from 65b4c99 to 19643ab Compare May 15, 2026 12:25
@Jwhiles Jwhiles requested a review from a team as a code owner May 15, 2026 12:25
Comment thread todo.md
- Auth: outbound requests target `oidc.dev-api.cx.metamask.io`.
- Chomp: `[ChompApiServiceInit] MM_DEV_API_ENV=dev; using env URL`.
- Bridge / WebSocket / Sentinel / Perps / Social / UserStorage /
Notifications: outbound URLs include `dev-api` subdomains.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Development tracking file accidentally committed to repo

Medium Severity

A personal development tracking file todo.md was committed to the repository root. It contains TODO checklists, verification steps, and outstanding-work notes that duplicate the PR description. It also incorrectly states uat is a supported value for MM_DEV_API_ENV (line 4: "Set MM_DEV_API_ENV=dev (or uat)"), but devApiEnv() only recognizes 'dev' and treats everything else — including 'uat' — as 'prod'. This file doesn't belong in the codebase and its inaccurate documentation could mislead future developers.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 19643ab. Configure here.

@Jwhiles Jwhiles requested a review from a team as a code owner May 15, 2026 14:00
@github-actions github-actions Bot added size-L and removed size-M labels May 15, 2026
Copy link
Copy Markdown
Contributor

@cursor cursor Bot left a comment

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.

There are 3 total unresolved issues (including 2 from previous reviews).

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 06b0172. Configure here.

Comment thread mise.toml
@@ -0,0 +1,3 @@
[tools]
yarn = "latest"
ruby = "3.2.9"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Tooling config file committed to repository root

Low Severity

mise.toml is a personal tool-version manager configuration file. The project's .gitignore already excludes the equivalent .tool-versions with the comment "don't save asdf tools-version config as nvm is prioritized." This file serves the same purpose and pins yarn = "latest", which is non-deterministic and could cause inconsistent tooling across developers and CI.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 06b0172. Configure here.

@sonarqubecloud
Copy link
Copy Markdown

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

Labels

pr-not-ready-for-e2e Skip E2E and block merging. Remove this label once the PR is ready to run the E2E tests. size-L team-earn

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants