// The device-local play identity: a persisted id that exists from the very first launch with no // network and no DB row. It fills the human seat's accountId in a local vs_ai game when there is no // server session yet (so the seat is recognised as "you" across reloads); hotseat seats keep their // own independent local identities. A purely-offline user never mints a server guest and consumes no // server resources — when the app first reaches the network the reconciliation (app.svelte.ts) mints // a server guest and adopts its session, but the local games created under this id stay device-only. // // The display name is not persisted here — it is a UI concern the caller localises (t('common.guest')), // so this module stays free of i18n and unit-tests in the node env alongside the other localgame libs. const ID_KEY = 'scrabble.localGuestId'; /** LOCAL_GUEST_PREFIX marks an account id as a device-local guest (no DB row). */ export const LOCAL_GUEST_PREFIX = 'localguest:'; function mintId(): string { // No crypto API, so it also works on the older engines the SPA still supports (mirrors // localgame/id.ts newLocalGameId). return `${LOCAL_GUEST_PREFIX}${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`; } /** * localGuestId returns the persisted device-local guest id, minting and storing one on first use. * Best-effort persistence: where storage is unavailable it returns a fresh ephemeral id each call (a * device that cannot persist still plays, it just does not carry a stable local identity across * reloads). */ export function localGuestId(): string { try { if (typeof localStorage !== 'undefined') { const existing = localStorage.getItem(ID_KEY); if (existing) return existing; const minted = mintId(); localStorage.setItem(ID_KEY, minted); return minted; } } catch { /* storage unavailable — fall through to an ephemeral id */ } return mintId(); } /** isLocalGuestId reports whether an account id is a device-local guest id. */ export function isLocalGuestId(id: string): boolean { return id.startsWith(LOCAL_GUEST_PREFIX); }