clone

an rts arena for scripts: submit tribe strategies over the web or mcp, run deterministic matches, watch them

main
tribes / web / src / auth.ts
auth.ts 1.9K
1/**2 * Auth glue: shoo.dev sign-in (script tag in index.html) + session cookie3 * exchange, with a dev fallback (POST /api/session {local: name}).4 *5 * shoo flow (per https://docs.shoo.dev/docs/getting-started-vanilla):6 * - window.Shoo.startSignIn() redirects through shoo and back; shoo.js7 * handles the /shoo/callback exchange and stores the identity locally.8 * - window.Shoo.getIdentity() then returns { userId, token } where token is9 * the signed id_token JWT — we POST it to /api/session for a cookie.10 */11import type { UserInfo } from '@tribes/protocol';12import { api, ApiError } from './api';1314interface ShooIdentity {15 userId: string;16 token: string;17}18interface ShooGlobal {19 startSignIn(opts?: { returnTo?: string; requestPii?: boolean }): void;20 getIdentity(): ShooIdentity | null;21 clearIdentity(): void;22}23declare global {24 interface Window {25 Shoo?: ShooGlobal;26 }27}2829export const shooAvailable = () => typeof window.Shoo?.startSignIn === 'function';3031export function startShooSignIn() {32 window.Shoo?.startSignIn({ returnTo: location.pathname });33}3435/**36 * Resolve the current user: existing session cookie first; otherwise, if shoo37 * left an identity in localStorage (post-callback), exchange it for a session.38 */39export async function resolveUser(): Promise<UserInfo | null> {40 try {41 return await api.me();42 } catch (err) {43 if (!(err instanceof ApiError) || err.status !== 401) throw err;44 }45 const identity = window.Shoo?.getIdentity?.();46 if (identity?.token) {47 try {48 await api.loginWithIdToken(identity.token);49 return await api.me();50 } catch {51 return null; // token rejected (expired/dev server) — fall through to logged out52 }53 }54 return null;55}5657export async function signOut(): Promise<void> {58 try {59 await api.logout();60 } catch {61 /* session may already be gone */62 }63 window.Shoo?.clearIdentity?.();64}