@riverbankcms/sdk 0.147.0 → 0.148.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 (381) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/{PreviewEditorSidebar-DtpB3_sS.mjs → PreviewEditorSidebar-DvEPG3Z2.mjs} +202 -143
  3. package/dist/{PreviewEditorUI-DxTLgaHo.mjs → PreviewEditorUI-D6eb6fkx.mjs} +68 -60
  4. package/dist/{PreviewQueryProvider-Dd4dxOiU.mjs → PreviewQueryProvider-5znTyJuz.mjs} +1 -1
  5. package/dist/{SdkPreviewModeRuntime-DMMNCngt.mjs → SdkPreviewModeRuntime-DJ6utQ_R.mjs} +1191 -513
  6. package/dist/{SiteChromeCustomizeContext-DQXZXiqS.mjs → SiteChromeCustomizeContext-CFJYh6vo.mjs} +201798 -197304
  7. package/dist/_dts/ai/src/contracts/proposals.d.ts +0 -33
  8. package/dist/_dts/ai/src/contracts/siteStyleProposalSchemas.d.ts +0 -3
  9. package/dist/_dts/api/src/accessAdmin.d.ts +0 -4
  10. package/dist/_dts/api/src/accountApi.d.ts +1 -1
  11. package/dist/_dts/api/src/admin.d.ts +22 -22
  12. package/dist/_dts/api/src/aiPatch.d.ts +2 -2
  13. package/dist/_dts/api/src/aiPlayground.d.ts +1 -0
  14. package/dist/_dts/api/src/analytics.d.ts +2 -2
  15. package/dist/_dts/api/src/apiEndpointTypes.d.ts +2 -0
  16. package/dist/_dts/api/src/appointmentSetup.d.ts +2 -2
  17. package/dist/_dts/api/src/auth.d.ts +10 -10
  18. package/dist/_dts/api/src/availability.d.ts +6 -6
  19. package/dist/_dts/api/src/billing.d.ts +42 -15
  20. package/dist/_dts/api/src/billingEndpointDefinitions.d.ts +8 -0
  21. package/dist/_dts/api/src/billingEndpointTypes.d.ts +15 -6
  22. package/dist/_dts/api/src/blocks.d.ts +15 -14
  23. package/dist/_dts/api/src/blocksKeys.d.ts +2 -0
  24. package/dist/_dts/api/src/bookingConfig.d.ts +0 -2
  25. package/dist/_dts/api/src/bookingOperations.d.ts +4 -4
  26. package/dist/_dts/api/src/bookingRecords.d.ts +1 -0
  27. package/dist/_dts/api/src/bookings.d.ts +7 -7
  28. package/dist/_dts/api/src/calendar.d.ts +9 -9
  29. package/dist/_dts/api/src/commercePortalEndpoints.d.ts +7 -6
  30. package/dist/_dts/api/src/common/envelope.d.ts +2 -2
  31. package/dist/_dts/api/src/content-editor.d.ts +2 -2
  32. package/dist/_dts/api/src/contentEntries.d.ts +17 -48
  33. package/dist/_dts/api/src/contentRuntime.d.ts +51 -37
  34. package/dist/_dts/api/src/contentTypes.d.ts +11 -11
  35. package/dist/_dts/api/src/contentVersionHistoryClient.d.ts +6 -6
  36. package/dist/_dts/api/src/documentLifecycle.d.ts +67 -0
  37. package/dist/_dts/api/src/domains.d.ts +16 -16
  38. package/dist/_dts/api/src/editLeaseEndpoints.d.ts +72 -0
  39. package/dist/_dts/api/src/emailSettings.d.ts +4 -4
  40. package/dist/_dts/api/src/endpoints.d.ts +133 -41
  41. package/dist/_dts/api/src/eventEmailTemplates.d.ts +2 -2
  42. package/dist/_dts/api/src/eventManagementContracts.d.ts +25 -0
  43. package/dist/_dts/api/src/eventManagementEndpointDefinitions.d.ts +0 -8
  44. package/dist/_dts/api/src/eventPageWords.d.ts +7 -12
  45. package/dist/_dts/api/src/footerSettings.d.ts +6 -6
  46. package/dist/_dts/api/src/index.d.ts +6 -5
  47. package/dist/_dts/api/src/indexCoreTypes.d.ts +1 -0
  48. package/dist/_dts/api/src/indexExtendedTypes.d.ts +1 -1
  49. package/dist/_dts/api/src/navigation.d.ts +5 -5
  50. package/dist/_dts/api/src/pageSurfaceEditorEndpoints.d.ts +55 -0
  51. package/dist/_dts/api/src/pageSurfaceEndpoints.d.ts +28 -7
  52. package/dist/_dts/api/src/pages.d.ts +7 -7
  53. package/dist/_dts/api/src/performance.d.ts +1 -1
  54. package/dist/_dts/api/src/public/index.d.ts +1 -1
  55. package/dist/_dts/api/src/publicAppointmentBookingContracts.d.ts +2 -0
  56. package/dist/_dts/api/src/publicExperience/commerceEndpoints.d.ts +4 -0
  57. package/dist/_dts/api/src/redirects.d.ts +3 -3
  58. package/dist/_dts/api/src/request.d.ts +10 -1
  59. package/dist/_dts/api/src/resources.d.ts +4 -4
  60. package/dist/_dts/api/src/routes.d.ts +8 -3
  61. package/dist/_dts/api/src/sdk-event-upsert.d.ts +0 -1
  62. package/dist/_dts/api/src/sdkBlockUpsertContracts.d.ts +21 -0
  63. package/dist/_dts/api/src/sdkContracts.d.ts +5 -28
  64. package/dist/_dts/api/src/sdkEventEndpointDefinitions.d.ts +1 -1
  65. package/dist/_dts/api/src/sdkEventOccurrenceRequestContracts.d.ts +43 -0
  66. package/dist/_dts/api/src/sdkManagedEventContracts.d.ts +4 -2
  67. package/dist/_dts/api/src/sdkPullEventContracts.d.ts +8 -1
  68. package/dist/_dts/api/src/seo.d.ts +4 -4
  69. package/dist/_dts/api/src/services.d.ts +4 -4
  70. package/dist/_dts/api/src/siteManagementEndpoints.d.ts +15 -8
  71. package/dist/_dts/api/src/siteMembers.d.ts +10 -10
  72. package/dist/_dts/api/src/siteOnboarding.d.ts +14 -0
  73. package/dist/_dts/api/src/sitePlatformEndpoints.d.ts +7 -3
  74. package/dist/_dts/api/src/siteRuntimeEndpoints.d.ts +5 -12
  75. package/dist/_dts/api/src/siteRuntimeEntry.d.ts +31 -0
  76. package/dist/_dts/billing/src/checkout/platform.d.ts +77 -0
  77. package/dist/_dts/billing/src/components/index.d.ts +25 -40
  78. package/dist/_dts/billing/src/membership/index.d.ts +1 -3
  79. package/dist/_dts/billing/src/plans/entitlements.d.ts +80 -0
  80. package/dist/_dts/billing/src/plans/registry.d.ts +16 -16
  81. package/dist/_dts/billing/src/plans/standing.d.ts +9 -2
  82. package/dist/_dts/billing/src/plans/types.d.ts +5 -15
  83. package/dist/_dts/billing/src/site-arrangements.d.ts +2 -2
  84. package/dist/_dts/billing/src/subscriptions/standingEvidence.d.ts +2 -4
  85. package/dist/_dts/billing/src/subscriptions/store.d.ts +17 -11
  86. package/dist/_dts/block-form/src/backend/store-backend.d.ts +6 -7
  87. package/dist/_dts/block-form/src/backend/types.d.ts +7 -0
  88. package/dist/_dts/block-form/src/widgets/FieldFrame.d.ts +3 -1
  89. package/dist/_dts/blocks/src/client/events.d.ts +3 -0
  90. package/dist/_dts/blocks/src/contracts/proof-block-islands.d.ts +16 -4
  91. package/dist/_dts/blocks/src/pageRenderAdmission.d.ts +4 -13
  92. package/dist/_dts/blocks/src/pageRendererContracts.d.ts +2 -0
  93. package/dist/_dts/blocks/src/portal/types.d.ts +0 -2
  94. package/dist/_dts/blocks/src/system/blocks/contact-newsletter.d.ts +2 -1
  95. package/dist/_dts/blocks/src/system/blocks/event-registration.d.ts +3 -1
  96. package/dist/_dts/blocks/src/system/blocks/events/shared/schemas.d.ts +4 -4
  97. package/dist/_dts/blocks/src/system/blocks/events/shared/types.d.ts +6 -1
  98. package/dist/_dts/blocks/src/system/runtime/api/client.d.ts +2 -2
  99. package/dist/_dts/blocks/src/system/runtime/api/index.d.ts +1 -1
  100. package/dist/_dts/blocks/src/system/runtime/api/types/appointments.d.ts +2 -0
  101. package/dist/_dts/blocks/src/system/runtime/api/types/events.d.ts +6 -0
  102. package/dist/_dts/blocks/src/system/runtime/api/types/portal.d.ts +6 -0
  103. package/dist/_dts/blocks/src/system/runtime/api/types/shop.d.ts +4 -0
  104. package/dist/_dts/blocks/src/system/runtime/components/booking/SuccessMessage.d.ts +4 -1
  105. package/dist/_dts/blocks/src/system/runtime/components/registry.client.d.ts +24 -6
  106. package/dist/_dts/blocks/src/system/runtime/components/runtime-backed-blocks.d.ts +12 -3
  107. package/dist/_dts/blocks/src/system/runtime/hooks/useHeadlessBookingFlow.d.ts +3 -0
  108. package/dist/_dts/blocks/src/system/runtime/hooks/usePaymentVerification.d.ts +2 -1
  109. package/dist/_dts/blocks/src/system/runtime/hooks/usePolling.d.ts +7 -48
  110. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.checkout-return-context.d.ts +7 -0
  111. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.completion.d.ts +3 -1
  112. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.headless.state.d.ts +4 -0
  113. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.interactive.d.ts +9 -0
  114. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.payment-confirmation.d.ts +13 -0
  115. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.state.d.ts +15 -1
  116. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.submit-actions.d.ts +8 -0
  117. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.submit-handler.d.ts +1 -0
  118. package/dist/_dts/blocks/src/system/runtime/nodes/booking-runtime-sources.d.ts +1 -0
  119. package/dist/_dts/blocks/src/system/runtime/nodes/checkout.server.d.ts +2 -1
  120. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/EventRegistrationSurface.d.ts +2 -1
  121. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/EventRegistrationWizard.d.ts +5 -0
  122. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/SuccessStep.d.ts +4 -1
  123. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/types.d.ts +2 -0
  124. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventRegistrationSubmit.d.ts +2 -5
  125. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration.interactive.d.ts +9 -5
  126. package/dist/_dts/blocks/src/system/runtime/nodes/events/EventListing.interactive.d.ts +6 -0
  127. package/dist/_dts/blocks/src/system/runtime/nodes/events/domain/dates.d.ts +37 -3
  128. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/EventCard.client.d.ts +1 -1
  129. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/EventCard.d.ts +16 -1
  130. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/eventCardPresentations.d.ts +13 -0
  131. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/eventCollectionContract.d.ts +5 -5
  132. package/dist/_dts/blocks/src/system/runtime/nodes/shared/MagicLinkForm.d.ts +1 -14
  133. package/dist/_dts/blocks/src/system/runtime/nodes/shared/MagicLinkForm.state.d.ts +12 -0
  134. package/dist/_dts/blocks/src/system/runtime/nodes/shop.interactive.d.ts +13 -0
  135. package/dist/_dts/blocks/src/system/runtime/shared/components/DemoBookingPortalAccess.d.ts +22 -0
  136. package/dist/_dts/blocks/src/system/runtime/shared/components/DemoPortalSignInLink.d.ts +4 -0
  137. package/dist/_dts/blocks/src/system/runtime/shared/components/index.d.ts +1 -0
  138. package/dist/_dts/blocks/src/system/runtime/shared/utils/demoBookingPassStorage.d.ts +10 -0
  139. package/dist/_dts/blocks/src/system/runtime/shared/utils/demoPortalMagicLink.d.ts +29 -0
  140. package/dist/_dts/commerce/src/purchase/event-registration-errors.d.ts +4 -0
  141. package/dist/_dts/content-editor/src/components/ContentFieldsForm.d.ts +2 -7
  142. package/dist/_dts/content-editor/src/controller/EditLeaseController.d.ts +39 -0
  143. package/dist/_dts/content-editor/src/controller/EditorWriteGate.d.ts +38 -0
  144. package/dist/_dts/content-editor/src/controller/EntryControllerProvider.d.ts +25 -61
  145. package/dist/_dts/content-editor/src/controller/LinkedEntryLeaseBanner.d.ts +7 -0
  146. package/dist/_dts/content-editor/src/controller/LinkedEntryLeaseControllers.d.ts +14 -0
  147. package/dist/_dts/content-editor/src/controller/deriveEditorUnpublishedState.d.ts +6 -0
  148. package/dist/_dts/content-editor/src/controller/documentValueBaseline.d.ts +25 -0
  149. package/dist/_dts/content-editor/src/controller/editLeaseLossSignal.d.ts +6 -0
  150. package/dist/_dts/content-editor/src/controller/editLeaseNotice.d.ts +28 -0
  151. package/dist/_dts/content-editor/src/controller/editorClientId.d.ts +2 -0
  152. package/dist/_dts/content-editor/src/controller/editorEditability.d.ts +38 -0
  153. package/dist/_dts/content-editor/src/controller/editorLeaseParticipation.d.ts +34 -0
  154. package/dist/_dts/content-editor/src/controller/normalizedMetadataBaseline.d.ts +29 -0
  155. package/dist/_dts/content-editor/src/controller/pageSurfaceDocumentBaselines.d.ts +14 -0
  156. package/dist/_dts/content-editor/src/controller/pageSurfaceLifecycle.d.ts +11 -0
  157. package/dist/_dts/content-editor/src/controller/planDocumentBaselineRefresh.d.ts +19 -0
  158. package/dist/_dts/content-editor/src/controller/readDocumentLeaseBaselines.d.ts +19 -0
  159. package/dist/_dts/content-editor/src/controller/refreshDocumentLeaseBaseline.d.ts +12 -0
  160. package/dist/_dts/content-editor/src/controller/refreshLinkedEntry.d.ts +17 -0
  161. package/dist/_dts/content-editor/src/controller/replayRestoredEditorEffects.d.ts +2 -3
  162. package/dist/_dts/content-editor/src/controller/routeWrites.d.ts +26 -0
  163. package/dist/_dts/content-editor/src/controller/useAutosaveTriggers.d.ts +16 -17
  164. package/dist/_dts/content-editor/src/controller/useBlockedPublishPlan.d.ts +6 -2
  165. package/dist/_dts/content-editor/src/controller/useBlocksList.d.ts +3 -3
  166. package/dist/_dts/content-editor/src/controller/useEntryValueAutosaves.d.ts +21 -0
  167. package/dist/_dts/content-editor/src/controller/useInitialEditorUiStore.d.ts +24 -0
  168. package/dist/_dts/content-editor/src/controller/useServerBaselineReconciliation.d.ts +17 -0
  169. package/dist/_dts/content-editor/src/footerComposerPanelTypes.d.ts +1 -1
  170. package/dist/_dts/content-editor/src/hooks/applyBlockedPublishPlan.d.ts +5 -1
  171. package/dist/_dts/content-editor/src/hooks/blockDraftLifecycle.d.ts +8 -47
  172. package/dist/_dts/content-editor/src/hooks/editLeaseMachine.d.ts +120 -0
  173. package/dist/_dts/content-editor/src/hooks/publishability.d.ts +6 -10
  174. package/dist/_dts/content-editor/src/hooks/useAutosaveStatus.d.ts +3 -0
  175. package/dist/_dts/content-editor/src/hooks/useBlockAutosave.d.ts +5 -15
  176. package/dist/_dts/content-editor/src/hooks/useDebouncedLatestSave.d.ts +7 -5
  177. package/dist/_dts/content-editor/src/hooks/useEditLease.d.ts +28 -0
  178. package/dist/_dts/content-editor/src/hooks/useEntryActions.d.ts +25 -39
  179. package/dist/_dts/content-editor/src/hooks/useEntryMutations.d.ts +17 -19
  180. package/dist/_dts/content-editor/src/hooks/useLinkedEntryAutosave.d.ts +5 -8
  181. package/dist/_dts/content-editor/src/hooks/useValueAutosave.d.ts +64 -0
  182. package/dist/_dts/content-editor/src/hooks/validateBlocksForPublish.d.ts +0 -7
  183. package/dist/_dts/content-editor/src/index.d.ts +26 -7
  184. package/dist/_dts/content-editor/src/linkedEntries/domain.d.ts +12 -0
  185. package/dist/_dts/content-editor/src/linkedEntries/owner.d.ts +9 -0
  186. package/dist/_dts/content-editor/src/liveDrafts/draftProjection.d.ts +66 -0
  187. package/dist/_dts/content-editor/src/liveDrafts/linkedSaveHandovers.d.ts +37 -0
  188. package/dist/_dts/content-editor/src/liveDrafts/remoteDraftOverlay.d.ts +113 -0
  189. package/dist/_dts/content-editor/src/liveDrafts/useLiveDrafts.d.ts +32 -0
  190. package/dist/_dts/content-editor/src/liveDrafts/useRetentionTicks.d.ts +7 -0
  191. package/dist/_dts/content-editor/src/primitives/shared/activePreviewField.d.ts +6 -0
  192. package/dist/_dts/content-editor/src/primitives/shared/storeBinding.d.ts +1 -0
  193. package/dist/_dts/content-editor/src/services/contentEntryServices.d.ts +96 -19
  194. package/dist/_dts/content-editor/src/services/editorApiClient.d.ts +13 -0
  195. package/dist/_dts/content-editor/src/services/index.d.ts +2 -0
  196. package/dist/_dts/content-editor/src/services/pageSurfaceEditorServices.d.ts +23 -0
  197. package/dist/_dts/content-editor/src/sync/flushValues.d.ts +13 -0
  198. package/dist/_dts/content-editor/src/sync/lifecycleFailure.d.ts +51 -0
  199. package/dist/_dts/content-editor/src/sync/runLifecycle.d.ts +64 -0
  200. package/dist/_dts/content-editor/src/sync/schedulerValues.d.ts +27 -0
  201. package/dist/_dts/content-editor/src/sync/sendPlanning.d.ts +104 -0
  202. package/dist/_dts/content-editor/src/sync/valueSync.d.ts +114 -0
  203. package/dist/_dts/content-editor/src/ui/blockCollection.d.ts +8 -0
  204. package/dist/_dts/content-editor/src/ui/documentLifecycle.d.ts +18 -0
  205. package/dist/_dts/content-editor/src/ui/editorLeaseUiState.d.ts +7 -0
  206. package/dist/_dts/content-editor/src/ui/editorRefresh.d.ts +82 -0
  207. package/dist/_dts/content-editor/src/ui/editorSnapshot.d.ts +102 -127
  208. package/dist/_dts/content-editor/src/ui/editorTransactionState.d.ts +1 -1
  209. package/dist/_dts/content-editor/src/ui/editorUiStore.d.ts +126 -72
  210. package/dist/_dts/content-editor/src/ui/editorValueSnapshot.d.ts +18 -0
  211. package/dist/_dts/content-editor/src/ui/serverBlockAdmission.d.ts +26 -0
  212. package/dist/_dts/content-editor/src/ui/stores/autosaveStore.d.ts +16 -27
  213. package/dist/_dts/content-editor/src/ui/stores/blockVersionsStore.d.ts +24 -0
  214. package/dist/_dts/content-editor/src/ui/stores/linkedEntryLeaseStore.d.ts +54 -0
  215. package/dist/_dts/content-editor/src/ui/stores/linkedSaveHandoversStore.d.ts +11 -0
  216. package/dist/_dts/content-editor/src/ui/stores/remoteDraftsStore.d.ts +10 -0
  217. package/dist/_dts/content-editor/src/ui/stores/types.d.ts +63 -3
  218. package/dist/_dts/content-editor/src/useFooterComposerState.d.ts +2 -2
  219. package/dist/_dts/content-editor/src/useFooterNavigationLayout.d.ts +1 -1
  220. package/dist/_dts/content-model/src/content-types/builtin-schemas.d.ts +4 -4
  221. package/dist/_dts/content-model/src/content-types/builtins.d.ts +4 -4
  222. package/dist/_dts/content-model/src/definitions/shared.d.ts +11 -2
  223. package/dist/_dts/content-model/src/entry-slots/index.d.ts +1 -0
  224. package/dist/_dts/content-model/src/entry-slots/serializeAllowedBlocks.d.ts +2 -0
  225. package/dist/_dts/content-model/src/metadataConfig.d.ts +10 -38
  226. package/dist/_dts/content-model/src/templates/defaults.d.ts +0 -1
  227. package/dist/_dts/content-model/src/types.d.ts +0 -1
  228. package/dist/_dts/core/src/block-content-identity.d.ts +49 -1
  229. package/dist/_dts/core/src/branded.d.ts +12 -0
  230. package/dist/_dts/core/src/currency-format.d.ts +8 -2
  231. package/dist/_dts/core/src/demo-lifecycle-status.d.ts +2 -2
  232. package/dist/_dts/core/src/demo-warm-pool-target.d.ts +8 -0
  233. package/dist/_dts/core/src/edit-lease.d.ts +55 -0
  234. package/dist/_dts/core/src/editor-state.d.ts +38 -13
  235. package/dist/_dts/core/src/editor-value-sync.d.ts +79 -0
  236. package/dist/_dts/core/src/html-entities.d.ts +6 -0
  237. package/dist/_dts/core/src/index.d.ts +4 -0
  238. package/dist/_dts/core/src/uuid.d.ts +7 -5
  239. package/dist/_dts/db/src/generated/supabase/database.types.d.ts +159 -153
  240. package/dist/_dts/editor/src/EditorProvider.d.ts +5 -0
  241. package/dist/_dts/editor/src/chrome/EditorChrome.d.ts +14 -0
  242. package/dist/_dts/editor/src/chrome/EditorStatusBar.d.ts +1 -0
  243. package/dist/_dts/editor/src/chrome/statusBarPresentation.d.ts +0 -1
  244. package/dist/_dts/editor/src/index.d.ts +1 -1
  245. package/dist/_dts/editor-blocks/src/BlockEditor.d.ts +10 -9
  246. package/dist/_dts/editor-blocks/src/BlockForm.d.ts +1 -1
  247. package/dist/_dts/editor-blocks/src/block-editor/BlockCard.d.ts +1 -1
  248. package/dist/_dts/editor-blocks/src/block-editor/BlockCardFrame.d.ts +1 -1
  249. package/dist/_dts/editor-blocks/src/block-editor/BlockSettingsModal.d.ts +1 -1
  250. package/dist/_dts/editor-blocks/src/block-editor/applyExtendedFieldDefaults.d.ts +3 -4
  251. package/dist/_dts/editor-blocks/src/block-editor/blockDraftBaselineSeed.d.ts +4 -8
  252. package/dist/_dts/editor-blocks/src/block-editor/editorBlockItem.d.ts +23 -0
  253. package/dist/_dts/editor-blocks/src/block-editor/generatedIconApplyCoordination.d.ts +2 -7
  254. package/dist/_dts/editor-blocks/src/block-editor/hooks/applyBlockStructureChange.d.ts +4 -0
  255. package/dist/_dts/editor-blocks/src/block-editor/hooks/buildInsertBlockHistoryCommand.d.ts +14 -5
  256. package/dist/_dts/editor-blocks/src/block-editor/hooks/useBlockBaselineSync.d.ts +21 -19
  257. package/dist/_dts/editor-blocks/src/block-editor/hooks/useBlockCreation.d.ts +2 -10
  258. package/dist/_dts/editor-blocks/src/block-editor/hooks/useBlockDuplication.d.ts +8 -16
  259. package/dist/_dts/editor-blocks/src/block-editor/owner.d.ts +6 -16
  260. package/dist/_dts/editor-blocks/src/block-editor/types.d.ts +37 -9
  261. package/dist/_dts/editor-blocks/src/index.d.ts +2 -1
  262. package/dist/_dts/editor-blocks/src/widgets/entry-picker/loaders.d.ts +1 -1
  263. package/dist/_dts/editor-blocks/src/widgets/link/loaders.d.ts +1 -1
  264. package/dist/_dts/editor-blocks/src/widgets/mailing-list-targeting/loaders.d.ts +1 -1
  265. package/dist/_dts/editor-blocks/src/widgets/reference/loaders.d.ts +1 -1
  266. package/dist/_dts/editor-blocks/src/widgets/site-option-picker/loaders.d.ts +3 -2
  267. package/dist/_dts/media-core/src/fileStorage.d.ts +4 -0
  268. package/dist/_dts/media-editor/src/context.d.ts +1 -1
  269. package/dist/_dts/media-editor/src/createMediaEditorProvider.d.ts +1 -2
  270. package/dist/_dts/media-editor/src/provider.d.ts +3 -2
  271. package/dist/_dts/media-react/src/hooks/internal/classification.d.ts +1 -1
  272. package/dist/_dts/media-react/src/hooks/useApiMediaUploader.d.ts +3 -1
  273. package/dist/_dts/preview-next/src/client/blocks/composer/mergeDrafts.d.ts +8 -3
  274. package/dist/_dts/preview-next/src/client/blocks/composer/types.d.ts +6 -3
  275. package/dist/_dts/preview-next/src/client/blocks/linkedEntryRenderOverlay.d.ts +22 -2
  276. package/dist/_dts/preview-next/src/client/blocks/previewProjection/entryFieldRebinding.d.ts +13 -0
  277. package/dist/_dts/preview-next/src/client/blocks/previewProjection/index.d.ts +2 -1
  278. package/dist/_dts/preview-next/src/client/blocks/previewProjection/types.d.ts +11 -1
  279. package/dist/_dts/preview-next/src/client/blocks/renderPrecedence.d.ts +17 -0
  280. package/dist/_dts/preview-next/src/client/blocks/useLinkedSaveHandoverRetention.d.ts +20 -0
  281. package/dist/_dts/preview-next/src/client/index.d.ts +1 -1
  282. package/dist/_dts/preview-next/src/client/preview/EntryEditorPanel.d.ts +2 -1
  283. package/dist/_dts/preview-next/src/client/preview/EntrySlotBlockEditorPanel.d.ts +2 -1
  284. package/dist/_dts/preview-next/src/client/preview/PreviewAccessBanners.d.ts +7 -0
  285. package/dist/_dts/preview-next/src/client/preview/PreviewEditorSidebar.d.ts +2 -1
  286. package/dist/_dts/preview-next/src/client/preview/PreviewEntryControllerProvider.d.ts +24 -14
  287. package/dist/_dts/preview-next/src/client/preview/PreviewLeaseEditingMode.d.ts +2 -0
  288. package/dist/_dts/preview-next/src/client/preview/PreviewShell.d.ts +9 -2
  289. package/dist/_dts/preview-next/src/client/preview/PreviewShellLayout.d.ts +1 -0
  290. package/dist/_dts/preview-next/src/client/preview/previewCustomizeAutosave.d.ts +5 -0
  291. package/dist/_dts/preview-next/src/client/preview/previewCustomizeWorkflowState.d.ts +3 -4
  292. package/dist/_dts/preview-next/src/client/preview/sdkConfig.d.ts +1 -0
  293. package/dist/_dts/preview-next/src/client/preview/usePreviewCustomizeWorkflowState.d.ts +4 -0
  294. package/dist/_dts/realtime/src/client.d.ts +3 -0
  295. package/dist/_dts/realtime/src/draftChannel.d.ts +91 -0
  296. package/dist/_dts/realtime/src/drafts.d.ts +210 -0
  297. package/dist/_dts/realtime/src/index.d.ts +3 -0
  298. package/dist/_dts/realtime/src/leaseChangeSubscriptions.d.ts +8 -0
  299. package/dist/_dts/realtime/src/types.d.ts +113 -0
  300. package/dist/_dts/realtime/src/useDraftChannel.d.ts +34 -0
  301. package/dist/_dts/realtime/src/useSiteRealtimeReload.d.ts +27 -0
  302. package/dist/_dts/sdk/src/public-api/contracts.d.ts +6 -55
  303. package/dist/_dts/sdk/src/rendering/blocks-page-renderer.d.ts +1 -0
  304. package/dist/_dts/sdk/src/rendering/components/pageShared.d.ts +1 -0
  305. package/dist/_dts/sdk/src/rendering/helpers/pageRuntimeSupport.d.ts +2 -0
  306. package/dist/_dts/sdk/src/version.d.ts +1 -1
  307. package/dist/_dts/surfaces/src/index.d.ts +1 -0
  308. package/dist/_dts/theme-core/src/site-styles/designState.d.ts +2 -2
  309. package/dist/client/{BookingMailingListNote-1n4Ch_u_.mjs → BookingMailingListNote-CzRt2dF_.mjs} +98 -96
  310. package/dist/client/DemoBookingPortalAccess-mxqwap3f.mjs +344 -0
  311. package/dist/client/{EventCombined.client-C0pgma9y.mjs → EventCombined.client-CDb11igO.mjs} +6 -6
  312. package/dist/client/{EventListing.client-4fhLOvHP.mjs → EventListing.client-EgYhzKPa.mjs} +2 -2
  313. package/dist/client/{LeafletStaticMap-DScC4F3w.mjs → LeafletStaticMap-gtmtaA2b.mjs} +1 -1
  314. package/dist/client/{TerminalPanel-B5ZUsYhe.mjs → TerminalPanel-DvNUP5ot.mjs} +1 -1
  315. package/dist/client/{ThemedButton-DoVIV1Ao.mjs → ThemedButton-C7CeUJjW.mjs} +1 -1
  316. package/dist/client/{accordion-CoT5g7zo.mjs → accordion-kjvt49rA.mjs} +1 -1
  317. package/dist/client/{bookingForm-BWxB46xD.mjs → bookingForm-pbRZordh.mjs} +212 -62
  318. package/dist/client/bookings.mjs +616 -225
  319. package/dist/client/{carousel-DtNYWFd3.mjs → carousel-f4Zbmicv.mjs} +1 -1
  320. package/dist/client/{cart-z4qZih1Y.mjs → cart-DO20An50.mjs} +3 -3
  321. package/dist/client/{checkout-DpL7euFH.mjs → checkout-Du5amDR_.mjs} +3 -3
  322. package/dist/client/{checkoutUrls-BEfR7kVu.mjs → checkoutUrls-CXhko2Rv.mjs} +1 -1
  323. package/dist/client/client.mjs +1753 -823
  324. package/dist/client/{context-C8TinPJc.mjs → context-eW97E945.mjs} +4 -3
  325. package/dist/client/{dates-vwwxTeB0.mjs → dates-jPCirRea.mjs} +56 -11
  326. package/dist/client/{eventCalendar-DIbHfJXO.mjs → eventCalendar-C2M-iE4j.mjs} +9 -9
  327. package/dist/client/{eventCombined-DoGMJ6cg.mjs → eventCombined-W6ns3LHg.mjs} +4 -4
  328. package/dist/client/{eventDetails-BjN9v6a1.mjs → eventDetails-CR-GT0f0.mjs} +4 -4
  329. package/dist/client/{eventListing-DajjWgOv.mjs → eventListing-BK8AfYZz.mjs} +4 -4
  330. package/dist/client/{eventRegistration-DMq9gMA-.mjs → eventRegistration-BJSd4KUu.mjs} +369 -242
  331. package/dist/client/{form-Qf6qTbos.mjs → form-BvpfbQaT.mjs} +3 -3
  332. package/dist/client/{headerSection-D7qJrqFX.mjs → headerSection-I5sUQ8x-.mjs} +3 -3
  333. package/dist/client/hooks.mjs +254 -53
  334. package/dist/client/{locationMap-CCF9-t_0.mjs → locationMap-BLvwf9_f.mjs} +3 -3
  335. package/dist/client/{media-CwBGetqC.mjs → media-Cl38iOMI.mjs} +10 -3
  336. package/dist/client/{newsletterForm-DzCLSP4S.mjs → newsletterForm-DrQ2weE8.mjs} +3 -3
  337. package/dist/client/{pricing-Cgxv2KLC.mjs → pricing-BES87mrR.mjs} +1 -1
  338. package/dist/client/{productDetail-ru9w5GHx.mjs → productDetail-Url9jcc5.mjs} +3 -3
  339. package/dist/client/{productList-zaapKSl-.mjs → productList-DE7ngEZJ.mjs} +3 -3
  340. package/dist/client/{propsDecoder-CwvvNOHx.mjs → propsDecoder-D1OtGXDV.mjs} +89 -17
  341. package/dist/client/rendering/client.mjs +1445 -658
  342. package/dist/client/rendering/islands.mjs +18 -18
  343. package/dist/client/rendering.mjs +2478 -1515
  344. package/dist/client/{routeIslandApiConfig-BwVFo0Y4.mjs → routeIslandApiConfig-BG9Y-SHg.mjs} +1 -1
  345. package/dist/client/{shop-mktkXvbV.mjs → shop-CJkuySJ3.mjs} +126 -79
  346. package/dist/client/{shop-commerce-De7gEnkA.mjs → shop-commerce-4rKj5n9h.mjs} +25 -13
  347. package/dist/client/{shop-commerce-store-B3MCxIBW.mjs → shop-commerce-store-Bxm75Pg6.mjs} +1 -1
  348. package/dist/client/{shopShared-TqExh235.mjs → shopShared-DpoQDWfz.mjs} +4 -4
  349. package/dist/client/{useEventFilters-n_OjkIjX.mjs → useEventFilters-D8HliSqR.mjs} +32 -17
  350. package/dist/preview-next/before-render.mjs +192 -83
  351. package/dist/preview-next/client/runtime.mjs +4 -4
  352. package/dist/preview-next/keepAlive.mjs +192 -83
  353. package/dist/preview-next/middleware.mjs +192 -83
  354. package/dist/{previewAuthStore-C_EHQ5XA.mjs → previewAuthStore-BXXF3hhW.mjs} +194 -83
  355. package/dist/{sdk-runtime-BIkJg5y1.mjs → sdk-runtime-C2a05WjL.mjs} +2 -2
  356. package/dist/{separator-C9qDP95Z.mjs → separator-CuNhBAhS.mjs} +1 -1
  357. package/dist/server/components.mjs +1720 -1392
  358. package/dist/server/config-validation.mjs +221 -37
  359. package/dist/server/config.mjs +221 -37
  360. package/dist/server/data.mjs +221 -37
  361. package/dist/server/index.mjs +195 -84
  362. package/dist/server/next.mjs +490 -196
  363. package/dist/server/page-converter.mjs +53 -14
  364. package/dist/server/prebuild.mjs +1 -1
  365. package/dist/server/rendering/server.mjs +1427 -1098
  366. package/dist/server/rendering.mjs +2693 -2365
  367. package/dist/server/routing.mjs +291 -55
  368. package/dist/server/server.mjs +281 -114
  369. package/package.json +1 -1
  370. package/dist/_dts/billing/src/plans/display.d.ts +0 -15
  371. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.mailing-list-note.d.ts +0 -3
  372. package/dist/_dts/content-editor/src/controller/buildBlockPublishedBaselines.d.ts +0 -4
  373. package/dist/_dts/content-editor/src/controller/buildPublishSuccessTransition.d.ts +0 -16
  374. package/dist/_dts/content-editor/src/controller/driver.d.ts +0 -14
  375. package/dist/_dts/content-editor/src/controller/seedDraftBaselinesFromBlocks.d.ts +0 -7
  376. package/dist/_dts/content-editor/src/controller/useEntrySyncHelpers.d.ts +0 -29
  377. package/dist/_dts/content-editor/src/hooks/autosaveScopePlanning.d.ts +0 -26
  378. package/dist/_dts/content-editor/src/hooks/useSimpleAutosave.d.ts +0 -64
  379. package/dist/_dts/content-editor/src/hooks/useStoreAutosave.d.ts +0 -48
  380. package/dist/_dts/content-editor/src/types.d.ts +0 -44
  381. package/dist/client/DiscountCodeDisclosure-CKJtz0mY.mjs +0 -137
