Packages

api-client

The platform-neutral JSON transport shared by web and Expo.

statshub-api-client owns HTTP behavior that must agree across the browser, Next.js, and React Native. It has no React, Next.js, Expo, Supabase, or Better Auth dependency.

Exports

ExportTypeDescription
createHttpClientfunctionCreates a client with get, post, put, patch, delete, and request methods.
buildUrlfunctionJoins a base URL and path, drops nullish query values, and serializes arrays as comma-separated values.
readResponseBodyfunctionReads empty, JSON, plain-text, and HTML bodies without losing the original text.
ApiErrorclassCarries the HTTP status, URL, and parsed body. Status 0 means no response arrived.
isAbortErrorfunctionRecognises browser cancellation and React Native's released-response cancellation error.

HttpClientConfig

PropertyTypeRequiredDefaultDescription
baseUrlstringNosame-origin pathPrefix for every request path.
fetch(url, init) => Promise<Response>Noglobal fetchAdapter used by Next.js to add cache metadata and by tests to supply responses.
headersHeadersInitNononeHeaders applied to every request.
getHeaders() => HeadersInit | Promise<HeadersInit>NononeRequest-scoped cookie or bearer headers. Called for every request.
unwrapDatabooleanNofalseReturns the value inside a successful { data: value } body.

Header precedence is fixed: static client headers, then getHeaders, then the JSON content type, then request headers. A caller can override any earlier value for one request.

Request behavior

ConditionResult
undefined or null query valueOmitted from the URL.
Array query valueOne comma-separated query value.
Body is presentJSON encoded with Content-Type: application/json.
Empty successful bodyResolves as undefined.
Non-2xx responseThrows ApiError with the parsed body.
Network failureThrows ApiError with status 0.
Aborted requestPreserves AbortError; never reports it as a network failure.

Example

import { createHttpClient } from "statshub-api-client";

const api = createHttpClient({
  baseUrl: "https://www.statshub.com/api/v2",
});

const fixtures = await api.get<{ data: unknown[] }>("/event/by-date", {
  query: { startOfDay: 1787950800, endOfDay: 1788037200 },
});

Platform adapters

ConsumerAdapter responsibility
Web Server ComponentsAdds Next.js revalidation tags. Private reads inject the complete Supabase cookie header and use no-store.
Web client componentsGives SWR a same-origin get or post function.
ExpoSupplies the absolute API origin. The StatsHub-specific client keeps its Cloudflare backoff and cached-5xx retry.

getHeaders is an authentication seam, not an identity provider. Web sessions remain Supabase sessions because the Go API validates Supabase credentials. Expo accounts remain Better Auth sessions in Convex. The two providers cannot be exchanged until the Go API accepts the same identity; sharing a TypeScript interface would not make their cookies or tokens compatible.

Errors

ErrorCondition
ApiError with status 0Fetch failed before an HTTP response arrived.
ApiError with status 400599The server returned a non-success status.
AbortErrorThe caller cancelled the request.
  • Web data — Next.js cache and SWR adapters.
  • Expo data — React Query resources and API-specific retries.
  • API contract — response compatibility between API implementations.

On this page