@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.
@@ -3801,6 +3801,7 @@ var u = /* @__PURE__ */ o({
3801
3801
  label: "HTML",
3802
3802
  type: "textarea",
3803
3803
  public: !0,
3804
+ editor: !1,
3804
3805
  rules: {}
3805
3806
  } },
3806
3807
  tabs: { access: {
@@ -4815,7 +4816,7 @@ var u = /* @__PURE__ */ o({
4815
4816
  channels: "\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n key TEXT UNIQUE NOT NULL,\n label TEXT NOT NULL,\n channelType TEXT,\n domain TEXT,\n baseUrl TEXT,\n defaultLanguage TEXT DEFAULT 'en',\n isHidden INTEGER NOT NULL DEFAULT 0,\n dataJson TEXT,\n createdById TEXT,\n updatedById TEXT,\n createdAt TEXT DEFAULT CURRENT_TIMESTAMP,\n updatedAt TEXT DEFAULT CURRENT_TIMESTAMP,\n FOREIGN KEY (createdById) REFERENCES users(id) ON DELETE SET NULL,\n FOREIGN KEY (updatedById) REFERENCES users(id) ON DELETE SET NULL\n ",
4816
4817
  trees: "\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n key TEXT UNIQUE NOT NULL,\n label TEXT NOT NULL,\n treeType TEXT,\n channelId INTEGER,\n isHidden INTEGER NOT NULL DEFAULT 0,\n dataJson TEXT,\n createdById TEXT,\n updatedById TEXT,\n createdAt TEXT DEFAULT CURRENT_TIMESTAMP,\n updatedAt TEXT DEFAULT CURRENT_TIMESTAMP,\n FOREIGN KEY (channelId) REFERENCES channels(id) ON DELETE SET NULL,\n FOREIGN KEY (createdById) REFERENCES users(id) ON DELETE SET NULL,\n FOREIGN KEY (updatedById) REFERENCES users(id) ON DELETE SET NULL\n ",
4817
4818
  channel_trees: "\n channelId INTEGER NOT NULL,\n treeId INTEGER NOT NULL,\n key TEXT NOT NULL DEFAULT 'main',\n metaJson TEXT,\n PRIMARY KEY (channelId, treeId, key),\n FOREIGN KEY (channelId) REFERENCES channels(id) ON DELETE CASCADE,\n FOREIGN KEY (treeId) REFERENCES trees(id) ON DELETE CASCADE\n ",
4818
- content_nodes: "\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n contentType TEXT NOT NULL,\n title TEXT NOT NULL,\n slug TEXT,\n language TEXT DEFAULT 'en',\n isHidden INTEGER NOT NULL DEFAULT 0,\n status TEXT DEFAULT 'draft',\n disabledRegionsJson TEXT DEFAULT '{}',\n dataJson TEXT,\n draftDataJson TEXT,\n publishedDataJson TEXT,\n publishedAt TEXT,\n createdById TEXT,\n updatedById TEXT,\n createdAt TEXT DEFAULT CURRENT_TIMESTAMP,\n updatedAt TEXT DEFAULT CURRENT_TIMESTAMP,\n deletedAt TEXT,\n FOREIGN KEY (createdById) REFERENCES users(id) ON DELETE SET NULL,\n FOREIGN KEY (updatedById) REFERENCES users(id) ON DELETE SET NULL\n ",
4819
+ content_nodes: "\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n contentType TEXT NOT NULL,\n title TEXT NOT NULL,\n slug TEXT,\n language TEXT DEFAULT 'en',\n isHidden INTEGER NOT NULL DEFAULT 0,\n status TEXT DEFAULT 'draft',\n hasUnpublishedChanges INTEGER DEFAULT 0,\n disabledRegionsJson TEXT DEFAULT '{}',\n dataJson TEXT,\n draftDataJson TEXT,\n publishedDataJson TEXT,\n publishedAt TEXT,\n createdById TEXT,\n updatedById TEXT,\n createdAt TEXT DEFAULT CURRENT_TIMESTAMP,\n updatedAt TEXT DEFAULT CURRENT_TIMESTAMP,\n deletedAt TEXT,\n FOREIGN KEY (createdById) REFERENCES users(id) ON DELETE SET NULL,\n FOREIGN KEY (updatedById) REFERENCES users(id) ON DELETE SET NULL\n ",
4819
4820
  node_channels: "\n nodeId INTEGER NOT NULL,\n channelId INTEGER NOT NULL,\n PRIMARY KEY (nodeId, channelId),\n FOREIGN KEY (nodeId) REFERENCES content_nodes(id) ON DELETE CASCADE,\n FOREIGN KEY (channelId) REFERENCES channels(id) ON DELETE CASCADE\n ",
4820
4821
  tree_nodes: "\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n treeId INTEGER NOT NULL,\n contentId INTEGER NOT NULL,\n parentId INTEGER,\n sortOrder INTEGER DEFAULT 0,\n FOREIGN KEY (treeId) REFERENCES trees(id) ON DELETE CASCADE,\n FOREIGN KEY (contentId) REFERENCES content_nodes(id) ON DELETE CASCADE,\n FOREIGN KEY (parentId) REFERENCES tree_nodes(id) ON DELETE CASCADE\n ",
4821
4822
  content_blocks: "\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n contentId INTEGER NOT NULL,\n region TEXT DEFAULT 'main',\n elementType TEXT NOT NULL,\n dataJson TEXT,\n sortOrder INTEGER DEFAULT 0,\n isDraft INTEGER NOT NULL DEFAULT 1,\n FOREIGN KEY (contentId) REFERENCES content_nodes(id) ON DELETE CASCADE\n ",
@@ -4846,9 +4847,14 @@ async function _(e, t) {
4846
4847
  for (let [t] of Object.entries(p)) {
4847
4848
  let n = await g(e, t);
4848
4849
  if (n.size > 0) {
4849
- if (t === "content_nodes" && !n.has("disabledRegionsJson")) try {
4850
- await e.prepare("ALTER TABLE \"content_nodes\" ADD COLUMN disabledRegionsJson TEXT DEFAULT '{}';").run();
4851
- } catch {}
4850
+ if (t === "content_nodes") {
4851
+ if (!n.has("disabledRegionsJson")) try {
4852
+ await e.prepare("ALTER TABLE \"content_nodes\" ADD COLUMN disabledRegionsJson TEXT DEFAULT '{}';").run();
4853
+ } catch {}
4854
+ if (!n.has("hasUnpublishedChanges")) try {
4855
+ await e.prepare("ALTER TABLE \"content_nodes\" ADD COLUMN hasUnpublishedChanges INTEGER DEFAULT 0;").run();
4856
+ } catch {}
4857
+ }
4852
4858
  if (t === "assets") {
4853
4859
  if (!n.has("parentAssetId")) try {
4854
4860
  await e.prepare("ALTER TABLE \"assets\" ADD COLUMN parentAssetId TEXT REFERENCES assets(id) ON DELETE SET NULL;").run();
@@ -6252,7 +6258,7 @@ V.get("/", async (e) => {
6252
6258
  if (isNaN(r)) return e.json({ error: "Invalid Node ID" }, 400);
6253
6259
  let i = await t.prepare("SELECT * FROM content_nodes WHERE id = ?").get(r);
6254
6260
  if (!i) return e.json({ error: "Node not found" }, 404);
6255
- let a = (i.status === "draft" || !i.status) && !!i.publishedAt, o = {
6261
+ let a = i.status === "draft" || !!i.hasUnpublishedChanges, o = {
6256
6262
  id: i.id,
6257
6263
  title: i.title,
6258
6264
  slug: i.slug,
@@ -6364,7 +6370,7 @@ V.get("/", async (e) => {
6364
6370
  });
6365
6371
  }
6366
6372
  let O = await Promise.all(w.map(async (e) => {
6367
- let n = (e.status === "draft" || !e.status) && !!e.publishedAt, r = {
6373
+ let n = e.status === "draft" || !!e.hasUnpublishedChanges, r = {
6368
6374
  id: e.id,
6369
6375
  title: e.title,
6370
6376
  slug: e.slug,
@@ -6400,37 +6406,33 @@ V.get("/", async (e) => {
6400
6406
  }), V.post("/", async (e) => {
6401
6407
  let t = e.get("db"), n = await e.req.json(), r = n.node || n.activeNode || n, i = r.id || n.id, a = i != null && i !== "" && !isNaN(Number(i)) ? Number(i) : null, { title: o, slug: s, language: c, nodeType: l, contentType: u, isHidden: d, hidden: f, is_hidden: p, blocks: m, channels: h, trees: g, ..._ } = r, { cleanedData: v, assetRefs: y } = ae(H(_)), b = fe(d === void 0 ? f === void 0 ? p : f : d), x = c || "en", S = l || u || "page", C = e.get("user")?.id || null, w = a, T = /* @__PURE__ */ new Set(), E = s === void 0 ? null : de(s);
6402
6408
  if (E) {
6403
- let n = !1, r = [];
6404
- if (g !== void 0 && Array.isArray(g) && g.length > 0) for (let e of g) r.push({
6409
+ let n = [];
6410
+ if (g !== void 0 && Array.isArray(g) && g.length > 0) for (let e of g) n.push({
6405
6411
  treeId: Number(e.treeId),
6406
6412
  parentId: pe(e.parentId ?? e._draftParentId ?? null)
6407
6413
  });
6408
6414
  else if (a) {
6409
- let e = await t.prepare("SELECT treeId, parentId FROM tree_nodes WHERE contentId = ?").all(a), n = Array.isArray(e) ? e : e?.results || [];
6410
- for (let e of n) r.push({
6415
+ let e = await t.prepare("SELECT treeId, parentId FROM tree_nodes WHERE contentId = ?").all(a), r = Array.isArray(e) ? e : e?.results || [];
6416
+ for (let e of r) n.push({
6411
6417
  treeId: Number(e.treeId),
6412
6418
  parentId: e.parentId === null ? null : Number(e.parentId)
6413
6419
  });
6414
6420
  }
6415
- for (let e of r) {
6416
- let r = e.parentId === null ? "tn.parentId IS NULL" : "tn.parentId = ?", i = e.parentId === null ? [e.treeId, E] : [
6417
- e.treeId,
6418
- e.parentId,
6421
+ for (let r of n) {
6422
+ let n = r.parentId === null ? "tn.parentId IS NULL" : "tn.parentId = ?", i = r.parentId === null ? [r.treeId, E] : [
6423
+ r.treeId,
6424
+ r.parentId,
6419
6425
  E
6420
6426
  ], o = `
6421
6427
  SELECT cn.id FROM tree_nodes tn
6422
6428
  INNER JOIN content_nodes cn ON tn.contentId = cn.id
6423
- WHERE tn.treeId = ? AND ${r} AND cn.slug = ? AND (cn.deletedAt IS NULL OR cn.deletedAt = '')
6429
+ WHERE tn.treeId = ? AND ${n} AND cn.slug = ? AND (cn.deletedAt IS NULL OR cn.deletedAt = '')
6424
6430
  `;
6425
- if (a && (o += " AND cn.id != ?", i.push(a)), o += " LIMIT 1", await t.prepare(o).get(...i)) {
6426
- n = !0;
6427
- break;
6428
- }
6431
+ if (a && (o += " AND cn.id != ?", i.push(a)), o += " LIMIT 1", await t.prepare(o).get(...i)) return e.json({
6432
+ error: `The slug '${E}' is already in use by another page in this section.`,
6433
+ field: "slug"
6434
+ }, 409);
6429
6435
  }
6430
- if (n) return e.json({
6431
- error: `The slug '${E}' is already in use by another page in this section.`,
6432
- field: "slug"
6433
- }, 409);
6434
6436
  }
6435
6437
  if (a) {
6436
6438
  let e = await t.prepare("SELECT title, slug, language, contentType, draftDataJson, dataJson, publishedAt, status FROM content_nodes WHERE id = ?").get(a), n = e?.draftDataJson || e?.dataJson || "{}";
@@ -6452,10 +6454,10 @@ V.get("/", async (e) => {
6452
6454
  let d = JSON.stringify({
6453
6455
  ...u,
6454
6456
  ...v
6455
- }), f = e?.status === "published" || e?.publishedAt ? "published" : "draft";
6456
- await t.prepare("\n UPDATE content_nodes \n SET title = ?, slug = ?, language = ?, contentType = ?, isHidden = ?, status = ?, draftDataJson = ?, updatedById = ?, updatedAt = CURRENT_TIMESTAMP\n WHERE id = ?\n ").run(r, i, c, s, b, f, d, C, a);
6457
+ }), f = e?.status === "published" || e?.publishedAt ? "published" : "draft", p = +(f === "published");
6458
+ await t.prepare("\n UPDATE content_nodes \n SET title = ?, slug = ?, language = ?, contentType = ?, isHidden = ?, status = ?, draftDataJson = ?, hasUnpublishedChanges = ?, updatedById = ?, updatedAt = CURRENT_TIMESTAMP\n WHERE id = ?\n ").run(r, i, c, s, b, f, d, p, C, a);
6457
6459
  } else {
6458
- let e = await t.prepare("\n INSERT INTO content_nodes (contentType, title, slug, language, isHidden, status, draftDataJson, dataJson, createdById, updatedById)\n VALUES (?, ?, ?, ?, ?, 'draft', ?, NULL, ?, ?)\n ").run(S, o || "Untitled", E, x, b, JSON.stringify(v), C, C);
6460
+ let e = await t.prepare("\n INSERT INTO content_nodes (contentType, title, slug, language, isHidden, status, draftDataJson, dataJson, hasUnpublishedChanges, createdById, updatedById)\n VALUES (?, ?, ?, ?, ?, 'draft', ?, NULL, 0, ?, ?)\n ").run(S, o || "Untitled", E, x, b, JSON.stringify(v), C, C);
6459
6461
  w = Number(e.lastInsertRowid);
6460
6462
  }
6461
6463
  if (h !== void 0 && Array.isArray(h) && w) {
@@ -6518,7 +6520,7 @@ V.get("/", async (e) => {
6518
6520
  c = typeof o.draftDataJson == "string" ? JSON.parse(o.draftDataJson) : o.draftDataJson || {};
6519
6521
  } catch {}
6520
6522
  let l = (s.title ?? o.title ?? "").trim(), u = (c.title ?? n.title ?? o.title ?? "").trim(), d = (s.slug ?? o.slug ?? "").trim(), f = (c.slug ?? n.slug ?? o.slug ?? "").trim(), p = l !== "" && u !== "" && l !== u || d !== "" && f !== "" && d !== f, m = o.draftDataJson || o.dataJson || "{}";
6521
- await t.prepare("\n UPDATE content_nodes\n SET publishedDataJson = ?, dataJson = ?, publishedAt = CURRENT_TIMESTAMP, status = 'published', updatedById = ?, updatedAt = CURRENT_TIMESTAMP\n WHERE id = ?\n ").run(m, m, a, i), await t.prepare("DELETE FROM content_blocks WHERE contentId = ? AND isDraft = 0").run(i);
6523
+ await t.prepare("\n UPDATE content_nodes\n SET publishedDataJson = ?, dataJson = ?, publishedAt = CURRENT_TIMESTAMP, status = 'published', hasUnpublishedChanges = 0, updatedById = ?, updatedAt = CURRENT_TIMESTAMP\n WHERE id = ?\n ").run(m, m, a, i), await t.prepare("DELETE FROM content_blocks WHERE contentId = ? AND isDraft = 0").run(i);
6522
6524
  let h = await t.prepare("SELECT * FROM content_blocks WHERE contentId = ? AND isDraft = 1 ORDER BY sortOrder ASC").all(i), g = Array.isArray(h) ? h : h?.results || [];
6523
6525
  if (g.length > 0) {
6524
6526
  let e = [], n = [];
@@ -6542,7 +6544,8 @@ V.get("/", async (e) => {
6542
6544
  id: i,
6543
6545
  status: "published",
6544
6546
  version: _,
6545
- publishedAt: v.publishedAt
6547
+ publishedAt: v.publishedAt,
6548
+ hasUnpublishedChanges: !1
6546
6549
  });
6547
6550
  }), V.delete("/", async (e) => {
6548
6551
  let t = e.get("db"), n = e.req.query("id");
@@ -6601,7 +6604,7 @@ V.get("/", async (e) => {
6601
6604
  } catch {
6602
6605
  return e.json({ error: "Corrupt snapshot data" }, 500);
6603
6606
  }
6604
- if (await t.prepare("\n UPDATE content_nodes\n SET draftDataJson = ?, title = ?, slug = ?, updatedById = ?, updatedAt = CURRENT_TIMESTAMP, status = 'draft'\n WHERE id = ?\n ").run(o.node?.dataJson || "{}", o.node?.title || "Restored Document", o.node?.slug || null, i, n), await t.prepare("DELETE FROM content_blocks WHERE contentId = ? AND isDraft = 1").run(n), o.blocks && Array.isArray(o.blocks) && o.blocks.length > 0) {
6607
+ if (await t.prepare("\n UPDATE content_nodes\n SET draftDataJson = ?, title = ?, slug = ?, updatedById = ?, updatedAt = CURRENT_TIMESTAMP, status = 'draft', hasUnpublishedChanges = 1\n WHERE id = ?\n ").run(o.node?.dataJson || "{}", o.node?.title || "Restored Document", o.node?.slug || null, i, n), await t.prepare("DELETE FROM content_blocks WHERE contentId = ? AND isDraft = 1").run(n), o.blocks && Array.isArray(o.blocks) && o.blocks.length > 0) {
6605
6608
  let e = [], r = [];
6606
6609
  for (let t of o.blocks) e.push("(?, ?, ?, ?, ?, 1)"), r.push(n, t.sortOrder, t.elementType, t.dataJson, t.region || "content");
6607
6610
  await t.prepare(`INSERT INTO content_blocks (contentId, sortOrder, elementType, dataJson, region, isDraft) VALUES ${e.join(", ")}`).run(...r);
@@ -6647,7 +6650,7 @@ G.get("/tree.json", async (e) => {
6647
6650
  e && e.id && (i = Number(e.id));
6648
6651
  }
6649
6652
  } else i = Number(n);
6650
- let a = await t.prepare("\n SELECT \n t.id as treeNodeId,\n t.treeId,\n t.contentId,\n t.parentId,\n t.sortOrder,\n c.title,\n c.slug,\n c.language,\n c.contentType as nodeType,\n c.isHidden,\n c.status,\n c.publishedAt,\n c.dataJson,\n c.draftDataJson,\n (SELECT COUNT(*) FROM node_assets WHERE nodeId = t.contentId) as assetCount\n FROM tree_nodes t\n INNER JOIN content_nodes c ON t.contentId = c.id\n WHERE t.treeId = ? AND (c.deletedAt IS NULL OR c.deletedAt = '')\n ORDER BY t.sortOrder ASC\n ").all(i), o = Array.isArray(a) ? a : a?.results || [], s = [], c = /* @__PURE__ */ new Set();
6653
+ let a = await t.prepare("\n SELECT \n t.id as treeNodeId,\n t.treeId,\n t.contentId,\n t.parentId,\n t.sortOrder,\n c.title,\n c.slug,\n c.language,\n c.contentType as nodeType,\n c.isHidden,\n c.status,\n c.publishedAt,\n c.hasUnpublishedChanges,\n c.dataJson,\n c.draftDataJson,\n (SELECT COUNT(*) FROM node_assets WHERE nodeId = t.contentId) as assetCount\n FROM tree_nodes t\n INNER JOIN content_nodes c ON t.contentId = c.id\n WHERE t.treeId = ? AND (c.deletedAt IS NULL OR c.deletedAt = '')\n ORDER BY t.sortOrder ASC\n ").all(i), o = Array.isArray(a) ? a : a?.results || [], s = [], c = /* @__PURE__ */ new Set();
6651
6654
  for (let e of o) {
6652
6655
  let t = e.contentId;
6653
6656
  c.has(t) || (c.add(t), s.push(e));
@@ -6665,7 +6668,7 @@ G.get("/tree.json", async (e) => {
6665
6668
  let { dataJson: r, draftDataJson: i, ...a } = e, o = {
6666
6669
  ...a,
6667
6670
  ...t
6668
- }, s = Number(e.isHidden) === 1 || o.hidden === !0 || o.hidden === 1 || o.hidden === "true", c = (e.status === "draft" || !e.status) && !!e.publishedAt;
6671
+ }, s = Number(e.isHidden) === 1 || o.hidden === !0 || o.hidden === 1 || o.hidden === "true", c = e.status === "draft" || !!e.hasUnpublishedChanges;
6669
6672
  return {
6670
6673
  ...o,
6671
6674
  id: e.contentId,
package/dist/index.html CHANGED
@@ -4,8 +4,10 @@
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <title>KAMA</title>
7
- <script type="module" crossorigin src="/assets/index-ckG1oyv-.js"></script>
8
- <link rel="stylesheet" crossorigin href="/assets/index-BSBvGvQz.css">
7
+ <link rel="icon" href="/favicon.png">
8
+ <link rel="apple-touch-icon" sizes="180x180" href="/favicon.png">
9
+ <script type="module" crossorigin src="/assets/index-DknACOqv.js"></script>
10
+ <link rel="stylesheet" crossorigin href="/assets/index-BJ80E0Sz.css">
9
11
  </head>
10
12
  <body>
11
13
  <div id="app"></div>
package/dist/index.js CHANGED
@@ -3803,6 +3803,7 @@ var u = /* @__PURE__ */ o({
3803
3803
  label: "HTML",
3804
3804
  type: "textarea",
3805
3805
  public: !0,
3806
+ editor: !1,
3806
3807
  rules: {}
3807
3808
  } },
3808
3809
  tabs: { access: {
@@ -4817,7 +4818,7 @@ var u = /* @__PURE__ */ o({
4817
4818
  channels: "\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n key TEXT UNIQUE NOT NULL,\n label TEXT NOT NULL,\n channelType TEXT,\n domain TEXT,\n baseUrl TEXT,\n defaultLanguage TEXT DEFAULT 'en',\n isHidden INTEGER NOT NULL DEFAULT 0,\n dataJson TEXT,\n createdById TEXT,\n updatedById TEXT,\n createdAt TEXT DEFAULT CURRENT_TIMESTAMP,\n updatedAt TEXT DEFAULT CURRENT_TIMESTAMP,\n FOREIGN KEY (createdById) REFERENCES users(id) ON DELETE SET NULL,\n FOREIGN KEY (updatedById) REFERENCES users(id) ON DELETE SET NULL\n ",
4818
4819
  trees: "\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n key TEXT UNIQUE NOT NULL,\n label TEXT NOT NULL,\n treeType TEXT,\n channelId INTEGER,\n isHidden INTEGER NOT NULL DEFAULT 0,\n dataJson TEXT,\n createdById TEXT,\n updatedById TEXT,\n createdAt TEXT DEFAULT CURRENT_TIMESTAMP,\n updatedAt TEXT DEFAULT CURRENT_TIMESTAMP,\n FOREIGN KEY (channelId) REFERENCES channels(id) ON DELETE SET NULL,\n FOREIGN KEY (createdById) REFERENCES users(id) ON DELETE SET NULL,\n FOREIGN KEY (updatedById) REFERENCES users(id) ON DELETE SET NULL\n ",
4819
4820
  channel_trees: "\n channelId INTEGER NOT NULL,\n treeId INTEGER NOT NULL,\n key TEXT NOT NULL DEFAULT 'main',\n metaJson TEXT,\n PRIMARY KEY (channelId, treeId, key),\n FOREIGN KEY (channelId) REFERENCES channels(id) ON DELETE CASCADE,\n FOREIGN KEY (treeId) REFERENCES trees(id) ON DELETE CASCADE\n ",
4820
- content_nodes: "\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n contentType TEXT NOT NULL,\n title TEXT NOT NULL,\n slug TEXT,\n language TEXT DEFAULT 'en',\n isHidden INTEGER NOT NULL DEFAULT 0,\n status TEXT DEFAULT 'draft',\n disabledRegionsJson TEXT DEFAULT '{}',\n dataJson TEXT,\n draftDataJson TEXT,\n publishedDataJson TEXT,\n publishedAt TEXT,\n createdById TEXT,\n updatedById TEXT,\n createdAt TEXT DEFAULT CURRENT_TIMESTAMP,\n updatedAt TEXT DEFAULT CURRENT_TIMESTAMP,\n deletedAt TEXT,\n FOREIGN KEY (createdById) REFERENCES users(id) ON DELETE SET NULL,\n FOREIGN KEY (updatedById) REFERENCES users(id) ON DELETE SET NULL\n ",
4821
+ content_nodes: "\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n contentType TEXT NOT NULL,\n title TEXT NOT NULL,\n slug TEXT,\n language TEXT DEFAULT 'en',\n isHidden INTEGER NOT NULL DEFAULT 0,\n status TEXT DEFAULT 'draft',\n hasUnpublishedChanges INTEGER DEFAULT 0,\n disabledRegionsJson TEXT DEFAULT '{}',\n dataJson TEXT,\n draftDataJson TEXT,\n publishedDataJson TEXT,\n publishedAt TEXT,\n createdById TEXT,\n updatedById TEXT,\n createdAt TEXT DEFAULT CURRENT_TIMESTAMP,\n updatedAt TEXT DEFAULT CURRENT_TIMESTAMP,\n deletedAt TEXT,\n FOREIGN KEY (createdById) REFERENCES users(id) ON DELETE SET NULL,\n FOREIGN KEY (updatedById) REFERENCES users(id) ON DELETE SET NULL\n ",
4821
4822
  node_channels: "\n nodeId INTEGER NOT NULL,\n channelId INTEGER NOT NULL,\n PRIMARY KEY (nodeId, channelId),\n FOREIGN KEY (nodeId) REFERENCES content_nodes(id) ON DELETE CASCADE,\n FOREIGN KEY (channelId) REFERENCES channels(id) ON DELETE CASCADE\n ",
4822
4823
  tree_nodes: "\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n treeId INTEGER NOT NULL,\n contentId INTEGER NOT NULL,\n parentId INTEGER,\n sortOrder INTEGER DEFAULT 0,\n FOREIGN KEY (treeId) REFERENCES trees(id) ON DELETE CASCADE,\n FOREIGN KEY (contentId) REFERENCES content_nodes(id) ON DELETE CASCADE,\n FOREIGN KEY (parentId) REFERENCES tree_nodes(id) ON DELETE CASCADE\n ",
4823
4824
  content_blocks: "\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n contentId INTEGER NOT NULL,\n region TEXT DEFAULT 'main',\n elementType TEXT NOT NULL,\n dataJson TEXT,\n sortOrder INTEGER DEFAULT 0,\n isDraft INTEGER NOT NULL DEFAULT 1,\n FOREIGN KEY (contentId) REFERENCES content_nodes(id) ON DELETE CASCADE\n ",
@@ -4848,9 +4849,14 @@ async function _(e, t) {
4848
4849
  for (let [t] of Object.entries(p)) {
4849
4850
  let n = await g(e, t);
4850
4851
  if (n.size > 0) {
4851
- if (t === "content_nodes" && !n.has("disabledRegionsJson")) try {
4852
- await e.prepare("ALTER TABLE \"content_nodes\" ADD COLUMN disabledRegionsJson TEXT DEFAULT '{}';").run();
4853
- } catch {}
4852
+ if (t === "content_nodes") {
4853
+ if (!n.has("disabledRegionsJson")) try {
4854
+ await e.prepare("ALTER TABLE \"content_nodes\" ADD COLUMN disabledRegionsJson TEXT DEFAULT '{}';").run();
4855
+ } catch {}
4856
+ if (!n.has("hasUnpublishedChanges")) try {
4857
+ await e.prepare("ALTER TABLE \"content_nodes\" ADD COLUMN hasUnpublishedChanges INTEGER DEFAULT 0;").run();
4858
+ } catch {}
4859
+ }
4854
4860
  if (t === "assets") {
4855
4861
  if (!n.has("parentAssetId")) try {
4856
4862
  await e.prepare("ALTER TABLE \"assets\" ADD COLUMN parentAssetId TEXT REFERENCES assets(id) ON DELETE SET NULL;").run();
@@ -6270,7 +6276,7 @@ V.get("/", async (e) => {
6270
6276
  if (isNaN(r)) return e.json({ error: "Invalid Node ID" }, 400);
6271
6277
  let i = await t.prepare("SELECT * FROM content_nodes WHERE id = ?").get(r);
6272
6278
  if (!i) return e.json({ error: "Node not found" }, 404);
6273
- let a = (i.status === "draft" || !i.status) && !!i.publishedAt, o = {
6279
+ let a = i.status === "draft" || !!i.hasUnpublishedChanges, o = {
6274
6280
  id: i.id,
6275
6281
  title: i.title,
6276
6282
  slug: i.slug,
@@ -6382,7 +6388,7 @@ V.get("/", async (e) => {
6382
6388
  });
6383
6389
  }
6384
6390
  let O = await Promise.all(w.map(async (e) => {
6385
- let n = (e.status === "draft" || !e.status) && !!e.publishedAt, r = {
6391
+ let n = e.status === "draft" || !!e.hasUnpublishedChanges, r = {
6386
6392
  id: e.id,
6387
6393
  title: e.title,
6388
6394
  slug: e.slug,
@@ -6418,37 +6424,33 @@ V.get("/", async (e) => {
6418
6424
  }), V.post("/", async (e) => {
6419
6425
  let t = e.get("db"), n = await e.req.json(), r = n.node || n.activeNode || n, i = r.id || n.id, a = i != null && i !== "" && !isNaN(Number(i)) ? Number(i) : null, { title: o, slug: s, language: c, nodeType: l, contentType: u, isHidden: d, hidden: f, is_hidden: p, blocks: m, channels: h, trees: g, ..._ } = r, { cleanedData: v, assetRefs: y } = ae(H(_)), b = fe(d === void 0 ? f === void 0 ? p : f : d), x = c || "en", S = l || u || "page", C = e.get("user")?.id || null, w = a, T = /* @__PURE__ */ new Set(), E = s === void 0 ? null : de(s);
6420
6426
  if (E) {
6421
- let n = !1, r = [];
6422
- if (g !== void 0 && Array.isArray(g) && g.length > 0) for (let e of g) r.push({
6427
+ let n = [];
6428
+ if (g !== void 0 && Array.isArray(g) && g.length > 0) for (let e of g) n.push({
6423
6429
  treeId: Number(e.treeId),
6424
6430
  parentId: pe(e.parentId ?? e._draftParentId ?? null)
6425
6431
  });
6426
6432
  else if (a) {
6427
- let e = await t.prepare("SELECT treeId, parentId FROM tree_nodes WHERE contentId = ?").all(a), n = Array.isArray(e) ? e : e?.results || [];
6428
- for (let e of n) r.push({
6433
+ let e = await t.prepare("SELECT treeId, parentId FROM tree_nodes WHERE contentId = ?").all(a), r = Array.isArray(e) ? e : e?.results || [];
6434
+ for (let e of r) n.push({
6429
6435
  treeId: Number(e.treeId),
6430
6436
  parentId: e.parentId === null ? null : Number(e.parentId)
6431
6437
  });
6432
6438
  }
6433
- for (let e of r) {
6434
- let r = e.parentId === null ? "tn.parentId IS NULL" : "tn.parentId = ?", i = e.parentId === null ? [e.treeId, E] : [
6435
- e.treeId,
6436
- e.parentId,
6439
+ for (let r of n) {
6440
+ let n = r.parentId === null ? "tn.parentId IS NULL" : "tn.parentId = ?", i = r.parentId === null ? [r.treeId, E] : [
6441
+ r.treeId,
6442
+ r.parentId,
6437
6443
  E
6438
6444
  ], o = `
6439
6445
  SELECT cn.id FROM tree_nodes tn
6440
6446
  INNER JOIN content_nodes cn ON tn.contentId = cn.id
6441
- WHERE tn.treeId = ? AND ${r} AND cn.slug = ? AND (cn.deletedAt IS NULL OR cn.deletedAt = '')
6447
+ WHERE tn.treeId = ? AND ${n} AND cn.slug = ? AND (cn.deletedAt IS NULL OR cn.deletedAt = '')
6442
6448
  `;
6443
- if (a && (o += " AND cn.id != ?", i.push(a)), o += " LIMIT 1", await t.prepare(o).get(...i)) {
6444
- n = !0;
6445
- break;
6446
- }
6449
+ if (a && (o += " AND cn.id != ?", i.push(a)), o += " LIMIT 1", await t.prepare(o).get(...i)) return e.json({
6450
+ error: `The slug '${E}' is already in use by another page in this section.`,
6451
+ field: "slug"
6452
+ }, 409);
6447
6453
  }
6448
- if (n) return e.json({
6449
- error: `The slug '${E}' is already in use by another page in this section.`,
6450
- field: "slug"
6451
- }, 409);
6452
6454
  }
6453
6455
  if (a) {
6454
6456
  let e = await t.prepare("SELECT title, slug, language, contentType, draftDataJson, dataJson, publishedAt, status FROM content_nodes WHERE id = ?").get(a), n = e?.draftDataJson || e?.dataJson || "{}";
@@ -6470,10 +6472,10 @@ V.get("/", async (e) => {
6470
6472
  let d = JSON.stringify({
6471
6473
  ...u,
6472
6474
  ...v
6473
- }), f = e?.status === "published" || e?.publishedAt ? "published" : "draft";
6474
- await t.prepare("\n UPDATE content_nodes \n SET title = ?, slug = ?, language = ?, contentType = ?, isHidden = ?, status = ?, draftDataJson = ?, updatedById = ?, updatedAt = CURRENT_TIMESTAMP\n WHERE id = ?\n ").run(r, i, c, s, b, f, d, C, a);
6475
+ }), f = e?.status === "published" || e?.publishedAt ? "published" : "draft", p = +(f === "published");
6476
+ await t.prepare("\n UPDATE content_nodes \n SET title = ?, slug = ?, language = ?, contentType = ?, isHidden = ?, status = ?, draftDataJson = ?, hasUnpublishedChanges = ?, updatedById = ?, updatedAt = CURRENT_TIMESTAMP\n WHERE id = ?\n ").run(r, i, c, s, b, f, d, p, C, a);
6475
6477
  } else {
6476
- let e = await t.prepare("\n INSERT INTO content_nodes (contentType, title, slug, language, isHidden, status, draftDataJson, dataJson, createdById, updatedById)\n VALUES (?, ?, ?, ?, ?, 'draft', ?, NULL, ?, ?)\n ").run(S, o || "Untitled", E, x, b, JSON.stringify(v), C, C);
6478
+ let e = await t.prepare("\n INSERT INTO content_nodes (contentType, title, slug, language, isHidden, status, draftDataJson, dataJson, hasUnpublishedChanges, createdById, updatedById)\n VALUES (?, ?, ?, ?, ?, 'draft', ?, NULL, 0, ?, ?)\n ").run(S, o || "Untitled", E, x, b, JSON.stringify(v), C, C);
6477
6479
  w = Number(e.lastInsertRowid);
6478
6480
  }
6479
6481
  if (h !== void 0 && Array.isArray(h) && w) {
@@ -6536,7 +6538,7 @@ V.get("/", async (e) => {
6536
6538
  c = typeof o.draftDataJson == "string" ? JSON.parse(o.draftDataJson) : o.draftDataJson || {};
6537
6539
  } catch {}
6538
6540
  let l = (s.title ?? o.title ?? "").trim(), u = (c.title ?? n.title ?? o.title ?? "").trim(), d = (s.slug ?? o.slug ?? "").trim(), f = (c.slug ?? n.slug ?? o.slug ?? "").trim(), p = l !== "" && u !== "" && l !== u || d !== "" && f !== "" && d !== f, m = o.draftDataJson || o.dataJson || "{}";
6539
- await t.prepare("\n UPDATE content_nodes\n SET publishedDataJson = ?, dataJson = ?, publishedAt = CURRENT_TIMESTAMP, status = 'published', updatedById = ?, updatedAt = CURRENT_TIMESTAMP\n WHERE id = ?\n ").run(m, m, a, i), await t.prepare("DELETE FROM content_blocks WHERE contentId = ? AND isDraft = 0").run(i);
6541
+ await t.prepare("\n UPDATE content_nodes\n SET publishedDataJson = ?, dataJson = ?, publishedAt = CURRENT_TIMESTAMP, status = 'published', hasUnpublishedChanges = 0, updatedById = ?, updatedAt = CURRENT_TIMESTAMP\n WHERE id = ?\n ").run(m, m, a, i), await t.prepare("DELETE FROM content_blocks WHERE contentId = ? AND isDraft = 0").run(i);
6540
6542
  let h = await t.prepare("SELECT * FROM content_blocks WHERE contentId = ? AND isDraft = 1 ORDER BY sortOrder ASC").all(i), g = Array.isArray(h) ? h : h?.results || [];
6541
6543
  if (g.length > 0) {
6542
6544
  let e = [], n = [];
@@ -6560,7 +6562,8 @@ V.get("/", async (e) => {
6560
6562
  id: i,
6561
6563
  status: "published",
6562
6564
  version: _,
6563
- publishedAt: v.publishedAt
6565
+ publishedAt: v.publishedAt,
6566
+ hasUnpublishedChanges: !1
6564
6567
  });
6565
6568
  }), V.delete("/", async (e) => {
6566
6569
  let t = e.get("db"), n = e.req.query("id");
@@ -6619,7 +6622,7 @@ V.get("/", async (e) => {
6619
6622
  } catch {
6620
6623
  return e.json({ error: "Corrupt snapshot data" }, 500);
6621
6624
  }
6622
- if (await t.prepare("\n UPDATE content_nodes\n SET draftDataJson = ?, title = ?, slug = ?, updatedById = ?, updatedAt = CURRENT_TIMESTAMP, status = 'draft'\n WHERE id = ?\n ").run(o.node?.dataJson || "{}", o.node?.title || "Restored Document", o.node?.slug || null, i, n), await t.prepare("DELETE FROM content_blocks WHERE contentId = ? AND isDraft = 1").run(n), o.blocks && Array.isArray(o.blocks) && o.blocks.length > 0) {
6625
+ if (await t.prepare("\n UPDATE content_nodes\n SET draftDataJson = ?, title = ?, slug = ?, updatedById = ?, updatedAt = CURRENT_TIMESTAMP, status = 'draft', hasUnpublishedChanges = 1\n WHERE id = ?\n ").run(o.node?.dataJson || "{}", o.node?.title || "Restored Document", o.node?.slug || null, i, n), await t.prepare("DELETE FROM content_blocks WHERE contentId = ? AND isDraft = 1").run(n), o.blocks && Array.isArray(o.blocks) && o.blocks.length > 0) {
6623
6626
  let e = [], r = [];
6624
6627
  for (let t of o.blocks) e.push("(?, ?, ?, ?, ?, 1)"), r.push(n, t.sortOrder, t.elementType, t.dataJson, t.region || "content");
6625
6628
  await t.prepare(`INSERT INTO content_blocks (contentId, sortOrder, elementType, dataJson, region, isDraft) VALUES ${e.join(", ")}`).run(...r);
@@ -6667,7 +6670,7 @@ G.get("/tree.json", async (e) => {
6667
6670
  e && e.id && (i = Number(e.id));
6668
6671
  }
6669
6672
  } else i = Number(n);
6670
- let a = await t.prepare("\n SELECT \n t.id as treeNodeId,\n t.treeId,\n t.contentId,\n t.parentId,\n t.sortOrder,\n c.title,\n c.slug,\n c.language,\n c.contentType as nodeType,\n c.isHidden,\n c.status,\n c.publishedAt,\n c.dataJson,\n c.draftDataJson,\n (SELECT COUNT(*) FROM node_assets WHERE nodeId = t.contentId) as assetCount\n FROM tree_nodes t\n INNER JOIN content_nodes c ON t.contentId = c.id\n WHERE t.treeId = ? AND (c.deletedAt IS NULL OR c.deletedAt = '')\n ORDER BY t.sortOrder ASC\n ").all(i), o = Array.isArray(a) ? a : a?.results || [], s = [], c = /* @__PURE__ */ new Set();
6673
+ let a = await t.prepare("\n SELECT \n t.id as treeNodeId,\n t.treeId,\n t.contentId,\n t.parentId,\n t.sortOrder,\n c.title,\n c.slug,\n c.language,\n c.contentType as nodeType,\n c.isHidden,\n c.status,\n c.publishedAt,\n c.hasUnpublishedChanges,\n c.dataJson,\n c.draftDataJson,\n (SELECT COUNT(*) FROM node_assets WHERE nodeId = t.contentId) as assetCount\n FROM tree_nodes t\n INNER JOIN content_nodes c ON t.contentId = c.id\n WHERE t.treeId = ? AND (c.deletedAt IS NULL OR c.deletedAt = '')\n ORDER BY t.sortOrder ASC\n ").all(i), o = Array.isArray(a) ? a : a?.results || [], s = [], c = /* @__PURE__ */ new Set();
6671
6674
  for (let e of o) {
6672
6675
  let t = e.contentId;
6673
6676
  c.has(t) || (c.add(t), s.push(e));
@@ -6685,7 +6688,7 @@ G.get("/tree.json", async (e) => {
6685
6688
  let { dataJson: r, draftDataJson: i, ...a } = e, o = {
6686
6689
  ...a,
6687
6690
  ...t
6688
- }, s = Number(e.isHidden) === 1 || o.hidden === !0 || o.hidden === 1 || o.hidden === "true", c = (e.status === "draft" || !e.status) && !!e.publishedAt;
6691
+ }, s = Number(e.isHidden) === 1 || o.hidden === !0 || o.hidden === 1 || o.hidden === "true", c = e.status === "draft" || !!e.hasUnpublishedChanges;
6689
6692
  return {
6690
6693
  ...o,
6691
6694
  id: e.contentId,
@@ -20,7 +20,7 @@ async function u() {
20
20
  if (n(d)) u = (await import(t(d).href)).compileDefinitions;
21
21
  else if (n(f)) u = (await import(t(f).href)).compileDefinitions;
22
22
  else try {
23
- u = (await import("./dist-a3ACJkRE.js")).compileDefinitions;
23
+ u = (await import("./dist-DvbQty0F.js")).compileDefinitions;
24
24
  } catch (e) {
25
25
  console.error("❌ Could not resolve Kama Schema Engine:", e), process.exit(1);
26
26
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brightsideoy/kama",
3
- "version": "0.1.0-alpha.149",
3
+ "version": "0.1.0-alpha.151",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
package/schema.sql CHANGED
@@ -92,6 +92,7 @@ CREATE TABLE IF NOT EXISTS "content_nodes" (
92
92
  language TEXT DEFAULT 'en',
93
93
  isHidden INTEGER NOT NULL DEFAULT 0,
94
94
  status TEXT DEFAULT 'draft',
95
+ hasUnpublishedChanges INTEGER DEFAULT 0,
95
96
  disabledRegionsJson TEXT DEFAULT '{}',
96
97
  dataJson TEXT,
97
98
  draftDataJson TEXT,