feat(api): add in-memory GameSessionStore

Add the session storage infrastructure for tracking correct answers
during a game. Designed for easy swap to Valkey in Phase 4.

- GameSessionStore interface with create/get/delete methods, all async
  to match the eventual Valkey implementation
- InMemoryGameSessionStore backed by a Map
- GameSessionData holds only the answer key (questionId → correctOptionId)
- Also fix root build script to build packages in dependency order
This commit is contained in:
lila 2026-04-11 11:42:13 +02:00
parent f53ac618bb
commit 1940ff3965
6 changed files with 31 additions and 4 deletions

View file

@ -0,0 +1,7 @@
export type GameSessionData = { answers: Map<string, number> };
export interface GameSessionStore {
create(sessionId: string, data: GameSessionData): Promise<void>;
get(sessionId: string): Promise<GameSessionData | null>;
delete(sessionId: string): Promise<void>;
}

View file

@ -0,0 +1,17 @@
import type { GameSessionStore, GameSessionData } from "./GameSessionStore.js";
export class InMemoryGameSessionStore implements GameSessionStore {
private sessions = new Map<string, GameSessionData>();
async create(sessionId: string, data: GameSessionData): Promise<void> {
this.sessions.set(sessionId, data);
}
async get(sessionId: string): Promise<GameSessionData | null> {
return this.sessions.get(sessionId) ?? null;
}
async delete(sessionId: string): Promise<void> {
this.sessions.delete(sessionId);
}
}

View file

@ -0,0 +1,2 @@
export type { GameSessionStore, GameSessionData } from "./GameSessionStore.js";
export { InMemoryGameSessionStore } from "./InMemoryGameSessionStore.js";

View file

@ -2,7 +2,7 @@
"extends": "../../tsconfig.base.json",
"references": [
{ "path": "../../packages/shared" },
{ "path": "../../packages/db" }
{ "path": "../../packages/db" },
],
"compilerOptions": {
"module": "NodeNext",
@ -10,7 +10,7 @@
"outDir": "./dist",
"resolveJsonModule": true,
"rootDir": ".",
"types": ["vitest/globals"]
"types": ["vitest/globals"],
},
"include": ["src", "vitest.config.ts", "../../packages/db/src/models"]
"include": ["src", "vitest.config.ts"],
}

View file

@ -4,6 +4,7 @@
"description": "a vocabulary trainer",
"private": true,
"scripts": {
"build": "pnpm --filter @glossa/shared build && pnpm --filter @glossa/db build",
"dev": "concurrently --names \"api,web\" -c \"magenta.bold,green.bold\" \"pnpm --filter @glossa/api dev\" \"pnpm --filter @glossa/web dev\"",
"test": "vitest",
"test:run": "vitest run",

View file

@ -103,7 +103,7 @@ const createDeck = async (tx: DbOrTx, validatedLanguages: string[]) => {
description: config.deckDescription,
source_language: config.sourceLanguage,
validated_languages: validatedLanguages,
is_public: false,
type: "core",
})
.returning({ id: decks.id });
const created = result[0];