@bettercms-ai/sdk 1.14.0 → 1.16.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/README.md CHANGED
@@ -85,6 +85,40 @@ try {
85
85
  }
86
86
  ```
87
87
 
88
+ ## Draft previews and visual editing
89
+
90
+ A client created with `perspective: "drafts"` reads unpublished content — through a
91
+ `content:read:draft` API key, or through a `previewToken` minted for one document.
92
+
93
+ Draft reads also carry **stega provenance**: invisible zero-width characters appended to every
94
+ prose value, naming the entry and field it came from. That is what lets the dashboard's canvas
95
+ (and the `<VisualEditing>` overlay) map a rendered string back to its editor without guessing at
96
+ its text. It is **on by default for `perspective: "drafts"` from 1.15.0** — before that it had to
97
+ be asked for, and a preview build that did not know to ask rendered anonymous strings.
98
+
99
+ ```ts
100
+ const draft = createClient({
101
+ apiUrl,
102
+ workspace: "my-workspace",
103
+ apiKey: process.env.BETTERCMS_DRAFT_KEY,
104
+ perspective: "drafts", // stega is on
105
+ });
106
+
107
+ // Opt out — e.g. when diffing or checksumming draft content, where the invisible
108
+ // characters would show up as differences.
109
+ const plain = createClient({
110
+ apiUrl,
111
+ workspace: "my-workspace",
112
+ apiKey: process.env.BETTERCMS_DRAFT_KEY,
113
+ perspective: "drafts",
114
+ stega: false,
115
+ });
116
+ ```
117
+
118
+ Published reads never carry provenance, whatever `stega` is set to: the payload must not reach a
119
+ production build. Strip it yourself with `stripStega(value)` if you need the clean string, and
120
+ decode it with `decodeStega(value)`.
121
+
88
122
  ## API
89
123
 
90
124
  ### `BetterCMS.site(options)`
package/dist/index.cjs CHANGED
@@ -89,6 +89,7 @@ __export(index_exports, {
89
89
  listWorkspaces: () => listWorkspaces,
90
90
  plain: () => plain,
91
91
  portableText: () => portableText,
92
+ publishManagedLayout: () => publishManagedLayout,
92
93
  publishPage: () => publishPage,
93
94
  regenerateApiKey: () => regenerateApiKey,
94
95
  removeMember: () => removeMember,
@@ -905,6 +906,14 @@ async function commandManagedLayout(client, input) {
905
906
  });
906
907
  return result.data;
907
908
  }
909
+ async function publishManagedLayout(client, input) {
910
+ const result = await client.fetchJSON(client.url("/management/layout/publish"), {
911
+ method: "POST",
912
+ headers: { "If-Match": `W/"${input.ifMatch}"`, ...input.projectId ? { "X-BCMS-Project": input.projectId } : {} },
913
+ body: JSON.stringify({ scope: "global" })
914
+ });
915
+ return result.data;
916
+ }
908
917
 
909
918
  // src/management-client.ts
910
919
  var DEFAULT_BASE_URL2 = "https://api.bettercms.ai/v1";
@@ -1080,13 +1089,16 @@ var BetterCMSManagementClient = class extends BetterCMSDeliveryClient {
1080
1089
  extractComponent(input) {
1081
1090
  return extractComponent(this, input);
1082
1091
  }
1083
- // ── Layout: draft-only Global/page authoring; publishing remains dashboard-gated. ──
1092
+ // ── Layout: Global/page draft authoring + Global Layout publish (page overrides go live with the page). ──
1084
1093
  getManagedLayout(opts) {
1085
1094
  return getManagedLayout(this, opts);
1086
1095
  }
1087
1096
  commandManagedLayout(input) {
1088
1097
  return commandManagedLayout(this, input);
1089
1098
  }
1099
+ publishManagedLayout(input) {
1100
+ return publishManagedLayout(this, input);
1101
+ }
1090
1102
  // ── AI (Option B): write/rewrite/translate copy + generate SEO meta (BYOK-metered) ──
1091
1103
  /** Write, rewrite, or translate a piece of copy. Returns the suggested text. */
1092
1104
  writeContent(input) {
@@ -1307,6 +1319,7 @@ function createClient(options) {
1307
1319
  throw lastError ?? new BetterCMSError("Unreachable", 0, "NETWORK_ERROR");
1308
1320
  }
1309
1321
  const draft = perspective === "drafts";
1322
+ const stega = options.stega ?? draft;
1310
1323
  return {
1311
1324
  perspective,
1312
1325
  async getEntry(slug, opts) {
@@ -1314,12 +1327,12 @@ function createClient(options) {
1314
1327
  token: previewToken,
1315
1328
  depth: opts?.depth,
1316
1329
  select: opts?.select?.join(","),
1317
- stega: options.stega ? "1" : void 0
1330
+ stega: stega ? "1" : void 0
1318
1331
  })}` : `${base}/content-entries/${encodeURIComponent(slug)}${qs({
1319
1332
  depth: opts?.depth,
1320
1333
  select: opts?.select?.join(","),
1321
1334
  perspective: draft ? "draft" : void 0,
1322
- stega: draft && options.stega ? "1" : void 0
1335
+ stega: draft && stega ? "1" : void 0
1323
1336
  })}`;
1324
1337
  return unwrap(await fetchJSON(url));
1325
1338
  },
@@ -1331,7 +1344,7 @@ function createClient(options) {
1331
1344
  depth: opts?.depth,
1332
1345
  select: opts?.select?.join(","),
1333
1346
  perspective: draft ? "draft" : void 0,
1334
- stega: draft && options.stega ? "1" : void 0
1347
+ stega: draft && stega ? "1" : void 0
1335
1348
  })}`;
1336
1349
  return unwrap(await fetchJSON(url));
1337
1350
  },
@@ -1457,7 +1470,21 @@ function derivedCanonical({ siteUrl, path }) {
1457
1470
  function jsonLdNodes(schema) {
1458
1471
  if (!schema) return [];
1459
1472
  const arr = Array.isArray(schema) ? schema : [schema];
1460
- return arr.filter((node) => node && Object.keys(node).length > 0);
1473
+ const out = [];
1474
+ for (const node of arr) {
1475
+ if (!node || Object.keys(node).length === 0) continue;
1476
+ const graph = node["@graph"];
1477
+ if (Array.isArray(graph)) {
1478
+ for (const child of graph) {
1479
+ if (child && typeof child === "object" && !Array.isArray(child) && Object.keys(child).length > 0) {
1480
+ out.push(child);
1481
+ }
1482
+ }
1483
+ continue;
1484
+ }
1485
+ out.push(node);
1486
+ }
1487
+ return out;
1461
1488
  }
1462
1489
  function resolveSeo(page, defaults = {}, location = {}) {
1463
1490
  const meta = page.metaJson ?? {};
@@ -1861,6 +1888,7 @@ var import_types = require("@bettercms-ai/types");
1861
1888
  listWorkspaces,
1862
1889
  plain,
1863
1890
  portableText,
1891
+ publishManagedLayout,
1864
1892
  publishPage,
1865
1893
  regenerateApiKey,
1866
1894
  removeMember,