84 lines
2.9 KiB
JavaScript
84 lines
2.9 KiB
JavaScript
import express from "express";
|
|
import helmet from "helmet";
|
|
import morgan from "morgan";
|
|
import { requestContext } from "./shared/middleware/requestContext";
|
|
import { handleErrors, successResponse } from "./shared/middleware/errorMiddleware";
|
|
import adminRoutes from "./routes/admin";
|
|
import integrationRoutes from "./routes/integrations";
|
|
import deviceRoutes from "./routes/device";
|
|
import { startNotificationOrchestrator } from "./shared/orchestrators/notificationOrchestrator";
|
|
import path from "node:path";
|
|
import fs from "node:fs";
|
|
const app = express();
|
|
startNotificationOrchestrator();
|
|
app.use(helmet({
|
|
crossOriginResourcePolicy: {
|
|
policy: "cross-origin"
|
|
},
|
|
contentSecurityPolicy: {
|
|
directives: {
|
|
defaultSrc: ["'self'"],
|
|
scriptSrc: ["'self'", "'unsafe-inline'", "'unsafe-eval'", "https://cdn.tailwindcss.com"],
|
|
scriptSrcAttr: ["'unsafe-inline'"],
|
|
styleSrc: ["'self'", "'unsafe-inline'", "https://fonts.googleapis.com"],
|
|
fontSrc: ["'self'", "https://fonts.gstatic.com", "data:"],
|
|
imgSrc: ["'self'", "data:", "https://lh3.googleusercontent.com", "https://*.googleusercontent.com"],
|
|
connectSrc: ["'self'"],
|
|
objectSrc: ["'none'"],
|
|
baseUri: ["'self'"]
|
|
}
|
|
}
|
|
}));
|
|
app.use(express.json());
|
|
app.use(morgan("dev"));
|
|
app.use(requestContext);
|
|
app.get("/", (_req, res) => {
|
|
res.json(successResponse(_req, { status: "ok" }));
|
|
});
|
|
function resolveUiPageFile(slug) {
|
|
const workspaceRoot = process.cwd();
|
|
const candidates = [
|
|
path.resolve(workspaceRoot, "ui", slug, "index.html"),
|
|
path.resolve(workspaceRoot, "ui", slug.replace(/_/g, "-"), "index.html"),
|
|
path.resolve(workspaceRoot, "ui", slug.replace(/-/g, "_"), "index.html")
|
|
];
|
|
return candidates.find((candidate) => fs.existsSync(candidate)) || null;
|
|
}
|
|
app.get("/ui", (_req, res) => {
|
|
const filePath = path.resolve(process.cwd(), "ui/index.html");
|
|
res.sendFile(filePath);
|
|
});
|
|
app.get("/ui/hub", (_req, res) => {
|
|
const filePath = path.resolve(process.cwd(), "ui/hub.html");
|
|
res.sendFile(filePath);
|
|
});
|
|
app.use("/ui/shared", express.static(path.resolve(process.cwd(), "ui", "shared")));
|
|
app.get("/ui/:page", (req, res, next) => {
|
|
const filePath = resolveUiPageFile(req.params.page);
|
|
if (!filePath) {
|
|
return next();
|
|
}
|
|
res.sendFile(filePath);
|
|
});
|
|
app.use("/admin", adminRoutes);
|
|
app.use("/integrations", integrationRoutes);
|
|
app.use("/device", deviceRoutes);
|
|
app.use((err, _req, res, next) => {
|
|
handleErrors(err, _req, res, next);
|
|
});
|
|
app.get("/health", (req, res) => {
|
|
res.status(200).json(successResponse(req, {
|
|
status: "healthy",
|
|
time: new Date().toISOString()
|
|
}));
|
|
});
|
|
app.use((req, res) => {
|
|
res.status(404).json({
|
|
code: "NOT_FOUND",
|
|
message: `Route ${req.path} not found`,
|
|
request_id: req.requestId,
|
|
timestamp: new Date().toISOString()
|
|
});
|
|
});
|
|
export default app;
|