@sprintup-cms/sdk 1.9.2 → 1.9.3

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/client.cjs CHANGED
@@ -3,6 +3,32 @@
3
3
  /* @sprintup-cms/sdk — https://forgecms.io */
4
4
 
5
5
  // src/client.ts
6
+ function resolveNavItems(items = []) {
7
+ return items.map((item) => {
8
+ let href = "#";
9
+ if (item.type === "anchor") {
10
+ const anchorId = item.anchorTarget || "";
11
+ const anchorPage = item.anchorPage || "";
12
+ if (anchorId) {
13
+ href = anchorPage ? `/${anchorPage}#${anchorId}` : `#${anchorId}`;
14
+ }
15
+ } else if (item.url) {
16
+ href = item.url;
17
+ }
18
+ return {
19
+ id: item.id ?? "",
20
+ type: item.type ?? "link",
21
+ label: item.label ?? "",
22
+ url: item.url,
23
+ anchorTarget: item.anchorTarget,
24
+ anchorPage: item.anchorPage,
25
+ href,
26
+ locked: item.locked ?? false,
27
+ openInNewTab: item.openInNewTab ?? false,
28
+ children: resolveNavItems(item.children ?? [])
29
+ };
30
+ });
31
+ }
6
32
  function createCMSClient(options) {
7
33
  function cfg() {
8
34
  return {
@@ -164,32 +190,6 @@ function createCMSClient(options) {
164
190
  return null;
165
191
  }
166
192
  }
167
- function resolveNavItems(items = []) {
168
- return items.map((item) => {
169
- let href = "#";
170
- if (item.type === "anchor") {
171
- const anchorId = item.anchorTarget || "";
172
- const anchorPage = item.anchorPage || "";
173
- if (anchorId) {
174
- href = anchorPage ? `/${anchorPage}#${anchorId}` : `#${anchorId}`;
175
- }
176
- } else if (item.url) {
177
- href = item.url;
178
- }
179
- return {
180
- id: item.id ?? "",
181
- type: item.type ?? "link",
182
- label: item.label ?? "",
183
- url: item.url,
184
- anchorTarget: item.anchorTarget,
185
- anchorPage: item.anchorPage,
186
- href,
187
- locked: item.locked ?? false,
188
- openInNewTab: item.openInNewTab ?? false,
189
- children: resolveNavItems(item.children ?? [])
190
- };
191
- });
192
- }
193
193
  async function getGlobals() {
194
194
  const { baseUrl, appId } = cfg();
195
195
  if (!baseUrl || !appId) return { navigation: null, footer: null, navItems: [] };
@@ -230,5 +230,6 @@ var cmsClient = createCMSClient();
230
230
 
231
231
  exports.cmsClient = cmsClient;
232
232
  exports.createCMSClient = createCMSClient;
233
+ exports.resolveNavItems = resolveNavItems;
233
234
  //# sourceMappingURL=client.cjs.map
234
235
  //# sourceMappingURL=client.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/client.ts"],"names":[],"mappings":"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","file":"client.cjs","sourcesContent":["/**\n * @sprintup-cms/sdk — Core Client\n *\n * Zero-dependency, framework-agnostic typed API client for SprintUp Forge CMS.\n *\n * @example\n * import { cmsClient } from '@sprintup-cms/sdk'\n * const page = await cmsClient.getPage('about')\n *\n * @example Custom instance\n * import { createCMSClient } from '@sprintup-cms/sdk'\n * const cms = createCMSClient({ baseUrl: '...', apiKey: '...', appId: '...' })\n */\n\n// ── Types ─────────────────────────────────────────────────────────────────────\n\nexport interface CMSBlock {\n id: string\n type: string\n label?: string\n locked?: boolean\n data?: Record<string, any>\n /** Legacy field — blocks created before v1.1 used `content` instead of `data` */\n content?: Record<string, any>\n order?: number\n}\n\nexport interface CMSPage {\n _id?: string\n slug: string\n title: string\n description?: string\n pageType?: string\n pageTypeId?: string\n variant?: string\n status: 'draft' | 'published' | 'archived'\n visibility?: 'public' | 'private' | 'password'\n blocks: CMSBlock[]\n publishedAt?: string\n updatedAt?: string\n seo?: {\n title?: string\n description?: string\n keywords?: string[]\n ogImage?: string\n noIndex?: boolean\n }\n}\n\nexport interface CMSPageTypeField {\n id: string\n name: string\n label: string\n fieldType:\n | 'text' | 'textarea' | 'richtext' | 'image' | 'url'\n | 'number' | 'boolean' | 'date' | 'select' | 'relation'\n | 'email' | 'phone' | 'slug' | 'color' | 'embed'\n | 'multi-select' | 'repeater' | 'file' | 'code'\n required?: boolean\n options?: string[]\n description?: string\n maxLength?: number\n multiple?: boolean\n targetPageTypeKey?: string\n}\n\nexport interface CMSPageTypeSection {\n id: string\n name: string\n label: string\n order: number\n locked?: boolean\n fields: CMSPageTypeField[]\n}\n\nexport interface CMSPageTypeVariant {\n key: string\n label: string\n description?: string\n visibleSections?: string[]\n}\n\nexport interface CMSPageType {\n _id: string\n name: string\n key: string\n description?: string\n icon?: string\n /** Used by page-type-renderers to pick a specialised React component */\n rendererKey?: string\n /** Active variant key (set per-page) */\n variant?: string\n category: 'singleton' | 'collection' | 'global'\n contentCategory: 'singleton' | 'collection' | 'global'\n allowedRoles?: string[]\n variants: CMSPageTypeVariant[]\n sections: CMSPageTypeSection[]\n}\n\n// ── Sitemap ────────────────────────────────────────────────────────────────────\n\nexport interface CMSSitemapUrl {\n loc: string\n lastmod?: string\n changefreq?: string\n priority?: number\n title?: string\n}\n\nexport interface CMSSitemapResponse {\n enabled: boolean\n urls: CMSSitemapUrl[]\n config?: {\n defaultChangeFreq?: string\n defaultPriority?: number\n }\n}\n\n// ── Status ─────────────────────────────────────────────────────────────────────\n\nexport interface CMSStatusResponse {\n appId: string\n totalPages: number\n publishedPages: number\n connected: boolean\n pages: Array<{\n slug: string\n title: string\n pageType?: string\n group?: string\n }>\n}\n\n// ── Site Structure ─────────────────────────────────────────────────────────────\n\n/**\n * @deprecated Navigation and footer menus are now managed as CMS Globals.\n * Use `cmsClient.getGlobals()` instead.\n */\nexport type CMSMenuItemType = 'page' | 'url' | 'dynamic' | 'anchor'\n\n/**\n * @deprecated Navigation and footer menus are now managed as CMS Globals.\n * Use `cmsClient.getGlobals()` instead.\n */\nexport interface CMSMenuItem {\n id: string\n type: CMSMenuItemType\n label: string\n contentId?: string\n url?: string\n /** For anchor links: the target section ID (e.g. \"features\", \"pricing\") */\n anchorTarget?: string\n /** For anchor links: the slug of the page containing the section (e.g. \"about\"). Empty string = home/current page. */\n anchorPage?: string\n /**\n * Resolved href — ready to pass to <Link href>.\n * - Same-page anchor: \"#section-id\"\n * - Cross-page anchor: \"/page-slug#section-id\"\n * - Regular link: \"/slug\" or \"https://…\"\n * Never null, falls back to \"#\".\n */\n href: string\n locked: boolean\n openInNewTab: boolean\n children: CMSMenuItem[]\n page?: {\n title?: string\n slug?: string\n seoTitle?: string\n seoDescription?: string\n }\n}\n\nexport interface CMSPageTreeNode {\n id: string\n contentId: string\n parentId: string | null\n order: number\n locked: boolean\n visible?: boolean\n page?: {\n title?: string\n slug?: string\n seoTitle?: string\n seoDescription?: string\n }\n}\n\n/**\n * @deprecated Footer columns are now managed as CMS Globals.\n * Use `cmsClient.getGlobals()` instead.\n */\nexport interface CMSFooterGroup {\n id: string\n heading: string\n headingUrl?: string\n locked: boolean\n links: CMSMenuItem[]\n}\n\nexport interface CMSSiteStructure {\n appId: string\n pageTree: CMSPageTreeNode[]\n /**\n * @deprecated Menus are no longer stored in site-structure.\n * Use `cmsClient.getGlobals()` for navigation and footer data.\n */\n menus?: {\n header: CMSMenuItem[]\n footer: CMSFooterGroup[]\n footerBottom: CMSMenuItem[]\n sidebar: CMSMenuItem[]\n [slot: string]: CMSMenuItem[] | CMSFooterGroup[]\n }\n updatedAt?: string\n}\n\n// ── Pagination & Responses ─────────────────────────────────────────────────────\n\n// v1 route returns { data, count } — flat, no nested meta object\ninterface CMSListResponse {\n data: CMSPage[]\n count: number\n appId?: string\n}\n\ninterface CMSSingleResponse {\n data: CMSPage\n}\n\n// ── Client Options ─────────────────────────────────────────────────────────────\n\nexport interface CMSClientOptions {\n /** Base URL of your Forge CMS instance, e.g. https://cms.yourschool.io */\n baseUrl?: string\n /** API key generated in CMS Admin → API Keys. Server-side only. */\n apiKey?: string\n /** App ID from CMS Admin → Apps, e.g. \"school-website\" */\n appId?: string\n}\n\nexport interface CMSGetPagesOptions {\n type?: string\n group?: string\n page?: number\n perPage?: number\n status?: 'published' | 'draft' | 'archived'\n}\n\n// ── Factory ───────────────────────────────────────────────────────────────────\n\nexport function createCMSClient(options?: CMSClientOptions) {\n /**\n * Resolve config lazily at request time — NOT at module/build time.\n * This prevents static prerendering crashes when env vars are absent during build.\n */\n function cfg() {\n return {\n baseUrl: (options?.baseUrl ?? process.env.NEXT_PUBLIC_CMS_URL ?? process.env.CMS_BASE_URL ?? '').replace(/\\/$/, ''),\n apiKey: options?.apiKey ?? process.env.CMS_API_KEY ?? '',\n appId: options?.appId ?? process.env.CMS_APP_ID ?? '',\n }\n }\n\n function headers() {\n return { 'X-CMS-API-Key': cfg().apiKey, 'Content-Type': 'application/json' }\n }\n\n // ── Pages ──────────────────────────────────────────────────────────────────\n\n async function getPages(params?: CMSGetPagesOptions): Promise<CMSPage[]> {\n const { baseUrl, apiKey, appId } = cfg()\n if (!baseUrl || !apiKey || !appId) {\n console.warn('[sprintup-cms] Missing CMS_BASE_URL / CMS_API_KEY / CMS_APP_ID — returning []')\n return []\n }\n try {\n const qs = new URLSearchParams()\n if (params?.type) qs.set('type', params.type)\n if (params?.group) qs.set('group', params.group)\n if (params?.page) qs.set('page', String(params.page))\n if (params?.perPage) qs.set('perPage', String(params.perPage))\n const url = `${baseUrl}/api/v1/${appId}/pages${qs.size ? `?${qs}` : ''}`\n const res = await fetch(url, {\n headers: headers(),\n next: { revalidate: 60, tags: [`cms-pages-${appId}`] },\n } as RequestInit)\n if (!res.ok) { console.error(`[sprintup-cms] getPages (${res.status})`); return [] }\n const json: CMSListResponse = await res.json()\n return json.data ?? []\n } catch (err) {\n console.error('[sprintup-cms] getPages error:', err)\n return []\n }\n }\n\n async function getPage(slug: string): Promise<CMSPage | null> {\n const { baseUrl, apiKey, appId } = cfg()\n if (!baseUrl || !apiKey || !appId) {\n console.warn('[sprintup-cms] Missing config — returning null')\n return null\n }\n try {\n const res = await fetch(`${baseUrl}/api/v1/${appId}/pages/${slug}`, {\n headers: headers(),\n next: { revalidate: 60, tags: [`cms-page-${slug}`, `cms-pages-${appId}`] },\n } as RequestInit)\n if (res.status === 404) return null\n if (!res.ok) { console.error(`[sprintup-cms] getPage \"${slug}\" (${res.status})`); return null }\n const json: CMSSingleResponse = await res.json()\n return json.data ?? null\n } catch (err) {\n console.error(`[sprintup-cms] getPage \"${slug}\" error:`, err)\n return null\n }\n }\n\n async function getBlogPosts(): Promise<CMSPage[]> {\n return getPages({ type: 'blog-post' })\n }\n\n async function getEvents(): Promise<CMSPage[]> {\n return getPages({ type: 'event-page' })\n }\n\n async function getAnnouncements(): Promise<CMSPage[]> {\n return getPages({ type: 'announcement-page' })\n }\n\n // ── Preview ────────────────────────────────────────────────────────────────\n\n async function getPreviewPage(token: string): Promise<CMSPage | null> {\n const { baseUrl, appId } = cfg()\n if (!baseUrl || !appId) {\n console.warn('[sprintup-cms] getPreviewPage: Missing baseUrl or appId — returning null')\n return null\n }\n try {\n const url = `${baseUrl}/api/v1/${appId}/preview?token=${encodeURIComponent(token)}`\n const res = await fetch(url, { cache: 'no-store' })\n if (!res.ok) {\n const errorText = await res.text().catch(() => '')\n console.error(`[sprintup-cms] getPreviewPage failed (${res.status}): ${errorText}`)\n return null\n }\n const json = await res.json()\n return json.data ?? null\n } catch (err) {\n console.error('[sprintup-cms] getPreviewPage error:', err)\n return null\n }\n }\n\n async function getPageWithPreview(slug: string, previewToken?: string | null): Promise<CMSPage | null> {\n if (previewToken) {\n const preview = await getPreviewPage(previewToken)\n if (preview?.slug === slug) return preview\n }\n return getPage(slug)\n }\n\n // ── Page Types ─────────────────────────────────────────────────────────────\n\n async function getPageType(pageTypeId: string): Promise<CMSPageType | null> {\n const { baseUrl, apiKey, appId } = cfg()\n if (!baseUrl || !apiKey || !appId || !pageTypeId) return null\n try {\n const res = await fetch(`${baseUrl}/api/v1/${appId}/page-types/${pageTypeId}`, {\n headers: headers(),\n next: { revalidate: 3600, tags: [`cms-page-type-${pageTypeId}`] },\n } as RequestInit)\n if (!res.ok) return null\n const json = await res.json()\n return json.data ?? null\n } catch {\n return null\n }\n }\n\n // ── Site Structure ─────────────────────────────────────────────────────────\n\n async function getSiteStructure(): Promise<CMSSiteStructure | null> {\n const { baseUrl, apiKey, appId } = cfg()\n if (!baseUrl || !apiKey || !appId) return null\n try {\n const res = await fetch(`${baseUrl}/api/v1/${appId}/site-structure`, {\n headers: headers(),\n next: {\n revalidate: 300,\n tags: [`site-structure-${appId}`],\n },\n } as RequestInit)\n if (!res.ok) return null\n const json = await res.json()\n return json.data ?? null\n } catch {\n return null\n }\n }\n\n /**\n * GET /api/v1/{appId}/sitemap\n * Fetch sitemap data for all published pages (priority, changefreq, lastmod).\n *\n * @example app/sitemap.ts\n * import type { MetadataRoute } from 'next'\n * import { cmsClient } from '@sprintup-cms/sdk'\n *\n * export default async function sitemap(): Promise<MetadataRoute.Sitemap> {\n * const data = await cmsClient.getSitemap()\n * if (!data?.enabled) return []\n * return data.urls.map(url => ({\n * url: `${process.env.NEXT_PUBLIC_SITE_URL}${url.loc}`,\n * lastModified: url.lastmod,\n * changeFrequency: url.changefreq as MetadataRoute.Sitemap[0]['changeFrequency'],\n * priority: url.priority,\n * }))\n * }\n */\n async function getSitemap(): Promise<CMSSitemapResponse | null> {\n const { baseUrl, apiKey, appId } = cfg()\n if (!baseUrl || !apiKey || !appId) return null\n try {\n const res = await fetch(`${baseUrl}/api/v1/${appId}/sitemap`, {\n headers: headers(),\n next: { revalidate: 3600 },\n } as RequestInit)\n if (!res.ok) return null\n const json = await res.json()\n return json.data ?? null\n } catch { return null }\n }\n\n /**\n * GET /api/v1/{appId}/status\n * Verify connectivity and retrieve page counts. Never cached — always fresh.\n * Useful for debugging API key setup.\n */\n async function getStatus(): Promise<CMSStatusResponse | null> {\n const { baseUrl, apiKey, appId } = cfg()\n if (!baseUrl || !apiKey || !appId) return null\n try {\n const res = await fetch(`${baseUrl}/api/v1/${appId}/status`, {\n headers: headers(),\n cache: 'no-store',\n } as RequestInit)\n if (!res.ok) return null\n return await res.json()\n } catch { return null }\n }\n\n /**\n * Resolves a raw nav item array (from globals block content) into typed CMSMenuItems.\n * Computes the `href` field from `type`, `url`, `anchorPage`, and `anchorTarget`.\n *\n * - type 'anchor' + anchorPage → \"/page-slug#section-id\"\n * - type 'anchor' + no anchorPage → \"#section-id\"\n * - type 'url' or 'link' → raw url value\n * - fallback → \"#\"\n */\n function resolveNavItems(items: any[] = []): CMSMenuItem[] {\n return items.map((item: any): CMSMenuItem => {\n let href = '#'\n if (item.type === 'anchor') {\n const anchorId = item.anchorTarget || ''\n const anchorPage = item.anchorPage || ''\n if (anchorId) {\n href = anchorPage ? `/${anchorPage}#${anchorId}` : `#${anchorId}`\n }\n } else if (item.url) {\n href = item.url\n }\n return {\n id: item.id ?? '',\n type: item.type ?? 'link',\n label: item.label ?? '',\n url: item.url,\n anchorTarget: item.anchorTarget,\n anchorPage: item.anchorPage,\n href,\n locked: item.locked ?? false,\n openInNewTab: item.openInNewTab ?? false,\n children: resolveNavItems(item.children ?? []),\n }\n })\n }\n\n async function getGlobals(): Promise<{\n navigation: CMSPage | null\n footer: CMSPage | null\n /** Pre-resolved navigation items — ready to map directly in your header component. */\n navItems: CMSMenuItem[]\n }> {\n const { baseUrl, appId } = cfg()\n if (!baseUrl || !appId) return { navigation: null, footer: null, navItems: [] }\n try {\n const res = await fetch(`${baseUrl}/api/v1/${appId}/globals`, {\n headers: headers(),\n next: { revalidate: 60, tags: [`cms-globals-${appId}`] },\n } as RequestInit)\n if (!res.ok) return { navigation: null, footer: null, navItems: [] }\n\n const json = await res.json()\n const navigation: CMSPage | null = json.data?.navigation ?? null\n\n // Nav items live in the first block's content.items array\n const rawItems = navigation?.blocks?.[0]?.content?.items\n ?? navigation?.blocks?.[0]?.data?.items\n ?? []\n\n return {\n navigation,\n footer: json.data?.footer ?? null,\n navItems: resolveNavItems(rawItems),\n }\n } catch {\n return { navigation: null, footer: null, navItems: [] }\n }\n }\n\n return {\n getPages,\n getPage,\n getGlobals,\n getBlogPosts,\n getEvents,\n getAnnouncements,\n getPreviewPage,\n getPageWithPreview,\n getPageType,\n getSiteStructure,\n getSitemap,\n getStatus,\n }\n}\n\n// ── Default singleton ─────────────────────────────────────────────────────────\n\n/** Pre-configured singleton. Reads env vars lazily at request time. */\nexport const cmsClient = createCMSClient()\n"]}
1
+ {"version":3,"sources":["../src/client.ts"],"names":[],"mappings":"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","file":"client.cjs","sourcesContent":["/**\n * @sprintup-cms/sdk — Core Client\n *\n * Zero-dependency, framework-agnostic typed API client for SprintUp Forge CMS.\n *\n * @example\n * import { cmsClient } from '@sprintup-cms/sdk'\n * const page = await cmsClient.getPage('about')\n *\n * @example Custom instance\n * import { createCMSClient } from '@sprintup-cms/sdk'\n * const cms = createCMSClient({ baseUrl: '...', apiKey: '...', appId: '...' })\n */\n\n// ── Types ─────────────────────────────────────────────────────────────────────\n\nexport interface CMSBlock {\n id: string\n type: string\n label?: string\n locked?: boolean\n data?: Record<string, any>\n /** Legacy field — blocks created before v1.1 used `content` instead of `data` */\n content?: Record<string, any>\n order?: number\n}\n\nexport interface CMSPage {\n _id?: string\n slug: string\n title: string\n description?: string\n pageType?: string\n pageTypeId?: string\n variant?: string\n status: 'draft' | 'published' | 'archived'\n visibility?: 'public' | 'private' | 'password'\n blocks: CMSBlock[]\n publishedAt?: string\n updatedAt?: string\n seo?: {\n title?: string\n description?: string\n keywords?: string[]\n ogImage?: string\n noIndex?: boolean\n }\n}\n\nexport interface CMSPageTypeField {\n id: string\n name: string\n label: string\n fieldType:\n | 'text' | 'textarea' | 'richtext' | 'image' | 'url'\n | 'number' | 'boolean' | 'date' | 'select' | 'relation'\n | 'email' | 'phone' | 'slug' | 'color' | 'embed'\n | 'multi-select' | 'repeater' | 'file' | 'code'\n required?: boolean\n options?: string[]\n description?: string\n maxLength?: number\n multiple?: boolean\n targetPageTypeKey?: string\n}\n\nexport interface CMSPageTypeSection {\n id: string\n name: string\n label: string\n order: number\n locked?: boolean\n fields: CMSPageTypeField[]\n}\n\nexport interface CMSPageTypeVariant {\n key: string\n label: string\n description?: string\n visibleSections?: string[]\n}\n\nexport interface CMSPageType {\n _id: string\n name: string\n key: string\n description?: string\n icon?: string\n /** Used by page-type-renderers to pick a specialised React component */\n rendererKey?: string\n /** Active variant key (set per-page) */\n variant?: string\n category: 'singleton' | 'collection' | 'global'\n contentCategory: 'singleton' | 'collection' | 'global'\n allowedRoles?: string[]\n variants: CMSPageTypeVariant[]\n sections: CMSPageTypeSection[]\n}\n\n// ── Sitemap ────────────────────────────────────────────────────────────────────\n\nexport interface CMSSitemapUrl {\n loc: string\n lastmod?: string\n changefreq?: string\n priority?: number\n title?: string\n}\n\nexport interface CMSSitemapResponse {\n enabled: boolean\n urls: CMSSitemapUrl[]\n config?: {\n defaultChangeFreq?: string\n defaultPriority?: number\n }\n}\n\n// ── Status ─────────────────────────────────────────────────────────────────────\n\nexport interface CMSStatusResponse {\n appId: string\n totalPages: number\n publishedPages: number\n connected: boolean\n pages: Array<{\n slug: string\n title: string\n pageType?: string\n group?: string\n }>\n}\n\n// ── Site Structure ─────────────────────────────────────────────────────────────\n\n/**\n * @deprecated Navigation and footer menus are now managed as CMS Globals.\n * Use `cmsClient.getGlobals()` instead.\n */\nexport type CMSMenuItemType = 'page' | 'url' | 'dynamic' | 'anchor'\n\n/**\n * @deprecated Navigation and footer menus are now managed as CMS Globals.\n * Use `cmsClient.getGlobals()` instead.\n */\nexport interface CMSMenuItem {\n id: string\n type: CMSMenuItemType\n label: string\n contentId?: string\n url?: string\n /** For anchor links: the target section ID (e.g. \"features\", \"pricing\") */\n anchorTarget?: string\n /** For anchor links: the slug of the page containing the section (e.g. \"about\"). Empty string = home/current page. */\n anchorPage?: string\n /**\n * Resolved href — ready to pass to <Link href>.\n * - Same-page anchor: \"#section-id\"\n * - Cross-page anchor: \"/page-slug#section-id\"\n * - Regular link: \"/slug\" or \"https://…\"\n * Never null, falls back to \"#\".\n */\n href: string\n locked: boolean\n openInNewTab: boolean\n children: CMSMenuItem[]\n page?: {\n title?: string\n slug?: string\n seoTitle?: string\n seoDescription?: string\n }\n}\n\nexport interface CMSPageTreeNode {\n id: string\n contentId: string\n parentId: string | null\n order: number\n locked: boolean\n visible?: boolean\n page?: {\n title?: string\n slug?: string\n seoTitle?: string\n seoDescription?: string\n }\n}\n\n/**\n * @deprecated Footer columns are now managed as CMS Globals.\n * Use `cmsClient.getGlobals()` instead.\n */\nexport interface CMSFooterGroup {\n id: string\n heading: string\n headingUrl?: string\n locked: boolean\n links: CMSMenuItem[]\n}\n\nexport interface CMSSiteStructure {\n appId: string\n pageTree: CMSPageTreeNode[]\n /**\n * @deprecated Menus are no longer stored in site-structure.\n * Use `cmsClient.getGlobals()` for navigation and footer data.\n */\n menus?: {\n header: CMSMenuItem[]\n footer: CMSFooterGroup[]\n footerBottom: CMSMenuItem[]\n sidebar: CMSMenuItem[]\n [slot: string]: CMSMenuItem[] | CMSFooterGroup[]\n }\n updatedAt?: string\n}\n\n// ── Pagination & Responses ─────────────────────────────────────────────────────\n\n// v1 route returns { data, count } — flat, no nested meta object\ninterface CMSListResponse {\n data: CMSPage[]\n count: number\n appId?: string\n}\n\ninterface CMSSingleResponse {\n data: CMSPage\n}\n\n// ── Client Options ─────────────────────────────────────────────────────────────\n\nexport interface CMSClientOptions {\n /** Base URL of your Forge CMS instance, e.g. https://cms.yourschool.io */\n baseUrl?: string\n /** API key generated in CMS Admin → API Keys. Server-side only. */\n apiKey?: string\n /** App ID from CMS Admin → Apps, e.g. \"school-website\" */\n appId?: string\n}\n\nexport interface CMSGetPagesOptions {\n type?: string\n group?: string\n page?: number\n perPage?: number\n status?: 'published' | 'draft' | 'archived'\n}\n\n// ── Nav Item Resolution ───────────────────────────────────────────────────────\n\n/**\n * Resolves a raw nav item array (from globals block content) into typed CMSMenuItems.\n * Computes the `href` field from `type`, `url`, `anchorPage`, and `anchorTarget`.\n *\n * - type 'anchor' + anchorPage → \"/page-slug#section-id\"\n * - type 'anchor' + no anchorPage → \"#section-id\"\n * - type 'url' or 'link' → raw url value\n * - fallback → \"#\"\n *\n * @example\n * import { resolveNavItems } from '@sprintup-cms/sdk'\n * const navItems = resolveNavItems(rawNavData)\n */\nexport function resolveNavItems(items: any[] = []): CMSMenuItem[] {\n return items.map((item: any): CMSMenuItem => {\n let href = '#'\n if (item.type === 'anchor') {\n const anchorId = item.anchorTarget || ''\n const anchorPage = item.anchorPage || ''\n if (anchorId) {\n href = anchorPage ? `/${anchorPage}#${anchorId}` : `#${anchorId}`\n }\n } else if (item.url) {\n href = item.url\n }\n return {\n id: item.id ?? '',\n type: item.type ?? 'link',\n label: item.label ?? '',\n url: item.url,\n anchorTarget: item.anchorTarget,\n anchorPage: item.anchorPage,\n href,\n locked: item.locked ?? false,\n openInNewTab: item.openInNewTab ?? false,\n children: resolveNavItems(item.children ?? []),\n }\n })\n}\n\n// ── Factory ───────────────────────────────────────────────────────────────────\n\nexport function createCMSClient(options?: CMSClientOptions) {\n /**\n * Resolve config lazily at request time — NOT at module/build time.\n * This prevents static prerendering crashes when env vars are absent during build.\n */\n function cfg() {\n return {\n baseUrl: (options?.baseUrl ?? process.env.NEXT_PUBLIC_CMS_URL ?? process.env.CMS_BASE_URL ?? '').replace(/\\/$/, ''),\n apiKey: options?.apiKey ?? process.env.CMS_API_KEY ?? '',\n appId: options?.appId ?? process.env.CMS_APP_ID ?? '',\n }\n }\n\n function headers() {\n return { 'X-CMS-API-Key': cfg().apiKey, 'Content-Type': 'application/json' }\n }\n\n // ── Pages ──────────────────────────────────────────────────────────────────\n\n async function getPages(params?: CMSGetPagesOptions): Promise<CMSPage[]> {\n const { baseUrl, apiKey, appId } = cfg()\n if (!baseUrl || !apiKey || !appId) {\n console.warn('[sprintup-cms] Missing CMS_BASE_URL / CMS_API_KEY / CMS_APP_ID — returning []')\n return []\n }\n try {\n const qs = new URLSearchParams()\n if (params?.type) qs.set('type', params.type)\n if (params?.group) qs.set('group', params.group)\n if (params?.page) qs.set('page', String(params.page))\n if (params?.perPage) qs.set('perPage', String(params.perPage))\n const url = `${baseUrl}/api/v1/${appId}/pages${qs.size ? `?${qs}` : ''}`\n const res = await fetch(url, {\n headers: headers(),\n next: { revalidate: 60, tags: [`cms-pages-${appId}`] },\n } as RequestInit)\n if (!res.ok) { console.error(`[sprintup-cms] getPages (${res.status})`); return [] }\n const json: CMSListResponse = await res.json()\n return json.data ?? []\n } catch (err) {\n console.error('[sprintup-cms] getPages error:', err)\n return []\n }\n }\n\n async function getPage(slug: string): Promise<CMSPage | null> {\n const { baseUrl, apiKey, appId } = cfg()\n if (!baseUrl || !apiKey || !appId) {\n console.warn('[sprintup-cms] Missing config — returning null')\n return null\n }\n try {\n const res = await fetch(`${baseUrl}/api/v1/${appId}/pages/${slug}`, {\n headers: headers(),\n next: { revalidate: 60, tags: [`cms-page-${slug}`, `cms-pages-${appId}`] },\n } as RequestInit)\n if (res.status === 404) return null\n if (!res.ok) { console.error(`[sprintup-cms] getPage \"${slug}\" (${res.status})`); return null }\n const json: CMSSingleResponse = await res.json()\n return json.data ?? null\n } catch (err) {\n console.error(`[sprintup-cms] getPage \"${slug}\" error:`, err)\n return null\n }\n }\n\n async function getBlogPosts(): Promise<CMSPage[]> {\n return getPages({ type: 'blog-post' })\n }\n\n async function getEvents(): Promise<CMSPage[]> {\n return getPages({ type: 'event-page' })\n }\n\n async function getAnnouncements(): Promise<CMSPage[]> {\n return getPages({ type: 'announcement-page' })\n }\n\n // ── Preview ────────────────────────────────────────────────────────────────\n\n async function getPreviewPage(token: string): Promise<CMSPage | null> {\n const { baseUrl, appId } = cfg()\n if (!baseUrl || !appId) {\n console.warn('[sprintup-cms] getPreviewPage: Missing baseUrl or appId — returning null')\n return null\n }\n try {\n const url = `${baseUrl}/api/v1/${appId}/preview?token=${encodeURIComponent(token)}`\n const res = await fetch(url, { cache: 'no-store' })\n if (!res.ok) {\n const errorText = await res.text().catch(() => '')\n console.error(`[sprintup-cms] getPreviewPage failed (${res.status}): ${errorText}`)\n return null\n }\n const json = await res.json()\n return json.data ?? null\n } catch (err) {\n console.error('[sprintup-cms] getPreviewPage error:', err)\n return null\n }\n }\n\n async function getPageWithPreview(slug: string, previewToken?: string | null): Promise<CMSPage | null> {\n if (previewToken) {\n const preview = await getPreviewPage(previewToken)\n if (preview?.slug === slug) return preview\n }\n return getPage(slug)\n }\n\n // ── Page Types ─────────────────────────────────────────────────────────────\n\n async function getPageType(pageTypeId: string): Promise<CMSPageType | null> {\n const { baseUrl, apiKey, appId } = cfg()\n if (!baseUrl || !apiKey || !appId || !pageTypeId) return null\n try {\n const res = await fetch(`${baseUrl}/api/v1/${appId}/page-types/${pageTypeId}`, {\n headers: headers(),\n next: { revalidate: 3600, tags: [`cms-page-type-${pageTypeId}`] },\n } as RequestInit)\n if (!res.ok) return null\n const json = await res.json()\n return json.data ?? null\n } catch {\n return null\n }\n }\n\n // ── Site Structure ─────────────────────────────────────────────────────────\n\n async function getSiteStructure(): Promise<CMSSiteStructure | null> {\n const { baseUrl, apiKey, appId } = cfg()\n if (!baseUrl || !apiKey || !appId) return null\n try {\n const res = await fetch(`${baseUrl}/api/v1/${appId}/site-structure`, {\n headers: headers(),\n next: {\n revalidate: 300,\n tags: [`site-structure-${appId}`],\n },\n } as RequestInit)\n if (!res.ok) return null\n const json = await res.json()\n return json.data ?? null\n } catch {\n return null\n }\n }\n\n /**\n * GET /api/v1/{appId}/sitemap\n * Fetch sitemap data for all published pages (priority, changefreq, lastmod).\n *\n * @example app/sitemap.ts\n * import type { MetadataRoute } from 'next'\n * import { cmsClient } from '@sprintup-cms/sdk'\n *\n * export default async function sitemap(): Promise<MetadataRoute.Sitemap> {\n * const data = await cmsClient.getSitemap()\n * if (!data?.enabled) return []\n * return data.urls.map(url => ({\n * url: `${process.env.NEXT_PUBLIC_SITE_URL}${url.loc}`,\n * lastModified: url.lastmod,\n * changeFrequency: url.changefreq as MetadataRoute.Sitemap[0]['changeFrequency'],\n * priority: url.priority,\n * }))\n * }\n */\n async function getSitemap(): Promise<CMSSitemapResponse | null> {\n const { baseUrl, apiKey, appId } = cfg()\n if (!baseUrl || !apiKey || !appId) return null\n try {\n const res = await fetch(`${baseUrl}/api/v1/${appId}/sitemap`, {\n headers: headers(),\n next: { revalidate: 3600 },\n } as RequestInit)\n if (!res.ok) return null\n const json = await res.json()\n return json.data ?? null\n } catch { return null }\n }\n\n /**\n * GET /api/v1/{appId}/status\n * Verify connectivity and retrieve page counts. Never cached — always fresh.\n * Useful for debugging API key setup.\n */\n async function getStatus(): Promise<CMSStatusResponse | null> {\n const { baseUrl, apiKey, appId } = cfg()\n if (!baseUrl || !apiKey || !appId) return null\n try {\n const res = await fetch(`${baseUrl}/api/v1/${appId}/status`, {\n headers: headers(),\n cache: 'no-store',\n } as RequestInit)\n if (!res.ok) return null\n return await res.json()\n } catch { return null }\n }\n\n async function getGlobals(): Promise<{\n navigation: CMSPage | null\n footer: CMSPage | null\n /** Pre-resolved navigation items — ready to map directly in your header component. */\n navItems: CMSMenuItem[]\n }> {\n const { baseUrl, appId } = cfg()\n if (!baseUrl || !appId) return { navigation: null, footer: null, navItems: [] }\n try {\n const res = await fetch(`${baseUrl}/api/v1/${appId}/globals`, {\n headers: headers(),\n next: { revalidate: 60, tags: [`cms-globals-${appId}`] },\n } as RequestInit)\n if (!res.ok) return { navigation: null, footer: null, navItems: [] }\n\n const json = await res.json()\n const navigation: CMSPage | null = json.data?.navigation ?? null\n\n // Nav items live in the first block's content.items array\n const rawItems = navigation?.blocks?.[0]?.content?.items\n ?? navigation?.blocks?.[0]?.data?.items\n ?? []\n\n return {\n navigation,\n footer: json.data?.footer ?? null,\n navItems: resolveNavItems(rawItems),\n }\n } catch {\n return { navigation: null, footer: null, navItems: [] }\n }\n }\n\n return {\n getPages,\n getPage,\n getGlobals,\n getBlogPosts,\n getEvents,\n getAnnouncements,\n getPreviewPage,\n getPageWithPreview,\n getPageType,\n getSiteStructure,\n getSitemap,\n getStatus,\n }\n}\n\n// ── Default singleton ─────────────────────────────────────────────────────────\n\n/** Pre-configured singleton. Reads env vars lazily at request time. */\nexport const cmsClient = createCMSClient()\n"]}
package/dist/client.d.cts CHANGED
@@ -204,6 +204,20 @@ interface CMSGetPagesOptions {
204
204
  perPage?: number;
205
205
  status?: 'published' | 'draft' | 'archived';
206
206
  }
207
+ /**
208
+ * Resolves a raw nav item array (from globals block content) into typed CMSMenuItems.
209
+ * Computes the `href` field from `type`, `url`, `anchorPage`, and `anchorTarget`.
210
+ *
211
+ * - type 'anchor' + anchorPage → "/page-slug#section-id"
212
+ * - type 'anchor' + no anchorPage → "#section-id"
213
+ * - type 'url' or 'link' → raw url value
214
+ * - fallback → "#"
215
+ *
216
+ * @example
217
+ * import { resolveNavItems } from '@sprintup-cms/sdk'
218
+ * const navItems = resolveNavItems(rawNavData)
219
+ */
220
+ declare function resolveNavItems(items?: any[]): CMSMenuItem[];
207
221
  declare function createCMSClient(options?: CMSClientOptions): {
208
222
  getPages: (params?: CMSGetPagesOptions) => Promise<CMSPage[]>;
209
223
  getPage: (slug: string) => Promise<CMSPage | null>;
@@ -244,4 +258,4 @@ declare const cmsClient: {
244
258
  getStatus: () => Promise<CMSStatusResponse | null>;
245
259
  };
246
260
 
247
- export { type CMSBlock, type CMSClientOptions, type CMSFooterGroup, type CMSGetPagesOptions, type CMSMenuItem, type CMSMenuItemType, type CMSPage, type CMSPageTreeNode, type CMSPageType, type CMSPageTypeField, type CMSPageTypeSection, type CMSPageTypeVariant, type CMSSiteStructure, type CMSSitemapResponse, type CMSSitemapUrl, type CMSStatusResponse, cmsClient, createCMSClient };
261
+ export { type CMSBlock, type CMSClientOptions, type CMSFooterGroup, type CMSGetPagesOptions, type CMSMenuItem, type CMSMenuItemType, type CMSPage, type CMSPageTreeNode, type CMSPageType, type CMSPageTypeField, type CMSPageTypeSection, type CMSPageTypeVariant, type CMSSiteStructure, type CMSSitemapResponse, type CMSSitemapUrl, type CMSStatusResponse, cmsClient, createCMSClient, resolveNavItems };
package/dist/client.d.ts CHANGED
@@ -204,6 +204,20 @@ interface CMSGetPagesOptions {
204
204
  perPage?: number;
205
205
  status?: 'published' | 'draft' | 'archived';
206
206
  }
207
+ /**
208
+ * Resolves a raw nav item array (from globals block content) into typed CMSMenuItems.
209
+ * Computes the `href` field from `type`, `url`, `anchorPage`, and `anchorTarget`.
210
+ *
211
+ * - type 'anchor' + anchorPage → "/page-slug#section-id"
212
+ * - type 'anchor' + no anchorPage → "#section-id"
213
+ * - type 'url' or 'link' → raw url value
214
+ * - fallback → "#"
215
+ *
216
+ * @example
217
+ * import { resolveNavItems } from '@sprintup-cms/sdk'
218
+ * const navItems = resolveNavItems(rawNavData)
219
+ */
220
+ declare function resolveNavItems(items?: any[]): CMSMenuItem[];
207
221
  declare function createCMSClient(options?: CMSClientOptions): {
208
222
  getPages: (params?: CMSGetPagesOptions) => Promise<CMSPage[]>;
209
223
  getPage: (slug: string) => Promise<CMSPage | null>;
@@ -244,4 +258,4 @@ declare const cmsClient: {
244
258
  getStatus: () => Promise<CMSStatusResponse | null>;
245
259
  };
246
260
 
247
- export { type CMSBlock, type CMSClientOptions, type CMSFooterGroup, type CMSGetPagesOptions, type CMSMenuItem, type CMSMenuItemType, type CMSPage, type CMSPageTreeNode, type CMSPageType, type CMSPageTypeField, type CMSPageTypeSection, type CMSPageTypeVariant, type CMSSiteStructure, type CMSSitemapResponse, type CMSSitemapUrl, type CMSStatusResponse, cmsClient, createCMSClient };
261
+ export { type CMSBlock, type CMSClientOptions, type CMSFooterGroup, type CMSGetPagesOptions, type CMSMenuItem, type CMSMenuItemType, type CMSPage, type CMSPageTreeNode, type CMSPageType, type CMSPageTypeField, type CMSPageTypeSection, type CMSPageTypeVariant, type CMSSiteStructure, type CMSSitemapResponse, type CMSSitemapUrl, type CMSStatusResponse, cmsClient, createCMSClient, resolveNavItems };
package/dist/client.js CHANGED
@@ -1,6 +1,32 @@
1
1
  /* @sprintup-cms/sdk — https://forgecms.io */
2
2
 
3
3
  // src/client.ts
4
+ function resolveNavItems(items = []) {
5
+ return items.map((item) => {
6
+ let href = "#";
7
+ if (item.type === "anchor") {
8
+ const anchorId = item.anchorTarget || "";
9
+ const anchorPage = item.anchorPage || "";
10
+ if (anchorId) {
11
+ href = anchorPage ? `/${anchorPage}#${anchorId}` : `#${anchorId}`;
12
+ }
13
+ } else if (item.url) {
14
+ href = item.url;
15
+ }
16
+ return {
17
+ id: item.id ?? "",
18
+ type: item.type ?? "link",
19
+ label: item.label ?? "",
20
+ url: item.url,
21
+ anchorTarget: item.anchorTarget,
22
+ anchorPage: item.anchorPage,
23
+ href,
24
+ locked: item.locked ?? false,
25
+ openInNewTab: item.openInNewTab ?? false,
26
+ children: resolveNavItems(item.children ?? [])
27
+ };
28
+ });
29
+ }
4
30
  function createCMSClient(options) {
5
31
  function cfg() {
6
32
  return {
@@ -162,32 +188,6 @@ function createCMSClient(options) {
162
188
  return null;
163
189
  }
164
190
  }
165
- function resolveNavItems(items = []) {
166
- return items.map((item) => {
167
- let href = "#";
168
- if (item.type === "anchor") {
169
- const anchorId = item.anchorTarget || "";
170
- const anchorPage = item.anchorPage || "";
171
- if (anchorId) {
172
- href = anchorPage ? `/${anchorPage}#${anchorId}` : `#${anchorId}`;
173
- }
174
- } else if (item.url) {
175
- href = item.url;
176
- }
177
- return {
178
- id: item.id ?? "",
179
- type: item.type ?? "link",
180
- label: item.label ?? "",
181
- url: item.url,
182
- anchorTarget: item.anchorTarget,
183
- anchorPage: item.anchorPage,
184
- href,
185
- locked: item.locked ?? false,
186
- openInNewTab: item.openInNewTab ?? false,
187
- children: resolveNavItems(item.children ?? [])
188
- };
189
- });
190
- }
191
191
  async function getGlobals() {
192
192
  const { baseUrl, appId } = cfg();
193
193
  if (!baseUrl || !appId) return { navigation: null, footer: null, navItems: [] };
@@ -226,6 +226,6 @@ function createCMSClient(options) {
226
226
  }
227
227
  var cmsClient = createCMSClient();
228
228
 
229
- export { cmsClient, createCMSClient };
229
+ export { cmsClient, createCMSClient, resolveNavItems };
230
230
  //# sourceMappingURL=client.js.map
231
231
  //# sourceMappingURL=client.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/client.ts"],"names":[],"mappings":"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","file":"client.js","sourcesContent":["/**\n * @sprintup-cms/sdk — Core Client\n *\n * Zero-dependency, framework-agnostic typed API client for SprintUp Forge CMS.\n *\n * @example\n * import { cmsClient } from '@sprintup-cms/sdk'\n * const page = await cmsClient.getPage('about')\n *\n * @example Custom instance\n * import { createCMSClient } from '@sprintup-cms/sdk'\n * const cms = createCMSClient({ baseUrl: '...', apiKey: '...', appId: '...' })\n */\n\n// ── Types ─────────────────────────────────────────────────────────────────────\n\nexport interface CMSBlock {\n id: string\n type: string\n label?: string\n locked?: boolean\n data?: Record<string, any>\n /** Legacy field — blocks created before v1.1 used `content` instead of `data` */\n content?: Record<string, any>\n order?: number\n}\n\nexport interface CMSPage {\n _id?: string\n slug: string\n title: string\n description?: string\n pageType?: string\n pageTypeId?: string\n variant?: string\n status: 'draft' | 'published' | 'archived'\n visibility?: 'public' | 'private' | 'password'\n blocks: CMSBlock[]\n publishedAt?: string\n updatedAt?: string\n seo?: {\n title?: string\n description?: string\n keywords?: string[]\n ogImage?: string\n noIndex?: boolean\n }\n}\n\nexport interface CMSPageTypeField {\n id: string\n name: string\n label: string\n fieldType:\n | 'text' | 'textarea' | 'richtext' | 'image' | 'url'\n | 'number' | 'boolean' | 'date' | 'select' | 'relation'\n | 'email' | 'phone' | 'slug' | 'color' | 'embed'\n | 'multi-select' | 'repeater' | 'file' | 'code'\n required?: boolean\n options?: string[]\n description?: string\n maxLength?: number\n multiple?: boolean\n targetPageTypeKey?: string\n}\n\nexport interface CMSPageTypeSection {\n id: string\n name: string\n label: string\n order: number\n locked?: boolean\n fields: CMSPageTypeField[]\n}\n\nexport interface CMSPageTypeVariant {\n key: string\n label: string\n description?: string\n visibleSections?: string[]\n}\n\nexport interface CMSPageType {\n _id: string\n name: string\n key: string\n description?: string\n icon?: string\n /** Used by page-type-renderers to pick a specialised React component */\n rendererKey?: string\n /** Active variant key (set per-page) */\n variant?: string\n category: 'singleton' | 'collection' | 'global'\n contentCategory: 'singleton' | 'collection' | 'global'\n allowedRoles?: string[]\n variants: CMSPageTypeVariant[]\n sections: CMSPageTypeSection[]\n}\n\n// ── Sitemap ────────────────────────────────────────────────────────────────────\n\nexport interface CMSSitemapUrl {\n loc: string\n lastmod?: string\n changefreq?: string\n priority?: number\n title?: string\n}\n\nexport interface CMSSitemapResponse {\n enabled: boolean\n urls: CMSSitemapUrl[]\n config?: {\n defaultChangeFreq?: string\n defaultPriority?: number\n }\n}\n\n// ── Status ─────────────────────────────────────────────────────────────────────\n\nexport interface CMSStatusResponse {\n appId: string\n totalPages: number\n publishedPages: number\n connected: boolean\n pages: Array<{\n slug: string\n title: string\n pageType?: string\n group?: string\n }>\n}\n\n// ── Site Structure ─────────────────────────────────────────────────────────────\n\n/**\n * @deprecated Navigation and footer menus are now managed as CMS Globals.\n * Use `cmsClient.getGlobals()` instead.\n */\nexport type CMSMenuItemType = 'page' | 'url' | 'dynamic' | 'anchor'\n\n/**\n * @deprecated Navigation and footer menus are now managed as CMS Globals.\n * Use `cmsClient.getGlobals()` instead.\n */\nexport interface CMSMenuItem {\n id: string\n type: CMSMenuItemType\n label: string\n contentId?: string\n url?: string\n /** For anchor links: the target section ID (e.g. \"features\", \"pricing\") */\n anchorTarget?: string\n /** For anchor links: the slug of the page containing the section (e.g. \"about\"). Empty string = home/current page. */\n anchorPage?: string\n /**\n * Resolved href — ready to pass to <Link href>.\n * - Same-page anchor: \"#section-id\"\n * - Cross-page anchor: \"/page-slug#section-id\"\n * - Regular link: \"/slug\" or \"https://…\"\n * Never null, falls back to \"#\".\n */\n href: string\n locked: boolean\n openInNewTab: boolean\n children: CMSMenuItem[]\n page?: {\n title?: string\n slug?: string\n seoTitle?: string\n seoDescription?: string\n }\n}\n\nexport interface CMSPageTreeNode {\n id: string\n contentId: string\n parentId: string | null\n order: number\n locked: boolean\n visible?: boolean\n page?: {\n title?: string\n slug?: string\n seoTitle?: string\n seoDescription?: string\n }\n}\n\n/**\n * @deprecated Footer columns are now managed as CMS Globals.\n * Use `cmsClient.getGlobals()` instead.\n */\nexport interface CMSFooterGroup {\n id: string\n heading: string\n headingUrl?: string\n locked: boolean\n links: CMSMenuItem[]\n}\n\nexport interface CMSSiteStructure {\n appId: string\n pageTree: CMSPageTreeNode[]\n /**\n * @deprecated Menus are no longer stored in site-structure.\n * Use `cmsClient.getGlobals()` for navigation and footer data.\n */\n menus?: {\n header: CMSMenuItem[]\n footer: CMSFooterGroup[]\n footerBottom: CMSMenuItem[]\n sidebar: CMSMenuItem[]\n [slot: string]: CMSMenuItem[] | CMSFooterGroup[]\n }\n updatedAt?: string\n}\n\n// ── Pagination & Responses ─────────────────────────────────────────────────────\n\n// v1 route returns { data, count } — flat, no nested meta object\ninterface CMSListResponse {\n data: CMSPage[]\n count: number\n appId?: string\n}\n\ninterface CMSSingleResponse {\n data: CMSPage\n}\n\n// ── Client Options ─────────────────────────────────────────────────────────────\n\nexport interface CMSClientOptions {\n /** Base URL of your Forge CMS instance, e.g. https://cms.yourschool.io */\n baseUrl?: string\n /** API key generated in CMS Admin → API Keys. Server-side only. */\n apiKey?: string\n /** App ID from CMS Admin → Apps, e.g. \"school-website\" */\n appId?: string\n}\n\nexport interface CMSGetPagesOptions {\n type?: string\n group?: string\n page?: number\n perPage?: number\n status?: 'published' | 'draft' | 'archived'\n}\n\n// ── Factory ───────────────────────────────────────────────────────────────────\n\nexport function createCMSClient(options?: CMSClientOptions) {\n /**\n * Resolve config lazily at request time — NOT at module/build time.\n * This prevents static prerendering crashes when env vars are absent during build.\n */\n function cfg() {\n return {\n baseUrl: (options?.baseUrl ?? process.env.NEXT_PUBLIC_CMS_URL ?? process.env.CMS_BASE_URL ?? '').replace(/\\/$/, ''),\n apiKey: options?.apiKey ?? process.env.CMS_API_KEY ?? '',\n appId: options?.appId ?? process.env.CMS_APP_ID ?? '',\n }\n }\n\n function headers() {\n return { 'X-CMS-API-Key': cfg().apiKey, 'Content-Type': 'application/json' }\n }\n\n // ── Pages ──────────────────────────────────────────────────────────────────\n\n async function getPages(params?: CMSGetPagesOptions): Promise<CMSPage[]> {\n const { baseUrl, apiKey, appId } = cfg()\n if (!baseUrl || !apiKey || !appId) {\n console.warn('[sprintup-cms] Missing CMS_BASE_URL / CMS_API_KEY / CMS_APP_ID — returning []')\n return []\n }\n try {\n const qs = new URLSearchParams()\n if (params?.type) qs.set('type', params.type)\n if (params?.group) qs.set('group', params.group)\n if (params?.page) qs.set('page', String(params.page))\n if (params?.perPage) qs.set('perPage', String(params.perPage))\n const url = `${baseUrl}/api/v1/${appId}/pages${qs.size ? `?${qs}` : ''}`\n const res = await fetch(url, {\n headers: headers(),\n next: { revalidate: 60, tags: [`cms-pages-${appId}`] },\n } as RequestInit)\n if (!res.ok) { console.error(`[sprintup-cms] getPages (${res.status})`); return [] }\n const json: CMSListResponse = await res.json()\n return json.data ?? []\n } catch (err) {\n console.error('[sprintup-cms] getPages error:', err)\n return []\n }\n }\n\n async function getPage(slug: string): Promise<CMSPage | null> {\n const { baseUrl, apiKey, appId } = cfg()\n if (!baseUrl || !apiKey || !appId) {\n console.warn('[sprintup-cms] Missing config — returning null')\n return null\n }\n try {\n const res = await fetch(`${baseUrl}/api/v1/${appId}/pages/${slug}`, {\n headers: headers(),\n next: { revalidate: 60, tags: [`cms-page-${slug}`, `cms-pages-${appId}`] },\n } as RequestInit)\n if (res.status === 404) return null\n if (!res.ok) { console.error(`[sprintup-cms] getPage \"${slug}\" (${res.status})`); return null }\n const json: CMSSingleResponse = await res.json()\n return json.data ?? null\n } catch (err) {\n console.error(`[sprintup-cms] getPage \"${slug}\" error:`, err)\n return null\n }\n }\n\n async function getBlogPosts(): Promise<CMSPage[]> {\n return getPages({ type: 'blog-post' })\n }\n\n async function getEvents(): Promise<CMSPage[]> {\n return getPages({ type: 'event-page' })\n }\n\n async function getAnnouncements(): Promise<CMSPage[]> {\n return getPages({ type: 'announcement-page' })\n }\n\n // ── Preview ────────────────────────────────────────────────────────────────\n\n async function getPreviewPage(token: string): Promise<CMSPage | null> {\n const { baseUrl, appId } = cfg()\n if (!baseUrl || !appId) {\n console.warn('[sprintup-cms] getPreviewPage: Missing baseUrl or appId — returning null')\n return null\n }\n try {\n const url = `${baseUrl}/api/v1/${appId}/preview?token=${encodeURIComponent(token)}`\n const res = await fetch(url, { cache: 'no-store' })\n if (!res.ok) {\n const errorText = await res.text().catch(() => '')\n console.error(`[sprintup-cms] getPreviewPage failed (${res.status}): ${errorText}`)\n return null\n }\n const json = await res.json()\n return json.data ?? null\n } catch (err) {\n console.error('[sprintup-cms] getPreviewPage error:', err)\n return null\n }\n }\n\n async function getPageWithPreview(slug: string, previewToken?: string | null): Promise<CMSPage | null> {\n if (previewToken) {\n const preview = await getPreviewPage(previewToken)\n if (preview?.slug === slug) return preview\n }\n return getPage(slug)\n }\n\n // ── Page Types ─────────────────────────────────────────────────────────────\n\n async function getPageType(pageTypeId: string): Promise<CMSPageType | null> {\n const { baseUrl, apiKey, appId } = cfg()\n if (!baseUrl || !apiKey || !appId || !pageTypeId) return null\n try {\n const res = await fetch(`${baseUrl}/api/v1/${appId}/page-types/${pageTypeId}`, {\n headers: headers(),\n next: { revalidate: 3600, tags: [`cms-page-type-${pageTypeId}`] },\n } as RequestInit)\n if (!res.ok) return null\n const json = await res.json()\n return json.data ?? null\n } catch {\n return null\n }\n }\n\n // ── Site Structure ─────────────────────────────────────────────────────────\n\n async function getSiteStructure(): Promise<CMSSiteStructure | null> {\n const { baseUrl, apiKey, appId } = cfg()\n if (!baseUrl || !apiKey || !appId) return null\n try {\n const res = await fetch(`${baseUrl}/api/v1/${appId}/site-structure`, {\n headers: headers(),\n next: {\n revalidate: 300,\n tags: [`site-structure-${appId}`],\n },\n } as RequestInit)\n if (!res.ok) return null\n const json = await res.json()\n return json.data ?? null\n } catch {\n return null\n }\n }\n\n /**\n * GET /api/v1/{appId}/sitemap\n * Fetch sitemap data for all published pages (priority, changefreq, lastmod).\n *\n * @example app/sitemap.ts\n * import type { MetadataRoute } from 'next'\n * import { cmsClient } from '@sprintup-cms/sdk'\n *\n * export default async function sitemap(): Promise<MetadataRoute.Sitemap> {\n * const data = await cmsClient.getSitemap()\n * if (!data?.enabled) return []\n * return data.urls.map(url => ({\n * url: `${process.env.NEXT_PUBLIC_SITE_URL}${url.loc}`,\n * lastModified: url.lastmod,\n * changeFrequency: url.changefreq as MetadataRoute.Sitemap[0]['changeFrequency'],\n * priority: url.priority,\n * }))\n * }\n */\n async function getSitemap(): Promise<CMSSitemapResponse | null> {\n const { baseUrl, apiKey, appId } = cfg()\n if (!baseUrl || !apiKey || !appId) return null\n try {\n const res = await fetch(`${baseUrl}/api/v1/${appId}/sitemap`, {\n headers: headers(),\n next: { revalidate: 3600 },\n } as RequestInit)\n if (!res.ok) return null\n const json = await res.json()\n return json.data ?? null\n } catch { return null }\n }\n\n /**\n * GET /api/v1/{appId}/status\n * Verify connectivity and retrieve page counts. Never cached — always fresh.\n * Useful for debugging API key setup.\n */\n async function getStatus(): Promise<CMSStatusResponse | null> {\n const { baseUrl, apiKey, appId } = cfg()\n if (!baseUrl || !apiKey || !appId) return null\n try {\n const res = await fetch(`${baseUrl}/api/v1/${appId}/status`, {\n headers: headers(),\n cache: 'no-store',\n } as RequestInit)\n if (!res.ok) return null\n return await res.json()\n } catch { return null }\n }\n\n /**\n * Resolves a raw nav item array (from globals block content) into typed CMSMenuItems.\n * Computes the `href` field from `type`, `url`, `anchorPage`, and `anchorTarget`.\n *\n * - type 'anchor' + anchorPage → \"/page-slug#section-id\"\n * - type 'anchor' + no anchorPage → \"#section-id\"\n * - type 'url' or 'link' → raw url value\n * - fallback → \"#\"\n */\n function resolveNavItems(items: any[] = []): CMSMenuItem[] {\n return items.map((item: any): CMSMenuItem => {\n let href = '#'\n if (item.type === 'anchor') {\n const anchorId = item.anchorTarget || ''\n const anchorPage = item.anchorPage || ''\n if (anchorId) {\n href = anchorPage ? `/${anchorPage}#${anchorId}` : `#${anchorId}`\n }\n } else if (item.url) {\n href = item.url\n }\n return {\n id: item.id ?? '',\n type: item.type ?? 'link',\n label: item.label ?? '',\n url: item.url,\n anchorTarget: item.anchorTarget,\n anchorPage: item.anchorPage,\n href,\n locked: item.locked ?? false,\n openInNewTab: item.openInNewTab ?? false,\n children: resolveNavItems(item.children ?? []),\n }\n })\n }\n\n async function getGlobals(): Promise<{\n navigation: CMSPage | null\n footer: CMSPage | null\n /** Pre-resolved navigation items — ready to map directly in your header component. */\n navItems: CMSMenuItem[]\n }> {\n const { baseUrl, appId } = cfg()\n if (!baseUrl || !appId) return { navigation: null, footer: null, navItems: [] }\n try {\n const res = await fetch(`${baseUrl}/api/v1/${appId}/globals`, {\n headers: headers(),\n next: { revalidate: 60, tags: [`cms-globals-${appId}`] },\n } as RequestInit)\n if (!res.ok) return { navigation: null, footer: null, navItems: [] }\n\n const json = await res.json()\n const navigation: CMSPage | null = json.data?.navigation ?? null\n\n // Nav items live in the first block's content.items array\n const rawItems = navigation?.blocks?.[0]?.content?.items\n ?? navigation?.blocks?.[0]?.data?.items\n ?? []\n\n return {\n navigation,\n footer: json.data?.footer ?? null,\n navItems: resolveNavItems(rawItems),\n }\n } catch {\n return { navigation: null, footer: null, navItems: [] }\n }\n }\n\n return {\n getPages,\n getPage,\n getGlobals,\n getBlogPosts,\n getEvents,\n getAnnouncements,\n getPreviewPage,\n getPageWithPreview,\n getPageType,\n getSiteStructure,\n getSitemap,\n getStatus,\n }\n}\n\n// ── Default singleton ─────────────────────────────────────────────────────────\n\n/** Pre-configured singleton. Reads env vars lazily at request time. */\nexport const cmsClient = createCMSClient()\n"]}
1
+ {"version":3,"sources":["../src/client.ts"],"names":[],"mappings":"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","file":"client.js","sourcesContent":["/**\n * @sprintup-cms/sdk — Core Client\n *\n * Zero-dependency, framework-agnostic typed API client for SprintUp Forge CMS.\n *\n * @example\n * import { cmsClient } from '@sprintup-cms/sdk'\n * const page = await cmsClient.getPage('about')\n *\n * @example Custom instance\n * import { createCMSClient } from '@sprintup-cms/sdk'\n * const cms = createCMSClient({ baseUrl: '...', apiKey: '...', appId: '...' })\n */\n\n// ── Types ─────────────────────────────────────────────────────────────────────\n\nexport interface CMSBlock {\n id: string\n type: string\n label?: string\n locked?: boolean\n data?: Record<string, any>\n /** Legacy field — blocks created before v1.1 used `content` instead of `data` */\n content?: Record<string, any>\n order?: number\n}\n\nexport interface CMSPage {\n _id?: string\n slug: string\n title: string\n description?: string\n pageType?: string\n pageTypeId?: string\n variant?: string\n status: 'draft' | 'published' | 'archived'\n visibility?: 'public' | 'private' | 'password'\n blocks: CMSBlock[]\n publishedAt?: string\n updatedAt?: string\n seo?: {\n title?: string\n description?: string\n keywords?: string[]\n ogImage?: string\n noIndex?: boolean\n }\n}\n\nexport interface CMSPageTypeField {\n id: string\n name: string\n label: string\n fieldType:\n | 'text' | 'textarea' | 'richtext' | 'image' | 'url'\n | 'number' | 'boolean' | 'date' | 'select' | 'relation'\n | 'email' | 'phone' | 'slug' | 'color' | 'embed'\n | 'multi-select' | 'repeater' | 'file' | 'code'\n required?: boolean\n options?: string[]\n description?: string\n maxLength?: number\n multiple?: boolean\n targetPageTypeKey?: string\n}\n\nexport interface CMSPageTypeSection {\n id: string\n name: string\n label: string\n order: number\n locked?: boolean\n fields: CMSPageTypeField[]\n}\n\nexport interface CMSPageTypeVariant {\n key: string\n label: string\n description?: string\n visibleSections?: string[]\n}\n\nexport interface CMSPageType {\n _id: string\n name: string\n key: string\n description?: string\n icon?: string\n /** Used by page-type-renderers to pick a specialised React component */\n rendererKey?: string\n /** Active variant key (set per-page) */\n variant?: string\n category: 'singleton' | 'collection' | 'global'\n contentCategory: 'singleton' | 'collection' | 'global'\n allowedRoles?: string[]\n variants: CMSPageTypeVariant[]\n sections: CMSPageTypeSection[]\n}\n\n// ── Sitemap ────────────────────────────────────────────────────────────────────\n\nexport interface CMSSitemapUrl {\n loc: string\n lastmod?: string\n changefreq?: string\n priority?: number\n title?: string\n}\n\nexport interface CMSSitemapResponse {\n enabled: boolean\n urls: CMSSitemapUrl[]\n config?: {\n defaultChangeFreq?: string\n defaultPriority?: number\n }\n}\n\n// ── Status ─────────────────────────────────────────────────────────────────────\n\nexport interface CMSStatusResponse {\n appId: string\n totalPages: number\n publishedPages: number\n connected: boolean\n pages: Array<{\n slug: string\n title: string\n pageType?: string\n group?: string\n }>\n}\n\n// ── Site Structure ─────────────────────────────────────────────────────────────\n\n/**\n * @deprecated Navigation and footer menus are now managed as CMS Globals.\n * Use `cmsClient.getGlobals()` instead.\n */\nexport type CMSMenuItemType = 'page' | 'url' | 'dynamic' | 'anchor'\n\n/**\n * @deprecated Navigation and footer menus are now managed as CMS Globals.\n * Use `cmsClient.getGlobals()` instead.\n */\nexport interface CMSMenuItem {\n id: string\n type: CMSMenuItemType\n label: string\n contentId?: string\n url?: string\n /** For anchor links: the target section ID (e.g. \"features\", \"pricing\") */\n anchorTarget?: string\n /** For anchor links: the slug of the page containing the section (e.g. \"about\"). Empty string = home/current page. */\n anchorPage?: string\n /**\n * Resolved href — ready to pass to <Link href>.\n * - Same-page anchor: \"#section-id\"\n * - Cross-page anchor: \"/page-slug#section-id\"\n * - Regular link: \"/slug\" or \"https://…\"\n * Never null, falls back to \"#\".\n */\n href: string\n locked: boolean\n openInNewTab: boolean\n children: CMSMenuItem[]\n page?: {\n title?: string\n slug?: string\n seoTitle?: string\n seoDescription?: string\n }\n}\n\nexport interface CMSPageTreeNode {\n id: string\n contentId: string\n parentId: string | null\n order: number\n locked: boolean\n visible?: boolean\n page?: {\n title?: string\n slug?: string\n seoTitle?: string\n seoDescription?: string\n }\n}\n\n/**\n * @deprecated Footer columns are now managed as CMS Globals.\n * Use `cmsClient.getGlobals()` instead.\n */\nexport interface CMSFooterGroup {\n id: string\n heading: string\n headingUrl?: string\n locked: boolean\n links: CMSMenuItem[]\n}\n\nexport interface CMSSiteStructure {\n appId: string\n pageTree: CMSPageTreeNode[]\n /**\n * @deprecated Menus are no longer stored in site-structure.\n * Use `cmsClient.getGlobals()` for navigation and footer data.\n */\n menus?: {\n header: CMSMenuItem[]\n footer: CMSFooterGroup[]\n footerBottom: CMSMenuItem[]\n sidebar: CMSMenuItem[]\n [slot: string]: CMSMenuItem[] | CMSFooterGroup[]\n }\n updatedAt?: string\n}\n\n// ── Pagination & Responses ─────────────────────────────────────────────────────\n\n// v1 route returns { data, count } — flat, no nested meta object\ninterface CMSListResponse {\n data: CMSPage[]\n count: number\n appId?: string\n}\n\ninterface CMSSingleResponse {\n data: CMSPage\n}\n\n// ── Client Options ─────────────────────────────────────────────────────────────\n\nexport interface CMSClientOptions {\n /** Base URL of your Forge CMS instance, e.g. https://cms.yourschool.io */\n baseUrl?: string\n /** API key generated in CMS Admin → API Keys. Server-side only. */\n apiKey?: string\n /** App ID from CMS Admin → Apps, e.g. \"school-website\" */\n appId?: string\n}\n\nexport interface CMSGetPagesOptions {\n type?: string\n group?: string\n page?: number\n perPage?: number\n status?: 'published' | 'draft' | 'archived'\n}\n\n// ── Nav Item Resolution ───────────────────────────────────────────────────────\n\n/**\n * Resolves a raw nav item array (from globals block content) into typed CMSMenuItems.\n * Computes the `href` field from `type`, `url`, `anchorPage`, and `anchorTarget`.\n *\n * - type 'anchor' + anchorPage → \"/page-slug#section-id\"\n * - type 'anchor' + no anchorPage → \"#section-id\"\n * - type 'url' or 'link' → raw url value\n * - fallback → \"#\"\n *\n * @example\n * import { resolveNavItems } from '@sprintup-cms/sdk'\n * const navItems = resolveNavItems(rawNavData)\n */\nexport function resolveNavItems(items: any[] = []): CMSMenuItem[] {\n return items.map((item: any): CMSMenuItem => {\n let href = '#'\n if (item.type === 'anchor') {\n const anchorId = item.anchorTarget || ''\n const anchorPage = item.anchorPage || ''\n if (anchorId) {\n href = anchorPage ? `/${anchorPage}#${anchorId}` : `#${anchorId}`\n }\n } else if (item.url) {\n href = item.url\n }\n return {\n id: item.id ?? '',\n type: item.type ?? 'link',\n label: item.label ?? '',\n url: item.url,\n anchorTarget: item.anchorTarget,\n anchorPage: item.anchorPage,\n href,\n locked: item.locked ?? false,\n openInNewTab: item.openInNewTab ?? false,\n children: resolveNavItems(item.children ?? []),\n }\n })\n}\n\n// ── Factory ───────────────────────────────────────────────────────────────────\n\nexport function createCMSClient(options?: CMSClientOptions) {\n /**\n * Resolve config lazily at request time — NOT at module/build time.\n * This prevents static prerendering crashes when env vars are absent during build.\n */\n function cfg() {\n return {\n baseUrl: (options?.baseUrl ?? process.env.NEXT_PUBLIC_CMS_URL ?? process.env.CMS_BASE_URL ?? '').replace(/\\/$/, ''),\n apiKey: options?.apiKey ?? process.env.CMS_API_KEY ?? '',\n appId: options?.appId ?? process.env.CMS_APP_ID ?? '',\n }\n }\n\n function headers() {\n return { 'X-CMS-API-Key': cfg().apiKey, 'Content-Type': 'application/json' }\n }\n\n // ── Pages ──────────────────────────────────────────────────────────────────\n\n async function getPages(params?: CMSGetPagesOptions): Promise<CMSPage[]> {\n const { baseUrl, apiKey, appId } = cfg()\n if (!baseUrl || !apiKey || !appId) {\n console.warn('[sprintup-cms] Missing CMS_BASE_URL / CMS_API_KEY / CMS_APP_ID — returning []')\n return []\n }\n try {\n const qs = new URLSearchParams()\n if (params?.type) qs.set('type', params.type)\n if (params?.group) qs.set('group', params.group)\n if (params?.page) qs.set('page', String(params.page))\n if (params?.perPage) qs.set('perPage', String(params.perPage))\n const url = `${baseUrl}/api/v1/${appId}/pages${qs.size ? `?${qs}` : ''}`\n const res = await fetch(url, {\n headers: headers(),\n next: { revalidate: 60, tags: [`cms-pages-${appId}`] },\n } as RequestInit)\n if (!res.ok) { console.error(`[sprintup-cms] getPages (${res.status})`); return [] }\n const json: CMSListResponse = await res.json()\n return json.data ?? []\n } catch (err) {\n console.error('[sprintup-cms] getPages error:', err)\n return []\n }\n }\n\n async function getPage(slug: string): Promise<CMSPage | null> {\n const { baseUrl, apiKey, appId } = cfg()\n if (!baseUrl || !apiKey || !appId) {\n console.warn('[sprintup-cms] Missing config — returning null')\n return null\n }\n try {\n const res = await fetch(`${baseUrl}/api/v1/${appId}/pages/${slug}`, {\n headers: headers(),\n next: { revalidate: 60, tags: [`cms-page-${slug}`, `cms-pages-${appId}`] },\n } as RequestInit)\n if (res.status === 404) return null\n if (!res.ok) { console.error(`[sprintup-cms] getPage \"${slug}\" (${res.status})`); return null }\n const json: CMSSingleResponse = await res.json()\n return json.data ?? null\n } catch (err) {\n console.error(`[sprintup-cms] getPage \"${slug}\" error:`, err)\n return null\n }\n }\n\n async function getBlogPosts(): Promise<CMSPage[]> {\n return getPages({ type: 'blog-post' })\n }\n\n async function getEvents(): Promise<CMSPage[]> {\n return getPages({ type: 'event-page' })\n }\n\n async function getAnnouncements(): Promise<CMSPage[]> {\n return getPages({ type: 'announcement-page' })\n }\n\n // ── Preview ────────────────────────────────────────────────────────────────\n\n async function getPreviewPage(token: string): Promise<CMSPage | null> {\n const { baseUrl, appId } = cfg()\n if (!baseUrl || !appId) {\n console.warn('[sprintup-cms] getPreviewPage: Missing baseUrl or appId — returning null')\n return null\n }\n try {\n const url = `${baseUrl}/api/v1/${appId}/preview?token=${encodeURIComponent(token)}`\n const res = await fetch(url, { cache: 'no-store' })\n if (!res.ok) {\n const errorText = await res.text().catch(() => '')\n console.error(`[sprintup-cms] getPreviewPage failed (${res.status}): ${errorText}`)\n return null\n }\n const json = await res.json()\n return json.data ?? null\n } catch (err) {\n console.error('[sprintup-cms] getPreviewPage error:', err)\n return null\n }\n }\n\n async function getPageWithPreview(slug: string, previewToken?: string | null): Promise<CMSPage | null> {\n if (previewToken) {\n const preview = await getPreviewPage(previewToken)\n if (preview?.slug === slug) return preview\n }\n return getPage(slug)\n }\n\n // ── Page Types ─────────────────────────────────────────────────────────────\n\n async function getPageType(pageTypeId: string): Promise<CMSPageType | null> {\n const { baseUrl, apiKey, appId } = cfg()\n if (!baseUrl || !apiKey || !appId || !pageTypeId) return null\n try {\n const res = await fetch(`${baseUrl}/api/v1/${appId}/page-types/${pageTypeId}`, {\n headers: headers(),\n next: { revalidate: 3600, tags: [`cms-page-type-${pageTypeId}`] },\n } as RequestInit)\n if (!res.ok) return null\n const json = await res.json()\n return json.data ?? null\n } catch {\n return null\n }\n }\n\n // ── Site Structure ─────────────────────────────────────────────────────────\n\n async function getSiteStructure(): Promise<CMSSiteStructure | null> {\n const { baseUrl, apiKey, appId } = cfg()\n if (!baseUrl || !apiKey || !appId) return null\n try {\n const res = await fetch(`${baseUrl}/api/v1/${appId}/site-structure`, {\n headers: headers(),\n next: {\n revalidate: 300,\n tags: [`site-structure-${appId}`],\n },\n } as RequestInit)\n if (!res.ok) return null\n const json = await res.json()\n return json.data ?? null\n } catch {\n return null\n }\n }\n\n /**\n * GET /api/v1/{appId}/sitemap\n * Fetch sitemap data for all published pages (priority, changefreq, lastmod).\n *\n * @example app/sitemap.ts\n * import type { MetadataRoute } from 'next'\n * import { cmsClient } from '@sprintup-cms/sdk'\n *\n * export default async function sitemap(): Promise<MetadataRoute.Sitemap> {\n * const data = await cmsClient.getSitemap()\n * if (!data?.enabled) return []\n * return data.urls.map(url => ({\n * url: `${process.env.NEXT_PUBLIC_SITE_URL}${url.loc}`,\n * lastModified: url.lastmod,\n * changeFrequency: url.changefreq as MetadataRoute.Sitemap[0]['changeFrequency'],\n * priority: url.priority,\n * }))\n * }\n */\n async function getSitemap(): Promise<CMSSitemapResponse | null> {\n const { baseUrl, apiKey, appId } = cfg()\n if (!baseUrl || !apiKey || !appId) return null\n try {\n const res = await fetch(`${baseUrl}/api/v1/${appId}/sitemap`, {\n headers: headers(),\n next: { revalidate: 3600 },\n } as RequestInit)\n if (!res.ok) return null\n const json = await res.json()\n return json.data ?? null\n } catch { return null }\n }\n\n /**\n * GET /api/v1/{appId}/status\n * Verify connectivity and retrieve page counts. Never cached — always fresh.\n * Useful for debugging API key setup.\n */\n async function getStatus(): Promise<CMSStatusResponse | null> {\n const { baseUrl, apiKey, appId } = cfg()\n if (!baseUrl || !apiKey || !appId) return null\n try {\n const res = await fetch(`${baseUrl}/api/v1/${appId}/status`, {\n headers: headers(),\n cache: 'no-store',\n } as RequestInit)\n if (!res.ok) return null\n return await res.json()\n } catch { return null }\n }\n\n async function getGlobals(): Promise<{\n navigation: CMSPage | null\n footer: CMSPage | null\n /** Pre-resolved navigation items — ready to map directly in your header component. */\n navItems: CMSMenuItem[]\n }> {\n const { baseUrl, appId } = cfg()\n if (!baseUrl || !appId) return { navigation: null, footer: null, navItems: [] }\n try {\n const res = await fetch(`${baseUrl}/api/v1/${appId}/globals`, {\n headers: headers(),\n next: { revalidate: 60, tags: [`cms-globals-${appId}`] },\n } as RequestInit)\n if (!res.ok) return { navigation: null, footer: null, navItems: [] }\n\n const json = await res.json()\n const navigation: CMSPage | null = json.data?.navigation ?? null\n\n // Nav items live in the first block's content.items array\n const rawItems = navigation?.blocks?.[0]?.content?.items\n ?? navigation?.blocks?.[0]?.data?.items\n ?? []\n\n return {\n navigation,\n footer: json.data?.footer ?? null,\n navItems: resolveNavItems(rawItems),\n }\n } catch {\n return { navigation: null, footer: null, navItems: [] }\n }\n }\n\n return {\n getPages,\n getPage,\n getGlobals,\n getBlogPosts,\n getEvents,\n getAnnouncements,\n getPreviewPage,\n getPageWithPreview,\n getPageType,\n getSiteStructure,\n getSitemap,\n getStatus,\n }\n}\n\n// ── Default singleton ─────────────────────────────────────────────────────────\n\n/** Pre-configured singleton. Reads env vars lazily at request time. */\nexport const cmsClient = createCMSClient()\n"]}
package/dist/index.cjs CHANGED
@@ -3,6 +3,32 @@
3
3
  /* @sprintup-cms/sdk — https://forgecms.io */
4
4
 
5
5
  // src/client.ts
6
+ function resolveNavItems(items = []) {
7
+ return items.map((item) => {
8
+ let href = "#";
9
+ if (item.type === "anchor") {
10
+ const anchorId = item.anchorTarget || "";
11
+ const anchorPage = item.anchorPage || "";
12
+ if (anchorId) {
13
+ href = anchorPage ? `/${anchorPage}#${anchorId}` : `#${anchorId}`;
14
+ }
15
+ } else if (item.url) {
16
+ href = item.url;
17
+ }
18
+ return {
19
+ id: item.id ?? "",
20
+ type: item.type ?? "link",
21
+ label: item.label ?? "",
22
+ url: item.url,
23
+ anchorTarget: item.anchorTarget,
24
+ anchorPage: item.anchorPage,
25
+ href,
26
+ locked: item.locked ?? false,
27
+ openInNewTab: item.openInNewTab ?? false,
28
+ children: resolveNavItems(item.children ?? [])
29
+ };
30
+ });
31
+ }
6
32
  function createCMSClient(options) {
7
33
  function cfg() {
8
34
  return {
@@ -164,32 +190,6 @@ function createCMSClient(options) {
164
190
  return null;
165
191
  }
166
192
  }
167
- function resolveNavItems(items = []) {
168
- return items.map((item) => {
169
- let href = "#";
170
- if (item.type === "anchor") {
171
- const anchorId = item.anchorTarget || "";
172
- const anchorPage = item.anchorPage || "";
173
- if (anchorId) {
174
- href = anchorPage ? `/${anchorPage}#${anchorId}` : `#${anchorId}`;
175
- }
176
- } else if (item.url) {
177
- href = item.url;
178
- }
179
- return {
180
- id: item.id ?? "",
181
- type: item.type ?? "link",
182
- label: item.label ?? "",
183
- url: item.url,
184
- anchorTarget: item.anchorTarget,
185
- anchorPage: item.anchorPage,
186
- href,
187
- locked: item.locked ?? false,
188
- openInNewTab: item.openInNewTab ?? false,
189
- children: resolveNavItems(item.children ?? [])
190
- };
191
- });
192
- }
193
193
  async function getGlobals() {
194
194
  const { baseUrl, appId } = cfg();
195
195
  if (!baseUrl || !appId) return { navigation: null, footer: null, navItems: [] };
@@ -230,5 +230,6 @@ var cmsClient = createCMSClient();
230
230
 
231
231
  exports.cmsClient = cmsClient;
232
232
  exports.createCMSClient = createCMSClient;
233
+ exports.resolveNavItems = resolveNavItems;
233
234
  //# sourceMappingURL=index.cjs.map
234
235
  //# sourceMappingURL=index.cjs.map