// Lightweight fetch wrapper with typed responses export type ApiError = { status: number message: string } export class ApiClient { private baseUrl: string private token?: string constructor(baseUrl: string, token?: string) { this.baseUrl = baseUrl.replace(/\/$/, "") this.token = token } setToken(token: string) { this.token = token } async get(path: string): Promise { return this.request("GET", path) } async post(path: string, body?: unknown): Promise { return this.request("POST", path, body) } private async request( method: string, path: string, body?: unknown ): Promise { const res = await fetch(this.baseUrl + path, { method, headers: { "Content-Type": "application/json", ...(this.token && { Authorization: `Bearer ${this.token}` }), }, body: body ? JSON.stringify(body) : undefined, }) if (!res.ok) { const msg = await res.text() throw { status: res.status, message: msg || res.statusText, } } return (await res.json()) as T } } // Example usage: const api = new ApiClient("https://api.pastehub.de", "user-token") api.get<{ username: string }>("/me").then((me) => { console.log("Logged in as", me.username) })