Preview proxy tuneup

This commit is contained in:
2026-02-22 16:00:52 +00:00
parent ca45301e3e
commit a8aba2aee2
2 changed files with 60 additions and 18 deletions
+42 -18
View File
@@ -192,29 +192,24 @@ devServerRouter.get('/logs', async (ctx) => {
// Proxy router — mounted outside protected router (no auth needed for sub-resources).
// Security: only proxies to ports that were started via authenticated /start calls.
devServerProxyRouter.all('/:slug/*', async (ctx) => {
const slug = ctx.req.param('slug');
if (!slug) return ctx.text('Not found', 404);
const entry = findEntryBySlug(slug);
if (!entry) return ctx.text('No dev server running', 404);
type ProxyParams = { entry: ServerEntry; slug: string; proxyPath: string; search: string; method: string; rawReq: Request };
async function proxyRequest({ entry, slug, proxyPath, search, method, rawReq }: ProxyParams): Promise<Response> {
const prefix = `/api/dev-server-proxy/${slug}`;
const targetUrl = `http://localhost:${entry.port}${proxyPath}${search}`;
touchEntry(entry);
const originalUrl = new URL(ctx.req.url);
const prefix = `/api/dev-server-proxy/${slug}`;
const proxyPath = originalUrl.pathname.replace(prefix, '') || '/';
const targetUrl = `http://localhost:${entry.port}${proxyPath}${originalUrl.search}`;
try {
const headers = new Headers(ctx.req.raw.headers);
const headers = new Headers(rawReq.headers);
headers.delete('host');
headers.delete('authorization');
const res = await fetch(targetUrl, {
method: ctx.req.method,
method,
headers,
body: ctx.req.method !== 'GET' && ctx.req.method !== 'HEAD' ? ctx.req.raw.body : undefined,
body: method !== 'GET' && method !== 'HEAD' ? rawReq.body : undefined,
redirect: 'manual',
});
@@ -235,13 +230,42 @@ devServerProxyRouter.all('/:slug/*', async (ctx) => {
return new Response(rewritten, { status: res.status, headers: newHeaders });
}
return new Response(res.body, {
status: res.status,
headers: res.headers,
});
return new Response(res.body, { status: res.status, headers: res.headers });
} catch {
return ctx.text('Dev server not reachable', 502);
return new Response('Dev server not reachable', { status: 502 });
}
}
// Proxy handler: tries slug from URL first, falls back to Referer for misrouted
// chunk requests caused by relative imports resolving at wrong path depth.
devServerProxyRouter.all('/:slug/*', async (ctx) => {
const slug = ctx.req.param('slug');
if (!slug) return ctx.text('Not found', 404);
const originalUrl = new URL(ctx.req.url);
const entry = findEntryBySlug(slug);
if (entry) {
const prefix = `/api/dev-server-proxy/${slug}`;
const proxyPath = originalUrl.pathname.replace(prefix, '') || '/';
return proxyRequest({ entry, slug, proxyPath, search: originalUrl.search, method: ctx.req.method, rawReq: ctx.req.raw });
}
// Slug didn't match a dev server — check Referer for the real slug
const referer = ctx.req.header('referer');
if (referer) {
const match = referer.match(/\/api\/dev-server-proxy\/([^/]+)/);
if (match) {
const realSlug = match[1]!;
const realEntry = findEntryBySlug(realSlug);
if (realEntry) {
const proxyPath = originalUrl.pathname.replace('/api/dev-server-proxy', '') || '/';
return proxyRequest({ entry: realEntry, slug: realSlug, proxyPath, search: originalUrl.search, method: ctx.req.method, rawReq: ctx.req.raw });
}
}
}
return ctx.text('No dev server running', 404);
});
// Injected into proxied HTML to intercept fetch/XHR so absolute paths (e.g. /api/hello)