@brightsideoy/kama 0.1.0-alpha.110 → 0.1.0-alpha.112
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 +36 -15
- package/bin/cli.js +126 -75
- package/dist/assets/{index-42YPjwst.js → index-sepj3KuT.js} +1 -1
- package/dist/index.html +1 -1
- package/kama-worker/bundled-definitions.js +2394 -0
- package/kama-worker/bundled-definitions.ts +2395 -0
- package/package.json +1 -1
- package/scripts/bundle-definitions.js +10 -2
package/README.md
CHANGED
|
@@ -87,40 +87,61 @@ At the heart of KAMA is the Schema Engine. Instead of complex database migration
|
|
|
87
87
|
|
|
88
88
|
## Getting Started
|
|
89
89
|
|
|
90
|
-
KAMA comes with
|
|
90
|
+
KAMA comes with an interactive executable CLI to instantly spin up a full monorepo (Backend Worker + optional Astro Frontend), add new sites to existing workspaces, or promote local setups to Cloudflare Edge.
|
|
91
91
|
|
|
92
|
-
|
|
92
|
+
### 1. Initialize a Workspace\*\*
|
|
93
|
+
|
|
94
|
+
Run the KAMA CLI to start the workspace wizard:
|
|
93
95
|
|
|
94
96
|
```bash
|
|
95
|
-
npx
|
|
97
|
+
npx kama init
|
|
96
98
|
```
|
|
97
99
|
|
|
98
|
-
|
|
100
|
+
The CLI will prompt you for your setup preferences and automatically:
|
|
99
101
|
|
|
100
|
-
-
|
|
101
|
-
-
|
|
102
|
-
-
|
|
103
|
-
-
|
|
102
|
+
- Scaffold the `kama-worker` engine and content definition directories (`content/definitions/`).
|
|
103
|
+
- Authenticate with Cloudflare and auto-provision a remote D1 database + R2 bucket bindings (if deploying to Edge).
|
|
104
|
+
- Scaffold a fully configured Astro frontend site inside `sites/` with built-in edge-caching middleware.
|
|
105
|
+
- Configure local SQLite fallback environments for completely offline development.
|
|
104
106
|
|
|
105
|
-
|
|
107
|
+
### 2. Local Development
|
|
106
108
|
|
|
107
|
-
Start the
|
|
109
|
+
Start the local CMS dev server from your workspace root:
|
|
108
110
|
|
|
109
111
|
```bash
|
|
110
112
|
npm run dev:cms
|
|
111
113
|
```
|
|
112
114
|
|
|
113
|
-
This
|
|
115
|
+
This command automatically compiles your YAML/JSON schemas into runtime JavaScript definitions, syncs your local SQLite database, and launches the Miniflare worker environment on `http://localhost:8787`.
|
|
116
|
+
|
|
117
|
+
### 3. Management Commands\*\*
|
|
118
|
+
|
|
119
|
+
You can run CLI commands anytime inside your workspace.
|
|
120
|
+
|
|
121
|
+
#### Add a New Astro Frontend Site
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
npx kama add site
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
#### Promote a Local Workspace to Cloudflare Edge
|
|
128
|
+
|
|
129
|
+
Convert a local offline workspace to Cloudflare Edge (auto-links domains & D1 databases):
|
|
114
130
|
|
|
115
|
-
|
|
131
|
+
```bash
|
|
132
|
+
npx kama promote
|
|
133
|
+
```
|
|
116
134
|
|
|
117
|
-
|
|
135
|
+
### 4. Deploy
|
|
136
|
+
|
|
137
|
+
Deploy your CMS engine, content definitions, and database migrations to Cloudflare Edge:
|
|
118
138
|
|
|
119
139
|
```bash
|
|
120
140
|
npm run deploy:cms
|
|
121
141
|
```
|
|
122
142
|
|
|
123
|
-
|
|
143
|
+
> **Note:** For self-hosted virtual servers (VPS) or Docker environments, you can run `npm run dev:cms` under PM2/Docker as a standalone `workerd` server.
|
|
144
|
+
> <br>
|
|
124
145
|
|
|
125
146
|
## Directory Structure Overview
|
|
126
147
|
|
|
@@ -134,7 +155,7 @@ my-kama-workspace/
|
|
|
134
155
|
│ ├── nodes/ # e.g., page.yaml, product.yaml
|
|
135
156
|
│ ├── blocks/ # e.g., hero.yaml, image_card.yaml
|
|
136
157
|
│ └── node-layouts/ # e.g., two-column.yaml
|
|
137
|
-
├──
|
|
158
|
+
├── kama-worker/ # 👉 BACKEND PIPELINE
|
|
138
159
|
│ ├── index.js # Worker entrypoint (ES Module)
|
|
139
160
|
│ ├── wrangler.json # Bindings (D1, R2, Vars)
|
|
140
161
|
│ └── package.json
|
package/bin/cli.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { execSync } from 'node:child_process';
|
|
3
|
-
import { existsSync, mkdirSync, writeFileSync, readFileSync } from 'node:fs';
|
|
3
|
+
import { existsSync, mkdirSync, writeFileSync, readFileSync, readdirSync } from 'node:fs';
|
|
4
4
|
import { join, dirname } from 'node:path';
|
|
5
5
|
import { fileURLToPath } from 'node:url';
|
|
6
6
|
import * as readline from 'node:readline/promises';
|
|
7
7
|
|
|
8
|
-
// Dynamically resolve
|
|
8
|
+
// Dynamically resolve current package version
|
|
9
9
|
const __filename = fileURLToPath(import.meta.url);
|
|
10
10
|
const __dirname = dirname(__filename);
|
|
11
11
|
let currentKamaVersion = 'alpha';
|
|
@@ -25,25 +25,42 @@ const rl = readline.createInterface({
|
|
|
25
25
|
});
|
|
26
26
|
|
|
27
27
|
async function main() {
|
|
28
|
-
|
|
28
|
+
const args = process.argv.slice(2);
|
|
29
|
+
const command = args[0]?.toLowerCase();
|
|
30
|
+
const subCommand = args[1]?.toLowerCase();
|
|
29
31
|
|
|
30
|
-
console.log('
|
|
31
|
-
console.log(' 1) Kickstart new Kama Monorepo (CMS + Optional Site)');
|
|
32
|
-
console.log(' 2) Add a new Astro Site to current workspace (sites/)');
|
|
32
|
+
console.log('\n🔥 --- KAMA ENGINE CLI --- 🔥\n');
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
if (
|
|
34
|
+
if (command === 'init') {
|
|
35
|
+
await createFullWorkspace();
|
|
36
|
+
} else if (command === 'add' && subCommand === 'site') {
|
|
37
37
|
await createNewSiteOnly();
|
|
38
|
+
} else if (command === 'promote') {
|
|
39
|
+
await promoteLocalToCloudflare();
|
|
38
40
|
} else {
|
|
39
|
-
|
|
41
|
+
// Interactive menu when invoked without arguments or unrecognized command
|
|
42
|
+
console.log('Available Commands:');
|
|
43
|
+
console.log(' 1) npx kama init - Kickstart new Monorepo (CMS + Optional Site)');
|
|
44
|
+
console.log(' 2) npx kama add site - Add new Astro Site to current workspace (sites/)');
|
|
45
|
+
console.log(' 3) npx kama promote - Promote current Local workspace to Cloudflare Edge');
|
|
46
|
+
|
|
47
|
+
const choice = await rl.question('\nSelect choice [1/2/3]: ');
|
|
48
|
+
|
|
49
|
+
if (choice.trim() === '3') {
|
|
50
|
+
await promoteLocalToCloudflare();
|
|
51
|
+
} else if (choice.trim() === '2') {
|
|
52
|
+
await createNewSiteOnly();
|
|
53
|
+
} else {
|
|
54
|
+
await createFullWorkspace();
|
|
55
|
+
}
|
|
40
56
|
}
|
|
41
57
|
|
|
42
58
|
rl.close();
|
|
43
59
|
}
|
|
44
60
|
|
|
45
61
|
/**
|
|
46
|
-
*
|
|
62
|
+
* COMMAND: npx kama init
|
|
63
|
+
* Kickstart full Monorepo Workspace
|
|
47
64
|
*/
|
|
48
65
|
async function createFullWorkspace() {
|
|
49
66
|
const projName = (await rl.question('Project folder name [kama-workspace]: ')) || 'kama-workspace';
|
|
@@ -54,14 +71,12 @@ async function createFullWorkspace() {
|
|
|
54
71
|
const envChoice = await rl.question('\nChoice [1/2]: ');
|
|
55
72
|
const isCloudflare = envChoice.trim() === '2';
|
|
56
73
|
|
|
57
|
-
// 🎯 Ask if user wants an Astro frontend site scaffolded
|
|
58
74
|
const createSiteInput = await rl.question('\n🚀 Do you want to scaffold an initial Astro frontend site? (y/n) [y]: ');
|
|
59
75
|
const shouldCreateSite = createSiteInput.trim().toLowerCase() !== 'n';
|
|
60
76
|
|
|
61
77
|
let cmsDomain = 'localhost:8787';
|
|
62
78
|
let siteDomain = 'localhost:4321';
|
|
63
79
|
|
|
64
|
-
// Only ask for domains if deploying to Cloudflare Edge
|
|
65
80
|
if (isCloudflare) {
|
|
66
81
|
cmsDomain = (await rl.question('\nCMS Admin Domain (e.g., admin.t3cloud.eu): ')) || 'admin.t3cloud.eu';
|
|
67
82
|
if (shouldCreateSite) {
|
|
@@ -69,13 +84,10 @@ async function createFullWorkspace() {
|
|
|
69
84
|
}
|
|
70
85
|
}
|
|
71
86
|
|
|
72
|
-
// Standardize scheme for localhost vs custom edge domains
|
|
73
87
|
const cmsProtocol = isCloudflare ? 'https://' : 'http://';
|
|
74
88
|
const cmsFullUrl = `${cmsProtocol}${cmsDomain.replace(/^https?:\/\//, '')}`;
|
|
75
|
-
|
|
76
89
|
const rootDir = join(process.cwd(), projName);
|
|
77
90
|
|
|
78
|
-
// 🎯 Derive dynamic worker, database, and bucket names from project folder name
|
|
79
91
|
const workerName = `${projName}-worker`.toLowerCase().replace(/[^a-z0-9_-]/g, '-');
|
|
80
92
|
let dbName = `${projName}-db`.replace(/[^a-zA-Z0-9_-]/g, '_');
|
|
81
93
|
const bucketName = `${projName}-media-prod`.toLowerCase().replace(/[^a-z0-9_-]/g, '-');
|
|
@@ -83,22 +95,21 @@ async function createFullWorkspace() {
|
|
|
83
95
|
console.log(`\n📁 Creating workspace folder at ./${projName}...`);
|
|
84
96
|
mkdirSync(rootDir, { recursive: true });
|
|
85
97
|
|
|
86
|
-
// 🎯 Generate root .gitignore so auto-generated bundles and secrets stay out of git
|
|
87
98
|
writeFileSync(
|
|
88
99
|
join(rootDir, '.gitignore'),
|
|
89
100
|
`node_modules/
|
|
90
101
|
.env
|
|
91
102
|
.DS_Store
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
103
|
+
kama-worker/.dev.vars
|
|
104
|
+
kama-worker/bundled-definitions.js
|
|
105
|
+
kama-worker/bundled-definitions.ts
|
|
106
|
+
kama-worker/.wrangler/
|
|
95
107
|
sites/*/.env
|
|
96
108
|
sites/*/.astro/
|
|
97
109
|
sites/*/dist/
|
|
98
110
|
`
|
|
99
111
|
);
|
|
100
112
|
|
|
101
|
-
// 🎯 Scaffold full schema directory structure
|
|
102
113
|
const schemaCategories = [
|
|
103
114
|
'block-layouts',
|
|
104
115
|
'blocks',
|
|
@@ -113,10 +124,8 @@ sites/*/dist/
|
|
|
113
124
|
mkdirSync(join(rootDir, 'content', 'definitions', category), { recursive: true });
|
|
114
125
|
}
|
|
115
126
|
|
|
116
|
-
// 🎯 Populate starter example YAML files
|
|
117
127
|
scaffoldSampleSchemas(rootDir);
|
|
118
128
|
|
|
119
|
-
// --- AUTO D1 CREATION MAGIC ---
|
|
120
129
|
let d1DatabaseId = '00000000-0000-0000-0000-000000000000';
|
|
121
130
|
let isAuthenticated = false;
|
|
122
131
|
|
|
@@ -188,20 +197,18 @@ sites/*/dist/
|
|
|
188
197
|
} else {
|
|
189
198
|
console.log(`\n💻 Local mode selected. Skipping Cloudflare authentication and domain setup...`);
|
|
190
199
|
}
|
|
191
|
-
// ------------------------------
|
|
192
200
|
|
|
193
|
-
// 🎯 1. Root package.json (includes 'sites/*' wildcard in workspaces so user can add sites later)
|
|
194
201
|
writeFileSync(
|
|
195
202
|
join(rootDir, 'package.json'),
|
|
196
203
|
JSON.stringify({
|
|
197
204
|
name: projName,
|
|
198
205
|
private: true,
|
|
199
206
|
type: 'module',
|
|
200
|
-
workspaces: ['
|
|
207
|
+
workspaces: ['kama-worker', 'sites/*'],
|
|
201
208
|
scripts: {
|
|
202
209
|
'bundle:schemas': 'node node_modules/@brightsideoy/kama/scripts/bundle-definitions.js',
|
|
203
|
-
'dev:cms': 'npm run bundle:schemas && npm run dev -w
|
|
204
|
-
'deploy:cms': 'npm run bundle:schemas && npm run deploy -w
|
|
210
|
+
'dev:cms': 'npm run bundle:schemas && npm run dev -w kama-worker',
|
|
211
|
+
'deploy:cms': 'npm run bundle:schemas && npm run deploy -w kama-worker',
|
|
205
212
|
},
|
|
206
213
|
dependencies: {
|
|
207
214
|
'@brightsideoy/kama': currentKamaVersion,
|
|
@@ -209,16 +216,13 @@ sites/*/dist/
|
|
|
209
216
|
}, null, 2)
|
|
210
217
|
);
|
|
211
218
|
|
|
212
|
-
// 🎯 2. Setup CMS Worker with Dynamic Names
|
|
213
219
|
console.log(`\n☁️ Configuring CMS Worker '${workerName}' (${cmsDomain})...`);
|
|
214
|
-
const cmsDir = join(rootDir, '
|
|
220
|
+
const cmsDir = join(rootDir, 'kama-worker');
|
|
215
221
|
mkdirSync(cmsDir, { recursive: true });
|
|
216
222
|
|
|
217
|
-
// 🎯 Properly wrap and inject BUNDLED_DEFINITIONS from LOCAL workspace, not node_modules
|
|
218
223
|
const cmsWorkerIndexContent = `import kamaWorker from '@brightsideoy/kama';
|
|
219
224
|
import * as bundledModule from './bundled-definitions.js';
|
|
220
225
|
|
|
221
|
-
// Resolve BUNDLED_DEFINITIONS across all module resolution formats
|
|
222
226
|
const BUNDLED_DEFINITIONS =
|
|
223
227
|
bundledModule.BUNDLED_DEFINITIONS ||
|
|
224
228
|
bundledModule.default?.BUNDLED_DEFINITIONS ||
|
|
@@ -237,10 +241,7 @@ export default {
|
|
|
237
241
|
};
|
|
238
242
|
`;
|
|
239
243
|
|
|
240
|
-
writeFileSync(
|
|
241
|
-
join(cmsDir, 'index.js'),
|
|
242
|
-
cmsWorkerIndexContent
|
|
243
|
-
);
|
|
244
|
+
writeFileSync(join(cmsDir, 'index.js'), cmsWorkerIndexContent);
|
|
244
245
|
|
|
245
246
|
writeFileSync(
|
|
246
247
|
join(cmsDir, 'package.json'),
|
|
@@ -259,13 +260,12 @@ export default {
|
|
|
259
260
|
'@brightsideoy/kama': currentKamaVersion,
|
|
260
261
|
},
|
|
261
262
|
devDependencies: {
|
|
262
|
-
wrangler: '^
|
|
263
|
+
wrangler: '^4.0.0',
|
|
263
264
|
tsx: '^4.19.2',
|
|
264
265
|
},
|
|
265
266
|
}, null, 2)
|
|
266
267
|
);
|
|
267
268
|
|
|
268
|
-
// 🎯 Fixed CMS wrangler.json
|
|
269
269
|
const cmsWranglerConfig = {
|
|
270
270
|
$schema: '../node_modules/wrangler/config-schema.json',
|
|
271
271
|
name: workerName,
|
|
@@ -299,23 +299,18 @@ export default {
|
|
|
299
299
|
cmsWranglerConfig.routes = [{ pattern: cmsDomain, custom_domain: true }];
|
|
300
300
|
}
|
|
301
301
|
|
|
302
|
-
writeFileSync(
|
|
303
|
-
join(cmsDir, 'wrangler.json'),
|
|
304
|
-
JSON.stringify(cmsWranglerConfig, null, 2)
|
|
305
|
-
);
|
|
302
|
+
writeFileSync(join(cmsDir, 'wrangler.json'), JSON.stringify(cmsWranglerConfig, null, 2));
|
|
306
303
|
|
|
307
|
-
// 🎯 Fixed .dev.vars
|
|
308
304
|
writeFileSync(
|
|
309
305
|
join(cmsDir, '.dev.vars'),
|
|
310
306
|
`# Cloudflare Edge Cache Purging Secrets\nCLOUDFLARE_API_TOKEN=${isCloudflare ? 'cfut_YOUR_CUSTOM_PURGE_TOKEN' : 'local_token'}\n`
|
|
311
307
|
);
|
|
312
308
|
|
|
313
|
-
// 🎯 3. Setup Astro Site (ONLY if requested)
|
|
314
309
|
if (shouldCreateSite) {
|
|
315
310
|
const siteFolderName = isCloudflare ? siteDomain.split('.')[0] : 'web';
|
|
316
311
|
await generateAstroSite(rootDir, siteFolderName, siteDomain, cmsFullUrl, workerName, isCloudflare);
|
|
317
312
|
} else {
|
|
318
|
-
console.log(`\nℹ️ Skipping Astro site creation. You can add a site later by running 'npx
|
|
313
|
+
console.log(`\nℹ️ Skipping Astro site creation. You can add a site later by running 'npx kama add site' inside this workspace.`);
|
|
319
314
|
}
|
|
320
315
|
|
|
321
316
|
console.log(`\n✨ Workspace ready! Next steps:`);
|
|
@@ -326,17 +321,18 @@ export default {
|
|
|
326
321
|
if (d1DatabaseId === '00000000-0000-0000-0000-000000000000' || d1DatabaseId === 'REPLACE_WITH_YOUR_D1_ID') {
|
|
327
322
|
console.log(` 3. Run 'npx wrangler login' and create a D1 database manually.`);
|
|
328
323
|
}
|
|
329
|
-
console.log(` 4. Update CLOUDFLARE_ZONE_ID in
|
|
330
|
-
console.log(` 5. Securely store your purge token: cd
|
|
324
|
+
console.log(` 4. Update CLOUDFLARE_ZONE_ID in kama-worker/wrangler.json with your actual Zone ID`);
|
|
325
|
+
console.log(` 5. Securely store your purge token: cd kama-worker && npx wrangler secret put CLOUDFLARE_API_TOKEN`);
|
|
331
326
|
console.log(` 6. Run 'npm run dev:cms' from the workspace root to start the backend.`);
|
|
332
327
|
} else {
|
|
333
328
|
console.log(` 3. Run 'npm run dev:cms' from the workspace root to start the local SQLite backend.`);
|
|
334
|
-
console.log(`\n💡 Note: You can deploy to Cloudflare later by
|
|
329
|
+
console.log(`\n💡 Note: You can deploy to Cloudflare later by running 'npx kama promote'.`);
|
|
335
330
|
}
|
|
336
331
|
}
|
|
337
332
|
|
|
338
333
|
/**
|
|
339
|
-
*
|
|
334
|
+
* COMMAND: npx kama add site
|
|
335
|
+
* Add Astro Site to existing workspace
|
|
340
336
|
*/
|
|
341
337
|
async function createNewSiteOnly() {
|
|
342
338
|
const rootDir = process.cwd();
|
|
@@ -347,7 +343,7 @@ async function createNewSiteOnly() {
|
|
|
347
343
|
}
|
|
348
344
|
|
|
349
345
|
let targetWorkerName = 'kama-worker';
|
|
350
|
-
const cmsWranglerPath = join(rootDir, '
|
|
346
|
+
const cmsWranglerPath = join(rootDir, 'kama-worker', 'wrangler.json');
|
|
351
347
|
if (existsSync(cmsWranglerPath)) {
|
|
352
348
|
try {
|
|
353
349
|
const cmsWrangler = JSON.parse(readFileSync(cmsWranglerPath, 'utf-8'));
|
|
@@ -378,12 +374,88 @@ async function createNewSiteOnly() {
|
|
|
378
374
|
}
|
|
379
375
|
|
|
380
376
|
/**
|
|
381
|
-
*
|
|
377
|
+
* COMMAND: npx kama promote
|
|
378
|
+
* Promote current Local workspace to Cloudflare Edge
|
|
382
379
|
*/
|
|
380
|
+
async function promoteLocalToCloudflare() {
|
|
381
|
+
const rootDir = process.cwd();
|
|
382
|
+
const workerWranglerPath = join(rootDir, 'kama-worker', 'wrangler.json');
|
|
383
|
+
|
|
384
|
+
if (!existsSync(workerWranglerPath)) {
|
|
385
|
+
console.error('❌ Error: Could not find kama-worker/wrangler.json. Run this command inside your workspace root.');
|
|
386
|
+
return;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
console.log('\n🌐 --- PROMOTING WORKSPACE TO CLOUDFLARE EDGE --- 🌐\n');
|
|
390
|
+
|
|
391
|
+
try {
|
|
392
|
+
execSync('npx wrangler whoami', { stdio: 'pipe' });
|
|
393
|
+
console.log('✅ Logged in to Cloudflare.');
|
|
394
|
+
} catch (e) {
|
|
395
|
+
console.log('🌐 Launching browser for Cloudflare login...');
|
|
396
|
+
try {
|
|
397
|
+
execSync('npx wrangler login', { stdio: 'inherit' });
|
|
398
|
+
} catch (loginError) {
|
|
399
|
+
console.log('❌ Cloudflare login failed or was cancelled.');
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
const cmsDomain = (await rl.question('\nCMS Admin Domain (e.g., admin.t3cloud.eu): ')) || 'admin.t3cloud.eu';
|
|
405
|
+
|
|
406
|
+
const sitesFolderDir = join(rootDir, 'sites');
|
|
407
|
+
let siteDomain = '';
|
|
408
|
+
if (existsSync(sitesFolderDir)) {
|
|
409
|
+
siteDomain = await rl.question('Frontend Website Domain (e.g., kama.t3cloud.eu): ');
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
const currentConfig = JSON.parse(readFileSync(workerWranglerPath, 'utf-8'));
|
|
413
|
+
const dbName = currentConfig.d1_databases?.[0]?.database_name || 'kama_db';
|
|
414
|
+
|
|
415
|
+
console.log(`\n🗄️ Provisioning remote Cloudflare D1 Database '${dbName}'...`);
|
|
416
|
+
let d1DatabaseId = '00000000-0000-0000-0000-000000000000';
|
|
417
|
+
|
|
418
|
+
try {
|
|
419
|
+
const d1Output = execSync(`npx wrangler d1 create ${dbName}`, { encoding: 'utf-8', stdio: 'pipe' });
|
|
420
|
+
const match = d1Output.match(/[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}/);
|
|
421
|
+
if (match) d1DatabaseId = match[0];
|
|
422
|
+
} catch (err) {
|
|
423
|
+
console.log('⚠️ Could not auto-create D1 (it may already exist). Please verify on your Cloudflare dashboard.');
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
currentConfig.vars.CDN_DOMAIN = cmsDomain;
|
|
427
|
+
if (siteDomain) {
|
|
428
|
+
currentConfig.vars.PUBLIC_FRONTEND_URL = `https://${siteDomain}`;
|
|
429
|
+
}
|
|
430
|
+
currentConfig.routes = [{ pattern: cmsDomain, custom_domain: true }];
|
|
431
|
+
if (currentConfig.d1_databases?.[0]) {
|
|
432
|
+
currentConfig.d1_databases[0].database_id = d1DatabaseId;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
writeFileSync(workerWranglerPath, JSON.stringify(currentConfig, null, 2));
|
|
436
|
+
|
|
437
|
+
if (siteDomain && existsSync(sitesFolderDir)) {
|
|
438
|
+
const sites = readdirSync(sitesFolderDir);
|
|
439
|
+
if (sites.length > 0) {
|
|
440
|
+
const siteWranglerPath = join(sitesFolderDir, sites[0], 'wrangler.json');
|
|
441
|
+
if (existsSync(siteWranglerPath)) {
|
|
442
|
+
const siteConfig = JSON.parse(readFileSync(siteWranglerPath, 'utf-8'));
|
|
443
|
+
siteConfig.routes = [{ pattern: siteDomain, custom_domain: true }];
|
|
444
|
+
siteConfig.vars.PUBLIC_CMS_URL = `https://${cmsDomain}`;
|
|
445
|
+
siteConfig.vars.PUBLIC_API_URL = `https://${cmsDomain}`;
|
|
446
|
+
writeFileSync(siteWranglerPath, JSON.stringify(siteConfig, null, 2));
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
console.log(`\n✅ Workspace successfully configured for Cloudflare Edge!`);
|
|
452
|
+
console.log(`\nNext steps:`);
|
|
453
|
+
console.log(` 1. Run 'npm run deploy:cms' from the root to publish your backend and database.`);
|
|
454
|
+
}
|
|
455
|
+
|
|
383
456
|
function scaffoldSampleSchemas(rootDir) {
|
|
384
457
|
const defsDir = join(rootDir, 'content', 'definitions');
|
|
385
458
|
|
|
386
|
-
// 1. Channels
|
|
387
459
|
writeFileSync(join(defsDir, 'channels', 'website.yaml'), `id: website
|
|
388
460
|
label: Main Website
|
|
389
461
|
defaultLanguage: en
|
|
@@ -392,7 +464,6 @@ languages:
|
|
|
392
464
|
- fi
|
|
393
465
|
`);
|
|
394
466
|
|
|
395
|
-
// 2. Nodes
|
|
396
467
|
writeFileSync(join(defsDir, 'nodes', 'page.yaml'), `id: page
|
|
397
468
|
label: Page
|
|
398
469
|
inTree: true
|
|
@@ -431,7 +502,6 @@ tabs:
|
|
|
431
502
|
linkedTo: title
|
|
432
503
|
`);
|
|
433
504
|
|
|
434
|
-
// 3. Blocks
|
|
435
505
|
writeFileSync(join(defsDir, 'blocks', 'hero.yaml'), `id: hero
|
|
436
506
|
label: Hero Section
|
|
437
507
|
fields:
|
|
@@ -452,7 +522,6 @@ fields:
|
|
|
452
522
|
type: richtext
|
|
453
523
|
`);
|
|
454
524
|
|
|
455
|
-
// 4. Block Layouts
|
|
456
525
|
writeFileSync(join(defsDir, 'block-layouts', 'two-column.yaml'), `id: two-column
|
|
457
526
|
label: Two Column Layout
|
|
458
527
|
regions:
|
|
@@ -462,7 +531,6 @@ regions:
|
|
|
462
531
|
label: Right Column
|
|
463
532
|
`);
|
|
464
533
|
|
|
465
|
-
// 5. Node Layouts
|
|
466
534
|
writeFileSync(join(defsDir, 'node-layouts', 'single-column.yml'), `id: single-column
|
|
467
535
|
label: Single Column Page
|
|
468
536
|
regions:
|
|
@@ -470,7 +538,6 @@ regions:
|
|
|
470
538
|
label: Main Content Area
|
|
471
539
|
`);
|
|
472
540
|
|
|
473
|
-
// 6. Field Sets
|
|
474
541
|
writeFileSync(join(defsDir, 'field-sets', 'page-base.yaml'), `id: page-base
|
|
475
542
|
label: Base Page Fields
|
|
476
543
|
fields:
|
|
@@ -482,7 +549,6 @@ fields:
|
|
|
482
549
|
type: text
|
|
483
550
|
`);
|
|
484
551
|
|
|
485
|
-
// 7. Trees
|
|
486
552
|
writeFileSync(join(defsDir, 'trees', 'navigation.yaml'), `id: navigation
|
|
487
553
|
label: Main Navigation Tree
|
|
488
554
|
maxDepth: 3
|
|
@@ -491,9 +557,6 @@ allowedNodeTypes:
|
|
|
491
557
|
`);
|
|
492
558
|
}
|
|
493
559
|
|
|
494
|
-
/**
|
|
495
|
-
* Helper: Scaffolds the Astro site with middleware, wrangler.json, & slug page
|
|
496
|
-
*/
|
|
497
560
|
async function generateAstroSite(rootDir, siteFolder, siteDomain, cmsFullUrl, workerName = 'kama-worker', isCloudflare = false) {
|
|
498
561
|
console.log(`\n🚀 Scaffolding Astro site (${siteFolder}) mapped to ${siteDomain} (Service: ${workerName})...`);
|
|
499
562
|
|
|
@@ -520,7 +583,7 @@ async function generateAstroSite(rootDir, siteFolder, siteDomain, cmsFullUrl, wo
|
|
|
520
583
|
'@astrojs/cloudflare': '^14.2.5',
|
|
521
584
|
'@brightsideoy/kama': currentKamaVersion,
|
|
522
585
|
astro: '^7.2.0',
|
|
523
|
-
wrangler: '^
|
|
586
|
+
wrangler: '^4.0.0',
|
|
524
587
|
},
|
|
525
588
|
}, null, 2)
|
|
526
589
|
);
|
|
@@ -582,7 +645,6 @@ export default defineConfig({
|
|
|
582
645
|
`PUBLIC_CMS_URL="${cmsFullUrl}"\nPUBLIC_API_URL="${cmsFullUrl}"\n`
|
|
583
646
|
);
|
|
584
647
|
|
|
585
|
-
// 🎯 Scaffold the Base Layout
|
|
586
648
|
writeFileSync(
|
|
587
649
|
join(siteDir, 'src/layouts/Layout.astro'),
|
|
588
650
|
`---
|
|
@@ -606,7 +668,6 @@ const { title } = Astro.props;
|
|
|
606
668
|
</html>`
|
|
607
669
|
);
|
|
608
670
|
|
|
609
|
-
// 🎯 Scaffold the Dynamic Slug Page
|
|
610
671
|
writeFileSync(
|
|
611
672
|
join(siteDir, 'src/pages/[...slug].astro'),
|
|
612
673
|
`---
|
|
@@ -614,10 +675,6 @@ import Layout from '../layouts/Layout.astro';
|
|
|
614
675
|
|
|
615
676
|
const { slug } = Astro.params;
|
|
616
677
|
const cmsUrl = import.meta.env.PUBLIC_CMS_URL;
|
|
617
|
-
|
|
618
|
-
// Example Data Fetch: Replace with actual KAMA fetch logic
|
|
619
|
-
// const response = await fetch(\`\${cmsUrl}/api/pages/\${slug || 'home'}\`);
|
|
620
|
-
// const pageData = await response.json();
|
|
621
678
|
---
|
|
622
679
|
<Layout title="Kama Generated Site">
|
|
623
680
|
\t<main>
|
|
@@ -627,7 +684,6 @@ const cmsUrl = import.meta.env.PUBLIC_CMS_URL;
|
|
|
627
684
|
</Layout>`
|
|
628
685
|
);
|
|
629
686
|
|
|
630
|
-
// 🎯 Scaffold the Full Edge-Caching Middleware
|
|
631
687
|
writeFileSync(
|
|
632
688
|
join(siteDir, 'src/middleware.ts'),
|
|
633
689
|
`import { defineMiddleware } from "astro:middleware";
|
|
@@ -639,7 +695,6 @@ export const onRequest = defineMiddleware(async (context, next) => {
|
|
|
639
695
|
const workerEnv = cfContext?.env || (env as any);
|
|
640
696
|
const HTML_CACHE = workerEnv?.HTML_CACHE;
|
|
641
697
|
|
|
642
|
-
// 🎯 1. CACHE PURGE ENDPOINT
|
|
643
698
|
if (pathname === "/api/purge" || pathname === "/api/purge/") {
|
|
644
699
|
if (context.request.method !== "POST") return new Response("Method Not Allowed", { status: 405 });
|
|
645
700
|
|
|
@@ -657,12 +712,11 @@ export const onRequest = defineMiddleware(async (context, next) => {
|
|
|
657
712
|
}));
|
|
658
713
|
}
|
|
659
714
|
|
|
660
|
-
// Surgical delete
|
|
661
715
|
if (Array.isArray(body.deleted_urls) && body.deleted_urls.length > 0) {
|
|
662
716
|
await Promise.all(body.deleted_urls.map(async (u: string) => {
|
|
663
717
|
const path = new URL(u).pathname.replace(/\\/$/, "") || "/";
|
|
664
718
|
const [siteVer, pageVer] = await Promise.all([
|
|
665
|
-
HTML_CACHE.get("site_version"), HTML_CACHE.get(\`v:\${
|
|
719
|
+
HTML_CACHE.get("site_version"), HTML_CACHE.get(\`v:\${cleanLookupPath}\`)
|
|
666
720
|
]);
|
|
667
721
|
if (siteVer || pageVer) {
|
|
668
722
|
await HTML_CACHE.delete(\`\${path}:v:\${siteVer || "1"}:\${pageVer || "1"}\`);
|
|
@@ -672,7 +726,6 @@ export const onRequest = defineMiddleware(async (context, next) => {
|
|
|
672
726
|
}
|
|
673
727
|
}
|
|
674
728
|
|
|
675
|
-
// Astro Worker Cache layer flush
|
|
676
729
|
if (typeof cfContext?.cache?.purge === 'function') await cfContext.cache.purge({ purgeEverything: true });
|
|
677
730
|
|
|
678
731
|
return new Response(JSON.stringify({ success: true }), { status: 200 });
|
|
@@ -681,7 +734,6 @@ export const onRequest = defineMiddleware(async (context, next) => {
|
|
|
681
734
|
}
|
|
682
735
|
}
|
|
683
736
|
|
|
684
|
-
// 🎯 2. KV HTML STATIC LOOKUP
|
|
685
737
|
const isWarmer = context.request.headers.get("X-Cache-Warmer") === "true";
|
|
686
738
|
const isHtmlPage = !pathname.includes('.') && !pathname.startsWith('/api/');
|
|
687
739
|
const cleanLookupPath = pathname.replace(/\\/$/, "") || "/";
|
|
@@ -713,7 +765,6 @@ export const onRequest = defineMiddleware(async (context, next) => {
|
|
|
713
765
|
|
|
714
766
|
const response = await next();
|
|
715
767
|
|
|
716
|
-
// 🎯 3. KV HTML STATIC WRITE
|
|
717
768
|
if (isHtmlPage && HTML_CACHE && response.status === 200 && response.headers.get("content-type")?.includes("text/html")) {
|
|
718
769
|
const htmlText = await response.clone().text();
|
|
719
770
|
const writeTask = (async () => {
|