api: serve frontend
vi did:web:vt3e.cat
Tue, 30 Jun 2026 19:33:54 +0100
5 files changed,
42 insertions(+),
18 deletions(-)
M
apps/api/package.json
→
apps/api/package.json
@@ -14,6 +14,7 @@ "dependencies": {
"@elysia/cors": "^1.4.2", "@elysia/openapi": "^1.4.15", "@elysia/server-timing": "^1.4.1", + "@elysia/static": "^1.4.11", "@purrkit/ratelimit": "^1.0.1", "@purrkit/rest": "^1.1.2", "@purrkit/types": "^1.1.1",
M
apps/api/src/app.ts
→
apps/api/src/app.ts
@@ -1,6 +1,8 @@
import cors from "@elysia/cors"; import openapi from "@elysia/openapi"; import serverTiming from "@elysia/server-timing"; +import { staticPlugin } from "@elysia/static"; +import config from "@stealth-developers/config"; import { getUser } from "@stealth-developers/db"; import { Elysia, t } from "elysia";@@ -11,10 +13,7 @@ import { ActorWithGuildSchema, ErrorSchema, UserSchema } from "./lib/schemas";
import * as routes from "./routes"; export const app = new Elysia() - .use(openapi()) - .use(cors()) - .use(authPlugin) - .use(serverTiming()) + .onError(({ error, set, request }) => { set.status = 500; console.error(request.url, error);@@ -22,6 +21,17 @@
if (error instanceof Error) return { message: error.message ?? "Internal Server Error" }; return { message: "Unknown Error" }; }) + .use(openapi()) + .use(cors()) + .use( + staticPlugin({ + assets: config.api.publicDir, + indexHTML: true, + prefix: "/", + }), + ) + .use(authPlugin) + .use(serverTiming()) .use(routes.authRoutes) .group("/api", (app) => app
M
apps/web/src/stores/api.ts
→
apps/web/src/stores/api.ts
@@ -15,22 +15,31 @@ const actors = ref<Record<string, SanitisedActorWithGuild>>({});
const guild = ref<unknown | null>(null); async function getUser() { - const res = await client.api.me.get(); - if (res.status !== 200 || !res.data) return; - isAuthenticated.value = true; - isAuthenticating.value = false; - user.value = res.data.user; + try { + const res = await client.api.me.get(); + + if (res.status === 200 && res.data) { + isAuthenticated.value = true; + user.value = res.data.user; - const resActors = res.data.actors; - actors.value = resActors.reduce( - (acc, actor) => { - acc[actor.guild!.discordId!] = actor; - return acc; - }, - {} as Record<string, SanitisedActorWithGuild>, - ); + const resActors = res.data.actors; + actors.value = resActors.reduce( + (acc, actor) => { + if (actor.guild?.discordId) { + acc[actor.guild.discordId] = actor; + } + return acc; + }, + {} as Record<string, SanitisedActorWithGuild>, + ); - guild.value = res.data.actors[0]?.guild; + guild.value = res.data.actors[0]?.guild; + } + } catch (error) { + console.error(error); + } finally { + isAuthenticating.value = false; + } } async function waitForAuth() {
M
bun.lock
→
bun.lock
@@ -25,6 +25,7 @@ "dependencies": {
"@elysia/cors": "^1.4.2", "@elysia/openapi": "^1.4.15", "@elysia/server-timing": "^1.4.1", + "@elysia/static": "^1.4.11", "@purrkit/ratelimit": "^1.0.1", "@purrkit/rest": "^1.1.2", "@purrkit/types": "^1.1.1",@@ -225,6 +226,8 @@
"@elysia/openapi": ["@elysia/openapi@1.4.15", "", { "peerDependencies": { "elysia": ">= 1.4.0" } }, "sha512-MrVGCPo5hnRF4/yWGOyH5ddjt4DlSIbeC5rrkupQtHY8TEQe+XdJa2YM9aUOrtgtRcy4UNGyiVlLl/jllPkPQA=="], "@elysia/server-timing": ["@elysia/server-timing@1.4.1", "", { "peerDependencies": { "elysia": ">= 1.4.0" } }, "sha512-+NDGhslxN0HZuyT8o4dt+hgib9bzsMuvxTE5bPrDhFFRl1duCNosseW3wE76pmwle8+m9+1aOeZ28mZAv51ggQ=="], + + "@elysia/static": ["@elysia/static@1.4.11", "", { "peerDependencies": { "elysia": ">= 1.4.0" } }, "sha512-L3PN8V+cgz9Oz9kTow7ed3DHHCTHb9ZqZZDLxmKhrIKcFmWvjqzTm9TcMR2aLKjjls+QMSGuB7ZyaO+usIXovA=="], "@emnapi/core": ["@emnapi/core@1.11.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.2", "tslib": "^2.4.0" } }, "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ=="],
M
pkgs/config/src/schema.ts
→
pkgs/config/src/schema.ts
@@ -33,6 +33,7 @@ });
const apiSchema = z.object({ port: z.number().default(3000), + publicDir: z.string(), }); const s3Schema = z.object({