Ecosystem ↗

@zenixjs/core

Minimal authorized CMS domain core, SQLite persistence and explicit limits.

↗ View Markdown

Implemented domain core#

@zenixjs/core/cms exposes an opt-in Node-only createCms over the existing SQLite connector. Root version and legacy status metadata remain compatible; new capabilities describes the minimal implemented scope. The separate zenixjs/application entry supplies initial host-configured SSR UI; the separate creator emits a host-configured SQLite integration scaffold. This core mounts no admin routes.

The core provides tenant/site-authorized sites, immutable content type versions, drafts, optimistic entry heads, immutable revision references, publication pointers and restore-to-new-draft. Auth-owned verified principals/permissions and explicit files media ownership/version/hash checks remain host integrations. Role names or client JSON never authenticate a caller.

Persistence and lifecycle#

Explicit migrate:true initializes schema v1 and its checksum journal on one native synchronous SQLite transaction. Head changes and revision inserts are also atomic; stale revisions conflict. Other adapters and async transaction parity are not claimed. Use a private file-backed database; without migration approval startup verifies the existing schema. The package README defines the journal and publication semantics.

Plugins are explicit trusted setup code with generation-owned cleanup. Startup resource rollback does not undo already committed plugin writes. Await close to abort/drain callbacks, dispose resources and close only the owned connector.

Public imports#

js
import {version, status, capabilities} from '@zenixjs/core';
import {createCms, cmsRolePermissions} from '@zenixjs/core/cms';

The package's examples/cms.ts shows private dependency injection and a minimal draft/publication flow. Host session proof, Origin/CSRF policy, media providers and private rendering remain explicit. Native SQLite fixtures check file-backed reopen, rollback, revision conflicts and denied sites; no browser/admin/provider qualification or complete CMS behavior is implied.

Public entry points

Manifest reference for @zenixjs/core@0.0.4. Each target describes a published entry, not automatic framework registration.

ImportTarget
@zenixjs/core
{
  "types": "./dist/index.d.ts",
  "import": "./dist/index.js",
  "default": "./dist/index.js"
}
@zenixjs/core/cms
{
  "types": "./dist/cms.d.ts",
  "browser": null,
  "import": "./dist/cms.js"
}
@zenixjs/core/types
{
  "types": "./dist/types.d.ts",
  "browser": null,
  "import": "./dist/types.js"
}
Runtime requirements and dependencies
{
  "engines": {},
  "dependencies": {
    "@zeruxjs/auth": "0.0.4",
    "@zeruxjs/db": "0.0.4",
    "@zeruxjs/db-sqlite": "0.0.4",
    "@zeruxjs/files": "0.0.4"
  },
  "peerDependencies": {},
  "bin": {}
}
Full package README

@zenixjs/core#

Minimal opt-in CMS domain core with one file-backed SQLite adapter. There are no admin routes, dashboard, project generator, authentication UI or implicit plugins. The separate zenixjs/application entry supplies an initial host-configured SSR UI; this domain package itself mounts no admin routes.

Public surface#

Root imports retain version = "0.0.4" and legacy status = "placeholder" for compatibility. New capabilities reports implemented scope; use the Node-only @zenixjs/core/cms entry for createCms, CmsError, role policy data and domain types. @zenixjs/core/types exposes package-owned types/role data. Root import opens no database and does not initialize the CMS dependencies.

js
import {createCms} from '@zenixjs/core/cms';
const cms = await createCms({
  adapter: 'sqlite', filename: '/private/app/content.sqlite', migrate: true,
  resolvePrincipal: authenticateServerSession,
  authorizeMedia: verifyFilesOwnershipVersionAndHash,
});
try {
  const current = await cms.readEntry({tenant:'tenantA',site:'siteA'}, 'welcome', serverSession);
} finally { await cms.close(); }

Callbacks and session variables above are host-owned, not bundled defaults. See the public-import example for explicit schema/draft/publication calls. No HTTP endpoint or zerux.config option is mounted automatically.

