Files
Qris-Soundbox/src/app.ts

104 lines
3.0 KiB
TypeScript

import express from "express";
import helmet from "helmet";
import morgan from "morgan";
import { env } from "./config/env";
import { requestContext } from "./shared/middleware/requestContext";
import { handleErrors, successResponse } from "./shared/middleware/errorMiddleware";
import { NextFunction, Request, Response } from "express";
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: string) {
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: Error, _req: Request, res: Response, next: NextFunction) => {
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;