@cascivo/registry 0.1.5 → 0.1.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2024 urbanisierung
3
+ Copyright (c) cascivo contributors
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -16,11 +16,35 @@
16
16
 
17
17
  ---
18
18
 
19
- Registry client and type definitions reads `registry.json` and validates component entries. Used internally by the CLI and MCP server.
19
+ The **registry schema v2** for the cascivo ecosystem: TypeScript types, validation, the static registry build, and a shadcn-interop projection. If a tool reads or writes `registry.json`, this package defines what "valid" means.
20
+
21
+ Consumers in this repo: the `cascivo` CLI (`add`, `view`, `search`, `update`, `template init`, `registry build`), the registry generation pipeline (`scripts/registry/generate.ts`, which emits the root `registry.json` + per-item payloads), and the docs site. Third-party registries use it to build and validate their own indexes.
22
+
23
+ ## Exports
24
+
25
+ **Types** — `RegistryIndex` (the `registry.json` shape: `schemaVersion: 2` + `items`), `RegistryItem` (one entry: `name`, `type`, `version`, `files`, `dependencies`, `registryDependencies`, `tags`, optional `advisories`/`meta`), `RegistryItemType` (`component | layout | block | chart | section | theme | style | template`), plus template metadata (`TemplateMeta`, `TemplateScreenshot`, `TemplateFileRole`) and directory/marketplace types.
26
+
27
+ **Validation**
28
+
29
+ ```ts
30
+ import { validateIndex, validateItem } from '@cascivo/registry'
31
+
32
+ const result = validateIndex(JSON.parse(raw)) // { valid, errors: [{ path, message }] }
33
+ ```
34
+
35
+ `validateItem` checks a single entry; `validateIndex` the whole index. `parseLegacyRegistry` upgrades the pre-v2 flat format (`{ version, components }`) into a v2 `RegistryIndex`.
36
+
37
+ **Static build** — `buildRegistry(index, outDir)` writes a hostable registry: a sorted `registry.json` (examples stripped from the index for size) plus one JSON payload per item. This is what `cascivo registry build` runs under the hood, so anyone can serve a registry from a static file host.
38
+
39
+ **Templates** — `isTemplateItem`, `asTemplateMeta`, `validateTemplate` for `type: 'template'` entries (whole-page compositions riding the normal registry transport), and `projectTemplate`/`buildCatalog` to project them into the marketplace catalog.
40
+
41
+ **Advisories** — `matchAdvisories` matches an item's advisories (`severity`, `affectedVersions`, `fixedIn`) against an installed version, so clients can warn on install/update.
42
+
43
+ **Directory** — `validateDirectory` for the multi-registry directory format (namespace → registry URL) behind `cascivo search --registry @ns` and the MCP `list_registries` tool.
20
44
 
21
45
  ## shadcn registry interop
22
46
 
23
- In addition to cascivo's own registry, the build emits a **shadcn-registry-compatible** projection so the shadcn CLI can install a cascivo component directly:
47
+ In addition to cascivo's own registry, the build emits a **shadcn-registry-compatible** projection (`toShadcnItem`, `writeShadcnRegistry`) so the shadcn CLI can install a cascivo component directly:
24
48
 
