@~lyre/contentkit
v0.1.0
Published
Dynamic content engine for SvelteKit + Drizzle + Postgres. Pages, sections, texts, buttons, icons, data — composable component blueprints with a batched resolver, LRU cache with tag invalidation, registry, and Dynamic{Text,Button,Icon,Image,Section,FAQ} S
Downloads
156
Maintainers
Readme
@lyre/contentkit
Dynamic content engine for SvelteKit + Drizzle + Postgres. Pages, sections, texts, buttons, icons, data — composable component blueprints with a batched resolver, LRU cache with tag invalidation, a section registry, and Dynamic{Text,Button,Icon,Image,Section,FAQ} Svelte 5 components.
Inspired by the Laravel lyre/content package, rebuilt for SvelteKit.
Install
pnpm add @lyre/contentkit drizzle-orm svelteQuick start
// 1. include the schemas in your Drizzle client
import { pages, sections, texts, buttons, icons, data } from '@lyre/contentkit/schema';
// 2. resolve content in your +page.server.ts
import { resolveContent } from '@lyre/contentkit';
export const load = async () => {
const content = await resolveContent({
db,
locale: 'en',
pages: ['home'] // auto-expands page → sections → texts/buttons/data
});
return { content };
};<script lang="ts">
import { ContentProvider, DynamicSection } from '@lyre/contentkit/components';
import { sectionRegistry } from '$lib/sections'; // your own registry
let { data } = $props();
</script>
<ContentProvider content={data.content} registry={sectionRegistry}>
<DynamicSection key="homepage.hero" />
</ContentProvider>Core concepts
| Concept | What it is |
|---|---|
| Page | URL-routable container. PK is (slug, locale). Contains an ordered list of sections. |
| Section | Reusable, composable unit. Names a component string that maps to a concrete Svelte component in the consumer app via createSectionRegistry(). |
| Text / Button / Icon | Localised content fragments, addressable by (key, locale). |
| Data | App-specific JSON payloads attached to a section (FAQ items, testimonials, pillars). |
| Pivot tables | page_sections, section_sections, section_texts, section_buttons carry ordering. |
Resolver guarantees
- Page expansion in 4 round-trips max regardless of fan-out (batched
inArrayqueries). - Locale fallback: missing-in-
<locale>rows fall back to thefallbackLocaleand are taggedisFallback: true. - Returns a tag set so admin mutations can invalidate selectively.
Cache
createContentCache({ max, ttlMs }) — LRU + TTL + tag-based invalidation. Process-local for the POC; swap for Redis or LISTEN/NOTIFY-backed cache in production by re-implementing the ContentCache interface.
Components
The components live at the @lyre/contentkit/components subpath so the main entry stays Node-importable (for seeds and migrations).
<ContentProvider content registry>— sets context for the whole tree<DynamicText key>— renderstext.contentvia{@html}(admin-controlled HTML)<DynamicButton key>— anchor; passvariantClass(v)to map button variant strings to your CSS<DynamicIcon name>— inline SVG from the icons table<DynamicImage src alt>— thin<img>wrapper<DynamicSection key>— polymorphic; renders the registered component forsection.component<DynamicFAQ section dataType?>— rendersdatarows of the giventypeas a<dl>
License
MIT