Capability Implemented behavior
Sites Create/read, fixed tenant and site scope; names are inert content
Content types Immutable numbered schemas; text, finite number, boolean and versioned media-reference fields
Entries Create draft, optimistic head updates, authorized reads
Revisions Immutable tenant/site/entry/revision references, actor/time and restore provenance
Publication Publishing creates a new immutable revision and advances a separate published pointer
Adapter SQLite file only through @zeruxjs/db-sqlite native synchronous transactions
Plugins Explicit trusted setup callbacks and LIFO async disposal; no package scanning
Not implemented Admin/router, anonymous delivery, localization, relations, nested rich text, search, deletion, unpublish, arbitrary migrations or other DB adapters

Authentication, permissions and media#

The host resolvePrincipal must verify a fresh authenticated/unexpired session and return the existing auth-owned TenantPrincipal. hasTenantPermission enforces exact tenant, permission and site allowlist on every operation. Omitted siteIds deny access; role strings, email, caller-supplied principal JSON and forwarding headers are never authentication. cmsRolePermissions is convenience policy data for hosts to grant through verified sessions, not an automatic role-to-privilege conversion. Site creation needs a preauthorized site ID, not a self-granted administrator.

Permissions are cms:read, cms:site-manage, cms:type-manage, cms:write, and cms:publish. All reads, including readPublished, are authorized private reads. Host routes remain responsible for CSRF/origin controls and cache/privacy policy. Auth persistence/session rotation remains in @zeruxjs/auth; CMS neither stores passwords nor implements a second session system.

Media references use files-owned storage/bucket/key addressing with an immutable version ID and lowercase SHA-256. Files validates addresses; a required authorizeMedia callback checks actual tenant ownership, storage permissions, version availability and hash before saving/publishing/restoring a reference. It must use configured files providers, never fetch a caller URL. Failed checks commit no entry/revision. References borrow bytes; CMS never uploads/deletes files, signs URLs, copies credentials or grants binary access. Host download handlers still run files authorization. The example/test callbacks are not S3/provider qualification.

Strings/notes are inert data, not HTML. Rendering clients must escape them for their output context. Content type fields reject unknown keys/kinds, getters, unsafe names, missing required values and invalid numeric/enum constraints. Types allow at most 64 fields, text at most 8192 characters and entry values at most 32 KiB. Text is not evaluated, and no request-time templates, SQL/JS expressions or plugins are loaded from content. Media permissions do not make user text trusted HTML.

Schema and revision model#

Configure a trusted private file path; CMS does not create parent directories or sandbox arbitrary filesystem paths. Reject HTTP-selected paths, secure directory permissions, backups and deployment storage separately. :memory: and URI filenames reject for owned adapters. Node's existing native node:sqlite driver is selected explicitly, with bounded busy timeout and WAL; no fallback to another driver or async transaction system is inferred. A borrowed connection must be a qualified file-backed SqliteConnector with real synchronousTransactions; it cannot also specify filename and stays host-owned. Query-only/unsupported adapters reject.

migrate:true explicitly authorizes startup schema-v1 creation. It runs DDL, scoped lookup index creation and a checksum journal insert on the same immediate SQLite transaction. Failures roll back all three. Existing journal version/checksum mismatches and future versions reject; no destructive automatic downgrade or guessed repair is performed. Without migration approval, startup only verifies the current journal and required columns. Tables are zenix_schema and zenix_content_v1; do not precreate conflicting tables or manually edit the journal. This is the initial v1 migration, not a user-defined schema migration runner.

SQLite's own file write transaction serializes migration/write admission. The shared @zeruxjs/db async pinned migration/transaction contract is deliberately not claimed: SQLite exposes a distinct synchronous transaction facade. See the connector's transaction documentation and official Node SQLite API. No PostgreSQL/MySQL/distributed migration support, replica durability or backup certification is implied.

Create a draft with expected = null; updates/publish/restore require the exact current head. A stale value raises CmsError('REVISION_CONFLICT'). Head update and new revision insert commit atomically. Type IDs/versions cannot change on an existing entry; register explicitly numbered content schemas (retaining prior versions) for new entries. Schemas are immutable and versions must retain contiguous history.

