@riverbankcms/sdk 0.138.0 → 0.140.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 (293) hide show
  1. package/README.md +12 -16
  2. package/dist/{PreviewEditorSidebar-BVPur_CU.mjs → PreviewEditorSidebar-CUyTzd5z.mjs} +4 -4
  3. package/dist/{PreviewEditorUI-DLhWX8oh.mjs → PreviewEditorUI-Agkw4v5i.mjs} +3 -3
  4. package/dist/{PreviewQueryProvider-BguJY1SW.mjs → PreviewQueryProvider-CN0ewic5.mjs} +1 -1
  5. package/dist/{SdkPreviewModeRuntime-Tda6qw4z.mjs → SdkPreviewModeRuntime-DdbeAdS8.mjs} +62 -28
  6. package/dist/{SiteChromeCustomizeContext-BHFgMjde.mjs → SiteChromeCustomizeContext-CqGOz-Kv.mjs} +8467 -5616
  7. package/dist/_dts/ai/src/contracts/proposals.d.ts +264 -495
  8. package/dist/_dts/ai/src/contracts/siteStyleProposalSchemas.d.ts +221 -242
  9. package/dist/_dts/api/src/accessAdmin.d.ts +74 -104
  10. package/dist/_dts/api/src/aiEndpoints.d.ts +5 -1
  11. package/dist/_dts/api/src/authSubmission.d.ts +46 -0
  12. package/dist/_dts/api/src/billing.d.ts +18 -7
  13. package/dist/_dts/api/src/billingEndpointDefinitions.d.ts +23 -0
  14. package/dist/_dts/api/src/billingEndpointTypes.d.ts +26 -0
  15. package/dist/_dts/api/src/blocks.d.ts +2 -0
  16. package/dist/_dts/api/src/bookingRecords.d.ts +1 -2
  17. package/dist/_dts/api/src/commercePortalEndpoints.d.ts +8 -1
  18. package/dist/_dts/api/src/communications.d.ts +0 -1
  19. package/dist/_dts/api/src/contentRuntime.d.ts +16 -4
  20. package/dist/_dts/api/src/endpoints.d.ts +275 -167
  21. package/dist/_dts/api/src/event-destination-policy.d.ts +2 -1
  22. package/dist/_dts/api/src/footerSettings.d.ts +10 -10
  23. package/dist/_dts/api/src/index.d.ts +11 -10
  24. package/dist/_dts/api/src/indexCoreTypes.d.ts +1 -1
  25. package/dist/_dts/api/src/indexExtendedTypes.d.ts +1 -1
  26. package/dist/_dts/api/src/mailchimpIntegration.d.ts +2 -59
  27. package/dist/_dts/api/src/mailingListIntegration.d.ts +123 -0
  28. package/dist/_dts/api/src/navigation/dashboardSettingsNav.d.ts +1 -1
  29. package/dist/_dts/api/src/navigation/locations.d.ts +1 -0
  30. package/dist/_dts/api/src/navigation/types.d.ts +1 -1
  31. package/dist/_dts/api/src/navigation.d.ts +1 -26
  32. package/dist/_dts/api/src/newsletterEndpointDefinitions.d.ts +109 -2
  33. package/dist/_dts/api/src/onboarding/confirmationResend.d.ts +25 -0
  34. package/dist/_dts/api/src/onboarding/surfaceData.d.ts +185 -0
  35. package/dist/_dts/api/src/privacyPolicy.d.ts +74 -2
  36. package/dist/_dts/api/src/publicBookingAvailabilityEndpointDefinitions.d.ts +14 -6
  37. package/dist/_dts/api/src/publicEventEndpointDefinitions.d.ts +1 -1
  38. package/dist/_dts/api/src/publicExperience/commerceEndpoints.d.ts +1 -0
  39. package/dist/_dts/api/src/publicExperience/eventEndpoints.d.ts +11 -3
  40. package/dist/_dts/api/src/publicExperience/newsletterEndpoints.d.ts +2 -4
  41. package/dist/_dts/api/src/publicExperience/sharedTypes.d.ts +9 -49
  42. package/dist/_dts/api/src/publicOnboardingAttemptEndpointDefinitions.d.ts +65 -0
  43. package/dist/_dts/api/src/publicReadEndpointDefinitions.d.ts +73 -0
  44. package/dist/_dts/api/src/saveOutcome.d.ts +20 -0
  45. package/dist/_dts/api/src/schemas/site-api-keys.d.ts +1 -1
  46. package/dist/_dts/api/src/sdkContracts.d.ts +5 -32
  47. package/dist/_dts/api/src/sdkPushContracts.d.ts +18 -0
  48. package/dist/_dts/api/src/sdkThemeWire.d.ts +46 -46
  49. package/dist/_dts/api/src/settings/permissions.d.ts +12 -0
  50. package/dist/_dts/api/src/siteManagementEndpoints.d.ts +9 -34
  51. package/dist/_dts/api/src/siteOnboarding.d.ts +84 -228
  52. package/dist/_dts/api/src/sitePlatformEndpoints.d.ts +3 -13
  53. package/dist/_dts/api/src/siteRuntimeEndpoints.d.ts +3 -1
  54. package/dist/_dts/api/src/siteSettings.d.ts +38 -6
  55. package/dist/_dts/api/src/types.d.ts +78 -77
  56. package/dist/_dts/api/src/wholeSeriesRuns.d.ts +2 -37
  57. package/dist/_dts/billing/src/membership/index.d.ts +17 -7
  58. package/dist/_dts/billing/src/plans/display.d.ts +15 -0
  59. package/dist/_dts/billing/src/plans/registry.d.ts +2 -0
  60. package/dist/_dts/billing/src/plans/standing.d.ts +19 -0
  61. package/dist/_dts/billing/src/plans/types.d.ts +4 -7
  62. package/dist/_dts/billing/src/site-arrangements.d.ts +14 -3
  63. package/dist/_dts/billing/src/subscriptions/evidence.d.ts +12 -0
  64. package/dist/_dts/billing/src/subscriptions/standingEvidence.d.ts +31 -0
  65. package/dist/_dts/billing/src/subscriptions/store.d.ts +23 -5
  66. package/dist/_dts/blocks/src/PageRenderer.d.ts +6 -15
  67. package/dist/_dts/blocks/src/client.d.ts +1 -1
  68. package/dist/_dts/blocks/src/contracts/proof-block-islands.d.ts +48 -20
  69. package/dist/_dts/blocks/src/pageRenderAdmission.d.ts +2 -0
  70. package/dist/_dts/blocks/src/pageRendererContracts.d.ts +9 -0
  71. package/dist/_dts/blocks/src/pageRenderingMode.d.ts +12 -6
  72. package/dist/_dts/blocks/src/portal/types.d.ts +2 -4
  73. package/dist/_dts/blocks/src/portal/waitlist-types.d.ts +35 -0
  74. package/dist/_dts/blocks/src/system/blocks/appointment-services.d.ts +11 -0
  75. package/dist/_dts/blocks/src/system/blocks/contact-newsletter.d.ts +39 -66
  76. package/dist/_dts/blocks/src/system/blocks/event-registration.d.ts +2 -0
  77. package/dist/_dts/blocks/src/system/blocks/events/shared/schemas.d.ts +42 -0
  78. package/dist/_dts/blocks/src/system/blocks/events/shared/types.d.ts +4 -0
  79. package/dist/_dts/blocks/src/system/blocks/newsletter-signup.d.ts +39 -114
  80. package/dist/_dts/blocks/src/system/blocks/offerings-preview/catalogue.d.ts +18 -0
  81. package/dist/_dts/blocks/src/system/blocks/offerings-preview/fields.d.ts +2 -0
  82. package/dist/_dts/blocks/src/system/blocks/offerings-preview/index.d.ts +4 -0
  83. package/dist/_dts/blocks/src/system/blocks/site-footer-runtime.d.ts +7 -13
  84. package/dist/_dts/blocks/src/system/constants/blockKinds.d.ts +1 -1
  85. package/dist/_dts/blocks/src/system/data/index.d.ts +4 -4
  86. package/dist/_dts/blocks/src/system/data/loaderEndpoints.d.ts +1 -1
  87. package/dist/_dts/blocks/src/system/data/prefetchBlockData.d.ts +2 -1
  88. package/dist/_dts/blocks/src/system/data/publicLoaderCachePolicy.d.ts +2 -74
  89. package/dist/_dts/blocks/src/system/data/types.d.ts +9 -0
  90. package/dist/_dts/blocks/src/system/fragments/library/newsletterForm.d.ts +33 -100
  91. package/dist/_dts/blocks/src/system/registry.d.ts +1 -0
  92. package/dist/_dts/blocks/src/system/runtime/api/client.d.ts +0 -28
  93. package/dist/_dts/blocks/src/system/runtime/api/index.d.ts +1 -1
  94. package/dist/_dts/blocks/src/system/runtime/api/types/events.d.ts +7 -3
  95. package/dist/_dts/blocks/src/system/runtime/api/types/newsletter.d.ts +5 -15
  96. package/dist/_dts/blocks/src/system/runtime/api/types/portal.d.ts +1 -1
  97. package/dist/_dts/blocks/src/system/runtime/api/types/waitlist-claims.d.ts +7 -2
  98. package/dist/_dts/blocks/src/system/runtime/components/registry.client.d.ts +78 -30
  99. package/dist/_dts/blocks/src/system/runtime/components/runtime-backed-blocks.d.ts +39 -15
  100. package/dist/_dts/blocks/src/system/runtime/hooks/useCalendarEvents.d.ts +3 -0
  101. package/dist/_dts/blocks/src/system/runtime/hooks/useCalendarEvents.state.d.ts +1 -1
  102. package/dist/_dts/blocks/src/system/runtime/hooks/useCalendarToday.d.ts +22 -0
  103. package/dist/_dts/blocks/src/system/runtime/nodes/appointment-services.d.ts +94 -0
  104. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/EventRegistrationSurface.d.ts +1 -2
  105. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/TicketSelectionStep.d.ts +2 -0
  106. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/checkoutRecovery.d.ts +14 -0
  107. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/eventSourceRecovery.d.ts +56 -0
  108. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/types.d.ts +6 -8
  109. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useCheckoutRecovery.d.ts +8 -0
  110. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventRegistrationSubmit.d.ts +8 -7
  111. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventRegistrationWizard.d.ts +12 -2
  112. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventSourceRecovery.d.ts +18 -0
  113. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration.client.d.ts +1 -1
  114. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration.interactive.d.ts +24 -7
  115. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration.server.d.ts +4 -2
  116. package/dist/_dts/blocks/src/system/runtime/nodes/events/EventCombined.client.d.ts +28 -0
  117. package/dist/_dts/blocks/src/system/runtime/nodes/events/domain/bookability.d.ts +9 -0
  118. package/dist/_dts/blocks/src/system/runtime/nodes/events/domain/dates.d.ts +14 -0
  119. package/dist/_dts/blocks/src/system/runtime/nodes/events/domain/duration.d.ts +2 -0
  120. package/dist/_dts/blocks/src/system/runtime/nodes/events/domain/index.d.ts +4 -0
  121. package/dist/_dts/blocks/src/system/runtime/nodes/events/domain/location.d.ts +2 -0
  122. package/dist/_dts/blocks/src/system/runtime/nodes/events/domain/quickDates.d.ts +16 -0
  123. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/AgendaEventCard.d.ts +9 -1
  124. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/CalendarDayCell.d.ts +2 -0
  125. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/CalendarDayHeaders.d.ts +4 -0
  126. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/DayEventsModal.d.ts +2 -1
  127. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/EventCard.d.ts +5 -0
  128. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/EventModals.d.ts +2 -1
  129. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/EventQuickDates.d.ts +15 -0
  130. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/WeekAgendaView.d.ts +7 -3
  131. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/WeekTimetableView.d.ts +1 -0
  132. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/index.d.ts +2 -0
  133. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/timetableModel.d.ts +1 -0
  134. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/useHydrationReady.d.ts +6 -0
  135. package/dist/_dts/blocks/src/system/runtime/nodes/newsletter-form.client.state.d.ts +3 -0
  136. package/dist/_dts/blocks/src/system/runtime/nodes/newsletter-form.interactive.d.ts +62 -33
  137. package/dist/_dts/blocks/src/system/runtime/nodes/newsletter-form.submission.d.ts +3 -3
  138. package/dist/_dts/blocks/src/system/runtime/nodes/newsletter-form.types.d.ts +14 -31
  139. package/dist/_dts/blocks/src/system/runtime/nodes/offerings-preview-catalogue.d.ts +14 -0
  140. package/dist/_dts/blocks/src/system/runtime/nodes/offerings-preview-content.d.ts +23 -0
  141. package/dist/_dts/blocks/src/system/runtime/nodes/offerings-preview.d.ts +4 -2
  142. package/dist/_dts/blocks/src/system/runtime/resolver.d.ts +1 -0
  143. package/dist/_dts/blocks/src/system/runtime/shared/components/index.d.ts +2 -6
  144. package/dist/_dts/blocks/src/system/runtime/shared/index.d.ts +2 -2
  145. package/dist/_dts/blocks/src/system/runtime/shared/useWaitlistClaim.d.ts +2 -0
  146. package/dist/_dts/blocks/src/system/transforms/registry/formatting.d.ts +5 -0
  147. package/dist/_dts/commerce/src/purchase/event-registration-errors.d.ts +4 -0
  148. package/dist/_dts/commerce/src/purchase/index.d.ts +1 -0
  149. package/dist/_dts/commerce/src/purchase/orderItemMetadata.d.ts +32 -16
  150. package/dist/_dts/commerce/src/purchase/stripeCommissionMetadata.d.ts +34 -0
  151. package/dist/_dts/content-editor/src/controller/EntryControllerProvider.d.ts +2 -1
  152. package/dist/_dts/content-editor/src/footerEngagementDraft.d.ts +6 -24
  153. package/dist/_dts/content-editor/src/hooks/useBlockAutosave.d.ts +3 -1
  154. package/dist/_dts/content-editor/src/useFooterComposerState.d.ts +4 -2
  155. package/dist/_dts/core/src/branded.d.ts +0 -8
  156. package/dist/_dts/core/src/footer-engagement.d.ts +2 -6
  157. package/dist/_dts/core/src/index.d.ts +10 -1
  158. package/dist/_dts/core/src/mailing-list-identifiers.d.ts +21 -0
  159. package/dist/_dts/core/src/mailing-list-runtime.d.ts +42 -0
  160. package/dist/_dts/core/src/mailing-list-setup-parser.d.ts +14 -0
  161. package/dist/_dts/core/src/mailing-list-setup.d.ts +142 -0
  162. package/dist/_dts/core/src/mailing-list-submission.d.ts +224 -0
  163. package/dist/_dts/core/src/mailing-list-targeting-parser.d.ts +12 -0
  164. package/dist/_dts/core/src/mailing-list-targeting.d.ts +93 -0
  165. package/dist/_dts/core/src/navigation-locations.d.ts +28 -0
  166. package/dist/_dts/core/src/participants.d.ts +2 -29
  167. package/dist/_dts/core/src/public-experience.d.ts +4 -0
  168. package/dist/_dts/core/src/public-profile.d.ts +35 -1
  169. package/dist/_dts/core/src/public-read-cache-contract.d.ts +45 -0
  170. package/dist/_dts/core/src/site-route-target.d.ts +9 -2
  171. package/dist/_dts/db/src/generated/supabase/database.types.d.ts +797 -954
  172. package/dist/_dts/editor-blocks/src/widgets/index.d.ts +1 -0
  173. package/dist/_dts/editor-blocks/src/widgets/mailing-list-targeting/MailingListGlobalSettingsSummary.d.ts +10 -0
  174. package/dist/_dts/editor-blocks/src/widgets/mailing-list-targeting/MailingListTargetingField.d.ts +12 -0
  175. package/dist/_dts/editor-blocks/src/widgets/mailing-list-targeting/context.d.ts +14 -0
  176. package/dist/_dts/editor-blocks/src/widgets/mailing-list-targeting/index.d.ts +3 -0
  177. package/dist/_dts/editor-blocks/src/widgets/mailing-list-targeting/loaders.d.ts +7 -0
  178. package/dist/_dts/editor-blocks/src/widgets/mailing-list-targeting/targetingState.d.ts +19 -0
  179. package/dist/_dts/preview-next/src/client/widgets/widgetOverrides.d.ts +1 -0
  180. package/dist/_dts/sdk/src/client/publicAppointmentReadOperations.d.ts +12 -0
  181. package/dist/_dts/sdk/src/client/publicEventReadOperations.d.ts +2 -1
  182. package/dist/_dts/sdk/src/client/publicLoaderCacheAccess.d.ts +11 -4
  183. package/dist/_dts/sdk/src/config/content-types.d.ts +3 -13
  184. package/dist/_dts/sdk/src/config/content-validation.d.ts +5 -8
  185. package/dist/_dts/sdk/src/constants.d.ts +3 -3
  186. package/dist/_dts/sdk/src/contracts/index.d.ts +1 -1
  187. package/dist/_dts/sdk/src/contracts/system-block-content.d.ts +12 -31
  188. package/dist/_dts/sdk/src/navigation/index.d.ts +11 -29
  189. package/dist/_dts/sdk/src/next/index.d.ts +4 -4
  190. package/dist/_dts/sdk/src/prebuild/types.d.ts +1 -5
  191. package/dist/_dts/sdk/src/public-api/contracts.d.ts +44 -33
  192. package/dist/_dts/sdk/src/rendering/blocks-page-renderer.d.ts +5 -0
  193. package/dist/_dts/sdk/src/rendering/client.d.ts +3 -20
  194. package/dist/_dts/sdk/src/rendering/components/pageShared.d.ts +5 -0
  195. package/dist/_dts/sdk/src/rendering/helpers/loadContent.d.ts +4 -0
  196. package/dist/_dts/sdk/src/rendering/helpers/pageRuntimeSupport.d.ts +8 -1
  197. package/dist/_dts/sdk/src/rendering/helpers/templateContent.d.ts +1 -0
  198. package/dist/_dts/sdk/src/rendering/index.d.ts +1 -1
  199. package/dist/_dts/sdk/src/types/block-kinds.d.ts +1 -1
  200. package/dist/_dts/sdk/src/version.d.ts +1 -1
  201. package/dist/_dts/theme-core/src/accordions/types.d.ts +3 -3
  202. package/dist/_dts/theme-core/src/cards/types.d.ts +21 -21
  203. package/dist/_dts/theme-core/src/generated/containerResponsiveThemeCss.d.ts +1 -1
  204. package/dist/_dts/theme-core/src/header/interactionPalette.d.ts +8 -2
  205. package/dist/_dts/theme-core/src/header/legacyHeaderVariant.d.ts +2 -2
  206. package/dist/_dts/theme-core/src/hosted-booking-appearance.d.ts +41 -0
  207. package/dist/_dts/theme-core/src/index.d.ts +1 -0
  208. package/dist/_dts/theme-core/src/inputs/types.d.ts +2 -2
  209. package/dist/_dts/theme-core/src/mock-themes/all.d.ts +54 -54
  210. package/dist/_dts/theme-core/src/runtime/buildThemeRuntime.d.ts +0 -1
  211. package/dist/_dts/theme-core/src/runtime/buildThemeRuntimeFromBridge.d.ts +1 -4
  212. package/dist/_dts/theme-core/src/schema.d.ts +84 -84
  213. package/dist/_dts/theme-core/src/shared/componentStyles.d.ts +1 -1
  214. package/dist/_dts/theme-core/src/site-styles/backgroundAppearance.d.ts +2 -2
  215. package/dist/_dts/theme-core/src/surfaces/foregroundInteraction.d.ts +77 -0
  216. package/dist/_dts/theme-core/src/surfaces/index.d.ts +1 -0
  217. package/dist/_dts/theme-core/src/tokens/tokens.d.ts +7 -0
  218. package/dist/_dts/theme-core/src/typography/generateTypographyCss.d.ts +2 -2
  219. package/dist/_dts/ui/src/badge.d.ts +1 -1
  220. package/dist/_dts/ui/src/callout.d.ts +1 -1
  221. package/dist/_dts/ui/src/lib/use-delayed-flag.d.ts +9 -0
  222. package/dist/_dts/ui/src/pending-button.d.ts +10 -0
  223. package/dist/client/{BookingConsentAgreement-DQUik1Mx.mjs → BookingConsentAgreement-CuKa82V4.mjs} +4 -4
  224. package/dist/client/{DiscountCodeDisclosure-CU67Q4vH.mjs → DiscountCodeDisclosure-BbYieKWB.mjs} +1 -1
  225. package/dist/client/{EventCombined.client-a02TXUgg.mjs → EventCombined.client-LTfR1Aby.mjs} +444 -200
  226. package/dist/client/{EventListing.client-99qx7jFl.mjs → EventListing.client-DUHpYSuo.mjs} +2 -2
  227. package/dist/client/{LeafletStaticMap-CWzcq73L.mjs → LeafletStaticMap-CHRupL6m.mjs} +1 -1
  228. package/dist/client/{accordion-D1nb3-Oj.mjs → accordion-6HiIFxNL.mjs} +1 -1
  229. package/dist/client/{bookingForm-BGrmLhaO.mjs → bookingForm-Dlmid43H.mjs} +7 -7
  230. package/dist/client/bookings.mjs +368 -142
  231. package/dist/client/{carousel-DSmOx3ad.mjs → carousel-DmkZRRq_.mjs} +2 -2
  232. package/dist/client/{carousel.client-59G_WMr4.mjs → carousel.client-DQTjCVQT.mjs} +1 -1
  233. package/dist/client/{cart-COWeOIUk.mjs → cart-CIC24330.mjs} +3 -3
  234. package/dist/client/{checkout-CeysaIJK.mjs → checkout-D1Zw9imo.mjs} +3 -3
  235. package/dist/client/{checkoutUrls-BuseL0dw.mjs → checkoutUrls-FL6lRkrt.mjs} +1 -1
  236. package/dist/client/client.mjs +5017 -2258
  237. package/dist/client/{colorStyles-CrxJrPjJ.mjs → colorStyles-3013aRAY.mjs} +3 -1
  238. package/dist/client/{context-DBzX85Xc.mjs → context-Cy1OayHx.mjs} +9 -21
  239. package/dist/client/{dates-DCYhZBlW.mjs → dates-aDcfoLHr.mjs} +21 -3
  240. package/dist/client/{eventCalendar-BgsN73Ul.mjs → eventCalendar-FQxMPAjf.mjs} +81 -79
  241. package/dist/client/{eventCombined-DcZQAMQP.mjs → eventCombined-Dr3ac6Hb.mjs} +3 -3
  242. package/dist/client/{eventDetails-BWwGJ54l.mjs → eventDetails-D-AzUHFQ.mjs} +4 -4
  243. package/dist/client/{eventListing-DqYqV8vp.mjs → eventListing-B3XxBf3i.mjs} +3 -3
  244. package/dist/client/{eventRegistration-DQGDgu_e.mjs → eventRegistration-I6EaokFD.mjs} +543 -155
  245. package/dist/client/{form-ClfpasVT.mjs → form-BbWckVWY.mjs} +3 -3
  246. package/dist/client/{headerSection-BuOMe98N.mjs → headerSection-C9qU4Y7x.mjs} +2 -2
  247. package/dist/client/hooks.mjs +1685 -716
  248. package/dist/client/{locationMap-CEqu_sfa.mjs → locationMap-CLCShvlG.mjs} +3 -3
  249. package/dist/client/{media-BOHuueS5.mjs → media-DHpfFwd3.mjs} +1 -1
  250. package/dist/client/newsletterForm-Briukxzi.mjs +444 -0
  251. package/dist/client/{pricing-xj7MPZlK.mjs → pricing-Copadu-2.mjs} +1 -1
  252. package/dist/client/{productDetail-vxqTt5Xj.mjs → productDetail-oujlRd-r.mjs} +3 -3
  253. package/dist/client/{productList-OTdZu8sb.mjs → productList-BRiIRUcd.mjs} +3 -3
  254. package/dist/client/{propsDecoder-CY9gGEF7.mjs → propsDecoder-CB2KS_ko.mjs} +706 -160
  255. package/dist/client/rendering/client.mjs +3161 -1226
  256. package/dist/client/rendering/islands.mjs +19 -19
  257. package/dist/client/rendering.mjs +4864 -1914
  258. package/dist/client/{scrollToBlock--BFV6kl-.mjs → scrollToBlock-B1IS1_ua.mjs} +1 -1
  259. package/dist/client/{shop-CP4YbDL9.mjs → shop-Vn6yNFED.mjs} +6 -6
  260. package/dist/client/{shop-commerce-APs4XBXE.mjs → shop-commerce-BVTqipYp.mjs} +7 -7
  261. package/dist/client/{shop-commerce-store-CAVLxLFr.mjs → shop-commerce-store-BVnJVy7v.mjs} +1 -1
  262. package/dist/client/{shopShared-BnSRrwXI.mjs → shopShared-COIeK77T.mjs} +4 -4
  263. package/dist/client/{useEventFilters-1a1by4c8.mjs → useEventFilters-DzIUcS9n.mjs} +58 -11
  264. package/dist/preview-next/before-render.mjs +357 -175
  265. package/dist/preview-next/client/runtime.mjs +4 -4
  266. package/dist/preview-next/keepAlive.mjs +357 -175
  267. package/dist/preview-next/middleware.mjs +357 -175
  268. package/dist/{previewAuthStore-BkEgnYPP.mjs → previewAuthStore-Gjb6r6vz.mjs} +357 -175
  269. package/dist/{sdk-runtime-DwGfsT0S.mjs → sdk-runtime-CnCLvZRv.mjs} +2 -2
  270. package/dist/{separator-BeqDLneQ.mjs → separator-DKDRJ1oH.mjs} +1 -1
  271. package/dist/server/components.mjs +3389 -1251
  272. package/dist/server/config-validation.mjs +2737 -1784
  273. package/dist/server/config.mjs +2742 -1788
  274. package/dist/server/data.mjs +1586 -615
  275. package/dist/server/index.mjs +496 -352
  276. package/dist/server/navigation.mjs +16 -47
  277. package/dist/server/next.mjs +3978 -2007
  278. package/dist/server/page-converter.mjs +1109 -553
  279. package/dist/server/prebuild.mjs +2 -3
  280. package/dist/server/rendering/server.mjs +4101 -1951
  281. package/dist/server/rendering.mjs +3416 -1259
  282. package/dist/server/routing.mjs +1869 -786
  283. package/dist/server/server.mjs +3260 -2482
  284. package/dist/server/theme-bridge.mjs +725 -124
  285. package/dist/server/theme.mjs +8 -2
  286. package/dist/styles/index.css +526 -68
  287. package/package.json +1 -1
  288. package/dist/_dts/api/src/navigation/identity.d.ts +0 -59
  289. package/dist/_dts/blocks/src/system/blocks/newsletter-signup-destination.d.ts +0 -291
  290. package/dist/_dts/blocks/src/system/runtime/shared/components/BookingOptionCompactRow.d.ts +0 -29
  291. package/dist/_dts/blocks/src/system/runtime/shared/components/BookingOptionList.d.ts +0 -13
  292. package/dist/_dts/core/src/newsletter-signup-destination.d.ts +0 -38
  293. package/dist/client/newsletterForm-IbrHjMxy.mjs +0 -322
