@riverbankcms/sdk 0.8.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +298 -2
- package/dist/cli/index.js +2409 -595
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/init-docs/content/agents-section.md +11 -0
- package/dist/cli/init-docs/content/cli-reference.md +15 -1
- package/dist/cli/init-docs/content/workflow-add-block.md +7 -0
- package/dist/cli/init-docs/content/workflow-block-extensions.md +361 -0
- package/dist/cli/init-docs/content/workflow-cmsify-page.md +357 -0
- package/dist/cli/init-docs/content/workflow-content-types.md +328 -0
- package/dist/cli/init-docs/content/workflow-create-page.md +9 -0
- package/dist/cli/init-docs/content/workflow-custom-block.md +446 -0
- package/dist/client/client.d.mts +2 -2
- package/dist/client/client.d.ts +2 -2
- package/dist/client/client.js +386 -45
- package/dist/client/client.js.map +1 -1
- package/dist/client/client.mjs +386 -45
- package/dist/client/client.mjs.map +1 -1
- package/dist/client/hooks.d.mts +2 -2
- package/dist/client/hooks.d.ts +2 -2
- package/dist/client/hooks.js +40 -26
- package/dist/client/hooks.js.map +1 -1
- package/dist/client/hooks.mjs +40 -26
- package/dist/client/hooks.mjs.map +1 -1
- package/dist/client/rendering/client.js +210 -128
- package/dist/client/rendering/client.js.map +1 -1
- package/dist/client/rendering/client.mjs +202 -114
- package/dist/client/rendering/client.mjs.map +1 -1
- package/dist/client/usePage--LiGLbVz.d.mts +7195 -0
- package/dist/client/usePage-BwQJlxpe.d.mts +7218 -0
- package/dist/client/usePage-Ds-ow1-d.d.ts +7195 -0
- package/dist/client/usePage-Dsi39Exp.d.ts +6915 -0
- package/dist/client/usePage-Duc2GC-H.d.ts +7218 -0
- package/dist/client/usePage-DyzrgxqR.d.mts +7215 -0
- package/dist/client/usePage-Im82JRRe.d.mts +6915 -0
- package/dist/client/usePage-lTWkuVMZ.d.ts +7215 -0
- package/dist/server/{Layout-l2v4Qa6E.d.ts → Layout-BHGokJmV.d.ts} +1 -1
- package/dist/server/{Layout-D4J009eS.d.mts → Layout-CXkMcTR4.d.mts} +1 -1
- package/dist/server/chunk-274Y2CUE.js +341 -0
- package/dist/server/chunk-274Y2CUE.js.map +1 -0
- package/dist/server/{chunk-RVDS7VSP.js → chunk-2WL52ZOE.js} +8 -8
- package/dist/server/{chunk-RVDS7VSP.js.map → chunk-2WL52ZOE.js.map} +1 -1
- package/dist/server/{chunk-TT5JWA4X.js → chunk-5HGVBSWA.js} +9 -9
- package/dist/server/{chunk-TT5JWA4X.js.map → chunk-5HGVBSWA.js.map} +1 -1
- package/dist/server/{chunk-YXA4GAAQ.mjs → chunk-6VTKALLN.mjs} +2 -6
- package/dist/server/{chunk-YXA4GAAQ.mjs.map → chunk-6VTKALLN.mjs.map} +1 -1
- package/dist/server/chunk-7WJGJY3B.js +7 -0
- package/dist/server/chunk-7WJGJY3B.js.map +1 -0
- package/dist/server/chunk-AGAOKSPY.mjs +22 -0
- package/dist/server/chunk-AGAOKSPY.mjs.map +1 -0
- package/dist/server/{chunk-BYBJA6SP.mjs → chunk-BOYBN4KN.mjs} +37 -23
- package/dist/server/chunk-BOYBN4KN.mjs.map +1 -0
- package/dist/server/{chunk-LNOUXALA.mjs → chunk-CKZDJBMC.mjs} +126 -17
- package/dist/server/chunk-CKZDJBMC.mjs.map +1 -0
- package/dist/server/{chunk-RBJFXNDM.mjs → chunk-E4R5ILRE.mjs} +4 -4
- package/dist/server/{chunk-WM646WI3.js → chunk-EC2AA2IP.js} +275 -297
- package/dist/server/chunk-EC2AA2IP.js.map +1 -0
- package/dist/server/{chunk-2KCF2DNK.js → chunk-F4U4LC5D.js} +8 -8
- package/dist/server/{chunk-2KCF2DNK.js.map → chunk-F4U4LC5D.js.map} +1 -1
- package/dist/server/{chunk-ARNCLSQT.mjs → chunk-H44G72AB.mjs} +2 -2
- package/dist/server/{chunk-7BVRA5MY.js → chunk-JVLQDZTZ.js} +9 -9
- package/dist/server/{chunk-7BVRA5MY.js.map → chunk-JVLQDZTZ.js.map} +1 -1
- package/dist/server/{chunk-OSF34JTQ.mjs → chunk-KKUR3PDT.mjs} +4 -4
- package/dist/server/chunk-NTG7XP3E.js +264 -0
- package/dist/server/chunk-NTG7XP3E.js.map +1 -0
- package/dist/server/{chunk-P4K63SBZ.mjs → chunk-OSTUHBFE.mjs} +3 -3
- package/dist/server/{chunk-EIVISR62.js → chunk-P4O3WSAR.js} +2 -6
- package/dist/server/chunk-P4O3WSAR.js.map +1 -0
- package/dist/server/chunk-PAHSKNY5.mjs +264 -0
- package/dist/server/chunk-PAHSKNY5.mjs.map +1 -0
- package/dist/server/chunk-PSN6HXUD.js +22 -0
- package/dist/server/chunk-PSN6HXUD.js.map +1 -0
- package/dist/server/{chunk-65A5HAUZ.mjs → chunk-QS6ZTLLB.mjs} +243 -265
- package/dist/server/chunk-QS6ZTLLB.mjs.map +1 -0
- package/dist/server/{chunk-P3NNN73G.js → chunk-R6T3Z4W5.js} +3 -3
- package/dist/server/{chunk-P3NNN73G.js.map → chunk-R6T3Z4W5.js.map} +1 -1
- package/dist/server/{chunk-EIJ27EZQ.js → chunk-RIROJYPX.js} +10 -6
- package/dist/server/chunk-RIROJYPX.js.map +1 -0
- package/dist/server/chunk-SVEQVEA5.mjs +341 -0
- package/dist/server/chunk-SVEQVEA5.mjs.map +1 -0
- package/dist/server/{chunk-AEFWG657.mjs → chunk-TBN35TGI.mjs} +6 -6
- package/dist/server/{chunk-AEFWG657.mjs.map → chunk-TBN35TGI.mjs.map} +1 -1
- package/dist/server/{chunk-4YQJUL5W.mjs → chunk-TBX6CXBM.mjs} +8 -4
- package/dist/server/chunk-TBX6CXBM.mjs.map +1 -0
- package/dist/server/{chunk-YYO3RIFO.js → chunk-U2F4BWKW.js} +37 -23
- package/dist/server/chunk-U2F4BWKW.js.map +1 -0
- package/dist/server/{chunk-NFEGQTCC.mjs → chunk-WMJKH4XE.mjs} +8 -1
- package/dist/server/chunk-WWGVFOLS.mjs +7 -0
- package/dist/server/chunk-WWGVFOLS.mjs.map +1 -0
- package/dist/server/{chunk-T26N3P26.js → chunk-X4REO3S7.js} +4 -4
- package/dist/server/{chunk-T26N3P26.js.map → chunk-X4REO3S7.js.map} +1 -1
- package/dist/server/{chunk-C6FIJC7T.mjs → chunk-YUD7ONZG.mjs} +2 -2
- package/dist/server/{chunk-4CV4JOE5.js → chunk-Z6ZWNWWR.js} +9 -2
- package/dist/server/chunk-Z6ZWNWWR.js.map +1 -0
- package/dist/server/{chunk-7UPVCT3K.js → chunk-ZJXFRSTC.js} +270 -161
- package/dist/server/chunk-ZJXFRSTC.js.map +1 -0
- package/dist/server/{components-vtYEmmPF.d.mts → components-Bqn4xmR6.d.mts} +75 -6
- package/dist/server/{components-D2uCKCj7.d.ts → components-C7j9yzAt.d.ts} +75 -6
- package/dist/server/components.d.mts +6 -6
- package/dist/server/components.d.ts +6 -6
- package/dist/server/components.js +9 -7
- package/dist/server/components.js.map +1 -1
- package/dist/server/components.mjs +8 -6
- package/dist/server/config-validation.d.mts +3 -3
- package/dist/server/config-validation.d.ts +3 -3
- package/dist/server/config-validation.js +6 -6
- package/dist/server/config-validation.mjs +5 -5
- package/dist/server/config.d.mts +5 -5
- package/dist/server/config.d.ts +5 -5
- package/dist/server/config.js +6 -6
- package/dist/server/config.mjs +5 -5
- package/dist/server/data.d.mts +3 -3
- package/dist/server/data.d.ts +3 -3
- package/dist/server/data.js +4 -4
- package/dist/server/data.mjs +3 -3
- package/dist/server/env.js +1 -1
- package/dist/server/env.mjs +1 -1
- package/dist/server/{index-BxrAuL9K.d.ts → index-Bns_1a4N.d.ts} +2 -2
- package/dist/server/{index-CH_dvF6n.d.ts → index-CHp2kyp0.d.ts} +2 -2
- package/dist/server/{index-2qnY7VH_.d.mts → index-CPDT8kn9.d.mts} +2 -2
- package/dist/server/{index-DfWg1Qle.d.mts → index-Cm9nMPkf.d.mts} +2 -2
- package/dist/server/index.d.mts +195 -217
- package/dist/server/index.d.ts +195 -217
- package/dist/server/index.js +10 -289
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +11 -290
- package/dist/server/index.mjs.map +1 -1
- package/dist/server/{loadContent-DECnsp4k.d.ts → loadContent-DD7J5_WO.d.ts} +26 -4
- package/dist/server/{loadContent-Du5kS8UM.d.mts → loadContent-DTEgYI-l.d.mts} +26 -4
- package/dist/server/{loadPage-VBorKlWv.d.mts → loadPage-B578Xg2W.d.mts} +3 -3
- package/dist/server/{loadPage-BZohBxxf.d.ts → loadPage-Dkiimbsg.d.ts} +3 -3
- package/dist/server/loadPage-IBX7FXGH.mjs +11 -0
- package/dist/server/loadPage-KG74OG4V.js +11 -0
- package/dist/server/{loadPage-AXNAERDS.js.map → loadPage-KG74OG4V.js.map} +1 -1
- package/dist/server/metadata.d.mts +5 -5
- package/dist/server/metadata.d.ts +5 -5
- package/dist/server/metadata.js +1 -1
- package/dist/server/metadata.mjs +1 -1
- package/dist/server/navigation.d.mts +4 -8
- package/dist/server/navigation.d.ts +4 -8
- package/dist/server/navigation.js +3 -7
- package/dist/server/navigation.js.map +1 -1
- package/dist/server/navigation.mjs +2 -6
- package/dist/server/next/revalidate.js +1 -1
- package/dist/server/next/revalidate.mjs +1 -1
- package/dist/server/next/tags.js +1 -1
- package/dist/server/next/tags.mjs +1 -1
- package/dist/server/next.d.mts +7 -7
- package/dist/server/next.d.ts +7 -7
- package/dist/server/next.js +23 -16
- package/dist/server/next.js.map +1 -1
- package/dist/server/next.mjs +15 -8
- package/dist/server/next.mjs.map +1 -1
- package/dist/server/prebuild-loader.d.mts +87 -0
- package/dist/server/prebuild-loader.d.ts +87 -0
- package/dist/server/prebuild-loader.js +15 -0
- package/dist/server/prebuild-loader.js.map +1 -0
- package/dist/server/prebuild-loader.mjs +15 -0
- package/dist/server/prebuild-loader.mjs.map +1 -0
- package/dist/server/prebuild-types.d.mts +201 -0
- package/dist/server/prebuild-types.d.ts +201 -0
- package/dist/server/prebuild-types.js +1 -0
- package/dist/server/prebuild-types.js.map +1 -0
- package/dist/server/prebuild-types.mjs +1 -0
- package/dist/server/prebuild-types.mjs.map +1 -0
- package/dist/server/prebuild.d.mts +46 -0
- package/dist/server/prebuild.d.ts +46 -0
- package/dist/server/prebuild.js +10 -0
- package/dist/server/prebuild.js.map +1 -0
- package/dist/server/prebuild.mjs +10 -0
- package/dist/server/prebuild.mjs.map +1 -0
- package/dist/server/rendering/server.d.mts +5 -5
- package/dist/server/rendering/server.d.ts +5 -5
- package/dist/server/rendering/server.js +9 -9
- package/dist/server/rendering/server.mjs +8 -8
- package/dist/server/rendering.d.mts +9 -9
- package/dist/server/rendering.d.ts +9 -9
- package/dist/server/rendering.js +13 -11
- package/dist/server/rendering.js.map +1 -1
- package/dist/server/rendering.mjs +12 -10
- package/dist/server/routing.d.mts +5 -5
- package/dist/server/routing.d.ts +5 -5
- package/dist/server/routing.js +2 -2
- package/dist/server/routing.mjs +2 -2
- package/dist/server/{schema-Z6-afHJG.d.mts → schema-DYtW0zEu.d.mts} +40 -0
- package/dist/server/{schema-Z6-afHJG.d.ts → schema-DYtW0zEu.d.ts} +40 -0
- package/dist/server/server.d.mts +6 -6
- package/dist/server/server.d.ts +6 -6
- package/dist/server/server.js +10 -7
- package/dist/server/server.js.map +1 -1
- package/dist/server/server.mjs +9 -6
- package/dist/server/theme-bridge.js +9 -9
- package/dist/server/theme-bridge.mjs +3 -3
- package/dist/server/theme.js +1 -1
- package/dist/server/theme.mjs +1 -1
- package/dist/server/{types-DT30Qy7x.d.mts → types-B6P_iaDz.d.mts} +296 -2
- package/dist/server/{types-CgSO0yxg.d.ts → types-C4jfCjaP.d.ts} +296 -2
- package/dist/server/{types-D0rPF8l5.d.ts → types-CSvCkmYi.d.mts} +13 -4
- package/dist/server/{types-D8XqwoVd.d.ts → types-DVesWaB7.d.ts} +1 -1
- package/dist/server/{types-CJfJwcuL.d.mts → types-M0CviVW2.d.mts} +1 -1
- package/dist/server/{types-BRQ_6yOc.d.mts → types-gKcrQV09.d.ts} +13 -4
- package/dist/server/{validation-Pv3Zs6dP.d.mts → validation-BA1TKthZ.d.mts} +2 -2
- package/dist/server/{validation-D1LaY1kQ.d.ts → validation-js7BCPN8.d.ts} +2 -2
- package/dist/server/webhooks.js +1 -1
- package/dist/server/webhooks.mjs +1 -1
- package/dist/styles/index.css +419 -0
- package/package.json +17 -3
- package/dist/server/chunk-4CV4JOE5.js.map +0 -1
- package/dist/server/chunk-4YQJUL5W.mjs.map +0 -1
- package/dist/server/chunk-65A5HAUZ.mjs.map +0 -1
- package/dist/server/chunk-7UPVCT3K.js.map +0 -1
- package/dist/server/chunk-BYBJA6SP.mjs.map +0 -1
- package/dist/server/chunk-EIJ27EZQ.js.map +0 -1
- package/dist/server/chunk-EIVISR62.js.map +0 -1
- package/dist/server/chunk-LNOUXALA.mjs.map +0 -1
- package/dist/server/chunk-WM646WI3.js.map +0 -1
- package/dist/server/chunk-YYO3RIFO.js.map +0 -1
- package/dist/server/loadPage-AXNAERDS.js +0 -11
- package/dist/server/loadPage-XR7ORQ2E.mjs +0 -11
- package/src/styles/index.css +0 -10
- /package/dist/server/{chunk-RBJFXNDM.mjs.map → chunk-E4R5ILRE.mjs.map} +0 -0
- /package/dist/server/{chunk-ARNCLSQT.mjs.map → chunk-H44G72AB.mjs.map} +0 -0
- /package/dist/server/{chunk-OSF34JTQ.mjs.map → chunk-KKUR3PDT.mjs.map} +0 -0
- /package/dist/server/{chunk-P4K63SBZ.mjs.map → chunk-OSTUHBFE.mjs.map} +0 -0
- /package/dist/server/{chunk-NFEGQTCC.mjs.map → chunk-WMJKH4XE.mjs.map} +0 -0
- /package/dist/server/{chunk-C6FIJC7T.mjs.map → chunk-YUD7ONZG.mjs.map} +0 -0
- /package/dist/server/{loadPage-XR7ORQ2E.mjs.map → loadPage-IBX7FXGH.mjs.map} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../blocks/src/system/runtime/bindings.ts","../../../blocks/src/system/data/utils.ts","../../../blocks/src/system/data/prefetchBlockData.ts","../../src/data/prefetchBlockData.ts"],"sourcesContent":["import { bindingSchema } from \"../node\";\n\nconst shouldLogWarnings = isNonProductionEnv();\n\nexport function resolveParamsBindings(\n input: unknown,\n vm: { content: Record<string, unknown>; $root?: Record<string, unknown> },\n meta?: { blockKind?: string },\n): unknown {\n if (input === null || typeof input !== \"object\") return input;\n if (Array.isArray(input)) return input.map((v) => resolveParamsBindings(v, vm, meta));\n\n // Binding object: { $bind: { from: '...', fallback: ... } }\n const maybeBind = (input as any).$bind;\n if (maybeBind && typeof maybeBind === \"object\") {\n try {\n const binding = bindingSchema.parse(maybeBind);\n const value = resolveBinding(binding.from, vm);\n // Return fallback if value is undefined/null\n if (value === undefined || value === null) {\n return binding.fallback;\n }\n return value;\n } catch (err) {\n if (shouldLogWarnings) {\n console.warn(\n `bindings: failed to parse loader param binding for block \"${meta?.blockKind ?? 'unknown'}\"`,\n err,\n );\n }\n return undefined;\n }\n }\n\n // Recurse object\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(input as Record<string, unknown>)) {\n out[k] = resolveParamsBindings(v, vm, meta);\n }\n return out;\n}\n\nexport function resolveBinding(\n path: string,\n vm: { content: Record<string, unknown>; $root?: Record<string, unknown> },\n): unknown {\n const segments = splitPath(path);\n if (!segments.length) return undefined;\n const [first, ...rest] = segments;\n let source: unknown = vm;\n if (first === \"$root\") {\n source = vm;\n return readFromSource(source as any, [first, ...rest]);\n }\n if (first === \"content\") {\n source = vm.content;\n return readFromSource(source, rest);\n }\n // Fallback: look in content first, then vm\n const contentResult = readFromSource(vm.content, segments);\n if (contentResult !== undefined) {\n return contentResult;\n }\n return readFromSource(vm as any, segments);\n}\n\nexport function splitPath(path: string): Array<string | number> {\n const PATH_SEPARATOR_REGEX = /\\./g;\n const BRACKET_ACCESS_REGEX = /\\[(?<token>[^\\]]+)\\]/g;\n const segments: Array<string | number> = [];\n const parts = path.split(PATH_SEPARATOR_REGEX);\n for (const raw of parts) {\n if (!raw) continue;\n const baseMatch = raw.match(/^([^\\[]+)/);\n if (baseMatch && baseMatch[1]) {\n segments.push(baseMatch[1]);\n }\n const bracketMatches = raw.matchAll(BRACKET_ACCESS_REGEX);\n for (const match of bracketMatches) {\n const token = match.groups?.token ?? \"\";\n if (token.startsWith(\"\\\"\") || token.startsWith(\"'\")) {\n segments.push(token.slice(1, -1));\n } else if (/^\\d+$/.test(token)) {\n segments.push(Number(token));\n } else {\n segments.push(token);\n }\n }\n if (!baseMatch && !raw.includes(\"[\")) {\n segments.push(raw);\n }\n }\n return segments;\n}\n\nexport function readFromSource(source: unknown, segments: Array<string | number>): unknown {\n return segments.reduce<unknown>((current, segment) => {\n if (current === undefined || current === null) return undefined;\n if (typeof segment === \"number\") {\n if (Array.isArray(current)) return current[segment];\n return undefined;\n }\n if (\n typeof current === \"object\" &&\n current !== null &&\n segment in (current as Record<string, unknown>)\n ) {\n return (current as Record<string, unknown>)[segment];\n }\n return undefined;\n }, source);\n}\n\nfunction isNonProductionEnv(): boolean {\n if (typeof globalThis === \"undefined\") {\n return true;\n }\n const maybeProcess = (globalThis as { process?: { env?: { NODE_ENV?: string } } }).process;\n const nodeEnv = maybeProcess?.env?.NODE_ENV;\n return nodeEnv !== \"production\";\n}\n\n","/**\n * Utility functions for block data loading.\n * Pure functions with no side effects.\n */\n\nimport type { BlockDataLoader } from '../registry';\nimport type { DataLoaderEntry } from './types';\n\n/**\n * Normalize data loaders from block definition\n */\nexport function normalizeDataLoaders(\n def: { dataLoaders?: Record<string, BlockDataLoader> } | null\n): DataLoaderEntry[] {\n if (!def?.dataLoaders) {\n return [];\n }\n return Object.entries(def.dataLoaders).map(([key, loader]) => ({ key, loader }));\n}\n\n/**\n * Normalize block content for data loading.\n * Priority: draftContent > content > publishedContent\n */\nexport function normalizeContent(block: {\n content?: unknown;\n draftContent?: unknown;\n publishedContent?: unknown;\n}): Record<string, unknown> {\n const source = block.draftContent ?? block.content ?? block.publishedContent ?? {};\n if (!isRecord(source)) return {};\n\n // Unwrap data wrapper if present and valid\n if ('data' in source) {\n const data = (source as { data?: unknown }).data;\n if (isRecord(data)) {\n return data;\n }\n // If data is null/undefined/non-record, treat as empty\n if (data === null || data === undefined) {\n return {};\n }\n }\n\n return source as Record<string, unknown>;\n}\n\n/**\n * Normalize params for API calls.\n * Converts all values to strings.\n */\nexport function normalizeParams(input: unknown): Record<string, string> {\n if (!input || typeof input !== 'object') return {};\n const entries = Object.entries(input as Record<string, unknown>).map(([key, value]) => [\n key,\n coerceToString(value),\n ]);\n return Object.fromEntries(entries);\n}\n\n/**\n * Coerce value to string for API params\n */\nexport function coerceToString(value: unknown): string {\n if (value === null || value === undefined) return '';\n if (Array.isArray(value)) return value.map(coerceToString).join(',');\n return String(value);\n}\n\n/**\n * Extract data from API response.\n * Unwraps common response wrappers: { data }, { form }, { entries }, { services }\n *\n * Note: We check that properties are NOT functions to avoid returning\n * built-in methods like Array.prototype.entries\n */\nexport function coercePayload(payload: unknown): unknown {\n if (payload && typeof payload === 'object' && !Array.isArray(payload)) {\n const record = payload as Record<string, unknown>;\n if ('data' in record && typeof record.data !== 'function') return record.data;\n if ('form' in record && typeof record.form !== 'function') return record.form;\n if ('entries' in record && typeof record.entries !== 'function') return record.entries;\n if ('services' in record && typeof record.services !== 'function') return record.services;\n }\n return payload;\n}\n\n/**\n * Type guard for record objects\n */\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n","/**\n * Core block data prefetching logic (framework-agnostic).\n *\n * This module provides the shared implementation for prefetching block data loaders.\n * It works with any API client by accepting it as a parameter (dependency injection).\n *\n * Usage:\n * - Frontend: provide internal API client\n * - SDK: provide SDK client with endpoint mapping\n */\n\nimport { getBlockDefinition, type BlockDataLoader } from '../registry';\nimport { resolveParamsBindings } from '../runtime/bindings';\nimport type { PageOutline } from '../../structure/schema';\nimport type { ApiClient, DataLoaderEntry, PrefetchContext, ResolvedBlockData } from './types';\nimport {\n normalizeDataLoaders,\n normalizeContent,\n normalizeParams,\n coercePayload,\n} from './utils';\n\nexport type PrefetchBlockDataOptions = {\n /**\n * API client function that makes the actual requests.\n * This allows the caller to provide their own client (internal or SDK).\n */\n apiClient: ApiClient;\n\n /**\n * Validation function to check if endpoint is valid.\n * Different environments have different endpoint registries.\n */\n isValidEndpoint?: (endpoint: string) => boolean;\n\n /**\n * Error handler for failed data fetches.\n * By default, errors are logged and suppressed (data loading is best-effort).\n */\n onError?: (error: unknown, context: { block: string; loader: string }) => void;\n\n /**\n * Custom block data loader lookup.\n *\n * Called for blocks that aren't found in the system registry.\n * Returns data loaders for SDK custom blocks.\n *\n * @param blockKind - The block's kind (e.g., 'custom.team-member')\n * @returns Record of data loaders, or undefined if not a custom block\n */\n getCustomBlockLoaders?: (blockKind: string) => Record<string, BlockDataLoader> | undefined;\n};\n\n/**\n * Core data prefetching logic (framework-agnostic).\n *\n * This function is shared between frontend and SDK implementations.\n * It handles:\n * - Extracting data loaders from block definitions\n * - Resolving loader params with block content\n * - Executing server-mode loaders in parallel\n * - Organizing results by block ID and loader key\n *\n * @example\n * ```typescript\n * const resolved = await prefetchBlockData(page, context, {\n * apiClient: async ({ endpoint, params }) => {\n * return await myApiClient({ endpoint, params });\n * },\n * isValidEndpoint: (endpoint) => endpoint in API_ENDPOINTS,\n * });\n * ```\n */\nexport async function prefetchBlockData(\n page: PageOutline,\n context: PrefetchContext,\n options: PrefetchBlockDataOptions\n): Promise<ResolvedBlockData> {\n const { apiClient, isValidEndpoint, onError, getCustomBlockLoaders } = options;\n\n const results: ResolvedBlockData = {};\n const tasks: Array<Promise<void>> = [];\n\n for (const block of page.blocks) {\n const blockId = block.id;\n if (!blockId) continue;\n\n // Get loaders from system block definition OR custom block lookup\n let loaders: DataLoaderEntry[];\n const def = getBlockDefinition(block.kind);\n\n if (def) {\n // System block - use normalizeDataLoaders\n loaders = normalizeDataLoaders(def);\n } else if (getCustomBlockLoaders) {\n // Custom block - check callback\n const customLoaders = getCustomBlockLoaders(block.kind);\n loaders = customLoaders\n ? Object.entries(customLoaders).map(([key, loader]) => ({ key, loader }))\n : [];\n } else {\n loaders = [];\n }\n\n if (loaders.length === 0) continue;\n\n const root = {\n siteId: context.siteId,\n pageId: context.pageId,\n previewStage: context.previewStage,\n };\n const normalizedContent = normalizeContent(block as { content?: unknown; draftContent?: unknown; publishedContent?: unknown });\n const vm = { content: normalizedContent, $root: root };\n\n for (const { key, loader } of loaders) {\n // Skip client-mode loaders (they run in browser)\n if (loader.mode === 'client') {\n continue;\n }\n\n // Resolve params using block content\n const rawParams = resolveParamsBindings(loader.params, vm, {\n blockKind: block.kind,\n });\n const params = normalizeParams(rawParams);\n\n const endpoint = loader.endpoint;\n\n // Validate endpoint if validator provided\n if (isValidEndpoint && !isValidEndpoint(endpoint)) {\n continue;\n }\n\n tasks.push(\n (async () => {\n try {\n const payload = await apiClient({ endpoint, params });\n const data = coercePayload(payload);\n\n if (!results[blockId]) {\n results[blockId] = {};\n }\n results[blockId]![key] = data;\n } catch (error) {\n // Call error handler if provided, otherwise fail silently\n // Data loading is best-effort - failures shouldn't break the page\n if (onError) {\n onError(error, { block: block.kind, loader: key });\n }\n }\n })()\n );\n }\n }\n\n if (tasks.length > 0) {\n await Promise.all(tasks);\n }\n\n return results;\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":["prefetchBlockData"]}
|
|
1
|
+
{"version":3,"sources":["../../../blocks/src/system/runtime/bindings.ts","../../../blocks/src/system/data/utils.ts","../../../blocks/src/system/data/prefetchBlockData.ts","../../src/data/prefetchBlockData.ts"],"sourcesContent":["import { bindingSchema } from \"../node\";\n\nconst shouldLogWarnings = isNonProductionEnv();\n\nexport function resolveParamsBindings(\n input: unknown,\n vm: { content: Record<string, unknown>; $root?: Record<string, unknown> },\n meta?: { blockKind?: string },\n): unknown {\n if (input === null || typeof input !== \"object\") return input;\n if (Array.isArray(input)) return input.map((v) => resolveParamsBindings(v, vm, meta));\n\n // Binding object: { $bind: { from: '...', fallback: ... } }\n const maybeBind = (input as any).$bind;\n if (maybeBind && typeof maybeBind === \"object\") {\n try {\n const binding = bindingSchema.parse(maybeBind);\n const value = resolveBinding(binding.from, vm);\n // Return fallback if value is undefined/null\n if (value === undefined || value === null) {\n return binding.fallback;\n }\n return value;\n } catch (err) {\n if (shouldLogWarnings) {\n console.warn(\n `bindings: failed to parse loader param binding for block \"${meta?.blockKind ?? 'unknown'}\"`,\n err,\n );\n }\n return undefined;\n }\n }\n\n // Recurse object\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(input as Record<string, unknown>)) {\n out[k] = resolveParamsBindings(v, vm, meta);\n }\n return out;\n}\n\nexport function resolveBinding(\n path: string,\n vm: { content: Record<string, unknown>; $root?: Record<string, unknown> },\n): unknown {\n const segments = splitPath(path);\n if (!segments.length) return undefined;\n const [first, ...rest] = segments;\n let source: unknown = vm;\n if (first === \"$root\") {\n source = vm;\n return readFromSource(source as any, [first, ...rest]);\n }\n if (first === \"content\") {\n source = vm.content;\n return readFromSource(source, rest);\n }\n // Fallback: look in content first, then vm\n const contentResult = readFromSource(vm.content, segments);\n if (contentResult !== undefined) {\n return contentResult;\n }\n return readFromSource(vm as any, segments);\n}\n\nexport function splitPath(path: string): Array<string | number> {\n const PATH_SEPARATOR_REGEX = /\\./g;\n const BRACKET_ACCESS_REGEX = /\\[(?<token>[^\\]]+)\\]/g;\n const segments: Array<string | number> = [];\n const parts = path.split(PATH_SEPARATOR_REGEX);\n for (const raw of parts) {\n if (!raw) continue;\n const baseMatch = raw.match(/^([^\\[]+)/);\n if (baseMatch && baseMatch[1]) {\n segments.push(baseMatch[1]);\n }\n const bracketMatches = raw.matchAll(BRACKET_ACCESS_REGEX);\n for (const match of bracketMatches) {\n const token = match.groups?.token ?? \"\";\n if (token.startsWith(\"\\\"\") || token.startsWith(\"'\")) {\n segments.push(token.slice(1, -1));\n } else if (/^\\d+$/.test(token)) {\n segments.push(Number(token));\n } else {\n segments.push(token);\n }\n }\n if (!baseMatch && !raw.includes(\"[\")) {\n segments.push(raw);\n }\n }\n return segments;\n}\n\nexport function readFromSource(source: unknown, segments: Array<string | number>): unknown {\n return segments.reduce<unknown>((current, segment) => {\n if (current === undefined || current === null) return undefined;\n if (typeof segment === \"number\") {\n if (Array.isArray(current)) return current[segment];\n return undefined;\n }\n if (\n typeof current === \"object\" &&\n current !== null &&\n segment in (current as Record<string, unknown>)\n ) {\n return (current as Record<string, unknown>)[segment];\n }\n return undefined;\n }, source);\n}\n\nfunction isNonProductionEnv(): boolean {\n if (typeof globalThis === \"undefined\") {\n return true;\n }\n const maybeProcess = (globalThis as { process?: { env?: { NODE_ENV?: string } } }).process;\n const nodeEnv = maybeProcess?.env?.NODE_ENV;\n return nodeEnv !== \"production\";\n}\n\n","/**\n * Utility functions for block data loading.\n * Pure functions with no side effects.\n */\n\nimport type { BlockDataLoader } from '../registry';\nimport type { DataLoaderEntry } from './types';\n\n/**\n * Normalize data loaders from block definition\n */\nexport function normalizeDataLoaders(\n def: { dataLoaders?: Record<string, BlockDataLoader> } | null\n): DataLoaderEntry[] {\n if (!def?.dataLoaders) {\n return [];\n }\n return Object.entries(def.dataLoaders).map(([key, loader]) => ({ key, loader }));\n}\n\n/**\n * Normalize block content for data loading.\n * Priority: draftContent > content > publishedContent\n */\nexport function normalizeContent(block: {\n content?: unknown;\n draftContent?: unknown;\n publishedContent?: unknown;\n}): Record<string, unknown> {\n const source = block.draftContent ?? block.content ?? block.publishedContent ?? {};\n if (!isRecord(source)) return {};\n\n // Unwrap data wrapper if present and valid\n if ('data' in source) {\n const data = (source as { data?: unknown }).data;\n if (isRecord(data)) {\n return data;\n }\n // If data is null/undefined/non-record, treat as empty\n if (data === null || data === undefined) {\n return {};\n }\n }\n\n return source as Record<string, unknown>;\n}\n\n/**\n * Normalize params for API calls.\n * Converts all values to strings.\n */\nexport function normalizeParams(input: unknown): Record<string, string> {\n if (!input || typeof input !== 'object') return {};\n const entries = Object.entries(input as Record<string, unknown>).map(([key, value]) => [\n key,\n coerceToString(value),\n ]);\n return Object.fromEntries(entries);\n}\n\n/**\n * Coerce value to string for API params\n */\nexport function coerceToString(value: unknown): string {\n if (value === null || value === undefined) return '';\n if (Array.isArray(value)) return value.map(coerceToString).join(',');\n return String(value);\n}\n\n/**\n * Extract data from API response.\n * Unwraps common response wrappers: { data }, { form }, { entries }, { services }\n *\n * Note: We check that properties are NOT functions to avoid returning\n * built-in methods like Array.prototype.entries\n */\nexport function coercePayload(payload: unknown): unknown {\n if (payload && typeof payload === 'object' && !Array.isArray(payload)) {\n const record = payload as Record<string, unknown>;\n if ('data' in record && typeof record.data !== 'function') return record.data;\n if ('form' in record && typeof record.form !== 'function') return record.form;\n if ('entries' in record && typeof record.entries !== 'function') return record.entries;\n if ('services' in record && typeof record.services !== 'function') return record.services;\n }\n return payload;\n}\n\n/**\n * Type guard for record objects\n */\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n","/**\n * Core block data prefetching logic (framework-agnostic).\n *\n * This module provides the shared implementation for prefetching block data loaders.\n * It works with any API client by accepting it as a parameter (dependency injection).\n *\n * Usage:\n * - Frontend: provide internal API client\n * - SDK: provide SDK client with endpoint mapping\n */\n\nimport { getBlockDefinition, type BlockDataLoader } from '../registry';\nimport { resolveParamsBindings } from '../runtime/bindings';\nimport type { PageOutline } from '../../structure/schema';\nimport type { ApiClient, DataLoaderEntry, PrefetchContext, ResolvedBlockData } from './types';\nimport {\n normalizeDataLoaders,\n normalizeContent,\n normalizeParams,\n coercePayload,\n} from './utils';\n\nexport type PrefetchBlockDataOptions = {\n /**\n * API client function that makes the actual requests.\n * This allows the caller to provide their own client (internal or SDK).\n */\n apiClient: ApiClient;\n\n /**\n * Validation function to check if endpoint is valid.\n * Different environments have different endpoint registries.\n */\n isValidEndpoint?: (endpoint: string) => boolean;\n\n /**\n * Error handler for failed data fetches.\n * By default, errors are logged and suppressed (data loading is best-effort).\n */\n onError?: (error: unknown, context: { block: string; loader: string }) => void;\n\n /**\n * Custom block data loader lookup.\n *\n * Called for blocks that aren't found in the system registry.\n * Returns data loaders for SDK custom blocks.\n *\n * @param blockKind - The block's kind (e.g., 'custom.team-member')\n * @returns Record of data loaders, or undefined if not a custom block\n */\n getCustomBlockLoaders?: (blockKind: string) => Record<string, BlockDataLoader> | undefined;\n};\n\n/**\n * Core data prefetching logic (framework-agnostic).\n *\n * This function is shared between frontend and SDK implementations.\n * It handles:\n * - Extracting data loaders from block definitions\n * - Resolving loader params with block content\n * - Executing server-mode loaders in parallel\n * - Organizing results by block ID and loader key\n *\n * @example\n * ```typescript\n * const resolved = await prefetchBlockData(page, context, {\n * apiClient: async ({ endpoint, params }) => {\n * return await myApiClient({ endpoint, params });\n * },\n * isValidEndpoint: (endpoint) => endpoint in API_ENDPOINTS,\n * });\n * ```\n */\nexport async function prefetchBlockData(\n page: PageOutline,\n context: PrefetchContext,\n options: PrefetchBlockDataOptions\n): Promise<ResolvedBlockData> {\n const { apiClient, isValidEndpoint, onError, getCustomBlockLoaders } = options;\n\n const results: ResolvedBlockData = {};\n const tasks: Array<Promise<void>> = [];\n\n for (const block of page.blocks) {\n const blockId = block.id;\n if (!blockId) continue;\n\n // Get loaders from system block definition OR custom block lookup\n let loaders: DataLoaderEntry[];\n const def = getBlockDefinition(block.kind);\n\n if (def) {\n // System block - use normalizeDataLoaders\n loaders = normalizeDataLoaders(def);\n } else if (getCustomBlockLoaders) {\n // Custom block - check callback\n const customLoaders = getCustomBlockLoaders(block.kind);\n loaders = customLoaders\n ? Object.entries(customLoaders).map(([key, loader]) => ({ key, loader }))\n : [];\n } else {\n loaders = [];\n }\n\n if (loaders.length === 0) continue;\n\n const root = {\n siteId: context.siteId,\n pageId: context.pageId,\n previewStage: context.previewStage,\n };\n const normalizedContent = normalizeContent(block as { content?: unknown; draftContent?: unknown; publishedContent?: unknown });\n const vm = { content: normalizedContent, $root: root };\n\n for (const { key, loader } of loaders) {\n // Skip client-mode loaders (they run in browser)\n if (loader.mode === 'client') {\n continue;\n }\n\n // Resolve params using block content\n const rawParams = resolveParamsBindings(loader.params, vm, {\n blockKind: block.kind,\n });\n const params = normalizeParams(rawParams);\n\n const endpoint = loader.endpoint;\n\n // Validate endpoint if validator provided\n if (isValidEndpoint && !isValidEndpoint(endpoint)) {\n continue;\n }\n\n tasks.push(\n (async () => {\n try {\n const payload = await apiClient({ endpoint, params });\n const data = coercePayload(payload);\n\n if (!results[blockId]) {\n results[blockId] = {};\n }\n results[blockId]![key] = data;\n } catch (error) {\n // Call error handler if provided, otherwise fail silently\n // Data loading is best-effort - failures shouldn't break the page\n if (onError) {\n onError(error, { block: block.kind, loader: key });\n }\n }\n })()\n );\n }\n }\n\n if (tasks.length > 0) {\n await Promise.all(tasks);\n }\n\n return results;\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 { formSlug } = params ?? {};\n if (!formSlug) {\n throw new Error('getPublicFormById requires formSlug param');\n }\n // Pass siteId from context for slug-based lookups\n return await client.getPublicFormById({ formId: formSlug, siteId: context.siteId });\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":["prefetchBlockData"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
prefetchBlockData
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-TBN35TGI.mjs";
|
|
4
4
|
|
|
5
5
|
// src/rendering/helpers/loadContent.ts
|
|
6
6
|
function isPageContent(result) {
|
|
@@ -46,7 +46,9 @@ async function loadContent(params) {
|
|
|
46
46
|
dataContext: { contentEntry: entry.content },
|
|
47
47
|
theme: site.theme,
|
|
48
48
|
siteId,
|
|
49
|
-
site: site.site
|
|
49
|
+
site: site.site,
|
|
50
|
+
sdkConfig: site.sdkConfig ?? null,
|
|
51
|
+
supabaseUrl: site.supabaseUrl
|
|
50
52
|
};
|
|
51
53
|
}
|
|
52
54
|
const { page: pageData } = contentResponse;
|
|
@@ -72,7 +74,9 @@ async function loadContent(params) {
|
|
|
72
74
|
theme: site.theme,
|
|
73
75
|
siteId,
|
|
74
76
|
resolvedData,
|
|
75
|
-
site: site.site
|
|
77
|
+
site: site.site,
|
|
78
|
+
sdkConfig: site.sdkConfig ?? null,
|
|
79
|
+
supabaseUrl: site.supabaseUrl
|
|
76
80
|
};
|
|
77
81
|
}
|
|
78
82
|
function isEntryResponse(response) {
|
|
@@ -141,4 +145,4 @@ export {
|
|
|
141
145
|
isEntryContent,
|
|
142
146
|
loadContent
|
|
143
147
|
};
|
|
144
|
-
//# sourceMappingURL=chunk-
|
|
148
|
+
//# sourceMappingURL=chunk-TBX6CXBM.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/rendering/helpers/loadContent.ts"],"sourcesContent":["/**\n * Server-side helper to fetch content (page or entry) by path.\n *\n * Use this for dynamic routing where a path could resolve to either\n * a page or a content entry.\n */\n\nimport type { Theme } from '@riverbankcms/blocks';\nimport type { RiverbankClient, PageResponse, SiteResponse } from '../../client/types';\nimport type { PageProps } from '../components/Page';\nimport { prefetchBlockData } from '../../data/prefetchBlockData';\nimport type { ResolvedBlockData } from '../../data/prefetchBlockData';\nimport type { RuntimeSdkConfig } from './loadPage';\n\n/**\n * Site data included in content results for metadata generation.\n */\nexport type SiteData = SiteResponse['site'];\n\nexport type LoadContentParams = {\n client: RiverbankClient;\n siteId: string;\n path: string;\n /**\n * If true, fetches draft/unpublished content instead of published content.\n * This affects both pages and entries.\n * Requires API key with site access.\n *\n * @default false\n */\n preview?: boolean;\n};\n\n/**\n * Content entry data returned when a path resolves to an entry\n */\nexport type ContentEntryData = {\n id: string;\n /** Content type key (e.g., 'blog-post', 'product') */\n type: string | null;\n title: string;\n slug: string | null;\n path: string | null;\n status: string;\n publishAt: string | null;\n /** The raw content fields - use these to render your own UI */\n content: Record<string, unknown>;\n metaTitle: string | null;\n metaDescription: string | null;\n createdAt: string;\n updatedAt: string;\n};\n\n/**\n * Result when path resolves to a page\n */\nexport type PageContentResult = {\n type: 'page';\n /** Page outline ready for rendering with <Page> component */\n page: PageProps['page'];\n /** Site theme for styling */\n theme: Theme;\n /** Site ID */\n siteId: string;\n /** Pre-fetched block data for data loaders */\n resolvedData: ResolvedBlockData;\n /** Site data for metadata generation */\n site: SiteData;\n /**\n * SDK site configuration containing theme palette overrides.\n * When provided, the SDK palette tokens are merged into the theme tokens,\n * allowing blocks to use SDK-defined color tokens for section backgrounds.\n */\n sdkConfig: RuntimeSdkConfig | null;\n /**\n * Supabase storage URL for direct image access.\n * SDK sites receive this from the API instead of requiring NEXT_PUBLIC_SUPABASE_URL env var.\n */\n supabaseUrl?: string;\n};\n\n/**\n * Result when path resolves to a content entry\n */\nexport type EntryContentResult = {\n type: 'entry';\n /** Raw entry data - render this however you want */\n entry: ContentEntryData;\n /** Template page for rendering the entry (if available) */\n templatePage: PageProps['page'] | null;\n /** Pre-fetched block data for template page data loaders */\n resolvedData: ResolvedBlockData;\n /** Data context for template blocks (includes entry content for bindings) */\n dataContext: { contentEntry: Record<string, unknown> };\n /** Site theme for styling (useful if rendering with SDK components) */\n theme: Theme;\n /** Site ID */\n siteId: string;\n /** Site data for metadata generation */\n site: SiteData;\n /**\n * SDK site configuration containing theme palette overrides.\n * When provided, the SDK palette tokens are merged into the theme tokens,\n * allowing blocks to use SDK-defined color tokens for section backgrounds.\n */\n sdkConfig: RuntimeSdkConfig | null;\n /**\n * Supabase storage URL for direct image access.\n * SDK sites receive this from the API instead of requiring NEXT_PUBLIC_SUPABASE_URL env var.\n */\n supabaseUrl?: string;\n};\n\n/**\n * Discriminated union result from loadContent\n */\nexport type LoadContentResult = PageContentResult | EntryContentResult;\n\n/**\n * Type guard to check if result is a page\n */\nexport function isPageContent(result: LoadContentResult): result is PageContentResult {\n return result.type === 'page';\n}\n\n/**\n * Type guard to check if result is an entry\n */\nexport function isEntryContent(result: LoadContentResult): result is EntryContentResult {\n return result.type === 'entry';\n}\n\n/**\n * Server-side helper to fetch content by path.\n *\n * Returns a discriminated union - either page data (ready for `<Page>` component)\n * or raw entry data (for custom rendering).\n *\n * @example Dynamic routing with both pages and entries\n * ```tsx\n * import { loadContent, Page, isPageContent } from '@riverbankcms/sdk';\n *\n * export default async function DynamicRoute({ params }) {\n * const content = await loadContent({\n * client,\n * siteId: 'site-123',\n * path: `/${params.slug?.join('/') || ''}`,\n * });\n *\n * if (isPageContent(content)) {\n * return <Page {...content} />;\n * }\n *\n * // Render entry with custom UI\n * return (\n * <article>\n * <h1>{content.entry.title}</h1>\n * <div>{content.entry.content.body}</div>\n * </article>\n * );\n * }\n * ```\n *\n * @example Entry-specific rendering based on content type\n * ```tsx\n * const content = await loadContent({ client, siteId, path });\n *\n * if (content.type === 'entry') {\n * switch (content.entry.type) {\n * case 'blog-post':\n * return <BlogPost entry={content.entry} theme={content.theme} />;\n * case 'product':\n * return <ProductPage entry={content.entry} theme={content.theme} />;\n * default:\n * return <GenericEntry entry={content.entry} />;\n * }\n * }\n *\n * return <Page {...content} />;\n * ```\n *\n * @example Preview mode for draft content\n * ```tsx\n * const content = await loadContent({\n * client,\n * siteId,\n * path,\n * preview: true, // Fetches draft content for both pages and entries\n * });\n * ```\n */\nexport async function loadContent(params: LoadContentParams): Promise<LoadContentResult> {\n const { client, siteId, path, preview = false } = params;\n\n // Fetch site and content in parallel\n const [site, contentResponse] = await Promise.all([\n client.getSite({ id: siteId }),\n client.getPage({ siteId, path, preview }),\n ]);\n\n // Check if response is an entry\n if (isEntryResponse(contentResponse)) {\n const entryData = contentResponse.entry;\n\n const entry: ContentEntryData = {\n id: entryData.id,\n type: entryData.type,\n title: entryData.title,\n slug: entryData.slug,\n path: entryData.path,\n status: entryData.status,\n publishAt: entryData.publishAt,\n // Use draft content in preview mode, otherwise use published content\n content: preview\n ? (entryData.draftContent ?? entryData.content)\n : entryData.content,\n metaTitle: preview\n ? (entryData.draftMetaTitle ?? entryData.metaTitle)\n : entryData.metaTitle,\n metaDescription: preview\n ? (entryData.draftMetaDescription ?? entryData.metaDescription)\n : entryData.metaDescription,\n createdAt: entryData.createdAt,\n updatedAt: entryData.updatedAt,\n };\n\n // Process template if available (uses first template from content type)\n const { templatePage, resolvedData } = await processEntryTemplate(\n contentResponse.templates as Template[] | undefined,\n entry,\n { siteId, preview },\n client\n );\n\n return {\n type: 'entry',\n entry,\n templatePage,\n resolvedData,\n dataContext: { contentEntry: entry.content },\n theme: site.theme,\n siteId,\n site: site.site,\n sdkConfig: site.sdkConfig ?? null,\n supabaseUrl: site.supabaseUrl,\n };\n }\n\n // Handle page response\n const { page: pageData } = contentResponse;\n\n // Convert API response blocks to PageOutline format with validation\n const blocks = pageData.blocks.map((block) => validateAndConvertBlock(block, 'page'));\n\n const pageOutline = {\n name: pageData.name,\n path: pageData.path,\n purpose: pageData.purpose,\n blocks,\n };\n\n // Prefetch block data loaders for pages\n const resolvedData = await prefetchBlockData(\n pageOutline,\n {\n siteId,\n pageId: pageData.id,\n previewStage: preview ? 'preview' : 'published',\n },\n client\n );\n\n return {\n type: 'page',\n page: pageOutline,\n theme: site.theme,\n siteId,\n resolvedData,\n site: site.site,\n sdkConfig: site.sdkConfig ?? null,\n supabaseUrl: site.supabaseUrl,\n };\n}\n\n/**\n * Type guard to check if API response is an entry\n */\nfunction isEntryResponse(response: PageResponse): response is Extract<PageResponse, { type: 'entry' }> {\n return 'type' in response && response.type === 'entry';\n}\n\n/**\n * Validates and converts a raw block from API response to PageOutline block format.\n * Used for both page blocks and template blocks to ensure consistent validation.\n */\nfunction validateAndConvertBlock(\n block: unknown,\n source: 'page' | 'template'\n): { id: string | null; kind: string; purpose: string; content?: Record<string, unknown> } {\n if (!block || typeof block !== 'object') {\n throw new Error(`Invalid block format in ${source} API response`);\n }\n\n const blockRecord = block as Record<string, unknown>;\n\n // Template blocks use 'blockKind', page blocks use 'kind'\n const kindField = source === 'template' ? 'blockKind' : 'kind';\n const kindValue = blockRecord[kindField];\n\n if (typeof blockRecord.id !== 'string' && blockRecord.id !== null) {\n throw new Error(`Invalid block id in ${source}: expected string or null, got ${typeof blockRecord.id}`);\n }\n if (typeof kindValue !== 'string') {\n throw new Error(`Invalid block ${kindField} in ${source}: expected string, got ${typeof kindValue}`);\n }\n\n // Template blocks derive purpose from scope, page blocks have explicit purpose\n if (source === 'page') {\n if (typeof blockRecord.purpose !== 'string') {\n throw new Error(`Invalid block purpose in ${source}: expected string, got ${typeof blockRecord.purpose}`);\n }\n // Include content for page blocks - required for data loader binding resolution\n const content = (blockRecord.content as Record<string, unknown> | null) ?? {};\n return {\n id: blockRecord.id as string | null,\n kind: kindValue,\n purpose: blockRecord.purpose,\n content,\n };\n }\n\n // Template block: derive purpose from scope, include content\n const scope = blockRecord.scope as 'entry' | 'template' | undefined;\n const content = (blockRecord.content as Record<string, unknown> | null) ?? {};\n\n return {\n id: blockRecord.id as string | null,\n kind: kindValue,\n purpose: scope === 'entry' ? 'entry-content' : 'template-layout',\n content,\n };\n}\n\n/** Template block structure from API response */\ntype TemplateBlock = {\n id: string;\n blockKind: string;\n scope: 'entry' | 'template';\n content: Record<string, unknown> | null;\n};\n\n/** Template structure from API response */\ntype Template = {\n id: string;\n name: string;\n templateKey: string;\n blocks: TemplateBlock[];\n};\n\n/**\n * Processes an entry's template into a PageOutline format and prefetches block data.\n * Returns null templatePage if no valid template with blocks is available.\n */\nasync function processEntryTemplate(\n templates: Template[] | undefined,\n entry: ContentEntryData,\n context: { siteId: string; preview: boolean },\n client: RiverbankClient\n): Promise<{ templatePage: PageProps['page'] | null; resolvedData: ResolvedBlockData }> {\n const template = templates?.[0];\n\n // Templates without blocks are treated as \"no template\" - the entry should be\n // rendered with custom UI rather than an empty template page\n if (!template || !template.blocks?.length) {\n return { templatePage: null, resolvedData: {} };\n }\n\n // Convert template blocks to PageOutline format with validation\n const blocks = template.blocks.map((block) => validateAndConvertBlock(block, 'template'));\n\n const templatePage: PageProps['page'] = {\n name: template.name || 'Entry Template',\n path: entry.path || '/',\n purpose: 'entry-template',\n blocks,\n };\n\n // Prefetch block data for template\n const resolvedData = await prefetchBlockData(\n templatePage,\n {\n siteId: context.siteId,\n pageId: template.id,\n previewStage: context.preview ? 'preview' : 'published',\n },\n client\n );\n\n return { templatePage, resolvedData };\n}\n"],"mappings":"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","names":["resolvedData","content"]}
|
|
@@ -108,7 +108,11 @@ var uiSchema = _zod.z.object({
|
|
|
108
108
|
layout: _zod.z.enum(["stack", "grid"]).optional(),
|
|
109
109
|
columns: _zod.z.number().int().min(2).max(4).optional(),
|
|
110
110
|
// Entry picker configuration
|
|
111
|
-
contentTypeField: _zod.z.string().optional()
|
|
111
|
+
contentTypeField: _zod.z.string().optional(),
|
|
112
|
+
// Extras pattern: fields marked as extras are hidden behind a modal toggle
|
|
113
|
+
extras: _zod.z.boolean().optional(),
|
|
114
|
+
// Render in block header instead of form body (used for section styles)
|
|
115
|
+
renderInHeader: _zod.z.boolean().optional()
|
|
112
116
|
}).partial();
|
|
113
117
|
var baseFieldSchema = _zod.z.object({
|
|
114
118
|
id: _zod.z.string().min(1, "Field id is required"),
|
|
@@ -1366,25 +1370,30 @@ function createButtonGroup(options = {}) {
|
|
|
1366
1370
|
ui: { colSpan: 2 }
|
|
1367
1371
|
}
|
|
1368
1372
|
];
|
|
1369
|
-
const
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1373
|
+
const iconFields = [
|
|
1374
|
+
{
|
|
1375
|
+
id: "iconLeft",
|
|
1376
|
+
type: "media",
|
|
1377
|
+
label: "Left icon",
|
|
1378
|
+
required: false,
|
|
1379
|
+
mediaKinds: ["image"],
|
|
1380
|
+
ui: { extras: true }
|
|
1381
|
+
},
|
|
1382
|
+
{
|
|
1383
|
+
id: "iconRight",
|
|
1384
|
+
type: "media",
|
|
1385
|
+
label: "Right icon",
|
|
1386
|
+
required: false,
|
|
1387
|
+
mediaKinds: ["image"],
|
|
1388
|
+
ui: { extras: true }
|
|
1380
1389
|
}
|
|
1381
|
-
|
|
1390
|
+
];
|
|
1382
1391
|
return {
|
|
1383
1392
|
id: groupId,
|
|
1384
1393
|
type: "group",
|
|
1385
1394
|
label: groupLabel,
|
|
1386
1395
|
ui: { layout: "grid", columns: 2, flattenInRepeater, hideLabel: !showGroupLabel },
|
|
1387
|
-
schema: { fields: [...mainFields,
|
|
1396
|
+
schema: { fields: [...mainFields, ...iconFields] },
|
|
1388
1397
|
required: false
|
|
1389
1398
|
};
|
|
1390
1399
|
}
|
|
@@ -1665,7 +1674,7 @@ var formEmbedFragment = defineFragment({
|
|
|
1665
1674
|
description: "Embeds a saved form with configurable submit button copy.",
|
|
1666
1675
|
fields: [
|
|
1667
1676
|
{
|
|
1668
|
-
id: "
|
|
1677
|
+
id: "formSlug",
|
|
1669
1678
|
type: "reference",
|
|
1670
1679
|
label: "Form",
|
|
1671
1680
|
description: "Pick a saved form to render.",
|
|
@@ -1701,7 +1710,7 @@ var formEmbedFragment = defineFragment({
|
|
|
1701
1710
|
loader: {
|
|
1702
1711
|
endpoint: "getPublicFormById",
|
|
1703
1712
|
params: {
|
|
1704
|
-
|
|
1713
|
+
formSlug: { $bind: { from: "formSlug" } }
|
|
1705
1714
|
},
|
|
1706
1715
|
mode: "server"
|
|
1707
1716
|
}
|
|
@@ -2705,6 +2714,10 @@ function getAnchorClasses(position) {
|
|
|
2705
2714
|
}
|
|
2706
2715
|
|
|
2707
2716
|
// ../blocks/src/system/fields/background.ts
|
|
2717
|
+
var BACKGROUND_WIDGETS = {
|
|
2718
|
+
COLOR: "backgroundColor",
|
|
2719
|
+
GRADIENT: "backgroundGradient"
|
|
2720
|
+
};
|
|
2708
2721
|
function createBackgroundField(options = {}) {
|
|
2709
2722
|
const {
|
|
2710
2723
|
id = "background",
|
|
@@ -2730,8 +2743,7 @@ function createBackgroundField(options = {}) {
|
|
|
2730
2743
|
required: false,
|
|
2731
2744
|
multiline: false,
|
|
2732
2745
|
ui: {
|
|
2733
|
-
|
|
2734
|
-
widget: "backgroundColor"
|
|
2746
|
+
widget: BACKGROUND_WIDGETS.COLOR
|
|
2735
2747
|
}
|
|
2736
2748
|
}
|
|
2737
2749
|
]
|
|
@@ -2748,11 +2760,11 @@ function createBackgroundField(options = {}) {
|
|
|
2748
2760
|
id: "gradient",
|
|
2749
2761
|
type: "text",
|
|
2750
2762
|
label: "Gradient",
|
|
2751
|
-
description: "
|
|
2763
|
+
description: "Select a gradient from theme presets.",
|
|
2752
2764
|
required: false,
|
|
2753
|
-
multiline:
|
|
2765
|
+
multiline: false,
|
|
2754
2766
|
ui: {
|
|
2755
|
-
|
|
2767
|
+
widget: BACKGROUND_WIDGETS.GRADIENT
|
|
2756
2768
|
}
|
|
2757
2769
|
}
|
|
2758
2770
|
]
|
|
@@ -2811,7 +2823,7 @@ function createBackgroundField(options = {}) {
|
|
|
2811
2823
|
id: "position",
|
|
2812
2824
|
type: "presetOrCustom",
|
|
2813
2825
|
label: "Position",
|
|
2814
|
-
description: 'Anchor point for
|
|
2826
|
+
description: 'Anchor point for scaled images. For "Fill" mode, the image focus point (if set) takes precedence.',
|
|
2815
2827
|
required: false,
|
|
2816
2828
|
presets: [...BACKGROUND_POSITION_PRESETS],
|
|
2817
2829
|
customInput: {
|
|
@@ -2902,6 +2914,8 @@ function sectionStylesField(options = {}) {
|
|
|
2902
2914
|
required: false,
|
|
2903
2915
|
schema: { fields: fields4 },
|
|
2904
2916
|
ui: {
|
|
2917
|
+
// Render in block header instead of form body
|
|
2918
|
+
renderInHeader: true,
|
|
2905
2919
|
modalConfig: {
|
|
2906
2920
|
buttonLabel: label,
|
|
2907
2921
|
description: "Configure background and spacing for this section.",
|
|
@@ -5473,4 +5487,4 @@ function getBlockDefinition(name) {
|
|
|
5473
5487
|
|
|
5474
5488
|
|
|
5475
5489
|
exports.bindingSchema = bindingSchema; exports.fieldSchema = fieldSchema; exports.blockCategoryEnum = blockCategoryEnum; exports.backgroundColorStyle = backgroundColorStyle; exports.textColorStyle = textColorStyle; exports.borderColorStyle = borderColorStyle; exports.mergeStyles = mergeStyles; exports.headingGroup = headingGroup; exports.isSemanticSpacing = isSemanticSpacing; exports.resolveSpacing = resolveSpacing; exports.ctaButton = ctaButton; exports.defineFragment = defineFragment; exports.bodyCopyFragment = bodyCopyFragment; exports.heroCopyFragment = heroCopyFragment; exports.createButtonGroup = createButtonGroup; exports.ctaRowFragment = ctaRowFragment; exports.ctaCopyFragment = ctaCopyFragment; exports.testimonialsHeadingFragment = testimonialsHeadingFragment; exports.testimonialsCarouselFragment = testimonialsCarouselFragment; exports.formCopyFragment = formCopyFragment; exports.formEmbedFragment = formEmbedFragment; exports.footerBottomTextFragment = footerBottomTextFragment; exports.footerLinkGroupsFragment = footerLinkGroupsFragment; exports.blogFeaturedPostFragment = blogFeaturedPostFragment; exports.blogListGridFragment = blogListGridFragment; exports.blogListStackFragment = blogListStackFragment; exports.faqHeadingFragment = faqHeadingFragment; exports.faqAccordionFragment = faqAccordionFragment; exports.cardFragment = cardFragment; exports.headingFragment = headingFragment; exports.richTextFragment = richTextFragment; exports.BACKGROUND_POSITION_PRESET_VALUES = BACKGROUND_POSITION_PRESET_VALUES; exports.getAnchorClasses = getAnchorClasses; exports.formattingTransforms = formattingTransforms; exports.uiTransforms = uiTransforms; exports.hexToRgb = hexToRgb; exports.oklchToHexGamut = oklchToHexGamut; exports.featuresFromHex = featuresFromHex; exports.layoutTransforms = layoutTransforms; exports.mediaTransforms = mediaTransforms; exports.siteHeaderManifest = siteHeaderManifest; exports.siteFooterManifest = siteFooterManifest; exports.getBlockDefinition = getBlockDefinition;
|
|
5476
|
-
//# sourceMappingURL=chunk-
|
|
5490
|
+
//# sourceMappingURL=chunk-U2F4BWKW.js.map
|