SPB Git forge

spb/spinza

Public
8commits 1branches 0releases
1.6 MBsize
maindefault branch
16 days agolast push
TypeScript 97.6% SQL 1.4% JavaScript 0.5%
1.4 KB · 43 lines typescript
Raw Blame History
1"use client";23import type { ApiError } from "@spinza/shared";45export class ApiClientError extends Error {6  constructor(7    public status: number,8    public code: string,9    message: string,10    public details?: unknown,11  ) {12    super(message);13  }14}1516/** Browser fetch wrapper: same-origin `/api/*`, JSON in/out, typed errors. */17export async function api<T>(path: string, init: RequestInit & { json?: unknown } = {}): Promise<T> {18  const { json, headers, ...rest } = init;19  const res = await fetch(path, {20    ...rest,21    method: rest.method ?? (json !== undefined ? "POST" : "GET"),22    credentials: "same-origin",23    headers: { ...(json !== undefined ? { "Content-Type": "application/json" } : {}), ...(headers ?? {}) },24    body: json !== undefined ? JSON.stringify(json) : rest.body,25  }).catch(() => {26    throw new ApiClientError(0, "NETWORK", "Connection lost. Check your network and try again.");27  });28  const text = await res.text();29  let data: unknown = null;30  try {31    data = text ? JSON.parse(text) : null;32  } catch {33    data = null;34  }35  if (!res.ok) {36    const e = (data ?? {}) as Partial<ApiError>;37    throw new ApiClientError(res.status, e.error ?? "HTTP_" + res.status, e.message ?? (res.status >= 500 ? "Server unavailable. Please try again shortly." : "Request failed."), e.details);38  }39  return data as T;40}4142export const isUnauthorized = (e: unknown) => e instanceof ApiClientError && e.status === 401;43