@stormycms/core
Framework-agnostic client, types, and utilities for talking to the StormyCMS API. Everything else (react, next) builds on this package.
pnpm add @stormycms/coreStormyCMSClient
The typed client. By default it reads configuration from environment variables:
import { StormyCMSClient } from '@stormycms/core';
// Uses STORMY_CMS_CLIENT_ID, STORMY_CMS_CLIENT_SECRET, NEXT_PUBLIC_SITE_URLconst client = new StormyCMSClient();
// Or configure explicitly:const client2 = new StormyCMSClient({ siteUrl: 'https://example.com', clientId: process.env.STORMY_CMS_CLIENT_ID!, clientSecret: process.env.STORMY_CMS_CLIENT_SECRET!, callbackUrl: 'https://admin.example.com/api/auth/stormy', // optional OAuth callback});The constructor throws if credentials are missing, so misconfiguration fails fast at startup.
Content methods (site credentials)
| Method | Returns | Notes |
|---|---|---|
getPages({ limit?, offset? }) | GqlPage[] | Defaults: limit 20, offset 0 |
getPage({ id }) | GqlPage | Throws if not found |
getPageBySlug({ slug }) | GqlPage | null | Returns null when missing — use for 404s |
getLayouts() | GqlLayout[] | |
getLayout({ id }) | GqlLayout | |
getCurrentSite() | SiteData | The site your credentials identify |
Editor methods (require a JWT)
These take a jwt as the first argument:
| Method | Notes |
|---|---|
createPage(jwt, { slug, metadata, components, layoutId, createdAt, updatedAt }) | |
updatePage(jwt, { id, slug, metadata, components, layoutId, updatedAt }) | Replaces the component tree |
deletePage(jwt, { id }) | |
createLayout(jwt, { name, components, createdAt, updatedAt }) | |
updateLayout(jwt, { id, name, components, parentLayoutId?, updatedAt }) | |
deleteLayout(jwt, { id }) | |
getMediaItems(jwt, { limit?, offset? }) / getMedia(jwt, id) | |
createMedia(jwt, { type, url, name, metadata }) | Record an uploaded file |
updateMedia(jwt, { id, ... }) / deleteMedia(jwt, { id }) | |
updateUser(jwt, { id, username?, displayName?, email?, ... }) |
Auth & session methods
| Method | Purpose |
|---|---|
signIn(provider?, options?, hooks?) / signUp(...) | Build the OAuth redirect to the Stormy auth service (github or google). Framework-agnostic via redirect/setCookie hooks. |
exchangeTokenForJWT(code) | Exchange an OAuth auth code for a session token + user |
mintJwt(sessionToken) | Mint a short-lived JWT ({ jwt, expiresIn }) |
getJWTToken(cookieHeader?) | Convenience: parse the stormy_session_token cookie and mint a JWT; returns null when signed out |
getSession(sessionToken?, cookieHeader?) | { user, jwt } for the current session (never throws) |
getUser(cookieHeader, userId?) | The signed-in user (or another visible user) |
Site & team methods (session-authenticated)
getSites, getSite, updateSite, resetClientId, resetClientSecret, getSiteWithUsers, inviteUser, resendInvite. Most teams manage sites and members through the account portal; these exist for programmatic workflows.
Escape hatch: raw GraphQL
const result = await client.graphql<MyResult>( `query { getCurrentSite { id name } }`, undefined, // variables cookieHeader, // optional: authenticates as the session user);// result: { data, errors, message? } — errors normalized to { code, message }Data Mapping Helpers
The GraphQL API represents props and attrs as name/value pairs. The map helpers convert to ergonomic shapes used by the React renderer and editor:
| Function | Converts |
|---|---|
mapPageData(gqlPage) | GqlPage → CMSPageData (props become plain records, metadata normalized) |
mapLayoutData(gqlLayout) | GqlLayout → CMSLayoutData |
mapComponentDataToInput(data) | CMSComponentData → componentInput for mutations |
ImageAsset
image fields use the ImageAsset type:
type ImageAsset = { src: string; alt?: string; mediaId?: string; name?: string; tags?: string[];};The boilerplate admin's media picker stores the public URL as src, the media record ID as mediaId, and any alt text/tags as alt/tags so components can render them directly or look up the full media record later.
Storage Helpers (S3)
Utilities for media storage against any S3-compatible service, used by the boilerplate admin's media routes:
uploadToS3(...),deleteFromS3(key, config),listObjects(...)getPresignedUploadUrl(...),getPresignedDownloadUrl(...)S3StorageClient— class wrapper over the same operations- Types:
S3Config,UploadResult
Configure via S3_ENDPOINT, S3_BUCKET, S3_ACCESS_KEY_ID, S3_SECRET_ACCESS_KEY, S3_REGION.
Types
Two families of types are exported:
Gql*— raw GraphQL shapes:GqlPage,GqlLayout,GqlComponent,GqlMetadata, plus inputs (GqlComponentInput,GqlMetadataInput) and response/param typesCMS*— editor/renderer-friendly shapes:CMSPageData,CMSLayoutData,CMSComponentData,CMSField,CMSFieldType,CMSFieldValue
Plus SessionUser, SiteData, Site, SiteWithUsers, User, MediaItem, ImageAsset, and type guards (isImageValue, isImageField, isCheckboxField, isInputField, isStringArray, ...).
See Components & Schema for how CMSField drives the editor UI.
Last updated: 7/9/26, 6:42 AM