@@ -62,6 +62,19 @@ const CURRENCY_LOCALE_BY_CODE = {
62
62
  function resolveCurrencyLocale(currencyCode, override) {
63
63
  return override ?? CURRENCY_LOCALE_BY_CODE[currencyCode] ?? "en";
64
64
  }
65
+ function fractionDigitsFor(decimals, exactFormatter) {
66
+ switch (decimals) {
67
+ case "exact": return {};
68
+ case "auto": return {
69
+ minimumFractionDigits: 0,
70
+ maximumFractionDigits: exactFormatter.resolvedOptions().maximumFractionDigits
71
+ };
72
+ case "whole": return {
73
+ minimumFractionDigits: 0,
74
+ maximumFractionDigits: 0
75
+ };
76
+ }
77
+ }
65
78
  /**
66
79
  * The single currency-amount formatter for the product: minor units in,
67
80
  * localized string out.
@@ -72,6 +85,13 @@ function resolveCurrencyLocale(currencyCode, override) {
72
85
  * own `Intl.NumberFormat`.
73
86
  */
74
87
  function formatCurrencyAmount(amountCents, currency, options) {
88
+ return formatCurrencyMajorUnits(amountCents / 100, currency, options);
89
+ }
90
+ /**
91
+ * `formatCurrencyAmount` for an amount already in MAJOR units (29.99 = £29.99),
92
+ * such as a registrar price. Prefer minor units everywhere else.
93
+ */
94
+ function formatCurrencyMajorUnits(amount, currency, options) {
75
95
  const currencyCode = currency.toUpperCase();
76
96
  const locale = resolveCurrencyLocale(currencyCode, options?.locale);
77
97
  try {
@@ -79,17 +99,13 @@ function formatCurrencyAmount(amountCents, currency, options) {
79
99
  style: "currency",
80
100
  currency: currencyCode
81
101
  });
82
- const fractionDigits = options?.decimals === "auto" ? {
83
- minimumFractionDigits: 0,
84
- maximumFractionDigits: exactFormatter.resolvedOptions().maximumFractionDigits
85
- } : {};
86
102
  return new Intl.NumberFormat(locale, {
87
103
  style: "currency",
88
104
  currency: currencyCode,
89
- ...fractionDigits
90
- }).format(amountCents / 100);
105
+ ...fractionDigitsFor(options?.decimals ?? "exact", exactFormatter)
106
+ }).format(amount);
91
107
  } catch {
92
- return `${(amountCents / 100).toFixed(2)} ${currencyCode}`;
108
+ return `${amount.toFixed(2)} ${currencyCode}`;
93
109
  }
94
110
  }
95
111
  /** Default clock for production callers that do not inject time explicitly. */
@@ -680,6 +696,26 @@ function toLocationCoordinates(value) {
680
696
  };
681
697
  }
682
698
  //#endregion
699
+ //#region ../core/src/block-content-identity.ts
700
+ function readContentVersionId(value) {
701
+ const parsed = parseContentVersionId(value);
702
+ return parsed.ok ? parsed.value : null;
703
+ }
704
+ /** The one pairing of a published id with its content. */
705
+ function readPublishedBlockPlacement(id, content) {
706
+ if (id == null && content == null) return null;
707
+ const versionId = readContentVersionId(id);
708
+ return versionId !== null && content != null ? {
709
+ kind: "published",
710
+ id: versionId,
711
+ content
712
+ } : {
713
+ kind: "incomplete",
714
+ id: id ?? null,
715
+ content: content ?? null
716
+ };
717
+ }
718
+ //#endregion
683
719
  //#region ../core/src/rich-text.ts
