@riverbankcms/sdk 0.4.2 → 0.5.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.
Files changed (180) hide show
  1. package/README.md +84 -0
  2. package/dist/cli/index.js +3104 -120
  3. package/dist/cli/index.js.map +1 -1
  4. package/dist/client/analytics.js +1 -1
  5. package/dist/client/analytics.js.map +1 -1
  6. package/dist/client/analytics.mjs +1 -1
  7. package/dist/client/analytics.mjs.map +1 -1
  8. package/dist/client/bookings.js +6 -6
  9. package/dist/client/bookings.js.map +1 -1
  10. package/dist/client/bookings.mjs +6 -6
  11. package/dist/client/bookings.mjs.map +1 -1
  12. package/dist/client/client.d.mts +2 -2
  13. package/dist/client/client.d.ts +2 -2
  14. package/dist/client/client.js +1368 -520
  15. package/dist/client/client.js.map +1 -1
  16. package/dist/client/client.mjs +1368 -520
  17. package/dist/client/client.mjs.map +1 -1
  18. package/dist/client/hooks.d.mts +2 -2
  19. package/dist/client/hooks.d.ts +2 -2
  20. package/dist/client/hooks.js +26 -11
  21. package/dist/client/hooks.js.map +1 -1
  22. package/dist/client/hooks.mjs +26 -11
  23. package/dist/client/hooks.mjs.map +1 -1
  24. package/dist/client/rendering/client.js +24 -14
  25. package/dist/client/rendering/client.js.map +1 -1
  26. package/dist/client/rendering/client.mjs +24 -14
  27. package/dist/client/rendering/client.mjs.map +1 -1
  28. package/dist/client/usePage--fGlyrgj.d.mts +6439 -0
  29. package/dist/client/usePage-BTPnCuWC.d.mts +6511 -0
  30. package/dist/client/usePage-BafOS9UT.d.mts +6512 -0
  31. package/dist/client/usePage-Bnx-kA6x.d.mts +6670 -0
  32. package/dist/client/usePage-CE7X5NcN.d.ts +6439 -0
  33. package/dist/client/usePage-DoPI6b8V.d.ts +6511 -0
  34. package/dist/client/usePage-QNWArrVO.d.ts +6670 -0
  35. package/dist/client/usePage-fBgPB6Oq.d.ts +6512 -0
  36. package/dist/server/{Layout-kRv5sU81.d.ts → Layout-B-q2Py4v.d.ts} +4 -4
  37. package/dist/server/{Layout-ByUnm35V.d.mts → Layout-Cc5HUXAH.d.mts} +4 -4
  38. package/dist/server/{chunk-6JBKKV3G.js → chunk-2KCF2DNK.js} +30 -10
  39. package/dist/server/chunk-2KCF2DNK.js.map +1 -0
  40. package/dist/server/{chunk-N3PX76AP.mjs → chunk-4HIRA33Z.mjs} +247 -135
  41. package/dist/server/chunk-4HIRA33Z.mjs.map +1 -0
  42. package/dist/server/chunk-5STV4MWD.js +189 -0
  43. package/dist/server/chunk-5STV4MWD.js.map +1 -0
  44. package/dist/server/{chunk-R5B6IOFQ.js → chunk-6OSNCH4F.js} +247 -135
  45. package/dist/server/chunk-6OSNCH4F.js.map +1 -0
  46. package/dist/server/{chunk-TKMA6D6U.js → chunk-7UPVCT3K.js} +1215 -497
  47. package/dist/server/chunk-7UPVCT3K.js.map +1 -0
  48. package/dist/server/{chunk-7DS4Q3GA.mjs → chunk-AEFWG657.mjs} +3 -3
  49. package/dist/server/chunk-AEFWG657.mjs.map +1 -0
  50. package/dist/server/{chunk-USQF2XTU.mjs → chunk-BYBJA6SP.mjs} +26 -11
  51. package/dist/server/chunk-BYBJA6SP.mjs.map +1 -0
  52. package/dist/server/{chunk-ZEAJW6T3.mjs → chunk-C6FIJC7T.mjs} +4 -3
  53. package/dist/server/chunk-C6FIJC7T.mjs.map +1 -0
  54. package/dist/server/{chunk-TO7FD6TQ.js → chunk-I2D7KOEA.js} +4 -4
  55. package/dist/server/{chunk-TO7FD6TQ.js.map → chunk-I2D7KOEA.js.map} +1 -1
  56. package/dist/server/chunk-KFLZGNPO.mjs +189 -0
  57. package/dist/server/chunk-KFLZGNPO.mjs.map +1 -0
  58. package/dist/server/chunk-L5EA4FXU.mjs +134 -0
  59. package/dist/server/chunk-L5EA4FXU.mjs.map +1 -0
  60. package/dist/server/{chunk-TNRADRPH.mjs → chunk-LNOUXALA.mjs} +1137 -419
  61. package/dist/server/chunk-LNOUXALA.mjs.map +1 -0
  62. package/dist/server/{chunk-SPXMMX3C.mjs → chunk-OSF34JTQ.mjs} +4 -4
  63. package/dist/server/{chunk-SWPHIUVE.js → chunk-P3NNN73G.js} +5 -4
  64. package/dist/server/chunk-P3NNN73G.js.map +1 -0
  65. package/dist/server/{chunk-I6K5REFT.mjs → chunk-P4K63SBZ.mjs} +24 -4
  66. package/dist/server/chunk-P4K63SBZ.mjs.map +1 -0
  67. package/dist/server/{chunk-HOY77YBF.js → chunk-RVDS7VSP.js} +5 -5
  68. package/dist/server/chunk-RVDS7VSP.js.map +1 -0
  69. package/dist/server/{chunk-NW5KHH4A.js → chunk-TT5JWA4X.js} +9 -9
  70. package/dist/server/{chunk-NW5KHH4A.js.map → chunk-TT5JWA4X.js.map} +1 -1
  71. package/dist/server/chunk-VSFQRHYZ.js +134 -0
  72. package/dist/server/chunk-VSFQRHYZ.js.map +1 -0
  73. package/dist/server/{chunk-EGTDJ4PL.js → chunk-YYO3RIFO.js} +26 -11
  74. package/dist/server/chunk-YYO3RIFO.js.map +1 -0
  75. package/dist/server/{chunk-OP2GHK27.mjs → chunk-Z5ZA6Q4D.mjs} +2 -2
  76. package/dist/server/{components-D1Z2mSDr.d.ts → components-CU46ZkAv.d.mts} +20 -75
  77. package/dist/server/{components-CY8jDQjv.d.mts → components-DvozDwRN.d.ts} +20 -75
  78. package/dist/server/components.d.mts +11 -8
  79. package/dist/server/components.d.ts +11 -8
  80. package/dist/server/components.js +5 -4
  81. package/dist/server/components.js.map +1 -1
  82. package/dist/server/components.mjs +4 -3
  83. package/dist/server/config-validation.d.mts +3 -3
  84. package/dist/server/config-validation.d.ts +3 -3
  85. package/dist/server/config-validation.js +9 -5
  86. package/dist/server/config-validation.js.map +1 -1
  87. package/dist/server/config-validation.mjs +8 -4
  88. package/dist/server/config.d.mts +243 -5
  89. package/dist/server/config.d.ts +243 -5
  90. package/dist/server/config.js +72 -5
  91. package/dist/server/config.js.map +1 -1
  92. package/dist/server/config.mjs +72 -5
  93. package/dist/server/config.mjs.map +1 -1
  94. package/dist/server/core-DsNWrl3o.d.mts +44 -0
  95. package/dist/server/core-DsNWrl3o.d.ts +44 -0
  96. package/dist/server/data.d.mts +4 -3
  97. package/dist/server/data.d.ts +4 -3
  98. package/dist/server/data.js +3 -3
  99. package/dist/server/data.mjs +2 -2
  100. package/dist/server/{index-DCIz9Ptv.d.ts → index-CJfMXZQr.d.ts} +2 -1
  101. package/dist/server/{index-DFQwtj3J.d.mts → index-Q7RLMAQ6.d.mts} +2 -1
  102. package/dist/server/index.d.mts +63 -6
  103. package/dist/server/index.d.ts +63 -6
  104. package/dist/server/index.js +91 -2
  105. package/dist/server/index.js.map +1 -1
  106. package/dist/server/index.mjs +90 -1
  107. package/dist/server/index.mjs.map +1 -1
  108. package/dist/server/link-DjxLyC82.d.mts +23 -0
  109. package/dist/server/link-DjxLyC82.d.ts +23 -0
  110. package/dist/server/{loadContent-CWuE8FCx.d.mts → loadContent-DgpSKWqY.d.mts} +4 -4
  111. package/dist/server/{loadContent-DynBuR5f.d.ts → loadContent-GPvUI1bN.d.ts} +4 -4
  112. package/dist/server/{loadPage-B8RmlYgV.d.mts → loadPage-DGnIK7s4.d.mts} +17 -47
  113. package/dist/server/loadPage-DNQTTRHL.mjs +11 -0
  114. package/dist/server/{loadPage-BTkKpizX.d.ts → loadPage-DW9WB-u9.d.ts} +17 -47
  115. package/dist/server/loadPage-IDGVDFBB.js +11 -0
  116. package/dist/server/{loadPage-DUHBXDEW.js.map → loadPage-IDGVDFBB.js.map} +1 -1
  117. package/dist/server/metadata.d.mts +6 -4
  118. package/dist/server/metadata.d.ts +6 -4
  119. package/dist/server/navigation.d.mts +199 -29
  120. package/dist/server/navigation.d.ts +199 -29
  121. package/dist/server/navigation.js +27 -43
  122. package/dist/server/navigation.js.map +1 -1
  123. package/dist/server/navigation.mjs +20 -36
  124. package/dist/server/navigation.mjs.map +1 -1
  125. package/dist/server/rendering/server.d.mts +8 -6
  126. package/dist/server/rendering/server.d.ts +8 -6
  127. package/dist/server/rendering/server.js +7 -6
  128. package/dist/server/rendering/server.js.map +1 -1
  129. package/dist/server/rendering/server.mjs +6 -5
  130. package/dist/server/rendering.d.mts +14 -10
  131. package/dist/server/rendering.d.ts +14 -10
  132. package/dist/server/rendering.js +9 -8
  133. package/dist/server/rendering.js.map +1 -1
  134. package/dist/server/rendering.mjs +8 -7
  135. package/dist/server/richTextSchema-DURiozvD.d.mts +62 -0
  136. package/dist/server/richTextSchema-DURiozvD.d.ts +62 -0
  137. package/dist/server/routing.d.mts +178 -11
  138. package/dist/server/routing.d.ts +178 -11
  139. package/dist/server/routing.js +95 -2
  140. package/dist/server/routing.js.map +1 -1
  141. package/dist/server/routing.mjs +94 -1
  142. package/dist/server/routing.mjs.map +1 -1
  143. package/dist/server/{schema-Bpy9N5ZI.d.ts → schema-Z6-afHJG.d.mts} +1 -1
  144. package/dist/server/{schema-Bpy9N5ZI.d.mts → schema-Z6-afHJG.d.ts} +1 -1
  145. package/dist/server/server.d.mts +9 -7
  146. package/dist/server/server.d.ts +9 -7
  147. package/dist/server/server.js +6 -6
  148. package/dist/server/server.mjs +5 -5
  149. package/dist/server/theme-bridge.js +8 -8
  150. package/dist/server/theme-bridge.mjs +2 -2
  151. package/dist/server/{types-oCM-fw4O.d.ts → types-0f4PIlgx.d.mts} +55 -2
  152. package/dist/server/{types-txWsSxN7.d.mts → types-BjgZt8xJ.d.mts} +63 -2
  153. package/dist/server/{types-BiRZnxDx.d.ts → types-C28kMfa1.d.ts} +256 -82
  154. package/dist/server/{types-CL916r6x.d.ts → types-DLBhEPSt.d.ts} +63 -2
  155. package/dist/server/{types-CdrJqlKx.d.mts → types-DuzJZKJI.d.mts} +256 -82
  156. package/dist/server/{types-DkKEctWn.d.mts → types-kOQyCFXO.d.ts} +55 -2
  157. package/dist/server/{validation-DzvDwwRo.d.mts → validation-BGuRo8P1.d.mts} +18 -5
  158. package/dist/server/{validation-CoU8uAiu.d.ts → validation-DU2YE7u5.d.ts} +18 -5
  159. package/package.json +5 -3
  160. package/dist/server/chunk-6JBKKV3G.js.map +0 -1
  161. package/dist/server/chunk-7BOIO2S7.mjs +0 -833
  162. package/dist/server/chunk-7BOIO2S7.mjs.map +0 -1
  163. package/dist/server/chunk-7DS4Q3GA.mjs.map +0 -1
  164. package/dist/server/chunk-BLKVTULP.js +0 -833
  165. package/dist/server/chunk-BLKVTULP.js.map +0 -1
  166. package/dist/server/chunk-EGTDJ4PL.js.map +0 -1
  167. package/dist/server/chunk-HOY77YBF.js.map +0 -1
  168. package/dist/server/chunk-I6K5REFT.mjs.map +0 -1
  169. package/dist/server/chunk-N3PX76AP.mjs.map +0 -1
  170. package/dist/server/chunk-R5B6IOFQ.js.map +0 -1
  171. package/dist/server/chunk-SWPHIUVE.js.map +0 -1
  172. package/dist/server/chunk-TKMA6D6U.js.map +0 -1
  173. package/dist/server/chunk-TNRADRPH.mjs.map +0 -1
  174. package/dist/server/chunk-USQF2XTU.mjs.map +0 -1
  175. package/dist/server/chunk-ZEAJW6T3.mjs.map +0 -1
  176. package/dist/server/loadPage-DUHBXDEW.js +0 -11
  177. package/dist/server/loadPage-LYVKY3WZ.mjs +0 -11
  178. /package/dist/server/{chunk-SPXMMX3C.mjs.map → chunk-OSF34JTQ.mjs.map} +0 -0
  179. /package/dist/server/{chunk-OP2GHK27.mjs.map → chunk-Z5ZA6Q4D.mjs.map} +0 -0
  180. /package/dist/server/{loadPage-LYVKY3WZ.mjs.map → loadPage-DNQTTRHL.mjs.map} +0 -0
