@beechcms/cms 0.8.0 → 0.9.0
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/README.md +1 -0
- package/bin/cli.mjs +143 -28
- package/bin/create.mjs +5 -0
- package/package.json +16 -10
package/README.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.github/README.md
|
package/bin/cli.mjs
CHANGED
|
@@ -5,7 +5,7 @@ import pc from 'picocolors'
|
|
|
5
5
|
|
|
6
6
|
let [,, command, ...args] = process.argv
|
|
7
7
|
|
|
8
|
-
if (command && args[0] && ['db', 'seed', 'schema', 'dev', 'generate', 'mailpit'].includes(command)) {
|
|
8
|
+
if (command && args[0] && !args[0].startsWith('-') && ['db', 'seed', 'schema', 'types', 'dev', 'generate', 'mailpit'].includes(command)) {
|
|
9
9
|
command = `${command}:${args.shift()}`
|
|
10
10
|
}
|
|
11
11
|
|
|
@@ -22,6 +22,13 @@ const COMMANDS = {
|
|
|
22
22
|
'seed:load': cmdSeedLoad,
|
|
23
23
|
'seed:create': cmdSeedCreate,
|
|
24
24
|
'schema:diff': cmdSchemaDiff,
|
|
25
|
+
'schema:audit': cmdSchemaAudit,
|
|
26
|
+
'schema:migrate': cmdSchemaMigrate,
|
|
27
|
+
'schema:export': cmdSchemaExport,
|
|
28
|
+
'schema:plan': cmdSchemaPlan,
|
|
29
|
+
'schema:apply': cmdSchemaApply,
|
|
30
|
+
'types:generate': cmdGenerateTypes,
|
|
31
|
+
'types:check': cmdTypesCheck,
|
|
25
32
|
'init': cmdInit,
|
|
26
33
|
'validate': cmdValidate,
|
|
27
34
|
'deploy': cmdDeploy,
|
|
@@ -72,12 +79,39 @@ function help() {
|
|
|
72
79
|
${pc.cyan('db:reset')} Remove local Wrangler state and re-bootstrap database
|
|
73
80
|
|
|
74
81
|
${pc.bold('3. Database & Types Management')}
|
|
75
|
-
${pc.cyan('
|
|
76
|
-
Generate TypeScript interfaces from
|
|
77
|
-
--local
|
|
78
|
-
--
|
|
82
|
+
${pc.cyan('types generate')} (aliases: ${pc.cyan('gen-types')}, ${pc.cyan('gen types typescript')})
|
|
83
|
+
Generate TypeScript interfaces + schema fingerprint from live D1
|
|
84
|
+
--local / --remote Target local SQLite state (default) or remote D1
|
|
85
|
+
--db <name> Override D1 database name
|
|
86
|
+
-o, --output <file> Output path (default: beech.generated.ts; aliases print to stdout)
|
|
87
|
+
${pc.cyan('types check')} Diff committed generated types against live D1 (writes nothing)
|
|
88
|
+
--local / --remote Target local SQLite state (default) or remote D1
|
|
89
|
+
--db <name> Override D1 database name
|
|
90
|
+
-o, --output <file> File to check (default: beech.generated.ts)
|
|
91
|
+
Exits 1 when the file is missing or stale.
|
|
92
|
+
${pc.cyan('schema export')} Write beech.schema.ts from live D1 state
|
|
93
|
+
--out <file> Destination (default: beech.schema.ts)
|
|
94
|
+
--stdout Print instead of writing
|
|
95
|
+
--remote Target remote D1
|
|
96
|
+
${pc.cyan('schema diff')} Compare beech.schema.ts against the deployed schema
|
|
97
|
+
--manifest <f> Manifest path (default: beech.schema.ts)
|
|
98
|
+
Exits 1 when drift is detected.
|
|
99
|
+
${pc.cyan('schema audit')} Report relation storage and legacy tag definitions that need repair (read-only)
|
|
100
|
+
--remote Target remote D1 instead of local (default: local)
|
|
101
|
+
--db <name> Override D1 database name
|
|
102
|
+
${pc.cyan('schema migrate')} Migrate pre-0.9 tag/choice seeds to the closed-vocabulary tags contract
|
|
103
|
+
--apply Write the changes (default: dry run, exits 1 while work is pending)
|
|
104
|
+
--remote Target remote D1 instead of local (default: local)
|
|
79
105
|
--db <name> Override D1 database name
|
|
80
|
-
|
|
106
|
+
${pc.cyan('schema plan')} Show what applying beech.schema.ts would change (writes nothing)
|
|
107
|
+
--manifest <f> Manifest path (default: beech.schema.ts)
|
|
108
|
+
--api-url <url> API origin (default: BEECH_API_URL or http://localhost:8789)
|
|
109
|
+
Exits 1 when a seed cannot be applied.
|
|
110
|
+
${pc.cyan('schema apply')} Apply beech.schema.ts through the control plane
|
|
111
|
+
--manifest <f> Manifest path (default: beech.schema.ts)
|
|
112
|
+
--api-url <url> API origin
|
|
113
|
+
-y, --yes Skip the confirmation prompt
|
|
114
|
+
Additive only. Authorizes in the browser on first use.
|
|
81
115
|
${pc.cyan('validate')} Validate runtime schema status
|
|
82
116
|
|
|
83
117
|
${pc.bold('4. Forms & Frontend Generation')}
|
|
@@ -102,6 +136,8 @@ function help() {
|
|
|
102
136
|
${pc.cyan('test')} Run the test suite via Turborepo / Vitest
|
|
103
137
|
--coverage Generate coverage reports
|
|
104
138
|
--diff Run test coverage only for files modified on the branch
|
|
139
|
+
--tier <list> Run one or more tiers: unit, flow, integration, e2e (comma-separated)
|
|
140
|
+
e2e is Playwright-driven and is never selected by --diff
|
|
105
141
|
${pc.cyan('lint')} Run ESLint quality checks
|
|
106
142
|
${pc.cyan('setup:cloudflare')} (alias: ${pc.cyan('setup:cf')})
|
|
107
143
|
Interactive 1-step Cloudflare provisioning (D1, R2, Presigned S3 secrets)
|
|
@@ -131,17 +167,17 @@ async function cmdInit(args) {
|
|
|
131
167
|
await init({ initDb, local: !remote, db, nonInteractive: yes })
|
|
132
168
|
}
|
|
133
169
|
|
|
134
|
-
async function cmdSeedLoad(
|
|
170
|
+
async function cmdSeedLoad() {
|
|
135
171
|
const { seedLoad } = await import('@beechcms/cli')
|
|
136
172
|
await seedLoad({})
|
|
137
173
|
}
|
|
138
174
|
|
|
139
|
-
async function cmdValidate(
|
|
175
|
+
async function cmdValidate() {
|
|
140
176
|
const { validate } = await import('@beechcms/cli')
|
|
141
177
|
await validate({})
|
|
142
178
|
}
|
|
143
179
|
|
|
144
|
-
async function cmdSeedCreate(
|
|
180
|
+
async function cmdSeedCreate() {
|
|
145
181
|
const { seedCreate } = await import('@beechcms/cli')
|
|
146
182
|
await seedCreate({})
|
|
147
183
|
}
|
|
@@ -153,7 +189,7 @@ async function cmdDeploy(args) {
|
|
|
153
189
|
await deploy({ skipSeed, skipCheck })
|
|
154
190
|
}
|
|
155
191
|
|
|
156
|
-
async function cmdUpdate(
|
|
192
|
+
async function cmdUpdate() {
|
|
157
193
|
const { update } = await import('@beechcms/cli')
|
|
158
194
|
await update({})
|
|
159
195
|
}
|
|
@@ -178,14 +214,64 @@ async function cmdReset(args) {
|
|
|
178
214
|
}
|
|
179
215
|
|
|
180
216
|
async function cmdSchemaDiff(args) {
|
|
181
|
-
const remote
|
|
182
|
-
const
|
|
183
|
-
const
|
|
184
|
-
const
|
|
185
|
-
const
|
|
186
|
-
const db = dbIdx !== -1 ? args[dbIdx + 1] : undefined
|
|
217
|
+
const remote = args.includes('--remote')
|
|
218
|
+
const manifestIdx = args.indexOf('--manifest')
|
|
219
|
+
const manifest = manifestIdx !== -1 ? args[manifestIdx + 1] : undefined
|
|
220
|
+
const dbIdx = args.indexOf('--db')
|
|
221
|
+
const db = dbIdx !== -1 ? args[dbIdx + 1] : undefined
|
|
187
222
|
const { schemaDiff } = await import('@beechcms/cli')
|
|
188
|
-
await schemaDiff({ local: !remote,
|
|
223
|
+
await schemaDiff({ local: !remote, manifest, db })
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
async function cmdSchemaAudit(args) {
|
|
227
|
+
const remote = args.includes('--remote')
|
|
228
|
+
const dbIdx = args.indexOf('--db')
|
|
229
|
+
const db = dbIdx !== -1 ? args[dbIdx + 1] : undefined
|
|
230
|
+
const { schemaAudit } = await import('@beechcms/cli')
|
|
231
|
+
await schemaAudit({ local: !remote, db })
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
async function cmdSchemaMigrate(args) {
|
|
235
|
+
const remote = args.includes('--remote')
|
|
236
|
+
const apply = args.includes('--apply')
|
|
237
|
+
const dbIdx = args.indexOf('--db')
|
|
238
|
+
const db = dbIdx !== -1 ? args[dbIdx + 1] : undefined
|
|
239
|
+
const { schemaMigrate } = await import('@beechcms/cli')
|
|
240
|
+
await schemaMigrate({ apply, local: !remote, db })
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
async function cmdSchemaExport(args) {
|
|
244
|
+
const remote = args.includes('--remote')
|
|
245
|
+
const stdout = args.includes('--stdout')
|
|
246
|
+
const outIdx = args.indexOf('--out')
|
|
247
|
+
const oIdx = args.indexOf('-o')
|
|
248
|
+
const out = stdout ? null
|
|
249
|
+
: outIdx !== -1 ? args[outIdx + 1]
|
|
250
|
+
: oIdx !== -1 ? args[oIdx + 1]
|
|
251
|
+
: undefined
|
|
252
|
+
const dbIdx = args.indexOf('--db')
|
|
253
|
+
const db = dbIdx !== -1 ? args[dbIdx + 1] : undefined
|
|
254
|
+
const { schemaExport } = await import('@beechcms/cli')
|
|
255
|
+
await schemaExport({ out, local: !remote, db })
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
async function cmdSchemaPlan(args) {
|
|
259
|
+
const manifestIdx = args.indexOf('--manifest')
|
|
260
|
+
const manifest = manifestIdx !== -1 ? args[manifestIdx + 1] : undefined
|
|
261
|
+
const apiIdx = args.indexOf('--api-url')
|
|
262
|
+
const apiUrl = apiIdx !== -1 ? args[apiIdx + 1] : undefined
|
|
263
|
+
const { schemaPlan } = await import('@beechcms/cli')
|
|
264
|
+
await schemaPlan({ manifest, apiUrl })
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
async function cmdSchemaApply(args) {
|
|
268
|
+
const manifestIdx = args.indexOf('--manifest')
|
|
269
|
+
const manifest = manifestIdx !== -1 ? args[manifestIdx + 1] : undefined
|
|
270
|
+
const apiIdx = args.indexOf('--api-url')
|
|
271
|
+
const apiUrl = apiIdx !== -1 ? args[apiIdx + 1] : undefined
|
|
272
|
+
const yes = args.includes('--yes') || args.includes('-y')
|
|
273
|
+
const { schemaApply } = await import('@beechcms/cli')
|
|
274
|
+
await schemaApply({ manifest, apiUrl, yes })
|
|
189
275
|
}
|
|
190
276
|
|
|
191
277
|
async function cmdGenerateTypes(args) {
|
|
@@ -196,7 +282,7 @@ async function cmdGenerateTypes(args) {
|
|
|
196
282
|
const outIdx = args.indexOf('--out')
|
|
197
283
|
const outputIdx = args.indexOf('--output')
|
|
198
284
|
const oIdx = args.indexOf('-o')
|
|
199
|
-
|
|
285
|
+
|
|
200
286
|
if (outIdx !== -1 && args[outIdx + 1]) out = args[outIdx + 1]
|
|
201
287
|
else if (outputIdx !== -1 && args[outputIdx + 1]) out = args[outputIdx + 1]
|
|
202
288
|
else if (oIdx !== -1 && args[oIdx + 1]) out = args[oIdx + 1]
|
|
@@ -204,8 +290,33 @@ async function cmdGenerateTypes(args) {
|
|
|
204
290
|
const dbIdx = args.indexOf('--db')
|
|
205
291
|
const db = dbIdx !== -1 ? args[dbIdx + 1] : undefined
|
|
206
292
|
|
|
293
|
+
// `beech types generate` writes beech.generated.ts; the historical `gen-types` aliases keep
|
|
294
|
+
// their stdout default, so no existing script changes behaviour.
|
|
295
|
+
const isTypesGenerate = command === 'types:generate'
|
|
296
|
+
const destination = out ?? (isTypesGenerate ? undefined : null)
|
|
297
|
+
|
|
207
298
|
const { generateTypes } = await import('@beechcms/cli')
|
|
208
|
-
await generateTypes({ out, local, db })
|
|
299
|
+
await generateTypes({ out: destination, local, db })
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
async function cmdTypesCheck(args) {
|
|
303
|
+
const remote = args.includes('--remote')
|
|
304
|
+
const local = !remote
|
|
305
|
+
|
|
306
|
+
let out
|
|
307
|
+
const outIdx = args.indexOf('--out')
|
|
308
|
+
const outputIdx = args.indexOf('--output')
|
|
309
|
+
const oIdx = args.indexOf('-o')
|
|
310
|
+
|
|
311
|
+
if (outIdx !== -1 && args[outIdx + 1]) out = args[outIdx + 1]
|
|
312
|
+
else if (outputIdx !== -1 && args[outputIdx + 1]) out = args[outputIdx + 1]
|
|
313
|
+
else if (oIdx !== -1 && args[oIdx + 1]) out = args[oIdx + 1]
|
|
314
|
+
|
|
315
|
+
const dbIdx = args.indexOf('--db')
|
|
316
|
+
const db = dbIdx !== -1 ? args[dbIdx + 1] : undefined
|
|
317
|
+
|
|
318
|
+
const { typesCheck } = await import('@beechcms/cli')
|
|
319
|
+
await typesCheck({ out, local, db })
|
|
209
320
|
}
|
|
210
321
|
|
|
211
322
|
async function cmdForms(args) {
|
|
@@ -225,12 +336,12 @@ async function cmdForms(args) {
|
|
|
225
336
|
}
|
|
226
337
|
|
|
227
338
|
// New unified command wrappers:
|
|
228
|
-
async function cmdDbMigrate(
|
|
339
|
+
async function cmdDbMigrate() {
|
|
229
340
|
const { dbMigrate } = await import('@beechcms/cli')
|
|
230
341
|
await dbMigrate({})
|
|
231
342
|
}
|
|
232
343
|
|
|
233
|
-
async function cmdDbReset(
|
|
344
|
+
async function cmdDbReset() {
|
|
234
345
|
const { dbReset } = await import('@beechcms/cli')
|
|
235
346
|
await dbReset({})
|
|
236
347
|
}
|
|
@@ -241,22 +352,22 @@ async function cmdDev(args) {
|
|
|
241
352
|
await dev({ plain })
|
|
242
353
|
}
|
|
243
354
|
|
|
244
|
-
async function cmdDevStop(
|
|
355
|
+
async function cmdDevStop() {
|
|
245
356
|
const { devStop } = await import('@beechcms/cli')
|
|
246
357
|
await devStop()
|
|
247
358
|
}
|
|
248
359
|
|
|
249
|
-
async function cmdDevReset(
|
|
360
|
+
async function cmdDevReset() {
|
|
250
361
|
const { devReset } = await import('@beechcms/cli')
|
|
251
362
|
await devReset()
|
|
252
363
|
}
|
|
253
364
|
|
|
254
|
-
async function cmdDevTunnel(
|
|
365
|
+
async function cmdDevTunnel() {
|
|
255
366
|
const { devTunnel } = await import('@beechcms/cli')
|
|
256
367
|
await devTunnel()
|
|
257
368
|
}
|
|
258
369
|
|
|
259
|
-
async function cmdMailpitClear(
|
|
370
|
+
async function cmdMailpitClear() {
|
|
260
371
|
const { mailpitClear } = await import('@beechcms/cli')
|
|
261
372
|
await mailpitClear()
|
|
262
373
|
}
|
|
@@ -270,16 +381,20 @@ async function cmdLogs(args) {
|
|
|
270
381
|
async function cmdTest(args) {
|
|
271
382
|
const coverage = args.includes('--coverage')
|
|
272
383
|
const diff = args.includes('--diff')
|
|
384
|
+
const tierIdx = args.indexOf('--tier')
|
|
385
|
+
const tier = tierIdx !== -1 && args[tierIdx + 1] && !args[tierIdx + 1].startsWith('--')
|
|
386
|
+
? args[tierIdx + 1]
|
|
387
|
+
: undefined
|
|
273
388
|
const { test } = await import('@beechcms/cli')
|
|
274
|
-
await test({ coverage, diff })
|
|
389
|
+
await test({ coverage, diff, tier })
|
|
275
390
|
}
|
|
276
391
|
|
|
277
|
-
async function cmdLint(
|
|
392
|
+
async function cmdLint() {
|
|
278
393
|
const { lint } = await import('@beechcms/cli')
|
|
279
394
|
await lint()
|
|
280
395
|
}
|
|
281
396
|
|
|
282
|
-
async function cmdDoctor(
|
|
397
|
+
async function cmdDoctor() {
|
|
283
398
|
const { doctor } = await import('@beechcms/cli')
|
|
284
399
|
await doctor()
|
|
285
400
|
}
|
package/bin/create.mjs
CHANGED
|
@@ -105,6 +105,7 @@ function buildWranglerJsonc(cfg) {
|
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
function buildDevVars(cloudflare) {
|
|
108
|
+
const PRIVACY_KEY_LINES = `# Master key for protected fields (AES-GCM + blind index). Do NOT change once data is stored.\nPRIVACY_MASTER_KEY=${randomBytes(32).toString('hex')}`
|
|
108
109
|
if (cloudflare) {
|
|
109
110
|
return [
|
|
110
111
|
`# Cloudflare R2 S3 credentials (required for direct client upload via Presigned URLs)`,
|
|
@@ -113,6 +114,8 @@ function buildDevVars(cloudflare) {
|
|
|
113
114
|
`R2_SECRET_ACCESS_KEY=${cloudflare.r2SecretKey}`,
|
|
114
115
|
`R2_ENDPOINT=${cloudflare.r2Endpoint}`,
|
|
115
116
|
`R2_BUCKET_NAME=${cloudflare.r2Bucket}`,
|
|
117
|
+
'',
|
|
118
|
+
PRIVACY_KEY_LINES,
|
|
116
119
|
].join('\n') + '\n'
|
|
117
120
|
}
|
|
118
121
|
return [
|
|
@@ -123,6 +126,8 @@ function buildDevVars(cloudflare) {
|
|
|
123
126
|
'R2_SECRET_ACCESS_KEY=',
|
|
124
127
|
'R2_ENDPOINT=https://<YOUR_ACCOUNT_ID>.r2.cloudflarestorage.com',
|
|
125
128
|
'R2_BUCKET_NAME=',
|
|
129
|
+
'',
|
|
130
|
+
PRIVACY_KEY_LINES,
|
|
126
131
|
].join('\n') + '\n'
|
|
127
132
|
}
|
|
128
133
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@beechcms/cms",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"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.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cms",
|
|
@@ -40,17 +40,18 @@
|
|
|
40
40
|
},
|
|
41
41
|
"type": "module",
|
|
42
42
|
"devDependencies": {
|
|
43
|
-
"@eslint/js": "^
|
|
44
|
-
"@types/node": "^
|
|
43
|
+
"@eslint/js": "^10.0.1",
|
|
44
|
+
"@types/node": "^26.5.1",
|
|
45
45
|
"cross-env": "^10.1.0",
|
|
46
|
-
"eslint": "^
|
|
47
|
-
"execa": "^
|
|
48
|
-
"globals": "^
|
|
46
|
+
"eslint": "^10.10.0",
|
|
47
|
+
"execa": "^10.0.1",
|
|
48
|
+
"globals": "^17.12.0",
|
|
49
49
|
"husky": "^9.1.7",
|
|
50
|
-
"ink": "^
|
|
50
|
+
"ink": "^7.1.1",
|
|
51
51
|
"ink-spinner": "^5.0.0",
|
|
52
|
+
"knip": "^6.41.0",
|
|
52
53
|
"react": "^19.2.7",
|
|
53
|
-
"react-doctor": "^0.
|
|
54
|
+
"react-doctor": "^0.9.14",
|
|
54
55
|
"strip-ansi": "^7.2.0",
|
|
55
56
|
"tsx": "^4.22.4",
|
|
56
57
|
"turbo": "^2.9.18",
|
|
@@ -58,10 +59,10 @@
|
|
|
58
59
|
"typedoc-plugin-markdown": "^4.12.0",
|
|
59
60
|
"typescript": "^5.9.3",
|
|
60
61
|
"vitepress": "^1.6.4",
|
|
61
|
-
"vitest": "^4.1.
|
|
62
|
+
"vitest": "^4.1.11"
|
|
62
63
|
},
|
|
63
64
|
"dependencies": {
|
|
64
|
-
"@beechcms/cli": "^0.
|
|
65
|
+
"@beechcms/cli": "^0.9.0",
|
|
65
66
|
"@clack/prompts": "^0.9.1",
|
|
66
67
|
"picocolors": "^1.1.1"
|
|
67
68
|
},
|
|
@@ -97,8 +98,13 @@
|
|
|
97
98
|
"dev:reset": "docker compose -f docker/docker-compose.yml down -v",
|
|
98
99
|
"build": "turbo run build",
|
|
99
100
|
"lint": "turbo run lint",
|
|
101
|
+
"lint:tests": "node scripts/check-test-placement.mjs",
|
|
102
|
+
"knip": "knip",
|
|
103
|
+
"knip:production": "knip --production",
|
|
104
|
+
"knip:ci": "knip --include files,dependencies,unlisted,binaries,unresolved",
|
|
100
105
|
"type-check": "turbo run type-check",
|
|
101
106
|
"test": "node scripts/test-runner.mjs",
|
|
107
|
+
"test:nocache": "node scripts/test-runner.mjs --nocache",
|
|
102
108
|
"test:coverage": "node scripts/test-runner.mjs --coverage",
|
|
103
109
|
"test:diff": "node scripts/test-coverage-diff.mjs",
|
|
104
110
|
"test:dev-cli": "vitest run --config scripts/dev-cli/vitest.config.ts",
|