busabase-cms-sdk 0.1.3 → 0.1.5
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.
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
//#region src/fallback.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* The "read from Busabase, fall back to bundled content on any failure" wrapper — every app
|
|
4
|
+
* consuming busabase-cms re-implemented this same try/catch/console.warn a couple of times
|
|
5
|
+
* (once for list-shaped reads, once for single-record reads). One generic version, one place
|
|
6
|
+
* to change the log format.
|
|
7
|
+
*/
|
|
8
|
+
declare const readCmsOrFallback: <T>(operation: (() => Promise<T>) | null | undefined, fallback: T, label: string) => Promise<T>;
|
|
9
|
+
/**
|
|
10
|
+
* The answer a read got, when the caller needs to act on it.
|
|
11
|
+
*
|
|
12
|
+
* `readCmsOrFallback` deliberately folds "unreachable" into "empty", which is the
|
|
13
|
+
* right default for rendering — a marketing page should not 500 because the
|
|
14
|
+
* workspace behind it blinked. It is the wrong answer the moment a page turns it
|
|
15
|
+
* into a claim: an unreachable CMS then renders as a 404, and whatever caching
|
|
16
|
+
* sits in front of it persists that as "this content was deleted".
|
|
17
|
+
*
|
|
18
|
+
* Reads whose result decides a `notFound()` should go through `readCmsStatus`
|
|
19
|
+
* instead and be told which answer they actually received.
|
|
20
|
+
*/
|
|
21
|
+
type CmsRead<T> = {
|
|
22
|
+
status: "ok";
|
|
23
|
+
data: T;
|
|
24
|
+
} | {
|
|
25
|
+
status: "unavailable";
|
|
26
|
+
};
|
|
27
|
+
declare const readCmsStatus: <T>(operation: (() => Promise<T>) | null | undefined,
|
|
28
|
+
/**
|
|
29
|
+
* What "nothing here" looks like for this read.
|
|
30
|
+
*
|
|
31
|
+
* Returned as a SUCCESSFUL read when the integration is simply not configured:
|
|
32
|
+
* an app with no CMS wired up is not broken, it just has no CMS content, and
|
|
33
|
+
* turning that into an error breaks first-run and CMS-off deployments.
|
|
34
|
+
*/
|
|
35
|
+
whenUnconfigured: T, label: string) => Promise<CmsRead<T>>;
|
|
36
|
+
/**
|
|
37
|
+
* Unwrap a read, or fail loudly.
|
|
38
|
+
*
|
|
39
|
+
* Throwing beats rendering a 404: an error response is not cached, so the page
|
|
40
|
+
* recovers on the next request, whereas a cached 404 tells crawlers the content
|
|
41
|
+
* is gone.
|
|
42
|
+
*/
|
|
43
|
+
declare const requireCmsRead: <T>(read: CmsRead<T>, what: string) => T;
|
|
44
|
+
//#endregion
|
|
45
|
+
export { requireCmsRead as i, readCmsOrFallback as n, readCmsStatus as r, CmsRead as t };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,14 +1,6 @@
|
|
|
1
1
|
import { C as taxonomyFieldsDTOSchema, S as tagVOSchema, _ as pageVOSchema, a as PageFieldsDTO, b as relationFieldsDTOSchema, c as PostVO, d as TagVO, f as attachmentFieldsDTOSchema, g as pageFieldsDTOSchema, h as categoryVOSchema, i as CategoryVO, l as RelationFieldsDTO, m as categoryFieldsDTOSchema, n as AttachmentVO, o as PageVO, p as attachmentVOSchema, r as CategoryFieldsDTO, s as PostFieldsDTO, t as AttachmentFieldsDTO, u as TagFieldsDTO, v as postFieldsDTOSchema, x as tagFieldsDTOSchema, y as postVOSchema } from "./types-QKFW2jvT.js";
|
|
2
2
|
import { $ as BusabaseCmsSetupError, A as BUSABASE_CMS_SCHEMA_PROFILES, B as i18nName, C as createBusabaseCms, D as mapPublishedPostRecord, E as mapPublishedPageRecord, F as BusabaseCmsFieldDefinition, G as BusabaseCmsFieldOptions, H as BusabaseCmsBase, I as BusabaseCmsFieldsOverride, J as BusabaseCmsSource, K as BusabaseCmsNode, L as BusabaseCmsFolderMetadata, M as BusabaseCmsBaseDefinition, N as BusabaseCmsBaseIds, O as BUSABASE_CMS_METADATA_KEY, P as BusabaseCmsBaseRole, Q as BusabaseCmsSchemaDriftError, R as BusabaseCmsSchemaProfile, S as InvalidCmsRecordIssue, T as mapActiveTagRecord, U as BusabaseCmsClient, V as replaceField, W as BusabaseCmsField, X as createBusabaseCmsSourceFromConfig, Y as createBusabaseCmsSource, Z as BusabaseCmsError, _ as CmsRecordKind, a as buildCmsCanonicalPath, b as DEFAULT_POSTS_BASE_SLUG, c as filterCmsPostsByTaxonomy, d as normalizeCmsPath, f as parseCmsCanonicalPath, g as BusabaseCmsTaxonomyCollection, h as BusabaseCmsPathCollection, i as CmsTaxonomyKind, j as BUSABASE_CMS_SCHEMA_VERSION, k as BUSABASE_CMS_ROLES, l as isCmsBlogPostPath, m as BusabaseCmsOptions, n as CmsCanonicalPathOptions, o as buildCmsTaxonomyArchivePath, p as BusabaseCms, q as BusabaseCmsRecord, r as CmsPathHelpers, s as createCmsPathHelpers, t as CmsCanonicalPath, u as isCmsContentForLocale, v as DEFAULT_CATEGORIES_BASE_SLUG, w as mapActiveCategoryRecord, x as DEFAULT_TAGS_BASE_SLUG, y as DEFAULT_PAGES_BASE_SLUG, z as getBusabaseCmsBaseDefinition } from "./routing-VU56uuJ0.js";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* The "read from Busabase, fall back to bundled content on any failure" wrapper — every app
|
|
6
|
-
* consuming busabase-cms re-implemented this same try/catch/console.warn a couple of times
|
|
7
|
-
* (once for list-shaped reads, once for single-record reads). One generic version, one place
|
|
8
|
-
* to change the log format.
|
|
9
|
-
*/
|
|
10
|
-
declare const readCmsOrFallback: <T>(operation: (() => Promise<T>) | null | undefined, fallback: T, label: string) => Promise<T>;
|
|
11
|
-
//#endregion
|
|
3
|
+
import { i as requireCmsRead, n as readCmsOrFallback, r as readCmsStatus, t as CmsRead } from "./fallback-5I_dTsOb.js";
|
|
12
4
|
//#region src/links.d.ts
|
|
13
5
|
/** Keep rendered CMS attachments on protocols browsers can navigate safely. */
|
|
14
6
|
declare const getSafeCmsExternalUrl: (value: string) => string | null;
|
|
@@ -30,4 +22,4 @@ interface BusabaseCmsSchemaConfig {
|
|
|
30
22
|
}>;
|
|
31
23
|
}
|
|
32
24
|
//#endregion
|
|
33
|
-
export { AttachmentFieldsDTO, AttachmentVO, BUSABASE_CMS_METADATA_KEY, BUSABASE_CMS_ROLES, BUSABASE_CMS_SCHEMA_PROFILES, BUSABASE_CMS_SCHEMA_VERSION, type BusabaseCms, type BusabaseCmsBase, type BusabaseCmsBaseDefinition, type BusabaseCmsBaseIds, type BusabaseCmsBaseRole, type BusabaseCmsClient, BusabaseCmsError, type BusabaseCmsField, type BusabaseCmsFieldDefinition, type BusabaseCmsFieldOptions, type BusabaseCmsFieldsOverride, type BusabaseCmsFolderMetadata, type BusabaseCmsNode, type BusabaseCmsOptions, type BusabaseCmsPathCollection, type BusabaseCmsRecord, type BusabaseCmsSchemaConfig, BusabaseCmsSchemaDriftError, type BusabaseCmsSchemaProfile, BusabaseCmsSetupError, type BusabaseCmsSource, type BusabaseCmsTaxonomyCollection, CategoryFieldsDTO, CategoryVO, CmsCanonicalPath, CmsCanonicalPathOptions, CmsPathHelpers, type CmsRecordKind, CmsTaxonomyKind, DEFAULT_CATEGORIES_BASE_SLUG, DEFAULT_PAGES_BASE_SLUG, DEFAULT_POSTS_BASE_SLUG, DEFAULT_TAGS_BASE_SLUG, type InvalidCmsRecordIssue, PageFieldsDTO, PageVO, PostFieldsDTO, PostVO, RelationFieldsDTO, TagFieldsDTO, TagVO, attachmentFieldsDTOSchema, attachmentVOSchema, buildCmsCanonicalPath, buildCmsTaxonomyArchivePath, i18nName as busabaseCmsFieldI18nName, categoryFieldsDTOSchema, categoryVOSchema, createBusabaseCms, createBusabaseCmsSource, createBusabaseCmsSourceFromConfig, createCmsPathHelpers, filterCmsPostsByTaxonomy, getBusabaseCmsBaseDefinition, getSafeCmsExternalUrl, isCmsBlogPostPath, isCmsContentForLocale, mapActiveCategoryRecord, mapActiveTagRecord, mapPublishedPageRecord, mapPublishedPostRecord, normalizeCmsPath, pageFieldsDTOSchema, pageVOSchema, parseCmsCanonicalPath, postFieldsDTOSchema, postVOSchema, readCmsOrFallback, relationFieldsDTOSchema, replaceField, tagFieldsDTOSchema, tagVOSchema, taxonomyFieldsDTOSchema };
|
|
25
|
+
export { AttachmentFieldsDTO, AttachmentVO, BUSABASE_CMS_METADATA_KEY, BUSABASE_CMS_ROLES, BUSABASE_CMS_SCHEMA_PROFILES, BUSABASE_CMS_SCHEMA_VERSION, type BusabaseCms, type BusabaseCmsBase, type BusabaseCmsBaseDefinition, type BusabaseCmsBaseIds, type BusabaseCmsBaseRole, type BusabaseCmsClient, BusabaseCmsError, type BusabaseCmsField, type BusabaseCmsFieldDefinition, type BusabaseCmsFieldOptions, type BusabaseCmsFieldsOverride, type BusabaseCmsFolderMetadata, type BusabaseCmsNode, type BusabaseCmsOptions, type BusabaseCmsPathCollection, type BusabaseCmsRecord, type BusabaseCmsSchemaConfig, BusabaseCmsSchemaDriftError, type BusabaseCmsSchemaProfile, BusabaseCmsSetupError, type BusabaseCmsSource, type BusabaseCmsTaxonomyCollection, CategoryFieldsDTO, CategoryVO, CmsCanonicalPath, CmsCanonicalPathOptions, CmsPathHelpers, CmsRead, type CmsRecordKind, CmsTaxonomyKind, DEFAULT_CATEGORIES_BASE_SLUG, DEFAULT_PAGES_BASE_SLUG, DEFAULT_POSTS_BASE_SLUG, DEFAULT_TAGS_BASE_SLUG, type InvalidCmsRecordIssue, PageFieldsDTO, PageVO, PostFieldsDTO, PostVO, RelationFieldsDTO, TagFieldsDTO, TagVO, attachmentFieldsDTOSchema, attachmentVOSchema, buildCmsCanonicalPath, buildCmsTaxonomyArchivePath, i18nName as busabaseCmsFieldI18nName, categoryFieldsDTOSchema, categoryVOSchema, createBusabaseCms, createBusabaseCmsSource, createBusabaseCmsSourceFromConfig, createCmsPathHelpers, filterCmsPostsByTaxonomy, getBusabaseCmsBaseDefinition, getSafeCmsExternalUrl, isCmsBlogPostPath, isCmsContentForLocale, mapActiveCategoryRecord, mapActiveTagRecord, mapPublishedPageRecord, mapPublishedPostRecord, normalizeCmsPath, pageFieldsDTOSchema, pageVOSchema, parseCmsCanonicalPath, postFieldsDTOSchema, postVOSchema, readCmsOrFallback, readCmsStatus, relationFieldsDTOSchema, replaceField, requireCmsRead, tagFieldsDTOSchema, tagVOSchema, taxonomyFieldsDTOSchema };
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { A as replaceField, C as createBusabaseCmsSourceFromConfig, D as BUSABASE_CMS_SCHEMA_VERSION, E as BUSABASE_CMS_SCHEMA_PROFILES, M as BusabaseCmsSchemaDriftError, N as BusabaseCmsSetupError, O as getBusabaseCmsBaseDefinition, S as createBusabaseCmsSource, T as BUSABASE_CMS_ROLES, _ as postVOSchema, a as createBusabaseCms, b as tagVOSchema, c as mapPublishedPageRecord, d as attachmentVOSchema, f as categoryFieldsDTOSchema, g as postFieldsDTOSchema, h as pageVOSchema, i as DEFAULT_TAGS_BASE_SLUG, j as BusabaseCmsError, k as i18nName, l as mapPublishedPostRecord, m as pageFieldsDTOSchema, n as DEFAULT_PAGES_BASE_SLUG, o as mapActiveCategoryRecord, p as categoryVOSchema, r as DEFAULT_POSTS_BASE_SLUG, s as mapActiveTagRecord, t as DEFAULT_CATEGORIES_BASE_SLUG, u as attachmentFieldsDTOSchema, v as relationFieldsDTOSchema, w as BUSABASE_CMS_METADATA_KEY, x as taxonomyFieldsDTOSchema, y as tagFieldsDTOSchema } from "./content-BXgsWQjQ.js";
|
|
2
|
-
import { a as isCmsBlogPostPath, c as parseCmsCanonicalPath, i as filterCmsPostsByTaxonomy, l as readCmsOrFallback, n as buildCmsTaxonomyArchivePath, o as isCmsContentForLocale, r as createCmsPathHelpers, s as normalizeCmsPath, t as buildCmsCanonicalPath } from "./routing-
|
|
2
|
+
import { a as isCmsBlogPostPath, c as parseCmsCanonicalPath, d as requireCmsRead, i as filterCmsPostsByTaxonomy, l as readCmsOrFallback, n as buildCmsTaxonomyArchivePath, o as isCmsContentForLocale, r as createCmsPathHelpers, s as normalizeCmsPath, t as buildCmsCanonicalPath, u as readCmsStatus } from "./routing-Cf35nomf.js";
|
|
3
3
|
//#region src/links.ts
|
|
4
4
|
/** Keep rendered CMS attachments on protocols browsers can navigate safely. */
|
|
5
5
|
const getSafeCmsExternalUrl = (value) => {
|
|
@@ -11,4 +11,4 @@ const getSafeCmsExternalUrl = (value) => {
|
|
|
11
11
|
}
|
|
12
12
|
};
|
|
13
13
|
//#endregion
|
|
14
|
-
export { BUSABASE_CMS_METADATA_KEY, BUSABASE_CMS_ROLES, BUSABASE_CMS_SCHEMA_PROFILES, BUSABASE_CMS_SCHEMA_VERSION, BusabaseCmsError, BusabaseCmsSchemaDriftError, BusabaseCmsSetupError, DEFAULT_CATEGORIES_BASE_SLUG, DEFAULT_PAGES_BASE_SLUG, DEFAULT_POSTS_BASE_SLUG, DEFAULT_TAGS_BASE_SLUG, attachmentFieldsDTOSchema, attachmentVOSchema, buildCmsCanonicalPath, buildCmsTaxonomyArchivePath, i18nName as busabaseCmsFieldI18nName, categoryFieldsDTOSchema, categoryVOSchema, createBusabaseCms, createBusabaseCmsSource, createBusabaseCmsSourceFromConfig, createCmsPathHelpers, filterCmsPostsByTaxonomy, getBusabaseCmsBaseDefinition, getSafeCmsExternalUrl, isCmsBlogPostPath, isCmsContentForLocale, mapActiveCategoryRecord, mapActiveTagRecord, mapPublishedPageRecord, mapPublishedPostRecord, normalizeCmsPath, pageFieldsDTOSchema, pageVOSchema, parseCmsCanonicalPath, postFieldsDTOSchema, postVOSchema, readCmsOrFallback, relationFieldsDTOSchema, replaceField, tagFieldsDTOSchema, tagVOSchema, taxonomyFieldsDTOSchema };
|
|
14
|
+
export { BUSABASE_CMS_METADATA_KEY, BUSABASE_CMS_ROLES, BUSABASE_CMS_SCHEMA_PROFILES, BUSABASE_CMS_SCHEMA_VERSION, BusabaseCmsError, BusabaseCmsSchemaDriftError, BusabaseCmsSetupError, DEFAULT_CATEGORIES_BASE_SLUG, DEFAULT_PAGES_BASE_SLUG, DEFAULT_POSTS_BASE_SLUG, DEFAULT_TAGS_BASE_SLUG, attachmentFieldsDTOSchema, attachmentVOSchema, buildCmsCanonicalPath, buildCmsTaxonomyArchivePath, i18nName as busabaseCmsFieldI18nName, categoryFieldsDTOSchema, categoryVOSchema, createBusabaseCms, createBusabaseCmsSource, createBusabaseCmsSourceFromConfig, createCmsPathHelpers, filterCmsPostsByTaxonomy, getBusabaseCmsBaseDefinition, getSafeCmsExternalUrl, isCmsBlogPostPath, isCmsContentForLocale, mapActiveCategoryRecord, mapActiveTagRecord, mapPublishedPageRecord, mapPublishedPostRecord, normalizeCmsPath, pageFieldsDTOSchema, pageVOSchema, parseCmsCanonicalPath, postFieldsDTOSchema, postVOSchema, readCmsOrFallback, readCmsStatus, relationFieldsDTOSchema, replaceField, requireCmsRead, tagFieldsDTOSchema, tagVOSchema, taxonomyFieldsDTOSchema };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { c as PostVO, d as TagVO, i as CategoryVO, o as PageVO } from "../types-QKFW2jvT.js";
|
|
2
2
|
import { S as InvalidCmsRecordIssue, i as CmsTaxonomyKind, p as BusabaseCms, r as CmsPathHelpers, t as CmsCanonicalPath } from "../routing-VU56uuJ0.js";
|
|
3
|
+
import { t as CmsRead } from "../fallback-5I_dTsOb.js";
|
|
3
4
|
import "server-only";
|
|
4
5
|
//#region src/integration/config.d.ts
|
|
5
6
|
/** Next data-cache `revalidate` used when an app does not override it. */
|
|
@@ -113,6 +114,8 @@ interface CmsPageReads {
|
|
|
113
114
|
getBusabaseLandingPageByPath: (path: string) => Promise<PageVO | null>;
|
|
114
115
|
listBusabaseLandingPagesOrFallback: () => Promise<PageVO[]>;
|
|
115
116
|
getBusabaseLandingPageByPathOrFallback: (path: string) => Promise<PageVO | null>;
|
|
117
|
+
/** Status-aware variant, for callers that turn a missing page into a 404. */
|
|
118
|
+
readBusabaseLandingPageByPath: (path: string) => Promise<CmsRead<PageVO | null>>;
|
|
116
119
|
}
|
|
117
120
|
declare const createCmsPageReads: ({ getCms, requireCms }: CmsClientProvider, appLabel: string) => CmsPageReads;
|
|
118
121
|
/** The argument object an app's own `generatePageMetadata` helper accepts. */
|
|
@@ -123,29 +126,73 @@ interface CmsPageMetadataOptions {
|
|
|
123
126
|
lang: string;
|
|
124
127
|
type: "website" | "article";
|
|
125
128
|
}
|
|
129
|
+
/**
|
|
130
|
+
* All the locale resolver actually reads off a Page: its canonical path and its locale. Kept
|
|
131
|
+
* deliberately narrower than `PageVO` so an app whose own Page VO omits SDK fields it does not
|
|
132
|
+
* store (Buda drops `hero`/`features`/`faqs`) still flows through these helpers with its own
|
|
133
|
+
* type intact, instead of being silently widened back to `PageVO`.
|
|
134
|
+
*/
|
|
135
|
+
type CmsPageIdentity = Pick<PageVO, "path" | "locale">;
|
|
136
|
+
/**
|
|
137
|
+
* A Page resolved for one request, carrying the locale that actually supplied the content.
|
|
138
|
+
* `isLocaleFallback` is what a route reads to decide whether to render a "not translated yet,
|
|
139
|
+
* showing English" notice. Structurally mirrors `ResolvedCmsPostPage` on the Post side.
|
|
140
|
+
*/
|
|
141
|
+
interface ResolvedCmsPage<TPage extends CmsPageIdentity = PageVO> {
|
|
142
|
+
page: TPage;
|
|
143
|
+
requestedLocale: string;
|
|
144
|
+
contentLocale: string;
|
|
145
|
+
isLocaleFallback: boolean;
|
|
146
|
+
}
|
|
126
147
|
/** The slice of a `CmsIntegration` the Page helpers depend on. */
|
|
127
|
-
interface CmsPageHelpersIntegration {
|
|
148
|
+
interface CmsPageHelpersIntegration<TPage extends CmsPageIdentity = PageVO> {
|
|
128
149
|
buildCmsPath: (locale: string, path: string | readonly string[]) => string | null;
|
|
129
150
|
parseCmsPath: (path: string) => CmsCanonicalPath | null;
|
|
130
151
|
isCmsContentForLocale: (item: {
|
|
131
152
|
locale: string;
|
|
132
153
|
path: string;
|
|
133
154
|
}, locale: string) => boolean;
|
|
134
|
-
getBusabaseLandingPageByPathOrFallback: (path: string) => Promise<
|
|
155
|
+
getBusabaseLandingPageByPathOrFallback: (path: string) => Promise<TPage | null>;
|
|
156
|
+
/** Status-aware variant, for callers that turn a missing page into a 404. */
|
|
157
|
+
readBusabaseLandingPageByPath: (path: string) => Promise<CmsRead<TPage | null>>;
|
|
135
158
|
}
|
|
136
|
-
interface CmsPageHelpersOptions<TMetadata> {
|
|
137
|
-
integration: CmsPageHelpersIntegration
|
|
159
|
+
interface CmsPageHelpersOptions<TMetadata, TPage extends CmsPageIdentity = PageVO> {
|
|
160
|
+
integration: CmsPageHelpersIntegration<TPage>;
|
|
138
161
|
/**
|
|
139
162
|
* The app's own metadata helper. Injected and typed structurally so the SDK does not depend
|
|
140
163
|
* on any app's site config.
|
|
141
164
|
*/
|
|
142
165
|
generatePageMetadata: (options: CmsPageMetadataOptions) => TMetadata;
|
|
143
166
|
}
|
|
144
|
-
interface CmsPageHelpers<TMetadata> {
|
|
145
|
-
|
|
167
|
+
interface CmsPageHelpers<TMetadata, TPage extends CmsPageIdentity = PageVO> {
|
|
168
|
+
/**
|
|
169
|
+
* STRICT per-locale lookup: no English fallback, `null` when this exact locale has no Page.
|
|
170
|
+
* Callers that run their own cross-locale cascade (Buda's use-case resolver cascades CMS →
|
|
171
|
+
* bundled ICP → editorial before falling back) must use this — handing them the fallback
|
|
172
|
+
* variant makes every locale look translated, which silently suppresses the "showing English"
|
|
173
|
+
* notice and mislabels the content locale.
|
|
174
|
+
*/
|
|
175
|
+
getCmsPageForLocale: (locale: string, path: string | readonly string[]) => Promise<TPage | null>;
|
|
176
|
+
/**
|
|
177
|
+
* The resolved Page only. Falls back to English when the requested locale has no translation,
|
|
178
|
+
* so an untranslated Page renders in English instead of 404ing — the same rule the Post
|
|
179
|
+
* resolver applies. Use `resolveCmsPageForRequest` when the route needs to know it fell back.
|
|
180
|
+
*/
|
|
181
|
+
getCmsPageForRequest: (lang: string, path: string | readonly string[]) => Promise<TPage | null>;
|
|
182
|
+
/** Same resolution as `getCmsPageForRequest`, plus which locale supplied the content. */
|
|
183
|
+
resolveCmsPageForRequest: (lang: string, path: string | readonly string[]) => Promise<ResolvedCmsPage<TPage> | null>;
|
|
184
|
+
/**
|
|
185
|
+
* Status-aware variant. A CMS Page has no local-MDX equivalent, so a catch-all
|
|
186
|
+
* route cannot otherwise tell "no page at this path" (a correct, cacheable
|
|
187
|
+
* 404) from "the CMS is unreachable" (a 404 that would be cached as though the
|
|
188
|
+
* page had been deleted).
|
|
189
|
+
*/
|
|
190
|
+
readCmsPageForRequest: (lang: string, path: string | readonly string[]) => Promise<CmsRead<TPage | null>>;
|
|
191
|
+
/** Status-aware variant of `resolveCmsPageForRequest`. */
|
|
192
|
+
readResolvedCmsPageForRequest: (lang: string, path: string | readonly string[]) => Promise<CmsRead<ResolvedCmsPage<TPage> | null>>;
|
|
146
193
|
generateCmsPageMetadata: (page: PageVO, lang: string) => TMetadata | Record<string, never>;
|
|
147
194
|
}
|
|
148
|
-
declare const createCmsPageHelpers: <TMetadata>({ integration, generatePageMetadata }: CmsPageHelpersOptions<TMetadata>) => CmsPageHelpers<TMetadata>;
|
|
195
|
+
declare const createCmsPageHelpers: <TMetadata, TPage extends CmsPageIdentity = PageVO>({ integration, generatePageMetadata }: CmsPageHelpersOptions<TMetadata, TPage>) => CmsPageHelpers<TMetadata, TPage>;
|
|
149
196
|
//#endregion
|
|
150
197
|
//#region src/integration/posts.d.ts
|
|
151
198
|
interface CmsPostReads {
|
|
@@ -222,6 +269,13 @@ interface CmsTaxonomyReads {
|
|
|
222
269
|
listBusabaseCategoriesOrFallback: () => Promise<CategoryVO[]>;
|
|
223
270
|
listBusabaseTags: () => Promise<TagVO[]>;
|
|
224
271
|
listBusabaseTagsOrFallback: () => Promise<TagVO[]>;
|
|
272
|
+
/**
|
|
273
|
+
* Status-aware variants, for callers that turn the result into a 404.
|
|
274
|
+
* A Category or Tag exists only in the CMS — there is no local fallback — so
|
|
275
|
+
* "the CMS is unreachable" and "no such taxonomy" are otherwise identical here.
|
|
276
|
+
*/
|
|
277
|
+
readBusabaseCategories: () => Promise<CmsRead<CategoryVO[]>>;
|
|
278
|
+
readBusabaseTags: () => Promise<CmsRead<TagVO[]>>;
|
|
225
279
|
}
|
|
226
280
|
declare const createCmsTaxonomyReads: ({ getCms, requireCms }: CmsClientProvider, appLabel: string) => CmsTaxonomyReads;
|
|
227
281
|
//#endregion
|
|
@@ -248,4 +302,4 @@ interface CmsIntegration extends CmsPostReads, CmsPageReads, CmsTaxonomyReads {
|
|
|
248
302
|
}
|
|
249
303
|
declare const createCmsIntegration: (config: CmsIntegrationConfig) => CmsIntegration;
|
|
250
304
|
//#endregion
|
|
251
|
-
export { type BlogCardContent, type CmsClientProvider, CmsIntegration, type CmsIntegrationBaseSlugs, type CmsIntegrationCacheConfig, type CmsIntegrationCacheTags, type CmsIntegrationConfig, type CmsPageHelpers, type CmsPageHelpersIntegration, type CmsPageHelpersOptions, type CmsPageMetadataOptions, type CmsPageReads, type CmsPostReads, type CmsPostResolver, type CmsPostResolverDependencies, type CmsPostResolverIntegration, type CmsPostResolverOptions, type CmsTaxonomyReads, DEFAULT_CMS_REVALIDATE_SECONDS, type LocalPostSourceLike, type ResolvedCmsConfig, type ResolvedCmsPostPage, buildCmsCacheKeyPrefix, createCmsClientProvider, createCmsIntegration, createCmsPageHelpers, createCmsPageReads, createCmsPostReads, createCmsPostResolver, createCmsTaxonomyReads, mergeBlogCardsByPath, readCmsEnvConfig, resolveCmsCacheTags };
|
|
305
|
+
export { type BlogCardContent, type CmsClientProvider, CmsIntegration, type CmsIntegrationBaseSlugs, type CmsIntegrationCacheConfig, type CmsIntegrationCacheTags, type CmsIntegrationConfig, type CmsPageHelpers, type CmsPageHelpersIntegration, type CmsPageHelpersOptions, type CmsPageIdentity, type CmsPageMetadataOptions, type CmsPageReads, type CmsPostReads, type CmsPostResolver, type CmsPostResolverDependencies, type CmsPostResolverIntegration, type CmsPostResolverOptions, type CmsTaxonomyReads, DEFAULT_CMS_REVALIDATE_SECONDS, type LocalPostSourceLike, type ResolvedCmsConfig, type ResolvedCmsPage, type ResolvedCmsPostPage, buildCmsCacheKeyPrefix, createCmsClientProvider, createCmsIntegration, createCmsPageHelpers, createCmsPageReads, createCmsPostReads, createCmsPostResolver, createCmsTaxonomyReads, mergeBlogCardsByPath, readCmsEnvConfig, resolveCmsCacheTags };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { l as readCmsOrFallback, r as createCmsPathHelpers, s as normalizeCmsPath } from "../routing-
|
|
1
|
+
import { l as readCmsOrFallback, r as createCmsPathHelpers, s as normalizeCmsPath, u as readCmsStatus } from "../routing-Cf35nomf.js";
|
|
2
2
|
import { createCachedBusabaseCms } from "../next.js";
|
|
3
3
|
import "server-only";
|
|
4
4
|
import { cache } from "react";
|
|
@@ -118,6 +118,10 @@ const createCmsClientProvider = (config) => {
|
|
|
118
118
|
const createCmsPageReads = ({ getCms, requireCms }, appLabel) => ({
|
|
119
119
|
listBusabaseLandingPages: async () => requireCms().pages.list(),
|
|
120
120
|
getBusabaseLandingPageByPath: async (path) => requireCms().pages.getByPath(path),
|
|
121
|
+
readBusabaseLandingPageByPath: async (path) => {
|
|
122
|
+
const cms = getCms();
|
|
123
|
+
return readCmsStatus(cms ? () => cms.pages.getByPath(path) : null, null, `get ${appLabel} page`);
|
|
124
|
+
},
|
|
121
125
|
listBusabaseLandingPagesOrFallback: async () => {
|
|
122
126
|
const cms = getCms();
|
|
123
127
|
return readCmsOrFallback(cms ? () => cms.pages.list() : null, [], `list ${appLabel} landing pages`);
|
|
@@ -127,27 +131,95 @@ const createCmsPageReads = ({ getCms, requireCms }, appLabel) => ({
|
|
|
127
131
|
return readCmsOrFallback(cms ? () => cms.pages.getByPath(path) : null, null, `get ${appLabel} landing page ${path}`);
|
|
128
132
|
}
|
|
129
133
|
});
|
|
134
|
+
/**
|
|
135
|
+
* The locale every other locale falls back to when it has no translation of a Page.
|
|
136
|
+
* Mirrors the Post resolver in ./posts.ts — see `resolvePostPageWithDependencies`.
|
|
137
|
+
*/
|
|
138
|
+
const FALLBACK_LOCALE = "en";
|
|
130
139
|
const createCmsPageHelpers = ({ integration, generatePageMetadata }) => {
|
|
131
|
-
const { buildCmsPath, getBusabaseLandingPageByPathOrFallback, isCmsContentForLocale, parseCmsPath } = integration;
|
|
132
|
-
const
|
|
133
|
-
const canonicalPath = buildCmsPath(
|
|
140
|
+
const { buildCmsPath, getBusabaseLandingPageByPathOrFallback, isCmsContentForLocale, parseCmsPath, readBusabaseLandingPageByPath } = integration;
|
|
141
|
+
const getForLocale = async (locale, path) => {
|
|
142
|
+
const canonicalPath = buildCmsPath(locale, path);
|
|
134
143
|
if (!canonicalPath) return null;
|
|
135
144
|
const page = await getBusabaseLandingPageByPathOrFallback(canonicalPath);
|
|
136
|
-
return page && isCmsContentForLocale(page,
|
|
145
|
+
return page && isCmsContentForLocale(page, locale) ? page : null;
|
|
146
|
+
};
|
|
147
|
+
const readForLocale = async (locale, path) => {
|
|
148
|
+
const canonicalPath = buildCmsPath(locale, path);
|
|
149
|
+
if (!canonicalPath) return {
|
|
150
|
+
status: "ok",
|
|
151
|
+
data: null
|
|
152
|
+
};
|
|
153
|
+
const read = await readBusabaseLandingPageByPath(canonicalPath);
|
|
154
|
+
if (read.status !== "ok") return read;
|
|
155
|
+
const page = read.data;
|
|
156
|
+
return {
|
|
157
|
+
status: "ok",
|
|
158
|
+
data: page && isCmsContentForLocale(page, locale) ? page : null
|
|
159
|
+
};
|
|
160
|
+
};
|
|
161
|
+
const resolved = (page, requestedLocale, contentLocale) => ({
|
|
162
|
+
page,
|
|
163
|
+
requestedLocale,
|
|
164
|
+
contentLocale,
|
|
165
|
+
isLocaleFallback: contentLocale !== requestedLocale
|
|
166
|
+
});
|
|
167
|
+
const resolveCmsPageForRequest = async (lang, path) => {
|
|
168
|
+
if (!buildCmsPath(lang, path)) return null;
|
|
169
|
+
const requested = await getForLocale(lang, path);
|
|
170
|
+
if (requested) return resolved(requested, lang, lang);
|
|
171
|
+
if (lang === FALLBACK_LOCALE) return null;
|
|
172
|
+
const fallback = await getForLocale(FALLBACK_LOCALE, path);
|
|
173
|
+
return fallback ? resolved(fallback, lang, FALLBACK_LOCALE) : null;
|
|
174
|
+
};
|
|
175
|
+
const getCmsPageForRequest = async (lang, path) => (await resolveCmsPageForRequest(lang, path))?.page ?? null;
|
|
176
|
+
const readResolvedCmsPageForRequest = async (lang, path) => {
|
|
177
|
+
if (!buildCmsPath(lang, path)) return {
|
|
178
|
+
status: "ok",
|
|
179
|
+
data: null
|
|
180
|
+
};
|
|
181
|
+
const requested = await readForLocale(lang, path);
|
|
182
|
+
if (requested.status !== "ok") return requested;
|
|
183
|
+
if (requested.data) return {
|
|
184
|
+
status: "ok",
|
|
185
|
+
data: resolved(requested.data, lang, lang)
|
|
186
|
+
};
|
|
187
|
+
if (lang === FALLBACK_LOCALE) return {
|
|
188
|
+
status: "ok",
|
|
189
|
+
data: null
|
|
190
|
+
};
|
|
191
|
+
const fallback = await readForLocale(FALLBACK_LOCALE, path);
|
|
192
|
+
if (fallback.status !== "ok") return fallback;
|
|
193
|
+
return {
|
|
194
|
+
status: "ok",
|
|
195
|
+
data: fallback.data ? resolved(fallback.data, lang, FALLBACK_LOCALE) : null
|
|
196
|
+
};
|
|
197
|
+
};
|
|
198
|
+
const readCmsPageForRequest = async (lang, path) => {
|
|
199
|
+
const read = await readResolvedCmsPageForRequest(lang, path);
|
|
200
|
+
return read.status === "ok" ? {
|
|
201
|
+
status: "ok",
|
|
202
|
+
data: read.data?.page ?? null
|
|
203
|
+
} : read;
|
|
137
204
|
};
|
|
138
205
|
const generateCmsPageMetadata = (page, lang) => {
|
|
139
206
|
const parsed = parseCmsPath(page.path);
|
|
140
|
-
if (!parsed
|
|
207
|
+
if (!parsed) return {};
|
|
208
|
+
const contentLocale = isCmsContentForLocale(page, lang) ? lang : parsed.locale;
|
|
141
209
|
return generatePageMetadata({
|
|
142
210
|
title: page.seoTitle ?? page.title,
|
|
143
211
|
description: page.seoDescription ?? "",
|
|
144
212
|
path: parsed.pathWithoutLocale,
|
|
145
|
-
lang,
|
|
213
|
+
lang: contentLocale,
|
|
146
214
|
type: "website"
|
|
147
215
|
});
|
|
148
216
|
};
|
|
149
217
|
return {
|
|
218
|
+
getCmsPageForLocale: getForLocale,
|
|
150
219
|
getCmsPageForRequest,
|
|
220
|
+
resolveCmsPageForRequest,
|
|
221
|
+
readCmsPageForRequest,
|
|
222
|
+
readResolvedCmsPageForRequest,
|
|
151
223
|
generateCmsPageMetadata
|
|
152
224
|
};
|
|
153
225
|
};
|
|
@@ -238,6 +310,14 @@ const createCmsTaxonomyReads = ({ getCms, requireCms }, appLabel) => ({
|
|
|
238
310
|
return readCmsOrFallback(cms ? () => cms.categories.list() : null, [], `list ${appLabel} categories`);
|
|
239
311
|
},
|
|
240
312
|
listBusabaseTags: async () => requireCms().tags.list(),
|
|
313
|
+
readBusabaseCategories: async () => {
|
|
314
|
+
const cms = getCms();
|
|
315
|
+
return readCmsStatus(cms ? () => cms.categories.list() : null, [], `list ${appLabel} categories`);
|
|
316
|
+
},
|
|
317
|
+
readBusabaseTags: async () => {
|
|
318
|
+
const cms = getCms();
|
|
319
|
+
return readCmsStatus(cms ? () => cms.tags.list() : null, [], `list ${appLabel} tags`);
|
|
320
|
+
},
|
|
241
321
|
listBusabaseTagsOrFallback: async () => {
|
|
242
322
|
const cms = getCms();
|
|
243
323
|
return readCmsOrFallback(cms ? () => cms.tags.list() : null, [], `list ${appLabel} tags`);
|
|
@@ -14,6 +14,32 @@ const readCmsOrFallback = async (operation, fallback, label) => {
|
|
|
14
14
|
return fallback;
|
|
15
15
|
}
|
|
16
16
|
};
|
|
17
|
+
const readCmsStatus = async (operation, whenUnconfigured, label) => {
|
|
18
|
+
if (!operation) return {
|
|
19
|
+
status: "ok",
|
|
20
|
+
data: whenUnconfigured
|
|
21
|
+
};
|
|
22
|
+
try {
|
|
23
|
+
return {
|
|
24
|
+
status: "ok",
|
|
25
|
+
data: await operation()
|
|
26
|
+
};
|
|
27
|
+
} catch (error) {
|
|
28
|
+
console.warn(`[busabase-cms] ${label} failed`, error);
|
|
29
|
+
return { status: "unavailable" };
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Unwrap a read, or fail loudly.
|
|
34
|
+
*
|
|
35
|
+
* Throwing beats rendering a 404: an error response is not cached, so the page
|
|
36
|
+
* recovers on the next request, whereas a cached 404 tells crawlers the content
|
|
37
|
+
* is gone.
|
|
38
|
+
*/
|
|
39
|
+
const requireCmsRead = (read, what) => {
|
|
40
|
+
if (read.status === "unavailable") throw new Error(`Busabase CMS unreachable while rendering ${what}`);
|
|
41
|
+
return read.data;
|
|
42
|
+
};
|
|
17
43
|
//#endregion
|
|
18
44
|
//#region src/routing.ts
|
|
19
45
|
const normalizeSegment = (segment) => {
|
|
@@ -88,4 +114,4 @@ const filterCmsPostsByTaxonomy = (posts, kind, taxonomy) => {
|
|
|
88
114
|
return posts.filter((post) => post.locale === taxonomy.locale && post[relationKey].includes(taxonomy.id));
|
|
89
115
|
};
|
|
90
116
|
//#endregion
|
|
91
|
-
export { isCmsBlogPostPath as a, parseCmsCanonicalPath as c, filterCmsPostsByTaxonomy as i, readCmsOrFallback as l, buildCmsTaxonomyArchivePath as n, isCmsContentForLocale as o, createCmsPathHelpers as r, normalizeCmsPath as s, buildCmsCanonicalPath as t };
|
|
117
|
+
export { isCmsBlogPostPath as a, parseCmsCanonicalPath as c, requireCmsRead as d, filterCmsPostsByTaxonomy as i, readCmsOrFallback as l, buildCmsTaxonomyArchivePath as n, isCmsContentForLocale as o, createCmsPathHelpers as r, normalizeCmsPath as s, buildCmsCanonicalPath as t, readCmsStatus as u };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "busabase-cms-sdk",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "Typed Posts, Pages, Categories, and Tags for Busabase CMS, Next.js, and Fumadocs.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://github.com/busabase/busabase/tree/main/packages/busabase-cms-sdk",
|
|
@@ -41,13 +41,13 @@
|
|
|
41
41
|
],
|
|
42
42
|
"sideEffects": false,
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"busabase-sdk": "^0.30.1",
|
|
45
44
|
"fumadocs-core": "16.14.5",
|
|
46
45
|
"rehype-sanitize": "^6.0.0",
|
|
47
46
|
"remark-gfm": "^4.0.1",
|
|
48
47
|
"sanitize-html": "^2.17.6",
|
|
49
48
|
"server-only": "^0.0.1",
|
|
50
|
-
"zod": "^4.3.6"
|
|
49
|
+
"zod": "^4.3.6",
|
|
50
|
+
"busabase-sdk": "^0.53.0"
|
|
51
51
|
},
|
|
52
52
|
"peerDependencies": {
|
|
53
53
|
"next": ">=15 <17",
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
}
|
|
63
63
|
},
|
|
64
64
|
"devDependencies": {
|
|
65
|
-
"@types/node": "^
|
|
65
|
+
"@types/node": "^26.3.0",
|
|
66
66
|
"@types/react": "^19.2.17",
|
|
67
67
|
"@types/sanitize-html": "^2.16.1",
|
|
68
68
|
"next": "16.3.3",
|