feat: initial elysium idle game prototype

Sets up the full monorepo with pnpm workspaces. Includes shared types
package, Hono API with Discord OAuth/JWT auth, Prisma v6 + MongoDB
Atlas, and React + Vite frontend with game loop, five tabs, and
Discord-linked save/load.
This commit is contained in:
2026-03-06 11:26:19 -08:00
committed by Naomi Carrigan
parent c69e155de3
commit a3daed1683
64 changed files with 9011 additions and 0 deletions
+81
View File
@@ -0,0 +1,81 @@
import type {
AuthResponse,
BossDamageRequest,
BossDamageResponse,
LoadResponse,
PrestigeRequest,
PrestigeResponse,
PublicProfileResponse,
SaveRequest,
SaveResponse,
} from "@elysium/types";
const BASE_URL = "/api";
const getToken = (): string | null => localStorage.getItem("elysium_token");
const headers = (): Record<string, string> => {
const token = getToken();
return {
"Content-Type": "application/json",
...(token ? { Authorization: `Bearer ${token}` } : {}),
};
};
const request = async <T>(
path: string,
options?: RequestInit,
): Promise<T> => {
const response = await fetch(`${BASE_URL}${path}`, {
...options,
headers: { ...headers(), ...options?.headers },
});
if (!response.ok) {
const error = (await response.json().catch(() => ({ error: "Unknown error" }))) as {
error: string;
};
throw new Error(error.error);
}
return response.json() as Promise<T>;
};
export const getAuthUrl = async (): Promise<string> => {
const data = await request<{ url: string }>("/auth/url");
return data.url;
};
export const handleAuthCallback = async (code: string): Promise<AuthResponse> => {
const data = await request<AuthResponse>(`/auth/callback?code=${code}`);
localStorage.setItem("elysium_token", data.token);
return data;
};
export const loadGame = async (): Promise<LoadResponse> =>
request<LoadResponse>("/game/load");
export const saveGame = async (body: SaveRequest): Promise<SaveResponse> =>
request<SaveResponse>("/game/save", {
method: "POST",
body: JSON.stringify(body),
});
export const dealBossDamage = async (
body: BossDamageRequest,
): Promise<BossDamageResponse> =>
request<BossDamageResponse>("/boss/damage", {
method: "POST",
body: JSON.stringify(body),
});
export const prestige = async (body: PrestigeRequest): Promise<PrestigeResponse> =>
request<PrestigeResponse>("/prestige", {
method: "POST",
body: JSON.stringify(body),
});
export const getPublicProfile = async (
discordId: string,
): Promise<PublicProfileResponse> =>
request<PublicProfileResponse>(`/profile/${discordId}`);