Server Fetch

Cookie-aware fetch for RSC & actions

serverFetch is a small, typed HTTP client for the places the React hook can't run: server components, server actions and route handlers. It speaks the same conventions as the generated client — normalised responses, timeouts and retries — without any React lifecycle.

Where useApiActions wraps interactive, stateful calls, serverFetch is for fetch-on-the-server-then-render: load data during SSR, mutate inside a server action, then revalidate. It returns a rich ServerFetchResponse including the raw Set-Cookie headers, so refreshed auth cookies can be forwarded straight back to the browser.

Use the shared serverFetch singleton for quick calls, or construct a ServerFetch with its own base URL and defaults for a specific upstream.

Making a request#

Each call describes the url and method, with optional headers, body, and per-request timeout/retry overrides. Object bodies are JSON-encoded for you. The generic parameters type both the success payload (T) and the error shape (E), where E defaults to the exported BaseError type — { message: string; code?: string; details?: unknown }.

app/dashboard/page.tsx — authenticated SSR read
1import { cookies } from "next/headers";2import { serverFetch } from "nucleus-core-ts";3import type { Product } from "@/types";4 5const cookie = (await cookies()).toString();6const res = await serverFetch.fetch<Product[]>({7  url: `${process.env.API_BASE_URL}/products`,8  method: "GET",9  headers: { cookie },10});11 12if (res.isSuccess) renderProducts(res.response);
serverFetch.fetch<T, E>(options)(options) => Promise<ServerFetchResponse<T, E>>Optional

serverFetch is a shared ServerFetch instance; call serverFetch.fetch(options) to perform a request and resolve to a typed, normalised response. Never throws on HTTP errors — inspect isSuccess and code instead.

verb shortcutsget/delete(url, options?) · post/put/patch(url, body, options?)Optional

The instance also exposes verb helpers that delegate to fetch(): serverFetch.get(url, options?), serverFetch.delete(url, options?), and serverFetch.post/put/patch(url, body, options?) — each returns the same ServerFetchResponse<T, E>.

options.urlstringRequired

Absolute URL, or a path appended to the instance baseUrl when one is configured.

options.method'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH'Required

The HTTP verb for the request.

options.bodyBodyInit | Record<string, unknown>Optional

Request body. Plain objects are serialised to JSON with the right Content-Type; pass a BodyInit (FormData, string…) to take control.

options.headersHeadersInitOptional

Per-request headers, merged over the instance defaultHeaders. This is where you forward the incoming request's cookie header for authenticated SSR calls.

options.timeoutnumberOptional

Per-request timeout in ms, overriding the instance default.

options.retries / options.retryDelaynumberOptional

Override how many times (and how long between, in ms) the request is retried for this call. Retries apply only to connection or timeout errors — a completed non-2xx HTTP response is returned immediately and never retried.

Configuring an instance#

new ServerFetch(config) creates a client preset with a base URL, default headers and global timeout/retry policy — handy when one service has its own conventions. The exported serverFetch is just a ready-made default instance.

baseUrlstringOptional

Prefix prepended to relative request URLs.

defaultHeadersRecord<string, string>Optional

Headers sent on every request from this instance (e.g. an API version or service token).

timeoutnumberOptional

Default timeout in ms applied when a call doesn't override it.

Default30000
retries / retryDelaynumberOptional

Default retry count and delay (ms) across this instance, for transient network/timeout failures only — non-2xx HTTP responses are returned, not retried. Defaults to no retries, 1000 ms apart when enabled.

Default0 / 1000
debugbooleanOptional

Enable pretty-printed, colorized log output for this instance. It only changes formatting: requests are logged (with timing and request id) on every call regardless, since the internal Logger runs at 'info' level independent of this flag.

Defaultfalse

The response shape#

ServerFetchResponse is deliberately explicit — no exceptions to catch. It tells you whether it worked, the parsed body or errors, the status, and crucially the raw Set-Cookie headers so token rotation can be relayed to the client.

isSuccessbooleanOptional

Whether the upstream returned a 2xx. Branch on this, not on try/catch.

response / errorsT | E | undefinedOptional

The parsed success payload, or the parsed error body when isSuccess is false. E defaults to the exported BaseError type ({ message, code?, details? }); when the request never completes (transport/timeout error) or the error body is non-JSON or empty, the client synthesises a plain { message } object as E rather than parsing one.

codenumber | nullOptional

The HTTP status code, or null if the request never completed.

rawSetCookiesstring[]Optional

Raw Set-Cookie headers from the upstream — forward these to the browser to propagate refreshed access/refresh tokens.

headers / durationMs / requestId / createdAtmetadataOptional

Response headers, wall-clock duration, a correlation id and a timestamp for logging and tracing.

Related sections