Trellis CMS
Read schema-aware TrellisDB collections from websites, apps, and agents with the trellis/cms SDK.
Trellis CMS
The trellis/cms package is the collection-oriented SDK for TrellisDB. It reads entries from a Trellis-compatible HTTP store and turns graph facts, links, schemas, references, and formula fields into app-friendly collection data.
Use it when you want a website, dashboard, documentation site, or app to consume content managed in TurtleCode/Trellis without exporting static JSON.
Install
npm install trellis@^3.1.6
Create a Client
import { createCmsClient } from "trellis/cms";
const cms = createCmsClient({
url: "http://localhost:4096",
directory: "/absolute/path/to/project",
});
directory is optional for single-project servers, but multi-project backends use it to route requests to the correct Trellis store.
List Collections
const collections = await cms.collections();
Collections include explicit CMS schemas and inferred collections discovered from non-system entity types.
type Collection = {
key: string;
label: string;
inferred: boolean;
count: number;
};
Read Entries
type BlogPostFields = {
title?: string;
slug?: string;
body?: string;
author?: string;
totalReadTime?: number;
};
const posts = await cms.collection<BlogPostFields>("blog_post").list({
status: "published",
expand: ["author"],
limit: 20,
});
list() defaults to status: "published". Pass status: "all" to include drafts.
const post = await cms.collection<BlogPostFields>("blog_post").get("blog_post:hello-world", {
expand: ["author"],
});
const samePost = await cms.entry<BlogPostFields>("blog_post:hello-world").get({
expand: ["author"],
});
Subscribe to Updates
Subscriptions currently use shared polling. Multiple subscribers to the same collection and options share one timer and one HTTP request per poll cycle.
const off = cms.collection<BlogPostFields>("blog_post").subscribe(
(entries) => {
console.log("Published posts changed:", entries);
},
{
status: "published",
expand: ["author"],
onError: console.error,
}
);
off();
You can tune polling with pollIntervalMs on the client. The minimum interval is 500ms and the default is 2000ms.
Formula Fields
Formula fields are virtual fields defined in a collection schema. They are evaluated by the SDK when entries are returned from list(), get(), and subscriptions, so consumers see computed values without persisting them as facts.
import type { FieldDefinition } from "trellis/cms";
const fields: FieldDefinition[] = [
{ key: "price", type: "number" },
{ key: "quantity", type: "number" },
{ key: "subtotal", type: "formula", formula: "{price} * {quantity}" },
{ key: "tax", type: "formula", formula: "{subtotal} * 0.0825" },
{ key: "total", type: "formula", formula: "{subtotal} + {tax}" },
];
The formula evaluator supports numeric field references with {field_key}, parentheses, unary + and -, and arithmetic operators +, -, *, and /. Missing or non-numeric inputs produce undefined.
You can also use the helper functions directly:
import { evaluateFormula } from "trellis/cms";
const total = evaluateFormula("{price} * {quantity}", {
price: 12,
quantity: 3,
});
Field Types
type FieldKind =
| "text"
| "rich_text"
| "number"
| "boolean"
| "date"
| "email"
| "url"
| "color"
| "select"
| "multiselect"
| "file"
| "formula"
| "reference"
| "image";
References are stored as entity IDs until expanded. Image and file fields are represented as string values, usually URLs or local paths.
Scaffold Consumer Code
Agents and tooling can generate starter integration files with the scaffold helpers:
import { scaffoldConsumer, scaffoldFilename } from "trellis/cms";
const opts = {
collection: "blog_post",
framework: "react" as const,
expand: ["author"],
directory: "/absolute/path/to/project",
};
const filename = scaffoldFilename(opts);
const source = scaffoldConsumer(opts);
Supported scaffold frameworks are vanilla, react, solid, and vue.
Client Options
| Option | Description |
|---|---|
url | Base URL of the Trellis-compatible HTTP server. |
basePath | Store route prefix. Defaults to /trellis/store. |
directory | Project directory for multi-instance backends. |
pollIntervalMs | Subscription polling interval. Defaults to 2000; minimum is 500. |
fetch | Custom fetch implementation for SSR or older runtimes. |
apiKey | Optional bearer token for authenticated routes. |