v1.1.0: session guard on all game routes + register + sign-in screen (ISS-107)
CI / build + unit + e2e (pull_request) Failing after 26m20s

This commit is contained in:
2026-09-26 14:40:56 +00:00
parent 21dd37f88c
commit b0f1bd8b67
54 changed files with 1002 additions and 91 deletions
+7 -2
View File
@@ -2,6 +2,7 @@
import { useCallback, useEffect, useRef, useState } from 'react';
import type { StateSnapshot } from './game/state';
import { sessionHeaders, storedSession } from './authClient';
export interface GameStateResult {
state: StateSnapshot | null;
@@ -19,7 +20,8 @@ export interface GameStateResult {
// Single fetch of the full game-state snapshot. Exported separately from the hook so it can be unit-tested with a mocked fetch.
export async function fetchState(): Promise<StateSnapshot> {
const res = await fetch('/api/state', { cache: 'no-store' });
// v1.1.0 (ISS-107): /api/state is session-guarded — the stored id rides along as X-Flight-Session.
const res = await fetch('/api/state', { cache: 'no-store', headers: sessionHeaders() });
if (!res.ok) throw new Error(`GET /api/state → HTTP ${res.status}`);
const snapshot = (await res.json()) as StateSnapshot;
// Dev/e2e hook (v0.15.0): the last successfully polled snapshot, so tests can compare what
@@ -93,7 +95,10 @@ export function useGameState(intervalMs = 1000): GameStateResult {
let source: EventSource | null = null;
try {
source = new EventSource(SSE_URL);
// v1.1.0 (ISS-107): EventSource cannot set custom headers, so the session id rides along as a
// query param — /api/events accepts ?session= exactly for this (requireAuthSse).
const sid = storedSession();
source = new EventSource(sid ? `${SSE_URL}?session=${encodeURIComponent(sid)}` : SSE_URL);
} catch {
source = null; // no EventSource support — pure polling below
}