@riverbankcms/sdk 0.7.0 → 0.7.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.
Files changed (184) hide show
  1. package/README.md +229 -0
  2. package/dist/cli/index.js +42 -95
  3. package/dist/cli/index.js.map +1 -1
  4. package/dist/cli/init-docs/content/agents-section.md +50 -0
  5. package/dist/cli/init-docs/content/cli-reference.md +574 -0
  6. package/dist/cli/init-docs/content/content-management.md +384 -0
  7. package/dist/cli/init-docs/content/context-brand.md +125 -0
  8. package/dist/cli/init-docs/content/context-brief.md +77 -0
  9. package/dist/cli/init-docs/content/context-knowledge.md +111 -0
  10. package/dist/cli/init-docs/content/getting-started.md +130 -0
  11. package/dist/cli/init-docs/content/site-workflows-readme.md +96 -0
  12. package/dist/cli/init-docs/content/workflow-add-block.md +228 -0
  13. package/dist/cli/init-docs/content/workflow-create-page.md +193 -0
  14. package/dist/cli/init-docs/content/workflow-publish.md +280 -0
  15. package/dist/client/bookings.d.mts +2 -0
  16. package/dist/client/bookings.d.ts +2 -0
  17. package/dist/client/bookings.js +2956 -104
  18. package/dist/client/bookings.js.map +1 -1
  19. package/dist/client/bookings.mjs +2929 -70
  20. package/dist/client/bookings.mjs.map +1 -1
  21. package/dist/client/client.d.mts +2 -2
  22. package/dist/client/client.d.ts +2 -2
  23. package/dist/client/client.js +602 -68
  24. package/dist/client/client.js.map +1 -1
  25. package/dist/client/client.mjs +602 -68
  26. package/dist/client/client.mjs.map +1 -1
  27. package/dist/client/hooks.d.mts +2 -2
  28. package/dist/client/hooks.d.ts +2 -2
  29. package/dist/client/rendering/client.js +3070 -259
  30. package/dist/client/rendering/client.js.map +1 -1
  31. package/dist/client/rendering/client.mjs +3212 -395
  32. package/dist/client/rendering/client.mjs.map +1 -1
  33. package/dist/client/spam-protection.d.mts +55 -0
  34. package/dist/client/spam-protection.d.ts +55 -0
  35. package/dist/client/spam-protection.js +2915 -0
  36. package/dist/client/spam-protection.js.map +1 -0
  37. package/dist/client/spam-protection.mjs +2893 -0
  38. package/dist/client/spam-protection.mjs.map +1 -0
  39. package/dist/client/{usePage-BiOReg0_.d.ts → usePage-BYmJCCm1.d.ts} +132 -11
  40. package/dist/client/{usePage-BXjk8BhD.d.mts → usePage-DZtrWajy.d.mts} +132 -11
  41. package/dist/server/{Layout-wBtJLTVX.d.ts → Layout-Yluyb6sK.d.ts} +1 -1
  42. package/dist/server/{Layout-B7cvis7r.d.mts → Layout-qWLdVm5-.d.mts} +1 -1
  43. package/dist/server/chunk-2IZ6S225.js +122 -0
  44. package/dist/server/chunk-2IZ6S225.js.map +1 -0
  45. package/dist/server/chunk-4CV4JOE5.js +27 -0
  46. package/dist/server/chunk-4CV4JOE5.js.map +1 -0
  47. package/dist/server/chunk-5LRR64Y6.mjs +72 -0
  48. package/dist/server/chunk-5LRR64Y6.mjs.map +1 -0
  49. package/dist/server/chunk-NBTRDLCM.js +72 -0
  50. package/dist/server/chunk-NBTRDLCM.js.map +1 -0
  51. package/dist/server/chunk-NFEGQTCC.mjs +27 -0
  52. package/dist/server/{chunk-7FIJSGHU.mjs → chunk-NFQLH5IA.mjs} +856 -74
  53. package/dist/server/chunk-NFQLH5IA.mjs.map +1 -0
  54. package/dist/server/chunk-PPHZV6YD.mjs +122 -0
  55. package/dist/server/chunk-PPHZV6YD.mjs.map +1 -0
  56. package/dist/server/{chunk-P7UVAMK6.js → chunk-VLXTNB2C.js} +866 -84
  57. package/dist/server/chunk-VLXTNB2C.js.map +1 -0
  58. package/dist/server/{components-CMMwDXTW.d.mts → components-DNHfSCML.d.mts} +3 -3
  59. package/dist/server/{components-CICSJyp_.d.ts → components-Di5ME6He.d.ts} +3 -3
  60. package/dist/server/components.d.mts +5 -5
  61. package/dist/server/components.d.ts +5 -5
  62. package/dist/server/components.js +1 -1
  63. package/dist/server/components.mjs +1 -1
  64. package/dist/server/config-validation.js +1 -1
  65. package/dist/server/config-validation.mjs +1 -1
  66. package/dist/server/config.js +1 -1
  67. package/dist/server/config.mjs +1 -1
  68. package/dist/server/data.d.mts +2 -2
  69. package/dist/server/data.d.ts +2 -2
  70. package/dist/server/data.js +1 -1
  71. package/dist/server/data.mjs +1 -1
  72. package/dist/server/env.d.mts +109 -0
  73. package/dist/server/env.d.ts +109 -0
  74. package/dist/server/env.js +14 -0
  75. package/dist/server/env.js.map +1 -0
  76. package/dist/server/env.mjs +14 -0
  77. package/dist/server/{index-DI_qlYx3.d.mts → index--Oyunk_B.d.mts} +2 -2
  78. package/dist/server/{index-BTwWvSBu.d.ts → index-C9Ra8dza.d.ts} +2 -2
  79. package/dist/server/{index-Bucs6UqG.d.mts → index-Clm3skz_.d.mts} +1 -1
  80. package/dist/server/{index-Cp7tJuRt.d.ts → index-DLvNddi-.d.ts} +1 -1
  81. package/dist/server/index.d.mts +216 -5
  82. package/dist/server/index.d.ts +216 -5
  83. package/dist/server/index.js +301 -4
  84. package/dist/server/index.js.map +1 -1
  85. package/dist/server/index.mjs +301 -4
  86. package/dist/server/index.mjs.map +1 -1
  87. package/dist/server/{loadContent-DmgpFcFC.d.ts → loadContent-D7LQwI0o.d.ts} +3 -3
  88. package/dist/server/{loadContent-C-YYUKQa.d.mts → loadContent-DVfuBLiZ.d.mts} +3 -3
  89. package/dist/server/{loadPage-IDGVDFBB.js → loadPage-AXNAERDS.js} +2 -2
  90. package/dist/server/{loadPage-IDGVDFBB.js.map → loadPage-AXNAERDS.js.map} +1 -1
  91. package/dist/server/{loadPage-DP3nrHBi.d.ts → loadPage-BmYJCe_V.d.ts} +2 -2
  92. package/dist/server/{loadPage-B8mQUUSo.d.mts → loadPage-BucnLHmE.d.mts} +2 -2
  93. package/dist/server/{loadPage-DNQTTRHL.mjs → loadPage-XR7ORQ2E.mjs} +2 -2
  94. package/dist/server/loadPage-XR7ORQ2E.mjs.map +1 -0
  95. package/dist/server/metadata.d.mts +4 -4
  96. package/dist/server/metadata.d.ts +4 -4
  97. package/dist/server/metadata.js +1 -1
  98. package/dist/server/metadata.mjs +1 -1
  99. package/dist/server/navigation.d.mts +2 -2
  100. package/dist/server/navigation.d.ts +2 -2
  101. package/dist/server/navigation.js +1 -1
  102. package/dist/server/navigation.mjs +1 -1
  103. package/dist/server/next/revalidate.d.mts +66 -0
  104. package/dist/server/next/revalidate.d.ts +66 -0
  105. package/dist/server/next/revalidate.js +60 -0
  106. package/dist/server/next/revalidate.js.map +1 -0
  107. package/dist/server/next/revalidate.mjs +60 -0
  108. package/dist/server/next/revalidate.mjs.map +1 -0
  109. package/dist/server/next/tags.d.mts +81 -0
  110. package/dist/server/next/tags.d.ts +81 -0
  111. package/dist/server/next/tags.js +36 -0
  112. package/dist/server/next/tags.js.map +1 -0
  113. package/dist/server/next/tags.mjs +36 -0
  114. package/dist/server/next/tags.mjs.map +1 -0
  115. package/dist/server/next.d.mts +164 -6
  116. package/dist/server/next.d.ts +164 -6
  117. package/dist/server/next.js +79 -11
  118. package/dist/server/next.js.map +1 -1
  119. package/dist/server/next.mjs +76 -8
  120. package/dist/server/next.mjs.map +1 -1
  121. package/dist/server/rendering/server.d.mts +4 -4
  122. package/dist/server/rendering/server.d.ts +4 -4
  123. package/dist/server/rendering/server.js +1 -1
  124. package/dist/server/rendering/server.mjs +1 -1
  125. package/dist/server/rendering.d.mts +7 -7
  126. package/dist/server/rendering.d.ts +7 -7
  127. package/dist/server/rendering.js +3 -3
  128. package/dist/server/rendering.js.map +1 -1
  129. package/dist/server/rendering.mjs +4 -4
  130. package/dist/server/routing.d.mts +3 -3
  131. package/dist/server/routing.d.ts +3 -3
  132. package/dist/server/routing.js +2 -2
  133. package/dist/server/routing.mjs +2 -2
  134. package/dist/server/server.d.mts +5 -5
  135. package/dist/server/server.d.ts +5 -5
  136. package/dist/server/server.js +5 -5
  137. package/dist/server/server.js.map +1 -1
  138. package/dist/server/server.mjs +5 -5
  139. package/dist/server/theme-bridge.js +1 -1
  140. package/dist/server/theme-bridge.mjs +1 -1
  141. package/dist/server/theme.js +1 -1
  142. package/dist/server/theme.mjs +1 -1
  143. package/dist/server/{types-BvcJU7zk.d.ts → types-BRQyLrQU.d.ts} +132 -11
  144. package/dist/server/{types-Dsu9wsUh.d.mts → types-BSV6Vc-P.d.mts} +2 -2
  145. package/dist/server/{types-1cLz0vnq.d.mts → types-C-LShyIg.d.mts} +132 -11
  146. package/dist/server/{types-CVykEqXN.d.ts → types-Dt98DeYa.d.ts} +2 -2
  147. package/dist/server/webhooks.d.mts +81 -0
  148. package/dist/server/webhooks.d.ts +81 -0
  149. package/dist/server/webhooks.js +12 -0
  150. package/dist/server/webhooks.js.map +1 -0
  151. package/dist/server/webhooks.mjs +12 -0
  152. package/dist/server/webhooks.mjs.map +1 -0
  153. package/package.json +29 -3
  154. package/dist/client/resolver-BhueZVxZ.d.mts +0 -61
  155. package/dist/client/resolver-BhueZVxZ.d.ts +0 -61
  156. package/dist/client/usePage--fGlyrgj.d.mts +0 -6439
  157. package/dist/client/usePage-BBcFCxOU.d.ts +0 -6297
  158. package/dist/client/usePage-BC8Q2E3t.d.mts +0 -6431
  159. package/dist/client/usePage-BTPnCuWC.d.mts +0 -6511
  160. package/dist/client/usePage-BafOS9UT.d.mts +0 -6512
  161. package/dist/client/usePage-BcjWPXvh.d.mts +0 -6388
  162. package/dist/client/usePage-Bnx-kA6x.d.mts +0 -6670
  163. package/dist/client/usePage-BvKAa3Zw.d.mts +0 -366
  164. package/dist/client/usePage-BvKAa3Zw.d.ts +0 -366
  165. package/dist/client/usePage-BydHcMYB.d.mts +0 -6297
  166. package/dist/client/usePage-C3ZKNwY7.d.mts +0 -6393
  167. package/dist/client/usePage-CE7X5NcN.d.ts +0 -6439
  168. package/dist/client/usePage-CHEybPMD.d.ts +0 -6429
  169. package/dist/client/usePage-CrKw1H6Y.d.ts +0 -6338
  170. package/dist/client/usePage-CyYpOJud.d.ts +0 -6388
  171. package/dist/client/usePage-D4fxZbRR.d.mts +0 -6429
  172. package/dist/client/usePage-DMI8ImsU.d.mts +0 -6338
  173. package/dist/client/usePage-DoPI6b8V.d.ts +0 -6511
  174. package/dist/client/usePage-DpRNZUtP.d.ts +0 -6431
  175. package/dist/client/usePage-QNWArrVO.d.ts +0 -6670
  176. package/dist/client/usePage-fBgPB6Oq.d.ts +0 -6512
  177. package/dist/client/usePage-gpVaeWDy.d.ts +0 -6393
  178. package/dist/server/chunk-7FIJSGHU.mjs.map +0 -1
  179. package/dist/server/chunk-BJTO5JO5.mjs +0 -11
  180. package/dist/server/chunk-DGUM43GV.js +0 -11
  181. package/dist/server/chunk-DGUM43GV.js.map +0 -1
  182. package/dist/server/chunk-P7UVAMK6.js.map +0 -1
  183. /package/dist/server/{chunk-BJTO5JO5.mjs.map → chunk-NFEGQTCC.mjs.map} +0 -0
  184. /package/dist/server/{loadPage-DNQTTRHL.mjs.map → env.mjs.map} +0 -0
