@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.
Files changed (33) hide show
  1. package/bin/cli.js +229 -231
  2. package/dist/assets/index-BesA3e7A.js +164 -0
  3. package/dist/assets/index-D6yHZ_u1.css +1 -0
  4. package/dist/{dist-C-WAK7EF.js → dist-mic4UZBb.js} +691 -439
  5. package/dist/index.html +2 -2
  6. package/dist/index.js +693 -439
  7. package/dist/schema-compiler.js +1 -1
  8. package/package.json +1 -1
  9. package/schema.sql +2 -2
  10. package/templates/astro-starter/src/components/blocks/BlockRenderer.astro +1 -0
  11. package/templates/astro-starter/src/components/blocks/ColumnLayout.astro +1 -0
  12. package/templates/astro-starter/src/components/blocks/HeaderImage.astro +1 -0
  13. package/templates/astro-starter/src/components/blocks/HtmlBlock.astro +2 -1
  14. package/templates/astro-starter/src/components/blocks/ImageBlock.astro +39 -71
  15. package/templates/astro-starter/src/components/blocks/TextBlock.astro +2 -0
  16. package/templates/astro-starter/src/components/global/Breadcrumb.astro +2 -0
  17. package/templates/astro-starter/src/components/global/Footer.astro +2 -0
  18. package/templates/astro-starter/src/components/global/Header.astro +100 -28
  19. package/templates/astro-starter/src/components/{seo/SeoHead.astro → global/MetaHead.astro} +101 -49
  20. package/templates/astro-starter/src/components/global/NavigationMenu.astro +1 -0
  21. package/templates/astro-starter/src/components/ui/KamaImage.astro +114 -67
  22. package/templates/astro-starter/src/layouts/SkeletonLayout.astro +5 -3
  23. package/templates/astro-starter/src/layouts/StandardLayout.astro +14 -5
  24. package/templates/astro-starter/src/lib/cms.ts +48 -0
  25. package/templates/astro-starter/src/lib/media/kama-image-service.ts +16 -1
  26. package/templates/astro-starter/src/lib/media/media-proxy.ts +8 -6
  27. package/templates/astro-starter/src/lib/media/media-url.ts +65 -1
  28. package/templates/astro-starter/src/middleware.ts +131 -18
  29. package/templates/astro-starter/src/pages/[...slug].astro +10 -9
  30. package/definitions/_page.yaml +0 -52
  31. package/dist/assets/index-DGHRgyms.js +0 -164
  32. package/dist/assets/index-EaDn3OUJ.css +0 -1
  33. /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
- import { env } from "cloudflare:workers";
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 cfContext = (context.locals as any).cfContext;
7
- const workerEnv = cfContext?.env || (env as any);
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. DIRECT EDGE INTERCEPT FOR CACHE PURGE ENDPOINT
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
- if (isHtmlPage && HTML_CACHE && !isWarmer) {
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. IMAGE & STATIC ASSET CACHING
266
- if (
267
- pathname.startsWith("/media/") ||
268
- pathname.startsWith("/_image") ||
269
- pathname.startsWith("/cdn-cgi/image/") ||
270
- pathname.match(/\.(png|jpg|jpeg|webp|avif|svg|gif|ico|woff2?|css|js)$/i)
271
- ) {
272
- response.headers.set(
273
- "Cache-Control",
274
- "public, max-age=31536000, s-maxage=31536000, immutable"
275
- );
276
- response.headers.set("Access-Control-Allow-Origin", "*");
277
- return response;
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
- const workerEnv = env || {};
52
- const cmsWorker = workerEnv.CMS_WORKER;
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 = (workerEnv as any).PUBLIC_HOME_SLUG;
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 = workerEnv.PUBLIC_API_URL;
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}
@@ -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