Relocate the ~6k-file docs tree from the repo root into plugins/document-navigator/docs/ so the plugin is self-contained and portable. docs/superpowers/ (specs and plans) stays at the repo root. Moved via cp+rm rather than git mv because directory rename() fails with EPERM on this WSL /mnt DrvFs mount; git rename-detection pairs the identical-content files at commit time. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@suaveplan/api-plugin-cms - Headless CMS primitives for @suaveplan/api: in-memory CmsEngine over @suaveplan/events with content models, entries, status lifecycle, version history, slug uniqueness, Zod-validated plugin options, RFC 7807 problem+json renderer, and an OTel instrument bundle. Server-tier — Bun + Node.
Headless content-management primitives for @suaveplan/api. Ships an
in-memory CmsEngine that manages flexible content models, content
entries with a draft → review → published → archived status
lifecycle, slug uniqueness within a model, and a per-entry version
trail. The package factory wraps the engine in a typed
PluginDescriptor consumable by @suaveplan/api-plugin's
PluginRegistry; the engine is exposed under the cms slot of the
host ServiceRegistry.
Documentation tree
- engine —
CmsEngineis the headless content-management core for@suaveplan/api-plugin-cms. It manages flexible content models…- cms-engine —
CmsEngineis the headless content-management core for@suaveplan/api-plugin-cms. It manages flexible content models…
- cms-engine —
- error-codes — This module owns the stable error-code namespace
CMS.*for the package and the concreteCmsErrorclass that consume…- error-codes — This module owns the stable error-code namespace
CMS.*for the package and the concreteCmsErrorclass that consume…
- error-codes — This module owns the stable error-code namespace
- otel — The package emits seven OpenTelemetry counters on every production mutation so operators can dashboard CMS activity and…
- instruments — The package emits seven OpenTelemetry counters on every production mutation so operators can dashboard CMS activity and…
- plugin — Wraps
CmsEnginein a typedPluginDescriptorconsumable by@suaveplan/api-plugin'sPluginRegistry. The factory m…- plugin — Wraps
CmsEnginein a typedPluginDescriptorconsumable by@suaveplan/api-plugin'sPluginRegistry. The factory m…
- plugin — Wraps
- routes — Render
CmsError(and arbitrary throwables) as RFC 7807 problem+json HTTP responses without requiring `@suaveplan/api-…- problem-json — Render
CmsError(and arbitrary throwables) as RFC 7807 problem+json HTTP responses without requiring `@suaveplan/api-…
- problem-json — Render
- schemas — Zod schema validating the
CmsPluginOptionsbundle accepted bycreateCmsPlugin(...). Boundary validation at the plug…- options — Zod schema validating the
CmsPluginOptionsbundle accepted bycreateCmsPlugin(...). Boundary validation at the plug…
- options — Zod schema validating the
- services — Declares the
cmsslot on the@suaveplan/api-plugin/service-registry'sServiceRegistryinterface via TypeScript mo…- registry-augmentation — Declares the
cmsslot on the@suaveplan/api-plugin/service-registry'sServiceRegistryinterface via TypeScript mo…
- registry-augmentation — Declares the
Install
bun add @suaveplan/api-plugin-cms
Quick start
import { createCmsPlugin } from "@suaveplan/api-plugin-cms";
import { createPluginRegistry } from "@suaveplan/api-plugin";
const registry = createPluginRegistry();
registry.register(createCmsPlugin({}));
await registry.initAll();
const cms = registry.context("cms").getService("cms");
const model = cms?.createModel({
name: "Blog post",
slug: "post",
contentType: "post",
fields: [
{ name: "title", type: "text", label: "Title", required: true },
{ name: "body", type: "richtext", label: "Body" },
],
});
const entry = cms?.createContent({
modelId: model!.id,
title: "Hello world",
data: { title: "Hello world", body: "Welcome." },
});
cms?.transitionStatus(entry!.id, "published");
Rendering errors as RFC 7807 problem+json
Use respondProblemJson(res, err) from your route's error handler.
The renderer maps every CMS.* code to the documented HTTP status
(404 / 400 / 409 / 500).
import { respondProblemJson } from "@suaveplan/api-plugin-cms";
app.onError((err, c) => respondProblemJson(c, err));
Modules
engine/cms-engine—CmsEnginecore (model + content CRUD, status FSM, versions).error-codes/error-codes—CMS_CODES,CmsError, factory helpers.otel/instruments— OpenTelemetry counters.plugin/plugin—createCmsPluginfactory.routes/problem-json— RFC 7807 renderer.schemas/options—CmsPluginOptionsSchema.services/registry-augmentation—ServiceRegistryaugmentation for thecmsslot.
License
MIT — © Suaveplan Team