@conloca/content-api
@conloca/content-api is the core content engine for Conloca CMS. It reads and writes VXJSON content files, maintains
an in-memory index for fast lookups, handles optimistic concurrency via etags, and provides the FileSystemContentAPI
class that all other packages depend on.
Overview
@conloca/content-api is the core engine powering Conloca CMS. It handles file-based content storage in VXJSON format,
asset management, and provides Cloudflare Access validation helpers for Node.js integrations.
Most developers interact with this package indirectly through @conloca/astro-cms. Direct installation is needed when:
- Importing auth providers for CMS configuration
- Using the content API programmatically (scripts, tests, CI)
- Building custom tooling around Conloca content
Installation
bun add @conloca/content-api
Entry Points
@conloca/content-api (browser-safe)
Types and interfaces safe for browser environments. No Node.js dependencies.
import type { ContentAPI, ContentEntry, ContentManifest } from '@conloca/content-api';
import { Blocks, Site, ErrorCodes } from '@conloca/content-api';
| Export | Kind | Purpose |
|---|---|---|
ContentAPI | type | Main API interface for content operations |
ContentEntry | type | Full content entry with all locales |
ContentManifest | type | Manifest entry (metadata without content body) |
LocalizedEntry | type | Single-locale content entry |
SitesConfig | type | Multi-site configuration |
Blocks | class | Block collection operations* |
Site | class | Site-scoped content operations* |
ErrorCodes | const | Standard error codes (CONTENT_NOT_FOUND, STALE_WRITE, etc.) |
ContentUtils | const | Content utility functions (object with pure helper methods) |
AssetEntry | type | Asset metadata entry |
FolderListing | type | Folder contents listing |
FolderTreeNode | type | Folder tree structure |
* Blocks and Site are exported from the browser-safe entry point for type-level use only (e.g., parameter and
return types). Runtime instantiation of these classes requires the Node.js entry point (@conloca/content-api/node).
@conloca/content-api/node (Node.js only)
Node.js-specific implementations requiring filesystem access.
import {
FileSystemContentAPI,
InMemoryContentAPI,
createContentAPIRouter,
createContentMiddleware,
createContentAPI,
createContentWatchHandlers,
ComponentRegistry,
AssetManifest,
AssetOperations,
conlocaContent,
} from '@conloca/content-api/node';
Authentication Helpers
| Export | Purpose |
|---|---|
validateCFAccessRequest(request) | Validate a Cloudflare Access JWT from the incoming request |
extractCFAccessToken(request) | Read the CF Access token from request headers or cookies |
CFAccessResult | Result type returned by validateCFAccessRequest() |
CFAccessUser | User shape extracted from a validated Cloudflare Access token |
Content API Implementations
| Export | Purpose |
|---|---|
FileSystemContentAPI | Production implementation backed by filesystem + VXJSON |
InMemoryContentAPI | In-memory implementation for testing |
createContentAPIRouter(api) | Create Hono router with all content middleware routes |
createContentMiddleware(api) | Create content middleware for custom Hono apps |
createContentAPI(options) | Factory function that creates FileSystemContentAPI with content watcher |
createContentWatchHandlers(api) | File watcher for live content updates |
Other Node.js Exports
| Export | Purpose |
|---|---|
ComponentRegistry | Component registration for Puck config |
AssetManifest | Asset manifest management |
AssetOperations | Asset CRUD operations |
conlocaContent(options) | Vite plugin for content integration |
@conloca/content-api/schemas
Zod schemas for content metadata validation.
import { pageMetaSchema, blockMetaSchema, pageEditableSchema, blockEditableSchema } from '@conloca/content-api/schemas';
| Export | Purpose |
|---|---|
pageMetaSchema | Full page metadata schema (with system fields) |
pageEditableSchema | Editable page fields only (for CMS forms) |
blockMetaSchema | Full block metadata schema (with system fields) |
blockEditableSchema | Editable block fields only (for CMS forms) |
dataMetaSchema | Full data entry metadata schema (with system fields) |
dataEditableSchema | Editable data entry fields only (for CMS forms) |
Current Authentication Support
Today, @conloca/content-api exposes low-level Cloudflare Access helpers only. In the standard Astro integration, you
normally do not call these functions yourself. Instead, @conloca/astro-cms uses them automatically when these
environment variables are present:
| Variable | Description |
|---|---|
CF_ACCESS_TEAM_NAME | Zero Trust team name, used to resolve the JWKS URL |
CF_ACCESS_AUD | Access application audience (aud) to validate JWT |
When these variables are missing, validation is skipped so local development can run without Cloudflare Access.
Dev Branch Preview
The dev branch currently adds a fuller auth surface to @conloca/content-api/node, including:
| Export | Purpose |
|---|---|
apiKey() | Bearer-token API key authentication |
oauth() | GitHub or Google OAuth with signed session cookies |
noAuth() | Explicit development-mode provider |
AuthConfig | provider, roles, and resolveRole configuration |
AuthProvider | Shared provider interface with validate() and optional logout |
Treat that API as preview material until it lands on the branch you are deploying from.
Examples
Programmatic Content Access
import { createContentAPI } from '@conloca/content-api/node';
const api = await createContentAPI({ contentRoot: './content' });
// List pages for a site (listPages is a generator)
const pages = Array.from(api.getSite('default')!.listPages('en'));
// Get a specific block (synchronous)
const block = api.blocks.getByName('shared', 'header', 'en');
Testing with InMemoryContentAPI
import { InMemoryContentAPI, createContentAPIRouter } from '@conloca/content-api/node';
const api = new InMemoryContentAPI({
sites: { default: { locales: ['en', 'de'], defaultLocale: 'en' } },
globalLocales: ['en', 'de'],
});
const router = createContentAPIRouter(api);
const response = await router.fetch(new Request('http://test/default/pages'));