@@ -1,5 +1,34 @@
1
1
  import "./chunk-BJTO5JO5.mjs";
2
2
 
3
+ // src/routing/checkRedirect.ts
4
+ async function checkRedirectForPath(params) {
5
+ const { client, siteId, path } = params;
6
+ try {
7
+ const response = await client.checkRedirect({
8
+ siteId,
9
+ path
10
+ });
11
+ if (response.redirectTo) {
12
+ const isPermanent = response.status === 301 || response.status === 308;
13
+ return {
14
+ hasRedirect: true,
15
+ redirect: {
16
+ destination: response.redirectTo,
17
+ permanent: isPermanent
18
+ }
19
+ };
20
+ }
21
+ return { hasRedirect: false, redirect: null };
22
+ } catch (error) {
23
+ console.warn("[checkRedirectForPath] Failed to check redirect", {
24
+ siteId,
25
+ path,
26
+ error: error instanceof Error ? error.message : String(error)
27
+ });
28
+ return { hasRedirect: false, redirect: null };
29
+ }
30
+ }
31
+
3
32
  // src/routing/resolveRoute.ts
4
33
  async function resolveRoute(params) {
5
34
  const { client, siteId, path, preview = false } = params;
@@ -10,7 +39,7 @@ async function resolveRoute(params) {
10
39
  preview
11
40
  });
12
41
  if (pageResponse) {
13
- const { loadPage } = await import("./loadPage-LYVKY3WZ.mjs");
42
+ const { loadPage } = await import("./loadPage-DNQTTRHL.mjs");
14
43
  const pageData = await loadPage({
15
44
  client,
16
45
  siteId,
@@ -33,6 +62,25 @@ async function resolveRoute(params) {
33
62
  });
34
63
  }
35
64
  }
65
+ try {
66
+ const redirectResult = await checkRedirectForPath({
67
+ client,
68
+ siteId,
69
+ path
70
+ });
71
+ if (redirectResult.hasRedirect) {
72
+ return {
73
+ type: "redirect",
74
+ destination: redirectResult.redirect.destination,
75
+ permanent: redirectResult.redirect.permanent
76
+ };
77
+ }
78
+ } catch (redirectError) {
79
+ console.debug("[resolveRoute] Redirect check failed", {
80
+ path,
81
+ error: redirectError instanceof Error ? redirectError.message : String(redirectError)
82
+ });
83
+ }
36
84
  return {
37
85
  type: "not-found"
38
86
  };
@@ -104,9 +152,54 @@ function matchPattern(pathSegments, patternSegments) {
104
152
  const slug = slugSegments.join("/");
105
153
  return { matches: true, slug };
106
154
  }