publish creates a new published revision from the specified current head. restoreDraft copies historical values into a new draft with sourceRevision; no history is overwritten. New drafts/restores keep any existing published pointer: entry.state describes the newest head, while publishedRevision separately identifies the still-published content. There is no unpublish operation in this minimal core.

Ownership, errors and limits#

Each instance owns its opened connector, abort scope and explicitly registered plugin resources. Plugins run in declaration order after schema initialization; immediately register disposal with onDispose. Startup failure aborts/disposes acquired plugin resources in reverse order and closes owned connections. Plugin-issued content writes are separate committed operations; resource rollback does not undo previously committed application data. Setup is trusted executable server code, not content or a sandbox. Create fresh plugin resources per generation and await close before dependencies.

Defaults: 16 pending operations (max 64), 5-second SQLite transaction deadline (max 60 seconds), 16 plugins and 64 cleanup callbacks. SQLite operations are synchronous; auth/media/plugin callbacks must cooperate with the instance abort signal and own any external deadlines. Close rejects admission, aborts and waits for actual pending work, disposes plugins LIFO and closes only owned connections. Signals cannot forcibly cancel arbitrary JavaScript. Borrowed auth/files services are never closed.

Public errors have fixed codes/messages and non-enumerable private causes. Do not return/log raw causes to clients. No file paths, credentials or content values are included in the default error envelope. Use restricted operational diagnostics for underlying database/provider failure evidence.

Verification and limits#

Run npm run build --workspace=@zenixjs/core and node --experimental-strip-types --test packages/@zenixjs/core/test/cms.test.ts from the repository root. Focused fixtures use real native Node SQLite files and verify durable close/reopen in a separate process, revision races, publication/restore history, tenant/site denial, malformed schemas, media denial, head-write rollback, migration rollback/version rejection and plugin cleanup. No browser/admin app, remote database, live auth provider or live files provider was exercised. Disk replication, recovery/backups and multi-process load qualification remain host responsibilities. This is a domain foundation, not a complete CMS or legal/compliance product.

License#

MIT OR Apache-2.0.

Source maintenance#

Module Ownership and review focus
src/index.ts Inert compatibility metadata; preserve version/status exports.
src/types.ts Package-owned domain contracts, field constraints and host callbacks; role data never authenticates a caller.
src/validation.ts Own-data checks and bounded schema/content/media syntax; files policy and authorization stay with their owners.
src/cms.ts SQLite migration identity, scoped reads, optimistic revision commits, fresh host authorization and instance cleanup.
examples/cms.ts Inert public-import helpers; setup/save/publish remain separate commits.
test/cms.test.ts Synthetic temporary SQLite files; tests close resources before removing owned paths.

Function/method contracts include typed parameters, return values and relevant failure behavior. Constants and loop bindings document provenance/ownership. Auth/media awaits stay outside synchronous SQLite callbacks; write permissions are rechecked before the final guarded commit. Admission remains occupied until actual promise settlement; close drains it before LIFO plugin disposal. Native SHA-256 identifies trusted schema/key data and is not a replacement for auth, signing or a managed service. This package has no source-marked deprecated APIs.

The repository reviewed-scope formatting/documentation gate applies to authored source/tests/examples/configuration, excluding generated output and license text. Do not sort/rewrite schema data as a cosmetic change: migration identity depends on its deterministic JSON content/order. Preserve embedded subprocess fixture source bytes and verify public consumers after any actual type/API change.

Implementation sources

Implementation files for the APIs described on this page.

ZeruxJS · Open source · MIT OR Apache-2.0

Make yourself at home.

Every shortcut has a visible control too. Reading and navigation work without JavaScript.

Ctrl / ⌘ K
Search all documentation
/
Search, outside editable fields
?
This help, outside editable fields
↑ / ↓
Move through search results
Esc
Close a dialog or version menu
Progress, privacy, offline reading and controls →

Reset this learning record?

This removes course answers, exercise confirmations, bookmarks and recent pages for this docs version in this browser. Export a copy first if you want to keep it.

Search documentation

Type at least two characters.