@riverbankcms/sdk 0.138.0 → 0.139.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.
- package/README.md +11 -15
- package/dist/{PreviewEditorSidebar-BVPur_CU.mjs → PreviewEditorSidebar-BDeenhi3.mjs} +4 -4
- package/dist/{PreviewEditorUI-DLhWX8oh.mjs → PreviewEditorUI-DSRhgjF5.mjs} +3 -3
- package/dist/{PreviewQueryProvider-BguJY1SW.mjs → PreviewQueryProvider-D2K8GLUG.mjs} +1 -1
- package/dist/{SdkPreviewModeRuntime-Tda6qw4z.mjs → SdkPreviewModeRuntime-CL7wSnYu.mjs} +47 -27
- package/dist/{SiteChromeCustomizeContext-BHFgMjde.mjs → SiteChromeCustomizeContext-BhDn-5ir.mjs} +7771 -5863
- package/dist/_dts/ai/src/contracts/proposals.d.ts +99 -330
- package/dist/_dts/ai/src/contracts/siteStyleProposalSchemas.d.ts +9 -30
- package/dist/_dts/api/src/billing.d.ts +10 -3
- package/dist/_dts/api/src/contentRuntime.d.ts +8 -1
- package/dist/_dts/api/src/endpoints.d.ts +182 -103
- package/dist/_dts/api/src/footerSettings.d.ts +2 -5
- package/dist/_dts/api/src/index.d.ts +11 -9
- package/dist/_dts/api/src/mailchimpIntegration.d.ts +2 -59
- package/dist/_dts/api/src/mailingListIntegration.d.ts +117 -0
- package/dist/_dts/api/src/navigation/locations.d.ts +1 -0
- package/dist/_dts/api/src/navigation.d.ts +1 -26
- package/dist/_dts/api/src/newsletterEndpointDefinitions.d.ts +109 -2
- package/dist/_dts/api/src/onboarding/surfaceData.d.ts +185 -0
- package/dist/_dts/api/src/privacyPolicy.d.ts +74 -2
- package/dist/_dts/api/src/publicBookingAvailabilityEndpointDefinitions.d.ts +6 -6
- package/dist/_dts/api/src/publicEventEndpointDefinitions.d.ts +1 -1
- package/dist/_dts/api/src/publicExperience/newsletterEndpoints.d.ts +2 -4
- package/dist/_dts/api/src/publicExperience/sharedTypes.d.ts +10 -24
- package/dist/_dts/api/src/publicReadEndpointDefinitions.d.ts +73 -0
- package/dist/_dts/api/src/schemas/site-api-keys.d.ts +1 -1
- package/dist/_dts/api/src/sdkContracts.d.ts +2 -10
- package/dist/_dts/api/src/sdkThemeWire.d.ts +2 -2
- package/dist/_dts/api/src/siteManagementEndpoints.d.ts +0 -29
- package/dist/_dts/api/src/siteOnboarding.d.ts +91 -228
- package/dist/_dts/api/src/sitePlatformEndpoints.d.ts +1 -9
- package/dist/_dts/api/src/siteSettings.d.ts +20 -1
- package/dist/_dts/api/src/types.d.ts +5 -4
- package/dist/_dts/billing/src/membership/index.d.ts +14 -7
- package/dist/_dts/billing/src/plans/display.d.ts +15 -0
- package/dist/_dts/billing/src/plans/registry.d.ts +2 -0
- package/dist/_dts/billing/src/plans/standing.d.ts +19 -0
- package/dist/_dts/billing/src/plans/types.d.ts +1 -7
- package/dist/_dts/billing/src/subscriptions/evidence.d.ts +12 -0
- package/dist/_dts/billing/src/subscriptions/standingEvidence.d.ts +31 -0
- package/dist/_dts/billing/src/subscriptions/store.d.ts +23 -5
- package/dist/_dts/blocks/src/PageRenderer.d.ts +6 -15
- package/dist/_dts/blocks/src/client.d.ts +1 -1
- package/dist/_dts/blocks/src/contracts/proof-block-islands.d.ts +32 -16
- package/dist/_dts/blocks/src/pageRendererContracts.d.ts +4 -0
- package/dist/_dts/blocks/src/pageRenderingMode.d.ts +12 -6
- package/dist/_dts/blocks/src/system/blocks/appointment-services.d.ts +11 -0
- package/dist/_dts/blocks/src/system/blocks/contact-newsletter.d.ts +39 -66
- package/dist/_dts/blocks/src/system/blocks/newsletter-signup.d.ts +39 -114
- package/dist/_dts/blocks/src/system/blocks/offerings-preview/catalogue.d.ts +18 -0
- package/dist/_dts/blocks/src/system/blocks/offerings-preview/fields.d.ts +2 -0
- package/dist/_dts/blocks/src/system/blocks/offerings-preview/index.d.ts +4 -0
- package/dist/_dts/blocks/src/system/blocks/site-footer-runtime.d.ts +7 -13
- package/dist/_dts/blocks/src/system/constants/blockKinds.d.ts +1 -1
- package/dist/_dts/blocks/src/system/data/index.d.ts +2 -2
- package/dist/_dts/blocks/src/system/data/loaderEndpoints.d.ts +1 -1
- package/dist/_dts/blocks/src/system/data/publicLoaderCachePolicy.d.ts +2 -74
- package/dist/_dts/blocks/src/system/fragments/library/newsletterForm.d.ts +33 -100
- package/dist/_dts/blocks/src/system/runtime/api/types/newsletter.d.ts +5 -15
- package/dist/_dts/blocks/src/system/runtime/components/registry.client.d.ts +48 -24
- package/dist/_dts/blocks/src/system/runtime/components/runtime-backed-blocks.d.ts +24 -12
- package/dist/_dts/blocks/src/system/runtime/hooks/useCalendarEvents.d.ts +3 -0
- package/dist/_dts/blocks/src/system/runtime/hooks/useCalendarEvents.state.d.ts +1 -1
- package/dist/_dts/blocks/src/system/runtime/hooks/useCalendarToday.d.ts +22 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/appointment-services.d.ts +51 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventRegistrationWizard.d.ts +2 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration.interactive.d.ts +0 -1
- package/dist/_dts/blocks/src/system/runtime/nodes/events/EventCombined.client.d.ts +28 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/events/domain/bookability.d.ts +9 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/events/domain/dates.d.ts +14 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/events/domain/duration.d.ts +2 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/events/domain/index.d.ts +4 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/events/domain/location.d.ts +2 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/events/domain/quickDates.d.ts +16 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/AgendaEventCard.d.ts +9 -1
- package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/CalendarDayCell.d.ts +2 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/CalendarDayHeaders.d.ts +4 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/DayEventsModal.d.ts +2 -1
- package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/EventCard.d.ts +5 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/EventModals.d.ts +2 -1
- package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/EventQuickDates.d.ts +15 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/WeekAgendaView.d.ts +7 -3
- package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/WeekTimetableView.d.ts +1 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/index.d.ts +2 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/timetableModel.d.ts +1 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/useHydrationReady.d.ts +6 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/newsletter-form.client.state.d.ts +3 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/newsletter-form.interactive.d.ts +56 -33
- package/dist/_dts/blocks/src/system/runtime/nodes/newsletter-form.submission.d.ts +3 -3
- package/dist/_dts/blocks/src/system/runtime/nodes/newsletter-form.types.d.ts +13 -31
- package/dist/_dts/blocks/src/system/runtime/nodes/offerings-preview-catalogue.d.ts +14 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/offerings-preview-content.d.ts +23 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/offerings-preview.d.ts +4 -2
- package/dist/_dts/blocks/src/system/transforms/registry/formatting.d.ts +5 -0
- package/dist/_dts/commerce/src/purchase/index.d.ts +1 -0
- package/dist/_dts/commerce/src/purchase/orderItemMetadata.d.ts +5 -12
- package/dist/_dts/commerce/src/purchase/stripeCommissionMetadata.d.ts +34 -0
- package/dist/_dts/content-editor/src/footerEngagementDraft.d.ts +6 -24
- package/dist/_dts/content-editor/src/useFooterComposerState.d.ts +1 -2
- package/dist/_dts/core/src/footer-engagement.d.ts +2 -6
- package/dist/_dts/core/src/index.d.ts +9 -1
- package/dist/_dts/core/src/mailing-list-identifiers.d.ts +21 -0
- package/dist/_dts/core/src/mailing-list-runtime.d.ts +42 -0
- package/dist/_dts/core/src/mailing-list-setup-parser.d.ts +14 -0
- package/dist/_dts/core/src/mailing-list-setup.d.ts +129 -0
- package/dist/_dts/core/src/mailing-list-submission.d.ts +244 -0
- package/dist/_dts/core/src/mailing-list-targeting-parser.d.ts +12 -0
- package/dist/_dts/core/src/mailing-list-targeting.d.ts +93 -0
- package/dist/_dts/core/src/navigation-locations.d.ts +28 -0
- package/dist/_dts/core/src/public-profile.d.ts +9 -1
- package/dist/_dts/core/src/public-read-cache-contract.d.ts +45 -0
- package/dist/_dts/db/src/generated/supabase/database.types.d.ts +529 -373
- package/dist/_dts/editor-blocks/src/widgets/index.d.ts +1 -0
- package/dist/_dts/editor-blocks/src/widgets/mailing-list-targeting/MailingListTargetingField.d.ts +11 -0
- package/dist/_dts/editor-blocks/src/widgets/mailing-list-targeting/context.d.ts +13 -0
- package/dist/_dts/editor-blocks/src/widgets/mailing-list-targeting/index.d.ts +3 -0
- package/dist/_dts/editor-blocks/src/widgets/mailing-list-targeting/loaders.d.ts +6 -0
- package/dist/_dts/preview-next/src/client/widgets/widgetOverrides.d.ts +1 -0
- package/dist/_dts/sdk/src/client/publicAppointmentReadOperations.d.ts +12 -0
- package/dist/_dts/sdk/src/client/publicEventReadOperations.d.ts +2 -1
- package/dist/_dts/sdk/src/client/publicLoaderCacheAccess.d.ts +11 -4
- package/dist/_dts/sdk/src/config/content-types.d.ts +3 -13
- package/dist/_dts/sdk/src/config/content-validation.d.ts +5 -8
- package/dist/_dts/sdk/src/constants.d.ts +3 -3
- package/dist/_dts/sdk/src/contracts/index.d.ts +1 -1
- package/dist/_dts/sdk/src/contracts/system-block-content.d.ts +12 -31
- package/dist/_dts/sdk/src/navigation/index.d.ts +11 -29
- package/dist/_dts/sdk/src/next/index.d.ts +4 -4
- package/dist/_dts/sdk/src/prebuild/types.d.ts +1 -5
- package/dist/_dts/sdk/src/public-api/contracts.d.ts +33 -16
- package/dist/_dts/sdk/src/rendering/blocks-page-renderer.d.ts +3 -0
- package/dist/_dts/sdk/src/rendering/client.d.ts +3 -20
- package/dist/_dts/sdk/src/rendering/components/pageShared.d.ts +3 -0
- package/dist/_dts/sdk/src/rendering/helpers/loadContent.d.ts +4 -0
- package/dist/_dts/sdk/src/rendering/helpers/pageRuntimeSupport.d.ts +1 -0
- package/dist/_dts/sdk/src/rendering/index.d.ts +1 -1
- package/dist/_dts/sdk/src/types/block-kinds.d.ts +1 -1
- package/dist/_dts/sdk/src/version.d.ts +1 -1
- package/dist/_dts/theme-core/src/generated/containerResponsiveThemeCss.d.ts +1 -1
- package/dist/_dts/theme-core/src/hosted-booking-appearance.d.ts +41 -0
- package/dist/_dts/theme-core/src/index.d.ts +1 -0
- package/dist/_dts/theme-core/src/runtime/buildThemeRuntime.d.ts +0 -1
- package/dist/_dts/theme-core/src/tokens/tokens.d.ts +7 -0
- package/dist/_dts/ui/src/badge.d.ts +1 -1
- package/dist/_dts/ui/src/callout.d.ts +1 -1
- package/dist/client/{BookingConsentAgreement-DQUik1Mx.mjs → BookingConsentAgreement-CZvTDtsK.mjs} +2 -2
- package/dist/client/{DiscountCodeDisclosure-CU67Q4vH.mjs → DiscountCodeDisclosure-D-DsLCMU.mjs} +1 -1
- package/dist/client/{EventCombined.client-a02TXUgg.mjs → EventCombined.client-dWqgd5ZO.mjs} +443 -199
- package/dist/client/{EventListing.client-99qx7jFl.mjs → EventListing.client-BMRa9IYp.mjs} +2 -2
- package/dist/client/{LeafletStaticMap-CWzcq73L.mjs → LeafletStaticMap-D21W9kBZ.mjs} +1 -1
- package/dist/client/{accordion-D1nb3-Oj.mjs → accordion-FxF_ta47.mjs} +1 -1
- package/dist/client/{bookingForm-BGrmLhaO.mjs → bookingForm-YnwW4TGw.mjs} +5 -5
- package/dist/client/bookings.mjs +43 -2
- package/dist/client/{carousel-DSmOx3ad.mjs → carousel-vng7fFT5.mjs} +1 -1
- package/dist/client/{cart-COWeOIUk.mjs → cart-DEPDsjNk.mjs} +3 -3
- package/dist/client/{checkout-CeysaIJK.mjs → checkout-CZRWu9rW.mjs} +3 -3
- package/dist/client/client.mjs +3331 -1407
- package/dist/client/{context-DBzX85Xc.mjs → context-DvU_WUmd.mjs} +4 -3
- package/dist/client/{dates-DCYhZBlW.mjs → dates-wnPMiRl5.mjs} +21 -3
- package/dist/client/{eventCalendar-BgsN73Ul.mjs → eventCalendar-BA3Q5L15.mjs} +80 -78
- package/dist/client/{eventCombined-DcZQAMQP.mjs → eventCombined-51wgR-1R.mjs} +3 -3
- package/dist/client/{eventDetails-BWwGJ54l.mjs → eventDetails-modaetpm.mjs} +4 -4
- package/dist/client/{eventListing-DqYqV8vp.mjs → eventListing-D8t2J3Kv.mjs} +3 -3
- package/dist/client/{eventRegistration-DQGDgu_e.mjs → eventRegistration-CYqtkCE_.mjs} +49 -9
- package/dist/client/{form-ClfpasVT.mjs → form-CBKXN5In.mjs} +2 -2
- package/dist/client/{headerSection-BuOMe98N.mjs → headerSection-DylDqNrs.mjs} +2 -2
- package/dist/client/hooks.mjs +1259 -555
- package/dist/client/{locationMap-CEqu_sfa.mjs → locationMap-CvWrG0vZ.mjs} +2 -2
- package/dist/client/{newsletterForm-IbrHjMxy.mjs → newsletterForm-Btwk70zw.mjs} +117 -38
- package/dist/client/{pricing-xj7MPZlK.mjs → pricing-Uzw-GQ6Y.mjs} +1 -1
- package/dist/client/{productDetail-vxqTt5Xj.mjs → productDetail-JLcUYKnd.mjs} +3 -3
- package/dist/client/{productList-OTdZu8sb.mjs → productList-FM0cbUzj.mjs} +3 -3
- package/dist/client/{propsDecoder-CY9gGEF7.mjs → propsDecoder-DYzafZb2.mjs} +592 -152
- package/dist/client/rendering/client.mjs +2259 -835
- package/dist/client/rendering/islands.mjs +17 -17
- package/dist/client/rendering.mjs +3308 -1236
- package/dist/client/{scrollToBlock--BFV6kl-.mjs → scrollToBlock-CvXszexS.mjs} +1 -1
- package/dist/client/{shop-CP4YbDL9.mjs → shop-BIcjvy5a.mjs} +6 -6
- package/dist/client/{shop-commerce-APs4XBXE.mjs → shop-commerce-BZQsy7xw.mjs} +5 -5
- package/dist/client/{shop-commerce-store-CAVLxLFr.mjs → shop-commerce-store-D5V7XAb5.mjs} +1 -1
- package/dist/client/{shopShared-BnSRrwXI.mjs → shopShared-DowkXevB.mjs} +3 -3
- package/dist/client/{useEventFilters-1a1by4c8.mjs → useEventFilters-oMoTw_JE.mjs} +56 -9
- package/dist/preview-next/before-render.mjs +238 -111
- package/dist/preview-next/client/runtime.mjs +4 -4
- package/dist/preview-next/keepAlive.mjs +238 -111
- package/dist/preview-next/middleware.mjs +238 -111
- package/dist/{previewAuthStore-BkEgnYPP.mjs → previewAuthStore-COUyAKaX.mjs} +238 -111
- package/dist/{sdk-runtime-DwGfsT0S.mjs → sdk-runtime-D4k2LSGF.mjs} +2 -2
- package/dist/{separator-BeqDLneQ.mjs → separator-UGtpag4Z.mjs} +1 -1
- package/dist/server/components.mjs +2697 -1023
- package/dist/server/config-validation.mjs +2424 -1720
- package/dist/server/config.mjs +2429 -1724
- package/dist/server/data.mjs +1164 -454
- package/dist/server/index.mjs +364 -280
- package/dist/server/navigation.mjs +16 -47
- package/dist/server/next.mjs +2915 -1380
- package/dist/server/page-converter.mjs +969 -522
- package/dist/server/prebuild.mjs +2 -3
- package/dist/server/rendering/server.mjs +2704 -1030
- package/dist/server/rendering.mjs +2742 -1063
- package/dist/server/routing.mjs +1386 -595
- package/dist/server/server.mjs +2878 -2324
- package/dist/server/theme-bridge.mjs +292 -24
- package/dist/styles/index.css +289 -25
- package/package.json +1 -1
- package/dist/_dts/api/src/navigation/identity.d.ts +0 -59
- package/dist/_dts/blocks/src/system/blocks/newsletter-signup-destination.d.ts +0 -291
- package/dist/_dts/core/src/newsletter-signup-destination.d.ts +0 -38
package/dist/server/config.mjs
CHANGED
|
@@ -45,6 +45,14 @@ function fallbackBinding(...sources) {
|
|
|
45
45
|
sources: [...sources]
|
|
46
46
|
};
|
|
47
47
|
}
|
|
48
|
+
//#endregion
|
|
49
|
+
//#region ../api/src/apiEndpointTypes.ts
|
|
50
|
+
function allowedDemoMutationPolicy() {
|
|
51
|
+
return {
|
|
52
|
+
classification: "allowed",
|
|
53
|
+
publicMessage: ""
|
|
54
|
+
};
|
|
55
|
+
}
|
|
48
56
|
function blockedDemoMutationPolicy(classification, publicMessage) {
|
|
49
57
|
if (publicMessage.trim() === "") throw new Error(`Demo mutation policy ${classification} requires publicMessage.`);
|
|
50
58
|
return {
|
|
@@ -57,6 +65,7 @@ function blockedDemoMutationPolicy(classification, publicMessage) {
|
|
|
57
65
|
const DEMO_MUTATION_BLOCKED_HIDDEN = blockedDemoMutationPolicy("blocked-hidden", "This action is not available in demo sites.");
|
|
58
66
|
const DEMO_MUTATION_BLOCKED_DISABLED = blockedDemoMutationPolicy("blocked-disabled", "This setting is disabled in demo sites.");
|
|
59
67
|
blockedDemoMutationPolicy("internal-only", "This internal operation is not available in demo sites.");
|
|
68
|
+
const DEMO_MUTATION_ALLOWED = allowedDemoMutationPolicy();
|
|
60
69
|
//#endregion
|
|
61
70
|
//#region ../api/src/cache-tags.ts
|
|
62
71
|
/**
|
|
@@ -988,14 +997,117 @@ const NEWSLETTER_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
|
|
|
988
997
|
responseKind: "json",
|
|
989
998
|
errors: ["auth:forbidden", "server:internal_error"]
|
|
990
999
|
},
|
|
991
|
-
|
|
992
|
-
path: "/sites/{siteId}/
|
|
1000
|
+
getMailingListSetup: {
|
|
1001
|
+
path: "/sites/{siteId}/mailing-list/setup",
|
|
1002
|
+
method: "GET",
|
|
1003
|
+
tags: [TAG_TEMPLATES.site, TAG_TEMPLATES.siteNewsletter],
|
|
1004
|
+
auth: "user",
|
|
1005
|
+
responseKind: "json",
|
|
1006
|
+
errors: ["auth:forbidden", "server:internal_error"]
|
|
1007
|
+
},
|
|
1008
|
+
getMailingListAuthoringContext: {
|
|
1009
|
+
path: "/sites/{siteId}/mailing-list/authoring-context",
|
|
1010
|
+
method: "GET",
|
|
1011
|
+
tags: [TAG_TEMPLATES.site, TAG_TEMPLATES.siteNewsletter],
|
|
1012
|
+
auth: "user",
|
|
1013
|
+
responseKind: "json",
|
|
1014
|
+
errors: ["auth:forbidden", "server:internal_error"]
|
|
1015
|
+
},
|
|
1016
|
+
previewMailingListSetupChange: {
|
|
1017
|
+
path: "/sites/{siteId}/mailing-list/setup/preview",
|
|
1018
|
+
method: "POST",
|
|
1019
|
+
tags: [TAG_TEMPLATES.site, TAG_TEMPLATES.siteNewsletter],
|
|
1020
|
+
auth: "user",
|
|
1021
|
+
responseKind: "json",
|
|
1022
|
+
demoMutation: DEMO_MUTATION_ALLOWED,
|
|
1023
|
+
errors: [
|
|
1024
|
+
"auth:forbidden",
|
|
1025
|
+
"validation:invalid_input",
|
|
1026
|
+
"server:internal_error"
|
|
1027
|
+
]
|
|
1028
|
+
},
|
|
1029
|
+
applyMailingListSetupChange: {
|
|
1030
|
+
path: "/sites/{siteId}/mailing-list/setup",
|
|
1031
|
+
method: "PUT",
|
|
1032
|
+
tags: [TAG_TEMPLATES.site, TAG_TEMPLATES.siteNewsletter],
|
|
1033
|
+
auth: "user",
|
|
1034
|
+
responseKind: "json",
|
|
1035
|
+
demoMutation: DEMO_MUTATION_BLOCKED_DISABLED,
|
|
1036
|
+
errors: [
|
|
1037
|
+
"auth:forbidden",
|
|
1038
|
+
"validation:invalid_input",
|
|
1039
|
+
"resource:conflict",
|
|
1040
|
+
"server:internal_error"
|
|
1041
|
+
]
|
|
1042
|
+
},
|
|
1043
|
+
getMailingListProviderCatalog: {
|
|
1044
|
+
path: "/sites/{siteId}/mailing-list/providers/{provider}/catalog",
|
|
1045
|
+
method: "GET",
|
|
1046
|
+
tags: [TAG_TEMPLATES.site, TAG_TEMPLATES.siteNewsletter],
|
|
1047
|
+
auth: "user",
|
|
1048
|
+
responseKind: "json",
|
|
1049
|
+
errors: [
|
|
1050
|
+
"auth:forbidden",
|
|
1051
|
+
"validation:invalid_input",
|
|
1052
|
+
"server:internal_error"
|
|
1053
|
+
]
|
|
1054
|
+
},
|
|
1055
|
+
refreshMailingListProviderCatalog: {
|
|
1056
|
+
path: "/sites/{siteId}/mailing-list/providers/{provider}/catalog/refresh",
|
|
1057
|
+
method: "POST",
|
|
1058
|
+
tags: [TAG_TEMPLATES.site, TAG_TEMPLATES.siteNewsletter],
|
|
1059
|
+
auth: "user",
|
|
1060
|
+
responseKind: "json",
|
|
1061
|
+
demoMutation: DEMO_MUTATION_BLOCKED_DISABLED,
|
|
1062
|
+
errors: [
|
|
1063
|
+
"auth:forbidden",
|
|
1064
|
+
"validation:invalid_input",
|
|
1065
|
+
"server:internal_error"
|
|
1066
|
+
]
|
|
1067
|
+
},
|
|
1068
|
+
getMailingListProviderHealth: {
|
|
1069
|
+
path: "/sites/{siteId}/mailing-list/health",
|
|
1070
|
+
method: "GET",
|
|
1071
|
+
tags: [TAG_TEMPLATES.site, TAG_TEMPLATES.siteNewsletter],
|
|
1072
|
+
auth: "user",
|
|
1073
|
+
responseKind: "json",
|
|
1074
|
+
errors: ["auth:forbidden", "server:internal_error"]
|
|
1075
|
+
},
|
|
1076
|
+
getBrevoConnection: {
|
|
1077
|
+
path: "/sites/{siteId}/integrations/brevo/connection",
|
|
993
1078
|
method: "GET",
|
|
994
1079
|
tags: [TAG_TEMPLATES.site],
|
|
995
1080
|
auth: "user",
|
|
996
1081
|
responseKind: "json",
|
|
997
1082
|
errors: ["auth:forbidden", "server:internal_error"]
|
|
998
1083
|
},
|
|
1084
|
+
connectBrevo: {
|
|
1085
|
+
path: "/sites/{siteId}/integrations/brevo/connection",
|
|
1086
|
+
method: "PUT",
|
|
1087
|
+
tags: [TAG_TEMPLATES.site],
|
|
1088
|
+
auth: "user",
|
|
1089
|
+
responseKind: "json",
|
|
1090
|
+
demoMutation: DEMO_MUTATION_BLOCKED_DISABLED,
|
|
1091
|
+
errors: [
|
|
1092
|
+
"auth:forbidden",
|
|
1093
|
+
"validation:invalid_input",
|
|
1094
|
+
"resource:conflict",
|
|
1095
|
+
"server:internal_error"
|
|
1096
|
+
]
|
|
1097
|
+
},
|
|
1098
|
+
disconnectBrevo: {
|
|
1099
|
+
path: "/sites/{siteId}/integrations/brevo/disconnect",
|
|
1100
|
+
method: "POST",
|
|
1101
|
+
tags: [TAG_TEMPLATES.site],
|
|
1102
|
+
auth: "user",
|
|
1103
|
+
responseKind: "json",
|
|
1104
|
+
demoMutation: DEMO_MUTATION_BLOCKED_DISABLED,
|
|
1105
|
+
errors: [
|
|
1106
|
+
"auth:forbidden",
|
|
1107
|
+
"resource:conflict",
|
|
1108
|
+
"server:internal_error"
|
|
1109
|
+
]
|
|
1110
|
+
},
|
|
999
1111
|
getMailchimpConnection: {
|
|
1000
1112
|
path: "/sites/{siteId}/integrations/mailchimp/connection",
|
|
1001
1113
|
method: "GET",
|
|
@@ -1219,994 +1331,329 @@ const NEWSLETTER_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
|
|
|
1219
1331
|
}
|
|
1220
1332
|
});
|
|
1221
1333
|
//#endregion
|
|
1222
|
-
//#region ../
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
auth: "public",
|
|
1236
|
-
responseKind: "json"
|
|
1237
|
-
},
|
|
1238
|
-
getPublicEventRegistrationOptions: {
|
|
1239
|
-
path: "/public/sites/{siteId}/events/registration-options",
|
|
1240
|
-
method: "POST",
|
|
1241
|
-
tags: [TAG_TEMPLATES.publicEvents, "event-registration-options"],
|
|
1242
|
-
auth: "public",
|
|
1243
|
-
responseKind: "json",
|
|
1244
|
-
errors: [
|
|
1245
|
-
"validation:invalid_input",
|
|
1246
|
-
"resource:not_found",
|
|
1247
|
-
"resource:conflict",
|
|
1248
|
-
"server:internal_error"
|
|
1249
|
-
]
|
|
1250
|
-
},
|
|
1251
|
-
resolveEventSubroute: {
|
|
1252
|
-
path: "/public/sites/{siteId}/events/subroutes/resolve",
|
|
1253
|
-
method: "GET",
|
|
1254
|
-
revalidate: 60,
|
|
1255
|
-
tags: [TAG_TEMPLATES.publicEvents, "event-subroute"],
|
|
1256
|
-
auth: "public",
|
|
1257
|
-
responseKind: "json",
|
|
1258
|
-
errors: []
|
|
1259
|
-
}
|
|
1260
|
-
});
|
|
1334
|
+
//#region ../core/src/result.ts
|
|
1335
|
+
function ok(value) {
|
|
1336
|
+
return {
|
|
1337
|
+
ok: true,
|
|
1338
|
+
value
|
|
1339
|
+
};
|
|
1340
|
+
}
|
|
1341
|
+
function err(error) {
|
|
1342
|
+
return {
|
|
1343
|
+
ok: false,
|
|
1344
|
+
error
|
|
1345
|
+
};
|
|
1346
|
+
}
|
|
1261
1347
|
//#endregion
|
|
1262
|
-
//#region ../
|
|
1348
|
+
//#region ../core/src/branded.ts
|
|
1349
|
+
const UUID_PATTERN$1 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
1350
|
+
function parseUuidBrand(value, unsafeConstructor) {
|
|
1351
|
+
if (typeof value !== "string") return err({ kind: "not_string" });
|
|
1352
|
+
const normalized = value.trim().toLowerCase();
|
|
1353
|
+
if (normalized.length === 0) return err({ kind: "empty_string" });
|
|
1354
|
+
if (!UUID_PATTERN$1.test(normalized)) return err({ kind: "invalid_uuid" });
|
|
1355
|
+
return ok(unsafeConstructor(normalized));
|
|
1356
|
+
}
|
|
1357
|
+
const unsafeAsSiteId = (id) => id;
|
|
1358
|
+
const unsafeAsApiKeyId = (id) => id;
|
|
1359
|
+
const unsafeAsEventOfferingId = (id) => id;
|
|
1360
|
+
const unsafeAsEventSeriesId = (id) => id;
|
|
1361
|
+
const unsafeAsUserId = (id) => id;
|
|
1362
|
+
const parseSiteId = (value) => parseUuidBrand(value, unsafeAsSiteId);
|
|
1363
|
+
const parseApiKeyId = (value) => parseUuidBrand(value, unsafeAsApiKeyId);
|
|
1364
|
+
const parseEventOfferingId = (value) => parseUuidBrand(value, unsafeAsEventOfferingId);
|
|
1365
|
+
const parseUserId = (value) => parseUuidBrand(value, unsafeAsUserId);
|
|
1366
|
+
const parseEventSeriesId = (value) => parseUuidBrand(value, unsafeAsEventSeriesId);
|
|
1367
|
+
//#endregion
|
|
1368
|
+
//#region ../core/src/assert-never.ts
|
|
1369
|
+
function assertNever$2(value, message = "Unexpected variant") {
|
|
1370
|
+
throw new Error(`${message}: ${String(value)}`);
|
|
1371
|
+
}
|
|
1372
|
+
//#endregion
|
|
1373
|
+
//#region ../core/src/currency-format.ts
|
|
1374
|
+
const CURRENCY_LOCALE_BY_CODE = {
|
|
1375
|
+
USD: "en-US",
|
|
1376
|
+
GBP: "en-GB",
|
|
1377
|
+
EUR: "de-DE",
|
|
1378
|
+
AUD: "en-AU",
|
|
1379
|
+
CAD: "en-CA",
|
|
1380
|
+
NZD: "en-NZ",
|
|
1381
|
+
JPY: "ja-JP",
|
|
1382
|
+
CNY: "zh-CN",
|
|
1383
|
+
CHF: "de-CH"
|
|
1384
|
+
};
|
|
1385
|
+
function resolveCurrencyLocale(currencyCode, override) {
|
|
1386
|
+
return override ?? CURRENCY_LOCALE_BY_CODE[currencyCode] ?? "en";
|
|
1387
|
+
}
|
|
1263
1388
|
/**
|
|
1264
|
-
* The
|
|
1265
|
-
*
|
|
1389
|
+
* The single currency-amount formatter for the product: minor units in,
|
|
1390
|
+
* localized string out.
|
|
1266
1391
|
*
|
|
1267
|
-
*
|
|
1268
|
-
*
|
|
1269
|
-
*
|
|
1270
|
-
*
|
|
1271
|
-
* (The endpoint that originally motivated the move, `checkPublicEventEligibility`,
|
|
1272
|
-
* was since deleted on dev by #1326.)
|
|
1392
|
+
* The locale is derived from the currency by default, so output is deterministic
|
|
1393
|
+
* across server and client (no SSR/hydration mismatch). All other money
|
|
1394
|
+
* formatters in the codebase should delegate here rather than constructing their
|
|
1395
|
+
* own `Intl.NumberFormat`.
|
|
1273
1396
|
*/
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1397
|
+
function formatCurrencyAmount(amountCents, currency, options) {
|
|
1398
|
+
const currencyCode = currency.toUpperCase();
|
|
1399
|
+
const locale = resolveCurrencyLocale(currencyCode, options?.locale);
|
|
1400
|
+
try {
|
|
1401
|
+
const exactFormatter = new Intl.NumberFormat(locale, {
|
|
1402
|
+
style: "currency",
|
|
1403
|
+
currency: currencyCode
|
|
1404
|
+
});
|
|
1405
|
+
const fractionDigits = options?.decimals === "auto" ? {
|
|
1406
|
+
minimumFractionDigits: 0,
|
|
1407
|
+
maximumFractionDigits: exactFormatter.resolvedOptions().maximumFractionDigits
|
|
1408
|
+
} : {};
|
|
1409
|
+
return new Intl.NumberFormat(locale, {
|
|
1410
|
+
style: "currency",
|
|
1411
|
+
currency: currencyCode,
|
|
1412
|
+
...fractionDigits
|
|
1413
|
+
}).format(amountCents / 100);
|
|
1414
|
+
} catch {
|
|
1415
|
+
return `${(amountCents / 100).toFixed(2)} ${currencyCode}`;
|
|
1288
1416
|
}
|
|
1289
|
-
}
|
|
1417
|
+
}
|
|
1290
1418
|
//#endregion
|
|
1291
|
-
//#region ../
|
|
1419
|
+
//#region ../core/src/planner.ts
|
|
1420
|
+
/** Default clock for production callers that do not inject time explicitly. */
|
|
1421
|
+
const systemPlanningClock = { now: () => Date.now() };
|
|
1422
|
+
/** Resolve current time as a Date from an explicit Date, injected clock, or system clock. */
|
|
1423
|
+
function resolvePlanningNowDate(input = {}) {
|
|
1424
|
+
if (input.now !== void 0) return input.now;
|
|
1425
|
+
return new Date((input.clock ?? systemPlanningClock).now());
|
|
1426
|
+
}
|
|
1427
|
+
//#endregion
|
|
1428
|
+
//#region ../core/src/event-pricing.ts
|
|
1429
|
+
/** Capacity closes booking, but does not make an otherwise eligible price unknown. */
|
|
1430
|
+
function isPublicEventPricingOptionDisplayable(option) {
|
|
1431
|
+
if (!option.isActive) return false;
|
|
1432
|
+
if (option.availability.kind === "available") return true;
|
|
1433
|
+
const reason = option.availability.reason;
|
|
1434
|
+
switch (reason) {
|
|
1435
|
+
case "sold_out":
|
|
1436
|
+
case "overallCapacityUnavailable": return true;
|
|
1437
|
+
case "inactive":
|
|
1438
|
+
case "not_on_sale_yet":
|
|
1439
|
+
case "sale_ended":
|
|
1440
|
+
case "attendance_mode_unavailable": return false;
|
|
1441
|
+
default: return assertNever$2(reason);
|
|
1442
|
+
}
|
|
1443
|
+
}
|
|
1444
|
+
function publicEventPricingDisplay(pricing) {
|
|
1445
|
+
switch (pricing.kind) {
|
|
1446
|
+
case "free":
|
|
1447
|
+
case "single":
|
|
1448
|
+
case "sliding_scale": return canonicalEventPricingDisplay(pricing);
|
|
1449
|
+
case "tiered": return resolvePricingOptionsPriceDisplay({
|
|
1450
|
+
options: pricing.options.filter(isPublicEventPricingOptionDisplayable),
|
|
1451
|
+
currency: pricing.currency,
|
|
1452
|
+
purpose: "configured"
|
|
1453
|
+
});
|
|
1454
|
+
case "external": return {
|
|
1455
|
+
kind: "external",
|
|
1456
|
+
label: pricing.label
|
|
1457
|
+
};
|
|
1458
|
+
}
|
|
1459
|
+
}
|
|
1460
|
+
function publicEventPricingType(pricing) {
|
|
1461
|
+
switch (pricing.kind) {
|
|
1462
|
+
case "free": return "free";
|
|
1463
|
+
case "single":
|
|
1464
|
+
case "tiered":
|
|
1465
|
+
case "sliding_scale": return isFreePublicEventPriceDisplay(publicEventPricingDisplay(pricing)) ? "free" : "paid";
|
|
1466
|
+
case "external": return "external";
|
|
1467
|
+
}
|
|
1468
|
+
}
|
|
1469
|
+
function isFreePublicEventPriceDisplay(display) {
|
|
1470
|
+
switch (display.kind) {
|
|
1471
|
+
case "free": return true;
|
|
1472
|
+
case "exact":
|
|
1473
|
+
case "from":
|
|
1474
|
+
case "range":
|
|
1475
|
+
case "mixed":
|
|
1476
|
+
case "unavailable":
|
|
1477
|
+
case "external": return false;
|
|
1478
|
+
}
|
|
1479
|
+
}
|
|
1480
|
+
function resolvePricingOptionSaleWindowState(option, now) {
|
|
1481
|
+
if (option.saleStartsAt !== null && option.saleStartsAt !== void 0 && new Date(option.saleStartsAt) > now) return "not_started";
|
|
1482
|
+
if (option.saleEndsAt !== null && option.saleEndsAt !== void 0 && new Date(option.saleEndsAt) < now) return "ended";
|
|
1483
|
+
return "open";
|
|
1484
|
+
}
|
|
1485
|
+
function resolvePricingOptionsPriceDisplay(input) {
|
|
1486
|
+
const now = input.purpose === "available_now" ? resolvePlanningNowDate({
|
|
1487
|
+
now: input.now,
|
|
1488
|
+
clock: input.clock
|
|
1489
|
+
}) : null;
|
|
1490
|
+
const amounts = input.options.filter((option) => option.isActive && (now === null || resolvePricingOptionSaleWindowState(option, now) === "open")).map((option) => option.priceAmount);
|
|
1491
|
+
return amounts.length === 0 ? {
|
|
1492
|
+
kind: "unavailable",
|
|
1493
|
+
currency: input.currency
|
|
1494
|
+
} : amountRangeDisplay(amounts, input.currency);
|
|
1495
|
+
}
|
|
1496
|
+
function amountRangeDisplay(amounts, currency) {
|
|
1497
|
+
const minAmount = Math.min(...amounts);
|
|
1498
|
+
const maxAmount = Math.max(...amounts);
|
|
1499
|
+
if (minAmount === maxAmount) return minAmount === 0 ? {
|
|
1500
|
+
kind: "free",
|
|
1501
|
+
currency
|
|
1502
|
+
} : {
|
|
1503
|
+
kind: "exact",
|
|
1504
|
+
amount: minAmount,
|
|
1505
|
+
currency
|
|
1506
|
+
};
|
|
1507
|
+
if (minAmount === 0) {
|
|
1508
|
+
const paidAmounts = amounts.filter((amount) => amount > 0);
|
|
1509
|
+
return {
|
|
1510
|
+
kind: "mixed",
|
|
1511
|
+
paidFromAmount: Math.min(...paidAmounts),
|
|
1512
|
+
paidToAmount: maxAmount,
|
|
1513
|
+
currency
|
|
1514
|
+
};
|
|
1515
|
+
}
|
|
1516
|
+
return {
|
|
1517
|
+
kind: "range",
|
|
1518
|
+
minAmount,
|
|
1519
|
+
maxAmount,
|
|
1520
|
+
currency
|
|
1521
|
+
};
|
|
1522
|
+
}
|
|
1523
|
+
/** Derives configured price presentation directly from canonical pricing. */
|
|
1524
|
+
function canonicalEventPricingDisplay(pricing) {
|
|
1525
|
+
switch (pricing.kind) {
|
|
1526
|
+
case "free": return {
|
|
1527
|
+
kind: "free",
|
|
1528
|
+
currency: pricing.currency
|
|
1529
|
+
};
|
|
1530
|
+
case "single": return {
|
|
1531
|
+
kind: "exact",
|
|
1532
|
+
amount: pricing.amount,
|
|
1533
|
+
currency: pricing.currency
|
|
1534
|
+
};
|
|
1535
|
+
case "sliding_scale": return pricing.minimum === pricing.maximum ? {
|
|
1536
|
+
kind: "exact",
|
|
1537
|
+
amount: pricing.maximum,
|
|
1538
|
+
currency: pricing.currency
|
|
1539
|
+
} : {
|
|
1540
|
+
kind: "range",
|
|
1541
|
+
minAmount: pricing.minimum,
|
|
1542
|
+
maxAmount: pricing.maximum,
|
|
1543
|
+
currency: pricing.currency
|
|
1544
|
+
};
|
|
1545
|
+
case "tiered": return resolvePricingOptionsPriceDisplay({
|
|
1546
|
+
options: pricing.options,
|
|
1547
|
+
currency: pricing.currency,
|
|
1548
|
+
purpose: "configured"
|
|
1549
|
+
});
|
|
1550
|
+
default: return assertNever$2(pricing);
|
|
1551
|
+
}
|
|
1552
|
+
}
|
|
1553
|
+
//#endregion
|
|
1554
|
+
//#region ../core/src/event-page-surface-subject.ts
|
|
1555
|
+
function createEventSeriesPageSurfaceSubject(eventSeriesId, bookingScope, eventDestinationMode) {
|
|
1556
|
+
const mode = eventDestinationMode ? { eventDestinationMode } : {};
|
|
1557
|
+
return bookingScope === "whole_series" ? {
|
|
1558
|
+
kind: "eventSeries",
|
|
1559
|
+
eventSeriesId,
|
|
1560
|
+
bookingScope,
|
|
1561
|
+
isWholeSeriesBooking: true,
|
|
1562
|
+
...mode
|
|
1563
|
+
} : {
|
|
1564
|
+
kind: "eventSeries",
|
|
1565
|
+
eventSeriesId,
|
|
1566
|
+
bookingScope,
|
|
1567
|
+
...mode
|
|
1568
|
+
};
|
|
1569
|
+
}
|
|
1570
|
+
function createEventOfferingPageSurfaceSubject(eventOfferingId, input) {
|
|
1571
|
+
const mode = input.eventDestinationMode ? { eventDestinationMode: input.eventDestinationMode } : {};
|
|
1572
|
+
const identity = {
|
|
1573
|
+
kind: "eventOffering",
|
|
1574
|
+
eventOfferingId,
|
|
1575
|
+
catalogueEventSeriesIds: input.catalogueEventSeriesIds
|
|
1576
|
+
};
|
|
1577
|
+
return input.bookingScope === "whole_series" ? {
|
|
1578
|
+
...identity,
|
|
1579
|
+
bookingScope: input.bookingScope,
|
|
1580
|
+
isWholeSeriesBooking: true,
|
|
1581
|
+
...mode
|
|
1582
|
+
} : {
|
|
1583
|
+
...identity,
|
|
1584
|
+
bookingScope: input.bookingScope,
|
|
1585
|
+
...mode
|
|
1586
|
+
};
|
|
1587
|
+
}
|
|
1292
1588
|
/**
|
|
1293
|
-
*
|
|
1294
|
-
*
|
|
1295
|
-
* These are the reads that appointment writes invalidate. They carry canonical
|
|
1296
|
-
* `riverbank:*` tags because the frontend revalidate endpoint discards anything
|
|
1297
|
-
* else, which is why the legacy `site-{siteId}` tag they used to declare could
|
|
1298
|
-
* never actually be cleared (issue 1364).
|
|
1589
|
+
* Read the destination mode off a wire value.
|
|
1299
1590
|
*
|
|
1300
|
-
*
|
|
1301
|
-
*
|
|
1591
|
+
* Absent or unrecognised reads as absent, which leaves the routed Event record
|
|
1592
|
+
* as the only authority — the behaviour every caller had before the field
|
|
1593
|
+
* existed.
|
|
1302
1594
|
*/
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
tags: [TAG_TEMPLATES.publicBookingAvailability, TAG_TEMPLATES.publicBookingServices],
|
|
1349
|
-
auth: "public",
|
|
1350
|
-
responseKind: "json",
|
|
1351
|
-
errors: []
|
|
1595
|
+
function parseEventPageSurfaceDestinationMode(value) {
|
|
1596
|
+
return value === "cms-managed" || value === "system-managed" ? value : void 0;
|
|
1597
|
+
}
|
|
1598
|
+
function parseEventPageSurfaceSubject(value) {
|
|
1599
|
+
if (!isRecord$11(value)) return err({ kind: "notObject" });
|
|
1600
|
+
switch (value.kind) {
|
|
1601
|
+
case "eventSeries": {
|
|
1602
|
+
const eventSeriesId = parseEventSeriesId(value.eventSeriesId);
|
|
1603
|
+
if (!eventSeriesId.ok) return err({
|
|
1604
|
+
kind: "invalidEventSeriesId",
|
|
1605
|
+
error: eventSeriesId.error
|
|
1606
|
+
});
|
|
1607
|
+
if (value.bookingScope !== "single_occurrence" && value.bookingScope !== "whole_series") return err({
|
|
1608
|
+
kind: "invalidEventSeriesBookingScope",
|
|
1609
|
+
bookingScope: value.bookingScope
|
|
1610
|
+
});
|
|
1611
|
+
return ok(createEventSeriesPageSurfaceSubject(eventSeriesId.value, value.bookingScope, parseEventPageSurfaceDestinationMode(value.eventDestinationMode)));
|
|
1612
|
+
}
|
|
1613
|
+
case "eventOffering": {
|
|
1614
|
+
const eventOfferingId = parseEventOfferingId(value.eventOfferingId);
|
|
1615
|
+
if (!eventOfferingId.ok) return err({
|
|
1616
|
+
kind: "invalidEventOfferingId",
|
|
1617
|
+
error: eventOfferingId.error
|
|
1618
|
+
});
|
|
1619
|
+
if (!Array.isArray(value.catalogueEventSeriesIds)) return err({
|
|
1620
|
+
kind: "invalidEventOfferingCatalogue",
|
|
1621
|
+
catalogue: value.catalogueEventSeriesIds
|
|
1622
|
+
});
|
|
1623
|
+
if (value.bookingScope !== "single_occurrence" && value.bookingScope !== "whole_series") return err({
|
|
1624
|
+
kind: "invalidEventOfferingBookingScope",
|
|
1625
|
+
bookingScope: value.bookingScope
|
|
1626
|
+
});
|
|
1627
|
+
const parsedCatalogueIds = parseEventSeriesIdList(value.catalogueEventSeriesIds);
|
|
1628
|
+
if (!parsedCatalogueIds.ok) return parsedCatalogueIds;
|
|
1629
|
+
const eventDestinationMode = parseEventPageSurfaceDestinationMode(value.eventDestinationMode);
|
|
1630
|
+
return ok(createEventOfferingPageSurfaceSubject(eventOfferingId.value, {
|
|
1631
|
+
catalogueEventSeriesIds: parsedCatalogueIds.value,
|
|
1632
|
+
bookingScope: value.bookingScope,
|
|
1633
|
+
...eventDestinationMode ? { eventDestinationMode } : {}
|
|
1634
|
+
}));
|
|
1635
|
+
}
|
|
1636
|
+
default: return err({
|
|
1637
|
+
kind: "unsupportedSubject",
|
|
1638
|
+
subjectKind: value.kind
|
|
1639
|
+
});
|
|
1352
1640
|
}
|
|
1353
|
-
}
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
const
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
}
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
responseKind: "json"
|
|
1370
|
-
},
|
|
1371
|
-
revokeSiteApiKey: {
|
|
1372
|
-
path: "/sites/{siteId}/api-keys/{keyId}",
|
|
1373
|
-
method: "DELETE",
|
|
1374
|
-
auth: "user",
|
|
1375
|
-
tags: ["site-{siteId}", "api-keys"],
|
|
1376
|
-
responseKind: "json"
|
|
1377
|
-
},
|
|
1378
|
-
listSitePreviewKeys: {
|
|
1379
|
-
path: "/sites/{siteId}/api-keys/preview",
|
|
1380
|
-
method: "GET",
|
|
1381
|
-
auth: "user",
|
|
1382
|
-
tags: [
|
|
1383
|
-
"site-{siteId}",
|
|
1384
|
-
"api-keys",
|
|
1385
|
-
"preview-key"
|
|
1386
|
-
],
|
|
1387
|
-
errors: [],
|
|
1388
|
-
responseKind: "json"
|
|
1389
|
-
},
|
|
1390
|
-
createSitePreviewKey: {
|
|
1391
|
-
path: "/sites/{siteId}/api-keys/preview",
|
|
1392
|
-
method: "POST",
|
|
1393
|
-
auth: "user",
|
|
1394
|
-
tags: [
|
|
1395
|
-
"site-{siteId}",
|
|
1396
|
-
"api-keys",
|
|
1397
|
-
"preview-key"
|
|
1398
|
-
],
|
|
1399
|
-
responseKind: "json"
|
|
1400
|
-
},
|
|
1401
|
-
getSiteApiKeyAccessLogs: {
|
|
1402
|
-
path: "/sites/{siteId}/api-keys/access-logs",
|
|
1403
|
-
method: "GET",
|
|
1404
|
-
auth: "user",
|
|
1405
|
-
tags: [
|
|
1406
|
-
"site-{siteId}",
|
|
1407
|
-
"api-keys",
|
|
1408
|
-
"access-logs"
|
|
1409
|
-
],
|
|
1410
|
-
responseKind: "json"
|
|
1411
|
-
},
|
|
1412
|
-
listManagementKeys: {
|
|
1413
|
-
path: "/sites/{siteId}/api-keys/management",
|
|
1414
|
-
method: "GET",
|
|
1415
|
-
auth: "user",
|
|
1416
|
-
tags: [
|
|
1417
|
-
"site-{siteId}",
|
|
1418
|
-
"api-keys",
|
|
1419
|
-
"management-keys"
|
|
1420
|
-
],
|
|
1421
|
-
responseKind: "json"
|
|
1422
|
-
},
|
|
1423
|
-
createManagementKey: {
|
|
1424
|
-
path: "/sites/{siteId}/api-keys/management",
|
|
1425
|
-
method: "POST",
|
|
1426
|
-
auth: "user",
|
|
1427
|
-
tags: [
|
|
1428
|
-
"site-{siteId}",
|
|
1429
|
-
"api-keys",
|
|
1430
|
-
"management-keys"
|
|
1431
|
-
],
|
|
1432
|
-
responseKind: "json"
|
|
1433
|
-
},
|
|
1434
|
-
revokeManagementKey: {
|
|
1435
|
-
path: "/sites/{siteId}/api-keys/management",
|
|
1436
|
-
method: "DELETE",
|
|
1437
|
-
auth: "user",
|
|
1438
|
-
tags: [
|
|
1439
|
-
"site-{siteId}",
|
|
1440
|
-
"api-keys",
|
|
1441
|
-
"management-keys"
|
|
1442
|
-
],
|
|
1443
|
-
responseKind: "json"
|
|
1444
|
-
}
|
|
1445
|
-
});
|
|
1446
|
-
//#endregion
|
|
1447
|
-
//#region ../api/src/eventManagementEndpointDefinitions.ts
|
|
1448
|
-
const EVENT_MANAGEMENT_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
|
|
1449
|
-
listEvents: {
|
|
1450
|
-
path: "/sites/{siteId}/bookings/events",
|
|
1451
|
-
method: "GET",
|
|
1452
|
-
tags: ["site-{siteId}", "event-series-{siteId}"],
|
|
1453
|
-
auth: "user",
|
|
1454
|
-
responseKind: "json",
|
|
1455
|
-
errors: []
|
|
1456
|
-
},
|
|
1457
|
-
createEvent: {
|
|
1458
|
-
path: "/sites/{siteId}/bookings/events",
|
|
1459
|
-
method: "POST",
|
|
1460
|
-
tags: ["site-{siteId}", "event-series-{siteId}"],
|
|
1461
|
-
auth: "user",
|
|
1462
|
-
responseKind: "json",
|
|
1463
|
-
errors: [
|
|
1464
|
-
"validation:invalid_input",
|
|
1465
|
-
"resource:already_exists",
|
|
1466
|
-
"server:internal_error"
|
|
1467
|
-
]
|
|
1468
|
-
},
|
|
1469
|
-
transitionEventLifecycle: {
|
|
1470
|
-
path: "/sites/{siteId}/bookings/events/{eventId}/lifecycle",
|
|
1471
|
-
method: "POST",
|
|
1472
|
-
tags: ["site-{siteId}", "event-series-{siteId}"],
|
|
1473
|
-
auth: "user",
|
|
1474
|
-
responseKind: "json",
|
|
1475
|
-
errors: [
|
|
1476
|
-
"validation:invalid_input",
|
|
1477
|
-
"resource:not_found",
|
|
1478
|
-
"resource:conflict",
|
|
1479
|
-
"server:internal_error"
|
|
1480
|
-
]
|
|
1481
|
-
},
|
|
1482
|
-
updateEventIdentity: {
|
|
1483
|
-
path: "/sites/{siteId}/bookings/events/{eventId}",
|
|
1484
|
-
method: "PATCH",
|
|
1485
|
-
tags: ["site-{siteId}", "event-series-{siteId}"],
|
|
1486
|
-
auth: "user",
|
|
1487
|
-
responseKind: "json",
|
|
1488
|
-
errors: [
|
|
1489
|
-
"validation:invalid_input",
|
|
1490
|
-
"resource:not_found",
|
|
1491
|
-
"server:internal_error"
|
|
1492
|
-
]
|
|
1493
|
-
},
|
|
1494
|
-
createWholeSeriesRun: {
|
|
1495
|
-
path: "/sites/{siteId}/bookings/events/{eventId}/runs",
|
|
1496
|
-
method: "POST",
|
|
1497
|
-
tags: ["site-{siteId}", "event-series-{siteId}"],
|
|
1498
|
-
auth: "user",
|
|
1499
|
-
responseKind: "json",
|
|
1500
|
-
errors: [
|
|
1501
|
-
"validation:invalid_input",
|
|
1502
|
-
"resource:not_found",
|
|
1503
|
-
"resource:already_exists",
|
|
1504
|
-
"server:internal_error"
|
|
1505
|
-
]
|
|
1506
|
-
},
|
|
1507
|
-
updateWholeSeriesRun: {
|
|
1508
|
-
path: "/sites/{siteId}/bookings/events/{eventId}/runs/{runId}",
|
|
1509
|
-
method: "PATCH",
|
|
1510
|
-
tags: ["site-{siteId}", "event-series-{siteId}"],
|
|
1511
|
-
auth: "user",
|
|
1512
|
-
responseKind: "json",
|
|
1513
|
-
errors: [
|
|
1514
|
-
"validation:invalid_input",
|
|
1515
|
-
"resource:not_found",
|
|
1516
|
-
"resource:conflict",
|
|
1517
|
-
"server:internal_error"
|
|
1518
|
-
]
|
|
1519
|
-
},
|
|
1520
|
-
cancelWholeSeriesRun: {
|
|
1521
|
-
path: "/sites/{siteId}/bookings/events/{eventId}/runs/{runId}/cancellation",
|
|
1522
|
-
method: "POST",
|
|
1523
|
-
tags: ["site-{siteId}", "event-series-{siteId}"],
|
|
1524
|
-
auth: "user",
|
|
1525
|
-
responseKind: "json",
|
|
1526
|
-
errors: [
|
|
1527
|
-
"validation:invalid_input",
|
|
1528
|
-
"resource:not_found",
|
|
1529
|
-
"resource:conflict",
|
|
1530
|
-
"server:internal_error"
|
|
1531
|
-
]
|
|
1532
|
-
}
|
|
1533
|
-
});
|
|
1534
|
-
//#endregion
|
|
1535
|
-
//#region ../api/src/giftingEndpointDefinitions.ts
|
|
1536
|
-
/**
|
|
1537
|
-
* Gifting endpoints (gift cards & vouchers) — the dashboard surface that manages
|
|
1538
|
-
* offers, gifts and settings, plus the public buy/claim surface.
|
|
1539
|
-
*/
|
|
1540
|
-
const GIFTING_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
|
|
1541
|
-
createGiftingOffer: {
|
|
1542
|
-
path: "/sites/{siteId}/gifting/offers",
|
|
1543
|
-
method: "POST",
|
|
1544
|
-
tags: ["site-{siteId}", "gifting-offers-{siteId}"],
|
|
1545
|
-
auth: "user",
|
|
1546
|
-
responseKind: "json",
|
|
1547
|
-
errors: [
|
|
1548
|
-
"validation:invalid_input",
|
|
1549
|
-
"auth:forbidden",
|
|
1550
|
-
"server:internal_error"
|
|
1551
|
-
]
|
|
1552
|
-
},
|
|
1553
|
-
updateGiftingOffer: {
|
|
1554
|
-
path: "/sites/{siteId}/gifting/offers/{offerId}",
|
|
1555
|
-
method: "PATCH",
|
|
1556
|
-
tags: ["site-{siteId}", "gifting-offers-{siteId}"],
|
|
1557
|
-
auth: "user",
|
|
1558
|
-
responseKind: "json",
|
|
1559
|
-
errors: [
|
|
1560
|
-
"validation:invalid_input",
|
|
1561
|
-
"auth:forbidden",
|
|
1562
|
-
"resource:not_found",
|
|
1563
|
-
"resource:conflict",
|
|
1564
|
-
"server:internal_error"
|
|
1565
|
-
]
|
|
1566
|
-
},
|
|
1567
|
-
deleteGiftingOffer: {
|
|
1568
|
-
path: "/sites/{siteId}/gifting/offers/{offerId}",
|
|
1569
|
-
method: "DELETE",
|
|
1570
|
-
tags: ["site-{siteId}", "gifting-offers-{siteId}"],
|
|
1571
|
-
auth: "user",
|
|
1572
|
-
responseKind: "json",
|
|
1573
|
-
errors: [
|
|
1574
|
-
"auth:forbidden",
|
|
1575
|
-
"resource:not_found",
|
|
1576
|
-
"resource:conflict",
|
|
1577
|
-
"server:internal_error"
|
|
1578
|
-
]
|
|
1579
|
-
},
|
|
1580
|
-
duplicateGiftingOffer: {
|
|
1581
|
-
path: "/sites/{siteId}/gifting/offers/{offerId}/duplicate",
|
|
1582
|
-
method: "POST",
|
|
1583
|
-
tags: ["site-{siteId}", "gifting-offers-{siteId}"],
|
|
1584
|
-
auth: "user",
|
|
1585
|
-
responseKind: "json",
|
|
1586
|
-
errors: [
|
|
1587
|
-
"auth:forbidden",
|
|
1588
|
-
"resource:not_found",
|
|
1589
|
-
"server:internal_error"
|
|
1590
|
-
]
|
|
1591
|
-
},
|
|
1592
|
-
reorderGiftingOffers: {
|
|
1593
|
-
path: "/sites/{siteId}/gifting/offers/order",
|
|
1594
|
-
method: "PUT",
|
|
1595
|
-
tags: ["site-{siteId}", "gifting-offers-{siteId}"],
|
|
1596
|
-
auth: "user",
|
|
1597
|
-
responseKind: "json",
|
|
1598
|
-
errors: [
|
|
1599
|
-
"validation:invalid_input",
|
|
1600
|
-
"auth:forbidden",
|
|
1601
|
-
"resource:not_found",
|
|
1602
|
-
"server:internal_error"
|
|
1603
|
-
]
|
|
1604
|
-
},
|
|
1605
|
-
sendGift: {
|
|
1606
|
-
path: "/sites/{siteId}/gifting/gifts",
|
|
1607
|
-
method: "POST",
|
|
1608
|
-
tags: ["site-{siteId}", "gifting-gifts-{siteId}"],
|
|
1609
|
-
auth: "user",
|
|
1610
|
-
demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN,
|
|
1611
|
-
responseKind: "json",
|
|
1612
|
-
errors: [
|
|
1613
|
-
"validation:invalid_input",
|
|
1614
|
-
"auth:forbidden",
|
|
1615
|
-
"resource:not_found",
|
|
1616
|
-
"server:internal_error"
|
|
1617
|
-
]
|
|
1618
|
-
},
|
|
1619
|
-
resendGift: {
|
|
1620
|
-
path: "/sites/{siteId}/gifting/gifts/{giftId}/resend",
|
|
1621
|
-
method: "POST",
|
|
1622
|
-
tags: ["site-{siteId}", "gifting-gifts-{siteId}"],
|
|
1623
|
-
auth: "user",
|
|
1624
|
-
demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN,
|
|
1625
|
-
responseKind: "json",
|
|
1626
|
-
errors: [
|
|
1627
|
-
"auth:forbidden",
|
|
1628
|
-
"resource:not_found",
|
|
1629
|
-
"resource:conflict",
|
|
1630
|
-
"server:internal_error"
|
|
1631
|
-
]
|
|
1632
|
-
},
|
|
1633
|
-
correctGiftEmailAndResend: {
|
|
1634
|
-
path: "/sites/{siteId}/gifting/gifts/{giftId}/correct-email-and-resend",
|
|
1635
|
-
method: "POST",
|
|
1636
|
-
tags: ["site-{siteId}", "gifting-gifts-{siteId}"],
|
|
1637
|
-
auth: "user",
|
|
1638
|
-
demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN,
|
|
1639
|
-
responseKind: "json",
|
|
1640
|
-
errors: [
|
|
1641
|
-
"validation:invalid_input",
|
|
1642
|
-
"auth:forbidden",
|
|
1643
|
-
"resource:not_found",
|
|
1644
|
-
"resource:conflict",
|
|
1645
|
-
"server:internal_error"
|
|
1646
|
-
]
|
|
1647
|
-
},
|
|
1648
|
-
updateGiftingSettings: {
|
|
1649
|
-
path: "/sites/{siteId}/gifting/settings",
|
|
1650
|
-
method: "PATCH",
|
|
1651
|
-
tags: [
|
|
1652
|
-
"site-{siteId}",
|
|
1653
|
-
"gifting-offers-{siteId}",
|
|
1654
|
-
"gifting-gifts-{siteId}"
|
|
1655
|
-
],
|
|
1656
|
-
auth: "user",
|
|
1657
|
-
responseKind: "json",
|
|
1658
|
-
errors: [
|
|
1659
|
-
"validation:invalid_input",
|
|
1660
|
-
"auth:forbidden",
|
|
1661
|
-
"server:internal_error"
|
|
1662
|
-
]
|
|
1663
|
-
},
|
|
1664
|
-
listPublicGiftingOffers: {
|
|
1665
|
-
path: "/public/sites/{siteId}/gifting/offers",
|
|
1666
|
-
method: "GET",
|
|
1667
|
-
revalidate: 300,
|
|
1668
|
-
tags: [TAG_TEMPLATES.publicGifting],
|
|
1669
|
-
errors: [],
|
|
1670
|
-
auth: "public",
|
|
1671
|
-
responseKind: "json"
|
|
1672
|
-
},
|
|
1673
|
-
createPublicGiftingCheckout: {
|
|
1674
|
-
path: "/public/sites/{siteId}/gifting/checkout",
|
|
1675
|
-
method: "POST",
|
|
1676
|
-
tags: [TAG_TEMPLATES.publicGifting],
|
|
1677
|
-
errors: [],
|
|
1678
|
-
auth: "public",
|
|
1679
|
-
responseKind: "json"
|
|
1680
|
-
},
|
|
1681
|
-
claimGiftCardPublic: {
|
|
1682
|
-
path: "/public/sites/{siteId}/gifting/claim",
|
|
1683
|
-
method: "POST",
|
|
1684
|
-
tags: [TAG_TEMPLATES.publicGifting],
|
|
1685
|
-
errors: [],
|
|
1686
|
-
auth: "public",
|
|
1687
|
-
responseKind: "json"
|
|
1688
|
-
}
|
|
1689
|
-
});
|
|
1690
|
-
//#endregion
|
|
1691
|
-
//#region ../api/src/sdkEndpointDefinitions.ts
|
|
1692
|
-
/** SDK management endpoints that do not belong to a CRUD resource family. */
|
|
1693
|
-
const SDK_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
|
|
1694
|
-
sdkUpdateSettings: {
|
|
1695
|
-
path: "/sdk/{siteId}/settings",
|
|
1696
|
-
method: "PATCH",
|
|
1697
|
-
auth: "service",
|
|
1698
|
-
responseKind: "json",
|
|
1699
|
-
errors: ["validation:invalid_input", "server:internal_error"]
|
|
1700
|
-
},
|
|
1701
|
-
sdkConfigureBookingVertical: {
|
|
1702
|
-
path: "/sdk/{siteId}/settings/booking/vertical",
|
|
1703
|
-
method: "POST",
|
|
1704
|
-
auth: "service",
|
|
1705
|
-
responseKind: "json"
|
|
1706
|
-
},
|
|
1707
|
-
sdkSetupRevalidationWebhook: {
|
|
1708
|
-
path: "/sdk/{siteId}/webhooks/revalidation/setup",
|
|
1709
|
-
method: "POST",
|
|
1710
|
-
auth: "service",
|
|
1711
|
-
responseKind: "json",
|
|
1712
|
-
errors: ["validation:invalid_input", "server:internal_error"]
|
|
1713
|
-
}
|
|
1714
|
-
});
|
|
1715
|
-
//#endregion
|
|
1716
|
-
//#region ../api/src/sdkMediaEndpointDefinitions.ts
|
|
1717
|
-
/** SDK media lookup, listing, deletion and upload endpoints (management-key authenticated). */
|
|
1718
|
-
const SDK_MEDIA_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
|
|
1719
|
-
sdkMediaExists: {
|
|
1720
|
-
path: "/sdk/{siteId}/media/exists",
|
|
1721
|
-
method: "POST",
|
|
1722
|
-
errors: ["validation:invalid_input"],
|
|
1723
|
-
auth: "service",
|
|
1724
|
-
responseKind: "json"
|
|
1725
|
-
},
|
|
1726
|
-
sdkMediaFindByChecksum: {
|
|
1727
|
-
path: "/sdk/{siteId}/media/find-by-checksum",
|
|
1728
|
-
method: "POST",
|
|
1729
|
-
errors: ["server:internal_error"],
|
|
1730
|
-
auth: "service",
|
|
1731
|
-
responseKind: "json"
|
|
1732
|
-
},
|
|
1733
|
-
sdkMediaResolve: {
|
|
1734
|
-
path: "/sdk/{siteId}/media/resolve",
|
|
1735
|
-
method: "POST",
|
|
1736
|
-
errors: ["server:internal_error"],
|
|
1737
|
-
auth: "service",
|
|
1738
|
-
responseKind: "json"
|
|
1739
|
-
},
|
|
1740
|
-
sdkMediaList: {
|
|
1741
|
-
path: "/sdk/{siteId}/media",
|
|
1742
|
-
method: "GET",
|
|
1743
|
-
auth: "service",
|
|
1744
|
-
errors: [],
|
|
1745
|
-
responseKind: "json"
|
|
1746
|
-
},
|
|
1747
|
-
sdkMediaDownload: {
|
|
1748
|
-
path: "/sdk/{siteId}/media/{identifier}/download",
|
|
1749
|
-
method: "GET",
|
|
1750
|
-
auth: "service",
|
|
1751
|
-
errors: [],
|
|
1752
|
-
responseKind: "json"
|
|
1753
|
-
},
|
|
1754
|
-
sdkMediaDeletePreview: {
|
|
1755
|
-
path: "/sdk/{siteId}/media/{identifier}/delete-preview",
|
|
1756
|
-
method: "POST",
|
|
1757
|
-
auth: "service",
|
|
1758
|
-
errors: [],
|
|
1759
|
-
responseKind: "json"
|
|
1760
|
-
},
|
|
1761
|
-
sdkMediaDeleteApply: {
|
|
1762
|
-
path: "/sdk/{siteId}/media/{identifier}",
|
|
1763
|
-
method: "DELETE",
|
|
1764
|
-
auth: "service",
|
|
1765
|
-
errors: [],
|
|
1766
|
-
responseKind: "json"
|
|
1767
|
-
},
|
|
1768
|
-
sdkMediaUploadUrl: {
|
|
1769
|
-
path: "/sdk/{siteId}/media/upload-url",
|
|
1770
|
-
method: "POST",
|
|
1771
|
-
errors: [
|
|
1772
|
-
"resource:not_found",
|
|
1773
|
-
"validation:invalid_input",
|
|
1774
|
-
"resource:conflict",
|
|
1775
|
-
"validation:payload_too_large",
|
|
1776
|
-
"billing:plan_limit_exceeded",
|
|
1777
|
-
"server:internal_error"
|
|
1778
|
-
],
|
|
1779
|
-
auth: "service",
|
|
1780
|
-
responseKind: "json"
|
|
1781
|
-
},
|
|
1782
|
-
sdkMediaUploadFinalize: {
|
|
1783
|
-
path: "/sdk/{siteId}/media/upload",
|
|
1784
|
-
method: "POST",
|
|
1785
|
-
errors: [
|
|
1786
|
-
"resource:not_found",
|
|
1787
|
-
"validation:invalid_input",
|
|
1788
|
-
"resource:conflict",
|
|
1789
|
-
"validation:payload_too_large",
|
|
1790
|
-
"billing:plan_limit_exceeded",
|
|
1791
|
-
"server:internal_error"
|
|
1792
|
-
],
|
|
1793
|
-
auth: "service",
|
|
1794
|
-
responseKind: "json"
|
|
1795
|
-
}
|
|
1796
|
-
});
|
|
1797
|
-
({
|
|
1798
|
-
...ACCOUNT_ENDPOINT_DEFINITIONS,
|
|
1799
|
-
...PUBLIC_EVENT_ENDPOINT_DEFINITIONS,
|
|
1800
|
-
...GIFTING_ENDPOINT_DEFINITIONS
|
|
1801
|
-
}), TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteTheme, TAG_TEMPLATES.siteCollection, { ...SITE_API_KEY_ENDPOINT_DEFINITIONS }, TAG_TEMPLATES.site, TAG_TEMPLATES.siteBookingSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteBookingSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteEmailSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteEmailSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteEmailSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteEmailSettings, {
|
|
1802
|
-
...NEWSLETTER_ENDPOINT_DEFINITIONS,
|
|
1803
|
-
...APPOINTMENT_ENDPOINT_DEFINITIONS,
|
|
1804
|
-
...EVENT_SERIES_REGISTRATION_ENDPOINT_DEFINITIONS
|
|
1805
|
-
}, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteById, TAG_TEMPLATES.siteBySlug, TAG_TEMPLATES.siteByDomain, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteById, TAG_TEMPLATES.siteBySlug, TAG_TEMPLATES.siteByDomain, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.workflowRunById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.routeById, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.site, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteNavigation, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteNavigation, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteNavigation, TAG_TEMPLATES.navigationMenuById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteNavigation, TAG_TEMPLATES.navigationMenuById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteNavigation, TAG_TEMPLATES.navigationMenuById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteNavigation, TAG_TEMPLATES.navigationMenuById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteNavigation, TAG_TEMPLATES.navigationMenuById, TAG_TEMPLATES.navigationItemById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteNavigation, TAG_TEMPLATES.navigationMenuById, TAG_TEMPLATES.navigationItemById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteNavigation, TAG_TEMPLATES.navigationMenuById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteTheme, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteTheme, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteTheme, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteRedirects, TAG_TEMPLATES.siteRouteOutcomes, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteRedirects, TAG_TEMPLATES.siteRouteOutcomes, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.formSubmissionsBySlug, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.formSubmissionsBySlug, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.formSubmissionsBySlug, TAG_TEMPLATES.formById, TAG_TEMPLATES.siteForms, { ...PUBLIC_BOOKING_AVAILABILITY_ENDPOINT_DEFINITIONS }, TAG_TEMPLATES.publicEvents, TAG_TEMPLATES.publicEventFilters, TAG_TEMPLATES.publicTeamMembers, TAG_TEMPLATES.publicEvents, TAG_TEMPLATES.publicPasses, TAG_TEMPLATES.publicMemberships, TAG_TEMPLATES.publicProducts, TAG_TEMPLATES.publicShop, TAG_TEMPLATES.publicCheckout, TAG_TEMPLATES.siteRoutableContent, { ...PUBLIC_EVENT_CHECKOUT_ENDPOINT_DEFINITIONS }, TAG_TEMPLATES.publicEvents, TAG_TEMPLATES.publicEvents, { ...EVENT_MANAGEMENT_ENDPOINT_DEFINITIONS }, { ...SDK_MEDIA_ENDPOINT_DEFINITIONS }, { ...SDK_ENDPOINT_DEFINITIONS }, { ...SDK_ENTRY_READ_ENDPOINTS };
|
|
1806
|
-
z.object({ refreshToken: z.string().min(1).max(4096) }).strict();
|
|
1807
|
-
z.object({
|
|
1808
|
-
accessToken: z.string().min(1).max(4096),
|
|
1809
|
-
refreshToken: z.string().min(1).max(4096)
|
|
1810
|
-
}).strict();
|
|
1811
|
-
const ACCOUNT_SITE_CURSOR_MAX_LENGTH = 2048;
|
|
1812
|
-
const ACCOUNT_SITE_TIMESTAMP_PATTERN = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.(\d{1,6}))?(Z|[+-]\d{2}:\d{2})$/;
|
|
1813
|
-
/** Strict, injection-safe PostgreSQL/RFC3339 timestamp text used in cursors. */
|
|
1814
|
-
function isAccountSiteTimestamp(value) {
|
|
1815
|
-
if (typeof value !== "string") return false;
|
|
1816
|
-
const match = ACCOUNT_SITE_TIMESTAMP_PATTERN.exec(value);
|
|
1817
|
-
if (!match) return false;
|
|
1818
|
-
const [, year, month, day, hour, minute, second, , offset] = match;
|
|
1819
|
-
const date = new Date(Date.UTC(Number(year), Number(month) - 1, Number(day)));
|
|
1820
|
-
const offsetValue = offset ?? "";
|
|
1821
|
-
const offsetIsValid = offsetValue === "Z" || (() => {
|
|
1822
|
-
const offsetMatch = /^(?:[+-])(\d{2}):(\d{2})$/.exec(offsetValue);
|
|
1823
|
-
if (!offsetMatch) return false;
|
|
1824
|
-
return Number(offsetMatch[1]) <= 23 && Number(offsetMatch[2]) <= 59;
|
|
1825
|
-
})();
|
|
1826
|
-
return date.getUTCFullYear() === Number(year) && date.getUTCMonth() === Number(month) - 1 && date.getUTCDate() === Number(day) && Number(hour) <= 23 && Number(minute) <= 59 && Number(second) <= 59 && offsetIsValid;
|
|
1827
|
-
}
|
|
1828
|
-
const accountSiteTimestampSchema = z.string().refine(isAccountSiteTimestamp, { message: "Expected a strict account site timestamp" });
|
|
1829
|
-
z.enum([
|
|
1830
|
-
"managed",
|
|
1831
|
-
"headless_cms",
|
|
1832
|
-
"headless_full"
|
|
1833
|
-
]);
|
|
1834
|
-
z.object({ title: z.string().trim().min(1).max(120) });
|
|
1835
|
-
const abandonedStandardKeyIdsSchema = z.object({
|
|
1836
|
-
live: z.string().uuid().optional(),
|
|
1837
|
-
management: z.string().uuid().optional()
|
|
1838
|
-
}).strict();
|
|
1839
|
-
const abandonedPreviewKeyIdsSchema = z.object({
|
|
1840
|
-
live: z.string().uuid().optional(),
|
|
1841
|
-
management: z.string().uuid().optional(),
|
|
1842
|
-
preview: z.string().uuid().optional()
|
|
1843
|
-
}).strict();
|
|
1844
|
-
z.discriminatedUnion("operation", [
|
|
1845
|
-
z.object({
|
|
1846
|
-
operation: z.literal("issue_standard"),
|
|
1847
|
-
siteId: z.string().uuid(),
|
|
1848
|
-
operationId: z.string().uuid(),
|
|
1849
|
-
projectName: z.string().trim().min(1).max(120),
|
|
1850
|
-
abandonedKeyIds: abandonedStandardKeyIdsSchema.default({})
|
|
1851
|
-
}).strict(),
|
|
1852
|
-
z.object({
|
|
1853
|
-
operation: z.literal("issue_with_preview"),
|
|
1854
|
-
siteId: z.string().uuid(),
|
|
1855
|
-
operationId: z.string().uuid(),
|
|
1856
|
-
projectName: z.string().trim().min(1).max(120),
|
|
1857
|
-
abandonedKeyIds: abandonedPreviewKeyIdsSchema.default({})
|
|
1858
|
-
}).strict(),
|
|
1859
|
-
z.object({
|
|
1860
|
-
operation: z.literal("revalidate_standard"),
|
|
1861
|
-
siteId: z.string().uuid(),
|
|
1862
|
-
operationId: z.string().uuid(),
|
|
1863
|
-
projectName: z.string().trim().min(1).max(120),
|
|
1864
|
-
keyIds: z.object({
|
|
1865
|
-
live: z.string().uuid(),
|
|
1866
|
-
management: z.string().uuid()
|
|
1867
|
-
}).strict()
|
|
1868
|
-
}).strict(),
|
|
1869
|
-
z.object({
|
|
1870
|
-
operation: z.literal("revalidate_with_preview"),
|
|
1871
|
-
siteId: z.string().uuid(),
|
|
1872
|
-
operationId: z.string().uuid(),
|
|
1873
|
-
projectName: z.string().trim().min(1).max(120),
|
|
1874
|
-
keyIds: z.object({
|
|
1875
|
-
live: z.string().uuid(),
|
|
1876
|
-
management: z.string().uuid(),
|
|
1877
|
-
preview: z.string().uuid()
|
|
1878
|
-
}).strict()
|
|
1879
|
-
}).strict()
|
|
1880
|
-
]);
|
|
1881
|
-
z.object({
|
|
1882
|
-
cursor: z.string().min(1).max(ACCOUNT_SITE_CURSOR_MAX_LENGTH).optional(),
|
|
1883
|
-
limit: z.coerce.number().int().min(1).max(100).default(50),
|
|
1884
|
-
search: z.string().trim().min(1).max(120).optional()
|
|
1885
|
-
});
|
|
1886
|
-
//#endregion
|
|
1887
|
-
//#region ../core/src/result.ts
|
|
1888
|
-
function ok(value) {
|
|
1889
|
-
return {
|
|
1890
|
-
ok: true,
|
|
1891
|
-
value
|
|
1892
|
-
};
|
|
1893
|
-
}
|
|
1894
|
-
function err(error) {
|
|
1895
|
-
return {
|
|
1896
|
-
ok: false,
|
|
1897
|
-
error
|
|
1898
|
-
};
|
|
1899
|
-
}
|
|
1900
|
-
//#endregion
|
|
1901
|
-
//#region ../core/src/branded.ts
|
|
1902
|
-
const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
1903
|
-
function parseUuidBrand(value, unsafeConstructor) {
|
|
1904
|
-
if (typeof value !== "string") return err({ kind: "not_string" });
|
|
1905
|
-
const normalized = value.trim().toLowerCase();
|
|
1906
|
-
if (normalized.length === 0) return err({ kind: "empty_string" });
|
|
1907
|
-
if (!UUID_PATTERN.test(normalized)) return err({ kind: "invalid_uuid" });
|
|
1908
|
-
return ok(unsafeConstructor(normalized));
|
|
1909
|
-
}
|
|
1910
|
-
const unsafeAsSiteId = (id) => id;
|
|
1911
|
-
const unsafeAsApiKeyId = (id) => id;
|
|
1912
|
-
const unsafeAsEventOfferingId = (id) => id;
|
|
1913
|
-
const unsafeAsEventSeriesId = (id) => id;
|
|
1914
|
-
const unsafeAsUserId = (id) => id;
|
|
1915
|
-
const parseSiteId = (value) => parseUuidBrand(value, unsafeAsSiteId);
|
|
1916
|
-
const parseApiKeyId = (value) => parseUuidBrand(value, unsafeAsApiKeyId);
|
|
1917
|
-
const parseEventOfferingId = (value) => parseUuidBrand(value, unsafeAsEventOfferingId);
|
|
1918
|
-
const parseUserId = (value) => parseUuidBrand(value, unsafeAsUserId);
|
|
1919
|
-
const parseEventSeriesId = (value) => parseUuidBrand(value, unsafeAsEventSeriesId);
|
|
1920
|
-
//#endregion
|
|
1921
|
-
//#region ../core/src/assert-never.ts
|
|
1922
|
-
function assertNever$2(value, message = "Unexpected variant") {
|
|
1923
|
-
throw new Error(`${message}: ${String(value)}`);
|
|
1924
|
-
}
|
|
1925
|
-
//#endregion
|
|
1926
|
-
//#region ../core/src/currency-format.ts
|
|
1927
|
-
const CURRENCY_LOCALE_BY_CODE = {
|
|
1928
|
-
USD: "en-US",
|
|
1929
|
-
GBP: "en-GB",
|
|
1930
|
-
EUR: "de-DE",
|
|
1931
|
-
AUD: "en-AU",
|
|
1932
|
-
CAD: "en-CA",
|
|
1933
|
-
NZD: "en-NZ",
|
|
1934
|
-
JPY: "ja-JP",
|
|
1935
|
-
CNY: "zh-CN",
|
|
1936
|
-
CHF: "de-CH"
|
|
1937
|
-
};
|
|
1938
|
-
function resolveCurrencyLocale(currencyCode, override) {
|
|
1939
|
-
return override ?? CURRENCY_LOCALE_BY_CODE[currencyCode] ?? "en";
|
|
1940
|
-
}
|
|
1941
|
-
/**
|
|
1942
|
-
* The single currency-amount formatter for the product: minor units in,
|
|
1943
|
-
* localized string out.
|
|
1944
|
-
*
|
|
1945
|
-
* The locale is derived from the currency by default, so output is deterministic
|
|
1946
|
-
* across server and client (no SSR/hydration mismatch). All other money
|
|
1947
|
-
* formatters in the codebase should delegate here rather than constructing their
|
|
1948
|
-
* own `Intl.NumberFormat`.
|
|
1949
|
-
*/
|
|
1950
|
-
function formatCurrencyAmount(amountCents, currency, options) {
|
|
1951
|
-
const currencyCode = currency.toUpperCase();
|
|
1952
|
-
const locale = resolveCurrencyLocale(currencyCode, options?.locale);
|
|
1953
|
-
try {
|
|
1954
|
-
const exactFormatter = new Intl.NumberFormat(locale, {
|
|
1955
|
-
style: "currency",
|
|
1956
|
-
currency: currencyCode
|
|
1957
|
-
});
|
|
1958
|
-
const fractionDigits = options?.decimals === "auto" ? {
|
|
1959
|
-
minimumFractionDigits: 0,
|
|
1960
|
-
maximumFractionDigits: exactFormatter.resolvedOptions().maximumFractionDigits
|
|
1961
|
-
} : {};
|
|
1962
|
-
return new Intl.NumberFormat(locale, {
|
|
1963
|
-
style: "currency",
|
|
1964
|
-
currency: currencyCode,
|
|
1965
|
-
...fractionDigits
|
|
1966
|
-
}).format(amountCents / 100);
|
|
1967
|
-
} catch {
|
|
1968
|
-
return `${(amountCents / 100).toFixed(2)} ${currencyCode}`;
|
|
1969
|
-
}
|
|
1970
|
-
}
|
|
1971
|
-
//#endregion
|
|
1972
|
-
//#region ../core/src/planner.ts
|
|
1973
|
-
/** Default clock for production callers that do not inject time explicitly. */
|
|
1974
|
-
const systemPlanningClock = { now: () => Date.now() };
|
|
1975
|
-
/** Resolve current time as a Date from an explicit Date, injected clock, or system clock. */
|
|
1976
|
-
function resolvePlanningNowDate(input = {}) {
|
|
1977
|
-
if (input.now !== void 0) return input.now;
|
|
1978
|
-
return new Date((input.clock ?? systemPlanningClock).now());
|
|
1979
|
-
}
|
|
1980
|
-
//#endregion
|
|
1981
|
-
//#region ../core/src/event-pricing.ts
|
|
1982
|
-
/** Capacity closes booking, but does not make an otherwise eligible price unknown. */
|
|
1983
|
-
function isPublicEventPricingOptionDisplayable(option) {
|
|
1984
|
-
if (!option.isActive) return false;
|
|
1985
|
-
if (option.availability.kind === "available") return true;
|
|
1986
|
-
const reason = option.availability.reason;
|
|
1987
|
-
switch (reason) {
|
|
1988
|
-
case "sold_out":
|
|
1989
|
-
case "overallCapacityUnavailable": return true;
|
|
1990
|
-
case "inactive":
|
|
1991
|
-
case "not_on_sale_yet":
|
|
1992
|
-
case "sale_ended":
|
|
1993
|
-
case "attendance_mode_unavailable": return false;
|
|
1994
|
-
default: return assertNever$2(reason);
|
|
1995
|
-
}
|
|
1996
|
-
}
|
|
1997
|
-
function publicEventPricingDisplay(pricing) {
|
|
1998
|
-
switch (pricing.kind) {
|
|
1999
|
-
case "free":
|
|
2000
|
-
case "single":
|
|
2001
|
-
case "sliding_scale": return canonicalEventPricingDisplay(pricing);
|
|
2002
|
-
case "tiered": return resolvePricingOptionsPriceDisplay({
|
|
2003
|
-
options: pricing.options.filter(isPublicEventPricingOptionDisplayable),
|
|
2004
|
-
currency: pricing.currency,
|
|
2005
|
-
purpose: "configured"
|
|
2006
|
-
});
|
|
2007
|
-
case "external": return {
|
|
2008
|
-
kind: "external",
|
|
2009
|
-
label: pricing.label
|
|
2010
|
-
};
|
|
2011
|
-
}
|
|
2012
|
-
}
|
|
2013
|
-
function publicEventPricingType(pricing) {
|
|
2014
|
-
switch (pricing.kind) {
|
|
2015
|
-
case "free": return "free";
|
|
2016
|
-
case "single":
|
|
2017
|
-
case "tiered":
|
|
2018
|
-
case "sliding_scale": return isFreePublicEventPriceDisplay(publicEventPricingDisplay(pricing)) ? "free" : "paid";
|
|
2019
|
-
case "external": return "external";
|
|
2020
|
-
}
|
|
2021
|
-
}
|
|
2022
|
-
function isFreePublicEventPriceDisplay(display) {
|
|
2023
|
-
switch (display.kind) {
|
|
2024
|
-
case "free": return true;
|
|
2025
|
-
case "exact":
|
|
2026
|
-
case "from":
|
|
2027
|
-
case "range":
|
|
2028
|
-
case "mixed":
|
|
2029
|
-
case "unavailable":
|
|
2030
|
-
case "external": return false;
|
|
2031
|
-
}
|
|
2032
|
-
}
|
|
2033
|
-
function resolvePricingOptionSaleWindowState(option, now) {
|
|
2034
|
-
if (option.saleStartsAt !== null && option.saleStartsAt !== void 0 && new Date(option.saleStartsAt) > now) return "not_started";
|
|
2035
|
-
if (option.saleEndsAt !== null && option.saleEndsAt !== void 0 && new Date(option.saleEndsAt) < now) return "ended";
|
|
2036
|
-
return "open";
|
|
2037
|
-
}
|
|
2038
|
-
function resolvePricingOptionsPriceDisplay(input) {
|
|
2039
|
-
const now = input.purpose === "available_now" ? resolvePlanningNowDate({
|
|
2040
|
-
now: input.now,
|
|
2041
|
-
clock: input.clock
|
|
2042
|
-
}) : null;
|
|
2043
|
-
const amounts = input.options.filter((option) => option.isActive && (now === null || resolvePricingOptionSaleWindowState(option, now) === "open")).map((option) => option.priceAmount);
|
|
2044
|
-
return amounts.length === 0 ? {
|
|
2045
|
-
kind: "unavailable",
|
|
2046
|
-
currency: input.currency
|
|
2047
|
-
} : amountRangeDisplay(amounts, input.currency);
|
|
2048
|
-
}
|
|
2049
|
-
function amountRangeDisplay(amounts, currency) {
|
|
2050
|
-
const minAmount = Math.min(...amounts);
|
|
2051
|
-
const maxAmount = Math.max(...amounts);
|
|
2052
|
-
if (minAmount === maxAmount) return minAmount === 0 ? {
|
|
2053
|
-
kind: "free",
|
|
2054
|
-
currency
|
|
2055
|
-
} : {
|
|
2056
|
-
kind: "exact",
|
|
2057
|
-
amount: minAmount,
|
|
2058
|
-
currency
|
|
2059
|
-
};
|
|
2060
|
-
if (minAmount === 0) {
|
|
2061
|
-
const paidAmounts = amounts.filter((amount) => amount > 0);
|
|
2062
|
-
return {
|
|
2063
|
-
kind: "mixed",
|
|
2064
|
-
paidFromAmount: Math.min(...paidAmounts),
|
|
2065
|
-
paidToAmount: maxAmount,
|
|
2066
|
-
currency
|
|
2067
|
-
};
|
|
2068
|
-
}
|
|
2069
|
-
return {
|
|
2070
|
-
kind: "range",
|
|
2071
|
-
minAmount,
|
|
2072
|
-
maxAmount,
|
|
2073
|
-
currency
|
|
2074
|
-
};
|
|
2075
|
-
}
|
|
2076
|
-
/** Derives configured price presentation directly from canonical pricing. */
|
|
2077
|
-
function canonicalEventPricingDisplay(pricing) {
|
|
2078
|
-
switch (pricing.kind) {
|
|
2079
|
-
case "free": return {
|
|
2080
|
-
kind: "free",
|
|
2081
|
-
currency: pricing.currency
|
|
2082
|
-
};
|
|
2083
|
-
case "single": return {
|
|
2084
|
-
kind: "exact",
|
|
2085
|
-
amount: pricing.amount,
|
|
2086
|
-
currency: pricing.currency
|
|
2087
|
-
};
|
|
2088
|
-
case "sliding_scale": return pricing.minimum === pricing.maximum ? {
|
|
2089
|
-
kind: "exact",
|
|
2090
|
-
amount: pricing.maximum,
|
|
2091
|
-
currency: pricing.currency
|
|
2092
|
-
} : {
|
|
2093
|
-
kind: "range",
|
|
2094
|
-
minAmount: pricing.minimum,
|
|
2095
|
-
maxAmount: pricing.maximum,
|
|
2096
|
-
currency: pricing.currency
|
|
2097
|
-
};
|
|
2098
|
-
case "tiered": return resolvePricingOptionsPriceDisplay({
|
|
2099
|
-
options: pricing.options,
|
|
2100
|
-
currency: pricing.currency,
|
|
2101
|
-
purpose: "configured"
|
|
2102
|
-
});
|
|
2103
|
-
default: return assertNever$2(pricing);
|
|
2104
|
-
}
|
|
2105
|
-
}
|
|
2106
|
-
//#endregion
|
|
2107
|
-
//#region ../core/src/event-page-surface-subject.ts
|
|
2108
|
-
function createEventSeriesPageSurfaceSubject(eventSeriesId, bookingScope, eventDestinationMode) {
|
|
2109
|
-
const mode = eventDestinationMode ? { eventDestinationMode } : {};
|
|
2110
|
-
return bookingScope === "whole_series" ? {
|
|
2111
|
-
kind: "eventSeries",
|
|
2112
|
-
eventSeriesId,
|
|
2113
|
-
bookingScope,
|
|
2114
|
-
isWholeSeriesBooking: true,
|
|
2115
|
-
...mode
|
|
2116
|
-
} : {
|
|
2117
|
-
kind: "eventSeries",
|
|
2118
|
-
eventSeriesId,
|
|
2119
|
-
bookingScope,
|
|
2120
|
-
...mode
|
|
2121
|
-
};
|
|
2122
|
-
}
|
|
2123
|
-
function createEventOfferingPageSurfaceSubject(eventOfferingId, input) {
|
|
2124
|
-
const mode = input.eventDestinationMode ? { eventDestinationMode: input.eventDestinationMode } : {};
|
|
2125
|
-
const identity = {
|
|
2126
|
-
kind: "eventOffering",
|
|
2127
|
-
eventOfferingId,
|
|
2128
|
-
catalogueEventSeriesIds: input.catalogueEventSeriesIds
|
|
2129
|
-
};
|
|
2130
|
-
return input.bookingScope === "whole_series" ? {
|
|
2131
|
-
...identity,
|
|
2132
|
-
bookingScope: input.bookingScope,
|
|
2133
|
-
isWholeSeriesBooking: true,
|
|
2134
|
-
...mode
|
|
2135
|
-
} : {
|
|
2136
|
-
...identity,
|
|
2137
|
-
bookingScope: input.bookingScope,
|
|
2138
|
-
...mode
|
|
2139
|
-
};
|
|
2140
|
-
}
|
|
2141
|
-
/**
|
|
2142
|
-
* Read the destination mode off a wire value.
|
|
2143
|
-
*
|
|
2144
|
-
* Absent or unrecognised reads as absent, which leaves the routed Event record
|
|
2145
|
-
* as the only authority — the behaviour every caller had before the field
|
|
2146
|
-
* existed.
|
|
2147
|
-
*/
|
|
2148
|
-
function parseEventPageSurfaceDestinationMode(value) {
|
|
2149
|
-
return value === "cms-managed" || value === "system-managed" ? value : void 0;
|
|
2150
|
-
}
|
|
2151
|
-
function parseEventPageSurfaceSubject(value) {
|
|
2152
|
-
if (!isRecord$8(value)) return err({ kind: "notObject" });
|
|
2153
|
-
switch (value.kind) {
|
|
2154
|
-
case "eventSeries": {
|
|
2155
|
-
const eventSeriesId = parseEventSeriesId(value.eventSeriesId);
|
|
2156
|
-
if (!eventSeriesId.ok) return err({
|
|
2157
|
-
kind: "invalidEventSeriesId",
|
|
2158
|
-
error: eventSeriesId.error
|
|
2159
|
-
});
|
|
2160
|
-
if (value.bookingScope !== "single_occurrence" && value.bookingScope !== "whole_series") return err({
|
|
2161
|
-
kind: "invalidEventSeriesBookingScope",
|
|
2162
|
-
bookingScope: value.bookingScope
|
|
2163
|
-
});
|
|
2164
|
-
return ok(createEventSeriesPageSurfaceSubject(eventSeriesId.value, value.bookingScope, parseEventPageSurfaceDestinationMode(value.eventDestinationMode)));
|
|
2165
|
-
}
|
|
2166
|
-
case "eventOffering": {
|
|
2167
|
-
const eventOfferingId = parseEventOfferingId(value.eventOfferingId);
|
|
2168
|
-
if (!eventOfferingId.ok) return err({
|
|
2169
|
-
kind: "invalidEventOfferingId",
|
|
2170
|
-
error: eventOfferingId.error
|
|
2171
|
-
});
|
|
2172
|
-
if (!Array.isArray(value.catalogueEventSeriesIds)) return err({
|
|
2173
|
-
kind: "invalidEventOfferingCatalogue",
|
|
2174
|
-
catalogue: value.catalogueEventSeriesIds
|
|
2175
|
-
});
|
|
2176
|
-
if (value.bookingScope !== "single_occurrence" && value.bookingScope !== "whole_series") return err({
|
|
2177
|
-
kind: "invalidEventOfferingBookingScope",
|
|
2178
|
-
bookingScope: value.bookingScope
|
|
2179
|
-
});
|
|
2180
|
-
const parsedCatalogueIds = parseEventSeriesIdList(value.catalogueEventSeriesIds);
|
|
2181
|
-
if (!parsedCatalogueIds.ok) return parsedCatalogueIds;
|
|
2182
|
-
const eventDestinationMode = parseEventPageSurfaceDestinationMode(value.eventDestinationMode);
|
|
2183
|
-
return ok(createEventOfferingPageSurfaceSubject(eventOfferingId.value, {
|
|
2184
|
-
catalogueEventSeriesIds: parsedCatalogueIds.value,
|
|
2185
|
-
bookingScope: value.bookingScope,
|
|
2186
|
-
...eventDestinationMode ? { eventDestinationMode } : {}
|
|
2187
|
-
}));
|
|
2188
|
-
}
|
|
2189
|
-
default: return err({
|
|
2190
|
-
kind: "unsupportedSubject",
|
|
2191
|
-
subjectKind: value.kind
|
|
2192
|
-
});
|
|
2193
|
-
}
|
|
2194
|
-
}
|
|
2195
|
-
function parseEventSeriesIdList(values) {
|
|
2196
|
-
const parsed = [];
|
|
2197
|
-
for (const value of values) {
|
|
2198
|
-
const eventSeriesId = parseEventSeriesId(value);
|
|
2199
|
-
if (!eventSeriesId.ok) return err({
|
|
2200
|
-
kind: "invalidEventSeriesId",
|
|
2201
|
-
error: eventSeriesId.error
|
|
2202
|
-
});
|
|
2203
|
-
parsed.push(eventSeriesId.value);
|
|
2204
|
-
}
|
|
2205
|
-
return ok(parsed);
|
|
2206
|
-
}
|
|
2207
|
-
function isRecord$8(value) {
|
|
2208
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2209
|
-
}
|
|
1641
|
+
}
|
|
1642
|
+
function parseEventSeriesIdList(values) {
|
|
1643
|
+
const parsed = [];
|
|
1644
|
+
for (const value of values) {
|
|
1645
|
+
const eventSeriesId = parseEventSeriesId(value);
|
|
1646
|
+
if (!eventSeriesId.ok) return err({
|
|
1647
|
+
kind: "invalidEventSeriesId",
|
|
1648
|
+
error: eventSeriesId.error
|
|
1649
|
+
});
|
|
1650
|
+
parsed.push(eventSeriesId.value);
|
|
1651
|
+
}
|
|
1652
|
+
return ok(parsed);
|
|
1653
|
+
}
|
|
1654
|
+
function isRecord$11(value) {
|
|
1655
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1656
|
+
}
|
|
2210
1657
|
//#endregion
|
|
2211
1658
|
//#region ../core/src/booking-time-zone.ts
|
|
2212
1659
|
const TIME_ZONE_VALIDITY_CACHE_LIMIT = 100;
|
|
@@ -2375,7 +1822,7 @@ function toLocationCoordinates(value) {
|
|
|
2375
1822
|
}
|
|
2376
1823
|
//#endregion
|
|
2377
1824
|
//#region ../core/src/rich-text.ts
|
|
2378
|
-
function isRecord$
|
|
1825
|
+
function isRecord$10(value) {
|
|
2379
1826
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2380
1827
|
}
|
|
2381
1828
|
function hasOnlyKeys(value, allowed) {
|
|
@@ -2395,20 +1842,390 @@ function isDenseArrayOf(value, predicate) {
|
|
|
2395
1842
|
return true;
|
|
2396
1843
|
}
|
|
2397
1844
|
function isTipTapMark(value) {
|
|
2398
|
-
return isRecord$
|
|
1845
|
+
return isRecord$10(value) && hasOnlyKeys(value, markKeys) && typeof value.type === "string" && value.type.length > 0 && (value.attrs === void 0 || isRecord$10(value.attrs));
|
|
2399
1846
|
}
|
|
2400
1847
|
function isTipTapNode(value) {
|
|
2401
|
-
if (!isRecord$
|
|
1848
|
+
if (!isRecord$10(value) || !hasOnlyKeys(value, nodeKeys) || typeof value.type !== "string" || value.type.length === 0 || value.type === "doc" || value.attrs !== void 0 && !isRecord$10(value.attrs) || value.marks !== void 0 && (!Array.isArray(value.marks) || !isDenseArrayOf(value.marks, isTipTapMark)) || value.content !== void 0 && (!Array.isArray(value.content) || !isDenseArrayOf(value.content, isTipTapNode))) return false;
|
|
2402
1849
|
if (value.type === "text") return typeof value.text === "string" && value.text.length > 0 && value.content === void 0;
|
|
2403
1850
|
return value.text === void 0;
|
|
2404
1851
|
}
|
|
2405
1852
|
function isCanonicalRichTextDoc(value) {
|
|
2406
|
-
return isRecord$
|
|
1853
|
+
return isRecord$10(value) && hasOnlyKeys(value, rootKeys) && value.type === "doc" && Array.isArray(value.content) && isDenseArrayOf(value.content, isTipTapNode);
|
|
1854
|
+
}
|
|
1855
|
+
//#endregion
|
|
1856
|
+
//#region ../core/src/mailing-list-identifiers.ts
|
|
1857
|
+
const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu;
|
|
1858
|
+
const OPAQUE_ID_PATTERN = /^[A-Za-z0-9_-]{1,100}$/u;
|
|
1859
|
+
function parseTrimmedMatchingString(value, pattern) {
|
|
1860
|
+
if (typeof value !== "string") return null;
|
|
1861
|
+
const trimmed = value.trim();
|
|
1862
|
+
return pattern.test(trimmed) ? trimmed : null;
|
|
1863
|
+
}
|
|
1864
|
+
function parsePositiveInteger(value) {
|
|
1865
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value > 0 ? value : null;
|
|
1866
|
+
}
|
|
1867
|
+
function parseNewsletterListId(value) {
|
|
1868
|
+
return parseTrimmedMatchingString(value, UUID_PATTERN);
|
|
1869
|
+
}
|
|
1870
|
+
function parseMailchimpAudienceId(value) {
|
|
1871
|
+
return parseTrimmedMatchingString(value, OPAQUE_ID_PATTERN);
|
|
1872
|
+
}
|
|
1873
|
+
function parseMailchimpInterestId(value) {
|
|
1874
|
+
return parseTrimmedMatchingString(value, OPAQUE_ID_PATTERN);
|
|
1875
|
+
}
|
|
1876
|
+
function parseBrevoListId(value) {
|
|
1877
|
+
return parsePositiveInteger(value);
|
|
1878
|
+
}
|
|
1879
|
+
//#endregion
|
|
1880
|
+
//#region ../core/src/mailing-list-setup-parser.ts
|
|
1881
|
+
function parseMailingListGlobalForm(value) {
|
|
1882
|
+
if (!isRecord$9(value)) return formError("shape");
|
|
1883
|
+
const fields = parseGlobalFields(value.fields);
|
|
1884
|
+
if (fields === null) return formError("fields");
|
|
1885
|
+
if (typeof value.includeOptionalPhone !== "boolean") return formError("includeOptionalPhone");
|
|
1886
|
+
const buttonLabel = parseRequiredString(value.buttonLabel);
|
|
1887
|
+
if (buttonLabel === null) return formError("buttonLabel");
|
|
1888
|
+
const privacyNote = parseOptionalString(value.privacyNote);
|
|
1889
|
+
if (privacyNote === void 0) return formError("privacyNote");
|
|
1890
|
+
return ok({
|
|
1891
|
+
fields,
|
|
1892
|
+
includeOptionalPhone: value.includeOptionalPhone,
|
|
1893
|
+
buttonLabel,
|
|
1894
|
+
privacyNote
|
|
1895
|
+
});
|
|
1896
|
+
}
|
|
1897
|
+
function parseGlobalFields(value) {
|
|
1898
|
+
if (!isRecord$9(value) || typeof value.preset !== "string") return null;
|
|
1899
|
+
switch (value.preset) {
|
|
1900
|
+
case "emailOnly": return { preset: "emailOnly" };
|
|
1901
|
+
case "emailName": return isRequirement(value.name) ? {
|
|
1902
|
+
preset: "emailName",
|
|
1903
|
+
name: value.name
|
|
1904
|
+
} : null;
|
|
1905
|
+
case "emailFirstLast": return isRequirement(value.firstName) && isRequirement(value.lastName) ? {
|
|
1906
|
+
preset: "emailFirstLast",
|
|
1907
|
+
firstName: value.firstName,
|
|
1908
|
+
lastName: value.lastName
|
|
1909
|
+
} : null;
|
|
1910
|
+
case "emailNameCompany": return isRequirement(value.name) && isRequirement(value.company) ? {
|
|
1911
|
+
preset: "emailNameCompany",
|
|
1912
|
+
name: value.name,
|
|
1913
|
+
company: value.company
|
|
1914
|
+
} : null;
|
|
1915
|
+
default: return null;
|
|
1916
|
+
}
|
|
1917
|
+
}
|
|
1918
|
+
function parseMailingListSetupRevision(value) {
|
|
1919
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value > 0 ? value : null;
|
|
1920
|
+
}
|
|
1921
|
+
function parseRequiredString(value) {
|
|
1922
|
+
if (typeof value !== "string") return null;
|
|
1923
|
+
const trimmed = value.trim();
|
|
1924
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
1925
|
+
}
|
|
1926
|
+
function parseOptionalString(value) {
|
|
1927
|
+
if (value === null || value === void 0) return null;
|
|
1928
|
+
if (typeof value !== "string") return void 0;
|
|
1929
|
+
const trimmed = value.trim();
|
|
1930
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
1931
|
+
}
|
|
1932
|
+
function isRequirement(value) {
|
|
1933
|
+
return value === "required" || value === "optional";
|
|
1934
|
+
}
|
|
1935
|
+
function isRecord$9(value) {
|
|
1936
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1937
|
+
}
|
|
1938
|
+
function formError(field) {
|
|
1939
|
+
return err({
|
|
1940
|
+
tag: "invalid_mailing_list_global_form",
|
|
1941
|
+
field
|
|
1942
|
+
});
|
|
1943
|
+
}
|
|
1944
|
+
//#endregion
|
|
1945
|
+
//#region ../core/src/mailing-list-targeting.ts
|
|
1946
|
+
function planMailingListChoicePresentation(targeting) {
|
|
1947
|
+
if (targeting.mode === "default" || targeting.selection.tag === "fixed") return { tag: "hidden" };
|
|
1948
|
+
switch (targeting.provider) {
|
|
1949
|
+
case "native": return targeting.selection.offeredTopicIds.length === 1 ? {
|
|
1950
|
+
tag: "automatic",
|
|
1951
|
+
selection: {
|
|
1952
|
+
provider: "native",
|
|
1953
|
+
topicIds: targeting.selection.offeredTopicIds
|
|
1954
|
+
}
|
|
1955
|
+
} : {
|
|
1956
|
+
tag: "visitor_choice",
|
|
1957
|
+
provider: "native",
|
|
1958
|
+
optionCount: targeting.selection.offeredTopicIds.length
|
|
1959
|
+
};
|
|
1960
|
+
case "brevo": return targeting.selection.offeredListIds.length === 1 ? {
|
|
1961
|
+
tag: "automatic",
|
|
1962
|
+
selection: {
|
|
1963
|
+
provider: "brevo",
|
|
1964
|
+
listIds: targeting.selection.offeredListIds
|
|
1965
|
+
}
|
|
1966
|
+
} : {
|
|
1967
|
+
tag: "visitor_choice",
|
|
1968
|
+
provider: "brevo",
|
|
1969
|
+
optionCount: targeting.selection.offeredListIds.length
|
|
1970
|
+
};
|
|
1971
|
+
case "mailchimp": return targeting.selection.offeredInterestIds.length === 1 ? {
|
|
1972
|
+
tag: "automatic",
|
|
1973
|
+
selection: {
|
|
1974
|
+
provider: "mailchimp",
|
|
1975
|
+
interestIds: targeting.selection.offeredInterestIds
|
|
1976
|
+
}
|
|
1977
|
+
} : {
|
|
1978
|
+
tag: "visitor_choice",
|
|
1979
|
+
provider: "mailchimp",
|
|
1980
|
+
optionCount: targeting.selection.offeredInterestIds.length
|
|
1981
|
+
};
|
|
1982
|
+
}
|
|
1983
|
+
}
|
|
1984
|
+
//#endregion
|
|
1985
|
+
//#region ../core/src/mailing-list-runtime.ts
|
|
1986
|
+
function parseMailingListRuntimeContext(value) {
|
|
1987
|
+
if (!isRecord$8(value)) return invalidRuntimeContext();
|
|
1988
|
+
if (value.tag === "not_configured") return ok({ tag: "not_configured" });
|
|
1989
|
+
if (value.tag !== "configured") return invalidRuntimeContext();
|
|
1990
|
+
const revision = parseMailingListSetupRevision(value.revision);
|
|
1991
|
+
const form = parseMailingListGlobalForm(value.form);
|
|
1992
|
+
const provider = parseRuntimeProvider(value.provider);
|
|
1993
|
+
if (revision === null || !form.ok || provider === null) return invalidRuntimeContext();
|
|
1994
|
+
return ok({
|
|
1995
|
+
tag: "configured",
|
|
1996
|
+
revision,
|
|
1997
|
+
form: form.value,
|
|
1998
|
+
provider
|
|
1999
|
+
});
|
|
2000
|
+
}
|
|
2001
|
+
function parseRuntimeProvider(value) {
|
|
2002
|
+
if (!isRecord$8(value)) return null;
|
|
2003
|
+
switch (value.provider) {
|
|
2004
|
+
case "native": return parseNativeRuntimeProvider(value);
|
|
2005
|
+
case "brevo": return parseBrevoRuntimeProvider(value);
|
|
2006
|
+
case "mailchimp": return parseMailchimpRuntimeProvider(value);
|
|
2007
|
+
default: return null;
|
|
2008
|
+
}
|
|
2009
|
+
}
|
|
2010
|
+
function parseNativeRuntimeProvider(value) {
|
|
2011
|
+
const defaultTopicId = parseNewsletterListId(value.defaultTopicId);
|
|
2012
|
+
const topics = parseNamedItems(value.topics, parseNewsletterListId);
|
|
2013
|
+
return defaultTopicId !== null && topics !== null ? {
|
|
2014
|
+
provider: "native",
|
|
2015
|
+
defaultTopicId,
|
|
2016
|
+
topics
|
|
2017
|
+
} : null;
|
|
2018
|
+
}
|
|
2019
|
+
function parseBrevoRuntimeProvider(value) {
|
|
2020
|
+
const defaultListId = parseBrevoListId(value.defaultListId);
|
|
2021
|
+
const lists = parseNamedItems(value.lists, parseBrevoListId);
|
|
2022
|
+
return defaultListId !== null && lists !== null ? {
|
|
2023
|
+
provider: "brevo",
|
|
2024
|
+
defaultListId,
|
|
2025
|
+
lists
|
|
2026
|
+
} : null;
|
|
2027
|
+
}
|
|
2028
|
+
function parseMailchimpRuntimeProvider(value) {
|
|
2029
|
+
if (!Array.isArray(value.audiences)) return null;
|
|
2030
|
+
const defaultAudienceId = parseMailchimpAudienceId(value.defaultAudienceId);
|
|
2031
|
+
if (defaultAudienceId === null) return null;
|
|
2032
|
+
const audiences = [];
|
|
2033
|
+
for (const audience of value.audiences) {
|
|
2034
|
+
if (!isRecord$8(audience)) return null;
|
|
2035
|
+
const id = parseMailchimpAudienceId(audience.id);
|
|
2036
|
+
const name = parseName(audience.name);
|
|
2037
|
+
if (id === null || name === null || !Array.isArray(audience.interests)) return null;
|
|
2038
|
+
const interests = parseMailchimpInterests(audience.interests);
|
|
2039
|
+
if (interests === null) return null;
|
|
2040
|
+
audiences.push({
|
|
2041
|
+
id,
|
|
2042
|
+
name,
|
|
2043
|
+
interests
|
|
2044
|
+
});
|
|
2045
|
+
}
|
|
2046
|
+
return {
|
|
2047
|
+
provider: "mailchimp",
|
|
2048
|
+
defaultAudienceId,
|
|
2049
|
+
audiences
|
|
2050
|
+
};
|
|
2051
|
+
}
|
|
2052
|
+
function parseMailchimpInterests(value) {
|
|
2053
|
+
const interests = [];
|
|
2054
|
+
for (const interest of value) {
|
|
2055
|
+
if (!isRecord$8(interest)) return null;
|
|
2056
|
+
const id = parseMailchimpInterestId(interest.id);
|
|
2057
|
+
const name = parseName(interest.name);
|
|
2058
|
+
const categoryName = parseName(interest.categoryName);
|
|
2059
|
+
if (id === null || name === null || categoryName === null) return null;
|
|
2060
|
+
interests.push({
|
|
2061
|
+
id,
|
|
2062
|
+
name,
|
|
2063
|
+
categoryName
|
|
2064
|
+
});
|
|
2065
|
+
}
|
|
2066
|
+
return interests;
|
|
2067
|
+
}
|
|
2068
|
+
function parseNamedItems(value, parseId) {
|
|
2069
|
+
if (!Array.isArray(value)) return null;
|
|
2070
|
+
const items = [];
|
|
2071
|
+
for (const item of value) {
|
|
2072
|
+
if (!isRecord$8(item)) return null;
|
|
2073
|
+
const id = parseId(item.id);
|
|
2074
|
+
const name = parseName(item.name);
|
|
2075
|
+
if (id === null || name === null) return null;
|
|
2076
|
+
items.push({
|
|
2077
|
+
id,
|
|
2078
|
+
name
|
|
2079
|
+
});
|
|
2080
|
+
}
|
|
2081
|
+
return items;
|
|
2082
|
+
}
|
|
2083
|
+
function parseName(value) {
|
|
2084
|
+
if (typeof value !== "string") return null;
|
|
2085
|
+
const name = value.trim();
|
|
2086
|
+
return name.length > 0 ? name : null;
|
|
2087
|
+
}
|
|
2088
|
+
function isRecord$8(value) {
|
|
2089
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2090
|
+
}
|
|
2091
|
+
function invalidRuntimeContext() {
|
|
2092
|
+
return err({ tag: "invalid_mailing_list_runtime_context" });
|
|
2093
|
+
}
|
|
2094
|
+
//#endregion
|
|
2095
|
+
//#region ../core/src/mailing-list-targeting-parser.ts
|
|
2096
|
+
function parseMailingListPlacementTargeting(value) {
|
|
2097
|
+
if (!isRecord$7(value)) return targetingError("shape");
|
|
2098
|
+
if (value.mode === "default") return ok({ mode: "default" });
|
|
2099
|
+
if (value.mode !== "custom") return targetingError("mode");
|
|
2100
|
+
if (!isRecord$7(value.selection)) return targetingError("selection");
|
|
2101
|
+
switch (value.provider) {
|
|
2102
|
+
case "native": return parseNativeTargeting(value.selection);
|
|
2103
|
+
case "brevo": return parseBrevoTargeting(value.selection);
|
|
2104
|
+
case "mailchimp": return parseMailchimpTargeting(value, value.selection);
|
|
2105
|
+
default: return targetingError("provider");
|
|
2106
|
+
}
|
|
2107
|
+
}
|
|
2108
|
+
function parseNativeTargeting(selection) {
|
|
2109
|
+
if (selection.tag === "fixed") {
|
|
2110
|
+
const topicIds = parseNonEmptyUniqueIds(selection.topicIds, parseNewsletterListId);
|
|
2111
|
+
return topicIds.ok ? ok({
|
|
2112
|
+
mode: "custom",
|
|
2113
|
+
provider: "native",
|
|
2114
|
+
selection: {
|
|
2115
|
+
tag: "fixed",
|
|
2116
|
+
topicIds: topicIds.value
|
|
2117
|
+
}
|
|
2118
|
+
}) : topicIds;
|
|
2119
|
+
}
|
|
2120
|
+
if (selection.tag === "visitor_choice") {
|
|
2121
|
+
const offeredTopicIds = parseNonEmptyUniqueIds(selection.offeredTopicIds, parseNewsletterListId);
|
|
2122
|
+
return offeredTopicIds.ok ? ok({
|
|
2123
|
+
mode: "custom",
|
|
2124
|
+
provider: "native",
|
|
2125
|
+
selection: {
|
|
2126
|
+
tag: "visitor_choice",
|
|
2127
|
+
offeredTopicIds: offeredTopicIds.value
|
|
2128
|
+
}
|
|
2129
|
+
}) : offeredTopicIds;
|
|
2130
|
+
}
|
|
2131
|
+
return targetingError("selection");
|
|
2132
|
+
}
|
|
2133
|
+
function parseBrevoTargeting(selection) {
|
|
2134
|
+
if (selection.tag === "fixed") {
|
|
2135
|
+
const listIds = parseNonEmptyUniqueIds(selection.listIds, parseBrevoListId);
|
|
2136
|
+
return listIds.ok ? ok({
|
|
2137
|
+
mode: "custom",
|
|
2138
|
+
provider: "brevo",
|
|
2139
|
+
selection: {
|
|
2140
|
+
tag: "fixed",
|
|
2141
|
+
listIds: listIds.value
|
|
2142
|
+
}
|
|
2143
|
+
}) : listIds;
|
|
2144
|
+
}
|
|
2145
|
+
if (selection.tag === "visitor_choice") {
|
|
2146
|
+
const offeredListIds = parseNonEmptyUniqueIds(selection.offeredListIds, parseBrevoListId);
|
|
2147
|
+
return offeredListIds.ok ? ok({
|
|
2148
|
+
mode: "custom",
|
|
2149
|
+
provider: "brevo",
|
|
2150
|
+
selection: {
|
|
2151
|
+
tag: "visitor_choice",
|
|
2152
|
+
offeredListIds: offeredListIds.value
|
|
2153
|
+
}
|
|
2154
|
+
}) : offeredListIds;
|
|
2155
|
+
}
|
|
2156
|
+
return targetingError("selection");
|
|
2157
|
+
}
|
|
2158
|
+
function parseMailchimpTargeting(value, selection) {
|
|
2159
|
+
const audienceId = parseMailchimpAudienceId(value.audienceId);
|
|
2160
|
+
if (audienceId === null) return targetingError("audienceId");
|
|
2161
|
+
if (selection.tag === "fixed") {
|
|
2162
|
+
const interestIds = parseUniqueIds(selection.interestIds, parseMailchimpInterestId);
|
|
2163
|
+
return interestIds.ok ? ok({
|
|
2164
|
+
mode: "custom",
|
|
2165
|
+
provider: "mailchimp",
|
|
2166
|
+
audienceId,
|
|
2167
|
+
selection: {
|
|
2168
|
+
tag: "fixed",
|
|
2169
|
+
interestIds: interestIds.value
|
|
2170
|
+
}
|
|
2171
|
+
}) : interestIds;
|
|
2172
|
+
}
|
|
2173
|
+
if (selection.tag === "visitor_choice") {
|
|
2174
|
+
const offeredInterestIds = parseNonEmptyUniqueIds(selection.offeredInterestIds, parseMailchimpInterestId);
|
|
2175
|
+
return offeredInterestIds.ok ? ok({
|
|
2176
|
+
mode: "custom",
|
|
2177
|
+
provider: "mailchimp",
|
|
2178
|
+
audienceId,
|
|
2179
|
+
selection: {
|
|
2180
|
+
tag: "visitor_choice",
|
|
2181
|
+
offeredInterestIds: offeredInterestIds.value
|
|
2182
|
+
}
|
|
2183
|
+
}) : offeredInterestIds;
|
|
2184
|
+
}
|
|
2185
|
+
return targetingError("selection");
|
|
2186
|
+
}
|
|
2187
|
+
function parseNonEmptyUniqueIds(value, parseId) {
|
|
2188
|
+
const parsed = parseUniqueIds(value, parseId);
|
|
2189
|
+
if (!parsed.ok) return parsed;
|
|
2190
|
+
const [first, ...rest] = parsed.value;
|
|
2191
|
+
return first === void 0 ? targetingError("targets") : ok([first, ...rest]);
|
|
2192
|
+
}
|
|
2193
|
+
function parseUniqueIds(value, parseId) {
|
|
2194
|
+
if (!Array.isArray(value)) return targetingError("targets");
|
|
2195
|
+
const parsed = [];
|
|
2196
|
+
for (const item of value) {
|
|
2197
|
+
const id = parseId(item);
|
|
2198
|
+
if (id === null) return targetingError("targets");
|
|
2199
|
+
if (parsed.includes(id)) return targetingError("duplicate_target");
|
|
2200
|
+
parsed.push(id);
|
|
2201
|
+
}
|
|
2202
|
+
return ok(parsed);
|
|
2203
|
+
}
|
|
2204
|
+
function isRecord$7(value) {
|
|
2205
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2206
|
+
}
|
|
2207
|
+
function targetingError(field) {
|
|
2208
|
+
return err({
|
|
2209
|
+
tag: "invalid_mailing_list_targeting",
|
|
2210
|
+
field
|
|
2211
|
+
});
|
|
2407
2212
|
}
|
|
2408
2213
|
//#endregion
|
|
2409
|
-
//#region ../core/src/
|
|
2410
|
-
function
|
|
2411
|
-
|
|
2214
|
+
//#region ../core/src/mailing-list-submission.ts
|
|
2215
|
+
function parseMailingListBlockId(value) {
|
|
2216
|
+
const parsed = typeof value === "string" ? value.trim() : "";
|
|
2217
|
+
return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu.test(parsed) ? parsed : null;
|
|
2218
|
+
}
|
|
2219
|
+
function parseMailingListSignedSourceToken(value) {
|
|
2220
|
+
const parsed = typeof value === "string" ? value.trim() : "";
|
|
2221
|
+
return /^[A-Za-z0-9._~-]{16,1000}$/u.test(parsed) ? parsed : null;
|
|
2222
|
+
}
|
|
2223
|
+
function buildMailingListSignupBlockSourceRef(blockId) {
|
|
2224
|
+
const parsed = parseMailingListBlockId(blockId);
|
|
2225
|
+
return parsed !== null ? {
|
|
2226
|
+
tag: "block_ref",
|
|
2227
|
+
blockId: parsed
|
|
2228
|
+
} : null;
|
|
2412
2229
|
}
|
|
2413
2230
|
//#endregion
|
|
2414
2231
|
//#region ../core/src/secret.ts
|
|
@@ -2449,320 +2266,1111 @@ function createSecretInternal(kind, value) {
|
|
|
2449
2266
|
return Object.freeze(secret);
|
|
2450
2267
|
}
|
|
2451
2268
|
/**
|
|
2452
|
-
* Parse an untrusted management API key before constructing its Secret value.
|
|
2269
|
+
* Parse an untrusted management API key before constructing its Secret value.
|
|
2270
|
+
*
|
|
2271
|
+
* The Secret type protects an already validated value from accidental
|
|
2272
|
+
* disclosure; this boundary is what validates the value's wire format.
|
|
2273
|
+
*/
|
|
2274
|
+
function parseManagementKey(raw) {
|
|
2275
|
+
if (typeof raw !== "string" || !raw.startsWith("bld_mgmt_sk_") || raw.length === 12) return err({ kind: "invalid-management-key" });
|
|
2276
|
+
return ok(createSecretInternal("management-key", raw));
|
|
2277
|
+
}
|
|
2278
|
+
function sessionStartMs(session) {
|
|
2279
|
+
return Date.parse(session.startsAt);
|
|
2280
|
+
}
|
|
2281
|
+
/**
|
|
2282
|
+
* The run's sessions that still count, in schedule order.
|
|
2283
|
+
*
|
|
2284
|
+
* Sessions whose start cannot be read are dropped rather than sorted to an
|
|
2285
|
+
* arbitrary end: an unparseable date is not a date a visitor can attend.
|
|
2286
|
+
*/
|
|
2287
|
+
function orderedLiveRunSessions(sessions) {
|
|
2288
|
+
return sessions.filter((session) => session.status !== "cancelled" && Number.isFinite(sessionStartMs(session))).sort((left, right) => sessionStartMs(left) - sessionStartMs(right));
|
|
2289
|
+
}
|
|
2290
|
+
const PUBLIC_CONTENT_FRESHNESS_SECONDS = 3600;
|
|
2291
|
+
function availability(transport) {
|
|
2292
|
+
return {
|
|
2293
|
+
kind: "live",
|
|
2294
|
+
reason: "booking_correctness",
|
|
2295
|
+
freshness: "availability",
|
|
2296
|
+
transport
|
|
2297
|
+
};
|
|
2298
|
+
}
|
|
2299
|
+
function content(tags, transport = "direct") {
|
|
2300
|
+
return {
|
|
2301
|
+
kind: "tagged",
|
|
2302
|
+
tags,
|
|
2303
|
+
freshness: "content",
|
|
2304
|
+
transport
|
|
2305
|
+
};
|
|
2306
|
+
}
|
|
2307
|
+
/** The single classification authority for cacheable public reads. */
|
|
2308
|
+
const PUBLIC_READ_CACHE_POLICIES = {
|
|
2309
|
+
listPublishedEntries: content(["published_content"]),
|
|
2310
|
+
getPublishedEntryPreview: content(["published_content"]),
|
|
2311
|
+
listPublicEvents: availability("direct"),
|
|
2312
|
+
listPublicEventCalendarWindow: availability("direct"),
|
|
2313
|
+
listPublicRecurringSchedule: availability("batch_only"),
|
|
2314
|
+
getPublicEventDetails: availability("batch_only"),
|
|
2315
|
+
resolveEventSubroute: availability("direct"),
|
|
2316
|
+
listPublicRouteCandidates: content(["published_content"], "batch_only"),
|
|
2317
|
+
listPublicTeamMembers: content(["public_team_members"]),
|
|
2318
|
+
listPublicProducts: availability("direct"),
|
|
2319
|
+
listPublicPasses: availability("direct"),
|
|
2320
|
+
listPublicMemberships: availability("direct"),
|
|
2321
|
+
getPublicFormById: content(["site_forms"]),
|
|
2322
|
+
getPublicBookingServices: availability("direct"),
|
|
2323
|
+
getPublicBookingService: availability("direct"),
|
|
2324
|
+
getPublicBookingResourcesReference: availability("direct"),
|
|
2325
|
+
getPublicBookingAvailableDates: availability("direct"),
|
|
2326
|
+
getPublicBookingAvailableSlots: availability("direct"),
|
|
2327
|
+
getPublicWeeklySlotAvailability: availability("direct"),
|
|
2328
|
+
listPublicForms: content(["site_forms"]),
|
|
2329
|
+
checkRedirect: content([]),
|
|
2330
|
+
getPublicRoutableContent: content(["published_content"]),
|
|
2331
|
+
getPublicSitemapRoutes: content(["published_content"])
|
|
2332
|
+
};
|
|
2333
|
+
new Set(Object.keys(PUBLIC_READ_CACHE_POLICIES));
|
|
2334
|
+
function getPublicReadCachePolicy(endpoint) {
|
|
2335
|
+
return PUBLIC_READ_CACHE_POLICIES[endpoint];
|
|
2336
|
+
}
|
|
2337
|
+
function publicReadFreshnessSeconds(endpoint) {
|
|
2338
|
+
return getPublicReadCachePolicy(endpoint).freshness === "availability" ? 60 : PUBLIC_CONTENT_FRESHNESS_SECONDS;
|
|
2339
|
+
}
|
|
2340
|
+
//#endregion
|
|
2341
|
+
//#region ../core/src/event-series-behaviour.ts
|
|
2342
|
+
const WHOLE_SERIES_EVENT_PRESET_VALUES = ["course", "term"];
|
|
2343
|
+
const SURFACE_EVENT_PRESET_VALUES = [
|
|
2344
|
+
"class",
|
|
2345
|
+
"course",
|
|
2346
|
+
"term",
|
|
2347
|
+
"workshop",
|
|
2348
|
+
"retreat",
|
|
2349
|
+
"performance"
|
|
2350
|
+
];
|
|
2351
|
+
//#endregion
|
|
2352
|
+
//#region ../core/src/booking-vertical-preset.ts
|
|
2353
|
+
const BOOKING_ENGINE_BY_BEHAVIOUR = {
|
|
2354
|
+
class: "event_series",
|
|
2355
|
+
workshop: "event_series",
|
|
2356
|
+
course: "event_series",
|
|
2357
|
+
retreat: "event_series",
|
|
2358
|
+
performance: "event_series",
|
|
2359
|
+
appointment: "appointment_service"
|
|
2360
|
+
};
|
|
2361
|
+
function verticalBookingPreset(id, verticalId, canonicalBehaviour, label, pluralLabel, description, availability = "onboarding") {
|
|
2362
|
+
return {
|
|
2363
|
+
id,
|
|
2364
|
+
verticalId,
|
|
2365
|
+
canonicalBehaviour,
|
|
2366
|
+
engine: BOOKING_ENGINE_BY_BEHAVIOUR[canonicalBehaviour],
|
|
2367
|
+
availability,
|
|
2368
|
+
label,
|
|
2369
|
+
pluralLabel,
|
|
2370
|
+
description
|
|
2371
|
+
};
|
|
2372
|
+
}
|
|
2373
|
+
//#endregion
|
|
2374
|
+
//#region ../core/src/booking-vertical-definitions.ts
|
|
2375
|
+
const VERTICAL_DEFINITIONS = [
|
|
2376
|
+
{
|
|
2377
|
+
id: "yoga_wellness",
|
|
2378
|
+
label: "Yoga, meditation or mindfulness",
|
|
2379
|
+
description: "Yoga studios, wellness teachers, and movement practitioners."
|
|
2380
|
+
},
|
|
2381
|
+
{
|
|
2382
|
+
id: "fitness_pt",
|
|
2383
|
+
label: "Fitness and personal training",
|
|
2384
|
+
description: "Personal trainers, group training, and fitness programmes."
|
|
2385
|
+
},
|
|
2386
|
+
{
|
|
2387
|
+
id: "dance_school",
|
|
2388
|
+
label: "Dance school",
|
|
2389
|
+
description: "Dance classes, courses or terms, workshops, private lessons, and shows."
|
|
2390
|
+
},
|
|
2391
|
+
{
|
|
2392
|
+
id: "physiotherapy_physical_health",
|
|
2393
|
+
label: "Physiotherapy & physical health",
|
|
2394
|
+
description: "Physiotherapists, chiropractors, osteopaths, sports therapists, and rehabilitation practitioners."
|
|
2395
|
+
},
|
|
2396
|
+
{
|
|
2397
|
+
id: "massage_bodywork",
|
|
2398
|
+
label: "Massage & bodywork",
|
|
2399
|
+
description: "Massage therapists, bodyworkers, and somatic practitioners."
|
|
2400
|
+
},
|
|
2401
|
+
{
|
|
2402
|
+
id: "therapist_practitioner",
|
|
2403
|
+
label: "Therapist or practitioner",
|
|
2404
|
+
description: "Appointments, sessions, consultations, and occasional group work."
|
|
2405
|
+
},
|
|
2406
|
+
{
|
|
2407
|
+
id: "beauty_spa",
|
|
2408
|
+
label: "Beauty or spa",
|
|
2409
|
+
description: "Treatment-led businesses with optional workshops."
|
|
2410
|
+
},
|
|
2411
|
+
{
|
|
2412
|
+
id: "consultant_coach",
|
|
2413
|
+
label: "Consultant or coach",
|
|
2414
|
+
description: "One-to-one calls, workshops, courses, and retreats."
|
|
2415
|
+
},
|
|
2416
|
+
{
|
|
2417
|
+
id: "training_provider",
|
|
2418
|
+
label: "Training provider",
|
|
2419
|
+
description: "Courses, workshops, classes, appointments, and residential training."
|
|
2420
|
+
},
|
|
2421
|
+
{
|
|
2422
|
+
id: "retreat_centre",
|
|
2423
|
+
label: "Retreat centre",
|
|
2424
|
+
description: "Residential retreats, workshops, classes, courses, and private sessions."
|
|
2425
|
+
},
|
|
2426
|
+
{
|
|
2427
|
+
id: "music_school",
|
|
2428
|
+
label: "Music teacher or school",
|
|
2429
|
+
description: "Lessons, classes, terms, workshops, and performances."
|
|
2430
|
+
},
|
|
2431
|
+
{
|
|
2432
|
+
id: "voice_singing",
|
|
2433
|
+
label: "Voice & Singing",
|
|
2434
|
+
description: "Singing lessons, choirs, voice circles, workshops, and performances."
|
|
2435
|
+
},
|
|
2436
|
+
{
|
|
2437
|
+
id: "performing_arts_school",
|
|
2438
|
+
label: "Theatre or performing arts school",
|
|
2439
|
+
description: "Classes, terms, workshops, performances, and lessons."
|
|
2440
|
+
},
|
|
2441
|
+
{
|
|
2442
|
+
id: "community_wellbeing",
|
|
2443
|
+
label: "Community or wellbeing centre",
|
|
2444
|
+
description: "Groups, workshops, courses, appointments, and retreats."
|
|
2445
|
+
},
|
|
2446
|
+
{
|
|
2447
|
+
id: "venue_event_space",
|
|
2448
|
+
label: "Venue or event space",
|
|
2449
|
+
description: "Room, resource, or access bookings. Depends on the future capacity-booking domain."
|
|
2450
|
+
}
|
|
2451
|
+
];
|
|
2452
|
+
VERTICAL_DEFINITIONS.map(({ id }) => id);
|
|
2453
|
+
//#endregion
|
|
2454
|
+
//#region ../core/src/booking-vertical-catalog.ts
|
|
2455
|
+
const VERTICAL_BOOKING_PRESETS = [
|
|
2456
|
+
verticalBookingPreset("yoga_wellness.classes", "yoga_wellness", "class", "Class", "Classes", "Regular scheduled classes and group sessions."),
|
|
2457
|
+
verticalBookingPreset("yoga_wellness.workshops", "yoga_wellness", "workshop", "Workshop", "Workshops", "One-off workshops, day retreats, or special sessions."),
|
|
2458
|
+
verticalBookingPreset("yoga_wellness.courses", "yoga_wellness", "course", "Course", "Courses", "Fixed-schedule courses or multi-session groups."),
|
|
2459
|
+
verticalBookingPreset("yoga_wellness.retreats", "yoga_wellness", "retreat", "Retreat", "Retreats", "Multi-day or residential retreats and immersive experiences."),
|
|
2460
|
+
verticalBookingPreset("yoga_wellness.appointments", "yoga_wellness", "appointment", "Appointment", "Appointments", "Private sessions, consultations, or one-to-one support."),
|
|
2461
|
+
verticalBookingPreset("fitness_pt.group_training", "fitness_pt", "class", "Group training", "Group training", "Regular scheduled classes and group sessions."),
|
|
2462
|
+
verticalBookingPreset("fitness_pt.personal_training", "fitness_pt", "appointment", "Personal training", "Personal training", "One-to-one sessions booked from your availability."),
|
|
2463
|
+
verticalBookingPreset("fitness_pt.programmes", "fitness_pt", "course", "Programme", "Programmes", "Multi-session programmes like bootcamps or courses."),
|
|
2464
|
+
verticalBookingPreset("fitness_pt.workshops", "fitness_pt", "workshop", "Workshop", "Workshops", "One-off workshops, events, or special sessions."),
|
|
2465
|
+
verticalBookingPreset("fitness_pt.retreats", "fitness_pt", "retreat", "Retreat", "Retreats", "Multi-day or residential fitness experiences."),
|
|
2466
|
+
verticalBookingPreset("dance_school.classes", "dance_school", "class", "Class", "Classes", "Regular group classes and weekly sessions."),
|
|
2467
|
+
{
|
|
2468
|
+
...verticalBookingPreset("dance_school.terms", "dance_school", "course", "Term", "Terms", "Multi-week term blocks or fixed-date course groups."),
|
|
2469
|
+
eventPresetOverride: "term"
|
|
2470
|
+
},
|
|
2471
|
+
verticalBookingPreset("dance_school.courses", "dance_school", "course", "Course", "Courses", "Fixed-schedule courses or multi-session groups.", "settings"),
|
|
2472
|
+
verticalBookingPreset("dance_school.workshops", "dance_school", "workshop", "Workshop", "Workshops", "One-off workshops, masterclasses, or intensives."),
|
|
2473
|
+
verticalBookingPreset("dance_school.private_lessons", "dance_school", "appointment", "Private lesson", "Private lessons", "One-to-one lessons or coaching sessions."),
|
|
2474
|
+
verticalBookingPreset("dance_school.shows", "dance_school", "performance", "Show", "Shows", "Ticketed performances, showcases, and recitals."),
|
|
2475
|
+
verticalBookingPreset("physiotherapy_physical_health.appointments", "physiotherapy_physical_health", "appointment", "Appointment", "Appointments", "Assessments, treatments, follow-ups, and rehabilitation sessions."),
|
|
2476
|
+
verticalBookingPreset("physiotherapy_physical_health.rehab_classes", "physiotherapy_physical_health", "class", "Rehab class", "Rehab classes", "Regular rehabilitation, mobility, strength, or recovery classes."),
|
|
2477
|
+
verticalBookingPreset("physiotherapy_physical_health.workshops", "physiotherapy_physical_health", "workshop", "Workshop", "Workshops", "One-off workshops, talks, or practical group sessions."),
|
|
2478
|
+
verticalBookingPreset("massage_bodywork.treatments", "massage_bodywork", "appointment", "Treatment", "Treatments", "Massage treatments, bodywork sessions, and one-to-one appointments."),
|
|
2479
|
+
verticalBookingPreset("massage_bodywork.group_sessions", "massage_bodywork", "class", "Group session", "Group sessions", "Regular bodywork, somatic movement, or self-massage sessions."),
|
|
2480
|
+
verticalBookingPreset("massage_bodywork.workshops", "massage_bodywork", "workshop", "Workshop", "Workshops", "One-off bodywork, self-massage, or somatic practice workshops."),
|
|
2481
|
+
verticalBookingPreset("therapist_practitioner.appointments", "therapist_practitioner", "appointment", "Appointment", "Appointments", "Sessions, consultations, treatments, or assessments."),
|
|
2482
|
+
verticalBookingPreset("therapist_practitioner.workshops", "therapist_practitioner", "workshop", "Workshop", "Workshops", "One-off group workshops, talks, or wellbeing sessions."),
|
|
2483
|
+
verticalBookingPreset("therapist_practitioner.retreats", "therapist_practitioner", "retreat", "Retreat", "Retreats", "Multi-day retreats or immersive group experiences."),
|
|
2484
|
+
verticalBookingPreset("beauty_spa.appointments", "beauty_spa", "appointment", "Appointment", "Appointments", "Treatments, consultations, services, and sessions."),
|
|
2485
|
+
verticalBookingPreset("beauty_spa.workshops", "beauty_spa", "workshop", "Workshop", "Workshops", "Skincare workshops, makeup lessons, demos, or group events."),
|
|
2486
|
+
verticalBookingPreset("consultant_coach.appointments", "consultant_coach", "appointment", "Appointment", "Appointments", "One-to-one calls, consultations, reviews, or coaching sessions."),
|
|
2487
|
+
verticalBookingPreset("consultant_coach.workshops", "consultant_coach", "workshop", "Workshop", "Workshops", "One-off group sessions, webinars, or strategy days."),
|
|
2488
|
+
verticalBookingPreset("consultant_coach.courses", "consultant_coach", "course", "Course", "Courses", "Fixed-schedule cohorts or multi-session group programmes."),
|
|
2489
|
+
verticalBookingPreset("consultant_coach.retreats", "consultant_coach", "retreat", "Retreat", "Retreats", "Multi-day coaching retreats or immersive experiences."),
|
|
2490
|
+
verticalBookingPreset("training_provider.courses", "training_provider", "course", "Course", "Courses", "Fixed-schedule courses, cohorts, and multi-session training."),
|
|
2491
|
+
verticalBookingPreset("training_provider.workshops", "training_provider", "workshop", "Workshop", "Workshops", "One-off workshops, masterclasses, and short training sessions."),
|
|
2492
|
+
verticalBookingPreset("training_provider.appointments", "training_provider", "appointment", "Appointment", "Appointments", "Consultations, assessments, mentoring, or office hours."),
|
|
2493
|
+
verticalBookingPreset("training_provider.classes", "training_provider", "class", "Class", "Classes", "Regular classes, sessions, or groups.", "settings"),
|
|
2494
|
+
verticalBookingPreset("training_provider.residentials", "training_provider", "retreat", "Residential", "Residentials", "Residential courses or multi-day training experiences.", "settings"),
|
|
2495
|
+
verticalBookingPreset("retreat_centre.retreats", "retreat_centre", "retreat", "Retreat", "Retreats", "Multi-day or residential retreats with richer booking needs."),
|
|
2496
|
+
verticalBookingPreset("retreat_centre.workshops", "retreat_centre", "workshop", "Workshop", "Workshops", "One-day retreats, ceremonies, workshops, or special events."),
|
|
2497
|
+
verticalBookingPreset("retreat_centre.classes", "retreat_centre", "class", "Class", "Classes", "Regular sessions like guided meditations or group practices."),
|
|
2498
|
+
verticalBookingPreset("retreat_centre.courses", "retreat_centre", "course", "Course", "Courses", "Fixed-schedule programmes or multi-session experiences."),
|
|
2499
|
+
verticalBookingPreset("retreat_centre.appointments", "retreat_centre", "appointment", "Appointment", "Appointments", "Private sessions, therapies, consultations, or add-ons."),
|
|
2500
|
+
verticalBookingPreset("music_school.lessons", "music_school", "appointment", "Lesson", "Lessons", "One-to-one lessons, consultations, or coaching sessions."),
|
|
2501
|
+
verticalBookingPreset("music_school.classes", "music_school", "class", "Class", "Classes", "Regular group classes, ensembles, or recurring sessions."),
|
|
2502
|
+
{
|
|
2503
|
+
...verticalBookingPreset("music_school.terms", "music_school", "course", "Term", "Terms", "Multi-week term blocks or fixed-date group courses."),
|
|
2504
|
+
eventPresetOverride: "term"
|
|
2505
|
+
},
|
|
2506
|
+
verticalBookingPreset("music_school.workshops", "music_school", "workshop", "Workshop", "Workshops", "One-off workshops, masterclasses, or intensives."),
|
|
2507
|
+
verticalBookingPreset("music_school.performances", "music_school", "performance", "Performance", "Performances", "Concerts, recitals, showcases, or ticketed performances."),
|
|
2508
|
+
verticalBookingPreset("voice_singing.lessons", "voice_singing", "appointment", "Voice session", "Voice sessions", "One-to-one singing lessons, voice coaching, or private practice sessions."),
|
|
2509
|
+
verticalBookingPreset("voice_singing.classes", "voice_singing", "class", "Ongoing weekly session", "Ongoing weekly sessions", "Regular choirs, voice circles, community singing, or group practice."),
|
|
2510
|
+
{
|
|
2511
|
+
...verticalBookingPreset("voice_singing.terms", "voice_singing", "course", "Singing term", "Singing terms", "Multi-week choir terms, voice courses, or fixed-date group programmes."),
|
|
2512
|
+
eventPresetOverride: "term"
|
|
2513
|
+
},
|
|
2514
|
+
verticalBookingPreset("voice_singing.workshops", "voice_singing", "workshop", "Workshop", "Workshops", "One-off singing workshops, voice journeys, or devotional singing sessions."),
|
|
2515
|
+
verticalBookingPreset("voice_singing.performances", "voice_singing", "performance", "Performance", "Performances", "Choir concerts, sharing events, recitals, or community performances."),
|
|
2516
|
+
verticalBookingPreset("performing_arts_school.classes", "performing_arts_school", "class", "Class", "Classes", "Regular group classes, rehearsals, or weekly sessions."),
|
|
2517
|
+
{
|
|
2518
|
+
...verticalBookingPreset("performing_arts_school.terms", "performing_arts_school", "course", "Term", "Terms", "Multi-week term blocks or fixed-date course groups."),
|
|
2519
|
+
eventPresetOverride: "term"
|
|
2520
|
+
},
|
|
2521
|
+
verticalBookingPreset("performing_arts_school.workshops", "performing_arts_school", "workshop", "Workshop", "Workshops", "One-off workshops, masterclasses, or intensives."),
|
|
2522
|
+
verticalBookingPreset("performing_arts_school.performances", "performing_arts_school", "performance", "Performance", "Performances", "Shows, showcases, productions, or ticketed performances."),
|
|
2523
|
+
verticalBookingPreset("performing_arts_school.lessons", "performing_arts_school", "appointment", "Lesson", "Lessons", "One-to-one lessons, coaching, or audition prep."),
|
|
2524
|
+
verticalBookingPreset("community_wellbeing.classes", "community_wellbeing", "class", "Class", "Classes", "Regular groups, sessions, practices, or weekly activities."),
|
|
2525
|
+
verticalBookingPreset("community_wellbeing.workshops", "community_wellbeing", "workshop", "Workshop", "Workshops", "One-off workshops, talks, events, or gatherings."),
|
|
2526
|
+
verticalBookingPreset("community_wellbeing.courses", "community_wellbeing", "course", "Course", "Courses", "Fixed-schedule courses, study groups, or multi-session programmes."),
|
|
2527
|
+
verticalBookingPreset("community_wellbeing.appointments", "community_wellbeing", "appointment", "Appointment", "Appointments", "One-to-one appointments, consultations, or support sessions."),
|
|
2528
|
+
verticalBookingPreset("community_wellbeing.retreats", "community_wellbeing", "retreat", "Retreat", "Retreats", "Multi-day or residential retreats."),
|
|
2529
|
+
verticalBookingPreset("venue_event_space.resource_hire", "venue_event_space", "appointment", "Hire slot", "Hire slots", "Future room, venue, and resource hire bookings.", "future")
|
|
2530
|
+
];
|
|
2531
|
+
//#endregion
|
|
2532
|
+
//#region ../core/src/booking-vertical-config.ts
|
|
2533
|
+
const VERTICAL_ID_SET = new Set(VERTICAL_DEFINITIONS.map(({ id }) => id));
|
|
2534
|
+
const VERTICAL_PRESET_ID_SET = new Set(VERTICAL_BOOKING_PRESETS.map((presetDefinition) => presetDefinition.id));
|
|
2535
|
+
function parseVerticalId(value) {
|
|
2536
|
+
return typeof value === "string" && VERTICAL_ID_SET.has(value) ? value : null;
|
|
2537
|
+
}
|
|
2538
|
+
function parseVerticalPresetId(value) {
|
|
2539
|
+
return typeof value === "string" && VERTICAL_PRESET_ID_SET.has(value) ? value : null;
|
|
2540
|
+
}
|
|
2541
|
+
function getVerticalPresetDefinition(presetId) {
|
|
2542
|
+
const definition = VERTICAL_BOOKING_PRESETS.find((presetDefinition) => presetDefinition.id === presetId);
|
|
2543
|
+
if (definition === void 0) throw new Error(`Unhandled vertical preset id: ${presetId}`);
|
|
2544
|
+
return definition;
|
|
2545
|
+
}
|
|
2546
|
+
function createConfiguredSiteVerticalBookingConfig(verticalId, selectedPresetIds) {
|
|
2547
|
+
return {
|
|
2548
|
+
verticalId,
|
|
2549
|
+
selectedPresetIds
|
|
2550
|
+
};
|
|
2551
|
+
}
|
|
2552
|
+
function toNonEmptyVerticalPresetIds(presetIds) {
|
|
2553
|
+
const firstPresetId = presetIds[0];
|
|
2554
|
+
return firstPresetId ? [firstPresetId, ...presetIds.slice(1)] : null;
|
|
2555
|
+
}
|
|
2556
|
+
const DEFAULT_SITE_VERTICAL_BOOKING_CONFIG = {
|
|
2557
|
+
verticalId: null,
|
|
2558
|
+
selectedPresetIds: []
|
|
2559
|
+
};
|
|
2560
|
+
function appendUniqueIssue(issues, issue) {
|
|
2561
|
+
return issues.some((existing) => existing.code === issue.code) ? issues : [...issues, issue];
|
|
2562
|
+
}
|
|
2563
|
+
function collectRawConfigIssues(rawConfig, config) {
|
|
2564
|
+
const rawPresetValue = rawConfig.selectedPresetIds;
|
|
2565
|
+
const rawPresetIds = Array.isArray(rawPresetValue) ? rawPresetValue : [];
|
|
2566
|
+
let issues = [];
|
|
2567
|
+
if (rawConfig.verticalId != null && config.verticalId === null) issues = appendUniqueIssue(issues, {
|
|
2568
|
+
code: "unknown_vertical",
|
|
2569
|
+
rawValue: rawConfig.verticalId
|
|
2570
|
+
});
|
|
2571
|
+
if (config.verticalId === null && config.selectedPresetIds.length > 0) issues = appendUniqueIssue(issues, { code: "missing_vertical" });
|
|
2572
|
+
if (rawPresetValue !== void 0 && !Array.isArray(rawPresetValue) || rawPresetIds.some((presetId) => parseVerticalPresetId(presetId) === null)) issues = appendUniqueIssue(issues, {
|
|
2573
|
+
code: "unknown_preset",
|
|
2574
|
+
rawValue: rawPresetValue
|
|
2575
|
+
});
|
|
2576
|
+
if (rawConfig.verticalId != null && config.selectedPresetIds.length === 0) issues = appendUniqueIssue(issues, { code: "empty_selected_presets" });
|
|
2577
|
+
return issues;
|
|
2578
|
+
}
|
|
2579
|
+
function collectPresetConfigIssues(config) {
|
|
2580
|
+
const seenPresetIds = /* @__PURE__ */ new Set();
|
|
2581
|
+
const seenBehaviours = /* @__PURE__ */ new Set();
|
|
2582
|
+
let issues = [];
|
|
2583
|
+
for (const presetId of config.selectedPresetIds) {
|
|
2584
|
+
const presetDefinition = getVerticalPresetDefinition(presetId);
|
|
2585
|
+
if (seenPresetIds.has(presetId)) issues = appendUniqueIssue(issues, { code: "duplicate_preset_id" });
|
|
2586
|
+
seenPresetIds.add(presetId);
|
|
2587
|
+
if (config.verticalId !== null && presetDefinition.verticalId !== config.verticalId) issues = appendUniqueIssue(issues, { code: "preset_vertical_mismatch" });
|
|
2588
|
+
if (presetDefinition.availability === "future") issues = appendUniqueIssue(issues, { code: "future_preset_selected" });
|
|
2589
|
+
if (seenBehaviours.has(presetDefinition.canonicalBehaviour)) issues = appendUniqueIssue(issues, { code: "duplicate_canonical_behaviour" });
|
|
2590
|
+
seenBehaviours.add(presetDefinition.canonicalBehaviour);
|
|
2591
|
+
}
|
|
2592
|
+
return issues;
|
|
2593
|
+
}
|
|
2594
|
+
function getSiteVerticalConfigIssues(rawConfig, config) {
|
|
2595
|
+
let issues = collectRawConfigIssues(rawConfig, config);
|
|
2596
|
+
for (const issue of collectPresetConfigIssues(config)) issues = appendUniqueIssue(issues, issue);
|
|
2597
|
+
return issues;
|
|
2598
|
+
}
|
|
2599
|
+
function resolveSiteVerticalBookingConfig(rawConfig) {
|
|
2600
|
+
if (rawConfig == null) return {
|
|
2601
|
+
kind: "unconfigured",
|
|
2602
|
+
config: DEFAULT_SITE_VERTICAL_BOOKING_CONFIG
|
|
2603
|
+
};
|
|
2604
|
+
const verticalId = parseVerticalId(rawConfig.verticalId);
|
|
2605
|
+
const selectedPresetIds = (Array.isArray(rawConfig.selectedPresetIds) ? rawConfig.selectedPresetIds : []).map(parseVerticalPresetId).filter((presetId) => Boolean(presetId));
|
|
2606
|
+
const config = {
|
|
2607
|
+
verticalId,
|
|
2608
|
+
selectedPresetIds
|
|
2609
|
+
};
|
|
2610
|
+
if (rawConfig.verticalId == null && selectedPresetIds.length === 0) return {
|
|
2611
|
+
kind: "unconfigured",
|
|
2612
|
+
config: DEFAULT_SITE_VERTICAL_BOOKING_CONFIG
|
|
2613
|
+
};
|
|
2614
|
+
const issues = getSiteVerticalConfigIssues(rawConfig, config);
|
|
2615
|
+
if (issues.length > 0) return {
|
|
2616
|
+
kind: "invalid",
|
|
2617
|
+
config,
|
|
2618
|
+
issues
|
|
2619
|
+
};
|
|
2620
|
+
const nonEmptyPresetIds = toNonEmptyVerticalPresetIds(selectedPresetIds);
|
|
2621
|
+
const configuredConfig = verticalId !== null && nonEmptyPresetIds !== null ? createConfiguredSiteVerticalBookingConfig(verticalId, nonEmptyPresetIds) : null;
|
|
2622
|
+
if (configuredConfig === null) return {
|
|
2623
|
+
kind: "invalid",
|
|
2624
|
+
config,
|
|
2625
|
+
issues: [{ code: "empty_selected_presets" }]
|
|
2626
|
+
};
|
|
2627
|
+
return {
|
|
2628
|
+
kind: "configured",
|
|
2629
|
+
config: configuredConfig,
|
|
2630
|
+
selectedPresets: configuredConfig.selectedPresetIds.map(getVerticalPresetDefinition)
|
|
2631
|
+
};
|
|
2632
|
+
}
|
|
2633
|
+
//#endregion
|
|
2634
|
+
//#region ../api/src/publicEventEndpointDefinitions.ts
|
|
2635
|
+
const PUBLIC_EVENT_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
|
|
2636
|
+
listPublicEventCalendarWindow: {
|
|
2637
|
+
path: "/public/sites/{siteId}/events/calendar-window",
|
|
2638
|
+
method: "GET",
|
|
2639
|
+
revalidate: 0,
|
|
2640
|
+
auth: "public",
|
|
2641
|
+
responseKind: "json"
|
|
2642
|
+
},
|
|
2643
|
+
resolvePublicEventCheckoutReturn: {
|
|
2644
|
+
path: "/public/sites/{siteId}/events/checkout-return",
|
|
2645
|
+
method: "POST",
|
|
2646
|
+
tags: [TAG_TEMPLATES.publicEvents, "event-checkout"],
|
|
2647
|
+
auth: "public",
|
|
2648
|
+
responseKind: "json"
|
|
2649
|
+
},
|
|
2650
|
+
getPublicEventRegistrationOptions: {
|
|
2651
|
+
path: "/public/sites/{siteId}/events/registration-options",
|
|
2652
|
+
method: "POST",
|
|
2653
|
+
tags: [TAG_TEMPLATES.publicEvents, "event-registration-options"],
|
|
2654
|
+
auth: "public",
|
|
2655
|
+
responseKind: "json",
|
|
2656
|
+
errors: [
|
|
2657
|
+
"validation:invalid_input",
|
|
2658
|
+
"resource:not_found",
|
|
2659
|
+
"resource:conflict",
|
|
2660
|
+
"server:internal_error"
|
|
2661
|
+
]
|
|
2662
|
+
},
|
|
2663
|
+
resolveEventSubroute: {
|
|
2664
|
+
path: "/public/sites/{siteId}/events/subroutes/resolve",
|
|
2665
|
+
method: "GET",
|
|
2666
|
+
revalidate: publicReadFreshnessSeconds("resolveEventSubroute"),
|
|
2667
|
+
tags: [TAG_TEMPLATES.publicEvents, "event-subroute"],
|
|
2668
|
+
auth: "public",
|
|
2669
|
+
responseKind: "json",
|
|
2670
|
+
errors: []
|
|
2671
|
+
}
|
|
2672
|
+
});
|
|
2673
|
+
//#endregion
|
|
2674
|
+
//#region ../api/src/publicEventCheckoutEndpointDefinitions.ts
|
|
2675
|
+
/**
|
|
2676
|
+
* The public event registration/checkout endpoints, extracted from
|
|
2677
|
+
* `endpoints.ts`.
|
|
2678
|
+
*
|
|
2679
|
+
* They were moved out for the same reason the `sdkMedia*` block was: adding the
|
|
2680
|
+
* `errors` metadata `require-api-endpoint-errors` asks of a newly-added endpoint
|
|
2681
|
+
* pushed `endpoints.ts` past its `max-lines` baseline. The block is spread back
|
|
2682
|
+
* at the exact position it occupied, so `API_ENDPOINTS` key order is unchanged.
|
|
2683
|
+
* (The endpoint that originally motivated the move, `checkPublicEventEligibility`,
|
|
2684
|
+
* was since deleted on dev by #1326.)
|
|
2685
|
+
*/
|
|
2686
|
+
const PUBLIC_EVENT_CHECKOUT_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
|
|
2687
|
+
registerForEvent: {
|
|
2688
|
+
path: "/public/sites/{siteId}/events/register",
|
|
2689
|
+
method: "POST",
|
|
2690
|
+
tags: [TAG_TEMPLATES.publicEvents, "event-registration"],
|
|
2691
|
+
auth: "public",
|
|
2692
|
+
responseKind: "json"
|
|
2693
|
+
},
|
|
2694
|
+
createPublicEventCheckout: {
|
|
2695
|
+
path: "/public/sites/{siteId}/events/checkout",
|
|
2696
|
+
method: "POST",
|
|
2697
|
+
tags: [TAG_TEMPLATES.publicEvents, "event-checkout"],
|
|
2698
|
+
auth: "public",
|
|
2699
|
+
responseKind: "json"
|
|
2700
|
+
}
|
|
2701
|
+
});
|
|
2702
|
+
//#endregion
|
|
2703
|
+
//#region ../api/src/publicBookingAvailabilityEndpointDefinitions.ts
|
|
2704
|
+
/**
|
|
2705
|
+
* Public appointment reads: the service catalogue and the bookable slot grid.
|
|
2453
2706
|
*
|
|
2454
|
-
*
|
|
2455
|
-
*
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
if (typeof raw !== "string" || !raw.startsWith("bld_mgmt_sk_") || raw.length === 12) return err({ kind: "invalid-management-key" });
|
|
2459
|
-
return ok(createSecretInternal("management-key", raw));
|
|
2460
|
-
}
|
|
2461
|
-
function sessionStartMs(session) {
|
|
2462
|
-
return Date.parse(session.startsAt);
|
|
2463
|
-
}
|
|
2464
|
-
/**
|
|
2465
|
-
* The run's sessions that still count, in schedule order.
|
|
2707
|
+
* These are the reads that appointment writes invalidate. They carry canonical
|
|
2708
|
+
* `riverbank:*` tags because the frontend revalidate endpoint discards anything
|
|
2709
|
+
* else, which is why the legacy `site-{siteId}` tag they used to declare could
|
|
2710
|
+
* never actually be cleared (issue 1364).
|
|
2466
2711
|
*
|
|
2467
|
-
*
|
|
2468
|
-
*
|
|
2712
|
+
* Slot availability depends on both tags: the grid moves when a booking lands,
|
|
2713
|
+
* and again when the service definition behind it changes.
|
|
2469
2714
|
*/
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2715
|
+
const PUBLIC_BOOKING_AVAILABILITY_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
|
|
2716
|
+
getPublicBookingServices: {
|
|
2717
|
+
path: "/public/bookings/services",
|
|
2718
|
+
method: "GET",
|
|
2719
|
+
revalidate: publicReadFreshnessSeconds("getPublicBookingServices"),
|
|
2720
|
+
tags: [TAG_TEMPLATES.publicBookingServices],
|
|
2721
|
+
auth: "public",
|
|
2722
|
+
responseKind: "json"
|
|
2723
|
+
},
|
|
2724
|
+
getPublicBookingService: {
|
|
2725
|
+
path: "/public/bookings/services/{serviceId}",
|
|
2726
|
+
method: "GET",
|
|
2727
|
+
revalidate: publicReadFreshnessSeconds("getPublicBookingService"),
|
|
2728
|
+
tags: [TAG_TEMPLATES.publicBookingServices],
|
|
2729
|
+
auth: "public",
|
|
2730
|
+
responseKind: "json"
|
|
2731
|
+
},
|
|
2732
|
+
getPublicBookingResourcesReference: {
|
|
2733
|
+
path: "/public/bookings/resources/reference",
|
|
2734
|
+
method: "GET",
|
|
2735
|
+
revalidate: publicReadFreshnessSeconds("getPublicBookingResourcesReference"),
|
|
2736
|
+
tags: [TAG_TEMPLATES.publicBookingServices],
|
|
2737
|
+
auth: "public",
|
|
2738
|
+
responseKind: "json"
|
|
2739
|
+
},
|
|
2740
|
+
getPublicBookingAvailableDates: {
|
|
2741
|
+
path: "/public/bookings/availability/dates",
|
|
2742
|
+
method: "GET",
|
|
2743
|
+
revalidate: publicReadFreshnessSeconds("getPublicBookingAvailableDates"),
|
|
2744
|
+
tags: [TAG_TEMPLATES.publicBookingAvailability, TAG_TEMPLATES.publicBookingServices],
|
|
2745
|
+
auth: "public",
|
|
2746
|
+
responseKind: "json"
|
|
2747
|
+
},
|
|
2748
|
+
getPublicBookingAvailableSlots: {
|
|
2749
|
+
path: "/public/bookings/availability/slots",
|
|
2750
|
+
method: "GET",
|
|
2751
|
+
revalidate: publicReadFreshnessSeconds("getPublicBookingAvailableSlots"),
|
|
2752
|
+
tags: [TAG_TEMPLATES.publicBookingAvailability, TAG_TEMPLATES.publicBookingServices],
|
|
2753
|
+
auth: "public",
|
|
2754
|
+
responseKind: "json"
|
|
2755
|
+
},
|
|
2756
|
+
getPublicWeeklySlotAvailability: {
|
|
2757
|
+
path: "/public/bookings/weekly-slot-availability",
|
|
2758
|
+
method: "GET",
|
|
2759
|
+
revalidate: publicReadFreshnessSeconds("getPublicWeeklySlotAvailability"),
|
|
2760
|
+
tags: [TAG_TEMPLATES.publicBookingAvailability, TAG_TEMPLATES.publicBookingServices],
|
|
2761
|
+
auth: "public",
|
|
2762
|
+
responseKind: "json",
|
|
2763
|
+
errors: []
|
|
2764
|
+
}
|
|
2765
|
+
});
|
|
2473
2766
|
//#endregion
|
|
2474
|
-
//#region ../
|
|
2475
|
-
const
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2767
|
+
//#region ../api/src/siteApiKeyEndpointDefinitions.ts
|
|
2768
|
+
const SITE_API_KEY_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
|
|
2769
|
+
listSiteApiKeys: {
|
|
2770
|
+
path: "/sites/{siteId}/api-keys",
|
|
2771
|
+
method: "GET",
|
|
2772
|
+
auth: "user",
|
|
2773
|
+
tags: ["site-{siteId}", "api-keys"],
|
|
2774
|
+
responseKind: "json"
|
|
2775
|
+
},
|
|
2776
|
+
createSiteApiKey: {
|
|
2777
|
+
path: "/sites/{siteId}/api-keys",
|
|
2778
|
+
method: "POST",
|
|
2779
|
+
auth: "user",
|
|
2780
|
+
tags: ["site-{siteId}", "api-keys"],
|
|
2781
|
+
responseKind: "json"
|
|
2782
|
+
},
|
|
2783
|
+
revokeSiteApiKey: {
|
|
2784
|
+
path: "/sites/{siteId}/api-keys/{keyId}",
|
|
2785
|
+
method: "DELETE",
|
|
2786
|
+
auth: "user",
|
|
2787
|
+
tags: ["site-{siteId}", "api-keys"],
|
|
2788
|
+
responseKind: "json"
|
|
2789
|
+
},
|
|
2790
|
+
listSitePreviewKeys: {
|
|
2791
|
+
path: "/sites/{siteId}/api-keys/preview",
|
|
2792
|
+
method: "GET",
|
|
2793
|
+
auth: "user",
|
|
2794
|
+
tags: [
|
|
2795
|
+
"site-{siteId}",
|
|
2796
|
+
"api-keys",
|
|
2797
|
+
"preview-key"
|
|
2798
|
+
],
|
|
2799
|
+
errors: [],
|
|
2800
|
+
responseKind: "json"
|
|
2801
|
+
},
|
|
2802
|
+
createSitePreviewKey: {
|
|
2803
|
+
path: "/sites/{siteId}/api-keys/preview",
|
|
2804
|
+
method: "POST",
|
|
2805
|
+
auth: "user",
|
|
2806
|
+
tags: [
|
|
2807
|
+
"site-{siteId}",
|
|
2808
|
+
"api-keys",
|
|
2809
|
+
"preview-key"
|
|
2810
|
+
],
|
|
2811
|
+
responseKind: "json"
|
|
2812
|
+
},
|
|
2813
|
+
getSiteApiKeyAccessLogs: {
|
|
2814
|
+
path: "/sites/{siteId}/api-keys/access-logs",
|
|
2815
|
+
method: "GET",
|
|
2816
|
+
auth: "user",
|
|
2817
|
+
tags: [
|
|
2818
|
+
"site-{siteId}",
|
|
2819
|
+
"api-keys",
|
|
2820
|
+
"access-logs"
|
|
2821
|
+
],
|
|
2822
|
+
responseKind: "json"
|
|
2823
|
+
},
|
|
2824
|
+
listManagementKeys: {
|
|
2825
|
+
path: "/sites/{siteId}/api-keys/management",
|
|
2826
|
+
method: "GET",
|
|
2827
|
+
auth: "user",
|
|
2828
|
+
tags: [
|
|
2829
|
+
"site-{siteId}",
|
|
2830
|
+
"api-keys",
|
|
2831
|
+
"management-keys"
|
|
2832
|
+
],
|
|
2833
|
+
responseKind: "json"
|
|
2834
|
+
},
|
|
2835
|
+
createManagementKey: {
|
|
2836
|
+
path: "/sites/{siteId}/api-keys/management",
|
|
2837
|
+
method: "POST",
|
|
2838
|
+
auth: "user",
|
|
2839
|
+
tags: [
|
|
2840
|
+
"site-{siteId}",
|
|
2841
|
+
"api-keys",
|
|
2842
|
+
"management-keys"
|
|
2843
|
+
],
|
|
2844
|
+
responseKind: "json"
|
|
2845
|
+
},
|
|
2846
|
+
revokeManagementKey: {
|
|
2847
|
+
path: "/sites/{siteId}/api-keys/management",
|
|
2848
|
+
method: "DELETE",
|
|
2849
|
+
auth: "user",
|
|
2850
|
+
tags: [
|
|
2851
|
+
"site-{siteId}",
|
|
2852
|
+
"api-keys",
|
|
2853
|
+
"management-keys"
|
|
2854
|
+
],
|
|
2855
|
+
responseKind: "json"
|
|
2856
|
+
}
|
|
2857
|
+
});
|
|
2484
2858
|
//#endregion
|
|
2485
|
-
//#region ../
|
|
2486
|
-
const
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2859
|
+
//#region ../api/src/eventManagementEndpointDefinitions.ts
|
|
2860
|
+
const EVENT_MANAGEMENT_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
|
|
2861
|
+
listEvents: {
|
|
2862
|
+
path: "/sites/{siteId}/bookings/events",
|
|
2863
|
+
method: "GET",
|
|
2864
|
+
tags: ["site-{siteId}", "event-series-{siteId}"],
|
|
2865
|
+
auth: "user",
|
|
2866
|
+
responseKind: "json",
|
|
2867
|
+
errors: []
|
|
2868
|
+
},
|
|
2869
|
+
createEvent: {
|
|
2870
|
+
path: "/sites/{siteId}/bookings/events",
|
|
2871
|
+
method: "POST",
|
|
2872
|
+
tags: ["site-{siteId}", "event-series-{siteId}"],
|
|
2873
|
+
auth: "user",
|
|
2874
|
+
responseKind: "json",
|
|
2875
|
+
errors: [
|
|
2876
|
+
"validation:invalid_input",
|
|
2877
|
+
"resource:already_exists",
|
|
2878
|
+
"server:internal_error"
|
|
2879
|
+
]
|
|
2880
|
+
},
|
|
2881
|
+
transitionEventLifecycle: {
|
|
2882
|
+
path: "/sites/{siteId}/bookings/events/{eventId}/lifecycle",
|
|
2883
|
+
method: "POST",
|
|
2884
|
+
tags: ["site-{siteId}", "event-series-{siteId}"],
|
|
2885
|
+
auth: "user",
|
|
2886
|
+
responseKind: "json",
|
|
2887
|
+
errors: [
|
|
2888
|
+
"validation:invalid_input",
|
|
2889
|
+
"resource:not_found",
|
|
2890
|
+
"resource:conflict",
|
|
2891
|
+
"server:internal_error"
|
|
2892
|
+
]
|
|
2893
|
+
},
|
|
2894
|
+
updateEventIdentity: {
|
|
2895
|
+
path: "/sites/{siteId}/bookings/events/{eventId}",
|
|
2896
|
+
method: "PATCH",
|
|
2897
|
+
tags: ["site-{siteId}", "event-series-{siteId}"],
|
|
2898
|
+
auth: "user",
|
|
2899
|
+
responseKind: "json",
|
|
2900
|
+
errors: [
|
|
2901
|
+
"validation:invalid_input",
|
|
2902
|
+
"resource:not_found",
|
|
2903
|
+
"server:internal_error"
|
|
2904
|
+
]
|
|
2905
|
+
},
|
|
2906
|
+
createWholeSeriesRun: {
|
|
2907
|
+
path: "/sites/{siteId}/bookings/events/{eventId}/runs",
|
|
2908
|
+
method: "POST",
|
|
2909
|
+
tags: ["site-{siteId}", "event-series-{siteId}"],
|
|
2910
|
+
auth: "user",
|
|
2911
|
+
responseKind: "json",
|
|
2912
|
+
errors: [
|
|
2913
|
+
"validation:invalid_input",
|
|
2914
|
+
"resource:not_found",
|
|
2915
|
+
"resource:already_exists",
|
|
2916
|
+
"server:internal_error"
|
|
2917
|
+
]
|
|
2918
|
+
},
|
|
2919
|
+
updateWholeSeriesRun: {
|
|
2920
|
+
path: "/sites/{siteId}/bookings/events/{eventId}/runs/{runId}",
|
|
2921
|
+
method: "PATCH",
|
|
2922
|
+
tags: ["site-{siteId}", "event-series-{siteId}"],
|
|
2923
|
+
auth: "user",
|
|
2924
|
+
responseKind: "json",
|
|
2925
|
+
errors: [
|
|
2926
|
+
"validation:invalid_input",
|
|
2927
|
+
"resource:not_found",
|
|
2928
|
+
"resource:conflict",
|
|
2929
|
+
"server:internal_error"
|
|
2930
|
+
]
|
|
2931
|
+
},
|
|
2932
|
+
cancelWholeSeriesRun: {
|
|
2933
|
+
path: "/sites/{siteId}/bookings/events/{eventId}/runs/{runId}/cancellation",
|
|
2934
|
+
method: "POST",
|
|
2935
|
+
tags: ["site-{siteId}", "event-series-{siteId}"],
|
|
2936
|
+
auth: "user",
|
|
2937
|
+
responseKind: "json",
|
|
2938
|
+
errors: [
|
|
2939
|
+
"validation:invalid_input",
|
|
2940
|
+
"resource:not_found",
|
|
2941
|
+
"resource:conflict",
|
|
2942
|
+
"server:internal_error"
|
|
2943
|
+
]
|
|
2944
|
+
}
|
|
2945
|
+
});
|
|
2506
2946
|
//#endregion
|
|
2507
|
-
//#region ../
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2947
|
+
//#region ../api/src/giftingEndpointDefinitions.ts
|
|
2948
|
+
/**
|
|
2949
|
+
* Gifting endpoints (gift cards & vouchers) — the dashboard surface that manages
|
|
2950
|
+
* offers, gifts and settings, plus the public buy/claim surface.
|
|
2951
|
+
*/
|
|
2952
|
+
const GIFTING_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
|
|
2953
|
+
createGiftingOffer: {
|
|
2954
|
+
path: "/sites/{siteId}/gifting/offers",
|
|
2955
|
+
method: "POST",
|
|
2956
|
+
tags: ["site-{siteId}", "gifting-offers-{siteId}"],
|
|
2957
|
+
auth: "user",
|
|
2958
|
+
responseKind: "json",
|
|
2959
|
+
errors: [
|
|
2960
|
+
"validation:invalid_input",
|
|
2961
|
+
"auth:forbidden",
|
|
2962
|
+
"server:internal_error"
|
|
2963
|
+
]
|
|
2513
2964
|
},
|
|
2514
|
-
{
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2965
|
+
updateGiftingOffer: {
|
|
2966
|
+
path: "/sites/{siteId}/gifting/offers/{offerId}",
|
|
2967
|
+
method: "PATCH",
|
|
2968
|
+
tags: ["site-{siteId}", "gifting-offers-{siteId}"],
|
|
2969
|
+
auth: "user",
|
|
2970
|
+
responseKind: "json",
|
|
2971
|
+
errors: [
|
|
2972
|
+
"validation:invalid_input",
|
|
2973
|
+
"auth:forbidden",
|
|
2974
|
+
"resource:not_found",
|
|
2975
|
+
"resource:conflict",
|
|
2976
|
+
"server:internal_error"
|
|
2977
|
+
]
|
|
2518
2978
|
},
|
|
2519
|
-
{
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2979
|
+
deleteGiftingOffer: {
|
|
2980
|
+
path: "/sites/{siteId}/gifting/offers/{offerId}",
|
|
2981
|
+
method: "DELETE",
|
|
2982
|
+
tags: ["site-{siteId}", "gifting-offers-{siteId}"],
|
|
2983
|
+
auth: "user",
|
|
2984
|
+
responseKind: "json",
|
|
2985
|
+
errors: [
|
|
2986
|
+
"auth:forbidden",
|
|
2987
|
+
"resource:not_found",
|
|
2988
|
+
"resource:conflict",
|
|
2989
|
+
"server:internal_error"
|
|
2990
|
+
]
|
|
2523
2991
|
},
|
|
2524
|
-
{
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2992
|
+
duplicateGiftingOffer: {
|
|
2993
|
+
path: "/sites/{siteId}/gifting/offers/{offerId}/duplicate",
|
|
2994
|
+
method: "POST",
|
|
2995
|
+
tags: ["site-{siteId}", "gifting-offers-{siteId}"],
|
|
2996
|
+
auth: "user",
|
|
2997
|
+
responseKind: "json",
|
|
2998
|
+
errors: [
|
|
2999
|
+
"auth:forbidden",
|
|
3000
|
+
"resource:not_found",
|
|
3001
|
+
"server:internal_error"
|
|
3002
|
+
]
|
|
2528
3003
|
},
|
|
2529
|
-
{
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
3004
|
+
reorderGiftingOffers: {
|
|
3005
|
+
path: "/sites/{siteId}/gifting/offers/order",
|
|
3006
|
+
method: "PUT",
|
|
3007
|
+
tags: ["site-{siteId}", "gifting-offers-{siteId}"],
|
|
3008
|
+
auth: "user",
|
|
3009
|
+
responseKind: "json",
|
|
3010
|
+
errors: [
|
|
3011
|
+
"validation:invalid_input",
|
|
3012
|
+
"auth:forbidden",
|
|
3013
|
+
"resource:not_found",
|
|
3014
|
+
"server:internal_error"
|
|
3015
|
+
]
|
|
2533
3016
|
},
|
|
2534
|
-
{
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
3017
|
+
sendGift: {
|
|
3018
|
+
path: "/sites/{siteId}/gifting/gifts",
|
|
3019
|
+
method: "POST",
|
|
3020
|
+
tags: ["site-{siteId}", "gifting-gifts-{siteId}"],
|
|
3021
|
+
auth: "user",
|
|
3022
|
+
demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN,
|
|
3023
|
+
responseKind: "json",
|
|
3024
|
+
errors: [
|
|
3025
|
+
"validation:invalid_input",
|
|
3026
|
+
"auth:forbidden",
|
|
3027
|
+
"resource:not_found",
|
|
3028
|
+
"server:internal_error"
|
|
3029
|
+
]
|
|
2538
3030
|
},
|
|
2539
|
-
{
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
3031
|
+
resendGift: {
|
|
3032
|
+
path: "/sites/{siteId}/gifting/gifts/{giftId}/resend",
|
|
3033
|
+
method: "POST",
|
|
3034
|
+
tags: ["site-{siteId}", "gifting-gifts-{siteId}"],
|
|
3035
|
+
auth: "user",
|
|
3036
|
+
demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN,
|
|
3037
|
+
responseKind: "json",
|
|
3038
|
+
errors: [
|
|
3039
|
+
"auth:forbidden",
|
|
3040
|
+
"resource:not_found",
|
|
3041
|
+
"resource:conflict",
|
|
3042
|
+
"server:internal_error"
|
|
3043
|
+
]
|
|
2543
3044
|
},
|
|
2544
|
-
{
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
3045
|
+
correctGiftEmailAndResend: {
|
|
3046
|
+
path: "/sites/{siteId}/gifting/gifts/{giftId}/correct-email-and-resend",
|
|
3047
|
+
method: "POST",
|
|
3048
|
+
tags: ["site-{siteId}", "gifting-gifts-{siteId}"],
|
|
3049
|
+
auth: "user",
|
|
3050
|
+
demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN,
|
|
3051
|
+
responseKind: "json",
|
|
3052
|
+
errors: [
|
|
3053
|
+
"validation:invalid_input",
|
|
3054
|
+
"auth:forbidden",
|
|
3055
|
+
"resource:not_found",
|
|
3056
|
+
"resource:conflict",
|
|
3057
|
+
"server:internal_error"
|
|
3058
|
+
]
|
|
2548
3059
|
},
|
|
2549
|
-
{
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
3060
|
+
updateGiftingSettings: {
|
|
3061
|
+
path: "/sites/{siteId}/gifting/settings",
|
|
3062
|
+
method: "PATCH",
|
|
3063
|
+
tags: [
|
|
3064
|
+
"site-{siteId}",
|
|
3065
|
+
"gifting-offers-{siteId}",
|
|
3066
|
+
"gifting-gifts-{siteId}"
|
|
3067
|
+
],
|
|
3068
|
+
auth: "user",
|
|
3069
|
+
responseKind: "json",
|
|
3070
|
+
errors: [
|
|
3071
|
+
"validation:invalid_input",
|
|
3072
|
+
"auth:forbidden",
|
|
3073
|
+
"server:internal_error"
|
|
3074
|
+
]
|
|
3075
|
+
},
|
|
3076
|
+
listPublicGiftingOffers: {
|
|
3077
|
+
path: "/public/sites/{siteId}/gifting/offers",
|
|
3078
|
+
method: "GET",
|
|
3079
|
+
revalidate: 300,
|
|
3080
|
+
tags: [TAG_TEMPLATES.publicGifting],
|
|
3081
|
+
errors: [],
|
|
3082
|
+
auth: "public",
|
|
3083
|
+
responseKind: "json"
|
|
3084
|
+
},
|
|
3085
|
+
createPublicGiftingCheckout: {
|
|
3086
|
+
path: "/public/sites/{siteId}/gifting/checkout",
|
|
3087
|
+
method: "POST",
|
|
3088
|
+
tags: [TAG_TEMPLATES.publicGifting],
|
|
3089
|
+
errors: [],
|
|
3090
|
+
auth: "public",
|
|
3091
|
+
responseKind: "json"
|
|
3092
|
+
},
|
|
3093
|
+
claimGiftCardPublic: {
|
|
3094
|
+
path: "/public/sites/{siteId}/gifting/claim",
|
|
3095
|
+
method: "POST",
|
|
3096
|
+
tags: [TAG_TEMPLATES.publicGifting],
|
|
3097
|
+
errors: [],
|
|
3098
|
+
auth: "public",
|
|
3099
|
+
responseKind: "json"
|
|
3100
|
+
}
|
|
3101
|
+
});
|
|
3102
|
+
//#endregion
|
|
3103
|
+
//#region ../api/src/sdkEndpointDefinitions.ts
|
|
3104
|
+
/** SDK management endpoints that do not belong to a CRUD resource family. */
|
|
3105
|
+
const SDK_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
|
|
3106
|
+
sdkUpdateSettings: {
|
|
3107
|
+
path: "/sdk/{siteId}/settings",
|
|
3108
|
+
method: "PATCH",
|
|
3109
|
+
auth: "service",
|
|
3110
|
+
responseKind: "json",
|
|
3111
|
+
errors: ["validation:invalid_input", "server:internal_error"]
|
|
3112
|
+
},
|
|
3113
|
+
sdkConfigureBookingVertical: {
|
|
3114
|
+
path: "/sdk/{siteId}/settings/booking/vertical",
|
|
3115
|
+
method: "POST",
|
|
3116
|
+
auth: "service",
|
|
3117
|
+
responseKind: "json"
|
|
3118
|
+
},
|
|
3119
|
+
sdkSetupRevalidationWebhook: {
|
|
3120
|
+
path: "/sdk/{siteId}/webhooks/revalidation/setup",
|
|
3121
|
+
method: "POST",
|
|
3122
|
+
auth: "service",
|
|
3123
|
+
responseKind: "json",
|
|
3124
|
+
errors: ["validation:invalid_input", "server:internal_error"]
|
|
3125
|
+
}
|
|
3126
|
+
});
|
|
3127
|
+
//#endregion
|
|
3128
|
+
//#region ../api/src/sdkMediaEndpointDefinitions.ts
|
|
3129
|
+
/** SDK media lookup, listing, deletion and upload endpoints (management-key authenticated). */
|
|
3130
|
+
const SDK_MEDIA_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
|
|
3131
|
+
sdkMediaExists: {
|
|
3132
|
+
path: "/sdk/{siteId}/media/exists",
|
|
3133
|
+
method: "POST",
|
|
3134
|
+
errors: ["validation:invalid_input"],
|
|
3135
|
+
auth: "service",
|
|
3136
|
+
responseKind: "json"
|
|
3137
|
+
},
|
|
3138
|
+
sdkMediaFindByChecksum: {
|
|
3139
|
+
path: "/sdk/{siteId}/media/find-by-checksum",
|
|
3140
|
+
method: "POST",
|
|
3141
|
+
errors: ["server:internal_error"],
|
|
3142
|
+
auth: "service",
|
|
3143
|
+
responseKind: "json"
|
|
2553
3144
|
},
|
|
2554
|
-
{
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
3145
|
+
sdkMediaResolve: {
|
|
3146
|
+
path: "/sdk/{siteId}/media/resolve",
|
|
3147
|
+
method: "POST",
|
|
3148
|
+
errors: ["server:internal_error"],
|
|
3149
|
+
auth: "service",
|
|
3150
|
+
responseKind: "json"
|
|
2558
3151
|
},
|
|
2559
|
-
{
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
3152
|
+
sdkMediaList: {
|
|
3153
|
+
path: "/sdk/{siteId}/media",
|
|
3154
|
+
method: "GET",
|
|
3155
|
+
auth: "service",
|
|
3156
|
+
errors: [],
|
|
3157
|
+
responseKind: "json"
|
|
2563
3158
|
},
|
|
2564
|
-
{
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
3159
|
+
sdkMediaDownload: {
|
|
3160
|
+
path: "/sdk/{siteId}/media/{identifier}/download",
|
|
3161
|
+
method: "GET",
|
|
3162
|
+
auth: "service",
|
|
3163
|
+
errors: [],
|
|
3164
|
+
responseKind: "json"
|
|
2568
3165
|
},
|
|
2569
|
-
{
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
3166
|
+
sdkMediaDeletePreview: {
|
|
3167
|
+
path: "/sdk/{siteId}/media/{identifier}/delete-preview",
|
|
3168
|
+
method: "POST",
|
|
3169
|
+
auth: "service",
|
|
3170
|
+
errors: [],
|
|
3171
|
+
responseKind: "json"
|
|
2573
3172
|
},
|
|
2574
|
-
{
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
3173
|
+
sdkMediaDeleteApply: {
|
|
3174
|
+
path: "/sdk/{siteId}/media/{identifier}",
|
|
3175
|
+
method: "DELETE",
|
|
3176
|
+
auth: "service",
|
|
3177
|
+
errors: [],
|
|
3178
|
+
responseKind: "json"
|
|
2578
3179
|
},
|
|
2579
|
-
{
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
3180
|
+
sdkMediaUploadUrl: {
|
|
3181
|
+
path: "/sdk/{siteId}/media/upload-url",
|
|
3182
|
+
method: "POST",
|
|
3183
|
+
errors: [
|
|
3184
|
+
"resource:not_found",
|
|
3185
|
+
"validation:invalid_input",
|
|
3186
|
+
"resource:conflict",
|
|
3187
|
+
"validation:payload_too_large",
|
|
3188
|
+
"billing:plan_limit_exceeded",
|
|
3189
|
+
"server:internal_error"
|
|
3190
|
+
],
|
|
3191
|
+
auth: "service",
|
|
3192
|
+
responseKind: "json"
|
|
3193
|
+
},
|
|
3194
|
+
sdkMediaUploadFinalize: {
|
|
3195
|
+
path: "/sdk/{siteId}/media/upload",
|
|
3196
|
+
method: "POST",
|
|
3197
|
+
errors: [
|
|
3198
|
+
"resource:not_found",
|
|
3199
|
+
"validation:invalid_input",
|
|
3200
|
+
"resource:conflict",
|
|
3201
|
+
"validation:payload_too_large",
|
|
3202
|
+
"billing:plan_limit_exceeded",
|
|
3203
|
+
"server:internal_error"
|
|
3204
|
+
],
|
|
3205
|
+
auth: "service",
|
|
3206
|
+
responseKind: "json"
|
|
2583
3207
|
}
|
|
2584
|
-
|
|
2585
|
-
VERTICAL_DEFINITIONS.map(({ id }) => id);
|
|
3208
|
+
});
|
|
2586
3209
|
//#endregion
|
|
2587
|
-
//#region ../
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
...verticalBookingPreset("dance_school.terms", "dance_school", "course", "Term", "Terms", "Multi-week term blocks or fixed-date course groups."),
|
|
2602
|
-
eventPresetOverride: "term"
|
|
3210
|
+
//#region ../api/src/publicReadEndpointDefinitions.ts
|
|
3211
|
+
/**
|
|
3212
|
+
* Direct public reads governed by the canonical public-read freshness policy.
|
|
3213
|
+
* Keeping these definitions together makes the endpoint identity used to
|
|
3214
|
+
* derive freshness reviewable beside its route and tags.
|
|
3215
|
+
*/
|
|
3216
|
+
const PUBLIC_READ_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
|
|
3217
|
+
getPublishedEntryPreview: {
|
|
3218
|
+
path: "/public/content/{siteId}/{type}/{slug}/preview",
|
|
3219
|
+
method: "GET",
|
|
3220
|
+
revalidate: publicReadFreshnessSeconds("getPublishedEntryPreview"),
|
|
3221
|
+
tags: ["content-{siteId}-{type}-{slug}"],
|
|
3222
|
+
auth: "public",
|
|
3223
|
+
responseKind: "json"
|
|
2603
3224
|
},
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
verticalBookingPreset("massage_bodywork.treatments", "massage_bodywork", "appointment", "Treatment", "Treatments", "Massage treatments, bodywork sessions, and one-to-one appointments."),
|
|
2612
|
-
verticalBookingPreset("massage_bodywork.group_sessions", "massage_bodywork", "class", "Group session", "Group sessions", "Regular bodywork, somatic movement, or self-massage sessions."),
|
|
2613
|
-
verticalBookingPreset("massage_bodywork.workshops", "massage_bodywork", "workshop", "Workshop", "Workshops", "One-off bodywork, self-massage, or somatic practice workshops."),
|
|
2614
|
-
verticalBookingPreset("therapist_practitioner.appointments", "therapist_practitioner", "appointment", "Appointment", "Appointments", "Sessions, consultations, treatments, or assessments."),
|
|
2615
|
-
verticalBookingPreset("therapist_practitioner.workshops", "therapist_practitioner", "workshop", "Workshop", "Workshops", "One-off group workshops, talks, or wellbeing sessions."),
|
|
2616
|
-
verticalBookingPreset("therapist_practitioner.retreats", "therapist_practitioner", "retreat", "Retreat", "Retreats", "Multi-day retreats or immersive group experiences."),
|
|
2617
|
-
verticalBookingPreset("beauty_spa.appointments", "beauty_spa", "appointment", "Appointment", "Appointments", "Treatments, consultations, services, and sessions."),
|
|
2618
|
-
verticalBookingPreset("beauty_spa.workshops", "beauty_spa", "workshop", "Workshop", "Workshops", "Skincare workshops, makeup lessons, demos, or group events."),
|
|
2619
|
-
verticalBookingPreset("consultant_coach.appointments", "consultant_coach", "appointment", "Appointment", "Appointments", "One-to-one calls, consultations, reviews, or coaching sessions."),
|
|
2620
|
-
verticalBookingPreset("consultant_coach.workshops", "consultant_coach", "workshop", "Workshop", "Workshops", "One-off group sessions, webinars, or strategy days."),
|
|
2621
|
-
verticalBookingPreset("consultant_coach.courses", "consultant_coach", "course", "Course", "Courses", "Fixed-schedule cohorts or multi-session group programmes."),
|
|
2622
|
-
verticalBookingPreset("consultant_coach.retreats", "consultant_coach", "retreat", "Retreat", "Retreats", "Multi-day coaching retreats or immersive experiences."),
|
|
2623
|
-
verticalBookingPreset("training_provider.courses", "training_provider", "course", "Course", "Courses", "Fixed-schedule courses, cohorts, and multi-session training."),
|
|
2624
|
-
verticalBookingPreset("training_provider.workshops", "training_provider", "workshop", "Workshop", "Workshops", "One-off workshops, masterclasses, and short training sessions."),
|
|
2625
|
-
verticalBookingPreset("training_provider.appointments", "training_provider", "appointment", "Appointment", "Appointments", "Consultations, assessments, mentoring, or office hours."),
|
|
2626
|
-
verticalBookingPreset("training_provider.classes", "training_provider", "class", "Class", "Classes", "Regular classes, sessions, or groups.", "settings"),
|
|
2627
|
-
verticalBookingPreset("training_provider.residentials", "training_provider", "retreat", "Residential", "Residentials", "Residential courses or multi-day training experiences.", "settings"),
|
|
2628
|
-
verticalBookingPreset("retreat_centre.retreats", "retreat_centre", "retreat", "Retreat", "Retreats", "Multi-day or residential retreats with richer booking needs."),
|
|
2629
|
-
verticalBookingPreset("retreat_centre.workshops", "retreat_centre", "workshop", "Workshop", "Workshops", "One-day retreats, ceremonies, workshops, or special events."),
|
|
2630
|
-
verticalBookingPreset("retreat_centre.classes", "retreat_centre", "class", "Class", "Classes", "Regular sessions like guided meditations or group practices."),
|
|
2631
|
-
verticalBookingPreset("retreat_centre.courses", "retreat_centre", "course", "Course", "Courses", "Fixed-schedule programmes or multi-session experiences."),
|
|
2632
|
-
verticalBookingPreset("retreat_centre.appointments", "retreat_centre", "appointment", "Appointment", "Appointments", "Private sessions, therapies, consultations, or add-ons."),
|
|
2633
|
-
verticalBookingPreset("music_school.lessons", "music_school", "appointment", "Lesson", "Lessons", "One-to-one lessons, consultations, or coaching sessions."),
|
|
2634
|
-
verticalBookingPreset("music_school.classes", "music_school", "class", "Class", "Classes", "Regular group classes, ensembles, or recurring sessions."),
|
|
2635
|
-
{
|
|
2636
|
-
...verticalBookingPreset("music_school.terms", "music_school", "course", "Term", "Terms", "Multi-week term blocks or fixed-date group courses."),
|
|
2637
|
-
eventPresetOverride: "term"
|
|
3225
|
+
listPublishedEntries: {
|
|
3226
|
+
path: "/public/content/{siteId}/{type}/entries",
|
|
3227
|
+
method: "GET",
|
|
3228
|
+
revalidate: publicReadFreshnessSeconds("listPublishedEntries"),
|
|
3229
|
+
tags: ["content-{siteId}-{type}"],
|
|
3230
|
+
auth: "public",
|
|
3231
|
+
responseKind: "json"
|
|
2638
3232
|
},
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
3233
|
+
getPublicFormById: {
|
|
3234
|
+
path: "/public/forms/{formId}",
|
|
3235
|
+
method: "GET",
|
|
3236
|
+
revalidate: publicReadFreshnessSeconds("getPublicFormById"),
|
|
3237
|
+
tags: [TAG_TEMPLATES.formById],
|
|
3238
|
+
auth: "public",
|
|
3239
|
+
responseKind: "json"
|
|
2646
3240
|
},
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
|
|
3241
|
+
listPublicEvents: {
|
|
3242
|
+
path: "/public/sites/{siteId}/events",
|
|
3243
|
+
method: "GET",
|
|
3244
|
+
revalidate: publicReadFreshnessSeconds("listPublicEvents"),
|
|
3245
|
+
tags: [TAG_TEMPLATES.publicEvents],
|
|
3246
|
+
auth: "public",
|
|
3247
|
+
responseKind: "json"
|
|
2653
3248
|
},
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
}
|
|
2671
|
-
|
|
2672
|
-
|
|
2673
|
-
|
|
2674
|
-
|
|
2675
|
-
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
}
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
|
|
2687
|
-
return firstPresetId ? [firstPresetId, ...presetIds.slice(1)] : null;
|
|
2688
|
-
}
|
|
2689
|
-
const DEFAULT_SITE_VERTICAL_BOOKING_CONFIG = {
|
|
2690
|
-
verticalId: null,
|
|
2691
|
-
selectedPresetIds: []
|
|
2692
|
-
};
|
|
2693
|
-
function appendUniqueIssue(issues, issue) {
|
|
2694
|
-
return issues.some((existing) => existing.code === issue.code) ? issues : [...issues, issue];
|
|
2695
|
-
}
|
|
2696
|
-
function collectRawConfigIssues(rawConfig, config) {
|
|
2697
|
-
const rawPresetValue = rawConfig.selectedPresetIds;
|
|
2698
|
-
const rawPresetIds = Array.isArray(rawPresetValue) ? rawPresetValue : [];
|
|
2699
|
-
let issues = [];
|
|
2700
|
-
if (rawConfig.verticalId != null && config.verticalId === null) issues = appendUniqueIssue(issues, {
|
|
2701
|
-
code: "unknown_vertical",
|
|
2702
|
-
rawValue: rawConfig.verticalId
|
|
2703
|
-
});
|
|
2704
|
-
if (config.verticalId === null && config.selectedPresetIds.length > 0) issues = appendUniqueIssue(issues, { code: "missing_vertical" });
|
|
2705
|
-
if (rawPresetValue !== void 0 && !Array.isArray(rawPresetValue) || rawPresetIds.some((presetId) => parseVerticalPresetId(presetId) === null)) issues = appendUniqueIssue(issues, {
|
|
2706
|
-
code: "unknown_preset",
|
|
2707
|
-
rawValue: rawPresetValue
|
|
2708
|
-
});
|
|
2709
|
-
if (rawConfig.verticalId != null && config.selectedPresetIds.length === 0) issues = appendUniqueIssue(issues, { code: "empty_selected_presets" });
|
|
2710
|
-
return issues;
|
|
2711
|
-
}
|
|
2712
|
-
function collectPresetConfigIssues(config) {
|
|
2713
|
-
const seenPresetIds = /* @__PURE__ */ new Set();
|
|
2714
|
-
const seenBehaviours = /* @__PURE__ */ new Set();
|
|
2715
|
-
let issues = [];
|
|
2716
|
-
for (const presetId of config.selectedPresetIds) {
|
|
2717
|
-
const presetDefinition = getVerticalPresetDefinition(presetId);
|
|
2718
|
-
if (seenPresetIds.has(presetId)) issues = appendUniqueIssue(issues, { code: "duplicate_preset_id" });
|
|
2719
|
-
seenPresetIds.add(presetId);
|
|
2720
|
-
if (config.verticalId !== null && presetDefinition.verticalId !== config.verticalId) issues = appendUniqueIssue(issues, { code: "preset_vertical_mismatch" });
|
|
2721
|
-
if (presetDefinition.availability === "future") issues = appendUniqueIssue(issues, { code: "future_preset_selected" });
|
|
2722
|
-
if (seenBehaviours.has(presetDefinition.canonicalBehaviour)) issues = appendUniqueIssue(issues, { code: "duplicate_canonical_behaviour" });
|
|
2723
|
-
seenBehaviours.add(presetDefinition.canonicalBehaviour);
|
|
3249
|
+
listPublicTeamMembers: {
|
|
3250
|
+
path: "/public/sites/{siteId}/team-members",
|
|
3251
|
+
method: "GET",
|
|
3252
|
+
revalidate: publicReadFreshnessSeconds("listPublicTeamMembers"),
|
|
3253
|
+
tags: [TAG_TEMPLATES.publicTeamMembers],
|
|
3254
|
+
errors: [],
|
|
3255
|
+
auth: "public",
|
|
3256
|
+
responseKind: "json"
|
|
3257
|
+
},
|
|
3258
|
+
listPublicPasses: {
|
|
3259
|
+
path: "/public/sites/{siteId}/bookings/products/passes",
|
|
3260
|
+
method: "GET",
|
|
3261
|
+
revalidate: publicReadFreshnessSeconds("listPublicPasses"),
|
|
3262
|
+
tags: [TAG_TEMPLATES.publicPasses],
|
|
3263
|
+
auth: "public",
|
|
3264
|
+
responseKind: "json"
|
|
3265
|
+
},
|
|
3266
|
+
listPublicMemberships: {
|
|
3267
|
+
path: "/public/sites/{siteId}/bookings/products/memberships",
|
|
3268
|
+
method: "GET",
|
|
3269
|
+
revalidate: publicReadFreshnessSeconds("listPublicMemberships"),
|
|
3270
|
+
tags: [TAG_TEMPLATES.publicMemberships],
|
|
3271
|
+
auth: "public",
|
|
3272
|
+
responseKind: "json"
|
|
3273
|
+
},
|
|
3274
|
+
listPublicProducts: {
|
|
3275
|
+
path: "/public/sites/{siteId}/products",
|
|
3276
|
+
method: "GET",
|
|
3277
|
+
revalidate: publicReadFreshnessSeconds("listPublicProducts"),
|
|
3278
|
+
tags: [TAG_TEMPLATES.publicProducts],
|
|
3279
|
+
errors: [],
|
|
3280
|
+
auth: "public",
|
|
3281
|
+
responseKind: "json"
|
|
2724
3282
|
}
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
}
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
config,
|
|
2758
|
-
issues: [{ code: "empty_selected_presets" }]
|
|
2759
|
-
};
|
|
2760
|
-
return {
|
|
2761
|
-
kind: "configured",
|
|
2762
|
-
config: configuredConfig,
|
|
2763
|
-
selectedPresets: configuredConfig.selectedPresetIds.map(getVerticalPresetDefinition)
|
|
2764
|
-
};
|
|
3283
|
+
});
|
|
3284
|
+
({
|
|
3285
|
+
...ACCOUNT_ENDPOINT_DEFINITIONS,
|
|
3286
|
+
...PUBLIC_EVENT_ENDPOINT_DEFINITIONS,
|
|
3287
|
+
...GIFTING_ENDPOINT_DEFINITIONS,
|
|
3288
|
+
...PUBLIC_READ_ENDPOINT_DEFINITIONS
|
|
3289
|
+
}), TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteTheme, TAG_TEMPLATES.siteCollection, { ...SITE_API_KEY_ENDPOINT_DEFINITIONS }, TAG_TEMPLATES.site, TAG_TEMPLATES.siteBookingSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteBookingSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteEmailSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteEmailSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteEmailSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteEmailSettings, {
|
|
3290
|
+
...NEWSLETTER_ENDPOINT_DEFINITIONS,
|
|
3291
|
+
...APPOINTMENT_ENDPOINT_DEFINITIONS,
|
|
3292
|
+
...EVENT_SERIES_REGISTRATION_ENDPOINT_DEFINITIONS
|
|
3293
|
+
}, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteById, TAG_TEMPLATES.siteBySlug, TAG_TEMPLATES.siteByDomain, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteById, TAG_TEMPLATES.siteBySlug, TAG_TEMPLATES.siteByDomain, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.workflowRunById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.routeById, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.site, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteNavigation, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteNavigation, TAG_TEMPLATES.navigationMenuById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteNavigation, TAG_TEMPLATES.navigationMenuById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteNavigation, TAG_TEMPLATES.navigationMenuById, TAG_TEMPLATES.navigationItemById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteNavigation, TAG_TEMPLATES.navigationMenuById, TAG_TEMPLATES.navigationItemById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteNavigation, TAG_TEMPLATES.navigationMenuById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteTheme, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteTheme, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteTheme, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteRedirects, TAG_TEMPLATES.siteRouteOutcomes, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteRedirects, TAG_TEMPLATES.siteRouteOutcomes, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.formSubmissionsBySlug, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.formSubmissionsBySlug, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.formSubmissionsBySlug, TAG_TEMPLATES.siteForms, { ...PUBLIC_BOOKING_AVAILABILITY_ENDPOINT_DEFINITIONS }, TAG_TEMPLATES.publicEventFilters, TAG_TEMPLATES.publicEvents, TAG_TEMPLATES.publicShop, TAG_TEMPLATES.publicCheckout, TAG_TEMPLATES.siteRoutableContent, { ...PUBLIC_EVENT_CHECKOUT_ENDPOINT_DEFINITIONS }, TAG_TEMPLATES.publicEvents, TAG_TEMPLATES.publicEvents, { ...EVENT_MANAGEMENT_ENDPOINT_DEFINITIONS }, { ...SDK_MEDIA_ENDPOINT_DEFINITIONS }, { ...SDK_ENDPOINT_DEFINITIONS }, { ...SDK_ENTRY_READ_ENDPOINTS };
|
|
3294
|
+
z.object({ refreshToken: z.string().min(1).max(4096) }).strict();
|
|
3295
|
+
z.object({
|
|
3296
|
+
accessToken: z.string().min(1).max(4096),
|
|
3297
|
+
refreshToken: z.string().min(1).max(4096)
|
|
3298
|
+
}).strict();
|
|
3299
|
+
const ACCOUNT_SITE_CURSOR_MAX_LENGTH = 2048;
|
|
3300
|
+
const ACCOUNT_SITE_TIMESTAMP_PATTERN = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.(\d{1,6}))?(Z|[+-]\d{2}:\d{2})$/;
|
|
3301
|
+
/** Strict, injection-safe PostgreSQL/RFC3339 timestamp text used in cursors. */
|
|
3302
|
+
function isAccountSiteTimestamp(value) {
|
|
3303
|
+
if (typeof value !== "string") return false;
|
|
3304
|
+
const match = ACCOUNT_SITE_TIMESTAMP_PATTERN.exec(value);
|
|
3305
|
+
if (!match) return false;
|
|
3306
|
+
const [, year, month, day, hour, minute, second, , offset] = match;
|
|
3307
|
+
const date = new Date(Date.UTC(Number(year), Number(month) - 1, Number(day)));
|
|
3308
|
+
const offsetValue = offset ?? "";
|
|
3309
|
+
const offsetIsValid = offsetValue === "Z" || (() => {
|
|
3310
|
+
const offsetMatch = /^(?:[+-])(\d{2}):(\d{2})$/.exec(offsetValue);
|
|
3311
|
+
if (!offsetMatch) return false;
|
|
3312
|
+
return Number(offsetMatch[1]) <= 23 && Number(offsetMatch[2]) <= 59;
|
|
3313
|
+
})();
|
|
3314
|
+
return date.getUTCFullYear() === Number(year) && date.getUTCMonth() === Number(month) - 1 && date.getUTCDate() === Number(day) && Number(hour) <= 23 && Number(minute) <= 59 && Number(second) <= 59 && offsetIsValid;
|
|
2765
3315
|
}
|
|
3316
|
+
const accountSiteTimestampSchema = z.string().refine(isAccountSiteTimestamp, { message: "Expected a strict account site timestamp" });
|
|
3317
|
+
z.enum([
|
|
3318
|
+
"managed",
|
|
3319
|
+
"headless_cms",
|
|
3320
|
+
"headless_full"
|
|
3321
|
+
]);
|
|
3322
|
+
z.object({ title: z.string().trim().min(1).max(120) });
|
|
3323
|
+
const abandonedStandardKeyIdsSchema = z.object({
|
|
3324
|
+
live: z.string().uuid().optional(),
|
|
3325
|
+
management: z.string().uuid().optional()
|
|
3326
|
+
}).strict();
|
|
3327
|
+
const abandonedPreviewKeyIdsSchema = z.object({
|
|
3328
|
+
live: z.string().uuid().optional(),
|
|
3329
|
+
management: z.string().uuid().optional(),
|
|
3330
|
+
preview: z.string().uuid().optional()
|
|
3331
|
+
}).strict();
|
|
3332
|
+
z.discriminatedUnion("operation", [
|
|
3333
|
+
z.object({
|
|
3334
|
+
operation: z.literal("issue_standard"),
|
|
3335
|
+
siteId: z.string().uuid(),
|
|
3336
|
+
operationId: z.string().uuid(),
|
|
3337
|
+
projectName: z.string().trim().min(1).max(120),
|
|
3338
|
+
abandonedKeyIds: abandonedStandardKeyIdsSchema.default({})
|
|
3339
|
+
}).strict(),
|
|
3340
|
+
z.object({
|
|
3341
|
+
operation: z.literal("issue_with_preview"),
|
|
3342
|
+
siteId: z.string().uuid(),
|
|
3343
|
+
operationId: z.string().uuid(),
|
|
3344
|
+
projectName: z.string().trim().min(1).max(120),
|
|
3345
|
+
abandonedKeyIds: abandonedPreviewKeyIdsSchema.default({})
|
|
3346
|
+
}).strict(),
|
|
3347
|
+
z.object({
|
|
3348
|
+
operation: z.literal("revalidate_standard"),
|
|
3349
|
+
siteId: z.string().uuid(),
|
|
3350
|
+
operationId: z.string().uuid(),
|
|
3351
|
+
projectName: z.string().trim().min(1).max(120),
|
|
3352
|
+
keyIds: z.object({
|
|
3353
|
+
live: z.string().uuid(),
|
|
3354
|
+
management: z.string().uuid()
|
|
3355
|
+
}).strict()
|
|
3356
|
+
}).strict(),
|
|
3357
|
+
z.object({
|
|
3358
|
+
operation: z.literal("revalidate_with_preview"),
|
|
3359
|
+
siteId: z.string().uuid(),
|
|
3360
|
+
operationId: z.string().uuid(),
|
|
3361
|
+
projectName: z.string().trim().min(1).max(120),
|
|
3362
|
+
keyIds: z.object({
|
|
3363
|
+
live: z.string().uuid(),
|
|
3364
|
+
management: z.string().uuid(),
|
|
3365
|
+
preview: z.string().uuid()
|
|
3366
|
+
}).strict()
|
|
3367
|
+
}).strict()
|
|
3368
|
+
]);
|
|
3369
|
+
z.object({
|
|
3370
|
+
cursor: z.string().min(1).max(ACCOUNT_SITE_CURSOR_MAX_LENGTH).optional(),
|
|
3371
|
+
limit: z.coerce.number().int().min(1).max(100).default(50),
|
|
3372
|
+
search: z.string().trim().min(1).max(120).optional()
|
|
3373
|
+
});
|
|
2766
3374
|
z.object({
|
|
2767
3375
|
formulaVersion: z.literal("managed-domain-overage-v1"),
|
|
2768
3376
|
conversionRule: z.literal("usd-to-gbp-1-to-1-v1"),
|
|
@@ -20722,102 +21330,31 @@ const newsletterFormFragment = defineFragment({
|
|
|
20722
21330
|
description: "Newsletter subscription form with preset field configurations.",
|
|
20723
21331
|
fields: [
|
|
20724
21332
|
{
|
|
20725
|
-
id: "
|
|
20726
|
-
type: "
|
|
20727
|
-
label: "
|
|
20728
|
-
description: "Choose
|
|
20729
|
-
defaultValue: "
|
|
20730
|
-
required:
|
|
20731
|
-
ui: { intent: "behavior" },
|
|
20732
|
-
options: [{
|
|
20733
|
-
value: "riverbank",
|
|
20734
|
-
label: "Riverbank newsletter"
|
|
20735
|
-
}]
|
|
20736
|
-
},
|
|
20737
|
-
{
|
|
20738
|
-
id: "listId",
|
|
20739
|
-
type: "reference",
|
|
20740
|
-
label: "Newsletter list",
|
|
20741
|
-
description: "Select the list new subscribers should be added to.",
|
|
20742
|
-
required: false,
|
|
20743
|
-
referenceKind: "newsletterList",
|
|
20744
|
-
allowManualEntry: false,
|
|
20745
|
-
ui: {
|
|
20746
|
-
intent: "behavior",
|
|
20747
|
-
visibleWhen: {
|
|
20748
|
-
field: "destinationProvider",
|
|
20749
|
-
equals: "riverbank"
|
|
20750
|
-
}
|
|
20751
|
-
}
|
|
20752
|
-
},
|
|
20753
|
-
{
|
|
20754
|
-
id: "mailchimpAudienceId",
|
|
20755
|
-
type: "reference",
|
|
20756
|
-
label: "Mailchimp audience",
|
|
20757
|
-
description: "Choose the Mailchimp audience for new subscribers.",
|
|
20758
|
-
required: false,
|
|
20759
|
-
referenceKind: "mailchimpAudience",
|
|
20760
|
-
allowManualEntry: false,
|
|
20761
|
-
ui: {
|
|
20762
|
-
intent: "behavior",
|
|
20763
|
-
visibleWhen: {
|
|
20764
|
-
field: "destinationProvider",
|
|
20765
|
-
equals: "mailchimp"
|
|
20766
|
-
}
|
|
20767
|
-
}
|
|
20768
|
-
},
|
|
20769
|
-
{
|
|
20770
|
-
id: "mailchimpTags",
|
|
20771
|
-
type: "text",
|
|
20772
|
-
label: "Mailchimp tags",
|
|
20773
|
-
description: "Optional tags to apply in Mailchimp, separated by commas or semicolons.",
|
|
21333
|
+
id: "targeting",
|
|
21334
|
+
type: "group",
|
|
21335
|
+
label: "Mailing-list targeting",
|
|
21336
|
+
description: "Choose what kind of emails people signing up here will receive.",
|
|
21337
|
+
defaultValue: { mode: "default" },
|
|
21338
|
+
required: true,
|
|
20774
21339
|
ui: {
|
|
20775
21340
|
intent: "behavior",
|
|
20776
|
-
|
|
20777
|
-
|
|
20778
|
-
|
|
20779
|
-
|
|
20780
|
-
|
|
20781
|
-
|
|
20782
|
-
|
|
20783
|
-
|
|
20784
|
-
|
|
20785
|
-
|
|
20786
|
-
|
|
20787
|
-
|
|
20788
|
-
|
|
20789
|
-
|
|
20790
|
-
|
|
20791
|
-
|
|
20792
|
-
|
|
20793
|
-
},
|
|
20794
|
-
{
|
|
20795
|
-
value: "emailName",
|
|
20796
|
-
label: "Email + Name"
|
|
20797
|
-
},
|
|
20798
|
-
{
|
|
20799
|
-
value: "emailFirstLast",
|
|
20800
|
-
label: "Email + First/Last Name"
|
|
20801
|
-
},
|
|
20802
|
-
{
|
|
20803
|
-
value: "emailNameCompany",
|
|
20804
|
-
label: "Email + Name + Company (B2B)"
|
|
20805
|
-
}
|
|
20806
|
-
]
|
|
20807
|
-
},
|
|
20808
|
-
{
|
|
20809
|
-
id: "includePhone",
|
|
20810
|
-
type: "boolean",
|
|
20811
|
-
label: "Include phone field (optional)",
|
|
20812
|
-
description: "Adds an optional phone field to the selected preset (never required).",
|
|
20813
|
-
defaultValue: false,
|
|
20814
|
-
ui: { intent: "display" }
|
|
20815
|
-
},
|
|
20816
|
-
{
|
|
20817
|
-
id: "buttonLabel",
|
|
20818
|
-
type: "text",
|
|
20819
|
-
label: "Button label",
|
|
20820
|
-
defaultValue: "Subscribe"
|
|
21341
|
+
widget: "mailingListTargeting"
|
|
21342
|
+
},
|
|
21343
|
+
schema: { fields: [{
|
|
21344
|
+
id: "mode",
|
|
21345
|
+
type: "select",
|
|
21346
|
+
label: "Mode",
|
|
21347
|
+
required: true,
|
|
21348
|
+
defaultValue: "default",
|
|
21349
|
+
options: [{
|
|
21350
|
+
value: "default",
|
|
21351
|
+
label: "Default"
|
|
21352
|
+
}, {
|
|
21353
|
+
value: "custom",
|
|
21354
|
+
label: "Custom"
|
|
21355
|
+
}],
|
|
21356
|
+
ui: { hidden: true }
|
|
21357
|
+
}] }
|
|
20821
21358
|
},
|
|
20822
21359
|
createButtonVariantField({
|
|
20823
21360
|
id: "buttonVariant",
|
|
@@ -20825,46 +21362,42 @@ const newsletterFormFragment = defineFragment({
|
|
|
20825
21362
|
defaultValue: "primary"
|
|
20826
21363
|
}),
|
|
20827
21364
|
{
|
|
20828
|
-
id: "
|
|
20829
|
-
type: "text",
|
|
20830
|
-
label: "Success message",
|
|
20831
|
-
description: "Shown after successful subscription.",
|
|
20832
|
-
defaultValue: "Thanks for subscribing!"
|
|
20833
|
-
},
|
|
20834
|
-
{
|
|
20835
|
-
id: "privacyNote",
|
|
21365
|
+
id: "mailingListSource",
|
|
20836
21366
|
type: "text",
|
|
20837
|
-
label: "
|
|
20838
|
-
|
|
21367
|
+
label: "Mailing-list source",
|
|
21368
|
+
ui: {
|
|
21369
|
+
hidden: true,
|
|
21370
|
+
intent: "behavior"
|
|
21371
|
+
}
|
|
20839
21372
|
},
|
|
20840
21373
|
{
|
|
20841
|
-
id: "
|
|
21374
|
+
id: "mailingListSourceToken",
|
|
20842
21375
|
type: "text",
|
|
20843
|
-
label: "
|
|
20844
|
-
description: "Optional tags to apply on subscribe (comma or semicolon separated).",
|
|
21376
|
+
label: "Mailing-list source token",
|
|
20845
21377
|
ui: {
|
|
20846
|
-
|
|
20847
|
-
|
|
20848
|
-
field: "destinationProvider",
|
|
20849
|
-
equals: "riverbank"
|
|
20850
|
-
}
|
|
21378
|
+
hidden: true,
|
|
21379
|
+
intent: "behavior"
|
|
20851
21380
|
}
|
|
20852
21381
|
}
|
|
20853
21382
|
],
|
|
20854
21383
|
layout: [el("newsletter-form", withApiBindings({
|
|
20855
|
-
source:
|
|
20856
|
-
|
|
20857
|
-
|
|
20858
|
-
|
|
20859
|
-
|
|
20860
|
-
|
|
21384
|
+
source: { $bind: {
|
|
21385
|
+
from: "mailingListSource",
|
|
21386
|
+
fallback: "block"
|
|
21387
|
+
} },
|
|
21388
|
+
sourceRef: {
|
|
21389
|
+
tag: "signed_source_ref",
|
|
21390
|
+
token: { $bind: { from: "mailingListSourceToken" } }
|
|
21391
|
+
},
|
|
21392
|
+
targeting: { $bind: {
|
|
21393
|
+
from: "targeting",
|
|
21394
|
+
fallback: { mode: "default" }
|
|
21395
|
+
} },
|
|
21396
|
+
mailingList: { $bind: { from: "$root.mailingList" } },
|
|
20861
21397
|
buttonVariant: { $bind: {
|
|
20862
21398
|
from: "buttonVariant",
|
|
20863
21399
|
fallback: "primary"
|
|
20864
21400
|
} },
|
|
20865
|
-
successMessage: { $bind: { from: "successMessage" } },
|
|
20866
|
-
privacyNote: { $bind: { from: "privacyNote" } },
|
|
20867
|
-
tags: { $bind: { from: "tags" } },
|
|
20868
21401
|
spamProtectionEnabled: { $bind: { from: "$root.spamProtectionEnabled" } }
|
|
20869
21402
|
}), [])]
|
|
20870
21403
|
});
|
|
@@ -23039,14 +23572,19 @@ const contactNewsletterLayout = styledSection({
|
|
|
23039
23572
|
as: "h2",
|
|
23040
23573
|
className: "newsletter-copy-title"
|
|
23041
23574
|
}, when("newsletterTitle"), bind("newsletterTitle")), richText({ className: "newsletter-copy-subtitle rb-prose rb-max-w-none" }, when("newsletterSubtitle"), bind("newsletterSubtitle"))]), el("newsletter-form", withApiBindings({
|
|
23042
|
-
source:
|
|
23043
|
-
|
|
23044
|
-
|
|
23045
|
-
|
|
23046
|
-
|
|
23047
|
-
|
|
23048
|
-
|
|
23049
|
-
|
|
23575
|
+
source: { $bind: {
|
|
23576
|
+
from: "mailingListSource",
|
|
23577
|
+
fallback: "block"
|
|
23578
|
+
} },
|
|
23579
|
+
sourceRef: {
|
|
23580
|
+
tag: "signed_source_ref",
|
|
23581
|
+
token: { $bind: { from: "mailingListSourceToken" } }
|
|
23582
|
+
},
|
|
23583
|
+
targeting: { $bind: {
|
|
23584
|
+
from: "targeting",
|
|
23585
|
+
fallback: { mode: "default" }
|
|
23586
|
+
} },
|
|
23587
|
+
mailingList: { $bind: { from: "$root.mailingList" } },
|
|
23050
23588
|
spamProtectionEnabled: { $bind: { from: "$root.spamProtectionEnabled" } }
|
|
23051
23589
|
}), [])])])], { className: "contact-newsletter-container" }),
|
|
23052
23590
|
baseClass: "",
|
|
@@ -23082,79 +23620,55 @@ const contactNewsletterBlockDefinition = {
|
|
|
23082
23620
|
label: "Newsletter intro"
|
|
23083
23621
|
},
|
|
23084
23622
|
{
|
|
23085
|
-
id: "
|
|
23086
|
-
type: "
|
|
23087
|
-
label: "
|
|
23088
|
-
description: "
|
|
23623
|
+
id: "targeting",
|
|
23624
|
+
type: "group",
|
|
23625
|
+
label: "Mailing-list targeting",
|
|
23626
|
+
description: "Choose what kind of emails people signing up here will receive.",
|
|
23089
23627
|
required: true,
|
|
23090
|
-
|
|
23091
|
-
|
|
23092
|
-
|
|
23093
|
-
|
|
23094
|
-
|
|
23095
|
-
|
|
23096
|
-
|
|
23097
|
-
|
|
23098
|
-
|
|
23099
|
-
|
|
23100
|
-
|
|
23101
|
-
{
|
|
23102
|
-
value: "
|
|
23103
|
-
label: "
|
|
23104
|
-
},
|
|
23105
|
-
|
|
23106
|
-
|
|
23107
|
-
|
|
23108
|
-
}
|
|
23109
|
-
|
|
23110
|
-
value: "emailFirstLast",
|
|
23111
|
-
label: "Email + First/Last Name"
|
|
23112
|
-
},
|
|
23113
|
-
{
|
|
23114
|
-
value: "emailNameCompany",
|
|
23115
|
-
label: "Email + Name + Company (B2B)"
|
|
23116
|
-
}
|
|
23117
|
-
]
|
|
23118
|
-
},
|
|
23119
|
-
{
|
|
23120
|
-
id: "includePhone",
|
|
23121
|
-
type: "boolean",
|
|
23122
|
-
label: "Include phone field",
|
|
23123
|
-
defaultValue: false,
|
|
23124
|
-
ui: { intent: "display" }
|
|
23125
|
-
},
|
|
23126
|
-
{
|
|
23127
|
-
id: "newsletterButtonLabel",
|
|
23128
|
-
type: "text",
|
|
23129
|
-
label: "Newsletter button label",
|
|
23130
|
-
defaultValue: "Subscribe",
|
|
23131
|
-
ui: { intent: "display" }
|
|
23132
|
-
},
|
|
23133
|
-
{
|
|
23134
|
-
id: "newsletterSuccessMessage",
|
|
23135
|
-
type: "text",
|
|
23136
|
-
label: "Newsletter success message",
|
|
23137
|
-
defaultValue: "Thanks for subscribing!",
|
|
23138
|
-
ui: { intent: "behavior" }
|
|
23628
|
+
defaultValue: { mode: "default" },
|
|
23629
|
+
ui: {
|
|
23630
|
+
intent: "behavior",
|
|
23631
|
+
widget: "mailingListTargeting"
|
|
23632
|
+
},
|
|
23633
|
+
schema: { fields: [{
|
|
23634
|
+
id: "mode",
|
|
23635
|
+
type: "select",
|
|
23636
|
+
label: "Mode",
|
|
23637
|
+
required: true,
|
|
23638
|
+
defaultValue: "default",
|
|
23639
|
+
options: [{
|
|
23640
|
+
value: "default",
|
|
23641
|
+
label: "Default"
|
|
23642
|
+
}, {
|
|
23643
|
+
value: "custom",
|
|
23644
|
+
label: "Custom"
|
|
23645
|
+
}],
|
|
23646
|
+
ui: { hidden: true }
|
|
23647
|
+
}] }
|
|
23139
23648
|
},
|
|
23140
23649
|
{
|
|
23141
|
-
id: "
|
|
23650
|
+
id: "contactTitle",
|
|
23142
23651
|
type: "text",
|
|
23143
|
-
label: "
|
|
23144
|
-
|
|
23652
|
+
label: "Contact title",
|
|
23653
|
+
defaultValue: "Get in touch"
|
|
23145
23654
|
},
|
|
23146
23655
|
{
|
|
23147
|
-
id: "
|
|
23656
|
+
id: "mailingListSource",
|
|
23148
23657
|
type: "text",
|
|
23149
|
-
label: "
|
|
23150
|
-
|
|
23151
|
-
|
|
23658
|
+
label: "Mailing-list source",
|
|
23659
|
+
ui: {
|
|
23660
|
+
hidden: true,
|
|
23661
|
+
intent: "behavior"
|
|
23662
|
+
}
|
|
23152
23663
|
},
|
|
23153
23664
|
{
|
|
23154
|
-
id: "
|
|
23665
|
+
id: "mailingListSourceToken",
|
|
23155
23666
|
type: "text",
|
|
23156
|
-
label: "
|
|
23157
|
-
|
|
23667
|
+
label: "Mailing-list source token",
|
|
23668
|
+
ui: {
|
|
23669
|
+
hidden: true,
|
|
23670
|
+
intent: "behavior"
|
|
23671
|
+
}
|
|
23158
23672
|
},
|
|
23159
23673
|
{
|
|
23160
23674
|
id: "contactIntro",
|
|
@@ -23355,6 +23869,12 @@ const arrayLengthTransform = {
|
|
|
23355
23869
|
summary: "Get the length of an array",
|
|
23356
23870
|
run: (value) => Array.isArray(value) ? value.length : 0
|
|
23357
23871
|
};
|
|
23872
|
+
const booleanNotTransform = {
|
|
23873
|
+
id: "boolean.not",
|
|
23874
|
+
kind: "formatter",
|
|
23875
|
+
summary: "Invert a boolean value; fail closed to false for other inputs",
|
|
23876
|
+
run: (value) => typeof value === "boolean" ? !value : false
|
|
23877
|
+
};
|
|
23358
23878
|
const jsonArrayTransform = {
|
|
23359
23879
|
id: "value.jsonArray",
|
|
23360
23880
|
kind: "formatter",
|
|
@@ -23405,33 +23925,51 @@ const marqueeLoopTransform = {
|
|
|
23405
23925
|
function toUnknownArray(value) {
|
|
23406
23926
|
return Array.isArray(value) ? value : [];
|
|
23407
23927
|
}
|
|
23928
|
+
/**
|
|
23929
|
+
* Map a content state/enum to a theme token colour — the first-class way to turn
|
|
23930
|
+
* a value like a class's availability (`available`/`filling`/`waitlist`), a
|
|
23931
|
+
* card's featured flag, or a pricing tier level into a themed colour. Authors
|
|
23932
|
+
* write role names and get `rgb(var(--tb-<role>))`, so the result live-recolours
|
|
23933
|
+
* with the theme and drops directly into a `style` binding (e.g.
|
|
23934
|
+
* `borderLeftColor`). Returns `undefined` when the value matches no case and no
|
|
23935
|
+
* fallback is given, so the style property is simply omitted.
|
|
23936
|
+
*/
|
|
23937
|
+
const mapTokenTransform = {
|
|
23938
|
+
id: "value.mapToken",
|
|
23939
|
+
kind: "formatter",
|
|
23940
|
+
summary: "Map a state/enum value to a theme token colour (rgb(var(--tb-<role>)))",
|
|
23941
|
+
schema: z.object({
|
|
23942
|
+
/**
|
|
23943
|
+
* Maps an input state/enum value (stringified) to a theme token ROLE name
|
|
23944
|
+
* (e.g. `secondary`, `accent`, `muted`, `border`). The role is wrapped to
|
|
23945
|
+
* `rgb(var(--tb-<role>))` so the result drops straight into a `style` binding.
|
|
23946
|
+
*/
|
|
23947
|
+
cases: z.record(z.string(), z.string()),
|
|
23948
|
+
/** Role used when the value matches no case. Omit to yield `undefined`. */
|
|
23949
|
+
fallback: z.string().optional()
|
|
23950
|
+
}),
|
|
23951
|
+
run: (value, options) => {
|
|
23952
|
+
const role = options.cases[String(value)] ?? options.fallback;
|
|
23953
|
+
return role ? `rgb(var(--tb-${role}))` : void 0;
|
|
23954
|
+
}
|
|
23955
|
+
};
|
|
23408
23956
|
const formattingTransforms = [
|
|
23957
|
+
{
|
|
23958
|
+
id: "value.equals",
|
|
23959
|
+
kind: "formatter",
|
|
23960
|
+
summary: "Compare a value to a fixed string",
|
|
23961
|
+
schema: z.object({ value: z.string() }),
|
|
23962
|
+
run: (value, options) => value === options.value
|
|
23963
|
+
},
|
|
23409
23964
|
uppercaseTransform,
|
|
23410
23965
|
fallbackTransform,
|
|
23411
23966
|
dateFormatShort,
|
|
23412
23967
|
arrayLengthTransform,
|
|
23968
|
+
booleanNotTransform,
|
|
23413
23969
|
jsonArrayTransform,
|
|
23414
23970
|
csvTransform,
|
|
23415
23971
|
marqueeLoopTransform,
|
|
23416
|
-
|
|
23417
|
-
id: "value.mapToken",
|
|
23418
|
-
kind: "formatter",
|
|
23419
|
-
summary: "Map a state/enum value to a theme token colour (rgb(var(--tb-<role>)))",
|
|
23420
|
-
schema: z.object({
|
|
23421
|
-
/**
|
|
23422
|
-
* Maps an input state/enum value (stringified) to a theme token ROLE name
|
|
23423
|
-
* (e.g. `secondary`, `accent`, `muted`, `border`). The role is wrapped to
|
|
23424
|
-
* `rgb(var(--tb-<role>))` so the result drops straight into a `style` binding.
|
|
23425
|
-
*/
|
|
23426
|
-
cases: z.record(z.string(), z.string()),
|
|
23427
|
-
/** Role used when the value matches no case. Omit to yield `undefined`. */
|
|
23428
|
-
fallback: z.string().optional()
|
|
23429
|
-
}),
|
|
23430
|
-
run: (value, options) => {
|
|
23431
|
-
const role = options.cases[String(value)] ?? options.fallback;
|
|
23432
|
-
return role ? `rgb(var(--tb-${role}))` : void 0;
|
|
23433
|
-
}
|
|
23434
|
-
}
|
|
23972
|
+
mapTokenTransform
|
|
23435
23973
|
];
|
|
23436
23974
|
//#endregion
|
|
23437
23975
|
//#region ../blocks/src/system/transforms/registry/ui.ts
|
|
@@ -24848,13 +25386,9 @@ const footerStandardContactBindings = {
|
|
|
24848
25386
|
};
|
|
24849
25387
|
const footerMailingListBindings = {
|
|
24850
25388
|
source: { $bind: { from: "module.engagement.runtime.source" } },
|
|
24851
|
-
|
|
24852
|
-
|
|
24853
|
-
|
|
24854
|
-
includePhone: { $bind: { from: "module.engagement.runtime.includePhone" } },
|
|
24855
|
-
buttonLabel: { $bind: { from: "module.engagement.runtime.buttonLabel" } },
|
|
24856
|
-
successMessage: { $bind: { from: "module.engagement.runtime.successMessage" } },
|
|
24857
|
-
privacyNote: { $bind: { from: "module.engagement.runtime.privacyNote" } }
|
|
25389
|
+
sourceRef: { $bind: { from: "module.engagement.runtime.sourceRef" } },
|
|
25390
|
+
mailingList: { $bind: { from: "module.engagement.runtime.mailingList" } },
|
|
25391
|
+
targeting: { $bind: { from: "module.engagement.runtime.targeting" } }
|
|
24858
25392
|
};
|
|
24859
25393
|
const footerSpamProtectionBinding = { spamProtectionEnabled: { $bind: { from: "$root.spamProtectionEnabled" } } };
|
|
24860
25394
|
const brandLogo = link({
|
|
@@ -26542,6 +27076,78 @@ const appointmentBookingBlockDefinition = {
|
|
|
26542
27076
|
}
|
|
26543
27077
|
}
|
|
26544
27078
|
};
|
|
27079
|
+
const appointmentServicesBlockDefinition = {
|
|
27080
|
+
manifest: createBlockManifest({
|
|
27081
|
+
id: "block.appointment-services",
|
|
27082
|
+
version: "1.0.0",
|
|
27083
|
+
title: "Appointment Services",
|
|
27084
|
+
titleSource: "heading",
|
|
27085
|
+
description: "List public appointment services with booking links",
|
|
27086
|
+
skipSectionStyles: true,
|
|
27087
|
+
additionalFields: [
|
|
27088
|
+
{
|
|
27089
|
+
id: "heading",
|
|
27090
|
+
type: "text",
|
|
27091
|
+
label: "Heading",
|
|
27092
|
+
required: false,
|
|
27093
|
+
multiline: false,
|
|
27094
|
+
defaultValue: "Appointments",
|
|
27095
|
+
ui: { intent: "content" }
|
|
27096
|
+
},
|
|
27097
|
+
{
|
|
27098
|
+
id: "description",
|
|
27099
|
+
type: "richText",
|
|
27100
|
+
label: "Description",
|
|
27101
|
+
required: false,
|
|
27102
|
+
ui: { intent: "content" }
|
|
27103
|
+
},
|
|
27104
|
+
sectionStylesField({
|
|
27105
|
+
id: "_sectionStyles",
|
|
27106
|
+
label: "Section styles",
|
|
27107
|
+
renderInHeader: false
|
|
27108
|
+
})
|
|
27109
|
+
],
|
|
27110
|
+
styleTokens: {
|
|
27111
|
+
background: "surface",
|
|
27112
|
+
typography: "body",
|
|
27113
|
+
spacing: "md"
|
|
27114
|
+
},
|
|
27115
|
+
behaviours: {
|
|
27116
|
+
supportsThemeSwitching: true,
|
|
27117
|
+
inlineEditing: true,
|
|
27118
|
+
animation: false,
|
|
27119
|
+
paletteHidden: false
|
|
27120
|
+
},
|
|
27121
|
+
category: "interactive",
|
|
27122
|
+
contentSource: { kind: "inline" },
|
|
27123
|
+
tags: [
|
|
27124
|
+
"booking",
|
|
27125
|
+
"appointment",
|
|
27126
|
+
"services",
|
|
27127
|
+
"scheduling"
|
|
27128
|
+
],
|
|
27129
|
+
icon: "CalendarDays",
|
|
27130
|
+
layout: [styledSection({
|
|
27131
|
+
baseClass: "",
|
|
27132
|
+
spacing: "spacious",
|
|
27133
|
+
children: sectionContainer([
|
|
27134
|
+
text({ as: "h2" }, bind("content.heading"), when("content.heading")),
|
|
27135
|
+
richText({ className: "rb-prose rb-max-w-none" }, bind("content.description"), when("content.description")),
|
|
27136
|
+
el("appointment-services", {
|
|
27137
|
+
sectionHeading: { $bind: { from: "content.heading" } },
|
|
27138
|
+
services: { $bind: { from: "data.services" } },
|
|
27139
|
+
pathname: { $bind: { from: "$root.pathname" } }
|
|
27140
|
+
})
|
|
27141
|
+
], { gap: "lg" })
|
|
27142
|
+
})]
|
|
27143
|
+
}),
|
|
27144
|
+
dataSchemas: { services: z.unknown().optional() },
|
|
27145
|
+
dataLoaders: { services: {
|
|
27146
|
+
endpoint: "getPublicBookingServices",
|
|
27147
|
+
params: { siteId: { $bind: { from: "$root.siteId" } } },
|
|
27148
|
+
mode: "server"
|
|
27149
|
+
} }
|
|
27150
|
+
};
|
|
26545
27151
|
//#endregion
|
|
26546
27152
|
//#region ../blocks/src/system/blocks/weekly-slot-availability.ts
|
|
26547
27153
|
const weeklySlotAvailabilityManifest = createBlockManifest({
|
|
@@ -27780,8 +28386,8 @@ z.object({
|
|
|
27780
28386
|
previewToken: z.string().nullable().optional(),
|
|
27781
28387
|
stage: previewStageSchema.optional()
|
|
27782
28388
|
});
|
|
27783
|
-
function
|
|
27784
|
-
const selectedRun = resolveSelectedWholeSeriesRun(
|
|
28389
|
+
function buildEventRegistrationDisplayFromScopedEvents(source, scopedSourceEvents) {
|
|
28390
|
+
const selectedRun = resolveSelectedWholeSeriesRun(scopedSourceEvents);
|
|
27785
28391
|
if (selectedRun && (!selectedRun.run.enrollmentOpen || toWholeSeriesRegistrationEvent(selectedRun) === null)) return {
|
|
27786
28392
|
kind: "event-registration",
|
|
27787
28393
|
state: "registration-closed",
|
|
@@ -27789,7 +28395,7 @@ function buildEventRegistrationDisplay(source) {
|
|
|
27789
28395
|
titleText: "Registration closed",
|
|
27790
28396
|
bodyText: "This run is no longer open for bookings."
|
|
27791
28397
|
};
|
|
27792
|
-
const stepLabels = buildEventRegistrationShellStepLabels(source);
|
|
28398
|
+
const stepLabels = buildEventRegistrationShellStepLabels(source, scopedSourceEvents);
|
|
27793
28399
|
return {
|
|
27794
28400
|
kind: "event-registration",
|
|
27795
28401
|
state: "generic-shell",
|
|
@@ -27800,8 +28406,8 @@ function buildEventRegistrationDisplay(source) {
|
|
|
27800
28406
|
summaryButtonText: source.buttonText?.trim() || "Register"
|
|
27801
28407
|
};
|
|
27802
28408
|
}
|
|
27803
|
-
function buildEventRegistrationShellStepLabels(source) {
|
|
27804
|
-
const selectedRun = resolveSelectedWholeSeriesRun(
|
|
28409
|
+
function buildEventRegistrationShellStepLabels(source, scopedSourceEvents) {
|
|
28410
|
+
const selectedRun = resolveSelectedWholeSeriesRun(scopedSourceEvents);
|
|
27805
28411
|
if (selectedRun) {
|
|
27806
28412
|
const selectedEvent = toWholeSeriesRegistrationEvent(selectedRun);
|
|
27807
28413
|
if (!selectedEvent) return EVENT_REGISTRATION_GENERIC_SHELL_STEP_LABELS;
|
|
@@ -27811,7 +28417,7 @@ function buildEventRegistrationShellStepLabels(source) {
|
|
|
27811
28417
|
event: selectedEvent
|
|
27812
28418
|
})).map((step) => shellLabelForRegistrationStep(step, [selectedEvent]));
|
|
27813
28419
|
}
|
|
27814
|
-
const scopedEvents =
|
|
28420
|
+
const scopedEvents = toScopedEventRegistrationEvents(scopedSourceEvents);
|
|
27815
28421
|
if (scopedEvents.length === 0) return EVENT_REGISTRATION_GENERIC_SHELL_STEP_LABELS;
|
|
27816
28422
|
const preSelectedEvent = findPreSelectedEvent({
|
|
27817
28423
|
scopedEvents,
|
|
@@ -27824,31 +28430,25 @@ function buildEventRegistrationShellStepLabels(source) {
|
|
|
27824
28430
|
event: preSelectedEvent
|
|
27825
28431
|
}) : false).map((step) => shellLabelForRegistrationStep(step, scopedEvents));
|
|
27826
28432
|
}
|
|
27827
|
-
function
|
|
27828
|
-
|
|
27829
|
-
return [...toRegistrationEvents(scoped), ...toWholeSeriesRegistrationEvents(scoped)];
|
|
28433
|
+
function toScopedEventRegistrationEvents(scopedSourceEvents) {
|
|
28434
|
+
return [...toRegistrationEvents(scopedSourceEvents), ...toWholeSeriesRegistrationEvents(scopedSourceEvents)];
|
|
27830
28435
|
}
|
|
27831
|
-
/**
|
|
27832
|
-
* Every event this surface may register for, from both of its loads.
|
|
27833
|
-
*
|
|
27834
|
-
* The date page and the run read answer different questions and can name the
|
|
27835
|
-
* same occurrence, so the two lists are joined and any occurrence that arrives
|
|
27836
|
-
* twice is kept once, in the order the date page gave it.
|
|
27837
|
-
*/
|
|
27838
28436
|
function scopeEventRegistrationSourceEvents(source) {
|
|
27839
|
-
|
|
27840
|
-
for (const event of [...source.events ?? [], ...source.wholeSeriesRunEvents ?? []]) if (!byOccurrenceId.has(event.occurrenceId)) byOccurrenceId.set(event.occurrenceId, event);
|
|
27841
|
-
return resolveEventRegistrationScopedEvents([...byOccurrenceId.values()], {
|
|
28437
|
+
return resolveEventRegistrationScopedEvents(source.wholeSeriesRunEvents ?? source.events ?? [], {
|
|
27842
28438
|
occurrenceContext: source.occurrenceContext,
|
|
27843
28439
|
subject: source.subject
|
|
27844
28440
|
});
|
|
27845
28441
|
}
|
|
28442
|
+
function resolveLoadedEventRegistrationSourceEvents(source, scopedSourceEvents) {
|
|
28443
|
+
if (source.events == null && source.wholeSeriesRunEvents == null) return null;
|
|
28444
|
+
return [...scopedSourceEvents];
|
|
28445
|
+
}
|
|
27846
28446
|
/**
|
|
27847
28447
|
* The one run this surface is registering for, when the scoped events describe
|
|
27848
28448
|
* exactly one. More than one run means the visitor still has to choose.
|
|
27849
28449
|
*/
|
|
27850
|
-
function resolveSelectedWholeSeriesRun(
|
|
27851
|
-
const runs = groupPublicEventsByRun(
|
|
28450
|
+
function resolveSelectedWholeSeriesRun(scopedSourceEvents) {
|
|
28451
|
+
const runs = groupPublicEventsByRun(scopedSourceEvents);
|
|
27852
28452
|
return runs.length === 1 ? runs[0] : null;
|
|
27853
28453
|
}
|
|
27854
28454
|
function shellLabelForRegistrationStep(step, events) {
|
|
@@ -27882,9 +28482,10 @@ const eventRegistrationBlockRuntime = defineClientOwnedBlockRuntime({
|
|
|
27882
28482
|
render: createZodCodec(eventRegistrationRenderSchema)
|
|
27883
28483
|
},
|
|
27884
28484
|
buildRender: (source) => {
|
|
27885
|
-
const
|
|
28485
|
+
const scopedSourceEvents = scopeEventRegistrationSourceEvents(source);
|
|
28486
|
+
const events = resolveLoadedEventRegistrationSourceEvents(source, scopedSourceEvents);
|
|
27886
28487
|
return {
|
|
27887
|
-
display:
|
|
28488
|
+
display: buildEventRegistrationDisplayFromScopedEvents(source, scopedSourceEvents),
|
|
27888
28489
|
hydration: {
|
|
27889
28490
|
occurrenceContext: source.occurrenceContext ?? null,
|
|
27890
28491
|
subject: source.subject ?? null,
|
|
@@ -28085,6 +28686,11 @@ const eventRegistrationBlockDefinition = {
|
|
|
28085
28686
|
dataLoaders: {
|
|
28086
28687
|
events: {
|
|
28087
28688
|
endpoint: "listPublicEvents",
|
|
28689
|
+
when: { $bind: {
|
|
28690
|
+
from: "$root.subject.isWholeSeriesBooking",
|
|
28691
|
+
fallback: true,
|
|
28692
|
+
transforms: [{ id: "boolean.not" }]
|
|
28693
|
+
} },
|
|
28088
28694
|
params: {
|
|
28089
28695
|
siteId: { $bind: { from: "$root.siteId" } },
|
|
28090
28696
|
limit: "50",
|
|
@@ -28106,13 +28712,9 @@ const eventRegistrationBlockDefinition = {
|
|
|
28106
28712
|
/**
|
|
28107
28713
|
* The runs this page can register for, finished ones included.
|
|
28108
28714
|
*
|
|
28109
|
-
*
|
|
28110
|
-
*
|
|
28111
|
-
* render
|
|
28112
|
-
* subject books whole runs. It is scoped exactly like the date page — same
|
|
28113
|
-
* series, same run subroute — because scope and grain are separate
|
|
28114
|
-
* questions. The two lists are joined by occurrence, so a run that appears
|
|
28115
|
-
* in both is still one run.
|
|
28715
|
+
* A run read is the sole Event source on a whole-series surface. It is
|
|
28716
|
+
* status-bounded rather than date-bounded, so completed runs can still
|
|
28717
|
+
* render their closed state and every run carries its complete schedule.
|
|
28116
28718
|
*/
|
|
28117
28719
|
wholeSeriesRunEvents: {
|
|
28118
28720
|
endpoint: "listPublicEvents",
|
|
@@ -30705,20 +31307,7 @@ function isRecord$2(value) {
|
|
|
30705
31307
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
30706
31308
|
}
|
|
30707
31309
|
//#endregion
|
|
30708
|
-
//#region ../blocks/src/system/blocks/offerings-preview/
|
|
30709
|
-
/**
|
|
30710
|
-
* The whole-series presets, as the CSV `listPublicEvents` expects. Both
|
|
30711
|
-
* whole-series presets share one loader: the block renders them as a single
|
|
30712
|
-
* run group.
|
|
30713
|
-
*/
|
|
30714
|
-
const WHOLE_SERIES_EVENT_PRESETS_PARAM = WHOLE_SERIES_EVENT_PRESET_VALUES.join(",");
|
|
30715
|
-
const publicRouteCandidatesSchema = z.object({ routes: z.array(z.object({
|
|
30716
|
-
entityId: z.string(),
|
|
30717
|
-
path: z.string(),
|
|
30718
|
-
title: z.string(),
|
|
30719
|
-
kind: z.enum(RESOLVED_INTERNAL_LINK_ENTITY_TYPES),
|
|
30720
|
-
contentTypeKey: z.string().nullable().optional()
|
|
30721
|
-
})) });
|
|
31310
|
+
//#region ../blocks/src/system/blocks/offerings-preview/fields.ts
|
|
30722
31311
|
const groupOverrideFields = [
|
|
30723
31312
|
{
|
|
30724
31313
|
id: "sourceKey",
|
|
@@ -30924,7 +31513,65 @@ const offeringsPreviewFields = [
|
|
|
30924
31513
|
renderInHeader: false
|
|
30925
31514
|
})
|
|
30926
31515
|
];
|
|
31516
|
+
function labelForOfferingPreviewSourceKey(sourceKey) {
|
|
31517
|
+
const eventDefinition = OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS.find((definition) => definition.sourceKey === sourceKey);
|
|
31518
|
+
if (eventDefinition) return eventDefinition.label;
|
|
31519
|
+
return "Courses";
|
|
31520
|
+
}
|
|
31521
|
+
//#endregion
|
|
31522
|
+
//#region ../blocks/src/system/blocks/offerings-preview/index.ts
|
|
31523
|
+
/**
|
|
31524
|
+
* The whole-series presets, as the CSV `listPublicEvents` expects. Both
|
|
31525
|
+
* whole-series presets share one loader: the block renders them as a single
|
|
31526
|
+
* run group.
|
|
31527
|
+
*/
|
|
31528
|
+
const WHOLE_SERIES_EVENT_PRESETS_PARAM = WHOLE_SERIES_EVENT_PRESET_VALUES.join(",");
|
|
31529
|
+
const publicRouteCandidatesSchema = z.object({ routes: z.array(z.object({
|
|
31530
|
+
entityId: z.string(),
|
|
31531
|
+
path: z.string(),
|
|
31532
|
+
title: z.string(),
|
|
31533
|
+
kind: z.enum(RESOLVED_INTERNAL_LINK_ENTITY_TYPES),
|
|
31534
|
+
contentTypeKey: z.string().nullable().optional()
|
|
31535
|
+
})) });
|
|
30927
31536
|
const offeringsPreviewEventDataBindings = Object.fromEntries(OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS.map((definition) => [definition.dataKey, { $bind: { from: `data.${definition.dataKey}` } }]));
|
|
31537
|
+
const DEFAULT_OFFERINGS_PREVIEW_DISPLAY_MODE = "preview";
|
|
31538
|
+
const displayModeBinding = {
|
|
31539
|
+
from: "content.displayMode",
|
|
31540
|
+
fallback: DEFAULT_OFFERINGS_PREVIEW_DISPLAY_MODE
|
|
31541
|
+
};
|
|
31542
|
+
const catalogueMode = { $bind: {
|
|
31543
|
+
...displayModeBinding,
|
|
31544
|
+
transforms: [{
|
|
31545
|
+
id: "value.equals",
|
|
31546
|
+
options: { value: "catalogue" }
|
|
31547
|
+
}]
|
|
31548
|
+
} };
|
|
31549
|
+
const previewMode = { $bind: {
|
|
31550
|
+
...displayModeBinding,
|
|
31551
|
+
transforms: [{
|
|
31552
|
+
id: "value.equals",
|
|
31553
|
+
options: { value: "preview" }
|
|
31554
|
+
}]
|
|
31555
|
+
} };
|
|
31556
|
+
function offeringsPreviewHeaderNodes() {
|
|
31557
|
+
return [text({
|
|
31558
|
+
as: "h2",
|
|
31559
|
+
className: { $bind: {
|
|
31560
|
+
from: "content.displayMode",
|
|
31561
|
+
fallback: "rb-text-center",
|
|
31562
|
+
transforms: [{
|
|
31563
|
+
id: "value.equals",
|
|
31564
|
+
options: { value: "catalogue" }
|
|
31565
|
+
}, {
|
|
31566
|
+
id: "ui.conditionalClass",
|
|
31567
|
+
options: {
|
|
31568
|
+
whenTrue: "rb-text-left",
|
|
31569
|
+
whenFalse: "rb-text-center"
|
|
31570
|
+
}
|
|
31571
|
+
}]
|
|
31572
|
+
} }
|
|
31573
|
+
}, bind("content.heading"), when("content.heading")), richText({ className: "rb-prose rb-max-w-none" }, bind("content.description"), when("content.description"))];
|
|
31574
|
+
}
|
|
30928
31575
|
const offeringsPreviewManifest = createBlockManifest({
|
|
30929
31576
|
id: "block.offerings-preview",
|
|
30930
31577
|
version: "1.0.0",
|
|
@@ -30955,48 +31602,45 @@ const offeringsPreviewManifest = createBlockManifest({
|
|
|
30955
31602
|
],
|
|
30956
31603
|
icon: "PanelsTopLeft",
|
|
30957
31604
|
layout: [styledSection({
|
|
30958
|
-
children: sectionContainer([
|
|
30959
|
-
|
|
30960
|
-
|
|
30961
|
-
|
|
30962
|
-
|
|
30963
|
-
|
|
30964
|
-
|
|
30965
|
-
|
|
30966
|
-
|
|
30967
|
-
|
|
30968
|
-
|
|
30969
|
-
|
|
30970
|
-
|
|
30971
|
-
|
|
30972
|
-
|
|
30973
|
-
|
|
30974
|
-
|
|
30975
|
-
|
|
30976
|
-
|
|
30977
|
-
|
|
30978
|
-
|
|
30979
|
-
|
|
30980
|
-
|
|
30981
|
-
|
|
30982
|
-
|
|
30983
|
-
|
|
30984
|
-
|
|
30985
|
-
|
|
30986
|
-
|
|
30987
|
-
|
|
30988
|
-
|
|
30989
|
-
|
|
30990
|
-
|
|
30991
|
-
|
|
30992
|
-
|
|
30993
|
-
|
|
30994
|
-
|
|
30995
|
-
|
|
30996
|
-
|
|
30997
|
-
...offeringsPreviewEventDataBindings
|
|
30998
|
-
})
|
|
30999
|
-
], { gap: "lg" }),
|
|
31605
|
+
children: sectionContainer([el("offerings-preview", {
|
|
31606
|
+
displayMode: { $bind: displayModeBinding },
|
|
31607
|
+
pathname: { $bind: { from: "$root.pathname" } },
|
|
31608
|
+
catalogueEvents: { $bind: { from: "data.catalogueEvents" } },
|
|
31609
|
+
quickDateEvents: { $bind: { from: "data.quickDateEvents" } },
|
|
31610
|
+
bookingOfferingPresets: { $bind: {
|
|
31611
|
+
from: "$root.bookingOfferingPresets",
|
|
31612
|
+
fallback: []
|
|
31613
|
+
} },
|
|
31614
|
+
groupOverrides: { $bind: {
|
|
31615
|
+
from: "content.groupOverrides",
|
|
31616
|
+
fallback: []
|
|
31617
|
+
} },
|
|
31618
|
+
groupOrder: { $bind: { from: "content.groupOrder" } },
|
|
31619
|
+
cardStyles: { $bind: { from: "content._cardStyles" } },
|
|
31620
|
+
itemLimit: { $bind: {
|
|
31621
|
+
from: "content.itemLimit",
|
|
31622
|
+
fallback: "3"
|
|
31623
|
+
} },
|
|
31624
|
+
buttonVariant: { $bind: {
|
|
31625
|
+
from: "content.buttonVariant",
|
|
31626
|
+
fallback: "primary"
|
|
31627
|
+
} },
|
|
31628
|
+
buttonText: { $bind: {
|
|
31629
|
+
from: "content.buttonText",
|
|
31630
|
+
fallback: OFFERINGS_PREVIEW_DEFAULT_BUTTON_TEXT
|
|
31631
|
+
} },
|
|
31632
|
+
emptyMessage: { $bind: {
|
|
31633
|
+
from: "content.emptyMessage",
|
|
31634
|
+
fallback: OFFERINGS_PREVIEW_DEFAULT_EMPTY_MESSAGE
|
|
31635
|
+
} },
|
|
31636
|
+
previewStage: { $bind: {
|
|
31637
|
+
from: "$root.previewStage",
|
|
31638
|
+
fallback: "published"
|
|
31639
|
+
} },
|
|
31640
|
+
routeCandidates: { $bind: { from: "data.routeCandidates" } },
|
|
31641
|
+
wholeSeriesRunEvents: { $bind: { from: "data.wholeSeriesRunEvents" } },
|
|
31642
|
+
...offeringsPreviewEventDataBindings
|
|
31643
|
+
}, offeringsPreviewHeaderNodes())], { gap: "lg" }),
|
|
31000
31644
|
baseClass: "",
|
|
31001
31645
|
spacing: "comfortable"
|
|
31002
31646
|
})]
|
|
@@ -31010,16 +31654,48 @@ const offeringsPreviewBlockDefinition = {
|
|
|
31010
31654
|
dataSchemas: {
|
|
31011
31655
|
...offeringsPreviewEventDataSchemas,
|
|
31012
31656
|
routeCandidates: publicRouteCandidatesSchema.optional(),
|
|
31013
|
-
wholeSeriesRunEvents: optionalPublicEventsArraySchema
|
|
31657
|
+
wholeSeriesRunEvents: optionalPublicEventsArraySchema,
|
|
31658
|
+
catalogueEvents: optionalPublicEventsArraySchema,
|
|
31659
|
+
quickDateEvents: optionalPublicEventsArraySchema
|
|
31014
31660
|
},
|
|
31015
31661
|
dataLoaders: {
|
|
31016
31662
|
...offeringsPreviewEventDataLoaders,
|
|
31017
31663
|
routeCandidates: {
|
|
31018
31664
|
endpoint: "listPublicRouteCandidates",
|
|
31665
|
+
when: previewMode,
|
|
31019
31666
|
params: {},
|
|
31020
31667
|
mode: "server"
|
|
31021
31668
|
},
|
|
31022
|
-
wholeSeriesRunEvents: wholeSeriesRunLoader()
|
|
31669
|
+
wholeSeriesRunEvents: wholeSeriesRunLoader(),
|
|
31670
|
+
catalogueEvents: {
|
|
31671
|
+
endpoint: "listPublicEvents",
|
|
31672
|
+
when: catalogueMode,
|
|
31673
|
+
params: {
|
|
31674
|
+
stage: { $bind: {
|
|
31675
|
+
from: "$root.previewStage",
|
|
31676
|
+
fallback: "published"
|
|
31677
|
+
} },
|
|
31678
|
+
detailLevel: "listing",
|
|
31679
|
+
readProfile: "listing-card",
|
|
31680
|
+
readIntent: "catalogue"
|
|
31681
|
+
},
|
|
31682
|
+
mode: "server"
|
|
31683
|
+
},
|
|
31684
|
+
quickDateEvents: {
|
|
31685
|
+
endpoint: "listPublicEvents",
|
|
31686
|
+
when: catalogueMode,
|
|
31687
|
+
params: {
|
|
31688
|
+
stage: { $bind: {
|
|
31689
|
+
from: "$root.previewStage",
|
|
31690
|
+
fallback: "published"
|
|
31691
|
+
} },
|
|
31692
|
+
detailLevel: "listing",
|
|
31693
|
+
readProfile: "listing-card",
|
|
31694
|
+
readIntent: "occurrences",
|
|
31695
|
+
limit: 40
|
|
31696
|
+
},
|
|
31697
|
+
mode: "server"
|
|
31698
|
+
}
|
|
31023
31699
|
}
|
|
31024
31700
|
};
|
|
31025
31701
|
/**
|
|
@@ -31036,6 +31712,7 @@ function wholeSeriesRunLoader() {
|
|
|
31036
31712
|
function eventPresetLoader(eventPresets, extraParams = {}) {
|
|
31037
31713
|
return {
|
|
31038
31714
|
endpoint: "listPublicEvents",
|
|
31715
|
+
when: previewMode,
|
|
31039
31716
|
params: {
|
|
31040
31717
|
siteId: { $bind: { from: "$root.siteId" } },
|
|
31041
31718
|
limit: { $bind: {
|
|
@@ -31054,15 +31731,10 @@ function eventPresetLoader(eventPresets, extraParams = {}) {
|
|
|
31054
31731
|
mode: "server"
|
|
31055
31732
|
};
|
|
31056
31733
|
}
|
|
31057
|
-
function labelForOfferingPreviewSourceKey(sourceKey) {
|
|
31058
|
-
const eventDefinition = OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS.find((definition) => definition.sourceKey === sourceKey);
|
|
31059
|
-
if (eventDefinition) return eventDefinition.label;
|
|
31060
|
-
return "Courses";
|
|
31061
|
-
}
|
|
31062
31734
|
function normalizeOfferingsPreviewBlockContent(value) {
|
|
31063
31735
|
const record = normalizeOfferingsPreviewContentForWrite(value);
|
|
31064
|
-
if (!record) return {};
|
|
31065
|
-
const normalized = {};
|
|
31736
|
+
if (!record) return { displayMode: DEFAULT_OFFERINGS_PREVIEW_DISPLAY_MODE };
|
|
31737
|
+
const normalized = { displayMode: normalizeOfferingsPreviewDisplayMode(record.displayMode) };
|
|
31066
31738
|
if (typeof record.heading === "string" || record.heading === null) normalized.heading = record.heading;
|
|
31067
31739
|
if ("description" in record) normalized.description = record.description;
|
|
31068
31740
|
if (isOfferingsPreviewItemLimit(record.itemLimit)) normalized.itemLimit = record.itemLimit;
|
|
@@ -31079,6 +31751,9 @@ function normalizeOfferingsPreviewBlockContent(value) {
|
|
|
31079
31751
|
if (sectionStyles !== void 0) normalized._sectionStyles = sectionStyles;
|
|
31080
31752
|
return normalized;
|
|
31081
31753
|
}
|
|
31754
|
+
function normalizeOfferingsPreviewDisplayMode(value) {
|
|
31755
|
+
return value === "catalogue" ? "catalogue" : DEFAULT_OFFERINGS_PREVIEW_DISPLAY_MODE;
|
|
31756
|
+
}
|
|
31082
31757
|
function isOfferingsPreviewItemLimit(value) {
|
|
31083
31758
|
return value === "1" || value === "2" || value === "3" || value === "4" || value === "5" || value === "6" || value === null;
|
|
31084
31759
|
}
|
|
@@ -34293,63 +34968,13 @@ const giftingBlockDefinition = {
|
|
|
34293
34968
|
} }
|
|
34294
34969
|
};
|
|
34295
34970
|
//#endregion
|
|
34296
|
-
//#region ../blocks/src/system/blocks/newsletter-signup-destination.ts
|
|
34297
|
-
function parseNewsletterSignupBlockId(value) {
|
|
34298
|
-
const trimmed = parseTrimmedString(value);
|
|
34299
|
-
return trimmed && BLOCK_ID_PATTERN.test(trimmed) ? trimmed : null;
|
|
34300
|
-
}
|
|
34301
|
-
function parseSignedNewsletterDestinationRef(value) {
|
|
34302
|
-
const trimmed = parseTrimmedString(value);
|
|
34303
|
-
return trimmed && SIGNED_DESTINATION_REF_PATTERN.test(trimmed) ? trimmed : null;
|
|
34304
|
-
}
|
|
34305
|
-
function buildNewsletterSignupBlockRef(blockId) {
|
|
34306
|
-
const parsed = parseNewsletterSignupBlockId(blockId);
|
|
34307
|
-
return parsed ? {
|
|
34308
|
-
tag: "block_ref",
|
|
34309
|
-
blockId: parsed
|
|
34310
|
-
} : null;
|
|
34311
|
-
}
|
|
34312
|
-
function normalizeNewsletterSignupEditorValuesForDestination(values) {
|
|
34313
|
-
const destinationProvider = parseNewsletterSignupDestinationProvider(values.destinationProvider) ?? "riverbank";
|
|
34314
|
-
if (destinationProvider === "mailchimp") return {
|
|
34315
|
-
destinationProvider,
|
|
34316
|
-
mailchimpAudienceId: values.mailchimpAudienceId,
|
|
34317
|
-
mailchimpTags: values.mailchimpTags
|
|
34318
|
-
};
|
|
34319
|
-
return {
|
|
34320
|
-
destinationProvider,
|
|
34321
|
-
listId: values.listId,
|
|
34322
|
-
tags: values.tags
|
|
34323
|
-
};
|
|
34324
|
-
}
|
|
34325
|
-
function deriveNewsletterSignupRuntimeSource(values) {
|
|
34326
|
-
const normalized = normalizeNewsletterSignupEditorValuesForDestination(values);
|
|
34327
|
-
if (normalized.destinationProvider === "mailchimp") return {
|
|
34328
|
-
destinationProvider: "mailchimp",
|
|
34329
|
-
listId: null,
|
|
34330
|
-
tags: null
|
|
34331
|
-
};
|
|
34332
|
-
return {
|
|
34333
|
-
destinationProvider: "riverbank",
|
|
34334
|
-
listId: parseTrimmedString(normalized.listId),
|
|
34335
|
-
tags: parseTrimmedString(normalized.tags)
|
|
34336
|
-
};
|
|
34337
|
-
}
|
|
34338
|
-
const BLOCK_ID_PATTERN = /^[A-Za-z0-9._:-]{1,200}$/;
|
|
34339
|
-
const SIGNED_DESTINATION_REF_PATTERN = /^[A-Za-z0-9._~-]{16,1000}$/;
|
|
34340
|
-
function parseTrimmedString(value) {
|
|
34341
|
-
if (typeof value !== "string") return null;
|
|
34342
|
-
const trimmed = value.trim();
|
|
34343
|
-
return trimmed.length > 0 ? trimmed : null;
|
|
34344
|
-
}
|
|
34345
|
-
//#endregion
|
|
34346
34971
|
//#region ../blocks/src/system/runtime/nodes/newsletter-form.types.ts
|
|
34347
34972
|
/**
|
|
34348
34973
|
* Get form fields based on preset configuration.
|
|
34349
34974
|
*/
|
|
34350
|
-
function
|
|
34351
|
-
const includePhone =
|
|
34352
|
-
switch (preset) {
|
|
34975
|
+
function getGlobalFormFields(form) {
|
|
34976
|
+
const includePhone = form.includeOptionalPhone;
|
|
34977
|
+
switch (form.fields.preset) {
|
|
34353
34978
|
case "emailOnly": return withOptionalPhone([{
|
|
34354
34979
|
id: "email",
|
|
34355
34980
|
type: "email",
|
|
@@ -34367,7 +34992,7 @@ function getPresetFields(preset, options) {
|
|
|
34367
34992
|
id: "name",
|
|
34368
34993
|
type: "text",
|
|
34369
34994
|
label: "Name",
|
|
34370
|
-
required:
|
|
34995
|
+
required: form.fields.name === "required",
|
|
34371
34996
|
placeholder: "Your name"
|
|
34372
34997
|
}], includePhone);
|
|
34373
34998
|
case "emailFirstLast": return withOptionalPhone([
|
|
@@ -34382,14 +35007,14 @@ function getPresetFields(preset, options) {
|
|
|
34382
35007
|
id: "firstName",
|
|
34383
35008
|
type: "text",
|
|
34384
35009
|
label: "First Name",
|
|
34385
|
-
required:
|
|
35010
|
+
required: form.fields.firstName === "required",
|
|
34386
35011
|
placeholder: "First name"
|
|
34387
35012
|
},
|
|
34388
35013
|
{
|
|
34389
35014
|
id: "lastName",
|
|
34390
35015
|
type: "text",
|
|
34391
35016
|
label: "Last Name",
|
|
34392
|
-
required:
|
|
35017
|
+
required: form.fields.lastName === "required",
|
|
34393
35018
|
placeholder: "Last name"
|
|
34394
35019
|
}
|
|
34395
35020
|
], includePhone);
|
|
@@ -34405,14 +35030,14 @@ function getPresetFields(preset, options) {
|
|
|
34405
35030
|
id: "name",
|
|
34406
35031
|
type: "text",
|
|
34407
35032
|
label: "Name",
|
|
34408
|
-
required:
|
|
35033
|
+
required: form.fields.name === "required",
|
|
34409
35034
|
placeholder: "Your name"
|
|
34410
35035
|
},
|
|
34411
35036
|
{
|
|
34412
35037
|
id: "company",
|
|
34413
35038
|
type: "text",
|
|
34414
35039
|
label: "Company",
|
|
34415
|
-
required:
|
|
35040
|
+
required: form.fields.company === "required",
|
|
34416
35041
|
placeholder: "Company name"
|
|
34417
35042
|
}
|
|
34418
35043
|
], includePhone);
|
|
@@ -34431,14 +35056,29 @@ function withOptionalPhone(fields, includePhone) {
|
|
|
34431
35056
|
}
|
|
34432
35057
|
//#endregion
|
|
34433
35058
|
//#region ../blocks/src/system/runtime/nodes/newsletter-form.interactive.ts
|
|
34434
|
-
const newsletterPresetSchema = z.enum([
|
|
34435
|
-
"emailOnly",
|
|
34436
|
-
"emailName",
|
|
34437
|
-
"emailFirstLast",
|
|
34438
|
-
"emailNameCompany"
|
|
34439
|
-
]);
|
|
34440
|
-
const newsletterDestinationProviderSchema = z.enum(["riverbank", "mailchimp"]);
|
|
34441
35059
|
const newsletterButtonVariantSchema = blockButtonRoleSchema;
|
|
35060
|
+
const mailingListContextSchema = z.unknown().transform((value, ctx) => {
|
|
35061
|
+
const parsed = parseMailingListRuntimeContext(value);
|
|
35062
|
+
if (!parsed.ok) {
|
|
35063
|
+
ctx.addIssue({
|
|
35064
|
+
code: z.ZodIssueCode.custom,
|
|
35065
|
+
message: "Invalid mailing-list runtime context"
|
|
35066
|
+
});
|
|
35067
|
+
return z.NEVER;
|
|
35068
|
+
}
|
|
35069
|
+
return parsed.value;
|
|
35070
|
+
});
|
|
35071
|
+
const mailingListTargetingSchema = z.unknown().transform((value, ctx) => {
|
|
35072
|
+
const parsed = parseMailingListPlacementTargeting(value);
|
|
35073
|
+
if (!parsed.ok) {
|
|
35074
|
+
ctx.addIssue({
|
|
35075
|
+
code: z.ZodIssueCode.custom,
|
|
35076
|
+
message: "Invalid mailing-list targeting"
|
|
35077
|
+
});
|
|
35078
|
+
return z.NEVER;
|
|
35079
|
+
}
|
|
35080
|
+
return parsed.value;
|
|
35081
|
+
});
|
|
34442
35082
|
const newsletterFieldSchema = z.object({
|
|
34443
35083
|
id: z.string(),
|
|
34444
35084
|
type: z.enum(["email", "text"]),
|
|
@@ -34446,73 +35086,73 @@ const newsletterFieldSchema = z.object({
|
|
|
34446
35086
|
required: z.boolean(),
|
|
34447
35087
|
placeholder: z.string().optional()
|
|
34448
35088
|
});
|
|
34449
|
-
const
|
|
34450
|
-
const
|
|
35089
|
+
const mailingListSignupBlockIdSchema = z.string().trim().min(1).transform(parseRequiredMailingListSignupBlockId);
|
|
35090
|
+
const signedMailingListSourceTokenSchema = z.string().trim().min(1).transform(parseRequiredMailingListSignedSourceToken);
|
|
34451
35091
|
const newsletterSourceCommonSchema = z.object({
|
|
34452
35092
|
siteId: z.string().optional(),
|
|
34453
35093
|
apiBaseUrl: z.string().optional(),
|
|
34454
|
-
|
|
34455
|
-
|
|
34456
|
-
buttonLabel: z.string().nullable().optional(),
|
|
35094
|
+
mailingList: mailingListContextSchema.optional(),
|
|
35095
|
+
targeting: mailingListTargetingSchema.optional(),
|
|
34457
35096
|
buttonVariant: newsletterButtonVariantSchema.nullable().optional(),
|
|
34458
|
-
successMessage: z.string().nullable().optional(),
|
|
34459
|
-
privacyNote: z.string().nullable().optional(),
|
|
34460
|
-
tags: z.string().nullable().optional(),
|
|
34461
35097
|
spamProtectionEnabled: z.boolean().optional(),
|
|
34462
35098
|
className: z.string().nullable().optional()
|
|
34463
35099
|
});
|
|
34464
35100
|
const newsletterSourceSchema = z.discriminatedUnion("source", [
|
|
34465
35101
|
newsletterSourceCommonSchema.extend({
|
|
34466
35102
|
source: z.literal("block"),
|
|
34467
|
-
blockId: z.string().nullable().optional()
|
|
34468
|
-
listId: z.string().nullable().optional(),
|
|
34469
|
-
destinationProvider: newsletterDestinationProviderSchema.nullable().optional()
|
|
35103
|
+
blockId: z.string().nullable().optional()
|
|
34470
35104
|
}),
|
|
34471
35105
|
newsletterSourceCommonSchema.extend({
|
|
34472
35106
|
source: z.literal("signed-footer"),
|
|
34473
|
-
|
|
34474
|
-
tag: z.literal("
|
|
34475
|
-
token:
|
|
35107
|
+
sourceRef: z.object({
|
|
35108
|
+
tag: z.literal("signed_source_ref"),
|
|
35109
|
+
token: signedMailingListSourceTokenSchema
|
|
34476
35110
|
})
|
|
34477
35111
|
}),
|
|
34478
|
-
newsletterSourceCommonSchema.extend({
|
|
34479
|
-
source: z.literal("legacy-direct-list"),
|
|
34480
|
-
listId: z.string().nullable()
|
|
34481
|
-
})
|
|
35112
|
+
newsletterSourceCommonSchema.extend({ source: z.literal("preview") })
|
|
34482
35113
|
]);
|
|
34483
35114
|
const newsletterDisplaySchema = z.object({
|
|
34484
35115
|
kind: z.literal("newsletter-form"),
|
|
35116
|
+
availability: z.enum(["ready", "unavailable"]),
|
|
34485
35117
|
className: z.string().nullable(),
|
|
34486
35118
|
buttonLabel: z.string(),
|
|
34487
35119
|
buttonVariant: newsletterButtonVariantSchema,
|
|
34488
|
-
successMessage: z.string().nullable(),
|
|
34489
35120
|
privacyNote: z.string().nullable(),
|
|
34490
|
-
fields: z.array(newsletterFieldSchema)
|
|
35121
|
+
fields: z.array(newsletterFieldSchema),
|
|
35122
|
+
choices: z.array(z.object({
|
|
35123
|
+
id: z.string(),
|
|
35124
|
+
label: z.string()
|
|
35125
|
+
}))
|
|
34491
35126
|
});
|
|
34492
35127
|
const newsletterHydrationSchema = z.object({
|
|
34493
35128
|
target: z.discriminatedUnion("tag", [
|
|
34494
35129
|
z.object({
|
|
34495
35130
|
tag: z.literal("block-source"),
|
|
34496
|
-
|
|
35131
|
+
sourceRef: z.object({
|
|
34497
35132
|
tag: z.literal("block_ref"),
|
|
34498
|
-
blockId:
|
|
35133
|
+
blockId: mailingListSignupBlockIdSchema
|
|
34499
35134
|
}).nullable()
|
|
34500
35135
|
}),
|
|
34501
35136
|
z.object({
|
|
34502
35137
|
tag: z.literal("signed-footer-source"),
|
|
34503
|
-
|
|
34504
|
-
tag: z.literal("
|
|
34505
|
-
token:
|
|
35138
|
+
sourceRef: z.object({
|
|
35139
|
+
tag: z.literal("signed_source_ref"),
|
|
35140
|
+
token: signedMailingListSourceTokenSchema
|
|
34506
35141
|
})
|
|
34507
35142
|
}),
|
|
34508
|
-
z.object({
|
|
34509
|
-
|
|
34510
|
-
|
|
34511
|
-
|
|
35143
|
+
z.object({ tag: z.literal("preview") })
|
|
35144
|
+
]),
|
|
35145
|
+
setupRevision: z.number().int().positive().nullable(),
|
|
35146
|
+
choiceProvider: z.enum([
|
|
35147
|
+
"native",
|
|
35148
|
+
"brevo",
|
|
35149
|
+
"mailchimp"
|
|
35150
|
+
]).nullable(),
|
|
35151
|
+
choicePresentation: z.enum([
|
|
35152
|
+
"hidden",
|
|
35153
|
+
"automatic",
|
|
35154
|
+
"visitor_choice"
|
|
34512
35155
|
]),
|
|
34513
|
-
preset: newsletterPresetSchema,
|
|
34514
|
-
includePhone: z.boolean(),
|
|
34515
|
-
tags: z.string().nullable().optional(),
|
|
34516
35156
|
spamProtectionEnabled: z.boolean().optional()
|
|
34517
35157
|
});
|
|
34518
35158
|
const newsletterRenderSchema = z.object({
|
|
@@ -34524,16 +35164,24 @@ z.object({
|
|
|
34524
35164
|
apiBaseUrl: z.string().optional()
|
|
34525
35165
|
});
|
|
34526
35166
|
function buildNewsletterDisplay(source) {
|
|
34527
|
-
const
|
|
34528
|
-
const
|
|
35167
|
+
const context = source.mailingList;
|
|
35168
|
+
const form = context?.tag === "configured" ? context.form : {
|
|
35169
|
+
fields: { preset: "emailOnly" },
|
|
35170
|
+
includeOptionalPhone: false,
|
|
35171
|
+
buttonLabel: "Subscribe",
|
|
35172
|
+
privacyNote: null
|
|
35173
|
+
};
|
|
35174
|
+
const targeting = source.targeting ?? { mode: "default" };
|
|
35175
|
+
const choices = resolveRuntimeChoices(context, targeting);
|
|
34529
35176
|
return {
|
|
34530
35177
|
kind: "newsletter-form",
|
|
35178
|
+
availability: runtimeTargetingIsAvailable(context, targeting, choices) ? "ready" : "unavailable",
|
|
34531
35179
|
className: source.className ?? null,
|
|
34532
|
-
buttonLabel:
|
|
35180
|
+
buttonLabel: form.buttonLabel,
|
|
34533
35181
|
buttonVariant: source.buttonVariant ?? "primary",
|
|
34534
|
-
|
|
34535
|
-
|
|
34536
|
-
|
|
35182
|
+
privacyNote: form.privacyNote,
|
|
35183
|
+
fields: getGlobalFormFields(form),
|
|
35184
|
+
choices
|
|
34537
35185
|
};
|
|
34538
35186
|
}
|
|
34539
35187
|
const newsletterFormBlockRuntime = defineProgressiveBlockRuntime({
|
|
@@ -34543,14 +35191,15 @@ const newsletterFormBlockRuntime = defineProgressiveBlockRuntime({
|
|
|
34543
35191
|
render: createZodCodec(newsletterRenderSchema)
|
|
34544
35192
|
},
|
|
34545
35193
|
buildRender: (source) => {
|
|
34546
|
-
const
|
|
35194
|
+
const targeting = source.targeting ?? { mode: "default" };
|
|
35195
|
+
const presentation = planMailingListChoicePresentation(targeting);
|
|
34547
35196
|
return {
|
|
34548
35197
|
display: buildNewsletterDisplay(source),
|
|
34549
35198
|
hydration: {
|
|
34550
35199
|
target: projectNewsletterFormHydrationTarget(source),
|
|
34551
|
-
|
|
34552
|
-
|
|
34553
|
-
|
|
35200
|
+
setupRevision: source.mailingList?.tag === "configured" ? source.mailingList.revision : null,
|
|
35201
|
+
choiceProvider: targeting.mode === "custom" ? targeting.provider : null,
|
|
35202
|
+
choicePresentation: presentation.tag,
|
|
34554
35203
|
spamProtectionEnabled: source.spamProtectionEnabled
|
|
34555
35204
|
}
|
|
34556
35205
|
};
|
|
@@ -34559,35 +35208,87 @@ const newsletterFormBlockRuntime = defineProgressiveBlockRuntime({
|
|
|
34559
35208
|
function projectNewsletterFormHydrationTarget(source) {
|
|
34560
35209
|
switch (source.source) {
|
|
34561
35210
|
case "block": {
|
|
34562
|
-
const
|
|
34563
|
-
if (
|
|
35211
|
+
const sourceRef = buildMailingListSignupBlockSourceRef(source.blockId);
|
|
35212
|
+
if (sourceRef?.tag === "block_ref") return {
|
|
34564
35213
|
tag: "block-source",
|
|
34565
|
-
|
|
35214
|
+
sourceRef
|
|
34566
35215
|
};
|
|
34567
35216
|
return {
|
|
34568
|
-
tag: "
|
|
34569
|
-
|
|
35217
|
+
tag: "block-source",
|
|
35218
|
+
sourceRef: null
|
|
34570
35219
|
};
|
|
34571
35220
|
}
|
|
34572
35221
|
case "signed-footer": return {
|
|
34573
35222
|
tag: "signed-footer-source",
|
|
34574
|
-
|
|
34575
|
-
};
|
|
34576
|
-
case "legacy-direct-list": return {
|
|
34577
|
-
tag: "legacy-direct-list",
|
|
34578
|
-
listId: source.listId
|
|
35223
|
+
sourceRef: source.sourceRef
|
|
34579
35224
|
};
|
|
35225
|
+
case "preview": return { tag: "preview" };
|
|
34580
35226
|
default: return assertNever$2(source);
|
|
34581
35227
|
}
|
|
34582
35228
|
}
|
|
34583
|
-
function
|
|
34584
|
-
|
|
34585
|
-
|
|
35229
|
+
function resolveRuntimeChoices(context, targeting) {
|
|
35230
|
+
if (context?.tag !== "configured" || targeting.mode !== "custom" || targeting.selection.tag !== "visitor_choice" || context.provider.provider !== targeting.provider) return [];
|
|
35231
|
+
switch (targeting.provider) {
|
|
35232
|
+
case "native": {
|
|
35233
|
+
const offered = new Set(targeting.selection.offeredTopicIds);
|
|
35234
|
+
return context.provider.provider === "native" ? context.provider.topics.filter((item) => offered.has(item.id)).map((item) => ({
|
|
35235
|
+
id: item.id,
|
|
35236
|
+
label: item.name
|
|
35237
|
+
})) : [];
|
|
35238
|
+
}
|
|
35239
|
+
case "brevo": {
|
|
35240
|
+
const offered = new Set(targeting.selection.offeredListIds);
|
|
35241
|
+
return context.provider.provider === "brevo" ? context.provider.lists.filter((item) => offered.has(item.id)).map((item) => ({
|
|
35242
|
+
id: String(item.id),
|
|
35243
|
+
label: item.name
|
|
35244
|
+
})) : [];
|
|
35245
|
+
}
|
|
35246
|
+
case "mailchimp": {
|
|
35247
|
+
const offered = new Set(targeting.selection.offeredInterestIds);
|
|
35248
|
+
return (context.provider.provider === "mailchimp" ? context.provider.audiences.find((item) => item.id === targeting.audienceId) : void 0)?.interests.filter((item) => offered.has(item.id)).map((item) => ({
|
|
35249
|
+
id: item.id,
|
|
35250
|
+
label: item.name
|
|
35251
|
+
})) ?? [];
|
|
35252
|
+
}
|
|
35253
|
+
}
|
|
35254
|
+
}
|
|
35255
|
+
function runtimeTargetingIsAvailable(context, targeting, choices) {
|
|
35256
|
+
if (context?.tag !== "configured") return false;
|
|
35257
|
+
const provider = context.provider;
|
|
35258
|
+
if (targeting.mode === "default") switch (provider.provider) {
|
|
35259
|
+
case "native": return provider.topics.some((item) => item.id === provider.defaultTopicId);
|
|
35260
|
+
case "brevo": return provider.lists.some((item) => item.id === provider.defaultListId);
|
|
35261
|
+
case "mailchimp": return provider.audiences.some((item) => item.id === provider.defaultAudienceId);
|
|
35262
|
+
}
|
|
35263
|
+
if (targeting.provider !== provider.provider) return false;
|
|
35264
|
+
switch (targeting.provider) {
|
|
35265
|
+
case "native": return provider.provider === "native" && nativeTargetIsAvailable(provider, targeting, choices);
|
|
35266
|
+
case "brevo": return provider.provider === "brevo" && brevoTargetIsAvailable(provider, targeting, choices);
|
|
35267
|
+
case "mailchimp": return provider.provider === "mailchimp" && mailchimpTargetIsAvailable(provider, targeting, choices);
|
|
35268
|
+
}
|
|
35269
|
+
}
|
|
35270
|
+
function nativeTargetIsAvailable(provider, targeting, choices) {
|
|
35271
|
+
const ids = targeting.selection.tag === "fixed" ? targeting.selection.topicIds : targeting.selection.offeredTopicIds;
|
|
35272
|
+
return ids.every((id) => provider.topics.some((item) => item.id === id)) && (targeting.selection.tag !== "visitor_choice" || choices.length === ids.length);
|
|
35273
|
+
}
|
|
35274
|
+
function brevoTargetIsAvailable(provider, targeting, choices) {
|
|
35275
|
+
const ids = targeting.selection.tag === "fixed" ? targeting.selection.listIds : targeting.selection.offeredListIds;
|
|
35276
|
+
return ids.every((id) => provider.lists.some((item) => item.id === id)) && (targeting.selection.tag !== "visitor_choice" || choices.length === ids.length);
|
|
35277
|
+
}
|
|
35278
|
+
function mailchimpTargetIsAvailable(provider, targeting, choices) {
|
|
35279
|
+
const audience = provider.audiences.find((item) => item.id === targeting.audienceId);
|
|
35280
|
+
if (!audience) return false;
|
|
35281
|
+
const ids = targeting.selection.tag === "fixed" ? targeting.selection.interestIds : targeting.selection.offeredInterestIds;
|
|
35282
|
+
return ids.every((id) => audience.interests.some((item) => item.id === id)) && (targeting.selection.tag !== "visitor_choice" || choices.length === ids.length);
|
|
35283
|
+
}
|
|
35284
|
+
function parseRequiredMailingListSignupBlockId(value) {
|
|
35285
|
+
const parsed = parseMailingListBlockId(value);
|
|
35286
|
+
if (!parsed) throw new Error("Mailing-list signup block source ref requires blockId");
|
|
34586
35287
|
return parsed;
|
|
34587
35288
|
}
|
|
34588
|
-
function
|
|
34589
|
-
const parsed =
|
|
34590
|
-
if (!parsed) throw new Error("
|
|
35289
|
+
function parseRequiredMailingListSignedSourceToken(value) {
|
|
35290
|
+
const parsed = parseMailingListSignedSourceToken(value);
|
|
35291
|
+
if (!parsed) throw new Error("Mailing-list signup signed source ref requires token");
|
|
34591
35292
|
return parsed;
|
|
34592
35293
|
}
|
|
34593
35294
|
//#endregion
|
|
@@ -35960,6 +36661,14 @@ const systemBlockDefinitions = [
|
|
|
35960
36661
|
weight: "standard"
|
|
35961
36662
|
})]
|
|
35962
36663
|
})),
|
|
36664
|
+
withDesignCapability("block.appointment-services", appointmentServicesBlockDefinition, sectionOnly(), defineBlockDesignMetadata({
|
|
36665
|
+
flow: conversionFlow,
|
|
36666
|
+
layoutProfiles: [layoutProfile({
|
|
36667
|
+
variantKey: "default",
|
|
36668
|
+
family: "stack",
|
|
36669
|
+
weight: "standard"
|
|
36670
|
+
})]
|
|
36671
|
+
})),
|
|
35963
36672
|
withDesignCapability("block.weekly-slot-availability", weeklySlotAvailabilityBlockDefinition, sectionOnly(), defineBlockDesignMetadata({
|
|
35964
36673
|
flow: offeringsFlow,
|
|
35965
36674
|
layoutProfiles: [layoutProfile({
|
|
@@ -37858,6 +38567,7 @@ const SYSTEM_BLOCK_KINDS = [
|
|
|
37858
38567
|
"block.form",
|
|
37859
38568
|
"block.contact-newsletter",
|
|
37860
38569
|
"block.appointment-booking",
|
|
38570
|
+
"block.appointment-services",
|
|
37861
38571
|
"block.weekly-slot-availability",
|
|
37862
38572
|
"block.event-registration",
|
|
37863
38573
|
"block.event-details",
|
|
@@ -38127,18 +38837,13 @@ const navigationItemConfigSchema = z.object({
|
|
|
38127
38837
|
isCta: z.boolean().optional()
|
|
38128
38838
|
}).extend({ children: z.lazy(() => z.array(navigationItemConfigSchema)).optional() });
|
|
38129
38839
|
const navigationMenuConfigSchema = z.object({
|
|
38130
|
-
|
|
38131
|
-
|
|
38132
|
-
|
|
38133
|
-
|
|
38134
|
-
|
|
38840
|
+
location: z.enum([
|
|
38841
|
+
"main",
|
|
38842
|
+
"footer",
|
|
38843
|
+
"legal"
|
|
38844
|
+
]),
|
|
38135
38845
|
items: z.array(navigationItemConfigSchema)
|
|
38136
|
-
}).superRefine((menu, ctx) => {
|
|
38137
|
-
if (menu.footerRole !== void 0 && menu.isFooter !== void 0 && menu.isFooter !== (menu.footerRole === "main")) ctx.addIssue({
|
|
38138
|
-
code: "custom",
|
|
38139
|
-
message: "footerRole and isFooter disagree",
|
|
38140
|
-
path: ["footerRole"]
|
|
38141
|
-
});
|
|
38846
|
+
}).strict().superRefine((menu, ctx) => {
|
|
38142
38847
|
const portalStats = collectPortalLinkStats(menu.items);
|
|
38143
38848
|
if (portalStats.count > 1) ctx.addIssue({
|
|
38144
38849
|
code: z.ZodIssueCode.custom,
|
|
@@ -38225,11 +38930,11 @@ const contentConfigSchema = z.object({
|
|
|
38225
38930
|
});
|
|
38226
38931
|
}
|
|
38227
38932
|
if (data.navigationMenus && data.navigationMenus.length > 1) {
|
|
38228
|
-
const
|
|
38229
|
-
const
|
|
38230
|
-
if (
|
|
38933
|
+
const locations = data.navigationMenus.map((m) => m.location);
|
|
38934
|
+
const duplicateLocations = locations.filter((location, i) => locations.indexOf(location) !== i);
|
|
38935
|
+
if (duplicateLocations.length > 0) ctx.addIssue({
|
|
38231
38936
|
code: z.ZodIssueCode.custom,
|
|
38232
|
-
message: `Navigation
|
|
38937
|
+
message: `Navigation locations must be unique. Duplicates: ${duplicateLocations.join(", ")}`,
|
|
38233
38938
|
path: ["navigationMenus"]
|
|
38234
38939
|
});
|
|
38235
38940
|
}
|