@beechcms/cms 0.6.0-preview.1 → 0.6.0-preview.2

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.
@@ -1,35 +1,35 @@
1
- /** Post: blog article with rich text, cover image, tags and SEO */
2
- export const POST_SEED: Seed = {
3
- slug: 'posts',
4
- label: 'Post',
5
- labelPlural: 'Posts',
6
- displayNameAlias: 'title',
7
- allowPublicRead: true,
8
- allowDrafts: true,
9
- branches: [
10
- { id: 'pst_01', alias: 'title', label: 'Title', type: 'text', requiredOnCreate: true },
11
- { id: 'pst_02', alias: 'publishedAt', label: 'Published at', type: 'date' },
12
- { id: 'pst_03', alias: 'coverImage', label: 'Cover image', type: 'file', fileOptions: { accept: 'image' } },
13
- { id: 'pst_04', alias: 'excerpt', label: 'Excerpt', type: 'text' },
14
- { id: 'pst_05', alias: 'tags', label: 'Tags', type: 'json', options: ['news', 'tutorial', 'release', 'guide', 'opinion'] },
15
- { id: 'pst_06', alias: 'body', label: 'Body', type: 'richtext' },
16
- { id: 'pst_07', alias: 'metaTitle', label: 'Meta title (SEO)', type: 'text' },
17
- { id: 'pst_08', alias: 'metaDescription', label: 'Meta description (SEO)', type: 'text' },
18
- ],
19
- }
20
-
21
- /** Author: content creator profile with photo and social link */
22
- export const AUTHOR_SEED: Seed = {
23
- slug: 'authors',
24
- label: 'Author',
25
- labelPlural: 'Authors',
26
- displayNameAlias: 'name',
27
- allowPublicRead: true,
28
- branches: [
29
- { id: 'aut_01', alias: 'name', label: 'Name', type: 'text', requiredOnCreate: true },
30
- { id: 'aut_02', alias: 'bio', label: 'Bio', type: 'text' },
31
- { id: 'aut_03', alias: 'photo', label: 'Photo', type: 'file', fileOptions: { accept: 'image' } },
32
- { id: 'aut_04', alias: 'website', label: 'Website URL', type: 'text' },
33
- { id: 'aut_05', alias: 'active', label: 'Active', type: 'boolean' },
34
- ],
35
- }
1
+ /** Post: blog article with rich text, cover image, tags and SEO */
2
+ export const POST_SEED: Seed = {
3
+ slug: 'posts',
4
+ label: 'Post',
5
+ labelPlural: 'Posts',
6
+ displayNameAlias: 'title',
7
+ allowPublicRead: true,
8
+ allowDrafts: true,
9
+ branches: [
10
+ { id: 'pst_01', alias: 'title', label: 'Title', type: 'text', requiredOnCreate: true },
11
+ { id: 'pst_02', alias: 'publishedAt', label: 'Published at', type: 'date' },
12
+ { id: 'pst_03', alias: 'coverImage', label: 'Cover image', type: 'file', fileOptions: { accept: 'image' } },
13
+ { id: 'pst_04', alias: 'excerpt', label: 'Excerpt', type: 'text' },
14
+ { id: 'pst_05', alias: 'tags', label: 'Tags', type: 'json', options: ['news', 'tutorial', 'release', 'guide', 'opinion'] },
15
+ { id: 'pst_06', alias: 'body', label: 'Body', type: 'richtext' },
16
+ { id: 'pst_07', alias: 'metaTitle', label: 'Meta title (SEO)', type: 'text' },
17
+ { id: 'pst_08', alias: 'metaDescription', label: 'Meta description (SEO)', type: 'text' },
18
+ ],
19
+ }
20
+
21
+ /** Author: content creator profile with photo and social link */
22
+ export const AUTHOR_SEED: Seed = {
23
+ slug: 'authors',
24
+ label: 'Author',
25
+ labelPlural: 'Authors',
26
+ displayNameAlias: 'name',
27
+ allowPublicRead: true,
28
+ branches: [
29
+ { id: 'aut_01', alias: 'name', label: 'Name', type: 'text', requiredOnCreate: true },
30
+ { id: 'aut_02', alias: 'bio', label: 'Bio', type: 'text' },
31
+ { id: 'aut_03', alias: 'photo', label: 'Photo', type: 'file', fileOptions: { accept: 'image' } },
32
+ { id: 'aut_04', alias: 'website', label: 'Website URL', type: 'text' },
33
+ { id: 'aut_05', alias: 'active', label: 'Active', type: 'boolean' },
34
+ ],
35
+ }
@@ -1,29 +1,29 @@
1
- /** Product: e-commerce product catalog with prices, inventory and ratings */
2
- export const PRODUCT_SEED: Seed = {
3
- slug: 'products',
4
- label: 'Product',
5
- labelPlural: 'Products',
6
- displayNameAlias: 'name',
7
- allowPublicRead: true,
8
- branches: [
9
- { alias: 'name', label: 'Product Name', type: 'text', requiredOnCreate: true },
10
- { alias: 'description', label: 'Description', type: 'richtext' },
11
- { alias: 'price', label: 'Price', type: 'number', numberOptions: { format: 'currency', currency: 'EUR', decimals: 2, min: 0, control: 'input', prefix: '€' } },
12
- { alias: 'inventory', label: 'Stock level', type: 'number', numberOptions: { min: 0, step: 1, control: 'stepper' } },
13
- { alias: 'rating', label: 'Rating', type: 'number', numberOptions: { min: 1, max: 5, step: 0.5, control: 'rating' } }
14
- ],
15
- }
16
-
17
- /** Review: product review */
18
- export const REVIEW_SEED: Seed = {
19
- slug: 'reviews',
20
- label: 'Review',
21
- labelPlural: 'Reviews',
22
- displayNameAlias: 'title',
23
- allowPublicRead: true,
24
- branches: [
25
- { alias: 'title', label: 'Review Title', type: 'text', requiredOnCreate: true },
26
- { alias: 'body', label: 'Body', type: 'text' },
27
- { alias: 'score', label: 'Score', type: 'number', numberOptions: { min: 1, max: 5, step: 1, control: 'rating' } }
28
- ],
29
- }
1
+ /** Product: e-commerce product catalog with prices, inventory and ratings */
2
+ export const PRODUCT_SEED: Seed = {
3
+ slug: 'products',
4
+ label: 'Product',
5
+ labelPlural: 'Products',
6
+ displayNameAlias: 'name',
7
+ allowPublicRead: true,
8
+ branches: [
9
+ { alias: 'name', label: 'Product Name', type: 'text', requiredOnCreate: true },
10
+ { alias: 'description', label: 'Description', type: 'richtext' },
11
+ { alias: 'price', label: 'Price', type: 'number', numberOptions: { format: 'currency', currency: 'EUR', decimals: 2, min: 0, control: 'input', prefix: '€' } },
12
+ { alias: 'inventory', label: 'Stock level', type: 'number', numberOptions: { min: 0, step: 1, control: 'stepper' } },
13
+ { alias: 'rating', label: 'Rating', type: 'number', numberOptions: { min: 1, max: 5, step: 0.5, control: 'rating' } }
14
+ ],
15
+ }
16
+
17
+ /** Review: product review */
18
+ export const REVIEW_SEED: Seed = {
19
+ slug: 'reviews',
20
+ label: 'Review',
21
+ labelPlural: 'Reviews',
22
+ displayNameAlias: 'title',
23
+ allowPublicRead: true,
24
+ branches: [
25
+ { alias: 'title', label: 'Review Title', type: 'text', requiredOnCreate: true },
26
+ { alias: 'body', label: 'Body', type: 'text' },
27
+ { alias: 'score', label: 'Score', type: 'number', numberOptions: { min: 1, max: 5, step: 1, control: 'rating' } }
28
+ ],
29
+ }
@@ -1,23 +1,23 @@
1
- /**
2
- * Message: public contact form submission.
3
- *
4
- * allowPublicPost: true — the Public API accepts POST requests without authentication,
5
- * so any frontend form can submit directly to this seed.
6
- * email visibility:masked — the email is stored in full but returned partially
7
- * redacted in API responses (e.g. "jo**@example.com").
8
- * email public:false — the email is never exposed through the Public API.
9
- */
10
- export const MESSAGE_SEED: Seed = {
11
- slug: 'messages',
12
- label: 'Message',
13
- labelPlural: 'Messages',
14
- displayNameAlias: 'name',
15
- allowPublicPost: true,
16
- branches: [
17
- { id: 'msg_01', alias: 'name', label: 'Name', type: 'text', requiredOnCreate: true },
18
- { id: 'msg_02', alias: 'email', label: 'Email', type: 'text', requiredOnCreate: true, policies: { visibility: 'masked', public: false } },
19
- { id: 'msg_03', alias: 'subject', label: 'Subject', type: 'text', requiredOnCreate: true },
20
- { id: 'msg_04', alias: 'message', label: 'Message', type: 'richtext', requiredOnCreate: true },
21
- { id: 'msg_05', alias: 'read', label: 'Read', type: 'boolean' },
22
- ],
23
- }
1
+ /**
2
+ * Message: public contact form submission.
3
+ *
4
+ * allowPublicPost: true — the Public API accepts POST requests without authentication,
5
+ * so any frontend form can submit directly to this seed.
6
+ * email visibility:masked — the email is stored in full but returned partially
7
+ * redacted in API responses (e.g. "jo**@example.com").
8
+ * email public:false — the email is never exposed through the Public API.
9
+ */
10
+ export const MESSAGE_SEED: Seed = {
11
+ slug: 'messages',
12
+ label: 'Message',
13
+ labelPlural: 'Messages',
14
+ displayNameAlias: 'name',
15
+ allowPublicPost: true,
16
+ branches: [
17
+ { id: 'msg_01', alias: 'name', label: 'Name', type: 'text', requiredOnCreate: true },
18
+ { id: 'msg_02', alias: 'email', label: 'Email', type: 'text', requiredOnCreate: true, policies: { visibility: 'masked', public: false } },
19
+ { id: 'msg_03', alias: 'subject', label: 'Subject', type: 'text', requiredOnCreate: true },
20
+ { id: 'msg_04', alias: 'message', label: 'Message', type: 'richtext', requiredOnCreate: true },
21
+ { id: 'msg_05', alias: 'read', label: 'Read', type: 'boolean' },
22
+ ],
23
+ }
@@ -1,41 +1,41 @@
1
- /**
2
- * Your seeds go here.
3
- *
4
- * A Seed defines a content type: its slug (used in API URLs), its display labels,
5
- * and its branches (fields).
6
- *
7
- * Each Branch has:
8
- * id — immutable database key (e.g. 'abc_01'). Never change this after
9
- * the first migration or stored data will break.
10
- * alias — the name used in API payloads (e.g. 'title'). Safe to rename.
11
- * label — human-readable label shown in the dashboard.
12
- * type — 'text' | 'number' | 'boolean' | 'date' | 'richtext' | 'file' | 'json'
13
- *
14
- * Seed-level flags:
15
- * allowPublicRead — expose entries via the unauthenticated Public API (GET).
16
- * allowPublicPost — accept submissions via the Public API (POST). Useful for forms.
17
- * allowDrafts — enable a pending-draft workflow for this content type.
18
- * displayNameAlias — which branch alias is used as the entry title in the dashboard.
19
- *
20
- * Branch policies (all optional):
21
- * policies.visibility — 'full' (default) | 'masked' | 'hidden'
22
- * policies.public — false to exclude the field from Public API responses
23
- * policies.search — false to exclude the field from full-text search
24
- *
25
- * Example — uncomment and adapt to define your first content type:
26
- *
27
- * export const PROJECT_SEED: Seed = {
28
- * slug: 'projects',
29
- * label: 'Project',
30
- * labelPlural: 'Projects',
31
- * displayNameAlias: 'title',
32
- * allowPublicRead: true,
33
- * branches: [
34
- * { id: 'prj_01', alias: 'title', label: 'Title', type: 'text', requiredOnCreate: true },
35
- * { id: 'prj_02', alias: 'description', label: 'Description', type: 'text' },
36
- * { id: 'prj_03', alias: 'coverImage', label: 'Cover image', type: 'file' },
37
- * { id: 'prj_04', alias: 'tags', label: 'Tags', type: 'json' },
38
- * { id: 'prj_05', alias: 'published', label: 'Published', type: 'boolean' },
39
- * ],
40
- * }
41
- */
1
+ /**
2
+ * Your seeds go here.
3
+ *
4
+ * A Seed defines a content type: its slug (used in API URLs), its display labels,
5
+ * and its branches (fields).
6
+ *
7
+ * Each Branch has:
8
+ * id — immutable database key (e.g. 'abc_01'). Never change this after
9
+ * the first migration or stored data will break.
10
+ * alias — the name used in API payloads (e.g. 'title'). Safe to rename.
11
+ * label — human-readable label shown in the dashboard.
12
+ * type — 'text' | 'number' | 'boolean' | 'date' | 'richtext' | 'file' | 'json'
13
+ *
14
+ * Seed-level flags:
15
+ * allowPublicRead — expose entries via the unauthenticated Public API (GET).
16
+ * allowPublicPost — accept submissions via the Public API (POST). Useful for forms.
17
+ * allowDrafts — enable a pending-draft workflow for this content type.
18
+ * displayNameAlias — which branch alias is used as the entry title in the dashboard.
19
+ *
20
+ * Branch policies (all optional):
21
+ * policies.visibility — 'full' (default) | 'masked' | 'hidden'
22
+ * policies.public — false to exclude the field from Public API responses
23
+ * policies.search — false to exclude the field from full-text search
24
+ *
25
+ * Example — uncomment and adapt to define your first content type:
26
+ *
27
+ * export const PROJECT_SEED: Seed = {
28
+ * slug: 'projects',
29
+ * label: 'Project',
30
+ * labelPlural: 'Projects',
31
+ * displayNameAlias: 'title',
32
+ * allowPublicRead: true,
33
+ * branches: [
34
+ * { id: 'prj_01', alias: 'title', label: 'Title', type: 'text', requiredOnCreate: true },
35
+ * { id: 'prj_02', alias: 'description', label: 'Description', type: 'text' },
36
+ * { id: 'prj_03', alias: 'coverImage', label: 'Cover image', type: 'file' },
37
+ * { id: 'prj_04', alias: 'tags', label: 'Tags', type: 'json' },
38
+ * { id: 'prj_05', alias: 'published', label: 'Published', type: 'boolean' },
39
+ * ],
40
+ * }
41
+ */
@@ -1,16 +1,16 @@
1
- /** Gallery item: image or media asset with title, tags and featured flag */
2
- export const GALLERY_SEED: Seed = {
3
- slug: 'gallery',
4
- label: 'Item',
5
- labelPlural: 'Gallery',
6
- displayNameAlias: 'title',
7
- allowPublicRead: true,
8
- branches: [
9
- { id: 'gal_01', alias: 'title', label: 'Title', type: 'text', requiredOnCreate: true },
10
- { id: 'gal_02', alias: 'description', label: 'Description', type: 'text' },
11
- { id: 'gal_03', alias: 'image', label: 'Image', type: 'file', requiredOnCreate: true, fileOptions: { accept: 'image' } },
12
- { id: 'gal_04', alias: 'tags', label: 'Tags', type: 'json' },
13
- { id: 'gal_05', alias: 'date', label: 'Date', type: 'date' },
14
- { id: 'gal_06', alias: 'featured', label: 'Featured', type: 'boolean' },
15
- ],
16
- }
1
+ /** Gallery item: image or media asset with title, tags and featured flag */
2
+ export const GALLERY_SEED: Seed = {
3
+ slug: 'gallery',
4
+ label: 'Item',
5
+ labelPlural: 'Gallery',
6
+ displayNameAlias: 'title',
7
+ allowPublicRead: true,
8
+ branches: [
9
+ { id: 'gal_01', alias: 'title', label: 'Title', type: 'text', requiredOnCreate: true },
10
+ { id: 'gal_02', alias: 'description', label: 'Description', type: 'text' },
11
+ { id: 'gal_03', alias: 'image', label: 'Image', type: 'file', requiredOnCreate: true, fileOptions: { accept: 'image' } },
12
+ { id: 'gal_04', alias: 'tags', label: 'Tags', type: 'json' },
13
+ { id: 'gal_05', alias: 'date', label: 'Date', type: 'date' },
14
+ { id: 'gal_06', alias: 'featured', label: 'Featured', type: 'boolean' },
15
+ ],
16
+ }
@@ -1,12 +1,12 @@
1
- /** Task: project management tasks with progress slider */
2
- export const TASK_SEED: Seed = {
3
- slug: 'tasks',
4
- label: 'Task',
5
- labelPlural: 'Tasks',
6
- displayNameAlias: 'title',
7
- branches: [
8
- { alias: 'title', label: 'Task Title', type: 'text', requiredOnCreate: true },
9
- { alias: 'taskStatus', label: 'Status', type: 'text', options: ['todo', 'in_progress', 'done'] },
10
- { alias: 'completion', label: 'Completion', type: 'number', numberOptions: { format: 'percentage', min: 0, max: 100, step: 5, control: 'slider' } }
11
- ],
12
- }
1
+ /** Task: project management tasks with progress slider */
2
+ export const TASK_SEED: Seed = {
3
+ slug: 'tasks',
4
+ label: 'Task',
5
+ labelPlural: 'Tasks',
6
+ displayNameAlias: 'title',
7
+ branches: [
8
+ { alias: 'title', label: 'Task Title', type: 'text', requiredOnCreate: true },
9
+ { alias: 'taskStatus', label: 'Status', type: 'text', options: ['todo', 'in_progress', 'done'] },
10
+ { alias: 'completion', label: 'Completion', type: 'number', numberOptions: { format: 'percentage', min: 0, max: 100, step: 5, control: 'slider' } }
11
+ ],
12
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@beechcms/cms",
3
- "version": "0.6.0-preview.1",
3
+ "version": "0.6.0-preview.2",
4
4
  "packageManager": "npm@11.9.0",
5
5
  "description": "Edge-Native, Schema-Driven Headless CMS built on Cloudflare Workers, D1, and R2. Features the Botanical Engine for alias-stable field management, a modular widget layer, and a React + Vite admin dashboard.",
6
6
  "keywords": [
@@ -28,7 +28,8 @@
28
28
  },
29
29
  "workspaces": [
30
30
  "apps/*",
31
- "packages/*"
31
+ "packages/*",
32
+ "examples/*"
32
33
  ],
33
34
  "files": [
34
35
  "bin/",
@@ -44,6 +45,7 @@
44
45
  "scripts": {
45
46
  "dev": "node scripts/dev.mjs",
46
47
  "dev:full": "node scripts/dev.mjs",
48
+ "dev:plain": "cross-env BEECH_DEV_PLAIN=1 node scripts/dev.mjs",
47
49
  "dev:tunnel-url": "docker compose logs tunnel 2>&1 | grep -Eo 'https://[a-z0-9-]+\\.trycloudflare\\.com' | tail -n 1",
48
50
  "dev:logs:mailpit": "docker compose logs -f mailpit",
49
51
  "dev:logs:sqlite": "docker compose logs -f sqlite-web",
@@ -55,6 +57,8 @@
55
57
  "build": "turbo run build",
56
58
  "test": "turbo run test",
57
59
  "test:coverage": "turbo run test:coverage",
60
+ "test:diff": "node scripts/test-coverage-diff.mjs",
61
+ "test:dev-cli": "vitest run --config scripts/dev-cli/vitest.config.ts",
58
62
  "setup:graph": "node scripts/setup-graph.mjs",
59
63
  "release": "node scripts/release.mjs",
60
64
  "release:preview": "node scripts/release.mjs --preview",
@@ -65,14 +69,25 @@
65
69
  "type": "module",
66
70
  "devDependencies": {
67
71
  "@vitest/coverage-v8": "^4.1.0",
72
+ "cross-env": "^10.1.0",
73
+ "execa": "^9.6.1",
68
74
  "husky": "^9.1.7",
75
+ "ink": "^6.8.0",
76
+ "ink-spinner": "^5.0.0",
77
+ "ink-testing-library": "^4.0.0",
78
+ "react": "^19.2.7",
79
+ "react-dom": "^19.2.7",
69
80
  "react-doctor": "^0.2.16",
70
81
  "shadcn": "^4.4.0",
82
+ "strip-ansi": "^7.2.0",
83
+ "tsx": "^4.22.4",
71
84
  "turbo": "^2.9.16",
72
85
  "typescript": "^5.9.3",
73
86
  "vitest": "^4.1.0"
74
87
  },
75
88
  "overrides": {
89
+ "react": "^19.2.7",
90
+ "react-dom": "^19.2.7",
76
91
  "qs": "^6.15.2",
77
92
  "ws": "^8.21.0",
78
93
  "miniflare": {
@@ -83,13 +98,13 @@
83
98
  }
84
99
  },
85
100
  "dependencies": {
86
- "@beechcms/cli": "^0.6.0-preview.1",
101
+ "@beechcms/cli": "^0.6.0-preview.2",
87
102
  "@clack/prompts": "^0.9.1",
88
103
  "picocolors": "^1.1.1"
89
104
  },
90
105
  "peerDependencies": {
91
- "@beechcms/api": "^0.6.0-preview.1",
92
- "@beechcms/core": "^0.6.0-preview.1"
106
+ "@beechcms/api": "^0.6.0-preview.2",
107
+ "@beechcms/core": "^0.6.0-preview.2"
93
108
  },
94
109
  "peerDependenciesMeta": {
95
110
  "@beechcms/api": {