@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.d.cts
CHANGED
|
@@ -404,18 +404,28 @@ declare class BetterCMSError extends Error {
|
|
|
404
404
|
* shares a status with others (e.g. 409 slug-conflict vs 409 project-deleted).
|
|
405
405
|
*/
|
|
406
406
|
readonly bodyCode?: string;
|
|
407
|
-
|
|
407
|
+
/**
|
|
408
|
+
* Per-field validation messages from a 400 `{ errors: { field: message } }` body.
|
|
409
|
+
* The backend returns validation failures in this shape (not `message`/`error`), so
|
|
410
|
+
* without this the SDK collapsed every validation 400 to a bare "Bad Request" with no
|
|
411
|
+
* hint which field or rule failed (FLO-474). Mirrors the forms client's `fieldErrors`.
|
|
412
|
+
*/
|
|
413
|
+
readonly fieldErrors?: Record<string, string>;
|
|
414
|
+
constructor(message: string, status: number, code: BetterCMSErrorCode, bodyCode?: string, fieldErrors?: Record<string, string>);
|
|
408
415
|
toJSON(): {
|
|
409
416
|
name: string;
|
|
410
417
|
message: string;
|
|
411
418
|
status: number;
|
|
412
419
|
code: BetterCMSErrorCode;
|
|
413
420
|
bodyCode: string | undefined;
|
|
421
|
+
fieldErrors: Record<string, string> | undefined;
|
|
414
422
|
};
|
|
415
423
|
/**
|
|
416
|
-
* Factory — creates a BetterCMSError from a failed fetch Response. Reads the
|
|
417
|
-
*
|
|
418
|
-
*
|
|
424
|
+
* Factory — creates a BetterCMSError from a failed fetch Response. Reads the body's
|
|
425
|
+
* `message` (or `error`) for the human message and `code` for a machine-readable
|
|
426
|
+
* condition surfaced as `bodyCode`. Validation failures arrive as `{ errors: {...} }`
|
|
427
|
+
* (no `message`/`error`), so fall back to the first field error for the message and
|
|
428
|
+
* expose the full map as `fieldErrors` (FLO-474).
|
|
419
429
|
*/
|
|
420
430
|
static from(res: Response): Promise<BetterCMSError>;
|
|
421
431
|
}
|
|
@@ -840,6 +850,60 @@ declare function decodeStega(value: string): {
|
|
|
840
850
|
/** Remove any stega payload, returning the clean string. */
|
|
841
851
|
declare function stripStega(value: string): string;
|
|
842
852
|
|
|
853
|
+
/**
|
|
854
|
+
* Reading a rich-text field, for any site.
|
|
855
|
+
*
|
|
856
|
+
* A `text` field delivers a bare string. A `richtext` field delivers the canonical envelope
|
|
857
|
+
* `{ format, value, html }`. Those are different shapes, and switching a field's type in the
|
|
858
|
+
* CMS switches which one your site receives — the Visual Editor offers exactly that switch,
|
|
859
|
+
* so it happens on live projects. A template that interpolates the value directly then
|
|
860
|
+
* renders `[object Object]` (or, in React, throws `Objects are not valid as a React child`).
|
|
861
|
+
*
|
|
862
|
+
* No payload can be both structured and safe to interpolate, which is why every headless CMS
|
|
863
|
+
* requires a renderer for rich text. These are ours:
|
|
864
|
+
*
|
|
865
|
+
* plain(v) → text, for <title>, meta descriptions, JSON-LD, alt text, aria-label
|
|
866
|
+
* rich(v) → HTML, for `set:html` / `dangerouslySetInnerHTML`
|
|
867
|
+
*
|
|
868
|
+
* Both accept a bare string, so a field can be switched in the CMS without touching the site.
|
|
869
|
+
*
|
|
870
|
+
* <h1 set:html={rich(page.heroTitle)} /> // Astro
|
|
871
|
+
* <h1 dangerouslySetInnerHTML={{ __html: rich(f.heroTitle) }}/> // React
|
|
872
|
+
* seo({ title: plain(page.heroTitle) })
|
|
873
|
+
*/
|
|
874
|
+
/** The canonical rich-text envelope returned by the Delivery API. */
|
|
875
|
+
interface RichTextValue {
|
|
876
|
+
readonly format?: string;
|
|
877
|
+
readonly value?: unknown;
|
|
878
|
+
/** Server-rendered, sanitized HTML. Computed on write. */
|
|
879
|
+
readonly html?: string;
|
|
880
|
+
}
|
|
881
|
+
/**
|
|
882
|
+
* A field that may arrive as either shape. Type author-editable text fields with this and the
|
|
883
|
+
* compiler routes you through `plain()`/`rich()`, so a type switch in the CMS can never reach
|
|
884
|
+
* production as `[object Object]`.
|
|
885
|
+
*/
|
|
886
|
+
type TextOrRich = string | RichTextValue | null | undefined;
|
|
887
|
+
/** True when the value is a rich-text envelope rather than a bare string. */
|
|
888
|
+
declare function isRichText(value: unknown): value is RichTextValue;
|
|
889
|
+
/**
|
|
890
|
+
* Plain text for an attribute context — `<title>`, meta description, JSON-LD, `alt`.
|
|
891
|
+
* Strips tags and decodes the entities that survive stripping, so the result is text the
|
|
892
|
+
* consumer can escape once without double-escaping.
|
|
893
|
+
*/
|
|
894
|
+
declare function plain(value: TextOrRich): string;
|
|
895
|
+
/**
|
|
896
|
+
* Renderable HTML. Rich text keeps its inline marks (the server sanitizes `html` on write);
|
|
897
|
+
* a bare string is escaped, so a plain field can never inject markup.
|
|
898
|
+
*
|
|
899
|
+
* A lone wrapping block is unwrapped: a field switched from `text` stores its value as
|
|
900
|
+
* `<p>…</p>`, but it renders inside the element that already is the block — and
|
|
901
|
+
* `<h1><p>…</p></h1>` is invalid, the parser closes the heading at the `<p>` and the text
|
|
902
|
+
* falls out of it. Values with real block structure (several paragraphs, a list) are left
|
|
903
|
+
* alone, so a body field still renders as a document.
|
|
904
|
+
*/
|
|
905
|
+
declare function rich(value: TextOrRich, fallback?: string): string;
|
|
906
|
+
|
|
843
907
|
/**
|
|
844
908
|
* resolveSeo — framework-agnostic page-over-site SEO merge for headless consumers.
|
|
845
909
|
*
|
|
@@ -1111,4 +1175,4 @@ declare function inviteMember(client: BetterCMSAdminClient, workspaceId: string,
|
|
|
1111
1175
|
declare function updateMemberRole(client: BetterCMSAdminClient, workspaceId: string, memberId: string, role: MemberRole): Promise<Member>;
|
|
1112
1176
|
declare function removeMember(client: BetterCMSAdminClient, workspaceId: string, memberId: string): Promise<void>;
|
|
1113
1177
|
|
|
1114
|
-
export { type AddPageFieldsInput, type ApiKeyUsage, type ApiKeyWithRaw, type AuthResult, BetterCMSError as BCMSClientError, ErrorCodes as BCMSErrorCodes, BetterCMS, BetterCMSAdminClient, type BetterCMSAdminOptions, BetterCMSDeliveryClient, BetterCMSError, BetterCMSManagementClient, type BetterCMSManagementOptions, type BetterCMSReadClient, type BetterCMSSiteOptions, type CreateApiKeyInput, type CreateClientOptions, type CreateEntryInput, type CreateFormInput, type CreateManagedPageInput, type CreateModelInput, type CreatePageInput, type CreateWorkspaceInput, type DeliveryForm, type DeliveryFormField, type DeliveryFormFieldType, ErrorCodes, type FormFieldInput, type FormListOptions, type FormSubmitError, type FormValue, type FormValues, type GetEntryOptions, type ListContentAllOptions, type ListContentOptions, type ListEntriesFilter, type ListEntriesOptions, type ListPagesOptions, type ManagedComponent, type ManagedComponentInput, type ManagedContentEntry, type ManagedContentModel, type ManagedForm, type ManagedFormInput, type ManagedPage, type ManagementClient, type MediaListOptions, type MediaMetadata, type Member, type MemberRole, type PageListOptions, type PendingInvite, type ResolvedSeo, type SearchHit, type SearchOptions, type SeoInput, type SeoMeta, type SeoMetaInput, type SetPageContentInput, type StegaPayload, type SubmissionListOptions, type SubmitFormOptions, type SubmitFormResult, type UpdateApiKeyInput, type UpdateEntryInput, type UpdateFormInput, type UpdateModelInput, type UpdatePageInput, type UpdateWorkspaceInput, type UploadAssetInput, type UploadedAsset, type WriteContentInput, addModelFields, addPageFields, createApiKey, createClient, createEntry, createForm, createManagedPage, createModel, createPage, createWorkspace, decodeStega, deleteForm, deleteMedia, deletePage, deleteSubmission, deleteWorkspace, encodeStega, formInitialValues, getApiKeyUsage, getEntry, getForm, getManagedPage, getMedia, getMember, getModel, getPage, getSubmission, getWorkspace, inviteMember, listApiKeys, listEntries, listForms, listManagedPages, listMedia, listMembers, listModels, listPages, listSubmissions, listWorkspaces, publishPage, regenerateApiKey, removeMember, resolveSeo, revokeApiKey, search, setPageContent, shouldShowField, signIn, signInWithGithub, signInWithGoogle, signUp, stripStega, submitForm, updateApiKey, updateEntry, updateForm, updateMemberRole, updateModel, updatePage, updateWorkspace, uploadMedia };
|
|
1178
|
+
export { type AddPageFieldsInput, type ApiKeyUsage, type ApiKeyWithRaw, type AuthResult, BetterCMSError as BCMSClientError, ErrorCodes as BCMSErrorCodes, BetterCMS, BetterCMSAdminClient, type BetterCMSAdminOptions, BetterCMSDeliveryClient, BetterCMSError, BetterCMSManagementClient, type BetterCMSManagementOptions, type BetterCMSReadClient, type BetterCMSSiteOptions, type CreateApiKeyInput, type CreateClientOptions, type CreateEntryInput, type CreateFormInput, type CreateManagedPageInput, type CreateModelInput, type CreatePageInput, type CreateWorkspaceInput, type DeliveryForm, type DeliveryFormField, type DeliveryFormFieldType, ErrorCodes, type FormFieldInput, type FormListOptions, type FormSubmitError, type FormValue, type FormValues, type GetEntryOptions, type ListContentAllOptions, type ListContentOptions, type ListEntriesFilter, type ListEntriesOptions, type ListPagesOptions, type ManagedComponent, type ManagedComponentInput, type ManagedContentEntry, type ManagedContentModel, type ManagedForm, type ManagedFormInput, type ManagedPage, type ManagementClient, type MediaListOptions, type MediaMetadata, type Member, type MemberRole, type PageListOptions, type PendingInvite, type ResolvedSeo, type RichTextValue, type SearchHit, type SearchOptions, type SeoInput, type SeoMeta, type SeoMetaInput, type SetPageContentInput, type StegaPayload, type SubmissionListOptions, type SubmitFormOptions, type SubmitFormResult, type TextOrRich, type UpdateApiKeyInput, type UpdateEntryInput, type UpdateFormInput, type UpdateModelInput, type UpdatePageInput, type UpdateWorkspaceInput, type UploadAssetInput, type UploadedAsset, type WriteContentInput, addModelFields, addPageFields, createApiKey, createClient, createEntry, createForm, createManagedPage, createModel, createPage, createWorkspace, decodeStega, deleteForm, deleteMedia, deletePage, deleteSubmission, deleteWorkspace, encodeStega, formInitialValues, getApiKeyUsage, getEntry, getForm, getManagedPage, getMedia, getMember, getModel, getPage, getSubmission, getWorkspace, inviteMember, isRichText, listApiKeys, listEntries, listForms, listManagedPages, listMedia, listMembers, listModels, listPages, listSubmissions, listWorkspaces, plain, publishPage, regenerateApiKey, removeMember, resolveSeo, revokeApiKey, rich, search, setPageContent, shouldShowField, signIn, signInWithGithub, signInWithGoogle, signUp, stripStega, submitForm, updateApiKey, updateEntry, updateForm, updateMemberRole, updateModel, updatePage, updateWorkspace, uploadMedia };
|
package/dist/index.d.ts
CHANGED
|
@@ -404,18 +404,28 @@ declare class BetterCMSError extends Error {
|
|
|
404
404
|
* shares a status with others (e.g. 409 slug-conflict vs 409 project-deleted).
|
|
405
405
|
*/
|
|
406
406
|
readonly bodyCode?: string;
|
|
407
|
-
|
|
407
|
+
/**
|
|
408
|
+
* Per-field validation messages from a 400 `{ errors: { field: message } }` body.
|
|
409
|
+
* The backend returns validation failures in this shape (not `message`/`error`), so
|
|
410
|
+
* without this the SDK collapsed every validation 400 to a bare "Bad Request" with no
|
|
411
|
+
* hint which field or rule failed (FLO-474). Mirrors the forms client's `fieldErrors`.
|
|
412
|
+
*/
|
|
413
|
+
readonly fieldErrors?: Record<string, string>;
|
|
414
|
+
constructor(message: string, status: number, code: BetterCMSErrorCode, bodyCode?: string, fieldErrors?: Record<string, string>);
|
|
408
415
|
toJSON(): {
|
|
409
416
|
name: string;
|
|
410
417
|
message: string;
|
|
411
418
|
status: number;
|
|
412
419
|
code: BetterCMSErrorCode;
|
|
413
420
|
bodyCode: string | undefined;
|
|
421
|
+
fieldErrors: Record<string, string> | undefined;
|
|
414
422
|
};
|
|
415
423
|
/**
|
|
416
|
-
* Factory — creates a BetterCMSError from a failed fetch Response. Reads the
|
|
417
|
-
*
|
|
418
|
-
*
|
|
424
|
+
* Factory — creates a BetterCMSError from a failed fetch Response. Reads the body's
|
|
425
|
+
* `message` (or `error`) for the human message and `code` for a machine-readable
|
|
426
|
+
* condition surfaced as `bodyCode`. Validation failures arrive as `{ errors: {...} }`
|
|
427
|
+
* (no `message`/`error`), so fall back to the first field error for the message and
|
|
428
|
+
* expose the full map as `fieldErrors` (FLO-474).
|
|
419
429
|
*/
|
|
420
430
|
static from(res: Response): Promise<BetterCMSError>;
|
|
421
431
|
}
|
|
@@ -840,6 +850,60 @@ declare function decodeStega(value: string): {
|
|
|
840
850
|
/** Remove any stega payload, returning the clean string. */
|
|
841
851
|
declare function stripStega(value: string): string;
|
|
842
852
|
|
|
853
|
+
/**
|
|
854
|
+
* Reading a rich-text field, for any site.
|
|
855
|
+
*
|
|
856
|
+
* A `text` field delivers a bare string. A `richtext` field delivers the canonical envelope
|
|
857
|
+
* `{ format, value, html }`. Those are different shapes, and switching a field's type in the
|
|
858
|
+
* CMS switches which one your site receives — the Visual Editor offers exactly that switch,
|
|
859
|
+
* so it happens on live projects. A template that interpolates the value directly then
|
|
860
|
+
* renders `[object Object]` (or, in React, throws `Objects are not valid as a React child`).
|
|
861
|
+
*
|
|
862
|
+
* No payload can be both structured and safe to interpolate, which is why every headless CMS
|
|
863
|
+
* requires a renderer for rich text. These are ours:
|
|
864
|
+
*
|
|
865
|
+
* plain(v) → text, for <title>, meta descriptions, JSON-LD, alt text, aria-label
|
|
866
|
+
* rich(v) → HTML, for `set:html` / `dangerouslySetInnerHTML`
|
|
867
|
+
*
|
|
868
|
+
* Both accept a bare string, so a field can be switched in the CMS without touching the site.
|
|
869
|
+
*
|
|
870
|
+
* <h1 set:html={rich(page.heroTitle)} /> // Astro
|
|
871
|
+
* <h1 dangerouslySetInnerHTML={{ __html: rich(f.heroTitle) }}/> // React
|
|
872
|
+
* seo({ title: plain(page.heroTitle) })
|
|
873
|
+
*/
|
|
874
|
+
/** The canonical rich-text envelope returned by the Delivery API. */
|
|
875
|
+
interface RichTextValue {
|
|
876
|
+
readonly format?: string;
|
|
877
|
+
readonly value?: unknown;
|
|
878
|
+
/** Server-rendered, sanitized HTML. Computed on write. */
|
|
879
|
+
readonly html?: string;
|
|
880
|
+
}
|
|
881
|
+
/**
|
|
882
|
+
* A field that may arrive as either shape. Type author-editable text fields with this and the
|
|
883
|
+
* compiler routes you through `plain()`/`rich()`, so a type switch in the CMS can never reach
|
|
884
|
+
* production as `[object Object]`.
|
|
885
|
+
*/
|
|
886
|
+
type TextOrRich = string | RichTextValue | null | undefined;
|
|
887
|
+
/** True when the value is a rich-text envelope rather than a bare string. */
|
|
888
|
+
declare function isRichText(value: unknown): value is RichTextValue;
|
|
889
|
+
/**
|
|
890
|
+
* Plain text for an attribute context — `<title>`, meta description, JSON-LD, `alt`.
|
|
891
|
+
* Strips tags and decodes the entities that survive stripping, so the result is text the
|
|
892
|
+
* consumer can escape once without double-escaping.
|
|
893
|
+
*/
|
|
894
|
+
declare function plain(value: TextOrRich): string;
|
|
895
|
+
/**
|
|
896
|
+
* Renderable HTML. Rich text keeps its inline marks (the server sanitizes `html` on write);
|
|
897
|
+
* a bare string is escaped, so a plain field can never inject markup.
|
|
898
|
+
*
|
|
899
|
+
* A lone wrapping block is unwrapped: a field switched from `text` stores its value as
|
|
900
|
+
* `<p>…</p>`, but it renders inside the element that already is the block — and
|
|
901
|
+
* `<h1><p>…</p></h1>` is invalid, the parser closes the heading at the `<p>` and the text
|
|
902
|
+
* falls out of it. Values with real block structure (several paragraphs, a list) are left
|
|
903
|
+
* alone, so a body field still renders as a document.
|
|
904
|
+
*/
|
|
905
|
+
declare function rich(value: TextOrRich, fallback?: string): string;
|
|
906
|
+
|
|
843
907
|
/**
|
|
844
908
|
* resolveSeo — framework-agnostic page-over-site SEO merge for headless consumers.
|
|
845
909
|
*
|
|
@@ -1111,4 +1175,4 @@ declare function inviteMember(client: BetterCMSAdminClient, workspaceId: string,
|
|
|
1111
1175
|
declare function updateMemberRole(client: BetterCMSAdminClient, workspaceId: string, memberId: string, role: MemberRole): Promise<Member>;
|
|
1112
1176
|
declare function removeMember(client: BetterCMSAdminClient, workspaceId: string, memberId: string): Promise<void>;
|
|
1113
1177
|
|
|
1114
|
-
export { type AddPageFieldsInput, type ApiKeyUsage, type ApiKeyWithRaw, type AuthResult, BetterCMSError as BCMSClientError, ErrorCodes as BCMSErrorCodes, BetterCMS, BetterCMSAdminClient, type BetterCMSAdminOptions, BetterCMSDeliveryClient, BetterCMSError, BetterCMSManagementClient, type BetterCMSManagementOptions, type BetterCMSReadClient, type BetterCMSSiteOptions, type CreateApiKeyInput, type CreateClientOptions, type CreateEntryInput, type CreateFormInput, type CreateManagedPageInput, type CreateModelInput, type CreatePageInput, type CreateWorkspaceInput, type DeliveryForm, type DeliveryFormField, type DeliveryFormFieldType, ErrorCodes, type FormFieldInput, type FormListOptions, type FormSubmitError, type FormValue, type FormValues, type GetEntryOptions, type ListContentAllOptions, type ListContentOptions, type ListEntriesFilter, type ListEntriesOptions, type ListPagesOptions, type ManagedComponent, type ManagedComponentInput, type ManagedContentEntry, type ManagedContentModel, type ManagedForm, type ManagedFormInput, type ManagedPage, type ManagementClient, type MediaListOptions, type MediaMetadata, type Member, type MemberRole, type PageListOptions, type PendingInvite, type ResolvedSeo, type SearchHit, type SearchOptions, type SeoInput, type SeoMeta, type SeoMetaInput, type SetPageContentInput, type StegaPayload, type SubmissionListOptions, type SubmitFormOptions, type SubmitFormResult, type UpdateApiKeyInput, type UpdateEntryInput, type UpdateFormInput, type UpdateModelInput, type UpdatePageInput, type UpdateWorkspaceInput, type UploadAssetInput, type UploadedAsset, type WriteContentInput, addModelFields, addPageFields, createApiKey, createClient, createEntry, createForm, createManagedPage, createModel, createPage, createWorkspace, decodeStega, deleteForm, deleteMedia, deletePage, deleteSubmission, deleteWorkspace, encodeStega, formInitialValues, getApiKeyUsage, getEntry, getForm, getManagedPage, getMedia, getMember, getModel, getPage, getSubmission, getWorkspace, inviteMember, listApiKeys, listEntries, listForms, listManagedPages, listMedia, listMembers, listModels, listPages, listSubmissions, listWorkspaces, publishPage, regenerateApiKey, removeMember, resolveSeo, revokeApiKey, search, setPageContent, shouldShowField, signIn, signInWithGithub, signInWithGoogle, signUp, stripStega, submitForm, updateApiKey, updateEntry, updateForm, updateMemberRole, updateModel, updatePage, updateWorkspace, uploadMedia };
|
|
1178
|
+
export { type AddPageFieldsInput, type ApiKeyUsage, type ApiKeyWithRaw, type AuthResult, BetterCMSError as BCMSClientError, ErrorCodes as BCMSErrorCodes, BetterCMS, BetterCMSAdminClient, type BetterCMSAdminOptions, BetterCMSDeliveryClient, BetterCMSError, BetterCMSManagementClient, type BetterCMSManagementOptions, type BetterCMSReadClient, type BetterCMSSiteOptions, type CreateApiKeyInput, type CreateClientOptions, type CreateEntryInput, type CreateFormInput, type CreateManagedPageInput, type CreateModelInput, type CreatePageInput, type CreateWorkspaceInput, type DeliveryForm, type DeliveryFormField, type DeliveryFormFieldType, ErrorCodes, type FormFieldInput, type FormListOptions, type FormSubmitError, type FormValue, type FormValues, type GetEntryOptions, type ListContentAllOptions, type ListContentOptions, type ListEntriesFilter, type ListEntriesOptions, type ListPagesOptions, type ManagedComponent, type ManagedComponentInput, type ManagedContentEntry, type ManagedContentModel, type ManagedForm, type ManagedFormInput, type ManagedPage, type ManagementClient, type MediaListOptions, type MediaMetadata, type Member, type MemberRole, type PageListOptions, type PendingInvite, type ResolvedSeo, type RichTextValue, type SearchHit, type SearchOptions, type SeoInput, type SeoMeta, type SeoMetaInput, type SetPageContentInput, type StegaPayload, type SubmissionListOptions, type SubmitFormOptions, type SubmitFormResult, type TextOrRich, type UpdateApiKeyInput, type UpdateEntryInput, type UpdateFormInput, type UpdateModelInput, type UpdatePageInput, type UpdateWorkspaceInput, type UploadAssetInput, type UploadedAsset, type WriteContentInput, addModelFields, addPageFields, createApiKey, createClient, createEntry, createForm, createManagedPage, createModel, createPage, createWorkspace, decodeStega, deleteForm, deleteMedia, deletePage, deleteSubmission, deleteWorkspace, encodeStega, formInitialValues, getApiKeyUsage, getEntry, getForm, getManagedPage, getMedia, getMember, getModel, getPage, getSubmission, getWorkspace, inviteMember, isRichText, listApiKeys, listEntries, listForms, listManagedPages, listMedia, listMembers, listModels, listPages, listSubmissions, listWorkspaces, plain, publishPage, regenerateApiKey, removeMember, resolveSeo, revokeApiKey, rich, search, setPageContent, shouldShowField, signIn, signInWithGithub, signInWithGoogle, signUp, stripStega, submitForm, updateApiKey, updateEntry, updateForm, updateMemberRole, updateModel, updatePage, updateWorkspace, uploadMedia };
|
package/dist/index.js
CHANGED
|
@@ -28,12 +28,20 @@ var BetterCMSError = class _BetterCMSError extends Error {
|
|
|
28
28
|
* shares a status with others (e.g. 409 slug-conflict vs 409 project-deleted).
|
|
29
29
|
*/
|
|
30
30
|
bodyCode;
|
|
31
|
-
|
|
31
|
+
/**
|
|
32
|
+
* Per-field validation messages from a 400 `{ errors: { field: message } }` body.
|
|
33
|
+
* The backend returns validation failures in this shape (not `message`/`error`), so
|
|
34
|
+
* without this the SDK collapsed every validation 400 to a bare "Bad Request" with no
|
|
35
|
+
* hint which field or rule failed (FLO-474). Mirrors the forms client's `fieldErrors`.
|
|
36
|
+
*/
|
|
37
|
+
fieldErrors;
|
|
38
|
+
constructor(message, status, code, bodyCode, fieldErrors) {
|
|
32
39
|
super(message);
|
|
33
40
|
this.name = "BetterCMSError";
|
|
34
41
|
this.status = status;
|
|
35
42
|
this.code = code;
|
|
36
43
|
this.bodyCode = bodyCode;
|
|
44
|
+
this.fieldErrors = fieldErrors;
|
|
37
45
|
if (Error.captureStackTrace) {
|
|
38
46
|
Error.captureStackTrace(this, _BetterCMSError);
|
|
39
47
|
}
|
|
@@ -44,25 +52,40 @@ var BetterCMSError = class _BetterCMSError extends Error {
|
|
|
44
52
|
message: this.message,
|
|
45
53
|
status: this.status,
|
|
46
54
|
code: this.code,
|
|
47
|
-
bodyCode: this.bodyCode
|
|
55
|
+
bodyCode: this.bodyCode,
|
|
56
|
+
fieldErrors: this.fieldErrors
|
|
48
57
|
};
|
|
49
58
|
}
|
|
50
59
|
/**
|
|
51
|
-
* Factory — creates a BetterCMSError from a failed fetch Response. Reads the
|
|
52
|
-
*
|
|
53
|
-
*
|
|
60
|
+
* Factory — creates a BetterCMSError from a failed fetch Response. Reads the body's
|
|
61
|
+
* `message` (or `error`) for the human message and `code` for a machine-readable
|
|
62
|
+
* condition surfaced as `bodyCode`. Validation failures arrive as `{ errors: {...} }`
|
|
63
|
+
* (no `message`/`error`), so fall back to the first field error for the message and
|
|
64
|
+
* expose the full map as `fieldErrors` (FLO-474).
|
|
54
65
|
*/
|
|
55
66
|
static async from(res) {
|
|
56
67
|
let message = res.statusText || "An error occurred";
|
|
57
68
|
let bodyCode;
|
|
69
|
+
let fieldErrors;
|
|
70
|
+
let code = statusToCode(res.status);
|
|
58
71
|
try {
|
|
59
72
|
const body = await res.json();
|
|
73
|
+
if (body?.errors && typeof body.errors === "object") {
|
|
74
|
+
fieldErrors = body.errors;
|
|
75
|
+
code = ErrorCodes.VALIDATION_ERROR;
|
|
76
|
+
}
|
|
60
77
|
if (body?.message) message = body.message;
|
|
61
78
|
else if (body?.error) message = body.error;
|
|
79
|
+
else if (fieldErrors) {
|
|
80
|
+
const [field, detail] = Object.entries(fieldErrors).find(
|
|
81
|
+
([, v]) => typeof v === "string" && v.length > 0
|
|
82
|
+
) ?? [];
|
|
83
|
+
if (field) message = `${field}: ${detail}`;
|
|
84
|
+
}
|
|
62
85
|
if (body?.code) bodyCode = body.code;
|
|
63
86
|
} catch {
|
|
64
87
|
}
|
|
65
|
-
return new _BetterCMSError(message, res.status,
|
|
88
|
+
return new _BetterCMSError(message, res.status, code, bodyCode, fieldErrors);
|
|
66
89
|
}
|
|
67
90
|
};
|
|
68
91
|
|
|
@@ -1127,6 +1150,30 @@ function stripStega(value) {
|
|
|
1127
1150
|
return value.replace(FRAME, "");
|
|
1128
1151
|
}
|
|
1129
1152
|
|
|
1153
|
+
// src/richtext.ts
|
|
1154
|
+
function isRichText(value) {
|
|
1155
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) && ("html" in value || "format" in value);
|
|
1156
|
+
}
|
|
1157
|
+
function plain(value) {
|
|
1158
|
+
if (typeof value === "string") return value;
|
|
1159
|
+
if (!isRichText(value) || typeof value.html !== "string") return "";
|
|
1160
|
+
return decodeEntities(value.html.replace(/<[^>]+>/g, "")).trim();
|
|
1161
|
+
}
|
|
1162
|
+
function rich(value, fallback = "") {
|
|
1163
|
+
const html = (typeof value === "string" ? escapeHtml(value) : isRichText(value) ? value.html ?? "" : "").trim();
|
|
1164
|
+
return html ? unwrapLoneBlock(html) : escapeHtml(fallback);
|
|
1165
|
+
}
|
|
1166
|
+
function unwrapLoneBlock(html) {
|
|
1167
|
+
const m = html.match(/^<(p|div|h[1-6])(?:\s[^>]*)?>([\s\S]*)<\/\1>$/i);
|
|
1168
|
+
return m && !new RegExp(`</${m[1]}>`, "i").test(m[2]) ? m[2] : html;
|
|
1169
|
+
}
|
|
1170
|
+
function escapeHtml(s) {
|
|
1171
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
1172
|
+
}
|
|
1173
|
+
function decodeEntities(s) {
|
|
1174
|
+
return s.replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/�?39;/g, "'").replace(/ /g, " ").replace(/&/g, "&");
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1130
1177
|
// src/seo.ts
|
|
1131
1178
|
function jsonLdNodes(schema) {
|
|
1132
1179
|
if (!schema) return [];
|
|
@@ -1499,6 +1546,7 @@ export {
|
|
|
1499
1546
|
default2 as imageUrlBuilder,
|
|
1500
1547
|
inviteMember,
|
|
1501
1548
|
isBlock,
|
|
1549
|
+
isRichText,
|
|
1502
1550
|
listApiKeys,
|
|
1503
1551
|
listEntries,
|
|
1504
1552
|
listForms2 as listForms,
|
|
@@ -1509,11 +1557,13 @@ export {
|
|
|
1509
1557
|
listPages,
|
|
1510
1558
|
listSubmissions,
|
|
1511
1559
|
listWorkspaces,
|
|
1560
|
+
plain,
|
|
1512
1561
|
publishPage,
|
|
1513
1562
|
regenerateApiKey,
|
|
1514
1563
|
removeMember,
|
|
1515
1564
|
resolveSeo,
|
|
1516
1565
|
revokeApiKey,
|
|
1566
|
+
rich,
|
|
1517
1567
|
search,
|
|
1518
1568
|
setPageContent,
|
|
1519
1569
|
shouldShowField,
|