@bygghammar/cms-platform
v0.80.1
Published
Shared CMS platform: blocks, block types, i18n core, UI primitives and design-token contract used by every Bygghammar/Voyara site.
Readme
@bygghammar/cms-platform
Shared CMS platform code for every site in this workspace (Voyara, barskola and future sites). Code only — no content, no data, no secrets, no theme.
What lives here
src/blocks/types.ts— block prop types and the JSON contract for block propssrc/blocks/icons.ts— the icon set blocks may referencesrc/blocks/block-props-context.tsx— block prop plumbing for inline editingsrc/i18n/*— the localization core (locales, types, resolver, context)src/backup/*— archive/media safety, browser-side large-media export and provider-neutral verification helperssrc/trips/*— reusable trips data contract, editor and legacy course-data compatibility. Each host supplies its own terminology (Courses, Cruises or Trips).src/navigation/*— public and backoffice navigation contracts plus shared active-state helpers. Menu content and visual headers remain per-site.src/theme.css— the design-token contract + neutral starter theme
Starting a new site
docs/NEW-SITE.md is the supported starter path: install, assert the contract,
apply the canonical schema with bunx cms-platform-migrations, import
theme.css, register host components / platform data / translations, wrap the
server cores and mount the shared backoffice views.
Compatibility policy
CHANGELOG.mdrecords every release; read it before upgrading.- Pre-1.0, a minor release may break shared views, adapters or cores; patch releases are always compatible.
PLATFORM_CONTRACT_VERSION(platform/contract) is bumped when a shared screen starts requiring schema or adapter capabilities an older site lacks. Sites pin it in a test.migrations/is schema only. Site content, SEO copy and seeds never belong there.
What must never live here
- colours, fonts or spacing values used by a specific site (see
theme.css) - page content, SEO copy, media, CMS page JSON
- Supabase generated types, auth users, secrets, API keys
- route files and per-site deployment config
- actual navigation links, public slugs, brand-specific headers or menu styling
- site table lists, import order, database clients, authentication and RLS policies; each host supplies those adapters to the shared backup core
Backup core
The package owns the CMS-wide, provider-neutral parts of backup and restore:
- media signature/path validation and secret sanitising
- streaming large media files into an archive in the authenticated browser
- archive progress and manifest contracts
- row-count, user/role and media verification helpers
The browser media exporter accepts a host storage adapter with only list()
and download() methods plus the host's expected archive format/schema
versions. Keep the dynamic import behind an import.meta.env.SSR guard in SSR
applications so the browser-only ZIP code cannot enter the optimized server
chunk graph.
Individual media downloads are retried before an export is stopped. Public media-bucket adapters should also fall back to the object's public URL when an authenticated Storage download fails, so one transient large-file request cannot discard an otherwise valid archive.
The consuming site remains responsible for its dataset groups, table import order, Supabase clients, superadmin authorization, HTTP routes, audit records and database migrations. The package never contains site data or credentials.
Per-site wiring
Translation data is per-site content, so each site registers its own maps once at startup:
import { registerTranslations } from "@bygghammar/cms-platform/i18n";
registerTranslations({ generated: TRANSLATIONS, overrides: TRANSLATION_OVERRIDES });Host components must participate in a value the application actually uses.
Do not rely only on import "./register-host" because an optimized build may
remove that module when the application's package.json declares
"sideEffects": false.
import { initializeHostComponents, type HostComponents } from "@bygghammar/cms-platform/host";
const HOST_COMPONENTS = {
FocalImage,
LazyVideo,
FocusPicker,
RichTextEditor,
mediaLibraryQueryOptions,
useMediaUpload,
} satisfies Partial<HostComponents>;
export const BLOCK_REGISTRY = initializeHostComponents(HOST_COMPONENTS, () =>
createBlockRegistry(),
);Keep any existing registration module in the consuming application's
sideEffects allowlist as defence in depth until every entry point uses the
explicit contract. CSS must also remain in that allowlist.
Repository, development and releases
The canonical source of truth is https://github.com/byggis79/cms-platform (private). This repository is standalone — it is no longer a directory inside a site repository, and it must never be copied back into a consuming site.
bun install
bun run check # typecheck + tests + package verificationThe package ships TypeScript sources; there is no build output. Every change
goes through a pull request, and every release is triggered by pushing a
vX.Y.Z tag that matches package.json, which publishes to npm from GitHub
Actions using the repository secret NPM_TOKEN. Never publish manually.
See CONTRIBUTING.md for the full workflow and changelog
conventions. Consumers install an explicit released version such as
@bygghammar/[email protected].
