@riverbankcms/sdk 0.1.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 (157) hide show
  1. package/README.md +1892 -0
  2. package/dist/cli/index.js +327 -0
  3. package/dist/cli/index.js.map +1 -0
  4. package/dist/client/analytics.d.mts +103 -0
  5. package/dist/client/analytics.d.ts +103 -0
  6. package/dist/client/analytics.js +197 -0
  7. package/dist/client/analytics.js.map +1 -0
  8. package/dist/client/analytics.mjs +169 -0
  9. package/dist/client/analytics.mjs.map +1 -0
  10. package/dist/client/bookings.d.mts +89 -0
  11. package/dist/client/bookings.d.ts +89 -0
  12. package/dist/client/bookings.js +34 -0
  13. package/dist/client/bookings.js.map +1 -0
  14. package/dist/client/bookings.mjs +11 -0
  15. package/dist/client/bookings.mjs.map +1 -0
  16. package/dist/client/client.d.mts +195 -0
  17. package/dist/client/client.d.ts +195 -0
  18. package/dist/client/client.js +606 -0
  19. package/dist/client/client.js.map +1 -0
  20. package/dist/client/client.mjs +572 -0
  21. package/dist/client/client.mjs.map +1 -0
  22. package/dist/client/hooks.d.mts +71 -0
  23. package/dist/client/hooks.d.ts +71 -0
  24. package/dist/client/hooks.js +264 -0
  25. package/dist/client/hooks.js.map +1 -0
  26. package/dist/client/hooks.mjs +235 -0
  27. package/dist/client/hooks.mjs.map +1 -0
  28. package/dist/client/rendering/client.d.mts +1 -0
  29. package/dist/client/rendering/client.d.ts +1 -0
  30. package/dist/client/rendering/client.js +33 -0
  31. package/dist/client/rendering/client.js.map +1 -0
  32. package/dist/client/rendering/client.mjs +8 -0
  33. package/dist/client/rendering/client.mjs.map +1 -0
  34. package/dist/client/usePage-BvKAa3Zw.d.mts +366 -0
  35. package/dist/client/usePage-BvKAa3Zw.d.ts +366 -0
  36. package/dist/server/chunk-2RW5HAQQ.mjs +86 -0
  37. package/dist/server/chunk-2RW5HAQQ.mjs.map +1 -0
  38. package/dist/server/chunk-3KKZVGH4.mjs +179 -0
  39. package/dist/server/chunk-3KKZVGH4.mjs.map +1 -0
  40. package/dist/server/chunk-4Z3GPTCS.js +179 -0
  41. package/dist/server/chunk-4Z3GPTCS.js.map +1 -0
  42. package/dist/server/chunk-4Z5FBFRL.mjs +211 -0
  43. package/dist/server/chunk-4Z5FBFRL.mjs.map +1 -0
  44. package/dist/server/chunk-ADREPXFU.js +86 -0
  45. package/dist/server/chunk-ADREPXFU.js.map +1 -0
  46. package/dist/server/chunk-F472SMKX.js +140 -0
  47. package/dist/server/chunk-F472SMKX.js.map +1 -0
  48. package/dist/server/chunk-GWBMJPLH.mjs +57 -0
  49. package/dist/server/chunk-GWBMJPLH.mjs.map +1 -0
  50. package/dist/server/chunk-JB4LIEFS.js +85 -0
  51. package/dist/server/chunk-JB4LIEFS.js.map +1 -0
  52. package/dist/server/chunk-PEAXKTDU.mjs +140 -0
  53. package/dist/server/chunk-PEAXKTDU.mjs.map +1 -0
  54. package/dist/server/chunk-QQ6U4QX6.js +120 -0
  55. package/dist/server/chunk-QQ6U4QX6.js.map +1 -0
  56. package/dist/server/chunk-R5YGLRUG.mjs +122 -0
  57. package/dist/server/chunk-R5YGLRUG.mjs.map +1 -0
  58. package/dist/server/chunk-SW7LE4M3.js +211 -0
  59. package/dist/server/chunk-SW7LE4M3.js.map +1 -0
  60. package/dist/server/chunk-W3K7LVPS.mjs +120 -0
  61. package/dist/server/chunk-W3K7LVPS.mjs.map +1 -0
  62. package/dist/server/chunk-WKG57P2H.mjs +85 -0
  63. package/dist/server/chunk-WKG57P2H.mjs.map +1 -0
  64. package/dist/server/chunk-YHEZMVTS.js +122 -0
  65. package/dist/server/chunk-YHEZMVTS.js.map +1 -0
  66. package/dist/server/chunk-YXDDFG3N.js +57 -0
  67. package/dist/server/chunk-YXDDFG3N.js.map +1 -0
  68. package/dist/server/components.d.mts +49 -0
  69. package/dist/server/components.d.ts +49 -0
  70. package/dist/server/components.js +22 -0
  71. package/dist/server/components.js.map +1 -0
  72. package/dist/server/components.mjs +22 -0
  73. package/dist/server/components.mjs.map +1 -0
  74. package/dist/server/config-validation.d.mts +300 -0
  75. package/dist/server/config-validation.d.ts +300 -0
  76. package/dist/server/config-validation.js +50 -0
  77. package/dist/server/config-validation.js.map +1 -0
  78. package/dist/server/config-validation.mjs +50 -0
  79. package/dist/server/config-validation.mjs.map +1 -0
  80. package/dist/server/config.d.mts +38 -0
  81. package/dist/server/config.d.ts +38 -0
  82. package/dist/server/config.js +44 -0
  83. package/dist/server/config.js.map +1 -0
  84. package/dist/server/config.mjs +44 -0
  85. package/dist/server/config.mjs.map +1 -0
  86. package/dist/server/data.d.mts +108 -0
  87. package/dist/server/data.d.ts +108 -0
  88. package/dist/server/data.js +15 -0
  89. package/dist/server/data.js.map +1 -0
  90. package/dist/server/data.mjs +15 -0
  91. package/dist/server/data.mjs.map +1 -0
  92. package/dist/server/index-B0yI_V6Z.d.mts +18 -0
  93. package/dist/server/index-C6M0Wfjq.d.ts +18 -0
  94. package/dist/server/index.d.mts +5 -0
  95. package/dist/server/index.d.ts +5 -0
  96. package/dist/server/index.js +12 -0
  97. package/dist/server/index.js.map +1 -0
  98. package/dist/server/index.mjs +12 -0
  99. package/dist/server/index.mjs.map +1 -0
  100. package/dist/server/loadContent-CJcbYF3J.d.ts +152 -0
  101. package/dist/server/loadContent-zhlL4YSE.d.mts +152 -0
  102. package/dist/server/loadPage-BYmVMk0V.d.ts +216 -0
  103. package/dist/server/loadPage-CCf15nt8.d.mts +216 -0
  104. package/dist/server/loadPage-DVH3DW6E.js +9 -0
  105. package/dist/server/loadPage-DVH3DW6E.js.map +1 -0
  106. package/dist/server/loadPage-PHQZ6XQZ.mjs +9 -0
  107. package/dist/server/loadPage-PHQZ6XQZ.mjs.map +1 -0
  108. package/dist/server/metadata.d.mts +135 -0
  109. package/dist/server/metadata.d.ts +135 -0
  110. package/dist/server/metadata.js +68 -0
  111. package/dist/server/metadata.js.map +1 -0
  112. package/dist/server/metadata.mjs +68 -0
  113. package/dist/server/metadata.mjs.map +1 -0
  114. package/dist/server/rendering/server.d.mts +83 -0
  115. package/dist/server/rendering/server.d.ts +83 -0
  116. package/dist/server/rendering/server.js +14 -0
  117. package/dist/server/rendering/server.js.map +1 -0
  118. package/dist/server/rendering/server.mjs +14 -0
  119. package/dist/server/rendering/server.mjs.map +1 -0
  120. package/dist/server/rendering.d.mts +12 -0
  121. package/dist/server/rendering.d.ts +12 -0
  122. package/dist/server/rendering.js +40 -0
  123. package/dist/server/rendering.js.map +1 -0
  124. package/dist/server/rendering.mjs +40 -0
  125. package/dist/server/rendering.mjs.map +1 -0
  126. package/dist/server/routing.d.mts +115 -0
  127. package/dist/server/routing.d.ts +115 -0
  128. package/dist/server/routing.js +57 -0
  129. package/dist/server/routing.js.map +1 -0
  130. package/dist/server/routing.mjs +57 -0
  131. package/dist/server/routing.mjs.map +1 -0
  132. package/dist/server/server.d.mts +9 -0
  133. package/dist/server/server.d.ts +9 -0
  134. package/dist/server/server.js +21 -0
  135. package/dist/server/server.js.map +1 -0
  136. package/dist/server/server.mjs +21 -0
  137. package/dist/server/server.mjs.map +1 -0
  138. package/dist/server/theme-bridge.d.mts +232 -0
  139. package/dist/server/theme-bridge.d.ts +232 -0
  140. package/dist/server/theme-bridge.js +231 -0
  141. package/dist/server/theme-bridge.js.map +1 -0
  142. package/dist/server/theme-bridge.mjs +231 -0
  143. package/dist/server/theme-bridge.mjs.map +1 -0
  144. package/dist/server/theme.d.mts +40 -0
  145. package/dist/server/theme.d.ts +40 -0
  146. package/dist/server/theme.js +17 -0
  147. package/dist/server/theme.js.map +1 -0
  148. package/dist/server/theme.mjs +17 -0
  149. package/dist/server/theme.mjs.map +1 -0
  150. package/dist/server/types-BCeqWtI2.d.mts +333 -0
  151. package/dist/server/types-BCeqWtI2.d.ts +333 -0
  152. package/dist/server/types-Bbo01M7P.d.mts +76 -0
  153. package/dist/server/types-Bbo01M7P.d.ts +76 -0
  154. package/dist/server/types-C6gmRHLe.d.mts +150 -0
  155. package/dist/server/types-C6gmRHLe.d.ts +150 -0
  156. package/package.json +147 -0
  157. package/src/styles/index.css +10 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/rendering/hooks/usePage.ts","../../src/data/prefetchBlockData.ts","../../src/rendering/hooks/useContent.ts","../../src/rendering/components/Page.tsx","../../src/client/index.ts","../../src/client/cache.ts"],"sourcesContent":["/**\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 * SDK wrapper for block data prefetching.\n * Uses the shared core implementation from @riverbankcms/blocks with the SDK client.\n */\n\nimport type { BlockDataLoader, PageOutline, SdkCustomBlock } from '@riverbankcms/blocks';\nimport { prefetchBlockData as prefetchBlockDataCore } from '@riverbankcms/blocks/system/data';\nimport type { PrefetchContext, ResolvedBlockData } from '@riverbankcms/blocks/system/data';\nimport type { RiverbankClient } from '../client/types';\n\nexport type { PrefetchContext, ResolvedBlockData };\n\n/**\n * Supported loader endpoints for SDK data fetching.\n * Only these endpoints can be used in block data loaders when using the SDK.\n *\n * This is the SINGLE SOURCE OF TRUTH for whitelisted endpoints.\n * - Zod validation schema derives from this array\n * - TypeScript types derive from this array\n * - Runtime validation uses this array\n */\nexport const SUPPORTED_LOADER_ENDPOINTS = [\n 'listPublishedEntries',\n 'getPublishedEntryPreview',\n 'listPublicEvents',\n 'getPublicFormById',\n 'getPublicBookingServices',\n] as const;\n\n/**\n * Union type of all supported loader endpoints.\n * Derived from SUPPORTED_LOADER_ENDPOINTS array.\n */\nexport type SupportedLoaderEndpoint = typeof SUPPORTED_LOADER_ENDPOINTS[number];\n\n/**\n * Options for SDK block data prefetching.\n */\nexport type SdkPrefetchOptions = {\n /**\n * SDK custom blocks from site config.\n * Used to look up data loaders for custom.* blocks.\n */\n customBlocks?: SdkCustomBlock[];\n};\n\n/**\n * Prefetch block data for SDK-based applications.\n * Maps loader endpoints to corresponding SDK client methods.\n *\n * Supports both system blocks and SDK custom blocks with data loaders.\n *\n * @example\n * ```typescript\n * import { createRiverbankClient } from '@riverbankcms/sdk';\n * import { prefetchBlockData } from '@riverbankcms/sdk/data';\n *\n * const client = createRiverbankClient({ apiKey, baseUrl });\n * const page = await client.getPage({ siteId, path: '/' });\n *\n * // Basic usage (system blocks only)\n * const blockData = await prefetchBlockData(page.outline, {\n * siteId: page.siteId,\n * pageId: page.id,\n * }, client);\n *\n * // With custom blocks from SDK config\n * const blockData = await prefetchBlockData(page.outline, context, client, {\n * customBlocks: site.sdkConfig?.customBlocks,\n * });\n * ```\n */\nexport async function prefetchBlockData(\n page: PageOutline,\n context: PrefetchContext,\n client: RiverbankClient,\n options?: SdkPrefetchOptions,\n): Promise<ResolvedBlockData> {\n const { customBlocks } = options ?? {};\n\n // Build lookup map for custom block loaders\n // Key is string (blockKind from page) matching block.id (custom.xxx)\n const customBlockMap = new Map<string, SdkCustomBlock>(\n (customBlocks ?? []).map((block) => [block.id as string, block])\n );\n\n return prefetchBlockDataCore(page, context, {\n apiClient: async ({ endpoint, params }) => {\n // Only support whitelisted loader endpoints\n if (!isSupportedEndpoint(endpoint)) {\n throw new Error(\n `Unsupported loader endpoint: ${endpoint}. ` +\n `SDK only supports: ${SUPPORTED_LOADER_ENDPOINTS.join(', ')}`\n );\n }\n\n // Map endpoint to SDK client method\n switch (endpoint) {\n case 'listPublishedEntries': {\n const { siteId, type, orderBy, limit, stage, mode, entryIds } = params ?? {};\n if (!siteId || !type) {\n throw new Error('listPublishedEntries requires siteId and type params');\n }\n\n // Parse limit if provided (can come as string from bindings)\n const parsedLimit = typeof limit === 'string'\n ? Number.parseInt(limit, 10)\n : typeof limit === 'number'\n ? limit\n : undefined;\n\n // Map orderBy to order param (matching embed block field values)\n const order = (orderBy === 'newest' || orderBy === 'oldest' || orderBy === 'title' || orderBy === 'order')\n ? orderBy as 'newest' | 'oldest' | 'title' | 'order'\n : undefined;\n\n // Extract entry IDs for manual mode\n // entryIds comes from binding to entries field which contains { entryId: \"uuid\" } objects\n let parsedEntryIds: string[] | undefined;\n if (mode === 'manual' && Array.isArray(entryIds)) {\n parsedEntryIds = entryIds\n .map((item: unknown) => {\n if (typeof item === 'object' && item !== null && 'entryId' in item) {\n return (item as { entryId: string }).entryId;\n }\n // Also support direct string IDs\n if (typeof item === 'string') {\n return item;\n }\n return null;\n })\n .filter((id): id is string => id !== null);\n }\n\n return await client.getEntries({\n siteId,\n contentType: type,\n limit: parsedLimit,\n order,\n preview: stage === 'preview',\n // Manual mode - pass entry IDs for hydration\n mode: mode === 'manual' ? 'manual' : undefined,\n entryIds: parsedEntryIds,\n });\n }\n\n case 'getPublishedEntryPreview': {\n const { siteId, type, slug } = params ?? {};\n if (!siteId || !type || !slug) {\n throw new Error('getPublishedEntryPreview requires siteId, type, and slug params');\n }\n return await client.getEntry({ siteId, contentType: type, slug });\n }\n case 'listPublicEvents': {\n const { siteId, limit, from, to, stage } = params ?? {};\n if (!siteId) {\n throw new Error('listPublicEvents requires siteId param');\n }\n const parsedLimit =\n typeof limit === 'string'\n ? Number.parseInt(limit, 10)\n : typeof limit === 'number'\n ? limit\n : undefined;\n return await client.listPublicEvents({ siteId, limit: parsedLimit, from, to, stage });\n }\n case 'getPublicFormById': {\n const { formId } = params ?? {};\n if (!formId) {\n throw new Error('getPublicFormById requires formId param');\n }\n return await client.getPublicFormById({ formId });\n }\n case 'getPublicBookingServices': {\n const { siteId, ids } = params ?? {};\n if (!siteId) {\n throw new Error('getPublicBookingServices requires siteId param');\n }\n return await client.getPublicBookingServices({ siteId, ids });\n }\n\n default: {\n // TypeScript should never reach here due to isSupportedEndpoint check\n const _exhaustive: never = endpoint;\n throw new Error(`Unhandled endpoint: ${_exhaustive}`);\n }\n }\n },\n isValidEndpoint: isSupportedEndpoint,\n onError: (error, { block, loader }) => {\n console.warn('[prefetchBlockData] failed to prefetch block data', {\n block,\n loader,\n error,\n });\n },\n // Provide custom block loader lookup for SDK custom blocks\n getCustomBlockLoaders: (blockKind): Record<string, BlockDataLoader> | undefined => {\n const customBlock = customBlockMap.get(blockKind);\n if (!customBlock?.dataLoaders) return undefined;\n\n // Convert SdkConfigLoader to BlockDataLoader\n // SdkConfigLoader.endpoint is SdkLoaderEndpoint (string union) -> string\n // SdkConfigLoader.params is Record<string, LoaderParamValue> -> Record<string, unknown>\n // Both are structurally compatible via covariance\n const loaders: Record<string, BlockDataLoader> = {};\n for (const [key, loader] of Object.entries(customBlock.dataLoaders)) {\n loaders[key] = {\n endpoint: loader.endpoint,\n params: loader.params,\n mode: loader.mode,\n };\n }\n return loaders;\n },\n });\n}\n\n/**\n * Type guard for supported loader endpoints\n */\nfunction isSupportedEndpoint(endpoint: string): endpoint is SupportedLoaderEndpoint {\n return SUPPORTED_LOADER_ENDPOINTS.includes(endpoint as SupportedLoaderEndpoint);\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 * Pure Page renderer component for Riverbank CMS.\n *\n * This component expects all data to be provided via props.\n * For data fetching, use:\n * - Server-side: `await loadPage({ client, siteId, path })`\n * - Client-side: `usePage({ client, siteId, path })`\n */\n\nimport { PageRenderer, buildThemeRuntime } from '@riverbankcms/blocks';\nimport type { PageOutline, RouteMap, Theme, ThemeTokens, BlockOverrides, OccurrenceContextData } from '@riverbankcms/blocks';\nimport type { ResolvedBlockData } from '../../data';\nimport type { RuntimeSdkConfig } from '../helpers/loadPage';\n\n// Re-export OccurrenceContextData for SDK consumers\nexport type { OccurrenceContextData };\n\nexport type PageProps = {\n // Required data (must be provided by caller)\n page: PageOutline;\n theme: Theme;\n siteId: string;\n\n // Optional data\n themeTokens?: ThemeTokens; // If not provided, will be built from theme\n resolvedData?: ResolvedBlockData; // Pre-fetched block data\n routeMap?: RouteMap;\n /**\n * SDK site configuration containing theme palette overrides.\n * When provided, the SDK palette tokens are merged into the theme tokens,\n * allowing blocks to use SDK-defined color tokens for section backgrounds.\n */\n sdkConfig?: RuntimeSdkConfig | null;\n\n /**\n * Additional context data for content entry pages.\n * Used to pass occurrence context and content entry data to blocks.\n */\n dataContext?: {\n /** Occurrence context for event pages (from URL like /events/yoga/2025-01-15) */\n occurrenceContext?: OccurrenceContextData | null;\n /** Content entry data for template pages */\n contentEntry?: Record<string, unknown> | null;\n };\n\n // Customization\n wrapBlock?: (blockId: string, rendered: React.ReactNode) => React.ReactNode;\n registry?: Parameters<typeof PageRenderer>[0]['registry'];\n usePlaceholders?: boolean;\n /**\n * Custom components to override default block rendering.\n * Keys can be full block kind (\"block.hero\") or short form (\"hero\").\n *\n * This is SSR-safe - no context or hooks required.\n *\n * @example\n * ```tsx\n * <Page\n * {...pageData}\n * blockOverrides={{\n * 'hero': MyCustomHero,\n * 'block.testimonials': MyCustomTestimonials,\n * }}\n * />\n * ```\n */\n blockOverrides?: BlockOverrides;\n};\n\n/**\n * Pure renderer for Riverbank CMS pages.\n *\n * This component expects all data to be provided via props.\n * For data fetching, use:\n * - Server-side: `await loadPage({ client, siteId, path })`\n * - Client-side: `usePage({ client, siteId, path })`\n *\n * @example Server-side (Next.js App Router)\n * ```tsx\n * import { createRiverbankClient } from '@riverbankcms/sdk';\n * import { loadPage, Page } from '@riverbankcms/sdk/rendering';\n *\n * const client = createRiverbankClient({ apiKey, baseUrl });\n *\n * export default async function PageRoute({ params }) {\n * const pageData = await loadPage({\n * client,\n * siteId: 'site-id',\n * path: `/${params.slug}`,\n * });\n *\n * return <Page {...pageData} />;\n * }\n * ```\n *\n * @example Client-side\n * ```tsx\n * import { createRiverbankClient } from '@riverbankcms/sdk';\n * import { usePage, Page } from '@riverbankcms/sdk/rendering';\n *\n * const client = createRiverbankClient({ apiKey, baseUrl });\n *\n * function MyPage({ path }) {\n * const pageData = usePage({ client, siteId: 'site-id', path });\n *\n * if (pageData.loading) return <LoadingState />;\n * if (pageData.error) return <ErrorState error={pageData.error} />;\n * if (!pageData.page) return <NotFound />;\n *\n * return <Page {...pageData} />;\n * }\n * ```\n */\nexport function Page({\n page,\n theme,\n themeTokens: providedTokens,\n siteId,\n resolvedData,\n routeMap,\n wrapBlock,\n registry,\n usePlaceholders = false,\n blockOverrides,\n sdkConfig,\n dataContext,\n}: PageProps) {\n // Build theme tokens if not provided\n const baseTokens = providedTokens ?? buildThemeRuntime(theme).tokens;\n\n // Merge SDK palette tokens into theme tokens\n // This allows blocks to resolve SDK-defined color tokens (e.g., 'primary' -> '#6d28d9')\n const themeTokens = sdkConfig?.theme?.palette\n ? { ...baseTokens, palette: { ...baseTokens.palette, ...sdkConfig.theme.palette } }\n : baseTokens;\n\n return (\n <PageRenderer\n theme={theme}\n page={page}\n themeTokens={themeTokens}\n usePlaceholders={usePlaceholders}\n dataContext={{\n siteId,\n resolvedData,\n routes: routeMap,\n occurrenceContext: dataContext?.occurrenceContext ?? null,\n contentEntry: dataContext?.contentEntry ?? null,\n }}\n routeMap={routeMap}\n wrapBlock={wrapBlock}\n registry={registry}\n blockOverrides={blockOverrides}\n sdkConfig={sdkConfig}\n />\n );\n}\n","import { createBearerAPIClient } from '@riverbankcms/api';\nimport type {\n RiverbankClient,\n RiverbankClientConfig,\n PublicBookingServicesResponse,\n PublicEventsResponse,\n PublicFormResponse,\n} from './types';\nimport { SimpleCache } from './cache';\n\n/**\n * Create a Riverbank CMS client for fetching content\n *\n * @example\n * ```ts\n * const client = createRiverbankClient({\n * apiKey: 'bld_live_sk_...',\n * baseUrl: 'https://dashboard.example.com/api',\n * });\n *\n * const site = await client.getSite({ slug: 'my-site' });\n * ```\n */\nexport function createRiverbankClient(config: RiverbankClientConfig): RiverbankClient {\n if (!config.baseUrl) {\n throw new Error(\n 'baseUrl is required when creating a Builder client. ' +\n 'Expected format: https://dashboard.example.com/api (must include /api path)'\n );\n }\n\n // Validate baseUrl format\n if (!config.baseUrl.endsWith('/api')) {\n throw new Error(\n `baseUrl must end with '/api'. Received: ${config.baseUrl}. ` +\n 'Expected format: https://dashboard.example.com/api'\n );\n }\n\n const cacheEnabled = config.cache?.enabled ?? true;\n const cacheTTL = (config.cache?.ttl ?? 300) * 1000; // Convert seconds to milliseconds\n const cacheMaxSize = config.cache?.maxSize ?? 100;\n\n // Create internal API client with Bearer token auth\n const apiClient = createBearerAPIClient(config.apiKey, config.baseUrl);\n\n // Create cache instance\n const cache = new SimpleCache<unknown>({\n maxSize: cacheMaxSize,\n ttl: cacheTTL,\n });\n\n /**\n * Helper to cache API calls\n */\n async function cachedFetch<T>(\n cacheKey: string,\n fetcher: () => Promise<T>,\n options?: { force?: boolean }\n ): Promise<T> {\n // Check cache unless force is true\n if (cacheEnabled && !options?.force) {\n const cached = cache.get(cacheKey) as T | undefined;\n if (cached !== undefined) {\n return cached;\n }\n }\n\n // Fetch fresh data\n const data = await fetcher();\n\n // Store in cache\n if (cacheEnabled) {\n cache.set(cacheKey, data);\n }\n\n return data;\n }\n\n return {\n async getSite(params) {\n const { slug, domain, id } = params;\n\n if (!slug && !domain && !id) {\n throw new Error(\n 'getSite() requires at least one identifier: slug, domain, or id. ' +\n `Received: ${JSON.stringify(params)}`\n );\n }\n\n const cacheKey = `site:${slug || domain || id}`;\n\n return cachedFetch(cacheKey, async () => {\n // Convert params to string record for API client\n const apiParams: Record<string, string> = {};\n if (params.slug) apiParams.slug = params.slug;\n if (params.domain) apiParams.domain = params.domain;\n if (params.id) apiParams.id = params.id;\n return await apiClient({ endpoint: 'getSite', params: apiParams });\n });\n },\n\n async getPage(params) {\n const { siteId, path, preview = false } = params;\n const cacheKey = `page:${siteId}:${path}:${preview}`;\n\n return cachedFetch(cacheKey, async () => {\n return await apiClient({ endpoint: 'getContentByPath', params: { siteId }, body: { path, preview } });\n });\n },\n\n async getEntries(params) {\n const { siteId, contentType, limit, order, preview = false, mode, entryIds } = params;\n\n // Include all params in cache key to ensure different queries are cached separately\n const entryIdsCacheKey = mode === 'manual' && entryIds?.length ? entryIds.join(',') : '';\n const cacheKey = `entries:${siteId}:${contentType}:${limit ?? ''}:${order ?? ''}:${preview}:${mode ?? ''}:${entryIdsCacheKey}`;\n\n return cachedFetch(cacheKey, async () => {\n // Build API params\n const apiParams: Record<string, string> = {\n siteId,\n type: contentType,\n };\n\n // Add optional pagination\n if (typeof limit === 'number') {\n apiParams.limit = String(limit);\n }\n\n // Convert user-friendly order to API format\n // 'order' means custom ordering - we don't pass an order param (API default)\n if (order === 'newest') {\n apiParams.order = 'published_at.desc';\n } else if (order === 'oldest') {\n apiParams.order = 'published_at.asc';\n } else if (order === 'title') {\n apiParams.order = 'title.asc';\n }\n // 'order' or undefined: don't set order param, use API default\n\n // Add preview stage if enabled\n if (preview) {\n apiParams.stage = 'preview';\n }\n\n // Manual mode - pass entry IDs for hydration\n if (mode === 'manual' && entryIds?.length) {\n apiParams.mode = 'manual';\n apiParams.entryIds = JSON.stringify(entryIds);\n }\n\n return await apiClient({ endpoint: 'listPublishedEntries', params: apiParams });\n });\n },\n\n async getEntry(params) {\n const { siteId, contentType, slug } = params;\n const cacheKey = `entry:${siteId}:${contentType}:${slug}`;\n\n return cachedFetch(cacheKey, async () => {\n return await apiClient({ endpoint: 'getPublishedEntryPreview', params: { siteId, type: contentType, slug } });\n });\n },\n\n async getPublicFormById(params) {\n const { formId } = params;\n if (!formId) {\n throw new Error('getPublicFormById() requires formId');\n }\n const cacheKey = `public-form:${formId}`;\n return cachedFetch(cacheKey, async () => {\n return await apiClient({ endpoint: 'getPublicFormById', params: { formId } }) as PublicFormResponse;\n });\n },\n\n async getPublicBookingServices(params) {\n const { siteId, ids } = params;\n if (!siteId) {\n throw new Error('getPublicBookingServices() requires siteId');\n }\n const cacheKey = `public-booking-services:${siteId}:${ids ?? ''}`;\n return cachedFetch(cacheKey, async () => {\n const apiParams: Record<string, string> = { siteId };\n if (ids) apiParams.ids = ids;\n return await apiClient({ endpoint: 'getPublicBookingServices', params: apiParams }) as PublicBookingServicesResponse;\n });\n },\n\n async listPublicEvents(params) {\n const { siteId, limit, from, to, stage } = params;\n if (!siteId) {\n throw new Error('listPublicEvents() requires siteId');\n }\n const cacheKey = `public-events:${siteId}:${limit ?? ''}:${from ?? ''}:${to ?? ''}:${stage ?? ''}`;\n return cachedFetch(cacheKey, async () => {\n const apiParams: Record<string, string> = { siteId };\n if (typeof limit === 'number') apiParams.limit = String(limit);\n if (from) apiParams.from = from;\n if (to) apiParams.to = to;\n if (stage) apiParams.stage = stage;\n return await apiClient({ endpoint: 'listPublicEvents', params: apiParams }) as PublicEventsResponse;\n });\n },\n\n clearCache() {\n cache.clear();\n },\n };\n}\n\n// Re-export types\nexport type { RiverbankClient, RiverbankClientConfig } from './types';\n","/**\n * Simple in-memory cache with TTL support\n */\nexport class SimpleCache<T> {\n private cache = new Map<string, { value: T; expires: number }>();\n private maxSize: number;\n private ttl: number;\n\n constructor(options: { maxSize?: number; ttl?: number } = {}) {\n this.maxSize = options.maxSize ?? 100;\n this.ttl = options.ttl ?? 300000; // 5 minutes in milliseconds\n }\n\n get(key: string): T | undefined {\n const entry = this.cache.get(key);\n if (!entry) return undefined;\n\n // Check if expired\n if (Date.now() > entry.expires) {\n this.cache.delete(key);\n return undefined;\n }\n\n return entry.value;\n }\n\n set(key: string, value: T): void {\n // Enforce max size with simple FIFO eviction\n if (this.cache.size >= this.maxSize) {\n const firstKey = this.cache.keys().next().value;\n if (firstKey) {\n this.cache.delete(firstKey);\n }\n }\n\n this.cache.set(key, {\n value,\n expires: Date.now() + this.ttl,\n });\n }\n\n clear(): void {\n this.cache.clear();\n }\n\n has(key: string): boolean {\n return this.get(key) !== undefined;\n }\n}\n"],"mappings":";AAMA,SAAS,UAAU,iBAAiB;;;ACApC,SAAS,qBAAqB,6BAA6B;AAepD,IAAM,6BAA6B;AAAA,EACxC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AA6CA,eAAsB,kBACpB,MACA,SACA,QACA,SAC4B;AAC5B,QAAM,EAAE,aAAa,IAAI,WAAW,CAAC;AAIrC,QAAM,iBAAiB,IAAI;AAAA,KACxB,gBAAgB,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,MAAM,IAAc,KAAK,CAAC;AAAA,EACjE;AAEA,SAAO,sBAAsB,MAAM,SAAS;AAAA,IAC1C,WAAW,OAAO,EAAE,UAAU,OAAO,MAAM;AAEzC,UAAI,CAAC,oBAAoB,QAAQ,GAAG;AAClC,cAAM,IAAI;AAAA,UACR,gCAAgC,QAAQ,wBAClB,2BAA2B,KAAK,IAAI,CAAC;AAAA,QAC7D;AAAA,MACF;AAGA,cAAQ,UAAU;AAAA,QAChB,KAAK,wBAAwB;AAC3B,gBAAM,EAAE,QAAQ,MAAM,SAAS,OAAO,OAAO,MAAM,SAAS,IAAI,UAAU,CAAC;AAC3E,cAAI,CAAC,UAAU,CAAC,MAAM;AACpB,kBAAM,IAAI,MAAM,sDAAsD;AAAA,UACxE;AAGA,gBAAM,cAAc,OAAO,UAAU,WACjC,OAAO,SAAS,OAAO,EAAE,IACzB,OAAO,UAAU,WACf,QACA;AAGN,gBAAM,QAAS,YAAY,YAAY,YAAY,YAAY,YAAY,WAAW,YAAY,UAC9F,UACA;AAIJ,cAAI;AACJ,cAAI,SAAS,YAAY,MAAM,QAAQ,QAAQ,GAAG;AAChD,6BAAiB,SACd,IAAI,CAAC,SAAkB;AACtB,kBAAI,OAAO,SAAS,YAAY,SAAS,QAAQ,aAAa,MAAM;AAClE,uBAAQ,KAA6B;AAAA,cACvC;AAEA,kBAAI,OAAO,SAAS,UAAU;AAC5B,uBAAO;AAAA,cACT;AACA,qBAAO;AAAA,YACT,CAAC,EACA,OAAO,CAAC,OAAqB,OAAO,IAAI;AAAA,UAC7C;AAEA,iBAAO,MAAM,OAAO,WAAW;AAAA,YAC7B;AAAA,YACA,aAAa;AAAA,YACb,OAAO;AAAA,YACP;AAAA,YACA,SAAS,UAAU;AAAA;AAAA,YAEnB,MAAM,SAAS,WAAW,WAAW;AAAA,YACrC,UAAU;AAAA,UACZ,CAAC;AAAA,QACH;AAAA,QAEA,KAAK,4BAA4B;AAC/B,gBAAM,EAAE,QAAQ,MAAM,KAAK,IAAI,UAAU,CAAC;AAC1C,cAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,MAAM;AAC7B,kBAAM,IAAI,MAAM,iEAAiE;AAAA,UACnF;AACA,iBAAO,MAAM,OAAO,SAAS,EAAE,QAAQ,aAAa,MAAM,KAAK,CAAC;AAAA,QAClE;AAAA,QACA,KAAK,oBAAoB;AACvB,gBAAM,EAAE,QAAQ,OAAO,MAAM,IAAI,MAAM,IAAI,UAAU,CAAC;AACtD,cAAI,CAAC,QAAQ;AACX,kBAAM,IAAI,MAAM,wCAAwC;AAAA,UAC1D;AACA,gBAAM,cACJ,OAAO,UAAU,WACb,OAAO,SAAS,OAAO,EAAE,IACzB,OAAO,UAAU,WACf,QACA;AACR,iBAAO,MAAM,OAAO,iBAAiB,EAAE,QAAQ,OAAO,aAAa,MAAM,IAAI,MAAM,CAAC;AAAA,QACtF;AAAA,QACA,KAAK,qBAAqB;AACxB,gBAAM,EAAE,OAAO,IAAI,UAAU,CAAC;AAC9B,cAAI,CAAC,QAAQ;AACX,kBAAM,IAAI,MAAM,yCAAyC;AAAA,UAC3D;AACA,iBAAO,MAAM,OAAO,kBAAkB,EAAE,OAAO,CAAC;AAAA,QAClD;AAAA,QACA,KAAK,4BAA4B;AAC/B,gBAAM,EAAE,QAAQ,IAAI,IAAI,UAAU,CAAC;AACnC,cAAI,CAAC,QAAQ;AACX,kBAAM,IAAI,MAAM,gDAAgD;AAAA,UAClE;AACA,iBAAO,MAAM,OAAO,yBAAyB,EAAE,QAAQ,IAAI,CAAC;AAAA,QAC9D;AAAA,QAEA,SAAS;AAEP,gBAAM,cAAqB;AAC3B,gBAAM,IAAI,MAAM,uBAAuB,WAAW,EAAE;AAAA,QACtD;AAAA,MACF;AAAA,IACF;AAAA,IACA,iBAAiB;AAAA,IACjB,SAAS,CAAC,OAAO,EAAE,OAAO,OAAO,MAAM;AACrC,cAAQ,KAAK,qDAAqD;AAAA,QAChE;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC;AAAA,IACH;AAAA;AAAA,IAEA,uBAAuB,CAAC,cAA2D;AACjF,YAAM,cAAc,eAAe,IAAI,SAAS;AAChD,UAAI,CAAC,aAAa,YAAa,QAAO;AAMtC,YAAM,UAA2C,CAAC;AAClD,iBAAW,CAAC,KAAK,MAAM,KAAK,OAAO,QAAQ,YAAY,WAAW,GAAG;AACnE,gBAAQ,GAAG,IAAI;AAAA,UACb,UAAU,OAAO;AAAA,UACjB,QAAQ,OAAO;AAAA,UACf,MAAM,OAAO;AAAA,QACf;AAAA,MACF;AACA,aAAO;AAAA,IACT;AAAA,EACF,CAAC;AACH;AAKA,SAAS,oBAAoB,UAAuD;AAClF,SAAO,2BAA2B,SAAS,QAAmC;AAChF;;;AD5HO,SAAS,QAAQ,QAAsC;AAC5D,QAAM,EAAE,QAAQ,QAAQ,MAAM,QAAQ,UAAU,MAAM,IAAI;AAE1D,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAwB;AAAA,IAClD,SAAS;AAAA,IACT,OAAO;AAAA,IACP,MAAM;AAAA,IACN,OAAO;AAAA,IACP;AAAA,IACA,cAAc;AAAA,IACd,WAAW;AAAA,EACb,CAAC;AAED,YAAU,MAAM;AACd,QAAI,YAAY;AAEhB,mBAAe,YAAY;AACzB,UAAI;AAEF,cAAM,CAAC,MAAM,YAAY,IAAI,MAAM,QAAQ,IAAI;AAAA,UAC7C,OAAO,QAAQ,EAAE,IAAI,OAAO,CAAC;AAAA,UAC7B,OAAO,QAAQ,EAAE,QAAQ,MAAM,QAAQ,CAAC;AAAA,QAC1C,CAAC;AAGD,YAAI,UAAW;AAGf,YAAI,WAAW,cAAc;AAC3B,gBAAM,IAAI;AAAA,YACR;AAAA,UAGF;AAAA,QACF;AAEA,cAAM,EAAE,MAAM,SAAS,IAAI;AAI3B,cAAM,SAAS,SAAS,OAAO,IAAI,CAAC,UAAU;AAC5C,cAAI,CAAC,SAAS,OAAO,UAAU,UAAU;AACvC,kBAAM,IAAI,MAAM,sCAAsC;AAAA,UACxD;AACA,cAAI,OAAO,MAAM,OAAO,YAAY,MAAM,OAAO,MAAM;AACrD,kBAAM,IAAI,MAAM,kDAAkD,OAAO,MAAM,EAAE,EAAE;AAAA,UACrF;AACA,cAAI,OAAO,MAAM,SAAS,UAAU;AAClC,kBAAM,IAAI,MAAM,4CAA4C,OAAO,MAAM,IAAI,EAAE;AAAA,UACjF;AACA,cAAI,OAAO,MAAM,YAAY,UAAU;AACrC,kBAAM,IAAI,MAAM,+CAA+C,OAAO,MAAM,OAAO,EAAE;AAAA,UACvF;AACA,iBAAO;AAAA,YACL,IAAI,MAAM;AAAA,YACV,MAAM,MAAM;AAAA,YACZ,SAAS,MAAM;AAAA,UACjB;AAAA,QACF,CAAC;AAED,cAAM,cAAc;AAAA,UAClB,MAAM,SAAS;AAAA,UACf,MAAM,SAAS;AAAA,UACf,SAAS,SAAS;AAAA,UAClB;AAAA,QACF;AAGA,cAAM,eAAe,MAAM;AAAA,UACzB;AAAA,UACA;AAAA,YACE;AAAA,YACA,QAAQ,UAAU,SAAS;AAAA,YAC3B,cAAc,UAAU,YAAY;AAAA,UACtC;AAAA,UACA;AAAA,QACF;AAGA,YAAI,UAAW;AAEf,kBAAU;AAAA,UACR,SAAS;AAAA,UACT,OAAO;AAAA,UACP,MAAM;AAAA,UACN,OAAO,KAAK;AAAA,UACZ;AAAA,UACA;AAAA,UACA,WAAW,KAAK,aAAa;AAAA,QAC/B,CAAC;AAAA,MACH,SAAS,OAAO;AACd,YAAI,UAAW;AAEf,kBAAU;AAAA,UACR,SAAS;AAAA,UACT,OAAO,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC;AAAA,UAC/D,MAAM;AAAA,UACN,OAAO;AAAA,UACP;AAAA,UACA,cAAc;AAAA,UACd,WAAW;AAAA,QACb,CAAC;AAAA,MACH;AAAA,IACF;AAEA,cAAU;AAEV,WAAO,MAAM;AACX,kBAAY;AAAA,IACd;AAAA,EACF,GAAG,CAAC,QAAQ,QAAQ,MAAM,QAAQ,OAAO,CAAC;AAE1C,SAAO;AACT;;;AE7MA,SAAS,YAAAA,WAAU,aAAAC,kBAAiB;AAmF7B,SAAS,iBAAiB,QAAkD;AACjF,SAAO,OAAO,YAAY;AAC5B;AAKO,SAAS,eAAe,QAAgD;AAC7E,SAAO,OAAO,YAAY,SAAS,OAAO,UAAU;AACtD;AAKO,SAAS,oBAAoB,QAAsD;AACxF,SAAO,OAAO,YAAY,SAAS,OAAO,UAAU,QAAQ,OAAO,SAAS;AAC9E;AAKO,SAAS,qBAAqB,QAAuD;AAC1F,SAAO,OAAO,YAAY,SAAS,OAAO,UAAU,QAAQ,OAAO,SAAS;AAC9E;AAwDO,SAAS,WAAW,QAA4C;AACrE,QAAM,EAAE,QAAQ,QAAQ,MAAM,UAAU,MAAM,IAAI;AAElD,QAAM,CAAC,QAAQ,SAAS,IAAIC,UAA2B;AAAA,IACrD,SAAS;AAAA,IACT,OAAO;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA,IACN,OAAO;AAAA,IACP,OAAO;AAAA,IACP;AAAA,IACA,cAAc;AAAA,EAChB,CAAC;AAED,EAAAC,WAAU,MAAM;AACd,QAAI,YAAY;AAEhB,mBAAe,eAAe;AAC5B,UAAI;AAEF,cAAM,CAAC,MAAM,eAAe,IAAI,MAAM,QAAQ,IAAI;AAAA,UAChD,OAAO,QAAQ,EAAE,IAAI,OAAO,CAAC;AAAA,UAC7B,OAAO,QAAQ,EAAE,QAAQ,MAAM,QAAQ,CAAC;AAAA,QAC1C,CAAC;AAGD,YAAI,UAAW;AAGf,YAAI,gBAAgB,eAAe,GAAG;AACpC,gBAAM,YAAY,gBAAgB;AAElC,gBAAM,QAA0B;AAAA,YAC9B,IAAI,UAAU;AAAA,YACd,MAAM,UAAU;AAAA,YAChB,OAAO,UAAU;AAAA,YACjB,MAAM,UAAU;AAAA,YAChB,MAAM,UAAU;AAAA,YAChB,QAAQ,UAAU;AAAA,YAClB,WAAW,UAAU;AAAA,YACrB,SAAS,UACJ,UAAU,gBAAgB,UAAU,UACrC,UAAU;AAAA,YACd,WAAW,UACN,UAAU,kBAAkB,UAAU,YACvC,UAAU;AAAA,YACd,iBAAiB,UACZ,UAAU,wBAAwB,UAAU,kBAC7C,UAAU;AAAA,YACd,WAAW,UAAU;AAAA,YACrB,WAAW,UAAU;AAAA,UACvB;AAEA,oBAAU;AAAA,YACR,SAAS;AAAA,YACT,OAAO;AAAA,YACP,MAAM;AAAA,YACN,MAAM;AAAA,YACN;AAAA,YACA,OAAO,KAAK;AAAA,YACZ;AAAA,YACA,cAAc;AAAA,UAChB,CAAC;AACD;AAAA,QACF;AAGA,cAAM,EAAE,MAAM,SAAS,IAAI;AAG3B,cAAM,SAAS,SAAS,OAAO,IAAI,CAAC,UAAU;AAC5C,cAAI,CAAC,SAAS,OAAO,UAAU,UAAU;AACvC,kBAAM,IAAI,MAAM,sCAAsC;AAAA,UACxD;AACA,cAAI,OAAO,MAAM,OAAO,YAAY,MAAM,OAAO,MAAM;AACrD,kBAAM,IAAI,MAAM,kDAAkD,OAAO,MAAM,EAAE,EAAE;AAAA,UACrF;AACA,cAAI,OAAO,MAAM,SAAS,UAAU;AAClC,kBAAM,IAAI,MAAM,4CAA4C,OAAO,MAAM,IAAI,EAAE;AAAA,UACjF;AACA,cAAI,OAAO,MAAM,YAAY,UAAU;AACrC,kBAAM,IAAI,MAAM,+CAA+C,OAAO,MAAM,OAAO,EAAE;AAAA,UACvF;AACA,iBAAO;AAAA,YACL,IAAI,MAAM;AAAA,YACV,MAAM,MAAM;AAAA,YACZ,SAAS,MAAM;AAAA,UACjB;AAAA,QACF,CAAC;AAED,cAAM,cAAc;AAAA,UAClB,MAAM,SAAS;AAAA,UACf,MAAM,SAAS;AAAA,UACf,SAAS,SAAS;AAAA,UAClB;AAAA,QACF;AAGA,cAAM,eAAe,MAAM;AAAA,UACzB;AAAA,UACA;AAAA,YACE;AAAA,YACA,QAAQ,SAAS;AAAA,YACjB,cAAc,UAAU,YAAY;AAAA,UACtC;AAAA,UACA;AAAA,QACF;AAGA,YAAI,UAAW;AAEf,kBAAU;AAAA,UACR,SAAS;AAAA,UACT,OAAO;AAAA,UACP,MAAM;AAAA,UACN,MAAM;AAAA,UACN,OAAO;AAAA,UACP,OAAO,KAAK;AAAA,UACZ;AAAA,UACA;AAAA,QACF,CAAC;AAAA,MACH,SAAS,OAAO;AACd,YAAI,UAAW;AAEf,kBAAU;AAAA,UACR,SAAS;AAAA,UACT,OAAO,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC;AAAA,UAC/D,MAAM;AAAA,UACN,MAAM;AAAA,UACN,OAAO;AAAA,UACP,OAAO;AAAA,UACP;AAAA,UACA,cAAc;AAAA,QAChB,CAAC;AAAA,MACH;AAAA,IACF;AAEA,iBAAa;AAEb,WAAO,MAAM;AACX,kBAAY;AAAA,IACd;AAAA,EACF,GAAG,CAAC,QAAQ,QAAQ,MAAM,OAAO,CAAC;AAElC,SAAO;AACT;AAKA,SAAS,gBAAgB,UAA8E;AACrG,SAAO,UAAU,YAAY,SAAS,SAAS;AACjD;;;ACxTA,SAAS,cAAc,yBAAyB;AAgI5C;AAxBG,SAAS,KAAK;AAAA,EACnB;AAAA,EACA;AAAA,EACA,aAAa;AAAA,EACb;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,kBAAkB;AAAA,EAClB;AAAA,EACA;AAAA,EACA;AACF,GAAc;AAEZ,QAAM,aAAa,kBAAkB,kBAAkB,KAAK,EAAE;AAI9D,QAAM,cAAc,WAAW,OAAO,UAClC,EAAE,GAAG,YAAY,SAAS,EAAE,GAAG,WAAW,SAAS,GAAG,UAAU,MAAM,QAAQ,EAAE,IAChF;AAEJ,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,aAAa;AAAA,QACX;AAAA,QACA;AAAA,QACA,QAAQ;AAAA,QACR,mBAAmB,aAAa,qBAAqB;AAAA,QACrD,cAAc,aAAa,gBAAgB;AAAA,MAC7C;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,EACF;AAEJ;;;AC5JA,SAAS,6BAA6B;;;ACG/B,IAAM,cAAN,MAAqB;AAAA,EAK1B,YAAY,UAA8C,CAAC,GAAG;AAJ9D,SAAQ,QAAQ,oBAAI,IAA2C;AAK7D,SAAK,UAAU,QAAQ,WAAW;AAClC,SAAK,MAAM,QAAQ,OAAO;AAAA,EAC5B;AAAA,EAEA,IAAI,KAA4B;AAC9B,UAAM,QAAQ,KAAK,MAAM,IAAI,GAAG;AAChC,QAAI,CAAC,MAAO,QAAO;AAGnB,QAAI,KAAK,IAAI,IAAI,MAAM,SAAS;AAC9B,WAAK,MAAM,OAAO,GAAG;AACrB,aAAO;AAAA,IACT;AAEA,WAAO,MAAM;AAAA,EACf;AAAA,EAEA,IAAI,KAAa,OAAgB;AAE/B,QAAI,KAAK,MAAM,QAAQ,KAAK,SAAS;AACnC,YAAM,WAAW,KAAK,MAAM,KAAK,EAAE,KAAK,EAAE;AAC1C,UAAI,UAAU;AACZ,aAAK,MAAM,OAAO,QAAQ;AAAA,MAC5B;AAAA,IACF;AAEA,SAAK,MAAM,IAAI,KAAK;AAAA,MAClB;AAAA,MACA,SAAS,KAAK,IAAI,IAAI,KAAK;AAAA,IAC7B,CAAC;AAAA,EACH;AAAA,EAEA,QAAc;AACZ,SAAK,MAAM,MAAM;AAAA,EACnB;AAAA,EAEA,IAAI,KAAsB;AACxB,WAAO,KAAK,IAAI,GAAG,MAAM;AAAA,EAC3B;AACF;;;ADzBO,SAAS,sBAAsB,QAAgD;AACpF,MAAI,CAAC,OAAO,SAAS;AACnB,UAAM,IAAI;AAAA,MACR;AAAA,IAEF;AAAA,EACF;AAGA,MAAI,CAAC,OAAO,QAAQ,SAAS,MAAM,GAAG;AACpC,UAAM,IAAI;AAAA,MACR,2CAA2C,OAAO,OAAO;AAAA,IAE3D;AAAA,EACF;AAEA,QAAM,eAAe,OAAO,OAAO,WAAW;AAC9C,QAAM,YAAY,OAAO,OAAO,OAAO,OAAO;AAC9C,QAAM,eAAe,OAAO,OAAO,WAAW;AAG9C,QAAM,YAAY,sBAAsB,OAAO,QAAQ,OAAO,OAAO;AAGrE,QAAM,QAAQ,IAAI,YAAqB;AAAA,IACrC,SAAS;AAAA,IACT,KAAK;AAAA,EACP,CAAC;AAKD,iBAAe,YACb,UACA,SACA,SACY;AAEZ,QAAI,gBAAgB,CAAC,SAAS,OAAO;AACnC,YAAM,SAAS,MAAM,IAAI,QAAQ;AACjC,UAAI,WAAW,QAAW;AACxB,eAAO;AAAA,MACT;AAAA,IACF;AAGA,UAAM,OAAO,MAAM,QAAQ;AAG3B,QAAI,cAAc;AAChB,YAAM,IAAI,UAAU,IAAI;AAAA,IAC1B;AAEA,WAAO;AAAA,EACT;AAEA,SAAO;AAAA,IACL,MAAM,QAAQ,QAAQ;AACpB,YAAM,EAAE,MAAM,QAAQ,GAAG,IAAI;AAE7B,UAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI;AAC3B,cAAM,IAAI;AAAA,UACR,8EACa,KAAK,UAAU,MAAM,CAAC;AAAA,QACrC;AAAA,MACF;AAEA,YAAM,WAAW,QAAQ,QAAQ,UAAU,EAAE;AAE7C,aAAO,YAAY,UAAU,YAAY;AAEvC,cAAM,YAAoC,CAAC;AAC3C,YAAI,OAAO,KAAM,WAAU,OAAO,OAAO;AACzC,YAAI,OAAO,OAAQ,WAAU,SAAS,OAAO;AAC7C,YAAI,OAAO,GAAI,WAAU,KAAK,OAAO;AACrC,eAAO,MAAM,UAAU,EAAE,UAAU,WAAW,QAAQ,UAAU,CAAC;AAAA,MACnE,CAAC;AAAA,IACH;AAAA,IAEA,MAAM,QAAQ,QAAQ;AACpB,YAAM,EAAE,QAAQ,MAAM,UAAU,MAAM,IAAI;AAC1C,YAAM,WAAW,QAAQ,MAAM,IAAI,IAAI,IAAI,OAAO;AAElD,aAAO,YAAY,UAAU,YAAY;AACvC,eAAO,MAAM,UAAU,EAAE,UAAU,oBAAoB,QAAQ,EAAE,OAAO,GAAG,MAAM,EAAE,MAAM,QAAQ,EAAE,CAAC;AAAA,MACtG,CAAC;AAAA,IACH;AAAA,IAEA,MAAM,WAAW,QAAQ;AACvB,YAAM,EAAE,QAAQ,aAAa,OAAO,OAAO,UAAU,OAAO,MAAM,SAAS,IAAI;AAG/E,YAAM,mBAAmB,SAAS,YAAY,UAAU,SAAS,SAAS,KAAK,GAAG,IAAI;AACtF,YAAM,WAAW,WAAW,MAAM,IAAI,WAAW,IAAI,SAAS,EAAE,IAAI,SAAS,EAAE,IAAI,OAAO,IAAI,QAAQ,EAAE,IAAI,gBAAgB;AAE5H,aAAO,YAAY,UAAU,YAAY;AAEvC,cAAM,YAAoC;AAAA,UACxC;AAAA,UACA,MAAM;AAAA,QACR;AAGA,YAAI,OAAO,UAAU,UAAU;AAC7B,oBAAU,QAAQ,OAAO,KAAK;AAAA,QAChC;AAIA,YAAI,UAAU,UAAU;AACtB,oBAAU,QAAQ;AAAA,QACpB,WAAW,UAAU,UAAU;AAC7B,oBAAU,QAAQ;AAAA,QACpB,WAAW,UAAU,SAAS;AAC5B,oBAAU,QAAQ;AAAA,QACpB;AAIA,YAAI,SAAS;AACX,oBAAU,QAAQ;AAAA,QACpB;AAGA,YAAI,SAAS,YAAY,UAAU,QAAQ;AACzC,oBAAU,OAAO;AACjB,oBAAU,WAAW,KAAK,UAAU,QAAQ;AAAA,QAC9C;AAEA,eAAO,MAAM,UAAU,EAAE,UAAU,wBAAwB,QAAQ,UAAU,CAAC;AAAA,MAChF,CAAC;AAAA,IACH;AAAA,IAEA,MAAM,SAAS,QAAQ;AACrB,YAAM,EAAE,QAAQ,aAAa,KAAK,IAAI;AACtC,YAAM,WAAW,SAAS,MAAM,IAAI,WAAW,IAAI,IAAI;AAEvD,aAAO,YAAY,UAAU,YAAY;AACvC,eAAO,MAAM,UAAU,EAAE,UAAU,4BAA4B,QAAQ,EAAE,QAAQ,MAAM,aAAa,KAAK,EAAE,CAAC;AAAA,MAC9G,CAAC;AAAA,IACH;AAAA,IAEA,MAAM,kBAAkB,QAAQ;AAC9B,YAAM,EAAE,OAAO,IAAI;AACnB,UAAI,CAAC,QAAQ;AACX,cAAM,IAAI,MAAM,qCAAqC;AAAA,MACvD;AACA,YAAM,WAAW,eAAe,MAAM;AACtC,aAAO,YAAY,UAAU,YAAY;AACvC,eAAO,MAAM,UAAU,EAAE,UAAU,qBAAqB,QAAQ,EAAE,OAAO,EAAE,CAAC;AAAA,MAC9E,CAAC;AAAA,IACH;AAAA,IAEA,MAAM,yBAAyB,QAAQ;AACrC,YAAM,EAAE,QAAQ,IAAI,IAAI;AACxB,UAAI,CAAC,QAAQ;AACX,cAAM,IAAI,MAAM,4CAA4C;AAAA,MAC9D;AACA,YAAM,WAAW,2BAA2B,MAAM,IAAI,OAAO,EAAE;AAC/D,aAAO,YAAY,UAAU,YAAY;AACvC,cAAM,YAAoC,EAAE,OAAO;AACnD,YAAI,IAAK,WAAU,MAAM;AACzB,eAAO,MAAM,UAAU,EAAE,UAAU,4BAA4B,QAAQ,UAAU,CAAC;AAAA,MACpF,CAAC;AAAA,IACH;AAAA,IAEA,MAAM,iBAAiB,QAAQ;AAC7B,YAAM,EAAE,QAAQ,OAAO,MAAM,IAAI,MAAM,IAAI;AAC3C,UAAI,CAAC,QAAQ;AACX,cAAM,IAAI,MAAM,oCAAoC;AAAA,MACtD;AACA,YAAM,WAAW,iBAAiB,MAAM,IAAI,SAAS,EAAE,IAAI,QAAQ,EAAE,IAAI,MAAM,EAAE,IAAI,SAAS,EAAE;AAChG,aAAO,YAAY,UAAU,YAAY;AACvC,cAAM,YAAoC,EAAE,OAAO;AACnD,YAAI,OAAO,UAAU,SAAU,WAAU,QAAQ,OAAO,KAAK;AAC7D,YAAI,KAAM,WAAU,OAAO;AAC3B,YAAI,GAAI,WAAU,KAAK;AACvB,YAAI,MAAO,WAAU,QAAQ;AAC7B,eAAO,MAAM,UAAU,EAAE,UAAU,oBAAoB,QAAQ,UAAU,CAAC;AAAA,MAC5E,CAAC;AAAA,IACH;AAAA,IAEA,aAAa;AACX,YAAM,MAAM;AAAA,IACd;AAAA,EACF;AACF;","names":["useState","useEffect","useState","useEffect"]}
@@ -0,0 +1,71 @@
1
+ import * as _riverbankcms_api from '@riverbankcms/api';
2
+ import { R as RiverbankClient, S as SiteResponse, P as PageResponse } from './usePage-BvKAa3Zw.mjs';
3
+ export { U as UsePageParams, a as UsePageResult, u as usePage } from './usePage-BvKAa3Zw.mjs';
4
+ import 'react/jsx-runtime';
5
+ import '@riverbankcms/blocks';
6
+ import '@riverbankcms/blocks/system/data';
7
+
8
+ /**
9
+ * Hook to fetch site data (Server Component compatible)
10
+ *
11
+ * @example Server Component
12
+ * ```tsx
13
+ * const site = use(client.getSite({ slug: 'my-site' }));
14
+ * ```
15
+ *
16
+ * @example Client Component
17
+ * ```tsx
18
+ * 'use client';
19
+ * const [site, setSite] = useState(null);
20
+ * useEffect(() => {
21
+ * client.getSite({ slug: 'my-site' }).then(setSite);
22
+ * }, []);
23
+ * ```
24
+ */
25
+ declare function useSite(client: RiverbankClient, params: {
26
+ slug?: string;
27
+ domain?: string;
28
+ id?: string;
29
+ }): SiteResponse;
30
+ /**
31
+ * Simple hook to fetch raw page data (Server Component compatible)
32
+ *
33
+ * For a more complete client-side hook with loading states and prefetched data,
34
+ * use the usePage export from this module instead.
35
+ *
36
+ * @example
37
+ * ```tsx
38
+ * const page = use(client.getPage({ siteId: site.site.id, path: '/' }));
39
+ * ```
40
+ */
41
+ declare function usePageRaw(client: RiverbankClient, params: {
42
+ siteId: string;
43
+ path: string;
44
+ }): PageResponse;
45
+ /**
46
+ * Hook to fetch content entries
47
+ *
48
+ * @example
49
+ * ```tsx
50
+ * const entries = use(client.getEntries({ siteId: site.site.id, contentType: 'blog' }));
51
+ * ```
52
+ */
53
+ declare function useEntries(client: RiverbankClient, params: {
54
+ siteId: string;
55
+ contentType: string;
56
+ }): _riverbankcms_api.ListPublishedEntriesResponse<Record<string, unknown>>;
57
+ /**
58
+ * Hook to fetch a single content entry
59
+ *
60
+ * @example
61
+ * ```tsx
62
+ * const entry = use(client.getEntry({ siteId: site.site.id, contentType: 'blog', slug: 'my-post' }));
63
+ * ```
64
+ */
65
+ declare function useEntry(client: RiverbankClient, params: {
66
+ siteId: string;
67
+ contentType: string;
68
+ slug: string;
69
+ }): _riverbankcms_api.PublishedContentEntryPreviewResponse;
70
+
71
+ export { useEntries, useEntry, usePageRaw, useSite };
@@ -0,0 +1,71 @@
1
+ import * as _riverbankcms_api from '@riverbankcms/api';
2
+ import { R as RiverbankClient, S as SiteResponse, P as PageResponse } from './usePage-BvKAa3Zw.js';
3
+ export { U as UsePageParams, a as UsePageResult, u as usePage } from './usePage-BvKAa3Zw.js';
4
+ import 'react/jsx-runtime';
5
+ import '@riverbankcms/blocks';
6
+ import '@riverbankcms/blocks/system/data';
7
+
8
+ /**
9
+ * Hook to fetch site data (Server Component compatible)
10
+ *
11
+ * @example Server Component
12
+ * ```tsx
13
+ * const site = use(client.getSite({ slug: 'my-site' }));
14
+ * ```
15
+ *
16
+ * @example Client Component
17
+ * ```tsx
18
+ * 'use client';
19
+ * const [site, setSite] = useState(null);
20
+ * useEffect(() => {
21
+ * client.getSite({ slug: 'my-site' }).then(setSite);
22
+ * }, []);
23
+ * ```
24
+ */
25
+ declare function useSite(client: RiverbankClient, params: {
26
+ slug?: string;
27
+ domain?: string;
28
+ id?: string;
29
+ }): SiteResponse;
30
+ /**
31
+ * Simple hook to fetch raw page data (Server Component compatible)
32
+ *
33
+ * For a more complete client-side hook with loading states and prefetched data,
34
+ * use the usePage export from this module instead.
35
+ *
36
+ * @example
37
+ * ```tsx
38
+ * const page = use(client.getPage({ siteId: site.site.id, path: '/' }));
39
+ * ```
40
+ */
41
+ declare function usePageRaw(client: RiverbankClient, params: {
42
+ siteId: string;
43
+ path: string;
44
+ }): PageResponse;
45
+ /**
46
+ * Hook to fetch content entries
47
+ *
48
+ * @example
49
+ * ```tsx
50
+ * const entries = use(client.getEntries({ siteId: site.site.id, contentType: 'blog' }));
51
+ * ```
52
+ */
53
+ declare function useEntries(client: RiverbankClient, params: {
54
+ siteId: string;
55
+ contentType: string;
56
+ }): _riverbankcms_api.ListPublishedEntriesResponse<Record<string, unknown>>;
57
+ /**
58
+ * Hook to fetch a single content entry
59
+ *
60
+ * @example
61
+ * ```tsx
62
+ * const entry = use(client.getEntry({ siteId: site.site.id, contentType: 'blog', slug: 'my-post' }));
63
+ * ```
64
+ */
65
+ declare function useEntry(client: RiverbankClient, params: {
66
+ siteId: string;
67
+ contentType: string;
68
+ slug: string;
69
+ }): _riverbankcms_api.PublishedContentEntryPreviewResponse;
70
+
71
+ export { useEntries, useEntry, usePageRaw, useSite };
@@ -0,0 +1,264 @@
1
+ "use client";
2
+ "use strict";
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+
21
+ // src/hooks/index.ts
22
+ var hooks_exports = {};
23
+ __export(hooks_exports, {
24
+ useEntries: () => useEntries,
25
+ useEntry: () => useEntry,
26
+ usePage: () => usePage,
27
+ usePageRaw: () => usePageRaw,
28
+ useSite: () => useSite
29
+ });
30
+ module.exports = __toCommonJS(hooks_exports);
31
+ var import_react2 = require("react");
32
+
33
+ // src/rendering/hooks/usePage.ts
34
+ var import_react = require("react");
35
+
36
+ // src/data/prefetchBlockData.ts
37
+ var import_data = require("@riverbankcms/blocks/system/data");
38
+ var SUPPORTED_LOADER_ENDPOINTS = [
39
+ "listPublishedEntries",
40
+ "getPublishedEntryPreview",
41
+ "listPublicEvents",
42
+ "getPublicFormById",
43
+ "getPublicBookingServices"
44
+ ];
45
+ async function prefetchBlockData(page, context, client, options) {
46
+ const { customBlocks } = options ?? {};
47
+ const customBlockMap = new Map(
48
+ (customBlocks ?? []).map((block) => [block.id, block])
49
+ );
50
+ return (0, import_data.prefetchBlockData)(page, context, {
51
+ apiClient: async ({ endpoint, params }) => {
52
+ if (!isSupportedEndpoint(endpoint)) {
53
+ throw new Error(
54
+ `Unsupported loader endpoint: ${endpoint}. SDK only supports: ${SUPPORTED_LOADER_ENDPOINTS.join(", ")}`
55
+ );
56
+ }
57
+ switch (endpoint) {
58
+ case "listPublishedEntries": {
59
+ const { siteId, type, orderBy, limit, stage, mode, entryIds } = params ?? {};
60
+ if (!siteId || !type) {
61
+ throw new Error("listPublishedEntries requires siteId and type params");
62
+ }
63
+ const parsedLimit = typeof limit === "string" ? Number.parseInt(limit, 10) : typeof limit === "number" ? limit : void 0;
64
+ const order = orderBy === "newest" || orderBy === "oldest" || orderBy === "title" || orderBy === "order" ? orderBy : void 0;
65
+ let parsedEntryIds;
66
+ if (mode === "manual" && Array.isArray(entryIds)) {
67
+ parsedEntryIds = entryIds.map((item) => {
68
+ if (typeof item === "object" && item !== null && "entryId" in item) {
69
+ return item.entryId;
70
+ }
71
+ if (typeof item === "string") {
72
+ return item;
73
+ }
74
+ return null;
75
+ }).filter((id) => id !== null);
76
+ }
77
+ return await client.getEntries({
78
+ siteId,
79
+ contentType: type,
80
+ limit: parsedLimit,
81
+ order,
82
+ preview: stage === "preview",
83
+ // Manual mode - pass entry IDs for hydration
84
+ mode: mode === "manual" ? "manual" : void 0,
85
+ entryIds: parsedEntryIds
86
+ });
87
+ }
88
+ case "getPublishedEntryPreview": {
89
+ const { siteId, type, slug } = params ?? {};
90
+ if (!siteId || !type || !slug) {
91
+ throw new Error("getPublishedEntryPreview requires siteId, type, and slug params");
92
+ }
93
+ return await client.getEntry({ siteId, contentType: type, slug });
94
+ }
95
+ case "listPublicEvents": {
96
+ const { siteId, limit, from, to, stage } = params ?? {};
97
+ if (!siteId) {
98
+ throw new Error("listPublicEvents requires siteId param");
99
+ }
100
+ const parsedLimit = typeof limit === "string" ? Number.parseInt(limit, 10) : typeof limit === "number" ? limit : void 0;
101
+ return await client.listPublicEvents({ siteId, limit: parsedLimit, from, to, stage });
102
+ }
103
+ case "getPublicFormById": {
104
+ const { formId } = params ?? {};
105
+ if (!formId) {
106
+ throw new Error("getPublicFormById requires formId param");
107
+ }
108
+ return await client.getPublicFormById({ formId });
109
+ }
110
+ case "getPublicBookingServices": {
111
+ const { siteId, ids } = params ?? {};
112
+ if (!siteId) {
113
+ throw new Error("getPublicBookingServices requires siteId param");
114
+ }
115
+ return await client.getPublicBookingServices({ siteId, ids });
116
+ }
117
+ default: {
118
+ const _exhaustive = endpoint;
119
+ throw new Error(`Unhandled endpoint: ${_exhaustive}`);
120
+ }
121
+ }
122
+ },
123
+ isValidEndpoint: isSupportedEndpoint,
124
+ onError: (error, { block, loader }) => {
125
+ console.warn("[prefetchBlockData] failed to prefetch block data", {
126
+ block,
127
+ loader,
128
+ error
129
+ });
130
+ },
131
+ // Provide custom block loader lookup for SDK custom blocks
132
+ getCustomBlockLoaders: (blockKind) => {
133
+ const customBlock = customBlockMap.get(blockKind);
134
+ if (!customBlock?.dataLoaders) return void 0;
135
+ const loaders = {};
136
+ for (const [key, loader] of Object.entries(customBlock.dataLoaders)) {
137
+ loaders[key] = {
138
+ endpoint: loader.endpoint,
139
+ params: loader.params,
140
+ mode: loader.mode
141
+ };
142
+ }
143
+ return loaders;
144
+ }
145
+ });
146
+ }
147
+ function isSupportedEndpoint(endpoint) {
148
+ return SUPPORTED_LOADER_ENDPOINTS.includes(endpoint);
149
+ }
150
+
151
+ // src/rendering/hooks/usePage.ts
152
+ function usePage(params) {
153
+ const { client, siteId, path, pageId, preview = false } = params;
154
+ const [result, setResult] = (0, import_react.useState)({
155
+ loading: true,
156
+ error: null,
157
+ page: null,
158
+ theme: null,
159
+ siteId,
160
+ resolvedData: null,
161
+ sdkConfig: null
162
+ });
163
+ (0, import_react.useEffect)(() => {
164
+ let cancelled = false;
165
+ async function fetchPage() {
166
+ try {
167
+ const [site, pageResponse] = await Promise.all([
168
+ client.getSite({ id: siteId }),
169
+ client.getPage({ siteId, path, preview })
170
+ ]);
171
+ if (cancelled) return;
172
+ if ("entry" in pageResponse) {
173
+ throw new Error(
174
+ "This path resolves to a content entry, not a page. Use useContent() instead, which handles both pages and entries. For entries, useContent() returns the raw entry data for custom rendering."
175
+ );
176
+ }
177
+ const { page: pageData } = pageResponse;
178
+ const blocks = pageData.blocks.map((block) => {
179
+ if (!block || typeof block !== "object") {
180
+ throw new Error("Invalid block format in API response");
181
+ }
182
+ if (typeof block.id !== "string" && block.id !== null) {
183
+ throw new Error(`Invalid block id: expected string or null, got ${typeof block.id}`);
184
+ }
185
+ if (typeof block.kind !== "string") {
186
+ throw new Error(`Invalid block kind: expected string, got ${typeof block.kind}`);
187
+ }
188
+ if (typeof block.purpose !== "string") {
189
+ throw new Error(`Invalid block purpose: expected string, got ${typeof block.purpose}`);
190
+ }
191
+ return {
192
+ id: block.id,
193
+ kind: block.kind,
194
+ purpose: block.purpose
195
+ };
196
+ });
197
+ const pageOutline = {
198
+ name: pageData.name,
199
+ path: pageData.path,
200
+ purpose: pageData.purpose,
201
+ blocks
202
+ };
203
+ const resolvedData = await prefetchBlockData(
204
+ pageOutline,
205
+ {
206
+ siteId,
207
+ pageId: pageId ?? pageData.id,
208
+ previewStage: preview ? "preview" : "published"
209
+ },
210
+ client
211
+ );
212
+ if (cancelled) return;
213
+ setResult({
214
+ loading: false,
215
+ error: null,
216
+ page: pageOutline,
217
+ theme: site.theme,
218
+ siteId,
219
+ resolvedData,
220
+ sdkConfig: site.sdkConfig ?? null
221
+ });
222
+ } catch (error) {
223
+ if (cancelled) return;
224
+ setResult({
225
+ loading: false,
226
+ error: error instanceof Error ? error : new Error(String(error)),
227
+ page: null,
228
+ theme: null,
229
+ siteId,
230
+ resolvedData: null,
231
+ sdkConfig: null
232
+ });
233
+ }
234
+ }
235
+ fetchPage();
236
+ return () => {
237
+ cancelled = true;
238
+ };
239
+ }, [client, siteId, path, pageId, preview]);
240
+ return result;
241
+ }
242
+
243
+ // src/hooks/index.ts
244
+ function useSite(client, params) {
245
+ return (0, import_react2.use)(client.getSite(params));
246
+ }
247
+ function usePageRaw(client, params) {
248
+ return (0, import_react2.use)(client.getPage(params));
249
+ }
250
+ function useEntries(client, params) {
251
+ return (0, import_react2.use)(client.getEntries(params));
252
+ }
253
+ function useEntry(client, params) {
254
+ return (0, import_react2.use)(client.getEntry(params));
255
+ }
256
+ // Annotate the CommonJS export names for ESM import in node:
257
+ 0 && (module.exports = {
258
+ useEntries,
259
+ useEntry,
260
+ usePage,
261
+ usePageRaw,
262
+ useSite
263
+ });
264
+ //# sourceMappingURL=hooks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/hooks/index.ts","../../src/rendering/hooks/usePage.ts","../../src/data/prefetchBlockData.ts"],"sourcesContent":["/**\n * React hooks for Riverbank CMS\n *\n * These hooks provide a convenient way to fetch Builder content\n * in React components (both Server and Client Components).\n */\n\nimport { use } from 'react';\nimport type { RiverbankClient, SiteResponse } from '../client/types';\n\n// Re-export full client-side page hook with loading states and block data prefetching\nexport { usePage } from '../rendering/hooks/usePage';\nexport type { UsePageParams, UsePageResult } from '../rendering/hooks/usePage';\n\n/**\n * Hook to fetch site data (Server Component compatible)\n *\n * @example Server Component\n * ```tsx\n * const site = use(client.getSite({ slug: 'my-site' }));\n * ```\n *\n * @example Client Component\n * ```tsx\n * 'use client';\n * const [site, setSite] = useState(null);\n * useEffect(() => {\n * client.getSite({ slug: 'my-site' }).then(setSite);\n * }, []);\n * ```\n */\nexport function useSite(\n client: RiverbankClient,\n params: { slug?: string; domain?: string; id?: string }\n): SiteResponse {\n // In React Server Components, use() unwraps the promise\n return use(client.getSite(params));\n}\n\n/**\n * Simple hook to fetch raw page data (Server Component compatible)\n *\n * For a more complete client-side hook with loading states and prefetched data,\n * use the usePage export from this module instead.\n *\n * @example\n * ```tsx\n * const page = use(client.getPage({ siteId: site.site.id, path: '/' }));\n * ```\n */\nexport function usePageRaw(client: RiverbankClient, params: { siteId: string; path: string }) {\n return use(client.getPage(params));\n}\n\n/**\n * Hook to fetch content entries\n *\n * @example\n * ```tsx\n * const entries = use(client.getEntries({ siteId: site.site.id, contentType: 'blog' }));\n * ```\n */\nexport function useEntries(client: RiverbankClient, params: { siteId: string; contentType: string }) {\n return use(client.getEntries(params));\n}\n\n/**\n * Hook to fetch a single content entry\n *\n * @example\n * ```tsx\n * const entry = use(client.getEntry({ siteId: site.site.id, contentType: 'blog', slug: 'my-post' }));\n * ```\n */\nexport function useEntry(\n client: RiverbankClient,\n params: { siteId: string; contentType: string; slug: string }\n) {\n return use(client.getEntry(params));\n}\n\n/**\n * Note: These hooks use React's use() API which works in Server Components.\n * For Client Components, you'll want to wrap these with useState/useEffect\n * or use a data fetching library like SWR or React Query.\n *\n * Example with useState:\n * ```tsx\n * 'use client';\n * import { useState, useEffect } from 'react';\n *\n * function MyComponent({ client }) {\n * const [site, setSite] = useState(null);\n * const [loading, setLoading] = useState(true);\n *\n * useEffect(() => {\n * client.getSite({ slug: 'my-site' })\n * .then(setSite)\n * .finally(() => setLoading(false));\n * }, []);\n *\n * if (loading) return <div>Loading...</div>;\n * return <div>{site.site.title}</div>;\n * }\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 * SDK wrapper for block data prefetching.\n * Uses the shared core implementation from @riverbankcms/blocks with the SDK client.\n */\n\nimport type { BlockDataLoader, PageOutline, SdkCustomBlock } from '@riverbankcms/blocks';\nimport { prefetchBlockData as prefetchBlockDataCore } from '@riverbankcms/blocks/system/data';\nimport type { PrefetchContext, ResolvedBlockData } from '@riverbankcms/blocks/system/data';\nimport type { RiverbankClient } from '../client/types';\n\nexport type { PrefetchContext, ResolvedBlockData };\n\n/**\n * Supported loader endpoints for SDK data fetching.\n * Only these endpoints can be used in block data loaders when using the SDK.\n *\n * This is the SINGLE SOURCE OF TRUTH for whitelisted endpoints.\n * - Zod validation schema derives from this array\n * - TypeScript types derive from this array\n * - Runtime validation uses this array\n */\nexport const SUPPORTED_LOADER_ENDPOINTS = [\n 'listPublishedEntries',\n 'getPublishedEntryPreview',\n 'listPublicEvents',\n 'getPublicFormById',\n 'getPublicBookingServices',\n] as const;\n\n/**\n * Union type of all supported loader endpoints.\n * Derived from SUPPORTED_LOADER_ENDPOINTS array.\n */\nexport type SupportedLoaderEndpoint = typeof SUPPORTED_LOADER_ENDPOINTS[number];\n\n/**\n * Options for SDK block data prefetching.\n */\nexport type SdkPrefetchOptions = {\n /**\n * SDK custom blocks from site config.\n * Used to look up data loaders for custom.* blocks.\n */\n customBlocks?: SdkCustomBlock[];\n};\n\n/**\n * Prefetch block data for SDK-based applications.\n * Maps loader endpoints to corresponding SDK client methods.\n *\n * Supports both system blocks and SDK custom blocks with data loaders.\n *\n * @example\n * ```typescript\n * import { createRiverbankClient } from '@riverbankcms/sdk';\n * import { prefetchBlockData } from '@riverbankcms/sdk/data';\n *\n * const client = createRiverbankClient({ apiKey, baseUrl });\n * const page = await client.getPage({ siteId, path: '/' });\n *\n * // Basic usage (system blocks only)\n * const blockData = await prefetchBlockData(page.outline, {\n * siteId: page.siteId,\n * pageId: page.id,\n * }, client);\n *\n * // With custom blocks from SDK config\n * const blockData = await prefetchBlockData(page.outline, context, client, {\n * customBlocks: site.sdkConfig?.customBlocks,\n * });\n * ```\n */\nexport async function prefetchBlockData(\n page: PageOutline,\n context: PrefetchContext,\n client: RiverbankClient,\n options?: SdkPrefetchOptions,\n): Promise<ResolvedBlockData> {\n const { customBlocks } = options ?? {};\n\n // Build lookup map for custom block loaders\n // Key is string (blockKind from page) matching block.id (custom.xxx)\n const customBlockMap = new Map<string, SdkCustomBlock>(\n (customBlocks ?? []).map((block) => [block.id as string, block])\n );\n\n return prefetchBlockDataCore(page, context, {\n apiClient: async ({ endpoint, params }) => {\n // Only support whitelisted loader endpoints\n if (!isSupportedEndpoint(endpoint)) {\n throw new Error(\n `Unsupported loader endpoint: ${endpoint}. ` +\n `SDK only supports: ${SUPPORTED_LOADER_ENDPOINTS.join(', ')}`\n );\n }\n\n // Map endpoint to SDK client method\n switch (endpoint) {\n case 'listPublishedEntries': {\n const { siteId, type, orderBy, limit, stage, mode, entryIds } = params ?? {};\n if (!siteId || !type) {\n throw new Error('listPublishedEntries requires siteId and type params');\n }\n\n // Parse limit if provided (can come as string from bindings)\n const parsedLimit = typeof limit === 'string'\n ? Number.parseInt(limit, 10)\n : typeof limit === 'number'\n ? limit\n : undefined;\n\n // Map orderBy to order param (matching embed block field values)\n const order = (orderBy === 'newest' || orderBy === 'oldest' || orderBy === 'title' || orderBy === 'order')\n ? orderBy as 'newest' | 'oldest' | 'title' | 'order'\n : undefined;\n\n // Extract entry IDs for manual mode\n // entryIds comes from binding to entries field which contains { entryId: \"uuid\" } objects\n let parsedEntryIds: string[] | undefined;\n if (mode === 'manual' && Array.isArray(entryIds)) {\n parsedEntryIds = entryIds\n .map((item: unknown) => {\n if (typeof item === 'object' && item !== null && 'entryId' in item) {\n return (item as { entryId: string }).entryId;\n }\n // Also support direct string IDs\n if (typeof item === 'string') {\n return item;\n }\n return null;\n })\n .filter((id): id is string => id !== null);\n }\n\n return await client.getEntries({\n siteId,\n contentType: type,\n limit: parsedLimit,\n order,\n preview: stage === 'preview',\n // Manual mode - pass entry IDs for hydration\n mode: mode === 'manual' ? 'manual' : undefined,\n entryIds: parsedEntryIds,\n });\n }\n\n case 'getPublishedEntryPreview': {\n const { siteId, type, slug } = params ?? {};\n if (!siteId || !type || !slug) {\n throw new Error('getPublishedEntryPreview requires siteId, type, and slug params');\n }\n return await client.getEntry({ siteId, contentType: type, slug });\n }\n case 'listPublicEvents': {\n const { siteId, limit, from, to, stage } = params ?? {};\n if (!siteId) {\n throw new Error('listPublicEvents requires siteId param');\n }\n const parsedLimit =\n typeof limit === 'string'\n ? Number.parseInt(limit, 10)\n : typeof limit === 'number'\n ? limit\n : undefined;\n return await client.listPublicEvents({ siteId, limit: parsedLimit, from, to, stage });\n }\n case 'getPublicFormById': {\n const { formId } = params ?? {};\n if (!formId) {\n throw new Error('getPublicFormById requires formId param');\n }\n return await client.getPublicFormById({ formId });\n }\n case 'getPublicBookingServices': {\n const { siteId, ids } = params ?? {};\n if (!siteId) {\n throw new Error('getPublicBookingServices requires siteId param');\n }\n return await client.getPublicBookingServices({ siteId, ids });\n }\n\n default: {\n // TypeScript should never reach here due to isSupportedEndpoint check\n const _exhaustive: never = endpoint;\n throw new Error(`Unhandled endpoint: ${_exhaustive}`);\n }\n }\n },\n isValidEndpoint: isSupportedEndpoint,\n onError: (error, { block, loader }) => {\n console.warn('[prefetchBlockData] failed to prefetch block data', {\n block,\n loader,\n error,\n });\n },\n // Provide custom block loader lookup for SDK custom blocks\n getCustomBlockLoaders: (blockKind): Record<string, BlockDataLoader> | undefined => {\n const customBlock = customBlockMap.get(blockKind);\n if (!customBlock?.dataLoaders) return undefined;\n\n // Convert SdkConfigLoader to BlockDataLoader\n // SdkConfigLoader.endpoint is SdkLoaderEndpoint (string union) -> string\n // SdkConfigLoader.params is Record<string, LoaderParamValue> -> Record<string, unknown>\n // Both are structurally compatible via covariance\n const loaders: Record<string, BlockDataLoader> = {};\n for (const [key, loader] of Object.entries(customBlock.dataLoaders)) {\n loaders[key] = {\n endpoint: loader.endpoint,\n params: loader.params,\n mode: loader.mode,\n };\n }\n return loaders;\n },\n });\n}\n\n/**\n * Type guard for supported loader endpoints\n */\nfunction isSupportedEndpoint(endpoint: string): endpoint is SupportedLoaderEndpoint {\n return SUPPORTED_LOADER_ENDPOINTS.includes(endpoint as SupportedLoaderEndpoint);\n}\n"],"mappings":"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","names":["import_react","prefetchBlockDataCore"]}