@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.
package/dist/index.js CHANGED
@@ -21285,6 +21285,13 @@ var Tb = /* @__PURE__ */ o({
21285
21285
  public: !0,
21286
21286
  allowedLinkTypes: ["tree", "node"],
21287
21287
  rules: {}
21288
+ },
21289
+ sortBy: {
21290
+ label: "Sort by",
21291
+ type: "node-sort",
21292
+ default: "updatedAt_desc",
21293
+ public: !0,
21294
+ rules: {}
21288
21295
  }
21289
21296
  },
21290
21297
  tabs: { access: {
@@ -22254,7 +22261,8 @@ var Tb = /* @__PURE__ */ o({
22254
22261
  nodeTemplate: null,
22255
22262
  treeTemplate: null,
22256
22263
  channelTemplate: null,
22257
- userTemplate: null
22264
+ userTemplate: null,
22265
+ treeExposedFields: ["summary"]
22258
22266
  }, Db = Eb, Ob = {
22259
22267
  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 ",
22260
22268
  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 ",
@@ -23632,7 +23640,8 @@ function px(e) {
23632
23640
  nodeLayouts: e.nodeLayouts || {},
23633
23641
  blockLayouts: e.blockLayouts || {},
23634
23642
  channels: e.channels || {},
23635
- taxonomies: e.taxonomies || {}
23643
+ taxonomies: e.taxonomies || {},
23644
+ treeExposedFields: e.treeExposedFields || ["summary"]
23636
23645
  } : {
23637
23646
  nodes: {},
23638
23647
  trees: {},
@@ -23640,7 +23649,8 @@ function px(e) {
23640
23649
  nodeLayouts: {},
23641
23650
  blockLayouts: {},
23642
23651
  channels: {},
23643
- taxonomies: {}
23652
+ taxonomies: {},
23653
+ treeExposedFields: ["summary"]
23644
23654
  };
23645
23655
  }
23646
23656
  //#endregion
@@ -25456,7 +25466,8 @@ function Qx(e) {
25456
25466
  nodeTemplate: null,
25457
25467
  treeTemplate: null,
25458
25468
  channelTemplate: null,
25459
- userTemplate: null
25469
+ userTemplate: null,
25470
+ treeExposedFields: ["summary"]
25460
25471
  };
25461
25472
  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 = {
25462
25473
  ...p,
@@ -25729,7 +25740,15 @@ function Qx(e) {
25729
25740
  let fe = _ ? {
25730
25741
  ..._,
25731
25742
  fields: de
25732
- } : null;
25743
+ } : null, pe = /* @__PURE__ */ new Set(["summary"]);
25744
+ for (let e of Object.values(k)) {
25745
+ let t = e.fields || e;
25746
+ for (let [e, n] of Object.entries(t || {})) n && typeof n == "object" && n.inTree && pe.add(e);
25747
+ }
25748
+ for (let e of Object.values(j)) {
25749
+ for (let [t, n] of Object.entries(e.fields || {})) n?.inTree && pe.add(t);
25750
+ for (let t of Object.values(e.tabs || {})) for (let [e, n] of Object.entries(t.fields || {})) n?.inTree && pe.add(e);
25751
+ }
25733
25752
  return {
25734
25753
  nodes: j,
25735
25754
  trees: re,
@@ -25742,7 +25761,8 @@ function Qx(e) {
25742
25761
  nodeTemplate: m || null,
25743
25762
  treeTemplate: h || null,
25744
25763
  channelTemplate: ue,
25745
- userTemplate: fe
25764
+ userTemplate: fe,
25765
+ treeExposedFields: Array.from(pe)
25746
25766
  };
25747
25767
  }
25748
25768
  //#endregion
@@ -26241,21 +26261,30 @@ function fS(e, t) {
26241
26261
  }
26242
26262
  return !0;
26243
26263
  }
26244
- async function pS(e, t, n, r, i) {
26245
- let a = t.filter((e) => e.componentId === "content-feed" || e.componentId === "article-list" || e.componentId === "nodeList" || e.componentId === "node-list");
26246
- await Promise.all(a.map(async (t) => {
26247
- 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();
26248
- 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));
26249
- let f = `FROM content_nodes WHERE contentType IN (${s.map(() => "?").join(",")}) AND isHidden = 0 AND IFNULL(status, 'published') = 'published'`, p = [...s];
26250
- 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));
26251
- let m = (/* @__PURE__ */ new Date()).toISOString();
26252
- f += " AND IFNULL(json_extract(dataJson, '$.startShowingAt'), '') <= ?", p.push(m), f += " AND IFNULL(json_extract(dataJson, '$.stopShowingAt'), '9999-12-31') >= ?", p.push(m);
26264
+ async function pS(e, t, n, r, i, a) {
26265
+ let o = t.filter((e) => e.componentId === "content-feed" || e.componentId === "article-list" || e.componentId === "nodeList" || e.componentId === "node-list");
26266
+ await Promise.all(o.map(async (t) => {
26267
+ let o = t.data || {}, s = o.nodeType || ["article"], c = (Array.isArray(s) ? s : String(s).split(",")).map((e) => String(e).trim()).filter(Boolean), l = {};
26268
+ if (a) for (let e of c) {
26269
+ l[e] = [];
26270
+ let t = a.nodes?.[e] || {}, n = { ...t.fields || {} };
26271
+ t.tabs && Object.values(t.tabs).forEach((e) => {
26272
+ Object.assign(n, e.fields || {});
26273
+ });
26274
+ for (let [t, r] of Object.entries(n)) (r.showInList || r.showInLists) && l[e].push(t);
26275
+ }
26276
+ 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();
26277
+ _.set("nodeType", c.join(",")), _.set("limit", u.toString()), _.set("offset", (d + u).toString()), _.set("sortBy", f), n && n !== "all" && _.set("channelId", String(n));
26278
+ let v = `FROM content_nodes WHERE contentType IN (${c.map(() => "?").join(",")}) AND isHidden = 0 AND IFNULL(status, 'published') = 'published'`, y = [...c];
26279
+ 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));
26280
+ let b = (/* @__PURE__ */ new Date()).toISOString();
26281
+ v += " AND IFNULL(json_extract(dataJson, '$.startShowingAt'), '') <= ?", y.push(b), v += " AND IFNULL(json_extract(dataJson, '$.stopShowingAt'), '9999-12-31') >= ?", y.push(b);
26253
26282
  for (let e of [
26254
26283
  "authors",
26255
26284
  "categories",
26256
26285
  "tags"
26257
- ]) if (a[e]) {
26258
- let t = (Array.isArray(a[e]) ? a[e] : [a[e]]).map((e) => {
26286
+ ]) if (o[e]) {
26287
+ let t = (Array.isArray(o[e]) ? o[e] : [o[e]]).map((e) => {
26259
26288
  if (typeof e == "object" && e) {
26260
26289
  if (e.key) return String(e.key);
26261
26290
  if (e.nodeId) return String(e.nodeId);
@@ -26264,93 +26293,100 @@ async function pS(e, t, n, r, i) {
26264
26293
  return String(e);
26265
26294
  }).filter((e) => e !== "undefined" && e !== "null" && e !== "");
26266
26295
  if (t.length > 0) {
26267
- d.set(e, t.join(","));
26296
+ _.set(e, t.join(","));
26268
26297
  let n = t.map(() => "?").join(",");
26269
- 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);
26298
+ 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);
26270
26299
  }
26271
26300
  }
26272
- let h = "ORDER BY updatedAt DESC";
26273
- u === "published_desc" || u === "createdAt" ? h = "ORDER BY createdAt DESC" : u === "title_asc" && (h = "ORDER BY LOWER(title) ASC");
26274
- let g = `SELECT id, title, slug, language, dataJson, createdAt, updatedAt ${f} ${h} LIMIT ? OFFSET ?`;
26275
- p.push(c, l);
26301
+ let x = `ORDER BY updatedAt ${h}`;
26302
+ 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}`);
26303
+ let S = `SELECT id, title, slug, language, dataJson, createdAt, updatedAt ${v} ${x} LIMIT ? OFFSET ?`;
26304
+ y.push(u, d);
26276
26305
  try {
26277
- let n = await e.prepare(g).all(...p), o = Array.isArray(n) ? n : n?.results || [];
26278
- t.data.initialItems = o.map((e) => {
26306
+ let n = await e.prepare(S).all(...y), s = Array.isArray(n) ? n : n?.results || [];
26307
+ t.data.initialItems = s.map((e) => {
26279
26308
  let t = {};
26280
26309
  if (e.dataJson) try {
26281
26310
  t = typeof e.dataJson == "string" ? JSON.parse(e.dataJson) : e.dataJson;
26282
26311
  } catch {}
26283
- return i && dS(t.startShowingAt, t.stopShowingAt, i), {
26312
+ i && dS(t.startShowingAt, t.stopShowingAt, i);
26313
+ let n = {};
26314
+ if (a) {
26315
+ let r = l[e.contentType || "article"] || [];
26316
+ for (let e of r) t[e] !== void 0 && (n[e] = t[e]);
26317
+ }
26318
+ return {
26284
26319
  id: e.id,
26285
26320
  title: e.title,
26286
26321
  slug: e.slug,
26287
26322
  language: e.language?.trim() || r || null,
26288
26323
  createdAt: e.createdAt,
26289
26324
  updatedAt: e.updatedAt,
26325
+ ...n,
26290
26326
  excerpt: t.excerpt || "",
26291
26327
  image: t.image || t.coverImage || null,
26292
26328
  author: t.author || null
26293
26329
  };
26294
- }), a.disablePagination !== !0 && a.disablePagination !== "1" && o.length === c ? t.data.loadMoreUrl = `/api/v1/nodes?${d.toString()}` : t.data.loadMoreUrl = null;
26330
+ }), o.disablePagination !== !0 && o.disablePagination !== "1" && s.length === u ? t.data.loadMoreUrl = `/api/v1/nodes?${_.toString()}` : t.data.loadMoreUrl = null;
26295
26331
  } catch (e) {
26296
26332
  console.error("[CMS Hydration] Failed to hydrate content feed block", e), t.data.initialItems = [], t.data.loadMoreUrl = null;
26297
26333
  }
26298
26334
  }));
26299
26335
  }
26300
- async function mS(e, t, n, r, i, a = !1, o, s) {
26336
+ async function mS(e, t, n, r, i, a, o = !1, s, c) {
26301
26337
  if (!t) return { blocks: [] };
26302
- 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 || [];
26303
- if (!l || l.length === 0) return { blocks: [] };
26304
- let u = l.map((e) => e.contentId).filter((e) => e != null);
26305
- if (u.length === 0) return { blocks: [] };
26306
- 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();
26307
- m.forEach((e) => {
26338
+ 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 || [];
26339
+ if (!u || u.length === 0) return { blocks: [] };
26340
+ let d = u.map((e) => e.contentId).filter((e) => e != null);
26341
+ if (d.length === 0) return { blocks: [] };
26342
+ 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();
26343
+ h.forEach((e) => {
26308
26344
  let t = String(e.contentId);
26309
- h.has(t) || h.set(t, []), h.get(t).push(e);
26345
+ g.has(t) || g.set(t, []), g.get(t).push(e);
26310
26346
  });
26311
- for (let t of l) {
26312
- let n = h.get(String(t.contentId)) || [];
26347
+ for (let t of u) {
26348
+ let n = g.get(String(t.contentId)) || [];
26313
26349
  if (n.filter((e) => e.region === r).length === 0) continue;
26314
- let o = /* @__PURE__ */ new Set([r]), c = !0;
26315
- for (; c;) {
26316
- c = !1;
26350
+ let l = /* @__PURE__ */ new Set([r]), u = !0;
26351
+ for (; u;) {
26352
+ u = !1;
26317
26353
  for (let e of n) {
26318
- if (!o.has(e.region)) continue;
26354
+ if (!l.has(e.region)) continue;
26319
26355
  let t = {};
26320
26356
  try {
26321
26357
  t = (typeof e.dataJson == "string" ? JSON.parse(e.dataJson) : e.dataJson) || {};
26322
26358
  } catch {}
26323
26359
  let r = String(e.id), i = String(t.blockId || t._instanceId || t.id || e.blockId);
26324
26360
  for (let e of n) {
26325
- if (!e.region || o.has(e.region)) continue;
26361
+ if (!e.region || l.has(e.region)) continue;
26326
26362
  let t = e.region;
26327
- (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);
26363
+ (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);
26328
26364
  }
26329
26365
  }
26330
26366
  }
26331
- let l = await Promise.all(n.filter((e) => o.has(e.region)).map(async (t) => {
26367
+ let d = await Promise.all(n.filter((e) => l.has(e.region)).map(async (t) => {
26332
26368
  let n = {};
26333
26369
  try {
26334
26370
  n = (typeof t.dataJson == "string" ? JSON.parse(t.dataJson) : t.dataJson) || {};
26335
26371
  } catch {}
26336
- s && dS(n.startShowingAt, n.stopShowingAt, s);
26337
- let o = n.hidden === !0 || n.hidden === 1 || n.hidden === "1" || n.hidden === "true", c = fS(n.startShowingAt, n.stopShowingAt);
26338
- if (!a && (o || !c)) return null;
26339
- 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);
26340
- return f = await fx(e, f), f = gS(f), f.blockId = d, {
26372
+ c && dS(n.startShowingAt, n.stopShowingAt, c);
26373
+ let l = n.hidden === !0 || n.hidden === 1 || n.hidden === "1" || n.hidden === "true", u = fS(n.startShowingAt, n.stopShowingAt);
26374
+ if (!o && (l || !u)) return null;
26375
+ 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);
26376
+ return m = await fx(e, m), m = gS(m), m = await _S(e, m, a, s), m.blockId = p, {
26341
26377
  region: t.region || r,
26342
26378
  block: {
26343
26379
  instanceId: t.id,
26344
- blockId: d,
26345
- componentId: l,
26346
- data: f
26380
+ blockId: p,
26381
+ componentId: d,
26382
+ data: m
26347
26383
  }
26348
26384
  };
26349
- })), u = {};
26350
- for (let e of l) e && (u[e.region] || (u[e.region] = []), u[e.region].push(e.block));
26351
- if (u[r] && u[r].length > 0) return {
26352
- blocks: u[r],
26353
- subRegions: u,
26385
+ })), f = {};
26386
+ for (let e of d) e && (f[e.region] || (f[e.region] = []), f[e.region].push(e.block));
26387
+ if (f[r] && f[r].length > 0) return {
26388
+ blocks: f[r],
26389
+ subRegions: f,
26354
26390
  inheritedFromId: String(t.contentId),
26355
26391
  inheritedFromTitle: t.title || t.slug
26356
26392
  };
@@ -26408,8 +26444,16 @@ async function _S(e, t, n, r) {
26408
26444
  if (i.size === 0 && a.size === 0) return t;
26409
26445
  let o = /* @__PURE__ */ new Map();
26410
26446
  if (i.size > 0) {
26411
- 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);
26412
- (Array.isArray(r) ? r : r?.results || []).forEach((e) => o.set(String(e.nodeId), e.path));
26447
+ let t = Array.from(i).map(() => "?").join(","), r = await e.prepare(`
26448
+ SELECT nodeId, path, channelId
26449
+ FROM node_routes
26450
+ WHERE nodeId IN (${t}) AND isCanonical = 1
26451
+ ORDER BY CASE WHEN channelId = ? THEN 0 ELSE 1 END ASC
26452
+ `).all(...i, n);
26453
+ (Array.isArray(r) ? r : r?.results || []).forEach((e) => {
26454
+ let t = String(e.nodeId);
26455
+ o.has(t) || o.set(t, e.path);
26456
+ });
26413
26457
  }
26414
26458
  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();
26415
26459
  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) => {
@@ -26445,7 +26489,7 @@ async function vS(e, t, n, r) {
26445
26489
  if (a) return yS(e, a[1], r);
26446
26490
  if (!i) return t.href;
26447
26491
  let o = i[1];
26448
- return (await e.prepare("SELECT path FROM node_routes WHERE nodeId = ? AND channelId = ? AND isCanonical = 1 LIMIT 1").get(Number(o), n))?.path || "#";
26492
+ 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 || "#";
26449
26493
  }
26450
26494
  async function yS(e, t, n) {
26451
26495
  let r = String(t), i = n.assetUrls.get(r);
@@ -26548,7 +26592,7 @@ async function wS(e) {
26548
26592
  if (!m) return e.json({ error: `Channel '${p}' not found` }, 404);
26549
26593
  let h = m.status === "disabled" || m.status === "inactive" || m.isEnabled === 0 || m.isEnabled === !1;
26550
26594
  if (!s && h) return e.json({ error: `Channel '${m.key || p}' is currently inactive` }, 404);
26551
- 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);
26595
+ let g = m.id, _ = m.key || p, v = await t.prepare("SELECT * FROM node_routes WHERE path = ? AND channelId = ? LIMIT 1").get(f, g);
26552
26596
  if (v?.redirectUrl) return e.json({
26553
26597
  redirect: v.redirectUrl,
26554
26598
  isCanonical: !1
@@ -26566,9 +26610,7 @@ async function wS(e) {
26566
26610
  let e = await t.prepare("SELECT snapshotJson FROM node_revisions WHERE nodeId = ? AND version = ?").get(y.id, Number(c));
26567
26611
  if (e && e.snapshotJson) try {
26568
26612
  x = JSON.parse(e.snapshotJson), x.node && (x.node.title && (y.title = x.node.title), x.node.slug && (y.slug = x.node.slug));
26569
- } catch (e) {
26570
- console.error("[CMS] Failed to parse snapshotJson", e);
26571
- }
26613
+ } catch {}
26572
26614
  }
26573
26615
  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] : []);
26574
26616
  !b && S?.treeId && (b = S.treeId), b ||= "main-nav";
@@ -26601,7 +26643,23 @@ async function wS(e) {
26601
26643
  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);
26602
26644
  }
26603
26645
  }
26604
- let A = S?.parentId || null, ne = v?.path || (f === "" ? "/" : f), j = {
26646
+ let A = S?.parentId || null;
26647
+ if (!S && !A) {
26648
+ let e = f.split("/").filter(Boolean);
26649
+ if (e.length > 1) {
26650
+ e.pop();
26651
+ let n = "/" + e.join("/"), r = await t.prepare("SELECT nodeId FROM node_routes WHERE path = ? AND channelId = ? LIMIT 1").get(n, g);
26652
+ if (r?.nodeId) {
26653
+ let e = await t.prepare("SELECT contentId, treeId FROM tree_nodes WHERE contentId = ? LIMIT 1").get(r.nodeId);
26654
+ e && (A = e.contentId, b = e.treeId);
26655
+ }
26656
+ }
26657
+ if (!A) {
26658
+ let e = await t.prepare("SELECT contentId, treeId FROM tree_nodes WHERE parentId IS NULL ORDER BY sortOrder ASC LIMIT 1").get();
26659
+ e && (A = e.contentId, b = e.treeId);
26660
+ }
26661
+ }
26662
+ let ne = v?.path || (f === "" ? "/" : f), j = {
26605
26663
  id: y.id,
26606
26664
  title: y.title,
26607
26665
  slug: y.slug,
@@ -26629,7 +26687,7 @@ async function wS(e) {
26629
26687
  if (!s && (be || xe || Se && !Ce)) return e.json({ error: "Node is hidden, offline, or has never been published." }, 404);
26630
26688
  let we = [];
26631
26689
  if (S?.treeNodeId) {
26632
- 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;
26690
+ 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;
26633
26691
  we = n.map((e) => {
26634
26692
  let t = {}, n = s && e.draftDataJson || e.dataJson;
26635
26693
  if (!n) return null;
@@ -26692,7 +26750,7 @@ async function wS(e) {
26692
26750
  for (let [e, i] of Object.entries(ke)) {
26693
26751
  let a = Ee[e] && Ee[e].length > 0, o = !!se[e];
26694
26752
  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) {
26695
- let i = await mS(t, A, String(b), e, re, s, n, r);
26753
+ let i = await mS(t, A, b, e, re, g, s, n, r);
26696
26754
  if (i.blocks.length > 0 && (Ee[e] = i.blocks, De[e] = {
26697
26755
  isInherited: !0,
26698
26756
  inheritedFromId: i.inheritedFromId,
@@ -26704,7 +26762,7 @@ async function wS(e) {
26704
26762
  });
26705
26763
  }
26706
26764
  }
26707
- await Promise.all(Object.keys(Ee).map((e) => pS(t, Ee[e], g, E, r)));
26765
+ await Promise.all(Object.keys(Ee).map((e) => pS(t, Ee[e], g, E, r, re)));
26708
26766
  let Ae = null, je = null;
26709
26767
  if (r.length > 0) {
26710
26768
  je = Math.min(...r);
@@ -26765,10 +26823,9 @@ var TS = X({
26765
26823
  method: "get",
26766
26824
  path: "/{path}",
26767
26825
  summary: "Fetch CMS Node Content",
26768
- description: "Retrieves a fully hydrated CMS node along with its content blocks and inherited regions using $O(1)$ routing table lookups.",
26769
26826
  tags: ["Public Node API"],
26770
26827
  request: {
26771
- params: X({ path: J().optional().openapi({ description: "The full URL path or slug of the requested node" }) }),
26828
+ params: X({ path: J().optional() }),
26772
26829
  query: TS
26773
26830
  },
26774
26831
  responses: {
@@ -26777,11 +26834,11 @@ var TS = X({
26777
26834
  content: { "application/json": { schema: DS } }
26778
26835
  },
26779
26836
  404: {
26780
- description: "Node or Channel not found",
26837
+ description: "Not found",
26781
26838
  content: { "application/json": { schema: ES } }
26782
26839
  },
26783
26840
  500: {
26784
- description: "Server error during hydration",
26841
+ description: "Server error",
26785
26842
  content: { "application/json": { schema: ES } }
26786
26843
  }
26787
26844
  }
@@ -26794,36 +26851,43 @@ var kS = new $y(), AS = X({
26794
26851
  channelId: J().optional().openapi({ description: "Channel ID or key" }),
26795
26852
  limit: Ky().min(1).max(50).default(12).openapi({ description: "Number of items (max 50)" }),
26796
26853
  offset: Ky().min(0).default(0).openapi({ description: "Pagination offset" }),
26797
- sortBy: lv([
26798
- "updatedAt",
26799
- "createdAt",
26800
- "title_asc"
26801
- ]).default("updatedAt"),
26854
+ sortBy: J().default("updatedAt_desc").openapi({ description: "Sort field and direction" }),
26802
26855
  authors: G_([J(), z_(J())]).optional(),
26803
26856
  categories: G_([J(), z_(J())]).optional(),
26804
26857
  tags: G_([J(), z_(J())]).optional()
26805
26858
  }), jS = async (e) => {
26806
26859
  try {
26807
- 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];
26808
- 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));
26809
- let s = (/* @__PURE__ */ new Date()).toISOString();
26810
- a += " AND IFNULL(json_extract(dataJson, '$.startShowingAt'), '') <= ?", o.push(s), a += " AND IFNULL(json_extract(dataJson, '$.stopShowingAt'), '9999-12-31') >= ?", o.push(s);
26811
- let c = (e, t, n = !1) => {
26860
+ 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 = {};
26861
+ for (let e of i) {
26862
+ s[e] = [];
26863
+ let t = o.nodes?.[e] || {}, n = { ...t.fields || {} };
26864
+ t.tabs && Object.values(t.tabs).forEach((e) => {
26865
+ Object.assign(n, e.fields || {});
26866
+ });
26867
+ for (let [t, r] of Object.entries(n)) (r.showInList || r.showInLists) && s[e].push(t);
26868
+ }
26869
+ let c = `FROM content_nodes WHERE contentType IN (${a}) AND isHidden = 0 AND IFNULL(status, 'published') = 'published'`, l = [...i];
26870
+ 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));
26871
+ let u = (/* @__PURE__ */ new Date()).toISOString();
26872
+ c += " AND IFNULL(json_extract(dataJson, '$.startShowingAt'), '') <= ?", l.push(u), c += " AND IFNULL(json_extract(dataJson, '$.stopShowingAt'), '9999-12-31') >= ?", l.push(u);
26873
+ let d = (e, t, n = !1) => {
26812
26874
  let r = Array.isArray(t) ? t : t.split(",").map((e) => e.trim());
26813
26875
  if (r.length === 0) return;
26814
26876
  let i = r.map(() => "?").join(",");
26815
- 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));
26877
+ 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));
26816
26878
  };
26817
- n.authors && c("authors", n.authors, !0), n.categories && c("categories", n.categories, !1), n.tags && c("tags", n.tags, !1);
26818
- let l = "ORDER BY updatedAt DESC";
26819
- n.sortBy === "createdAt" ? l = "ORDER BY createdAt DESC" : n.sortBy === "title_asc" && (l = "ORDER BY LOWER(title) ASC");
26820
- let u = `SELECT id, title, slug, language, dataJson, createdAt, updatedAt ${a} ${l} LIMIT ? OFFSET ?`;
26821
- o.push(n.limit, n.offset);
26822
- let d = await t.prepare(u).all(...o), f = Array.isArray(d) ? d : d?.results || [], p = f.map((e) => {
26879
+ n.authors && d("authors", n.authors, !0), n.categories && d("categories", n.categories, !1), n.tags && d("tags", n.tags, !1);
26880
+ 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}`;
26881
+ 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}`);
26882
+ let v = `SELECT id, title, slug, language, dataJson, createdAt, updatedAt ${c} ${_} LIMIT ? OFFSET ?`;
26883
+ l.push(n.limit, n.offset);
26884
+ let y = await t.prepare(v).all(...l), b = Array.isArray(y) ? y : y?.results || [], x = b.map((e) => {
26823
26885
  let t = {};
26824
26886
  try {
26825
26887
  t = typeof e.dataJson == "string" ? JSON.parse(e.dataJson) : e.dataJson || {};
26826
26888
  } catch {}
26889
+ let n = {}, r = s[e.contentType || "article"] || [];
26890
+ for (let e of r) t[e] !== void 0 && (n[e] = t[e]);
26827
26891
  return {
26828
26892
  id: e.id,
26829
26893
  title: e.title,
@@ -26831,15 +26895,16 @@ var kS = new $y(), AS = X({
26831
26895
  language: e.language,
26832
26896
  createdAt: e.createdAt,
26833
26897
  updatedAt: e.updatedAt,
26898
+ ...n,
26834
26899
  excerpt: t.excerpt || "",
26835
26900
  image: t.image || t.coverImage || null,
26836
26901
  author: t.author || null
26837
26902
  };
26838
26903
  });
26839
26904
  return e.json({
26840
- items: p,
26841
- count: p.length,
26842
- rawCount: f.length,
26905
+ items: x,
26906
+ count: x.length,
26907
+ rawCount: b.length,
26843
26908
  limit: n.limit,
26844
26909
  offset: n.offset
26845
26910
  }, 200);
@@ -26901,11 +26966,11 @@ var IS = X({ treeParam: J().openapi({ description: "The ID or key of the request
26901
26966
  path: J(),
26902
26967
  nodeType: J().optional(),
26903
26968
  hidden: c_(),
26904
- summary: J(),
26969
+ summary: J().optional(),
26905
26970
  url: J().optional(),
26906
26971
  target: J().optional(),
26907
26972
  children: z_(zS).optional()
26908
- })).openapi("TreeItem"), BS = X({
26973
+ }).passthrough()).openapi("TreeItem"), BS = X({
26909
26974
  treeId: G_([c_(), J()]),
26910
26975
  key: J(),
26911
26976
  channelId: J(),
@@ -26963,42 +27028,42 @@ NS.openapi(VS, async (e) => {
26963
27028
  let t = await p.get(m);
26964
27029
  if (t) return e.header("X-Cache", "HIT"), e.json(t, 200);
26965
27030
  }
26966
- let g = u?.id || (l ? Number(n) : null), _ = {};
27031
+ let g = u?.id || (l ? Number(n) : null), _ = e.env?.BUNDLED_DEFINITIONS, v = px(_), y = v.treeExposedFields || ["summary"], b = {};
26967
27032
  if (u && u.dataJson) try {
26968
- 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 || {};
26969
- for (let [e, n] of Object.entries(t)) a[e]?.public === !0 && (_[e] = n);
27033
+ let e = typeof u.dataJson == "string" ? JSON.parse(u.dataJson) : u.dataJson, t = (v.trees?.[u.treeType || n] || v.trees?.site || {}).fields || {};
27034
+ for (let [n, r] of Object.entries(e)) t[n]?.public === !0 && (b[n] = r);
26970
27035
  } catch (e) {
26971
27036
  console.warn("[CMS Public Tree API] Failed to parse tree dataJson", e);
26972
27037
  }
26973
- let v = [];
27038
+ let x = [];
26974
27039
  if (g !== null) {
26975
27040
  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);
26976
- v = Array.isArray(e) ? e : e?.results || [];
27041
+ x = Array.isArray(e) ? e : e?.results || [];
26977
27042
  }
26978
- if ((!v || v.length === 0) && !u) return e.json({ error: `Tree '${n}' not found` }, 404);
26979
- let y = /* @__PURE__ */ new Map();
26980
- for (let e of v) {
26981
- let t = !e.parentId || e.parentId === "null" || e.parentId === "" ? null : e.parentId, n = t === null ? "__ROOT__" : String(t), r = y.get(n);
26982
- r ? r.push(e) : y.set(n, [e]);
27043
+ if ((!x || x.length === 0) && !u) return e.json({ error: `Tree '${n}' not found` }, 404);
27044
+ let S = /* @__PURE__ */ new Map();
27045
+ for (let e of x) {
27046
+ let t = !e.parentId || e.parentId === "null" || e.parentId === "" ? null : e.parentId, n = t === null ? "__ROOT__" : String(t), r = S.get(n);
27047
+ r ? r.push(e) : S.set(n, [e]);
26983
27048
  }
26984
- let b = /* @__PURE__ */ new Map();
26985
- for (let e of v) {
27049
+ let C = /* @__PURE__ */ new Map();
27050
+ for (let e of x) {
26986
27051
  let t = String(e.id), n = o && e.draftDataJson ? e.draftDataJson : e.dataJson;
26987
27052
  if (!n) {
26988
- b.set(t, {});
27053
+ C.set(t, {});
26989
27054
  continue;
26990
27055
  }
26991
27056
  try {
26992
27057
  let e = typeof n == "string" ? JSON.parse(n) : n;
26993
- b.set(t, e && typeof e == "object" ? e : {});
27058
+ C.set(t, e && typeof e == "object" ? e : {});
26994
27059
  } catch {
26995
- b.set(t, {});
27060
+ C.set(t, {});
26996
27061
  }
26997
27062
  }
26998
- function x(e = null, t = "") {
27063
+ function w(e = null, t = "") {
26999
27064
  let n = e == null || e === "" || e === "null" ? "__ROOT__" : String(e);
27000
- return (y.get(n) || []).map((e) => {
27001
- let n = b.get(String(e.id)) || {}, r = {};
27065
+ return (S.get(n) || []).map((e) => {
27066
+ let n = C.get(String(e.id)) || {}, r = {};
27002
27067
  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);
27003
27068
  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 = {
27004
27069
  id: e.id,
@@ -27009,24 +27074,24 @@ NS.openapi(VS, async (e) => {
27009
27074
  language: d,
27010
27075
  path: u,
27011
27076
  nodeType: e.nodeType,
27012
- hidden: a || !s ? 1 : 0,
27013
- summary: r.summary || ""
27077
+ hidden: a || !s ? 1 : 0
27014
27078
  };
27079
+ for (let e of y) r[e] !== void 0 && (p[e] = r[e]);
27015
27080
  e.nodeType === "external-link" && (r.url && (p.url = r.url), r.target && (p.target = r.target));
27016
27081
  let m = u === "/" ? "" : u;
27017
- return p.children = x(e.id, m), p;
27082
+ return p.children = w(e.id, m), p;
27018
27083
  }).filter((e) => o || !e.hidden);
27019
27084
  }
27020
- let S = {
27085
+ let T = {
27021
27086
  treeId: u?.id || g,
27022
27087
  key: u?.key || n,
27023
27088
  channelId: String(i),
27024
27089
  language: f,
27025
27090
  label: u?.label || n,
27026
- ..._,
27027
- items: x(null)
27091
+ ...b,
27092
+ items: w(null)
27028
27093
  };
27029
- return !o && !h && (e.header("X-Cache", "MISS"), await FS(p, m, S, 300)), e.json(S, 200);
27094
+ return !o && !h && (e.header("X-Cache", "MISS"), await FS(p, m, T, 300)), e.json(T, 200);
27030
27095
  } catch (t) {
27031
27096
  return console.error("[CMS Public Tree API] Error:", t), e.json({
27032
27097
  error: "Failed to fetch public tree",
@@ -30,7 +30,7 @@ async function f() {
30
30
  if (n(f)) l = (await import(t(f).href)).compileDefinitions;
31
31
  else if (n(p)) l = (await import(t(p).href)).compileDefinitions;
32
32
  else try {
33
- l = (await import("./dist-Bta0OpXl.js")).compileDefinitions;
33
+ l = (await import("./dist-D_Q1y4Kh.js")).compileDefinitions;
34
34
  } catch (e) {
35
35
  console.error("\x1B[31m ✖\x1B[0m \x1B[31mCould not resolve Kama Schema Engine:\x1B[0m", e), process.exit(1);
36
36
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brightsideoy/kama",
3
- "version": "1.0.0-alpha.19",
3
+ "version": "1.0.0-alpha.20",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",