@brightsideoy/kama 1.0.0-alpha.3 → 1.0.0-alpha.5
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.js +156 -278
- package/dist/assets/{index-DhguVxzs.js → index-DG2Asvtk.js} +41 -41
- package/dist/assets/index-NX0xNTzY.css +1 -0
- package/dist/{dist-cK3xGnBZ.js → dist-BmDMKgKk.js} +441 -378
- package/dist/index.html +2 -2
- package/dist/index.js +441 -378
- package/dist/schema-compiler.js +1 -1
- package/npm-update.sh +67 -0
- package/package.json +1 -1
- package/templates/astro-starter/src/layouts/StandardLayout.astro +5 -5
- package/templates/astro-starter/src/middleware.ts +115 -42
- package/templates/astro-starter/src/pages/[...slug].astro +61 -31
- package/dist/assets/index-C3LzwJjY.css +0 -1
package/bin/cli.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { execSync } from 'node:child_process';
|
|
3
|
-
import { existsSync, mkdirSync, writeFileSync, readFileSync, readdirSync, cpSync, unlinkSync
|
|
3
|
+
import { existsSync, mkdirSync, writeFileSync, readFileSync, readdirSync, cpSync, unlinkSync } from 'node:fs';
|
|
4
4
|
import { join, dirname, basename, resolve } from 'node:path';
|
|
5
5
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
6
6
|
|
|
@@ -48,28 +48,78 @@ try {
|
|
|
48
48
|
console.warn("⚠️ Could not detect Kama version, defaulting to 'alpha'");
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
+
/**
|
|
52
|
+
* 🎯 BULLETPROOF WRANGLER EXECUTION RESOLVER
|
|
53
|
+
* Forces npx to load wrangler via explicit --package definition to prevent
|
|
54
|
+
* subshell binary resolution crashes inside automated npx contexts.
|
|
55
|
+
*/
|
|
56
|
+
function getWranglerCmd() {
|
|
57
|
+
try {
|
|
58
|
+
execSync('wrangler --version', { stdio: 'ignore' });
|
|
59
|
+
return 'wrangler';
|
|
60
|
+
} catch (e) {
|
|
61
|
+
return 'npx --yes --package=wrangler wrangler';
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* 🎯 ROBUST WRANGLER RUNNER
|
|
67
|
+
* Inherits full process environment and executes safely across isolated subshells.
|
|
68
|
+
*/
|
|
69
|
+
function runWrangler(cmd, options = {}) {
|
|
70
|
+
const baseWrangler = getWranglerCmd();
|
|
71
|
+
try {
|
|
72
|
+
return execSync(`${baseWrangler} ${cmd}`, {
|
|
73
|
+
encoding: 'utf-8',
|
|
74
|
+
stdio: options.stdio || ['ignore', 'pipe', 'pipe'],
|
|
75
|
+
env: {
|
|
76
|
+
...process.env,
|
|
77
|
+
PATH: process.env.PATH
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
} catch (e) {
|
|
81
|
+
if (options.throw) throw e;
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* 🎯 BULLETPROOF KV PROVISIONING ENGINE
|
|
88
|
+
*/
|
|
89
|
+
function getOrCreateKV(title) {
|
|
90
|
+
const out = runWrangler(`kv namespace create "${title}"`);
|
|
91
|
+
if (out) {
|
|
92
|
+
const match = out.match(/"id":\s*"([a-fA-F0-9]{32})"/);
|
|
93
|
+
if (match) return match[1];
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const listOut = runWrangler(`kv namespace list`);
|
|
97
|
+
if (listOut) {
|
|
98
|
+
try {
|
|
99
|
+
const namespaces = JSON.parse(listOut);
|
|
100
|
+
const found = namespaces.find(n => n.title === title);
|
|
101
|
+
if (found) return found.id;
|
|
102
|
+
} catch (err) { }
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return `REPLACE_WITH_${title}_ID`;
|
|
106
|
+
}
|
|
107
|
+
|
|
51
108
|
function showHelp() {
|
|
52
109
|
console.log(`\n${pc.bgCyan(' KAMA • ENGINE CLI ')}\n`);
|
|
53
110
|
console.log('Usage: npx kama <command> [options]\n');
|
|
54
|
-
|
|
55
111
|
console.log(pc.cyan('Commands:'));
|
|
56
112
|
console.log(' init Kickstart a new Monorepo (CMS Worker + Optional Astro Site)');
|
|
57
113
|
console.log(' add site Add a new Astro Frontend Site to the current workspace (sites/)');
|
|
58
114
|
console.log(' bundle Compile and bundle YAML schemas into bundled-definitions.js for Edge deployment');
|
|
59
115
|
console.log(' promote Promote the current Local workspace to Cloudflare Edge');
|
|
60
116
|
console.log(' help, -h Show this help message\n');
|
|
61
|
-
|
|
62
117
|
console.log(pc.cyan('Workspace Scripts (Run from project root):'));
|
|
63
118
|
console.log(' npm update Update to latest KAMA version');
|
|
64
|
-
console.log(' npm run setup Initialize database schema
|
|
119
|
+
console.log(' npm run setup Initialize database schema (Run Once)');
|
|
65
120
|
console.log(' npm run dev Boot up the CMS backend and Astro frontend concurrently');
|
|
66
121
|
console.log(' npm run deploy:cms Deploy the backend worker and database to Cloudflare');
|
|
67
122
|
console.log(' npm run deploy:site Deploy the Astro frontend site to Cloudflare\n');
|
|
68
|
-
|
|
69
|
-
console.log(pc.cyan('Examples:'));
|
|
70
|
-
console.log(' npx kama init');
|
|
71
|
-
console.log(' npx kama add site');
|
|
72
|
-
console.log(' npx kama bundle\n');
|
|
73
123
|
}
|
|
74
124
|
|
|
75
125
|
async function main() {
|
|
@@ -124,9 +174,6 @@ async function main() {
|
|
|
124
174
|
}
|
|
125
175
|
}
|
|
126
176
|
|
|
127
|
-
/**
|
|
128
|
-
* Helper to update astro.config.mjs for Cloudflare
|
|
129
|
-
*/
|
|
130
177
|
function convertAstroConfigToCloudflare(siteDir) {
|
|
131
178
|
const configPath = join(siteDir, 'astro.config.mjs');
|
|
132
179
|
if (existsSync(configPath)) {
|
|
@@ -140,7 +187,6 @@ function convertAstroConfigToCloudflare(siteDir) {
|
|
|
140
187
|
|
|
141
188
|
/**
|
|
142
189
|
* COMMAND: npx kama init
|
|
143
|
-
* Kickstart full Monorepo Workspace
|
|
144
190
|
*/
|
|
145
191
|
async function createFullWorkspace() {
|
|
146
192
|
const cwdName = basename(process.cwd());
|
|
@@ -206,9 +252,7 @@ async function createFullWorkspace() {
|
|
|
206
252
|
const s = spinner();
|
|
207
253
|
s.start('Provisioning workspace...');
|
|
208
254
|
|
|
209
|
-
if (!isCurrentDir) {
|
|
210
|
-
mkdirSync(rootDir, { recursive: true });
|
|
211
|
-
}
|
|
255
|
+
if (!isCurrentDir) mkdirSync(rootDir, { recursive: true });
|
|
212
256
|
|
|
213
257
|
writeFileSync(
|
|
214
258
|
join(rootDir, '.gitignore'),
|
|
@@ -217,100 +261,78 @@ async function createFullWorkspace() {
|
|
|
217
261
|
|
|
218
262
|
const sourceDefsDir = join(__dirname, '../content/definitions');
|
|
219
263
|
const targetDefsDir = join(rootDir, 'content', 'definitions');
|
|
220
|
-
if (existsSync(sourceDefsDir)) {
|
|
221
|
-
cpSync(sourceDefsDir, targetDefsDir, { recursive: true });
|
|
222
|
-
}
|
|
264
|
+
if (existsSync(sourceDefsDir)) cpSync(sourceDefsDir, targetDefsDir, { recursive: true });
|
|
223
265
|
|
|
224
266
|
let d1DatabaseId = '00000000-0000-0000-0000-000000000000';
|
|
267
|
+
let backendCacheId = 'REPLACE_WITH_CACHE_KV_ID';
|
|
225
268
|
let isAuthenticated = false;
|
|
226
269
|
|
|
227
270
|
if (isCloudflare) {
|
|
228
271
|
s.message('Checking Cloudflare authentication...');
|
|
229
|
-
|
|
230
|
-
|
|
272
|
+
const whoami = runWrangler('whoami');
|
|
273
|
+
if (whoami && (whoami.includes('Getting User Settings') || whoami.includes('You are logged in'))) {
|
|
231
274
|
isAuthenticated = true;
|
|
232
|
-
}
|
|
275
|
+
} else {
|
|
233
276
|
s.stop('Not authenticated with Cloudflare.', true);
|
|
234
277
|
console.log(pc.dim('Launching browser for Cloudflare login...'));
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
isAuthenticated = true;
|
|
238
|
-
} catch (loginError) {
|
|
239
|
-
// Ignore
|
|
240
|
-
}
|
|
278
|
+
const login = runWrangler('login', { stdio: 'inherit' });
|
|
279
|
+
if (login !== null) isAuthenticated = true;
|
|
241
280
|
s.start('Resuming provisioning...');
|
|
242
281
|
}
|
|
243
282
|
|
|
244
283
|
if (isAuthenticated) {
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
message: 'Do you want to link this existing database?',
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
s.start(`Creating new database '${dbName}'...`);
|
|
273
|
-
const d1Output = execSync(`npx wrangler d1 create ${dbName}`, { encoding: 'utf-8', stdio: ['ignore', 'pipe', 'pipe'] });
|
|
274
|
-
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}/);
|
|
275
|
-
if (match) {
|
|
276
|
-
d1DatabaseId = match[0];
|
|
284
|
+
s.message('Provisioning backend KV Cache...');
|
|
285
|
+
backendCacheId = getOrCreateKV(`CACHE_KV_${workerName.toUpperCase().replace(/-/g, '_')}`);
|
|
286
|
+
|
|
287
|
+
s.message('Checking existing Cloudflare D1 databases...');
|
|
288
|
+
const listOutput = runWrangler('d1 list --json');
|
|
289
|
+
if (listOutput) {
|
|
290
|
+
try {
|
|
291
|
+
const jsonStart = listOutput.indexOf('[');
|
|
292
|
+
const jsonEnd = listOutput.lastIndexOf(']') + 1;
|
|
293
|
+
let databases = [];
|
|
294
|
+
|
|
295
|
+
if (jsonStart !== -1 && jsonEnd !== -1) databases = JSON.parse(listOutput.substring(jsonStart, jsonEnd));
|
|
296
|
+
const existingDb = databases.find(db => db.name === dbName);
|
|
297
|
+
|
|
298
|
+
if (existingDb) {
|
|
299
|
+
s.stop(`Database '${dbName}' already exists on your account.`);
|
|
300
|
+
const useExisting = handleCancel(await confirm({ message: 'Do you want to link this existing database?', initialValue: true }));
|
|
301
|
+
|
|
302
|
+
if (useExisting) {
|
|
303
|
+
d1DatabaseId = existingDb.uuid;
|
|
304
|
+
s.start(`Linked existing database ID: ${d1DatabaseId}`);
|
|
305
|
+
} else {
|
|
306
|
+
dbName = handleCancel(await text({ message: 'Enter a new database name:' }));
|
|
307
|
+
s.start(`Creating new database '${dbName}'...`);
|
|
308
|
+
const d1Output = runWrangler(`d1 create ${dbName}`);
|
|
309
|
+
const match = d1Output ? 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}/) : null;
|
|
310
|
+
if (match) d1DatabaseId = match[0];
|
|
277
311
|
}
|
|
312
|
+
} else {
|
|
313
|
+
s.message(`Attempting to auto-create Cloudflare D1 Database '${dbName}'...`);
|
|
314
|
+
const d1Output = runWrangler(`d1 create ${dbName}`);
|
|
315
|
+
const match = d1Output ? 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}/) : null;
|
|
316
|
+
if (match) d1DatabaseId = match[0];
|
|
278
317
|
}
|
|
279
|
-
}
|
|
280
|
-
s.message(`Attempting to auto-create Cloudflare D1 Database '${dbName}'...`);
|
|
281
|
-
const d1Output = execSync(`npx wrangler d1 create ${dbName}`, { encoding: 'utf-8', stdio: ['ignore', 'pipe', 'pipe'] });
|
|
282
|
-
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}/);
|
|
283
|
-
if (match) {
|
|
284
|
-
d1DatabaseId = match[0];
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
} catch (error) {
|
|
288
|
-
// Placeholder
|
|
318
|
+
} catch (error) { }
|
|
289
319
|
}
|
|
290
320
|
}
|
|
291
321
|
}
|
|
292
322
|
|
|
293
323
|
s.message('Writing configuration files...');
|
|
294
324
|
|
|
295
|
-
const rootScripts = {
|
|
296
|
-
'setup': 'npm run setup:local -w kama-worker',
|
|
297
|
-
};
|
|
298
|
-
|
|
299
325
|
const rootPkg = {
|
|
300
326
|
name: projName,
|
|
301
327
|
private: true,
|
|
302
328
|
type: 'module',
|
|
303
329
|
workspaces: ['kama-worker', 'sites/*'],
|
|
304
|
-
scripts:
|
|
305
|
-
dependencies: {
|
|
306
|
-
'@brightsideoy/kama': currentKamaVersion,
|
|
307
|
-
},
|
|
330
|
+
scripts: { 'setup': 'npm run setup:local -w kama-worker' },
|
|
331
|
+
dependencies: { '@brightsideoy/kama': currentKamaVersion },
|
|
308
332
|
devDependencies: {}
|
|
309
333
|
};
|
|
310
334
|
|
|
311
|
-
if (isCloudflare)
|
|
312
|
-
rootPkg.devDependencies['wrangler'] = WRANGLER_LATEST;
|
|
313
|
-
}
|
|
335
|
+
if (isCloudflare) rootPkg.devDependencies['wrangler'] = WRANGLER_LATEST;
|
|
314
336
|
|
|
315
337
|
if (shouldCreateSite) {
|
|
316
338
|
rootPkg.devDependencies['concurrently'] = '^9.0.0';
|
|
@@ -330,16 +352,12 @@ async function createFullWorkspace() {
|
|
|
330
352
|
const cmsDir = join(rootDir, 'kama-worker');
|
|
331
353
|
mkdirSync(cmsDir, { recursive: true });
|
|
332
354
|
|
|
333
|
-
writeFileSync(join(cmsDir, 'seed.sql'), '-- Kama Auto-Generated Seed File\nSELECT 1;\n');
|
|
334
|
-
|
|
335
355
|
const emptyDefs = `{ nodes: {}, trees: {}, blocks: {}, nodeLayouts: {}, blockLayouts: {}, channels: {} }`;
|
|
336
356
|
writeFileSync(join(cmsDir, 'bundled-definitions.js'), `const defs = ${emptyDefs};\nexport const BUNDLED_DEFINITIONS = defs;\nexport default defs;\n`);
|
|
337
357
|
|
|
338
358
|
if (isCloudflare) {
|
|
339
359
|
const templateIndexPath = join(__dirname, '../templates/kama-worker/index.js');
|
|
340
|
-
if (existsSync(templateIndexPath))
|
|
341
|
-
cpSync(templateIndexPath, join(cmsDir, 'index.js'));
|
|
342
|
-
}
|
|
360
|
+
if (existsSync(templateIndexPath)) cpSync(templateIndexPath, join(cmsDir, 'index.js'));
|
|
343
361
|
|
|
344
362
|
writeFileSync(
|
|
345
363
|
join(cmsDir, 'package.json'),
|
|
@@ -348,18 +366,13 @@ async function createFullWorkspace() {
|
|
|
348
366
|
type: 'module',
|
|
349
367
|
version: '1.0.0',
|
|
350
368
|
scripts: {
|
|
351
|
-
"setup:local": `wrangler d1 execute ${dbName} --local --file=../node_modules/@brightsideoy/kama/schema.sql > /dev/null 2>&1
|
|
352
|
-
"setup:remote": `wrangler d1 execute ${dbName} --remote --file=../node_modules/@brightsideoy/kama/schema.sql
|
|
369
|
+
"setup:local": `wrangler d1 execute ${dbName} --local --file=../node_modules/@brightsideoy/kama/schema.sql > /dev/null 2>&1`,
|
|
370
|
+
"setup:remote": `wrangler d1 execute ${dbName} --remote --file=../node_modules/@brightsideoy/kama/schema.sql`,
|
|
353
371
|
"dev": "wrangler dev --port 8787 --inspector-port 9239",
|
|
354
372
|
"deploy": "npm run setup:remote && wrangler deploy"
|
|
355
373
|
},
|
|
356
|
-
dependencies: {
|
|
357
|
-
|
|
358
|
-
'@libsql/client': '^0.14.0'
|
|
359
|
-
},
|
|
360
|
-
devDependencies: {
|
|
361
|
-
"wrangler": WRANGLER_LATEST
|
|
362
|
-
},
|
|
374
|
+
dependencies: { '@brightsideoy/kama': currentKamaVersion, '@libsql/client': '^0.14.0' },
|
|
375
|
+
devDependencies: { "wrangler": WRANGLER_LATEST },
|
|
363
376
|
}, null, 2)
|
|
364
377
|
);
|
|
365
378
|
|
|
@@ -370,9 +383,9 @@ async function createFullWorkspace() {
|
|
|
370
383
|
compatibility_date: '2024-09-23',
|
|
371
384
|
compatibility_flags: ['nodejs_compat'],
|
|
372
385
|
dev: { host: 'localhost', port: 8787 },
|
|
373
|
-
cache: { enabled: true },
|
|
374
386
|
assets: { directory: '../node_modules/@brightsideoy/kama/dist', binding: 'ASSETS' },
|
|
375
387
|
images: { binding: 'IMAGES' },
|
|
388
|
+
kv_namespaces: [{ binding: 'CACHE_KV', id: backendCacheId }],
|
|
376
389
|
vars: {
|
|
377
390
|
CDN_DOMAIN: cmsDomain || 'localhost:8787',
|
|
378
391
|
PUBLIC_FRONTEND_URL: (shouldCreateSite) ? (siteDomain && siteDomain !== 'localhost:4321' ? `https://${siteDomain}` : 'http://localhost:4321') : 'http://localhost:4321',
|
|
@@ -385,13 +398,10 @@ async function createFullWorkspace() {
|
|
|
385
398
|
};
|
|
386
399
|
|
|
387
400
|
writeFileSync(join(cmsDir, 'wrangler.json'), JSON.stringify(cmsWranglerConfig, null, 2));
|
|
388
|
-
|
|
389
401
|
writeFileSync(join(cmsDir, '.dev.vars'), `# Cloudflare Edge Cache Purging Secrets\nCLOUDFLARE_API_TOKEN=cfut_YOUR_CUSTOM_PURGE_TOKEN\n\n# Local Development Overrides\nCDN_DOMAIN=\nPUBLIC_FRONTEND_URL=http://localhost:4321\n`);
|
|
390
402
|
} else {
|
|
391
403
|
const templateServerPath = join(__dirname, '../templates/kama-worker/server.js');
|
|
392
|
-
if (existsSync(templateServerPath))
|
|
393
|
-
cpSync(templateServerPath, join(cmsDir, 'server.js'));
|
|
394
|
-
}
|
|
404
|
+
if (existsSync(templateServerPath)) cpSync(templateServerPath, join(cmsDir, 'server.js'));
|
|
395
405
|
|
|
396
406
|
writeFileSync(
|
|
397
407
|
join(cmsDir, 'package.json'),
|
|
@@ -400,20 +410,12 @@ async function createFullWorkspace() {
|
|
|
400
410
|
type: 'module',
|
|
401
411
|
version: '1.0.0',
|
|
402
412
|
scripts: {
|
|
403
|
-
"setup:local": "sqlite3 kama.db < ../node_modules/@brightsideoy/kama/schema.sql
|
|
413
|
+
"setup:local": "sqlite3 kama.db < ../node_modules/@brightsideoy/kama/schema.sql",
|
|
404
414
|
"dev": "tsx server.js",
|
|
405
415
|
"start": "node server.js"
|
|
406
416
|
},
|
|
407
|
-
dependencies: {
|
|
408
|
-
|
|
409
|
-
'@hono/node-server': '^1.13.0',
|
|
410
|
-
'@libsql/client': '^0.14.0',
|
|
411
|
-
'sharp': '^0.33.5',
|
|
412
|
-
'dotenv': '^16.4.5'
|
|
413
|
-
},
|
|
414
|
-
devDependencies: {
|
|
415
|
-
"tsx": "^4.19.0"
|
|
416
|
-
},
|
|
417
|
+
dependencies: { '@brightsideoy/kama': currentKamaVersion, '@hono/node-server': '^1.13.0', '@libsql/client': '^0.14.0', 'sharp': '^0.33.5', 'dotenv': '^16.4.5' },
|
|
418
|
+
devDependencies: { "tsx": "^4.19.0" },
|
|
417
419
|
}, null, 2)
|
|
418
420
|
);
|
|
419
421
|
|
|
@@ -434,7 +436,7 @@ async function createFullWorkspace() {
|
|
|
434
436
|
let stepCount = 1;
|
|
435
437
|
if (!isCurrentDir) nextSteps += `${stepCount++}. cd ${projName}\n`;
|
|
436
438
|
nextSteps += `${stepCount++}. npm install\n`;
|
|
437
|
-
nextSteps += `${stepCount++}. npm run setup ${pc.dim('<- Run this once to init the database!')}\n`;
|
|
439
|
+
nextSteps += `${stepCount++}. npm run setup ${pc.dim('<- Run this once to init the database schema!')}\n`;
|
|
438
440
|
nextSteps += `${stepCount++}. npm run dev\n`;
|
|
439
441
|
|
|
440
442
|
if (isCloudflare) {
|
|
@@ -489,17 +491,11 @@ async function createNewSiteOnly() {
|
|
|
489
491
|
let cmsFullUrl = 'http://localhost:8787';
|
|
490
492
|
|
|
491
493
|
if (isCloudflare) {
|
|
492
|
-
siteDomain = handleCancel(await text({
|
|
493
|
-
message: 'Website Domain (e.g., brand.com):',
|
|
494
|
-
defaultValue: ''
|
|
495
|
-
}));
|
|
494
|
+
siteDomain = handleCancel(await text({ message: 'Website Domain (e.g., brand.com):', defaultValue: '' }));
|
|
496
495
|
if (detectedCmsDomain) {
|
|
497
496
|
cmsFullUrl = detectedCmsDomain.startsWith('http') ? detectedCmsDomain : `https://${detectedCmsDomain.replace(/^https?:\/\//, '')}`;
|
|
498
497
|
} else {
|
|
499
|
-
const cmsDomainInput = handleCancel(await text({
|
|
500
|
-
message: 'CMS API Domain (e.g., admin.brand.com):',
|
|
501
|
-
defaultValue: ''
|
|
502
|
-
}));
|
|
498
|
+
const cmsDomainInput = handleCancel(await text({ message: 'CMS API Domain (e.g., admin.brand.com):', defaultValue: '' }));
|
|
503
499
|
cmsFullUrl = `https://${cmsDomainInput.replace(/^https?:\/\//, '')}`;
|
|
504
500
|
}
|
|
505
501
|
}
|
|
@@ -509,7 +505,7 @@ async function createNewSiteOnly() {
|
|
|
509
505
|
await generateAstroSite(rootDir, siteFolder, siteDomain, cmsFullUrl, targetWorkerName, isCloudflare);
|
|
510
506
|
s.stop(`Site created in sites/${siteFolder}!`);
|
|
511
507
|
|
|
512
|
-
note(`1. npm install\n2. npm run
|
|
508
|
+
note(`1. npm install\n2. npm run dev`, 'Next steps');
|
|
513
509
|
outro('Site added successfully! 🚀');
|
|
514
510
|
}
|
|
515
511
|
|
|
@@ -541,27 +537,27 @@ async function promoteLocalToCloudflare() {
|
|
|
541
537
|
const rootPkgPath = join(rootDir, 'package.json');
|
|
542
538
|
|
|
543
539
|
if (!existsSync(workerDir) || !existsSync(rootPkgPath)) {
|
|
544
|
-
cancel('Error: Could not find kama-worker folder or package.json.
|
|
540
|
+
cancel('Error: Could not find kama-worker folder or package.json.');
|
|
545
541
|
process.exit(1);
|
|
546
542
|
}
|
|
547
543
|
|
|
548
544
|
const s = spinner();
|
|
549
545
|
s.start('Checking Cloudflare authentication...');
|
|
550
546
|
|
|
551
|
-
|
|
552
|
-
|
|
547
|
+
const whoami = runWrangler('whoami');
|
|
548
|
+
if (whoami && (whoami.includes('Getting User Settings') || whoami.includes('You are logged in'))) {
|
|
553
549
|
s.stop('Logged in to Cloudflare.');
|
|
554
|
-
}
|
|
550
|
+
} else {
|
|
555
551
|
s.stop('Not logged in to Cloudflare.', true);
|
|
556
552
|
console.log(pc.dim('Launching browser for Cloudflare login...'));
|
|
557
|
-
|
|
558
|
-
|
|
553
|
+
const login = runWrangler('login', { stdio: 'inherit' });
|
|
554
|
+
if (login === null) {
|
|
555
|
+
cancel('Cloudflare login failed.');
|
|
556
|
+
process.exit(1);
|
|
557
|
+
}
|
|
559
558
|
}
|
|
560
559
|
|
|
561
|
-
const cmsDomain = handleCancel(await text({
|
|
562
|
-
message: 'CMS Admin Domain (e.g., admin.yourdomain.com):',
|
|
563
|
-
defaultValue: ''
|
|
564
|
-
}));
|
|
560
|
+
const cmsDomain = handleCancel(await text({ message: 'CMS Admin Domain (e.g., admin.yourdomain.com):', defaultValue: '' }));
|
|
565
561
|
|
|
566
562
|
const sitesFolderDir = join(rootDir, 'sites');
|
|
567
563
|
let siteDomain = '';
|
|
@@ -570,10 +566,7 @@ async function promoteLocalToCloudflare() {
|
|
|
570
566
|
const sites = readdirSync(sitesFolderDir);
|
|
571
567
|
if (sites.length > 0) {
|
|
572
568
|
siteDir = join(sitesFolderDir, sites[0]);
|
|
573
|
-
siteDomain = handleCancel(await text({
|
|
574
|
-
message: `Frontend Website Domain for ${sites[0]} (e.g., yourdomain.com):`,
|
|
575
|
-
defaultValue: ''
|
|
576
|
-
}));
|
|
569
|
+
siteDomain = handleCancel(await text({ message: `Frontend Website Domain for ${sites[0]}:`, defaultValue: '' }));
|
|
577
570
|
}
|
|
578
571
|
}
|
|
579
572
|
|
|
@@ -583,41 +576,41 @@ async function promoteLocalToCloudflare() {
|
|
|
583
576
|
let dbName = `${projName}-db`.replace(/[^a-zA-Z0-9_-]/g, '_');
|
|
584
577
|
let d1DatabaseId = '00000000-0000-0000-0000-000000000000';
|
|
585
578
|
|
|
586
|
-
|
|
587
|
-
|
|
579
|
+
const d1Output = runWrangler(`d1 create ${dbName}`);
|
|
580
|
+
if (d1Output) {
|
|
588
581
|
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}/);
|
|
589
582
|
if (match) d1DatabaseId = match[0];
|
|
590
|
-
}
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
const workerName = `${projName}-worker`.toLowerCase().replace(/[^a-z0-9_-]/g, '-');
|
|
586
|
+
const bucketName = `${projName}-media-prod`.toLowerCase().replace(/[^a-z0-9_-]/g, '-');
|
|
587
|
+
|
|
588
|
+
const backendCacheId = getOrCreateKV(`CACHE_KV_${workerName.toUpperCase().replace(/-/g, '_')}`);
|
|
591
589
|
|
|
592
590
|
const rootPkg = JSON.parse(readFileSync(rootPkgPath, 'utf-8'));
|
|
593
591
|
rootPkg.devDependencies = rootPkg.devDependencies || {};
|
|
594
592
|
rootPkg.devDependencies['wrangler'] = WRANGLER_LATEST;
|
|
595
593
|
writeFileSync(rootPkgPath, JSON.stringify(rootPkg, null, 2));
|
|
596
594
|
|
|
597
|
-
const workerName = `${projName}-worker`.toLowerCase().replace(/[^a-z0-9_-]/g, '-');
|
|
598
|
-
const bucketName = `${projName}-media-prod`.toLowerCase().replace(/[^a-z0-9_-]/g, '-');
|
|
599
595
|
const workerWranglerPath = join(workerDir, 'wrangler.json');
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
:
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
images: { binding: 'IMAGES' },
|
|
611
|
-
vars: { CLOUDFLARE_ZONE_ID: "REPLACE_WITH_YOUR_32_CHAR_ZONE_ID", KAMA_RUNTIME: 'cloudflare' }
|
|
612
|
-
};
|
|
596
|
+
let currentConfig = existsSync(workerWranglerPath) ? JSON.parse(readFileSync(workerWranglerPath, 'utf-8')) : {
|
|
597
|
+
$schema: '../node_modules/wrangler/config-schema.json',
|
|
598
|
+
name: workerName,
|
|
599
|
+
main: 'index.js',
|
|
600
|
+
compatibility_date: '2024-09-23',
|
|
601
|
+
compatibility_flags: ['nodejs_compat'],
|
|
602
|
+
assets: { directory: '../node_modules/@brightsideoy/kama/dist', binding: 'ASSETS' },
|
|
603
|
+
images: { binding: 'IMAGES' },
|
|
604
|
+
vars: { CLOUDFLARE_ZONE_ID: "REPLACE_WITH_YOUR_32_CHAR_ZONE_ID", KAMA_RUNTIME: 'cloudflare' }
|
|
605
|
+
};
|
|
613
606
|
|
|
614
607
|
currentConfig.dev = currentConfig.dev || { host: 'localhost', port: 8787 };
|
|
615
|
-
currentConfig.cache = { enabled: true };
|
|
616
608
|
currentConfig.vars.CDN_DOMAIN = cmsDomain;
|
|
617
609
|
if (siteDomain) currentConfig.vars.PUBLIC_FRONTEND_URL = `https://${siteDomain}`;
|
|
618
610
|
currentConfig.routes = [{ pattern: cmsDomain, custom_domain: true }];
|
|
619
611
|
currentConfig.d1_databases = [{ binding: 'DB', database_name: dbName, database_id: d1DatabaseId }];
|
|
620
612
|
currentConfig.r2_buckets = [{ binding: 'MEDIA_BUCKET', bucket_name: bucketName }];
|
|
613
|
+
currentConfig.kv_namespaces = [{ binding: 'CACHE_KV', id: backendCacheId }];
|
|
621
614
|
|
|
622
615
|
writeFileSync(workerWranglerPath, JSON.stringify(currentConfig, null, 2));
|
|
623
616
|
|
|
@@ -625,37 +618,22 @@ async function promoteLocalToCloudflare() {
|
|
|
625
618
|
writeFileSync(join(workerDir, '.dev.vars'), `CLOUDFLARE_API_TOKEN=cfut_YOUR_CUSTOM_PURGE_TOKEN\nCDN_DOMAIN=\nPUBLIC_FRONTEND_URL=http://localhost:4321\n`);
|
|
626
619
|
}
|
|
627
620
|
|
|
628
|
-
const workerIndexPath = join(workerDir, 'index.js');
|
|
629
|
-
if (!existsSync(workerIndexPath)) {
|
|
630
|
-
const templateIndexPath = join(__dirname, '../templates/kama-worker/index.js');
|
|
631
|
-
if (existsSync(templateIndexPath)) {
|
|
632
|
-
cpSync(templateIndexPath, workerIndexPath);
|
|
633
|
-
}
|
|
634
|
-
}
|
|
635
|
-
|
|
636
621
|
const workerPkgPath = join(workerDir, 'package.json');
|
|
637
622
|
if (existsSync(workerPkgPath)) {
|
|
638
623
|
const workerPkg = JSON.parse(readFileSync(workerPkgPath, 'utf-8'));
|
|
639
624
|
workerPkg.scripts.dev = "wrangler dev --port 8787 --inspector-port 9239";
|
|
640
625
|
workerPkg.scripts.deploy = "npm run setup:remote && wrangler deploy";
|
|
641
|
-
workerPkg.scripts["setup:local"] = `wrangler d1 execute ${dbName} --local --file=../node_modules/@brightsideoy/kama/schema.sql
|
|
642
|
-
workerPkg.scripts["setup:remote"] = `wrangler d1 execute ${dbName} --remote --file=../node_modules/@brightsideoy/kama/schema.sql
|
|
626
|
+
workerPkg.scripts["setup:local"] = `wrangler d1 execute ${dbName} --local --file=../node_modules/@brightsideoy/kama/schema.sql`;
|
|
627
|
+
workerPkg.scripts["setup:remote"] = `wrangler d1 execute ${dbName} --remote --file=../node_modules/@brightsideoy/kama/schema.sql`;
|
|
643
628
|
workerPkg.devDependencies = workerPkg.devDependencies || {};
|
|
644
629
|
workerPkg.devDependencies.wrangler = WRANGLER_LATEST;
|
|
645
630
|
writeFileSync(workerPkgPath, JSON.stringify(workerPkg, null, 2));
|
|
646
631
|
}
|
|
647
632
|
|
|
648
633
|
if (siteDir && siteDomain) {
|
|
649
|
-
let sessionId = "REPLACE_WITH_YOUR_SESSION_KV_ID";
|
|
650
|
-
let htmlCacheId = "REPLACE_WITH_YOUR_HTML_CACHE_KV_ID";
|
|
651
634
|
const prefix = basename(siteDir).replace(/[^a-zA-Z0-9]/g, '_').toUpperCase();
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
const sessionOut = execSync(`npx wrangler kv namespace create "SESSION_${prefix}"`, { encoding: 'utf-8', stdio: ['ignore', 'pipe', 'pipe'] });
|
|
655
|
-
if (sessionOut.match(/"id":\s*"([a-f0-9]{32})"/)) sessionId = sessionOut.match(/"id":\s*"([a-f0-9]{32})"/)[1];
|
|
656
|
-
const cacheOut = execSync(`npx wrangler kv namespace create "HTML_CACHE_${prefix}"`, { encoding: 'utf-8', stdio: ['ignore', 'pipe', 'pipe'] });
|
|
657
|
-
if (cacheOut.match(/"id":\s*"([a-f0-9]{32})"/)) htmlCacheId = cacheOut.match(/"id":\s*"([a-f0-9]{32})"/)[1];
|
|
658
|
-
} catch (err) { }
|
|
635
|
+
const sessionId = getOrCreateKV(`SESSION_${prefix}`);
|
|
636
|
+
const htmlCacheId = getOrCreateKV(`HTML_CACHE_${prefix}`);
|
|
659
637
|
|
|
660
638
|
const siteWranglerPath = join(siteDir, 'wrangler.json');
|
|
661
639
|
const siteConfig = {
|
|
@@ -678,25 +656,14 @@ async function promoteLocalToCloudflare() {
|
|
|
678
656
|
const sitePkg = JSON.parse(readFileSync(sitePkgPath, 'utf-8'));
|
|
679
657
|
sitePkg.dependencies = sitePkg.dependencies || {};
|
|
680
658
|
sitePkg.dependencies['astro'] = ASTRO_LATEST;
|
|
681
|
-
|
|
682
659
|
if (sitePkg.dependencies['@astrojs/node']) delete sitePkg.dependencies['@astrojs/node'];
|
|
683
660
|
sitePkg.dependencies['@astrojs/cloudflare'] = ASTRO_CF_LATEST;
|
|
684
|
-
|
|
685
661
|
sitePkg.devDependencies = sitePkg.devDependencies || {};
|
|
686
662
|
sitePkg.devDependencies['wrangler'] = WRANGLER_LATEST;
|
|
687
|
-
|
|
688
663
|
writeFileSync(sitePkgPath, JSON.stringify(sitePkg, null, 2));
|
|
689
664
|
}
|
|
690
665
|
|
|
691
666
|
convertAstroConfigToCloudflare(siteDir);
|
|
692
|
-
|
|
693
|
-
const tsConfigPath = join(siteDir, 'tsconfig.json');
|
|
694
|
-
if (existsSync(tsConfigPath)) {
|
|
695
|
-
const tsConfig = JSON.parse(readFileSync(tsConfigPath, 'utf-8'));
|
|
696
|
-
tsConfig.compilerOptions = tsConfig.compilerOptions || {};
|
|
697
|
-
tsConfig.compilerOptions.types = ["@cloudflare/workers-types"];
|
|
698
|
-
writeFileSync(tsConfigPath, JSON.stringify(tsConfig, null, 2));
|
|
699
|
-
}
|
|
700
667
|
}
|
|
701
668
|
|
|
702
669
|
s.stop('Workspace successfully upgraded to Cloudflare Edge!');
|
|
@@ -710,16 +677,11 @@ async function generateAstroSite(rootDir, siteFolder, siteDomain, cmsFullUrl, wo
|
|
|
710
677
|
const siteDir = join(rootDir, 'sites', siteFolder);
|
|
711
678
|
const templateDir = join(__dirname, '../templates/astro-starter');
|
|
712
679
|
|
|
713
|
-
if (!existsSync(templateDir))
|
|
714
|
-
return;
|
|
715
|
-
}
|
|
680
|
+
if (!existsSync(templateDir)) return;
|
|
716
681
|
|
|
717
682
|
cpSync(templateDir, siteDir, { recursive: true });
|
|
718
683
|
|
|
719
|
-
const tsConfig = {
|
|
720
|
-
extends: "astro/tsconfigs/strict",
|
|
721
|
-
compilerOptions: { baseUrl: ".", paths: { "@/*": ["src/*"] } }
|
|
722
|
-
};
|
|
684
|
+
const tsConfig = { extends: "astro/tsconfigs/strict", compilerOptions: { baseUrl: ".", paths: { "@/*": ["src/*"] } } };
|
|
723
685
|
if (isCloudflare) tsConfig.compilerOptions.types = ["@cloudflare/workers-types"];
|
|
724
686
|
writeFileSync(join(siteDir, 'tsconfig.json'), JSON.stringify(tsConfig, null, 2));
|
|
725
687
|
|
|
@@ -728,7 +690,6 @@ async function generateAstroSite(rootDir, siteFolder, siteDomain, cmsFullUrl, wo
|
|
|
728
690
|
const rawContent = readFileSync(templatePkgPath, 'utf-8')
|
|
729
691
|
.replace(/\{\{SITE_NAME\}\}/g, siteFolder)
|
|
730
692
|
.replace(/\{\{KAMA_VERSION\}\}/g, currentKamaVersion);
|
|
731
|
-
|
|
732
693
|
const sitePkg = JSON.parse(rawContent);
|
|
733
694
|
|
|
734
695
|
sitePkg.dependencies = sitePkg.dependencies || {};
|
|
@@ -738,14 +699,12 @@ async function generateAstroSite(rootDir, siteFolder, siteDomain, cmsFullUrl, wo
|
|
|
738
699
|
if (sitePkg.dependencies['@astrojs/cloudflare']) delete sitePkg.dependencies['@astrojs/cloudflare'];
|
|
739
700
|
if (sitePkg.dependencies['wrangler']) delete sitePkg.dependencies['wrangler'];
|
|
740
701
|
if (sitePkg.devDependencies && sitePkg.devDependencies['wrangler']) delete sitePkg.devDependencies['wrangler'];
|
|
741
|
-
|
|
742
702
|
sitePkg.dependencies['@astrojs/node'] = ASTRO_NODE_LATEST;
|
|
743
703
|
} else {
|
|
744
704
|
sitePkg.dependencies['@astrojs/cloudflare'] = ASTRO_CF_LATEST;
|
|
745
705
|
if (sitePkg.dependencies['wrangler']) delete sitePkg.dependencies['wrangler'];
|
|
746
706
|
sitePkg.devDependencies = sitePkg.devDependencies || {};
|
|
747
707
|
sitePkg.devDependencies['wrangler'] = WRANGLER_LATEST;
|
|
748
|
-
|
|
749
708
|
convertAstroConfigToCloudflare(siteDir);
|
|
750
709
|
}
|
|
751
710
|
|
|
@@ -754,23 +713,14 @@ async function generateAstroSite(rootDir, siteFolder, siteDomain, cmsFullUrl, wo
|
|
|
754
713
|
}
|
|
755
714
|
|
|
756
715
|
const siteLabel = siteFolder.split(/[-_]/).map(word => word.charAt(0).toUpperCase() + word.slice(1)).join(' ');
|
|
757
|
-
const safeSiteLabel = siteLabel.replace(/'/g, "''");
|
|
758
716
|
const channelKey = siteFolder.replace(/[^a-z0-9_-]/gi, '-').toLowerCase();
|
|
759
|
-
const homeSlug = `welcome-to-${channelKey}`;
|
|
760
717
|
const treeKey = 'main-tree';
|
|
761
718
|
const safeWorkerName = `${siteFolder.toLowerCase().replace(/[^a-z0-9-]/g, '-')}-site`;
|
|
762
719
|
|
|
763
720
|
if (isCloudflare) {
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
try {
|
|
768
|
-
const prefix = siteFolder.replace(/[^a-zA-Z0-9]/g, '_').toUpperCase();
|
|
769
|
-
const sessionOut = execSync(`npx wrangler kv namespace create "SESSION_${prefix}"`, { encoding: 'utf-8', stdio: ['ignore', 'pipe', 'pipe'] });
|
|
770
|
-
if (sessionOut.match(/"id":\s*"([a-f0-9]{32})"/)) sessionId = sessionOut.match(/"id":\s*"([a-f0-9]{32})"/)[1];
|
|
771
|
-
const cacheOut = execSync(`npx wrangler kv namespace create "HTML_CACHE_${prefix}"`, { encoding: 'utf-8', stdio: ['ignore', 'pipe', 'pipe'] });
|
|
772
|
-
if (cacheOut.match(/"id":\s*"([a-f0-9]{32})"/)) htmlCacheId = cacheOut.match(/"id":\s*"([a-f0-9]{32})"/)[1];
|
|
773
|
-
} catch (err) { }
|
|
721
|
+
const prefix = siteFolder.replace(/[^a-zA-Z0-9]/g, '_').toUpperCase();
|
|
722
|
+
const sessionId = getOrCreateKV(`SESSION_${prefix}`);
|
|
723
|
+
const htmlCacheId = getOrCreateKV(`HTML_CACHE_${prefix}`);
|
|
774
724
|
|
|
775
725
|
const siteConfig = {
|
|
776
726
|
$schema: "node_modules/wrangler/config-schema.json",
|
|
@@ -789,78 +739,6 @@ async function generateAstroSite(rootDir, siteFolder, siteDomain, cmsFullUrl, wo
|
|
|
789
739
|
writeFileSync(join(siteDir, 'wrangler.json'), JSON.stringify(siteConfig, null, 2));
|
|
790
740
|
}
|
|
791
741
|
|
|
792
|
-
const siteUrl = (siteDomain === 'localhost:4321' || !isCloudflare) ? `http://${siteDomain}` : `https://${siteDomain}`;
|
|
793
|
-
|
|
794
|
-
const seedSql = `
|
|
795
|
-
-- Seed data for site: ${safeSiteLabel}
|
|
796
|
-
|
|
797
|
-
-- 1. Create content node
|
|
798
|
-
INSERT INTO content_nodes (contentType, title, slug, language, status, hasUnpublishedChanges, disabledRegionsJson, dataJson, draftDataJson, publishedDataJson, publishedAt)
|
|
799
|
-
SELECT 'page', 'Welcome to ${safeSiteLabel}', '${homeSlug}', '', 'published', 0, '{}',
|
|
800
|
-
'{"titleSuffix":"– ${safeSiteLabel}","layoutId":"single-column","subpageLayoutId":"two-column","logoText":"${safeSiteLabel}","schemaType":"WebPage"}',
|
|
801
|
-
'{"titleSuffix":"– ${safeSiteLabel}","layoutId":"single-column","subpageLayoutId":"two-column","logoText":"${safeSiteLabel}","schemaType":"WebPage"}',
|
|
802
|
-
'{"titleSuffix":"– ${safeSiteLabel}","layoutId":"single-column","subpageLayoutId":"two-column","logoText":"${safeSiteLabel}","schemaType":"WebPage"}',
|
|
803
|
-
CURRENT_TIMESTAMP
|
|
804
|
-
WHERE NOT EXISTS (SELECT 1 FROM content_nodes WHERE slug = '${homeSlug}' AND title = 'Welcome to ${safeSiteLabel}');
|
|
805
|
-
|
|
806
|
-
-- 2. Create channel
|
|
807
|
-
INSERT OR IGNORE INTO channels (key, label, channelType, baseUrl, defaultLanguage, isHidden, dataJson)
|
|
808
|
-
VALUES ('${channelKey}', '${safeSiteLabel}', 'website', '${siteUrl}', '', 0, '{}');
|
|
809
|
-
|
|
810
|
-
-- 3. Link channelRoot in channel JSON
|
|
811
|
-
UPDATE channels
|
|
812
|
-
SET dataJson = json_patch(
|
|
813
|
-
COALESCE(NULLIF(dataJson, ''), '{}'),
|
|
814
|
-
json_object(
|
|
815
|
-
'channelRoot', json_object(
|
|
816
|
-
'href', '#node:' || (SELECT id FROM content_nodes WHERE slug = '${homeSlug}' AND title = 'Welcome to ${safeSiteLabel}' ORDER BY id DESC LIMIT 1),
|
|
817
|
-
'kind', 'node',
|
|
818
|
-
'target', '_self',
|
|
819
|
-
'label', 'Welcome to ${safeSiteLabel}',
|
|
820
|
-
'nodeId', (SELECT id FROM content_nodes WHERE slug = '${homeSlug}' AND title = 'Welcome to ${safeSiteLabel}' ORDER BY id DESC LIMIT 1)
|
|
821
|
-
)
|
|
822
|
-
)
|
|
823
|
-
)
|
|
824
|
-
WHERE key = '${channelKey}';
|
|
825
|
-
|
|
826
|
-
-- 4. Create Trees & Relations
|
|
827
|
-
INSERT OR IGNORE INTO trees (key, label, treeType, channelId, isHidden, dataJson)
|
|
828
|
-
VALUES ('${treeKey}', 'Main Tree', 'navigation', (SELECT id FROM channels WHERE key = '${channelKey}'), 0, '{}');
|
|
829
|
-
|
|
830
|
-
INSERT OR IGNORE INTO channel_trees (channelId, treeId, key)
|
|
831
|
-
VALUES ((SELECT id FROM channels WHERE key = '${channelKey}'), (SELECT id FROM trees WHERE key = '${treeKey}'), 'main');
|
|
832
|
-
|
|
833
|
-
INSERT OR IGNORE INTO node_channels (nodeId, channelId)
|
|
834
|
-
VALUES ((SELECT id FROM content_nodes WHERE slug = '${homeSlug}' ORDER BY id DESC LIMIT 1), (SELECT id FROM channels WHERE key = '${channelKey}'));
|
|
835
|
-
|
|
836
|
-
INSERT OR IGNORE INTO tree_nodes (treeId, contentId, parentId, sortOrder)
|
|
837
|
-
VALUES ((SELECT id FROM trees WHERE key = '${treeKey}'), (SELECT id FROM content_nodes WHERE slug = '${homeSlug}' ORDER BY id DESC LIMIT 1), NULL, 0);
|
|
838
|
-
|
|
839
|
-
-- 5. Node Routing (TWO records: Canonical '/' and Redirect '/slug' -> '/')
|
|
840
|
-
INSERT OR IGNORE INTO node_routes (path, channelId, nodeId, treeId, isCanonical, redirectUrl)
|
|
841
|
-
VALUES (
|
|
842
|
-
'/',
|
|
843
|
-
(SELECT id FROM channels WHERE key = '${channelKey}'),
|
|
844
|
-
(SELECT id FROM content_nodes WHERE slug = '${homeSlug}' ORDER BY id DESC LIMIT 1),
|
|
845
|
-
(SELECT id FROM trees WHERE key = '${treeKey}'),
|
|
846
|
-
1,
|
|
847
|
-
NULL
|
|
848
|
-
);
|
|
849
|
-
|
|
850
|
-
INSERT OR IGNORE INTO node_routes (path, channelId, nodeId, treeId, isCanonical, redirectUrl)
|
|
851
|
-
VALUES (
|
|
852
|
-
'/${homeSlug}',
|
|
853
|
-
(SELECT id FROM channels WHERE key = '${channelKey}'),
|
|
854
|
-
(SELECT id FROM content_nodes WHERE slug = '${homeSlug}' ORDER BY id DESC LIMIT 1),
|
|
855
|
-
NULL,
|
|
856
|
-
0,
|
|
857
|
-
'/'
|
|
858
|
-
);
|
|
859
|
-
`;
|
|
860
|
-
|
|
861
|
-
const workerDir = join(rootDir, 'kama-worker');
|
|
862
|
-
if (existsSync(workerDir)) appendFileSync(join(workerDir, 'seed.sql'), seedSql);
|
|
863
|
-
|
|
864
742
|
writeFileSync(join(siteDir, '.env'), `# Local Development Overrides\nPUBLIC_CMS_URL="http://127.0.0.1:8787"\nPUBLIC_API_URL="http://127.0.0.1:8787"\nPUBLIC_CHANNEL_ID="${channelKey}"\nPUBLIC_TREE_ID="${treeKey}"\nPUBLIC_SITE_NAME="${siteLabel.replace(/"/g, '\\"')}"\n`);
|
|
865
743
|
}
|
|
866
744
|
|