import cors from "@elysia/cors"; import openapi from "@elysia/openapi"; import serverTiming from "@elysia/server-timing"; import config from "@stealth-developers/config"; import { getUser } from "@stealth-developers/db"; import { Elysia, t } from "elysia"; import { join } from "node:path"; import { authPlugin } from "./lib/auth"; import { getLinkedActors } from "./lib/db"; import { sanitiseActors, sanitiseUser } from "./lib/sanitise"; import { ActorWithGuildSchema, ErrorSchema, UserSchema } from "./lib/schemas"; import * as routes from "./routes"; export const app = new Elysia() .onError(({ error, set, request }) => { set.status = 500; console.error(request.url, error); if (error instanceof Error) return { message: error.message ?? "Internal Server Error" }; return { message: "Unknown Error" }; }) .use(openapi()) .use(cors()) .use(authPlugin) .use(serverTiming()) .use(routes.authRoutes) .group("/api", (app) => app .get("/health", () => "ok") .resolve(({ session, status }) => { if (!session) return status(401, { message: "unauthorized" }); return { session }; }) .get( "/me", // @ts-expect-error watever async ({ session }) => { const [user, actors] = await Promise.all([ getUser(session.userId), getLinkedActors(session.userId), ]); return { user: user ? sanitiseUser(user) : null, actors: sanitiseActors(actors, false), }; }, { response: { 200: t.Object({ user: t.Nullable(UserSchema), actors: t.Array(ActorWithGuildSchema), }), 401: ErrorSchema, 500: ErrorSchema, }, tags: ["auth"], }, ) .use(routes.guildRoutes), ) .get("*", async ({ path, set }) => { const isExcluded = path === "/api" || path.startsWith("/api/") || path === "/auth" || path.startsWith("/auth/"); if (isExcluded) { set.status = 404; return { message: "Not Found" }; } if (path.includes("..")) { set.status = 400; return { message: "Bad Request" }; } if (path !== "/") { const staticFile = Bun.file(join(config.api.publicDir, path)); if (await staticFile.exists()) { if (path.startsWith("/assets/")) { set.headers["cache-control"] = "public, max-age=31536000, immutable"; } return staticFile; } } set.headers["cache-control"] = "no-store, no-cache, must-revalidate, proxy-revalidate"; return Bun.file(join(config.api.publicDir, "index.html")); }); export type App = typeof app; export type { ErrorResponse, GuildAccess, SanitisedActor, SanitisedActorWithGuild, SanitisedGuild, SanitisedTicket, SanitisedTicketAttachment, SanitisedTicketComment, SanitisedTicketMessage, SanitisedTicketParticipant, SanitisedUser, OverallStats, LeaderboardEntry, LeaderboardResponse, } from "./lib/schemas";