WIP! A BB-style forum, on the ATmosphere! We're still working... we'll be back soon when we have something to show off!
node typescript hono htmx atproto
at f53be90536e6445b2c17faf0d219937abc94a3d4 43 lines 1.3 kB view raw
1import { loadConfig } from "./config.js"; 2 3const config = loadConfig(); 4 5/** 6 * Fetches from the AppView API and returns parsed JSON. 7 * 8 * Throws two distinct error shapes that callers must classify: 9 * - `"AppView network error: ..."` — AppView is unreachable; callers should 10 * return 503 so the user knows to retry. 11 * - `"AppView API error: N ..."` — AppView returned a non-ok HTTP status; 12 * callers should map to an appropriate response (404, 400, 500, etc.). 13 */ 14export async function fetchApi<T>( 15 path: string, 16 options?: { cookieHeader?: string } 17): Promise<T> { 18 const url = `${config.appviewUrl}/api${path}`; 19 const headers: Record<string, string> = {}; 20 if (options?.cookieHeader) { 21 headers["Cookie"] = options.cookieHeader; 22 } 23 let res: Response; 24 try { 25 res = await fetch(url, { headers }); 26 } catch (error) { 27 throw new Error( 28 `AppView network error: ${error instanceof Error ? error.message : String(error)}` 29 ); 30 } 31 if (!res.ok) { 32 throw new Error(`AppView API error: ${res.status} ${res.statusText}`); 33 } 34 let parsed: T; 35 try { 36 parsed = (await res.json()) as T; 37 } catch (error) { 38 throw new Error( 39 `AppView response error: invalid JSON from ${path} (${error instanceof Error ? error.message : String(error)})` 40 ); 41 } 42 return parsed; 43}