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
| Option | Type | Required | Description |
|---|---|---|---|
baseUrl | string | Yes | Base URL of the Strapi instance |
apiToken | string | No | API token for authentication |
timeout | number | No | Request timeout in milliseconds (default: 30000) |
headers | object | No | Custom 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:
| Operator | Description |
|---|---|
$eq | Equal |
$ne | Not equal |
$lt | Less than |
$lte | Less than or equal |
$gt | Greater than |
$gte | Greater than or equal |
$in | In array |
$notIn | Not in array |
$contains | Contains (case-sensitive) |
$containsi | Contains (case-insensitive) |
$null | Is null |
$notNull | Is not null |
$between | Between two values |
$startsWith | Starts with |
$endsWith | Ends with |
$or | OR condition |
$and | AND 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
| Variable | Description |
|---|---|
CMS_URL | CMS base URL (default: http://localhost:1337) |
CMS_API_TOKEN | API 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
}
}