155
+
156
+ // src/routing/resolveOccurrence.ts
157
+ function isISODateString(str) {
158
+ return /^\d{4}-\d{2}-\d{2}$/.test(str);
159
+ }
160
+ function isUUID(str) {
161
+ return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(str);
162
+ }
163
+ function isValidSegment(segment) {
164
+ return isISODateString(segment) || isUUID(segment);
165
+ }
166
+ async function resolveOccurrence(params) {
167
+ const { client, siteId, entryId, segment } = params;
168
+ if (!isValidSegment(segment)) {
169
+ console.debug("[resolveOccurrence] Invalid segment format", { segment });
170
+ return { found: false, occurrence: null };
171
+ }
172
+ try {
173
+ const response = await client.resolveEventOccurrence({
174
+ siteId,
175
+ entryId,
176
+ segment
177
+ });
178
+ if (response.occurrence) {
179
+ return {
180
+ found: true,
181
+ occurrence: response.occurrence
182
+ };
183
+ }
184
+ return { found: false, occurrence: null };
185
+ } catch (error) {
186
+ console.warn("[resolveOccurrence] Failed to resolve occurrence", {
187
+ siteId,
188
+ entryId,
189
+ segment,
190
+ error: error instanceof Error ? error.message : String(error)
191
+ });
192
+ return { found: false, occurrence: null };
193
+ }
194
+ }
107
195
  export {
196
+ checkRedirectForPath,
108
197
  getContentEntryPrefixes,
109
198
  isContentEntryPath,
199
+ isISODateString,
200
+ isUUID,
201
+ isValidSegment,
202
+ resolveOccurrence,
110
203
  resolveRoute,
111
204
  resolveRoutes
112
205
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/routing/resolveRoute.ts","../../src/routing/contentRoutes.ts"],"sourcesContent":["/**\n * Route resolution helper for dynamic page routing\n *\n * Resolves URL paths to pages, entries, redirects, or 404s.\n */\n\nimport type { RiverbankClient } from '../client/types';\nimport type { LoadPageResult } from '../rendering/helpers/loadPage';\n\nexport type RouteResolution =\n | {\n type: 'page';\n pageData: LoadPageResult;\n }\n | {\n type: 'redirect';\n destination: string;\n permanent: boolean;\n }\n | {\n type: 'not-found';\n };\n\nexport type ResolveRouteParams = {\n /**\n * Builder client instance\n */\n client: RiverbankClient;\n\n /**\n * Site ID\n */\n siteId: string;\n\n /**\n * URL path to resolve (e.g., '/about', '/blog/post-1')\n */\n path: string;\n\n /**\n * If true, fetches draft/unpublished content instead of published content.\n * @default false\n */\n preview?: boolean;\n};\n\n/**\n * Resolve a URL path to page data, redirect, or 404\n *\n * This helper attempts to fetch the page at the given path and returns\n * a discriminated union indicating whether the page was found or not.\n *\n * **Note:** Redirect support is not yet implemented. The `redirect` type\n * exists in the return type for future compatibility, but this function\n * currently only returns `page` or `not-found` types.\n *\n * @example\n * ```tsx\n * import { resolveRoute } from '@riverbankcms/sdk/routing';\n * import { notFound, redirect } from 'next/navigation';\n *\n * export default async function DynamicPage({ params }) {\n * const path = `/${params.slug?.join('/') || ''}`;\n * const resolution = await resolveRoute({\n * client,\n * siteId: 'your-site-id',\n * path,\n * });\n *\n * if (resolution.type === 'redirect') {\n * redirect(resolution.destination);\n * }\n *\n * if (resolution.type === 'not-found') {\n * notFound();\n * }\n *\n * // resolution.type === 'page'\n * return <Page {...resolution.pageData} />;\n * }\n * ```\n */\nexport async function resolveRoute(\n params: ResolveRouteParams\n): Promise<RouteResolution> {\n const { client, siteId, path, preview = false } = params;\n\n try {\n // Attempt to fetch page data\n const pageResponse = await client.getPage({\n siteId,\n path,\n preview,\n });\n\n if (pageResponse) {\n // Successfully found page - load full page data\n const { loadPage } = await import('../rendering/helpers/loadPage');\n const pageData = await loadPage({\n client,\n siteId,\n path,\n preview,\n });\n\n return {\n type: 'page',\n pageData,\n };\n }\n } catch (error) {\n // Distinguish between expected 404s and unexpected errors\n const is404 = error instanceof Error &&\n (error.message.includes('404') ||\n error.message.includes('Not Found') ||\n error.message.includes('not found'));\n\n if (is404) {\n console.debug('[resolveRoute] Page not found', { path });\n } else {\n // Unexpected error - log as warning for visibility\n console.warn('[resolveRoute] Failed to fetch page', {\n path,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n // No page found - return not-found\n // Note: Redirect support will be added when client.getRedirect() API is available\n return {\n type: 'not-found',\n };\n}\n\n/**\n * Batch resolve multiple routes in parallel\n *\n * Useful for pre-fetching multiple routes or validating a sitemap.\n *\n * @example\n * ```tsx\n * const resolutions = await resolveRoutes({\n * client,\n * siteId: 'your-site-id',\n * paths: ['/', '/about', '/blog', '/contact'],\n * });\n *\n * resolutions.forEach(({ path, resolution }) => {\n * if (resolution.type === 'page') {\n * console.log(`${path} → Page: ${resolution.pageData.page.name}`);\n * } else if (resolution.type === 'redirect') {\n * console.log(`${path} → Redirect to ${resolution.destination}`);\n * } else {\n * console.log(`${path} → Not found`);\n * }\n * });\n * ```\n */\nexport async function resolveRoutes(params: {\n client: RiverbankClient;\n siteId: string;\n paths: string[];\n preview?: boolean;\n}): Promise<Array<{ path: string; resolution: RouteResolution }>> {\n const { client, siteId, paths, preview } = params;\n\n const resolutions = await Promise.all(\n paths.map(async (path) => {\n const resolution = await resolveRoute({\n client,\n siteId,\n path,\n preview,\n });\n\n return { path, resolution };\n })\n );\n\n return resolutions;\n}\n","/**\n * Content route matching utilities.\n *\n * Derive route matching from SDK config to determine whether a URL path\n * is a CMS page or a content entry, without duplicating route patterns.\n */\n\nimport type { RiverbankSiteConfig, ContentTypeConfig } from '../config';\n\n/**\n * Extract the first path segment from each routable content type's routePattern.\n *\n * Useful for simple prefix-based routing decisions. For more precise matching\n * that handles nested patterns, use `isContentEntryPath` instead.\n *\n * @param config - The SDK config object from defineConfig()\n * @returns Array of first path segments from content type routePatterns\n *\n * @example\n * ```typescript\n * import { getContentEntryPrefixes } from '@riverbankcms/sdk/routing';\n * import config from '../riverbank.config';\n *\n * // Config with routePatterns: '/blog/{slug}', '/work/projects/{slug}'\n * const prefixes = getContentEntryPrefixes(config);\n * // Returns ['blog', 'work']\n * ```\n */\nexport function getContentEntryPrefixes(config: RiverbankSiteConfig): string[] {\n const contentTypes = config.content?.contentTypes ?? [];\n\n return contentTypes\n .filter((ct): ct is ContentTypeConfig & { routePattern: string } =>\n ct.hasPages && typeof ct.routePattern === 'string'\n )\n .map(ct => {\n // '/blog/{slug}' → 'blog'\n // '/work/projects/{slug}' → 'work'\n // '/{slug}' → undefined (no static prefix)\n const match = ct.routePattern.match(/^\\/([^/]+)/);\n const segment = match?.[1];\n // Skip dynamic segments (those containing {})\n if (segment?.includes('{')) return undefined;\n return segment;\n })\n .filter((prefix): prefix is string => typeof prefix === 'string');\n}\n\n/**\n * Result of checking if a path matches a content entry route.\n */\nexport type ContentEntryMatch = {\n /** Whether the path matches a content entry route pattern */\n isEntry: boolean;\n /** The content type key if matched (e.g., 'blog-post') */\n contentType?: string;\n /** The slug extracted from the path if matched */\n slug?: string;\n};\n\n/**\n * Check if a URL path matches any content entry route pattern.\n *\n * Supports nested patterns like '/work/projects/{slug}'. Returns the matched\n * content type key and extracted slug, useful for routing decisions.\n *\n * **Note:** Content types are checked in array order. If multiple patterns\n * could match a path, the first matching content type wins. Order more specific\n * patterns before generic ones in your config.\n *\n * @param config - The SDK config object from defineConfig()\n * @param path - URL path as string ('/blog/my-post') or segments ['blog', 'my-post']\n * @returns Match result with content type and slug if matched\n *\n * @example\n * ```typescript\n * import { isContentEntryPath } from '@riverbankcms/sdk/routing';\n * import config from '../riverbank.config';\n *\n * // Simple pattern: '/blog/{slug}'\n * isContentEntryPath(config, '/blog/my-post');\n * // Returns { isEntry: true, contentType: 'blog-post', slug: 'my-post' }\n *\n * // Nested pattern: '/work/projects/{slug}'\n * isContentEntryPath(config, '/work/projects/website-redesign');\n * // Returns { isEntry: true, contentType: 'project', slug: 'website-redesign' }\n *\n * // Non-matching path\n * isContentEntryPath(config, '/about');\n * // Returns { isEntry: false }\n * ```\n */\nexport function isContentEntryPath(\n config: RiverbankSiteConfig,\n path: string | string[]\n): ContentEntryMatch {\n const segments = typeof path === 'string'\n ? path.split('/').filter(Boolean)\n : path;\n\n const contentTypes = config.content?.contentTypes ?? [];\n\n for (const ct of contentTypes) {\n if (!ct.hasPages || !ct.routePattern) continue;\n\n // Parse pattern: '/blog/{slug}' → ['blog'], '/work/projects/{slug}' → ['work', 'projects']\n const patternSegments = parseRoutePattern(ct.routePattern);\n\n // Check if path segments match the pattern\n const match = matchPattern(segments, patternSegments);\n if (match.matches) {\n return {\n isEntry: true,\n contentType: ct.key,\n slug: match.slug,\n };\n }\n }\n\n return { isEntry: false };\n}\n\n/**\n * Parse a route pattern into static segments before {slug}.\n *\n * @example\n * parseRoutePattern('/blog/{slug}') // ['blog']\n * parseRoutePattern('/work/projects/{slug}') // ['work', 'projects']\n * parseRoutePattern('/{slug}') // []\n */\nfunction parseRoutePattern(pattern: string): string[] {\n const segments = pattern.split('/').filter(Boolean);\n const staticSegments: string[] = [];\n\n for (const segment of segments) {\n if (segment.includes('{')) break; // Stop at dynamic segment\n staticSegments.push(segment);\n }\n\n return staticSegments;\n}\n\n/**\n * Check if path segments match pattern segments.\n * Path must have at least one more segment than pattern (the slug).\n *\n * @returns Match result with extracted slug if matched\n */\nfunction matchPattern(\n pathSegments: string[],\n patternSegments: string[]\n): { matches: boolean; slug?: string } {\n // Path needs: pattern segments + at least 1 slug segment\n if (pathSegments.length < patternSegments.length + 1) {\n return { matches: false };\n }\n\n // All pattern segments must match exactly\n for (let i = 0; i < patternSegments.length; i++) {\n if (pathSegments[i] !== patternSegments[i]) {\n return { matches: false };\n }\n }\n\n // Extract slug (everything after the pattern segments)\n // For '/blog/{slug}' with path '/blog/my-post' → slug = 'my-post'\n // For nested slugs, join remaining segments (rare but supported)\n const slugSegments = pathSegments.slice(patternSegments.length);\n const slug = slugSegments.join('/');\n\n return { matches: true, slug };\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/routing/checkRedirect.ts","../../src/routing/resolveRoute.ts","../../src/routing/contentRoutes.ts","../../src/routing/resolveOccurrence.ts"],"sourcesContent":["/**\n * Redirect checking for 404 handling\n *\n * Check if a path has a configured redirect rule before returning 404.\n */\n\nimport type { RiverbankClient } from '../client/types';\n\n/**\n * Redirect rule data\n */\nexport type RedirectRule = {\n /**\n * Destination URL to redirect to\n */\n destination: string;\n\n /**\n * Whether this is a permanent redirect (301/308) or temporary (302/307)\n */\n permanent: boolean;\n};\n\n/**\n * Result of redirect checking\n */\nexport type RedirectResult =\n | {\n hasRedirect: true;\n redirect: RedirectRule;\n }\n | {\n hasRedirect: false;\n redirect: null;\n };\n\n/**\n * Parameters for checking redirects\n */\nexport type CheckRedirectParams = {\n /**\n * SDK client instance\n */\n client: RiverbankClient;\n\n /**\n * Site ID\n */\n siteId: string;\n\n /**\n * URL path to check (e.g., '/old-page')\n */\n path: string;\n};\n\n/**\n * Check if a path has a configured redirect rule\n *\n * Use this when a page is not found to check if there's a redirect\n * configured for the path before returning a 404.\n *\n * @example\n * ```tsx\n * import { checkRedirectForPath } from '@riverbankcms/sdk/routing';\n * import { notFound, redirect } from 'next/navigation';\n *\n * export default async function Page({ params }) {\n * const page = await getPage(params.path);\n *\n * if (!page) {\n * // Check for redirect before 404\n * const result = await checkRedirectForPath({\n * client,\n * siteId: 'your-site-id',\n * path: params.path,\n * });\n *\n * if (result.hasRedirect) {\n * redirect(result.redirect.destination);\n * }\n *\n * notFound();\n * }\n *\n * return <PageContent page={page} />;\n * }\n * ```\n */\nexport async function checkRedirectForPath(\n params: CheckRedirectParams\n): Promise<RedirectResult> {\n const { client, siteId, path } = params;\n\n try {\n const response = await client.checkRedirect({\n siteId,\n path,\n });\n\n // API returns { redirectTo: string | null, status?: number }\n if (response.redirectTo) {\n // Status 301 and 308 are permanent, others are temporary\n const isPermanent = response.status === 301 || response.status === 308;\n\n return {\n hasRedirect: true,\n redirect: {\n destination: response.redirectTo,\n permanent: isPermanent,\n },\n };\n }\n\n return { hasRedirect: false, redirect: null };\n } catch (error) {\n console.warn('[checkRedirectForPath] Failed to check redirect', {\n siteId,\n path,\n error: error instanceof Error ? error.message : String(error),\n });\n\n return { hasRedirect: false, redirect: null };\n }\n}\n","/**\n * Route resolution helper for dynamic page routing\n *\n * Resolves URL paths to pages, entries, redirects, or 404s.\n */\n\nimport type { RiverbankClient } from '../client/types';\nimport type { LoadPageResult } from '../rendering/helpers/loadPage';\nimport { checkRedirectForPath } from './checkRedirect';\n\nexport type RouteResolution =\n | {\n type: 'page';\n pageData: LoadPageResult;\n }\n | {\n type: 'redirect';\n destination: string;\n permanent: boolean;\n }\n | {\n type: 'not-found';\n };\n\nexport type ResolveRouteParams = {\n /**\n * Builder client instance\n */\n client: RiverbankClient;\n\n /**\n * Site ID\n */\n siteId: string;\n\n /**\n * URL path to resolve (e.g., '/about', '/blog/post-1')\n */\n path: string;\n\n /**\n * If true, fetches draft/unpublished content instead of published content.\n * @default false\n */\n preview?: boolean;\n};\n\n/**\n * Resolve a URL path to page data, redirect, or 404\n *\n * This helper attempts to fetch the page at the given path. If the page\n * is not found, it checks for configured redirects before returning 404.\n *\n * Returns a discriminated union indicating:\n * - `page`: Page was found, includes full page data\n * - `redirect`: Path has a redirect rule configured\n * - `not-found`: No page or redirect exists for this path\n *\n * @example\n * ```tsx\n * import { resolveRoute } from '@riverbankcms/sdk/routing';\n * import { notFound, redirect } from 'next/navigation';\n *\n * export default async function DynamicPage({ params }) {\n * const path = `/${params.slug?.join('/') || ''}`;\n * const resolution = await resolveRoute({\n * client,\n * siteId: 'your-site-id',\n * path,\n * });\n *\n * if (resolution.type === 'redirect') {\n * redirect(resolution.destination);\n * }\n *\n * if (resolution.type === 'not-found') {\n * notFound();\n * }\n *\n * // resolution.type === 'page'\n * return <Page {...resolution.pageData} />;\n * }\n * ```\n */\nexport async function resolveRoute(\n params: ResolveRouteParams\n): Promise<RouteResolution> {\n const { client, siteId, path, preview = false } = params;\n\n try {\n // Attempt to fetch page data\n const pageResponse = await client.getPage({\n siteId,\n path,\n preview,\n });\n\n if (pageResponse) {\n // Successfully found page - load full page data\n const { loadPage } = await import('../rendering/helpers/loadPage');\n const pageData = await loadPage({\n client,\n siteId,\n path,\n preview,\n });\n\n return {\n type: 'page',\n pageData,\n };\n }\n } catch (error) {\n // Distinguish between expected 404s and unexpected errors\n const is404 = error instanceof Error &&\n (error.message.includes('404') ||\n error.message.includes('Not Found') ||\n error.message.includes('not found'));\n\n if (is404) {\n console.debug('[resolveRoute] Page not found', { path });\n } else {\n // Unexpected error - log as warning for visibility\n console.warn('[resolveRoute] Failed to fetch page', {\n path,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n // No page found - check for redirect before returning 404\n try {\n const redirectResult = await checkRedirectForPath({\n client,\n siteId,\n path,\n });\n\n if (redirectResult.hasRedirect) {\n return {\n type: 'redirect',\n destination: redirectResult.redirect.destination,\n permanent: redirectResult.redirect.permanent,\n };\n }\n } catch (redirectError) {\n console.debug('[resolveRoute] Redirect check failed', {\n path,\n error: redirectError instanceof Error ? redirectError.message : String(redirectError),\n });\n }\n\n return {\n type: 'not-found',\n };\n}\n\n/**\n * Batch resolve multiple routes in parallel\n *\n * Useful for pre-fetching multiple routes or validating a sitemap.\n *\n * @example\n * ```tsx\n * const resolutions = await resolveRoutes({\n * client,\n * siteId: 'your-site-id',\n * paths: ['/', '/about', '/blog', '/contact'],\n * });\n *\n * resolutions.forEach(({ path, resolution }) => {\n * if (resolution.type === 'page') {\n * console.log(`${path} → Page: ${resolution.pageData.page.name}`);\n * } else if (resolution.type === 'redirect') {\n * console.log(`${path} → Redirect to ${resolution.destination}`);\n * } else {\n * console.log(`${path} → Not found`);\n * }\n * });\n * ```\n */\nexport async function resolveRoutes(params: {\n client: RiverbankClient;\n siteId: string;\n paths: string[];\n preview?: boolean;\n}): Promise<Array<{ path: string; resolution: RouteResolution }>> {\n const { client, siteId, paths, preview } = params;\n\n const resolutions = await Promise.all(\n paths.map(async (path) => {\n const resolution = await resolveRoute({\n client,\n siteId,\n path,\n preview,\n });\n\n return { path, resolution };\n })\n );\n\n return resolutions;\n}\n","/**\n * Content route matching utilities.\n *\n * Derive route matching from SDK config to determine whether a URL path\n * is a CMS page or a content entry, without duplicating route patterns.\n */\n\nimport type { RiverbankSiteConfig, ContentTypeConfig } from '../config';\n\n/**\n * Extract the first path segment from each routable content type's routePattern.\n *\n * Useful for simple prefix-based routing decisions. For more precise matching\n * that handles nested patterns, use `isContentEntryPath` instead.\n *\n * @param config - The SDK config object from defineConfig()\n * @returns Array of first path segments from content type routePatterns\n *\n * @example\n * ```typescript\n * import { getContentEntryPrefixes } from '@riverbankcms/sdk/routing';\n * import config from '../riverbank.config';\n *\n * // Config with routePatterns: '/blog/{slug}', '/work/projects/{slug}'\n * const prefixes = getContentEntryPrefixes(config);\n * // Returns ['blog', 'work']\n * ```\n */\nexport function getContentEntryPrefixes(config: RiverbankSiteConfig): string[] {\n const contentTypes = config.content?.contentTypes ?? [];\n\n return contentTypes\n .filter((ct): ct is ContentTypeConfig & { routePattern: string } =>\n ct.hasPages && typeof ct.routePattern === 'string'\n )\n .map(ct => {\n // '/blog/{slug}' → 'blog'\n // '/work/projects/{slug}' → 'work'\n // '/{slug}' → undefined (no static prefix)\n const match = ct.routePattern.match(/^\\/([^/]+)/);\n const segment = match?.[1];\n // Skip dynamic segments (those containing {})\n if (segment?.includes('{')) return undefined;\n return segment;\n })\n .filter((prefix): prefix is string => typeof prefix === 'string');\n}\n\n/**\n * Result of checking if a path matches a content entry route.\n */\nexport type ContentEntryMatch = {\n /** Whether the path matches a content entry route pattern */\n isEntry: boolean;\n /** The content type key if matched (e.g., 'blog-post') */\n contentType?: string;\n /** The slug extracted from the path if matched */\n slug?: string;\n};\n\n/**\n * Check if a URL path matches any content entry route pattern.\n *\n * Supports nested patterns like '/work/projects/{slug}'. Returns the matched\n * content type key and extracted slug, useful for routing decisions.\n *\n * **Note:** Content types are checked in array order. If multiple patterns\n * could match a path, the first matching content type wins. Order more specific\n * patterns before generic ones in your config.\n *\n * @param config - The SDK config object from defineConfig()\n * @param path - URL path as string ('/blog/my-post') or segments ['blog', 'my-post']\n * @returns Match result with content type and slug if matched\n *\n * @example\n * ```typescript\n * import { isContentEntryPath } from '@riverbankcms/sdk/routing';\n * import config from '../riverbank.config';\n *\n * // Simple pattern: '/blog/{slug}'\n * isContentEntryPath(config, '/blog/my-post');\n * // Returns { isEntry: true, contentType: 'blog-post', slug: 'my-post' }\n *\n * // Nested pattern: '/work/projects/{slug}'\n * isContentEntryPath(config, '/work/projects/website-redesign');\n * // Returns { isEntry: true, contentType: 'project', slug: 'website-redesign' }\n *\n * // Non-matching path\n * isContentEntryPath(config, '/about');\n * // Returns { isEntry: false }\n * ```\n */\nexport function isContentEntryPath(\n config: RiverbankSiteConfig,\n path: string | string[]\n): ContentEntryMatch {\n const segments = typeof path === 'string'\n ? path.split('/').filter(Boolean)\n : path;\n\n const contentTypes = config.content?.contentTypes ?? [];\n\n for (const ct of contentTypes) {\n if (!ct.hasPages || !ct.routePattern) continue;\n\n // Parse pattern: '/blog/{slug}' → ['blog'], '/work/projects/{slug}' → ['work', 'projects']\n const patternSegments = parseRoutePattern(ct.routePattern);\n\n // Check if path segments match the pattern\n const match = matchPattern(segments, patternSegments);\n if (match.matches) {\n return {\n isEntry: true,\n contentType: ct.key,\n slug: match.slug,\n };\n }\n }\n\n return { isEntry: false };\n}\n\n/**\n * Parse a route pattern into static segments before {slug}.\n *\n * @example\n * parseRoutePattern('/blog/{slug}') // ['blog']\n * parseRoutePattern('/work/projects/{slug}') // ['work', 'projects']\n * parseRoutePattern('/{slug}') // []\n */\nfunction parseRoutePattern(pattern: string): string[] {\n const segments = pattern.split('/').filter(Boolean);\n const staticSegments: string[] = [];\n\n for (const segment of segments) {\n if (segment.includes('{')) break; // Stop at dynamic segment\n staticSegments.push(segment);\n }\n\n return staticSegments;\n}\n\n/**\n * Check if path segments match pattern segments.\n * Path must have at least one more segment than pattern (the slug).\n *\n * @returns Match result with extracted slug if matched\n */\nfunction matchPattern(\n pathSegments: string[],\n patternSegments: string[]\n): { matches: boolean; slug?: string } {\n // Path needs: pattern segments + at least 1 slug segment\n if (pathSegments.length < patternSegments.length + 1) {\n return { matches: false };\n }\n\n // All pattern segments must match exactly\n for (let i = 0; i < patternSegments.length; i++) {\n if (pathSegments[i] !== patternSegments[i]) {\n return { matches: false };\n }\n }\n\n // Extract slug (everything after the pattern segments)\n // For '/blog/{slug}' with path '/blog/my-post' → slug = 'my-post'\n // For nested slugs, join remaining segments (rare but supported)\n const slugSegments = pathSegments.slice(patternSegments.length);\n const slug = slugSegments.join('/');\n\n return { matches: true, slug };\n}\n","/**\n * Event occurrence resolution for dynamic URLs\n *\n * Resolves URL segments like \"2025-01-15\" or \"abc123-uuid\" to event occurrence data.\n */\n\nimport type { RiverbankClient, ResolveEventOccurrenceResponse } from '../client/types';\n\n/**\n * Data for a resolved event occurrence\n */\nexport type OccurrenceData = NonNullable<ResolveEventOccurrenceResponse['occurrence']>;\n\n/**\n * Result of occurrence resolution\n */\nexport type OccurrenceResolution =\n | {\n found: true;\n occurrence: OccurrenceData;\n }\n | {\n found: false;\n occurrence: null;\n };\n\n/**\n * Parameters for resolving an event occurrence\n */\nexport type ResolveOccurrenceParams = {\n /**\n * SDK client instance\n */\n client: RiverbankClient;\n\n /**\n * Site ID\n */\n siteId: string;\n\n /**\n * Parent content entry ID (the event entry)\n */\n entryId: string;\n\n /**\n * URL segment to resolve - either a date (YYYY-MM-DD) or UUID\n */\n segment: string;\n};\n\n/**\n * Check if a string is a valid ISO date (YYYY-MM-DD)\n */\nfunction isISODateString(str: string): boolean {\n return /^\\d{4}-\\d{2}-\\d{2}$/.test(str);\n}\n\n/**\n * Check if a string is a valid UUID\n */\nfunction isUUID(str: string): boolean {\n return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(str);\n}\n\n/**\n * Validate URL segment format before making API call\n */\nfunction isValidSegment(segment: string): boolean {\n return isISODateString(segment) || isUUID(segment);\n}\n\n/**\n * Resolve an event occurrence from a URL segment\n *\n * Supports two segment formats:\n * - Date format: \"2025-01-15\" → finds occurrence starting on that date\n * - UUID format: \"abc123...\" → finds occurrence by ID\n *\n * @example\n * ```tsx\n * import { resolveOccurrence } from '@riverbankcms/sdk/routing';\n *\n * // In a Next.js dynamic route: /events/[slug]/[occurrence]\n * export default async function EventOccurrencePage({ params }) {\n * const result = await resolveOccurrence({\n * client,\n * siteId: 'your-site-id',\n * entryId: eventEntry.id,\n * segment: params.occurrence, // e.g., \"2025-01-15\"\n * });\n *\n * if (!result.found) {\n * notFound();\n * }\n *\n * return <EventOccurrence occurrence={result.occurrence} />;\n * }\n * ```\n */\nexport async function resolveOccurrence(\n params: ResolveOccurrenceParams\n): Promise<OccurrenceResolution> {\n const { client, siteId, entryId, segment } = params;\n\n // Validate segment format client-side to avoid unnecessary API calls\n if (!isValidSegment(segment)) {\n console.debug('[resolveOccurrence] Invalid segment format', { segment });\n return { found: false, occurrence: null };\n }\n\n try {\n const response = await client.resolveEventOccurrence({\n siteId,\n entryId,\n segment,\n });\n\n if (response.occurrence) {\n return {\n found: true,\n occurrence: response.occurrence,\n };\n }\n\n return { found: false, occurrence: null };\n } catch (error) {\n console.warn('[resolveOccurrence] Failed to resolve occurrence', {\n siteId,\n entryId,\n segment,\n error: error instanceof Error ? error.message : String(error),\n });\n\n return { found: false, occurrence: null };\n }\n}\n\nexport { isISODateString, isUUID, isValidSegment };\n"],"mappings":"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","names":[]}
@@ -1867,4 +1867,4 @@ declare const pageOutlineSchema: z$1.ZodObject<{
1867
1867
  }, z$1.core.$strip>;
1868
1868
  type PageOutline = z$1.infer<typeof pageOutlineSchema>;
1869
1869
 
1870
- export type { FieldDefinition as F, PageOutline as P, SdkCustomBlock as S };
1870
+ export type { BooleanFieldDefinition as B, ContentTypeSelectFieldDefinition as C, DateFieldDefinition as D, EntryPickerFieldDefinition as E, FieldDefinition as F, GroupFieldDefinition as G, LinkFieldDefinition as L, MediaFieldDefinition as M, NumberFieldDefinition as N, PageOutline as P, RichTextFieldDefinition as R, SdkCustomBlock as S, TextFieldDefinition as T, UrlFieldDefinition as U, TimeFieldDefinition as a, DateTimeFieldDefinition as b, SlugFieldDefinition as c, ReferenceFieldDefinition as d, PresetOrCustomFieldDefinition as e, SelectFieldDefinition as f, ModalFieldDefinition as g, RepeaterFieldDefinition as h, TabGroupFieldDefinition as i };
@@ -1867,4 +1867,4 @@ declare const pageOutlineSchema: z$1.ZodObject<{
1867
1867
  }, z$1.core.$strip>;
1868
1868
  type PageOutline = z$1.infer<typeof pageOutlineSchema>;
1869
1869
 
1870
- export type { FieldDefinition as F, PageOutline as P, SdkCustomBlock as S };
1870
+ export type { BooleanFieldDefinition as B, ContentTypeSelectFieldDefinition as C, DateFieldDefinition as D, EntryPickerFieldDefinition as E, FieldDefinition as F, GroupFieldDefinition as G, LinkFieldDefinition as L, MediaFieldDefinition as M, NumberFieldDefinition as N, PageOutline as P, RichTextFieldDefinition as R, SdkCustomBlock as S, TextFieldDefinition as T, UrlFieldDefinition as U, TimeFieldDefinition as a, DateTimeFieldDefinition as b, SlugFieldDefinition as c, ReferenceFieldDefinition as d, PresetOrCustomFieldDefinition as e, SelectFieldDefinition as f, ModalFieldDefinition as g, RepeaterFieldDefinition as h, TabGroupFieldDefinition as i };
@@ -1,14 +1,16 @@
1
- export { c as createRiverbankClient } from './index-DFQwtj3J.mjs';
2
- export { E as EntriesResponse, b as EntryResponse, P as PageResponse, R as RiverbankClient, a as RiverbankClientConfig, S as SiteResponse } from './types-DkKEctWn.mjs';
3
- export { L as LoadPageParams, a as LoadPageResult, R as RuntimeSdkConfig, l as loadPage } from './loadPage-B8RmlYgV.mjs';
4
- export { C as ContentEntryData, E as EntryContentResult, L as LoadContentParams, b as LoadContentResult, P as PageContentResult, a as isEntryContent, i as isPageContent, l as loadContent } from './loadContent-CWuE8FCx.mjs';
5
- import './types-CdrJqlKx.mjs';
6
- import '@riverbankcms/ai';
7
- import './schema-Bpy9N5ZI.mjs';
1
+ export { c as createRiverbankClient } from './index-Q7RLMAQ6.mjs';
2
+ export { E as EntriesResponse, b as EntryResponse, P as PageResponse, R as RiverbankClient, a as RiverbankClientConfig, S as SiteResponse } from './types-0f4PIlgx.mjs';
3
+ export { L as LoadPageParams, a as LoadPageResult, R as RuntimeSdkConfig, l as loadPage } from './loadPage-DGnIK7s4.mjs';
4
+ export { C as ContentEntryData, E as EntryContentResult, L as LoadContentParams, b as LoadContentResult, P as PageContentResult, a as isEntryContent, i as isPageContent, l as loadContent } from './loadContent-DgpSKWqY.mjs';
5
+ import './schema-Z6-afHJG.mjs';
8
6
  import 'zod';
7
+ import './types-DuzJZKJI.mjs';
8
+ import '@riverbankcms/ai';
9
+ import './link-DjxLyC82.mjs';
9
10
  import '@riverbankcms/media-storage-supabase';
10
11
  import '@riverbankcms/db';
11
12
  import 'react/jsx-runtime';
12
13
  import 'react';
14
+ import './core-DsNWrl3o.mjs';
13
15
  import './types-CbagRQ_7.mjs';
14
16
  import './blockKinds-B6MWzNWp.mjs';
@@ -1,14 +1,16 @@
1
- export { c as createRiverbankClient } from './index-DCIz9Ptv.js';
2
- export { E as EntriesResponse, b as EntryResponse, P as PageResponse, R as RiverbankClient, a as RiverbankClientConfig, S as SiteResponse } from './types-oCM-fw4O.js';
3
- export { L as LoadPageParams, a as LoadPageResult, R as RuntimeSdkConfig, l as loadPage } from './loadPage-BTkKpizX.js';
4
- export { C as ContentEntryData, E as EntryContentResult, L as LoadContentParams, b as LoadContentResult, P as PageContentResult, a as isEntryContent, i as isPageContent, l as loadContent } from './loadContent-DynBuR5f.js';
5
- import './types-BiRZnxDx.js';
6
- import '@riverbankcms/ai';
7
- import './schema-Bpy9N5ZI.js';
1
+ export { c as createRiverbankClient } from './index-CJfMXZQr.js';
2
+ export { E as EntriesResponse, b as EntryResponse, P as PageResponse, R as RiverbankClient, a as RiverbankClientConfig, S as SiteResponse } from './types-kOQyCFXO.js';
3
+ export { L as LoadPageParams, a as LoadPageResult, R as RuntimeSdkConfig, l as loadPage } from './loadPage-DW9WB-u9.js';
4
+ export { C as ContentEntryData, E as EntryContentResult, L as LoadContentParams, b as LoadContentResult, P as PageContentResult, a as isEntryContent, i as isPageContent, l as loadContent } from './loadContent-GPvUI1bN.js';
5
+ import './schema-Z6-afHJG.js';
8
6
  import 'zod';
7
+ import './types-C28kMfa1.js';
8
+ import '@riverbankcms/ai';
9
+ import './link-DjxLyC82.js';
9
10
  import '@riverbankcms/media-storage-supabase';
10
11
  import '@riverbankcms/db';
11
12
  import 'react/jsx-runtime';
12
13
  import 'react';
14
+ import './core-DsNWrl3o.js';
13
15
  import './types-DuQCNVV0.js';
14
16
  import './blockKinds-B6MWzNWp.js';
@@ -1,17 +1,17 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true});
2
2
 
3
- var _chunkR5B6IOFQjs = require('./chunk-R5B6IOFQ.js');
3
+ var _chunk6OSNCH4Fjs = require('./chunk-6OSNCH4F.js');
4
4
 
5
5
 
6
6
 
7
7
 
8
- var _chunkTO7FD6TQjs = require('./chunk-TO7FD6TQ.js');
8
+ var _chunkI2D7KOEAjs = require('./chunk-I2D7KOEA.js');
9
9
 
10
10
 
11
- var _chunkSWPHIUVEjs = require('./chunk-SWPHIUVE.js');
11
+ var _chunkP3NNN73Gjs = require('./chunk-P3NNN73G.js');
12
12
  require('./chunk-Y7347JMZ.js');
13
- require('./chunk-HOY77YBF.js');
14
- require('./chunk-EGTDJ4PL.js');
13
+ require('./chunk-RVDS7VSP.js');
14
+ require('./chunk-YYO3RIFO.js');
15
15
  require('./chunk-DGUM43GV.js');
16
16
 
17
17
 
@@ -19,5 +19,5 @@ require('./chunk-DGUM43GV.js');
19
19
 
20
20
 
21
21
 
22
- exports.createRiverbankClient = _chunkR5B6IOFQjs.createRiverbankClient; exports.isEntryContent = _chunkTO7FD6TQjs.isEntryContent; exports.isPageContent = _chunkTO7FD6TQjs.isPageContent; exports.loadContent = _chunkTO7FD6TQjs.loadContent; exports.loadPage = _chunkSWPHIUVEjs.loadPage;
22
+ exports.createRiverbankClient = _chunk6OSNCH4Fjs.createRiverbankClient; exports.isEntryContent = _chunkI2D7KOEAjs.isEntryContent; exports.isPageContent = _chunkI2D7KOEAjs.isPageContent; exports.loadContent = _chunkI2D7KOEAjs.loadContent; exports.loadPage = _chunkP3NNN73Gjs.loadPage;
23
23
  //# sourceMappingURL=server.js.map
@@ -1,17 +1,17 @@
1
1
  import {
2
2
  createRiverbankClient
3
- } from "./chunk-N3PX76AP.mjs";
3
+ } from "./chunk-4HIRA33Z.mjs";
4
4
  import {
5
5
  isEntryContent,
6
6
  isPageContent,
7
7
  loadContent
8
- } from "./chunk-OP2GHK27.mjs";
8
+ } from "./chunk-Z5ZA6Q4D.mjs";
9
9
  import {
10
10
  loadPage
11
- } from "./chunk-ZEAJW6T3.mjs";
11
+ } from "./chunk-C6FIJC7T.mjs";
12
12
  import "./chunk-A2FZMRDW.mjs";
