import { Hono } from "hono"; import { serve } from '@hono/node-server'; import { serveStatic } from '@hono/node-server/serve-static'; import { rpcApp } from "./routes/rpc.js"; import { caldavApp } from "./routes/caldav.js"; import { clientEntry } from "./routes/client-entry.js"; const app = new Hono(); // Allow all hosts for Tailscale Funnel app.use("*", async (c, next) => { // Accept requests from any host return next(); }); // Health check endpoint app.get("/health", (c) => { return c.json({ status: "ok", timestamp: new Date().toISOString() }); }); // Legal config endpoint (temporary fix for RPC issue) app.get("/api/legal-config", async (c) => { try { const { getLegalConfig } = await import("./lib/legal-config.js"); const config = getLegalConfig(); return c.json(config); } catch (error) { console.error("Legal config error:", error); return c.json({ error: "Failed to load legal config" }, 500); } }); // Security.txt endpoint (RFC 9116) app.get("/.well-known/security.txt", (c) => { const securityContact = process.env.SECURITY_CONTACT || "security@example.com"; const securityText = `Contact: ${securityContact} Expires: 2025-12-31T23:59:59.000Z Preferred-Languages: de, en Canonical: https://${process.env.DOMAIN || 'localhost:5173'}/.well-known/security.txt # Security Policy # Please report security vulnerabilities responsibly by contacting us via email. # We will respond to security reports within 48 hours. # # Scope: This security policy applies to the Stargirlnails booking system. # # Rewards: We appreciate security researchers who help us improve our security. # While we don't have a formal bug bounty program, we may offer recognition # for significant security improvements. `; return c.text(securityText, 200, { "Content-Type": "text/plain; charset=utf-8", "Cache-Control": "public, max-age=86400", // Cache for 24 hours }); }); // Serve static files (only in production) if (process.env.NODE_ENV === 'production') { app.use('/static/*', serveStatic({ root: './dist' })); app.use('/assets/*', serveStatic({ root: './dist' })); } app.use('/favicon.png', serveStatic({ path: './public/favicon.png' })); app.use('/AGB.pdf', serveStatic({ path: './public/AGB.pdf' })); app.use('/icons/*', serveStatic({ root: './public' })); app.use('/manifest.json', serveStatic({ path: './public/manifest.json' })); app.route("/rpc", rpcApp); app.route("/caldav", caldavApp); app.get("/*", clientEntry); // Start server const port = process.env.PORT ? parseInt(process.env.PORT) : 3000; const host = process.env.HOST || "0.0.0.0"; console.log(`🚀 Server starting on ${host}:${port}`); // Start the server serve({ fetch: app.fetch, port, hostname: host, }); export default app;