@riverbankcms/sdk 0.130.2 → 0.134.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 (405) hide show
  1. package/CHANGELOG.md +13 -3
  2. package/dist/{PreviewEditorSidebar-BY-1QdE2.mjs → PreviewEditorSidebar-DfRhJPFQ.mjs} +351 -95
  3. package/dist/{PreviewEditorUI-BS34jI9_.mjs → PreviewEditorUI-Dppxcr_g.mjs} +3 -3
  4. package/dist/{PreviewQueryProvider-BD0kOjtI.mjs → PreviewQueryProvider-D51gQaG3.mjs} +1 -1
  5. package/dist/{SdkPreviewModeRuntime-B1pWnhu-.mjs → SdkPreviewModeRuntime-8CyGCXir.mjs} +91 -21
  6. package/dist/{SiteChromeCustomizeContext-BhUG_72i.mjs → SiteChromeCustomizeContext-DVMTMvqA.mjs} +6896 -4335
  7. package/dist/_dts/ai/src/contracts/proposals.d.ts +1105 -533
  8. package/dist/_dts/ai/src/contracts/siteStyleProposalSchemas.d.ts +363 -276
  9. package/dist/_dts/api/src/accountApi.d.ts +5 -5
  10. package/dist/_dts/api/src/appointmentEndpointDefinitions.d.ts +1 -1
  11. package/dist/_dts/api/src/bookingConfig.d.ts +13 -9
  12. package/dist/_dts/api/src/bookingManagementEndpoints.d.ts +8 -19
  13. package/dist/_dts/api/src/bookingManagementEventEndpointTypes.d.ts +31 -2
  14. package/dist/_dts/api/src/bookingOperations.d.ts +2 -14
  15. package/dist/_dts/api/src/bookingVerticals.d.ts +1 -140
  16. package/dist/_dts/api/src/bookings.d.ts +2 -2
  17. package/dist/_dts/api/src/commercePortalEndpoints.d.ts +45 -12
  18. package/dist/_dts/api/src/contentRuntime.d.ts +3 -2
  19. package/dist/_dts/api/src/courseEndpointDefinitions.d.ts +2 -2
  20. package/dist/_dts/api/src/courses.d.ts +1 -19
  21. package/dist/_dts/api/src/endpoints.d.ts +469 -349
  22. package/dist/_dts/api/src/event-destination-policy.d.ts +1 -1
  23. package/dist/_dts/api/src/eventManagementContracts.d.ts +91 -1
  24. package/dist/_dts/api/src/eventManagementEndpointDefinitions.d.ts +32 -0
  25. package/dist/_dts/api/src/giftingDashboard.d.ts +117 -0
  26. package/dist/_dts/api/src/giftingEndpointDefinitions.d.ts +124 -0
  27. package/dist/_dts/api/src/index.d.ts +4 -4
  28. package/dist/_dts/api/src/indexCoreTypes.d.ts +1 -1
  29. package/dist/_dts/api/src/indexExtendedTypes.d.ts +1 -1
  30. package/dist/_dts/api/src/media.d.ts +1 -0
  31. package/dist/_dts/api/src/navigation/contracts.d.ts +9 -6
  32. package/dist/_dts/api/src/navigation/dashboardBookingsNav.d.ts +3 -4
  33. package/dist/_dts/api/src/navigation/linkResolver.d.ts +6 -2
  34. package/dist/_dts/api/src/navigation/types.d.ts +23 -6
  35. package/dist/_dts/api/src/navigation.d.ts +1 -1
  36. package/dist/_dts/api/src/publicBookingService.d.ts +15 -0
  37. package/dist/_dts/api/src/publicEventEndpointDefinitions.d.ts +11 -0
  38. package/dist/_dts/api/src/publicExperience/eventEndpoints.d.ts +28 -13
  39. package/dist/_dts/api/src/publicExperience/sharedTypes.d.ts +2 -0
  40. package/dist/_dts/api/src/publicExperience/wholeSeriesEndpoints.d.ts +3 -0
  41. package/dist/_dts/api/src/sdk-event-upsert.d.ts +3 -3
  42. package/dist/_dts/api/src/sdkBookingVerticalContracts.d.ts +29 -0
  43. package/dist/_dts/api/src/sdkContracts.d.ts +9 -32
  44. package/dist/_dts/api/src/sdkEndpointDefinitions.d.ts +23 -0
  45. package/dist/_dts/api/src/sdkSettingsContracts.d.ts +25 -0
  46. package/dist/_dts/api/src/sdkThemeCatalogContracts.d.ts +20 -0
  47. package/dist/_dts/api/src/sdkThemeWire.d.ts +64 -54
  48. package/dist/_dts/api/src/siteBanner.d.ts +4 -2
  49. package/dist/_dts/api/src/siteOnboarding.d.ts +3 -3
  50. package/dist/_dts/api/src/sitePlatformEndpoints.d.ts +4 -10
  51. package/dist/_dts/api/src/siteRuntimeEndpoints.d.ts +0 -3
  52. package/dist/_dts/api/src/types.d.ts +2 -3
  53. package/dist/_dts/api/src/webhooks.d.ts +12 -12
  54. package/dist/_dts/blocks/src/PageRenderer.d.ts +2 -13
  55. package/dist/_dts/blocks/src/client.d.ts +1 -1
  56. package/dist/_dts/blocks/src/contracts/non-block-islands.d.ts +9 -0
  57. package/dist/_dts/blocks/src/contracts/proof-block-islands.d.ts +54 -116
  58. package/dist/_dts/blocks/src/index.d.ts +4 -3
  59. package/dist/_dts/blocks/src/primitives/content/components/RichText.d.ts +2 -2
  60. package/dist/_dts/blocks/src/primitives/content/primitives.d.ts +1 -0
  61. package/dist/_dts/blocks/src/subroutes/fold.d.ts +2 -1
  62. package/dist/_dts/blocks/src/system/blocks/courses/shared/index.d.ts +0 -3
  63. package/dist/_dts/blocks/src/system/blocks/courses/shared/pricing.d.ts +2 -50
  64. package/dist/_dts/blocks/src/system/blocks/courses/shared/schemas.d.ts +1 -929
  65. package/dist/_dts/blocks/src/system/blocks/courses/shared/types.d.ts +1 -97
  66. package/dist/_dts/blocks/src/system/blocks/event-details.d.ts +39 -6
  67. package/dist/_dts/blocks/src/system/blocks/events/event-calendar.d.ts +2 -1
  68. package/dist/_dts/blocks/src/system/blocks/events/event-listing.d.ts +3 -3
  69. package/dist/_dts/blocks/src/system/blocks/events/event-spotlight.d.ts +2 -3
  70. package/dist/_dts/blocks/src/system/blocks/events/shared/filtering.d.ts +2 -2
  71. package/dist/_dts/blocks/src/system/blocks/events/shared/schemas.d.ts +42 -20
  72. package/dist/_dts/blocks/src/system/blocks/events/shared/types.d.ts +5 -9
  73. package/dist/_dts/blocks/src/system/blocks/events/whole-series/index.d.ts +3 -0
  74. package/dist/_dts/blocks/src/system/blocks/events/whole-series/pricing.d.ts +50 -0
  75. package/dist/_dts/blocks/src/system/blocks/events/whole-series/schemas.d.ts +135 -0
  76. package/dist/_dts/blocks/src/system/blocks/events/whole-series/types.d.ts +84 -0
  77. package/dist/_dts/blocks/src/system/blocks/location-map.d.ts +4 -4
  78. package/dist/_dts/blocks/src/system/blocks/media-text.d.ts +148 -148
  79. package/dist/_dts/blocks/src/system/blocks/offerings-preview/model.d.ts +3 -2
  80. package/dist/_dts/blocks/src/system/blocks/shared/bookingConsent.d.ts +36 -0
  81. package/dist/_dts/blocks/src/system/fields/boxStyles.d.ts +7 -8
  82. package/dist/_dts/blocks/src/system/manifest/hydrateLinks.d.ts +9 -2
  83. package/dist/_dts/blocks/src/system/manifest/resolveBlockData.d.ts +8 -0
  84. package/dist/_dts/blocks/src/system/manifest/schema.d.ts +79 -79
  85. package/dist/_dts/blocks/src/system/node/validation-constants.d.ts +1 -1
  86. package/dist/_dts/blocks/src/system/runtime/api/types/appointments.d.ts +2 -11
  87. package/dist/_dts/blocks/src/system/runtime/api/types/courses.d.ts +2 -0
  88. package/dist/_dts/blocks/src/system/runtime/api/types/events.d.ts +1 -0
  89. package/dist/_dts/blocks/src/system/runtime/blockComposition.d.ts +1 -1
  90. package/dist/_dts/blocks/src/system/runtime/components/multi-step/DynamicFormFields.d.ts +3 -19
  91. package/dist/_dts/blocks/src/system/runtime/components/registry.client.d.ts +45 -72
  92. package/dist/_dts/blocks/src/system/runtime/components/runtime-backed-blocks.d.ts +22 -37
  93. package/dist/_dts/blocks/src/system/runtime/hooks/useHeadlessWholeSeriesRegistrationFlow.d.ts +6 -6
  94. package/dist/_dts/blocks/src/system/runtime/hooks/useSelectedAppointmentConsentForm.d.ts +2 -0
  95. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.consent.d.ts +10 -0
  96. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.field-values.d.ts +4 -0
  97. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.fields.d.ts +21 -0
  98. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.headless.state.d.ts +2 -1
  99. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.interactive.d.ts +38 -144
  100. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.state.d.ts +5 -19
  101. package/dist/_dts/blocks/src/system/runtime/nodes/booking-runtime-sources.d.ts +3 -2
  102. package/dist/_dts/blocks/src/system/runtime/nodes/course-page-surface-scope.d.ts +2 -5
  103. package/dist/_dts/blocks/src/system/runtime/nodes/course-registration.client.d.ts +4 -2
  104. package/dist/_dts/blocks/src/system/runtime/nodes/course-registration.interactive.d.ts +19 -7
  105. package/dist/_dts/blocks/src/system/runtime/nodes/event-details/logic.d.ts +25 -4
  106. package/dist/_dts/blocks/src/system/runtime/nodes/event-details/presentation.d.ts +75 -0
  107. package/dist/_dts/blocks/src/system/runtime/nodes/event-details/view.d.ts +4 -1
  108. package/dist/_dts/blocks/src/system/runtime/nodes/event-details.client.d.ts +5 -2
  109. package/dist/_dts/blocks/src/system/runtime/nodes/event-details.server.d.ts +5 -2
  110. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/AttendeeDetailsStep.d.ts +2 -0
  111. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/PaymentSelectionStep.d.ts +4 -0
  112. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/RegistrationClosedState.d.ts +5 -0
  113. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/SiteCreditPreviewPanel.d.ts +6 -0
  114. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/eventPaymentOptions.d.ts +2 -0
  115. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/hooks.d.ts +17 -0
  116. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/registrationSurface.d.ts +21 -4
  117. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/siteCreditPreview.d.ts +51 -0
  118. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/types.d.ts +3 -3
  119. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventRegistrationWizard.d.ts +6 -4
  120. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/validation.d.ts +2 -1
  121. package/dist/_dts/blocks/src/system/runtime/nodes/{course-registration → event-registration/whole-series}/BookingModeStep.d.ts +1 -1
  122. package/dist/_dts/blocks/src/system/runtime/nodes/{course-registration → event-registration/whole-series}/CheckIcon.d.ts +1 -1
  123. package/dist/_dts/blocks/src/system/runtime/nodes/{course-registration → event-registration/whole-series}/ErrorStep.d.ts +1 -1
  124. package/dist/_dts/blocks/src/system/runtime/nodes/{course-registration → event-registration/whole-series}/MembershipHero.d.ts +3 -3
  125. package/dist/_dts/blocks/src/system/runtime/nodes/{course-registration → event-registration/whole-series}/PaymentFailedStep.d.ts +1 -1
  126. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/whole-series/StepIndicator.d.ts +6 -0
  127. package/dist/_dts/blocks/src/system/runtime/nodes/{course-registration → event-registration/whole-series}/VerifyingTimeoutStep.d.ts +1 -1
  128. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/whole-series/WholeSeriesRegistrationActiveSteps.d.ts +9 -0
  129. package/dist/_dts/blocks/src/system/runtime/nodes/{course-registration/CourseRegistrationErrorBoundary.d.ts → event-registration/whole-series/WholeSeriesRegistrationErrorBoundary.d.ts} +5 -2
  130. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/whole-series/WholeSeriesRegistrationTerminalContent.d.ts +8 -0
  131. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/whole-series/WholeSeriesRegistrationWizard.d.ts +8 -0
  132. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/whole-series/components.d.ts +46 -0
  133. package/dist/_dts/blocks/src/system/runtime/nodes/{course-registration → event-registration/whole-series}/index.d.ts +4 -4
  134. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/whole-series/presentation.d.ts +7 -0
  135. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/whole-series/pricing.d.ts +14 -0
  136. package/dist/_dts/blocks/src/system/runtime/nodes/{course-registration → event-registration/whole-series}/types.d.ts +18 -16
  137. package/dist/_dts/blocks/src/system/runtime/nodes/{course-registration/useCourseEligibility.d.ts → event-registration/whole-series/useWholeSeriesEligibility.d.ts} +6 -6
  138. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/whole-series/useWholeSeriesPaymentVerification.d.ts +10 -0
  139. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/whole-series/useWholeSeriesRegistrationActions.d.ts +35 -0
  140. package/dist/_dts/blocks/src/system/runtime/nodes/{course-registration/useCourseRegistrationPortal.d.ts → event-registration/whole-series/useWholeSeriesRegistrationPortal.d.ts} +2 -2
  141. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/whole-series/useWholeSeriesRegistrationSelection.d.ts +35 -0
  142. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/whole-series/useWholeSeriesRegistrationWizard.d.ts +185 -0
  143. package/dist/_dts/blocks/src/system/runtime/nodes/{course-registration/useCourseWaitlistSelection.d.ts → event-registration/whole-series/useWholeSeriesWaitlistSelection.d.ts} +5 -5
  144. package/dist/_dts/blocks/src/system/runtime/nodes/{course-registration → event-registration/whole-series}/utils.d.ts +4 -4
  145. package/dist/_dts/blocks/src/system/runtime/nodes/{course-registration → event-registration/whole-series}/whole-series-registration.headless.contract.d.ts +7 -7
  146. package/dist/_dts/blocks/src/system/runtime/nodes/{course-registration → event-registration/whole-series}/whole-series-registration.headless.planning.d.ts +2 -2
  147. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/whole-series/wholeSeriesPageSurfaceScope.d.ts +17 -0
  148. package/dist/_dts/blocks/src/system/runtime/nodes/{course-registration/courseRegistrationViewState.d.ts → event-registration/whole-series/wholeSeriesRegistrationViewState.d.ts} +7 -7
  149. package/dist/_dts/blocks/src/system/runtime/nodes/{course-registration → event-registration/whole-series}/wizardSteps.d.ts +4 -4
  150. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration.interactive.d.ts +24 -54
  151. package/dist/_dts/blocks/src/system/runtime/nodes/events/EventCombined.client.d.ts +2 -0
  152. package/dist/_dts/blocks/src/system/runtime/nodes/events/EventCombined.interactive.d.ts +3 -0
  153. package/dist/_dts/blocks/src/system/runtime/nodes/events/EventListing.interactive.d.ts +12 -11
  154. package/dist/_dts/blocks/src/system/runtime/nodes/events/EventListing.server.d.ts +3 -2
  155. package/dist/_dts/blocks/src/system/runtime/nodes/events/EventSpotlight.d.ts +3 -2
  156. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/EventCard.d.ts +3 -2
  157. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/EventDetailModal.d.ts +4 -3
  158. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/EventModalCloseButton.d.ts +7 -0
  159. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/EventModals.d.ts +4 -3
  160. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/WeekBoardView.d.ts +14 -0
  161. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/eventCollectionContract.d.ts +51 -14
  162. package/dist/_dts/blocks/src/system/runtime/nodes/shared/MagicLinkForm.d.ts +1 -1
  163. package/dist/_dts/blocks/src/system/runtime/shared/components/BookingConsentAgreement.d.ts +7 -0
  164. package/dist/_dts/blocks/src/system/runtime/shared/components/DiscountCodeDisclosure.d.ts +12 -12
  165. package/dist/_dts/blocks/src/system/runtime/shared/types.d.ts +1 -0
  166. package/dist/_dts/blocks/src/system/runtime/shared/useWaitlistClaim.d.ts +1 -0
  167. package/dist/_dts/blocks/src/system/transforms/registry/_utils/boxStyleClassNames.d.ts +30 -11
  168. package/dist/_dts/blocks/src/system/transforms/registry/boxStyles.d.ts +15 -4
  169. package/dist/_dts/blocks/src/system/transforms/registry/index.d.ts +1 -0
  170. package/dist/_dts/blocks/src/system/transforms/typed.d.ts +1 -4
  171. package/dist/_dts/blocks/src/system/types/link.d.ts +7 -1
  172. package/dist/_dts/commerce/src/purchase/bookingInstalmentSchedule.d.ts +13 -0
  173. package/dist/_dts/commerce/src/purchase/cancellationPolicy.d.ts +7 -0
  174. package/dist/_dts/commerce/src/purchase/canonicalRefundPlanner.d.ts +48 -0
  175. package/dist/_dts/commerce/src/purchase/checkoutCollectionPlan.d.ts +39 -0
  176. package/dist/_dts/commerce/src/purchase/checkoutCommitPlan.d.ts +40 -0
  177. package/dist/_dts/commerce/src/purchase/checkoutDiscountContextPlanning.d.ts +80 -0
  178. package/dist/_dts/commerce/src/purchase/checkoutErrorCodes.d.ts +1 -0
  179. package/dist/_dts/commerce/src/purchase/checkoutOrderItemProjection.d.ts +22 -0
  180. package/dist/_dts/commerce/src/purchase/checkoutPaymentFlow.d.ts +50 -0
  181. package/dist/_dts/commerce/src/purchase/checkoutPaymentPlanPlanning.d.ts +30 -0
  182. package/dist/_dts/commerce/src/purchase/checkoutPaymentTermPlanning.d.ts +10 -0
  183. package/dist/_dts/commerce/src/purchase/checkoutPaymentTerms.d.ts +53 -0
  184. package/dist/_dts/commerce/src/purchase/checkoutQuantity.d.ts +8 -0
  185. package/dist/_dts/commerce/src/purchase/checkoutSessionMetadata.d.ts +76 -0
  186. package/dist/_dts/commerce/src/purchase/checkoutSettlement.d.ts +46 -0
  187. package/dist/_dts/commerce/src/purchase/checkoutStripeFinalizationPlanning.d.ts +12 -0
  188. package/dist/_dts/commerce/src/purchase/checkoutStripeSessionPlanning.d.ts +125 -0
  189. package/dist/_dts/commerce/src/purchase/checkoutValidatedItemPlanning.d.ts +55 -0
  190. package/dist/_dts/commerce/src/purchase/confirmationEmailPayment.d.ts +91 -0
  191. package/dist/_dts/commerce/src/purchase/discountApplication.d.ts +74 -0
  192. package/dist/_dts/commerce/src/purchase/index.d.ts +55 -0
  193. package/dist/_dts/commerce/src/purchase/oneTimeCheckoutPlanning.d.ts +86 -0
  194. package/dist/_dts/commerce/src/purchase/order-number.d.ts +33 -0
  195. package/dist/_dts/commerce/src/purchase/orderCancellationPlan.d.ts +19 -0
  196. package/dist/_dts/commerce/src/purchase/orderCompletionEmailPlan.d.ts +71 -0
  197. package/dist/_dts/commerce/src/purchase/orderConfirmationPlanning.d.ts +120 -0
  198. package/dist/_dts/commerce/src/purchase/orderFulfillmentPlan.d.ts +81 -0
  199. package/dist/_dts/commerce/src/purchase/orderFulfillmentResult.d.ts +8 -0
  200. package/dist/_dts/commerce/src/purchase/orderHistoryLedgerFilters.d.ts +1 -0
  201. package/dist/_dts/commerce/src/purchase/orderHistorySource.d.ts +11 -0
  202. package/dist/_dts/commerce/src/purchase/orderInstalmentAdminSettlement.d.ts +43 -0
  203. package/dist/_dts/commerce/src/purchase/orderInstalmentClosure.d.ts +29 -0
  204. package/dist/_dts/commerce/src/purchase/orderInstalmentLifecycle.d.ts +44 -0
  205. package/dist/_dts/commerce/src/purchase/orderInstalmentPayoff.d.ts +24 -0
  206. package/dist/_dts/commerce/src/purchase/orderInstalmentPlan.d.ts +40 -0
  207. package/dist/_dts/commerce/src/purchase/orderItemMetadata.d.ts +151 -0
  208. package/dist/_dts/commerce/src/purchase/orderItemSupport.d.ts +14 -0
  209. package/dist/_dts/commerce/src/purchase/orderListFilters.d.ts +3 -0
  210. package/dist/_dts/commerce/src/purchase/orderPaymentLinkPlanning.d.ts +60 -0
  211. package/dist/_dts/commerce/src/purchase/orderPaymentReceipt.d.ts +184 -0
  212. package/dist/_dts/commerce/src/purchase/orderPaymentState.d.ts +135 -0
  213. package/dist/_dts/commerce/src/purchase/orderPlanningTypes.d.ts +102 -0
  214. package/dist/_dts/commerce/src/purchase/orderRefundPlanning.d.ts +50 -0
  215. package/dist/_dts/commerce/src/purchase/orderRefundPolicy.d.ts +36 -0
  216. package/dist/_dts/commerce/src/purchase/orderTotals.d.ts +23 -0
  217. package/dist/_dts/commerce/src/purchase/orderTypes.d.ts +39 -0
  218. package/dist/_dts/commerce/src/purchase/pendingCheckoutSessionClaim.d.ts +1 -0
  219. package/dist/_dts/commerce/src/purchase/persistedCheckoutLines.d.ts +27 -0
  220. package/dist/_dts/commerce/src/purchase/protectedDepositRefundPolicy.d.ts +86 -0
  221. package/dist/_dts/commerce/src/purchase/refundPolicy.d.ts +8 -0
  222. package/dist/_dts/commerce/src/purchase/refundRailSplit.d.ts +40 -0
  223. package/dist/_dts/commerce/src/purchase/result.d.ts +2 -0
  224. package/dist/_dts/commerce/src/purchase/settlement.d.ts +97 -0
  225. package/dist/_dts/commerce/src/purchase/shopRefundPlanning.d.ts +43 -0
  226. package/dist/_dts/commerce/src/purchase/stateTransitions.d.ts +31 -0
  227. package/dist/_dts/commerce/src/purchase/stripeMinimumCharge.d.ts +10 -0
  228. package/dist/_dts/commerce/src/purchase/types.d.ts +168 -0
  229. package/dist/_dts/commerce/src/shop/shipmentEligibility.d.ts +14 -0
  230. package/dist/_dts/commerce/src/utils/assertNever.d.ts +1 -0
  231. package/dist/_dts/content-model/src/content-types/builtin-schemas.d.ts +4 -0
  232. package/dist/_dts/content-model/src/content-types/builtins.d.ts +4 -0
  233. package/dist/_dts/content-model/src/content-types/schema.d.ts +4 -4
  234. package/dist/_dts/core/src/booking-consent.d.ts +8 -0
  235. package/dist/_dts/core/src/booking-vertical-catalog.d.ts +741 -0
  236. package/dist/_dts/core/src/booking-vertical-config.d.ts +66 -0
  237. package/dist/_dts/core/src/booking-vertical-definitions.d.ts +68 -0
  238. package/dist/_dts/{api/src/bookingVerticalPreset.d.ts → core/src/booking-vertical-preset.d.ts} +1 -1
  239. package/dist/_dts/core/src/booking-verticals.d.ts +98 -0
  240. package/dist/_dts/core/src/event-page-selection.d.ts +22 -0
  241. package/dist/_dts/core/src/event-pricing.d.ts +5 -0
  242. package/dist/_dts/core/src/event-series-behaviour.d.ts +16 -0
  243. package/dist/_dts/core/src/index.d.ts +4 -0
  244. package/dist/_dts/db/src/generated/supabase/database.types.d.ts +81 -3
  245. package/dist/_dts/db/src/schemas/forms.d.ts +25 -25
  246. package/dist/_dts/db/src/types/jsonb.d.ts +1 -1
  247. package/dist/_dts/editor/src/primitives/rich-text/RichTextEditorSurface.d.ts +2 -1
  248. package/dist/_dts/editor/src/primitives/rich-text/config.d.ts +2 -1
  249. package/dist/_dts/editor/src/primitives/rich-text/toolbar/linkPopoverUtils.d.ts +3 -2
  250. package/dist/_dts/editor/src/primitives/rich-text/useRichTextEditor.d.ts +3 -4
  251. package/dist/_dts/media-core/src/fileUploadCompletion.d.ts +3 -0
  252. package/dist/_dts/media-core/src/fileUploadDurableFinalization.d.ts +2 -0
  253. package/dist/_dts/media-core/src/identifiers.d.ts +10 -0
  254. package/dist/_dts/media-core/src/mediaWriteNormalizer.d.ts +2 -6
  255. package/dist/_dts/media-core/src/types.d.ts +2 -1
  256. package/dist/_dts/media-core/src/usageScanner.d.ts +1 -1
  257. package/dist/_dts/media-editor/src/index.d.ts +2 -2
  258. package/dist/_dts/media-editor/src/mediaSelection.d.ts +1 -22
  259. package/dist/_dts/media-editor/src/useMediaSelection.d.ts +0 -9
  260. package/dist/_dts/preview-next/src/client/preview/ButtonHoverRoleControls.d.ts +10 -0
  261. package/dist/_dts/preview-next/src/client/preview/ButtonStylePicker.d.ts +3 -2
  262. package/dist/_dts/preview-next/src/client/preview/PreviewEditorSidebar.d.ts +3 -1
  263. package/dist/_dts/preview-next/src/client/preview/PreviewShell.d.ts +2 -1
  264. package/dist/_dts/preview-next/src/client/preview/PreviewShellLayout.d.ts +2 -1
  265. package/dist/_dts/preview-next/src/client/preview/StyleConfigurator.d.ts +3 -1
  266. package/dist/_dts/preview-next/src/client/preview/StyleConfiguratorWarningNotice.d.ts +7 -0
  267. package/dist/_dts/preview-next/src/client/preview/siteStylePreviewPlanner.d.ts +1 -1
  268. package/dist/_dts/sdk/src/bookings/types.d.ts +7 -89
  269. package/dist/_dts/sdk/src/client/eventSubrouteReadOperations.d.ts +11 -0
  270. package/dist/_dts/sdk/src/client/types.d.ts +12 -5
  271. package/dist/_dts/sdk/src/components.d.ts +1 -1
  272. package/dist/_dts/sdk/src/config/validation.d.ts +30 -30
  273. package/dist/_dts/sdk/src/contracts/content.d.ts +10 -36
  274. package/dist/_dts/sdk/src/contracts/index.d.ts +1 -1
  275. package/dist/_dts/sdk/src/contracts/page.d.ts +2 -13
  276. package/dist/_dts/sdk/src/contracts/rendering.d.ts +1 -1
  277. package/dist/_dts/sdk/src/contracts/system-block-content.d.ts +4 -16
  278. package/dist/_dts/sdk/src/manifest/passes/pass1-fields.d.ts +9 -9
  279. package/dist/_dts/sdk/src/next/pageMetadataProjection.d.ts +7 -0
  280. package/dist/_dts/sdk/src/next/resolveEventPageSubroute.d.ts +12 -0
  281. package/dist/_dts/sdk/src/public-api/contracts.d.ts +11 -38
  282. package/dist/_dts/sdk/src/public-api/eventSubrouteContracts.d.ts +12 -0
  283. package/dist/_dts/sdk/src/public-api/runtime.d.ts +1 -1
  284. package/dist/_dts/sdk/src/rendering/client.d.ts +44 -0
  285. package/dist/_dts/sdk/src/rendering/index.d.ts +1 -1
  286. package/dist/_dts/sdk/src/routing/entrySubroutes.d.ts +1 -1
  287. package/dist/_dts/sdk/src/routing/resolveOccurrence.d.ts +4 -3
  288. package/dist/_dts/sdk/src/routing/resolvePageContent.d.ts +7 -3
  289. package/dist/_dts/sdk/src/version.d.ts +1 -1
  290. package/dist/_dts/theme-core/src/accordions/types.d.ts +2 -2
  291. package/dist/_dts/theme-core/src/buttons/buttonSurfaceContext.d.ts +1 -1
  292. package/dist/_dts/theme-core/src/buttons/contextualHover.d.ts +41 -0
  293. package/dist/_dts/theme-core/src/buttons/index.d.ts +1 -0
  294. package/dist/_dts/theme-core/src/buttons/resolveButtonColourStates.d.ts +3 -0
  295. package/dist/_dts/theme-core/src/buttons/resolveButtonHoverTreatment.d.ts +14 -0
  296. package/dist/_dts/theme-core/src/buttons/styles/domain.d.ts +21 -4
  297. package/dist/_dts/theme-core/src/buttons/styles/recipes/flatInk.d.ts +92 -0
  298. package/dist/_dts/theme-core/src/buttons/styles/recipes/staticRecipes.d.ts +10 -150
  299. package/dist/_dts/theme-core/src/buttons/styles/registry.d.ts +57 -102
  300. package/dist/_dts/theme-core/src/buttons/styles/selection.d.ts +50 -2
  301. package/dist/_dts/theme-core/src/buttons/types.d.ts +41 -12
  302. package/dist/_dts/theme-core/src/cards/types.d.ts +7 -29
  303. package/dist/_dts/theme-core/src/generated/containerResponsiveThemeCss.d.ts +1 -1
  304. package/dist/_dts/theme-core/src/mock-themes/all.d.ts +90 -75
  305. package/dist/_dts/theme-core/src/navigation/types.d.ts +4 -4
  306. package/dist/_dts/theme-core/src/palette/colors.d.ts +1 -1
  307. package/dist/_dts/theme-core/src/palette/curated/types.d.ts +2 -2
  308. package/dist/_dts/theme-core/src/schema.d.ts +98 -110
  309. package/dist/_dts/theme-core/src/site-styles/appearancePresetCatalog.d.ts +27 -0
  310. package/dist/_dts/theme-core/src/site-styles/blockAppearancePresets.d.ts +27 -0
  311. package/dist/_dts/theme-core/src/site-styles/buttonSelectionCompiler.d.ts +18 -0
  312. package/dist/_dts/theme-core/src/site-styles/cardRoleVocabulary.d.ts +1 -1
  313. package/dist/_dts/theme-core/src/site-styles/compilationPlan.d.ts +21 -0
  314. package/dist/_dts/theme-core/src/site-styles/designState.d.ts +2 -2
  315. package/dist/_dts/theme-core/src/site-styles/generatedSchemas.d.ts +4 -4
  316. package/dist/_dts/theme-core/src/site-styles/logoBranding.d.ts +4 -4
  317. package/dist/_dts/theme-core/src/site-styles/previewCompiler.d.ts +2 -11
  318. package/dist/_dts/theme-core/src/site-styles/selectionFallbackWarning.d.ts +15 -0
  319. package/dist/_dts/theme-core/src/site-styles/types.d.ts +13 -1
  320. package/dist/_dts/theme-core/src/tokens/themeColorTokens.d.ts +1 -1
  321. package/dist/_dts/ui/src/badge.d.ts +1 -1
  322. package/dist/_dts/ui/src/button.d.ts +1 -1
  323. package/dist/_dts/ui/src/callout.d.ts +1 -1
  324. package/dist/_dts/ui/src/card.d.ts +1 -1
  325. package/dist/_dts/ui/src/navigation-tabs.d.ts +2 -0
  326. package/dist/client/{StepIndicator-CLjQhkDb.mjs → BookingConsentAgreement-BxgpGEFD.mjs} +26 -4
  327. package/dist/client/{DiscountCodeDisclosure-BPZ-yfGI.mjs → DiscountCodeDisclosure-CfuPOHD0.mjs} +12 -12
  328. package/dist/client/{EventCombined.client-Cjt3kKYR.mjs → EventCombined.client-DB8Qfzi-.mjs} +37 -49
  329. package/dist/client/{EventListing.client-DY9dn6Fh.mjs → EventListing.client-DD4X8hp4.mjs} +2 -2
  330. package/dist/client/{LeafletStaticMap--2c61XYn.mjs → LeafletStaticMap-QhgIBQbv.mjs} +1 -1
  331. package/dist/client/{CourseRegistrationWizard-DGW9F0SQ.mjs → WholeSeriesRegistrationWizard-DwtC7bCs.mjs} +1460 -1247
  332. package/dist/client/{accordion-_boYwHHi.mjs → accordion-DFXpLvwg.mjs} +1 -1
  333. package/dist/client/{bookingForm--AqEfyBX.mjs → bookingForm-sI05d3lk.mjs} +73 -47
  334. package/dist/client/bookings.mjs +1719 -706
  335. package/dist/client/{carousel-CVI2dqZr.mjs → carousel-wjyWTZCh.mjs} +1 -1
  336. package/dist/client/{cart-DR6IiPz9.mjs → cart-DCwdpA4i.mjs} +3 -3
  337. package/dist/client/{checkout-CsrGAfQt.mjs → checkout-DTDW3l0R.mjs} +3 -3
  338. package/dist/client/checkoutUrls-DQYC_Br-.mjs +187 -0
  339. package/dist/client/client.mjs +6830 -3672
  340. package/dist/client/{context-B83PiNzm.mjs → context-TSK1CGx8.mjs} +1 -14
  341. package/dist/client/{courseRegistration-aNJVaLa3.mjs → courseRegistration-A-Tg7qw_.mjs} +11 -5
  342. package/dist/client/{eventCalendar-OZ7h59VN.mjs → eventCalendar-B0Zg-i_w.mjs} +41 -44
  343. package/dist/client/{eventCombined-BbJ6bFKz.mjs → eventCombined-B8Y2wizd.mjs} +3 -3
  344. package/dist/client/{eventDetails-BLyUBiCT.mjs → eventDetails-DPDOwURJ.mjs} +276 -94
  345. package/dist/client/{eventListing-DuP1yhBS.mjs → eventListing-CjBcmSLn.mjs} +3 -3
  346. package/dist/client/{eventRegistration-BXyECPa-.mjs → eventRegistration-CK30HsAq.mjs} +730 -190
  347. package/dist/client/{form-BA4t3kKU.mjs → form-CUXfsABE.mjs} +2 -2
  348. package/dist/client/{headerSection-CpNaJxhW.mjs → headerSection-N-mN3rjr.mjs} +2 -2
  349. package/dist/client/hooks.mjs +1418 -484
  350. package/dist/client/{locationMap-3HGMCL7_.mjs → locationMap-oiIDQMBt.mjs} +2 -2
  351. package/dist/client/{newsletterForm-C2s6Mw67.mjs → newsletterForm-CkQ2tTrM.mjs} +2 -2
  352. package/dist/client/pricing-Caa0QWzh.mjs +195 -0
  353. package/dist/client/{productDetail-C9joWhdE.mjs → productDetail-CnidyrsN.mjs} +3 -3
  354. package/dist/client/{productList-CjzdU3pB.mjs → productList-CttYcS_S.mjs} +3 -3
  355. package/dist/client/{propsDecoder-CBPGXEYX.mjs → propsDecoder-CeUMxI9a.mjs} +677 -350
  356. package/dist/client/rendering/client.mjs +6075 -4150
  357. package/dist/client/rendering/islands.mjs +18 -18
  358. package/dist/client/rendering.mjs +7589 -4388
  359. package/dist/client/{scrollToBlock-DZ73aEX6.mjs → scrollToBlock-lPr1oqxB.mjs} +1 -1
  360. package/dist/client/{shop-CQRai7hj.mjs → shop-DXQtMo2O.mjs} +6 -6
  361. package/dist/client/{shop-commerce-hP9UboOx.mjs → shop-commerce-quDL411J.mjs} +7 -164
  362. package/dist/client/{shop-commerce-store-DiD5a32e.mjs → shop-commerce-store-Dnu-8Iub.mjs} +1 -1
  363. package/dist/client/{shopShared-DP8DXTkF.mjs → shopShared-BWPUURvG.mjs} +3 -3
  364. package/dist/client/{useEventFilters-pF_OJNQP.mjs → useEventFilters-DRhWp2_5.mjs} +196 -7
  365. package/dist/client/{usePolling-Cls91SD2.mjs → usePolling-UN4WKnaM.mjs} +3 -3
  366. package/dist/preview-next/before-render.mjs +247 -60
  367. package/dist/preview-next/client/runtime.mjs +4 -4
  368. package/dist/preview-next/keepAlive.mjs +247 -60
  369. package/dist/preview-next/middleware.mjs +247 -60
  370. package/dist/{previewAuthStore-CX1C_KJ4.mjs → previewAuthStore-BFKd4LrN.mjs} +247 -60
  371. package/dist/{sdk-runtime-5CcPAI14.mjs → sdk-runtime-Ca5RD78X.mjs} +2 -2
  372. package/dist/{separator-BXlYN_gr.mjs → separator-CMhj6BTi.mjs} +1 -1
  373. package/dist/server/components.mjs +3578 -1614
  374. package/dist/server/config-validation.mjs +1418 -485
  375. package/dist/server/config.mjs +1418 -485
  376. package/dist/server/data.mjs +1418 -484
  377. package/dist/server/index.mjs +289 -81
  378. package/dist/server/manifest.mjs +0 -1
  379. package/dist/server/next.mjs +3761 -1794
  380. package/dist/server/page-converter.mjs +911 -261
  381. package/dist/server/prebuild.mjs +1 -1
  382. package/dist/server/rendering/server.mjs +3580 -1613
  383. package/dist/server/rendering.mjs +3578 -1614
  384. package/dist/server/routing.mjs +1687 -689
  385. package/dist/server/server.mjs +1458 -563
  386. package/dist/server/theme-bridge.mjs +1996 -935
  387. package/dist/server/theme.mjs +346 -133
  388. package/dist/styles/index.css +1602 -796
  389. package/package.json +2 -2
  390. package/dist/_dts/api/src/bookingVerticalCatalog.d.ts +0 -746
  391. package/dist/_dts/api/src/eventSeriesPresentationPreset.d.ts +0 -12
  392. package/dist/_dts/blocks/src/system/runtime/nodes/course-registration/CourseRegistrationWizard.d.ts +0 -3
  393. package/dist/_dts/blocks/src/system/runtime/nodes/course-registration/StepIndicator.d.ts +0 -6
  394. package/dist/_dts/blocks/src/system/runtime/nodes/course-registration/components.d.ts +0 -45
  395. package/dist/_dts/blocks/src/system/runtime/nodes/course-registration/pricing.d.ts +0 -14
  396. package/dist/_dts/blocks/src/system/runtime/nodes/course-registration/useCoursePaymentVerification.d.ts +0 -9
  397. package/dist/_dts/blocks/src/system/runtime/nodes/course-registration/useCourseRegistrationActions.d.ts +0 -35
  398. package/dist/_dts/blocks/src/system/runtime/nodes/course-registration/useCourseRegistrationSelection.d.ts +0 -31
  399. package/dist/_dts/blocks/src/system/runtime/nodes/course-registration/useCourseRegistrationWizard.d.ts +0 -102
  400. package/dist/client/checkoutUrls-Ct8Mxna3.mjs +0 -26
  401. package/dist/client/eventProductEligibility-AVxyCB1u.mjs +0 -50
  402. package/dist/client/pricing-BiqIMgZk.mjs +0 -174
  403. /package/dist/_dts/blocks/src/system/runtime/nodes/{course-registration → event-registration/whole-series}/PortalAuthSidebar.d.ts +0 -0
  404. /package/dist/_dts/blocks/src/system/runtime/nodes/{course-registration → event-registration/whole-series}/SuccessStep.d.ts +0 -0
  405. /package/dist/_dts/blocks/src/system/runtime/nodes/{course-registration → event-registration/whole-series}/WaitlistStep.d.ts +0 -0
