API Client & Curator Auth
dicechess-analytics-ui communicates with the analytical backend database via a lightweight, typed API Client wrapper and manages position favorite annotations via Curator tokens.
1. API Client (ApiClient)
Section titled “1. API Client (ApiClient)”The core API request wrapper is defined in src/lib/api/client.ts.
Key Features
Section titled “Key Features”- Response Handling: Automatically resolves standard responses. If the response content is empty, returns
null. Parses JSON responses where possible, returning raw text as a fallback. - Error Handling: Converts non-ok HTTP statuses into a custom
ApiErrorclass containing status codes and detailed backend messages (fromdetailormessageproperties). - Verb Wrappers: Provides standard typing and configurations for
get(),post(),put(), anddelete().
export class ApiError extends Error { status: number; constructor(status: number, message: string) { super(message); this.status = status; this.name = 'ApiError'; }}2. Favorites API Contract
Section titled “2. Favorites API Contract”The favorites curation contract is defined in src/lib/api/favorites.ts. It exposes three core endpoints:
export interface FavoriteEntry { normalized_fen: string; dice_sorted: string; moves: string[]; note: string | null;}
export interface PositionFavorites { normalized_fen: string; items: FavoriteEntry[];}
// GET /api/opening-book/favorites?fen=...export function getFavorites(fen: string): Promise<PositionFavorites>;
// PUT /api/opening-book/favorites (body: { fen, dice, moves })export function putFavorite( fen: string, dice: string, moves: string[], token: string,): Promise<FavoriteEntry>;
// DELETE /api/opening-book/favorites (body: { fen, dice })export function deleteFavorite(fen: string, dice: string, token: string): Promise<void>;3. Curator Token & Store (CuratorStore)
Section titled “3. Curator Token & Store (CuratorStore)”The application supports setting recommendations (favorites) for specific positions and rolled dice combinations. Curation permissions are gated via a Curator Token.
The token state, cache, and validation actions are managed via curatorStore.svelte.ts.
Persistent Caching
Section titled “Persistent Caching”The token is cached locally inside the user’s browser localStorage using the key dc-curator-token. This ensures curators do not have to re-enter their token on page reload.
const TOKEN_KEY = 'dc-curator-token';
class CuratorStore { token = $state<string>('');
constructor() { if (typeof window !== 'undefined') { try { this.token = localStorage.getItem(TOKEN_KEY) ?? ''; } catch (_e) { // Ignored — privacy mode or storage unavailable } } }}Race-Condition Protection
Section titled “Race-Condition Protection”When a user navigates between chess positions rapidly, multiple asynchronous HTTP requests to getFavorites are fired in flight. To prevent late-arriving responses from overwriting the state of the currently active board position, CuratorStore employs a monotonic version counter:
class CuratorStore { private version = 0; private loadedFen = '';
async loadFavorites(fen: string) { if (!this.hasToken || fen === this.loadedFen) return; const myVersion = ++this.version; try { const data = await getFavorites(fen); // Discard if a newer invalidate() or loadFavorites() was triggered in flight if (myVersion !== this.version) return;
// Map data to reactive favMap... } catch (_e) { // Fail silently, leave favMap empty } }}[!TIP] When a user changes positions or the explorer component is unmounted, calling
curatorStore.invalidate()increments theversioncounter and clearsfavMap. This immediately discards any active in-flight request and prevents memory leaks or state bleeding between positions.
Pessimistic State Updates
Section titled “Pessimistic State Updates”When toggling favorites via toggleFavorite(), CuratorStore performs a pessimistic update. It awaits the backend API request (PUT or DELETE) to succeed before updating the reactive favMap in memory. If the API request fails (e.g., due to an expired token or network error), the map state remains unmodified, preventing the UI from showing incorrect recommendations.