From 70f52a9b5534340956ec0ec52ed7fc500d07b6b4 Mon Sep 17 00:00:00 2001 From: Chris Wanstrath Date: Sat, 4 Apr 2026 14:56:29 -0700 Subject: [PATCH] Add x-app-url header to tunnel requests --- docs/GUIDE.md | 6 +++--- src/server/tunnels.ts | 5 +++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/docs/GUIDE.md b/docs/GUIDE.md index a4d33f9..bfd2ffa 100644 --- a/docs/GUIDE.md +++ b/docs/GUIDE.md @@ -686,16 +686,16 @@ toes share my-app **`toes unshare [name]`** — Stop sharing an app. -When an app is shared, every proxied request includes an `x-app-url` header set to the app's public tunnel URL (e.g., `https://myapp.toes.space`). When not shared, it's the local URL (e.g., `http://myapp.toes.local`). +Every request to your app includes an `x-app-url` header with the app's public-facing URL. When shared, this is the tunnel URL (e.g., `https://myapp.toes.space`). When not shared, it's the local URL (e.g., `http://myapp.toes.local`). This works whether the request arrives through the local proxy or through a tunnel. -Use `appUrl()` from `@because/toes` to read this header: +Use `appUrl()` from `@because/toes` to read it — never hardcode your app's URL: ```tsx import { appUrl } from '@because/toes' app.get('/callback', c => { const url = appUrl(c.req.raw) - // url = "https://myapp.toes.space" if shared, "http://myapp.toes.local" otherwise + // "https://myapp.toes.space" when shared, "http://myapp.toes.local" otherwise return c.redirect(`${url}/done`) }) ``` diff --git a/src/server/tunnels.ts b/src/server/tunnels.ts index 5419e57..942a1dd 100644 --- a/src/server/tunnels.ts +++ b/src/server/tunnels.ts @@ -177,6 +177,11 @@ function openTunnel(appName: string, port: number, subdomain?: string, isReconne subdomain, reconnect: false, + onRequest(req) { + const app = getApp(appName) + if (app?.tunnelUrl) req.headers['x-app-url'] = app.tunnelUrl + }, + onOpen(assignedSubdomain) { hostLog(`Tunnel open: ${appName} -> ${assignedSubdomain}`)