From 18609710a6945ba6e01462cb214cde03e804d908 Mon Sep 17 00:00:00 2001 From: Harshith Mullapudi Date: Wed, 27 Aug 2025 06:59:41 +0530 Subject: [PATCH] Fix: facts page is not opening --- apps/webapp/app/services/email.server.ts | 20 +++++ apps/webapp/server.js | 109 +++++++++++++++++++++++ 2 files changed, 129 insertions(+) create mode 100644 apps/webapp/server.js diff --git a/apps/webapp/app/services/email.server.ts b/apps/webapp/app/services/email.server.ts index e3dc47c..feecd5e 100644 --- a/apps/webapp/app/services/email.server.ts +++ b/apps/webapp/app/services/email.server.ts @@ -55,6 +55,26 @@ function buildTransportOptions(): MailTransportOptions { } } +export async function sendMagicLinkEmail(options: any): Promise { + logger.debug("Sending magic link email", { + emailAddress: options.emailAddress, + }); + + try { + return await client.send({ + email: "magic_link", + to: options.emailAddress, + magicLink: options.magicLink, + }); + } catch (error) { + logger.error("Error sending magic link email", { + error: JSON.stringify(error), + }); + + throw error; + } +} + export async function sendPlainTextEmail(options: SendPlainTextOptions) { return client.sendPlainText(options); } diff --git a/apps/webapp/server.js b/apps/webapp/server.js new file mode 100644 index 0000000..909dc3f --- /dev/null +++ b/apps/webapp/server.js @@ -0,0 +1,109 @@ +import { createRequestHandler } from "@remix-run/express"; +import compression from "compression"; +import express from "express"; +import morgan from "morgan"; +// import { handleMCPRequest, handleSessionRequest } from "~/services/mcp.server"; +// import { authenticateHybridRequest } from "~/services/routeBuilders/apiBuilder.server"; +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"); + const module = build.entry?.module; + 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")); + app.get("/api/v1/mcp", async (req, res) => { + const authenticationResult = await module.authenticateHybridRequest(req, { + allowJWT: true, + }); + if (!authenticationResult) { + res.status(401).json({ error: "Authentication required" }); + return; + } + await module.handleSessionRequest(req, res, authenticationResult.userId); + }); + app.post("/api/v1/mcp", async (req, res) => { + const authenticationResult = await module.authenticateHybridRequest(req, { + allowJWT: true, + }); + if (!authenticationResult) { + res.status(401).json({ error: "Authentication required" }); + return; + } + let body = ""; + req.on("data", (chunk) => { + body += chunk; + }); + req.on("end", async () => { + try { + const parsedBody = JSON.parse(body); + const queryParams = req.query; // Get query parameters from the request + await module.handleMCPRequest(req, res, parsedBody, authenticationResult, queryParams); + } + catch (error) { + res.status(400).json({ error: "Invalid JSON" }); + } + }); + }); + app.delete("/api/v1/mcp", async (req, res) => { + const authenticationResult = await module.authenticateHybridRequest(req, { + allowJWT: true, + }); + if (!authenticationResult) { + res.status(401).json({ error: "Authentication required" }); + return; + } + await module.handleSessionRequest(req, res, authenticationResult.userId); + }); + app.options("/api/v1/mcp", (_, res) => { + res.json({}); + }); + 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", "plain"], + token_endpoint_auth_methods_supported: [ + "client_secret_basic", + "none", + "client_secret_post", + ], + }); + }); + // handle SSR requests + app.all("*", remixHandler); + const port = process.env.REMIX_APP_PORT || 3000; + app.listen(port, () => console.log(`Express server listening at http://localhost:${port}`)); +} +init().catch(console.error);