riverbankcms 0.6.0 → 0.7.1
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 +2903 -2093
- 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 +2 -2
- package/dist/{eventUpsertInputSchema-CtkDnYlQ.mjs → eventUpsertInputSchema-DP8gbZJ9.mjs} +2 -2
- package/dist/{load-config-DbMjs6df.mjs → load-config-CkSoLJFY.mjs} +1 -1
- package/dist/load-config-Dgi_eByc.mjs +5 -0
- package/dist/{plan-DubdLR3N.mjs → plan-BFmMfERc.mjs} +22 -14
- package/dist/scaffold/index.mjs +2 -2
- package/dist/{sdk-event-upsert-CvFCbzNc.mjs → sdk-event-upsert-Cp043nSP.mjs} +842 -631
- package/dist/{sdk-peer-CyQ2so48.mjs → sdk-peer-CADuG9SR.mjs} +3 -3
- package/dist/{src-X9oZOIoK.mjs → src-B8fOSKJ6.mjs} +1236 -174
- package/dist/{style-aixm8BXi.mjs → style-BiosmAJm.mjs} +11 -18
- package/dist/testing.mjs +4 -4
- package/package.json +2 -2
- package/dist/load-config-NNJ0ww1N.mjs +0 -5
|
@@ -79,7 +79,6 @@ const unsafeAsBookingSessionId = (id) => id;
|
|
|
79
79
|
const unsafeAsDatedOfferingCapacityHoldId = (value) => value;
|
|
80
80
|
const unsafeAsDatedOfferingCapacityHoldAuditRef = (value) => value;
|
|
81
81
|
const unsafeAsDatedOfferingRevocationAuditEventId = (value) => value;
|
|
82
|
-
const unsafeAsDatedOfferingNonCashProjectionClaimToken = (value) => value;
|
|
83
82
|
const unsafeAsDatedOfferingWaitlistCapacityEffectId = (value) => value;
|
|
84
83
|
const unsafeAsDatedOfferingWaitlistCapacityEffectClaimToken = (value) => value;
|
|
85
84
|
const unsafeAsDatedOfferingRunCancellationOperationId = (value) => value;
|
|
@@ -103,7 +102,6 @@ const unsafeAsCheckoutLineId = (id) => id;
|
|
|
103
102
|
const unsafeAsAttendeeId = (id) => id;
|
|
104
103
|
const unsafeAsEventRegistrationCommandId = (id) => id;
|
|
105
104
|
const unsafeAsEventRegistrationCommandRowId = (id) => id;
|
|
106
|
-
const unsafeAsEventRegistrationProjectionClaimToken = (id) => id;
|
|
107
105
|
const unsafeAsCustomerPassId = (id) => id;
|
|
108
106
|
const unsafeAsCustomerMembershipId = (id) => id;
|
|
109
107
|
const unsafeAsAppointmentId = (id) => id;
|
|
@@ -149,7 +147,6 @@ const unsafeAsParticipantId = (id) => id;
|
|
|
149
147
|
const unsafeAsParticipantParticipationId = (id) => id;
|
|
150
148
|
const unsafeAsParticipantRosterAssertionJobId = (id) => id;
|
|
151
149
|
const unsafeAsParticipantBookingQuestionsTaskId = (id) => id;
|
|
152
|
-
const unsafeAsEventAttendeeGuestId = (id) => id;
|
|
153
150
|
const unsafeAsPersonRecordId = (id) => id;
|
|
154
151
|
const unsafeAsEncounterRecordId = (id) => id;
|
|
155
152
|
const unsafeAsRecordEntryId = (id) => id;
|
|
@@ -186,11 +183,9 @@ const parseAppointmentReservationRunId = (value) => parseUuidBrand(value, unsafe
|
|
|
186
183
|
const parseAttendeeId = (value) => parseUuidBrand(value, unsafeAsAttendeeId);
|
|
187
184
|
const parseEventRegistrationCommandId = (value) => parseUuidBrand(value, unsafeAsEventRegistrationCommandId);
|
|
188
185
|
const parseEventRegistrationCommandRowId = (value) => parseUuidBrand(value, unsafeAsEventRegistrationCommandRowId);
|
|
189
|
-
const parseEventRegistrationProjectionClaimToken = (value) => parseUuidBrand(value, unsafeAsEventRegistrationProjectionClaimToken);
|
|
190
186
|
const parseDatedOfferingCapacityHoldId = (value) => parseUuidBrand(value, unsafeAsDatedOfferingCapacityHoldId);
|
|
191
187
|
const parseDatedOfferingCapacityHoldAuditRef = (value) => parseUuidBrand(value, unsafeAsDatedOfferingCapacityHoldAuditRef);
|
|
192
188
|
const parseDatedOfferingRevocationAuditEventId = (value) => parseUuidBrand(value, unsafeAsDatedOfferingRevocationAuditEventId);
|
|
193
|
-
const parseDatedOfferingNonCashProjectionClaimToken = (value) => parseUuidBrand(value, unsafeAsDatedOfferingNonCashProjectionClaimToken);
|
|
194
189
|
const parseDatedOfferingWaitlistCapacityEffectId = (value) => parseUuidBrand(value, unsafeAsDatedOfferingWaitlistCapacityEffectId);
|
|
195
190
|
const parseDatedOfferingWaitlistCapacityEffectClaimToken = (value) => parseUuidBrand(value, unsafeAsDatedOfferingWaitlistCapacityEffectClaimToken);
|
|
196
191
|
const parseDatedOfferingRunCancellationOperationId = (value) => parseUuidBrand(value, unsafeAsDatedOfferingRunCancellationOperationId);
|
|
@@ -814,20 +809,20 @@ function parseOptionAvailability(input) {
|
|
|
814
809
|
function parseEventPricingOption(input) {
|
|
815
810
|
const identity = parseOptionIdentity(input);
|
|
816
811
|
const commercials = parseOptionCommercials(input);
|
|
817
|
-
const availability = parseOptionAvailability(input);
|
|
812
|
+
const availability$1 = parseOptionAvailability(input);
|
|
818
813
|
const issues = [
|
|
819
814
|
identity,
|
|
820
815
|
commercials,
|
|
821
|
-
availability
|
|
816
|
+
availability$1
|
|
822
817
|
].flatMap((result) => result.ok ? [] : [result.error]);
|
|
823
|
-
if (!identity.ok || !commercials.ok || !availability.ok) {
|
|
818
|
+
if (!identity.ok || !commercials.ok || !availability$1.ok) {
|
|
824
819
|
const nonEmptyIssues = fromReadonlyArray(issues);
|
|
825
820
|
return err(nonEmptyIssues.ok ? nonEmptyIssues.value : oneIssue({ kind: "invalid_object" }));
|
|
826
821
|
}
|
|
827
822
|
return ok({
|
|
828
823
|
...identity.value,
|
|
829
824
|
...commercials.value,
|
|
830
|
-
...availability.value
|
|
825
|
+
...availability$1.value
|
|
831
826
|
});
|
|
832
827
|
}
|
|
833
828
|
function unexpectedValues(input, fields) {
|
|
@@ -1303,7 +1298,7 @@ function parseEventPageSurfaceDestinationMode(value) {
|
|
|
1303
1298
|
return value === "cms-managed" || value === "system-managed" ? value : undefined;
|
|
1304
1299
|
}
|
|
1305
1300
|
function parseEventPageSurfaceSubject(value) {
|
|
1306
|
-
if (!isRecord$
|
|
1301
|
+
if (!isRecord$9(value)) return err({ kind: "notObject" });
|
|
1307
1302
|
switch (value.kind) {
|
|
1308
1303
|
case "eventSeries": {
|
|
1309
1304
|
const eventSeriesId = parseEventSeriesId(value.eventSeriesId);
|
|
@@ -1373,7 +1368,7 @@ function parseEventSeriesIdList(values) {
|
|
|
1373
1368
|
}
|
|
1374
1369
|
return ok(parsed);
|
|
1375
1370
|
}
|
|
1376
|
-
function isRecord$
|
|
1371
|
+
function isRecord$9(value) {
|
|
1377
1372
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1378
1373
|
}
|
|
1379
1374
|
|
|
@@ -2575,41 +2570,14 @@ function parseParticipantCount(value) {
|
|
|
2575
2570
|
}
|
|
2576
2571
|
return ok(unsafeAsParticipantCount(value));
|
|
2577
2572
|
}
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
kind: identity.kind,
|
|
2587
|
-
source: "event_guest_backfill",
|
|
2588
|
-
eventAttendeeGuestId: identity.eventAttendeeGuestId,
|
|
2589
|
-
slotKey: identity.slotKey
|
|
2590
|
-
}) };
|
|
2591
|
-
function encodeProvisionalParticipantIdentity(identity) {
|
|
2592
|
-
return provisionalParticipantIdentityEncoders[identity.kind](identity);
|
|
2593
|
-
}
|
|
2594
|
-
function parseProvisionalParticipantIdentity(value) {
|
|
2595
|
-
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
2596
|
-
return err({ kind: "not_an_object" });
|
|
2597
|
-
}
|
|
2598
|
-
const metadata = value;
|
|
2599
|
-
const kind = metadata.kind ?? metadata.source;
|
|
2600
|
-
if (kind !== "event_guest" && kind !== "event_guest_backfill") {
|
|
2601
|
-
return err({ kind: "unsupported_identity_kind" });
|
|
2602
|
-
}
|
|
2603
|
-
if (typeof metadata.eventAttendeeGuestId !== "string") {
|
|
2604
|
-
return err({ kind: "missing_event_attendee_guest_id" });
|
|
2605
|
-
}
|
|
2606
|
-
if (typeof metadata.slotKey !== "string") {
|
|
2607
|
-
return err({ kind: "missing_slot_key" });
|
|
2608
|
-
}
|
|
2609
|
-
return ok(provisionalEventGuestParticipantIdentity({
|
|
2610
|
-
eventAttendeeGuestId: unsafeAsEventAttendeeGuestId(metadata.eventAttendeeGuestId),
|
|
2611
|
-
slotKey: unsafeAsParticipantSlotKey(metadata.slotKey)
|
|
2612
|
-
}));
|
|
2573
|
+
/**
|
|
2574
|
+
* The in-memory planning key for one guest place on an occurrence registration.
|
|
2575
|
+
*
|
|
2576
|
+
* Persistence uses the participation row and its explicit guest ordinal. This
|
|
2577
|
+
* key only lets pure roster planning correlate issues and resolutions.
|
|
2578
|
+
*/
|
|
2579
|
+
function eventGuestRosterSlotKey(input) {
|
|
2580
|
+
return unsafeAsParticipantSlotKey(`event_guest:${input.attendeeId}:${input.guestIndex}`);
|
|
2613
2581
|
}
|
|
2614
2582
|
function deriveParticipantDisplayLabel(input) {
|
|
2615
2583
|
const displayName = trimmedStringOrNull(input.displayName);
|
|
@@ -2735,12 +2703,15 @@ function projectEventRegistrationParticipantRoster(input) {
|
|
|
2735
2703
|
}
|
|
2736
2704
|
});
|
|
2737
2705
|
const guestSlots = input.guests.map((guest) => buildSlot({
|
|
2738
|
-
slotKey:
|
|
2706
|
+
slotKey: eventGuestRosterSlotKey({
|
|
2707
|
+
attendeeId: input.attendeeId,
|
|
2708
|
+
guestIndex: guest.guestIndex
|
|
2709
|
+
}),
|
|
2739
2710
|
contact: guest,
|
|
2740
2711
|
participation: {
|
|
2741
2712
|
kind: "event_guest",
|
|
2742
2713
|
attendeeId: input.attendeeId,
|
|
2743
|
-
|
|
2714
|
+
guestIndex: guest.guestIndex
|
|
2744
2715
|
}
|
|
2745
2716
|
}));
|
|
2746
2717
|
const slots = [bookerSlot, ...guestSlots];
|
|
@@ -3239,7 +3210,7 @@ const knownSocialPlatforms = [
|
|
|
3239
3210
|
"x",
|
|
3240
3211
|
"youtube"
|
|
3241
3212
|
];
|
|
3242
|
-
function isRecord$
|
|
3213
|
+
function isRecord$8(value) {
|
|
3243
3214
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3244
3215
|
}
|
|
3245
3216
|
function trimmedOptionalString(value) {
|
|
@@ -3249,7 +3220,7 @@ function trimmedOptionalString(value) {
|
|
|
3249
3220
|
return trimmed.length > 0 ? trimmed : null;
|
|
3250
3221
|
}
|
|
3251
3222
|
function parsePublicContactDetails(value) {
|
|
3252
|
-
if (!isRecord$
|
|
3223
|
+
if (!isRecord$8(value)) {
|
|
3253
3224
|
return err({
|
|
3254
3225
|
code: "invalid_shape",
|
|
3255
3226
|
path: "contact",
|
|
@@ -3345,7 +3316,7 @@ function minutesSinceMidnight(value) {
|
|
|
3345
3316
|
}
|
|
3346
3317
|
function parseOpeningHoursDay(value, expectedWeekday, index) {
|
|
3347
3318
|
const path = `openingHours.days.${index}`;
|
|
3348
|
-
if (!isRecord$
|
|
3319
|
+
if (!isRecord$8(value) || value.weekday !== expectedWeekday) {
|
|
3349
3320
|
return err({
|
|
3350
3321
|
code: "invalid_weekdays",
|
|
3351
3322
|
path,
|
|
@@ -3366,7 +3337,7 @@ function parseOpeningHoursDay(value, expectedWeekday, index) {
|
|
|
3366
3337
|
const intervals = [];
|
|
3367
3338
|
for (const [intervalIndex, rawInterval] of value.intervals.entries()) {
|
|
3368
3339
|
const intervalPath = `${path}.intervals.${intervalIndex}`;
|
|
3369
|
-
if (!isRecord$
|
|
3340
|
+
if (!isRecord$8(rawInterval)) {
|
|
3370
3341
|
return err({
|
|
3371
3342
|
code: "invalid_interval",
|
|
3372
3343
|
path: intervalPath,
|
|
@@ -3416,7 +3387,7 @@ function parseOpeningHoursDay(value, expectedWeekday, index) {
|
|
|
3416
3387
|
});
|
|
3417
3388
|
}
|
|
3418
3389
|
function parseWeeklyOpeningHours(value) {
|
|
3419
|
-
if (!isRecord$
|
|
3390
|
+
if (!isRecord$8(value) || !Array.isArray(value.days) || value.days.length !== publicProfileWeekdays.length) {
|
|
3420
3391
|
return err({
|
|
3421
3392
|
code: "invalid_weekdays",
|
|
3422
3393
|
path: "openingHours.days",
|
|
@@ -3496,7 +3467,7 @@ function parsePublicSocialLinks(value) {
|
|
|
3496
3467
|
const ids = new Set();
|
|
3497
3468
|
for (const [index, rawLink] of value.entries()) {
|
|
3498
3469
|
const path = `socialLinks.${index}`;
|
|
3499
|
-
if (!isRecord$
|
|
3470
|
+
if (!isRecord$8(rawLink)) {
|
|
3500
3471
|
return err({
|
|
3501
3472
|
code: "invalid_social_link",
|
|
3502
3473
|
path,
|
|
@@ -3543,7 +3514,7 @@ function parsePublicSocialLinks(value) {
|
|
|
3543
3514
|
return ok(links);
|
|
3544
3515
|
}
|
|
3545
3516
|
function parsePublicProfile(value) {
|
|
3546
|
-
if (!isRecord$
|
|
3517
|
+
if (!isRecord$8(value)) {
|
|
3547
3518
|
return err({
|
|
3548
3519
|
code: "invalid_shape",
|
|
3549
3520
|
path: "",
|
|
@@ -3556,23 +3527,105 @@ function parsePublicProfile(value) {
|
|
|
3556
3527
|
if (!openingHours.ok) return openingHours;
|
|
3557
3528
|
const socialLinks = parsePublicSocialLinks(value.socialLinks);
|
|
3558
3529
|
if (!socialLinks.ok) return socialLinks;
|
|
3530
|
+
const addressVisibility = parseAddressVisibility(value.addressVisibility);
|
|
3531
|
+
if (!addressVisibility.ok) return addressVisibility;
|
|
3532
|
+
const contactVisibility = parseContactVisibility(value.contactVisibility);
|
|
3533
|
+
if (!contactVisibility.ok) return contactVisibility;
|
|
3534
|
+
const premises = parsePremises(value.premises);
|
|
3535
|
+
if (!premises.ok) return premises;
|
|
3559
3536
|
return ok({
|
|
3560
3537
|
contact: contact.value,
|
|
3538
|
+
contactVisibility: contactVisibility.value,
|
|
3561
3539
|
openingHours: openingHours.value,
|
|
3562
|
-
socialLinks: socialLinks.value
|
|
3540
|
+
socialLinks: socialLinks.value,
|
|
3541
|
+
addressVisibility: addressVisibility.value,
|
|
3542
|
+
premises: premises.value
|
|
3543
|
+
});
|
|
3544
|
+
}
|
|
3545
|
+
function parseFieldVisibility(value, path) {
|
|
3546
|
+
if (value === undefined || value === null) return ok("shown");
|
|
3547
|
+
if (value === "shown" || value === "hidden") return ok(value);
|
|
3548
|
+
return err({
|
|
3549
|
+
code: "invalid_contact_visibility",
|
|
3550
|
+
path,
|
|
3551
|
+
message: "Contact visibility must be shown or hidden."
|
|
3552
|
+
});
|
|
3553
|
+
}
|
|
3554
|
+
function parseContactVisibility(value) {
|
|
3555
|
+
if (value === undefined || value === null) {
|
|
3556
|
+
return ok({
|
|
3557
|
+
phone: "shown",
|
|
3558
|
+
email: "shown"
|
|
3559
|
+
});
|
|
3560
|
+
}
|
|
3561
|
+
if (!isRecord$8(value)) {
|
|
3562
|
+
return err({
|
|
3563
|
+
code: "invalid_contact_visibility",
|
|
3564
|
+
path: "contactVisibility",
|
|
3565
|
+
message: "Contact visibility must be an object."
|
|
3566
|
+
});
|
|
3567
|
+
}
|
|
3568
|
+
const phone = parseFieldVisibility(value.phone, "contactVisibility.phone");
|
|
3569
|
+
if (!phone.ok) return phone;
|
|
3570
|
+
const email = parseFieldVisibility(value.email, "contactVisibility.email");
|
|
3571
|
+
if (!email.ok) return email;
|
|
3572
|
+
return ok({
|
|
3573
|
+
phone: phone.value,
|
|
3574
|
+
email: email.value
|
|
3575
|
+
});
|
|
3576
|
+
}
|
|
3577
|
+
function parsePremises(value) {
|
|
3578
|
+
if (value === undefined || value === null) return ok(null);
|
|
3579
|
+
if (typeof value === "boolean") return ok(value);
|
|
3580
|
+
return err({
|
|
3581
|
+
code: "invalid_premises",
|
|
3582
|
+
path: "premises",
|
|
3583
|
+
message: "Premises must be true or false."
|
|
3584
|
+
});
|
|
3585
|
+
}
|
|
3586
|
+
/**
|
|
3587
|
+
* Resolves whether a site has premises, falling back to whether it already
|
|
3588
|
+
* holds a business address for every profile saved before the switch existed.
|
|
3589
|
+
*/
|
|
3590
|
+
function resolvePublicProfilePremises(profile, hasBusinessAddress) {
|
|
3591
|
+
return profile.premises ?? hasBusinessAddress;
|
|
3592
|
+
}
|
|
3593
|
+
function parseAddressVisibility(value) {
|
|
3594
|
+
if (value === undefined || value === null) return ok("shown");
|
|
3595
|
+
if (value === "shown" || value === "hidden") return ok(value);
|
|
3596
|
+
return err({
|
|
3597
|
+
code: "invalid_address_visibility",
|
|
3598
|
+
path: "addressVisibility",
|
|
3599
|
+
message: "Address visibility must be shown or hidden."
|
|
3563
3600
|
});
|
|
3564
3601
|
}
|
|
3565
3602
|
function emptyPublicProfile() {
|
|
3566
3603
|
return {
|
|
3567
3604
|
contact: null,
|
|
3605
|
+
contactVisibility: {
|
|
3606
|
+
phone: "shown",
|
|
3607
|
+
email: "shown"
|
|
3608
|
+
},
|
|
3568
3609
|
openingHours: null,
|
|
3569
|
-
socialLinks: []
|
|
3610
|
+
socialLinks: [],
|
|
3611
|
+
addressVisibility: "shown",
|
|
3612
|
+
premises: null
|
|
3570
3613
|
};
|
|
3571
3614
|
}
|
|
3572
3615
|
|
|
3616
|
+
//#endregion
|
|
3617
|
+
//#region ../core/src/public-experience.ts
|
|
3618
|
+
const PUBLIC_EXPERIENCES = ["website", "hosted_booking"];
|
|
3619
|
+
function isPublicExperience(value) {
|
|
3620
|
+
return typeof value === "string" && PUBLIC_EXPERIENCES.includes(value);
|
|
3621
|
+
}
|
|
3622
|
+
function parsePublicExperience(value) {
|
|
3623
|
+
return isPublicExperience(value) ? value : null;
|
|
3624
|
+
}
|
|
3625
|
+
|
|
3573
3626
|
//#endregion
|
|
3574
3627
|
//#region ../core/src/rich-text.ts
|
|
3575
|
-
function isRecord$
|
|
3628
|
+
function isRecord$7(value) {
|
|
3576
3629
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3577
3630
|
}
|
|
3578
3631
|
function hasOnlyKeys(value, allowed) {
|
|
@@ -3594,10 +3647,10 @@ function isDenseArrayOf(value, predicate) {
|
|
|
3594
3647
|
return true;
|
|
3595
3648
|
}
|
|
3596
3649
|
function isTipTapMark(value) {
|
|
3597
|
-
return isRecord$
|
|
3650
|
+
return isRecord$7(value) && hasOnlyKeys(value, markKeys) && typeof value.type === "string" && value.type.length > 0 && (value.attrs === undefined || isRecord$7(value.attrs));
|
|
3598
3651
|
}
|
|
3599
3652
|
function isTipTapNode(value) {
|
|
3600
|
-
if (!isRecord$
|
|
3653
|
+
if (!isRecord$7(value) || !hasOnlyKeys(value, nodeKeys) || typeof value.type !== "string" || value.type.length === 0 || value.type === "doc" || value.attrs !== undefined && !isRecord$7(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
3654
|
return false;
|
|
3602
3655
|
}
|
|
3603
3656
|
if (value.type === "text") {
|
|
@@ -3606,89 +3659,222 @@ function isTipTapNode(value) {
|
|
|
3606
3659
|
return value.text === undefined;
|
|
3607
3660
|
}
|
|
3608
3661
|
function isCanonicalRichTextDoc(value) {
|
|
3609
|
-
return isRecord$
|
|
3662
|
+
return isRecord$7(value) && hasOnlyKeys(value, rootKeys) && value.type === "doc" && Array.isArray(value.content) && isDenseArrayOf(value.content, isTipTapNode);
|
|
3610
3663
|
}
|
|
3611
3664
|
|
|
3612
3665
|
//#endregion
|
|
3613
|
-
//#region ../core/src/
|
|
3666
|
+
//#region ../core/src/mailing-list-identifiers.ts
|
|
3614
3667
|
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
|
|
3668
|
+
const OPAQUE_ID_PATTERN = /^[A-Za-z0-9_-]{1,100}$/u;
|
|
3616
3669
|
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) {
|
|
3670
|
+
function parseTrimmedMatchingString(value, pattern) {
|
|
3621
3671
|
if (typeof value !== "string") return null;
|
|
3622
3672
|
const trimmed = value.trim();
|
|
3623
|
-
return trimmed
|
|
3673
|
+
return pattern.test(trimmed) ? trimmed : null;
|
|
3674
|
+
}
|
|
3675
|
+
function parsePositiveInteger(value) {
|
|
3676
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value > 0 ? value : null;
|
|
3624
3677
|
}
|
|
3625
3678
|
function parseNewsletterListId(value) {
|
|
3626
|
-
|
|
3627
|
-
return trimmed !== null && UUID_PATTERN.test(trimmed) ? trimmed : null;
|
|
3679
|
+
return parseTrimmedMatchingString(value, UUID_PATTERN);
|
|
3628
3680
|
}
|
|
3629
3681
|
function parseMailchimpConnectionId(value) {
|
|
3630
|
-
|
|
3631
|
-
|
|
3682
|
+
return parseTrimmedMatchingString(value, UUID_PATTERN);
|
|
3683
|
+
}
|
|
3684
|
+
function parseMailchimpAccountId(value) {
|
|
3685
|
+
return parseTrimmedMatchingString(value, OPAQUE_ID_PATTERN);
|
|
3632
3686
|
}
|
|
3633
3687
|
function parseMailchimpAudienceId(value) {
|
|
3634
|
-
|
|
3635
|
-
|
|
3688
|
+
return parseTrimmedMatchingString(value, OPAQUE_ID_PATTERN);
|
|
3689
|
+
}
|
|
3690
|
+
function parseMailchimpInterestId(value) {
|
|
3691
|
+
return parseTrimmedMatchingString(value, OPAQUE_ID_PATTERN);
|
|
3636
3692
|
}
|
|
3637
3693
|
function parseMailchimpTagName(value) {
|
|
3638
|
-
|
|
3639
|
-
|
|
3640
|
-
|
|
3641
|
-
|
|
3642
|
-
|
|
3643
|
-
|
|
3644
|
-
|
|
3645
|
-
|
|
3646
|
-
|
|
3647
|
-
|
|
3648
|
-
|
|
3649
|
-
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
|
|
3653
|
-
|
|
3694
|
+
if (typeof value !== "string") return null;
|
|
3695
|
+
const trimmed = value.trim();
|
|
3696
|
+
return trimmed.length > 0 && trimmed.length <= 100 && !CONTROL_CHARACTER_PATTERN.test(trimmed) ? trimmed : null;
|
|
3697
|
+
}
|
|
3698
|
+
function parseBrevoConnectionId(value) {
|
|
3699
|
+
return parseTrimmedMatchingString(value, UUID_PATTERN);
|
|
3700
|
+
}
|
|
3701
|
+
function parseBrevoAccountId(value) {
|
|
3702
|
+
return parseTrimmedMatchingString(value, OPAQUE_ID_PATTERN);
|
|
3703
|
+
}
|
|
3704
|
+
function parseBrevoListId(value) {
|
|
3705
|
+
return parsePositiveInteger(value);
|
|
3706
|
+
}
|
|
3707
|
+
function parseBrevoConfirmationTemplateId(value) {
|
|
3708
|
+
return parsePositiveInteger(value);
|
|
3709
|
+
}
|
|
3710
|
+
|
|
3711
|
+
//#endregion
|
|
3712
|
+
//#region ../core/src/mailing-list-targeting-parser.ts
|
|
3713
|
+
function parseMailingListPlacementTargeting(value) {
|
|
3714
|
+
if (!isRecord$6(value)) return targetingError("shape");
|
|
3715
|
+
if (value.mode === "default") return ok({ mode: "default" });
|
|
3716
|
+
if (value.mode !== "custom") return targetingError("mode");
|
|
3717
|
+
if (!isRecord$6(value.selection)) return targetingError("selection");
|
|
3718
|
+
switch (value.provider) {
|
|
3719
|
+
case "native": return parseNativeTargeting(value.selection);
|
|
3720
|
+
case "brevo": return parseBrevoTargeting(value.selection);
|
|
3721
|
+
case "mailchimp": return parseMailchimpTargeting(value, value.selection);
|
|
3722
|
+
default: return targetingError("provider");
|
|
3723
|
+
}
|
|
3724
|
+
}
|
|
3725
|
+
function parseMailingListVisitorSelection(value) {
|
|
3726
|
+
if (!isRecord$6(value)) return visitorSelectionError("shape");
|
|
3727
|
+
switch (value.provider) {
|
|
3728
|
+
case "native": {
|
|
3729
|
+
const topicIds = parseVisitorIds(value.topicIds, parseNewsletterListId);
|
|
3730
|
+
return topicIds === null ? visitorSelectionError("targets") : ok({
|
|
3731
|
+
provider: "native",
|
|
3732
|
+
topicIds
|
|
3654
3733
|
});
|
|
3655
3734
|
}
|
|
3656
|
-
case "
|
|
3657
|
-
const
|
|
3658
|
-
|
|
3659
|
-
|
|
3735
|
+
case "brevo": {
|
|
3736
|
+
const listIds = parseVisitorIds(value.listIds, parseBrevoListId);
|
|
3737
|
+
return listIds === null ? visitorSelectionError("targets") : ok({
|
|
3738
|
+
provider: "brevo",
|
|
3739
|
+
listIds
|
|
3740
|
+
});
|
|
3741
|
+
}
|
|
3742
|
+
case "mailchimp": {
|
|
3743
|
+
const interestIds = parseVisitorIds(value.interestIds, parseMailchimpInterestId);
|
|
3744
|
+
return interestIds === null ? visitorSelectionError("targets") : ok({
|
|
3745
|
+
provider: "mailchimp",
|
|
3746
|
+
interestIds
|
|
3747
|
+
});
|
|
3748
|
+
}
|
|
3749
|
+
default: return visitorSelectionError("provider");
|
|
3750
|
+
}
|
|
3751
|
+
}
|
|
3752
|
+
function parseNativeTargeting(selection) {
|
|
3753
|
+
if (selection.tag === "fixed") {
|
|
3754
|
+
const topicIds = parseNonEmptyUniqueIds(selection.topicIds, parseNewsletterListId);
|
|
3755
|
+
return topicIds.ok ? ok({
|
|
3756
|
+
mode: "custom",
|
|
3757
|
+
provider: "native",
|
|
3758
|
+
selection: {
|
|
3759
|
+
tag: "fixed",
|
|
3760
|
+
topicIds: topicIds.value
|
|
3660
3761
|
}
|
|
3661
|
-
|
|
3662
|
-
|
|
3663
|
-
|
|
3762
|
+
}) : topicIds;
|
|
3763
|
+
}
|
|
3764
|
+
if (selection.tag === "visitor_choice") {
|
|
3765
|
+
const offeredTopicIds = parseNonEmptyUniqueIds(selection.offeredTopicIds, parseNewsletterListId);
|
|
3766
|
+
return offeredTopicIds.ok ? ok({
|
|
3767
|
+
mode: "custom",
|
|
3768
|
+
provider: "native",
|
|
3769
|
+
selection: {
|
|
3770
|
+
tag: "visitor_choice",
|
|
3771
|
+
offeredTopicIds: offeredTopicIds.value
|
|
3664
3772
|
}
|
|
3665
|
-
|
|
3666
|
-
|
|
3667
|
-
|
|
3773
|
+
}) : offeredTopicIds;
|
|
3774
|
+
}
|
|
3775
|
+
return targetingError("selection");
|
|
3776
|
+
}
|
|
3777
|
+
function parseBrevoTargeting(selection) {
|
|
3778
|
+
if (selection.tag === "fixed") {
|
|
3779
|
+
const listIds = parseNonEmptyUniqueIds(selection.listIds, parseBrevoListId);
|
|
3780
|
+
return listIds.ok ? ok({
|
|
3781
|
+
mode: "custom",
|
|
3782
|
+
provider: "brevo",
|
|
3783
|
+
selection: {
|
|
3784
|
+
tag: "fixed",
|
|
3785
|
+
listIds: listIds.value
|
|
3668
3786
|
}
|
|
3669
|
-
|
|
3670
|
-
|
|
3671
|
-
|
|
3672
|
-
|
|
3673
|
-
|
|
3787
|
+
}) : listIds;
|
|
3788
|
+
}
|
|
3789
|
+
if (selection.tag === "visitor_choice") {
|
|
3790
|
+
const offeredListIds = parseNonEmptyUniqueIds(selection.offeredListIds, parseBrevoListId);
|
|
3791
|
+
return offeredListIds.ok ? ok({
|
|
3792
|
+
mode: "custom",
|
|
3793
|
+
provider: "brevo",
|
|
3794
|
+
selection: {
|
|
3795
|
+
tag: "visitor_choice",
|
|
3796
|
+
offeredListIds: offeredListIds.value
|
|
3674
3797
|
}
|
|
3675
|
-
|
|
3676
|
-
|
|
3677
|
-
|
|
3678
|
-
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
|
|
3682
|
-
|
|
3683
|
-
|
|
3684
|
-
|
|
3685
|
-
|
|
3798
|
+
}) : offeredListIds;
|
|
3799
|
+
}
|
|
3800
|
+
return targetingError("selection");
|
|
3801
|
+
}
|
|
3802
|
+
function parseMailchimpTargeting(value, selection) {
|
|
3803
|
+
const audienceId = parseMailchimpAudienceId(value.audienceId);
|
|
3804
|
+
if (audienceId === null) return targetingError("audienceId");
|
|
3805
|
+
if (selection.tag === "fixed") {
|
|
3806
|
+
const interestIds = parseUniqueIds(selection.interestIds, parseMailchimpInterestId);
|
|
3807
|
+
return interestIds.ok ? ok({
|
|
3808
|
+
mode: "custom",
|
|
3809
|
+
provider: "mailchimp",
|
|
3810
|
+
audienceId,
|
|
3811
|
+
selection: {
|
|
3812
|
+
tag: "fixed",
|
|
3813
|
+
interestIds: interestIds.value
|
|
3814
|
+
}
|
|
3815
|
+
}) : interestIds;
|
|
3816
|
+
}
|
|
3817
|
+
if (selection.tag === "visitor_choice") {
|
|
3818
|
+
const offeredInterestIds = parseNonEmptyUniqueIds(selection.offeredInterestIds, parseMailchimpInterestId);
|
|
3819
|
+
return offeredInterestIds.ok ? ok({
|
|
3820
|
+
mode: "custom",
|
|
3821
|
+
provider: "mailchimp",
|
|
3822
|
+
audienceId,
|
|
3823
|
+
selection: {
|
|
3824
|
+
tag: "visitor_choice",
|
|
3825
|
+
offeredInterestIds: offeredInterestIds.value
|
|
3826
|
+
}
|
|
3827
|
+
}) : offeredInterestIds;
|
|
3828
|
+
}
|
|
3829
|
+
return targetingError("selection");
|
|
3830
|
+
}
|
|
3831
|
+
function parseNonEmptyUniqueIds(value, parseId) {
|
|
3832
|
+
const parsed = parseUniqueIds(value, parseId);
|
|
3833
|
+
if (!parsed.ok) return parsed;
|
|
3834
|
+
const [first, ...rest] = parsed.value;
|
|
3835
|
+
return first === undefined ? targetingError("targets") : ok([first, ...rest]);
|
|
3836
|
+
}
|
|
3837
|
+
function parseUniqueIds(value, parseId) {
|
|
3838
|
+
if (!Array.isArray(value)) return targetingError("targets");
|
|
3839
|
+
const parsed = [];
|
|
3840
|
+
for (const item of value) {
|
|
3841
|
+
const id = parseId(item);
|
|
3842
|
+
if (id === null) return targetingError("targets");
|
|
3843
|
+
if (parsed.includes(id)) return targetingError("duplicate_target");
|
|
3844
|
+
parsed.push(id);
|
|
3686
3845
|
}
|
|
3846
|
+
return ok(parsed);
|
|
3847
|
+
}
|
|
3848
|
+
function parseVisitorIds(value, parseId) {
|
|
3849
|
+
if (!Array.isArray(value) || value.length === 0) return null;
|
|
3850
|
+
const parsed = [];
|
|
3851
|
+
for (const item of value) {
|
|
3852
|
+
const id = parseId(item);
|
|
3853
|
+
if (id === null) return null;
|
|
3854
|
+
if (parsed.includes(id)) return null;
|
|
3855
|
+
parsed.push(id);
|
|
3856
|
+
}
|
|
3857
|
+
return parsed;
|
|
3858
|
+
}
|
|
3859
|
+
function isRecord$6(value) {
|
|
3860
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3861
|
+
}
|
|
3862
|
+
function targetingError(field) {
|
|
3863
|
+
return err({
|
|
3864
|
+
tag: "invalid_mailing_list_targeting",
|
|
3865
|
+
field
|
|
3866
|
+
});
|
|
3867
|
+
}
|
|
3868
|
+
function visitorSelectionError(field) {
|
|
3869
|
+
return err({
|
|
3870
|
+
tag: "invalid_mailing_list_visitor_selection",
|
|
3871
|
+
field
|
|
3872
|
+
});
|
|
3687
3873
|
}
|
|
3688
3874
|
|
|
3689
3875
|
//#endregion
|
|
3690
3876
|
//#region ../core/src/footer-engagement.ts
|
|
3691
|
-
function isRecord$
|
|
3877
|
+
function isRecord$5(value) {
|
|
3692
3878
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3693
3879
|
}
|
|
3694
3880
|
function invalid(path, message) {
|
|
@@ -3722,7 +3908,7 @@ function parseEngagementBase(value, base, path) {
|
|
|
3722
3908
|
}
|
|
3723
3909
|
const treatment = parseTreatment(value.treatment, `${path}.treatment`);
|
|
3724
3910
|
if (!treatment.ok) return treatment;
|
|
3725
|
-
if (!isRecord$
|
|
3911
|
+
if (!isRecord$5(value.source)) {
|
|
3726
3912
|
return err(invalid(`${path}.source`, "Footer engagement source is invalid."));
|
|
3727
3913
|
}
|
|
3728
3914
|
const intro = parseBoundedText(value.source.intro, `${path}.source.intro`, {
|
|
@@ -3751,36 +3937,17 @@ function parseStandardContact(source, base, path) {
|
|
|
3751
3937
|
}
|
|
3752
3938
|
function parseMailingList(source, base, path) {
|
|
3753
3939
|
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."));
|
|
3940
|
+
const targeting = parseMailingListPlacementTargeting(source.targeting);
|
|
3941
|
+
if (!targeting.ok) {
|
|
3942
|
+
return err(invalid(`${path}.targeting`, "Footer mailing-list targeting is invalid."));
|
|
3772
3943
|
}
|
|
3773
3944
|
return ok({
|
|
3774
3945
|
...section,
|
|
3775
3946
|
kind: "engagement",
|
|
3776
3947
|
source: {
|
|
3777
3948
|
kind: "mailing-list",
|
|
3778
|
-
|
|
3779
|
-
intro
|
|
3780
|
-
buttonLabel: buttonLabel.value,
|
|
3781
|
-
successMessage: successMessage.value,
|
|
3782
|
-
privacyNote: privacyNote.value,
|
|
3783
|
-
fieldPreset: "emailOnly"
|
|
3949
|
+
targeting: targeting.value,
|
|
3950
|
+
intro
|
|
3784
3951
|
}
|
|
3785
3952
|
});
|
|
3786
3953
|
}
|
|
@@ -3788,7 +3955,7 @@ function parseFooterEngagementSectionValue(value, sectionBase, path) {
|
|
|
3788
3955
|
const base = parseEngagementBase(value, sectionBase, path);
|
|
3789
3956
|
if (!base.ok) return base;
|
|
3790
3957
|
const source = value.source;
|
|
3791
|
-
if (!isRecord$
|
|
3958
|
+
if (!isRecord$5(source)) {
|
|
3792
3959
|
return err(invalid(`${path}.source`, "Footer engagement source is invalid."));
|
|
3793
3960
|
}
|
|
3794
3961
|
switch (source.kind) {
|
|
@@ -3903,7 +4070,7 @@ function unsafeAsFooterModuleId(value) {
|
|
|
3903
4070
|
function parseFooterModuleId(value) {
|
|
3904
4071
|
return parseSectionId(value, "sectionId");
|
|
3905
4072
|
}
|
|
3906
|
-
function isRecord$
|
|
4073
|
+
function isRecord$4(value) {
|
|
3907
4074
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3908
4075
|
}
|
|
3909
4076
|
function isRichText(value) {
|
|
@@ -3933,7 +4100,7 @@ function parseHeading(value, path) {
|
|
|
3933
4100
|
}
|
|
3934
4101
|
function parseFooterSection(value, index) {
|
|
3935
4102
|
const path = `sections.${index}`;
|
|
3936
|
-
if (!isRecord$
|
|
4103
|
+
if (!isRecord$4(value)) {
|
|
3937
4104
|
return err({
|
|
3938
4105
|
code: "invalid_section",
|
|
3939
4106
|
path,
|
|
@@ -3968,7 +4135,7 @@ function parseFooterSection(value, index) {
|
|
|
3968
4135
|
}
|
|
3969
4136
|
break;
|
|
3970
4137
|
case "navigation":
|
|
3971
|
-
if (isRecord$
|
|
4138
|
+
if (isRecord$4(value.source) && value.source.kind === "menu-role" && value.source.role === "main") {
|
|
3972
4139
|
return ok({
|
|
3973
4140
|
...base,
|
|
3974
4141
|
kind: "navigation",
|
|
@@ -3981,7 +4148,7 @@ function parseFooterSection(value, index) {
|
|
|
3981
4148
|
}
|
|
3982
4149
|
break;
|
|
3983
4150
|
case "legal-navigation":
|
|
3984
|
-
if (isRecord$
|
|
4151
|
+
if (isRecord$4(value.source) && value.source.kind === "menu-role" && value.source.role === "legal-policy") {
|
|
3985
4152
|
return ok({
|
|
3986
4153
|
...base,
|
|
3987
4154
|
kind: "legal-navigation",
|
|
@@ -3994,7 +4161,7 @@ function parseFooterSection(value, index) {
|
|
|
3994
4161
|
}
|
|
3995
4162
|
break;
|
|
3996
4163
|
case "business-address":
|
|
3997
|
-
if (isRecord$
|
|
4164
|
+
if (isRecord$4(value.source) && value.source.kind === "business-address") {
|
|
3998
4165
|
return ok({
|
|
3999
4166
|
...base,
|
|
4000
4167
|
kind: "business-address",
|
|
@@ -4006,7 +4173,7 @@ function parseFooterSection(value, index) {
|
|
|
4006
4173
|
case "contact":
|
|
4007
4174
|
case "opening-hours":
|
|
4008
4175
|
case "social-links":
|
|
4009
|
-
if (isRecord$
|
|
4176
|
+
if (isRecord$4(value.source) && value.source.kind === "public-profile") {
|
|
4010
4177
|
return ok({
|
|
4011
4178
|
...base,
|
|
4012
4179
|
kind: value.kind,
|
|
@@ -4058,7 +4225,7 @@ function validateFooterComposition(composition) {
|
|
|
4058
4225
|
return ok(composition);
|
|
4059
4226
|
}
|
|
4060
4227
|
function parseFooterCompositionV1(value) {
|
|
4061
|
-
if (!isRecord$
|
|
4228
|
+
if (!isRecord$4(value)) {
|
|
4062
4229
|
return err({
|
|
4063
4230
|
code: "invalid_shape",
|
|
4064
4231
|
path: "",
|
|
@@ -4091,7 +4258,7 @@ function parseFooterCompositionV1(value) {
|
|
|
4091
4258
|
});
|
|
4092
4259
|
}
|
|
4093
4260
|
function parseLegacyPlacementSection(value, index, selectedIds) {
|
|
4094
|
-
if (!isRecord$
|
|
4261
|
+
if (!isRecord$4(value)) {
|
|
4095
4262
|
return err({
|
|
4096
4263
|
code: "invalid_section",
|
|
4097
4264
|
path: `modules.${index}`,
|
|
@@ -4099,7 +4266,7 @@ function parseLegacyPlacementSection(value, index, selectedIds) {
|
|
|
4099
4266
|
});
|
|
4100
4267
|
}
|
|
4101
4268
|
const selected = typeof value.id === "string" && selectedIds.has(value.id);
|
|
4102
|
-
const source = isRecord$
|
|
4269
|
+
const source = isRecord$4(value.source) ? value.source : null;
|
|
4103
4270
|
const mapped = value.kind === "navigation" && source?.kind === "menu-role" && source.role === "footer" ? {
|
|
4104
4271
|
...value,
|
|
4105
4272
|
source: {
|
|
@@ -4118,7 +4285,7 @@ function parseLegacyPlacementSection(value, index, selectedIds) {
|
|
|
4118
4285
|
* It is intentionally not called by the runtime parser.
|
|
4119
4286
|
*/
|
|
4120
4287
|
function upgradePlacementFooterCompositionV1(value) {
|
|
4121
|
-
if (!isRecord$
|
|
4288
|
+
if (!isRecord$4(value) || value.schemaVersion !== 1 || !Array.isArray(value.modules) || !Array.isArray(value.placements)) {
|
|
4122
4289
|
return err({
|
|
4123
4290
|
code: "invalid_shape",
|
|
4124
4291
|
path: "",
|
|
@@ -4127,7 +4294,7 @@ function upgradePlacementFooterCompositionV1(value) {
|
|
|
4127
4294
|
}
|
|
4128
4295
|
const selectedIds = new Set();
|
|
4129
4296
|
for (const [index, placement] of value.placements.entries()) {
|
|
4130
|
-
if (!isRecord$
|
|
4297
|
+
if (!isRecord$4(placement) || typeof placement.moduleId !== "string") {
|
|
4131
4298
|
return err({
|
|
4132
4299
|
code: "invalid_shape",
|
|
4133
4300
|
path: `placements.${index}`,
|
|
@@ -4230,8 +4397,8 @@ function repairTargetFor(section) {
|
|
|
4230
4397
|
};
|
|
4231
4398
|
}
|
|
4232
4399
|
}
|
|
4233
|
-
function resolveFooterSections(composition, availability) {
|
|
4234
|
-
return composition.sections.filter((section) => section.selected).map((section) => isSectionRenderable(section, availability) ? {
|
|
4400
|
+
function resolveFooterSections(composition, availability$1) {
|
|
4401
|
+
return composition.sections.filter((section) => section.selected).map((section) => isSectionRenderable(section, availability$1) ? {
|
|
4235
4402
|
kind: "renderable",
|
|
4236
4403
|
section
|
|
4237
4404
|
} : {
|
|
@@ -4240,16 +4407,16 @@ function resolveFooterSections(composition, availability) {
|
|
|
4240
4407
|
repairTarget: repairTargetFor(section)
|
|
4241
4408
|
});
|
|
4242
4409
|
}
|
|
4243
|
-
function isSectionRenderable(section, availability) {
|
|
4410
|
+
function isSectionRenderable(section, availability$1) {
|
|
4244
4411
|
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;
|
|
4412
|
+
case "brand": return section.showLogo && availability$1.hasLogo || section.showTitle;
|
|
4413
|
+
case "navigation": return availability$1.hasMainNavigation;
|
|
4414
|
+
case "legal-navigation": return availability$1.hasLegalPolicyNavigation;
|
|
4415
|
+
case "business-address": return availability$1.hasBusinessAddress;
|
|
4416
|
+
case "contact": return availability$1.hasContact;
|
|
4417
|
+
case "opening-hours": return availability$1.hasOpeningHours;
|
|
4418
|
+
case "social-links": return availability$1.hasSocialLinks;
|
|
4419
|
+
case "engagement": return availability$1.hasEngagementSource;
|
|
4253
4420
|
case "supporting-text":
|
|
4254
4421
|
case "legal": return section.content !== null;
|
|
4255
4422
|
}
|
|
@@ -4342,7 +4509,7 @@ const defaultSections = (legacy, options) => {
|
|
|
4342
4509
|
];
|
|
4343
4510
|
};
|
|
4344
4511
|
function normalizeLegacyFooterContentToV1(value, options = {}) {
|
|
4345
|
-
if (!isRecord$
|
|
4512
|
+
if (!isRecord$4(value)) {
|
|
4346
4513
|
return err({
|
|
4347
4514
|
code: "invalid_shape",
|
|
4348
4515
|
path: "",
|
|
@@ -4363,6 +4530,773 @@ function normalizeFooterNavigationLayout(value) {
|
|
|
4363
4530
|
return value === "stack" ? "stack" : defaultFooterNavigationLayout;
|
|
4364
4531
|
}
|
|
4365
4532
|
|
|
4533
|
+
//#endregion
|
|
4534
|
+
//#region ../core/src/mailing-list-setup.ts
|
|
4535
|
+
function isRecord$3(value) {
|
|
4536
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
4537
|
+
}
|
|
4538
|
+
/** The name shown to people for each provider; the native one is the product brand. */
|
|
4539
|
+
function mailingListProviderName(provider) {
|
|
4540
|
+
switch (provider) {
|
|
4541
|
+
case "native": return "Macadamia";
|
|
4542
|
+
case "mailchimp": return "Mailchimp";
|
|
4543
|
+
case "brevo": return "Brevo";
|
|
4544
|
+
}
|
|
4545
|
+
}
|
|
4546
|
+
const DEFAULT_MAILING_LIST_SUCCESS_MESSAGE = "Thanks — you're on the list.";
|
|
4547
|
+
/**
|
|
4548
|
+
* Seeded into a new setup so every signup form carries a preferences/unsubscribe
|
|
4549
|
+
* reassurance out of the box. Administrators can edit or clear it.
|
|
4550
|
+
*/
|
|
4551
|
+
const DEFAULT_MAILING_LIST_PRIVACY_NOTE = "Change your preferences or unsubscribe at any time.";
|
|
4552
|
+
function planMailingListFieldCompatibility(input) {
|
|
4553
|
+
const collectedFields = resolveCollectedGlobalFields(input.form);
|
|
4554
|
+
const requiredFields = resolveRequiredGlobalFields(input.form.fields);
|
|
4555
|
+
const issues = [];
|
|
4556
|
+
for (const destination of input.destinations) {
|
|
4557
|
+
for (const field of destination.requiredFields) {
|
|
4558
|
+
if (!collectedFields.includes(field)) {
|
|
4559
|
+
issues.push({
|
|
4560
|
+
tag: "destination_requires_uncollected_field",
|
|
4561
|
+
destinationKey: destination.destinationKey,
|
|
4562
|
+
field
|
|
4563
|
+
});
|
|
4564
|
+
} else if (!requiredFields.includes(field)) {
|
|
4565
|
+
issues.push({
|
|
4566
|
+
tag: "destination_requires_site_required_field",
|
|
4567
|
+
destinationKey: destination.destinationKey,
|
|
4568
|
+
field
|
|
4569
|
+
});
|
|
4570
|
+
}
|
|
4571
|
+
}
|
|
4572
|
+
for (const field of collectedFields) {
|
|
4573
|
+
if (!destination.acceptedFields.includes(field)) {
|
|
4574
|
+
issues.push({
|
|
4575
|
+
tag: requiredFields.includes(field) ? "destination_rejects_required_site_field" : "destination_rejects_collected_site_field",
|
|
4576
|
+
destinationKey: destination.destinationKey,
|
|
4577
|
+
field
|
|
4578
|
+
});
|
|
4579
|
+
}
|
|
4580
|
+
}
|
|
4581
|
+
}
|
|
4582
|
+
const [first, ...rest] = issues;
|
|
4583
|
+
return first === undefined ? { tag: "compatible" } : {
|
|
4584
|
+
tag: "blocked",
|
|
4585
|
+
issues: [first, ...rest]
|
|
4586
|
+
};
|
|
4587
|
+
}
|
|
4588
|
+
function resolveCollectedGlobalFields(form) {
|
|
4589
|
+
const phone = form.includeOptionalPhone ? ["phone"] : [];
|
|
4590
|
+
switch (form.fields.preset) {
|
|
4591
|
+
case "emailOnly": return phone;
|
|
4592
|
+
case "emailName": return ["name", ...phone];
|
|
4593
|
+
case "emailFirstLast": return [
|
|
4594
|
+
"first_name",
|
|
4595
|
+
"last_name",
|
|
4596
|
+
...phone
|
|
4597
|
+
];
|
|
4598
|
+
case "emailNameCompany": return [
|
|
4599
|
+
"name",
|
|
4600
|
+
"company",
|
|
4601
|
+
...phone
|
|
4602
|
+
];
|
|
4603
|
+
}
|
|
4604
|
+
}
|
|
4605
|
+
function resolveRequiredGlobalFields(fields) {
|
|
4606
|
+
switch (fields.preset) {
|
|
4607
|
+
case "emailOnly": return [];
|
|
4608
|
+
case "emailName": return fields.name === "required" ? ["name"] : [];
|
|
4609
|
+
case "emailFirstLast": return [...fields.firstName === "required" ? ["first_name"] : [], ...fields.lastName === "required" ? ["last_name"] : []];
|
|
4610
|
+
case "emailNameCompany": return [...fields.name === "required" ? ["name"] : [], ...fields.company === "required" ? ["company"] : []];
|
|
4611
|
+
}
|
|
4612
|
+
}
|
|
4613
|
+
function planMailingListSetupSwitch(input) {
|
|
4614
|
+
if (input.previousScope === null) {
|
|
4615
|
+
return {
|
|
4616
|
+
tag: "activate",
|
|
4617
|
+
affectedPlacementCount: 0
|
|
4618
|
+
};
|
|
4619
|
+
}
|
|
4620
|
+
if (sameMailingListProviderScope(input.previousScope, input.nextScope)) {
|
|
4621
|
+
return {
|
|
4622
|
+
tag: "update_same_scope",
|
|
4623
|
+
affectedPlacementCount: input.defaultChanged ? countDefaultMailingListPlacements(input.placementModes) : 0
|
|
4624
|
+
};
|
|
4625
|
+
}
|
|
4626
|
+
return {
|
|
4627
|
+
tag: "replace_scope",
|
|
4628
|
+
affectedPlacementCount: input.placementModes.length
|
|
4629
|
+
};
|
|
4630
|
+
}
|
|
4631
|
+
function mailingListProviderScopeFromConfigured(provider) {
|
|
4632
|
+
switch (provider.provider) {
|
|
4633
|
+
case "native": return { provider: "native" };
|
|
4634
|
+
case "brevo": return {
|
|
4635
|
+
provider: "brevo",
|
|
4636
|
+
accountId: provider.accountId
|
|
4637
|
+
};
|
|
4638
|
+
case "mailchimp": return {
|
|
4639
|
+
provider: "mailchimp",
|
|
4640
|
+
accountId: provider.accountId
|
|
4641
|
+
};
|
|
4642
|
+
}
|
|
4643
|
+
}
|
|
4644
|
+
function parseMailingListProviderScope(value) {
|
|
4645
|
+
if (!isRecord$3(value)) return err("invalid_mailing_list_provider_scope");
|
|
4646
|
+
if (value.provider === "native") return ok({ provider: "native" });
|
|
4647
|
+
if (value.provider === "brevo") {
|
|
4648
|
+
const accountId = parseBrevoAccountId(value.accountId);
|
|
4649
|
+
return accountId !== null ? ok({
|
|
4650
|
+
provider: "brevo",
|
|
4651
|
+
accountId
|
|
4652
|
+
}) : err("invalid_mailing_list_provider_scope");
|
|
4653
|
+
}
|
|
4654
|
+
if (value.provider === "mailchimp") {
|
|
4655
|
+
const accountId = parseMailchimpAccountId(value.accountId);
|
|
4656
|
+
return accountId !== null ? ok({
|
|
4657
|
+
provider: "mailchimp",
|
|
4658
|
+
accountId
|
|
4659
|
+
}) : err("invalid_mailing_list_provider_scope");
|
|
4660
|
+
}
|
|
4661
|
+
return err("invalid_mailing_list_provider_scope");
|
|
4662
|
+
}
|
|
4663
|
+
function sameMailingListProviderScope(previous, next) {
|
|
4664
|
+
if (previous.provider !== next.provider) return false;
|
|
4665
|
+
switch (previous.provider) {
|
|
4666
|
+
case "native": return true;
|
|
4667
|
+
case "mailchimp": return next.provider === "mailchimp" && previous.accountId === next.accountId;
|
|
4668
|
+
case "brevo": return next.provider === "brevo" && previous.accountId === next.accountId;
|
|
4669
|
+
}
|
|
4670
|
+
}
|
|
4671
|
+
function countDefaultMailingListPlacements(placementModes) {
|
|
4672
|
+
return placementModes.filter((mode) => mode === "default").length;
|
|
4673
|
+
}
|
|
4674
|
+
|
|
4675
|
+
//#endregion
|
|
4676
|
+
//#region ../core/src/mailing-list-setup-parser.ts
|
|
4677
|
+
function parseMailingListGlobalForm(value) {
|
|
4678
|
+
if (!isRecord$2(value)) return formError("shape");
|
|
4679
|
+
const fields = parseGlobalFields(value.fields);
|
|
4680
|
+
if (fields === null) return formError("fields");
|
|
4681
|
+
if (typeof value.includeOptionalPhone !== "boolean") {
|
|
4682
|
+
return formError("includeOptionalPhone");
|
|
4683
|
+
}
|
|
4684
|
+
const buttonLabel = parseRequiredString(value.buttonLabel);
|
|
4685
|
+
if (buttonLabel === null) return formError("buttonLabel");
|
|
4686
|
+
const successMessage = parseRequiredString(value.successMessage);
|
|
4687
|
+
if (successMessage === null) return formError("successMessage");
|
|
4688
|
+
const privacyNote = parseOptionalString(value.privacyNote);
|
|
4689
|
+
if (privacyNote === undefined) return formError("privacyNote");
|
|
4690
|
+
return ok({
|
|
4691
|
+
fields,
|
|
4692
|
+
includeOptionalPhone: value.includeOptionalPhone,
|
|
4693
|
+
buttonLabel,
|
|
4694
|
+
successMessage,
|
|
4695
|
+
privacyNote
|
|
4696
|
+
});
|
|
4697
|
+
}
|
|
4698
|
+
function parseMailingListSiteSetup(value) {
|
|
4699
|
+
if (!isRecord$2(value)) return setupError("shape");
|
|
4700
|
+
const siteId = parseSiteId(value.siteId);
|
|
4701
|
+
if (!siteId.ok) return setupError("siteId");
|
|
4702
|
+
if (value.tag === "not_configured") {
|
|
4703
|
+
return ok({
|
|
4704
|
+
tag: "not_configured",
|
|
4705
|
+
siteId: siteId.value
|
|
4706
|
+
});
|
|
4707
|
+
}
|
|
4708
|
+
if (value.tag !== "configured") return setupError("tag");
|
|
4709
|
+
const revision = parseMailingListSetupRevision(value.revision);
|
|
4710
|
+
if (revision === null) return setupError("revision");
|
|
4711
|
+
const form = parseMailingListGlobalForm(value.form);
|
|
4712
|
+
if (!form.ok) return setupError("form");
|
|
4713
|
+
const provider = parseConfiguredMailingListProvider(value.provider);
|
|
4714
|
+
if (!provider.ok) return provider;
|
|
4715
|
+
return ok({
|
|
4716
|
+
tag: "configured",
|
|
4717
|
+
siteId: siteId.value,
|
|
4718
|
+
revision,
|
|
4719
|
+
form: form.value,
|
|
4720
|
+
provider: provider.value
|
|
4721
|
+
});
|
|
4722
|
+
}
|
|
4723
|
+
function parseConfiguredMailingListProvider(value) {
|
|
4724
|
+
if (!isRecord$2(value) || typeof value.provider !== "string") {
|
|
4725
|
+
return setupError("provider");
|
|
4726
|
+
}
|
|
4727
|
+
switch (value.provider) {
|
|
4728
|
+
case "native": {
|
|
4729
|
+
const defaultTopicId = parseNewsletterListId(value.defaultTopicId);
|
|
4730
|
+
if (defaultTopicId === null) return setupError("defaultTargetId");
|
|
4731
|
+
const confirmation = parseToggleConfirmation(value.confirmation);
|
|
4732
|
+
return confirmation === null ? setupError("confirmation") : ok({
|
|
4733
|
+
provider: "native",
|
|
4734
|
+
defaultTopicId,
|
|
4735
|
+
confirmation
|
|
4736
|
+
});
|
|
4737
|
+
}
|
|
4738
|
+
case "mailchimp": {
|
|
4739
|
+
const connectionId = parseMailchimpConnectionId(value.connectionId);
|
|
4740
|
+
if (connectionId === null) return setupError("connectionId");
|
|
4741
|
+
const accountId = parseMailchimpAccountId(value.accountId);
|
|
4742
|
+
if (accountId === null) return setupError("accountId");
|
|
4743
|
+
const defaultAudienceId = parseMailchimpAudienceId(value.defaultAudienceId);
|
|
4744
|
+
if (defaultAudienceId === null) return setupError("defaultTargetId");
|
|
4745
|
+
const confirmation = parseToggleConfirmation(value.confirmation);
|
|
4746
|
+
return confirmation === null ? setupError("confirmation") : ok({
|
|
4747
|
+
provider: "mailchimp",
|
|
4748
|
+
connectionId,
|
|
4749
|
+
accountId,
|
|
4750
|
+
defaultAudienceId,
|
|
4751
|
+
confirmation
|
|
4752
|
+
});
|
|
4753
|
+
}
|
|
4754
|
+
case "brevo": {
|
|
4755
|
+
const connectionId = parseBrevoConnectionId(value.connectionId);
|
|
4756
|
+
if (connectionId === null) return setupError("connectionId");
|
|
4757
|
+
const accountId = parseBrevoAccountId(value.accountId);
|
|
4758
|
+
if (accountId === null) return setupError("accountId");
|
|
4759
|
+
const defaultListId = parseBrevoListId(value.defaultListId);
|
|
4760
|
+
if (defaultListId === null) return setupError("defaultTargetId");
|
|
4761
|
+
const confirmation = parseBrevoConfirmation(value.confirmation);
|
|
4762
|
+
return confirmation === null ? setupError("confirmation") : ok({
|
|
4763
|
+
provider: "brevo",
|
|
4764
|
+
connectionId,
|
|
4765
|
+
accountId,
|
|
4766
|
+
defaultListId,
|
|
4767
|
+
confirmation
|
|
4768
|
+
});
|
|
4769
|
+
}
|
|
4770
|
+
default: return setupError("provider");
|
|
4771
|
+
}
|
|
4772
|
+
}
|
|
4773
|
+
function parseGlobalFields(value) {
|
|
4774
|
+
if (!isRecord$2(value) || typeof value.preset !== "string") return null;
|
|
4775
|
+
switch (value.preset) {
|
|
4776
|
+
case "emailOnly": return { preset: "emailOnly" };
|
|
4777
|
+
case "emailName": return isRequirement(value.name) ? {
|
|
4778
|
+
preset: "emailName",
|
|
4779
|
+
name: value.name
|
|
4780
|
+
} : null;
|
|
4781
|
+
case "emailFirstLast": return isRequirement(value.firstName) && isRequirement(value.lastName) ? {
|
|
4782
|
+
preset: "emailFirstLast",
|
|
4783
|
+
firstName: value.firstName,
|
|
4784
|
+
lastName: value.lastName
|
|
4785
|
+
} : null;
|
|
4786
|
+
case "emailNameCompany": return isRequirement(value.name) && isRequirement(value.company) ? {
|
|
4787
|
+
preset: "emailNameCompany",
|
|
4788
|
+
name: value.name,
|
|
4789
|
+
company: value.company
|
|
4790
|
+
} : null;
|
|
4791
|
+
default: return null;
|
|
4792
|
+
}
|
|
4793
|
+
}
|
|
4794
|
+
function parseToggleConfirmation(value) {
|
|
4795
|
+
if (!isRecord$2(value)) return null;
|
|
4796
|
+
return value.tag === "on" || value.tag === "off" ? { tag: value.tag } : null;
|
|
4797
|
+
}
|
|
4798
|
+
function parseBrevoConfirmation(value) {
|
|
4799
|
+
if (!isRecord$2(value)) return null;
|
|
4800
|
+
if (value.tag === "off") return { tag: "off" };
|
|
4801
|
+
if (value.tag !== "on") return null;
|
|
4802
|
+
const templateId = parseBrevoConfirmationTemplateId(value.templateId);
|
|
4803
|
+
const redirectUrl = parseHttpUrl(value.redirectUrl);
|
|
4804
|
+
return templateId === null || redirectUrl === null ? null : {
|
|
4805
|
+
tag: "on",
|
|
4806
|
+
templateId,
|
|
4807
|
+
redirectUrl
|
|
4808
|
+
};
|
|
4809
|
+
}
|
|
4810
|
+
function parseMailingListSetupRevision(value) {
|
|
4811
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value > 0 ? value : null;
|
|
4812
|
+
}
|
|
4813
|
+
function parseHttpUrl(value) {
|
|
4814
|
+
if (typeof value !== "string") return null;
|
|
4815
|
+
try {
|
|
4816
|
+
const url = new URL(value);
|
|
4817
|
+
return url.protocol === "http:" || url.protocol === "https:" ? url.toString() : null;
|
|
4818
|
+
} catch {
|
|
4819
|
+
return null;
|
|
4820
|
+
}
|
|
4821
|
+
}
|
|
4822
|
+
function parseRequiredString(value) {
|
|
4823
|
+
if (typeof value !== "string") return null;
|
|
4824
|
+
const trimmed = value.trim();
|
|
4825
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
4826
|
+
}
|
|
4827
|
+
function parseOptionalString(value) {
|
|
4828
|
+
if (value === null || value === undefined) return null;
|
|
4829
|
+
if (typeof value !== "string") return undefined;
|
|
4830
|
+
const trimmed = value.trim();
|
|
4831
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
4832
|
+
}
|
|
4833
|
+
function isRequirement(value) {
|
|
4834
|
+
return value === "required" || value === "optional";
|
|
4835
|
+
}
|
|
4836
|
+
function isRecord$2(value) {
|
|
4837
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
4838
|
+
}
|
|
4839
|
+
function formError(field) {
|
|
4840
|
+
return err({
|
|
4841
|
+
tag: "invalid_mailing_list_global_form",
|
|
4842
|
+
field
|
|
4843
|
+
});
|
|
4844
|
+
}
|
|
4845
|
+
function setupError(field) {
|
|
4846
|
+
return err({
|
|
4847
|
+
tag: "invalid_mailing_list_setup",
|
|
4848
|
+
field
|
|
4849
|
+
});
|
|
4850
|
+
}
|
|
4851
|
+
|
|
4852
|
+
//#endregion
|
|
4853
|
+
//#region ../core/src/mailing-list-targeting.ts
|
|
4854
|
+
function sameMailingListPlacementTargeting(left, right) {
|
|
4855
|
+
if (left.mode !== right.mode) return false;
|
|
4856
|
+
if (left.mode === "default" || right.mode === "default") return true;
|
|
4857
|
+
if (left.provider !== right.provider || left.selection.tag !== right.selection.tag) return false;
|
|
4858
|
+
if (left.provider === "mailchimp" && (right.provider !== "mailchimp" || left.audienceId !== right.audienceId)) return false;
|
|
4859
|
+
return sameIds(targetingSelectionIds(left), targetingSelectionIds(right));
|
|
4860
|
+
}
|
|
4861
|
+
function targetingSelectionIds(targeting) {
|
|
4862
|
+
switch (targeting.provider) {
|
|
4863
|
+
case "native": return targeting.selection.tag === "fixed" ? targeting.selection.topicIds : targeting.selection.offeredTopicIds;
|
|
4864
|
+
case "brevo": return targeting.selection.tag === "fixed" ? targeting.selection.listIds : targeting.selection.offeredListIds;
|
|
4865
|
+
case "mailchimp": return targeting.selection.tag === "fixed" ? targeting.selection.interestIds : targeting.selection.offeredInterestIds;
|
|
4866
|
+
}
|
|
4867
|
+
}
|
|
4868
|
+
function sameIds(left, right) {
|
|
4869
|
+
const leftIds = new Set(left);
|
|
4870
|
+
const rightIds = new Set(right);
|
|
4871
|
+
return leftIds.size === left.length && rightIds.size === right.length && leftIds.size === rightIds.size && [...leftIds].every((id) => rightIds.has(id));
|
|
4872
|
+
}
|
|
4873
|
+
function resolveMailingListTarget(input) {
|
|
4874
|
+
if (input.targeting.mode === "default") {
|
|
4875
|
+
if (input.visitorSelection !== undefined) {
|
|
4876
|
+
return err({ tag: "visitor_selection_not_allowed" });
|
|
4877
|
+
}
|
|
4878
|
+
return ok(resolveDefaultTarget(input.setup));
|
|
4879
|
+
}
|
|
4880
|
+
if (input.targeting.provider !== input.setup.provider) {
|
|
4881
|
+
return err({
|
|
4882
|
+
tag: "targeting_provider_mismatch",
|
|
4883
|
+
setupProvider: input.setup.provider,
|
|
4884
|
+
targetingProvider: input.targeting.provider
|
|
4885
|
+
});
|
|
4886
|
+
}
|
|
4887
|
+
return resolveCustomTarget(input.targeting, input.visitorSelection);
|
|
4888
|
+
}
|
|
4889
|
+
function resolveDefaultTarget(setup) {
|
|
4890
|
+
switch (setup.provider) {
|
|
4891
|
+
case "native": return {
|
|
4892
|
+
provider: "native",
|
|
4893
|
+
topicIds: [setup.defaultTopicId]
|
|
4894
|
+
};
|
|
4895
|
+
case "brevo": return {
|
|
4896
|
+
provider: "brevo",
|
|
4897
|
+
listIds: [setup.defaultListId]
|
|
4898
|
+
};
|
|
4899
|
+
case "mailchimp": return {
|
|
4900
|
+
provider: "mailchimp",
|
|
4901
|
+
audienceId: setup.defaultAudienceId,
|
|
4902
|
+
interestIds: []
|
|
4903
|
+
};
|
|
4904
|
+
}
|
|
4905
|
+
}
|
|
4906
|
+
function resolveCustomTarget(targeting, visitorSelection) {
|
|
4907
|
+
switch (targeting.provider) {
|
|
4908
|
+
case "native": return resolveNativeTarget(targeting, visitorSelection);
|
|
4909
|
+
case "brevo": return resolveBrevoTarget(targeting, visitorSelection);
|
|
4910
|
+
case "mailchimp": return resolveMailchimpTarget(targeting, visitorSelection);
|
|
4911
|
+
}
|
|
4912
|
+
}
|
|
4913
|
+
function resolveNativeTarget(targeting, selection) {
|
|
4914
|
+
if (targeting.selection.tag === "fixed") {
|
|
4915
|
+
return selection === undefined ? ok({
|
|
4916
|
+
provider: "native",
|
|
4917
|
+
topicIds: targeting.selection.topicIds
|
|
4918
|
+
}) : err({ tag: "visitor_selection_not_allowed" });
|
|
4919
|
+
}
|
|
4920
|
+
if (selection === undefined) {
|
|
4921
|
+
return targeting.selection.offeredTopicIds.length === 1 ? ok({
|
|
4922
|
+
provider: "native",
|
|
4923
|
+
topicIds: targeting.selection.offeredTopicIds
|
|
4924
|
+
}) : err({ tag: "visitor_selection_required" });
|
|
4925
|
+
}
|
|
4926
|
+
if (selection.provider !== "native") {
|
|
4927
|
+
return err({ tag: "visitor_selection_provider_mismatch" });
|
|
4928
|
+
}
|
|
4929
|
+
const selected = selectedNonEmptySubset(selection.topicIds, targeting.selection.offeredTopicIds);
|
|
4930
|
+
return selected.ok ? ok({
|
|
4931
|
+
provider: "native",
|
|
4932
|
+
topicIds: selected.value
|
|
4933
|
+
}) : err({ tag: "visitor_selection_outside_offer" });
|
|
4934
|
+
}
|
|
4935
|
+
function resolveBrevoTarget(targeting, selection) {
|
|
4936
|
+
if (targeting.selection.tag === "fixed") {
|
|
4937
|
+
return selection === undefined ? ok({
|
|
4938
|
+
provider: "brevo",
|
|
4939
|
+
listIds: targeting.selection.listIds
|
|
4940
|
+
}) : err({ tag: "visitor_selection_not_allowed" });
|
|
4941
|
+
}
|
|
4942
|
+
if (selection === undefined) {
|
|
4943
|
+
return targeting.selection.offeredListIds.length === 1 ? ok({
|
|
4944
|
+
provider: "brevo",
|
|
4945
|
+
listIds: targeting.selection.offeredListIds
|
|
4946
|
+
}) : err({ tag: "visitor_selection_required" });
|
|
4947
|
+
}
|
|
4948
|
+
if (selection.provider !== "brevo") {
|
|
4949
|
+
return err({ tag: "visitor_selection_provider_mismatch" });
|
|
4950
|
+
}
|
|
4951
|
+
const selected = selectedNonEmptySubset(selection.listIds, targeting.selection.offeredListIds);
|
|
4952
|
+
return selected.ok ? ok({
|
|
4953
|
+
provider: "brevo",
|
|
4954
|
+
listIds: selected.value
|
|
4955
|
+
}) : err({ tag: "visitor_selection_outside_offer" });
|
|
4956
|
+
}
|
|
4957
|
+
function resolveMailchimpTarget(targeting, selection) {
|
|
4958
|
+
if (targeting.selection.tag === "fixed") {
|
|
4959
|
+
return selection === undefined ? ok({
|
|
4960
|
+
provider: "mailchimp",
|
|
4961
|
+
audienceId: targeting.audienceId,
|
|
4962
|
+
interestIds: targeting.selection.interestIds
|
|
4963
|
+
}) : err({ tag: "visitor_selection_not_allowed" });
|
|
4964
|
+
}
|
|
4965
|
+
if (selection === undefined) {
|
|
4966
|
+
return targeting.selection.offeredInterestIds.length === 1 ? ok({
|
|
4967
|
+
provider: "mailchimp",
|
|
4968
|
+
audienceId: targeting.audienceId,
|
|
4969
|
+
interestIds: targeting.selection.offeredInterestIds
|
|
4970
|
+
}) : err({ tag: "visitor_selection_required" });
|
|
4971
|
+
}
|
|
4972
|
+
if (selection.provider !== "mailchimp") {
|
|
4973
|
+
return err({ tag: "visitor_selection_provider_mismatch" });
|
|
4974
|
+
}
|
|
4975
|
+
const subset = selectedNonEmptySubset(selection.interestIds, targeting.selection.offeredInterestIds);
|
|
4976
|
+
return subset.ok ? ok({
|
|
4977
|
+
provider: "mailchimp",
|
|
4978
|
+
audienceId: targeting.audienceId,
|
|
4979
|
+
interestIds: subset.value
|
|
4980
|
+
}) : err({ tag: "visitor_selection_outside_offer" });
|
|
4981
|
+
}
|
|
4982
|
+
function selectedNonEmptySubset(selected, offered) {
|
|
4983
|
+
const normalized = [...new Set(selected)];
|
|
4984
|
+
const [first, ...rest] = normalized;
|
|
4985
|
+
if (first === undefined || normalized.some((item) => !offered.includes(item))) {
|
|
4986
|
+
return err("invalid_selection");
|
|
4987
|
+
}
|
|
4988
|
+
return ok([first, ...rest]);
|
|
4989
|
+
}
|
|
4990
|
+
function planMailingListChoicePresentation(targeting) {
|
|
4991
|
+
if (targeting.mode === "default" || targeting.selection.tag === "fixed") {
|
|
4992
|
+
return { tag: "hidden" };
|
|
4993
|
+
}
|
|
4994
|
+
switch (targeting.provider) {
|
|
4995
|
+
case "native": return targeting.selection.offeredTopicIds.length === 1 ? {
|
|
4996
|
+
tag: "automatic",
|
|
4997
|
+
selection: {
|
|
4998
|
+
provider: "native",
|
|
4999
|
+
topicIds: targeting.selection.offeredTopicIds
|
|
5000
|
+
}
|
|
5001
|
+
} : {
|
|
5002
|
+
tag: "visitor_choice",
|
|
5003
|
+
provider: "native",
|
|
5004
|
+
optionCount: targeting.selection.offeredTopicIds.length
|
|
5005
|
+
};
|
|
5006
|
+
case "brevo": return targeting.selection.offeredListIds.length === 1 ? {
|
|
5007
|
+
tag: "automatic",
|
|
5008
|
+
selection: {
|
|
5009
|
+
provider: "brevo",
|
|
5010
|
+
listIds: targeting.selection.offeredListIds
|
|
5011
|
+
}
|
|
5012
|
+
} : {
|
|
5013
|
+
tag: "visitor_choice",
|
|
5014
|
+
provider: "brevo",
|
|
5015
|
+
optionCount: targeting.selection.offeredListIds.length
|
|
5016
|
+
};
|
|
5017
|
+
case "mailchimp": return targeting.selection.offeredInterestIds.length === 1 ? {
|
|
5018
|
+
tag: "automatic",
|
|
5019
|
+
selection: {
|
|
5020
|
+
provider: "mailchimp",
|
|
5021
|
+
interestIds: targeting.selection.offeredInterestIds
|
|
5022
|
+
}
|
|
5023
|
+
} : {
|
|
5024
|
+
tag: "visitor_choice",
|
|
5025
|
+
provider: "mailchimp",
|
|
5026
|
+
optionCount: targeting.selection.offeredInterestIds.length
|
|
5027
|
+
};
|
|
5028
|
+
}
|
|
5029
|
+
}
|
|
5030
|
+
|
|
5031
|
+
//#endregion
|
|
5032
|
+
//#region ../core/src/mailing-list-runtime.ts
|
|
5033
|
+
function parseMailingListRuntimeContext(value) {
|
|
5034
|
+
if (!isRecord$1(value)) return invalidRuntimeContext();
|
|
5035
|
+
if (value.tag === "not_configured") return ok({ tag: "not_configured" });
|
|
5036
|
+
if (value.tag !== "configured") return invalidRuntimeContext();
|
|
5037
|
+
const revision = parseMailingListSetupRevision(value.revision);
|
|
5038
|
+
const form = parseMailingListGlobalForm(value.form);
|
|
5039
|
+
const provider = parseRuntimeProvider(value.provider);
|
|
5040
|
+
if (revision === null || !form.ok || provider === null) {
|
|
5041
|
+
return invalidRuntimeContext();
|
|
5042
|
+
}
|
|
5043
|
+
return ok({
|
|
5044
|
+
tag: "configured",
|
|
5045
|
+
revision,
|
|
5046
|
+
form: form.value,
|
|
5047
|
+
provider
|
|
5048
|
+
});
|
|
5049
|
+
}
|
|
5050
|
+
function parseRuntimeProvider(value) {
|
|
5051
|
+
if (!isRecord$1(value)) return null;
|
|
5052
|
+
switch (value.provider) {
|
|
5053
|
+
case "native": return parseNativeRuntimeProvider(value);
|
|
5054
|
+
case "brevo": return parseBrevoRuntimeProvider(value);
|
|
5055
|
+
case "mailchimp": return parseMailchimpRuntimeProvider(value);
|
|
5056
|
+
default: return null;
|
|
5057
|
+
}
|
|
5058
|
+
}
|
|
5059
|
+
function parseNativeRuntimeProvider(value) {
|
|
5060
|
+
const defaultTopicId = parseNewsletterListId(value.defaultTopicId);
|
|
5061
|
+
const topics = parseNamedItems(value.topics, parseNewsletterListId);
|
|
5062
|
+
return defaultTopicId !== null && topics !== null ? {
|
|
5063
|
+
provider: "native",
|
|
5064
|
+
defaultTopicId,
|
|
5065
|
+
topics
|
|
5066
|
+
} : null;
|
|
5067
|
+
}
|
|
5068
|
+
function parseBrevoRuntimeProvider(value) {
|
|
5069
|
+
const defaultListId = parseBrevoListId(value.defaultListId);
|
|
5070
|
+
const lists = parseNamedItems(value.lists, parseBrevoListId);
|
|
5071
|
+
return defaultListId !== null && lists !== null ? {
|
|
5072
|
+
provider: "brevo",
|
|
5073
|
+
defaultListId,
|
|
5074
|
+
lists
|
|
5075
|
+
} : null;
|
|
5076
|
+
}
|
|
5077
|
+
function parseMailchimpRuntimeProvider(value) {
|
|
5078
|
+
if (!Array.isArray(value.audiences)) return null;
|
|
5079
|
+
const defaultAudienceId = parseMailchimpAudienceId(value.defaultAudienceId);
|
|
5080
|
+
if (defaultAudienceId === null) return null;
|
|
5081
|
+
const audiences = [];
|
|
5082
|
+
for (const audience of value.audiences) {
|
|
5083
|
+
if (!isRecord$1(audience)) return null;
|
|
5084
|
+
const id = parseMailchimpAudienceId(audience.id);
|
|
5085
|
+
const name = parseName(audience.name);
|
|
5086
|
+
if (id === null || name === null || !Array.isArray(audience.interests)) {
|
|
5087
|
+
return null;
|
|
5088
|
+
}
|
|
5089
|
+
const interests = parseMailchimpInterests(audience.interests);
|
|
5090
|
+
if (interests === null) return null;
|
|
5091
|
+
audiences.push({
|
|
5092
|
+
id,
|
|
5093
|
+
name,
|
|
5094
|
+
interests
|
|
5095
|
+
});
|
|
5096
|
+
}
|
|
5097
|
+
return {
|
|
5098
|
+
provider: "mailchimp",
|
|
5099
|
+
defaultAudienceId,
|
|
5100
|
+
audiences
|
|
5101
|
+
};
|
|
5102
|
+
}
|
|
5103
|
+
function parseMailchimpInterests(value) {
|
|
5104
|
+
const interests = [];
|
|
5105
|
+
for (const interest of value) {
|
|
5106
|
+
if (!isRecord$1(interest)) return null;
|
|
5107
|
+
const id = parseMailchimpInterestId(interest.id);
|
|
5108
|
+
const name = parseName(interest.name);
|
|
5109
|
+
const categoryName = parseName(interest.categoryName);
|
|
5110
|
+
if (id === null || name === null || categoryName === null) return null;
|
|
5111
|
+
interests.push({
|
|
5112
|
+
id,
|
|
5113
|
+
name,
|
|
5114
|
+
categoryName
|
|
5115
|
+
});
|
|
5116
|
+
}
|
|
5117
|
+
return interests;
|
|
5118
|
+
}
|
|
5119
|
+
function parseNamedItems(value, parseId) {
|
|
5120
|
+
if (!Array.isArray(value)) return null;
|
|
5121
|
+
const items = [];
|
|
5122
|
+
for (const item of value) {
|
|
5123
|
+
if (!isRecord$1(item)) return null;
|
|
5124
|
+
const id = parseId(item.id);
|
|
5125
|
+
const name = parseName(item.name);
|
|
5126
|
+
if (id === null || name === null) return null;
|
|
5127
|
+
items.push({
|
|
5128
|
+
id,
|
|
5129
|
+
name
|
|
5130
|
+
});
|
|
5131
|
+
}
|
|
5132
|
+
return items;
|
|
5133
|
+
}
|
|
5134
|
+
function parseName(value) {
|
|
5135
|
+
if (typeof value !== "string") return null;
|
|
5136
|
+
const name = value.trim();
|
|
5137
|
+
return name.length > 0 ? name : null;
|
|
5138
|
+
}
|
|
5139
|
+
function isRecord$1(value) {
|
|
5140
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5141
|
+
}
|
|
5142
|
+
function invalidRuntimeContext() {
|
|
5143
|
+
return err({ tag: "invalid_mailing_list_runtime_context" });
|
|
5144
|
+
}
|
|
5145
|
+
|
|
5146
|
+
//#endregion
|
|
5147
|
+
//#region ../core/src/mailing-list-submission.ts
|
|
5148
|
+
const MAILING_LIST_SUBMISSION_BUDGET_MS = 1e4;
|
|
5149
|
+
function parseMailingListBlockId(value) {
|
|
5150
|
+
const parsed = typeof value === "string" ? value.trim() : "";
|
|
5151
|
+
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;
|
|
5152
|
+
}
|
|
5153
|
+
function parseMailingListSignedSourceToken(value) {
|
|
5154
|
+
const parsed = typeof value === "string" ? value.trim() : "";
|
|
5155
|
+
return /^[A-Za-z0-9._~-]{16,1000}$/u.test(parsed) ? parsed : null;
|
|
5156
|
+
}
|
|
5157
|
+
function parseMailingListSdkFooterBlockId(value) {
|
|
5158
|
+
const parsed = typeof value === "string" ? value.trim() : "";
|
|
5159
|
+
return /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u.test(parsed) ? parsed : null;
|
|
5160
|
+
}
|
|
5161
|
+
function parseMailingListSdkContentHash(value) {
|
|
5162
|
+
const parsed = typeof value === "string" ? value.trim() : "";
|
|
5163
|
+
return /^[a-f0-9]{16}$/iu.test(parsed) ? parsed : null;
|
|
5164
|
+
}
|
|
5165
|
+
function parseMailingListContentVersionId(value) {
|
|
5166
|
+
const parsed = parseContentVersionId(value);
|
|
5167
|
+
return parsed.ok ? parsed.value : null;
|
|
5168
|
+
}
|
|
5169
|
+
function parseMailingListFooterRevision(value) {
|
|
5170
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : null;
|
|
5171
|
+
}
|
|
5172
|
+
function buildMailingListSignupBlockSourceRef(blockId, contentVersionId) {
|
|
5173
|
+
const parsedBlockId = parseMailingListBlockId(blockId);
|
|
5174
|
+
const parsedContentVersionId = parseMailingListContentVersionId(contentVersionId);
|
|
5175
|
+
return parsedBlockId !== null && parsedContentVersionId !== null ? {
|
|
5176
|
+
tag: "block_ref",
|
|
5177
|
+
blockId: parsedBlockId,
|
|
5178
|
+
contentVersionId: parsedContentVersionId
|
|
5179
|
+
} : null;
|
|
5180
|
+
}
|
|
5181
|
+
function parseMailingListSignupProfile(form, input) {
|
|
5182
|
+
const email = normalizeSubscriberEmail(input.email);
|
|
5183
|
+
if (email === null) return {
|
|
5184
|
+
ok: false,
|
|
5185
|
+
error: { tag: "invalid_email" }
|
|
5186
|
+
};
|
|
5187
|
+
const phone = form.includeOptionalPhone ? {
|
|
5188
|
+
tag: "collected",
|
|
5189
|
+
value: normalizeOptionalValue(input.phone)
|
|
5190
|
+
} : { tag: "not_collected" };
|
|
5191
|
+
switch (form.fields.preset) {
|
|
5192
|
+
case "emailOnly": return {
|
|
5193
|
+
ok: true,
|
|
5194
|
+
value: {
|
|
5195
|
+
preset: "emailOnly",
|
|
5196
|
+
email,
|
|
5197
|
+
phone
|
|
5198
|
+
}
|
|
5199
|
+
};
|
|
5200
|
+
case "emailName": {
|
|
5201
|
+
const name = resolveProfileField("name", form.fields.name, input.name);
|
|
5202
|
+
return name.ok ? {
|
|
5203
|
+
ok: true,
|
|
5204
|
+
value: {
|
|
5205
|
+
preset: "emailName",
|
|
5206
|
+
email,
|
|
5207
|
+
phone,
|
|
5208
|
+
name: name.value
|
|
5209
|
+
}
|
|
5210
|
+
} : name;
|
|
5211
|
+
}
|
|
5212
|
+
case "emailFirstLast": {
|
|
5213
|
+
const firstName = resolveProfileField("first_name", form.fields.firstName, input.firstName);
|
|
5214
|
+
if (!firstName.ok) return firstName;
|
|
5215
|
+
const lastName = resolveProfileField("last_name", form.fields.lastName, input.lastName);
|
|
5216
|
+
return lastName.ok ? {
|
|
5217
|
+
ok: true,
|
|
5218
|
+
value: {
|
|
5219
|
+
preset: "emailFirstLast",
|
|
5220
|
+
email,
|
|
5221
|
+
phone,
|
|
5222
|
+
firstName: firstName.value,
|
|
5223
|
+
lastName: lastName.value
|
|
5224
|
+
}
|
|
5225
|
+
} : lastName;
|
|
5226
|
+
}
|
|
5227
|
+
case "emailNameCompany": {
|
|
5228
|
+
const name = resolveProfileField("name", form.fields.name, input.name);
|
|
5229
|
+
if (!name.ok) return name;
|
|
5230
|
+
const company = resolveProfileField("company", form.fields.company, input.company);
|
|
5231
|
+
return company.ok ? {
|
|
5232
|
+
ok: true,
|
|
5233
|
+
value: {
|
|
5234
|
+
preset: "emailNameCompany",
|
|
5235
|
+
email,
|
|
5236
|
+
phone,
|
|
5237
|
+
name: name.value,
|
|
5238
|
+
company: company.value
|
|
5239
|
+
}
|
|
5240
|
+
} : company;
|
|
5241
|
+
}
|
|
5242
|
+
}
|
|
5243
|
+
}
|
|
5244
|
+
function resolveProfileField(field, requirement, input) {
|
|
5245
|
+
const value = normalizeOptionalValue(input);
|
|
5246
|
+
if (requirement === "required") {
|
|
5247
|
+
return value === null ? {
|
|
5248
|
+
ok: false,
|
|
5249
|
+
error: {
|
|
5250
|
+
tag: "required_field_missing",
|
|
5251
|
+
field
|
|
5252
|
+
}
|
|
5253
|
+
} : {
|
|
5254
|
+
ok: true,
|
|
5255
|
+
value: {
|
|
5256
|
+
requirement: "required",
|
|
5257
|
+
value
|
|
5258
|
+
}
|
|
5259
|
+
};
|
|
5260
|
+
}
|
|
5261
|
+
return {
|
|
5262
|
+
ok: true,
|
|
5263
|
+
value: {
|
|
5264
|
+
requirement: "optional",
|
|
5265
|
+
value
|
|
5266
|
+
}
|
|
5267
|
+
};
|
|
5268
|
+
}
|
|
5269
|
+
function normalizeSubscriberEmail(value) {
|
|
5270
|
+
const normalized = value.trim().toLowerCase();
|
|
5271
|
+
const at = normalized.indexOf("@");
|
|
5272
|
+
return normalized.length <= 320 && at > 0 && at === normalized.lastIndexOf("@") && at < normalized.length - 1 ? normalized : null;
|
|
5273
|
+
}
|
|
5274
|
+
function normalizeOptionalValue(value) {
|
|
5275
|
+
const normalized = value?.trim() ?? "";
|
|
5276
|
+
return normalized.length > 0 ? normalized : null;
|
|
5277
|
+
}
|
|
5278
|
+
function toMailingListPublicSignupResponse(result) {
|
|
5279
|
+
if (result.ok) {
|
|
5280
|
+
return result.acknowledgement.tag === "subscribed" ? { tag: "subscribed" } : { tag: "confirmation_required" };
|
|
5281
|
+
}
|
|
5282
|
+
if (result.error.tag === "profile_rejected") {
|
|
5283
|
+
return {
|
|
5284
|
+
tag: "invalid_input",
|
|
5285
|
+
reason: "profile_rejected"
|
|
5286
|
+
};
|
|
5287
|
+
}
|
|
5288
|
+
if (result.error.tag === "subscriber_suppressed") {
|
|
5289
|
+
return { tag: "confirmation_required" };
|
|
5290
|
+
}
|
|
5291
|
+
return result.error.tag === "uncertain" ? {
|
|
5292
|
+
tag: "uncertain",
|
|
5293
|
+
reason: result.error.reason
|
|
5294
|
+
} : {
|
|
5295
|
+
tag: "unavailable",
|
|
5296
|
+
reason: result.error.tag
|
|
5297
|
+
};
|
|
5298
|
+
}
|
|
5299
|
+
|
|
4366
5300
|
//#endregion
|
|
4367
5301
|
//#region ../core/src/number-input.ts
|
|
4368
5302
|
/**
|
|
@@ -5110,7 +6044,8 @@ function failInvalidSecret() {
|
|
|
5110
6044
|
const SITE_ROUTE_NODE_TYPES = [
|
|
5111
6045
|
"page",
|
|
5112
6046
|
"content_entry",
|
|
5113
|
-
"page_surface"
|
|
6047
|
+
"page_surface",
|
|
6048
|
+
"appointment_service"
|
|
5114
6049
|
];
|
|
5115
6050
|
function parseSiteRouteTarget(input) {
|
|
5116
6051
|
if (typeof input.nodeType !== "string") {
|
|
@@ -5150,6 +6085,16 @@ function parseSiteRouteTarget(input) {
|
|
|
5150
6085
|
error: surfaceId.error
|
|
5151
6086
|
});
|
|
5152
6087
|
}
|
|
6088
|
+
case "appointment_service": {
|
|
6089
|
+
const serviceId = parseAppointmentServiceId(input.nodeId);
|
|
6090
|
+
return serviceId.ok ? ok({
|
|
6091
|
+
kind: "appointmentService",
|
|
6092
|
+
serviceId: serviceId.value
|
|
6093
|
+
}) : err({
|
|
6094
|
+
kind: "invalid-appointment-service-id",
|
|
6095
|
+
error: serviceId.error
|
|
6096
|
+
});
|
|
6097
|
+
}
|
|
5153
6098
|
default: return err({
|
|
5154
6099
|
kind: "unsupported-node-type",
|
|
5155
6100
|
nodeType: input.nodeType
|
|
@@ -5161,6 +6106,7 @@ function siteRouteTargetNodeType(target) {
|
|
|
5161
6106
|
case "page": return "page";
|
|
5162
6107
|
case "contentEntry": return "content_entry";
|
|
5163
6108
|
case "pageSurface": return "page_surface";
|
|
6109
|
+
case "appointmentService": return "appointment_service";
|
|
5164
6110
|
default: return assertNever(target);
|
|
5165
6111
|
}
|
|
5166
6112
|
}
|
|
@@ -5169,6 +6115,7 @@ function foldSiteRouteTarget(target, cases) {
|
|
|
5169
6115
|
case "page": return cases.page(target.pageId);
|
|
5170
6116
|
case "contentEntry": return cases.contentEntry(target.entryId);
|
|
5171
6117
|
case "pageSurface": return cases.pageSurface(target.surfaceId);
|
|
6118
|
+
case "appointmentService": return cases.appointmentService(target.serviceId);
|
|
5172
6119
|
default: return assertNever(target);
|
|
5173
6120
|
}
|
|
5174
6121
|
}
|
|
@@ -5274,6 +6221,63 @@ function resolveWholeSeriesBookingPhase(run, now) {
|
|
|
5274
6221
|
}
|
|
5275
6222
|
}
|
|
5276
6223
|
|
|
6224
|
+
//#endregion
|
|
6225
|
+
//#region ../core/src/public-read-cache-contract.ts
|
|
6226
|
+
const PUBLIC_AVAILABILITY_FRESHNESS_SECONDS = 60;
|
|
6227
|
+
const PUBLIC_CONTENT_FRESHNESS_SECONDS = 3600;
|
|
6228
|
+
function availability(transport) {
|
|
6229
|
+
return {
|
|
6230
|
+
kind: "live",
|
|
6231
|
+
reason: "booking_correctness",
|
|
6232
|
+
freshness: "availability",
|
|
6233
|
+
transport
|
|
6234
|
+
};
|
|
6235
|
+
}
|
|
6236
|
+
function content(tags, transport = "direct") {
|
|
6237
|
+
return {
|
|
6238
|
+
kind: "tagged",
|
|
6239
|
+
tags,
|
|
6240
|
+
freshness: "content",
|
|
6241
|
+
transport
|
|
6242
|
+
};
|
|
6243
|
+
}
|
|
6244
|
+
/** The single classification authority for cacheable public reads. */
|
|
6245
|
+
const PUBLIC_READ_CACHE_POLICIES = {
|
|
6246
|
+
listPublishedEntries: content(["published_content"]),
|
|
6247
|
+
getPublishedEntryPreview: content(["published_content"]),
|
|
6248
|
+
listPublicEvents: availability("direct"),
|
|
6249
|
+
listPublicEventCalendarWindow: availability("direct"),
|
|
6250
|
+
listPublicRecurringSchedule: availability("batch_only"),
|
|
6251
|
+
getPublicEventDetails: availability("batch_only"),
|
|
6252
|
+
resolveEventSubroute: availability("direct"),
|
|
6253
|
+
listPublicRouteCandidates: content(["published_content"], "batch_only"),
|
|
6254
|
+
listPublicTeamMembers: content(["public_team_members"]),
|
|
6255
|
+
listPublicProducts: availability("direct"),
|
|
6256
|
+
listPublicPasses: availability("direct"),
|
|
6257
|
+
listPublicMemberships: availability("direct"),
|
|
6258
|
+
getPublicFormById: content(["site_forms"]),
|
|
6259
|
+
getPublicBookingServices: availability("direct"),
|
|
6260
|
+
getPublicBookingService: availability("direct"),
|
|
6261
|
+
getPublicBookingResourcesReference: availability("direct"),
|
|
6262
|
+
getPublicBookingAvailableDates: availability("direct"),
|
|
6263
|
+
getPublicBookingAvailableSlots: availability("direct"),
|
|
6264
|
+
getPublicWeeklySlotAvailability: availability("direct"),
|
|
6265
|
+
listPublicForms: content(["site_forms"]),
|
|
6266
|
+
checkRedirect: content([]),
|
|
6267
|
+
getPublicRoutableContent: content(["published_content"]),
|
|
6268
|
+
getPublicSitemapRoutes: content(["published_content"])
|
|
6269
|
+
};
|
|
6270
|
+
const PUBLIC_READ_ENDPOINT_SET = new Set(Object.keys(PUBLIC_READ_CACHE_POLICIES));
|
|
6271
|
+
function isPublicReadEndpoint(endpoint) {
|
|
6272
|
+
return PUBLIC_READ_ENDPOINT_SET.has(endpoint);
|
|
6273
|
+
}
|
|
6274
|
+
function getPublicReadCachePolicy(endpoint) {
|
|
6275
|
+
return PUBLIC_READ_CACHE_POLICIES[endpoint];
|
|
6276
|
+
}
|
|
6277
|
+
function publicReadFreshnessSeconds(endpoint) {
|
|
6278
|
+
return getPublicReadCachePolicy(endpoint).freshness === "availability" ? PUBLIC_AVAILABILITY_FRESHNESS_SECONDS : PUBLIC_CONTENT_FRESHNESS_SECONDS;
|
|
6279
|
+
}
|
|
6280
|
+
|
|
5277
6281
|
//#endregion
|
|
5278
6282
|
//#region ../core/src/event-series-behaviour.ts
|
|
5279
6283
|
const EVENT_PRESET_VALUES = [
|
|
@@ -5357,13 +6361,13 @@ const BOOKING_DEFAULTS_BY_BEHAVIOUR = {
|
|
|
5357
6361
|
memberships: "off"
|
|
5358
6362
|
}
|
|
5359
6363
|
};
|
|
5360
|
-
function verticalBookingPreset(id, verticalId, canonicalBehaviour, label, pluralLabel, description, availability = "onboarding") {
|
|
6364
|
+
function verticalBookingPreset(id, verticalId, canonicalBehaviour, label, pluralLabel, description, availability$1 = "onboarding") {
|
|
5361
6365
|
return {
|
|
5362
6366
|
id,
|
|
5363
6367
|
verticalId,
|
|
5364
6368
|
canonicalBehaviour,
|
|
5365
6369
|
engine: BOOKING_ENGINE_BY_BEHAVIOUR[canonicalBehaviour],
|
|
5366
|
-
availability,
|
|
6370
|
+
availability: availability$1,
|
|
5367
6371
|
label,
|
|
5368
6372
|
pluralLabel,
|
|
5369
6373
|
description
|
|
@@ -5717,12 +6721,12 @@ const VERTICAL_PRESET_AVAILABILITIES = [
|
|
|
5717
6721
|
"future"
|
|
5718
6722
|
];
|
|
5719
6723
|
function getVerticalPresetsForVertical(verticalId, options) {
|
|
5720
|
-
const availability = options?.availability;
|
|
6724
|
+
const availability$1 = options?.availability;
|
|
5721
6725
|
return VERTICAL_BOOKING_PRESETS.filter((presetDefinition) => {
|
|
5722
6726
|
if (presetDefinition.verticalId !== verticalId) return false;
|
|
5723
|
-
if (!availability) return true;
|
|
5724
|
-
if (availability === "selectable") return presetDefinition.availability !== "future";
|
|
5725
|
-
return presetDefinition.availability === availability;
|
|
6727
|
+
if (!availability$1) return true;
|
|
6728
|
+
if (availability$1 === "selectable") return presetDefinition.availability !== "future";
|
|
6729
|
+
return presetDefinition.availability === availability$1;
|
|
5726
6730
|
});
|
|
5727
6731
|
}
|
|
5728
6732
|
function getOnboardingPresetsForVertical(verticalId) {
|
|
@@ -5946,4 +6950,62 @@ function orderPresetIdsForVertical(verticalId, presetIds) {
|
|
|
5946
6950
|
}
|
|
5947
6951
|
|
|
5948
6952
|
//#endregion
|
|
5949
|
-
|
|
6953
|
+
//#region ../core/src/navigation-locations.ts
|
|
6954
|
+
/** The only places a site's navigation can be displayed. */
|
|
6955
|
+
const NAVIGATION_LOCATIONS = [
|
|
6956
|
+
"main",
|
|
6957
|
+
"footer",
|
|
6958
|
+
"legal"
|
|
6959
|
+
];
|
|
6960
|
+
const NAVIGATION_LOCATION_DESCRIPTORS = {
|
|
6961
|
+
main: {
|
|
6962
|
+
location: "main",
|
|
6963
|
+
label: "Main navigation",
|
|
6964
|
+
description: "Links shown in the site header when header navigation is enabled."
|
|
6965
|
+
},
|
|
6966
|
+
footer: {
|
|
6967
|
+
location: "footer",
|
|
6968
|
+
label: "Footer links",
|
|
6969
|
+
description: "Links shown in the main footer links section when it is enabled."
|
|
6970
|
+
},
|
|
6971
|
+
legal: {
|
|
6972
|
+
location: "legal",
|
|
6973
|
+
label: "Legal links",
|
|
6974
|
+
description: "Smaller footer links for privacy, terms and other policies."
|
|
6975
|
+
}
|
|
6976
|
+
};
|
|
6977
|
+
function isNavigationLocation(value) {
|
|
6978
|
+
return typeof value === "string" && NAVIGATION_LOCATIONS.includes(value);
|
|
6979
|
+
}
|
|
6980
|
+
/** Parse all rows for one site into a complete fixed-location record. */
|
|
6981
|
+
function parseSiteNavigationLocations(rows) {
|
|
6982
|
+
const locations = {};
|
|
6983
|
+
for (const [index, row] of rows.entries()) {
|
|
6984
|
+
if (!isNavigationLocation(row.location)) {
|
|
6985
|
+
return err({
|
|
6986
|
+
kind: "invalid_location",
|
|
6987
|
+
index,
|
|
6988
|
+
value: row.location
|
|
6989
|
+
});
|
|
6990
|
+
}
|
|
6991
|
+
if (Object.prototype.hasOwnProperty.call(locations, row.location)) {
|
|
6992
|
+
return err({
|
|
6993
|
+
kind: "duplicate_location",
|
|
6994
|
+
location: row.location
|
|
6995
|
+
});
|
|
6996
|
+
}
|
|
6997
|
+
locations[row.location] = row.value;
|
|
6998
|
+
}
|
|
6999
|
+
for (const location of NAVIGATION_LOCATIONS) {
|
|
7000
|
+
if (!Object.prototype.hasOwnProperty.call(locations, location)) {
|
|
7001
|
+
return err({
|
|
7002
|
+
kind: "missing_location",
|
|
7003
|
+
location
|
|
7004
|
+
});
|
|
7005
|
+
}
|
|
7006
|
+
}
|
|
7007
|
+
return ok(locations);
|
|
7008
|
+
}
|
|
7009
|
+
|
|
7010
|
+
//#endregion
|
|
7011
|
+
export { formatEventPricing as $, parseFooterCompositionV1 as A, unsafeAsPositiveSeconds as At, formatBookingTime as B, unsafeAsUserId as Bt, parseMailingListContentVersionId as C, unsafeAsEventOfferingId as Ct, DEFAULT_MAILING_LIST_SUCCESS_MESSAGE as D, unsafeAsOccurrenceId as Dt, planMailingListChoicePresentation as E, unsafeAsMediaAssetId as Et, normalizeLocationAddressText as F, unsafeAsSiteScopedStoragePath as Ft, getLocalScheduleTime as G, formatLocalScheduleTime as H, ok as Ht, toLocationCoordinates as I, unsafeAsStaffMemberId as It, toScheduledBookingDateRange as J, parseUtcIsoDateTimeString as K, buildBookingUtcDateWindow as L, unsafeAsStorageBucketName as Lt, isCanonicalRichTextDoc as M, unsafeAsSafeDownloadFilename as Mt, assertAllowedPublicUrl as N, unsafeAsSiteFontId as Nt, parseMailingListProviderScope as O, unsafeAsOriginalFilename as Ot, isPresent as P, unsafeAsSiteId as Pt, formatBookingPriceDisplay as Q, formatBookingDate as R, unsafeAsStoragePath as Rt, parseMailingListBlockId as S, unsafeAsEntitlementId as St, parseMailingListRuntimeContext as T, unsafeAsFileChecksumSha256 as Tt, getBookingLocalDateKey as U, formatLocalScheduleDate as V, err as Vt, getLocalScheduleDate as W, parseBookingTimeZone as X, toScheduledBookingDateTime as Y, parseEventPageSurfaceSubject as Z, createSecret as _, unsafeAsBookingRequirementId as _t, parseVerticalId as a, resolvePricingOptionsPriceDisplay as at, stableJsonStringify as b, unsafeAsDemoCapability as bt, DEFAULT_EVENT_TYPE_PRESETS as c, formatCurrencyAmount as ct, SURFACE_EVENT_PRESET_VALUES as d, parseEventSeriesId as dt, isPublicEventPricingOptionDisplayable as et, WHOLE_SERIES_EVENT_PRESET_VALUES as f, parseMediaAssetId as ft, resolveWholeSeriesBookingPhase as g, unsafeAsAppointmentResourceId as gt, orderedLiveRunSessions as h, parseUserId as ht, isEventSeriesVerticalPresetDefinition as i, resolveExactOrFreePriceDisplay as it, parseMailingListPlacementTargeting as j, unsafeAsProductId as jt, footerNavigationLayouts as k, unsafeAsPositiveByteCount as kt, EVENT_PRESET_VALUES as l, assertNever as lt, CANCELLED_SESSION_STATUS as m, parseSiteId as mt, areConfiguredBookingVerticalConfigsEqual as n, publicEventPricingDisplay as nt, parseVerticalPresetId as o, fromArray as ot, publicReadFreshnessSeconds as p, parsePageId as pt, toBookingTimeZone as q, canonicalizeConfiguredBookingVerticalConfig as r, publicEventPricingType as rt, resolveSiteVerticalBookingConfig as s, mapNonEmptyArray as st, NAVIGATION_LOCATIONS as t, publicEventPricingCurrency as tt, ORDINARY_EVENT_PRESET_VALUES as u, parseApiKeyId as ut, exposeSecret as v, unsafeAsBookingSessionId as vt, parseMailingListSignedSourceToken as w, unsafeAsEventSeriesId as wt, buildMailingListSignupBlockSourceRef as x, unsafeAsDetectedMimeType as xt, parseManagementKey as y, unsafeAsDeclaredMimeType as yt, formatBookingDateParts as z, unsafeAsUploadSessionId as zt };
|