Skip to content

feat: serve base path#2889

Open
tarik02 wants to merge 9 commits into
pingdotgg:mainfrom
tarik02:feat/web-base-path
Open

feat: serve base path#2889
tarik02 wants to merge 9 commits into
pingdotgg:mainfrom
tarik02:feat/web-base-path

Conversation

@tarik02
Copy link
Copy Markdown
Contributor

@tarik02 tarik02 commented May 31, 2026

What Changed

Feature to specify custom (instead of just root /) base path when running t3 serve.

Caveat: dev mode was left out of scope intentionally.

Why

In order to host multiple t3code instances on single domain.

About index.html paths rewriting: I consider using JSX and fully-generated index.html via renderToStaticMarkup, but it would look less focused, can be implemented in separate PR if needed.

UI Changes

2026-05-31.19.52.59.mov

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes

Note

Add configurable base path support for serving the app under a URL prefix

  • Introduces NormalizedBasePath, ROOT_BASE_PATH, and normalizeBasePath in packages/shared/src/basePath.ts as the canonical base path type shared across packages.
  • Adds a --base-path CLI flag and T3CODE_BASE_PATH env var; the resolved basePath is stored in ServerConfigShape and propagated throughout the server.
  • Mounts all HTTP routes under config.basePath in apps/server/src/server.ts and rewrites index.html asset URLs to use the base path before serving static files.
  • Updates URL construction in the web app, mobile app, client-runtime, shared, and tailscale packages so all HTTP, WebSocket, pairing, and favicon URLs include the base path.
  • Sets Vite base to an empty string so built assets use relative paths, and configures TanStack Router with the runtime-derived BASE_PATH.
  • Behavioral Change: session cookies are now scoped to the configured base path instead of /; WebSocket connection URLs point to <basePath>/ rather than /ws.

Macroscope summarized 0548816.


Note

Medium Risk
Changes auth cookie scope, pairing/startup URLs, and WebSocket paths; mis-set basePath could break login and RPC until config matches the reverse proxy.

Overview
Adds configurable URL base path so T3 can run under a path prefix (e.g. /custom) on one host, not only at /.

Server: basePath is resolved from --base-path / T3CODE_BASE_PATH (via shared normalizeBasePath), stored on ServerConfig, and used to prefix the HTTP router (router.prefixed(config.basePath)). Static index.html rewrites src/href asset paths to include the prefix. Auth session cookies use path {basePath}/; pairing and headless URLs point at {basePath}/pair with the prefix in connection strings.

Clients: Web derives BASE_PATH at runtime and passes it to TanStack Router; mobile and shared helpers build API/attachment URLs under the prefix. WebSocket RPC uses {basePath}/ws (and minted WS URLs align with the HTTP base path). Vite base: "" keeps built assets relative for subpath deploys.

Not in scope: dev-mode base path (per PR description).

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

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 31, 2026

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: cc16bd82-6e13-4971-8ae8-e0c0b348d7e6

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels May 31, 2026
Comment thread apps/server/src/http.ts
});
}

let filePath = path.resolve(staticRoot, staticRelativePath);
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.

Static paths ignore base prefix

High Severity

The catch-all static handler maps HttpServerRequest.toURL’s pathname directly onto files under staticRoot without removing the configured basePath. With a non-root prefix, requests like /custom/assets/… resolve to staticRoot/custom/…, so assets are missing and the handler often serves rewritten index.html instead of JS/CSS, breaking the served UI.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit a29e812. Configure here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

not a case, app is mounted on basePath already
can add special handling (404?) if needed

Comment thread apps/server/src/http.ts
if (config.devUrl && isLoopbackHostname(url.value.hostname)) {
return HttpServerResponse.redirect(resolveDevRedirectUrl(config.devUrl, url.value), {
status: 302,
});
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.

Dev redirect keeps base prefix

Medium Severity

Loopback dev redirects copy the incoming request pathname onto devUrl unchanged. After mounting under a non-root basePath, that pathname includes the serve prefix, so the Vite dev server receives URLs it does not own and redirects fail or 404 when devUrl is set alongside a custom prefix.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit a29e812. Configure here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

dev mode out of scope

Comment thread apps/web/src/components/SplashScreen.tsx Outdated
Comment thread packages/shared/src/advertisedEndpoint.ts Outdated
@macroscopeapp
Copy link
Copy Markdown
Contributor

macroscopeapp Bot commented May 31, 2026

Approvability

Verdict: Needs human review

New feature introducing configurable base path across the entire stack (server, web, mobile). Two unresolved review comments identify bugs: static file serving and dev redirects don't properly strip the base path prefix, which would break the UI when deployed under a non-root path.

You can customize Macroscope's approvability policy. Learn more.

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, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 73c0214. Configure here.

Comment thread apps/web/src/basePath.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L 100-499 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant