@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,274 @@
|
|
|
1
|
+
import { ReactNode, ComponentType } from 'react';
|
|
2
|
+
import { R as RiverbankClient } from './types-1cLz0vnq.mjs';
|
|
3
|
+
import { R as RiverbankSiteConfig } from './types-BjgZt8xJ.mjs';
|
|
4
|
+
import { B as BlockOverrides } from './loadPage-B8mQUUSo.mjs';
|
|
5
|
+
import './schema-Z6-afHJG.mjs';
|
|
6
|
+
import { M as Metadata } from './index-DI_qlYx3.mjs';
|
|
7
|
+
import { b as LoadContentResult } from './loadContent-C-YYUKQa.mjs';
|
|
8
|
+
import './types-Dsu9wsUh.mjs';
|
|
9
|
+
import '@riverbankcms/ai';
|
|
10
|
+
import 'zod';
|
|
11
|
+
import './link-DjxLyC82.mjs';
|
|
12
|
+
import '@riverbankcms/media-storage-supabase';
|
|
13
|
+
import '@riverbankcms/db';
|
|
14
|
+
import './blockKinds-B6MWzNWp.mjs';
|
|
15
|
+
import 'react/jsx-runtime';
|
|
16
|
+
import './core-DsNWrl3o.mjs';
|
|
17
|
+
import './types-CbagRQ_7.mjs';
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Type definitions for Next.js integration helpers.
|
|
21
|
+
*
|
|
22
|
+
* These types define the options and props for the `createCatchAllPage()` factory,
|
|
23
|
+
* which simplifies catch-all routing for Riverbank CMS sites.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Context passed to escape hatch callbacks.
|
|
28
|
+
*/
|
|
29
|
+
interface CatchAllContext {
|
|
30
|
+
/** Loaded content (page or entry) */
|
|
31
|
+
content: LoadContentResult;
|
|
32
|
+
/** Resolved URL path (e.g., '/about', '/blog/my-post') */
|
|
33
|
+
path: string;
|
|
34
|
+
/** Whether preview mode is enabled */
|
|
35
|
+
preview: boolean;
|
|
36
|
+
/** Search parameters from the URL (for filtering, pagination, etc.) */
|
|
37
|
+
searchParams: Record<string, string | string[] | undefined>;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Options for the `createCatchAllPage()` factory.
|
|
41
|
+
*
|
|
42
|
+
* @example Basic usage
|
|
43
|
+
* ```tsx
|
|
44
|
+
* const { Page, generateMetadata } = createCatchAllPage({
|
|
45
|
+
* getClient: getRiverbankClient,
|
|
46
|
+
* config,
|
|
47
|
+
* blockOverrides: { hero: MyCustomHero },
|
|
48
|
+
* });
|
|
49
|
+
* ```
|
|
50
|
+
*
|
|
51
|
+
* @example With maintenance mode
|
|
52
|
+
* ```tsx
|
|
53
|
+
* const { Page, generateMetadata } = createCatchAllPage({
|
|
54
|
+
* getClient,
|
|
55
|
+
* config,
|
|
56
|
+
* beforeRender: async () => {
|
|
57
|
+
* if (process.env.MAINTENANCE_MODE === 'true') {
|
|
58
|
+
* return <MaintenancePage />;
|
|
59
|
+
* }
|
|
60
|
+
* return null; // Continue with normal rendering
|
|
61
|
+
* },
|
|
62
|
+
* });
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
interface CreateCatchAllPageOptions {
|
|
66
|
+
/**
|
|
67
|
+
* Function that returns the Riverbank client.
|
|
68
|
+
* Called fresh on each request to support different caching strategies.
|
|
69
|
+
*/
|
|
70
|
+
getClient: () => RiverbankClient;
|
|
71
|
+
/**
|
|
72
|
+
* Site configuration from `defineConfig()`.
|
|
73
|
+
* Provides siteId and content type routing information.
|
|
74
|
+
*/
|
|
75
|
+
config: RiverbankSiteConfig;
|
|
76
|
+
/**
|
|
77
|
+
* Custom block component overrides for rendering.
|
|
78
|
+
* Keys can be full block kind ("block.hero") or short form ("hero").
|
|
79
|
+
*/
|
|
80
|
+
blockOverrides?: BlockOverrides;
|
|
81
|
+
/**
|
|
82
|
+
* Override site URL for metadata generation.
|
|
83
|
+
* Defaults to `config.liveUrl` or `config.previewUrl` based on preview mode.
|
|
84
|
+
*/
|
|
85
|
+
siteUrl?: string;
|
|
86
|
+
/**
|
|
87
|
+
* Intercept before rendering to implement maintenance mode, access control, etc.
|
|
88
|
+
*
|
|
89
|
+
* Return a React node to short-circuit rendering, or `null` to continue
|
|
90
|
+
* with normal page/entry rendering.
|
|
91
|
+
*
|
|
92
|
+
* @example Maintenance mode
|
|
93
|
+
* ```tsx
|
|
94
|
+
* beforeRender: async () => {
|
|
95
|
+
* if (process.env.MAINTENANCE_MODE === 'true') {
|
|
96
|
+
* return <MaintenancePage />;
|
|
97
|
+
* }
|
|
98
|
+
* return null;
|
|
99
|
+
* }
|
|
100
|
+
* ```
|
|
101
|
+
*
|
|
102
|
+
* @example Access control
|
|
103
|
+
* ```tsx
|
|
104
|
+
* beforeRender: async ({ path }) => {
|
|
105
|
+
* if (path.startsWith('/members')) {
|
|
106
|
+
* const session = await getSession();
|
|
107
|
+
* if (!session) return <LoginPage redirect={path} />;
|
|
108
|
+
* }
|
|
109
|
+
* return null;
|
|
110
|
+
* }
|
|
111
|
+
* ```
|
|
112
|
+
*/
|
|
113
|
+
beforeRender?: (context: CatchAllContext) => ReactNode | null | Promise<ReactNode | null>;
|
|
114
|
+
/**
|
|
115
|
+
* Custom metadata generator. If provided, replaces default metadata generation.
|
|
116
|
+
*
|
|
117
|
+
* Use this when you need full control over SEO metadata, such as adding
|
|
118
|
+
* product-specific Open Graph tags for e-commerce sites.
|
|
119
|
+
*
|
|
120
|
+
* @example Custom product metadata
|
|
121
|
+
* ```tsx
|
|
122
|
+
* customMetadata: async ({ content }) => {
|
|
123
|
+
* if (isEntryContent(content) && content.entry.type === 'product') {
|
|
124
|
+
* return {
|
|
125
|
+
* title: `${content.entry.title} | Shop`,
|
|
126
|
+
* openGraph: { type: 'product' },
|
|
127
|
+
* };
|
|
128
|
+
* }
|
|
129
|
+
* // Use default for other content types
|
|
130
|
+
* return generatePageMetadata({ page, site, path, siteUrl });
|
|
131
|
+
* }
|
|
132
|
+
* ```
|
|
133
|
+
*/
|
|
134
|
+
customMetadata?: (context: CatchAllContext) => Metadata | Promise<Metadata>;
|
|
135
|
+
/**
|
|
136
|
+
* Wrapper component around rendered content.
|
|
137
|
+
*
|
|
138
|
+
* Useful for adding analytics scripts, error boundaries, or layout wrappers
|
|
139
|
+
* that should wrap all page content.
|
|
140
|
+
*
|
|
141
|
+
* @example Analytics wrapper
|
|
142
|
+
* ```tsx
|
|
143
|
+
* wrapper: ({ children }) => (
|
|
144
|
+
* <>
|
|
145
|
+
* {children}
|
|
146
|
+
* <AnalyticsScript siteId={config.siteId} />
|
|
147
|
+
* </>
|
|
148
|
+
* )
|
|
149
|
+
* ```
|
|
150
|
+
*/
|
|
151
|
+
wrapper?: ComponentType<{
|
|
152
|
+
children: ReactNode;
|
|
153
|
+
}>;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Next.js page props for catch-all routes.
|
|
157
|
+
*
|
|
158
|
+
* This matches the signature expected by Next.js 15+ App Router pages
|
|
159
|
+
* with the `[[...slug]]` pattern.
|
|
160
|
+
*/
|
|
161
|
+
interface CatchAllPageProps {
|
|
162
|
+
/** Route parameters containing the slug segments */
|
|
163
|
+
params: Promise<{
|
|
164
|
+
slug?: string[];
|
|
165
|
+
}>;
|
|
166
|
+
/** Optional search parameters from the URL */
|
|
167
|
+
searchParams?: Promise<Record<string, string | string[] | undefined>>;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Result of the `createCatchAllPage()` factory.
|
|
171
|
+
*/
|
|
172
|
+
interface CreateCatchAllPageResult {
|
|
173
|
+
/**
|
|
174
|
+
* React component to use as the default export of your catch-all page.
|
|
175
|
+
*
|
|
176
|
+
* @example
|
|
177
|
+
* ```tsx
|
|
178
|
+
* const { Page, generateMetadata } = createCatchAllPage({ ... });
|
|
179
|
+
* export default Page;
|
|
180
|
+
* ```
|
|
181
|
+
*/
|
|
182
|
+
Page: (props: CatchAllPageProps) => Promise<ReactNode>;
|
|
183
|
+
/**
|
|
184
|
+
* Metadata generation function for Next.js `generateMetadata`.
|
|
185
|
+
*
|
|
186
|
+
* @example
|
|
187
|
+
* ```tsx
|
|
188
|
+
* const { Page, generateMetadata } = createCatchAllPage({ ... });
|
|
189
|
+
* export { generateMetadata };
|
|
190
|
+
* ```
|
|
191
|
+
*/
|
|
192
|
+
generateMetadata: (props: CatchAllPageProps) => Promise<Metadata>;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Next.js catch-all page factory for Riverbank CMS.
|
|
197
|
+
*
|
|
198
|
+
* Provides a simple, opinionated way to render CMS content in Next.js catch-all routes.
|
|
199
|
+
* Reduces typical page.tsx boilerplate from ~160 lines to ~10 lines.
|
|
200
|
+
*
|
|
201
|
+
* @example
|
|
202
|
+
* ```tsx
|
|
203
|
+
* // src/app/[[...slug]]/page.tsx
|
|
204
|
+
* import { createCatchAllPage } from '@riverbankcms/sdk/next';
|
|
205
|
+
* import { getRiverbankClient } from '@/lib/builder-client';
|
|
206
|
+
* import config from '@/riverbank.config';
|
|
207
|
+
*
|
|
208
|
+
* const { Page, generateMetadata } = createCatchAllPage({
|
|
209
|
+
* getClient: getRiverbankClient,
|
|
210
|
+
* config,
|
|
211
|
+
* blockOverrides: { hero: MyCustomHero },
|
|
212
|
+
* });
|
|
213
|
+
*
|
|
214
|
+
* export default Page;
|
|
215
|
+
* export { generateMetadata };
|
|
216
|
+
* ```
|
|
217
|
+
*/
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Factory function to create a Next.js catch-all page component and metadata generator.
|
|
221
|
+
*
|
|
222
|
+
* This provides a simple, opinionated setup for rendering Riverbank CMS content
|
|
223
|
+
* in external SDK sites. It handles:
|
|
224
|
+
*
|
|
225
|
+
* - Page and content entry routing
|
|
226
|
+
* - Preview mode detection (via `RIVERBANK_PREVIEW_MODE` env var)
|
|
227
|
+
* - SEO metadata generation
|
|
228
|
+
* - Block overrides for custom components
|
|
229
|
+
* - 404 handling for missing content
|
|
230
|
+
*
|
|
231
|
+
* ## Escape Hatches
|
|
232
|
+
*
|
|
233
|
+
* For customization beyond the defaults, use these options:
|
|
234
|
+
*
|
|
235
|
+
* - `beforeRender`: Intercept before rendering (maintenance mode, access control)
|
|
236
|
+
* - `customMetadata`: Full control over SEO metadata
|
|
237
|
+
* - `wrapper`: Wrap all content (analytics, error boundaries)
|
|
238
|
+
*
|
|
239
|
+
* For maximum control, use the lower-level helpers directly:
|
|
240
|
+
* - `loadContent()` from `@riverbankcms/sdk/rendering`
|
|
241
|
+
* - `Page` component from `@riverbankcms/sdk/rendering`
|
|
242
|
+
* - `generatePageMetadata()` from `@riverbankcms/sdk/metadata`
|
|
243
|
+
*
|
|
244
|
+
* @param options - Configuration options
|
|
245
|
+
* @returns Object with `Page` component and `generateMetadata` function
|
|
246
|
+
*
|
|
247
|
+
* @example Basic usage
|
|
248
|
+
* ```tsx
|
|
249
|
+
* const { Page, generateMetadata } = createCatchAllPage({
|
|
250
|
+
* getClient: getRiverbankClient,
|
|
251
|
+
* config,
|
|
252
|
+
* });
|
|
253
|
+
*
|
|
254
|
+
* export default Page;
|
|
255
|
+
* export { generateMetadata };
|
|
256
|
+
* ```
|
|
257
|
+
*
|
|
258
|
+
* @example With maintenance mode
|
|
259
|
+
* ```tsx
|
|
260
|
+
* const { Page, generateMetadata } = createCatchAllPage({
|
|
261
|
+
* getClient,
|
|
262
|
+
* config,
|
|
263
|
+
* beforeRender: async () => {
|
|
264
|
+
* if (process.env.MAINTENANCE_MODE === 'true') {
|
|
265
|
+
* return <MaintenancePage />;
|
|
266
|
+
* }
|
|
267
|
+
* return null;
|
|
268
|
+
* },
|
|
269
|
+
* });
|
|
270
|
+
* ```
|
|
271
|
+
*/
|
|
272
|
+
declare function createCatchAllPage(options: CreateCatchAllPageOptions): CreateCatchAllPageResult;
|
|
273
|
+
|
|
274
|
+
export { type CatchAllContext, type CatchAllPageProps, type CreateCatchAllPageOptions, type CreateCatchAllPageResult, createCatchAllPage };
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
import { ReactNode, ComponentType } from 'react';
|
|
2
|
+
import { R as RiverbankClient } from './types-BvcJU7zk.js';
|
|
3
|
+
import { R as RiverbankSiteConfig } from './types-DLBhEPSt.js';
|
|
4
|
+
import { B as BlockOverrides } from './loadPage-DP3nrHBi.js';
|
|
5
|
+
import './schema-Z6-afHJG.js';
|
|
6
|
+
import { M as Metadata } from './index-BTwWvSBu.js';
|
|
7
|
+
import { b as LoadContentResult } from './loadContent-DmgpFcFC.js';
|
|
8
|
+
import './types-CVykEqXN.js';
|
|
9
|
+
import '@riverbankcms/ai';
|
|
10
|
+
import 'zod';
|
|
11
|
+
import './link-DjxLyC82.js';
|
|
12
|
+
import '@riverbankcms/media-storage-supabase';
|
|
13
|
+
import '@riverbankcms/db';
|
|
14
|
+
import './blockKinds-B6MWzNWp.js';
|
|
15
|
+
import 'react/jsx-runtime';
|
|
16
|
+
import './core-DsNWrl3o.js';
|
|
17
|
+
import './types-DuQCNVV0.js';
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Type definitions for Next.js integration helpers.
|
|
21
|
+
*
|
|
22
|
+
* These types define the options and props for the `createCatchAllPage()` factory,
|
|
23
|
+
* which simplifies catch-all routing for Riverbank CMS sites.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Context passed to escape hatch callbacks.
|
|
28
|
+
*/
|
|
29
|
+
interface CatchAllContext {
|
|
30
|
+
/** Loaded content (page or entry) */
|
|
31
|
+
content: LoadContentResult;
|
|
32
|
+
/** Resolved URL path (e.g., '/about', '/blog/my-post') */
|
|
33
|
+
path: string;
|
|
34
|
+
/** Whether preview mode is enabled */
|
|
35
|
+
preview: boolean;
|
|
36
|
+
/** Search parameters from the URL (for filtering, pagination, etc.) */
|
|
37
|
+
searchParams: Record<string, string | string[] | undefined>;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Options for the `createCatchAllPage()` factory.
|
|
41
|
+
*
|
|
42
|
+
* @example Basic usage
|
|
43
|
+
* ```tsx
|
|
44
|
+
* const { Page, generateMetadata } = createCatchAllPage({
|
|
45
|
+
* getClient: getRiverbankClient,
|
|
46
|
+
* config,
|
|
47
|
+
* blockOverrides: { hero: MyCustomHero },
|
|
48
|
+
* });
|
|
49
|
+
* ```
|
|
50
|
+
*
|
|
51
|
+
* @example With maintenance mode
|
|
52
|
+
* ```tsx
|
|
53
|
+
* const { Page, generateMetadata } = createCatchAllPage({
|
|
54
|
+
* getClient,
|
|
55
|
+
* config,
|
|
56
|
+
* beforeRender: async () => {
|
|
57
|
+
* if (process.env.MAINTENANCE_MODE === 'true') {
|
|
58
|
+
* return <MaintenancePage />;
|
|
59
|
+
* }
|
|
60
|
+
* return null; // Continue with normal rendering
|
|
61
|
+
* },
|
|
62
|
+
* });
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
interface CreateCatchAllPageOptions {
|
|
66
|
+
/**
|
|
67
|
+
* Function that returns the Riverbank client.
|
|
68
|
+
* Called fresh on each request to support different caching strategies.
|
|
69
|
+
*/
|
|
70
|
+
getClient: () => RiverbankClient;
|
|
71
|
+
/**
|
|
72
|
+
* Site configuration from `defineConfig()`.
|
|
73
|
+
* Provides siteId and content type routing information.
|
|
74
|
+
*/
|
|
75
|
+
config: RiverbankSiteConfig;
|
|
76
|
+
/**
|
|
77
|
+
* Custom block component overrides for rendering.
|
|
78
|
+
* Keys can be full block kind ("block.hero") or short form ("hero").
|
|
79
|
+
*/
|
|
80
|
+
blockOverrides?: BlockOverrides;
|
|
81
|
+
/**
|
|
82
|
+
* Override site URL for metadata generation.
|
|
83
|
+
* Defaults to `config.liveUrl` or `config.previewUrl` based on preview mode.
|
|
84
|
+
*/
|
|
85
|
+
siteUrl?: string;
|
|
86
|
+
/**
|
|
87
|
+
* Intercept before rendering to implement maintenance mode, access control, etc.
|
|
88
|
+
*
|
|
89
|
+
* Return a React node to short-circuit rendering, or `null` to continue
|
|
90
|
+
* with normal page/entry rendering.
|
|
91
|
+
*
|
|
92
|
+
* @example Maintenance mode
|
|
93
|
+
* ```tsx
|
|
94
|
+
* beforeRender: async () => {
|
|
95
|
+
* if (process.env.MAINTENANCE_MODE === 'true') {
|
|
96
|
+
* return <MaintenancePage />;
|
|
97
|
+
* }
|
|
98
|
+
* return null;
|
|
99
|
+
* }
|
|
100
|
+
* ```
|
|
101
|
+
*
|
|
102
|
+
* @example Access control
|
|
103
|
+
* ```tsx
|
|
104
|
+
* beforeRender: async ({ path }) => {
|
|
105
|
+
* if (path.startsWith('/members')) {
|
|
106
|
+
* const session = await getSession();
|
|
107
|
+
* if (!session) return <LoginPage redirect={path} />;
|
|
108
|
+
* }
|
|
109
|
+
* return null;
|
|
110
|
+
* }
|
|
111
|
+
* ```
|
|
112
|
+
*/
|
|
113
|
+
beforeRender?: (context: CatchAllContext) => ReactNode | null | Promise<ReactNode | null>;
|
|
114
|
+
/**
|
|
115
|
+
* Custom metadata generator. If provided, replaces default metadata generation.
|
|
116
|
+
*
|
|
117
|
+
* Use this when you need full control over SEO metadata, such as adding
|
|
118
|
+
* product-specific Open Graph tags for e-commerce sites.
|
|
119
|
+
*
|
|
120
|
+
* @example Custom product metadata
|
|
121
|
+
* ```tsx
|
|
122
|
+
* customMetadata: async ({ content }) => {
|
|
123
|
+
* if (isEntryContent(content) && content.entry.type === 'product') {
|
|
124
|
+
* return {
|
|
125
|
+
* title: `${content.entry.title} | Shop`,
|
|
126
|
+
* openGraph: { type: 'product' },
|
|
127
|
+
* };
|
|
128
|
+
* }
|
|
129
|
+
* // Use default for other content types
|
|
130
|
+
* return generatePageMetadata({ page, site, path, siteUrl });
|
|
131
|
+
* }
|
|
132
|
+
* ```
|
|
133
|
+
*/
|
|
134
|
+
customMetadata?: (context: CatchAllContext) => Metadata | Promise<Metadata>;
|
|
135
|
+
/**
|
|
136
|
+
* Wrapper component around rendered content.
|
|
137
|
+
*
|
|
138
|
+
* Useful for adding analytics scripts, error boundaries, or layout wrappers
|
|
139
|
+
* that should wrap all page content.
|
|
140
|
+
*
|
|
141
|
+
* @example Analytics wrapper
|
|
142
|
+
* ```tsx
|
|
143
|
+
* wrapper: ({ children }) => (
|
|
144
|
+
* <>
|
|
145
|
+
* {children}
|
|
146
|
+
* <AnalyticsScript siteId={config.siteId} />
|
|
147
|
+
* </>
|
|
148
|
+
* )
|
|
149
|
+
* ```
|
|
150
|
+
*/
|
|
151
|
+
wrapper?: ComponentType<{
|
|
152
|
+
children: ReactNode;
|
|
153
|
+
}>;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Next.js page props for catch-all routes.
|
|
157
|
+
*
|
|
158
|
+
* This matches the signature expected by Next.js 15+ App Router pages
|
|
159
|
+
* with the `[[...slug]]` pattern.
|
|
160
|
+
*/
|
|
161
|
+
interface CatchAllPageProps {
|
|
162
|
+
/** Route parameters containing the slug segments */
|
|
163
|
+
params: Promise<{
|
|
164
|
+
slug?: string[];
|
|
165
|
+
}>;
|
|
166
|
+
/** Optional search parameters from the URL */
|
|
167
|
+
searchParams?: Promise<Record<string, string | string[] | undefined>>;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Result of the `createCatchAllPage()` factory.
|
|
171
|
+
*/
|
|
172
|
+
interface CreateCatchAllPageResult {
|
|
173
|
+
/**
|
|
174
|
+
* React component to use as the default export of your catch-all page.
|
|
175
|
+
*
|
|
176
|
+
* @example
|
|
177
|
+
* ```tsx
|
|
178
|
+
* const { Page, generateMetadata } = createCatchAllPage({ ... });
|
|
179
|
+
* export default Page;
|
|
180
|
+
* ```
|
|
181
|
+
*/
|
|
182
|
+
Page: (props: CatchAllPageProps) => Promise<ReactNode>;
|
|
183
|
+
/**
|
|
184
|
+
* Metadata generation function for Next.js `generateMetadata`.
|
|
185
|
+
*
|
|
186
|
+
* @example
|
|
187
|
+
* ```tsx
|
|
188
|
+
* const { Page, generateMetadata } = createCatchAllPage({ ... });
|
|
189
|
+
* export { generateMetadata };
|
|
190
|
+
* ```
|
|
191
|
+
*/
|
|
192
|
+
generateMetadata: (props: CatchAllPageProps) => Promise<Metadata>;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Next.js catch-all page factory for Riverbank CMS.
|
|
197
|
+
*
|
|
198
|
+
* Provides a simple, opinionated way to render CMS content in Next.js catch-all routes.
|
|
199
|
+
* Reduces typical page.tsx boilerplate from ~160 lines to ~10 lines.
|
|
200
|
+
*
|
|
201
|
+
* @example
|
|
202
|
+
* ```tsx
|
|
203
|
+
* // src/app/[[...slug]]/page.tsx
|
|
204
|
+
* import { createCatchAllPage } from '@riverbankcms/sdk/next';
|
|
205
|
+
* import { getRiverbankClient } from '@/lib/builder-client';
|
|
206
|
+
* import config from '@/riverbank.config';
|
|
207
|
+
*
|
|
208
|
+
* const { Page, generateMetadata } = createCatchAllPage({
|
|
209
|
+
* getClient: getRiverbankClient,
|
|
210
|
+
* config,
|
|
211
|
+
* blockOverrides: { hero: MyCustomHero },
|
|
212
|
+
* });
|
|
213
|
+
*
|
|
214
|
+
* export default Page;
|
|
215
|
+
* export { generateMetadata };
|
|
216
|
+
* ```
|
|
217
|
+
*/
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Factory function to create a Next.js catch-all page component and metadata generator.
|
|
221
|
+
*
|
|
222
|
+
* This provides a simple, opinionated setup for rendering Riverbank CMS content
|
|
223
|
+
* in external SDK sites. It handles:
|
|
224
|
+
*
|
|
225
|
+
* - Page and content entry routing
|
|
226
|
+
* - Preview mode detection (via `RIVERBANK_PREVIEW_MODE` env var)
|
|
227
|
+
* - SEO metadata generation
|
|
228
|
+
* - Block overrides for custom components
|
|
229
|
+
* - 404 handling for missing content
|
|
230
|
+
*
|
|
231
|
+
* ## Escape Hatches
|
|
232
|
+
*
|
|
233
|
+
* For customization beyond the defaults, use these options:
|
|
234
|
+
*
|
|
235
|
+
* - `beforeRender`: Intercept before rendering (maintenance mode, access control)
|
|
236
|
+
* - `customMetadata`: Full control over SEO metadata
|
|
237
|
+
* - `wrapper`: Wrap all content (analytics, error boundaries)
|
|
238
|
+
*
|
|
239
|
+
* For maximum control, use the lower-level helpers directly:
|
|
240
|
+
* - `loadContent()` from `@riverbankcms/sdk/rendering`
|
|
241
|
+
* - `Page` component from `@riverbankcms/sdk/rendering`
|
|
242
|
+
* - `generatePageMetadata()` from `@riverbankcms/sdk/metadata`
|
|
243
|
+
*
|
|
244
|
+
* @param options - Configuration options
|
|
245
|
+
* @returns Object with `Page` component and `generateMetadata` function
|
|
246
|
+
*
|
|
247
|
+
* @example Basic usage
|
|
248
|
+
* ```tsx
|
|
249
|
+
* const { Page, generateMetadata } = createCatchAllPage({
|
|
250
|
+
* getClient: getRiverbankClient,
|
|
251
|
+
* config,
|
|
252
|
+
* });
|
|
253
|
+
*
|
|
254
|
+
* export default Page;
|
|
255
|
+
* export { generateMetadata };
|
|
256
|
+
* ```
|
|
257
|
+
*
|
|
258
|
+
* @example With maintenance mode
|
|
259
|
+
* ```tsx
|
|
260
|
+
* const { Page, generateMetadata } = createCatchAllPage({
|
|
261
|
+
* getClient,
|
|
262
|
+
* config,
|
|
263
|
+
* beforeRender: async () => {
|
|
264
|
+
* if (process.env.MAINTENANCE_MODE === 'true') {
|
|
265
|
+
* return <MaintenancePage />;
|
|
266
|
+
* }
|
|
267
|
+
* return null;
|
|
268
|
+
* },
|
|
269
|
+
* });
|
|
270
|
+
* ```
|
|
271
|
+
*/
|
|
272
|
+
declare function createCatchAllPage(options: CreateCatchAllPageOptions): CreateCatchAllPageResult;
|
|
273
|
+
|
|
274
|
+
export { type CatchAllContext, type CatchAllPageProps, type CreateCatchAllPageOptions, type CreateCatchAllPageResult, createCatchAllPage };
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
var _chunkBNQV3PXPjs = require('./chunk-BNQV3PXP.js');
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
var _chunkJWRNMNWIjs = require('./chunk-JWRNMNWI.js');
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
var _chunkT26N3P26js = require('./chunk-T26N3P26.js');
|
|
13
|
+
require('./chunk-7UPVCT3K.js');
|
|
14
|
+
require('./chunk-RVDS7VSP.js');
|
|
15
|
+
require('./chunk-YYO3RIFO.js');
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
var _chunkDGUM43GVjs = require('./chunk-DGUM43GV.js');
|
|
19
|
+
|
|
20
|
+
// src/next/catch-all.tsx
|
|
21
|
+
var _jsxruntime = require('react/jsx-runtime');
|
|
22
|
+
var { notFound } = _chunkDGUM43GVjs.__require.call(void 0, "next/navigation");
|
|
23
|
+
function isPreviewMode() {
|
|
24
|
+
return process.env.RIVERBANK_PREVIEW_MODE === "true";
|
|
25
|
+
}
|
|
26
|
+
function slugToPath(slug) {
|
|
27
|
+
if (!slug || slug.length === 0) return "/";
|
|
28
|
+
return "/" + slug.join("/");
|
|
29
|
+
}
|
|
30
|
+
function createCatchAllPage(options) {
|
|
31
|
+
const {
|
|
32
|
+
getClient,
|
|
33
|
+
config,
|
|
34
|
+
blockOverrides,
|
|
35
|
+
siteUrl,
|
|
36
|
+
beforeRender,
|
|
37
|
+
customMetadata,
|
|
38
|
+
wrapper: Wrapper
|
|
39
|
+
} = options;
|
|
40
|
+
async function Page2({ params, searchParams: searchParamsPromise }) {
|
|
41
|
+
const [{ slug }, searchParams] = await Promise.all([
|
|
42
|
+
params,
|
|
43
|
+
_nullishCoalesce(searchParamsPromise, () => ( Promise.resolve({})))
|
|
44
|
+
]);
|
|
45
|
+
const path = slugToPath(slug);
|
|
46
|
+
const preview = isPreviewMode();
|
|
47
|
+
const client = getClient();
|
|
48
|
+
let content;
|
|
49
|
+
try {
|
|
50
|
+
content = await _chunkJWRNMNWIjs.loadContent.call(void 0, {
|
|
51
|
+
client,
|
|
52
|
+
siteId: config.siteId,
|
|
53
|
+
path,
|
|
54
|
+
preview
|
|
55
|
+
});
|
|
56
|
+
} catch (error) {
|
|
57
|
+
console.debug("[createCatchAllPage] Failed to load content for path:", path, error);
|
|
58
|
+
return notFound();
|
|
59
|
+
}
|
|
60
|
+
if (beforeRender) {
|
|
61
|
+
const intercepted = await beforeRender({ content, path, preview, searchParams });
|
|
62
|
+
if (intercepted !== null) {
|
|
63
|
+
return Wrapper ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Wrapper, { children: intercepted }) : intercepted;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
let rendered;
|
|
67
|
+
if (_chunkJWRNMNWIjs.isPageContent.call(void 0, content)) {
|
|
68
|
+
rendered = /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
69
|
+
_chunkT26N3P26js.Page,
|
|
70
|
+
{
|
|
71
|
+
page: content.page,
|
|
72
|
+
theme: content.theme,
|
|
73
|
+
siteId: content.siteId,
|
|
74
|
+
resolvedData: content.resolvedData,
|
|
75
|
+
blockOverrides
|
|
76
|
+
}
|
|
77
|
+
);
|
|
78
|
+
} else if (_chunkJWRNMNWIjs.isEntryContent.call(void 0, content)) {
|
|
79
|
+
if (!content.templatePage) {
|
|
80
|
+
return notFound();
|
|
81
|
+
}
|
|
82
|
+
rendered = /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
83
|
+
_chunkT26N3P26js.Page,
|
|
84
|
+
{
|
|
85
|
+
page: content.templatePage,
|
|
86
|
+
theme: content.theme,
|
|
87
|
+
siteId: content.siteId,
|
|
88
|
+
resolvedData: content.resolvedData,
|
|
89
|
+
blockOverrides,
|
|
90
|
+
dataContext: {
|
|
91
|
+
contentEntry: content.dataContext.contentEntry
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
);
|
|
95
|
+
} else {
|
|
96
|
+
return notFound();
|
|
97
|
+
}
|
|
98
|
+
return Wrapper ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Wrapper, { children: rendered }) : rendered;
|
|
99
|
+
}
|
|
100
|
+
async function generateMetadataFn({ params, searchParams: searchParamsPromise }) {
|
|
101
|
+
const [{ slug }, searchParams] = await Promise.all([
|
|
102
|
+
params,
|
|
103
|
+
_nullishCoalesce(searchParamsPromise, () => ( Promise.resolve({})))
|
|
104
|
+
]);
|
|
105
|
+
const path = slugToPath(slug);
|
|
106
|
+
const preview = isPreviewMode();
|
|
107
|
+
try {
|
|
108
|
+
const content = await _chunkJWRNMNWIjs.loadContent.call(void 0, {
|
|
109
|
+
client: getClient(),
|
|
110
|
+
siteId: config.siteId,
|
|
111
|
+
path,
|
|
112
|
+
preview
|
|
113
|
+
});
|
|
114
|
+
if (customMetadata) {
|
|
115
|
+
return customMetadata({ content, path, preview, searchParams });
|
|
116
|
+
}
|
|
117
|
+
const resolvedUrl = _nullishCoalesce(_nullishCoalesce(siteUrl, () => ( (preview ? config.previewUrl : config.liveUrl))), () => ( ""));
|
|
118
|
+
if (!resolvedUrl) {
|
|
119
|
+
console.warn(
|
|
120
|
+
"[createCatchAllPage] No siteUrl configured. OpenGraph and Twitter tags will have relative URLs which may cause social sharing previews to fail. Set siteUrl option, or config.liveUrl/config.previewUrl in your riverbank.config."
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
const page = _chunkJWRNMNWIjs.isPageContent.call(void 0, content) ? content.page : _chunkJWRNMNWIjs.isEntryContent.call(void 0, content) ? {
|
|
124
|
+
name: _nullishCoalesce(content.entry.metaTitle, () => ( content.entry.title)),
|
|
125
|
+
purpose: _nullishCoalesce(content.entry.metaDescription, () => ( void 0))
|
|
126
|
+
} : { name: "Page" };
|
|
127
|
+
const metadataGenerator = preview ? _chunkBNQV3PXPjs.generatePreviewMetadata : _chunkBNQV3PXPjs.generatePageMetadata;
|
|
128
|
+
return metadataGenerator({
|
|
129
|
+
page,
|
|
130
|
+
site: content.site,
|
|
131
|
+
path,
|
|
132
|
+
siteUrl: resolvedUrl
|
|
133
|
+
});
|
|
134
|
+
} catch (error) {
|
|
135
|
+
console.debug("[createCatchAllPage] Failed to generate metadata for path:", path, error);
|
|
136
|
+
return {
|
|
137
|
+
title: "Page Not Found",
|
|
138
|
+
robots: { index: false, follow: false }
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return {
|
|
143
|
+
Page: Page2,
|
|
144
|
+
generateMetadata: generateMetadataFn
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
exports.createCatchAllPage = createCatchAllPage;
|
|
150
|
+
//# sourceMappingURL=next.js.map
|