@@ -1,11 +1,11 @@
1
1
  import { ReactNode, ComponentType } from 'react';
2
- import { R as RiverbankClient } from './types-BvcJU7zk.js';
2
+ import { R as RiverbankClient } from './types-BRQyLrQU.js';
3
3
  import { R as RiverbankSiteConfig } from './types-DLBhEPSt.js';
4
- import { B as BlockOverrides } from './loadPage-DP3nrHBi.js';
4
+ import { B as BlockOverrides } from './loadPage-BmYJCe_V.js';
5
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';
6
+ import { M as Metadata } from './index-C9Ra8dza.js';
7
+ import { b as LoadContentResult } from './loadContent-D7LQwI0o.js';
8
+ import './types-Dt98DeYa.js';
9
9
  import '@riverbankcms/ai';
10
10
  import 'zod';
11
11
  import './link-DjxLyC82.js';
@@ -271,4 +271,162 @@ interface CreateCatchAllPageResult {
271
271
  */
272
272
  declare function createCatchAllPage(options: CreateCatchAllPageOptions): CreateCatchAllPageResult;
273
273
 
274
- export { type CatchAllContext, type CatchAllPageProps, type CreateCatchAllPageOptions, type CreateCatchAllPageResult, createCatchAllPage };
274
+ /**
275
+ * Static params generation for Next.js SSG
276
+ *
277
+ * Provides helpers for generating static params from published CMS routes.
278
+ *
279
+ * @example
280
+ * ```tsx
281
+ * // app/[[...slug]]/page.tsx
282
+ * import { generateAllStaticParams } from '@riverbankcms/sdk/next';
283
+ *
284
+ * export { generateAllStaticParams as generateStaticParams };
285
+ * ```
286
+ */
287
+ /**
288
+ * Environment variable validation result
289
+ */
290
+ type StaticParamsEnvResult = {
291
+ valid: true;
292
+ config: {
293
+ apiKey: string;
294
+ siteId: string;
295
+ baseUrl: string;
296
+ };
297
+ } | {
298
+ valid: false;
299
+ missingVars: string[];
300
+ };
301
+ /**
302
+ * Validate that all required environment variables are set.
303
+ *
304
+ * Required env vars:
305
+ * - RIVERBANK_API_KEY: API key for published content
306
+ * - RIVERBANK_SITE_ID: Site ID
307
+ * - NEXT_PUBLIC_DASHBOARD_URL: Dashboard API URL
308
+ *
309
+ * @returns Validation result with config or missing vars
310
+ */
311
+ declare function validateStaticParamsEnv(): StaticParamsEnvResult;
312
+ /**
313
+ * Convert a route path to a Next.js slug array.
314
+ *
315
+ * @param path - The route path (e.g., '/about', '/blog/post')
316
+ * @returns The slug array for Next.js catch-all route
317
+ *
318
+ * @example
319
+ * ```ts
320
+ * pathToSlugArray('/') // []
321
+ * pathToSlugArray('/about') // ['about']
322
+ * pathToSlugArray('/blog/post') // ['blog', 'post']
323
+ * ```
324
+ */
325
+ declare function pathToSlugArray(path: string): string[];
326
+ /**
327
+ * Generate static params for all published routes.
328
+ *
329
+ * This function fetches all published routes from the CMS and converts them
330
+ * to the static params format expected by Next.js catch-all routes.
331
+ *
332
+ * Requires environment variables:
333
+ * - RIVERBANK_API_KEY: API key for published content
334
+ * - RIVERBANK_SITE_ID: Site ID
335
+ * - NEXT_PUBLIC_DASHBOARD_URL: Dashboard API URL
336
+ *
337
+ * @throws Error if required env vars are missing (prevents silent empty SSG in CI)
338
+ * @returns Array of static params objects for Next.js
339
+ *
340
+ * @example
341
+ * ```tsx
342
+ * // app/[[...slug]]/page.tsx
343
+ * import { generateAllStaticParams } from '@riverbankcms/sdk/next';
344
+ *
345
+ * export { generateAllStaticParams as generateStaticParams };
346
+ *
347
+ * // Or with custom logic:
348
+ * export async function generateStaticParams() {
349
+ * const params = await generateAllStaticParams();
350
+ * // Filter or modify params as needed
351
+ * return params.filter(p => !p.slug.includes('private'));
352
+ * }
353
+ * ```
354
+ */
355
+ declare function generateAllStaticParams(): Promise<{
356
+ slug: string[];
357
+ }[]>;
358
+
359
+ /**
360
+ * Next.js integration helpers for Riverbank CMS SDK.
361
+ *
362
+ * Provides opinionated factories for common Next.js patterns, reducing
363
+ * boilerplate while maintaining full customizability through escape hatches.
364
+ *
365
+ * @example Basic catch-all page
366
+ * ```tsx
367
+ * // src/app/[[...slug]]/page.tsx
368
+ * import { createCatchAllPage } from '@riverbankcms/sdk/next';
369
+ * import { getRiverbankClient } from '@/lib/builder-client';
370
+ * import config from '@/riverbank.config';
371
+ *
372
+ * const { Page, generateMetadata } = createCatchAllPage({
373
+ * getClient: getRiverbankClient,
374
+ * config,
375
+ * });
376
+ *
377
+ * export default Page;
378
+ * export { generateMetadata };
379
+ * ```
380
+ *
381
+ * @example With customization
382
+ * ```tsx
383
+ * const { Page, generateMetadata } = createCatchAllPage({
384
+ * getClient,
385
+ * config,
386
+ * blockOverrides: { hero: MyCustomHero },
387
+ * beforeRender: async () => {
388
+ * if (process.env.MAINTENANCE_MODE === 'true') {
389
+ * return <MaintenancePage />;
390
+ * }
391
+ * return null;
392
+ * },
393
+ * });
394
+ * ```
395
+ *
396
+ * @packageDocumentation
397
+ */
398
+
399
+ /**
400
+ * ISR revalidation duration in seconds for production mode.
401
+ * 5 minutes provides a good balance between freshness and performance.
402
+ */
403
+ declare const ISR_REVALIDATE_SECONDS = 300;
404
+ interface ISRConfig {
405
+ /**
406
+ * Revalidation interval in seconds.
407
+ * - 0: Dynamic rendering (no caching) - used in preview mode
408
+ * - 300: 5 minute ISR - used in production mode
409
+ */
410
+ revalidate: number | false;
411
+ /**
412
+ * Whether the current environment is in preview mode.
413
+ * Useful for conditional rendering or data fetching behavior.
414
+ */
415
+ isPreview: boolean;
416
+ }
417
+ /**
418
+ * Get ISR configuration based on the current environment.
419
+ *
420
+ * @example
421
+ * ```tsx
422
+ * // app/[[...slug]]/page.tsx
423
+ * import { getISRConfig } from '@riverbankcms/sdk/next';
424
+ *
425
+ * export const revalidate = getISRConfig().revalidate;
426
+ * ```
427
+ *
428
+ * @returns ISR configuration with revalidate interval and preview flag
429
+ */
430
+ declare function getISRConfig(): ISRConfig;
431
+
432
+ export { type CatchAllContext, type CatchAllPageProps, type CreateCatchAllPageOptions, type CreateCatchAllPageResult, type ISRConfig, ISR_REVALIDATE_SECONDS, type StaticParamsEnvResult, createCatchAllPage, generateAllStaticParams, getISRConfig, pathToSlugArray, validateStaticParamsEnv };
@@ -4,6 +4,12 @@
4
4
  var _chunkBNQV3PXPjs = require('./chunk-BNQV3PXP.js');
5
5
 
6
6
 
7
+ var _chunk2IZ6S225js = require('./chunk-2IZ6S225.js');
8
+
9
+
10
+ var _chunkVLXTNB2Cjs = require('./chunk-VLXTNB2C.js');
11
+
12
+
7
13
 
8
14
 
9
15
  var _chunkJWRNMNWIjs = require('./chunk-JWRNMNWI.js');
@@ -13,14 +19,12 @@ var _chunkT26N3P26js = require('./chunk-T26N3P26.js');
13
19
  require('./chunk-7UPVCT3K.js');
14
20
  require('./chunk-RVDS7VSP.js');
15
21
  require('./chunk-YYO3RIFO.js');
16
-
17
-
18
- var _chunkDGUM43GVjs = require('./chunk-DGUM43GV.js');
22
+ require('./chunk-4CV4JOE5.js');
19
23
 
20
24
  // src/next/catch-all.tsx
25
+ var _navigation = require('next/navigation');
21
26
  var _jsxruntime = require('react/jsx-runtime');
22
- var { notFound } = _chunkDGUM43GVjs.__require.call(void 0, "next/navigation");
23
- function isPreviewMode() {
27
+ function isPreviewMode2() {
24
28
  return process.env.RIVERBANK_PREVIEW_MODE === "true";
25
29
  }
26
30
  function slugToPath(slug) {
@@ -43,7 +47,7 @@ function createCatchAllPage(options) {
43
47
  _nullishCoalesce(searchParamsPromise, () => ( Promise.resolve({})))
44
48
  ]);
45
49
  const path = slugToPath(slug);
46
- const preview = isPreviewMode();
50
+ const preview = isPreviewMode2();
47
51
  const client = getClient();
48
52
  let content;
49
53
  try {
@@ -55,7 +59,7 @@ function createCatchAllPage(options) {
55
59
  });
56
60
  } catch (error) {
57
61
  console.debug("[createCatchAllPage] Failed to load content for path:", path, error);
58
- return notFound();
62
+ return _navigation.notFound.call(void 0, );
59
63
  }
60
64
  if (beforeRender) {
61
65
  const intercepted = await beforeRender({ content, path, preview, searchParams });
@@ -77,7 +81,7 @@ function createCatchAllPage(options) {
77
81
  );
78
82
  } else if (_chunkJWRNMNWIjs.isEntryContent.call(void 0, content)) {
79
83
  if (!content.templatePage) {
80
- return notFound();
84
+ return _navigation.notFound.call(void 0, );
81
85
  }
82
86
  rendered = /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
83
87
  _chunkT26N3P26js.Page,
@@ -93,7 +97,7 @@ function createCatchAllPage(options) {
93
97
  }
94
98
  );
95
99
  } else {
96
- return notFound();
100
+ return _navigation.notFound.call(void 0, );
97
101
  }
