@brightsideoy/kama 0.1.0-alpha.158 → 0.1.0-alpha.159

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 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, statSync, unlinkSync, appendFileSync } from 'node:fs';
3
+ import { existsSync, mkdirSync, writeFileSync, readFileSync, readdirSync, cpSync, unlinkSync, appendFileSync } from 'node:fs';
4
4
  import { join, dirname, basename, resolve } from 'node:path';
5
5
  import { fileURLToPath, pathToFileURL } from 'node:url';
6
6
  import * as readline from 'node:readline/promises';
@@ -81,15 +81,15 @@ async function main() {
81
81
  console.log(' 4) npx kama promote - Promote current Local workspace to Cloudflare Edge');
82
82
  console.log(' 5) Help - Show all commands and usage');
83
83
 
84
- const choice = await rl.question('\nSelect choice [1/2/3/4/5]: ');
84
+ const choice = (await rl.question('\nSelect choice [1/2/3/4/5]: ')).trim();
85
85
 
86
- if (choice.trim() === '5') {
86
+ if (choice === '5') {
87
87
  showHelp();
88
- } else if (choice.trim() === '4') {
88
+ } else if (choice === '4') {
89
89
  await promoteLocalToCloudflare();
90
- } else if (choice.trim() === '3') {
90
+ } else if (choice === '3') {
91
91
  await bundleWorkspaceSchemas();
92
- } else if (choice.trim() === '2') {
92
+ } else if (choice === '2') {
93
93
  await createNewSiteOnly();
94
94
  } else {
95
95
  await createFullWorkspace();
@@ -99,6 +99,20 @@ async function main() {
99
99
  rl.close();
100
100
  }
101
101
 
102
+ /**
103
+ * Helper to update astro.config.mjs for Cloudflare
104
+ */
105
+ function convertAstroConfigToCloudflare(siteDir) {
106
+ const configPath = join(siteDir, 'astro.config.mjs');
107
+ if (existsSync(configPath)) {
108
+ let content = readFileSync(configPath, 'utf-8');
109
+ content = content
110
+ .replace("import node from '@astrojs/node';", "import cloudflare from '@astrojs/cloudflare';")
111
+ .replace('adapter: node({ mode: "standalone" })', 'adapter: cloudflare({ imageService: process.env.NODE_ENV === "production" ? "cloudflare" : "passthrough" })');
112
+ writeFileSync(configPath, content, 'utf-8');
113
+ }
114
+ }
115
+
102
116
  /**
103
117
  * COMMAND: npx kama init
104
118
  * Kickstart full Monorepo Workspace
@@ -174,14 +188,15 @@ async function createFullWorkspace() {
174
188
  if (isCloudflare) {
175
189
  console.log(`\n🔑 Checking Cloudflare authentication...`);
176
190
  try {
177
- execSync('npx wrangler whoami', { stdio: 'pipe' });
191
+ // Pass stdio: 'ignore' so child process doesn't drain parent stdin stream!
192
+ execSync('npx wrangler whoami', { stdio: 'ignore' });
178
193
  isAuthenticated = true;
179
194
  console.log(`✅ Logged in to Cloudflare.`);
180
195
  } catch (error) {
181
196
  console.log(`⚠️ You are not logged in to Cloudflare.`);
182
197
  console.log(`🌐 Launching browser for Cloudflare login...`);
183
198
  try {
184
- execSync('npx wrangler login', { stdio: 'inherit' });
199
+ execSync('npx wrangler login', { stdio: 'ignore' });
185
200
  isAuthenticated = true;
186
201
  console.log(`✅ Successfully logged in!`);
187
202
  } catch (loginError) {
@@ -192,7 +207,7 @@ async function createFullWorkspace() {
192
207
  if (isAuthenticated) {
193
208
  try {
194
209
  console.log(`\n🗄️ Checking existing Cloudflare D1 databases...`);
195
- const listOutput = execSync(`npx wrangler d1 list --json`, { encoding: 'utf-8', stdio: 'pipe' });
210
+ const listOutput = execSync(`npx wrangler d1 list --json`, { encoding: 'utf-8', stdio: ['ignore', 'pipe', 'pipe'] });
196
211
  const jsonStart = listOutput.indexOf('[');
197
212
  const jsonEnd = listOutput.lastIndexOf(']') + 1;
198
213
  let databases = [];
@@ -213,7 +228,7 @@ async function createFullWorkspace() {
213
228
  } else {
214
229
  dbName = (await rl.question(`Enter a new database name: `)).trim();
215
230
  console.log(`\n🗄️ Creating new database '${dbName}'...`);
216
- const d1Output = execSync(`npx wrangler d1 create ${dbName}`, { encoding: 'utf-8', stdio: 'pipe' });
231
+ const d1Output = execSync(`npx wrangler d1 create ${dbName}`, { encoding: 'utf-8', stdio: ['ignore', 'pipe', 'pipe'] });
217
232
  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}/);
218
233
  if (match) {
219
234
  d1DatabaseId = match[0];
@@ -222,7 +237,7 @@ async function createFullWorkspace() {
222
237
  }
223
238
  } else {
224
239
  console.log(`\n🗄️ Attempting to auto-create Cloudflare D1 Database '${dbName}'...`);
225
- const d1Output = execSync(`npx wrangler d1 create ${dbName}`, { encoding: 'utf-8', stdio: 'pipe' });
240
+ const d1Output = execSync(`npx wrangler d1 create ${dbName}`, { encoding: 'utf-8', stdio: ['ignore', 'pipe', 'pipe'] });
226
241
  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}/);
227
242
  if (match) {
228
243
  d1DatabaseId = match[0];
@@ -283,27 +298,10 @@ async function createFullWorkspace() {
283
298
  writeFileSync(join(cmsDir, 'bundled-definitions.js'), `const defs = ${emptyDefs};\nexport const BUNDLED_DEFINITIONS = defs;\nexport default defs;\n`);
284
299
 
285
300
  if (isCloudflare) {
286
- const cmsWorkerIndexContent = `import kamaWorker from '@brightsideoy/kama';
287
- import * as localBundle from './bundled-definitions.js';
288
-
289
- export default {
290
- async fetch(request, env, ctx) {
291
- const schemas = localBundle.BUNDLED_DEFINITIONS || localBundle.default || localBundle;
292
- const customEnv = { ...env, BUNDLED_DEFINITIONS: schemas, KAMA_RUNTIME: 'cloudflare' };
293
-
294
- if (kamaWorker && typeof kamaWorker.fetch === 'function') {
295
- return kamaWorker.fetch(request, customEnv, ctx);
296
- }
297
-
298
- if (kamaWorker && kamaWorker.app && typeof kamaWorker.app.fetch === 'function') {
299
- return kamaWorker.app.fetch(request, customEnv, ctx);
300
- }
301
-
302
- return new Response('Kama Engine Worker Ready', { status: 200 });
303
- }
304
- };
305
- `;
306
- writeFileSync(join(cmsDir, 'index.js'), cmsWorkerIndexContent);
301
+ const templateIndexPath = join(__dirname, '../templates/kama-worker/index.js');
302
+ if (existsSync(templateIndexPath)) {
303
+ cpSync(templateIndexPath, join(cmsDir, 'index.js'));
304
+ }
307
305
 
308
306
  writeFileSync(
309
307
  join(cmsDir, 'package.json'),
@@ -352,71 +350,18 @@ export default {
352
350
 
353
351
  writeFileSync(join(cmsDir, 'wrangler.json'), JSON.stringify(cmsWranglerConfig, null, 2));
354
352
 
355
- // 🎯 FIX: CDN_DOMAIN left empty to auto-detect http://localhost:8787
356
353
  writeFileSync(join(cmsDir, '.dev.vars'), `# Cloudflare Edge Cache Purging Secrets
357
354
  CLOUDFLARE_API_TOKEN=cfut_YOUR_CUSTOM_PURGE_TOKEN
358
355
 
359
- # Local Development Overrides (Takes precedence over wrangler.json vars during local dev)
356
+ # Local Development Overrides
360
357
  CDN_DOMAIN=
361
358
  PUBLIC_FRONTEND_URL=http://localhost:4321
362
359
  `);
363
360
  } else {
364
- const nodeServerContent = `import { serve } from '@hono/node-server';
365
- import { serveStatic } from '@hono/node-server/serve-static';
366
- import kamaApp from '@brightsideoy/kama';
367
- import * as localBundle from './bundled-definitions.js';
368
- import dotenv from 'dotenv';
369
- import { readFileSync, existsSync } from 'node:fs';
370
- import { join } from 'node:path';
371
-
372
- dotenv.config();
373
-
374
- const possiblePaths = [
375
- './node_modules/@brightsideoy/kama/dist',
376
- '../node_modules/@brightsideoy/kama/dist',
377
- '../../node_modules/@brightsideoy/kama/dist'
378
- ];
379
- const distPath = possiblePaths.find(p => existsSync(p));
380
-
381
- if (!distPath) {
382
- console.warn('⚠️ Could not locate @brightsideoy/kama/dist folder. Admin UI will not load.');
383
- }
384
-
385
- kamaApp.use('*', async (c, next) => {
386
- c.env = {
387
- ...process.env,
388
- ...c.env,
389
- BUNDLED_DEFINITIONS: localBundle.BUNDLED_DEFINITIONS,
390
- KAMA_RUNTIME: 'node'
391
- };
392
- await next();
393
- });
394
-
395
- kamaApp.use('/media/*', serveStatic({ root: './' }));
396
-
397
- if (distPath) {
398
- kamaApp.use('/assets/*', serveStatic({ root: distPath }));
399
-
400
- kamaApp.get('/*', async (c, next) => {
401
- if (c.req.path.startsWith('/api') || c.req.path.startsWith('/media')) return next();
402
-
403
- const indexPath = join(distPath, 'index.html');
404
- if (existsSync(indexPath)) {
405
- return c.html(readFileSync(indexPath, 'utf-8'));
406
- }
407
- return next();
408
- });
409
- }
410
-
411
- const port = process.env.PORT ? parseInt(process.env.PORT, 10) : 8787;
412
-
413
- serve({ fetch: kamaApp.fetch, port }, (info) => {
414
- console.log(\`\\n🔥 KAMA CMS Node Server is running!\`);
415
- console.log(\`┃ Local http://localhost:\${info.port}/\`);
416
- if (distPath) console.log(\`┃ Admin UI Serving from: \${distPath}\\n\`);
417
- });
418
- `;
419
- writeFileSync(join(cmsDir, 'server.js'), nodeServerContent);
361
+ const templateServerPath = join(__dirname, '../templates/kama-worker/server.js');
362
+ if (existsSync(templateServerPath)) {
363
+ cpSync(templateServerPath, join(cmsDir, 'server.js'));
364
+ }
420
365
 
421
366
  writeFileSync(
422
367
  join(cmsDir, 'package.json'),
@@ -443,7 +388,6 @@ serve({ fetch: kamaApp.fetch, port }, (info) => {
443
388
  }, null, 2)
444
389
  );
445
390
 
446
- // For Node mode, localhost is explicitly used
447
391
  writeFileSync(join(cmsDir, '.env'), `PORT=8787\nKAMA_RUNTIME=node\nDB_PATH=./kama.db\nLOCAL_MEDIA_PATH=./public/media\nPUBLIC_CMS_URL=http://127.0.0.1:8787\nPUBLIC_API_URL=http://127.0.0.1:8787\nPUBLIC_FRONTEND_URL=http://127.0.0.1:4321\n`);
448
392
  }
449
393
 
@@ -554,11 +498,11 @@ async function promoteLocalToCloudflare() {
554
498
  console.log('\n🌐 --- UPGRADING WORKSPACE TO CLOUDFLARE EDGE --- 🌐\n');
555
499
 
556
500
  try {
557
- execSync('npx wrangler whoami', { stdio: 'pipe' });
501
+ execSync('npx wrangler whoami', { stdio: 'ignore' });
558
502
  console.log('✅ Logged in to Cloudflare.');
559
503
  } catch (e) {
560
504
  console.log('🌐 Launching browser for Cloudflare login...');
561
- try { execSync('npx wrangler login', { stdio: 'inherit' }); }
505
+ try { execSync('npx wrangler login', { stdio: 'ignore' }); }
562
506
  catch (loginError) { console.log('❌ Cloudflare login failed.'); return; }
563
507
  }
564
508
 
@@ -580,18 +524,16 @@ async function promoteLocalToCloudflare() {
580
524
  let d1DatabaseId = '00000000-0000-0000-0000-000000000000';
581
525
 
582
526
  try {
583
- const d1Output = execSync(`npx wrangler d1 create ${dbName}`, { encoding: 'utf-8', stdio: 'pipe' });
527
+ const d1Output = execSync(`npx wrangler d1 create ${dbName}`, { encoding: 'utf-8', stdio: ['ignore', 'pipe', 'pipe'] });
584
528
  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}/);
585
529
  if (match) d1DatabaseId = match[0];
586
530
  } catch (err) { }
587
531
 
588
- // 1. Upgrade Root
589
532
  const rootPkg = JSON.parse(readFileSync(rootPkgPath, 'utf-8'));
590
533
  rootPkg.devDependencies = rootPkg.devDependencies || {};
591
534
  rootPkg.devDependencies['wrangler'] = WRANGLER_LATEST;
592
535
  writeFileSync(rootPkgPath, JSON.stringify(rootPkg, null, 2));
593
536
 
594
- // 2. Upgrade Worker
595
537
  const workerName = `${projName}-worker`.toLowerCase().replace(/[^a-z0-9_-]/g, '-');
596
538
  const bucketName = `${projName}-media-prod`.toLowerCase().replace(/[^a-z0-9_-]/g, '-');
597
539
  const workerWranglerPath = join(workerDir, 'wrangler.json');
@@ -619,14 +561,16 @@ async function promoteLocalToCloudflare() {
619
561
 
620
562
  writeFileSync(workerWranglerPath, JSON.stringify(currentConfig, null, 2));
621
563
 
622
- // 🎯 FIX: CDN_DOMAIN left empty to auto-detect http://localhost:8787
623
564
  if (!existsSync(join(workerDir, '.dev.vars'))) {
624
565
  writeFileSync(join(workerDir, '.dev.vars'), `CLOUDFLARE_API_TOKEN=cfut_YOUR_CUSTOM_PURGE_TOKEN\nCDN_DOMAIN=\nPUBLIC_FRONTEND_URL=http://localhost:4321\n`);
625
566
  }
626
567
 
627
568
  const workerIndexPath = join(workerDir, 'index.js');
628
569
  if (!existsSync(workerIndexPath)) {
629
- writeFileSync(workerIndexPath, `import kamaWorker from '@brightsideoy/kama';\nimport * as localBundle from './bundled-definitions.js';\nexport default {\n async fetch(request, env, ctx) {\n const schemas = localBundle.BUNDLED_DEFINITIONS || localBundle.default || localBundle;\n const customEnv = { ...env, BUNDLED_DEFINITIONS: schemas, KAMA_RUNTIME: 'cloudflare' };\n if (kamaWorker && typeof kamaWorker.fetch === 'function') return kamaWorker.fetch(request, customEnv, ctx);\n if (kamaWorker && kamaWorker.app && typeof kamaWorker.app.fetch === 'function') return kamaWorker.app.fetch(request, customEnv, ctx);\n return new Response('Kama Engine Worker Ready', { status: 200 });\n }\n};\n`);
570
+ const templateIndexPath = join(__dirname, '../templates/kama-worker/index.js');
571
+ if (existsSync(templateIndexPath)) {
572
+ cpSync(templateIndexPath, workerIndexPath);
573
+ }
630
574
  }
631
575
 
632
576
  const workerPkgPath = join(workerDir, 'package.json');
@@ -641,16 +585,15 @@ async function promoteLocalToCloudflare() {
641
585
  writeFileSync(workerPkgPath, JSON.stringify(workerPkg, null, 2));
642
586
  }
643
587
 
644
- // 3. Upgrade Site
645
588
  if (siteDir && siteDomain) {
646
589
  let sessionId = "REPLACE_WITH_YOUR_SESSION_KV_ID";
647
590
  let htmlCacheId = "REPLACE_WITH_YOUR_HTML_CACHE_KV_ID";
648
591
  const prefix = basename(siteDir).replace(/[^a-zA-Z0-9]/g, '_').toUpperCase();
649
592
 
650
593
  try {
651
- const sessionOut = execSync(`npx wrangler kv namespace create "SESSION_${prefix}"`, { encoding: 'utf-8', stdio: 'pipe' });
594
+ const sessionOut = execSync(`npx wrangler kv namespace create "SESSION_${prefix}"`, { encoding: 'utf-8', stdio: ['ignore', 'pipe', 'pipe'] });
652
595
  if (sessionOut.match(/"id":\s*"([a-f0-9]{32})"/)) sessionId = sessionOut.match(/"id":\s*"([a-f0-9]{32})"/)[1];
653
- const cacheOut = execSync(`npx wrangler kv namespace create "HTML_CACHE_${prefix}"`, { encoding: 'utf-8', stdio: 'pipe' });
596
+ const cacheOut = execSync(`npx wrangler kv namespace create "HTML_CACHE_${prefix}"`, { encoding: 'utf-8', stdio: ['ignore', 'pipe', 'pipe'] });
654
597
  if (cacheOut.match(/"id":\s*"([a-f0-9]{32})"/)) htmlCacheId = cacheOut.match(/"id":\s*"([a-f0-9]{32})"/)[1];
655
598
  } catch (err) { }
656
599
 
@@ -685,10 +628,7 @@ async function promoteLocalToCloudflare() {
685
628
  writeFileSync(sitePkgPath, JSON.stringify(sitePkg, null, 2));
686
629
  }
687
630
 
688
- // 🎯 100% BULLETPROOF CONFIG WRITE FOR CLOUDFLARE
689
- const astroConfigPath = join(siteDir, 'astro.config.mjs');
690
- const cfConfigContent = `import { defineConfig } from 'astro/config';\nimport cloudflare from '@astrojs/cloudflare';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\nexport default defineConfig({\n output: 'server',\n trailingSlash: 'ignore',\n image: { service: { entrypoint: './src/lib/media/kama-image-service.ts' } },\n adapter: cloudflare({ imageService: process.env.NODE_ENV === 'production' ? "cloudflare" : "passthrough" }),\n vite: {\n resolve: { alias: { '@': path.resolve(__dirname, './src') } },\n ssr: {\n external: ['cloudflare:workers', 'tinyexec', 'node:child_process', 'node:fs', 'node:url', 'node:path', 'node:stream', 'node:readline', 'node:stream/promises']\n },\n environments: {\n ssr: {\n external: ['cloudflare:workers', 'tinyexec', 'node:child_process', 'node:fs', 'node:url', 'node:path', 'node:stream', 'node:readline', 'node:stream/promises']\n }\n }\n }\n});\n`;
691
- writeFileSync(astroConfigPath, cfConfigContent);
631
+ convertAstroConfigToCloudflare(siteDir);
692
632
 
693
633
  const tsConfigPath = join(siteDir, 'tsconfig.json');
694
634
  if (existsSync(tsConfigPath)) {
@@ -742,22 +682,13 @@ async function generateAstroSite(rootDir, siteFolder, siteDomain, cmsFullUrl, wo
742
682
  if (sitePkg.devDependencies && sitePkg.devDependencies['wrangler']) delete sitePkg.devDependencies['wrangler'];
743
683
 
744
684
  sitePkg.dependencies['@astrojs/node'] = ASTRO_NODE_LATEST;
745
-
746
- // 🎯 100% BULLETPROOF CONFIG WRITE FOR NODE
747
- const astroConfigPath = join(siteDir, 'astro.config.mjs');
748
- const nodeConfigContent = `import { defineConfig } from 'astro/config';\nimport node from '@astrojs/node';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\nexport default defineConfig({\n output: 'server',\n trailingSlash: 'ignore',\n image: { service: { entrypoint: './src/lib/media/kama-image-service.ts' } },\n adapter: node({ mode: "standalone" }),\n vite: {\n resolve: { alias: { '@': path.resolve(__dirname, './src') } },\n ssr: {\n external: ['cloudflare:workers', 'tinyexec', 'node:child_process', 'node:fs', 'node:url', 'node:path', 'node:stream', 'node:readline', 'node:stream/promises']\n },\n environments: {\n ssr: {\n external: ['cloudflare:workers', 'tinyexec', 'node:child_process', 'node:fs', 'node:url', 'node:path', 'node:stream', 'node:readline', 'node:stream/promises']\n }\n }\n }\n});\n`;
749
- writeFileSync(astroConfigPath, nodeConfigContent);
750
-
751
685
  } else {
752
686
  sitePkg.dependencies['@astrojs/cloudflare'] = ASTRO_CF_LATEST;
753
687
  if (sitePkg.dependencies['wrangler']) delete sitePkg.dependencies['wrangler'];
754
688
  sitePkg.devDependencies = sitePkg.devDependencies || {};
755
689
  sitePkg.devDependencies['wrangler'] = WRANGLER_LATEST;
756
690
 
757
- // 🎯 100% BULLETPROOF CONFIG WRITE FOR CLOUDFLARE
758
- const astroConfigPath = join(siteDir, 'astro.config.mjs');
759
- const cfConfigContent = `import { defineConfig } from 'astro/config';\nimport cloudflare from '@astrojs/cloudflare';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\nexport default defineConfig({\n output: 'server',\n trailingSlash: 'ignore',\n image: { service: { entrypoint: './src/lib/media/kama-image-service.ts' } },\n adapter: cloudflare({ imageService: process.env.NODE_ENV === 'production' ? "cloudflare" : "passthrough" }),\n vite: {\n resolve: { alias: { '@': path.resolve(__dirname, './src') } },\n ssr: {\n external: ['cloudflare:workers', 'tinyexec', 'node:child_process', 'node:fs', 'node:url', 'node:path', 'node:stream', 'node:readline', 'node:stream/promises']\n },\n environments: {\n ssr: {\n external: ['cloudflare:workers', 'tinyexec', 'node:child_process', 'node:fs', 'node:url', 'node:path', 'node:stream', 'node:readline', 'node:stream/promises']\n }\n }\n }\n});\n`;
760
- writeFileSync(astroConfigPath, cfConfigContent);
691
+ convertAstroConfigToCloudflare(siteDir);
761
692
  }
762
693
 
763
694
  writeFileSync(join(siteDir, 'package.json'), JSON.stringify(sitePkg, null, 2));
@@ -776,9 +707,9 @@ async function generateAstroSite(rootDir, siteFolder, siteDomain, cmsFullUrl, wo
776
707
 
777
708
  try {
778
709
  const prefix = siteFolder.replace(/[^a-zA-Z0-9]/g, '_').toUpperCase();
779
- const sessionOut = execSync(`npx wrangler kv namespace create "SESSION_${prefix}"`, { encoding: 'utf-8', stdio: 'pipe' });
710
+ const sessionOut = execSync(`npx wrangler kv namespace create "SESSION_${prefix}"`, { encoding: 'utf-8', stdio: ['ignore', 'pipe', 'pipe'] });
780
711
  if (sessionOut.match(/"id":\s*"([a-f0-9]{32})"/)) sessionId = sessionOut.match(/"id":\s*"([a-f0-9]{32})"/)[1];
781
- const cacheOut = execSync(`npx wrangler kv namespace create "HTML_CACHE_${prefix}"`, { encoding: 'utf-8', stdio: 'pipe' });
712
+ const cacheOut = execSync(`npx wrangler kv namespace create "HTML_CACHE_${prefix}"`, { encoding: 'utf-8', stdio: ['ignore', 'pipe', 'pipe'] });
782
713
  if (cacheOut.match(/"id":\s*"([a-f0-9]{32})"/)) htmlCacheId = cacheOut.match(/"id":\s*"([a-f0-9]{32})"/)[1];
783
714
  } catch (err) { }
784
715
 
@@ -19,6 +19,8 @@ regions:
19
19
  footer:
20
20
  label: Footer
21
21
  inherit: parent
22
+ purgeTargets:
23
+ - "/partials/footer"
22
24
  disallowedBlocks:
23
25
  - hero
24
26
  - image_card
@@ -35,6 +35,8 @@ regions:
35
35
  footer:
36
36
  label: Footer
37
37
  inherit: parent
38
+ purgeTargets:
39
+ - "/partials/footer"
38
40
  disallowedBlocks:
39
41
  - hero
40
42
  - image_card
@@ -40,6 +40,8 @@ regions:
40
40
  footer:
41
41
  label: Footer
42
42
  inherit: parent
43
+ purgeTargets:
44
+ - "/partials/footer"
43
45
  disallowedBlocks:
44
46
  - hero
45
47
  - image_card