@conapps/cms-sdk
v0.1.0
Published
TypeScript SDK for the platform Content Delivery API. Works in browsers, Node, Nuxt and Vue.
Maintainers
Readme
@conapps/cms-sdk
Typed client for the platform's Content Delivery API
(/delivery/v1/spaces/:workspaceId/...). Runs in browsers, Node 18+, Nuxt
(SSR + client) and Vue.
Install
npm install @conapps/cms-sdk
# Vue/Nuxt integration is optional:
npm install vueQuick start
import { createCmsClient } from '@conapps/cms-sdk';
const cms = createCmsClient({
endpoint: 'https://cms.example.com',
workspaceId: 'ws_123',
token: process.env.CMS_DELIVERY_TOKEN!, // Keycloak-issued JWT
environment: 'master', // default: "master"
defaultLocale: 'de-DE',
assetBaseUrl: 'https://cdn.example.com/assets', // optional
});
const posts = await cms.getEntries({ contentType: 'blogPost', take: 10 });
const post = await cms.getEntry('abc123', { include: 2 });
const asset = await cms.getAsset('xyz789');Authentication
The Delivery API expects a Keycloak-issued bearer token whose workspace_id
claim matches the requested space and whose scope contains
content-management:read. Provision the token in the platform UI under
Settings → Content → Delivery Tokens.
API
new CmsClient(opts) / createCmsClient(opts)
| Option | Type | Description |
|---|---|---|
| endpoint | string | Base URL of the CMS service. Required. |
| workspaceId | string | Workspace ("space") id. Required. |
| token | string | Delivery JWT. Required. |
| environment | string | Default "master". |
| defaultLocale | string | Used when a call omits locale. |
| assetBaseUrl | string | If set, Asset.url is filled with ${assetBaseUrl}/${storageKey}. |
| fetch | typeof fetch | Custom fetch (e.g. Nuxt's $fetch, undici). |
| cacheTtlMs | number | In-memory GET cache TTL. Default 0 (disabled). |
Methods
client.getContentTypes(): Promise<Collection<ContentType>>;
client.getEntries<TFields>(query?: EntriesQuery): Promise<Collection<Entry<TFields>>>;
client.getEntry<TFields>(id: string, query?: EntryQuery): Promise<Entry<TFields> | null>;
client.getEntryBy<TFields>(contentType, field, value, query?): Promise<Entry<TFields> | null>;
client.getAsset(id: string): Promise<Asset | null>;
client.clearCache(): void;include: number resolves linked entries / assets up to that depth — the SDK
fetches each id once and inlines the resolved object back into the field.
Typed fields
Pass a generic to your entry shape for full type safety on entry.fields:
interface BlogPost {
title: string;
slug: string;
body: string;
coverImage?: { id: string; url?: string; fileName: string };
}
const post = await cms.getEntry<BlogPost>('abc123', { include: 1 });
post?.fields.title; // stringErrors
import { CmsError, CmsAuthError, CmsNotFoundError } from '@conapps/cms-sdk';CmsAuthError is thrown on 401/403, CmsNotFoundError on 404, and
CmsError on any other non-2xx.
Vue / Nuxt
// main.ts (Vue) or plugins/cms.client.ts (Nuxt)
import { createCmsClient } from '@conapps/cms-sdk';
import { cmsPlugin } from '@conapps/cms-sdk/vue';
app.use(cmsPlugin, createCmsClient({ endpoint, workspaceId, token }));<script setup lang="ts">
import { useEntries } from '@conapps/cms-sdk/vue';
const { data, pending, error } = useEntries({ contentType: 'blogPost', take: 5 });
</script>For Nuxt, pass $fetch so SSR uses the server's fetch implementation:
// plugins/cms.ts
export default defineNuxtPlugin((nuxt) => {
const { public: cfg } = useRuntimeConfig();
nuxt.vueApp.use(cmsPlugin, createCmsClient({
endpoint: cfg.cmsEndpoint,
workspaceId: cfg.cmsWorkspaceId,
token: cfg.cmsToken,
fetch: $fetch as unknown as typeof fetch,
}));
});A complete working example lives under
../examples/nuxt-demo.
Build & test
npm install
npm run build # tsup → dist/{index,vue}.{js,cjs,d.ts}
npm test # vitest — 46 unit tests
npx vitest run --coverage # ≥ 98% line coverage on src/The suite covers the HTTP client (URL composition, locale defaulting, paging,
encoding, all error mappings, in-memory cache TTL + invalidation, asset URL
decoration, single-level + array + recursive link resolution, broken-link
tolerance) and every Vue composable (plugin injection, eager fetch, reactive
re-fetch when refs change, error capture, manual refresh()).
