@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
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import "react/jsx-runtime";
|
|
3
3
|
import "react";
|
|
4
|
+
//#region ../api/src/apiEndpointTypes.ts
|
|
5
|
+
function allowedDemoMutationPolicy() {
|
|
6
|
+
return {
|
|
7
|
+
classification: "allowed",
|
|
8
|
+
publicMessage: ""
|
|
9
|
+
};
|
|
10
|
+
}
|
|
4
11
|
function blockedDemoMutationPolicy(classification, publicMessage) {
|
|
5
12
|
if (publicMessage.trim() === "") throw new Error(`Demo mutation policy ${classification} requires publicMessage.`);
|
|
6
13
|
return {
|
|
@@ -13,6 +20,7 @@ function blockedDemoMutationPolicy(classification, publicMessage) {
|
|
|
13
20
|
const DEMO_MUTATION_BLOCKED_HIDDEN = blockedDemoMutationPolicy("blocked-hidden", "This action is not available in demo sites.");
|
|
14
21
|
const DEMO_MUTATION_BLOCKED_DISABLED = blockedDemoMutationPolicy("blocked-disabled", "This setting is disabled in demo sites.");
|
|
15
22
|
blockedDemoMutationPolicy("internal-only", "This internal operation is not available in demo sites.");
|
|
23
|
+
const DEMO_MUTATION_ALLOWED = allowedDemoMutationPolicy();
|
|
16
24
|
//#endregion
|
|
17
25
|
//#region ../api/src/cache-tags.ts
|
|
18
26
|
/**
|
|
@@ -944,14 +952,117 @@ const NEWSLETTER_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
|
|
|
944
952
|
responseKind: "json",
|
|
945
953
|
errors: ["auth:forbidden", "server:internal_error"]
|
|
946
954
|
},
|
|
947
|
-
|
|
948
|
-
path: "/sites/{siteId}/
|
|
955
|
+
getMailingListSetup: {
|
|
956
|
+
path: "/sites/{siteId}/mailing-list/setup",
|
|
957
|
+
method: "GET",
|
|
958
|
+
tags: [TAG_TEMPLATES.site, TAG_TEMPLATES.siteNewsletter],
|
|
959
|
+
auth: "user",
|
|
960
|
+
responseKind: "json",
|
|
961
|
+
errors: ["auth:forbidden", "server:internal_error"]
|
|
962
|
+
},
|
|
963
|
+
getMailingListAuthoringContext: {
|
|
964
|
+
path: "/sites/{siteId}/mailing-list/authoring-context",
|
|
965
|
+
method: "GET",
|
|
966
|
+
tags: [TAG_TEMPLATES.site, TAG_TEMPLATES.siteNewsletter],
|
|
967
|
+
auth: "user",
|
|
968
|
+
responseKind: "json",
|
|
969
|
+
errors: ["auth:forbidden", "server:internal_error"]
|
|
970
|
+
},
|
|
971
|
+
previewMailingListSetupChange: {
|
|
972
|
+
path: "/sites/{siteId}/mailing-list/setup/preview",
|
|
973
|
+
method: "POST",
|
|
974
|
+
tags: [TAG_TEMPLATES.site, TAG_TEMPLATES.siteNewsletter],
|
|
975
|
+
auth: "user",
|
|
976
|
+
responseKind: "json",
|
|
977
|
+
demoMutation: DEMO_MUTATION_ALLOWED,
|
|
978
|
+
errors: [
|
|
979
|
+
"auth:forbidden",
|
|
980
|
+
"validation:invalid_input",
|
|
981
|
+
"server:internal_error"
|
|
982
|
+
]
|
|
983
|
+
},
|
|
984
|
+
applyMailingListSetupChange: {
|
|
985
|
+
path: "/sites/{siteId}/mailing-list/setup",
|
|
986
|
+
method: "PUT",
|
|
987
|
+
tags: [TAG_TEMPLATES.site, TAG_TEMPLATES.siteNewsletter],
|
|
988
|
+
auth: "user",
|
|
989
|
+
responseKind: "json",
|
|
990
|
+
demoMutation: DEMO_MUTATION_BLOCKED_DISABLED,
|
|
991
|
+
errors: [
|
|
992
|
+
"auth:forbidden",
|
|
993
|
+
"validation:invalid_input",
|
|
994
|
+
"resource:conflict",
|
|
995
|
+
"server:internal_error"
|
|
996
|
+
]
|
|
997
|
+
},
|
|
998
|
+
getMailingListProviderCatalog: {
|
|
999
|
+
path: "/sites/{siteId}/mailing-list/providers/{provider}/catalog",
|
|
1000
|
+
method: "GET",
|
|
1001
|
+
tags: [TAG_TEMPLATES.site, TAG_TEMPLATES.siteNewsletter],
|
|
1002
|
+
auth: "user",
|
|
1003
|
+
responseKind: "json",
|
|
1004
|
+
errors: [
|
|
1005
|
+
"auth:forbidden",
|
|
1006
|
+
"validation:invalid_input",
|
|
1007
|
+
"server:internal_error"
|
|
1008
|
+
]
|
|
1009
|
+
},
|
|
1010
|
+
refreshMailingListProviderCatalog: {
|
|
1011
|
+
path: "/sites/{siteId}/mailing-list/providers/{provider}/catalog/refresh",
|
|
1012
|
+
method: "POST",
|
|
1013
|
+
tags: [TAG_TEMPLATES.site, TAG_TEMPLATES.siteNewsletter],
|
|
1014
|
+
auth: "user",
|
|
1015
|
+
responseKind: "json",
|
|
1016
|
+
demoMutation: DEMO_MUTATION_BLOCKED_DISABLED,
|
|
1017
|
+
errors: [
|
|
1018
|
+
"auth:forbidden",
|
|
1019
|
+
"validation:invalid_input",
|
|
1020
|
+
"server:internal_error"
|
|
1021
|
+
]
|
|
1022
|
+
},
|
|
1023
|
+
getMailingListProviderHealth: {
|
|
1024
|
+
path: "/sites/{siteId}/mailing-list/health",
|
|
1025
|
+
method: "GET",
|
|
1026
|
+
tags: [TAG_TEMPLATES.site, TAG_TEMPLATES.siteNewsletter],
|
|
1027
|
+
auth: "user",
|
|
1028
|
+
responseKind: "json",
|
|
1029
|
+
errors: ["auth:forbidden", "server:internal_error"]
|
|
1030
|
+
},
|
|
1031
|
+
getBrevoConnection: {
|
|
1032
|
+
path: "/sites/{siteId}/integrations/brevo/connection",
|
|
949
1033
|
method: "GET",
|
|
950
1034
|
tags: [TAG_TEMPLATES.site],
|
|
951
1035
|
auth: "user",
|
|
952
1036
|
responseKind: "json",
|
|
953
1037
|
errors: ["auth:forbidden", "server:internal_error"]
|
|
954
1038
|
},
|
|
1039
|
+
connectBrevo: {
|
|
1040
|
+
path: "/sites/{siteId}/integrations/brevo/connection",
|
|
1041
|
+
method: "PUT",
|
|
1042
|
+
tags: [TAG_TEMPLATES.site],
|
|
1043
|
+
auth: "user",
|
|
1044
|
+
responseKind: "json",
|
|
1045
|
+
demoMutation: DEMO_MUTATION_BLOCKED_DISABLED,
|
|
1046
|
+
errors: [
|
|
1047
|
+
"auth:forbidden",
|
|
1048
|
+
"validation:invalid_input",
|
|
1049
|
+
"resource:conflict",
|
|
1050
|
+
"server:internal_error"
|
|
1051
|
+
]
|
|
1052
|
+
},
|
|
1053
|
+
disconnectBrevo: {
|
|
1054
|
+
path: "/sites/{siteId}/integrations/brevo/disconnect",
|
|
1055
|
+
method: "POST",
|
|
1056
|
+
tags: [TAG_TEMPLATES.site],
|
|
1057
|
+
auth: "user",
|
|
1058
|
+
responseKind: "json",
|
|
1059
|
+
demoMutation: DEMO_MUTATION_BLOCKED_DISABLED,
|
|
1060
|
+
errors: [
|
|
1061
|
+
"auth:forbidden",
|
|
1062
|
+
"resource:conflict",
|
|
1063
|
+
"server:internal_error"
|
|
1064
|
+
]
|
|
1065
|
+
},
|
|
955
1066
|
getMailchimpConnection: {
|
|
956
1067
|
path: "/sites/{siteId}/integrations/mailchimp/connection",
|
|
957
1068
|
method: "GET",
|
|
@@ -1175,994 +1286,329 @@ const NEWSLETTER_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
|
|
|
1175
1286
|
}
|
|
1176
1287
|
});
|
|
1177
1288
|
//#endregion
|
|
1178
|
-
//#region ../
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
auth: "public",
|
|
1192
|
-
responseKind: "json"
|
|
1193
|
-
},
|
|
1194
|
-
getPublicEventRegistrationOptions: {
|
|
1195
|
-
path: "/public/sites/{siteId}/events/registration-options",
|
|
1196
|
-
method: "POST",
|
|
1197
|
-
tags: [TAG_TEMPLATES.publicEvents, "event-registration-options"],
|
|
1198
|
-
auth: "public",
|
|
1199
|
-
responseKind: "json",
|
|
1200
|
-
errors: [
|
|
1201
|
-
"validation:invalid_input",
|
|
1202
|
-
"resource:not_found",
|
|
1203
|
-
"resource:conflict",
|
|
1204
|
-
"server:internal_error"
|
|
1205
|
-
]
|
|
1206
|
-
},
|
|
1207
|
-
resolveEventSubroute: {
|
|
1208
|
-
path: "/public/sites/{siteId}/events/subroutes/resolve",
|
|
1209
|
-
method: "GET",
|
|
1210
|
-
revalidate: 60,
|
|
1211
|
-
tags: [TAG_TEMPLATES.publicEvents, "event-subroute"],
|
|
1212
|
-
auth: "public",
|
|
1213
|
-
responseKind: "json",
|
|
1214
|
-
errors: []
|
|
1215
|
-
}
|
|
1216
|
-
});
|
|
1289
|
+
//#region ../core/src/result.ts
|
|
1290
|
+
function ok(value) {
|
|
1291
|
+
return {
|
|
1292
|
+
ok: true,
|
|
1293
|
+
value
|
|
1294
|
+
};
|
|
1295
|
+
}
|
|
1296
|
+
function err(error) {
|
|
1297
|
+
return {
|
|
1298
|
+
ok: false,
|
|
1299
|
+
error
|
|
1300
|
+
};
|
|
1301
|
+
}
|
|
1217
1302
|
//#endregion
|
|
1218
|
-
//#region ../
|
|
1303
|
+
//#region ../core/src/branded.ts
|
|
1304
|
+
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;
|
|
1305
|
+
function parseUuidBrand(value, unsafeConstructor) {
|
|
1306
|
+
if (typeof value !== "string") return err({ kind: "not_string" });
|
|
1307
|
+
const normalized = value.trim().toLowerCase();
|
|
1308
|
+
if (normalized.length === 0) return err({ kind: "empty_string" });
|
|
1309
|
+
if (!UUID_PATTERN$1.test(normalized)) return err({ kind: "invalid_uuid" });
|
|
1310
|
+
return ok(unsafeConstructor(normalized));
|
|
1311
|
+
}
|
|
1312
|
+
const unsafeAsSiteId = (id) => id;
|
|
1313
|
+
const unsafeAsApiKeyId = (id) => id;
|
|
1314
|
+
const unsafeAsEventOfferingId = (id) => id;
|
|
1315
|
+
const unsafeAsEventSeriesId = (id) => id;
|
|
1316
|
+
const unsafeAsUserId = (id) => id;
|
|
1317
|
+
const parseSiteId = (value) => parseUuidBrand(value, unsafeAsSiteId);
|
|
1318
|
+
const parseApiKeyId = (value) => parseUuidBrand(value, unsafeAsApiKeyId);
|
|
1319
|
+
const parseEventOfferingId = (value) => parseUuidBrand(value, unsafeAsEventOfferingId);
|
|
1320
|
+
const parseUserId = (value) => parseUuidBrand(value, unsafeAsUserId);
|
|
1321
|
+
const parseEventSeriesId = (value) => parseUuidBrand(value, unsafeAsEventSeriesId);
|
|
1322
|
+
//#endregion
|
|
1323
|
+
//#region ../core/src/assert-never.ts
|
|
1324
|
+
function assertNever$2(value, message = "Unexpected variant") {
|
|
1325
|
+
throw new Error(`${message}: ${String(value)}`);
|
|
1326
|
+
}
|
|
1327
|
+
//#endregion
|
|
1328
|
+
//#region ../core/src/currency-format.ts
|
|
1329
|
+
const CURRENCY_LOCALE_BY_CODE = {
|
|
1330
|
+
USD: "en-US",
|
|
1331
|
+
GBP: "en-GB",
|
|
1332
|
+
EUR: "de-DE",
|
|
1333
|
+
AUD: "en-AU",
|
|
1334
|
+
CAD: "en-CA",
|
|
1335
|
+
NZD: "en-NZ",
|
|
1336
|
+
JPY: "ja-JP",
|
|
1337
|
+
CNY: "zh-CN",
|
|
1338
|
+
CHF: "de-CH"
|
|
1339
|
+
};
|
|
1340
|
+
function resolveCurrencyLocale(currencyCode, override) {
|
|
1341
|
+
return override ?? CURRENCY_LOCALE_BY_CODE[currencyCode] ?? "en";
|
|
1342
|
+
}
|
|
1219
1343
|
/**
|
|
1220
|
-
* The
|
|
1221
|
-
*
|
|
1344
|
+
* The single currency-amount formatter for the product: minor units in,
|
|
1345
|
+
* localized string out.
|
|
1222
1346
|
*
|
|
1223
|
-
*
|
|
1224
|
-
*
|
|
1225
|
-
*
|
|
1226
|
-
*
|
|
1227
|
-
* (The endpoint that originally motivated the move, `checkPublicEventEligibility`,
|
|
1228
|
-
* was since deleted on dev by #1326.)
|
|
1347
|
+
* The locale is derived from the currency by default, so output is deterministic
|
|
1348
|
+
* across server and client (no SSR/hydration mismatch). All other money
|
|
1349
|
+
* formatters in the codebase should delegate here rather than constructing their
|
|
1350
|
+
* own `Intl.NumberFormat`.
|
|
1229
1351
|
*/
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1352
|
+
function formatCurrencyAmount(amountCents, currency, options) {
|
|
1353
|
+
const currencyCode = currency.toUpperCase();
|
|
1354
|
+
const locale = resolveCurrencyLocale(currencyCode, options?.locale);
|
|
1355
|
+
try {
|
|
1356
|
+
const exactFormatter = new Intl.NumberFormat(locale, {
|
|
1357
|
+
style: "currency",
|
|
1358
|
+
currency: currencyCode
|
|
1359
|
+
});
|
|
1360
|
+
const fractionDigits = options?.decimals === "auto" ? {
|
|
1361
|
+
minimumFractionDigits: 0,
|
|
1362
|
+
maximumFractionDigits: exactFormatter.resolvedOptions().maximumFractionDigits
|
|
1363
|
+
} : {};
|
|
1364
|
+
return new Intl.NumberFormat(locale, {
|
|
1365
|
+
style: "currency",
|
|
1366
|
+
currency: currencyCode,
|
|
1367
|
+
...fractionDigits
|
|
1368
|
+
}).format(amountCents / 100);
|
|
1369
|
+
} catch {
|
|
1370
|
+
return `${(amountCents / 100).toFixed(2)} ${currencyCode}`;
|
|
1244
1371
|
}
|
|
1245
|
-
}
|
|
1372
|
+
}
|
|
1246
1373
|
//#endregion
|
|
1247
|
-
//#region ../
|
|
1374
|
+
//#region ../core/src/planner.ts
|
|
1375
|
+
/** Default clock for production callers that do not inject time explicitly. */
|
|
1376
|
+
const systemPlanningClock = { now: () => Date.now() };
|
|
1377
|
+
/** Resolve current time as a Date from an explicit Date, injected clock, or system clock. */
|
|
1378
|
+
function resolvePlanningNowDate(input = {}) {
|
|
1379
|
+
if (input.now !== void 0) return input.now;
|
|
1380
|
+
return new Date((input.clock ?? systemPlanningClock).now());
|
|
1381
|
+
}
|
|
1382
|
+
//#endregion
|
|
1383
|
+
//#region ../core/src/event-pricing.ts
|
|
1384
|
+
/** Capacity closes booking, but does not make an otherwise eligible price unknown. */
|
|
1385
|
+
function isPublicEventPricingOptionDisplayable(option) {
|
|
1386
|
+
if (!option.isActive) return false;
|
|
1387
|
+
if (option.availability.kind === "available") return true;
|
|
1388
|
+
const reason = option.availability.reason;
|
|
1389
|
+
switch (reason) {
|
|
1390
|
+
case "sold_out":
|
|
1391
|
+
case "overallCapacityUnavailable": return true;
|
|
1392
|
+
case "inactive":
|
|
1393
|
+
case "not_on_sale_yet":
|
|
1394
|
+
case "sale_ended":
|
|
1395
|
+
case "attendance_mode_unavailable": return false;
|
|
1396
|
+
default: return assertNever$2(reason);
|
|
1397
|
+
}
|
|
1398
|
+
}
|
|
1399
|
+
function publicEventPricingDisplay(pricing) {
|
|
1400
|
+
switch (pricing.kind) {
|
|
1401
|
+
case "free":
|
|
1402
|
+
case "single":
|
|
1403
|
+
case "sliding_scale": return canonicalEventPricingDisplay(pricing);
|
|
1404
|
+
case "tiered": return resolvePricingOptionsPriceDisplay({
|
|
1405
|
+
options: pricing.options.filter(isPublicEventPricingOptionDisplayable),
|
|
1406
|
+
currency: pricing.currency,
|
|
1407
|
+
purpose: "configured"
|
|
1408
|
+
});
|
|
1409
|
+
case "external": return {
|
|
1410
|
+
kind: "external",
|
|
1411
|
+
label: pricing.label
|
|
1412
|
+
};
|
|
1413
|
+
}
|
|
1414
|
+
}
|
|
1415
|
+
function publicEventPricingType(pricing) {
|
|
1416
|
+
switch (pricing.kind) {
|
|
1417
|
+
case "free": return "free";
|
|
1418
|
+
case "single":
|
|
1419
|
+
case "tiered":
|
|
1420
|
+
case "sliding_scale": return isFreePublicEventPriceDisplay(publicEventPricingDisplay(pricing)) ? "free" : "paid";
|
|
1421
|
+
case "external": return "external";
|
|
1422
|
+
}
|
|
1423
|
+
}
|
|
1424
|
+
function isFreePublicEventPriceDisplay(display) {
|
|
1425
|
+
switch (display.kind) {
|
|
1426
|
+
case "free": return true;
|
|
1427
|
+
case "exact":
|
|
1428
|
+
case "from":
|
|
1429
|
+
case "range":
|
|
1430
|
+
case "mixed":
|
|
1431
|
+
case "unavailable":
|
|
1432
|
+
case "external": return false;
|
|
1433
|
+
}
|
|
1434
|
+
}
|
|
1435
|
+
function resolvePricingOptionSaleWindowState(option, now) {
|
|
1436
|
+
if (option.saleStartsAt !== null && option.saleStartsAt !== void 0 && new Date(option.saleStartsAt) > now) return "not_started";
|
|
1437
|
+
if (option.saleEndsAt !== null && option.saleEndsAt !== void 0 && new Date(option.saleEndsAt) < now) return "ended";
|
|
1438
|
+
return "open";
|
|
1439
|
+
}
|
|
1440
|
+
function resolvePricingOptionsPriceDisplay(input) {
|
|
1441
|
+
const now = input.purpose === "available_now" ? resolvePlanningNowDate({
|
|
1442
|
+
now: input.now,
|
|
1443
|
+
clock: input.clock
|
|
1444
|
+
}) : null;
|
|
1445
|
+
const amounts = input.options.filter((option) => option.isActive && (now === null || resolvePricingOptionSaleWindowState(option, now) === "open")).map((option) => option.priceAmount);
|
|
1446
|
+
return amounts.length === 0 ? {
|
|
1447
|
+
kind: "unavailable",
|
|
1448
|
+
currency: input.currency
|
|
1449
|
+
} : amountRangeDisplay(amounts, input.currency);
|
|
1450
|
+
}
|
|
1451
|
+
function amountRangeDisplay(amounts, currency) {
|
|
1452
|
+
const minAmount = Math.min(...amounts);
|
|
1453
|
+
const maxAmount = Math.max(...amounts);
|
|
1454
|
+
if (minAmount === maxAmount) return minAmount === 0 ? {
|
|
1455
|
+
kind: "free",
|
|
1456
|
+
currency
|
|
1457
|
+
} : {
|
|
1458
|
+
kind: "exact",
|
|
1459
|
+
amount: minAmount,
|
|
1460
|
+
currency
|
|
1461
|
+
};
|
|
1462
|
+
if (minAmount === 0) {
|
|
1463
|
+
const paidAmounts = amounts.filter((amount) => amount > 0);
|
|
1464
|
+
return {
|
|
1465
|
+
kind: "mixed",
|
|
1466
|
+
paidFromAmount: Math.min(...paidAmounts),
|
|
1467
|
+
paidToAmount: maxAmount,
|
|
1468
|
+
currency
|
|
1469
|
+
};
|
|
1470
|
+
}
|
|
1471
|
+
return {
|
|
1472
|
+
kind: "range",
|
|
1473
|
+
minAmount,
|
|
1474
|
+
maxAmount,
|
|
1475
|
+
currency
|
|
1476
|
+
};
|
|
1477
|
+
}
|
|
1478
|
+
/** Derives configured price presentation directly from canonical pricing. */
|
|
1479
|
+
function canonicalEventPricingDisplay(pricing) {
|
|
1480
|
+
switch (pricing.kind) {
|
|
1481
|
+
case "free": return {
|
|
1482
|
+
kind: "free",
|
|
1483
|
+
currency: pricing.currency
|
|
1484
|
+
};
|
|
1485
|
+
case "single": return {
|
|
1486
|
+
kind: "exact",
|
|
1487
|
+
amount: pricing.amount,
|
|
1488
|
+
currency: pricing.currency
|
|
1489
|
+
};
|
|
1490
|
+
case "sliding_scale": return pricing.minimum === pricing.maximum ? {
|
|
1491
|
+
kind: "exact",
|
|
1492
|
+
amount: pricing.maximum,
|
|
1493
|
+
currency: pricing.currency
|
|
1494
|
+
} : {
|
|
1495
|
+
kind: "range",
|
|
1496
|
+
minAmount: pricing.minimum,
|
|
1497
|
+
maxAmount: pricing.maximum,
|
|
1498
|
+
currency: pricing.currency
|
|
1499
|
+
};
|
|
1500
|
+
case "tiered": return resolvePricingOptionsPriceDisplay({
|
|
1501
|
+
options: pricing.options,
|
|
1502
|
+
currency: pricing.currency,
|
|
1503
|
+
purpose: "configured"
|
|
1504
|
+
});
|
|
1505
|
+
default: return assertNever$2(pricing);
|
|
1506
|
+
}
|
|
1507
|
+
}
|
|
1508
|
+
//#endregion
|
|
1509
|
+
//#region ../core/src/event-page-surface-subject.ts
|
|
1510
|
+
function createEventSeriesPageSurfaceSubject(eventSeriesId, bookingScope, eventDestinationMode) {
|
|
1511
|
+
const mode = eventDestinationMode ? { eventDestinationMode } : {};
|
|
1512
|
+
return bookingScope === "whole_series" ? {
|
|
1513
|
+
kind: "eventSeries",
|
|
1514
|
+
eventSeriesId,
|
|
1515
|
+
bookingScope,
|
|
1516
|
+
isWholeSeriesBooking: true,
|
|
1517
|
+
...mode
|
|
1518
|
+
} : {
|
|
1519
|
+
kind: "eventSeries",
|
|
1520
|
+
eventSeriesId,
|
|
1521
|
+
bookingScope,
|
|
1522
|
+
...mode
|
|
1523
|
+
};
|
|
1524
|
+
}
|
|
1525
|
+
function createEventOfferingPageSurfaceSubject(eventOfferingId, input) {
|
|
1526
|
+
const mode = input.eventDestinationMode ? { eventDestinationMode: input.eventDestinationMode } : {};
|
|
1527
|
+
const identity = {
|
|
1528
|
+
kind: "eventOffering",
|
|
1529
|
+
eventOfferingId,
|
|
1530
|
+
catalogueEventSeriesIds: input.catalogueEventSeriesIds
|
|
1531
|
+
};
|
|
1532
|
+
return input.bookingScope === "whole_series" ? {
|
|
1533
|
+
...identity,
|
|
1534
|
+
bookingScope: input.bookingScope,
|
|
1535
|
+
isWholeSeriesBooking: true,
|
|
1536
|
+
...mode
|
|
1537
|
+
} : {
|
|
1538
|
+
...identity,
|
|
1539
|
+
bookingScope: input.bookingScope,
|
|
1540
|
+
...mode
|
|
1541
|
+
};
|
|
1542
|
+
}
|
|
1248
1543
|
/**
|
|
1249
|
-
*
|
|
1250
|
-
*
|
|
1251
|
-
* These are the reads that appointment writes invalidate. They carry canonical
|
|
1252
|
-
* `riverbank:*` tags because the frontend revalidate endpoint discards anything
|
|
1253
|
-
* else, which is why the legacy `site-{siteId}` tag they used to declare could
|
|
1254
|
-
* never actually be cleared (issue 1364).
|
|
1544
|
+
* Read the destination mode off a wire value.
|
|
1255
1545
|
*
|
|
1256
|
-
*
|
|
1257
|
-
*
|
|
1546
|
+
* Absent or unrecognised reads as absent, which leaves the routed Event record
|
|
1547
|
+
* as the only authority — the behaviour every caller had before the field
|
|
1548
|
+
* existed.
|
|
1258
1549
|
*/
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
tags: [TAG_TEMPLATES.publicBookingAvailability, TAG_TEMPLATES.publicBookingServices],
|
|
1305
|
-
auth: "public",
|
|
1306
|
-
responseKind: "json",
|
|
1307
|
-
errors: []
|
|
1550
|
+
function parseEventPageSurfaceDestinationMode(value) {
|
|
1551
|
+
return value === "cms-managed" || value === "system-managed" ? value : void 0;
|
|
1552
|
+
}
|
|
1553
|
+
function parseEventPageSurfaceSubject(value) {
|
|
1554
|
+
if (!isRecord$10(value)) return err({ kind: "notObject" });
|
|
1555
|
+
switch (value.kind) {
|
|
1556
|
+
case "eventSeries": {
|
|
1557
|
+
const eventSeriesId = parseEventSeriesId(value.eventSeriesId);
|
|
1558
|
+
if (!eventSeriesId.ok) return err({
|
|
1559
|
+
kind: "invalidEventSeriesId",
|
|
1560
|
+
error: eventSeriesId.error
|
|
1561
|
+
});
|
|
1562
|
+
if (value.bookingScope !== "single_occurrence" && value.bookingScope !== "whole_series") return err({
|
|
1563
|
+
kind: "invalidEventSeriesBookingScope",
|
|
1564
|
+
bookingScope: value.bookingScope
|
|
1565
|
+
});
|
|
1566
|
+
return ok(createEventSeriesPageSurfaceSubject(eventSeriesId.value, value.bookingScope, parseEventPageSurfaceDestinationMode(value.eventDestinationMode)));
|
|
1567
|
+
}
|
|
1568
|
+
case "eventOffering": {
|
|
1569
|
+
const eventOfferingId = parseEventOfferingId(value.eventOfferingId);
|
|
1570
|
+
if (!eventOfferingId.ok) return err({
|
|
1571
|
+
kind: "invalidEventOfferingId",
|
|
1572
|
+
error: eventOfferingId.error
|
|
1573
|
+
});
|
|
1574
|
+
if (!Array.isArray(value.catalogueEventSeriesIds)) return err({
|
|
1575
|
+
kind: "invalidEventOfferingCatalogue",
|
|
1576
|
+
catalogue: value.catalogueEventSeriesIds
|
|
1577
|
+
});
|
|
1578
|
+
if (value.bookingScope !== "single_occurrence" && value.bookingScope !== "whole_series") return err({
|
|
1579
|
+
kind: "invalidEventOfferingBookingScope",
|
|
1580
|
+
bookingScope: value.bookingScope
|
|
1581
|
+
});
|
|
1582
|
+
const parsedCatalogueIds = parseEventSeriesIdList(value.catalogueEventSeriesIds);
|
|
1583
|
+
if (!parsedCatalogueIds.ok) return parsedCatalogueIds;
|
|
1584
|
+
const eventDestinationMode = parseEventPageSurfaceDestinationMode(value.eventDestinationMode);
|
|
1585
|
+
return ok(createEventOfferingPageSurfaceSubject(eventOfferingId.value, {
|
|
1586
|
+
catalogueEventSeriesIds: parsedCatalogueIds.value,
|
|
1587
|
+
bookingScope: value.bookingScope,
|
|
1588
|
+
...eventDestinationMode ? { eventDestinationMode } : {}
|
|
1589
|
+
}));
|
|
1590
|
+
}
|
|
1591
|
+
default: return err({
|
|
1592
|
+
kind: "unsupportedSubject",
|
|
1593
|
+
subjectKind: value.kind
|
|
1594
|
+
});
|
|
1308
1595
|
}
|
|
1309
|
-
}
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
const
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
}
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
responseKind: "json"
|
|
1326
|
-
},
|
|
1327
|
-
revokeSiteApiKey: {
|
|
1328
|
-
path: "/sites/{siteId}/api-keys/{keyId}",
|
|
1329
|
-
method: "DELETE",
|
|
1330
|
-
auth: "user",
|
|
1331
|
-
tags: ["site-{siteId}", "api-keys"],
|
|
1332
|
-
responseKind: "json"
|
|
1333
|
-
},
|
|
1334
|
-
listSitePreviewKeys: {
|
|
1335
|
-
path: "/sites/{siteId}/api-keys/preview",
|
|
1336
|
-
method: "GET",
|
|
1337
|
-
auth: "user",
|
|
1338
|
-
tags: [
|
|
1339
|
-
"site-{siteId}",
|
|
1340
|
-
"api-keys",
|
|
1341
|
-
"preview-key"
|
|
1342
|
-
],
|
|
1343
|
-
errors: [],
|
|
1344
|
-
responseKind: "json"
|
|
1345
|
-
},
|
|
1346
|
-
createSitePreviewKey: {
|
|
1347
|
-
path: "/sites/{siteId}/api-keys/preview",
|
|
1348
|
-
method: "POST",
|
|
1349
|
-
auth: "user",
|
|
1350
|
-
tags: [
|
|
1351
|
-
"site-{siteId}",
|
|
1352
|
-
"api-keys",
|
|
1353
|
-
"preview-key"
|
|
1354
|
-
],
|
|
1355
|
-
responseKind: "json"
|
|
1356
|
-
},
|
|
1357
|
-
getSiteApiKeyAccessLogs: {
|
|
1358
|
-
path: "/sites/{siteId}/api-keys/access-logs",
|
|
1359
|
-
method: "GET",
|
|
1360
|
-
auth: "user",
|
|
1361
|
-
tags: [
|
|
1362
|
-
"site-{siteId}",
|
|
1363
|
-
"api-keys",
|
|
1364
|
-
"access-logs"
|
|
1365
|
-
],
|
|
1366
|
-
responseKind: "json"
|
|
1367
|
-
},
|
|
1368
|
-
listManagementKeys: {
|
|
1369
|
-
path: "/sites/{siteId}/api-keys/management",
|
|
1370
|
-
method: "GET",
|
|
1371
|
-
auth: "user",
|
|
1372
|
-
tags: [
|
|
1373
|
-
"site-{siteId}",
|
|
1374
|
-
"api-keys",
|
|
1375
|
-
"management-keys"
|
|
1376
|
-
],
|
|
1377
|
-
responseKind: "json"
|
|
1378
|
-
},
|
|
1379
|
-
createManagementKey: {
|
|
1380
|
-
path: "/sites/{siteId}/api-keys/management",
|
|
1381
|
-
method: "POST",
|
|
1382
|
-
auth: "user",
|
|
1383
|
-
tags: [
|
|
1384
|
-
"site-{siteId}",
|
|
1385
|
-
"api-keys",
|
|
1386
|
-
"management-keys"
|
|
1387
|
-
],
|
|
1388
|
-
responseKind: "json"
|
|
1389
|
-
},
|
|
1390
|
-
revokeManagementKey: {
|
|
1391
|
-
path: "/sites/{siteId}/api-keys/management",
|
|
1392
|
-
method: "DELETE",
|
|
1393
|
-
auth: "user",
|
|
1394
|
-
tags: [
|
|
1395
|
-
"site-{siteId}",
|
|
1396
|
-
"api-keys",
|
|
1397
|
-
"management-keys"
|
|
1398
|
-
],
|
|
1399
|
-
responseKind: "json"
|
|
1400
|
-
}
|
|
1401
|
-
});
|
|
1402
|
-
//#endregion
|
|
1403
|
-
//#region ../api/src/eventManagementEndpointDefinitions.ts
|
|
1404
|
-
const EVENT_MANAGEMENT_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
|
|
1405
|
-
listEvents: {
|
|
1406
|
-
path: "/sites/{siteId}/bookings/events",
|
|
1407
|
-
method: "GET",
|
|
1408
|
-
tags: ["site-{siteId}", "event-series-{siteId}"],
|
|
1409
|
-
auth: "user",
|
|
1410
|
-
responseKind: "json",
|
|
1411
|
-
errors: []
|
|
1412
|
-
},
|
|
1413
|
-
createEvent: {
|
|
1414
|
-
path: "/sites/{siteId}/bookings/events",
|
|
1415
|
-
method: "POST",
|
|
1416
|
-
tags: ["site-{siteId}", "event-series-{siteId}"],
|
|
1417
|
-
auth: "user",
|
|
1418
|
-
responseKind: "json",
|
|
1419
|
-
errors: [
|
|
1420
|
-
"validation:invalid_input",
|
|
1421
|
-
"resource:already_exists",
|
|
1422
|
-
"server:internal_error"
|
|
1423
|
-
]
|
|
1424
|
-
},
|
|
1425
|
-
transitionEventLifecycle: {
|
|
1426
|
-
path: "/sites/{siteId}/bookings/events/{eventId}/lifecycle",
|
|
1427
|
-
method: "POST",
|
|
1428
|
-
tags: ["site-{siteId}", "event-series-{siteId}"],
|
|
1429
|
-
auth: "user",
|
|
1430
|
-
responseKind: "json",
|
|
1431
|
-
errors: [
|
|
1432
|
-
"validation:invalid_input",
|
|
1433
|
-
"resource:not_found",
|
|
1434
|
-
"resource:conflict",
|
|
1435
|
-
"server:internal_error"
|
|
1436
|
-
]
|
|
1437
|
-
},
|
|
1438
|
-
updateEventIdentity: {
|
|
1439
|
-
path: "/sites/{siteId}/bookings/events/{eventId}",
|
|
1440
|
-
method: "PATCH",
|
|
1441
|
-
tags: ["site-{siteId}", "event-series-{siteId}"],
|
|
1442
|
-
auth: "user",
|
|
1443
|
-
responseKind: "json",
|
|
1444
|
-
errors: [
|
|
1445
|
-
"validation:invalid_input",
|
|
1446
|
-
"resource:not_found",
|
|
1447
|
-
"server:internal_error"
|
|
1448
|
-
]
|
|
1449
|
-
},
|
|
1450
|
-
createWholeSeriesRun: {
|
|
1451
|
-
path: "/sites/{siteId}/bookings/events/{eventId}/runs",
|
|
1452
|
-
method: "POST",
|
|
1453
|
-
tags: ["site-{siteId}", "event-series-{siteId}"],
|
|
1454
|
-
auth: "user",
|
|
1455
|
-
responseKind: "json",
|
|
1456
|
-
errors: [
|
|
1457
|
-
"validation:invalid_input",
|
|
1458
|
-
"resource:not_found",
|
|
1459
|
-
"resource:already_exists",
|
|
1460
|
-
"server:internal_error"
|
|
1461
|
-
]
|
|
1462
|
-
},
|
|
1463
|
-
updateWholeSeriesRun: {
|
|
1464
|
-
path: "/sites/{siteId}/bookings/events/{eventId}/runs/{runId}",
|
|
1465
|
-
method: "PATCH",
|
|
1466
|
-
tags: ["site-{siteId}", "event-series-{siteId}"],
|
|
1467
|
-
auth: "user",
|
|
1468
|
-
responseKind: "json",
|
|
1469
|
-
errors: [
|
|
1470
|
-
"validation:invalid_input",
|
|
1471
|
-
"resource:not_found",
|
|
1472
|
-
"resource:conflict",
|
|
1473
|
-
"server:internal_error"
|
|
1474
|
-
]
|
|
1475
|
-
},
|
|
1476
|
-
cancelWholeSeriesRun: {
|
|
1477
|
-
path: "/sites/{siteId}/bookings/events/{eventId}/runs/{runId}/cancellation",
|
|
1478
|
-
method: "POST",
|
|
1479
|
-
tags: ["site-{siteId}", "event-series-{siteId}"],
|
|
1480
|
-
auth: "user",
|
|
1481
|
-
responseKind: "json",
|
|
1482
|
-
errors: [
|
|
1483
|
-
"validation:invalid_input",
|
|
1484
|
-
"resource:not_found",
|
|
1485
|
-
"resource:conflict",
|
|
1486
|
-
"server:internal_error"
|
|
1487
|
-
]
|
|
1488
|
-
}
|
|
1489
|
-
});
|
|
1490
|
-
//#endregion
|
|
1491
|
-
//#region ../api/src/giftingEndpointDefinitions.ts
|
|
1492
|
-
/**
|
|
1493
|
-
* Gifting endpoints (gift cards & vouchers) — the dashboard surface that manages
|
|
1494
|
-
* offers, gifts and settings, plus the public buy/claim surface.
|
|
1495
|
-
*/
|
|
1496
|
-
const GIFTING_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
|
|
1497
|
-
createGiftingOffer: {
|
|
1498
|
-
path: "/sites/{siteId}/gifting/offers",
|
|
1499
|
-
method: "POST",
|
|
1500
|
-
tags: ["site-{siteId}", "gifting-offers-{siteId}"],
|
|
1501
|
-
auth: "user",
|
|
1502
|
-
responseKind: "json",
|
|
1503
|
-
errors: [
|
|
1504
|
-
"validation:invalid_input",
|
|
1505
|
-
"auth:forbidden",
|
|
1506
|
-
"server:internal_error"
|
|
1507
|
-
]
|
|
1508
|
-
},
|
|
1509
|
-
updateGiftingOffer: {
|
|
1510
|
-
path: "/sites/{siteId}/gifting/offers/{offerId}",
|
|
1511
|
-
method: "PATCH",
|
|
1512
|
-
tags: ["site-{siteId}", "gifting-offers-{siteId}"],
|
|
1513
|
-
auth: "user",
|
|
1514
|
-
responseKind: "json",
|
|
1515
|
-
errors: [
|
|
1516
|
-
"validation:invalid_input",
|
|
1517
|
-
"auth:forbidden",
|
|
1518
|
-
"resource:not_found",
|
|
1519
|
-
"resource:conflict",
|
|
1520
|
-
"server:internal_error"
|
|
1521
|
-
]
|
|
1522
|
-
},
|
|
1523
|
-
deleteGiftingOffer: {
|
|
1524
|
-
path: "/sites/{siteId}/gifting/offers/{offerId}",
|
|
1525
|
-
method: "DELETE",
|
|
1526
|
-
tags: ["site-{siteId}", "gifting-offers-{siteId}"],
|
|
1527
|
-
auth: "user",
|
|
1528
|
-
responseKind: "json",
|
|
1529
|
-
errors: [
|
|
1530
|
-
"auth:forbidden",
|
|
1531
|
-
"resource:not_found",
|
|
1532
|
-
"resource:conflict",
|
|
1533
|
-
"server:internal_error"
|
|
1534
|
-
]
|
|
1535
|
-
},
|
|
1536
|
-
duplicateGiftingOffer: {
|
|
1537
|
-
path: "/sites/{siteId}/gifting/offers/{offerId}/duplicate",
|
|
1538
|
-
method: "POST",
|
|
1539
|
-
tags: ["site-{siteId}", "gifting-offers-{siteId}"],
|
|
1540
|
-
auth: "user",
|
|
1541
|
-
responseKind: "json",
|
|
1542
|
-
errors: [
|
|
1543
|
-
"auth:forbidden",
|
|
1544
|
-
"resource:not_found",
|
|
1545
|
-
"server:internal_error"
|
|
1546
|
-
]
|
|
1547
|
-
},
|
|
1548
|
-
reorderGiftingOffers: {
|
|
1549
|
-
path: "/sites/{siteId}/gifting/offers/order",
|
|
1550
|
-
method: "PUT",
|
|
1551
|
-
tags: ["site-{siteId}", "gifting-offers-{siteId}"],
|
|
1552
|
-
auth: "user",
|
|
1553
|
-
responseKind: "json",
|
|
1554
|
-
errors: [
|
|
1555
|
-
"validation:invalid_input",
|
|
1556
|
-
"auth:forbidden",
|
|
1557
|
-
"resource:not_found",
|
|
1558
|
-
"server:internal_error"
|
|
1559
|
-
]
|
|
1560
|
-
},
|
|
1561
|
-
sendGift: {
|
|
1562
|
-
path: "/sites/{siteId}/gifting/gifts",
|
|
1563
|
-
method: "POST",
|
|
1564
|
-
tags: ["site-{siteId}", "gifting-gifts-{siteId}"],
|
|
1565
|
-
auth: "user",
|
|
1566
|
-
demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN,
|
|
1567
|
-
responseKind: "json",
|
|
1568
|
-
errors: [
|
|
1569
|
-
"validation:invalid_input",
|
|
1570
|
-
"auth:forbidden",
|
|
1571
|
-
"resource:not_found",
|
|
1572
|
-
"server:internal_error"
|
|
1573
|
-
]
|
|
1574
|
-
},
|
|
1575
|
-
resendGift: {
|
|
1576
|
-
path: "/sites/{siteId}/gifting/gifts/{giftId}/resend",
|
|
1577
|
-
method: "POST",
|
|
1578
|
-
tags: ["site-{siteId}", "gifting-gifts-{siteId}"],
|
|
1579
|
-
auth: "user",
|
|
1580
|
-
demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN,
|
|
1581
|
-
responseKind: "json",
|
|
1582
|
-
errors: [
|
|
1583
|
-
"auth:forbidden",
|
|
1584
|
-
"resource:not_found",
|
|
1585
|
-
"resource:conflict",
|
|
1586
|
-
"server:internal_error"
|
|
1587
|
-
]
|
|
1588
|
-
},
|
|
1589
|
-
correctGiftEmailAndResend: {
|
|
1590
|
-
path: "/sites/{siteId}/gifting/gifts/{giftId}/correct-email-and-resend",
|
|
1591
|
-
method: "POST",
|
|
1592
|
-
tags: ["site-{siteId}", "gifting-gifts-{siteId}"],
|
|
1593
|
-
auth: "user",
|
|
1594
|
-
demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN,
|
|
1595
|
-
responseKind: "json",
|
|
1596
|
-
errors: [
|
|
1597
|
-
"validation:invalid_input",
|
|
1598
|
-
"auth:forbidden",
|
|
1599
|
-
"resource:not_found",
|
|
1600
|
-
"resource:conflict",
|
|
1601
|
-
"server:internal_error"
|
|
1602
|
-
]
|
|
1603
|
-
},
|
|
1604
|
-
updateGiftingSettings: {
|
|
1605
|
-
path: "/sites/{siteId}/gifting/settings",
|
|
1606
|
-
method: "PATCH",
|
|
1607
|
-
tags: [
|
|
1608
|
-
"site-{siteId}",
|
|
1609
|
-
"gifting-offers-{siteId}",
|
|
1610
|
-
"gifting-gifts-{siteId}"
|
|
1611
|
-
],
|
|
1612
|
-
auth: "user",
|
|
1613
|
-
responseKind: "json",
|
|
1614
|
-
errors: [
|
|
1615
|
-
"validation:invalid_input",
|
|
1616
|
-
"auth:forbidden",
|
|
1617
|
-
"server:internal_error"
|
|
1618
|
-
]
|
|
1619
|
-
},
|
|
1620
|
-
listPublicGiftingOffers: {
|
|
1621
|
-
path: "/public/sites/{siteId}/gifting/offers",
|
|
1622
|
-
method: "GET",
|
|
1623
|
-
revalidate: 300,
|
|
1624
|
-
tags: [TAG_TEMPLATES.publicGifting],
|
|
1625
|
-
errors: [],
|
|
1626
|
-
auth: "public",
|
|
1627
|
-
responseKind: "json"
|
|
1628
|
-
},
|
|
1629
|
-
createPublicGiftingCheckout: {
|
|
1630
|
-
path: "/public/sites/{siteId}/gifting/checkout",
|
|
1631
|
-
method: "POST",
|
|
1632
|
-
tags: [TAG_TEMPLATES.publicGifting],
|
|
1633
|
-
errors: [],
|
|
1634
|
-
auth: "public",
|
|
1635
|
-
responseKind: "json"
|
|
1636
|
-
},
|
|
1637
|
-
claimGiftCardPublic: {
|
|
1638
|
-
path: "/public/sites/{siteId}/gifting/claim",
|
|
1639
|
-
method: "POST",
|
|
1640
|
-
tags: [TAG_TEMPLATES.publicGifting],
|
|
1641
|
-
errors: [],
|
|
1642
|
-
auth: "public",
|
|
1643
|
-
responseKind: "json"
|
|
1644
|
-
}
|
|
1645
|
-
});
|
|
1646
|
-
//#endregion
|
|
1647
|
-
//#region ../api/src/sdkEndpointDefinitions.ts
|
|
1648
|
-
/** SDK management endpoints that do not belong to a CRUD resource family. */
|
|
1649
|
-
const SDK_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
|
|
1650
|
-
sdkUpdateSettings: {
|
|
1651
|
-
path: "/sdk/{siteId}/settings",
|
|
1652
|
-
method: "PATCH",
|
|
1653
|
-
auth: "service",
|
|
1654
|
-
responseKind: "json",
|
|
1655
|
-
errors: ["validation:invalid_input", "server:internal_error"]
|
|
1656
|
-
},
|
|
1657
|
-
sdkConfigureBookingVertical: {
|
|
1658
|
-
path: "/sdk/{siteId}/settings/booking/vertical",
|
|
1659
|
-
method: "POST",
|
|
1660
|
-
auth: "service",
|
|
1661
|
-
responseKind: "json"
|
|
1662
|
-
},
|
|
1663
|
-
sdkSetupRevalidationWebhook: {
|
|
1664
|
-
path: "/sdk/{siteId}/webhooks/revalidation/setup",
|
|
1665
|
-
method: "POST",
|
|
1666
|
-
auth: "service",
|
|
1667
|
-
responseKind: "json",
|
|
1668
|
-
errors: ["validation:invalid_input", "server:internal_error"]
|
|
1669
|
-
}
|
|
1670
|
-
});
|
|
1671
|
-
//#endregion
|
|
1672
|
-
//#region ../api/src/sdkMediaEndpointDefinitions.ts
|
|
1673
|
-
/** SDK media lookup, listing, deletion and upload endpoints (management-key authenticated). */
|
|
1674
|
-
const SDK_MEDIA_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
|
|
1675
|
-
sdkMediaExists: {
|
|
1676
|
-
path: "/sdk/{siteId}/media/exists",
|
|
1677
|
-
method: "POST",
|
|
1678
|
-
errors: ["validation:invalid_input"],
|
|
1679
|
-
auth: "service",
|
|
1680
|
-
responseKind: "json"
|
|
1681
|
-
},
|
|
1682
|
-
sdkMediaFindByChecksum: {
|
|
1683
|
-
path: "/sdk/{siteId}/media/find-by-checksum",
|
|
1684
|
-
method: "POST",
|
|
1685
|
-
errors: ["server:internal_error"],
|
|
1686
|
-
auth: "service",
|
|
1687
|
-
responseKind: "json"
|
|
1688
|
-
},
|
|
1689
|
-
sdkMediaResolve: {
|
|
1690
|
-
path: "/sdk/{siteId}/media/resolve",
|
|
1691
|
-
method: "POST",
|
|
1692
|
-
errors: ["server:internal_error"],
|
|
1693
|
-
auth: "service",
|
|
1694
|
-
responseKind: "json"
|
|
1695
|
-
},
|
|
1696
|
-
sdkMediaList: {
|
|
1697
|
-
path: "/sdk/{siteId}/media",
|
|
1698
|
-
method: "GET",
|
|
1699
|
-
auth: "service",
|
|
1700
|
-
errors: [],
|
|
1701
|
-
responseKind: "json"
|
|
1702
|
-
},
|
|
1703
|
-
sdkMediaDownload: {
|
|
1704
|
-
path: "/sdk/{siteId}/media/{identifier}/download",
|
|
1705
|
-
method: "GET",
|
|
1706
|
-
auth: "service",
|
|
1707
|
-
errors: [],
|
|
1708
|
-
responseKind: "json"
|
|
1709
|
-
},
|
|
1710
|
-
sdkMediaDeletePreview: {
|
|
1711
|
-
path: "/sdk/{siteId}/media/{identifier}/delete-preview",
|
|
1712
|
-
method: "POST",
|
|
1713
|
-
auth: "service",
|
|
1714
|
-
errors: [],
|
|
1715
|
-
responseKind: "json"
|
|
1716
|
-
},
|
|
1717
|
-
sdkMediaDeleteApply: {
|
|
1718
|
-
path: "/sdk/{siteId}/media/{identifier}",
|
|
1719
|
-
method: "DELETE",
|
|
1720
|
-
auth: "service",
|
|
1721
|
-
errors: [],
|
|
1722
|
-
responseKind: "json"
|
|
1723
|
-
},
|
|
1724
|
-
sdkMediaUploadUrl: {
|
|
1725
|
-
path: "/sdk/{siteId}/media/upload-url",
|
|
1726
|
-
method: "POST",
|
|
1727
|
-
errors: [
|
|
1728
|
-
"resource:not_found",
|
|
1729
|
-
"validation:invalid_input",
|
|
1730
|
-
"resource:conflict",
|
|
1731
|
-
"validation:payload_too_large",
|
|
1732
|
-
"billing:plan_limit_exceeded",
|
|
1733
|
-
"server:internal_error"
|
|
1734
|
-
],
|
|
1735
|
-
auth: "service",
|
|
1736
|
-
responseKind: "json"
|
|
1737
|
-
},
|
|
1738
|
-
sdkMediaUploadFinalize: {
|
|
1739
|
-
path: "/sdk/{siteId}/media/upload",
|
|
1740
|
-
method: "POST",
|
|
1741
|
-
errors: [
|
|
1742
|
-
"resource:not_found",
|
|
1743
|
-
"validation:invalid_input",
|
|
1744
|
-
"resource:conflict",
|
|
1745
|
-
"validation:payload_too_large",
|
|
1746
|
-
"billing:plan_limit_exceeded",
|
|
1747
|
-
"server:internal_error"
|
|
1748
|
-
],
|
|
1749
|
-
auth: "service",
|
|
1750
|
-
responseKind: "json"
|
|
1751
|
-
}
|
|
1752
|
-
});
|
|
1753
|
-
({
|
|
1754
|
-
...ACCOUNT_ENDPOINT_DEFINITIONS,
|
|
1755
|
-
...PUBLIC_EVENT_ENDPOINT_DEFINITIONS,
|
|
1756
|
-
...GIFTING_ENDPOINT_DEFINITIONS
|
|
1757
|
-
}), 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, {
|
|
1758
|
-
...NEWSLETTER_ENDPOINT_DEFINITIONS,
|
|
1759
|
-
...APPOINTMENT_ENDPOINT_DEFINITIONS,
|
|
1760
|
-
...EVENT_SERIES_REGISTRATION_ENDPOINT_DEFINITIONS
|
|
1761
|
-
}, 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 };
|
|
1762
|
-
z.object({ refreshToken: z.string().min(1).max(4096) }).strict();
|
|
1763
|
-
z.object({
|
|
1764
|
-
accessToken: z.string().min(1).max(4096),
|
|
1765
|
-
refreshToken: z.string().min(1).max(4096)
|
|
1766
|
-
}).strict();
|
|
1767
|
-
const ACCOUNT_SITE_CURSOR_MAX_LENGTH = 2048;
|
|
1768
|
-
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})$/;
|
|
1769
|
-
/** Strict, injection-safe PostgreSQL/RFC3339 timestamp text used in cursors. */
|
|
1770
|
-
function isAccountSiteTimestamp(value) {
|
|
1771
|
-
if (typeof value !== "string") return false;
|
|
1772
|
-
const match = ACCOUNT_SITE_TIMESTAMP_PATTERN.exec(value);
|
|
1773
|
-
if (!match) return false;
|
|
1774
|
-
const [, year, month, day, hour, minute, second, , offset] = match;
|
|
1775
|
-
const date = new Date(Date.UTC(Number(year), Number(month) - 1, Number(day)));
|
|
1776
|
-
const offsetValue = offset ?? "";
|
|
1777
|
-
const offsetIsValid = offsetValue === "Z" || (() => {
|
|
1778
|
-
const offsetMatch = /^(?:[+-])(\d{2}):(\d{2})$/.exec(offsetValue);
|
|
1779
|
-
if (!offsetMatch) return false;
|
|
1780
|
-
return Number(offsetMatch[1]) <= 23 && Number(offsetMatch[2]) <= 59;
|
|
1781
|
-
})();
|
|
1782
|
-
return date.getUTCFullYear() === Number(year) && date.getUTCMonth() === Number(month) - 1 && date.getUTCDate() === Number(day) && Number(hour) <= 23 && Number(minute) <= 59 && Number(second) <= 59 && offsetIsValid;
|
|
1783
|
-
}
|
|
1784
|
-
const accountSiteTimestampSchema = z.string().refine(isAccountSiteTimestamp, { message: "Expected a strict account site timestamp" });
|
|
1785
|
-
z.enum([
|
|
1786
|
-
"managed",
|
|
1787
|
-
"headless_cms",
|
|
1788
|
-
"headless_full"
|
|
1789
|
-
]);
|
|
1790
|
-
z.object({ title: z.string().trim().min(1).max(120) });
|
|
1791
|
-
const abandonedStandardKeyIdsSchema = z.object({
|
|
1792
|
-
live: z.string().uuid().optional(),
|
|
1793
|
-
management: z.string().uuid().optional()
|
|
1794
|
-
}).strict();
|
|
1795
|
-
const abandonedPreviewKeyIdsSchema = z.object({
|
|
1796
|
-
live: z.string().uuid().optional(),
|
|
1797
|
-
management: z.string().uuid().optional(),
|
|
1798
|
-
preview: z.string().uuid().optional()
|
|
1799
|
-
}).strict();
|
|
1800
|
-
z.discriminatedUnion("operation", [
|
|
1801
|
-
z.object({
|
|
1802
|
-
operation: z.literal("issue_standard"),
|
|
1803
|
-
siteId: z.string().uuid(),
|
|
1804
|
-
operationId: z.string().uuid(),
|
|
1805
|
-
projectName: z.string().trim().min(1).max(120),
|
|
1806
|
-
abandonedKeyIds: abandonedStandardKeyIdsSchema.default({})
|
|
1807
|
-
}).strict(),
|
|
1808
|
-
z.object({
|
|
1809
|
-
operation: z.literal("issue_with_preview"),
|
|
1810
|
-
siteId: z.string().uuid(),
|
|
1811
|
-
operationId: z.string().uuid(),
|
|
1812
|
-
projectName: z.string().trim().min(1).max(120),
|
|
1813
|
-
abandonedKeyIds: abandonedPreviewKeyIdsSchema.default({})
|
|
1814
|
-
}).strict(),
|
|
1815
|
-
z.object({
|
|
1816
|
-
operation: z.literal("revalidate_standard"),
|
|
1817
|
-
siteId: z.string().uuid(),
|
|
1818
|
-
operationId: z.string().uuid(),
|
|
1819
|
-
projectName: z.string().trim().min(1).max(120),
|
|
1820
|
-
keyIds: z.object({
|
|
1821
|
-
live: z.string().uuid(),
|
|
1822
|
-
management: z.string().uuid()
|
|
1823
|
-
}).strict()
|
|
1824
|
-
}).strict(),
|
|
1825
|
-
z.object({
|
|
1826
|
-
operation: z.literal("revalidate_with_preview"),
|
|
1827
|
-
siteId: z.string().uuid(),
|
|
1828
|
-
operationId: z.string().uuid(),
|
|
1829
|
-
projectName: z.string().trim().min(1).max(120),
|
|
1830
|
-
keyIds: z.object({
|
|
1831
|
-
live: z.string().uuid(),
|
|
1832
|
-
management: z.string().uuid(),
|
|
1833
|
-
preview: z.string().uuid()
|
|
1834
|
-
}).strict()
|
|
1835
|
-
}).strict()
|
|
1836
|
-
]);
|
|
1837
|
-
z.object({
|
|
1838
|
-
cursor: z.string().min(1).max(ACCOUNT_SITE_CURSOR_MAX_LENGTH).optional(),
|
|
1839
|
-
limit: z.coerce.number().int().min(1).max(100).default(50),
|
|
1840
|
-
search: z.string().trim().min(1).max(120).optional()
|
|
1841
|
-
});
|
|
1842
|
-
//#endregion
|
|
1843
|
-
//#region ../core/src/result.ts
|
|
1844
|
-
function ok(value) {
|
|
1845
|
-
return {
|
|
1846
|
-
ok: true,
|
|
1847
|
-
value
|
|
1848
|
-
};
|
|
1849
|
-
}
|
|
1850
|
-
function err(error) {
|
|
1851
|
-
return {
|
|
1852
|
-
ok: false,
|
|
1853
|
-
error
|
|
1854
|
-
};
|
|
1855
|
-
}
|
|
1856
|
-
//#endregion
|
|
1857
|
-
//#region ../core/src/branded.ts
|
|
1858
|
-
const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
1859
|
-
function parseUuidBrand(value, unsafeConstructor) {
|
|
1860
|
-
if (typeof value !== "string") return err({ kind: "not_string" });
|
|
1861
|
-
const normalized = value.trim().toLowerCase();
|
|
1862
|
-
if (normalized.length === 0) return err({ kind: "empty_string" });
|
|
1863
|
-
if (!UUID_PATTERN.test(normalized)) return err({ kind: "invalid_uuid" });
|
|
1864
|
-
return ok(unsafeConstructor(normalized));
|
|
1865
|
-
}
|
|
1866
|
-
const unsafeAsSiteId = (id) => id;
|
|
1867
|
-
const unsafeAsApiKeyId = (id) => id;
|
|
1868
|
-
const unsafeAsEventOfferingId = (id) => id;
|
|
1869
|
-
const unsafeAsEventSeriesId = (id) => id;
|
|
1870
|
-
const unsafeAsUserId = (id) => id;
|
|
1871
|
-
const parseSiteId = (value) => parseUuidBrand(value, unsafeAsSiteId);
|
|
1872
|
-
const parseApiKeyId = (value) => parseUuidBrand(value, unsafeAsApiKeyId);
|
|
1873
|
-
const parseEventOfferingId = (value) => parseUuidBrand(value, unsafeAsEventOfferingId);
|
|
1874
|
-
const parseUserId = (value) => parseUuidBrand(value, unsafeAsUserId);
|
|
1875
|
-
const parseEventSeriesId = (value) => parseUuidBrand(value, unsafeAsEventSeriesId);
|
|
1876
|
-
//#endregion
|
|
1877
|
-
//#region ../core/src/assert-never.ts
|
|
1878
|
-
function assertNever$2(value, message = "Unexpected variant") {
|
|
1879
|
-
throw new Error(`${message}: ${String(value)}`);
|
|
1880
|
-
}
|
|
1881
|
-
//#endregion
|
|
1882
|
-
//#region ../core/src/currency-format.ts
|
|
1883
|
-
const CURRENCY_LOCALE_BY_CODE = {
|
|
1884
|
-
USD: "en-US",
|
|
1885
|
-
GBP: "en-GB",
|
|
1886
|
-
EUR: "de-DE",
|
|
1887
|
-
AUD: "en-AU",
|
|
1888
|
-
CAD: "en-CA",
|
|
1889
|
-
NZD: "en-NZ",
|
|
1890
|
-
JPY: "ja-JP",
|
|
1891
|
-
CNY: "zh-CN",
|
|
1892
|
-
CHF: "de-CH"
|
|
1893
|
-
};
|
|
1894
|
-
function resolveCurrencyLocale(currencyCode, override) {
|
|
1895
|
-
return override ?? CURRENCY_LOCALE_BY_CODE[currencyCode] ?? "en";
|
|
1896
|
-
}
|
|
1897
|
-
/**
|
|
1898
|
-
* The single currency-amount formatter for the product: minor units in,
|
|
1899
|
-
* localized string out.
|
|
1900
|
-
*
|
|
1901
|
-
* The locale is derived from the currency by default, so output is deterministic
|
|
1902
|
-
* across server and client (no SSR/hydration mismatch). All other money
|
|
1903
|
-
* formatters in the codebase should delegate here rather than constructing their
|
|
1904
|
-
* own `Intl.NumberFormat`.
|
|
1905
|
-
*/
|
|
1906
|
-
function formatCurrencyAmount(amountCents, currency, options) {
|
|
1907
|
-
const currencyCode = currency.toUpperCase();
|
|
1908
|
-
const locale = resolveCurrencyLocale(currencyCode, options?.locale);
|
|
1909
|
-
try {
|
|
1910
|
-
const exactFormatter = new Intl.NumberFormat(locale, {
|
|
1911
|
-
style: "currency",
|
|
1912
|
-
currency: currencyCode
|
|
1913
|
-
});
|
|
1914
|
-
const fractionDigits = options?.decimals === "auto" ? {
|
|
1915
|
-
minimumFractionDigits: 0,
|
|
1916
|
-
maximumFractionDigits: exactFormatter.resolvedOptions().maximumFractionDigits
|
|
1917
|
-
} : {};
|
|
1918
|
-
return new Intl.NumberFormat(locale, {
|
|
1919
|
-
style: "currency",
|
|
1920
|
-
currency: currencyCode,
|
|
1921
|
-
...fractionDigits
|
|
1922
|
-
}).format(amountCents / 100);
|
|
1923
|
-
} catch {
|
|
1924
|
-
return `${(amountCents / 100).toFixed(2)} ${currencyCode}`;
|
|
1925
|
-
}
|
|
1926
|
-
}
|
|
1927
|
-
//#endregion
|
|
1928
|
-
//#region ../core/src/planner.ts
|
|
1929
|
-
/** Default clock for production callers that do not inject time explicitly. */
|
|
1930
|
-
const systemPlanningClock = { now: () => Date.now() };
|
|
1931
|
-
/** Resolve current time as a Date from an explicit Date, injected clock, or system clock. */
|
|
1932
|
-
function resolvePlanningNowDate(input = {}) {
|
|
1933
|
-
if (input.now !== void 0) return input.now;
|
|
1934
|
-
return new Date((input.clock ?? systemPlanningClock).now());
|
|
1935
|
-
}
|
|
1936
|
-
//#endregion
|
|
1937
|
-
//#region ../core/src/event-pricing.ts
|
|
1938
|
-
/** Capacity closes booking, but does not make an otherwise eligible price unknown. */
|
|
1939
|
-
function isPublicEventPricingOptionDisplayable(option) {
|
|
1940
|
-
if (!option.isActive) return false;
|
|
1941
|
-
if (option.availability.kind === "available") return true;
|
|
1942
|
-
const reason = option.availability.reason;
|
|
1943
|
-
switch (reason) {
|
|
1944
|
-
case "sold_out":
|
|
1945
|
-
case "overallCapacityUnavailable": return true;
|
|
1946
|
-
case "inactive":
|
|
1947
|
-
case "not_on_sale_yet":
|
|
1948
|
-
case "sale_ended":
|
|
1949
|
-
case "attendance_mode_unavailable": return false;
|
|
1950
|
-
default: return assertNever$2(reason);
|
|
1951
|
-
}
|
|
1952
|
-
}
|
|
1953
|
-
function publicEventPricingDisplay(pricing) {
|
|
1954
|
-
switch (pricing.kind) {
|
|
1955
|
-
case "free":
|
|
1956
|
-
case "single":
|
|
1957
|
-
case "sliding_scale": return canonicalEventPricingDisplay(pricing);
|
|
1958
|
-
case "tiered": return resolvePricingOptionsPriceDisplay({
|
|
1959
|
-
options: pricing.options.filter(isPublicEventPricingOptionDisplayable),
|
|
1960
|
-
currency: pricing.currency,
|
|
1961
|
-
purpose: "configured"
|
|
1962
|
-
});
|
|
1963
|
-
case "external": return {
|
|
1964
|
-
kind: "external",
|
|
1965
|
-
label: pricing.label
|
|
1966
|
-
};
|
|
1967
|
-
}
|
|
1968
|
-
}
|
|
1969
|
-
function publicEventPricingType(pricing) {
|
|
1970
|
-
switch (pricing.kind) {
|
|
1971
|
-
case "free": return "free";
|
|
1972
|
-
case "single":
|
|
1973
|
-
case "tiered":
|
|
1974
|
-
case "sliding_scale": return isFreePublicEventPriceDisplay(publicEventPricingDisplay(pricing)) ? "free" : "paid";
|
|
1975
|
-
case "external": return "external";
|
|
1976
|
-
}
|
|
1977
|
-
}
|
|
1978
|
-
function isFreePublicEventPriceDisplay(display) {
|
|
1979
|
-
switch (display.kind) {
|
|
1980
|
-
case "free": return true;
|
|
1981
|
-
case "exact":
|
|
1982
|
-
case "from":
|
|
1983
|
-
case "range":
|
|
1984
|
-
case "mixed":
|
|
1985
|
-
case "unavailable":
|
|
1986
|
-
case "external": return false;
|
|
1987
|
-
}
|
|
1988
|
-
}
|
|
1989
|
-
function resolvePricingOptionSaleWindowState(option, now) {
|
|
1990
|
-
if (option.saleStartsAt !== null && option.saleStartsAt !== void 0 && new Date(option.saleStartsAt) > now) return "not_started";
|
|
1991
|
-
if (option.saleEndsAt !== null && option.saleEndsAt !== void 0 && new Date(option.saleEndsAt) < now) return "ended";
|
|
1992
|
-
return "open";
|
|
1993
|
-
}
|
|
1994
|
-
function resolvePricingOptionsPriceDisplay(input) {
|
|
1995
|
-
const now = input.purpose === "available_now" ? resolvePlanningNowDate({
|
|
1996
|
-
now: input.now,
|
|
1997
|
-
clock: input.clock
|
|
1998
|
-
}) : null;
|
|
1999
|
-
const amounts = input.options.filter((option) => option.isActive && (now === null || resolvePricingOptionSaleWindowState(option, now) === "open")).map((option) => option.priceAmount);
|
|
2000
|
-
return amounts.length === 0 ? {
|
|
2001
|
-
kind: "unavailable",
|
|
2002
|
-
currency: input.currency
|
|
2003
|
-
} : amountRangeDisplay(amounts, input.currency);
|
|
2004
|
-
}
|
|
2005
|
-
function amountRangeDisplay(amounts, currency) {
|
|
2006
|
-
const minAmount = Math.min(...amounts);
|
|
2007
|
-
const maxAmount = Math.max(...amounts);
|
|
2008
|
-
if (minAmount === maxAmount) return minAmount === 0 ? {
|
|
2009
|
-
kind: "free",
|
|
2010
|
-
currency
|
|
2011
|
-
} : {
|
|
2012
|
-
kind: "exact",
|
|
2013
|
-
amount: minAmount,
|
|
2014
|
-
currency
|
|
2015
|
-
};
|
|
2016
|
-
if (minAmount === 0) {
|
|
2017
|
-
const paidAmounts = amounts.filter((amount) => amount > 0);
|
|
2018
|
-
return {
|
|
2019
|
-
kind: "mixed",
|
|
2020
|
-
paidFromAmount: Math.min(...paidAmounts),
|
|
2021
|
-
paidToAmount: maxAmount,
|
|
2022
|
-
currency
|
|
2023
|
-
};
|
|
2024
|
-
}
|
|
2025
|
-
return {
|
|
2026
|
-
kind: "range",
|
|
2027
|
-
minAmount,
|
|
2028
|
-
maxAmount,
|
|
2029
|
-
currency
|
|
2030
|
-
};
|
|
2031
|
-
}
|
|
2032
|
-
/** Derives configured price presentation directly from canonical pricing. */
|
|
2033
|
-
function canonicalEventPricingDisplay(pricing) {
|
|
2034
|
-
switch (pricing.kind) {
|
|
2035
|
-
case "free": return {
|
|
2036
|
-
kind: "free",
|
|
2037
|
-
currency: pricing.currency
|
|
2038
|
-
};
|
|
2039
|
-
case "single": return {
|
|
2040
|
-
kind: "exact",
|
|
2041
|
-
amount: pricing.amount,
|
|
2042
|
-
currency: pricing.currency
|
|
2043
|
-
};
|
|
2044
|
-
case "sliding_scale": return pricing.minimum === pricing.maximum ? {
|
|
2045
|
-
kind: "exact",
|
|
2046
|
-
amount: pricing.maximum,
|
|
2047
|
-
currency: pricing.currency
|
|
2048
|
-
} : {
|
|
2049
|
-
kind: "range",
|
|
2050
|
-
minAmount: pricing.minimum,
|
|
2051
|
-
maxAmount: pricing.maximum,
|
|
2052
|
-
currency: pricing.currency
|
|
2053
|
-
};
|
|
2054
|
-
case "tiered": return resolvePricingOptionsPriceDisplay({
|
|
2055
|
-
options: pricing.options,
|
|
2056
|
-
currency: pricing.currency,
|
|
2057
|
-
purpose: "configured"
|
|
2058
|
-
});
|
|
2059
|
-
default: return assertNever$2(pricing);
|
|
2060
|
-
}
|
|
2061
|
-
}
|
|
2062
|
-
//#endregion
|
|
2063
|
-
//#region ../core/src/event-page-surface-subject.ts
|
|
2064
|
-
function createEventSeriesPageSurfaceSubject(eventSeriesId, bookingScope, eventDestinationMode) {
|
|
2065
|
-
const mode = eventDestinationMode ? { eventDestinationMode } : {};
|
|
2066
|
-
return bookingScope === "whole_series" ? {
|
|
2067
|
-
kind: "eventSeries",
|
|
2068
|
-
eventSeriesId,
|
|
2069
|
-
bookingScope,
|
|
2070
|
-
isWholeSeriesBooking: true,
|
|
2071
|
-
...mode
|
|
2072
|
-
} : {
|
|
2073
|
-
kind: "eventSeries",
|
|
2074
|
-
eventSeriesId,
|
|
2075
|
-
bookingScope,
|
|
2076
|
-
...mode
|
|
2077
|
-
};
|
|
2078
|
-
}
|
|
2079
|
-
function createEventOfferingPageSurfaceSubject(eventOfferingId, input) {
|
|
2080
|
-
const mode = input.eventDestinationMode ? { eventDestinationMode: input.eventDestinationMode } : {};
|
|
2081
|
-
const identity = {
|
|
2082
|
-
kind: "eventOffering",
|
|
2083
|
-
eventOfferingId,
|
|
2084
|
-
catalogueEventSeriesIds: input.catalogueEventSeriesIds
|
|
2085
|
-
};
|
|
2086
|
-
return input.bookingScope === "whole_series" ? {
|
|
2087
|
-
...identity,
|
|
2088
|
-
bookingScope: input.bookingScope,
|
|
2089
|
-
isWholeSeriesBooking: true,
|
|
2090
|
-
...mode
|
|
2091
|
-
} : {
|
|
2092
|
-
...identity,
|
|
2093
|
-
bookingScope: input.bookingScope,
|
|
2094
|
-
...mode
|
|
2095
|
-
};
|
|
2096
|
-
}
|
|
2097
|
-
/**
|
|
2098
|
-
* Read the destination mode off a wire value.
|
|
2099
|
-
*
|
|
2100
|
-
* Absent or unrecognised reads as absent, which leaves the routed Event record
|
|
2101
|
-
* as the only authority — the behaviour every caller had before the field
|
|
2102
|
-
* existed.
|
|
2103
|
-
*/
|
|
2104
|
-
function parseEventPageSurfaceDestinationMode(value) {
|
|
2105
|
-
return value === "cms-managed" || value === "system-managed" ? value : void 0;
|
|
2106
|
-
}
|
|
2107
|
-
function parseEventPageSurfaceSubject(value) {
|
|
2108
|
-
if (!isRecord$7(value)) return err({ kind: "notObject" });
|
|
2109
|
-
switch (value.kind) {
|
|
2110
|
-
case "eventSeries": {
|
|
2111
|
-
const eventSeriesId = parseEventSeriesId(value.eventSeriesId);
|
|
2112
|
-
if (!eventSeriesId.ok) return err({
|
|
2113
|
-
kind: "invalidEventSeriesId",
|
|
2114
|
-
error: eventSeriesId.error
|
|
2115
|
-
});
|
|
2116
|
-
if (value.bookingScope !== "single_occurrence" && value.bookingScope !== "whole_series") return err({
|
|
2117
|
-
kind: "invalidEventSeriesBookingScope",
|
|
2118
|
-
bookingScope: value.bookingScope
|
|
2119
|
-
});
|
|
2120
|
-
return ok(createEventSeriesPageSurfaceSubject(eventSeriesId.value, value.bookingScope, parseEventPageSurfaceDestinationMode(value.eventDestinationMode)));
|
|
2121
|
-
}
|
|
2122
|
-
case "eventOffering": {
|
|
2123
|
-
const eventOfferingId = parseEventOfferingId(value.eventOfferingId);
|
|
2124
|
-
if (!eventOfferingId.ok) return err({
|
|
2125
|
-
kind: "invalidEventOfferingId",
|
|
2126
|
-
error: eventOfferingId.error
|
|
2127
|
-
});
|
|
2128
|
-
if (!Array.isArray(value.catalogueEventSeriesIds)) return err({
|
|
2129
|
-
kind: "invalidEventOfferingCatalogue",
|
|
2130
|
-
catalogue: value.catalogueEventSeriesIds
|
|
2131
|
-
});
|
|
2132
|
-
if (value.bookingScope !== "single_occurrence" && value.bookingScope !== "whole_series") return err({
|
|
2133
|
-
kind: "invalidEventOfferingBookingScope",
|
|
2134
|
-
bookingScope: value.bookingScope
|
|
2135
|
-
});
|
|
2136
|
-
const parsedCatalogueIds = parseEventSeriesIdList(value.catalogueEventSeriesIds);
|
|
2137
|
-
if (!parsedCatalogueIds.ok) return parsedCatalogueIds;
|
|
2138
|
-
const eventDestinationMode = parseEventPageSurfaceDestinationMode(value.eventDestinationMode);
|
|
2139
|
-
return ok(createEventOfferingPageSurfaceSubject(eventOfferingId.value, {
|
|
2140
|
-
catalogueEventSeriesIds: parsedCatalogueIds.value,
|
|
2141
|
-
bookingScope: value.bookingScope,
|
|
2142
|
-
...eventDestinationMode ? { eventDestinationMode } : {}
|
|
2143
|
-
}));
|
|
2144
|
-
}
|
|
2145
|
-
default: return err({
|
|
2146
|
-
kind: "unsupportedSubject",
|
|
2147
|
-
subjectKind: value.kind
|
|
2148
|
-
});
|
|
2149
|
-
}
|
|
2150
|
-
}
|
|
2151
|
-
function parseEventSeriesIdList(values) {
|
|
2152
|
-
const parsed = [];
|
|
2153
|
-
for (const value of values) {
|
|
2154
|
-
const eventSeriesId = parseEventSeriesId(value);
|
|
2155
|
-
if (!eventSeriesId.ok) return err({
|
|
2156
|
-
kind: "invalidEventSeriesId",
|
|
2157
|
-
error: eventSeriesId.error
|
|
2158
|
-
});
|
|
2159
|
-
parsed.push(eventSeriesId.value);
|
|
2160
|
-
}
|
|
2161
|
-
return ok(parsed);
|
|
2162
|
-
}
|
|
2163
|
-
function isRecord$7(value) {
|
|
2164
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2165
|
-
}
|
|
1596
|
+
}
|
|
1597
|
+
function parseEventSeriesIdList(values) {
|
|
1598
|
+
const parsed = [];
|
|
1599
|
+
for (const value of values) {
|
|
1600
|
+
const eventSeriesId = parseEventSeriesId(value);
|
|
1601
|
+
if (!eventSeriesId.ok) return err({
|
|
1602
|
+
kind: "invalidEventSeriesId",
|
|
1603
|
+
error: eventSeriesId.error
|
|
1604
|
+
});
|
|
1605
|
+
parsed.push(eventSeriesId.value);
|
|
1606
|
+
}
|
|
1607
|
+
return ok(parsed);
|
|
1608
|
+
}
|
|
1609
|
+
function isRecord$10(value) {
|
|
1610
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1611
|
+
}
|
|
2166
1612
|
//#endregion
|
|
2167
1613
|
//#region ../core/src/booking-time-zone.ts
|
|
2168
1614
|
const TIME_ZONE_VALIDITY_CACHE_LIMIT = 100;
|
|
@@ -2330,9 +1776,379 @@ function toLocationCoordinates(value) {
|
|
|
2330
1776
|
};
|
|
2331
1777
|
}
|
|
2332
1778
|
//#endregion
|
|
2333
|
-
//#region ../core/src/
|
|
2334
|
-
|
|
2335
|
-
|
|
1779
|
+
//#region ../core/src/mailing-list-identifiers.ts
|
|
1780
|
+
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;
|
|
1781
|
+
const OPAQUE_ID_PATTERN = /^[A-Za-z0-9_-]{1,100}$/u;
|
|
1782
|
+
function parseTrimmedMatchingString(value, pattern) {
|
|
1783
|
+
if (typeof value !== "string") return null;
|
|
1784
|
+
const trimmed = value.trim();
|
|
1785
|
+
return pattern.test(trimmed) ? trimmed : null;
|
|
1786
|
+
}
|
|
1787
|
+
function parsePositiveInteger(value) {
|
|
1788
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value > 0 ? value : null;
|
|
1789
|
+
}
|
|
1790
|
+
function parseNewsletterListId(value) {
|
|
1791
|
+
return parseTrimmedMatchingString(value, UUID_PATTERN);
|
|
1792
|
+
}
|
|
1793
|
+
function parseMailchimpAudienceId(value) {
|
|
1794
|
+
return parseTrimmedMatchingString(value, OPAQUE_ID_PATTERN);
|
|
1795
|
+
}
|
|
1796
|
+
function parseMailchimpInterestId(value) {
|
|
1797
|
+
return parseTrimmedMatchingString(value, OPAQUE_ID_PATTERN);
|
|
1798
|
+
}
|
|
1799
|
+
function parseBrevoListId(value) {
|
|
1800
|
+
return parsePositiveInteger(value);
|
|
1801
|
+
}
|
|
1802
|
+
//#endregion
|
|
1803
|
+
//#region ../core/src/mailing-list-setup-parser.ts
|
|
1804
|
+
function parseMailingListGlobalForm(value) {
|
|
1805
|
+
if (!isRecord$9(value)) return formError("shape");
|
|
1806
|
+
const fields = parseGlobalFields(value.fields);
|
|
1807
|
+
if (fields === null) return formError("fields");
|
|
1808
|
+
if (typeof value.includeOptionalPhone !== "boolean") return formError("includeOptionalPhone");
|
|
1809
|
+
const buttonLabel = parseRequiredString(value.buttonLabel);
|
|
1810
|
+
if (buttonLabel === null) return formError("buttonLabel");
|
|
1811
|
+
const privacyNote = parseOptionalString(value.privacyNote);
|
|
1812
|
+
if (privacyNote === void 0) return formError("privacyNote");
|
|
1813
|
+
return ok({
|
|
1814
|
+
fields,
|
|
1815
|
+
includeOptionalPhone: value.includeOptionalPhone,
|
|
1816
|
+
buttonLabel,
|
|
1817
|
+
privacyNote
|
|
1818
|
+
});
|
|
1819
|
+
}
|
|
1820
|
+
function parseGlobalFields(value) {
|
|
1821
|
+
if (!isRecord$9(value) || typeof value.preset !== "string") return null;
|
|
1822
|
+
switch (value.preset) {
|
|
1823
|
+
case "emailOnly": return { preset: "emailOnly" };
|
|
1824
|
+
case "emailName": return isRequirement(value.name) ? {
|
|
1825
|
+
preset: "emailName",
|
|
1826
|
+
name: value.name
|
|
1827
|
+
} : null;
|
|
1828
|
+
case "emailFirstLast": return isRequirement(value.firstName) && isRequirement(value.lastName) ? {
|
|
1829
|
+
preset: "emailFirstLast",
|
|
1830
|
+
firstName: value.firstName,
|
|
1831
|
+
lastName: value.lastName
|
|
1832
|
+
} : null;
|
|
1833
|
+
case "emailNameCompany": return isRequirement(value.name) && isRequirement(value.company) ? {
|
|
1834
|
+
preset: "emailNameCompany",
|
|
1835
|
+
name: value.name,
|
|
1836
|
+
company: value.company
|
|
1837
|
+
} : null;
|
|
1838
|
+
default: return null;
|
|
1839
|
+
}
|
|
1840
|
+
}
|
|
1841
|
+
function parseMailingListSetupRevision(value) {
|
|
1842
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value > 0 ? value : null;
|
|
1843
|
+
}
|
|
1844
|
+
function parseRequiredString(value) {
|
|
1845
|
+
if (typeof value !== "string") return null;
|
|
1846
|
+
const trimmed = value.trim();
|
|
1847
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
1848
|
+
}
|
|
1849
|
+
function parseOptionalString(value) {
|
|
1850
|
+
if (value === null || value === void 0) return null;
|
|
1851
|
+
if (typeof value !== "string") return void 0;
|
|
1852
|
+
const trimmed = value.trim();
|
|
1853
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
1854
|
+
}
|
|
1855
|
+
function isRequirement(value) {
|
|
1856
|
+
return value === "required" || value === "optional";
|
|
1857
|
+
}
|
|
1858
|
+
function isRecord$9(value) {
|
|
1859
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1860
|
+
}
|
|
1861
|
+
function formError(field) {
|
|
1862
|
+
return err({
|
|
1863
|
+
tag: "invalid_mailing_list_global_form",
|
|
1864
|
+
field
|
|
1865
|
+
});
|
|
1866
|
+
}
|
|
1867
|
+
//#endregion
|
|
1868
|
+
//#region ../core/src/mailing-list-targeting.ts
|
|
1869
|
+
function planMailingListChoicePresentation(targeting) {
|
|
1870
|
+
if (targeting.mode === "default" || targeting.selection.tag === "fixed") return { tag: "hidden" };
|
|
1871
|
+
switch (targeting.provider) {
|
|
1872
|
+
case "native": return targeting.selection.offeredTopicIds.length === 1 ? {
|
|
1873
|
+
tag: "automatic",
|
|
1874
|
+
selection: {
|
|
1875
|
+
provider: "native",
|
|
1876
|
+
topicIds: targeting.selection.offeredTopicIds
|
|
1877
|
+
}
|
|
1878
|
+
} : {
|
|
1879
|
+
tag: "visitor_choice",
|
|
1880
|
+
provider: "native",
|
|
1881
|
+
optionCount: targeting.selection.offeredTopicIds.length
|
|
1882
|
+
};
|
|
1883
|
+
case "brevo": return targeting.selection.offeredListIds.length === 1 ? {
|
|
1884
|
+
tag: "automatic",
|
|
1885
|
+
selection: {
|
|
1886
|
+
provider: "brevo",
|
|
1887
|
+
listIds: targeting.selection.offeredListIds
|
|
1888
|
+
}
|
|
1889
|
+
} : {
|
|
1890
|
+
tag: "visitor_choice",
|
|
1891
|
+
provider: "brevo",
|
|
1892
|
+
optionCount: targeting.selection.offeredListIds.length
|
|
1893
|
+
};
|
|
1894
|
+
case "mailchimp": return targeting.selection.offeredInterestIds.length === 1 ? {
|
|
1895
|
+
tag: "automatic",
|
|
1896
|
+
selection: {
|
|
1897
|
+
provider: "mailchimp",
|
|
1898
|
+
interestIds: targeting.selection.offeredInterestIds
|
|
1899
|
+
}
|
|
1900
|
+
} : {
|
|
1901
|
+
tag: "visitor_choice",
|
|
1902
|
+
provider: "mailchimp",
|
|
1903
|
+
optionCount: targeting.selection.offeredInterestIds.length
|
|
1904
|
+
};
|
|
1905
|
+
}
|
|
1906
|
+
}
|
|
1907
|
+
//#endregion
|
|
1908
|
+
//#region ../core/src/mailing-list-runtime.ts
|
|
1909
|
+
function parseMailingListRuntimeContext(value) {
|
|
1910
|
+
if (!isRecord$8(value)) return invalidRuntimeContext();
|
|
1911
|
+
if (value.tag === "not_configured") return ok({ tag: "not_configured" });
|
|
1912
|
+
if (value.tag !== "configured") return invalidRuntimeContext();
|
|
1913
|
+
const revision = parseMailingListSetupRevision(value.revision);
|
|
1914
|
+
const form = parseMailingListGlobalForm(value.form);
|
|
1915
|
+
const provider = parseRuntimeProvider(value.provider);
|
|
1916
|
+
if (revision === null || !form.ok || provider === null) return invalidRuntimeContext();
|
|
1917
|
+
return ok({
|
|
1918
|
+
tag: "configured",
|
|
1919
|
+
revision,
|
|
1920
|
+
form: form.value,
|
|
1921
|
+
provider
|
|
1922
|
+
});
|
|
1923
|
+
}
|
|
1924
|
+
function parseRuntimeProvider(value) {
|
|
1925
|
+
if (!isRecord$8(value)) return null;
|
|
1926
|
+
switch (value.provider) {
|
|
1927
|
+
case "native": return parseNativeRuntimeProvider(value);
|
|
1928
|
+
case "brevo": return parseBrevoRuntimeProvider(value);
|
|
1929
|
+
case "mailchimp": return parseMailchimpRuntimeProvider(value);
|
|
1930
|
+
default: return null;
|
|
1931
|
+
}
|
|
1932
|
+
}
|
|
1933
|
+
function parseNativeRuntimeProvider(value) {
|
|
1934
|
+
const defaultTopicId = parseNewsletterListId(value.defaultTopicId);
|
|
1935
|
+
const topics = parseNamedItems(value.topics, parseNewsletterListId);
|
|
1936
|
+
return defaultTopicId !== null && topics !== null ? {
|
|
1937
|
+
provider: "native",
|
|
1938
|
+
defaultTopicId,
|
|
1939
|
+
topics
|
|
1940
|
+
} : null;
|
|
1941
|
+
}
|
|
1942
|
+
function parseBrevoRuntimeProvider(value) {
|
|
1943
|
+
const defaultListId = parseBrevoListId(value.defaultListId);
|
|
1944
|
+
const lists = parseNamedItems(value.lists, parseBrevoListId);
|
|
1945
|
+
return defaultListId !== null && lists !== null ? {
|
|
1946
|
+
provider: "brevo",
|
|
1947
|
+
defaultListId,
|
|
1948
|
+
lists
|
|
1949
|
+
} : null;
|
|
1950
|
+
}
|
|
1951
|
+
function parseMailchimpRuntimeProvider(value) {
|
|
1952
|
+
if (!Array.isArray(value.audiences)) return null;
|
|
1953
|
+
const defaultAudienceId = parseMailchimpAudienceId(value.defaultAudienceId);
|
|
1954
|
+
if (defaultAudienceId === null) return null;
|
|
1955
|
+
const audiences = [];
|
|
1956
|
+
for (const audience of value.audiences) {
|
|
1957
|
+
if (!isRecord$8(audience)) return null;
|
|
1958
|
+
const id = parseMailchimpAudienceId(audience.id);
|
|
1959
|
+
const name = parseName(audience.name);
|
|
1960
|
+
if (id === null || name === null || !Array.isArray(audience.interests)) return null;
|
|
1961
|
+
const interests = parseMailchimpInterests(audience.interests);
|
|
1962
|
+
if (interests === null) return null;
|
|
1963
|
+
audiences.push({
|
|
1964
|
+
id,
|
|
1965
|
+
name,
|
|
1966
|
+
interests
|
|
1967
|
+
});
|
|
1968
|
+
}
|
|
1969
|
+
return {
|
|
1970
|
+
provider: "mailchimp",
|
|
1971
|
+
defaultAudienceId,
|
|
1972
|
+
audiences
|
|
1973
|
+
};
|
|
1974
|
+
}
|
|
1975
|
+
function parseMailchimpInterests(value) {
|
|
1976
|
+
const interests = [];
|
|
1977
|
+
for (const interest of value) {
|
|
1978
|
+
if (!isRecord$8(interest)) return null;
|
|
1979
|
+
const id = parseMailchimpInterestId(interest.id);
|
|
1980
|
+
const name = parseName(interest.name);
|
|
1981
|
+
const categoryName = parseName(interest.categoryName);
|
|
1982
|
+
if (id === null || name === null || categoryName === null) return null;
|
|
1983
|
+
interests.push({
|
|
1984
|
+
id,
|
|
1985
|
+
name,
|
|
1986
|
+
categoryName
|
|
1987
|
+
});
|
|
1988
|
+
}
|
|
1989
|
+
return interests;
|
|
1990
|
+
}
|
|
1991
|
+
function parseNamedItems(value, parseId) {
|
|
1992
|
+
if (!Array.isArray(value)) return null;
|
|
1993
|
+
const items = [];
|
|
1994
|
+
for (const item of value) {
|
|
1995
|
+
if (!isRecord$8(item)) return null;
|
|
1996
|
+
const id = parseId(item.id);
|
|
1997
|
+
const name = parseName(item.name);
|
|
1998
|
+
if (id === null || name === null) return null;
|
|
1999
|
+
items.push({
|
|
2000
|
+
id,
|
|
2001
|
+
name
|
|
2002
|
+
});
|
|
2003
|
+
}
|
|
2004
|
+
return items;
|
|
2005
|
+
}
|
|
2006
|
+
function parseName(value) {
|
|
2007
|
+
if (typeof value !== "string") return null;
|
|
2008
|
+
const name = value.trim();
|
|
2009
|
+
return name.length > 0 ? name : null;
|
|
2010
|
+
}
|
|
2011
|
+
function isRecord$8(value) {
|
|
2012
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2013
|
+
}
|
|
2014
|
+
function invalidRuntimeContext() {
|
|
2015
|
+
return err({ tag: "invalid_mailing_list_runtime_context" });
|
|
2016
|
+
}
|
|
2017
|
+
//#endregion
|
|
2018
|
+
//#region ../core/src/mailing-list-targeting-parser.ts
|
|
2019
|
+
function parseMailingListPlacementTargeting(value) {
|
|
2020
|
+
if (!isRecord$7(value)) return targetingError("shape");
|
|
2021
|
+
if (value.mode === "default") return ok({ mode: "default" });
|
|
2022
|
+
if (value.mode !== "custom") return targetingError("mode");
|
|
2023
|
+
if (!isRecord$7(value.selection)) return targetingError("selection");
|
|
2024
|
+
switch (value.provider) {
|
|
2025
|
+
case "native": return parseNativeTargeting(value.selection);
|
|
2026
|
+
case "brevo": return parseBrevoTargeting(value.selection);
|
|
2027
|
+
case "mailchimp": return parseMailchimpTargeting(value, value.selection);
|
|
2028
|
+
default: return targetingError("provider");
|
|
2029
|
+
}
|
|
2030
|
+
}
|
|
2031
|
+
function parseNativeTargeting(selection) {
|
|
2032
|
+
if (selection.tag === "fixed") {
|
|
2033
|
+
const topicIds = parseNonEmptyUniqueIds(selection.topicIds, parseNewsletterListId);
|
|
2034
|
+
return topicIds.ok ? ok({
|
|
2035
|
+
mode: "custom",
|
|
2036
|
+
provider: "native",
|
|
2037
|
+
selection: {
|
|
2038
|
+
tag: "fixed",
|
|
2039
|
+
topicIds: topicIds.value
|
|
2040
|
+
}
|
|
2041
|
+
}) : topicIds;
|
|
2042
|
+
}
|
|
2043
|
+
if (selection.tag === "visitor_choice") {
|
|
2044
|
+
const offeredTopicIds = parseNonEmptyUniqueIds(selection.offeredTopicIds, parseNewsletterListId);
|
|
2045
|
+
return offeredTopicIds.ok ? ok({
|
|
2046
|
+
mode: "custom",
|
|
2047
|
+
provider: "native",
|
|
2048
|
+
selection: {
|
|
2049
|
+
tag: "visitor_choice",
|
|
2050
|
+
offeredTopicIds: offeredTopicIds.value
|
|
2051
|
+
}
|
|
2052
|
+
}) : offeredTopicIds;
|
|
2053
|
+
}
|
|
2054
|
+
return targetingError("selection");
|
|
2055
|
+
}
|
|
2056
|
+
function parseBrevoTargeting(selection) {
|
|
2057
|
+
if (selection.tag === "fixed") {
|
|
2058
|
+
const listIds = parseNonEmptyUniqueIds(selection.listIds, parseBrevoListId);
|
|
2059
|
+
return listIds.ok ? ok({
|
|
2060
|
+
mode: "custom",
|
|
2061
|
+
provider: "brevo",
|
|
2062
|
+
selection: {
|
|
2063
|
+
tag: "fixed",
|
|
2064
|
+
listIds: listIds.value
|
|
2065
|
+
}
|
|
2066
|
+
}) : listIds;
|
|
2067
|
+
}
|
|
2068
|
+
if (selection.tag === "visitor_choice") {
|
|
2069
|
+
const offeredListIds = parseNonEmptyUniqueIds(selection.offeredListIds, parseBrevoListId);
|
|
2070
|
+
return offeredListIds.ok ? ok({
|
|
2071
|
+
mode: "custom",
|
|
2072
|
+
provider: "brevo",
|
|
2073
|
+
selection: {
|
|
2074
|
+
tag: "visitor_choice",
|
|
2075
|
+
offeredListIds: offeredListIds.value
|
|
2076
|
+
}
|
|
2077
|
+
}) : offeredListIds;
|
|
2078
|
+
}
|
|
2079
|
+
return targetingError("selection");
|
|
2080
|
+
}
|
|
2081
|
+
function parseMailchimpTargeting(value, selection) {
|
|
2082
|
+
const audienceId = parseMailchimpAudienceId(value.audienceId);
|
|
2083
|
+
if (audienceId === null) return targetingError("audienceId");
|
|
2084
|
+
if (selection.tag === "fixed") {
|
|
2085
|
+
const interestIds = parseUniqueIds(selection.interestIds, parseMailchimpInterestId);
|
|
2086
|
+
return interestIds.ok ? ok({
|
|
2087
|
+
mode: "custom",
|
|
2088
|
+
provider: "mailchimp",
|
|
2089
|
+
audienceId,
|
|
2090
|
+
selection: {
|
|
2091
|
+
tag: "fixed",
|
|
2092
|
+
interestIds: interestIds.value
|
|
2093
|
+
}
|
|
2094
|
+
}) : interestIds;
|
|
2095
|
+
}
|
|
2096
|
+
if (selection.tag === "visitor_choice") {
|
|
2097
|
+
const offeredInterestIds = parseNonEmptyUniqueIds(selection.offeredInterestIds, parseMailchimpInterestId);
|
|
2098
|
+
return offeredInterestIds.ok ? ok({
|
|
2099
|
+
mode: "custom",
|
|
2100
|
+
provider: "mailchimp",
|
|
2101
|
+
audienceId,
|
|
2102
|
+
selection: {
|
|
2103
|
+
tag: "visitor_choice",
|
|
2104
|
+
offeredInterestIds: offeredInterestIds.value
|
|
2105
|
+
}
|
|
2106
|
+
}) : offeredInterestIds;
|
|
2107
|
+
}
|
|
2108
|
+
return targetingError("selection");
|
|
2109
|
+
}
|
|
2110
|
+
function parseNonEmptyUniqueIds(value, parseId) {
|
|
2111
|
+
const parsed = parseUniqueIds(value, parseId);
|
|
2112
|
+
if (!parsed.ok) return parsed;
|
|
2113
|
+
const [first, ...rest] = parsed.value;
|
|
2114
|
+
return first === void 0 ? targetingError("targets") : ok([first, ...rest]);
|
|
2115
|
+
}
|
|
2116
|
+
function parseUniqueIds(value, parseId) {
|
|
2117
|
+
if (!Array.isArray(value)) return targetingError("targets");
|
|
2118
|
+
const parsed = [];
|
|
2119
|
+
for (const item of value) {
|
|
2120
|
+
const id = parseId(item);
|
|
2121
|
+
if (id === null) return targetingError("targets");
|
|
2122
|
+
if (parsed.includes(id)) return targetingError("duplicate_target");
|
|
2123
|
+
parsed.push(id);
|
|
2124
|
+
}
|
|
2125
|
+
return ok(parsed);
|
|
2126
|
+
}
|
|
2127
|
+
function isRecord$7(value) {
|
|
2128
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2129
|
+
}
|
|
2130
|
+
function targetingError(field) {
|
|
2131
|
+
return err({
|
|
2132
|
+
tag: "invalid_mailing_list_targeting",
|
|
2133
|
+
field
|
|
2134
|
+
});
|
|
2135
|
+
}
|
|
2136
|
+
//#endregion
|
|
2137
|
+
//#region ../core/src/mailing-list-submission.ts
|
|
2138
|
+
function parseMailingListBlockId(value) {
|
|
2139
|
+
const parsed = typeof value === "string" ? value.trim() : "";
|
|
2140
|
+
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;
|
|
2141
|
+
}
|
|
2142
|
+
function parseMailingListSignedSourceToken(value) {
|
|
2143
|
+
const parsed = typeof value === "string" ? value.trim() : "";
|
|
2144
|
+
return /^[A-Za-z0-9._~-]{16,1000}$/u.test(parsed) ? parsed : null;
|
|
2145
|
+
}
|
|
2146
|
+
function buildMailingListSignupBlockSourceRef(blockId) {
|
|
2147
|
+
const parsed = parseMailingListBlockId(blockId);
|
|
2148
|
+
return parsed !== null ? {
|
|
2149
|
+
tag: "block_ref",
|
|
2150
|
+
blockId: parsed
|
|
2151
|
+
} : null;
|
|
2336
2152
|
}
|
|
2337
2153
|
//#endregion
|
|
2338
2154
|
//#region ../core/src/secret.ts
|
|
@@ -2373,320 +2189,1111 @@ function createSecretInternal(kind, value) {
|
|
|
2373
2189
|
return Object.freeze(secret);
|
|
2374
2190
|
}
|
|
2375
2191
|
/**
|
|
2376
|
-
* Parse an untrusted management API key before constructing its Secret value.
|
|
2192
|
+
* Parse an untrusted management API key before constructing its Secret value.
|
|
2193
|
+
*
|
|
2194
|
+
* The Secret type protects an already validated value from accidental
|
|
2195
|
+
* disclosure; this boundary is what validates the value's wire format.
|
|
2196
|
+
*/
|
|
2197
|
+
function parseManagementKey(raw) {
|
|
2198
|
+
if (typeof raw !== "string" || !raw.startsWith("bld_mgmt_sk_") || raw.length === 12) return err({ kind: "invalid-management-key" });
|
|
2199
|
+
return ok(createSecretInternal("management-key", raw));
|
|
2200
|
+
}
|
|
2201
|
+
function sessionStartMs(session) {
|
|
2202
|
+
return Date.parse(session.startsAt);
|
|
2203
|
+
}
|
|
2204
|
+
/**
|
|
2205
|
+
* The run's sessions that still count, in schedule order.
|
|
2206
|
+
*
|
|
2207
|
+
* Sessions whose start cannot be read are dropped rather than sorted to an
|
|
2208
|
+
* arbitrary end: an unparseable date is not a date a visitor can attend.
|
|
2209
|
+
*/
|
|
2210
|
+
function orderedLiveRunSessions(sessions) {
|
|
2211
|
+
return sessions.filter((session) => session.status !== "cancelled" && Number.isFinite(sessionStartMs(session))).sort((left, right) => sessionStartMs(left) - sessionStartMs(right));
|
|
2212
|
+
}
|
|
2213
|
+
const PUBLIC_CONTENT_FRESHNESS_SECONDS = 3600;
|
|
2214
|
+
function availability(transport) {
|
|
2215
|
+
return {
|
|
2216
|
+
kind: "live",
|
|
2217
|
+
reason: "booking_correctness",
|
|
2218
|
+
freshness: "availability",
|
|
2219
|
+
transport
|
|
2220
|
+
};
|
|
2221
|
+
}
|
|
2222
|
+
function content(tags, transport = "direct") {
|
|
2223
|
+
return {
|
|
2224
|
+
kind: "tagged",
|
|
2225
|
+
tags,
|
|
2226
|
+
freshness: "content",
|
|
2227
|
+
transport
|
|
2228
|
+
};
|
|
2229
|
+
}
|
|
2230
|
+
/** The single classification authority for cacheable public reads. */
|
|
2231
|
+
const PUBLIC_READ_CACHE_POLICIES = {
|
|
2232
|
+
listPublishedEntries: content(["published_content"]),
|
|
2233
|
+
getPublishedEntryPreview: content(["published_content"]),
|
|
2234
|
+
listPublicEvents: availability("direct"),
|
|
2235
|
+
listPublicEventCalendarWindow: availability("direct"),
|
|
2236
|
+
listPublicRecurringSchedule: availability("batch_only"),
|
|
2237
|
+
getPublicEventDetails: availability("batch_only"),
|
|
2238
|
+
resolveEventSubroute: availability("direct"),
|
|
2239
|
+
listPublicRouteCandidates: content(["published_content"], "batch_only"),
|
|
2240
|
+
listPublicTeamMembers: content(["public_team_members"]),
|
|
2241
|
+
listPublicProducts: availability("direct"),
|
|
2242
|
+
listPublicPasses: availability("direct"),
|
|
2243
|
+
listPublicMemberships: availability("direct"),
|
|
2244
|
+
getPublicFormById: content(["site_forms"]),
|
|
2245
|
+
getPublicBookingServices: availability("direct"),
|
|
2246
|
+
getPublicBookingService: availability("direct"),
|
|
2247
|
+
getPublicBookingResourcesReference: availability("direct"),
|
|
2248
|
+
getPublicBookingAvailableDates: availability("direct"),
|
|
2249
|
+
getPublicBookingAvailableSlots: availability("direct"),
|
|
2250
|
+
getPublicWeeklySlotAvailability: availability("direct"),
|
|
2251
|
+
listPublicForms: content(["site_forms"]),
|
|
2252
|
+
checkRedirect: content([]),
|
|
2253
|
+
getPublicRoutableContent: content(["published_content"]),
|
|
2254
|
+
getPublicSitemapRoutes: content(["published_content"])
|
|
2255
|
+
};
|
|
2256
|
+
new Set(Object.keys(PUBLIC_READ_CACHE_POLICIES));
|
|
2257
|
+
function getPublicReadCachePolicy(endpoint) {
|
|
2258
|
+
return PUBLIC_READ_CACHE_POLICIES[endpoint];
|
|
2259
|
+
}
|
|
2260
|
+
function publicReadFreshnessSeconds(endpoint) {
|
|
2261
|
+
return getPublicReadCachePolicy(endpoint).freshness === "availability" ? 60 : PUBLIC_CONTENT_FRESHNESS_SECONDS;
|
|
2262
|
+
}
|
|
2263
|
+
//#endregion
|
|
2264
|
+
//#region ../core/src/event-series-behaviour.ts
|
|
2265
|
+
const WHOLE_SERIES_EVENT_PRESET_VALUES = ["course", "term"];
|
|
2266
|
+
const SURFACE_EVENT_PRESET_VALUES = [
|
|
2267
|
+
"class",
|
|
2268
|
+
"course",
|
|
2269
|
+
"term",
|
|
2270
|
+
"workshop",
|
|
2271
|
+
"retreat",
|
|
2272
|
+
"performance"
|
|
2273
|
+
];
|
|
2274
|
+
//#endregion
|
|
2275
|
+
//#region ../core/src/booking-vertical-preset.ts
|
|
2276
|
+
const BOOKING_ENGINE_BY_BEHAVIOUR = {
|
|
2277
|
+
class: "event_series",
|
|
2278
|
+
workshop: "event_series",
|
|
2279
|
+
course: "event_series",
|
|
2280
|
+
retreat: "event_series",
|
|
2281
|
+
performance: "event_series",
|
|
2282
|
+
appointment: "appointment_service"
|
|
2283
|
+
};
|
|
2284
|
+
function verticalBookingPreset(id, verticalId, canonicalBehaviour, label, pluralLabel, description, availability = "onboarding") {
|
|
2285
|
+
return {
|
|
2286
|
+
id,
|
|
2287
|
+
verticalId,
|
|
2288
|
+
canonicalBehaviour,
|
|
2289
|
+
engine: BOOKING_ENGINE_BY_BEHAVIOUR[canonicalBehaviour],
|
|
2290
|
+
availability,
|
|
2291
|
+
label,
|
|
2292
|
+
pluralLabel,
|
|
2293
|
+
description
|
|
2294
|
+
};
|
|
2295
|
+
}
|
|
2296
|
+
//#endregion
|
|
2297
|
+
//#region ../core/src/booking-vertical-definitions.ts
|
|
2298
|
+
const VERTICAL_DEFINITIONS = [
|
|
2299
|
+
{
|
|
2300
|
+
id: "yoga_wellness",
|
|
2301
|
+
label: "Yoga, meditation or mindfulness",
|
|
2302
|
+
description: "Yoga studios, wellness teachers, and movement practitioners."
|
|
2303
|
+
},
|
|
2304
|
+
{
|
|
2305
|
+
id: "fitness_pt",
|
|
2306
|
+
label: "Fitness and personal training",
|
|
2307
|
+
description: "Personal trainers, group training, and fitness programmes."
|
|
2308
|
+
},
|
|
2309
|
+
{
|
|
2310
|
+
id: "dance_school",
|
|
2311
|
+
label: "Dance school",
|
|
2312
|
+
description: "Dance classes, courses or terms, workshops, private lessons, and shows."
|
|
2313
|
+
},
|
|
2314
|
+
{
|
|
2315
|
+
id: "physiotherapy_physical_health",
|
|
2316
|
+
label: "Physiotherapy & physical health",
|
|
2317
|
+
description: "Physiotherapists, chiropractors, osteopaths, sports therapists, and rehabilitation practitioners."
|
|
2318
|
+
},
|
|
2319
|
+
{
|
|
2320
|
+
id: "massage_bodywork",
|
|
2321
|
+
label: "Massage & bodywork",
|
|
2322
|
+
description: "Massage therapists, bodyworkers, and somatic practitioners."
|
|
2323
|
+
},
|
|
2324
|
+
{
|
|
2325
|
+
id: "therapist_practitioner",
|
|
2326
|
+
label: "Therapist or practitioner",
|
|
2327
|
+
description: "Appointments, sessions, consultations, and occasional group work."
|
|
2328
|
+
},
|
|
2329
|
+
{
|
|
2330
|
+
id: "beauty_spa",
|
|
2331
|
+
label: "Beauty or spa",
|
|
2332
|
+
description: "Treatment-led businesses with optional workshops."
|
|
2333
|
+
},
|
|
2334
|
+
{
|
|
2335
|
+
id: "consultant_coach",
|
|
2336
|
+
label: "Consultant or coach",
|
|
2337
|
+
description: "One-to-one calls, workshops, courses, and retreats."
|
|
2338
|
+
},
|
|
2339
|
+
{
|
|
2340
|
+
id: "training_provider",
|
|
2341
|
+
label: "Training provider",
|
|
2342
|
+
description: "Courses, workshops, classes, appointments, and residential training."
|
|
2343
|
+
},
|
|
2344
|
+
{
|
|
2345
|
+
id: "retreat_centre",
|
|
2346
|
+
label: "Retreat centre",
|
|
2347
|
+
description: "Residential retreats, workshops, classes, courses, and private sessions."
|
|
2348
|
+
},
|
|
2349
|
+
{
|
|
2350
|
+
id: "music_school",
|
|
2351
|
+
label: "Music teacher or school",
|
|
2352
|
+
description: "Lessons, classes, terms, workshops, and performances."
|
|
2353
|
+
},
|
|
2354
|
+
{
|
|
2355
|
+
id: "voice_singing",
|
|
2356
|
+
label: "Voice & Singing",
|
|
2357
|
+
description: "Singing lessons, choirs, voice circles, workshops, and performances."
|
|
2358
|
+
},
|
|
2359
|
+
{
|
|
2360
|
+
id: "performing_arts_school",
|
|
2361
|
+
label: "Theatre or performing arts school",
|
|
2362
|
+
description: "Classes, terms, workshops, performances, and lessons."
|
|
2363
|
+
},
|
|
2364
|
+
{
|
|
2365
|
+
id: "community_wellbeing",
|
|
2366
|
+
label: "Community or wellbeing centre",
|
|
2367
|
+
description: "Groups, workshops, courses, appointments, and retreats."
|
|
2368
|
+
},
|
|
2369
|
+
{
|
|
2370
|
+
id: "venue_event_space",
|
|
2371
|
+
label: "Venue or event space",
|
|
2372
|
+
description: "Room, resource, or access bookings. Depends on the future capacity-booking domain."
|
|
2373
|
+
}
|
|
2374
|
+
];
|
|
2375
|
+
VERTICAL_DEFINITIONS.map(({ id }) => id);
|
|
2376
|
+
//#endregion
|
|
2377
|
+
//#region ../core/src/booking-vertical-catalog.ts
|
|
2378
|
+
const VERTICAL_BOOKING_PRESETS = [
|
|
2379
|
+
verticalBookingPreset("yoga_wellness.classes", "yoga_wellness", "class", "Class", "Classes", "Regular scheduled classes and group sessions."),
|
|
2380
|
+
verticalBookingPreset("yoga_wellness.workshops", "yoga_wellness", "workshop", "Workshop", "Workshops", "One-off workshops, day retreats, or special sessions."),
|
|
2381
|
+
verticalBookingPreset("yoga_wellness.courses", "yoga_wellness", "course", "Course", "Courses", "Fixed-schedule courses or multi-session groups."),
|
|
2382
|
+
verticalBookingPreset("yoga_wellness.retreats", "yoga_wellness", "retreat", "Retreat", "Retreats", "Multi-day or residential retreats and immersive experiences."),
|
|
2383
|
+
verticalBookingPreset("yoga_wellness.appointments", "yoga_wellness", "appointment", "Appointment", "Appointments", "Private sessions, consultations, or one-to-one support."),
|
|
2384
|
+
verticalBookingPreset("fitness_pt.group_training", "fitness_pt", "class", "Group training", "Group training", "Regular scheduled classes and group sessions."),
|
|
2385
|
+
verticalBookingPreset("fitness_pt.personal_training", "fitness_pt", "appointment", "Personal training", "Personal training", "One-to-one sessions booked from your availability."),
|
|
2386
|
+
verticalBookingPreset("fitness_pt.programmes", "fitness_pt", "course", "Programme", "Programmes", "Multi-session programmes like bootcamps or courses."),
|
|
2387
|
+
verticalBookingPreset("fitness_pt.workshops", "fitness_pt", "workshop", "Workshop", "Workshops", "One-off workshops, events, or special sessions."),
|
|
2388
|
+
verticalBookingPreset("fitness_pt.retreats", "fitness_pt", "retreat", "Retreat", "Retreats", "Multi-day or residential fitness experiences."),
|
|
2389
|
+
verticalBookingPreset("dance_school.classes", "dance_school", "class", "Class", "Classes", "Regular group classes and weekly sessions."),
|
|
2390
|
+
{
|
|
2391
|
+
...verticalBookingPreset("dance_school.terms", "dance_school", "course", "Term", "Terms", "Multi-week term blocks or fixed-date course groups."),
|
|
2392
|
+
eventPresetOverride: "term"
|
|
2393
|
+
},
|
|
2394
|
+
verticalBookingPreset("dance_school.courses", "dance_school", "course", "Course", "Courses", "Fixed-schedule courses or multi-session groups.", "settings"),
|
|
2395
|
+
verticalBookingPreset("dance_school.workshops", "dance_school", "workshop", "Workshop", "Workshops", "One-off workshops, masterclasses, or intensives."),
|
|
2396
|
+
verticalBookingPreset("dance_school.private_lessons", "dance_school", "appointment", "Private lesson", "Private lessons", "One-to-one lessons or coaching sessions."),
|
|
2397
|
+
verticalBookingPreset("dance_school.shows", "dance_school", "performance", "Show", "Shows", "Ticketed performances, showcases, and recitals."),
|
|
2398
|
+
verticalBookingPreset("physiotherapy_physical_health.appointments", "physiotherapy_physical_health", "appointment", "Appointment", "Appointments", "Assessments, treatments, follow-ups, and rehabilitation sessions."),
|
|
2399
|
+
verticalBookingPreset("physiotherapy_physical_health.rehab_classes", "physiotherapy_physical_health", "class", "Rehab class", "Rehab classes", "Regular rehabilitation, mobility, strength, or recovery classes."),
|
|
2400
|
+
verticalBookingPreset("physiotherapy_physical_health.workshops", "physiotherapy_physical_health", "workshop", "Workshop", "Workshops", "One-off workshops, talks, or practical group sessions."),
|
|
2401
|
+
verticalBookingPreset("massage_bodywork.treatments", "massage_bodywork", "appointment", "Treatment", "Treatments", "Massage treatments, bodywork sessions, and one-to-one appointments."),
|
|
2402
|
+
verticalBookingPreset("massage_bodywork.group_sessions", "massage_bodywork", "class", "Group session", "Group sessions", "Regular bodywork, somatic movement, or self-massage sessions."),
|
|
2403
|
+
verticalBookingPreset("massage_bodywork.workshops", "massage_bodywork", "workshop", "Workshop", "Workshops", "One-off bodywork, self-massage, or somatic practice workshops."),
|
|
2404
|
+
verticalBookingPreset("therapist_practitioner.appointments", "therapist_practitioner", "appointment", "Appointment", "Appointments", "Sessions, consultations, treatments, or assessments."),
|
|
2405
|
+
verticalBookingPreset("therapist_practitioner.workshops", "therapist_practitioner", "workshop", "Workshop", "Workshops", "One-off group workshops, talks, or wellbeing sessions."),
|
|
2406
|
+
verticalBookingPreset("therapist_practitioner.retreats", "therapist_practitioner", "retreat", "Retreat", "Retreats", "Multi-day retreats or immersive group experiences."),
|
|
2407
|
+
verticalBookingPreset("beauty_spa.appointments", "beauty_spa", "appointment", "Appointment", "Appointments", "Treatments, consultations, services, and sessions."),
|
|
2408
|
+
verticalBookingPreset("beauty_spa.workshops", "beauty_spa", "workshop", "Workshop", "Workshops", "Skincare workshops, makeup lessons, demos, or group events."),
|
|
2409
|
+
verticalBookingPreset("consultant_coach.appointments", "consultant_coach", "appointment", "Appointment", "Appointments", "One-to-one calls, consultations, reviews, or coaching sessions."),
|
|
2410
|
+
verticalBookingPreset("consultant_coach.workshops", "consultant_coach", "workshop", "Workshop", "Workshops", "One-off group sessions, webinars, or strategy days."),
|
|
2411
|
+
verticalBookingPreset("consultant_coach.courses", "consultant_coach", "course", "Course", "Courses", "Fixed-schedule cohorts or multi-session group programmes."),
|
|
2412
|
+
verticalBookingPreset("consultant_coach.retreats", "consultant_coach", "retreat", "Retreat", "Retreats", "Multi-day coaching retreats or immersive experiences."),
|
|
2413
|
+
verticalBookingPreset("training_provider.courses", "training_provider", "course", "Course", "Courses", "Fixed-schedule courses, cohorts, and multi-session training."),
|
|
2414
|
+
verticalBookingPreset("training_provider.workshops", "training_provider", "workshop", "Workshop", "Workshops", "One-off workshops, masterclasses, and short training sessions."),
|
|
2415
|
+
verticalBookingPreset("training_provider.appointments", "training_provider", "appointment", "Appointment", "Appointments", "Consultations, assessments, mentoring, or office hours."),
|
|
2416
|
+
verticalBookingPreset("training_provider.classes", "training_provider", "class", "Class", "Classes", "Regular classes, sessions, or groups.", "settings"),
|
|
2417
|
+
verticalBookingPreset("training_provider.residentials", "training_provider", "retreat", "Residential", "Residentials", "Residential courses or multi-day training experiences.", "settings"),
|
|
2418
|
+
verticalBookingPreset("retreat_centre.retreats", "retreat_centre", "retreat", "Retreat", "Retreats", "Multi-day or residential retreats with richer booking needs."),
|
|
2419
|
+
verticalBookingPreset("retreat_centre.workshops", "retreat_centre", "workshop", "Workshop", "Workshops", "One-day retreats, ceremonies, workshops, or special events."),
|
|
2420
|
+
verticalBookingPreset("retreat_centre.classes", "retreat_centre", "class", "Class", "Classes", "Regular sessions like guided meditations or group practices."),
|
|
2421
|
+
verticalBookingPreset("retreat_centre.courses", "retreat_centre", "course", "Course", "Courses", "Fixed-schedule programmes or multi-session experiences."),
|
|
2422
|
+
verticalBookingPreset("retreat_centre.appointments", "retreat_centre", "appointment", "Appointment", "Appointments", "Private sessions, therapies, consultations, or add-ons."),
|
|
2423
|
+
verticalBookingPreset("music_school.lessons", "music_school", "appointment", "Lesson", "Lessons", "One-to-one lessons, consultations, or coaching sessions."),
|
|
2424
|
+
verticalBookingPreset("music_school.classes", "music_school", "class", "Class", "Classes", "Regular group classes, ensembles, or recurring sessions."),
|
|
2425
|
+
{
|
|
2426
|
+
...verticalBookingPreset("music_school.terms", "music_school", "course", "Term", "Terms", "Multi-week term blocks or fixed-date group courses."),
|
|
2427
|
+
eventPresetOverride: "term"
|
|
2428
|
+
},
|
|
2429
|
+
verticalBookingPreset("music_school.workshops", "music_school", "workshop", "Workshop", "Workshops", "One-off workshops, masterclasses, or intensives."),
|
|
2430
|
+
verticalBookingPreset("music_school.performances", "music_school", "performance", "Performance", "Performances", "Concerts, recitals, showcases, or ticketed performances."),
|
|
2431
|
+
verticalBookingPreset("voice_singing.lessons", "voice_singing", "appointment", "Voice session", "Voice sessions", "One-to-one singing lessons, voice coaching, or private practice sessions."),
|
|
2432
|
+
verticalBookingPreset("voice_singing.classes", "voice_singing", "class", "Ongoing weekly session", "Ongoing weekly sessions", "Regular choirs, voice circles, community singing, or group practice."),
|
|
2433
|
+
{
|
|
2434
|
+
...verticalBookingPreset("voice_singing.terms", "voice_singing", "course", "Singing term", "Singing terms", "Multi-week choir terms, voice courses, or fixed-date group programmes."),
|
|
2435
|
+
eventPresetOverride: "term"
|
|
2436
|
+
},
|
|
2437
|
+
verticalBookingPreset("voice_singing.workshops", "voice_singing", "workshop", "Workshop", "Workshops", "One-off singing workshops, voice journeys, or devotional singing sessions."),
|
|
2438
|
+
verticalBookingPreset("voice_singing.performances", "voice_singing", "performance", "Performance", "Performances", "Choir concerts, sharing events, recitals, or community performances."),
|
|
2439
|
+
verticalBookingPreset("performing_arts_school.classes", "performing_arts_school", "class", "Class", "Classes", "Regular group classes, rehearsals, or weekly sessions."),
|
|
2440
|
+
{
|
|
2441
|
+
...verticalBookingPreset("performing_arts_school.terms", "performing_arts_school", "course", "Term", "Terms", "Multi-week term blocks or fixed-date course groups."),
|
|
2442
|
+
eventPresetOverride: "term"
|
|
2443
|
+
},
|
|
2444
|
+
verticalBookingPreset("performing_arts_school.workshops", "performing_arts_school", "workshop", "Workshop", "Workshops", "One-off workshops, masterclasses, or intensives."),
|
|
2445
|
+
verticalBookingPreset("performing_arts_school.performances", "performing_arts_school", "performance", "Performance", "Performances", "Shows, showcases, productions, or ticketed performances."),
|
|
2446
|
+
verticalBookingPreset("performing_arts_school.lessons", "performing_arts_school", "appointment", "Lesson", "Lessons", "One-to-one lessons, coaching, or audition prep."),
|
|
2447
|
+
verticalBookingPreset("community_wellbeing.classes", "community_wellbeing", "class", "Class", "Classes", "Regular groups, sessions, practices, or weekly activities."),
|
|
2448
|
+
verticalBookingPreset("community_wellbeing.workshops", "community_wellbeing", "workshop", "Workshop", "Workshops", "One-off workshops, talks, events, or gatherings."),
|
|
2449
|
+
verticalBookingPreset("community_wellbeing.courses", "community_wellbeing", "course", "Course", "Courses", "Fixed-schedule courses, study groups, or multi-session programmes."),
|
|
2450
|
+
verticalBookingPreset("community_wellbeing.appointments", "community_wellbeing", "appointment", "Appointment", "Appointments", "One-to-one appointments, consultations, or support sessions."),
|
|
2451
|
+
verticalBookingPreset("community_wellbeing.retreats", "community_wellbeing", "retreat", "Retreat", "Retreats", "Multi-day or residential retreats."),
|
|
2452
|
+
verticalBookingPreset("venue_event_space.resource_hire", "venue_event_space", "appointment", "Hire slot", "Hire slots", "Future room, venue, and resource hire bookings.", "future")
|
|
2453
|
+
];
|
|
2454
|
+
//#endregion
|
|
2455
|
+
//#region ../core/src/booking-vertical-config.ts
|
|
2456
|
+
const VERTICAL_ID_SET = new Set(VERTICAL_DEFINITIONS.map(({ id }) => id));
|
|
2457
|
+
const VERTICAL_PRESET_ID_SET = new Set(VERTICAL_BOOKING_PRESETS.map((presetDefinition) => presetDefinition.id));
|
|
2458
|
+
function parseVerticalId(value) {
|
|
2459
|
+
return typeof value === "string" && VERTICAL_ID_SET.has(value) ? value : null;
|
|
2460
|
+
}
|
|
2461
|
+
function parseVerticalPresetId(value) {
|
|
2462
|
+
return typeof value === "string" && VERTICAL_PRESET_ID_SET.has(value) ? value : null;
|
|
2463
|
+
}
|
|
2464
|
+
function getVerticalPresetDefinition(presetId) {
|
|
2465
|
+
const definition = VERTICAL_BOOKING_PRESETS.find((presetDefinition) => presetDefinition.id === presetId);
|
|
2466
|
+
if (definition === void 0) throw new Error(`Unhandled vertical preset id: ${presetId}`);
|
|
2467
|
+
return definition;
|
|
2468
|
+
}
|
|
2469
|
+
function createConfiguredSiteVerticalBookingConfig(verticalId, selectedPresetIds) {
|
|
2470
|
+
return {
|
|
2471
|
+
verticalId,
|
|
2472
|
+
selectedPresetIds
|
|
2473
|
+
};
|
|
2474
|
+
}
|
|
2475
|
+
function toNonEmptyVerticalPresetIds(presetIds) {
|
|
2476
|
+
const firstPresetId = presetIds[0];
|
|
2477
|
+
return firstPresetId ? [firstPresetId, ...presetIds.slice(1)] : null;
|
|
2478
|
+
}
|
|
2479
|
+
const DEFAULT_SITE_VERTICAL_BOOKING_CONFIG = {
|
|
2480
|
+
verticalId: null,
|
|
2481
|
+
selectedPresetIds: []
|
|
2482
|
+
};
|
|
2483
|
+
function appendUniqueIssue(issues, issue) {
|
|
2484
|
+
return issues.some((existing) => existing.code === issue.code) ? issues : [...issues, issue];
|
|
2485
|
+
}
|
|
2486
|
+
function collectRawConfigIssues(rawConfig, config) {
|
|
2487
|
+
const rawPresetValue = rawConfig.selectedPresetIds;
|
|
2488
|
+
const rawPresetIds = Array.isArray(rawPresetValue) ? rawPresetValue : [];
|
|
2489
|
+
let issues = [];
|
|
2490
|
+
if (rawConfig.verticalId != null && config.verticalId === null) issues = appendUniqueIssue(issues, {
|
|
2491
|
+
code: "unknown_vertical",
|
|
2492
|
+
rawValue: rawConfig.verticalId
|
|
2493
|
+
});
|
|
2494
|
+
if (config.verticalId === null && config.selectedPresetIds.length > 0) issues = appendUniqueIssue(issues, { code: "missing_vertical" });
|
|
2495
|
+
if (rawPresetValue !== void 0 && !Array.isArray(rawPresetValue) || rawPresetIds.some((presetId) => parseVerticalPresetId(presetId) === null)) issues = appendUniqueIssue(issues, {
|
|
2496
|
+
code: "unknown_preset",
|
|
2497
|
+
rawValue: rawPresetValue
|
|
2498
|
+
});
|
|
2499
|
+
if (rawConfig.verticalId != null && config.selectedPresetIds.length === 0) issues = appendUniqueIssue(issues, { code: "empty_selected_presets" });
|
|
2500
|
+
return issues;
|
|
2501
|
+
}
|
|
2502
|
+
function collectPresetConfigIssues(config) {
|
|
2503
|
+
const seenPresetIds = /* @__PURE__ */ new Set();
|
|
2504
|
+
const seenBehaviours = /* @__PURE__ */ new Set();
|
|
2505
|
+
let issues = [];
|
|
2506
|
+
for (const presetId of config.selectedPresetIds) {
|
|
2507
|
+
const presetDefinition = getVerticalPresetDefinition(presetId);
|
|
2508
|
+
if (seenPresetIds.has(presetId)) issues = appendUniqueIssue(issues, { code: "duplicate_preset_id" });
|
|
2509
|
+
seenPresetIds.add(presetId);
|
|
2510
|
+
if (config.verticalId !== null && presetDefinition.verticalId !== config.verticalId) issues = appendUniqueIssue(issues, { code: "preset_vertical_mismatch" });
|
|
2511
|
+
if (presetDefinition.availability === "future") issues = appendUniqueIssue(issues, { code: "future_preset_selected" });
|
|
2512
|
+
if (seenBehaviours.has(presetDefinition.canonicalBehaviour)) issues = appendUniqueIssue(issues, { code: "duplicate_canonical_behaviour" });
|
|
2513
|
+
seenBehaviours.add(presetDefinition.canonicalBehaviour);
|
|
2514
|
+
}
|
|
2515
|
+
return issues;
|
|
2516
|
+
}
|
|
2517
|
+
function getSiteVerticalConfigIssues(rawConfig, config) {
|
|
2518
|
+
let issues = collectRawConfigIssues(rawConfig, config);
|
|
2519
|
+
for (const issue of collectPresetConfigIssues(config)) issues = appendUniqueIssue(issues, issue);
|
|
2520
|
+
return issues;
|
|
2521
|
+
}
|
|
2522
|
+
function resolveSiteVerticalBookingConfig(rawConfig) {
|
|
2523
|
+
if (rawConfig == null) return {
|
|
2524
|
+
kind: "unconfigured",
|
|
2525
|
+
config: DEFAULT_SITE_VERTICAL_BOOKING_CONFIG
|
|
2526
|
+
};
|
|
2527
|
+
const verticalId = parseVerticalId(rawConfig.verticalId);
|
|
2528
|
+
const selectedPresetIds = (Array.isArray(rawConfig.selectedPresetIds) ? rawConfig.selectedPresetIds : []).map(parseVerticalPresetId).filter((presetId) => Boolean(presetId));
|
|
2529
|
+
const config = {
|
|
2530
|
+
verticalId,
|
|
2531
|
+
selectedPresetIds
|
|
2532
|
+
};
|
|
2533
|
+
if (rawConfig.verticalId == null && selectedPresetIds.length === 0) return {
|
|
2534
|
+
kind: "unconfigured",
|
|
2535
|
+
config: DEFAULT_SITE_VERTICAL_BOOKING_CONFIG
|
|
2536
|
+
};
|
|
2537
|
+
const issues = getSiteVerticalConfigIssues(rawConfig, config);
|
|
2538
|
+
if (issues.length > 0) return {
|
|
2539
|
+
kind: "invalid",
|
|
2540
|
+
config,
|
|
2541
|
+
issues
|
|
2542
|
+
};
|
|
2543
|
+
const nonEmptyPresetIds = toNonEmptyVerticalPresetIds(selectedPresetIds);
|
|
2544
|
+
const configuredConfig = verticalId !== null && nonEmptyPresetIds !== null ? createConfiguredSiteVerticalBookingConfig(verticalId, nonEmptyPresetIds) : null;
|
|
2545
|
+
if (configuredConfig === null) return {
|
|
2546
|
+
kind: "invalid",
|
|
2547
|
+
config,
|
|
2548
|
+
issues: [{ code: "empty_selected_presets" }]
|
|
2549
|
+
};
|
|
2550
|
+
return {
|
|
2551
|
+
kind: "configured",
|
|
2552
|
+
config: configuredConfig,
|
|
2553
|
+
selectedPresets: configuredConfig.selectedPresetIds.map(getVerticalPresetDefinition)
|
|
2554
|
+
};
|
|
2555
|
+
}
|
|
2556
|
+
//#endregion
|
|
2557
|
+
//#region ../api/src/publicEventEndpointDefinitions.ts
|
|
2558
|
+
const PUBLIC_EVENT_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
|
|
2559
|
+
listPublicEventCalendarWindow: {
|
|
2560
|
+
path: "/public/sites/{siteId}/events/calendar-window",
|
|
2561
|
+
method: "GET",
|
|
2562
|
+
revalidate: 0,
|
|
2563
|
+
auth: "public",
|
|
2564
|
+
responseKind: "json"
|
|
2565
|
+
},
|
|
2566
|
+
resolvePublicEventCheckoutReturn: {
|
|
2567
|
+
path: "/public/sites/{siteId}/events/checkout-return",
|
|
2568
|
+
method: "POST",
|
|
2569
|
+
tags: [TAG_TEMPLATES.publicEvents, "event-checkout"],
|
|
2570
|
+
auth: "public",
|
|
2571
|
+
responseKind: "json"
|
|
2572
|
+
},
|
|
2573
|
+
getPublicEventRegistrationOptions: {
|
|
2574
|
+
path: "/public/sites/{siteId}/events/registration-options",
|
|
2575
|
+
method: "POST",
|
|
2576
|
+
tags: [TAG_TEMPLATES.publicEvents, "event-registration-options"],
|
|
2577
|
+
auth: "public",
|
|
2578
|
+
responseKind: "json",
|
|
2579
|
+
errors: [
|
|
2580
|
+
"validation:invalid_input",
|
|
2581
|
+
"resource:not_found",
|
|
2582
|
+
"resource:conflict",
|
|
2583
|
+
"server:internal_error"
|
|
2584
|
+
]
|
|
2585
|
+
},
|
|
2586
|
+
resolveEventSubroute: {
|
|
2587
|
+
path: "/public/sites/{siteId}/events/subroutes/resolve",
|
|
2588
|
+
method: "GET",
|
|
2589
|
+
revalidate: publicReadFreshnessSeconds("resolveEventSubroute"),
|
|
2590
|
+
tags: [TAG_TEMPLATES.publicEvents, "event-subroute"],
|
|
2591
|
+
auth: "public",
|
|
2592
|
+
responseKind: "json",
|
|
2593
|
+
errors: []
|
|
2594
|
+
}
|
|
2595
|
+
});
|
|
2596
|
+
//#endregion
|
|
2597
|
+
//#region ../api/src/publicEventCheckoutEndpointDefinitions.ts
|
|
2598
|
+
/**
|
|
2599
|
+
* The public event registration/checkout endpoints, extracted from
|
|
2600
|
+
* `endpoints.ts`.
|
|
2601
|
+
*
|
|
2602
|
+
* They were moved out for the same reason the `sdkMedia*` block was: adding the
|
|
2603
|
+
* `errors` metadata `require-api-endpoint-errors` asks of a newly-added endpoint
|
|
2604
|
+
* pushed `endpoints.ts` past its `max-lines` baseline. The block is spread back
|
|
2605
|
+
* at the exact position it occupied, so `API_ENDPOINTS` key order is unchanged.
|
|
2606
|
+
* (The endpoint that originally motivated the move, `checkPublicEventEligibility`,
|
|
2607
|
+
* was since deleted on dev by #1326.)
|
|
2608
|
+
*/
|
|
2609
|
+
const PUBLIC_EVENT_CHECKOUT_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
|
|
2610
|
+
registerForEvent: {
|
|
2611
|
+
path: "/public/sites/{siteId}/events/register",
|
|
2612
|
+
method: "POST",
|
|
2613
|
+
tags: [TAG_TEMPLATES.publicEvents, "event-registration"],
|
|
2614
|
+
auth: "public",
|
|
2615
|
+
responseKind: "json"
|
|
2616
|
+
},
|
|
2617
|
+
createPublicEventCheckout: {
|
|
2618
|
+
path: "/public/sites/{siteId}/events/checkout",
|
|
2619
|
+
method: "POST",
|
|
2620
|
+
tags: [TAG_TEMPLATES.publicEvents, "event-checkout"],
|
|
2621
|
+
auth: "public",
|
|
2622
|
+
responseKind: "json"
|
|
2623
|
+
}
|
|
2624
|
+
});
|
|
2625
|
+
//#endregion
|
|
2626
|
+
//#region ../api/src/publicBookingAvailabilityEndpointDefinitions.ts
|
|
2627
|
+
/**
|
|
2628
|
+
* Public appointment reads: the service catalogue and the bookable slot grid.
|
|
2377
2629
|
*
|
|
2378
|
-
*
|
|
2379
|
-
*
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
if (typeof raw !== "string" || !raw.startsWith("bld_mgmt_sk_") || raw.length === 12) return err({ kind: "invalid-management-key" });
|
|
2383
|
-
return ok(createSecretInternal("management-key", raw));
|
|
2384
|
-
}
|
|
2385
|
-
function sessionStartMs(session) {
|
|
2386
|
-
return Date.parse(session.startsAt);
|
|
2387
|
-
}
|
|
2388
|
-
/**
|
|
2389
|
-
* The run's sessions that still count, in schedule order.
|
|
2630
|
+
* These are the reads that appointment writes invalidate. They carry canonical
|
|
2631
|
+
* `riverbank:*` tags because the frontend revalidate endpoint discards anything
|
|
2632
|
+
* else, which is why the legacy `site-{siteId}` tag they used to declare could
|
|
2633
|
+
* never actually be cleared (issue 1364).
|
|
2390
2634
|
*
|
|
2391
|
-
*
|
|
2392
|
-
*
|
|
2635
|
+
* Slot availability depends on both tags: the grid moves when a booking lands,
|
|
2636
|
+
* and again when the service definition behind it changes.
|
|
2393
2637
|
*/
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2638
|
+
const PUBLIC_BOOKING_AVAILABILITY_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
|
|
2639
|
+
getPublicBookingServices: {
|
|
2640
|
+
path: "/public/bookings/services",
|
|
2641
|
+
method: "GET",
|
|
2642
|
+
revalidate: publicReadFreshnessSeconds("getPublicBookingServices"),
|
|
2643
|
+
tags: [TAG_TEMPLATES.publicBookingServices],
|
|
2644
|
+
auth: "public",
|
|
2645
|
+
responseKind: "json"
|
|
2646
|
+
},
|
|
2647
|
+
getPublicBookingService: {
|
|
2648
|
+
path: "/public/bookings/services/{serviceId}",
|
|
2649
|
+
method: "GET",
|
|
2650
|
+
revalidate: publicReadFreshnessSeconds("getPublicBookingService"),
|
|
2651
|
+
tags: [TAG_TEMPLATES.publicBookingServices],
|
|
2652
|
+
auth: "public",
|
|
2653
|
+
responseKind: "json"
|
|
2654
|
+
},
|
|
2655
|
+
getPublicBookingResourcesReference: {
|
|
2656
|
+
path: "/public/bookings/resources/reference",
|
|
2657
|
+
method: "GET",
|
|
2658
|
+
revalidate: publicReadFreshnessSeconds("getPublicBookingResourcesReference"),
|
|
2659
|
+
tags: [TAG_TEMPLATES.publicBookingServices],
|
|
2660
|
+
auth: "public",
|
|
2661
|
+
responseKind: "json"
|
|
2662
|
+
},
|
|
2663
|
+
getPublicBookingAvailableDates: {
|
|
2664
|
+
path: "/public/bookings/availability/dates",
|
|
2665
|
+
method: "GET",
|
|
2666
|
+
revalidate: publicReadFreshnessSeconds("getPublicBookingAvailableDates"),
|
|
2667
|
+
tags: [TAG_TEMPLATES.publicBookingAvailability, TAG_TEMPLATES.publicBookingServices],
|
|
2668
|
+
auth: "public",
|
|
2669
|
+
responseKind: "json"
|
|
2670
|
+
},
|
|
2671
|
+
getPublicBookingAvailableSlots: {
|
|
2672
|
+
path: "/public/bookings/availability/slots",
|
|
2673
|
+
method: "GET",
|
|
2674
|
+
revalidate: publicReadFreshnessSeconds("getPublicBookingAvailableSlots"),
|
|
2675
|
+
tags: [TAG_TEMPLATES.publicBookingAvailability, TAG_TEMPLATES.publicBookingServices],
|
|
2676
|
+
auth: "public",
|
|
2677
|
+
responseKind: "json"
|
|
2678
|
+
},
|
|
2679
|
+
getPublicWeeklySlotAvailability: {
|
|
2680
|
+
path: "/public/bookings/weekly-slot-availability",
|
|
2681
|
+
method: "GET",
|
|
2682
|
+
revalidate: publicReadFreshnessSeconds("getPublicWeeklySlotAvailability"),
|
|
2683
|
+
tags: [TAG_TEMPLATES.publicBookingAvailability, TAG_TEMPLATES.publicBookingServices],
|
|
2684
|
+
auth: "public",
|
|
2685
|
+
responseKind: "json",
|
|
2686
|
+
errors: []
|
|
2687
|
+
}
|
|
2688
|
+
});
|
|
2397
2689
|
//#endregion
|
|
2398
|
-
//#region ../
|
|
2399
|
-
const
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2690
|
+
//#region ../api/src/siteApiKeyEndpointDefinitions.ts
|
|
2691
|
+
const SITE_API_KEY_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
|
|
2692
|
+
listSiteApiKeys: {
|
|
2693
|
+
path: "/sites/{siteId}/api-keys",
|
|
2694
|
+
method: "GET",
|
|
2695
|
+
auth: "user",
|
|
2696
|
+
tags: ["site-{siteId}", "api-keys"],
|
|
2697
|
+
responseKind: "json"
|
|
2698
|
+
},
|
|
2699
|
+
createSiteApiKey: {
|
|
2700
|
+
path: "/sites/{siteId}/api-keys",
|
|
2701
|
+
method: "POST",
|
|
2702
|
+
auth: "user",
|
|
2703
|
+
tags: ["site-{siteId}", "api-keys"],
|
|
2704
|
+
responseKind: "json"
|
|
2705
|
+
},
|
|
2706
|
+
revokeSiteApiKey: {
|
|
2707
|
+
path: "/sites/{siteId}/api-keys/{keyId}",
|
|
2708
|
+
method: "DELETE",
|
|
2709
|
+
auth: "user",
|
|
2710
|
+
tags: ["site-{siteId}", "api-keys"],
|
|
2711
|
+
responseKind: "json"
|
|
2712
|
+
},
|
|
2713
|
+
listSitePreviewKeys: {
|
|
2714
|
+
path: "/sites/{siteId}/api-keys/preview",
|
|
2715
|
+
method: "GET",
|
|
2716
|
+
auth: "user",
|
|
2717
|
+
tags: [
|
|
2718
|
+
"site-{siteId}",
|
|
2719
|
+
"api-keys",
|
|
2720
|
+
"preview-key"
|
|
2721
|
+
],
|
|
2722
|
+
errors: [],
|
|
2723
|
+
responseKind: "json"
|
|
2724
|
+
},
|
|
2725
|
+
createSitePreviewKey: {
|
|
2726
|
+
path: "/sites/{siteId}/api-keys/preview",
|
|
2727
|
+
method: "POST",
|
|
2728
|
+
auth: "user",
|
|
2729
|
+
tags: [
|
|
2730
|
+
"site-{siteId}",
|
|
2731
|
+
"api-keys",
|
|
2732
|
+
"preview-key"
|
|
2733
|
+
],
|
|
2734
|
+
responseKind: "json"
|
|
2735
|
+
},
|
|
2736
|
+
getSiteApiKeyAccessLogs: {
|
|
2737
|
+
path: "/sites/{siteId}/api-keys/access-logs",
|
|
2738
|
+
method: "GET",
|
|
2739
|
+
auth: "user",
|
|
2740
|
+
tags: [
|
|
2741
|
+
"site-{siteId}",
|
|
2742
|
+
"api-keys",
|
|
2743
|
+
"access-logs"
|
|
2744
|
+
],
|
|
2745
|
+
responseKind: "json"
|
|
2746
|
+
},
|
|
2747
|
+
listManagementKeys: {
|
|
2748
|
+
path: "/sites/{siteId}/api-keys/management",
|
|
2749
|
+
method: "GET",
|
|
2750
|
+
auth: "user",
|
|
2751
|
+
tags: [
|
|
2752
|
+
"site-{siteId}",
|
|
2753
|
+
"api-keys",
|
|
2754
|
+
"management-keys"
|
|
2755
|
+
],
|
|
2756
|
+
responseKind: "json"
|
|
2757
|
+
},
|
|
2758
|
+
createManagementKey: {
|
|
2759
|
+
path: "/sites/{siteId}/api-keys/management",
|
|
2760
|
+
method: "POST",
|
|
2761
|
+
auth: "user",
|
|
2762
|
+
tags: [
|
|
2763
|
+
"site-{siteId}",
|
|
2764
|
+
"api-keys",
|
|
2765
|
+
"management-keys"
|
|
2766
|
+
],
|
|
2767
|
+
responseKind: "json"
|
|
2768
|
+
},
|
|
2769
|
+
revokeManagementKey: {
|
|
2770
|
+
path: "/sites/{siteId}/api-keys/management",
|
|
2771
|
+
method: "DELETE",
|
|
2772
|
+
auth: "user",
|
|
2773
|
+
tags: [
|
|
2774
|
+
"site-{siteId}",
|
|
2775
|
+
"api-keys",
|
|
2776
|
+
"management-keys"
|
|
2777
|
+
],
|
|
2778
|
+
responseKind: "json"
|
|
2779
|
+
}
|
|
2780
|
+
});
|
|
2408
2781
|
//#endregion
|
|
2409
|
-
//#region ../
|
|
2410
|
-
const
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2782
|
+
//#region ../api/src/eventManagementEndpointDefinitions.ts
|
|
2783
|
+
const EVENT_MANAGEMENT_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
|
|
2784
|
+
listEvents: {
|
|
2785
|
+
path: "/sites/{siteId}/bookings/events",
|
|
2786
|
+
method: "GET",
|
|
2787
|
+
tags: ["site-{siteId}", "event-series-{siteId}"],
|
|
2788
|
+
auth: "user",
|
|
2789
|
+
responseKind: "json",
|
|
2790
|
+
errors: []
|
|
2791
|
+
},
|
|
2792
|
+
createEvent: {
|
|
2793
|
+
path: "/sites/{siteId}/bookings/events",
|
|
2794
|
+
method: "POST",
|
|
2795
|
+
tags: ["site-{siteId}", "event-series-{siteId}"],
|
|
2796
|
+
auth: "user",
|
|
2797
|
+
responseKind: "json",
|
|
2798
|
+
errors: [
|
|
2799
|
+
"validation:invalid_input",
|
|
2800
|
+
"resource:already_exists",
|
|
2801
|
+
"server:internal_error"
|
|
2802
|
+
]
|
|
2803
|
+
},
|
|
2804
|
+
transitionEventLifecycle: {
|
|
2805
|
+
path: "/sites/{siteId}/bookings/events/{eventId}/lifecycle",
|
|
2806
|
+
method: "POST",
|
|
2807
|
+
tags: ["site-{siteId}", "event-series-{siteId}"],
|
|
2808
|
+
auth: "user",
|
|
2809
|
+
responseKind: "json",
|
|
2810
|
+
errors: [
|
|
2811
|
+
"validation:invalid_input",
|
|
2812
|
+
"resource:not_found",
|
|
2813
|
+
"resource:conflict",
|
|
2814
|
+
"server:internal_error"
|
|
2815
|
+
]
|
|
2816
|
+
},
|
|
2817
|
+
updateEventIdentity: {
|
|
2818
|
+
path: "/sites/{siteId}/bookings/events/{eventId}",
|
|
2819
|
+
method: "PATCH",
|
|
2820
|
+
tags: ["site-{siteId}", "event-series-{siteId}"],
|
|
2821
|
+
auth: "user",
|
|
2822
|
+
responseKind: "json",
|
|
2823
|
+
errors: [
|
|
2824
|
+
"validation:invalid_input",
|
|
2825
|
+
"resource:not_found",
|
|
2826
|
+
"server:internal_error"
|
|
2827
|
+
]
|
|
2828
|
+
},
|
|
2829
|
+
createWholeSeriesRun: {
|
|
2830
|
+
path: "/sites/{siteId}/bookings/events/{eventId}/runs",
|
|
2831
|
+
method: "POST",
|
|
2832
|
+
tags: ["site-{siteId}", "event-series-{siteId}"],
|
|
2833
|
+
auth: "user",
|
|
2834
|
+
responseKind: "json",
|
|
2835
|
+
errors: [
|
|
2836
|
+
"validation:invalid_input",
|
|
2837
|
+
"resource:not_found",
|
|
2838
|
+
"resource:already_exists",
|
|
2839
|
+
"server:internal_error"
|
|
2840
|
+
]
|
|
2841
|
+
},
|
|
2842
|
+
updateWholeSeriesRun: {
|
|
2843
|
+
path: "/sites/{siteId}/bookings/events/{eventId}/runs/{runId}",
|
|
2844
|
+
method: "PATCH",
|
|
2845
|
+
tags: ["site-{siteId}", "event-series-{siteId}"],
|
|
2846
|
+
auth: "user",
|
|
2847
|
+
responseKind: "json",
|
|
2848
|
+
errors: [
|
|
2849
|
+
"validation:invalid_input",
|
|
2850
|
+
"resource:not_found",
|
|
2851
|
+
"resource:conflict",
|
|
2852
|
+
"server:internal_error"
|
|
2853
|
+
]
|
|
2854
|
+
},
|
|
2855
|
+
cancelWholeSeriesRun: {
|
|
2856
|
+
path: "/sites/{siteId}/bookings/events/{eventId}/runs/{runId}/cancellation",
|
|
2857
|
+
method: "POST",
|
|
2858
|
+
tags: ["site-{siteId}", "event-series-{siteId}"],
|
|
2859
|
+
auth: "user",
|
|
2860
|
+
responseKind: "json",
|
|
2861
|
+
errors: [
|
|
2862
|
+
"validation:invalid_input",
|
|
2863
|
+
"resource:not_found",
|
|
2864
|
+
"resource:conflict",
|
|
2865
|
+
"server:internal_error"
|
|
2866
|
+
]
|
|
2867
|
+
}
|
|
2868
|
+
});
|
|
2430
2869
|
//#endregion
|
|
2431
|
-
//#region ../
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2870
|
+
//#region ../api/src/giftingEndpointDefinitions.ts
|
|
2871
|
+
/**
|
|
2872
|
+
* Gifting endpoints (gift cards & vouchers) — the dashboard surface that manages
|
|
2873
|
+
* offers, gifts and settings, plus the public buy/claim surface.
|
|
2874
|
+
*/
|
|
2875
|
+
const GIFTING_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
|
|
2876
|
+
createGiftingOffer: {
|
|
2877
|
+
path: "/sites/{siteId}/gifting/offers",
|
|
2878
|
+
method: "POST",
|
|
2879
|
+
tags: ["site-{siteId}", "gifting-offers-{siteId}"],
|
|
2880
|
+
auth: "user",
|
|
2881
|
+
responseKind: "json",
|
|
2882
|
+
errors: [
|
|
2883
|
+
"validation:invalid_input",
|
|
2884
|
+
"auth:forbidden",
|
|
2885
|
+
"server:internal_error"
|
|
2886
|
+
]
|
|
2437
2887
|
},
|
|
2438
|
-
{
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2888
|
+
updateGiftingOffer: {
|
|
2889
|
+
path: "/sites/{siteId}/gifting/offers/{offerId}",
|
|
2890
|
+
method: "PATCH",
|
|
2891
|
+
tags: ["site-{siteId}", "gifting-offers-{siteId}"],
|
|
2892
|
+
auth: "user",
|
|
2893
|
+
responseKind: "json",
|
|
2894
|
+
errors: [
|
|
2895
|
+
"validation:invalid_input",
|
|
2896
|
+
"auth:forbidden",
|
|
2897
|
+
"resource:not_found",
|
|
2898
|
+
"resource:conflict",
|
|
2899
|
+
"server:internal_error"
|
|
2900
|
+
]
|
|
2442
2901
|
},
|
|
2443
|
-
{
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2902
|
+
deleteGiftingOffer: {
|
|
2903
|
+
path: "/sites/{siteId}/gifting/offers/{offerId}",
|
|
2904
|
+
method: "DELETE",
|
|
2905
|
+
tags: ["site-{siteId}", "gifting-offers-{siteId}"],
|
|
2906
|
+
auth: "user",
|
|
2907
|
+
responseKind: "json",
|
|
2908
|
+
errors: [
|
|
2909
|
+
"auth:forbidden",
|
|
2910
|
+
"resource:not_found",
|
|
2911
|
+
"resource:conflict",
|
|
2912
|
+
"server:internal_error"
|
|
2913
|
+
]
|
|
2447
2914
|
},
|
|
2448
|
-
{
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2915
|
+
duplicateGiftingOffer: {
|
|
2916
|
+
path: "/sites/{siteId}/gifting/offers/{offerId}/duplicate",
|
|
2917
|
+
method: "POST",
|
|
2918
|
+
tags: ["site-{siteId}", "gifting-offers-{siteId}"],
|
|
2919
|
+
auth: "user",
|
|
2920
|
+
responseKind: "json",
|
|
2921
|
+
errors: [
|
|
2922
|
+
"auth:forbidden",
|
|
2923
|
+
"resource:not_found",
|
|
2924
|
+
"server:internal_error"
|
|
2925
|
+
]
|
|
2452
2926
|
},
|
|
2453
|
-
{
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2927
|
+
reorderGiftingOffers: {
|
|
2928
|
+
path: "/sites/{siteId}/gifting/offers/order",
|
|
2929
|
+
method: "PUT",
|
|
2930
|
+
tags: ["site-{siteId}", "gifting-offers-{siteId}"],
|
|
2931
|
+
auth: "user",
|
|
2932
|
+
responseKind: "json",
|
|
2933
|
+
errors: [
|
|
2934
|
+
"validation:invalid_input",
|
|
2935
|
+
"auth:forbidden",
|
|
2936
|
+
"resource:not_found",
|
|
2937
|
+
"server:internal_error"
|
|
2938
|
+
]
|
|
2457
2939
|
},
|
|
2458
|
-
{
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2940
|
+
sendGift: {
|
|
2941
|
+
path: "/sites/{siteId}/gifting/gifts",
|
|
2942
|
+
method: "POST",
|
|
2943
|
+
tags: ["site-{siteId}", "gifting-gifts-{siteId}"],
|
|
2944
|
+
auth: "user",
|
|
2945
|
+
demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN,
|
|
2946
|
+
responseKind: "json",
|
|
2947
|
+
errors: [
|
|
2948
|
+
"validation:invalid_input",
|
|
2949
|
+
"auth:forbidden",
|
|
2950
|
+
"resource:not_found",
|
|
2951
|
+
"server:internal_error"
|
|
2952
|
+
]
|
|
2462
2953
|
},
|
|
2463
|
-
{
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2954
|
+
resendGift: {
|
|
2955
|
+
path: "/sites/{siteId}/gifting/gifts/{giftId}/resend",
|
|
2956
|
+
method: "POST",
|
|
2957
|
+
tags: ["site-{siteId}", "gifting-gifts-{siteId}"],
|
|
2958
|
+
auth: "user",
|
|
2959
|
+
demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN,
|
|
2960
|
+
responseKind: "json",
|
|
2961
|
+
errors: [
|
|
2962
|
+
"auth:forbidden",
|
|
2963
|
+
"resource:not_found",
|
|
2964
|
+
"resource:conflict",
|
|
2965
|
+
"server:internal_error"
|
|
2966
|
+
]
|
|
2467
2967
|
},
|
|
2468
|
-
{
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2968
|
+
correctGiftEmailAndResend: {
|
|
2969
|
+
path: "/sites/{siteId}/gifting/gifts/{giftId}/correct-email-and-resend",
|
|
2970
|
+
method: "POST",
|
|
2971
|
+
tags: ["site-{siteId}", "gifting-gifts-{siteId}"],
|
|
2972
|
+
auth: "user",
|
|
2973
|
+
demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN,
|
|
2974
|
+
responseKind: "json",
|
|
2975
|
+
errors: [
|
|
2976
|
+
"validation:invalid_input",
|
|
2977
|
+
"auth:forbidden",
|
|
2978
|
+
"resource:not_found",
|
|
2979
|
+
"resource:conflict",
|
|
2980
|
+
"server:internal_error"
|
|
2981
|
+
]
|
|
2472
2982
|
},
|
|
2473
|
-
{
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2983
|
+
updateGiftingSettings: {
|
|
2984
|
+
path: "/sites/{siteId}/gifting/settings",
|
|
2985
|
+
method: "PATCH",
|
|
2986
|
+
tags: [
|
|
2987
|
+
"site-{siteId}",
|
|
2988
|
+
"gifting-offers-{siteId}",
|
|
2989
|
+
"gifting-gifts-{siteId}"
|
|
2990
|
+
],
|
|
2991
|
+
auth: "user",
|
|
2992
|
+
responseKind: "json",
|
|
2993
|
+
errors: [
|
|
2994
|
+
"validation:invalid_input",
|
|
2995
|
+
"auth:forbidden",
|
|
2996
|
+
"server:internal_error"
|
|
2997
|
+
]
|
|
2998
|
+
},
|
|
2999
|
+
listPublicGiftingOffers: {
|
|
3000
|
+
path: "/public/sites/{siteId}/gifting/offers",
|
|
3001
|
+
method: "GET",
|
|
3002
|
+
revalidate: 300,
|
|
3003
|
+
tags: [TAG_TEMPLATES.publicGifting],
|
|
3004
|
+
errors: [],
|
|
3005
|
+
auth: "public",
|
|
3006
|
+
responseKind: "json"
|
|
3007
|
+
},
|
|
3008
|
+
createPublicGiftingCheckout: {
|
|
3009
|
+
path: "/public/sites/{siteId}/gifting/checkout",
|
|
3010
|
+
method: "POST",
|
|
3011
|
+
tags: [TAG_TEMPLATES.publicGifting],
|
|
3012
|
+
errors: [],
|
|
3013
|
+
auth: "public",
|
|
3014
|
+
responseKind: "json"
|
|
3015
|
+
},
|
|
3016
|
+
claimGiftCardPublic: {
|
|
3017
|
+
path: "/public/sites/{siteId}/gifting/claim",
|
|
3018
|
+
method: "POST",
|
|
3019
|
+
tags: [TAG_TEMPLATES.publicGifting],
|
|
3020
|
+
errors: [],
|
|
3021
|
+
auth: "public",
|
|
3022
|
+
responseKind: "json"
|
|
3023
|
+
}
|
|
3024
|
+
});
|
|
3025
|
+
//#endregion
|
|
3026
|
+
//#region ../api/src/sdkEndpointDefinitions.ts
|
|
3027
|
+
/** SDK management endpoints that do not belong to a CRUD resource family. */
|
|
3028
|
+
const SDK_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
|
|
3029
|
+
sdkUpdateSettings: {
|
|
3030
|
+
path: "/sdk/{siteId}/settings",
|
|
3031
|
+
method: "PATCH",
|
|
3032
|
+
auth: "service",
|
|
3033
|
+
responseKind: "json",
|
|
3034
|
+
errors: ["validation:invalid_input", "server:internal_error"]
|
|
3035
|
+
},
|
|
3036
|
+
sdkConfigureBookingVertical: {
|
|
3037
|
+
path: "/sdk/{siteId}/settings/booking/vertical",
|
|
3038
|
+
method: "POST",
|
|
3039
|
+
auth: "service",
|
|
3040
|
+
responseKind: "json"
|
|
3041
|
+
},
|
|
3042
|
+
sdkSetupRevalidationWebhook: {
|
|
3043
|
+
path: "/sdk/{siteId}/webhooks/revalidation/setup",
|
|
3044
|
+
method: "POST",
|
|
3045
|
+
auth: "service",
|
|
3046
|
+
responseKind: "json",
|
|
3047
|
+
errors: ["validation:invalid_input", "server:internal_error"]
|
|
3048
|
+
}
|
|
3049
|
+
});
|
|
3050
|
+
//#endregion
|
|
3051
|
+
//#region ../api/src/sdkMediaEndpointDefinitions.ts
|
|
3052
|
+
/** SDK media lookup, listing, deletion and upload endpoints (management-key authenticated). */
|
|
3053
|
+
const SDK_MEDIA_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
|
|
3054
|
+
sdkMediaExists: {
|
|
3055
|
+
path: "/sdk/{siteId}/media/exists",
|
|
3056
|
+
method: "POST",
|
|
3057
|
+
errors: ["validation:invalid_input"],
|
|
3058
|
+
auth: "service",
|
|
3059
|
+
responseKind: "json"
|
|
3060
|
+
},
|
|
3061
|
+
sdkMediaFindByChecksum: {
|
|
3062
|
+
path: "/sdk/{siteId}/media/find-by-checksum",
|
|
3063
|
+
method: "POST",
|
|
3064
|
+
errors: ["server:internal_error"],
|
|
3065
|
+
auth: "service",
|
|
3066
|
+
responseKind: "json"
|
|
2477
3067
|
},
|
|
2478
|
-
{
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
3068
|
+
sdkMediaResolve: {
|
|
3069
|
+
path: "/sdk/{siteId}/media/resolve",
|
|
3070
|
+
method: "POST",
|
|
3071
|
+
errors: ["server:internal_error"],
|
|
3072
|
+
auth: "service",
|
|
3073
|
+
responseKind: "json"
|
|
2482
3074
|
},
|
|
2483
|
-
{
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
3075
|
+
sdkMediaList: {
|
|
3076
|
+
path: "/sdk/{siteId}/media",
|
|
3077
|
+
method: "GET",
|
|
3078
|
+
auth: "service",
|
|
3079
|
+
errors: [],
|
|
3080
|
+
responseKind: "json"
|
|
2487
3081
|
},
|
|
2488
|
-
{
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
3082
|
+
sdkMediaDownload: {
|
|
3083
|
+
path: "/sdk/{siteId}/media/{identifier}/download",
|
|
3084
|
+
method: "GET",
|
|
3085
|
+
auth: "service",
|
|
3086
|
+
errors: [],
|
|
3087
|
+
responseKind: "json"
|
|
2492
3088
|
},
|
|
2493
|
-
{
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
3089
|
+
sdkMediaDeletePreview: {
|
|
3090
|
+
path: "/sdk/{siteId}/media/{identifier}/delete-preview",
|
|
3091
|
+
method: "POST",
|
|
3092
|
+
auth: "service",
|
|
3093
|
+
errors: [],
|
|
3094
|
+
responseKind: "json"
|
|
2497
3095
|
},
|
|
2498
|
-
{
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
3096
|
+
sdkMediaDeleteApply: {
|
|
3097
|
+
path: "/sdk/{siteId}/media/{identifier}",
|
|
3098
|
+
method: "DELETE",
|
|
3099
|
+
auth: "service",
|
|
3100
|
+
errors: [],
|
|
3101
|
+
responseKind: "json"
|
|
2502
3102
|
},
|
|
2503
|
-
{
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
3103
|
+
sdkMediaUploadUrl: {
|
|
3104
|
+
path: "/sdk/{siteId}/media/upload-url",
|
|
3105
|
+
method: "POST",
|
|
3106
|
+
errors: [
|
|
3107
|
+
"resource:not_found",
|
|
3108
|
+
"validation:invalid_input",
|
|
3109
|
+
"resource:conflict",
|
|
3110
|
+
"validation:payload_too_large",
|
|
3111
|
+
"billing:plan_limit_exceeded",
|
|
3112
|
+
"server:internal_error"
|
|
3113
|
+
],
|
|
3114
|
+
auth: "service",
|
|
3115
|
+
responseKind: "json"
|
|
3116
|
+
},
|
|
3117
|
+
sdkMediaUploadFinalize: {
|
|
3118
|
+
path: "/sdk/{siteId}/media/upload",
|
|
3119
|
+
method: "POST",
|
|
3120
|
+
errors: [
|
|
3121
|
+
"resource:not_found",
|
|
3122
|
+
"validation:invalid_input",
|
|
3123
|
+
"resource:conflict",
|
|
3124
|
+
"validation:payload_too_large",
|
|
3125
|
+
"billing:plan_limit_exceeded",
|
|
3126
|
+
"server:internal_error"
|
|
3127
|
+
],
|
|
3128
|
+
auth: "service",
|
|
3129
|
+
responseKind: "json"
|
|
2507
3130
|
}
|
|
2508
|
-
|
|
2509
|
-
VERTICAL_DEFINITIONS.map(({ id }) => id);
|
|
3131
|
+
});
|
|
2510
3132
|
//#endregion
|
|
2511
|
-
//#region ../
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
...verticalBookingPreset("dance_school.terms", "dance_school", "course", "Term", "Terms", "Multi-week term blocks or fixed-date course groups."),
|
|
2526
|
-
eventPresetOverride: "term"
|
|
3133
|
+
//#region ../api/src/publicReadEndpointDefinitions.ts
|
|
3134
|
+
/**
|
|
3135
|
+
* Direct public reads governed by the canonical public-read freshness policy.
|
|
3136
|
+
* Keeping these definitions together makes the endpoint identity used to
|
|
3137
|
+
* derive freshness reviewable beside its route and tags.
|
|
3138
|
+
*/
|
|
3139
|
+
const PUBLIC_READ_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
|
|
3140
|
+
getPublishedEntryPreview: {
|
|
3141
|
+
path: "/public/content/{siteId}/{type}/{slug}/preview",
|
|
3142
|
+
method: "GET",
|
|
3143
|
+
revalidate: publicReadFreshnessSeconds("getPublishedEntryPreview"),
|
|
3144
|
+
tags: ["content-{siteId}-{type}-{slug}"],
|
|
3145
|
+
auth: "public",
|
|
3146
|
+
responseKind: "json"
|
|
2527
3147
|
},
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
verticalBookingPreset("massage_bodywork.treatments", "massage_bodywork", "appointment", "Treatment", "Treatments", "Massage treatments, bodywork sessions, and one-to-one appointments."),
|
|
2536
|
-
verticalBookingPreset("massage_bodywork.group_sessions", "massage_bodywork", "class", "Group session", "Group sessions", "Regular bodywork, somatic movement, or self-massage sessions."),
|
|
2537
|
-
verticalBookingPreset("massage_bodywork.workshops", "massage_bodywork", "workshop", "Workshop", "Workshops", "One-off bodywork, self-massage, or somatic practice workshops."),
|
|
2538
|
-
verticalBookingPreset("therapist_practitioner.appointments", "therapist_practitioner", "appointment", "Appointment", "Appointments", "Sessions, consultations, treatments, or assessments."),
|
|
2539
|
-
verticalBookingPreset("therapist_practitioner.workshops", "therapist_practitioner", "workshop", "Workshop", "Workshops", "One-off group workshops, talks, or wellbeing sessions."),
|
|
2540
|
-
verticalBookingPreset("therapist_practitioner.retreats", "therapist_practitioner", "retreat", "Retreat", "Retreats", "Multi-day retreats or immersive group experiences."),
|
|
2541
|
-
verticalBookingPreset("beauty_spa.appointments", "beauty_spa", "appointment", "Appointment", "Appointments", "Treatments, consultations, services, and sessions."),
|
|
2542
|
-
verticalBookingPreset("beauty_spa.workshops", "beauty_spa", "workshop", "Workshop", "Workshops", "Skincare workshops, makeup lessons, demos, or group events."),
|
|
2543
|
-
verticalBookingPreset("consultant_coach.appointments", "consultant_coach", "appointment", "Appointment", "Appointments", "One-to-one calls, consultations, reviews, or coaching sessions."),
|
|
2544
|
-
verticalBookingPreset("consultant_coach.workshops", "consultant_coach", "workshop", "Workshop", "Workshops", "One-off group sessions, webinars, or strategy days."),
|
|
2545
|
-
verticalBookingPreset("consultant_coach.courses", "consultant_coach", "course", "Course", "Courses", "Fixed-schedule cohorts or multi-session group programmes."),
|
|
2546
|
-
verticalBookingPreset("consultant_coach.retreats", "consultant_coach", "retreat", "Retreat", "Retreats", "Multi-day coaching retreats or immersive experiences."),
|
|
2547
|
-
verticalBookingPreset("training_provider.courses", "training_provider", "course", "Course", "Courses", "Fixed-schedule courses, cohorts, and multi-session training."),
|
|
2548
|
-
verticalBookingPreset("training_provider.workshops", "training_provider", "workshop", "Workshop", "Workshops", "One-off workshops, masterclasses, and short training sessions."),
|
|
2549
|
-
verticalBookingPreset("training_provider.appointments", "training_provider", "appointment", "Appointment", "Appointments", "Consultations, assessments, mentoring, or office hours."),
|
|
2550
|
-
verticalBookingPreset("training_provider.classes", "training_provider", "class", "Class", "Classes", "Regular classes, sessions, or groups.", "settings"),
|
|
2551
|
-
verticalBookingPreset("training_provider.residentials", "training_provider", "retreat", "Residential", "Residentials", "Residential courses or multi-day training experiences.", "settings"),
|
|
2552
|
-
verticalBookingPreset("retreat_centre.retreats", "retreat_centre", "retreat", "Retreat", "Retreats", "Multi-day or residential retreats with richer booking needs."),
|
|
2553
|
-
verticalBookingPreset("retreat_centre.workshops", "retreat_centre", "workshop", "Workshop", "Workshops", "One-day retreats, ceremonies, workshops, or special events."),
|
|
2554
|
-
verticalBookingPreset("retreat_centre.classes", "retreat_centre", "class", "Class", "Classes", "Regular sessions like guided meditations or group practices."),
|
|
2555
|
-
verticalBookingPreset("retreat_centre.courses", "retreat_centre", "course", "Course", "Courses", "Fixed-schedule programmes or multi-session experiences."),
|
|
2556
|
-
verticalBookingPreset("retreat_centre.appointments", "retreat_centre", "appointment", "Appointment", "Appointments", "Private sessions, therapies, consultations, or add-ons."),
|
|
2557
|
-
verticalBookingPreset("music_school.lessons", "music_school", "appointment", "Lesson", "Lessons", "One-to-one lessons, consultations, or coaching sessions."),
|
|
2558
|
-
verticalBookingPreset("music_school.classes", "music_school", "class", "Class", "Classes", "Regular group classes, ensembles, or recurring sessions."),
|
|
2559
|
-
{
|
|
2560
|
-
...verticalBookingPreset("music_school.terms", "music_school", "course", "Term", "Terms", "Multi-week term blocks or fixed-date group courses."),
|
|
2561
|
-
eventPresetOverride: "term"
|
|
3148
|
+
listPublishedEntries: {
|
|
3149
|
+
path: "/public/content/{siteId}/{type}/entries",
|
|
3150
|
+
method: "GET",
|
|
3151
|
+
revalidate: publicReadFreshnessSeconds("listPublishedEntries"),
|
|
3152
|
+
tags: ["content-{siteId}-{type}"],
|
|
3153
|
+
auth: "public",
|
|
3154
|
+
responseKind: "json"
|
|
2562
3155
|
},
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
3156
|
+
getPublicFormById: {
|
|
3157
|
+
path: "/public/forms/{formId}",
|
|
3158
|
+
method: "GET",
|
|
3159
|
+
revalidate: publicReadFreshnessSeconds("getPublicFormById"),
|
|
3160
|
+
tags: [TAG_TEMPLATES.formById],
|
|
3161
|
+
auth: "public",
|
|
3162
|
+
responseKind: "json"
|
|
2570
3163
|
},
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
3164
|
+
listPublicEvents: {
|
|
3165
|
+
path: "/public/sites/{siteId}/events",
|
|
3166
|
+
method: "GET",
|
|
3167
|
+
revalidate: publicReadFreshnessSeconds("listPublicEvents"),
|
|
3168
|
+
tags: [TAG_TEMPLATES.publicEvents],
|
|
3169
|
+
auth: "public",
|
|
3170
|
+
responseKind: "json"
|
|
2577
3171
|
},
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
}
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
}
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
return firstPresetId ? [firstPresetId, ...presetIds.slice(1)] : null;
|
|
2612
|
-
}
|
|
2613
|
-
const DEFAULT_SITE_VERTICAL_BOOKING_CONFIG = {
|
|
2614
|
-
verticalId: null,
|
|
2615
|
-
selectedPresetIds: []
|
|
2616
|
-
};
|
|
2617
|
-
function appendUniqueIssue(issues, issue) {
|
|
2618
|
-
return issues.some((existing) => existing.code === issue.code) ? issues : [...issues, issue];
|
|
2619
|
-
}
|
|
2620
|
-
function collectRawConfigIssues(rawConfig, config) {
|
|
2621
|
-
const rawPresetValue = rawConfig.selectedPresetIds;
|
|
2622
|
-
const rawPresetIds = Array.isArray(rawPresetValue) ? rawPresetValue : [];
|
|
2623
|
-
let issues = [];
|
|
2624
|
-
if (rawConfig.verticalId != null && config.verticalId === null) issues = appendUniqueIssue(issues, {
|
|
2625
|
-
code: "unknown_vertical",
|
|
2626
|
-
rawValue: rawConfig.verticalId
|
|
2627
|
-
});
|
|
2628
|
-
if (config.verticalId === null && config.selectedPresetIds.length > 0) issues = appendUniqueIssue(issues, { code: "missing_vertical" });
|
|
2629
|
-
if (rawPresetValue !== void 0 && !Array.isArray(rawPresetValue) || rawPresetIds.some((presetId) => parseVerticalPresetId(presetId) === null)) issues = appendUniqueIssue(issues, {
|
|
2630
|
-
code: "unknown_preset",
|
|
2631
|
-
rawValue: rawPresetValue
|
|
2632
|
-
});
|
|
2633
|
-
if (rawConfig.verticalId != null && config.selectedPresetIds.length === 0) issues = appendUniqueIssue(issues, { code: "empty_selected_presets" });
|
|
2634
|
-
return issues;
|
|
2635
|
-
}
|
|
2636
|
-
function collectPresetConfigIssues(config) {
|
|
2637
|
-
const seenPresetIds = /* @__PURE__ */ new Set();
|
|
2638
|
-
const seenBehaviours = /* @__PURE__ */ new Set();
|
|
2639
|
-
let issues = [];
|
|
2640
|
-
for (const presetId of config.selectedPresetIds) {
|
|
2641
|
-
const presetDefinition = getVerticalPresetDefinition(presetId);
|
|
2642
|
-
if (seenPresetIds.has(presetId)) issues = appendUniqueIssue(issues, { code: "duplicate_preset_id" });
|
|
2643
|
-
seenPresetIds.add(presetId);
|
|
2644
|
-
if (config.verticalId !== null && presetDefinition.verticalId !== config.verticalId) issues = appendUniqueIssue(issues, { code: "preset_vertical_mismatch" });
|
|
2645
|
-
if (presetDefinition.availability === "future") issues = appendUniqueIssue(issues, { code: "future_preset_selected" });
|
|
2646
|
-
if (seenBehaviours.has(presetDefinition.canonicalBehaviour)) issues = appendUniqueIssue(issues, { code: "duplicate_canonical_behaviour" });
|
|
2647
|
-
seenBehaviours.add(presetDefinition.canonicalBehaviour);
|
|
3172
|
+
listPublicTeamMembers: {
|
|
3173
|
+
path: "/public/sites/{siteId}/team-members",
|
|
3174
|
+
method: "GET",
|
|
3175
|
+
revalidate: publicReadFreshnessSeconds("listPublicTeamMembers"),
|
|
3176
|
+
tags: [TAG_TEMPLATES.publicTeamMembers],
|
|
3177
|
+
errors: [],
|
|
3178
|
+
auth: "public",
|
|
3179
|
+
responseKind: "json"
|
|
3180
|
+
},
|
|
3181
|
+
listPublicPasses: {
|
|
3182
|
+
path: "/public/sites/{siteId}/bookings/products/passes",
|
|
3183
|
+
method: "GET",
|
|
3184
|
+
revalidate: publicReadFreshnessSeconds("listPublicPasses"),
|
|
3185
|
+
tags: [TAG_TEMPLATES.publicPasses],
|
|
3186
|
+
auth: "public",
|
|
3187
|
+
responseKind: "json"
|
|
3188
|
+
},
|
|
3189
|
+
listPublicMemberships: {
|
|
3190
|
+
path: "/public/sites/{siteId}/bookings/products/memberships",
|
|
3191
|
+
method: "GET",
|
|
3192
|
+
revalidate: publicReadFreshnessSeconds("listPublicMemberships"),
|
|
3193
|
+
tags: [TAG_TEMPLATES.publicMemberships],
|
|
3194
|
+
auth: "public",
|
|
3195
|
+
responseKind: "json"
|
|
3196
|
+
},
|
|
3197
|
+
listPublicProducts: {
|
|
3198
|
+
path: "/public/sites/{siteId}/products",
|
|
3199
|
+
method: "GET",
|
|
3200
|
+
revalidate: publicReadFreshnessSeconds("listPublicProducts"),
|
|
3201
|
+
tags: [TAG_TEMPLATES.publicProducts],
|
|
3202
|
+
errors: [],
|
|
3203
|
+
auth: "public",
|
|
3204
|
+
responseKind: "json"
|
|
2648
3205
|
}
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
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
|
-
config,
|
|
2682
|
-
issues: [{ code: "empty_selected_presets" }]
|
|
2683
|
-
};
|
|
2684
|
-
return {
|
|
2685
|
-
kind: "configured",
|
|
2686
|
-
config: configuredConfig,
|
|
2687
|
-
selectedPresets: configuredConfig.selectedPresetIds.map(getVerticalPresetDefinition)
|
|
2688
|
-
};
|
|
3206
|
+
});
|
|
3207
|
+
({
|
|
3208
|
+
...ACCOUNT_ENDPOINT_DEFINITIONS,
|
|
3209
|
+
...PUBLIC_EVENT_ENDPOINT_DEFINITIONS,
|
|
3210
|
+
...GIFTING_ENDPOINT_DEFINITIONS,
|
|
3211
|
+
...PUBLIC_READ_ENDPOINT_DEFINITIONS
|
|
3212
|
+
}), 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, {
|
|
3213
|
+
...NEWSLETTER_ENDPOINT_DEFINITIONS,
|
|
3214
|
+
...APPOINTMENT_ENDPOINT_DEFINITIONS,
|
|
3215
|
+
...EVENT_SERIES_REGISTRATION_ENDPOINT_DEFINITIONS
|
|
3216
|
+
}, 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 };
|
|
3217
|
+
z.object({ refreshToken: z.string().min(1).max(4096) }).strict();
|
|
3218
|
+
z.object({
|
|
3219
|
+
accessToken: z.string().min(1).max(4096),
|
|
3220
|
+
refreshToken: z.string().min(1).max(4096)
|
|
3221
|
+
}).strict();
|
|
3222
|
+
const ACCOUNT_SITE_CURSOR_MAX_LENGTH = 2048;
|
|
3223
|
+
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})$/;
|
|
3224
|
+
/** Strict, injection-safe PostgreSQL/RFC3339 timestamp text used in cursors. */
|
|
3225
|
+
function isAccountSiteTimestamp(value) {
|
|
3226
|
+
if (typeof value !== "string") return false;
|
|
3227
|
+
const match = ACCOUNT_SITE_TIMESTAMP_PATTERN.exec(value);
|
|
3228
|
+
if (!match) return false;
|
|
3229
|
+
const [, year, month, day, hour, minute, second, , offset] = match;
|
|
3230
|
+
const date = new Date(Date.UTC(Number(year), Number(month) - 1, Number(day)));
|
|
3231
|
+
const offsetValue = offset ?? "";
|
|
3232
|
+
const offsetIsValid = offsetValue === "Z" || (() => {
|
|
3233
|
+
const offsetMatch = /^(?:[+-])(\d{2}):(\d{2})$/.exec(offsetValue);
|
|
3234
|
+
if (!offsetMatch) return false;
|
|
3235
|
+
return Number(offsetMatch[1]) <= 23 && Number(offsetMatch[2]) <= 59;
|
|
3236
|
+
})();
|
|
3237
|
+
return date.getUTCFullYear() === Number(year) && date.getUTCMonth() === Number(month) - 1 && date.getUTCDate() === Number(day) && Number(hour) <= 23 && Number(minute) <= 59 && Number(second) <= 59 && offsetIsValid;
|
|
2689
3238
|
}
|
|
3239
|
+
const accountSiteTimestampSchema = z.string().refine(isAccountSiteTimestamp, { message: "Expected a strict account site timestamp" });
|
|
3240
|
+
z.enum([
|
|
3241
|
+
"managed",
|
|
3242
|
+
"headless_cms",
|
|
3243
|
+
"headless_full"
|
|
3244
|
+
]);
|
|
3245
|
+
z.object({ title: z.string().trim().min(1).max(120) });
|
|
3246
|
+
const abandonedStandardKeyIdsSchema = z.object({
|
|
3247
|
+
live: z.string().uuid().optional(),
|
|
3248
|
+
management: z.string().uuid().optional()
|
|
3249
|
+
}).strict();
|
|
3250
|
+
const abandonedPreviewKeyIdsSchema = z.object({
|
|
3251
|
+
live: z.string().uuid().optional(),
|
|
3252
|
+
management: z.string().uuid().optional(),
|
|
3253
|
+
preview: z.string().uuid().optional()
|
|
3254
|
+
}).strict();
|
|
3255
|
+
z.discriminatedUnion("operation", [
|
|
3256
|
+
z.object({
|
|
3257
|
+
operation: z.literal("issue_standard"),
|
|
3258
|
+
siteId: z.string().uuid(),
|
|
3259
|
+
operationId: z.string().uuid(),
|
|
3260
|
+
projectName: z.string().trim().min(1).max(120),
|
|
3261
|
+
abandonedKeyIds: abandonedStandardKeyIdsSchema.default({})
|
|
3262
|
+
}).strict(),
|
|
3263
|
+
z.object({
|
|
3264
|
+
operation: z.literal("issue_with_preview"),
|
|
3265
|
+
siteId: z.string().uuid(),
|
|
3266
|
+
operationId: z.string().uuid(),
|
|
3267
|
+
projectName: z.string().trim().min(1).max(120),
|
|
3268
|
+
abandonedKeyIds: abandonedPreviewKeyIdsSchema.default({})
|
|
3269
|
+
}).strict(),
|
|
3270
|
+
z.object({
|
|
3271
|
+
operation: z.literal("revalidate_standard"),
|
|
3272
|
+
siteId: z.string().uuid(),
|
|
3273
|
+
operationId: z.string().uuid(),
|
|
3274
|
+
projectName: z.string().trim().min(1).max(120),
|
|
3275
|
+
keyIds: z.object({
|
|
3276
|
+
live: z.string().uuid(),
|
|
3277
|
+
management: z.string().uuid()
|
|
3278
|
+
}).strict()
|
|
3279
|
+
}).strict(),
|
|
3280
|
+
z.object({
|
|
3281
|
+
operation: z.literal("revalidate_with_preview"),
|
|
3282
|
+
siteId: z.string().uuid(),
|
|
3283
|
+
operationId: z.string().uuid(),
|
|
3284
|
+
projectName: z.string().trim().min(1).max(120),
|
|
3285
|
+
keyIds: z.object({
|
|
3286
|
+
live: z.string().uuid(),
|
|
3287
|
+
management: z.string().uuid(),
|
|
3288
|
+
preview: z.string().uuid()
|
|
3289
|
+
}).strict()
|
|
3290
|
+
}).strict()
|
|
3291
|
+
]);
|
|
3292
|
+
z.object({
|
|
3293
|
+
cursor: z.string().min(1).max(ACCOUNT_SITE_CURSOR_MAX_LENGTH).optional(),
|
|
3294
|
+
limit: z.coerce.number().int().min(1).max(100).default(50),
|
|
3295
|
+
search: z.string().trim().min(1).max(120).optional()
|
|
3296
|
+
});
|
|
2690
3297
|
z.object({
|
|
2691
3298
|
formulaVersion: z.literal("managed-domain-overage-v1"),
|
|
2692
3299
|
conversionRule: z.literal("usd-to-gbp-1-to-1-v1"),
|
|
@@ -20646,102 +21253,31 @@ const newsletterFormFragment = defineFragment({
|
|
|
20646
21253
|
description: "Newsletter subscription form with preset field configurations.",
|
|
20647
21254
|
fields: [
|
|
20648
21255
|
{
|
|
20649
|
-
id: "
|
|
20650
|
-
type: "
|
|
20651
|
-
label: "
|
|
20652
|
-
description: "Choose
|
|
20653
|
-
defaultValue: "
|
|
20654
|
-
required:
|
|
20655
|
-
ui: { intent: "behavior" },
|
|
20656
|
-
options: [{
|
|
20657
|
-
value: "riverbank",
|
|
20658
|
-
label: "Riverbank newsletter"
|
|
20659
|
-
}]
|
|
20660
|
-
},
|
|
20661
|
-
{
|
|
20662
|
-
id: "listId",
|
|
20663
|
-
type: "reference",
|
|
20664
|
-
label: "Newsletter list",
|
|
20665
|
-
description: "Select the list new subscribers should be added to.",
|
|
20666
|
-
required: false,
|
|
20667
|
-
referenceKind: "newsletterList",
|
|
20668
|
-
allowManualEntry: false,
|
|
20669
|
-
ui: {
|
|
20670
|
-
intent: "behavior",
|
|
20671
|
-
visibleWhen: {
|
|
20672
|
-
field: "destinationProvider",
|
|
20673
|
-
equals: "riverbank"
|
|
20674
|
-
}
|
|
20675
|
-
}
|
|
20676
|
-
},
|
|
20677
|
-
{
|
|
20678
|
-
id: "mailchimpAudienceId",
|
|
20679
|
-
type: "reference",
|
|
20680
|
-
label: "Mailchimp audience",
|
|
20681
|
-
description: "Choose the Mailchimp audience for new subscribers.",
|
|
20682
|
-
required: false,
|
|
20683
|
-
referenceKind: "mailchimpAudience",
|
|
20684
|
-
allowManualEntry: false,
|
|
20685
|
-
ui: {
|
|
20686
|
-
intent: "behavior",
|
|
20687
|
-
visibleWhen: {
|
|
20688
|
-
field: "destinationProvider",
|
|
20689
|
-
equals: "mailchimp"
|
|
20690
|
-
}
|
|
20691
|
-
}
|
|
20692
|
-
},
|
|
20693
|
-
{
|
|
20694
|
-
id: "mailchimpTags",
|
|
20695
|
-
type: "text",
|
|
20696
|
-
label: "Mailchimp tags",
|
|
20697
|
-
description: "Optional tags to apply in Mailchimp, separated by commas or semicolons.",
|
|
21256
|
+
id: "targeting",
|
|
21257
|
+
type: "group",
|
|
21258
|
+
label: "Mailing-list targeting",
|
|
21259
|
+
description: "Choose what kind of emails people signing up here will receive.",
|
|
21260
|
+
defaultValue: { mode: "default" },
|
|
21261
|
+
required: true,
|
|
20698
21262
|
ui: {
|
|
20699
21263
|
intent: "behavior",
|
|
20700
|
-
|
|
20701
|
-
|
|
20702
|
-
|
|
20703
|
-
|
|
20704
|
-
|
|
20705
|
-
|
|
20706
|
-
|
|
20707
|
-
|
|
20708
|
-
|
|
20709
|
-
|
|
20710
|
-
|
|
20711
|
-
|
|
20712
|
-
|
|
20713
|
-
|
|
20714
|
-
|
|
20715
|
-
|
|
20716
|
-
|
|
20717
|
-
},
|
|
20718
|
-
{
|
|
20719
|
-
value: "emailName",
|
|
20720
|
-
label: "Email + Name"
|
|
20721
|
-
},
|
|
20722
|
-
{
|
|
20723
|
-
value: "emailFirstLast",
|
|
20724
|
-
label: "Email + First/Last Name"
|
|
20725
|
-
},
|
|
20726
|
-
{
|
|
20727
|
-
value: "emailNameCompany",
|
|
20728
|
-
label: "Email + Name + Company (B2B)"
|
|
20729
|
-
}
|
|
20730
|
-
]
|
|
20731
|
-
},
|
|
20732
|
-
{
|
|
20733
|
-
id: "includePhone",
|
|
20734
|
-
type: "boolean",
|
|
20735
|
-
label: "Include phone field (optional)",
|
|
20736
|
-
description: "Adds an optional phone field to the selected preset (never required).",
|
|
20737
|
-
defaultValue: false,
|
|
20738
|
-
ui: { intent: "display" }
|
|
20739
|
-
},
|
|
20740
|
-
{
|
|
20741
|
-
id: "buttonLabel",
|
|
20742
|
-
type: "text",
|
|
20743
|
-
label: "Button label",
|
|
20744
|
-
defaultValue: "Subscribe"
|
|
21264
|
+
widget: "mailingListTargeting"
|
|
21265
|
+
},
|
|
21266
|
+
schema: { fields: [{
|
|
21267
|
+
id: "mode",
|
|
21268
|
+
type: "select",
|
|
21269
|
+
label: "Mode",
|
|
21270
|
+
required: true,
|
|
21271
|
+
defaultValue: "default",
|
|
21272
|
+
options: [{
|
|
21273
|
+
value: "default",
|
|
21274
|
+
label: "Default"
|
|
21275
|
+
}, {
|
|
21276
|
+
value: "custom",
|
|
21277
|
+
label: "Custom"
|
|
21278
|
+
}],
|
|
21279
|
+
ui: { hidden: true }
|
|
21280
|
+
}] }
|
|
20745
21281
|
},
|
|
20746
21282
|
createButtonVariantField({
|
|
20747
21283
|
id: "buttonVariant",
|
|
@@ -20749,46 +21285,42 @@ const newsletterFormFragment = defineFragment({
|
|
|
20749
21285
|
defaultValue: "primary"
|
|
20750
21286
|
}),
|
|
20751
21287
|
{
|
|
20752
|
-
id: "
|
|
20753
|
-
type: "text",
|
|
20754
|
-
label: "Success message",
|
|
20755
|
-
description: "Shown after successful subscription.",
|
|
20756
|
-
defaultValue: "Thanks for subscribing!"
|
|
20757
|
-
},
|
|
20758
|
-
{
|
|
20759
|
-
id: "privacyNote",
|
|
21288
|
+
id: "mailingListSource",
|
|
20760
21289
|
type: "text",
|
|
20761
|
-
label: "
|
|
20762
|
-
|
|
21290
|
+
label: "Mailing-list source",
|
|
21291
|
+
ui: {
|
|
21292
|
+
hidden: true,
|
|
21293
|
+
intent: "behavior"
|
|
21294
|
+
}
|
|
20763
21295
|
},
|
|
20764
21296
|
{
|
|
20765
|
-
id: "
|
|
21297
|
+
id: "mailingListSourceToken",
|
|
20766
21298
|
type: "text",
|
|
20767
|
-
label: "
|
|
20768
|
-
description: "Optional tags to apply on subscribe (comma or semicolon separated).",
|
|
21299
|
+
label: "Mailing-list source token",
|
|
20769
21300
|
ui: {
|
|
20770
|
-
|
|
20771
|
-
|
|
20772
|
-
field: "destinationProvider",
|
|
20773
|
-
equals: "riverbank"
|
|
20774
|
-
}
|
|
21301
|
+
hidden: true,
|
|
21302
|
+
intent: "behavior"
|
|
20775
21303
|
}
|
|
20776
21304
|
}
|
|
20777
21305
|
],
|
|
20778
21306
|
layout: [el("newsletter-form", withApiBindings({
|
|
20779
|
-
source:
|
|
20780
|
-
|
|
20781
|
-
|
|
20782
|
-
|
|
20783
|
-
|
|
20784
|
-
|
|
21307
|
+
source: { $bind: {
|
|
21308
|
+
from: "mailingListSource",
|
|
21309
|
+
fallback: "block"
|
|
21310
|
+
} },
|
|
21311
|
+
sourceRef: {
|
|
21312
|
+
tag: "signed_source_ref",
|
|
21313
|
+
token: { $bind: { from: "mailingListSourceToken" } }
|
|
21314
|
+
},
|
|
21315
|
+
targeting: { $bind: {
|
|
21316
|
+
from: "targeting",
|
|
21317
|
+
fallback: { mode: "default" }
|
|
21318
|
+
} },
|
|
21319
|
+
mailingList: { $bind: { from: "$root.mailingList" } },
|
|
20785
21320
|
buttonVariant: { $bind: {
|
|
20786
21321
|
from: "buttonVariant",
|
|
20787
21322
|
fallback: "primary"
|
|
20788
21323
|
} },
|
|
20789
|
-
successMessage: { $bind: { from: "successMessage" } },
|
|
20790
|
-
privacyNote: { $bind: { from: "privacyNote" } },
|
|
20791
|
-
tags: { $bind: { from: "tags" } },
|
|
20792
21324
|
spamProtectionEnabled: { $bind: { from: "$root.spamProtectionEnabled" } }
|
|
20793
21325
|
}), [])]
|
|
20794
21326
|
});
|
|
@@ -22963,14 +23495,19 @@ const contactNewsletterLayout = styledSection({
|
|
|
22963
23495
|
as: "h2",
|
|
22964
23496
|
className: "newsletter-copy-title"
|
|
22965
23497
|
}, when("newsletterTitle"), bind("newsletterTitle")), richText({ className: "newsletter-copy-subtitle rb-prose rb-max-w-none" }, when("newsletterSubtitle"), bind("newsletterSubtitle"))]), el("newsletter-form", withApiBindings({
|
|
22966
|
-
source:
|
|
22967
|
-
|
|
22968
|
-
|
|
22969
|
-
|
|
22970
|
-
|
|
22971
|
-
|
|
22972
|
-
|
|
22973
|
-
|
|
23498
|
+
source: { $bind: {
|
|
23499
|
+
from: "mailingListSource",
|
|
23500
|
+
fallback: "block"
|
|
23501
|
+
} },
|
|
23502
|
+
sourceRef: {
|
|
23503
|
+
tag: "signed_source_ref",
|
|
23504
|
+
token: { $bind: { from: "mailingListSourceToken" } }
|
|
23505
|
+
},
|
|
23506
|
+
targeting: { $bind: {
|
|
23507
|
+
from: "targeting",
|
|
23508
|
+
fallback: { mode: "default" }
|
|
23509
|
+
} },
|
|
23510
|
+
mailingList: { $bind: { from: "$root.mailingList" } },
|
|
22974
23511
|
spamProtectionEnabled: { $bind: { from: "$root.spamProtectionEnabled" } }
|
|
22975
23512
|
}), [])])])], { className: "contact-newsletter-container" }),
|
|
22976
23513
|
baseClass: "",
|
|
@@ -23006,79 +23543,55 @@ const contactNewsletterBlockDefinition = {
|
|
|
23006
23543
|
label: "Newsletter intro"
|
|
23007
23544
|
},
|
|
23008
23545
|
{
|
|
23009
|
-
id: "
|
|
23010
|
-
type: "
|
|
23011
|
-
label: "
|
|
23012
|
-
description: "
|
|
23546
|
+
id: "targeting",
|
|
23547
|
+
type: "group",
|
|
23548
|
+
label: "Mailing-list targeting",
|
|
23549
|
+
description: "Choose what kind of emails people signing up here will receive.",
|
|
23013
23550
|
required: true,
|
|
23014
|
-
|
|
23015
|
-
|
|
23016
|
-
|
|
23017
|
-
|
|
23018
|
-
|
|
23019
|
-
|
|
23020
|
-
|
|
23021
|
-
|
|
23022
|
-
|
|
23023
|
-
|
|
23024
|
-
|
|
23025
|
-
{
|
|
23026
|
-
value: "
|
|
23027
|
-
label: "
|
|
23028
|
-
},
|
|
23029
|
-
|
|
23030
|
-
|
|
23031
|
-
|
|
23032
|
-
}
|
|
23033
|
-
|
|
23034
|
-
value: "emailFirstLast",
|
|
23035
|
-
label: "Email + First/Last Name"
|
|
23036
|
-
},
|
|
23037
|
-
{
|
|
23038
|
-
value: "emailNameCompany",
|
|
23039
|
-
label: "Email + Name + Company (B2B)"
|
|
23040
|
-
}
|
|
23041
|
-
]
|
|
23042
|
-
},
|
|
23043
|
-
{
|
|
23044
|
-
id: "includePhone",
|
|
23045
|
-
type: "boolean",
|
|
23046
|
-
label: "Include phone field",
|
|
23047
|
-
defaultValue: false,
|
|
23048
|
-
ui: { intent: "display" }
|
|
23049
|
-
},
|
|
23050
|
-
{
|
|
23051
|
-
id: "newsletterButtonLabel",
|
|
23052
|
-
type: "text",
|
|
23053
|
-
label: "Newsletter button label",
|
|
23054
|
-
defaultValue: "Subscribe",
|
|
23055
|
-
ui: { intent: "display" }
|
|
23056
|
-
},
|
|
23057
|
-
{
|
|
23058
|
-
id: "newsletterSuccessMessage",
|
|
23059
|
-
type: "text",
|
|
23060
|
-
label: "Newsletter success message",
|
|
23061
|
-
defaultValue: "Thanks for subscribing!",
|
|
23062
|
-
ui: { intent: "behavior" }
|
|
23551
|
+
defaultValue: { mode: "default" },
|
|
23552
|
+
ui: {
|
|
23553
|
+
intent: "behavior",
|
|
23554
|
+
widget: "mailingListTargeting"
|
|
23555
|
+
},
|
|
23556
|
+
schema: { fields: [{
|
|
23557
|
+
id: "mode",
|
|
23558
|
+
type: "select",
|
|
23559
|
+
label: "Mode",
|
|
23560
|
+
required: true,
|
|
23561
|
+
defaultValue: "default",
|
|
23562
|
+
options: [{
|
|
23563
|
+
value: "default",
|
|
23564
|
+
label: "Default"
|
|
23565
|
+
}, {
|
|
23566
|
+
value: "custom",
|
|
23567
|
+
label: "Custom"
|
|
23568
|
+
}],
|
|
23569
|
+
ui: { hidden: true }
|
|
23570
|
+
}] }
|
|
23063
23571
|
},
|
|
23064
23572
|
{
|
|
23065
|
-
id: "
|
|
23573
|
+
id: "contactTitle",
|
|
23066
23574
|
type: "text",
|
|
23067
|
-
label: "
|
|
23068
|
-
|
|
23575
|
+
label: "Contact title",
|
|
23576
|
+
defaultValue: "Get in touch"
|
|
23069
23577
|
},
|
|
23070
23578
|
{
|
|
23071
|
-
id: "
|
|
23579
|
+
id: "mailingListSource",
|
|
23072
23580
|
type: "text",
|
|
23073
|
-
label: "
|
|
23074
|
-
|
|
23075
|
-
|
|
23581
|
+
label: "Mailing-list source",
|
|
23582
|
+
ui: {
|
|
23583
|
+
hidden: true,
|
|
23584
|
+
intent: "behavior"
|
|
23585
|
+
}
|
|
23076
23586
|
},
|
|
23077
23587
|
{
|
|
23078
|
-
id: "
|
|
23588
|
+
id: "mailingListSourceToken",
|
|
23079
23589
|
type: "text",
|
|
23080
|
-
label: "
|
|
23081
|
-
|
|
23590
|
+
label: "Mailing-list source token",
|
|
23591
|
+
ui: {
|
|
23592
|
+
hidden: true,
|
|
23593
|
+
intent: "behavior"
|
|
23594
|
+
}
|
|
23082
23595
|
},
|
|
23083
23596
|
{
|
|
23084
23597
|
id: "contactIntro",
|
|
@@ -23279,6 +23792,12 @@ const arrayLengthTransform = {
|
|
|
23279
23792
|
summary: "Get the length of an array",
|
|
23280
23793
|
run: (value) => Array.isArray(value) ? value.length : 0
|
|
23281
23794
|
};
|
|
23795
|
+
const booleanNotTransform = {
|
|
23796
|
+
id: "boolean.not",
|
|
23797
|
+
kind: "formatter",
|
|
23798
|
+
summary: "Invert a boolean value; fail closed to false for other inputs",
|
|
23799
|
+
run: (value) => typeof value === "boolean" ? !value : false
|
|
23800
|
+
};
|
|
23282
23801
|
const jsonArrayTransform = {
|
|
23283
23802
|
id: "value.jsonArray",
|
|
23284
23803
|
kind: "formatter",
|
|
@@ -23329,33 +23848,51 @@ const marqueeLoopTransform = {
|
|
|
23329
23848
|
function toUnknownArray(value) {
|
|
23330
23849
|
return Array.isArray(value) ? value : [];
|
|
23331
23850
|
}
|
|
23851
|
+
/**
|
|
23852
|
+
* Map a content state/enum to a theme token colour — the first-class way to turn
|
|
23853
|
+
* a value like a class's availability (`available`/`filling`/`waitlist`), a
|
|
23854
|
+
* card's featured flag, or a pricing tier level into a themed colour. Authors
|
|
23855
|
+
* write role names and get `rgb(var(--tb-<role>))`, so the result live-recolours
|
|
23856
|
+
* with the theme and drops directly into a `style` binding (e.g.
|
|
23857
|
+
* `borderLeftColor`). Returns `undefined` when the value matches no case and no
|
|
23858
|
+
* fallback is given, so the style property is simply omitted.
|
|
23859
|
+
*/
|
|
23860
|
+
const mapTokenTransform = {
|
|
23861
|
+
id: "value.mapToken",
|
|
23862
|
+
kind: "formatter",
|
|
23863
|
+
summary: "Map a state/enum value to a theme token colour (rgb(var(--tb-<role>)))",
|
|
23864
|
+
schema: z.object({
|
|
23865
|
+
/**
|
|
23866
|
+
* Maps an input state/enum value (stringified) to a theme token ROLE name
|
|
23867
|
+
* (e.g. `secondary`, `accent`, `muted`, `border`). The role is wrapped to
|
|
23868
|
+
* `rgb(var(--tb-<role>))` so the result drops straight into a `style` binding.
|
|
23869
|
+
*/
|
|
23870
|
+
cases: z.record(z.string(), z.string()),
|
|
23871
|
+
/** Role used when the value matches no case. Omit to yield `undefined`. */
|
|
23872
|
+
fallback: z.string().optional()
|
|
23873
|
+
}),
|
|
23874
|
+
run: (value, options) => {
|
|
23875
|
+
const role = options.cases[String(value)] ?? options.fallback;
|
|
23876
|
+
return role ? `rgb(var(--tb-${role}))` : void 0;
|
|
23877
|
+
}
|
|
23878
|
+
};
|
|
23332
23879
|
const formattingTransforms = [
|
|
23880
|
+
{
|
|
23881
|
+
id: "value.equals",
|
|
23882
|
+
kind: "formatter",
|
|
23883
|
+
summary: "Compare a value to a fixed string",
|
|
23884
|
+
schema: z.object({ value: z.string() }),
|
|
23885
|
+
run: (value, options) => value === options.value
|
|
23886
|
+
},
|
|
23333
23887
|
uppercaseTransform,
|
|
23334
23888
|
fallbackTransform,
|
|
23335
23889
|
dateFormatShort,
|
|
23336
23890
|
arrayLengthTransform,
|
|
23891
|
+
booleanNotTransform,
|
|
23337
23892
|
jsonArrayTransform,
|
|
23338
23893
|
csvTransform,
|
|
23339
23894
|
marqueeLoopTransform,
|
|
23340
|
-
|
|
23341
|
-
id: "value.mapToken",
|
|
23342
|
-
kind: "formatter",
|
|
23343
|
-
summary: "Map a state/enum value to a theme token colour (rgb(var(--tb-<role>)))",
|
|
23344
|
-
schema: z.object({
|
|
23345
|
-
/**
|
|
23346
|
-
* Maps an input state/enum value (stringified) to a theme token ROLE name
|
|
23347
|
-
* (e.g. `secondary`, `accent`, `muted`, `border`). The role is wrapped to
|
|
23348
|
-
* `rgb(var(--tb-<role>))` so the result drops straight into a `style` binding.
|
|
23349
|
-
*/
|
|
23350
|
-
cases: z.record(z.string(), z.string()),
|
|
23351
|
-
/** Role used when the value matches no case. Omit to yield `undefined`. */
|
|
23352
|
-
fallback: z.string().optional()
|
|
23353
|
-
}),
|
|
23354
|
-
run: (value, options) => {
|
|
23355
|
-
const role = options.cases[String(value)] ?? options.fallback;
|
|
23356
|
-
return role ? `rgb(var(--tb-${role}))` : void 0;
|
|
23357
|
-
}
|
|
23358
|
-
}
|
|
23895
|
+
mapTokenTransform
|
|
23359
23896
|
];
|
|
23360
23897
|
//#endregion
|
|
23361
23898
|
//#region ../blocks/src/system/transforms/registry/ui.ts
|
|
@@ -24772,13 +25309,9 @@ const footerStandardContactBindings = {
|
|
|
24772
25309
|
};
|
|
24773
25310
|
const footerMailingListBindings = {
|
|
24774
25311
|
source: { $bind: { from: "module.engagement.runtime.source" } },
|
|
24775
|
-
|
|
24776
|
-
|
|
24777
|
-
|
|
24778
|
-
includePhone: { $bind: { from: "module.engagement.runtime.includePhone" } },
|
|
24779
|
-
buttonLabel: { $bind: { from: "module.engagement.runtime.buttonLabel" } },
|
|
24780
|
-
successMessage: { $bind: { from: "module.engagement.runtime.successMessage" } },
|
|
24781
|
-
privacyNote: { $bind: { from: "module.engagement.runtime.privacyNote" } }
|
|
25312
|
+
sourceRef: { $bind: { from: "module.engagement.runtime.sourceRef" } },
|
|
25313
|
+
mailingList: { $bind: { from: "module.engagement.runtime.mailingList" } },
|
|
25314
|
+
targeting: { $bind: { from: "module.engagement.runtime.targeting" } }
|
|
24782
25315
|
};
|
|
24783
25316
|
const footerSpamProtectionBinding = { spamProtectionEnabled: { $bind: { from: "$root.spamProtectionEnabled" } } };
|
|
24784
25317
|
const brandLogo = link({
|
|
@@ -26466,6 +26999,78 @@ const appointmentBookingBlockDefinition = {
|
|
|
26466
26999
|
}
|
|
26467
27000
|
}
|
|
26468
27001
|
};
|
|
27002
|
+
const appointmentServicesBlockDefinition = {
|
|
27003
|
+
manifest: createBlockManifest({
|
|
27004
|
+
id: "block.appointment-services",
|
|
27005
|
+
version: "1.0.0",
|
|
27006
|
+
title: "Appointment Services",
|
|
27007
|
+
titleSource: "heading",
|
|
27008
|
+
description: "List public appointment services with booking links",
|
|
27009
|
+
skipSectionStyles: true,
|
|
27010
|
+
additionalFields: [
|
|
27011
|
+
{
|
|
27012
|
+
id: "heading",
|
|
27013
|
+
type: "text",
|
|
27014
|
+
label: "Heading",
|
|
27015
|
+
required: false,
|
|
27016
|
+
multiline: false,
|
|
27017
|
+
defaultValue: "Appointments",
|
|
27018
|
+
ui: { intent: "content" }
|
|
27019
|
+
},
|
|
27020
|
+
{
|
|
27021
|
+
id: "description",
|
|
27022
|
+
type: "richText",
|
|
27023
|
+
label: "Description",
|
|
27024
|
+
required: false,
|
|
27025
|
+
ui: { intent: "content" }
|
|
27026
|
+
},
|
|
27027
|
+
sectionStylesField({
|
|
27028
|
+
id: "_sectionStyles",
|
|
27029
|
+
label: "Section styles",
|
|
27030
|
+
renderInHeader: false
|
|
27031
|
+
})
|
|
27032
|
+
],
|
|
27033
|
+
styleTokens: {
|
|
27034
|
+
background: "surface",
|
|
27035
|
+
typography: "body",
|
|
27036
|
+
spacing: "md"
|
|
27037
|
+
},
|
|
27038
|
+
behaviours: {
|
|
27039
|
+
supportsThemeSwitching: true,
|
|
27040
|
+
inlineEditing: true,
|
|
27041
|
+
animation: false,
|
|
27042
|
+
paletteHidden: false
|
|
27043
|
+
},
|
|
27044
|
+
category: "interactive",
|
|
27045
|
+
contentSource: { kind: "inline" },
|
|
27046
|
+
tags: [
|
|
27047
|
+
"booking",
|
|
27048
|
+
"appointment",
|
|
27049
|
+
"services",
|
|
27050
|
+
"scheduling"
|
|
27051
|
+
],
|
|
27052
|
+
icon: "CalendarDays",
|
|
27053
|
+
layout: [styledSection({
|
|
27054
|
+
baseClass: "",
|
|
27055
|
+
spacing: "spacious",
|
|
27056
|
+
children: sectionContainer([
|
|
27057
|
+
text({ as: "h2" }, bind("content.heading"), when("content.heading")),
|
|
27058
|
+
richText({ className: "rb-prose rb-max-w-none" }, bind("content.description"), when("content.description")),
|
|
27059
|
+
el("appointment-services", {
|
|
27060
|
+
sectionHeading: { $bind: { from: "content.heading" } },
|
|
27061
|
+
services: { $bind: { from: "data.services" } },
|
|
27062
|
+
pathname: { $bind: { from: "$root.pathname" } }
|
|
27063
|
+
})
|
|
27064
|
+
], { gap: "lg" })
|
|
27065
|
+
})]
|
|
27066
|
+
}),
|
|
27067
|
+
dataSchemas: { services: z.unknown().optional() },
|
|
27068
|
+
dataLoaders: { services: {
|
|
27069
|
+
endpoint: "getPublicBookingServices",
|
|
27070
|
+
params: { siteId: { $bind: { from: "$root.siteId" } } },
|
|
27071
|
+
mode: "server"
|
|
27072
|
+
} }
|
|
27073
|
+
};
|
|
26469
27074
|
//#endregion
|
|
26470
27075
|
//#region ../blocks/src/system/blocks/weekly-slot-availability.ts
|
|
26471
27076
|
const weeklySlotAvailabilityManifest = createBlockManifest({
|
|
@@ -27704,8 +28309,8 @@ z.object({
|
|
|
27704
28309
|
previewToken: z.string().nullable().optional(),
|
|
27705
28310
|
stage: previewStageSchema.optional()
|
|
27706
28311
|
});
|
|
27707
|
-
function
|
|
27708
|
-
const selectedRun = resolveSelectedWholeSeriesRun(
|
|
28312
|
+
function buildEventRegistrationDisplayFromScopedEvents(source, scopedSourceEvents) {
|
|
28313
|
+
const selectedRun = resolveSelectedWholeSeriesRun(scopedSourceEvents);
|
|
27709
28314
|
if (selectedRun && (!selectedRun.run.enrollmentOpen || toWholeSeriesRegistrationEvent(selectedRun) === null)) return {
|
|
27710
28315
|
kind: "event-registration",
|
|
27711
28316
|
state: "registration-closed",
|
|
@@ -27713,7 +28318,7 @@ function buildEventRegistrationDisplay(source) {
|
|
|
27713
28318
|
titleText: "Registration closed",
|
|
27714
28319
|
bodyText: "This run is no longer open for bookings."
|
|
27715
28320
|
};
|
|
27716
|
-
const stepLabels = buildEventRegistrationShellStepLabels(source);
|
|
28321
|
+
const stepLabels = buildEventRegistrationShellStepLabels(source, scopedSourceEvents);
|
|
27717
28322
|
return {
|
|
27718
28323
|
kind: "event-registration",
|
|
27719
28324
|
state: "generic-shell",
|
|
@@ -27724,8 +28329,8 @@ function buildEventRegistrationDisplay(source) {
|
|
|
27724
28329
|
summaryButtonText: source.buttonText?.trim() || "Register"
|
|
27725
28330
|
};
|
|
27726
28331
|
}
|
|
27727
|
-
function buildEventRegistrationShellStepLabels(source) {
|
|
27728
|
-
const selectedRun = resolveSelectedWholeSeriesRun(
|
|
28332
|
+
function buildEventRegistrationShellStepLabels(source, scopedSourceEvents) {
|
|
28333
|
+
const selectedRun = resolveSelectedWholeSeriesRun(scopedSourceEvents);
|
|
27729
28334
|
if (selectedRun) {
|
|
27730
28335
|
const selectedEvent = toWholeSeriesRegistrationEvent(selectedRun);
|
|
27731
28336
|
if (!selectedEvent) return EVENT_REGISTRATION_GENERIC_SHELL_STEP_LABELS;
|
|
@@ -27735,7 +28340,7 @@ function buildEventRegistrationShellStepLabels(source) {
|
|
|
27735
28340
|
event: selectedEvent
|
|
27736
28341
|
})).map((step) => shellLabelForRegistrationStep(step, [selectedEvent]));
|
|
27737
28342
|
}
|
|
27738
|
-
const scopedEvents =
|
|
28343
|
+
const scopedEvents = toScopedEventRegistrationEvents(scopedSourceEvents);
|
|
27739
28344
|
if (scopedEvents.length === 0) return EVENT_REGISTRATION_GENERIC_SHELL_STEP_LABELS;
|
|
27740
28345
|
const preSelectedEvent = findPreSelectedEvent({
|
|
27741
28346
|
scopedEvents,
|
|
@@ -27748,31 +28353,25 @@ function buildEventRegistrationShellStepLabels(source) {
|
|
|
27748
28353
|
event: preSelectedEvent
|
|
27749
28354
|
}) : false).map((step) => shellLabelForRegistrationStep(step, scopedEvents));
|
|
27750
28355
|
}
|
|
27751
|
-
function
|
|
27752
|
-
|
|
27753
|
-
return [...toRegistrationEvents(scoped), ...toWholeSeriesRegistrationEvents(scoped)];
|
|
28356
|
+
function toScopedEventRegistrationEvents(scopedSourceEvents) {
|
|
28357
|
+
return [...toRegistrationEvents(scopedSourceEvents), ...toWholeSeriesRegistrationEvents(scopedSourceEvents)];
|
|
27754
28358
|
}
|
|
27755
|
-
/**
|
|
27756
|
-
* Every event this surface may register for, from both of its loads.
|
|
27757
|
-
*
|
|
27758
|
-
* The date page and the run read answer different questions and can name the
|
|
27759
|
-
* same occurrence, so the two lists are joined and any occurrence that arrives
|
|
27760
|
-
* twice is kept once, in the order the date page gave it.
|
|
27761
|
-
*/
|
|
27762
28359
|
function scopeEventRegistrationSourceEvents(source) {
|
|
27763
|
-
|
|
27764
|
-
for (const event of [...source.events ?? [], ...source.wholeSeriesRunEvents ?? []]) if (!byOccurrenceId.has(event.occurrenceId)) byOccurrenceId.set(event.occurrenceId, event);
|
|
27765
|
-
return resolveEventRegistrationScopedEvents([...byOccurrenceId.values()], {
|
|
28360
|
+
return resolveEventRegistrationScopedEvents(source.wholeSeriesRunEvents ?? source.events ?? [], {
|
|
27766
28361
|
occurrenceContext: source.occurrenceContext,
|
|
27767
28362
|
subject: source.subject
|
|
27768
28363
|
});
|
|
27769
28364
|
}
|
|
28365
|
+
function resolveLoadedEventRegistrationSourceEvents(source, scopedSourceEvents) {
|
|
28366
|
+
if (source.events == null && source.wholeSeriesRunEvents == null) return null;
|
|
28367
|
+
return [...scopedSourceEvents];
|
|
28368
|
+
}
|
|
27770
28369
|
/**
|
|
27771
28370
|
* The one run this surface is registering for, when the scoped events describe
|
|
27772
28371
|
* exactly one. More than one run means the visitor still has to choose.
|
|
27773
28372
|
*/
|
|
27774
|
-
function resolveSelectedWholeSeriesRun(
|
|
27775
|
-
const runs = groupPublicEventsByRun(
|
|
28373
|
+
function resolveSelectedWholeSeriesRun(scopedSourceEvents) {
|
|
28374
|
+
const runs = groupPublicEventsByRun(scopedSourceEvents);
|
|
27776
28375
|
return runs.length === 1 ? runs[0] : null;
|
|
27777
28376
|
}
|
|
27778
28377
|
function shellLabelForRegistrationStep(step, events) {
|
|
@@ -27806,9 +28405,10 @@ const eventRegistrationBlockRuntime = defineClientOwnedBlockRuntime({
|
|
|
27806
28405
|
render: createZodCodec(eventRegistrationRenderSchema)
|
|
27807
28406
|
},
|
|
27808
28407
|
buildRender: (source) => {
|
|
27809
|
-
const
|
|
28408
|
+
const scopedSourceEvents = scopeEventRegistrationSourceEvents(source);
|
|
28409
|
+
const events = resolveLoadedEventRegistrationSourceEvents(source, scopedSourceEvents);
|
|
27810
28410
|
return {
|
|
27811
|
-
display:
|
|
28411
|
+
display: buildEventRegistrationDisplayFromScopedEvents(source, scopedSourceEvents),
|
|
27812
28412
|
hydration: {
|
|
27813
28413
|
occurrenceContext: source.occurrenceContext ?? null,
|
|
27814
28414
|
subject: source.subject ?? null,
|
|
@@ -28009,6 +28609,11 @@ const eventRegistrationBlockDefinition = {
|
|
|
28009
28609
|
dataLoaders: {
|
|
28010
28610
|
events: {
|
|
28011
28611
|
endpoint: "listPublicEvents",
|
|
28612
|
+
when: { $bind: {
|
|
28613
|
+
from: "$root.subject.isWholeSeriesBooking",
|
|
28614
|
+
fallback: true,
|
|
28615
|
+
transforms: [{ id: "boolean.not" }]
|
|
28616
|
+
} },
|
|
28012
28617
|
params: {
|
|
28013
28618
|
siteId: { $bind: { from: "$root.siteId" } },
|
|
28014
28619
|
limit: "50",
|
|
@@ -28030,13 +28635,9 @@ const eventRegistrationBlockDefinition = {
|
|
|
28030
28635
|
/**
|
|
28031
28636
|
* The runs this page can register for, finished ones included.
|
|
28032
28637
|
*
|
|
28033
|
-
*
|
|
28034
|
-
*
|
|
28035
|
-
* render
|
|
28036
|
-
* subject books whole runs. It is scoped exactly like the date page — same
|
|
28037
|
-
* series, same run subroute — because scope and grain are separate
|
|
28038
|
-
* questions. The two lists are joined by occurrence, so a run that appears
|
|
28039
|
-
* in both is still one run.
|
|
28638
|
+
* A run read is the sole Event source on a whole-series surface. It is
|
|
28639
|
+
* status-bounded rather than date-bounded, so completed runs can still
|
|
28640
|
+
* render their closed state and every run carries its complete schedule.
|
|
28040
28641
|
*/
|
|
28041
28642
|
wholeSeriesRunEvents: {
|
|
28042
28643
|
endpoint: "listPublicEvents",
|
|
@@ -30629,20 +31230,7 @@ function isRecord$2(value) {
|
|
|
30629
31230
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
30630
31231
|
}
|
|
30631
31232
|
//#endregion
|
|
30632
|
-
//#region ../blocks/src/system/blocks/offerings-preview/
|
|
30633
|
-
/**
|
|
30634
|
-
* The whole-series presets, as the CSV `listPublicEvents` expects. Both
|
|
30635
|
-
* whole-series presets share one loader: the block renders them as a single
|
|
30636
|
-
* run group.
|
|
30637
|
-
*/
|
|
30638
|
-
const WHOLE_SERIES_EVENT_PRESETS_PARAM = WHOLE_SERIES_EVENT_PRESET_VALUES.join(",");
|
|
30639
|
-
const publicRouteCandidatesSchema = z.object({ routes: z.array(z.object({
|
|
30640
|
-
entityId: z.string(),
|
|
30641
|
-
path: z.string(),
|
|
30642
|
-
title: z.string(),
|
|
30643
|
-
kind: z.enum(RESOLVED_INTERNAL_LINK_ENTITY_TYPES),
|
|
30644
|
-
contentTypeKey: z.string().nullable().optional()
|
|
30645
|
-
})) });
|
|
31233
|
+
//#region ../blocks/src/system/blocks/offerings-preview/fields.ts
|
|
30646
31234
|
const groupOverrideFields = [
|
|
30647
31235
|
{
|
|
30648
31236
|
id: "sourceKey",
|
|
@@ -30848,7 +31436,65 @@ const offeringsPreviewFields = [
|
|
|
30848
31436
|
renderInHeader: false
|
|
30849
31437
|
})
|
|
30850
31438
|
];
|
|
31439
|
+
function labelForOfferingPreviewSourceKey(sourceKey) {
|
|
31440
|
+
const eventDefinition = OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS.find((definition) => definition.sourceKey === sourceKey);
|
|
31441
|
+
if (eventDefinition) return eventDefinition.label;
|
|
31442
|
+
return "Courses";
|
|
31443
|
+
}
|
|
31444
|
+
//#endregion
|
|
31445
|
+
//#region ../blocks/src/system/blocks/offerings-preview/index.ts
|
|
31446
|
+
/**
|
|
31447
|
+
* The whole-series presets, as the CSV `listPublicEvents` expects. Both
|
|
31448
|
+
* whole-series presets share one loader: the block renders them as a single
|
|
31449
|
+
* run group.
|
|
31450
|
+
*/
|
|
31451
|
+
const WHOLE_SERIES_EVENT_PRESETS_PARAM = WHOLE_SERIES_EVENT_PRESET_VALUES.join(",");
|
|
31452
|
+
const publicRouteCandidatesSchema = z.object({ routes: z.array(z.object({
|
|
31453
|
+
entityId: z.string(),
|
|
31454
|
+
path: z.string(),
|
|
31455
|
+
title: z.string(),
|
|
31456
|
+
kind: z.enum(RESOLVED_INTERNAL_LINK_ENTITY_TYPES),
|
|
31457
|
+
contentTypeKey: z.string().nullable().optional()
|
|
31458
|
+
})) });
|
|
30851
31459
|
const offeringsPreviewEventDataBindings = Object.fromEntries(OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS.map((definition) => [definition.dataKey, { $bind: { from: `data.${definition.dataKey}` } }]));
|
|
31460
|
+
const DEFAULT_OFFERINGS_PREVIEW_DISPLAY_MODE = "preview";
|
|
31461
|
+
const displayModeBinding = {
|
|
31462
|
+
from: "content.displayMode",
|
|
31463
|
+
fallback: DEFAULT_OFFERINGS_PREVIEW_DISPLAY_MODE
|
|
31464
|
+
};
|
|
31465
|
+
const catalogueMode = { $bind: {
|
|
31466
|
+
...displayModeBinding,
|
|
31467
|
+
transforms: [{
|
|
31468
|
+
id: "value.equals",
|
|
31469
|
+
options: { value: "catalogue" }
|
|
31470
|
+
}]
|
|
31471
|
+
} };
|
|
31472
|
+
const previewMode = { $bind: {
|
|
31473
|
+
...displayModeBinding,
|
|
31474
|
+
transforms: [{
|
|
31475
|
+
id: "value.equals",
|
|
31476
|
+
options: { value: "preview" }
|
|
31477
|
+
}]
|
|
31478
|
+
} };
|
|
31479
|
+
function offeringsPreviewHeaderNodes() {
|
|
31480
|
+
return [text({
|
|
31481
|
+
as: "h2",
|
|
31482
|
+
className: { $bind: {
|
|
31483
|
+
from: "content.displayMode",
|
|
31484
|
+
fallback: "rb-text-center",
|
|
31485
|
+
transforms: [{
|
|
31486
|
+
id: "value.equals",
|
|
31487
|
+
options: { value: "catalogue" }
|
|
31488
|
+
}, {
|
|
31489
|
+
id: "ui.conditionalClass",
|
|
31490
|
+
options: {
|
|
31491
|
+
whenTrue: "rb-text-left",
|
|
31492
|
+
whenFalse: "rb-text-center"
|
|
31493
|
+
}
|
|
31494
|
+
}]
|
|
31495
|
+
} }
|
|
31496
|
+
}, bind("content.heading"), when("content.heading")), richText({ className: "rb-prose rb-max-w-none" }, bind("content.description"), when("content.description"))];
|
|
31497
|
+
}
|
|
30852
31498
|
const offeringsPreviewManifest = createBlockManifest({
|
|
30853
31499
|
id: "block.offerings-preview",
|
|
30854
31500
|
version: "1.0.0",
|
|
@@ -30879,48 +31525,45 @@ const offeringsPreviewManifest = createBlockManifest({
|
|
|
30879
31525
|
],
|
|
30880
31526
|
icon: "PanelsTopLeft",
|
|
30881
31527
|
layout: [styledSection({
|
|
30882
|
-
children: sectionContainer([
|
|
30883
|
-
|
|
30884
|
-
|
|
30885
|
-
|
|
30886
|
-
|
|
30887
|
-
|
|
30888
|
-
|
|
30889
|
-
|
|
30890
|
-
|
|
30891
|
-
|
|
30892
|
-
|
|
30893
|
-
|
|
30894
|
-
|
|
30895
|
-
|
|
30896
|
-
|
|
30897
|
-
|
|
30898
|
-
|
|
30899
|
-
|
|
30900
|
-
|
|
30901
|
-
|
|
30902
|
-
|
|
30903
|
-
|
|
30904
|
-
|
|
30905
|
-
|
|
30906
|
-
|
|
30907
|
-
|
|
30908
|
-
|
|
30909
|
-
|
|
30910
|
-
|
|
30911
|
-
|
|
30912
|
-
|
|
30913
|
-
|
|
30914
|
-
|
|
30915
|
-
|
|
30916
|
-
|
|
30917
|
-
|
|
30918
|
-
|
|
30919
|
-
|
|
30920
|
-
|
|
30921
|
-
...offeringsPreviewEventDataBindings
|
|
30922
|
-
})
|
|
30923
|
-
], { gap: "lg" }),
|
|
31528
|
+
children: sectionContainer([el("offerings-preview", {
|
|
31529
|
+
displayMode: { $bind: displayModeBinding },
|
|
31530
|
+
pathname: { $bind: { from: "$root.pathname" } },
|
|
31531
|
+
catalogueEvents: { $bind: { from: "data.catalogueEvents" } },
|
|
31532
|
+
quickDateEvents: { $bind: { from: "data.quickDateEvents" } },
|
|
31533
|
+
bookingOfferingPresets: { $bind: {
|
|
31534
|
+
from: "$root.bookingOfferingPresets",
|
|
31535
|
+
fallback: []
|
|
31536
|
+
} },
|
|
31537
|
+
groupOverrides: { $bind: {
|
|
31538
|
+
from: "content.groupOverrides",
|
|
31539
|
+
fallback: []
|
|
31540
|
+
} },
|
|
31541
|
+
groupOrder: { $bind: { from: "content.groupOrder" } },
|
|
31542
|
+
cardStyles: { $bind: { from: "content._cardStyles" } },
|
|
31543
|
+
itemLimit: { $bind: {
|
|
31544
|
+
from: "content.itemLimit",
|
|
31545
|
+
fallback: "3"
|
|
31546
|
+
} },
|
|
31547
|
+
buttonVariant: { $bind: {
|
|
31548
|
+
from: "content.buttonVariant",
|
|
31549
|
+
fallback: "primary"
|
|
31550
|
+
} },
|
|
31551
|
+
buttonText: { $bind: {
|
|
31552
|
+
from: "content.buttonText",
|
|
31553
|
+
fallback: OFFERINGS_PREVIEW_DEFAULT_BUTTON_TEXT
|
|
31554
|
+
} },
|
|
31555
|
+
emptyMessage: { $bind: {
|
|
31556
|
+
from: "content.emptyMessage",
|
|
31557
|
+
fallback: OFFERINGS_PREVIEW_DEFAULT_EMPTY_MESSAGE
|
|
31558
|
+
} },
|
|
31559
|
+
previewStage: { $bind: {
|
|
31560
|
+
from: "$root.previewStage",
|
|
31561
|
+
fallback: "published"
|
|
31562
|
+
} },
|
|
31563
|
+
routeCandidates: { $bind: { from: "data.routeCandidates" } },
|
|
31564
|
+
wholeSeriesRunEvents: { $bind: { from: "data.wholeSeriesRunEvents" } },
|
|
31565
|
+
...offeringsPreviewEventDataBindings
|
|
31566
|
+
}, offeringsPreviewHeaderNodes())], { gap: "lg" }),
|
|
30924
31567
|
baseClass: "",
|
|
30925
31568
|
spacing: "comfortable"
|
|
30926
31569
|
})]
|
|
@@ -30934,16 +31577,48 @@ const offeringsPreviewBlockDefinition = {
|
|
|
30934
31577
|
dataSchemas: {
|
|
30935
31578
|
...offeringsPreviewEventDataSchemas,
|
|
30936
31579
|
routeCandidates: publicRouteCandidatesSchema.optional(),
|
|
30937
|
-
wholeSeriesRunEvents: optionalPublicEventsArraySchema
|
|
31580
|
+
wholeSeriesRunEvents: optionalPublicEventsArraySchema,
|
|
31581
|
+
catalogueEvents: optionalPublicEventsArraySchema,
|
|
31582
|
+
quickDateEvents: optionalPublicEventsArraySchema
|
|
30938
31583
|
},
|
|
30939
31584
|
dataLoaders: {
|
|
30940
31585
|
...offeringsPreviewEventDataLoaders,
|
|
30941
31586
|
routeCandidates: {
|
|
30942
31587
|
endpoint: "listPublicRouteCandidates",
|
|
31588
|
+
when: previewMode,
|
|
30943
31589
|
params: {},
|
|
30944
31590
|
mode: "server"
|
|
30945
31591
|
},
|
|
30946
|
-
wholeSeriesRunEvents: wholeSeriesRunLoader()
|
|
31592
|
+
wholeSeriesRunEvents: wholeSeriesRunLoader(),
|
|
31593
|
+
catalogueEvents: {
|
|
31594
|
+
endpoint: "listPublicEvents",
|
|
31595
|
+
when: catalogueMode,
|
|
31596
|
+
params: {
|
|
31597
|
+
stage: { $bind: {
|
|
31598
|
+
from: "$root.previewStage",
|
|
31599
|
+
fallback: "published"
|
|
31600
|
+
} },
|
|
31601
|
+
detailLevel: "listing",
|
|
31602
|
+
readProfile: "listing-card",
|
|
31603
|
+
readIntent: "catalogue"
|
|
31604
|
+
},
|
|
31605
|
+
mode: "server"
|
|
31606
|
+
},
|
|
31607
|
+
quickDateEvents: {
|
|
31608
|
+
endpoint: "listPublicEvents",
|
|
31609
|
+
when: catalogueMode,
|
|
31610
|
+
params: {
|
|
31611
|
+
stage: { $bind: {
|
|
31612
|
+
from: "$root.previewStage",
|
|
31613
|
+
fallback: "published"
|
|
31614
|
+
} },
|
|
31615
|
+
detailLevel: "listing",
|
|
31616
|
+
readProfile: "listing-card",
|
|
31617
|
+
readIntent: "occurrences",
|
|
31618
|
+
limit: 40
|
|
31619
|
+
},
|
|
31620
|
+
mode: "server"
|
|
31621
|
+
}
|
|
30947
31622
|
}
|
|
30948
31623
|
};
|
|
30949
31624
|
/**
|
|
@@ -30960,6 +31635,7 @@ function wholeSeriesRunLoader() {
|
|
|
30960
31635
|
function eventPresetLoader(eventPresets, extraParams = {}) {
|
|
30961
31636
|
return {
|
|
30962
31637
|
endpoint: "listPublicEvents",
|
|
31638
|
+
when: previewMode,
|
|
30963
31639
|
params: {
|
|
30964
31640
|
siteId: { $bind: { from: "$root.siteId" } },
|
|
30965
31641
|
limit: { $bind: {
|
|
@@ -30978,15 +31654,10 @@ function eventPresetLoader(eventPresets, extraParams = {}) {
|
|
|
30978
31654
|
mode: "server"
|
|
30979
31655
|
};
|
|
30980
31656
|
}
|
|
30981
|
-
function labelForOfferingPreviewSourceKey(sourceKey) {
|
|
30982
|
-
const eventDefinition = OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS.find((definition) => definition.sourceKey === sourceKey);
|
|
30983
|
-
if (eventDefinition) return eventDefinition.label;
|
|
30984
|
-
return "Courses";
|
|
30985
|
-
}
|
|
30986
31657
|
function normalizeOfferingsPreviewBlockContent(value) {
|
|
30987
31658
|
const record = normalizeOfferingsPreviewContentForWrite(value);
|
|
30988
|
-
if (!record) return {};
|
|
30989
|
-
const normalized = {};
|
|
31659
|
+
if (!record) return { displayMode: DEFAULT_OFFERINGS_PREVIEW_DISPLAY_MODE };
|
|
31660
|
+
const normalized = { displayMode: normalizeOfferingsPreviewDisplayMode(record.displayMode) };
|
|
30990
31661
|
if (typeof record.heading === "string" || record.heading === null) normalized.heading = record.heading;
|
|
30991
31662
|
if ("description" in record) normalized.description = record.description;
|
|
30992
31663
|
if (isOfferingsPreviewItemLimit(record.itemLimit)) normalized.itemLimit = record.itemLimit;
|
|
@@ -31003,6 +31674,9 @@ function normalizeOfferingsPreviewBlockContent(value) {
|
|
|
31003
31674
|
if (sectionStyles !== void 0) normalized._sectionStyles = sectionStyles;
|
|
31004
31675
|
return normalized;
|
|
31005
31676
|
}
|
|
31677
|
+
function normalizeOfferingsPreviewDisplayMode(value) {
|
|
31678
|
+
return value === "catalogue" ? "catalogue" : DEFAULT_OFFERINGS_PREVIEW_DISPLAY_MODE;
|
|
31679
|
+
}
|
|
31006
31680
|
function isOfferingsPreviewItemLimit(value) {
|
|
31007
31681
|
return value === "1" || value === "2" || value === "3" || value === "4" || value === "5" || value === "6" || value === null;
|
|
31008
31682
|
}
|
|
@@ -34217,63 +34891,13 @@ const giftingBlockDefinition = {
|
|
|
34217
34891
|
} }
|
|
34218
34892
|
};
|
|
34219
34893
|
//#endregion
|
|
34220
|
-
//#region ../blocks/src/system/blocks/newsletter-signup-destination.ts
|
|
34221
|
-
function parseNewsletterSignupBlockId(value) {
|
|
34222
|
-
const trimmed = parseTrimmedString(value);
|
|
34223
|
-
return trimmed && BLOCK_ID_PATTERN.test(trimmed) ? trimmed : null;
|
|
34224
|
-
}
|
|
34225
|
-
function parseSignedNewsletterDestinationRef(value) {
|
|
34226
|
-
const trimmed = parseTrimmedString(value);
|
|
34227
|
-
return trimmed && SIGNED_DESTINATION_REF_PATTERN.test(trimmed) ? trimmed : null;
|
|
34228
|
-
}
|
|
34229
|
-
function buildNewsletterSignupBlockRef(blockId) {
|
|
34230
|
-
const parsed = parseNewsletterSignupBlockId(blockId);
|
|
34231
|
-
return parsed ? {
|
|
34232
|
-
tag: "block_ref",
|
|
34233
|
-
blockId: parsed
|
|
34234
|
-
} : null;
|
|
34235
|
-
}
|
|
34236
|
-
function normalizeNewsletterSignupEditorValuesForDestination(values) {
|
|
34237
|
-
const destinationProvider = parseNewsletterSignupDestinationProvider(values.destinationProvider) ?? "riverbank";
|
|
34238
|
-
if (destinationProvider === "mailchimp") return {
|
|
34239
|
-
destinationProvider,
|
|
34240
|
-
mailchimpAudienceId: values.mailchimpAudienceId,
|
|
34241
|
-
mailchimpTags: values.mailchimpTags
|
|
34242
|
-
};
|
|
34243
|
-
return {
|
|
34244
|
-
destinationProvider,
|
|
34245
|
-
listId: values.listId,
|
|
34246
|
-
tags: values.tags
|
|
34247
|
-
};
|
|
34248
|
-
}
|
|
34249
|
-
function deriveNewsletterSignupRuntimeSource(values) {
|
|
34250
|
-
const normalized = normalizeNewsletterSignupEditorValuesForDestination(values);
|
|
34251
|
-
if (normalized.destinationProvider === "mailchimp") return {
|
|
34252
|
-
destinationProvider: "mailchimp",
|
|
34253
|
-
listId: null,
|
|
34254
|
-
tags: null
|
|
34255
|
-
};
|
|
34256
|
-
return {
|
|
34257
|
-
destinationProvider: "riverbank",
|
|
34258
|
-
listId: parseTrimmedString(normalized.listId),
|
|
34259
|
-
tags: parseTrimmedString(normalized.tags)
|
|
34260
|
-
};
|
|
34261
|
-
}
|
|
34262
|
-
const BLOCK_ID_PATTERN = /^[A-Za-z0-9._:-]{1,200}$/;
|
|
34263
|
-
const SIGNED_DESTINATION_REF_PATTERN = /^[A-Za-z0-9._~-]{16,1000}$/;
|
|
34264
|
-
function parseTrimmedString(value) {
|
|
34265
|
-
if (typeof value !== "string") return null;
|
|
34266
|
-
const trimmed = value.trim();
|
|
34267
|
-
return trimmed.length > 0 ? trimmed : null;
|
|
34268
|
-
}
|
|
34269
|
-
//#endregion
|
|
34270
34894
|
//#region ../blocks/src/system/runtime/nodes/newsletter-form.types.ts
|
|
34271
34895
|
/**
|
|
34272
34896
|
* Get form fields based on preset configuration.
|
|
34273
34897
|
*/
|
|
34274
|
-
function
|
|
34275
|
-
const includePhone =
|
|
34276
|
-
switch (preset) {
|
|
34898
|
+
function getGlobalFormFields(form) {
|
|
34899
|
+
const includePhone = form.includeOptionalPhone;
|
|
34900
|
+
switch (form.fields.preset) {
|
|
34277
34901
|
case "emailOnly": return withOptionalPhone([{
|
|
34278
34902
|
id: "email",
|
|
34279
34903
|
type: "email",
|
|
@@ -34291,7 +34915,7 @@ function getPresetFields(preset, options) {
|
|
|
34291
34915
|
id: "name",
|
|
34292
34916
|
type: "text",
|
|
34293
34917
|
label: "Name",
|
|
34294
|
-
required:
|
|
34918
|
+
required: form.fields.name === "required",
|
|
34295
34919
|
placeholder: "Your name"
|
|
34296
34920
|
}], includePhone);
|
|
34297
34921
|
case "emailFirstLast": return withOptionalPhone([
|
|
@@ -34306,14 +34930,14 @@ function getPresetFields(preset, options) {
|
|
|
34306
34930
|
id: "firstName",
|
|
34307
34931
|
type: "text",
|
|
34308
34932
|
label: "First Name",
|
|
34309
|
-
required:
|
|
34933
|
+
required: form.fields.firstName === "required",
|
|
34310
34934
|
placeholder: "First name"
|
|
34311
34935
|
},
|
|
34312
34936
|
{
|
|
34313
34937
|
id: "lastName",
|
|
34314
34938
|
type: "text",
|
|
34315
34939
|
label: "Last Name",
|
|
34316
|
-
required:
|
|
34940
|
+
required: form.fields.lastName === "required",
|
|
34317
34941
|
placeholder: "Last name"
|
|
34318
34942
|
}
|
|
34319
34943
|
], includePhone);
|
|
@@ -34329,14 +34953,14 @@ function getPresetFields(preset, options) {
|
|
|
34329
34953
|
id: "name",
|
|
34330
34954
|
type: "text",
|
|
34331
34955
|
label: "Name",
|
|
34332
|
-
required:
|
|
34956
|
+
required: form.fields.name === "required",
|
|
34333
34957
|
placeholder: "Your name"
|
|
34334
34958
|
},
|
|
34335
34959
|
{
|
|
34336
34960
|
id: "company",
|
|
34337
34961
|
type: "text",
|
|
34338
34962
|
label: "Company",
|
|
34339
|
-
required:
|
|
34963
|
+
required: form.fields.company === "required",
|
|
34340
34964
|
placeholder: "Company name"
|
|
34341
34965
|
}
|
|
34342
34966
|
], includePhone);
|
|
@@ -34355,14 +34979,29 @@ function withOptionalPhone(fields, includePhone) {
|
|
|
34355
34979
|
}
|
|
34356
34980
|
//#endregion
|
|
34357
34981
|
//#region ../blocks/src/system/runtime/nodes/newsletter-form.interactive.ts
|
|
34358
|
-
const newsletterPresetSchema = z.enum([
|
|
34359
|
-
"emailOnly",
|
|
34360
|
-
"emailName",
|
|
34361
|
-
"emailFirstLast",
|
|
34362
|
-
"emailNameCompany"
|
|
34363
|
-
]);
|
|
34364
|
-
const newsletterDestinationProviderSchema = z.enum(["riverbank", "mailchimp"]);
|
|
34365
34982
|
const newsletterButtonVariantSchema = blockButtonRoleSchema;
|
|
34983
|
+
const mailingListContextSchema = z.unknown().transform((value, ctx) => {
|
|
34984
|
+
const parsed = parseMailingListRuntimeContext(value);
|
|
34985
|
+
if (!parsed.ok) {
|
|
34986
|
+
ctx.addIssue({
|
|
34987
|
+
code: z.ZodIssueCode.custom,
|
|
34988
|
+
message: "Invalid mailing-list runtime context"
|
|
34989
|
+
});
|
|
34990
|
+
return z.NEVER;
|
|
34991
|
+
}
|
|
34992
|
+
return parsed.value;
|
|
34993
|
+
});
|
|
34994
|
+
const mailingListTargetingSchema = z.unknown().transform((value, ctx) => {
|
|
34995
|
+
const parsed = parseMailingListPlacementTargeting(value);
|
|
34996
|
+
if (!parsed.ok) {
|
|
34997
|
+
ctx.addIssue({
|
|
34998
|
+
code: z.ZodIssueCode.custom,
|
|
34999
|
+
message: "Invalid mailing-list targeting"
|
|
35000
|
+
});
|
|
35001
|
+
return z.NEVER;
|
|
35002
|
+
}
|
|
35003
|
+
return parsed.value;
|
|
35004
|
+
});
|
|
34366
35005
|
const newsletterFieldSchema = z.object({
|
|
34367
35006
|
id: z.string(),
|
|
34368
35007
|
type: z.enum(["email", "text"]),
|
|
@@ -34370,73 +35009,73 @@ const newsletterFieldSchema = z.object({
|
|
|
34370
35009
|
required: z.boolean(),
|
|
34371
35010
|
placeholder: z.string().optional()
|
|
34372
35011
|
});
|
|
34373
|
-
const
|
|
34374
|
-
const
|
|
35012
|
+
const mailingListSignupBlockIdSchema = z.string().trim().min(1).transform(parseRequiredMailingListSignupBlockId);
|
|
35013
|
+
const signedMailingListSourceTokenSchema = z.string().trim().min(1).transform(parseRequiredMailingListSignedSourceToken);
|
|
34375
35014
|
const newsletterSourceCommonSchema = z.object({
|
|
34376
35015
|
siteId: z.string().optional(),
|
|
34377
35016
|
apiBaseUrl: z.string().optional(),
|
|
34378
|
-
|
|
34379
|
-
|
|
34380
|
-
buttonLabel: z.string().nullable().optional(),
|
|
35017
|
+
mailingList: mailingListContextSchema.optional(),
|
|
35018
|
+
targeting: mailingListTargetingSchema.optional(),
|
|
34381
35019
|
buttonVariant: newsletterButtonVariantSchema.nullable().optional(),
|
|
34382
|
-
successMessage: z.string().nullable().optional(),
|
|
34383
|
-
privacyNote: z.string().nullable().optional(),
|
|
34384
|
-
tags: z.string().nullable().optional(),
|
|
34385
35020
|
spamProtectionEnabled: z.boolean().optional(),
|
|
34386
35021
|
className: z.string().nullable().optional()
|
|
34387
35022
|
});
|
|
34388
35023
|
const newsletterSourceSchema = z.discriminatedUnion("source", [
|
|
34389
35024
|
newsletterSourceCommonSchema.extend({
|
|
34390
35025
|
source: z.literal("block"),
|
|
34391
|
-
blockId: z.string().nullable().optional()
|
|
34392
|
-
listId: z.string().nullable().optional(),
|
|
34393
|
-
destinationProvider: newsletterDestinationProviderSchema.nullable().optional()
|
|
35026
|
+
blockId: z.string().nullable().optional()
|
|
34394
35027
|
}),
|
|
34395
35028
|
newsletterSourceCommonSchema.extend({
|
|
34396
35029
|
source: z.literal("signed-footer"),
|
|
34397
|
-
|
|
34398
|
-
tag: z.literal("
|
|
34399
|
-
token:
|
|
35030
|
+
sourceRef: z.object({
|
|
35031
|
+
tag: z.literal("signed_source_ref"),
|
|
35032
|
+
token: signedMailingListSourceTokenSchema
|
|
34400
35033
|
})
|
|
34401
35034
|
}),
|
|
34402
|
-
newsletterSourceCommonSchema.extend({
|
|
34403
|
-
source: z.literal("legacy-direct-list"),
|
|
34404
|
-
listId: z.string().nullable()
|
|
34405
|
-
})
|
|
35035
|
+
newsletterSourceCommonSchema.extend({ source: z.literal("preview") })
|
|
34406
35036
|
]);
|
|
34407
35037
|
const newsletterDisplaySchema = z.object({
|
|
34408
35038
|
kind: z.literal("newsletter-form"),
|
|
35039
|
+
availability: z.enum(["ready", "unavailable"]),
|
|
34409
35040
|
className: z.string().nullable(),
|
|
34410
35041
|
buttonLabel: z.string(),
|
|
34411
35042
|
buttonVariant: newsletterButtonVariantSchema,
|
|
34412
|
-
successMessage: z.string().nullable(),
|
|
34413
35043
|
privacyNote: z.string().nullable(),
|
|
34414
|
-
fields: z.array(newsletterFieldSchema)
|
|
35044
|
+
fields: z.array(newsletterFieldSchema),
|
|
35045
|
+
choices: z.array(z.object({
|
|
35046
|
+
id: z.string(),
|
|
35047
|
+
label: z.string()
|
|
35048
|
+
}))
|
|
34415
35049
|
});
|
|
34416
35050
|
const newsletterHydrationSchema = z.object({
|
|
34417
35051
|
target: z.discriminatedUnion("tag", [
|
|
34418
35052
|
z.object({
|
|
34419
35053
|
tag: z.literal("block-source"),
|
|
34420
|
-
|
|
35054
|
+
sourceRef: z.object({
|
|
34421
35055
|
tag: z.literal("block_ref"),
|
|
34422
|
-
blockId:
|
|
35056
|
+
blockId: mailingListSignupBlockIdSchema
|
|
34423
35057
|
}).nullable()
|
|
34424
35058
|
}),
|
|
34425
35059
|
z.object({
|
|
34426
35060
|
tag: z.literal("signed-footer-source"),
|
|
34427
|
-
|
|
34428
|
-
tag: z.literal("
|
|
34429
|
-
token:
|
|
35061
|
+
sourceRef: z.object({
|
|
35062
|
+
tag: z.literal("signed_source_ref"),
|
|
35063
|
+
token: signedMailingListSourceTokenSchema
|
|
34430
35064
|
})
|
|
34431
35065
|
}),
|
|
34432
|
-
z.object({
|
|
34433
|
-
|
|
34434
|
-
|
|
34435
|
-
|
|
35066
|
+
z.object({ tag: z.literal("preview") })
|
|
35067
|
+
]),
|
|
35068
|
+
setupRevision: z.number().int().positive().nullable(),
|
|
35069
|
+
choiceProvider: z.enum([
|
|
35070
|
+
"native",
|
|
35071
|
+
"brevo",
|
|
35072
|
+
"mailchimp"
|
|
35073
|
+
]).nullable(),
|
|
35074
|
+
choicePresentation: z.enum([
|
|
35075
|
+
"hidden",
|
|
35076
|
+
"automatic",
|
|
35077
|
+
"visitor_choice"
|
|
34436
35078
|
]),
|
|
34437
|
-
preset: newsletterPresetSchema,
|
|
34438
|
-
includePhone: z.boolean(),
|
|
34439
|
-
tags: z.string().nullable().optional(),
|
|
34440
35079
|
spamProtectionEnabled: z.boolean().optional()
|
|
34441
35080
|
});
|
|
34442
35081
|
const newsletterRenderSchema = z.object({
|
|
@@ -34448,16 +35087,24 @@ z.object({
|
|
|
34448
35087
|
apiBaseUrl: z.string().optional()
|
|
34449
35088
|
});
|
|
34450
35089
|
function buildNewsletterDisplay(source) {
|
|
34451
|
-
const
|
|
34452
|
-
const
|
|
35090
|
+
const context = source.mailingList;
|
|
35091
|
+
const form = context?.tag === "configured" ? context.form : {
|
|
35092
|
+
fields: { preset: "emailOnly" },
|
|
35093
|
+
includeOptionalPhone: false,
|
|
35094
|
+
buttonLabel: "Subscribe",
|
|
35095
|
+
privacyNote: null
|
|
35096
|
+
};
|
|
35097
|
+
const targeting = source.targeting ?? { mode: "default" };
|
|
35098
|
+
const choices = resolveRuntimeChoices(context, targeting);
|
|
34453
35099
|
return {
|
|
34454
35100
|
kind: "newsletter-form",
|
|
35101
|
+
availability: runtimeTargetingIsAvailable(context, targeting, choices) ? "ready" : "unavailable",
|
|
34455
35102
|
className: source.className ?? null,
|
|
34456
|
-
buttonLabel:
|
|
35103
|
+
buttonLabel: form.buttonLabel,
|
|
34457
35104
|
buttonVariant: source.buttonVariant ?? "primary",
|
|
34458
|
-
|
|
34459
|
-
|
|
34460
|
-
|
|
35105
|
+
privacyNote: form.privacyNote,
|
|
35106
|
+
fields: getGlobalFormFields(form),
|
|
35107
|
+
choices
|
|
34461
35108
|
};
|
|
34462
35109
|
}
|
|
34463
35110
|
const newsletterFormBlockRuntime = defineProgressiveBlockRuntime({
|
|
@@ -34467,14 +35114,15 @@ const newsletterFormBlockRuntime = defineProgressiveBlockRuntime({
|
|
|
34467
35114
|
render: createZodCodec(newsletterRenderSchema)
|
|
34468
35115
|
},
|
|
34469
35116
|
buildRender: (source) => {
|
|
34470
|
-
const
|
|
35117
|
+
const targeting = source.targeting ?? { mode: "default" };
|
|
35118
|
+
const presentation = planMailingListChoicePresentation(targeting);
|
|
34471
35119
|
return {
|
|
34472
35120
|
display: buildNewsletterDisplay(source),
|
|
34473
35121
|
hydration: {
|
|
34474
35122
|
target: projectNewsletterFormHydrationTarget(source),
|
|
34475
|
-
|
|
34476
|
-
|
|
34477
|
-
|
|
35123
|
+
setupRevision: source.mailingList?.tag === "configured" ? source.mailingList.revision : null,
|
|
35124
|
+
choiceProvider: targeting.mode === "custom" ? targeting.provider : null,
|
|
35125
|
+
choicePresentation: presentation.tag,
|
|
34478
35126
|
spamProtectionEnabled: source.spamProtectionEnabled
|
|
34479
35127
|
}
|
|
34480
35128
|
};
|
|
@@ -34483,35 +35131,87 @@ const newsletterFormBlockRuntime = defineProgressiveBlockRuntime({
|
|
|
34483
35131
|
function projectNewsletterFormHydrationTarget(source) {
|
|
34484
35132
|
switch (source.source) {
|
|
34485
35133
|
case "block": {
|
|
34486
|
-
const
|
|
34487
|
-
if (
|
|
35134
|
+
const sourceRef = buildMailingListSignupBlockSourceRef(source.blockId);
|
|
35135
|
+
if (sourceRef?.tag === "block_ref") return {
|
|
34488
35136
|
tag: "block-source",
|
|
34489
|
-
|
|
35137
|
+
sourceRef
|
|
34490
35138
|
};
|
|
34491
35139
|
return {
|
|
34492
|
-
tag: "
|
|
34493
|
-
|
|
35140
|
+
tag: "block-source",
|
|
35141
|
+
sourceRef: null
|
|
34494
35142
|
};
|
|
34495
35143
|
}
|
|
34496
35144
|
case "signed-footer": return {
|
|
34497
35145
|
tag: "signed-footer-source",
|
|
34498
|
-
|
|
34499
|
-
};
|
|
34500
|
-
case "legacy-direct-list": return {
|
|
34501
|
-
tag: "legacy-direct-list",
|
|
34502
|
-
listId: source.listId
|
|
35146
|
+
sourceRef: source.sourceRef
|
|
34503
35147
|
};
|
|
35148
|
+
case "preview": return { tag: "preview" };
|
|
34504
35149
|
default: return assertNever$2(source);
|
|
34505
35150
|
}
|
|
34506
35151
|
}
|
|
34507
|
-
function
|
|
34508
|
-
|
|
34509
|
-
|
|
35152
|
+
function resolveRuntimeChoices(context, targeting) {
|
|
35153
|
+
if (context?.tag !== "configured" || targeting.mode !== "custom" || targeting.selection.tag !== "visitor_choice" || context.provider.provider !== targeting.provider) return [];
|
|
35154
|
+
switch (targeting.provider) {
|
|
35155
|
+
case "native": {
|
|
35156
|
+
const offered = new Set(targeting.selection.offeredTopicIds);
|
|
35157
|
+
return context.provider.provider === "native" ? context.provider.topics.filter((item) => offered.has(item.id)).map((item) => ({
|
|
35158
|
+
id: item.id,
|
|
35159
|
+
label: item.name
|
|
35160
|
+
})) : [];
|
|
35161
|
+
}
|
|
35162
|
+
case "brevo": {
|
|
35163
|
+
const offered = new Set(targeting.selection.offeredListIds);
|
|
35164
|
+
return context.provider.provider === "brevo" ? context.provider.lists.filter((item) => offered.has(item.id)).map((item) => ({
|
|
35165
|
+
id: String(item.id),
|
|
35166
|
+
label: item.name
|
|
35167
|
+
})) : [];
|
|
35168
|
+
}
|
|
35169
|
+
case "mailchimp": {
|
|
35170
|
+
const offered = new Set(targeting.selection.offeredInterestIds);
|
|
35171
|
+
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) => ({
|
|
35172
|
+
id: item.id,
|
|
35173
|
+
label: item.name
|
|
35174
|
+
})) ?? [];
|
|
35175
|
+
}
|
|
35176
|
+
}
|
|
35177
|
+
}
|
|
35178
|
+
function runtimeTargetingIsAvailable(context, targeting, choices) {
|
|
35179
|
+
if (context?.tag !== "configured") return false;
|
|
35180
|
+
const provider = context.provider;
|
|
35181
|
+
if (targeting.mode === "default") switch (provider.provider) {
|
|
35182
|
+
case "native": return provider.topics.some((item) => item.id === provider.defaultTopicId);
|
|
35183
|
+
case "brevo": return provider.lists.some((item) => item.id === provider.defaultListId);
|
|
35184
|
+
case "mailchimp": return provider.audiences.some((item) => item.id === provider.defaultAudienceId);
|
|
35185
|
+
}
|
|
35186
|
+
if (targeting.provider !== provider.provider) return false;
|
|
35187
|
+
switch (targeting.provider) {
|
|
35188
|
+
case "native": return provider.provider === "native" && nativeTargetIsAvailable(provider, targeting, choices);
|
|
35189
|
+
case "brevo": return provider.provider === "brevo" && brevoTargetIsAvailable(provider, targeting, choices);
|
|
35190
|
+
case "mailchimp": return provider.provider === "mailchimp" && mailchimpTargetIsAvailable(provider, targeting, choices);
|
|
35191
|
+
}
|
|
35192
|
+
}
|
|
35193
|
+
function nativeTargetIsAvailable(provider, targeting, choices) {
|
|
35194
|
+
const ids = targeting.selection.tag === "fixed" ? targeting.selection.topicIds : targeting.selection.offeredTopicIds;
|
|
35195
|
+
return ids.every((id) => provider.topics.some((item) => item.id === id)) && (targeting.selection.tag !== "visitor_choice" || choices.length === ids.length);
|
|
35196
|
+
}
|
|
35197
|
+
function brevoTargetIsAvailable(provider, targeting, choices) {
|
|
35198
|
+
const ids = targeting.selection.tag === "fixed" ? targeting.selection.listIds : targeting.selection.offeredListIds;
|
|
35199
|
+
return ids.every((id) => provider.lists.some((item) => item.id === id)) && (targeting.selection.tag !== "visitor_choice" || choices.length === ids.length);
|
|
35200
|
+
}
|
|
35201
|
+
function mailchimpTargetIsAvailable(provider, targeting, choices) {
|
|
35202
|
+
const audience = provider.audiences.find((item) => item.id === targeting.audienceId);
|
|
35203
|
+
if (!audience) return false;
|
|
35204
|
+
const ids = targeting.selection.tag === "fixed" ? targeting.selection.interestIds : targeting.selection.offeredInterestIds;
|
|
35205
|
+
return ids.every((id) => audience.interests.some((item) => item.id === id)) && (targeting.selection.tag !== "visitor_choice" || choices.length === ids.length);
|
|
35206
|
+
}
|
|
35207
|
+
function parseRequiredMailingListSignupBlockId(value) {
|
|
35208
|
+
const parsed = parseMailingListBlockId(value);
|
|
35209
|
+
if (!parsed) throw new Error("Mailing-list signup block source ref requires blockId");
|
|
34510
35210
|
return parsed;
|
|
34511
35211
|
}
|
|
34512
|
-
function
|
|
34513
|
-
const parsed =
|
|
34514
|
-
if (!parsed) throw new Error("
|
|
35212
|
+
function parseRequiredMailingListSignedSourceToken(value) {
|
|
35213
|
+
const parsed = parseMailingListSignedSourceToken(value);
|
|
35214
|
+
if (!parsed) throw new Error("Mailing-list signup signed source ref requires token");
|
|
34515
35215
|
return parsed;
|
|
34516
35216
|
}
|
|
34517
35217
|
//#endregion
|
|
@@ -35884,6 +36584,14 @@ const systemBlockDefinitions = [
|
|
|
35884
36584
|
weight: "standard"
|
|
35885
36585
|
})]
|
|
35886
36586
|
})),
|
|
36587
|
+
withDesignCapability("block.appointment-services", appointmentServicesBlockDefinition, sectionOnly(), defineBlockDesignMetadata({
|
|
36588
|
+
flow: conversionFlow,
|
|
36589
|
+
layoutProfiles: [layoutProfile({
|
|
36590
|
+
variantKey: "default",
|
|
36591
|
+
family: "stack",
|
|
36592
|
+
weight: "standard"
|
|
36593
|
+
})]
|
|
36594
|
+
})),
|
|
35887
36595
|
withDesignCapability("block.weekly-slot-availability", weeklySlotAvailabilityBlockDefinition, sectionOnly(), defineBlockDesignMetadata({
|
|
35888
36596
|
flow: offeringsFlow,
|
|
35889
36597
|
layoutProfiles: [layoutProfile({
|
|
@@ -37782,6 +38490,7 @@ const SYSTEM_BLOCK_KINDS = [
|
|
|
37782
38490
|
"block.form",
|
|
37783
38491
|
"block.contact-newsletter",
|
|
37784
38492
|
"block.appointment-booking",
|
|
38493
|
+
"block.appointment-services",
|
|
37785
38494
|
"block.weekly-slot-availability",
|
|
37786
38495
|
"block.event-registration",
|
|
37787
38496
|
"block.event-details",
|
|
@@ -38060,18 +38769,13 @@ const navigationItemConfigSchema = z.object({
|
|
|
38060
38769
|
isCta: z.boolean().optional()
|
|
38061
38770
|
}).extend({ children: z.lazy(() => z.array(navigationItemConfigSchema)).optional() });
|
|
38062
38771
|
const navigationMenuConfigSchema = z.object({
|
|
38063
|
-
|
|
38064
|
-
|
|
38065
|
-
|
|
38066
|
-
|
|
38067
|
-
|
|
38772
|
+
location: z.enum([
|
|
38773
|
+
"main",
|
|
38774
|
+
"footer",
|
|
38775
|
+
"legal"
|
|
38776
|
+
]),
|
|
38068
38777
|
items: z.array(navigationItemConfigSchema)
|
|
38069
|
-
}).superRefine((menu, ctx) => {
|
|
38070
|
-
if (menu.footerRole !== void 0 && menu.isFooter !== void 0 && menu.isFooter !== (menu.footerRole === "main")) ctx.addIssue({
|
|
38071
|
-
code: "custom",
|
|
38072
|
-
message: "footerRole and isFooter disagree",
|
|
38073
|
-
path: ["footerRole"]
|
|
38074
|
-
});
|
|
38778
|
+
}).strict().superRefine((menu, ctx) => {
|
|
38075
38779
|
const portalStats = collectPortalLinkStats(menu.items);
|
|
38076
38780
|
if (portalStats.count > 1) ctx.addIssue({
|
|
38077
38781
|
code: z.ZodIssueCode.custom,
|
|
@@ -38158,11 +38862,11 @@ const contentConfigSchema = z.object({
|
|
|
38158
38862
|
});
|
|
38159
38863
|
}
|
|
38160
38864
|
if (data.navigationMenus && data.navigationMenus.length > 1) {
|
|
38161
|
-
const
|
|
38162
|
-
const
|
|
38163
|
-
if (
|
|
38865
|
+
const locations = data.navigationMenus.map((m) => m.location);
|
|
38866
|
+
const duplicateLocations = locations.filter((location, i) => locations.indexOf(location) !== i);
|
|
38867
|
+
if (duplicateLocations.length > 0) ctx.addIssue({
|
|
38164
38868
|
code: z.ZodIssueCode.custom,
|
|
38165
|
-
message: `Navigation
|
|
38869
|
+
message: `Navigation locations must be unique. Duplicates: ${duplicateLocations.join(", ")}`,
|
|
38166
38870
|
path: ["navigationMenus"]
|
|
38167
38871
|
});
|
|
38168
38872
|
}
|