diff --git a/server/app.js b/server/app.js index dbc77ab..ac5baeb 100644 --- a/server/app.js +++ b/server/app.js @@ -1,23 +1,24 @@ import express from 'express'; import cors from "cors"; -import cookieParser from "cookie-parser"; +import logger from "./middlewares/logger.js"; import errorHandler from "./middlewares/errorHandler.js"; import authRoutes from "./modules/auth/routes.js"; import userRoutes from "./modules/user/routes.js"; import codeforcesRoutes from "./modules/codeforces/routes.js"; import aiRoutes from "./modules/ai/routes.js"; import githubRoutes from "./modules/github/routes.js"; -import { globalLimiter, apiLimiter } from "./middlewares/rateLimiter.js"; const app = express(); +app.use(logger); + const allowedOrigins = [ process.env.CLIENT_URL, process.env.CLIENT_URI, - ...(process.env.NODE_ENV !== "production" ? ["http://localhost:5173"] : []) + "http://localhost:5173" ].filter(Boolean); -const corsOptions = { +const corsOptions ={ origin: function (origin, callback) { if (!origin || allowedOrigins.includes(origin)) { callback(null, true); @@ -26,38 +27,31 @@ const corsOptions = { } }, methods: ["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"], - credentials: true, // Required for cookies to be sent cross-origin + credentials: true, allowedHeaders: ["Content-Type", "Authorization"] -}; +} app.use(cors(corsOptions)); -app.use(express.json()); -// Apply global rate limiter to all requests -app.use(globalLimiter); - -// ── Cookie Parser ───────────────────────────────────────────────────────────── -// Must come BEFORE routes so req.cookies is populated -app.use(cookieParser()); +app.use(express.json()); app.get('/api/health', (req, res) => { res.status(200).json({ status: 'ok', message: 'CodeLens API is running' }); }); -// ── Routes ──────────────────────────────────────────────────────────────────── -app.use("/api", apiLimiter); // Apply API limiter to all /api routes -app.use("/api/auth", authRoutes); -app.use("/api/user", userRoutes); +// Mount routes +app.use("/api/auth", authRoutes); +app.use("/api/user", userRoutes); app.use("/api/codeforces", codeforcesRoutes); -app.use("/api/ai", aiRoutes); -app.use("/api/github", githubRoutes); +app.use("/api/ai", aiRoutes); +app.use("/api/github", githubRoutes); -// ── 404 catch-all ───────────────────────────────────────────────────────────── +// 404 catch-all route app.use((req, res) => { res.status(404).json({ success: false, message: "Route not found" }); }); -// ── Global error handler ────────────────────────────────────────────────────── +// Global error handler middleware app.use(errorHandler); export default app; diff --git a/server/middlewares/logger.js b/server/middlewares/logger.js new file mode 100644 index 0000000..1a84cc4 --- /dev/null +++ b/server/middlewares/logger.js @@ -0,0 +1,28 @@ +/** + * HTTP request logger middleware. + * Logs method, URL, status code, execution duration, and IP. + */ +export const logger = (req, res, next) => { + const start = Date.now(); + const { method, originalUrl, ip } = req; + + // Wait for the response to finish before logging + res.on('finish', () => { + const duration = Date.now() - start; + const { statusCode } = res; + + let statusColor = "\x1b[32m"; // green for 2xx + if (statusCode >= 400) statusColor = "\x1b[31m"; // red for 4xx/5xx + else if (statusCode >= 300) statusColor = "\x1b[33m"; // yellow for 3xx + + const resetColor = "\x1b[0m"; + + console.log( + `[${new Date().toISOString()}] ${method} ${originalUrl} - ${statusColor}${statusCode}${resetColor} (${duration}ms) - IP: ${ip}` + ); + }); + + next(); +}; + +export default logger;