@bettercms-ai/sdk 1.18.0 → 1.20.0

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
@@ -35,13 +35,24 @@ var BetterCMSError = class _BetterCMSError extends Error {
35
35
  * hint which field or rule failed (FLO-474). Mirrors the forms client's `fieldErrors`.
36
36
  */
37
37
  fieldErrors;
38
- constructor(message, status, code, bodyCode, fieldErrors) {
38
+ /**
39
+ * The parsed response body, when there was one.
40
+ *
41
+ * Several refusals carry STRUCTURED detail that neither `message` nor `fieldErrors` can hold,
42
+ * and which is the whole point of the refusal: a component publish 409s with the full
43
+ * `readiness` tuple (what evidence is missing, whether a human still has to approve it) and
44
+ * 422s with the `issues` naming the Layouts it would break. Collapsing those to a sentence
45
+ * leaves a caller able to report that something failed and not what to do about it.
46
+ */
47
+ body;
48
+ constructor(message, status, code, bodyCode, fieldErrors, body) {
39
49
  super(message);
40
50
  this.name = "BetterCMSError";
41
51
  this.status = status;
42
52
  this.code = code;
43
53
  this.bodyCode = bodyCode;
44
54
  this.fieldErrors = fieldErrors;
55
+ this.body = body;
45
56
  if (Error.captureStackTrace) {
46
57
  Error.captureStackTrace(this, _BetterCMSError);
47
58
  }
@@ -68,6 +79,7 @@ var BetterCMSError = class _BetterCMSError extends Error {
68
79
  let bodyCode;
69
80
  let fieldErrors;
70
81
  let code = statusToCode(res.status);
82
+ let raw;
71
83
  try {
72
84
  const body = await res.json();
73
85
  if (body?.errors && typeof body.errors === "object") {
@@ -83,9 +95,10 @@ var BetterCMSError = class _BetterCMSError extends Error {
83
95
  if (field) message = `${field}: ${detail}`;
84
96
  }
85
97
  if (body?.code) bodyCode = body.code;
98
+ raw = body;
86
99
  } catch {
87
100
  }
88
- return new _BetterCMSError(message, res.status, code, bodyCode, fieldErrors);
101
+ return new _BetterCMSError(message, res.status, code, bodyCode, fieldErrors, raw);
89
102
  }
90
103
  };
91
104
 
@@ -545,6 +558,13 @@ async function deleteModel(client, id) {
545
558
  }
546
559
 
547
560
  // src/methods/management/media.ts
561
+ async function updateAsset(client, id, input) {
562
+ const { data } = await client.fetchJSON(
563
+ client.url(`/management/media/${encodeURIComponent(id)}`),
564
+ { method: "PATCH", body: JSON.stringify(input) }
565
+ );
566
+ return data;
567
+ }
548
568
  var MIME_BY_EXT = {
549
569
  png: "image/png",
550
570
  jpg: "image/jpeg",
@@ -672,6 +692,10 @@ async function uploadAsset(client, input) {
672
692
  body: bytes
673
693
  }
674
694
  );
695
+ if (input.transcript && input.transcript.trim()) {
696
+ await updateAsset(client, data.id, { transcript: input.transcript });
697
+ return { ...data, transcript: input.transcript };
698
+ }
675
699
  return data;
676
700
  }
677
701
 
@@ -706,9 +730,10 @@ async function updateForm(client, id, input) {
706
730
  }
707
731
 
708
732
  // src/methods/management/components.ts
709
- async function listComponents(client) {
733
+ async function listComponents(client, options) {
734
+ const query = options?.select ? `?select=${options.select}` : "";
710
735
  const res = await client.fetchJSON(
711
- client.url("/management/components"),
736
+ client.url(`/management/components${query}`),
712
737
  { method: "GET" }
713
738
  );
714
739
  return res.data;
@@ -932,6 +957,10 @@ var BetterCMSManagementClient = class extends BetterCMSDeliveryClient {
932
957
  uploadAsset(input) {
933
958
  return uploadAsset(this, input);
934
959
  }
960
+ /** Set an asset's alt text, caption or transcript (video/audio only). `null` clears. */
961
+ updateAsset(id, input) {
962
+ return updateAsset(this, id, input);
963
+ }
935
964
  // ── Forms (read-only): discover dashboard-built forms to embed into site code ──
936
965
  /** List forms in the key's project (or workspace-level). */
937
966
  listForms() {
@@ -949,9 +978,8 @@ var BetterCMSManagementClient = class extends BetterCMSDeliveryClient {
949
978
  updateForm(id, input) {
950
979
  return updateForm(this, id, input);
951
980
  }
952
- // ── Components: discover + author reusable symbols ──
953
- listComponents() {
954
- return listComponents(this);
981
+ listComponents(options) {
982
+ return options?.select ? listComponents(this, { select: options.select }) : listComponents(this);
955
983
  }
956
984
  getComponent(id) {
957
985
  return getComponent(this, id);
@@ -1401,6 +1429,68 @@ function jsonLdNodes(schema) {
1401
1429
  }
1402
1430
  return out;
1403
1431
  }
1432
+ var SCHEMA_TYPE_CHOICES = [
1433
+ "WebPage",
1434
+ "AboutPage",
1435
+ "ContactPage",
1436
+ "CollectionPage",
1437
+ "Blog",
1438
+ "BlogPosting",
1439
+ "Article",
1440
+ "Product",
1441
+ "FAQPage",
1442
+ "Event",
1443
+ "Organization",
1444
+ "LocalBusiness"
1445
+ ];
1446
+ function compact(node) {
1447
+ return Object.fromEntries(Object.entries(node).filter(([, value]) => value != null && value !== ""));
1448
+ }
1449
+ function schemaNode(type, { name, description, image, url }) {
1450
+ switch (type) {
1451
+ case "BlogPosting":
1452
+ case "Article":
1453
+ return compact({ "@type": type, headline: name, description, image, url, mainEntityOfPage: url });
1454
+ case "Product":
1455
+ case "Event":
1456
+ return compact({ "@type": type, name, description, image, url });
1457
+ case "FAQPage":
1458
+ case "WebSite":
1459
+ return compact({ "@type": type, name, description, url });
1460
+ case "Organization":
1461
+ return compact({ "@type": type, name, description, url, logo: image });
1462
+ default:
1463
+ return compact({ "@type": type, name, description, url, image });
1464
+ }
1465
+ }
1466
+ function pageJsonLd(page, meta, canonical, siteSchema) {
1467
+ const custom = jsonLdNodes(meta.schema);
1468
+ if (custom.length > 0) return custom;
1469
+ const props = {
1470
+ name: (page.metaTitle || page.title || "").trim(),
1471
+ description: (page.metaDescription || "").trim(),
1472
+ image: (meta.og?.image || "").trim(),
1473
+ url: canonical.trim()
1474
+ };
1475
+ const schemaType = meta.schemaType;
1476
+ if (typeof schemaType === "string" && SCHEMA_TYPE_CHOICES.includes(schemaType)) {
1477
+ return [schemaNode(schemaType, props)];
1478
+ }
1479
+ if (page.slug === "home") {
1480
+ return jsonLdNodes(siteSchema).length > 0 ? [] : [schemaNode("WebSite", props)];
1481
+ }
1482
+ return [schemaNode("WebPage", props)];
1483
+ }
1484
+ function entrySeoInput(entry) {
1485
+ const { metaTitle, metaDescription, noindex, ...metaJson } = entry.seo ?? {};
1486
+ return {
1487
+ title: metaTitle || entry.slug,
1488
+ metaTitle: metaTitle ?? null,
1489
+ metaDescription: metaDescription ?? null,
1490
+ metaJson,
1491
+ noindex: noindex === true
1492
+ };
1493
+ }
1404
1494
  function resolveSeo(page, defaults = {}, location = {}) {
1405
1495
  const meta = page.metaJson ?? {};
1406
1496
  const title = page.metaTitle || page.title || "";
@@ -1428,7 +1518,9 @@ function resolveSeo(page, defaults = {}, location = {}) {
1428
1518
  image: twImage,
1429
1519
  site: defaults.twitterHandle || ""
1430
1520
  },
1431
- jsonLd: [...jsonLdNodes(defaults.siteSchema), ...jsonLdNodes(meta.schema)]
1521
+ jsonLd: [...jsonLdNodes(defaults.siteSchema), ...pageJsonLd(page, meta, canonical, defaults.siteSchema)],
1522
+ noindex: page.noindex === true,
1523
+ robots: { index: page.noindex !== true, follow: true }
1432
1524
  };
1433
1525
  }
1434
1526
 
@@ -1771,6 +1863,7 @@ export {
1771
1863
  deleteSubmission,
1772
1864
  deleteWorkspace,
1773
1865
  encodeStega,
1866
+ entrySeoInput,
1774
1867
  formInitialValues,
1775
1868
  getApiKeyUsage,
1776
1869
  getBlockType,