Compare commits

...

2 Commits

Author SHA1 Message Date
Jeff Emmett 9f258702a1 Merge branch 'dev'
CI/CD / deploy (push) Failing after 2m32s Details
2026-04-15 17:19:44 -04:00
Jeff Emmett c82eca38fa fix(server): add styled 404 page + stop SPA fallback serving stale HTML
Add app.notFound() handler with themed 404 page instead of Hono's
plain "404 Not Found". Restrict canvas.html SPA fallback to /rspace
sub-paths only — was serving index.html for all unmatched routes,
causing stale "Activated" page to appear on navigation errors.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-15 17:19:41 -04:00
1 changed files with 36 additions and 5 deletions

View File

@ -3664,6 +3664,37 @@ app.get("/:space", (c) => {
return c.redirect("/", 302);
});
// ── Custom 404 page ──
app.notFound((c) => {
const path = c.req.path;
// API routes: return JSON 404
if (path.startsWith("/api/") || c.req.header("accept")?.includes("application/json")) {
return c.json({ error: "Not found" }, 404);
}
return c.html(`<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>Page Not Found | rSpace</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:system-ui,-apple-system,sans-serif;min-height:100vh;display:flex;align-items:center;justify-content:center;background:#0f172a;color:#e2e8f0}
.c{max-width:480px;text-align:center;padding:2rem}
h1{font-size:4rem;margin-bottom:0.5rem;background:linear-gradient(135deg,#5eead4,#a78bfa);-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text}
p{color:#94a3b8;line-height:1.6;margin-bottom:1.5rem}
a{color:#5eead4;text-decoration:none;padding:0.5rem 1.5rem;border:1px solid #5eead4;border-radius:8px;transition:all 0.2s}
a:hover{background:#5eead4;color:#0f172a}
.sub{font-size:0.85rem;color:#475569;margin-top:2rem}
</style>
</head>
<body><div class="c">
<h1>404</h1>
<p>This page doesn't exist it may have moved or the URL might be wrong.</p>
<a href="/">Back to rSpace</a>
<p class="sub">${path}</p>
</div></body></html>`, 404);
});
// ── WebSocket types ──
interface WSData {
communitySlug: string;
@ -4343,11 +4374,11 @@ const server = Bun.serve<WSData>({
if (shellResponse.status === 200) return shellResponse;
}
// Non-module path — try canvas/index SPA fallback
// Canvas SPA fallback (only for /rspace sub-paths, not general 404s)
if (parts[0] === "rspace" || (subdomain && parts[0] === "rspace")) {
const canvasHtml = await serveStatic("canvas.html");
if (canvasHtml) return canvasHtml;
const indexHtml = await serveStatic("index.html");
if (indexHtml) return indexHtml;
}
}
}