@krios/sdk
TypeScript client for the Krios delivery + management APIs. ESM, zero runtime deps, runs anywhere fetch is available.
Install
pnpm add @krios/sdk
Configure
import { KriosClient } from "@krios/sdk";
const krios = new KriosClient({
endpoint: "https://cms.example.com",
projectSlug: "demo",
apiKey: process.env.KRIOS_DELIVERY_KEY!,
locale: "en-US",
preview: false,
});
| Option | Notes |
|---|---|
endpoint | Base URL of the CMS deployment. |
projectSlug | The project to read from. |
apiKey | Bearer key (delivery / preview / management). |
locale | Default locale for reads. Override per call. |
preview | When true, requests drafts and sends an x-krios-preview: 1 request header. (The data-krios-* attributes used by the preview overlay are emitted by @krios/react's KriosRichText, not the SDK.) |
Reading entries
const entry = await krios.getEntry("ckl_…", { locale: "fr-CA" });
const list = await krios.getEntries("articlePage", { page: 1, limit: 25 }); // { items, total, page, limit }
const bySlug = await krios.getEntryBySlug("hello-world", "main");
getEntry returns the full entry including resolved field values for the active locale. Reference / blocks fields are returned as { _ref, _type } placeholders by default; pass { include: 1 } to expand them inline.
Resolving routes
The single most useful method for frontends:
const result = await krios.resolveRoute("main", "/about/team");
switch (result.kind) {
case "entry": return render(result.entry);
case "redirect": return Response.redirect(result.target, result.status);
case "not_found": return notFound();
}
resolveRoute honors plain redirects + regex redirects + the auto-redirect-on-slug-change behavior described in Routing.
Writing (management keys only)
const krios = new KriosClient({
endpoint: "https://cms.example.com",
projectSlug: "demo",
apiKey: process.env.KRIOS_MANAGEMENT_KEY!, // server-only — never ship to client
});
const created = await krios.createEntry({
contentTypeApiName: "blogPost",
siteId: "site_main",
locale: "en-US",
treeParentId: "node_blog",
slug: "hello-world",
fields: { title: "Hello World", body: { type: "doc", content: [...] } },
});
await krios.updateEntry(created._id, {
version: 1, // the version you are updating from (optimistic concurrency)
locale: "en-US",
fields: { title: "Hello, World!" },
});
await krios.publishEntry(created._id, "en-US");
The SDK throws typed KriosError instances on 4xx / 5xx (with subclasses NotFoundError, ConflictError, ValidationError, AuthError, RateLimitError); catch and inspect err.code for the stable error code (version_conflict, field_permission_denied, etc.).
Retry behavior
429 responses trigger an exponential backoff retry honoring the Retry-After header. Retry is not configurable: it is fixed at 3 attempts with exponential backoff (~1s / 2s / 4s).
Type generation
For full type-safety on field reads, generate per-project interfaces:
krios types generate --output ./src/krios.types.ts
import type { ArticlePage } from "./krios.types";
const article = (await krios.getEntry("ckl_…")) as ArticlePage;
article.fields.body; // typed as the rich-text projection shape