gazetta 0.0.4 → 0.0.6
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/admin-dist/assets/{index-o6Ikobnh.js → index-CVC2_Byr.js} +68 -65
- package/admin-dist/assets/{index-CWxPBgs-.css → index-W1ylqX_Y.css} +1 -1
- package/admin-dist/index.html +2 -2
- package/dist/admin-api/routes/preview.js +4 -1
- package/dist/admin-api/routes/preview.js.map +1 -1
- package/dist/admin-api/routes/publish.d.ts.map +1 -1
- package/dist/admin-api/routes/publish.js +30 -7
- package/dist/admin-api/routes/publish.js.map +1 -1
- package/dist/assemble.d.ts +23 -0
- package/dist/assemble.d.ts.map +1 -0
- package/dist/assemble.js +95 -0
- package/dist/assemble.js.map +1 -0
- package/dist/cli/index.js +273 -4
- package/dist/cli/index.js.map +1 -1
- package/dist/content.d.ts +6 -0
- package/dist/content.d.ts.map +1 -0
- package/dist/content.js +28 -0
- package/dist/content.js.map +1 -0
- package/dist/editor/mount.d.ts.map +1 -1
- package/dist/editor/mount.js +11 -19
- package/dist/editor/mount.js.map +1 -1
- package/dist/formats.d.ts +60 -0
- package/dist/formats.d.ts.map +1 -0
- package/dist/formats.js +34 -0
- package/dist/formats.js.map +1 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/manifest.d.ts.map +1 -1
- package/dist/manifest.js +1 -0
- package/dist/manifest.js.map +1 -1
- package/dist/publish-rendered.d.ts +6 -4
- package/dist/publish-rendered.d.ts.map +1 -1
- package/dist/publish-rendered.js +64 -12
- package/dist/publish-rendered.js.map +1 -1
- package/dist/resolver.d.ts.map +1 -1
- package/dist/resolver.js +3 -2
- package/dist/resolver.js.map +1 -1
- package/dist/targets.d.ts +3 -1
- package/dist/targets.d.ts.map +1 -1
- package/dist/targets.js +14 -10
- package/dist/targets.js.map +1 -1
- package/dist/types.d.ts +23 -4
- package/dist/types.d.ts.map +1 -1
- package/dist/workers/cloudflare-r2.d.ts +31 -0
- package/dist/workers/cloudflare-r2.d.ts.map +1 -0
- package/dist/workers/cloudflare-r2.js +122 -0
- package/dist/workers/cloudflare-r2.js.map +1 -0
- package/package.json +16 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
.publish-content[data-v-878d0536]{display:flex;flex-direction:column;gap:1rem}.publish-item[data-v-878d0536]{display:flex;align-items:center;gap:.5rem;font-weight:600;font-size:1rem}.publish-empty[data-v-878d0536]{color:#888;font-size:.875rem}.publish-label[data-v-878d0536]{font-size:.75rem;text-transform:uppercase;color:#888;letter-spacing:.03em}.publish-targets[data-v-878d0536]{display:flex;flex-direction:column;gap:.5rem}.publish-target[data-v-878d0536]{display:flex;align-items:center;gap:.5rem}.publish-target label[data-v-878d0536]{cursor:pointer}.publish-results[data-v-878d0536]{display:flex;flex-direction:column;gap:.5rem}.publish-result[data-v-878d0536]{display:flex;align-items:center;gap:.5rem;padding:.5rem;border-radius:6px}.publish-result.success[data-v-878d0536]{background:#052e16;color:#4ade80}.publish-result.error[data-v-878d0536]{background:#450a0a;color:#f87171}.result-target[data-v-878d0536]{font-weight:600}.result-detail[data-v-878d0536]{margin-left:auto;font-size:.875rem;opacity:.8}.fetch-content[data-v-359a5f85]{display:flex;flex-direction:column;gap:1rem}.fetch-empty[data-v-359a5f85]{color:#888;font-size:.875rem}.fetch-label[data-v-359a5f85]{font-size:.875rem;color:#aaa;margin-bottom:.5rem}.fetch-list[data-v-359a5f85]{width:100%}.fetch-result[data-v-359a5f85]{display:flex;align-items:flex-start;gap:.75rem;padding:.75rem;border-radius:6px}.fetch-result.success[data-v-359a5f85]{background:#052e16;color:#4ade80}.fetch-result.error[data-v-359a5f85]{background:#450a0a;color:#f87171}.fetch-items[data-v-359a5f85]{font-size:.75rem;opacity:.7;margin-top:.25rem}.cms-toolbar[data-v-
|
|
1
|
+
.publish-content[data-v-878d0536]{display:flex;flex-direction:column;gap:1rem}.publish-item[data-v-878d0536]{display:flex;align-items:center;gap:.5rem;font-weight:600;font-size:1rem}.publish-empty[data-v-878d0536]{color:#888;font-size:.875rem}.publish-label[data-v-878d0536]{font-size:.75rem;text-transform:uppercase;color:#888;letter-spacing:.03em}.publish-targets[data-v-878d0536]{display:flex;flex-direction:column;gap:.5rem}.publish-target[data-v-878d0536]{display:flex;align-items:center;gap:.5rem}.publish-target label[data-v-878d0536]{cursor:pointer}.publish-results[data-v-878d0536]{display:flex;flex-direction:column;gap:.5rem}.publish-result[data-v-878d0536]{display:flex;align-items:center;gap:.5rem;padding:.5rem;border-radius:6px}.publish-result.success[data-v-878d0536]{background:#052e16;color:#4ade80}.publish-result.error[data-v-878d0536]{background:#450a0a;color:#f87171}.result-target[data-v-878d0536]{font-weight:600}.result-detail[data-v-878d0536]{margin-left:auto;font-size:.875rem;opacity:.8}.fetch-content[data-v-359a5f85]{display:flex;flex-direction:column;gap:1rem}.fetch-empty[data-v-359a5f85]{color:#888;font-size:.875rem}.fetch-label[data-v-359a5f85]{font-size:.875rem;color:#aaa;margin-bottom:.5rem}.fetch-list[data-v-359a5f85]{width:100%}.fetch-result[data-v-359a5f85]{display:flex;align-items:flex-start;gap:.75rem;padding:.75rem;border-radius:6px}.fetch-result.success[data-v-359a5f85]{background:#052e16;color:#4ade80}.fetch-result.error[data-v-359a5f85]{background:#450a0a;color:#f87171}.fetch-items[data-v-359a5f85]{font-size:.75rem;opacity:.7;margin-top:.25rem}.cms-toolbar[data-v-ad5a7042]{border-radius:0;border-left:0;border-right:0;border-top:0}.cms-logo[data-v-ad5a7042]{font-weight:700;font-size:1.125rem;display:flex;align-items:center;gap:.5rem}.cms-site-name[data-v-ad5a7042]{margin-left:1rem;color:#888;font-size:.875rem}.cms-btn[data-v-ad5a7042]{margin-left:.5rem}.cms-toast[data-v-ad5a7042]{font-size:.8125rem;display:flex;align-items:center;gap:.375rem}.cms-toast-success[data-v-ad5a7042]{color:#16a34a}.cms-toast-error[data-v-ad5a7042]{color:#dc2626}.cms-toast-dirty[data-v-ad5a7042]{color:#d97706}.fade-enter-active[data-v-ad5a7042],.fade-leave-active[data-v-ad5a7042]{transition:opacity .2s}.fade-enter-from[data-v-ad5a7042],.fade-leave-to[data-v-ad5a7042]{opacity:0}*{box-sizing:border-box;margin:0;padding:0}html,body,#app,.cms-app{height:100%}body{font-family:system-ui,-apple-system,sans-serif;color:#1a1a1a;background:#fff}.dark body{color:#e4e4e7;background:#09090b}.cms-error{padding:2rem;color:#c00}.cms-loading{padding:2rem;color:#666}.create-content[data-v-b021d738]{display:flex;flex-direction:column;gap:1rem}.create-field[data-v-b021d738]{display:flex;flex-direction:column;gap:.375rem}.create-field label[data-v-b021d738]{font-size:.75rem;text-transform:uppercase;color:#888;letter-spacing:.03em}.create-input[data-v-b021d738],.create-list[data-v-b021d738]{width:100%}.create-hint[data-v-b021d738]{font-size:.75rem;color:#666}.create-error[data-v-b021d738]{color:#f87171;font-size:.875rem}.create-content[data-v-0b98775c]{display:flex;flex-direction:column;gap:1rem}.create-field[data-v-0b98775c]{display:flex;flex-direction:column;gap:.375rem}.create-field label[data-v-0b98775c]{font-size:.75rem;text-transform:uppercase;color:#888;letter-spacing:.03em}.create-input[data-v-0b98775c],.create-list[data-v-0b98775c]{width:100%}.create-error[data-v-0b98775c]{color:#f87171;font-size:.875rem}.site-tree h3[data-v-ccc411a6]{font-size:.75rem;text-transform:uppercase;color:#888;margin-bottom:.5rem;letter-spacing:.05em}.tree[data-v-ccc411a6]{font-size:.875rem}.new-btns[data-v-ccc411a6]{display:flex;gap:.5rem;margin-top:.5rem}.node-row[data-v-ccc411a6]{display:flex;align-items:center;gap:.25rem;width:100%}.node-label[data-v-ccc411a6]{flex:1}.node-delete[data-v-ccc411a6]{opacity:0;transition:opacity .15s}.node-row:hover .node-delete[data-v-ccc411a6]{opacity:1}.add-content[data-v-db28dbd0]{display:flex;flex-direction:column;gap:1rem}.add-field[data-v-db28dbd0]{display:flex;flex-direction:column;gap:.375rem}.add-field label[data-v-db28dbd0]{font-size:.75rem;text-transform:uppercase;color:#888;letter-spacing:.03em}.add-input[data-v-db28dbd0],.add-list[data-v-db28dbd0]{width:100%}.add-error[data-v-db28dbd0]{color:#f87171;font-size:.875rem}.component-tree[data-v-51814cff]{margin-top:1.5rem}.component-tree h3[data-v-51814cff]{font-size:.75rem;text-transform:uppercase;color:#888;margin-bottom:.5rem;letter-spacing:.05em}.component-template[data-v-51814cff]{font-size:.75rem;color:#aaa;margin-bottom:.5rem}.tree[data-v-51814cff]{font-size:.875rem}.empty[data-v-51814cff]{font-size:.875rem;color:#aaa}.node-row[data-v-51814cff]{display:flex;align-items:center;gap:.5rem;width:100%}.node-label[data-v-51814cff]{flex:1}.node-template[data-v-51814cff]{font-size:.6875rem;color:#666}.node-actions[data-v-51814cff]{display:flex;gap:0;opacity:0;transition:opacity .15s}.node-row:hover .node-actions[data-v-51814cff]{opacity:1}.add-btn[data-v-51814cff]{margin-top:.5rem}.editor-panel h3[data-v-0ed9b006]{font-size:.75rem;text-transform:uppercase;color:#888;margin-bottom:1rem;letter-spacing:.05em}.editor-empty[data-v-0ed9b006]{color:#aaa;font-size:.875rem;display:flex;flex-direction:column;align-items:center;padding-top:3rem}.editor-container[data-v-0ed9b006]{font-size:.875rem}.preview-panel[data-v-28c53c49]{height:100%;display:flex;flex-direction:column}.preview-empty[data-v-28c53c49]{padding:3rem 1rem 1rem;color:#aaa;font-size:.875rem;display:flex;flex-direction:column;align-items:center}.preview-iframe[data-v-28c53c49]{flex:1;width:100%;border:0;background:#fff}.cms-editor[data-v-e4099a0e]{border:0;border-radius:0}.cms-panel[data-v-e4099a0e]{overflow:auto}.cms-panel-content[data-v-e4099a0e]{padding:1rem}
|
package/admin-dist/index.html
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
6
|
<title>Gazetta CMS</title>
|
|
7
7
|
<link rel="stylesheet" href="https://unpkg.com/primeicons/primeicons.css">
|
|
8
|
-
<script type="module" crossorigin src="/admin/assets/index-
|
|
9
|
-
<link rel="stylesheet" crossorigin href="/admin/assets/index-
|
|
8
|
+
<script type="module" crossorigin src="/admin/assets/index-CVC2_Byr.js"></script>
|
|
9
|
+
<link rel="stylesheet" crossorigin href="/admin/assets/index-W1ylqX_Y.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
|
12
12
|
<div id="app"></div>
|
|
@@ -26,7 +26,10 @@ async function renderPreview(c, siteDir, storage, overrides) {
|
|
|
26
26
|
return c.html(await renderPage(resolved, page.metadata, params));
|
|
27
27
|
}
|
|
28
28
|
catch (err) {
|
|
29
|
-
|
|
29
|
+
const e = err;
|
|
30
|
+
const msg = e.message.replace(/</g, '<').replace(/>/g, '>');
|
|
31
|
+
const stack = (e.stack ?? '').replace(/</g, '<').replace(/>/g, '>');
|
|
32
|
+
return c.html(`<div style="font-family:system-ui;padding:2rem;color:#fca5a5;background:#1a1a2e;min-height:100vh"><h2 style="color:#f87171;margin-bottom:1rem">Template Error</h2><pre style="white-space:pre-wrap;font-size:0.875rem;line-height:1.7">${msg}</pre><details style="margin-top:1rem"><summary style="color:#52525b;cursor:pointer">Stack trace</summary><pre style="color:#52525b;font-size:0.75rem;margin-top:0.5rem">${stack}</pre></details></div>`, 500);
|
|
30
33
|
}
|
|
31
34
|
}
|
|
32
35
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"preview.js","sourceRoot":"","sources":["../../../src/admin-api/routes/preview.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAgB,MAAM,MAAM,CAAA;AAEzC,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAA;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAE9C,MAAM,UAAU,aAAa,CAAC,OAAe,EAAE,OAAwB;IACrE,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAA;IAEtB,GAAG,CAAC,GAAG,CAAC,YAAY,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QAChC,OAAO,aAAa,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,CAAA;IAC3C,CAAC,CAAC,CAAA;IAEF,GAAG,CAAC,IAAI,CAAC,YAAY,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QACjC,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,GAAG,CAAC,IAAI,EAA6D,CAAA;QAC1F,OAAO,aAAa,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,CAAA;IAC3D,CAAC,CAAC,CAAA;IAEF,OAAO,GAAG,CAAA;AACZ,CAAC;AAED,KAAK,UAAU,aAAa,CAC1B,CAAU,EACV,OAAe,EACf,OAAwB,EACxB,SAAmD;IAEnD,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;IAC7C,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,IAAI,GAAG,CAAA;IAEhF,KAAK,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QAC1C,MAAM,MAAM,GAAG,UAAU,CAAC,IAAI,CAAC,KAAK,EAAE,WAAW,CAAC,CAAA;QAClD,IAAI,MAAM,EAAE,CAAC;YACX,IAAI,CAAC;gBACH,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAA;gBAClD,IAAI,SAAS;oBAAE,cAAc,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAA;gBAClD,OAAO,CAAC,CAAC,IAAI,CAAC,MAAM,UAAU,CAAC,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAA;YAClE,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,OAAO,CAAC,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"preview.js","sourceRoot":"","sources":["../../../src/admin-api/routes/preview.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"publish.d.ts","sourceRoot":"","sources":["../../../src/admin-api/routes/publish.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAC3B,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;
|
|
1
|
+
{"version":3,"file":"publish.d.ts","sourceRoot":"","sources":["../../../src/admin-api/routes/publish.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAC3B,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAMnE,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EACf,aAAa,EAAE,eAAe,EAC9B,cAAc,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,EAC7C,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,8EAgL7C"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Hono } from 'hono';
|
|
2
2
|
import { publishItems, resolveDependencies } from '../../publish.js';
|
|
3
|
-
import { publishPageRendered, publishFragmentRendered, publishSiteManifest, publishFragmentIndex,
|
|
3
|
+
import { publishPageRendered, publishFragmentRendered, publishSiteManifest, publishFragmentIndex, createCloudflarePurge } from '../../publish-rendered.js';
|
|
4
|
+
import { loadSite } from '../../site-loader.js';
|
|
4
5
|
export function publishRoutes(siteDir, sourceStorage, preInitTargets, targetConfigs) {
|
|
5
6
|
const app = new Hono();
|
|
6
7
|
// Background target initialization
|
|
@@ -57,7 +58,8 @@ export function publishRoutes(siteDir, sourceStorage, preInitTargets, targetConf
|
|
|
57
58
|
for (const item of allItems) {
|
|
58
59
|
if (item.startsWith('pages/')) {
|
|
59
60
|
const pageName = item.replace('pages/', '');
|
|
60
|
-
const
|
|
61
|
+
const config = getTargetConfig(targetName);
|
|
62
|
+
const { files } = await publishPageRendered(pageName, sourceStorage, siteDir, targetStorage, config?.cache);
|
|
61
63
|
totalFiles += files;
|
|
62
64
|
}
|
|
63
65
|
else if (item.startsWith('fragments/')) {
|
|
@@ -70,12 +72,33 @@ export function publishRoutes(siteDir, sourceStorage, preInitTargets, targetConf
|
|
|
70
72
|
await publishSiteManifest(sourceStorage, siteDir, targetStorage);
|
|
71
73
|
await publishFragmentIndex(sourceStorage, siteDir, targetStorage);
|
|
72
74
|
totalFiles += 2;
|
|
73
|
-
// 4. Purge edge cache
|
|
75
|
+
// 4. Purge edge cache via Cloudflare API
|
|
74
76
|
const config = getTargetConfig(targetName);
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
77
|
+
const zoneId = process.env.CF_ZONE_ID;
|
|
78
|
+
const apiToken = process.env.CF_API_TOKEN;
|
|
79
|
+
if (config?.siteUrl && zoneId && apiToken) {
|
|
80
|
+
const purge = createCloudflarePurge(zoneId, apiToken);
|
|
81
|
+
const hasFragments = allItems.some(i => i.startsWith('fragments/'));
|
|
82
|
+
if (hasFragments) {
|
|
83
|
+
// Fragment changed — purge everything (all pages use fragments)
|
|
84
|
+
await purge.purgeAll();
|
|
85
|
+
console.log(` ${targetName}: cache purged (all)`);
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
// Only pages changed — purge specific URLs
|
|
89
|
+
const site = await loadSite(siteDir, sourceStorage);
|
|
90
|
+
const urls = allItems
|
|
91
|
+
.filter(i => i.startsWith('pages/'))
|
|
92
|
+
.map(i => {
|
|
93
|
+
const page = site.pages.get(i.replace('pages/', ''));
|
|
94
|
+
return page ? `${config.siteUrl}${page.route}` : null;
|
|
95
|
+
})
|
|
96
|
+
.filter(Boolean);
|
|
97
|
+
if (urls.length > 0) {
|
|
98
|
+
await purge.purgeUrls(urls);
|
|
99
|
+
console.log(` ${targetName}: cache purged (${urls.join(', ')})`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
79
102
|
}
|
|
80
103
|
results.push({ target: targetName, success: true, copiedFiles: totalFiles });
|
|
81
104
|
console.log(` ${targetName}: ${totalFiles} files`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"publish.js","sourceRoot":"","sources":["../../../src/admin-api/routes/publish.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAE3B,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAA;AAEpE,OAAO,EAAE,mBAAmB,EAAE,uBAAuB,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,
|
|
1
|
+
{"version":3,"file":"publish.js","sourceRoot":"","sources":["../../../src/admin-api/routes/publish.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ESI assembly — pure string functions, no I/O, no platform deps.
|
|
3
|
+
* Used by edge workers and Node servers to compose pages from fragments.
|
|
4
|
+
*/
|
|
5
|
+
/** Parse and strip cache comment from page HTML */
|
|
6
|
+
export declare function parseCacheComment(html: string): {
|
|
7
|
+
html: string;
|
|
8
|
+
browser: number;
|
|
9
|
+
edge: number;
|
|
10
|
+
};
|
|
11
|
+
/** Split fragment HTML into head and body sections */
|
|
12
|
+
export declare function splitFragment(html: string): {
|
|
13
|
+
head: string;
|
|
14
|
+
body: string;
|
|
15
|
+
};
|
|
16
|
+
/** Find all ESI paths referenced in the page HTML */
|
|
17
|
+
export declare function findEsiPaths(html: string): string[];
|
|
18
|
+
/** Assemble page HTML with fragment head and body content */
|
|
19
|
+
export declare function assembleEsi(pageHtml: string, fragments: Map<string, {
|
|
20
|
+
head: string;
|
|
21
|
+
body: string;
|
|
22
|
+
}>): string;
|
|
23
|
+
//# sourceMappingURL=assemble.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assemble.d.ts","sourceRoot":"","sources":["../src/assemble.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,mDAAmD;AACnD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAQ/F;AAED,sDAAsD;AACtD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAY1E;AAED,qDAAqD;AACrD,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAMnD;AAED,6DAA6D;AAC7D,wBAAgB,WAAW,CACzB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,GACrD,MAAM,CA0DR"}
|
package/dist/assemble.js
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ESI assembly — pure string functions, no I/O, no platform deps.
|
|
3
|
+
* Used by edge workers and Node servers to compose pages from fragments.
|
|
4
|
+
*/
|
|
5
|
+
/** Parse and strip cache comment from page HTML */
|
|
6
|
+
export function parseCacheComment(html) {
|
|
7
|
+
const match = html.match(/^<!--cache:browser=(\d+),edge=(\d+)-->\n/);
|
|
8
|
+
if (!match)
|
|
9
|
+
return { html, browser: 0, edge: 86400 };
|
|
10
|
+
return {
|
|
11
|
+
html: html.slice(match[0].length),
|
|
12
|
+
browser: parseInt(match[1], 10),
|
|
13
|
+
edge: parseInt(match[2], 10),
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
/** Split fragment HTML into head and body sections */
|
|
17
|
+
export function splitFragment(html) {
|
|
18
|
+
const headStart = html.indexOf('<head>');
|
|
19
|
+
const headEnd = html.indexOf('</head>');
|
|
20
|
+
if (headStart === -1 || headEnd === -1) {
|
|
21
|
+
return { head: '', body: html };
|
|
22
|
+
}
|
|
23
|
+
return {
|
|
24
|
+
head: html.slice(headStart + 6, headEnd).trim(),
|
|
25
|
+
body: (html.slice(0, headStart) + html.slice(headEnd + 7)).trim(),
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
/** Find all ESI paths referenced in the page HTML */
|
|
29
|
+
export function findEsiPaths(html) {
|
|
30
|
+
const paths = new Set();
|
|
31
|
+
const regex = /<!--esi(?:-head)?:(\/[^>]+)-->/g;
|
|
32
|
+
let match;
|
|
33
|
+
while ((match = regex.exec(html)) !== null)
|
|
34
|
+
paths.add(match[1]);
|
|
35
|
+
return [...paths];
|
|
36
|
+
}
|
|
37
|
+
/** Assemble page HTML with fragment head and body content */
|
|
38
|
+
export function assembleEsi(pageHtml, fragments) {
|
|
39
|
+
const esiHeadRegex = /<!--esi-head:(\/[^>]+)-->/g;
|
|
40
|
+
const esiBodyRegex = /<!--esi:(\/[^>]+)-->/g;
|
|
41
|
+
// Collect ESI head order from page
|
|
42
|
+
const esiHeadOrder = [];
|
|
43
|
+
const esiHeadRegex2 = /<!--esi-head:(\/[^>]+)-->/g;
|
|
44
|
+
let m;
|
|
45
|
+
while ((m = esiHeadRegex2.exec(pageHtml)) !== null) {
|
|
46
|
+
if (!esiHeadOrder.includes(m[1]))
|
|
47
|
+
esiHeadOrder.push(m[1]);
|
|
48
|
+
}
|
|
49
|
+
// Collect CSS and JS separately, preserving fragment order, deduplicating
|
|
50
|
+
const cssLines = [];
|
|
51
|
+
const jsLines = [];
|
|
52
|
+
const otherLines = [];
|
|
53
|
+
const seen = new Set();
|
|
54
|
+
for (const path of esiHeadOrder) {
|
|
55
|
+
const frag = fragments.get(path);
|
|
56
|
+
if (!frag?.head)
|
|
57
|
+
continue;
|
|
58
|
+
for (const line of frag.head.split('\n').map(l => l.trim()).filter(Boolean)) {
|
|
59
|
+
if (seen.has(line))
|
|
60
|
+
continue;
|
|
61
|
+
seen.add(line);
|
|
62
|
+
if (line.includes('rel="stylesheet"') || line.includes("rel='stylesheet'")) {
|
|
63
|
+
cssLines.push(line);
|
|
64
|
+
}
|
|
65
|
+
else if (line.startsWith('<script')) {
|
|
66
|
+
jsLines.push(line);
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
otherLines.push(line);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// Replace first esi-head with other + CSS, remove the rest
|
|
74
|
+
let html = pageHtml;
|
|
75
|
+
const collectedCss = [...otherLines, ...cssLines].join('\n ');
|
|
76
|
+
let cssInserted = false;
|
|
77
|
+
html = html.replace(esiHeadRegex, () => {
|
|
78
|
+
if (!cssInserted && collectedCss) {
|
|
79
|
+
cssInserted = true;
|
|
80
|
+
return collectedCss;
|
|
81
|
+
}
|
|
82
|
+
return '';
|
|
83
|
+
});
|
|
84
|
+
// Insert JS before </head> (after all CSS, preserving fragment order)
|
|
85
|
+
if (jsLines.length > 0) {
|
|
86
|
+
html = html.replace('</head>', ` ${jsLines.join('\n ')}\n</head>`);
|
|
87
|
+
}
|
|
88
|
+
// Replace esi body tags with fragment body content
|
|
89
|
+
html = html.replace(esiBodyRegex, (_match, path) => {
|
|
90
|
+
const frag = fragments.get(path);
|
|
91
|
+
return frag?.body ?? `<!-- fragment not found: ${path} -->`;
|
|
92
|
+
});
|
|
93
|
+
return html;
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=assemble.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assemble.js","sourceRoot":"","sources":["../src/assemble.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,mDAAmD;AACnD,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,0CAA0C,CAAC,CAAA;IACpE,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAA;IACpD,OAAO;QACL,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;QACjC,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;QAC/B,IAAI,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;KAC7B,CAAA;AACH,CAAC;AAED,sDAAsD;AACtD,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;IACxC,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAA;IAEvC,IAAI,SAAS,KAAK,CAAC,CAAC,IAAI,OAAO,KAAK,CAAC,CAAC,EAAE,CAAC;QACvC,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAA;IACjC,CAAC;IAED,OAAO;QACL,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE;QAC/C,IAAI,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE;KAClE,CAAA;AACH,CAAC;AAED,qDAAqD;AACrD,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAA;IAC/B,MAAM,KAAK,GAAG,iCAAiC,CAAA;IAC/C,IAAI,KAAK,CAAA;IACT,OAAO,CAAC,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI;QAAE,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;IAC/D,OAAO,CAAC,GAAG,KAAK,CAAC,CAAA;AACnB,CAAC;AAED,6DAA6D;AAC7D,MAAM,UAAU,WAAW,CACzB,QAAgB,EAChB,SAAsD;IAEtD,MAAM,YAAY,GAAG,4BAA4B,CAAA;IACjD,MAAM,YAAY,GAAG,uBAAuB,CAAA;IAE5C,mCAAmC;IACnC,MAAM,YAAY,GAAa,EAAE,CAAA;IACjC,MAAM,aAAa,GAAG,4BAA4B,CAAA;IAClD,IAAI,CAAC,CAAA;IACL,OAAO,CAAC,CAAC,GAAG,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QACnD,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAAE,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;IAC3D,CAAC;IAED,0EAA0E;IAC1E,MAAM,QAAQ,GAAa,EAAE,CAAA;IAC7B,MAAM,OAAO,GAAa,EAAE,CAAA;IAC5B,MAAM,UAAU,GAAa,EAAE,CAAA;IAC/B,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAA;IAE9B,KAAK,MAAM,IAAI,IAAI,YAAY,EAAE,CAAC;QAChC,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;QAChC,IAAI,CAAC,IAAI,EAAE,IAAI;YAAE,SAAQ;QACzB,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;YAC5E,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;gBAAE,SAAQ;YAC5B,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;YACd,IAAI,IAAI,CAAC,QAAQ,CAAC,kBAAkB,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,kBAAkB,CAAC,EAAE,CAAC;gBAC3E,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YACrB,CAAC;iBAAM,IAAI,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;gBACtC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YACpB,CAAC;iBAAM,CAAC;gBACN,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YACvB,CAAC;QACH,CAAC;IACH,CAAC;IAED,2DAA2D;IAC3D,IAAI,IAAI,GAAG,QAAQ,CAAA;IACnB,MAAM,YAAY,GAAG,CAAC,GAAG,UAAU,EAAE,GAAG,QAAQ,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;IAC9D,IAAI,WAAW,GAAG,KAAK,CAAA;IACvB,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,GAAG,EAAE;QACrC,IAAI,CAAC,WAAW,IAAI,YAAY,EAAE,CAAC;YACjC,WAAW,GAAG,IAAI,CAAA;YAClB,OAAO,YAAY,CAAA;QACrB,CAAC;QACD,OAAO,EAAE,CAAA;IACX,CAAC,CAAC,CAAA;IAEF,sEAAsE;IACtE,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,CAAA;IACtE,CAAC;IAED,mDAAmD;IACnD,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC,MAAM,EAAE,IAAY,EAAE,EAAE;QACzD,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;QAChC,OAAO,IAAI,EAAE,IAAI,IAAI,4BAA4B,IAAI,MAAM,CAAA;IAC7D,CAAC,CAAC,CAAA;IAEF,OAAO,IAAI,CAAA;AACb,CAAC"}
|
package/dist/cli/index.js
CHANGED
|
@@ -22,30 +22,40 @@ function printHelp() {
|
|
|
22
22
|
Usage:
|
|
23
23
|
gazetta init [dir] Create a new site
|
|
24
24
|
gazetta dev [site-dir] Start dev server + CMS at /admin
|
|
25
|
+
gazetta publish [site-dir] Pre-render and publish to targets
|
|
26
|
+
gazetta deploy -t <name> Deploy worker to hosting (one-time setup)
|
|
27
|
+
gazetta validate [site-dir] Check site for broken references
|
|
25
28
|
gazetta help Show this help message
|
|
26
29
|
|
|
27
30
|
Options:
|
|
28
31
|
--port, -p <port> Server port (default: 3000)
|
|
32
|
+
--target, -t <name> Target to publish/deploy to (default: all)
|
|
29
33
|
|
|
30
34
|
Examples:
|
|
31
35
|
gazetta init my-site # scaffold a new site
|
|
32
36
|
gazetta dev # dev server + CMS
|
|
33
|
-
gazetta
|
|
34
|
-
gazetta
|
|
37
|
+
gazetta publish # publish to all targets
|
|
38
|
+
gazetta publish -t production # publish to specific target
|
|
39
|
+
gazetta deploy -t production # deploy worker (one-time)
|
|
40
|
+
gazetta validate # check site for broken references
|
|
35
41
|
`);
|
|
36
42
|
}
|
|
37
43
|
function parseArgs(input) {
|
|
38
44
|
let siteDir = '.';
|
|
39
45
|
let port;
|
|
46
|
+
let target;
|
|
40
47
|
for (let i = 0; i < input.length; i++) {
|
|
41
48
|
if (input[i] === '--port' || input[i] === '-p') {
|
|
42
49
|
port = parseInt(input[++i], 10);
|
|
43
50
|
}
|
|
51
|
+
else if (input[i] === '--target' || input[i] === '-t') {
|
|
52
|
+
target = input[++i];
|
|
53
|
+
}
|
|
44
54
|
else if (!input[i].startsWith('-')) {
|
|
45
55
|
siteDir = input[i];
|
|
46
56
|
}
|
|
47
57
|
}
|
|
48
|
-
return { siteDir: resolve(siteDir), port };
|
|
58
|
+
return { siteDir: resolve(siteDir), port, target };
|
|
49
59
|
}
|
|
50
60
|
async function runInit(dir) {
|
|
51
61
|
const { writeFile, mkdir } = await import('node:fs/promises');
|
|
@@ -67,6 +77,8 @@ const template: TemplateFunction = ({ children = [] }) => ({
|
|
|
67
77
|
css: \`main { max-width: 800px; margin: 0 auto; padding: 2rem; font-family: system-ui, sans-serif; }
|
|
68
78
|
\${children.map(c => c.css).join('\\n')}\`,
|
|
69
79
|
js: children.map(c => c.js).filter(Boolean).join('\\n'),
|
|
80
|
+
head: \`<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>⚡</text></svg>">
|
|
81
|
+
\${children.map(c => c.head).filter(Boolean).join('\\n')}\`,
|
|
70
82
|
})
|
|
71
83
|
|
|
72
84
|
export default template
|
|
@@ -183,6 +195,254 @@ content:
|
|
|
183
195
|
console.log(` npx gazetta dev`);
|
|
184
196
|
console.log();
|
|
185
197
|
}
|
|
198
|
+
async function runPublish(siteDir, targetName) {
|
|
199
|
+
const storage = createFilesystemProvider();
|
|
200
|
+
console.log(`\n Loading site from ${siteDir}...`);
|
|
201
|
+
const site = await loadSite(siteDir, storage);
|
|
202
|
+
// Load target configs from site.yaml
|
|
203
|
+
const siteYamlPath = join(siteDir, 'site.yaml');
|
|
204
|
+
if (!existsSync(siteYamlPath)) {
|
|
205
|
+
console.error(`\n Error: No site.yaml found at ${siteDir}\n`);
|
|
206
|
+
process.exit(1);
|
|
207
|
+
}
|
|
208
|
+
const siteYaml = yaml.load(readFileSync(siteYamlPath, 'utf-8'));
|
|
209
|
+
if (!siteYaml.targets || Object.keys(siteYaml.targets).length === 0) {
|
|
210
|
+
console.error(`\n Error: No targets configured in site.yaml\n`);
|
|
211
|
+
process.exit(1);
|
|
212
|
+
}
|
|
213
|
+
// Determine which targets to publish to
|
|
214
|
+
const targetNames = targetName ? [targetName] : Object.keys(siteYaml.targets);
|
|
215
|
+
for (const name of targetNames) {
|
|
216
|
+
if (!siteYaml.targets[name]) {
|
|
217
|
+
console.error(`\n Error: Unknown target "${name}". Available: ${Object.keys(siteYaml.targets).join(', ')}\n`);
|
|
218
|
+
process.exit(1);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
// Initialize targets
|
|
222
|
+
const { createTargetRegistry } = await import('../targets.js');
|
|
223
|
+
const targets = await createTargetRegistry(Object.fromEntries(targetNames.map(n => [n, siteYaml.targets[n]])), siteDir);
|
|
224
|
+
const { publishPageRendered, publishFragmentRendered, publishSiteManifest, publishFragmentIndex } = await import('../publish-rendered.js');
|
|
225
|
+
console.log(`\n Site: ${site.manifest.name}`);
|
|
226
|
+
console.log(` Pages: ${[...site.pages.keys()].join(', ')}`);
|
|
227
|
+
console.log(` Fragments: ${[...site.fragments.keys()].join(', ')}`);
|
|
228
|
+
console.log(` Targets: ${targetNames.join(', ')}\n`);
|
|
229
|
+
for (const name of targetNames) {
|
|
230
|
+
const targetStorage = targets.get(name);
|
|
231
|
+
if (!targetStorage) {
|
|
232
|
+
console.error(` ${name}: SKIPPED (failed to initialize)`);
|
|
233
|
+
continue;
|
|
234
|
+
}
|
|
235
|
+
console.log(` Publishing to ${name}...`);
|
|
236
|
+
let totalFiles = 0;
|
|
237
|
+
// Publish all fragments
|
|
238
|
+
for (const fragName of site.fragments.keys()) {
|
|
239
|
+
const { files } = await publishFragmentRendered(fragName, storage, siteDir, targetStorage);
|
|
240
|
+
totalFiles += files;
|
|
241
|
+
console.log(` fragment: ${fragName} (${files} files)`);
|
|
242
|
+
}
|
|
243
|
+
// Publish all pages
|
|
244
|
+
for (const pageName of site.pages.keys()) {
|
|
245
|
+
const { files } = await publishPageRendered(pageName, storage, siteDir, targetStorage, siteYaml.targets[name]?.cache);
|
|
246
|
+
totalFiles += files;
|
|
247
|
+
console.log(` page: ${pageName} (${files} files)`);
|
|
248
|
+
}
|
|
249
|
+
// Site manifest + fragment index
|
|
250
|
+
await publishSiteManifest(storage, siteDir, targetStorage);
|
|
251
|
+
await publishFragmentIndex(storage, siteDir, targetStorage);
|
|
252
|
+
totalFiles += 2;
|
|
253
|
+
console.log(` ${name}: ${totalFiles} files published\n`);
|
|
254
|
+
}
|
|
255
|
+
// Purge cache once at the end (all targets)
|
|
256
|
+
const zoneId = process.env.CF_ZONE_ID;
|
|
257
|
+
const apiToken = process.env.CF_API_TOKEN;
|
|
258
|
+
if (zoneId && apiToken) {
|
|
259
|
+
const { createCloudflarePurge } = await import('../publish-rendered.js');
|
|
260
|
+
const purge = createCloudflarePurge(zoneId, apiToken);
|
|
261
|
+
await purge.purgeAll();
|
|
262
|
+
console.log(` Cache purged\n`);
|
|
263
|
+
}
|
|
264
|
+
console.log(` Done!\n`);
|
|
265
|
+
}
|
|
266
|
+
async function runDeploy(siteDir, targetName) {
|
|
267
|
+
const { execSync } = await import('node:child_process');
|
|
268
|
+
const { writeFile, mkdir, rm } = await import('node:fs/promises');
|
|
269
|
+
const siteYamlPath = join(siteDir, 'site.yaml');
|
|
270
|
+
if (!existsSync(siteYamlPath)) {
|
|
271
|
+
console.error(`\n Error: No site.yaml found at ${siteDir}\n`);
|
|
272
|
+
process.exit(1);
|
|
273
|
+
}
|
|
274
|
+
const siteYaml = yaml.load(readFileSync(siteYamlPath, 'utf-8'));
|
|
275
|
+
if (!siteYaml.targets) {
|
|
276
|
+
console.error(`\n Error: No targets configured in site.yaml\n`);
|
|
277
|
+
process.exit(1);
|
|
278
|
+
}
|
|
279
|
+
if (!targetName) {
|
|
280
|
+
console.error(`\n Error: --target is required for deploy\n Usage: gazetta deploy -t <target-name>\n`);
|
|
281
|
+
process.exit(1);
|
|
282
|
+
}
|
|
283
|
+
const target = siteYaml.targets[targetName];
|
|
284
|
+
if (!target) {
|
|
285
|
+
console.error(`\n Error: Unknown target "${targetName}". Available: ${Object.keys(siteYaml.targets).join(', ')}\n`);
|
|
286
|
+
process.exit(1);
|
|
287
|
+
}
|
|
288
|
+
if (!target.worker) {
|
|
289
|
+
console.error(`\n Error: Target "${targetName}" has no worker config. Add to site.yaml:\n\n worker:\n type: cloudflare\n name: my-site\n`);
|
|
290
|
+
process.exit(1);
|
|
291
|
+
}
|
|
292
|
+
if (target.worker.type !== 'cloudflare') {
|
|
293
|
+
console.error(`\n Error: Unsupported worker type "${target.worker.type}". Currently only "cloudflare" is supported.\n`);
|
|
294
|
+
process.exit(1);
|
|
295
|
+
}
|
|
296
|
+
// Generate worker in temp dir
|
|
297
|
+
const workerName = target.worker.name ?? targetName;
|
|
298
|
+
const bucketName = target.storage.bucket ?? workerName;
|
|
299
|
+
const tmpDir = join(siteDir, '.gazetta-deploy');
|
|
300
|
+
await rm(tmpDir, { recursive: true, force: true });
|
|
301
|
+
await mkdir(tmpDir, { recursive: true });
|
|
302
|
+
// Generate wrangler.toml
|
|
303
|
+
let wranglerToml = `name = "${workerName}"\nmain = "index.ts"\ncompatibility_date = "2024-12-01"\nworkers_dev = true\n\n[[r2_buckets]]\nbinding = "SITE_BUCKET"\nbucket_name = "${bucketName}"\n`;
|
|
304
|
+
// Add custom domain route if siteUrl is configured
|
|
305
|
+
if (target.siteUrl) {
|
|
306
|
+
const url = new URL(target.siteUrl);
|
|
307
|
+
const hostname = url.hostname;
|
|
308
|
+
wranglerToml += `\n[[routes]]\npattern = "${hostname}/*"\nzone_name = "${hostname}"\n`;
|
|
309
|
+
}
|
|
310
|
+
await writeFile(join(tmpDir, 'wrangler.toml'), wranglerToml);
|
|
311
|
+
// Generate worker entry point
|
|
312
|
+
const workerCode = `import { createWorker } from 'gazetta/workers/cloudflare-r2'\nexport default createWorker()\n`;
|
|
313
|
+
await writeFile(join(tmpDir, 'index.ts'), workerCode);
|
|
314
|
+
// Generate package.json for wrangler
|
|
315
|
+
const pkgJson = JSON.stringify({
|
|
316
|
+
type: 'module',
|
|
317
|
+
dependencies: { gazetta: '*', hono: '*' },
|
|
318
|
+
});
|
|
319
|
+
await writeFile(join(tmpDir, 'package.json'), pkgJson);
|
|
320
|
+
// Install deps and deploy
|
|
321
|
+
console.log(` Deploying worker "${workerName}" to Cloudflare...`);
|
|
322
|
+
try {
|
|
323
|
+
execSync('npm install --install-links ' + resolve(import.meta.dirname, '../..'), { cwd: tmpDir, stdio: 'pipe' });
|
|
324
|
+
const output = execSync('npx wrangler deploy', { cwd: tmpDir, stdio: 'pipe' }).toString();
|
|
325
|
+
const urlMatch = output.match(/https:\/\/[^\s]+/);
|
|
326
|
+
console.log(` Worker deployed: ${urlMatch?.[0] ?? workerName}`);
|
|
327
|
+
if (target.siteUrl)
|
|
328
|
+
console.log(` Site: ${target.siteUrl}`);
|
|
329
|
+
}
|
|
330
|
+
catch (err) {
|
|
331
|
+
const stderr = err.stderr?.toString() ?? err.message;
|
|
332
|
+
console.error(`\n Deploy failed: ${stderr}\n`);
|
|
333
|
+
process.exit(1);
|
|
334
|
+
}
|
|
335
|
+
finally {
|
|
336
|
+
await rm(tmpDir, { recursive: true, force: true });
|
|
337
|
+
}
|
|
338
|
+
console.log(`\n Worker deployed. Now publish content:\n gazetta publish -t ${targetName}\n`);
|
|
339
|
+
}
|
|
340
|
+
async function runValidate(siteDir) {
|
|
341
|
+
const storage = createFilesystemProvider();
|
|
342
|
+
console.log(`\n Validating ${siteDir}...\n`);
|
|
343
|
+
// 1. Check site.yaml
|
|
344
|
+
let site;
|
|
345
|
+
try {
|
|
346
|
+
site = await loadSite(siteDir, storage);
|
|
347
|
+
console.log(` ✓ site.yaml — ${site.manifest.name}`);
|
|
348
|
+
}
|
|
349
|
+
catch (err) {
|
|
350
|
+
console.error(` ✗ site.yaml — ${err.message}`);
|
|
351
|
+
process.exit(1);
|
|
352
|
+
}
|
|
353
|
+
let errors = 0;
|
|
354
|
+
// 2. Validate all fragments
|
|
355
|
+
for (const [fragName, frag] of site.fragments) {
|
|
356
|
+
try {
|
|
357
|
+
const { resolveComponent } = await import('../resolver.js');
|
|
358
|
+
const templatesDir = join(siteDir, 'templates');
|
|
359
|
+
const ctx = { site, templatesDir, visited: new Set(), path: [`@${fragName}`] };
|
|
360
|
+
await resolveComponent(`@${fragName}`, '', ctx);
|
|
361
|
+
const childCount = frag.components?.length ?? 0;
|
|
362
|
+
console.log(` ✓ fragment: ${fragName} (${childCount} components)`);
|
|
363
|
+
}
|
|
364
|
+
catch (err) {
|
|
365
|
+
console.error(` ✗ fragment: ${fragName} — ${err.message}`);
|
|
366
|
+
errors++;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
// 3. Validate all pages
|
|
370
|
+
for (const [pageName, page] of site.pages) {
|
|
371
|
+
try {
|
|
372
|
+
await resolvePage(pageName, site);
|
|
373
|
+
const componentCount = page.components?.length ?? 0;
|
|
374
|
+
const fragmentCount = page.components?.filter(c => c.startsWith('@')).length ?? 0;
|
|
375
|
+
console.log(` ✓ page: ${pageName} (${componentCount} components, ${fragmentCount} fragments)`);
|
|
376
|
+
}
|
|
377
|
+
catch (err) {
|
|
378
|
+
console.error(` ✗ page: ${pageName} — ${err.message}`);
|
|
379
|
+
errors++;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
// 4. List templates
|
|
383
|
+
const templatesDir = join(siteDir, 'templates');
|
|
384
|
+
try {
|
|
385
|
+
const entries = await storage.readDir(templatesDir);
|
|
386
|
+
const templateCount = entries.filter(e => e.isDirectory).length;
|
|
387
|
+
console.log(` ✓ ${templateCount} templates found`);
|
|
388
|
+
}
|
|
389
|
+
catch {
|
|
390
|
+
console.log(` ⚠ templates/ directory not found`);
|
|
391
|
+
}
|
|
392
|
+
console.log();
|
|
393
|
+
if (errors > 0) {
|
|
394
|
+
console.error(` ${errors} error${errors > 1 ? 's' : ''} found.\n`);
|
|
395
|
+
process.exit(1);
|
|
396
|
+
}
|
|
397
|
+
else {
|
|
398
|
+
console.log(` All good.\n`);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
function renderErrorOverlay(err) {
|
|
402
|
+
const message = err.message.replace(/</g, '<').replace(/>/g, '>');
|
|
403
|
+
const stack = (err.stack ?? '').replace(/</g, '<').replace(/>/g, '>');
|
|
404
|
+
// Extract file path from error message or stack
|
|
405
|
+
const fileMatch = stack.match(/\(?(\/[^\s:)]+):(\d+)/);
|
|
406
|
+
const filePath = fileMatch ? fileMatch[1] : '';
|
|
407
|
+
const lineNum = fileMatch ? fileMatch[2] : '';
|
|
408
|
+
const location = filePath ? `${filePath}${lineNum ? `:${lineNum}` : ''}` : '';
|
|
409
|
+
return `<!DOCTYPE html>
|
|
410
|
+
<html>
|
|
411
|
+
<head>
|
|
412
|
+
<meta charset="UTF-8">
|
|
413
|
+
<title>Error — Gazetta</title>
|
|
414
|
+
<style>
|
|
415
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
416
|
+
body { font-family: system-ui, -apple-system, sans-serif; background: #1a1a2e; color: #e4e4e7; min-height: 100vh; display: flex; align-items: center; justify-content: center; }
|
|
417
|
+
.overlay { max-width: 48rem; width: 100%; margin: 2rem; }
|
|
418
|
+
.header { display: flex; align-items: center; gap: 0.75rem; margin-bottom: 1.5rem; }
|
|
419
|
+
.header svg { flex-shrink: 0; }
|
|
420
|
+
.header h1 { font-size: 1.25rem; font-weight: 600; color: #f87171; }
|
|
421
|
+
.message { background: #0f0f1a; border: 1px solid #27272a; border-radius: 8px; padding: 1.5rem; margin-bottom: 1rem; font-family: 'JetBrains Mono', 'Fira Code', monospace; font-size: 0.875rem; line-height: 1.7; white-space: pre-wrap; word-break: break-word; color: #fca5a5; }
|
|
422
|
+
.location { font-size: 0.8125rem; color: #71717a; margin-bottom: 1rem; }
|
|
423
|
+
.location span { color: #a78bfa; }
|
|
424
|
+
.stack { background: #0f0f1a; border: 1px solid #27272a; border-radius: 8px; padding: 1.5rem; font-family: 'JetBrains Mono', 'Fira Code', monospace; font-size: 0.75rem; line-height: 1.7; white-space: pre-wrap; word-break: break-word; color: #52525b; max-height: 20rem; overflow: auto; }
|
|
425
|
+
.hint { margin-top: 1.5rem; font-size: 0.8125rem; color: #52525b; }
|
|
426
|
+
</style>
|
|
427
|
+
</head>
|
|
428
|
+
<body>
|
|
429
|
+
<div class="overlay">
|
|
430
|
+
<div class="header">
|
|
431
|
+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#f87171" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>
|
|
432
|
+
<h1>Template Error</h1>
|
|
433
|
+
</div>
|
|
434
|
+
${location ? `<div class="location">File: <span>${location}</span></div>` : ''}
|
|
435
|
+
<div class="message">${message}</div>
|
|
436
|
+
<details>
|
|
437
|
+
<summary style="color:#52525b;font-size:0.8125rem;cursor:pointer;margin-bottom:0.5rem">Stack trace</summary>
|
|
438
|
+
<div class="stack">${stack}</div>
|
|
439
|
+
</details>
|
|
440
|
+
<div class="hint">Fix the error and save — the page will reload automatically.</div>
|
|
441
|
+
</div>
|
|
442
|
+
<script>new EventSource('/__reload').onmessage = () => location.reload()</script>
|
|
443
|
+
</body>
|
|
444
|
+
</html>`;
|
|
445
|
+
}
|
|
186
446
|
async function runDev(siteDir, port) {
|
|
187
447
|
const storage = createFilesystemProvider();
|
|
188
448
|
console.log(`\n Loading site from ${siteDir}...`);
|
|
@@ -221,7 +481,7 @@ async function runDev(siteDir, port) {
|
|
|
221
481
|
return c.html(html.replace('</body>', `${RELOAD_SCRIPT}\n</body>`));
|
|
222
482
|
}
|
|
223
483
|
catch (err) {
|
|
224
|
-
return c.html(
|
|
484
|
+
return c.html(renderErrorOverlay(err), 500);
|
|
225
485
|
}
|
|
226
486
|
});
|
|
227
487
|
}
|
|
@@ -424,6 +684,15 @@ async function main() {
|
|
|
424
684
|
case 'init':
|
|
425
685
|
await runInit(args[1] ?? '.');
|
|
426
686
|
break;
|
|
687
|
+
case 'publish':
|
|
688
|
+
await runPublish(parsed.siteDir, parsed.target);
|
|
689
|
+
break;
|
|
690
|
+
case 'deploy':
|
|
691
|
+
await runDeploy(parsed.siteDir, parsed.target);
|
|
692
|
+
break;
|
|
693
|
+
case 'validate':
|
|
694
|
+
await runValidate(parsed.siteDir);
|
|
695
|
+
break;
|
|
427
696
|
case 'dev':
|
|
428
697
|
await runDev(parsed.siteDir, parsed.port ?? 3000);
|
|
429
698
|
break;
|