@riverbankcms/sdk 0.147.0 → 0.149.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 (442) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +1 -1
  3. package/dist/{PreviewEditorSidebar-DtpB3_sS.mjs → PreviewEditorSidebar-DBKln68M.mjs} +301 -205
  4. package/dist/{PreviewEditorUI-DxTLgaHo.mjs → PreviewEditorUI-DpRX4Mum.mjs} +68 -63
  5. package/dist/{PreviewQueryProvider-Dd4dxOiU.mjs → PreviewQueryProvider-C0mndwHB.mjs} +3 -3
  6. package/dist/{SdkPreviewModeRuntime-DMMNCngt.mjs → SdkPreviewModeRuntime-DJPmPY-r.mjs} +1247 -541
  7. package/dist/{SiteChromeCustomizeContext-DQXZXiqS.mjs → SiteChromeCustomizeContext-JYA0cJ_Z.mjs} +209720 -204978
  8. package/dist/_dts/ai/src/contracts/proposals.d.ts +0 -33
  9. package/dist/_dts/ai/src/contracts/siteStyleProposalSchemas.d.ts +0 -3
  10. package/dist/_dts/api/src/accessAdmin.d.ts +0 -4
  11. package/dist/_dts/api/src/accountApi.d.ts +1 -1
  12. package/dist/_dts/api/src/admin.d.ts +22 -22
  13. package/dist/_dts/api/src/aiPatch.d.ts +2 -2
  14. package/dist/_dts/api/src/aiPlayground.d.ts +1 -0
  15. package/dist/_dts/api/src/analytics.d.ts +2 -2
  16. package/dist/_dts/api/src/apiEndpointTypes.d.ts +2 -0
  17. package/dist/_dts/api/src/appointmentSetup.d.ts +2 -2
  18. package/dist/_dts/api/src/auth.d.ts +10 -10
  19. package/dist/_dts/api/src/availability.d.ts +6 -6
  20. package/dist/_dts/api/src/billing.d.ts +42 -15
  21. package/dist/_dts/api/src/billingEndpointDefinitions.d.ts +8 -0
  22. package/dist/_dts/api/src/billingEndpointTypes.d.ts +15 -6
  23. package/dist/_dts/api/src/blocks.d.ts +15 -14
  24. package/dist/_dts/api/src/blocksKeys.d.ts +2 -0
  25. package/dist/_dts/api/src/bookingConfig.d.ts +33 -50
  26. package/dist/_dts/api/src/bookingManagementEndpoints.d.ts +2 -6
  27. package/dist/_dts/api/src/bookingOperations.d.ts +9 -11
  28. package/dist/_dts/api/src/bookingRecords.d.ts +16 -11
  29. package/dist/_dts/api/src/bookingRefundOutcomes.d.ts +5 -5
  30. package/dist/_dts/api/src/bookings.d.ts +7 -7
  31. package/dist/_dts/api/src/calendar.d.ts +9 -9
  32. package/dist/_dts/api/src/clientErrorReporting.d.ts +11 -0
  33. package/dist/_dts/api/src/commercePortalEndpoints.d.ts +7 -8
  34. package/dist/_dts/api/src/common/cancellation.d.ts +23 -0
  35. package/dist/_dts/api/src/common/envelope.d.ts +2 -2
  36. package/dist/_dts/api/src/content-editor.d.ts +2 -2
  37. package/dist/_dts/api/src/contentEntries.d.ts +17 -48
  38. package/dist/_dts/api/src/contentRuntime.d.ts +51 -37
  39. package/dist/_dts/api/src/contentTypes.d.ts +11 -11
  40. package/dist/_dts/api/src/contentVersionHistoryClient.d.ts +6 -6
  41. package/dist/_dts/api/src/customerMembershipOutcomes.d.ts +1 -1
  42. package/dist/_dts/api/src/documentLifecycle.d.ts +67 -0
  43. package/dist/_dts/api/src/domains.d.ts +16 -16
  44. package/dist/_dts/api/src/editLeaseEndpoints.d.ts +72 -0
  45. package/dist/_dts/api/src/emailSettings.d.ts +4 -4
  46. package/dist/_dts/api/src/endpoints.d.ts +135 -51
  47. package/dist/_dts/api/src/eventEmailTemplates.d.ts +2 -2
  48. package/dist/_dts/api/src/eventManagementContracts.d.ts +29 -7
  49. package/dist/_dts/api/src/eventManagementEndpointDefinitions.d.ts +0 -8
  50. package/dist/_dts/api/src/eventPageWords.d.ts +7 -12
  51. package/dist/_dts/api/src/footerSettings.d.ts +6 -6
  52. package/dist/_dts/api/src/index.d.ts +8 -7
  53. package/dist/_dts/api/src/indexCoreTypes.d.ts +1 -0
  54. package/dist/_dts/api/src/indexExtendedTypes.d.ts +1 -1
  55. package/dist/_dts/api/src/navigation.d.ts +5 -5
  56. package/dist/_dts/api/src/pageSurfaceEditorEndpoints.d.ts +55 -0
  57. package/dist/_dts/api/src/pageSurfaceEndpoints.d.ts +28 -7
  58. package/dist/_dts/api/src/pages.d.ts +7 -7
  59. package/dist/_dts/api/src/performance.d.ts +1 -1
  60. package/dist/_dts/api/src/public/index.d.ts +1 -1
  61. package/dist/_dts/api/src/publicAppointmentBookingContracts.d.ts +4 -2
  62. package/dist/_dts/api/src/publicExperience/commerceEndpoints.d.ts +6 -29
  63. package/dist/_dts/api/src/redirects.d.ts +3 -3
  64. package/dist/_dts/api/src/request.d.ts +11 -2
  65. package/dist/_dts/api/src/resources.d.ts +4 -4
  66. package/dist/_dts/api/src/routes.d.ts +8 -3
  67. package/dist/_dts/api/src/sdk-event-upsert.d.ts +1 -2
  68. package/dist/_dts/api/src/sdkBlockUpsertContracts.d.ts +21 -0
  69. package/dist/_dts/api/src/sdkContracts.d.ts +5 -28
  70. package/dist/_dts/api/src/sdkEventEndpointDefinitions.d.ts +1 -1
  71. package/dist/_dts/api/src/sdkEventOccurrenceRequestContracts.d.ts +43 -0
  72. package/dist/_dts/api/src/sdkManagedEventContracts.d.ts +4 -2
  73. package/dist/_dts/api/src/sdkPullEventContracts.d.ts +9 -2
  74. package/dist/_dts/api/src/seo.d.ts +4 -4
  75. package/dist/_dts/api/src/services.d.ts +4 -4
  76. package/dist/_dts/api/src/siteManagementEndpoints.d.ts +15 -8
  77. package/dist/_dts/api/src/siteMembers.d.ts +10 -10
  78. package/dist/_dts/api/src/siteOnboarding.d.ts +14 -0
  79. package/dist/_dts/api/src/siteOperations.d.ts +6 -2
  80. package/dist/_dts/api/src/sitePlatformEndpoints.d.ts +7 -3
  81. package/dist/_dts/api/src/siteRuntimeEndpoints.d.ts +5 -12
  82. package/dist/_dts/api/src/siteRuntimeEntry.d.ts +31 -0
  83. package/dist/_dts/billing/src/checkout/platform.d.ts +77 -0
  84. package/dist/_dts/billing/src/components/index.d.ts +25 -40
  85. package/dist/_dts/billing/src/membership/index.d.ts +1 -3
  86. package/dist/_dts/billing/src/plans/entitlements.d.ts +80 -0
  87. package/dist/_dts/billing/src/plans/registry.d.ts +16 -16
  88. package/dist/_dts/billing/src/plans/standing.d.ts +9 -2
  89. package/dist/_dts/billing/src/plans/types.d.ts +5 -15
  90. package/dist/_dts/billing/src/site-arrangements.d.ts +2 -2
  91. package/dist/_dts/billing/src/subscriptions/standingEvidence.d.ts +2 -4
  92. package/dist/_dts/billing/src/subscriptions/store.d.ts +17 -11
  93. package/dist/_dts/block-form/src/backend/store-backend.d.ts +6 -7
  94. package/dist/_dts/block-form/src/backend/types.d.ts +7 -0
  95. package/dist/_dts/block-form/src/widgets/FieldFrame.d.ts +3 -1
  96. package/dist/_dts/blocks/src/client/events.d.ts +3 -0
  97. package/dist/_dts/blocks/src/contracts/index.d.ts +1 -1
  98. package/dist/_dts/blocks/src/contracts/non-block-islands.d.ts +2 -2
  99. package/dist/_dts/blocks/src/contracts/proof-block-islands.d.ts +54 -14
  100. package/dist/_dts/blocks/src/pageRenderAdmission.d.ts +4 -13
  101. package/dist/_dts/blocks/src/pageRendererContracts.d.ts +2 -0
  102. package/dist/_dts/blocks/src/portal/types.d.ts +9 -8
  103. package/dist/_dts/blocks/src/system/blocks/contact-newsletter.d.ts +2 -1
  104. package/dist/_dts/blocks/src/system/blocks/event-registration.d.ts +3 -1
  105. package/dist/_dts/blocks/src/system/blocks/events/shared/schemas.d.ts +28 -28
  106. package/dist/_dts/blocks/src/system/blocks/events/shared/types.d.ts +7 -2
  107. package/dist/_dts/blocks/src/system/blocks/shared/bookingPaymentTerms.d.ts +84 -160
  108. package/dist/_dts/blocks/src/system/blocks/shop.d.ts +2 -2
  109. package/dist/_dts/blocks/src/system/blocks/shop.shared.d.ts +31 -4
  110. package/dist/_dts/blocks/src/system/runtime/api/client.d.ts +2 -2
  111. package/dist/_dts/blocks/src/system/runtime/api/index.d.ts +1 -1
  112. package/dist/_dts/blocks/src/system/runtime/api/types/appointments.d.ts +4 -2
  113. package/dist/_dts/blocks/src/system/runtime/api/types/core.d.ts +3 -1
  114. package/dist/_dts/blocks/src/system/runtime/api/types/events.d.ts +6 -0
  115. package/dist/_dts/blocks/src/system/runtime/api/types/portal.d.ts +6 -0
  116. package/dist/_dts/blocks/src/system/runtime/api/types/shop.d.ts +4 -0
  117. package/dist/_dts/blocks/src/system/runtime/components/booking/SuccessMessage.d.ts +4 -1
  118. package/dist/_dts/blocks/src/system/runtime/components/registry.client.d.ts +72 -12
  119. package/dist/_dts/blocks/src/system/runtime/components/runtime-backed-blocks.d.ts +36 -6
  120. package/dist/_dts/blocks/src/system/runtime/hooks/useBookingNowIso.d.ts +8 -0
  121. package/dist/_dts/blocks/src/system/runtime/hooks/useHeadlessBookingFlow.d.ts +3 -0
  122. package/dist/_dts/blocks/src/system/runtime/hooks/usePaymentVerification.d.ts +2 -1
  123. package/dist/_dts/blocks/src/system/runtime/hooks/usePolling.d.ts +7 -48
  124. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.checkout-return-context.d.ts +7 -0
  125. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.completion.d.ts +3 -1
  126. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.headless.state.d.ts +4 -0
  127. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.interactive.d.ts +9 -0
  128. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.payment-confirmation.d.ts +13 -0
  129. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.state.d.ts +17 -2
  130. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.submit-actions.d.ts +8 -0
  131. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.submit-handler.d.ts +1 -0
  132. package/dist/_dts/blocks/src/system/runtime/nodes/booking-runtime-sources.d.ts +1 -0
  133. package/dist/_dts/blocks/src/system/runtime/nodes/checkout.server.d.ts +2 -1
  134. package/dist/_dts/blocks/src/system/runtime/nodes/commerce/shared/display.d.ts +9 -2
  135. package/dist/_dts/blocks/src/system/runtime/nodes/event-details/presentation.d.ts +14 -2
  136. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/EventRegistrationSurface.d.ts +2 -1
  137. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/EventRegistrationWizard.d.ts +5 -0
  138. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/PaymentSelectionStep.d.ts +2 -0
  139. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/SuccessStep.d.ts +4 -1
  140. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/eventPaymentOptions.d.ts +3 -3
  141. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/types.d.ts +2 -0
  142. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventRegistrationSubmit.d.ts +2 -5
  143. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventRegistrationWizard.d.ts +4 -0
  144. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration.interactive.d.ts +9 -5
  145. package/dist/_dts/blocks/src/system/runtime/nodes/events/EventListing.interactive.d.ts +6 -0
  146. package/dist/_dts/blocks/src/system/runtime/nodes/events/domain/dates.d.ts +37 -3
  147. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/EventCard.client.d.ts +1 -1
  148. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/EventCard.d.ts +16 -1
  149. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/eventCardPresentations.d.ts +13 -0
  150. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/eventCollectionContract.d.ts +29 -29
  151. package/dist/_dts/blocks/src/system/runtime/nodes/shared/MagicLinkForm.d.ts +1 -14
  152. package/dist/_dts/blocks/src/system/runtime/nodes/shared/MagicLinkForm.state.d.ts +12 -0
  153. package/dist/_dts/blocks/src/system/runtime/nodes/shop.interactive.d.ts +54 -6
  154. package/dist/_dts/blocks/src/system/runtime/shared/bookingPaymentOptions.d.ts +7 -2
  155. package/dist/_dts/blocks/src/system/runtime/shared/components/DemoBookingPortalAccess.d.ts +22 -0
  156. package/dist/_dts/blocks/src/system/runtime/shared/components/DemoPortalSignInLink.d.ts +4 -0
  157. package/dist/_dts/blocks/src/system/runtime/shared/components/index.d.ts +1 -0
  158. package/dist/_dts/blocks/src/system/runtime/shared/utils/demoBookingPassStorage.d.ts +10 -0
  159. package/dist/_dts/blocks/src/system/runtime/shared/utils/demoPortalMagicLink.d.ts +29 -0
  160. package/dist/_dts/commerce/src/purchase/bookingPaymentSelection.d.ts +54 -0
  161. package/dist/_dts/commerce/src/purchase/checkoutCommitPlan.d.ts +58 -13
  162. package/dist/_dts/commerce/src/purchase/checkoutErrorCodes.d.ts +1 -1
  163. package/dist/_dts/commerce/src/purchase/checkoutPaymentPlanPlanning.d.ts +16 -21
  164. package/dist/_dts/commerce/src/purchase/checkoutPaymentTerms.d.ts +23 -40
  165. package/dist/_dts/commerce/src/purchase/checkoutSessionMetadata.d.ts +2 -2
  166. package/dist/_dts/commerce/src/purchase/checkoutStripeSessionPlanning.d.ts +5 -4
  167. package/dist/_dts/commerce/src/purchase/event-registration-errors.d.ts +4 -0
  168. package/dist/_dts/commerce/src/purchase/index.d.ts +1 -3
  169. package/dist/_dts/commerce/src/purchase/membershipOrderItemMetadata.d.ts +4 -0
  170. package/dist/_dts/commerce/src/purchase/oneTimeCheckoutPlanning.d.ts +9 -4
  171. package/dist/_dts/commerce/src/purchase/orderInstalmentClosure.d.ts +13 -1
  172. package/dist/_dts/commerce/src/purchase/orderInstalmentLifecycle.d.ts +5 -0
  173. package/dist/_dts/commerce/src/purchase/orderItemMetadata.d.ts +3 -1
  174. package/dist/_dts/commerce/src/purchase/orderTypes.d.ts +7 -1
  175. package/dist/_dts/commerce/src/purchase/refundRailSplit.d.ts +1 -1
  176. package/dist/_dts/commerce/src/purchase/stateTransitions.d.ts +2 -2
  177. package/dist/_dts/commerce/src/purchase/stripeMinimumCharge.d.ts +6 -0
  178. package/dist/_dts/commerce/src/purchase/types.d.ts +2 -1
  179. package/dist/_dts/content-editor/src/components/ContentFieldsForm.d.ts +2 -7
  180. package/dist/_dts/content-editor/src/controller/EditLeaseController.d.ts +39 -0
  181. package/dist/_dts/content-editor/src/controller/EditorWriteGate.d.ts +38 -0
  182. package/dist/_dts/content-editor/src/controller/EntryControllerProvider.d.ts +25 -61
  183. package/dist/_dts/content-editor/src/controller/LinkedEntryLeaseBanner.d.ts +7 -0
  184. package/dist/_dts/content-editor/src/controller/LinkedEntryLeaseControllers.d.ts +14 -0
  185. package/dist/_dts/content-editor/src/controller/deriveEditorUnpublishedState.d.ts +6 -0
  186. package/dist/_dts/content-editor/src/controller/documentValueBaseline.d.ts +25 -0
  187. package/dist/_dts/content-editor/src/controller/editLeaseHandover.d.ts +30 -0
  188. package/dist/_dts/content-editor/src/controller/editLeaseLossSignal.d.ts +6 -0
  189. package/dist/_dts/content-editor/src/controller/editLeaseNotice.d.ts +28 -0
  190. package/dist/_dts/content-editor/src/controller/editorClientId.d.ts +2 -0
  191. package/dist/_dts/content-editor/src/controller/editorEditability.d.ts +38 -0
  192. package/dist/_dts/content-editor/src/controller/editorLeaseParticipation.d.ts +34 -0
  193. package/dist/_dts/content-editor/src/controller/normalizedMetadataBaseline.d.ts +29 -0
  194. package/dist/_dts/content-editor/src/controller/pageSurfaceDocumentBaselines.d.ts +14 -0
  195. package/dist/_dts/content-editor/src/controller/pageSurfaceLifecycle.d.ts +11 -0
  196. package/dist/_dts/content-editor/src/controller/planDocumentBaselineRefresh.d.ts +19 -0
  197. package/dist/_dts/content-editor/src/controller/readDocumentLeaseBaselines.d.ts +19 -0
  198. package/dist/_dts/content-editor/src/controller/refreshDocumentLeaseBaseline.d.ts +12 -0
  199. package/dist/_dts/content-editor/src/controller/refreshLinkedEntry.d.ts +17 -0
  200. package/dist/_dts/content-editor/src/controller/replayRestoredEditorEffects.d.ts +2 -3
  201. package/dist/_dts/content-editor/src/controller/routeWrites.d.ts +26 -0
  202. package/dist/_dts/content-editor/src/controller/useAutosaveTriggers.d.ts +16 -17
  203. package/dist/_dts/content-editor/src/controller/useBlockedPublishPlan.d.ts +6 -2
  204. package/dist/_dts/content-editor/src/controller/useBlocksList.d.ts +3 -3
  205. package/dist/_dts/content-editor/src/controller/useEntryValueAutosaves.d.ts +21 -0
  206. package/dist/_dts/content-editor/src/controller/useInitialEditorUiStore.d.ts +24 -0
  207. package/dist/_dts/content-editor/src/controller/useServerBaselineReconciliation.d.ts +17 -0
  208. package/dist/_dts/content-editor/src/footerComposerPanelTypes.d.ts +1 -1
  209. package/dist/_dts/content-editor/src/hooks/applyBlockedPublishPlan.d.ts +5 -1
  210. package/dist/_dts/content-editor/src/hooks/blockDraftLifecycle.d.ts +8 -47
  211. package/dist/_dts/content-editor/src/hooks/editLeaseMachine.d.ts +120 -0
  212. package/dist/_dts/content-editor/src/hooks/publishability.d.ts +6 -10
  213. package/dist/_dts/content-editor/src/hooks/useAutosaveStatus.d.ts +3 -0
  214. package/dist/_dts/content-editor/src/hooks/useBlockAutosave.d.ts +5 -15
  215. package/dist/_dts/content-editor/src/hooks/useDebouncedLatestSave.d.ts +7 -5
  216. package/dist/_dts/content-editor/src/hooks/useEditLease.d.ts +28 -0
  217. package/dist/_dts/content-editor/src/hooks/useEntryActions.d.ts +25 -39
  218. package/dist/_dts/content-editor/src/hooks/useEntryMutations.d.ts +17 -19
  219. package/dist/_dts/content-editor/src/hooks/useLinkedEntryAutosave.d.ts +5 -8
  220. package/dist/_dts/content-editor/src/hooks/useValueAutosave.d.ts +64 -0
  221. package/dist/_dts/content-editor/src/hooks/validateBlocksForPublish.d.ts +0 -7
  222. package/dist/_dts/content-editor/src/index.d.ts +26 -7
  223. package/dist/_dts/content-editor/src/lib/browserStorage.d.ts +5 -0
  224. package/dist/_dts/content-editor/src/linkedEntries/domain.d.ts +12 -0
  225. package/dist/_dts/content-editor/src/linkedEntries/owner.d.ts +9 -0
  226. package/dist/_dts/content-editor/src/liveDrafts/draftProjection.d.ts +66 -0
  227. package/dist/_dts/content-editor/src/liveDrafts/linkedSaveHandovers.d.ts +37 -0
  228. package/dist/_dts/content-editor/src/liveDrafts/remoteDraftOverlay.d.ts +113 -0
  229. package/dist/_dts/content-editor/src/liveDrafts/useLiveDrafts.d.ts +32 -0
  230. package/dist/_dts/content-editor/src/liveDrafts/useRetentionTicks.d.ts +7 -0
  231. package/dist/_dts/content-editor/src/primitives/shared/activePreviewField.d.ts +6 -0
  232. package/dist/_dts/content-editor/src/primitives/shared/storeBinding.d.ts +1 -0
  233. package/dist/_dts/content-editor/src/services/contentEntryServices.d.ts +96 -19
  234. package/dist/_dts/content-editor/src/services/editorApiClient.d.ts +13 -0
  235. package/dist/_dts/content-editor/src/services/index.d.ts +2 -0
  236. package/dist/_dts/content-editor/src/services/pageSurfaceEditorServices.d.ts +23 -0
  237. package/dist/_dts/content-editor/src/sync/flushValues.d.ts +13 -0
  238. package/dist/_dts/content-editor/src/sync/lifecycleFailure.d.ts +51 -0
  239. package/dist/_dts/content-editor/src/sync/runLifecycle.d.ts +64 -0
  240. package/dist/_dts/content-editor/src/sync/schedulerValues.d.ts +27 -0
  241. package/dist/_dts/content-editor/src/sync/sendPlanning.d.ts +104 -0
  242. package/dist/_dts/content-editor/src/sync/valueSync.d.ts +114 -0
  243. package/dist/_dts/content-editor/src/ui/blockCollection.d.ts +8 -0
  244. package/dist/_dts/content-editor/src/ui/documentLifecycle.d.ts +18 -0
  245. package/dist/_dts/content-editor/src/ui/editorLeaseUiState.d.ts +7 -0
  246. package/dist/_dts/content-editor/src/ui/editorRefresh.d.ts +82 -0
  247. package/dist/_dts/content-editor/src/ui/editorSnapshot.d.ts +102 -127
  248. package/dist/_dts/content-editor/src/ui/editorTransactionState.d.ts +1 -1
  249. package/dist/_dts/content-editor/src/ui/editorUiStore.d.ts +126 -72
  250. package/dist/_dts/content-editor/src/ui/editorValueSnapshot.d.ts +18 -0
  251. package/dist/_dts/content-editor/src/ui/serverBlockAdmission.d.ts +26 -0
  252. package/dist/_dts/content-editor/src/ui/stores/autosaveStore.d.ts +16 -27
  253. package/dist/_dts/content-editor/src/ui/stores/blockVersionsStore.d.ts +24 -0
  254. package/dist/_dts/content-editor/src/ui/stores/linkedEntryLeaseStore.d.ts +54 -0
  255. package/dist/_dts/content-editor/src/ui/stores/linkedSaveHandoversStore.d.ts +11 -0
  256. package/dist/_dts/content-editor/src/ui/stores/remoteDraftsStore.d.ts +10 -0
  257. package/dist/_dts/content-editor/src/ui/stores/types.d.ts +63 -3
  258. package/dist/_dts/content-editor/src/useFooterComposerState.d.ts +2 -2
  259. package/dist/_dts/content-editor/src/useFooterNavigationLayout.d.ts +1 -1
  260. package/dist/_dts/content-model/src/content-types/builtin-schemas.d.ts +4 -4
  261. package/dist/_dts/content-model/src/content-types/builtins.d.ts +4 -4
  262. package/dist/_dts/content-model/src/definitions/shared.d.ts +11 -2
  263. package/dist/_dts/content-model/src/entry-slots/index.d.ts +1 -0
  264. package/dist/_dts/content-model/src/entry-slots/serializeAllowedBlocks.d.ts +2 -0
  265. package/dist/_dts/content-model/src/metadataConfig.d.ts +10 -38
  266. package/dist/_dts/content-model/src/templates/defaults.d.ts +0 -1
  267. package/dist/_dts/content-model/src/types.d.ts +0 -1
  268. package/dist/_dts/core/src/block-content-identity.d.ts +49 -1
  269. package/dist/_dts/core/src/booking-flexible-balance.d.ts +2 -2
  270. package/dist/_dts/core/src/booking-instalment-deposit.d.ts +20 -0
  271. package/dist/_dts/core/src/booking-live-payment-terms.d.ts +72 -0
  272. package/dist/_dts/core/src/booking-payment-options.d.ts +24 -0
  273. package/dist/_dts/core/src/booking-payment-schemas.d.ts +522 -0
  274. package/dist/_dts/core/src/branded.d.ts +15 -0
  275. package/dist/_dts/core/src/currency-format.d.ts +8 -2
  276. package/dist/_dts/core/src/demo-lifecycle-status.d.ts +2 -2
  277. package/dist/_dts/core/src/demo-warm-pool-target.d.ts +8 -0
  278. package/dist/_dts/core/src/edit-lease.d.ts +60 -0
  279. package/dist/_dts/core/src/editor-state.d.ts +38 -13
  280. package/dist/_dts/core/src/editor-value-sync.d.ts +79 -0
  281. package/dist/_dts/core/src/html-entities.d.ts +6 -0
  282. package/dist/_dts/core/src/index.d.ts +7 -0
  283. package/dist/_dts/core/src/uuid.d.ts +7 -5
  284. package/dist/_dts/db/src/generated/supabase/database.types.d.ts +456 -189
  285. package/dist/_dts/editor/src/EditorProvider.d.ts +5 -0
  286. package/dist/_dts/editor/src/chrome/EditorChrome.d.ts +14 -0
  287. package/dist/_dts/editor/src/chrome/EditorStatusBar.d.ts +1 -0
  288. package/dist/_dts/editor/src/chrome/statusBarPresentation.d.ts +0 -1
  289. package/dist/_dts/editor/src/index.d.ts +1 -1
  290. package/dist/_dts/editor-blocks/src/BlockEditor.d.ts +10 -9
  291. package/dist/_dts/editor-blocks/src/BlockForm.d.ts +1 -1
  292. package/dist/_dts/editor-blocks/src/block-editor/BlockCard.d.ts +1 -1
  293. package/dist/_dts/editor-blocks/src/block-editor/BlockCardFrame.d.ts +1 -1
  294. package/dist/_dts/editor-blocks/src/block-editor/BlockSettingsModal.d.ts +1 -1
  295. package/dist/_dts/editor-blocks/src/block-editor/applyExtendedFieldDefaults.d.ts +3 -4
  296. package/dist/_dts/editor-blocks/src/block-editor/blockDraftBaselineSeed.d.ts +4 -8
  297. package/dist/_dts/editor-blocks/src/block-editor/editorBlockItem.d.ts +23 -0
  298. package/dist/_dts/editor-blocks/src/block-editor/generatedIconApplyCoordination.d.ts +2 -7
  299. package/dist/_dts/editor-blocks/src/block-editor/hooks/applyBlockStructureChange.d.ts +4 -0
  300. package/dist/_dts/editor-blocks/src/block-editor/hooks/buildInsertBlockHistoryCommand.d.ts +14 -5
  301. package/dist/_dts/editor-blocks/src/block-editor/hooks/useBlockBaselineSync.d.ts +21 -19
  302. package/dist/_dts/editor-blocks/src/block-editor/hooks/useBlockCreation.d.ts +2 -10
  303. package/dist/_dts/editor-blocks/src/block-editor/hooks/useBlockDuplication.d.ts +8 -16
  304. package/dist/_dts/editor-blocks/src/block-editor/owner.d.ts +6 -16
  305. package/dist/_dts/editor-blocks/src/block-editor/types.d.ts +37 -9
  306. package/dist/_dts/editor-blocks/src/index.d.ts +2 -1
  307. package/dist/_dts/editor-blocks/src/widgets/entry-picker/loaders.d.ts +1 -1
  308. package/dist/_dts/editor-blocks/src/widgets/link/loaders.d.ts +1 -1
  309. package/dist/_dts/editor-blocks/src/widgets/mailing-list-targeting/loaders.d.ts +1 -1
  310. package/dist/_dts/editor-blocks/src/widgets/reference/loaders.d.ts +1 -1
  311. package/dist/_dts/editor-blocks/src/widgets/site-option-picker/loaders.d.ts +3 -2
  312. package/dist/_dts/media-core/src/fileStorage.d.ts +4 -0
  313. package/dist/_dts/media-editor/src/MediaPickerDialog.d.ts +3 -1
  314. package/dist/_dts/media-editor/src/MediaPickerMiniDialog.d.ts +10 -0
  315. package/dist/_dts/media-editor/src/context.d.ts +1 -1
  316. package/dist/_dts/media-editor/src/createMediaEditorProvider.d.ts +1 -2
  317. package/dist/_dts/media-editor/src/index.d.ts +2 -0
  318. package/dist/_dts/media-editor/src/provider.d.ts +3 -2
  319. package/dist/_dts/media-react/src/hooks/internal/classification.d.ts +1 -1
  320. package/dist/_dts/media-react/src/hooks/useApiMediaUploader.d.ts +3 -1
  321. package/dist/_dts/preview-next/src/client/blocks/composer/mergeDrafts.d.ts +8 -3
  322. package/dist/_dts/preview-next/src/client/blocks/composer/types.d.ts +6 -3
  323. package/dist/_dts/preview-next/src/client/blocks/linkedEntryRenderOverlay.d.ts +22 -2
  324. package/dist/_dts/preview-next/src/client/blocks/previewProjection/entryFieldRebinding.d.ts +13 -0
  325. package/dist/_dts/preview-next/src/client/blocks/previewProjection/index.d.ts +2 -1
  326. package/dist/_dts/preview-next/src/client/blocks/previewProjection/types.d.ts +11 -1
  327. package/dist/_dts/preview-next/src/client/blocks/renderPrecedence.d.ts +17 -0
  328. package/dist/_dts/preview-next/src/client/blocks/useLinkedSaveHandoverRetention.d.ts +20 -0
  329. package/dist/_dts/preview-next/src/client/index.d.ts +1 -1
  330. package/dist/_dts/preview-next/src/client/preview/EntryEditorPanel.d.ts +2 -1
  331. package/dist/_dts/preview-next/src/client/preview/EntrySlotBlockEditorPanel.d.ts +2 -1
  332. package/dist/_dts/preview-next/src/client/preview/PreviewAccessBanners.d.ts +7 -0
  333. package/dist/_dts/preview-next/src/client/preview/PreviewEditorSidebar.d.ts +2 -1
  334. package/dist/_dts/preview-next/src/client/preview/PreviewEntryControllerProvider.d.ts +23 -14
  335. package/dist/_dts/preview-next/src/client/preview/PreviewLeaseEditingMode.d.ts +2 -0
  336. package/dist/_dts/preview-next/src/client/preview/PreviewShell.d.ts +9 -2
  337. package/dist/_dts/preview-next/src/client/preview/PreviewShellLayout.d.ts +1 -0
  338. package/dist/_dts/preview-next/src/client/preview/previewCustomizeAutosave.d.ts +5 -0
  339. package/dist/_dts/preview-next/src/client/preview/previewCustomizeWorkflowState.d.ts +3 -4
  340. package/dist/_dts/preview-next/src/client/preview/sdkConfig.d.ts +1 -0
  341. package/dist/_dts/preview-next/src/client/preview/usePreviewCustomizeWorkflowState.d.ts +4 -0
  342. package/dist/_dts/preview-next/src/client/previewAuthStore.d.ts +7 -0
  343. package/dist/_dts/preview-next/src/constants.d.ts +4 -0
  344. package/dist/_dts/preview-next/src/keepAlive.d.ts +1 -0
  345. package/dist/_dts/realtime/src/client.d.ts +3 -0
  346. package/dist/_dts/realtime/src/draftChannel.d.ts +91 -0
  347. package/dist/_dts/realtime/src/drafts.d.ts +210 -0
  348. package/dist/_dts/realtime/src/index.d.ts +3 -0
  349. package/dist/_dts/realtime/src/leaseChangeSubscriptions.d.ts +8 -0
  350. package/dist/_dts/realtime/src/types.d.ts +113 -0
  351. package/dist/_dts/realtime/src/useDraftChannel.d.ts +34 -0
  352. package/dist/_dts/realtime/src/useSiteRealtimeReload.d.ts +27 -0
  353. package/dist/_dts/sdk/src/public-api/contracts.d.ts +6 -55
  354. package/dist/_dts/sdk/src/rendering/blocks-page-renderer.d.ts +1 -0
  355. package/dist/_dts/sdk/src/rendering/components/pageShared.d.ts +1 -0
  356. package/dist/_dts/sdk/src/rendering/helpers/pageRuntimeSupport.d.ts +2 -0
  357. package/dist/_dts/sdk/src/rendering/islands/types.d.ts +2 -12
  358. package/dist/_dts/sdk/src/version.d.ts +1 -1
  359. package/dist/_dts/surfaces/src/index.d.ts +1 -0
  360. package/dist/_dts/theme-core/src/site-styles/designState.d.ts +2 -2
  361. package/dist/_dts/theme-core/src/site-styles/pageDesignIntent.d.ts +0 -5
  362. package/dist/_dts/ui/src/color-picker.d.ts +1 -1
  363. package/dist/_dts/ui/src/palette/useHexDraft.d.ts +7 -0
  364. package/dist/client/{BookingMailingListNote-1n4Ch_u_.mjs → BookingMailingListNote-Cr3EeTP5.mjs} +504 -163
  365. package/dist/client/DemoBookingPortalAccess-BFGB1Fay.mjs +344 -0
  366. package/dist/client/{EventCombined.client-C0pgma9y.mjs → EventCombined.client-DKYV0_ft.mjs} +6 -6
  367. package/dist/client/{EventListing.client-4fhLOvHP.mjs → EventListing.client-B9UIcEYc.mjs} +2 -2
  368. package/dist/client/{LeafletStaticMap-DScC4F3w.mjs → LeafletStaticMap-CFLPkP0K.mjs} +1 -1
  369. package/dist/client/{TerminalPanel-B5ZUsYhe.mjs → TerminalPanel-JjmgxEsR.mjs} +1 -1
  370. package/dist/client/{ThemedButton-DoVIV1Ao.mjs → ThemedButton-CKV1Jh2m.mjs} +1 -1
  371. package/dist/client/{accordion-CoT5g7zo.mjs → accordion-DXWIfT3T.mjs} +1 -1
  372. package/dist/client/{bookingForm-BWxB46xD.mjs → bookingForm-CjZgHNvv.mjs} +216 -63
  373. package/dist/client/bookings.mjs +1187 -692
  374. package/dist/client/{carousel-DtNYWFd3.mjs → carousel-DSLikmvZ.mjs} +1 -1
  375. package/dist/client/{cart-z4qZih1Y.mjs → cart-HDjWReFt.mjs} +3 -3
  376. package/dist/client/{checkout-DpL7euFH.mjs → checkout-CUvRZA3W.mjs} +3 -3
  377. package/dist/client/{checkoutUrls-BEfR7kVu.mjs → checkoutUrls-CXhko2Rv.mjs} +1 -1
  378. package/dist/client/client.mjs +2711 -1684
  379. package/dist/client/{context-C8TinPJc.mjs → context-DFmaZa-Q.mjs} +4 -3
  380. package/dist/client/{dates-vwwxTeB0.mjs → dates-BBep1JnF.mjs} +56 -11
  381. package/dist/client/{eventCalendar-DIbHfJXO.mjs → eventCalendar-zEobhxo4.mjs} +9 -9
  382. package/dist/client/{eventCombined-DoGMJ6cg.mjs → eventCombined-Dp7bz5k-.mjs} +4 -4
  383. package/dist/client/{eventDetails-BjN9v6a1.mjs → eventDetails-FE-zqTt7.mjs} +4 -4
  384. package/dist/client/{eventListing-DajjWgOv.mjs → eventListing-BMt5snal.mjs} +4 -4
  385. package/dist/client/{eventRegistration-DMq9gMA-.mjs → eventRegistration-O6ZxHfOb.mjs} +422 -570
  386. package/dist/client/{form-Qf6qTbos.mjs → form-DFa1D8vt.mjs} +3 -3
  387. package/dist/client/{headerSection-D7qJrqFX.mjs → headerSection-CmjHLR-N.mjs} +3 -3
  388. package/dist/client/hooks.mjs +414 -182
  389. package/dist/client/{locationMap-CCF9-t_0.mjs → locationMap-BXKP_lGh.mjs} +3 -3
  390. package/dist/client/{media-CwBGetqC.mjs → media-Cl38iOMI.mjs} +10 -3
  391. package/dist/client/{newsletterForm-DzCLSP4S.mjs → newsletterForm-CU-HmxGx.mjs} +3 -3
  392. package/dist/client/{pricing-Cgxv2KLC.mjs → pricing-KEAEsibq.mjs} +1 -1
  393. package/dist/client/{productDetail-ru9w5GHx.mjs → productDetail-Ckp7MGnt.mjs} +3 -3
  394. package/dist/client/{productList-zaapKSl-.mjs → productList-D91V0sYa.mjs} +3 -3
  395. package/dist/client/{propsDecoder-CwvvNOHx.mjs → propsDecoder-DZd6RJeA.mjs} +244 -94
  396. package/dist/client/rendering/client.mjs +2656 -1705
  397. package/dist/client/rendering/islands.mjs +18 -18
  398. package/dist/client/rendering.mjs +3430 -2352
  399. package/dist/client/{routeIslandApiConfig-BwVFo0Y4.mjs → routeIslandApiConfig-E1EkhhYY.mjs} +1 -1
  400. package/dist/client/{shop-mktkXvbV.mjs → shop-4F2jLQPI.mjs} +131 -85
  401. package/dist/client/{shop-commerce-De7gEnkA.mjs → shop-commerce-BbfCJjB3.mjs} +25 -13
  402. package/dist/client/{shop-commerce-store-B3MCxIBW.mjs → shop-commerce-store-vicweP2K.mjs} +1 -1
  403. package/dist/client/{shopShared-TqExh235.mjs → shopShared-DlONJt0T.mjs} +4 -4
  404. package/dist/client/{useEventFilters-n_OjkIjX.mjs → useEventFilters-COYyL3m7.mjs} +32 -17
  405. package/dist/preview-next/before-render.mjs +207 -105
  406. package/dist/preview-next/client/runtime.mjs +4 -4
  407. package/dist/preview-next/constants.mjs +5 -1
  408. package/dist/preview-next/index.mjs +5 -1
  409. package/dist/preview-next/keepAlive.mjs +341 -165
  410. package/dist/preview-next/middleware.mjs +207 -105
  411. package/dist/{previewAuthStore-C_EHQ5XA.mjs → previewAuthStore-BBmV7UsW.mjs} +243 -112
  412. package/dist/{sdk-runtime-BIkJg5y1.mjs → sdk-runtime-CwvFFjB-.mjs} +2 -2
  413. package/dist/{separator-C9qDP95Z.mjs → separator-ByL72zUT.mjs} +1 -1
  414. package/dist/server/components.mjs +1839 -1475
  415. package/dist/server/config-validation.mjs +381 -166
  416. package/dist/server/config.mjs +381 -166
  417. package/dist/server/data.mjs +381 -166
  418. package/dist/server/index.mjs +214 -110
  419. package/dist/server/next.mjs +663 -351
  420. package/dist/server/page-converter.mjs +198 -79
  421. package/dist/server/prebuild.mjs +1 -1
  422. package/dist/server/rendering/server.mjs +1536 -1169
  423. package/dist/server/rendering.mjs +2432 -2068
  424. package/dist/server/routing.mjs +456 -173
  425. package/dist/server/server.mjs +447 -267
  426. package/package.json +1 -1
  427. package/dist/_dts/api/src/bookingPaymentTermSchemas.d.ts +0 -123
  428. package/dist/_dts/billing/src/plans/display.d.ts +0 -15
  429. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.mailing-list-note.d.ts +0 -3
  430. package/dist/_dts/commerce/src/purchase/checkoutPaymentTermPlanning.d.ts +0 -10
  431. package/dist/_dts/commerce/src/purchase/checkoutValidatedItemPlanning.d.ts +0 -55
  432. package/dist/_dts/commerce/src/purchase/orderInstalmentPayoff.d.ts +0 -24
  433. package/dist/_dts/content-editor/src/controller/buildBlockPublishedBaselines.d.ts +0 -4
  434. package/dist/_dts/content-editor/src/controller/buildPublishSuccessTransition.d.ts +0 -16
  435. package/dist/_dts/content-editor/src/controller/driver.d.ts +0 -14
  436. package/dist/_dts/content-editor/src/controller/seedDraftBaselinesFromBlocks.d.ts +0 -7
  437. package/dist/_dts/content-editor/src/controller/useEntrySyncHelpers.d.ts +0 -29
  438. package/dist/_dts/content-editor/src/hooks/autosaveScopePlanning.d.ts +0 -26
  439. package/dist/_dts/content-editor/src/hooks/useSimpleAutosave.d.ts +0 -64
  440. package/dist/_dts/content-editor/src/hooks/useStoreAutosave.d.ts +0 -48
  441. package/dist/_dts/content-editor/src/types.d.ts +0 -44
  442. package/dist/client/DiscountCodeDisclosure-CKJtz0mY.mjs +0 -137
