@brightsideoy/kama 1.0.0-alpha.19 → 1.0.0-alpha.20

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.
@@ -21117,6 +21117,13 @@ var Tb = /* @__PURE__ */ o({
21117
21117
  public: !0,
21118
21118
  allowedLinkTypes: ["tree", "node"],
21119
21119
  rules: {}
21120
+ },
21121
+ sortBy: {
21122
+ label: "Sort by",
21123
+ type: "node-sort",
21124
+ default: "updatedAt_desc",
21125
+ public: !0,
21126
+ rules: {}
21120
21127
  }
21121
21128
  },
21122
21129
  tabs: { access: {
@@ -22086,7 +22093,8 @@ var Tb = /* @__PURE__ */ o({
22086
22093
  nodeTemplate: null,
22087
22094
  treeTemplate: null,
22088
22095
  channelTemplate: null,
22089
- userTemplate: null
22096
+ userTemplate: null,
22097
+ treeExposedFields: ["summary"]
22090
22098
  }, Db = Eb, Ob = {
22091
22099
  content_schemas: "\n id TEXT PRIMARY KEY,\n name TEXT NOT NULL,\n type TEXT UNIQUE NOT NULL,\n schemaJson TEXT NOT NULL,\n isSystem INTEGER DEFAULT 1,\n createdAt TEXT DEFAULT CURRENT_TIMESTAMP,\n updatedAt TEXT DEFAULT CURRENT_TIMESTAMP\n ",
22092
22100
  users: "\n id TEXT PRIMARY KEY,\n email UNIQUE NOT NULL,\n name TEXT NOT NULL,\n globalRole TEXT DEFAULT 'editor',\n createdAt TEXT DEFAULT CURRENT_TIMESTAMP,\n updatedAt TEXT DEFAULT CURRENT_TIMESTAMP\n ",
@@ -23450,7 +23458,8 @@ function px(e) {
23450
23458
  nodeLayouts: e.nodeLayouts || {},
23451
23459
  blockLayouts: e.blockLayouts || {},
23452
23460
  channels: e.channels || {},
23453
- taxonomies: e.taxonomies || {}
23461
+ taxonomies: e.taxonomies || {},
23462
+ treeExposedFields: e.treeExposedFields || ["summary"]
23454
23463
  } : {
23455
23464
  nodes: {},
23456
23465
  trees: {},
@@ -23458,7 +23467,8 @@ function px(e) {
23458
23467
  nodeLayouts: {},
23459
23468
  blockLayouts: {},
23460
23469
  channels: {},
23461
- taxonomies: {}
23470
+ taxonomies: {},
23471
+ treeExposedFields: ["summary"]
23462
23472
  };
23463
23473
  }
23464
23474
  var mx = class {
@@ -25260,7 +25270,8 @@ function Qx(e) {
25260
25270
  nodeTemplate: null,
25261
25271
  treeTemplate: null,
25262
25272
  channelTemplate: null,
25263
- userTemplate: null
25273
+ userTemplate: null,
25274
+ treeExposedFields: ["summary"]
25264
25275
  };
25265
25276
  let { rawNodes: t = {}, rawTrees: n = {}, rawChannels: r = {}, channels: i = {}, rawTaxonomies: a = {}, taxonomies: o = {}, rawBlocks: s = {}, rawElements: c = {}, rawNodeLayouts: l = {}, rawBlockLayouts: u = {}, rawLayouts: d = {}, rawFieldSets: f = {}, rawTemplates: p = {}, nodeTemplate: m = null, treeTemplate: h = null, channelTemplate: g = null, userTemplate: _ = null, nodes: v = {}, trees: y = {}, blocks: b = {}, nodeLayouts: x = {}, blockLayouts: S = {} } = e, C = Object.keys(t).length > 0 ? t : v, w = Object.keys(n).length > 0 ? n : y, T = Object.keys(r).length > 0 ? r : i, ee = Object.keys(a).length > 0 ? a : o, E = Object.keys(s).length > 0 ? s : Object.keys(c).length > 0 ? c : b, D = Object.keys(l).length > 0 ? l : Object.keys(d).length > 0 ? d : x, te = Object.keys(u).length > 0 ? u : S, O = m?.fields || {}, k = {
25266
25277
  ...p,
@@ -25533,7 +25544,15 @@ function Qx(e) {
25533
25544
  let fe = _ ? {
25534
25545
  ..._,
25535
25546
  fields: de
25536
- } : null;
25547
+ } : null, pe = /* @__PURE__ */ new Set(["summary"]);
25548
+ for (let e of Object.values(k)) {
25549
+ let t = e.fields || e;
25550
+ for (let [e, n] of Object.entries(t || {})) n && typeof n == "object" && n.inTree && pe.add(e);
25551
+ }
25552
+ for (let e of Object.values(j)) {
25553
+ for (let [t, n] of Object.entries(e.fields || {})) n?.inTree && pe.add(t);
25554
+ for (let t of Object.values(e.tabs || {})) for (let [e, n] of Object.entries(t.fields || {})) n?.inTree && pe.add(e);
25555
+ }
25537
25556
  return {
25538
25557
  nodes: j,
25539
25558
  trees: re,
@@ -25546,7 +25565,8 @@ function Qx(e) {
25546
25565
  nodeTemplate: m || null,
25547
25566
  treeTemplate: h || null,
25548
25567
  channelTemplate: ue,
25549
- userTemplate: fe
25568
+ userTemplate: fe,
25569
+ treeExposedFields: Array.from(pe)
25550
25570
  };
25551
25571
  }
25552
25572
  var $x = new e(), eS = (e) => {
@@ -26035,21 +26055,30 @@ function fS(e, t) {
26035
26055
  }
26036
26056
  return !0;
26037
26057
  }
26038
- async function pS(e, t, n, r, i) {
26039
- let a = t.filter((e) => e.componentId === "content-feed" || e.componentId === "article-list" || e.componentId === "nodeList" || e.componentId === "node-list");
26040
- await Promise.all(a.map(async (t) => {
26041
- let a = t.data || {}, o = a.nodeType || ["article"], s = (Array.isArray(o) ? o : String(o).split(",")).map((e) => String(e).trim()).filter(Boolean), c = Number(a.limit) || 12, l = Number(a.offset) || 0, u = a.sortBy || "updatedAt", d = new URLSearchParams();
26042
- d.set("nodeType", s.join(",")), d.set("limit", c.toString()), d.set("offset", (l + c).toString()), d.set("sortBy", u), n && n !== "all" && d.set("channelId", String(n));
26043
- let f = `FROM content_nodes WHERE contentType IN (${s.map(() => "?").join(",")}) AND isHidden = 0 AND IFNULL(status, 'published') = 'published'`, p = [...s];
26044
- n && n !== "all" && (f += " AND EXISTS (SELECT 1 FROM node_channels nc WHERE nc.nodeId = content_nodes.id AND nc.channelId = ?)", p.push(Number(n) || n));
26045
- let m = (/* @__PURE__ */ new Date()).toISOString();
26046
- f += " AND IFNULL(json_extract(dataJson, '$.startShowingAt'), '') <= ?", p.push(m), f += " AND IFNULL(json_extract(dataJson, '$.stopShowingAt'), '9999-12-31') >= ?", p.push(m);
26058
+ async function pS(e, t, n, r, i, a) {
26059
+ let o = t.filter((e) => e.componentId === "content-feed" || e.componentId === "article-list" || e.componentId === "nodeList" || e.componentId === "node-list");
26060
+ await Promise.all(o.map(async (t) => {
26061
+ let o = t.data || {}, s = o.nodeType || ["article"], c = (Array.isArray(s) ? s : String(s).split(",")).map((e) => String(e).trim()).filter(Boolean), l = {};
26062
+ if (a) for (let e of c) {
26063
+ l[e] = [];
26064
+ let t = a.nodes?.[e] || {}, n = { ...t.fields || {} };
26065
+ t.tabs && Object.values(t.tabs).forEach((e) => {
26066
+ Object.assign(n, e.fields || {});
26067
+ });
26068
+ for (let [t, r] of Object.entries(n)) (r.showInList || r.showInLists) && l[e].push(t);
26069
+ }
26070
+ let u = Number(o.limit) || 12, d = Number(o.offset) || 0, f = String(o.sortBy || "updatedAt_desc"), [p, m] = f.includes("_") ? f.split("_") : [f, "desc"], h = String(m).toLowerCase() === "asc" ? "ASC" : "DESC", g = String(p).replace(/[^a-zA-Z0-9_]/g, ""), _ = new URLSearchParams();
26071
+ _.set("nodeType", c.join(",")), _.set("limit", u.toString()), _.set("offset", (d + u).toString()), _.set("sortBy", f), n && n !== "all" && _.set("channelId", String(n));
26072
+ let v = `FROM content_nodes WHERE contentType IN (${c.map(() => "?").join(",")}) AND isHidden = 0 AND IFNULL(status, 'published') = 'published'`, y = [...c];
26073
+ n && n !== "all" && (v += " AND EXISTS (SELECT 1 FROM node_channels nc WHERE nc.nodeId = content_nodes.id AND nc.channelId = ?)", y.push(Number(n) || n));
26074
+ let b = (/* @__PURE__ */ new Date()).toISOString();
26075
+ v += " AND IFNULL(json_extract(dataJson, '$.startShowingAt'), '') <= ?", y.push(b), v += " AND IFNULL(json_extract(dataJson, '$.stopShowingAt'), '9999-12-31') >= ?", y.push(b);
26047
26076
  for (let e of [
26048
26077
  "authors",
26049
26078
  "categories",
26050
26079
  "tags"
26051
- ]) if (a[e]) {
26052
- let t = (Array.isArray(a[e]) ? a[e] : [a[e]]).map((e) => {
26080
+ ]) if (o[e]) {
26081
+ let t = (Array.isArray(o[e]) ? o[e] : [o[e]]).map((e) => {
26053
26082
  if (typeof e == "object" && e) {
26054
26083
  if (e.key) return String(e.key);
26055
26084
  if (e.nodeId) return String(e.nodeId);
@@ -26058,93 +26087,100 @@ async function pS(e, t, n, r, i) {
26058
26087
  return String(e);
26059
26088
  }).filter((e) => e !== "undefined" && e !== "null" && e !== "");
26060
26089
  if (t.length > 0) {
26061
- d.set(e, t.join(","));
26090
+ _.set(e, t.join(","));
26062
26091
  let n = t.map(() => "?").join(",");
26063
- f += e === "authors" ? ` AND EXISTS (SELECT 1 FROM node_relations nr WHERE nr.sourceNodeId = content_nodes.id AND nr.fieldKey = ? AND nr.targetNodeId IN (${n}))` : ` AND EXISTS (SELECT 1 FROM node_terms nt INNER JOIN taxonomy_terms tt ON nt.termId = tt.id WHERE nt.nodeId = content_nodes.id AND tt.taxonomy = ? AND tt.key IN (${n}))`, p.push(e, ...t);
26092
+ v += e === "authors" ? ` AND EXISTS (SELECT 1 FROM node_relations nr WHERE nr.sourceNodeId = content_nodes.id AND nr.fieldKey = ? AND nr.targetNodeId IN (${n}))` : ` AND EXISTS (SELECT 1 FROM node_terms nt INNER JOIN taxonomy_terms tt ON nt.termId = tt.id WHERE nt.nodeId = content_nodes.id AND tt.taxonomy = ? AND tt.key IN (${n}))`, y.push(e, ...t);
26064
26093
  }
26065
26094
  }
26066
- let h = "ORDER BY updatedAt DESC";
26067
- u === "published_desc" || u === "createdAt" ? h = "ORDER BY createdAt DESC" : u === "title_asc" && (h = "ORDER BY LOWER(title) ASC");
26068
- let g = `SELECT id, title, slug, language, dataJson, createdAt, updatedAt ${f} ${h} LIMIT ? OFFSET ?`;
26069
- p.push(c, l);
26095
+ let x = `ORDER BY updatedAt ${h}`;
26096
+ g === "createdAt" || g === "published" ? x = `ORDER BY createdAt ${h}` : g === "title" ? x = `ORDER BY LOWER(title) ${h}` : g !== "updatedAt" && g !== "" && (x = `ORDER BY json_extract(dataJson, '$.${g}') ${h}`);
26097
+ let S = `SELECT id, title, slug, language, dataJson, createdAt, updatedAt ${v} ${x} LIMIT ? OFFSET ?`;
26098
+ y.push(u, d);
26070
26099
  try {
26071
- let n = await e.prepare(g).all(...p), o = Array.isArray(n) ? n : n?.results || [];
26072
- t.data.initialItems = o.map((e) => {
26100
+ let n = await e.prepare(S).all(...y), s = Array.isArray(n) ? n : n?.results || [];
26101
+ t.data.initialItems = s.map((e) => {
26073
26102
  let t = {};
26074
26103
  if (e.dataJson) try {
26075
26104
  t = typeof e.dataJson == "string" ? JSON.parse(e.dataJson) : e.dataJson;
26076
26105
  } catch {}
26077
- return i && dS(t.startShowingAt, t.stopShowingAt, i), {
26106
+ i && dS(t.startShowingAt, t.stopShowingAt, i);
26107
+ let n = {};
26108
+ if (a) {
26109
+ let r = l[e.contentType || "article"] || [];
26110
+ for (let e of r) t[e] !== void 0 && (n[e] = t[e]);
26111
+ }
26112
+ return {
26078
26113
  id: e.id,
26079
26114
  title: e.title,
26080
26115
  slug: e.slug,
26081
26116
  language: e.language?.trim() || r || null,
26082
26117
  createdAt: e.createdAt,
26083
26118
  updatedAt: e.updatedAt,
26119
+ ...n,
26084
26120
  excerpt: t.excerpt || "",
26085
26121
  image: t.image || t.coverImage || null,
26086
26122
  author: t.author || null
26087
26123
  };
26088
- }), a.disablePagination !== !0 && a.disablePagination !== "1" && o.length === c ? t.data.loadMoreUrl = `/api/v1/nodes?${d.toString()}` : t.data.loadMoreUrl = null;
26124
+ }), o.disablePagination !== !0 && o.disablePagination !== "1" && s.length === u ? t.data.loadMoreUrl = `/api/v1/nodes?${_.toString()}` : t.data.loadMoreUrl = null;
26089
26125
  } catch (e) {
26090
26126
  console.error("[CMS Hydration] Failed to hydrate content feed block", e), t.data.initialItems = [], t.data.loadMoreUrl = null;
26091
26127
  }
26092
26128
  }));
26093
26129
  }
26094
- async function mS(e, t, n, r, i, a = !1, o, s) {
26130
+ async function mS(e, t, n, r, i, a, o = !1, s, c) {
26095
26131
  if (!t) return { blocks: [] };
26096
- let c = await e.prepare("\n WITH RECURSIVE ancestor_path(contentId, title, slug, parentId, level) AS (\n SELECT t.contentId, c.title, c.slug, t.parentId, 0 FROM tree_nodes t INNER JOIN content_nodes c ON t.contentId = c.id WHERE t.contentId = ? AND t.treeId = ?\n UNION ALL\n SELECT t.contentId, c.title, c.slug, t.parentId, ap.level + 1 FROM tree_nodes t INNER JOIN content_nodes c ON t.contentId = c.id INNER JOIN ancestor_path ap ON t.contentId = ap.parentId AND t.treeId = ?\n )\n SELECT * FROM ancestor_path ORDER BY level ASC\n ").all(t, n, n), l = Array.isArray(c) ? c : c?.results || [];
26097
- if (!l || l.length === 0) return { blocks: [] };
26098
- let u = l.map((e) => e.contentId).filter((e) => e != null);
26099
- if (u.length === 0) return { blocks: [] };
26100
- let d = u.map(() => "?").join(","), f = +!!a, p = await e.prepare(`SELECT * FROM content_blocks WHERE contentId IN (${d}) AND isDraft = ? ORDER BY contentId ASC, sortOrder ASC`).all(...u, f), m = Array.isArray(p) ? p : p?.results || [], h = /* @__PURE__ */ new Map();
26101
- m.forEach((e) => {
26132
+ let l = await e.prepare("\n WITH RECURSIVE ancestor_path(contentId, title, slug, parentId, level) AS (\n SELECT t.contentId, c.title, c.slug, t.parentId, 0 FROM tree_nodes t INNER JOIN content_nodes c ON t.contentId = c.id WHERE t.contentId = ? AND t.treeId = ?\n UNION ALL\n SELECT t.contentId, c.title, c.slug, t.parentId, ap.level + 1 FROM tree_nodes t INNER JOIN content_nodes c ON t.contentId = c.id INNER JOIN ancestor_path ap ON t.contentId = ap.parentId AND t.treeId = ?\n )\n SELECT * FROM ancestor_path ORDER BY level ASC\n ").all(t, n, n), u = Array.isArray(l) ? l : l?.results || [];
26133
+ if (!u || u.length === 0) return { blocks: [] };
26134
+ let d = u.map((e) => e.contentId).filter((e) => e != null);
26135
+ if (d.length === 0) return { blocks: [] };
26136
+ let f = d.map(() => "?").join(","), p = +!!o, m = await e.prepare(`SELECT * FROM content_blocks WHERE contentId IN (${f}) AND isDraft = ? ORDER BY contentId ASC, sortOrder ASC`).all(...d, p), h = Array.isArray(m) ? m : m?.results || [], g = /* @__PURE__ */ new Map();
26137
+ h.forEach((e) => {
26102
26138
  let t = String(e.contentId);
26103
- h.has(t) || h.set(t, []), h.get(t).push(e);
26139
+ g.has(t) || g.set(t, []), g.get(t).push(e);
26104
26140
  });
26105
- for (let t of l) {
26106
- let n = h.get(String(t.contentId)) || [];
26141
+ for (let t of u) {
26142
+ let n = g.get(String(t.contentId)) || [];
26107
26143
  if (n.filter((e) => e.region === r).length === 0) continue;
26108
- let o = /* @__PURE__ */ new Set([r]), c = !0;
26109
- for (; c;) {
26110
- c = !1;
26144
+ let l = /* @__PURE__ */ new Set([r]), u = !0;
26145
+ for (; u;) {
26146
+ u = !1;
26111
26147
  for (let e of n) {
26112
- if (!o.has(e.region)) continue;
26148
+ if (!l.has(e.region)) continue;
26113
26149
  let t = {};
26114
26150
  try {
26115
26151
  t = (typeof e.dataJson == "string" ? JSON.parse(e.dataJson) : e.dataJson) || {};
26116
26152
  } catch {}
26117
26153
  let r = String(e.id), i = String(t.blockId || t._instanceId || t.id || e.blockId);
26118
26154
  for (let e of n) {
26119
- if (!e.region || o.has(e.region)) continue;
26155
+ if (!e.region || l.has(e.region)) continue;
26120
26156
  let t = e.region;
26121
- (t.startsWith(`${r}-`) || t.startsWith(`${r}_`) || i && i !== "undefined" && i !== "null" && (t.startsWith(`${i}-`) || t.startsWith(`${i}_`) || t.startsWith(i))) && (o.add(t), c = !0);
26157
+ (t.startsWith(`${r}-`) || t.startsWith(`${r}_`) || i && i !== "undefined" && i !== "null" && (t.startsWith(`${i}-`) || t.startsWith(`${i}_`) || t.startsWith(i))) && (l.add(t), u = !0);
26122
26158
  }
26123
26159
  }
26124
26160
  }
26125
- let l = await Promise.all(n.filter((e) => o.has(e.region)).map(async (t) => {
26161
+ let d = await Promise.all(n.filter((e) => l.has(e.region)).map(async (t) => {
26126
26162
  let n = {};
26127
26163
  try {
26128
26164
  n = (typeof t.dataJson == "string" ? JSON.parse(t.dataJson) : t.dataJson) || {};
26129
26165
  } catch {}
26130
- s && dS(n.startShowingAt, n.stopShowingAt, s);
26131
- let o = n.hidden === !0 || n.hidden === 1 || n.hidden === "1" || n.hidden === "true", c = fS(n.startShowingAt, n.stopShowingAt);
26132
- if (!a && (o || !c)) return null;
26133
- let l = t.elementType || t.componentId || "text-block", u = i.blocks?.[l]?.fields || i.elements?.[l]?.fields || i.components?.[l]?.fields || {}, d = String(n.blockId || n._instanceId || n.id || t.blockId || t.id), f = hS(n, u);
26134
- return f = await fx(e, f), f = gS(f), f.blockId = d, {
26166
+ c && dS(n.startShowingAt, n.stopShowingAt, c);
26167
+ let l = n.hidden === !0 || n.hidden === 1 || n.hidden === "1" || n.hidden === "true", u = fS(n.startShowingAt, n.stopShowingAt);
26168
+ if (!o && (l || !u)) return null;
26169
+ let d = t.elementType || t.componentId || "text-block", f = i.blocks?.[d]?.fields || i.elements?.[d]?.fields || i.components?.[d]?.fields || {}, p = String(n.blockId || n._instanceId || n.id || t.blockId || t.id), m = hS(n, f);
26170
+ return m = await fx(e, m), m = gS(m), m = await _S(e, m, a, s), m.blockId = p, {
26135
26171
  region: t.region || r,
26136
26172
  block: {
26137
26173
  instanceId: t.id,
26138
- blockId: d,
26139
- componentId: l,
26140
- data: f
26174
+ blockId: p,
26175
+ componentId: d,
26176
+ data: m
26141
26177
  }
26142
26178
  };
26143
- })), u = {};
26144
- for (let e of l) e && (u[e.region] || (u[e.region] = []), u[e.region].push(e.block));
26145
- if (u[r] && u[r].length > 0) return {
26146
- blocks: u[r],
26147
- subRegions: u,
26179
+ })), f = {};
26180
+ for (let e of d) e && (f[e.region] || (f[e.region] = []), f[e.region].push(e.block));
26181
+ if (f[r] && f[r].length > 0) return {
26182
+ blocks: f[r],
26183
+ subRegions: f,
26148
26184
  inheritedFromId: String(t.contentId),
26149
26185
  inheritedFromTitle: t.title || t.slug
26150
26186
  };
@@ -26202,8 +26238,16 @@ async function _S(e, t, n, r) {
26202
26238
  if (i.size === 0 && a.size === 0) return t;
26203
26239
  let o = /* @__PURE__ */ new Map();
26204
26240
  if (i.size > 0) {
26205
- let t = Array.from(i).map(() => "?").join(","), r = await e.prepare(`SELECT nodeId, path FROM node_routes WHERE channelId = ? AND nodeId IN (${t}) AND isCanonical = 1`).all(n, ...i);
26206
- (Array.isArray(r) ? r : r?.results || []).forEach((e) => o.set(String(e.nodeId), e.path));
26241
+ let t = Array.from(i).map(() => "?").join(","), r = await e.prepare(`
26242
+ SELECT nodeId, path, channelId
26243
+ FROM node_routes
26244
+ WHERE nodeId IN (${t}) AND isCanonical = 1
26245
+ ORDER BY CASE WHEN channelId = ? THEN 0 ELSE 1 END ASC
26246
+ `).all(...i, n);
26247
+ (Array.isArray(r) ? r : r?.results || []).forEach((e) => {
26248
+ let t = String(e.nodeId);
26249
+ o.has(t) || o.set(t, e.path);
26250
+ });
26207
26251
  }
26208
26252
  let s = Array.from(a).map(() => "?").join(","), c = a.size > 0 ? await e.prepare(`SELECT id, cdnUrl, storageKeyPrivate FROM assets WHERE id IN (${s})`).all(...a) : [], l = /* @__PURE__ */ new Map();
26209
26253
  return (Array.isArray(c) ? c : c?.results || []).forEach((e) => l.set(String(e.id), e.cdnUrl || (e.storageKeyPrivate ? `/media/${e.storageKeyPrivate}` : ""))), t.replace(/<a\s+([^>]+)>/gi, (e, t) => {
@@ -26239,7 +26283,7 @@ async function vS(e, t, n, r) {
26239
26283
  if (a) return yS(e, a[1], r);
26240
26284
  if (!i) return t.href;
26241
26285
  let o = i[1];
26242
- return (await e.prepare("SELECT path FROM node_routes WHERE nodeId = ? AND channelId = ? AND isCanonical = 1 LIMIT 1").get(Number(o), n))?.path || "#";
26286
+ return (await e.prepare("\n SELECT path \n FROM node_routes \n WHERE nodeId = ? AND isCanonical = 1 \n ORDER BY CASE WHEN channelId = ? THEN 0 ELSE 1 END ASC \n LIMIT 1\n ").get(Number(o), n))?.path || "#";
26243
26287
  }
26244
26288
  async function yS(e, t, n) {
26245
26289
  let r = String(t), i = n.assetUrls.get(r);
@@ -26342,7 +26386,7 @@ async function wS(e) {
26342
26386
  if (!m) return e.json({ error: `Channel '${p}' not found` }, 404);
26343
26387
  let h = m.status === "disabled" || m.status === "inactive" || m.isEnabled === 0 || m.isEnabled === !1;
26344
26388
  if (!s && h) return e.json({ error: `Channel '${m.key || p}' is currently inactive` }, 404);
26345
- let g = m.id, _ = m.key || p, v = await t.prepare("\n SELECT * FROM node_routes WHERE path = ? AND channelId = ? LIMIT 1\n ").get(f, g);
26389
+ let g = m.id, _ = m.key || p, v = await t.prepare("SELECT * FROM node_routes WHERE path = ? AND channelId = ? LIMIT 1").get(f, g);
26346
26390
  if (v?.redirectUrl) return e.json({
26347
26391
  redirect: v.redirectUrl,
26348
26392
  isCanonical: !1
@@ -26360,9 +26404,7 @@ async function wS(e) {
26360
26404
  let e = await t.prepare("SELECT snapshotJson FROM node_revisions WHERE nodeId = ? AND version = ?").get(y.id, Number(c));
26361
26405
  if (e && e.snapshotJson) try {
26362
26406
  x = JSON.parse(e.snapshotJson), x.node && (x.node.title && (y.title = x.node.title), x.node.slug && (y.slug = x.node.slug));
26363
- } catch (e) {
26364
- console.error("[CMS] Failed to parse snapshotJson", e);
26365
- }
26407
+ } catch {}
26366
26408
  }
26367
26409
  let S = await t.prepare(`SELECT contentId as treeNodeId, treeId, parentId FROM tree_nodes WHERE contentId = ? ${b ? "AND treeId = ?" : ""} LIMIT 1`).get(y.id, ...b ? [b] : []);
26368
26410
  !b && S?.treeId && (b = S.treeId), b ||= "main-nav";
@@ -26395,7 +26437,23 @@ async function wS(e) {
26395
26437
  return n > 0 ? e.header("Cache-Control", `public, max-age=${n}, s-maxage=${n}`) : e.header("Cache-Control", "no-cache, no-store, must-revalidate"), e.json(t);
26396
26438
  }
26397
26439
  }
26398
- let A = S?.parentId || null, ne = v?.path || (f === "" ? "/" : f), j = {
26440
+ let A = S?.parentId || null;
26441
+ if (!S && !A) {
26442
+ let e = f.split("/").filter(Boolean);
26443
+ if (e.length > 1) {
26444
+ e.pop();
26445
+ let n = "/" + e.join("/"), r = await t.prepare("SELECT nodeId FROM node_routes WHERE path = ? AND channelId = ? LIMIT 1").get(n, g);
26446
+ if (r?.nodeId) {
26447
+ let e = await t.prepare("SELECT contentId, treeId FROM tree_nodes WHERE contentId = ? LIMIT 1").get(r.nodeId);
26448
+ e && (A = e.contentId, b = e.treeId);
26449
+ }
26450
+ }
26451
+ if (!A) {
26452
+ let e = await t.prepare("SELECT contentId, treeId FROM tree_nodes WHERE parentId IS NULL ORDER BY sortOrder ASC LIMIT 1").get();
26453
+ e && (A = e.contentId, b = e.treeId);
26454
+ }
26455
+ }
26456
+ let ne = v?.path || (f === "" ? "/" : f), j = {
26399
26457
  id: y.id,
26400
26458
  title: y.title,
26401
26459
  slug: y.slug,
@@ -26423,7 +26481,7 @@ async function wS(e) {
26423
26481
  if (!s && (be || xe || Se && !Ce)) return e.json({ error: "Node is hidden, offline, or has never been published." }, 404);
26424
26482
  let we = [];
26425
26483
  if (S?.treeNodeId) {
26426
- let e = await t.prepare("\n SELECT t.contentId as treeNodeId, t.contentId as id, c.title, c.slug, c.language, c.contentType as nodeType, c.isHidden, c.dataJson, c.draftDataJson\n FROM tree_nodes t INNER JOIN content_nodes c ON t.contentId = c.id WHERE t.parentId = ? AND t.treeId = ? ORDER BY t.sortOrder ASC\n ").all(S.treeNodeId, b), n = Array.isArray(e) ? e : e?.results || [], i = j.path || "", a = i === "/" ? "" : i;
26484
+ let e = await t.prepare("SELECT t.contentId as treeNodeId, t.contentId as id, c.title, c.slug, c.language, c.contentType as nodeType, c.isHidden, c.dataJson, c.draftDataJson FROM tree_nodes t INNER JOIN content_nodes c ON t.contentId = c.id WHERE t.parentId = ? AND t.treeId = ? ORDER BY t.sortOrder ASC").all(S.treeNodeId, b), n = Array.isArray(e) ? e : e?.results || [], i = j.path || "", a = i === "/" ? "" : i;
26427
26485
  we = n.map((e) => {
26428
26486
  let t = {}, n = s && e.draftDataJson || e.dataJson;
26429
26487
  if (!n) return null;
@@ -26486,7 +26544,7 @@ async function wS(e) {
26486
26544
  for (let [e, i] of Object.entries(ke)) {
26487
26545
  let a = Ee[e] && Ee[e].length > 0, o = !!se[e];
26488
26546
  if (Ee[e] || (Ee[e] = [], De[e] = { isInherited: !1 }), (i?.inherit === "parent" || i?.inherit === !0 || i?.inherit === "true" || e === "header" || e === "footer") && !a && !o && A) {
26489
- let i = await mS(t, A, String(b), e, re, s, n, r);
26547
+ let i = await mS(t, A, b, e, re, g, s, n, r);
26490
26548
  if (i.blocks.length > 0 && (Ee[e] = i.blocks, De[e] = {
26491
26549
  isInherited: !0,
26492
26550
  inheritedFromId: i.inheritedFromId,
@@ -26498,7 +26556,7 @@ async function wS(e) {
26498
26556
  });
26499
26557
  }
26500
26558
  }
26501
- await Promise.all(Object.keys(Ee).map((e) => pS(t, Ee[e], g, E, r)));
26559
+ await Promise.all(Object.keys(Ee).map((e) => pS(t, Ee[e], g, E, r, re)));
26502
26560
  let Ae = null, je = null;
26503
26561
  if (r.length > 0) {
26504
26562
  je = Math.min(...r);
@@ -26559,10 +26617,9 @@ var TS = X({
26559
26617
  method: "get",
26560
26618
  path: "/{path}",
26561
26619
  summary: "Fetch CMS Node Content",
26562
- description: "Retrieves a fully hydrated CMS node along with its content blocks and inherited regions using $O(1)$ routing table lookups.",
26563
26620
  tags: ["Public Node API"],
26564
26621
  request: {
26565
- params: X({ path: J().optional().openapi({ description: "The full URL path or slug of the requested node" }) }),
26622
+ params: X({ path: J().optional() }),
26566
26623
  query: TS
26567
26624
  },
26568
26625
  responses: {
@@ -26571,11 +26628,11 @@ var TS = X({
26571
26628
  content: { "application/json": { schema: DS } }
26572
26629
  },
26573
26630
  404: {
26574
- description: "Node or Channel not found",
26631
+ description: "Not found",
26575
26632
  content: { "application/json": { schema: ES } }
26576
26633
  },
26577
26634
  500: {
26578
- description: "Server error during hydration",
26635
+ description: "Server error",
26579
26636
  content: { "application/json": { schema: ES } }
26580
26637
  }
26581
26638
  }
@@ -26586,36 +26643,43 @@ var kS = new $y(), AS = X({
26586
26643
  channelId: J().optional().openapi({ description: "Channel ID or key" }),
26587
26644
  limit: Ky().min(1).max(50).default(12).openapi({ description: "Number of items (max 50)" }),
26588
26645
  offset: Ky().min(0).default(0).openapi({ description: "Pagination offset" }),
26589
- sortBy: lv([
26590
- "updatedAt",
26591
- "createdAt",
26592
- "title_asc"
26593
- ]).default("updatedAt"),
26646
+ sortBy: J().default("updatedAt_desc").openapi({ description: "Sort field and direction" }),
26594
26647
  authors: G_([J(), z_(J())]).optional(),
26595
26648
  categories: G_([J(), z_(J())]).optional(),
26596
26649
  tags: G_([J(), z_(J())]).optional()
26597
26650
  }), jS = async (e) => {
26598
26651
  try {
26599
- let t = e.get("db"), n = e.req.valid("query"), r = n.nodeType || "article", i = String(r).split(",").map((e) => e.trim()).filter(Boolean), a = `FROM content_nodes WHERE contentType IN (${i.map(() => "?").join(",")}) AND isHidden = 0 AND IFNULL(status, 'published') = 'published'`, o = [...i];
26600
- n.channelId && n.channelId !== "all" && (a += " AND EXISTS (SELECT 1 FROM node_channels nc WHERE nc.nodeId = content_nodes.id AND nc.channelId = ?)", o.push(Number(n.channelId) || n.channelId));
26601
- let s = (/* @__PURE__ */ new Date()).toISOString();
26602
- a += " AND IFNULL(json_extract(dataJson, '$.startShowingAt'), '') <= ?", o.push(s), a += " AND IFNULL(json_extract(dataJson, '$.stopShowingAt'), '9999-12-31') >= ?", o.push(s);
26603
- let c = (e, t, n = !1) => {
26652
+ let t = e.get("db"), n = e.req.valid("query"), r = n.nodeType || "article", i = String(r).split(",").map((e) => e.trim()).filter(Boolean), a = i.map(() => "?").join(","), o = px(e.env?.BUNDLED_DEFINITIONS), s = {};
26653
+ for (let e of i) {
26654
+ s[e] = [];
26655
+ let t = o.nodes?.[e] || {}, n = { ...t.fields || {} };
26656
+ t.tabs && Object.values(t.tabs).forEach((e) => {
26657
+ Object.assign(n, e.fields || {});
26658
+ });
26659
+ for (let [t, r] of Object.entries(n)) (r.showInList || r.showInLists) && s[e].push(t);
26660
+ }
26661
+ let c = `FROM content_nodes WHERE contentType IN (${a}) AND isHidden = 0 AND IFNULL(status, 'published') = 'published'`, l = [...i];
26662
+ n.channelId && n.channelId !== "all" && (c += " AND EXISTS (SELECT 1 FROM node_channels nc WHERE nc.nodeId = content_nodes.id AND nc.channelId = ?)", l.push(Number(n.channelId) || n.channelId));
26663
+ let u = (/* @__PURE__ */ new Date()).toISOString();
26664
+ c += " AND IFNULL(json_extract(dataJson, '$.startShowingAt'), '') <= ?", l.push(u), c += " AND IFNULL(json_extract(dataJson, '$.stopShowingAt'), '9999-12-31') >= ?", l.push(u);
26665
+ let d = (e, t, n = !1) => {
26604
26666
  let r = Array.isArray(t) ? t : t.split(",").map((e) => e.trim());
26605
26667
  if (r.length === 0) return;
26606
26668
  let i = r.map(() => "?").join(",");
26607
- n ? (a += ` AND EXISTS (SELECT 1 FROM node_relations nr WHERE nr.sourceNodeId = content_nodes.id AND nr.fieldKey = ? AND nr.targetNodeId IN (${i}))`, o.push(e, ...r)) : (a += ` AND EXISTS (SELECT 1 FROM node_terms nt INNER JOIN taxonomy_terms tt ON nt.termId = tt.id WHERE nt.nodeId = content_nodes.id AND tt.taxonomy = ? AND tt.key IN (${i}))`, o.push(e, ...r));
26669
+ n ? (c += ` AND EXISTS (SELECT 1 FROM node_relations nr WHERE nr.sourceNodeId = content_nodes.id AND nr.fieldKey = ? AND nr.targetNodeId IN (${i}))`, l.push(e, ...r)) : (c += ` AND EXISTS (SELECT 1 FROM node_terms nt INNER JOIN taxonomy_terms tt ON nt.termId = tt.id WHERE nt.nodeId = content_nodes.id AND tt.taxonomy = ? AND tt.key IN (${i}))`, l.push(e, ...r));
26608
26670
  };
26609
- n.authors && c("authors", n.authors, !0), n.categories && c("categories", n.categories, !1), n.tags && c("tags", n.tags, !1);
26610
- let l = "ORDER BY updatedAt DESC";
26611
- n.sortBy === "createdAt" ? l = "ORDER BY createdAt DESC" : n.sortBy === "title_asc" && (l = "ORDER BY LOWER(title) ASC");
26612
- let u = `SELECT id, title, slug, language, dataJson, createdAt, updatedAt ${a} ${l} LIMIT ? OFFSET ?`;
26613
- o.push(n.limit, n.offset);
26614
- let d = await t.prepare(u).all(...o), f = Array.isArray(d) ? d : d?.results || [], p = f.map((e) => {
26671
+ n.authors && d("authors", n.authors, !0), n.categories && d("categories", n.categories, !1), n.tags && d("tags", n.tags, !1);
26672
+ let f = String(n.sortBy || "updatedAt_desc"), [p, m] = f.includes("_") ? f.split("_") : [f, "desc"], h = String(m).toLowerCase() === "asc" ? "ASC" : "DESC", g = String(p).replace(/[^a-zA-Z0-9_]/g, ""), _ = `ORDER BY updatedAt ${h}`;
26673
+ g === "createdAt" || g === "published" ? _ = `ORDER BY createdAt ${h}` : g === "title" ? _ = `ORDER BY LOWER(title) ${h}` : g !== "updatedAt" && g !== "" && (_ = `ORDER BY json_extract(dataJson, '$.${g}') ${h}`);
26674
+ let v = `SELECT id, title, slug, language, dataJson, createdAt, updatedAt ${c} ${_} LIMIT ? OFFSET ?`;
26675
+ l.push(n.limit, n.offset);
26676
+ let y = await t.prepare(v).all(...l), b = Array.isArray(y) ? y : y?.results || [], x = b.map((e) => {
26615
26677
  let t = {};
26616
26678
  try {
26617
26679
  t = typeof e.dataJson == "string" ? JSON.parse(e.dataJson) : e.dataJson || {};
26618
26680
  } catch {}
26681
+ let n = {}, r = s[e.contentType || "article"] || [];
26682
+ for (let e of r) t[e] !== void 0 && (n[e] = t[e]);
26619
26683
  return {
26620
26684
  id: e.id,
26621
26685
  title: e.title,
@@ -26623,15 +26687,16 @@ var kS = new $y(), AS = X({
26623
26687
  language: e.language,
26624
26688
  createdAt: e.createdAt,
26625
26689
  updatedAt: e.updatedAt,
26690
+ ...n,
26626
26691
  excerpt: t.excerpt || "",
26627
26692
  image: t.image || t.coverImage || null,
26628
26693
  author: t.author || null
26629
26694
  };
26630
26695
  });
26631
26696
  return e.json({
26632
- items: p,
26633
- count: p.length,
26634
- rawCount: f.length,
26697
+ items: x,
26698
+ count: x.length,
26699
+ rawCount: b.length,
26635
26700
  limit: n.limit,
26636
26701
  offset: n.offset
26637
26702
  }, 200);
@@ -26691,11 +26756,11 @@ var IS = X({ treeParam: J().openapi({ description: "The ID or key of the request
26691
26756
  path: J(),
26692
26757
  nodeType: J().optional(),
26693
26758
  hidden: c_(),
26694
- summary: J(),
26759
+ summary: J().optional(),
26695
26760
  url: J().optional(),
26696
26761
  target: J().optional(),
26697
26762
  children: z_(zS).optional()
26698
- })).openapi("TreeItem"), BS = X({
26763
+ }).passthrough()).openapi("TreeItem"), BS = X({
26699
26764
  treeId: G_([c_(), J()]),
26700
26765
  key: J(),
26701
26766
  channelId: J(),
@@ -26753,42 +26818,42 @@ NS.openapi(VS, async (e) => {
26753
26818
  let t = await p.get(m);
26754
26819
  if (t) return e.header("X-Cache", "HIT"), e.json(t, 200);
26755
26820
  }
26756
- let g = u?.id || (l ? Number(n) : null), _ = {};
26821
+ let g = u?.id || (l ? Number(n) : null), _ = e.env?.BUNDLED_DEFINITIONS, v = px(_), y = v.treeExposedFields || ["summary"], b = {};
26757
26822
  if (u && u.dataJson) try {
26758
- let t = typeof u.dataJson == "string" ? JSON.parse(u.dataJson) : u.dataJson, r = e.env?.BUNDLED_DEFINITIONS, i = px(r), a = (i.trees?.[u.treeType || n] || i.trees?.site || {}).fields || {};
26759
- for (let [e, n] of Object.entries(t)) a[e]?.public === !0 && (_[e] = n);
26823
+ let e = typeof u.dataJson == "string" ? JSON.parse(u.dataJson) : u.dataJson, t = (v.trees?.[u.treeType || n] || v.trees?.site || {}).fields || {};
26824
+ for (let [n, r] of Object.entries(e)) t[n]?.public === !0 && (b[n] = r);
26760
26825
  } catch (e) {
26761
26826
  console.warn("[CMS Public Tree API] Failed to parse tree dataJson", e);
26762
26827
  }
26763
- let v = [];
26828
+ let x = [];
26764
26829
  if (g !== null) {
26765
26830
  let e = await t.prepare("\n SELECT \n t.contentId as treeNodeId,\n t.treeId,\n t.contentId as id,\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.startShowingAt,\n c.stopShowingAt,\n c.status,\n c.dataJson,\n c.draftDataJson,\n (\n SELECT path \n FROM node_routes \n WHERE nodeId = c.id AND channelId = ? \n ORDER BY CASE WHEN treeId = t.treeId THEN 0 ELSE 1 END ASC \n LIMIT 1\n ) as materializedPath\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(c, g);
26766
- v = Array.isArray(e) ? e : e?.results || [];
26831
+ x = Array.isArray(e) ? e : e?.results || [];
26767
26832
  }
26768
- if ((!v || v.length === 0) && !u) return e.json({ error: `Tree '${n}' not found` }, 404);
26769
- let y = /* @__PURE__ */ new Map();
26770
- for (let e of v) {
26771
- let t = !e.parentId || e.parentId === "null" || e.parentId === "" ? null : e.parentId, n = t === null ? "__ROOT__" : String(t), r = y.get(n);
26772
- r ? r.push(e) : y.set(n, [e]);
26833
+ if ((!x || x.length === 0) && !u) return e.json({ error: `Tree '${n}' not found` }, 404);
26834
+ let S = /* @__PURE__ */ new Map();
26835
+ for (let e of x) {
26836
+ let t = !e.parentId || e.parentId === "null" || e.parentId === "" ? null : e.parentId, n = t === null ? "__ROOT__" : String(t), r = S.get(n);
26837
+ r ? r.push(e) : S.set(n, [e]);
26773
26838
  }
26774
- let b = /* @__PURE__ */ new Map();
26775
- for (let e of v) {
26839
+ let C = /* @__PURE__ */ new Map();
26840
+ for (let e of x) {
26776
26841
  let t = String(e.id), n = o && e.draftDataJson ? e.draftDataJson : e.dataJson;
26777
26842
  if (!n) {
26778
- b.set(t, {});
26843
+ C.set(t, {});
26779
26844
  continue;
26780
26845
  }
26781
26846
  try {
26782
26847
  let e = typeof n == "string" ? JSON.parse(n) : n;
26783
- b.set(t, e && typeof e == "object" ? e : {});
26848
+ C.set(t, e && typeof e == "object" ? e : {});
26784
26849
  } catch {
26785
- b.set(t, {});
26850
+ C.set(t, {});
26786
26851
  }
26787
26852
  }
26788
- function x(e = null, t = "") {
26853
+ function w(e = null, t = "") {
26789
26854
  let n = e == null || e === "" || e === "null" ? "__ROOT__" : String(e);
26790
- return (y.get(n) || []).map((e) => {
26791
- let n = b.get(String(e.id)) || {}, r = {};
26855
+ return (S.get(n) || []).map((e) => {
26856
+ let n = C.get(String(e.id)) || {}, r = {};
26792
26857
  for (let [e, t] of Object.entries(n)) e !== "_isTreeDraft" && e !== "_draftParentId" && e !== "isNew" && e !== "hidden" && e !== "is_hidden" && e !== "isHidden" && e !== "status" && (r[e] = t);
26793
26858
  let i = !o && (e.status === "draft" || e.status === "new"), a = Number(e.isHidden) === 1 || i || n.hidden === !0 || n.hidden === 1 || n.hidden === "1" || n.hidden === "true", s = PS(e.startShowingAt === void 0 ? n.startShowingAt : e.startShowingAt, e.stopShowingAt === void 0 ? n.stopShowingAt : e.stopShowingAt), c = (e.slug || "").replace(/^\/+|\/+$/g, ""), l = !e.parentId || e.parentId === "null" || e.parentId === "", u = e.materializedPath || (l ? `/${c}` : `${t}/${c}`.replace(/\/+/g, "/")), d = e.language && String(e.language).trim() !== "" ? e.language.trim() : f, p = {
26794
26859
  id: e.id,
@@ -26799,24 +26864,24 @@ NS.openapi(VS, async (e) => {
26799
26864
  language: d,
26800
26865
  path: u,
26801
26866
  nodeType: e.nodeType,
26802
- hidden: a || !s ? 1 : 0,
26803
- summary: r.summary || ""
26867
+ hidden: a || !s ? 1 : 0
26804
26868
  };
26869
+ for (let e of y) r[e] !== void 0 && (p[e] = r[e]);
26805
26870
  e.nodeType === "external-link" && (r.url && (p.url = r.url), r.target && (p.target = r.target));
26806
26871
  let m = u === "/" ? "" : u;
26807
- return p.children = x(e.id, m), p;
26872
+ return p.children = w(e.id, m), p;
26808
26873
  }).filter((e) => o || !e.hidden);
26809
26874
  }
26810
- let S = {
26875
+ let T = {
26811
26876
  treeId: u?.id || g,
26812
26877
  key: u?.key || n,
26813
26878
  channelId: String(i),
26814
26879
  language: f,
26815
26880
  label: u?.label || n,
26816
- ..._,
26817
- items: x(null)
26881
+ ...b,
26882
+ items: w(null)
26818
26883
  };
26819
- return !o && !h && (e.header("X-Cache", "MISS"), await FS(p, m, S, 300)), e.json(S, 200);
26884
+ return !o && !h && (e.header("X-Cache", "MISS"), await FS(p, m, T, 300)), e.json(T, 200);
26820
26885
  } catch (t) {
26821
26886
  return console.error("[CMS Public Tree API] Error:", t), e.json({
26822
26887
  error: "Failed to fetch public tree",
package/dist/index.html CHANGED
@@ -6,11 +6,11 @@
6
6
  <title>KAMA</title>
7
7
  <link rel="icon" href="/favicon.png">
8
8
  <link rel="apple-touch-icon" sizes="180x180" href="/favicon.png">
9
- <script type="module" crossorigin src="/assets/index-BIES-eB_.js"></script>
9
+ <script type="module" crossorigin src="/assets/index-DQ6_RmCI.js"></script>
10
10
  <link rel="modulepreload" crossorigin href="/assets/_plugin-vue_export-helper-CQxWhVtr.js">
11
- <link rel="modulepreload" crossorigin href="/assets/schema-helpers-1UXlO0Ye.js">
12
- <link rel="modulepreload" crossorigin href="/assets/useNodes-W5j_uxdQ.js">
13
- <link rel="modulepreload" crossorigin href="/assets/plus-mqZr4I1D.js">
11
+ <link rel="modulepreload" crossorigin href="/assets/schema-helpers-DvficKko.js">
12
+ <link rel="modulepreload" crossorigin href="/assets/useNodes-D2-VxsxR.js">
13
+ <link rel="modulepreload" crossorigin href="/assets/plus-FQRsZBoJ.js">
14
14
  <link rel="modulepreload" crossorigin href="/assets/send-F-mJeL54.js">
15
15
  <link rel="modulepreload" crossorigin href="/assets/CmsPaneResizer-B62ZqsnE.js">
16
16
  <link rel="modulepreload" crossorigin href="/assets/user-IFlT6mYq.js">