@@ -3211,20 +3211,7 @@ function createBlockApi(config) {
3211
3211
  const path = buildPath(WHOLE_SERIES.checkout.path, { siteId: sid });
3212
3212
  return request(WHOLE_SERIES.checkout, {
3213
3213
  path,
3214
- body: {
3215
- eventSeriesId: data.eventSeriesId,
3216
- ...data.pricingOptionId ? { pricingOptionId: data.pricingOptionId } : {},
3217
- ...data.selectedSlidingAmount !== void 0 ? { selectedSlidingAmount: data.selectedSlidingAmount } : {},
3218
- email: data.email,
3219
- name: data.name,
3220
- phone: data.phone,
3221
- formData: data.formData,
3222
- altchaSolution: data.altchaSolution,
3223
- discountCode: data.discountCode,
3224
- successUrl: data.successUrl,
3225
- cancelUrl: data.cancelUrl,
3226
- claimToken: data.claimToken
3227
- }
3214
+ body: data
3228
3215
  });
3229
3216
  },
3230
3217
  async getWholeSeriesRegistrationStatus(params) {
@@ -3676,7 +3663,7 @@ function getChallengeUrl() {
3676
3663
  }
3677
3664
  //#endregion
3678
3665
  //#region ../core/src/result.ts
3679
- function ok(value) {
3666
+ function ok$1(value) {
3680
3667
  return {
3681
3668
  ok: true,
3682
3669
  value
@@ -3696,11 +3683,14 @@ function parseUuidBrand(value, unsafeConstructor) {
3696
3683
  const normalized = value.trim().toLowerCase();
3697
3684
  if (normalized.length === 0) return err$1({ kind: "empty_string" });
3698
3685
  if (!UUID_PATTERN.test(normalized)) return err$1({ kind: "invalid_uuid" });
3699
- return ok(unsafeConstructor(normalized));
3686
+ return ok$1(unsafeConstructor(normalized));
3700
3687
  }
3701
3688
  const unsafeAsSiteId = (id) => id;
3702
3689
  const unsafeAsEventOfferingId = (id) => id;
3703
3690
  const unsafeAsEventSeriesId = (id) => id;
3691
+ const unsafeAsMediaAssetId = (id) => id;
3692
+ const unsafeAsStorageBucketName = (value) => value;
3693
+ const unsafeAsStoragePath = (value) => value;
3704
3694
  const unsafeAsFormId = (id) => id;
3705
3695
  const unsafeAsPassId = (id) => id;
3706
3696
  const unsafeAsCustomerPassId = (id) => id;
@@ -3843,7 +3833,7 @@ function parseEventPageSurfaceSubject(value) {
3843
3833
  kind: "invalidEventSeriesBookingScope",
3844
3834
  bookingScope: value.bookingScope
3845
3835
  });
3846
- return ok(createEventSeriesPageSurfaceSubject(eventSeriesId.value, value.bookingScope));
3836
+ return ok$1(createEventSeriesPageSurfaceSubject(eventSeriesId.value, value.bookingScope));
3847
3837
  }
3848
3838
  case "eventOffering": {
3849
3839
  const eventOfferingId = parseEventOfferingId(value.eventOfferingId);
@@ -3864,7 +3854,7 @@ function parseEventPageSurfaceSubject(value) {
3864
3854
  });
3865
3855
  parsedSeriesIds.push(eventSeriesId.value);
3866
3856
  }
3867
- return ok({
3857
+ return ok$1({
3868
3858
  kind: "eventOffering",
3869
3859
  eventOfferingId: eventOfferingId.value,
3870
3860
  availableEventSeriesIds: parsedSeriesIds
@@ -3982,7 +3972,7 @@ function parseBookingTimeZone(timeZone) {
3982
3972
  if (typeof timeZone !== "string") return err$1("invalid-time-zone");
3983
3973
  const normalized = timeZone.trim();
3984
3974
  if (normalized.length === 0 || NUMERIC_OFFSET_TIME_ZONE_PATTERN.test(normalized) || !isValidBookingTimeZone(normalized)) return err$1("invalid-time-zone");
3985
- return ok(normalized);
3975
+ return ok$1(normalized);
3986
3976
  }
3987
3977
  //#endregion
3988
3978
  //#region ../core/src/booking-date-time.ts
@@ -4061,7 +4051,7 @@ function parseUtcIsoDateTimeString(value) {
4061
4051
  if (!hasUtcSuffix && !hasExplicitOffset) return err$1("missing-timezone-offset");
4062
4052
  const date = new Date(normalized);
4063
4053
  if (Number.isNaN(date.getTime())) return err$1("invalid-date-time");
4064
- return ok(date.toISOString());
4054
+ return ok$1(date.toISOString());
4065
4055
  }
4066
4056
  function toUtcIsoDateTimeString(value) {
4067
4057
  const parsed = parseUtcIsoDateTimeString(value);
@@ -4213,6 +4203,109 @@ function assertNever(value, message) {
4213
4203
  throw new Error(message ?? `Unexpected value: ${String(value)}`);
4214
4204
  }
4215
4205
  //#endregion
4206
+ //#region ../blocks/src/system/manifest/richTextSchema.ts
4207
+ /**
4208
+ * Shared Rich Text Schema
4209
+ *
4210
+ * This module provides a single source of truth for TipTap rich text validation
4211
+ * across both the block-form editor and the block rendering system.
4212
+ *
4213
+ * Rich-text fields use one canonical root shape:
4214
+ * `{ type: 'doc', content: [...] }`.
4215
+ */
4216
+ /**
4217
+ * TipTap document node schema (recursive structure)
4218
+ *
4219
+ * Supports the full TipTap document structure including:
4220
+ * - type: Node type (e.g., 'doc', 'paragraph', 'text')
4221
+ * - content: Nested array of child nodes
4222
+ * - text: Text content for text nodes
4223
+ * - attrs: Node attributes (e.g., alignment, color)
4224
+ * - marks: Text formatting marks (e.g., bold, italic)
4225
+ */
4226
+ const TipTapMarkSchema = z.object({
4227
+ type: z.string().min(1),
4228
+ attrs: z.record(z.string(), z.unknown()).optional()
4229
+ }).strict();
4230
+ const TipTapNodeSchema = z.lazy(() => z.object({
4231
+ type: z.string().min(1),
4232
+ content: z.array(TipTapNodeSchema).optional(),
4233
+ text: z.string().optional(),
4234
+ attrs: z.record(z.string(), z.unknown()).optional(),
4235
+ marks: z.array(TipTapMarkSchema).optional()
4236
+ }).strict().superRefine((node, ctx) => {
4237
+ if (node.type === "doc") ctx.addIssue({
4238
+ code: "custom",
4239
+ path: ["type"],
4240
+ message: "Document nodes are only valid at the rich-text root"
4241
+ });
4242
+ if (node.type === "text") {
4243
+ if (node.text === void 0 || node.text.length === 0) ctx.addIssue({
4244
+ code: "custom",
4245
+ path: ["text"],
4246
+ message: "Text nodes require a non-empty text value"
4247
+ });
4248
+ if (node.content !== void 0) ctx.addIssue({
4249
+ code: "custom",
4250
+ path: ["content"],
4251
+ message: "Text nodes cannot contain child nodes"
4252
+ });
4253
+ return;
4254
+ }
4255
+ if (node.text !== void 0) ctx.addIssue({
4256
+ code: "custom",
4257
+ path: ["text"],
4258
+ message: "Only text nodes can contain a text value"
4259
+ });
4260
+ }));
4261
+ /**
4262
+ * Canonical schema for a TipTap rich-text document root.
4263
+ *
4264
+ * Stricter than {@link TipTapNodeSchema}: `type` is literally `'doc'` and
4265
+ * `content` is required (possibly empty). This is the shape every producer
4266
+ * (dummy content, editor output, migrations) must emit, and the shape every
4267
+ * non-legacy consumer can rely on.
4268
+ *
4269
+ */
4270
+ const RichTextDocSchema = z.object({
4271
+ type: z.literal("doc"),
4272
+ content: z.array(TipTapNodeSchema)
4273
+ }).strict();
4274
+ //#endregion
4275
+ //#region ../blocks/src/system/blocks/shared/bookingConsent.ts
4276
+ const BOOKING_REQUIREMENT_CONSENT_FIELD_PREFIX = "booking_requirement_consent_";
4277
+ function toBookingRequirementConsentFieldId(requirementId) {
4278
+ return `${BOOKING_REQUIREMENT_CONSENT_FIELD_PREFIX}${requirementId}`;
4279
+ }
4280
+ function isBookingRequirementConsentFieldId(value) {
4281
+ return value.startsWith(BOOKING_REQUIREMENT_CONSENT_FIELD_PREFIX);
4282
+ }
4283
+ function toBookingRequirementConsentField(consent) {
4284
+ return {
4285
+ id: toBookingRequirementConsentFieldId(consent.requirementId),
4286
+ label: consent.title,
4287
+ type: "booking_requirement_consent",
4288
+ required: true,
4289
+ agreement: consent.agreement,
4290
+ checkboxLabel: consent.checkboxLabel
4291
+ };
4292
+ }
4293
+ const blockBookingConsentSchema = z.object({
4294
+ requirementId: z.string(),
4295
+ title: z.string(),
4296
+ agreement: RichTextDocSchema,
4297
+ checkboxLabel: z.string()
4298
+ });
4299
+ const bookingRequirementConsentFieldSchema = z.object({
4300
+ id: z.string(),
4301
+ label: z.string(),
4302
+ type: z.literal("booking_requirement_consent"),
4303
+ required: z.literal(true),
4304
+ agreement: RichTextDocSchema,
4305
+ checkboxLabel: z.string().min(1)
4306
+ });
4307
+ z.union([blockBookingConsentSchema, bookingRequirementConsentFieldSchema]);
4308
+ //#endregion
4216
4309
  //#region ../blocks/src/system/runtime/nodes/booking-form.reserved-fields.ts
4217
4310
  const BOOKING_FORM_DATA_RESERVED_KEY_VALUES = [
4218
4311
  "serviceId",
@@ -4226,6 +4319,28 @@ const BOOKING_FORM_DATA_RESERVED_KEY_VALUES = [
4226
4319
  ];
4227
4320
  const BOOKING_FORM_DATA_RESERVED_KEYS = new Set(BOOKING_FORM_DATA_RESERVED_KEY_VALUES);
4228
4321
  //#endregion
4322
+ //#region ../blocks/src/system/runtime/nodes/booking-form.consent.ts
4323
+ function resolveSelectedAppointmentConsent(service) {
4324
+ return service?.consent ? {
4325
+ kind: "required-for-selected-service",
4326
+ field: toBookingRequirementConsentField(service.consent)
4327
+ } : { kind: "not-applicable" };
4328
+ }
4329
+ function projectSelectedAppointmentConsentIntoForm(form, selectedConsent) {
4330
+ if (!form) return null;
4331
+ const sourceFields = form.schema?.fields ?? [];
4332
+ const baseFields = sourceFields.filter((field) => field.type !== "booking_requirement_consent");
4333
+ const fields = selectedConsent.kind === "required-for-selected-service" ? [...baseFields, selectedConsent.field] : baseFields;
4334
+ if (selectedConsent.kind === "not-applicable" && baseFields.length === sourceFields.length) return form;
4335
+ return {
4336
+ ...form,
4337
+ schema: {
4338
+ ...form.schema,
4339
+ fields
4340
+ }
4341
+ };
4342
+ }
4343
+ //#endregion
4229
4344
  //#region ../blocks/src/system/runtime/nodes/booking-form.state.ts
4230
4345
  function toTrimmedString(value) {
4231
4346
  const trimmed = value?.trim();
@@ -4408,7 +4523,6 @@ function readBookingFieldType(value) {
4408
4523
  case "select":
4409
4524
  case "radio":
4410
4525
  case "checkbox":
4411
- case "booking_requirement_consent":
4412
4526
  case "tel":
4413
4527
  case "url":
4414
4528
  case "number":
@@ -4443,7 +4557,7 @@ function normalizeBookingSettings(value) {
4443
4557
  };
4444
4558
  }
4445
4559
  function isBookingFormService(value) {
4446
- return isRecord$5(value) && typeof value.id === "string" && typeof value.siteId === "string" && typeof value.title === "string";
4560
+ return isRecord$5(value) && typeof value.id === "string" && typeof value.siteId === "string" && typeof value.title === "string" && (value.consent === void 0 || blockBookingConsentSchema.safeParse(value.consent).success);
4447
4561
  }
4448
4562
  function collectBookingCustomFields(data) {
4449
4563
  const customFields = {};
@@ -4687,6 +4801,11 @@ function getBookingSuccessMessage(successMessage) {
4687
4801
  return successMessage?.trim() || "Your appointment has been booked! Check your email for confirmation.";
4688
4802
  }
4689
4803
  //#endregion
4804
+ //#region ../blocks/src/system/runtime/hooks/useSelectedAppointmentConsentForm.ts
4805
+ function useSelectedAppointmentConsentForm(form, selectedService) {
4806
+ return useMemo(() => projectSelectedAppointmentConsentIntoForm(form, resolveSelectedAppointmentConsent(selectedService)), [form, selectedService]);
4807
+ }
4808
+ //#endregion
4690
4809
  //#region ../blocks/src/utils/date-formatting.ts
4691
4810
  /**
4692
4811
  * Resolve the browser/runtime timezone for booking surfaces.
@@ -5751,6 +5870,19 @@ function clearBookingFieldError(errors, fieldId) {
5751
5870
  };
5752
5871
  }
5753
5872
  //#endregion
5873
+ //#region ../blocks/src/system/runtime/nodes/booking-form.field-values.ts
5874
+ function collectInitialBookingFieldValues(initialData) {
5875
+ const values = {};
5876
+ for (const [key, value] of Object.entries(initialData)) if (!BOOKING_FORM_DATA_RESERVED_KEYS.has(key) && !isBookingRequirementConsentFieldId(key) && isBookingFieldValue(value)) values[key] = value;
5877
+ return values;
5878
+ }
5879
+ function omitBookingConsentEntries(record) {
5880
+ return Object.fromEntries(Object.entries(record).filter(([key]) => !isBookingRequirementConsentFieldId(key)));
5881
+ }
5882
+ function isBookingFieldValue(value) {
5883
+ return value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean" || Array.isArray(value) && value.every((item) => typeof item === "string");
5884
+ }
5885
+ //#endregion
5754
5886
  //#region ../blocks/src/system/runtime/nodes/booking-form.headless.state.ts
5755
5887
  const unsafeAsBookingFieldId = (id) => id;
5756
5888
  function createInitialBookingFlowReducerState(input) {
@@ -5762,7 +5894,7 @@ function createInitialBookingFlowReducerState(input) {
5762
5894
  selectedResourceId: toOptionalAppointmentResourceId(toOptionalString(initialData.resourceId) ?? input.defaultResourceId),
5763
5895
  selectedDate: toOptionalString(initialData.selectedDate),
5764
5896
  selectedSlot: null,
5765
- fieldValues: collectInitialFieldValues(initialData),
5897
+ fieldValues: collectInitialBookingFieldValues(initialData),
5766
5898
  touchedFields: {},
5767
5899
  attemptedStepIds: {},
5768
5900
  discountCode: toOptionalString(initialData.discountCode) ?? "",
@@ -5774,14 +5906,6 @@ function createInitialBookingFlowReducerState(input) {
5774
5906
  feedback: { kind: "none" }
5775
5907
  };
5776
5908
  }
5777
- function collectInitialFieldValues(initialData) {
5778
- const values = {};
5779
- for (const [key, value] of Object.entries(initialData)) {
5780
- if (BOOKING_FORM_DATA_RESERVED_KEYS.has(key) || !isBookingFieldValue(value)) continue;
5781
- values[key] = value;
5782
- }
5783
- return values;
5784
- }
5785
5909
  function toOptionalString(value) {
5786
5910
  if (typeof value !== "string") return void 0;
5787
5911
  const trimmed = value.trim();
@@ -5803,9 +5927,6 @@ function toOptionalAppointmentResourceId(value) {
5803
5927
  function toOptionalCustomerPassId(value) {
5804
5928
  return toOptionalBrandedId(value, unsafeAsCustomerPassId);
5805
5929
  }
5806
- function isBookingFieldValue(value) {
5807
- return value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean" || Array.isArray(value) && value.every((item) => typeof item === "string");
5808
- }
5809
5930
  /**
5810
5931
  * Send the flow back to the date step when the slot it was holding went away,
5811
5932
  * leaving a scoped feedback message. A completed booking is left alone.
@@ -5827,17 +5948,7 @@ function applyAvailabilitySelectionInvalidation(state, invalidation) {
5827
5948
  }
5828
5949
  function bookingFlowReducer(state, event) {
5829
5950
  switch (event.type) {
5830
- case "service-selected": return {
5831
- ...state,
5832
- selectedServiceId: event.serviceId,
5833
- selectedResourceId: void 0,
5834
- selectedDate: void 0,
5835
- selectedSlot: null,
5836
- selectedAppointmentPackageId: void 0,
5837
- selectedSlidingAmountInput: "",
5838
- selectedCollectionOptionKind: void 0,
5839
- validationErrors: clearBookingFormError(state.validationErrors)
5840
- };
5951
+ case "service-selected": return applyBookingServiceSelection(state, event.serviceId);
5841
5952
  case "resource-selected": return {
5842
5953
  ...state,
5843
5954
  selectedResourceId: event.resourceId ?? void 0,
@@ -5944,6 +6055,24 @@ function bookingFlowReducer(state, event) {
5944
6055
  default: return assertNever(event);
5945
6056
  }
5946
6057
  }
6058
+ function applyBookingServiceSelection(state, serviceId) {
6059
+ return {
6060
+ ...state,
6061
+ selectedServiceId: serviceId,
6062
+ selectedResourceId: void 0,
6063
+ selectedDate: void 0,
6064
+ selectedSlot: null,
6065
+ selectedAppointmentPackageId: void 0,
6066
+ selectedSlidingAmountInput: "",
6067
+ selectedCollectionOptionKind: void 0,
6068
+ fieldValues: omitBookingConsentEntries(state.fieldValues),
6069
+ touchedFields: omitBookingConsentEntries(state.touchedFields),
6070
+ validationErrors: {
6071
+ ...clearBookingFormError(state.validationErrors),
6072
+ fieldErrors: omitBookingConsentEntries(state.validationErrors.fieldErrors)
6073
+ }
6074
+ };
6075
+ }
5947
6076
  function clearAvailabilityFeedback(feedback) {
5948
6077
  return feedback.kind === "error" && feedback.scope === "availability" ? { kind: "none" } : feedback;
5949
6078
  }
@@ -6104,7 +6233,8 @@ function validateBookingFields(input) {
6104
6233
  return errors;
6105
6234
  }
6106
6235
  function validateBookingField(field, value) {
6107
- if (field.required && isBlankFieldValue(value)) return `${field.label} is required`;
6236
+ const requiredError = validateRequiredBookingField(field, value);
6237
+ if (requiredError) return requiredError;
6108
6238
  if (isBlankFieldValue(value)) return null;
6109
6239
  const strValue = typeof value === "string" ? value : String(value);
6110
6240
  if (field.type === "email") return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(strValue) ? null : "Please enter a valid email address";
@@ -6133,6 +6263,10 @@ function validateBookingField(field, value) {
6133
6263
  }
6134
6264
  return null;
6135
6265
  }
6266
+ function validateRequiredBookingField(field, value) {
6267
+ if (field.type === "booking_requirement_consent") return value === true ? null : `${field.label} is required`;
6268
+ return field.required && isBlankFieldValue(value) ? `${field.label} is required` : null;
6269
+ }
6136
6270
  function deriveBookingFlowSteps(input) {
6137
6271
  const stepResolution = buildBookingStepResolution({
6138
6272
  form: input.form,
@@ -6204,7 +6338,8 @@ function deriveBookingFieldViews(input) {
6204
6338
  return (input.form?.schema?.fields ?? []).map((field) => {
6205
6339
  const fieldId = unsafeAsBookingFieldId(field.id);
6206
6340
  const inputId = `${input.idPrefix}-${fieldId}`;
6207
- const helpTextId = field.helpText ? `${inputId}-help` : null;
6341
+ const helpText = field.type === "booking_requirement_consent" ? null : field.helpText ?? null;
6342
+ const helpTextId = helpText ? `${inputId}-help` : null;
6208
6343
  const fieldValue = input.values[field.id] ?? null;
6209
6344
  const localError = input.touched?.[field.id] ? validateBookingField(field, fieldValue) : null;
6210
6345
  const error = input.errors[field.id] ?? localError;
@@ -6214,17 +6349,17 @@ function deriveBookingFieldViews(input) {
6214
6349
  field,
6215
6350
  id: fieldId,
6216
6351
  label: field.label,
6217
- type: field.type,
6218
6352
  value: fieldValue,
6219
6353
  required: Boolean(field.required),
6220
6354
  error,
6221
- helpText: field.helpText ?? null,
6355
+ helpText,
6222
6356
  inputId,
6223
6357
  labelId: `${inputId}-label`,
6224
6358
  helpTextId,
6225
6359
  errorId,
6226
6360
  describedBy,
6227
- ariaInvalid: Boolean(error)
6361
+ ariaInvalid: Boolean(error),
6362
+ type: field.type
6228
6363
  };
6229
6364
  });
6230
6365
  }
@@ -6486,6 +6621,7 @@ function useHeadlessBookingFlow(options) {
6486
6621
  const selectedServiceId = state.selectedServiceId ?? defaultServiceId;
6487
6622
  const selectedResourceId = state.selectedResourceId ?? defaultResourceId;
6488
6623
  const selectedService = options.services.find((service) => service.id === selectedServiceId) ?? null;
6624
+ const runtimeForm = useSelectedAppointmentConsentForm(options.form, selectedService);
6489
6625
  const lastSlidingServiceIdRef = useRef(null);
6490
6626
  useEffect(() => {
6491
6627
  const selectedId = selectedService?.id ?? null;
@@ -6526,7 +6662,7 @@ function useHeadlessBookingFlow(options) {
6526
6662
  viewerTimeZone
6527
6663
  ]);
6528
6664
  const stepState = useMemo(() => deriveBookingFlowSteps({
6529
- form: options.form,
6665
+ form: runtimeForm,
6530
6666
  services: options.services,
6531
6667
  data,
6532
6668
  defaultServiceId,
@@ -6542,7 +6678,7 @@ function useHeadlessBookingFlow(options) {
6542
6678
  defaultServiceId,
6543
6679
  defaultResourceId,
6544
6680
  options.enableAppointmentPackages,
6545
- options.form,
6681
+ runtimeForm,
6546
6682
  options.requiresResourceSelection,
6547
6683
  options.requiresServiceSelection,
6548
6684
  options.services,
@@ -6596,13 +6732,13 @@ function useHeadlessBookingFlow(options) {
6596
6732
  state.selectedSlot
6597
6733
  ]);
6598
6734
  const fields = useMemo(() => deriveBookingFieldViews({
6599
- form: options.form,
6735
+ form: runtimeForm,
6600
6736
  values: state.fieldValues,
6601
6737
  errors: state.validationErrors.fieldErrors,
6602
6738
  touched: state.touchedFields,
6603
6739
  idPrefix: `booking-${options.formId}`
6604
6740
  }), [
6605
- options.form,
6741
+ runtimeForm,
6606
6742
  options.formId,
6607
6743
  state.fieldValues,
6608
6744
  state.touchedFields,
@@ -6722,7 +6858,7 @@ function useHeadlessBookingFlow(options) {
6722
6858
  const latestRef = useLatestRef({
6723
6859
  state,
6724
6860
  data,
6725
- form: options.form,
6861
+ form: runtimeForm,
6726
6862
  formId: formKey,
6727
6863
  services: options.services,
6728
6864
  defaultServiceId,
@@ -6974,7 +7110,7 @@ function useHeadlessBookingFlow(options) {
6974
7110
  phase: state.phase
6975
7111
  });
6976
7112
  const view = resolveHeadlessBookingView({
6977
- form: options.form,
7113
+ form: runtimeForm,
6978
7114
  feedback: state.feedback
6979
7115
  });
6980
7116
  const appointmentPackagesModel = resolveAppointmentPackagesModel({
@@ -7530,6 +7666,12 @@ const opaqueButtonColourTokenSchema = themeColorTokenSchema.refine((value) => pa
7530
7666
  if (token === null) throw new Error("Invariant: opaque button token passed its schema");
7531
7667
  return token;
7532
7668
  });
7669
+ const contextualButtonHoverSchema = z.strictObject({
7670
+ kind: z.literal("shade-shift"),
7671
+ seedToken: opaqueButtonColourTokenSchema,
7672
+ fallbackDirection: z.enum(["lighter", "darker"]),
7673
+ preferredToken: opaqueButtonColourTokenSchema.optional()
7674
+ });
7533
7675
  const buttonShadeAmountSchema = z.number().finite().min(0).max(900).multipleOf(100);
7534
7676
  const buttonShadowIntensitySchema = z.enum([
7535
7677
  "subtle",
@@ -7869,6 +8011,7 @@ const buttonVariantSchema = z.strictObject({
7869
8011
  shadow: variantShadowSchema.optional(),
7870
8012
  border: buttonBorderSchema.optional(),
7871
8013
  hoverBackgroundToken: opaqueButtonColourTokenSchema.optional(),
8014
+ contextualHover: contextualButtonHoverSchema.optional(),
7872
8015
  effects: variantEffectsSchema.optional(),
7873
8016
  sizes: variantSizeOverridesSchema.optional(),
7874
8017
  affordance: buttonVariantAffordanceSchema.optional()
@@ -8154,8 +8297,8 @@ const openCardRoleValue = "open";
8154
8297
  */
8155
8298
  const surfaceCardRoleValues = [...cardVariantRoleValues, openCardRoleValue];
8156
8299
  /**
8157
- * The closed card-role vocabulary Looks and blocks address cards by — this is
8158
- * `BoxStylesCardVariant` widened with `open`, not a parallel enum.
8300
+ * The closed role vocabulary Looks and blocks use for surfaced and boxless
8301
+ * card choices.
8159
8302
  *
8160
8303
  * - `none` — no site-style card surface; the block's own composition and
8161
8304
  * the author's own card fields govern the item. This is *not*
@@ -8199,11 +8342,6 @@ const gradientDirectionSchema = z.enum([
8199
8342
  z.enum(cardVariantRoleValues);
8200
8343
  const surfaceCardRoleSchema = z.enum(surfaceCardRoleValues);
8201
8344
  const cardRoleSchema = z.enum(cardRoleValues);
8202
- /**
8203
- * Historical name for the role vocabulary as it reaches box styles. Widened to
8204
- * the full `CardRole` set — old values keep parsing, `open` now parses too.
8205
- */
8206
- const boxStylesCardVariantSchema = cardRoleSchema;
8207
8345
  const PRIORITY_ROLE_INFERENCE = {
8208
8346
  1: "default",
8209
8347
  2: "alternative"
@@ -9608,8 +9746,7 @@ const cardStylesOverrideSchema = z.object({
9608
9746
  spacing: semanticSpacingSchema.nullable().optional(),
9609
9747
  raised: z.boolean().nullable().optional(),
9610
9748
  rounded: boxRoundedSchema.nullable().optional(),
9611
- role: cardRoleSchema.nullable().optional(),
9612
- cardVariant: boxStylesCardVariantSchema.nullable().optional()
9749
+ role: cardRoleSchema.nullable().optional()
9613
9750
  });
9614
9751
  const blockStyleOverridesSchema = z.object({
9615
9752
  sectionStyles: sectionStylesOverrideSchema.nullable().optional(),
@@ -10238,13 +10375,7 @@ function shadeBackgroundEffect(config) {
10238
10375
  buttonSizeNameSchema.options;
10239
10376
  //#endregion
10240
10377
  //#region ../theme-core/src/buttons/styles/domain.ts
10241
- const PUBLIC_BUTTON_ROLES = [
10242
- "primary",
10243
- "secondary",
10244
- "outline",
10245
- "ghost",
10246
- "accent"
10247
- ];
10378
+ const PUBLIC_BUTTON_ROLES = VARIANT_ROLES;
10248
10379
  function defineButtonStyleRecipe(recipe) {
10249
10380
  return recipe;
10250
10381
  }
@@ -10340,6 +10471,14 @@ const BUTTON_STYLE_IDS = [
10340
10471
  "quiet-arrow"
10341
10472
  ];
10342
10473
  const quietArrowParametersSchema = z.object({ secondaryTreatment: z.enum(["outlined", "solid-accent"]) }).strict();
10474
+ const flatInkHoverTreatmentSchema = z.enum([
10475
+ "contextual",
10476
+ "secondary",
10477
+ "accent"
10478
+ ]);
10479
+ const flatInkHoverPreferencesShape = Object.fromEntries(VARIANT_ROLES.map((role) => [role, flatInkHoverTreatmentSchema.optional()]));
10480
+ const flatInkHoverPreferencesSchema = z.strictObject(flatInkHoverPreferencesShape);
10481
+ const flatInkParametersSchema = z.strictObject({ hoverPreferences: flatInkHoverPreferencesSchema.optional() });
10343
10482
  const emptyParametersSchema$1 = z.object({}).strict();
10344
10483
  function selectionBranch(styleId, parameters) {
10345
10484
  return z.object({
@@ -10354,7 +10493,7 @@ z.discriminatedUnion("styleId", [
10354
10493
  selectionBranch("editorial-link", emptyParametersSchema$1),
10355
10494
  selectionBranch("pebble", emptyParametersSchema$1),
10356
10495
  selectionBranch("ink-stamp", emptyParametersSchema$1),
10357
- selectionBranch("flat-ink", emptyParametersSchema$1),
10496
+ selectionBranch("flat-ink", flatInkParametersSchema),
10358
10497
  selectionBranch("brushed-wash", emptyParametersSchema$1),
10359
10498
  selectionBranch("showtime-pill", emptyParametersSchema$1),
10360
10499
  selectionBranch("joy-stamp", emptyParametersSchema$1),
@@ -10491,105 +10630,288 @@ const quietArrowRecipe = defineButtonStyleRecipe({
10491
10630
  })
10492
10631
  });
10493
10632
  //#endregion
10494
- //#region ../theme-core/src/buttons/styles/recipes/defineStaticButtonStyleRecipe.ts
10495
- const emptyParametersSchema = z.object({}).strict();
10496
- function defineStaticButtonStyleRecipe(input) {
10497
- const system = normalizeSystem(input.system);
10498
- return defineButtonStyleRecipe({
10499
- id: input.id,
10500
- accessibilityLabel: input.accessibilityLabel,
10501
- tags: input.tags,
10502
- parameterSchema: emptyParametersSchema,
10503
- defaultParameters: {},
10504
- controls: [],
10505
- defineSystem: () => system
10506
- });
10507
- }
10508
- function normalizeSystem(input) {
10509
- return {
10510
- global: buttonGlobalSettingsSchema.parse(input.global),
10511
- ...input.sizes ? { sizes: input.sizes } : {},
10512
- roles: {
10513
- primary: normalizeCompleteRole(input.roles.primary),
10514
- secondary: normalizeCompleteRole(input.roles.secondary),
10515
- outline: normalizeSupportingRole(input.roles.outline),
10516
- ghost: normalizeSupportingRole(input.roles.ghost),
10517
- accent: normalizeSupportingRole(input.roles.accent)
10633
+ //#region ../theme-core/src/buttons/styles/recipes/flatInk.ts
10634
+ const contextualRoleConfig = {
10635
+ primary: {
10636
+ contextualSeedToken: unsafeAsOpaqueButtonColourToken("primary"),
10637
+ fallbackDirection: "darker"
10638
+ },
10639
+ secondary: {
10640
+ contextualSeedToken: unsafeAsOpaqueButtonColourToken("surfaceAlt"),
10641
+ fallbackDirection: "darker"
10642
+ },
10643
+ outline: {
10644
+ contextualSeedToken: unsafeAsOpaqueButtonColourToken("surfaceAlt"),
10645
+ fallbackDirection: "darker"
10646
+ },
10647
+ ghost: {
10648
+ contextualSeedToken: unsafeAsOpaqueButtonColourToken("surfaceAlt"),
10649
+ fallbackDirection: "darker"
10650
+ },
10651
+ accent: {
10652
+ contextualSeedToken: unsafeAsOpaqueButtonColourToken("accent"),
10653
+ fallbackDirection: "darker"
10654
+ }
10655
+ };
10656
+ const hoverControl = {
10657
+ kind: "button-hover-by-role",
10658
+ parameter: "hoverPreferences",
10659
+ label: "Button hover",
10660
+ roles: contextualRoleConfig,
10661
+ options: [
10662
+ {
10663
+ value: "contextual",
10664
+ label: "Contextual shade shift"
10665
+ },
10666
+ {
10667
+ value: "secondary",
10668
+ label: "Secondary button colour"
10669
+ },
10670
+ {
10671
+ value: "accent",
10672
+ label: "Accent button colour"
10518
10673
  }
10519
- };
10520
- }
10521
- function normalizeCompleteRole(role) {
10522
- return {
10523
- kind: "complete",
10524
- appearance: normalizeAppearance(role.appearance)
10525
- };
10526
- }
10527
- function normalizeSupportingRole(role) {
10528
- if (role.kind === "complete") return normalizeCompleteRole(role);
10529
- return {
10530
- kind: "derive",
10531
- from: role.from,
10532
- ...role.overrides ? { overrides: normalizeAppearanceOverrides(role.overrides) } : {}
10533
- };
10534
- }
10535
- function normalizeAppearance(appearance) {
10536
- const { background, hoverBackgroundToken, ...rest } = appearance;
10537
- return {
10538
- ...rest,
10539
- background: buttonColourTreatmentSchema.parse(background),
10540
- ...hoverBackgroundToken ? { hoverBackgroundToken: opaqueButtonColourTokenSchema.parse(hoverBackgroundToken) } : {}
10541
- };
10542
- }
10543
- function normalizeAppearanceOverrides(overrides) {
10544
- const { background, hoverBackgroundToken, ...rest } = overrides;
10545
- return {
10546
- ...rest,
10547
- ...background ? { background: buttonColourTreatmentSchema.parse(background) } : {},
10548
- ...hoverBackgroundToken ? { hoverBackgroundToken: opaqueButtonColourTokenSchema.parse(hoverBackgroundToken) } : {}
10549
- };
10550
- }
10551
- //#endregion
10552
- //#region ../theme-core/src/buttons/styles/recipes/staticRecipes.ts
10553
- const softPillRecipe = defineStaticButtonStyleRecipe({
10554
- id: "soft-pill",
10555
- accessibilityLabel: "Rounded pill buttons with a gentle hover lift",
10674
+ ]
10675
+ };
10676
+ const lift = { effectId: "lift" };
10677
+ const flatInkRecipe = defineButtonStyleRecipe({
10678
+ id: "flat-ink",
10679
+ accessibilityLabel: "Flat rounded buttons with arrow affordances",
10556
10680
  tags: {
10557
10681
  tone: "classic",
10558
10682
  energy: "calm",
10559
10683
  motion: "subtle",
10560
- era: "organic"
10684
+ era: "editorial"
10561
10685
  },
10562
- system: {
10686
+ parameterSchema: flatInkParametersSchema,
10687
+ defaultParameters: {},
10688
+ controls: [hoverControl],
10689
+ defineSystem: (parameters) => ({
10563
10690
  global: {
10564
- cornerStyle: "pill",
10565
- shadow: "low",
10691
+ cornerStyle: "rounded",
10566
10692
  textTransform: "none",
10567
- fontWeight: 500,
10693
+ fontWeight: 600,
10694
+ typography: "body",
10695
+ letterSpacing: "tight",
10696
+ paddingPreset: "default",
10568
10697
  hoverTransform: "lift",
10569
10698
  hoverColor: "none"
10570
10699
  },
10700
+ sizes: {
10701
+ sm: {
10702
+ padding: "0.625rem 1.125rem",
10703
+ fontSize: "text-sm"
10704
+ },
10705
+ md: { padding: "0.8125rem 1.375rem" },
10706
+ lg: {
10707
+ padding: "0.9375rem 1.625rem",
10708
+ fontSize: "text-lg"
10709
+ },
10710
+ xl: {
10711
+ padding: "1.0625rem 2rem",
10712
+ fontSize: "text-xl"
10713
+ }
10714
+ },
10571
10715
  roles: {
10572
10716
  primary: {
10573
10717
  kind: "complete",
10574
10718
  appearance: {
10575
10719
  background: {
10576
10720
  type: "solid",
10577
- colorToken: "primary"
10578
- },
10579
- borderRadius: "rounded-full",
10580
- shadow: {
10581
- elevation: "low",
10582
- softness: "soft",
10583
- position: "bottom"
10721
+ colorToken: unsafeAsOpaqueButtonColourToken("primary")
10584
10722
  },
10585
- effects: {
10586
- hover: [{ effectId: "lift" }],
10587
- active: [{
10588
- effectId: "scale-down",
10589
- options: { scale: "0.98" }
10590
- }]
10591
- }
10592
- }
10723
+ borderRadius: "rounded-lg",
10724
+ affordance: { iconId: "ArrowRight" },
10725
+ ...hoverAppearance("primary", parameters, [lift, {
10726
+ effectId: "background-on-hover",
10727
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("secondary") }
10728
+ }])
10729
+ }
10730
+ },
10731
+ secondary: {
10732
+ kind: "complete",
10733
+ appearance: {
10734
+ background: {
10735
+ type: "surface",
10736
+ role: "link"
10737
+ },
10738
+ borderRadius: "rounded-lg",
10739
+ border: { widthClass: "border" },
10740
+ ...hoverAppearance("secondary", parameters, [lift, {
10741
+ effectId: "background-on-hover",
10742
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surfaceAlt") }
10743
+ }])
10744
+ }
10745
+ },
10746
+ outline: {
10747
+ kind: "complete",
10748
+ appearance: {
10749
+ background: {
10750
+ type: "surface",
10751
+ role: "link"
10752
+ },
10753
+ borderRadius: "rounded-lg",
10754
+ border: { widthClass: "border" },
10755
+ ...hoverAppearance("outline", parameters, [lift, {
10756
+ effectId: "background-on-hover",
10757
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surfaceAlt") }
10758
+ }])
10759
+ }
10760
+ },
10761
+ ghost: {
10762
+ kind: "complete",
10763
+ appearance: {
10764
+ background: {
10765
+ type: "surface",
10766
+ role: "link"
10767
+ },
10768
+ borderRadius: "rounded-lg",
10769
+ ...hoverAppearance("ghost", parameters, [lift])
10770
+ }
10771
+ },
10772
+ accent: {
10773
+ kind: "complete",
10774
+ appearance: {
10775
+ background: {
10776
+ type: "solid",
10777
+ colorToken: unsafeAsOpaqueButtonColourToken("accent")
10778
+ },
10779
+ borderRadius: "rounded-lg",
10780
+ affordance: { iconId: "ArrowRight" },
10781
+ ...hoverAppearance("accent", parameters, [lift])
10782
+ }
10783
+ }
10784
+ }
10785
+ })
10786
+ });
10787
+ function hoverAppearance(role, parameters, recommended) {
10788
+ const preference = parameters.hoverPreferences?.[role];
10789
+ if (preference === void 0) return { effects: { hover: [...recommended] } };
10790
+ if (preference === "contextual") {
10791
+ const config = contextualRoleConfig[role];
10792
+ return {
10793
+ effects: { hover: [lift] },
10794
+ contextualHover: {
10795
+ kind: "shade-shift",
10796
+ seedToken: config.contextualSeedToken,
10797
+ fallbackDirection: config.fallbackDirection
10798
+ }
10799
+ };
10800
+ }
10801
+ const config = contextualRoleConfig[role];
10802
+ return {
10803
+ effects: { hover: [lift] },
10804
+ contextualHover: {
10805
+ kind: "shade-shift",
10806
+ seedToken: config.contextualSeedToken,
10807
+ fallbackDirection: config.fallbackDirection,
10808
+ preferredToken: unsafeAsOpaqueButtonColourToken(paletteRole(preference))
10809
+ }
10810
+ };
10811
+ }
10812
+ function paletteRole(preference) {
10813
+ return preference;
10814
+ }
10815
+ //#endregion
10816
+ //#region ../theme-core/src/buttons/styles/recipes/defineStaticButtonStyleRecipe.ts
10817
+ const emptyParametersSchema = z.object({}).strict();
10818
+ function defineStaticButtonStyleRecipe(input) {
10819
+ const system = normalizeSystem(input.system);
10820
+ return defineButtonStyleRecipe({
10821
+ id: input.id,
10822
+ accessibilityLabel: input.accessibilityLabel,
10823
+ tags: input.tags,
10824
+ parameterSchema: emptyParametersSchema,
10825
+ defaultParameters: {},
10826
+ controls: [],
10827
+ defineSystem: () => system
10828
+ });
10829
+ }
10830
+ function normalizeSystem(input) {
10831
+ return {
10832
+ global: buttonGlobalSettingsSchema.parse(input.global),
10833
+ ...input.sizes ? { sizes: input.sizes } : {},
10834
+ roles: {
10835
+ primary: normalizeCompleteRole(input.roles.primary),
10836
+ secondary: normalizeCompleteRole(input.roles.secondary),
10837
+ outline: normalizeSupportingRole(input.roles.outline),
10838
+ ghost: normalizeSupportingRole(input.roles.ghost),
10839
+ accent: normalizeSupportingRole(input.roles.accent)
10840
+ }
10841
+ };
10842
+ }
10843
+ function normalizeCompleteRole(role) {
10844
+ return {
10845
+ kind: "complete",
10846
+ appearance: normalizeAppearance(role.appearance)
10847
+ };
10848
+ }
10849
+ function normalizeSupportingRole(role) {
10850
+ if (role.kind === "complete") return normalizeCompleteRole(role);
10851
+ return {
10852
+ kind: "derive",
10853
+ from: role.from,
10854
+ ...role.overrides ? { overrides: normalizeAppearanceOverrides(role.overrides) } : {}
10855
+ };
10856
+ }
10857
+ function normalizeAppearance(appearance) {
10858
+ const { background, hoverBackgroundToken, ...rest } = appearance;
10859
+ return {
10860
+ ...rest,
10861
+ background: buttonColourTreatmentSchema.parse(background),
10862
+ ...hoverBackgroundToken ? { hoverBackgroundToken: opaqueButtonColourTokenSchema.parse(hoverBackgroundToken) } : {}
10863
+ };
10864
+ }
10865
+ function normalizeAppearanceOverrides(overrides) {
10866
+ const { background, hoverBackgroundToken, ...rest } = overrides;
10867
+ return {
10868
+ ...rest,
10869
+ ...background ? { background: buttonColourTreatmentSchema.parse(background) } : {},
10870
+ ...hoverBackgroundToken ? { hoverBackgroundToken: opaqueButtonColourTokenSchema.parse(hoverBackgroundToken) } : {}
10871
+ };
10872
+ }
10873
+ //#endregion
10874
+ //#region ../theme-core/src/buttons/styles/recipes/staticRecipes.ts
10875
+ const softPillRecipe = defineStaticButtonStyleRecipe({
10876
+ id: "soft-pill",
10877
+ accessibilityLabel: "Rounded pill buttons with a gentle hover lift",
10878
+ tags: {
10879
+ tone: "classic",
10880
+ energy: "calm",
10881
+ motion: "subtle",
10882
+ era: "organic"
10883
+ },
10884
+ system: {
10885
+ global: {
10886
+ cornerStyle: "pill",
10887
+ shadow: "low",
10888
+ textTransform: "none",
10889
+ fontWeight: 500,
10890
+ hoverTransform: "lift",
10891
+ hoverColor: "none"
10892
+ },
10893
+ roles: {
10894
+ primary: {
10895
+ kind: "complete",
10896
+ appearance: {
10897
+ background: {
10898
+ type: "solid",
10899
+ colorToken: "primary"
10900
+ },
10901
+ borderRadius: "rounded-full",
10902
+ shadow: {
10903
+ elevation: "low",
10904
+ softness: "soft",
10905
+ position: "bottom"
10906
+ },
10907
+ effects: {
10908
+ hover: [{ effectId: "lift" }],
10909
+ active: [{
10910
+ effectId: "scale-down",
10911
+ options: { scale: "0.98" }
10912
+ }]
10913
+ }
10914
+ }
10593
10915
  },
10594
10916
  secondary: {
10595
10917
  kind: "complete",
@@ -11337,113 +11659,6 @@ const inkStampRecipe = defineStaticButtonStyleRecipe({
11337
11659
  }
11338
11660
  }
11339
11661
  });
11340
- const flatInkRecipe = defineStaticButtonStyleRecipe({
11341
- id: "flat-ink",
11342
- accessibilityLabel: "Flat rounded buttons with arrow affordances",
11343
- tags: {
11344
- tone: "classic",
11345
- energy: "calm",
11346
- motion: "subtle",
11347
- era: "editorial"
11348
- },
11349
- system: {
11350
- global: {
11351
- cornerStyle: "rounded",
11352
- textTransform: "none",
11353
- fontWeight: 600,
11354
- typography: "body",
11355
- letterSpacing: "tight",
11356
- paddingPreset: "default",
11357
- hoverTransform: "lift",
11358
- hoverColor: "none"
11359
- },
11360
- sizes: {
11361
- sm: {
11362
- padding: "0.625rem 1.125rem",
11363
- fontSize: "text-sm"
11364
- },
11365
- md: { padding: "0.8125rem 1.375rem" },
11366
- lg: {
11367
- padding: "0.9375rem 1.625rem",
11368
- fontSize: "text-lg"
11369
- },
11370
- xl: {
11371
- padding: "1.0625rem 2rem",
11372
- fontSize: "text-xl"
11373
- }
11374
- },
11375
- roles: {
11376
- primary: {
11377
- kind: "complete",
11378
- appearance: {
11379
- background: {
11380
- type: "solid",
11381
- colorToken: "primary"
11382
- },
11383
- borderRadius: "rounded-lg",
11384
- affordance: { iconId: "ArrowRight" },
11385
- effects: { hover: [{ effectId: "lift" }, {
11386
- effectId: "background-on-hover",
11387
- options: { colorToken: unsafeAsOpaqueButtonColourToken("secondary") }
11388
- }] }
11389
- }
11390
- },
11391
- secondary: {
11392
- kind: "complete",
11393
- appearance: {
11394
- background: {
11395
- type: "surface",
11396
- role: "link"
11397
- },
11398
- borderRadius: "rounded-lg",
11399
- border: { widthClass: "border" },
11400
- effects: { hover: [{ effectId: "lift" }, {
11401
- effectId: "background-on-hover",
11402
- options: { colorToken: unsafeAsOpaqueButtonColourToken("surfaceAlt") }
11403
- }] }
11404
- }
11405
- },
11406
- outline: {
11407
- kind: "complete",
11408
- appearance: {
11409
- background: {
11410
- type: "surface",
11411
- role: "link"
11412
- },
11413
- borderRadius: "rounded-lg",
11414
- border: { widthClass: "border" },
11415
- effects: { hover: [{ effectId: "lift" }, {
11416
- effectId: "background-on-hover",
11417
- options: { colorToken: unsafeAsOpaqueButtonColourToken("surfaceAlt") }
11418
- }] }
11419
- }
11420
- },
11421
- ghost: {
11422
- kind: "complete",
11423
- appearance: {
11424
- background: {
11425
- type: "surface",
11426
- role: "link"
11427
- },
11428
- borderRadius: "rounded-lg",
11429
- effects: { hover: [{ effectId: "lift" }] }
11430
- }
11431
- },
11432
- accent: {
11433
- kind: "complete",
11434
- appearance: {
11435
- background: {
11436
- type: "solid",
11437
- colorToken: "accent"
11438
- },
11439
- borderRadius: "rounded-lg",
11440
- affordance: { iconId: "ArrowRight" },
11441
- effects: { hover: [{ effectId: "lift" }] }
11442
- }
11443
- }
11444
- }
11445
- }
11446
- });
11447
11662
  const showtimePillRecipe = defineStaticButtonStyleRecipe({
11448
11663
  id: "showtime-pill",
11449
11664
  accessibilityLabel: "Bold uppercase pill buttons with playful movement",
@@ -12198,17 +12413,17 @@ function StepIndicator({ currentStep, totalSteps, stepLabels, classPrefix, emitS
12198
12413
  //#endregion
12199
12414
  //#region ../blocks/src/system/runtime/shared/components/DiscountCodeDisclosure.tsx
12200
12415
  const BLOCK_DISCOUNT_CODE_DISCLOSURE_CLASSES = {
12201
- "course-registration": {
12202
- root: "cr-discount",
12203
- toggle: "cr-discount__toggle",
12204
- form: "cr-discount__form",
12205
- label: "cr-discount__label",
12206
- row: "cr-discount__row",
12207
- input: "cr-discount__input",
12208
- apply: "cr-discount__apply",
12209
- remove: "cr-discount__remove",
12210
- hint: "cr-discount__hint",
12211
- feedback: "cr-discount__feedback"
12416
+ "whole-series-registration": {
12417
+ root: "er-whole-series-discount",
12418
+ toggle: "er-whole-series-discount__toggle",
12419
+ form: "er-whole-series-discount__form",
12420
+ label: "er-whole-series-discount__label",
12421
+ row: "er-whole-series-discount__row",
12422
+ input: "er-whole-series-discount__input",
12423
+ apply: "er-whole-series-discount__apply",
12424
+ remove: "er-whole-series-discount__remove",
12425
+ hint: "er-whole-series-discount__hint",
12426
+ feedback: "er-whole-series-discount__feedback"
12212
12427
  },
12213
12428
  "event-registration": {
12214
12429
  root: "er-discount",
@@ -12316,27 +12531,789 @@ function DiscountCodeDisclosure({ surface, isOpen, code, onOpen, onChange, onRem
12316
12531
  });
12317
12532
  }
12318
12533
  //#endregion
12319
- //#region ../blocks/src/system/runtime/shared/components/FieldValidationMessage.tsx
12320
- function getFieldValidationControlProps({ message, messageId, describedBy }) {
12321
- const hasMessage = Boolean(message);
12322
- const ariaDescribedBy = [describedBy, hasMessage ? messageId : void 0].filter((part) => typeof part === "string" && part.length > 0).join(" ");
12323
- return {
12324
- "aria-invalid": hasMessage ? "true" : void 0,
12325
- "aria-describedby": ariaDescribedBy || void 0
12326
- };
12534
+ //#region ../blocks/src/system/runtime/shared/components/FieldValidationMessage.tsx
12535
+ function getFieldValidationControlProps({ message, messageId, describedBy }) {
12536
+ const hasMessage = Boolean(message);
12537
+ const ariaDescribedBy = [describedBy, hasMessage ? messageId : void 0].filter((part) => typeof part === "string" && part.length > 0).join(" ");
12538
+ return {
12539
+ "aria-invalid": hasMessage ? "true" : void 0,
12540
+ "aria-describedby": ariaDescribedBy || void 0
12541
+ };
12542
+ }
12543
+ function FieldValidationMessage({ id, children, className, live = "assertive" }) {
12544
+ return /* @__PURE__ */ jsx("p", {
12545
+ id,
12546
+ className,
12547
+ "data-field-validation-message": true,
12548
+ "data-field-validation-tone": "error",
12549
+ role: "alert",
12550
+ "aria-live": live === "off" ? void 0 : live,
12551
+ children
12552
+ });
12553
+ }
12554
+ //#endregion
12555
+ //#region ../blocks/src/primitives/content/utils/sanitizeHref.ts
12556
+ const SAFE_PROTOCOLS = /* @__PURE__ */ new Set([
12557
+ "http:",
12558
+ "https:",
12559
+ "mailto:",
12560
+ "tel:"
12561
+ ]);
12562
+ const CONTROL_CHARS_PATTERN = /[\u0000-\u001F\u007F]+/g;
12563
+ function normalizeInput(value) {
12564
+ return value.replace(CONTROL_CHARS_PATTERN, "").trim();
12565
+ }
12566
+ function decodeForSchemeCheck(value) {
12567
+ try {
12568
+ return decodeURIComponent(value);
12569
+ } catch {
12570
+ return value;
12571
+ }
12572
+ }
12573
+ /**
12574
+ * Returns a safe href for rich-text anchors, or null when the value should not be rendered.
12575
+ *
12576
+ * Policy:
12577
+ * - Allow absolute URLs with protocols: http, https, mailto, tel.
12578
+ * - Allow root-relative ("/path") and hash-only ("#section") links.
12579
+ * - Reject protocol-relative URLs ("//example.com"), bare domains ("example.com"),
12580
+ * executable schemes (javascript/data/vbscript), malformed URLs, and empty values.
12581
+ * - Preserve percent-encoding from the original normalized input.
12582
+ */
12583
+ function sanitizeHref(raw) {
12584
+ if (typeof raw !== "string") return null;
12585
+ const normalized = normalizeInput(raw);
12586
+ if (!normalized) return null;
12587
+ if (normalized.startsWith("//")) return null;
12588
+ if (normalized.startsWith("/")) return normalized;
12589
+ if (normalized.startsWith("#")) return normalized;
12590
+ const schemeMatch = normalizeInput(decodeForSchemeCheck(normalized)).match(/^([a-zA-Z][a-zA-Z0-9+.-]*):/);
12591
+ if (!schemeMatch) return null;
12592
+ const rawScheme = schemeMatch[1];
12593
+ if (!rawScheme) return null;
12594
+ const protocol = `${rawScheme.toLowerCase()}:`;
12595
+ if (!SAFE_PROTOCOLS.has(protocol)) return null;
12596
+ try {
12597
+ const parsed = new URL(normalized);
12598
+ if (!SAFE_PROTOCOLS.has(parsed.protocol.toLowerCase())) return null;
12599
+ } catch {
12600
+ return null;
12601
+ }
12602
+ return normalized;
12603
+ }
12604
+ //#endregion
12605
+ //#region ../media-core/src/fileSafety.ts
12606
+ const CONTROL_CHARACTER_PATTERN = /[\u0000-\u001f\u007f]/u;
12607
+ function containsUnsafePathSegmentCharacter(value) {
12608
+ return value.includes("/") || value.includes("\\") || CONTROL_CHARACTER_PATTERN.test(value);
12609
+ }
12610
+ function isReservedPathSegment(value) {
12611
+ return value === "." || value === "..";
12612
+ }
12613
+ function isUnsafePathSegment(segment) {
12614
+ return segment.trim().length === 0 || segment !== segment.trim() || isReservedPathSegment(segment) || containsUnsafePathSegmentCharacter(segment);
12615
+ }
12616
+ ({
12617
+ publicSite: unsafeAsStorageBucketName("media"),
12618
+ privateSite: unsafeAsStorageBucketName("site-files-private"),
12619
+ temporary: unsafeAsStorageBucketName("temp-uploads")
12620
+ }).publicSite;
12621
+ function parseStoragePath(value) {
12622
+ return joinStoragePathSegments(value.split("/"));
12623
+ }
12624
+ /**
12625
+ * Joins already-branded path segments while preserving the Storage RLS invariant
12626
+ * that every tenant/site identifier remains one segment, never a nested path.
12627
+ */
12628
+ function joinStoragePathSegments(segments) {
12629
+ if (segments.some(isUnsafePathSegment)) return err$1("unsafe-path-segment");
12630
+ return ok$1(unsafeAsStoragePath(segments.join("/")));
12631
+ }
12632
+ //#endregion
12633
+ //#region ../media-core/src/storagePathDomain.ts
12634
+ function ok(value) {
12635
+ return {
12636
+ ok: true,
12637
+ value
12638
+ };
12639
+ }
12640
+ function fail(error) {
12641
+ return {
12642
+ ok: false,
12643
+ error
12644
+ };
12645
+ }
12646
+ function normalizeStringInput(value) {
12647
+ if (typeof value !== "string") return fail({ tag: "MISSING" });
12648
+ const trimmed = value.trim();
12649
+ if (!trimmed) return fail({ tag: "EMPTY" });
12650
+ return ok(trimmed);
12651
+ }
12652
+ function validateRelativeStoragePath(value) {
12653
+ if (value.startsWith("sites/")) return fail({ tag: "SITE_SCOPED_PATH" });
12654
+ if (value.startsWith("/")) return fail({ tag: "LEADING_SLASH" });
12655
+ if (value.includes("//")) return fail({ tag: "DOUBLE_SLASH" });
12656
+ if (value.includes("%")) return fail({ tag: "PERCENT_ENCODING" });
12657
+ if (value.split("/").some((segment) => segment === "." || segment === "..")) return fail({ tag: "TRAVERSAL" });
12658
+ return ok(value);
12659
+ }
12660
+ function brandRelativeStoragePath(value) {
12661
+ return value;
12662
+ }
12663
+ function parseRelativeStoragePath(value) {
12664
+ const normalized = normalizeStringInput(value);
12665
+ if (!normalized.ok) return normalized;
12666
+ const validated = validateRelativeStoragePath(normalized.value);
12667
+ if (!validated.ok) return validated;
12668
+ return ok(brandRelativeStoragePath(validated.value));
12669
+ }
12670
+ //#endregion
12671
+ //#region ../media-core/src/url.ts
12672
+ const DEFAULT_BASE_PATH = "/api/img";
12673
+ function isSiteScopedDirectImageStoragePath(storagePath) {
12674
+ return storagePath.startsWith("sites/") && parseStoragePath(storagePath).ok;
12675
+ }
12676
+ function encodeStoragePath(storagePath) {
12677
+ return storagePath.split("/").map((segment) => encodeURIComponent(segment)).join("/");
12678
+ }
12679
+ function resolveDirectImagePathTarget(target) {
12680
+ switch (target.kind) {
12681
+ case "relative": return `sites/${target.siteId}/${target.storagePath}`;
12682
+ case "site-scoped":
12683
+ case "bucket-scoped": return target.storagePath;
12684
+ }
12685
+ }
12686
+ function getDirectImageUrl(supabaseUrl, target, storageBucket = "media", options) {
12687
+ const baseUrl = supabaseUrl.replace(/\/$/, "");
12688
+ const encodedPath = encodeStoragePath(resolveDirectImagePathTarget(target));
12689
+ const isSvg = target.storagePath.toLowerCase().endsWith(".svg");
12690
+ if (options && !isSvg && (options.width || options.height)) {
12691
+ const params = new URLSearchParams();
12692
+ if (options.width) params.set("width", String(options.width));
12693
+ if (options.height) params.set("height", String(options.height));
12694
+ if (options.quality) params.set("quality", String(options.quality));
12695
+ if (options.resize) params.set("resize", options.resize);
12696
+ return `${baseUrl}/storage/v1/render/image/public/${storageBucket}/${encodedPath}?${params.toString()}`;
12697
+ }
12698
+ return `${baseUrl}/storage/v1/object/public/${storageBucket}/${encodedPath}`;
12699
+ }
12700
+ function getDirectImageUrlForRelativePath(supabaseUrl, storagePath, siteId, storageBucket = "media", options) {
12701
+ return getDirectImageUrl(supabaseUrl, {
12702
+ kind: "relative",
12703
+ storagePath,
12704
+ siteId
12705
+ }, storageBucket, options);
12706
+ }
12707
+ function getDirectImageUrlForSiteScopedPath(supabaseUrl, storagePath, storageBucket = "media", options) {
12708
+ return getDirectImageUrl(supabaseUrl, {
12709
+ kind: "site-scoped",
12710
+ storagePath
12711
+ }, storageBucket, options);
12712
+ }
12713
+ const formatNumber = (value) => Number.isInteger(value) ? value.toString() : value.toFixed(6).replace(/0+$/, "").replace(/\.$/, "");
12714
+ const ORDER = [
12715
+ "w",
12716
+ "h",
12717
+ "fit",
12718
+ "rect",
12719
+ "q",
12720
+ "autoFormat",
12721
+ "or"
12722
+ ];
12723
+ const getImageUrl = (asset, params = {}, basePath = DEFAULT_BASE_PATH) => {
12724
+ const path = `${basePath.endsWith("/") ? basePath.slice(0, Math.max(basePath.length - 1, 0)) : basePath}/${encodeURIComponent(asset.id)}`;
12725
+ const searchParams = new URLSearchParams();
12726
+ if (params.w !== void 0) searchParams.set("w", formatNumber(params.w));
12727
+ if (params.h !== void 0) searchParams.set("h", formatNumber(params.h));
12728
+ if (params.fit !== void 0) searchParams.set("fit", params.fit);
12729
+ if (params.rect) searchParams.set("rect", params.rect.map(formatNumber).join(","));
12730
+ if (params.q !== void 0) searchParams.set("q", formatNumber(params.q));
12731
+ if (params.autoFormat) searchParams.append("auto", "format");
12732
+ if (params.or !== void 0) searchParams.set("or", String(params.or));
12733
+ const sorted = new URLSearchParams();
12734
+ ORDER.forEach((key) => {
12735
+ if (key === "autoFormat") {
12736
+ if (params.autoFormat) sorted.append("auto", "format");
12737
+ return;
12738
+ }
12739
+ const value = searchParams.get(key);
12740
+ if (value !== null) sorted.set(key, value);
12741
+ });
12742
+ const query = sorted.toString();
12743
+ return query ? `${path}?${query}` : path;
12744
+ };
12745
+ //#endregion
12746
+ //#region ../media-core/src/transformRect.ts
12747
+ function isValidTransformRectStructure(rect) {
12748
+ if (!Array.isArray(rect) || rect.length !== 4) return false;
12749
+ const [left, top, width, height] = rect;
12750
+ return Number.isFinite(left) && Number.isFinite(top) && Number.isFinite(width) && Number.isFinite(height) && left >= 0 && top >= 0 && width > 0 && height > 0;
12751
+ }
12752
+ //#endregion
12753
+ //#region ../media-core/src/aspectTransforms.ts
12754
+ const DEFAULT_RECT_EPSILON = .5;
12755
+ function parseAspectRatioValue(value) {
12756
+ if (typeof value === "number") return Number.isFinite(value) && value > 0 ? value : void 0;
12757
+ if (typeof value !== "string") return void 0;
12758
+ const normalized = value.trim();
12759
+ if (!normalized) return void 0;
12760
+ if (normalized === "auto") return void 0;
12761
+ if (normalized.includes(":") || normalized.includes("/")) {
12762
+ const delimiter = normalized.includes(":") ? ":" : "/";
12763
+ const [wRaw, hRaw] = normalized.split(delimiter);
12764
+ const width = Number(wRaw?.trim());
12765
+ const height = Number(hRaw?.trim());
12766
+ if (!Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0) return;
12767
+ return width / height;
12768
+ }
12769
+ const numeric = Number(normalized);
12770
+ if (!Number.isFinite(numeric) || numeric <= 0) return void 0;
12771
+ return numeric;
12772
+ }
12773
+ const MAX_ASPECT_DISTANCE = .25;
12774
+ function resolveMediaTransformForAspect(transform, targetAspect) {
12775
+ if (!transform) return {};
12776
+ const base = {
12777
+ rect: transform.rect,
12778
+ hotspot: transform.hotspot,
12779
+ rotation: transform.rotation
12780
+ };
12781
+ const target = parseAspectRatioValue(targetAspect);
12782
+ const crops = transform.aspectCrops;
12783
+ if (!target || !crops || Object.keys(crops).length === 0) return base;
12784
+ let best = null;
12785
+ let bestDistance = Number.POSITIVE_INFINITY;
12786
+ for (const [key, candidate] of Object.entries(crops)) {
12787
+ const candidateAspect = parseAspectRatioValue(candidate.aspect ?? key);
12788
+ if (!candidateAspect) continue;
12789
+ const distance = Math.abs(Math.log(candidateAspect / target));
12790
+ if (distance < bestDistance) {
12791
+ best = candidate;
12792
+ bestDistance = distance;
12793
+ }
12794
+ }
12795
+ if (!best) return base;
12796
+ if (bestDistance > MAX_ASPECT_DISTANCE) return base;
12797
+ return {
12798
+ rect: best.rect ?? base.rect,
12799
+ hotspot: best.hotspot ?? base.hotspot,
12800
+ rotation: best.rotation ?? base.rotation
12801
+ };
12802
+ }
12803
+ function isValidTransformRect(rect) {
12804
+ return isValidTransformRectStructure(rect);
12805
+ }
12806
+ function isExplicitRectCrop(rect, sourceWidth, sourceHeight, epsilon = DEFAULT_RECT_EPSILON) {
12807
+ if (!isValidTransformRect(rect)) return false;
12808
+ if (!(typeof sourceWidth === "number" && Number.isFinite(sourceWidth) && sourceWidth > 0 && typeof sourceHeight === "number" && Number.isFinite(sourceHeight) && sourceHeight > 0)) return true;
12809
+ const [x, y, width, height] = rect;
12810
+ return !(Math.abs(x) <= epsilon && Math.abs(y) <= epsilon && Math.abs(width - sourceWidth) <= epsilon && Math.abs(height - sourceHeight) <= epsilon);
12811
+ }
12812
+ //#endregion
12813
+ //#region ../media-core/src/renderableMediaAsset.ts
12814
+ function attachRenderableMediaAssetFields(media, asset) {
12815
+ return {
12816
+ ...media,
12817
+ assetId: asset.id,
12818
+ id: asset.id,
12819
+ identifier: mediaIdentifierOrFallback(media.identifier, asset.identifier),
12820
+ storageBucket: asset.storageBucket ?? media.storageBucket,
12821
+ storagePath: asset.storagePath ?? media.storagePath,
12822
+ width: asset.width ?? media.width,
12823
+ height: asset.height ?? media.height,
12824
+ mimeType: asset.mimeType ?? media.mimeType
12825
+ };
12826
+ }
12827
+ /**
12828
+ * Preserve an explicit per-usage identifier when one exists. Otherwise prefer
12829
+ * the canonical asset identifier, while keeping intentionally blank legacy
12830
+ * string values from becoming null.
12831
+ */
12832
+ function mediaIdentifierOrFallback(current, fallback) {
12833
+ if (typeof current === "string" && current.trim().length > 0) return current;
12834
+ return fallback ?? (typeof current === "string" ? current : void 0);
12835
+ }
12836
+ //#endregion
12837
+ //#region ../blocks/src/system/runtime/nodes/media.tsx
12838
+ const MAX_RENDER_DIMENSION = 4096;
12839
+ const RELATIVE_IMG_PROXY_BASE_PATH = "/api/img";
12840
+ function getValidSourceDimension(value) {
12841
+ return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : void 0;
12842
+ }
12843
+ function isExplicitCropProxyEnabled() {
12844
+ const raw = process.env.NEXT_PUBLIC_MEDIA_EXPLICIT_CROP_PROXY_ENABLED ?? process.env.MEDIA_EXPLICIT_CROP_PROXY_ENABLED;
12845
+ if (!raw) return true;
12846
+ const normalized = raw.trim().toLowerCase();
12847
+ return !(normalized === "0" || normalized === "false" || normalized === "no" || normalized === "off");
12848
+ }
12849
+ function getRequestedDimension(value) {
12850
+ if (typeof value !== "number" || !Number.isFinite(value)) return void 0;
12851
+ return Math.min(MAX_RENDER_DIMENSION, Math.max(1, Math.round(value)));
12852
+ }
12853
+ function mapResizeToFit(resize) {
12854
+ if (resize === "contain") return "clip";
12855
+ return "crop";
12856
+ }
12857
+ function shouldUseExplicitRectProxy(value, options, resolvedTransform, sourceWidth, sourceHeight) {
12858
+ if ("original" in options && options.original) return false;
12859
+ if (!isExplicitCropProxyEnabled()) return false;
12860
+ if (!value.assetId) return false;
12861
+ if (typeof resolvedTransform.rotation === "number" && resolvedTransform.rotation !== 0) return true;
12862
+ return isExplicitRectCrop(resolvedTransform.rect, sourceWidth, sourceHeight);
12863
+ }
12864
+ function buildProxyTransformParams(options, resolvedTransform) {
12865
+ const params = {
12866
+ w: "width" in options ? getRequestedDimension(options.width) : void 0,
12867
+ h: "height" in options ? getRequestedDimension(options.height) : void 0,
12868
+ q: "quality" in options ? options.quality : void 0,
12869
+ fit: mapResizeToFit("resize" in options ? options.resize : void 0),
12870
+ autoFormat: true
12871
+ };
12872
+ if (resolvedTransform.rect) params.rect = resolvedTransform.rect;
12873
+ if (resolvedTransform.rotation) params.or = resolvedTransform.rotation;
12874
+ return params;
12875
+ }
12876
+ function buildDirectTransformOptions(options) {
12877
+ if ("original" in options && options.original) return void 0;
12878
+ return {
12879
+ width: "width" in options ? getRequestedDimension(options.width) : void 0,
12880
+ height: "height" in options ? getRequestedDimension(options.height) : void 0,
12881
+ quality: "quality" in options ? options.quality : void 0,
12882
+ resize: "resize" in options ? options.resize : void 0
12883
+ };
12884
+ }
12885
+ function resolveTransformResolution(value, targetAspectRatio) {
12886
+ return {
12887
+ resolvedTransform: resolveMediaTransformForAspect(value.transform, targetAspectRatio),
12888
+ sourceWidth: getValidSourceDimension(value.width),
12889
+ sourceHeight: getValidSourceDimension(value.height)
12890
+ };
12891
+ }
12892
+ function getProxyImageUrl(value, options, transformAspectRatio, resolved) {
12893
+ if (!value.assetId) return void 0;
12894
+ const targetAspect = transformAspectRatio ?? resolveTargetAspectRatio(options);
12895
+ const { resolvedTransform, sourceWidth, sourceHeight } = resolved ?? resolveTransformResolution(value, targetAspect);
12896
+ if (!shouldUseExplicitRectProxy(value, options, resolvedTransform, sourceWidth, sourceHeight)) return void 0;
12897
+ const params = buildProxyTransformParams(options, resolvedTransform);
12898
+ const proxyBasePath = getImageProxyBasePath();
12899
+ const proxyUrl = getImageUrl({ id: unsafeAsMediaAssetId(value.assetId) }, params, proxyBasePath);
12900
+ debugMediaNodeLog("resolve:proxy-img", {
12901
+ assetId: value.assetId,
12902
+ params,
12903
+ proxyBasePath,
12904
+ proxyUrl
12905
+ });
12906
+ return proxyUrl;
12907
+ }
12908
+ function warnForMediaUrlResolution(result) {
12909
+ switch (result.kind) {
12910
+ case "missing-site-context":
12911
+ console.warn(`[blocks] Relative storagePath "${result.storagePath}" requires siteId context. Media URL may be incorrect. Ensure siteId is set via runWithMediaContext or setContextSiteId.`);
12912
+ return;
12913
+ case "missing-supabase-url":
12914
+ console.warn(`[blocks] ${result.message} Media URL may be unavailable. Ensure NEXT_PUBLIC_SUPABASE_URL is configured or pass supabaseUrl in the media context.`);
12915
+ return;
12916
+ case "invalid-storage-path":
12917
+ console.warn(`[blocks] Invalid media storagePath "${result.storagePath}".`);
12918
+ return;
12919
+ case "resolved":
12920
+ case "unsupported-media-type":
12921
+ case "missing-storage-path":
12922
+ case "missing-image-url": return;
12923
+ }
12924
+ }
12925
+ function resolveMediaStorageUrlResult(value, context, transformOptions) {
12926
+ const canonical = resolveMediaWithCanonicalAsset(value, context ?? void 0);
12927
+ if (!canonical.storagePath || canonical.storagePath.length === 0) return {
12928
+ kind: "missing-storage-path",
12929
+ assetId: canonical.assetId,
12930
+ identifier: canonical.identifier
12931
+ };
12932
+ const siteId = context?.siteId ?? getSiteId();
12933
+ const bucket = canonical.storageBucket ?? "media";
12934
+ const siteScopedPath = isSiteScopedDirectImageStoragePath(canonical.storagePath) ? canonical.storagePath : null;
12935
+ let supabaseUrl;
12936
+ try {
12937
+ supabaseUrl = context?.supabaseUrl?.replace(/\/$/, "") ?? getSupabaseUrl();
12938
+ } catch (error) {
12939
+ return {
12940
+ kind: "missing-supabase-url",
12941
+ message: error instanceof Error ? error.message : "Supabase URL is not configured."
12942
+ };
12943
+ }
12944
+ let directUrl;
12945
+ if (siteScopedPath) directUrl = getDirectImageUrlForSiteScopedPath(supabaseUrl, siteScopedPath, bucket, transformOptions);
12946
+ else {
12947
+ const relativePath = parseRelativeStoragePath(canonical.storagePath);
12948
+ if (!relativePath.ok) return {
12949
+ kind: "invalid-storage-path",
12950
+ storagePath: canonical.storagePath
12951
+ };
12952
+ if (!siteId) return {
12953
+ kind: "missing-site-context",
12954
+ storagePath: canonical.storagePath
12955
+ };
12956
+ directUrl = getDirectImageUrlForRelativePath(supabaseUrl, relativePath.value, siteId, bucket, transformOptions);
12957
+ }
12958
+ debugMediaNodeLog("resolve:direct-supabase", {
12959
+ storagePath: canonical.storagePath,
12960
+ siteId,
12961
+ bucket,
12962
+ directUrl,
12963
+ transformOptions
12964
+ });
12965
+ return {
12966
+ kind: "resolved",
12967
+ url: directUrl
12968
+ };
12969
+ }
12970
+ function getDirectImageUrlForValue(value, options, context) {
12971
+ const result = resolveMediaStorageUrlResult(value, context, buildDirectTransformOptions(options));
12972
+ return result.kind === "resolved" ? result.url : void 0;
12973
+ }
12974
+ function resolveStorageImageUrl(value, options, context, transformAspectRatio, resolved) {
12975
+ const proxyUrl = getProxyImageUrl(value, options, transformAspectRatio, resolved);
12976
+ if (proxyUrl) return proxyUrl;
12977
+ const directUrl = getDirectImageUrlForValue(value, options, context);
12978
+ if (directUrl) return directUrl;
12979
+ }
12980
+ /**
12981
+ * Common image size presets.
12982
+ * Use these for consistent sizing across the application.
12983
+ */
12984
+ const ImagePresets = {
12985
+ /** Small thumbnails (200px) - for block previews, lists */
12986
+ thumbnail: {
12987
+ width: 200,
12988
+ quality: 80,
12989
+ resize: "contain"
12990
+ },
12991
+ /** Card-sized images (600px) - for cards, grids */
12992
+ card: {
12993
+ width: 600,
12994
+ quality: 80,
12995
+ resize: "contain"
12996
+ },
12997
+ /** Hero images (1200px) - for above-fold content */
12998
+ hero: {
12999
+ width: 1200,
13000
+ quality: 85,
13001
+ resize: "contain"
13002
+ },
13003
+ /** Full-width images (1920px) - for backgrounds, large displays */
13004
+ full: {
13005
+ width: 1920,
13006
+ quality: 85,
13007
+ resize: "contain"
13008
+ }
13009
+ };
13010
+ /**
13011
+ * Server-side: AsyncLocalStorage for request isolation.
13012
+ * Prevents race conditions when multiple requests are processed concurrently.
13013
+ *
13014
+ * Lazy initialization to avoid issues in environments that don't support async_hooks.
13015
+ */
13016
+ let _serverStorage = null;
13017
+ let _serverStorageChecked = false;
13018
+ function getServerStorage() {
13019
+ if (typeof window !== "undefined") return null;
13020
+ if (_serverStorageChecked) return _serverStorage;
13021
+ _serverStorageChecked = true;
13022
+ try {
13023
+ const globalWithNonWebpackRequire = globalThis;
13024
+ const AsyncLocalStorage = (typeof globalWithNonWebpackRequire.__non_webpack_require__ === "function" ? globalWithNonWebpackRequire.__non_webpack_require__ : new Function("id", "return require(id)"))("async_hooks").AsyncLocalStorage;
13025
+ if (AsyncLocalStorage) {
13026
+ _serverStorage = new AsyncLocalStorage();
13027
+ return _serverStorage;
13028
+ }
13029
+ return null;
13030
+ } catch {
13031
+ console.warn("[blocks] AsyncLocalStorage not available - using module-level state");
13032
+ return null;
13033
+ }
13034
+ }
13035
+ /**
13036
+ * Client-side context storage.
13037
+ * Safe because browsers are single-threaded per tab.
13038
+ *
13039
+ * IMPORTANT: This must be shared across bundles.
13040
+ * SDK preview mode can load multiple independently-bundled entrypoints
13041
+ * (e.g. `@riverbankcms/sdk/rendering` + `@riverbankcms/sdk/preview-next/client`),
13042
+ * which can otherwise each get their own module-scoped singleton.
13043
+ */
13044
+ const RB_MEDIA_CONTEXT_KEY = Symbol.for("riverbankcms.blocks.mediaContext");
13045
+ function getClientContextStore() {
13046
+ const g = globalThis;
13047
+ const existing = g[RB_MEDIA_CONTEXT_KEY];
13048
+ if (existing && typeof existing === "object") return existing;
13049
+ const next = {};
13050
+ g[RB_MEDIA_CONTEXT_KEY] = next;
13051
+ return next;
13052
+ }
13053
+ /**
13054
+ * Get the current media context.
13055
+ * Server-side: Uses AsyncLocalStorage for request isolation.
13056
+ * Client-side: Uses module-level state (safe in single-threaded browser).
13057
+ */
13058
+ function getMediaContext() {
13059
+ const storage = getServerStorage();
13060
+ if (storage) return storage.getStore() ?? {};
13061
+ return getClientContextStore();
13062
+ }
13063
+ function getCurrentResolveImageUrlContext() {
13064
+ const context = getMediaContext();
13065
+ if (!context.supabaseUrl && !context.siteId && !context.mediaAssetIndex) return;
13066
+ return {
13067
+ supabaseUrl: context.supabaseUrl,
13068
+ siteId: context.siteId,
13069
+ mediaAssetIndex: context.mediaAssetIndex
13070
+ };
13071
+ }
13072
+ /**
13073
+ * Get the Supabase URL for constructing direct storage URLs.
13074
+ * Used for serving images directly from Supabase storage CDN.
13075
+ *
13076
+ * Resolution order:
13077
+ * 1. Context URL (set via runWithMediaContext or setContextSupabaseUrl)
13078
+ * 2. Environment variable NEXT_PUBLIC_SUPABASE_URL
13079
+ *
13080
+ * SDK sites receive the URL from the API, so they don't need the env var.
13081
+ * Dashboard and frontend apps use the env var.
13082
+ */
13083
+ function getSupabaseUrl() {
13084
+ const context = getMediaContext();
13085
+ if (context.supabaseUrl) return context.supabaseUrl;
13086
+ const url = process.env.NEXT_PUBLIC_SUPABASE_URL;
13087
+ if (!url) throw new Error("NEXT_PUBLIC_SUPABASE_URL is not configured. Set it to your Supabase project URL (e.g., https://xxx.supabase.co)");
13088
+ return url.replace(/\/$/, "");
13089
+ }
13090
+ function resolveDashboardOrigin(raw) {
13091
+ if (!raw) return void 0;
13092
+ const trimmed = raw.trim();
13093
+ if (!trimmed) return void 0;
13094
+ const withoutApiSuffix = trimmed.replace(/\/+$/, "").replace(/\/api\/?$/, "");
13095
+ const normalized = /^https?:\/\//i.test(withoutApiSuffix) ? withoutApiSuffix : `http://${withoutApiSuffix.replace(/^\/+/, "")}`;
13096
+ try {
13097
+ return new URL(normalized).origin;
13098
+ } catch {
13099
+ return;
13100
+ }
13101
+ }
13102
+ function getImageProxyBasePath() {
13103
+ const dashboardOrigin = resolveDashboardOrigin(process.env.NEXT_PUBLIC_DASHBOARD_URL);
13104
+ if (!dashboardOrigin) return RELATIVE_IMG_PROXY_BASE_PATH;
13105
+ return `${dashboardOrigin}${RELATIVE_IMG_PROXY_BASE_PATH}`;
13106
+ }
13107
+ /**
13108
+ * Get the site ID for constructing storage paths.
13109
+ * Required for relative path resolution.
13110
+ */
13111
+ function getSiteId() {
13112
+ return getMediaContext().siteId;
13113
+ }
13114
+ function getMediaAssetIndex(context) {
13115
+ return context?.mediaAssetIndex ?? getMediaContext().mediaAssetIndex;
13116
+ }
13117
+ function resolveCanonicalMediaAsset(value, context) {
13118
+ const index = getMediaAssetIndex(context);
13119
+ if (!index) return void 0;
13120
+ if (value.assetId) {
13121
+ const hit = index.byId.get(value.assetId);
13122
+ if (hit) return hit;
13123
+ }
13124
+ const identifier = typeof value.identifier === "string" ? value.identifier.trim() : "";
13125
+ if (identifier) {
13126
+ const hit = index.byIdentifier.get(identifier);
13127
+ if (hit) return hit;
13128
+ }
13129
+ }
13130
+ function resolveMediaWithCanonicalAsset(value, context) {
13131
+ const asset = resolveCanonicalMediaAsset(value, context);
13132
+ if (!asset) return value;
13133
+ return attachRenderableMediaAssetFields(value, asset);
13134
+ }
13135
+ const debugMediaNodeLog = (...args) => {
13136
+ if (typeof window === "undefined") return;
13137
+ if (Reflect.get(window, "__DEBUG_MEDIA_NODE__") === true) console.log("[MediaNode]", ...args);
13138
+ };
13139
+ function resolveTargetAspectRatio(size) {
13140
+ if ("original" in size) return void 0;
13141
+ if ("width" in size && "height" in size && typeof size.width === "number" && typeof size.height === "number") return size.width / size.height;
13142
+ }
13143
+ function resolveImageUrlWithContext(value, options, context, transformAspectRatio) {
13144
+ const result = resolveImageUrlWithContextResult(value, options, context, transformAspectRatio);
13145
+ warnForMediaUrlResolution(result);
13146
+ return result.kind === "resolved" ? result.url : void 0;
13147
+ }
13148
+ function resolveImageUrlWithContextResult(value, options, context, transformAspectRatio) {
13149
+ if (value.type !== "image") return {
13150
+ kind: "unsupported-media-type",
13151
+ mediaType: value.type
13152
+ };
13153
+ const url = resolveImageUrlWithContextInternal(value, options, context ?? void 0, transformAspectRatio);
13154
+ if (url) return {
13155
+ kind: "resolved",
13156
+ url
13157
+ };
13158
+ const canonical = resolveMediaWithCanonicalAsset(value, context ?? void 0);
13159
+ if (canonical.storagePath && canonical.storagePath.length > 0) return resolveMediaStorageUrlResult(canonical, context, buildDirectTransformOptions(options));
13160
+ return {
13161
+ kind: "missing-image-url",
13162
+ assetId: canonical.assetId,
13163
+ identifier: canonical.identifier
13164
+ };
13165
+ }
13166
+ function resolveImageUrlWithContextInternal(value, options, context, transformAspectRatio, resolved) {
13167
+ if (value.type !== "image") return void 0;
13168
+ const canonical = resolveMediaWithCanonicalAsset(value, context);
13169
+ debugMediaNodeLog("resolveImageUrl input", {
13170
+ assetId: canonical.assetId,
13171
+ storagePath: canonical.storagePath,
13172
+ src: canonical.src,
13173
+ type: canonical.type,
13174
+ options
13175
+ });
13176
+ if (canonical.storagePath && canonical.storagePath.length > 0) {
13177
+ const resolvedStorageUrl = resolveStorageImageUrl(canonical, options, context, transformAspectRatio, resolved);
13178
+ if (resolvedStorageUrl) return resolvedStorageUrl;
13179
+ }
13180
+ if (typeof canonical.src === "string" && canonical.src.length > 0) {
13181
+ debugMediaNodeLog("resolve:explicit-src", { src: canonical.src });
13182
+ return canonical.src;
13183
+ }
13184
+ const legacyUrl = typeof canonical === "object" && canonical !== null ? Reflect.get(canonical, "url") : void 0;
13185
+ debugMediaNodeLog("resolve:fallback-url", { fallbackUrl: typeof legacyUrl === "string" ? legacyUrl : null });
13186
+ return typeof legacyUrl === "string" ? legacyUrl : void 0;
13187
+ }
13188
+ //#endregion
13189
+ //#region ../blocks/src/primitives/content/components/RichText.tsx
13190
+ function parseDimension(value) {
13191
+ if (typeof value === "number" && Number.isFinite(value) && value > 0) return Math.round(value);
13192
+ if (typeof value === "string" && value.trim().length > 0) {
13193
+ const parsed = Number(value);
13194
+ if (Number.isFinite(parsed) && parsed > 0) return Math.round(parsed);
13195
+ }
12327
13196
  }
12328
- function FieldValidationMessage({ id, children, className, live = "assertive" }) {
12329
- return /* @__PURE__ */ jsx("p", {
12330
- id,
12331
- className,
12332
- "data-field-validation-message": true,
12333
- "data-field-validation-tone": "error",
12334
- role: "alert",
12335
- "aria-live": live === "off" ? void 0 : live,
12336
- children
13197
+ function normalizeRel(target, rel) {
13198
+ const normalizedRel = rel?.trim();
13199
+ if (target !== "_blank") return normalizedRel && normalizedRel.length > 0 ? normalizedRel : void 0;
13200
+ const tokens = new Set((normalizedRel ?? "").split(/\s+/).map((token) => token.trim().toLowerCase()).filter(Boolean));
13201
+ tokens.add("noopener");
13202
+ tokens.add("noreferrer");
13203
+ return Array.from(tokens).join(" ");
13204
+ }
13205
+ function renderMarks(text, marks, key, linkTarget) {
13206
+ if (!marks || marks.length === 0) return text;
13207
+ return marks.reduce((acc, mark) => {
13208
+ switch (mark.type) {
13209
+ case "bold":
13210
+ case "strong": return /* @__PURE__ */ jsx("strong", { children: acc }, `${key}-b`);
13211
+ case "italic":
13212
+ case "em": return /* @__PURE__ */ jsx("em", { children: acc }, `${key}-i`);
13213
+ case "link": {
13214
+ if (typeof acc === "string" && acc.length === 0) return acc;
13215
+ const attrs = mark.attrs ?? {};
13216
+ const href = sanitizeHref(attrs.href);
13217
+ if (!href) return acc;
13218
+ const storedTarget = typeof attrs.target === "string" && attrs.target.trim().length > 0 ? attrs.target.trim() : void 0;
13219
+ const target = linkTarget === "new-tab" ? "_blank" : storedTarget;
13220
+ return /* @__PURE__ */ jsx("a", {
13221
+ href,
13222
+ target,
13223
+ rel: normalizeRel(target, typeof attrs.rel === "string" ? attrs.rel : void 0),
13224
+ children: acc
13225
+ }, `${key}-l`);
13226
+ }
13227
+ default: return acc;
13228
+ }
13229
+ }, text);
13230
+ }
13231
+ function renderDoc(node, key, imageResolveContext, linkTarget) {
13232
+ if (!node || !node.type) return null;
13233
+ const children = node.content?.map((child, index) => renderDoc(child, `${key}-${index}`, imageResolveContext, linkTarget));
13234
+ switch (node.type) {
13235
+ case "doc": return /* @__PURE__ */ jsx(Fragment, { children });
13236
+ case "paragraph":
13237
+ if (!children && !node.text) return /* @__PURE__ */ jsx("p", {}, key);
13238
+ return /* @__PURE__ */ jsx("p", { children: children ?? renderMarks(node.text ?? "", node.marks, key, linkTarget) }, key);
13239
+ case "heading": {
13240
+ const headingTag = `h${Math.min(Math.max(node.attrs?.level ?? 2, 1), 6)}`;
13241
+ return React.createElement(headingTag, { key }, children);
13242
+ }
13243
+ case "bulletList": return /* @__PURE__ */ jsx("ul", { children }, key);
13244
+ case "orderedList": return /* @__PURE__ */ jsx("ol", { children }, key);
13245
+ case "listItem": return /* @__PURE__ */ jsx("li", { children }, key);
13246
+ case "blockquote": return /* @__PURE__ */ jsx("blockquote", { children }, key);
13247
+ case "horizontalRule": return /* @__PURE__ */ jsx("hr", {}, key);
13248
+ case "hardBreak": return /* @__PURE__ */ jsx("br", {}, key);
13249
+ case "image": {
13250
+ const attrs = node.attrs ?? {};
13251
+ const src = typeof attrs.src === "string" ? attrs.src.trim() : "";
13252
+ const identifier = typeof attrs.identifier === "string" ? attrs.identifier.trim() : "";
13253
+ const alt = typeof attrs.alt === "string" ? attrs.alt : "";
13254
+ const title = typeof attrs.title === "string" && attrs.title.trim().length > 0 ? attrs.title : void 0;
13255
+ const width = parseDimension(attrs.width);
13256
+ const height = parseDimension(attrs.height);
13257
+ const resolvedSrc = src || (identifier ? resolveImageUrlWithContext({
13258
+ type: "image",
13259
+ identifier
13260
+ }, width ? {
13261
+ width,
13262
+ resize: "contain",
13263
+ quality: 85
13264
+ } : height ? {
13265
+ height,
13266
+ resize: "contain",
13267
+ quality: 85
13268
+ } : ImagePresets.full, imageResolveContext ?? void 0) ?? "" : "");
13269
+ if (!resolvedSrc) return null;
13270
+ return /* @__PURE__ */ jsx("img", {
13271
+ src: resolvedSrc,
13272
+ alt,
13273
+ title,
13274
+ width,
13275
+ height,
13276
+ loading: "lazy",
13277
+ decoding: "async"
13278
+ }, key);
13279
+ }
13280
+ case "text": return renderMarks(node.text ?? "", node.marks, key, linkTarget);
13281
+ default: return null;
13282
+ }
13283
+ }
13284
+ const DEFAULT_RICH_TEXT_CLASS = "rb-prose rb-max-w-none";
13285
+ function RichText({ as: Comp = "div", className, doc, path, linkTarget = "stored" }) {
13286
+ const imageResolveContext = getCurrentResolveImageUrlContext() ?? null;
13287
+ const content = doc ? renderDoc(doc, "doc", imageResolveContext, linkTarget) : null;
13288
+ const dataAttributes = path ? { "data-builder-richtext": path } : void 0;
13289
+ return /* @__PURE__ */ jsx(Comp, {
13290
+ className: className?.trim() || DEFAULT_RICH_TEXT_CLASS,
13291
+ ...dataAttributes,
13292
+ children: content
12337
13293
  });
12338
13294
  }
12339
13295
  //#endregion
13296
+ //#region ../blocks/src/system/runtime/shared/components/BookingConsentAgreement.tsx
13297
+ function BookingConsentAgreement({ agreement, showTitle = true, title, titleId }) {
13298
+ return /* @__PURE__ */ jsxs(Fragment, { children: [showTitle ? /* @__PURE__ */ jsxs("div", {
13299
+ id: titleId,
13300
+ className: "form-label",
13301
+ children: [title, /* @__PURE__ */ jsx("span", {
13302
+ className: "required-marker",
13303
+ children: "*"
13304
+ })]
13305
+ }) : null, /* @__PURE__ */ jsx("div", {
13306
+ role: "group",
13307
+ "aria-label": showTitle ? void 0 : title,
13308
+ "aria-labelledby": showTitle ? titleId : void 0,
13309
+ children: /* @__PURE__ */ jsx(RichText, {
13310
+ doc: agreement,
13311
+ linkTarget: "new-tab",
13312
+ className: "rb-prose rb-max-w-none"
13313
+ })
13314
+ })] });
13315
+ }
13316
+ //#endregion
12340
13317
  //#region ../blocks/src/system/runtime/nodes/booking-form.default-ui.tsx
12341
13318
  function optionCardClassName(isSelected) {
12342
13319
  return `rb-option-card${isSelected ? " rb-option-card--selected" : ""}`;
@@ -12785,7 +13762,11 @@ function DefaultDynamicField({ booking, field }) {
12785
13762
  return /* @__PURE__ */ jsxs("div", {
12786
13763
  className: "rb-space-y-2",
12787
13764
  children: [
12788
- /* @__PURE__ */ jsxs("label", {
13765
+ field.field.type === "booking_requirement_consent" ? /* @__PURE__ */ jsx(BookingConsentAgreement, {
13766
+ agreement: field.field.agreement,
13767
+ title: field.label,
13768
+ titleId: field.labelId
13769
+ }) : /* @__PURE__ */ jsxs("label", {
12789
13770
  id: field.labelId,
12790
13771
  htmlFor: field.inputId,
12791
13772
  className: "form-label",
@@ -12830,7 +13811,7 @@ function DefaultFieldInput({ describedBy, error, errorId, field, onBlur, onChang
12830
13811
  required: field.required,
12831
13812
  ...validationProps
12832
13813
  };
12833
- switch (field.type) {
13814
+ switch (field.field.type) {
12834
13815
  case "textarea": return /* @__PURE__ */ jsx("textarea", {
12835
13816
  ...commonProps,
12836
13817
  value: strValue,
@@ -12944,7 +13925,7 @@ function DefaultFieldInput({ describedBy, error, errorId, field, onBlur, onChang
12944
13925
  className: "form-checkbox rb-mt-0.5"
12945
13926
  }), /* @__PURE__ */ jsx("span", {
12946
13927
  className: "rb-caption",
12947
- children: field.field.placeholder || field.label
13928
+ children: field.field.checkboxLabel
12948
13929
  })]
12949
13930
  });
12950
13931
  case "number": return /* @__PURE__ */ jsx("input", {
@@ -13013,10 +13994,10 @@ function DefaultBookingDiscount({ booking }) {
13013
13994
  children: /* @__PURE__ */ jsxs("p", {
13014
13995
  className: "ab-text",
13015
13996
  children: [
13016
- "Discount available: ",
13017
- booking.discount.autoAppliedDiscount.publicLabel,
13997
+ "Discount available:",
13018
13998
  " ",
13019
- "will apply automatically at checkout."
13999
+ booking.discount.autoAppliedDiscount.publicLabel,
14000
+ " will apply automatically at checkout."
13020
14001
  ]
13021
14002
  })
13022
14003
  }) : null]
@@ -13601,11 +14582,21 @@ function readAmount(value) {
13601
14582
  }
13602
14583
  //#endregion
13603
14584
  //#region ../blocks/src/system/runtime/nodes/event-registration/validation.ts
13604
- function validateFormData(formData) {
14585
+ function createInitialRegistrationFormData() {
14586
+ return {
14587
+ name: "",
14588
+ email: "",
14589
+ phone: "",
14590
+ notes: "",
14591
+ consentAccepted: false
14592
+ };
14593
+ }
14594
+ function validateFormData(formData, requiresConsent = false) {
13605
14595
  const errors = {};
13606
14596
  if (!formData.name.trim()) errors.name = "Name is required";
13607
14597
  if (!formData.email.trim()) errors.email = "Email is required";
13608
14598
  else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(formData.email)) errors.email = "Invalid email address";
14599
+ if (requiresConsent && formData.consentAccepted !== true) errors.consentAccepted = "Please read and accept the agreement before continuing.";
13609
14600
  return errors;
13610
14601
  }
13611
14602
  /**
@@ -13764,6 +14755,15 @@ function existingRegistrationLookupReducer(state, action) {
13764
14755
  * Custom hooks for portal authentication and eligibility checking.
13765
14756
  * Extracted from the main EventRegistrationClient for better separation of concerns.
13766
14757
  */
14758
+ function scopePortalCreditStateToSubject(state, subjectEmail) {
14759
+ if (!subjectEmail) return { kind: "not_authenticated" };
14760
+ if (state.kind === "not_authenticated") return state;
14761
+ const normalizedSubject = subjectEmail.trim().toLowerCase();
14762
+ return state.subjectEmail === normalizedSubject ? state : {
14763
+ kind: "loading",
14764
+ subjectEmail: normalizedSubject
14765
+ };
14766
+ }
13767
14767
  const eventRegistrationHooksDeps = { useBlockApi };
13768
14768
  /**
13769
14769
  * Hook for managing portal authentication state.
@@ -13778,27 +14778,54 @@ function usePortalAuthWithDeps(deps) {
13778
14778
  const api = deps.useBlockApi();
13779
14779
  const [authState, setAuthState] = useState("checking");
13780
14780
  const [profile, setProfile] = useState(null);
14781
+ const [creditState, setCreditState] = useState({ kind: "not_authenticated" });
13781
14782
  useEffect(() => {
13782
14783
  let cancelled = false;
13783
14784
  async function checkPortalAuth() {
13784
14785
  if ((api.config.authOverrides?.portal ?? api.config.auth).type !== "bearer") {
13785
14786
  setAuthState("unauthenticated");
14787
+ setProfile(null);
14788
+ setCreditState({ kind: "not_authenticated" });
13786
14789
  return;
13787
14790
  }
13788
14791
  setAuthState("checking");
14792
+ setProfile(null);
14793
+ setCreditState({ kind: "not_authenticated" });
13789
14794
  try {
13790
14795
  const me = await api.getPortalProfile();
13791
14796
  if (cancelled) return;
13792
- setAuthState("authenticated");
13793
- setProfile({
14797
+ const nextProfile = {
13794
14798
  email: me.profile.email,
13795
14799
  name: me.profile.name,
13796
14800
  phone: me.profile.phone || ""
14801
+ };
14802
+ const subjectEmail = nextProfile.email.trim().toLowerCase();
14803
+ setProfile(nextProfile);
14804
+ setCreditState({
14805
+ kind: "loading",
14806
+ subjectEmail
13797
14807
  });
14808
+ setAuthState("authenticated");
14809
+ try {
14810
+ const credit = await api.getPortalCredit();
14811
+ if (cancelled) return;
14812
+ setCreditState({
14813
+ kind: "loaded",
14814
+ subjectEmail,
14815
+ credit
14816
+ });
14817
+ } catch {
14818
+ if (cancelled) return;
14819
+ setCreditState({
14820
+ kind: "unavailable",
14821
+ subjectEmail
14822
+ });
14823
+ }
13798
14824
  } catch {
13799
14825
  if (cancelled) return;
13800
14826
  setAuthState("unauthenticated");
13801
14827
  setProfile(null);
14828
+ setCreditState({ kind: "not_authenticated" });
13802
14829
  }
13803
14830
  }
13804
14831
  checkPortalAuth();
@@ -13818,6 +14845,7 @@ function usePortalAuthWithDeps(deps) {
13818
14845
  isAuthenticated: authState === "authenticated",
13819
14846
  isChecking: authState === "checking",
13820
14847
  profile,
14848
+ creditState: scopePortalCreditStateToSubject(creditState, authState === "authenticated" ? profile?.email ?? null : null),
13821
14849
  logout
13822
14850
  };
13823
14851
  }
@@ -14058,9 +15086,14 @@ function getWaitlistClaimTokenSnapshot() {
14058
15086
  function useWaitlistClaim() {
14059
15087
  return useWaitlistClaimWithDeps(useWaitlistClaimDeps);
14060
15088
  }
15089
+ function useWaitlistClaimForToken(token) {
15090
+ return useResolvedWaitlistClaim(useWaitlistClaimDeps, token);
15091
+ }
14061
15092
  function useWaitlistClaimWithDeps(deps) {
15093
+ return useResolvedWaitlistClaim(deps, useSyncExternalStore(subscribeToWaitlistClaimToken, getWaitlistClaimTokenSnapshot, () => null));
15094
+ }
15095
+ function useResolvedWaitlistClaim(deps, token) {
14062
15096
  const api = deps.useBlockApi();
14063
- const token = useSyncExternalStore(subscribeToWaitlistClaimToken, getWaitlistClaimTokenSnapshot, () => null);
14064
15097
  const [state, dispatch] = useReducer(waitlistClaimReducer, Boolean(token), createInitialWaitlistClaimState);
14065
15098
  useEffect(() => {
14066
15099
  let cancelled = false;
@@ -14487,6 +15520,7 @@ function useEventRegistrationSubmitWithDeps(options, deps) {
14487
15520
  name: options.formData.name.trim(),
14488
15521
  phone: options.formData.phone.trim() || void 0,
14489
15522
  notes: options.formData.notes.trim() || void 0,
15523
+ consentAccepted: options.formData.consentAccepted,
14490
15524
  altchaSolution: options.altchaSolution,
14491
15525
  paymentMethod: method,
14492
15526
  customerPassId: method === "pass" ? passId : void 0,
@@ -14704,88 +15738,171 @@ function requiresPaymentStep(params) {
14704
15738
  return !isEntitlementSelection(params.paymentSelection);
14705
15739
  }
14706
15740
  //#endregion
14707
- //#region ../blocks/src/system/manifest/richTextSchema.ts
14708
- /**
14709
- * Shared Rich Text Schema
14710
- *
14711
- * This module provides a single source of truth for TipTap rich text validation
14712
- * across both the block-form editor and the block rendering system.
14713
- *
14714
- * Rich-text fields use one canonical root shape:
14715
- * `{ type: 'doc', content: [...] }`.
14716
- */
14717
- /**
14718
- * TipTap document node schema (recursive structure)
14719
- *
14720
- * Supports the full TipTap document structure including:
14721
- * - type: Node type (e.g., 'doc', 'paragraph', 'text')
14722
- * - content: Nested array of child nodes
14723
- * - text: Text content for text nodes
14724
- * - attrs: Node attributes (e.g., alignment, color)
14725
- * - marks: Text formatting marks (e.g., bold, italic)
14726
- */
14727
- const TipTapMarkSchema = z.object({
14728
- type: z.string().min(1),
14729
- attrs: z.record(z.string(), z.unknown()).optional()
14730
- }).strict();
14731
- const TipTapNodeSchema = z.lazy(() => z.object({
14732
- type: z.string().min(1),
14733
- content: z.array(TipTapNodeSchema).optional(),
14734
- text: z.string().optional(),
14735
- attrs: z.record(z.string(), z.unknown()).optional(),
14736
- marks: z.array(TipTapMarkSchema).optional()
14737
- }).strict().superRefine((node, ctx) => {
14738
- if (node.type === "doc") ctx.addIssue({
14739
- code: "custom",
14740
- path: ["type"],
14741
- message: "Document nodes are only valid at the rich-text root"
15741
+ //#region ../blocks/src/system/blocks/events/whole-series/pricing.ts
15742
+ function isSaleWindowOpen(option, now) {
15743
+ if (!option.isActive) return false;
15744
+ if (option.saleStartsAt && new Date(option.saleStartsAt) > now) return false;
15745
+ if (option.saleEndsAt && new Date(option.saleEndsAt) < now) return false;
15746
+ return true;
15747
+ }
15748
+ function toExactOrFreeDisplay(amount, currency) {
15749
+ if (amount <= 0) return {
15750
+ kind: "free",
15751
+ currency
15752
+ };
15753
+ return {
15754
+ kind: "exact",
15755
+ amount,
15756
+ currency
15757
+ };
15758
+ }
15759
+ function getSelectableWholeSeriesPricingOptionsForNow(offering, now) {
15760
+ if (offering.pricing.pricingStrategy !== "tiered") return [];
15761
+ return [...offering.pricing.options].filter((option) => isSaleWindowOpen(option, now)).sort((left, right) => {
15762
+ if (left.sortOrder !== right.sortOrder) return left.sortOrder - right.sortOrder;
15763
+ if (left.priceAmount !== right.priceAmount) return left.priceAmount - right.priceAmount;
15764
+ return left.name.localeCompare(right.name);
14742
15765
  });
14743
- if (node.type === "text") {
14744
- if (node.text === void 0 || node.text.length === 0) ctx.addIssue({
14745
- code: "custom",
14746
- path: ["text"],
14747
- message: "Text nodes require a non-empty text value"
14748
- });
14749
- if (node.content !== void 0) ctx.addIssue({
14750
- code: "custom",
14751
- path: ["content"],
14752
- message: "Text nodes cannot contain child nodes"
14753
- });
14754
- return;
15766
+ }
15767
+ function resolveWholeSeriesPricingState(offering, selectedPricingOptionId, selectedSlidingAmountOrNowInput, nowInput = {}) {
15768
+ const selection = normalizePricingSelectionInput(selectedSlidingAmountOrNowInput, nowInput);
15769
+ const currency = offering.pricing.currency;
15770
+ switch (offering.pricing.pricingStrategy) {
15771
+ case "free": return resolveFreePricing(currency);
15772
+ case "single": return resolveSinglePricing(offering.pricing.singlePriceAmount ?? 0, currency);
15773
+ case "tiered": return resolveTieredPricing(offering, selectedPricingOptionId, selection.nowInput);
15774
+ case "sliding_scale": return resolveSlidingScalePricing(offering, selection.selectedSlidingAmount);
14755
15775
  }
14756
- if (node.text !== void 0) ctx.addIssue({
14757
- code: "custom",
14758
- path: ["text"],
14759
- message: "Only text nodes can contain a text value"
14760
- });
14761
- }));
14762
- /**
14763
- * Canonical schema for a TipTap rich-text document root.
14764
- *
14765
- * Stricter than {@link TipTapNodeSchema}: `type` is literally `'doc'` and
14766
- * `content` is required (possibly empty). This is the shape every producer
14767
- * (dummy content, editor output, migrations) must emit, and the shape every
14768
- * non-legacy consumer can rely on.
14769
- *
14770
- */
14771
- const RichTextDocSchema = z.object({
14772
- type: z.literal("doc"),
14773
- content: z.array(TipTapNodeSchema)
14774
- }).strict();
15776
+ }
15777
+ function normalizePricingSelectionInput(selectedSlidingAmountOrNowInput, nowInput) {
15778
+ return typeof selectedSlidingAmountOrNowInput === "object" && selectedSlidingAmountOrNowInput !== null ? {
15779
+ selectedSlidingAmount: null,
15780
+ nowInput: selectedSlidingAmountOrNowInput
15781
+ } : {
15782
+ selectedSlidingAmount: typeof selectedSlidingAmountOrNowInput === "number" || selectedSlidingAmountOrNowInput === null ? selectedSlidingAmountOrNowInput : null,
15783
+ nowInput
15784
+ };
15785
+ }
15786
+ function resolveFreePricing(currency) {
15787
+ return {
15788
+ currency,
15789
+ display: {
15790
+ kind: "free",
15791
+ currency
15792
+ },
15793
+ selectableOptions: [],
15794
+ requiresSelection: false,
15795
+ selectedOption: null,
15796
+ slidingScale: null,
15797
+ selectedSlidingAmount: null,
15798
+ selectedPriceAmount: 0,
15799
+ selectedRequiresPayment: false,
15800
+ hasPaidSelection: false,
15801
+ hasFreeSelection: true
15802
+ };
15803
+ }
15804
+ function resolveSinglePricing(amount, currency) {
15805
+ return {
15806
+ currency,
15807
+ display: toExactOrFreeDisplay(amount, currency),
15808
+ selectableOptions: [],
15809
+ requiresSelection: false,
15810
+ selectedOption: null,
15811
+ slidingScale: null,
15812
+ selectedSlidingAmount: null,
15813
+ selectedPriceAmount: amount,
15814
+ selectedRequiresPayment: amount > 0,
15815
+ hasPaidSelection: amount > 0,
15816
+ hasFreeSelection: amount <= 0
15817
+ };
15818
+ }
15819
+ function resolveTieredPricing(offering, selectedPricingOptionId, nowInput) {
15820
+ const currency = offering.pricing.currency;
15821
+ const selectableOptions = getSelectableWholeSeriesPricingOptionsForNow(offering, resolvePlanningDateInput(nowInput));
15822
+ const selectedOption = resolveSelectedTier(selectableOptions, selectedPricingOptionId);
15823
+ return {
15824
+ currency,
15825
+ display: resolveTieredDisplay(selectableOptions.reduce((lowest, option) => lowest === null || option.priceAmount < lowest ? option.priceAmount : lowest, null), selectableOptions.length, currency),
15826
+ selectableOptions,
15827
+ requiresSelection: selectableOptions.length > 1,
15828
+ selectedOption,
15829
+ slidingScale: null,
15830
+ selectedSlidingAmount: null,
15831
+ selectedPriceAmount: selectedOption?.priceAmount ?? null,
15832
+ selectedRequiresPayment: (selectedOption?.priceAmount ?? 0) > 0,
15833
+ hasPaidSelection: selectableOptions.some((option) => option.priceAmount > 0),
15834
+ hasFreeSelection: selectableOptions.some((option) => option.priceAmount === 0)
15835
+ };
15836
+ }
15837
+ function resolveSelectedTier(options, selectedId) {
15838
+ return (selectedId ? options.find((option) => option.id === selectedId) : null) ?? (options.length === 1 ? options[0] ?? null : null);
15839
+ }
15840
+ function resolveTieredDisplay(lowestAmount, optionCount, currency) {
15841
+ if (lowestAmount === null) return {
15842
+ kind: "unavailable",
15843
+ currency
15844
+ };
15845
+ return optionCount > 1 && lowestAmount > 0 ? {
15846
+ kind: "from",
15847
+ amount: lowestAmount,
15848
+ currency
15849
+ } : toExactOrFreeDisplay(lowestAmount, currency);
15850
+ }
15851
+ function resolveSlidingScalePricing(offering, selectedSlidingAmount) {
15852
+ const currency = offering.pricing.currency;
15853
+ const minAmount = offering.pricing.slidingMinAmount ?? null;
15854
+ const maxAmount = offering.pricing.slidingMaxAmount ?? null;
15855
+ if (minAmount === null || maxAmount === null || minAmount < 0 || maxAmount < minAmount) return unavailableSlidingScale(currency);
15856
+ const selectedAmount = Number.isFinite(selectedSlidingAmount) ? selectedSlidingAmount : null;
15857
+ return {
15858
+ currency,
15859
+ display: {
15860
+ kind: "range",
15861
+ minAmount,
15862
+ maxAmount,
15863
+ currency
15864
+ },
15865
+ selectableOptions: [],
15866
+ requiresSelection: selectedAmount === null,
15867
+ selectedOption: null,
15868
+ slidingScale: {
15869
+ minAmount,
15870
+ maxAmount,
15871
+ suggestedAmount: offering.pricing.slidingSuggestedAmount ?? null
15872
+ },
15873
+ selectedSlidingAmount: selectedAmount,
15874
+ selectedPriceAmount: selectedAmount,
15875
+ selectedRequiresPayment: (selectedAmount ?? 0) > 0,
15876
+ hasPaidSelection: maxAmount > 0,
15877
+ hasFreeSelection: minAmount === 0
15878
+ };
15879
+ }
15880
+ function unavailableSlidingScale(currency) {
15881
+ return {
15882
+ currency,
15883
+ display: {
15884
+ kind: "unavailable",
15885
+ currency
15886
+ },
15887
+ selectableOptions: [],
15888
+ requiresSelection: true,
15889
+ selectedOption: null,
15890
+ slidingScale: null,
15891
+ selectedSlidingAmount: null,
15892
+ selectedPriceAmount: null,
15893
+ selectedRequiresPayment: false,
15894
+ hasPaidSelection: false,
15895
+ hasFreeSelection: false
15896
+ };
15897
+ }
14775
15898
  //#endregion
14776
- //#region ../blocks/src/system/blocks/courses/shared/schemas.ts
14777
- /**
14778
- * Zod schema for course venue data
14779
- */
14780
- const courseVenueSchema = z.object({
15899
+ //#region ../blocks/src/system/blocks/events/whole-series/schemas.ts
15900
+ const wholeSeriesVenueSchema = z.object({
14781
15901
  id: z.string(),
14782
15902
  name: z.string(),
14783
15903
  address: z.string().nullable()
14784
15904
  });
14785
- /**
14786
- * Zod schema for course session (occurrence) data
14787
- */
14788
- const courseSessionSchema = z.object({
15905
+ const wholeSeriesSessionSchema = z.object({
14789
15906
  id: z.string(),
14790
15907
  startsAt: z.string(),
14791
15908
  endsAt: z.string(),
@@ -14793,14 +15910,14 @@ const courseSessionSchema = z.object({
14793
15910
  capacityOverride: z.number().nullable().optional(),
14794
15911
  overrides: z.record(z.string(), z.unknown()).nullable().optional()
14795
15912
  });
14796
- const courseTeamMemberSummarySchema = z.object({
15913
+ const wholeSeriesTeamMemberSummarySchema = z.object({
14797
15914
  id: z.string(),
14798
15915
  name: z.string(),
14799
15916
  roleLabel: z.string().nullable(),
14800
15917
  summary: z.string().nullable(),
14801
15918
  profilePath: z.string().nullable()
14802
15919
  });
14803
- const coursePricingOptionSchema = z.object({
15920
+ const wholeSeriesPricingOptionSchema = z.object({
14804
15921
  id: z.string(),
14805
15922
  name: z.string(),
14806
15923
  description: z.string().nullable(),
@@ -14816,7 +15933,7 @@ const coursePricingOptionSchema = z.object({
14816
15933
  "both"
14817
15934
  ]).nullable().optional()
14818
15935
  });
14819
- const coursePricingSchema = z.object({
15936
+ const wholeSeriesPricingSchema = z.object({
14820
15937
  bookingRequirement: z.enum(["none", "required"]),
14821
15938
  pricingStrategy: z.enum([
14822
15939
  "free",
@@ -14830,22 +15947,20 @@ const coursePricingSchema = z.object({
14830
15947
  slidingMaxAmount: z.number().nullable().optional(),
14831
15948
  slidingSuggestedAmount: z.number().nullable().optional(),
14832
15949
  paymentTerms: blockBookingPaymentTermsSchema,
14833
- options: z.array(coursePricingOptionSchema)
15950
+ options: z.array(wholeSeriesPricingOptionSchema)
14834
15951
  });
14835
- /**
14836
- * Zod schema for public course data
14837
- */
14838
15952
  const publicWholeSeriesOfferingSchema = z.object({
14839
15953
  eventSeriesId: z.string(),
14840
15954
  eventOfferingId: z.string(),
14841
15955
  title: z.string(),
14842
15956
  slug: z.string(),
14843
15957
  description: z.unknown().nullable(),
14844
- teamMembers: z.array(courseTeamMemberSummarySchema).optional(),
15958
+ teamMembers: z.array(wholeSeriesTeamMemberSummarySchema).optional(),
14845
15959
  enrollmentOpen: z.boolean(),
14846
- pricing: coursePricingSchema,
15960
+ pricing: wholeSeriesPricingSchema,
14847
15961
  currency: z.string(),
14848
15962
  paymentTerms: blockBookingPaymentTermsSchema,
15963
+ consent: blockBookingConsentSchema.nullable(),
14849
15964
  enrollmentCapacity: z.number().nullable(),
14850
15965
  acceptsMemberships: z.boolean(),
14851
15966
  status: z.enum([
@@ -14856,8 +15971,8 @@ const publicWholeSeriesOfferingSchema = z.object({
14856
15971
  sessionsCount: z.number(),
14857
15972
  enrolledCount: z.number(),
14858
15973
  availableSpots: z.number().nullable(),
14859
- sessions: z.array(courseSessionSchema),
14860
- venue: courseVenueSchema.nullable()
15974
+ sessions: z.array(wholeSeriesSessionSchema),
15975
+ venue: wholeSeriesVenueSchema.nullable()
14861
15976
  });
14862
15977
  z.array(publicWholeSeriesOfferingSchema);
14863
15978
  //#endregion
@@ -15163,6 +16278,7 @@ const publicEventSchema = z.object({
15163
16278
  timeZone: z.string(),
15164
16279
  pricing: publicEventPricingSchema,
15165
16280
  paymentTerms: blockBookingPaymentTermsSchema,
16281
+ consent: blockBookingConsentSchema.nullable(),
15166
16282
  accessRestriction: accessRestrictionSchema,
15167
16283
  allowedCategoryIds: z.array(z.string()),
15168
16284
  requireGuestDetails: z.boolean().optional(),
@@ -15170,7 +16286,7 @@ const publicEventSchema = z.object({
15170
16286
  acceptsMemberships: z.boolean().optional(),
15171
16287
  wholeSeries: z.object({
15172
16288
  eventSeriesId: z.string(),
15173
- pricing: coursePricingSchema,
16289
+ pricing: wholeSeriesPricingSchema,
15174
16290
  currency: z.string(),
15175
16291
  enrollmentOpen: z.boolean()
15176
16292
  }).nullable().optional()
@@ -15681,12 +16797,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
15681
16797
  const step = flowState.step;
15682
16798
  const paymentSelection = flowState.paymentSelection;
15683
16799
  const [selectedEvent, setSelectedEvent] = useState(preSelectedEvent ?? null);
15684
- const [formData, setFormData] = useState({
15685
- name: "",
15686
- email: "",
15687
- phone: "",
15688
- notes: ""
15689
- });
16800
+ const [formData, setFormData] = useState(createInitialRegistrationFormData);
15690
16801
  const [errors, setErrors] = useState({});
15691
16802
  const [guests, setGuests] = useState([]);
15692
16803
  const [guestErrors, setGuestErrors] = useState({});
@@ -15700,7 +16811,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
15700
16811
  const [registrationResult, setRegistrationResult] = useState(null);
15701
16812
  const [errorMessage, setErrorMessage] = useState("");
15702
16813
  const [altchaSolution, setAltchaSolution] = useState(null);
15703
- const { authState: portalAuthState, profile: portalProfile } = deps.usePortalAuth();
16814
+ const { authState: portalAuthState, profile: portalProfile, creditState: portalCreditState } = deps.usePortalAuth();
15704
16815
  const waitlistClaim = deps.useWaitlistClaim();
15705
16816
  const [showMagicLinkModal, setShowMagicLinkModal] = useState(false);
15706
16817
  const [pendingAttendeeId, setPendingAttendeeId] = useState(null);
@@ -15984,7 +17095,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
15984
17095
  guests
15985
17096
  ]);
15986
17097
  const validateForm = () => {
15987
- const newErrors = validateFormData(formData);
17098
+ const newErrors = validateFormData(formData, Boolean(currentEvent?.consent));
15988
17099
  setErrors(newErrors);
15989
17100
  const newGuestErrors = {};
15990
17101
  if (requireGuestDetails && guests.length > 0) {
@@ -16173,6 +17284,10 @@ function useEventRegistrationWizardWithDeps(options, deps) {
16173
17284
  });
16174
17285
  const handleEventSelect = (event) => {
16175
17286
  setSelectedEvent(event);
17287
+ setFormData((current) => ({
17288
+ ...current,
17289
+ consentAccepted: false
17290
+ }));
16176
17291
  const slidingScale = getSlidingScaleForEvent(event);
16177
17292
  setSelectedSlidingAmountInput(slidingScale?.suggestedAmount !== null && slidingScale?.suggestedAmount !== void 0 ? formatCentsAsCurrencyInput$1(slidingScale.suggestedAmount) : "");
16178
17293
  setSelectedAttendanceMode((event.deliveryMode ?? "in_person") === "hybrid" ? null : (event.deliveryMode ?? "in_person") === "online" ? "online" : "in_person");
@@ -16253,6 +17368,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
16253
17368
  setAltchaSolution,
16254
17369
  portalAuthState,
16255
17370
  portalProfile,
17371
+ portalCreditState,
16256
17372
  showMagicLinkModal,
16257
17373
  setShowMagicLinkModal,
16258
17374
  handleLogout,
@@ -16307,7 +17423,7 @@ function buildEventRegistrationPaymentOptionsViewModel(input) {
16307
17423
  return {
16308
17424
  mode: selection.mode,
16309
17425
  sectionTitle: selection.sectionTitle,
16310
- options: selection.options.map((option) => toEventDirectPaymentOption(option, selection.mode))
17426
+ options: selection.options.map((option, index) => toEventDirectPaymentOption(option, supportedOptions[index] ?? DEFAULT_EVENT_DIRECT_PAYMENT_OPTION, selection.mode, input.totalPriceCents))
16311
17427
  };
16312
17428
  }
16313
17429
  function selectSupportedEventDirectPaymentOptions(paymentTerms) {
@@ -16317,17 +17433,24 @@ function selectSupportedEventDirectPaymentOptions(paymentTerms) {
16317
17433
  function isSupportedEventDirectPaymentOption(option) {
16318
17434
  return option.kind === "upfront" || option.kind === "flexible_balance";
16319
17435
  }
16320
- function toEventDirectPaymentOption(option, mode) {
17436
+ function toEventDirectPaymentOption(option, sourceOption, mode, totalCents) {
16321
17437
  switch (option.kind) {
16322
17438
  case "upfront": return {
16323
17439
  ...option,
16324
17440
  kind: "upfront",
16325
- label: mode === "choice_required" ? "Pay in full now" : "Pay by card"
17441
+ label: mode === "choice_required" ? "Pay in full now" : "Pay by card",
17442
+ totalCents,
17443
+ configuredPaymentDueNowCents: totalCents
16326
17444
  };
16327
17445
  case "flexible_balance": return {
16328
17446
  ...option,
16329
17447
  kind: "flexible_balance",
16330
- label: "Pay deposit now"
17448
+ label: "Pay deposit now",
17449
+ totalCents,
17450
+ configuredPaymentDueNowCents: sourceOption.kind === "flexible_balance" ? resolveFlexibleBalanceInitialPaymentCents({
17451
+ totalAmountCents: totalCents,
17452
+ config: sourceOption.config
17453
+ }) : totalCents
16331
17454
  };
16332
17455
  case "deferred_manual":
16333
17456
  case "instalment_plan": throw new Error(`Unsupported event registration payment option: ${option.kind}`);
@@ -16660,13 +17783,13 @@ function resolveHeadlessDirectPaymentOptions(wizard) {
16660
17783
  }).options;
16661
17784
  }
16662
17785
  //#endregion
16663
- //#region ../blocks/src/system/runtime/nodes/course-registration/utils.ts
17786
+ //#region ../blocks/src/system/runtime/nodes/event-registration/whole-series/utils.ts
16664
17787
  /**
16665
17788
  * Anchor ID for the registration block, used for scroll targeting.
16666
17789
  */
16667
- const COURSE_REGISTRATION_ANCHOR_ID = "course-registration";
17790
+ const WHOLE_SERIES_REGISTRATION_ANCHOR_ID = "event-registration";
16668
17791
  //#endregion
16669
- //#region ../blocks/src/system/runtime/nodes/course-registration/pricing.ts
17792
+ //#region ../blocks/src/system/runtime/nodes/event-registration/whole-series/pricing.ts
16670
17793
  function parseCurrencyInputToCents(value) {
16671
17794
  const trimmed = value.trim();
16672
17795
  if (!trimmed) return null;
@@ -16678,31 +17801,31 @@ function formatCentsAsCurrencyInput(amount) {
16678
17801
  const major = amount / 100;
16679
17802
  return Number.isInteger(major) ? String(major) : major.toFixed(2);
16680
17803
  }
16681
- function getMissingCoursePricingSelectionMessage(pricing) {
17804
+ function getMissingWholeSeriesPricingSelectionMessage(pricing) {
16682
17805
  if (pricing?.requiresSelection && !pricing.selectedOption) return pricing.slidingScale ? "Choose an amount to continue." : "Choose a pricing option to continue.";
16683
17806
  const selectedAmount = pricing?.selectedSlidingAmount;
16684
17807
  const scale = pricing?.slidingScale;
16685
17808
  if (scale && selectedAmount !== null && selectedAmount !== void 0 && (selectedAmount < scale.minAmount || selectedAmount > scale.maxAmount)) return "Choose an amount within the sliding scale.";
16686
17809
  return null;
16687
17810
  }
16688
- function buildCoursePricingOptionPayload(pricing) {
17811
+ function buildWholeSeriesPricingOptionPayload(pricing) {
16689
17812
  if (pricing?.selectedOption) return { pricingOptionId: pricing.selectedOption.id };
16690
17813
  if (pricing?.slidingScale && pricing.selectedSlidingAmount !== null) return { selectedSlidingAmount: pricing.selectedSlidingAmount };
16691
17814
  return {};
16692
17815
  }
16693
- function defaultCoursePricingSelection(pricing, previousOptionId) {
17816
+ function defaultWholeSeriesPricingSelection(pricing, previousOptionId) {
16694
17817
  return {
16695
17818
  pricingOptionId: previousOptionId && pricing.selectableOptions.some((option) => option.id === previousOptionId) ? previousOptionId : pricing.selectedOption?.id ?? null,
16696
17819
  slidingAmountInput: pricing.slidingScale?.suggestedAmount !== null && pricing.slidingScale?.suggestedAmount !== void 0 ? formatCentsAsCurrencyInput(pricing.slidingScale.suggestedAmount) : ""
16697
17820
  };
16698
17821
  }
16699
17822
  //#endregion
16700
- //#region ../blocks/src/system/runtime/nodes/course-registration/wizardSteps.ts
17823
+ //#region ../blocks/src/system/runtime/nodes/event-registration/whole-series/wizardSteps.ts
16701
17824
  /**
16702
17825
  * Step labels for the wizard indicator
16703
17826
  */
16704
17827
  const STEP_LABELS = {
16705
- "select-course": "Course",
17828
+ "select-run": "Run",
16706
17829
  "enter-details": "Details",
16707
17830
  "booking-mode": "Method",
16708
17831
  "select-payment": "Payment",
@@ -16718,36 +17841,36 @@ const STEP_LABELS = {
16718
17841
  /**
16719
17842
  * Determine which wizard steps to show based on context and eligibility.
16720
17843
  *
16721
- * @param hasPreSelectedCourse - Whether course is pre-selected (skips course selection)
16722
- * @param requiresPayment - Whether the course requires payment
17844
+ * @param hasPreSelectedRun - Whether run is pre-selected (skips run selection)
17845
+ * @param requiresPayment - Whether the run requires payment
16723
17846
  * @param hasEligibleMemberships - Whether user has eligible memberships
16724
17847
  * @param bookingMode - Current booking mode selection
16725
17848
  * @param isMembershipFastTrack - Whether user qualifies for single-step membership flow
16726
17849
  * @returns Array of wizard steps to display
16727
17850
  */
16728
- function getWizardStepsForContext(hasPreSelectedCourse, requiresPayment, hasEligibleMemberships, bookingMode, isMembershipFastTrack) {
16729
- if (isMembershipFastTrack) return hasPreSelectedCourse ? ["enter-details"] : ["select-course", "enter-details"];
16730
- if (!requiresPayment) return hasPreSelectedCourse ? ["enter-details"] : ["select-course", "enter-details"];
17851
+ function getWizardStepsForContext(hasPreSelectedRun, requiresPayment, hasEligibleMemberships, bookingMode, isMembershipFastTrack) {
17852
+ if (isMembershipFastTrack) return hasPreSelectedRun ? ["enter-details"] : ["select-run", "enter-details"];
17853
+ if (!requiresPayment) return hasPreSelectedRun ? ["enter-details"] : ["select-run", "enter-details"];
16731
17854
  if (hasEligibleMemberships) {
16732
17855
  const skipPayment = bookingMode === "membership";
16733
- if (hasPreSelectedCourse) return skipPayment ? ["enter-details", "booking-mode"] : [
17856
+ if (hasPreSelectedRun) return skipPayment ? ["enter-details", "booking-mode"] : [
16734
17857
  "enter-details",
16735
17858
  "booking-mode",
16736
17859
  "select-payment"
16737
17860
  ];
16738
17861
  return skipPayment ? [
16739
- "select-course",
17862
+ "select-run",
16740
17863
  "enter-details",
16741
17864
  "booking-mode"
16742
17865
  ] : [
16743
- "select-course",
17866
+ "select-run",
16744
17867
  "enter-details",
16745
17868
  "booking-mode",
16746
17869
  "select-payment"
16747
17870
  ];
16748
17871
  }
16749
- return hasPreSelectedCourse ? ["enter-details", "select-payment"] : [
16750
- "select-course",
17872
+ return hasPreSelectedRun ? ["enter-details", "select-payment"] : [
17873
+ "select-run",
16751
17874
  "enter-details",
16752
17875
  "select-payment"
16753
17876
  ];
@@ -16759,21 +17882,21 @@ function getStepLabels(steps) {
16759
17882
  return steps.map((step) => STEP_LABELS[step] ?? step);
16760
17883
  }
16761
17884
  //#endregion
16762
- //#region ../blocks/src/system/runtime/nodes/course-registration/courseRegistrationViewState.ts
16763
- function deriveCourseRegistrationViewState(input) {
16764
- const hasCoursePayment = resolveCoursePaymentRequirement(input.pricing);
16765
- const canUseMembership = hasCoursePayment && input.selectedCourse?.acceptsMemberships === true && input.portalAuthState === "authenticated" && input.eligibleMembershipCount > 0;
16766
- const hasPreSelectedCourse = input.scopedCourses.length === 1;
17885
+ //#region ../blocks/src/system/runtime/nodes/event-registration/whole-series/wholeSeriesRegistrationViewState.ts
17886
+ function deriveWholeSeriesRegistrationViewState(input) {
17887
+ const hasRunPayment = resolveWholeSeriesPaymentRequirement(input.pricing);
17888
+ const canUseMembership = hasRunPayment && input.selectedRun?.acceptsMemberships === true && input.portalAuthState === "authenticated" && input.eligibleMembershipCount > 0;
17889
+ const hasPreSelectedRun = input.scopedRuns.length === 1;
16767
17890
  const fastTrack = canUseMembership && input.eligibleMembershipCount === 1 && input.bookingMode === "membership";
16768
- const wizardSteps = getWizardStepsForContext(hasPreSelectedCourse, hasCoursePayment, canUseMembership, input.bookingMode, fastTrack);
17891
+ const wizardSteps = getWizardStepsForContext(hasPreSelectedRun, hasRunPayment, canUseMembership, input.bookingMode, fastTrack);
16769
17892
  const showPortalAuthSidebar = shouldShowPortalAuthSidebar({
16770
17893
  ...input,
16771
- hasCoursePayment
17894
+ hasRunPayment
16772
17895
  });
16773
17896
  return {
16774
- hasCoursePayment,
17897
+ hasRunPayment,
16775
17898
  canUseMembership,
16776
- hasPreSelectedCourse,
17899
+ hasPreSelectedRun,
16777
17900
  wizardSteps,
16778
17901
  currentStepNumber: getStepNumber(input.step, wizardSteps),
16779
17902
  totalSteps: wizardSteps.length,
@@ -16781,24 +17904,24 @@ function deriveCourseRegistrationViewState(input) {
16781
17904
  showPortalAuthSidebar
16782
17905
  };
16783
17906
  }
16784
- function resolveCoursePaymentRequirement(pricing) {
17907
+ function resolveWholeSeriesPaymentRequirement(pricing) {
16785
17908
  if (!pricing) return false;
16786
17909
  return pricing.selectedOption ? pricing.selectedRequiresPayment : pricing.hasPaidSelection;
16787
17910
  }
16788
17911
  function shouldShowPortalAuthSidebar(input) {
16789
17912
  if (input.portalAuthState !== "unauthenticated") return false;
16790
17913
  if (input.step === "success" || input.step === "waitlist" || input.step === "error") return false;
16791
- return input.waitlistRequiresPortalLogin || input.hasCoursePayment && input.selectedCourse?.acceptsMemberships === true && input.step !== "select-course";
17914
+ return input.waitlistRequiresPortalLogin || input.hasRunPayment && input.selectedRun?.acceptsMemberships === true && input.step !== "select-run";
16792
17915
  }
16793
17916
  //#endregion
16794
- //#region ../blocks/src/system/runtime/nodes/course-registration/useCourseEligibility.ts
17917
+ //#region ../blocks/src/system/runtime/nodes/event-registration/whole-series/useWholeSeriesEligibility.ts
16795
17918
  function shouldFetchEligibility(input) {
16796
- if (!input.course || input.portalAuthState === "checking" || input.hasWaitlistClaimToken) return false;
16797
- const membershipCheck = input.portalAuthState === "authenticated" && input.hasPaidSelection && input.course.acceptsMemberships;
16798
- const capacityCheck = input.course.availableSpots !== null && input.course.availableSpots <= 0;
17919
+ if (!input.run || input.portalAuthState === "checking" || input.hasWaitlistClaimToken) return false;
17920
+ const membershipCheck = input.portalAuthState === "authenticated" && input.hasPaidSelection && input.run.acceptsMemberships;
17921
+ const capacityCheck = input.run.availableSpots !== null && input.run.availableSpots <= 0;
16799
17922
  return membershipCheck || capacityCheck;
16800
17923
  }
16801
- function useCourseEligibility(input) {
17924
+ function useWholeSeriesEligibility(input) {
16802
17925
  const [loading, setLoading] = useState(false);
16803
17926
  const [error, setError] = useState(null);
16804
17927
  const [eligibility, setEligibility] = useState(null);
@@ -16819,15 +17942,15 @@ function useCourseEligibility(input) {
16819
17942
  setError(null);
16820
17943
  setPaymentChoice("checkout");
16821
17944
  const eligibilityInput = {
16822
- course: input.selectedCourse,
17945
+ run: input.selectedRun,
16823
17946
  hasPaidSelection: input.hasPaidSelection,
16824
17947
  portalAuthState: input.portalAuthState,
16825
17948
  hasWaitlistClaimToken: input.waitlistClaimToken !== null
16826
17949
  };
16827
17950
  if (!shouldFetchEligibility(eligibilityInput)) return;
16828
- const course = eligibilityInput.course;
17951
+ const run = eligibilityInput.run;
16829
17952
  setLoading(true);
16830
- input.api.checkWholeSeriesEligibility({ eventSeriesId: course.eventSeriesId }).then((result) => {
17953
+ input.api.checkWholeSeriesEligibility({ eventSeriesId: run.eventSeriesId }).then((result) => {
16831
17954
  if (cancelled) return;
16832
17955
  const eligibleMemberships = result.eligibleMemberships ?? [];
16833
17956
  setEligibility(result);
@@ -16848,13 +17971,13 @@ function useCourseEligibility(input) {
16848
17971
  input.api,
16849
17972
  input.hasPaidSelection,
16850
17973
  input.portalAuthState,
16851
- input.selectedCourse,
17974
+ input.selectedRun,
16852
17975
  input.waitlistClaimToken
16853
17976
  ]);
16854
17977
  return {
16855
17978
  eligibilityLoading: loading,
16856
17979
  eligibilityError: error,
16857
- courseEligibility: eligibility,
17980
+ runEligibility: eligibility,
16858
17981
  eligibleMemberships: memberships,
16859
17982
  paymentChoice,
16860
17983
  choosePaymentChoice,
@@ -16863,149 +17986,12 @@ function useCourseEligibility(input) {
16863
17986
  };
16864
17987
  }
16865
17988
  //#endregion
16866
- //#region ../blocks/src/system/blocks/courses/shared/pricing.ts
16867
- function isSaleWindowOpen(option, now) {
16868
- if (!option.isActive) return false;
16869
- if (option.saleStartsAt && new Date(option.saleStartsAt) > now) return false;
16870
- if (option.saleEndsAt && new Date(option.saleEndsAt) < now) return false;
16871
- return true;
16872
- }
16873
- function toExactOrFreeDisplay(amount, currency) {
16874
- if (amount <= 0) return {
16875
- kind: "free",
16876
- currency
16877
- };
16878
- return {
16879
- kind: "exact",
16880
- amount,
16881
- currency
16882
- };
16883
- }
16884
- function getSelectableCoursePricingOptionsForNow(course, now) {
16885
- if (course.pricing.pricingStrategy !== "tiered") return [];
16886
- return [...course.pricing.options].filter((option) => isSaleWindowOpen(option, now)).sort((left, right) => {
16887
- if (left.sortOrder !== right.sortOrder) return left.sortOrder - right.sortOrder;
16888
- if (left.priceAmount !== right.priceAmount) return left.priceAmount - right.priceAmount;
16889
- return left.name.localeCompare(right.name);
16890
- });
16891
- }
16892
- function resolveCoursePricingState(course, selectedPricingOptionId, selectedSlidingAmountOrNowInput, nowInput = {}) {
16893
- const selectedSlidingAmount = typeof selectedSlidingAmountOrNowInput === "number" || selectedSlidingAmountOrNowInput === null ? selectedSlidingAmountOrNowInput : null;
16894
- const effectiveNowInput = typeof selectedSlidingAmountOrNowInput === "object" && selectedSlidingAmountOrNowInput !== null ? selectedSlidingAmountOrNowInput : nowInput;
16895
- const currency = course.pricing.currency;
16896
- switch (course.pricing.pricingStrategy) {
16897
- case "free": return {
16898
- currency,
16899
- display: {
16900
- kind: "free",
16901
- currency
16902
- },
16903
- selectableOptions: [],
16904
- requiresSelection: false,
16905
- selectedOption: null,
16906
- slidingScale: null,
16907
- selectedSlidingAmount: null,
16908
- selectedPriceAmount: 0,
16909
- selectedRequiresPayment: false,
16910
- hasPaidSelection: false,
16911
- hasFreeSelection: true
16912
- };
16913
- case "single": {
16914
- const amount = course.pricing.singlePriceAmount ?? 0;
16915
- return {
16916
- currency,
16917
- display: toExactOrFreeDisplay(amount, currency),
16918
- selectableOptions: [],
16919
- requiresSelection: false,
16920
- selectedOption: null,
16921
- slidingScale: null,
16922
- selectedSlidingAmount: null,
16923
- selectedPriceAmount: amount,
16924
- selectedRequiresPayment: amount > 0,
16925
- hasPaidSelection: amount > 0,
16926
- hasFreeSelection: amount <= 0
16927
- };
16928
- }
16929
- case "tiered": {
16930
- const selectableOptions = getSelectableCoursePricingOptionsForNow(course, resolvePlanningDateInput(effectiveNowInput));
16931
- const selectedOption = (selectedPricingOptionId ? selectableOptions.find((option) => option.id === selectedPricingOptionId) : null) ?? (selectableOptions.length === 1 ? selectableOptions[0] ?? null : null);
16932
- const lowestAmount = selectableOptions.reduce((lowest, option) => {
16933
- if (lowest === null || option.priceAmount < lowest) return option.priceAmount;
16934
- return lowest;
16935
- }, null);
16936
- return {
16937
- currency,
16938
- display: lowestAmount === null ? {
16939
- kind: "unavailable",
16940
- currency
16941
- } : selectableOptions.length > 1 && lowestAmount > 0 ? {
16942
- kind: "from",
16943
- amount: lowestAmount,
16944
- currency
16945
- } : toExactOrFreeDisplay(lowestAmount, currency),
16946
- selectableOptions,
16947
- requiresSelection: selectableOptions.length > 1,
16948
- selectedOption,
16949
- slidingScale: null,
16950
- selectedSlidingAmount: null,
16951
- selectedPriceAmount: selectedOption?.priceAmount ?? null,
16952
- selectedRequiresPayment: (selectedOption?.priceAmount ?? 0) > 0,
16953
- hasPaidSelection: selectableOptions.some((option) => option.priceAmount > 0),
16954
- hasFreeSelection: selectableOptions.some((option) => option.priceAmount === 0)
16955
- };
16956
- }
16957
- case "sliding_scale": {
16958
- const minAmount = course.pricing.slidingMinAmount ?? null;
16959
- const maxAmount = course.pricing.slidingMaxAmount ?? null;
16960
- if (minAmount === null || maxAmount === null || minAmount < 0 || maxAmount < minAmount) return {
16961
- currency,
16962
- display: {
16963
- kind: "unavailable",
16964
- currency
16965
- },
16966
- selectableOptions: [],
16967
- requiresSelection: true,
16968
- selectedOption: null,
16969
- slidingScale: null,
16970
- selectedSlidingAmount: null,
16971
- selectedPriceAmount: null,
16972
- selectedRequiresPayment: false,
16973
- hasPaidSelection: false,
16974
- hasFreeSelection: false
16975
- };
16976
- const normalizedSelectedAmount = typeof selectedSlidingAmount === "number" && Number.isFinite(selectedSlidingAmount) ? selectedSlidingAmount : null;
16977
- return {
16978
- currency,
16979
- display: {
16980
- kind: "range",
16981
- minAmount,
16982
- maxAmount,
16983
- currency
16984
- },
16985
- selectableOptions: [],
16986
- requiresSelection: normalizedSelectedAmount === null,
16987
- selectedOption: null,
16988
- slidingScale: {
16989
- minAmount,
16990
- maxAmount,
16991
- suggestedAmount: course.pricing.slidingSuggestedAmount ?? null
16992
- },
16993
- selectedSlidingAmount: normalizedSelectedAmount,
16994
- selectedPriceAmount: normalizedSelectedAmount,
16995
- selectedRequiresPayment: (normalizedSelectedAmount ?? 0) > 0,
16996
- hasPaidSelection: maxAmount > 0,
16997
- hasFreeSelection: minAmount === 0
16998
- };
16999
- }
17000
- }
17001
- }
17002
- //#endregion
17003
- //#region ../blocks/src/system/runtime/nodes/course-page-surface-scope.ts
17989
+ //#region ../blocks/src/system/runtime/nodes/event-registration/whole-series/wholeSeriesPageSurfaceScope.ts
17004
17990
  /**
17005
- * Resolves native course-page ownership without falling back to entry or slug
17991
+ * Resolves native run-page ownership without falling back to entry or slug
17006
17992
  * coincidence when a page-surface subject is present but invalid.
17007
17993
  */
17008
- function resolveCoursePageSurfaceScope(courses, subjectValue) {
17994
+ function resolveWholeSeriesPageSurfaceScope(runs, subjectValue) {
17009
17995
  if (subjectValue === null || subjectValue === void 0) return { kind: "absent" };
17010
17996
  const parsed = parseEventPageSurfaceSubject(subjectValue);
17011
17997
  if (!parsed.ok) return {
@@ -17017,7 +18003,7 @@ function resolveCoursePageSurfaceScope(courses, subjectValue) {
17017
18003
  return {
17018
18004
  kind: "scoped",
17019
18005
  subject: parsed.value,
17020
- courses: courses.filter((course) => allowedSeriesIds.has(course.eventSeriesId))
18006
+ runs: runs.filter((run) => allowedSeriesIds.has(run.eventSeriesId))
17021
18007
  };
17022
18008
  }
17023
18009
  function eventSeriesIdsForSubject(subject) {
@@ -17028,33 +18014,43 @@ function eventSeriesIdsForSubject(subject) {
17028
18014
  }
17029
18015
  }
17030
18016
  //#endregion
17031
- //#region ../blocks/src/system/runtime/nodes/course-registration/useCourseRegistrationSelection.ts
17032
- function selectScopedCourses(props) {
17033
- const surfaceScope = resolveCoursePageSurfaceScope(props.courses ?? [], props.subject);
18017
+ //#region ../blocks/src/system/runtime/nodes/event-registration/whole-series/useWholeSeriesRegistrationSelection.ts
18018
+ function selectScopedRuns(props) {
18019
+ const surfaceScope = resolveWholeSeriesPageSurfaceScope(props.runs ?? [], props.subject);
17034
18020
  if (surfaceScope.kind === "unsupported") return [];
17035
- if (surfaceScope.kind === "scoped") return surfaceScope.courses;
18021
+ if (surfaceScope.kind === "scoped") return surfaceScope.runs;
17036
18022
  return [];
17037
18023
  }
17038
- function getCourseCheckoutSessionId() {
17039
- const fromSearch = new URLSearchParams(window.location.search).get("session_id");
18024
+ function getWholeSeriesCheckoutSessionId(location = window.location) {
18025
+ const fromSearch = new URLSearchParams(location.search).get("session_id");
17040
18026
  if (fromSearch) return fromSearch;
17041
- return window.location.hash.match(/[?&]session_id=([^&]+)/)?.[1] ?? null;
18027
+ return location.hash.match(/[?&]session_id=([^&]+)/)?.[1] ?? null;
17042
18028
  }
17043
- function initialStep(courses) {
17044
- if (new URLSearchParams(window.location.search).get("enrollment") === "success" && getCourseCheckoutSessionId()) return "verifying-payment";
17045
- return courses.length === 1 ? "enter-details" : "select-course";
18029
+ function initialStep(runs, location) {
18030
+ if (new URLSearchParams(location.search).get("enrollment") === "success" && getWholeSeriesCheckoutSessionId(location)) return "verifying-payment";
18031
+ return runs.length === 1 ? "enter-details" : "select-run";
17046
18032
  }
17047
- function useCourseRegistrationSelection(props) {
17048
- const scopedCourses = useMemo(() => selectScopedCourses(props), [props.courses, props.subject]);
17049
- const [step, setStep] = useState(() => initialStep(scopedCourses));
17050
- const [selectedCourse, setSelectedCourse] = useState(scopedCourses.length === 1 ? scopedCourses[0] ?? null : null);
18033
+ function useWholeSeriesRegistrationSelection(props, location = window.location) {
18034
+ const scopeSnapshot = JSON.stringify({
18035
+ runs: props.runs ?? [],
18036
+ subject: props.subject ?? null
18037
+ });
18038
+ const stableScope = useRef(null);
18039
+ if (stableScope.current?.snapshot !== scopeSnapshot) stableScope.current = {
18040
+ snapshot: scopeSnapshot,
18041
+ runs: selectScopedRuns(props)
18042
+ };
18043
+ const scopedRuns = stableScope.current.runs;
18044
+ const [step, setStep] = useState(() => initialStep(scopedRuns, location));
18045
+ const [selectedRunId, setSelectedRunId] = useState(scopedRuns.length === 1 ? scopedRuns[0]?.eventSeriesId ?? null : null);
18046
+ const selectedRun = useMemo(() => scopedRuns.find((run) => run.eventSeriesId === selectedRunId) ?? (scopedRuns.length === 1 ? scopedRuns[0] ?? null : null), [scopedRuns, selectedRunId]);
17051
18047
  const [selectedPricingOptionId, setSelectedPricingOptionId] = useState(null);
17052
18048
  const [selectedSlidingAmountInput, setSelectedSlidingAmountInput] = useState("");
17053
18049
  const goToStep = useCallback((nextStep) => {
17054
18050
  setStep(nextStep);
17055
18051
  }, []);
17056
- const chooseCourse = useCallback((course) => {
17057
- setSelectedCourse(course);
18052
+ const chooseRun = useCallback((run) => {
18053
+ setSelectedRunId(run.eventSeriesId);
17058
18054
  }, []);
17059
18055
  const choosePricingOption = useCallback((pricingOptionId) => {
17060
18056
  setSelectedPricingOptionId(pricingOptionId);
@@ -17062,36 +18058,36 @@ function useCourseRegistrationSelection(props) {
17062
18058
  const changeSlidingAmount = useCallback((amount) => {
17063
18059
  setSelectedSlidingAmountInput(amount);
17064
18060
  }, []);
17065
- const selectedCoursePricing = useMemo(() => selectedCourse ? resolveCoursePricingState(selectedCourse, selectedPricingOptionId, parseCurrencyInputToCents(selectedSlidingAmountInput)) : null, [
17066
- selectedCourse,
18061
+ const selectedRunPricing = useMemo(() => selectedRun ? resolveWholeSeriesPricingState(selectedRun, selectedPricingOptionId, parseCurrencyInputToCents(selectedSlidingAmountInput)) : null, [
18062
+ selectedRun,
17067
18063
  selectedPricingOptionId,
17068
18064
  selectedSlidingAmountInput
17069
18065
  ]);
17070
18066
  useEffect(() => {
17071
- if (!selectedCourse) {
18067
+ if (!selectedRun) {
17072
18068
  setSelectedPricingOptionId(null);
17073
18069
  setSelectedSlidingAmountInput("");
17074
18070
  return;
17075
18071
  }
17076
- const selection = defaultCoursePricingSelection(resolveCoursePricingState(selectedCourse, null), selectedPricingOptionId);
18072
+ const selection = defaultWholeSeriesPricingSelection(resolveWholeSeriesPricingState(selectedRun, null), selectedPricingOptionId);
17077
18073
  setSelectedPricingOptionId(selection.pricingOptionId);
17078
18074
  setSelectedSlidingAmountInput(selection.slidingAmountInput);
17079
- }, [selectedCourse]);
18075
+ }, [selectedRun?.eventSeriesId]);
17080
18076
  return {
17081
- scopedCourses,
18077
+ scopedRuns,
17082
18078
  step,
17083
18079
  goToStep,
17084
- selectedCourse,
17085
- chooseCourse,
18080
+ selectedRun,
18081
+ chooseRun,
17086
18082
  selectedPricingOptionId,
17087
18083
  choosePricingOption,
17088
18084
  selectedSlidingAmountInput,
17089
18085
  changeSlidingAmount,
17090
- selectedCoursePricing
18086
+ selectedRunPricing
17091
18087
  };
17092
18088
  }
17093
18089
  //#endregion
17094
- //#region ../blocks/src/system/runtime/nodes/course-registration/useCoursePaymentVerification.ts
18090
+ //#region ../blocks/src/system/runtime/nodes/event-registration/whole-series/useWholeSeriesPaymentVerification.ts
17095
18091
  function applyTerminalStatus(status, setters) {
17096
18092
  if (status === "enrolled" || status === "completed") {
17097
18093
  setters.setEnrollmentResult({
@@ -17113,7 +18109,7 @@ function applyTerminalStatus(status, setters) {
17113
18109
  setters.setStep("error");
17114
18110
  return true;
17115
18111
  }
17116
- async function pollCourseRegistrationStatus(api, sessionId, setters, isCancelled) {
18112
+ async function pollWholeSeriesRegistrationStatus(api, sessionId, setters, isCancelled) {
17117
18113
  const startedAt = Date.now();
17118
18114
  while (!isCancelled()) {
17119
18115
  try {
@@ -17134,21 +18130,21 @@ async function pollCourseRegistrationStatus(api, sessionId, setters, isCancelled
17134
18130
  await new Promise((resolve) => setTimeout(resolve, 1500));
17135
18131
  }
17136
18132
  }
17137
- function useCoursePaymentVerification(api, setters) {
18133
+ function useWholeSeriesPaymentVerification(api, setters, anchorId = WHOLE_SERIES_REGISTRATION_ANCHOR_ID, location = window.location) {
17138
18134
  useEffect(() => {
17139
18135
  let cancelled = false;
17140
- const enrollment = new URLSearchParams(window.location.search).get("enrollment");
17141
- const sessionId = getCourseCheckoutSessionId();
18136
+ const enrollment = new URLSearchParams(location.search).get("enrollment");
18137
+ const sessionId = getWholeSeriesCheckoutSessionId(location);
17142
18138
  if (enrollment === "cancelled") {
17143
- scrollToBlock(COURSE_REGISTRATION_ANCHOR_ID);
18139
+ scrollToBlock(anchorId);
17144
18140
  setters.setErrorMessage("Payment was cancelled. You can try again.");
17145
18141
  setters.setStep("error");
17146
18142
  return;
17147
18143
  }
17148
18144
  if (enrollment !== "success" || !sessionId) return;
17149
- scrollToBlock(COURSE_REGISTRATION_ANCHOR_ID);
18145
+ scrollToBlock(anchorId);
17150
18146
  setters.setStep("verifying-payment");
17151
- pollCourseRegistrationStatus(api, sessionId, setters, () => cancelled);
18147
+ pollWholeSeriesRegistrationStatus(api, sessionId, setters, () => cancelled);
17152
18148
  return () => {
17153
18149
  cancelled = true;
17154
18150
  };
@@ -17156,11 +18152,13 @@ function useCoursePaymentVerification(api, setters) {
17156
18152
  api,
17157
18153
  setters.setEnrollmentResult,
17158
18154
  setters.setErrorMessage,
17159
- setters.setStep
18155
+ setters.setStep,
18156
+ anchorId,
18157
+ location
17160
18158
  ]);
17161
18159
  }
17162
18160
  //#endregion
17163
- //#region ../blocks/src/system/runtime/nodes/course-registration/useCourseRegistrationActions.ts
18161
+ //#region ../blocks/src/system/runtime/nodes/event-registration/whole-series/useWholeSeriesRegistrationActions.ts
17164
18162
  function blocked(message, setters) {
17165
18163
  setters.setErrorMessage(message);
17166
18164
  setters.setStep("error");
@@ -17170,16 +18168,17 @@ function blocked(message, setters) {
17170
18168
  };
17171
18169
  }
17172
18170
  function validateSubmission(state, setters) {
17173
- if (!state.selectedCourse) return {
18171
+ if (!state.selectedRun) return {
17174
18172
  kind: "blocked",
17175
18173
  message: "Choose an available set of dates to continue."
17176
18174
  };
17177
18175
  const errors = validateFormData$1(state.formData);
18176
+ if (state.selectedRun.consent && state.formData.consentAccepted !== true) errors.consentAccepted = "Please read and accept the agreement before continuing.";
17178
18177
  setters.setErrors(errors);
17179
18178
  if (Object.keys(errors).length > 0) return { kind: "validation-failed" };
17180
- const pricingMessage = getMissingCoursePricingSelectionMessage(state.pricing);
18179
+ const pricingMessage = getMissingWholeSeriesPricingSelectionMessage(state.pricing);
17181
18180
  if (pricingMessage) return blocked(pricingMessage, setters);
17182
- if (!state.hasClaim && state.eligibility?.isFull && !state.eligibility.canJoinWaitlist) return blocked(state.eligibility.reason ?? "This course is fully booked.", setters);
18181
+ if (!state.hasClaim && state.eligibility?.isFull && !state.eligibility.canJoinWaitlist) return blocked(state.eligibility.reason ?? "This run is fully booked.", setters);
17183
18182
  if (isSpamProtectionEnabled() && !state.altchaSolution) return blocked("Please complete the verification check.", setters);
17184
18183
  return null;
17185
18184
  }
@@ -17192,12 +18191,13 @@ function enrollmentPayload(state, payment) {
17192
18191
  }
17193
18192
  function registrantPayload(state) {
17194
18193
  return {
17195
- eventSeriesId: state.selectedCourse.eventSeriesId,
17196
- ...buildCoursePricingOptionPayload(state.pricing),
18194
+ eventSeriesId: state.selectedRun.eventSeriesId,
18195
+ ...buildWholeSeriesPricingOptionPayload(state.pricing),
17197
18196
  email: state.formData.email.trim().toLowerCase(),
17198
18197
  name: state.formData.name.trim(),
17199
18198
  phone: state.formData.phone.trim() || void 0,
17200
18199
  formData: { notes: state.formData.notes.trim() || void 0 },
18200
+ consentAccepted: state.formData.consentAccepted,
17201
18201
  altchaSolution: state.altchaSolution,
17202
18202
  claimToken: state.claimToken ?? void 0
17203
18203
  };
@@ -17226,7 +18226,7 @@ async function enroll(state, setters, payment) {
17226
18226
  async function checkout(state, setters) {
17227
18227
  setters.setStep("submitting");
17228
18228
  try {
17229
- const urls = buildCheckoutReturnUrls("enrollment", COURSE_REGISTRATION_ANCHOR_ID);
18229
+ const urls = buildCheckoutReturnUrls("enrollment", state.options.anchorId ?? "event-registration");
17230
18230
  const result = await state.api.createWholeSeriesCheckout({
17231
18231
  ...registrantPayload(state),
17232
18232
  discountCode: state.discountCode.trim() || void 0,
@@ -17261,10 +18261,10 @@ async function checkout(state, setters) {
17261
18261
  }
17262
18262
  async function submitDetails(state, setters) {
17263
18263
  const invalid = validateSubmission(state, setters);
17264
- if (invalid || !state.selectedCourse) return invalid ?? { kind: "validation-failed" };
18264
+ if (invalid || !state.selectedRun) return invalid ?? { kind: "validation-failed" };
17265
18265
  if (state.eligibility?.canJoinWaitlist) return enroll(state, setters, { method: "free" });
17266
18266
  const requiresPayment = state.pricing?.selectedRequiresPayment ?? false;
17267
- const canUseMembership = requiresPayment && state.selectedCourse.acceptsMemberships && state.portalAuthState === "authenticated" && state.eligibleMemberships.length > 0;
18267
+ const canUseMembership = requiresPayment && state.selectedRun.acceptsMemberships && state.portalAuthState === "authenticated" && state.eligibleMemberships.length > 0;
17268
18268
  if (requiresPayment && canUseMembership) {
17269
18269
  setters.setStep("select-payment");
17270
18270
  return { kind: "state-updated" };
@@ -17274,7 +18274,7 @@ async function submitDetails(state, setters) {
17274
18274
  }
17275
18275
  async function continuePayment(state, setters) {
17276
18276
  const invalid = validateSubmission(state, setters);
17277
- if (invalid || !state.selectedCourse) return invalid ?? { kind: "validation-failed" };
18277
+ if (invalid || !state.selectedRun) return invalid ?? { kind: "validation-failed" };
17278
18278
  if (!state.pricing?.selectedRequiresPayment) {
17279
18279
  setters.setStep("enter-details");
17280
18280
  return { kind: "state-updated" };
@@ -17289,7 +18289,7 @@ async function continuePayment(state, setters) {
17289
18289
  }
17290
18290
  return checkout(selectedState, setters);
17291
18291
  }
17292
- function useCourseRegistrationActions(state, setStep) {
18292
+ function useWholeSeriesRegistrationActions(state, setStep) {
17293
18293
  const [errors, setErrors] = useState({});
17294
18294
  const [enrollmentResult, setEnrollmentResult] = useState(null);
17295
18295
  const [errorMessage, setErrorMessage] = useState("");
@@ -17316,14 +18316,15 @@ function useCourseRegistrationActions(state, setStep) {
17316
18316
  };
17317
18317
  }
17318
18318
  //#endregion
17319
- //#region ../blocks/src/system/runtime/nodes/course-registration/useCourseRegistrationPortal.ts
18319
+ //#region ../blocks/src/system/runtime/nodes/event-registration/whole-series/useWholeSeriesRegistrationPortal.ts
17320
18320
  const EMPTY_FORM = {
17321
18321
  name: "",
17322
18322
  email: "",
17323
18323
  phone: "",
17324
- notes: ""
18324
+ notes: "",
18325
+ consentAccepted: false
17325
18326
  };
17326
- function useCourseRegistrationPortal(api) {
18327
+ function useWholeSeriesRegistrationPortal(api) {
17327
18328
  const [formData, setFormData] = useState(EMPTY_FORM);
17328
18329
  const [portalAuthState, setPortalAuthState] = useState("checking");
17329
18330
  const updateFormData = useCallback((updater) => {
@@ -17359,19 +18360,19 @@ function useCourseRegistrationPortal(api) {
17359
18360
  };
17360
18361
  }
17361
18362
  //#endregion
17362
- //#region ../blocks/src/system/runtime/nodes/course-registration/useCourseWaitlistSelection.ts
17363
- function useCourseWaitlistSelection(input) {
18363
+ //#region ../blocks/src/system/runtime/nodes/event-registration/whole-series/useWholeSeriesWaitlistSelection.ts
18364
+ function useWholeSeriesWaitlistSelection(input) {
17364
18365
  useEffect(() => {
17365
18366
  const claim = input.waitlistClaim.claim;
17366
18367
  if (!claim || claim.subject.kind !== "whole_series") return;
17367
18368
  const eventSeriesId = claim.subject.eventSeriesId;
17368
- const course = input.scopedCourses.find((candidate) => candidate.eventSeriesId === eventSeriesId);
17369
- if (!course) {
17370
- input.reportError("This waitlist claim is for a different course.");
18369
+ const run = input.scopedRuns.find((candidate) => candidate.eventSeriesId === eventSeriesId);
18370
+ if (!run) {
18371
+ input.reportError("This waitlist claim is for a different run.");
17371
18372
  input.goToStep("error");
17372
18373
  return;
17373
18374
  }
17374
- input.chooseCourse(course);
18375
+ input.chooseRun(run);
17375
18376
  input.updateFormData((current) => ({
17376
18377
  ...current,
17377
18378
  email: claim.prefill.email,
@@ -17379,12 +18380,12 @@ function useCourseWaitlistSelection(input) {
17379
18380
  phone: claim.prefill.phone ?? "",
17380
18381
  notes: claim.prefill.notes ?? ""
17381
18382
  }));
17382
- if (input.step === "select-course") input.goToStep("enter-details");
18383
+ if (input.step === "select-run") input.goToStep("enter-details");
17383
18384
  }, [
17384
- input.chooseCourse,
18385
+ input.chooseRun,
17385
18386
  input.goToStep,
17386
18387
  input.reportError,
17387
- input.scopedCourses,
18388
+ input.scopedRuns,
17388
18389
  input.step,
17389
18390
  input.updateFormData,
17390
18391
  input.waitlistClaim.claim
@@ -17401,40 +18402,48 @@ function useCourseWaitlistSelection(input) {
17401
18402
  ]);
17402
18403
  }
17403
18404
  //#endregion
17404
- //#region ../blocks/src/system/runtime/nodes/course-registration/useCourseRegistrationWizard.ts
17405
- function useCourseRegistrationWizard(props, options = {}) {
18405
+ //#region ../blocks/src/system/runtime/nodes/event-registration/whole-series/useWholeSeriesRegistrationWizard.ts
18406
+ function useWholeSeriesRegistrationWizard(props, options = {}) {
18407
+ return useWholeSeriesRegistrationWizardWithDeps(wholeSeriesRegistrationWizardDeps, props, options);
18408
+ }
18409
+ const wholeSeriesRegistrationWizardDeps = { readLocation: () => ({
18410
+ search: window.location.search,
18411
+ hash: window.location.hash
18412
+ }) };
18413
+ function useWholeSeriesRegistrationWizardWithDeps(deps, props, options = {}) {
17406
18414
  const api = useBlockApi();
17407
- const selection = useCourseRegistrationSelection(props);
17408
- const portal = useCourseRegistrationPortal(api);
17409
- const waitlistClaim = useWaitlistClaim();
18415
+ const [location] = useState(deps.readLocation);
18416
+ const selection = useWholeSeriesRegistrationSelection(props, location);
18417
+ const portal = useWholeSeriesRegistrationPortal(api);
18418
+ const waitlistClaim = useWaitlistClaimForToken(new URLSearchParams(location.search).get("waitlist_claim")?.trim() || null);
17410
18419
  const [bookingMode, setBookingMode] = useState(null);
17411
18420
  const [altchaSolution, setAltchaSolution] = useState(null);
17412
- const eligibility = useCourseEligibility({
18421
+ const eligibility = useWholeSeriesEligibility({
17413
18422
  api,
17414
- selectedCourse: selection.selectedCourse,
17415
- hasPaidSelection: selection.selectedCoursePricing?.hasPaidSelection ?? false,
18423
+ selectedRun: selection.selectedRun,
18424
+ hasPaidSelection: selection.selectedRunPricing?.hasPaidSelection ?? false,
17416
18425
  portalAuthState: portal.portalAuthState,
17417
18426
  waitlistClaimToken: waitlistClaim.token
17418
18427
  });
17419
18428
  const discountUi = useDiscountCodeUi({
17420
18429
  api,
17421
- discountContext: useMemo(() => selection.selectedCourse && selection.selectedCoursePricing?.selectedRequiresPayment && eligibility.paymentChoice === "checkout" ? {
18430
+ discountContext: useMemo(() => selection.selectedRun && selection.selectedRunPricing?.selectedRequiresPayment && eligibility.paymentChoice === "checkout" ? {
17422
18431
  type: "whole_series",
17423
- eventSeriesId: selection.selectedCourse.eventSeriesId
18432
+ eventSeriesId: selection.selectedRun.eventSeriesId
17424
18433
  } : null, [
17425
18434
  eligibility.paymentChoice,
17426
- selection.selectedCourse,
17427
- selection.selectedCoursePricing?.selectedRequiresPayment
18435
+ selection.selectedRun,
18436
+ selection.selectedRunPricing?.selectedRequiresPayment
17428
18437
  ]),
17429
- subtotalCents: selection.selectedCoursePricing?.selectedPriceAmount ?? void 0
18438
+ subtotalCents: selection.selectedRunPricing?.selectedPriceAmount ?? void 0
17430
18439
  });
17431
- const actions = useCourseRegistrationActions({
18440
+ const actions = useWholeSeriesRegistrationActions({
17432
18441
  api,
17433
- selectedCourse: selection.selectedCourse,
17434
- pricing: selection.selectedCoursePricing,
18442
+ selectedRun: selection.selectedRun,
18443
+ pricing: selection.selectedRunPricing,
17435
18444
  formData: portal.formData,
17436
18445
  portalAuthState: portal.portalAuthState,
17437
- eligibility: eligibility.courseEligibility,
18446
+ eligibility: eligibility.runEligibility,
17438
18447
  eligibleMemberships: eligibility.eligibleMemberships,
17439
18448
  paymentChoice: eligibility.paymentChoice,
17440
18449
  selectedMembershipId: eligibility.selectedMembershipId,
@@ -17444,14 +18453,16 @@ function useCourseRegistrationWizard(props, options = {}) {
17444
18453
  discountCode: discountUi.discountCode,
17445
18454
  options
17446
18455
  }, selection.goToStep);
17447
- useCourseRegistrationEffects({
18456
+ useWholeSeriesRegistrationEffects({
17448
18457
  api,
17449
18458
  actions,
17450
18459
  portal,
17451
18460
  selection,
17452
- waitlistClaim
18461
+ waitlistClaim,
18462
+ anchorId: options.anchorId ?? "event-registration",
18463
+ location
17453
18464
  });
17454
- return buildCourseRegistrationWizardResult({
18465
+ return buildWholeSeriesRegistrationWizardResult({
17455
18466
  api,
17456
18467
  selection,
17457
18468
  portal,
@@ -17459,10 +18470,10 @@ function useCourseRegistrationWizard(props, options = {}) {
17459
18470
  actions,
17460
18471
  discountUi,
17461
18472
  waitlistClaim,
17462
- view: deriveCourseRegistrationViewState({
17463
- scopedCourses: selection.scopedCourses,
17464
- selectedCourse: selection.selectedCourse,
17465
- pricing: selection.selectedCoursePricing,
18473
+ view: deriveWholeSeriesRegistrationViewState({
18474
+ scopedRuns: selection.scopedRuns,
18475
+ selectedRun: selection.selectedRun,
18476
+ pricing: selection.selectedRunPricing,
17466
18477
  portalAuthState: portal.portalAuthState,
17467
18478
  eligibleMembershipCount: eligibility.eligibleMemberships.length,
17468
18479
  bookingMode,
@@ -17472,26 +18483,27 @@ function useCourseRegistrationWizard(props, options = {}) {
17472
18483
  bookingMode,
17473
18484
  setBookingMode,
17474
18485
  altchaSolution,
17475
- setAltchaSolution
18486
+ setAltchaSolution,
18487
+ anchorId: options.anchorId ?? "event-registration"
17476
18488
  });
17477
18489
  }
17478
- function useCourseRegistrationEffects(input) {
17479
- useCoursePaymentVerification(input.api, {
18490
+ function useWholeSeriesRegistrationEffects(input) {
18491
+ useWholeSeriesPaymentVerification(input.api, {
17480
18492
  setStep: input.selection.goToStep,
17481
18493
  setErrorMessage: input.actions.reportError,
17482
18494
  setEnrollmentResult: input.actions.recordEnrollmentResult
17483
- });
17484
- useCourseWaitlistSelection({
18495
+ }, input.anchorId, input.location);
18496
+ useWholeSeriesWaitlistSelection({
17485
18497
  waitlistClaim: input.waitlistClaim,
17486
- scopedCourses: input.selection.scopedCourses,
18498
+ scopedRuns: input.selection.scopedRuns,
17487
18499
  step: input.selection.step,
17488
18500
  goToStep: input.selection.goToStep,
17489
- chooseCourse: input.selection.chooseCourse,
18501
+ chooseRun: input.selection.chooseRun,
17490
18502
  updateFormData: input.portal.updateFormData,
17491
18503
  reportError: input.actions.reportError
17492
18504
  });
17493
18505
  }
17494
- function buildCourseRegistrationWizardResult(parts) {
18506
+ function buildWholeSeriesRegistrationWizardResult(parts) {
17495
18507
  const handleBookingModeChange = (mode) => {
17496
18508
  parts.setBookingMode(mode);
17497
18509
  parts.eligibility.choosePaymentChoice(mode === "membership" ? "membership" : "checkout");
@@ -17515,30 +18527,30 @@ function buildCourseRegistrationWizardResult(parts) {
17515
18527
  manualCodeEntryAllowed: parts.discountUi.manualCodeEntryAllowed,
17516
18528
  discountsAvailableLoading: parts.discountUi.discountsAvailableLoading,
17517
18529
  ...parts.view,
17518
- handleCourseSelect: (course) => {
17519
- parts.selection.chooseCourse(course);
18530
+ handleRunSelect: (run) => {
18531
+ parts.selection.chooseRun(run);
17520
18532
  parts.selection.goToStep("enter-details");
17521
18533
  },
17522
18534
  handleRetry: () => {
17523
- parts.selection.goToStep(parts.selection.scopedCourses.length === 1 ? "enter-details" : "select-course");
18535
+ parts.selection.goToStep(parts.selection.scopedRuns.length === 1 ? "enter-details" : "select-run");
17524
18536
  parts.actions.reportError("");
17525
18537
  },
17526
18538
  handleBookingModeChange,
17527
- handleLogout: parts.portal.portalAuthState === "authenticated" ? () => logoutPortal(COURSE_REGISTRATION_ANCHOR_ID) : void 0,
17528
- selectedCoursePricingPayload: buildCoursePricingOptionPayload(parts.selection.selectedCoursePricing)
18539
+ handleLogout: parts.portal.portalAuthState === "authenticated" ? () => logoutPortal(parts.anchorId) : void 0,
18540
+ selectedRunPricingPayload: buildWholeSeriesPricingOptionPayload(parts.selection.selectedRunPricing)
17529
18541
  };
17530
18542
  }
17531
18543
  //#endregion
17532
- //#region ../blocks/src/system/runtime/nodes/course-registration/whole-series-registration.headless.planning.ts
18544
+ //#region ../blocks/src/system/runtime/nodes/event-registration/whole-series/whole-series-registration.headless.planning.ts
17533
18545
  const STEP_IDS = {
17534
- "select-course": "select-run",
18546
+ "select-run": "select-run",
17535
18547
  "enter-details": "enter-details",
17536
18548
  "booking-mode": "select-booking-method",
17537
18549
  "select-payment": "select-payment"
17538
18550
  };
17539
18551
  function toPublicStepId(step) {
17540
18552
  switch (step) {
17541
- case "select-course":
18553
+ case "select-run":
17542
18554
  case "enter-details":
17543
18555
  case "booking-mode":
17544
18556
  case "select-payment": return STEP_IDS[step];
@@ -17598,7 +18610,7 @@ function resolveWholeSeriesRegistrationStatus(wizard) {
17598
18610
  tag: "error",
17599
18611
  message: wizard.errorMessage
17600
18612
  };
17601
- case "select-course":
18613
+ case "select-run":
17602
18614
  case "enter-details":
17603
18615
  case "booking-mode":
17604
18616
  case "select-payment": return { tag: "ready" };
@@ -17632,7 +18644,7 @@ function resolveWholeSeriesRegistrationView(wizard) {
17632
18644
  kind: "error",
17633
18645
  message: "Waitlist registration completed without a result."
17634
18646
  };
17635
- case "select-course":
18647
+ case "select-run":
17636
18648
  case "enter-details":
17637
18649
  case "booking-mode":
17638
18650
  case "select-payment":
@@ -17669,7 +18681,7 @@ function resolveWholeSeriesPaymentSelection(input) {
17669
18681
  }
17670
18682
  //#endregion
17671
18683
  //#region ../blocks/src/system/runtime/hooks/useHeadlessWholeSeriesRegistrationFlow.ts
17672
- const wholeSeriesRegistrationControllerDeps = { useCourseRegistrationWizard };
18684
+ const wholeSeriesRegistrationControllerDeps = { useWholeSeriesRegistrationWizard };
17673
18685
  function createWholeSeriesRegistrationBlockApiConfig(input) {
17674
18686
  return {
17675
18687
  baseUrl: input.apiBaseUrl,
@@ -17695,8 +18707,8 @@ function useHeadlessWholeSeriesRegistrationFlow(options) {
17695
18707
  return useWholeSeriesRegistrationControllerWithDeps(options, wholeSeriesRegistrationControllerDeps);
17696
18708
  }
17697
18709
  function useWholeSeriesRegistrationControllerWithDeps(options, deps) {
17698
- const wizard = deps.useCourseRegistrationWizard({
17699
- courses: (options.runs ?? []).map(toPublicCourse),
18710
+ const wizard = deps.useWholeSeriesRegistrationWizard({
18711
+ runs: (options.runs ?? []).map(toPublicWholeSeriesOffering),
17700
18712
  subject: options.subject ?? null
17701
18713
  }, { onCheckoutRedirect: () => {} });
17702
18714
  const steps = useMemo(() => deriveWholeSeriesRegistrationSteps({
@@ -17704,11 +18716,11 @@ function useWholeSeriesRegistrationControllerWithDeps(options, deps) {
17704
18716
  step: wizard.step
17705
18717
  }), [wizard.step, wizard.wizardSteps]);
17706
18718
  const currentStep = steps.find((step) => step.state === "active") ?? null;
17707
- const pricingSelection = resolveWholeSeriesPricingSelection(wizard.selectedCoursePricing);
18719
+ const pricingSelection = resolveWholeSeriesPricingSelection(wizard.selectedRunPricing);
17708
18720
  const paymentSelection = resolveWholeSeriesPaymentSelection({
17709
18721
  paymentChoice: wizard.paymentChoice,
17710
18722
  selectedMembershipId: wizard.selectedMembershipId,
17711
- required: wizard.selectedCoursePricing?.selectedRequiresPayment ?? false
18723
+ required: wizard.selectedRunPricing?.selectedRequiresPayment ?? false
17712
18724
  });
17713
18725
  const updateRegistrant = useCallback((values) => wizard.updateFormData(values), [wizard]);
17714
18726
  const setSlidingAmountCents = useCallback((amount) => {
@@ -17734,8 +18746,8 @@ function useWholeSeriesRegistrationControllerWithDeps(options, deps) {
17734
18746
  const blocked = resolveActionBlocker(wizard);
17735
18747
  if (blocked) return blocked;
17736
18748
  switch (wizard.step) {
17737
- case "select-course":
17738
- if (!wizard.selectedCourse) return {
18749
+ case "select-run":
18750
+ if (!wizard.selectedRun) return {
17739
18751
  ok: false,
17740
18752
  reason: "blocked",
17741
18753
  message: "Choose an available set of dates to continue."
@@ -17765,7 +18777,7 @@ function useWholeSeriesRegistrationControllerWithDeps(options, deps) {
17765
18777
  const back = useCallback(() => {
17766
18778
  switch (wizard.step) {
17767
18779
  case "enter-details":
17768
- if (!wizard.hasPreSelectedCourse) wizard.goToStep("select-course");
18780
+ if (!wizard.hasPreSelectedRun) wizard.goToStep("select-run");
17769
18781
  return;
17770
18782
  case "booking-mode":
17771
18783
  wizard.goToStep("enter-details");
@@ -17773,7 +18785,7 @@ function useWholeSeriesRegistrationControllerWithDeps(options, deps) {
17773
18785
  case "select-payment":
17774
18786
  wizard.goToStep(wizard.canUseMembership ? "booking-mode" : "enter-details");
17775
18787
  return;
17776
- case "select-course":
18788
+ case "select-run":
17777
18789
  case "submitting":
17778
18790
  case "redirecting":
17779
18791
  case "verifying-payment":
@@ -17785,7 +18797,7 @@ function useWholeSeriesRegistrationControllerWithDeps(options, deps) {
17785
18797
  }
17786
18798
  }, [wizard]);
17787
18799
  const payment = {
17788
- required: wizard.selectedCoursePricing?.selectedRequiresPayment ?? false,
18800
+ required: wizard.selectedRunPricing?.selectedRequiresPayment ?? false,
17789
18801
  selection: paymentSelection,
17790
18802
  canUseMembership: wizard.canUseMembership,
17791
18803
  eligibleMemberships: wizard.eligibleMemberships.map((membership) => ({
@@ -17795,7 +18807,7 @@ function useWholeSeriesRegistrationControllerWithDeps(options, deps) {
17795
18807
  eligibility: wizard.eligibilityLoading ? { tag: "loading" } : wizard.eligibilityError ? {
17796
18808
  tag: "error",
17797
18809
  message: wizard.eligibilityError
17798
- } : wizard.courseEligibility || wizard.portalAuthState !== "checking" ? { tag: "loaded" } : { tag: "idle" }
18810
+ } : wizard.runEligibility || wizard.portalAuthState !== "checking" ? { tag: "loaded" } : { tag: "idle" }
17799
18811
  };
17800
18812
  const spamProtection = wizard.showSpamProtection ? {
17801
18813
  enabled: true,
@@ -17806,13 +18818,13 @@ function useWholeSeriesRegistrationControllerWithDeps(options, deps) {
17806
18818
  },
17807
18819
  solution: wizard.altchaSolution
17808
18820
  } : { enabled: false };
17809
- const selectedRun = wizard.selectedCourse;
17810
- const isFull = wizard.courseEligibility?.isFull ?? (selectedRun?.availableSpots !== null && selectedRun?.availableSpots !== void 0 ? selectedRun.availableSpots <= 0 : false);
18821
+ const selectedRun = wizard.selectedRun;
18822
+ const isFull = wizard.runEligibility?.isFull ?? (selectedRun?.availableSpots !== null && selectedRun?.availableSpots !== void 0 ? selectedRun.availableSpots <= 0 : false);
17811
18823
  return {
17812
18824
  status: resolveWholeSeriesRegistrationStatus(wizard),
17813
18825
  view: resolveWholeSeriesRegistrationView({
17814
18826
  step: wizard.step,
17815
- scopedRunsCount: wizard.scopedCourses.length,
18827
+ scopedRunsCount: wizard.scopedRuns.length,
17816
18828
  selectedRun,
17817
18829
  enrollmentResult: wizard.enrollmentResult,
17818
18830
  errorMessage: wizard.errorMessage
@@ -17820,10 +18832,10 @@ function useWholeSeriesRegistrationControllerWithDeps(options, deps) {
17820
18832
  steps,
17821
18833
  currentStep,
17822
18834
  runs: {
17823
- items: (options.runs ?? []).map((run) => toWholeSeriesRegistrationRun(toPublicCourse(run))),
17824
- scoped: wizard.scopedCourses.map(toWholeSeriesRegistrationRun),
18835
+ items: (options.runs ?? []).map((run) => toWholeSeriesRegistrationRun(toPublicWholeSeriesOffering(run))),
18836
+ scoped: wizard.scopedRuns.map(toWholeSeriesRegistrationRun),
17825
18837
  selected: selectedRun ? toWholeSeriesRegistrationRun(selectedRun) : null,
17826
- hasPreSelectedRun: wizard.hasPreSelectedCourse,
18838
+ hasPreSelectedRun: wizard.hasPreSelectedRun,
17827
18839
  subject: options.subject ?? null
17828
18840
  },
17829
18841
  registrant: {
@@ -17831,7 +18843,7 @@ function useWholeSeriesRegistrationControllerWithDeps(options, deps) {
17831
18843
  errors: wizard.errors
17832
18844
  },
17833
18845
  pricing: {
17834
- ...toWholeSeriesRegistrationPricing(wizard.selectedCoursePricing),
18846
+ ...toWholeSeriesRegistrationPricing(wizard.selectedRunPricing),
17835
18847
  selectedOptionId: wizard.selectedPricingOptionId,
17836
18848
  selection: pricingSelection
17837
18849
  },
@@ -17847,8 +18859,8 @@ function useWholeSeriesRegistrationControllerWithDeps(options, deps) {
17847
18859
  enrollmentOpen: selectedRun?.enrollmentOpen ?? false,
17848
18860
  availableSpots: selectedRun?.availableSpots ?? null,
17849
18861
  isFull,
17850
- canJoinWaitlist: wizard.courseEligibility?.canJoinWaitlist ?? false,
17851
- message: wizard.courseEligibility?.reason ?? null
18862
+ canJoinWaitlist: wizard.runEligibility?.canJoinWaitlist ?? false,
18863
+ message: wizard.runEligibility?.reason ?? null
17852
18864
  },
17853
18865
  portalAuth: {
17854
18866
  state: wizard.portalAuthState,
@@ -17862,8 +18874,8 @@ function useWholeSeriesRegistrationControllerWithDeps(options, deps) {
17862
18874
  },
17863
18875
  actions: {
17864
18876
  selectRun: (runId) => {
17865
- const run = wizard.scopedCourses.find((candidate) => candidate.eventSeriesId === runId) ?? null;
17866
- if (run) wizard.handleCourseSelect(run);
18877
+ const run = wizard.scopedRuns.find((candidate) => candidate.eventSeriesId === runId) ?? null;
18878
+ if (run) wizard.handleRunSelect(run);
17867
18879
  },
17868
18880
  updateRegistrant,
17869
18881
  selectPricingOption: wizard.choosePricingOption,
@@ -17907,8 +18919,8 @@ function toHeadlessActionResult(result) {
17907
18919
  };
17908
18920
  }
17909
18921
  }
17910
- function toPublicCourse(run) {
17911
- const pricing = toCoursePricing(run.pricing);
18922
+ function toPublicWholeSeriesOffering(run) {
18923
+ const pricing = toWholeSeriesPricing(run.pricing);
17912
18924
  return {
17913
18925
  eventSeriesId: run.registrationTarget.eventSeriesId,
17914
18926
  eventOfferingId: run.eventOfferingId,
@@ -17916,6 +18928,7 @@ function toPublicCourse(run) {
17916
18928
  slug: run.slug,
17917
18929
  description: run.description,
17918
18930
  teamMembers: run.teamMembers ? [...run.teamMembers] : void 0,
18931
+ consent: run.consent,
17919
18932
  enrollmentOpen: run.registrationOpen,
17920
18933
  pricing,
17921
18934
  currency: run.pricing.currency,
@@ -17933,7 +18946,7 @@ function toPublicCourse(run) {
17933
18946
  venue: run.venue
17934
18947
  };
17935
18948
  }
17936
- function toCoursePricing(pricing) {
18949
+ function toWholeSeriesPricing(pricing) {
17937
18950
  const common = {
17938
18951
  bookingRequirement: pricing.bookingRequirement,
17939
18952
  pricingStrategy: pricing.pricingStrategy,
@@ -18060,8 +19073,8 @@ function resolveWaitlistClaim(wizard) {
18060
19073
  return { tag: "none" };
18061
19074
  }
18062
19075
  function resolveActionBlocker(wizard) {
18063
- if (!wizard.selectedCourse) return null;
18064
- if (!wizard.selectedCourse.enrollmentOpen) return {
19076
+ if (!wizard.selectedRun) return null;
19077
+ if (!wizard.selectedRun.enrollmentOpen) return {
18065
19078
  ok: false,
18066
19079
  reason: "blocked",
18067
19080
  message: "Sign-up is closed."
@@ -18071,10 +19084,10 @@ function resolveActionBlocker(wizard) {
18071
19084
  reason: "blocked",
18072
19085
  message: "Availability is still being checked."
18073
19086
  };
18074
- if (wizard.courseEligibility?.isFull && !wizard.courseEligibility.canJoinWaitlist) return {
19087
+ if (wizard.runEligibility?.isFull && !wizard.runEligibility.canJoinWaitlist) return {
18075
19088
  ok: false,
18076
19089
  reason: "blocked",
18077
- message: wizard.courseEligibility.reason ?? "There are no places available."
19090
+ message: wizard.runEligibility.reason ?? "There are no places available."
18078
19091
  };
18079
19092
  return null;
18080
19093
  }