RAQIM Deploy
Deploy RAQIM 2026-05-02 19:46
4080217
import express, {
type Express,
type Request,
type Response,
type NextFunction,
} from "express";
import cors from "cors";
import cookieParser from "cookie-parser";
import pinoHttp from "pino-http";
import path from "path";
import multer from "multer";
import { logger } from "./lib/logger";
import router from "./routes";
const app: Express = express();
app.set("trust proxy", 1);
app.use(
pinoHttp({
logger,
serializers: {
req(req) {
return {
id: req.id,
method: req.method,
url: req.url?.split("?")[0],
};
},
res(res) {
return {
statusCode: res.statusCode,
};
},
},
}),
);
app.use(cors({ origin: true, credentials: true }));
app.use(cookieParser());
app.use(express.json({ limit: "50mb" }));
app.use(express.urlencoded({ extended: true, limit: "50mb" }));
// API routes
app.use("/api", router);
// ── Static frontend serving (production / Docker / HF Spaces) ─────────────
if (process.env.NODE_ENV === "production") {
const frontendDist =
process.env.FRONTEND_DIST ||
path.join(__dirname, "../../raqim/dist/public");
app.use(express.static(frontendDist));
// SPA fallback — serve index.html for every non-API path
// Express 5 / path-to-regexp v8 requires named wildcard syntax
app.get("/{*path}", (_req: Request, res: Response, _next: NextFunction) => {
res.sendFile(path.join(frontendDist, "index.html"));
});
}
// ── Global error handler — must have 4 params for Express to treat as error handler ──
// Catches multer errors, route errors, and anything else that calls next(err)
app.use((err: unknown, req: Request, res: Response, _next: NextFunction) => {
// Log to pino and stderr so it always appears in HF Space container logs
const error = err instanceof Error ? err : new Error(String(err));
logger.error({ err: error, url: req.url, method: req.method }, "unhandled error");
console.error("[RAQIM ERROR]", req.method, req.url, error.message, error.stack);
// Multer-specific errors (file too large, wrong field name, etc.)
if (err instanceof multer.MulterError) {
const msg =
err.code === "LIMIT_FILE_SIZE"
? "حجم الملف يتجاوز الحد المسموح (500 ميغابايت)"
: `خطأ في رفع الملف: ${err.message}`;
res.status(400).json({ error: "upload_error", message: msg });
return;
}
// Generic error — avoid leaking stack traces to clients
const status = (err as any)?.status ?? (err as any)?.statusCode ?? 500;
res.status(status).json({
error: "server_error",
message: error.message || "حدث خطأ غير متوقع في الخادم",
});
});
export default app;