first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,97 @@
# @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`.
<!-- begin:auto-docs -->
## Documentation tree
- [engine](./src/engine/cms-engine.md) — `CmsEngine` is the headless content-management core for `@suaveplan/api-plugin-cms`. It manages flexible content models…
- [cms-engine](./src/engine/cms-engine.md) — `CmsEngine` is the headless content-management core for `@suaveplan/api-plugin-cms`. It manages flexible content models…
- [error-codes](./src/error-codes/error-codes.md) — This module owns the stable error-code namespace `CMS.*` for the package and the concrete `CmsError` class that consume…
- [error-codes](./src/error-codes/error-codes.md) — This module owns the stable error-code namespace `CMS.*` for the package and the concrete `CmsError` class that consume…
- [otel](./src/otel/instruments.md) — The package emits seven OpenTelemetry counters on every production mutation so operators can dashboard CMS activity and…
- [instruments](./src/otel/instruments.md) — The package emits seven OpenTelemetry counters on every production mutation so operators can dashboard CMS activity and…
- [plugin](./src/plugin/plugin.md) — Wraps `CmsEngine` in a typed `PluginDescriptor` consumable by `@suaveplan/api-plugin`'s `PluginRegistry`. The factory m…
- [plugin](./src/plugin/plugin.md) — Wraps `CmsEngine` in a typed `PluginDescriptor` consumable by `@suaveplan/api-plugin`'s `PluginRegistry`. The factory m…
- [routes](./src/routes/problem-json.md) — Render `CmsError` (and arbitrary throwables) as RFC 7807 problem+json HTTP responses without requiring `@suaveplan/api-…
- [problem-json](./src/routes/problem-json.md) — Render `CmsError` (and arbitrary throwables) as RFC 7807 problem+json HTTP responses without requiring `@suaveplan/api-…
- [schemas](./src/schemas/options.md) — Zod schema validating the `CmsPluginOptions` bundle accepted by `createCmsPlugin(...)`. Boundary validation at the plug…
- [options](./src/schemas/options.md) — Zod schema validating the `CmsPluginOptions` bundle accepted by `createCmsPlugin(...)`. Boundary validation at the plug…
- [services](./src/services/registry-augmentation.md) — Declares the `cms` slot on the `@suaveplan/api-plugin/service-registry`'s `ServiceRegistry` interface via TypeScript mo…
- [registry-augmentation](./src/services/registry-augmentation.md) — Declares the `cms` slot on the `@suaveplan/api-plugin/service-registry`'s `ServiceRegistry` interface via TypeScript mo…
<!-- end:auto-docs -->
## Install
```bash
bun add @suaveplan/api-plugin-cms
```
## Quick start
```ts
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).
```ts
import { respondProblemJson } from "@suaveplan/api-plugin-cms";
app.onError((err, c) => respondProblemJson(c, err));
```
## Modules
- [`engine/cms-engine`](./src/engine/cms-engine.md) — `CmsEngine`
core (model + content CRUD, status FSM, versions).
- [`error-codes/error-codes`](./src/error-codes/error-codes.md) —
`CMS_CODES`, `CmsError`, factory helpers.
- [`otel/instruments`](./src/otel/instruments.md) — OpenTelemetry
counters.
- [`plugin/plugin`](./src/plugin/plugin.md) — `createCmsPlugin`
factory.
- [`routes/problem-json`](./src/routes/problem-json.md) — RFC 7807
renderer.
- [`schemas/options`](./src/schemas/options.md) —
`CmsPluginOptionsSchema`.
- [`services/registry-augmentation`](./src/services/registry-augmentation.md)
— `ServiceRegistry` augmentation for the `cms` slot.
## License
MIT — © Suaveplan Team