@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
@@ -61,6 +61,19 @@ const CURRENCY_LOCALE_BY_CODE = {
61
61
  function resolveCurrencyLocale(currencyCode, override) {
62
62
  return override ?? CURRENCY_LOCALE_BY_CODE[currencyCode] ?? "en";
63
63
  }
64
+ function fractionDigitsFor(decimals, exactFormatter) {
65
+ switch (decimals) {
66
+ case "exact": return {};
67
+ case "auto": return {
68
+ minimumFractionDigits: 0,
69
+ maximumFractionDigits: exactFormatter.resolvedOptions().maximumFractionDigits
70
+ };
71
+ case "whole": return {
72
+ minimumFractionDigits: 0,
73
+ maximumFractionDigits: 0
74
+ };
75
+ }
76
+ }
64
77
  /**
65
78
  * The single currency-amount formatter for the product: minor units in,
66
79
  * localized string out.
@@ -71,6 +84,13 @@ function resolveCurrencyLocale(currencyCode, override) {
71
84
  * own `Intl.NumberFormat`.
72
85
  */
73
86
  function formatCurrencyAmount(amountCents, currency, options) {
87
+ return formatCurrencyMajorUnits(amountCents / 100, currency, options);
88
+ }
89
+ /**
90
+ * `formatCurrencyAmount` for an amount already in MAJOR units (29.99 = £29.99),
91
+ * such as a registrar price. Prefer minor units everywhere else.
92
+ */
93
+ function formatCurrencyMajorUnits(amount, currency, options) {
74
94
  const currencyCode = currency.toUpperCase();
75
95
  const locale = resolveCurrencyLocale(currencyCode, options?.locale);
76
96
  try {
@@ -78,17 +98,13 @@ function formatCurrencyAmount(amountCents, currency, options) {
78
98
  style: "currency",
79
99
  currency: currencyCode
80
100
  });
81
- const fractionDigits = options?.decimals === "auto" ? {
82
- minimumFractionDigits: 0,
83
- maximumFractionDigits: exactFormatter.resolvedOptions().maximumFractionDigits
84
- } : {};
85
101
  return new Intl.NumberFormat(locale, {
86
102
  style: "currency",
87
103
  currency: currencyCode,
88
- ...fractionDigits
89
- }).format(amountCents / 100);
104
+ ...fractionDigitsFor(options?.decimals ?? "exact", exactFormatter)
105
+ }).format(amount);
90
106
  } catch {
91
- return `${(amountCents / 100).toFixed(2)} ${currencyCode}`;
107
+ return `${amount.toFixed(2)} ${currencyCode}`;
92
108
  }
93
109
  }
94
110
  //#endregion
@@ -681,6 +697,26 @@ function toLocationCoordinates(value) {
681
697
  };
682
698
  }
683
699
  //#endregion
700
+ //#region ../core/src/block-content-identity.ts
701
+ function readContentVersionId(value) {
702
+ const parsed = parseContentVersionId(value);
703
+ return parsed.ok ? parsed.value : null;
704
+ }
705
+ /** The one pairing of a published id with its content. */
706
+ function readPublishedBlockPlacement(id, content) {
707
+ if (id == null && content == null) return null;
708
+ const versionId = readContentVersionId(id);
709
+ return versionId !== null && content != null ? {
710
+ kind: "published",
711
+ id: versionId,
712
+ content
713
+ } : {
714
+ kind: "incomplete",
715
+ id: id ?? null,
716
+ content: content ?? null
717
+ };
718
+ }
719
+ //#endregion
684
720
  //#region ../core/src/mailing-list-identifiers.ts
685
721
  const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu;
686
722
  const OPAQUE_ID_PATTERN = /^[A-Za-z0-9_-]{1,100}$/u;