25
49
  ```sh
26
50
  npx shadcn add https://<host>/r/shadcn/button.json
package/dist/index.d.mts CHANGED
@@ -74,6 +74,8 @@ interface RegistryItem {
74
74
  homepage?: string;
75
75
  files: RegistryFile[];
76
76
  install?: string;
77
+ /** Stylesheet the npm package requires, e.g. `@cascivo/charts/styles.css`. */
78
+ styles?: string;
77
79
  dependencies: string[];
78
80
  registryDependencies?: string[];
79
81
  tags: string[];
@@ -94,6 +96,7 @@ interface LegacyRegistryEntry {
94
96
  version: string;
95
97
  files: string[];
96
98
  install?: string;
99
+ styles?: string;
97
100
  dependencies: string[];
98
101
  tags: string[];
99
102
  meta?: unknown;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/validate.ts","../src/template.ts","../src/build.ts","../src/shadcn.ts","../src/advisories.ts","../src/directory.ts","../src/marketplace.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/validate.ts","../src/template.ts","../src/build.ts","../src/shadcn.ts","../src/advisories.ts","../src/directory.ts","../src/marketplace.ts"],"mappings":"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"}
package/dist/index.mjs CHANGED
@@ -74,6 +74,7 @@ function validateItem(raw) {
74
74
  "homepage",
75
75
  "files",
76
76
  "install",
77
+ "styles",
77
78
  "dependencies",
78
79
  "registryDependencies",
79
80
  "tags",
@@ -125,6 +126,7 @@ function parseLegacyRegistry(raw) {
125
126
  };
126
127
  if (typeof c["category"] === "string") item.category = c["category"];
127
128
  if (typeof c["install"] === "string") item.install = c["install"];
129
+ if (typeof c["styles"] === "string") item.styles = c["styles"];
128
130
  if (c["meta"]) item.meta = c["meta"];
129
131
  return item;
130
132
  })
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../src/validate.ts","../src/template.ts","../src/build.ts","../src/shadcn.ts","../src/advisories.ts","../src/directory.ts","../src/marketplace.ts"],"sourcesContent":["import type { RegistryIndex, RegistryItem } from './types.ts'\n\nexport interface ValidationResult {\n ok: boolean\n errors: string[]\n warnings: string[]\n}\n\nconst VALID_TYPES = new Set([\n 'component',\n 'layout',\n 'block',\n 'chart',\n 'section',\n 'theme',\n 'style',\n 'template',\n])\nconst VALID_SEVERITIES = new Set(['low', 'moderate', 'high', 'critical'])\n\nfunction ok(warnings: string[] = []): ValidationResult {\n return { ok: true, errors: [], warnings }\n}\n\nfunction fail(errors: string[], warnings: string[] = []): ValidationResult {\n return { ok: false, errors, warnings }\n}\n\nexport function validateItem(raw: unknown): ValidationResult {\n if (!raw || typeof raw !== 'object') {\n return fail(['Item must be an object'])\n }\n const obj = raw as Record<string, unknown>\n const errors: string[] = []\n const warnings: string[] = []\n\n if (obj['schemaVersion'] !== 2) {\n errors.push(`schemaVersion must be 2, got ${JSON.stringify(obj['schemaVersion'])}`)\n }\n if (typeof obj['name'] !== 'string' || !obj['name']) {\n errors.push('name is required and must be a non-empty string')\n }\n if (!VALID_TYPES.has(obj['type'] as string)) {\n errors.push(\n `type must be one of ${[...VALID_TYPES].join('|')}, got ${JSON.stringify(obj['type'])}`,\n )\n }\n if (typeof obj['description'] !== 'string') {\n errors.push('description is required and must be a string')\n }\n if (typeof obj['version'] !== 'string' || !obj['version']) {\n errors.push('version is required and must be a non-empty string')\n }\n if (!Array.isArray(obj['files'])) {\n errors.push('files is required and must be an array')\n }\n if (!Array.isArray(obj['dependencies'])) {\n errors.push('dependencies is required and must be an array')\n }\n if (!Array.isArray(obj['tags'])) {\n errors.push('tags is required and must be an array')\n }\n\n if (obj['advisories'] !== undefined) {\n if (!Array.isArray(obj['advisories'])) {\n errors.push('advisories must be an array')\n } else {\n const ids = new Set<string>()\n for (const adv of obj['advisories'] as unknown[]) {\n if (!adv || typeof adv !== 'object') {\n errors.push('each advisory must be an object')\n continue\n }\n const a = adv as Record<string, unknown>\n if (typeof a['id'] !== 'string') errors.push('advisory.id must be a string')\n else if (ids.has(a['id'] as string)) errors.push(`advisory id \"${a['id']}\" is not unique`)\n else ids.add(a['id'] as string)\n if (!VALID_SEVERITIES.has(a['severity'] as string))\n errors.push(`advisory.severity must be one of ${[...VALID_SEVERITIES].join('|')}`)\n if (typeof a['affectedVersions'] !== 'string')\n errors.push('advisory.affectedVersions must be a string')\n if (typeof a['summary'] !== 'string') errors.push('advisory.summary must be a string')\n }\n }\n }\n\n const knownKeys = new Set([\n 'schemaVersion',\n 'name',\n 'type',\n 'description',\n 'category',\n 'version',\n 'changelog',\n 'author',\n 'license',\n 'homepage',\n 'files',\n 'install',\n 'dependencies',\n 'registryDependencies',\n 'tags',\n 'meta',\n 'advisories',\n ])\n for (const key of Object.keys(obj)) {\n if (!knownKeys.has(key)) {\n warnings.push(`Unknown field \"${key}\" — ignored (forward compat)`)\n }\n }\n\n return errors.length > 0 ? fail(errors, warnings) : ok(warnings)\n}\n\nexport function validateIndex(raw: unknown): ValidationResult {\n if (!raw || typeof raw !== 'object') {\n return fail(['Index must be an object'])\n }\n const obj = raw as Record<string, unknown>\n const errors: string[] = []\n const warnings: string[] = []\n\n if (obj['schemaVersion'] !== 2) {\n errors.push(`schemaVersion must be 2, got ${JSON.stringify(obj['schemaVersion'])}`)\n }\n if (typeof obj['name'] !== 'string' || !obj['name']) {\n errors.push('name is required and must be a non-empty string')\n }\n if (!Array.isArray(obj['items'])) {\n errors.push('items is required and must be an array')\n } else {\n for (let i = 0; i < obj['items'].length; i++) {\n const itemResult = validateItem(obj['items'][i])\n for (const e of itemResult.errors) errors.push(`items[${i}]: ${e}`)\n for (const w of itemResult.warnings) warnings.push(`items[${i}]: ${w}`)\n }\n }\n\n const knownKeys = new Set(['schemaVersion', 'name', 'homepage', 'items'])\n for (const key of Object.keys(obj)) {\n if (!knownKeys.has(key)) {\n warnings.push(`Unknown field \"${key}\" — ignored (forward compat)`)\n }\n }\n\n return errors.length > 0 ? fail(errors, warnings) : ok(warnings)\n}\n\nexport function parseLegacyRegistry(raw: unknown): RegistryIndex {\n if (!raw || typeof raw !== 'object') throw new Error('Legacy registry must be an object')\n const obj = raw as Record<string, unknown>\n const topVersion = typeof obj['version'] === 'string' ? obj['version'] : '0.0.0'\n const components = Array.isArray(obj['components']) ? obj['components'] : []\n\n return {\n schemaVersion: 2,\n name: 'cascivo',\n items: (components as Record<string, unknown>[]).map((c) => {\n const item: RegistryItem = {\n schemaVersion: 2,\n name: typeof c['name'] === 'string' ? c['name'] : '',\n type: (c['type'] as RegistryItem['type']) ?? 'component',\n description: typeof c['description'] === 'string' ? c['description'] : '',\n version: topVersion,\n files: Array.isArray(c['files']) ? (c['files'] as string[]).map((url) => ({ url })) : [],\n dependencies: Array.isArray(c['dependencies']) ? (c['dependencies'] as string[]) : [],\n tags: Array.isArray(c['tags']) ? (c['tags'] as string[]) : [],\n }\n if (typeof c['category'] === 'string') item.category = c['category']\n if (typeof c['install'] === 'string') item.install = c['install']\n if (c['meta']) item.meta = c['meta'] as RegistryItem['meta']\n return item\n }),\n }\n}\n","import type { RegistryItem, TemplateMeta, TemplateFileRole } from './types.ts'\n\nconst VALID_FRAMEWORKS = new Set(['react-vite', 'react-next'])\nconst VALID_FILE_ROLES = new Set<TemplateFileRole>(['page', 'fixture', 'asset', 'config'])\n\n/** True when an item is a template. */\nexport function isTemplateItem(item: RegistryItem): boolean {\n return item.type === 'template'\n}\n\n/**\n * Narrow an item's `meta` to a {@link TemplateMeta}, throwing on shape mismatch.\n * Use after {@link validateTemplate} has passed.\n */\nexport function asTemplateMeta(meta: unknown): TemplateMeta {\n const errors = validateTemplateMeta(meta)\n if (errors.length > 0) {\n throw new Error(`Invalid TemplateMeta: ${errors.join('; ')}`)\n }\n return meta as TemplateMeta\n}\n\nfunction validateTemplateMeta(meta: unknown): string[] {\n const errors: string[] = []\n if (!meta || typeof meta !== 'object') {\n return ['meta must be a TemplateMeta object']\n }\n const m = meta as Record<string, unknown>\n\n if (typeof m['intent'] !== 'string' || !m['intent']) {\n errors.push('meta.intent is required and must be a non-empty string')\n }\n if (!VALID_FRAMEWORKS.has(m['framework'] as string)) {\n errors.push(`meta.framework must be one of ${[...VALID_FRAMEWORKS].join('|')}`)\n }\n if (typeof m['category'] !== 'string' || !m['category']) {\n errors.push('meta.category is required and must be a non-empty string')\n }\n\n if (!Array.isArray(m['screenshots']) || m['screenshots'].length === 0) {\n errors.push('meta.screenshots is required and must have at least one entry')\n } else {\n for (let i = 0; i < m['screenshots'].length; i++) {\n const shot = m['screenshots'][i] as Record<string, unknown>\n if (!shot || typeof shot !== 'object') {\n errors.push(`meta.screenshots[${i}] must be an object`)\n continue\n }\n if (typeof shot['light'] !== 'string' || !shot['light'])\n errors.push(`meta.screenshots[${i}].light is required`)\n if (typeof shot['alt'] !== 'string' || !shot['alt'])\n errors.push(`meta.screenshots[${i}].alt is required`)\n }\n }\n\n if (m['demoUrl'] !== undefined && typeof m['demoUrl'] !== 'string') {\n errors.push('meta.demoUrl must be a string when present')\n }\n\n if (!m['fileRoles'] || typeof m['fileRoles'] !== 'object') {\n errors.push('meta.fileRoles is required and must be an object')\n } else {\n for (const [target, role] of Object.entries(m['fileRoles'] as Record<string, unknown>)) {\n if (!VALID_FILE_ROLES.has(role as TemplateFileRole)) {\n errors.push(`meta.fileRoles[\"${target}\"] must be one of ${[...VALID_FILE_ROLES].join('|')}`)\n }\n }\n }\n\n if (m['pages'] !== undefined) {\n if (!Array.isArray(m['pages'])) {\n errors.push('meta.pages must be an array when present')\n } else {\n for (let i = 0; i < m['pages'].length; i++) {\n const page = m['pages'][i] as Record<string, unknown>\n if (!page || typeof page !== 'object') {\n errors.push(`meta.pages[${i}] must be an object`)\n continue\n }\n if (typeof page['name'] !== 'string') errors.push(`meta.pages[${i}].name is required`)\n if (typeof page['target'] !== 'string') errors.push(`meta.pages[${i}].target is required`)\n }\n }\n }\n\n return errors\n}\n\n/**\n * Validate a template item beyond the base item schema. Returns a list of\n * errors (empty when valid). Requires:\n * - `type === 'template'`\n * - a valid {@link TemplateMeta}\n * - at least one component (`registryDependencies`) or one `page` file\n * - a non-empty `license`\n * - every `files[].target` present in `meta.fileRoles`\n */\nexport function validateTemplate(item: RegistryItem): string[] {\n const errors: string[] = []\n\n if (item.type !== 'template') {\n errors.push(`type must be 'template', got ${JSON.stringify(item.type)}`)\n return errors\n }\n\n const metaErrors = validateTemplateMeta(item.meta)\n errors.push(...metaErrors)\n\n const meta = (item.meta ?? {}) as Partial<TemplateMeta>\n const fileRoles = (meta.fileRoles ?? {}) as Record<string, TemplateFileRole>\n\n const hasComponents = Array.isArray(item.registryDependencies)\n ? item.registryDependencies.length > 0\n : false\n const hasPageFile = Object.values(fileRoles).includes('page')\n if (!hasComponents && !hasPageFile) {\n errors.push(\n 'a template must list at least one component in registryDependencies or one page file',\n )\n }\n\n if (typeof item.license !== 'string' || !item.license) {\n errors.push('license is required for a template')\n }\n\n for (const file of item.files ?? []) {\n if (!file.target) {\n errors.push(`template file ${JSON.stringify(file.url)} must declare a target`)\n } else if (metaErrors.length === 0 && !(file.target in fileRoles)) {\n errors.push(`file target \"${file.target}\" is missing from meta.fileRoles`)\n }\n }\n\n return errors\n}\n","import { mkdir, writeFile } from 'node:fs/promises'\nimport { join } from 'node:path'\nimport type { RegistryIndex, RegistryItem } from './types.ts'\n\nfunction flatName(name: string): string {\n return name.replace(/\\//g, '-')\n}\n\nfunction itemWithoutExamples(item: RegistryItem): RegistryItem {\n if (!item.meta || typeof item.meta !== 'object') return item\n const meta = item.meta as Record<string, unknown>\n if (!Array.isArray(meta['examples']) || meta['examples'].length === 0) return item\n return { ...item, meta: { ...meta, examples: [] } }\n}\n\nexport async function buildRegistry(index: RegistryIndex, outDir: string): Promise<void> {\n await mkdir(outDir, { recursive: true })\n\n const sortedItems = [...index.items].sort((a, b) => a.name.localeCompare(b.name))\n\n const indexOut: RegistryIndex = {\n schemaVersion: 2,\n name: index.name,\n ...(index.homepage ? { homepage: index.homepage } : {}),\n items: sortedItems.map(itemWithoutExamples),\n }\n await writeFile(join(outDir, 'registry.json'), `${JSON.stringify(indexOut, null, 2)}\\n`, 'utf8')\n\n for (const item of sortedItems) {\n const flat = flatName(item.name)\n await writeFile(join(outDir, `${flat}.json`), `${JSON.stringify(item, null, 2)}\\n`, 'utf8')\n await writeFile(\n join(outDir, `${flat}@${item.version}.json`),\n `${JSON.stringify(item, null, 2)}\\n`,\n 'utf8',\n )\n }\n}\n","/**\n * shadcn-registry-compatible projection of the cascivo registry.\n *\n * This is purely ADDITIVE interop: it maps cascivo's own `RegistryItem`s into\n * the shadcn `registry:*` item schema so the shadcn CLI can install a cascivo\n * component (`npx shadcn add <host>/r/shadcn/<name>.json`). cascivo's own\n * `registry.json` schema is untouched.\n *\n * cascivo is CSS-native: components ship `.tsx` + `.module.css` and rely on a\n * `@cascivo/themes` import plus the `@cascivo/core` peer — there is no Tailwind\n * config, so no `cssVars`/`tailwind` block is emitted.\n */\nimport { mkdir, writeFile } from 'node:fs/promises'\nimport { join } from 'node:path'\nimport type { RegistryIndex, RegistryItem, RegistryItemType } from './types.ts'\n\nconst SHADCN_ITEM_SCHEMA = 'https://ui.shadcn.com/schema/registry-item.json'\nconst SHADCN_REGISTRY_SCHEMA = 'https://ui.shadcn.com/schema/registry.json'\n\nexport type ShadcnItemType =\n | 'registry:component'\n | 'registry:block'\n | 'registry:lib'\n | 'registry:ui'\n | 'registry:hook'\n | 'registry:theme'\n | 'registry:style'\n | 'registry:file'\n\nexport interface ShadcnRegistryFile {\n path: string\n type: ShadcnItemType\n content?: string\n target?: string\n}\n\nexport interface ShadcnRegistryItem {\n $schema: string\n name: string\n type: ShadcnItemType\n description?: string\n dependencies?: string[]\n registryDependencies?: string[]\n files: ShadcnRegistryFile[]\n categories?: string[]\n meta?: Record<string, unknown>\n}\n\nexport interface ToShadcnOptions {\n /** Resolve a cascivo file URL to its source text, to inline as `content`. */\n resolveContent?: (fileUrl: string) => string | undefined\n}\n\nconst TYPE_MAP: Record<RegistryItemType, ShadcnItemType> = {\n component: 'registry:component',\n layout: 'registry:block',\n block: 'registry:block',\n section: 'registry:block',\n chart: 'registry:component',\n theme: 'registry:theme',\n style: 'registry:style',\n template: 'registry:block',\n}\n\n/** Flatten a possibly-prefixed cascivo name (\"block/x\") into a shadcn slug. */\nexport function shadcnName(name: string): string {\n return name.replace(/\\//g, '-')\n}\n\nfunction filePath(fileUrl: string, slug: string): string {\n const base = fileUrl.split('/').pop() ?? fileUrl\n return `${slug}/${base}`\n}\n\nexport function toShadcnItem(item: RegistryItem, opts: ToShadcnOptions = {}): ShadcnRegistryItem {\n const slug = shadcnName(item.name)\n const type = TYPE_MAP[item.type] ?? 'registry:component'\n\n const files: ShadcnRegistryFile[] = item.files.map((f) => {\n const file: ShadcnRegistryFile = { path: filePath(f.url, slug), type }\n const content = opts.resolveContent?.(f.url)\n if (content !== undefined) file.content = content\n return file\n })\n\n const out: ShadcnRegistryItem = {\n $schema: SHADCN_ITEM_SCHEMA,\n name: slug,\n type,\n files,\n }\n if (item.description) out.description = item.description\n if (item.dependencies.length > 0) out.dependencies = [...item.dependencies]\n if (item.registryDependencies && item.registryDependencies.length > 0) {\n out.registryDependencies = [...item.registryDependencies]\n }\n if (item.category) out.categories = [item.category]\n out.meta = { cascivo: { type: item.type, version: item.version } }\n return out\n}\n\n/**\n * Write one shadcn `r/<name>.json` per item (with inlined file content when a\n * resolver is supplied) plus a lean `registry.json` index (content omitted).\n */\nexport async function writeShadcnRegistry(\n index: RegistryIndex,\n outDir: string,\n opts: ToShadcnOptions = {},\n): Promise<void> {\n await mkdir(outDir, { recursive: true })\n\n const sorted = [...index.items].sort((a, b) => a.name.localeCompare(b.name))\n const items = sorted.map((it) => toShadcnItem(it, opts))\n\n for (const item of items) {\n await writeFile(join(outDir, `${item.name}.json`), `${JSON.stringify(item, null, 2)}\\n`, 'utf8')\n }\n\n const indexItems = items.map((it) => ({\n ...it,\n files: it.files.map((f) => ({\n path: f.path,\n type: f.type,\n ...(f.target ? { target: f.target } : {}),\n })),\n }))\n const registry = {\n $schema: SHADCN_REGISTRY_SCHEMA,\n name: index.name,\n ...(index.homepage ? { homepage: index.homepage } : {}),\n items: indexItems,\n }\n await writeFile(join(outDir, 'registry.json'), `${JSON.stringify(registry, null, 2)}\\n`, 'utf8')\n}\n","import type { RegistryAdvisory, RegistryItem } from './types.ts'\n\nfunction parseVersionParts(v: string): number[] {\n return v\n .replace(/^[^0-9]*/, '')\n .split('.')\n .map(Number)\n}\n\nfunction compareVersions(a: string, b: string): number {\n const pa = parseVersionParts(a)\n const pb = parseVersionParts(b)\n for (let i = 0; i < Math.max(pa.length, pb.length); i++) {\n const na = pa[i] ?? 0\n const nb = pb[i] ?? 0\n if (na !== nb) return na - nb\n }\n return 0\n}\n\nfunction matchesRange(version: string, range: string): boolean {\n try {\n const trimmed = range.trim()\n if (trimmed.startsWith('>=')) {\n return compareVersions(version, trimmed.slice(2).trim()) >= 0\n }\n if (trimmed.startsWith('>')) {\n return compareVersions(version, trimmed.slice(1).trim()) > 0\n }\n if (trimmed.startsWith('<=')) {\n return compareVersions(version, trimmed.slice(2).trim()) <= 0\n }\n if (trimmed.startsWith('<')) {\n return compareVersions(version, trimmed.slice(1).trim()) < 0\n }\n if (trimmed.startsWith('^')) {\n const base = trimmed.slice(1).trim()\n const baseParts = parseVersionParts(base)\n const major = baseParts[0] ?? 0\n const vParts = parseVersionParts(version)\n const vMajor = vParts[0] ?? 0\n return vMajor === major && compareVersions(version, base) >= 0\n }\n if (trimmed.startsWith('~')) {\n const base = trimmed.slice(1).trim()\n const baseParts = parseVersionParts(base)\n const major = baseParts[0] ?? 0\n const minor = baseParts[1] ?? 0\n const vParts = parseVersionParts(version)\n const vMajor = vParts[0] ?? 0\n const vMinor = vParts[1] ?? 0\n return vMajor === major && vMinor === minor && compareVersions(version, base) >= 0\n }\n return version === trimmed\n } catch {\n return false\n }\n}\n\nexport function matchAdvisories(\n item: Pick<RegistryItem, 'advisories'>,\n lockedVersion: string,\n): RegistryAdvisory[] {\n if (!item.advisories) return []\n const matched: RegistryAdvisory[] = []\n for (const adv of item.advisories) {\n try {\n if (matchesRange(lockedVersion, adv.affectedVersions)) {\n matched.push(adv)\n }\n } catch {\n // malformed range — skip silently, never crash an audit\n }\n }\n return matched\n}\n","/** What kinds of items a directory-listed registry publishes. */\nexport type DirectoryProvides = 'component' | 'template' | 'theme'\n\nexport interface DirectoryEntry {\n namespace: string\n name: string\n description: string\n homepage: string\n registryUrl: string\n tags: string[]\n verified: boolean\n /** Item kinds this registry provides. Absent ⇒ component-only. */\n provides?: DirectoryProvides[]\n}\n\nconst VALID_PROVIDES = new Set<DirectoryProvides>(['component', 'template', 'theme'])\n\nexport interface RegistryDirectory {\n schemaVersion: 1\n registries: DirectoryEntry[]\n}\n\nexport interface DirectoryValidationResult {\n ok: boolean\n errors: string[]\n warnings: string[]\n}\n\nfunction levenshtein(a: string, b: string): number {\n const m = a.length\n const n = b.length\n const dp: number[][] = Array.from({ length: m + 1 }, (_, i) =>\n Array.from({ length: n + 1 }, (_, j) => (i === 0 ? j : j === 0 ? i : 0)),\n )\n for (let i = 1; i <= m; i++) {\n for (let j = 1; j <= n; j++) {\n dp[i]![j] =\n a[i - 1] === b[j - 1]\n ? dp[i - 1]![j - 1]!\n : 1 + Math.min(dp[i - 1]![j]!, dp[i]![j - 1]!, dp[i - 1]![j - 1]!)\n }\n }\n return dp[m]![n]!\n}\n\nexport function validateDirectory(raw: unknown): DirectoryValidationResult {\n if (!raw || typeof raw !== 'object') {\n return { ok: false, errors: ['Directory must be an object'], warnings: [] }\n }\n const obj = raw as Record<string, unknown>\n const errors: string[] = []\n const warnings: string[] = []\n\n if (obj['schemaVersion'] !== 1) {\n errors.push(`schemaVersion must be 1, got ${JSON.stringify(obj['schemaVersion'])}`)\n }\n if (!Array.isArray(obj['registries'])) {\n errors.push('registries must be an array')\n return { ok: false, errors, warnings }\n }\n\n const namespaces: string[] = []\n for (let i = 0; i < obj['registries'].length; i++) {\n const entry = obj['registries'][i] as Record<string, unknown>\n const ns = entry['namespace']\n if (typeof ns !== 'string' || !ns) errors.push(`registries[${i}].namespace is required`)\n else {\n if (namespaces.includes(ns)) errors.push(`Duplicate namespace \"${ns}\" at index ${i}`)\n namespaces.push(ns)\n }\n if (typeof entry['name'] !== 'string') errors.push(`registries[${i}].name is required`)\n if (typeof entry['description'] !== 'string')\n errors.push(`registries[${i}].description is required`)\n if (typeof entry['homepage'] !== 'string') errors.push(`registries[${i}].homepage is required`)\n if (typeof entry['registryUrl'] !== 'string')\n errors.push(`registries[${i}].registryUrl is required`)\n else if (!(entry['registryUrl'] as string).includes('{name}'))\n errors.push(`registries[${i}].registryUrl must contain {name} placeholder`)\n if (!Array.isArray(entry['tags'])) errors.push(`registries[${i}].tags must be an array`)\n if (typeof entry['verified'] !== 'boolean')\n errors.push(`registries[${i}].verified must be a boolean`)\n if (entry['provides'] !== undefined) {\n if (!Array.isArray(entry['provides'])) {\n errors.push(`registries[${i}].provides must be an array when present`)\n } else {\n for (const p of entry['provides'] as unknown[]) {\n if (!VALID_PROVIDES.has(p as DirectoryProvides))\n errors.push(\n `registries[${i}].provides has invalid value ${JSON.stringify(p)} (allowed: ${[...VALID_PROVIDES].join('|')})`,\n )\n }\n }\n }\n }\n\n for (let i = 0; i < namespaces.length; i++) {\n for (let j = i + 1; j < namespaces.length; j++) {\n const a = namespaces[i]!\n const b = namespaces[j]!\n if (levenshtein(a, b) <= 2) {\n warnings.push(\n `Namespaces \"${a}\" and \"${b}\" are suspiciously similar (Levenshtein distance ≤ 2)`,\n )\n }\n }\n }\n\n return { ok: errors.length === 0, errors, warnings }\n}\n","import type { RegistryItem, TemplateScreenshot } from './types.ts'\nimport { isTemplateItem, asTemplateMeta } from './template.ts'\n\n/** A template projected into a flat, gallery-ready record. */\nexport interface MarketplaceTemplate {\n name: string\n namespace: string\n description: string\n category: string\n framework: string\n tags: string[]\n /** Component names the template composes (from `registryDependencies`). */\n components: string[]\n screenshots: TemplateScreenshot[]\n demoUrl?: string\n version: string\n license: string\n verified: boolean\n homepage?: string\n /** The spec a user passes to `cascivo add` (e.g. \"@acme/dashboard\"). */\n installSpec: string\n /** GitHub stars, baked at CI build time (omitted when unknown). */\n stars?: number\n}\n\n/** The static marketplace catalog written to `apps/site/public/marketplace.json`. */\nexport interface MarketplaceCatalog {\n generatedAt: string\n templates: MarketplaceTemplate[]\n facets: { categories: string[]; frameworks: string[]; tags: string[] }\n}\n\n/** One registry's resolved index + the directory metadata that referenced it. */\nexport interface MarketplaceSource {\n entry: { namespace: string; verified?: boolean; homepage?: string; stars?: number }\n items: RegistryItem[]\n}\n\n/**\n * Project a template item into a gallery record, or `null` if the item is not a\n * valid template. Pure — no I/O.\n */\nexport function projectTemplate(\n item: RegistryItem,\n source: MarketplaceSource['entry'],\n): MarketplaceTemplate | null {\n if (!isTemplateItem(item)) return null\n let meta\n try {\n meta = asTemplateMeta(item.meta)\n } catch {\n return null\n }\n const record: MarketplaceTemplate = {\n name: item.name,\n namespace: source.namespace,\n description: item.description,\n category: meta.category,\n framework: meta.framework,\n tags: item.tags ?? [],\n components: item.registryDependencies ?? [],\n screenshots: meta.screenshots,\n version: item.version,\n license: item.license ?? '',\n verified: source.verified ?? false,\n installSpec: `${source.namespace}/${item.name}`,\n }\n if (meta.demoUrl) record.demoUrl = meta.demoUrl\n const homepage = item.homepage ?? source.homepage\n if (homepage) record.homepage = homepage\n if (typeof source.stars === 'number') record.stars = source.stars\n return record\n}\n\nfunction uniqueSorted(values: string[]): string[] {\n return [...new Set(values)].sort((a, b) => a.localeCompare(b))\n}\n\n/**\n * Build the marketplace catalog from a set of resolved registry sources. Pure —\n * the caller does the fetching + star lookups and supplies the timestamp.\n * Templates are sorted verified-first, then by stars (desc), then by name.\n */\nexport function buildCatalog(\n sources: MarketplaceSource[],\n generatedAt: string,\n): MarketplaceCatalog {\n const templates: MarketplaceTemplate[] = []\n for (const src of sources) {\n for (const item of src.items) {\n const record = projectTemplate(item, src.entry)\n if (record) templates.push(record)\n }\n }\n\n templates.sort((a, b) => {\n if (a.verified !== b.verified) return a.verified ? -1 : 1\n const sa = a.stars ?? 0\n const sb = b.stars ?? 0\n if (sa !== sb) return sb - sa\n return a.name.localeCompare(b.name)\n })\n\n return {\n generatedAt,\n templates,\n facets: {\n categories: uniqueSorted(templates.map((t) => t.category)),\n frameworks: uniqueSorted(templates.map((t) => t.framework)),\n tags: uniqueSorted(templates.flatMap((t) => t.tags)),\n },\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/validate.ts","../src/template.ts","../src/build.ts","../src/shadcn.ts","../src/advisories.ts","../src/directory.ts","../src/marketplace.ts"],"sourcesContent":["import type { RegistryIndex, RegistryItem } from './types.ts'\n\nexport interface ValidationResult {\n ok: boolean\n errors: string[]\n warnings: string[]\n}\n\nconst VALID_TYPES = new Set([\n 'component',\n 'layout',\n 'block',\n 'chart',\n 'section',\n 'theme',\n 'style',\n 'template',\n])\nconst VALID_SEVERITIES = new Set(['low', 'moderate', 'high', 'critical'])\n\nfunction ok(warnings: string[] = []): ValidationResult {\n return { ok: true, errors: [], warnings }\n}\n\nfunction fail(errors: string[], warnings: string[] = []): ValidationResult {\n return { ok: false, errors, warnings }\n}\n\nexport function validateItem(raw: unknown): ValidationResult {\n if (!raw || typeof raw !== 'object') {\n return fail(['Item must be an object'])\n }\n const obj = raw as Record<string, unknown>\n const errors: string[] = []\n const warnings: string[] = []\n\n if (obj['schemaVersion'] !== 2) {\n errors.push(`schemaVersion must be 2, got ${JSON.stringify(obj['schemaVersion'])}`)\n }\n if (typeof obj['name'] !== 'string' || !obj['name']) {\n errors.push('name is required and must be a non-empty string')\n }\n if (!VALID_TYPES.has(obj['type'] as string)) {\n errors.push(\n `type must be one of ${[...VALID_TYPES].join('|')}, got ${JSON.stringify(obj['type'])}`,\n )\n }\n if (typeof obj['description'] !== 'string') {\n errors.push('description is required and must be a string')\n }\n if (typeof obj['version'] !== 'string' || !obj['version']) {\n errors.push('version is required and must be a non-empty string')\n }\n if (!Array.isArray(obj['files'])) {\n errors.push('files is required and must be an array')\n }\n if (!Array.isArray(obj['dependencies'])) {\n errors.push('dependencies is required and must be an array')\n }\n if (!Array.isArray(obj['tags'])) {\n errors.push('tags is required and must be an array')\n }\n\n if (obj['advisories'] !== undefined) {\n if (!Array.isArray(obj['advisories'])) {\n errors.push('advisories must be an array')\n } else {\n const ids = new Set<string>()\n for (const adv of obj['advisories'] as unknown[]) {\n if (!adv || typeof adv !== 'object') {\n errors.push('each advisory must be an object')\n continue\n }\n const a = adv as Record<string, unknown>\n if (typeof a['id'] !== 'string') errors.push('advisory.id must be a string')\n else if (ids.has(a['id'] as string)) errors.push(`advisory id \"${a['id']}\" is not unique`)\n else ids.add(a['id'] as string)\n if (!VALID_SEVERITIES.has(a['severity'] as string))\n errors.push(`advisory.severity must be one of ${[...VALID_SEVERITIES].join('|')}`)\n if (typeof a['affectedVersions'] !== 'string')\n errors.push('advisory.affectedVersions must be a string')\n if (typeof a['summary'] !== 'string') errors.push('advisory.summary must be a string')\n }\n }\n }\n\n const knownKeys = new Set([\n 'schemaVersion',\n 'name',\n 'type',\n 'description',\n 'category',\n 'version',\n 'changelog',\n 'author',\n 'license',\n 'homepage',\n 'files',\n 'install',\n 'styles',\n 'dependencies',\n 'registryDependencies',\n 'tags',\n 'meta',\n 'advisories',\n ])\n for (const key of Object.keys(obj)) {\n if (!knownKeys.has(key)) {\n warnings.push(`Unknown field \"${key}\" — ignored (forward compat)`)\n }\n }\n\n return errors.length > 0 ? fail(errors, warnings) : ok(warnings)\n}\n\nexport function validateIndex(raw: unknown): ValidationResult {\n if (!raw || typeof raw !== 'object') {\n return fail(['Index must be an object'])\n }\n const obj = raw as Record<string, unknown>\n const errors: string[] = []\n const warnings: string[] = []\n\n if (obj['schemaVersion'] !== 2) {\n errors.push(`schemaVersion must be 2, got ${JSON.stringify(obj['schemaVersion'])}`)\n }\n if (typeof obj['name'] !== 'string' || !obj['name']) {\n errors.push('name is required and must be a non-empty string')\n }\n if (!Array.isArray(obj['items'])) {\n errors.push('items is required and must be an array')\n } else {\n for (let i = 0; i < obj['items'].length; i++) {\n const itemResult = validateItem(obj['items'][i])\n for (const e of itemResult.errors) errors.push(`items[${i}]: ${e}`)\n for (const w of itemResult.warnings) warnings.push(`items[${i}]: ${w}`)\n }\n }\n\n const knownKeys = new Set(['schemaVersion', 'name', 'homepage', 'items'])\n for (const key of Object.keys(obj)) {\n if (!knownKeys.has(key)) {\n warnings.push(`Unknown field \"${key}\" — ignored (forward compat)`)\n }\n }\n\n return errors.length > 0 ? fail(errors, warnings) : ok(warnings)\n}\n\nexport function parseLegacyRegistry(raw: unknown): RegistryIndex {\n if (!raw || typeof raw !== 'object') throw new Error('Legacy registry must be an object')\n const obj = raw as Record<string, unknown>\n const topVersion = typeof obj['version'] === 'string' ? obj['version'] : '0.0.0'\n const components = Array.isArray(obj['components']) ? obj['components'] : []\n\n return {\n schemaVersion: 2,\n name: 'cascivo',\n items: (components as Record<string, unknown>[]).map((c) => {\n const item: RegistryItem = {\n schemaVersion: 2,\n name: typeof c['name'] === 'string' ? c['name'] : '',\n type: (c['type'] as RegistryItem['type']) ?? 'component',\n description: typeof c['description'] === 'string' ? c['description'] : '',\n version: topVersion,\n files: Array.isArray(c['files']) ? (c['files'] as string[]).map((url) => ({ url })) : [],\n dependencies: Array.isArray(c['dependencies']) ? (c['dependencies'] as string[]) : [],\n tags: Array.isArray(c['tags']) ? (c['tags'] as string[]) : [],\n }\n if (typeof c['category'] === 'string') item.category = c['category']\n if (typeof c['install'] === 'string') item.install = c['install']\n if (typeof c['styles'] === 'string') item.styles = c['styles']\n if (c['meta']) item.meta = c['meta'] as RegistryItem['meta']\n return item\n }),\n }\n}\n","import type { RegistryItem, TemplateMeta, TemplateFileRole } from './types.ts'\n\nconst VALID_FRAMEWORKS = new Set(['react-vite', 'react-next'])\nconst VALID_FILE_ROLES = new Set<TemplateFileRole>(['page', 'fixture', 'asset', 'config'])\n\n/** True when an item is a template. */\nexport function isTemplateItem(item: RegistryItem): boolean {\n return item.type === 'template'\n}\n\n/**\n * Narrow an item's `meta` to a {@link TemplateMeta}, throwing on shape mismatch.\n * Use after {@link validateTemplate} has passed.\n */\nexport function asTemplateMeta(meta: unknown): TemplateMeta {\n const errors = validateTemplateMeta(meta)\n if (errors.length > 0) {\n throw new Error(`Invalid TemplateMeta: ${errors.join('; ')}`)\n }\n return meta as TemplateMeta\n}\n\nfunction validateTemplateMeta(meta: unknown): string[] {\n const errors: string[] = []\n if (!meta || typeof meta !== 'object') {\n return ['meta must be a TemplateMeta object']\n }\n const m = meta as Record<string, unknown>\n\n if (typeof m['intent'] !== 'string' || !m['intent']) {\n errors.push('meta.intent is required and must be a non-empty string')\n }\n if (!VALID_FRAMEWORKS.has(m['framework'] as string)) {\n errors.push(`meta.framework must be one of ${[...VALID_FRAMEWORKS].join('|')}`)\n }\n if (typeof m['category'] !== 'string' || !m['category']) {\n errors.push('meta.category is required and must be a non-empty string')\n }\n\n if (!Array.isArray(m['screenshots']) || m['screenshots'].length === 0) {\n errors.push('meta.screenshots is required and must have at least one entry')\n } else {\n for (let i = 0; i < m['screenshots'].length; i++) {\n const shot = m['screenshots'][i] as Record<string, unknown>\n if (!shot || typeof shot !== 'object') {\n errors.push(`meta.screenshots[${i}] must be an object`)\n continue\n }\n if (typeof shot['light'] !== 'string' || !shot['light'])\n errors.push(`meta.screenshots[${i}].light is required`)\n if (typeof shot['alt'] !== 'string' || !shot['alt'])\n errors.push(`meta.screenshots[${i}].alt is required`)\n }\n }\n\n if (m['demoUrl'] !== undefined && typeof m['demoUrl'] !== 'string') {\n errors.push('meta.demoUrl must be a string when present')\n }\n\n if (!m['fileRoles'] || typeof m['fileRoles'] !== 'object') {\n errors.push('meta.fileRoles is required and must be an object')\n } else {\n for (const [target, role] of Object.entries(m['fileRoles'] as Record<string, unknown>)) {\n if (!VALID_FILE_ROLES.has(role as TemplateFileRole)) {\n errors.push(`meta.fileRoles[\"${target}\"] must be one of ${[...VALID_FILE_ROLES].join('|')}`)\n }\n }\n }\n\n if (m['pages'] !== undefined) {\n if (!Array.isArray(m['pages'])) {\n errors.push('meta.pages must be an array when present')\n } else {\n for (let i = 0; i < m['pages'].length; i++) {\n const page = m['pages'][i] as Record<string, unknown>\n if (!page || typeof page !== 'object') {\n errors.push(`meta.pages[${i}] must be an object`)\n continue\n }\n if (typeof page['name'] !== 'string') errors.push(`meta.pages[${i}].name is required`)\n if (typeof page['target'] !== 'string') errors.push(`meta.pages[${i}].target is required`)\n }\n }\n }\n\n return errors\n}\n\n/**\n * Validate a template item beyond the base item schema. Returns a list of\n * errors (empty when valid). Requires:\n * - `type === 'template'`\n * - a valid {@link TemplateMeta}\n * - at least one component (`registryDependencies`) or one `page` file\n * - a non-empty `license`\n * - every `files[].target` present in `meta.fileRoles`\n */\nexport function validateTemplate(item: RegistryItem): string[] {\n const errors: string[] = []\n\n if (item.type !== 'template') {\n errors.push(`type must be 'template', got ${JSON.stringify(item.type)}`)\n return errors\n }\n\n const metaErrors = validateTemplateMeta(item.meta)\n errors.push(...metaErrors)\n\n const meta = (item.meta ?? {}) as Partial<TemplateMeta>\n const fileRoles = (meta.fileRoles ?? {}) as Record<string, TemplateFileRole>\n\n const hasComponents = Array.isArray(item.registryDependencies)\n ? item.registryDependencies.length > 0\n : false\n const hasPageFile = Object.values(fileRoles).includes('page')\n if (!hasComponents && !hasPageFile) {\n errors.push(\n 'a template must list at least one component in registryDependencies or one page file',\n )\n }\n\n if (typeof item.license !== 'string' || !item.license) {\n errors.push('license is required for a template')\n }\n\n for (const file of item.files ?? []) {\n if (!file.target) {\n errors.push(`template file ${JSON.stringify(file.url)} must declare a target`)\n } else if (metaErrors.length === 0 && !(file.target in fileRoles)) {\n errors.push(`file target \"${file.target}\" is missing from meta.fileRoles`)\n }\n }\n\n return errors\n}\n","import { mkdir, writeFile } from 'node:fs/promises'\nimport { join } from 'node:path'\nimport type { RegistryIndex, RegistryItem } from './types.ts'\n\nfunction flatName(name: string): string {\n return name.replace(/\\//g, '-')\n}\n\nfunction itemWithoutExamples(item: RegistryItem): RegistryItem {\n if (!item.meta || typeof item.meta !== 'object') return item\n const meta = item.meta as Record<string, unknown>\n if (!Array.isArray(meta['examples']) || meta['examples'].length === 0) return item\n return { ...item, meta: { ...meta, examples: [] } }\n}\n\nexport async function buildRegistry(index: RegistryIndex, outDir: string): Promise<void> {\n await mkdir(outDir, { recursive: true })\n\n const sortedItems = [...index.items].sort((a, b) => a.name.localeCompare(b.name))\n\n const indexOut: RegistryIndex = {\n schemaVersion: 2,\n name: index.name,\n ...(index.homepage ? { homepage: index.homepage } : {}),\n items: sortedItems.map(itemWithoutExamples),\n }\n await writeFile(join(outDir, 'registry.json'), `${JSON.stringify(indexOut, null, 2)}\\n`, 'utf8')\n\n for (const item of sortedItems) {\n const flat = flatName(item.name)\n await writeFile(join(outDir, `${flat}.json`), `${JSON.stringify(item, null, 2)}\\n`, 'utf8')\n await writeFile(\n join(outDir, `${flat}@${item.version}.json`),\n `${JSON.stringify(item, null, 2)}\\n`,\n 'utf8',\n )\n }\n}\n","/**\n * shadcn-registry-compatible projection of the cascivo registry.\n *\n * This is purely ADDITIVE interop: it maps cascivo's own `RegistryItem`s into\n * the shadcn `registry:*` item schema so the shadcn CLI can install a cascivo\n * component (`npx shadcn add <host>/r/shadcn/<name>.json`). cascivo's own\n * `registry.json` schema is untouched.\n *\n * cascivo is CSS-native: components ship `.tsx` + `.module.css` and rely on a\n * `@cascivo/themes` import plus the `@cascivo/core` peer — there is no Tailwind\n * config, so no `cssVars`/`tailwind` block is emitted.\n */\nimport { mkdir, writeFile } from 'node:fs/promises'\nimport { join } from 'node:path'\nimport type { RegistryIndex, RegistryItem, RegistryItemType } from './types.ts'\n\nconst SHADCN_ITEM_SCHEMA = 'https://ui.shadcn.com/schema/registry-item.json'\nconst SHADCN_REGISTRY_SCHEMA = 'https://ui.shadcn.com/schema/registry.json'\n\nexport type ShadcnItemType =\n | 'registry:component'\n | 'registry:block'\n | 'registry:lib'\n | 'registry:ui'\n | 'registry:hook'\n | 'registry:theme'\n | 'registry:style'\n | 'registry:file'\n\nexport interface ShadcnRegistryFile {\n path: string\n type: ShadcnItemType\n content?: string\n target?: string\n}\n\nexport interface ShadcnRegistryItem {\n $schema: string\n name: string\n type: ShadcnItemType\n description?: string\n dependencies?: string[]\n registryDependencies?: string[]\n files: ShadcnRegistryFile[]\n categories?: string[]\n meta?: Record<string, unknown>\n}\n\nexport interface ToShadcnOptions {\n /** Resolve a cascivo file URL to its source text, to inline as `content`. */\n resolveContent?: (fileUrl: string) => string | undefined\n}\n\nconst TYPE_MAP: Record<RegistryItemType, ShadcnItemType> = {\n component: 'registry:component',\n layout: 'registry:block',\n block: 'registry:block',\n section: 'registry:block',\n chart: 'registry:component',\n theme: 'registry:theme',\n style: 'registry:style',\n template: 'registry:block',\n}\n\n/** Flatten a possibly-prefixed cascivo name (\"block/x\") into a shadcn slug. */\nexport function shadcnName(name: string): string {\n return name.replace(/\\//g, '-')\n}\n\nfunction filePath(fileUrl: string, slug: string): string {\n const base = fileUrl.split('/').pop() ?? fileUrl\n return `${slug}/${base}`\n}\n\nexport function toShadcnItem(item: RegistryItem, opts: ToShadcnOptions = {}): ShadcnRegistryItem {\n const slug = shadcnName(item.name)\n const type = TYPE_MAP[item.type] ?? 'registry:component'\n\n const files: ShadcnRegistryFile[] = item.files.map((f) => {\n const file: ShadcnRegistryFile = { path: filePath(f.url, slug), type }\n const content = opts.resolveContent?.(f.url)\n if (content !== undefined) file.content = content\n return file\n })\n\n const out: ShadcnRegistryItem = {\n $schema: SHADCN_ITEM_SCHEMA,\n name: slug,\n type,\n files,\n }\n if (item.description) out.description = item.description\n if (item.dependencies.length > 0) out.dependencies = [...item.dependencies]\n if (item.registryDependencies && item.registryDependencies.length > 0) {\n out.registryDependencies = [...item.registryDependencies]\n }\n if (item.category) out.categories = [item.category]\n out.meta = { cascivo: { type: item.type, version: item.version } }\n return out\n}\n\n/**\n * Write one shadcn `r/<name>.json` per item (with inlined file content when a\n * resolver is supplied) plus a lean `registry.json` index (content omitted).\n */\nexport async function writeShadcnRegistry(\n index: RegistryIndex,\n outDir: string,\n opts: ToShadcnOptions = {},\n): Promise<void> {\n await mkdir(outDir, { recursive: true })\n\n const sorted = [...index.items].sort((a, b) => a.name.localeCompare(b.name))\n const items = sorted.map((it) => toShadcnItem(it, opts))\n\n for (const item of items) {\n await writeFile(join(outDir, `${item.name}.json`), `${JSON.stringify(item, null, 2)}\\n`, 'utf8')\n }\n\n const indexItems = items.map((it) => ({\n ...it,\n files: it.files.map((f) => ({\n path: f.path,\n type: f.type,\n ...(f.target ? { target: f.target } : {}),\n })),\n }))\n const registry = {\n $schema: SHADCN_REGISTRY_SCHEMA,\n name: index.name,\n ...(index.homepage ? { homepage: index.homepage } : {}),\n items: indexItems,\n }\n await writeFile(join(outDir, 'registry.json'), `${JSON.stringify(registry, null, 2)}\\n`, 'utf8')\n}\n","import type { RegistryAdvisory, RegistryItem } from './types.ts'\n\nfunction parseVersionParts(v: string): number[] {\n return v\n .replace(/^[^0-9]*/, '')\n .split('.')\n .map(Number)\n}\n\nfunction compareVersions(a: string, b: string): number {\n const pa = parseVersionParts(a)\n const pb = parseVersionParts(b)\n for (let i = 0; i < Math.max(pa.length, pb.length); i++) {\n const na = pa[i] ?? 0\n const nb = pb[i] ?? 0\n if (na !== nb) return na - nb\n }\n return 0\n}\n\nfunction matchesRange(version: string, range: string): boolean {\n try {\n const trimmed = range.trim()\n if (trimmed.startsWith('>=')) {\n return compareVersions(version, trimmed.slice(2).trim()) >= 0\n }\n if (trimmed.startsWith('>')) {\n return compareVersions(version, trimmed.slice(1).trim()) > 0\n }\n if (trimmed.startsWith('<=')) {\n return compareVersions(version, trimmed.slice(2).trim()) <= 0\n }\n if (trimmed.startsWith('<')) {\n return compareVersions(version, trimmed.slice(1).trim()) < 0\n }\n if (trimmed.startsWith('^')) {\n const base = trimmed.slice(1).trim()\n const baseParts = parseVersionParts(base)\n const major = baseParts[0] ?? 0\n const vParts = parseVersionParts(version)\n const vMajor = vParts[0] ?? 0\n return vMajor === major && compareVersions(version, base) >= 0\n }\n if (trimmed.startsWith('~')) {\n const base = trimmed.slice(1).trim()\n const baseParts = parseVersionParts(base)\n const major = baseParts[0] ?? 0\n const minor = baseParts[1] ?? 0\n const vParts = parseVersionParts(version)\n const vMajor = vParts[0] ?? 0\n const vMinor = vParts[1] ?? 0\n return vMajor === major && vMinor === minor && compareVersions(version, base) >= 0\n }\n return version === trimmed\n } catch {\n return false\n }\n}\n\nexport function matchAdvisories(\n item: Pick<RegistryItem, 'advisories'>,\n lockedVersion: string,\n): RegistryAdvisory[] {\n if (!item.advisories) return []\n const matched: RegistryAdvisory[] = []\n for (const adv of item.advisories) {\n try {\n if (matchesRange(lockedVersion, adv.affectedVersions)) {\n matched.push(adv)\n }\n } catch {\n // malformed range — skip silently, never crash an audit\n }\n }\n return matched\n}\n","/** What kinds of items a directory-listed registry publishes. */\nexport type DirectoryProvides = 'component' | 'template' | 'theme'\n\nexport interface DirectoryEntry {\n namespace: string\n name: string\n description: string\n homepage: string\n registryUrl: string\n tags: string[]\n verified: boolean\n /** Item kinds this registry provides. Absent ⇒ component-only. */\n provides?: DirectoryProvides[]\n}\n\nconst VALID_PROVIDES = new Set<DirectoryProvides>(['component', 'template', 'theme'])\n\nexport interface RegistryDirectory {\n schemaVersion: 1\n registries: DirectoryEntry[]\n}\n\nexport interface DirectoryValidationResult {\n ok: boolean\n errors: string[]\n warnings: string[]\n}\n\nfunction levenshtein(a: string, b: string): number {\n const m = a.length\n const n = b.length\n const dp: number[][] = Array.from({ length: m + 1 }, (_, i) =>\n Array.from({ length: n + 1 }, (_, j) => (i === 0 ? j : j === 0 ? i : 0)),\n )\n for (let i = 1; i <= m; i++) {\n for (let j = 1; j <= n; j++) {\n dp[i]![j] =\n a[i - 1] === b[j - 1]\n ? dp[i - 1]![j - 1]!\n : 1 + Math.min(dp[i - 1]![j]!, dp[i]![j - 1]!, dp[i - 1]![j - 1]!)\n }\n }\n return dp[m]![n]!\n}\n\nexport function validateDirectory(raw: unknown): DirectoryValidationResult {\n if (!raw || typeof raw !== 'object') {\n return { ok: false, errors: ['Directory must be an object'], warnings: [] }\n }\n const obj = raw as Record<string, unknown>\n const errors: string[] = []\n const warnings: string[] = []\n\n if (obj['schemaVersion'] !== 1) {\n errors.push(`schemaVersion must be 1, got ${JSON.stringify(obj['schemaVersion'])}`)\n }\n if (!Array.isArray(obj['registries'])) {\n errors.push('registries must be an array')\n return { ok: false, errors, warnings }\n }\n\n const namespaces: string[] = []\n for (let i = 0; i < obj['registries'].length; i++) {\n const entry = obj['registries'][i] as Record<string, unknown>\n const ns = entry['namespace']\n if (typeof ns !== 'string' || !ns) errors.push(`registries[${i}].namespace is required`)\n else {\n if (namespaces.includes(ns)) errors.push(`Duplicate namespace \"${ns}\" at index ${i}`)\n namespaces.push(ns)\n }\n if (typeof entry['name'] !== 'string') errors.push(`registries[${i}].name is required`)\n if (typeof entry['description'] !== 'string')\n errors.push(`registries[${i}].description is required`)\n if (typeof entry['homepage'] !== 'string') errors.push(`registries[${i}].homepage is required`)\n if (typeof entry['registryUrl'] !== 'string')\n errors.push(`registries[${i}].registryUrl is required`)\n else if (!(entry['registryUrl'] as string).includes('{name}'))\n errors.push(`registries[${i}].registryUrl must contain {name} placeholder`)\n if (!Array.isArray(entry['tags'])) errors.push(`registries[${i}].tags must be an array`)\n if (typeof entry['verified'] !== 'boolean')\n errors.push(`registries[${i}].verified must be a boolean`)\n if (entry['provides'] !== undefined) {\n if (!Array.isArray(entry['provides'])) {\n errors.push(`registries[${i}].provides must be an array when present`)\n } else {\n for (const p of entry['provides'] as unknown[]) {\n if (!VALID_PROVIDES.has(p as DirectoryProvides))\n errors.push(\n `registries[${i}].provides has invalid value ${JSON.stringify(p)} (allowed: ${[...VALID_PROVIDES].join('|')})`,\n )\n }\n }\n }\n }\n\n for (let i = 0; i < namespaces.length; i++) {\n for (let j = i + 1; j < namespaces.length; j++) {\n const a = namespaces[i]!\n const b = namespaces[j]!\n if (levenshtein(a, b) <= 2) {\n warnings.push(\n `Namespaces \"${a}\" and \"${b}\" are suspiciously similar (Levenshtein distance ≤ 2)`,\n )\n }\n }\n }\n\n return { ok: errors.length === 0, errors, warnings }\n}\n","import type { RegistryItem, TemplateScreenshot } from './types.ts'\nimport { isTemplateItem, asTemplateMeta } from './template.ts'\n\n/** A template projected into a flat, gallery-ready record. */\nexport interface MarketplaceTemplate {\n name: string\n namespace: string\n description: string\n category: string\n framework: string\n tags: string[]\n /** Component names the template composes (from `registryDependencies`). */\n components: string[]\n screenshots: TemplateScreenshot[]\n demoUrl?: string\n version: string\n license: string\n verified: boolean\n homepage?: string\n /** The spec a user passes to `cascivo add` (e.g. \"@acme/dashboard\"). */\n installSpec: string\n /** GitHub stars, baked at CI build time (omitted when unknown). */\n stars?: number\n}\n\n/** The static marketplace catalog written to `apps/site/public/marketplace.json`. */\nexport interface MarketplaceCatalog {\n generatedAt: string\n templates: MarketplaceTemplate[]\n facets: { categories: string[]; frameworks: string[]; tags: string[] }\n}\n\n/** One registry's resolved index + the directory metadata that referenced it. */\nexport interface MarketplaceSource {\n entry: { namespace: string; verified?: boolean; homepage?: string; stars?: number }\n items: RegistryItem[]\n}\n\n/**\n * Project a template item into a gallery record, or `null` if the item is not a\n * valid template. Pure — no I/O.\n */\nexport function projectTemplate(\n item: RegistryItem,\n source: MarketplaceSource['entry'],\n): MarketplaceTemplate | null {\n if (!isTemplateItem(item)) return null\n let meta\n try {\n meta = asTemplateMeta(item.meta)\n } catch {\n return null\n }\n const record: MarketplaceTemplate = {\n name: item.name,\n namespace: source.namespace,\n description: item.description,\n category: meta.category,\n framework: meta.framework,\n tags: item.tags ?? [],\n components: item.registryDependencies ?? [],\n screenshots: meta.screenshots,\n version: item.version,\n license: item.license ?? '',\n verified: source.verified ?? false,\n installSpec: `${source.namespace}/${item.name}`,\n }\n if (meta.demoUrl) record.demoUrl = meta.demoUrl\n const homepage = item.homepage ?? source.homepage\n if (homepage) record.homepage = homepage\n if (typeof source.stars === 'number') record.stars = source.stars\n return record\n}\n\nfunction uniqueSorted(values: string[]): string[] {\n return [...new Set(values)].sort((a, b) => a.localeCompare(b))\n}\n\n/**\n * Build the marketplace catalog from a set of resolved registry sources. Pure —\n * the caller does the fetching + star lookups and supplies the timestamp.\n * Templates are sorted verified-first, then by stars (desc), then by name.\n */\nexport function buildCatalog(\n sources: MarketplaceSource[],\n generatedAt: string,\n): MarketplaceCatalog {\n const templates: MarketplaceTemplate[] = []\n for (const src of sources) {\n for (const item of src.items) {\n const record = projectTemplate(item, src.entry)\n if (record) templates.push(record)\n }\n }\n\n templates.sort((a, b) => {\n if (a.verified !== b.verified) return a.verified ? -1 : 1\n const sa = a.stars ?? 0\n const sb = b.stars ?? 0\n if (sa !== sb) return sb - sa\n return a.name.localeCompare(b.name)\n })\n\n return {\n generatedAt,\n templates,\n facets: {\n categories: uniqueSorted(templates.map((t) => t.category)),\n frameworks: uniqueSorted(templates.map((t) => t.framework)),\n tags: uniqueSorted(templates.flatMap((t) => t.tags)),\n },\n }\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cascivo/registry",
3
- "version": "0.1.5",
3
+ "version": "0.1.10",
4
4
  "private": false,
5
5
  "description": "Registry schema v2 types, validation, and static build for the cascivo ecosystem",
6
6
  "keywords": [
package/readme.body.md CHANGED
@@ -1,8 +1,32 @@
1
- Registry client and type definitions reads `registry.json` and validates component entries. Used internally by the CLI and MCP server.
1
+ The **registry schema v2** for the cascivo ecosystem: TypeScript types, validation, the static registry build, and a shadcn-interop projection. If a tool reads or writes `registry.json`, this package defines what "valid" means.
2
+
3
+ Consumers in this repo: the `cascivo` CLI (`add`, `view`, `search`, `update`, `template init`, `registry build`), the registry generation pipeline (`scripts/registry/generate.ts`, which emits the root `registry.json` + per-item payloads), and the docs site. Third-party registries use it to build and validate their own indexes.
4
+
5
+ ## Exports
6
+
7
+ **Types** — `RegistryIndex` (the `registry.json` shape: `schemaVersion: 2` + `items`), `RegistryItem` (one entry: `name`, `type`, `version`, `files`, `dependencies`, `registryDependencies`, `tags`, optional `advisories`/`meta`), `RegistryItemType` (`component | layout | block | chart | section | theme | style | template`), plus template metadata (`TemplateMeta`, `TemplateScreenshot`, `TemplateFileRole`) and directory/marketplace types.
8
+
9
+ **Validation**
10
+
11
+ ```ts
12
+ import { validateIndex, validateItem } from '@cascivo/registry'
13
+
14
+ const result = validateIndex(JSON.parse(raw)) // { valid, errors: [{ path, message }] }
15
+ ```
16
+
17
+ `validateItem` checks a single entry; `validateIndex` the whole index. `parseLegacyRegistry` upgrades the pre-v2 flat format (`{ version, components }`) into a v2 `RegistryIndex`.
18
+
19
+ **Static build** — `buildRegistry(index, outDir)` writes a hostable registry: a sorted `registry.json` (examples stripped from the index for size) plus one JSON payload per item. This is what `cascivo registry build` runs under the hood, so anyone can serve a registry from a static file host.
20
+
21
+ **Templates** — `isTemplateItem`, `asTemplateMeta`, `validateTemplate` for `type: 'template'` entries (whole-page compositions riding the normal registry transport), and `projectTemplate`/`buildCatalog` to project them into the marketplace catalog.
22
+
23
+ **Advisories** — `matchAdvisories` matches an item's advisories (`severity`, `affectedVersions`, `fixedIn`) against an installed version, so clients can warn on install/update.
24
+
25
+ **Directory** — `validateDirectory` for the multi-registry directory format (namespace → registry URL) behind `cascivo search --registry @ns` and the MCP `list_registries` tool.
2
26
 
3
27
  ## shadcn registry interop
4
28
 
5
- In addition to cascivo's own registry, the build emits a **shadcn-registry-compatible** projection so the shadcn CLI can install a cascivo component directly:
29
+ In addition to cascivo's own registry, the build emits a **shadcn-registry-compatible** projection (`toShadcnItem`, `writeShadcnRegistry`) so the shadcn CLI can install a cascivo component directly:
6
30
 
7
31
  ```sh
8
32
  npx shadcn add https://<host>/r/shadcn/button.json