@beechcms/cli 0.6.0-preview.4 → 0.6.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/package.json CHANGED
@@ -1,18 +1,22 @@
1
1
  {
2
2
  "name": "@beechcms/cli",
3
- "version": "0.6.0-preview.4",
3
+ "version": "0.6.0",
4
4
  "type": "module",
5
+ "files": [
6
+ "dist"
7
+ ],
5
8
  "main": "dist/index.js",
6
9
  "exports": {
7
10
  ".": "./dist/index.js"
8
11
  },
9
12
  "dependencies": {
10
- "@beechcms/core": "^0.6.0-preview.4",
13
+ "@beechcms/core": "^0.6.0",
11
14
  "picocolors": "^1.1.1"
12
15
  },
13
16
  "devDependencies": {
17
+ "@types/node": "^24.10.1",
14
18
  "esbuild": "^0.28.1",
15
- "typescript": "^5.9.3",
19
+ "typescript": "^7.0.2",
16
20
  "vitest": "^4.1.0"
17
21
  },
18
22
  "license": "MIT",
@@ -1,5 +0,0 @@
1
- $ tsc --noEmit && esbuild src/index.ts --bundle --packages=external --platform=node --format=esm --outfile=dist/index.js
2
-
3
- dist\index.js 59.9kb
4
-
5
- Done in 10ms
@@ -1 +0,0 @@
1
- $ eslint . "--quiet"
@@ -1,3 +0,0 @@
1
- {"total": {"lines":{"total":35,"covered":35,"skipped":0,"pct":100},"statements":{"total":43,"covered":43,"skipped":0,"pct":100},"functions":{"total":9,"covered":9,"skipped":0,"pct":100},"branches":{"total":18,"covered":14,"skipped":0,"pct":77.77},"branchesTrue":{"total":0,"covered":0,"skipped":0,"pct":"Unknown"}}
2
- ,"C:\\Users\\flavi\\Desktop\\beech-cms\\packages\\cli\\src\\commands\\validate.ts": {"lines":{"total":35,"covered":35,"skipped":0,"pct":100},"functions":{"total":9,"covered":9,"skipped":0,"pct":100},"statements":{"total":43,"covered":43,"skipped":0,"pct":100},"branches":{"total":18,"covered":14,"skipped":0,"pct":77.77}}
3
- }
@@ -1,126 +0,0 @@
1
- // SPDX-License-Identifier: MIT
2
- // Copyright (c) 2024–2026 Flavio De Musso
3
-
4
- import pc from 'picocolors'
5
- import { spawnSync } from 'node:child_process'
6
- import { readFileSync } from 'node:fs'
7
- import { findWranglerConfig } from '../lib/wrangler.js'
8
-
9
- export interface DeployOptions {
10
- skipSeed?: boolean
11
- skipCheck?: boolean
12
- }
13
-
14
- function readWorkerName(configPath: string | null): string | null {
15
- if (!configPath) return null
16
- try {
17
- const raw = readFileSync(configPath, 'utf-8')
18
- const stripped = raw
19
- .replace(/\/\/[^\n]*/g, '')
20
- .replace(/\/\*[\s\S]*?\*\//g, '')
21
- const parsed = JSON.parse(stripped)
22
- return (parsed?.name as string) ?? null
23
- } catch {
24
- return null
25
- }
26
- }
27
-
28
- // Extracts the first workers.dev URL from wrangler deploy stdout.
29
- // wrangler writes progress to stderr (shown live) and the summary to stdout (captured).
30
- function extractWorkerUrl(output: string): string | null {
31
- const match = output.match(/https:\/\/[a-zA-Z0-9-]+\.[a-zA-Z0-9-]+\.workers\.dev\b/)
32
- return match?.[0] ?? null
33
- }
34
-
35
- async function checkAdmin(url: string): Promise<{ ok: boolean; status: number | null }> {
36
- try {
37
- const res = await fetch(`${url}/admin`, {
38
- method: 'HEAD',
39
- redirect: 'follow',
40
- signal: AbortSignal.timeout(12_000),
41
- })
42
- return { ok: res.status < 500, status: res.status }
43
- } catch {
44
- return { ok: false, status: null }
45
- }
46
- }
47
-
48
- export async function deploy(args: DeployOptions): Promise<void> {
49
- console.log(pc.cyan('\n beech deploy\n'))
50
-
51
- // Step 1: wrangler deploy via npm run deploy.
52
- // stdout captured to extract the deployed URL; stderr stays on the terminal for live progress.
53
- console.log(pc.dim(' [1/3] Deploying Worker…\n'))
54
- const deployResult = spawnSync('npm', ['run', 'deploy'], {
55
- stdio: ['inherit', 'pipe', 'inherit'],
56
- encoding: 'utf-8',
57
- cwd: process.cwd(),
58
- shell: true,
59
- })
60
-
61
- const deployStdout = deployResult.stdout ?? ''
62
- if (deployStdout) process.stdout.write(deployStdout)
63
-
64
- if (deployResult.status !== 0) {
65
- console.log(pc.red('\n ✗ Worker deploy failed\n'))
66
- console.log(pc.dim(' Check the wrangler output above for details.'))
67
- console.log(pc.cyan('\n → Run: npx wrangler login # if not authenticated'))
68
- console.log(pc.cyan(' → Or: Update wrangler.jsonc # if database_id is wrong\n'))
69
- process.exit(1)
70
- }
71
-
72
- const deployedUrl = extractWorkerUrl(deployStdout)
73
- console.log(pc.green('\n ✓ Worker deployed'))
74
-
75
- // Step 2: seed:load --remote as a subprocess so that wrangler failures
76
- // (which call process.exit internally) don't abort our own process.
77
- if (args.skipSeed) {
78
- console.log(pc.dim('\n [2/3] Skipping seed:load (--skip-seed)'))
79
- } else {
80
- console.log(pc.dim('\n [2/3] Syncing content schema to remote D1…\n'))
81
- const seedResult = spawnSync('npx', ['beech', 'seed:load'], {
82
- stdio: 'inherit',
83
- cwd: process.cwd(),
84
- shell: true,
85
- })
86
- if (seedResult.status !== 0) {
87
- console.log(pc.yellow('\n ⚠ seed:load failed\n'))
88
- console.log(pc.dim(' Sync the remote content schema manually:'))
89
- console.log(pc.cyan(' → Run: npx beech seed:load\n'))
90
- } else {
91
- console.log(pc.green('\n ✓ Content schema synced'))
92
- }
93
- }
94
-
95
- // Step 3: check /admin reachability.
96
- // Use URL extracted from deploy output; fall back to worker name from wrangler.jsonc.
97
- if (args.skipCheck) {
98
- console.log(pc.dim('\n [3/3] Skipping admin check (--skip-check)\n'))
99
- return
100
- }
101
-
102
- const adminBase = deployedUrl ?? (() => {
103
- const workerName = readWorkerName(findWranglerConfig())
104
- // We can't reliably construct the full workers.dev subdomain without knowing the account,
105
- // so only use the name-based URL as a fallback when nothing better is available.
106
- return workerName ? `https://${workerName}.workers.dev` : null
107
- })()
108
-
109
- if (!adminBase) {
110
- console.log(pc.dim('\n [3/3] Could not determine worker URL — skipping admin check\n'))
111
- console.log(pc.dim(' The deployed URL is printed by wrangler above. Open <url>/admin to verify.\n'))
112
- return
113
- }
114
-
115
- console.log(pc.dim(`\n [3/3] Checking ${adminBase}/admin…\n`))
116
- const { ok, status } = await checkAdmin(adminBase)
117
-
118
- if (ok) {
119
- console.log(pc.green(` ✓ Admin reachable at: ${adminBase}/admin\n`))
120
- } else {
121
- const statusStr = status != null ? ` (HTTP ${status})` : ''
122
- console.log(pc.yellow(` ⚠ Admin returned an error${statusStr} at: ${adminBase}/admin\n`))
123
- console.log(pc.dim(' The database may not be fully initialized.'))
124
- console.log(pc.cyan(' → Run: npx beech init --db --remote\n'))
125
- }
126
- }
@@ -1,65 +0,0 @@
1
- // SPDX-License-Identifier: MIT
2
- // Copyright (c) 2024–2026 Flavio De Musso
3
-
4
- import { writeFileSync, mkdirSync } from 'node:fs'
5
- import { dirname, resolve } from 'node:path'
6
- import pc from 'picocolors'
7
- import type { Seed } from '@beechcms/core'
8
- import { generateSeedTypes } from '@beechcms/core'
9
- import {
10
- queryD1,
11
- findWranglerConfig,
12
- resolveDbName,
13
- type WranglerOptions,
14
- } from '../lib/wrangler.js'
15
-
16
- export interface GenerateTypesOptions {
17
- /** Output path for the generated .ts file. */
18
- out: string
19
- /** Read from in-code SEED_REGISTRY (true) instead of introspecting D1 (false). */
20
- local: boolean
21
- /** Pre-resolved registry (injected by bin/ for --local, and by tests). */
22
- registry?: Record<string, Seed> | null
23
- /** Override D1 database name (remote path only). */
24
- db?: string
25
- }
26
-
27
- interface SeedRow { slug: string; definition: string; [key: string]: unknown }
28
-
29
- /** Remote path: read canonical Seed JSON from the `seeds` system table. */
30
- function loadSeedsFromD1(db: string): Seed[] {
31
- const configPath = findWranglerConfig()
32
- const options: WranglerOptions = { db, local: false, configPath }
33
- const rows = queryD1<SeedRow>(
34
- `SELECT slug, definition FROM seeds WHERE status = 'active';`,
35
- options,
36
- )
37
- return rows.map(r => JSON.parse(r.definition) as Seed)
38
- }
39
-
40
- export async function generateTypes(args: GenerateTypesOptions): Promise<void> {
41
- let seeds: Seed[]
42
-
43
- if (args.local) {
44
- const registry = args.registry ?? {}
45
- if (Object.keys(registry).length === 0) {
46
- console.log(pc.red('\n ✗ No seeds found (seeds.ts empty or missing).\n'))
47
- process.exit(1)
48
- }
49
- seeds = Object.values(registry)
50
- } else {
51
- const db = args.db ?? resolveDbName(findWranglerConfig())
52
- seeds = loadSeedsFromD1(db)
53
- if (seeds.length === 0) {
54
- console.log(pc.red(`\n ✗ No active seeds in D1 (${db}). Run \`beech seed:load\` first.\n`))
55
- process.exit(1)
56
- }
57
- }
58
-
59
- const code = generateSeedTypes(seeds)
60
- const outPath = resolve(process.cwd(), args.out)
61
- mkdirSync(dirname(outPath), { recursive: true })
62
- writeFileSync(outPath, code, 'utf-8')
63
-
64
- console.log(pc.green(`\n ✓ Generated ${seeds.length} interface(s) → ${args.out}\n`))
65
- }