@@ -2539,7 +2539,7 @@ function subtractDaysFromIso(isoString, dayCount) {
2539
2539
  }
2540
2540
  //#endregion
2541
2541
  //#region ../core/src/assert-never.ts
2542
- function assertNever$3(value, message = "Unexpected variant") {
2542
+ function assertNever$4(value, message = "Unexpected variant") {
2543
2543
  throw new Error(`${message}: ${String(value)}`);
2544
2544
  }
2545
2545
  //#endregion
@@ -2563,6 +2563,19 @@ const CURRENCY_LOCALE_BY_CODE = {
2563
2563
  function resolveCurrencyLocale(currencyCode, override) {
2564
2564
  return override ?? CURRENCY_LOCALE_BY_CODE[currencyCode] ?? "en";
2565
2565
  }
2566
+ function fractionDigitsFor(decimals, exactFormatter) {
2567
+ switch (decimals) {
2568
+ case "exact": return {};
2569
+ case "auto": return {
2570
+ minimumFractionDigits: 0,
2571
+ maximumFractionDigits: exactFormatter.resolvedOptions().maximumFractionDigits
2572
+ };
2573
+ case "whole": return {
2574
+ minimumFractionDigits: 0,
2575
+ maximumFractionDigits: 0
2576
+ };
2577
+ }
2578
+ }
2566
2579
  /**
2567
2580
  * The single currency-amount formatter for the product: minor units in,
2568
2581
  * localized string out.
@@ -2573,6 +2586,13 @@ function resolveCurrencyLocale(currencyCode, override) {
2573
2586
  * own `Intl.NumberFormat`.
2574
2587
  */
2575
2588
  function formatCurrencyAmount(amountCents, currency, options) {
2589
+ return formatCurrencyMajorUnits(amountCents / 100, currency, options);
2590
+ }
2591
+ /**
2592
+ * `formatCurrencyAmount` for an amount already in MAJOR units (29.99 = £29.99),
2593
+ * such as a registrar price. Prefer minor units everywhere else.
2594
+ */
2595
+ function formatCurrencyMajorUnits(amount, currency, options) {
2576
2596
  const currencyCode = currency.toUpperCase();
2577
2597
  const locale = resolveCurrencyLocale(currencyCode, options?.locale);
2578
2598
  try {
@@ -2580,17 +2600,13 @@ function formatCurrencyAmount(amountCents, currency, options) {
2580
2600
  style: "currency",
2581
2601
  currency: currencyCode
2582
2602
  });
2583
- const fractionDigits = options?.decimals === "auto" ? {
2584
- minimumFractionDigits: 0,
2585
- maximumFractionDigits: exactFormatter.resolvedOptions().maximumFractionDigits
2586
- } : {};
2587
2603
  return new Intl.NumberFormat(locale, {
2588
2604
  style: "currency",
2589
2605
  currency: currencyCode,
2590
- ...fractionDigits
2591
- }).format(amountCents / 100);
2606
+ ...fractionDigitsFor(options?.decimals ?? "exact", exactFormatter)
2607
+ }).format(amount);
2592
2608
  } catch {
2593
- return `${(amountCents / 100).toFixed(2)} ${currencyCode}`;
2609
+ return `${amount.toFixed(2)} ${currencyCode}`;
2594
2610
  }
2595
2611
  }
2596
2612
  //#endregion