@@ -17,12 +17,12 @@ function err(error) {
17
17
  }
18
18
  //#endregion
19
19
  //#region ../core/src/branded.ts
20
- const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
20
+ const UUID_PATTERN$1 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
21
21
  function parseUuidBrand(value, unsafeConstructor) {
22
22
  if (typeof value !== "string") return err({ kind: "not_string" });
23
23
  const normalized = value.trim().toLowerCase();
24
24
  if (normalized.length === 0) return err({ kind: "empty_string" });
25
- if (!UUID_PATTERN.test(normalized)) return err({ kind: "invalid_uuid" });
25
+ if (!UUID_PATTERN$1.test(normalized)) return err({ kind: "invalid_uuid" });
26
26
  return ok(unsafeConstructor(normalized));
27
27
  }
28
28
  const unsafeAsSiteId = (id) => id;
@@ -30,10 +30,12 @@ const unsafeAsApiKeyId = (id) => id;
30
30
  const unsafeAsEventOfferingId = (id) => id;
31
31
  const unsafeAsEventSeriesId = (id) => id;
32
32
  const unsafeAsUserId = (id) => id;
33
+ const unsafeAsContentVersionId = (id) => id;
33
34
  const parseSiteId = (value) => parseUuidBrand(value, unsafeAsSiteId);
34
35
  const parseApiKeyId = (value) => parseUuidBrand(value, unsafeAsApiKeyId);
35
36
  const parseEventOfferingId = (value) => parseUuidBrand(value, unsafeAsEventOfferingId);
36
37
  const parseUserId = (value) => parseUuidBrand(value, unsafeAsUserId);
38
+ const parseContentVersionId = (value) => parseUuidBrand(value, unsafeAsContentVersionId);
37
39
  const parseEventSeriesId = (value) => parseUuidBrand(value, unsafeAsEventSeriesId);
38
40
  //#endregion
39
41
  //#region ../core/src/assert-never.ts
@@ -267,7 +269,7 @@ function parseEventPageSurfaceDestinationMode(value) {
267
269
  return value === "cms-managed" || value === "system-managed" ? value : void 0;
268
270
  }
