M1 기반: 모노레포, 공통 엔진, 공용 프로토콜, 오목 엔진, 서버 골격

- packages/engine: 시드 RNG(sfc32), GameDefinition 타입, 무작위 대국·정보 유출 테스트 도구
- packages/shared: WS 프로토콜 스키마, 닉네임·방 코드 규칙, 게임 카탈로그
- packages/games/omok: 한국식·렌주·자유룰, 재귀 금수 판정, 무르기·무승부·시계 (테스트 27개)
- apps/server: SQLite 스키마, 게스트·디스코드 로그인, 세션, 방 관리(저장·복구·타이머·재접속), WS 게이트웨이, HTTP API

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
EJClaw
2026-10-04 04:18:29 +09:00
parent f4d63e1544
commit 6ee8da18f1
45 changed files with 4175 additions and 0 deletions

30
apps/server/src/config.ts Normal file
View File

@@ -0,0 +1,30 @@
export interface Config {
port: number;
publicOrigin: string;
/** Extra origins accepted for WS/CSRF checks (e.g. Vite dev server). */
allowedOrigins: string[];
dbPath: string;
discord: { clientId: string; clientSecret: string } | null;
sessionSecret: string;
secureCookies: boolean;
}
export function loadConfig(env: Record<string, string | undefined> = process.env): Config {
const publicOrigin = (env.PUBLIC_ORIGIN ?? 'http://localhost:5173').replace(/\/$/, '');
const extra = (env.ALLOWED_ORIGINS ?? '').split(',').map((s) => s.trim()).filter(Boolean);
const clientId = env.DISCORD_CLIENT_ID;
const clientSecret = env.DISCORD_CLIENT_SECRET;
const sessionSecret = env.SESSION_SECRET ?? '';
if (publicOrigin.startsWith('https://') && sessionSecret.length < 32) {
throw new Error('SESSION_SECRET must be at least 32 characters in production');
}
return {
port: Number(env.PORT ?? 3000),
publicOrigin,
allowedOrigins: [publicOrigin, ...extra],
dbPath: env.DB_PATH ?? './data/app.db',
discord: clientId && clientSecret ? { clientId, clientSecret } : null,
sessionSecret: sessionSecret || 'dev-only-insecure-session-secret-change-me',
secureCookies: publicOrigin.startsWith('https://'),
};
}