busabase-cms-sdk 0.1.3 → 0.1.4

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
- //#region src/fallback.d.ts
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-C3lkVAZ8.js";
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. */
@@ -132,6 +135,8 @@ interface CmsPageHelpersIntegration {
132
135
  path: string;
133
136
  }, locale: string) => boolean;
134
137
  getBusabaseLandingPageByPathOrFallback: (path: string) => Promise<PageVO | null>;
138
+ /** Status-aware variant, for callers that turn a missing page into a 404. */
139
+ readBusabaseLandingPageByPath: (path: string) => Promise<CmsRead<PageVO | null>>;
135
140
  }
136
141
  interface CmsPageHelpersOptions<TMetadata> {
137
142
  integration: CmsPageHelpersIntegration;
@@ -143,6 +148,13 @@ interface CmsPageHelpersOptions<TMetadata> {
143
148
  }
144
149
  interface CmsPageHelpers<TMetadata> {
145
150
  getCmsPageForRequest: (lang: string, path: string | readonly string[]) => Promise<PageVO | null>;
151
+ /**
152
+ * Status-aware variant. A CMS Page has no local-MDX equivalent, so a catch-all
153
+ * route cannot otherwise tell "no page at this path" (a correct, cacheable
154
+ * 404) from "the CMS is unreachable" (a 404 that would be cached as though the
155
+ * page had been deleted).
156
+ */
157
+ readCmsPageForRequest: (lang: string, path: string | readonly string[]) => Promise<CmsRead<PageVO | null>>;
146
158
  generateCmsPageMetadata: (page: PageVO, lang: string) => TMetadata | Record<string, never>;
147
159
  }
148
160
  declare const createCmsPageHelpers: <TMetadata>({ integration, generatePageMetadata }: CmsPageHelpersOptions<TMetadata>) => CmsPageHelpers<TMetadata>;
@@ -222,6 +234,13 @@ interface CmsTaxonomyReads {
222
234
  listBusabaseCategoriesOrFallback: () => Promise<CategoryVO[]>;
223
235
  listBusabaseTags: () => Promise<TagVO[]>;
224
236
  listBusabaseTagsOrFallback: () => Promise<TagVO[]>;
237
+ /**
238
+ * Status-aware variants, for callers that turn the result into a 404.
239
+ * A Category or Tag exists only in the CMS — there is no local fallback — so
240
+ * "the CMS is unreachable" and "no such taxonomy" are otherwise identical here.
241
+ */
242
+ readBusabaseCategories: () => Promise<CmsRead<CategoryVO[]>>;
243
+ readBusabaseTags: () => Promise<CmsRead<TagVO[]>>;
225
244
  }
226
245
  declare const createCmsTaxonomyReads: ({ getCms, requireCms }: CmsClientProvider, appLabel: string) => CmsTaxonomyReads;
227
246
  //#endregion
@@ -1,4 +1,4 @@
1
- import { l as readCmsOrFallback, r as createCmsPathHelpers, s as normalizeCmsPath } from "../routing-C3lkVAZ8.js";
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`);
@@ -128,13 +132,27 @@ const createCmsPageReads = ({ getCms, requireCms }, appLabel) => ({
128
132
  }
129
133
  });
130
134
  const createCmsPageHelpers = ({ integration, generatePageMetadata }) => {
131
- const { buildCmsPath, getBusabaseLandingPageByPathOrFallback, isCmsContentForLocale, parseCmsPath } = integration;
135
+ const { buildCmsPath, getBusabaseLandingPageByPathOrFallback, isCmsContentForLocale, parseCmsPath, readBusabaseLandingPageByPath } = integration;
132
136
  const getCmsPageForRequest = async (lang, path) => {
133
137
  const canonicalPath = buildCmsPath(lang, path);
134
138
  if (!canonicalPath) return null;
135
139
  const page = await getBusabaseLandingPageByPathOrFallback(canonicalPath);
136
140
  return page && isCmsContentForLocale(page, lang) ? page : null;
137
141
  };
142
+ const readCmsPageForRequest = async (lang, path) => {
143
+ const canonicalPath = buildCmsPath(lang, path);
144
+ if (!canonicalPath) return {
145
+ status: "ok",
146
+ data: null
147
+ };
148
+ const read = await readBusabaseLandingPageByPath(canonicalPath);
149
+ if (read.status !== "ok") return read;
150
+ const page = read.data;
151
+ return {
152
+ status: "ok",
153
+ data: page && isCmsContentForLocale(page, lang) ? page : null
154
+ };
155
+ };
138
156
  const generateCmsPageMetadata = (page, lang) => {
139
157
  const parsed = parseCmsPath(page.path);
140
158
  if (!parsed || parsed.locale !== lang) return {};
@@ -148,6 +166,7 @@ const createCmsPageHelpers = ({ integration, generatePageMetadata }) => {
148
166
  };
149
167
  return {
150
168
  getCmsPageForRequest,
169
+ readCmsPageForRequest,
151
170
  generateCmsPageMetadata
152
171
  };
153
172
  };
@@ -238,6 +257,14 @@ const createCmsTaxonomyReads = ({ getCms, requireCms }, appLabel) => ({
238
257
  return readCmsOrFallback(cms ? () => cms.categories.list() : null, [], `list ${appLabel} categories`);
239
258
  },
240
259
  listBusabaseTags: async () => requireCms().tags.list(),
260
+ readBusabaseCategories: async () => {
261
+ const cms = getCms();
262
+ return readCmsStatus(cms ? () => cms.categories.list() : null, [], `list ${appLabel} categories`);
263
+ },
264
+ readBusabaseTags: async () => {
265
+ const cms = getCms();
266
+ return readCmsStatus(cms ? () => cms.tags.list() : null, [], `list ${appLabel} tags`);
267
+ },
241
268
  listBusabaseTagsOrFallback: async () => {
242
269
  const cms = getCms();
243
270
  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",
3
+ "version": "0.1.4",
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.50.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": "^24.13.2",
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",