/* ============================================================ VYNDR 2.0 — app-shell routing config (§6, §12). Plain CommonJS so the client AuthGate/HashRedirect import it (allowJs) AND the Jest suite requires it directly (no transform). AUTH NOTE: our auth is client-side Supabase (session in localStorage via @supabase/supabase-js), and the existing middleware.ts is locale-only. A Next server middleware can't read that session, so the gate is enforced CLIENT-side by . This file is the single source of truth for which routes gate. ============================================================ */ /* Gated — require an authenticated user. Deliberately narrower than the prototype's GATED set: the prototype also gated dashboard + scan, but those are OUR free-scan acquisition funnel (anon/free users get 5 reads), so gating them would be a monetization regression. We gate only the genuinely personal surfaces (a user's own ledger, bets, account, alerts). */ const GATED_ROUTES = [ '/desk', // Session 63 (A1-S4) — the founder's media surface (+ backend allowlist) '/ledger', '/tracker', '/account', '/profile', '/settings', '/notifications', '/invite', ]; /* Open — reachable without auth (marketing + the free funnel + auth itself). */ /* Session 57 (Phase 0): '/terminal' removed — the route now server-redirects to /dashboard (fabricated surface retired), so it needs no gate exemption. */ const OPEN_ROUTES = [ '/', '/dashboard', '/slate', '/scan', '/compare', '/game', '/pricing', '/blog', '/article', '/responsible-gambling', '/help', '/about', '/terms', '/privacy', '/login', '/signup', '/auth', '/forgot-password', '/verify', '/welcome', '/offline', '/upgrade', ]; /* Hash deep-link aliases (§C.3.4). The prototype was a single HTML file using #scan / #terminal; we keep Next file-based routing and treat these hashes as redirects so old share links and PWA shortcuts still resolve. */ const HASH_ALIASES = { '#slate': '/dashboard', '#dashboard': '/dashboard', '#scan': '/scan', '#terminal': '/dashboard', // retired surface (Session 57) — old links land on the slate '#compare': '/compare', '#ledger': '/ledger', '#tracker': '/tracker', '#account': '/account', '#pricing': '/pricing', '#blog': '/blog', '#invite': '/invite', '#notifications': '/notifications', }; /** True when `pathname` falls under a gated route (exact or nested). */ function isGatedRoute(pathname) { if (!pathname) return false; return GATED_ROUTES.some((r) => pathname === r || pathname.startsWith(r + '/')); } /** Resolve a window.location.hash (e.g. "#scan") to a real route, or null. */ function resolveHashAlias(hash) { if (!hash) return null; return HASH_ALIASES[hash] || null; } module.exports = { GATED_ROUTES, OPEN_ROUTES, HASH_ALIASES, isGatedRoute, resolveHashAlias, };