@keystone-sites/core
v1.1.3
Published
Keystone Sites Core - server-side API client, consumer session helpers, and Next.js API route handlers for customer websites
Maintainers
Keywords
Readme
@keystone-sites/core
Backend middleware for Keystone customer websites — no UI. Supplies the typed server-side API client, consumer session helpers, server actions, CTA URL resolution, cookie-consent state (CCPA opt-out + GDPR opt-in), and Next.js API route handler factories used by every customer site (legacy or generated).
Package exports
| Import path | Contents |
|---|---|
| @keystone-sites/core | Server actions (submitContactFormAction, submitLeadFormAction), resolveCtaUrls, resolvePortalPath, isExternalCtaUrl, cookie-consent state (CCPA: hasOptedOut, getStoredChoice, setStoredChoice, clearStoredChoice, isGpcSignalActive; GDPR: getGranularChoice, getStoredGranularChoice, setStoredGranularChoice, clearStoredGranularChoice, getConsentRegime) |
| @keystone-sites/core/consent | Cookie-consent state: KS_COOKIE_CONSENT_KEY, hasOptedOut, getStoredChoice, setStoredChoice, clearStoredChoice, isGpcSignalActive, KS_GDPR_CONSENT_KEY, getGranularChoice, getStoredGranularChoice, setStoredGranularChoice, clearStoredGranularChoice |
| @keystone-sites/core/consent/region | getConsentRegime() — server-side GDPR vs. CCPA region detection |
| @keystone-sites/core/lib/server-api | All server-side data fetching functions (getCompanyInformation, getServices, getAdsConfig, getAnalyticsConfig, …) |
| @keystone-sites/core/lib/server-log | Structured server-side logging (serverLog, serverWarn, serverError) |
| @keystone-sites/core/lib/cta-urls | resolveCtaUrls, resolvePortalPath, isExternalCtaUrl |
| @keystone-sites/core/lib/consumer-session | Consumer auth cookie constant + API helpers (fetchConsumerMe, fetchConsumerConversations, fetchConsumerMessages) |
| @keystone-sites/core/lib/actions | Server actions for form submissions |
| @keystone-sites/core/next/routes/form | createFormRouteHandlers |
| @keystone-sites/core/next/routes/chat | createChatRouteHandlers |
| @keystone-sites/core/next/routes/consumer-auth | createConsumerAuthHandlers |
| @keystone-sites/core/next/routes/proxy-headers | clientContextHeaders |
| @keystone-sites/core/types | Shared TypeScript types for Keystone API responses |
Source directory structure
src/
├── consent/
│ ├── consentState.ts # Cookie-consent state (CCPA/CPRA opt-out + GDPR opt-in)
│ └── region.ts # GDPR vs. CCPA region detection (Cloudflare CF-IPCountry)
├── lib/
│ ├── server-api.ts # Server-side API fetch helpers
│ ├── server-log.ts # Structured server-side logging
│ ├── consumer-session.ts # Consumer auth cookie + API helpers
│ ├── actions.ts # Server actions for form submissions
│ └── cta-urls.ts # CTA URL resolution utilities
├── next/
│ └── routes/ # API route handler factories (form, chat, consumer-auth, proxy-headers)
└── types/
└── api/ # Keystone API response typesCookie consent (CCPA/CPRA)
hasOptedOut() is the one server-side read the rest of the platform needs: it
reads the first-party ks_cookie_consent cookie (written by
@keystone-sites/widgets' CookieConsentModal / CookiePreferencesLink via
setStoredChoice) and returns true only when the visitor previously chose
'declined'. @keystone-sites/services' KeystoneServices calls it to skip
mounting trackers for a returning visitor who already opted out — first-visit
behavior with no stored choice is unaffected. getStoredChoice /
setStoredChoice / clearStoredChoice are the client-side counterparts
(localStorage + the mirrored cookie); isGpcSignalActive detects the
browser's Global Privacy Control signal, a legally recognized automatic
opt-out under CCPA/CPRA.
Cookie consent (GDPR, EU/EEA/UK/CH)
getConsentRegime() (./consent/region) reads the CF-IPCountry header
Cloudflare attaches to every request and returns 'gdpr' or 'ccpa' — the
platform's generated sites deploy exclusively behind Cloudflare (OpenNext),
so this needs no third-party geolocation lookup. It fails closed to 'gdpr'
when the header is absent (local dev, a preview not yet behind Cloudflare).
For 'gdpr' visitors, ePrivacy Directive Art. 5(3) requires PRIOR opt-in —
the opposite of the CCPA model above — so consent is stored separately and
granularly: getGranularChoice() (server) / getStoredGranularChoice()
(client) return a { analytics, advertising } object or null if the
visitor hasn't decided yet, in the ks_gdpr_consent cookie/localStorage key
(never conflated with the CCPA ks_cookie_consent key).
setStoredGranularChoice / clearStoredGranularChoice are the client-side
writers. @keystone-sites/services' KeystoneServices mounts a GDPR
visitor's analytics/advertising trackers only once that category is
explicitly true — undecided means denied, per opt-in law, not "mount and
wait to be told to stop" like the CCPA path.
Environment variables
Both this package and customer sites use two server-side environment variables:
| Variable | Required | Default | Description |
|---|---|---|---|
| API_URL | Yes | http://localhost:3000/api/v1 | Base URL for the Keystone API |
| API_KEY | Yes | "" | Service account API key for this site |
These are read at SSR time only and never exposed to the browser. Set them in .env.local for local development.
Publishing workflow
Publish to the public npm registry in dependency order (wait for each package to propagate before publishing dependents):
# 1. @keystone-sites/core (no internal Keystone deps)
npm run test && npm publish --access public
# 2. @keystone-sites/services (depends on @keystone-sites/core)
npm run test && npm publish --access public
# 3. @keystone-sites/widgets (depends on @keystone-sites/core + @keystone-sites/services)
npm run test && npm publish --access publicprepublishOnly runs npm run build automatically before each publish.
For local development against an unpublished build, use yalc:
# In @keystone-sites/core — build and publish to local yalc store
npm run build && yalc publish
# In the customer site — link to the local build
yalc add @keystone-sites/core
# or update an existing link
yalc update @keystone-sites/coreTo restore the published npm version:
yalc remove @keystone-sites/core
npm installDocs
docs/server-api.md— server API client reference
