@riverbankcms/sdk 0.6.1 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client/client.js +1 -1
- package/dist/client/client.js.map +1 -1
- package/dist/client/client.mjs +1 -1
- package/dist/client/client.mjs.map +1 -1
- package/dist/server/{chunk-Z5ZA6Q4D.mjs → chunk-74XUVNOO.mjs} +5 -3
- package/dist/server/chunk-74XUVNOO.mjs.map +1 -0
- package/dist/server/{chunk-3B364WO2.js → chunk-7BVRA5MY.js} +4 -49
- package/dist/server/chunk-7BVRA5MY.js.map +1 -0
- package/dist/server/{chunk-I7ZR2WO3.mjs → chunk-7FIJSGHU.mjs} +2 -2
- package/dist/server/{chunk-I7ZR2WO3.mjs.map → chunk-7FIJSGHU.mjs.map} +1 -1
- package/dist/server/chunk-ARNCLSQT.mjs +52 -0
- package/dist/server/chunk-ARNCLSQT.mjs.map +1 -0
- package/dist/server/chunk-BNQV3PXP.js +69 -0
- package/dist/server/chunk-BNQV3PXP.js.map +1 -0
- package/dist/server/{chunk-I2D7KOEA.js → chunk-JWRNMNWI.js} +5 -3
- package/dist/server/chunk-JWRNMNWI.js.map +1 -0
- package/dist/server/{chunk-IVHIQFJH.js → chunk-P7UVAMK6.js} +2 -2
- package/dist/server/{chunk-IVHIQFJH.js.map → chunk-P7UVAMK6.js.map} +1 -1
- package/dist/server/{chunk-XXFF4RVR.mjs → chunk-RBJFXNDM.mjs} +1 -46
- package/dist/server/chunk-RBJFXNDM.mjs.map +1 -0
- package/dist/server/chunk-SWYWZT3L.mjs +69 -0
- package/dist/server/chunk-SWYWZT3L.mjs.map +1 -0
- package/dist/server/chunk-T26N3P26.js +52 -0
- package/dist/server/chunk-T26N3P26.js.map +1 -0
- package/dist/server/components.js +5 -3
- package/dist/server/components.js.map +1 -1
- package/dist/server/components.mjs +5 -3
- package/dist/server/index-BTwWvSBu.d.ts +130 -0
- package/dist/server/index-DI_qlYx3.d.mts +130 -0
- package/dist/server/index.js +2 -2
- package/dist/server/index.mjs +1 -1
- package/dist/server/{loadContent-BS-3wesN.d.mts → loadContent-C-YYUKQa.d.mts} +10 -2
- package/dist/server/{loadContent-Buvmudee.d.ts → loadContent-DmgpFcFC.d.ts} +10 -2
- package/dist/server/metadata.d.mts +8 -135
- package/dist/server/metadata.d.ts +8 -135
- package/dist/server/metadata.js +5 -65
- package/dist/server/metadata.js.map +1 -1
- package/dist/server/metadata.mjs +4 -64
- package/dist/server/metadata.mjs.map +1 -1
- package/dist/server/next.d.mts +274 -0
- package/dist/server/next.d.ts +274 -0
- package/dist/server/next.js +150 -0
- package/dist/server/next.js.map +1 -0
- package/dist/server/next.mjs +150 -0
- package/dist/server/next.mjs.map +1 -0
- package/dist/server/rendering/server.js +5 -3
- package/dist/server/rendering/server.js.map +1 -1
- package/dist/server/rendering/server.mjs +5 -3
- package/dist/server/rendering.d.mts +1 -1
- package/dist/server/rendering.d.ts +1 -1
- package/dist/server/rendering.js +6 -4
- package/dist/server/rendering.js.map +1 -1
- package/dist/server/rendering.mjs +6 -4
- package/dist/server/server.d.mts +1 -1
- package/dist/server/server.d.ts +1 -1
- package/dist/server/server.js +3 -3
- package/dist/server/server.mjs +2 -2
- package/package.json +13 -1
- package/dist/server/chunk-3B364WO2.js.map +0 -1
- package/dist/server/chunk-I2D7KOEA.js.map +0 -1
- package/dist/server/chunk-XXFF4RVR.mjs.map +0 -1
- package/dist/server/chunk-Z5ZA6Q4D.mjs.map +0 -1
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import {
|
|
2
|
+
PageRenderer,
|
|
3
|
+
buildThemeRuntime
|
|
4
|
+
} from "./chunk-LNOUXALA.mjs";
|
|
5
|
+
|
|
6
|
+
// src/rendering/components/Page.tsx
|
|
7
|
+
import { jsx } from "react/jsx-runtime";
|
|
8
|
+
function Page({
|
|
9
|
+
page,
|
|
10
|
+
theme,
|
|
11
|
+
themeTokens: providedTokens,
|
|
12
|
+
siteId,
|
|
13
|
+
resolvedData,
|
|
14
|
+
routeMap,
|
|
15
|
+
wrapBlock,
|
|
16
|
+
registry,
|
|
17
|
+
usePlaceholders = false,
|
|
18
|
+
blockOverrides,
|
|
19
|
+
sdkConfig,
|
|
20
|
+
supabaseUrl,
|
|
21
|
+
dataContext
|
|
22
|
+
}) {
|
|
23
|
+
const baseTokens = providedTokens ?? buildThemeRuntime(theme).tokens;
|
|
24
|
+
const themeTokens = sdkConfig?.theme?.palette ? { ...baseTokens, palette: { ...baseTokens.palette, ...sdkConfig.theme.palette } } : baseTokens;
|
|
25
|
+
return /* @__PURE__ */ jsx(
|
|
26
|
+
PageRenderer,
|
|
27
|
+
{
|
|
28
|
+
theme,
|
|
29
|
+
page,
|
|
30
|
+
themeTokens,
|
|
31
|
+
usePlaceholders,
|
|
32
|
+
dataContext: {
|
|
33
|
+
siteId,
|
|
34
|
+
resolvedData,
|
|
35
|
+
routes: routeMap,
|
|
36
|
+
occurrenceContext: dataContext?.occurrenceContext ?? null,
|
|
37
|
+
contentEntry: dataContext?.contentEntry ?? null,
|
|
38
|
+
supabaseUrl
|
|
39
|
+
},
|
|
40
|
+
routeMap,
|
|
41
|
+
wrapBlock,
|
|
42
|
+
registry,
|
|
43
|
+
blockOverrides,
|
|
44
|
+
sdkConfig
|
|
45
|
+
}
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export {
|
|
50
|
+
Page
|
|
51
|
+
};
|
|
52
|
+
//# sourceMappingURL=chunk-ARNCLSQT.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/rendering/components/Page.tsx"],"sourcesContent":["/**\n * Pure Page renderer component for Riverbank CMS.\n *\n * This component expects all data to be provided via props.\n * For data fetching, use:\n * - Server-side: `await loadPage({ client, siteId, path })`\n * - Client-side: `usePage({ client, siteId, path })`\n */\n\nimport { PageRenderer, buildThemeRuntime } from '@riverbankcms/blocks';\nimport type { PageOutline, RouteMap, Theme, ThemeTokens, BlockOverrides, OccurrenceContextData } from '@riverbankcms/blocks';\nimport type { ResolvedBlockData } from '../../data';\nimport type { RuntimeSdkConfig } from '../helpers/loadPage';\n\n// Re-export OccurrenceContextData for SDK consumers\nexport type { OccurrenceContextData };\n\nexport type PageProps = {\n // Required data (must be provided by caller)\n page: PageOutline;\n theme: Theme;\n siteId: string;\n\n // Optional data\n themeTokens?: ThemeTokens; // If not provided, will be built from theme\n resolvedData?: ResolvedBlockData; // Pre-fetched block data\n routeMap?: RouteMap;\n /**\n * SDK site configuration containing theme palette overrides.\n * When provided, the SDK palette tokens are merged into the theme tokens,\n * allowing blocks to use SDK-defined color tokens for section backgrounds.\n */\n sdkConfig?: RuntimeSdkConfig | null;\n /**\n * Supabase storage URL for direct image access.\n * SDK sites receive this from the API instead of requiring NEXT_PUBLIC_SUPABASE_URL env var.\n */\n supabaseUrl?: string;\n\n /**\n * Additional context data for content entry pages.\n * Used to pass occurrence context and content entry data to blocks.\n */\n dataContext?: {\n /** Occurrence context for event pages (from URL like /events/yoga/2025-01-15) */\n occurrenceContext?: OccurrenceContextData | null;\n /** Content entry data for template pages */\n contentEntry?: Record<string, unknown> | null;\n };\n\n // Customization\n wrapBlock?: (blockId: string, rendered: React.ReactNode) => React.ReactNode;\n registry?: Parameters<typeof PageRenderer>[0]['registry'];\n usePlaceholders?: boolean;\n /**\n * Custom components to override default block rendering.\n * Keys can be full block kind (\"block.hero\") or short form (\"hero\").\n *\n * This is SSR-safe - no context or hooks required.\n *\n * @example\n * ```tsx\n * <Page\n * {...pageData}\n * blockOverrides={{\n * 'hero': MyCustomHero,\n * 'block.testimonials': MyCustomTestimonials,\n * }}\n * />\n * ```\n */\n blockOverrides?: BlockOverrides;\n};\n\n/**\n * Pure renderer for Riverbank CMS pages.\n *\n * This component expects all data to be provided via props.\n * For data fetching, use:\n * - Server-side: `await loadPage({ client, siteId, path })`\n * - Client-side: `usePage({ client, siteId, path })`\n *\n * @example Server-side (Next.js App Router)\n * ```tsx\n * import { createRiverbankClient } from '@riverbankcms/sdk';\n * import { loadPage, Page } from '@riverbankcms/sdk/rendering';\n *\n * const client = createRiverbankClient({ apiKey, baseUrl });\n *\n * export default async function PageRoute({ params }) {\n * const pageData = await loadPage({\n * client,\n * siteId: 'site-id',\n * path: `/${params.slug}`,\n * });\n *\n * return <Page {...pageData} />;\n * }\n * ```\n *\n * @example Client-side\n * ```tsx\n * import { createRiverbankClient } from '@riverbankcms/sdk';\n * import { usePage, Page } from '@riverbankcms/sdk/rendering';\n *\n * const client = createRiverbankClient({ apiKey, baseUrl });\n *\n * function MyPage({ path }) {\n * const pageData = usePage({ client, siteId: 'site-id', path });\n *\n * if (pageData.loading) return <LoadingState />;\n * if (pageData.error) return <ErrorState error={pageData.error} />;\n * if (!pageData.page) return <NotFound />;\n *\n * return <Page {...pageData} />;\n * }\n * ```\n */\nexport function Page({\n page,\n theme,\n themeTokens: providedTokens,\n siteId,\n resolvedData,\n routeMap,\n wrapBlock,\n registry,\n usePlaceholders = false,\n blockOverrides,\n sdkConfig,\n supabaseUrl,\n dataContext,\n}: PageProps) {\n // Build theme tokens if not provided\n const baseTokens = providedTokens ?? buildThemeRuntime(theme).tokens;\n\n // Merge SDK palette tokens into theme tokens\n // This allows blocks to resolve SDK-defined color tokens (e.g., 'primary' -> '#6d28d9')\n const themeTokens = sdkConfig?.theme?.palette\n ? { ...baseTokens, palette: { ...baseTokens.palette, ...sdkConfig.theme.palette } }\n : baseTokens;\n\n return (\n <PageRenderer\n theme={theme}\n page={page}\n themeTokens={themeTokens}\n usePlaceholders={usePlaceholders}\n dataContext={{\n siteId,\n resolvedData,\n routes: routeMap,\n occurrenceContext: dataContext?.occurrenceContext ?? null,\n contentEntry: dataContext?.contentEntry ?? null,\n supabaseUrl,\n }}\n routeMap={routeMap}\n wrapBlock={wrapBlock}\n registry={registry}\n blockOverrides={blockOverrides}\n sdkConfig={sdkConfig}\n />\n );\n}\n"],"mappings":";;;;;;AA+II;AAzBG,SAAS,KAAK;AAAA,EACnB;AAAA,EACA;AAAA,EACA,aAAa;AAAA,EACb;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,kBAAkB;AAAA,EAClB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAc;AAEZ,QAAM,aAAa,kBAAkB,kBAAkB,KAAK,EAAE;AAI9D,QAAM,cAAc,WAAW,OAAO,UAClC,EAAE,GAAG,YAAY,SAAS,EAAE,GAAG,WAAW,SAAS,GAAG,UAAU,MAAM,QAAQ,EAAE,IAChF;AAEJ,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,aAAa;AAAA,QACX;AAAA,QACA;AAAA,QACA,QAAQ;AAAA,QACR,mBAAmB,aAAa,qBAAqB;AAAA,QACrD,cAAc,aAAa,gBAAgB;AAAA,QAC3C;AAAA,MACF;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,EACF;AAEJ;","names":[]}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }// src/metadata/generatePageMetadata.ts
|
|
2
|
+
function generatePageMetadata(input) {
|
|
3
|
+
const { page, site, path, siteUrl, overrides, googleSiteVerification } = input;
|
|
4
|
+
const pageTitle = _nullishCoalesce(_optionalChain([overrides, 'optionalAccess', _ => _.title]), () => ( page.name));
|
|
5
|
+
const fullTitle = pageTitle === site.title ? pageTitle : `${pageTitle} | ${site.title}`;
|
|
6
|
+
const description = _nullishCoalesce(_optionalChain([overrides, 'optionalAccess', _2 => _2.description]), () => ( page.purpose));
|
|
7
|
+
const canonicalUrl = _nullishCoalesce(_optionalChain([overrides, 'optionalAccess', _3 => _3.canonicalUrl]), () => ( `${siteUrl}${path}`));
|
|
8
|
+
const fullUrl = `${siteUrl}${path}`;
|
|
9
|
+
const metadata = {
|
|
10
|
+
title: fullTitle,
|
|
11
|
+
description: _nullishCoalesce(description, () => ( void 0)),
|
|
12
|
+
alternates: {
|
|
13
|
+
canonical: canonicalUrl
|
|
14
|
+
},
|
|
15
|
+
openGraph: {
|
|
16
|
+
title: pageTitle,
|
|
17
|
+
description: _nullishCoalesce(description, () => ( void 0)),
|
|
18
|
+
url: fullUrl,
|
|
19
|
+
siteName: site.title,
|
|
20
|
+
type: "website",
|
|
21
|
+
..._optionalChain([overrides, 'optionalAccess', _4 => _4.ogImage]) ? {
|
|
22
|
+
images: [
|
|
23
|
+
{
|
|
24
|
+
url: overrides.ogImage,
|
|
25
|
+
alt: pageTitle
|
|
26
|
+
}
|
|
27
|
+
]
|
|
28
|
+
} : {}
|
|
29
|
+
},
|
|
30
|
+
twitter: {
|
|
31
|
+
card: "summary_large_image",
|
|
32
|
+
title: pageTitle,
|
|
33
|
+
description: _nullishCoalesce(description, () => ( void 0)),
|
|
34
|
+
..._optionalChain([overrides, 'optionalAccess', _5 => _5.ogImage]) ? {
|
|
35
|
+
images: [overrides.ogImage]
|
|
36
|
+
} : {}
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
if (_optionalChain([overrides, 'optionalAccess', _6 => _6.robots])) {
|
|
40
|
+
metadata.robots = {
|
|
41
|
+
index: _nullishCoalesce(overrides.robots.index, () => ( true)),
|
|
42
|
+
follow: _nullishCoalesce(overrides.robots.follow, () => ( true))
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
if (googleSiteVerification) {
|
|
46
|
+
metadata.verification = {
|
|
47
|
+
google: googleSiteVerification
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
return metadata;
|
|
51
|
+
}
|
|
52
|
+
function generatePreviewMetadata(input) {
|
|
53
|
+
return generatePageMetadata({
|
|
54
|
+
...input,
|
|
55
|
+
overrides: {
|
|
56
|
+
...input.overrides,
|
|
57
|
+
robots: {
|
|
58
|
+
index: false,
|
|
59
|
+
follow: false
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
exports.generatePageMetadata = generatePageMetadata; exports.generatePreviewMetadata = generatePreviewMetadata;
|
|
69
|
+
//# sourceMappingURL=chunk-BNQV3PXP.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/Users/will/Projects/Business/cms/builder/packages/sdk/dist/server/chunk-BNQV3PXP.js","../../src/metadata/generatePageMetadata.ts"],"names":[],"mappings":"AAAA;ACgHO,SAAS,oBAAA,CAAqB,KAAA,EAAoC;AACvE,EAAA,MAAM,EAAE,IAAA,EAAM,IAAA,EAAM,IAAA,EAAM,OAAA,EAAS,SAAA,EAAW,uBAAuB,EAAA,EAAI,KAAA;AAGzE,EAAA,MAAM,UAAA,mCAAY,SAAA,2BAAW,OAAA,UAAS,IAAA,CAAK,MAAA;AAC3C,EAAA,MAAM,UAAA,EAAY,UAAA,IAAc,IAAA,CAAK,MAAA,EAAQ,UAAA,EAAY,CAAA,EAAA;AAGN,EAAA;AAGO,EAAA;AACzB,EAAA;AAGN,EAAA;AAClB,IAAA;AACqB,IAAA;AAChB,IAAA;AACC,MAAA;AACb,IAAA;AACW,IAAA;AACF,MAAA;AACqB,MAAA;AACvB,MAAA;AACU,MAAA;AACT,MAAA;AAEF,MAAA;AACU,QAAA;AACN,UAAA;AACiB,YAAA;AACV,YAAA;AACP,UAAA;AACF,QAAA;AAED,MAAA;AACP,IAAA;AACS,IAAA;AACD,MAAA;AACC,MAAA;AACqB,MAAA;AAExB,MAAA;AAC4B,QAAA;AAE3B,MAAA;AACP,IAAA;AACF,EAAA;AAGuB,EAAA;AACH,IAAA;AACiB,MAAA;AACE,MAAA;AACrC,IAAA;AACF,EAAA;AAG4B,EAAA;AACF,IAAA;AACd,MAAA;AACV,IAAA;AACF,EAAA;AAEO,EAAA;AACT;AAuB4E;AAC9C,EAAA;AACvB,IAAA;AACQ,IAAA;AACA,MAAA;AACD,MAAA;AACC,QAAA;AACC,QAAA;AACV,MAAA;AACF,IAAA;AACD,EAAA;AACH;ADrJ4D;AACA;AACA;AACA;AACA","file":"/Users/will/Projects/Business/cms/builder/packages/sdk/dist/server/chunk-BNQV3PXP.js","sourcesContent":[null,"/**\n * Metadata generation helper for Next.js pages\n *\n * Generates SEO-optimized metadata from Builder page data for use in\n * Next.js generateMetadata() functions.\n */\n\nimport type { LoadPageResult } from '../rendering/helpers/loadPage';\nimport type { SiteResponse } from '../client/types';\n\n/**\n * Next.js Metadata type\n * Simplified version to avoid requiring Next.js as a dependency\n */\nexport type Metadata = {\n title?: string;\n description?: string;\n alternates?: {\n canonical?: string;\n };\n openGraph?: {\n title?: string;\n description?: string;\n url?: string;\n siteName?: string;\n type?: string;\n images?: Array<{\n url: string;\n alt?: string;\n }>;\n };\n twitter?: {\n card?: string;\n title?: string;\n description?: string;\n images?: string[];\n };\n robots?: {\n index?: boolean;\n follow?: boolean;\n };\n verification?: {\n google?: string;\n };\n};\n\nexport type PageMetadataInput = {\n /**\n * Page data from loadPage() or custom page object\n */\n page: LoadPageResult['page'] | {\n name: string;\n purpose?: string;\n };\n\n /**\n * Site data from client.getSite()\n */\n site: SiteResponse['site'];\n\n /**\n * Current URL path (e.g., '/about', '/blog/post-1')\n */\n path: string;\n\n /**\n * Full site URL for canonical and OG URLs\n * Example: 'https://example.com'\n */\n siteUrl: string;\n\n /**\n * Optional custom metadata overrides\n */\n overrides?: {\n title?: string;\n description?: string;\n ogImage?: string;\n canonicalUrl?: string;\n robots?: {\n index?: boolean;\n follow?: boolean;\n };\n };\n\n /**\n * Optional Google site verification token\n */\n googleSiteVerification?: string;\n};\n\n/**\n * Generate Next.js Metadata object from Builder page data\n *\n * @example\n * ```tsx\n * import { generatePageMetadata } from '@riverbankcms/sdk/metadata';\n * import { loadPage } from '@riverbankcms/sdk';\n *\n * export async function generateMetadata({ params }) {\n * const pageData = await loadPage({ client, siteId, path: params.slug });\n * const siteData = await client.getSite({ id: siteId });\n *\n * return generatePageMetadata({\n * page: pageData.page,\n * site: siteData.site,\n * path: params.slug,\n * siteUrl: 'https://example.com',\n * });\n * }\n * ```\n */\nexport function generatePageMetadata(input: PageMetadataInput): Metadata {\n const { page, site, path, siteUrl, overrides, googleSiteVerification } = input;\n\n // Build page title\n const pageTitle = overrides?.title ?? page.name;\n const fullTitle = pageTitle === site.title ? pageTitle : `${pageTitle} | ${site.title}`;\n\n // Use page purpose as description fallback\n const description = overrides?.description ?? page.purpose;\n\n // Build full URLs\n const canonicalUrl = overrides?.canonicalUrl ?? `${siteUrl}${path}`;\n const fullUrl = `${siteUrl}${path}`;\n\n // Build metadata object\n const metadata: Metadata = {\n title: fullTitle,\n description: description ?? undefined,\n alternates: {\n canonical: canonicalUrl,\n },\n openGraph: {\n title: pageTitle,\n description: description ?? undefined,\n url: fullUrl,\n siteName: site.title,\n type: 'website',\n ...(overrides?.ogImage\n ? {\n images: [\n {\n url: overrides.ogImage,\n alt: pageTitle,\n },\n ],\n }\n : {}),\n },\n twitter: {\n card: 'summary_large_image',\n title: pageTitle,\n description: description ?? undefined,\n ...(overrides?.ogImage\n ? {\n images: [overrides.ogImage],\n }\n : {}),\n },\n };\n\n // Add robots meta if specified\n if (overrides?.robots) {\n metadata.robots = {\n index: overrides.robots.index ?? true,\n follow: overrides.robots.follow ?? true,\n };\n }\n\n // Add Google site verification if provided\n if (googleSiteVerification) {\n metadata.verification = {\n google: googleSiteVerification,\n };\n }\n\n return metadata;\n}\n\n/**\n * Generate metadata for preview/staging environments\n *\n * This helper adds noindex/nofollow robots tags to prevent search engines\n * from indexing preview or staging URLs.\n *\n * @example\n * ```tsx\n * export async function generateMetadata({ params }) {\n * const pageData = await loadPage({ client, siteId, path: params.slug });\n * const isPreview = process.env.VERCEL_ENV !== 'production';\n *\n * return generatePreviewMetadata({\n * page: pageData.page,\n * site: siteData.site,\n * path: params.slug,\n * siteUrl: 'https://example.com',\n * });\n * }\n * ```\n */\nexport function generatePreviewMetadata(input: PageMetadataInput): Metadata {\n return generatePageMetadata({\n ...input,\n overrides: {\n ...input.overrides,\n robots: {\n index: false,\n follow: false,\n },\n },\n });\n}\n"]}
|
|
@@ -45,7 +45,8 @@ async function loadContent(params) {
|
|
|
45
45
|
resolvedData: resolvedData2,
|
|
46
46
|
dataContext: { contentEntry: entry.content },
|
|
47
47
|
theme: site.theme,
|
|
48
|
-
siteId
|
|
48
|
+
siteId,
|
|
49
|
+
site: site.site
|
|
49
50
|
};
|
|
50
51
|
}
|
|
51
52
|
const { page: pageData } = contentResponse;
|
|
@@ -70,7 +71,8 @@ async function loadContent(params) {
|
|
|
70
71
|
page: pageOutline,
|
|
71
72
|
theme: site.theme,
|
|
72
73
|
siteId,
|
|
73
|
-
resolvedData
|
|
74
|
+
resolvedData,
|
|
75
|
+
site: site.site
|
|
74
76
|
};
|
|
75
77
|
}
|
|
76
78
|
function isEntryResponse(response) {
|
|
@@ -137,4 +139,4 @@ async function processEntryTemplate(templates, entry, context, client) {
|
|
|
137
139
|
|
|
138
140
|
|
|
139
141
|
exports.isPageContent = isPageContent; exports.isEntryContent = isEntryContent; exports.loadContent = loadContent;
|
|
140
|
-
//# sourceMappingURL=chunk-
|
|
142
|
+
//# sourceMappingURL=chunk-JWRNMNWI.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/Users/will/Projects/Business/cms/builder/packages/sdk/dist/server/chunk-JWRNMNWI.js","../../src/rendering/helpers/loadContent.ts"],"names":["resolvedData"],"mappings":"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","file":"/Users/will/Projects/Business/cms/builder/packages/sdk/dist/server/chunk-JWRNMNWI.js","sourcesContent":[null,"/**\n * Server-side helper to fetch content (page or entry) by path.\n *\n * Use this for dynamic routing where a path could resolve to either\n * a page or a content entry.\n */\n\nimport type { Theme } from '@riverbankcms/blocks';\nimport type { RiverbankClient, PageResponse, SiteResponse } from '../../client/types';\nimport type { PageProps } from '../components/Page';\nimport { prefetchBlockData } from '../../data/prefetchBlockData';\nimport type { ResolvedBlockData } from '../../data/prefetchBlockData';\n\n/**\n * Site data included in content results for metadata generation.\n */\nexport type SiteData = SiteResponse['site'];\n\nexport type LoadContentParams = {\n client: RiverbankClient;\n siteId: string;\n path: string;\n /**\n * If true, fetches draft/unpublished content instead of published content.\n * This affects both pages and entries.\n * Requires API key with site access.\n *\n * @default false\n */\n preview?: boolean;\n};\n\n/**\n * Content entry data returned when a path resolves to an entry\n */\nexport type ContentEntryData = {\n id: string;\n /** Content type key (e.g., 'blog-post', 'product') */\n type: string | null;\n title: string;\n slug: string | null;\n path: string | null;\n status: string;\n publishAt: string | null;\n /** The raw content fields - use these to render your own UI */\n content: Record<string, unknown>;\n metaTitle: string | null;\n metaDescription: string | null;\n createdAt: string;\n updatedAt: string;\n};\n\n/**\n * Result when path resolves to a page\n */\nexport type PageContentResult = {\n type: 'page';\n /** Page outline ready for rendering with <Page> component */\n page: PageProps['page'];\n /** Site theme for styling */\n theme: Theme;\n /** Site ID */\n siteId: string;\n /** Pre-fetched block data for data loaders */\n resolvedData: ResolvedBlockData;\n /** Site data for metadata generation */\n site: SiteData;\n};\n\n/**\n * Result when path resolves to a content entry\n */\nexport type EntryContentResult = {\n type: 'entry';\n /** Raw entry data - render this however you want */\n entry: ContentEntryData;\n /** Template page for rendering the entry (if available) */\n templatePage: PageProps['page'] | null;\n /** Pre-fetched block data for template page data loaders */\n resolvedData: ResolvedBlockData;\n /** Data context for template blocks (includes entry content for bindings) */\n dataContext: { contentEntry: Record<string, unknown> };\n /** Site theme for styling (useful if rendering with SDK components) */\n theme: Theme;\n /** Site ID */\n siteId: string;\n /** Site data for metadata generation */\n site: SiteData;\n};\n\n/**\n * Discriminated union result from loadContent\n */\nexport type LoadContentResult = PageContentResult | EntryContentResult;\n\n/**\n * Type guard to check if result is a page\n */\nexport function isPageContent(result: LoadContentResult): result is PageContentResult {\n return result.type === 'page';\n}\n\n/**\n * Type guard to check if result is an entry\n */\nexport function isEntryContent(result: LoadContentResult): result is EntryContentResult {\n return result.type === 'entry';\n}\n\n/**\n * Server-side helper to fetch content by path.\n *\n * Returns a discriminated union - either page data (ready for `<Page>` component)\n * or raw entry data (for custom rendering).\n *\n * @example Dynamic routing with both pages and entries\n * ```tsx\n * import { loadContent, Page, isPageContent } from '@riverbankcms/sdk';\n *\n * export default async function DynamicRoute({ params }) {\n * const content = await loadContent({\n * client,\n * siteId: 'site-123',\n * path: `/${params.slug?.join('/') || ''}`,\n * });\n *\n * if (isPageContent(content)) {\n * return <Page {...content} />;\n * }\n *\n * // Render entry with custom UI\n * return (\n * <article>\n * <h1>{content.entry.title}</h1>\n * <div>{content.entry.content.body}</div>\n * </article>\n * );\n * }\n * ```\n *\n * @example Entry-specific rendering based on content type\n * ```tsx\n * const content = await loadContent({ client, siteId, path });\n *\n * if (content.type === 'entry') {\n * switch (content.entry.type) {\n * case 'blog-post':\n * return <BlogPost entry={content.entry} theme={content.theme} />;\n * case 'product':\n * return <ProductPage entry={content.entry} theme={content.theme} />;\n * default:\n * return <GenericEntry entry={content.entry} />;\n * }\n * }\n *\n * return <Page {...content} />;\n * ```\n *\n * @example Preview mode for draft content\n * ```tsx\n * const content = await loadContent({\n * client,\n * siteId,\n * path,\n * preview: true, // Fetches draft content for both pages and entries\n * });\n * ```\n */\nexport async function loadContent(params: LoadContentParams): Promise<LoadContentResult> {\n const { client, siteId, path, preview = false } = params;\n\n // Fetch site and content in parallel\n const [site, contentResponse] = await Promise.all([\n client.getSite({ id: siteId }),\n client.getPage({ siteId, path, preview }),\n ]);\n\n // Check if response is an entry\n if (isEntryResponse(contentResponse)) {\n const entryData = contentResponse.entry;\n\n const entry: ContentEntryData = {\n id: entryData.id,\n type: entryData.type,\n title: entryData.title,\n slug: entryData.slug,\n path: entryData.path,\n status: entryData.status,\n publishAt: entryData.publishAt,\n // Use draft content in preview mode, otherwise use published content\n content: preview\n ? (entryData.draftContent ?? entryData.content)\n : entryData.content,\n metaTitle: preview\n ? (entryData.draftMetaTitle ?? entryData.metaTitle)\n : entryData.metaTitle,\n metaDescription: preview\n ? (entryData.draftMetaDescription ?? entryData.metaDescription)\n : entryData.metaDescription,\n createdAt: entryData.createdAt,\n updatedAt: entryData.updatedAt,\n };\n\n // Process template if available (uses first template from content type)\n const { templatePage, resolvedData } = await processEntryTemplate(\n contentResponse.templates as Template[] | undefined,\n entry,\n { siteId, preview },\n client\n );\n\n return {\n type: 'entry',\n entry,\n templatePage,\n resolvedData,\n dataContext: { contentEntry: entry.content },\n theme: site.theme,\n siteId,\n site: site.site,\n };\n }\n\n // Handle page response\n const { page: pageData } = contentResponse;\n\n // Convert API response blocks to PageOutline format with validation\n const blocks = pageData.blocks.map((block) => validateAndConvertBlock(block, 'page'));\n\n const pageOutline = {\n name: pageData.name,\n path: pageData.path,\n purpose: pageData.purpose,\n blocks,\n };\n\n // Prefetch block data loaders for pages\n const resolvedData = await prefetchBlockData(\n pageOutline,\n {\n siteId,\n pageId: pageData.id,\n previewStage: preview ? 'preview' : 'published',\n },\n client\n );\n\n return {\n type: 'page',\n page: pageOutline,\n theme: site.theme,\n siteId,\n resolvedData,\n site: site.site,\n };\n}\n\n/**\n * Type guard to check if API response is an entry\n */\nfunction isEntryResponse(response: PageResponse): response is Extract<PageResponse, { type: 'entry' }> {\n return 'type' in response && response.type === 'entry';\n}\n\n/**\n * Validates and converts a raw block from API response to PageOutline block format.\n * Used for both page blocks and template blocks to ensure consistent validation.\n */\nfunction validateAndConvertBlock(\n block: unknown,\n source: 'page' | 'template'\n): { id: string | null; kind: string; purpose: string; content?: Record<string, unknown> } {\n if (!block || typeof block !== 'object') {\n throw new Error(`Invalid block format in ${source} API response`);\n }\n\n const blockRecord = block as Record<string, unknown>;\n\n // Template blocks use 'blockKind', page blocks use 'kind'\n const kindField = source === 'template' ? 'blockKind' : 'kind';\n const kindValue = blockRecord[kindField];\n\n if (typeof blockRecord.id !== 'string' && blockRecord.id !== null) {\n throw new Error(`Invalid block id in ${source}: expected string or null, got ${typeof blockRecord.id}`);\n }\n if (typeof kindValue !== 'string') {\n throw new Error(`Invalid block ${kindField} in ${source}: expected string, got ${typeof kindValue}`);\n }\n\n // Template blocks derive purpose from scope, page blocks have explicit purpose\n if (source === 'page') {\n if (typeof blockRecord.purpose !== 'string') {\n throw new Error(`Invalid block purpose in ${source}: expected string, got ${typeof blockRecord.purpose}`);\n }\n return {\n id: blockRecord.id as string | null,\n kind: kindValue,\n purpose: blockRecord.purpose,\n };\n }\n\n // Template block: derive purpose from scope, include content\n const scope = blockRecord.scope as 'entry' | 'template' | undefined;\n const content = (blockRecord.content as Record<string, unknown> | null) ?? {};\n\n return {\n id: blockRecord.id as string | null,\n kind: kindValue,\n purpose: scope === 'entry' ? 'entry-content' : 'template-layout',\n content,\n };\n}\n\n/** Template block structure from API response */\ntype TemplateBlock = {\n id: string;\n blockKind: string;\n scope: 'entry' | 'template';\n content: Record<string, unknown> | null;\n};\n\n/** Template structure from API response */\ntype Template = {\n id: string;\n name: string;\n templateKey: string;\n blocks: TemplateBlock[];\n};\n\n/**\n * Processes an entry's template into a PageOutline format and prefetches block data.\n * Returns null templatePage if no valid template with blocks is available.\n */\nasync function processEntryTemplate(\n templates: Template[] | undefined,\n entry: ContentEntryData,\n context: { siteId: string; preview: boolean },\n client: RiverbankClient\n): Promise<{ templatePage: PageProps['page'] | null; resolvedData: ResolvedBlockData }> {\n const template = templates?.[0];\n\n // Templates without blocks are treated as \"no template\" - the entry should be\n // rendered with custom UI rather than an empty template page\n if (!template || !template.blocks?.length) {\n return { templatePage: null, resolvedData: {} };\n }\n\n // Convert template blocks to PageOutline format with validation\n const blocks = template.blocks.map((block) => validateAndConvertBlock(block, 'template'));\n\n const templatePage: PageProps['page'] = {\n name: template.name || 'Entry Template',\n path: entry.path || '/',\n purpose: 'entry-template',\n blocks,\n };\n\n // Prefetch block data for template\n const resolvedData = await prefetchBlockData(\n templatePage,\n {\n siteId: context.siteId,\n pageId: template.id,\n previewStage: context.preview ? 'preview' : 'published',\n },\n client\n );\n\n return { templatePage, resolvedData };\n}\n"]}
|
|
@@ -1996,7 +1996,7 @@ var SimpleCache = class {
|
|
|
1996
1996
|
};
|
|
1997
1997
|
|
|
1998
1998
|
// src/version.ts
|
|
1999
|
-
var SDK_VERSION = "0.
|
|
1999
|
+
var SDK_VERSION = "0.7.0";
|
|
2000
2000
|
|
|
2001
2001
|
// src/client/error.ts
|
|
2002
2002
|
var RiverbankApiError = class _RiverbankApiError extends Error {
|
|
@@ -2267,4 +2267,4 @@ function createRiverbankClient(config) {
|
|
|
2267
2267
|
|
|
2268
2268
|
|
|
2269
2269
|
exports.API_ENDPOINTS = API_ENDPOINTS; exports.buildEndpointURL = buildEndpointURL; exports.createRiverbankClient = createRiverbankClient;
|
|
2270
|
-
//# sourceMappingURL=chunk-
|
|
2270
|
+
//# sourceMappingURL=chunk-P7UVAMK6.js.map
|