269
271
  function parseEventPageSurfaceSubject(value) {
270
- if (!isRecord$13(value)) return err({ kind: "notObject" });
272
+ if (!isRecord$16(value)) return err({ kind: "notObject" });
271
273
  switch (value.kind) {
272
274
  case "eventSeries": {
273
275
  const eventSeriesId = parseEventSeriesId(value.eventSeriesId);
@@ -322,7 +324,7 @@ function parseEventSeriesIdList(values) {
322
324
  }
323
325
  return ok(parsed);
324
326
  }
325
- function isRecord$13(value) {
327
+ function isRecord$16(value) {
326
328
  return typeof value === "object" && value !== null && !Array.isArray(value);
327
329
  }
328
330
  //#endregion
@@ -492,9 +494,419 @@ function toLocationCoordinates(value) {
492
494
  };
493
495
  }
494
496
  //#endregion
495
- //#region ../core/src/newsletter-signup-destination.ts
496
- function parseNewsletterSignupDestinationProvider(value) {
497
- return value === "riverbank" || value === "mailchimp" ? value : null;
497
+ //#region ../core/src/mailing-list-identifiers.ts
498
+ 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;
499
+ const OPAQUE_ID_PATTERN = /^[A-Za-z0-9_-]{1,100}$/u;
500
+ function parseTrimmedMatchingString(value, pattern) {
501
+ if (typeof value !== "string") return null;
502
+ const trimmed = value.trim();
503
+ return pattern.test(trimmed) ? trimmed : null;
504
+ }
505
+ function parsePositiveInteger(value) {
506
+ return typeof value === "number" && Number.isSafeInteger(value) && value > 0 ? value : null;
507
+ }
508
+ function parseNewsletterListId(value) {
509
+ return parseTrimmedMatchingString(value, UUID_PATTERN);
510
+ }
511
+ function parseMailchimpAccountId(value) {
512
+ return parseTrimmedMatchingString(value, OPAQUE_ID_PATTERN);
513
+ }
514
+ function parseMailchimpAudienceId(value) {
515
+ return parseTrimmedMatchingString(value, OPAQUE_ID_PATTERN);
516
+ }
517
+ function parseMailchimpInterestId(value) {
518
+ return parseTrimmedMatchingString(value, OPAQUE_ID_PATTERN);
519
+ }
520
+ function parseBrevoAccountId(value) {
521
+ return parseTrimmedMatchingString(value, OPAQUE_ID_PATTERN);
522
+ }
523
+ function parseBrevoListId(value) {
524
+ return parsePositiveInteger(value);
525
+ }
526
+ //#endregion
527
+ //#region ../core/src/mailing-list-setup.ts
528
+ function isRecord$15(value) {
529
+ return typeof value === "object" && value !== null && !Array.isArray(value);
530
+ }
531
+ const DEFAULT_MAILING_LIST_SUCCESS_MESSAGE = "Thanks — you're on the list.";
532
+ function parseMailingListProviderScope(value) {
533
+ if (!isRecord$15(value)) return err("invalid_mailing_list_provider_scope");
534
+ if (value.provider === "native") return ok({ provider: "native" });
535
+ if (value.provider === "brevo") {
536
+ const accountId = parseBrevoAccountId(value.accountId);
537
+ return accountId !== null ? ok({
538
+ provider: "brevo",
539
+ accountId
540
+ }) : err("invalid_mailing_list_provider_scope");
541
+ }
542
+ if (value.provider === "mailchimp") {
543
+ const accountId = parseMailchimpAccountId(value.accountId);
544
+ return accountId !== null ? ok({
545
+ provider: "mailchimp",
546
+ accountId
547
+ }) : err("invalid_mailing_list_provider_scope");
548
+ }
549
+ return err("invalid_mailing_list_provider_scope");
550
+ }
551
+ //#endregion
552
+ //#region ../core/src/mailing-list-setup-parser.ts
553
+ function parseMailingListGlobalForm(value) {
554
+ if (!isRecord$14(value)) return formError("shape");
555
+ const fields = parseGlobalFields(value.fields);
556
+ if (fields === null) return formError("fields");
557
+ if (typeof value.includeOptionalPhone !== "boolean") return formError("includeOptionalPhone");
558
+ const buttonLabel = parseRequiredString(value.buttonLabel);
559
+ if (buttonLabel === null) return formError("buttonLabel");
560
+ const successMessage = parseRequiredString(value.successMessage);
561
+ if (successMessage === null) return formError("successMessage");
562
+ const privacyNote = parseOptionalString(value.privacyNote);
563
+ if (privacyNote === void 0) return formError("privacyNote");
564
+ return ok({
565
+ fields,
566
+ includeOptionalPhone: value.includeOptionalPhone,
567
+ buttonLabel,
568
+ successMessage,
569
+ privacyNote
570
+ });
571
+ }
572
+ function parseGlobalFields(value) {
573
+ if (!isRecord$14(value) || typeof value.preset !== "string") return null;
574
+ switch (value.preset) {
575
+ case "emailOnly": return { preset: "emailOnly" };
576
+ case "emailName": return isRequirement(value.name) ? {
577
+ preset: "emailName",
578
+ name: value.name
579
+ } : null;
580
+ case "emailFirstLast": return isRequirement(value.firstName) && isRequirement(value.lastName) ? {
581
+ preset: "emailFirstLast",
582
+ firstName: value.firstName,
583
+ lastName: value.lastName
584
+ } : null;
585
+ case "emailNameCompany": return isRequirement(value.name) && isRequirement(value.company) ? {
586
+ preset: "emailNameCompany",
587
+ name: value.name,
588
+ company: value.company
589
+ } : null;
590
+ default: return null;
591
+ }
592
+ }
593
+ function parseMailingListSetupRevision(value) {
594
+ return typeof value === "number" && Number.isSafeInteger(value) && value > 0 ? value : null;
595
+ }
596
+ function parseRequiredString(value) {
597
+ if (typeof value !== "string") return null;
598
+ const trimmed = value.trim();
599
+ return trimmed.length > 0 ? trimmed : null;
600
+ }
601
+ function parseOptionalString(value) {
602
+ if (value === null || value === void 0) return null;
603
+ if (typeof value !== "string") return void 0;
604
+ const trimmed = value.trim();
605
+ return trimmed.length > 0 ? trimmed : null;
606
+ }
607
+ function isRequirement(value) {
608
+ return value === "required" || value === "optional";
609
+ }
610
+ function isRecord$14(value) {
611
+ return typeof value === "object" && value !== null && !Array.isArray(value);
612
+ }
613
+ function formError(field) {
614
+ return err({
615
+ tag: "invalid_mailing_list_global_form",
616
+ field
617
+ });
618
+ }
619
+ //#endregion
620
+ //#region ../core/src/mailing-list-targeting.ts
621
+ function planMailingListChoicePresentation(targeting) {
622
+ if (targeting.mode === "default" || targeting.selection.tag === "fixed") return { tag: "hidden" };
623
+ switch (targeting.provider) {
624
+ case "native": return targeting.selection.offeredTopicIds.length === 1 ? {
625
+ tag: "automatic",
626
+ selection: {
627
+ provider: "native",
628
+ topicIds: targeting.selection.offeredTopicIds
629
+ }
630
+ } : {
631
+ tag: "visitor_choice",
632
+ provider: "native",
633
+ optionCount: targeting.selection.offeredTopicIds.length
634
+ };
635
+ case "brevo": return targeting.selection.offeredListIds.length === 1 ? {
636
+ tag: "automatic",
637
+ selection: {
638
+ provider: "brevo",
639
+ listIds: targeting.selection.offeredListIds
640
+ }
641
+ } : {
642
+ tag: "visitor_choice",
643
+ provider: "brevo",
644
+ optionCount: targeting.selection.offeredListIds.length
645
+ };
646
+ case "mailchimp": return targeting.selection.offeredInterestIds.length === 1 ? {
647
+ tag: "automatic",
648
+ selection: {
649
+ provider: "mailchimp",
650
+ interestIds: targeting.selection.offeredInterestIds
651
+ }
652
+ } : {
653
+ tag: "visitor_choice",
654
+ provider: "mailchimp",
655
+ optionCount: targeting.selection.offeredInterestIds.length
656
+ };
657
+ }
658
+ }
659
+ //#endregion
660
+ //#region ../core/src/mailing-list-runtime.ts
661
+ function parseMailingListRuntimeContext(value) {
662
+ if (!isRecord$13(value)) return invalidRuntimeContext();
663
+ if (value.tag === "not_configured") return ok({ tag: "not_configured" });
664
+ if (value.tag !== "configured") return invalidRuntimeContext();
665
+ const revision = parseMailingListSetupRevision(value.revision);
666
+ const form = parseMailingListGlobalForm(value.form);
667
+ const provider = parseRuntimeProvider(value.provider);
668
+ if (revision === null || !form.ok || provider === null) return invalidRuntimeContext();
669
+ return ok({
670
+ tag: "configured",
671
+ revision,
672
+ form: form.value,
673
+ provider
674
+ });
675
+ }
676
+ function parseRuntimeProvider(value) {
677
+ if (!isRecord$13(value)) return null;
678
+ switch (value.provider) {
679
+ case "native": return parseNativeRuntimeProvider(value);
680
+ case "brevo": return parseBrevoRuntimeProvider(value);
681
+ case "mailchimp": return parseMailchimpRuntimeProvider(value);
682
+ default: return null;
683
+ }
684
+ }
685
+ function parseNativeRuntimeProvider(value) {
686
+ const defaultTopicId = parseNewsletterListId(value.defaultTopicId);
687
+ const topics = parseNamedItems(value.topics, parseNewsletterListId);
688
+ return defaultTopicId !== null && topics !== null ? {
689
+ provider: "native",
690
+ defaultTopicId,
691
+ topics
692
+ } : null;
693
+ }
694
+ function parseBrevoRuntimeProvider(value) {
695
+ const defaultListId = parseBrevoListId(value.defaultListId);
696
+ const lists = parseNamedItems(value.lists, parseBrevoListId);
697
+ return defaultListId !== null && lists !== null ? {
698
+ provider: "brevo",
699
+ defaultListId,
700
+ lists
701
+ } : null;
702
+ }
703
+ function parseMailchimpRuntimeProvider(value) {
704
+ if (!Array.isArray(value.audiences)) return null;
705
+ const defaultAudienceId = parseMailchimpAudienceId(value.defaultAudienceId);
706
+ if (defaultAudienceId === null) return null;
707
+ const audiences = [];
708
+ for (const audience of value.audiences) {
709
+ if (!isRecord$13(audience)) return null;
710
+ const id = parseMailchimpAudienceId(audience.id);
711
+ const name = parseName(audience.name);
712
+ if (id === null || name === null || !Array.isArray(audience.interests)) return null;
713
+ const interests = parseMailchimpInterests(audience.interests);
714
+ if (interests === null) return null;
715
+ audiences.push({
716
+ id,
717
+ name,
718
+ interests
719
+ });
720
+ }
721
+ return {
722
+ provider: "mailchimp",
723
+ defaultAudienceId,
724
+ audiences
725
+ };
726
+ }
727
+ function parseMailchimpInterests(value) {
728
+ const interests = [];
729
+ for (const interest of value) {
730
+ if (!isRecord$13(interest)) return null;
731
+ const id = parseMailchimpInterestId(interest.id);
732
+ const name = parseName(interest.name);
733
+ const categoryName = parseName(interest.categoryName);
734
+ if (id === null || name === null || categoryName === null) return null;
735
+ interests.push({
736
+ id,
737
+ name,
738
+ categoryName
739
+ });
740
+ }
741
+ return interests;
742
+ }
743
+ function parseNamedItems(value, parseId) {
744
+ if (!Array.isArray(value)) return null;
745
+ const items = [];
746
+ for (const item of value) {
747
+ if (!isRecord$13(item)) return null;
748
+ const id = parseId(item.id);
749
+ const name = parseName(item.name);
750
+ if (id === null || name === null) return null;
751
+ items.push({
752
+ id,
753
+ name
754
+ });
755
+ }
756
+ return items;
757
+ }
758
+ function parseName(value) {
759
+ if (typeof value !== "string") return null;
760
+ const name = value.trim();
761
+ return name.length > 0 ? name : null;
762
+ }
763
+ function isRecord$13(value) {
764
+ return typeof value === "object" && value !== null && !Array.isArray(value);
765
+ }
766
+ function invalidRuntimeContext() {
767
+ return err({ tag: "invalid_mailing_list_runtime_context" });
768
+ }
769
+ //#endregion
770
+ //#region ../core/src/mailing-list-targeting-parser.ts
771
+ function parseMailingListPlacementTargeting(value) {
772
+ if (!isRecord$12(value)) return targetingError("shape");
773
+ if (value.mode === "default") return ok({ mode: "default" });
774
+ if (value.mode !== "custom") return targetingError("mode");
775
+ if (!isRecord$12(value.selection)) return targetingError("selection");
776
+ switch (value.provider) {
777
+ case "native": return parseNativeTargeting(value.selection);
778
+ case "brevo": return parseBrevoTargeting(value.selection);
779
+ case "mailchimp": return parseMailchimpTargeting(value, value.selection);
780
+ default: return targetingError("provider");
781
+ }
782
+ }
783
+ function parseNativeTargeting(selection) {
784
+ if (selection.tag === "fixed") {
785
+ const topicIds = parseNonEmptyUniqueIds(selection.topicIds, parseNewsletterListId);
786
+ return topicIds.ok ? ok({
787
+ mode: "custom",
788
+ provider: "native",
789
+ selection: {
790
+ tag: "fixed",
791
+ topicIds: topicIds.value
792
+ }
793
+ }) : topicIds;
794
+ }
795
+ if (selection.tag === "visitor_choice") {
796
+ const offeredTopicIds = parseNonEmptyUniqueIds(selection.offeredTopicIds, parseNewsletterListId);
797
+ return offeredTopicIds.ok ? ok({
798
+ mode: "custom",
799
+ provider: "native",
800
+ selection: {
801
+ tag: "visitor_choice",
802
+ offeredTopicIds: offeredTopicIds.value
803
+ }
804
+ }) : offeredTopicIds;
805
+ }
806
+ return targetingError("selection");
807
+ }
808
+ function parseBrevoTargeting(selection) {
809
+ if (selection.tag === "fixed") {
810
+ const listIds = parseNonEmptyUniqueIds(selection.listIds, parseBrevoListId);
811
+ return listIds.ok ? ok({
812
+ mode: "custom",
813
+ provider: "brevo",
814
+ selection: {
815
+ tag: "fixed",
816
+ listIds: listIds.value
817
+ }
818
+ }) : listIds;
819
+ }
820
+ if (selection.tag === "visitor_choice") {
821
+ const offeredListIds = parseNonEmptyUniqueIds(selection.offeredListIds, parseBrevoListId);
822
+ return offeredListIds.ok ? ok({
823
+ mode: "custom",
824
+ provider: "brevo",
825
+ selection: {
826
+ tag: "visitor_choice",
827
+ offeredListIds: offeredListIds.value
828
+ }
829
+ }) : offeredListIds;
830
+ }
831
+ return targetingError("selection");
832
+ }
833
+ function parseMailchimpTargeting(value, selection) {
834
+ const audienceId = parseMailchimpAudienceId(value.audienceId);
835
+ if (audienceId === null) return targetingError("audienceId");
836
+ if (selection.tag === "fixed") {
837
+ const interestIds = parseUniqueIds(selection.interestIds, parseMailchimpInterestId);
838
+ return interestIds.ok ? ok({
839
+ mode: "custom",
840
+ provider: "mailchimp",
841
+ audienceId,
842
+ selection: {
843
+ tag: "fixed",
844
+ interestIds: interestIds.value
845
+ }
846
+ }) : interestIds;
847
+ }
848
+ if (selection.tag === "visitor_choice") {
849
+ const offeredInterestIds = parseNonEmptyUniqueIds(selection.offeredInterestIds, parseMailchimpInterestId);
850
+ return offeredInterestIds.ok ? ok({
851
+ mode: "custom",
852
+ provider: "mailchimp",
853
+ audienceId,
854
+ selection: {
855
+ tag: "visitor_choice",
856
+ offeredInterestIds: offeredInterestIds.value
857
+ }
858
+ }) : offeredInterestIds;
859
+ }
860
+ return targetingError("selection");
861
+ }
862
+ function parseNonEmptyUniqueIds(value, parseId) {
863
+ const parsed = parseUniqueIds(value, parseId);
864
+ if (!parsed.ok) return parsed;
865
+ const [first, ...rest] = parsed.value;
866
+ return first === void 0 ? targetingError("targets") : ok([first, ...rest]);
867
+ }
868
+ function parseUniqueIds(value, parseId) {
869
+ if (!Array.isArray(value)) return targetingError("targets");
870
+ const parsed = [];
871
+ for (const item of value) {
872
+ const id = parseId(item);
873
+ if (id === null) return targetingError("targets");
874
+ if (parsed.includes(id)) return targetingError("duplicate_target");
875
+ parsed.push(id);
876
+ }
877
+ return ok(parsed);
878
+ }
879
+ function isRecord$12(value) {
880
+ return typeof value === "object" && value !== null && !Array.isArray(value);
881
+ }
882
+ function targetingError(field) {
883
+ return err({
884
+ tag: "invalid_mailing_list_targeting",
885
+ field
886
+ });
887
+ }
888
+ //#endregion
889
+ //#region ../core/src/mailing-list-submission.ts
890
+ function parseMailingListBlockId(value) {
891
+ const parsed = typeof value === "string" ? value.trim() : "";
892
+ return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu.test(parsed) ? parsed : null;
893
+ }
894
+ function parseMailingListSignedSourceToken(value) {
895
+ const parsed = typeof value === "string" ? value.trim() : "";
896
+ return /^[A-Za-z0-9._~-]{16,1000}$/u.test(parsed) ? parsed : null;
897
+ }
898
+ function parseMailingListContentVersionId(value) {
899
+ const parsed = parseContentVersionId(value);
900
+ return parsed.ok ? parsed.value : null;
901
+ }
902
+ function buildMailingListSignupBlockSourceRef(blockId, contentVersionId) {
903
+ const parsedBlockId = parseMailingListBlockId(blockId);
904
+ const parsedContentVersionId = parseMailingListContentVersionId(contentVersionId);
905
+ return parsedBlockId !== null && parsedContentVersionId !== null ? {
906
+ tag: "block_ref",
907
+ blockId: parsedBlockId,
908
+ contentVersionId: parsedContentVersionId
909
+ } : null;
498
910
  }
499
911
  //#endregion
500
912
  //#region ../core/src/secret.ts
@@ -556,6 +968,56 @@ function sessionStartMs(session) {
556
968
  function orderedLiveRunSessions(sessions) {
557
969
  return sessions.filter((session) => session.status !== "cancelled" && Number.isFinite(sessionStartMs(session))).sort((left, right) => sessionStartMs(left) - sessionStartMs(right));
558
970
  }
971
+ const PUBLIC_CONTENT_FRESHNESS_SECONDS = 3600;
972
+ function availability(transport) {
973
+ return {
974
+ kind: "live",
975
+ reason: "booking_correctness",
976
+ freshness: "availability",
977
+ transport
978
+ };
979
+ }
980
+ function content(tags, transport = "direct") {
981
+ return {
982
+ kind: "tagged",
983
+ tags,
984
+ freshness: "content",
985
+ transport
986
+ };
987
+ }
988
+ /** The single classification authority for cacheable public reads. */
989
+ const PUBLIC_READ_CACHE_POLICIES = {
990
+ listPublishedEntries: content(["published_content"]),
991
+ getPublishedEntryPreview: content(["published_content"]),
992
+ listPublicEvents: availability("direct"),
993
+ listPublicEventCalendarWindow: availability("direct"),
994
+ listPublicRecurringSchedule: availability("batch_only"),
995
+ getPublicEventDetails: availability("batch_only"),
996
+ resolveEventSubroute: availability("direct"),
997
+ listPublicRouteCandidates: content(["published_content"], "batch_only"),
998
+ listPublicTeamMembers: content(["public_team_members"]),
999
+ listPublicProducts: availability("direct"),
1000
+ listPublicPasses: availability("direct"),
1001
+ listPublicMemberships: availability("direct"),
1002
+ getPublicFormById: content(["site_forms"]),
1003
+ getPublicBookingServices: availability("direct"),
1004
+ getPublicBookingService: availability("direct"),
1005
+ getPublicBookingResourcesReference: availability("direct"),
1006
+ getPublicBookingAvailableDates: availability("direct"),
1007
+ getPublicBookingAvailableSlots: availability("direct"),
1008
+ getPublicWeeklySlotAvailability: availability("direct"),
1009
+ listPublicForms: content(["site_forms"]),
1010
+ checkRedirect: content([]),
1011
+ getPublicRoutableContent: content(["published_content"]),
1012
+ getPublicSitemapRoutes: content(["published_content"])
1013
+ };
1014
+ new Set(Object.keys(PUBLIC_READ_CACHE_POLICIES));
1015
+ function getPublicReadCachePolicy(endpoint) {
1016
+ return PUBLIC_READ_CACHE_POLICIES[endpoint];
1017
+ }
1018
+ function publicReadFreshnessSeconds(endpoint) {
1019
+ return getPublicReadCachePolicy(endpoint).freshness === "availability" ? 60 : PUBLIC_CONTENT_FRESHNESS_SECONDS;
1020
+ }
559
1021
  //#endregion
560
1022
  //#region ../core/src/event-series-behaviour.ts
561
1023
  const WHOLE_SERIES_EVENT_PRESET_VALUES = ["course", "term"];
@@ -851,7 +1313,7 @@ function resolveSiteVerticalBookingConfig(rawConfig) {
851
1313
  }
852
1314
  //#endregion
853
1315
  //#region ../media-core/src/typeGuards.ts
854
- function isRecord$12(value) {
1316
+ function isRecord$11(value) {
855
1317
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
856
1318
  }
857
1319
  //#endregion
@@ -969,8 +1431,8 @@ function walkAndCollectImageAttrs(value, out, location = "") {
969
1431
  value.forEach((item, index) => walkAndCollectImageAttrs(item, out, `${location}[${index}]`));
970
1432
  return;
971
1433
  }
972
- if (!isRecord$12(value)) return;
973
- if (value.type === "image" && isRecord$12(value.attrs)) out.push({
1434
+ if (!isRecord$11(value)) return;
1435
+ if (value.type === "image" && isRecord$11(value.attrs)) out.push({
974
1436
  attrs: value.attrs,
975
1437
  location: location ? `${location}.attrs` : "attrs"
976
1438
  });
@@ -2588,59 +3050,108 @@ function interpolateHex(startHex, endHex, position) {
2588
3050
  const channel = (from, to) => Math.round(from + (to - from) * position).toString(16).padStart(2, "0");
2589
3051
  return `#${channel(start.r, end.r)}${channel(start.g, end.g)}${channel(start.b, end.b)}`;
2590
3052
  }
2591
- shadeBackgroundEffect({
2592
- id: "darken-background",
2593
- name: "Darken on Hover",
2594
- description: "Darkens the background color on hover",
2595
- label: "Darken Amount (shade step)",
2596
- shadeDirection: 1
2597
- });
2598
- shadeBackgroundEffect({
2599
- id: "lighten-background",
2600
- name: "Lighten on Hover",
2601
- description: "Lightens the background color on hover",
2602
- label: "Lighten Amount (shade step)",
2603
- shadeDirection: -1
2604
- });
2605
- function shadeBackgroundEffect(config) {
2606
- return {
2607
- id: config.id,
2608
- name: config.name,
2609
- description: config.description,
2610
- category: "background",
2611
- pseudoElement: "none",
2612
- applicableTo: ["button"],
2613
- customizableOption: {
2614
- name: "amount",
2615
- type: "select",
2616
- label: config.label,
2617
- default: 100,
2618
- options: [
2619
- 0,
2620
- 100,
2621
- 200,
2622
- 300,
2623
- 400,
2624
- 500,
2625
- 600,
2626
- 700,
2627
- 800,
2628
- 900
2629
- ]
3053
+ //#endregion
3054
+ //#region ../theme-core/src/tokens/tokens.ts
3055
+ const defaultThemeTokens = {
3056
+ color: {
3057
+ "background/base": "#ffffff",
3058
+ "background/elevated": "#f5f5f5",
3059
+ "surface/base": "#ffffff",
3060
+ "surface/subtle": "#f9f9fb",
3061
+ "surface/inverted": "#111111",
3062
+ "content/primary": "#111111",
3063
+ "content/secondary": "#3f3f46",
3064
+ "accent/primary": "#2563eb",
3065
+ "accent/secondary": "#1d4ed8",
3066
+ "border/base": "#e5e7eb"
3067
+ },
3068
+ typography: {
3069
+ "display/hero": {
3070
+ fontSize: "clamp(48px, 8vw, 96px)",
3071
+ lineHeight: "1.05",
3072
+ fontWeight: "700"
2630
3073
  },
2631
- isApplicable: (buttonConfig) => buttonConfig.background.type === "solid",
2632
- generateCSS: ({ themeId, variantId, options, tokens, buttonConfig }) => {
2633
- if (buttonConfig.background.type !== "solid") return "";
2634
- const amount = (options.amount || 100) * config.shadeDirection;
2635
- const baseToken = buttonConfig.background.colorToken ?? "primary-500";
2636
- return `
2637
- :where([data-theme-scope="${themeId}"]) .${variantId}:hover {
2638
- background-color: ${tokens.getColor(tokens.adjustShade(baseToken, amount))};
2639
- }
2640
- `;
3074
+ "display/section": {
3075
+ fontSize: "clamp(40px, 6vw, 72px)",
3076
+ lineHeight: "1.1",
3077
+ fontWeight: "700"
3078
+ },
3079
+ "heading/large": {
3080
+ fontSize: "clamp(32px, 4vw, 48px)",
3081
+ lineHeight: "1.2",
3082
+ fontWeight: "600"
3083
+ },
3084
+ "heading/medium": {
3085
+ fontSize: "clamp(24px, 3vw, 32px)",
3086
+ lineHeight: "1.25",
3087
+ fontWeight: "600"
3088
+ },
3089
+ "heading/small": {
3090
+ fontSize: "20px",
3091
+ lineHeight: "1.3",
3092
+ fontWeight: "600"
3093
+ },
3094
+ "body/normal": {
3095
+ fontSize: "16px",
3096
+ lineHeight: "1.6",
3097
+ fontWeight: "400"
3098
+ },
3099
+ "body/small": {
3100
+ fontSize: "14px",
3101
+ lineHeight: "1.5",
3102
+ fontWeight: "400"
3103
+ },
3104
+ caption: {
3105
+ fontSize: "12px",
3106
+ lineHeight: "1.4",
3107
+ fontWeight: "500"
2641
3108
  }
2642
- };
2643
- }
3109
+ },
3110
+ spacing: {
3111
+ none: "0px",
3112
+ "3xs": "4px",
3113
+ "2xs": "8px",
3114
+ xs: "12px",
3115
+ sm: "16px",
3116
+ md: "24px",
3117
+ lg: "32px",
3118
+ xl: "40px",
3119
+ "2xl": "56px",
3120
+ "3xl": "72px"
3121
+ },
3122
+ radius: {
3123
+ none: "0px",
3124
+ xs: "2px",
3125
+ sm: "4px",
3126
+ md: "8px",
3127
+ lg: "12px",
3128
+ pill: "999px",
3129
+ full: "9999px"
3130
+ },
3131
+ shadow: {
3132
+ none: "none",
3133
+ soft: "0px 2px 8px rgba(15, 23, 42, 0.08)",
3134
+ medium: "0px 6px 18px rgba(15, 23, 42, 0.12)",
3135
+ strong: "0px 12px 36px rgba(15, 23, 42, 0.16)"
3136
+ },
3137
+ palette: {
3138
+ surface: "#ffffff",
3139
+ "neutral-50": "#f9fafb",
3140
+ "neutral-900": "#111827",
3141
+ primary: "#2563eb",
3142
+ "primary-50": "#eff6ff",
3143
+ "primary-500": "#2563eb",
3144
+ "primary-900": "#1d4ed8",
3145
+ secondary: "#9333ea",
3146
+ "secondary-50": "#f3e8ff",
3147
+ "secondary-500": "#9333ea",
3148
+ "secondary-900": "#4c1d95",
3149
+ accent: "#f97316",
3150
+ "accent-50": "#fff7ed",
3151
+ "accent-500": "#f97316",
3152
+ "accent-900": "#7c2d12"
3153
+ }
3154
+ };
2644
3155
  //#endregion
2645
3156
  //#region ../theme-core/src/palette/utils/opaqueSurfaceColor.ts
2646
3157
  /** Resolve an opaque colour, compositing alpha against an explicit underlay. */
@@ -2925,6 +3436,59 @@ function mergeStyles(...styles) {
2925
3436
  }
2926
3437
  return Object.keys(merged).length ? merged : void 0;
2927
3438
  }
3439
+ shadeBackgroundEffect({
3440
+ id: "darken-background",
3441
+ name: "Darken on Hover",
3442
+ description: "Darkens the background color on hover",
3443
+ label: "Darken Amount (shade step)",
3444
+ shadeDirection: 1
3445
+ });
3446
+ shadeBackgroundEffect({
3447
+ id: "lighten-background",
3448
+ name: "Lighten on Hover",
3449
+ description: "Lightens the background color on hover",
3450
+ label: "Lighten Amount (shade step)",
3451
+ shadeDirection: -1
3452
+ });
3453
+ function shadeBackgroundEffect(config) {
3454
+ return {
3455
+ id: config.id,
3456
+ name: config.name,
3457
+ description: config.description,
3458
+ category: "background",
3459
+ pseudoElement: "none",
3460
+ applicableTo: ["button"],
3461
+ customizableOption: {
3462
+ name: "amount",
3463
+ type: "select",
3464
+ label: config.label,
3465
+ default: 100,
3466
+ options: [
3467
+ 0,
3468
+ 100,
3469
+ 200,
3470
+ 300,
3471
+ 400,
3472
+ 500,
3473
+ 600,
3474
+ 700,
3475
+ 800,
3476
+ 900
3477
+ ]
3478
+ },
3479
+ isApplicable: (buttonConfig) => buttonConfig.background.type === "solid",
3480
+ generateCSS: ({ themeId, variantId, options, tokens, buttonConfig }) => {
3481
+ if (buttonConfig.background.type !== "solid") return "";
3482
+ const amount = (options.amount || 100) * config.shadeDirection;
3483
+ const baseToken = buttonConfig.background.colorToken ?? "primary-500";
3484
+ return `
3485
+ :where([data-theme-scope="${themeId}"]) .${variantId}:hover {
3486
+ background-color: ${tokens.getColor(tokens.adjustShade(baseToken, amount))};
3487
+ }
3488
+ `;
3489
+ }
3490
+ };
3491
+ }
2928
3492
  //#endregion
2929
3493
  //#region ../theme-core/src/utils/tokenOrColor.ts
2930
3494
  /**
@@ -6346,8 +6910,14 @@ const headerInteractionPillPaletteValues = [
6346
6910
  "accent"
6347
6911
  ];
6348
6912
  /**
6349
- * "No pill": the nav link keeps whatever hover treatment its recipe compiled,
6350
- * and the palette step writes nothing at all (#1318 Phase 4c decision 2).
6913
+ * "No pill": a colour change on hover rather than a filled background.
6914
+ *
6915
+ * The palette step writes nothing (#1318 Phase 4c decision 2), but on a
6916
+ * foreground-adaptive style that is not the end of the story: the hover colour
6917
+ * is derived from the resolved opening foreground at render time, paired with
6918
+ * the resting colour, so `quiet` resolves to a definite colour rather than to
6919
+ * whatever brand token the recipe happened to name. See
6920
+ * `applyOpeningForeground`.
6351
6921
  *
6352
6922
  * It exists because "a colour change on hover, no filled background" was not
6353
6923
  * expressible in the vocabulary, and it is what
@@ -6415,7 +6985,7 @@ const boxBackgroundSchema = z.discriminatedUnion("type", [
6415
6985
  })
6416
6986
  ]);
6417
6987
  function normalizeAuthoringOpacity(value) {
6418
- if (!isRecord$11(value)) return value;
6988
+ if (!isRecord$10(value)) return value;
6419
6989
  return {
6420
6990
  ...value,
6421
6991
  opacity: normalizeOpacity(value.opacity)
@@ -6424,7 +6994,7 @@ function normalizeAuthoringOpacity(value) {
6424
6994
  function normalizeOpacity(value) {
6425
6995
  return typeof value === "number" && value > 1 && value <= 100 ? value / 100 : value;
6426
6996
  }
6427
- function isRecord$11(value) {
6997
+ function isRecord$10(value) {
6428
6998
  return typeof value === "object" && value !== null && !Array.isArray(value);
6429
6999
  }
6430
7000
  //#endregion
@@ -7175,7 +7745,7 @@ const PUBLIC_DOWNLOAD_MEDIA_TYPES = [
7175
7745
  /**
7176
7746
  * Strict record guard: excludes null, primitives, and arrays.
7177
7747
  */
7178
- function isRecord$10(value) {
7748
+ function isRecord$9(value) {
7179
7749
  return typeof value === "object" && value !== null && !Array.isArray(value);
7180
7750
  }
7181
7751
  /**
@@ -7349,6 +7919,28 @@ const bookingRequirementConsentFieldSchema = z.object({
7349
7919
  z.union([blockBookingConsentSchema, bookingRequirementConsentFieldSchema]);
7350
7920
  //#endregion
7351
7921
  //#region ../blocks/src/system/blocks/events/shared/schemas.ts
7922
+ const publicEventLoaderQuerySchemaShape = {
7923
+ limit: z.string().optional(),
7924
+ from: z.string().optional(),
7925
+ to: z.string().optional(),
7926
+ afterStartsAt: z.string().optional(),
7927
+ afterId: z.string().optional(),
7928
+ categoryIds: z.string().optional(),
7929
+ venueId: z.string().optional(),
7930
+ staffMemberId: z.string().optional(),
7931
+ eventSurface: z.string().optional(),
7932
+ eventPresets: z.string().optional(),
7933
+ scheduleScope: z.string().optional(),
7934
+ seriesId: z.string().optional(),
7935
+ seriesIds: z.string().optional(),
7936
+ runSeriesId: z.string().optional(),
7937
+ seriesSlug: z.string().optional(),
7938
+ includeOccurrenceId: z.string().optional(),
7939
+ readIntent: z.string().optional(),
7940
+ detailLevel: z.string().optional(),
7941
+ readProfile: z.string().optional()
7942
+ };
7943
+ z.object(publicEventLoaderQuerySchemaShape);
7352
7944
  const eventPresetSchema = z.enum([
7353
7945
  "event",
7354
7946
  "class",
@@ -7807,6 +8399,14 @@ const calendarWindowPageSchema = z.discriminatedUnion("kind", [z.object({
7807
8399
  kind: z.literal("partial"),
7808
8400
  nextCursor: calendarSourceCursorSchema
7809
8401
  })]);
8402
+ //#endregion
8403
+ //#region ../api/src/apiEndpointTypes.ts
8404
+ function allowedDemoMutationPolicy() {
8405
+ return {
8406
+ classification: "allowed",
8407
+ publicMessage: ""
8408
+ };
8409
+ }
7810
8410
  function blockedDemoMutationPolicy(classification, publicMessage) {
7811
8411
  if (publicMessage.trim() === "") throw new Error(`Demo mutation policy ${classification} requires publicMessage.`);
7812
8412
  return {
@@ -7819,6 +8419,7 @@ function blockedDemoMutationPolicy(classification, publicMessage) {
7819
8419
  const DEMO_MUTATION_BLOCKED_HIDDEN = blockedDemoMutationPolicy("blocked-hidden", "This action is not available in demo sites.");
7820
8420
  const DEMO_MUTATION_BLOCKED_DISABLED = blockedDemoMutationPolicy("blocked-disabled", "This setting is disabled in demo sites.");
7821
8421
  blockedDemoMutationPolicy("internal-only", "This internal operation is not available in demo sites.");
8422
+ const DEMO_MUTATION_ALLOWED = allowedDemoMutationPolicy();
7822
8423
  //#endregion
7823
8424
  //#region ../api/src/cache-tags.ts
7824
8425
  /**
@@ -8750,14 +9351,117 @@ const NEWSLETTER_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
8750
9351
  responseKind: "json",
8751
9352
  errors: ["auth:forbidden", "server:internal_error"]
8752
9353
  },
8753
- getMailchimpSignupSyncHealth: {
8754
- path: "/sites/{siteId}/integrations/mailchimp/signup-sync-health",
9354
+ getMailingListSetup: {
9355
+ path: "/sites/{siteId}/mailing-list/setup",
9356
+ method: "GET",
9357
+ tags: [TAG_TEMPLATES.site, TAG_TEMPLATES.siteNewsletter],
9358
+ auth: "user",
9359
+ responseKind: "json",
9360
+ errors: ["auth:forbidden", "server:internal_error"]
9361
+ },
9362
+ getMailingListAuthoringContext: {
9363
+ path: "/sites/{siteId}/mailing-list/authoring-context",
9364
+ method: "GET",
9365
+ tags: [TAG_TEMPLATES.site, TAG_TEMPLATES.siteNewsletter],
9366
+ auth: "user",
9367
+ responseKind: "json",
9368
+ errors: ["auth:forbidden", "server:internal_error"]
9369
+ },
9370
+ previewMailingListSetupChange: {
9371
+ path: "/sites/{siteId}/mailing-list/setup/preview",
9372
+ method: "POST",
9373
+ tags: [TAG_TEMPLATES.site, TAG_TEMPLATES.siteNewsletter],
9374
+ auth: "user",
9375
+ responseKind: "json",
9376
+ demoMutation: DEMO_MUTATION_ALLOWED,
9377
+ errors: [
9378
+ "auth:forbidden",
9379
+ "validation:invalid_input",
9380
+ "server:internal_error"
9381
+ ]
9382
+ },
9383
+ applyMailingListSetupChange: {
9384
+ path: "/sites/{siteId}/mailing-list/setup",
9385
+ method: "PUT",
9386
+ tags: [TAG_TEMPLATES.site, TAG_TEMPLATES.siteNewsletter],
9387
+ auth: "user",
9388
+ responseKind: "json",
9389
+ demoMutation: DEMO_MUTATION_BLOCKED_DISABLED,
9390
+ errors: [
9391
+ "auth:forbidden",
9392
+ "validation:invalid_input",
9393
+ "resource:conflict",
9394
+ "server:internal_error"
9395
+ ]
9396
+ },
9397
+ getMailingListProviderCatalog: {
9398
+ path: "/sites/{siteId}/mailing-list/providers/{provider}/catalog",
9399
+ method: "GET",
9400
+ tags: [TAG_TEMPLATES.site, TAG_TEMPLATES.siteNewsletter],
9401
+ auth: "user",
9402
+ responseKind: "json",
9403
+ errors: [
9404
+ "auth:forbidden",
9405
+ "validation:invalid_input",
9406
+ "server:internal_error"
9407
+ ]
9408
+ },
9409
+ refreshMailingListProviderCatalog: {
9410
+ path: "/sites/{siteId}/mailing-list/providers/{provider}/catalog/refresh",
9411
+ method: "POST",
9412
+ tags: [TAG_TEMPLATES.site, TAG_TEMPLATES.siteNewsletter],
9413
+ auth: "user",
9414
+ responseKind: "json",
9415
+ demoMutation: DEMO_MUTATION_BLOCKED_DISABLED,
9416
+ errors: [
9417
+ "auth:forbidden",
9418
+ "validation:invalid_input",
9419
+ "server:internal_error"
9420
+ ]
9421
+ },
9422
+ getMailingListProviderHealth: {
9423
+ path: "/sites/{siteId}/mailing-list/health",
9424
+ method: "GET",
9425
+ tags: [TAG_TEMPLATES.site, TAG_TEMPLATES.siteNewsletter],
9426
+ auth: "user",
9427
+ responseKind: "json",
9428
+ errors: ["auth:forbidden", "server:internal_error"]
9429
+ },
9430
+ getBrevoConnection: {
9431
+ path: "/sites/{siteId}/integrations/brevo/connection",
8755
9432
  method: "GET",
8756
9433
  tags: [TAG_TEMPLATES.site],
8757
9434
  auth: "user",
8758
9435
  responseKind: "json",
8759
9436
  errors: ["auth:forbidden", "server:internal_error"]
8760
9437
  },
9438
+ connectBrevo: {
9439
+ path: "/sites/{siteId}/integrations/brevo/connection",
9440
+ method: "PUT",
9441
+ tags: [TAG_TEMPLATES.site],
9442
+ auth: "user",
9443
+ responseKind: "json",
9444
+ demoMutation: DEMO_MUTATION_BLOCKED_DISABLED,
9445
+ errors: [
9446
+ "auth:forbidden",
9447
+ "validation:invalid_input",
9448
+ "resource:conflict",
9449
+ "server:internal_error"
9450
+ ]
9451
+ },
9452
+ disconnectBrevo: {
9453
+ path: "/sites/{siteId}/integrations/brevo/disconnect",
9454
+ method: "POST",
9455
+ tags: [TAG_TEMPLATES.site],
9456
+ auth: "user",
9457
+ responseKind: "json",
9458
+ demoMutation: DEMO_MUTATION_BLOCKED_DISABLED,
9459
+ errors: [
9460
+ "auth:forbidden",
9461
+ "resource:conflict",
9462
+ "server:internal_error"
9463
+ ]
9464
+ },
8761
9465
  getMailchimpConnection: {
8762
9466
  path: "/sites/{siteId}/integrations/mailchimp/connection",
8763
9467
  method: "GET",
@@ -9013,7 +9717,7 @@ const PUBLIC_EVENT_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
9013
9717
  resolveEventSubroute: {
9014
9718
  path: "/public/sites/{siteId}/events/subroutes/resolve",
9015
9719
  method: "GET",
9016
- revalidate: 60,
9720
+ revalidate: publicReadFreshnessSeconds("resolveEventSubroute"),
9017
9721
  tags: [TAG_TEMPLATES.publicEvents, "event-subroute"],
9018
9722
  auth: "public",
9019
9723
  responseKind: "json",
@@ -9066,7 +9770,7 @@ const PUBLIC_BOOKING_AVAILABILITY_ENDPOINT_DEFINITIONS = defineEndpointDefinitio
9066
9770
  getPublicBookingServices: {
9067
9771
  path: "/public/bookings/services",
9068
9772
  method: "GET",
9069
- revalidate: 60,
9773
+ revalidate: publicReadFreshnessSeconds("getPublicBookingServices"),
9070
9774
  tags: [TAG_TEMPLATES.publicBookingServices],
9071
9775
  auth: "public",
9072
9776
  responseKind: "json"
@@ -9074,7 +9778,15 @@ const PUBLIC_BOOKING_AVAILABILITY_ENDPOINT_DEFINITIONS = defineEndpointDefinitio
9074
9778
  getPublicBookingService: {
9075
9779
  path: "/public/bookings/services/{serviceId}",
9076
9780
  method: "GET",
9077
- revalidate: 60,
9781
+ revalidate: publicReadFreshnessSeconds("getPublicBookingService"),
9782
+ tags: [TAG_TEMPLATES.publicBookingServices],
9783
+ auth: "public",
9784
+ responseKind: "json"
9785
+ },
9786
+ getPublicBookingServiceBySlug: {
9787
+ path: "/public/bookings/services/by-slug/{slug}",
9788
+ method: "GET",
9789
+ revalidate: publicReadFreshnessSeconds("getPublicBookingService"),
9078
9790
  tags: [TAG_TEMPLATES.publicBookingServices],
9079
9791
  auth: "public",
9080
9792
  responseKind: "json"
@@ -9082,7 +9794,7 @@ const PUBLIC_BOOKING_AVAILABILITY_ENDPOINT_DEFINITIONS = defineEndpointDefinitio
9082
9794
  getPublicBookingResourcesReference: {
9083
9795
  path: "/public/bookings/resources/reference",
9084
9796
  method: "GET",
9085
- revalidate: 60,
9797
+ revalidate: publicReadFreshnessSeconds("getPublicBookingResourcesReference"),
9086
9798
  tags: [TAG_TEMPLATES.publicBookingServices],
9087
9799
  auth: "public",
9088
9800
  responseKind: "json"
@@ -9090,7 +9802,7 @@ const PUBLIC_BOOKING_AVAILABILITY_ENDPOINT_DEFINITIONS = defineEndpointDefinitio
9090
9802
  getPublicBookingAvailableDates: {
9091
9803
  path: "/public/bookings/availability/dates",
9092
9804
  method: "GET",
9093
- revalidate: 60,
9805
+ revalidate: publicReadFreshnessSeconds("getPublicBookingAvailableDates"),
9094
9806
  tags: [TAG_TEMPLATES.publicBookingAvailability, TAG_TEMPLATES.publicBookingServices],
9095
9807
  auth: "public",
9096
9808
  responseKind: "json"
@@ -9098,7 +9810,7 @@ const PUBLIC_BOOKING_AVAILABILITY_ENDPOINT_DEFINITIONS = defineEndpointDefinitio
9098
9810
  getPublicBookingAvailableSlots: {
9099
9811
  path: "/public/bookings/availability/slots",
9100
9812
  method: "GET",
9101
- revalidate: 60,
9813
+ revalidate: publicReadFreshnessSeconds("getPublicBookingAvailableSlots"),
9102
9814
  tags: [TAG_TEMPLATES.publicBookingAvailability, TAG_TEMPLATES.publicBookingServices],
9103
9815
  auth: "public",
9104
9816
  responseKind: "json"
@@ -9106,7 +9818,7 @@ const PUBLIC_BOOKING_AVAILABILITY_ENDPOINT_DEFINITIONS = defineEndpointDefinitio
9106
9818
  getPublicWeeklySlotAvailability: {
9107
9819
  path: "/public/bookings/weekly-slot-availability",
9108
9820
  method: "GET",
9109
- revalidate: 60,
9821
+ revalidate: publicReadFreshnessSeconds("getPublicWeeklySlotAvailability"),
9110
9822
  tags: [TAG_TEMPLATES.publicBookingAvailability, TAG_TEMPLATES.publicBookingServices],
9111
9823
  auth: "public",
9112
9824
  responseKind: "json",
@@ -9556,15 +10268,185 @@ const SDK_MEDIA_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
9556
10268
  responseKind: "json"
9557
10269
  }
9558
10270
  });
10271
+ //#endregion
10272
+ //#region ../api/src/publicReadEndpointDefinitions.ts
10273
+ /**
10274
+ * Direct public reads governed by the canonical public-read freshness policy.
10275
+ * Keeping these definitions together makes the endpoint identity used to
10276
+ * derive freshness reviewable beside its route and tags.
10277
+ */
10278
+ const PUBLIC_READ_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
10279
+ getPublishedEntryPreview: {
10280
+ path: "/public/content/{siteId}/{type}/{slug}/preview",
10281
+ method: "GET",
10282
+ revalidate: publicReadFreshnessSeconds("getPublishedEntryPreview"),
10283
+ tags: ["content-{siteId}-{type}-{slug}"],
10284
+ auth: "public",
10285
+ responseKind: "json"
10286
+ },
10287
+ listPublishedEntries: {
10288
+ path: "/public/content/{siteId}/{type}/entries",
10289
+ method: "GET",
10290
+ revalidate: publicReadFreshnessSeconds("listPublishedEntries"),
10291
+ tags: ["content-{siteId}-{type}"],
10292
+ auth: "public",
10293
+ responseKind: "json"
10294
+ },
10295
+ getPublicFormById: {
10296
+ path: "/public/forms/{formId}",
10297
+ method: "GET",
10298
+ revalidate: publicReadFreshnessSeconds("getPublicFormById"),
10299
+ tags: [TAG_TEMPLATES.formById],
10300
+ auth: "public",
10301
+ responseKind: "json"
10302
+ },
10303
+ listPublicEvents: {
10304
+ path: "/public/sites/{siteId}/events",
10305
+ method: "GET",
10306
+ revalidate: publicReadFreshnessSeconds("listPublicEvents"),
10307
+ tags: [TAG_TEMPLATES.publicEvents],
10308
+ auth: "public",
10309
+ responseKind: "json"
10310
+ },
10311
+ listPublicTeamMembers: {
10312
+ path: "/public/sites/{siteId}/team-members",
10313
+ method: "GET",
10314
+ revalidate: publicReadFreshnessSeconds("listPublicTeamMembers"),
10315
+ tags: [TAG_TEMPLATES.publicTeamMembers],
10316
+ errors: [],
10317
+ auth: "public",
10318
+ responseKind: "json"
10319
+ },
10320
+ listPublicPasses: {
10321
+ path: "/public/sites/{siteId}/bookings/products/passes",
10322
+ method: "GET",
10323
+ revalidate: publicReadFreshnessSeconds("listPublicPasses"),
10324
+ tags: [TAG_TEMPLATES.publicPasses],
10325
+ auth: "public",
10326
+ responseKind: "json"
10327
+ },
10328
+ listPublicMemberships: {
10329
+ path: "/public/sites/{siteId}/bookings/products/memberships",
10330
+ method: "GET",
10331
+ revalidate: publicReadFreshnessSeconds("listPublicMemberships"),
10332
+ tags: [TAG_TEMPLATES.publicMemberships],
10333
+ auth: "public",
10334
+ responseKind: "json"
10335
+ },
10336
+ listPublicProducts: {
10337
+ path: "/public/sites/{siteId}/products",
10338
+ method: "GET",
10339
+ revalidate: publicReadFreshnessSeconds("listPublicProducts"),
10340
+ tags: [TAG_TEMPLATES.publicProducts],
10341
+ errors: [],
10342
+ auth: "public",
10343
+ responseKind: "json"
10344
+ }
10345
+ });
10346
+ //#endregion
10347
+ //#region ../api/src/publicOnboardingAttemptEndpointDefinitions.ts
10348
+ /**
10349
+ * The anonymous onboarding attempt, addressed by its opaque resume token.
10350
+ *
10351
+ * Every route here is reached before there is an account, so none of them can
10352
+ * be scoped to a site or a user: the token is the whole credential. They are
10353
+ * kept together so that stays obvious.
10354
+ */
10355
+ const PUBLIC_ONBOARDING_ATTEMPT_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
10356
+ createPublicOnboardingAttempt: {
10357
+ path: "/public/onboarding/attempts",
10358
+ method: "POST",
10359
+ auth: "public",
10360
+ errors: [],
10361
+ responseKind: "json"
10362
+ },
10363
+ createPublicOnboardingLogoUploadUrl: {
10364
+ path: "/public/onboarding/attempts/{attemptToken}/logo-upload-url",
10365
+ method: "POST",
10366
+ auth: "public",
10367
+ errors: [],
10368
+ responseKind: "json"
10369
+ },
10370
+ uploadPublicOnboardingLogo: {
10371
+ path: "/public/onboarding/attempts/{attemptToken}/logo",
10372
+ method: "POST",
10373
+ auth: "public",
10374
+ errors: [],
10375
+ responseKind: "json"
10376
+ },
10377
+ getPublicOnboardingAttempt: {
10378
+ path: "/public/onboarding/attempts/{attemptToken}",
10379
+ method: "GET",
10380
+ auth: "public",
10381
+ errors: [],
10382
+ responseKind: "json"
10383
+ },
10384
+ getPublicOnboardingAttemptProgress: {
10385
+ path: "/public/onboarding/attempts/{attemptToken}/status",
10386
+ method: "GET",
10387
+ auth: "public",
10388
+ errors: [],
10389
+ responseKind: "json"
10390
+ },
10391
+ updatePublicOnboardingAttempt: {
10392
+ path: "/public/onboarding/attempts/{attemptToken}",
10393
+ method: "PATCH",
10394
+ auth: "public",
10395
+ errors: [],
10396
+ responseKind: "json"
10397
+ },
10398
+ runPublicOnboardingAttempt: {
10399
+ path: "/public/onboarding/attempts/{attemptToken}/run",
10400
+ method: "POST",
10401
+ auth: "public",
10402
+ errors: [],
10403
+ responseKind: "json"
10404
+ },
10405
+ resendPublicOnboardingAttemptConfirmation: {
10406
+ path: "/public/onboarding/attempts/{attemptToken}/resend-confirmation",
10407
+ method: "POST",
10408
+ auth: "public",
10409
+ errors: [],
10410
+ responseKind: "json"
10411
+ }
10412
+ });
10413
+ //#endregion
10414
+ //#region ../api/src/billingEndpointDefinitions.ts
10415
+ const BILLING_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
10416
+ adminChangePlan: {
10417
+ path: "/admin/billing/plan",
10418
+ method: "POST",
10419
+ tags: ["admin", "billing"],
10420
+ auth: "admin",
10421
+ responseKind: "json"
10422
+ },
10423
+ changePlan: {
10424
+ path: "/billing/plan/change",
10425
+ method: "POST",
10426
+ tags: ["billing"],
10427
+ auth: "user",
10428
+ responseKind: "json"
10429
+ },
10430
+ createBillingPortalSession: {
10431
+ path: "/billing/portal/session",
10432
+ method: "POST",
10433
+ tags: ["billing"],
10434
+ auth: "user",
10435
+ responseKind: "json"
10436
+ }
10437
+ });
9559
10438
  ({
9560
10439
  ...ACCOUNT_ENDPOINT_DEFINITIONS,
10440
+ ...PUBLIC_ONBOARDING_ATTEMPT_ENDPOINT_DEFINITIONS,
9561
10441
  ...PUBLIC_EVENT_ENDPOINT_DEFINITIONS,
9562
- ...GIFTING_ENDPOINT_DEFINITIONS
10442
+ ...GIFTING_ENDPOINT_DEFINITIONS,
10443
+ ...PUBLIC_READ_ENDPOINT_DEFINITIONS,
10444
+ ...BILLING_ENDPOINT_DEFINITIONS
9563
10445
  }), 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, {
9564
10446
  ...NEWSLETTER_ENDPOINT_DEFINITIONS,
9565
10447
  ...APPOINTMENT_ENDPOINT_DEFINITIONS,
9566
10448
  ...EVENT_SERIES_REGISTRATION_ENDPOINT_DEFINITIONS
9567
- }, 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.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.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.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.formById, TAG_TEMPLATES.siteForms, { ...PUBLIC_BOOKING_AVAILABILITY_ENDPOINT_DEFINITIONS }, TAG_TEMPLATES.publicEvents, TAG_TEMPLATES.publicEventFilters, TAG_TEMPLATES.publicTeamMembers, TAG_TEMPLATES.publicEvents, TAG_TEMPLATES.publicPasses, TAG_TEMPLATES.publicMemberships, TAG_TEMPLATES.publicProducts, TAG_TEMPLATES.publicShop, TAG_TEMPLATES.publicCheckout, TAG_TEMPLATES.siteRoutableContent, { ...PUBLIC_EVENT_CHECKOUT_ENDPOINT_DEFINITIONS }, TAG_TEMPLATES.publicEvents, TAG_TEMPLATES.publicEvents, { ...EVENT_MANAGEMENT_ENDPOINT_DEFINITIONS }, { ...SDK_MEDIA_ENDPOINT_DEFINITIONS }, { ...SDK_ENDPOINT_DEFINITIONS }, { ...SDK_ENTRY_READ_ENDPOINTS };
10449
+ }, 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 }, { ...SDK_MEDIA_ENDPOINT_DEFINITIONS }, { ...SDK_ENDPOINT_DEFINITIONS }, { ...SDK_ENTRY_READ_ENDPOINTS };
9568
10450
  z.object({ refreshToken: z.string().min(1).max(4096) }).strict();
9569
10451
  z.object({
9570
10452
  accessToken: z.string().min(1).max(4096),
@@ -11833,108 +12715,6 @@ function assertUniqueLayoutProfileKeys(profiles) {
11833
12715
  if (duplicates.length > 0) throw new Error(`Duplicate block layout design profiles: ${duplicates.join(", ")}`);
11834
12716
  }
11835
12717
  //#endregion
11836
- //#region ../theme-core/src/tokens/tokens.ts
11837
- const defaultThemeTokens = {
11838
- color: {
11839
- "background/base": "#ffffff",
11840
- "background/elevated": "#f5f5f5",
11841
- "surface/base": "#ffffff",
11842
- "surface/subtle": "#f9f9fb",
11843
- "surface/inverted": "#111111",
11844
- "content/primary": "#111111",
11845
- "content/secondary": "#3f3f46",
11846
- "accent/primary": "#2563eb",
11847
- "accent/secondary": "#1d4ed8",
11848
- "border/base": "#e5e7eb"
11849
- },
11850
- typography: {
11851
- "display/hero": {
11852
- fontSize: "clamp(48px, 8vw, 96px)",
11853
- lineHeight: "1.05",
11854
- fontWeight: "700"
11855
- },
11856
- "display/section": {
11857
- fontSize: "clamp(40px, 6vw, 72px)",
11858
- lineHeight: "1.1",
11859
- fontWeight: "700"
11860
- },
11861
- "heading/large": {
11862
- fontSize: "clamp(32px, 4vw, 48px)",
11863
- lineHeight: "1.2",
11864
- fontWeight: "600"
11865
- },
11866
- "heading/medium": {
11867
- fontSize: "clamp(24px, 3vw, 32px)",
11868
- lineHeight: "1.25",
11869
- fontWeight: "600"
11870
- },
11871
- "heading/small": {
11872
- fontSize: "20px",
11873
- lineHeight: "1.3",
11874
- fontWeight: "600"
11875
- },
11876
- "body/normal": {
11877
- fontSize: "16px",
11878
- lineHeight: "1.6",
11879
- fontWeight: "400"
11880
- },
11881
- "body/small": {
11882
- fontSize: "14px",
11883
- lineHeight: "1.5",
11884
- fontWeight: "400"
11885
- },
11886
- caption: {
11887
- fontSize: "12px",
11888
- lineHeight: "1.4",
11889
- fontWeight: "500"
11890
- }
11891
- },
11892
- spacing: {
11893
- none: "0px",
11894
- "3xs": "4px",
11895
- "2xs": "8px",
11896
- xs: "12px",
11897
- sm: "16px",
11898
- md: "24px",
11899
- lg: "32px",
11900
- xl: "40px",
11901
- "2xl": "56px",
11902
- "3xl": "72px"
11903
- },
11904
- radius: {
11905
- none: "0px",
11906
- xs: "2px",
11907
- sm: "4px",
11908
- md: "8px",
11909
- lg: "12px",
11910
- pill: "999px",
11911
- full: "9999px"
11912
- },
11913
- shadow: {
11914
- none: "none",
11915
- soft: "0px 2px 8px rgba(15, 23, 42, 0.08)",
11916
- medium: "0px 6px 18px rgba(15, 23, 42, 0.12)",
11917
- strong: "0px 12px 36px rgba(15, 23, 42, 0.16)"
11918
- },
11919
- palette: {
11920
- surface: "#ffffff",
11921
- "neutral-50": "#f9fafb",
11922
- "neutral-900": "#111827",
11923
- primary: "#2563eb",
11924
- "primary-50": "#eff6ff",
11925
- "primary-500": "#2563eb",
11926
- "primary-900": "#1d4ed8",
11927
- secondary: "#9333ea",
11928
- "secondary-50": "#f3e8ff",
11929
- "secondary-500": "#9333ea",
11930
- "secondary-900": "#4c1d95",
11931
- accent: "#f97316",
11932
- "accent-50": "#fff7ed",
11933
- "accent-500": "#f97316",
11934
- "accent-900": "#7c2d12"
11935
- }
11936
- };
11937
- //#endregion
11938
12718
  //#region ../theme-core/src/site-styles/backgroundAppearance.ts
11939
12719
  const backgroundAppearanceQuickColorTokenNames = [
11940
12720
  "background",
@@ -17664,7 +18444,7 @@ function isSemanticIconId(value) {
17664
18444
  //#endregion
17665
18445
  //#region ../blocks/src/system/icons/value.ts
17666
18446
  const NO_BLOCK_ICON_VALUE = { kind: "none" };
17667
- function isRecord$9(value) {
18447
+ function isRecord$8(value) {
17668
18448
  return typeof value === "object" && value !== null && !Array.isArray(value);
17669
18449
  }
17670
18450
  function parseBlockIconValue(value) {
@@ -17672,7 +18452,7 @@ function parseBlockIconValue(value) {
17672
18452
  kind: "semantic",
17673
18453
  iconId: value
17674
18454
  };
17675
- if (!isRecord$9(value)) return NO_BLOCK_ICON_VALUE;
18455
+ if (!isRecord$8(value)) return NO_BLOCK_ICON_VALUE;
17676
18456
  switch (value.kind) {
17677
18457
  case "none": return NO_BLOCK_ICON_VALUE;
17678
18458
  case "semantic": return isSemanticIconId(value.iconId) ? {
@@ -23134,102 +23914,31 @@ const newsletterFormFragment = defineFragment({
23134
23914
  description: "Newsletter subscription form with preset field configurations.",
23135
23915
  fields: [
23136
23916
  {
23137
- id: "destinationProvider",
23138
- type: "select",
23139
- label: "Send signups to",
23140
- description: "Choose where new subscribers from this form should go.",
23141
- defaultValue: "riverbank",
23142
- required: false,
23143
- ui: { intent: "behavior" },
23144
- options: [{
23145
- value: "riverbank",
23146
- label: "Riverbank newsletter"
23147
- }]
23148
- },
23149
- {
23150
- id: "listId",
23151
- type: "reference",
23152
- label: "Newsletter list",
23153
- description: "Select the list new subscribers should be added to.",
23154
- required: false,
23155
- referenceKind: "newsletterList",
23156
- allowManualEntry: false,
23157
- ui: {
23158
- intent: "behavior",
23159
- visibleWhen: {
23160
- field: "destinationProvider",
23161
- equals: "riverbank"
23162
- }
23163
- }
23164
- },
23165
- {
23166
- id: "mailchimpAudienceId",
23167
- type: "reference",
23168
- label: "Mailchimp audience",
23169
- description: "Choose the Mailchimp audience for new subscribers.",
23170
- required: false,
23171
- referenceKind: "mailchimpAudience",
23172
- allowManualEntry: false,
23173
- ui: {
23174
- intent: "behavior",
23175
- visibleWhen: {
23176
- field: "destinationProvider",
23177
- equals: "mailchimp"
23178
- }
23179
- }
23180
- },
23181
- {
23182
- id: "mailchimpTags",
23183
- type: "text",
23184
- label: "Mailchimp tags",
23185
- description: "Optional tags to apply in Mailchimp, separated by commas or semicolons.",
23917
+ id: "targeting",
23918
+ type: "group",
23919
+ label: "Mailing-list targeting",
23920
+ description: "Choose what kind of emails people signing up here will receive.",
23921
+ defaultValue: { mode: "default" },
23922
+ required: true,
23186
23923
  ui: {
23187
23924
  intent: "behavior",
23188
- visibleWhen: {
23189
- field: "destinationProvider",
23190
- equals: "mailchimp"
23191
- }
23192
- }
23193
- },
23194
- {
23195
- id: "preset",
23196
- type: "select",
23197
- label: "Form fields",
23198
- description: "Choose which fields to collect.",
23199
- defaultValue: "emailOnly",
23200
- ui: { intent: "display" },
23201
- options: [
23202
- {
23203
- value: "emailOnly",
23204
- label: "Email only"
23205
- },
23206
- {
23207
- value: "emailName",
23208
- label: "Email + Name"
23209
- },
23210
- {
23211
- value: "emailFirstLast",
23212
- label: "Email + First/Last Name"
23213
- },
23214
- {
23215
- value: "emailNameCompany",
23216
- label: "Email + Name + Company (B2B)"
23217
- }
23218
- ]
23219
- },
23220
- {
23221
- id: "includePhone",
23222
- type: "boolean",
23223
- label: "Include phone field (optional)",
23224
- description: "Adds an optional phone field to the selected preset (never required).",
23225
- defaultValue: false,
23226
- ui: { intent: "display" }
23227
- },
23228
- {
23229
- id: "buttonLabel",
23230
- type: "text",
23231
- label: "Button label",
23232
- defaultValue: "Subscribe"
23925
+ widget: "mailingListTargeting"
23926
+ },
23927
+ schema: { fields: [{
23928
+ id: "mode",
23929
+ type: "select",
23930
+ label: "Mode",
23931
+ required: true,
23932
+ defaultValue: "default",
23933
+ options: [{
23934
+ value: "default",
23935
+ label: "Default"
23936
+ }, {
23937
+ value: "custom",
23938
+ label: "Custom"
23939
+ }],
23940
+ ui: { hidden: true }
23941
+ }] }
23233
23942
  },
23234
23943
  createButtonVariantField({
23235
23944
  id: "buttonVariant",
@@ -23237,46 +23946,42 @@ const newsletterFormFragment = defineFragment({
23237
23946
  defaultValue: "primary"
23238
23947
  }),
23239
23948
  {
23240
- id: "successMessage",
23241
- type: "text",
23242
- label: "Success message",
23243
- description: "Shown after successful subscription.",
23244
- defaultValue: "Thanks for subscribing!"
23245
- },
23246
- {
23247
- id: "privacyNote",
23949
+ id: "mailingListSource",
23248
23950
  type: "text",
23249
- label: "Privacy note",
23250
- description: "Optional small text below the form (e.g., privacy policy link)."
23951
+ label: "Mailing-list source",
23952
+ ui: {
23953
+ hidden: true,
23954
+ intent: "behavior"
23955
+ }
23251
23956
  },
23252
23957
  {
23253
- id: "tags",
23958
+ id: "mailingListSourceToken",
23254
23959
  type: "text",
23255
- label: "Tags (optional)",
23256
- description: "Optional tags to apply on subscribe (comma or semicolon separated).",
23960
+ label: "Mailing-list source token",
23257
23961
  ui: {
23258
- intent: "behavior",
23259
- visibleWhen: {
23260
- field: "destinationProvider",
23261
- equals: "riverbank"
23262
- }
23962
+ hidden: true,
23963
+ intent: "behavior"
23263
23964
  }
23264
23965
  }
23265
23966
  ],
23266
23967
  layout: [el("newsletter-form", withApiBindings({
23267
- source: "block",
23268
- destinationProvider: { $bind: { from: "destinationProvider" } },
23269
- listId: { $bind: { from: "listId" } },
23270
- preset: { $bind: { from: "preset" } },
23271
- includePhone: { $bind: { from: "includePhone" } },
23272
- buttonLabel: { $bind: { from: "buttonLabel" } },
23968
+ source: { $bind: {
23969
+ from: "mailingListSource",
23970
+ fallback: "block"
23971
+ } },
23972
+ sourceRef: {
23973
+ tag: "signed_source_ref",
23974
+ token: { $bind: { from: "mailingListSourceToken" } }
23975
+ },
23976
+ targeting: { $bind: {
23977
+ from: "targeting",
23978
+ fallback: { mode: "default" }
23979
+ } },
23980
+ mailingList: { $bind: { from: "$root.mailingList" } },
23273
23981
  buttonVariant: { $bind: {
23274
23982
  from: "buttonVariant",
23275
23983
  fallback: "primary"
23276
23984
  } },
23277
- successMessage: { $bind: { from: "successMessage" } },
23278
- privacyNote: { $bind: { from: "privacyNote" } },
23279
- tags: { $bind: { from: "tags" } },
23280
23985
  spamProtectionEnabled: { $bind: { from: "$root.spamProtectionEnabled" } }
23281
23986
  }), [])]
23282
23987
  });
@@ -25451,14 +26156,19 @@ const contactNewsletterLayout = styledSection({
25451
26156
  as: "h2",
25452
26157
  className: "newsletter-copy-title"
25453
26158
  }, when("newsletterTitle"), bind("newsletterTitle")), richText({ className: "newsletter-copy-subtitle rb-prose rb-max-w-none" }, when("newsletterSubtitle"), bind("newsletterSubtitle"))]), el("newsletter-form", withApiBindings({
25454
- source: "block",
25455
- listId: { $bind: { from: "listId" } },
25456
- preset: { $bind: { from: "preset" } },
25457
- includePhone: { $bind: { from: "includePhone" } },
25458
- buttonLabel: { $bind: { from: "newsletterButtonLabel" } },
25459
- successMessage: { $bind: { from: "newsletterSuccessMessage" } },
25460
- privacyNote: { $bind: { from: "newsletterPrivacyNote" } },
25461
- tags: { $bind: { from: "newsletterTags" } },
26159
+ source: { $bind: {
26160
+ from: "mailingListSource",
26161
+ fallback: "block"
26162
+ } },
26163
+ sourceRef: {
26164
+ tag: "signed_source_ref",
26165
+ token: { $bind: { from: "mailingListSourceToken" } }
26166
+ },
26167
+ targeting: { $bind: {
26168
+ from: "targeting",
26169
+ fallback: { mode: "default" }
26170
+ } },
26171
+ mailingList: { $bind: { from: "$root.mailingList" } },
25462
26172
  spamProtectionEnabled: { $bind: { from: "$root.spamProtectionEnabled" } }
25463
26173
  }), [])])])], { className: "contact-newsletter-container" }),
25464
26174
  baseClass: "",
@@ -25494,79 +26204,55 @@ const contactNewsletterBlockDefinition = {
25494
26204
  label: "Newsletter intro"
25495
26205
  },
25496
26206
  {
25497
- id: "listId",
25498
- type: "reference",
25499
- label: "Newsletter list",
25500
- description: "Select the list new subscribers should be added to.",
26207
+ id: "targeting",
26208
+ type: "group",
26209
+ label: "Mailing-list targeting",
26210
+ description: "Choose what kind of emails people signing up here will receive.",
25501
26211
  required: true,
25502
- referenceKind: "newsletterList",
25503
- allowManualEntry: false,
25504
- ui: { intent: "behavior" }
25505
- },
25506
- {
25507
- id: "preset",
25508
- type: "select",
25509
- label: "Newsletter fields",
25510
- defaultValue: "emailOnly",
25511
- ui: { intent: "display" },
25512
- options: [
25513
- {
25514
- value: "emailOnly",
25515
- label: "Email only"
25516
- },
25517
- {
25518
- value: "emailName",
25519
- label: "Email + Name"
25520
- },
25521
- {
25522
- value: "emailFirstLast",
25523
- label: "Email + First/Last Name"
25524
- },
25525
- {
25526
- value: "emailNameCompany",
25527
- label: "Email + Name + Company (B2B)"
25528
- }
25529
- ]
25530
- },
25531
- {
25532
- id: "includePhone",
25533
- type: "boolean",
25534
- label: "Include phone field",
25535
- defaultValue: false,
25536
- ui: { intent: "display" }
25537
- },
25538
- {
25539
- id: "newsletterButtonLabel",
25540
- type: "text",
25541
- label: "Newsletter button label",
25542
- defaultValue: "Subscribe",
25543
- ui: { intent: "display" }
25544
- },
25545
- {
25546
- id: "newsletterSuccessMessage",
25547
- type: "text",
25548
- label: "Newsletter success message",
25549
- defaultValue: "Thanks for subscribing!",
25550
- ui: { intent: "behavior" }
26212
+ defaultValue: { mode: "default" },
26213
+ ui: {
26214
+ intent: "behavior",
26215
+ widget: "mailingListTargeting"
26216
+ },
26217
+ schema: { fields: [{
26218
+ id: "mode",
26219
+ type: "select",
26220
+ label: "Mode",
26221
+ required: true,
26222
+ defaultValue: "default",
26223
+ options: [{
26224
+ value: "default",
26225
+ label: "Default"
26226
+ }, {
26227
+ value: "custom",
26228
+ label: "Custom"
26229
+ }],
26230
+ ui: { hidden: true }
26231
+ }] }
25551
26232
  },
25552
26233
  {
25553
- id: "newsletterPrivacyNote",
26234
+ id: "contactTitle",
25554
26235
  type: "text",
25555
- label: "Privacy note",
25556
- ui: { intent: "display" }
26236
+ label: "Contact title",
26237
+ defaultValue: "Get in touch"
25557
26238
  },
25558
26239
  {
25559
- id: "newsletterTags",
26240
+ id: "mailingListSource",
25560
26241
  type: "text",
25561
- label: "Newsletter tags",
25562
- description: "Optional tags to apply on subscribe, separated by comma or semicolon.",
25563
- ui: { intent: "behavior" }
26242
+ label: "Mailing-list source",
26243
+ ui: {
26244
+ hidden: true,
26245
+ intent: "behavior"
26246
+ }
25564
26247
  },
25565
26248
  {
25566
- id: "contactTitle",
26249
+ id: "mailingListSourceToken",
25567
26250
  type: "text",
25568
- label: "Contact title",
25569
- defaultValue: "Get in touch"
26251
+ label: "Mailing-list source token",
26252
+ ui: {
26253
+ hidden: true,
26254
+ intent: "behavior"
26255
+ }
25570
26256
  },
25571
26257
  {
25572
26258
  id: "contactIntro",
@@ -25767,6 +26453,12 @@ const arrayLengthTransform = {
25767
26453
  summary: "Get the length of an array",
25768
26454
  run: (value) => Array.isArray(value) ? value.length : 0
25769
26455
  };
26456
+ const booleanNotTransform = {
26457
+ id: "boolean.not",
26458
+ kind: "formatter",
26459
+ summary: "Invert a boolean value; fail closed to false for other inputs",
26460
+ run: (value) => typeof value === "boolean" ? !value : false
26461
+ };
25770
26462
  const jsonArrayTransform = {
25771
26463
  id: "value.jsonArray",
25772
26464
  kind: "formatter",
@@ -25817,33 +26509,51 @@ const marqueeLoopTransform = {
25817
26509
  function toUnknownArray(value) {
25818
26510
  return Array.isArray(value) ? value : [];
25819
26511
  }
26512
+ /**
26513
+ * Map a content state/enum to a theme token colour — the first-class way to turn
26514
+ * a value like a class's availability (`available`/`filling`/`waitlist`), a
26515
+ * card's featured flag, or a pricing tier level into a themed colour. Authors
26516
+ * write role names and get `rgb(var(--tb-<role>))`, so the result live-recolours
26517
+ * with the theme and drops directly into a `style` binding (e.g.
26518
+ * `borderLeftColor`). Returns `undefined` when the value matches no case and no
26519
+ * fallback is given, so the style property is simply omitted.
26520
+ */
26521
+ const mapTokenTransform = {
26522
+ id: "value.mapToken",
26523
+ kind: "formatter",
26524
+ summary: "Map a state/enum value to a theme token colour (rgb(var(--tb-<role>)))",
26525
+ schema: z.object({
26526
+ /**
26527
+ * Maps an input state/enum value (stringified) to a theme token ROLE name
26528
+ * (e.g. `secondary`, `accent`, `muted`, `border`). The role is wrapped to
26529
+ * `rgb(var(--tb-<role>))` so the result drops straight into a `style` binding.
26530
+ */
26531
+ cases: z.record(z.string(), z.string()),
26532
+ /** Role used when the value matches no case. Omit to yield `undefined`. */
26533
+ fallback: z.string().optional()
26534
+ }),
26535
+ run: (value, options) => {
26536
+ const role = options.cases[String(value)] ?? options.fallback;
26537
+ return role ? `rgb(var(--tb-${role}))` : void 0;
26538
+ }
26539
+ };
25820
26540
  const formattingTransforms = [
26541
+ {
26542
+ id: "value.equals",
26543
+ kind: "formatter",
26544
+ summary: "Compare a value to a fixed string",
26545
+ schema: z.object({ value: z.string() }),
26546
+ run: (value, options) => value === options.value
26547
+ },
25821
26548
  uppercaseTransform,
25822
26549
  fallbackTransform,
25823
26550
  dateFormatShort,
25824
26551
  arrayLengthTransform,
26552
+ booleanNotTransform,
25825
26553
  jsonArrayTransform,
25826
26554
  csvTransform,
25827
26555
  marqueeLoopTransform,
25828
- {
25829
- id: "value.mapToken",
25830
- kind: "formatter",
25831
- summary: "Map a state/enum value to a theme token colour (rgb(var(--tb-<role>)))",
25832
- schema: z.object({
25833
- /**
25834
- * Maps an input state/enum value (stringified) to a theme token ROLE name
25835
- * (e.g. `secondary`, `accent`, `muted`, `border`). The role is wrapped to
25836
- * `rgb(var(--tb-<role>))` so the result drops straight into a `style` binding.
25837
- */
25838
- cases: z.record(z.string(), z.string()),
25839
- /** Role used when the value matches no case. Omit to yield `undefined`. */
25840
- fallback: z.string().optional()
25841
- }),
25842
- run: (value, options) => {
25843
- const role = options.cases[String(value)] ?? options.fallback;
25844
- return role ? `rgb(var(--tb-${role}))` : void 0;
25845
- }
25846
- }
26556
+ mapTokenTransform
25847
26557
  ];
25848
26558
  //#endregion
25849
26559
  //#region ../blocks/src/system/transforms/registry/ui.ts
@@ -26838,16 +27548,16 @@ const interpolateRichTextTokensOptionsSchema = z.object({ tokens: z.array(suppor
26838
27548
  const richTextTokenPattern = /\{\{\s*([a-zA-Z0-9_]+)\s*\}\}/g;
26839
27549
  function getSiteName(context) {
26840
27550
  const viewModel = context.viewModel;
26841
- if (!isRecord$10(viewModel)) return null;
27551
+ if (!isRecord$9(viewModel)) return null;
26842
27552
  const site = viewModel.site;
26843
- if (isRecord$10(site) && typeof site.title === "string") {
27553
+ if (isRecord$9(site) && typeof site.title === "string") {
26844
27554
  const title = site.title.trim();
26845
27555
  return title.length > 0 ? title : null;
26846
27556
  }
26847
27557
  const root = viewModel.$root;
26848
- if (isRecord$10(root)) {
27558
+ if (isRecord$9(root)) {
26849
27559
  const rootSite = root.site;
26850
- if (isRecord$10(rootSite) && typeof rootSite.title === "string") {
27560
+ if (isRecord$9(rootSite) && typeof rootSite.title === "string") {
26851
27561
  const title = rootSite.title.trim();
26852
27562
  if (title.length > 0) return title;
26853
27563
  }
@@ -26869,7 +27579,7 @@ function replaceTokenText(input, allowedTokens, tokenValues) {
26869
27579
  });
26870
27580
  }
26871
27581
  function visitRichTextNode(node, allowedTokens, tokenValues) {
26872
- if (!isRecord$10(node)) return node;
27582
+ if (!isRecord$9(node)) return node;
26873
27583
  let changed = false;
26874
27584
  const nextNode = { ...node };
26875
27585
  if (nextNode.type === "text" && typeof nextNode.text === "string") {
@@ -26890,7 +27600,7 @@ function visitRichTextNode(node, allowedTokens, tokenValues) {
26890
27600
  return changed ? nextNode : node;
26891
27601
  }
26892
27602
  function interpolateRichTextTokens(value, options, context) {
26893
- if (!isRecord$10(value)) return value;
27603
+ if (!isRecord$9(value)) return value;
26894
27604
  return visitRichTextNode(value, new Set(options.tokens), {
26895
27605
  year: String((/* @__PURE__ */ new Date()).getFullYear()),
26896
27606
  site_name: getSiteName(context)
@@ -27252,13 +27962,9 @@ const footerStandardContactBindings = {
27252
27962
  };
27253
27963
  const footerMailingListBindings = {
27254
27964
  source: { $bind: { from: "module.engagement.runtime.source" } },
27255
- destinationRef: { $bind: { from: "module.engagement.runtime.destinationRef" } },
27256
- listId: { $bind: { from: "module.engagement.runtime.listId" } },
27257
- preset: { $bind: { from: "module.engagement.runtime.preset" } },
27258
- includePhone: { $bind: { from: "module.engagement.runtime.includePhone" } },
27259
- buttonLabel: { $bind: { from: "module.engagement.runtime.buttonLabel" } },
27260
- successMessage: { $bind: { from: "module.engagement.runtime.successMessage" } },
27261
- privacyNote: { $bind: { from: "module.engagement.runtime.privacyNote" } }
27965
+ sourceRef: { $bind: { from: "module.engagement.runtime.sourceRef" } },
27966
+ mailingList: { $bind: { from: "module.engagement.runtime.mailingList" } },
27967
+ targeting: { $bind: { from: "module.engagement.runtime.targeting" } }
27262
27968
  };
27263
27969
  const footerSpamProtectionBinding = { spamProtectionEnabled: { $bind: { from: "$root.spamProtectionEnabled" } } };
27264
27970
  const brandLogo = link({
@@ -28946,6 +29652,78 @@ const appointmentBookingBlockDefinition = {
28946
29652
  }
28947
29653
  }
28948
29654
  };
29655
+ const appointmentServicesBlockDefinition = {
29656
+ manifest: createBlockManifest({
29657
+ id: "block.appointment-services",
29658
+ version: "1.0.0",
29659
+ title: "Appointment Services",
29660
+ titleSource: "heading",
29661
+ description: "List public appointment services with booking links",
29662
+ skipSectionStyles: true,
29663
+ additionalFields: [
29664
+ {
29665
+ id: "heading",
29666
+ type: "text",
29667
+ label: "Heading",
29668
+ required: false,
29669
+ multiline: false,
29670
+ defaultValue: "Appointments",
29671
+ ui: { intent: "content" }
29672
+ },
29673
+ {
29674
+ id: "description",
29675
+ type: "richText",
29676
+ label: "Description",
29677
+ required: false,
29678
+ ui: { intent: "content" }
29679
+ },
29680
+ sectionStylesField({
29681
+ id: "_sectionStyles",
29682
+ label: "Section styles",
29683
+ renderInHeader: false
29684
+ })
29685
+ ],
29686
+ styleTokens: {
29687
+ background: "surface",
29688
+ typography: "body",
29689
+ spacing: "md"
29690
+ },
29691
+ behaviours: {
29692
+ supportsThemeSwitching: true,
29693
+ inlineEditing: true,
29694
+ animation: false,
29695
+ paletteHidden: false
29696
+ },
29697
+ category: "interactive",
29698
+ contentSource: { kind: "inline" },
29699
+ tags: [
29700
+ "booking",
29701
+ "appointment",
29702
+ "services",
29703
+ "scheduling"
29704
+ ],
29705
+ icon: "CalendarDays",
29706
+ layout: [styledSection({
29707
+ baseClass: "",
29708
+ spacing: "spacious",
29709
+ children: sectionContainer([
29710
+ text({ as: "h2" }, bind("content.heading"), when("content.heading")),
29711
+ richText({ className: "rb-prose rb-max-w-none" }, bind("content.description"), when("content.description")),
29712
+ el("appointment-services", {
29713
+ sectionHeading: { $bind: { from: "content.heading" } },
29714
+ services: { $bind: { from: "data.services" } },
29715
+ pathname: { $bind: { from: "$root.pathname" } }
29716
+ })
29717
+ ], { gap: "lg" })
29718
+ })]
29719
+ }),
29720
+ dataSchemas: { services: z.unknown().optional() },
29721
+ dataLoaders: { services: {
29722
+ endpoint: "getPublicBookingServices",
29723
+ params: { siteId: { $bind: { from: "$root.siteId" } } },
29724
+ mode: "server"
29725
+ } }
29726
+ };
28949
29727
  //#endregion
28950
29728
  //#region ../blocks/src/system/blocks/weekly-slot-availability.ts
28951
29729
  const weeklySlotAvailabilityManifest = createBlockManifest({
@@ -29464,11 +30242,11 @@ function resolveEventRegistrationScopedEvents(events, context) {
29464
30242
  }
29465
30243
  //#endregion
29466
30244
  //#region ../blocks/src/system/runtime/nodes/events/domain/destination.ts
29467
- function isRecord$8(value) {
30245
+ function isRecord$7(value) {
29468
30246
  return typeof value === "object" && value !== null && !Array.isArray(value);
29469
30247
  }
29470
30248
  function isRuntimeEventDestination(value) {
29471
- if (!isRecord$8(value) || typeof value.kind !== "string") return false;
30249
+ if (!isRecord$7(value) || typeof value.kind !== "string") return false;
29472
30250
  if (value.kind === "native") return (value.mode === "cms-managed" || value.mode === "system-managed") && typeof value.path === "string";
29473
30251
  return value.kind === "external" && typeof value.url === "string" && typeof value.label === "string";
29474
30252
  }
@@ -29590,6 +30368,44 @@ function toWholeSeriesRegistrationEvents(events) {
29590
30368
  return groupPublicEventsByRun(events).map(toWholeSeriesRegistrationEvent).filter((event) => event !== null);
29591
30369
  }
29592
30370
  //#endregion
30371
+ //#region ../blocks/src/system/runtime/nodes/event-registration/eventSourceRecovery.ts
30372
+ const { limit: _rawLimit, eventSurface: _rawEventSurface, scheduleScope: _rawScheduleScope, detailLevel: _rawDetailLevel, ...stringEventQueryShape } = publicEventLoaderQuerySchemaShape;
30373
+ const eventRecoveryRequestSchema = z.object({
30374
+ ...stringEventQueryShape,
30375
+ limit: z.coerce.number().int().positive().optional(),
30376
+ eventSurface: z.enum(eventSurfaceScopeValues).optional(),
30377
+ scheduleScope: z.enum(eventScheduleScopeValues).optional(),
30378
+ detailLevel: z.enum(["full", "listing"]).optional(),
30379
+ stage: z.enum(["preview", "published"]).optional()
30380
+ });
30381
+ function resolveEventRegistrationEventSource(input) {
30382
+ if (input.wholeSeriesRunEvents != null) return {
30383
+ kind: "loaded",
30384
+ events: input.wholeSeriesRunEvents
30385
+ };
30386
+ if (input.events != null) return {
30387
+ kind: "loaded",
30388
+ events: input.events
30389
+ };
30390
+ return {
30391
+ kind: "unresolved",
30392
+ request: parseEventLoaderRecoveryRequest(input.failures?.wholeSeriesRunEvents ?? input.failures?.events)
30393
+ };
30394
+ }
30395
+ const eventLoaderFailureSchema = z.object({
30396
+ endpoint: z.literal("listPublicEvents"),
30397
+ params: eventRecoveryRequestSchema.extend({ siteId: z.string().optional() })
30398
+ });
30399
+ function parseEventLoaderRecoveryRequest(value) {
30400
+ const parsed = eventLoaderFailureSchema.safeParse(value);
30401
+ if (!parsed.success) return null;
30402
+ const { siteId: _siteId, stage, ...params } = parsed.data.params;
30403
+ return {
30404
+ ...params,
30405
+ stage: stage ?? "published"
30406
+ };
30407
+ }
30408
+ //#endregion
29593
30409
  //#region ../blocks/src/system/runtime/nodes/event-registration.interactive.ts
29594
30410
  const EVENT_REGISTRATION_GENERIC_SHELL_STEP_LABELS = [
29595
30411
  "Date",
@@ -29607,8 +30423,6 @@ const eventRegistrationPublicEventSchema = z.preprocess(normalizeEventRegistrati
29607
30423
  const eventRegistrationHydrationSchemaShape = {
29608
30424
  occurrenceContext: occurrenceContextSchema.optional(),
29609
30425
  subject: eventRegistrationPageSurfaceSubjectSchema.nullable().optional(),
29610
- events: z.array(eventRegistrationPublicEventSchema).nullable().optional(),
29611
- wholeSeriesRunEvents: z.array(eventRegistrationPublicEventSchema).nullable().optional(),
29612
30426
  maxTickets: z.string().optional(),
29613
30427
  showVenue: z.boolean().optional(),
29614
30428
  showCapacity: z.boolean().optional(),
@@ -29620,12 +30434,22 @@ const eventRegistrationHydrationSchemaShape = {
29620
30434
  sitePasses: publicPassProductCollectionSchema.nullable().optional(),
29621
30435
  siteMemberships: publicMembershipProductCollectionSchema.nullable().optional()
29622
30436
  };
30437
+ const eventRegistrationEventSourceSchema = z.discriminatedUnion("kind", [z.object({
30438
+ kind: z.literal("loaded"),
30439
+ events: z.array(eventRegistrationPublicEventSchema)
30440
+ }), z.object({
30441
+ kind: z.literal("unresolved"),
30442
+ request: eventRecoveryRequestSchema.nullable()
30443
+ })]);
29623
30444
  const eventRegistrationSourceSchema = z.object({
29624
30445
  siteId: z.string().optional(),
29625
30446
  apiBaseUrl: z.string().optional(),
29626
30447
  portalToken: z.string().nullable().optional(),
29627
30448
  previewToken: z.string().nullable().optional(),
29628
30449
  ...eventRegistrationHydrationSchemaShape,
30450
+ events: z.array(eventRegistrationPublicEventSchema).nullable().optional(),
30451
+ wholeSeriesRunEvents: z.array(eventRegistrationPublicEventSchema).nullable().optional(),
30452
+ eventLoaderFailures: z.record(z.string(), z.unknown()).nullable().optional(),
29629
30453
  className: z.string().nullable().optional(),
29630
30454
  buttonText: z.string().nullable().optional(),
29631
30455
  maxTickets: z.string().nullable().optional(),
@@ -29646,7 +30470,10 @@ const eventRegistrationDisplaySchema = z.discriminatedUnion("state", [z.object({
29646
30470
  titleText: z.string(),
29647
30471
  bodyText: z.string()
29648
30472
  })]);
29649
- const eventRegistrationHydrationSchema = z.object(eventRegistrationHydrationSchemaShape);
30473
+ const eventRegistrationHydrationSchema = z.object({
30474
+ ...eventRegistrationHydrationSchemaShape,
30475
+ eventSource: eventRegistrationEventSourceSchema
30476
+ });
29650
30477
  const eventRegistrationRenderSchema = z.object({
29651
30478
  display: eventRegistrationDisplaySchema,
29652
30479
  hydration: eventRegistrationHydrationSchema
@@ -29658,8 +30485,8 @@ z.object({
29658
30485
  previewToken: z.string().nullable().optional(),
29659
30486
  stage: previewStageSchema.optional()
29660
30487
  });
29661
- function buildEventRegistrationDisplay(source) {
29662
- const selectedRun = resolveSelectedWholeSeriesRun(source);
30488
+ function buildEventRegistrationDisplayFromScopedEvents(source, scopedSourceEvents) {
30489
+ const selectedRun = resolveSelectedWholeSeriesRun(scopedSourceEvents);
29663
30490
  if (selectedRun && (!selectedRun.run.enrollmentOpen || toWholeSeriesRegistrationEvent(selectedRun) === null)) return {
29664
30491
  kind: "event-registration",
29665
30492
  state: "registration-closed",
@@ -29667,7 +30494,7 @@ function buildEventRegistrationDisplay(source) {
29667
30494
  titleText: "Registration closed",
29668
30495
  bodyText: "This run is no longer open for bookings."
29669
30496
  };
29670
- const stepLabels = buildEventRegistrationShellStepLabels(source);
30497
+ const stepLabels = buildEventRegistrationShellStepLabels(source, scopedSourceEvents);
29671
30498
  return {
29672
30499
  kind: "event-registration",
29673
30500
  state: "generic-shell",
@@ -29678,8 +30505,8 @@ function buildEventRegistrationDisplay(source) {
29678
30505
  summaryButtonText: source.buttonText?.trim() || "Register"
29679
30506
  };
29680
30507
  }
29681
- function buildEventRegistrationShellStepLabels(source) {
29682
- const selectedRun = resolveSelectedWholeSeriesRun(source);
30508
+ function buildEventRegistrationShellStepLabels(source, scopedSourceEvents) {
30509
+ const selectedRun = resolveSelectedWholeSeriesRun(scopedSourceEvents);
29683
30510
  if (selectedRun) {
29684
30511
  const selectedEvent = toWholeSeriesRegistrationEvent(selectedRun);
29685
30512
  if (!selectedEvent) return EVENT_REGISTRATION_GENERIC_SHELL_STEP_LABELS;
@@ -29689,7 +30516,7 @@ function buildEventRegistrationShellStepLabels(source) {
29689
30516
  event: selectedEvent
29690
30517
  })).map((step) => shellLabelForRegistrationStep(step, [selectedEvent]));
29691
30518
  }
29692
- const scopedEvents = scopeEventRegistrationEvents(source);
30519
+ const scopedEvents = toScopedEventRegistrationEvents(scopedSourceEvents);
29693
30520
  if (scopedEvents.length === 0) return EVENT_REGISTRATION_GENERIC_SHELL_STEP_LABELS;
29694
30521
  const preSelectedEvent = findPreSelectedEvent({
29695
30522
  scopedEvents,
@@ -29702,21 +30529,11 @@ function buildEventRegistrationShellStepLabels(source) {
29702
30529
  event: preSelectedEvent
29703
30530
  }) : false).map((step) => shellLabelForRegistrationStep(step, scopedEvents));
29704
30531
  }
29705
- function scopeEventRegistrationEvents(source) {
29706
- const scoped = scopeEventRegistrationSourceEvents(source);
29707
- return [...toRegistrationEvents(scoped), ...toWholeSeriesRegistrationEvents(scoped)];
30532
+ function toScopedEventRegistrationEvents(scopedSourceEvents) {
30533
+ return [...toRegistrationEvents(scopedSourceEvents), ...toWholeSeriesRegistrationEvents(scopedSourceEvents)];
29708
30534
  }
29709
- /**
29710
- * Every event this surface may register for, from both of its loads.
29711
- *
29712
- * The date page and the run read answer different questions and can name the
29713
- * same occurrence, so the two lists are joined and any occurrence that arrives
29714
- * twice is kept once, in the order the date page gave it.
29715
- */
29716
- function scopeEventRegistrationSourceEvents(source) {
29717
- const byOccurrenceId = /* @__PURE__ */ new Map();
29718
- for (const event of [...source.events ?? [], ...source.wholeSeriesRunEvents ?? []]) if (!byOccurrenceId.has(event.occurrenceId)) byOccurrenceId.set(event.occurrenceId, event);
29719
- return resolveEventRegistrationScopedEvents([...byOccurrenceId.values()], {
30535
+ function scopeEventRegistrationSourceEvents(source, eventSource) {
30536
+ return resolveEventRegistrationScopedEvents(eventSource.kind === "loaded" ? eventSource.events : [], {
29720
30537
  occurrenceContext: source.occurrenceContext,
29721
30538
  subject: source.subject
29722
30539
  });
@@ -29725,8 +30542,8 @@ function scopeEventRegistrationSourceEvents(source) {
29725
30542
  * The one run this surface is registering for, when the scoped events describe
29726
30543
  * exactly one. More than one run means the visitor still has to choose.
29727
30544
  */
29728
- function resolveSelectedWholeSeriesRun(source) {
29729
- const runs = groupPublicEventsByRun(scopeEventRegistrationSourceEvents(source));
30545
+ function resolveSelectedWholeSeriesRun(scopedSourceEvents) {
30546
+ const runs = groupPublicEventsByRun(scopedSourceEvents);
29730
30547
  return runs.length === 1 ? runs[0] : null;
29731
30548
  }
29732
30549
  function shellLabelForRegistrationStep(step, events) {
@@ -29760,13 +30577,21 @@ const eventRegistrationBlockRuntime = defineClientOwnedBlockRuntime({
29760
30577
  render: createZodCodec(eventRegistrationRenderSchema)
29761
30578
  },
29762
30579
  buildRender: (source) => {
29763
- const events = source.events == null ? null : scopeEventRegistrationSourceEvents(source);
30580
+ const eventSource = resolveEventRegistrationEventSource({
30581
+ events: source.events,
30582
+ wholeSeriesRunEvents: source.wholeSeriesRunEvents,
30583
+ failures: source.eventLoaderFailures
30584
+ });
30585
+ const scopedSourceEvents = scopeEventRegistrationSourceEvents(source, eventSource);
29764
30586
  return {
29765
- display: buildEventRegistrationDisplay(source),
30587
+ display: buildEventRegistrationDisplayFromScopedEvents(source, scopedSourceEvents),
29766
30588
  hydration: {
29767
30589
  occurrenceContext: source.occurrenceContext ?? null,
29768
30590
  subject: source.subject ?? null,
29769
- events,
30591
+ eventSource: eventSource.kind === "loaded" ? {
30592
+ ...eventSource,
30593
+ events: [...scopedSourceEvents]
30594
+ } : eventSource,
29770
30595
  maxTickets: source.maxTickets ?? void 0,
29771
30596
  showVenue: source.showVenue,
29772
30597
  showCapacity: source.showCapacity,
@@ -29782,13 +30607,13 @@ const eventRegistrationBlockRuntime = defineClientOwnedBlockRuntime({
29782
30607
  }
29783
30608
  });
29784
30609
  function normalizeEventRegistrationEventInput(value) {
29785
- if (!isRecord$7(value)) return value;
30610
+ if (!isRecord$6(value)) return value;
29786
30611
  return {
29787
30612
  ...value,
29788
30613
  destination: resolveRuntimeEventDestination(value)
29789
30614
  };
29790
30615
  }
29791
- function isRecord$7(value) {
30616
+ function isRecord$6(value) {
29792
30617
  return typeof value === "object" && value !== null && !Array.isArray(value);
29793
30618
  }
29794
30619
  const eventRegistrationBlockDefinition = {
@@ -29942,6 +30767,7 @@ const eventRegistrationBlockDefinition = {
29942
30767
  } },
29943
30768
  events: { $bind: { from: "data.events" } },
29944
30769
  wholeSeriesRunEvents: { $bind: { from: "data.wholeSeriesRunEvents" } },
30770
+ loaderFailures: { $bind: { from: "$root.loaderFailures" } },
29945
30771
  sitePasses: { $bind: { from: "data.sitePasses" } },
29946
30772
  siteMemberships: { $bind: { from: "data.siteMemberships" } },
29947
30773
  stage: { $bind: {
@@ -29963,6 +30789,11 @@ const eventRegistrationBlockDefinition = {
29963
30789
  dataLoaders: {
29964
30790
  events: {
29965
30791
  endpoint: "listPublicEvents",
30792
+ when: { $bind: {
30793
+ from: "$root.subject.isWholeSeriesBooking",
30794
+ fallback: true,
30795
+ transforms: [{ id: "boolean.not" }]
30796
+ } },
29966
30797
  params: {
29967
30798
  siteId: { $bind: { from: "$root.siteId" } },
29968
30799
  limit: "50",
@@ -29984,13 +30815,9 @@ const eventRegistrationBlockDefinition = {
29984
30815
  /**
29985
30816
  * The runs this page can register for, finished ones included.
29986
30817
  *
29987
- * The `events` page above is date-bounded, so a run whose first session has
29988
- * passed contributes no rows to it and the surface would have nothing to
29989
- * render as closed. This asks for runs instead, and only on a page whose
29990
- * subject books whole runs. It is scoped exactly like the date page — same
29991
- * series, same run subroute — because scope and grain are separate
29992
- * questions. The two lists are joined by occurrence, so a run that appears
29993
- * in both is still one run.
30818
+ * A run read is the sole Event source on a whole-series surface. It is
30819
+ * status-bounded rather than date-bounded, so completed runs can still
30820
+ * render their closed state and every run carries its complete schedule.
29994
30821
  */
29995
30822
  wholeSeriesRunEvents: {
29996
30823
  endpoint: "listPublicEvents",
@@ -32685,7 +33512,7 @@ function inferLegacyOfferingsPreviewGroupOrder(overrides) {
32685
33512
  return keys.length >= 2 ? keys : [];
32686
33513
  }
32687
33514
  function normalizeOfferingsPreviewContentForWrite(value) {
32688
- if (!isRecord$6(value)) return null;
33515
+ if (!isRecord$5(value)) return null;
32689
33516
  const groupOrderValue = value.groupOrder;
32690
33517
  if (Array.isArray(groupOrderValue)) {
32691
33518
  const normalized = normalizeOfferingsPreviewGroupOrder(groupOrderValue);
@@ -32698,7 +33525,7 @@ function normalizeOfferingsPreviewContentForWrite(value) {
32698
33525
  ...value,
32699
33526
  groupOrder: []
32700
33527
  };
32701
- const legacyOrder = inferLegacyOfferingsPreviewGroupOrder(Array.isArray(value.groupOverrides) ? value.groupOverrides.filter(isRecord$6) : []);
33528
+ const legacyOrder = inferLegacyOfferingsPreviewGroupOrder(Array.isArray(value.groupOverrides) ? value.groupOverrides.filter(isRecord$5) : []);
32702
33529
  return legacyOrder.length > 0 ? {
32703
33530
  ...value,
32704
33531
  groupOrder: legacyOrder
@@ -32712,24 +33539,11 @@ function uniqueOfferingsPreviewSourceKeys(values) {
32712
33539
  }
32713
33540
  return keys;
32714
33541
  }
32715
- function isRecord$6(value) {
33542
+ function isRecord$5(value) {
32716
33543
  return typeof value === "object" && value !== null && !Array.isArray(value);
32717
33544
  }
32718
33545
  //#endregion
32719
- //#region ../blocks/src/system/blocks/offerings-preview/index.ts
32720
- /**
32721
- * The whole-series presets, as the CSV `listPublicEvents` expects. Both
32722
- * whole-series presets share one loader: the block renders them as a single
32723
- * run group.
32724
- */
32725
- const WHOLE_SERIES_EVENT_PRESETS_PARAM = WHOLE_SERIES_EVENT_PRESET_VALUES.join(",");
32726
- const publicRouteCandidatesSchema = z.object({ routes: z.array(z.object({
32727
- entityId: z.string(),
32728
- path: z.string(),
32729
- title: z.string(),
32730
- kind: z.enum(RESOLVED_INTERNAL_LINK_ENTITY_TYPES),
32731
- contentTypeKey: z.string().nullable().optional()
32732
- })) });
33546
+ //#region ../blocks/src/system/blocks/offerings-preview/fields.ts
32733
33547
  const groupOverrideFields = [
32734
33548
  {
32735
33549
  id: "sourceKey",
@@ -32935,7 +33749,65 @@ const offeringsPreviewFields = [
32935
33749
  renderInHeader: false
32936
33750
  })
32937
33751
  ];
33752
+ function labelForOfferingPreviewSourceKey(sourceKey) {
33753
+ const eventDefinition = OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS.find((definition) => definition.sourceKey === sourceKey);
33754
+ if (eventDefinition) return eventDefinition.label;
33755
+ return "Courses";
33756
+ }
33757
+ //#endregion
33758
+ //#region ../blocks/src/system/blocks/offerings-preview/index.ts
33759
+ /**
33760
+ * The whole-series presets, as the CSV `listPublicEvents` expects. Both
33761
+ * whole-series presets share one loader: the block renders them as a single
33762
+ * run group.
33763
+ */
33764
+ const WHOLE_SERIES_EVENT_PRESETS_PARAM = WHOLE_SERIES_EVENT_PRESET_VALUES.join(",");
33765
+ const publicRouteCandidatesSchema = z.object({ routes: z.array(z.object({
33766
+ entityId: z.string(),
33767
+ path: z.string(),
33768
+ title: z.string(),
33769
+ kind: z.enum(RESOLVED_INTERNAL_LINK_ENTITY_TYPES),
33770
+ contentTypeKey: z.string().nullable().optional()
33771
+ })) });
32938
33772
  const offeringsPreviewEventDataBindings = Object.fromEntries(OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS.map((definition) => [definition.dataKey, { $bind: { from: `data.${definition.dataKey}` } }]));
33773
+ const DEFAULT_OFFERINGS_PREVIEW_DISPLAY_MODE = "preview";
33774
+ const displayModeBinding = {
33775
+ from: "content.displayMode",
33776
+ fallback: DEFAULT_OFFERINGS_PREVIEW_DISPLAY_MODE
33777
+ };
33778
+ const catalogueMode = { $bind: {
33779
+ ...displayModeBinding,
33780
+ transforms: [{
33781
+ id: "value.equals",
33782
+ options: { value: "catalogue" }
33783
+ }]
33784
+ } };
33785
+ const previewMode = { $bind: {
33786
+ ...displayModeBinding,
33787
+ transforms: [{
33788
+ id: "value.equals",
33789
+ options: { value: "preview" }
33790
+ }]
33791
+ } };
33792
+ function offeringsPreviewHeaderNodes() {
33793
+ return [text({
33794
+ as: "h2",
33795
+ className: { $bind: {
33796
+ from: "content.displayMode",
33797
+ fallback: "rb-text-center",
33798
+ transforms: [{
33799
+ id: "value.equals",
33800
+ options: { value: "catalogue" }
33801
+ }, {
33802
+ id: "ui.conditionalClass",
33803
+ options: {
33804
+ whenTrue: "rb-text-left",
33805
+ whenFalse: "rb-text-center"
33806
+ }
33807
+ }]
33808
+ } }
33809
+ }, bind("content.heading"), when("content.heading")), richText({ className: "rb-prose rb-max-w-none" }, bind("content.description"), when("content.description"))];
33810
+ }
32939
33811
  const offeringsPreviewManifest = createBlockManifest({
32940
33812
  id: "block.offerings-preview",
32941
33813
  version: "1.0.0",
@@ -32966,48 +33838,45 @@ const offeringsPreviewManifest = createBlockManifest({
32966
33838
  ],
32967
33839
  icon: "PanelsTopLeft",
32968
33840
  layout: [styledSection({
32969
- children: sectionContainer([
32970
- text({
32971
- as: "h2",
32972
- className: "rb-text-center"
32973
- }, bind("content.heading"), when("content.heading")),
32974
- richText({ className: "rb-prose rb-max-w-none" }, bind("content.description"), when("content.description")),
32975
- el("offerings-preview", {
32976
- bookingOfferingPresets: { $bind: {
32977
- from: "$root.bookingOfferingPresets",
32978
- fallback: []
32979
- } },
32980
- groupOverrides: { $bind: {
32981
- from: "content.groupOverrides",
32982
- fallback: []
32983
- } },
32984
- groupOrder: { $bind: { from: "content.groupOrder" } },
32985
- cardStyles: { $bind: { from: "content._cardStyles" } },
32986
- itemLimit: { $bind: {
32987
- from: "content.itemLimit",
32988
- fallback: "3"
32989
- } },
32990
- buttonVariant: { $bind: {
32991
- from: "content.buttonVariant",
32992
- fallback: "primary"
32993
- } },
32994
- buttonText: { $bind: {
32995
- from: "content.buttonText",
32996
- fallback: OFFERINGS_PREVIEW_DEFAULT_BUTTON_TEXT
32997
- } },
32998
- emptyMessage: { $bind: {
32999
- from: "content.emptyMessage",
33000
- fallback: OFFERINGS_PREVIEW_DEFAULT_EMPTY_MESSAGE
33001
- } },
33002
- previewStage: { $bind: {
33003
- from: "$root.previewStage",
33004
- fallback: "published"
33005
- } },
33006
- routeCandidates: { $bind: { from: "data.routeCandidates" } },
33007
- wholeSeriesRunEvents: { $bind: { from: "data.wholeSeriesRunEvents" } },
33008
- ...offeringsPreviewEventDataBindings
33009
- })
33010
- ], { gap: "lg" }),
33841
+ children: sectionContainer([el("offerings-preview", {
33842
+ displayMode: { $bind: displayModeBinding },
33843
+ pathname: { $bind: { from: "$root.pathname" } },
33844
+ catalogueEvents: { $bind: { from: "data.catalogueEvents" } },
33845
+ quickDateEvents: { $bind: { from: "data.quickDateEvents" } },
33846
+ bookingOfferingPresets: { $bind: {
33847
+ from: "$root.bookingOfferingPresets",
33848
+ fallback: []
33849
+ } },
33850
+ groupOverrides: { $bind: {
33851
+ from: "content.groupOverrides",
33852
+ fallback: []
33853
+ } },
33854
+ groupOrder: { $bind: { from: "content.groupOrder" } },
33855
+ cardStyles: { $bind: { from: "content._cardStyles" } },
33856
+ itemLimit: { $bind: {
33857
+ from: "content.itemLimit",
33858
+ fallback: "3"
33859
+ } },
33860
+ buttonVariant: { $bind: {
33861
+ from: "content.buttonVariant",
33862
+ fallback: "primary"
33863
+ } },
33864
+ buttonText: { $bind: {
33865
+ from: "content.buttonText",
33866
+ fallback: OFFERINGS_PREVIEW_DEFAULT_BUTTON_TEXT
33867
+ } },
33868
+ emptyMessage: { $bind: {
33869
+ from: "content.emptyMessage",
33870
+ fallback: OFFERINGS_PREVIEW_DEFAULT_EMPTY_MESSAGE
33871
+ } },
33872
+ previewStage: { $bind: {
33873
+ from: "$root.previewStage",
33874
+ fallback: "published"
33875
+ } },
33876
+ routeCandidates: { $bind: { from: "data.routeCandidates" } },
33877
+ wholeSeriesRunEvents: { $bind: { from: "data.wholeSeriesRunEvents" } },
33878
+ ...offeringsPreviewEventDataBindings
33879
+ }, offeringsPreviewHeaderNodes())], { gap: "lg" }),
33011
33880
  baseClass: "",
33012
33881
  spacing: "comfortable"
33013
33882
  })]
@@ -33021,16 +33890,48 @@ const offeringsPreviewBlockDefinition = {
33021
33890
  dataSchemas: {
33022
33891
  ...offeringsPreviewEventDataSchemas,
33023
33892
  routeCandidates: publicRouteCandidatesSchema.optional(),
33024
- wholeSeriesRunEvents: optionalPublicEventsArraySchema
33893
+ wholeSeriesRunEvents: optionalPublicEventsArraySchema,
33894
+ catalogueEvents: optionalPublicEventsArraySchema,
33895
+ quickDateEvents: optionalPublicEventsArraySchema
33025
33896
  },
33026
33897
  dataLoaders: {
33027
33898
  ...offeringsPreviewEventDataLoaders,
33028
33899
  routeCandidates: {
33029
33900
  endpoint: "listPublicRouteCandidates",
33901
+ when: previewMode,
33030
33902
  params: {},
33031
33903
  mode: "server"
33032
33904
  },
33033
- wholeSeriesRunEvents: wholeSeriesRunLoader()
33905
+ wholeSeriesRunEvents: wholeSeriesRunLoader(),
33906
+ catalogueEvents: {
33907
+ endpoint: "listPublicEvents",
33908
+ when: catalogueMode,
33909
+ params: {
33910
+ stage: { $bind: {
33911
+ from: "$root.previewStage",
33912
+ fallback: "published"
33913
+ } },
33914
+ detailLevel: "listing",
33915
+ readProfile: "listing-card",
33916
+ readIntent: "catalogue"
33917
+ },
33918
+ mode: "server"
33919
+ },
33920
+ quickDateEvents: {
33921
+ endpoint: "listPublicEvents",
33922
+ when: catalogueMode,
33923
+ params: {
33924
+ stage: { $bind: {
33925
+ from: "$root.previewStage",
33926
+ fallback: "published"
33927
+ } },
33928
+ detailLevel: "listing",
33929
+ readProfile: "listing-card",
33930
+ readIntent: "occurrences",
33931
+ limit: 40
33932
+ },
33933
+ mode: "server"
33934
+ }
33034
33935
  }
33035
33936
  };
33036
33937
  /**
@@ -33047,6 +33948,7 @@ function wholeSeriesRunLoader() {
33047
33948
  function eventPresetLoader(eventPresets, extraParams = {}) {
33048
33949
  return {
33049
33950
  endpoint: "listPublicEvents",
33951
+ when: previewMode,
33050
33952
  params: {
33051
33953
  siteId: { $bind: { from: "$root.siteId" } },
33052
33954
  limit: { $bind: {
@@ -33065,15 +33967,10 @@ function eventPresetLoader(eventPresets, extraParams = {}) {
33065
33967
  mode: "server"
33066
33968
  };
33067
33969
  }
33068
- function labelForOfferingPreviewSourceKey(sourceKey) {
33069
- const eventDefinition = OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS.find((definition) => definition.sourceKey === sourceKey);
33070
- if (eventDefinition) return eventDefinition.label;
33071
- return "Courses";
33072
- }
33073
33970
  function normalizeOfferingsPreviewBlockContent(value) {
33074
33971
  const record = normalizeOfferingsPreviewContentForWrite(value);
33075
- if (!record) return {};
33076
- const normalized = {};
33972
+ if (!record) return { displayMode: DEFAULT_OFFERINGS_PREVIEW_DISPLAY_MODE };
33973
+ const normalized = { displayMode: normalizeOfferingsPreviewDisplayMode(record.displayMode) };
33077
33974
  if (typeof record.heading === "string" || record.heading === null) normalized.heading = record.heading;
33078
33975
  if ("description" in record) normalized.description = record.description;
33079
33976
  if (isOfferingsPreviewItemLimit(record.itemLimit)) normalized.itemLimit = record.itemLimit;
@@ -33090,11 +33987,14 @@ function normalizeOfferingsPreviewBlockContent(value) {
33090
33987
  if (sectionStyles !== void 0) normalized._sectionStyles = sectionStyles;
33091
33988
  return normalized;
33092
33989
  }
33990
+ function normalizeOfferingsPreviewDisplayMode(value) {
33991
+ return value === "catalogue" ? "catalogue" : DEFAULT_OFFERINGS_PREVIEW_DISPLAY_MODE;
33992
+ }
33093
33993
  function isOfferingsPreviewItemLimit(value) {
33094
33994
  return value === "1" || value === "2" || value === "3" || value === "4" || value === "5" || value === "6" || value === null;
33095
33995
  }
33096
33996
  function normalizeOfferingsPreviewGroupOverride(value) {
33097
- if (!isRecord$5(value)) return [];
33997
+ if (!isRecord$4(value)) return [];
33098
33998
  const override = {};
33099
33999
  if (isOfferingsPreviewSourceKey(value.sourceKey) || value.sourceKey === null) override.sourceKey = value.sourceKey;
33100
34000
  if (typeof value.title === "string" || value.title === null) override.title = value.title;
@@ -33117,7 +34017,7 @@ function normalizeSectionStylesContent(value) {
33117
34017
  }
33118
34018
  function normalizeBoxStylesContent(value) {
33119
34019
  if (value === null) return null;
33120
- if (!isRecord$5(value)) return void 0;
34020
+ if (!isRecord$4(value)) return void 0;
33121
34021
  const { background: _background, ...rest } = value;
33122
34022
  const background = parseBackgroundContent(value.background);
33123
34023
  return {
@@ -33125,7 +34025,7 @@ function normalizeBoxStylesContent(value) {
33125
34025
  ...background ? { background } : {}
33126
34026
  };
33127
34027
  }
33128
- function isRecord$5(value) {
34028
+ function isRecord$4(value) {
33129
34029
  return typeof value === "object" && value !== null && !Array.isArray(value);
33130
34030
  }
33131
34031
  const embedManifest = createBlockManifest({
@@ -36304,83 +37204,13 @@ const giftingBlockDefinition = {
36304
37204
  } }
36305
37205
  };
36306
37206
  //#endregion
36307
- //#region ../blocks/src/system/blocks/newsletter-signup-destination.ts
36308
- function parseNewsletterSignupBlockId(value) {
36309
- const trimmed = parseTrimmedString(value);
36310
- return trimmed && BLOCK_ID_PATTERN.test(trimmed) ? trimmed : null;
36311
- }
36312
- function parseSignedNewsletterDestinationRef(value) {
36313
- const trimmed = parseTrimmedString(value);
36314
- return trimmed && SIGNED_DESTINATION_REF_PATTERN.test(trimmed) ? trimmed : null;
36315
- }
36316
- function buildNewsletterSignupBlockRef(blockId) {
36317
- const parsed = parseNewsletterSignupBlockId(blockId);
36318
- return parsed ? {
36319
- tag: "block_ref",
36320
- blockId: parsed
36321
- } : null;
36322
- }
36323
- function normalizeNewsletterSignupEditorValuesForDestination(values) {
36324
- const destinationProvider = parseNewsletterSignupDestinationProvider(values.destinationProvider) ?? "riverbank";
36325
- if (destinationProvider === "mailchimp") return {
36326
- destinationProvider,
36327
- mailchimpAudienceId: values.mailchimpAudienceId,
36328
- mailchimpTags: values.mailchimpTags
36329
- };
36330
- return {
36331
- destinationProvider,
36332
- listId: values.listId,
36333
- tags: values.tags
36334
- };
36335
- }
36336
- function deriveNewsletterSignupRuntimeSource(values) {
36337
- const normalized = normalizeNewsletterSignupEditorValuesForDestination(values);
36338
- if (normalized.destinationProvider === "mailchimp") return {
36339
- destinationProvider: "mailchimp",
36340
- listId: null,
36341
- tags: null
36342
- };
36343
- return {
36344
- destinationProvider: "riverbank",
36345
- listId: parseTrimmedString(normalized.listId),
36346
- tags: parseTrimmedString(normalized.tags)
36347
- };
36348
- }
36349
- function sanitizeNewsletterSignupPublicContent(content) {
36350
- if (!isRecord$4(content)) return content;
36351
- const provider = parseNewsletterSignupDestinationProvider(content.destinationProvider) ?? getProviderFromExplicitDestination(content.destination);
36352
- const { destination: _destination, destinationProvider: _destinationProvider, mailchimpAudienceId: _mailchimpAudienceId, mailchimpTags: _mailchimpTags, listId, tags, ...publicContent } = content;
36353
- const mutablePublicContent = { ...publicContent };
36354
- if (provider !== "mailchimp") {
36355
- if ("listId" in content) mutablePublicContent.listId = listId;
36356
- if ("tags" in content) mutablePublicContent.tags = tags;
36357
- }
36358
- return mutablePublicContent;
36359
- }
36360
- function getProviderFromExplicitDestination(destination) {
36361
- if (!isRecord$4(destination) || typeof destination.tag !== "string") return null;
36362
- if (destination.tag === "riverbank_list") return "riverbank";
36363
- if (destination.tag === "mailchimp_audience") return "mailchimp";
36364
- return null;
36365
- }
36366
- const BLOCK_ID_PATTERN = /^[A-Za-z0-9._:-]{1,200}$/;
36367
- const SIGNED_DESTINATION_REF_PATTERN = /^[A-Za-z0-9._~-]{16,1000}$/;
36368
- function parseTrimmedString(value) {
36369
- if (typeof value !== "string") return null;
36370
- const trimmed = value.trim();
36371
- return trimmed.length > 0 ? trimmed : null;
36372
- }
36373
- function isRecord$4(value) {
36374
- return typeof value === "object" && value !== null;
36375
- }
36376
- //#endregion
36377
37207
  //#region ../blocks/src/system/runtime/nodes/newsletter-form.types.ts
36378
37208
  /**
36379
37209
  * Get form fields based on preset configuration.
36380
37210
  */
36381
- function getPresetFields(preset, options) {
36382
- const includePhone = Boolean(options?.includePhone);
36383
- switch (preset) {
37211
+ function getGlobalFormFields(form) {
37212
+ const includePhone = form.includeOptionalPhone;
37213
+ switch (form.fields.preset) {
36384
37214
  case "emailOnly": return withOptionalPhone([{
36385
37215
  id: "email",
36386
37216
  type: "email",
@@ -36398,7 +37228,7 @@ function getPresetFields(preset, options) {
36398
37228
  id: "name",
36399
37229
  type: "text",
36400
37230
  label: "Name",
36401
- required: false,
37231
+ required: form.fields.name === "required",
36402
37232
  placeholder: "Your name"
36403
37233
  }], includePhone);
36404
37234
  case "emailFirstLast": return withOptionalPhone([
@@ -36413,14 +37243,14 @@ function getPresetFields(preset, options) {
36413
37243
  id: "firstName",
36414
37244
  type: "text",
36415
37245
  label: "First Name",
36416
- required: false,
37246
+ required: form.fields.firstName === "required",
36417
37247
  placeholder: "First name"
36418
37248
  },
36419
37249
  {
36420
37250
  id: "lastName",
36421
37251
  type: "text",
36422
37252
  label: "Last Name",
36423
- required: false,
37253
+ required: form.fields.lastName === "required",
36424
37254
  placeholder: "Last name"
36425
37255
  }
36426
37256
  ], includePhone);
@@ -36436,14 +37266,14 @@ function getPresetFields(preset, options) {
36436
37266
  id: "name",
36437
37267
  type: "text",
36438
37268
  label: "Name",
36439
- required: false,
37269
+ required: form.fields.name === "required",
36440
37270
  placeholder: "Your name"
36441
37271
  },
36442
37272
  {
36443
37273
  id: "company",
36444
37274
  type: "text",
36445
37275
  label: "Company",
36446
- required: false,
37276
+ required: form.fields.company === "required",
36447
37277
  placeholder: "Company name"
36448
37278
  }
36449
37279
  ], includePhone);
@@ -36462,14 +37292,29 @@ function withOptionalPhone(fields, includePhone) {
36462
37292
  }
36463
37293
  //#endregion
36464
37294
  //#region ../blocks/src/system/runtime/nodes/newsletter-form.interactive.ts
36465
- const newsletterPresetSchema = z.enum([
36466
- "emailOnly",
36467
- "emailName",
36468
- "emailFirstLast",
36469
- "emailNameCompany"
36470
- ]);
36471
- const newsletterDestinationProviderSchema = z.enum(["riverbank", "mailchimp"]);
36472
37295
  const newsletterButtonVariantSchema = blockButtonRoleSchema;
37296
+ const mailingListContextSchema = z.unknown().transform((value, ctx) => {
37297
+ const parsed = parseMailingListRuntimeContext(value);
37298
+ if (!parsed.ok) {
37299
+ ctx.addIssue({
37300
+ code: z.ZodIssueCode.custom,
37301
+ message: "Invalid mailing-list runtime context"
37302
+ });
37303
+ return z.NEVER;
37304
+ }
37305
+ return parsed.value;
37306
+ });
37307
+ const mailingListTargetingSchema = z.unknown().transform((value, ctx) => {
37308
+ const parsed = parseMailingListPlacementTargeting(value);
37309
+ if (!parsed.ok) {
37310
+ ctx.addIssue({
37311
+ code: z.ZodIssueCode.custom,
37312
+ message: "Invalid mailing-list targeting"
37313
+ });
37314
+ return z.NEVER;
37315
+ }
37316
+ return parsed.value;
37317
+ });
36473
37318
  const newsletterFieldSchema = z.object({
36474
37319
  id: z.string(),
36475
37320
  type: z.enum(["email", "text"]),
@@ -36477,18 +37322,23 @@ const newsletterFieldSchema = z.object({
36477
37322
  required: z.boolean(),
36478
37323
  placeholder: z.string().optional()
36479
37324
  });
36480
- const newsletterSignupBlockIdSchema = z.string().trim().min(1).transform(parseRequiredNewsletterSignupBlockId);
36481
- const signedNewsletterDestinationRefSchema = z.string().trim().min(1).transform(parseRequiredSignedNewsletterDestinationRef);
37325
+ const mailingListSignupBlockIdSchema = z.string().trim().min(1).transform(parseRequiredMailingListSignupBlockId);
37326
+ const mailingListContentVersionIdSchema = z.string().transform((value, ctx) => {
37327
+ const parsed = parseMailingListContentVersionId(value);
37328
+ if (parsed) return parsed;
37329
+ ctx.addIssue({
37330
+ code: z.ZodIssueCode.custom,
37331
+ message: "Invalid mailing-list content version ID"
37332
+ });
37333
+ return z.NEVER;
37334
+ });
37335
+ const signedMailingListSourceTokenSchema = z.string().trim().min(1).transform(parseRequiredMailingListSignedSourceToken);
36482
37336
  const newsletterSourceCommonSchema = z.object({
36483
37337
  siteId: z.string().optional(),
36484
37338
  apiBaseUrl: z.string().optional(),
36485
- preset: newsletterPresetSchema.optional(),
36486
- includePhone: z.boolean().optional(),
36487
- buttonLabel: z.string().nullable().optional(),
37339
+ mailingList: mailingListContextSchema.optional(),
37340
+ targeting: mailingListTargetingSchema.optional(),
36488
37341
  buttonVariant: newsletterButtonVariantSchema.nullable().optional(),
36489
- successMessage: z.string().nullable().optional(),
36490
- privacyNote: z.string().nullable().optional(),
36491
- tags: z.string().nullable().optional(),
36492
37342
  spamProtectionEnabled: z.boolean().optional(),
36493
37343
  className: z.string().nullable().optional()
36494
37344
  });
@@ -36496,54 +37346,61 @@ const newsletterSourceSchema = z.discriminatedUnion("source", [
36496
37346
  newsletterSourceCommonSchema.extend({
36497
37347
  source: z.literal("block"),
36498
37348
  blockId: z.string().nullable().optional(),
36499
- listId: z.string().nullable().optional(),
36500
- destinationProvider: newsletterDestinationProviderSchema.nullable().optional()
37349
+ contentVersionId: z.string().nullable().optional()
36501
37350
  }),
36502
37351
  newsletterSourceCommonSchema.extend({
36503
37352
  source: z.literal("signed-footer"),
36504
- destinationRef: z.object({
36505
- tag: z.literal("signed_destination_ref"),
36506
- token: signedNewsletterDestinationRefSchema
37353
+ sourceRef: z.object({
37354
+ tag: z.literal("signed_source_ref"),
37355
+ token: signedMailingListSourceTokenSchema
36507
37356
  })
36508
37357
  }),
36509
- newsletterSourceCommonSchema.extend({
36510
- source: z.literal("legacy-direct-list"),
36511
- listId: z.string().nullable()
36512
- })
37358
+ newsletterSourceCommonSchema.extend({ source: z.literal("preview") })
36513
37359
  ]);
36514
37360
  const newsletterDisplaySchema = z.object({
36515
37361
  kind: z.literal("newsletter-form"),
37362
+ availability: z.enum(["ready", "unavailable"]),
36516
37363
  className: z.string().nullable(),
36517
37364
  buttonLabel: z.string(),
37365
+ successMessage: z.string(),
36518
37366
  buttonVariant: newsletterButtonVariantSchema,
36519
- successMessage: z.string().nullable(),
36520
37367
  privacyNote: z.string().nullable(),
36521
- fields: z.array(newsletterFieldSchema)
37368
+ fields: z.array(newsletterFieldSchema),
37369
+ choices: z.array(z.object({
37370
+ id: z.string(),
37371
+ label: z.string()
37372
+ }))
36522
37373
  });
36523
37374
  const newsletterHydrationSchema = z.object({
36524
37375
  target: z.discriminatedUnion("tag", [
36525
37376
  z.object({
36526
37377
  tag: z.literal("block-source"),
36527
- destinationRef: z.object({
37378
+ sourceRef: z.object({
36528
37379
  tag: z.literal("block_ref"),
36529
- blockId: newsletterSignupBlockIdSchema
37380
+ blockId: mailingListSignupBlockIdSchema,
37381
+ contentVersionId: mailingListContentVersionIdSchema
36530
37382
  }).nullable()
36531
37383
  }),
36532
37384
  z.object({
36533
37385
  tag: z.literal("signed-footer-source"),
36534
- destinationRef: z.object({
36535
- tag: z.literal("signed_destination_ref"),
36536
- token: signedNewsletterDestinationRefSchema
37386
+ sourceRef: z.object({
37387
+ tag: z.literal("signed_source_ref"),
37388
+ token: signedMailingListSourceTokenSchema
36537
37389
  })
36538
37390
  }),
36539
- z.object({
36540
- tag: z.literal("legacy-direct-list"),
36541
- listId: z.string().nullable()
36542
- })
37391
+ z.object({ tag: z.literal("preview") })
37392
+ ]),
37393
+ setupRevision: z.number().int().positive().nullable(),
37394
+ choiceProvider: z.enum([
37395
+ "native",
37396
+ "brevo",
37397
+ "mailchimp"
37398
+ ]).nullable(),
37399
+ choicePresentation: z.enum([
37400
+ "hidden",
37401
+ "automatic",
37402
+ "visitor_choice"
36543
37403
  ]),
36544
- preset: newsletterPresetSchema,
36545
- includePhone: z.boolean(),
36546
- tags: z.string().nullable().optional(),
36547
37404
  spamProtectionEnabled: z.boolean().optional()
36548
37405
  });
36549
37406
  const newsletterRenderSchema = z.object({
@@ -36555,16 +37412,26 @@ z.object({
36555
37412
  apiBaseUrl: z.string().optional()
36556
37413
  });
36557
37414
  function buildNewsletterDisplay(source) {
36558
- const preset = source.preset ?? "emailOnly";
36559
- const includePhone = source.includePhone ?? false;
37415
+ const context = source.mailingList;
37416
+ const form = context?.tag === "configured" ? context.form : {
37417
+ fields: { preset: "emailOnly" },
37418
+ includeOptionalPhone: false,
37419
+ buttonLabel: "Subscribe",
37420
+ successMessage: DEFAULT_MAILING_LIST_SUCCESS_MESSAGE,
37421
+ privacyNote: null
37422
+ };
37423
+ const targeting = source.targeting ?? { mode: "default" };
37424
+ const choices = resolveRuntimeChoices(context, targeting);
36560
37425
  return {
36561
37426
  kind: "newsletter-form",
37427
+ availability: runtimeTargetingIsAvailable(context, targeting, choices) ? "ready" : "unavailable",
36562
37428
  className: source.className ?? null,
36563
- buttonLabel: source.buttonLabel?.trim() || "Subscribe",
37429
+ buttonLabel: form.buttonLabel,
37430
+ successMessage: form.successMessage,
36564
37431
  buttonVariant: source.buttonVariant ?? "primary",
36565
- successMessage: source.successMessage ?? "Thanks for subscribing!",
36566
- privacyNote: source.privacyNote ?? null,
36567
- fields: getPresetFields(preset, { includePhone })
37432
+ privacyNote: form.privacyNote,
37433
+ fields: getGlobalFormFields(form),
37434
+ choices
36568
37435
  };
36569
37436
  }
36570
37437
  const newsletterFormBlockRuntime = defineProgressiveBlockRuntime({
@@ -36574,14 +37441,15 @@ const newsletterFormBlockRuntime = defineProgressiveBlockRuntime({
36574
37441
  render: createZodCodec(newsletterRenderSchema)
36575
37442
  },
36576
37443
  buildRender: (source) => {
36577
- const runtimeSource = source.source === "block" ? deriveNewsletterSignupRuntimeSource(source) : null;
37444
+ const targeting = source.targeting ?? { mode: "default" };
37445
+ const presentation = planMailingListChoicePresentation(targeting);
36578
37446
  return {
36579
37447
  display: buildNewsletterDisplay(source),
36580
37448
  hydration: {
36581
37449
  target: projectNewsletterFormHydrationTarget(source),
36582
- preset: source.preset ?? "emailOnly",
36583
- includePhone: source.includePhone ?? false,
36584
- tags: runtimeSource ? runtimeSource.tags : source.tags,
37450
+ setupRevision: source.mailingList?.tag === "configured" ? source.mailingList.revision : null,
37451
+ choiceProvider: targeting.mode === "custom" ? targeting.provider : null,
37452
+ choicePresentation: presentation.tag,
36585
37453
  spamProtectionEnabled: source.spamProtectionEnabled
36586
37454
  }
36587
37455
  };
@@ -36590,35 +37458,87 @@ const newsletterFormBlockRuntime = defineProgressiveBlockRuntime({
36590
37458
  function projectNewsletterFormHydrationTarget(source) {
36591
37459
  switch (source.source) {
36592
37460
  case "block": {
36593
- const destinationRef = buildNewsletterSignupBlockRef(source.blockId);
36594
- if (destinationRef?.tag === "block_ref") return {
37461
+ const sourceRef = buildMailingListSignupBlockSourceRef(source.blockId, source.contentVersionId);
37462
+ if (sourceRef?.tag === "block_ref") return {
36595
37463
  tag: "block-source",
36596
- destinationRef
37464
+ sourceRef
36597
37465
  };
36598
37466
  return {
36599
- tag: "legacy-direct-list",
36600
- listId: source.listId ?? null
37467
+ tag: "block-source",
37468
+ sourceRef: null
36601
37469
  };
36602
37470
  }
36603
37471
  case "signed-footer": return {
36604
37472
  tag: "signed-footer-source",
36605
- destinationRef: source.destinationRef
36606
- };
36607
- case "legacy-direct-list": return {
36608
- tag: "legacy-direct-list",
36609
- listId: source.listId
37473
+ sourceRef: source.sourceRef
36610
37474
  };
37475
+ case "preview": return { tag: "preview" };
36611
37476
  default: return assertNever$3(source);
36612
37477
  }
36613
37478
  }
36614
- function parseRequiredNewsletterSignupBlockId(value) {
36615
- const parsed = parseNewsletterSignupBlockId(value);
36616
- if (!parsed) throw new Error("Newsletter signup block destination ref requires blockId");
37479
+ function resolveRuntimeChoices(context, targeting) {
37480
+ if (context?.tag !== "configured" || targeting.mode !== "custom" || targeting.selection.tag !== "visitor_choice" || context.provider.provider !== targeting.provider) return [];
37481
+ switch (targeting.provider) {
37482
+ case "native": {
37483
+ const offered = new Set(targeting.selection.offeredTopicIds);
37484
+ return context.provider.provider === "native" ? context.provider.topics.filter((item) => offered.has(item.id)).map((item) => ({
37485
+ id: item.id,
37486
+ label: item.name
37487
+ })) : [];
37488
+ }
37489
+ case "brevo": {
37490
+ const offered = new Set(targeting.selection.offeredListIds);
37491
+ return context.provider.provider === "brevo" ? context.provider.lists.filter((item) => offered.has(item.id)).map((item) => ({
37492
+ id: String(item.id),
37493
+ label: item.name
37494
+ })) : [];
37495
+ }
37496
+ case "mailchimp": {
37497
+ const offered = new Set(targeting.selection.offeredInterestIds);
37498
+ return (context.provider.provider === "mailchimp" ? context.provider.audiences.find((item) => item.id === targeting.audienceId) : void 0)?.interests.filter((item) => offered.has(item.id)).map((item) => ({
37499
+ id: item.id,
37500
+ label: item.name
37501
+ })) ?? [];
37502
+ }
37503
+ }
37504
+ }
37505
+ function runtimeTargetingIsAvailable(context, targeting, choices) {
37506
+ if (context?.tag !== "configured") return false;
37507
+ const provider = context.provider;
37508
+ if (targeting.mode === "default") switch (provider.provider) {
37509
+ case "native": return provider.topics.some((item) => item.id === provider.defaultTopicId);
37510
+ case "brevo": return provider.lists.some((item) => item.id === provider.defaultListId);
37511
+ case "mailchimp": return provider.audiences.some((item) => item.id === provider.defaultAudienceId);
37512
+ }
37513
+ if (targeting.provider !== provider.provider) return false;
37514
+ switch (targeting.provider) {
37515
+ case "native": return provider.provider === "native" && nativeTargetIsAvailable(provider, targeting, choices);
37516
+ case "brevo": return provider.provider === "brevo" && brevoTargetIsAvailable(provider, targeting, choices);
37517
+ case "mailchimp": return provider.provider === "mailchimp" && mailchimpTargetIsAvailable(provider, targeting, choices);
37518
+ }
37519
+ }
37520
+ function nativeTargetIsAvailable(provider, targeting, choices) {
37521
+ const ids = targeting.selection.tag === "fixed" ? targeting.selection.topicIds : targeting.selection.offeredTopicIds;
37522
+ return ids.every((id) => provider.topics.some((item) => item.id === id)) && (targeting.selection.tag !== "visitor_choice" || choices.length === ids.length);
37523
+ }
37524
+ function brevoTargetIsAvailable(provider, targeting, choices) {
37525
+ const ids = targeting.selection.tag === "fixed" ? targeting.selection.listIds : targeting.selection.offeredListIds;
37526
+ return ids.every((id) => provider.lists.some((item) => item.id === id)) && (targeting.selection.tag !== "visitor_choice" || choices.length === ids.length);
37527
+ }
37528
+ function mailchimpTargetIsAvailable(provider, targeting, choices) {
37529
+ const audience = provider.audiences.find((item) => item.id === targeting.audienceId);
37530
+ if (!audience) return false;
37531
+ const ids = targeting.selection.tag === "fixed" ? targeting.selection.interestIds : targeting.selection.offeredInterestIds;
37532
+ return ids.every((id) => audience.interests.some((item) => item.id === id)) && (targeting.selection.tag !== "visitor_choice" || choices.length === ids.length);
37533
+ }
37534
+ function parseRequiredMailingListSignupBlockId(value) {
37535
+ const parsed = parseMailingListBlockId(value);
37536
+ if (!parsed) throw new Error("Mailing-list signup block source ref requires blockId");
36617
37537
  return parsed;
36618
37538
  }
36619
- function parseRequiredSignedNewsletterDestinationRef(value) {
36620
- const parsed = parseSignedNewsletterDestinationRef(value);
36621
- if (!parsed) throw new Error("Newsletter signup signed destination ref requires token");
37539
+ function parseRequiredMailingListSignedSourceToken(value) {
37540
+ const parsed = parseMailingListSignedSourceToken(value);
37541
+ if (!parsed) throw new Error("Mailing-list signup signed source ref requires token");
36622
37542
  return parsed;
36623
37543
  }
36624
37544
  //#endregion
@@ -36651,65 +37571,79 @@ const editorialSplitLayout = styledSection({
36651
37571
  spacing: "comfortable",
36652
37572
  background: "surface"
36653
37573
  });
36654
- const newsletterSignupBlockDefinition = {
36655
- manifest: createBlockManifest({
36656
- id: "block.newsletter-signup",
36657
- title: "Newsletter Signup",
36658
- titleSource: "title",
36659
- description: "Newsletter subscription form with configurable field presets.",
36660
- category: "interactive",
36661
- contentSource: { kind: "inline" },
36662
- fragments: [{
36663
- fragment: newsletterCopyFragment,
36664
- fieldPriority: 0
36665
- }, {
36666
- fragment: newsletterFormFragment,
36667
- fieldPriority: 1
36668
- }],
36669
- layout: stackedLayout,
36670
- variants: {
36671
- stacked: stackedLayout,
36672
- inline: inlineLayout,
36673
- "editorial-split": editorialSplitLayout
36674
- },
36675
- defaultVariant: "stacked",
36676
- variantOptions: {
36677
- stacked: {
36678
- label: "Stacked",
36679
- description: "Vertical layout with fields stacked"
36680
- },
36681
- inline: {
36682
- label: "Inline",
36683
- description: "Horizontal layout (email + button side by side)"
36684
- },
36685
- "editorial-split": {
36686
- label: "Editorial split",
36687
- description: "Copy and form in balanced side-by-side columns, stacked on mobile."
36688
- }
36689
- },
36690
- styleTokens: {
36691
- background: "surface",
36692
- typography: "body",
36693
- spacing: "md"
37574
+ const newsletterSignupManifest = createBlockManifest({
37575
+ id: "block.newsletter-signup",
37576
+ title: "Newsletter Signup",
37577
+ titleSource: "title",
37578
+ description: "Newsletter subscription form with configurable field presets.",
37579
+ category: "interactive",
37580
+ contentSource: { kind: "inline" },
37581
+ fragments: [{
37582
+ fragment: newsletterCopyFragment,
37583
+ fieldPriority: 0
37584
+ }, {
37585
+ fragment: newsletterFormFragment,
37586
+ fieldPriority: 1
37587
+ }],
37588
+ layout: stackedLayout,
37589
+ variants: {
37590
+ stacked: stackedLayout,
37591
+ inline: inlineLayout,
37592
+ "editorial-split": editorialSplitLayout
37593
+ },
37594
+ defaultVariant: "stacked",
37595
+ variantOptions: {
37596
+ stacked: {
37597
+ label: "Stacked",
37598
+ description: "Vertical layout with fields stacked"
36694
37599
  },
36695
- behaviours: {
36696
- supportsThemeSwitching: true,
36697
- inlineEditing: false,
36698
- animation: false,
36699
- paletteHidden: false
37600
+ inline: {
37601
+ label: "Inline",
37602
+ description: "Horizontal layout (email + button side by side)"
36700
37603
  },
36701
- tags: [
36702
- "newsletter",
36703
- "signup",
36704
- "email",
36705
- "subscribe",
36706
- "subscription",
36707
- "mailchimp",
36708
- "marketing",
36709
- "lead-capture"
36710
- ],
36711
- icon: "Mail"
36712
- }),
37604
+ "editorial-split": {
37605
+ label: "Editorial split",
37606
+ description: "Copy and form in balanced side-by-side columns, stacked on mobile."
37607
+ }
37608
+ },
37609
+ styleTokens: {
37610
+ background: "surface",
37611
+ typography: "body",
37612
+ spacing: "md"
37613
+ },
37614
+ behaviours: {
37615
+ supportsThemeSwitching: true,
37616
+ inlineEditing: false,
37617
+ animation: false,
37618
+ paletteHidden: false
37619
+ },
37620
+ tags: [
37621
+ "newsletter",
37622
+ "signup",
37623
+ "email",
37624
+ "subscribe",
37625
+ "subscription",
37626
+ "mailchimp",
37627
+ "marketing",
37628
+ "lead-capture"
37629
+ ],
37630
+ icon: "Mail"
37631
+ });
37632
+ function sanitizeNewsletterSignupPublicContent(content) {
37633
+ if (typeof content !== "object" || content === null || Array.isArray(content)) return content;
37634
+ const value = content;
37635
+ return {
37636
+ title: value.title,
37637
+ subtitle: value.subtitle,
37638
+ targeting: value.targeting,
37639
+ buttonVariant: value.buttonVariant,
37640
+ mailingListSource: value.mailingListSource,
37641
+ mailingListSourceToken: value.mailingListSourceToken,
37642
+ _sectionStyles: value._sectionStyles
37643
+ };
37644
+ }
37645
+ const newsletterSignupBlockDefinition = {
37646
+ manifest: newsletterSignupManifest,
36713
37647
  runtime: newsletterFormBlockRuntime
36714
37648
  };
36715
37649
  //#endregion
@@ -37991,6 +38925,14 @@ const systemBlockDefinitions = [
37991
38925
  weight: "standard"
37992
38926
  })]
37993
38927
  })),
38928
+ withDesignCapability("block.appointment-services", appointmentServicesBlockDefinition, sectionOnly(), defineBlockDesignMetadata({
38929
+ flow: conversionFlow,
38930
+ layoutProfiles: [layoutProfile({
38931
+ variantKey: "default",
38932
+ family: "stack",
38933
+ weight: "standard"
38934
+ })]
38935
+ })),
37994
38936
  withDesignCapability("block.weekly-slot-availability", weeklySlotAvailabilityBlockDefinition, sectionOnly(), defineBlockDesignMetadata({
37995
38937
  flow: offeringsFlow,
37996
38938
  layoutProfiles: [layoutProfile({
@@ -39070,8 +40012,12 @@ function shouldSkipResolvedLoader(input) {
39070
40012
  * ```
39071
40013
  */
39072
40014
  async function prefetchBlockData$1(page, context, options) {
40015
+ return (await prefetchBlockDataWithFailures(page, context, options)).resolvedData;
40016
+ }
40017
+ async function prefetchBlockDataWithFailures(page, context, options) {
39073
40018
  const { apiClient, isValidEndpoint, onError, getCustomBlockLoaders, getBlockDefinition: getBlockDefinition$1 = getBlockDefinition, resolveParamsBindings: resolveParamsBindings$1 = resolveParamsBindings } = options;
39074
40019
  const results = {};
40020
+ const loaderFailures = {};
39075
40021
  const tasks = [];
39076
40022
  for (const block of page.blocks) {
39077
40023
  const blockId = block.id;
@@ -39119,6 +40065,11 @@ async function prefetchBlockData$1(page, context, options) {
39119
40065
  const blockResults = results[blockId] ?? (results[blockId] = {});
39120
40066
  blockResults[key] = data;
39121
40067
  } catch (error) {
40068
+ const blockFailures = loaderFailures[blockId] ?? (loaderFailures[blockId] = {});
40069
+ blockFailures[key] = {
40070
+ endpoint,
40071
+ params
40072
+ };
39122
40073
  if (onError) onError(error, {
39123
40074
  block: block.kind,
39124
40075
  loader: key
@@ -39128,7 +40079,10 @@ async function prefetchBlockData$1(page, context, options) {
39128
40079
  }
39129
40080
  }
39130
40081
  if (tasks.length > 0) await Promise.all(tasks);
39131
- return results;
40082
+ return {
40083
+ resolvedData: results,
40084
+ loaderFailures
40085
+ };
39132
40086
  }
39133
40087
  //#endregion
39134
40088
  //#region ../blocks/src/system/data/loaderEndpoints.ts
@@ -39478,7 +40432,17 @@ const riverbankSiteConfigInputSchema = z.object({
39478
40432
  z.object({
39479
40433
  config: riverbankSiteConfigInputSchema,
39480
40434
  forceContentTypes: z.boolean().optional(),
39481
- mode: z.enum(["apply", "preview"]).optional()
40435
+ mode: z.enum(["apply", "preview"]).optional(),
40436
+ expectedMailingListProviderScope: z.unknown().transform((value, ctx) => {
40437
+ if (value === void 0) return void 0;
40438
+ const parsed = parseMailingListProviderScope(value);
40439
+ if (parsed.ok) return parsed.value;
40440
+ ctx.addIssue({
40441
+ code: "custom",
40442
+ message: "Invalid mailing-list provider scope"
40443
+ });
40444
+ return z.NEVER;
40445
+ }).optional()
39482
40446
  }).strict();
39483
40447
  //#endregion
39484
40448
  //#region ../api/src/sdkThemeWire.ts
@@ -40612,9 +41576,11 @@ function convertPageResponseBlock(block) {
40612
41576
  if (typeof block.id !== "string" && block.id !== null) throw new Error(`Invalid block id in page: expected string or null, got ${typeof block.id}`);
40613
41577
  if (typeof block.kind !== "string") throw new Error(`Invalid block kind in page: expected string, got ${typeof block.kind}`);
40614
41578
  if (typeof block.purpose !== "string") throw new Error(`Invalid block purpose in page: expected string, got ${typeof block.purpose}`);
41579
+ 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}`);
40615
41580
  const admission = readInvalidBlockAdmission(block.admission);
40616
41581
  return {
40617
41582
  id: block.id,
41583
+ ...block.contentVersionId !== void 0 ? { contentVersionId: block.contentVersionId } : {},
40618
41584
  kind: block.kind,
40619
41585
  purpose: block.purpose,
40620
41586
  content: sanitizeSdkRuntimeBlockContent(block.kind, readContentRecord(block.content) ?? {}),
@@ -40647,6 +41613,7 @@ function projectRenderablePageOutline(page) {
40647
41613
  ...page,
40648
41614
  blocks: page.blocks.flatMap((block) => block.admission.kind === "renderable" ? [{
40649
41615
  id: block.id,
41616
+ ...block.contentVersionId !== void 0 ? { contentVersionId: block.contentVersionId } : {},
40650
41617
  kind: block.kind,
40651
41618
  purpose: block.purpose,
40652
41619
  content: block.admission.content,
@@ -40657,6 +41624,7 @@ function projectRenderablePageOutline(page) {
40657
41624
  function admitSdkRuntimePageBlock(block, customBlocks) {
40658
41625
  const base = {
40659
41626
  id: block.id,
41627
+ ...block.contentVersionId !== void 0 ? { contentVersionId: block.contentVersionId } : {},
40660
41628
  kind: block.kind,
40661
41629
  purpose: block.purpose,
40662
41630
  ...block.bindings ? { bindings: block.bindings } : {}
@@ -40832,6 +41800,7 @@ function usePage(params) {
40832
41800
  theme: requireSdkTheme(site.theme, siteId),
40833
41801
  siteId,
40834
41802
  resolvedData,
41803
+ mailingList: site.mailingList,
40835
41804
  sdkConfig: site.sdkConfig ?? null,
40836
41805
  supabaseUrl: site.supabaseUrl,
40837
41806
  ...mediaAssets ? { mediaAssets } : {}