65 lines
2.5 KiB
TypeScript
65 lines
2.5 KiB
TypeScript
import express, { type Express } from "express";
|
|
import cors from "cors";
|
|
import path from "path";
|
|
import { fileURLToPath } from "url";
|
|
import router from "./routes/index.js";
|
|
import { responseTimeMiddleware } from "./middlewares/response-time.js";
|
|
|
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
|
|
const app: Express = express();
|
|
|
|
app.set("trust proxy", 1);
|
|
|
|
// ── CORS (#5) ────────────────────────────────────────────────────────────────
|
|
// CORS_ORIGINS = comma-separated list of allowed origins.
|
|
// Default in production: alexanderwhitestone.com (and www. variant).
|
|
// Default in development: all origins permitted.
|
|
const isProd = process.env["NODE_ENV"] === "production";
|
|
|
|
const rawOrigins = process.env["CORS_ORIGINS"];
|
|
const allowedOrigins: string[] = rawOrigins
|
|
? rawOrigins.split(",").map((o) => o.trim()).filter(Boolean)
|
|
: isProd
|
|
? ["https://alexanderwhitestone.com", "https://www.alexanderwhitestone.com"]
|
|
: [];
|
|
|
|
app.use(
|
|
cors({
|
|
origin:
|
|
allowedOrigins.length === 0
|
|
? true
|
|
: (origin, callback) => {
|
|
if (!origin || allowedOrigins.includes(origin)) {
|
|
callback(null, true);
|
|
} else {
|
|
callback(new Error(`CORS: origin '${origin}' not allowed`));
|
|
}
|
|
},
|
|
credentials: true,
|
|
methods: ["GET", "POST", "PATCH", "DELETE", "OPTIONS"],
|
|
allowedHeaders: ["Content-Type", "Authorization", "X-Session-Token"],
|
|
exposedHeaders: ["X-Session-Token"],
|
|
}),
|
|
);
|
|
|
|
app.use(express.json());
|
|
app.use(express.urlencoded({ extended: true }));
|
|
app.use(responseTimeMiddleware);
|
|
|
|
app.use("/api", router);
|
|
|
|
// ── Tower (Matrix 3D frontend) ───────────────────────────────────────────────
|
|
// Serve the pre-built Three.js world at /tower. The Matrix's WebSocket client
|
|
// auto-connects to /api/ws on the same host.
|
|
// __dirname resolves to artifacts/api-server/dist/ at runtime.
|
|
// Go up three levels to reach workspace root, then into the-matrix/dist.
|
|
const towerDist = path.join(__dirname, "..", "..", "..", "the-matrix", "dist");
|
|
app.use("/tower", express.static(towerDist));
|
|
app.get("/tower/*splat", (_req, res) => res.sendFile(path.join(towerDist, "index.html")));
|
|
|
|
app.get("/", (_req, res) => res.redirect("/tower"));
|
|
app.get("/api", (_req, res) => res.redirect("/api/ui"));
|
|
|
|
export default app;
|