Something went wrong. Try again.
Cooperative email for PDS operators
Something went wrong. Try again.
2.9 kB · 76 lines
TypeScript
at main
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677// Client-side auth gate. Loaded as an inline module on every// authenticated page; runs on DOMContentLoaded and probes// `/api/v1/me`. If the probe returns 401 (or a non-2xx), the page is// redirected to `/` — the marketing landing now doubles as the// sign-in surface (the consolidation PR merged the old /signup form// into the landing).//// History: this used to redirect to `/account` (legacy Templ rendered// a sign-in landing there for anon visitors). When `/account` became// an Astro shell, redirecting to it from the page that ALSO runs this// guard infinite-looped. The intermediate hotfix moved the target to// `/signup`; the consolidation PR then merged /signup into / and// moved the target one step further.//// We deliberately render the page HTML server-side and use this script// to *replace* it on unauthenticated requests rather than wait to fetch// before rendering: the chrome (masthead, nav, footer) is identical in// either state, and a momentary flash of the page shell before the// redirect is cheaper than blanking the page on every dashboard hit.//// The contract is: import this module from any page that requires// auth; on success it dispatches an `auth-ready` event with the// {did, handle} on `document`, which page-level scripts listen for// before fetching their own data. NEVER import this module from `/`// — `/` is the redirect target and importing the guard there would// re-introduce a loop for unauthenticated visitors.
import { apiFetch, type MeResponse } from "../lib/api";
export interface AuthReadyDetail { did: string; handle: string;}
async function check(): Promise<void> { const res = await apiFetch<MeResponse>("/api/v1/me", { redirectOnUnauthorized: false, });
if (!res.ok || !res.data.authenticated) { // Guard against the import-from-/signup mistake catastrophically // resurfacing: if for any reason this module is loaded on // /signup, do NOT redirect (the user is already at the right // place and /signup runs its own funnel-resume probe). if (window.location.pathname === "/") { return; } window.location.href = "/"; return; }
const detail: AuthReadyDetail = { did: res.data.did ?? "", handle: res.data.handle ?? "", };
// Update the right-aligned user chip with the resolved handle // (the server-rendered chrome ships with an empty chip so a stale // CDN cache can't leak another member's identity). const chip = document.querySelector<HTMLElement>(".appnav-user"); if (chip && detail.handle) { chip.textContent = detail.handle; }
document.dispatchEvent( new CustomEvent<AuthReadyDetail>("auth-ready", { detail }), );}
if (document.readyState === "loading") { document.addEventListener("DOMContentLoaded", () => { void check(); });} else { void check();}