MCPcopy
hub / github.com/tashfeenahmed/freellmapi / apiFetch

Function apiFetch

client/src/lib/api.ts:18–55  ·  view source on GitHub ↗
(path: string, options?: RequestInit)

Source from the content-addressed store, hash-verified

16export const UNAUTHORIZED_EVENT = 'freellmapi:unauthorized';
17
18export async function apiFetch<T>(path: string, options?: RequestInit): Promise<T> {
19 const token = getToken();
20 const res = await fetch(`${BASE}${path}`, {
21 // `...options` first so an explicit method/body/signal applies, but headers
22 // are merged last — otherwise an options.headers would clobber the
23 // Content-Type and Authorization we set here.
24 ...options,
25 headers: {
26 'Content-Type': 'application/json',
27 ...(token ? { Authorization: `Bearer ${token}` } : {}),
28 ...options?.headers,
29 },
30 });
31 if (res.status === 401) {
32 // Session missing/expired — drop the token and let the AuthGate re-render.
33 clearToken();
34 window.dispatchEvent(new CustomEvent(UNAUTHORIZED_EVENT));
35 }
36 if (!res.ok) {
37 const body = await res.json().catch(() => ({ error: { message: res.statusText } }));
38 throw new Error(body.error?.message ?? `HTTP ${res.status}`);
39 }
40 // A 200 whose body isn't JSON means this request never reached the API — the
41 // usual cause is a reverse proxy (or static host) serving the dashboard's
42 // index.html for /api/* instead of forwarding it to the backend. Without this
43 // guard the raw res.json() throws an opaque "Unexpected token '<'", which on
44 // the setup/login form surfaces as "sign up page cannot work". Say what's
45 // actually wrong. (#257)
46 const text = await res.text();
47 try {
48 return JSON.parse(text) as T;
49 } catch {
50 throw new Error(
51 `Expected JSON from ${path} but got a non-JSON response. The API isn't reachable at this origin — ` +
52 `make sure the backend is running and that /api is forwarded to it, not served as the dashboard's static files.`,
53 );
54 }
55}
56
57export async function logout(): Promise<void> {
58 try { await apiFetch('/api/auth/logout', { method: 'POST' }); } catch { /* ignore */ }

Callers 13

AuthGateFunction · 0.90
UnifiedKeySectionFunction · 0.90
ProxySettingsSectionFunction · 0.90
CustomProviderSectionFunction · 0.90
KeysPageFunction · 0.90
PremiumPageFunction · 0.90
AnalyticsPageFunction · 0.90
FallbackPageFunction · 0.90
PlaygroundPageFunction · 0.90
EmbeddingsPageFunction · 0.90
ModelDetailPageFunction · 0.90
FusionPageFunction · 0.90

Calls 2

getTokenFunction · 0.85
clearTokenFunction · 0.85

Tested by

no test coverage detected