spb/internetpressure
Public
TypeScript 36.3%
Python 31.8%
Go 18%
JavaScript 9.8%
Shell 1.9%
SQL 1.4%
CSS 0.5%
1'use client';23/** Tiny client for /api/admin/* — token lives in sessionStorage only and travels as X-IP-Admin-Token. */4const KEY = 'ip.admin-token';56export function getAdminToken(): string {7 try {8 return window.sessionStorage.getItem(KEY) ?? '';9 } catch {10 return '';11 }12}13export function setAdminToken(token: string) {14 try {15 if (token) window.sessionStorage.setItem(KEY, token);16 else window.sessionStorage.removeItem(KEY);17 } catch {18 /* ignore */19 }20}2122export class AdminError extends Error {23 constructor(24 public status: number,25 public body: unknown,26 ) {27 super(status === 401 ? 'Unauthorized' : `Admin API error ${status}`);28 }29}3031export async function adminFetch<T>(path: string, init?: { method?: string; body?: unknown; params?: Record<string, string | number | undefined> }): Promise<T> {32 const qs = init?.params33 ? '?' +34 Object.entries(init.params)35 .filter(([, v]) => v !== undefined && v !== '')36 .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(String(v))}`)37 .join('&')38 : '';39 const res = await fetch(`/api/admin${path}${qs}`, {40 method: init?.method ?? 'GET',41 headers: { 'X-IP-Admin-Token': getAdminToken(), ...(init?.body !== undefined ? { 'Content-Type': 'application/json' } : {}) },42 body: init?.body !== undefined ? JSON.stringify(init.body) : undefined,43 cache: 'no-store',44 });45 if (!res.ok) {46 let body: unknown = null;47 try {48 body = await res.json();49 } catch {50 /* no body */51 }52 throw new AdminError(res.status, body);53 }54 return (await res.json()) as T;55}56