Skip to main content

Shared CMS SDK

TypeScript SDK for interfacing with the Strapi CMS.

Installation

The package is included in the workspace. Add it to your project's dependencies:

{
"dependencies": {
"shared-cms": "workspace:*"
}
}

Quick Start

Creating a Client

import { createCmsClient } from "shared-cms";

const cms = createCmsClient({
baseUrl: "http://localhost:1337",
apiToken: "your-api-token",
});

Configuration Options

OptionTypeRequiredDescription
baseUrlstringYesBase URL of the Strapi instance
apiTokenstringNoAPI token for authentication
timeoutnumberNoRequest timeout in milliseconds (default: 30000)
headersobjectNoCustom headers for all requests

API Reference

Finding Entries

findMany(contentType, params?)

Find multiple entries of a content type.

// Basic query
const articles = await cms.findMany("articles");

// With filters
const publishedArticles = await cms.findMany("articles", {
filters: {
publishedAt: { $notNull: true },
},
});

// With pagination
const paginatedArticles = await cms.findMany("articles", {
pagination: {
page: 1,
pageSize: 10,
},
});

// With sorting
const sortedArticles = await cms.findMany("articles", {
sort: ["createdAt:desc"],
});

// With population
const articlesWithAuthor = await cms.findMany("articles", {
populate: ["author", "category"],
});

// Deep population
const articlesWithNestedData = await cms.findMany("articles", {
populate: {
author: {
populate: ["avatar"],
},
category: true,
},
});

findOne(contentType, documentId, params?)

Find a single entry by document ID.

const article = await cms.findOne("articles", "abc123", {
populate: ["author", "category"],
});

if (article.data) {
console.log(article.data.title);
}

Creating Entries

create(contentType, params)

Create a new entry.

const newArticle = await cms.create("articles", {
data: {
title: "Hello World",
content: "This is my first article.",
author: authorId,
},
});

console.log(newArticle.data?.documentId);

Updating Entries

update(contentType, documentId, params)

Update an existing entry.

const updatedArticle = await cms.update("articles", "abc123", {
data: {
title: "Updated Title",
},
});

Deleting Entries

delete(contentType, documentId)

Delete an entry.

await cms.delete("articles", "abc123");

Content Types

listContentTypes()

List all available content types.

const contentTypes = await cms.listContentTypes();

for (const ct of contentTypes) {
console.log(`${ct.displayName} (${ct.uid})`);
}

getContentType(uid)

Get detailed information about a content type.

const articleType = await cms.getContentType("api::article.article");

if (articleType) {
console.log("Attributes:", Object.keys(articleType.schema.attributes));
}

File Upload

upload(file, info)

Upload a file to the media library.

const file = new Blob(["Hello World"], { type: "text/plain" });
const media = await cms.upload(file, { name: "hello.txt" });

console.log("Uploaded:", media.url);

Health Check

healthCheck()

Check if the CMS is accessible.

const isHealthy = await cms.healthCheck();
console.log(isHealthy ? "CMS is up" : "CMS is down");

Filter Operators

The SDK supports all Strapi filter operators:

OperatorDescription
$eqEqual
$neNot equal
$ltLess than
$lteLess than or equal
$gtGreater than
$gteGreater than or equal
$inIn array
$notInNot in array
$containsContains (case-sensitive)
$containsiContains (case-insensitive)
$nullIs null
$notNullIs not null
$betweenBetween two values
$startsWithStarts with
$endsWithEnds with
$orOR condition
$andAND condition

Filter Examples

// Equal
await cms.findMany("articles", {
filters: { status: "published" },
});

// Not equal
await cms.findMany("articles", {
filters: { status: { $ne: "draft" } },
});

// Contains
await cms.findMany("articles", {
filters: { title: { $containsi: "typescript" } },
});

// In array
await cms.findMany("articles", {
filters: { category: { $in: ["tech", "programming"] } },
});

// OR condition
await cms.findMany("articles", {
filters: {
$or: [{ status: "published" }, { featured: true }],
},
});

// Nested filters
await cms.findMany("articles", {
filters: {
author: {
name: { $eq: "John" },
},
},
});

CLI Usage

The package includes a CLI for quick operations.

Environment Variables

VariableDescription
CMS_URLCMS base URL (default: http://localhost:1337)
CMS_API_TOKENAPI token for authentication

Commands

# Check CMS health
cms-cli health

# List content types
cms-cli content-types
cms-cli content-types --json

# Find entries
cms-cli find articles
cms-cli find articles --limit 10 --page 2
cms-cli find articles --sort "createdAt:desc"
cms-cli find articles --populate "author,category"
cms-cli find articles --json

# Get single entry
cms-cli get articles abc123
cms-cli get articles abc123 --populate "*"

# Export entries
cms-cli export articles
cms-cli export articles --output articles.json
cms-cli export articles --limit 50 --populate "*"

# Get content type info
cms-cli info api::article.article

Error Handling

The SDK throws typed errors for failed requests:

import { CmsError } from "shared-cms";

try {
await cms.findOne("articles", "invalid-id");
} catch (error) {
const cmsError = error as CmsError;
console.error(`Error: ${cmsError.name} - ${cmsError.message}`);
console.error(`Status: ${cmsError.status}`);
}

TypeScript Support

The SDK is fully typed. You can define your content types:

import { CmsEntry, createCmsClient } from "shared-cms";

interface Article extends CmsEntry {
title: string;
content: string;
author?: {
id: number;
name: string;
};
}

const cms = createCmsClient({ baseUrl: "..." });

// Typed response
const { data } = await cms.findMany<Article>("articles");

if (data) {
for (const article of data) {
console.log(article.title); // TypeScript knows this is a string
}
}