export interface SessionContext { sessionCode: string; playerId: number; token: string; } export interface SessionContextInput { sessionCode: string; playerId: number; token: string; } export interface SessionContextStore { get(): SessionContext | null; set(input: SessionContextInput): SessionContext; clear(): void; } export interface StorageLike { getItem(key: string): string | null; setItem(key: string, value: string): void; removeItem(key: string): void; } const DEFAULT_STORAGE_KEY = 'wpp.session-context'; function normalizeSessionCode(value: string): string { return value.trim().toUpperCase(); } function normalizeToken(value: string): string { return value.trim(); } function toContext(input: SessionContextInput): SessionContext { const sessionCode = normalizeSessionCode(input.sessionCode); const token = normalizeToken(input.token); if (!sessionCode) { throw new Error('sessionCode is required'); } if (!Number.isInteger(input.playerId) || input.playerId <= 0) { throw new Error('playerId must be a positive integer'); } if (!token) { throw new Error('token is required'); } return { sessionCode, playerId: input.playerId, token }; } function safeParse(raw: string): SessionContext | null { try { const data = JSON.parse(raw) as Partial; if (typeof data.sessionCode !== 'string' || typeof data.playerId !== 'number' || typeof data.token !== 'string') { return null; } return toContext({ sessionCode: data.sessionCode, playerId: data.playerId, token: data.token }); } catch { return null; } } export function createSessionContextStore(storage?: StorageLike, storageKey = DEFAULT_STORAGE_KEY): SessionContextStore { let current: SessionContext | null = null; function getFromStorage(): SessionContext | null { if (!storage) { return null; } const raw = storage.getItem(storageKey); if (!raw) { return null; } const parsed = safeParse(raw); if (!parsed) { storage.removeItem(storageKey); return null; } return parsed; } return { get(): SessionContext | null { if (current) { return { ...current }; } const fromStorage = getFromStorage(); if (fromStorage) { current = fromStorage; return { ...current }; } return null; }, set(input: SessionContextInput): SessionContext { const normalized = toContext(input); current = normalized; if (storage) { storage.setItem(storageKey, JSON.stringify(normalized)); } return { ...normalized }; }, clear(): void { current = null; if (storage) { storage.removeItem(storageKey); } } }; }