Przejdź do głównej zawartości

Interface: ServerClientOptions

Extends

Properties

apiUrl

apiUrl: string

GraphQL API URL (e.g. 'https://api.doswiftly.pl')

Inherited from

StorefrontClientConfig.apiUrl


buildApiUrl?

optional buildApiUrl?: string | null

Host to read storefront data from WHILE A BUILD IS RUNNING, instead of apiUrl.

A shop served from its own api.{apex} sits behind that zone's bot protection, which challenges precisely what a build looks like — a datacenter address issuing one burst — and cannot be waived for it. Reading from the platform host during the build sidesteps that, while the browser bundle keeps pointing at the merchant host, which is the whole reason that host exists.

Applies ONLY during a build; live server rendering always uses apiUrl. Defaults to DOSWIFTLY_BUILD_API_URL, which the deploy pipeline sets. Pass a value to pin it, or null to keep using apiUrl even during a build.


debug?

optional debug?: boolean | "verbose" | DebugOptions

Enable debug logging (request/response in dev).

Tagged union (backward-compatible):

  • false / omitted — no logging.
  • true — minimal logs: operationName + variables on request, status + hasErrors + userErrors on response. The exact output is preserved from the v17.1.0 minimal mode.
  • 'verbose' — every dimension on: full query + variables + headers + response body + userErrors + timing.
  • DebugOptions — granular opt-in per dimension.

Falls back to process.env.DOSWIFTLY_SDK_DEBUG ('verbose' / 'true' / '1') when this prop is omitted. NODE_ENV=production requires an explicit debug setting — env-driven verbose mode is no-op in production to prevent accidental logging of customer PII.

Authorization: Bearer … and customerAccessToken=… cookie values are unconditionally redacted to ***<last4> whenever headers are logged, regardless of mode.

Inherited from

StorefrontClientConfig.debug


defaultHeaders?

optional defaultHeaders?: Record<string, string>

Default headers for all requests

Inherited from

StorefrontClientConfig.defaultHeaders


fetch?

optional fetch?: {(input, init?): Promise<Response>; (input, init?): Promise<Response>; }

Custom fetch implementation (polyfill, test mocks, edge)

Call Signature

(input, init?): Promise<Response>

MDN Reference

Parameters
input

RequestInfo | URL

init?

RequestInit

Returns

Promise<Response>

Call Signature

(input, init?): Promise<Response>

MDN Reference

Parameters
input

string | Request | URL

init?

RequestInit

Returns

Promise<Response>

Inherited from

StorefrontClientConfig.fetch


getBuyerIp?

optional getBuyerIp?: () => string | Promise<string | null | undefined> | null | undefined

Buyer-IP source that ENABLES forwarded-IP signing (opt-in). The forwarded-IP middleware is wired ONLY when this is provided — without it the client never reads the buyer IP and never signs (a fully static-safe, inert pass-through).

Reading the buyer IP needs a request-scoped dynamic API (e.g. next/headers headers()), which is ILLEGAL in statically-generated / ISR routes — calling it there crashes the page ("static to dynamic at runtime"). So provide this ONLY on routes that are already dynamic (per-request rendered). A server-rendered storefront otherwise collapses every buyer onto its own server IP for rate limiting; forwarding the real IP restores per-buyer limits. May be async. Server-side only.

Returns

string | Promise<string | null | undefined> | null | undefined

Example

// ONLY on a dynamic route — `headers()` forces dynamic rendering:
import { headers } from 'next/headers';
getStorefrontClient({ apiUrl, shopSlug, getBuyerIp: async () => (await headers()).get('cf-connecting-ip') });

getForwardedIpSecret?

optional getForwardedIpSecret?: () => string | Promise<string | null | undefined> | null | undefined

OPTIONAL override for the forwarded-IP signing secret. By default it is read from process.env.DOSWIFTLY_FORWARDED_IP_SECRET, set in your DoSwiftly deployment environment. Provide this getter only to override the env source — e.g. a runtime that does not expose the secret on process.env. Lazy getter — a rotated secret is picked up without rebuilding the client. NEVER expose this to the browser. Sync or async.

Returns

string | Promise<string | null | undefined> | null | undefined


graphqlPath?

optional graphqlPath?: string

GraphQL endpoint path appended to apiUrl. Defaults to /storefront/graphql (the public catalog surface — cacheable). Set to /storefront/customer/graphql to target the customer-account surface (orders, addresses, wishlist, loyalty), which is always served fresh (never shared-cached). Must start with /.

Inherited from

StorefrontClientConfig.graphqlPath


maxConcurrency?

optional maxConcurrency?: number

Maximum data requests this process keeps in flight at once. 0 disables the cap.

Unbounded fan-out from one process is what rate limits punish: a production build renders every page in one process and fires its requests as fast as the renderer schedules them, and a sitemap route or a bulk migration script does the same. Capping spreads the same work over a window the API will serve. The budget is shared by every client in the process, so a per-request client still counts against it.

When you pass a value it is always honoured. When you do not, the deploy pipeline's build environment supplies one (DOSWIFTLY_BUILD_CONCURRENCY, default 6) and live rendering is left uncapped, so no visitor request ever queues behind another.


middleware?

optional middleware?: Middleware[]

Additional middleware (prepended to default pipeline).

Use this for request-scoped headers (e.g. currency from cookie, language from URL, custom tracking):

getStorefrontClient({
apiUrl, shopSlug,
middleware: [
async (req, next) => {
req.headers['X-Preferred-Currency'] = await readCookieFromHeaders();
return next(req);
},
],
});

minRequestIntervalMs?

optional minRequestIntervalMs?: number

Minimum spacing between request starts, in milliseconds. 0 disables it.

A ceiling on requests in flight does not bound requests per MINUTE, which is what a server-side rate limit measures — six slots against fast responses still sustains tens of requests per second. Spacing is what bounds it.

Same resolution as maxConcurrency: an explicit value always wins, otherwise a deploy build supplies one (DOSWIFTLY_BUILD_MIN_INTERVAL_MS, default 200 ms ≈ 300 requests per minute) and live rendering is left unpaced.


shopSlug

shopSlug: string

Shop slug for multi-tenant routing

Inherited from

StorefrontClientConfig.shopSlug


telemetry?

optional telemetry?: boolean | { endpoint?: string; heartbeatIntervalMs?: number; includeNonProduction?: boolean; }

Cookieless visitor telemetry (page-load ping + heartbeat while the tab is visible). Collects the raw referrer, user agent and an ephemeral per-tab session id — no cookies, no PII.

Enabled by default on a live shop; pass false to opt out. Nothing is sent from a local address (localhost, a loopback IP, a .local / .localhost name) or from a build whose mode is not production, so your development sessions stay out of the shop's figures. Set includeNonProduction: true when you deliberately want to measure such an environment.

Inherited from

StorefrontClientConfig.telemetry


trustedDocuments?

optional trustedDocuments?: boolean

Whether the target GraphQL surface resolves persisted-document ids (trusted documents). The default public catalog endpoint does; the customer-account endpoint does not. When false, the client always sends the full query — it never uses the cacheable GET nor sends a documentId over POST. Defaults to true. createCustomerClient forces false; set it yourself only when pointing createStorefrontClient at a custom endpoint without persisted-document support.

Inherited from

StorefrontClientConfig.trustedDocuments