@@ -2616,7 +2632,7 @@ function isPublicEventPricingOptionDisplayable(option) {
2616
2632
  case "not_on_sale_yet":
2617
2633
  case "sale_ended":
2618
2634
  case "attendance_mode_unavailable": return false;
2619
- default: return assertNever$3(reason);
2635
+ default: return assertNever$4(reason);
2620
2636
  }
2621
2637
  }
2622
2638
  function publicEventPricingDisplay(pricing) {
@@ -2737,7 +2753,7 @@ function canonicalEventPricingDisplay(pricing) {
2737
2753
  currency: pricing.currency,
2738
2754
  purpose: "configured"
2739
2755
  });
2740
- default: return assertNever$3(pricing);
2756
+ default: return assertNever$4(pricing);
2741
2757
  }
2742
2758
  }
2743
2759
  //#endregion
@@ -2786,7 +2802,7 @@ function parseEventPageSurfaceDestinationMode(value) {
2786
2802
  return value === "cms-managed" || value === "system-managed" ? value : void 0;
2787
2803
  }
2788
2804
  function parseEventPageSurfaceSubject(value) {
2789
- if (!isRecord$7(value)) return err$1({ kind: "notObject" });
2805
+ if (!isRecord$9(value)) return err$1({ kind: "notObject" });
2790
2806
  switch (value.kind) {
2791
2807
  case "eventSeries": {
2792
2808
  const eventSeriesId = parseEventSeriesId(value.eventSeriesId);
@@ -2841,7 +2857,7 @@ function parseEventSeriesIdList(values) {
2841
2857
  }
2842
2858
  return ok$1(parsed);
2843
2859
  }
2844
- function isRecord$7(value) {
2860
+ function isRecord$9(value) {
2845
2861
  return typeof value === "object" && value !== null && !Array.isArray(value);
2846
2862
  }
2847
2863
  //#endregion
@@ -2868,10 +2884,10 @@ function resolveFlexibleBalanceDueAt(input) {
2868
2884
  switch (input.dueDateRule.kind) {
2869
2885
  case "relative_to_start_date": return subtractDaysFromIso(input.bookingStartAt, input.dueDateRule.daysBeforeStart);
2870
2886
  case "fixed_calendar_date": return input.dueDateRule.dueAt;
2871
- default: return assertNever$2(input.dueDateRule);
2887
+ default: return assertNever$3(input.dueDateRule);
2872
2888
  }
2873
2889
  }
2874
- function assertNever$2(value) {
2890
+ function assertNever$3(value) {
2875
2891
  throw new Error(`Unexpected value: ${String(value)}`);
2876
2892
  }
2877
2893
  //#endregion
@@ -2881,7 +2897,7 @@ function isDepositBearingBookingInstalmentPlan(plan) {
2881
2897
  case "deposit_plus_one_remainder":
2882
2898
  case "deposit_plus_scheduled_instalments": return true;
2883
2899
  case "equal_scheduled_instalments": return false;
2884
- default: return assertNever$1(plan);
2900
+ default: return assertNever$2(plan);
2885
2901
  }
2886
2902
  }
2887
2903
  function getBookingInstalmentDepositRefundability(plan) {
@@ -2907,7 +2923,7 @@ function addIntervalPreservingMonthAnchor(isoString, intervalCount, intervalUnit
2907
2923
  date.setUTCDate(date.getUTCDate() + intervalCount * 7);
2908
2924
  return date.toISOString();
2909
2925
  case "month": return addMonthsPreservingAnchorDay(date, intervalCount).toISOString();
2910
- default: return assertNever$1(intervalUnit);
2926
+ default: return assertNever$2(intervalUnit);
2911
2927
  }
2912
2928
  }
2913
2929
  function getBookingInstalmentPlanIntervalCount(plan) {
@@ -2915,7 +2931,7 @@ function getBookingInstalmentPlanIntervalCount(plan) {
2915
2931
  case "deposit_plus_one_remainder": return plan.remainderDueCount;
2916
2932
  case "deposit_plus_scheduled_instalments":
2917
2933
  case "equal_scheduled_instalments": return plan.intervalCount;
2918
- default: return assertNever$1(plan);
2934
+ default: return assertNever$2(plan);
2919
2935
  }
2920
2936
  }
2921
2937
  function omitZeroAmountFutureRows(rows) {
@@ -2931,10 +2947,20 @@ function addMonthsPreservingAnchorDay(date, intervalCount) {
2931
2947
  nextMonth.setUTCDate(Math.min(anchorDay, lastDayOfTargetMonth));
2932
2948
  return nextMonth;
2933
2949
  }
2934
- function assertNever$1(value) {
2950
+ function assertNever$2(value) {
2935
2951
  throw new Error(`Unexpected value: ${String(value)}`);
2936
2952
  }
2937
2953
  //#endregion
2954
+ //#region ../core/src/booking-payment-options.ts
2955
+ /** Automatic instalments and a flexible balance cannot share one booking offer. */
2956
+ function validateBookingPaymentOptionKinds(kinds) {
2957
+ if (kinds.length === 0) return err$1("no_options");
2958
+ const uniqueKinds = new Set(kinds);
2959
+ if (uniqueKinds.size !== kinds.length) return err$1("duplicate_kind");
2960
+ if (uniqueKinds.has("instalment_plan") && uniqueKinds.has("flexible_balance")) return err$1("incompatible_collection_options");
2961
+ return ok$1(void 0);
2962
+ }
2963
+ //#endregion
2938
2964
  //#region ../core/src/booking-time-zone.ts
2939
2965
  const TIME_ZONE_VALIDITY_CACHE_LIMIT = 100;
2940
2966
  const timeZoneValidityCache = /* @__PURE__ */ new Map();
@@ -3168,6 +3194,16 @@ function resolveBookingSignupOffer(context, siteName) {
3168
3194
  const name = siteName?.trim() ?? "";
3169
3195
  return context?.tag === "configured" && context.bookingSignup.tag === "offered" ? { siteName: name.length > 0 ? name : "this site" } : null;
3170
3196
  }
3197
+ //#endregion
3198
+ //#region ../core/src/uuid.ts
3199
+ function generateUuidV4(cryptoSource = globalThis.crypto) {
3200
+ if (typeof cryptoSource.randomUUID === "function") return cryptoSource.randomUUID();
3201
+ const bytes = cryptoSource.getRandomValues(/* @__PURE__ */ new Uint8Array(16));
3202
+ bytes[6] = (bytes[6] ?? 0) & 15 | 64;
3203
+ bytes[8] = (bytes[8] ?? 0) & 63 | 128;
3204
+ const hex = Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0"));
3205
+ return `${hex.slice(0, 4).join("")}-${hex.slice(4, 6).join("")}-${hex.slice(6, 8).join("")}-${hex.slice(8, 10).join("")}-${hex.slice(10).join("")}`;
3206
+ }
3171
3207
  function sessionStartMs(session) {
3172
3208
  return Date.parse(session.startsAt);
3173
3209
  }
@@ -7023,7 +7059,7 @@ const boxBackgroundSchema = z.discriminatedUnion("type", [
7023
7059
  })
7024
7060
  ]);
7025
7061
  function normalizeAuthoringOpacity(value) {
7026
- if (!isRecord$6(value)) return value;
7062
+ if (!isRecord$8(value)) return value;
7027
7063
  return {
7028
7064
  ...value,
7029
7065
  opacity: normalizeOpacity(value.opacity)
@@ -7032,7 +7068,7 @@ function normalizeAuthoringOpacity(value) {
7032
7068
  function normalizeOpacity(value) {
7033
7069
  return typeof value === "number" && value > 1 && value <= 100 ? value / 100 : value;
7034
7070
  }
7035
- function isRecord$6(value) {
7071
+ function isRecord$8(value) {
7036
7072
  return typeof value === "object" && value !== null && !Array.isArray(value);
7037
7073
  }
7038
7074
  //#endregion
@@ -7833,68 +7869,115 @@ const RichTextDocSchema = z.object({
7833
7869
  content: z.array(TipTapNodeSchema)
7834
7870
  }).strict();
7835
7871
  //#endregion
7836
- //#region ../blocks/src/system/blocks/shared/bookingPaymentTerms.ts
7837
- const bookingDepositRefundPolicySchema = z.enum(["refundable", "non_refundable"]);
7838
- const bookingInstalmentPlanSchema = z.union([
7839
- z.object({
7840
- kind: z.literal("deposit_plus_one_remainder"),
7841
- depositAmountCents: z.number().int().min(0),
7842
- depositRefundability: bookingDepositRefundPolicySchema,
7843
- remainderDueCount: z.number().int().positive(),
7844
- intervalUnit: z.enum([
7845
- "day",
7846
- "week",
7847
- "month"
7848
- ])
7849
- }),
7850
- z.object({
7851
- kind: z.literal("deposit_plus_scheduled_instalments"),
7852
- depositAmountCents: z.number().int().min(0),
7853
- depositRefundability: bookingDepositRefundPolicySchema,
7854
- instalmentCount: z.number().int().positive(),
7855
- intervalCount: z.number().int().positive(),
7856
- intervalUnit: z.enum([
7857
- "day",
7858
- "week",
7859
- "month"
7860
- ])
7861
- }),
7862
- z.object({
7863
- kind: z.literal("equal_scheduled_instalments"),
7864
- instalmentCount: z.number().int().positive(),
7865
- intervalCount: z.number().int().positive(),
7866
- intervalUnit: z.enum([
7867
- "day",
7868
- "week",
7869
- "month"
7870
- ])
7871
- })
7872
- ]);
7873
- const bookingFlexibleBalanceDueDateRuleSchema = z.union([z.object({
7874
- kind: z.literal("relative_to_start_date"),
7875
- daysBeforeStart: z.number().int().positive()
7876
- }), z.object({
7877
- kind: z.literal("fixed_calendar_date"),
7878
- dueAt: z.string().datetime()
7879
- })]);
7880
- const bookingFlexibleBalanceConfigSchema = z.object({
7881
- upfrontAmountCents: z.number().int().min(0),
7882
- dueDateRule: bookingFlexibleBalanceDueDateRuleSchema,
7883
- depositRefundability: bookingDepositRefundPolicySchema
7884
- });
7885
- const blockBookingPaymentCollectionOptionSchema = z.union([
7886
- z.object({ kind: z.literal("upfront") }),
7887
- z.object({ kind: z.literal("deferred_manual") }),
7888
- z.object({
7889
- kind: z.literal("instalment_plan"),
7890
- plan: bookingInstalmentPlanSchema
7891
- }),
7892
- z.object({
7893
- kind: z.literal("flexible_balance"),
7894
- config: bookingFlexibleBalanceConfigSchema
7895
- })
7872
+ //#region ../core/src/booking-payment-schemas.ts
7873
+ const stripObject = (shape) => z.object(shape);
7874
+ const strictObject = (shape) => z.strictObject(shape);
7875
+ const depositRefundPolicySchema = z.enum(["refundable", "non_refundable"]);
7876
+ const intervalUnitSchema = z.enum([
7877
+ "day",
7878
+ "week",
7879
+ "month"
7896
7880
  ]);
7897
- const blockBookingPaymentTermsSchema = z.object({ allowedOptions: z.array(blockBookingPaymentCollectionOptionSchema).min(1) });
7881
+ const nonNegativeIntegerSchema = z.number().int().nonnegative();
7882
+ const positiveIntegerSchema = z.number().int().positive();
7883
+ function createInstalmentPlanSchema(object) {
7884
+ return z.discriminatedUnion("kind", [
7885
+ object({
7886
+ kind: z.literal("deposit_plus_one_remainder"),
7887
+ depositAmountCents: nonNegativeIntegerSchema,
7888
+ depositRefundability: depositRefundPolicySchema,
7889
+ remainderDueCount: positiveIntegerSchema,
7890
+ intervalUnit: intervalUnitSchema
7891
+ }),
7892
+ object({
7893
+ kind: z.literal("deposit_plus_scheduled_instalments"),
7894
+ depositAmountCents: nonNegativeIntegerSchema,
7895
+ depositRefundability: depositRefundPolicySchema,
7896
+ instalmentCount: positiveIntegerSchema,
7897
+ intervalCount: positiveIntegerSchema,
7898
+ intervalUnit: intervalUnitSchema
7899
+ }),
7900
+ object({
7901
+ kind: z.literal("equal_scheduled_instalments"),
7902
+ instalmentCount: positiveIntegerSchema,
7903
+ intervalCount: positiveIntegerSchema,
7904
+ intervalUnit: intervalUnitSchema
7905
+ })
7906
+ ]);
7907
+ }
7908
+ function createFlexibleBalanceSchemas(object) {
7909
+ const dueDateRule = z.discriminatedUnion("kind", [object({
7910
+ kind: z.literal("relative_to_start_date"),
7911
+ daysBeforeStart: positiveIntegerSchema
7912
+ }), object({
7913
+ kind: z.literal("fixed_calendar_date"),
7914
+ dueAt: z.string().datetime()
7915
+ })]);
7916
+ return {
7917
+ dueDateRule,
7918
+ config: object({
7919
+ upfrontAmountCents: nonNegativeIntegerSchema,
7920
+ dueDateRule,
7921
+ depositRefundability: depositRefundPolicySchema
7922
+ })
7923
+ };
7924
+ }
7925
+ const paymentOptionKindsMessages = {
7926
+ no_options: "Choose at least one way for customers to pay.",
7927
+ duplicate_kind: "Choose each payment option only once.",
7928
+ incompatible_collection_options: "Offer instalments or a deposit with the rest paid later, but not both."
7929
+ };
7930
+ function buildBookingPaymentOptionSchemas(object) {
7931
+ const instalmentPlan = createInstalmentPlanSchema(object);
7932
+ const flexibleBalance = createFlexibleBalanceSchemas(object);
7933
+ const paymentCollectionOption = z.discriminatedUnion("kind", [
7934
+ object({ kind: z.literal("upfront") }),
7935
+ object({ kind: z.literal("deferred_manual") }),
7936
+ object({
7937
+ kind: z.literal("instalment_plan"),
7938
+ plan: instalmentPlan
7939
+ }),
7940
+ object({
7941
+ kind: z.literal("flexible_balance"),
7942
+ config: flexibleBalance.config
7943
+ })
7944
+ ]);
7945
+ const paymentTerms = object({ allowedOptions: z.array(paymentCollectionOption) }).superRefine(({ allowedOptions }, ctx) => {
7946
+ const result = validateBookingPaymentOptionKinds(allowedOptions.map(({ kind }) => kind));
7947
+ if (!result.ok) ctx.addIssue({
7948
+ code: "custom",
7949
+ path: ["allowedOptions"],
7950
+ message: paymentOptionKindsMessages[result.error]
7951
+ });
7952
+ });
7953
+ const paymentOptionsChoice = z.discriminatedUnion("source", [z.strictObject({ source: z.literal("default") }), z.strictObject({
7954
+ source: z.literal("custom"),
7955
+ paymentTerms
7956
+ })]);
7957
+ return {
7958
+ depositRefundPolicy: depositRefundPolicySchema,
7959
+ instalmentPlan,
7960
+ flexibleBalanceDueDateRule: flexibleBalance.dueDateRule,
7961
+ flexibleBalanceConfig: flexibleBalance.config,
7962
+ paymentCollectionOption,
7963
+ paymentTerms,
7964
+ paymentOptionsChoice
7965
+ };
7966
+ }
7967
+ function createBookingPaymentOptionSchemas(mode) {
7968
+ return mode === "strict" ? buildBookingPaymentOptionSchemas(strictObject) : buildBookingPaymentOptionSchemas(stripObject);
7969
+ }
7970
+ const bookingPaymentOptionSchemas = createBookingPaymentOptionSchemas("strip");
7971
+ bookingPaymentOptionSchemas.depositRefundPolicy;
7972
+ bookingPaymentOptionSchemas.instalmentPlan;
7973
+ bookingPaymentOptionSchemas.flexibleBalanceDueDateRule;
7974
+ bookingPaymentOptionSchemas.flexibleBalanceConfig;
7975
+ bookingPaymentOptionSchemas.paymentCollectionOption;
7976
+ const bookingPaymentTermsSchema = bookingPaymentOptionSchemas.paymentTerms;
7977
+ bookingPaymentOptionSchemas.paymentOptionsChoice;
7978
+ //#endregion
7979
+ //#region ../blocks/src/system/blocks/shared/bookingPaymentTerms.ts
7980
+ const blockBookingPaymentTermsSchema = bookingPaymentTermsSchema;
7898
7981
  //#endregion
7899
7982
  //#region ../blocks/src/system/blocks/shared/bookingConsent.ts
7900
7983
  const BOOKING_REQUIREMENT_CONSENT_FIELD_PREFIX = "booking_requirement_consent_";
@@ -8156,7 +8239,6 @@ const publicEventBaseSchema = z.object({
8156
8239
  description: z.string().nullable(),
8157
8240
  content: z.object({ body: RichTextDocSchema.nullable().optional() }).optional(),
8158
8241
  presentation: z.object({
8159
- cardTitleOverride: z.string().nullable().optional(),
8160
8242
  summary: z.string().nullable().optional(),
8161
8243
  image: mediaSchema.nullable().optional()
8162
8244
  }).optional(),
@@ -8189,6 +8271,7 @@ const publicEventBaseSchema = z.object({
8189
8271
  "archived"
8190
8272
  ]).optional(),
8191
8273
  timeZone: z.string(),
8274
+ siteTimeZone: z.string().optional(),
8192
8275
  pricing: publicEventPricingSchema,
8193
8276
  paymentTerms: blockBookingPaymentTermsSchema,
8194
8277
  cancellationPolicy: z.object({ refunds: z.object({
@@ -8716,7 +8799,7 @@ var BlockApiError = class extends Error {
8716
8799
  this.name = "BlockApiError";
8717
8800
  }
8718
8801
  };
8719
- function isRecord$5(value) {
8802
+ function isRecord$7(value) {
8720
8803
  return typeof value === "object" && value !== null;
8721
8804
  }
8722
8805
  function isJsonResponseContentType(contentType) {
@@ -8740,15 +8823,15 @@ async function parseJsonBody(response) {
8740
8823
  }
8741
8824
  }
8742
8825
  function isFieldError(value) {
8743
- return isRecord$5(value) && !Array.isArray(value) && typeof value.field === "string" && typeof value.code === "string" && typeof value.message === "string";
8826
+ return isRecord$7(value) && !Array.isArray(value) && typeof value.field === "string" && typeof value.code === "string" && typeof value.message === "string";
8744
8827
  }
8745
8828
  function fieldErrorsFromUnknown(value) {
8746
8829
  if (!Array.isArray(value)) return void 0;
8747
8830
  return value.every(isFieldError) ? value : void 0;
8748
8831
  }
8749
8832
  function getBlockApiErrorDetails(data) {
8750
- if (!isRecord$5(data)) return {};
8751
- const nestedError = isRecord$5(data.error) ? data.error : void 0;
8833
+ if (!isRecord$7(data)) return {};
8834
+ const nestedError = isRecord$7(data.error) ? data.error : void 0;
8752
8835
  const message = typeof nestedError?.message === "string" ? nestedError.message : typeof data.message === "string" ? data.message : void 0;
8753
8836
  const code = typeof nestedError?.code === "string" ? nestedError.code : typeof data.code === "string" ? data.code : void 0;
8754
8837
  const fieldErrors = fieldErrorsFromUnknown(nestedError?.fieldErrors) ?? fieldErrorsFromUnknown(data.fieldErrors);
@@ -9317,10 +9400,11 @@ function createBlockApi(config) {
9317
9400
  },
9318
9401
  async sendMagicLink(data) {
9319
9402
  const sid = requireSiteId();
9320
- await request(PORTAL.sendMagicLink, { body: {
9403
+ return request(PORTAL.sendMagicLink, { body: {
9321
9404
  siteId: sid,
9322
9405
  email: data.email,
9323
- redirectUrl: data.redirectUrl
9406
+ redirectUrl: data.redirectUrl,
9407
+ demoBookingPass: data.demoBookingPass
9324
9408
  } });
9325
9409
  },
9326
9410
  async logout() {
@@ -9465,7 +9549,7 @@ function err(error) {
9465
9549
  error
9466
9550
  };
9467
9551
  }
9468
- function assertNever(value, message) {
9552
+ function assertNever$1(value, message) {
9469
9553
  throw new Error(message ?? `Unexpected value: ${String(value)}`);
9470
9554
  }
9471
9555
  //#endregion
@@ -9543,7 +9627,7 @@ function resolveAppointmentCheckoutVerificationState(input) {
9543
9627
  tag: "timeout",
9544
9628
  sessionId: input.config.sessionId,
9545
9629
  appointmentId,
9546
- message: "Could not verify your appointment payment. If you were charged, please contact support."
9630
+ message: "We’re still confirming your payment. This can take a minute – you can check again, and you won’t be charged twice."
9547
9631
  };
9548
9632
  if (input.pollingStatus === "failed") {
9549
9633
  if (paymentStatus === "refunded") return {
@@ -9607,26 +9691,26 @@ function deriveBookingFormViewState(input) {
9607
9691
  message: input.verificationState.message
9608
9692
  };
9609
9693
  case "timeout": return {
9610
- kind: "error",
9694
+ kind: "timeout",
9611
9695
  message: input.verificationState.message
9612
9696
  };
9613
9697
  case "confirmed": return {
9614
9698
  kind: "success",
9615
9699
  resourceName: input.verificationState.resourceName
9616
9700
  };
9617
- default: return assertNever(input.verificationState);
9701
+ default: return assertNever$1(input.verificationState);
9618
9702
  }
9619
9703
  }
9620
9704
  function resolveBookingSiteId(siteId, form) {
9621
9705
  return siteId || form?.siteId || "";
9622
9706
  }
9623
9707
  function normalizeBookingFormConfig(form) {
9624
- if (!isRecord$4(form)) return null;
9708
+ if (!isRecord$6(form)) return null;
9625
9709
  const id = readNonEmptyString(form.id);
9626
9710
  const name = readNonEmptyString(form.name);
9627
9711
  if (!id || !name) return null;
9628
- const schemaSource = isRecord$4(form.schema) ? form.schema : isRecord$4(form.schemaJson) ? form.schemaJson : null;
9629
- const settingsSource = isRecord$4(form.settings) ? form.settings : isRecord$4(form.settingsJson) ? form.settingsJson : null;
9712
+ const schemaSource = isRecord$6(form.schema) ? form.schema : isRecord$6(form.schemaJson) ? form.schemaJson : null;
9713
+ const settingsSource = isRecord$6(form.settings) ? form.settings : isRecord$6(form.settingsJson) ? form.settingsJson : null;
9630
9714
  return {
9631
9715
  id,
9632
9716
  name,
@@ -9646,8 +9730,8 @@ function normalizeBookingServices(services) {
9646
9730
  };
9647
9731
  if (!services) return [];
9648
9732
  if (Array.isArray(services)) return services.filter(isBookingFormService).map(normalizeService);
9649
- if (isRecord$4(services) && "services" in services) return Array.isArray(services.services) ? services.services.filter(isBookingFormService).map(normalizeService) : [];
9650
- return isRecord$4(services) ? Object.values(services).filter(isBookingFormService).map(normalizeService) : [];
9733
+ if (isRecord$6(services) && "services" in services) return Array.isArray(services.services) ? services.services.filter(isBookingFormService).map(normalizeService) : [];
9734
+ return isRecord$6(services) ? Object.values(services).filter(isBookingFormService).map(normalizeService) : [];
9651
9735
  }
9652
9736
  function normalizeBookingSchema(value) {
9653
9737
  if (!value) return void 0;
@@ -9658,7 +9742,7 @@ function normalizeBookingSchema(value) {
9658
9742
  };
9659
9743
  }
9660
9744
  function readBookingFormField(value) {
9661
- if (!isRecord$4(value)) return null;
9745
+ if (!isRecord$6(value)) return null;
9662
9746
  const id = readNonEmptyString(value.id);
9663
9747
  const label = readNonEmptyString(value.label);
9664
9748
  const type = readBookingFieldType(value.type);
@@ -9701,7 +9785,7 @@ function readBookingFieldOptions(value) {
9701
9785
  return options.length > 0 ? options : void 0;
9702
9786
  }
9703
9787
  function readBookingFieldOption(value) {
9704
- if (!isRecord$4(value)) return null;
9788
+ if (!isRecord$6(value)) return null;
9705
9789
  const optionValue = readNonEmptyString(value.value);
9706
9790
  const label = readNonEmptyString(value.label);
9707
9791
  return optionValue && label ? {
@@ -9721,7 +9805,7 @@ function normalizeBookingSettings(value) {
9721
9805
  };
9722
9806
  }
9723
9807
  function isBookingFormService(value) {
9724
- return isRecord$4(value) && typeof value.id === "string" && typeof value.siteId === "string" && typeof value.title === "string" && (value.consent === void 0 || blockBookingConsentSchema.safeParse(value.consent).success);
9808
+ return isRecord$6(value) && typeof value.id === "string" && typeof value.siteId === "string" && typeof value.title === "string" && (value.consent === void 0 || blockBookingConsentSchema.safeParse(value.consent).success);
9725
9809
  }
9726
9810
  function collectBookingCustomFields(data) {
9727
9811
  const customFields = {};
@@ -9771,26 +9855,24 @@ function readStringArray(value) {
9771
9855
  const strings = value.filter((item) => typeof item === "string");
9772
9856
  return strings.length > 0 ? strings : void 0;
9773
9857
  }
9774
- function isRecord$4(value) {
9858
+ function isRecord$6(value) {
9775
9859
  return typeof value === "object" && value !== null;
9776
9860
  }
9777
9861
  function getBookingServicePaymentSelectionMode(service) {
9778
9862
  if (service?.paymentTermsAvailability?.kind === "pending_stripe_setup") return "pending_stripe_setup";
9779
9863
  const allowedKinds = service?.paymentTerms?.allowedOptions.map((option) => option.kind) ?? [];
9780
9864
  if (allowedKinds.length === 0) return "implicit_upfront";
9781
- if (allowedKinds.length === 1) {
9782
- const onlyKind = allowedKinds[0];
9783
- if (!onlyKind) return "unsupported";
9784
- switch (onlyKind) {
9785
- case "upfront": return "implicit_upfront";
9786
- case "deferred_manual": return "implicit_deferred_manual";
9787
- case "instalment_plan": return "implicit_instalment_plan";
9788
- case "flexible_balance": return "implicit_flexible_balance";
9789
- default: return assertNever(onlyKind);
9790
- }
9865
+ if (!validateBookingPaymentOptionKinds(allowedKinds).ok) return "unsupported";
9866
+ if (allowedKinds.length > 1) return "choice_required";
9867
+ const onlyKind = allowedKinds[0];
9868
+ switch (onlyKind) {
9869
+ case "upfront": return "implicit_upfront";
9870
+ case "deferred_manual": return "implicit_deferred_manual";
9871
+ case "instalment_plan": return "implicit_instalment_plan";
9872
+ case "flexible_balance": return "implicit_flexible_balance";
9873
+ case void 0: return "unsupported";
9874
+ default: return assertNever$1(onlyKind);
9791
9875
  }
9792
- if (allowedKinds.length === 2 && allowedKinds.includes("upfront") && (allowedKinds.includes("deferred_manual") || allowedKinds.includes("instalment_plan") || allowedKinds.includes("flexible_balance"))) return "choice_required";
9793
- return "unsupported";
9794
9876
  }
9795
9877
  function resolveDefaultBookingServiceId(formConfig, services) {
9796
9878
  const configuredServiceId = toTrimmedString(formConfig?.settings?.serviceId);
@@ -9962,11 +10044,43 @@ function formatBookingSubmissionPreparationError(error) {
9962
10044
  case "sliding-amount-out-of-range": return `Please choose an amount within the sliding scale for "${error.serviceTitle}".`;
9963
10045
  case "payment-option-unsupported": return `Service "${error.serviceTitle}" has a payment option that is not supported yet.`;
9964
10046
  case "service-missing-duration": return `Service "${error.serviceTitle}" is missing duration. Please update the service in the dashboard to include a duration (e.g., 30 minutes).`;
9965
- default: return assertNever(error);
10047
+ default: return assertNever$1(error);
10048
+ }
10049
+ }
10050
+ const DEFAULT_BOOKING_SUCCESS_COPY = {
10051
+ message: "Your booking has been confirmed.",
10052
+ defaultEmailSentence: "Check your email for details."
10053
+ };
10054
+ const DEFAULT_BOOKING_SUCCESS_MESSAGE = "Your booking has been confirmed. Check your email for details.";
10055
+ function getBookingSuccessCopy(successMessage) {
10056
+ const customMessage = successMessage?.trim();
10057
+ return customMessage && customMessage !== DEFAULT_BOOKING_SUCCESS_MESSAGE ? { message: customMessage } : DEFAULT_BOOKING_SUCCESS_COPY;
10058
+ }
10059
+ //#endregion
10060
+ //#region ../blocks/src/system/runtime/nodes/booking-form.payment-confirmation.ts
10061
+ function bookingServiceRequiresPaymentBeforeBooking(input) {
10062
+ switch (getBookingServicePaymentSelectionMode(input.service)) {
10063
+ case "implicit_upfront":
10064
+ case "implicit_instalment_plan":
10065
+ case "implicit_flexible_balance": return true;
10066
+ case "choice_required": return input.selectedCollectionOptionKind !== void 0 && input.selectedCollectionOptionKind !== "deferred_manual";
10067
+ case "implicit_deferred_manual":
10068
+ case "pending_stripe_setup":
10069
+ case "unsupported": return false;
9966
10070
  }
9967
10071
  }
9968
- function getBookingSuccessMessage(successMessage) {
9969
- return successMessage?.trim() || "Your appointment has been booked! Check your email for confirmation.";
10072
+ function resolveBookingPaymentConfirmationSummary(input) {
10073
+ const service = input.service;
10074
+ if (!service || input.hasSelectedAppointmentPackage || !Number.isFinite(input.priceAmount) || input.priceAmount <= 0 || !service.durationMinutes || !bookingServiceRequiresPaymentBeforeBooking({
10075
+ service,
10076
+ selectedCollectionOptionKind: input.selectedCollectionOptionKind
10077
+ })) return null;
10078
+ return {
10079
+ serviceTitle: service.title,
10080
+ durationMinutes: service.durationMinutes,
10081
+ priceAmount: input.priceAmount,
10082
+ priceCurrency: service.priceCurrency ?? service.pricing?.currency ?? "USD"
10083
+ };
9970
10084
  }
9971
10085
  //#endregion
9972
10086
  //#region ../blocks/src/system/runtime/hooks/useSelectedAppointmentConsentForm.ts
@@ -10183,7 +10297,7 @@ function availableDatesReducer(state, action) {
10183
10297
  data: state.data,
10184
10298
  message: action.message
10185
10299
  };
10186
- default: return assertNever(action);
10300
+ default: return assertNever$1(action);
10187
10301
  }
10188
10302
  }
10189
10303
  //#endregion
@@ -10320,7 +10434,7 @@ function getAvailableSlots(state) {
10320
10434
  case "loaded":
10321
10435
  case "refreshing":
10322
10436
  case "error": return state.slots;
10323
- default: return assertNever(state);
10437
+ default: return assertNever$1(state);
10324
10438
  }
10325
10439
  }
10326
10440
  function hasLoadedAvailableSlots(state) {
@@ -10330,7 +10444,7 @@ function hasLoadedAvailableSlots(state) {
10330
10444
  case "refreshing":
10331
10445
  case "error": return state.hasLoaded;
10332
10446
  case "loaded": return true;
10333
- default: return assertNever(state);
10447
+ default: return assertNever$1(state);
10334
10448
  }
10335
10449
  }
10336
10450
  function isLoadingAvailableSlots(state) {
@@ -10364,7 +10478,7 @@ function availableSlotsReducer(state, action) {
10364
10478
  hasLoaded: hasLoadedAvailableSlots(state),
10365
10479
  message: action.message
10366
10480
  };
10367
- default: return assertNever(action);
10481
+ default: return assertNever$1(action);
10368
10482
  }
10369
10483
  }
10370
10484
  //#endregion
@@ -10459,6 +10573,19 @@ function useAvailableSlots({ siteId: _siteId, serviceId, resourceId, selectedDat
10459
10573
  };
10460
10574
  }
10461
10575
  //#endregion
10576
+ //#region ../blocks/src/system/runtime/hooks/useBookingNowIso.ts
10577
+ /**
10578
+ * The moment a booking or registration flow opened, as an ISO timestamp.
10579
+ *
10580
+ * Payment previews take this as their "now" so the pure view-model builders
10581
+ * never read the clock themselves. It's captured once per mount, which keeps
10582
+ * memoised previews stable across renders.
10583
+ */
10584
+ function useBookingNowIso() {
10585
+ const [nowIso] = useState(() => (/* @__PURE__ */ new Date()).toISOString());
10586
+ return nowIso;
10587
+ }
10588
+ //#endregion
10462
10589
  //#region ../blocks/src/system/runtime/hooks/useBookingSubmission.state.ts
10463
10590
  const initialBookingSubmissionState = {
10464
10591
  status: { tag: "idle" },
@@ -10480,13 +10607,61 @@ function bookingSubmissionReducer(state, action) {
10480
10607
  feedback: reportWorkflowError(state, action.message).feedback
10481
10608
  };
10482
10609
  case "feedback-cleared": return clearWorkflowFeedback(state);
10483
- default: return assertNever(action);
10610
+ default: return assertNever$1(action);
10484
10611
  }
10485
10612
  }
10486
10613
  function selectIsSubmitting(state) {
10487
10614
  return state.status.tag === "submitting";
10488
10615
  }
10489
10616
  //#endregion
10617
+ //#region ../blocks/src/system/runtime/shared/utils/demoBookingPassStorage.ts
10618
+ const STORAGE_KEY = "riverbank:demo-booking-passes:v1";
10619
+ const MAX_STORED_PASSES = 10;
10620
+ function normalizeDemoBookingEmail(email) {
10621
+ return email.trim().toLowerCase();
10622
+ }
10623
+ function storeDemoBookingPass(email, pass) {
10624
+ try {
10625
+ const normalizedEmail = normalizeDemoBookingEmail(email);
10626
+ if (!normalizedEmail || !pass) return;
10627
+ const current = readStoredDemoBookingPasses();
10628
+ const updated = [{
10629
+ email: normalizedEmail,
10630
+ pass
10631
+ }, ...current.filter((entry) => entry.email !== normalizedEmail)].slice(0, MAX_STORED_PASSES);
10632
+ window.localStorage.setItem(STORAGE_KEY, JSON.stringify(updated));
10633
+ } catch {}
10634
+ }
10635
+ function storeDemoBookingPassIfAvailable(email, pass) {
10636
+ if (email && pass) storeDemoBookingPass(email, pass);
10637
+ }
10638
+ function getDemoBookingPass(email) {
10639
+ try {
10640
+ const normalizedEmail = normalizeDemoBookingEmail(email);
10641
+ return readStoredDemoBookingPasses().find((entry) => entry.email === normalizedEmail)?.pass ?? null;
10642
+ } catch {
10643
+ return null;
10644
+ }
10645
+ }
10646
+ function readStoredDemoBookingPasses() {
10647
+ try {
10648
+ const raw = window.localStorage.getItem(STORAGE_KEY);
10649
+ if (!raw) return [];
10650
+ const parsed = JSON.parse(raw);
10651
+ return Array.isArray(parsed) ? parsed.filter(isStoredDemoBookingPass) : [];
10652
+ } catch {
10653
+ return [];
10654
+ }
10655
+ }
10656
+ function isStoredDemoBookingPass(value) {
10657
+ if (!isRecord$5(value)) return false;
10658
+ const record = value;
10659
+ return typeof record.email === "string" && record.email.length > 0 && typeof record.pass === "string" && record.pass.length > 0;
10660
+ }
10661
+ function isRecord$5(value) {
10662
+ return typeof value === "object" && value !== null && !Array.isArray(value);
10663
+ }
10664
+ //#endregion
10490
10665
  //#region ../blocks/src/system/runtime/hooks/useBookingSubmission.ts
10491
10666
  /**
10492
10667
  * Custom hook for submitting appointment bookings
@@ -10552,6 +10727,7 @@ function useBookingSubmission(_siteId) {
10552
10727
  successUrl: data.successUrl,
10553
10728
  cancelUrl: data.cancelUrl
10554
10729
  });
10730
+ storeDemoBookingPassIfAvailable(response.customer.email, response.demoBookingPass);
10555
10731
  dispatch({
10556
10732
  type: "submission-succeeded",
10557
10733
  message: response.type === "checkout_redirect" ? "Redirecting to secure checkout..." : "Booking submitted successfully."
@@ -10590,15 +10766,18 @@ function completeBookingSubmission(input) {
10590
10766
  kind: "checkout_redirect",
10591
10767
  checkoutUrl: data.checkoutUrl,
10592
10768
  sessionId: data.sessionId,
10769
+ customerEmail: data.customer.email,
10770
+ ...data.demoBookingPass ? { demoBookingPass: data.demoBookingPass } : {},
10593
10771
  ...data.mailingListSignupNote ? { mailingListSignupNote: data.mailingListSignupNote } : {}
10594
10772
  }
10595
10773
  };
10596
10774
  }
10775
+ const successCopy = getBookingSuccessCopy(input.successMessage);
10597
10776
  input.dispatch({
10598
10777
  type: "feedback-set",
10599
10778
  feedback: {
10600
10779
  kind: "success",
10601
- message: getBookingSuccessMessage(input.successMessage),
10780
+ message: successCopy.defaultEmailSentence ? `${successCopy.message} ${successCopy.defaultEmailSentence}`.trim() : successCopy.message,
10602
10781
  resourceName: data.appointment.resourceName
10603
10782
  }
10604
10783
  });
@@ -10608,6 +10787,8 @@ function completeBookingSubmission(input) {
10608
10787
  kind: "booked",
10609
10788
  appointmentId: data.appointment.id,
10610
10789
  resourceName: data.appointment.resourceName,
10790
+ customerEmail: data.customer.email,
10791
+ ...data.demoBookingPass ? { demoBookingPass: data.demoBookingPass } : {},
10611
10792
  ...data.mailingListSignupNote ? { mailingListSignupNote: data.mailingListSignupNote } : {}
10612
10793
  }
10613
10794
  };
@@ -10788,168 +10969,390 @@ function useDiscountCodeUi(options) {
10788
10969
  };
10789
10970
  }
10790
10971
  //#endregion
10791
- //#region ../blocks/src/system/runtime/shared/bookingPaymentOptionCopy.ts
10792
- function buildUpfrontBookingPaymentOptionCopy(formattedTotal) {
10793
- return {
10794
- title: "Pay in full",
10795
- description: "Pay everything today and your booking is confirmed.",
10796
- ctaLabel: `Pay ${formattedTotal} now`
10797
- };
10798
- }
10799
- function buildDeferredManualBookingPaymentOptionCopy() {
10800
- return {
10801
- title: "Pay offline",
10802
- description: "Book now and pay the business later, outside the platform.",
10803
- helperText: "Nothing is due today.",
10804
- ctaLabel: "Book now"
10805
- };
10806
- }
10807
- function buildInstalmentBookingPaymentOptionCopy(input) {
10808
- return {
10809
- title: "Payment plan",
10810
- description: describeInstalmentPlanCopy(input),
10811
- helperText: "You can pay the rest early any time in your customer portal.",
10812
- ctaLabel: `Pay ${input.formattedDueToday} now`
10813
- };
10814
- }
10815
- function describeInstalmentPlanCopy(input) {
10816
- if (input.depositRefundability) return `Pay ${input.formattedDueToday} today, then continue with scheduled payments. Your deposit is ${formatDepositRefundabilityLabel(input.depositRefundability)}.`;
10817
- if (input.futurePaymentCount === 0) return `Pay ${input.formattedDueToday} today.`;
10818
- if (input.futurePaymentCount === 1) return `Pay ${input.formattedDueToday} today, then one more payment later.`;
10819
- const formattedFirstFuture = input.formattedFirstFuture ?? input.formattedDueToday;
10820
- return `Pay ${input.formattedDueToday} today, then ${input.futurePaymentCount} more ${input.cadenceLabel} payments from ${formattedFirstFuture}.`;
10821
- }
10822
- function buildFlexibleBalanceBookingPaymentOptionCopy(input) {
10823
- return {
10824
- title: "Deposit now, pay the rest later",
10825
- description: `Pay ${input.formattedDueToday} today, then pay the remaining balance any time before ${input.dueDateLabel}. Your deposit is ${formatDepositRefundabilityLabel(input.depositRefundability)}.`,
10826
- helperText: "You can return in your customer portal to pay the rest before the due date.",
10827
- ctaLabel: `Pay ${input.formattedDueToday} now`
10828
- };
10829
- }
10830
- function formatDepositRefundabilityLabel(depositRefundability) {
10831
- return depositRefundability === "non_refundable" ? "non-refundable" : "refundable";
10972
+ //#region ../commerce/src/utils/assertNever.ts
10973
+ function assertNever(value, message) {
10974
+ if (message) throw new Error(message);
10975
+ throw new Error(`Unexpected value: ${String(value)}`);
10832
10976
  }
10833
10977
  //#endregion
10834
- //#region ../blocks/src/system/runtime/shared/utils/formatting.ts
10835
- /**
10836
- * Shared Formatting Utilities
10837
- *
10838
- * Currency and date formatting helpers for registration blocks.
10839
- */
10840
- /**
10841
- * Format a price in cents to a localized currency string.
10842
- *
10843
- * @param cents - Price in cents
10844
- * @param currency - ISO 4217 currency code (e.g., 'USD', 'GBP')
10845
- * @param locale - Optional locale override (defaults to the currency's locale)
10846
- * @returns Formatted price string (e.g., "£100.00")
10847
- */
10848
- function formatPrice(cents, currency = "GBP", locale) {
10849
- return formatCurrencyAmount(cents, currency, { locale });
10978
+ //#region ../commerce/src/purchase/bookingInstalmentSchedule.ts
10979
+ function resolveBookingInitialInstalmentAmountCents(input) {
10980
+ const totalAmountCents = Math.max(0, input.totalAmountCents);
10981
+ switch (input.plan.kind) {
10982
+ case "deposit_plus_one_remainder":
10983
+ case "deposit_plus_scheduled_instalments": return clampConfiguredAmount(input.plan.depositAmountCents, totalAmountCents);
10984
+ case "equal_scheduled_instalments": return splitAmountWithRemainderInFirst(totalAmountCents, input.plan.instalmentCount)[0] ?? 0;
10985
+ default: return assertNever(input.plan);
10986
+ }
10850
10987
  }
10851
- //#endregion
10852
- //#region ../blocks/src/system/runtime/shared/bookingPaymentOptions.ts
10853
- function resolveBookingPaymentDueNowCents(input) {
10854
- switch (input.option.kind) {
10855
- case "upfront": return input.totalCents;
10856
- case "deferred_manual": return 0;
10857
- case "instalment_plan": return buildInstalmentSchedulePreview({
10858
- totalCents: input.totalCents,
10859
- option: input.option,
10860
- bookingStartAt: input.bookingStartAt
10861
- })[0]?.amountCents ?? input.totalCents;
10862
- case "flexible_balance": return resolveFlexibleBalanceInitialPaymentCents({
10863
- totalAmountCents: input.totalCents,
10864
- config: input.option.config
10865
- });
10866
- default: return assertNever(input.option);
10988
+ function buildBookingInstalmentSchedule(input) {
10989
+ const totalAmountCents = Math.max(0, input.totalAmountCents);
10990
+ switch (input.plan.kind) {
10991
+ case "deposit_plus_one_remainder": {
10992
+ const depositAmountCents = resolveBookingInitialInstalmentAmountCents(input);
10993
+ const remainderAmountCents = Math.max(0, totalAmountCents - depositAmountCents);
10994
+ return omitZeroAmountFutureRows([createScheduleRow({
10995
+ sequence: 1,
10996
+ stateAtBooking: "paid_today",
10997
+ dueAt: input.anchorAt,
10998
+ amountCents: depositAmountCents
10999
+ }), createScheduleRow({
11000
+ sequence: 2,
11001
+ stateAtBooking: "scheduled",
11002
+ dueAt: addIntervalPreservingMonthAnchor(input.anchorAt, input.plan.remainderDueCount, input.plan.intervalUnit),
11003
+ amountCents: remainderAmountCents
11004
+ })]);
11005
+ }
11006
+ case "deposit_plus_scheduled_instalments": {
11007
+ const plan = input.plan;
11008
+ const depositAmountCents = resolveBookingInitialInstalmentAmountCents(input);
11009
+ const instalmentAmounts = splitAmountWithRemainderInFirst(Math.max(0, totalAmountCents - depositAmountCents), plan.instalmentCount);
11010
+ return omitZeroAmountFutureRows([createScheduleRow({
11011
+ sequence: 1,
11012
+ stateAtBooking: "paid_today",
11013
+ dueAt: input.anchorAt,
11014
+ amountCents: depositAmountCents
11015
+ }), ...instalmentAmounts.map((amountCents, index) => createScheduleRow({
11016
+ sequence: index + 2,
11017
+ stateAtBooking: "scheduled",
11018
+ dueAt: addIntervalPreservingMonthAnchor(input.anchorAt, plan.intervalCount * (index + 1), plan.intervalUnit),
11019
+ amountCents
11020
+ }))]);
11021
+ }
11022
+ case "equal_scheduled_instalments": {
11023
+ const plan = input.plan;
11024
+ return omitZeroAmountFutureRows(splitAmountWithRemainderInFirst(totalAmountCents, plan.instalmentCount).map((amountCents, index) => createScheduleRow({
11025
+ sequence: index + 1,
11026
+ stateAtBooking: index === 0 ? "paid_today" : "scheduled",
11027
+ dueAt: index === 0 ? input.anchorAt : addIntervalPreservingMonthAnchor(input.anchorAt, plan.intervalCount * index, plan.intervalUnit),
11028
+ amountCents
11029
+ })));
11030
+ }
11031
+ default: return assertNever(input.plan);
10867
11032
  }
10868
11033
  }
10869
- function buildBookingPaymentSelectionViewModel(input) {
10870
- const currency = input.priceCurrency ?? "USD";
10871
- const totalCents = Math.max(0, input.priceAmount ?? 0);
10872
- const allowedOptions = input.paymentTerms?.allowedOptions ?? [{ kind: "upfront" }];
10873
- const mode = allowedOptions.length > 1 ? "choice_required" : "single_option";
11034
+ function createScheduleRow(input) {
10874
11035
  return {
10875
- mode,
10876
- sectionTitle: mode === "choice_required" ? "Choose how you'd like to pay" : "Payment",
10877
- serviceTitle: input.serviceTitle,
10878
- options: allowedOptions.map((option) => buildBookingPaymentOptionViewModel({
10879
- option,
10880
- totalCents,
10881
- currency,
10882
- bookingStartAt: input.bookingStartAt,
10883
- locale: input.locale
10884
- }))
11036
+ id: `payment-${input.sequence}`,
11037
+ sequence: input.sequence,
11038
+ stateAtBooking: input.stateAtBooking,
11039
+ dueAt: input.dueAt,
11040
+ amountCents: input.amountCents
10885
11041
  };
10886
11042
  }
10887
- function buildBookingPaymentOptionViewModel(input) {
10888
- switch (input.option.kind) {
10889
- case "upfront": {
10890
- const formattedTotal = formatPrice(input.totalCents, input.currency, input.locale);
10891
- const copy = buildUpfrontBookingPaymentOptionCopy(formattedTotal);
10892
- return {
10893
- kind: "upfront",
10894
- title: copy.title,
10895
- description: copy.description,
10896
- summaryRows: [{
10897
- label: "Total",
10898
- value: formattedTotal
10899
- }, {
10900
- label: "Due today",
10901
- value: formattedTotal
10902
- }],
10903
- ctaLabel: copy.ctaLabel
10904
- };
10905
- }
10906
- case "deferred_manual": {
10907
- const formattedTotal = formatPrice(input.totalCents, input.currency, input.locale);
10908
- const copy = buildDeferredManualBookingPaymentOptionCopy();
10909
- return {
10910
- kind: "deferred_manual",
10911
- title: copy.title,
10912
- description: copy.description,
10913
- summaryRows: [{
10914
- label: "Total",
10915
- value: formattedTotal
10916
- }, {
10917
- label: "Due today",
10918
- value: formatPrice(0, input.currency, input.locale)
10919
- }],
10920
- helperText: copy.helperText,
10921
- ctaLabel: copy.ctaLabel
10922
- };
10923
- }
10924
- case "instalment_plan": {
10925
- const schedulePreview = buildInstalmentSchedulePreview({
10926
- totalCents: input.totalCents,
10927
- option: input.option,
10928
- bookingStartAt: input.bookingStartAt
10929
- });
10930
- const dueToday = resolveBookingPaymentDueNowCents({
10931
- option: input.option,
10932
- totalCents: input.totalCents,
10933
- bookingStartAt: input.bookingStartAt
10934
- });
10935
- const futureRows = schedulePreview.slice(1);
10936
- const formattedTotal = formatPrice(input.totalCents, input.currency, input.locale);
10937
- const formattedDueToday = formatPrice(dueToday, input.currency, input.locale);
10938
- const depositRefundability = getBookingInstalmentDepositRefundability(input.option.plan);
10939
- const copy = buildInstalmentBookingPaymentOptionCopy({
10940
- formattedDueToday,
10941
- futurePaymentCount: futureRows.length,
10942
- formattedFirstFuture: futureRows[0] ? formatPrice(futureRows[0].amountCents, input.currency, input.locale) : null,
10943
- cadenceLabel: getPaymentCadenceLabel(input.option.plan),
10944
- depositRefundability
10945
- });
10946
- return {
10947
- kind: "instalment_plan",
10948
- title: copy.title,
10949
- description: copy.description,
10950
- summaryRows: [
10951
- {
10952
- label: "Total",
11043
+ //#endregion
11044
+ //#region ../commerce/src/purchase/checkoutSessionMetadata.ts
11045
+ const datedOfferingSharedEngineMetadataShape = {
11046
+ datedOfferingEngineContractVersion: z.literal("shared_v1"),
11047
+ datedOfferingEngineRouteKind: z.literal("shared_whole_series_registration"),
11048
+ datedOfferingCapacityHoldId: z.string().uuid(),
11049
+ datedOfferingCapacityHoldAuditRef: z.string().uuid(),
11050
+ customerId: z.string().uuid(),
11051
+ eventSeriesId: z.string().uuid()
11052
+ };
11053
+ z.object(datedOfferingSharedEngineMetadataShape);
11054
+ const orderCheckoutSessionMetadataBaseShape = {
11055
+ type: z.literal("order"),
11056
+ site_id: z.string().uuid(),
11057
+ order_id: z.string().uuid().optional(),
11058
+ customer_email: z.string().email().optional(),
11059
+ customer_name: z.string().optional(),
11060
+ product_id: z.string().uuid().optional(),
11061
+ attendee_id: z.string().uuid().optional(),
11062
+ occurrence_id: z.string().uuid().optional(),
11063
+ tickets_count: z.string().optional(),
11064
+ notes: z.string().optional(),
11065
+ discount_redemption_id: z.string().uuid().optional(),
11066
+ discount_code_id: z.string().uuid().optional(),
11067
+ discount_code: z.string().optional(),
11068
+ discount_public_label: z.string().optional(),
11069
+ credit_reservation_id: z.string().uuid().optional(),
11070
+ credit_reserved_cents: z.string().optional(),
11071
+ discount_code_amount_cents: z.string().optional(),
11072
+ order_payment_reason: z.enum([
11073
+ "instalment_payoff",
11074
+ "flexible_balance_initial",
11075
+ "flexible_balance_paydown"
11076
+ ]).optional(),
11077
+ order_payment_plan_id: z.string().uuid().optional(),
11078
+ order_flexible_balance_contract_id: z.string().uuid().optional()
11079
+ };
11080
+ const absentDatedOfferingSharedEngineMetadataShape = {
11081
+ datedOfferingEngineContractVersion: z.never().optional(),
11082
+ datedOfferingEngineRouteKind: z.never().optional(),
11083
+ datedOfferingCapacityHoldId: z.never().optional(),
11084
+ datedOfferingCapacityHoldAuditRef: z.never().optional(),
11085
+ customerId: z.never().optional(),
11086
+ eventSeriesId: z.never().optional()
11087
+ };
11088
+ const LegacyOrderCheckoutSessionMetadataSchema = z.object({
11089
+ ...orderCheckoutSessionMetadataBaseShape,
11090
+ ...absentDatedOfferingSharedEngineMetadataShape
11091
+ });
11092
+ const SharedDatedOfferingOrderCheckoutSessionMetadataSchema = z.object({
11093
+ ...orderCheckoutSessionMetadataBaseShape,
11094
+ ...datedOfferingSharedEngineMetadataShape
11095
+ });
11096
+ z.union([SharedDatedOfferingOrderCheckoutSessionMetadataSchema, LegacyOrderCheckoutSessionMetadataSchema]);
11097
+ //#endregion
11098
+ //#region ../commerce/src/purchase/stripeCommissionMetadata.ts
11099
+ /** Reasons are payment evidence, not an independent pricing policy. */
11100
+ const STRIPE_COMMISSION_FREE_REASONS = [
11101
+ "managed_billing",
11102
+ "no_commission_plan",
11103
+ "billing_evidence_invalid",
11104
+ "fee_rounds_to_zero",
11105
+ "payment_not_stripe"
11106
+ ];
11107
+ const historicalContext = {
11108
+ currency: z.string().refine((value) => parseCurrencyCode(value) !== null).optional(),
11109
+ sourcePlanId: z.string().trim().min(1).optional()
11110
+ };
11111
+ const percentSchema = z.number().finite().min(0).max(100);
11112
+ z.discriminatedUnion("kind", [
11113
+ z.object({
11114
+ kind: z.literal("commission_free"),
11115
+ reason: z.enum(STRIPE_COMMISSION_FREE_REASONS),
11116
+ ...historicalContext
11117
+ }),
11118
+ z.object({
11119
+ kind: z.literal("application_fee_amount"),
11120
+ amountCents: z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER),
11121
+ percent: percentSchema,
11122
+ ...historicalContext
11123
+ }),
11124
+ z.object({
11125
+ kind: z.literal("application_fee_percent"),
11126
+ percent: percentSchema,
11127
+ ...historicalContext
11128
+ })
11129
+ ]);
11130
+ toNonNegativeCents(0);
11131
+ //#endregion
11132
+ //#region ../commerce/src/purchase/event-registration-errors.ts
11133
+ const eventRegistrationErrors = {
11134
+ registrationClosed: {
11135
+ message: "Booking is currently closed for this event. Please contact the organiser if you’d like to find out more.",
11136
+ action: "none"
11137
+ },
11138
+ paymentInvestigationRequired: {
11139
+ message: "We still can’t confirm your payment. Please don’t make another payment. Contact the organiser so they can check your booking.",
11140
+ action: "none"
11141
+ },
11142
+ paymentProviderUnavailable: {
11143
+ message: "We couldn’t reach the payment provider. Please try again in a minute.",
11144
+ action: "retry"
11145
+ },
11146
+ paymentPageUnavailable: {
11147
+ message: "We couldn’t open the payment page. Please refresh this page and try again. If this keeps happening, contact the organiser for help.",
11148
+ action: "retry"
11149
+ },
11150
+ paymentUnavailable: {
11151
+ message: "Online payment is not available for this event right now. Please contact the organiser for help with booking.",
11152
+ action: "none"
11153
+ },
11154
+ capacityChanged: {
11155
+ message: "Sorry, there aren’t enough places left for your selection. Please check the available places and choose again.",
11156
+ action: "places"
11157
+ },
11158
+ selectionChanged: {
11159
+ message: "The booking options for this event have changed. Please check the latest options and choose your places again.",
11160
+ action: "places"
11161
+ },
11162
+ registrationPreparationChanged: {
11163
+ message: "The booking options for this event have changed. Please check the latest options and choose your places again.",
11164
+ action: "places"
11165
+ },
11166
+ registrationAlreadyExists: {
11167
+ message: "You already have a booking for this event. Please check your bookings to see its status. If you need help, contact the organiser.",
11168
+ action: "portal"
11169
+ },
11170
+ holdExpired: {
11171
+ message: "Your reservation has timed out. Please check availability and choose your places again.",
11172
+ action: "start"
11173
+ },
11174
+ waitlistUnavailable: {
11175
+ message: "Sorry, the waiting list place offered in this invitation is no longer available. Please check the event for available places or contact the organiser for help.",
11176
+ action: "event"
11177
+ },
11178
+ paymentContextMismatch: {
11179
+ message: "The payment options for this event have changed. Please check the latest options before continuing.",
11180
+ action: "payment-options"
11181
+ },
11182
+ verificationFailed: {
11183
+ message: "We couldn’t confirm this request came from a person. Please refresh the page and try again.",
11184
+ action: "none"
11185
+ },
11186
+ idempotencyConflict: {
11187
+ message: "You’ve already started booking this event. Please finish in the other tab if it’s still open, or check your booking status before starting again.",
11188
+ action: "portal"
11189
+ },
11190
+ invalidCommitInput: {
11191
+ message: "We couldn’t accept your booking details. Please check the information you entered and try again. If this keeps happening, contact the organiser for help.",
11192
+ action: "details"
11193
+ }
11194
+ };
11195
+ function parseEventRegistrationErrorReason(value) {
11196
+ return typeof value === "string" && Object.prototype.hasOwnProperty.call(eventRegistrationErrors, value) ? value : null;
11197
+ }
11198
+ //#endregion
11199
+ //#region ../blocks/src/system/runtime/shared/bookingPaymentOptionCopy.ts
11200
+ function buildUpfrontBookingPaymentOptionCopy(formattedTotal) {
11201
+ return {
11202
+ title: "Pay in full",
11203
+ description: "Pay everything today and your booking is confirmed.",
11204
+ ctaLabel: `Pay ${formattedTotal} now`
11205
+ };
11206
+ }
11207
+ function buildDeferredManualBookingPaymentOptionCopy() {
11208
+ return {
11209
+ title: "Pay offline",
11210
+ description: "Book now and pay the business later, outside the platform.",
11211
+ helperText: "Nothing is due today.",
11212
+ ctaLabel: "Book now"
11213
+ };
11214
+ }
11215
+ function buildInstalmentBookingPaymentOptionCopy(input) {
11216
+ return {
11217
+ title: "Payment plan",
11218
+ description: describeInstalmentPlanCopy(input),
11219
+ helperText: "You can pay the rest early any time in your customer portal.",
11220
+ ctaLabel: `Pay ${input.formattedDueToday} now`
11221
+ };
11222
+ }
11223
+ function describeInstalmentPlanCopy(input) {
11224
+ if (input.depositRefundability) return `Pay ${input.formattedDueToday} today, then continue with scheduled payments. Your deposit is ${formatDepositRefundabilityLabel(input.depositRefundability)}.`;
11225
+ if (input.futurePaymentCount === 0) return `Pay ${input.formattedDueToday} today.`;
11226
+ if (input.futurePaymentCount === 1) return `Pay ${input.formattedDueToday} today, then one more payment later.`;
11227
+ const formattedFirstFuture = input.formattedFirstFuture ?? input.formattedDueToday;
11228
+ return `Pay ${input.formattedDueToday} today, then ${input.futurePaymentCount} more ${input.cadenceLabel} payments from ${formattedFirstFuture}.`;
11229
+ }
11230
+ function buildFlexibleBalanceBookingPaymentOptionCopy(input) {
11231
+ return {
11232
+ title: "Deposit now, pay the rest later",
11233
+ description: `Pay ${input.formattedDueToday} today, then pay the remaining balance any time before ${input.dueDateLabel}. Your deposit is ${formatDepositRefundabilityLabel(input.depositRefundability)}.`,
11234
+ helperText: "You can return in your customer portal to pay the rest before the due date.",
11235
+ ctaLabel: `Pay ${input.formattedDueToday} now`
11236
+ };
11237
+ }
11238
+ function formatDepositRefundabilityLabel(depositRefundability) {
11239
+ return depositRefundability === "non_refundable" ? "non-refundable" : "refundable";
11240
+ }
11241
+ //#endregion
11242
+ //#region ../blocks/src/system/runtime/shared/utils/formatting.ts
11243
+ /**
11244
+ * Shared Formatting Utilities
11245
+ *
11246
+ * Currency and date formatting helpers for registration blocks.
11247
+ */
11248
+ /**
11249
+ * Format a price in cents to a localized currency string.
11250
+ *
11251
+ * @param cents - Price in cents
11252
+ * @param currency - ISO 4217 currency code (e.g., 'USD', 'GBP')
11253
+ * @param locale - Optional locale override (defaults to the currency's locale)
11254
+ * @returns Formatted price string (e.g., "£100.00")
11255
+ */
11256
+ function formatPrice(cents, currency = "GBP", locale) {
11257
+ return formatCurrencyAmount(cents, currency, { locale });
11258
+ }
11259
+ //#endregion
11260
+ //#region ../blocks/src/system/runtime/shared/bookingPaymentOptions.ts
11261
+ function resolveBookingPaymentDueNowCents(input) {
11262
+ switch (input.option.kind) {
11263
+ case "upfront": return input.totalCents;
11264
+ case "deferred_manual": return 0;
11265
+ case "instalment_plan": return resolveBookingInitialInstalmentAmountCents({
11266
+ totalAmountCents: input.totalCents,
11267
+ plan: input.option.plan
11268
+ });
11269
+ case "flexible_balance": return resolveFlexibleBalanceInitialPaymentCents({
11270
+ totalAmountCents: input.totalCents,
11271
+ config: input.option.config
11272
+ });
11273
+ default: return assertNever$1(input.option);
11274
+ }
11275
+ }
11276
+ function buildBookingPaymentSelectionViewModel(input) {
11277
+ const currency = input.priceCurrency ?? "USD";
11278
+ const totalCents = Math.max(0, input.priceAmount ?? 0);
11279
+ const allowedOptions = input.paymentTerms?.allowedOptions ?? [{ kind: "upfront" }];
11280
+ const mode = allowedOptions.length > 1 ? "choice_required" : "single_option";
11281
+ return {
11282
+ mode,
11283
+ sectionTitle: mode === "choice_required" ? "Choose how you'd like to pay" : "Payment",
11284
+ serviceTitle: input.serviceTitle,
11285
+ options: allowedOptions.map((option) => buildBookingPaymentOptionViewModel({
11286
+ option,
11287
+ totalCents,
11288
+ currency,
11289
+ bookingStartAt: input.bookingStartAt,
11290
+ nowIso: input.nowIso,
11291
+ locale: input.locale
11292
+ }))
11293
+ };
11294
+ }
11295
+ function buildBookingPaymentOptionViewModel(input) {
11296
+ switch (input.option.kind) {
11297
+ case "upfront": {
11298
+ const formattedTotal = formatPrice(input.totalCents, input.currency, input.locale);
11299
+ const copy = buildUpfrontBookingPaymentOptionCopy(formattedTotal);
11300
+ return {
11301
+ kind: "upfront",
11302
+ title: copy.title,
11303
+ description: copy.description,
11304
+ summaryRows: [{
11305
+ label: "Total",
11306
+ value: formattedTotal
11307
+ }, {
11308
+ label: "Due today",
11309
+ value: formattedTotal
11310
+ }],
11311
+ ctaLabel: copy.ctaLabel
11312
+ };
11313
+ }
11314
+ case "deferred_manual": {
11315
+ const formattedTotal = formatPrice(input.totalCents, input.currency, input.locale);
11316
+ const copy = buildDeferredManualBookingPaymentOptionCopy();
11317
+ return {
11318
+ kind: "deferred_manual",
11319
+ title: copy.title,
11320
+ description: copy.description,
11321
+ summaryRows: [{
11322
+ label: "Total",
11323
+ value: formattedTotal
11324
+ }, {
11325
+ label: "Due today",
11326
+ value: formatPrice(0, input.currency, input.locale)
11327
+ }],
11328
+ helperText: copy.helperText,
11329
+ ctaLabel: copy.ctaLabel
11330
+ };
11331
+ }
11332
+ case "instalment_plan": {
11333
+ const [firstRow, ...futureRows] = buildBookingInstalmentSchedule({
11334
+ anchorAt: input.nowIso,
11335
+ totalAmountCents: input.totalCents,
11336
+ plan: input.option.plan
11337
+ });
11338
+ const dueToday = firstRow?.amountCents ?? 0;
11339
+ const formattedTotal = formatPrice(input.totalCents, input.currency, input.locale);
11340
+ const formattedDueToday = formatPrice(dueToday, input.currency, input.locale);
11341
+ const depositRefundability = getBookingInstalmentDepositRefundability(input.option.plan);
11342
+ const copy = buildInstalmentBookingPaymentOptionCopy({
11343
+ formattedDueToday,
11344
+ futurePaymentCount: futureRows.length,
11345
+ formattedFirstFuture: futureRows[0] ? formatPrice(futureRows[0].amountCents, input.currency, input.locale) : null,
11346
+ cadenceLabel: getPaymentCadenceLabel(input.option.plan),
11347
+ depositRefundability
11348
+ });
11349
+ return {
11350
+ kind: "instalment_plan",
11351
+ title: copy.title,
11352
+ description: copy.description,
11353
+ summaryRows: [
11354
+ {
11355
+ label: "Total",
10953
11356
  value: formattedTotal
10954
11357
  },
10955
11358
  {
@@ -10979,7 +11382,7 @@ function buildBookingPaymentOptionViewModel(input) {
10979
11382
  const formattedDueToday = formatPrice(dueToday, input.currency, input.locale);
10980
11383
  const formattedRemainingBalance = formatPrice(remainingBalance, input.currency, input.locale);
10981
11384
  const dueAt = resolveFlexibleBalanceDueAt({
10982
- bookingStartAt: input.bookingStartAt ?? (/* @__PURE__ */ new Date()).toISOString(),
11385
+ bookingStartAt: input.bookingStartAt ?? input.nowIso,
10983
11386
  dueDateRule: input.option.config.dueDateRule
10984
11387
  });
10985
11388
  const copy = buildFlexibleBalanceBookingPaymentOptionCopy({
@@ -11017,43 +11420,7 @@ function buildBookingPaymentOptionViewModel(input) {
11017
11420
  ctaLabel: copy.ctaLabel
11018
11421
  };
11019
11422
  }
11020
- default: return assertNever(input.option);
11021
- }
11022
- }
11023
- function buildInstalmentSchedulePreview(input) {
11024
- const startAt = input.bookingStartAt ?? (/* @__PURE__ */ new Date()).toISOString();
11025
- switch (input.option.plan.kind) {
11026
- case "deposit_plus_one_remainder": {
11027
- const deposit = clampConfiguredAmount(input.option.plan.depositAmountCents, input.totalCents);
11028
- const remainder = Math.max(0, input.totalCents - deposit);
11029
- return compactSchedulePreview([{
11030
- dueAt: startAt,
11031
- amountCents: deposit
11032
- }, {
11033
- dueAt: addIntervalPreservingMonthAnchor(startAt, input.option.plan.remainderDueCount, input.option.plan.intervalUnit),
11034
- amountCents: remainder
11035
- }]);
11036
- }
11037
- case "deposit_plus_scheduled_instalments": {
11038
- const plan = input.option.plan;
11039
- const deposit = clampConfiguredAmount(plan.depositAmountCents, input.totalCents);
11040
- const instalments = splitAmountWithRemainderInFirst(Math.max(0, input.totalCents - deposit), plan.instalmentCount);
11041
- return compactSchedulePreview([{
11042
- dueAt: startAt,
11043
- amountCents: deposit
11044
- }, ...instalments.map((amountCents, index) => ({
11045
- dueAt: addIntervalPreservingMonthAnchor(startAt, plan.intervalCount * (index + 1), plan.intervalUnit),
11046
- amountCents
11047
- }))]);
11048
- }
11049
- case "equal_scheduled_instalments": {
11050
- const plan = input.option.plan;
11051
- return compactSchedulePreview(splitAmountWithRemainderInFirst(input.totalCents, plan.instalmentCount).map((amountCents, index) => ({
11052
- dueAt: index === 0 ? startAt : addIntervalPreservingMonthAnchor(startAt, plan.intervalCount * index, plan.intervalUnit),
11053
- amountCents
11054
- })));
11055
- }
11056
- default: return assertNever(input.option.plan);
11423
+ default: return assertNever$1(input.option);
11057
11424
  }
11058
11425
  }
11059
11426
  function getPaymentCadenceLabel(plan) {
@@ -11061,9 +11428,6 @@ function getPaymentCadenceLabel(plan) {
11061
11428
  const unitLabel = intervalCount === 1 ? plan.intervalUnit : `${plan.intervalUnit}s`;
11062
11429
  return intervalCount === 1 ? unitLabel : `every ${intervalCount} ${unitLabel}`;
11063
11430
  }
11064
- function compactSchedulePreview(schedule) {
11065
- return omitZeroAmountFutureRows(schedule);
11066
- }
11067
11431
  function formatScheduleDate(isoString, locale) {
11068
11432
  const date = new Date(isoString);
11069
11433
  if (!Number.isFinite(date.getTime())) return isoString;
@@ -11071,11 +11435,11 @@ function formatScheduleDate(isoString, locale) {
11071
11435
  }
11072
11436
  //#endregion
11073
11437
  //#region ../blocks/src/system/runtime/nodes/booking-form.service-categories.ts
11074
- function isRecord$3(value) {
11438
+ function isRecord$4(value) {
11075
11439
  return typeof value === "object" && value !== null && !Array.isArray(value);
11076
11440
  }
11077
11441
  function readCategory(value) {
11078
- if (!isRecord$3(value)) return [];
11442
+ if (!isRecord$4(value)) return [];
11079
11443
  const { id, name, description } = value;
11080
11444
  if (typeof id !== "string" || id.trim() === "" || typeof name !== "string") return [];
11081
11445
  return [{
@@ -11091,7 +11455,7 @@ function readCategory(value) {
11091
11455
  * it.
11092
11456
  */
11093
11457
  function normalizeBookingServiceCategories(services) {
11094
- if (!isRecord$3(services) || !Array.isArray(services.categories)) return [];
11458
+ if (!isRecord$4(services) || !Array.isArray(services.categories)) return [];
11095
11459
  return services.categories.flatMap(readCategory);
11096
11460
  }
11097
11461
  /**
@@ -11099,7 +11463,7 @@ function normalizeBookingServiceCategories(services) {
11099
11463
  * its loader data (`data.services`).
11100
11464
  */
11101
11465
  function readOverrideServiceCategories(data) {
11102
- return isRecord$3(data) ? normalizeBookingServiceCategories(data.services) : [];
11466
+ return isRecord$4(data) ? normalizeBookingServiceCategories(data.services) : [];
11103
11467
  }
11104
11468
  //#endregion
11105
11469
  //#region ../blocks/src/system/runtime/nodes/booking-form.validationErrors.ts
@@ -11346,7 +11710,7 @@ function bookingFlowReducer(state, event) {
11346
11710
  phase: "editing"
11347
11711
  } : state;
11348
11712
  case "reset": return event.initial;
11349
- default: return assertNever(event);
11713
+ default: return assertNever$1(event);
11350
11714
  }
11351
11715
  }
11352
11716
  function applyBookingServiceSelection(state, serviceId) {
@@ -11516,7 +11880,7 @@ function validateBookingStep(input) {
11516
11880
  errors: createFieldBookingValidationErrors(errors)
11517
11881
  } : { ok: true };
11518
11882
  }
11519
- default: return assertNever(input.stepId);
11883
+ default: return assertNever$1(input.stepId);
11520
11884
  }
11521
11885
  }
11522
11886
  function validateBookingFields(input) {
@@ -11816,7 +12180,7 @@ function resolveAppointmentPackagesModel(input) {
11816
12180
  selected
11817
12181
  };
11818
12182
  }
11819
- default: return assertNever(input.state);
12183
+ default: return assertNever$1(input.state);
11820
12184
  }
11821
12185
  }
11822
12186
  function toHeadlessEligibleAppointmentPackage(appointmentPackage) {
@@ -11865,7 +12229,7 @@ function isBlankFieldValue(value) {
11865
12229
  return false;
11866
12230
  }
11867
12231
  function readAppointmentBookingOverrideData(value) {
11868
- if (!isRecord$2(value)) return null;
12232
+ if (!isRecord$3(value)) return null;
11869
12233
  const services = normalizeBookingServices(value.services);
11870
12234
  return {
11871
12235
  form: normalizeBookingFormConfig(value.form),
@@ -11880,7 +12244,7 @@ function createOverrideInputError(reason, message, warnInDev = false) {
11880
12244
  message
11881
12245
  };
11882
12246
  }
11883
- function isRecord$2(value) {
12247
+ function isRecord$3(value) {
11884
12248
  return typeof value === "object" && value !== null;
11885
12249
  }
11886
12250
  //#endregion
@@ -12371,18 +12735,27 @@ function useHeadlessBookingFlow(options) {
12371
12735
  defaultServiceId,
12372
12736
  options.services
12373
12737
  ]);
12738
+ const bookingNowIso = useBookingNowIso();
12374
12739
  const paymentSelection = useMemo(() => selectedService && paymentResolution.mode !== "unsupported" ? buildBookingPaymentSelectionViewModel({
12375
12740
  serviceTitle: selectedService.title,
12376
12741
  paymentTerms: selectedService.paymentTerms,
12377
12742
  priceAmount: selectedAppointmentPriceAmount,
12378
12743
  priceCurrency: selectedService.priceCurrency,
12379
- bookingStartAt: state.selectedSlot?.startAt
12744
+ bookingStartAt: state.selectedSlot?.startAt,
12745
+ nowIso: bookingNowIso
12380
12746
  }) : null, [
12747
+ bookingNowIso,
12381
12748
  paymentResolution.mode,
12382
12749
  selectedAppointmentPriceAmount,
12383
12750
  selectedService,
12384
12751
  state.selectedSlot?.startAt
12385
12752
  ]);
12753
+ const paymentConfirmationSummary = resolveBookingPaymentConfirmationSummary({
12754
+ service: selectedService,
12755
+ priceAmount: selectedAppointmentPriceAmount,
12756
+ selectedCollectionOptionKind: state.selectedCollectionOptionKind,
12757
+ hasSelectedAppointmentPackage: Boolean(state.selectedAppointmentPackageId)
12758
+ });
12386
12759
  const appointmentPackageItems = appointmentPackages.tag === "loaded" ? appointmentPackages.value : [];
12387
12760
  const selectedAppointmentPackage = appointmentPackageItems.find((appointmentPackage) => appointmentPackage.customerPassId === state.selectedAppointmentPackageId) ?? null;
12388
12761
  const spamProtectionEnabled = options.spamProtectionEnabled ?? isSpamProtectionEnabled();
@@ -12412,7 +12785,8 @@ function useHeadlessBookingFlow(options) {
12412
12785
  selectedSlidingAmount,
12413
12786
  slidingScale: selectedServiceSlidingScale,
12414
12787
  appointmentPackages: appointmentPackagesModel,
12415
- errorMessage: paymentResolution.errorMessage ?? "This service cannot be booked right now."
12788
+ errorMessage: paymentResolution.errorMessage ?? "This service cannot be booked right now.",
12789
+ confirmationSummary: null
12416
12790
  } : {
12417
12791
  kind: "ok",
12418
12792
  mode: paymentResolution.mode,
@@ -12422,7 +12796,8 @@ function useHeadlessBookingFlow(options) {
12422
12796
  selectedSlidingAmountInput: state.selectedSlidingAmountInput,
12423
12797
  selectedSlidingAmount,
12424
12798
  slidingScale: selectedServiceSlidingScale,
12425
- appointmentPackages: appointmentPackagesModel
12799
+ appointmentPackages: appointmentPackagesModel,
12800
+ confirmationSummary: paymentConfirmationSummary
12426
12801
  };
12427
12802
  return {
12428
12803
  mailingList,
@@ -12562,14 +12937,14 @@ function pollingReducer(state, action) {
12562
12937
  case "completed":
12563
12938
  case "failed":
12564
12939
  case "timeout": return state;
12565
- default: return assertNever(state);
12940
+ default: return assertNever$1(state);
12566
12941
  }
12567
12942
  case "polling-timed-out": return {
12568
12943
  tag: "timeout",
12569
12944
  result: state.result,
12570
12945
  error: /* @__PURE__ */ new Error("Polling timed out")
12571
12946
  };
12572
- default: return assertNever(action);
12947
+ default: return assertNever$1(action);
12573
12948
  }
12574
12949
  }
12575
12950
  //#endregion
@@ -12580,67 +12955,24 @@ function pollingReducer(state, action) {
12580
12955
  * Provides a reusable polling mechanism with configurable intervals,
12581
12956
  * max attempts, and completion detection. Used by usePaymentVerification
12582
12957
  * and other hooks that need to poll for status changes.
12583
- *
12584
- * @example
12585
- * ```tsx
12586
- * const polling = usePolling(shouldPoll ? {
12587
- * pollFn: () => api.getStatus(id),
12588
- * isComplete: (result) => result.status === 'done',
12589
- * } : null);
12590
- *
12591
- * useEffect(() => {
12592
- * if (polling.status === 'completed') {
12593
- * handleSuccess(polling.result);
12594
- * }
12595
- * }, [polling.status]);
12596
- * ```
12597
12958
  */
12598
12959
  const DEFAULT_MAX_ATTEMPTS = 10;
12599
12960
  const DEFAULT_POLL_INTERVAL = 1e3;
12600
- /**
12601
- * Generic hook for polling an async operation until completion.
12602
- *
12603
- * Pass config to start polling, or null to stop/idle.
12604
- * The hook handles cleanup on unmount and config changes.
12605
- *
12606
- * **IMPORTANT: Config identity stability**
12607
- *
12608
- * The config object is used as an effect dependency. If config identity
12609
- * changes on every render (e.g., inline objects), polling will restart
12610
- * continuously, causing infinite request loops.
12611
- *
12612
- * Always memoize the config object:
12613
- *
12614
- * @example
12615
- * ```tsx
12616
- * // BAD - inline object creates new identity every render
12617
- * usePolling({
12618
- * pollFn: () => api.getStatus(id),
12619
- * isComplete: (result) => result.status === 'done',
12620
- * });
12621
- *
12622
- * // GOOD - memoized config, stable identity
12623
- * const pollConfig = useMemo(() => shouldPoll ? {
12624
- * pollFn: () => api.getStatus(id),
12625
- * isComplete: (result) => result.status === 'done',
12626
- * } : null, [shouldPoll, api, id]);
12627
- *
12628
- * usePolling(pollConfig);
12629
- * ```
12630
- *
12631
- * @param config - Configuration for polling, or null to stop
12632
- * @returns Polling result with status, data, and retry function
12633
- */
12634
- function usePolling(config) {
12635
- const [state, dispatch] = useReducer(pollingReducer, void 0, createInitialPollingState);
12636
- const attemptsRef = useRef(0);
12637
- const timeoutRef = useRef(null);
12638
- const isPollingRef = useRef(false);
12639
- const isActiveRef = useRef(false);
12640
- const generationRef = useRef(0);
12641
- const configRef = useRef(config);
12642
- configRef.current = config;
12643
- const cleanup = useCallback(() => {
12961
+ function usePollingRuntime(config) {
12962
+ const runtime = {
12963
+ configRef: useRef(config),
12964
+ attemptsRef: useRef(0),
12965
+ timeoutRef: useRef(null),
12966
+ isPollingRef: useRef(false),
12967
+ isActiveRef: useRef(false),
12968
+ generationRef: useRef(0)
12969
+ };
12970
+ runtime.configRef.current = config;
12971
+ return runtime;
12972
+ }
12973
+ function usePollingCleanup(runtime) {
12974
+ const { isActiveRef, generationRef, timeoutRef, isPollingRef } = runtime;
12975
+ return useCallback(() => {
12644
12976
  isActiveRef.current = false;
12645
12977
  generationRef.current += 1;
12646
12978
  if (timeoutRef.current) {
@@ -12648,16 +12980,27 @@ function usePolling(config) {
12648
12980
  timeoutRef.current = null;
12649
12981
  }
12650
12982
  isPollingRef.current = false;
12651
- }, []);
12652
- const resetState = useCallback(() => {
12983
+ }, [
12984
+ generationRef,
12985
+ isActiveRef,
12986
+ isPollingRef,
12987
+ timeoutRef
12988
+ ]);
12989
+ }
12990
+ function usePollingReset(runtime, dispatch) {
12991
+ const { attemptsRef } = runtime;
12992
+ return useCallback(() => {
12653
12993
  dispatch({ type: "polling-reset" });
12654
12994
  attemptsRef.current = 0;
12655
- }, []);
12656
- const poll = useCallback(async () => {
12657
- const cfg = configRef.current;
12658
- if (!cfg) return true;
12995
+ }, [attemptsRef, dispatch]);
12996
+ }
12997
+ function usePollingRequest(runtime, dispatch, cleanup) {
12998
+ const { configRef, attemptsRef, isPollingRef, isActiveRef, generationRef } = runtime;
12999
+ return useCallback(async () => {
13000
+ const config = configRef.current;
13001
+ if (!config) return true;
12659
13002
  if (isPollingRef.current) return false;
12660
- const maxAttempts = cfg.maxAttempts ?? DEFAULT_MAX_ATTEMPTS;
13003
+ const maxAttempts = config.maxAttempts ?? DEFAULT_MAX_ATTEMPTS;
12661
13004
  if (attemptsRef.current >= maxAttempts) {
12662
13005
  dispatch({ type: "polling-timed-out" });
12663
13006
  cleanup();
@@ -12667,81 +13010,115 @@ function usePolling(config) {
12667
13010
  attemptsRef.current += 1;
12668
13011
  const generation = generationRef.current;
12669
13012
  try {
12670
- const data = await cfg.pollFn();
12671
- if (generation !== generationRef.current || !isActiveRef.current) {
12672
- isPollingRef.current = false;
12673
- return true;
12674
- }
12675
- if (cfg.isFailed?.(data)) {
13013
+ const result = await config.pollFn();
13014
+ if (generation !== generationRef.current || !isActiveRef.current) return true;
13015
+ if (config.isFailed?.(result)) {
12676
13016
  dispatch({
12677
13017
  type: "polling-failed",
12678
- result: data
13018
+ result
12679
13019
  });
12680
13020
  cleanup();
12681
13021
  return true;
12682
13022
  }
12683
- if (cfg.isComplete(data)) {
13023
+ if (config.isComplete(result)) {
12684
13024
  dispatch({
12685
13025
  type: "polling-completed",
12686
- result: data
13026
+ result
12687
13027
  });
12688
13028
  cleanup();
12689
13029
  return true;
12690
13030
  }
12691
13031
  dispatch({
12692
13032
  type: "polling-progressed",
12693
- result: data
13033
+ result
12694
13034
  });
12695
13035
  isPollingRef.current = false;
12696
13036
  return false;
12697
- } catch (err) {
12698
- if (generation !== generationRef.current || !isActiveRef.current) {
12699
- isPollingRef.current = false;
12700
- return true;
12701
- }
12702
- if (err instanceof Error) dispatch({
13037
+ } catch (error) {
13038
+ if (generation !== generationRef.current || !isActiveRef.current) return true;
13039
+ if (error instanceof Error) dispatch({
12703
13040
  type: "polling-request-failed",
12704
- error: err
13041
+ error
12705
13042
  });
12706
13043
  isPollingRef.current = false;
12707
13044
  return false;
12708
13045
  }
12709
- }, [cleanup]);
12710
- const schedulePoll = useCallback(() => {
13046
+ }, [
13047
+ attemptsRef,
13048
+ cleanup,
13049
+ configRef,
13050
+ dispatch,
13051
+ generationRef,
13052
+ isActiveRef,
13053
+ isPollingRef
13054
+ ]);
13055
+ }
13056
+ function usePollingScheduler(runtime, poll) {
13057
+ const { attemptsRef, configRef, isActiveRef, timeoutRef } = runtime;
13058
+ return useCallback(() => {
12711
13059
  if (!isActiveRef.current) return;
12712
- const pollInterval = configRef.current?.interval ?? DEFAULT_POLL_INTERVAL;
12713
13060
  const doPoll = async () => {
12714
- if (!await poll() && isActiveRef.current) timeoutRef.current = setTimeout(doPoll, pollInterval);
13061
+ if (!await poll() && isActiveRef.current) {
13062
+ const configuredInterval = configRef.current?.interval;
13063
+ const interval = typeof configuredInterval === "function" ? configuredInterval(attemptsRef.current) : configuredInterval ?? DEFAULT_POLL_INTERVAL;
13064
+ timeoutRef.current = setTimeout(doPoll, interval);
13065
+ }
12715
13066
  };
12716
13067
  doPoll();
12717
- }, [poll]);
13068
+ }, [
13069
+ attemptsRef,
13070
+ configRef,
13071
+ isActiveRef,
13072
+ poll,
13073
+ timeoutRef
13074
+ ]);
13075
+ }
13076
+ function usePollingCycle(config, runtime, dispatch) {
13077
+ const cleanup = usePollingCleanup(runtime);
13078
+ const resetState = usePollingReset(runtime, dispatch);
13079
+ const schedulePoll = usePollingScheduler(runtime, usePollingRequest(runtime, dispatch, cleanup));
13080
+ const pollingEnabled = config !== null;
12718
13081
  useEffect(() => {
12719
- if (!config) {
13082
+ if (!pollingEnabled) {
12720
13083
  cleanup();
12721
13084
  dispatch({ type: "polling-went-idle" });
12722
13085
  return;
12723
13086
  }
12724
13087
  resetState();
12725
- isActiveRef.current = true;
13088
+ runtime.isActiveRef.current = true;
12726
13089
  schedulePoll();
12727
13090
  return cleanup;
12728
13091
  }, [
12729
- config,
12730
13092
  cleanup,
13093
+ dispatch,
13094
+ pollingEnabled,
12731
13095
  resetState,
13096
+ config?.restartKey ?? null,
13097
+ runtime.isActiveRef,
12732
13098
  schedulePoll
12733
13099
  ]);
12734
- const retry = useCallback(() => {
12735
- if (!configRef.current) return;
13100
+ return useCallback(() => {
13101
+ if (!runtime.configRef.current) return;
12736
13102
  cleanup();
12737
13103
  resetState();
12738
- isActiveRef.current = true;
13104
+ runtime.isActiveRef.current = true;
12739
13105
  schedulePoll();
12740
13106
  }, [
12741
13107
  cleanup,
12742
13108
  resetState,
13109
+ runtime.configRef,
13110
+ runtime.isActiveRef,
12743
13111
  schedulePoll
12744
13112
  ]);
13113
+ }
13114
+ /**
13115
+ * Polls until the operation completes, fails, times out, or becomes disabled.
13116
+ * Config objects may be rebuilt across renders; change restartKey to begin a
13117
+ * new operation and reset its attempt budget.
13118
+ */
13119
+ function usePolling(config) {
13120
+ const [state, dispatch] = useReducer(pollingReducer, void 0, createInitialPollingState);
13121
+ const retry = usePollingCycle(config, usePollingRuntime(config), dispatch);
12745
13122
  return {
12746
13123
  status: config ? state.tag : "idle",
12747
13124
  result: config ? state.result : null,
@@ -12751,6 +13128,10 @@ function usePolling(config) {
12751
13128
  }
12752
13129
  //#endregion
12753
13130
  //#region ../blocks/src/system/runtime/hooks/useAppointmentCheckoutVerification.ts
13131
+ const APPOINTMENT_CHECKOUT_MAX_ATTEMPTS = 12;
13132
+ function resolveAppointmentCheckoutPollInterval(attempt) {
13133
+ return Math.min(1e3 * 2 ** (attempt - 1), 4e3);
13134
+ }
12754
13135
  const appointmentCheckoutVerificationDeps = {
12755
13136
  useBlockApi,
12756
13137
  usePolling
@@ -12760,16 +13141,25 @@ function useAppointmentCheckoutVerification(config) {
12760
13141
  }
12761
13142
  function useAppointmentCheckoutVerificationWithDeps(config, deps) {
12762
13143
  const api = deps.useBlockApi();
13144
+ const sessionId = config?.sessionId ?? null;
13145
+ const maxAttempts = config?.maxAttempts;
13146
+ const pollInterval = config?.pollInterval;
12763
13147
  const pollingConfig = useMemo(() => {
12764
- if (!config) return null;
13148
+ if (sessionId === null) return null;
12765
13149
  return {
12766
- pollFn: () => api.getAppointmentBookingStatus({ sessionId: config.sessionId }),
13150
+ restartKey: sessionId,
13151
+ pollFn: () => api.getAppointmentBookingStatus({ sessionId }),
12767
13152
  isComplete: (result) => (result.paymentStatus === "completed" || result.paymentStatus === "not_required") && result.appointmentStatus === "confirmed",
12768
13153
  isFailed: (result) => result.paymentStatus === "failed" || result.paymentStatus === "cancelled" || result.paymentStatus === "refunded" || result.appointmentStatus === "cancelled",
12769
- maxAttempts: config.maxAttempts,
12770
- interval: config.pollInterval
13154
+ maxAttempts: maxAttempts ?? APPOINTMENT_CHECKOUT_MAX_ATTEMPTS,
13155
+ interval: pollInterval ?? resolveAppointmentCheckoutPollInterval
12771
13156
  };
12772
- }, [api, config]);
13157
+ }, [
13158
+ api,
13159
+ sessionId,
13160
+ maxAttempts,
13161
+ pollInterval
13162
+ ]);
12773
13163
  const polling = deps.usePolling(pollingConfig);
12774
13164
  return {
12775
13165
  state: resolveAppointmentCheckoutVerificationState({
@@ -13381,11 +13771,18 @@ function isReservedPathSegment(value) {
13381
13771
  function isUnsafePathSegment(segment) {
13382
13772
  return segment.trim().length === 0 || segment !== segment.trim() || isReservedPathSegment(segment) || containsUnsafePathSegmentCharacter(segment);
13383
13773
  }
13384
- ({
13774
+ //#endregion
13775
+ //#region ../media-core/src/fileStorage.ts
13776
+ const FILE_STORAGE_BUCKETS = {
13385
13777
  publicSite: unsafeAsStorageBucketName("media"),
13386
13778
  privateSite: unsafeAsStorageBucketName("site-files-private"),
13387
- temporary: unsafeAsStorageBucketName("temp-uploads")
13388
- }).publicSite;
13779
+ temporary: unsafeAsStorageBucketName("temp-uploads"),
13780
+ siteAssets: unsafeAsStorageBucketName("site-assets"),
13781
+ siteFonts: unsafeAsStorageBucketName("site-fonts"),
13782
+ bookingRequirementDocuments: unsafeAsStorageBucketName("booking-requirement-documents")
13783
+ };
13784
+ FILE_STORAGE_BUCKETS.publicSite, FILE_STORAGE_BUCKETS.siteAssets, FILE_STORAGE_BUCKETS.siteFonts;
13785
+ FILE_STORAGE_BUCKETS.publicSite, FILE_STORAGE_BUCKETS.privateSite, FILE_STORAGE_BUCKETS.temporary, FILE_STORAGE_BUCKETS.siteAssets, FILE_STORAGE_BUCKETS.siteFonts, FILE_STORAGE_BUCKETS.bookingRequirementDocuments;
13389
13786
  function parseStoragePath(value) {
13390
13787
  return joinStoragePathSegments(value.split("/"));
13391
13788
  }
@@ -14175,7 +14572,7 @@ function DefaultServiceChoices({ booking }) {
14175
14572
  })]
14176
14573
  }, group.key))
14177
14574
  });
14178
- default: return assertNever(layout);
14575
+ default: return assertNever$1(layout);
14179
14576
  }
14180
14577
  }
14181
14578
  function ServiceChoiceGrid({ booking, choices }) {
@@ -14211,6 +14608,72 @@ function ServiceChoiceGrid({ booking, choices }) {
14211
14608
  });
14212
14609
  }
14213
14610
  //#endregion
14611
+ //#region ../blocks/src/system/runtime/nodes/booking-form.submit-actions.tsx
14612
+ function resolvePrimaryActionLabel(isLastStep, requiresPayment) {
14613
+ if (!isLastStep) return "Continue";
14614
+ return requiresPayment ? "Continue to payment" : "Complete";
14615
+ }
14616
+ function formatBookingConfirmationDateTime(booking) {
14617
+ const startAt = booking.currentStep?.id === "datetime-selection" ? booking.availability.selectedSlot?.startAt : void 0;
14618
+ return startAt ? new Intl.DateTimeFormat(void 0, {
14619
+ dateStyle: "medium",
14620
+ timeStyle: "short",
14621
+ timeZone: booking.availability.timezone
14622
+ }).format(new Date(startAt)) : null;
14623
+ }
14624
+ function BookingPaymentConfirmationText({ booking, summary }) {
14625
+ if (!summary) return null;
14626
+ const dateTime = formatBookingConfirmationDateTime(booking);
14627
+ return /* @__PURE__ */ jsxs("p", {
14628
+ className: "ab-text rb-on-surface--muted",
14629
+ children: [
14630
+ summary.serviceTitle,
14631
+ " · ",
14632
+ summary.durationMinutes,
14633
+ " min ·",
14634
+ " ",
14635
+ formatCurrencyAmount(summary.priceAmount, summary.priceCurrency, { decimals: "auto" }),
14636
+ dateTime ? ` · ${dateTime}` : ""
14637
+ ]
14638
+ });
14639
+ }
14640
+ function BookingFormSubmitActions({ booking, onSubmit }) {
14641
+ const currentStepIndex = booking.currentStep?.visibleIndex ?? 0;
14642
+ const isFirstStep = currentStepIndex === 0;
14643
+ const isLastStep = currentStepIndex === booking.steps.length - 1;
14644
+ const isSubmitting = booking.status.tag === "submitting";
14645
+ const paymentSummary = isLastStep && booking.payment.kind === "ok" ? booking.payment.confirmationSummary : null;
14646
+ const handlePrimaryAction = async () => {
14647
+ if ((await booking.actions.next()).ok && isLastStep) await onSubmit();
14648
+ };
14649
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(BookingPaymentConfirmationText, {
14650
+ booking,
14651
+ summary: paymentSummary
14652
+ }), /* @__PURE__ */ jsxs("div", {
14653
+ className: "rb-wizard-actions",
14654
+ children: [!isFirstStep ? /* @__PURE__ */ jsx(ThemedButton, {
14655
+ type: "button",
14656
+ onClick: booking.actions.back,
14657
+ variant: "outline",
14658
+ size: "md",
14659
+ label: "Back"
14660
+ }) : null, /* @__PURE__ */ jsx(ThemedButton, {
14661
+ type: "button",
14662
+ onClick: () => {
14663
+ handlePrimaryAction();
14664
+ },
14665
+ disabled: isSubmitting,
14666
+ variant: "primary",
14667
+ size: "md",
14668
+ label: resolvePrimaryActionLabel(isLastStep, Boolean(paymentSummary)),
14669
+ pending: isSubmitting ? {
14670
+ label: "Submitting...",
14671
+ srLabel: "Submitting"
14672
+ } : void 0
14673
+ })]
14674
+ })] });
14675
+ }
14676
+ //#endregion
14214
14677
  //#region ../blocks/src/system/runtime/nodes/booking-form.default-ui.tsx
14215
14678
  function formatBookingAmount(amount, currency) {
14216
14679
  return formatCurrencyAmount(amount, currency, { decimals: "auto" });
@@ -14219,13 +14682,6 @@ function HeadlessBookingDefaultForm({ booking, onSubmit }) {
14219
14682
  const currentStep = booking.currentStep;
14220
14683
  const errorSummaryId = React.useId();
14221
14684
  const currentStepIndex = currentStep?.visibleIndex ?? 0;
14222
- const isFirstStep = currentStepIndex === 0;
14223
- const isLastStep = currentStepIndex === booking.steps.length - 1;
14224
- const isSubmitting = booking.status.tag === "submitting";
14225
- const handlePrimaryAction = async () => {
14226
- if (!(await booking.actions.next()).ok) return;
14227
- if (isLastStep) await onSubmit();
14228
- };
14229
14685
  if (!currentStep) return /* @__PURE__ */ jsx("div", {
14230
14686
  className: "rb-text-center rb-py-12",
14231
14687
  children: /* @__PURE__ */ jsx("p", {
@@ -14253,28 +14709,9 @@ function HeadlessBookingDefaultForm({ booking, onSubmit }) {
14253
14709
  errors: currentStep.errors,
14254
14710
  id: errorSummaryId
14255
14711
  }),
14256
- /* @__PURE__ */ jsxs("div", {
14257
- className: "rb-wizard-actions",
14258
- children: [!isFirstStep ? /* @__PURE__ */ jsx(ThemedButton, {
14259
- type: "button",
14260
- onClick: booking.actions.back,
14261
- variant: "outline",
14262
- size: "md",
14263
- label: "Back"
14264
- }) : null, /* @__PURE__ */ jsx(ThemedButton, {
14265
- type: "button",
14266
- onClick: () => {
14267
- handlePrimaryAction();
14268
- },
14269
- disabled: isSubmitting,
14270
- variant: "primary",
14271
- size: "md",
14272
- label: isLastStep ? "Complete" : "Continue",
14273
- pending: isSubmitting ? {
14274
- label: "Submitting...",
14275
- srLabel: "Submitting"
14276
- } : void 0
14277
- })]
14712
+ /* @__PURE__ */ jsx(BookingFormSubmitActions, {
14713
+ booking,
14714
+ onSubmit
14278
14715
  }),
14279
14716
  /* @__PURE__ */ jsx(DefaultBookingDiscount, { booking }),
14280
14717
  /* @__PURE__ */ jsx(DefaultBookingFeedback, { booking }),
@@ -14296,7 +14733,7 @@ function DefaultBookingStepContent({ booking, errorSummaryId }) {
14296
14733
  fields: booking.fields.items,
14297
14734
  booking
14298
14735
  });
14299
- default: return assertNever(stepId);
14736
+ default: return assertNever$1(stepId);
14300
14737
  }
14301
14738
  }
14302
14739
  function DefaultServiceSelectionStep({ booking }) {
@@ -14985,27 +15422,167 @@ function TerminalPanel({ tone, title, titleAs: Title = "h3", body, secondaryBody
14985
15422
  "data-terminal-title": true,
14986
15423
  children: title
14987
15424
  }),
14988
- body ? /* @__PURE__ */ jsx("div", {
14989
- className: joinClasses(bodyClassName),
14990
- "data-terminal-body": true,
14991
- children: body
14992
- }) : null,
14993
- actions ? /* @__PURE__ */ jsx("div", {
14994
- className: joinClasses(actionsClassName),
14995
- "data-terminal-actions": true,
14996
- children: actions
15425
+ body ? /* @__PURE__ */ jsx("div", {
15426
+ className: joinClasses(bodyClassName),
15427
+ "data-terminal-body": true,
15428
+ children: body
15429
+ }) : null,
15430
+ actions ? /* @__PURE__ */ jsx("div", {
15431
+ className: joinClasses(actionsClassName),
15432
+ "data-terminal-actions": true,
15433
+ children: actions
15434
+ }) : null,
15435
+ secondaryBody ? /* @__PURE__ */ jsx("div", {
15436
+ className: joinClasses(secondaryBodyClassName),
15437
+ "data-terminal-secondary-body": true,
15438
+ children: secondaryBody
15439
+ }) : null
15440
+ ]
15441
+ });
15442
+ }
15443
+ //#endregion
15444
+ //#region ../blocks/src/system/runtime/shared/utils/demoPortalMagicLink.ts
15445
+ const CUSTOMER_PORTAL_PATH = "/portal";
15446
+ function buildPortalCallbackUrl(origin, redirectTo) {
15447
+ const url = new URL("/api/portal/callback", origin);
15448
+ url.searchParams.set("redirect_to", redirectTo);
15449
+ return url.toString();
15450
+ }
15451
+ async function requestDemoPortalMagicLink(input) {
15452
+ const email = normalizeDemoBookingEmail(input.email);
15453
+ const pass = getDemoBookingPass(email);
15454
+ const request = {
15455
+ email,
15456
+ redirectUrl: input.redirectUrl,
15457
+ ...pass ? { demoBookingPass: pass } : {}
15458
+ };
15459
+ try {
15460
+ const response = await input.send(request);
15461
+ if ("kind" in response) return {
15462
+ kind: "refused",
15463
+ message: response.message
15464
+ };
15465
+ return "demoSignInUrl" in response ? {
15466
+ kind: "demo_sign_in",
15467
+ url: response.demoSignInUrl
15468
+ } : { kind: "email_sent" };
15469
+ } catch (error) {
15470
+ if (error instanceof BlockApiError && error.tag === "demo_email_not_booked_here") return {
15471
+ kind: "refused",
15472
+ message: error.message
15473
+ };
15474
+ throw error;
15475
+ }
15476
+ }
15477
+ //#endregion
15478
+ //#region ../blocks/src/system/runtime/shared/components/DemoBookingPortalAccess.tsx
15479
+ const SUPPRESSED_CONFIRMATION_NOTE = "This is a demo, so we haven’t sent a confirmation email. You can still see your booking in the customer portal.";
15480
+ function BookingConfirmation(props) {
15481
+ const content = renderConfirmationMessage((props.demoEmailSuppressed ? [props.copy.message] : [props.copy.message, props.copy.defaultEmailSentence ?? ""]).filter((part) => part.trim().length > 0).join(" "), props.messagePresentation);
15482
+ if (!props.demoEmailSuppressed) return content;
15483
+ return /* @__PURE__ */ jsxs(Fragment, { children: [content, /* @__PURE__ */ jsx(DemoBookingPortalAccess, {
15484
+ email: props.email,
15485
+ noteClassName: props.noteClassName,
15486
+ showConfirmationNote: props.showConfirmationNote
15487
+ })] });
15488
+ }
15489
+ function DemoBookingPortalAccess(props) {
15490
+ const { state, openPortal } = useDemoBookingPortalAccess(props.email);
15491
+ return /* @__PURE__ */ jsxs("div", {
15492
+ className: "rb-mt-4 rb-flex rb-flex-col rb-items-start rb-gap-3",
15493
+ "data-testid": "demo-booking-portal-access",
15494
+ children: [
15495
+ props.showConfirmationNote === false ? null : /* @__PURE__ */ jsx("p", {
15496
+ className: props.noteClassName ?? "ab-text",
15497
+ children: SUPPRESSED_CONFIRMATION_NOTE
15498
+ }),
15499
+ /* @__PURE__ */ jsx(ThemedButton, {
15500
+ type: "button",
15501
+ variant: "default",
15502
+ size: "md",
15503
+ label: state.tag === "opening" ? "Opening…" : "Open the customer portal",
15504
+ disabled: state.tag === "opening",
15505
+ onClick: openPortal
15506
+ }),
15507
+ state.tag === "refused" ? /* @__PURE__ */ jsx("p", {
15508
+ role: "alert",
15509
+ children: state.message
14997
15510
  }) : null,
14998
- secondaryBody ? /* @__PURE__ */ jsx("div", {
14999
- className: joinClasses(secondaryBodyClassName),
15000
- "data-terminal-secondary-body": true,
15001
- children: secondaryBody
15511
+ state.tag === "error" ? /* @__PURE__ */ jsx("p", {
15512
+ role: "alert",
15513
+ children: state.message
15002
15514
  }) : null
15003
15515
  ]
15004
15516
  });
15005
15517
  }
15518
+ function renderConfirmationMessage(message, presentation) {
15519
+ if (!message) return null;
15520
+ switch (presentation.kind) {
15521
+ case "paragraph": return /* @__PURE__ */ jsx("p", {
15522
+ className: presentation.className,
15523
+ children: message
15524
+ });
15525
+ case "plain": return message;
15526
+ }
15527
+ }
15528
+ function useDemoBookingPortalAccess(email) {
15529
+ const api = useBlockApi();
15530
+ const [state, setState] = React.useState({ tag: "idle" });
15531
+ const openPortal = async () => {
15532
+ if (state.tag === "opening") return;
15533
+ if (!email) {
15534
+ setState({
15535
+ tag: "error",
15536
+ message: "We couldn’t open the customer portal. Please try again."
15537
+ });
15538
+ return;
15539
+ }
15540
+ setState({ tag: "opening" });
15541
+ try {
15542
+ const result = await requestDemoPortalMagicLink({
15543
+ email,
15544
+ redirectUrl: buildPortalCallbackUrl(window.location.origin, CUSTOMER_PORTAL_PATH),
15545
+ send: (request) => api.sendMagicLink(request)
15546
+ });
15547
+ switch (result.kind) {
15548
+ case "demo_sign_in":
15549
+ window.location.assign(result.url);
15550
+ return;
15551
+ case "refused":
15552
+ setState({
15553
+ tag: "refused",
15554
+ message: result.message
15555
+ });
15556
+ return;
15557
+ case "email_sent":
15558
+ setState({ tag: "idle" });
15559
+ return;
15560
+ }
15561
+ } catch (error) {
15562
+ setState(handlePortalAccessError(error));
15563
+ }
15564
+ };
15565
+ return {
15566
+ state,
15567
+ openPortal
15568
+ };
15569
+ }
15570
+ function handlePortalAccessError(error) {
15571
+ if (error instanceof BlockApiError && error.tag === "demo_email_not_booked_here") return {
15572
+ tag: "refused",
15573
+ message: error.message
15574
+ };
15575
+ return error instanceof BlockApiError ? {
15576
+ tag: "error",
15577
+ message: error.message
15578
+ } : {
15579
+ tag: "error",
15580
+ message: "We couldn’t open the customer portal. Please try again."
15581
+ };
15582
+ }
15006
15583
  //#endregion
15007
15584
  //#region ../blocks/src/system/runtime/components/booking/SuccessMessage.tsx
15008
- const SuccessMessage = ({ message, resourceName, className }) => {
15585
+ const SuccessMessage = ({ copy, resourceName, className, demoEmailSuppressed = false, customerEmail = null }) => {
15009
15586
  return /* @__PURE__ */ jsx(TerminalPanel, {
15010
15587
  tone: "success",
15011
15588
  title: "Booking confirmed",
@@ -15013,9 +15590,15 @@ const SuccessMessage = ({ message, resourceName, className }) => {
15013
15590
  variant: "success",
15014
15591
  children: /* @__PURE__ */ jsx(CheckIcon, { strokeWidth: 3 })
15015
15592
  }),
15016
- body: /* @__PURE__ */ jsx("p", {
15017
- className: "ab-text",
15018
- children: message
15593
+ body: /* @__PURE__ */ jsx(BookingConfirmation, {
15594
+ demoEmailSuppressed,
15595
+ email: customerEmail,
15596
+ copy,
15597
+ messagePresentation: {
15598
+ kind: "paragraph",
15599
+ className: "ab-text"
15600
+ },
15601
+ noteClassName: "ab-text"
15019
15602
  }),
15020
15603
  secondaryBody: resourceName ? /* @__PURE__ */ jsxs("p", {
15021
15604
  className: "ab-text rb-on-surface--muted",
@@ -15051,31 +15634,54 @@ function BookingMailingListNote(props) {
15051
15634
  });
15052
15635
  }
15053
15636
  //#endregion
15054
- //#region ../blocks/src/system/runtime/nodes/booking-form.mailing-list-note.ts
15637
+ //#region ../blocks/src/system/runtime/nodes/booking-form.checkout-return-context.ts
15055
15638
  function storageKey(sessionId) {
15056
15639
  return `riverbank:booking:mailing-list:${sessionId}`;
15057
15640
  }
15058
- function saveAppointmentMailingListNote(sessionId, note) {
15059
- if (!note) return;
15641
+ function saveAppointmentCheckoutReturnContext(sessionId, context) {
15642
+ if (!context.customerEmail && !context.mailingListNote) return;
15060
15643
  try {
15061
- window.sessionStorage.setItem(storageKey(sessionId), note);
15644
+ window.sessionStorage.setItem(storageKey(sessionId), JSON.stringify(context));
15062
15645
  } catch {}
15063
15646
  }
15064
- function readAppointmentMailingListNote(sessionId) {
15647
+ function readAppointmentCheckoutReturnContext(sessionId) {
15065
15648
  try {
15066
15649
  const stored = window.sessionStorage.getItem(storageKey(sessionId));
15067
- return stored === "confirmation_required" || stored === "not_confirmed" ? stored : null;
15650
+ if (!stored) return null;
15651
+ return parseContext(stored);
15068
15652
  } catch {
15069
15653
  return null;
15070
15654
  }
15071
15655
  }
15656
+ function parseContext(value) {
15657
+ try {
15658
+ const parsed = JSON.parse(value);
15659
+ return isContext(parsed) ? parsed : null;
15660
+ } catch {
15661
+ return value === "confirmation_required" || value === "not_confirmed" ? {
15662
+ customerEmail: null,
15663
+ mailingListNote: value
15664
+ } : null;
15665
+ }
15666
+ }
15667
+ function isContext(value) {
15668
+ if (!isRecord$2(value)) return false;
15669
+ return (typeof value.customerEmail === "string" || value.customerEmail === null) && (value.mailingListNote === null || value.mailingListNote === "confirmation_required" || value.mailingListNote === "not_confirmed");
15670
+ }
15671
+ function isRecord$2(value) {
15672
+ return typeof value === "object" && value !== null && !Array.isArray(value);
15673
+ }
15072
15674
  //#endregion
15073
15675
  //#region ../blocks/src/system/runtime/nodes/booking-form.completion.tsx
15074
- function BookingFormCompletion({ resourceName, successMessage, redirectState, localNote }) {
15075
- const note = redirectState.kind === "success" ? readAppointmentMailingListNote(redirectState.sessionId) : localNote;
15676
+ function BookingFormCompletion({ resourceName, successMessage, redirectState, localNote, customerEmail, demoEmailSuppressed = false }) {
15677
+ const returnContext = redirectState.kind === "success" ? readAppointmentCheckoutReturnContext(redirectState.sessionId) : null;
15678
+ const note = redirectState.kind === "success" ? returnContext?.mailingListNote ?? null : localNote;
15679
+ const confirmedEmail = returnContext?.customerEmail ?? customerEmail;
15076
15680
  return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(SuccessMessage, {
15077
- message: getBookingSuccessMessage(successMessage),
15078
- resourceName
15681
+ copy: getBookingSuccessCopy(successMessage),
15682
+ resourceName,
15683
+ demoEmailSuppressed,
15684
+ customerEmail: confirmedEmail
15079
15685
  }), note ? /* @__PURE__ */ jsx(BookingMailingListNote, {
15080
15686
  note,
15081
15687
  context: "booking",
@@ -15099,12 +15705,17 @@ function createBookingFormSubmitHandler(input) {
15099
15705
  cancelUrl: appendRebookFlag(cancelUrl, input.isPortalRebook)
15100
15706
  });
15101
15707
  if (!result.ok) return;
15708
+ storeDemoBookingPassIfAvailable(result.outcome.customerEmail, result.outcome.demoBookingPass);
15102
15709
  if (result.outcome.kind === "checkout_redirect") {
15103
- saveAppointmentMailingListNote(result.outcome.sessionId, result.outcome.mailingListSignupNote);
15710
+ saveAppointmentCheckoutReturnContext(result.outcome.sessionId, {
15711
+ customerEmail: result.outcome.customerEmail,
15712
+ mailingListNote: result.outcome.mailingListSignupNote ?? null
15713
+ });
15104
15714
  window.location.href = result.outcome.checkoutUrl;
15105
15715
  return;
15106
15716
  }
15107
15717
  input.setLocalMailingListNote(result.outcome.mailingListSignupNote ?? null);
15718
+ input.setLocalCustomerEmail(result.outcome.customerEmail);
15108
15719
  };
15109
15720
  }
15110
15721
  //#endregion
@@ -15144,6 +15755,7 @@ const BookingFormClient$1 = ({ siteId: siteIdProp, render }) => {
15144
15755
  const hasLoggedRebookCompletionRef = useRef(false);
15145
15756
  const [redirectState] = useState(() => getBookingRedirectStateFromLocation(getBookingRedirectLocationSnapshot()));
15146
15757
  const [localMailingListNote, setLocalMailingListNote] = useState(null);
15758
+ const [localCustomerEmail, setLocalCustomerEmail] = useState(null);
15147
15759
  const showSpamProtection = render.hydration.spamProtectionEnabled ?? isSpamProtectionEnabled();
15148
15760
  const api = useBlockApi();
15149
15761
  const hasPortalAuth = api.config.auth.type === "bearer" || api.config.authOverrides?.portal?.type === "bearer";
@@ -15226,7 +15838,8 @@ const BookingFormClient$1 = ({ siteId: siteIdProp, render }) => {
15226
15838
  booking,
15227
15839
  bookingAnchorId,
15228
15840
  isPortalRebook,
15229
- setLocalMailingListNote
15841
+ setLocalMailingListNote,
15842
+ setLocalCustomerEmail
15230
15843
  });
15231
15844
  if (viewState.kind === "success") return /* @__PURE__ */ jsx(BookingSurface, {
15232
15845
  id: bookingAnchorId,
@@ -15235,7 +15848,9 @@ const BookingFormClient$1 = ({ siteId: siteIdProp, render }) => {
15235
15848
  successMessage: render.display.successMessage,
15236
15849
  resourceName: viewState.resourceName,
15237
15850
  redirectState,
15238
- localNote: localMailingListNote
15851
+ localNote: localMailingListNote,
15852
+ customerEmail: localCustomerEmail,
15853
+ demoEmailSuppressed: render.hydration.demoEmailSuppressed
15239
15854
  })
15240
15855
  });
15241
15856
  if (viewState.kind === "verifying") return /* @__PURE__ */ jsx(BookingSurface, {
@@ -15251,6 +15866,25 @@ const BookingFormClient$1 = ({ siteId: siteIdProp, render }) => {
15251
15866
  })
15252
15867
  })
15253
15868
  });
15869
+ if (viewState.kind === "timeout") return /* @__PURE__ */ jsxs(BookingSurface, {
15870
+ id: bookingAnchorId,
15871
+ className: render.display.className,
15872
+ children: [/* @__PURE__ */ jsx(FeedbackMessage, {
15873
+ tone: "info",
15874
+ className: "alert alert-info",
15875
+ role: "status",
15876
+ children: /* @__PURE__ */ jsx("p", {
15877
+ className: "ab-text",
15878
+ children: viewState.message
15879
+ })
15880
+ }), /* @__PURE__ */ jsx(ThemedButton, {
15881
+ type: "button",
15882
+ variant: "primary",
15883
+ size: "md",
15884
+ label: "Check again",
15885
+ onClick: verification.retry
15886
+ })]
15887
+ });
15254
15888
  return /* @__PURE__ */ jsxs(BookingSurface, {
15255
15889
  id: bookingAnchorId,
15256
15890
  className: render.display.className,
@@ -15311,7 +15945,7 @@ function recoverRegistrationError(action, handlers) {
15311
15945
  switch (action) {
15312
15946
  case "none": return;
15313
15947
  case "portal":
15314
- window.location.assign("/portal");
15948
+ window.location.assign(CUSTOMER_PORTAL_PATH);
15315
15949
  return;
15316
15950
  case "event":
15317
15951
  window.location.assign(window.location.pathname);
@@ -15566,7 +16200,7 @@ function eligibilityLookupReducer(state, action) {
15566
16200
  settledRequestKey: null,
15567
16201
  error: action.message
15568
16202
  };
15569
- default: return assertNever(action);
16203
+ default: return assertNever$1(action);
15570
16204
  }
15571
16205
  }
15572
16206
  const initialExistingRegistrationLookupState = {
@@ -15584,7 +16218,7 @@ function existingRegistrationLookupReducer(state, action) {
15584
16218
  tag: "resolved",
15585
16219
  registration: action.registration
15586
16220
  };
15587
- default: return assertNever(action);
16221
+ default: return assertNever$1(action);
15588
16222
  }
15589
16223
  }
15590
16224
  //#endregion
@@ -15838,157 +16472,6 @@ function logoutPortal(anchorId) {
15838
16472
  form.submit();
15839
16473
  }
15840
16474
  //#endregion
15841
- //#region ../commerce/src/purchase/checkoutSessionMetadata.ts
15842
- const datedOfferingSharedEngineMetadataShape = {
15843
- datedOfferingEngineContractVersion: z.literal("shared_v1"),
15844
- datedOfferingEngineRouteKind: z.literal("shared_whole_series_registration"),
15845
- datedOfferingCapacityHoldId: z.string().uuid(),
15846
- datedOfferingCapacityHoldAuditRef: z.string().uuid(),
15847
- customerId: z.string().uuid(),
15848
- eventSeriesId: z.string().uuid()
15849
- };
15850
- z.object(datedOfferingSharedEngineMetadataShape);
15851
- const orderCheckoutSessionMetadataBaseShape = {
15852
- type: z.literal("order"),
15853
- site_id: z.string().uuid(),
15854
- order_id: z.string().uuid().optional(),
15855
- customer_email: z.string().email(),
15856
- customer_name: z.string().optional(),
15857
- product_id: z.string().uuid().optional(),
15858
- attendee_id: z.string().uuid().optional(),
15859
- occurrence_id: z.string().uuid().optional(),
15860
- tickets_count: z.string().optional(),
15861
- notes: z.string().optional(),
15862
- discount_redemption_id: z.string().uuid().optional(),
15863
- discount_code_id: z.string().uuid().optional(),
15864
- discount_code: z.string().optional(),
15865
- discount_public_label: z.string().optional(),
15866
- credit_reservation_id: z.string().uuid().optional(),
15867
- credit_reserved_cents: z.string().optional(),
15868
- discount_code_amount_cents: z.string().optional(),
15869
- order_payment_reason: z.enum([
15870
- "instalment_payoff",
15871
- "flexible_balance_initial",
15872
- "flexible_balance_paydown"
15873
- ]).optional(),
15874
- order_payment_plan_id: z.string().uuid().optional(),
15875
- order_flexible_balance_contract_id: z.string().uuid().optional()
15876
- };
15877
- const absentDatedOfferingSharedEngineMetadataShape = {
15878
- datedOfferingEngineContractVersion: z.never().optional(),
15879
- datedOfferingEngineRouteKind: z.never().optional(),
15880
- datedOfferingCapacityHoldId: z.never().optional(),
15881
- datedOfferingCapacityHoldAuditRef: z.never().optional(),
15882
- customerId: z.never().optional(),
15883
- eventSeriesId: z.never().optional()
15884
- };
15885
- const LegacyOrderCheckoutSessionMetadataSchema = z.object({
15886
- ...orderCheckoutSessionMetadataBaseShape,
15887
- ...absentDatedOfferingSharedEngineMetadataShape
15888
- });
15889
- const SharedDatedOfferingOrderCheckoutSessionMetadataSchema = z.object({
15890
- ...orderCheckoutSessionMetadataBaseShape,
15891
- ...datedOfferingSharedEngineMetadataShape
15892
- });
15893
- z.union([SharedDatedOfferingOrderCheckoutSessionMetadataSchema, LegacyOrderCheckoutSessionMetadataSchema]);
15894
- //#endregion
15895
- //#region ../commerce/src/purchase/stripeCommissionMetadata.ts
15896
- /** Reasons are payment evidence, not an independent pricing policy. */
15897
- const STRIPE_COMMISSION_FREE_REASONS = [
15898
- "managed_billing",
15899
- "no_commission_plan",
15900
- "billing_evidence_invalid",
15901
- "fee_rounds_to_zero",
15902
- "payment_not_stripe"
15903
- ];
15904
- const historicalContext = {
15905
- currency: z.string().refine((value) => parseCurrencyCode(value) !== null).optional(),
15906
- sourcePlanId: z.string().trim().min(1).optional()
15907
- };
15908
- const percentSchema = z.number().finite().min(0).max(100);
15909
- z.discriminatedUnion("kind", [
15910
- z.object({
15911
- kind: z.literal("commission_free"),
15912
- reason: z.enum(STRIPE_COMMISSION_FREE_REASONS),
15913
- ...historicalContext
15914
- }),
15915
- z.object({
15916
- kind: z.literal("application_fee_amount"),
15917
- amountCents: z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER),
15918
- percent: percentSchema,
15919
- ...historicalContext
15920
- }),
15921
- z.object({
15922
- kind: z.literal("application_fee_percent"),
15923
- percent: percentSchema,
15924
- ...historicalContext
15925
- })
15926
- ]);
15927
- toNonNegativeCents(0);
15928
- //#endregion
15929
- //#region ../commerce/src/purchase/event-registration-errors.ts
15930
- const eventRegistrationErrors = {
15931
- registrationClosed: {
15932
- message: "Booking is currently closed for this event. Please contact the organiser if you’d like to find out more.",
15933
- action: "none"
15934
- },
15935
- paymentInvestigationRequired: {
15936
- message: "We still can’t confirm your payment. Please don’t make another payment. Contact the organiser so they can check your booking.",
15937
- action: "none"
15938
- },
15939
- paymentProviderUnavailable: {
15940
- message: "We couldn’t reach the payment provider. Please try again in a minute.",
15941
- action: "retry"
15942
- },
15943
- paymentPageUnavailable: {
15944
- message: "We couldn’t open the payment page. Please refresh this page and try again. If this keeps happening, contact the organiser for help.",
15945
- action: "retry"
15946
- },
15947
- paymentUnavailable: {
15948
- message: "Online payment is not available for this event right now. Please contact the organiser for help with booking.",
15949
- action: "none"
15950
- },
15951
- capacityChanged: {
15952
- message: "Sorry, there aren’t enough places left for your selection. Please check the available places and choose again.",
15953
- action: "places"
15954
- },
15955
- selectionChanged: {
15956
- message: "The booking options for this event have changed. Please check the latest options and choose your places again.",
15957
- action: "places"
15958
- },
15959
- registrationPreparationChanged: {
15960
- message: "The booking options for this event have changed. Please check the latest options and choose your places again.",
15961
- action: "places"
15962
- },
15963
- registrationAlreadyExists: {
15964
- message: "You already have a booking for this event. Please check your bookings to see its status. If you need help, contact the organiser.",
15965
- action: "portal"
15966
- },
15967
- holdExpired: {
15968
- message: "Your reservation has timed out. Please check availability and choose your places again.",
15969
- action: "start"
15970
- },
15971
- waitlistUnavailable: {
15972
- message: "Sorry, the waiting list place offered in this invitation is no longer available. Please check the event for available places or contact the organiser for help.",
15973
- action: "event"
15974
- },
15975
- paymentContextMismatch: {
15976
- message: "The payment options for this event have changed. Please check the latest options before continuing.",
15977
- action: "payment-options"
15978
- },
15979
- idempotencyConflict: {
15980
- message: "You’ve already started booking this event. Please finish in the other tab if it’s still open, or check your booking status before starting again.",
15981
- action: "portal"
15982
- },
15983
- invalidCommitInput: {
15984
- message: "We couldn’t accept your booking details. Please check the information you entered and try again. If this keeps happening, contact the organiser for help.",
15985
- action: "details"
15986
- }
15987
- };
15988
- function parseEventRegistrationErrorReason(value) {
15989
- return typeof value === "string" && Object.prototype.hasOwnProperty.call(eventRegistrationErrors, value) ? value : null;
15990
- }
15991
- //#endregion
15992
16475
  //#region ../blocks/src/system/runtime/shared/useWaitlistClaim.state.ts
15993
16476
  const DEFAULT_WAITLIST_CLAIM_ERROR = "Online booking is unavailable right now. Please contact the organiser for help with booking.";
15994
16477
  function createInitialWaitlistClaimState(hasToken) {
@@ -16163,11 +16646,50 @@ function useResolvedWaitlistClaim(deps, credential) {
16163
16646
  * ```
16164
16647
  */
16165
16648
  const paymentVerificationDeps = { useBlockApi };
16649
+ function resolvePaymentPollingTarget(config) {
16650
+ const reference = config.reference;
16651
+ return reference.scope === "occurrence" ? {
16652
+ key: `occurrence:${reference.attendeeId}`,
16653
+ reference
16654
+ } : {
16655
+ key: `wholeSeries:${reference.registrationId}`,
16656
+ reference
16657
+ };
16658
+ }
16659
+ function createPaymentPollingConfig(api, settings) {
16660
+ if (settings === null) return null;
16661
+ const target = resolvePaymentPollingTarget(settings);
16662
+ return {
16663
+ restartKey: target.key,
16664
+ pollFn: () => api.getEventRegistrationStatus(target.reference),
16665
+ isComplete: (result) => result.paymentStatus === "completed" || result.paymentStatus === "not_required",
16666
+ isFailed: (result) => result.paymentStatus === "failed" || result.paymentStatus === "refunded",
16667
+ maxAttempts: settings.maxAttempts,
16668
+ interval: settings.pollInterval
16669
+ };
16670
+ }
16671
+ function getPaymentVerificationError(polling, paymentStatus) {
16672
+ if (polling.status === "timeout") return "Could not verify payment. If you were charged, please contact support.";
16673
+ if (polling.status === "failed" && paymentStatus !== null) return paymentStatus === "refunded" ? "Payment was refunded. Please contact support." : "Payment was declined. Please try again.";
16674
+ return polling.error?.message ?? null;
16675
+ }
16676
+ function mapPaymentVerificationResult(polling) {
16677
+ const paymentStatus = polling.result?.paymentStatus ?? null;
16678
+ return {
16679
+ status: polling.status,
16680
+ paymentStatus,
16681
+ attendeeStatus: polling.result?.attendeeStatus ?? null,
16682
+ waitlistPosition: polling.result?.waitlistPosition ?? null,
16683
+ error: getPaymentVerificationError(polling, paymentStatus),
16684
+ retry: polling.retry
16685
+ };
16686
+ }
16166
16687
  /**
16167
16688
  * Hook for polling payment status after Stripe redirects.
16168
16689
  *
16169
16690
  * Pass config to start polling, or null to stop/idle.
16170
- * The hook handles cleanup on unmount and config changes.
16691
+ * The hook handles cleanup on unmount and starts a new cycle when the status
16692
+ * reference changes.
16171
16693
  *
16172
16694
  * @param config - Configuration for polling, or null to stop
16173
16695
  * @returns Verification result with status, data, and retry function
@@ -16176,30 +16698,7 @@ function usePaymentVerification(config) {
16176
16698
  return usePaymentVerificationWithDeps(config, paymentVerificationDeps);
16177
16699
  }
16178
16700
  function usePaymentVerificationWithDeps(config, deps) {
16179
- const api = deps.useBlockApi();
16180
- const polling = usePolling(useMemo(() => {
16181
- if (!config) return null;
16182
- return {
16183
- pollFn: () => api.getEventRegistrationStatus(config.reference),
16184
- isComplete: (result) => result.paymentStatus === "completed" || result.paymentStatus === "not_required",
16185
- isFailed: (result) => result.paymentStatus === "failed" || result.paymentStatus === "refunded",
16186
- maxAttempts: config.maxAttempts,
16187
- interval: config.pollInterval
16188
- };
16189
- }, [api, config]));
16190
- const paymentStatus = polling.result?.paymentStatus ?? null;
16191
- let errorMessage = null;
16192
- if (polling.status === "timeout") errorMessage = "Could not verify payment. If you were charged, please contact support.";
16193
- else if (polling.status === "failed" && paymentStatus) errorMessage = paymentStatus === "refunded" ? "Payment was refunded. Please contact support." : "Payment was declined. Please try again.";
16194
- else if (polling.error) errorMessage = polling.error.message;
16195
- return {
16196
- status: polling.status,
16197
- paymentStatus,
16198
- attendeeStatus: polling.result?.attendeeStatus ?? null,
16199
- waitlistPosition: polling.result?.waitlistPosition ?? null,
16200
- error: errorMessage,
16201
- retry: polling.retry
16202
- };
16701
+ return mapPaymentVerificationResult(usePolling(createPaymentPollingConfig(deps.useBlockApi(), config)));
16203
16702
  }
16204
16703
  //#endregion
16205
16704
  //#region ../blocks/src/system/runtime/nodes/event-registration/constants.ts
@@ -16572,20 +17071,9 @@ function registrationErrorPresentation(error) {
16572
17071
  function wantsMailingListSignup(options) {
16573
17072
  return options.mailingListSignup !== null && options.formData.mailingListOptIn === true;
16574
17073
  }
16575
- function createClientCommandId(cryptoSource = {
16576
- randomUUID: globalThis.crypto.randomUUID?.bind(globalThis.crypto),
16577
- getRandomValues: (bytes) => globalThis.crypto.getRandomValues(bytes)
16578
- }) {
16579
- if (cryptoSource.randomUUID) return cryptoSource.randomUUID();
16580
- const bytes = cryptoSource.getRandomValues(/* @__PURE__ */ new Uint8Array(16));
16581
- bytes[6] = (bytes[6] ?? 0) & 15 | 64;
16582
- bytes[8] = (bytes[8] ?? 0) & 63 | 128;
16583
- const hex = Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0"));
16584
- return `${hex.slice(0, 4).join("")}-${hex.slice(4, 6).join("")}-${hex.slice(6, 8).join("")}-${hex.slice(8, 10).join("")}-${hex.slice(10).join("")}`;
16585
- }
16586
17074
  const eventRegistrationSubmitDeps = {
16587
17075
  savePendingRegistration,
16588
- createClientCommandId
17076
+ createClientCommandId: generateUuidV4
16589
17077
  };
16590
17078
  function useEventRegistrationSubmit(options) {
16591
17079
  return useEventRegistrationSubmitWithDeps(options, eventRegistrationSubmitDeps);
@@ -16665,6 +17153,7 @@ function useEventRegistrationSubmitWithDeps(options, deps) {
16665
17153
  };
16666
17154
  }
16667
17155
  async function completeRegistrationSubmission(options, deps, prepared, result, submitOptions) {
17156
+ if (result.demoBookingPass) storeDemoBookingPass(options.formData.email, result.demoBookingPass);
16668
17157
  switch (result.kind) {
16669
17158
  case "paymentStatusRequired":
16670
17159
  options.setPaymentStatusRecovery({
@@ -16687,6 +17176,7 @@ async function completeRegistrationSubmission(options, deps, prepared, result, s
16687
17176
  status: "waitlist",
16688
17177
  title: "Added to waitlist",
16689
17178
  message: result.waitlist.message,
17179
+ emailFollowupMessage: result.waitlist.emailFollowupMessage,
16690
17180
  mailingListSignupNote: result.mailingListSignupNote
16691
17181
  });
16692
17182
  break;
@@ -16902,6 +17392,7 @@ function buildEventRegistrationPaymentOptionsViewModel(input) {
16902
17392
  priceAmount: input.totalPriceCents,
16903
17393
  priceCurrency: input.currency,
16904
17394
  bookingStartAt: input.startsAt,
17395
+ nowIso: input.nowIso,
16905
17396
  locale: input.locale
16906
17397
  });
16907
17398
  return {
@@ -16909,7 +17400,7 @@ function buildEventRegistrationPaymentOptionsViewModel(input) {
16909
17400
  sectionTitle: selection.sectionTitle,
16910
17401
  options: selection.options.flatMap((option, index) => {
16911
17402
  const sourceOption = approvedOptions[index];
16912
- return sourceOption ? [toEventDirectPaymentOption(option, sourceOption, selection.mode, input.totalPriceCents, input.startsAt)] : [];
17403
+ return sourceOption ? [toEventDirectPaymentOption(option, sourceOption, selection.mode, input.totalPriceCents)] : [];
16913
17404
  })
16914
17405
  };
16915
17406
  }
@@ -16917,11 +17408,10 @@ function selectApprovedEventDirectPaymentOptions(approvedPaymentOptions, payment
16917
17408
  const approvedKinds = new Set(getApprovedDirectPaymentCollectionOptionKinds(approvedPaymentOptions));
16918
17409
  return paymentTerms.allowedOptions.filter((option) => approvedKinds.has(option.kind));
16919
17410
  }
16920
- function toEventDirectPaymentOption(option, sourceOption, mode, totalCents, startsAt) {
17411
+ function toEventDirectPaymentOption(option, sourceOption, mode, totalCents) {
16921
17412
  const configuredPaymentDueNowCents = resolveBookingPaymentDueNowCents({
16922
17413
  option: sourceOption,
16923
- totalCents,
16924
- bookingStartAt: startsAt
17414
+ totalCents
16925
17415
  });
16926
17416
  switch (option.kind) {
16927
17417
  case "upfront": return {
@@ -17908,13 +18398,15 @@ const eventRegistrationWizardDeps = {
17908
18398
  useWaitlistClaim,
17909
18399
  useEventRegistrationStripeReturn,
17910
18400
  useEventRegistrationSubmit,
17911
- useDiscountCodeUi
18401
+ useDiscountCodeUi,
18402
+ useBookingNowIso
17912
18403
  };
17913
18404
  function useEventRegistrationWizard(options) {
17914
18405
  return useEventRegistrationWizardWithDeps(options, eventRegistrationWizardDeps);
17915
18406
  }
17916
18407
  function useEventRegistrationWizardWithDeps(options, deps) {
17917
18408
  const api = useBlockApi();
18409
+ const nowIso = deps.useBookingNowIso();
17918
18410
  const registrationEvents = useMemo(() => [...toRegistrationEvents(options.events ?? []), ...toWholeSeriesRegistrationEvents(options.events ?? [])], [options.events]);
17919
18411
  const scopedEvents = useMemo(() => {
17920
18412
  return resolveEventRegistrationScopedEvents(registrationEvents, {
@@ -18445,6 +18937,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
18445
18937
  });
18446
18938
  return {
18447
18939
  api,
18940
+ nowIso,
18448
18941
  anchorId: options.anchorId,
18449
18942
  occurrenceContext: options.occurrenceContext,
18450
18943
  registrationTarget,
@@ -18573,6 +19066,7 @@ function useEventRegistrationControllerWithDeps(options, deps) {
18573
19066
  const currentStep = steps.find((step) => step.state === "active") ?? null;
18574
19067
  const directPaymentOptions = useMemo(() => resolveHeadlessDirectPaymentOptions(wizard), [
18575
19068
  wizard.eligibility,
19069
+ wizard.nowIso,
18576
19070
  wizard.occurrenceContext,
18577
19071
  wizard.preSelectedEvent,
18578
19072
  wizard.selectedEvent,
@@ -18850,7 +19344,8 @@ function resolveHeadlessDirectPaymentOptions(wizard) {
18850
19344
  paymentTerms: eligibility.paymentTerms,
18851
19345
  totalPriceCents: eligibility.price,
18852
19346
  currency: eligibility.currency,
18853
- startsAt: wizard.occurrenceContext?.startsAt ?? event?.startsAt
19347
+ startsAt: wizard.occurrenceContext?.startsAt ?? event?.startsAt,
19348
+ nowIso: wizard.nowIso
18854
19349
  }).options;
18855
19350
  }
18856
19351
  //#endregion
@@ -18903,7 +19398,7 @@ function bookingFormConfigReducer(state, action) {
18903
19398
  message: action.message,
18904
19399
  previous: toBookingFormConfigSnapshot(state)
18905
19400
  };
18906
- default: return assertNever(action);
19401
+ default: return assertNever$1(action);
18907
19402
  }
18908
19403
  }
18909
19404
  function selectBookingFormConfig(state) {
@@ -18926,7 +19421,7 @@ function toBookingFormConfigSnapshot(state) {
18926
19421
  formConfig: state.formConfig,
18927
19422
  services: state.services
18928
19423
  };
18929
- default: return assertNever(state);
19424
+ default: return assertNever$1(state);
18930
19425
  }
18931
19426
  }
18932
19427
  //#endregion