webpods
Version:
Append-only log service with OAuth authentication
179 lines • 6.42 kB
JavaScript
/**
* WebPods server factory
*/
import express from "express";
import session from "express-session";
import helmet from "helmet";
import cors from "cors";
import compression from "compression";
import cookieParser from "cookie-parser";
import { createLogger } from "./logger.js";
import { getSessionConfig } from "./auth/session-store.js";
import { getConfig } from "./config-loader.js";
import { getVersion } from "./version.js";
import { isMainDomain, isSubdomainOf } from "./utils.js";
import authRouter from "./auth/routes.js";
import oauthRouter from "./oauth/routes.js";
import podsRouter from "./routes/pods.js";
const logger = createLogger("webpods");
export function createApp() {
const app = express();
const config = getConfig();
const startTime = Date.now();
// Security middleware
app.use(helmet());
app.use(cors({
origin: config.server.corsOrigin?.split(",") || "*",
credentials: true,
}));
// Request parsing with configurable payload size
const payloadLimit = config.server.maxPayloadSize || "10mb";
app.use(express.json({ limit: payloadLimit }));
app.use(express.text({ limit: payloadLimit }));
app.use(express.urlencoded({ extended: true, limit: payloadLimit }));
app.use(compression());
app.use(cookieParser());
// Session management for SSO (works on all domains but only used for auth)
const sessionMiddleware = session(getSessionConfig());
app.use(sessionMiddleware);
// Request logging
app.use((req, res, next) => {
const start = Date.now();
res.on("finish", () => {
const duration = Date.now() - start;
logger.info("Request completed", {
method: req.method,
url: req.url,
originalUrl: req.originalUrl,
path: req.path,
hostname: req.hostname,
status: res.statusCode,
duration,
ip: req.ip,
});
});
next();
});
// Health check endpoint (main domain only)
app.get("/health", async (req, res) => {
// Only allow health checks on main domain
const hostname = req.hostname || req.headers.host?.split(":")[0] || "";
const mainDomain = config.server.public?.hostname || "localhost";
if (!isMainDomain(hostname, mainDomain)) {
res.status(404).json({
error: {
code: "NOT_FOUND",
message: "Health endpoint is only available on the main domain",
},
});
return;
}
const uptime = Math.floor((Date.now() - startTime) / 1000);
// Check database connection
let dbStatus = "disconnected";
try {
const { getDb } = await import("./db.js");
const db = getDb();
await db.one("SELECT 1 as result");
dbStatus = "connected";
}
catch {
dbStatus = "disconnected";
}
res.json({
status: "healthy",
uptime_seconds: uptime,
uptime,
timestamp: new Date().toISOString(),
version: getVersion(),
services: {
database: dbStatus,
cache: "not_configured",
},
});
});
// OAuth routes (main domain only)
app.use("/oauth", (req, res, next) => {
const hostname = req.hostname || req.headers.host?.split(":")[0] || "";
const mainDomain = config.server.public?.hostname || "localhost";
if (isMainDomain(hostname, mainDomain)) {
oauthRouter(req, res, next);
}
else {
res.status(404).json({
error: {
code: "NOT_FOUND",
message: "OAuth endpoints are only available on the main domain",
},
});
}
});
// Auth routes (main domain only, except /auth/callback which pods handle)
app.use("/auth", (req, res, next) => {
// Check if this is the main domain
const hostname = req.hostname || req.headers.host?.split(":")[0] || "";
const mainDomain = config.server.public?.hostname || "localhost";
if (isMainDomain(hostname, mainDomain)) {
// On main domain, use auth router
authRouter(req, res, next);
}
else {
// On subdomains, /auth/callback is handled by pod router
// Skip this middleware and let it fall through
if (req.path === "/callback") {
next("route"); // Skip to next route handler
}
else {
// Other /auth routes return 404 on subdomains
res.status(404).json({
error: {
code: "NOT_FOUND",
message: "Authentication endpoints are only available on the main domain",
},
});
}
}
});
// Pod routes (subdomain-based and rootPod)
app.use(podsRouter);
// 404 handler
app.use((req, res) => {
const hostname = req.hostname || req.headers.host?.split(":")[0] || "";
const mainDomain = config.server.public?.hostname || "localhost";
if (isSubdomainOf(hostname, mainDomain)) {
const podId = hostname.split(".")[0];
res.status(404).json({
error: {
code: "STREAM_NOT_FOUND",
message: `Stream not found in pod '${podId}'`,
},
});
}
else {
res.status(404).json({
error: {
code: "NOT_FOUND",
message: "Resource not found",
},
});
}
});
// Error handler
app.use((err, req, res, _next) => {
logger.error("Unhandled error", {
error: err.message,
stack: err.stack,
url: req.url,
method: req.method,
});
const showDetails = process.env.LOG_LEVEL === "debug";
res.status(err.status || 500).json({
error: {
code: "INTERNAL_ERROR",
message: showDetails ? err.message : "An error occurred",
},
});
});
return app;
}
//# sourceMappingURL=server.js.map