@brightsideoy/kama 0.1.0-alpha.16 → 0.1.0-alpha.161
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/README.md +169 -0
- package/bin/cli.js +686 -155
- package/content/definitions/block-layouts/three-column.yaml +20 -0
- package/content/definitions/block-layouts/two-column.yaml +29 -0
- package/content/definitions/blocks/button.yaml +24 -0
- package/content/definitions/blocks/header.yaml +13 -0
- package/content/definitions/blocks/header_image.yaml +21 -0
- package/content/definitions/blocks/hero.yaml +28 -0
- package/content/definitions/blocks/html.yaml +13 -0
- package/content/definitions/blocks/image_card.yaml +56 -0
- package/content/definitions/blocks/single_image.yaml +27 -0
- package/content/definitions/blocks/text.yaml +15 -0
- package/content/definitions/channels/ecommerce.yaml +28 -0
- package/content/definitions/channels/website.yaml +41 -0
- package/content/definitions/field-sets/access.yaml +27 -0
- package/content/definitions/field-sets/channel-base.yaml +50 -0
- package/content/definitions/field-sets/channel-seo.yaml +21 -0
- package/content/definitions/field-sets/comments.yaml +11 -0
- package/content/definitions/field-sets/content-block.yaml +41 -0
- package/content/definitions/field-sets/page-base.yaml +44 -0
- package/content/definitions/field-sets/page-seo.yaml +34 -0
- package/content/definitions/field-sets/page-social.yaml +78 -0
- package/content/definitions/field-sets/schema-type.yaml +43 -0
- package/content/definitions/field-sets/tree-base.yaml +31 -0
- package/content/definitions/field-sets/visibility.yaml +8 -0
- package/content/definitions/node-layouts/content.yml +12 -0
- package/content/definitions/node-layouts/landing-page.yml +27 -0
- package/content/definitions/node-layouts/single-column.yml +43 -0
- package/content/definitions/node-layouts/two-column.yml +48 -0
- package/content/definitions/nodes/address.yaml +40 -0
- package/content/definitions/nodes/article.yaml +37 -0
- package/content/definitions/nodes/event.yaml +55 -0
- package/content/definitions/nodes/external-link.yaml +29 -0
- package/content/definitions/nodes/page-skeleton.yaml +48 -0
- package/content/definitions/nodes/page.yaml +54 -0
- package/content/definitions/nodes/person.yaml +41 -0
- package/content/definitions/nodes/product.yaml +89 -0
- package/content/definitions/trees/navigation.yaml +24 -0
- package/definitions/editor/button.ts +11 -0
- package/definitions/editor/default.ts +21 -0
- package/definitions/editor/header.ts +36 -0
- package/definitions/editor/minimal.ts +15 -0
- package/definitions/validators/iban.ts +12 -0
- package/definitions/validators/magic-word.ts +7 -0
- package/dist/assets/index-C5TmJVER.css +1 -0
- package/dist/assets/index-jpMh2BZv.js +164 -0
- package/dist/dist-BNkCx-o-.js +8912 -0
- package/dist/index.html +15 -0
- package/dist/index.js +7646 -1562
- package/dist/schema-compiler.js +48 -0
- package/documentation/SCHEMAS.md +182 -0
- package/package.json +19 -17
- package/schema.sql +206 -0
- package/templates/astro-starter/astro.config.mjs +24 -0
- package/templates/astro-starter/package.json.template +20 -0
- package/templates/astro-starter/public/robots.txt +23 -0
- package/templates/astro-starter/src/components/blocks/BlockRenderer.astro +134 -0
- package/templates/astro-starter/src/components/blocks/ColumnLayout.astro +67 -0
- package/templates/astro-starter/src/components/blocks/HeaderImage.astro +132 -0
- package/templates/astro-starter/src/components/blocks/Hero.astro +218 -0
- package/templates/astro-starter/src/components/blocks/HtmlBlock.astro +25 -0
- package/templates/astro-starter/src/components/blocks/ImageBlock.astro +92 -0
- package/templates/astro-starter/src/components/blocks/TextBlock.astro +15 -0
- package/templates/astro-starter/src/components/global/Breadcrumb.astro +67 -0
- package/templates/astro-starter/src/components/global/Footer.astro +50 -0
- package/templates/astro-starter/src/components/global/Header.astro +177 -0
- package/templates/astro-starter/src/components/global/MetaHead.astro +266 -0
- package/templates/astro-starter/src/components/global/NavigationMenu.astro +318 -0
- package/templates/astro-starter/src/components/ui/KamaImage.astro +172 -0
- package/templates/astro-starter/src/layouts/SkeletonLayout.astro +47 -0
- package/templates/astro-starter/src/layouts/StandardLayout.astro +62 -0
- package/templates/astro-starter/src/lib/cms.ts +197 -0
- package/templates/astro-starter/src/lib/media/kama-image-service.ts +56 -0
- package/templates/astro-starter/src/lib/media/media-proxy.ts +129 -0
- package/templates/astro-starter/src/lib/media/media-url.ts +98 -0
- package/templates/astro-starter/src/middleware.ts +406 -0
- package/templates/astro-starter/src/pages/404.astro +46 -0
- package/templates/astro-starter/src/pages/[...slug].astro +238 -0
- package/templates/astro-starter/src/pages/llms-full.txt.ts +171 -0
- package/templates/astro-starter/src/pages/llms.txt.ts +113 -0
- package/templates/astro-starter/src/pages/media/[...path].ts +14 -0
- package/templates/astro-starter/src/pages/partials/footer.astro +69 -0
- package/templates/astro-starter/src/pages/partials/nav.astro +141 -0
- package/templates/astro-starter/src/styles/standard-theme.css +157 -0
- package/templates/astro-starter/src/utils/tiptap.ts +113 -0
- package/templates/astro-starter/tsconfig.json +0 -0
- package/templates/kama-worker/index.js +19 -0
- package/templates/kama-worker/server.js +98 -0
- package/wrangler.json +22 -0
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
// src/utils/tiptap.ts
|
|
2
|
+
|
|
3
|
+
export interface TiptapNode {
|
|
4
|
+
type: string;
|
|
5
|
+
text?: string;
|
|
6
|
+
attrs?: Record<string, any>;
|
|
7
|
+
marks?: Array<{ type: string; attrs?: Record<string, any> }>;
|
|
8
|
+
content?: TiptapNode[];
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Traverses a ProseMirror / Tiptap AST node and converts it into HTML.
|
|
13
|
+
*/
|
|
14
|
+
export function renderTiptapNode(node?: TiptapNode | null): string {
|
|
15
|
+
if (!node) return "";
|
|
16
|
+
if (typeof node === "string") return node;
|
|
17
|
+
|
|
18
|
+
// 1. Text Node Handling (with Marks)
|
|
19
|
+
if (node.type === "text") {
|
|
20
|
+
let text = escapeHtml(node.text || "");
|
|
21
|
+
if (node.marks && Array.isArray(node.marks)) {
|
|
22
|
+
node.marks.forEach((mark) => {
|
|
23
|
+
switch (mark.type) {
|
|
24
|
+
case "bold":
|
|
25
|
+
case "strong":
|
|
26
|
+
text = `<strong>${text}</strong>`;
|
|
27
|
+
break;
|
|
28
|
+
case "italic":
|
|
29
|
+
case "em":
|
|
30
|
+
text = `<em>${text}</em>`;
|
|
31
|
+
break;
|
|
32
|
+
case "underline":
|
|
33
|
+
text = `<u>${text}</u>`;
|
|
34
|
+
break;
|
|
35
|
+
case "strike":
|
|
36
|
+
text = `<s>${text}</s>`;
|
|
37
|
+
break;
|
|
38
|
+
case "code":
|
|
39
|
+
text = `<code>${text}</code>`;
|
|
40
|
+
break;
|
|
41
|
+
case "link": {
|
|
42
|
+
const href = mark.attrs?.href ? escapeHtml(mark.attrs.href) : "#";
|
|
43
|
+
const target = mark.attrs?.target ? ` target="${escapeHtml(mark.attrs.target)}"` : "";
|
|
44
|
+
const rel = mark.attrs?.target === "_blank" ? ' rel="noopener noreferrer"' : "";
|
|
45
|
+
text = `<a href="${href}"${target}${rel}>${text}</a>`;
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
return text;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// 2. Traversal of Child Nodes
|
|
55
|
+
const childrenHtml = Array.isArray(node.content)
|
|
56
|
+
? node.content.map(renderTiptapNode).join("")
|
|
57
|
+
: "";
|
|
58
|
+
|
|
59
|
+
// 3. Block Level Mapping
|
|
60
|
+
switch (node.type) {
|
|
61
|
+
case "doc":
|
|
62
|
+
return childrenHtml;
|
|
63
|
+
case "paragraph":
|
|
64
|
+
return childrenHtml.trim() ? `<p>${childrenHtml}</p>` : "";
|
|
65
|
+
case "heading": {
|
|
66
|
+
const level = Math.min(Math.max(node.attrs?.level || 2, 1), 6);
|
|
67
|
+
return `<h${level}>${childrenHtml}</h${level}>`;
|
|
68
|
+
}
|
|
69
|
+
case "bulletList":
|
|
70
|
+
return `<ul>${childrenHtml}</ul>`;
|
|
71
|
+
case "orderedList": {
|
|
72
|
+
const start = node.attrs?.start ? ` start="${node.attrs.start}"` : "";
|
|
73
|
+
return `<ol${start}>${childrenHtml}</ol>`;
|
|
74
|
+
}
|
|
75
|
+
case "listItem":
|
|
76
|
+
return `<li>${childrenHtml}</li>`;
|
|
77
|
+
case "blockquote":
|
|
78
|
+
return `<blockquote>${childrenHtml}</blockquote>`;
|
|
79
|
+
case "codeBlock": {
|
|
80
|
+
const lang = node.attrs?.language ? ` class="language-${escapeHtml(node.attrs.language)}"` : "";
|
|
81
|
+
return `<pre><code${lang}>${childrenHtml}</code></pre>`;
|
|
82
|
+
}
|
|
83
|
+
case "horizontalRule":
|
|
84
|
+
return "<hr />";
|
|
85
|
+
case "hardBreak":
|
|
86
|
+
return "<br />";
|
|
87
|
+
default:
|
|
88
|
+
return childrenHtml;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Universal helper that handles plain strings, legacy objects, and Tiptap ASTs safely.
|
|
94
|
+
*/
|
|
95
|
+
export function extractHtml(value: any): string {
|
|
96
|
+
if (!value) return "";
|
|
97
|
+
if (typeof value === "string") return value; // Already HTML/string
|
|
98
|
+
if (typeof value === "object") {
|
|
99
|
+
if (value.type === "doc") return renderTiptapNode(value);
|
|
100
|
+
if (value.html) return value.html;
|
|
101
|
+
if (value.markup) return value.markup;
|
|
102
|
+
}
|
|
103
|
+
return String(value);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function escapeHtml(str: string): string {
|
|
107
|
+
return str
|
|
108
|
+
.replace(/&/g, "&")
|
|
109
|
+
.replace(/</g, "<")
|
|
110
|
+
.replace(/>/g, ">")
|
|
111
|
+
.replace(/"/g, """)
|
|
112
|
+
.replace(/'/g, "'");
|
|
113
|
+
}
|
|
File without changes
|
|
@@ -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
|
+
}
|
package/wrangler.json
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "node_modules/wrangler/config-schema.json",
|
|
3
|
+
"name": "kama",
|
|
4
|
+
"main": "server/index.ts",
|
|
5
|
+
"compatibility_date": "2024-09-23",
|
|
6
|
+
"compatibility_flags": [
|
|
7
|
+
"nodejs_compat"
|
|
8
|
+
],
|
|
9
|
+
"d1_databases": [
|
|
10
|
+
{
|
|
11
|
+
"binding": "DB",
|
|
12
|
+
"database_name": "kama-db",
|
|
13
|
+
"database_id": "local-kama-db"
|
|
14
|
+
}
|
|
15
|
+
],
|
|
16
|
+
"r2_buckets": [
|
|
17
|
+
{
|
|
18
|
+
"binding": "MEDIA_BUCKET",
|
|
19
|
+
"bucket_name": "kama-media"
|
|
20
|
+
}
|
|
21
|
+
]
|
|
22
|
+
}
|