// Pure hash-path -> Route parsing for the router. Kept dependency-free and free of any // reactive state so it unit-tests in the node environment; router.svelte.ts wraps it with // the reactive route rune and navigation. export type RouteName = | 'login' | 'lobby' | 'new' | 'game' | 'gameChat' | 'gameCheck' | 'profile' | 'settings' | 'about' | 'friends' | 'feedback' | 'stats' | 'notfound'; export interface Route { name: RouteName; params: Record; } /** * parse maps a location hash to a Route. An empty hash is the lobby root. A Telegram Mini * App cold launch appends its launch params to the URL fragment (#tgWebAppData=...& * tgWebAppVersion=...); those are launch metadata, not a route, so the fragment is treated * as the lobby root. Otherwise it would parse as notfound, and bootstrap's navigate('/') * would then re-key the route pane (notfound -> lobby), sliding the lobby in on launch as if * returning from another screen. */ export function parse(hash: string): Route { const raw = hash.replace(/^#/, ''); if (raw === '' || raw.startsWith('tgWebApp')) return { name: 'lobby', params: {} }; const path = raw.split('?')[0]; const seg = path.split('/').filter(Boolean); if (seg.length === 0) return { name: 'lobby', params: {} }; switch (seg[0]) { case 'login': return { name: 'login', params: {} }; case 'new': return { name: 'new', params: {} }; case 'game': if (!seg[1]) return { name: 'notfound', params: {} }; if (seg[2] === 'chat') return { name: 'gameChat', params: { id: seg[1] } }; if (seg[2] === 'check') return { name: 'gameCheck', params: { id: seg[1] } }; return { name: 'game', params: { id: seg[1] } }; case 'profile': return { name: 'profile', params: {} }; case 'settings': return { name: 'settings', params: {} }; case 'about': return { name: 'about', params: {} }; case 'friends': return { name: 'friends', params: {} }; case 'feedback': return { name: 'feedback', params: {} }; case 'stats': return { name: 'stats', params: {} }; default: return { name: 'notfound', params: {} }; } }