Runtime
@sonordev/site-kit/runtime is how a package that builds on site-kit talks to Sonor from the browser, so it never needs a transport of its own. commerce-kit is built on it.
Building a site? You don't need this entry. Forms, analytics, articles and the rest of site-kit already use the same transport.
What it gives a kit
| Export | Use it to |
|---|---|
sonorFetch(url, init?, options?) | Call the Sonor API from the browser. It sends the site credential you pass as apiKey, retries transient failures with a timeout, refreshes an expired site token once, and pauses for a few minutes after an authentication failure, so a misconfigured site doesn't hammer the API. |
getClientApiConfig(options?) | Find the API origin and credential. In the browser that's what SiteKitLayout published. During server rendering it's the server's SONOR_API_URL, and with { serverKey: true } its SONOR_API_KEY. |
readPublishedApiConfig() | Exactly what SiteKitLayout published, with no fallbacks. For code that must stay quiet on a page without the layout. |
DEFAULT_SONOR_API_URL | https://api.sonor.io. |
readAnalyticsIdentity() | Get the visitor's analytics ids, { sessionId, visitorId }, so what you send to Sonor ties to the visit analytics recorded. It only reads: either id is null during server rendering and before analytics has started a session in the tab. It returns null ids when current analytics permission blocks collection. It never throws, including when the browser blocks site storage. |
The types SonorFetchOptions, FetchRetryOptions, ClientApiConfigOptions and AnalyticsIdentity come with them.
import { getClientApiConfig, sonorFetch } from '@sonordev/site-kit/runtime'
export async function startCheckout(payload: unknown) {
const { apiUrl, apiKey } = getClientApiConfig()
// Anything that isn't safe to repeat (checkout, payments, uploads) passes retries: 0.
const response = await sonorFetch(
`${apiUrl}/api/public/example/checkout`,
{ method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) },
{ apiKey, retries: 0 },
)
return response.json()
}Pass apiKey from getClientApiConfig() and sonorFetch sets the x-api-key header itself, using the site's freshest token when the site uses one. Don't set x-api-key or Authorization yourself: on a site that uses tokens, a stale header you set is replaced by the fresh one.
Rules for kits
- Use this entry for browser calls. Don't read
window.__SITE_KIT_*and don't callfetchon the Sonor API directly. A second transport is a second copy of the credential, retry and breaker logic, and it drifts. - Get the visitor's ids from
readAnalyticsIdentity(). Where site-kit keeps them is its own business and can change. - Server data goes through
@sonordev/site-kit/server.serverApiFetchsends the key, bounds each call in time and retries transient failures. Tag what you fetch with your content's entry inSITE_CACHE_TAGSso an edit in Sonor refreshes it, and if you catch errors around your own server calls, rethrow the onesisNextControlFlowrecognizes: they're Next steering the render (a page turning dynamic,redirect(),notFound()), not failures. - Events go through
trackEventandtrackConversionfrom@sonordev/site-kit/analytics(@sonordev/site-kit/clientexports them too). They wait for the analytics provider, which mounts after the page. Don't use theuseAnalyticshooks in a kit: underSiteKitLayoutyour components sit outside the provider, so the hooks have nothing to return. - Lead capture goes through
ManagedFormfrom@sonordev/site-kit/forms. - List site-kit as a peer dependency and mark it external in your bundler, so every kit shares the site's one copy.
Why it's its own entry
@sonordev/site-kit/client is stamped 'use client'. A function imported from a stamped module into a server component becomes a client reference there and can't be called, and getClientApiConfig is built to run during server rendering. So runtime isn't stamped, imports neither React nor Next, and works the same from a server component, a route handler or a client component.
Analytics identity reads share the same current consent state as the layout and analytics runtime, including when separate bundles load them. Pending preferences, withdrawal and expired configured policy block reads synchronously. Reading an identity never grants advertising permission or creates an id.
Stability
This entry is public API under semver. New exports arrive in minor releases; nothing in the list above is removed or changed in a minor or patch release.
Shared website utilities (8.3)
@sonordev/site-kit/shared provides withSiteParam, withSiteBody, resolveSiteHost, readPublishedSite, applyTrailingSlash, resolveTrailingSlash and safeJsonLd. These are framework-free functions for kits and sites; the entry is never marked use client. Press Kit uses them to keep sub-site scoping, URL shape and JSON-LD escaping consistent without reaching into private Site Kit files. readPublishedSite() returns the layout's explicitly published host, or undefined on the server.
sonorFetch loads its shared execution path on use and keeps its existing Promise-based API. Optional dispatch checks run again after loading and before each attempt. The same token state, refresh and auth breaker serve every caller; loading failure rejects the Promise rather than using another transport. Synchronous unload telemetry doesn't wait for that execution module.