// Thin client for the OTIVM save and map APIs // Backend: GET /api/save/:token — load state // POST /api/save/:token — write state // GET /api/map/:h5/:epoch — H7 land/sea cells for one waypoint at one epoch const BASE_SAVE = '/api/save' const BASE_MAP = '/api/map' // Generate a random 8-character hex token export function generateToken() { return Array.from(crypto.getRandomValues(new Uint8Array(4))) .map((b) => b.toString(16).padStart(2, '0')) .join('') } // Load state from server — returns parsed state object or null export async function loadState(token) { try { const res = await fetch(`${BASE_SAVE}/${token}`) if (!res.ok) return null return await res.json() } catch { return null } } // Save state to server — returns true on success export async function saveState(token, state) { try { const res = await fetch(`${BASE_SAVE}/${token}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(state), }) return res.ok } catch { return false } } // Fetch H7 land/sea classification for one H5 waypoint at one named epoch. // h5: H3 res-5 hex string (e.g. '851e805bfffffff') // epochKey: named epoch from paleo_epochs (e.g. 'roman_14bce') // Returns: { epoch_key, sl_offset_cm, h5, cells: [{ h7, h7_land, h9_total, is_land }] } // Returns null on any error. export async function fetchMapCells(h5, epochKey) { try { const res = await fetch(`${BASE_MAP}/${h5}/${epochKey}`) if (!res.ok) return null return await res.json() } catch { return null } }