prmsu / backend /server.js
wendel latina
Deploy PRMSU Essay Grader
f853e83 verified
Raw History Blame Contribute Delete
2.7 kB
import express from "express";
import cors from "cors";
import dotenv from "dotenv";
import fs from "node:fs";
import path from "node:path";
import multer from "multer";
import rubricRoutes from "./routes/rubricRoutes.js";
import essayRoutes from "./routes/essayRoutes.js";
import authRoutes from "./routes/authRoutes.js";
import evaluationRoutes from "./routes/evaluationRoutes.js";
dotenv.config({ quiet: true });
const app = express();
// Behind a host's proxy (Hugging Face, Render) the client address arrives in
// X-Forwarded-For; without this every visitor would share the proxy's IP for rate limits.
app.set("trust proxy", true);
// Only the website itself may call the API from a browser. CORS_ORIGINS lists the allowed
// sites, comma-separated; locally it defaults to the Vite dev server. When the website is
// served by this same server (the hosted setup), requests are same-origin and CORS does
// not apply at all.
const allowedOrigins = (process.env.CORS_ORIGINS || "http://localhost:5173,http://127.0.0.1:5173")
.split(",")
.map((o) => o.trim().replace(/\/+$/, ""))
.filter(Boolean);
app.use(
cors({
origin: (origin, cb) => cb(null, !origin || allowedOrigins.includes(origin)),
})
);
app.use(express.json({ limit: "200kb" }));
app.use("/api/auth", authRoutes);
app.use("/api", rubricRoutes);
app.use("/api", essayRoutes);
app.use("/api", evaluationRoutes);
// Hosted, the built website is served from here too: one address, no CORS, one process.
const frontendDist = process.env.FRONTEND_DIST
? path.resolve(process.env.FRONTEND_DIST)
: null;
if (frontendDist && fs.existsSync(path.join(frontendDist, "index.html"))) {
app.use(express.static(frontendDist));
// Any non-API path is the single-page app.
app.get(/^\/(?!api\/).*/, (req, res) => res.sendFile(path.join(frontendDist, "index.html")));
} else {
app.get("/", (req, res) => {
res.send("Essay AI Backend Running");
});
}
// Oversized uploads and oversized JSON bodies become readable messages, not stack traces.
app.use((err, req, res, next) => {
if (err instanceof multer.MulterError && err.code === "LIMIT_FILE_SIZE") {
return res.status(413).json({ error: "File too large", message: "The photo is too large. Take it again at a lower resolution." });
}
if (err?.type === "entity.too.large") {
return res.status(413).json({ error: "Too large", message: "The answer is too long." });
}
if (err?.message === "Only image files can be uploaded") {
return res.status(400).json({ error: "Wrong file type", message: err.message });
}
next(err);
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});