@brightsideoy/kama 0.1.0-alpha.149 → 0.1.0-alpha.151

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.
@@ -1,130 +0,0 @@
1
- import { defineMiddleware } from "astro:middleware";
2
- import { env } from "cloudflare:workers";
3
-
4
- export const apiPurgeMiddleware = defineMiddleware(async (context, next) => {
5
- const pathname = context.url.pathname;
6
-
7
- // Bypass this middleware entirely if it's not a purge request
8
- if (pathname !== "/api/purge" && pathname !== "/api/purge/") {
9
- return next();
10
- }
11
-
12
- const locals = context.locals as any;
13
- const cfContext = locals.cfContext;
14
- const workerEnv = (typeof env !== "undefined" ? env : (process?.env || {})) as any;
15
- const HTML_CACHE = workerEnv?.HTML_CACHE;
16
-
17
- if (context.request.method !== "POST") {
18
- return new Response(JSON.stringify({ error: "Method Not Allowed" }), { status: 405, headers: { "Content-Type": "application/json" } });
19
- }
20
-
21
- const authHeader = context.request.headers.get("Authorization");
22
- const expectedToken = workerEnv.CLOUDFLARE_API_TOKEN;
23
-
24
- if (!expectedToken || authHeader !== `Bearer ${expectedToken}`) {
25
- return new Response(JSON.stringify({ error: "Unauthorized Token Mismatch" }), { status: 401, headers: { "Content-Type": "application/json" } });
26
- }
27
-
28
- try {
29
- const body = await context.request.json();
30
- const edgeCache = typeof caches !== "undefined" && caches.default ? caches.default : null;
31
- const origin = context.url.origin;
32
-
33
- // A. Purge Workers Caching Layer (Astro v6 cfContext)
34
- if (typeof cfContext?.cache?.purge === 'function') {
35
- try {
36
- await cfContext.cache.purge({ purgeEverything: true });
37
- console.log("✅ New Cloudflare Workers Cache Engine Purged");
38
- } catch (e) {
39
- console.error("❌ Failed to purge new Workers Cache Engine", e);
40
- }
41
- }
42
-
43
- // B. Version-Based Instant Invalidation (0ms KV Write)
44
- if (HTML_CACHE) {
45
- try {
46
- const now = Date.now().toString();
47
-
48
- if (body.purge_everything) {
49
- await HTML_CACHE.put("site_version", now);
50
- console.log(`✅ [Version Tagging] Global site_version updated to ${now}`);
51
- } else if (Array.isArray(body.urls) && body.urls.length > 0) {
52
- const purgeTasks = body.urls.map((targetUrl: string) => {
53
- const urlPath = new URL(targetUrl).pathname;
54
- const cleanPath = urlPath.replace(/\/$/, "") || "/";
55
- return HTML_CACHE.put(`v:${cleanPath}`, now);
56
- });
57
- await Promise.all(purgeTasks);
58
- console.log(`✅ [Version Tagging] Updated versions for ${body.urls.length} URLs`);
59
- }
60
- } catch (kvErr) {
61
- console.error("❌ KV Version Tagging Error:", kvErr);
62
- }
63
- }
64
-
65
- // C. Global Legacy Worker Cache Purge
66
- if (body.purge_everything) {
67
- if (edgeCache) {
68
- const rootUrls = [origin, `${origin}/`, `${origin}/home`, `${origin}/home/`];
69
- for (const url of rootUrls) await edgeCache.delete(new Request(url));
70
- }
71
- return new Response(JSON.stringify({ success: true, message: "All Worker Caches Purged" }), { status: 200, headers: { "Content-Type": "application/json" } });
72
- }
73
-
74
- // D. Surgical Legacy Worker Cache Purge
75
- if (Array.isArray(body.urls) && body.urls.length > 0) {
76
- const results = [];
77
- for (const targetUrl of body.urls) {
78
- const cleanUrl = targetUrl.split('?')[0];
79
- const urlNoSlash = cleanUrl.replace(/\/$/, "");
80
- const urlWithSlash = urlNoSlash + "/";
81
- let p1 = false, p2 = false;
82
-
83
- if (edgeCache) {
84
- p1 = await edgeCache.delete(new Request(urlNoSlash));
85
- p2 = await edgeCache.delete(new Request(urlWithSlash));
86
- }
87
- results.push({ url: targetUrl, purged: p1 || p2 });
88
- }
89
- return new Response(JSON.stringify({ success: true, message: "URLs processed", results }), { status: 200, headers: { "Content-Type": "application/json" } });
90
- }
91
-
92
- // E. Surgical Deletion for Deleted Pages
93
- if (Array.isArray(body.deleted_urls) && body.deleted_urls.length > 0) {
94
- const results: any[] = [];
95
- const deleteTasks = body.deleted_urls.map(async (targetUrl: string) => {
96
- const urlPath = new URL(targetUrl).pathname;
97
- const cleanPath = urlPath.replace(/\/$/, "") || "/";
98
- let purgedKv = false;
99
-
100
- if (HTML_CACHE) {
101
- const [siteVer, pageVer] = await Promise.all([HTML_CACHE.get("site_version"), HTML_CACHE.get(`v:${cleanPath}`)]);
102
- if (siteVer || pageVer) {
103
- const activeCacheKey = `${cleanPath}:v:${siteVer || "1"}:${pageVer || "1"}`;
104
- await HTML_CACHE.delete(activeCacheKey);
105
- purgedKv = true;
106
- }
107
- await HTML_CACHE.delete(`v:${cleanPath}`);
108
- }
109
-
110
- const cleanUrl = targetUrl.split('?')[0];
111
- const urlNoSlash = cleanUrl.replace(/\/$/, "");
112
- let p1 = false, p2 = false;
113
-
114
- if (edgeCache) {
115
- p1 = await edgeCache.delete(new Request(urlNoSlash));
116
- p2 = await edgeCache.delete(new Request(urlNoSlash + "/"));
117
- }
118
- results.push({ url: targetUrl, purgedKv, purgedLegacy: p1 || p2 });
119
- });
120
-
121
- await Promise.all(deleteTasks);
122
- return new Response(JSON.stringify({ success: true, message: "Deleted URLs permanently removed", results }), { status: 200, headers: { "Content-Type": "application/json" } });
123
- }
124
-
125
- return new Response(JSON.stringify({ error: "Invalid payload format" }), { status: 400, headers: { "Content-Type": "application/json" } });
126
-
127
- } catch (err: any) {
128
- return new Response(JSON.stringify({ error: err.message }), { status: 500, headers: { "Content-Type": "application/json" } });
129
- }
130
- });
@@ -1,10 +0,0 @@
1
- import { sequence } from "astro:middleware";
2
- import { apiPurgeMiddleware } from "./api-purge";
3
- import { kvCacheMiddleware } from "./kv-cache";
4
- import { responseHeadersMiddleware } from "./response-headers";
5
-
6
- export const onRequest = sequence(
7
- apiPurgeMiddleware,
8
- kvCacheMiddleware,
9
- responseHeadersMiddleware
10
- );
@@ -1,76 +0,0 @@
1
- import { defineMiddleware } from "astro:middleware";
2
- import { env } from "cloudflare:workers";
3
-
4
- export const kvCacheMiddleware = defineMiddleware(async (context, next) => {
5
- const pathname = context.url.pathname;
6
- const locals = context.locals as any;
7
- const cfContext = locals.cfContext;
8
- const workerEnv = (typeof env !== "undefined" ? env : (process?.env || {})) as any;
9
- const HTML_CACHE = workerEnv?.HTML_CACHE;
10
-
11
- const isWarmer = context.request.headers.get("X-Cache-Warmer") === "true";
12
- const isHtmlPage = !pathname.includes('.') && !pathname.startsWith('/api/');
13
- const cleanLookupPath = pathname.replace(/\/$/, "") || "/";
14
-
15
- let activeCacheKey = cleanLookupPath;
16
-
17
- // 🎯 1. READ PHASE
18
- if (isHtmlPage && HTML_CACHE && !isWarmer) {
19
- try {
20
- const [siteVer, pageVer] = await Promise.all([
21
- HTML_CACHE.get("site_version"),
22
- HTML_CACHE.get(`v:${cleanLookupPath}`)
23
- ]);
24
-
25
- activeCacheKey = `${cleanLookupPath}:v:${siteVer || "1"}:${pageVer || "1"}`;
26
-
27
- const cachedHtml = await HTML_CACHE.get(activeCacheKey);
28
- if (cachedHtml) {
29
- return new Response(cachedHtml, {
30
- status: 200,
31
- headers: {
32
- "Content-Type": "text/html; charset=utf-8",
33
- "X-Cache-Status": "HIT-KV-STATICFILE",
34
- "X-Cache-Key": activeCacheKey,
35
- "Cache-Control": "no-store, no-cache, must-revalidate, proxy-revalidate"
36
- }
37
- });
38
- }
39
- } catch (e) {
40
- console.warn("[KV Cache] Lookup bypassed:", e);
41
- }
42
- }
43
-
44
- // Process downstream SSR route
45
- const response = await next();
46
-
47
- // 🎯 2. WRITE PHASE
48
- if (
49
- isHtmlPage &&
50
- HTML_CACHE &&
51
- response.status === 200 &&
52
- response.headers.get("content-type")?.includes("text/html")
53
- ) {
54
- const htmlText = await response.clone().text();
55
-
56
- const writeTask = (async () => {
57
- if (activeCacheKey === cleanLookupPath || isWarmer) {
58
- const forcedVersion = Date.now().toString();
59
- await HTML_CACHE.put(`v:${cleanLookupPath}`, forcedVersion);
60
- const siteVer = await HTML_CACHE.get("site_version") || "1";
61
- activeCacheKey = `${cleanLookupPath}:v:${siteVer}:${forcedVersion}`;
62
- }
63
-
64
- await HTML_CACHE.put(activeCacheKey, htmlText);
65
- console.log(`✅ [KV Cache] Saved HTML under key: ${activeCacheKey}`);
66
- })();
67
-
68
- if (cfContext && typeof cfContext.waitUntil === 'function') {
69
- cfContext.waitUntil(writeTask);
70
- } else {
71
- writeTask.catch((e: any) => console.error("KV write error:", e));
72
- }
73
- }
74
-
75
- return response;
76
- });
@@ -1,43 +0,0 @@
1
- import { defineMiddleware } from "astro:middleware";
2
-
3
- export const responseHeadersMiddleware = defineMiddleware(async (context, next) => {
4
- // Process downstream routes first so we have the response to modify
5
- const response = await next();
6
- const pathname = context.url.pathname;
7
-
8
- // 1. LLMs & XML Configs
9
- if (pathname === "/llms.txt" || pathname === "/llms-full.txt") {
10
- response.headers.set("Content-Type", "text/plain; charset=utf-8");
11
- response.headers.set("Cache-Control", "public, max-age=3600");
12
- response.headers.set("Access-Control-Allow-Origin", "*");
13
- }
14
- else if (pathname === "/llxml.txt") {
15
- response.headers.set("Content-Type", "application/xml; charset=utf-8");
16
- response.headers.set("Cache-Control", "public, max-age=3600");
17
- response.headers.set("Access-Control-Allow-Origin", "*");
18
- }
19
-
20
- // 2. Static Asset Caching
21
- else if (
22
- pathname.startsWith("/media/") ||
23
- pathname.startsWith("/_image") ||
24
- pathname.match(/\.(png|jpg|jpeg|webp|avif|svg|gif|ico|woff2?|css|js)$/i)
25
- ) {
26
- response.headers.set("Cache-Control", "public, max-age=31536000, s-maxage=31536000, immutable");
27
- response.headers.set("Access-Control-Allow-Origin", "*");
28
- }
29
-
30
- // 3. Security Headers for HTML
31
- if (response.headers.get("content-type")?.includes("text/html")) {
32
- response.headers.set("Strict-Transport-Security", "max-age=31536000; includeSubDomains; preload");
33
- response.headers.set("X-Frame-Options", "SAMEORIGIN");
34
- response.headers.set("X-Content-Type-Options", "nosniff");
35
- response.headers.set("Cross-Origin-Opener-Policy", "same-origin-allow-popups");
36
- response.headers.set(
37
- "Content-Security-Policy",
38
- "default-src 'self' https: data: 'unsafe-inline' 'unsafe-eval'; img-src 'self' https: data: blob:; connect-src 'self' https:; frame-ancestors 'self';"
39
- );
40
- }
41
-
42
- return response;
43
- });