// Typed fetch wrappers for the /api/auth/* surface (SD-0001 §6.4). Same-origin via the Vite // proxy; cookies carry the session. Errors return the §6.4 envelope; helpers normalize them. import type { SessionState } from "./routing"; export interface ApiError { code: string; message: string; retry_after_s?: number; attempts_remaining?: number; } export interface VerifyResult { account: { email: string }; storefront: { id: number; name: string } | null; created: boolean; } export async function errorOf(resp: Response): Promise { try { const body = await resp.json(); if (body && body.error) return body.error as ApiError; } catch { /* fall through */ } return { code: "unexpected", message: "Something went wrong. Please try again." }; } export async function getMe(): Promise { const resp = await fetch("/api/auth/me", { credentials: "include" }); if (resp.status === 401) return null; if (!resp.ok) return null; return (await resp.json()) as SessionState; } export async function requestCode(email: string): Promise { const resp = await fetch("/api/auth/request-code", { method: "POST", headers: { "content-type": "application/json" }, credentials: "include", body: JSON.stringify({ email }), }); return resp.ok ? null : await errorOf(resp); } export async function verifyCode( email: string, code: string, ): Promise<{ ok: true; result: VerifyResult } | { ok: false; error: ApiError }> { const resp = await fetch("/api/auth/verify", { method: "POST", headers: { "content-type": "application/json" }, credentials: "include", body: JSON.stringify({ email, code }), }); if (resp.ok) return { ok: true, result: (await resp.json()) as VerifyResult }; return { ok: false, error: await errorOf(resp) }; } export async function logout(): Promise { await fetch("/api/auth/logout", { method: "POST", credentials: "include" }); } export interface StorefrontResult { id: number; name: string; } export async function createStorefront( name: string, ): Promise<{ ok: true; storefront: StorefrontResult } | { ok: false; error: ApiError }> { const resp = await fetch("/api/storefronts", { method: "POST", headers: { "content-type": "application/json" }, credentials: "include", body: JSON.stringify(name.trim() ? { name: name.trim() } : {}), }); if (resp.ok) return { ok: true, storefront: (await resp.json()) as StorefrontResult }; return { ok: false, error: await errorOf(resp) }; }