Fix save/resume after refresh + map basemap

Map (basemap was rendering black):
- Inline MapLibre style (dark-navy background + subtle OpenFreeMap ne2sr
  raster) instead of the remote "dark" style, whose vector tiles are empty at
  world zoom and gated the choropleth on a remote styledata fetch.
- Explicit prod worker URL (maplibre-gl-worker via ?url) so GeoJSON sources
  process in the production bundle.
- Hardened the choropleth against geo load-order races (empty sources up
  front, ownership stamped once data lands) and bumped fill opacity so the
  vivid per-nation colors are the star on the non-black background.

Save/resume (a refresh used to drop users to the home screen):
- Persist the active game id in localStorage (history.activeGameId) on create
  and resume; clear it when explicitly starting a new game.
- Auto-resume the last game on a page refresh (GET /api/games/:id + /map),
  re-attaching the SSE stream; fall back to home gracefully if it's gone.
- Home screen: prominent "Resume last game" button + a "Saved games" section
  (newest first). New GET /api/games list endpoint.

e2e: two new deterministic tests — auto-resume-on-reload and explicit resume
from the home screen (both under LLM_STUB=1).

Quality gates: typecheck, lint, 21 unit tests, 3 e2e tests — all pass.
This commit is contained in:
2026-10-11 07:18:11 +00:00
parent 913d094e11
commit 2ed1b15318
6 changed files with 380 additions and 32 deletions
+19
View File
@@ -118,6 +118,25 @@ app.post('/api/games', (req: Request, res) => {
res.json({ game: state });
});
// List every saved game (newest-updated first) as a lightweight summary, so the
// home screen can offer to resume prior games. `db.listIds()` is already ordered
// by updated_at DESC.
app.get('/api/games', (_req, res) => {
const games = db
.listIds()
.map((id) => db.load(id))
.filter((g): g is GameState => g !== null)
.map((g) => ({
id: g.id,
presetId: g.presetId,
presetTitle: g.presetTitle,
playerNationId: g.playerNationId,
turn: g.turn,
date: g.date,
}));
res.json({ games });
});
app.get('/api/games/:id', (req, res) => {
const game = db.load(req.params.id);
if (!game) return res.status(404).json({ error: 'game not found' });