app.ts
Raw
1import path from "node:path";
2import { staticPlugin } from "@elysiajs/static";
3import { Elysia } from "elysia";
4import config from "./config.ts";
5import { db } from "./db/index.ts";
6import { authRoutes } from "./routes/auth.tsx";
7import { avatarRoutes } from "./routes/avatars.ts";
8import { ciRoutes } from "./routes/ci.tsx";
9import { gitRoutes } from "./routes/git.ts";
10import { issueRoutes } from "./routes/issues.tsx";
11import { patchRoutes } from "./routes/patches.tsx";
12import { releasesRoutes } from "./routes/releases.tsx";
13import { repoRoutes } from "./routes/repos.tsx";
14import { settingsRoutes } from "./routes/settings.tsx";
15import { cancelStaleRuns } from "./services/ci.ts";
16import { syncStartup } from "./services/repoSync.ts";
17
18const CSP = [
19 "default-src 'self'",
20 "script-src 'self'",
21 "style-src 'self' 'unsafe-inline'",
22 "img-src 'self'",
23 "connect-src 'self'",
24 "frame-ancestors 'none'",
25 "form-action 'self'",
26 "object-src 'none'",
27].join("; ");
28
29async function cleanupSessions() {
30 await db
31 .deleteFrom("sessions")
32 .where("expires_at", "<", new Date().toISOString())
33 .execute();
34}
35
36export async function createApp(port: number) {
37 await syncStartup();
38 await cancelStaleRuns();
39
40 // Recurring session cleanup — runs every 24 hours
41 setInterval(cleanupSessions, 24 * 60 * 60 * 1000);
42
43 return new Elysia({
44 serve: { maxRequestBodySize: config.MAX_UPLOAD_BYTES },
45 })
46 .use(
47 staticPlugin({
48 assets: path.resolve("./public"),
49 prefix: "/",
50 }),
51 )
52 .onAfterHandle(({ response }) => {
53 if (response instanceof Response) {
54 response.headers.set("Content-Security-Policy", CSP);
55 response.headers.set("X-Frame-Options", "DENY");
56 }
57 })
58 .get("/health", async () => {
59 try {
60 await db.selectFrom("users").select("id").limit(1).execute();
61 return new Response(JSON.stringify({ ok: true }), {
62 headers: { "Content-Type": "application/json" },
63 });
64 } catch (e) {
65 return new Response(
66 JSON.stringify({
67 ok: false,
68 error: e instanceof Error ? e.message : "DB error",
69 }),
70 {
71 status: 503,
72 headers: { "Content-Type": "application/json" },
73 },
74 );
75 }
76 })
77 .use(gitRoutes)
78 .use(settingsRoutes)
79 .use(authRoutes)
80 .use(repoRoutes)
81 .use(issueRoutes)
82 .use(patchRoutes)
83 .use(releasesRoutes)
84 .use(ciRoutes)
85 .use(avatarRoutes)
86 .listen(port);
87}
88