From 61b63682482de633ceb9c1b5e2572959a81cb2e8 Mon Sep 17 00:00:00 2001 From: Jeff Emmett Date: Fri, 2 Jan 2026 10:31:19 +0100 Subject: [PATCH] Fix static asset serving and add reserved subdomains MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Serve static assets (js, wasm, css) before subdomain routing - Add WASM and image content types - Reserve 'create', 'new', 'start' subdomains for community creation form - Fixes canvas not loading on subdomains 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- server/index.ts | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/server/index.ts b/server/index.ts index 938d711..153079a 100644 --- a/server/index.ts +++ b/server/index.ts @@ -34,6 +34,9 @@ function getClient(slug: string, peerId: string): ServerWebSocket | unde return communityClients.get(slug)?.get(peerId); } +// Special subdomains that should show the creation form instead of canvas +const RESERVED_SUBDOMAINS = ["www", "rspace", "create", "new", "start"]; + // Parse subdomain from host header function getSubdomain(host: string | null): string | null { if (!host) return null; @@ -47,7 +50,8 @@ function getSubdomain(host: string | null): string | null { const parts = host.split("."); if (parts.length >= 3 && parts.slice(-2).join(".") === "rspace.online") { const subdomain = parts[0]; - if (subdomain !== "www" && subdomain !== "rspace") { + // Reserved subdomains show the creation form + if (!RESERVED_SUBDOMAINS.includes(subdomain)) { return subdomain; } } @@ -76,7 +80,12 @@ function getContentType(path: string): string { if (path.endsWith(".css")) return "text/css"; if (path.endsWith(".json")) return "application/json"; if (path.endsWith(".svg")) return "image/svg+xml"; - return "text/plain"; + if (path.endsWith(".wasm")) return "application/wasm"; + if (path.endsWith(".png")) return "image/png"; + if (path.endsWith(".jpg") || path.endsWith(".jpeg")) return "image/jpeg"; + if (path.endsWith(".gif")) return "image/gif"; + if (path.endsWith(".ico")) return "image/x-icon"; + return "application/octet-stream"; } // Main server @@ -106,6 +115,16 @@ const server = Bun.serve({ return handleAPI(req, url); } + // Static files (serve these first, before subdomain routing) + let filePath = url.pathname; + + // Try to serve static assets first (js, css, wasm, etc.) + if (filePath !== "/" && filePath !== "/canvas") { + const assetPath = filePath.slice(1); // Remove leading slash + const staticResponse = await serveStatic(assetPath); + if (staticResponse) return staticResponse; + } + // Community canvas route (subdomain detected) if (subdomain) { const community = await loadCommunity(subdomain); @@ -118,8 +137,7 @@ const server = Bun.serve({ if (canvasHtml) return canvasHtml; } - // Static files - let filePath = url.pathname; + // Handle root paths if (filePath === "/") filePath = "/index.html"; if (filePath === "/canvas") filePath = "/canvas.html";