@bettercms-ai/sdk 1.12.0 → 1.13.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 +10 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +36 -5
- package/dist/index.d.ts +36 -5
- package/dist/index.js +10 -2
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.d.cts
CHANGED
|
@@ -476,6 +476,20 @@ interface DeliveryFormField {
|
|
|
476
476
|
field: string;
|
|
477
477
|
equals: string;
|
|
478
478
|
};
|
|
479
|
+
/**
|
|
480
|
+
* Per-field rules the API enforces on submit. Renderers should mirror them onto the
|
|
481
|
+
* native control (`min`/`max`/`pattern`) so the browser reports them before the round
|
|
482
|
+
* trip — the server check is the one that counts.
|
|
483
|
+
*/
|
|
484
|
+
validation?: DeliveryFormFieldValidation;
|
|
485
|
+
}
|
|
486
|
+
/** @see FormFieldValidation in @bettercms-ai/types — same shape, delivered to the site. */
|
|
487
|
+
interface DeliveryFormFieldValidation {
|
|
488
|
+
emailPolicy?: "any" | "business";
|
|
489
|
+
min?: number;
|
|
490
|
+
max?: number;
|
|
491
|
+
phoneFormat?: "any" | "e164";
|
|
492
|
+
pattern?: string;
|
|
479
493
|
}
|
|
480
494
|
/** The pick-many type, whose value is an array rather than a scalar. */
|
|
481
495
|
declare function isMultiValueField(type: DeliveryFormFieldType): boolean;
|
|
@@ -1081,7 +1095,11 @@ interface SeoInput {
|
|
|
1081
1095
|
interface ResolvedSeo {
|
|
1082
1096
|
title: string;
|
|
1083
1097
|
description: string;
|
|
1084
|
-
/**
|
|
1098
|
+
/**
|
|
1099
|
+
* Canonical URL — the page's own `canonical`, else `siteUrl` + `path` when both are given,
|
|
1100
|
+
* else "". Empty means the consumer must omit the tag: a RELATIVE canonical is worse than
|
|
1101
|
+
* none at all.
|
|
1102
|
+
*/
|
|
1085
1103
|
canonical: string;
|
|
1086
1104
|
og: {
|
|
1087
1105
|
title: string;
|
|
@@ -1100,11 +1118,24 @@ interface ResolvedSeo {
|
|
|
1100
1118
|
/** JSON-LD nodes (site schema first, then the page's), already flattened + de-empted. */
|
|
1101
1119
|
jsonLd: Array<Record<string, unknown>>;
|
|
1102
1120
|
}
|
|
1121
|
+
/** Where this page lives, so a canonical can be derived when the page sets none. */
|
|
1122
|
+
interface SeoLocation {
|
|
1123
|
+
/** Absolute site origin, e.g. `https://acme.com`. Trailing slash optional. */
|
|
1124
|
+
siteUrl?: string;
|
|
1125
|
+
/** This page's path, e.g. `/about` or `/`. */
|
|
1126
|
+
path?: string;
|
|
1127
|
+
}
|
|
1103
1128
|
/**
|
|
1104
|
-
* Merge a page's own SEO over the site defaults
|
|
1105
|
-
*
|
|
1129
|
+
* Merge a page's own SEO over the site defaults: page meta wins, then site defaults, then
|
|
1130
|
+
* sensible fallbacks.
|
|
1131
|
+
*
|
|
1132
|
+
* The CANONICAL is the one field that cannot be resolved from content alone, and getting this
|
|
1133
|
+
* wrong is silent. The hosted renderer (`mergeSeoMeta` in the backend) falls back to a canonical
|
|
1134
|
+
* it derives from the request's own origin and path — headless consumers have no request, so
|
|
1135
|
+
* they must pass `location`. Without it this returns "" and the caller ships no
|
|
1136
|
+
* `<link rel="canonical">` and no `og:url`, exactly as it did before `location` existed.
|
|
1106
1137
|
*/
|
|
1107
|
-
declare function resolveSeo(page: SeoInput, defaults?: SiteSeoDefaults): ResolvedSeo;
|
|
1138
|
+
declare function resolveSeo(page: SeoInput, defaults?: SiteSeoDefaults, location?: SeoLocation): ResolvedSeo;
|
|
1108
1139
|
|
|
1109
1140
|
/**
|
|
1110
1141
|
* Public site search — the headless surface for the visitor-facing search box.
|
|
@@ -1326,4 +1357,4 @@ declare function inviteMember(client: BetterCMSAdminClient, workspaceId: string,
|
|
|
1326
1357
|
declare function updateMemberRole(client: BetterCMSAdminClient, workspaceId: string, memberId: string, role: MemberRole): Promise<Member>;
|
|
1327
1358
|
declare function removeMember(client: BetterCMSAdminClient, workspaceId: string, memberId: string): Promise<void>;
|
|
1328
1359
|
|
|
1329
|
-
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 CommandManagedLayoutInput, type CreateApiKeyInput, type CreateClientOptions, type CreateEntryInput, type CreateFormInput, type CreateManagedPageInput, type CreateModelInput, type CreatePageInput, type CreateWorkspaceInput, type DeliveryForm, type DeliveryFormField, type DeliveryFormFieldType, ErrorCodes, type ExtractionCandidate, type FormFieldInput, type FormListOptions, type FormSubmitError, type FormValue, type FormValues, type GetEntryOptions, type GetManagedLayoutOptions, type ListContentAllOptions, type ListContentOptions, type ListEntriesFilter, type ListEntriesOptions, type ListPagesOptions, type ManagedComponent, type ManagedComponentInput, type ManagedContentEntry, type ManagedContentModel, type ManagedForm, type ManagedFormInput, type ManagedLayoutClient, type ManagedLayoutDocument, 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, asStringArray, commandManagedLayout, createApiKey, createClient, createEntry, createForm, createManagedPage, createModel, createPage, createWorkspace, decodeStega, deleteForm, deleteMedia, deletePage, deleteSubmission, deleteWorkspace, encodeStega, formInitialValues, getApiKeyUsage, getEntry, getForm, getManagedLayout, getManagedPage, getMedia, getMember, getModel, getPage, getSubmission, getWorkspace, inviteMember, isMultiValueField, 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, toggleOption, updateApiKey, updateEntry, updateForm, updateMemberRole, updateModel, updatePage, updateWorkspace, uploadMedia };
|
|
1360
|
+
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 CommandManagedLayoutInput, type CreateApiKeyInput, type CreateClientOptions, type CreateEntryInput, type CreateFormInput, type CreateManagedPageInput, type CreateModelInput, type CreatePageInput, type CreateWorkspaceInput, type DeliveryForm, type DeliveryFormField, type DeliveryFormFieldType, ErrorCodes, type ExtractionCandidate, type FormFieldInput, type FormListOptions, type FormSubmitError, type FormValue, type FormValues, type GetEntryOptions, type GetManagedLayoutOptions, type ListContentAllOptions, type ListContentOptions, type ListEntriesFilter, type ListEntriesOptions, type ListPagesOptions, type ManagedComponent, type ManagedComponentInput, type ManagedContentEntry, type ManagedContentModel, type ManagedForm, type ManagedFormInput, type ManagedLayoutClient, type ManagedLayoutDocument, 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 SeoLocation, 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, asStringArray, commandManagedLayout, createApiKey, createClient, createEntry, createForm, createManagedPage, createModel, createPage, createWorkspace, decodeStega, deleteForm, deleteMedia, deletePage, deleteSubmission, deleteWorkspace, encodeStega, formInitialValues, getApiKeyUsage, getEntry, getForm, getManagedLayout, getManagedPage, getMedia, getMember, getModel, getPage, getSubmission, getWorkspace, inviteMember, isMultiValueField, 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, toggleOption, updateApiKey, updateEntry, updateForm, updateMemberRole, updateModel, updatePage, updateWorkspace, uploadMedia };
|
package/dist/index.d.ts
CHANGED
|
@@ -476,6 +476,20 @@ interface DeliveryFormField {
|
|
|
476
476
|
field: string;
|
|
477
477
|
equals: string;
|
|
478
478
|
};
|
|
479
|
+
/**
|
|
480
|
+
* Per-field rules the API enforces on submit. Renderers should mirror them onto the
|
|
481
|
+
* native control (`min`/`max`/`pattern`) so the browser reports them before the round
|
|
482
|
+
* trip — the server check is the one that counts.
|
|
483
|
+
*/
|
|
484
|
+
validation?: DeliveryFormFieldValidation;
|
|
485
|
+
}
|
|
486
|
+
/** @see FormFieldValidation in @bettercms-ai/types — same shape, delivered to the site. */
|
|
487
|
+
interface DeliveryFormFieldValidation {
|
|
488
|
+
emailPolicy?: "any" | "business";
|
|
489
|
+
min?: number;
|
|
490
|
+
max?: number;
|
|
491
|
+
phoneFormat?: "any" | "e164";
|
|
492
|
+
pattern?: string;
|
|
479
493
|
}
|
|
480
494
|
/** The pick-many type, whose value is an array rather than a scalar. */
|
|
481
495
|
declare function isMultiValueField(type: DeliveryFormFieldType): boolean;
|
|
@@ -1081,7 +1095,11 @@ interface SeoInput {
|
|
|
1081
1095
|
interface ResolvedSeo {
|
|
1082
1096
|
title: string;
|
|
1083
1097
|
description: string;
|
|
1084
|
-
/**
|
|
1098
|
+
/**
|
|
1099
|
+
* Canonical URL — the page's own `canonical`, else `siteUrl` + `path` when both are given,
|
|
1100
|
+
* else "". Empty means the consumer must omit the tag: a RELATIVE canonical is worse than
|
|
1101
|
+
* none at all.
|
|
1102
|
+
*/
|
|
1085
1103
|
canonical: string;
|
|
1086
1104
|
og: {
|
|
1087
1105
|
title: string;
|
|
@@ -1100,11 +1118,24 @@ interface ResolvedSeo {
|
|
|
1100
1118
|
/** JSON-LD nodes (site schema first, then the page's), already flattened + de-empted. */
|
|
1101
1119
|
jsonLd: Array<Record<string, unknown>>;
|
|
1102
1120
|
}
|
|
1121
|
+
/** Where this page lives, so a canonical can be derived when the page sets none. */
|
|
1122
|
+
interface SeoLocation {
|
|
1123
|
+
/** Absolute site origin, e.g. `https://acme.com`. Trailing slash optional. */
|
|
1124
|
+
siteUrl?: string;
|
|
1125
|
+
/** This page's path, e.g. `/about` or `/`. */
|
|
1126
|
+
path?: string;
|
|
1127
|
+
}
|
|
1103
1128
|
/**
|
|
1104
|
-
* Merge a page's own SEO over the site defaults
|
|
1105
|
-
*
|
|
1129
|
+
* Merge a page's own SEO over the site defaults: page meta wins, then site defaults, then
|
|
1130
|
+
* sensible fallbacks.
|
|
1131
|
+
*
|
|
1132
|
+
* The CANONICAL is the one field that cannot be resolved from content alone, and getting this
|
|
1133
|
+
* wrong is silent. The hosted renderer (`mergeSeoMeta` in the backend) falls back to a canonical
|
|
1134
|
+
* it derives from the request's own origin and path — headless consumers have no request, so
|
|
1135
|
+
* they must pass `location`. Without it this returns "" and the caller ships no
|
|
1136
|
+
* `<link rel="canonical">` and no `og:url`, exactly as it did before `location` existed.
|
|
1106
1137
|
*/
|
|
1107
|
-
declare function resolveSeo(page: SeoInput, defaults?: SiteSeoDefaults): ResolvedSeo;
|
|
1138
|
+
declare function resolveSeo(page: SeoInput, defaults?: SiteSeoDefaults, location?: SeoLocation): ResolvedSeo;
|
|
1108
1139
|
|
|
1109
1140
|
/**
|
|
1110
1141
|
* Public site search — the headless surface for the visitor-facing search box.
|
|
@@ -1326,4 +1357,4 @@ declare function inviteMember(client: BetterCMSAdminClient, workspaceId: string,
|
|
|
1326
1357
|
declare function updateMemberRole(client: BetterCMSAdminClient, workspaceId: string, memberId: string, role: MemberRole): Promise<Member>;
|
|
1327
1358
|
declare function removeMember(client: BetterCMSAdminClient, workspaceId: string, memberId: string): Promise<void>;
|
|
1328
1359
|
|
|
1329
|
-
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 CommandManagedLayoutInput, type CreateApiKeyInput, type CreateClientOptions, type CreateEntryInput, type CreateFormInput, type CreateManagedPageInput, type CreateModelInput, type CreatePageInput, type CreateWorkspaceInput, type DeliveryForm, type DeliveryFormField, type DeliveryFormFieldType, ErrorCodes, type ExtractionCandidate, type FormFieldInput, type FormListOptions, type FormSubmitError, type FormValue, type FormValues, type GetEntryOptions, type GetManagedLayoutOptions, type ListContentAllOptions, type ListContentOptions, type ListEntriesFilter, type ListEntriesOptions, type ListPagesOptions, type ManagedComponent, type ManagedComponentInput, type ManagedContentEntry, type ManagedContentModel, type ManagedForm, type ManagedFormInput, type ManagedLayoutClient, type ManagedLayoutDocument, 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, asStringArray, commandManagedLayout, createApiKey, createClient, createEntry, createForm, createManagedPage, createModel, createPage, createWorkspace, decodeStega, deleteForm, deleteMedia, deletePage, deleteSubmission, deleteWorkspace, encodeStega, formInitialValues, getApiKeyUsage, getEntry, getForm, getManagedLayout, getManagedPage, getMedia, getMember, getModel, getPage, getSubmission, getWorkspace, inviteMember, isMultiValueField, 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, toggleOption, updateApiKey, updateEntry, updateForm, updateMemberRole, updateModel, updatePage, updateWorkspace, uploadMedia };
|
|
1360
|
+
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 CommandManagedLayoutInput, type CreateApiKeyInput, type CreateClientOptions, type CreateEntryInput, type CreateFormInput, type CreateManagedPageInput, type CreateModelInput, type CreatePageInput, type CreateWorkspaceInput, type DeliveryForm, type DeliveryFormField, type DeliveryFormFieldType, ErrorCodes, type ExtractionCandidate, type FormFieldInput, type FormListOptions, type FormSubmitError, type FormValue, type FormValues, type GetEntryOptions, type GetManagedLayoutOptions, type ListContentAllOptions, type ListContentOptions, type ListEntriesFilter, type ListEntriesOptions, type ListPagesOptions, type ManagedComponent, type ManagedComponentInput, type ManagedContentEntry, type ManagedContentModel, type ManagedForm, type ManagedFormInput, type ManagedLayoutClient, type ManagedLayoutDocument, 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 SeoLocation, 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, asStringArray, commandManagedLayout, createApiKey, createClient, createEntry, createForm, createManagedPage, createModel, createPage, createWorkspace, decodeStega, deleteForm, deleteMedia, deletePage, deleteSubmission, deleteWorkspace, encodeStega, formInitialValues, getApiKeyUsage, getEntry, getForm, getManagedLayout, getManagedPage, getMedia, getMember, getModel, getPage, getSubmission, getWorkspace, inviteMember, isMultiValueField, 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, toggleOption, updateApiKey, updateEntry, updateForm, updateMemberRole, updateModel, updatePage, updateWorkspace, uploadMedia };
|
package/dist/index.js
CHANGED
|
@@ -1247,12 +1247,20 @@ function decodeEntities(s) {
|
|
|
1247
1247
|
}
|
|
1248
1248
|
|
|
1249
1249
|
// src/seo.ts
|
|
1250
|
+
function derivedCanonical({ siteUrl, path }) {
|
|
1251
|
+
if (!siteUrl || !path) return "";
|
|
1252
|
+
try {
|
|
1253
|
+
return new URL(path, siteUrl.endsWith("/") ? siteUrl : `${siteUrl}/`).toString();
|
|
1254
|
+
} catch {
|
|
1255
|
+
return "";
|
|
1256
|
+
}
|
|
1257
|
+
}
|
|
1250
1258
|
function jsonLdNodes(schema) {
|
|
1251
1259
|
if (!schema) return [];
|
|
1252
1260
|
const arr = Array.isArray(schema) ? schema : [schema];
|
|
1253
1261
|
return arr.filter((node) => node && Object.keys(node).length > 0);
|
|
1254
1262
|
}
|
|
1255
|
-
function resolveSeo(page, defaults = {}) {
|
|
1263
|
+
function resolveSeo(page, defaults = {}, location = {}) {
|
|
1256
1264
|
const meta = page.metaJson ?? {};
|
|
1257
1265
|
const title = page.metaTitle || page.title || "";
|
|
1258
1266
|
const description = page.metaDescription || defaults.metaDescription || "";
|
|
@@ -1260,7 +1268,7 @@ function resolveSeo(page, defaults = {}) {
|
|
|
1260
1268
|
const ogTitle = meta.og?.title || title;
|
|
1261
1269
|
const ogDescription = meta.og?.description || description;
|
|
1262
1270
|
const twImage = meta.twitter?.image || ogImage;
|
|
1263
|
-
const canonical = meta.canonical ||
|
|
1271
|
+
const canonical = meta.canonical || derivedCanonical(location);
|
|
1264
1272
|
return {
|
|
1265
1273
|
title,
|
|
1266
1274
|
description,
|