import { createRequestHandler } from "@remix-run/express"; import compression from "compression"; import express from "express"; import morgan from "morgan"; import fs from "fs"; import path from "path"; // Load environment variables from root .env file try { const envPath = path.resolve(process.cwd(), "../../.env"); const envContent = fs.readFileSync(envPath, "utf8"); const envLines = envContent.split("\n").filter(line => line.trim() && !line.startsWith("#")); for (const line of envLines) { const [key, ...valueParts] = line.split("="); if (key && valueParts.length > 0) { const value = valueParts.join("=").replace(/^["']|["']$/g, ""); process.env[key.trim()] = value.trim(); } } console.log("✅ Environment variables loaded from root .env"); } catch (error) { console.warn("⚠️ Could not load root .env file:", error.message); } let viteDevServer; let remixHandler; async function init() { if (process.env.NODE_ENV !== "production") { const vite = await import("vite"); viteDevServer = await vite.createServer({ server: { middlewareMode: true }, }); } const build = viteDevServer ? () => viteDevServer.ssrLoadModule("virtual:remix/server-build") : await import("./build/server/index.js"); remixHandler = createRequestHandler({ build }); const app = express(); app.use(compression()); // http://expressjs.com/en/advanced/best-practice-security.html#at-a-minimum-disable-x-powered-by-header app.disable("x-powered-by"); // handle asset requests if (viteDevServer) { app.use(viteDevServer.middlewares); } else { // Vite fingerprints its assets so we can cache forever. app.use( "/assets", express.static("build/client/assets", { immutable: true, maxAge: "1y" }), ); } // Everything else (like favicon.ico) is cached for an hour. You may want to be // more aggressive with this caching. app.use(express.static("build/client", { maxAge: "1h" })); app.use(morgan("tiny")); // Health check endpoint for HuggingFace app.get("/health", (req, res) => { res.status(200).json({ status: "ok", timestamp: new Date().toISOString(), version: "1.0.0" }); }); app.get("/.well-known/oauth-authorization-server", (req, res) => { res.json({ issuer: process.env.APP_ORIGIN, authorization_endpoint: `${process.env.APP_ORIGIN}/oauth/authorize`, token_endpoint: `${process.env.APP_ORIGIN}/oauth/token`, registration_endpoint: `${process.env.APP_ORIGIN}/oauth/register`, scopes_supported: ["mcp"], response_types_supported: ["code"], grant_types_supported: [ "authorization_code", "refresh_token", "client_credentials", ], code_challenge_methods_supported: ["S256"], token_endpoint_auth_methods_supported: ["client_secret_basic", "none"], }); }); // handle SSR requests app.all("*", remixHandler); const port = process.env.PORT || process.env.REMIX_APP_PORT || 7860; const host = process.env.HOST || "0.0.0.0"; app.listen(port, host, () => console.log(`🚀 Context Store listening at http://${host}:${port}`), ); } init().catch(console.error);