98
102
  return Wrapper ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Wrapper, { children: rendered }) : rendered;
99
103
  }
@@ -103,7 +107,7 @@ function createCatchAllPage(options) {
103
107
  _nullishCoalesce(searchParamsPromise, () => ( Promise.resolve({})))
104
108
  ]);
105
109
  const path = slugToPath(slug);
106
- const preview = isPreviewMode();
110
+ const preview = isPreviewMode2();
107
111
  try {
108
112
  const content = await _chunkJWRNMNWIjs.loadContent.call(void 0, {
109
113
  client: getClient(),
@@ -145,6 +149,70 @@ function createCatchAllPage(options) {
145
149
  };
146
150
  }
147
151
 
152
+ // src/rendering/hooks/usePage.ts
153
+ var _react = require('react');
154
+
155
+ // src/rendering/hooks/useContent.ts
156
+
157
+
158
+ // src/next/static-params.ts
159
+ function validateStaticParamsEnv() {
160
+ const apiKey = process.env.RIVERBANK_API_KEY;
161
+ const siteId = process.env.RIVERBANK_SITE_ID;
162
+ const baseUrl = process.env.NEXT_PUBLIC_DASHBOARD_URL;
163
+ const missingVars = [];
164
+ if (!apiKey) missingVars.push("RIVERBANK_API_KEY");
165
+ if (!siteId) missingVars.push("RIVERBANK_SITE_ID");
166
+ if (!baseUrl) missingVars.push("NEXT_PUBLIC_DASHBOARD_URL");
167
+ if (missingVars.length > 0) {
168
+ return { valid: false, missingVars };
169
+ }
170
+ return {
171
+ valid: true,
172
+ config: { apiKey, siteId, baseUrl }
173
+ };
174
+ }
175
+ function pathToSlugArray(path) {
176
+ if (path === "/") return [];
177
+ return path.slice(1).split("/");
178
+ }
179
+ async function generateAllStaticParams() {
180
+ const envResult = validateStaticParamsEnv();
181
+ if (!envResult.valid) {
182
+ throw new Error(
183
+ `[Riverbank] generateAllStaticParams requires env vars: ${envResult.missingVars.join(", ")}. This error prevents accidentally deploying with zero static pages.`
184
+ );
185
+ }
186
+ const { apiKey, siteId: _siteId, baseUrl } = envResult.config;
187
+ const _client = _chunkVLXTNB2Cjs.createRiverbankClient.call(void 0, {
188
+ apiKey,
189
+ baseUrl,
190
+ // Disable caching for build-time fetches
191
+ cache: { enabled: false },
192
+ // Disable resilience for build-time fetches (want fast failure)
193
+ resilience: { enabled: false }
194
+ });
195
+ console.warn(
196
+ "[Riverbank] generateAllStaticParams: getAllPublishedRoutes API not yet implemented. Pages will be generated on-demand with ISR."
197
+ );
198
+ return [{ slug: [] }];
199
+ }
200
+
201
+ // src/next/index.ts
202
+ var ISR_REVALIDATE_SECONDS = 300;
203
+ function getISRConfig() {
204
+ const preview = _chunk2IZ6S225js.isPreviewMode.call(void 0, );
205
+ return {
206
+ revalidate: preview ? 0 : ISR_REVALIDATE_SECONDS,
207
+ isPreview: preview
208
+ };
209
+ }
210
+
211
+
212
+
213
+
214
+
215
+
148
216
 
149
- exports.createCatchAllPage = createCatchAllPage;
217
+ exports.ISR_REVALIDATE_SECONDS = ISR_REVALIDATE_SECONDS; exports.createCatchAllPage = createCatchAllPage; exports.generateAllStaticParams = generateAllStaticParams; exports.getISRConfig = getISRConfig; exports.pathToSlugArray = pathToSlugArray; exports.validateStaticParamsEnv = validateStaticParamsEnv;
150
218
  //# sourceMappingURL=next.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/will/Projects/Business/cms/builder/packages/sdk/dist/server/next.js","../../src/next/catch-all.tsx"],"names":["Page"],"mappings":"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","file":"/Users/will/Projects/Business/cms/builder/packages/sdk/dist/server/next.js","sourcesContent":[null,"/**\n * Next.js catch-all page factory for Riverbank CMS.\n *\n * Provides a simple, opinionated way to render CMS content in Next.js catch-all routes.\n * Reduces typical page.tsx boilerplate from ~160 lines to ~10 lines.\n *\n * @example\n * ```tsx\n * // src/app/[[...slug]]/page.tsx\n * import { createCatchAllPage } from '@riverbankcms/sdk/next';\n * import { getRiverbankClient } from '@/lib/builder-client';\n * import config from '@/riverbank.config';\n *\n * const { Page, generateMetadata } = createCatchAllPage({\n * getClient: getRiverbankClient,\n * config,\n * blockOverrides: { hero: MyCustomHero },\n * });\n *\n * export default Page;\n * export { generateMetadata };\n * ```\n */\n\n// Note: next is a peerDependency - this module only works in Next.js projects.\n// We use require() with a type cast because Next.js's notFound() is typed as () => never\n// but TypeScript doesn't infer this from the dynamic import, causing false\n// \"unreachable code\" warnings without explicit type information.\nconst { notFound } = require('next/navigation') as { notFound: () => never };\n\nimport {\n loadContent,\n isPageContent,\n isEntryContent,\n} from '../rendering/helpers/loadContent';\nimport type { LoadContentResult } from '../rendering/helpers/loadContent';\nimport { Page as PageComponent } from '../rendering/components/Page';\nimport {\n generatePageMetadata,\n generatePreviewMetadata,\n type Metadata,\n} from '../metadata/generatePageMetadata';\nimport type {\n CreateCatchAllPageOptions,\n CatchAllPageProps,\n CreateCatchAllPageResult,\n} from './types';\n\n/**\n * Detect preview mode from environment variable.\n *\n * Sites can enable preview mode by setting:\n * ```\n * RIVERBANK_PREVIEW_MODE=true\n * ```\n *\n * This is typically set in preview/staging environments to fetch\n * draft content instead of published content.\n */\nfunction isPreviewMode(): boolean {\n return process.env.RIVERBANK_PREVIEW_MODE === 'true';\n}\n\n/**\n * Convert URL slug segments to a path string.\n *\n * @example\n * ```\n * slugToPath(undefined) // '/'\n * slugToPath([]) // '/'\n * slugToPath(['about']) // '/about'\n * slugToPath(['blog', 'post']) // '/blog/post'\n * ```\n */\nfunction slugToPath(slug?: string[]): string {\n if (!slug || slug.length === 0) return '/';\n return '/' + slug.join('/');\n}\n\n/**\n * Factory function to create a Next.js catch-all page component and metadata generator.\n *\n * This provides a simple, opinionated setup for rendering Riverbank CMS content\n * in external SDK sites. It handles:\n *\n * - Page and content entry routing\n * - Preview mode detection (via `RIVERBANK_PREVIEW_MODE` env var)\n * - SEO metadata generation\n * - Block overrides for custom components\n * - 404 handling for missing content\n *\n * ## Escape Hatches\n *\n * For customization beyond the defaults, use these options:\n *\n * - `beforeRender`: Intercept before rendering (maintenance mode, access control)\n * - `customMetadata`: Full control over SEO metadata\n * - `wrapper`: Wrap all content (analytics, error boundaries)\n *\n * For maximum control, use the lower-level helpers directly:\n * - `loadContent()` from `@riverbankcms/sdk/rendering`\n * - `Page` component from `@riverbankcms/sdk/rendering`\n * - `generatePageMetadata()` from `@riverbankcms/sdk/metadata`\n *\n * @param options - Configuration options\n * @returns Object with `Page` component and `generateMetadata` function\n *\n * @example Basic usage\n * ```tsx\n * const { Page, generateMetadata } = createCatchAllPage({\n * getClient: getRiverbankClient,\n * config,\n * });\n *\n * export default Page;\n * export { generateMetadata };\n * ```\n *\n * @example With maintenance mode\n * ```tsx\n * const { Page, generateMetadata } = createCatchAllPage({\n * getClient,\n * config,\n * beforeRender: async () => {\n * if (process.env.MAINTENANCE_MODE === 'true') {\n * return <MaintenancePage />;\n * }\n * return null;\n * },\n * });\n * ```\n */\nexport function createCatchAllPage(\n options: CreateCatchAllPageOptions\n): CreateCatchAllPageResult {\n const {\n getClient,\n config,\n blockOverrides,\n siteUrl,\n beforeRender,\n customMetadata,\n wrapper: Wrapper,\n } = options;\n\n /**\n * Main page component that loads and renders CMS content.\n */\n async function Page({ params, searchParams: searchParamsPromise }: CatchAllPageProps): Promise<React.ReactNode> {\n const [{ slug }, searchParams] = await Promise.all([\n params,\n searchParamsPromise ?? Promise.resolve({}),\n ]);\n const path = slugToPath(slug);\n const preview = isPreviewMode();\n const client = getClient();\n\n // Load content (page or entry)\n let content: LoadContentResult;\n try {\n content = await loadContent({\n client,\n siteId: config.siteId,\n path,\n preview,\n });\n } catch (error) {\n // Log the error for debugging - could be a network error, auth failure, etc.\n // We treat all errors as \"not found\" since the page can't be rendered\n console.debug('[createCatchAllPage] Failed to load content for path:', path, error);\n return notFound();\n }\n\n // ESCAPE HATCH: beforeRender for maintenance mode, access control, etc.\n if (beforeRender) {\n const intercepted = await beforeRender({ content, path, preview, searchParams });\n if (intercepted !== null) {\n return Wrapper ? <Wrapper>{intercepted}</Wrapper> : intercepted;\n }\n }\n\n let rendered: React.ReactNode;\n\n // Render page content\n if (isPageContent(content)) {\n rendered = (\n <PageComponent\n page={content.page}\n theme={content.theme}\n siteId={content.siteId}\n resolvedData={content.resolvedData}\n blockOverrides={blockOverrides}\n />\n );\n }\n // Render entry content with template\n else if (isEntryContent(content)) {\n // Entries without template pages should 404\n if (!content.templatePage) {\n return notFound();\n }\n\n rendered = (\n <PageComponent\n page={content.templatePage}\n theme={content.theme}\n siteId={content.siteId}\n resolvedData={content.resolvedData}\n blockOverrides={blockOverrides}\n dataContext={{\n contentEntry: content.dataContext.contentEntry,\n }}\n />\n );\n }\n // Unexpected content type - should never happen\n else {\n return notFound();\n }\n\n return Wrapper ? <Wrapper>{rendered}</Wrapper> : rendered;\n }\n\n /**\n * Generate SEO metadata for the page.\n */\n async function generateMetadataFn({ params, searchParams: searchParamsPromise }: CatchAllPageProps): Promise<Metadata> {\n const [{ slug }, searchParams] = await Promise.all([\n params,\n searchParamsPromise ?? Promise.resolve({}),\n ]);\n const path = slugToPath(slug);\n const preview = isPreviewMode();\n\n try {\n const content = await loadContent({\n client: getClient(),\n siteId: config.siteId,\n path,\n preview,\n });\n\n // ESCAPE HATCH: Custom metadata generation\n if (customMetadata) {\n return customMetadata({ content, path, preview, searchParams });\n }\n\n // Resolve site URL (use config URLs as fallback)\n const resolvedUrl =\n siteUrl ?? (preview ? config.previewUrl : config.liveUrl) ?? '';\n\n // Warn if no site URL is configured - OG/Twitter tags require absolute URLs\n if (!resolvedUrl) {\n console.warn(\n '[createCatchAllPage] No siteUrl configured. OpenGraph and Twitter tags will have relative URLs which may cause social sharing previews to fail. ' +\n 'Set siteUrl option, or config.liveUrl/config.previewUrl in your riverbank.config.'\n );\n }\n\n // Build page object for metadata\n // For entries, we use metaTitle/metaDescription; purpose is used as description fallback\n const page = isPageContent(content)\n ? content.page\n : isEntryContent(content)\n ? {\n name: content.entry.metaTitle ?? content.entry.title,\n purpose: content.entry.metaDescription ?? undefined,\n }\n : { name: 'Page' };\n\n // Use preview metadata (noindex) in preview mode\n const metadataGenerator = preview\n ? generatePreviewMetadata\n : generatePageMetadata;\n\n // Use site data from loadContent result (no duplicate API call needed)\n return metadataGenerator({\n page,\n site: content.site,\n path,\n siteUrl: resolvedUrl,\n });\n } catch (error) {\n // Log the error for debugging purposes\n console.debug('[createCatchAllPage] Failed to generate metadata for path:', path, error);\n // Return minimal metadata on error - page will handle the actual 404\n return {\n title: 'Page Not Found',\n robots: { index: false, follow: false },\n };\n }\n }\n\n return {\n Page,\n generateMetadata: generateMetadataFn,\n };\n}\n"]}
1
+ {"version":3,"sources":["/Users/will/Projects/Business/cms/builder/packages/sdk/dist/server/next.js","../../src/next/catch-all.tsx","../../src/rendering/hooks/usePage.ts","../../src/rendering/hooks/useContent.ts","../../src/next/static-params.ts","../../src/next/index.ts"],"names":["isPreviewMode","Page"],"mappings":"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","file":"/Users/will/Projects/Business/cms/builder/packages/sdk/dist/server/next.js","sourcesContent":[null,"/**\n * Next.js catch-all page factory for Riverbank CMS.\n *\n * Provides a simple, opinionated way to render CMS content in Next.js catch-all routes.\n * Reduces typical page.tsx boilerplate from ~160 lines to ~10 lines.\n *\n * @example\n * ```tsx\n * // src/app/[[...slug]]/page.tsx\n * import { createCatchAllPage } from '@riverbankcms/sdk/next';\n * import { getRiverbankClient } from '@/lib/builder-client';\n * import config from '@/riverbank.config';\n *\n * const { Page, generateMetadata } = createCatchAllPage({\n * getClient: getRiverbankClient,\n * config,\n * blockOverrides: { hero: MyCustomHero },\n * });\n *\n * export default Page;\n * export { generateMetadata };\n * ```\n */\n\n// Note: next is a peerDependency - this module only works in Next.js projects.\nimport { notFound } from 'next/navigation';\n\nimport {\n loadContent,\n isPageContent,\n isEntryContent,\n} from '../rendering/helpers/loadContent';\nimport type { LoadContentResult } from '../rendering/helpers/loadContent';\nimport { Page as PageComponent } from '../rendering/components/Page';\nimport {\n generatePageMetadata,\n generatePreviewMetadata,\n type Metadata,\n} from '../metadata/generatePageMetadata';\nimport type {\n CreateCatchAllPageOptions,\n CatchAllPageProps,\n CreateCatchAllPageResult,\n} from './types';\n\n/**\n * Detect preview mode from environment variable.\n *\n * Sites can enable preview mode by setting:\n * ```\n * RIVERBANK_PREVIEW_MODE=true\n * ```\n *\n * This is typically set in preview/staging environments to fetch\n * draft content instead of published content.\n */\nfunction isPreviewMode(): boolean {\n return process.env.RIVERBANK_PREVIEW_MODE === 'true';\n}\n\n/**\n * Convert URL slug segments to a path string.\n *\n * @example\n * ```\n * slugToPath(undefined) // '/'\n * slugToPath([]) // '/'\n * slugToPath(['about']) // '/about'\n * slugToPath(['blog', 'post']) // '/blog/post'\n * ```\n */\nfunction slugToPath(slug?: string[]): string {\n if (!slug || slug.length === 0) return '/';\n return '/' + slug.join('/');\n}\n\n/**\n * Factory function to create a Next.js catch-all page component and metadata generator.\n *\n * This provides a simple, opinionated setup for rendering Riverbank CMS content\n * in external SDK sites. It handles:\n *\n * - Page and content entry routing\n * - Preview mode detection (via `RIVERBANK_PREVIEW_MODE` env var)\n * - SEO metadata generation\n * - Block overrides for custom components\n * - 404 handling for missing content\n *\n * ## Escape Hatches\n *\n * For customization beyond the defaults, use these options:\n *\n * - `beforeRender`: Intercept before rendering (maintenance mode, access control)\n * - `customMetadata`: Full control over SEO metadata\n * - `wrapper`: Wrap all content (analytics, error boundaries)\n *\n * For maximum control, use the lower-level helpers directly:\n * - `loadContent()` from `@riverbankcms/sdk/rendering`\n * - `Page` component from `@riverbankcms/sdk/rendering`\n * - `generatePageMetadata()` from `@riverbankcms/sdk/metadata`\n *\n * @param options - Configuration options\n * @returns Object with `Page` component and `generateMetadata` function\n *\n * @example Basic usage\n * ```tsx\n * const { Page, generateMetadata } = createCatchAllPage({\n * getClient: getRiverbankClient,\n * config,\n * });\n *\n * export default Page;\n * export { generateMetadata };\n * ```\n *\n * @example With maintenance mode\n * ```tsx\n * const { Page, generateMetadata } = createCatchAllPage({\n * getClient,\n * config,\n * beforeRender: async () => {\n * if (process.env.MAINTENANCE_MODE === 'true') {\n * return <MaintenancePage />;\n * }\n * return null;\n * },\n * });\n * ```\n */\nexport function createCatchAllPage(\n options: CreateCatchAllPageOptions\n): CreateCatchAllPageResult {\n const {\n getClient,\n config,\n blockOverrides,\n siteUrl,\n beforeRender,\n customMetadata,\n wrapper: Wrapper,\n } = options;\n\n /**\n * Main page component that loads and renders CMS content.\n */\n async function Page({ params, searchParams: searchParamsPromise }: CatchAllPageProps): Promise<React.ReactNode> {\n const [{ slug }, searchParams] = await Promise.all([\n params,\n searchParamsPromise ?? Promise.resolve({}),\n ]);\n const path = slugToPath(slug);\n const preview = isPreviewMode();\n const client = getClient();\n\n // Load content (page or entry)\n let content: LoadContentResult;\n try {\n content = await loadContent({\n client,\n siteId: config.siteId,\n path,\n preview,\n });\n } catch (error) {\n // Log the error for debugging - could be a network error, auth failure, etc.\n // We treat all errors as \"not found\" since the page can't be rendered\n console.debug('[createCatchAllPage] Failed to load content for path:', path, error);\n return notFound();\n }\n\n // ESCAPE HATCH: beforeRender for maintenance mode, access control, etc.\n if (beforeRender) {\n const intercepted = await beforeRender({ content, path, preview, searchParams });\n if (intercepted !== null) {\n return Wrapper ? <Wrapper>{intercepted}</Wrapper> : intercepted;\n }\n }\n\n let rendered: React.ReactNode;\n\n // Render page content\n if (isPageContent(content)) {\n rendered = (\n <PageComponent\n page={content.page}\n theme={content.theme}\n siteId={content.siteId}\n resolvedData={content.resolvedData}\n blockOverrides={blockOverrides}\n />\n );\n }\n // Render entry content with template\n else if (isEntryContent(content)) {\n // Entries without template pages should 404\n if (!content.templatePage) {\n return notFound();\n }\n\n rendered = (\n <PageComponent\n page={content.templatePage}\n theme={content.theme}\n siteId={content.siteId}\n resolvedData={content.resolvedData}\n blockOverrides={blockOverrides}\n dataContext={{\n contentEntry: content.dataContext.contentEntry,\n }}\n />\n );\n }\n // Unexpected content type - should never happen\n else {\n return notFound();\n }\n\n return Wrapper ? <Wrapper>{rendered}</Wrapper> : rendered;\n }\n\n /**\n * Generate SEO metadata for the page.\n */\n async function generateMetadataFn({ params, searchParams: searchParamsPromise }: CatchAllPageProps): Promise<Metadata> {\n const [{ slug }, searchParams] = await Promise.all([\n params,\n searchParamsPromise ?? Promise.resolve({}),\n ]);\n const path = slugToPath(slug);\n const preview = isPreviewMode();\n\n try {\n const content = await loadContent({\n client: getClient(),\n siteId: config.siteId,\n path,\n preview,\n });\n\n // ESCAPE HATCH: Custom metadata generation\n if (customMetadata) {\n return customMetadata({ content, path, preview, searchParams });\n }\n\n // Resolve site URL (use config URLs as fallback)\n const resolvedUrl =\n siteUrl ?? (preview ? config.previewUrl : config.liveUrl) ?? '';\n\n // Warn if no site URL is configured - OG/Twitter tags require absolute URLs\n if (!resolvedUrl) {\n console.warn(\n '[createCatchAllPage] No siteUrl configured. OpenGraph and Twitter tags will have relative URLs which may cause social sharing previews to fail. ' +\n 'Set siteUrl option, or config.liveUrl/config.previewUrl in your riverbank.config.'\n );\n }\n\n // Build page object for metadata\n // For entries, we use metaTitle/metaDescription; purpose is used as description fallback\n const page = isPageContent(content)\n ? content.page\n : isEntryContent(content)\n ? {\n name: content.entry.metaTitle ?? content.entry.title,\n purpose: content.entry.metaDescription ?? undefined,\n }\n : { name: 'Page' };\n\n // Use preview metadata (noindex) in preview mode\n const metadataGenerator = preview\n ? generatePreviewMetadata\n : generatePageMetadata;\n\n // Use site data from loadContent result (no duplicate API call needed)\n return metadataGenerator({\n page,\n site: content.site,\n path,\n siteUrl: resolvedUrl,\n });\n } catch (error) {\n // Log the error for debugging purposes\n console.debug('[createCatchAllPage] Failed to generate metadata for path:', path, error);\n // Return minimal metadata on error - page will handle the actual 404\n return {\n title: 'Page Not Found',\n robots: { index: false, follow: false },\n };\n }\n }\n\n return {\n Page,\n generateMetadata: generateMetadataFn,\n };\n}\n","/**\n * Client-side React hook to fetch page data.\n *\n * Use this in client components for dynamic page loading.\n */\n\nimport { useState, useEffect } from 'react';\nimport type { RiverbankClient } from '../../client/types';\nimport type { PageProps } from '../components/Page';\nimport type { RuntimeSdkConfig } from '../helpers/loadPage';\nimport { prefetchBlockData } from '../../data/prefetchBlockData';\n\nexport type UsePageParams = {\n client: RiverbankClient;\n siteId: string;\n path: string;\n pageId?: string;\n /**\n * If true, fetches draft/unpublished content instead of published content.\n * This affects both the page structure and block data loaders.\n * Requires API key with site access.\n *\n * @default false\n */\n preview?: boolean;\n};\n\nexport type UsePageResult =\n | { loading: true; error: null; page: null; theme: null; siteId: string; resolvedData: null; sdkConfig: null }\n | { loading: false; error: Error; page: null; theme: null; siteId: string; resolvedData: null; sdkConfig: null }\n | { loading: false; error: null; sdkConfig: RuntimeSdkConfig | null } & Omit<PageProps, 'registry' | 'wrapBlock' | 'usePlaceholders' | 'sdkConfig'>;\n\n/**\n * Client-side React hook to fetch all data needed for <Page> component.\n *\n * Fetches site data, page data, and prefetches block data loaders.\n * Returns loading and error states for proper UI handling.\n *\n * IMPORTANT: The client object should be stable across renders to avoid\n * unnecessary re-fetches. Create it outside your component or use useMemo:\n *\n * ```tsx\n * // ✅ Good - stable reference\n * const client = useMemo(\n * () => createRiverbankClient({ apiKey, baseUrl }),\n * [apiKey, baseUrl]\n * );\n *\n * // ❌ Bad - new client on every render (causes infinite loops)\n * const client = createRiverbankClient({ apiKey, baseUrl });\n * ```\n *\n * @example Basic usage\n * ```tsx\n * import { createRiverbankClient } from '@riverbankcms/sdk';\n * import { usePage, Page } from '@riverbankcms/sdk/rendering';\n *\n * const client = createRiverbankClient({\n * apiKey: process.env.NEXT_PUBLIC_RIVERBANK_API_KEY!,\n * baseUrl: process.env.NEXT_PUBLIC_DASHBOARD_URL + '/api',\n * });\n *\n * function MyPage({ path }: { path: string }) {\n * const pageData = usePage({ client, siteId: 'site-123', path });\n *\n * if (pageData.loading) {\n * return <div>Loading...</div>;\n * }\n *\n * if (pageData.error) {\n * return <div>Error: {pageData.error.message}</div>;\n * }\n *\n * return <Page {...pageData} />;\n * }\n * ```\n *\n * @example With custom loading/error states\n * ```tsx\n * function MyPage({ path }: { path: string }) {\n * const pageData = usePage({ client, siteId: 'site-123', path });\n *\n * if (pageData.loading) {\n * return <Skeleton />;\n * }\n *\n * if (pageData.error) {\n * return (\n * <ErrorBoundary\n * error={pageData.error}\n * onRetry={() => window.location.reload()}\n * />\n * );\n * }\n *\n * return <Page {...pageData} />;\n * }\n * ```\n */\nexport function usePage(params: UsePageParams): UsePageResult {\n const { client, siteId, path, pageId, preview = false } = params;\n\n const [result, setResult] = useState<UsePageResult>({\n loading: true,\n error: null,\n page: null,\n theme: null,\n siteId,\n resolvedData: null,\n sdkConfig: null,\n });\n\n useEffect(() => {\n let cancelled = false;\n\n async function fetchPage() {\n try {\n // Fetch site and page data in parallel\n const [site, pageResponse] = await Promise.all([\n client.getSite({ id: siteId }),\n client.getPage({ siteId, path, preview }),\n ]);\n\n // If component unmounted, don't update state\n if (cancelled) return;\n\n // Extract page data (getContentByPath can return page or entry)\n if ('entry' in pageResponse) {\n throw new Error(\n 'This path resolves to a content entry, not a page. ' +\n 'Use useContent() instead, which handles both pages and entries. ' +\n 'For entries, useContent() returns the raw entry data for custom rendering.'\n );\n }\n\n const { page: pageData } = pageResponse;\n\n // Convert API response blocks to PageOutline format\n // API returns blocks with full content, but PageOutline only needs structure\n const blocks = pageData.blocks.map((block) => {\n if (!block || typeof block !== 'object') {\n throw new Error('Invalid block format in API response');\n }\n if (typeof block.id !== 'string' && block.id !== null) {\n throw new Error(`Invalid block id: expected string or null, got ${typeof block.id}`);\n }\n if (typeof block.kind !== 'string') {\n throw new Error(`Invalid block kind: expected string, got ${typeof block.kind}`);\n }\n if (typeof block.purpose !== 'string') {\n throw new Error(`Invalid block purpose: expected string, got ${typeof block.purpose}`);\n }\n return {\n id: block.id,\n kind: block.kind,\n purpose: block.purpose,\n };\n });\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\n const resolvedData = await prefetchBlockData(\n pageOutline,\n {\n siteId,\n pageId: pageId ?? pageData.id,\n previewStage: preview ? 'preview' : 'published',\n },\n client\n );\n\n // If component unmounted, don't update state\n if (cancelled) return;\n\n setResult({\n loading: false,\n error: null,\n page: pageOutline,\n theme: site.theme,\n siteId,\n resolvedData,\n sdkConfig: site.sdkConfig ?? null,\n });\n } catch (error) {\n if (cancelled) return;\n\n setResult({\n loading: false,\n error: error instanceof Error ? error : new Error(String(error)),\n page: null,\n theme: null,\n siteId,\n resolvedData: null,\n sdkConfig: null,\n });\n }\n }\n\n fetchPage();\n\n return () => {\n cancelled = true;\n };\n }, [client, siteId, path, pageId, preview]);\n\n return result;\n}\n","/**\n * Client-side React hook to fetch content (page or entry) by path.\n *\n * Use this in client components for dynamic routing where a path\n * could resolve to either a page or content entry.\n */\n\nimport { useState, useEffect } from 'react';\nimport type { Theme } from '@riverbankcms/blocks';\nimport type { RiverbankClient, PageResponse } from '../../client/types';\nimport type { PageProps } from '../components/Page';\nimport { prefetchBlockData } from '../../data/prefetchBlockData';\nimport type { ResolvedBlockData } from '../../data/prefetchBlockData';\nimport type { ContentEntryData } from '../helpers/loadContent';\n\nexport type UseContentParams = {\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 * Loading state\n */\ntype LoadingState = {\n loading: true;\n error: null;\n type: null;\n page: null;\n entry: null;\n theme: null;\n siteId: string;\n resolvedData: null;\n};\n\n/**\n * Error state\n */\ntype ErrorState = {\n loading: false;\n error: Error;\n type: null;\n page: null;\n entry: null;\n theme: null;\n siteId: string;\n resolvedData: null;\n};\n\n/**\n * Success state for page content\n */\ntype PageSuccessState = {\n loading: false;\n error: null;\n type: 'page';\n page: PageProps['page'];\n entry: null;\n theme: Theme;\n siteId: string;\n resolvedData: ResolvedBlockData;\n};\n\n/**\n * Success state for entry content\n */\ntype EntrySuccessState = {\n loading: false;\n error: null;\n type: 'entry';\n page: null;\n entry: ContentEntryData;\n theme: Theme;\n siteId: string;\n resolvedData: null;\n};\n\nexport type UseContentResult = LoadingState | ErrorState | PageSuccessState | EntrySuccessState;\n\n/**\n * Type guard to check if result is loading\n */\nexport function isContentLoading(result: UseContentResult): result is LoadingState {\n return result.loading === true;\n}\n\n/**\n * Type guard to check if result has an error\n */\nexport function isContentError(result: UseContentResult): result is ErrorState {\n return result.loading === false && result.error !== null;\n}\n\n/**\n * Type guard to check if result is a page\n */\nexport function isPageContentResult(result: UseContentResult): result is PageSuccessState {\n return result.loading === false && result.error === null && result.type === 'page';\n}\n\n/**\n * Type guard to check if result is an entry\n */\nexport function isEntryContentResult(result: UseContentResult): result is EntrySuccessState {\n return result.loading === false && result.error === null && result.type === 'entry';\n}\n\n/**\n * Client-side React hook to fetch content by path.\n *\n * Returns a discriminated union with loading/error states, and either\n * page data (ready for `<Page>` component) or raw entry data (for custom rendering).\n *\n * IMPORTANT: The client object should be stable across renders to avoid\n * unnecessary re-fetches. Create it outside your component or use useMemo.\n *\n * @example Dynamic routing with both pages and entries\n * ```tsx\n * \"use client\";\n *\n * import { useContent, Page, isPageContentResult } from '@riverbankcms/sdk/client';\n *\n * function DynamicPage({ path }: { path: string }) {\n * const content = useContent({ client, siteId: 'site-123', path });\n *\n * if (content.loading) return <div>Loading...</div>;\n * if (content.error) return <div>Error: {content.error.message}</div>;\n *\n * if (isPageContentResult(content)) {\n * return <Page page={content.page} theme={content.theme} siteId={content.siteId} resolvedData={content.resolvedData} />;\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 = useContent({ client, siteId, path });\n *\n * if (content.loading) return <Spinner />;\n * if (content.error) return <Error error={content.error} />;\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 * }\n * }\n *\n * return <Page {...content} />;\n * ```\n */\nexport function useContent(params: UseContentParams): UseContentResult {\n const { client, siteId, path, preview = false } = params;\n\n const [result, setResult] = useState<UseContentResult>({\n loading: true,\n error: null,\n type: null,\n page: null,\n entry: null,\n theme: null,\n siteId,\n resolvedData: null,\n });\n\n useEffect(() => {\n let cancelled = false;\n\n async function fetchContent() {\n try {\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 // If component unmounted, don't update state\n if (cancelled) return;\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 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 setResult({\n loading: false,\n error: null,\n type: 'entry',\n page: null,\n entry,\n theme: site.theme,\n siteId,\n resolvedData: null,\n });\n return;\n }\n\n // Handle page response\n const { page: pageData } = contentResponse;\n\n // Convert API response blocks to PageOutline format\n const blocks = pageData.blocks.map((block) => {\n if (!block || typeof block !== 'object') {\n throw new Error('Invalid block format in API response');\n }\n if (typeof block.id !== 'string' && block.id !== null) {\n throw new Error(`Invalid block id: expected string or null, got ${typeof block.id}`);\n }\n if (typeof block.kind !== 'string') {\n throw new Error(`Invalid block kind: expected string, got ${typeof block.kind}`);\n }\n if (typeof block.purpose !== 'string') {\n throw new Error(`Invalid block purpose: expected string, got ${typeof block.purpose}`);\n }\n return {\n id: block.id,\n kind: block.kind,\n purpose: block.purpose,\n };\n });\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 // If component unmounted, don't update state\n if (cancelled) return;\n\n setResult({\n loading: false,\n error: null,\n type: 'page',\n page: pageOutline,\n entry: null,\n theme: site.theme,\n siteId,\n resolvedData,\n });\n } catch (error) {\n if (cancelled) return;\n\n setResult({\n loading: false,\n error: error instanceof Error ? error : new Error(String(error)),\n type: null,\n page: null,\n entry: null,\n theme: null,\n siteId,\n resolvedData: null,\n });\n }\n }\n\n fetchContent();\n\n return () => {\n cancelled = true;\n };\n }, [client, siteId, path, preview]);\n\n return result;\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 * Static params generation for Next.js SSG\n *\n * Provides helpers for generating static params from published CMS routes.\n *\n * @example\n * ```tsx\n * // app/[[...slug]]/page.tsx\n * import { generateAllStaticParams } from '@riverbankcms/sdk/next';\n *\n * export { generateAllStaticParams as generateStaticParams };\n * ```\n */\n\nimport { createRiverbankClient } from '../client';\n\n/**\n * Environment variable validation result\n */\nexport type StaticParamsEnvResult =\n | { valid: true; config: { apiKey: string; siteId: string; baseUrl: string } }\n | { valid: false; missingVars: string[] };\n\n/**\n * Validate that all required environment variables are set.\n *\n * Required env vars:\n * - RIVERBANK_API_KEY: API key for published content\n * - RIVERBANK_SITE_ID: Site ID\n * - NEXT_PUBLIC_DASHBOARD_URL: Dashboard API URL\n *\n * @returns Validation result with config or missing vars\n */\nexport function validateStaticParamsEnv(): StaticParamsEnvResult {\n const apiKey = process.env.RIVERBANK_API_KEY;\n const siteId = process.env.RIVERBANK_SITE_ID;\n const baseUrl = process.env.NEXT_PUBLIC_DASHBOARD_URL;\n\n const missingVars: string[] = [];\n\n if (!apiKey) missingVars.push('RIVERBANK_API_KEY');\n if (!siteId) missingVars.push('RIVERBANK_SITE_ID');\n if (!baseUrl) missingVars.push('NEXT_PUBLIC_DASHBOARD_URL');\n\n if (missingVars.length > 0) {\n return { valid: false, missingVars };\n }\n\n // TypeScript can't narrow through the checks above, so assert non-null\n return {\n valid: true,\n config: { apiKey: apiKey!, siteId: siteId!, baseUrl: baseUrl! },\n };\n}\n\n/**\n * Convert a route path to a Next.js slug array.\n *\n * @param path - The route path (e.g., '/about', '/blog/post')\n * @returns The slug array for Next.js catch-all route\n *\n * @example\n * ```ts\n * pathToSlugArray('/') // []\n * pathToSlugArray('/about') // ['about']\n * pathToSlugArray('/blog/post') // ['blog', 'post']\n * ```\n */\nexport function pathToSlugArray(path: string): string[] {\n if (path === '/') return [];\n return path.slice(1).split('/');\n}\n\n/**\n * Generate static params for all published routes.\n *\n * This function fetches all published routes from the CMS and converts them\n * to the static params format expected by Next.js catch-all routes.\n *\n * Requires environment variables:\n * - RIVERBANK_API_KEY: API key for published content\n * - RIVERBANK_SITE_ID: Site ID\n * - NEXT_PUBLIC_DASHBOARD_URL: Dashboard API URL\n *\n * @throws Error if required env vars are missing (prevents silent empty SSG in CI)\n * @returns Array of static params objects for Next.js\n *\n * @example\n * ```tsx\n * // app/[[...slug]]/page.tsx\n * import { generateAllStaticParams } from '@riverbankcms/sdk/next';\n *\n * export { generateAllStaticParams as generateStaticParams };\n *\n * // Or with custom logic:\n * export async function generateStaticParams() {\n * const params = await generateAllStaticParams();\n * // Filter or modify params as needed\n * return params.filter(p => !p.slug.includes('private'));\n * }\n * ```\n */\nexport async function generateAllStaticParams(): Promise<{ slug: string[] }[]> {\n const envResult = validateStaticParamsEnv();\n\n if (!envResult.valid) {\n throw new Error(\n `[Riverbank] generateAllStaticParams requires env vars: ${envResult.missingVars.join(', ')}. ` +\n `This error prevents accidentally deploying with zero static pages.`\n );\n }\n\n const { apiKey, siteId: _siteId, baseUrl } = envResult.config;\n\n // Create client (unused until getAllPublishedRoutes is implemented)\n const _client = createRiverbankClient({\n apiKey,\n baseUrl,\n // Disable caching for build-time fetches\n cache: { enabled: false },\n // Disable resilience for build-time fetches (want fast failure)\n resilience: { enabled: false },\n });\n\n // TODO: This requires adding getAllPublishedRoutes to the client\n // which requires the CMS endpoint to be updated to accept API key auth\n // and support the publishedOnly query param.\n //\n // For now, we'll use getPage to fetch the site's homepage which contains\n // the navigation data, and extract routes from there.\n //\n // In the future, implement:\n // const routes = await client.getAllPublishedRoutes({ siteId });\n // return routes.map(path => ({ slug: pathToSlugArray(path) }));\n\n // Temporary: Return empty array with warning\n // This allows the helper to be used but won't pre-render any pages\n console.warn(\n '[Riverbank] generateAllStaticParams: getAllPublishedRoutes API not yet implemented. ' +\n 'Pages will be generated on-demand with ISR.'\n );\n\n // Return at least the homepage\n return [{ slug: [] }];\n}\n","/**\n * Next.js integration helpers for Riverbank CMS SDK.\n *\n * Provides opinionated factories for common Next.js patterns, reducing\n * boilerplate while maintaining full customizability through escape hatches.\n *\n * @example Basic catch-all page\n * ```tsx\n * // src/app/[[...slug]]/page.tsx\n * import { createCatchAllPage } from '@riverbankcms/sdk/next';\n * import { getRiverbankClient } from '@/lib/builder-client';\n * import config from '@/riverbank.config';\n *\n * const { Page, generateMetadata } = createCatchAllPage({\n * getClient: getRiverbankClient,\n * config,\n * });\n *\n * export default Page;\n * export { generateMetadata };\n * ```\n *\n * @example With customization\n * ```tsx\n * const { Page, generateMetadata } = createCatchAllPage({\n * getClient,\n * config,\n * blockOverrides: { hero: MyCustomHero },\n * beforeRender: async () => {\n * if (process.env.MAINTENANCE_MODE === 'true') {\n * return <MaintenancePage />;\n * }\n * return null;\n * },\n * });\n * ```\n *\n * @packageDocumentation\n */\n\nimport { isPreviewMode } from '../env';\n\n// Catch-all page factory\nexport { createCatchAllPage } from './catch-all';\nexport type {\n CreateCatchAllPageOptions,\n CreateCatchAllPageResult,\n CatchAllPageProps,\n CatchAllContext,\n} from './types';\n\n// Static params utilities\nexport {\n generateAllStaticParams,\n validateStaticParamsEnv,\n pathToSlugArray,\n type StaticParamsEnvResult,\n} from './static-params';\n\n/**\n * ISR revalidation duration in seconds for production mode.\n * 5 minutes provides a good balance between freshness and performance.\n */\nexport const ISR_REVALIDATE_SECONDS = 300;\n\nexport interface ISRConfig {\n /**\n * Revalidation interval in seconds.\n * - 0: Dynamic rendering (no caching) - used in preview mode\n * - 300: 5 minute ISR - used in production mode\n */\n revalidate: number | false;\n\n /**\n * Whether the current environment is in preview mode.\n * Useful for conditional rendering or data fetching behavior.\n */\n isPreview: boolean;\n}\n\n/**\n * Get ISR configuration based on the current environment.\n *\n * @example\n * ```tsx\n * // app/[[...slug]]/page.tsx\n * import { getISRConfig } from '@riverbankcms/sdk/next';\n *\n * export const revalidate = getISRConfig().revalidate;\n * ```\n *\n * @returns ISR configuration with revalidate interval and preview flag\n */\nexport function getISRConfig(): ISRConfig {\n const preview = isPreviewMode();\n return {\n revalidate: preview ? 0 : ISR_REVALIDATE_SECONDS,\n isPreview: preview,\n };\n}\n"]}
@@ -2,6 +2,12 @@ import {
2
2
  generatePageMetadata,
3
3
  generatePreviewMetadata
4
4
  } from "./chunk-SWYWZT3L.mjs";
5
+ import {
6
+ isPreviewMode
7
+ } from "./chunk-PPHZV6YD.mjs";
8
+ import {
9
+ createRiverbankClient
10
+ } from "./chunk-NFQLH5IA.mjs";
5
11
  import {
6
12
  isEntryContent,
7
13
  isPageContent,
@@ -13,14 +19,12 @@ import {
13
19
  import "./chunk-LNOUXALA.mjs";
14
20
  import "./chunk-AEFWG657.mjs";
15
21
  import "./chunk-BYBJA6SP.mjs";
16
- import {
17
- __require
18
- } from "./chunk-BJTO5JO5.mjs";
22
+ import "./chunk-NFEGQTCC.mjs";
19
23
 
20
24
  // src/next/catch-all.tsx
25
+ import { notFound } from "next/navigation";
21
26
  import { jsx } from "react/jsx-runtime";
22
- var { notFound } = __require("next/navigation");
23
- function isPreviewMode() {
27
+ function isPreviewMode2() {
24
28
  return process.env.RIVERBANK_PREVIEW_MODE === "true";
25
29
  }
26
30
  function slugToPath(slug) {
@@ -43,7 +47,7 @@ function createCatchAllPage(options) {
43
47
  searchParamsPromise ?? Promise.resolve({})
44
48
  ]);
45
49
  const path = slugToPath(slug);
46
- const preview = isPreviewMode();
50
+ const preview = isPreviewMode2();
47
51
  const client = getClient();
48
52
  let content;
49
53
  try {
@@ -103,7 +107,7 @@ function createCatchAllPage(options) {
103
107
  searchParamsPromise ?? Promise.resolve({})
104
108
  ]);
105
109
  const path = slugToPath(slug);
106
- const preview = isPreviewMode();
110
+ const preview = isPreviewMode2();
107
111
  try {
108
112
  const content = await loadContent({
109
113
  client: getClient(),
@@ -144,7 +148,71 @@ function createCatchAllPage(options) {
144
148
  generateMetadata: generateMetadataFn
145
149
  };
146
150
  }
151
+
152
+ // src/rendering/hooks/usePage.ts
153
+ import { useState, useEffect } from "react";
154
+
155
+ // src/rendering/hooks/useContent.ts
156
+ import { useState as useState2, useEffect as useEffect2 } from "react";
157
+
158
+ // src/next/static-params.ts
159
+ function validateStaticParamsEnv() {
160
+ const apiKey = process.env.RIVERBANK_API_KEY;
161
+ const siteId = process.env.RIVERBANK_SITE_ID;
162
+ const baseUrl = process.env.NEXT_PUBLIC_DASHBOARD_URL;
163
+ const missingVars = [];
164
+ if (!apiKey) missingVars.push("RIVERBANK_API_KEY");
165
+ if (!siteId) missingVars.push("RIVERBANK_SITE_ID");
166
+ if (!baseUrl) missingVars.push("NEXT_PUBLIC_DASHBOARD_URL");
167
+ if (missingVars.length > 0) {
168
+ return { valid: false, missingVars };
169
+ }
170
+ return {
171
+ valid: true,
172
+ config: { apiKey, siteId, baseUrl }
173
+ };
174
+ }
175
+ function pathToSlugArray(path) {
176
+ if (path === "/") return [];
177
+ return path.slice(1).split("/");
178
+ }
179
+ async function generateAllStaticParams() {
180
+ const envResult = validateStaticParamsEnv();
181
+ if (!envResult.valid) {
182
+ throw new Error(
183
+ `[Riverbank] generateAllStaticParams requires env vars: ${envResult.missingVars.join(", ")}. This error prevents accidentally deploying with zero static pages.`
184
+ );
185
+ }
186
+ const { apiKey, siteId: _siteId, baseUrl } = envResult.config;
187
+ const _client = createRiverbankClient({
188
+ apiKey,
189
+ baseUrl,
190
+ // Disable caching for build-time fetches
191
+ cache: { enabled: false },
192
+ // Disable resilience for build-time fetches (want fast failure)
193
+ resilience: { enabled: false }
194
+ });
195
+ console.warn(
196
+ "[Riverbank] generateAllStaticParams: getAllPublishedRoutes API not yet implemented. Pages will be generated on-demand with ISR."
197
+ );
198
+ return [{ slug: [] }];
199
+ }
200
+
201
+ // src/next/index.ts
202
+ var ISR_REVALIDATE_SECONDS = 300;
203
+ function getISRConfig() {
204
+ const preview = isPreviewMode();
205
+ return {
206
+ revalidate: preview ? 0 : ISR_REVALIDATE_SECONDS,
207
+ isPreview: preview
208
+ };
209
+ }
147
210
  export {
148
- createCatchAllPage
211
+ ISR_REVALIDATE_SECONDS,
212
+ createCatchAllPage,
213
+ generateAllStaticParams,
214
+ getISRConfig,
215
+ pathToSlugArray,
216
+ validateStaticParamsEnv
149
217
  };
150
218
  //# sourceMappingURL=next.mjs.map