riverbankcms 0.6.0 → 0.7.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/dist/acceptance/matrix.mjs +24 -38
- package/dist/cli/index.mjs +2339 -1952
- package/dist/cli/init-docs/content/cli-reference.md +12 -17
- package/dist/cli/init-docs/content/content-management.md +4 -5
- package/dist/cli/init-docs/content/workflow-isr-revalidation.md +1 -1
- package/dist/{eventUpsertInputSchema-CtkDnYlQ.mjs → eventUpsertInputSchema-CWglzaib.mjs} +2 -2
- package/dist/load-config-CZ9qKC9m.mjs +5 -0
- package/dist/{load-config-DbMjs6df.mjs → load-config-DBGNYfxV.mjs} +1 -1
- package/dist/{plan-DubdLR3N.mjs → plan-DgjlCWxa.mjs} +22 -14
- package/dist/scaffold/index.mjs +2 -2
- package/dist/{sdk-event-upsert-CvFCbzNc.mjs → sdk-event-upsert-CS9tY-KW.mjs} +44 -17
- package/dist/{sdk-peer-CyQ2so48.mjs → sdk-peer-BjTmH5Mt.mjs} +3 -3
- package/dist/{src-X9oZOIoK.mjs → src-DT7DBZtQ.mjs} +1083 -131
- package/dist/{style-aixm8BXi.mjs → style-D2srLsI5.mjs} +11 -18
- package/dist/testing.mjs +4 -4
- package/package.json +2 -2
- package/dist/load-config-NNJ0ww1N.mjs +0 -5
|
@@ -814,20 +814,20 @@ function parseOptionAvailability(input) {
|
|
|
814
814
|
function parseEventPricingOption(input) {
|
|
815
815
|
const identity = parseOptionIdentity(input);
|
|
816
816
|
const commercials = parseOptionCommercials(input);
|
|
817
|
-
const availability = parseOptionAvailability(input);
|
|
817
|
+
const availability$1 = parseOptionAvailability(input);
|
|
818
818
|
const issues = [
|
|
819
819
|
identity,
|
|
820
820
|
commercials,
|
|
821
|
-
availability
|
|
821
|
+
availability$1
|
|
822
822
|
].flatMap((result) => result.ok ? [] : [result.error]);
|
|
823
|
-
if (!identity.ok || !commercials.ok || !availability.ok) {
|
|
823
|
+
if (!identity.ok || !commercials.ok || !availability$1.ok) {
|
|
824
824
|
const nonEmptyIssues = fromReadonlyArray(issues);
|
|
825
825
|
return err(nonEmptyIssues.ok ? nonEmptyIssues.value : oneIssue({ kind: "invalid_object" }));
|
|
826
826
|
}
|
|
827
827
|
return ok({
|
|
828
828
|
...identity.value,
|
|
829
829
|
...commercials.value,
|
|
830
|
-
...availability.value
|
|
830
|
+
...availability$1.value
|
|
831
831
|
});
|
|
832
832
|
}
|
|
833
833
|
function unexpectedValues(input, fields) {
|
|
@@ -1303,7 +1303,7 @@ function parseEventPageSurfaceDestinationMode(value) {
|
|
|
1303
1303
|
return value === "cms-managed" || value === "system-managed" ? value : undefined;
|
|
1304
1304
|
}
|
|
1305
1305
|
function parseEventPageSurfaceSubject(value) {
|
|
1306
|
-
if (!isRecord$
|
|
1306
|
+
if (!isRecord$8(value)) return err({ kind: "notObject" });
|
|
1307
1307
|
switch (value.kind) {
|
|
1308
1308
|
case "eventSeries": {
|
|
1309
1309
|
const eventSeriesId = parseEventSeriesId(value.eventSeriesId);
|
|
@@ -1373,7 +1373,7 @@ function parseEventSeriesIdList(values) {
|
|
|
1373
1373
|
}
|
|
1374
1374
|
return ok(parsed);
|
|
1375
1375
|
}
|
|
1376
|
-
function isRecord$
|
|
1376
|
+
function isRecord$8(value) {
|
|
1377
1377
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1378
1378
|
}
|
|
1379
1379
|
|
|
@@ -3239,7 +3239,7 @@ const knownSocialPlatforms = [
|
|
|
3239
3239
|
"x",
|
|
3240
3240
|
"youtube"
|
|
3241
3241
|
];
|
|
3242
|
-
function isRecord$
|
|
3242
|
+
function isRecord$7(value) {
|
|
3243
3243
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3244
3244
|
}
|
|
3245
3245
|
function trimmedOptionalString(value) {
|
|
@@ -3249,7 +3249,7 @@ function trimmedOptionalString(value) {
|
|
|
3249
3249
|
return trimmed.length > 0 ? trimmed : null;
|
|
3250
3250
|
}
|
|
3251
3251
|
function parsePublicContactDetails(value) {
|
|
3252
|
-
if (!isRecord$
|
|
3252
|
+
if (!isRecord$7(value)) {
|
|
3253
3253
|
return err({
|
|
3254
3254
|
code: "invalid_shape",
|
|
3255
3255
|
path: "contact",
|
|
@@ -3345,7 +3345,7 @@ function minutesSinceMidnight(value) {
|
|
|
3345
3345
|
}
|
|
3346
3346
|
function parseOpeningHoursDay(value, expectedWeekday, index) {
|
|
3347
3347
|
const path = `openingHours.days.${index}`;
|
|
3348
|
-
if (!isRecord$
|
|
3348
|
+
if (!isRecord$7(value) || value.weekday !== expectedWeekday) {
|
|
3349
3349
|
return err({
|
|
3350
3350
|
code: "invalid_weekdays",
|
|
3351
3351
|
path,
|
|
@@ -3366,7 +3366,7 @@ function parseOpeningHoursDay(value, expectedWeekday, index) {
|
|
|
3366
3366
|
const intervals = [];
|
|
3367
3367
|
for (const [intervalIndex, rawInterval] of value.intervals.entries()) {
|
|
3368
3368
|
const intervalPath = `${path}.intervals.${intervalIndex}`;
|
|
3369
|
-
if (!isRecord$
|
|
3369
|
+
if (!isRecord$7(rawInterval)) {
|
|
3370
3370
|
return err({
|
|
3371
3371
|
code: "invalid_interval",
|
|
3372
3372
|
path: intervalPath,
|
|
@@ -3416,7 +3416,7 @@ function parseOpeningHoursDay(value, expectedWeekday, index) {
|
|
|
3416
3416
|
});
|
|
3417
3417
|
}
|
|
3418
3418
|
function parseWeeklyOpeningHours(value) {
|
|
3419
|
-
if (!isRecord$
|
|
3419
|
+
if (!isRecord$7(value) || !Array.isArray(value.days) || value.days.length !== publicProfileWeekdays.length) {
|
|
3420
3420
|
return err({
|
|
3421
3421
|
code: "invalid_weekdays",
|
|
3422
3422
|
path: "openingHours.days",
|
|
@@ -3496,7 +3496,7 @@ function parsePublicSocialLinks(value) {
|
|
|
3496
3496
|
const ids = new Set();
|
|
3497
3497
|
for (const [index, rawLink] of value.entries()) {
|
|
3498
3498
|
const path = `socialLinks.${index}`;
|
|
3499
|
-
if (!isRecord$
|
|
3499
|
+
if (!isRecord$7(rawLink)) {
|
|
3500
3500
|
return err({
|
|
3501
3501
|
code: "invalid_social_link",
|
|
3502
3502
|
path,
|
|
@@ -3543,7 +3543,7 @@ function parsePublicSocialLinks(value) {
|
|
|
3543
3543
|
return ok(links);
|
|
3544
3544
|
}
|
|
3545
3545
|
function parsePublicProfile(value) {
|
|
3546
|
-
if (!isRecord$
|
|
3546
|
+
if (!isRecord$7(value)) {
|
|
3547
3547
|
return err({
|
|
3548
3548
|
code: "invalid_shape",
|
|
3549
3549
|
path: "",
|
|
@@ -3556,23 +3556,36 @@ function parsePublicProfile(value) {
|
|
|
3556
3556
|
if (!openingHours.ok) return openingHours;
|
|
3557
3557
|
const socialLinks = parsePublicSocialLinks(value.socialLinks);
|
|
3558
3558
|
if (!socialLinks.ok) return socialLinks;
|
|
3559
|
+
const addressVisibility = parseAddressVisibility(value.addressVisibility);
|
|
3560
|
+
if (!addressVisibility.ok) return addressVisibility;
|
|
3559
3561
|
return ok({
|
|
3560
3562
|
contact: contact.value,
|
|
3561
3563
|
openingHours: openingHours.value,
|
|
3562
|
-
socialLinks: socialLinks.value
|
|
3564
|
+
socialLinks: socialLinks.value,
|
|
3565
|
+
addressVisibility: addressVisibility.value
|
|
3566
|
+
});
|
|
3567
|
+
}
|
|
3568
|
+
function parseAddressVisibility(value) {
|
|
3569
|
+
if (value === undefined || value === null) return ok("shown");
|
|
3570
|
+
if (value === "shown" || value === "hidden") return ok(value);
|
|
3571
|
+
return err({
|
|
3572
|
+
code: "invalid_address_visibility",
|
|
3573
|
+
path: "addressVisibility",
|
|
3574
|
+
message: "Address visibility must be shown or hidden."
|
|
3563
3575
|
});
|
|
3564
3576
|
}
|
|
3565
3577
|
function emptyPublicProfile() {
|
|
3566
3578
|
return {
|
|
3567
3579
|
contact: null,
|
|
3568
3580
|
openingHours: null,
|
|
3569
|
-
socialLinks: []
|
|
3581
|
+
socialLinks: [],
|
|
3582
|
+
addressVisibility: "shown"
|
|
3570
3583
|
};
|
|
3571
3584
|
}
|
|
3572
3585
|
|
|
3573
3586
|
//#endregion
|
|
3574
3587
|
//#region ../core/src/rich-text.ts
|
|
3575
|
-
function isRecord$
|
|
3588
|
+
function isRecord$6(value) {
|
|
3576
3589
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3577
3590
|
}
|
|
3578
3591
|
function hasOnlyKeys(value, allowed) {
|
|
@@ -3594,10 +3607,10 @@ function isDenseArrayOf(value, predicate) {
|
|
|
3594
3607
|
return true;
|
|
3595
3608
|
}
|
|
3596
3609
|
function isTipTapMark(value) {
|
|
3597
|
-
return isRecord$
|
|
3610
|
+
return isRecord$6(value) && hasOnlyKeys(value, markKeys) && typeof value.type === "string" && value.type.length > 0 && (value.attrs === undefined || isRecord$6(value.attrs));
|
|
3598
3611
|
}
|
|
3599
3612
|
function isTipTapNode(value) {
|
|
3600
|
-
if (!isRecord$
|
|
3613
|
+
if (!isRecord$6(value) || !hasOnlyKeys(value, nodeKeys) || typeof value.type !== "string" || value.type.length === 0 || value.type === "doc" || value.attrs !== undefined && !isRecord$6(value.attrs) || value.marks !== undefined && (!Array.isArray(value.marks) || !isDenseArrayOf(value.marks, isTipTapMark)) || value.content !== undefined && (!Array.isArray(value.content) || !isDenseArrayOf(value.content, isTipTapNode))) {
|
|
3601
3614
|
return false;
|
|
3602
3615
|
}
|
|
3603
3616
|
if (value.type === "text") {
|
|
@@ -3606,89 +3619,222 @@ function isTipTapNode(value) {
|
|
|
3606
3619
|
return value.text === undefined;
|
|
3607
3620
|
}
|
|
3608
3621
|
function isCanonicalRichTextDoc(value) {
|
|
3609
|
-
return isRecord$
|
|
3622
|
+
return isRecord$6(value) && hasOnlyKeys(value, rootKeys) && value.type === "doc" && Array.isArray(value.content) && isDenseArrayOf(value.content, isTipTapNode);
|
|
3610
3623
|
}
|
|
3611
3624
|
|
|
3612
3625
|
//#endregion
|
|
3613
|
-
//#region ../core/src/
|
|
3626
|
+
//#region ../core/src/mailing-list-identifiers.ts
|
|
3614
3627
|
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;
|
|
3615
|
-
const
|
|
3628
|
+
const OPAQUE_ID_PATTERN = /^[A-Za-z0-9_-]{1,100}$/u;
|
|
3616
3629
|
const CONTROL_CHARACTER_PATTERN = /[\u0000-\u001f\u007f]/u;
|
|
3617
|
-
function
|
|
3618
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3619
|
-
}
|
|
3620
|
-
function parseTrimmedString(value) {
|
|
3630
|
+
function parseTrimmedMatchingString(value, pattern) {
|
|
3621
3631
|
if (typeof value !== "string") return null;
|
|
3622
3632
|
const trimmed = value.trim();
|
|
3623
|
-
return trimmed
|
|
3633
|
+
return pattern.test(trimmed) ? trimmed : null;
|
|
3634
|
+
}
|
|
3635
|
+
function parsePositiveInteger(value) {
|
|
3636
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value > 0 ? value : null;
|
|
3624
3637
|
}
|
|
3625
3638
|
function parseNewsletterListId(value) {
|
|
3626
|
-
|
|
3627
|
-
return trimmed !== null && UUID_PATTERN.test(trimmed) ? trimmed : null;
|
|
3639
|
+
return parseTrimmedMatchingString(value, UUID_PATTERN);
|
|
3628
3640
|
}
|
|
3629
3641
|
function parseMailchimpConnectionId(value) {
|
|
3630
|
-
|
|
3631
|
-
|
|
3642
|
+
return parseTrimmedMatchingString(value, UUID_PATTERN);
|
|
3643
|
+
}
|
|
3644
|
+
function parseMailchimpAccountId(value) {
|
|
3645
|
+
return parseTrimmedMatchingString(value, OPAQUE_ID_PATTERN);
|
|
3632
3646
|
}
|
|
3633
3647
|
function parseMailchimpAudienceId(value) {
|
|
3634
|
-
|
|
3635
|
-
|
|
3648
|
+
return parseTrimmedMatchingString(value, OPAQUE_ID_PATTERN);
|
|
3649
|
+
}
|
|
3650
|
+
function parseMailchimpInterestId(value) {
|
|
3651
|
+
return parseTrimmedMatchingString(value, OPAQUE_ID_PATTERN);
|
|
3636
3652
|
}
|
|
3637
3653
|
function parseMailchimpTagName(value) {
|
|
3638
|
-
|
|
3639
|
-
|
|
3640
|
-
|
|
3641
|
-
|
|
3642
|
-
|
|
3643
|
-
|
|
3644
|
-
|
|
3645
|
-
|
|
3646
|
-
|
|
3647
|
-
|
|
3648
|
-
|
|
3649
|
-
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
|
|
3653
|
-
|
|
3654
|
+
if (typeof value !== "string") return null;
|
|
3655
|
+
const trimmed = value.trim();
|
|
3656
|
+
return trimmed.length > 0 && trimmed.length <= 100 && !CONTROL_CHARACTER_PATTERN.test(trimmed) ? trimmed : null;
|
|
3657
|
+
}
|
|
3658
|
+
function parseBrevoConnectionId(value) {
|
|
3659
|
+
return parseTrimmedMatchingString(value, UUID_PATTERN);
|
|
3660
|
+
}
|
|
3661
|
+
function parseBrevoAccountId(value) {
|
|
3662
|
+
return parseTrimmedMatchingString(value, OPAQUE_ID_PATTERN);
|
|
3663
|
+
}
|
|
3664
|
+
function parseBrevoListId(value) {
|
|
3665
|
+
return parsePositiveInteger(value);
|
|
3666
|
+
}
|
|
3667
|
+
function parseBrevoConfirmationTemplateId(value) {
|
|
3668
|
+
return parsePositiveInteger(value);
|
|
3669
|
+
}
|
|
3670
|
+
|
|
3671
|
+
//#endregion
|
|
3672
|
+
//#region ../core/src/mailing-list-targeting-parser.ts
|
|
3673
|
+
function parseMailingListPlacementTargeting(value) {
|
|
3674
|
+
if (!isRecord$5(value)) return targetingError("shape");
|
|
3675
|
+
if (value.mode === "default") return ok({ mode: "default" });
|
|
3676
|
+
if (value.mode !== "custom") return targetingError("mode");
|
|
3677
|
+
if (!isRecord$5(value.selection)) return targetingError("selection");
|
|
3678
|
+
switch (value.provider) {
|
|
3679
|
+
case "native": return parseNativeTargeting(value.selection);
|
|
3680
|
+
case "brevo": return parseBrevoTargeting(value.selection);
|
|
3681
|
+
case "mailchimp": return parseMailchimpTargeting(value, value.selection);
|
|
3682
|
+
default: return targetingError("provider");
|
|
3683
|
+
}
|
|
3684
|
+
}
|
|
3685
|
+
function parseMailingListVisitorSelection(value) {
|
|
3686
|
+
if (!isRecord$5(value)) return visitorSelectionError("shape");
|
|
3687
|
+
switch (value.provider) {
|
|
3688
|
+
case "native": {
|
|
3689
|
+
const topicIds = parseVisitorIds(value.topicIds, parseNewsletterListId);
|
|
3690
|
+
return topicIds === null ? visitorSelectionError("targets") : ok({
|
|
3691
|
+
provider: "native",
|
|
3692
|
+
topicIds
|
|
3654
3693
|
});
|
|
3655
3694
|
}
|
|
3656
|
-
case "
|
|
3657
|
-
const
|
|
3658
|
-
|
|
3659
|
-
|
|
3695
|
+
case "brevo": {
|
|
3696
|
+
const listIds = parseVisitorIds(value.listIds, parseBrevoListId);
|
|
3697
|
+
return listIds === null ? visitorSelectionError("targets") : ok({
|
|
3698
|
+
provider: "brevo",
|
|
3699
|
+
listIds
|
|
3700
|
+
});
|
|
3701
|
+
}
|
|
3702
|
+
case "mailchimp": {
|
|
3703
|
+
const interestIds = parseVisitorIds(value.interestIds, parseMailchimpInterestId);
|
|
3704
|
+
return interestIds === null ? visitorSelectionError("targets") : ok({
|
|
3705
|
+
provider: "mailchimp",
|
|
3706
|
+
interestIds
|
|
3707
|
+
});
|
|
3708
|
+
}
|
|
3709
|
+
default: return visitorSelectionError("provider");
|
|
3710
|
+
}
|
|
3711
|
+
}
|
|
3712
|
+
function parseNativeTargeting(selection) {
|
|
3713
|
+
if (selection.tag === "fixed") {
|
|
3714
|
+
const topicIds = parseNonEmptyUniqueIds(selection.topicIds, parseNewsletterListId);
|
|
3715
|
+
return topicIds.ok ? ok({
|
|
3716
|
+
mode: "custom",
|
|
3717
|
+
provider: "native",
|
|
3718
|
+
selection: {
|
|
3719
|
+
tag: "fixed",
|
|
3720
|
+
topicIds: topicIds.value
|
|
3660
3721
|
}
|
|
3661
|
-
|
|
3662
|
-
|
|
3663
|
-
|
|
3722
|
+
}) : topicIds;
|
|
3723
|
+
}
|
|
3724
|
+
if (selection.tag === "visitor_choice") {
|
|
3725
|
+
const offeredTopicIds = parseNonEmptyUniqueIds(selection.offeredTopicIds, parseNewsletterListId);
|
|
3726
|
+
return offeredTopicIds.ok ? ok({
|
|
3727
|
+
mode: "custom",
|
|
3728
|
+
provider: "native",
|
|
3729
|
+
selection: {
|
|
3730
|
+
tag: "visitor_choice",
|
|
3731
|
+
offeredTopicIds: offeredTopicIds.value
|
|
3664
3732
|
}
|
|
3665
|
-
|
|
3666
|
-
|
|
3667
|
-
|
|
3733
|
+
}) : offeredTopicIds;
|
|
3734
|
+
}
|
|
3735
|
+
return targetingError("selection");
|
|
3736
|
+
}
|
|
3737
|
+
function parseBrevoTargeting(selection) {
|
|
3738
|
+
if (selection.tag === "fixed") {
|
|
3739
|
+
const listIds = parseNonEmptyUniqueIds(selection.listIds, parseBrevoListId);
|
|
3740
|
+
return listIds.ok ? ok({
|
|
3741
|
+
mode: "custom",
|
|
3742
|
+
provider: "brevo",
|
|
3743
|
+
selection: {
|
|
3744
|
+
tag: "fixed",
|
|
3745
|
+
listIds: listIds.value
|
|
3668
3746
|
}
|
|
3669
|
-
|
|
3670
|
-
|
|
3671
|
-
|
|
3672
|
-
|
|
3673
|
-
|
|
3747
|
+
}) : listIds;
|
|
3748
|
+
}
|
|
3749
|
+
if (selection.tag === "visitor_choice") {
|
|
3750
|
+
const offeredListIds = parseNonEmptyUniqueIds(selection.offeredListIds, parseBrevoListId);
|
|
3751
|
+
return offeredListIds.ok ? ok({
|
|
3752
|
+
mode: "custom",
|
|
3753
|
+
provider: "brevo",
|
|
3754
|
+
selection: {
|
|
3755
|
+
tag: "visitor_choice",
|
|
3756
|
+
offeredListIds: offeredListIds.value
|
|
3674
3757
|
}
|
|
3675
|
-
|
|
3676
|
-
|
|
3677
|
-
|
|
3678
|
-
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
|
|
3682
|
-
|
|
3683
|
-
|
|
3684
|
-
|
|
3685
|
-
|
|
3758
|
+
}) : offeredListIds;
|
|
3759
|
+
}
|
|
3760
|
+
return targetingError("selection");
|
|
3761
|
+
}
|
|
3762
|
+
function parseMailchimpTargeting(value, selection) {
|
|
3763
|
+
const audienceId = parseMailchimpAudienceId(value.audienceId);
|
|
3764
|
+
if (audienceId === null) return targetingError("audienceId");
|
|
3765
|
+
if (selection.tag === "fixed") {
|
|
3766
|
+
const interestIds = parseUniqueIds(selection.interestIds, parseMailchimpInterestId);
|
|
3767
|
+
return interestIds.ok ? ok({
|
|
3768
|
+
mode: "custom",
|
|
3769
|
+
provider: "mailchimp",
|
|
3770
|
+
audienceId,
|
|
3771
|
+
selection: {
|
|
3772
|
+
tag: "fixed",
|
|
3773
|
+
interestIds: interestIds.value
|
|
3774
|
+
}
|
|
3775
|
+
}) : interestIds;
|
|
3776
|
+
}
|
|
3777
|
+
if (selection.tag === "visitor_choice") {
|
|
3778
|
+
const offeredInterestIds = parseNonEmptyUniqueIds(selection.offeredInterestIds, parseMailchimpInterestId);
|
|
3779
|
+
return offeredInterestIds.ok ? ok({
|
|
3780
|
+
mode: "custom",
|
|
3781
|
+
provider: "mailchimp",
|
|
3782
|
+
audienceId,
|
|
3783
|
+
selection: {
|
|
3784
|
+
tag: "visitor_choice",
|
|
3785
|
+
offeredInterestIds: offeredInterestIds.value
|
|
3786
|
+
}
|
|
3787
|
+
}) : offeredInterestIds;
|
|
3686
3788
|
}
|
|
3789
|
+
return targetingError("selection");
|
|
3790
|
+
}
|
|
3791
|
+
function parseNonEmptyUniqueIds(value, parseId) {
|
|
3792
|
+
const parsed = parseUniqueIds(value, parseId);
|
|
3793
|
+
if (!parsed.ok) return parsed;
|
|
3794
|
+
const [first, ...rest] = parsed.value;
|
|
3795
|
+
return first === undefined ? targetingError("targets") : ok([first, ...rest]);
|
|
3796
|
+
}
|
|
3797
|
+
function parseUniqueIds(value, parseId) {
|
|
3798
|
+
if (!Array.isArray(value)) return targetingError("targets");
|
|
3799
|
+
const parsed = [];
|
|
3800
|
+
for (const item of value) {
|
|
3801
|
+
const id = parseId(item);
|
|
3802
|
+
if (id === null) return targetingError("targets");
|
|
3803
|
+
if (parsed.includes(id)) return targetingError("duplicate_target");
|
|
3804
|
+
parsed.push(id);
|
|
3805
|
+
}
|
|
3806
|
+
return ok(parsed);
|
|
3807
|
+
}
|
|
3808
|
+
function parseVisitorIds(value, parseId) {
|
|
3809
|
+
if (!Array.isArray(value) || value.length === 0) return null;
|
|
3810
|
+
const parsed = [];
|
|
3811
|
+
for (const item of value) {
|
|
3812
|
+
const id = parseId(item);
|
|
3813
|
+
if (id === null) return null;
|
|
3814
|
+
if (parsed.includes(id)) return null;
|
|
3815
|
+
parsed.push(id);
|
|
3816
|
+
}
|
|
3817
|
+
return parsed;
|
|
3818
|
+
}
|
|
3819
|
+
function isRecord$5(value) {
|
|
3820
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3821
|
+
}
|
|
3822
|
+
function targetingError(field) {
|
|
3823
|
+
return err({
|
|
3824
|
+
tag: "invalid_mailing_list_targeting",
|
|
3825
|
+
field
|
|
3826
|
+
});
|
|
3827
|
+
}
|
|
3828
|
+
function visitorSelectionError(field) {
|
|
3829
|
+
return err({
|
|
3830
|
+
tag: "invalid_mailing_list_visitor_selection",
|
|
3831
|
+
field
|
|
3832
|
+
});
|
|
3687
3833
|
}
|
|
3688
3834
|
|
|
3689
3835
|
//#endregion
|
|
3690
3836
|
//#region ../core/src/footer-engagement.ts
|
|
3691
|
-
function isRecord$
|
|
3837
|
+
function isRecord$4(value) {
|
|
3692
3838
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3693
3839
|
}
|
|
3694
3840
|
function invalid(path, message) {
|
|
@@ -3722,7 +3868,7 @@ function parseEngagementBase(value, base, path) {
|
|
|
3722
3868
|
}
|
|
3723
3869
|
const treatment = parseTreatment(value.treatment, `${path}.treatment`);
|
|
3724
3870
|
if (!treatment.ok) return treatment;
|
|
3725
|
-
if (!isRecord$
|
|
3871
|
+
if (!isRecord$4(value.source)) {
|
|
3726
3872
|
return err(invalid(`${path}.source`, "Footer engagement source is invalid."));
|
|
3727
3873
|
}
|
|
3728
3874
|
const intro = parseBoundedText(value.source.intro, `${path}.source.intro`, {
|
|
@@ -3751,36 +3897,17 @@ function parseStandardContact(source, base, path) {
|
|
|
3751
3897
|
}
|
|
3752
3898
|
function parseMailingList(source, base, path) {
|
|
3753
3899
|
const { intro, ...section } = base;
|
|
3754
|
-
const
|
|
3755
|
-
if (!
|
|
3756
|
-
return err(invalid(`${path}.
|
|
3757
|
-
}
|
|
3758
|
-
const buttonLabel = parseBoundedText(source.buttonLabel, `${path}.buttonLabel`, { maxLength: 40 });
|
|
3759
|
-
if (!buttonLabel.ok) return buttonLabel;
|
|
3760
|
-
const successMessage = parseBoundedText(source.successMessage, `${path}.successMessage`, { maxLength: 160 });
|
|
3761
|
-
if (!successMessage.ok) return successMessage;
|
|
3762
|
-
const privacyNote = parseBoundedText(source.privacyNote, `${path}.privacyNote`, {
|
|
3763
|
-
maxLength: 240,
|
|
3764
|
-
optional: true
|
|
3765
|
-
});
|
|
3766
|
-
if (!privacyNote.ok) return privacyNote;
|
|
3767
|
-
if (buttonLabel.value === null || successMessage.value === null) {
|
|
3768
|
-
return err(invalid(path, "Footer mailing-list copy cannot be empty."));
|
|
3769
|
-
}
|
|
3770
|
-
if (source.fieldPreset !== "emailOnly") {
|
|
3771
|
-
return err(invalid(`${path}.fieldPreset`, "Footer mailing-list signup must be email-only."));
|
|
3900
|
+
const targeting = parseMailingListPlacementTargeting(source.targeting);
|
|
3901
|
+
if (!targeting.ok) {
|
|
3902
|
+
return err(invalid(`${path}.targeting`, "Footer mailing-list targeting is invalid."));
|
|
3772
3903
|
}
|
|
3773
3904
|
return ok({
|
|
3774
3905
|
...section,
|
|
3775
3906
|
kind: "engagement",
|
|
3776
3907
|
source: {
|
|
3777
3908
|
kind: "mailing-list",
|
|
3778
|
-
|
|
3779
|
-
intro
|
|
3780
|
-
buttonLabel: buttonLabel.value,
|
|
3781
|
-
successMessage: successMessage.value,
|
|
3782
|
-
privacyNote: privacyNote.value,
|
|
3783
|
-
fieldPreset: "emailOnly"
|
|
3909
|
+
targeting: targeting.value,
|
|
3910
|
+
intro
|
|
3784
3911
|
}
|
|
3785
3912
|
});
|
|
3786
3913
|
}
|
|
@@ -3788,7 +3915,7 @@ function parseFooterEngagementSectionValue(value, sectionBase, path) {
|
|
|
3788
3915
|
const base = parseEngagementBase(value, sectionBase, path);
|
|
3789
3916
|
if (!base.ok) return base;
|
|
3790
3917
|
const source = value.source;
|
|
3791
|
-
if (!isRecord$
|
|
3918
|
+
if (!isRecord$4(source)) {
|
|
3792
3919
|
return err(invalid(`${path}.source`, "Footer engagement source is invalid."));
|
|
3793
3920
|
}
|
|
3794
3921
|
switch (source.kind) {
|
|
@@ -3903,7 +4030,7 @@ function unsafeAsFooterModuleId(value) {
|
|
|
3903
4030
|
function parseFooterModuleId(value) {
|
|
3904
4031
|
return parseSectionId(value, "sectionId");
|
|
3905
4032
|
}
|
|
3906
|
-
function isRecord$
|
|
4033
|
+
function isRecord$3(value) {
|
|
3907
4034
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3908
4035
|
}
|
|
3909
4036
|
function isRichText(value) {
|
|
@@ -3933,7 +4060,7 @@ function parseHeading(value, path) {
|
|
|
3933
4060
|
}
|
|
3934
4061
|
function parseFooterSection(value, index) {
|
|
3935
4062
|
const path = `sections.${index}`;
|
|
3936
|
-
if (!isRecord$
|
|
4063
|
+
if (!isRecord$3(value)) {
|
|
3937
4064
|
return err({
|
|
3938
4065
|
code: "invalid_section",
|
|
3939
4066
|
path,
|
|
@@ -3968,7 +4095,7 @@ function parseFooterSection(value, index) {
|
|
|
3968
4095
|
}
|
|
3969
4096
|
break;
|
|
3970
4097
|
case "navigation":
|
|
3971
|
-
if (isRecord$
|
|
4098
|
+
if (isRecord$3(value.source) && value.source.kind === "menu-role" && value.source.role === "main") {
|
|
3972
4099
|
return ok({
|
|
3973
4100
|
...base,
|
|
3974
4101
|
kind: "navigation",
|
|
@@ -3981,7 +4108,7 @@ function parseFooterSection(value, index) {
|
|
|
3981
4108
|
}
|
|
3982
4109
|
break;
|
|
3983
4110
|
case "legal-navigation":
|
|
3984
|
-
if (isRecord$
|
|
4111
|
+
if (isRecord$3(value.source) && value.source.kind === "menu-role" && value.source.role === "legal-policy") {
|
|
3985
4112
|
return ok({
|
|
3986
4113
|
...base,
|
|
3987
4114
|
kind: "legal-navigation",
|
|
@@ -3994,7 +4121,7 @@ function parseFooterSection(value, index) {
|
|
|
3994
4121
|
}
|
|
3995
4122
|
break;
|
|
3996
4123
|
case "business-address":
|
|
3997
|
-
if (isRecord$
|
|
4124
|
+
if (isRecord$3(value.source) && value.source.kind === "business-address") {
|
|
3998
4125
|
return ok({
|
|
3999
4126
|
...base,
|
|
4000
4127
|
kind: "business-address",
|
|
@@ -4006,7 +4133,7 @@ function parseFooterSection(value, index) {
|
|
|
4006
4133
|
case "contact":
|
|
4007
4134
|
case "opening-hours":
|
|
4008
4135
|
case "social-links":
|
|
4009
|
-
if (isRecord$
|
|
4136
|
+
if (isRecord$3(value.source) && value.source.kind === "public-profile") {
|
|
4010
4137
|
return ok({
|
|
4011
4138
|
...base,
|
|
4012
4139
|
kind: value.kind,
|
|
@@ -4058,7 +4185,7 @@ function validateFooterComposition(composition) {
|
|
|
4058
4185
|
return ok(composition);
|
|
4059
4186
|
}
|
|
4060
4187
|
function parseFooterCompositionV1(value) {
|
|
4061
|
-
if (!isRecord$
|
|
4188
|
+
if (!isRecord$3(value)) {
|
|
4062
4189
|
return err({
|
|
4063
4190
|
code: "invalid_shape",
|
|
4064
4191
|
path: "",
|
|
@@ -4091,7 +4218,7 @@ function parseFooterCompositionV1(value) {
|
|
|
4091
4218
|
});
|
|
4092
4219
|
}
|
|
4093
4220
|
function parseLegacyPlacementSection(value, index, selectedIds) {
|
|
4094
|
-
if (!isRecord$
|
|
4221
|
+
if (!isRecord$3(value)) {
|
|
4095
4222
|
return err({
|
|
4096
4223
|
code: "invalid_section",
|
|
4097
4224
|
path: `modules.${index}`,
|
|
@@ -4099,7 +4226,7 @@ function parseLegacyPlacementSection(value, index, selectedIds) {
|
|
|
4099
4226
|
});
|
|
4100
4227
|
}
|
|
4101
4228
|
const selected = typeof value.id === "string" && selectedIds.has(value.id);
|
|
4102
|
-
const source = isRecord$
|
|
4229
|
+
const source = isRecord$3(value.source) ? value.source : null;
|
|
4103
4230
|
const mapped = value.kind === "navigation" && source?.kind === "menu-role" && source.role === "footer" ? {
|
|
4104
4231
|
...value,
|
|
4105
4232
|
source: {
|
|
@@ -4118,7 +4245,7 @@ function parseLegacyPlacementSection(value, index, selectedIds) {
|
|
|
4118
4245
|
* It is intentionally not called by the runtime parser.
|
|
4119
4246
|
*/
|
|
4120
4247
|
function upgradePlacementFooterCompositionV1(value) {
|
|
4121
|
-
if (!isRecord$
|
|
4248
|
+
if (!isRecord$3(value) || value.schemaVersion !== 1 || !Array.isArray(value.modules) || !Array.isArray(value.placements)) {
|
|
4122
4249
|
return err({
|
|
4123
4250
|
code: "invalid_shape",
|
|
4124
4251
|
path: "",
|
|
@@ -4127,7 +4254,7 @@ function upgradePlacementFooterCompositionV1(value) {
|
|
|
4127
4254
|
}
|
|
4128
4255
|
const selectedIds = new Set();
|
|
4129
4256
|
for (const [index, placement] of value.placements.entries()) {
|
|
4130
|
-
if (!isRecord$
|
|
4257
|
+
if (!isRecord$3(placement) || typeof placement.moduleId !== "string") {
|
|
4131
4258
|
return err({
|
|
4132
4259
|
code: "invalid_shape",
|
|
4133
4260
|
path: `placements.${index}`,
|
|
@@ -4230,8 +4357,8 @@ function repairTargetFor(section) {
|
|
|
4230
4357
|
};
|
|
4231
4358
|
}
|
|
4232
4359
|
}
|
|
4233
|
-
function resolveFooterSections(composition, availability) {
|
|
4234
|
-
return composition.sections.filter((section) => section.selected).map((section) => isSectionRenderable(section, availability) ? {
|
|
4360
|
+
function resolveFooterSections(composition, availability$1) {
|
|
4361
|
+
return composition.sections.filter((section) => section.selected).map((section) => isSectionRenderable(section, availability$1) ? {
|
|
4235
4362
|
kind: "renderable",
|
|
4236
4363
|
section
|
|
4237
4364
|
} : {
|
|
@@ -4240,16 +4367,16 @@ function resolveFooterSections(composition, availability) {
|
|
|
4240
4367
|
repairTarget: repairTargetFor(section)
|
|
4241
4368
|
});
|
|
4242
4369
|
}
|
|
4243
|
-
function isSectionRenderable(section, availability) {
|
|
4370
|
+
function isSectionRenderable(section, availability$1) {
|
|
4244
4371
|
switch (section.kind) {
|
|
4245
|
-
case "brand": return section.showLogo && availability.hasLogo || section.showTitle;
|
|
4246
|
-
case "navigation": return availability.hasMainNavigation;
|
|
4247
|
-
case "legal-navigation": return availability.hasLegalPolicyNavigation;
|
|
4248
|
-
case "business-address": return availability.hasBusinessAddress;
|
|
4249
|
-
case "contact": return availability.hasContact;
|
|
4250
|
-
case "opening-hours": return availability.hasOpeningHours;
|
|
4251
|
-
case "social-links": return availability.hasSocialLinks;
|
|
4252
|
-
case "engagement": return availability.hasEngagementSource;
|
|
4372
|
+
case "brand": return section.showLogo && availability$1.hasLogo || section.showTitle;
|
|
4373
|
+
case "navigation": return availability$1.hasMainNavigation;
|
|
4374
|
+
case "legal-navigation": return availability$1.hasLegalPolicyNavigation;
|
|
4375
|
+
case "business-address": return availability$1.hasBusinessAddress;
|
|
4376
|
+
case "contact": return availability$1.hasContact;
|
|
4377
|
+
case "opening-hours": return availability$1.hasOpeningHours;
|
|
4378
|
+
case "social-links": return availability$1.hasSocialLinks;
|
|
4379
|
+
case "engagement": return availability$1.hasEngagementSource;
|
|
4253
4380
|
case "supporting-text":
|
|
4254
4381
|
case "legal": return section.content !== null;
|
|
4255
4382
|
}
|
|
@@ -4342,7 +4469,7 @@ const defaultSections = (legacy, options) => {
|
|
|
4342
4469
|
];
|
|
4343
4470
|
};
|
|
4344
4471
|
function normalizeLegacyFooterContentToV1(value, options = {}) {
|
|
4345
|
-
if (!isRecord$
|
|
4472
|
+
if (!isRecord$3(value)) {
|
|
4346
4473
|
return err({
|
|
4347
4474
|
code: "invalid_shape",
|
|
4348
4475
|
path: "",
|
|
@@ -4363,6 +4490,716 @@ function normalizeFooterNavigationLayout(value) {
|
|
|
4363
4490
|
return value === "stack" ? "stack" : defaultFooterNavigationLayout;
|
|
4364
4491
|
}
|
|
4365
4492
|
|
|
4493
|
+
//#endregion
|
|
4494
|
+
//#region ../core/src/mailing-list-setup.ts
|
|
4495
|
+
function planMailingListFieldCompatibility(input) {
|
|
4496
|
+
const collectedFields = resolveCollectedGlobalFields(input.form);
|
|
4497
|
+
const requiredFields = resolveRequiredGlobalFields(input.form.fields);
|
|
4498
|
+
const issues = [];
|
|
4499
|
+
for (const destination of input.destinations) {
|
|
4500
|
+
for (const field of destination.requiredFields) {
|
|
4501
|
+
if (!collectedFields.includes(field)) {
|
|
4502
|
+
issues.push({
|
|
4503
|
+
tag: "destination_requires_uncollected_field",
|
|
4504
|
+
destinationKey: destination.destinationKey,
|
|
4505
|
+
field
|
|
4506
|
+
});
|
|
4507
|
+
} else if (!requiredFields.includes(field)) {
|
|
4508
|
+
issues.push({
|
|
4509
|
+
tag: "destination_requires_site_required_field",
|
|
4510
|
+
destinationKey: destination.destinationKey,
|
|
4511
|
+
field
|
|
4512
|
+
});
|
|
4513
|
+
}
|
|
4514
|
+
}
|
|
4515
|
+
for (const field of collectedFields) {
|
|
4516
|
+
if (!destination.acceptedFields.includes(field)) {
|
|
4517
|
+
issues.push({
|
|
4518
|
+
tag: requiredFields.includes(field) ? "destination_rejects_required_site_field" : "destination_rejects_collected_site_field",
|
|
4519
|
+
destinationKey: destination.destinationKey,
|
|
4520
|
+
field
|
|
4521
|
+
});
|
|
4522
|
+
}
|
|
4523
|
+
}
|
|
4524
|
+
}
|
|
4525
|
+
const [first, ...rest] = issues;
|
|
4526
|
+
return first === undefined ? { tag: "compatible" } : {
|
|
4527
|
+
tag: "blocked",
|
|
4528
|
+
issues: [first, ...rest]
|
|
4529
|
+
};
|
|
4530
|
+
}
|
|
4531
|
+
function resolveCollectedGlobalFields(form) {
|
|
4532
|
+
const phone = form.includeOptionalPhone ? ["phone"] : [];
|
|
4533
|
+
switch (form.fields.preset) {
|
|
4534
|
+
case "emailOnly": return phone;
|
|
4535
|
+
case "emailName": return ["name", ...phone];
|
|
4536
|
+
case "emailFirstLast": return [
|
|
4537
|
+
"first_name",
|
|
4538
|
+
"last_name",
|
|
4539
|
+
...phone
|
|
4540
|
+
];
|
|
4541
|
+
case "emailNameCompany": return [
|
|
4542
|
+
"name",
|
|
4543
|
+
"company",
|
|
4544
|
+
...phone
|
|
4545
|
+
];
|
|
4546
|
+
}
|
|
4547
|
+
}
|
|
4548
|
+
function resolveRequiredGlobalFields(fields) {
|
|
4549
|
+
switch (fields.preset) {
|
|
4550
|
+
case "emailOnly": return [];
|
|
4551
|
+
case "emailName": return fields.name === "required" ? ["name"] : [];
|
|
4552
|
+
case "emailFirstLast": return [...fields.firstName === "required" ? ["first_name"] : [], ...fields.lastName === "required" ? ["last_name"] : []];
|
|
4553
|
+
case "emailNameCompany": return [...fields.name === "required" ? ["name"] : [], ...fields.company === "required" ? ["company"] : []];
|
|
4554
|
+
}
|
|
4555
|
+
}
|
|
4556
|
+
function planMailingListSetupSwitch(input) {
|
|
4557
|
+
if (input.previousScope === null) {
|
|
4558
|
+
return {
|
|
4559
|
+
tag: "activate",
|
|
4560
|
+
affectedPlacementCount: 0
|
|
4561
|
+
};
|
|
4562
|
+
}
|
|
4563
|
+
if (sameProviderScope(input.previousScope, input.nextScope)) {
|
|
4564
|
+
return {
|
|
4565
|
+
tag: "update_same_scope",
|
|
4566
|
+
affectedPlacementCount: input.defaultChanged ? countDefaultMailingListPlacements(input.placementModes) : 0
|
|
4567
|
+
};
|
|
4568
|
+
}
|
|
4569
|
+
return {
|
|
4570
|
+
tag: "replace_scope",
|
|
4571
|
+
affectedPlacementCount: input.placementModes.length
|
|
4572
|
+
};
|
|
4573
|
+
}
|
|
4574
|
+
function sameProviderScope(previous, next) {
|
|
4575
|
+
if (previous.provider !== next.provider) return false;
|
|
4576
|
+
switch (previous.provider) {
|
|
4577
|
+
case "native": return true;
|
|
4578
|
+
case "mailchimp": return next.provider === "mailchimp" && previous.accountId === next.accountId;
|
|
4579
|
+
case "brevo": return next.provider === "brevo" && previous.accountId === next.accountId;
|
|
4580
|
+
}
|
|
4581
|
+
}
|
|
4582
|
+
function countDefaultMailingListPlacements(placementModes) {
|
|
4583
|
+
return placementModes.filter((mode) => mode === "default").length;
|
|
4584
|
+
}
|
|
4585
|
+
|
|
4586
|
+
//#endregion
|
|
4587
|
+
//#region ../core/src/mailing-list-setup-parser.ts
|
|
4588
|
+
function parseMailingListGlobalForm(value) {
|
|
4589
|
+
if (!isRecord$2(value)) return formError("shape");
|
|
4590
|
+
const fields = parseGlobalFields(value.fields);
|
|
4591
|
+
if (fields === null) return formError("fields");
|
|
4592
|
+
if (typeof value.includeOptionalPhone !== "boolean") {
|
|
4593
|
+
return formError("includeOptionalPhone");
|
|
4594
|
+
}
|
|
4595
|
+
const buttonLabel = parseRequiredString(value.buttonLabel);
|
|
4596
|
+
if (buttonLabel === null) return formError("buttonLabel");
|
|
4597
|
+
const privacyNote = parseOptionalString(value.privacyNote);
|
|
4598
|
+
if (privacyNote === undefined) return formError("privacyNote");
|
|
4599
|
+
return ok({
|
|
4600
|
+
fields,
|
|
4601
|
+
includeOptionalPhone: value.includeOptionalPhone,
|
|
4602
|
+
buttonLabel,
|
|
4603
|
+
privacyNote
|
|
4604
|
+
});
|
|
4605
|
+
}
|
|
4606
|
+
function parseMailingListSiteSetup(value) {
|
|
4607
|
+
if (!isRecord$2(value)) return setupError("shape");
|
|
4608
|
+
const siteId = parseSiteId(value.siteId);
|
|
4609
|
+
if (!siteId.ok) return setupError("siteId");
|
|
4610
|
+
if (value.tag === "not_configured") {
|
|
4611
|
+
return ok({
|
|
4612
|
+
tag: "not_configured",
|
|
4613
|
+
siteId: siteId.value
|
|
4614
|
+
});
|
|
4615
|
+
}
|
|
4616
|
+
if (value.tag !== "configured") return setupError("tag");
|
|
4617
|
+
const revision = parseMailingListSetupRevision(value.revision);
|
|
4618
|
+
if (revision === null) return setupError("revision");
|
|
4619
|
+
const form = parseMailingListGlobalForm(value.form);
|
|
4620
|
+
if (!form.ok) return setupError("form");
|
|
4621
|
+
const provider = parseConfiguredMailingListProvider(value.provider);
|
|
4622
|
+
if (!provider.ok) return provider;
|
|
4623
|
+
return ok({
|
|
4624
|
+
tag: "configured",
|
|
4625
|
+
siteId: siteId.value,
|
|
4626
|
+
revision,
|
|
4627
|
+
form: form.value,
|
|
4628
|
+
provider: provider.value
|
|
4629
|
+
});
|
|
4630
|
+
}
|
|
4631
|
+
function parseConfiguredMailingListProvider(value) {
|
|
4632
|
+
if (!isRecord$2(value) || typeof value.provider !== "string") {
|
|
4633
|
+
return setupError("provider");
|
|
4634
|
+
}
|
|
4635
|
+
switch (value.provider) {
|
|
4636
|
+
case "native": {
|
|
4637
|
+
const defaultTopicId = parseNewsletterListId(value.defaultTopicId);
|
|
4638
|
+
if (defaultTopicId === null) return setupError("defaultTargetId");
|
|
4639
|
+
const confirmation = parseToggleConfirmation(value.confirmation);
|
|
4640
|
+
return confirmation === null ? setupError("confirmation") : ok({
|
|
4641
|
+
provider: "native",
|
|
4642
|
+
defaultTopicId,
|
|
4643
|
+
confirmation
|
|
4644
|
+
});
|
|
4645
|
+
}
|
|
4646
|
+
case "mailchimp": {
|
|
4647
|
+
const connectionId = parseMailchimpConnectionId(value.connectionId);
|
|
4648
|
+
if (connectionId === null) return setupError("connectionId");
|
|
4649
|
+
const accountId = parseMailchimpAccountId(value.accountId);
|
|
4650
|
+
if (accountId === null) return setupError("accountId");
|
|
4651
|
+
const defaultAudienceId = parseMailchimpAudienceId(value.defaultAudienceId);
|
|
4652
|
+
if (defaultAudienceId === null) return setupError("defaultTargetId");
|
|
4653
|
+
const confirmation = parseToggleConfirmation(value.confirmation);
|
|
4654
|
+
return confirmation === null ? setupError("confirmation") : ok({
|
|
4655
|
+
provider: "mailchimp",
|
|
4656
|
+
connectionId,
|
|
4657
|
+
accountId,
|
|
4658
|
+
defaultAudienceId,
|
|
4659
|
+
confirmation
|
|
4660
|
+
});
|
|
4661
|
+
}
|
|
4662
|
+
case "brevo": {
|
|
4663
|
+
const connectionId = parseBrevoConnectionId(value.connectionId);
|
|
4664
|
+
if (connectionId === null) return setupError("connectionId");
|
|
4665
|
+
const accountId = parseBrevoAccountId(value.accountId);
|
|
4666
|
+
if (accountId === null) return setupError("accountId");
|
|
4667
|
+
const defaultListId = parseBrevoListId(value.defaultListId);
|
|
4668
|
+
if (defaultListId === null) return setupError("defaultTargetId");
|
|
4669
|
+
const confirmation = parseBrevoConfirmation(value.confirmation);
|
|
4670
|
+
return confirmation === null ? setupError("confirmation") : ok({
|
|
4671
|
+
provider: "brevo",
|
|
4672
|
+
connectionId,
|
|
4673
|
+
accountId,
|
|
4674
|
+
defaultListId,
|
|
4675
|
+
confirmation
|
|
4676
|
+
});
|
|
4677
|
+
}
|
|
4678
|
+
default: return setupError("provider");
|
|
4679
|
+
}
|
|
4680
|
+
}
|
|
4681
|
+
function parseGlobalFields(value) {
|
|
4682
|
+
if (!isRecord$2(value) || typeof value.preset !== "string") return null;
|
|
4683
|
+
switch (value.preset) {
|
|
4684
|
+
case "emailOnly": return { preset: "emailOnly" };
|
|
4685
|
+
case "emailName": return isRequirement(value.name) ? {
|
|
4686
|
+
preset: "emailName",
|
|
4687
|
+
name: value.name
|
|
4688
|
+
} : null;
|
|
4689
|
+
case "emailFirstLast": return isRequirement(value.firstName) && isRequirement(value.lastName) ? {
|
|
4690
|
+
preset: "emailFirstLast",
|
|
4691
|
+
firstName: value.firstName,
|
|
4692
|
+
lastName: value.lastName
|
|
4693
|
+
} : null;
|
|
4694
|
+
case "emailNameCompany": return isRequirement(value.name) && isRequirement(value.company) ? {
|
|
4695
|
+
preset: "emailNameCompany",
|
|
4696
|
+
name: value.name,
|
|
4697
|
+
company: value.company
|
|
4698
|
+
} : null;
|
|
4699
|
+
default: return null;
|
|
4700
|
+
}
|
|
4701
|
+
}
|
|
4702
|
+
function parseToggleConfirmation(value) {
|
|
4703
|
+
if (!isRecord$2(value)) return null;
|
|
4704
|
+
return value.tag === "on" || value.tag === "off" ? { tag: value.tag } : null;
|
|
4705
|
+
}
|
|
4706
|
+
function parseBrevoConfirmation(value) {
|
|
4707
|
+
if (!isRecord$2(value)) return null;
|
|
4708
|
+
if (value.tag === "off") return { tag: "off" };
|
|
4709
|
+
if (value.tag !== "on") return null;
|
|
4710
|
+
const templateId = parseBrevoConfirmationTemplateId(value.templateId);
|
|
4711
|
+
const redirectUrl = parseHttpUrl(value.redirectUrl);
|
|
4712
|
+
return templateId === null || redirectUrl === null ? null : {
|
|
4713
|
+
tag: "on",
|
|
4714
|
+
templateId,
|
|
4715
|
+
redirectUrl
|
|
4716
|
+
};
|
|
4717
|
+
}
|
|
4718
|
+
function parseMailingListSetupRevision(value) {
|
|
4719
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value > 0 ? value : null;
|
|
4720
|
+
}
|
|
4721
|
+
function parseHttpUrl(value) {
|
|
4722
|
+
if (typeof value !== "string") return null;
|
|
4723
|
+
try {
|
|
4724
|
+
const url = new URL(value);
|
|
4725
|
+
return url.protocol === "http:" || url.protocol === "https:" ? url.toString() : null;
|
|
4726
|
+
} catch {
|
|
4727
|
+
return null;
|
|
4728
|
+
}
|
|
4729
|
+
}
|
|
4730
|
+
function parseRequiredString(value) {
|
|
4731
|
+
if (typeof value !== "string") return null;
|
|
4732
|
+
const trimmed = value.trim();
|
|
4733
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
4734
|
+
}
|
|
4735
|
+
function parseOptionalString(value) {
|
|
4736
|
+
if (value === null || value === undefined) return null;
|
|
4737
|
+
if (typeof value !== "string") return undefined;
|
|
4738
|
+
const trimmed = value.trim();
|
|
4739
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
4740
|
+
}
|
|
4741
|
+
function isRequirement(value) {
|
|
4742
|
+
return value === "required" || value === "optional";
|
|
4743
|
+
}
|
|
4744
|
+
function isRecord$2(value) {
|
|
4745
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
4746
|
+
}
|
|
4747
|
+
function formError(field) {
|
|
4748
|
+
return err({
|
|
4749
|
+
tag: "invalid_mailing_list_global_form",
|
|
4750
|
+
field
|
|
4751
|
+
});
|
|
4752
|
+
}
|
|
4753
|
+
function setupError(field) {
|
|
4754
|
+
return err({
|
|
4755
|
+
tag: "invalid_mailing_list_setup",
|
|
4756
|
+
field
|
|
4757
|
+
});
|
|
4758
|
+
}
|
|
4759
|
+
|
|
4760
|
+
//#endregion
|
|
4761
|
+
//#region ../core/src/mailing-list-targeting.ts
|
|
4762
|
+
function sameMailingListPlacementTargeting(left, right) {
|
|
4763
|
+
if (left.mode !== right.mode) return false;
|
|
4764
|
+
if (left.mode === "default" || right.mode === "default") return true;
|
|
4765
|
+
if (left.provider !== right.provider || left.selection.tag !== right.selection.tag) return false;
|
|
4766
|
+
if (left.provider === "mailchimp" && (right.provider !== "mailchimp" || left.audienceId !== right.audienceId)) return false;
|
|
4767
|
+
return sameIds(targetingSelectionIds(left), targetingSelectionIds(right));
|
|
4768
|
+
}
|
|
4769
|
+
function targetingSelectionIds(targeting) {
|
|
4770
|
+
switch (targeting.provider) {
|
|
4771
|
+
case "native": return targeting.selection.tag === "fixed" ? targeting.selection.topicIds : targeting.selection.offeredTopicIds;
|
|
4772
|
+
case "brevo": return targeting.selection.tag === "fixed" ? targeting.selection.listIds : targeting.selection.offeredListIds;
|
|
4773
|
+
case "mailchimp": return targeting.selection.tag === "fixed" ? targeting.selection.interestIds : targeting.selection.offeredInterestIds;
|
|
4774
|
+
}
|
|
4775
|
+
}
|
|
4776
|
+
function sameIds(left, right) {
|
|
4777
|
+
const leftIds = new Set(left);
|
|
4778
|
+
const rightIds = new Set(right);
|
|
4779
|
+
return leftIds.size === left.length && rightIds.size === right.length && leftIds.size === rightIds.size && [...leftIds].every((id) => rightIds.has(id));
|
|
4780
|
+
}
|
|
4781
|
+
function resolveMailingListTarget(input) {
|
|
4782
|
+
if (input.targeting.mode === "default") {
|
|
4783
|
+
if (input.visitorSelection !== undefined) {
|
|
4784
|
+
return err({ tag: "visitor_selection_not_allowed" });
|
|
4785
|
+
}
|
|
4786
|
+
return ok(resolveDefaultTarget(input.setup));
|
|
4787
|
+
}
|
|
4788
|
+
if (input.targeting.provider !== input.setup.provider) {
|
|
4789
|
+
return err({
|
|
4790
|
+
tag: "targeting_provider_mismatch",
|
|
4791
|
+
setupProvider: input.setup.provider,
|
|
4792
|
+
targetingProvider: input.targeting.provider
|
|
4793
|
+
});
|
|
4794
|
+
}
|
|
4795
|
+
return resolveCustomTarget(input.targeting, input.visitorSelection);
|
|
4796
|
+
}
|
|
4797
|
+
function resolveDefaultTarget(setup) {
|
|
4798
|
+
switch (setup.provider) {
|
|
4799
|
+
case "native": return {
|
|
4800
|
+
provider: "native",
|
|
4801
|
+
topicIds: [setup.defaultTopicId]
|
|
4802
|
+
};
|
|
4803
|
+
case "brevo": return {
|
|
4804
|
+
provider: "brevo",
|
|
4805
|
+
listIds: [setup.defaultListId]
|
|
4806
|
+
};
|
|
4807
|
+
case "mailchimp": return {
|
|
4808
|
+
provider: "mailchimp",
|
|
4809
|
+
audienceId: setup.defaultAudienceId,
|
|
4810
|
+
interestIds: []
|
|
4811
|
+
};
|
|
4812
|
+
}
|
|
4813
|
+
}
|
|
4814
|
+
function resolveCustomTarget(targeting, visitorSelection) {
|
|
4815
|
+
switch (targeting.provider) {
|
|
4816
|
+
case "native": return resolveNativeTarget(targeting, visitorSelection);
|
|
4817
|
+
case "brevo": return resolveBrevoTarget(targeting, visitorSelection);
|
|
4818
|
+
case "mailchimp": return resolveMailchimpTarget(targeting, visitorSelection);
|
|
4819
|
+
}
|
|
4820
|
+
}
|
|
4821
|
+
function resolveNativeTarget(targeting, selection) {
|
|
4822
|
+
if (targeting.selection.tag === "fixed") {
|
|
4823
|
+
return selection === undefined ? ok({
|
|
4824
|
+
provider: "native",
|
|
4825
|
+
topicIds: targeting.selection.topicIds
|
|
4826
|
+
}) : err({ tag: "visitor_selection_not_allowed" });
|
|
4827
|
+
}
|
|
4828
|
+
if (selection === undefined) {
|
|
4829
|
+
return targeting.selection.offeredTopicIds.length === 1 ? ok({
|
|
4830
|
+
provider: "native",
|
|
4831
|
+
topicIds: targeting.selection.offeredTopicIds
|
|
4832
|
+
}) : err({ tag: "visitor_selection_required" });
|
|
4833
|
+
}
|
|
4834
|
+
if (selection.provider !== "native") {
|
|
4835
|
+
return err({ tag: "visitor_selection_provider_mismatch" });
|
|
4836
|
+
}
|
|
4837
|
+
const selected = selectedNonEmptySubset(selection.topicIds, targeting.selection.offeredTopicIds);
|
|
4838
|
+
return selected.ok ? ok({
|
|
4839
|
+
provider: "native",
|
|
4840
|
+
topicIds: selected.value
|
|
4841
|
+
}) : err({ tag: "visitor_selection_outside_offer" });
|
|
4842
|
+
}
|
|
4843
|
+
function resolveBrevoTarget(targeting, selection) {
|
|
4844
|
+
if (targeting.selection.tag === "fixed") {
|
|
4845
|
+
return selection === undefined ? ok({
|
|
4846
|
+
provider: "brevo",
|
|
4847
|
+
listIds: targeting.selection.listIds
|
|
4848
|
+
}) : err({ tag: "visitor_selection_not_allowed" });
|
|
4849
|
+
}
|
|
4850
|
+
if (selection === undefined) {
|
|
4851
|
+
return targeting.selection.offeredListIds.length === 1 ? ok({
|
|
4852
|
+
provider: "brevo",
|
|
4853
|
+
listIds: targeting.selection.offeredListIds
|
|
4854
|
+
}) : err({ tag: "visitor_selection_required" });
|
|
4855
|
+
}
|
|
4856
|
+
if (selection.provider !== "brevo") {
|
|
4857
|
+
return err({ tag: "visitor_selection_provider_mismatch" });
|
|
4858
|
+
}
|
|
4859
|
+
const selected = selectedNonEmptySubset(selection.listIds, targeting.selection.offeredListIds);
|
|
4860
|
+
return selected.ok ? ok({
|
|
4861
|
+
provider: "brevo",
|
|
4862
|
+
listIds: selected.value
|
|
4863
|
+
}) : err({ tag: "visitor_selection_outside_offer" });
|
|
4864
|
+
}
|
|
4865
|
+
function resolveMailchimpTarget(targeting, selection) {
|
|
4866
|
+
if (targeting.selection.tag === "fixed") {
|
|
4867
|
+
return selection === undefined ? ok({
|
|
4868
|
+
provider: "mailchimp",
|
|
4869
|
+
audienceId: targeting.audienceId,
|
|
4870
|
+
interestIds: targeting.selection.interestIds
|
|
4871
|
+
}) : err({ tag: "visitor_selection_not_allowed" });
|
|
4872
|
+
}
|
|
4873
|
+
if (selection === undefined) {
|
|
4874
|
+
return targeting.selection.offeredInterestIds.length === 1 ? ok({
|
|
4875
|
+
provider: "mailchimp",
|
|
4876
|
+
audienceId: targeting.audienceId,
|
|
4877
|
+
interestIds: targeting.selection.offeredInterestIds
|
|
4878
|
+
}) : err({ tag: "visitor_selection_required" });
|
|
4879
|
+
}
|
|
4880
|
+
if (selection.provider !== "mailchimp") {
|
|
4881
|
+
return err({ tag: "visitor_selection_provider_mismatch" });
|
|
4882
|
+
}
|
|
4883
|
+
const subset = selectedNonEmptySubset(selection.interestIds, targeting.selection.offeredInterestIds);
|
|
4884
|
+
return subset.ok ? ok({
|
|
4885
|
+
provider: "mailchimp",
|
|
4886
|
+
audienceId: targeting.audienceId,
|
|
4887
|
+
interestIds: subset.value
|
|
4888
|
+
}) : err({ tag: "visitor_selection_outside_offer" });
|
|
4889
|
+
}
|
|
4890
|
+
function selectedNonEmptySubset(selected, offered) {
|
|
4891
|
+
const normalized = [...new Set(selected)];
|
|
4892
|
+
const [first, ...rest] = normalized;
|
|
4893
|
+
if (first === undefined || normalized.some((item) => !offered.includes(item))) {
|
|
4894
|
+
return err("invalid_selection");
|
|
4895
|
+
}
|
|
4896
|
+
return ok([first, ...rest]);
|
|
4897
|
+
}
|
|
4898
|
+
function planMailingListChoicePresentation(targeting) {
|
|
4899
|
+
if (targeting.mode === "default" || targeting.selection.tag === "fixed") {
|
|
4900
|
+
return { tag: "hidden" };
|
|
4901
|
+
}
|
|
4902
|
+
switch (targeting.provider) {
|
|
4903
|
+
case "native": return targeting.selection.offeredTopicIds.length === 1 ? {
|
|
4904
|
+
tag: "automatic",
|
|
4905
|
+
selection: {
|
|
4906
|
+
provider: "native",
|
|
4907
|
+
topicIds: targeting.selection.offeredTopicIds
|
|
4908
|
+
}
|
|
4909
|
+
} : {
|
|
4910
|
+
tag: "visitor_choice",
|
|
4911
|
+
provider: "native",
|
|
4912
|
+
optionCount: targeting.selection.offeredTopicIds.length
|
|
4913
|
+
};
|
|
4914
|
+
case "brevo": return targeting.selection.offeredListIds.length === 1 ? {
|
|
4915
|
+
tag: "automatic",
|
|
4916
|
+
selection: {
|
|
4917
|
+
provider: "brevo",
|
|
4918
|
+
listIds: targeting.selection.offeredListIds
|
|
4919
|
+
}
|
|
4920
|
+
} : {
|
|
4921
|
+
tag: "visitor_choice",
|
|
4922
|
+
provider: "brevo",
|
|
4923
|
+
optionCount: targeting.selection.offeredListIds.length
|
|
4924
|
+
};
|
|
4925
|
+
case "mailchimp": return targeting.selection.offeredInterestIds.length === 1 ? {
|
|
4926
|
+
tag: "automatic",
|
|
4927
|
+
selection: {
|
|
4928
|
+
provider: "mailchimp",
|
|
4929
|
+
interestIds: targeting.selection.offeredInterestIds
|
|
4930
|
+
}
|
|
4931
|
+
} : {
|
|
4932
|
+
tag: "visitor_choice",
|
|
4933
|
+
provider: "mailchimp",
|
|
4934
|
+
optionCount: targeting.selection.offeredInterestIds.length
|
|
4935
|
+
};
|
|
4936
|
+
}
|
|
4937
|
+
}
|
|
4938
|
+
|
|
4939
|
+
//#endregion
|
|
4940
|
+
//#region ../core/src/mailing-list-runtime.ts
|
|
4941
|
+
function parseMailingListRuntimeContext(value) {
|
|
4942
|
+
if (!isRecord$1(value)) return invalidRuntimeContext();
|
|
4943
|
+
if (value.tag === "not_configured") return ok({ tag: "not_configured" });
|
|
4944
|
+
if (value.tag !== "configured") return invalidRuntimeContext();
|
|
4945
|
+
const revision = parseMailingListSetupRevision(value.revision);
|
|
4946
|
+
const form = parseMailingListGlobalForm(value.form);
|
|
4947
|
+
const provider = parseRuntimeProvider(value.provider);
|
|
4948
|
+
if (revision === null || !form.ok || provider === null) {
|
|
4949
|
+
return invalidRuntimeContext();
|
|
4950
|
+
}
|
|
4951
|
+
return ok({
|
|
4952
|
+
tag: "configured",
|
|
4953
|
+
revision,
|
|
4954
|
+
form: form.value,
|
|
4955
|
+
provider
|
|
4956
|
+
});
|
|
4957
|
+
}
|
|
4958
|
+
function parseRuntimeProvider(value) {
|
|
4959
|
+
if (!isRecord$1(value)) return null;
|
|
4960
|
+
switch (value.provider) {
|
|
4961
|
+
case "native": return parseNativeRuntimeProvider(value);
|
|
4962
|
+
case "brevo": return parseBrevoRuntimeProvider(value);
|
|
4963
|
+
case "mailchimp": return parseMailchimpRuntimeProvider(value);
|
|
4964
|
+
default: return null;
|
|
4965
|
+
}
|
|
4966
|
+
}
|
|
4967
|
+
function parseNativeRuntimeProvider(value) {
|
|
4968
|
+
const defaultTopicId = parseNewsletterListId(value.defaultTopicId);
|
|
4969
|
+
const topics = parseNamedItems(value.topics, parseNewsletterListId);
|
|
4970
|
+
return defaultTopicId !== null && topics !== null ? {
|
|
4971
|
+
provider: "native",
|
|
4972
|
+
defaultTopicId,
|
|
4973
|
+
topics
|
|
4974
|
+
} : null;
|
|
4975
|
+
}
|
|
4976
|
+
function parseBrevoRuntimeProvider(value) {
|
|
4977
|
+
const defaultListId = parseBrevoListId(value.defaultListId);
|
|
4978
|
+
const lists = parseNamedItems(value.lists, parseBrevoListId);
|
|
4979
|
+
return defaultListId !== null && lists !== null ? {
|
|
4980
|
+
provider: "brevo",
|
|
4981
|
+
defaultListId,
|
|
4982
|
+
lists
|
|
4983
|
+
} : null;
|
|
4984
|
+
}
|
|
4985
|
+
function parseMailchimpRuntimeProvider(value) {
|
|
4986
|
+
if (!Array.isArray(value.audiences)) return null;
|
|
4987
|
+
const defaultAudienceId = parseMailchimpAudienceId(value.defaultAudienceId);
|
|
4988
|
+
if (defaultAudienceId === null) return null;
|
|
4989
|
+
const audiences = [];
|
|
4990
|
+
for (const audience of value.audiences) {
|
|
4991
|
+
if (!isRecord$1(audience)) return null;
|
|
4992
|
+
const id = parseMailchimpAudienceId(audience.id);
|
|
4993
|
+
const name = parseName(audience.name);
|
|
4994
|
+
if (id === null || name === null || !Array.isArray(audience.interests)) {
|
|
4995
|
+
return null;
|
|
4996
|
+
}
|
|
4997
|
+
const interests = parseMailchimpInterests(audience.interests);
|
|
4998
|
+
if (interests === null) return null;
|
|
4999
|
+
audiences.push({
|
|
5000
|
+
id,
|
|
5001
|
+
name,
|
|
5002
|
+
interests
|
|
5003
|
+
});
|
|
5004
|
+
}
|
|
5005
|
+
return {
|
|
5006
|
+
provider: "mailchimp",
|
|
5007
|
+
defaultAudienceId,
|
|
5008
|
+
audiences
|
|
5009
|
+
};
|
|
5010
|
+
}
|
|
5011
|
+
function parseMailchimpInterests(value) {
|
|
5012
|
+
const interests = [];
|
|
5013
|
+
for (const interest of value) {
|
|
5014
|
+
if (!isRecord$1(interest)) return null;
|
|
5015
|
+
const id = parseMailchimpInterestId(interest.id);
|
|
5016
|
+
const name = parseName(interest.name);
|
|
5017
|
+
const categoryName = parseName(interest.categoryName);
|
|
5018
|
+
if (id === null || name === null || categoryName === null) return null;
|
|
5019
|
+
interests.push({
|
|
5020
|
+
id,
|
|
5021
|
+
name,
|
|
5022
|
+
categoryName
|
|
5023
|
+
});
|
|
5024
|
+
}
|
|
5025
|
+
return interests;
|
|
5026
|
+
}
|
|
5027
|
+
function parseNamedItems(value, parseId) {
|
|
5028
|
+
if (!Array.isArray(value)) return null;
|
|
5029
|
+
const items = [];
|
|
5030
|
+
for (const item of value) {
|
|
5031
|
+
if (!isRecord$1(item)) return null;
|
|
5032
|
+
const id = parseId(item.id);
|
|
5033
|
+
const name = parseName(item.name);
|
|
5034
|
+
if (id === null || name === null) return null;
|
|
5035
|
+
items.push({
|
|
5036
|
+
id,
|
|
5037
|
+
name
|
|
5038
|
+
});
|
|
5039
|
+
}
|
|
5040
|
+
return items;
|
|
5041
|
+
}
|
|
5042
|
+
function parseName(value) {
|
|
5043
|
+
if (typeof value !== "string") return null;
|
|
5044
|
+
const name = value.trim();
|
|
5045
|
+
return name.length > 0 ? name : null;
|
|
5046
|
+
}
|
|
5047
|
+
function isRecord$1(value) {
|
|
5048
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5049
|
+
}
|
|
5050
|
+
function invalidRuntimeContext() {
|
|
5051
|
+
return err({ tag: "invalid_mailing_list_runtime_context" });
|
|
5052
|
+
}
|
|
5053
|
+
|
|
5054
|
+
//#endregion
|
|
5055
|
+
//#region ../core/src/mailing-list-submission.ts
|
|
5056
|
+
const MAILING_LIST_SUBMISSION_BUDGET_MS = 1e4;
|
|
5057
|
+
function parseMailingListBlockId(value) {
|
|
5058
|
+
const parsed = typeof value === "string" ? value.trim() : "";
|
|
5059
|
+
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;
|
|
5060
|
+
}
|
|
5061
|
+
function parseMailingListSignedSourceToken(value) {
|
|
5062
|
+
const parsed = typeof value === "string" ? value.trim() : "";
|
|
5063
|
+
return /^[A-Za-z0-9._~-]{16,1000}$/u.test(parsed) ? parsed : null;
|
|
5064
|
+
}
|
|
5065
|
+
function parseMailingListSdkFooterBlockId(value) {
|
|
5066
|
+
const parsed = typeof value === "string" ? value.trim() : "";
|
|
5067
|
+
return /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u.test(parsed) ? parsed : null;
|
|
5068
|
+
}
|
|
5069
|
+
function parseMailingListSdkContentHash(value) {
|
|
5070
|
+
const parsed = typeof value === "string" ? value.trim() : "";
|
|
5071
|
+
return /^[a-f0-9]{16}$/iu.test(parsed) ? parsed : null;
|
|
5072
|
+
}
|
|
5073
|
+
function parseMailingListContentVersionId(value) {
|
|
5074
|
+
const parsed = parseContentVersionId(value);
|
|
5075
|
+
return parsed.ok ? parsed.value : null;
|
|
5076
|
+
}
|
|
5077
|
+
function parseMailingListFooterRevision(value) {
|
|
5078
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : null;
|
|
5079
|
+
}
|
|
5080
|
+
function buildMailingListSignupBlockSourceRef(blockId) {
|
|
5081
|
+
const parsed = parseMailingListBlockId(blockId);
|
|
5082
|
+
return parsed !== null ? {
|
|
5083
|
+
tag: "block_ref",
|
|
5084
|
+
blockId: parsed
|
|
5085
|
+
} : null;
|
|
5086
|
+
}
|
|
5087
|
+
function parseMailingListSignupProfile(form, input) {
|
|
5088
|
+
const email = normalizeSubscriberEmail(input.email);
|
|
5089
|
+
if (email === null) return {
|
|
5090
|
+
ok: false,
|
|
5091
|
+
error: { tag: "invalid_email" }
|
|
5092
|
+
};
|
|
5093
|
+
const phone = form.includeOptionalPhone ? {
|
|
5094
|
+
tag: "collected",
|
|
5095
|
+
value: normalizeOptionalValue(input.phone)
|
|
5096
|
+
} : { tag: "not_collected" };
|
|
5097
|
+
switch (form.fields.preset) {
|
|
5098
|
+
case "emailOnly": return {
|
|
5099
|
+
ok: true,
|
|
5100
|
+
value: {
|
|
5101
|
+
preset: "emailOnly",
|
|
5102
|
+
email,
|
|
5103
|
+
phone
|
|
5104
|
+
}
|
|
5105
|
+
};
|
|
5106
|
+
case "emailName": {
|
|
5107
|
+
const name = resolveProfileField("name", form.fields.name, input.name);
|
|
5108
|
+
return name.ok ? {
|
|
5109
|
+
ok: true,
|
|
5110
|
+
value: {
|
|
5111
|
+
preset: "emailName",
|
|
5112
|
+
email,
|
|
5113
|
+
phone,
|
|
5114
|
+
name: name.value
|
|
5115
|
+
}
|
|
5116
|
+
} : name;
|
|
5117
|
+
}
|
|
5118
|
+
case "emailFirstLast": {
|
|
5119
|
+
const firstName = resolveProfileField("first_name", form.fields.firstName, input.firstName);
|
|
5120
|
+
if (!firstName.ok) return firstName;
|
|
5121
|
+
const lastName = resolveProfileField("last_name", form.fields.lastName, input.lastName);
|
|
5122
|
+
return lastName.ok ? {
|
|
5123
|
+
ok: true,
|
|
5124
|
+
value: {
|
|
5125
|
+
preset: "emailFirstLast",
|
|
5126
|
+
email,
|
|
5127
|
+
phone,
|
|
5128
|
+
firstName: firstName.value,
|
|
5129
|
+
lastName: lastName.value
|
|
5130
|
+
}
|
|
5131
|
+
} : lastName;
|
|
5132
|
+
}
|
|
5133
|
+
case "emailNameCompany": {
|
|
5134
|
+
const name = resolveProfileField("name", form.fields.name, input.name);
|
|
5135
|
+
if (!name.ok) return name;
|
|
5136
|
+
const company = resolveProfileField("company", form.fields.company, input.company);
|
|
5137
|
+
return company.ok ? {
|
|
5138
|
+
ok: true,
|
|
5139
|
+
value: {
|
|
5140
|
+
preset: "emailNameCompany",
|
|
5141
|
+
email,
|
|
5142
|
+
phone,
|
|
5143
|
+
name: name.value,
|
|
5144
|
+
company: company.value
|
|
5145
|
+
}
|
|
5146
|
+
} : company;
|
|
5147
|
+
}
|
|
5148
|
+
}
|
|
5149
|
+
}
|
|
5150
|
+
function resolveProfileField(field, requirement, input) {
|
|
5151
|
+
const value = normalizeOptionalValue(input);
|
|
5152
|
+
if (requirement === "required") {
|
|
5153
|
+
return value === null ? {
|
|
5154
|
+
ok: false,
|
|
5155
|
+
error: {
|
|
5156
|
+
tag: "required_field_missing",
|
|
5157
|
+
field
|
|
5158
|
+
}
|
|
5159
|
+
} : {
|
|
5160
|
+
ok: true,
|
|
5161
|
+
value: {
|
|
5162
|
+
requirement: "required",
|
|
5163
|
+
value
|
|
5164
|
+
}
|
|
5165
|
+
};
|
|
5166
|
+
}
|
|
5167
|
+
return {
|
|
5168
|
+
ok: true,
|
|
5169
|
+
value: {
|
|
5170
|
+
requirement: "optional",
|
|
5171
|
+
value
|
|
5172
|
+
}
|
|
5173
|
+
};
|
|
5174
|
+
}
|
|
5175
|
+
function normalizeSubscriberEmail(value) {
|
|
5176
|
+
const normalized = value.trim().toLowerCase();
|
|
5177
|
+
const at = normalized.indexOf("@");
|
|
5178
|
+
return normalized.length <= 320 && at > 0 && at === normalized.lastIndexOf("@") && at < normalized.length - 1 ? normalized : null;
|
|
5179
|
+
}
|
|
5180
|
+
function normalizeOptionalValue(value) {
|
|
5181
|
+
const normalized = value?.trim() ?? "";
|
|
5182
|
+
return normalized.length > 0 ? normalized : null;
|
|
5183
|
+
}
|
|
5184
|
+
function toMailingListPublicSignupResponse(result) {
|
|
5185
|
+
if (result.ok) {
|
|
5186
|
+
return result.acknowledgement.tag === "subscribed" ? { tag: "subscribed" } : { tag: "confirmation_required" };
|
|
5187
|
+
}
|
|
5188
|
+
if (result.error.tag === "profile_rejected") {
|
|
5189
|
+
return {
|
|
5190
|
+
tag: "invalid_input",
|
|
5191
|
+
reason: "profile_rejected"
|
|
5192
|
+
};
|
|
5193
|
+
}
|
|
5194
|
+
return result.error.tag === "uncertain" ? {
|
|
5195
|
+
tag: "uncertain",
|
|
5196
|
+
reason: result.error.reason
|
|
5197
|
+
} : {
|
|
5198
|
+
tag: "unavailable",
|
|
5199
|
+
reason: result.error.tag
|
|
5200
|
+
};
|
|
5201
|
+
}
|
|
5202
|
+
|
|
4366
5203
|
//#endregion
|
|
4367
5204
|
//#region ../core/src/number-input.ts
|
|
4368
5205
|
/**
|
|
@@ -5274,6 +6111,63 @@ function resolveWholeSeriesBookingPhase(run, now) {
|
|
|
5274
6111
|
}
|
|
5275
6112
|
}
|
|
5276
6113
|
|
|
6114
|
+
//#endregion
|
|
6115
|
+
//#region ../core/src/public-read-cache-contract.ts
|
|
6116
|
+
const PUBLIC_AVAILABILITY_FRESHNESS_SECONDS = 60;
|
|
6117
|
+
const PUBLIC_CONTENT_FRESHNESS_SECONDS = 3600;
|
|
6118
|
+
function availability(transport) {
|
|
6119
|
+
return {
|
|
6120
|
+
kind: "live",
|
|
6121
|
+
reason: "booking_correctness",
|
|
6122
|
+
freshness: "availability",
|
|
6123
|
+
transport
|
|
6124
|
+
};
|
|
6125
|
+
}
|
|
6126
|
+
function content(tags, transport = "direct") {
|
|
6127
|
+
return {
|
|
6128
|
+
kind: "tagged",
|
|
6129
|
+
tags,
|
|
6130
|
+
freshness: "content",
|
|
6131
|
+
transport
|
|
6132
|
+
};
|
|
6133
|
+
}
|
|
6134
|
+
/** The single classification authority for cacheable public reads. */
|
|
6135
|
+
const PUBLIC_READ_CACHE_POLICIES = {
|
|
6136
|
+
listPublishedEntries: content(["published_content"]),
|
|
6137
|
+
getPublishedEntryPreview: content(["published_content"]),
|
|
6138
|
+
listPublicEvents: availability("direct"),
|
|
6139
|
+
listPublicEventCalendarWindow: availability("direct"),
|
|
6140
|
+
listPublicRecurringSchedule: availability("batch_only"),
|
|
6141
|
+
getPublicEventDetails: availability("batch_only"),
|
|
6142
|
+
resolveEventSubroute: availability("direct"),
|
|
6143
|
+
listPublicRouteCandidates: content(["published_content"], "batch_only"),
|
|
6144
|
+
listPublicTeamMembers: content(["public_team_members"]),
|
|
6145
|
+
listPublicProducts: availability("direct"),
|
|
6146
|
+
listPublicPasses: availability("direct"),
|
|
6147
|
+
listPublicMemberships: availability("direct"),
|
|
6148
|
+
getPublicFormById: content(["site_forms"]),
|
|
6149
|
+
getPublicBookingServices: availability("direct"),
|
|
6150
|
+
getPublicBookingService: availability("direct"),
|
|
6151
|
+
getPublicBookingResourcesReference: availability("direct"),
|
|
6152
|
+
getPublicBookingAvailableDates: availability("direct"),
|
|
6153
|
+
getPublicBookingAvailableSlots: availability("direct"),
|
|
6154
|
+
getPublicWeeklySlotAvailability: availability("direct"),
|
|
6155
|
+
listPublicForms: content(["site_forms"]),
|
|
6156
|
+
checkRedirect: content([]),
|
|
6157
|
+
getPublicRoutableContent: content(["published_content"]),
|
|
6158
|
+
getPublicSitemapRoutes: content(["published_content"])
|
|
6159
|
+
};
|
|
6160
|
+
const PUBLIC_READ_ENDPOINT_SET = new Set(Object.keys(PUBLIC_READ_CACHE_POLICIES));
|
|
6161
|
+
function isPublicReadEndpoint(endpoint) {
|
|
6162
|
+
return PUBLIC_READ_ENDPOINT_SET.has(endpoint);
|
|
6163
|
+
}
|
|
6164
|
+
function getPublicReadCachePolicy(endpoint) {
|
|
6165
|
+
return PUBLIC_READ_CACHE_POLICIES[endpoint];
|
|
6166
|
+
}
|
|
6167
|
+
function publicReadFreshnessSeconds(endpoint) {
|
|
6168
|
+
return getPublicReadCachePolicy(endpoint).freshness === "availability" ? PUBLIC_AVAILABILITY_FRESHNESS_SECONDS : PUBLIC_CONTENT_FRESHNESS_SECONDS;
|
|
6169
|
+
}
|
|
6170
|
+
|
|
5277
6171
|
//#endregion
|
|
5278
6172
|
//#region ../core/src/event-series-behaviour.ts
|
|
5279
6173
|
const EVENT_PRESET_VALUES = [
|
|
@@ -5357,13 +6251,13 @@ const BOOKING_DEFAULTS_BY_BEHAVIOUR = {
|
|
|
5357
6251
|
memberships: "off"
|
|
5358
6252
|
}
|
|
5359
6253
|
};
|
|
5360
|
-
function verticalBookingPreset(id, verticalId, canonicalBehaviour, label, pluralLabel, description, availability = "onboarding") {
|
|
6254
|
+
function verticalBookingPreset(id, verticalId, canonicalBehaviour, label, pluralLabel, description, availability$1 = "onboarding") {
|
|
5361
6255
|
return {
|
|
5362
6256
|
id,
|
|
5363
6257
|
verticalId,
|
|
5364
6258
|
canonicalBehaviour,
|
|
5365
6259
|
engine: BOOKING_ENGINE_BY_BEHAVIOUR[canonicalBehaviour],
|
|
5366
|
-
availability,
|
|
6260
|
+
availability: availability$1,
|
|
5367
6261
|
label,
|
|
5368
6262
|
pluralLabel,
|
|
5369
6263
|
description
|
|
@@ -5717,12 +6611,12 @@ const VERTICAL_PRESET_AVAILABILITIES = [
|
|
|
5717
6611
|
"future"
|
|
5718
6612
|
];
|
|
5719
6613
|
function getVerticalPresetsForVertical(verticalId, options) {
|
|
5720
|
-
const availability = options?.availability;
|
|
6614
|
+
const availability$1 = options?.availability;
|
|
5721
6615
|
return VERTICAL_BOOKING_PRESETS.filter((presetDefinition) => {
|
|
5722
6616
|
if (presetDefinition.verticalId !== verticalId) return false;
|
|
5723
|
-
if (!availability) return true;
|
|
5724
|
-
if (availability === "selectable") return presetDefinition.availability !== "future";
|
|
5725
|
-
return presetDefinition.availability === availability;
|
|
6617
|
+
if (!availability$1) return true;
|
|
6618
|
+
if (availability$1 === "selectable") return presetDefinition.availability !== "future";
|
|
6619
|
+
return presetDefinition.availability === availability$1;
|
|
5726
6620
|
});
|
|
5727
6621
|
}
|
|
5728
6622
|
function getOnboardingPresetsForVertical(verticalId) {
|
|
@@ -5946,4 +6840,62 @@ function orderPresetIdsForVertical(verticalId, presetIds) {
|
|
|
5946
6840
|
}
|
|
5947
6841
|
|
|
5948
6842
|
//#endregion
|
|
5949
|
-
|
|
6843
|
+
//#region ../core/src/navigation-locations.ts
|
|
6844
|
+
/** The only places a site's navigation can be displayed. */
|
|
6845
|
+
const NAVIGATION_LOCATIONS = [
|
|
6846
|
+
"main",
|
|
6847
|
+
"footer",
|
|
6848
|
+
"legal"
|
|
6849
|
+
];
|
|
6850
|
+
const NAVIGATION_LOCATION_DESCRIPTORS = {
|
|
6851
|
+
main: {
|
|
6852
|
+
location: "main",
|
|
6853
|
+
label: "Main navigation",
|
|
6854
|
+
description: "Links shown in the site header when header navigation is enabled."
|
|
6855
|
+
},
|
|
6856
|
+
footer: {
|
|
6857
|
+
location: "footer",
|
|
6858
|
+
label: "Footer links",
|
|
6859
|
+
description: "Links shown in the main footer links section when it is enabled."
|
|
6860
|
+
},
|
|
6861
|
+
legal: {
|
|
6862
|
+
location: "legal",
|
|
6863
|
+
label: "Legal links",
|
|
6864
|
+
description: "Smaller footer links for privacy, terms and other policies."
|
|
6865
|
+
}
|
|
6866
|
+
};
|
|
6867
|
+
function isNavigationLocation(value) {
|
|
6868
|
+
return typeof value === "string" && NAVIGATION_LOCATIONS.includes(value);
|
|
6869
|
+
}
|
|
6870
|
+
/** Parse all rows for one site into a complete fixed-location record. */
|
|
6871
|
+
function parseSiteNavigationLocations(rows) {
|
|
6872
|
+
const locations = {};
|
|
6873
|
+
for (const [index, row] of rows.entries()) {
|
|
6874
|
+
if (!isNavigationLocation(row.location)) {
|
|
6875
|
+
return err({
|
|
6876
|
+
kind: "invalid_location",
|
|
6877
|
+
index,
|
|
6878
|
+
value: row.location
|
|
6879
|
+
});
|
|
6880
|
+
}
|
|
6881
|
+
if (Object.prototype.hasOwnProperty.call(locations, row.location)) {
|
|
6882
|
+
return err({
|
|
6883
|
+
kind: "duplicate_location",
|
|
6884
|
+
location: row.location
|
|
6885
|
+
});
|
|
6886
|
+
}
|
|
6887
|
+
locations[row.location] = row.value;
|
|
6888
|
+
}
|
|
6889
|
+
for (const location of NAVIGATION_LOCATIONS) {
|
|
6890
|
+
if (!Object.prototype.hasOwnProperty.call(locations, location)) {
|
|
6891
|
+
return err({
|
|
6892
|
+
kind: "missing_location",
|
|
6893
|
+
location
|
|
6894
|
+
});
|
|
6895
|
+
}
|
|
6896
|
+
}
|
|
6897
|
+
return ok(locations);
|
|
6898
|
+
}
|
|
6899
|
+
|
|
6900
|
+
//#endregion
|
|
6901
|
+
export { publicEventPricingDisplay as $, assertAllowedPublicUrl as A, unsafeAsSiteFontId as At, getBookingLocalDateKey as B, parseMailingListSignedSourceToken as C, unsafeAsMediaAssetId as Ct, parseFooterCompositionV1 as D, unsafeAsPositiveSeconds as Dt, footerNavigationLayouts as E, unsafeAsPositiveByteCount as Et, formatBookingDate as F, unsafeAsStoragePath as Ft, toScheduledBookingDateRange as G, getLocalScheduleTime as H, formatBookingDateParts as I, unsafeAsUploadSessionId as It, parseEventPageSurfaceSubject as J, toScheduledBookingDateTime as K, formatBookingTime as L, unsafeAsUserId as Lt, normalizeLocationAddressText as M, unsafeAsSiteScopedStoragePath as Mt, toLocationCoordinates as N, unsafeAsStaffMemberId as Nt, parseMailingListPlacementTargeting as O, unsafeAsProductId as Ot, buildBookingUtcDateWindow as P, unsafeAsStorageBucketName as Pt, publicEventPricingCurrency as Q, formatLocalScheduleDate as R, err as Rt, parseMailingListBlockId as S, unsafeAsFileChecksumSha256 as St, planMailingListChoicePresentation as T, unsafeAsOriginalFilename as Tt, parseUtcIsoDateTimeString as U, getLocalScheduleDate as V, toBookingTimeZone as W, formatEventPricing as X, formatBookingPriceDisplay as Y, isPublicEventPricingOptionDisplayable as Z, createSecret as _, unsafeAsDemoCapability as _t, parseVerticalId as a, formatCurrencyAmount as at, stableJsonStringify as b, unsafeAsEventOfferingId as bt, DEFAULT_EVENT_TYPE_PRESETS as c, parseEventSeriesId as ct, SURFACE_EVENT_PRESET_VALUES as d, parseSiteId as dt, publicEventPricingType as et, WHOLE_SERIES_EVENT_PRESET_VALUES as f, parseUserId as ft, resolveWholeSeriesBookingPhase as g, unsafeAsDeclaredMimeType as gt, orderedLiveRunSessions as h, unsafeAsBookingSessionId as ht, isEventSeriesVerticalPresetDefinition as i, mapNonEmptyArray as it, isPresent as j, unsafeAsSiteId as jt, isCanonicalRichTextDoc as k, unsafeAsSafeDownloadFilename as kt, EVENT_PRESET_VALUES as l, parseMediaAssetId as lt, CANCELLED_SESSION_STATUS as m, unsafeAsBookingRequirementId as mt, areConfiguredBookingVerticalConfigsEqual as n, resolvePricingOptionsPriceDisplay as nt, parseVerticalPresetId as o, assertNever as ot, publicReadFreshnessSeconds as p, unsafeAsAppointmentResourceId as pt, parseBookingTimeZone as q, canonicalizeConfiguredBookingVerticalConfig as r, fromArray as rt, resolveSiteVerticalBookingConfig as s, parseApiKeyId as st, NAVIGATION_LOCATIONS as t, resolveExactOrFreePriceDisplay as tt, ORDINARY_EVENT_PRESET_VALUES as u, parsePageId as ut, exposeSecret as v, unsafeAsDetectedMimeType as vt, parseMailingListRuntimeContext as w, unsafeAsOccurrenceId as wt, buildMailingListSignupBlockSourceRef as x, unsafeAsEventSeriesId as xt, parseManagementKey as y, unsafeAsEntitlementId as yt, formatLocalScheduleTime as z, ok as zt };
|