13
- import "./chunk-7DS4Q3GA.mjs";
14
- import "./chunk-USQF2XTU.mjs";
13
+ import "./chunk-AEFWG657.mjs";
14
+ import "./chunk-BYBJA6SP.mjs";
15
15
  import "./chunk-BJTO5JO5.mjs";
16
16
  export {
17
17
  createRiverbankClient,
@@ -5,8 +5,8 @@
5
5
 
6
6
 
7
7
 
8
- var _chunkTKMA6D6Ujs = require('./chunk-TKMA6D6U.js');
9
- require('./chunk-EGTDJ4PL.js');
8
+ var _chunk7UPVCT3Kjs = require('./chunk-7UPVCT3K.js');
9
+ require('./chunk-YYO3RIFO.js');
10
10
  require('./chunk-DGUM43GV.js');
11
11
 
12
12
  // src/theme-bridge/ThemeBridgeProvider.tsx
@@ -147,7 +147,7 @@ ${cssLines}
147
147
  }
148
148
  function generateButtonsCss(config, corners, shadows) {
149
149
  const buttonConfig = _optionalChain([config, 'access', _7 => _7.components, 'optionalAccess', _8 => _8.buttons]);
150
- let variants = _chunkTKMA6D6Ujs.getDefaultButtonVariants.call(void 0, );
150
+ let variants = _chunk7UPVCT3Kjs.getDefaultButtonVariants.call(void 0, );
151
151
  if (typeof buttonConfig === "object" && buttonConfig.variants) {
152
152
  const requestedIds = new Set(buttonConfig.variants);
153
153
  variants = variants.filter((v) => requestedIds.has(v.id));
@@ -159,11 +159,11 @@ function generateButtonsCss(config, corners, shadows) {
159
159
  fontWeight: 500,
160
160
  textTransform: "none"
161
161
  };
162
- return _chunkTKMA6D6Ujs.generateButtonCoreCss.call(void 0, SCOPE_ID, variants, settings);
162
+ return _chunk7UPVCT3Kjs.generateButtonCoreCss.call(void 0, SCOPE_ID, variants, settings);
163
163
  }
164
164
  function generateCardsCss(config, corners, shadows) {
165
165
  const cardConfig = _optionalChain([config, 'access', _9 => _9.components, 'optionalAccess', _10 => _10.cards]);
166
- let variants = _chunkTKMA6D6Ujs.getDefaultCardVariants.call(void 0, );
166
+ let variants = _chunk7UPVCT3Kjs.getDefaultCardVariants.call(void 0, );
167
167
  if (typeof cardConfig === "object" && cardConfig.variants) {
168
168
  const requestedIds = new Set(cardConfig.variants);
169
169
  variants = variants.filter((v) => requestedIds.has(v.id));
@@ -173,13 +173,13 @@ function generateCardsCss(config, corners, shadows) {
173
173
  shadow: shadows,
174
174
  borderWidth: "thin"
175
175
  };
176
- return _chunkTKMA6D6Ujs.generateCardCoreCss.call(void 0, SCOPE_ID, variants, settings);
176
+ return _chunk7UPVCT3Kjs.generateCardCoreCss.call(void 0, SCOPE_ID, variants, settings);
177
177
  }
178
178
  function generateInputsCss(config, corners, shadows) {
179
- const settings = _chunkTKMA6D6Ujs.getDefaultInputSettings.call(void 0, );
179
+ const settings = _chunk7UPVCT3Kjs.getDefaultInputSettings.call(void 0, );
180
180
  settings.corners = corners;
181
181
  settings.shadow = shadows === "none" ? "none" : "low";
182
- return _chunkTKMA6D6Ujs.generateInputCoreCss.call(void 0, SCOPE_ID, settings);
182
+ return _chunk7UPVCT3Kjs.generateInputCoreCss.call(void 0, SCOPE_ID, settings);
183
183
  }
184
184
  function generateOverrideCss(overrides) {
185
185
  const chunks = [];
@@ -5,8 +5,8 @@ import {
5
5
  getDefaultButtonVariants,
6
6
  getDefaultCardVariants,
7
7
  getDefaultInputSettings
8
- } from "./chunk-TNRADRPH.mjs";
9
- import "./chunk-USQF2XTU.mjs";
8
+ } from "./chunk-LNOUXALA.mjs";
9
+ import "./chunk-BYBJA6SP.mjs";
10
10
  import "./chunk-BJTO5JO5.mjs";
11
11
 
12
12
  // src/theme-bridge/ThemeBridgeProvider.tsx
@@ -1,4 +1,5 @@
1
- import { A as APIEndpoints } from './types-BiRZnxDx.js';
1
+ import { A as APIEndpoints } from './types-DuzJZKJI.mjs';
2
+ import './schema-Z6-afHJG.mjs';
2
3
 
3
4
  type SiteResponse = NonNullable<APIEndpoints['getSite']['response']>;
4
5
  type PageResponse = NonNullable<APIEndpoints['getContentByPath']['response']>;
@@ -7,6 +8,8 @@ type EntryResponse = NonNullable<APIEndpoints['getPublishedEntryPreview']['respo
7
8
  type PublicFormResponse = NonNullable<APIEndpoints['getPublicFormById']['response']>;
8
9
  type PublicBookingServicesResponse = NonNullable<APIEndpoints['getPublicBookingServices']['response']>;
9
10
  type PublicEventsResponse = NonNullable<APIEndpoints['listPublicEvents']['response']>;
11
+ type ResolveEventOccurrenceResponse = NonNullable<APIEndpoints['resolveEventOccurrence']['response']>;
12
+ type CheckRedirectResponse = NonNullable<APIEndpoints['checkRedirect']['response']>;
10
13
  /**
11
14
  * Pagination metadata returned when `includeMeta: true`
12
15
  */
@@ -189,10 +192,60 @@ interface RiverbankClient {
189
192
  to?: string;
190
193
  stage?: string;
191
194
  }): Promise<PublicEventsResponse>;
195
+ /**
196
+ * Resolve an event occurrence by URL segment (date or UUID)
197
+ *
198
+ * @param params.siteId - The site ID
199
+ * @param params.entryId - The parent content entry ID
200
+ * @param params.segment - URL segment - either a date (YYYY-MM-DD) or UUID
201
+ *
202
+ * @example
203
+ * ```ts
204
+ * // Resolve occurrence by date
205
+ * const result = await client.resolveEventOccurrence({
206
+ * siteId: 'site-id',
207
+ * entryId: 'entry-id',
208
+ * segment: '2025-01-15',
209
+ * });
210
+ *
211
+ * // Resolve occurrence by UUID
212
+ * const result = await client.resolveEventOccurrence({
213
+ * siteId: 'site-id',
214
+ * entryId: 'entry-id',
215
+ * segment: 'abc123-...',
216
+ * });
217
+ * ```
218
+ */
219
+ resolveEventOccurrence(params: {
220
+ siteId: string;
221
+ entryId: string;
222
+ segment: string;
223
+ }): Promise<ResolveEventOccurrenceResponse>;
224
+ /**
225
+ * Check if a path has a configured redirect rule
226
+ *
227
+ * @param params.siteId - The site ID
228
+ * @param params.path - The URL path to check
229
+ *
230
+ * @example
231
+ * ```ts
232
+ * const redirect = await client.checkRedirect({
233
+ * siteId: 'site-id',
234
+ * path: '/old-page',
235
+ * });
236
+ * if (redirect.redirect) {
237
+ * // Handle redirect to redirect.redirect.destination
238
+ * }
239
+ * ```
240
+ */
241
+ checkRedirect(params: {
242
+ siteId: string;
243
+ path: string;
244
+ }): Promise<CheckRedirectResponse>;
192
245
  /**
193
246
  * Force clear the cache
194
247
  */
195
248
  clearCache(): void;
196
249
  }
197
250
 
198
- export type { EntriesResponse as E, PageResponse as P, RiverbankClient as R, SiteResponse as S, RiverbankClientConfig as a, EntryResponse as b, EntriesResponseWithMeta as c, PaginationMeta as d };
251
+ export type { EntriesResponse as E, PageResponse as P, RiverbankClient as R, SiteResponse as S, RiverbankClientConfig as a, EntryResponse as b, EntriesResponseWithMeta as c, PaginationMeta as d, ResolveEventOccurrenceResponse as e };
@@ -1,4 +1,4 @@
1
- import { F as FieldDefinition, S as SdkCustomBlock } from './schema-Bpy9N5ZI.mjs';
1
+ import { F as FieldDefinition, S as SdkCustomBlock } from './schema-Z6-afHJG.mjs';
2
2
  import { B as BlockKind } from './blockKinds-B6MWzNWp.mjs';
3
3
 
4
4
  /**
@@ -482,6 +482,27 @@ interface BlockFieldExtension {
482
482
  * ```
483
483
  */
484
484
  type BlockFieldExtensionsMap = Record<string, BlockFieldExtension>;
485
+ /**
486
+ * Sync behavior configuration for CLI push operations.
487
+ *
488
+ * Controls how the SDK CLI handles content synchronization.
489
+ */
490
+ interface SyncConfig {
491
+ /**
492
+ * How to handle existing entries during push.
493
+ * - 'skip': Only create new entries, never update existing
494
+ * - 'update': Create new entries and update existing ones
495
+ * @default 'skip'
496
+ */
497
+ existingEntries?: 'skip' | 'update';
498
+ /**
499
+ * Target for content updates.
500
+ * - 'draft': Updates save as draft (unpublished changes)
501
+ * - 'publish': Updates are published immediately
502
+ * @default 'draft'
503
+ */
504
+ contentTarget?: 'draft' | 'publish';
505
+ }
485
506
  /**
486
507
  * Top-level SDK site configuration.
487
508
  *
@@ -530,6 +551,20 @@ type BlockFieldExtensionsMap = Record<string, BlockFieldExtension>;
530
551
  interface RiverbankSiteConfig {
531
552
  /** Site UUID from the dashboard - identifies which site this config belongs to */
532
553
  siteId: string;
554
+ /**
555
+ * Preview URL for this SDK site.
556
+ * Used by dashboard preview buttons to open the site's preview/staging environment.
557
+ * If not provided, preview buttons will be hidden for SDK sites.
558
+ * @example 'https://staging.mysite.com'
559
+ */
560
+ previewUrl?: string;
561
+ /**
562
+ * Live/production URL for this SDK site.
563
+ * Used by "View live site" links in the dashboard.
564
+ * If not provided, live site links will be hidden for SDK sites.
565
+ * @example 'https://mysite.com'
566
+ */
567
+ liveUrl?: string;
533
568
  /** SDK-defined theme with color palette for token resolution */
534
569
  theme?: SdkThemeConfig;
535
570
  /** Style configuration for curating editor options */
@@ -612,6 +647,32 @@ interface RiverbankSiteConfig {
612
647
  * ```
613
648
  */
614
649
  content?: ContentConfig;
650
+ /**
651
+ * Content directory path for CLI operations.
652
+ *
653
+ * When using `riverbankcms push` or `riverbankcms pull`, content is
654
+ * read from or written to this directory. JSON files in this directory
655
+ * are the source of truth for content.
656
+ *
657
+ * @default './content'
658
+ * @example './src/content'
659
+ */
660
+ contentDir?: string;
661
+ /**
662
+ * Sync behavior configuration for CLI push operations.
663
+ *
664
+ * Controls how the SDK CLI handles content synchronization when
665
+ * pushing content from local files to the CMS.
666
+ *
667
+ * @example
668
+ * ```typescript
669
+ * sync: {
670
+ * existingEntries: 'update', // Update existing entries
671
+ * contentTarget: 'draft', // Keep updates as drafts
672
+ * }
673
+ * ```
674
+ */
675
+ sync?: SyncConfig;
615
676
  }
616
677
 
617
- export type { BlockFieldConfig as B, ContentConfig as C, EntryConfig as E, FieldSelectOption as F, NavigationMenuConfig as N, PageConfig as P, RiverbankSiteConfig as R, SiteStyleConfig as S, SectionBackground as a, SectionOptionsConfig as b, ContainerOptionsConfig as c, SectionSpacing as d, ContainerMaxWidth as e, ContainerAlignment as f, SdkThemeConfig as g, SdkThemePalette as h, BlockFieldOptionsMap as i, BlockFieldExtension as j, BlockFieldExtensionsMap as k, ContentTypeConfig as l, BlockConfig as m, NavigationItemConfig as n, NavigationLinkType as o, SiteSettingsConfig as p };
678
+ export type { BlockFieldConfig as B, ContentTypeConfig as C, EntryConfig as E, FieldSelectOption as F, NavigationMenuConfig as N, PageConfig as P, RiverbankSiteConfig as R, SiteStyleConfig as S, ContentConfig as a, SectionBackground as b, SectionOptionsConfig as c, ContainerOptionsConfig as d, SectionSpacing as e, ContainerMaxWidth as f, ContainerAlignment as g, SdkThemeConfig as h, SdkThemePalette as i, BlockFieldOptionsMap as j, BlockFieldExtension as k, BlockFieldExtensionsMap as l, BlockConfig as m, NavigationItemConfig as n, NavigationLinkType as o, SiteSettingsConfig as p, SyncConfig as q };