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

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