@brightsideoy/kama 0.1.0-alpha.100 → 0.1.0-alpha.107
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 +174 -0
- package/bin/cli.js +321 -118
- package/{defaults → content}/definitions/node-layouts/two-column.yml +1 -1
- package/{defaults → content}/definitions/nodes/person.yaml +2 -0
- package/dist/assets/index-D12geIgG.js +1394 -0
- package/dist/index.html +1 -1
- package/dist/index.js +1420 -1179
- package/documentation/SCHEMAS.md +182 -0
- package/package.json +4 -3
- package/scripts/bundle-definitions.js +44 -4
- package/dist/assets/index-u699KJW2.js +0 -1392
- /package/{defaults → content}/definitions/block-layouts/three-column.yaml +0 -0
- /package/{defaults → content}/definitions/block-layouts/two-column.yaml +0 -0
- /package/{defaults → content}/definitions/blocks/button.yaml +0 -0
- /package/{defaults → content}/definitions/blocks/header.yaml +0 -0
- /package/{defaults → content}/definitions/blocks/header_image.yaml +0 -0
- /package/{defaults → content}/definitions/blocks/hero.yaml +0 -0
- /package/{defaults → content}/definitions/blocks/image_card.yaml +0 -0
- /package/{defaults → content}/definitions/blocks/single_image.yaml +0 -0
- /package/{defaults → content}/definitions/blocks/text.yaml +0 -0
- /package/{defaults → content}/definitions/channels/ecommerce.yaml +0 -0
- /package/{defaults → content}/definitions/channels/website.yaml +0 -0
- /package/{defaults → content}/definitions/field-sets/access.yaml +0 -0
- /package/{defaults → content}/definitions/field-sets/channel-base.yaml +0 -0
- /package/{defaults → content}/definitions/field-sets/comments.yaml +0 -0
- /package/{defaults → content}/definitions/field-sets/content-block.yaml +0 -0
- /package/{defaults → content}/definitions/field-sets/page-base.yaml +0 -0
- /package/{defaults → content}/definitions/field-sets/page-meta.yaml +0 -0
- /package/{defaults → content}/definitions/field-sets/page-social.yaml +0 -0
- /package/{defaults → content}/definitions/field-sets/tree-base.yaml +0 -0
- /package/{defaults → content}/definitions/field-sets/visibility.yaml +0 -0
- /package/{defaults → content}/definitions/node-layouts/landing-page.yml +0 -0
- /package/{defaults → content}/definitions/node-layouts/single-column.yml +0 -0
- /package/{defaults → content}/definitions/node-layouts/three-column.yml +0 -0
- /package/{defaults → content}/definitions/nodes/address.yaml +0 -0
- /package/{defaults → content}/definitions/nodes/article.yaml +0 -0
- /package/{defaults → content}/definitions/nodes/event.yaml +0 -0
- /package/{defaults → content}/definitions/nodes/external-link.yaml +0 -0
- /package/{defaults → content}/definitions/nodes/page.yaml +0 -0
- /package/{defaults → content}/definitions/nodes/product.yaml +0 -0
- /package/{defaults → content}/definitions/trees/navigation.yaml +0 -0
- /package/{defaults → content}/definitions/trees/social-links.yaml +0 -0
package/bin/cli.js
CHANGED
|
@@ -32,8 +32,25 @@ async function main() {
|
|
|
32
32
|
*/
|
|
33
33
|
async function createFullWorkspace() {
|
|
34
34
|
const projName = (await rl.question('Project folder name [kama-workspace]: ')) || 'kama-workspace';
|
|
35
|
-
|
|
36
|
-
|
|
35
|
+
|
|
36
|
+
console.log('\n🌍 Where do you plan to deploy KAMA?');
|
|
37
|
+
console.log(' 1) Local Development Only (SQLite / Testing)');
|
|
38
|
+
console.log(' 2) Cloudflare Edge (Workers / D1 / R2)');
|
|
39
|
+
const envChoice = await rl.question('\nChoice [1/2]: ');
|
|
40
|
+
const isCloudflare = envChoice.trim() === '2';
|
|
41
|
+
|
|
42
|
+
let cmsDomain = 'localhost:8787';
|
|
43
|
+
let siteDomain = 'localhost:4321';
|
|
44
|
+
|
|
45
|
+
// Only ask for domains if deploying to Cloudflare Edge
|
|
46
|
+
if (isCloudflare) {
|
|
47
|
+
cmsDomain = (await rl.question('\nCMS Admin Domain (e.g., admin.t3cloud.eu): ')) || 'admin.t3cloud.eu';
|
|
48
|
+
siteDomain = (await rl.question('First Website Domain (e.g., kama.t3cloud.eu): ')) || 'kama.t3cloud.eu';
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Standardize scheme for localhost vs custom edge domains
|
|
52
|
+
const cmsProtocol = isCloudflare ? 'https://' : 'http://';
|
|
53
|
+
const cmsFullUrl = `${cmsProtocol}${cmsDomain.replace(/^https?:\/\//, '')}`;
|
|
37
54
|
|
|
38
55
|
const rootDir = join(process.cwd(), projName);
|
|
39
56
|
|
|
@@ -45,56 +62,81 @@ async function createFullWorkspace() {
|
|
|
45
62
|
console.log(`\n📁 Creating workspace folder at ./${projName}...`);
|
|
46
63
|
mkdirSync(rootDir, { recursive: true });
|
|
47
64
|
|
|
48
|
-
// 🎯 Scaffold
|
|
49
|
-
|
|
50
|
-
|
|
65
|
+
// 🎯 Scaffold full schema directory structure
|
|
66
|
+
const schemaCategories = [
|
|
67
|
+
'block-layouts',
|
|
68
|
+
'blocks',
|
|
69
|
+
'channels',
|
|
70
|
+
'field-sets',
|
|
71
|
+
'node-layouts',
|
|
72
|
+
'nodes',
|
|
73
|
+
'trees'
|
|
74
|
+
];
|
|
75
|
+
|
|
76
|
+
for (const category of schemaCategories) {
|
|
77
|
+
mkdirSync(join(rootDir, 'content', 'definitions', category), { recursive: true });
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// 🎯 Populate starter example YAML files
|
|
81
|
+
scaffoldSampleSchemas(rootDir);
|
|
51
82
|
|
|
52
83
|
// --- AUTO D1 CREATION MAGIC ---
|
|
53
|
-
|
|
84
|
+
// Use a zeroed UUID for local testing so Wrangler's schema validator doesn't crash
|
|
85
|
+
let d1DatabaseId = '00000000-0000-0000-0000-000000000000';
|
|
54
86
|
let isAuthenticated = false;
|
|
55
87
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
execSync('npx wrangler whoami', { stdio: 'pipe' });
|
|
59
|
-
isAuthenticated = true;
|
|
60
|
-
console.log(`✅ Logged in to Cloudflare.`);
|
|
61
|
-
} catch (error) {
|
|
62
|
-
console.log(`⚠️ You are not logged in to Cloudflare.`);
|
|
63
|
-
console.log(`🌐 Launching browser for Cloudflare login...`);
|
|
88
|
+
if (isCloudflare) {
|
|
89
|
+
console.log(`\n🔑 Checking Cloudflare authentication...`);
|
|
64
90
|
try {
|
|
65
|
-
execSync('npx wrangler
|
|
91
|
+
execSync('npx wrangler whoami', { stdio: 'pipe' });
|
|
66
92
|
isAuthenticated = true;
|
|
67
|
-
console.log(`✅
|
|
68
|
-
} catch (
|
|
69
|
-
console.log(
|
|
93
|
+
console.log(`✅ Logged in to Cloudflare.`);
|
|
94
|
+
} catch (error) {
|
|
95
|
+
console.log(`⚠️ You are not logged in to Cloudflare.`);
|
|
96
|
+
console.log(`🌐 Launching browser for Cloudflare login...`);
|
|
97
|
+
try {
|
|
98
|
+
execSync('npx wrangler login', { stdio: 'inherit' });
|
|
99
|
+
isAuthenticated = true;
|
|
100
|
+
console.log(`✅ Successfully logged in!`);
|
|
101
|
+
} catch (loginError) {
|
|
102
|
+
console.log(`❌ Login failed or was cancelled.`);
|
|
103
|
+
}
|
|
70
104
|
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
if (isAuthenticated) {
|
|
74
|
-
try {
|
|
75
|
-
console.log(`\n🗄️ Checking existing Cloudflare D1 databases...`);
|
|
76
|
-
const listOutput = execSync(`npx wrangler d1 list --json`, { encoding: 'utf-8', stdio: 'pipe' });
|
|
77
105
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
106
|
+
if (isAuthenticated) {
|
|
107
|
+
try {
|
|
108
|
+
console.log(`\n🗄️ Checking existing Cloudflare D1 databases...`);
|
|
109
|
+
const listOutput = execSync(`npx wrangler d1 list --json`, { encoding: 'utf-8', stdio: 'pipe' });
|
|
81
110
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
const existingDb = databases.find(db => db.name === dbName);
|
|
111
|
+
const jsonStart = listOutput.indexOf('[');
|
|
112
|
+
const jsonEnd = listOutput.lastIndexOf(']') + 1;
|
|
113
|
+
let databases = [];
|
|
87
114
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
115
|
+
if (jsonStart !== -1 && jsonEnd !== -1) {
|
|
116
|
+
databases = JSON.parse(listOutput.substring(jsonStart, jsonEnd));
|
|
117
|
+
}
|
|
91
118
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
119
|
+
const existingDb = databases.find(db => db.name === dbName);
|
|
120
|
+
|
|
121
|
+
if (existingDb) {
|
|
122
|
+
console.log(`⚠️ Database '${dbName}' already exists on your account.`);
|
|
123
|
+
const useExisting = await rl.question(`Do you want to link this existing database? (y/n) [y]: `);
|
|
124
|
+
|
|
125
|
+
if (useExisting.toLowerCase() !== 'n') {
|
|
126
|
+
d1DatabaseId = existingDb.uuid;
|
|
127
|
+
console.log(`✅ Linked existing database ID: ${d1DatabaseId}`);
|
|
128
|
+
} else {
|
|
129
|
+
dbName = (await rl.question(`Enter a new database name: `)).trim();
|
|
130
|
+
console.log(`\n🗄️ Creating new database '${dbName}'...`);
|
|
131
|
+
const d1Output = execSync(`npx wrangler d1 create ${dbName}`, { encoding: 'utf-8', stdio: 'pipe' });
|
|
132
|
+
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}/);
|
|
133
|
+
if (match) {
|
|
134
|
+
d1DatabaseId = match[0];
|
|
135
|
+
console.log(`✅ Success! Database ID bound: ${d1DatabaseId}`);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
95
138
|
} else {
|
|
96
|
-
|
|
97
|
-
console.log(`\n🗄️ Creating new database '${dbName}'...`);
|
|
139
|
+
console.log(`\n🗄️ Attempting to auto-create Cloudflare D1 Database '${dbName}'...`);
|
|
98
140
|
const d1Output = execSync(`npx wrangler d1 create ${dbName}`, { encoding: 'utf-8', stdio: 'pipe' });
|
|
99
141
|
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}/);
|
|
100
142
|
if (match) {
|
|
@@ -102,20 +144,14 @@ async function createFullWorkspace() {
|
|
|
102
144
|
console.log(`✅ Success! Database ID bound: ${d1DatabaseId}`);
|
|
103
145
|
}
|
|
104
146
|
}
|
|
105
|
-
}
|
|
106
|
-
console.log(
|
|
107
|
-
const d1Output = execSync(`npx wrangler d1 create ${dbName}`, { encoding: 'utf-8', stdio: 'pipe' });
|
|
108
|
-
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}/);
|
|
109
|
-
if (match) {
|
|
110
|
-
d1DatabaseId = match[0];
|
|
111
|
-
console.log(`✅ Success! Database ID bound: ${d1DatabaseId}`);
|
|
112
|
-
}
|
|
147
|
+
} catch (error) {
|
|
148
|
+
console.log(`⚠️ Database operation failed. We'll leave a placeholder.`);
|
|
113
149
|
}
|
|
114
|
-
}
|
|
115
|
-
console.log(`⚠️
|
|
150
|
+
} else {
|
|
151
|
+
console.log(`⚠️ Skipping database creation. We'll leave a placeholder in wrangler.json.`);
|
|
116
152
|
}
|
|
117
153
|
} else {
|
|
118
|
-
console.log(
|
|
154
|
+
console.log(`\n💻 Local mode selected. Skipping Cloudflare authentication and domain setup...`);
|
|
119
155
|
}
|
|
120
156
|
// ------------------------------
|
|
121
157
|
|
|
@@ -143,9 +179,32 @@ async function createFullWorkspace() {
|
|
|
143
179
|
const cmsDir = join(rootDir, 'cms-worker');
|
|
144
180
|
mkdirSync(cmsDir, { recursive: true });
|
|
145
181
|
|
|
182
|
+
// 🎯 Properly wrap and inject BUNDLED_DEFINITIONS directly into fetch env
|
|
183
|
+
const cmsWorkerIndexContent = `import kamaWorker from '@brightsideoy/kama';
|
|
184
|
+
import * as bundledModule from '../node_modules/@brightsideoy/kama/dist/bundled-definitions.js';
|
|
185
|
+
|
|
186
|
+
// Resolve BUNDLED_DEFINITIONS across all module resolution formats
|
|
187
|
+
const BUNDLED_DEFINITIONS =
|
|
188
|
+
bundledModule.BUNDLED_DEFINITIONS ||
|
|
189
|
+
bundledModule.default?.BUNDLED_DEFINITIONS ||
|
|
190
|
+
bundledModule.default ||
|
|
191
|
+
bundledModule;
|
|
192
|
+
|
|
193
|
+
export default {
|
|
194
|
+
async fetch(request, env, ctx) {
|
|
195
|
+
const customEnv = {
|
|
196
|
+
...env,
|
|
197
|
+
BUNDLED_DEFINITIONS,
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
return kamaWorker.fetch(request, customEnv, ctx);
|
|
201
|
+
},
|
|
202
|
+
};
|
|
203
|
+
`;
|
|
204
|
+
|
|
146
205
|
writeFileSync(
|
|
147
206
|
join(cmsDir, 'index.js'),
|
|
148
|
-
|
|
207
|
+
cmsWorkerIndexContent
|
|
149
208
|
);
|
|
150
209
|
|
|
151
210
|
writeFileSync(
|
|
@@ -171,59 +230,70 @@ async function createFullWorkspace() {
|
|
|
171
230
|
}, null, 2)
|
|
172
231
|
);
|
|
173
232
|
|
|
174
|
-
// 🎯 Fixed CMS wrangler.json
|
|
233
|
+
// 🎯 Fixed CMS wrangler.json
|
|
234
|
+
const cmsWranglerConfig = {
|
|
235
|
+
$schema: '../node_modules/wrangler/config-schema.json',
|
|
236
|
+
name: workerName,
|
|
237
|
+
main: 'index.js',
|
|
238
|
+
compatibility_date: '2026-08-01',
|
|
239
|
+
compatibility_flags: ['nodejs_compat'],
|
|
240
|
+
assets: {
|
|
241
|
+
directory: '../node_modules/@brightsideoy/kama/dist',
|
|
242
|
+
binding: 'ASSETS'
|
|
243
|
+
},
|
|
244
|
+
images: {
|
|
245
|
+
binding: 'IMAGES'
|
|
246
|
+
},
|
|
247
|
+
vars: {
|
|
248
|
+
CDN_DOMAIN: cmsDomain,
|
|
249
|
+
PUBLIC_FRONTEND_URL: isCloudflare ? `https://${siteDomain}` : 'http://localhost:4321',
|
|
250
|
+
CLOUDFLARE_ZONE_ID: isCloudflare ? "REPLACE_WITH_YOUR_32_CHAR_ZONE_ID" : "local-zone-not-needed"
|
|
251
|
+
},
|
|
252
|
+
d1_databases: [{
|
|
253
|
+
binding: 'DB',
|
|
254
|
+
database_name: dbName,
|
|
255
|
+
database_id: d1DatabaseId,
|
|
256
|
+
}],
|
|
257
|
+
r2_buckets: [{
|
|
258
|
+
binding: 'MEDIA_BUCKET',
|
|
259
|
+
bucket_name: bucketName,
|
|
260
|
+
}],
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
if (isCloudflare) {
|
|
264
|
+
cmsWranglerConfig.routes = [{ pattern: cmsDomain, custom_domain: true }];
|
|
265
|
+
}
|
|
266
|
+
|
|
175
267
|
writeFileSync(
|
|
176
268
|
join(cmsDir, 'wrangler.json'),
|
|
177
|
-
JSON.stringify(
|
|
178
|
-
$schema: '../node_modules/wrangler/config-schema.json',
|
|
179
|
-
name: workerName,
|
|
180
|
-
main: 'index.js',
|
|
181
|
-
compatibility_date: '2026-08-01',
|
|
182
|
-
compatibility_flags: ['nodejs_compat'],
|
|
183
|
-
assets: {
|
|
184
|
-
directory: '../node_modules/@brightsideoy/kama/dist',
|
|
185
|
-
binding: 'ASSETS'
|
|
186
|
-
},
|
|
187
|
-
images: {
|
|
188
|
-
binding: 'IMAGES'
|
|
189
|
-
},
|
|
190
|
-
routes: [{ pattern: cmsDomain, custom_domain: true }],
|
|
191
|
-
vars: {
|
|
192
|
-
CDN_DOMAIN: cmsDomain,
|
|
193
|
-
PUBLIC_FRONTEND_URL: `https://${siteDomain}`,
|
|
194
|
-
CLOUDFLARE_ZONE_ID: "REPLACE_WITH_YOUR_32_CHAR_ZONE_ID"
|
|
195
|
-
},
|
|
196
|
-
d1_databases: [{
|
|
197
|
-
binding: 'DB',
|
|
198
|
-
database_name: dbName,
|
|
199
|
-
database_id: d1DatabaseId,
|
|
200
|
-
}],
|
|
201
|
-
r2_buckets: [{
|
|
202
|
-
binding: 'MEDIA_BUCKET',
|
|
203
|
-
bucket_name: bucketName,
|
|
204
|
-
}],
|
|
205
|
-
}, null, 2)
|
|
269
|
+
JSON.stringify(cmsWranglerConfig, null, 2)
|
|
206
270
|
);
|
|
207
271
|
|
|
208
|
-
// 🎯 Fixed .dev.vars
|
|
272
|
+
// 🎯 Fixed .dev.vars
|
|
209
273
|
writeFileSync(
|
|
210
274
|
join(cmsDir, '.dev.vars'),
|
|
211
|
-
`# Cloudflare Edge Cache Purging Secrets\nCLOUDFLARE_API_TOKEN
|
|
275
|
+
`# Cloudflare Edge Cache Purging Secrets\nCLOUDFLARE_API_TOKEN=${isCloudflare ? 'cfut_YOUR_CUSTOM_PURGE_TOKEN' : 'local_token'}\n`
|
|
212
276
|
);
|
|
213
277
|
|
|
214
278
|
// 🎯 3. Setup First Astro Site tied to target workerName
|
|
215
|
-
const siteFolderName = siteDomain.split('.')[0];
|
|
216
|
-
await generateAstroSite(rootDir, siteFolderName, siteDomain,
|
|
279
|
+
const siteFolderName = isCloudflare ? siteDomain.split('.')[0] : 'web';
|
|
280
|
+
await generateAstroSite(rootDir, siteFolderName, siteDomain, cmsFullUrl, workerName, isCloudflare);
|
|
217
281
|
|
|
218
282
|
console.log(`\n✨ Workspace ready! Next steps:`);
|
|
219
283
|
console.log(` 1. cd ${projName}`);
|
|
220
284
|
console.log(` 2. npm install`);
|
|
221
|
-
|
|
222
|
-
|
|
285
|
+
|
|
286
|
+
if (isCloudflare) {
|
|
287
|
+
if (d1DatabaseId === '00000000-0000-0000-0000-000000000000' || d1DatabaseId === 'REPLACE_WITH_YOUR_D1_ID') {
|
|
288
|
+
console.log(` 3. Run 'npx wrangler login' and create a D1 database manually.`);
|
|
289
|
+
}
|
|
290
|
+
console.log(` 4. Update CLOUDFLARE_ZONE_ID in cms-worker/wrangler.json with your actual Zone ID`);
|
|
291
|
+
console.log(` 5. Securely store your purge token: cd cms-worker && npx wrangler secret put CLOUDFLARE_API_TOKEN`);
|
|
292
|
+
console.log(` 6. Run 'npm run dev:cms' from the workspace root to start the backend.`);
|
|
293
|
+
} else {
|
|
294
|
+
console.log(` 3. Run 'npm run dev:cms' from the workspace root to start the local SQLite backend.`);
|
|
295
|
+
console.log(`\n💡 Note: You can deploy to Cloudflare later by updating 'cms-worker/wrangler.json' with real IDs.`);
|
|
223
296
|
}
|
|
224
|
-
console.log(` 4. Update CLOUDFLARE_ZONE_ID in cms-worker/wrangler.json with your actual Zone ID`);
|
|
225
|
-
console.log(` 5. Securely store your purge token: cd cms-worker && npx wrangler secret put CLOUDFLARE_API_TOKEN`);
|
|
226
|
-
console.log(` 6. Run 'npm run dev:cms' from the workspace root to start the backend.`);
|
|
227
297
|
}
|
|
228
298
|
|
|
229
299
|
/**
|
|
@@ -246,19 +316,146 @@ async function createNewSiteOnly() {
|
|
|
246
316
|
} catch (e) { }
|
|
247
317
|
}
|
|
248
318
|
|
|
319
|
+
console.log('\n🌍 Deployment Mode:');
|
|
320
|
+
console.log(' 1) Local Development');
|
|
321
|
+
console.log(' 2) Cloudflare Edge');
|
|
322
|
+
const envChoice = await rl.question('\nChoice [1/2]: ');
|
|
323
|
+
const isCloudflare = envChoice.trim() === '2';
|
|
324
|
+
|
|
249
325
|
const siteFolder = await rl.question('Site folder name (e.g., my-new-site): ');
|
|
250
|
-
const siteDomain = await rl.question('Website Domain (e.g., brand.com): ');
|
|
251
|
-
const cmsDomain = (await rl.question('CMS API Domain (e.g., admin.t3cloud.eu): ')) || 'admin.t3cloud.eu';
|
|
252
326
|
|
|
253
|
-
|
|
327
|
+
let siteDomain = 'localhost:4321';
|
|
328
|
+
let cmsFullUrl = 'http://localhost:8787';
|
|
329
|
+
|
|
330
|
+
if (isCloudflare) {
|
|
331
|
+
siteDomain = await rl.question('Website Domain (e.g., brand.com): ');
|
|
332
|
+
const cmsDomainInput = (await rl.question('CMS API Domain (e.g., admin.t3cloud.eu): ')) || 'admin.t3cloud.eu';
|
|
333
|
+
cmsFullUrl = `https://${cmsDomainInput.replace(/^https?:\/\//, '')}`;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
await generateAstroSite(rootDir, siteFolder, siteDomain, cmsFullUrl, targetWorkerName, isCloudflare);
|
|
254
337
|
|
|
255
338
|
console.log(`\n✨ Site created in sites/${siteFolder}! Run 'npm install' at workspace root.`);
|
|
256
339
|
}
|
|
257
340
|
|
|
341
|
+
/**
|
|
342
|
+
* Helper: Scaffolds initial starter schemas for all category folders
|
|
343
|
+
*/
|
|
344
|
+
function scaffoldSampleSchemas(rootDir) {
|
|
345
|
+
const defsDir = join(rootDir, 'content', 'definitions');
|
|
346
|
+
|
|
347
|
+
// 1. Channels
|
|
348
|
+
writeFileSync(join(defsDir, 'channels', 'website.yaml'), `id: website
|
|
349
|
+
label: Main Website
|
|
350
|
+
defaultLanguage: en
|
|
351
|
+
languages:
|
|
352
|
+
- en
|
|
353
|
+
- fi
|
|
354
|
+
`);
|
|
355
|
+
|
|
356
|
+
// 2. Nodes
|
|
357
|
+
writeFileSync(join(defsDir, 'nodes', 'page.yaml'), `id: page
|
|
358
|
+
label: Page
|
|
359
|
+
inTree: true
|
|
360
|
+
inVault: false
|
|
361
|
+
hasCanvas: true
|
|
362
|
+
tabs:
|
|
363
|
+
settings:
|
|
364
|
+
label: Settings
|
|
365
|
+
fields:
|
|
366
|
+
title:
|
|
367
|
+
label: Page Title
|
|
368
|
+
type: text
|
|
369
|
+
required: true
|
|
370
|
+
slug:
|
|
371
|
+
label: URL Slug
|
|
372
|
+
type: slug
|
|
373
|
+
linkedTo: title
|
|
374
|
+
`);
|
|
375
|
+
|
|
376
|
+
writeFileSync(join(defsDir, 'nodes', 'article.yaml'), `id: article
|
|
377
|
+
label: Article
|
|
378
|
+
inTree: false
|
|
379
|
+
inVault: true
|
|
380
|
+
hasCanvas: true
|
|
381
|
+
tabs:
|
|
382
|
+
settings:
|
|
383
|
+
label: Settings
|
|
384
|
+
fields:
|
|
385
|
+
title:
|
|
386
|
+
label: Title
|
|
387
|
+
type: text
|
|
388
|
+
required: true
|
|
389
|
+
slug:
|
|
390
|
+
label: Slug
|
|
391
|
+
type: slug
|
|
392
|
+
linkedTo: title
|
|
393
|
+
`);
|
|
394
|
+
|
|
395
|
+
// 3. Blocks
|
|
396
|
+
writeFileSync(join(defsDir, 'blocks', 'hero.yaml'), `id: hero
|
|
397
|
+
label: Hero Section
|
|
398
|
+
fields:
|
|
399
|
+
heading:
|
|
400
|
+
label: Heading
|
|
401
|
+
type: text
|
|
402
|
+
required: true
|
|
403
|
+
subheading:
|
|
404
|
+
label: Subheading
|
|
405
|
+
type: text
|
|
406
|
+
`);
|
|
407
|
+
|
|
408
|
+
writeFileSync(join(defsDir, 'blocks', 'text.yaml'), `id: text
|
|
409
|
+
label: Text Block
|
|
410
|
+
fields:
|
|
411
|
+
content:
|
|
412
|
+
label: Content
|
|
413
|
+
type: richtext
|
|
414
|
+
`);
|
|
415
|
+
|
|
416
|
+
// 4. Block Layouts
|
|
417
|
+
writeFileSync(join(defsDir, 'block-layouts', 'two-column.yaml'), `id: two-column
|
|
418
|
+
label: Two Column Layout
|
|
419
|
+
regions:
|
|
420
|
+
left:
|
|
421
|
+
label: Left Column
|
|
422
|
+
right:
|
|
423
|
+
label: Right Column
|
|
424
|
+
`);
|
|
425
|
+
|
|
426
|
+
// 5. Node Layouts
|
|
427
|
+
writeFileSync(join(defsDir, 'node-layouts', 'single-column.yml'), `id: single-column
|
|
428
|
+
label: Single Column Page
|
|
429
|
+
regions:
|
|
430
|
+
main:
|
|
431
|
+
label: Main Content Area
|
|
432
|
+
`);
|
|
433
|
+
|
|
434
|
+
// 6. Field Sets
|
|
435
|
+
writeFileSync(join(defsDir, 'field-sets', 'page-base.yaml'), `id: page-base
|
|
436
|
+
label: Base Page Fields
|
|
437
|
+
fields:
|
|
438
|
+
metaTitle:
|
|
439
|
+
label: Meta Title
|
|
440
|
+
type: text
|
|
441
|
+
metaDescription:
|
|
442
|
+
label: Meta Description
|
|
443
|
+
type: text
|
|
444
|
+
`);
|
|
445
|
+
|
|
446
|
+
// 7. Trees
|
|
447
|
+
writeFileSync(join(defsDir, 'trees', 'navigation.yaml'), `id: navigation
|
|
448
|
+
label: Main Navigation Tree
|
|
449
|
+
maxDepth: 3
|
|
450
|
+
allowedNodeTypes:
|
|
451
|
+
- page
|
|
452
|
+
`);
|
|
453
|
+
}
|
|
454
|
+
|
|
258
455
|
/**
|
|
259
456
|
* Helper: Scaffolds the Astro site with middleware, wrangler.json, & slug page
|
|
260
457
|
*/
|
|
261
|
-
async function generateAstroSite(rootDir, siteFolder, siteDomain,
|
|
458
|
+
async function generateAstroSite(rootDir, siteFolder, siteDomain, cmsFullUrl, workerName = 'kama-worker', isCloudflare = false) {
|
|
262
459
|
console.log(`\n🚀 Scaffolding Astro site (${siteFolder}) mapped to ${siteDomain} (Service: ${workerName})...`);
|
|
263
460
|
|
|
264
461
|
const siteDir = join(rootDir, 'sites', siteFolder);
|
|
@@ -289,30 +486,36 @@ async function generateAstroSite(rootDir, siteFolder, siteDomain, cmsDomain, wor
|
|
|
289
486
|
}, null, 2)
|
|
290
487
|
);
|
|
291
488
|
|
|
292
|
-
|
|
489
|
+
const siteWranglerConfig = {
|
|
490
|
+
$schema: 'node_modules/wrangler/config-schema.json',
|
|
491
|
+
name: siteFolder,
|
|
492
|
+
compatibility_date: '2026-08-01',
|
|
493
|
+
compatibility_flags: ['nodejs_compat'],
|
|
494
|
+
assets: {
|
|
495
|
+
directory: './dist/client',
|
|
496
|
+
binding: 'ASSETS',
|
|
497
|
+
html_handling: 'drop-trailing-slash',
|
|
498
|
+
not_found_handling: '404-page',
|
|
499
|
+
run_worker_first: true
|
|
500
|
+
},
|
|
501
|
+
services: [{ binding: 'CMS_WORKER', service: workerName }],
|
|
502
|
+
vars: {
|
|
503
|
+
PUBLIC_CMS_URL: cmsFullUrl,
|
|
504
|
+
PUBLIC_API_URL: cmsFullUrl,
|
|
505
|
+
},
|
|
506
|
+
};
|
|
507
|
+
|
|
508
|
+
if (isCloudflare) {
|
|
509
|
+
siteWranglerConfig.routes = [{ pattern: siteDomain, custom_domain: true }];
|
|
510
|
+
}
|
|
511
|
+
|
|
293
512
|
writeFileSync(
|
|
294
513
|
join(siteDir, 'wrangler.json'),
|
|
295
|
-
JSON.stringify(
|
|
296
|
-
$schema: 'node_modules/wrangler/config-schema.json',
|
|
297
|
-
name: siteFolder,
|
|
298
|
-
compatibility_date: '2026-08-01',
|
|
299
|
-
compatibility_flags: ['nodejs_compat'],
|
|
300
|
-
assets: {
|
|
301
|
-
directory: './dist/client',
|
|
302
|
-
binding: 'ASSETS',
|
|
303
|
-
html_handling: 'drop-trailing-slash',
|
|
304
|
-
not_found_handling: '404-page',
|
|
305
|
-
run_worker_first: true
|
|
306
|
-
},
|
|
307
|
-
services: [{ binding: 'CMS_WORKER', service: workerName }],
|
|
308
|
-
routes: [{ pattern: siteDomain, custom_domain: true }],
|
|
309
|
-
vars: {
|
|
310
|
-
PUBLIC_CMS_URL: `https://${cmsDomain}`,
|
|
311
|
-
PUBLIC_API_URL: `https://${cmsDomain}`,
|
|
312
|
-
},
|
|
313
|
-
}, null, 2)
|
|
514
|
+
JSON.stringify(siteWranglerConfig, null, 2)
|
|
314
515
|
);
|
|
315
516
|
|
|
517
|
+
const cmsHostname = cmsFullUrl.replace(/^https?:\/\//, '').split(':')[0];
|
|
518
|
+
|
|
316
519
|
const astroConfig = `import { defineConfig } from 'astro/config';
|
|
317
520
|
import cloudflare from '@astrojs/cloudflare';
|
|
318
521
|
|
|
@@ -321,8 +524,8 @@ export default defineConfig({
|
|
|
321
524
|
trailingSlash: 'ignore',
|
|
322
525
|
image: {
|
|
323
526
|
remotePatterns: [
|
|
324
|
-
{ protocol: 'http', hostname: 'localhost', port: '
|
|
325
|
-
{ protocol: 'https', hostname: '${
|
|
527
|
+
{ protocol: 'http', hostname: 'localhost', port: '8787' },
|
|
528
|
+
{ protocol: '${isCloudflare ? 'https' : 'http'}', hostname: '${cmsHostname}' }
|
|
326
529
|
]
|
|
327
530
|
},
|
|
328
531
|
build: {
|
|
@@ -336,7 +539,7 @@ export default defineConfig({
|
|
|
336
539
|
|
|
337
540
|
writeFileSync(
|
|
338
541
|
join(siteDir, '.env'),
|
|
339
|
-
`PUBLIC_CMS_URL="
|
|
542
|
+
`PUBLIC_CMS_URL="${cmsFullUrl}"\nPUBLIC_API_URL="${cmsFullUrl}"\n`
|
|
340
543
|
);
|
|
341
544
|
}
|
|
342
545
|
|