@brightsideoy/kama 0.1.0-alpha.155 → 0.1.0-alpha.157
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 +229 -231
- package/dist/assets/index-BesA3e7A.js +164 -0
- package/dist/assets/index-D6yHZ_u1.css +1 -0
- package/dist/{dist-C-WAK7EF.js → dist-mic4UZBb.js} +691 -439
- package/dist/index.html +2 -2
- package/dist/index.js +693 -439
- package/dist/schema-compiler.js +1 -1
- package/package.json +1 -1
- package/schema.sql +2 -2
- package/templates/astro-starter/src/components/blocks/BlockRenderer.astro +1 -0
- package/templates/astro-starter/src/components/blocks/ColumnLayout.astro +1 -0
- package/templates/astro-starter/src/components/blocks/HeaderImage.astro +1 -0
- package/templates/astro-starter/src/components/blocks/HtmlBlock.astro +2 -1
- package/templates/astro-starter/src/components/blocks/ImageBlock.astro +39 -71
- package/templates/astro-starter/src/components/blocks/TextBlock.astro +2 -0
- package/templates/astro-starter/src/components/global/Breadcrumb.astro +2 -0
- package/templates/astro-starter/src/components/global/Footer.astro +2 -0
- package/templates/astro-starter/src/components/global/Header.astro +100 -28
- package/templates/astro-starter/src/components/{seo/SeoHead.astro → global/MetaHead.astro} +101 -49
- package/templates/astro-starter/src/components/global/NavigationMenu.astro +1 -0
- package/templates/astro-starter/src/components/ui/KamaImage.astro +114 -67
- package/templates/astro-starter/src/layouts/SkeletonLayout.astro +5 -3
- package/templates/astro-starter/src/layouts/StandardLayout.astro +14 -5
- package/templates/astro-starter/src/lib/cms.ts +48 -0
- package/templates/astro-starter/src/lib/media/kama-image-service.ts +16 -1
- package/templates/astro-starter/src/lib/media/media-proxy.ts +8 -6
- package/templates/astro-starter/src/lib/media/media-url.ts +65 -1
- package/templates/astro-starter/src/middleware.ts +131 -18
- package/templates/astro-starter/src/pages/[...slug].astro +10 -9
- package/definitions/_page.yaml +0 -52
- package/dist/assets/index-DGHRgyms.js +0 -164
- package/dist/assets/index-EaDn3OUJ.css +0 -1
- /package/templates/astro-starter/{public/css → src/styles}/standard-theme.css +0 -0
|
@@ -1,13 +1,121 @@
|
|
|
1
|
+
// src/middleware.ts
|
|
2
|
+
|
|
1
3
|
import { defineMiddleware } from "astro:middleware";
|
|
2
|
-
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Safely extracts environment variables across Astro 7, Node.js, and Cloudflare Workers
|
|
7
|
+
* without triggering the `@astrojs/cloudflare` runtime.env getter exception.
|
|
8
|
+
*/
|
|
9
|
+
async function getSafeEnv(locals: any): Promise<Record<string, any>> {
|
|
10
|
+
// 1. Try native Cloudflare Workers module (Astro 5+ / workerd)
|
|
11
|
+
try {
|
|
12
|
+
// @ts-ignore
|
|
13
|
+
const cf = await import("cloudflare:workers");
|
|
14
|
+
if (cf?.env) return cf.env;
|
|
15
|
+
} catch (e) {
|
|
16
|
+
// Not running inside a Cloudflare Worker container
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// 2. Safe check for locals.runtime / cfContext (Local Node.js / Hono)
|
|
20
|
+
const runtime = locals?.runtime || locals?.cfContext;
|
|
21
|
+
if (runtime && typeof runtime === "object") {
|
|
22
|
+
if ("CMS_WORKER" in runtime || "PUBLIC_API_URL" in runtime) {
|
|
23
|
+
return runtime;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Safely check property descriptor to avoid triggering throwing getters
|
|
27
|
+
try {
|
|
28
|
+
const desc = Object.getOwnPropertyDescriptor(runtime, "env");
|
|
29
|
+
if (desc && !desc.get) {
|
|
30
|
+
return runtime.env;
|
|
31
|
+
}
|
|
32
|
+
} catch (e) {
|
|
33
|
+
// Ignore getter throws
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// 3. Fallback for standalone Node.js mode
|
|
38
|
+
return typeof process !== "undefined" ? process.env || {} : {};
|
|
39
|
+
}
|
|
3
40
|
|
|
4
41
|
export const onRequest = defineMiddleware(async (context, next) => {
|
|
5
42
|
const pathname = context.url.pathname;
|
|
6
|
-
const
|
|
7
|
-
|
|
43
|
+
const pathLower = pathname.toLowerCase();
|
|
44
|
+
|
|
45
|
+
// 🎯 Detect Local Vite Dev Mode to bypass edge caching locally
|
|
46
|
+
const isDev = import.meta.env.DEV;
|
|
47
|
+
|
|
48
|
+
// 🎯 Safe dual-environment context extraction
|
|
49
|
+
const workerEnv = await getSafeEnv(context.locals);
|
|
50
|
+
|
|
51
|
+
// Attach to locals so Astro components (like Header.astro) don't have to re-evaluate it
|
|
52
|
+
(context.locals as any).safeEnv = workerEnv;
|
|
53
|
+
|
|
54
|
+
// 🎯 Safe ctx extraction (Fixing the runtime.ctx crash in Astro 6/7)
|
|
55
|
+
let cfContext = (context.locals as any).cfContext;
|
|
56
|
+
if (!cfContext) {
|
|
57
|
+
const runtime = (context.locals as any).runtime;
|
|
58
|
+
if (runtime && typeof runtime === "object") {
|
|
59
|
+
try {
|
|
60
|
+
const desc = Object.getOwnPropertyDescriptor(runtime, "ctx");
|
|
61
|
+
if (desc && !desc.get) {
|
|
62
|
+
cfContext = runtime.ctx;
|
|
63
|
+
}
|
|
64
|
+
} catch (e) { }
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
cfContext = cfContext || {};
|
|
68
|
+
|
|
8
69
|
const HTML_CACHE = workerEnv?.HTML_CACHE; // KV Namespace binding
|
|
9
70
|
|
|
10
|
-
// 🎯 0.
|
|
71
|
+
// 🎯 0. INSTANT EDGE SPAM DROP (Blocks bots before hit to CMS worker/database)
|
|
72
|
+
const isSpam =
|
|
73
|
+
pathLower.includes("wp-") ||
|
|
74
|
+
pathLower.includes("wordpress") ||
|
|
75
|
+
pathLower.endsWith(".php") ||
|
|
76
|
+
pathLower === "/wp";
|
|
77
|
+
|
|
78
|
+
if (isSpam) {
|
|
79
|
+
return new Response("Not Found", { status: 404 });
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// 🎯 0B. DIRECT MEDIA PROXY VIA SERVICE BINDING
|
|
83
|
+
if (pathname.startsWith("/media/")) {
|
|
84
|
+
const cmsWorker = workerEnv?.CMS_WORKER;
|
|
85
|
+
const envApiUrl = import.meta.env?.PUBLIC_API_URL;
|
|
86
|
+
const workerApiUrl = workerEnv?.PUBLIC_API_URL;
|
|
87
|
+
const baseApiUrl = String(envApiUrl || workerApiUrl || "https://kama.kamaengine.com");
|
|
88
|
+
const cleanApiUrl = baseApiUrl.endsWith("/") ? baseApiUrl.slice(0, -1) : baseApiUrl;
|
|
89
|
+
|
|
90
|
+
const mediaUrl = `${cleanApiUrl}${pathname}${context.url.search}`;
|
|
91
|
+
const mediaReq = new Request(mediaUrl, {
|
|
92
|
+
headers: context.request.headers
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
let mediaResponse: Response;
|
|
96
|
+
|
|
97
|
+
if (cmsWorker && typeof cmsWorker.fetch === "function") {
|
|
98
|
+
mediaResponse = await cmsWorker.fetch(mediaReq);
|
|
99
|
+
} else {
|
|
100
|
+
mediaResponse = await fetch(mediaReq);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const newHeaders = new Headers(mediaResponse.headers);
|
|
104
|
+
|
|
105
|
+
// 🎯 DEV FIX: Only apply 1-year cache on media in Production
|
|
106
|
+
if (!isDev) {
|
|
107
|
+
newHeaders.set("Cache-Control", "public, max-age=31536000, s-maxage=31536000, immutable");
|
|
108
|
+
}
|
|
109
|
+
newHeaders.set("Access-Control-Allow-Origin", "*");
|
|
110
|
+
|
|
111
|
+
return new Response(mediaResponse.body, {
|
|
112
|
+
status: mediaResponse.status,
|
|
113
|
+
statusText: mediaResponse.statusText,
|
|
114
|
+
headers: newHeaders
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// 🎯 0C. DIRECT EDGE INTERCEPT FOR CACHE PURGE ENDPOINT
|
|
11
119
|
if (pathname === "/api/purge" || pathname === "/api/purge/") {
|
|
12
120
|
if (context.request.method !== "POST") {
|
|
13
121
|
return new Response(JSON.stringify({ error: "Method Not Allowed" }), {
|
|
@@ -187,7 +295,8 @@ export const onRequest = defineMiddleware(async (context, next) => {
|
|
|
187
295
|
|
|
188
296
|
let activeCacheKey = cleanLookupPath;
|
|
189
297
|
|
|
190
|
-
|
|
298
|
+
// 🎯 DEV FIX: Bypass KV Read in local dev
|
|
299
|
+
if (!isDev && isHtmlPage && HTML_CACHE && !isWarmer) {
|
|
191
300
|
try {
|
|
192
301
|
const [siteVer, pageVer] = await Promise.all([
|
|
193
302
|
HTML_CACHE.get("site_version"),
|
|
@@ -217,7 +326,9 @@ export const onRequest = defineMiddleware(async (context, next) => {
|
|
|
217
326
|
const response = await next();
|
|
218
327
|
|
|
219
328
|
// 🎯 2. KV STATIC "FILE" CACHE WRITE (Save HTML under active Version Key)
|
|
329
|
+
// 🎯 DEV FIX: Bypass KV Write in local dev
|
|
220
330
|
if (
|
|
331
|
+
!isDev &&
|
|
221
332
|
isHtmlPage &&
|
|
222
333
|
HTML_CACHE &&
|
|
223
334
|
response.status === 200 &&
|
|
@@ -262,19 +373,21 @@ export const onRequest = defineMiddleware(async (context, next) => {
|
|
|
262
373
|
return response;
|
|
263
374
|
}
|
|
264
375
|
|
|
265
|
-
// 🎯 4.
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
376
|
+
// 🎯 4. STATIC ASSET CACHING FOR COMPRESSED BUNDLES / ASSETS
|
|
377
|
+
// 🎯 DEV FIX: Do not apply max-age=31536000 locally to prevent breaking Vite HMR
|
|
378
|
+
if (!isDev) {
|
|
379
|
+
if (
|
|
380
|
+
pathname.startsWith("/_image") ||
|
|
381
|
+
pathname.startsWith("/cdn-cgi/image/") ||
|
|
382
|
+
pathname.match(/\.(png|jpg|jpeg|webp|avif|svg|gif|ico|woff2?|css|js)$/i)
|
|
383
|
+
) {
|
|
384
|
+
response.headers.set(
|
|
385
|
+
"Cache-Control",
|
|
386
|
+
"public, max-age=31536000, s-maxage=31536000, immutable"
|
|
387
|
+
);
|
|
388
|
+
response.headers.set("Access-Control-Allow-Origin", "*");
|
|
389
|
+
return response;
|
|
390
|
+
}
|
|
278
391
|
}
|
|
279
392
|
|
|
280
393
|
// 🎯 5. SECURITY HEADERS FOR HTML PAGES
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
---
|
|
2
|
+
// src/pages/[...slug].astro
|
|
3
|
+
|
|
2
4
|
import StandardLayout from "../layouts/StandardLayout.astro";
|
|
3
5
|
import SkeletonLayout from "../layouts/SkeletonLayout.astro";
|
|
4
6
|
import BlockRenderer from "../components/blocks/BlockRenderer.astro";
|
|
@@ -6,9 +8,6 @@ import Breadcrumb from "../components/global/Breadcrumb.astro";
|
|
|
6
8
|
import { getNodeByPath, getChannelId, getTree, getTreeId } from "../lib/cms";
|
|
7
9
|
import type { NodeResponse, TreeNode } from "../lib/cms";
|
|
8
10
|
|
|
9
|
-
// 🎯 Import environment variables directly from Cloudflare
|
|
10
|
-
import { env } from "cloudflare:workers";
|
|
11
|
-
|
|
12
11
|
export const prerender = false;
|
|
13
12
|
|
|
14
13
|
const { slug } = Astro.params;
|
|
@@ -47,17 +46,18 @@ if (isStaticAsset) {
|
|
|
47
46
|
return new Response(null, { status: 404 });
|
|
48
47
|
}
|
|
49
48
|
|
|
50
|
-
// 2. ENV & WORKER RESOLUTION
|
|
51
|
-
|
|
52
|
-
const
|
|
49
|
+
// 2. ENV & WORKER RESOLUTION (Safe Dual-Environment)
|
|
50
|
+
// 🎯 Replaced throwing runtime getter with safeEnv from middleware
|
|
51
|
+
const safeEnv = (Astro.locals as any).safeEnv || {};
|
|
52
|
+
const cmsWorker = safeEnv.CMS_WORKER;
|
|
53
53
|
|
|
54
54
|
// Extract environment configuration & fallback slug
|
|
55
55
|
const envHomeSlug = import.meta.env.PUBLIC_HOME_SLUG;
|
|
56
|
-
const workerHomeSlug =
|
|
56
|
+
const workerHomeSlug = safeEnv.PUBLIC_HOME_SLUG;
|
|
57
57
|
const homeSlug = String(envHomeSlug || workerHomeSlug || "home").trim();
|
|
58
58
|
|
|
59
59
|
const envApiUrl = import.meta.env.PUBLIC_API_URL;
|
|
60
|
-
const workerApiUrl =
|
|
60
|
+
const workerApiUrl = safeEnv.PUBLIC_API_URL;
|
|
61
61
|
const baseApiUrl = String(
|
|
62
62
|
envApiUrl || workerApiUrl || "https://admin.kamaengine.com",
|
|
63
63
|
);
|
|
@@ -93,7 +93,6 @@ const customFetch = async (input: RequestInfo | URL, init?: RequestInit) => {
|
|
|
93
93
|
const fetchOpts: RequestInit = {
|
|
94
94
|
...init,
|
|
95
95
|
headers: reqHeaders,
|
|
96
|
-
cache: "no-store",
|
|
97
96
|
};
|
|
98
97
|
|
|
99
98
|
const req = new Request(urlStr, fetchOpts);
|
|
@@ -172,6 +171,7 @@ const isSkeleton = node?.nodeType === "page-skeleton";
|
|
|
172
171
|
<SkeletonLayout
|
|
173
172
|
node={node}
|
|
174
173
|
content={content}
|
|
174
|
+
language={pageData?.language}
|
|
175
175
|
normalizedSlug={normalizedSlug}
|
|
176
176
|
isHomePage={isHomePage}
|
|
177
177
|
>
|
|
@@ -181,6 +181,7 @@ const isSkeleton = node?.nodeType === "page-skeleton";
|
|
|
181
181
|
<StandardLayout
|
|
182
182
|
node={node}
|
|
183
183
|
content={content}
|
|
184
|
+
language={pageData?.language}
|
|
184
185
|
normalizedSlug={normalizedSlug}
|
|
185
186
|
isHomePage={isHomePage}
|
|
186
187
|
hasSidebar={hasSidebar}
|
package/definitions/_page.yaml
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
id: _page
|
|
2
|
-
label: Page Old
|
|
3
|
-
inTree: true
|
|
4
|
-
inVault: true
|
|
5
|
-
hasCanvas: true
|
|
6
|
-
|
|
7
|
-
layout:
|
|
8
|
-
columns: "10fr 4fr"
|
|
9
|
-
areas:
|
|
10
|
-
- ["header", "header"]
|
|
11
|
-
- ["main", "sidebar"]
|
|
12
|
-
- ["footer", "footer"]
|
|
13
|
-
|
|
14
|
-
regions:
|
|
15
|
-
header:
|
|
16
|
-
label: Header
|
|
17
|
-
inherit: parent
|
|
18
|
-
main:
|
|
19
|
-
label: Content
|
|
20
|
-
sidebar:
|
|
21
|
-
label: Sidebar
|
|
22
|
-
footer:
|
|
23
|
-
label: Footer
|
|
24
|
-
inherit: parent
|
|
25
|
-
|
|
26
|
-
allowedBlocks:
|
|
27
|
-
- header
|
|
28
|
-
- hero
|
|
29
|
-
- text
|
|
30
|
-
- image_card
|
|
31
|
-
|
|
32
|
-
# 👉 TABS DEFINITION
|
|
33
|
-
tabs:
|
|
34
|
-
settings:
|
|
35
|
-
label: "Page"
|
|
36
|
-
fields:
|
|
37
|
-
# Imports core fields: title, slug, isHidden
|
|
38
|
-
- fieldSet: page-base
|
|
39
|
-
|
|
40
|
-
# Overrides & custom properties
|
|
41
|
-
- menuTitle:
|
|
42
|
-
label: Menu Title
|
|
43
|
-
type: text
|
|
44
|
-
dbType: text
|
|
45
|
-
public: true
|
|
46
|
-
placeholder: "Short title for navigation menus"
|
|
47
|
-
|
|
48
|
-
# SEO / OpenGraph metadata
|
|
49
|
-
- fieldSet: meta
|
|
50
|
-
|
|
51
|
-
# Role permissions & access control
|
|
52
|
-
- fieldSet: access
|