@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.
@@ -0,0 +1,141 @@
1
+ ---
2
+ // src/pages/partials/nav.astro
3
+ export const partial = true; // 🎯 Tells Astro not to wrap this in <html><body>
4
+
5
+ import { getTree, getTreeId, getChannelId } from "@/lib/cms";
6
+ import type { TreeNode } from "@/lib/cms";
7
+
8
+ const safeEnv = (Astro.locals as any).safeEnv || {};
9
+ const cmsWorker = safeEnv.CMS_WORKER;
10
+
11
+ const customFetch = (input: RequestInfo | URL, init?: RequestInit) => {
12
+ const reqInit = { ...init };
13
+ delete reqInit.cache;
14
+
15
+ let urlStr = input instanceof URL ? input.toString() : String(input);
16
+ if (urlStr.startsWith("/")) {
17
+ const baseUrl =
18
+ import.meta.env.PUBLIC_API_URL ||
19
+ safeEnv.PUBLIC_API_URL ||
20
+ "http://127.0.0.1:8787";
21
+ urlStr = `${baseUrl}${urlStr}`;
22
+ }
23
+
24
+ const req = new Request(urlStr, reqInit);
25
+ if (cmsWorker && typeof cmsWorker.fetch === "function")
26
+ return cmsWorker.fetch(req);
27
+ return fetch(req);
28
+ };
29
+
30
+ // Fetch fresh tree from CMS
31
+ const channelId = getChannelId() || "website";
32
+ const treeId = getTreeId() || "main-nav";
33
+ let tree: TreeNode[] = [];
34
+ try {
35
+ tree = (await getTree(treeId, channelId, customFetch)) || [];
36
+ } catch (e) {
37
+ console.error("[Partials/Nav] Failed to fetch tree:", e);
38
+ }
39
+
40
+ // Get the current path from the client's fetch request
41
+ const currentPath =
42
+ (Astro.url.searchParams.get("path") || "/").replace(/\/$/, "") || "/";
43
+ const homeSlug = String(import.meta.env.PUBLIC_HOME_SLUG || "home").trim();
44
+
45
+ const homeNode = tree.find(
46
+ item =>
47
+ item.slug === homeSlug ||
48
+ item.slug === "" ||
49
+ item.path === "/" ||
50
+ item.path === "",
51
+ );
52
+
53
+ const topLevelNavItems =
54
+ homeNode?.children && homeNode.children.length > 0
55
+ ? homeNode.children
56
+ : tree.filter(
57
+ item =>
58
+ item.slug !== homeSlug &&
59
+ item.slug !== "" &&
60
+ item.path !== "/" &&
61
+ item.path !== "",
62
+ );
63
+
64
+ const isPathActive = (itemPath?: string) => {
65
+ const normItem = (itemPath || "").replace(/\/$/, "") || "/";
66
+ if (normItem === "/") return currentPath === "/";
67
+ return currentPath === normItem || currentPath.startsWith(`${normItem}/`);
68
+ };
69
+
70
+ const isExactActive = (itemPath?: string) => {
71
+ return currentPath === ((itemPath || "").replace(/\/$/, "") || "/");
72
+ };
73
+ ---
74
+
75
+ <ul class="nav-list">
76
+ {
77
+ topLevelNavItems.map(item => {
78
+ const hasChildren = item.children && item.children.length > 0;
79
+ const isParentActive = isPathActive(item.path);
80
+
81
+ if (hasChildren) {
82
+ return (
83
+ <li class="nav-item">
84
+ <details class="nav-details">
85
+ <summary
86
+ class:list={[
87
+ "nav-button",
88
+ "dropdown-summary",
89
+ { active: isParentActive },
90
+ ]}
91
+ >
92
+ <span>{item.title}</span>
93
+ <span class="indicator">▼</span>
94
+ </summary>
95
+ <div class="submenu-container">
96
+ <ul class="dropdown-panel">
97
+ <li>
98
+ <a
99
+ href={item.path}
100
+ class:list={[
101
+ "dropdown-item",
102
+ "overview-item",
103
+ { active: isExactActive(item.path) },
104
+ ]}
105
+ >
106
+ {item.title} Overview
107
+ </a>
108
+ </li>
109
+ {item.children?.map(child => (
110
+ <li>
111
+ <a
112
+ href={child.path}
113
+ class:list={[
114
+ "dropdown-item",
115
+ { active: isExactActive(child.path) },
116
+ ]}
117
+ >
118
+ {child.title}
119
+ </a>
120
+ </li>
121
+ ))}
122
+ </ul>
123
+ </div>
124
+ </details>
125
+ </li>
126
+ );
127
+ }
128
+
129
+ return (
130
+ <li class="nav-item">
131
+ <a
132
+ href={item.path}
133
+ class:list={["nav-button", { active: isExactActive(item.path) }]}
134
+ >
135
+ {item.title}
136
+ </a>
137
+ </li>
138
+ );
139
+ })
140
+ }
141
+ </ul>
@@ -0,0 +1,19 @@
1
+ import kamaWorker from '@brightsideoy/kama';
2
+ import * as localBundle from './bundled-definitions.js';
3
+
4
+ export default {
5
+ async fetch(request, env, ctx) {
6
+ const schemas = localBundle.BUNDLED_DEFINITIONS || localBundle.default || localBundle;
7
+ const customEnv = { ...env, BUNDLED_DEFINITIONS: schemas, KAMA_RUNTIME: 'cloudflare' };
8
+
9
+ if (kamaWorker && typeof kamaWorker.fetch === 'function') {
10
+ return kamaWorker.fetch(request, customEnv, ctx);
11
+ }
12
+
13
+ if (kamaWorker && kamaWorker.app && typeof kamaWorker.app.fetch === 'function') {
14
+ return kamaWorker.app.fetch(request, customEnv, ctx);
15
+ }
16
+
17
+ return new Response('Kama Engine Worker Ready', { status: 200 });
18
+ }
19
+ };
@@ -0,0 +1,98 @@
1
+ import { serve } from '@hono/node-server';
2
+ import { serveStatic } from '@hono/node-server/serve-static';
3
+ import { Hono } from 'hono';
4
+ import kamaApp from '@brightsideoy/kama';
5
+ import * as localBundle from './bundled-definitions.js';
6
+ import dotenv from 'dotenv';
7
+ import { readFileSync, existsSync, statSync } from 'node:fs';
8
+ import { join } from 'node:path';
9
+ import { pathToFileURL } from 'node:url';
10
+
11
+ dotenv.config();
12
+
13
+ const possiblePaths = [
14
+ './node_modules/@brightsideoy/kama/dist',
15
+ '../node_modules/@brightsideoy/kama/dist',
16
+ '../../node_modules/@brightsideoy/kama/dist'
17
+ ];
18
+ const distPath = possiblePaths.find(p => existsSync(p));
19
+
20
+ if (!distPath) {
21
+ console.warn('⚠️ Could not locate @brightsideoy/kama/dist folder. Admin UI will not load.');
22
+ }
23
+
24
+ const app = new Hono();
25
+
26
+ let cachedSchemas = localBundle.BUNDLED_DEFINITIONS || localBundle.default || localBundle;
27
+ let lastModified = 0;
28
+
29
+ async function getCustomEnv(c) {
30
+ try {
31
+ const bundlePath = join(process.cwd(), 'bundled-definitions.js');
32
+ if (existsSync(bundlePath)) {
33
+ const mtime = statSync(bundlePath).mtimeMs;
34
+ if (mtime > lastModified) {
35
+ if (lastModified !== 0) console.log('🔄 Hot-reloading fresh schema definitions!');
36
+ const mod = await import(`${pathToFileURL(bundlePath).href}?t=${mtime}`);
37
+ cachedSchemas = mod.BUNDLED_DEFINITIONS || mod.default || mod;
38
+ lastModified = mtime;
39
+ }
40
+ }
41
+ } catch (err) { }
42
+
43
+ return {
44
+ ...process.env,
45
+ ...(c.env || {}),
46
+ BUNDLED_DEFINITIONS: cachedSchemas,
47
+ KAMA_RUNTIME: (c.env && c.env.DB) ? 'cloudflare' : 'node'
48
+ };
49
+ }
50
+
51
+ app.use('/media/*', serveStatic({ root: './' }));
52
+ if (distPath) {
53
+ app.use('/assets/*', serveStatic({ root: distPath }));
54
+ }
55
+
56
+ function resolveExecutionContext(c) {
57
+ try {
58
+ if (c.executionCtx) return c.executionCtx;
59
+ } catch (e) { }
60
+ return {
61
+ waitUntil: (promise) => Promise.resolve(promise).catch(console.error),
62
+ passThroughOnException: () => { }
63
+ };
64
+ }
65
+
66
+ app.all('*', async (c) => {
67
+ const customEnv = await getCustomEnv(c);
68
+ const execCtx = resolveExecutionContext(c);
69
+
70
+ let response;
71
+ if (typeof kamaApp.fetch === 'function') {
72
+ response = await kamaApp.fetch(c.req.raw, customEnv, execCtx);
73
+ } else if (kamaApp.app && typeof kamaApp.app.fetch === 'function') {
74
+ response = await kamaApp.app.fetch(c.req.raw, customEnv, execCtx);
75
+ } else {
76
+ return c.text("Engine not configured correctly", 500);
77
+ }
78
+
79
+ if (response.status === 404 && distPath && !c.req.path.startsWith('/api')) {
80
+ const indexPath = join(distPath, 'index.html');
81
+ if (existsSync(indexPath)) {
82
+ return c.html(readFileSync(indexPath, 'utf-8'));
83
+ }
84
+ }
85
+
86
+ return response;
87
+ });
88
+
89
+ export default app;
90
+
91
+ if (typeof process !== 'undefined' && process.argv && process.argv[1] && process.argv[1].endsWith('server.js')) {
92
+ const port = process.env.PORT ? parseInt(process.env.PORT, 10) : 8787;
93
+ serve({ fetch: app.fetch, port }, (info) => {
94
+ console.log(`\n🔥 KAMA CMS Node Server is running!`);
95
+ console.log(`┃ Local http://localhost:${info.port}/`);
96
+ if (distPath) console.log(`┃ Admin UI Serving from: ${distPath}\n`);
97
+ });
98
+ }