Skip to content

🤖 feat: support Coder path-app iframe embedding#3194

Open
ibetitsmike wants to merge 4 commits intomainfrom
mike/mux-iframe-qmab
Open

🤖 feat: support Coder path-app iframe embedding#3194
ibetitsmike wants to merge 4 commits intomainfrom
mike/mux-iframe-qmab

Conversation

@ibetitsmike
Copy link
Copy Markdown
Contributor

@ibetitsmike ibetitsmike commented Apr 26, 2026

Mux is working on behalf of Mike.

Summary

Adds path-app iframe support for Mux when it is served behind a Coder app prefix such as /@user/workspace/apps/mux/. Built assets, static web app metadata, API routes, docs, auth redirects, router paths, and WebSocket upgrades now resolve through the detected public prefix instead of assuming origin root.

Background

Mux's production HTML injected <base href="/" />, which caused relative Vite bundle paths to resolve from origin root. That breaks when Coder serves Mux under a path prefix inside an iframe. The backend also matched HTTP and WebSocket routes only at root paths, so deployments where the proxy forwards prefixed paths could miss /api, /orpc, /auth, and WS upgrade routes.

Implementation

  • Added src/common/appProxyBasePath.ts to centralize Coder app-proxy path parsing and stripping.
  • Changed the server to compute <base href> per request from forwarded headers or direct prefixed paths, with validated and escaped path values.
  • Added early server middleware that strips a detected app-proxy prefix from HTTP route matching while preserving the public base path for generated URLs.
  • Normalized WebSocket upgrade paths before matching /orpc/ws, /browser/ws, and /desktop/ws.
  • Made Scalar docs, OpenAPI server URLs, and OAuth redirect URLs prefix-aware.
  • Updated browser routing and URL helpers so MemoryRouter sync, service worker registration, terminal popouts, and frontend asset resolution preserve the prefix.
  • Converted manifest, favicon, apple-touch-icon, PWA icon, and PWA shortcut URLs to relative app-root paths so they respect the injected <base href> and manifest location.

Validation

Before opening the PR:

  • make static-check
  • bun test src/common/appProxyBasePath.test.ts src/browser/utils/backendBaseUrl.test.ts src/node/orpc/server.test.ts
  • make typecheck
  • make lint
  • Production build and dist/cli/index.js server --no-auth smoke checks:
    • Root request serves <base href="/" />.
    • Prefixed request serves <base href="/@u/ws/apps/mux/" />.
    • Sequential prefixed requests for different tenants get distinct base href values.
    • Prefixed bundle, manifest, favicon, font, and icon requests all return 200 under the prefix.
    • Prefixed /api/docs emits /@u/ws/apps/mux/api/spec.json.
  • agent-browser iframe smoke:
    • Loaded a wrapper page containing an iframe pointed at /@u/ws/apps/mux/.
    • Verified the Mux provider onboarding dialog renders inside the iframe.
    • Captured HAR showing the app's HTML, JS, CSS, manifest, font, favicon, and icon requests resolve under /@u/ws/apps/mux/.

After Codex approval on head 52f9524bf4dbd6e1bea2d6eaab953b09b3b8e908:

  • bun test src/common/appProxyBasePath.test.ts src/browser/utils/backendBaseUrl.test.ts src/node/orpc/server.test.ts
  • make static-check
  • make build
  • Production curl smoke on a fresh dist/cli/index.js server --no-auth:
    • Root base href: <base href="/" />.
    • Prefix base href: <base href="/@u/ws/apps/mux/" />.
    • Alternate prefix base href: <base href="/@a/b/apps/mux/" />.
    • Manifest shortcut URL: ./?action=new.
    • Manifest icon URL: icon-192.png.
    • Prefixed /api/spec.json: 200.
    • Prefixed /api/docs spec URL: /@u/ws/apps/mux/api/spec.json.
    • Prefixed main JS asset: 200.
  • agent-browser root and prefix smoke:
    • Root app loads and registers service worker at root scope.
    • Prefixed app loads and registers service worker at /@u/ws/apps/mux/ scope.
    • document.baseURI, manifest href, and favicon href all resolve under /@u/ws/apps/mux/.
  • agent-browser iframe smoke:
    • Wrapper page loaded an iframe pointed at /@u/ws/apps/mux/.
    • Provider onboarding dialog rendered inside the iframe.
    • HAR showed no Mux app requests escaping to origin root.

Artifacts from local dogfood are under dogfood-output/mux-path-app/.

Review status

Codex initially flagged the PWA shortcut URL. The shortcut now uses ./?action=new, the review thread was resolved, and Codex approved the updated head. Required checks passed.

Risks

The main risk is route rewriting affecting root-hosted deployments or normal app routes that contain /apps/. The parser is anchored to Coder-shaped path-app prefixes, and tests cover root mode, direct-prefixed mode, forwarded-header mode, non-prefix /apps/ paths, sequential tenant prefixes, origin validation, WebSocket upgrade normalization, docs URLs, and OAuth URL generation.


Generated with mux • Model: openai:gpt-5.5 • Thinking: xhigh • Cost: $56.00

Audit:
- backendBaseUrl now re-exports the shared parser.
- RouterContext and App preserve the cached app-proxy prefix on browser history writes.
- main.tsx and terminal popouts resolve service-worker.js and terminal.html through document.baseURI with the cached prefix.
- terminal.html uses a relative terminal window module script so it stays under the proxy base path.
- Grep found no raw browser-runtime /api, /auth, /orpc, /service-worker.js, or /terminal.html literals outside stories after the changes.

Validation:
- bun test src/common/appProxyBasePath.test.ts src/browser/utils/backendBaseUrl.test.ts
- make typecheck
Support Coder app-proxy base paths across HTTP routing, WebSocket upgrades, generated SPA base hrefs, Scalar docs, session cookie paths, and OAuth URLs.

Validation:

- bun test src/node/orpc/server.test.ts src/browser/utils/backendBaseUrl.test.ts src/common/appProxyBasePath.test.ts

- make typecheck

- make lint
Use relative manifest and icon URLs so the server-injected base href keeps Coder path-app prefixes for HTML, manifest, and dynamic favicon updates.
@ibetitsmike
Copy link
Copy Markdown
Contributor Author

@codex review

Mux is working on behalf of Mike.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 37af608cd4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread public/manifest.json Outdated
@ibetitsmike
Copy link
Copy Markdown
Contributor Author

@codex review

Mux is working on behalf of Mike.

@chatgpt-codex-connector
Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Keep it up!

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

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