Files
api/src/index.ts
Flavio Fois 9458d1e8ad Introduces configurable test database for bug reports
Enables switching between production and testing MySQL databases based on the `ENABLE_TEST_DB` environment variable and an `X-DB-ENV` request header.

Applies this dual database functionality primarily to bug report submission and administration features. New `TESTING_MYSQL_` environment variables are added for defining test database credentials.

Refines HTTP request logging by excluding health checks and admin session validation endpoints to reduce noise. Allows `/health` endpoints to bypass API and Admin key guards.

Temporarily disables HWID-based rate limiting for bug report submissions.
2026-03-02 23:15:15 +01:00

92 lines
2.5 KiB
TypeScript

import { Elysia } from "elysia";
import { config, validateConfig } from "./config";
import { runMigrations } from "./db/migrate";
import { closePool } from "./db/connection";
import { bugReportRoutes } from "./routes/bugReports";
import { adminRoutes } from "./routes/admin";
import { authRoutes } from "./routes/auth";
import { initLogger, Log } from "./logger";
const INSTANCE_ID =
process.env.HOSTNAME + "_" + Math.random().toString(16).slice(2, 6);
// Initialize logger
initLogger();
// Validate environment
validateConfig();
// Run database migrations
try {
await runMigrations();
} catch (error) {
Log("ERROR", "Failed to run migrations:", error);
process.exit(1);
}
const app = new Elysia()
.onRequest(({ request }) => {
const url = new URL(request.url);
const ip =
request.headers.get("x-forwarded-for")?.split(",")[0]?.trim() ||
request.headers.get("x-real-ip") ||
"unknown";
if (url.pathname !== "/api/admin/auth/validate")
Log(
"HTTP",
`[${INSTANCE_ID}] ${request.method} ${url.pathname} from ${ip}`,
);
})
.onAfterResponse(({ request, set }) => {
const url = new URL(request.url);
if (url.pathname !== "/api/admin/auth/validate")
Log("HTTP", `${request.method} ${url.pathname} -> ${set.status ?? 200}`);
})
.onError(({ error, set, code }) => {
console.error("Error processing request:", error);
console.log(code);
if (code === "NOT_FOUND") {
set.status = 404;
return { success: false, message: "Not found" };
}
if (code === "VALIDATION") {
set.status = 422;
return { success: false, message: "Validation error" };
}
Log("ERROR", "Unhandled error:", error);
set.status = 500;
return { success: false, message: "Internal server error" };
})
.get("/health", () => ({
status: "ok",
instance: INSTANCE_ID,
timestamp: new Date().toISOString(),
}))
.get("/", () => ({ status: "ok", message: "API is running" }))
.use(bugReportRoutes)
.use(authRoutes)
.use(adminRoutes)
.listen({
port: config.port,
//@ts-ignore
maxBody: 50 * 1024 * 1024, // 50MB
});
Log(
"SERVER",
`EMLy Bug Report API running on http://localhost:${app.server?.port}`,
);
// Graceful shutdown
process.on("SIGINT", async () => {
Log("SERVER", "Shutting down (SIGINT)...");
await closePool();
process.exit(0);
});
process.on("SIGTERM", async () => {
Log("SERVER", "Shutting down (SIGTERM)...");
await closePool();
process.exit(0);
});