@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.
- package/LICENSE +40 -40
- package/README.md +125 -125
- package/bin/cli.mjs +216 -216
- package/bin/create.mjs +447 -447
- package/bin/templates/blog.ts +35 -35
- package/bin/templates/commerce.ts +29 -29
- package/bin/templates/contact.ts +23 -23
- package/bin/templates/empty.ts +41 -41
- package/bin/templates/gallery.ts +16 -16
- package/bin/templates/tasks.ts +12 -12
- package/package.json +20 -5
package/bin/cli.mjs
CHANGED
|
@@ -1,216 +1,216 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// @ts-check
|
|
3
|
-
|
|
4
|
-
import { spawnSync } from 'node:child_process'
|
|
5
|
-
import { existsSync } from 'node:fs'
|
|
6
|
-
import { resolve } from 'node:path'
|
|
7
|
-
import { pathToFileURL } from 'node:url'
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const [,, command, ...args] = process.argv
|
|
11
|
-
|
|
12
|
-
const COMMANDS = {
|
|
13
|
-
build: cmdBuild,
|
|
14
|
-
'seed:load': cmdSeedLoad,
|
|
15
|
-
'seed:create': cmdSeedCreate,
|
|
16
|
-
'init': cmdInit,
|
|
17
|
-
'validate': cmdValidate,
|
|
18
|
-
'deploy': cmdDeploy,
|
|
19
|
-
'update': cmdUpdate,
|
|
20
|
-
'onboard': cmdOnboard,
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function help() {
|
|
24
|
-
console.log(`
|
|
25
|
-
beech <command> [options]
|
|
26
|
-
|
|
27
|
-
Commands:
|
|
28
|
-
init Check project files and optionally initialise the database
|
|
29
|
-
--db Also initialise the D1 database (system tables)
|
|
30
|
-
--remote Target remote D1 instead of local (default: local)
|
|
31
|
-
--db-name <n> Override D1 database name
|
|
32
|
-
|
|
33
|
-
build Rebuild @beechcms/core after editing seeds.ts
|
|
34
|
-
|
|
35
|
-
validate Validate SEED_REGISTRY for common errors (duplicate aliases,
|
|
36
|
-
missing displayNameAlias, duplicate slugs). Exit code 1 on errors.
|
|
37
|
-
|
|
38
|
-
seed:load Create/update content tables from SEED_REGISTRY
|
|
39
|
-
--dry-run Print SQL without executing
|
|
40
|
-
--diff Show schema differences vs current DB
|
|
41
|
-
--remote Execute against remote D1 (default: local)
|
|
42
|
-
--db <name> Override D1 database name
|
|
43
|
-
|
|
44
|
-
seed:create Interactive wizard — generate a new Seed definition and append
|
|
45
|
-
it to seeds.ts, including SEED_REGISTRY entry
|
|
46
|
-
|
|
47
|
-
deploy Deploy Worker, sync remote schema, and verify /admin
|
|
48
|
-
--skip-seed Skip remote seed:load step
|
|
49
|
-
--skip-check Skip /admin reachability check
|
|
50
|
-
|
|
51
|
-
update Update @beechcms/api and @beechcms/core to latest, then
|
|
52
|
-
apply any new system migrations to the local database
|
|
53
|
-
|
|
54
|
-
onboard One-command local provisioning (init + seed:load). Designed
|
|
55
|
-
for non-interactive use by agents and CI.
|
|
56
|
-
--remote Target remote D1 instead of local (default: local)
|
|
57
|
-
--yes Skip all interactive prompts (non-interactive mode)
|
|
58
|
-
--db <name> Override D1 database name
|
|
59
|
-
|
|
60
|
-
Scaffold a new project (interactive, or pass --yes for non-interactive defaults):
|
|
61
|
-
npm create @beechcms/cms [project-name] [--yes] [--with-examples]
|
|
62
|
-
|
|
63
|
-
Golden path (local):
|
|
64
|
-
npx beech onboard --local --yes # fully automated
|
|
65
|
-
# or step by step:
|
|
66
|
-
npx beech init --db --local
|
|
67
|
-
npx beech seed:load --local
|
|
68
|
-
npx wrangler dev
|
|
69
|
-
|
|
70
|
-
Golden path (deploy):
|
|
71
|
-
npx beech deploy
|
|
72
|
-
npx beech init --db --remote # verify remote DB post-deploy
|
|
73
|
-
`)
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
function cmdBuild() {
|
|
77
|
-
console.log(
|
|
78
|
-
'\nNo build step needed for BeechCMS projects.\n' +
|
|
79
|
-
'Edit seeds.ts then run `npx beech seed:load` to sync schema changes to D1.\n'
|
|
80
|
-
)
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
async function tryLoadLocalRegistry() {
|
|
84
|
-
const cwd = process.cwd()
|
|
85
|
-
|
|
86
|
-
// Try compiled JS first (root or apps/api)
|
|
87
|
-
const searchDirs = [cwd, resolve(cwd, 'apps', 'api')]
|
|
88
|
-
for (const dir of searchDirs) {
|
|
89
|
-
for (const name of ['seeds.js', 'seeds.mjs', 'seed.js', 'seed.mjs']) {
|
|
90
|
-
const p = resolve(dir, name)
|
|
91
|
-
if (existsSync(p)) {
|
|
92
|
-
try {
|
|
93
|
-
const mod = await import(pathToFileURL(p).href)
|
|
94
|
-
if (mod.SEED_REGISTRY && typeof mod.SEED_REGISTRY === 'object') {
|
|
95
|
-
return mod.SEED_REGISTRY
|
|
96
|
-
}
|
|
97
|
-
if (Array.isArray(mod.seeds)) {
|
|
98
|
-
return Object.fromEntries(mod.seeds.map(s => [s.slug, s]))
|
|
99
|
-
}
|
|
100
|
-
if (Array.isArray(mod.default)) {
|
|
101
|
-
return Object.fromEntries(mod.default.map(s => [s.slug, s]))
|
|
102
|
-
}
|
|
103
|
-
} catch {}
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// Try seeds.ts / seed.ts (root or apps/api)
|
|
109
|
-
let tsPath = null
|
|
110
|
-
for (const dir of searchDirs) {
|
|
111
|
-
const p = existsSync(resolve(dir, 'seeds.ts'))
|
|
112
|
-
? resolve(dir, 'seeds.ts')
|
|
113
|
-
: resolve(dir, 'seed.ts')
|
|
114
|
-
if (existsSync(p)) {
|
|
115
|
-
tsPath = p
|
|
116
|
-
break
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
if (tsPath) {
|
|
121
|
-
const result = spawnSync(process.execPath, [
|
|
122
|
-
'--experimental-strip-types',
|
|
123
|
-
'--input-type=module',
|
|
124
|
-
'--eval',
|
|
125
|
-
`
|
|
126
|
-
import * as mod from ${JSON.stringify(pathToFileURL(tsPath).href)};
|
|
127
|
-
let out = null;
|
|
128
|
-
if (mod.SEED_REGISTRY && typeof mod.SEED_REGISTRY === 'object') out = mod.SEED_REGISTRY;
|
|
129
|
-
else if (Array.isArray(mod.seeds)) out = Object.fromEntries(mod.seeds.map(s => [s.slug, s]));
|
|
130
|
-
else if (Array.isArray(mod.default)) out = Object.fromEntries(mod.default.map(s => [s.slug, s]));
|
|
131
|
-
if (out) process.stdout.write(JSON.stringify(out));
|
|
132
|
-
`.trim(),
|
|
133
|
-
], { encoding: 'utf-8' })
|
|
134
|
-
|
|
135
|
-
if (result.status === 0 && result.stdout) {
|
|
136
|
-
try { return JSON.parse(result.stdout) } catch (err) {
|
|
137
|
-
console.error(' Failed to parse seeds.ts output:', err)
|
|
138
|
-
}
|
|
139
|
-
} else if (result.status !== 0) {
|
|
140
|
-
console.error(' Error loading seeds.ts:')
|
|
141
|
-
console.error(result.stderr || result.stdout || 'Unknown error')
|
|
142
|
-
if (process.version.slice(1).split('.')[0] < 22) {
|
|
143
|
-
console.warn(' Note: Node.js 22.6+ is required to load .ts files directly. Current version:', process.version)
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
return null
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
async function cmdInit(args) {
|
|
152
|
-
const initDb = args.includes('--db')
|
|
153
|
-
const remote = args.includes('--remote')
|
|
154
|
-
const dbIdx = args.indexOf('--db-name')
|
|
155
|
-
const db = dbIdx !== -1 ? args[dbIdx + 1] : undefined
|
|
156
|
-
|
|
157
|
-
const { init } = await import('@beechcms/cli')
|
|
158
|
-
await init({ initDb, local: !remote, db })
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
async function cmdSeedLoad(args) {
|
|
162
|
-
const dryRun = args.includes('--dry-run')
|
|
163
|
-
const diff = args.includes('--diff')
|
|
164
|
-
const remote = args.includes('--remote')
|
|
165
|
-
const dbIdx = args.indexOf('--db')
|
|
166
|
-
const db = dbIdx !== -1 ? args[dbIdx + 1] : undefined
|
|
167
|
-
|
|
168
|
-
const registry = await tryLoadLocalRegistry()
|
|
169
|
-
|
|
170
|
-
const { seedLoad } = await import('@beechcms/cli')
|
|
171
|
-
await seedLoad({ dryRun, diff, local: !remote, db, registry })
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
async function cmdValidate(args) {
|
|
175
|
-
const registry = await tryLoadLocalRegistry()
|
|
176
|
-
const { validate } = await import('@beechcms/cli')
|
|
177
|
-
await validate({ registry })
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
async function cmdSeedCreate(_args) {
|
|
181
|
-
const { seedCreate } = await import('@beechcms/cli')
|
|
182
|
-
await seedCreate({})
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
async function cmdDeploy(args) {
|
|
186
|
-
const skipSeed = args.includes('--skip-seed')
|
|
187
|
-
const skipCheck = args.includes('--skip-check')
|
|
188
|
-
const registry = skipSeed ? null : await tryLoadLocalRegistry()
|
|
189
|
-
const { deploy } = await import('@beechcms/cli')
|
|
190
|
-
await deploy({ registry, skipSeed, skipCheck })
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
async function cmdUpdate(_args) {
|
|
194
|
-
const { update } = await import('@beechcms/cli')
|
|
195
|
-
await update({})
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
async function cmdOnboard(args) {
|
|
199
|
-
const local = !args.includes('--remote')
|
|
200
|
-
const yes = args.includes('--yes')
|
|
201
|
-
const dbIdx = args.indexOf('--db')
|
|
202
|
-
const db = dbIdx !== -1 ? args[dbIdx + 1] : undefined
|
|
203
|
-
const registry = await tryLoadLocalRegistry()
|
|
204
|
-
const { onboard } = await import('@beechcms/cli')
|
|
205
|
-
await onboard({ local, yes, db, registry })
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
const handler = COMMANDS[command]
|
|
209
|
-
if (!handler) {
|
|
210
|
-
help()
|
|
211
|
-
if (command) process.exit(1)
|
|
212
|
-
} else if (args.includes('--help') || args.includes('-h')) {
|
|
213
|
-
help()
|
|
214
|
-
} else {
|
|
215
|
-
await handler(args)
|
|
216
|
-
}
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// @ts-check
|
|
3
|
+
|
|
4
|
+
import { spawnSync } from 'node:child_process'
|
|
5
|
+
import { existsSync } from 'node:fs'
|
|
6
|
+
import { resolve } from 'node:path'
|
|
7
|
+
import { pathToFileURL } from 'node:url'
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
const [,, command, ...args] = process.argv
|
|
11
|
+
|
|
12
|
+
const COMMANDS = {
|
|
13
|
+
build: cmdBuild,
|
|
14
|
+
'seed:load': cmdSeedLoad,
|
|
15
|
+
'seed:create': cmdSeedCreate,
|
|
16
|
+
'init': cmdInit,
|
|
17
|
+
'validate': cmdValidate,
|
|
18
|
+
'deploy': cmdDeploy,
|
|
19
|
+
'update': cmdUpdate,
|
|
20
|
+
'onboard': cmdOnboard,
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function help() {
|
|
24
|
+
console.log(`
|
|
25
|
+
beech <command> [options]
|
|
26
|
+
|
|
27
|
+
Commands:
|
|
28
|
+
init Check project files and optionally initialise the database
|
|
29
|
+
--db Also initialise the D1 database (system tables)
|
|
30
|
+
--remote Target remote D1 instead of local (default: local)
|
|
31
|
+
--db-name <n> Override D1 database name
|
|
32
|
+
|
|
33
|
+
build Rebuild @beechcms/core after editing seeds.ts
|
|
34
|
+
|
|
35
|
+
validate Validate SEED_REGISTRY for common errors (duplicate aliases,
|
|
36
|
+
missing displayNameAlias, duplicate slugs). Exit code 1 on errors.
|
|
37
|
+
|
|
38
|
+
seed:load Create/update content tables from SEED_REGISTRY
|
|
39
|
+
--dry-run Print SQL without executing
|
|
40
|
+
--diff Show schema differences vs current DB
|
|
41
|
+
--remote Execute against remote D1 (default: local)
|
|
42
|
+
--db <name> Override D1 database name
|
|
43
|
+
|
|
44
|
+
seed:create Interactive wizard — generate a new Seed definition and append
|
|
45
|
+
it to seeds.ts, including SEED_REGISTRY entry
|
|
46
|
+
|
|
47
|
+
deploy Deploy Worker, sync remote schema, and verify /admin
|
|
48
|
+
--skip-seed Skip remote seed:load step
|
|
49
|
+
--skip-check Skip /admin reachability check
|
|
50
|
+
|
|
51
|
+
update Update @beechcms/api and @beechcms/core to latest, then
|
|
52
|
+
apply any new system migrations to the local database
|
|
53
|
+
|
|
54
|
+
onboard One-command local provisioning (init + seed:load). Designed
|
|
55
|
+
for non-interactive use by agents and CI.
|
|
56
|
+
--remote Target remote D1 instead of local (default: local)
|
|
57
|
+
--yes Skip all interactive prompts (non-interactive mode)
|
|
58
|
+
--db <name> Override D1 database name
|
|
59
|
+
|
|
60
|
+
Scaffold a new project (interactive, or pass --yes for non-interactive defaults):
|
|
61
|
+
npm create @beechcms/cms [project-name] [--yes] [--with-examples]
|
|
62
|
+
|
|
63
|
+
Golden path (local):
|
|
64
|
+
npx beech onboard --local --yes # fully automated
|
|
65
|
+
# or step by step:
|
|
66
|
+
npx beech init --db --local
|
|
67
|
+
npx beech seed:load --local
|
|
68
|
+
npx wrangler dev
|
|
69
|
+
|
|
70
|
+
Golden path (deploy):
|
|
71
|
+
npx beech deploy
|
|
72
|
+
npx beech init --db --remote # verify remote DB post-deploy
|
|
73
|
+
`)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function cmdBuild() {
|
|
77
|
+
console.log(
|
|
78
|
+
'\nNo build step needed for BeechCMS projects.\n' +
|
|
79
|
+
'Edit seeds.ts then run `npx beech seed:load` to sync schema changes to D1.\n'
|
|
80
|
+
)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
async function tryLoadLocalRegistry() {
|
|
84
|
+
const cwd = process.cwd()
|
|
85
|
+
|
|
86
|
+
// Try compiled JS first (root or apps/api)
|
|
87
|
+
const searchDirs = [cwd, resolve(cwd, 'apps', 'api')]
|
|
88
|
+
for (const dir of searchDirs) {
|
|
89
|
+
for (const name of ['seeds.js', 'seeds.mjs', 'seed.js', 'seed.mjs']) {
|
|
90
|
+
const p = resolve(dir, name)
|
|
91
|
+
if (existsSync(p)) {
|
|
92
|
+
try {
|
|
93
|
+
const mod = await import(pathToFileURL(p).href)
|
|
94
|
+
if (mod.SEED_REGISTRY && typeof mod.SEED_REGISTRY === 'object') {
|
|
95
|
+
return mod.SEED_REGISTRY
|
|
96
|
+
}
|
|
97
|
+
if (Array.isArray(mod.seeds)) {
|
|
98
|
+
return Object.fromEntries(mod.seeds.map(s => [s.slug, s]))
|
|
99
|
+
}
|
|
100
|
+
if (Array.isArray(mod.default)) {
|
|
101
|
+
return Object.fromEntries(mod.default.map(s => [s.slug, s]))
|
|
102
|
+
}
|
|
103
|
+
} catch {}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Try seeds.ts / seed.ts (root or apps/api)
|
|
109
|
+
let tsPath = null
|
|
110
|
+
for (const dir of searchDirs) {
|
|
111
|
+
const p = existsSync(resolve(dir, 'seeds.ts'))
|
|
112
|
+
? resolve(dir, 'seeds.ts')
|
|
113
|
+
: resolve(dir, 'seed.ts')
|
|
114
|
+
if (existsSync(p)) {
|
|
115
|
+
tsPath = p
|
|
116
|
+
break
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (tsPath) {
|
|
121
|
+
const result = spawnSync(process.execPath, [
|
|
122
|
+
'--experimental-strip-types',
|
|
123
|
+
'--input-type=module',
|
|
124
|
+
'--eval',
|
|
125
|
+
`
|
|
126
|
+
import * as mod from ${JSON.stringify(pathToFileURL(tsPath).href)};
|
|
127
|
+
let out = null;
|
|
128
|
+
if (mod.SEED_REGISTRY && typeof mod.SEED_REGISTRY === 'object') out = mod.SEED_REGISTRY;
|
|
129
|
+
else if (Array.isArray(mod.seeds)) out = Object.fromEntries(mod.seeds.map(s => [s.slug, s]));
|
|
130
|
+
else if (Array.isArray(mod.default)) out = Object.fromEntries(mod.default.map(s => [s.slug, s]));
|
|
131
|
+
if (out) process.stdout.write(JSON.stringify(out));
|
|
132
|
+
`.trim(),
|
|
133
|
+
], { encoding: 'utf-8' })
|
|
134
|
+
|
|
135
|
+
if (result.status === 0 && result.stdout) {
|
|
136
|
+
try { return JSON.parse(result.stdout) } catch (err) {
|
|
137
|
+
console.error(' Failed to parse seeds.ts output:', err)
|
|
138
|
+
}
|
|
139
|
+
} else if (result.status !== 0) {
|
|
140
|
+
console.error(' Error loading seeds.ts:')
|
|
141
|
+
console.error(result.stderr || result.stdout || 'Unknown error')
|
|
142
|
+
if (process.version.slice(1).split('.')[0] < 22) {
|
|
143
|
+
console.warn(' Note: Node.js 22.6+ is required to load .ts files directly. Current version:', process.version)
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return null
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
async function cmdInit(args) {
|
|
152
|
+
const initDb = args.includes('--db')
|
|
153
|
+
const remote = args.includes('--remote')
|
|
154
|
+
const dbIdx = args.indexOf('--db-name')
|
|
155
|
+
const db = dbIdx !== -1 ? args[dbIdx + 1] : undefined
|
|
156
|
+
|
|
157
|
+
const { init } = await import('@beechcms/cli')
|
|
158
|
+
await init({ initDb, local: !remote, db })
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
async function cmdSeedLoad(args) {
|
|
162
|
+
const dryRun = args.includes('--dry-run')
|
|
163
|
+
const diff = args.includes('--diff')
|
|
164
|
+
const remote = args.includes('--remote')
|
|
165
|
+
const dbIdx = args.indexOf('--db')
|
|
166
|
+
const db = dbIdx !== -1 ? args[dbIdx + 1] : undefined
|
|
167
|
+
|
|
168
|
+
const registry = await tryLoadLocalRegistry()
|
|
169
|
+
|
|
170
|
+
const { seedLoad } = await import('@beechcms/cli')
|
|
171
|
+
await seedLoad({ dryRun, diff, local: !remote, db, registry })
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
async function cmdValidate(args) {
|
|
175
|
+
const registry = await tryLoadLocalRegistry()
|
|
176
|
+
const { validate } = await import('@beechcms/cli')
|
|
177
|
+
await validate({ registry })
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
async function cmdSeedCreate(_args) {
|
|
181
|
+
const { seedCreate } = await import('@beechcms/cli')
|
|
182
|
+
await seedCreate({})
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
async function cmdDeploy(args) {
|
|
186
|
+
const skipSeed = args.includes('--skip-seed')
|
|
187
|
+
const skipCheck = args.includes('--skip-check')
|
|
188
|
+
const registry = skipSeed ? null : await tryLoadLocalRegistry()
|
|
189
|
+
const { deploy } = await import('@beechcms/cli')
|
|
190
|
+
await deploy({ registry, skipSeed, skipCheck })
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
async function cmdUpdate(_args) {
|
|
194
|
+
const { update } = await import('@beechcms/cli')
|
|
195
|
+
await update({})
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
async function cmdOnboard(args) {
|
|
199
|
+
const local = !args.includes('--remote')
|
|
200
|
+
const yes = args.includes('--yes')
|
|
201
|
+
const dbIdx = args.indexOf('--db')
|
|
202
|
+
const db = dbIdx !== -1 ? args[dbIdx + 1] : undefined
|
|
203
|
+
const registry = await tryLoadLocalRegistry()
|
|
204
|
+
const { onboard } = await import('@beechcms/cli')
|
|
205
|
+
await onboard({ local, yes, db, registry })
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const handler = COMMANDS[command]
|
|
209
|
+
if (!handler) {
|
|
210
|
+
help()
|
|
211
|
+
if (command) process.exit(1)
|
|
212
|
+
} else if (args.includes('--help') || args.includes('-h')) {
|
|
213
|
+
help()
|
|
214
|
+
} else {
|
|
215
|
+
await handler(args)
|
|
216
|
+
}
|