684
720
  function isRecord$39(value) {
685
721
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -1657,11 +1693,18 @@ function isReservedPathSegment(value) {
1657
1693
  function isUnsafePathSegment$1(segment) {
1658
1694
  return segment.trim().length === 0 || segment !== segment.trim() || isReservedPathSegment(segment) || containsUnsafePathSegmentCharacter(segment);
1659
1695
  }
1660
- ({
1696
+ //#endregion
1697
+ //#region ../media-core/src/fileStorage.ts
1698
+ const FILE_STORAGE_BUCKETS = {
1661
1699
  publicSite: unsafeAsStorageBucketName("media"),
1662
1700
  privateSite: unsafeAsStorageBucketName("site-files-private"),
1663
- temporary: unsafeAsStorageBucketName("temp-uploads")
1664
- }).publicSite;
1701
+ temporary: unsafeAsStorageBucketName("temp-uploads"),
1702
+ siteAssets: unsafeAsStorageBucketName("site-assets"),
1703
+ siteFonts: unsafeAsStorageBucketName("site-fonts"),
1704
+ bookingRequirementDocuments: unsafeAsStorageBucketName("booking-requirement-documents")
1705
+ };
1706
+ FILE_STORAGE_BUCKETS.publicSite, FILE_STORAGE_BUCKETS.siteAssets, FILE_STORAGE_BUCKETS.siteFonts;
1707
+ FILE_STORAGE_BUCKETS.publicSite, FILE_STORAGE_BUCKETS.privateSite, FILE_STORAGE_BUCKETS.temporary, FILE_STORAGE_BUCKETS.siteAssets, FILE_STORAGE_BUCKETS.siteFonts, FILE_STORAGE_BUCKETS.bookingRequirementDocuments;
1665
1708
  function parseStoragePath(value) {
1666
1709
  return joinStoragePathSegments(value.split("/"));
1667
1710
  }
@@ -29776,7 +29819,6 @@ const publicEventBaseSchema = z$1.object({
29776
29819
  description: z$1.string().nullable(),
29777
29820
  content: z$1.object({ body: RichTextDocSchema.nullable().optional() }).optional(),
29778
29821
  presentation: z$1.object({
29779
- cardTitleOverride: z$1.string().nullable().optional(),
29780
29822
  summary: z$1.string().nullable().optional(),
29781
29823
  image: mediaSchema.nullable().optional()
29782
29824
  }).optional(),
@@ -29809,6 +29851,7 @@ const publicEventBaseSchema = z$1.object({
29809
29851
  "archived"
29810
29852
  ]).optional(),
29811
29853
  timeZone: z$1.string(),
29854
+ siteTimeZone: z$1.string().optional(),
29812
29855
  pricing: publicEventPricingSchema,
29813
29856
  paymentTerms: blockBookingPaymentTermsSchema,
29814
29857
  cancellationPolicy: z$1.object({ refunds: z$1.object({
@@ -33795,6 +33838,7 @@ const bookingMailingListContextSchema = z$1.unknown().transform((value) => {
33795
33838
  return parsed.ok ? parsed.value : void 0;
33796
33839
  });
33797
33840
  const bookingSourceSchema = z$1.object({
33841
+ demoEmailSuppressed: z$1.boolean().optional(),
33798
33842
  mailingList: bookingMailingListContextSchema.optional(),
33799
33843
  siteName: z$1.string().optional(),
33800
33844
  siteId: z$1.string().optional(),
@@ -33825,6 +33869,7 @@ const bookingDisplaySchema = z$1.object({
33825
33869
  message: z$1.string().nullable()
33826
33870
  });
33827
33871
  const bookingHydrationSchema = z$1.object({
33872
+ demoEmailSuppressed: z$1.boolean().optional(),
33828
33873
  mailingList: bookingMailingListContextSchema.optional(),
33829
33874
  siteName: z$1.string().optional(),
33830
33875
  formId: z$1.string().nullable(),
@@ -33872,6 +33917,7 @@ const bookingFormBlockRuntime = defineClientOwnedBlockRuntime({
33872
33917
  return {
33873
33918
  display: buildBookingFormDisplay(source, form),
33874
33919
  hydration: {
33920
+ demoEmailSuppressed: source.demoEmailSuppressed,
33875
33921
  mailingList: source.mailingList,
33876
33922
  siteName: source.siteName,
33877
33923
  formId: form?.id ?? source.formId ?? null,
@@ -34708,6 +34754,44 @@ function resolveEventCta(event, buttonText) {
34708
34754
  * timestamps become strings or date buckets. Calendar-grid primitives are
34709
34755
  * re-exported from @riverbankcms/calendar so block code has one import.
34710
34756
  */
34757
+ /**
34758
+ * The English locale a site's public dates are written in, read from the
34759
+ * site's own time zone (Will, 2026-09-26: "date style from site time zone").
34760
+ *
34761
+ * Sites don't store a locale, and every public word around a date is English,
34762
+ * so the only open question is which English conventions to follow: day or
34763
+ * month first, and a 24 or 12-hour clock. The site's time zone is the one
34764
+ * fact every site carries about where it is. It is the site's, never an
34765
+ * event's: a venue left at UTC must not turn a UK site's dates American.
34766
+ * Anywhere this can't place (UTC, the Americas, Asia) keeps US English, which
34767
+ * is what these helpers wrote before sites were placed at all.
34768
+ */
34769
+ function eventDateLocale(siteTimeZone) {
34770
+ if (!siteTimeZone) return "en-US";
34771
+ if (siteTimeZone === "Europe/Dublin") return "en-IE";
34772
+ if (siteTimeZone.startsWith("Europe/")) return "en-GB";
34773
+ if (siteTimeZone.startsWith("Australia/")) return "en-AU";
34774
+ if (siteTimeZone === "Pacific/Auckland" || siteTimeZone === "Pacific/Chatham") return "en-NZ";
34775
+ return "en-US";
34776
+ }
34777
+ /**
34778
+ * Formatting options for an event's dates: the times in the event's own zone,
34779
+ * written in its site's locale. A record from an older server that doesn't
34780
+ * name the site's zone falls back to the event's.
34781
+ */
34782
+ function eventDateOptions(place) {
34783
+ return {
34784
+ timeZone: place.timeZone ?? null,
34785
+ locale: eventDateLocale(place.siteTimeZone ?? place.timeZone)
34786
+ };
34787
+ }
34788
+ /**
34789
+ * Start and end times as cards write them, in the site's locale:
34790
+ * "10:00 to 16:00" in the UK, "10:00 AM to 4:00 PM" in the US.
34791
+ */
34792
+ function formatEventTimeRange$1(times, options) {
34793
+ return `${formatTime(times.startsAt, options)} to ${formatTime(times.endsAt, options)}`;
34794
+ }
34711
34795
  /** Use the event timezone when present, otherwise the calendar/site timezone. */
34712
34796
  function resolveEventTimeZone(event, calendarTimeZone) {
34713
34797
  return event.timeZone || calendarTimeZone;
@@ -34729,18 +34813,25 @@ function formatDate$2(isoTimestamp, options) {
34729
34813
  });
34730
34814
  }
34731
34815
  /**
34732
- * Format time for display.
34733
- * Returns: "10:00 AM"
34816
+ * Whether the locale reads a 24-hour clock, where hours are written with two
34817
+ * digits ("09:00"), as the dashboard writes them.
34818
+ */
34819
+ function usesTwentyFourHourClock(locale) {
34820
+ return new Intl.DateTimeFormat(locale, { hour: "numeric" }).resolvedOptions().hour12 === false;
34821
+ }
34822
+ /**
34823
+ * Format time for display, on the locale's own clock.
34824
+ * Returns: "9:00 AM" (en-US) or "09:00" (en-GB)
34734
34825
  */
34735
34826
  function formatTime(isoTimestamp, options) {
34827
+ const locale = options?.locale ?? "en-US";
34736
34828
  return formatBookingTime(toScheduledBookingDateTime({
34737
34829
  startsAt: isoTimestamp,
34738
34830
  timeZone: toBookingTimeZone(options?.timeZone ?? "UTC"),
34739
- locale: options?.locale ?? "en-US"
34831
+ locale
34740
34832
  }), {
34741
- hour: "numeric",
34742
- minute: "2-digit",
34743
- hour12: true
34833
+ hour: usesTwentyFourHourClock(locale) ? "2-digit" : "numeric",
34834
+ minute: "2-digit"
34744
34835
  });
34745
34836
  }
34746
34837
  function formatEventDateParts(args) {
@@ -34772,7 +34863,7 @@ function formatEventCompactDateRail(isoTimestamp, options) {
34772
34863
  locale: options?.locale ?? "en-US"
34773
34864
  });
34774
34865
  const weekday = formatBookingDate(dateTime, { weekday: "short" }).toLocaleUpperCase(options?.locale ?? "en-US");
34775
- const month = formatBookingDate(dateTime, { month: "short" }).toLocaleUpperCase(options?.locale ?? "en-US");
34866
+ const month = formatBookingDate(dateTime, { month: "short" }).slice(0, 3).toLocaleUpperCase(options?.locale ?? "en-US");
34776
34867
  return {
34777
34868
  weekday,
34778
34869
  day: formatBookingDate(dateTime, { day: "numeric" }),
@@ -34792,7 +34883,7 @@ function formatEventCompactDateRail(isoTimestamp, options) {
34792
34883
  * keep the fact panel on the same date and timezone rules as event rows.
34793
34884
  */
34794
34885
  function formatEventNextDateFact(event) {
34795
- const rail = formatEventCompactDateRail(event.startsAt, { timeZone: event.timeZone });
34886
+ const rail = formatEventCompactDateRail(event.startsAt, eventDateOptions(event));
34796
34887
  return {
34797
34888
  dateTime: event.startsAt,
34798
34889
  value: `${rail.weekday} ${rail.day} ${rail.month}`,
@@ -35639,6 +35730,13 @@ function CalendarIcon({ className, size = 16, strokeWidth = 2 }) {
35639
35730
  }
35640
35731
  //#endregion
35641
35732
  //#region ../blocks/src/system/runtime/nodes/events/shared/EventCard.tsx
35733
+ /** The category's badge, when the event has a category. */
35734
+ function eventCardCategoryBadge(category) {
35735
+ return category ? {
35736
+ label: category.name,
35737
+ style: getCategoryBadgeStyle(category.color ?? null)
35738
+ } : null;
35739
+ }
35642
35740
  /**
35643
35741
  * EventCard Component
35644
35742
  *
@@ -35647,24 +35745,19 @@ function CalendarIcon({ className, size = 16, strokeWidth = 2 }) {
35647
35745
  *
35648
35746
  * This component is server-safe (uses no client APIs like Intl).
35649
35747
  */
35650
- const EventCard = ({ event, cardRole = "default", buttonVariant = "primary", buttonText, showVenue = true, showMap = true, mapSlot, allowMap = true, showCapacity = true, showImage = true, showCategory = true, showSummary = true, orientation = "vertical", presentation, headingLevel }) => {
35748
+ const EventCard = ({ event, cardRole = "default", buttonVariant = "primary", buttonText, showVenue = true, showMap = true, mapSlot, allowMap = true, showCapacity = true, showImage = true, showCategory = true, showSummary = true, orientation = "vertical", presentation, headingLevel, imageResolveContext }) => {
35651
35749
  const { presentation: cardPresentation, presentationClass, headingLevel: cardHeadingLevel } = resolveEventCardOptions({
35652
35750
  presentation,
35653
35751
  headingLevel
35654
35752
  });
35655
- const timeZone = event.timeZone ?? null;
35656
- const formattedDate = formatDate$2(event.startsAt, { timeZone });
35657
- const formattedTime = `${formatTime(event.startsAt, { timeZone })} - ${formatTime(event.endsAt, { timeZone })}`;
35753
+ const { formattedDate, formattedTime } = formatEventCardWhen(event);
35658
35754
  const cta = resolveEventCta(event, buttonText);
35659
35755
  const cardClass = boxStyleClassNames({ role: cardRole }, { baseClass: "event-card" });
35660
35756
  const title = event.title;
35661
35757
  const summary = event.presentation?.summary ?? event.description;
35662
35758
  const image = event.presentation?.image ?? null;
35663
35759
  const category = event.eventCategory;
35664
- const categoryBadge = category && showCategory ? {
35665
- label: category.name,
35666
- style: getCategoryBadgeStyle(category.color ?? null)
35667
- } : null;
35760
+ const categoryBadge = showCategory ? eventCardCategoryBadge(category) : null;
35668
35761
  const hasImage = Boolean(showImage && image);
35669
35762
  const dateFact = resolveEventCardDateFact({
35670
35763
  event,
@@ -35683,7 +35776,8 @@ const EventCard = ({ event, cardRole = "default", buttonVariant = "primary", but
35683
35776
  categoryId: category?.id,
35684
35777
  dateFact,
35685
35778
  hasImage,
35686
- image
35779
+ image,
35780
+ imageResolveContext
35687
35781
  }), /* @__PURE__ */ jsx(EventCardContent, {
35688
35782
  allowMap,
35689
35783
  buttonVariant,
@@ -35731,7 +35825,8 @@ function EventCardMedia(props) {
35731
35825
  /* @__PURE__ */ jsx(MediaNodeServer, {
35732
35826
  value: props.image,
35733
35827
  className: "event-card-image",
35734
- size: ImagePresets$1.card
35828
+ size: ImagePresets$1.card,
35829
+ imageResolveContext: props.imageResolveContext
35735
35830
  }),
35736
35831
  props.categoryBadge && /* @__PURE__ */ jsx("span", {
35737
35832
  className: "event-category-badge event-category-badge--overlay",
@@ -35846,6 +35941,17 @@ function resolveEventCardOptions(props) {
35846
35941
  headingLevel: props.headingLevel ?? 3
35847
35942
  };
35848
35943
  }
35944
+ /**
35945
+ * The card's date and times, written the way the event's place writes them
35946
+ * ("Friday, 16 October 2026" and "10:00 to 16:00" in the UK).
35947
+ */
35948
+ function formatEventCardWhen(event) {
35949
+ const options = eventDateOptions(event);
35950
+ return {
35951
+ formattedDate: formatDate$2(event.startsAt, options),
35952
+ formattedTime: formatEventTimeRange$1(event, options)
35953
+ };
35954
+ }
35849
35955
  function resolveEventCardDateFact(props) {
35850
35956
  if (!props.showImage || props.image || props.presentation !== "catalogue") return null;
35851
35957
  return formatEventNextDateFact(props.event);
@@ -37283,6 +37389,34 @@ function buildEventCombinedInteractiveIslandProps(props) {
37283
37389
  });
37284
37390
  }
37285
37391
  //#endregion
37392
+ //#region ../blocks/src/system/runtime/nodes/events/shared/eventCardPresentations.ts
37393
+ /** A booking page's catalogue card: one per series, "See dates" for dated events. */
37394
+ function catalogueEventCardProps(event, buttonVariant = "primary") {
37395
+ return {
37396
+ presentation: "catalogue",
37397
+ headingLevel: 4,
37398
+ buttonVariant,
37399
+ buttonText: event.bookingScope === "single_occurrence" ? "See dates" : void 0,
37400
+ showMap: false,
37401
+ allowMap: false,
37402
+ showCategory: false,
37403
+ orientation: "vertical"
37404
+ };
37405
+ }
37406
+ /** An events listing's card, from the listing's display settings. */
37407
+ function listingEventCardProps(display) {
37408
+ return {
37409
+ cardRole: display.cardRole,
37410
+ buttonVariant: display.buttonVariant,
37411
+ buttonText: display.buttonText,
37412
+ showVenue: display.showVenue,
37413
+ showMap: display.showMap,
37414
+ allowMap: false,
37415
+ showCapacity: display.showCapacity,
37416
+ orientation: display.orientation
37417
+ };
37418
+ }
37419
+ //#endregion
37286
37420
  //#region ../blocks/src/system/runtime/nodes/events/shared/renderEventListItem.tsx
37287
37421
  /**
37288
37422
  * Shared SSR render function for event list items.
@@ -37299,14 +37433,7 @@ function renderEventListItem(event, display) {
37299
37433
  }, event.occurrenceId || event.id);
37300
37434
  return /* @__PURE__ */ jsx(EventCard, {
37301
37435
  event,
37302
- cardRole: display.cardRole,
37303
- buttonVariant: display.buttonVariant,
37304
- buttonText: display.buttonText,
37305
- showVenue: display.showVenue,
37306
- showMap: display.showMap,
37307
- allowMap: false,
37308
- showCapacity: display.showCapacity,
37309
- orientation: display.orientation
37436
+ ...listingEventCardProps(display)
37310
37437
  }, event.occurrenceId || event.id);
37311
37438
  }
37312
37439
  //#endregion
@@ -37712,14 +37839,7 @@ function OfferingsCatalogue(props) {
37712
37839
  style: { gridTemplateColumns: "repeat(auto-fill, minmax(min(100%, 18rem), 1fr))" },
37713
37840
  children: events.map((event) => /* @__PURE__ */ jsx(EventCard, {
37714
37841
  event,
37715
- presentation: "catalogue",
37716
- headingLevel: 4,
37717
- buttonVariant: props.buttonVariant ?? "primary",
37718
- buttonText: event.bookingScope === "single_occurrence" ? "See dates" : void 0,
37719
- showMap: false,
37720
- allowMap: false,
37721
- showCategory: false,
37722
- orientation: "vertical"
37842
+ ...catalogueEventCardProps(event, props.buttonVariant ?? "primary")
37723
37843
  }, event.seriesId))
37724
37844
  })]
37725
37845
  }, group.sourceKey))
@@ -38007,45 +38127,73 @@ function FeaturedOfferingSummary({ item }) {
38007
38127
  }
38008
38128
  function featuredSummaryDetails(item) {
38009
38129
  switch (item.kind) {
38010
- case "event": return formatFeaturedSummary(deriveEventScheduleSummary(item.event), item.event.venue?.name ?? null);
38130
+ case "event": return formatFeaturedSummary(deriveEventScheduleSummary(item.event), {
38131
+ venue: item.event.venue?.name ?? null,
38132
+ siteTimeZone: item.event.siteTimeZone
38133
+ });
38011
38134
  case "run": {
38012
38135
  const schedule = derivePreviewRunSchedule(item.run.run.sessions);
38013
- return schedule.kind === "scheduled" ? formatFeaturedSummary(schedule.summary, item.run.representative.venue?.name ?? null) : null;
38136
+ return schedule.kind === "scheduled" ? formatFeaturedSummary(schedule.summary, {
38137
+ venue: item.run.representative.venue?.name ?? null,
38138
+ siteTimeZone: item.run.representative.siteTimeZone
38139
+ }) : null;
38014
38140
  }
38015
38141
  default: return assertNever$21(item, "Unhandled offerings preview item");
38016
38142
  }
38017
38143
  }
38018
- function formatFeaturedSummary(summary, venue) {
38144
+ function formatFeaturedSummary(summary, place) {
38019
38145
  switch (summary.kind) {
38020
- case "single-occurrence": return detailsFromOccurrences(summary.occurrence, null, venue, null, null);
38021
- case "multi-day-span": return detailsFromOccurrences(summary.occurrence, summary.occurrence, venue, null, null, true);
38022
- case "fixed-recurring-run": return detailsFromOccurrences(summary.first, summary.last, venue, summary.recurrenceLabel, null);
38023
- case "irregular-multi-session-run": return detailsFromOccurrences(summary.first, summary.last, venue, null, `${summary.sessionCount} dates`);
38146
+ case "single-occurrence": return detailsFromOccurrences({
38147
+ first: summary.occurrence,
38148
+ last: null,
38149
+ place
38150
+ });
38151
+ case "multi-day-span": return detailsFromOccurrences({
38152
+ first: summary.occurrence,
38153
+ last: summary.occurrence,
38154
+ place,
38155
+ spanUsesEndDate: true
38156
+ });
38157
+ case "fixed-recurring-run": return detailsFromOccurrences({
38158
+ first: summary.first,
38159
+ last: summary.last,
38160
+ place,
38161
+ recurrence: summary.recurrenceLabel
38162
+ });
38163
+ case "irregular-multi-session-run": return detailsFromOccurrences({
38164
+ first: summary.first,
38165
+ last: summary.last,
38166
+ place,
38167
+ sessionCount: `${summary.sessionCount} dates`
38168
+ });
38024
38169
  default: return assertNever$21(summary, "Unhandled offerings preview schedule summary");
38025
38170
  }
38026
38171
  }
38027
- function detailsFromOccurrences(first, last, venue, recurrence, sessionCount, spanUsesEndDate = false) {
38028
- const endDateTime = spanUsesEndDate ? first.endsAt : last?.startsAt ?? first.startsAt;
38172
+ function detailsFromOccurrences(input) {
38173
+ const { first, last, place } = input;
38174
+ const endDateTime = input.spanUsesEndDate ? first.endsAt : last?.startsAt ?? first.startsAt;
38175
+ const options = eventDateOptions({
38176
+ timeZone: first.timeZone,
38177
+ siteTimeZone: place.siteTimeZone
38178
+ });
38179
+ const summaryDate = (isoTimestamp, timeZone) => formatSummaryDate(isoTimestamp, {
38180
+ timeZone,
38181
+ locale: options.locale
38182
+ });
38029
38183
  return {
38030
- startDate: formatSummaryDate(first.startsAt, first.timeZone),
38184
+ startDate: summaryDate(first.startsAt, first.timeZone),
38031
38185
  startDateTime: first.startsAt,
38032
- endDate: last ? formatSummaryDate(endDateTime, last.timeZone) : null,
38186
+ endDate: last ? summaryDate(endDateTime, last.timeZone) : null,
38033
38187
  endDateTime,
38034
- timeRange: `${formatTime(first.startsAt, {
38035
- timeZone: first.timeZone,
38036
- locale: "en-GB"
38037
- })} – ${formatTime(first.endsAt, {
38038
- timeZone: first.timeZone,
38039
- locale: "en-GB"
38040
- })}`,
38041
- recurrence,
38042
- sessionCount,
38043
- venue
38044
- };
38045
- }
38046
- function formatSummaryDate(isoTimestamp, timeZone) {
38047
- return new Intl.DateTimeFormat("en-GB", {
38048
- timeZone,
38188
+ timeRange: formatEventTimeRange$1(first, options),
38189
+ recurrence: input.recurrence ?? null,
38190
+ sessionCount: input.sessionCount ?? null,
38191
+ venue: place.venue
38192
+ };
38193
+ }
38194
+ function formatSummaryDate(isoTimestamp, options) {
38195
+ return new Intl.DateTimeFormat(options.locale, {
38196
+ timeZone: options.timeZone,
38049
38197
  weekday: "long",
38050
38198
  day: "numeric",
38051
38199
  month: "long",
@@ -38092,9 +38240,12 @@ function WholeSeriesRunCompactRow({ group, path, now }) {
38092
38240
  path
38093
38241
  });
38094
38242
  const { sessionCount: sessionsCount, firstSession } = schedule;
38095
- const timeZone = firstSession.timeZone;
38096
- const dateRail = formatEventCompactDateRail(firstSession.startsAt, { timeZone });
38097
- const timeRange = `${formatTime(firstSession.startsAt, { timeZone })} - ${formatTime(firstSession.endsAt, { timeZone })}`;
38243
+ const options = eventDateOptions({
38244
+ timeZone: firstSession.timeZone,
38245
+ siteTimeZone: group.representative.siteTimeZone
38246
+ });
38247
+ const dateRail = formatEventCompactDateRail(firstSession.startsAt, options);
38248
+ const timeRange = formatEventTimeRange$1(firstSession, options);
38098
38249
  const price = formatEventPriceDisplay(group.representative.pricing);
38099
38250
  const statusLabel = resolveWholeSeriesBookingPhase(group.run, now).kind === "open" ? null : "Registration closed";
38100
38251
  return /* @__PURE__ */ jsxs("article", {
@@ -38174,9 +38325,12 @@ function WholeSeriesRunFeatureCard({ group, now, path, buttonVariant, buttonText
38174
38325
  path
38175
38326
  });
38176
38327
  const { firstSession } = schedule;
38177
- const timeZone = firstSession.timeZone;
38178
- const formattedDate = formatEventCompactDateRail(firstSession.startsAt, { timeZone }).label;
38179
- const timeRange = `${formatTime(firstSession.startsAt, { timeZone })} - ${formatTime(firstSession.endsAt, { timeZone })}`;
38328
+ const options = eventDateOptions({
38329
+ timeZone: firstSession.timeZone,
38330
+ siteTimeZone: group.representative.siteTimeZone
38331
+ });
38332
+ const formattedDate = formatEventCompactDateRail(firstSession.startsAt, options).label;
38333
+ const timeRange = formatEventTimeRange$1(firstSession, options);
38180
38334
  const price = formatEventPriceDisplay(group.representative.pricing);
38181
38335
  const statusLabel = resolveWholeSeriesBookingPhase(group.run, now).kind === "open" ? null : "Registration closed";
38182
38336
  const description = group.representative.description;
@@ -39092,6 +39246,7 @@ const shopSourceSchema = z$1.object({
39092
39246
  memberships: z$1.array(publicMembershipProductSchema).nullable().optional(),
39093
39247
  products: z$1.array(publicProductSchema).nullable().optional(),
39094
39248
  siteId: z$1.string().optional(),
39249
+ demoEmailSuppressed: z$1.boolean().optional(),
39095
39250
  apiBaseUrl: z$1.string().optional(),
39096
39251
  readAuthority: browserReadAuthoritySchema.optional(),
39097
39252
  stage: previewStageSchema.optional()
@@ -39211,7 +39366,8 @@ const checkoutDisplaySchema = z$1.object({
39211
39366
  const passesMembershipsHydrationSchema = z$1.object({
39212
39367
  memberships: z$1.array(publicMembershipProductSchema),
39213
39368
  passPurchaseMode: z$1.enum(["add_to_cart", "buy_now"]),
39214
- buttonVariant: blockButtonRoleSchema
39369
+ buttonVariant: blockButtonRoleSchema,
39370
+ demoEmailSuppressed: z$1.boolean().optional()
39215
39371
  });
39216
39372
  const productListHydrationSchema = z$1.object({
39217
39373
  products: z$1.array(publicProductSchema),
@@ -39233,7 +39389,8 @@ const cartHydrationSchema = z$1.object({
39233
39389
  });
39234
39390
  const checkoutHydrationSchema = z$1.object({
39235
39391
  emptyStateText: z$1.string(),
39236
- submitButtonText: z$1.string()
39392
+ submitButtonText: z$1.string(),
39393
+ demoEmailSuppressed: z$1.boolean().optional()
39237
39394
  });
39238
39395
  const passesMembershipsRenderSchema = z$1.object({
39239
39396
  display: passesMembershipsDisplaySchema,
@@ -39292,7 +39449,8 @@ const shopBlockRuntime = defineProgressiveBlockRuntime({
39292
39449
  hydration: {
39293
39450
  memberships: source.showMemberships === false ? [] : source.memberships ?? [],
39294
39451
  passPurchaseMode,
39295
- buttonVariant: source.buttonVariant ?? "primary"
39452
+ buttonVariant: source.buttonVariant ?? "primary",
39453
+ demoEmailSuppressed: source.demoEmailSuppressed
39296
39454
  }
39297
39455
  };
39298
39456
  }
@@ -39385,7 +39543,8 @@ const checkoutBlockRuntime = defineClientOwnedBlockRuntime({
39385
39543
  }),
39386
39544
  hydration: {
39387
39545
  emptyStateText: source.emptyStateText ?? "Add something to your cart to continue.",
39388
- submitButtonText: source.submitButtonText ?? "Checkout"
39546
+ submitButtonText: source.submitButtonText ?? "Checkout",
39547
+ demoEmailSuppressed: source.demoEmailSuppressed
39389
39548
  }
39390
39549
  })
39391
39550
  });
@@ -39626,6 +39785,10 @@ const checkoutBlockDefinition = {
39626
39785
  baseClass: "",
39627
39786
  spacing: "spacious",
39628
39787
  children: sectionContainer([checkout(withApiBindings({
39788
+ demoEmailSuppressed: { $bind: {
39789
+ from: "$root.demoEmailSuppressed",
39790
+ fallback: false
39791
+ } },
39629
39792
  readAuthority: { $bind: { from: "$root.readAuthority" } },
39630
39793
  mode: "checkout",
39631
39794
  heading: { $bind: {
@@ -40034,6 +40197,7 @@ const EVENT_REGISTRATION_SHELL_STEP_LABELS = [
40034
40197
  ];
40035
40198
  const eventRegistrationPublicEventSchema = z$1.preprocess(normalizeEventRegistrationEventInput, publicEventSchema);
40036
40199
  const eventRegistrationHydrationSchemaShape = {
40200
+ demoEmailSuppressed: z$1.boolean().optional(),
40037
40201
  occurrenceContext: occurrenceContextSchema.optional(),
40038
40202
  subject: eventRegistrationPageSurfaceSubjectSchema.nullable().optional(),
40039
40203
  maxTickets: z$1.string().optional(),
@@ -40214,6 +40378,7 @@ const eventRegistrationBlockRuntime = defineClientOwnedBlockRuntime({
40214
40378
  ...eventSource,
40215
40379
  events: [...scopedSourceEvents]
40216
40380
  } : eventSource,
40381
+ demoEmailSuppressed: source.demoEmailSuppressed,
40217
40382
  maxTickets: source.maxTickets ?? void 0,
40218
40383
  showVenue: source.showVenue,
40219
40384
  showCapacity: source.showCapacity,
@@ -40357,8 +40522,8 @@ const eventRegistrationBlockDefinition = {
40357
40522
  description: "Message shown after successful registration",
40358
40523
  required: false,
40359
40524
  multiline: true,
40360
- defaultValue: "Thank you for registering! Check your email for confirmation details.",
40361
- maxLength: 500
40525
+ maxLength: 500,
40526
+ ui: { placeholder: "Thank you for registering! Check your email for confirmation details." }
40362
40527
  },
40363
40528
  {
40364
40529
  id: "buttonText",
@@ -40379,6 +40544,10 @@ const eventRegistrationBlockDefinition = {
40379
40544
  text({ as: "h2" }, bind("content.heading"), when("content.heading")),
40380
40545
  richText({ className: "rb-prose rb-max-w-none" }, bind("content.description"), when("content.description")),
40381
40546
  eventRegistration(withApiBindings({
40547
+ demoEmailSuppressed: { $bind: {
40548
+ from: "$root.demoEmailSuppressed",
40549
+ fallback: false
40550
+ } },
40382
40551
  readAuthority: { $bind: { from: "$root.readAuthority" } },
40383
40552
  occurrenceContext: { $bind: { from: "$root.occurrenceContext" } },
40384
40553
  subject: { $bind: { from: "$root.subject" } },
@@ -43419,6 +43588,10 @@ const shopBlockDefinition = {
43419
43588
  spacing: "spacious",
43420
43589
  children: sectionContainer([shop(withApiBindings({
43421
43590
  readAuthority: { $bind: { from: "$root.readAuthority" } },
43591
+ demoEmailSuppressed: { $bind: {
43592
+ from: "$root.demoEmailSuppressed",
43593
+ fallback: false
43594
+ } },
43422
43595
  mode: "passes-memberships",
43423
43596
  showPasses: { $bind: {
43424
43597
  from: "content.showPasses",
@@ -43909,11 +44082,12 @@ function CartSSR({ blockId, siteId, apiBaseUrl, stage, children, ...rest }) {
43909
44082
  }
43910
44083
  //#endregion
43911
44084
  //#region ../blocks/src/system/runtime/nodes/checkout.server.tsx
43912
- function CheckoutSSR({ blockId, siteId, apiBaseUrl, stage, children, ...rest }) {
44085
+ function CheckoutSSR({ blockId, siteId, apiBaseUrl, stage, demoEmailSuppressed, children, ...rest }) {
43913
44086
  const islandProps = buildCheckoutInteractiveIslandProps({
43914
44087
  siteId,
43915
44088
  apiBaseUrl,
43916
44089
  stage,
44090
+ demoEmailSuppressed,
43917
44091
  ...rest
43918
44092
  });
43919
44093
  return /* @__PURE__ */ jsxs("div", {
@@ -50109,6 +50283,7 @@ function buildPageRendererRootRuntime(dataContext) {
50109
50283
  const { siteId = null, siteName, pageId = null, pathname = null, bookingTimeZone, previewStage = "published", apiBaseUrl = null, portalToken = null, readAuthority, bookingOfferingPresets = [], appointmentServicePathPrefix = null, mailingList = { tag: "not_configured" }, eventRegistrationOverlayEnabled = false, loaderFailures = {} } = dataContext ?? {};
50110
50284
  return {
50111
50285
  siteId,
50286
+ demoEmailSuppressed: resolveDemoEmailSuppression(dataContext),
50112
50287
  siteName,
50113
50288
  pageId,
50114
50289
  pathname,
@@ -50124,6 +50299,9 @@ function buildPageRendererRootRuntime(dataContext) {
50124
50299
  loaderFailures
50125
50300
  };
50126
50301
  }
50302
+ function resolveDemoEmailSuppression(dataContext) {
50303
+ return dataContext?.demoEmailSuppressed === true;
50304
+ }
50127
50305
  //#endregion
50128
50306
  //#region ../blocks/src/pageRenderAudience.tsx
50129
50307
  /**
@@ -54671,6 +54849,10 @@ const bookingDescription = richText({}, bind("content.description"), when("conte
54671
54849
  * that hydration never rewrites.
54672
54850
  */
54673
54851
  const bookingWizard = bookingForm(withApiBindings({
54852
+ demoEmailSuppressed: { $bind: {
54853
+ from: "$root.demoEmailSuppressed",
54854
+ fallback: false
54855
+ } },
54674
54856
  portalToken: { $bind: {
54675
54857
  from: "$root.portalToken",
54676
54858
  fallback: null
@@ -59847,15 +60029,17 @@ function planNewsletterBlockSubmission(placement) {
59847
60029
  sourceRef
59848
60030
  } : { tag: "unavailable" };
59849
60031
  }
59850
- if (placement.publishedPlacement && "kind" in placement.publishedPlacement) return { tag: "unpublished-settings" };
59851
- if (placement.publishedPlacement) return planNewsletterPreviewSubmission({
59852
- blockId: placement.blockId,
59853
- publishedContentId: placement.publishedPlacement.id,
59854
- renderedContent: placement.renderedContent,
59855
- publishedContent: placement.publishedPlacement.content
59856
- });
59857
- if (placement.stage === "preview") return { tag: "unpublished-form" };
59858
- return { tag: "unavailable" };
60032
+ const published = placement.publishedPlacement;
60033
+ if (published === null) return placement.stage === "preview" ? { tag: "unpublished-form" } : { tag: "unavailable" };
60034
+ switch (published.kind) {
60035
+ case "incomplete": return { tag: "unpublished-settings" };
60036
+ case "published": return planNewsletterPreviewSubmission({
60037
+ blockId: placement.blockId,
60038
+ publishedContentId: published.id,
60039
+ renderedContent: placement.renderedContent,
60040
+ publishedContent: published.content
60041
+ });
60042
+ }
59859
60043
  }
59860
60044
  /** Decide whether the visible draft can safely cite the published placement. */
59861
60045
  function planNewsletterPreviewSubmission(placement) {
@@ -60102,19 +60286,6 @@ function createBlockErrorBoundary() {
60102
60286
  const BlockErrorBoundary = createBlockErrorBoundary();
60103
60287
  //#endregion
60104
60288
  //#region ../blocks/src/pageRenderAdmission.ts
60105
- /** Pair a published version with the content it authorises at the render boundary. */
60106
- function readPublishedBlockPlacement(id, content) {
60107
- if (id == null && content == null) return null;
60108
- if (id == null || content == null) return {
60109
- kind: "incomplete",
60110
- id: id ?? null,
60111
- content: content ?? null
60112
- };
60113
- return {
60114
- id,
60115
- content
60116
- };
60117
- }
60118
60289
  function toPresentationPage(page) {
60119
60290
  if (!page) return null;
60120
60291
  return {
@@ -74249,985 +74420,228 @@ function toBlocksImageResolveContextInput(context) {
74249
74420
  mediaAssets: toBlocksMediaAssets(context.mediaAssets)
74250
74421
  };
74251
74422
  }
74252
- function isOverrideOnlyPageRenderer(props) {
74253
- return props.rendering?.kind === "overrides-only";
74254
- }
74255
- function normalizeSdkCustomBlocks(customBlocks) {
74256
- if (!customBlocks) return void 0;
74257
- return customBlocks.map((block) => {
74258
- return {
74259
- ...block,
74260
- fields: parseFieldDefinitions(block.fields)
74261
- };
74262
- });
74263
- }
74264
- function toBlocksBlockOverrides(overrides) {
74265
- if (!overrides) return void 0;
74266
- const result = {};
74267
- for (const [key, OverrideComponent] of Object.entries(overrides)) result[key] = function BlocksOverrideAdapter(props) {
74268
- const sdkOverride = OverrideComponent;
74269
- return React$1.createElement(sdkOverride, {
74270
- ...props,
74271
- entrySubrouteContext: props.entrySubrouteContext
74272
- });
74273
- };
74274
- return result;
74275
- }
74276
- function toBlocksPageRendererDataContext(dataContext) {
74277
- return {
74278
- ...dataContext,
74279
- mediaAssets: toBlocksMediaAssets(dataContext.mediaAssets),
74280
- imageResolveContext: toBlocksImageResolveContextInput(dataContext.imageResolveContext)
74281
- };
74282
- }
74283
- function toBlocksCommonProps(props) {
74284
- return {
74285
- page: props.page,
74286
- runtimeJoins: props.runtimeJoins,
74287
- dataContext: toBlocksPageRendererDataContext(props.dataContext),
74288
- routeMap: props.routeMap,
74289
- wrapBlock: props.wrapBlock,
74290
- registry: props.registry,
74291
- blockOverrides: toBlocksBlockOverrides(props.blockOverrides),
74292
- sdkConfig: props.sdkConfig ? { customBlocks: normalizeSdkCustomBlocks(props.sdkConfig.customBlocks) } : props.sdkConfig,
74293
- customBlocks: normalizeSdkCustomBlocks(props.customBlocks)
74294
- };
74295
- }
74296
- function PageRenderer(props) {
74297
- const commonBlocksProps = toBlocksCommonProps(props);
74298
- const blocksProps = isOverrideOnlyPageRenderer(props) ? {
74299
- ...commonBlocksProps,
74300
- rendering: { kind: "overrides-only" },
74301
- blockOverrides: toBlocksBlockOverrides(props.blockOverrides) ?? {}
74302
- } : {
74303
- ...commonBlocksProps,
74304
- theme: parseBlocksTheme(props.theme),
74305
- themeTokens: props.themeTokens
74306
- };
74307
- return React$1.createElement(PageRenderer$1, blocksProps);
74308
- }
74309
74423
  //#endregion
74310
- //#region src/rendering/blocks-theme-scope.ts
74311
- function ThemeScope(props) {
74312
- const { theme, children, ...rest } = props;
74313
- const blocksTheme = parseBlocksTheme(theme);
74314
- return React$1.createElement(ThemeScope$1, {
74315
- ...rest,
74316
- theme: blocksTheme,
74317
- children: children ?? null
74318
- });
74319
- }
74424
+ //#region ../blocks/src/structure/schema.ts
74425
+ const BlockKind = z.string();
74426
+ const blockSchema = z.object({
74427
+ id: z.string().nullable(),
74428
+ kind: BlockKind,
74429
+ purpose: z.string().min(1),
74430
+ content: z.record(z.string(), z.unknown()).optional(),
74431
+ draftContent: z.record(z.string(), z.unknown()).nullable().optional(),
74432
+ bindings: z.record(z.string(), z.unknown()).optional()
74433
+ }).passthrough();
74434
+ const pagePath = z.string().regex(/^\/[\S]*$/, "path must start with \"/\" and contain no spaces");
74435
+ z.object({
74436
+ name: z.string().min(1),
74437
+ path: pagePath,
74438
+ purpose: z.string().min(1),
74439
+ blocks: z.array(blockSchema).min(1)
74440
+ });
74320
74441
  //#endregion
74321
- //#region src/rendering/themeRuntime.tsx
74322
- const defaultLayoutThemeRuntime = { kind: "cms-theme" };
74323
- const defaultSdkChromeThemeRuntime = { kind: "responsive-only" };
74324
- const defaultPageThemeRuntime = { kind: "none" };
74325
- function planLayoutThemeRuntime(input) {
74326
- const requested = input.themeRuntime ?? defaultLayoutThemeRuntime;
74327
- if (requested.kind === "none" && input.usesSdkChrome) {
74328
- if (process.env.NODE_ENV !== "production") console.warn("[sdk] Layout themeRuntime { kind: \"none\" } is not compatible with SDK-managed header/footer chrome; using responsive-only runtime instead.");
74329
- return defaultSdkChromeThemeRuntime;
74330
- }
74331
- return requested;
74332
- }
74333
- function renderWithSdkThemeRuntime({ themeRuntime, theme, children }) {
74334
- switch (themeRuntime.kind) {
74335
- case "cms-theme": return /* @__PURE__ */ jsx(ThemeScope, {
74336
- theme,
74337
- responsiveMode: themeRuntime.responsiveMode,
74338
- children
74339
- });
74340
- case "responsive-only": return /* @__PURE__ */ jsx(ResponsiveScope, {
74341
- responsiveMode: themeRuntime.responsiveMode,
74342
- children
74343
- });
74344
- case "none": return /* @__PURE__ */ jsx(Fragment, { children });
74345
- default: return assertNever$21(themeRuntime);
74442
+ //#region ../../node_modules/.pnpm/@vibrant+image@4.0.4/node_modules/@vibrant/image/dist/esm/histogram.js
74443
+ var Histogram = class {
74444
+ constructor(pixels, opts) {
74445
+ this.pixels = pixels;
74446
+ this.opts = opts;
74447
+ const { sigBits } = opts;
74448
+ const getColorIndex = (r2, g2, b2) => (r2 << 2 * sigBits) + (g2 << sigBits) + b2;
74449
+ this.getColorIndex = getColorIndex;
74450
+ const rshift = 8 - sigBits;
74451
+ const hn = 1 << 3 * sigBits;
74452
+ const hist = new Uint32Array(hn);
74453
+ let rmax;
74454
+ let rmin;
74455
+ let gmax;
74456
+ let gmin;
74457
+ let bmax;
74458
+ let bmin;
74459
+ let r;
74460
+ let g;
74461
+ let b;
74462
+ let a;
74463
+ rmax = gmax = bmax = 0;
74464
+ rmin = gmin = bmin = Number.MAX_VALUE;
74465
+ const n = pixels.length / 4;
74466
+ let i = 0;
74467
+ while (i < n) {
74468
+ const offset = i * 4;
74469
+ i++;
74470
+ r = pixels[offset + 0];
74471
+ g = pixels[offset + 1];
74472
+ b = pixels[offset + 2];
74473
+ a = pixels[offset + 3];
74474
+ if (a === 0) continue;
74475
+ r = r >> rshift;
74476
+ g = g >> rshift;
74477
+ b = b >> rshift;
74478
+ const index = getColorIndex(r, g, b);
74479
+ if (hist[index] === void 0) hist[index] = 0;
74480
+ hist[index] += 1;
74481
+ if (r > rmax) rmax = r;
74482
+ if (r < rmin) rmin = r;
74483
+ if (g > gmax) gmax = g;
74484
+ if (g < gmin) gmin = g;
74485
+ if (b > bmax) bmax = b;
74486
+ if (b < bmin) bmin = b;
74487
+ }
74488
+ this._colorCount = hist.reduce((total, c) => c > 0 ? total + 1 : total, 0);
74489
+ this.hist = hist;
74490
+ this.rmax = rmax;
74491
+ this.rmin = rmin;
74492
+ this.gmax = gmax;
74493
+ this.gmin = gmin;
74494
+ this.bmax = bmax;
74495
+ this.bmin = bmin;
74346
74496
  }
74347
- }
74348
- function renderWithOverrideOnlyRuntime({ runtime, children }) {
74349
- switch (runtime.kind) {
74350
- case "responsive-only": return /* @__PURE__ */ jsx(ResponsiveScope, {
74351
- responsiveMode: runtime.responsiveMode,
74352
- children
74353
- });
74354
- case "none": return /* @__PURE__ */ jsx(Fragment, { children });
74355
- default: return assertNever$21(runtime);
74497
+ get colorCount() {
74498
+ return this._colorCount;
74356
74499
  }
74357
- }
74500
+ };
74358
74501
  //#endregion
74359
- //#region src/rendering/components/pageShared.tsx
74360
- function isOverrideOnlyPage(props) {
74361
- return props.rendering?.kind === "overrides-only";
74362
- }
74363
- function resolvePageThemeTokens(props) {
74364
- const baseTokens = props.themeTokens ?? buildThemeRuntime(props.theme).tokens;
74365
- return props.sdkConfig?.theme?.palette ? {
74366
- ...baseTokens,
74367
- palette: {
74368
- ...baseTokens.palette,
74369
- ...props.sdkConfig.theme.palette
74502
+ //#region ../../node_modules/.pnpm/@vibrant+image@4.0.4/node_modules/@vibrant/image/dist/esm/index.js
74503
+ var ImageBase = class {
74504
+ scaleDown(opts) {
74505
+ const width = this.getWidth();
74506
+ const height = this.getHeight();
74507
+ let ratio = 1;
74508
+ if (opts.maxDimension > 0) {
74509
+ const maxSide = Math.max(width, height);
74510
+ if (maxSide > opts.maxDimension) ratio = opts.maxDimension / maxSide;
74511
+ } else ratio = 1 / opts.quality;
74512
+ if (ratio < 1) this.resize(width * ratio, height * ratio, ratio);
74513
+ }
74514
+ };
74515
+ function applyFilters(imageData, filters) {
74516
+ if (filters.length > 0) {
74517
+ const pixels = imageData.data;
74518
+ const n = pixels.length / 4;
74519
+ let offset;
74520
+ let r;
74521
+ let g;
74522
+ let b;
74523
+ let a;
74524
+ for (let i = 0; i < n; i++) {
74525
+ offset = i * 4;
74526
+ r = pixels[offset + 0];
74527
+ g = pixels[offset + 1];
74528
+ b = pixels[offset + 2];
74529
+ a = pixels[offset + 3];
74530
+ for (let j = 0; j < filters.length; j++) if (!filters[j]?.(r, g, b, a)) {
74531
+ pixels[offset + 3] = 0;
74532
+ break;
74533
+ }
74370
74534
  }
74371
- } : baseTokens;
74372
- }
74373
- function toPageHydrationBootstrapConfig(props) {
74374
- return {
74375
- siteId: props.siteId,
74376
- supabaseUrl: props.supabaseUrl,
74377
- mediaAssets: props.mediaAssets
74378
- };
74379
- }
74380
- function resolveSdkBookingTimeZone(timeZone) {
74381
- return timeZone ?? "UTC";
74535
+ }
74536
+ return imageData;
74382
74537
  }
74383
- function buildPageRouteRenderContext(dataContext) {
74384
- return {
74385
- ...buildPageIdentityRenderContext(dataContext),
74386
- occurrenceContext: dataContext.occurrenceContext ?? null,
74387
- entrySubrouteContext: dataContext.entrySubrouteContext ?? null,
74388
- contentEntry: dataContext.contentEntry ?? null,
74389
- pageSurface: dataContext.pageSurface ?? null,
74390
- subject: dataContext.subject ?? null,
74391
- editableRouteMetadataFieldIds: dataContext.editableRouteMetadataFieldIds ?? null,
74392
- previewStage: dataContext.previewStage
74393
- };
74538
+ //#endregion
74539
+ //#region ../../node_modules/.pnpm/@vibrant+image-browser@4.0.4/node_modules/@vibrant/image-browser/dist/esm/index.js
74540
+ function isRelativeUrl(url) {
74541
+ const u = new URL(url, location.href);
74542
+ return u.protocol === location.protocol && u.host === location.host && u.port === location.port;
74394
74543
  }
74395
- function buildPageIdentityRenderContext(dataContext) {
74396
- return {
74397
- siteName: dataContext.siteName,
74398
- pathname: dataContext.pathname
74399
- };
74544
+ function isSameOrigin(a, b) {
74545
+ const ua = new URL(a);
74546
+ const ub = new URL(b);
74547
+ return ua.protocol === ub.protocol && ua.hostname === ub.hostname && ua.port === ub.port;
74400
74548
  }
74401
- function PageContent(props) {
74402
- const { page, runtimeJoins, siteId, resolvedData, bookingOfferingPresets, mailingList, bookingTimeZone, routeMap, pagesByIdentifier, entriesByIdentifier, wrapBlock, registry, blockOverrides, sdkConfig, customBlocks, supabaseUrl, mediaAssets, apiBaseUrl, portalToken, previewToken, readAuthority, dataContext } = props;
74403
- const rendererCommonProps = {
74404
- page,
74405
- runtimeJoins,
74406
- dataContext: {
74407
- siteId,
74408
- ...buildPageRouteRenderContext(dataContext),
74409
- apiBaseUrl,
74410
- portalToken,
74411
- previewToken,
74412
- readAuthority: readAuthority ?? dataContext.readAuthority,
74413
- resolvedData,
74414
- bookingOfferingPresets: bookingOfferingPresets ?? [],
74415
- mailingList: mailingList ?? dataContext.mailingList,
74416
- bookingTimeZone: resolveSdkBookingTimeZone(bookingTimeZone),
74417
- routes: routeMap,
74418
- pagesByIdentifier,
74419
- entriesByIdentifier,
74420
- supabaseUrl,
74421
- mediaAssets,
74422
- imageResolveContext: {
74423
- siteId,
74424
- supabaseUrl,
74425
- mediaAssets
74549
+ var BrowserImage = class extends ImageBase {
74550
+ _getCanvas() {
74551
+ if (!this._canvas) throw new Error("Canvas is not initialized");
74552
+ return this._canvas;
74553
+ }
74554
+ _getContext() {
74555
+ if (!this._context) throw new Error("Context is not initialized");
74556
+ return this._context;
74557
+ }
74558
+ _getWidth() {
74559
+ if (!this._width) throw new Error("Width is not initialized");
74560
+ return this._width;
74561
+ }
74562
+ _getHeight() {
74563
+ if (!this._height) throw new Error("Height is not initialized");
74564
+ return this._height;
74565
+ }
74566
+ _initCanvas() {
74567
+ const img = this.image;
74568
+ if (!img) throw new Error("Image is not initialized");
74569
+ const canvas = this._canvas = document.createElement("canvas");
74570
+ const context = canvas.getContext("2d");
74571
+ if (!context) throw new ReferenceError("Failed to create canvas context");
74572
+ this._context = context;
74573
+ canvas.className = "@vibrant/canvas";
74574
+ canvas.style.display = "none";
74575
+ this._width = canvas.width = img.width;
74576
+ this._height = canvas.height = img.height;
74577
+ context.drawImage(img, 0, 0);
74578
+ document.body.appendChild(canvas);
74579
+ }
74580
+ load(image) {
74581
+ let img;
74582
+ let src;
74583
+ if (typeof image === "string") {
74584
+ img = document.createElement("img");
74585
+ src = image;
74586
+ if (!isRelativeUrl(src) && !isSameOrigin(window.location.href, src)) img.crossOrigin = "anonymous";
74587
+ img.src = src;
74588
+ } else if (image instanceof HTMLImageElement) {
74589
+ img = image;
74590
+ src = image.src;
74591
+ } else return Promise.reject(/* @__PURE__ */ new Error(`Cannot load buffer as an image in browser`));
74592
+ this.image = img;
74593
+ return new Promise((resolve, reject) => {
74594
+ const onImageLoad = () => {
74595
+ this._initCanvas();
74596
+ resolve(this);
74597
+ };
74598
+ if (img.complete) onImageLoad();
74599
+ else {
74600
+ img.onload = onImageLoad;
74601
+ img.onerror = (_e) => reject(/* @__PURE__ */ new Error(`Fail to load image: ${src}`));
74426
74602
  }
74427
- },
74428
- routeMap,
74429
- wrapBlock,
74430
- registry,
74431
- sdkConfig: sdkConfig ? { customBlocks: sdkConfig.customBlocks } : null,
74432
- customBlocks
74433
- };
74434
- const content = isOverrideOnlyPage(props) ? /* @__PURE__ */ jsx(PageRenderer, {
74435
- ...rendererCommonProps,
74436
- rendering: { kind: "overrides-only" },
74437
- blockOverrides: props.blockOverrides
74438
- }) : /* @__PURE__ */ jsx(PageRenderer, {
74439
- ...rendererCommonProps,
74440
- theme: props.theme,
74441
- themeTokens: resolvePageThemeTokens(props),
74442
- blockOverrides
74443
- });
74444
- return isOverrideOnlyPage(props) ? renderWithOverrideOnlyRuntime({
74445
- runtime: props.rendering.runtime,
74446
- children: content
74447
- }) : renderWithSdkThemeRuntime({
74448
- themeRuntime: props.themeRuntime ?? defaultPageThemeRuntime,
74449
- theme: props.theme,
74450
- children: content
74451
- });
74452
- }
74453
- //#endregion
74454
- //#region src/rendering/components/Page.tsx
74455
- const HydratorWithContextProps$1 = BlocksIslandsHydrator;
74456
- /**
74457
- * Default renderer for Riverbank CMS pages.
74458
- *
74459
- * This component expects all data to be provided via props and automatically
74460
- * mounts the CMS island hydration bootstrap.
74461
- * For data fetching, use:
74462
- * - Server-side: `await loadPage({ client, siteId, path })`
74463
- * - Client-side: `usePage({ client, siteId, path })`
74464
- *
74465
- * @example Server-side (Next.js App Router)
74466
- * ```tsx
74467
- * import { createRiverbankClient } from '@riverbankcms/sdk';
74468
- * import { loadPage, Page } from '@riverbankcms/sdk/rendering';
74469
- *
74470
- * const client = createRiverbankClient({ apiKey, baseUrl });
74471
- *
74472
- * export default async function PageRoute({ params }) {
74473
- * const pageData = await loadPage({
74474
- * client,
74475
- * siteId: 'site-id',
74476
- * path: `/${params.slug}`,
74477
- * });
74478
- *
74479
- * return <Page {...pageData} />;
74480
- * }
74481
- * ```
74482
- *
74483
- * @example Client-side
74484
- * ```tsx
74485
- * import { createRiverbankClient } from '@riverbankcms/sdk';
74486
- * import { usePage, Page } from '@riverbankcms/sdk/rendering';
74487
- *
74488
- * const client = createRiverbankClient({ apiKey, baseUrl });
74489
- *
74490
- * function MyPage({ path }) {
74491
- * const pageData = usePage({ client, siteId: 'site-id', path });
74492
- *
74493
- * if (pageData.loading) return <LoadingState />;
74494
- * if (pageData.error) return <ErrorState error={pageData.error} />;
74495
- * if (!pageData.page) return <NotFound />;
74496
- *
74497
- * return <Page {...pageData} />;
74498
- * }
74499
- * ```
74500
- */
74501
- function Page(props) {
74502
- return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(HydratorWithContextProps$1, { ...toPageHydrationBootstrapConfig(props) }), /* @__PURE__ */ jsx(PageContent, { ...props })] });
74503
- }
74504
- //#endregion
74505
- //#region src/env.ts
74506
- /**
74507
- * Error thrown when required environment variables are missing
74508
- */
74509
- var RiverbankEnvError = class extends Error {
74510
- constructor(message, missingVars) {
74511
- super(message);
74512
- this.missingVars = missingVars;
74513
- this.name = "RiverbankEnvError";
74514
- }
74515
- };
74516
- /**
74517
- * Get the environment variable prefix based on target
74518
- */
74519
- function getEnvPrefix(target) {
74520
- return target === "remote" ? "RIVERBANK_REMOTE" : "RIVERBANK_LOCAL";
74521
- }
74522
- /**
74523
- * Detect the environment target from RIVERBANK_ENV
74524
- */
74525
- function detectTarget() {
74526
- const env = process.env.RIVERBANK_ENV?.toLowerCase();
74527
- if (env === "remote" || env === "production" || env === "prod") return "remote";
74528
- return "local";
74529
- }
74530
- /**
74531
- * Detect if preview mode is enabled.
74532
- * Uses RIVERBANK_PREVIEW_MODE first, then falls back to RIVERBANK_PREVIEW for backward compat.
74533
- */
74534
- function detectPreviewMode() {
74535
- const previewMode = process.env.RIVERBANK_PREVIEW_MODE;
74536
- if (previewMode !== void 0 && previewMode !== "") return previewMode === "true";
74537
- const previewLegacy = process.env.RIVERBANK_PREVIEW;
74538
- if (previewLegacy !== void 0 && previewLegacy !== "") return previewLegacy === "true";
74539
- return process.env.VERCEL_ENV === "preview";
74540
- }
74541
- /**
74542
- * Validate that an API key matches the expected format for its type
74543
- */
74544
- function validateKeyType(key, expectedType) {
74545
- const isPreviewKey = key.startsWith("bld_preview_sk_");
74546
- const isContentKey = key.startsWith("bld_live_sk_");
74547
- if (expectedType === "preview" && !isPreviewKey) {
74548
- if (isContentKey) throw new RiverbankEnvError("Preview mode is enabled (RIVERBANK_PREVIEW_MODE=true) but a content key was provided. Preview mode requires a preview API key (bld_preview_sk_...) to access draft content. Either:\n 1. Set RIVERBANK_*_PREVIEW_API_KEY with your preview key, or\n 2. Set RIVERBANK_PREVIEW_MODE=false to fetch published content instead.", []);
74549
- throw new RiverbankEnvError(`Invalid API key format for preview mode. Expected key starting with bld_preview_sk_`, []);
74550
- }
74551
- if (expectedType === "content" && !isContentKey) {
74552
- if (isPreviewKey) {
74553
- console.debug("[getRiverbankEnv] Using preview key for published content. Consider using a content key (bld_live_sk_...) for production.");
74554
- return;
74555
- }
74556
- throw new RiverbankEnvError(`Invalid API key format for content access. Expected key starting with bld_live_sk_ or bld_preview_sk_`, []);
74557
- }
74558
- }
74559
- /**
74560
- * Get runtime environment configuration with automatic API key selection.
74561
- *
74562
- * This helper reads environment variables and automatically selects the correct
74563
- * API key based on the current environment and preview mode:
74564
- *
74565
- * - When `RIVERBANK_PREVIEW_MODE=true`: Uses preview API key (bld_preview_sk_...)
74566
- * - When `RIVERBANK_PREVIEW_MODE=false` (default): Uses content API key (bld_live_sk_...)
74567
- *
74568
- * Environment variable patterns:
74569
- * - `RIVERBANK_ENV`: 'local' (default) or 'remote'
74570
- * - `RIVERBANK_PREVIEW_MODE`: 'true' or 'false' (default)
74571
- * - `RIVERBANK_{LOCAL|REMOTE}_SITE_ID`: Site ID
74572
- * - `RIVERBANK_{LOCAL|REMOTE}_DASHBOARD_URL`: Dashboard URL
74573
- * - `RIVERBANK_{LOCAL|REMOTE}_API_KEY`: Content/live API key
74574
- * - `RIVERBANK_{LOCAL|REMOTE}_PREVIEW_API_KEY`: Preview API key
74575
- *
74576
- * @returns Environment configuration with auto-selected API key
74577
- * @throws {RiverbankEnvError} If required environment variables are missing
74578
- *
74579
- * @example
74580
- * ```ts
74581
- * // lib/builder-client.ts
74582
- * import { getRiverbankEnv } from '@riverbankcms/sdk/env';
74583
- * import { createRiverbankClient } from '@riverbankcms/sdk';
74584
- *
74585
- * const env = getRiverbankEnv();
74586
- *
74587
- * export const client = createRiverbankClient({
74588
- * apiKey: env.apiKey,
74589
- * baseUrl: env.baseUrl,
74590
- * });
74591
- *
74592
- * export const siteId = env.siteId;
74593
- * ```
74594
- */
74595
- function getRiverbankEnv() {
74596
- const target = detectTarget();
74597
- const previewMode = detectPreviewMode();
74598
- const prefix = getEnvPrefix(target);
74599
- const siteId = process.env[`${prefix}_SITE_ID`];
74600
- const dashboardUrl = process.env[`${prefix}_DASHBOARD_URL`];
74601
- const contentKey = process.env[`${prefix}_API_KEY`];
74602
- const previewKey = process.env[`${prefix}_PREVIEW_API_KEY`];
74603
- const missingVars = [];
74604
- if (!siteId) missingVars.push(`${prefix}_SITE_ID`);
74605
- if (!dashboardUrl) missingVars.push(`${prefix}_DASHBOARD_URL`);
74606
- let apiKey;
74607
- let keyType;
74608
- if (previewMode) {
74609
- apiKey = previewKey;
74610
- keyType = "preview";
74611
- if (!apiKey) missingVars.push(`${prefix}_PREVIEW_API_KEY`);
74612
- } else {
74613
- apiKey = contentKey || previewKey;
74614
- keyType = contentKey ? "content" : "preview";
74615
- if (!apiKey) missingVars.push(`${prefix}_API_KEY`);
74616
- }
74617
- if (missingVars.length > 0) throw new RiverbankEnvError(`Missing required environment variables for Riverbank SDK:\n` + missingVars.map((v) => ` - ${v}`).join("\n") + `\n\nCurrent settings: RIVERBANK_ENV=${process.env.RIVERBANK_ENV || "local"}, RIVERBANK_PREVIEW_MODE=${process.env.RIVERBANK_PREVIEW_MODE || "false"}`, missingVars);
74618
- if (!apiKey || !dashboardUrl || !siteId) throw new RiverbankEnvError("Required environment variables missing", missingVars);
74619
- validateKeyType(apiKey, keyType);
74620
- let baseUrl = dashboardUrl;
74621
- if (!baseUrl.endsWith("/api")) baseUrl = baseUrl.replace(/\/$/, "") + "/api";
74622
- return {
74623
- target,
74624
- previewMode,
74625
- siteId,
74626
- baseUrl,
74627
- apiKey,
74628
- keyType
74629
- };
74630
- }
74631
- /**
74632
- * Get the fixed main navigation menu object.
74633
- * Returns null when the runtime payload is incomplete.
74634
- *
74635
- * @example
74636
- * ```ts
74637
- * const menu = getPrimaryNavigation(siteData.navigation);
74638
- * console.log(menu?.location); // "main"
74639
- * ```
74640
- */
74641
- function getPrimaryNavigation(navigation) {
74642
- if (!navigation || navigation.length === 0) return null;
74643
- return navigation.find((menu) => menu.location === "main") ?? null;
74644
- }
74645
- function getFooterNavigationByRole(navigation, role) {
74646
- if (!navigation || navigation.length === 0) return null;
74647
- const canonicalLocation = role === "main" ? "footer" : "legal";
74648
- return navigation.find((menu) => menu.location === canonicalLocation) ?? null;
74649
- }
74650
- /**
74651
- * Resolve alt text with fallback.
74652
- * Returns the provided alt if non-empty, otherwise falls back to the provided fallback or 'Site logo'.
74653
- * @internal
74654
- */
74655
- function resolveAltText(alt, fallback) {
74656
- return alt && alt.trim().length > 0 ? alt : fallback ?? "Site logo";
74657
- }
74658
- function readNavigationItemPayload(item) {
74659
- return item.url ?? null;
74660
- }
74661
- function isPortalEnabled(options) {
74662
- return options?.portalEnabled === true;
74663
- }
74664
- function isCommerceEnabled(options) {
74665
- return options?.commerceEnabled === true;
74666
- }
74667
- function resolvePortalHref(link) {
74668
- return link.path?.trim() || "/portal";
74669
- }
74670
- function resolveCheckoutHref(options) {
74671
- if (options?.checkoutHref === null) return null;
74672
- const href = options?.checkoutHref?.trim();
74673
- return href && href.length > 0 ? href : "/checkout";
74674
- }
74675
- function resolvePortalLabel(link, options) {
74676
- const loggedOutLabel = link.labels?.loggedOut?.trim() || PORTAL_NAV_DEFAULT_LABELS.loggedOut;
74677
- const loggedInLabel = link.labels?.loggedIn?.trim() || PORTAL_NAV_DEFAULT_LABELS.loggedIn;
74678
- return options?.hasPortalSession ? loggedInLabel : loggedOutLabel;
74679
- }
74680
- function resolveItemLabel(link, fallbackLabel, options) {
74681
- if (link?.kind === "portal") return resolvePortalLabel(link, options);
74682
- if (link?.kind === "cart") return resolveCartVisibleLabel(link) ?? fallbackLabel;
74683
- return fallbackLabel;
74684
- }
74685
- function resolveCartVisibleLabel(link) {
74686
- if (link.label.kind !== "icon-with-label") return null;
74687
- const label = link.label.label.trim();
74688
- return label.length > 0 ? label : null;
74689
- }
74690
- function resolveCartAriaLabel(link, fallbackLabel) {
74691
- const fallback = fallbackLabel.trim();
74692
- return resolveCartVisibleLabel(link) ?? (fallback.length > 0 ? fallback : "Cart");
74693
- }
74694
- function buildCartNavViewModel(link, fallbackLabel, options) {
74695
- return {
74696
- visibleLabel: resolveCartVisibleLabel(link),
74697
- badge: link.badge,
74698
- ariaLabel: resolveCartAriaLabel(link, fallbackLabel),
74699
- checkoutHref: resolveCheckoutHref(options)
74700
- };
74701
- }
74702
- function deriveRenderableNavigationLink(item, options) {
74703
- const payload = readNavigationItemPayload(item);
74704
- if (!payload) return null;
74705
- if (payload.kind === "portal" && !isPortalEnabled(options)) return null;
74706
- if (payload.kind === "cart" && !isCommerceEnabled(options)) return null;
74707
- return {
74708
- id: item.id,
74709
- label: resolveItemLabel(payload, item.label, options),
74710
- payload,
74711
- isExternal: isExternalLink(payload),
74712
- ...payload.kind === "cart" ? { cart: buildCartNavViewModel(payload, item.label, options) } : {}
74713
- };
74714
- }
74715
- function buildNavLinkFromResolvedHref(item, href) {
74716
- if (!href) return null;
74717
- return {
74718
- kind: "link",
74719
- id: item.id,
74720
- label: item.label,
74721
- href,
74722
- link: { href },
74723
- isExternal: item.isExternal,
74724
- ...item.cart ? { cart: item.cart } : {}
74725
- };
74726
- }
74727
- /**
74728
- * Determines if a navigation item's link is external.
74729
- */
74730
- function isExternalLink(link) {
74731
- if (!link) return false;
74732
- return link.kind === "external";
74733
- }
74734
- /**
74735
- * Build a map of children items by parent ID.
74736
- * Also warns about deeply nested items (grandchildren) which CMS shouldn't allow.
74737
- * @internal
74738
- */
74739
- function buildChildrenByParentId(items) {
74740
- const childrenByParentId = /* @__PURE__ */ new Map();
74741
- const itemsById = /* @__PURE__ */ new Map();
74742
- for (const item of items) itemsById.set(item.id, item);
74743
- for (const item of items) if (item.parentId) {
74744
- if (itemsById.get(item.parentId)?.parentId && typeof process !== "undefined" && process.env.NODE_ENV !== "production") {
74745
- console.warn(`[SDK Navigation] Deeply nested item detected: "${item.label}" (id: ${item.id}). Only 1 level of nesting is supported. This item will be ignored.`);
74746
- continue;
74747
- }
74748
- const siblings = childrenByParentId.get(item.parentId) ?? [];
74749
- siblings.push(item);
74750
- childrenByParentId.set(item.parentId, siblings);
74751
- }
74752
- return childrenByParentId;
74753
- }
74754
- /**
74755
- * Generic nested structure builder.
74756
- * @internal
74757
- */
74758
- function buildNestedStructure(items, options) {
74759
- const childrenByParentId = buildChildrenByParentId(items);
74760
- const rootItems = items.filter((item) => !item.parentId).sort((a, b) => (a.orderIndex ?? a.position ?? 0) - (b.orderIndex ?? b.position ?? 0));
74761
- const result = [];
74762
- let ctaItem = null;
74763
- for (const item of rootItems) {
74764
- if (options.extractCta && !ctaItem && Boolean(item.isCta) && item.urlType !== "dropdown") {
74765
- const link = options.toLink(item);
74766
- if (link) {
74767
- ctaItem = link;
74768
- continue;
74769
- }
74770
- }
74771
- const childRecords = childrenByParentId.get(item.id) ?? [];
74772
- const hasChildren = childRecords.length > 0;
74773
- if (item.urlType === "dropdown" || hasChildren) {
74774
- const children = childRecords.sort((a, b) => (a.orderIndex ?? a.position ?? 0) - (b.orderIndex ?? b.position ?? 0)).map(options.toLink).filter((child) => child !== null);
74775
- if (children.length > 0) result.push(options.createDropdown(item.id, item.label, children));
74776
- continue;
74777
- }
74778
- const link = options.toLink(item);
74779
- if (link) result.push(link);
74780
- }
74781
- return {
74782
- items: result,
74783
- ctaItem
74784
- };
74785
- }
74786
- /**
74787
- * Build a Menu from navigation data with pre-resolved hrefs.
74788
- * Supports dropdown containers with nested children.
74789
- *
74790
- * @param navigation - Navigation menus from site data
74791
- * @param routes - Route map for resolving internal links
74792
- * @param options - Include identifier maps to resolve canonical `page`/`entry` links.
74793
- *
74794
- * @example
74795
- * ```ts
74796
- * const menu = buildMenu(siteData.navigation, siteData.routes, {
74797
- * pagesByIdentifier: siteData.pagesByIdentifier,
74798
- * entriesByIdentifier: siteData.entriesByIdentifier,
74799
- * });
74800
- * menu.items.forEach(item => {
74801
- * if (item.kind === 'dropdown') {
74802
- * console.log(item.children);
74803
- * }
74804
- * });
74805
- * ```
74806
- */
74807
- function buildMenu(navigation, routes, options) {
74808
- const menu = getPrimaryNavigation(navigation);
74809
- if (!menu) return {
74810
- items: [],
74811
- ctaItem: null
74812
- };
74813
- const toNavLink = (item) => {
74814
- const renderable = deriveRenderableNavigationLink(item, options);
74815
- if (!renderable) return null;
74816
- return buildNavLinkFromResolvedHref(renderable, resolveHref(renderable.payload, routes, options));
74817
- };
74818
- const { items, ctaItem } = buildNestedStructure(menu.items, {
74819
- toLink: toNavLink,
74820
- createDropdown: (id, label, children) => ({
74821
- kind: "dropdown",
74822
- id,
74823
- label,
74824
- children
74825
- }),
74826
- extractCta: true
74827
- });
74828
- return {
74829
- items,
74830
- ctaItem: ctaItem ? {
74831
- ...ctaItem,
74832
- variant: "primary"
74833
- } : null
74834
- };
74835
- }
74836
- /**
74837
- * Build a Menu from the footer navigation data.
74838
- * Returns empty menu if no footer menu is designated.
74839
- *
74840
- * @param navigation - Navigation menus from site data
74841
- * @param routes - Route map for resolving internal links
74842
- * @param options - Include identifier maps to resolve canonical `page`/`entry` links.
74843
- *
74844
- * @example
74845
- * ```ts
74846
- * const footerMenu = buildFooterMenu(siteData.navigation, siteData.routes, {
74847
- * pagesByIdentifier: siteData.pagesByIdentifier,
74848
- * entriesByIdentifier: siteData.entriesByIdentifier,
74849
- * });
74850
- * footerMenu.items.forEach(item => {
74851
- * if (item.kind === 'dropdown') {
74852
- * // Footer renders children expanded, not as hover dropdowns
74853
- * console.log(item.children);
74854
- * }
74855
- * });
74856
- * ```
74857
- */
74858
- function buildFooterMenu(navigation, routes, options) {
74859
- return buildFooterMenuForRole(navigation, routes, "main", options);
74860
- }
74861
- function buildFooterMenuForRole(navigation, routes, role, options) {
74862
- const menu = getFooterNavigationByRole(navigation, role);
74863
- if (!menu) return {
74864
- items: [],
74865
- ctaItem: null,
74866
- groups: [],
74867
- links: []
74868
- };
74869
- const toNavLink = (item) => {
74870
- const renderable = deriveRenderableNavigationLink(item, options);
74871
- if (!renderable) return null;
74872
- return buildNavLinkFromResolvedHref(renderable, resolveHref(renderable.payload, routes, options));
74873
- };
74874
- const built = buildNestedStructure(menu.items, {
74875
- toLink: toNavLink,
74876
- createDropdown: (id, label, children) => ({
74877
- kind: "dropdown",
74878
- id,
74879
- label,
74880
- children
74881
- }),
74882
- extractCta: false
74883
- });
74884
- const groups = built.items.filter((item) => item.kind === "dropdown");
74885
- const links = built.items.filter((item) => item.kind === "link");
74886
- return {
74887
- items: built.items,
74888
- ctaItem: null,
74889
- groups,
74890
- links
74891
- };
74892
- }
74893
- /**
74894
- * Resolve href from a link payload using route map.
74895
- * @internal
74896
- */
74897
- function resolveHref(link, routes, options) {
74898
- if (!link) return null;
74899
- if (link.kind === "external" || link.kind === "url") return link.href || null;
74900
- if (link.kind === "portal") return isPortalEnabled(options) ? resolvePortalHref(link) : null;
74901
- if (link.kind === "cart") return isCommerceEnabled(options) ? resolveCheckoutHref(options) : null;
74902
- const stage = normalizeRenderStage(options?.previewStage);
74903
- if (link.kind === "internal") return resolveRouteHrefWithFallback(link.routeId, link.href ?? null, routes, stage);
74904
- if (link.kind === "page") {
74905
- const routeIdFromPayload = readRouteIdFromLink(link);
74906
- const routeIdFromIdentifierMap = options?.pagesByIdentifier?.[link.identifier] ?? null;
74907
- return resolveRouteHrefWithFallback(routeIdFromPayload ?? routeIdFromIdentifierMap, readHrefFromLink(link), routes, stage);
74908
- }
74909
- if (link.kind === "entry") {
74910
- const routeIdFromPayload = readRouteIdFromLink(link);
74911
- const routeIdFromIdentifierMap = readEntryRouteIdFromIdentifierMap(options, link.contentType, link.identifier);
74912
- return resolveRouteHrefWithFallback(routeIdFromPayload ?? routeIdFromIdentifierMap, readHrefFromLink(link), routes, stage);
74913
- }
74914
- return null;
74915
- }
74916
- function resolveRouteHrefWithFallback(routeId, fallbackHref, routes, stage) {
74917
- if (!routeId) return fallbackHref;
74918
- const resolved = resolveRouteHrefForStage(routeId, routes, stage);
74919
- if (resolved) return resolved;
74920
- const route = routes[routeId];
74921
- if (!route) return fallbackHref;
74922
- if (!isRouteVisibleInStage(route, stage)) return null;
74923
- return fallbackHref;
74924
- }
74925
- function readRouteIdFromLink(link) {
74926
- if (!("routeId" in link) || typeof link.routeId !== "string") return null;
74927
- return link.routeId;
74928
- }
74929
- function readHrefFromLink(link) {
74930
- if (!("href" in link) || typeof link.href !== "string") return null;
74931
- return link.href;
74932
- }
74933
- function readEntryRouteIdFromIdentifierMap(options, contentType, identifier) {
74934
- const entryMap = options?.entriesByIdentifier?.[contentType];
74935
- if (!entryMap) return null;
74936
- return entryMap[identifier] ?? null;
74937
- }
74938
- /**
74939
- * Build a Logo from site layout data.
74940
- *
74941
- * @param logo - Logo data from site layout
74942
- * @param fallbackAlt - Fallback alt text (usually site title)
74943
- *
74944
- * @example
74945
- * ```ts
74946
- * const logo = buildLogo(siteData.layout.logo, siteData.site.title);
74947
- * // { src: 'https://...', alt: 'Site Name', width: 200, height: 50 }
74948
- * ```
74949
- */
74950
- function buildLogo(logo, fallbackAlt) {
74951
- if (!logo || !logo.url) return null;
74952
- const alt = resolveAltText(logo.alt, fallbackAlt);
74953
- const result = {
74954
- type: "image",
74955
- src: logo.url,
74956
- alt
74957
- };
74958
- if (logo.width != null) result.width = logo.width;
74959
- if (logo.height != null) result.height = logo.height;
74960
- return result;
74961
- }
74962
- /**
74963
- * Build both site logos from layout data. The default header and footer choose
74964
- * between them by the surface they sit on; custom chrome can do the same.
74965
- *
74966
- * @example
74967
- * ```ts
74968
- * const logoVariants = buildLogoVariants(siteData.layout, siteData.site.title);
74969
- * ```
74970
- */
74971
- function buildLogoVariants(layout, fallbackAlt) {
74972
- return {
74973
- forLightBackgrounds: buildLogo(layout?.logo ?? null, fallbackAlt),
74974
- forDarkBackgrounds: buildLogo(layout?.logoForDarkBackgrounds ?? null, fallbackAlt)
74975
- };
74976
- }
74977
- /**
74978
- * Header/footer block content for the site logos. `logo` stays populated with
74979
- * whichever logo exists so presence checks keep working; `logoVariants` is
74980
- * what the blocks select from at render.
74981
- */
74982
- function buildChromeLogoContent(layout, fallbackAlt) {
74983
- const logoVariants = buildLogoVariants(layout, fallbackAlt);
74984
- return {
74985
- logo: logoVariants.forLightBackgrounds ?? logoVariants.forDarkBackgrounds,
74986
- logoVariants
74987
- };
74988
- }
74989
- //#endregion
74990
- //#region src/rendering/themeAdmission.ts
74991
- const MISSING_SDK_THEME_ERROR_CODE = "missing_sdk_theme";
74992
- var MissingSdkThemeError = class extends Error {
74993
- constructor(siteId, reason = "cms_theme_absent", themeKey) {
74994
- super(`[Riverbank SDK] Site "${siteId}" has no resolvable theme. ` + (themeKey ? `Theme key "${themeKey}" is not present. ` : "") + "Select a CMS theme, provide { theme }, { themes }, or { getTheme }, or use rendering: { kind: 'overrides-only' } with complete block overrides.");
74995
- this.siteId = siteId;
74996
- this.reason = reason;
74997
- this.themeKey = themeKey;
74998
- this.code = MISSING_SDK_THEME_ERROR_CODE;
74999
- this.name = "MissingSdkThemeError";
75000
- }
75001
- };
75002
- function requireSdkTheme(theme, siteId, reason = "cms_theme_absent") {
75003
- if (theme === null || theme === void 0) throw new MissingSdkThemeError(siteId, reason);
75004
- return theme;
75005
- }
75006
- //#endregion
75007
- //#region src/rendering/renderingMode.ts
75008
- const defaultOverrideOnlyRuntime = { kind: "responsive-only" };
75009
- //#endregion
75010
- //#region ../blocks/src/structure/schema.ts
75011
- const BlockKind = z.string();
75012
- const blockSchema = z.object({
75013
- id: z.string().nullable(),
75014
- kind: BlockKind,
75015
- purpose: z.string().min(1),
75016
- content: z.record(z.string(), z.unknown()).optional(),
75017
- draftContent: z.record(z.string(), z.unknown()).nullable().optional(),
75018
- bindings: z.record(z.string(), z.unknown()).optional()
75019
- }).passthrough();
75020
- const pagePath = z.string().regex(/^\/[\S]*$/, "path must start with \"/\" and contain no spaces");
75021
- z.object({
75022
- name: z.string().min(1),
75023
- path: pagePath,
75024
- purpose: z.string().min(1),
75025
- blocks: z.array(blockSchema).min(1)
75026
- });
75027
- //#endregion
75028
- //#region ../../node_modules/.pnpm/@vibrant+image@4.0.4/node_modules/@vibrant/image/dist/esm/histogram.js
75029
- var Histogram = class {
75030
- constructor(pixels, opts) {
75031
- this.pixels = pixels;
75032
- this.opts = opts;
75033
- const { sigBits } = opts;
75034
- const getColorIndex = (r2, g2, b2) => (r2 << 2 * sigBits) + (g2 << sigBits) + b2;
75035
- this.getColorIndex = getColorIndex;
75036
- const rshift = 8 - sigBits;
75037
- const hn = 1 << 3 * sigBits;
75038
- const hist = new Uint32Array(hn);
75039
- let rmax;
75040
- let rmin;
75041
- let gmax;
75042
- let gmin;
75043
- let bmax;
75044
- let bmin;
75045
- let r;
75046
- let g;
75047
- let b;
75048
- let a;
75049
- rmax = gmax = bmax = 0;
75050
- rmin = gmin = bmin = Number.MAX_VALUE;
75051
- const n = pixels.length / 4;
75052
- let i = 0;
75053
- while (i < n) {
75054
- const offset = i * 4;
75055
- i++;
75056
- r = pixels[offset + 0];
75057
- g = pixels[offset + 1];
75058
- b = pixels[offset + 2];
75059
- a = pixels[offset + 3];
75060
- if (a === 0) continue;
75061
- r = r >> rshift;
75062
- g = g >> rshift;
75063
- b = b >> rshift;
75064
- const index = getColorIndex(r, g, b);
75065
- if (hist[index] === void 0) hist[index] = 0;
75066
- hist[index] += 1;
75067
- if (r > rmax) rmax = r;
75068
- if (r < rmin) rmin = r;
75069
- if (g > gmax) gmax = g;
75070
- if (g < gmin) gmin = g;
75071
- if (b > bmax) bmax = b;
75072
- if (b < bmin) bmin = b;
75073
- }
75074
- this._colorCount = hist.reduce((total, c) => c > 0 ? total + 1 : total, 0);
75075
- this.hist = hist;
75076
- this.rmax = rmax;
75077
- this.rmin = rmin;
75078
- this.gmax = gmax;
75079
- this.gmin = gmin;
75080
- this.bmax = bmax;
75081
- this.bmin = bmin;
75082
- }
75083
- get colorCount() {
75084
- return this._colorCount;
75085
- }
75086
- };
75087
- //#endregion
75088
- //#region ../../node_modules/.pnpm/@vibrant+image@4.0.4/node_modules/@vibrant/image/dist/esm/index.js
75089
- var ImageBase = class {
75090
- scaleDown(opts) {
75091
- const width = this.getWidth();
75092
- const height = this.getHeight();
75093
- let ratio = 1;
75094
- if (opts.maxDimension > 0) {
75095
- const maxSide = Math.max(width, height);
75096
- if (maxSide > opts.maxDimension) ratio = opts.maxDimension / maxSide;
75097
- } else ratio = 1 / opts.quality;
75098
- if (ratio < 1) this.resize(width * ratio, height * ratio, ratio);
75099
- }
75100
- };
75101
- function applyFilters(imageData, filters) {
75102
- if (filters.length > 0) {
75103
- const pixels = imageData.data;
75104
- const n = pixels.length / 4;
75105
- let offset;
75106
- let r;
75107
- let g;
75108
- let b;
75109
- let a;
75110
- for (let i = 0; i < n; i++) {
75111
- offset = i * 4;
75112
- r = pixels[offset + 0];
75113
- g = pixels[offset + 1];
75114
- b = pixels[offset + 2];
75115
- a = pixels[offset + 3];
75116
- for (let j = 0; j < filters.length; j++) if (!filters[j]?.(r, g, b, a)) {
75117
- pixels[offset + 3] = 0;
75118
- break;
75119
- }
75120
- }
75121
- }
75122
- return imageData;
75123
- }
75124
- //#endregion
75125
- //#region ../../node_modules/.pnpm/@vibrant+image-browser@4.0.4/node_modules/@vibrant/image-browser/dist/esm/index.js
75126
- function isRelativeUrl(url) {
75127
- const u = new URL(url, location.href);
75128
- return u.protocol === location.protocol && u.host === location.host && u.port === location.port;
75129
- }
75130
- function isSameOrigin(a, b) {
75131
- const ua = new URL(a);
75132
- const ub = new URL(b);
75133
- return ua.protocol === ub.protocol && ua.hostname === ub.hostname && ua.port === ub.port;
75134
- }
75135
- var BrowserImage = class extends ImageBase {
75136
- _getCanvas() {
75137
- if (!this._canvas) throw new Error("Canvas is not initialized");
75138
- return this._canvas;
75139
- }
75140
- _getContext() {
75141
- if (!this._context) throw new Error("Context is not initialized");
75142
- return this._context;
75143
- }
75144
- _getWidth() {
75145
- if (!this._width) throw new Error("Width is not initialized");
75146
- return this._width;
75147
- }
75148
- _getHeight() {
75149
- if (!this._height) throw new Error("Height is not initialized");
75150
- return this._height;
75151
- }
75152
- _initCanvas() {
75153
- const img = this.image;
75154
- if (!img) throw new Error("Image is not initialized");
75155
- const canvas = this._canvas = document.createElement("canvas");
75156
- const context = canvas.getContext("2d");
75157
- if (!context) throw new ReferenceError("Failed to create canvas context");
75158
- this._context = context;
75159
- canvas.className = "@vibrant/canvas";
75160
- canvas.style.display = "none";
75161
- this._width = canvas.width = img.width;
75162
- this._height = canvas.height = img.height;
75163
- context.drawImage(img, 0, 0);
75164
- document.body.appendChild(canvas);
75165
- }
75166
- load(image) {
75167
- let img;
75168
- let src;
75169
- if (typeof image === "string") {
75170
- img = document.createElement("img");
75171
- src = image;
75172
- if (!isRelativeUrl(src) && !isSameOrigin(window.location.href, src)) img.crossOrigin = "anonymous";
75173
- img.src = src;
75174
- } else if (image instanceof HTMLImageElement) {
75175
- img = image;
75176
- src = image.src;
75177
- } else return Promise.reject(/* @__PURE__ */ new Error(`Cannot load buffer as an image in browser`));
75178
- this.image = img;
75179
- return new Promise((resolve, reject) => {
75180
- const onImageLoad = () => {
75181
- this._initCanvas();
75182
- resolve(this);
75183
- };
75184
- if (img.complete) onImageLoad();
75185
- else {
75186
- img.onload = onImageLoad;
75187
- img.onerror = (_e) => reject(/* @__PURE__ */ new Error(`Fail to load image: ${src}`));
75188
- }
75189
- });
75190
- }
75191
- clear() {
75192
- this._getContext().clearRect(0, 0, this._getWidth(), this._getHeight());
75193
- }
75194
- update(imageData) {
75195
- this._getContext().putImageData(imageData, 0, 0);
75196
- }
75197
- getWidth() {
75198
- return this._getWidth();
75199
- }
75200
- getHeight() {
75201
- return this._getHeight();
75202
- }
75203
- resize(targetWidth, targetHeight, ratio) {
75204
- if (!this.image) throw new Error("Image is not initialized");
75205
- this._width = this._getCanvas().width = targetWidth;
75206
- this._height = this._getCanvas().height = targetHeight;
75207
- this._getContext().scale(ratio, ratio);
75208
- this._getContext().drawImage(this.image, 0, 0);
75209
- }
75210
- getPixelCount() {
75211
- return this._getWidth() * this._getHeight();
75212
- }
75213
- getImageData() {
75214
- return this._getContext().getImageData(0, 0, this._getWidth(), this._getHeight());
75215
- }
75216
- remove() {
75217
- if (this._canvas && this._canvas.parentNode) this._canvas.parentNode.removeChild(this._canvas);
75218
- }
75219
- };
75220
- function assignDeep(target, ...sources) {
75221
- sources.forEach((s) => {
75222
- if (!s) return;
75223
- for (const key in s) if (s.hasOwnProperty(key)) {
75224
- const v = s[key];
75225
- if (Array.isArray(v)) target[key] = v.slice(0);
75226
- else if (typeof v === "object") {
75227
- if (!target[key]) target[key] = {};
75228
- assignDeep(target[key], v);
75229
- } else target[key] = v;
75230
- }
74603
+ });
74604
+ }
74605
+ clear() {
74606
+ this._getContext().clearRect(0, 0, this._getWidth(), this._getHeight());
74607
+ }
74608
+ update(imageData) {
74609
+ this._getContext().putImageData(imageData, 0, 0);
74610
+ }
74611
+ getWidth() {
74612
+ return this._getWidth();
74613
+ }
74614
+ getHeight() {
74615
+ return this._getHeight();
74616
+ }
74617
+ resize(targetWidth, targetHeight, ratio) {
74618
+ if (!this.image) throw new Error("Image is not initialized");
74619
+ this._width = this._getCanvas().width = targetWidth;
74620
+ this._height = this._getCanvas().height = targetHeight;
74621
+ this._getContext().scale(ratio, ratio);
74622
+ this._getContext().drawImage(this.image, 0, 0);
74623
+ }
74624
+ getPixelCount() {
74625
+ return this._getWidth() * this._getHeight();
74626
+ }
74627
+ getImageData() {
74628
+ return this._getContext().getImageData(0, 0, this._getWidth(), this._getHeight());
74629
+ }
74630
+ remove() {
74631
+ if (this._canvas && this._canvas.parentNode) this._canvas.parentNode.removeChild(this._canvas);
74632
+ }
74633
+ };
74634
+ function assignDeep(target, ...sources) {
74635
+ sources.forEach((s) => {
74636
+ if (!s) return;
74637
+ for (const key in s) if (s.hasOwnProperty(key)) {
74638
+ const v = s[key];
74639
+ if (Array.isArray(v)) target[key] = v.slice(0);
74640
+ else if (typeof v === "object") {
74641
+ if (!target[key]) target[key] = {};
74642
+ assignDeep(target[key], v);
74643
+ } else target[key] = v;
74644
+ }
75231
74645
  });
75232
74646
  return target;
75233
74647
  }
@@ -76055,351 +75469,1121 @@ const pipeline = new BasicPipeline().filter.register("default", (r, g, b, a) =>
76055
75469
  //#region ../../node_modules/.pnpm/node-vibrant@4.0.4/node_modules/node-vibrant/dist/esm/browser.js
76056
75470
  Vibrant.use(pipeline);
76057
75471
  //#endregion
76058
- //#region ../blocks/src/system/runtime/bindings.ts
76059
- const shouldLogWarnings = isNonProductionEnv();
76060
- function isPlainObject$1(value) {
76061
- return typeof value === "object" && value !== null && !Array.isArray(value);
75472
+ //#region ../blocks/src/system/runtime/bindings.ts
75473
+ const shouldLogWarnings = isNonProductionEnv();
75474
+ function isPlainObject$1(value) {
75475
+ return typeof value === "object" && value !== null && !Array.isArray(value);
75476
+ }
75477
+ function isRouteMapEntry(value) {
75478
+ if (typeof value === "string") return true;
75479
+ return isPlainObject$1(value);
75480
+ }
75481
+ function isRouteMap(value) {
75482
+ if (!isPlainObject$1(value)) return false;
75483
+ return Object.values(value).every(isRouteMapEntry);
75484
+ }
75485
+ function isPageIdentifierMap(value) {
75486
+ if (!isPlainObject$1(value)) return false;
75487
+ return Object.values(value).every((v) => typeof v === "string");
75488
+ }
75489
+ function isEntryIdentifierMap(value) {
75490
+ if (!isPlainObject$1(value)) return false;
75491
+ for (const v of Object.values(value)) {
75492
+ if (!isPlainObject$1(v)) return false;
75493
+ if (!Object.values(v).every((inner) => typeof inner === "string")) return false;
75494
+ }
75495
+ return true;
75496
+ }
75497
+ function buildTransformContext(vm) {
75498
+ const root = vm.$root;
75499
+ const stage = root && isPlainObject$1(root) && root.previewStage === "preview" ? "preview" : "published";
75500
+ const routes = root && isPlainObject$1(root) && isRouteMap(root.routes) ? root.routes : void 0;
75501
+ const pagesByIdentifier = root && isPlainObject$1(root) && isPageIdentifierMap(root.pagesByIdentifier) ? root.pagesByIdentifier : void 0;
75502
+ const entriesByIdentifier = root && isPlainObject$1(root) && isEntryIdentifierMap(root.entriesByIdentifier) ? root.entriesByIdentifier : void 0;
75503
+ return {
75504
+ theme: defaultThemeTokens,
75505
+ stage,
75506
+ data: vm.content,
75507
+ routes,
75508
+ pagesByIdentifier,
75509
+ entriesByIdentifier
75510
+ };
75511
+ }
75512
+ function resolveParamsBindings(input, vm, meta) {
75513
+ if (input === null || typeof input !== "object") return input;
75514
+ if (Array.isArray(input)) return input.map((v) => resolveParamsBindings(v, vm, meta));
75515
+ const maybeBind = input.$bind;
75516
+ if (maybeBind && typeof maybeBind === "object") try {
75517
+ const binding = bindingSchema.parse(maybeBind);
75518
+ const value = resolveBinding(binding.from, vm);
75519
+ const resolved = value === void 0 || value === null ? binding.fallback : runTransforms(value, binding.transforms, buildTransformContext(vm), defaultTransforms);
75520
+ if (resolved === void 0 || resolved === null || resolved === "") return binding.fallback;
75521
+ return resolved;
75522
+ } catch (err) {
75523
+ if (shouldLogWarnings) console.warn(`bindings: failed to parse loader param binding for block "${meta?.blockKind ?? "unknown"}"`, err);
75524
+ return;
75525
+ }
75526
+ const out = {};
75527
+ for (const [k, v] of Object.entries(input)) out[k] = resolveParamsBindings(v, vm, meta);
75528
+ return out;
75529
+ }
75530
+ function resolveBinding(path, vm) {
75531
+ const segments = splitPath(path);
75532
+ if (!segments.length) return void 0;
75533
+ const [first, ...rest] = segments;
75534
+ let source = vm;
75535
+ if (first === "$root") {
75536
+ source = vm;
75537
+ return readFromSource(source, [first, ...rest]);
75538
+ }
75539
+ if (first === "content") {
75540
+ source = vm.content;
75541
+ return readFromSource(source, rest);
75542
+ }
75543
+ const contentResult = readFromSource(vm.content, segments);
75544
+ if (contentResult !== void 0) return contentResult;
75545
+ return readFromSource(vm, segments);
75546
+ }
75547
+ function splitPath(path) {
75548
+ const PATH_SEPARATOR_REGEX = /\./g;
75549
+ const BRACKET_ACCESS_REGEX = /\[(?<token>[^\]]+)\]/g;
75550
+ const segments = [];
75551
+ const parts = path.split(PATH_SEPARATOR_REGEX);
75552
+ for (const raw of parts) {
75553
+ if (!raw) continue;
75554
+ const baseMatch = raw.match(/^([^\[]+)/);
75555
+ if (baseMatch && baseMatch[1]) segments.push(baseMatch[1]);
75556
+ const bracketMatches = raw.matchAll(BRACKET_ACCESS_REGEX);
75557
+ for (const match of bracketMatches) {
75558
+ const token = match.groups?.token ?? "";
75559
+ if (token.startsWith("\"") || token.startsWith("'")) segments.push(token.slice(1, -1));
75560
+ else if (/^\d+$/.test(token)) segments.push(Number(token));
75561
+ else segments.push(token);
75562
+ }
75563
+ if (!baseMatch && !raw.includes("[")) segments.push(raw);
75564
+ }
75565
+ return segments;
75566
+ }
75567
+ function readFromSource(source, segments) {
75568
+ return segments.reduce((current, segment) => {
75569
+ if (current === void 0 || current === null) return void 0;
75570
+ if (typeof segment === "number") {
75571
+ if (Array.isArray(current)) return current[segment];
75572
+ return;
75573
+ }
75574
+ if (typeof current === "object" && current !== null && segment in current) return current[segment];
75575
+ }, source);
75576
+ }
75577
+ function isNonProductionEnv() {
75578
+ if (typeof globalThis === "undefined") return true;
75579
+ return globalThis.process?.env?.NODE_ENV !== "production";
75580
+ }
75581
+ function isNonArrayObject(value) {
75582
+ return typeof value === "object" && value !== null && !Array.isArray(value);
75583
+ }
75584
+ function safeJsonStringify(value) {
75585
+ try {
75586
+ return JSON.stringify(value);
75587
+ } catch {
75588
+ return;
75589
+ }
75590
+ }
75591
+ /**
75592
+ * Coerce value to string for API params
75593
+ */
75594
+ function coerceToString(value) {
75595
+ if (value === null || value === void 0) return "";
75596
+ if (Array.isArray(value)) {
75597
+ if (value.some(isNonArrayObject)) {
75598
+ const json = safeJsonStringify(value);
75599
+ if (typeof json === "string") return json;
75600
+ }
75601
+ return value.map(coerceToString).join(",");
75602
+ }
75603
+ if (isNonArrayObject(value)) {
75604
+ const json = safeJsonStringify(value);
75605
+ if (typeof json === "string") return json;
75606
+ }
75607
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") return String(value);
75608
+ return "";
75609
+ }
75610
+ //#endregion
75611
+ //#region ../blocks/src/system/data/loaderEndpoints.ts
75612
+ const SUPPORTED_LOADER_ENDPOINTS$1 = [
75613
+ "listPublishedEntries",
75614
+ "getPublishedEntryPreview",
75615
+ "listPublicEvents",
75616
+ "listPublicEventCalendarWindow",
75617
+ "listPublicRecurringSchedule",
75618
+ "getPublicEventDetails",
75619
+ "listPublicRouteCandidates",
75620
+ "listPublicTeamMembers",
75621
+ "listPublicProducts",
75622
+ "listPublicPasses",
75623
+ "listPublicMemberships",
75624
+ "getPublicFormById",
75625
+ "getPublicBookingServices",
75626
+ "getPublicWeeklySlotAvailability"
75627
+ ];
75628
+ //#endregion
75629
+ //#region ../blocks/src/system/data/batching.ts
75630
+ function stableNormalize(value) {
75631
+ if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") return value;
75632
+ if (Array.isArray(value)) return value.map(stableNormalize);
75633
+ if (typeof value === "object" && value) {
75634
+ const obj = value;
75635
+ const keys = Object.keys(obj).sort();
75636
+ const out = {};
75637
+ for (const key of keys) {
75638
+ const v = obj[key];
75639
+ if (v === void 0) continue;
75640
+ out[key] = stableNormalize(v);
75641
+ }
75642
+ return out;
75643
+ }
75644
+ if (typeof value === "bigint" || typeof value === "symbol" || typeof value === "undefined") return String(value);
75645
+ return null;
75646
+ }
75647
+ const RichText$1 = RichText$2;
75648
+ //#endregion
75649
+ //#region ../blocks/src/system/customize/facets.ts
75650
+ function defineCustomizeFacet(definition) {
75651
+ return definition;
75652
+ }
75653
+ const systemCustomizeFacetDefinitions = [defineCustomizeFacet({
75654
+ blockKind: "block.event-calendar",
75655
+ id: "eventCalendar.listLayout",
75656
+ label: "List style",
75657
+ values: eventCalendarListLayoutOptions.map((option) => ({
75658
+ value: option.id,
75659
+ label: option.label
75660
+ })),
75661
+ defaultValue: "stack",
75662
+ target: { kind: "event-calendar-list-layout-content" },
75663
+ appliesToLayoutVariants: eventCalendarListLayoutCompatibleDisplayModeValues
75664
+ })];
75665
+ systemCustomizeFacetDefinitions.map((definition) => definition.id);
75666
+ Array.from(new Set(systemCustomizeFacetDefinitions.flatMap((definition) => definition.values.map((option) => option.value))));
75667
+ const backgroundColorTokenNames = backgroundAppearanceColorTokenNames;
75668
+ const backgroundColorTokenNameSet = new Set(backgroundColorTokenNames);
75669
+ const backgroundColorTokens = toBackgroundColorTokens(backgroundColorTokenNames);
75670
+ const quickBackgroundColorTokens = toBackgroundColorTokens(backgroundAppearanceQuickColorTokenNames);
75671
+ backgroundColorTokens.filter((token) => !quickBackgroundColorTokens.includes(token));
75672
+ function toBackgroundColorTokens(tokenNames) {
75673
+ return tokenNames.flatMap((name) => {
75674
+ const token = parseBackgroundColorToken(name);
75675
+ if (!token) return [];
75676
+ return [token];
75677
+ });
75678
+ }
75679
+ function parseBackgroundColorToken(value) {
75680
+ if (typeof value !== "string") return null;
75681
+ const normalized = value.trim();
75682
+ if (!backgroundColorTokenNameSet.has(normalized)) return null;
75683
+ const token = parseBackgroundAppearanceColorToken(normalized);
75684
+ if (!token) return null;
75685
+ return token ? token : null;
75686
+ }
75687
+ //#endregion
75688
+ //#region src/rendering/helpers/siteCustomBlocks.ts
75689
+ /**
75690
+ * Prefer the DB-backed custom block manifest list (`site.customBlocks`) when available,
75691
+ * but fall back to SDK config custom blocks (`site.sdkConfig.customBlocks`) for SDK-mode sites.
75692
+ *
75693
+ * This avoids subtle DX bugs where one source is populated but the renderer/prefetch layer
75694
+ * is looking at the other.
75695
+ */
75696
+ function resolveSiteCustomBlocks(site) {
75697
+ const dbBlocks = site.customBlocks;
75698
+ if (Array.isArray(dbBlocks) && dbBlocks.length > 0) return dbBlocks;
75699
+ const sdkBlocks = site.sdkConfig?.customBlocks;
75700
+ if (Array.isArray(sdkBlocks) && sdkBlocks.length > 0) return sdkBlocks;
75701
+ }
75702
+ function readBlockContentId(value, name) {
75703
+ if (value === null || value === void 0) return null;
75704
+ if (typeof value === "string") return value;
75705
+ throw new Error(`Invalid ${name} in page: expected string or null`);
75706
+ }
75707
+ function readTransportedBlockIdentity(block, kind, stage) {
75708
+ return {
75709
+ draftContentId: readBlockContentId(block.draftContentId, "draft content id"),
75710
+ publishedPlacement: stage === "preview" ? readSdkPreviewPublishedPlacement(block, kind) : null
75711
+ };
75712
+ }
75713
+ /** Pair SDK preview publication data whether it is transported or already admitted. */
75714
+ function readSdkPreviewPublishedPlacement(block, kind) {
75715
+ if (block.publishedPlacement !== void 0 && block.publishedPlacement !== null) {
75716
+ if (!isRecord$8(block.publishedPlacement)) throw new Error("Invalid published placement in page");
75717
+ return readPublishedBlockPlacement(readBlockContentId(block.publishedPlacement.id, "published content id"), sanitizeNullableSdkRuntimeBlockContent(kind, readContentRecord(block.publishedPlacement.content) ?? null));
75718
+ }
75719
+ return readPublishedBlockPlacement(readBlockContentId(block.publishedContentId, "published content id"), sanitizeNullableSdkRuntimeBlockContent(kind, readSdkPublishedContentRecord(block.publishedContent)));
75720
+ }
75721
+ function convertPageResponseBlock(block, stage) {
75722
+ if (!isRecord$8(block)) throw new Error("Invalid block format in page API response");
75723
+ const header = readTransportedBlockHeader(block);
75724
+ const admission = readInvalidBlockAdmission(block.admission);
75725
+ return {
75726
+ ...header,
75727
+ ...readTransportedBlockIdentity(block, header.kind, stage),
75728
+ content: sanitizeSdkRuntimeBlockContent(header.kind, readContentRecord(block.content) ?? {}),
75729
+ draftContent: sanitizeNullableSdkRuntimeBlockContent(header.kind, readNestedContentRecord(block.draftContent)),
75730
+ ...admission ? { admission } : {}
75731
+ };
75732
+ }
75733
+ function readTransportedBlockHeader(block) {
75734
+ if (typeof block.id !== "string" && block.id !== null) throw new Error(`Invalid block id in page: expected string or null, got ${typeof block.id}`);
75735
+ if (typeof block.kind !== "string") throw new Error(`Invalid block kind in page: expected string, got ${typeof block.kind}`);
75736
+ if (typeof block.purpose !== "string") throw new Error(`Invalid block purpose in page: expected string, got ${typeof block.purpose}`);
75737
+ if (block.contentVersionId !== void 0 && block.contentVersionId !== null && typeof block.contentVersionId !== "string") throw new Error(`Invalid content version id in page: expected string or null, got ${typeof block.contentVersionId}`);
75738
+ return {
75739
+ id: block.id,
75740
+ ...block.contentVersionId !== void 0 ? { contentVersionId: block.contentVersionId } : {},
75741
+ kind: block.kind,
75742
+ purpose: block.purpose
75743
+ };
75744
+ }
75745
+ function readInvalidBlockAdmission(value) {
75746
+ if (!isRecord$8(value) || value.kind !== "invalid" || !isRecord$8(value.error)) return null;
75747
+ if (value.error.kind !== "invalid_manifest_content" && value.error.kind !== "manifest_unavailable") return null;
75748
+ return value;
75749
+ }
75750
+ function buildPageOutline(input) {
75751
+ return {
75752
+ name: input.name,
75753
+ path: input.path ?? input.fallbackPath,
75754
+ purpose: input.purpose,
75755
+ blocks: input.blocks.map((block) => convertPageResponseBlock(block, input.previewStage))
75756
+ };
75757
+ }
75758
+ function buildRenderablePageOutline(input) {
75759
+ const page = buildPageOutline(input);
75760
+ return {
75761
+ ...page,
75762
+ blocks: page.blocks.map((block) => admitSdkRuntimePageBlock(block, input.customBlocks))
75763
+ };
75764
+ }
75765
+ function admitSdkRuntimePageBlock(block, customBlocks) {
75766
+ const base = {
75767
+ id: block.id,
75768
+ draftContentId: block.draftContentId,
75769
+ publishedPlacement: block.publishedPlacement,
75770
+ ...block.contentVersionId !== void 0 ? { contentVersionId: block.contentVersionId } : {},
75771
+ kind: block.kind,
75772
+ purpose: block.purpose,
75773
+ ...block.bindings ? { bindings: block.bindings } : {}
75774
+ };
75775
+ const transportedAdmission = readInvalidBlockAdmission(block.admission);
75776
+ if (transportedAdmission) return invalidRenderableBlock(base, transportedAdmission.error);
75777
+ const manifest = resolveSdkBlockManifest(block.kind, customBlocks);
75778
+ if (!manifest) return invalidRenderableBlock(base, { kind: "manifest_unavailable" });
75779
+ const content = block.content ?? {};
75780
+ const renderable = admitTransportedRenderableManifestContent(compileManifestContentContract(manifest), content);
75781
+ if (!renderable.ok) return invalidRenderableBlock(base, {
75782
+ kind: "invalid_manifest_content",
75783
+ error: renderable.error
75784
+ });
75785
+ return {
75786
+ ...base,
75787
+ admission: {
75788
+ kind: "renderable",
75789
+ content: renderable.value
75790
+ }
75791
+ };
75792
+ }
75793
+ function resolveSdkBlockManifest(blockKind, customBlocks) {
75794
+ const customBlock = customBlocks?.find((candidate) => candidate.id === blockKind);
75795
+ return customBlock ? parseFieldDefinitions(customBlock.fields) : getBlockDefinition(blockKind)?.manifest ?? null;
75796
+ }
75797
+ function invalidRenderableBlock(block, error) {
75798
+ return {
75799
+ ...block,
75800
+ admission: {
75801
+ kind: "invalid",
75802
+ error
75803
+ }
75804
+ };
75805
+ }
75806
+ function isRecord$8(value) {
75807
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
75808
+ }
75809
+ function readContentRecord(value) {
75810
+ return isRecord$8(value) ? value : void 0;
75811
+ }
75812
+ function readNestedContentRecord(value) {
75813
+ if (!isRecord$8(value)) return null;
75814
+ return readContentRecord(value.data) ?? null;
75815
+ }
75816
+ function readSdkPublishedContentRecord(value) {
75817
+ if (!isRecord$8(value)) return null;
75818
+ return "data" in value ? readContentRecord(value.data) ?? null : value;
75819
+ }
75820
+ function sanitizeSdkRuntimeBlockContent(blockKind, content) {
75821
+ if (blockKind !== "block.newsletter-signup") return content;
75822
+ const sanitized = sanitizeNewsletterSignupPublicContent(content);
75823
+ return isRecord$8(sanitized) ? sanitized : {};
75824
+ }
75825
+ function sanitizeNullableSdkRuntimeBlockContent(blockKind, content) {
75826
+ return content ? sanitizeSdkRuntimeBlockContent(blockKind, content) : null;
75827
+ }
75828
+ function isOverrideOnlyPageRenderer(props) {
75829
+ return props.rendering?.kind === "overrides-only";
75830
+ }
75831
+ function normalizeSdkCustomBlocks(customBlocks) {
75832
+ if (!customBlocks) return void 0;
75833
+ return customBlocks.map((block) => {
75834
+ return {
75835
+ ...block,
75836
+ fields: parseFieldDefinitions(block.fields)
75837
+ };
75838
+ });
75839
+ }
75840
+ function toBlocksBlockOverrides(overrides) {
75841
+ if (!overrides) return void 0;
75842
+ const result = {};
75843
+ for (const [key, OverrideComponent] of Object.entries(overrides)) result[key] = function BlocksOverrideAdapter(props) {
75844
+ const sdkOverride = OverrideComponent;
75845
+ return React$1.createElement(sdkOverride, {
75846
+ ...props,
75847
+ entrySubrouteContext: props.entrySubrouteContext
75848
+ });
75849
+ };
75850
+ return result;
75851
+ }
75852
+ function toBlocksPageRendererDataContext(dataContext) {
75853
+ return {
75854
+ ...dataContext,
75855
+ mediaAssets: toBlocksMediaAssets(dataContext.mediaAssets),
75856
+ imageResolveContext: toBlocksImageResolveContextInput(dataContext.imageResolveContext)
75857
+ };
75858
+ }
75859
+ function toBlocksCommonProps(props) {
75860
+ return {
75861
+ page: props.page,
75862
+ runtimeJoins: props.runtimeJoins,
75863
+ dataContext: toBlocksPageRendererDataContext(props.dataContext),
75864
+ routeMap: props.routeMap,
75865
+ wrapBlock: props.wrapBlock,
75866
+ registry: props.registry,
75867
+ blockOverrides: toBlocksBlockOverrides(props.blockOverrides),
75868
+ sdkConfig: props.sdkConfig ? { customBlocks: normalizeSdkCustomBlocks(props.sdkConfig.customBlocks) } : props.sdkConfig,
75869
+ customBlocks: normalizeSdkCustomBlocks(props.customBlocks)
75870
+ };
75871
+ }
75872
+ function PageRenderer(props) {
75873
+ const commonBlocksProps = toBlocksCommonProps(props);
75874
+ const blocksProps = isOverrideOnlyPageRenderer(props) ? {
75875
+ ...commonBlocksProps,
75876
+ rendering: { kind: "overrides-only" },
75877
+ blockOverrides: toBlocksBlockOverrides(props.blockOverrides) ?? {}
75878
+ } : {
75879
+ ...commonBlocksProps,
75880
+ theme: parseBlocksTheme(props.theme),
75881
+ themeTokens: props.themeTokens
75882
+ };
75883
+ return React$1.createElement(PageRenderer$1, blocksProps);
75884
+ }
75885
+ //#endregion
75886
+ //#region src/rendering/blocks-theme-scope.ts
75887
+ function ThemeScope(props) {
75888
+ const { theme, children, ...rest } = props;
75889
+ const blocksTheme = parseBlocksTheme(theme);
75890
+ return React$1.createElement(ThemeScope$1, {
75891
+ ...rest,
75892
+ theme: blocksTheme,
75893
+ children: children ?? null
75894
+ });
75895
+ }
75896
+ //#endregion
75897
+ //#region src/rendering/themeRuntime.tsx
75898
+ const defaultLayoutThemeRuntime = { kind: "cms-theme" };
75899
+ const defaultSdkChromeThemeRuntime = { kind: "responsive-only" };
75900
+ const defaultPageThemeRuntime = { kind: "none" };
75901
+ function planLayoutThemeRuntime(input) {
75902
+ const requested = input.themeRuntime ?? defaultLayoutThemeRuntime;
75903
+ if (requested.kind === "none" && input.usesSdkChrome) {
75904
+ if (process.env.NODE_ENV !== "production") console.warn("[sdk] Layout themeRuntime { kind: \"none\" } is not compatible with SDK-managed header/footer chrome; using responsive-only runtime instead.");
75905
+ return defaultSdkChromeThemeRuntime;
75906
+ }
75907
+ return requested;
75908
+ }
75909
+ function renderWithSdkThemeRuntime({ themeRuntime, theme, children }) {
75910
+ switch (themeRuntime.kind) {
75911
+ case "cms-theme": return /* @__PURE__ */ jsx(ThemeScope, {
75912
+ theme,
75913
+ responsiveMode: themeRuntime.responsiveMode,
75914
+ children
75915
+ });
75916
+ case "responsive-only": return /* @__PURE__ */ jsx(ResponsiveScope, {
75917
+ responsiveMode: themeRuntime.responsiveMode,
75918
+ children
75919
+ });
75920
+ case "none": return /* @__PURE__ */ jsx(Fragment, { children });
75921
+ default: return assertNever$21(themeRuntime);
75922
+ }
75923
+ }
75924
+ function renderWithOverrideOnlyRuntime({ runtime, children }) {
75925
+ switch (runtime.kind) {
75926
+ case "responsive-only": return /* @__PURE__ */ jsx(ResponsiveScope, {
75927
+ responsiveMode: runtime.responsiveMode,
75928
+ children
75929
+ });
75930
+ case "none": return /* @__PURE__ */ jsx(Fragment, { children });
75931
+ default: return assertNever$21(runtime);
75932
+ }
75933
+ }
75934
+ //#endregion
75935
+ //#region src/rendering/components/pageShared.tsx
75936
+ function isOverrideOnlyPage(props) {
75937
+ return props.rendering?.kind === "overrides-only";
76062
75938
  }
76063
- function isRouteMapEntry(value) {
76064
- if (typeof value === "string") return true;
76065
- return isPlainObject$1(value);
75939
+ function resolvePageThemeTokens(props) {
75940
+ const baseTokens = props.themeTokens ?? buildThemeRuntime(props.theme).tokens;
75941
+ return props.sdkConfig?.theme?.palette ? {
75942
+ ...baseTokens,
75943
+ palette: {
75944
+ ...baseTokens.palette,
75945
+ ...props.sdkConfig.theme.palette
75946
+ }
75947
+ } : baseTokens;
76066
75948
  }
76067
- function isRouteMap(value) {
76068
- if (!isPlainObject$1(value)) return false;
76069
- return Object.values(value).every(isRouteMapEntry);
75949
+ function toPageHydrationBootstrapConfig(props) {
75950
+ return {
75951
+ siteId: props.siteId,
75952
+ supabaseUrl: props.supabaseUrl,
75953
+ mediaAssets: props.mediaAssets
75954
+ };
76070
75955
  }
76071
- function isPageIdentifierMap(value) {
76072
- if (!isPlainObject$1(value)) return false;
76073
- return Object.values(value).every((v) => typeof v === "string");
75956
+ function resolveSdkBookingTimeZone(timeZone) {
75957
+ return timeZone ?? "UTC";
76074
75958
  }
76075
- function isEntryIdentifierMap(value) {
76076
- if (!isPlainObject$1(value)) return false;
76077
- for (const v of Object.values(value)) {
76078
- if (!isPlainObject$1(v)) return false;
76079
- if (!Object.values(v).every((inner) => typeof inner === "string")) return false;
76080
- }
76081
- return true;
75959
+ function buildPageRouteRenderContext(dataContext) {
75960
+ return {
75961
+ ...buildPageIdentityRenderContext(dataContext),
75962
+ occurrenceContext: dataContext.occurrenceContext ?? null,
75963
+ entrySubrouteContext: dataContext.entrySubrouteContext ?? null,
75964
+ contentEntry: dataContext.contentEntry ?? null,
75965
+ pageSurface: dataContext.pageSurface ?? null,
75966
+ subject: dataContext.subject ?? null,
75967
+ editableRouteMetadataFieldIds: dataContext.editableRouteMetadataFieldIds ?? null,
75968
+ previewStage: dataContext.previewStage
75969
+ };
76082
75970
  }
76083
- function buildTransformContext(vm) {
76084
- const root = vm.$root;
76085
- const stage = root && isPlainObject$1(root) && root.previewStage === "preview" ? "preview" : "published";
76086
- const routes = root && isPlainObject$1(root) && isRouteMap(root.routes) ? root.routes : void 0;
76087
- const pagesByIdentifier = root && isPlainObject$1(root) && isPageIdentifierMap(root.pagesByIdentifier) ? root.pagesByIdentifier : void 0;
76088
- const entriesByIdentifier = root && isPlainObject$1(root) && isEntryIdentifierMap(root.entriesByIdentifier) ? root.entriesByIdentifier : void 0;
75971
+ function buildPageIdentityRenderContext(dataContext) {
76089
75972
  return {
76090
- theme: defaultThemeTokens,
76091
- stage,
76092
- data: vm.content,
76093
- routes,
76094
- pagesByIdentifier,
76095
- entriesByIdentifier
75973
+ demoEmailSuppressed: dataContext.demoEmailSuppressed,
75974
+ siteName: dataContext.siteName,
75975
+ pathname: dataContext.pathname
76096
75976
  };
76097
75977
  }
76098
- function resolveParamsBindings(input, vm, meta) {
76099
- if (input === null || typeof input !== "object") return input;
76100
- if (Array.isArray(input)) return input.map((v) => resolveParamsBindings(v, vm, meta));
76101
- const maybeBind = input.$bind;
76102
- if (maybeBind && typeof maybeBind === "object") try {
76103
- const binding = bindingSchema.parse(maybeBind);
76104
- const value = resolveBinding(binding.from, vm);
76105
- const resolved = value === void 0 || value === null ? binding.fallback : runTransforms(value, binding.transforms, buildTransformContext(vm), defaultTransforms);
76106
- if (resolved === void 0 || resolved === null || resolved === "") return binding.fallback;
76107
- return resolved;
76108
- } catch (err) {
76109
- if (shouldLogWarnings) console.warn(`bindings: failed to parse loader param binding for block "${meta?.blockKind ?? "unknown"}"`, err);
76110
- return;
76111
- }
76112
- const out = {};
76113
- for (const [k, v] of Object.entries(input)) out[k] = resolveParamsBindings(v, vm, meta);
76114
- return out;
75978
+ function PageContent(props) {
75979
+ const { page, runtimeJoins, siteId, resolvedData, bookingOfferingPresets, mailingList, bookingTimeZone, routeMap, pagesByIdentifier, entriesByIdentifier, wrapBlock, registry, blockOverrides, sdkConfig, customBlocks, supabaseUrl, mediaAssets, apiBaseUrl, portalToken, previewToken, readAuthority, dataContext } = props;
75980
+ const rendererCommonProps = {
75981
+ page,
75982
+ runtimeJoins,
75983
+ dataContext: {
75984
+ siteId,
75985
+ ...buildPageRouteRenderContext(dataContext),
75986
+ apiBaseUrl,
75987
+ portalToken,
75988
+ previewToken,
75989
+ readAuthority: readAuthority ?? dataContext.readAuthority,
75990
+ resolvedData,
75991
+ bookingOfferingPresets: bookingOfferingPresets ?? [],
75992
+ mailingList: mailingList ?? dataContext.mailingList,
75993
+ bookingTimeZone: resolveSdkBookingTimeZone(bookingTimeZone),
75994
+ routes: routeMap,
75995
+ pagesByIdentifier,
75996
+ entriesByIdentifier,
75997
+ supabaseUrl,
75998
+ mediaAssets,
75999
+ imageResolveContext: {
76000
+ siteId,
76001
+ supabaseUrl,
76002
+ mediaAssets
76003
+ }
76004
+ },
76005
+ routeMap,
76006
+ wrapBlock,
76007
+ registry,
76008
+ sdkConfig: sdkConfig ? { customBlocks: sdkConfig.customBlocks } : null,
76009
+ customBlocks
76010
+ };
76011
+ const content = isOverrideOnlyPage(props) ? /* @__PURE__ */ jsx(PageRenderer, {
76012
+ ...rendererCommonProps,
76013
+ rendering: { kind: "overrides-only" },
76014
+ blockOverrides: props.blockOverrides
76015
+ }) : /* @__PURE__ */ jsx(PageRenderer, {
76016
+ ...rendererCommonProps,
76017
+ theme: props.theme,
76018
+ themeTokens: resolvePageThemeTokens(props),
76019
+ blockOverrides
76020
+ });
76021
+ return isOverrideOnlyPage(props) ? renderWithOverrideOnlyRuntime({
76022
+ runtime: props.rendering.runtime,
76023
+ children: content
76024
+ }) : renderWithSdkThemeRuntime({
76025
+ themeRuntime: props.themeRuntime ?? defaultPageThemeRuntime,
76026
+ theme: props.theme,
76027
+ children: content
76028
+ });
76115
76029
  }
76116
- function resolveBinding(path, vm) {
76117
- const segments = splitPath(path);
76118
- if (!segments.length) return void 0;
76119
- const [first, ...rest] = segments;
76120
- let source = vm;
76121
- if (first === "$root") {
76122
- source = vm;
76123
- return readFromSource(source, [first, ...rest]);
76124
- }
76125
- if (first === "content") {
76126
- source = vm.content;
76127
- return readFromSource(source, rest);
76128
- }
76129
- const contentResult = readFromSource(vm.content, segments);
76130
- if (contentResult !== void 0) return contentResult;
76131
- return readFromSource(vm, segments);
76030
+ //#endregion
76031
+ //#region src/rendering/components/Page.tsx
76032
+ const HydratorWithContextProps$1 = BlocksIslandsHydrator;
76033
+ /**
76034
+ * Default renderer for Riverbank CMS pages.
76035
+ *
76036
+ * This component expects all data to be provided via props and automatically
76037
+ * mounts the CMS island hydration bootstrap.
76038
+ * For data fetching, use:
76039
+ * - Server-side: `await loadPage({ client, siteId, path })`
76040
+ * - Client-side: `usePage({ client, siteId, path })`
76041
+ *
76042
+ * @example Server-side (Next.js App Router)
76043
+ * ```tsx
76044
+ * import { createRiverbankClient } from '@riverbankcms/sdk';
76045
+ * import { loadPage, Page } from '@riverbankcms/sdk/rendering';
76046
+ *
76047
+ * const client = createRiverbankClient({ apiKey, baseUrl });
76048
+ *
76049
+ * export default async function PageRoute({ params }) {
76050
+ * const pageData = await loadPage({
76051
+ * client,
76052
+ * siteId: 'site-id',
76053
+ * path: `/${params.slug}`,
76054
+ * });
76055
+ *
76056
+ * return <Page {...pageData} />;
76057
+ * }
76058
+ * ```
76059
+ *
76060
+ * @example Client-side
76061
+ * ```tsx
76062
+ * import { createRiverbankClient } from '@riverbankcms/sdk';
76063
+ * import { usePage, Page } from '@riverbankcms/sdk/rendering';
76064
+ *
76065
+ * const client = createRiverbankClient({ apiKey, baseUrl });
76066
+ *
76067
+ * function MyPage({ path }) {
76068
+ * const pageData = usePage({ client, siteId: 'site-id', path });
76069
+ *
76070
+ * if (pageData.loading) return <LoadingState />;
76071
+ * if (pageData.error) return <ErrorState error={pageData.error} />;
76072
+ * if (!pageData.page) return <NotFound />;
76073
+ *
76074
+ * return <Page {...pageData} />;
76075
+ * }
76076
+ * ```
76077
+ */
76078
+ function Page(props) {
76079
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(HydratorWithContextProps$1, { ...toPageHydrationBootstrapConfig(props) }), /* @__PURE__ */ jsx(PageContent, { ...props })] });
76132
76080
  }
76133
- function splitPath(path) {
76134
- const PATH_SEPARATOR_REGEX = /\./g;
76135
- const BRACKET_ACCESS_REGEX = /\[(?<token>[^\]]+)\]/g;
76136
- const segments = [];
76137
- const parts = path.split(PATH_SEPARATOR_REGEX);
76138
- for (const raw of parts) {
76139
- if (!raw) continue;
76140
- const baseMatch = raw.match(/^([^\[]+)/);
76141
- if (baseMatch && baseMatch[1]) segments.push(baseMatch[1]);
76142
- const bracketMatches = raw.matchAll(BRACKET_ACCESS_REGEX);
76143
- for (const match of bracketMatches) {
76144
- const token = match.groups?.token ?? "";
76145
- if (token.startsWith("\"") || token.startsWith("'")) segments.push(token.slice(1, -1));
76146
- else if (/^\d+$/.test(token)) segments.push(Number(token));
76147
- else segments.push(token);
76148
- }
76149
- if (!baseMatch && !raw.includes("[")) segments.push(raw);
76081
+ //#endregion
76082
+ //#region src/env.ts
76083
+ /**
76084
+ * Error thrown when required environment variables are missing
76085
+ */
76086
+ var RiverbankEnvError = class extends Error {
76087
+ constructor(message, missingVars) {
76088
+ super(message);
76089
+ this.missingVars = missingVars;
76090
+ this.name = "RiverbankEnvError";
76150
76091
  }
76151
- return segments;
76152
- }
76153
- function readFromSource(source, segments) {
76154
- return segments.reduce((current, segment) => {
76155
- if (current === void 0 || current === null) return void 0;
76156
- if (typeof segment === "number") {
76157
- if (Array.isArray(current)) return current[segment];
76158
- return;
76159
- }
76160
- if (typeof current === "object" && current !== null && segment in current) return current[segment];
76161
- }, source);
76162
- }
76163
- function isNonProductionEnv() {
76164
- if (typeof globalThis === "undefined") return true;
76165
- return globalThis.process?.env?.NODE_ENV !== "production";
76092
+ };
76093
+ /**
76094
+ * Get the environment variable prefix based on target
76095
+ */
76096
+ function getEnvPrefix(target) {
76097
+ return target === "remote" ? "RIVERBANK_REMOTE" : "RIVERBANK_LOCAL";
76166
76098
  }
76167
- function isNonArrayObject(value) {
76168
- return typeof value === "object" && value !== null && !Array.isArray(value);
76099
+ /**
76100
+ * Detect the environment target from RIVERBANK_ENV
76101
+ */
76102
+ function detectTarget() {
76103
+ const env = process.env.RIVERBANK_ENV?.toLowerCase();
76104
+ if (env === "remote" || env === "production" || env === "prod") return "remote";
76105
+ return "local";
76169
76106
  }
76170
- function safeJsonStringify(value) {
76171
- try {
76172
- return JSON.stringify(value);
76173
- } catch {
76174
- return;
76175
- }
76107
+ /**
76108
+ * Detect if preview mode is enabled.
76109
+ * Uses RIVERBANK_PREVIEW_MODE first, then falls back to RIVERBANK_PREVIEW for backward compat.
76110
+ */
76111
+ function detectPreviewMode() {
76112
+ const previewMode = process.env.RIVERBANK_PREVIEW_MODE;
76113
+ if (previewMode !== void 0 && previewMode !== "") return previewMode === "true";
76114
+ const previewLegacy = process.env.RIVERBANK_PREVIEW;
76115
+ if (previewLegacy !== void 0 && previewLegacy !== "") return previewLegacy === "true";
76116
+ return process.env.VERCEL_ENV === "preview";
76176
76117
  }
76177
76118
  /**
76178
- * Coerce value to string for API params
76119
+ * Validate that an API key matches the expected format for its type
76179
76120
  */
76180
- function coerceToString(value) {
76181
- if (value === null || value === void 0) return "";
76182
- if (Array.isArray(value)) {
76183
- if (value.some(isNonArrayObject)) {
76184
- const json = safeJsonStringify(value);
76185
- if (typeof json === "string") return json;
76186
- }
76187
- return value.map(coerceToString).join(",");
76188
- }
76189
- if (isNonArrayObject(value)) {
76190
- const json = safeJsonStringify(value);
76191
- if (typeof json === "string") return json;
76121
+ function validateKeyType(key, expectedType) {
76122
+ const isPreviewKey = key.startsWith("bld_preview_sk_");
76123
+ const isContentKey = key.startsWith("bld_live_sk_");
76124
+ if (expectedType === "preview" && !isPreviewKey) {
76125
+ if (isContentKey) throw new RiverbankEnvError("Preview mode is enabled (RIVERBANK_PREVIEW_MODE=true) but a content key was provided. Preview mode requires a preview API key (bld_preview_sk_...) to access draft content. Either:\n 1. Set RIVERBANK_*_PREVIEW_API_KEY with your preview key, or\n 2. Set RIVERBANK_PREVIEW_MODE=false to fetch published content instead.", []);
76126
+ throw new RiverbankEnvError(`Invalid API key format for preview mode. Expected key starting with bld_preview_sk_`, []);
76192
76127
  }
76193
- if (typeof value === "string" || typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") return String(value);
76194
- return "";
76195
- }
76196
- //#endregion
76197
- //#region ../blocks/src/system/data/loaderEndpoints.ts
76198
- const SUPPORTED_LOADER_ENDPOINTS$1 = [
76199
- "listPublishedEntries",
76200
- "getPublishedEntryPreview",
76201
- "listPublicEvents",
76202
- "listPublicEventCalendarWindow",
76203
- "listPublicRecurringSchedule",
76204
- "getPublicEventDetails",
76205
- "listPublicRouteCandidates",
76206
- "listPublicTeamMembers",
76207
- "listPublicProducts",
76208
- "listPublicPasses",
76209
- "listPublicMemberships",
76210
- "getPublicFormById",
76211
- "getPublicBookingServices",
76212
- "getPublicWeeklySlotAvailability"
76213
- ];
76214
- //#endregion
76215
- //#region ../blocks/src/system/data/batching.ts
76216
- function stableNormalize(value) {
76217
- if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") return value;
76218
- if (Array.isArray(value)) return value.map(stableNormalize);
76219
- if (typeof value === "object" && value) {
76220
- const obj = value;
76221
- const keys = Object.keys(obj).sort();
76222
- const out = {};
76223
- for (const key of keys) {
76224
- const v = obj[key];
76225
- if (v === void 0) continue;
76226
- out[key] = stableNormalize(v);
76128
+ if (expectedType === "content" && !isContentKey) {
76129
+ if (isPreviewKey) {
76130
+ console.debug("[getRiverbankEnv] Using preview key for published content. Consider using a content key (bld_live_sk_...) for production.");
76131
+ return;
76227
76132
  }
76228
- return out;
76133
+ throw new RiverbankEnvError(`Invalid API key format for content access. Expected key starting with bld_live_sk_ or bld_preview_sk_`, []);
76229
76134
  }
76230
- if (typeof value === "bigint" || typeof value === "symbol" || typeof value === "undefined") return String(value);
76231
- return null;
76232
76135
  }
76233
- const RichText$1 = RichText$2;
76234
- //#endregion
76235
- //#region ../blocks/src/system/customize/facets.ts
76236
- function defineCustomizeFacet(definition) {
76237
- return definition;
76136
+ /**
76137
+ * Get runtime environment configuration with automatic API key selection.
76138
+ *
76139
+ * This helper reads environment variables and automatically selects the correct
76140
+ * API key based on the current environment and preview mode:
76141
+ *
76142
+ * - When `RIVERBANK_PREVIEW_MODE=true`: Uses preview API key (bld_preview_sk_...)
76143
+ * - When `RIVERBANK_PREVIEW_MODE=false` (default): Uses content API key (bld_live_sk_...)
76144
+ *
76145
+ * Environment variable patterns:
76146
+ * - `RIVERBANK_ENV`: 'local' (default) or 'remote'
76147
+ * - `RIVERBANK_PREVIEW_MODE`: 'true' or 'false' (default)
76148
+ * - `RIVERBANK_{LOCAL|REMOTE}_SITE_ID`: Site ID
76149
+ * - `RIVERBANK_{LOCAL|REMOTE}_DASHBOARD_URL`: Dashboard URL
76150
+ * - `RIVERBANK_{LOCAL|REMOTE}_API_KEY`: Content/live API key
76151
+ * - `RIVERBANK_{LOCAL|REMOTE}_PREVIEW_API_KEY`: Preview API key
76152
+ *
76153
+ * @returns Environment configuration with auto-selected API key
76154
+ * @throws {RiverbankEnvError} If required environment variables are missing
76155
+ *
76156
+ * @example
76157
+ * ```ts
76158
+ * // lib/builder-client.ts
76159
+ * import { getRiverbankEnv } from '@riverbankcms/sdk/env';
76160
+ * import { createRiverbankClient } from '@riverbankcms/sdk';
76161
+ *
76162
+ * const env = getRiverbankEnv();
76163
+ *
76164
+ * export const client = createRiverbankClient({
76165
+ * apiKey: env.apiKey,
76166
+ * baseUrl: env.baseUrl,
76167
+ * });
76168
+ *
76169
+ * export const siteId = env.siteId;
76170
+ * ```
76171
+ */
76172
+ function getRiverbankEnv() {
76173
+ const target = detectTarget();
76174
+ const previewMode = detectPreviewMode();
76175
+ const prefix = getEnvPrefix(target);
76176
+ const siteId = process.env[`${prefix}_SITE_ID`];
76177
+ const dashboardUrl = process.env[`${prefix}_DASHBOARD_URL`];
76178
+ const contentKey = process.env[`${prefix}_API_KEY`];
76179
+ const previewKey = process.env[`${prefix}_PREVIEW_API_KEY`];
76180
+ const missingVars = [];
76181
+ if (!siteId) missingVars.push(`${prefix}_SITE_ID`);
76182
+ if (!dashboardUrl) missingVars.push(`${prefix}_DASHBOARD_URL`);
76183
+ let apiKey;
76184
+ let keyType;
76185
+ if (previewMode) {
76186
+ apiKey = previewKey;
76187
+ keyType = "preview";
76188
+ if (!apiKey) missingVars.push(`${prefix}_PREVIEW_API_KEY`);
76189
+ } else {
76190
+ apiKey = contentKey || previewKey;
76191
+ keyType = contentKey ? "content" : "preview";
76192
+ if (!apiKey) missingVars.push(`${prefix}_API_KEY`);
76193
+ }
76194
+ if (missingVars.length > 0) throw new RiverbankEnvError(`Missing required environment variables for Riverbank SDK:\n` + missingVars.map((v) => ` - ${v}`).join("\n") + `\n\nCurrent settings: RIVERBANK_ENV=${process.env.RIVERBANK_ENV || "local"}, RIVERBANK_PREVIEW_MODE=${process.env.RIVERBANK_PREVIEW_MODE || "false"}`, missingVars);
76195
+ if (!apiKey || !dashboardUrl || !siteId) throw new RiverbankEnvError("Required environment variables missing", missingVars);
76196
+ validateKeyType(apiKey, keyType);
76197
+ let baseUrl = dashboardUrl;
76198
+ if (!baseUrl.endsWith("/api")) baseUrl = baseUrl.replace(/\/$/, "") + "/api";
76199
+ return {
76200
+ target,
76201
+ previewMode,
76202
+ siteId,
76203
+ baseUrl,
76204
+ apiKey,
76205
+ keyType
76206
+ };
76238
76207
  }
76239
- const systemCustomizeFacetDefinitions = [defineCustomizeFacet({
76240
- blockKind: "block.event-calendar",
76241
- id: "eventCalendar.listLayout",
76242
- label: "List style",
76243
- values: eventCalendarListLayoutOptions.map((option) => ({
76244
- value: option.id,
76245
- label: option.label
76246
- })),
76247
- defaultValue: "stack",
76248
- target: { kind: "event-calendar-list-layout-content" },
76249
- appliesToLayoutVariants: eventCalendarListLayoutCompatibleDisplayModeValues
76250
- })];
76251
- systemCustomizeFacetDefinitions.map((definition) => definition.id);
76252
- Array.from(new Set(systemCustomizeFacetDefinitions.flatMap((definition) => definition.values.map((option) => option.value))));
76253
- const backgroundColorTokenNames = backgroundAppearanceColorTokenNames;
76254
- const backgroundColorTokenNameSet = new Set(backgroundColorTokenNames);
76255
- const backgroundColorTokens = toBackgroundColorTokens(backgroundColorTokenNames);
76256
- const quickBackgroundColorTokens = toBackgroundColorTokens(backgroundAppearanceQuickColorTokenNames);
76257
- backgroundColorTokens.filter((token) => !quickBackgroundColorTokens.includes(token));
76258
- function toBackgroundColorTokens(tokenNames) {
76259
- return tokenNames.flatMap((name) => {
76260
- const token = parseBackgroundColorToken(name);
76261
- if (!token) return [];
76262
- return [token];
76263
- });
76208
+ /**
76209
+ * Get the fixed main navigation menu object.
76210
+ * Returns null when the runtime payload is incomplete.
76211
+ *
76212
+ * @example
76213
+ * ```ts
76214
+ * const menu = getPrimaryNavigation(siteData.navigation);
76215
+ * console.log(menu?.location); // "main"
76216
+ * ```
76217
+ */
76218
+ function getPrimaryNavigation(navigation) {
76219
+ if (!navigation || navigation.length === 0) return null;
76220
+ return navigation.find((menu) => menu.location === "main") ?? null;
76264
76221
  }
76265
- function parseBackgroundColorToken(value) {
76266
- if (typeof value !== "string") return null;
76267
- const normalized = value.trim();
76268
- if (!backgroundColorTokenNameSet.has(normalized)) return null;
76269
- const token = parseBackgroundAppearanceColorToken(normalized);
76270
- if (!token) return null;
76271
- return token ? token : null;
76222
+ function getFooterNavigationByRole(navigation, role) {
76223
+ if (!navigation || navigation.length === 0) return null;
76224
+ const canonicalLocation = role === "main" ? "footer" : "legal";
76225
+ return navigation.find((menu) => menu.location === canonicalLocation) ?? null;
76272
76226
  }
76273
- //#endregion
76274
- //#region src/rendering/helpers/siteCustomBlocks.ts
76275
76227
  /**
76276
- * Prefer the DB-backed custom block manifest list (`site.customBlocks`) when available,
76277
- * but fall back to SDK config custom blocks (`site.sdkConfig.customBlocks`) for SDK-mode sites.
76278
- *
76279
- * This avoids subtle DX bugs where one source is populated but the renderer/prefetch layer
76280
- * is looking at the other.
76228
+ * Resolve alt text with fallback.
76229
+ * Returns the provided alt if non-empty, otherwise falls back to the provided fallback or 'Site logo'.
76230
+ * @internal
76281
76231
  */
76282
- function resolveSiteCustomBlocks(site) {
76283
- const dbBlocks = site.customBlocks;
76284
- if (Array.isArray(dbBlocks) && dbBlocks.length > 0) return dbBlocks;
76285
- const sdkBlocks = site.sdkConfig?.customBlocks;
76286
- if (Array.isArray(sdkBlocks) && sdkBlocks.length > 0) return sdkBlocks;
76232
+ function resolveAltText(alt, fallback) {
76233
+ return alt && alt.trim().length > 0 ? alt : fallback ?? "Site logo";
76234
+ }
76235
+ function readNavigationItemPayload(item) {
76236
+ return item.url ?? null;
76237
+ }
76238
+ function isPortalEnabled(options) {
76239
+ return options?.portalEnabled === true;
76240
+ }
76241
+ function isCommerceEnabled(options) {
76242
+ return options?.commerceEnabled === true;
76243
+ }
76244
+ function resolvePortalHref(link) {
76245
+ return link.path?.trim() || "/portal";
76246
+ }
76247
+ function resolveCheckoutHref(options) {
76248
+ if (options?.checkoutHref === null) return null;
76249
+ const href = options?.checkoutHref?.trim();
76250
+ return href && href.length > 0 ? href : "/checkout";
76251
+ }
76252
+ function resolvePortalLabel(link, options) {
76253
+ const loggedOutLabel = link.labels?.loggedOut?.trim() || PORTAL_NAV_DEFAULT_LABELS.loggedOut;
76254
+ const loggedInLabel = link.labels?.loggedIn?.trim() || PORTAL_NAV_DEFAULT_LABELS.loggedIn;
76255
+ return options?.hasPortalSession ? loggedInLabel : loggedOutLabel;
76256
+ }
76257
+ function resolveItemLabel(link, fallbackLabel, options) {
76258
+ if (link?.kind === "portal") return resolvePortalLabel(link, options);
76259
+ if (link?.kind === "cart") return resolveCartVisibleLabel(link) ?? fallbackLabel;
76260
+ return fallbackLabel;
76287
76261
  }
76288
- function readBlockContentId(value, name) {
76289
- if (value === null || value === void 0) return null;
76290
- if (typeof value === "string") return value;
76291
- throw new Error(`Invalid ${name} in page: expected string or null`);
76262
+ function resolveCartVisibleLabel(link) {
76263
+ if (link.label.kind !== "icon-with-label") return null;
76264
+ const label = link.label.label.trim();
76265
+ return label.length > 0 ? label : null;
76292
76266
  }
76293
- function readTransportedBlockIdentity(block, kind, stage) {
76267
+ function resolveCartAriaLabel(link, fallbackLabel) {
76268
+ const fallback = fallbackLabel.trim();
76269
+ return resolveCartVisibleLabel(link) ?? (fallback.length > 0 ? fallback : "Cart");
76270
+ }
76271
+ function buildCartNavViewModel(link, fallbackLabel, options) {
76294
76272
  return {
76295
- draftContentId: readBlockContentId(block.draftContentId, "draft content id"),
76296
- publishedPlacement: stage === "preview" ? readPublishedBlockPlacement(readBlockContentId(block.publishedContentId, "published content id"), sanitizeNullableSdkRuntimeBlockContent(kind, readNestedContentRecord(block.publishedContent))) : null
76273
+ visibleLabel: resolveCartVisibleLabel(link),
76274
+ badge: link.badge,
76275
+ ariaLabel: resolveCartAriaLabel(link, fallbackLabel),
76276
+ checkoutHref: resolveCheckoutHref(options)
76297
76277
  };
76298
76278
  }
76299
- function convertPageResponseBlock(block, stage) {
76300
- if (!isRecord$8(block)) throw new Error("Invalid block format in page API response");
76301
- const header = readTransportedBlockHeader(block);
76302
- const admission = readInvalidBlockAdmission(block.admission);
76279
+ function deriveRenderableNavigationLink(item, options) {
76280
+ const payload = readNavigationItemPayload(item);
76281
+ if (!payload) return null;
76282
+ if (payload.kind === "portal" && !isPortalEnabled(options)) return null;
76283
+ if (payload.kind === "cart" && !isCommerceEnabled(options)) return null;
76303
76284
  return {
76304
- ...header,
76305
- ...readTransportedBlockIdentity(block, header.kind, stage),
76306
- content: sanitizeSdkRuntimeBlockContent(header.kind, readContentRecord(block.content) ?? {}),
76307
- draftContent: sanitizeNullableSdkRuntimeBlockContent(header.kind, readNestedContentRecord(block.draftContent)),
76308
- ...admission ? { admission } : {}
76285
+ id: item.id,
76286
+ label: resolveItemLabel(payload, item.label, options),
76287
+ payload,
76288
+ isExternal: isExternalLink(payload),
76289
+ ...payload.kind === "cart" ? { cart: buildCartNavViewModel(payload, item.label, options) } : {}
76309
76290
  };
76310
76291
  }
76311
- function readTransportedBlockHeader(block) {
76312
- if (typeof block.id !== "string" && block.id !== null) throw new Error(`Invalid block id in page: expected string or null, got ${typeof block.id}`);
76313
- if (typeof block.kind !== "string") throw new Error(`Invalid block kind in page: expected string, got ${typeof block.kind}`);
76314
- if (typeof block.purpose !== "string") throw new Error(`Invalid block purpose in page: expected string, got ${typeof block.purpose}`);
76315
- if (block.contentVersionId !== void 0 && block.contentVersionId !== null && typeof block.contentVersionId !== "string") throw new Error(`Invalid content version id in page: expected string or null, got ${typeof block.contentVersionId}`);
76292
+ function buildNavLinkFromResolvedHref(item, href) {
76293
+ if (!href) return null;
76316
76294
  return {
76317
- id: block.id,
76318
- ...block.contentVersionId !== void 0 ? { contentVersionId: block.contentVersionId } : {},
76319
- kind: block.kind,
76320
- purpose: block.purpose
76295
+ kind: "link",
76296
+ id: item.id,
76297
+ label: item.label,
76298
+ href,
76299
+ link: { href },
76300
+ isExternal: item.isExternal,
76301
+ ...item.cart ? { cart: item.cart } : {}
76321
76302
  };
76322
76303
  }
76323
- function readInvalidBlockAdmission(value) {
76324
- if (!isRecord$8(value) || value.kind !== "invalid" || !isRecord$8(value.error)) return null;
76325
- if (value.error.kind !== "invalid_manifest_content" && value.error.kind !== "manifest_unavailable") return null;
76326
- return value;
76304
+ /**
76305
+ * Determines if a navigation item's link is external.
76306
+ */
76307
+ function isExternalLink(link) {
76308
+ if (!link) return false;
76309
+ return link.kind === "external";
76327
76310
  }
76328
- function buildPageOutline(input) {
76329
- return {
76330
- name: input.name,
76331
- path: input.path ?? input.fallbackPath,
76332
- purpose: input.purpose,
76333
- blocks: input.blocks.map((block) => convertPageResponseBlock(block, input.previewStage))
76334
- };
76311
+ /**
76312
+ * Build a map of children items by parent ID.
76313
+ * Also warns about deeply nested items (grandchildren) which CMS shouldn't allow.
76314
+ * @internal
76315
+ */
76316
+ function buildChildrenByParentId(items) {
76317
+ const childrenByParentId = /* @__PURE__ */ new Map();
76318
+ const itemsById = /* @__PURE__ */ new Map();
76319
+ for (const item of items) itemsById.set(item.id, item);
76320
+ for (const item of items) if (item.parentId) {
76321
+ if (itemsById.get(item.parentId)?.parentId && typeof process !== "undefined" && process.env.NODE_ENV !== "production") {
76322
+ console.warn(`[SDK Navigation] Deeply nested item detected: "${item.label}" (id: ${item.id}). Only 1 level of nesting is supported. This item will be ignored.`);
76323
+ continue;
76324
+ }
76325
+ const siblings = childrenByParentId.get(item.parentId) ?? [];
76326
+ siblings.push(item);
76327
+ childrenByParentId.set(item.parentId, siblings);
76328
+ }
76329
+ return childrenByParentId;
76335
76330
  }
76336
- function buildRenderablePageOutline(input) {
76337
- const page = buildPageOutline(input);
76331
+ /**
76332
+ * Generic nested structure builder.
76333
+ * @internal
76334
+ */
76335
+ function buildNestedStructure(items, options) {
76336
+ const childrenByParentId = buildChildrenByParentId(items);
76337
+ const rootItems = items.filter((item) => !item.parentId).sort((a, b) => (a.orderIndex ?? a.position ?? 0) - (b.orderIndex ?? b.position ?? 0));
76338
+ const result = [];
76339
+ let ctaItem = null;
76340
+ for (const item of rootItems) {
76341
+ if (options.extractCta && !ctaItem && Boolean(item.isCta) && item.urlType !== "dropdown") {
76342
+ const link = options.toLink(item);
76343
+ if (link) {
76344
+ ctaItem = link;
76345
+ continue;
76346
+ }
76347
+ }
76348
+ const childRecords = childrenByParentId.get(item.id) ?? [];
76349
+ const hasChildren = childRecords.length > 0;
76350
+ if (item.urlType === "dropdown" || hasChildren) {
76351
+ const children = childRecords.sort((a, b) => (a.orderIndex ?? a.position ?? 0) - (b.orderIndex ?? b.position ?? 0)).map(options.toLink).filter((child) => child !== null);
76352
+ if (children.length > 0) result.push(options.createDropdown(item.id, item.label, children));
76353
+ continue;
76354
+ }
76355
+ const link = options.toLink(item);
76356
+ if (link) result.push(link);
76357
+ }
76338
76358
  return {
76339
- ...page,
76340
- blocks: page.blocks.map((block) => admitSdkRuntimePageBlock(block, input.customBlocks))
76359
+ items: result,
76360
+ ctaItem
76341
76361
  };
76342
76362
  }
76343
- function admitSdkRuntimePageBlock(block, customBlocks) {
76344
- const base = {
76345
- id: block.id,
76346
- draftContentId: block.draftContentId,
76347
- publishedPlacement: block.publishedPlacement,
76348
- ...block.contentVersionId !== void 0 ? { contentVersionId: block.contentVersionId } : {},
76349
- kind: block.kind,
76350
- purpose: block.purpose,
76351
- ...block.bindings ? { bindings: block.bindings } : {}
76363
+ /**
76364
+ * Build a Menu from navigation data with pre-resolved hrefs.
76365
+ * Supports dropdown containers with nested children.
76366
+ *
76367
+ * @param navigation - Navigation menus from site data
76368
+ * @param routes - Route map for resolving internal links
76369
+ * @param options - Include identifier maps to resolve canonical `page`/`entry` links.
76370
+ *
76371
+ * @example
76372
+ * ```ts
76373
+ * const menu = buildMenu(siteData.navigation, siteData.routes, {
76374
+ * pagesByIdentifier: siteData.pagesByIdentifier,
76375
+ * entriesByIdentifier: siteData.entriesByIdentifier,
76376
+ * });
76377
+ * menu.items.forEach(item => {
76378
+ * if (item.kind === 'dropdown') {
76379
+ * console.log(item.children);
76380
+ * }
76381
+ * });
76382
+ * ```
76383
+ */
76384
+ function buildMenu(navigation, routes, options) {
76385
+ const menu = getPrimaryNavigation(navigation);
76386
+ if (!menu) return {
76387
+ items: [],
76388
+ ctaItem: null
76352
76389
  };
76353
- const transportedAdmission = readInvalidBlockAdmission(block.admission);
76354
- if (transportedAdmission) return invalidRenderableBlock(base, transportedAdmission.error);
76355
- const manifest = resolveSdkBlockManifest(block.kind, customBlocks);
76356
- if (!manifest) return invalidRenderableBlock(base, { kind: "manifest_unavailable" });
76357
- const content = block.content ?? {};
76358
- const renderable = admitTransportedRenderableManifestContent(compileManifestContentContract(manifest), content);
76359
- if (!renderable.ok) return invalidRenderableBlock(base, {
76360
- kind: "invalid_manifest_content",
76361
- error: renderable.error
76390
+ const toNavLink = (item) => {
76391
+ const renderable = deriveRenderableNavigationLink(item, options);
76392
+ if (!renderable) return null;
76393
+ return buildNavLinkFromResolvedHref(renderable, resolveHref(renderable.payload, routes, options));
76394
+ };
76395
+ const { items, ctaItem } = buildNestedStructure(menu.items, {
76396
+ toLink: toNavLink,
76397
+ createDropdown: (id, label, children) => ({
76398
+ kind: "dropdown",
76399
+ id,
76400
+ label,
76401
+ children
76402
+ }),
76403
+ extractCta: true
76362
76404
  });
76363
76405
  return {
76364
- ...base,
76365
- admission: {
76366
- kind: "renderable",
76367
- content: renderable.value
76368
- }
76406
+ items,
76407
+ ctaItem: ctaItem ? {
76408
+ ...ctaItem,
76409
+ variant: "primary"
76410
+ } : null
76369
76411
  };
76370
76412
  }
76371
- function resolveSdkBlockManifest(blockKind, customBlocks) {
76372
- const customBlock = customBlocks?.find((candidate) => candidate.id === blockKind);
76373
- return customBlock ? parseFieldDefinitions(customBlock.fields) : getBlockDefinition(blockKind)?.manifest ?? null;
76413
+ /**
76414
+ * Build a Menu from the footer navigation data.
76415
+ * Returns empty menu if no footer menu is designated.
76416
+ *
76417
+ * @param navigation - Navigation menus from site data
76418
+ * @param routes - Route map for resolving internal links
76419
+ * @param options - Include identifier maps to resolve canonical `page`/`entry` links.
76420
+ *
76421
+ * @example
76422
+ * ```ts
76423
+ * const footerMenu = buildFooterMenu(siteData.navigation, siteData.routes, {
76424
+ * pagesByIdentifier: siteData.pagesByIdentifier,
76425
+ * entriesByIdentifier: siteData.entriesByIdentifier,
76426
+ * });
76427
+ * footerMenu.items.forEach(item => {
76428
+ * if (item.kind === 'dropdown') {
76429
+ * // Footer renders children expanded, not as hover dropdowns
76430
+ * console.log(item.children);
76431
+ * }
76432
+ * });
76433
+ * ```
76434
+ */
76435
+ function buildFooterMenu(navigation, routes, options) {
76436
+ return buildFooterMenuForRole(navigation, routes, "main", options);
76374
76437
  }
76375
- function invalidRenderableBlock(block, error) {
76438
+ function buildFooterMenuForRole(navigation, routes, role, options) {
76439
+ const menu = getFooterNavigationByRole(navigation, role);
76440
+ if (!menu) return {
76441
+ items: [],
76442
+ ctaItem: null,
76443
+ groups: [],
76444
+ links: []
76445
+ };
76446
+ const toNavLink = (item) => {
76447
+ const renderable = deriveRenderableNavigationLink(item, options);
76448
+ if (!renderable) return null;
76449
+ return buildNavLinkFromResolvedHref(renderable, resolveHref(renderable.payload, routes, options));
76450
+ };
76451
+ const built = buildNestedStructure(menu.items, {
76452
+ toLink: toNavLink,
76453
+ createDropdown: (id, label, children) => ({
76454
+ kind: "dropdown",
76455
+ id,
76456
+ label,
76457
+ children
76458
+ }),
76459
+ extractCta: false
76460
+ });
76461
+ const groups = built.items.filter((item) => item.kind === "dropdown");
76462
+ const links = built.items.filter((item) => item.kind === "link");
76376
76463
  return {
76377
- ...block,
76378
- admission: {
76379
- kind: "invalid",
76380
- error
76381
- }
76464
+ items: built.items,
76465
+ ctaItem: null,
76466
+ groups,
76467
+ links
76382
76468
  };
76383
76469
  }
76384
- function isRecord$8(value) {
76385
- return Boolean(value) && typeof value === "object" && !Array.isArray(value);
76470
+ /**
76471
+ * Resolve href from a link payload using route map.
76472
+ * @internal
76473
+ */
76474
+ function resolveHref(link, routes, options) {
76475
+ if (!link) return null;
76476
+ if (link.kind === "external" || link.kind === "url") return link.href || null;
76477
+ if (link.kind === "portal") return isPortalEnabled(options) ? resolvePortalHref(link) : null;
76478
+ if (link.kind === "cart") return isCommerceEnabled(options) ? resolveCheckoutHref(options) : null;
76479
+ const stage = normalizeRenderStage(options?.previewStage);
76480
+ if (link.kind === "internal") return resolveRouteHrefWithFallback(link.routeId, link.href ?? null, routes, stage);
76481
+ if (link.kind === "page") {
76482
+ const routeIdFromPayload = readRouteIdFromLink(link);
76483
+ const routeIdFromIdentifierMap = options?.pagesByIdentifier?.[link.identifier] ?? null;
76484
+ return resolveRouteHrefWithFallback(routeIdFromPayload ?? routeIdFromIdentifierMap, readHrefFromLink(link), routes, stage);
76485
+ }
76486
+ if (link.kind === "entry") {
76487
+ const routeIdFromPayload = readRouteIdFromLink(link);
76488
+ const routeIdFromIdentifierMap = readEntryRouteIdFromIdentifierMap(options, link.contentType, link.identifier);
76489
+ return resolveRouteHrefWithFallback(routeIdFromPayload ?? routeIdFromIdentifierMap, readHrefFromLink(link), routes, stage);
76490
+ }
76491
+ return null;
76386
76492
  }
76387
- function readContentRecord(value) {
76388
- return isRecord$8(value) ? value : void 0;
76493
+ function resolveRouteHrefWithFallback(routeId, fallbackHref, routes, stage) {
76494
+ if (!routeId) return fallbackHref;
76495
+ const resolved = resolveRouteHrefForStage(routeId, routes, stage);
76496
+ if (resolved) return resolved;
76497
+ const route = routes[routeId];
76498
+ if (!route) return fallbackHref;
76499
+ if (!isRouteVisibleInStage(route, stage)) return null;
76500
+ return fallbackHref;
76389
76501
  }
76390
- function readNestedContentRecord(value) {
76391
- if (!isRecord$8(value)) return null;
76392
- return readContentRecord(value.data) ?? null;
76502
+ function readRouteIdFromLink(link) {
76503
+ if (!("routeId" in link) || typeof link.routeId !== "string") return null;
76504
+ return link.routeId;
76393
76505
  }
76394
- function sanitizeSdkRuntimeBlockContent(blockKind, content) {
76395
- if (blockKind !== "block.newsletter-signup") return content;
76396
- const sanitized = sanitizeNewsletterSignupPublicContent(content);
76397
- return isRecord$8(sanitized) ? sanitized : {};
76506
+ function readHrefFromLink(link) {
76507
+ if (!("href" in link) || typeof link.href !== "string") return null;
76508
+ return link.href;
76398
76509
  }
76399
- function sanitizeNullableSdkRuntimeBlockContent(blockKind, content) {
76400
- return content ? sanitizeSdkRuntimeBlockContent(blockKind, content) : null;
76510
+ function readEntryRouteIdFromIdentifierMap(options, contentType, identifier) {
76511
+ const entryMap = options?.entriesByIdentifier?.[contentType];
76512
+ if (!entryMap) return null;
76513
+ return entryMap[identifier] ?? null;
76514
+ }
76515
+ /**
76516
+ * Build a Logo from site layout data.
76517
+ *
76518
+ * @param logo - Logo data from site layout
76519
+ * @param fallbackAlt - Fallback alt text (usually site title)
76520
+ *
76521
+ * @example
76522
+ * ```ts
76523
+ * const logo = buildLogo(siteData.layout.logo, siteData.site.title);
76524
+ * // { src: 'https://...', alt: 'Site Name', width: 200, height: 50 }
76525
+ * ```
76526
+ */
76527
+ function buildLogo(logo, fallbackAlt) {
76528
+ if (!logo || !logo.url) return null;
76529
+ const alt = resolveAltText(logo.alt, fallbackAlt);
76530
+ const result = {
76531
+ type: "image",
76532
+ src: logo.url,
76533
+ alt
76534
+ };
76535
+ if (logo.width != null) result.width = logo.width;
76536
+ if (logo.height != null) result.height = logo.height;
76537
+ return result;
76538
+ }
76539
+ /**
76540
+ * Build both site logos from layout data. The default header and footer choose
76541
+ * between them by the surface they sit on; custom chrome can do the same.
76542
+ *
76543
+ * @example
76544
+ * ```ts
76545
+ * const logoVariants = buildLogoVariants(siteData.layout, siteData.site.title);
76546
+ * ```
76547
+ */
76548
+ function buildLogoVariants(layout, fallbackAlt) {
76549
+ return {
76550
+ forLightBackgrounds: buildLogo(layout?.logo ?? null, fallbackAlt),
76551
+ forDarkBackgrounds: buildLogo(layout?.logoForDarkBackgrounds ?? null, fallbackAlt)
76552
+ };
76553
+ }
76554
+ /**
76555
+ * Header/footer block content for the site logos. `logo` stays populated with
76556
+ * whichever logo exists so presence checks keep working; `logoVariants` is
76557
+ * what the blocks select from at render.
76558
+ */
76559
+ function buildChromeLogoContent(layout, fallbackAlt) {
76560
+ const logoVariants = buildLogoVariants(layout, fallbackAlt);
76561
+ return {
76562
+ logo: logoVariants.forLightBackgrounds ?? logoVariants.forDarkBackgrounds,
76563
+ logoVariants
76564
+ };
76565
+ }
76566
+ //#endregion
76567
+ //#region src/rendering/themeAdmission.ts
76568
+ const MISSING_SDK_THEME_ERROR_CODE = "missing_sdk_theme";
76569
+ var MissingSdkThemeError = class extends Error {
76570
+ constructor(siteId, reason = "cms_theme_absent", themeKey) {
76571
+ super(`[Riverbank SDK] Site "${siteId}" has no resolvable theme. ` + (themeKey ? `Theme key "${themeKey}" is not present. ` : "") + "Select a CMS theme, provide { theme }, { themes }, or { getTheme }, or use rendering: { kind: 'overrides-only' } with complete block overrides.");
76572
+ this.siteId = siteId;
76573
+ this.reason = reason;
76574
+ this.themeKey = themeKey;
76575
+ this.code = MISSING_SDK_THEME_ERROR_CODE;
76576
+ this.name = "MissingSdkThemeError";
76577
+ }
76578
+ };
76579
+ function requireSdkTheme(theme, siteId, reason = "cms_theme_absent") {
76580
+ if (theme === null || theme === void 0) throw new MissingSdkThemeError(siteId, reason);
76581
+ return theme;
76401
76582
  }
76402
76583
  //#endregion
76584
+ //#region src/rendering/renderingMode.ts
76585
+ const defaultOverrideOnlyRuntime = { kind: "responsive-only" };
76586
+ //#endregion
76403
76587
  //#region src/rendering/helpers/footerPageOutline.ts
76404
76588
  /**
76405
76589
  * Admit footer blocks returned by the site API for public rendering.
@@ -78291,6 +78475,7 @@ const SDK_EVENT_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
78291
78475
  responseKind: "json",
78292
78476
  errors: [
78293
78477
  "resource:not_found",
78478
+ "validation:invalid_input",
78294
78479
  "resource:conflict",
78295
78480
  "server:internal_error"
78296
78481
  ]
@@ -78745,28 +78930,6 @@ const EVENT_MANAGEMENT_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
78745
78930
  "resource:conflict",
78746
78931
  "server:internal_error"
78747
78932
  ]
78748
- },
78749
- /**
78750
- * The Content tab's one write: the short introduction, image and
78751
- * description of an event's page, published without its layout.
78752
- */
78753
- saveEventPageWords: {
78754
- path: "/sites/{siteId}/page-surfaces/{pageSurfaceId}/words",
78755
- method: "PUT",
78756
- tags: [
78757
- TAG_TEMPLATES.siteCollection,
78758
- TAG_TEMPLATES.siteRoutableContent,
78759
- TAG_TEMPLATES.pageSurfaceById
78760
- ],
78761
- auth: "user",
78762
- responseKind: "json",
78763
- errors: [
78764
- "auth:forbidden",
78765
- "validation:invalid_input",
78766
- "resource:not_found",
78767
- "resource:conflict",
78768
- "server:internal_error"
78769
- ]
78770
78933
  }
78771
78934
  });
78772
78935
  //#endregion
@@ -79191,6 +79354,15 @@ const BILLING_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
79191
79354
  auth: "user",
79192
79355
  responseKind: "json"
79193
79356
  },
79357
+ /** Continue on Free from the onboarding card page; only the attempt's owner. */
79358
+ continueOnboardingOnFree: {
79359
+ path: "/onboarding/attempts/{attemptToken}/plan/free",
79360
+ method: "POST",
79361
+ tags: ["billing"],
79362
+ auth: "user",
79363
+ errors: [],
79364
+ responseKind: "json"
79365
+ },
79194
79366
  createBillingPortalSession: {
79195
79367
  path: "/billing/portal/session",
79196
79368
  method: "POST",
@@ -79200,6 +79372,161 @@ const BILLING_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
79200
79372
  }
79201
79373
  });
79202
79374
  //#endregion
79375
+ //#region ../api/src/editLeaseEndpoints.ts
79376
+ const path = "/sites/{siteId}/edit-leases/{nodeType}/{nodeId}";
79377
+ const lifecycleErrors = [
79378
+ "auth:lease_required",
79379
+ "auth:forbidden",
79380
+ "resource:not_found",
79381
+ "validation:invalid_input",
79382
+ "server:internal_error"
79383
+ ];
79384
+ const EDIT_LEASE_ENDPOINT_DEFINITIONS = {
79385
+ readEditLease: {
79386
+ path,
79387
+ method: "GET",
79388
+ editLease: "lifecycle",
79389
+ errors: lifecycleErrors,
79390
+ auth: "user",
79391
+ responseKind: "json"
79392
+ },
79393
+ acquireEditLease: {
79394
+ path,
79395
+ method: "POST",
79396
+ editLease: "lifecycle",
79397
+ errors: lifecycleErrors,
79398
+ auth: "user",
79399
+ responseKind: "json"
79400
+ },
79401
+ takeOverEditLease: {
79402
+ path,
79403
+ method: "PUT",
79404
+ editLease: "lifecycle",
79405
+ errors: lifecycleErrors,
79406
+ auth: "user",
79407
+ responseKind: "json"
79408
+ },
79409
+ heartbeatEditLease: {
79410
+ path,
79411
+ method: "PATCH",
79412
+ editLease: "lifecycle",
79413
+ errors: [...lifecycleErrors, "auth:lease_lost"],
79414
+ auth: "user",
79415
+ responseKind: "json"
79416
+ },
79417
+ releaseEditLease: {
79418
+ path,
79419
+ method: "DELETE",
79420
+ editLease: "lifecycle",
79421
+ errors: lifecycleErrors,
79422
+ auth: "user",
79423
+ responseKind: "json"
79424
+ }
79425
+ };
79426
+ //#endregion
79427
+ //#region ../api/src/pageSurfaceEditorEndpoints.ts
79428
+ const surfaceTags = [TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.pageSurfaceById];
79429
+ const PAGE_SURFACE_EDITOR_ENDPOINT_DEFINITIONS = {
79430
+ getPageSurfaceEditorDocument: {
79431
+ path: "/sites/{siteId}/page-surfaces/{pageSurfaceId}/content",
79432
+ method: "GET",
79433
+ errors: [
79434
+ "auth:forbidden",
79435
+ "validation:invalid_input",
79436
+ "resource:not_found",
79437
+ "resource:conflict",
79438
+ "server:internal_error"
79439
+ ],
79440
+ tags: surfaceTags,
79441
+ auth: "user",
79442
+ responseKind: "json"
79443
+ },
79444
+ updatePageSurfaceDraftContent: {
79445
+ editLease: "managed",
79446
+ path: "/sites/{siteId}/page-surfaces/{pageSurfaceId}/content",
79447
+ method: "PUT",
79448
+ errors: [
79449
+ "validation:invalid_input",
79450
+ "resource:not_found",
79451
+ "resource:conflict",
79452
+ "server:internal_error"
79453
+ ],
79454
+ tags: surfaceTags,
79455
+ auth: "user",
79456
+ responseKind: "json"
79457
+ },
79458
+ discardPageSurfaceDraftContent: {
79459
+ editLease: "managed",
79460
+ path: "/sites/{siteId}/page-surfaces/{pageSurfaceId}/content/draft",
79461
+ method: "DELETE",
79462
+ errors: [
79463
+ "validation:invalid_input",
79464
+ "resource:not_found",
79465
+ "resource:conflict",
79466
+ "server:internal_error"
79467
+ ],
79468
+ tags: surfaceTags,
79469
+ auth: "user",
79470
+ responseKind: "json"
79471
+ },
79472
+ updatePageSurfaceRouteMetadata: {
79473
+ editLease: "managed",
79474
+ path: "/sites/{siteId}/page-surfaces/{pageSurfaceId}/metadata",
79475
+ method: "PATCH",
79476
+ errors: [
79477
+ "validation:invalid_input",
79478
+ "resource:not_found",
79479
+ "resource:conflict",
79480
+ "server:internal_error"
79481
+ ],
79482
+ tags: [
79483
+ TAG_TEMPLATES.siteCollection,
79484
+ TAG_TEMPLATES.siteRoutableContent,
79485
+ TAG_TEMPLATES.pageSurfaceById
79486
+ ],
79487
+ auth: "user",
79488
+ responseKind: "json"
79489
+ },
79490
+ publishPageSurface: {
79491
+ editLease: "managed",
79492
+ path: "/sites/{siteId}/page-surfaces/{pageSurfaceId}/publication",
79493
+ method: "POST",
79494
+ errors: [
79495
+ "auth:forbidden",
79496
+ "validation:invalid_input",
79497
+ "resource:not_found",
79498
+ "resource:conflict",
79499
+ "server:internal_error"
79500
+ ],
79501
+ tags: [
79502
+ TAG_TEMPLATES.siteCollection,
79503
+ TAG_TEMPLATES.siteRoutableContent,
79504
+ TAG_TEMPLATES.pageSurfaceById
79505
+ ],
79506
+ auth: "user",
79507
+ responseKind: "json"
79508
+ },
79509
+ saveEventContentTab: {
79510
+ editLease: "managed",
79511
+ path: "/sites/{siteId}/page-surfaces/{pageSurfaceId}/event-content",
79512
+ method: "PUT",
79513
+ errors: [
79514
+ "auth:forbidden",
79515
+ "validation:invalid_input",
79516
+ "resource:not_found",
79517
+ "resource:conflict",
79518
+ "server:internal_error"
79519
+ ],
79520
+ tags: [
79521
+ TAG_TEMPLATES.siteCollection,
79522
+ TAG_TEMPLATES.siteRoutableContent,
79523
+ TAG_TEMPLATES.pageSurfaceById
79524
+ ],
79525
+ auth: "user",
79526
+ responseKind: "json"
79527
+ }
79528
+ };
79529
+ //#endregion
79203
79530
  //#region ../api/src/bookingPeopleEndpointDefinitions.ts
79204
79531
  /**
79205
79532
  * People endpoints (#1356): the People list, its CSV export, and deleting a
@@ -79292,12 +79619,14 @@ z$1.object({
79292
79619
  ...GIFTING_ENDPOINT_DEFINITIONS,
79293
79620
  ...PUBLIC_READ_ENDPOINT_DEFINITIONS,
79294
79621
  ...BILLING_ENDPOINT_DEFINITIONS,
79622
+ ...EDIT_LEASE_ENDPOINT_DEFINITIONS,
79623
+ ...PAGE_SURFACE_EDITOR_ENDPOINT_DEFINITIONS,
79295
79624
  ...SITE_MANAGEMENT_ENDPOINT_DEFINITIONS
79296
79625
  }), TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteTheme, TAG_TEMPLATES.siteCollection, { ...SITE_API_KEY_ENDPOINT_DEFINITIONS }, TAG_TEMPLATES.site, TAG_TEMPLATES.siteBookingSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteBookingSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteEmailSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteEmailSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteEmailSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteEmailSettings, {
79297
79626
  ...NEWSLETTER_ENDPOINT_DEFINITIONS,
79298
79627
  ...APPOINTMENT_ENDPOINT_DEFINITIONS,
79299
79628
  ...EVENT_SERIES_REGISTRATION_ENDPOINT_DEFINITIONS
79300
- }, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteById, TAG_TEMPLATES.siteBySlug, TAG_TEMPLATES.siteByDomain, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteById, TAG_TEMPLATES.siteBySlug, TAG_TEMPLATES.siteByDomain, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.workflowRunById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.routeById, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.site, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteNavigation, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteNavigation, TAG_TEMPLATES.navigationMenuById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteNavigation, TAG_TEMPLATES.navigationMenuById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteNavigation, TAG_TEMPLATES.navigationMenuById, TAG_TEMPLATES.navigationItemById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteNavigation, TAG_TEMPLATES.navigationMenuById, TAG_TEMPLATES.navigationItemById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteNavigation, TAG_TEMPLATES.navigationMenuById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.publicEvents, TAG_TEMPLATES.publicBookingServices, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteTheme, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteTheme, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteTheme, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteRedirects, TAG_TEMPLATES.siteRouteOutcomes, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteRedirects, TAG_TEMPLATES.siteRouteOutcomes, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.formSubmissionsBySlug, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.formSubmissionsBySlug, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.formSubmissionsBySlug, TAG_TEMPLATES.siteForms, { ...PUBLIC_BOOKING_AVAILABILITY_ENDPOINT_DEFINITIONS }, TAG_TEMPLATES.publicEventFilters, TAG_TEMPLATES.publicEvents, TAG_TEMPLATES.publicShop, TAG_TEMPLATES.publicCheckout, TAG_TEMPLATES.siteRoutableContent, { ...PUBLIC_EVENT_CHECKOUT_ENDPOINT_DEFINITIONS }, TAG_TEMPLATES.publicEvents, TAG_TEMPLATES.publicEvents, { ...EVENT_MANAGEMENT_ENDPOINT_DEFINITIONS }, { ...BOOKING_PEOPLE_ENDPOINT_DEFINITIONS }, { ...SDK_MEDIA_ENDPOINT_DEFINITIONS }, { ...SDK_ENDPOINT_DEFINITIONS }, { ...SDK_PAGE_DESIGN_ENDPOINT_DEFINITIONS }, { ...SDK_EVENT_ENDPOINT_DEFINITIONS }, { ...SDK_ENTRY_READ_ENDPOINTS };
79629
+ }, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteById, TAG_TEMPLATES.siteBySlug, TAG_TEMPLATES.siteByDomain, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteById, TAG_TEMPLATES.siteBySlug, TAG_TEMPLATES.siteByDomain, TAG_TEMPLATES.workflowRunById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.routeById, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.site, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteNavigation, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteNavigation, TAG_TEMPLATES.navigationMenuById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteNavigation, TAG_TEMPLATES.navigationMenuById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteNavigation, TAG_TEMPLATES.navigationMenuById, TAG_TEMPLATES.navigationItemById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteNavigation, TAG_TEMPLATES.navigationMenuById, TAG_TEMPLATES.navigationItemById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteNavigation, TAG_TEMPLATES.navigationMenuById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.publicEvents, TAG_TEMPLATES.publicBookingServices, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteTheme, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteTheme, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteTheme, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteRedirects, TAG_TEMPLATES.siteRouteOutcomes, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteRedirects, TAG_TEMPLATES.siteRouteOutcomes, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.formSubmissionsBySlug, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.formSubmissionsBySlug, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.formSubmissionsBySlug, TAG_TEMPLATES.siteForms, { ...PUBLIC_BOOKING_AVAILABILITY_ENDPOINT_DEFINITIONS }, TAG_TEMPLATES.publicEventFilters, TAG_TEMPLATES.publicEvents, TAG_TEMPLATES.publicShop, TAG_TEMPLATES.publicCheckout, TAG_TEMPLATES.siteRoutableContent, { ...PUBLIC_EVENT_CHECKOUT_ENDPOINT_DEFINITIONS }, TAG_TEMPLATES.publicEvents, TAG_TEMPLATES.publicEvents, { ...EVENT_MANAGEMENT_ENDPOINT_DEFINITIONS }, { ...BOOKING_PEOPLE_ENDPOINT_DEFINITIONS }, { ...SDK_MEDIA_ENDPOINT_DEFINITIONS }, { ...SDK_ENDPOINT_DEFINITIONS }, { ...SDK_PAGE_DESIGN_ENDPOINT_DEFINITIONS }, { ...SDK_EVENT_ENDPOINT_DEFINITIONS }, { ...SDK_ENTRY_READ_ENDPOINTS };
79301
79630
  z$1.object({ refreshToken: z$1.string().min(1).max(4096) }).strict();
79302
79631
  z$1.object({
79303
79632
  accessToken: z$1.string().min(1).max(4096),
@@ -81670,20 +81999,20 @@ const BUILTIN_CONTENT_TYPE_SCHEMAS = {
81670
81999
  id: "summary",
81671
82000
  type: "textarea",
81672
82001
  label: "Short introduction",
81673
- description: "Write one or two sentences that help people quickly understand what this is. It appears wherever the event is listed and near the top of its page.",
82002
+ description: "Shown in your listings and search results, and at the top of its page.",
81674
82003
  rows: 3
81675
82004
  },
81676
82005
  {
81677
82006
  id: "image",
81678
82007
  type: "media",
81679
82008
  label: "Event image",
81680
- description: "Choose the main image people will see wherever the event is listed and on its page."
82009
+ description: "At the top of its page and beside it in your listings."
81681
82010
  },
81682
82011
  {
81683
82012
  id: "body",
81684
82013
  type: "richText",
81685
- label: "About this event",
81686
- description: "Add the main information people need before booking—what to expect, who it’s for, what’s included, and anything they should bring or know."
82014
+ label: "Full description",
82015
+ description: "The main text on its page, under the introduction."
81687
82016
  }
81688
82017
  ],
81689
82018
  routing: {
@@ -82073,7 +82402,6 @@ const DEFAULT_TEMPLATE_DEFINITIONS = {
82073
82402
  maxTickets: "5",
82074
82403
  showVenue: true,
82075
82404
  showCapacity: true,
82076
- successMessage: "Thank you for registering! Check your email for confirmation details.",
82077
82405
  buttonText: "Complete Registration",
82078
82406
  buttonVariant: "primary"
82079
82407
  },