@@ -1620,11 +1656,18 @@ function isReservedPathSegment(value) {
1620
1656
  function isUnsafePathSegment(segment) {
1621
1657
  return segment.trim().length === 0 || segment !== segment.trim() || isReservedPathSegment(segment) || containsUnsafePathSegmentCharacter(segment);
1622
1658
  }
1623
- ({
1659
+ //#endregion
1660
+ //#region ../media-core/src/fileStorage.ts
1661
+ const FILE_STORAGE_BUCKETS = {
1624
1662
  publicSite: unsafeAsStorageBucketName("media"),
1625
1663
  privateSite: unsafeAsStorageBucketName("site-files-private"),
1626
- temporary: unsafeAsStorageBucketName("temp-uploads")
1627
- }).publicSite;
1664
+ temporary: unsafeAsStorageBucketName("temp-uploads"),
1665
+ siteAssets: unsafeAsStorageBucketName("site-assets"),
1666
+ siteFonts: unsafeAsStorageBucketName("site-fonts"),
1667
+ bookingRequirementDocuments: unsafeAsStorageBucketName("booking-requirement-documents")
1668
+ };
1669
+ FILE_STORAGE_BUCKETS.publicSite, FILE_STORAGE_BUCKETS.siteAssets, FILE_STORAGE_BUCKETS.siteFonts;
1670
+ FILE_STORAGE_BUCKETS.publicSite, FILE_STORAGE_BUCKETS.privateSite, FILE_STORAGE_BUCKETS.temporary, FILE_STORAGE_BUCKETS.siteAssets, FILE_STORAGE_BUCKETS.siteFonts, FILE_STORAGE_BUCKETS.bookingRequirementDocuments;
1628
1671
  function parseStoragePath(value) {
1629
1672
  return joinStoragePathSegments(value.split("/"));
1630
1673
  }
@@ -29031,7 +29074,6 @@ const publicEventBaseSchema = z.object({
29031
29074
  description: z.string().nullable(),
29032
29075
  content: z.object({ body: RichTextDocSchema.nullable().optional() }).optional(),
29033
29076
  presentation: z.object({
29034
- cardTitleOverride: z.string().nullable().optional(),
29035
29077
  summary: z.string().nullable().optional(),
29036
29078
  image: mediaSchema.nullable().optional()
29037
29079
  }).optional(),
@@ -29064,6 +29106,7 @@ const publicEventBaseSchema = z.object({
29064
29106
  "archived"
29065
29107
  ]).optional(),
29066
29108
  timeZone: z.string(),
29109
+ siteTimeZone: z.string().optional(),
29067
29110
  pricing: publicEventPricingSchema,
29068
29111
  paymentTerms: blockBookingPaymentTermsSchema,
29069
29112
  cancellationPolicy: z.object({ refunds: z.object({
@@ -33027,6 +33070,7 @@ const bookingMailingListContextSchema = z.unknown().transform((value) => {
33027
33070
  return parsed.ok ? parsed.value : void 0;
33028
33071
  });
33029
33072
  const bookingSourceSchema = z.object({
33073
+ demoEmailSuppressed: z.boolean().optional(),
33030
33074
  mailingList: bookingMailingListContextSchema.optional(),
33031
33075
  siteName: z.string().optional(),
33032
33076
  siteId: z.string().optional(),
@@ -33057,6 +33101,7 @@ const bookingDisplaySchema = z.object({
33057
33101
  message: z.string().nullable()
33058
33102
  });
33059
33103
  const bookingHydrationSchema = z.object({
33104
+ demoEmailSuppressed: z.boolean().optional(),
33060
33105
  mailingList: bookingMailingListContextSchema.optional(),
33061
33106
  siteName: z.string().optional(),
33062
33107
  formId: z.string().nullable(),
@@ -33104,6 +33149,7 @@ const bookingFormBlockRuntime = defineClientOwnedBlockRuntime({
33104
33149
  return {
33105
33150
  display: buildBookingFormDisplay(source, form),
33106
33151
  hydration: {
33152
+ demoEmailSuppressed: source.demoEmailSuppressed,
33107
33153
  mailingList: source.mailingList,
33108
33154
  siteName: source.siteName,
33109
33155
  formId: form?.id ?? source.formId ?? null,
@@ -33940,6 +33986,44 @@ function resolveEventCta(event, buttonText) {
33940
33986
  * timestamps become strings or date buckets. Calendar-grid primitives are
33941
33987
  * re-exported from @riverbankcms/calendar so block code has one import.
33942
33988
  */
33989
+ /**
33990
+ * The English locale a site's public dates are written in, read from the
33991
+ * site's own time zone (Will, 2026-09-26: "date style from site time zone").
33992
+ *
33993
+ * Sites don't store a locale, and every public word around a date is English,
33994
+ * so the only open question is which English conventions to follow: day or
33995
+ * month first, and a 24 or 12-hour clock. The site's time zone is the one
33996
+ * fact every site carries about where it is. It is the site's, never an
33997
+ * event's: a venue left at UTC must not turn a UK site's dates American.
33998
+ * Anywhere this can't place (UTC, the Americas, Asia) keeps US English, which
33999
+ * is what these helpers wrote before sites were placed at all.
34000
+ */
34001
+ function eventDateLocale(siteTimeZone) {
34002
+ if (!siteTimeZone) return "en-US";
34003
+ if (siteTimeZone === "Europe/Dublin") return "en-IE";
34004
+ if (siteTimeZone.startsWith("Europe/")) return "en-GB";
34005
+ if (siteTimeZone.startsWith("Australia/")) return "en-AU";
34006
+ if (siteTimeZone === "Pacific/Auckland" || siteTimeZone === "Pacific/Chatham") return "en-NZ";
34007
+ return "en-US";
34008
+ }
34009
+ /**
34010
+ * Formatting options for an event's dates: the times in the event's own zone,
34011
+ * written in its site's locale. A record from an older server that doesn't
34012
+ * name the site's zone falls back to the event's.
34013
+ */
34014
+ function eventDateOptions(place) {
34015
+ return {
34016
+ timeZone: place.timeZone ?? null,
34017
+ locale: eventDateLocale(place.siteTimeZone ?? place.timeZone)
34018
+ };
34019
+ }
34020
+ /**
34021
+ * Start and end times as cards write them, in the site's locale:
34022
+ * "10:00 to 16:00" in the UK, "10:00 AM to 4:00 PM" in the US.
34023
+ */
34024
+ function formatEventTimeRange$1(times, options) {
34025
+ return `${formatTime(times.startsAt, options)} to ${formatTime(times.endsAt, options)}`;
34026
+ }
33943
34027
  /** Use the event timezone when present, otherwise the calendar/site timezone. */
33944
34028
  function resolveEventTimeZone(event, calendarTimeZone) {
33945
34029
  return event.timeZone || calendarTimeZone;
@@ -33961,18 +34045,25 @@ function formatDate(isoTimestamp, options) {
33961
34045
  });
33962
34046
  }
33963
34047
  /**
33964
- * Format time for display.
33965
- * Returns: "10:00 AM"
34048
+ * Whether the locale reads a 24-hour clock, where hours are written with two
34049
+ * digits ("09:00"), as the dashboard writes them.
34050
+ */
34051
+ function usesTwentyFourHourClock(locale) {
34052
+ return new Intl.DateTimeFormat(locale, { hour: "numeric" }).resolvedOptions().hour12 === false;
34053
+ }
34054
+ /**
34055
+ * Format time for display, on the locale's own clock.
34056
+ * Returns: "9:00 AM" (en-US) or "09:00" (en-GB)
33966
34057
  */
33967
34058
  function formatTime(isoTimestamp, options) {
34059
+ const locale = options?.locale ?? "en-US";
33968
34060
  return formatBookingTime(toScheduledBookingDateTime({
33969
34061
  startsAt: isoTimestamp,
33970
34062
  timeZone: toBookingTimeZone(options?.timeZone ?? "UTC"),
33971
- locale: options?.locale ?? "en-US"
34063
+ locale
33972
34064
  }), {
33973
- hour: "numeric",
33974
- minute: "2-digit",
33975
- hour12: true
34065
+ hour: usesTwentyFourHourClock(locale) ? "2-digit" : "numeric",
34066
+ minute: "2-digit"
33976
34067
  });
33977
34068
  }
33978
34069
  function formatEventDateParts(args) {
@@ -34004,7 +34095,7 @@ function formatEventCompactDateRail(isoTimestamp, options) {
34004
34095
  locale: options?.locale ?? "en-US"
34005
34096
  });
34006
34097
  const weekday = formatBookingDate(dateTime, { weekday: "short" }).toLocaleUpperCase(options?.locale ?? "en-US");
34007
- const month = formatBookingDate(dateTime, { month: "short" }).toLocaleUpperCase(options?.locale ?? "en-US");
34098
+ const month = formatBookingDate(dateTime, { month: "short" }).slice(0, 3).toLocaleUpperCase(options?.locale ?? "en-US");
34008
34099
  return {
34009
34100
  weekday,
34010
34101
  day: formatBookingDate(dateTime, { day: "numeric" }),
@@ -34024,7 +34115,7 @@ function formatEventCompactDateRail(isoTimestamp, options) {
34024
34115
  * keep the fact panel on the same date and timezone rules as event rows.
34025
34116
  */
34026
34117
  function formatEventNextDateFact(event) {
34027
- const rail = formatEventCompactDateRail(event.startsAt, { timeZone: event.timeZone });
34118
+ const rail = formatEventCompactDateRail(event.startsAt, eventDateOptions(event));
34028
34119
  return {
34029
34120
  dateTime: event.startsAt,
34030
34121
  value: `${rail.weekday} ${rail.day} ${rail.month}`,
@@ -34871,6 +34962,13 @@ function CalendarIcon({ className, size = 16, strokeWidth = 2 }) {
34871
34962
  }
34872
34963
  //#endregion
34873
34964
  //#region ../blocks/src/system/runtime/nodes/events/shared/EventCard.tsx
34965
+ /** The category's badge, when the event has a category. */
34966
+ function eventCardCategoryBadge(category) {
34967
+ return category ? {
34968
+ label: category.name,
34969
+ style: getCategoryBadgeStyle(category.color ?? null)
34970
+ } : null;
34971
+ }
34874
34972
  /**
34875
34973
  * EventCard Component
34876
34974
  *
@@ -34879,24 +34977,19 @@ function CalendarIcon({ className, size = 16, strokeWidth = 2 }) {
34879
34977
  *
34880
34978
  * This component is server-safe (uses no client APIs like Intl).
34881
34979
  */
34882
- 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 }) => {
34980
+ 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 }) => {
34883
34981
  const { presentation: cardPresentation, presentationClass, headingLevel: cardHeadingLevel } = resolveEventCardOptions({
34884
34982
  presentation,
34885
34983
  headingLevel
34886
34984
  });
34887
- const timeZone = event.timeZone ?? null;
34888
- const formattedDate = formatDate(event.startsAt, { timeZone });
34889
- const formattedTime = `${formatTime(event.startsAt, { timeZone })} - ${formatTime(event.endsAt, { timeZone })}`;
34985
+ const { formattedDate, formattedTime } = formatEventCardWhen(event);
34890
34986
  const cta = resolveEventCta(event, buttonText);
34891
34987
  const cardClass = boxStyleClassNames({ role: cardRole }, { baseClass: "event-card" });
34892
34988
  const title = event.title;
34893
34989
  const summary = event.presentation?.summary ?? event.description;
34894
34990
  const image = event.presentation?.image ?? null;
34895
34991
  const category = event.eventCategory;
34896
- const categoryBadge = category && showCategory ? {
34897
- label: category.name,
34898
- style: getCategoryBadgeStyle(category.color ?? null)
34899
- } : null;
34992
+ const categoryBadge = showCategory ? eventCardCategoryBadge(category) : null;
34900
34993
  const hasImage = Boolean(showImage && image);
34901
34994
  const dateFact = resolveEventCardDateFact({
34902
34995
  event,
@@ -34915,7 +35008,8 @@ const EventCard = ({ event, cardRole = "default", buttonVariant = "primary", but
34915
35008
  categoryId: category?.id,
34916
35009
  dateFact,
34917
35010
  hasImage,
34918
- image
35011
+ image,
35012
+ imageResolveContext
34919
35013
  }), /* @__PURE__ */ jsx(EventCardContent, {
34920
35014
  allowMap,
34921
35015
  buttonVariant,
@@ -34963,7 +35057,8 @@ function EventCardMedia(props) {
34963
35057
  /* @__PURE__ */ jsx(MediaNodeServer, {
34964
35058
  value: props.image,
34965
35059
  className: "event-card-image",
34966
- size: ImagePresets.card
35060
+ size: ImagePresets.card,
35061
+ imageResolveContext: props.imageResolveContext
34967
35062
  }),
34968
35063
  props.categoryBadge && /* @__PURE__ */ jsx("span", {
34969
35064
  className: "event-category-badge event-category-badge--overlay",
@@ -35078,6 +35173,17 @@ function resolveEventCardOptions(props) {
35078
35173
  headingLevel: props.headingLevel ?? 3
35079
35174
  };
35080
35175
  }
35176
+ /**
35177
+ * The card's date and times, written the way the event's place writes them
35178
+ * ("Friday, 16 October 2026" and "10:00 to 16:00" in the UK).
35179
+ */
35180
+ function formatEventCardWhen(event) {
35181
+ const options = eventDateOptions(event);
35182
+ return {
35183
+ formattedDate: formatDate(event.startsAt, options),
35184
+ formattedTime: formatEventTimeRange$1(event, options)
35185
+ };
35186
+ }
35081
35187
  function resolveEventCardDateFact(props) {
35082
35188
  if (!props.showImage || props.image || props.presentation !== "catalogue") return null;
35083
35189
  return formatEventNextDateFact(props.event);
@@ -36504,6 +36610,34 @@ function buildEventCombinedInteractiveIslandProps(props) {
36504
36610
  });
36505
36611
  }
36506
36612
  //#endregion
36613
+ //#region ../blocks/src/system/runtime/nodes/events/shared/eventCardPresentations.ts
36614
+ /** A booking page's catalogue card: one per series, "See dates" for dated events. */
36615
+ function catalogueEventCardProps(event, buttonVariant = "primary") {
36616
+ return {
36617
+ presentation: "catalogue",
36618
+ headingLevel: 4,
36619
+ buttonVariant,
36620
+ buttonText: event.bookingScope === "single_occurrence" ? "See dates" : void 0,
36621
+ showMap: false,
36622
+ allowMap: false,
36623
+ showCategory: false,
36624
+ orientation: "vertical"
36625
+ };
36626
+ }
36627
+ /** An events listing's card, from the listing's display settings. */
36628
+ function listingEventCardProps(display) {
36629
+ return {
36630
+ cardRole: display.cardRole,
36631
+ buttonVariant: display.buttonVariant,
36632
+ buttonText: display.buttonText,
36633
+ showVenue: display.showVenue,
36634
+ showMap: display.showMap,
36635
+ allowMap: false,
36636
+ showCapacity: display.showCapacity,
36637
+ orientation: display.orientation
36638
+ };
36639
+ }
36640
+ //#endregion
36507
36641
  //#region ../blocks/src/system/runtime/nodes/events/shared/renderEventListItem.tsx
36508
36642
  /**
36509
36643
  * Shared SSR render function for event list items.
@@ -36520,14 +36654,7 @@ function renderEventListItem(event, display) {
36520
36654
  }, event.occurrenceId || event.id);
36521
36655
  return /* @__PURE__ */ jsx(EventCard, {
36522
36656
  event,
36523
- cardRole: display.cardRole,
36524
- buttonVariant: display.buttonVariant,
36525
- buttonText: display.buttonText,
36526
- showVenue: display.showVenue,
36527
- showMap: display.showMap,
36528
- allowMap: false,
36529
- showCapacity: display.showCapacity,
36530
- orientation: display.orientation
36657
+ ...listingEventCardProps(display)
36531
36658
  }, event.occurrenceId || event.id);
36532
36659
  }
36533
36660
  //#endregion
@@ -36933,14 +37060,7 @@ function OfferingsCatalogue(props) {
36933
37060
  style: { gridTemplateColumns: "repeat(auto-fill, minmax(min(100%, 18rem), 1fr))" },
36934
37061
  children: events.map((event) => /* @__PURE__ */ jsx(EventCard, {
36935
37062
  event,
36936
- presentation: "catalogue",
36937
- headingLevel: 4,
36938
- buttonVariant: props.buttonVariant ?? "primary",
36939
- buttonText: event.bookingScope === "single_occurrence" ? "See dates" : void 0,
36940
- showMap: false,
36941
- allowMap: false,
36942
- showCategory: false,
36943
- orientation: "vertical"
37063
+ ...catalogueEventCardProps(event, props.buttonVariant ?? "primary")
36944
37064
  }, event.seriesId))
36945
37065
  })]
36946
37066
  }, group.sourceKey))
@@ -37228,45 +37348,73 @@ function FeaturedOfferingSummary({ item }) {
37228
37348
  }
37229
37349
  function featuredSummaryDetails(item) {
37230
37350
  switch (item.kind) {
37231
- case "event": return formatFeaturedSummary(deriveEventScheduleSummary(item.event), item.event.venue?.name ?? null);
37351
+ case "event": return formatFeaturedSummary(deriveEventScheduleSummary(item.event), {
37352
+ venue: item.event.venue?.name ?? null,
37353
+ siteTimeZone: item.event.siteTimeZone
37354
+ });
37232
37355
  case "run": {
37233
37356
  const schedule = derivePreviewRunSchedule(item.run.run.sessions);
37234
- return schedule.kind === "scheduled" ? formatFeaturedSummary(schedule.summary, item.run.representative.venue?.name ?? null) : null;
37357
+ return schedule.kind === "scheduled" ? formatFeaturedSummary(schedule.summary, {
37358
+ venue: item.run.representative.venue?.name ?? null,
37359
+ siteTimeZone: item.run.representative.siteTimeZone
37360
+ }) : null;
37235
37361
  }
37236
37362
  default: return assertNever$4(item, "Unhandled offerings preview item");
37237
37363
  }
37238
37364
  }
37239
- function formatFeaturedSummary(summary, venue) {
37365
+ function formatFeaturedSummary(summary, place) {
37240
37366
  switch (summary.kind) {
37241
- case "single-occurrence": return detailsFromOccurrences(summary.occurrence, null, venue, null, null);
37242
- case "multi-day-span": return detailsFromOccurrences(summary.occurrence, summary.occurrence, venue, null, null, true);
37243
- case "fixed-recurring-run": return detailsFromOccurrences(summary.first, summary.last, venue, summary.recurrenceLabel, null);
37244
- case "irregular-multi-session-run": return detailsFromOccurrences(summary.first, summary.last, venue, null, `${summary.sessionCount} dates`);
37367
+ case "single-occurrence": return detailsFromOccurrences({
37368
+ first: summary.occurrence,
37369
+ last: null,
37370
+ place
37371
+ });
37372
+ case "multi-day-span": return detailsFromOccurrences({
37373
+ first: summary.occurrence,
37374
+ last: summary.occurrence,
37375
+ place,
37376
+ spanUsesEndDate: true
37377
+ });
37378
+ case "fixed-recurring-run": return detailsFromOccurrences({
37379
+ first: summary.first,
37380
+ last: summary.last,
37381
+ place,
37382
+ recurrence: summary.recurrenceLabel
37383
+ });
37384
+ case "irregular-multi-session-run": return detailsFromOccurrences({
37385
+ first: summary.first,
37386
+ last: summary.last,
37387
+ place,
37388
+ sessionCount: `${summary.sessionCount} dates`
37389
+ });
37245
37390
  default: return assertNever$4(summary, "Unhandled offerings preview schedule summary");
37246
37391
  }
37247
37392
  }
37248
- function detailsFromOccurrences(first, last, venue, recurrence, sessionCount, spanUsesEndDate = false) {
37249
- const endDateTime = spanUsesEndDate ? first.endsAt : last?.startsAt ?? first.startsAt;
37393
+ function detailsFromOccurrences(input) {
37394
+ const { first, last, place } = input;
37395
+ const endDateTime = input.spanUsesEndDate ? first.endsAt : last?.startsAt ?? first.startsAt;
37396
+ const options = eventDateOptions({
37397
+ timeZone: first.timeZone,
37398
+ siteTimeZone: place.siteTimeZone
37399
+ });
37400
+ const summaryDate = (isoTimestamp, timeZone) => formatSummaryDate(isoTimestamp, {
37401
+ timeZone,
37402
+ locale: options.locale
37403
+ });
37250
37404
  return {
37251
- startDate: formatSummaryDate(first.startsAt, first.timeZone),
37405
+ startDate: summaryDate(first.startsAt, first.timeZone),
37252
37406
  startDateTime: first.startsAt,
37253
- endDate: last ? formatSummaryDate(endDateTime, last.timeZone) : null,
37407
+ endDate: last ? summaryDate(endDateTime, last.timeZone) : null,
37254
37408
  endDateTime,
37255
- timeRange: `${formatTime(first.startsAt, {
37256
- timeZone: first.timeZone,
37257
- locale: "en-GB"
37258
- })} – ${formatTime(first.endsAt, {
37259
- timeZone: first.timeZone,
37260
- locale: "en-GB"
37261
- })}`,
37262
- recurrence,
37263
- sessionCount,
37264
- venue
37265
- };
37266
- }
37267
- function formatSummaryDate(isoTimestamp, timeZone) {
37268
- return new Intl.DateTimeFormat("en-GB", {
37269
- timeZone,
37409
+ timeRange: formatEventTimeRange$1(first, options),
37410
+ recurrence: input.recurrence ?? null,
37411
+ sessionCount: input.sessionCount ?? null,
37412
+ venue: place.venue
37413
+ };
37414
+ }
37415
+ function formatSummaryDate(isoTimestamp, options) {
37416
+ return new Intl.DateTimeFormat(options.locale, {
37417
+ timeZone: options.timeZone,
37270
37418
  weekday: "long",
37271
37419
  day: "numeric",
37272
37420
  month: "long",
@@ -37313,9 +37461,12 @@ function WholeSeriesRunCompactRow({ group, path, now }) {
37313
37461
  path
37314
37462
  });
37315
37463
  const { sessionCount: sessionsCount, firstSession } = schedule;
37316
- const timeZone = firstSession.timeZone;
37317
- const dateRail = formatEventCompactDateRail(firstSession.startsAt, { timeZone });
37318
- const timeRange = `${formatTime(firstSession.startsAt, { timeZone })} - ${formatTime(firstSession.endsAt, { timeZone })}`;
37464
+ const options = eventDateOptions({
37465
+ timeZone: firstSession.timeZone,
37466
+ siteTimeZone: group.representative.siteTimeZone
37467
+ });
37468
+ const dateRail = formatEventCompactDateRail(firstSession.startsAt, options);
37469
+ const timeRange = formatEventTimeRange$1(firstSession, options);
37319
37470
  const price = formatEventPriceDisplay(group.representative.pricing);
37320
37471
  const statusLabel = resolveWholeSeriesBookingPhase(group.run, now).kind === "open" ? null : "Registration closed";
37321
37472
  return /* @__PURE__ */ jsxs("article", {
@@ -37395,9 +37546,12 @@ function WholeSeriesRunFeatureCard({ group, now, path, buttonVariant, buttonText
37395
37546
  path
37396
37547
  });
37397
37548
  const { firstSession } = schedule;
37398
- const timeZone = firstSession.timeZone;
37399
- const formattedDate = formatEventCompactDateRail(firstSession.startsAt, { timeZone }).label;
37400
- const timeRange = `${formatTime(firstSession.startsAt, { timeZone })} - ${formatTime(firstSession.endsAt, { timeZone })}`;
37549
+ const options = eventDateOptions({
37550
+ timeZone: firstSession.timeZone,
37551
+ siteTimeZone: group.representative.siteTimeZone
37552
+ });
37553
+ const formattedDate = formatEventCompactDateRail(firstSession.startsAt, options).label;
37554
+ const timeRange = formatEventTimeRange$1(firstSession, options);
37401
37555
  const price = formatEventPriceDisplay(group.representative.pricing);
37402
37556
  const statusLabel = resolveWholeSeriesBookingPhase(group.run, now).kind === "open" ? null : "Registration closed";
37403
37557
  const description = group.representative.description;
@@ -38313,6 +38467,7 @@ const shopSourceSchema = z.object({
38313
38467
  memberships: z.array(publicMembershipProductSchema).nullable().optional(),
38314
38468
  products: z.array(publicProductSchema).nullable().optional(),
38315
38469
  siteId: z.string().optional(),
38470
+ demoEmailSuppressed: z.boolean().optional(),
38316
38471
  apiBaseUrl: z.string().optional(),
38317
38472
  readAuthority: browserReadAuthoritySchema.optional(),
38318
38473
  stage: previewStageSchema.optional()
@@ -38432,7 +38587,8 @@ const checkoutDisplaySchema = z.object({
38432
38587
  const passesMembershipsHydrationSchema = z.object({
38433
38588
  memberships: z.array(publicMembershipProductSchema),
38434
38589
  passPurchaseMode: z.enum(["add_to_cart", "buy_now"]),
38435
- buttonVariant: blockButtonRoleSchema
38590
+ buttonVariant: blockButtonRoleSchema,
38591
+ demoEmailSuppressed: z.boolean().optional()
38436
38592
  });
38437
38593
  const productListHydrationSchema = z.object({
38438
38594
  products: z.array(publicProductSchema),
@@ -38454,7 +38610,8 @@ const cartHydrationSchema = z.object({
38454
38610
  });
38455
38611
  const checkoutHydrationSchema = z.object({
38456
38612
  emptyStateText: z.string(),
38457
- submitButtonText: z.string()
38613
+ submitButtonText: z.string(),
38614
+ demoEmailSuppressed: z.boolean().optional()
38458
38615
  });
38459
38616
  const passesMembershipsRenderSchema = z.object({
38460
38617
  display: passesMembershipsDisplaySchema,
@@ -38513,7 +38670,8 @@ const shopBlockRuntime = defineProgressiveBlockRuntime({
38513
38670
  hydration: {
38514
38671
  memberships: source.showMemberships === false ? [] : source.memberships ?? [],
38515
38672
  passPurchaseMode,
38516
- buttonVariant: source.buttonVariant ?? "primary"
38673
+ buttonVariant: source.buttonVariant ?? "primary",
38674
+ demoEmailSuppressed: source.demoEmailSuppressed
38517
38675
  }
38518
38676
  };
38519
38677
  }
@@ -38606,7 +38764,8 @@ const checkoutBlockRuntime = defineClientOwnedBlockRuntime({
38606
38764
  }),
38607
38765
  hydration: {
38608
38766
  emptyStateText: source.emptyStateText ?? "Add something to your cart to continue.",
38609
- submitButtonText: source.submitButtonText ?? "Checkout"
38767
+ submitButtonText: source.submitButtonText ?? "Checkout",
38768
+ demoEmailSuppressed: source.demoEmailSuppressed
38610
38769
  }
38611
38770
  })
38612
38771
  });
@@ -38847,6 +39006,10 @@ const checkoutBlockDefinition = {
38847
39006
  baseClass: "",
38848
39007
  spacing: "spacious",
38849
39008
  children: sectionContainer([checkout(withApiBindings({
39009
+ demoEmailSuppressed: { $bind: {
39010
+ from: "$root.demoEmailSuppressed",
39011
+ fallback: false
39012
+ } },
38850
39013
  readAuthority: { $bind: { from: "$root.readAuthority" } },
38851
39014
  mode: "checkout",
38852
39015
  heading: { $bind: {
@@ -39259,6 +39422,7 @@ const EVENT_REGISTRATION_SHELL_STEP_LABELS = [
39259
39422
  ];
39260
39423
  const eventRegistrationPublicEventSchema = z.preprocess(normalizeEventRegistrationEventInput, publicEventSchema);
39261
39424
  const eventRegistrationHydrationSchemaShape = {
39425
+ demoEmailSuppressed: z.boolean().optional(),
39262
39426
  occurrenceContext: occurrenceContextSchema.optional(),
39263
39427
  subject: eventRegistrationPageSurfaceSubjectSchema.nullable().optional(),
39264
39428
  maxTickets: z.string().optional(),
@@ -39439,6 +39603,7 @@ const eventRegistrationBlockRuntime = defineClientOwnedBlockRuntime({
39439
39603
  ...eventSource,
39440
39604
  events: [...scopedSourceEvents]
39441
39605
  } : eventSource,
39606
+ demoEmailSuppressed: source.demoEmailSuppressed,
39442
39607
  maxTickets: source.maxTickets ?? void 0,
39443
39608
  showVenue: source.showVenue,
39444
39609
  showCapacity: source.showCapacity,
@@ -39582,8 +39747,8 @@ const eventRegistrationBlockDefinition = {
39582
39747
  description: "Message shown after successful registration",
39583
39748
  required: false,
39584
39749
  multiline: true,
39585
- defaultValue: "Thank you for registering! Check your email for confirmation details.",
39586
- maxLength: 500
39750
+ maxLength: 500,
39751
+ ui: { placeholder: "Thank you for registering! Check your email for confirmation details." }
39587
39752
  },
39588
39753
  {
39589
39754
  id: "buttonText",
@@ -39604,6 +39769,10 @@ const eventRegistrationBlockDefinition = {
39604
39769
  text({ as: "h2" }, bind("content.heading"), when("content.heading")),
39605
39770
  richText({ className: "rb-prose rb-max-w-none" }, bind("content.description"), when("content.description")),
39606
39771
  eventRegistration(withApiBindings({
39772
+ demoEmailSuppressed: { $bind: {
39773
+ from: "$root.demoEmailSuppressed",
39774
+ fallback: false
39775
+ } },
39607
39776
  readAuthority: { $bind: { from: "$root.readAuthority" } },
39608
39777
  occurrenceContext: { $bind: { from: "$root.occurrenceContext" } },
39609
39778
  subject: { $bind: { from: "$root.subject" } },
@@ -42644,6 +42813,10 @@ const shopBlockDefinition = {
42644
42813
  spacing: "spacious",
42645
42814
  children: sectionContainer([shop(withApiBindings({
42646
42815
  readAuthority: { $bind: { from: "$root.readAuthority" } },
42816
+ demoEmailSuppressed: { $bind: {
42817
+ from: "$root.demoEmailSuppressed",
42818
+ fallback: false
42819
+ } },
42647
42820
  mode: "passes-memberships",
42648
42821
  showPasses: { $bind: {
42649
42822
  from: "content.showPasses",
@@ -43134,11 +43307,12 @@ function CartSSR({ blockId, siteId, apiBaseUrl, stage, children, ...rest }) {
43134
43307
  }
43135
43308
  //#endregion
43136
43309
  //#region ../blocks/src/system/runtime/nodes/checkout.server.tsx
43137
- function CheckoutSSR({ blockId, siteId, apiBaseUrl, stage, children, ...rest }) {
43310
+ function CheckoutSSR({ blockId, siteId, apiBaseUrl, stage, demoEmailSuppressed, children, ...rest }) {
43138
43311
  const islandProps = buildCheckoutInteractiveIslandProps({
43139
43312
  siteId,
43140
43313
  apiBaseUrl,
43141
43314
  stage,
43315
+ demoEmailSuppressed,
43142
43316
  ...rest
43143
43317
  });
43144
43318
  return /* @__PURE__ */ jsxs("div", {
@@ -49345,6 +49519,7 @@ function buildPageRendererRootRuntime(dataContext) {
49345
49519
  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 ?? {};
49346
49520
  return {
49347
49521
  siteId,
49522
+ demoEmailSuppressed: resolveDemoEmailSuppression(dataContext),
49348
49523
  siteName,
49349
49524
  pageId,
49350
49525
  pathname,
@@ -49360,6 +49535,9 @@ function buildPageRendererRootRuntime(dataContext) {
49360
49535
  loaderFailures
49361
49536
  };
49362
49537
  }
49538
+ function resolveDemoEmailSuppression(dataContext) {
49539
+ return dataContext?.demoEmailSuppressed === true;
49540
+ }
49363
49541
  //#endregion
49364
49542
  //#region ../blocks/src/pageRenderAudience.tsx
49365
49543
  /**
@@ -53881,6 +54059,10 @@ const bookingDescription = richText({}, bind("content.description"), when("conte
53881
54059
  * that hydration never rewrites.
53882
54060
  */
53883
54061
  const bookingWizard = bookingForm(withApiBindings({
54062
+ demoEmailSuppressed: { $bind: {
54063
+ from: "$root.demoEmailSuppressed",
54064
+ fallback: false
54065
+ } },
53884
54066
  portalToken: { $bind: {
53885
54067
  from: "$root.portalToken",
53886
54068
  fallback: null
@@ -59195,15 +59377,17 @@ function planNewsletterBlockSubmission(placement) {
59195
59377
  sourceRef
59196
59378
  } : { tag: "unavailable" };
59197
59379
  }
59198
- if (placement.publishedPlacement && "kind" in placement.publishedPlacement) return { tag: "unpublished-settings" };
59199
- if (placement.publishedPlacement) return planNewsletterPreviewSubmission({
59200
- blockId: placement.blockId,
59201
- publishedContentId: placement.publishedPlacement.id,
59202
- renderedContent: placement.renderedContent,
59203
- publishedContent: placement.publishedPlacement.content
59204
- });
59205
- if (placement.stage === "preview") return { tag: "unpublished-form" };
59206
- return { tag: "unavailable" };
59380
+ const published = placement.publishedPlacement;
59381
+ if (published === null) return placement.stage === "preview" ? { tag: "unpublished-form" } : { tag: "unavailable" };
59382
+ switch (published.kind) {
59383
+ case "incomplete": return { tag: "unpublished-settings" };
59384
+ case "published": return planNewsletterPreviewSubmission({
59385
+ blockId: placement.blockId,
59386
+ publishedContentId: published.id,
59387
+ renderedContent: placement.renderedContent,
59388
+ publishedContent: published.content
59389
+ });
59390
+ }
59207
59391
  }
59208
59392
  /** Decide whether the visible draft can safely cite the published placement. */
59209
59393
  function planNewsletterPreviewSubmission(placement) {
@@ -59450,19 +59634,6 @@ function createBlockErrorBoundary() {
59450
59634
  const BlockErrorBoundary = createBlockErrorBoundary();
59451
59635
  //#endregion
59452
59636
  //#region ../blocks/src/pageRenderAdmission.ts
59453
- /** Pair a published version with the content it authorises at the render boundary. */
59454
- function readPublishedBlockPlacement(id, content) {
59455
- if (id == null && content == null) return null;
59456
- if (id == null || content == null) return {
59457
- kind: "incomplete",
59458
- id: id ?? null,
59459
- content: content ?? null
59460
- };
59461
- return {
59462
- id,
59463
- content
59464
- };
59465
- }
59466
59637
  function toPresentationPage(page) {
59467
59638
  if (!page) return null;
59468
59639
  return {
@@ -73598,922 +73769,213 @@ function toBlocksImageResolveContextInput(context) {
73598
73769
  };
73599
73770
  }
73600
73771
  //#endregion
73601
- //#region src/rendering/blocks-page-renderer.ts
73602
- const MissingBlockOverrideError = MissingBlockOverrideError$1;
73603
- function isOverrideOnlyPageRenderer(props) {
73604
- return props.rendering?.kind === "overrides-only";
73772
+ //#region ../blocks/src/system/runtime/bindings.ts
73773
+ const shouldLogWarnings = isNonProductionEnv();
73774
+ function isPlainObject(value) {
73775
+ return typeof value === "object" && value !== null && !Array.isArray(value);
73605
73776
  }
73606
- function normalizeSdkCustomBlocks(customBlocks) {
73607
- if (!customBlocks) return void 0;
73608
- return customBlocks.map((block) => {
73609
- return {
73610
- ...block,
73611
- fields: parseFieldDefinitions(block.fields)
73612
- };
73613
- });
73777
+ function isRouteMapEntry(value) {
73778
+ if (typeof value === "string") return true;
73779
+ return isPlainObject(value);
73614
73780
  }
73615
- function toBlocksBlockOverrides(overrides) {
73616
- if (!overrides) return void 0;
73617
- const result = {};
73618
- for (const [key, OverrideComponent] of Object.entries(overrides)) result[key] = function BlocksOverrideAdapter(props) {
73619
- const sdkOverride = OverrideComponent;
73620
- return React$1.createElement(sdkOverride, {
73621
- ...props,
73622
- entrySubrouteContext: props.entrySubrouteContext
73623
- });
73624
- };
73625
- return result;
73781
+ function isRouteMap(value) {
73782
+ if (!isPlainObject(value)) return false;
73783
+ return Object.values(value).every(isRouteMapEntry);
73626
73784
  }
73627
- function toBlocksPageRendererDataContext(dataContext) {
73628
- return {
73629
- ...dataContext,
73630
- mediaAssets: toBlocksMediaAssets(dataContext.mediaAssets),
73631
- imageResolveContext: toBlocksImageResolveContextInput(dataContext.imageResolveContext)
73632
- };
73785
+ function isPageIdentifierMap(value) {
73786
+ if (!isPlainObject(value)) return false;
73787
+ return Object.values(value).every((v) => typeof v === "string");
73633
73788
  }
73634
- function toBlocksCommonProps(props) {
73635
- return {
73636
- page: props.page,
73637
- runtimeJoins: props.runtimeJoins,
73638
- dataContext: toBlocksPageRendererDataContext(props.dataContext),
73639
- routeMap: props.routeMap,
73640
- wrapBlock: props.wrapBlock,
73641
- registry: props.registry,
73642
- blockOverrides: toBlocksBlockOverrides(props.blockOverrides),
73643
- sdkConfig: props.sdkConfig ? { customBlocks: normalizeSdkCustomBlocks(props.sdkConfig.customBlocks) } : props.sdkConfig,
73644
- customBlocks: normalizeSdkCustomBlocks(props.customBlocks)
73645
- };
73789
+ function isEntryIdentifierMap(value) {
73790
+ if (!isPlainObject(value)) return false;
73791
+ for (const v of Object.values(value)) {
73792
+ if (!isPlainObject(v)) return false;
73793
+ if (!Object.values(v).every((inner) => typeof inner === "string")) return false;
73794
+ }
73795
+ return true;
73646
73796
  }
73647
- function PageRenderer(props) {
73648
- const commonBlocksProps = toBlocksCommonProps(props);
73649
- const blocksProps = isOverrideOnlyPageRenderer(props) ? {
73650
- ...commonBlocksProps,
73651
- rendering: { kind: "overrides-only" },
73652
- blockOverrides: toBlocksBlockOverrides(props.blockOverrides) ?? {}
73653
- } : {
73654
- ...commonBlocksProps,
73655
- theme: parseBlocksTheme(props.theme),
73656
- themeTokens: props.themeTokens
73797
+ function buildTransformContext(vm) {
73798
+ const root = vm.$root;
73799
+ const stage = root && isPlainObject(root) && root.previewStage === "preview" ? "preview" : "published";
73800
+ const routes = root && isPlainObject(root) && isRouteMap(root.routes) ? root.routes : void 0;
73801
+ const pagesByIdentifier = root && isPlainObject(root) && isPageIdentifierMap(root.pagesByIdentifier) ? root.pagesByIdentifier : void 0;
73802
+ const entriesByIdentifier = root && isPlainObject(root) && isEntryIdentifierMap(root.entriesByIdentifier) ? root.entriesByIdentifier : void 0;
73803
+ return {
73804
+ theme: defaultThemeTokens,
73805
+ stage,
73806
+ data: vm.content,
73807
+ routes,
73808
+ pagesByIdentifier,
73809
+ entriesByIdentifier
73657
73810
  };
73658
- return React$1.createElement(PageRenderer$1, blocksProps);
73659
- }
73660
- //#endregion
73661
- //#region src/rendering/blocks-theme-scope.ts
73662
- function ThemeScope(props) {
73663
- const { theme, children, ...rest } = props;
73664
- const blocksTheme = parseBlocksTheme(theme);
73665
- return React$1.createElement(ThemeScope$1, {
73666
- ...rest,
73667
- theme: blocksTheme,
73668
- children: children ?? null
73669
- });
73670
73811
  }
73671
- //#endregion
73672
- //#region src/rendering/themeRuntime.tsx
73673
- const defaultLayoutThemeRuntime = { kind: "cms-theme" };
73674
- const defaultSdkChromeThemeRuntime = { kind: "responsive-only" };
73675
- const defaultPageThemeRuntime = { kind: "none" };
73676
- function planLayoutThemeRuntime(input) {
73677
- const requested = input.themeRuntime ?? defaultLayoutThemeRuntime;
73678
- if (requested.kind === "none" && input.usesSdkChrome) {
73679
- 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.");
73680
- return defaultSdkChromeThemeRuntime;
73812
+ function resolveParamsBindings(input, vm, meta) {
73813
+ if (input === null || typeof input !== "object") return input;
73814
+ if (Array.isArray(input)) return input.map((v) => resolveParamsBindings(v, vm, meta));
73815
+ const maybeBind = input.$bind;
73816
+ if (maybeBind && typeof maybeBind === "object") try {
73817
+ const binding = bindingSchema.parse(maybeBind);
73818
+ const value = resolveBinding(binding.from, vm);
73819
+ const resolved = value === void 0 || value === null ? binding.fallback : runTransforms(value, binding.transforms, buildTransformContext(vm), defaultTransforms);
73820
+ if (resolved === void 0 || resolved === null || resolved === "") return binding.fallback;
73821
+ return resolved;
73822
+ } catch (err) {
73823
+ if (shouldLogWarnings) console.warn(`bindings: failed to parse loader param binding for block "${meta?.blockKind ?? "unknown"}"`, err);
73824
+ return;
73681
73825
  }
73682
- return requested;
73826
+ const out = {};
73827
+ for (const [k, v] of Object.entries(input)) out[k] = resolveParamsBindings(v, vm, meta);
73828
+ return out;
73683
73829
  }
73684
- function renderWithSdkThemeRuntime({ themeRuntime, theme, children }) {
73685
- switch (themeRuntime.kind) {
73686
- case "cms-theme": return /* @__PURE__ */ jsx(ThemeScope, {
73687
- theme,
73688
- responsiveMode: themeRuntime.responsiveMode,
73689
- children
73690
- });
73691
- case "responsive-only": return /* @__PURE__ */ jsx(ResponsiveScope, {
73692
- responsiveMode: themeRuntime.responsiveMode,
73693
- children
73694
- });
73695
- case "none": return /* @__PURE__ */ jsx(Fragment, { children });
73696
- default: return assertNever$4(themeRuntime);
73830
+ function resolveBinding(path, vm) {
73831
+ const segments = splitPath(path);
73832
+ if (!segments.length) return void 0;
73833
+ const [first, ...rest] = segments;
73834
+ let source = vm;
73835
+ if (first === "$root") {
73836
+ source = vm;
73837
+ return readFromSource(source, [first, ...rest]);
73697
73838
  }
73698
- }
73699
- function renderWithOverrideOnlyRuntime({ runtime, children }) {
73700
- switch (runtime.kind) {
73701
- case "responsive-only": return /* @__PURE__ */ jsx(ResponsiveScope, {
73702
- responsiveMode: runtime.responsiveMode,
73703
- children
73704
- });
73705
- case "none": return /* @__PURE__ */ jsx(Fragment, { children });
73706
- default: return assertNever$4(runtime);
73839
+ if (first === "content") {
73840
+ source = vm.content;
73841
+ return readFromSource(source, rest);
73707
73842
  }
73843
+ const contentResult = readFromSource(vm.content, segments);
73844
+ if (contentResult !== void 0) return contentResult;
73845
+ return readFromSource(vm, segments);
73708
73846
  }
73709
- //#endregion
73710
- //#region src/rendering/components/pageShared.tsx
73711
- function isOverrideOnlyPage(props) {
73712
- return props.rendering?.kind === "overrides-only";
73713
- }
73714
- function resolvePageThemeTokens(props) {
73715
- const baseTokens = props.themeTokens ?? buildThemeRuntime(props.theme).tokens;
73716
- return props.sdkConfig?.theme?.palette ? {
73717
- ...baseTokens,
73718
- palette: {
73719
- ...baseTokens.palette,
73720
- ...props.sdkConfig.theme.palette
73847
+ function splitPath(path) {
73848
+ const PATH_SEPARATOR_REGEX = /\./g;
73849
+ const BRACKET_ACCESS_REGEX = /\[(?<token>[^\]]+)\]/g;
73850
+ const segments = [];
73851
+ const parts = path.split(PATH_SEPARATOR_REGEX);
73852
+ for (const raw of parts) {
73853
+ if (!raw) continue;
73854
+ const baseMatch = raw.match(/^([^\[]+)/);
73855
+ if (baseMatch && baseMatch[1]) segments.push(baseMatch[1]);
73856
+ const bracketMatches = raw.matchAll(BRACKET_ACCESS_REGEX);
73857
+ for (const match of bracketMatches) {
73858
+ const token = match.groups?.token ?? "";
73859
+ if (token.startsWith("\"") || token.startsWith("'")) segments.push(token.slice(1, -1));
73860
+ else if (/^\d+$/.test(token)) segments.push(Number(token));
73861
+ else segments.push(token);
73721
73862
  }
73722
- } : baseTokens;
73723
- }
73724
- function resolveSdkBookingTimeZone(timeZone) {
73725
- return timeZone ?? "UTC";
73726
- }
73727
- function buildPageRouteRenderContext(dataContext) {
73728
- return {
73729
- ...buildPageIdentityRenderContext(dataContext),
73730
- occurrenceContext: dataContext.occurrenceContext ?? null,
73731
- entrySubrouteContext: dataContext.entrySubrouteContext ?? null,
73732
- contentEntry: dataContext.contentEntry ?? null,
73733
- pageSurface: dataContext.pageSurface ?? null,
73734
- subject: dataContext.subject ?? null,
73735
- editableRouteMetadataFieldIds: dataContext.editableRouteMetadataFieldIds ?? null,
73736
- previewStage: dataContext.previewStage
73737
- };
73863
+ if (!baseMatch && !raw.includes("[")) segments.push(raw);
73864
+ }
73865
+ return segments;
73738
73866
  }
73739
- function buildPageIdentityRenderContext(dataContext) {
73740
- return {
73741
- siteName: dataContext.siteName,
73742
- pathname: dataContext.pathname
73743
- };
73867
+ function readFromSource(source, segments) {
73868
+ return segments.reduce((current, segment) => {
73869
+ if (current === void 0 || current === null) return void 0;
73870
+ if (typeof segment === "number") {
73871
+ if (Array.isArray(current)) return current[segment];
73872
+ return;
73873
+ }
73874
+ if (typeof current === "object" && current !== null && segment in current) return current[segment];
73875
+ }, source);
73744
73876
  }
73745
- function PageContent(props) {
73746
- const { page, runtimeJoins, siteId, resolvedData, bookingOfferingPresets, mailingList, bookingTimeZone, routeMap, pagesByIdentifier, entriesByIdentifier, wrapBlock, registry, blockOverrides, sdkConfig, customBlocks, supabaseUrl, mediaAssets, apiBaseUrl, portalToken, previewToken, readAuthority, dataContext } = props;
73747
- const rendererCommonProps = {
73748
- page,
73749
- runtimeJoins,
73750
- dataContext: {
73751
- siteId,
73752
- ...buildPageRouteRenderContext(dataContext),
73753
- apiBaseUrl,
73754
- portalToken,
73755
- previewToken,
73756
- readAuthority: readAuthority ?? dataContext.readAuthority,
73757
- resolvedData,
73758
- bookingOfferingPresets: bookingOfferingPresets ?? [],
73759
- mailingList: mailingList ?? dataContext.mailingList,
73760
- bookingTimeZone: resolveSdkBookingTimeZone(bookingTimeZone),
73761
- routes: routeMap,
73762
- pagesByIdentifier,
73763
- entriesByIdentifier,
73764
- supabaseUrl,
73765
- mediaAssets,
73766
- imageResolveContext: {
73767
- siteId,
73768
- supabaseUrl,
73769
- mediaAssets
73770
- }
73771
- },
73772
- routeMap,
73773
- wrapBlock,
73774
- registry,
73775
- sdkConfig: sdkConfig ? { customBlocks: sdkConfig.customBlocks } : null,
73776
- customBlocks
73777
- };
73778
- const content = isOverrideOnlyPage(props) ? /* @__PURE__ */ jsx(PageRenderer, {
73779
- ...rendererCommonProps,
73780
- rendering: { kind: "overrides-only" },
73781
- blockOverrides: props.blockOverrides
73782
- }) : /* @__PURE__ */ jsx(PageRenderer, {
73783
- ...rendererCommonProps,
73784
- theme: props.theme,
73785
- themeTokens: resolvePageThemeTokens(props),
73786
- blockOverrides
73787
- });
73788
- return isOverrideOnlyPage(props) ? renderWithOverrideOnlyRuntime({
73789
- runtime: props.rendering.runtime,
73790
- children: content
73791
- }) : renderWithSdkThemeRuntime({
73792
- themeRuntime: props.themeRuntime ?? defaultPageThemeRuntime,
73793
- theme: props.theme,
73794
- children: content
73795
- });
73877
+ function isNonProductionEnv() {
73878
+ if (typeof globalThis === "undefined") return true;
73879
+ return globalThis.process?.env?.NODE_ENV !== "production";
73796
73880
  }
73797
73881
  //#endregion
73798
- //#region src/rendering/components/Page.server.tsx
73799
- function Page(props) {
73800
- return /* @__PURE__ */ jsx(PageContent, { ...props });
73882
+ //#region ../blocks/src/system/data/utils.ts
73883
+ /**
73884
+ * Normalize data loaders from block definition
73885
+ */
73886
+ function normalizeDataLoaders(def) {
73887
+ if (!def?.dataLoaders) return [];
73888
+ return Object.entries(def.dataLoaders).map(([key, loader]) => ({
73889
+ key,
73890
+ loader
73891
+ }));
73801
73892
  }
73802
- //#endregion
73803
- //#region src/env.ts
73804
73893
  /**
73805
- * Error thrown when required environment variables are missing
73894
+ * Normalize block content for data loading.
73895
+ * Priority: draftContent > content > publishedContent
73806
73896
  */
73807
- var RiverbankEnvError = class extends Error {
73808
- constructor(message, missingVars) {
73809
- super(message);
73810
- this.missingVars = missingVars;
73811
- this.name = "RiverbankEnvError";
73897
+ function normalizeContent(block) {
73898
+ const source = block.draftContent ?? block.content ?? block.publishedContent ?? {};
73899
+ if (!isObjectRecord$1(source)) return {};
73900
+ if ("data" in source) {
73901
+ const data = source.data;
73902
+ if (isObjectRecord$1(data)) return data;
73903
+ if (data === null || data === void 0) return {};
73812
73904
  }
73813
- };
73905
+ return source;
73906
+ }
73814
73907
  /**
73815
- * Get the environment variable prefix based on target
73908
+ * Normalize params for API calls.
73909
+ * Converts supplied values to strings, preserving absent versus explicitly empty params.
73816
73910
  */
73817
- function getEnvPrefix(target) {
73818
- return target === "remote" ? "RIVERBANK_REMOTE" : "RIVERBANK_LOCAL";
73911
+ function normalizeParams(input) {
73912
+ if (!input || typeof input !== "object") return {};
73913
+ const output = {};
73914
+ for (const [key, value] of Object.entries(input)) if (value !== void 0 && value !== null) output[key] = coerceToString(value);
73915
+ return output;
73916
+ }
73917
+ function isNonArrayObject(value) {
73918
+ return typeof value === "object" && value !== null && !Array.isArray(value);
73919
+ }
73920
+ function safeJsonStringify(value) {
73921
+ try {
73922
+ return JSON.stringify(value);
73923
+ } catch {
73924
+ return;
73925
+ }
73819
73926
  }
73820
73927
  /**
73821
- * Detect the environment target from RIVERBANK_ENV
73928
+ * Coerce value to string for API params
73822
73929
  */
73823
- function detectTarget() {
73824
- const env = process.env.RIVERBANK_ENV?.toLowerCase();
73825
- if (env === "remote" || env === "production" || env === "prod") return "remote";
73826
- return "local";
73930
+ function coerceToString(value) {
73931
+ if (value === null || value === void 0) return "";
73932
+ if (Array.isArray(value)) {
73933
+ if (value.some(isNonArrayObject)) {
73934
+ const json = safeJsonStringify(value);
73935
+ if (typeof json === "string") return json;
73936
+ }
73937
+ return value.map(coerceToString).join(",");
73938
+ }
73939
+ if (isNonArrayObject(value)) {
73940
+ const json = safeJsonStringify(value);
73941
+ if (typeof json === "string") return json;
73942
+ }
73943
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") return String(value);
73944
+ return "";
73827
73945
  }
73828
73946
  /**
73829
- * Detect if preview mode is enabled.
73830
- * Uses RIVERBANK_PREVIEW_MODE first, then falls back to RIVERBANK_PREVIEW for backward compat.
73947
+ * The appointment-services catalogue (issue 1403) pairs the services with the
73948
+ * site's ordered categories. Both are needed to group them, so that response
73949
+ * is passed through whole; any other `{ services }` wrapper is unwrapped.
73831
73950
  */
73832
- function detectPreviewMode() {
73833
- const previewMode = process.env.RIVERBANK_PREVIEW_MODE;
73834
- if (previewMode !== void 0 && previewMode !== "") return previewMode === "true";
73835
- const previewLegacy = process.env.RIVERBANK_PREVIEW;
73836
- if (previewLegacy !== void 0 && previewLegacy !== "") return previewLegacy === "true";
73837
- return process.env.VERCEL_ENV === "preview";
73951
+ function coerceServicesPayload(record) {
73952
+ return Array.isArray(record.services) && Array.isArray(record.categories) ? {
73953
+ services: record.services,
73954
+ categories: record.categories
73955
+ } : record.services;
73838
73956
  }
73839
73957
  /**
73840
- * Validate that an API key matches the expected format for its type
73958
+ * Extract data from API response.
73959
+ * Unwraps common response wrappers: { data }, { form }, { entries }, { services }, { teamMembers }
73960
+ *
73961
+ * Note: We check that properties are NOT functions to avoid returning
73962
+ * built-in methods like Array.prototype.entries
73841
73963
  */
73842
- function validateKeyType(key, expectedType) {
73843
- const isPreviewKey = key.startsWith("bld_preview_sk_");
73844
- const isContentKey = key.startsWith("bld_live_sk_");
73845
- if (expectedType === "preview" && !isPreviewKey) {
73846
- 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.", []);
73847
- throw new RiverbankEnvError(`Invalid API key format for preview mode. Expected key starting with bld_preview_sk_`, []);
73848
- }
73849
- if (expectedType === "content" && !isContentKey) {
73850
- if (isPreviewKey) {
73851
- console.debug("[getRiverbankEnv] Using preview key for published content. Consider using a content key (bld_live_sk_...) for production.");
73852
- return;
73853
- }
73854
- throw new RiverbankEnvError(`Invalid API key format for content access. Expected key starting with bld_live_sk_ or bld_preview_sk_`, []);
73964
+ function coercePayload(payload) {
73965
+ const linkedContentEntries = coerceLinkedContentEntriesPayload(payload);
73966
+ if (linkedContentEntries !== payload) return linkedContentEntries;
73967
+ if (payload && typeof payload === "object" && !Array.isArray(payload)) {
73968
+ const record = payload;
73969
+ if ("data" in record && typeof record.data !== "function") return record.data;
73970
+ if ("form" in record && typeof record.form !== "function") return record.form;
73971
+ if ("entries" in record && typeof record.entries !== "function") return record.entries;
73972
+ if ("services" in record && typeof record.services !== "function") return coerceServicesPayload(record);
73973
+ if ("teamMembers" in record && typeof record.teamMembers !== "function") return record.teamMembers;
73855
73974
  }
73975
+ return payload;
73856
73976
  }
73857
- /**
73858
- * Get runtime environment configuration with automatic API key selection.
73859
- *
73860
- * This helper reads environment variables and automatically selects the correct
73861
- * API key based on the current environment and preview mode:
73862
- *
73863
- * - When `RIVERBANK_PREVIEW_MODE=true`: Uses preview API key (bld_preview_sk_...)
73864
- * - When `RIVERBANK_PREVIEW_MODE=false` (default): Uses content API key (bld_live_sk_...)
73865
- *
73866
- * Environment variable patterns:
73867
- * - `RIVERBANK_ENV`: 'local' (default) or 'remote'
73868
- * - `RIVERBANK_PREVIEW_MODE`: 'true' or 'false' (default)
73869
- * - `RIVERBANK_{LOCAL|REMOTE}_SITE_ID`: Site ID
73870
- * - `RIVERBANK_{LOCAL|REMOTE}_DASHBOARD_URL`: Dashboard URL
73871
- * - `RIVERBANK_{LOCAL|REMOTE}_API_KEY`: Content/live API key
73872
- * - `RIVERBANK_{LOCAL|REMOTE}_PREVIEW_API_KEY`: Preview API key
73873
- *
73874
- * @returns Environment configuration with auto-selected API key
73875
- * @throws {RiverbankEnvError} If required environment variables are missing
73876
- *
73877
- * @example
73878
- * ```ts
73879
- * // lib/builder-client.ts
73880
- * import { getRiverbankEnv } from '@riverbankcms/sdk/env';
73881
- * import { createRiverbankClient } from '@riverbankcms/sdk';
73882
- *
73883
- * const env = getRiverbankEnv();
73884
- *
73885
- * export const client = createRiverbankClient({
73886
- * apiKey: env.apiKey,
73887
- * baseUrl: env.baseUrl,
73888
- * });
73889
- *
73890
- * export const siteId = env.siteId;
73891
- * ```
73892
- */
73893
- function getRiverbankEnv() {
73894
- const target = detectTarget();
73895
- const previewMode = detectPreviewMode();
73896
- const prefix = getEnvPrefix(target);
73897
- const siteId = process.env[`${prefix}_SITE_ID`];
73898
- const dashboardUrl = process.env[`${prefix}_DASHBOARD_URL`];
73899
- const contentKey = process.env[`${prefix}_API_KEY`];
73900
- const previewKey = process.env[`${prefix}_PREVIEW_API_KEY`];
73901
- const missingVars = [];
73902
- if (!siteId) missingVars.push(`${prefix}_SITE_ID`);
73903
- if (!dashboardUrl) missingVars.push(`${prefix}_DASHBOARD_URL`);
73904
- let apiKey;
73905
- let keyType;
73906
- if (previewMode) {
73907
- apiKey = previewKey;
73908
- keyType = "preview";
73909
- if (!apiKey) missingVars.push(`${prefix}_PREVIEW_API_KEY`);
73910
- } else {
73911
- apiKey = contentKey || previewKey;
73912
- keyType = contentKey ? "content" : "preview";
73913
- if (!apiKey) missingVars.push(`${prefix}_API_KEY`);
73914
- }
73915
- 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);
73916
- if (!apiKey || !dashboardUrl || !siteId) throw new RiverbankEnvError("Required environment variables missing", missingVars);
73917
- validateKeyType(apiKey, keyType);
73918
- let baseUrl = dashboardUrl;
73919
- if (!baseUrl.endsWith("/api")) baseUrl = baseUrl.replace(/\/$/, "") + "/api";
73920
- return {
73921
- target,
73922
- previewMode,
73923
- siteId,
73924
- baseUrl,
73925
- apiKey,
73926
- keyType
73927
- };
73928
- }
73929
- //#endregion
73930
- //#region src/navigation/index.ts
73931
- /**
73932
- * Get the fixed main navigation menu object.
73933
- * Returns null when the runtime payload is incomplete.
73934
- *
73935
- * @example
73936
- * ```ts
73937
- * const menu = getPrimaryNavigation(siteData.navigation);
73938
- * console.log(menu?.location); // "main"
73939
- * ```
73940
- */
73941
- function getPrimaryNavigation(navigation) {
73942
- if (!navigation || navigation.length === 0) return null;
73943
- return navigation.find((menu) => menu.location === "main") ?? null;
73944
- }
73945
- function getFooterNavigationByRole(navigation, role) {
73946
- if (!navigation || navigation.length === 0) return null;
73947
- const canonicalLocation = role === "main" ? "footer" : "legal";
73948
- return navigation.find((menu) => menu.location === canonicalLocation) ?? null;
73949
- }
73950
- /**
73951
- * Resolve alt text with fallback.
73952
- * Returns the provided alt if non-empty, otherwise falls back to the provided fallback or 'Site logo'.
73953
- * @internal
73954
- */
73955
- function resolveAltText(alt, fallback) {
73956
- return alt && alt.trim().length > 0 ? alt : fallback ?? "Site logo";
73957
- }
73958
- function readNavigationItemPayload(item) {
73959
- return item.url ?? null;
73960
- }
73961
- function isPortalEnabled(options) {
73962
- return options?.portalEnabled === true;
73963
- }
73964
- function isCommerceEnabled(options) {
73965
- return options?.commerceEnabled === true;
73966
- }
73967
- function resolvePortalHref(link) {
73968
- return link.path?.trim() || "/portal";
73969
- }
73970
- function resolveCheckoutHref(options) {
73971
- if (options?.checkoutHref === null) return null;
73972
- const href = options?.checkoutHref?.trim();
73973
- return href && href.length > 0 ? href : "/checkout";
73974
- }
73975
- function resolvePortalLabel(link, options) {
73976
- const loggedOutLabel = link.labels?.loggedOut?.trim() || PORTAL_NAV_DEFAULT_LABELS.loggedOut;
73977
- const loggedInLabel = link.labels?.loggedIn?.trim() || PORTAL_NAV_DEFAULT_LABELS.loggedIn;
73978
- return options?.hasPortalSession ? loggedInLabel : loggedOutLabel;
73979
- }
73980
- function resolveItemLabel(link, fallbackLabel, options) {
73981
- if (link?.kind === "portal") return resolvePortalLabel(link, options);
73982
- if (link?.kind === "cart") return resolveCartVisibleLabel(link) ?? fallbackLabel;
73983
- return fallbackLabel;
73984
- }
73985
- function resolveCartVisibleLabel(link) {
73986
- if (link.label.kind !== "icon-with-label") return null;
73987
- const label = link.label.label.trim();
73988
- return label.length > 0 ? label : null;
73989
- }
73990
- function resolveCartAriaLabel(link, fallbackLabel) {
73991
- const fallback = fallbackLabel.trim();
73992
- return resolveCartVisibleLabel(link) ?? (fallback.length > 0 ? fallback : "Cart");
73993
- }
73994
- function buildCartNavViewModel(link, fallbackLabel, options) {
73995
- return {
73996
- visibleLabel: resolveCartVisibleLabel(link),
73997
- badge: link.badge,
73998
- ariaLabel: resolveCartAriaLabel(link, fallbackLabel),
73999
- checkoutHref: resolveCheckoutHref(options)
74000
- };
74001
- }
74002
- function deriveRenderableNavigationLink(item, options) {
74003
- const payload = readNavigationItemPayload(item);
74004
- if (!payload) return null;
74005
- if (payload.kind === "portal" && !isPortalEnabled(options)) return null;
74006
- if (payload.kind === "cart" && !isCommerceEnabled(options)) return null;
74007
- return {
74008
- id: item.id,
74009
- label: resolveItemLabel(payload, item.label, options),
74010
- payload,
74011
- isExternal: isExternalLink(payload),
74012
- ...payload.kind === "cart" ? { cart: buildCartNavViewModel(payload, item.label, options) } : {}
74013
- };
74014
- }
74015
- function buildNavLinkFromResolvedHref(item, href) {
74016
- if (!href) return null;
74017
- return {
74018
- kind: "link",
74019
- id: item.id,
74020
- label: item.label,
74021
- href,
74022
- link: { href },
74023
- isExternal: item.isExternal,
74024
- ...item.cart ? { cart: item.cart } : {}
74025
- };
74026
- }
74027
- /**
74028
- * Determines if a navigation item's link is external.
74029
- */
74030
- function isExternalLink(link) {
74031
- if (!link) return false;
74032
- return link.kind === "external";
74033
- }
74034
- /**
74035
- * Build a map of children items by parent ID.
74036
- * Also warns about deeply nested items (grandchildren) which CMS shouldn't allow.
74037
- * @internal
74038
- */
74039
- function buildChildrenByParentId(items) {
74040
- const childrenByParentId = /* @__PURE__ */ new Map();
74041
- const itemsById = /* @__PURE__ */ new Map();
74042
- for (const item of items) itemsById.set(item.id, item);
74043
- for (const item of items) if (item.parentId) {
74044
- if (itemsById.get(item.parentId)?.parentId && typeof process !== "undefined" && process.env.NODE_ENV !== "production") {
74045
- 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.`);
74046
- continue;
74047
- }
74048
- const siblings = childrenByParentId.get(item.parentId) ?? [];
74049
- siblings.push(item);
74050
- childrenByParentId.set(item.parentId, siblings);
74051
- }
74052
- return childrenByParentId;
74053
- }
74054
- /**
74055
- * Generic nested structure builder.
74056
- * @internal
74057
- */
74058
- function buildNestedStructure(items, options) {
74059
- const childrenByParentId = buildChildrenByParentId(items);
74060
- const rootItems = items.filter((item) => !item.parentId).sort((a, b) => (a.orderIndex ?? a.position ?? 0) - (b.orderIndex ?? b.position ?? 0));
74061
- const result = [];
74062
- let ctaItem = null;
74063
- for (const item of rootItems) {
74064
- if (options.extractCta && !ctaItem && Boolean(item.isCta) && item.urlType !== "dropdown") {
74065
- const link = options.toLink(item);
74066
- if (link) {
74067
- ctaItem = link;
74068
- continue;
74069
- }
74070
- }
74071
- const childRecords = childrenByParentId.get(item.id) ?? [];
74072
- const hasChildren = childRecords.length > 0;
74073
- if (item.urlType === "dropdown" || hasChildren) {
74074
- const children = childRecords.sort((a, b) => (a.orderIndex ?? a.position ?? 0) - (b.orderIndex ?? b.position ?? 0)).map(options.toLink).filter((child) => child !== null);
74075
- if (children.length > 0) result.push(options.createDropdown(item.id, item.label, children));
74076
- continue;
74077
- }
74078
- const link = options.toLink(item);
74079
- if (link) result.push(link);
74080
- }
74081
- return {
74082
- items: result,
74083
- ctaItem
74084
- };
74085
- }
74086
- /**
74087
- * Build a Menu from navigation data with pre-resolved hrefs.
74088
- * Supports dropdown containers with nested children.
74089
- *
74090
- * @param navigation - Navigation menus from site data
74091
- * @param routes - Route map for resolving internal links
74092
- * @param options - Include identifier maps to resolve canonical `page`/`entry` links.
74093
- *
74094
- * @example
74095
- * ```ts
74096
- * const menu = buildMenu(siteData.navigation, siteData.routes, {
74097
- * pagesByIdentifier: siteData.pagesByIdentifier,
74098
- * entriesByIdentifier: siteData.entriesByIdentifier,
74099
- * });
74100
- * menu.items.forEach(item => {
74101
- * if (item.kind === 'dropdown') {
74102
- * console.log(item.children);
74103
- * }
74104
- * });
74105
- * ```
74106
- */
74107
- function buildMenu(navigation, routes, options) {
74108
- const menu = getPrimaryNavigation(navigation);
74109
- if (!menu) return {
74110
- items: [],
74111
- ctaItem: null
74112
- };
74113
- const toNavLink = (item) => {
74114
- const renderable = deriveRenderableNavigationLink(item, options);
74115
- if (!renderable) return null;
74116
- return buildNavLinkFromResolvedHref(renderable, resolveHref(renderable.payload, routes, options));
74117
- };
74118
- const { items, ctaItem } = buildNestedStructure(menu.items, {
74119
- toLink: toNavLink,
74120
- createDropdown: (id, label, children) => ({
74121
- kind: "dropdown",
74122
- id,
74123
- label,
74124
- children
74125
- }),
74126
- extractCta: true
74127
- });
74128
- return {
74129
- items,
74130
- ctaItem: ctaItem ? {
74131
- ...ctaItem,
74132
- variant: "primary"
74133
- } : null
74134
- };
74135
- }
74136
- /**
74137
- * Build a Menu from the footer navigation data.
74138
- * Returns empty menu if no footer menu is designated.
74139
- *
74140
- * @param navigation - Navigation menus from site data
74141
- * @param routes - Route map for resolving internal links
74142
- * @param options - Include identifier maps to resolve canonical `page`/`entry` links.
74143
- *
74144
- * @example
74145
- * ```ts
74146
- * const footerMenu = buildFooterMenu(siteData.navigation, siteData.routes, {
74147
- * pagesByIdentifier: siteData.pagesByIdentifier,
74148
- * entriesByIdentifier: siteData.entriesByIdentifier,
74149
- * });
74150
- * footerMenu.items.forEach(item => {
74151
- * if (item.kind === 'dropdown') {
74152
- * // Footer renders children expanded, not as hover dropdowns
74153
- * console.log(item.children);
74154
- * }
74155
- * });
74156
- * ```
74157
- */
74158
- function buildFooterMenu(navigation, routes, options) {
74159
- return buildFooterMenuForRole(navigation, routes, "main", options);
74160
- }
74161
- function buildFooterMenuForRole(navigation, routes, role, options) {
74162
- const menu = getFooterNavigationByRole(navigation, role);
74163
- if (!menu) return {
74164
- items: [],
74165
- ctaItem: null,
74166
- groups: [],
74167
- links: []
74168
- };
74169
- const toNavLink = (item) => {
74170
- const renderable = deriveRenderableNavigationLink(item, options);
74171
- if (!renderable) return null;
74172
- return buildNavLinkFromResolvedHref(renderable, resolveHref(renderable.payload, routes, options));
74173
- };
74174
- const built = buildNestedStructure(menu.items, {
74175
- toLink: toNavLink,
74176
- createDropdown: (id, label, children) => ({
74177
- kind: "dropdown",
74178
- id,
74179
- label,
74180
- children
74181
- }),
74182
- extractCta: false
74183
- });
74184
- const groups = built.items.filter((item) => item.kind === "dropdown");
74185
- const links = built.items.filter((item) => item.kind === "link");
74186
- return {
74187
- items: built.items,
74188
- ctaItem: null,
74189
- groups,
74190
- links
74191
- };
74192
- }
74193
- /**
74194
- * Resolve href from a link payload using route map.
74195
- * @internal
74196
- */
74197
- function resolveHref(link, routes, options) {
74198
- if (!link) return null;
74199
- if (link.kind === "external" || link.kind === "url") return link.href || null;
74200
- if (link.kind === "portal") return isPortalEnabled(options) ? resolvePortalHref(link) : null;
74201
- if (link.kind === "cart") return isCommerceEnabled(options) ? resolveCheckoutHref(options) : null;
74202
- const stage = normalizeRenderStage(options?.previewStage);
74203
- if (link.kind === "internal") return resolveRouteHrefWithFallback(link.routeId, link.href ?? null, routes, stage);
74204
- if (link.kind === "page") {
74205
- const routeIdFromPayload = readRouteIdFromLink(link);
74206
- const routeIdFromIdentifierMap = options?.pagesByIdentifier?.[link.identifier] ?? null;
74207
- return resolveRouteHrefWithFallback(routeIdFromPayload ?? routeIdFromIdentifierMap, readHrefFromLink(link), routes, stage);
74208
- }
74209
- if (link.kind === "entry") {
74210
- const routeIdFromPayload = readRouteIdFromLink(link);
74211
- const routeIdFromIdentifierMap = readEntryRouteIdFromIdentifierMap(options, link.contentType, link.identifier);
74212
- return resolveRouteHrefWithFallback(routeIdFromPayload ?? routeIdFromIdentifierMap, readHrefFromLink(link), routes, stage);
74213
- }
74214
- return null;
74215
- }
74216
- function resolveRouteHrefWithFallback(routeId, fallbackHref, routes, stage) {
74217
- if (!routeId) return fallbackHref;
74218
- const resolved = resolveRouteHrefForStage(routeId, routes, stage);
74219
- if (resolved) return resolved;
74220
- const route = routes[routeId];
74221
- if (!route) return fallbackHref;
74222
- if (!isRouteVisibleInStage(route, stage)) return null;
74223
- return fallbackHref;
74224
- }
74225
- function readRouteIdFromLink(link) {
74226
- if (!("routeId" in link) || typeof link.routeId !== "string") return null;
74227
- return link.routeId;
74228
- }
74229
- function readHrefFromLink(link) {
74230
- if (!("href" in link) || typeof link.href !== "string") return null;
74231
- return link.href;
74232
- }
74233
- function readEntryRouteIdFromIdentifierMap(options, contentType, identifier) {
74234
- const entryMap = options?.entriesByIdentifier?.[contentType];
74235
- if (!entryMap) return null;
74236
- return entryMap[identifier] ?? null;
74237
- }
74238
- /**
74239
- * Build a Logo from site layout data.
74240
- *
74241
- * @param logo - Logo data from site layout
74242
- * @param fallbackAlt - Fallback alt text (usually site title)
74243
- *
74244
- * @example
74245
- * ```ts
74246
- * const logo = buildLogo(siteData.layout.logo, siteData.site.title);
74247
- * // { src: 'https://...', alt: 'Site Name', width: 200, height: 50 }
74248
- * ```
74249
- */
74250
- function buildLogo(logo, fallbackAlt) {
74251
- if (!logo || !logo.url) return null;
74252
- const alt = resolveAltText(logo.alt, fallbackAlt);
74253
- const result = {
74254
- type: "image",
74255
- src: logo.url,
74256
- alt
74257
- };
74258
- if (logo.width != null) result.width = logo.width;
74259
- if (logo.height != null) result.height = logo.height;
74260
- return result;
74261
- }
74262
- /**
74263
- * Build both site logos from layout data. The default header and footer choose
74264
- * between them by the surface they sit on; custom chrome can do the same.
74265
- *
74266
- * @example
74267
- * ```ts
74268
- * const logoVariants = buildLogoVariants(siteData.layout, siteData.site.title);
74269
- * ```
74270
- */
74271
- function buildLogoVariants(layout, fallbackAlt) {
74272
- return {
74273
- forLightBackgrounds: buildLogo(layout?.logo ?? null, fallbackAlt),
74274
- forDarkBackgrounds: buildLogo(layout?.logoForDarkBackgrounds ?? null, fallbackAlt)
74275
- };
74276
- }
74277
- /**
74278
- * Header/footer block content for the site logos. `logo` stays populated with
74279
- * whichever logo exists so presence checks keep working; `logoVariants` is
74280
- * what the blocks select from at render.
74281
- */
74282
- function buildChromeLogoContent(layout, fallbackAlt) {
74283
- const logoVariants = buildLogoVariants(layout, fallbackAlt);
74284
- return {
74285
- logo: logoVariants.forLightBackgrounds ?? logoVariants.forDarkBackgrounds,
74286
- logoVariants
74287
- };
74288
- }
74289
- //#endregion
74290
- //#region src/rendering/themeAdmission.ts
74291
- const MISSING_SDK_THEME_ERROR_CODE = "missing_sdk_theme";
74292
- var MissingSdkThemeError = class extends Error {
74293
- constructor(siteId, reason = "cms_theme_absent", themeKey) {
74294
- 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.");
74295
- this.siteId = siteId;
74296
- this.reason = reason;
74297
- this.themeKey = themeKey;
74298
- this.code = MISSING_SDK_THEME_ERROR_CODE;
74299
- this.name = "MissingSdkThemeError";
74300
- }
74301
- };
74302
- function requireSdkTheme(theme, siteId, reason = "cms_theme_absent") {
74303
- if (theme === null || theme === void 0) throw new MissingSdkThemeError(siteId, reason);
74304
- return theme;
74305
- }
74306
- //#endregion
74307
- //#region src/rendering/renderingMode.ts
74308
- const defaultOverrideOnlyRuntime = { kind: "responsive-only" };
74309
- //#endregion
74310
- //#region ../blocks/src/system/runtime/bindings.ts
74311
- const shouldLogWarnings = isNonProductionEnv();
74312
- function isPlainObject(value) {
74313
- return typeof value === "object" && value !== null && !Array.isArray(value);
74314
- }
74315
- function isRouteMapEntry(value) {
74316
- if (typeof value === "string") return true;
74317
- return isPlainObject(value);
74318
- }
74319
- function isRouteMap(value) {
74320
- if (!isPlainObject(value)) return false;
74321
- return Object.values(value).every(isRouteMapEntry);
74322
- }
74323
- function isPageIdentifierMap(value) {
74324
- if (!isPlainObject(value)) return false;
74325
- return Object.values(value).every((v) => typeof v === "string");
74326
- }
74327
- function isEntryIdentifierMap(value) {
74328
- if (!isPlainObject(value)) return false;
74329
- for (const v of Object.values(value)) {
74330
- if (!isPlainObject(v)) return false;
74331
- if (!Object.values(v).every((inner) => typeof inner === "string")) return false;
74332
- }
74333
- return true;
74334
- }
74335
- function buildTransformContext(vm) {
74336
- const root = vm.$root;
74337
- const stage = root && isPlainObject(root) && root.previewStage === "preview" ? "preview" : "published";
74338
- const routes = root && isPlainObject(root) && isRouteMap(root.routes) ? root.routes : void 0;
74339
- const pagesByIdentifier = root && isPlainObject(root) && isPageIdentifierMap(root.pagesByIdentifier) ? root.pagesByIdentifier : void 0;
74340
- const entriesByIdentifier = root && isPlainObject(root) && isEntryIdentifierMap(root.entriesByIdentifier) ? root.entriesByIdentifier : void 0;
74341
- return {
74342
- theme: defaultThemeTokens,
74343
- stage,
74344
- data: vm.content,
74345
- routes,
74346
- pagesByIdentifier,
74347
- entriesByIdentifier
74348
- };
74349
- }
74350
- function resolveParamsBindings(input, vm, meta) {
74351
- if (input === null || typeof input !== "object") return input;
74352
- if (Array.isArray(input)) return input.map((v) => resolveParamsBindings(v, vm, meta));
74353
- const maybeBind = input.$bind;
74354
- if (maybeBind && typeof maybeBind === "object") try {
74355
- const binding = bindingSchema.parse(maybeBind);
74356
- const value = resolveBinding(binding.from, vm);
74357
- const resolved = value === void 0 || value === null ? binding.fallback : runTransforms(value, binding.transforms, buildTransformContext(vm), defaultTransforms);
74358
- if (resolved === void 0 || resolved === null || resolved === "") return binding.fallback;
74359
- return resolved;
74360
- } catch (err) {
74361
- if (shouldLogWarnings) console.warn(`bindings: failed to parse loader param binding for block "${meta?.blockKind ?? "unknown"}"`, err);
74362
- return;
74363
- }
74364
- const out = {};
74365
- for (const [k, v] of Object.entries(input)) out[k] = resolveParamsBindings(v, vm, meta);
74366
- return out;
74367
- }
74368
- function resolveBinding(path, vm) {
74369
- const segments = splitPath(path);
74370
- if (!segments.length) return void 0;
74371
- const [first, ...rest] = segments;
74372
- let source = vm;
74373
- if (first === "$root") {
74374
- source = vm;
74375
- return readFromSource(source, [first, ...rest]);
74376
- }
74377
- if (first === "content") {
74378
- source = vm.content;
74379
- return readFromSource(source, rest);
74380
- }
74381
- const contentResult = readFromSource(vm.content, segments);
74382
- if (contentResult !== void 0) return contentResult;
74383
- return readFromSource(vm, segments);
74384
- }
74385
- function splitPath(path) {
74386
- const PATH_SEPARATOR_REGEX = /\./g;
74387
- const BRACKET_ACCESS_REGEX = /\[(?<token>[^\]]+)\]/g;
74388
- const segments = [];
74389
- const parts = path.split(PATH_SEPARATOR_REGEX);
74390
- for (const raw of parts) {
74391
- if (!raw) continue;
74392
- const baseMatch = raw.match(/^([^\[]+)/);
74393
- if (baseMatch && baseMatch[1]) segments.push(baseMatch[1]);
74394
- const bracketMatches = raw.matchAll(BRACKET_ACCESS_REGEX);
74395
- for (const match of bracketMatches) {
74396
- const token = match.groups?.token ?? "";
74397
- if (token.startsWith("\"") || token.startsWith("'")) segments.push(token.slice(1, -1));
74398
- else if (/^\d+$/.test(token)) segments.push(Number(token));
74399
- else segments.push(token);
74400
- }
74401
- if (!baseMatch && !raw.includes("[")) segments.push(raw);
74402
- }
74403
- return segments;
74404
- }
74405
- function readFromSource(source, segments) {
74406
- return segments.reduce((current, segment) => {
74407
- if (current === void 0 || current === null) return void 0;
74408
- if (typeof segment === "number") {
74409
- if (Array.isArray(current)) return current[segment];
74410
- return;
74411
- }
74412
- if (typeof current === "object" && current !== null && segment in current) return current[segment];
74413
- }, source);
74414
- }
74415
- function isNonProductionEnv() {
74416
- if (typeof globalThis === "undefined") return true;
74417
- return globalThis.process?.env?.NODE_ENV !== "production";
74418
- }
74419
- //#endregion
74420
- //#region ../blocks/src/system/data/utils.ts
74421
- /**
74422
- * Normalize data loaders from block definition
74423
- */
74424
- function normalizeDataLoaders(def) {
74425
- if (!def?.dataLoaders) return [];
74426
- return Object.entries(def.dataLoaders).map(([key, loader]) => ({
74427
- key,
74428
- loader
74429
- }));
74430
- }
74431
- /**
74432
- * Normalize block content for data loading.
74433
- * Priority: draftContent > content > publishedContent
74434
- */
74435
- function normalizeContent(block) {
74436
- const source = block.draftContent ?? block.content ?? block.publishedContent ?? {};
74437
- if (!isObjectRecord$1(source)) return {};
74438
- if ("data" in source) {
74439
- const data = source.data;
74440
- if (isObjectRecord$1(data)) return data;
74441
- if (data === null || data === void 0) return {};
74442
- }
74443
- return source;
74444
- }
74445
- /**
74446
- * Normalize params for API calls.
74447
- * Converts supplied values to strings, preserving absent versus explicitly empty params.
74448
- */
74449
- function normalizeParams(input) {
74450
- if (!input || typeof input !== "object") return {};
74451
- const output = {};
74452
- for (const [key, value] of Object.entries(input)) if (value !== void 0 && value !== null) output[key] = coerceToString(value);
74453
- return output;
74454
- }
74455
- function isNonArrayObject(value) {
74456
- return typeof value === "object" && value !== null && !Array.isArray(value);
74457
- }
74458
- function safeJsonStringify(value) {
74459
- try {
74460
- return JSON.stringify(value);
74461
- } catch {
74462
- return;
74463
- }
74464
- }
74465
- /**
74466
- * Coerce value to string for API params
74467
- */
74468
- function coerceToString(value) {
74469
- if (value === null || value === void 0) return "";
74470
- if (Array.isArray(value)) {
74471
- if (value.some(isNonArrayObject)) {
74472
- const json = safeJsonStringify(value);
74473
- if (typeof json === "string") return json;
74474
- }
74475
- return value.map(coerceToString).join(",");
74476
- }
74477
- if (isNonArrayObject(value)) {
74478
- const json = safeJsonStringify(value);
74479
- if (typeof json === "string") return json;
74480
- }
74481
- if (typeof value === "string" || typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") return String(value);
74482
- return "";
74483
- }
74484
- /**
74485
- * The appointment-services catalogue (issue 1403) pairs the services with the
74486
- * site's ordered categories. Both are needed to group them, so that response
74487
- * is passed through whole; any other `{ services }` wrapper is unwrapped.
74488
- */
74489
- function coerceServicesPayload(record) {
74490
- return Array.isArray(record.services) && Array.isArray(record.categories) ? {
74491
- services: record.services,
74492
- categories: record.categories
74493
- } : record.services;
74494
- }
74495
- /**
74496
- * Extract data from API response.
74497
- * Unwraps common response wrappers: { data }, { form }, { entries }, { services }, { teamMembers }
74498
- *
74499
- * Note: We check that properties are NOT functions to avoid returning
74500
- * built-in methods like Array.prototype.entries
74501
- */
74502
- function coercePayload(payload) {
74503
- const linkedContentEntries = coerceLinkedContentEntriesPayload(payload);
74504
- if (linkedContentEntries !== payload) return linkedContentEntries;
74505
- if (payload && typeof payload === "object" && !Array.isArray(payload)) {
74506
- const record = payload;
74507
- if ("data" in record && typeof record.data !== "function") return record.data;
74508
- if ("form" in record && typeof record.form !== "function") return record.form;
74509
- if ("entries" in record && typeof record.entries !== "function") return record.entries;
74510
- if ("services" in record && typeof record.services !== "function") return coerceServicesPayload(record);
74511
- if ("teamMembers" in record && typeof record.teamMembers !== "function") return record.teamMembers;
74512
- }
74513
- return payload;
74514
- }
74515
- //#endregion
74516
- //#region ../blocks/src/system/data/prefetchBlockData.ts
73977
+ //#endregion
73978
+ //#region ../blocks/src/system/data/prefetchBlockData.ts
74517
73979
  /**
74518
73980
  * Core block data prefetching logic (framework-agnostic).
74519
73981
  *
@@ -74729,123 +74191,845 @@ function resolveSiteCustomBlocks(site) {
74729
74191
  const sdkBlocks = site.sdkConfig?.customBlocks;
74730
74192
  if (Array.isArray(sdkBlocks) && sdkBlocks.length > 0) return sdkBlocks;
74731
74193
  }
74732
- //#endregion
74733
- //#region src/rendering/helpers/pageRuntimeSupport.ts
74734
- function readBlockContentId(value, name) {
74735
- if (value === null || value === void 0) return null;
74736
- if (typeof value === "string") return value;
74737
- throw new Error(`Invalid ${name} in page: expected string or null`);
74194
+ //#endregion
74195
+ //#region src/rendering/helpers/pageRuntimeSupport.ts
74196
+ function readBlockContentId(value, name) {
74197
+ if (value === null || value === void 0) return null;
74198
+ if (typeof value === "string") return value;
74199
+ throw new Error(`Invalid ${name} in page: expected string or null`);
74200
+ }
74201
+ function readTransportedBlockIdentity(block, kind, stage) {
74202
+ return {
74203
+ draftContentId: readBlockContentId(block.draftContentId, "draft content id"),
74204
+ publishedPlacement: stage === "preview" ? readSdkPreviewPublishedPlacement(block, kind) : null
74205
+ };
74206
+ }
74207
+ /** Pair SDK preview publication data whether it is transported or already admitted. */
74208
+ function readSdkPreviewPublishedPlacement(block, kind) {
74209
+ if (block.publishedPlacement !== void 0 && block.publishedPlacement !== null) {
74210
+ if (!isRecord$3(block.publishedPlacement)) throw new Error("Invalid published placement in page");
74211
+ return readPublishedBlockPlacement(readBlockContentId(block.publishedPlacement.id, "published content id"), sanitizeNullableSdkRuntimeBlockContent(kind, readContentRecord(block.publishedPlacement.content) ?? null));
74212
+ }
74213
+ return readPublishedBlockPlacement(readBlockContentId(block.publishedContentId, "published content id"), sanitizeNullableSdkRuntimeBlockContent(kind, readSdkPublishedContentRecord(block.publishedContent)));
74214
+ }
74215
+ function convertPageResponseBlock(block, stage) {
74216
+ if (!isRecord$3(block)) throw new Error("Invalid block format in page API response");
74217
+ const header = readTransportedBlockHeader(block);
74218
+ const admission = readInvalidBlockAdmission(block.admission);
74219
+ return {
74220
+ ...header,
74221
+ ...readTransportedBlockIdentity(block, header.kind, stage),
74222
+ content: sanitizeSdkRuntimeBlockContent(header.kind, readContentRecord(block.content) ?? {}),
74223
+ draftContent: sanitizeNullableSdkRuntimeBlockContent(header.kind, readNestedContentRecord(block.draftContent)),
74224
+ ...admission ? { admission } : {}
74225
+ };
74226
+ }
74227
+ function readTransportedBlockHeader(block) {
74228
+ if (typeof block.id !== "string" && block.id !== null) throw new Error(`Invalid block id in page: expected string or null, got ${typeof block.id}`);
74229
+ if (typeof block.kind !== "string") throw new Error(`Invalid block kind in page: expected string, got ${typeof block.kind}`);
74230
+ if (typeof block.purpose !== "string") throw new Error(`Invalid block purpose in page: expected string, got ${typeof block.purpose}`);
74231
+ 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}`);
74232
+ return {
74233
+ id: block.id,
74234
+ ...block.contentVersionId !== void 0 ? { contentVersionId: block.contentVersionId } : {},
74235
+ kind: block.kind,
74236
+ purpose: block.purpose
74237
+ };
74238
+ }
74239
+ function readInvalidBlockAdmission(value) {
74240
+ if (!isRecord$3(value) || value.kind !== "invalid" || !isRecord$3(value.error)) return null;
74241
+ if (value.error.kind !== "invalid_manifest_content" && value.error.kind !== "manifest_unavailable") return null;
74242
+ return value;
74243
+ }
74244
+ function buildPageOutline(input) {
74245
+ return {
74246
+ name: input.name,
74247
+ path: input.path ?? input.fallbackPath,
74248
+ purpose: input.purpose,
74249
+ blocks: input.blocks.map((block) => convertPageResponseBlock(block, input.previewStage))
74250
+ };
74251
+ }
74252
+ function buildRenderablePageOutline(input) {
74253
+ const page = buildPageOutline(input);
74254
+ return {
74255
+ ...page,
74256
+ blocks: page.blocks.map((block) => admitSdkRuntimePageBlock(block, input.customBlocks))
74257
+ };
74258
+ }
74259
+ function admitSdkRuntimePageBlock(block, customBlocks) {
74260
+ const base = {
74261
+ id: block.id,
74262
+ draftContentId: block.draftContentId,
74263
+ publishedPlacement: block.publishedPlacement,
74264
+ ...block.contentVersionId !== void 0 ? { contentVersionId: block.contentVersionId } : {},
74265
+ kind: block.kind,
74266
+ purpose: block.purpose,
74267
+ ...block.bindings ? { bindings: block.bindings } : {}
74268
+ };
74269
+ const transportedAdmission = readInvalidBlockAdmission(block.admission);
74270
+ if (transportedAdmission) return invalidRenderableBlock(base, transportedAdmission.error);
74271
+ const manifest = resolveSdkBlockManifest(block.kind, customBlocks);
74272
+ if (!manifest) return invalidRenderableBlock(base, { kind: "manifest_unavailable" });
74273
+ const content = block.content ?? {};
74274
+ const renderable = admitTransportedRenderableManifestContent(compileManifestContentContract(manifest), content);
74275
+ if (!renderable.ok) return invalidRenderableBlock(base, {
74276
+ kind: "invalid_manifest_content",
74277
+ error: renderable.error
74278
+ });
74279
+ return {
74280
+ ...base,
74281
+ admission: {
74282
+ kind: "renderable",
74283
+ content: renderable.value
74284
+ }
74285
+ };
74286
+ }
74287
+ function resolveSdkBlockManifest(blockKind, customBlocks) {
74288
+ const customBlock = customBlocks?.find((candidate) => candidate.id === blockKind);
74289
+ return customBlock ? parseFieldDefinitions(customBlock.fields) : getBlockDefinition(blockKind)?.manifest ?? null;
74290
+ }
74291
+ function invalidRenderableBlock(block, error) {
74292
+ return {
74293
+ ...block,
74294
+ admission: {
74295
+ kind: "invalid",
74296
+ error
74297
+ }
74298
+ };
74299
+ }
74300
+ function isRecord$3(value) {
74301
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
74302
+ }
74303
+ function readContentRecord(value) {
74304
+ return isRecord$3(value) ? value : void 0;
74305
+ }
74306
+ function readNestedContentRecord(value) {
74307
+ if (!isRecord$3(value)) return null;
74308
+ return readContentRecord(value.data) ?? null;
74309
+ }
74310
+ function readSdkPublishedContentRecord(value) {
74311
+ if (!isRecord$3(value)) return null;
74312
+ return "data" in value ? readContentRecord(value.data) ?? null : value;
74313
+ }
74314
+ function sanitizeSdkRuntimeBlockContent(blockKind, content) {
74315
+ if (blockKind !== "block.newsletter-signup") return content;
74316
+ const sanitized = sanitizeNewsletterSignupPublicContent(content);
74317
+ return isRecord$3(sanitized) ? sanitized : {};
74318
+ }
74319
+ function sanitizeNullableSdkRuntimeBlockContent(blockKind, content) {
74320
+ return content ? sanitizeSdkRuntimeBlockContent(blockKind, content) : null;
74321
+ }
74322
+ //#endregion
74323
+ //#region src/rendering/blocks-page-renderer.ts
74324
+ const MissingBlockOverrideError = MissingBlockOverrideError$1;
74325
+ function isOverrideOnlyPageRenderer(props) {
74326
+ return props.rendering?.kind === "overrides-only";
74327
+ }
74328
+ function normalizeSdkCustomBlocks(customBlocks) {
74329
+ if (!customBlocks) return void 0;
74330
+ return customBlocks.map((block) => {
74331
+ return {
74332
+ ...block,
74333
+ fields: parseFieldDefinitions(block.fields)
74334
+ };
74335
+ });
74336
+ }
74337
+ function toBlocksBlockOverrides(overrides) {
74338
+ if (!overrides) return void 0;
74339
+ const result = {};
74340
+ for (const [key, OverrideComponent] of Object.entries(overrides)) result[key] = function BlocksOverrideAdapter(props) {
74341
+ const sdkOverride = OverrideComponent;
74342
+ return React$1.createElement(sdkOverride, {
74343
+ ...props,
74344
+ entrySubrouteContext: props.entrySubrouteContext
74345
+ });
74346
+ };
74347
+ return result;
74348
+ }
74349
+ function toBlocksPageRendererDataContext(dataContext) {
74350
+ return {
74351
+ ...dataContext,
74352
+ mediaAssets: toBlocksMediaAssets(dataContext.mediaAssets),
74353
+ imageResolveContext: toBlocksImageResolveContextInput(dataContext.imageResolveContext)
74354
+ };
74355
+ }
74356
+ function toBlocksCommonProps(props) {
74357
+ return {
74358
+ page: props.page,
74359
+ runtimeJoins: props.runtimeJoins,
74360
+ dataContext: toBlocksPageRendererDataContext(props.dataContext),
74361
+ routeMap: props.routeMap,
74362
+ wrapBlock: props.wrapBlock,
74363
+ registry: props.registry,
74364
+ blockOverrides: toBlocksBlockOverrides(props.blockOverrides),
74365
+ sdkConfig: props.sdkConfig ? { customBlocks: normalizeSdkCustomBlocks(props.sdkConfig.customBlocks) } : props.sdkConfig,
74366
+ customBlocks: normalizeSdkCustomBlocks(props.customBlocks)
74367
+ };
74368
+ }
74369
+ function PageRenderer(props) {
74370
+ const commonBlocksProps = toBlocksCommonProps(props);
74371
+ const blocksProps = isOverrideOnlyPageRenderer(props) ? {
74372
+ ...commonBlocksProps,
74373
+ rendering: { kind: "overrides-only" },
74374
+ blockOverrides: toBlocksBlockOverrides(props.blockOverrides) ?? {}
74375
+ } : {
74376
+ ...commonBlocksProps,
74377
+ theme: parseBlocksTheme(props.theme),
74378
+ themeTokens: props.themeTokens
74379
+ };
74380
+ return React$1.createElement(PageRenderer$1, blocksProps);
74381
+ }
74382
+ //#endregion
74383
+ //#region src/rendering/blocks-theme-scope.ts
74384
+ function ThemeScope(props) {
74385
+ const { theme, children, ...rest } = props;
74386
+ const blocksTheme = parseBlocksTheme(theme);
74387
+ return React$1.createElement(ThemeScope$1, {
74388
+ ...rest,
74389
+ theme: blocksTheme,
74390
+ children: children ?? null
74391
+ });
74392
+ }
74393
+ //#endregion
74394
+ //#region src/rendering/themeRuntime.tsx
74395
+ const defaultLayoutThemeRuntime = { kind: "cms-theme" };
74396
+ const defaultSdkChromeThemeRuntime = { kind: "responsive-only" };
74397
+ const defaultPageThemeRuntime = { kind: "none" };
74398
+ function planLayoutThemeRuntime(input) {
74399
+ const requested = input.themeRuntime ?? defaultLayoutThemeRuntime;
74400
+ if (requested.kind === "none" && input.usesSdkChrome) {
74401
+ 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.");
74402
+ return defaultSdkChromeThemeRuntime;
74403
+ }
74404
+ return requested;
74405
+ }
74406
+ function renderWithSdkThemeRuntime({ themeRuntime, theme, children }) {
74407
+ switch (themeRuntime.kind) {
74408
+ case "cms-theme": return /* @__PURE__ */ jsx(ThemeScope, {
74409
+ theme,
74410
+ responsiveMode: themeRuntime.responsiveMode,
74411
+ children
74412
+ });
74413
+ case "responsive-only": return /* @__PURE__ */ jsx(ResponsiveScope, {
74414
+ responsiveMode: themeRuntime.responsiveMode,
74415
+ children
74416
+ });
74417
+ case "none": return /* @__PURE__ */ jsx(Fragment, { children });
74418
+ default: return assertNever$4(themeRuntime);
74419
+ }
74420
+ }
74421
+ function renderWithOverrideOnlyRuntime({ runtime, children }) {
74422
+ switch (runtime.kind) {
74423
+ case "responsive-only": return /* @__PURE__ */ jsx(ResponsiveScope, {
74424
+ responsiveMode: runtime.responsiveMode,
74425
+ children
74426
+ });
74427
+ case "none": return /* @__PURE__ */ jsx(Fragment, { children });
74428
+ default: return assertNever$4(runtime);
74429
+ }
74430
+ }
74431
+ //#endregion
74432
+ //#region src/rendering/components/pageShared.tsx
74433
+ function isOverrideOnlyPage(props) {
74434
+ return props.rendering?.kind === "overrides-only";
74435
+ }
74436
+ function resolvePageThemeTokens(props) {
74437
+ const baseTokens = props.themeTokens ?? buildThemeRuntime(props.theme).tokens;
74438
+ return props.sdkConfig?.theme?.palette ? {
74439
+ ...baseTokens,
74440
+ palette: {
74441
+ ...baseTokens.palette,
74442
+ ...props.sdkConfig.theme.palette
74443
+ }
74444
+ } : baseTokens;
74445
+ }
74446
+ function resolveSdkBookingTimeZone(timeZone) {
74447
+ return timeZone ?? "UTC";
74448
+ }
74449
+ function buildPageRouteRenderContext(dataContext) {
74450
+ return {
74451
+ ...buildPageIdentityRenderContext(dataContext),
74452
+ occurrenceContext: dataContext.occurrenceContext ?? null,
74453
+ entrySubrouteContext: dataContext.entrySubrouteContext ?? null,
74454
+ contentEntry: dataContext.contentEntry ?? null,
74455
+ pageSurface: dataContext.pageSurface ?? null,
74456
+ subject: dataContext.subject ?? null,
74457
+ editableRouteMetadataFieldIds: dataContext.editableRouteMetadataFieldIds ?? null,
74458
+ previewStage: dataContext.previewStage
74459
+ };
74460
+ }
74461
+ function buildPageIdentityRenderContext(dataContext) {
74462
+ return {
74463
+ demoEmailSuppressed: dataContext.demoEmailSuppressed,
74464
+ siteName: dataContext.siteName,
74465
+ pathname: dataContext.pathname
74466
+ };
74467
+ }
74468
+ function PageContent(props) {
74469
+ const { page, runtimeJoins, siteId, resolvedData, bookingOfferingPresets, mailingList, bookingTimeZone, routeMap, pagesByIdentifier, entriesByIdentifier, wrapBlock, registry, blockOverrides, sdkConfig, customBlocks, supabaseUrl, mediaAssets, apiBaseUrl, portalToken, previewToken, readAuthority, dataContext } = props;
74470
+ const rendererCommonProps = {
74471
+ page,
74472
+ runtimeJoins,
74473
+ dataContext: {
74474
+ siteId,
74475
+ ...buildPageRouteRenderContext(dataContext),
74476
+ apiBaseUrl,
74477
+ portalToken,
74478
+ previewToken,
74479
+ readAuthority: readAuthority ?? dataContext.readAuthority,
74480
+ resolvedData,
74481
+ bookingOfferingPresets: bookingOfferingPresets ?? [],
74482
+ mailingList: mailingList ?? dataContext.mailingList,
74483
+ bookingTimeZone: resolveSdkBookingTimeZone(bookingTimeZone),
74484
+ routes: routeMap,
74485
+ pagesByIdentifier,
74486
+ entriesByIdentifier,
74487
+ supabaseUrl,
74488
+ mediaAssets,
74489
+ imageResolveContext: {
74490
+ siteId,
74491
+ supabaseUrl,
74492
+ mediaAssets
74493
+ }
74494
+ },
74495
+ routeMap,
74496
+ wrapBlock,
74497
+ registry,
74498
+ sdkConfig: sdkConfig ? { customBlocks: sdkConfig.customBlocks } : null,
74499
+ customBlocks
74500
+ };
74501
+ const content = isOverrideOnlyPage(props) ? /* @__PURE__ */ jsx(PageRenderer, {
74502
+ ...rendererCommonProps,
74503
+ rendering: { kind: "overrides-only" },
74504
+ blockOverrides: props.blockOverrides
74505
+ }) : /* @__PURE__ */ jsx(PageRenderer, {
74506
+ ...rendererCommonProps,
74507
+ theme: props.theme,
74508
+ themeTokens: resolvePageThemeTokens(props),
74509
+ blockOverrides
74510
+ });
74511
+ return isOverrideOnlyPage(props) ? renderWithOverrideOnlyRuntime({
74512
+ runtime: props.rendering.runtime,
74513
+ children: content
74514
+ }) : renderWithSdkThemeRuntime({
74515
+ themeRuntime: props.themeRuntime ?? defaultPageThemeRuntime,
74516
+ theme: props.theme,
74517
+ children: content
74518
+ });
74519
+ }
74520
+ //#endregion
74521
+ //#region src/rendering/components/Page.server.tsx
74522
+ function Page(props) {
74523
+ return /* @__PURE__ */ jsx(PageContent, { ...props });
74524
+ }
74525
+ //#endregion
74526
+ //#region src/env.ts
74527
+ /**
74528
+ * Error thrown when required environment variables are missing
74529
+ */
74530
+ var RiverbankEnvError = class extends Error {
74531
+ constructor(message, missingVars) {
74532
+ super(message);
74533
+ this.missingVars = missingVars;
74534
+ this.name = "RiverbankEnvError";
74535
+ }
74536
+ };
74537
+ /**
74538
+ * Get the environment variable prefix based on target
74539
+ */
74540
+ function getEnvPrefix(target) {
74541
+ return target === "remote" ? "RIVERBANK_REMOTE" : "RIVERBANK_LOCAL";
74542
+ }
74543
+ /**
74544
+ * Detect the environment target from RIVERBANK_ENV
74545
+ */
74546
+ function detectTarget() {
74547
+ const env = process.env.RIVERBANK_ENV?.toLowerCase();
74548
+ if (env === "remote" || env === "production" || env === "prod") return "remote";
74549
+ return "local";
74550
+ }
74551
+ /**
74552
+ * Detect if preview mode is enabled.
74553
+ * Uses RIVERBANK_PREVIEW_MODE first, then falls back to RIVERBANK_PREVIEW for backward compat.
74554
+ */
74555
+ function detectPreviewMode() {
74556
+ const previewMode = process.env.RIVERBANK_PREVIEW_MODE;
74557
+ if (previewMode !== void 0 && previewMode !== "") return previewMode === "true";
74558
+ const previewLegacy = process.env.RIVERBANK_PREVIEW;
74559
+ if (previewLegacy !== void 0 && previewLegacy !== "") return previewLegacy === "true";
74560
+ return process.env.VERCEL_ENV === "preview";
74561
+ }
74562
+ /**
74563
+ * Validate that an API key matches the expected format for its type
74564
+ */
74565
+ function validateKeyType(key, expectedType) {
74566
+ const isPreviewKey = key.startsWith("bld_preview_sk_");
74567
+ const isContentKey = key.startsWith("bld_live_sk_");
74568
+ if (expectedType === "preview" && !isPreviewKey) {
74569
+ 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.", []);
74570
+ throw new RiverbankEnvError(`Invalid API key format for preview mode. Expected key starting with bld_preview_sk_`, []);
74571
+ }
74572
+ if (expectedType === "content" && !isContentKey) {
74573
+ if (isPreviewKey) {
74574
+ console.debug("[getRiverbankEnv] Using preview key for published content. Consider using a content key (bld_live_sk_...) for production.");
74575
+ return;
74576
+ }
74577
+ throw new RiverbankEnvError(`Invalid API key format for content access. Expected key starting with bld_live_sk_ or bld_preview_sk_`, []);
74578
+ }
74579
+ }
74580
+ /**
74581
+ * Get runtime environment configuration with automatic API key selection.
74582
+ *
74583
+ * This helper reads environment variables and automatically selects the correct
74584
+ * API key based on the current environment and preview mode:
74585
+ *
74586
+ * - When `RIVERBANK_PREVIEW_MODE=true`: Uses preview API key (bld_preview_sk_...)
74587
+ * - When `RIVERBANK_PREVIEW_MODE=false` (default): Uses content API key (bld_live_sk_...)
74588
+ *
74589
+ * Environment variable patterns:
74590
+ * - `RIVERBANK_ENV`: 'local' (default) or 'remote'
74591
+ * - `RIVERBANK_PREVIEW_MODE`: 'true' or 'false' (default)
74592
+ * - `RIVERBANK_{LOCAL|REMOTE}_SITE_ID`: Site ID
74593
+ * - `RIVERBANK_{LOCAL|REMOTE}_DASHBOARD_URL`: Dashboard URL
74594
+ * - `RIVERBANK_{LOCAL|REMOTE}_API_KEY`: Content/live API key
74595
+ * - `RIVERBANK_{LOCAL|REMOTE}_PREVIEW_API_KEY`: Preview API key
74596
+ *
74597
+ * @returns Environment configuration with auto-selected API key
74598
+ * @throws {RiverbankEnvError} If required environment variables are missing
74599
+ *
74600
+ * @example
74601
+ * ```ts
74602
+ * // lib/builder-client.ts
74603
+ * import { getRiverbankEnv } from '@riverbankcms/sdk/env';
74604
+ * import { createRiverbankClient } from '@riverbankcms/sdk';
74605
+ *
74606
+ * const env = getRiverbankEnv();
74607
+ *
74608
+ * export const client = createRiverbankClient({
74609
+ * apiKey: env.apiKey,
74610
+ * baseUrl: env.baseUrl,
74611
+ * });
74612
+ *
74613
+ * export const siteId = env.siteId;
74614
+ * ```
74615
+ */
74616
+ function getRiverbankEnv() {
74617
+ const target = detectTarget();
74618
+ const previewMode = detectPreviewMode();
74619
+ const prefix = getEnvPrefix(target);
74620
+ const siteId = process.env[`${prefix}_SITE_ID`];
74621
+ const dashboardUrl = process.env[`${prefix}_DASHBOARD_URL`];
74622
+ const contentKey = process.env[`${prefix}_API_KEY`];
74623
+ const previewKey = process.env[`${prefix}_PREVIEW_API_KEY`];
74624
+ const missingVars = [];
74625
+ if (!siteId) missingVars.push(`${prefix}_SITE_ID`);
74626
+ if (!dashboardUrl) missingVars.push(`${prefix}_DASHBOARD_URL`);
74627
+ let apiKey;
74628
+ let keyType;
74629
+ if (previewMode) {
74630
+ apiKey = previewKey;
74631
+ keyType = "preview";
74632
+ if (!apiKey) missingVars.push(`${prefix}_PREVIEW_API_KEY`);
74633
+ } else {
74634
+ apiKey = contentKey || previewKey;
74635
+ keyType = contentKey ? "content" : "preview";
74636
+ if (!apiKey) missingVars.push(`${prefix}_API_KEY`);
74637
+ }
74638
+ 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);
74639
+ if (!apiKey || !dashboardUrl || !siteId) throw new RiverbankEnvError("Required environment variables missing", missingVars);
74640
+ validateKeyType(apiKey, keyType);
74641
+ let baseUrl = dashboardUrl;
74642
+ if (!baseUrl.endsWith("/api")) baseUrl = baseUrl.replace(/\/$/, "") + "/api";
74643
+ return {
74644
+ target,
74645
+ previewMode,
74646
+ siteId,
74647
+ baseUrl,
74648
+ apiKey,
74649
+ keyType
74650
+ };
74651
+ }
74652
+ //#endregion
74653
+ //#region src/navigation/index.ts
74654
+ /**
74655
+ * Get the fixed main navigation menu object.
74656
+ * Returns null when the runtime payload is incomplete.
74657
+ *
74658
+ * @example
74659
+ * ```ts
74660
+ * const menu = getPrimaryNavigation(siteData.navigation);
74661
+ * console.log(menu?.location); // "main"
74662
+ * ```
74663
+ */
74664
+ function getPrimaryNavigation(navigation) {
74665
+ if (!navigation || navigation.length === 0) return null;
74666
+ return navigation.find((menu) => menu.location === "main") ?? null;
74667
+ }
74668
+ function getFooterNavigationByRole(navigation, role) {
74669
+ if (!navigation || navigation.length === 0) return null;
74670
+ const canonicalLocation = role === "main" ? "footer" : "legal";
74671
+ return navigation.find((menu) => menu.location === canonicalLocation) ?? null;
74672
+ }
74673
+ /**
74674
+ * Resolve alt text with fallback.
74675
+ * Returns the provided alt if non-empty, otherwise falls back to the provided fallback or 'Site logo'.
74676
+ * @internal
74677
+ */
74678
+ function resolveAltText(alt, fallback) {
74679
+ return alt && alt.trim().length > 0 ? alt : fallback ?? "Site logo";
74680
+ }
74681
+ function readNavigationItemPayload(item) {
74682
+ return item.url ?? null;
74683
+ }
74684
+ function isPortalEnabled(options) {
74685
+ return options?.portalEnabled === true;
74686
+ }
74687
+ function isCommerceEnabled(options) {
74688
+ return options?.commerceEnabled === true;
74689
+ }
74690
+ function resolvePortalHref(link) {
74691
+ return link.path?.trim() || "/portal";
74692
+ }
74693
+ function resolveCheckoutHref(options) {
74694
+ if (options?.checkoutHref === null) return null;
74695
+ const href = options?.checkoutHref?.trim();
74696
+ return href && href.length > 0 ? href : "/checkout";
74697
+ }
74698
+ function resolvePortalLabel(link, options) {
74699
+ const loggedOutLabel = link.labels?.loggedOut?.trim() || PORTAL_NAV_DEFAULT_LABELS.loggedOut;
74700
+ const loggedInLabel = link.labels?.loggedIn?.trim() || PORTAL_NAV_DEFAULT_LABELS.loggedIn;
74701
+ return options?.hasPortalSession ? loggedInLabel : loggedOutLabel;
74702
+ }
74703
+ function resolveItemLabel(link, fallbackLabel, options) {
74704
+ if (link?.kind === "portal") return resolvePortalLabel(link, options);
74705
+ if (link?.kind === "cart") return resolveCartVisibleLabel(link) ?? fallbackLabel;
74706
+ return fallbackLabel;
74707
+ }
74708
+ function resolveCartVisibleLabel(link) {
74709
+ if (link.label.kind !== "icon-with-label") return null;
74710
+ const label = link.label.label.trim();
74711
+ return label.length > 0 ? label : null;
74712
+ }
74713
+ function resolveCartAriaLabel(link, fallbackLabel) {
74714
+ const fallback = fallbackLabel.trim();
74715
+ return resolveCartVisibleLabel(link) ?? (fallback.length > 0 ? fallback : "Cart");
74738
74716
  }
74739
- function readTransportedBlockIdentity(block, kind, stage) {
74717
+ function buildCartNavViewModel(link, fallbackLabel, options) {
74740
74718
  return {
74741
- draftContentId: readBlockContentId(block.draftContentId, "draft content id"),
74742
- publishedPlacement: stage === "preview" ? readPublishedBlockPlacement(readBlockContentId(block.publishedContentId, "published content id"), sanitizeNullableSdkRuntimeBlockContent(kind, readNestedContentRecord(block.publishedContent))) : null
74719
+ visibleLabel: resolveCartVisibleLabel(link),
74720
+ badge: link.badge,
74721
+ ariaLabel: resolveCartAriaLabel(link, fallbackLabel),
74722
+ checkoutHref: resolveCheckoutHref(options)
74743
74723
  };
74744
74724
  }
74745
- function convertPageResponseBlock(block, stage) {
74746
- if (!isRecord$3(block)) throw new Error("Invalid block format in page API response");
74747
- const header = readTransportedBlockHeader(block);
74748
- const admission = readInvalidBlockAdmission(block.admission);
74725
+ function deriveRenderableNavigationLink(item, options) {
74726
+ const payload = readNavigationItemPayload(item);
74727
+ if (!payload) return null;
74728
+ if (payload.kind === "portal" && !isPortalEnabled(options)) return null;
74729
+ if (payload.kind === "cart" && !isCommerceEnabled(options)) return null;
74749
74730
  return {
74750
- ...header,
74751
- ...readTransportedBlockIdentity(block, header.kind, stage),
74752
- content: sanitizeSdkRuntimeBlockContent(header.kind, readContentRecord(block.content) ?? {}),
74753
- draftContent: sanitizeNullableSdkRuntimeBlockContent(header.kind, readNestedContentRecord(block.draftContent)),
74754
- ...admission ? { admission } : {}
74731
+ id: item.id,
74732
+ label: resolveItemLabel(payload, item.label, options),
74733
+ payload,
74734
+ isExternal: isExternalLink(payload),
74735
+ ...payload.kind === "cart" ? { cart: buildCartNavViewModel(payload, item.label, options) } : {}
74755
74736
  };
74756
74737
  }
74757
- function readTransportedBlockHeader(block) {
74758
- if (typeof block.id !== "string" && block.id !== null) throw new Error(`Invalid block id in page: expected string or null, got ${typeof block.id}`);
74759
- if (typeof block.kind !== "string") throw new Error(`Invalid block kind in page: expected string, got ${typeof block.kind}`);
74760
- if (typeof block.purpose !== "string") throw new Error(`Invalid block purpose in page: expected string, got ${typeof block.purpose}`);
74761
- 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}`);
74738
+ function buildNavLinkFromResolvedHref(item, href) {
74739
+ if (!href) return null;
74762
74740
  return {
74763
- id: block.id,
74764
- ...block.contentVersionId !== void 0 ? { contentVersionId: block.contentVersionId } : {},
74765
- kind: block.kind,
74766
- purpose: block.purpose
74741
+ kind: "link",
74742
+ id: item.id,
74743
+ label: item.label,
74744
+ href,
74745
+ link: { href },
74746
+ isExternal: item.isExternal,
74747
+ ...item.cart ? { cart: item.cart } : {}
74767
74748
  };
74768
74749
  }
74769
- function readInvalidBlockAdmission(value) {
74770
- if (!isRecord$3(value) || value.kind !== "invalid" || !isRecord$3(value.error)) return null;
74771
- if (value.error.kind !== "invalid_manifest_content" && value.error.kind !== "manifest_unavailable") return null;
74772
- return value;
74750
+ /**
74751
+ * Determines if a navigation item's link is external.
74752
+ */
74753
+ function isExternalLink(link) {
74754
+ if (!link) return false;
74755
+ return link.kind === "external";
74773
74756
  }
74774
- function buildPageOutline(input) {
74775
- return {
74776
- name: input.name,
74777
- path: input.path ?? input.fallbackPath,
74778
- purpose: input.purpose,
74779
- blocks: input.blocks.map((block) => convertPageResponseBlock(block, input.previewStage))
74780
- };
74757
+ /**
74758
+ * Build a map of children items by parent ID.
74759
+ * Also warns about deeply nested items (grandchildren) which CMS shouldn't allow.
74760
+ * @internal
74761
+ */
74762
+ function buildChildrenByParentId(items) {
74763
+ const childrenByParentId = /* @__PURE__ */ new Map();
74764
+ const itemsById = /* @__PURE__ */ new Map();
74765
+ for (const item of items) itemsById.set(item.id, item);
74766
+ for (const item of items) if (item.parentId) {
74767
+ if (itemsById.get(item.parentId)?.parentId && typeof process !== "undefined" && process.env.NODE_ENV !== "production") {
74768
+ 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.`);
74769
+ continue;
74770
+ }
74771
+ const siblings = childrenByParentId.get(item.parentId) ?? [];
74772
+ siblings.push(item);
74773
+ childrenByParentId.set(item.parentId, siblings);
74774
+ }
74775
+ return childrenByParentId;
74781
74776
  }
74782
- function buildRenderablePageOutline(input) {
74783
- const page = buildPageOutline(input);
74777
+ /**
74778
+ * Generic nested structure builder.
74779
+ * @internal
74780
+ */
74781
+ function buildNestedStructure(items, options) {
74782
+ const childrenByParentId = buildChildrenByParentId(items);
74783
+ const rootItems = items.filter((item) => !item.parentId).sort((a, b) => (a.orderIndex ?? a.position ?? 0) - (b.orderIndex ?? b.position ?? 0));
74784
+ const result = [];
74785
+ let ctaItem = null;
74786
+ for (const item of rootItems) {
74787
+ if (options.extractCta && !ctaItem && Boolean(item.isCta) && item.urlType !== "dropdown") {
74788
+ const link = options.toLink(item);
74789
+ if (link) {
74790
+ ctaItem = link;
74791
+ continue;
74792
+ }
74793
+ }
74794
+ const childRecords = childrenByParentId.get(item.id) ?? [];
74795
+ const hasChildren = childRecords.length > 0;
74796
+ if (item.urlType === "dropdown" || hasChildren) {
74797
+ const children = childRecords.sort((a, b) => (a.orderIndex ?? a.position ?? 0) - (b.orderIndex ?? b.position ?? 0)).map(options.toLink).filter((child) => child !== null);
74798
+ if (children.length > 0) result.push(options.createDropdown(item.id, item.label, children));
74799
+ continue;
74800
+ }
74801
+ const link = options.toLink(item);
74802
+ if (link) result.push(link);
74803
+ }
74784
74804
  return {
74785
- ...page,
74786
- blocks: page.blocks.map((block) => admitSdkRuntimePageBlock(block, input.customBlocks))
74805
+ items: result,
74806
+ ctaItem
74787
74807
  };
74788
74808
  }
74789
- function admitSdkRuntimePageBlock(block, customBlocks) {
74790
- const base = {
74791
- id: block.id,
74792
- draftContentId: block.draftContentId,
74793
- publishedPlacement: block.publishedPlacement,
74794
- ...block.contentVersionId !== void 0 ? { contentVersionId: block.contentVersionId } : {},
74795
- kind: block.kind,
74796
- purpose: block.purpose,
74797
- ...block.bindings ? { bindings: block.bindings } : {}
74809
+ /**
74810
+ * Build a Menu from navigation data with pre-resolved hrefs.
74811
+ * Supports dropdown containers with nested children.
74812
+ *
74813
+ * @param navigation - Navigation menus from site data
74814
+ * @param routes - Route map for resolving internal links
74815
+ * @param options - Include identifier maps to resolve canonical `page`/`entry` links.
74816
+ *
74817
+ * @example
74818
+ * ```ts
74819
+ * const menu = buildMenu(siteData.navigation, siteData.routes, {
74820
+ * pagesByIdentifier: siteData.pagesByIdentifier,
74821
+ * entriesByIdentifier: siteData.entriesByIdentifier,
74822
+ * });
74823
+ * menu.items.forEach(item => {
74824
+ * if (item.kind === 'dropdown') {
74825
+ * console.log(item.children);
74826
+ * }
74827
+ * });
74828
+ * ```
74829
+ */
74830
+ function buildMenu(navigation, routes, options) {
74831
+ const menu = getPrimaryNavigation(navigation);
74832
+ if (!menu) return {
74833
+ items: [],
74834
+ ctaItem: null
74798
74835
  };
74799
- const transportedAdmission = readInvalidBlockAdmission(block.admission);
74800
- if (transportedAdmission) return invalidRenderableBlock(base, transportedAdmission.error);
74801
- const manifest = resolveSdkBlockManifest(block.kind, customBlocks);
74802
- if (!manifest) return invalidRenderableBlock(base, { kind: "manifest_unavailable" });
74803
- const content = block.content ?? {};
74804
- const renderable = admitTransportedRenderableManifestContent(compileManifestContentContract(manifest), content);
74805
- if (!renderable.ok) return invalidRenderableBlock(base, {
74806
- kind: "invalid_manifest_content",
74807
- error: renderable.error
74836
+ const toNavLink = (item) => {
74837
+ const renderable = deriveRenderableNavigationLink(item, options);
74838
+ if (!renderable) return null;
74839
+ return buildNavLinkFromResolvedHref(renderable, resolveHref(renderable.payload, routes, options));
74840
+ };
74841
+ const { items, ctaItem } = buildNestedStructure(menu.items, {
74842
+ toLink: toNavLink,
74843
+ createDropdown: (id, label, children) => ({
74844
+ kind: "dropdown",
74845
+ id,
74846
+ label,
74847
+ children
74848
+ }),
74849
+ extractCta: true
74808
74850
  });
74809
74851
  return {
74810
- ...base,
74811
- admission: {
74812
- kind: "renderable",
74813
- content: renderable.value
74814
- }
74852
+ items,
74853
+ ctaItem: ctaItem ? {
74854
+ ...ctaItem,
74855
+ variant: "primary"
74856
+ } : null
74815
74857
  };
74816
74858
  }
74817
- function resolveSdkBlockManifest(blockKind, customBlocks) {
74818
- const customBlock = customBlocks?.find((candidate) => candidate.id === blockKind);
74819
- return customBlock ? parseFieldDefinitions(customBlock.fields) : getBlockDefinition(blockKind)?.manifest ?? null;
74859
+ /**
74860
+ * Build a Menu from the footer navigation data.
74861
+ * Returns empty menu if no footer menu is designated.
74862
+ *
74863
+ * @param navigation - Navigation menus from site data
74864
+ * @param routes - Route map for resolving internal links
74865
+ * @param options - Include identifier maps to resolve canonical `page`/`entry` links.
74866
+ *
74867
+ * @example
74868
+ * ```ts
74869
+ * const footerMenu = buildFooterMenu(siteData.navigation, siteData.routes, {
74870
+ * pagesByIdentifier: siteData.pagesByIdentifier,
74871
+ * entriesByIdentifier: siteData.entriesByIdentifier,
74872
+ * });
74873
+ * footerMenu.items.forEach(item => {
74874
+ * if (item.kind === 'dropdown') {
74875
+ * // Footer renders children expanded, not as hover dropdowns
74876
+ * console.log(item.children);
74877
+ * }
74878
+ * });
74879
+ * ```
74880
+ */
74881
+ function buildFooterMenu(navigation, routes, options) {
74882
+ return buildFooterMenuForRole(navigation, routes, "main", options);
74820
74883
  }
74821
- function invalidRenderableBlock(block, error) {
74884
+ function buildFooterMenuForRole(navigation, routes, role, options) {
74885
+ const menu = getFooterNavigationByRole(navigation, role);
74886
+ if (!menu) return {
74887
+ items: [],
74888
+ ctaItem: null,
74889
+ groups: [],
74890
+ links: []
74891
+ };
74892
+ const toNavLink = (item) => {
74893
+ const renderable = deriveRenderableNavigationLink(item, options);
74894
+ if (!renderable) return null;
74895
+ return buildNavLinkFromResolvedHref(renderable, resolveHref(renderable.payload, routes, options));
74896
+ };
74897
+ const built = buildNestedStructure(menu.items, {
74898
+ toLink: toNavLink,
74899
+ createDropdown: (id, label, children) => ({
74900
+ kind: "dropdown",
74901
+ id,
74902
+ label,
74903
+ children
74904
+ }),
74905
+ extractCta: false
74906
+ });
74907
+ const groups = built.items.filter((item) => item.kind === "dropdown");
74908
+ const links = built.items.filter((item) => item.kind === "link");
74822
74909
  return {
74823
- ...block,
74824
- admission: {
74825
- kind: "invalid",
74826
- error
74827
- }
74910
+ items: built.items,
74911
+ ctaItem: null,
74912
+ groups,
74913
+ links
74828
74914
  };
74829
74915
  }
74830
- function isRecord$3(value) {
74831
- return Boolean(value) && typeof value === "object" && !Array.isArray(value);
74916
+ /**
74917
+ * Resolve href from a link payload using route map.
74918
+ * @internal
74919
+ */
74920
+ function resolveHref(link, routes, options) {
74921
+ if (!link) return null;
74922
+ if (link.kind === "external" || link.kind === "url") return link.href || null;
74923
+ if (link.kind === "portal") return isPortalEnabled(options) ? resolvePortalHref(link) : null;
74924
+ if (link.kind === "cart") return isCommerceEnabled(options) ? resolveCheckoutHref(options) : null;
74925
+ const stage = normalizeRenderStage(options?.previewStage);
74926
+ if (link.kind === "internal") return resolveRouteHrefWithFallback(link.routeId, link.href ?? null, routes, stage);
74927
+ if (link.kind === "page") {
74928
+ const routeIdFromPayload = readRouteIdFromLink(link);
74929
+ const routeIdFromIdentifierMap = options?.pagesByIdentifier?.[link.identifier] ?? null;
74930
+ return resolveRouteHrefWithFallback(routeIdFromPayload ?? routeIdFromIdentifierMap, readHrefFromLink(link), routes, stage);
74931
+ }
74932
+ if (link.kind === "entry") {
74933
+ const routeIdFromPayload = readRouteIdFromLink(link);
74934
+ const routeIdFromIdentifierMap = readEntryRouteIdFromIdentifierMap(options, link.contentType, link.identifier);
74935
+ return resolveRouteHrefWithFallback(routeIdFromPayload ?? routeIdFromIdentifierMap, readHrefFromLink(link), routes, stage);
74936
+ }
74937
+ return null;
74832
74938
  }
74833
- function readContentRecord(value) {
74834
- return isRecord$3(value) ? value : void 0;
74939
+ function resolveRouteHrefWithFallback(routeId, fallbackHref, routes, stage) {
74940
+ if (!routeId) return fallbackHref;
74941
+ const resolved = resolveRouteHrefForStage(routeId, routes, stage);
74942
+ if (resolved) return resolved;
74943
+ const route = routes[routeId];
74944
+ if (!route) return fallbackHref;
74945
+ if (!isRouteVisibleInStage(route, stage)) return null;
74946
+ return fallbackHref;
74835
74947
  }
74836
- function readNestedContentRecord(value) {
74837
- if (!isRecord$3(value)) return null;
74838
- return readContentRecord(value.data) ?? null;
74948
+ function readRouteIdFromLink(link) {
74949
+ if (!("routeId" in link) || typeof link.routeId !== "string") return null;
74950
+ return link.routeId;
74839
74951
  }
74840
- function sanitizeSdkRuntimeBlockContent(blockKind, content) {
74841
- if (blockKind !== "block.newsletter-signup") return content;
74842
- const sanitized = sanitizeNewsletterSignupPublicContent(content);
74843
- return isRecord$3(sanitized) ? sanitized : {};
74952
+ function readHrefFromLink(link) {
74953
+ if (!("href" in link) || typeof link.href !== "string") return null;
74954
+ return link.href;
74844
74955
  }
74845
- function sanitizeNullableSdkRuntimeBlockContent(blockKind, content) {
74846
- return content ? sanitizeSdkRuntimeBlockContent(blockKind, content) : null;
74956
+ function readEntryRouteIdFromIdentifierMap(options, contentType, identifier) {
74957
+ const entryMap = options?.entriesByIdentifier?.[contentType];
74958
+ if (!entryMap) return null;
74959
+ return entryMap[identifier] ?? null;
74960
+ }
74961
+ /**
74962
+ * Build a Logo from site layout data.
74963
+ *
74964
+ * @param logo - Logo data from site layout
74965
+ * @param fallbackAlt - Fallback alt text (usually site title)
74966
+ *
74967
+ * @example
74968
+ * ```ts
74969
+ * const logo = buildLogo(siteData.layout.logo, siteData.site.title);
74970
+ * // { src: 'https://...', alt: 'Site Name', width: 200, height: 50 }
74971
+ * ```
74972
+ */
74973
+ function buildLogo(logo, fallbackAlt) {
74974
+ if (!logo || !logo.url) return null;
74975
+ const alt = resolveAltText(logo.alt, fallbackAlt);
74976
+ const result = {
74977
+ type: "image",
74978
+ src: logo.url,
74979
+ alt
74980
+ };
74981
+ if (logo.width != null) result.width = logo.width;
74982
+ if (logo.height != null) result.height = logo.height;
74983
+ return result;
74984
+ }
74985
+ /**
74986
+ * Build both site logos from layout data. The default header and footer choose
74987
+ * between them by the surface they sit on; custom chrome can do the same.
74988
+ *
74989
+ * @example
74990
+ * ```ts
74991
+ * const logoVariants = buildLogoVariants(siteData.layout, siteData.site.title);
74992
+ * ```
74993
+ */
74994
+ function buildLogoVariants(layout, fallbackAlt) {
74995
+ return {
74996
+ forLightBackgrounds: buildLogo(layout?.logo ?? null, fallbackAlt),
74997
+ forDarkBackgrounds: buildLogo(layout?.logoForDarkBackgrounds ?? null, fallbackAlt)
74998
+ };
74999
+ }
75000
+ /**
75001
+ * Header/footer block content for the site logos. `logo` stays populated with
75002
+ * whichever logo exists so presence checks keep working; `logoVariants` is
75003
+ * what the blocks select from at render.
75004
+ */
75005
+ function buildChromeLogoContent(layout, fallbackAlt) {
75006
+ const logoVariants = buildLogoVariants(layout, fallbackAlt);
75007
+ return {
75008
+ logo: logoVariants.forLightBackgrounds ?? logoVariants.forDarkBackgrounds,
75009
+ logoVariants
75010
+ };
75011
+ }
75012
+ //#endregion
75013
+ //#region src/rendering/themeAdmission.ts
75014
+ const MISSING_SDK_THEME_ERROR_CODE = "missing_sdk_theme";
75015
+ var MissingSdkThemeError = class extends Error {
75016
+ constructor(siteId, reason = "cms_theme_absent", themeKey) {
75017
+ 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.");
75018
+ this.siteId = siteId;
75019
+ this.reason = reason;
75020
+ this.themeKey = themeKey;
75021
+ this.code = MISSING_SDK_THEME_ERROR_CODE;
75022
+ this.name = "MissingSdkThemeError";
75023
+ }
75024
+ };
75025
+ function requireSdkTheme(theme, siteId, reason = "cms_theme_absent") {
75026
+ if (theme === null || theme === void 0) throw new MissingSdkThemeError(siteId, reason);
75027
+ return theme;
74847
75028
  }
74848
75029
  //#endregion
75030
+ //#region src/rendering/renderingMode.ts
75031
+ const defaultOverrideOnlyRuntime = { kind: "responsive-only" };
75032
+ //#endregion
74849
75033
  //#region src/rendering/helpers/footerPageOutline.ts
74850
75034
  /**
74851
75035
  * Admit footer blocks returned by the site API for public rendering.
@@ -76670,6 +76854,7 @@ const SDK_EVENT_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
76670
76854
  responseKind: "json",
76671
76855
  errors: [
76672
76856
  "resource:not_found",
76857
+ "validation:invalid_input",
76673
76858
  "resource:conflict",
76674
76859
  "server:internal_error"
76675
76860
  ]
@@ -77124,28 +77309,6 @@ const EVENT_MANAGEMENT_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
77124
77309
  "resource:conflict",
77125
77310
  "server:internal_error"
77126
77311
  ]
77127
- },
77128
- /**
77129
- * The Content tab's one write: the short introduction, image and
77130
- * description of an event's page, published without its layout.
77131
- */
77132
- saveEventPageWords: {
77133
- path: "/sites/{siteId}/page-surfaces/{pageSurfaceId}/words",
77134
- method: "PUT",
77135
- tags: [
77136
- TAG_TEMPLATES.siteCollection,
77137
- TAG_TEMPLATES.siteRoutableContent,
77138
- TAG_TEMPLATES.pageSurfaceById
77139
- ],
77140
- auth: "user",
77141
- responseKind: "json",
77142
- errors: [
77143
- "auth:forbidden",
77144
- "validation:invalid_input",
77145
- "resource:not_found",
77146
- "resource:conflict",
77147
- "server:internal_error"
77148
- ]
77149
77312
  }
77150
77313
  });
77151
77314
  //#endregion
@@ -77570,6 +77733,15 @@ const BILLING_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
77570
77733
  auth: "user",
77571
77734
  responseKind: "json"
77572
77735
  },
77736
+ /** Continue on Free from the onboarding card page; only the attempt's owner. */
77737
+ continueOnboardingOnFree: {
77738
+ path: "/onboarding/attempts/{attemptToken}/plan/free",
77739
+ method: "POST",
77740
+ tags: ["billing"],
77741
+ auth: "user",
77742
+ errors: [],
77743
+ responseKind: "json"
77744
+ },
77573
77745
  createBillingPortalSession: {
77574
77746
  path: "/billing/portal/session",
77575
77747
  method: "POST",
@@ -77579,6 +77751,161 @@ const BILLING_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
77579
77751
  }
77580
77752
  });
77581
77753
  //#endregion
77754
+ //#region ../api/src/editLeaseEndpoints.ts
77755
+ const path = "/sites/{siteId}/edit-leases/{nodeType}/{nodeId}";
77756
+ const lifecycleErrors = [
77757
+ "auth:lease_required",
77758
+ "auth:forbidden",
77759
+ "resource:not_found",
77760
+ "validation:invalid_input",
77761
+ "server:internal_error"
77762
+ ];
77763
+ const EDIT_LEASE_ENDPOINT_DEFINITIONS = {
77764
+ readEditLease: {
77765
+ path,
77766
+ method: "GET",
77767
+ editLease: "lifecycle",
77768
+ errors: lifecycleErrors,
77769
+ auth: "user",
77770
+ responseKind: "json"
77771
+ },
77772
+ acquireEditLease: {
77773
+ path,
77774
+ method: "POST",
77775
+ editLease: "lifecycle",
77776
+ errors: lifecycleErrors,
77777
+ auth: "user",
77778
+ responseKind: "json"
77779
+ },
77780
+ takeOverEditLease: {
77781
+ path,
77782
+ method: "PUT",
77783
+ editLease: "lifecycle",
77784
+ errors: lifecycleErrors,
77785
+ auth: "user",
77786
+ responseKind: "json"
77787
+ },
77788
+ heartbeatEditLease: {
77789
+ path,
77790
+ method: "PATCH",
77791
+ editLease: "lifecycle",
77792
+ errors: [...lifecycleErrors, "auth:lease_lost"],
77793
+ auth: "user",
77794
+ responseKind: "json"
77795
+ },
77796
+ releaseEditLease: {
77797
+ path,
77798
+ method: "DELETE",
77799
+ editLease: "lifecycle",
77800
+ errors: lifecycleErrors,
77801
+ auth: "user",
77802
+ responseKind: "json"
77803
+ }
77804
+ };
77805
+ //#endregion
77806
+ //#region ../api/src/pageSurfaceEditorEndpoints.ts
77807
+ const surfaceTags = [TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.pageSurfaceById];
77808
+ const PAGE_SURFACE_EDITOR_ENDPOINT_DEFINITIONS = {
77809
+ getPageSurfaceEditorDocument: {
77810
+ path: "/sites/{siteId}/page-surfaces/{pageSurfaceId}/content",
77811
+ method: "GET",
77812
+ errors: [
77813
+ "auth:forbidden",
77814
+ "validation:invalid_input",
77815
+ "resource:not_found",
77816
+ "resource:conflict",
77817
+ "server:internal_error"
77818
+ ],
77819
+ tags: surfaceTags,
77820
+ auth: "user",
77821
+ responseKind: "json"
77822
+ },
77823
+ updatePageSurfaceDraftContent: {
77824
+ editLease: "managed",
77825
+ path: "/sites/{siteId}/page-surfaces/{pageSurfaceId}/content",
77826
+ method: "PUT",
77827
+ errors: [
77828
+ "validation:invalid_input",
77829
+ "resource:not_found",
77830
+ "resource:conflict",
77831
+ "server:internal_error"
77832
+ ],
77833
+ tags: surfaceTags,
77834
+ auth: "user",
77835
+ responseKind: "json"
77836
+ },
77837
+ discardPageSurfaceDraftContent: {
77838
+ editLease: "managed",
77839
+ path: "/sites/{siteId}/page-surfaces/{pageSurfaceId}/content/draft",
77840
+ method: "DELETE",
77841
+ errors: [
77842
+ "validation:invalid_input",
77843
+ "resource:not_found",
77844
+ "resource:conflict",
77845
+ "server:internal_error"
77846
+ ],
77847
+ tags: surfaceTags,
77848
+ auth: "user",
77849
+ responseKind: "json"
77850
+ },
77851
+ updatePageSurfaceRouteMetadata: {
77852
+ editLease: "managed",
77853
+ path: "/sites/{siteId}/page-surfaces/{pageSurfaceId}/metadata",
77854
+ method: "PATCH",
77855
+ errors: [
77856
+ "validation:invalid_input",
77857
+ "resource:not_found",
77858
+ "resource:conflict",
77859
+ "server:internal_error"
77860
+ ],
77861
+ tags: [
77862
+ TAG_TEMPLATES.siteCollection,
77863
+ TAG_TEMPLATES.siteRoutableContent,
77864
+ TAG_TEMPLATES.pageSurfaceById
77865
+ ],
77866
+ auth: "user",
77867
+ responseKind: "json"
77868
+ },
77869
+ publishPageSurface: {
77870
+ editLease: "managed",
77871
+ path: "/sites/{siteId}/page-surfaces/{pageSurfaceId}/publication",
77872
+ method: "POST",
77873
+ errors: [
77874
+ "auth:forbidden",
77875
+ "validation:invalid_input",
77876
+ "resource:not_found",
77877
+ "resource:conflict",
77878
+ "server:internal_error"
77879
+ ],
77880
+ tags: [
77881
+ TAG_TEMPLATES.siteCollection,
77882
+ TAG_TEMPLATES.siteRoutableContent,
77883
+ TAG_TEMPLATES.pageSurfaceById
77884
+ ],
77885
+ auth: "user",
77886
+ responseKind: "json"
77887
+ },
77888
+ saveEventContentTab: {
77889
+ editLease: "managed",
77890
+ path: "/sites/{siteId}/page-surfaces/{pageSurfaceId}/event-content",
77891
+ method: "PUT",
77892
+ errors: [
77893
+ "auth:forbidden",
77894
+ "validation:invalid_input",
77895
+ "resource:not_found",
77896
+ "resource:conflict",
77897
+ "server:internal_error"
77898
+ ],
77899
+ tags: [
77900
+ TAG_TEMPLATES.siteCollection,
77901
+ TAG_TEMPLATES.siteRoutableContent,
77902
+ TAG_TEMPLATES.pageSurfaceById
77903
+ ],
77904
+ auth: "user",
77905
+ responseKind: "json"
77906
+ }
77907
+ };
77908
+ //#endregion
77582
77909
  //#region ../api/src/bookingPeopleEndpointDefinitions.ts
77583
77910
  /**
77584
77911
  * People endpoints (#1356): the People list, its CSV export, and deleting a
@@ -77671,12 +77998,14 @@ z.object({
77671
77998
  ...GIFTING_ENDPOINT_DEFINITIONS,
77672
77999
  ...PUBLIC_READ_ENDPOINT_DEFINITIONS,
77673
78000
  ...BILLING_ENDPOINT_DEFINITIONS,
78001
+ ...EDIT_LEASE_ENDPOINT_DEFINITIONS,
78002
+ ...PAGE_SURFACE_EDITOR_ENDPOINT_DEFINITIONS,
77674
78003
  ...SITE_MANAGEMENT_ENDPOINT_DEFINITIONS
77675
78004
  }), 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, {
77676
78005
  ...NEWSLETTER_ENDPOINT_DEFINITIONS,
77677
78006
  ...APPOINTMENT_ENDPOINT_DEFINITIONS,
77678
78007
  ...EVENT_SERIES_REGISTRATION_ENDPOINT_DEFINITIONS
77679
- }, 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 };
78008
+ }, 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 };
77680
78009
  z.object({ refreshToken: z.string().min(1).max(4096) }).strict();
77681
78010
  z.object({
77682
78011
  accessToken: z.string().min(1).max(4096),