@bettercms-ai/sdk 1.8.0 → 1.9.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.cjs +59 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +69 -5
- package/dist/index.d.ts +69 -5
- package/dist/index.js +56 -6
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -71,6 +71,7 @@ __export(index_exports, {
|
|
|
71
71
|
imageUrlBuilder: () => import_image_url.default,
|
|
72
72
|
inviteMember: () => inviteMember,
|
|
73
73
|
isBlock: () => import_types.isBlock,
|
|
74
|
+
isRichText: () => isRichText,
|
|
74
75
|
listApiKeys: () => listApiKeys,
|
|
75
76
|
listEntries: () => listEntries,
|
|
76
77
|
listForms: () => listForms2,
|
|
@@ -81,11 +82,13 @@ __export(index_exports, {
|
|
|
81
82
|
listPages: () => listPages,
|
|
82
83
|
listSubmissions: () => listSubmissions,
|
|
83
84
|
listWorkspaces: () => listWorkspaces,
|
|
85
|
+
plain: () => plain,
|
|
84
86
|
publishPage: () => publishPage,
|
|
85
87
|
regenerateApiKey: () => regenerateApiKey,
|
|
86
88
|
removeMember: () => removeMember,
|
|
87
89
|
resolveSeo: () => resolveSeo,
|
|
88
90
|
revokeApiKey: () => revokeApiKey,
|
|
91
|
+
rich: () => rich,
|
|
89
92
|
search: () => search,
|
|
90
93
|
setPageContent: () => setPageContent,
|
|
91
94
|
shouldShowField: () => shouldShowField,
|
|
@@ -136,12 +139,20 @@ var BetterCMSError = class _BetterCMSError extends Error {
|
|
|
136
139
|
* shares a status with others (e.g. 409 slug-conflict vs 409 project-deleted).
|
|
137
140
|
*/
|
|
138
141
|
bodyCode;
|
|
139
|
-
|
|
142
|
+
/**
|
|
143
|
+
* Per-field validation messages from a 400 `{ errors: { field: message } }` body.
|
|
144
|
+
* The backend returns validation failures in this shape (not `message`/`error`), so
|
|
145
|
+
* without this the SDK collapsed every validation 400 to a bare "Bad Request" with no
|
|
146
|
+
* hint which field or rule failed (FLO-474). Mirrors the forms client's `fieldErrors`.
|
|
147
|
+
*/
|
|
148
|
+
fieldErrors;
|
|
149
|
+
constructor(message, status, code, bodyCode, fieldErrors) {
|
|
140
150
|
super(message);
|
|
141
151
|
this.name = "BetterCMSError";
|
|
142
152
|
this.status = status;
|
|
143
153
|
this.code = code;
|
|
144
154
|
this.bodyCode = bodyCode;
|
|
155
|
+
this.fieldErrors = fieldErrors;
|
|
145
156
|
if (Error.captureStackTrace) {
|
|
146
157
|
Error.captureStackTrace(this, _BetterCMSError);
|
|
147
158
|
}
|
|
@@ -152,25 +163,40 @@ var BetterCMSError = class _BetterCMSError extends Error {
|
|
|
152
163
|
message: this.message,
|
|
153
164
|
status: this.status,
|
|
154
165
|
code: this.code,
|
|
155
|
-
bodyCode: this.bodyCode
|
|
166
|
+
bodyCode: this.bodyCode,
|
|
167
|
+
fieldErrors: this.fieldErrors
|
|
156
168
|
};
|
|
157
169
|
}
|
|
158
170
|
/**
|
|
159
|
-
* Factory — creates a BetterCMSError from a failed fetch Response. Reads the
|
|
160
|
-
*
|
|
161
|
-
*
|
|
171
|
+
* Factory — creates a BetterCMSError from a failed fetch Response. Reads the body's
|
|
172
|
+
* `message` (or `error`) for the human message and `code` for a machine-readable
|
|
173
|
+
* condition surfaced as `bodyCode`. Validation failures arrive as `{ errors: {...} }`
|
|
174
|
+
* (no `message`/`error`), so fall back to the first field error for the message and
|
|
175
|
+
* expose the full map as `fieldErrors` (FLO-474).
|
|
162
176
|
*/
|
|
163
177
|
static async from(res) {
|
|
164
178
|
let message = res.statusText || "An error occurred";
|
|
165
179
|
let bodyCode;
|
|
180
|
+
let fieldErrors;
|
|
181
|
+
let code = statusToCode(res.status);
|
|
166
182
|
try {
|
|
167
183
|
const body = await res.json();
|
|
184
|
+
if (body?.errors && typeof body.errors === "object") {
|
|
185
|
+
fieldErrors = body.errors;
|
|
186
|
+
code = ErrorCodes.VALIDATION_ERROR;
|
|
187
|
+
}
|
|
168
188
|
if (body?.message) message = body.message;
|
|
169
189
|
else if (body?.error) message = body.error;
|
|
190
|
+
else if (fieldErrors) {
|
|
191
|
+
const [field, detail] = Object.entries(fieldErrors).find(
|
|
192
|
+
([, v]) => typeof v === "string" && v.length > 0
|
|
193
|
+
) ?? [];
|
|
194
|
+
if (field) message = `${field}: ${detail}`;
|
|
195
|
+
}
|
|
170
196
|
if (body?.code) bodyCode = body.code;
|
|
171
197
|
} catch {
|
|
172
198
|
}
|
|
173
|
-
return new _BetterCMSError(message, res.status,
|
|
199
|
+
return new _BetterCMSError(message, res.status, code, bodyCode, fieldErrors);
|
|
174
200
|
}
|
|
175
201
|
};
|
|
176
202
|
|
|
@@ -1235,6 +1261,30 @@ function stripStega(value) {
|
|
|
1235
1261
|
return value.replace(FRAME, "");
|
|
1236
1262
|
}
|
|
1237
1263
|
|
|
1264
|
+
// src/richtext.ts
|
|
1265
|
+
function isRichText(value) {
|
|
1266
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) && ("html" in value || "format" in value);
|
|
1267
|
+
}
|
|
1268
|
+
function plain(value) {
|
|
1269
|
+
if (typeof value === "string") return value;
|
|
1270
|
+
if (!isRichText(value) || typeof value.html !== "string") return "";
|
|
1271
|
+
return decodeEntities(value.html.replace(/<[^>]+>/g, "")).trim();
|
|
1272
|
+
}
|
|
1273
|
+
function rich(value, fallback = "") {
|
|
1274
|
+
const html = (typeof value === "string" ? escapeHtml(value) : isRichText(value) ? value.html ?? "" : "").trim();
|
|
1275
|
+
return html ? unwrapLoneBlock(html) : escapeHtml(fallback);
|
|
1276
|
+
}
|
|
1277
|
+
function unwrapLoneBlock(html) {
|
|
1278
|
+
const m = html.match(/^<(p|div|h[1-6])(?:\s[^>]*)?>([\s\S]*)<\/\1>$/i);
|
|
1279
|
+
return m && !new RegExp(`</${m[1]}>`, "i").test(m[2]) ? m[2] : html;
|
|
1280
|
+
}
|
|
1281
|
+
function escapeHtml(s) {
|
|
1282
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
1283
|
+
}
|
|
1284
|
+
function decodeEntities(s) {
|
|
1285
|
+
return s.replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/�?39;/g, "'").replace(/ /g, " ").replace(/&/g, "&");
|
|
1286
|
+
}
|
|
1287
|
+
|
|
1238
1288
|
// src/seo.ts
|
|
1239
1289
|
function jsonLdNodes(schema) {
|
|
1240
1290
|
if (!schema) return [];
|
|
@@ -1608,6 +1658,7 @@ var import_types = require("@bettercms-ai/types");
|
|
|
1608
1658
|
imageUrlBuilder,
|
|
1609
1659
|
inviteMember,
|
|
1610
1660
|
isBlock,
|
|
1661
|
+
isRichText,
|
|
1611
1662
|
listApiKeys,
|
|
1612
1663
|
listEntries,
|
|
1613
1664
|
listForms,
|
|
@@ -1618,11 +1669,13 @@ var import_types = require("@bettercms-ai/types");
|
|
|
1618
1669
|
listPages,
|
|
1619
1670
|
listSubmissions,
|
|
1620
1671
|
listWorkspaces,
|
|
1672
|
+
plain,
|
|
1621
1673
|
publishPage,
|
|
1622
1674
|
regenerateApiKey,
|
|
1623
1675
|
removeMember,
|
|
1624
1676
|
resolveSeo,
|
|
1625
1677
|
revokeApiKey,
|
|
1678
|
+
rich,
|
|
1626
1679
|
search,
|
|
1627
1680
|
setPageContent,
|
|
1628
1681
|
shouldShowField,
|