riverbankcms 0.17.1 → 0.19.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 +3 -3
- package/dist/cli/index.mjs +2474 -1989
- package/dist/{eventUpsertInputSchema-PT5biDSq.mjs → eventUpsertInputSchema-Bkafrrjw.mjs} +2 -2
- package/dist/{load-config-DR5qJgmx.mjs → load-config-CErro6mj.mjs} +2 -2
- package/dist/load-config-rPaisrdG.mjs +4 -0
- package/dist/local-sync-CWLEhMZ-.mjs +4635 -0
- package/dist/{plan-BreyfN6E.mjs → plan-DW5O751d.mjs} +1 -1
- package/dist/scaffold/index.mjs +2 -2
- package/dist/{sdk-event-upsert-JKXlp2Ct.mjs → sdk-event-upsert-BdvfnCyV.mjs} +20382 -13501
- package/dist/{src-JsJh7WAb.mjs → src-yL0DBH7S.mjs} +870 -218
- package/dist/testing.mjs +3 -3
- package/package.json +1 -1
- package/dist/load-config-CyzQYQmx.mjs +0 -4
- package/dist/local-sync-C0m2pobl.mjs +0 -10685
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
|
|
2
4
|
//#region ../core/src/result.ts
|
|
3
5
|
function ok(value) {
|
|
4
6
|
return {
|
|
@@ -1476,7 +1478,7 @@ function resolveFlexibleBalanceDueAt(input) {
|
|
|
1476
1478
|
switch (input.dueDateRule.kind) {
|
|
1477
1479
|
case "relative_to_start_date": return subtractDaysFromIso(input.bookingStartAt, input.dueDateRule.daysBeforeStart);
|
|
1478
1480
|
case "fixed_calendar_date": return input.dueDateRule.dueAt;
|
|
1479
|
-
default: return assertNever$
|
|
1481
|
+
default: return assertNever$5(input.dueDateRule);
|
|
1480
1482
|
}
|
|
1481
1483
|
}
|
|
1482
1484
|
function calculateFlexibleBalanceMinimumPaymentCents(input) {
|
|
@@ -1531,7 +1533,7 @@ function resolveFlexibleBalancePaymentEligibility(input) {
|
|
|
1531
1533
|
suggestedPayFullAmountCents: input.remainingBalanceCents
|
|
1532
1534
|
};
|
|
1533
1535
|
}
|
|
1534
|
-
default: return assertNever$
|
|
1536
|
+
default: return assertNever$5(input.status);
|
|
1535
1537
|
}
|
|
1536
1538
|
}
|
|
1537
1539
|
function isFlexibleBalanceReminderSuppressed(input) {
|
|
@@ -1567,7 +1569,7 @@ function buildFlexibleBalanceReminderSchedule(input) {
|
|
|
1567
1569
|
})
|
|
1568
1570
|
}));
|
|
1569
1571
|
}
|
|
1570
|
-
function assertNever$
|
|
1572
|
+
function assertNever$5(value) {
|
|
1571
1573
|
throw new Error(`Unexpected value: ${String(value)}`);
|
|
1572
1574
|
}
|
|
1573
1575
|
|
|
@@ -1599,6 +1601,10 @@ function createOriginalPaymentRefundCommand(options) {
|
|
|
1599
1601
|
protectedDepositOverride
|
|
1600
1602
|
};
|
|
1601
1603
|
}
|
|
1604
|
+
/** Narrow an already typed schedule-write response by its receipt discriminant. */
|
|
1605
|
+
function isAcceptedEventScheduleUpdate(response) {
|
|
1606
|
+
return "kind" in response && response.kind === "accepted_unavailable";
|
|
1607
|
+
}
|
|
1602
1608
|
|
|
1603
1609
|
//#endregion
|
|
1604
1610
|
//#region ../core/src/booking-instalments.ts
|
|
@@ -1607,7 +1613,7 @@ function isDepositBearingBookingInstalmentPlan(plan) {
|
|
|
1607
1613
|
case "deposit_plus_one_remainder":
|
|
1608
1614
|
case "deposit_plus_scheduled_instalments": return true;
|
|
1609
1615
|
case "equal_scheduled_instalments": return false;
|
|
1610
|
-
default: return assertNever$
|
|
1616
|
+
default: return assertNever$4(plan);
|
|
1611
1617
|
}
|
|
1612
1618
|
}
|
|
1613
1619
|
function getBookingInstalmentDepositRefundability(plan) {
|
|
@@ -1640,7 +1646,7 @@ function addIntervalPreservingMonthAnchor(isoString, intervalCount, intervalUnit
|
|
|
1640
1646
|
date.setUTCDate(date.getUTCDate() + intervalCount * 7);
|
|
1641
1647
|
return date.toISOString();
|
|
1642
1648
|
case "month": return addMonthsPreservingAnchorDay(date, intervalCount).toISOString();
|
|
1643
|
-
default: return assertNever$
|
|
1649
|
+
default: return assertNever$4(intervalUnit);
|
|
1644
1650
|
}
|
|
1645
1651
|
}
|
|
1646
1652
|
function getBookingInstalmentPlanIntervalCount(plan) {
|
|
@@ -1648,7 +1654,7 @@ function getBookingInstalmentPlanIntervalCount(plan) {
|
|
|
1648
1654
|
case "deposit_plus_one_remainder": return plan.remainderDueCount;
|
|
1649
1655
|
case "deposit_plus_scheduled_instalments":
|
|
1650
1656
|
case "equal_scheduled_instalments": return plan.intervalCount;
|
|
1651
|
-
default: return assertNever$
|
|
1657
|
+
default: return assertNever$4(plan);
|
|
1652
1658
|
}
|
|
1653
1659
|
}
|
|
1654
1660
|
function omitZeroAmountFutureRows(rows) {
|
|
@@ -1672,7 +1678,7 @@ function formatOrderInstalmentStatusLabel(input) {
|
|
|
1672
1678
|
case "cancelled": return "Cancelled";
|
|
1673
1679
|
case "cancelled_as_paid_early": return "Paid early";
|
|
1674
1680
|
case "refunded": return "Refunded";
|
|
1675
|
-
default: return assertNever$
|
|
1681
|
+
default: return assertNever$4(input.status);
|
|
1676
1682
|
}
|
|
1677
1683
|
}
|
|
1678
1684
|
const NEXT_DUE_STATUSES = new Set(["scheduled", "failed"]);
|
|
@@ -1693,7 +1699,7 @@ function addMonthsPreservingAnchorDay(date, intervalCount) {
|
|
|
1693
1699
|
nextMonth.setUTCDate(Math.min(anchorDay, lastDayOfTargetMonth));
|
|
1694
1700
|
return nextMonth;
|
|
1695
1701
|
}
|
|
1696
|
-
function assertNever$
|
|
1702
|
+
function assertNever$4(value) {
|
|
1697
1703
|
throw new Error(`Unexpected value: ${String(value)}`);
|
|
1698
1704
|
}
|
|
1699
1705
|
|
|
@@ -1828,6 +1834,42 @@ function validateBookingPaymentOptionKinds(kinds) {
|
|
|
1828
1834
|
return ok(undefined);
|
|
1829
1835
|
}
|
|
1830
1836
|
|
|
1837
|
+
//#endregion
|
|
1838
|
+
//#region ../core/src/date-time-formatter.ts
|
|
1839
|
+
/** Shared Intl engine, internal to core's date presentation owners. */
|
|
1840
|
+
const FORMATTER_CACHE_LIMIT$1 = 100;
|
|
1841
|
+
const dateTimeFormatterCache = new Map();
|
|
1842
|
+
function getDateTimeFormatter(locale, timeZone, format) {
|
|
1843
|
+
const formatKey = JSON.stringify(Object.entries(format).sort(([left], [right]) => left.localeCompare(right)));
|
|
1844
|
+
const key = `${locale}\u0000${timeZone}\u0000${formatKey}`;
|
|
1845
|
+
const cached = dateTimeFormatterCache.get(key);
|
|
1846
|
+
if (cached !== undefined) {
|
|
1847
|
+
return cached;
|
|
1848
|
+
}
|
|
1849
|
+
if (typeof locale !== "string" || Intl.DateTimeFormat.supportedLocalesOf([locale]).length === 0) {
|
|
1850
|
+
throw new RangeError("An explicit supported locale is required");
|
|
1851
|
+
}
|
|
1852
|
+
if (typeof timeZone !== "string" || timeZone.length === 0) {
|
|
1853
|
+
throw new RangeError("An explicit time zone is required");
|
|
1854
|
+
}
|
|
1855
|
+
const formatter = new Intl.DateTimeFormat(locale, {
|
|
1856
|
+
...format,
|
|
1857
|
+
timeZone
|
|
1858
|
+
});
|
|
1859
|
+
if (dateTimeFormatterCache.size >= FORMATTER_CACHE_LIMIT$1) {
|
|
1860
|
+
dateTimeFormatterCache.clear();
|
|
1861
|
+
}
|
|
1862
|
+
dateTimeFormatterCache.set(key, formatter);
|
|
1863
|
+
return formatter;
|
|
1864
|
+
}
|
|
1865
|
+
function formatIntlRange(formatter, start, end) {
|
|
1866
|
+
const nativeFormatRange = Reflect.get(formatter, "formatRange");
|
|
1867
|
+
if (typeof nativeFormatRange !== "function") throw new Error("Intl.DateTimeFormat.formatRange is required");
|
|
1868
|
+
const output = Reflect.apply(nativeFormatRange, formatter, [start, end]);
|
|
1869
|
+
if (typeof output !== "string") throw new Error("Intl.DateTimeFormat.formatRange returned a non-string value");
|
|
1870
|
+
return output;
|
|
1871
|
+
}
|
|
1872
|
+
|
|
1831
1873
|
//#endregion
|
|
1832
1874
|
//#region ../core/src/booking-time-zone.ts
|
|
1833
1875
|
const TIME_ZONE_VALIDITY_CACHE_LIMIT = 100;
|
|
@@ -1862,7 +1904,7 @@ function parseBookingTimeZone(timeZone) {
|
|
|
1862
1904
|
|
|
1863
1905
|
//#endregion
|
|
1864
1906
|
//#region ../core/src/booking-date-time.ts
|
|
1865
|
-
const DEFAULT_LOCALE = "en-US";
|
|
1907
|
+
const DEFAULT_LOCALE$1 = "en-US";
|
|
1866
1908
|
const FALLBACK_TIMEZONE = "UTC";
|
|
1867
1909
|
const DEFAULT_BOOKING_DATE_TIME_FORMAT = {
|
|
1868
1910
|
weekday: "short",
|
|
@@ -1877,8 +1919,6 @@ const START_OF_DAY = {
|
|
|
1877
1919
|
second: 0
|
|
1878
1920
|
};
|
|
1879
1921
|
const LOCAL_DATE_PATTERN = /^(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})$/u;
|
|
1880
|
-
const DATE_TIME_FORMATTER_CACHE_LIMIT = 100;
|
|
1881
|
-
const dateTimeFormatterCache = new Map();
|
|
1882
1922
|
function getSafeTimeZone(timeZone) {
|
|
1883
1923
|
const normalized = typeof timeZone === "string" ? timeZone.trim() : "";
|
|
1884
1924
|
return normalized.length > 0 && isValidBookingTimeZone(normalized) ? normalized : FALLBACK_TIMEZONE;
|
|
@@ -1895,24 +1935,7 @@ function formatParseError(error) {
|
|
|
1895
1935
|
}
|
|
1896
1936
|
}
|
|
1897
1937
|
function formatToPartsLookup(date, locale, timeZone, format) {
|
|
1898
|
-
return new Map(
|
|
1899
|
-
}
|
|
1900
|
-
function getCachedDateTimeFormatter(locale, timeZone, format) {
|
|
1901
|
-
const formatKey = JSON.stringify(Object.entries(format).sort(([left], [right]) => left.localeCompare(right)));
|
|
1902
|
-
const key = `${locale}\u0000${timeZone}\u0000${formatKey}`;
|
|
1903
|
-
const cached = dateTimeFormatterCache.get(key);
|
|
1904
|
-
if (cached !== undefined) {
|
|
1905
|
-
return cached;
|
|
1906
|
-
}
|
|
1907
|
-
const formatter = new Intl.DateTimeFormat(locale, {
|
|
1908
|
-
...format,
|
|
1909
|
-
timeZone
|
|
1910
|
-
});
|
|
1911
|
-
if (dateTimeFormatterCache.size >= DATE_TIME_FORMATTER_CACHE_LIMIT) {
|
|
1912
|
-
dateTimeFormatterCache.clear();
|
|
1913
|
-
}
|
|
1914
|
-
dateTimeFormatterCache.set(key, formatter);
|
|
1915
|
-
return formatter;
|
|
1938
|
+
return new Map(getDateTimeFormatter(locale, timeZone, format).formatToParts(date).map((part) => [part.type, part.value]));
|
|
1916
1939
|
}
|
|
1917
1940
|
function getZonedDateTimeParts(date, timeZone) {
|
|
1918
1941
|
const parts = formatToPartsLookup(date, "en-GB", timeZone, {
|
|
@@ -2054,7 +2077,7 @@ function formatBookingInstant(isoString, options) {
|
|
|
2054
2077
|
if (Number.isNaN(date.getTime())) {
|
|
2055
2078
|
return isoString;
|
|
2056
2079
|
}
|
|
2057
|
-
return
|
|
2080
|
+
return getDateTimeFormatter(options.locale ?? DEFAULT_LOCALE$1, getSafeTimeZone(options.timeZone), options.format).format(date);
|
|
2058
2081
|
}
|
|
2059
2082
|
function formatBookingDate(input, format = {
|
|
2060
2083
|
weekday: "long",
|
|
@@ -2327,6 +2350,469 @@ function localScheduleDateTimeToUtcDate(localDate, localTime, timeZone) {
|
|
|
2327
2350
|
return new Date(guess);
|
|
2328
2351
|
}
|
|
2329
2352
|
|
|
2353
|
+
//#endregion
|
|
2354
|
+
//#region ../core/src/date-display.ts
|
|
2355
|
+
/** Site-language policy, shared by customer emails and public event adapters. */
|
|
2356
|
+
function inferSiteDateLocale(siteTimeZone) {
|
|
2357
|
+
if (siteTimeZone === null || siteTimeZone === undefined || siteTimeZone === "") return "en-US";
|
|
2358
|
+
if (siteTimeZone === "Europe/Dublin") return "en-IE";
|
|
2359
|
+
if (siteTimeZone.startsWith("Europe/")) return "en-GB";
|
|
2360
|
+
if (siteTimeZone.startsWith("Australia/")) return "en-AU";
|
|
2361
|
+
if (siteTimeZone === "Pacific/Auckland" || siteTimeZone === "Pacific/Chatham") return "en-NZ";
|
|
2362
|
+
return "en-US";
|
|
2363
|
+
}
|
|
2364
|
+
/** Callers resolve the facts once; all clocks consume the same label decision. */
|
|
2365
|
+
function resolveBookingDisplayContext(input) {
|
|
2366
|
+
return {
|
|
2367
|
+
context: {
|
|
2368
|
+
locale: input.locale,
|
|
2369
|
+
timeZone: input.sessionTimeZone
|
|
2370
|
+
},
|
|
2371
|
+
zone: input.surface === "email" && input.isOnline || input.sessionTimeZone !== input.siteTimeZone ? "always" : "omit"
|
|
2372
|
+
};
|
|
2373
|
+
}
|
|
2374
|
+
const SDK_STANDARD_TIME_FORMAT = {
|
|
2375
|
+
hour: "numeric",
|
|
2376
|
+
minute: "2-digit"
|
|
2377
|
+
};
|
|
2378
|
+
/** Public SDK option policy lives beside the display profile, never in its adapter. */
|
|
2379
|
+
function sdkPresentationProfile(context, dateFormat$1, time = {}) {
|
|
2380
|
+
const compact = time.timePresentation !== "standard" && new Intl.Locale(context.locale).language === "en";
|
|
2381
|
+
const standard = time.timePresentation === "standard" ? time.format ?? SDK_STANDARD_TIME_FORMAT : SDK_STANDARD_TIME_FORMAT;
|
|
2382
|
+
return {
|
|
2383
|
+
kind: "sdk",
|
|
2384
|
+
dateFormat: dateFormat$1,
|
|
2385
|
+
clock: compact ? {
|
|
2386
|
+
kind: "compact",
|
|
2387
|
+
localeSource: "context"
|
|
2388
|
+
} : {
|
|
2389
|
+
kind: "intl",
|
|
2390
|
+
format: standard
|
|
2391
|
+
},
|
|
2392
|
+
zone: "omit"
|
|
2393
|
+
};
|
|
2394
|
+
}
|
|
2395
|
+
function formatDate(value, context, options = {}) {
|
|
2396
|
+
return presentDate(value, context, displayProfile(options, "omit"));
|
|
2397
|
+
}
|
|
2398
|
+
function formatDateRange(start, endInclusive, context, options = {}) {
|
|
2399
|
+
return presentDateRange({
|
|
2400
|
+
kind: "civil",
|
|
2401
|
+
value: projectDate(start, context)
|
|
2402
|
+
}, {
|
|
2403
|
+
kind: "civil",
|
|
2404
|
+
value: projectDate(endInclusive, context)
|
|
2405
|
+
}, context, displayProfile(options, "omit"));
|
|
2406
|
+
}
|
|
2407
|
+
function formatDateTime(value, context, options) {
|
|
2408
|
+
return presentDateTime(value, context, displayProfile(options, options.zone));
|
|
2409
|
+
}
|
|
2410
|
+
function formatDateTimeRange(span, context, options) {
|
|
2411
|
+
return presentDateTimeRange(span, context, displayProfile(options, options.zone));
|
|
2412
|
+
}
|
|
2413
|
+
function formatTime(value, context, options) {
|
|
2414
|
+
return presentTime(value, context, displayProfile({}, options.zone));
|
|
2415
|
+
}
|
|
2416
|
+
function formatTimeRange(start, end, context, options) {
|
|
2417
|
+
return presentTimeRange({
|
|
2418
|
+
start,
|
|
2419
|
+
end
|
|
2420
|
+
}, context, displayProfile({}, options.zone));
|
|
2421
|
+
}
|
|
2422
|
+
/** Sole date projection/typography owner, used by display and scheduled adapters. */
|
|
2423
|
+
function presentDate(value, context, profile) {
|
|
2424
|
+
const date = dateCarrier(value);
|
|
2425
|
+
const zone = value.kind === "civil" ? "UTC" : context.timeZone;
|
|
2426
|
+
const output = getDateTimeFormatter(context.locale, zone, profile.dateFormat).format(date);
|
|
2427
|
+
if (profile.kind === "sdk") return output;
|
|
2428
|
+
const normalized = normalizeDisplay(output);
|
|
2429
|
+
return profile.dateFormat.weekday && new Intl.Locale(context.locale).language === "en" ? normalized.replace(/^([^,]+), /u, "$1 ") : normalized;
|
|
2430
|
+
}
|
|
2431
|
+
function presentDateRange(start, end, context, profile) {
|
|
2432
|
+
if (dateCarrier(end).getTime() < dateCarrier(start).getTime()) throw new RangeError("Date range end must be on or after its start");
|
|
2433
|
+
if (profile.kind === "display" && compareLocalScheduleDates(projectDate(start, context), projectDate(end, context)) === 0) {
|
|
2434
|
+
return presentDate(start, context, profile);
|
|
2435
|
+
}
|
|
2436
|
+
const output = formatIntlRange(getDateTimeFormatter(context.locale, start.kind === "civil" ? "UTC" : context.timeZone, profile.dateFormat), dateCarrier(start), dateCarrier(end));
|
|
2437
|
+
if (profile.kind === "sdk") return output;
|
|
2438
|
+
const startDate = projectDate(start, context);
|
|
2439
|
+
const endDate = projectDate(end, context);
|
|
2440
|
+
const separator = startDate.month === endDate.month && startDate.year === endDate.year ? "–" : " – ";
|
|
2441
|
+
return normalizeDisplay(output).replace(/\s*–\s*/gu, separator);
|
|
2442
|
+
}
|
|
2443
|
+
function presentTime(value, context, profile) {
|
|
2444
|
+
const clock = presentClock(value, context, profile.clock);
|
|
2445
|
+
return profile.zone === "always" ? `${clock} ${zoneLabel(value, context)}` : clock;
|
|
2446
|
+
}
|
|
2447
|
+
function presentDateTime(value, context, profile) {
|
|
2448
|
+
if (profile.clock.kind === "intl") {
|
|
2449
|
+
return getDateTimeFormatter(context.locale, context.timeZone, combinedFormat(profile.dateFormat, profile.clock)).format(new Date(value));
|
|
2450
|
+
}
|
|
2451
|
+
return `${presentDate({
|
|
2452
|
+
kind: "instant",
|
|
2453
|
+
value
|
|
2454
|
+
}, context, profile)}, ${presentTime(value, context, profile)}`;
|
|
2455
|
+
}
|
|
2456
|
+
function presentTimeRange(span, context, profile) {
|
|
2457
|
+
assertOrdered(span.start, span.end);
|
|
2458
|
+
if (profile.clock.kind === "intl") return presentNativeRange(span, context, profile.clock.format);
|
|
2459
|
+
const startClock = presentClock(span.start, context, profile.clock);
|
|
2460
|
+
const endClock = presentClock(span.end, context, profile.clock);
|
|
2461
|
+
const equal = profile.kind === "sdk" ? startClock === endClock : span.start === span.end;
|
|
2462
|
+
const clocks = equal ? startClock : `${startClock}–${endClock}`;
|
|
2463
|
+
const labels = decideRangeLabels(span, context, profile);
|
|
2464
|
+
switch (labels.kind) {
|
|
2465
|
+
case "omit": return clocks;
|
|
2466
|
+
case "shared": return `${clocks} ${labels.label}`;
|
|
2467
|
+
case "endpoints": return `${startClock} ${labels.start} – ${endClock} ${labels.end}`;
|
|
2468
|
+
}
|
|
2469
|
+
}
|
|
2470
|
+
function presentDateTimeRange(span, context, profile) {
|
|
2471
|
+
assertOrdered(span.start, span.end);
|
|
2472
|
+
if (profile.clock.kind === "intl") return presentNativeRange(span, context, combinedFormat(profile.dateFormat, profile.clock));
|
|
2473
|
+
const startDate = getLocalScheduleDate(new Date(span.start), context.timeZone);
|
|
2474
|
+
const endDate = getLocalScheduleDate(new Date(span.end), context.timeZone);
|
|
2475
|
+
if (compareLocalScheduleDates(startDate, endDate) === 0) {
|
|
2476
|
+
return `${presentDate({
|
|
2477
|
+
kind: "instant",
|
|
2478
|
+
value: span.start
|
|
2479
|
+
}, context, profile)}, ${presentTimeRange(span, context, profile)}`;
|
|
2480
|
+
}
|
|
2481
|
+
const labels = decideRangeLabels(span, context, profile);
|
|
2482
|
+
const startProfile = profile.kind === "display" && startDate.year === endDate.year ? {
|
|
2483
|
+
...profile,
|
|
2484
|
+
dateFormat: {
|
|
2485
|
+
...profile.dateFormat,
|
|
2486
|
+
year: undefined
|
|
2487
|
+
}
|
|
2488
|
+
} : profile;
|
|
2489
|
+
const start = presentRangeEndpoint(span.start, context, startProfile, labels.kind === "endpoints" ? labels.start : undefined);
|
|
2490
|
+
const end = presentRangeEndpoint(span.end, context, profile, labels.kind === "endpoints" ? labels.end : undefined);
|
|
2491
|
+
const separator = profile.kind === "sdk" ? "–" : " – ";
|
|
2492
|
+
return profile.kind === "sdk" && start === end ? start : `${start}${separator}${end}`;
|
|
2493
|
+
}
|
|
2494
|
+
/** Offset changes override ordinary venue omission for the approved display profile. */
|
|
2495
|
+
function decideRangeLabels(span, context, profile) {
|
|
2496
|
+
if (profile.kind === "sdk") return { kind: "omit" };
|
|
2497
|
+
const offsetsDiffer = offsetToken(span.start, context) !== offsetToken(span.end, context);
|
|
2498
|
+
if (!offsetsDiffer && profile.zone === "omit") return { kind: "omit" };
|
|
2499
|
+
const start = zoneLabel(span.start, context);
|
|
2500
|
+
const end = zoneLabel(span.end, context);
|
|
2501
|
+
return offsetsDiffer || start !== end ? {
|
|
2502
|
+
kind: "endpoints",
|
|
2503
|
+
start,
|
|
2504
|
+
end
|
|
2505
|
+
} : {
|
|
2506
|
+
kind: "shared",
|
|
2507
|
+
label: start
|
|
2508
|
+
};
|
|
2509
|
+
}
|
|
2510
|
+
function presentRangeEndpoint(value, context, profile, label) {
|
|
2511
|
+
const date = presentDate({
|
|
2512
|
+
kind: "instant",
|
|
2513
|
+
value
|
|
2514
|
+
}, context, profile);
|
|
2515
|
+
const time = label === undefined ? presentTime(value, context, profile) : `${presentClock(value, context, profile.clock)} ${label}`;
|
|
2516
|
+
return `${date}, ${time}`;
|
|
2517
|
+
}
|
|
2518
|
+
function presentNativeRange(span, context, format) {
|
|
2519
|
+
return formatIntlRange(getDateTimeFormatter(context.locale, context.timeZone, format), new Date(span.start), new Date(span.end));
|
|
2520
|
+
}
|
|
2521
|
+
function combinedFormat(date, clock) {
|
|
2522
|
+
return {
|
|
2523
|
+
...date,
|
|
2524
|
+
...clock.format
|
|
2525
|
+
};
|
|
2526
|
+
}
|
|
2527
|
+
function displayProfile(options, zone) {
|
|
2528
|
+
return {
|
|
2529
|
+
kind: "display",
|
|
2530
|
+
dateFormat: dateFormat(options),
|
|
2531
|
+
clock: {
|
|
2532
|
+
kind: "compact",
|
|
2533
|
+
localeSource: "product"
|
|
2534
|
+
},
|
|
2535
|
+
zone
|
|
2536
|
+
};
|
|
2537
|
+
}
|
|
2538
|
+
function dateCarrier(value) {
|
|
2539
|
+
return value.kind === "civil" ? civilCarrier(value.value) : new Date(value.value);
|
|
2540
|
+
}
|
|
2541
|
+
function presentClock(value, context, clock) {
|
|
2542
|
+
return clock.kind === "compact" ? formatBookingCompactEnglishTime({
|
|
2543
|
+
startsAt: value,
|
|
2544
|
+
timeZone: context.timeZone,
|
|
2545
|
+
locale: clock.localeSource === "product" ? "en-GB" : context.locale
|
|
2546
|
+
}) : getDateTimeFormatter(context.locale, context.timeZone, clock.format).format(new Date(value));
|
|
2547
|
+
}
|
|
2548
|
+
function offsetToken(value, context) {
|
|
2549
|
+
return getDateTimeFormatter("en-GB", context.timeZone, { timeZoneName: "longOffset" }).formatToParts(new Date(value)).find((part) => part.type === "timeZoneName")?.value ?? "";
|
|
2550
|
+
}
|
|
2551
|
+
function formatTimeAgo(value, now, context) {
|
|
2552
|
+
return formatRelative(value, now, context, "past");
|
|
2553
|
+
}
|
|
2554
|
+
function formatTimeUntil(value, now, context) {
|
|
2555
|
+
return formatRelative(value, now, context, "future");
|
|
2556
|
+
}
|
|
2557
|
+
function dateFormat(options) {
|
|
2558
|
+
const style = options.date ?? "long";
|
|
2559
|
+
return {
|
|
2560
|
+
day: style === "numeric" ? "2-digit" : "numeric",
|
|
2561
|
+
month: style === "numeric" ? "2-digit" : style,
|
|
2562
|
+
...options.year === "omit" ? {} : { year: "numeric" },
|
|
2563
|
+
...options.weekday ? { weekday: options.weekday } : {}
|
|
2564
|
+
};
|
|
2565
|
+
}
|
|
2566
|
+
function civilCarrier(value) {
|
|
2567
|
+
return new Date(Date.UTC(value.year, value.month - 1, value.day, 12));
|
|
2568
|
+
}
|
|
2569
|
+
function projectDate(value, context) {
|
|
2570
|
+
return value.kind === "civil" ? value.value : getLocalScheduleDate(new Date(value.value), context.timeZone);
|
|
2571
|
+
}
|
|
2572
|
+
function normalizeDisplay(value) {
|
|
2573
|
+
return value.replace(/[\u00a0\u202f]/gu, " ");
|
|
2574
|
+
}
|
|
2575
|
+
function zoneToken(value, context, locale) {
|
|
2576
|
+
return getDateTimeFormatter(locale, context.timeZone, { timeZoneName: "short" }).formatToParts(new Date(value)).find((part) => part.type === "timeZoneName")?.value ?? "";
|
|
2577
|
+
}
|
|
2578
|
+
function zoneLabel(value, context) {
|
|
2579
|
+
const tokens = [zoneToken(value, context, "en-GB"), zoneToken(value, context, "en-US")];
|
|
2580
|
+
const abbreviation = tokens.find((token) => /^[A-Z]{2,6}$/u.test(token));
|
|
2581
|
+
const fallback = context.timeZone.startsWith("Etc/") ? "local time" : `${context.timeZone.split("/").slice(-1)[0]?.replace(/_/gu, " ") ?? context.timeZone} time`;
|
|
2582
|
+
return abbreviation ?? fallback;
|
|
2583
|
+
}
|
|
2584
|
+
function assertOrdered(start, end) {
|
|
2585
|
+
if (new Date(end).getTime() < new Date(start).getTime()) {
|
|
2586
|
+
throw new RangeError("Date/time range end must be on or after its start");
|
|
2587
|
+
}
|
|
2588
|
+
}
|
|
2589
|
+
function calendarDayDifference(value, now, context) {
|
|
2590
|
+
return compareLocalScheduleDates(getLocalScheduleDate(new Date(value), context.timeZone), getLocalScheduleDate(new Date(now), context.timeZone)) / 864e5;
|
|
2591
|
+
}
|
|
2592
|
+
function formatRelative(value, now, context, direction) {
|
|
2593
|
+
const seconds = (new Date(value).getTime() - new Date(now).getTime()) / 1e3;
|
|
2594
|
+
const magnitude = Math.abs(seconds);
|
|
2595
|
+
if (magnitude < 60) return relativeNearNow(context.locale, direction);
|
|
2596
|
+
const days = calendarDayDifference(value, now, context);
|
|
2597
|
+
if (Math.abs(days) > 7) return formatDate({
|
|
2598
|
+
kind: "instant",
|
|
2599
|
+
value
|
|
2600
|
+
}, context);
|
|
2601
|
+
const formatter = new Intl.RelativeTimeFormat(context.locale, { numeric: "auto" });
|
|
2602
|
+
if (days !== 0) return formatter.format(days, "day");
|
|
2603
|
+
const unit = magnitude < 3600 ? "minute" : "hour";
|
|
2604
|
+
const signedCount = Math.sign(seconds) * Math.floor(magnitude / (unit === "minute" ? 60 : 3600));
|
|
2605
|
+
return formatter.format(signedCount, unit);
|
|
2606
|
+
}
|
|
2607
|
+
function relativeNearNow(locale, direction) {
|
|
2608
|
+
if (new Intl.Locale(locale).language === "en") return direction === "past" ? "just now" : "in a moment";
|
|
2609
|
+
return new Intl.RelativeTimeFormat(locale, { numeric: "auto" }).format(0, "second");
|
|
2610
|
+
}
|
|
2611
|
+
|
|
2612
|
+
//#endregion
|
|
2613
|
+
//#region ../core/src/scheduled-date-time.ts
|
|
2614
|
+
const DEFAULT_LOCALE = "en-GB";
|
|
2615
|
+
const FORMATTER_CACHE_LIMIT = 100;
|
|
2616
|
+
const DEFAULT_DATE_FORMAT = {
|
|
2617
|
+
weekday: "long",
|
|
2618
|
+
year: "numeric",
|
|
2619
|
+
month: "long",
|
|
2620
|
+
day: "numeric"
|
|
2621
|
+
};
|
|
2622
|
+
const DEFAULT_RANGE_DATE_FORMAT = {
|
|
2623
|
+
weekday: "short",
|
|
2624
|
+
year: "numeric",
|
|
2625
|
+
month: "short",
|
|
2626
|
+
day: "numeric"
|
|
2627
|
+
};
|
|
2628
|
+
const parsedLocaleCache = new Map();
|
|
2629
|
+
var RiverbankDateTimeFormatError = class extends Error {
|
|
2630
|
+
constructor(details) {
|
|
2631
|
+
super(formatErrorMessage(details));
|
|
2632
|
+
this.name = "RiverbankDateTimeFormatError";
|
|
2633
|
+
this.code = details.code;
|
|
2634
|
+
this.field = details.field;
|
|
2635
|
+
this.value = details.value;
|
|
2636
|
+
}
|
|
2637
|
+
};
|
|
2638
|
+
/** Public contract adapters: admission/options here, all presentation in date-display. */
|
|
2639
|
+
function formatScheduledDate(input, options = {}) {
|
|
2640
|
+
const parsed = parseDateTime(input);
|
|
2641
|
+
return presentDate({
|
|
2642
|
+
kind: "instant",
|
|
2643
|
+
value: parsed.startsAt
|
|
2644
|
+
}, scheduledContext(parsed), sdkPresentationProfile(scheduledContext(parsed), options.format ?? DEFAULT_DATE_FORMAT));
|
|
2645
|
+
}
|
|
2646
|
+
function formatScheduledTime(input, options = {}) {
|
|
2647
|
+
const parsed = parseDateTime(input);
|
|
2648
|
+
return presentTime(parsed.startsAt, scheduledContext(parsed), sdkPresentationProfile(scheduledContext(parsed), {}, options));
|
|
2649
|
+
}
|
|
2650
|
+
function formatScheduledDateTime(input, options = {}) {
|
|
2651
|
+
const parsed = parseDateTime(input);
|
|
2652
|
+
return presentDateTime(parsed.startsAt, scheduledContext(parsed), sdkPresentationProfile(scheduledContext(parsed), options.dateFormat ?? DEFAULT_DATE_FORMAT, options.time));
|
|
2653
|
+
}
|
|
2654
|
+
function formatScheduledDateRange(input, options = {}) {
|
|
2655
|
+
const parsed = parseDateRange(input);
|
|
2656
|
+
return presentDateRange({
|
|
2657
|
+
kind: "instant",
|
|
2658
|
+
value: parsed.startsAt
|
|
2659
|
+
}, {
|
|
2660
|
+
kind: "instant",
|
|
2661
|
+
value: parsed.endsAt
|
|
2662
|
+
}, scheduledContext(parsed), sdkPresentationProfile(scheduledContext(parsed), options.format ?? DEFAULT_RANGE_DATE_FORMAT));
|
|
2663
|
+
}
|
|
2664
|
+
function formatScheduledTimeRange(input, options = {}) {
|
|
2665
|
+
const parsed = parseDateRange(input);
|
|
2666
|
+
return presentTimeRange({
|
|
2667
|
+
start: parsed.startsAt,
|
|
2668
|
+
end: parsed.endsAt
|
|
2669
|
+
}, scheduledContext(parsed), sdkPresentationProfile(scheduledContext(parsed), {}, options));
|
|
2670
|
+
}
|
|
2671
|
+
function formatScheduledDateTimeRange(input, options = {}) {
|
|
2672
|
+
const parsed = parseDateRange(input);
|
|
2673
|
+
return presentDateTimeRange({
|
|
2674
|
+
start: parsed.startsAt,
|
|
2675
|
+
end: parsed.endsAt
|
|
2676
|
+
}, scheduledContext(parsed), sdkPresentationProfile(scheduledContext(parsed), options.dateFormat ?? DEFAULT_RANGE_DATE_FORMAT, options.time));
|
|
2677
|
+
}
|
|
2678
|
+
function scheduledContext(input) {
|
|
2679
|
+
return {
|
|
2680
|
+
locale: input.locale,
|
|
2681
|
+
timeZone: input.timeZone
|
|
2682
|
+
};
|
|
2683
|
+
}
|
|
2684
|
+
function parseDateTime(input) {
|
|
2685
|
+
const locale = parseLocale(input.locale);
|
|
2686
|
+
assertStringTimeZone(input.timeZone);
|
|
2687
|
+
const result = parseScheduledBookingDateTime({
|
|
2688
|
+
...input,
|
|
2689
|
+
locale: locale.locale
|
|
2690
|
+
});
|
|
2691
|
+
if (result.ok) {
|
|
2692
|
+
return {
|
|
2693
|
+
...result.value,
|
|
2694
|
+
locale: locale.locale
|
|
2695
|
+
};
|
|
2696
|
+
}
|
|
2697
|
+
throw fromCoreParseError(result);
|
|
2698
|
+
}
|
|
2699
|
+
function parseDateRange(input) {
|
|
2700
|
+
const locale = parseLocale(input.locale);
|
|
2701
|
+
assertStringTimeZone(input.timeZone);
|
|
2702
|
+
assertRequiredEnd(input.endsAt);
|
|
2703
|
+
const result = parseScheduledBookingDateRange({
|
|
2704
|
+
...input,
|
|
2705
|
+
locale: locale.locale
|
|
2706
|
+
});
|
|
2707
|
+
if (!result.ok) {
|
|
2708
|
+
throw fromCoreParseError(result);
|
|
2709
|
+
}
|
|
2710
|
+
if (result.value.endsAt === null || result.value.endsAt === undefined) {
|
|
2711
|
+
throw new RiverbankDateTimeFormatError({
|
|
2712
|
+
code: "missing_ends_at",
|
|
2713
|
+
field: "endsAt",
|
|
2714
|
+
value: ""
|
|
2715
|
+
});
|
|
2716
|
+
}
|
|
2717
|
+
if (new Date(result.value.endsAt).getTime() < new Date(result.value.startsAt).getTime()) {
|
|
2718
|
+
throw new RiverbankDateTimeFormatError({
|
|
2719
|
+
code: "end_before_start",
|
|
2720
|
+
field: "endsAt",
|
|
2721
|
+
value: input.endsAt
|
|
2722
|
+
});
|
|
2723
|
+
}
|
|
2724
|
+
return {
|
|
2725
|
+
...result.value,
|
|
2726
|
+
endsAt: result.value.endsAt,
|
|
2727
|
+
locale: locale.locale
|
|
2728
|
+
};
|
|
2729
|
+
}
|
|
2730
|
+
function assertRequiredEnd(value) {
|
|
2731
|
+
if (value === null || value === undefined) {
|
|
2732
|
+
throw new RiverbankDateTimeFormatError({
|
|
2733
|
+
code: "missing_ends_at",
|
|
2734
|
+
field: "endsAt",
|
|
2735
|
+
value: ""
|
|
2736
|
+
});
|
|
2737
|
+
}
|
|
2738
|
+
}
|
|
2739
|
+
function parseLocale(value) {
|
|
2740
|
+
const locale = value === undefined ? DEFAULT_LOCALE : value;
|
|
2741
|
+
if (typeof locale !== "string") {
|
|
2742
|
+
throw new RiverbankDateTimeFormatError({
|
|
2743
|
+
code: "invalid_locale",
|
|
2744
|
+
field: "locale",
|
|
2745
|
+
value: ""
|
|
2746
|
+
});
|
|
2747
|
+
}
|
|
2748
|
+
const cached = parsedLocaleCache.get(locale);
|
|
2749
|
+
if (cached !== undefined) {
|
|
2750
|
+
return cached;
|
|
2751
|
+
}
|
|
2752
|
+
try {
|
|
2753
|
+
const parsed = new Intl.Locale(locale);
|
|
2754
|
+
const canonical = parsed.toString();
|
|
2755
|
+
if (Intl.DateTimeFormat.supportedLocalesOf([canonical]).length === 0) {
|
|
2756
|
+
throw new RangeError("Unsupported locale");
|
|
2757
|
+
}
|
|
2758
|
+
const result = { locale: canonical };
|
|
2759
|
+
if (parsedLocaleCache.size >= FORMATTER_CACHE_LIMIT) {
|
|
2760
|
+
parsedLocaleCache.clear();
|
|
2761
|
+
}
|
|
2762
|
+
parsedLocaleCache.set(locale, result);
|
|
2763
|
+
return result;
|
|
2764
|
+
} catch {
|
|
2765
|
+
throw new RiverbankDateTimeFormatError({
|
|
2766
|
+
code: "invalid_locale",
|
|
2767
|
+
field: "locale",
|
|
2768
|
+
value: typeof value === "string" ? value : ""
|
|
2769
|
+
});
|
|
2770
|
+
}
|
|
2771
|
+
}
|
|
2772
|
+
function assertStringTimeZone(value) {
|
|
2773
|
+
if (typeof value !== "string") {
|
|
2774
|
+
throw new RiverbankDateTimeFormatError({
|
|
2775
|
+
code: "invalid_time_zone",
|
|
2776
|
+
field: "timeZone",
|
|
2777
|
+
value: ""
|
|
2778
|
+
});
|
|
2779
|
+
}
|
|
2780
|
+
}
|
|
2781
|
+
function fromCoreParseError(error) {
|
|
2782
|
+
switch (error.reason) {
|
|
2783
|
+
case "invalid_starts_at": return new RiverbankDateTimeFormatError({
|
|
2784
|
+
code: error.reason,
|
|
2785
|
+
field: error.field,
|
|
2786
|
+
value: typeof error.value === "string" ? error.value : ""
|
|
2787
|
+
});
|
|
2788
|
+
case "invalid_ends_at": return new RiverbankDateTimeFormatError({
|
|
2789
|
+
code: error.reason,
|
|
2790
|
+
field: error.field,
|
|
2791
|
+
value: typeof error.value === "string" ? error.value : ""
|
|
2792
|
+
});
|
|
2793
|
+
case "invalid_time_zone": return new RiverbankDateTimeFormatError({
|
|
2794
|
+
code: error.reason,
|
|
2795
|
+
field: error.field,
|
|
2796
|
+
value: error.value
|
|
2797
|
+
});
|
|
2798
|
+
default: return assertNever$3(error);
|
|
2799
|
+
}
|
|
2800
|
+
}
|
|
2801
|
+
function formatErrorMessage(details) {
|
|
2802
|
+
switch (details.code) {
|
|
2803
|
+
case "invalid_starts_at": return `Expected startsAt to be a valid offset-aware ISO datetime, received "${details.value}"`;
|
|
2804
|
+
case "invalid_ends_at": return `Expected endsAt to be a valid offset-aware ISO datetime, received "${details.value}"`;
|
|
2805
|
+
case "missing_ends_at": return "Expected endsAt to be provided for a scheduled range";
|
|
2806
|
+
case "invalid_time_zone": return `Expected timeZone to be a valid IANA timezone, received "${details.value}"`;
|
|
2807
|
+
case "invalid_locale": return `Expected locale to be a supported BCP 47 locale, received "${details.value}"`;
|
|
2808
|
+
case "end_before_start": return `Expected endsAt to be on or after startsAt, received "${details.value}"`;
|
|
2809
|
+
default: return assertNever$3(details);
|
|
2810
|
+
}
|
|
2811
|
+
}
|
|
2812
|
+
function assertNever$3(value) {
|
|
2813
|
+
throw new Error(`Unhandled date-time variant: ${String(value)}`);
|
|
2814
|
+
}
|
|
2815
|
+
|
|
2330
2816
|
//#endregion
|
|
2331
2817
|
//#region ../core/src/appointment-service-categories.ts
|
|
2332
2818
|
/**
|
|
@@ -3733,6 +4219,32 @@ function parsePublicSocialLinks(value) {
|
|
|
3733
4219
|
}
|
|
3734
4220
|
return ok(links);
|
|
3735
4221
|
}
|
|
4222
|
+
/** Historical stored profiles read absent description as null. */
|
|
4223
|
+
function parsePublicBusinessDescription(value) {
|
|
4224
|
+
const description = trimmedOptionalString(value);
|
|
4225
|
+
return description === undefined || description !== null && description.length > 2e3 ? err({
|
|
4226
|
+
code: "invalid_business_description",
|
|
4227
|
+
path: "businessDescription",
|
|
4228
|
+
message: "Use a business description of 2,000 characters or fewer."
|
|
4229
|
+
}) : ok(description);
|
|
4230
|
+
}
|
|
4231
|
+
/** Public copy and visibility preferences share historical absent-field defaults. */
|
|
4232
|
+
function parsePublicProfilePresentation(value) {
|
|
4233
|
+
const businessDescription = parsePublicBusinessDescription(value.businessDescription);
|
|
4234
|
+
if (!businessDescription.ok) return businessDescription;
|
|
4235
|
+
const addressVisibility = parseAddressVisibility(value.addressVisibility);
|
|
4236
|
+
if (!addressVisibility.ok) return addressVisibility;
|
|
4237
|
+
const contactVisibility = parseContactVisibility(value.contactVisibility);
|
|
4238
|
+
if (!contactVisibility.ok) return contactVisibility;
|
|
4239
|
+
const premises = parsePremises(value.premises);
|
|
4240
|
+
if (!premises.ok) return premises;
|
|
4241
|
+
return ok({
|
|
4242
|
+
businessDescription: businessDescription.value,
|
|
4243
|
+
addressVisibility: addressVisibility.value,
|
|
4244
|
+
contactVisibility: contactVisibility.value,
|
|
4245
|
+
premises: premises.value
|
|
4246
|
+
});
|
|
4247
|
+
}
|
|
3736
4248
|
function parsePublicProfile(value) {
|
|
3737
4249
|
if (!isRecord$8(value)) {
|
|
3738
4250
|
return err({
|
|
@@ -3741,25 +4253,19 @@ function parsePublicProfile(value) {
|
|
|
3741
4253
|
message: "Public profile must be an object."
|
|
3742
4254
|
});
|
|
3743
4255
|
}
|
|
4256
|
+
const presentation = parsePublicProfilePresentation(value);
|
|
4257
|
+
if (!presentation.ok) return presentation;
|
|
3744
4258
|
const contact = value.contact === null ? ok(null) : parsePublicContactDetails(value.contact);
|
|
3745
4259
|
if (!contact.ok) return contact;
|
|
3746
4260
|
const openingHours = value.openingHours === null ? ok(null) : parseWeeklyOpeningHours(value.openingHours);
|
|
3747
4261
|
if (!openingHours.ok) return openingHours;
|
|
3748
4262
|
const socialLinks = parsePublicSocialLinks(value.socialLinks);
|
|
3749
4263
|
if (!socialLinks.ok) return socialLinks;
|
|
3750
|
-
const addressVisibility = parseAddressVisibility(value.addressVisibility);
|
|
3751
|
-
if (!addressVisibility.ok) return addressVisibility;
|
|
3752
|
-
const contactVisibility = parseContactVisibility(value.contactVisibility);
|
|
3753
|
-
if (!contactVisibility.ok) return contactVisibility;
|
|
3754
|
-
const premises = parsePremises(value.premises);
|
|
3755
|
-
if (!premises.ok) return premises;
|
|
3756
4264
|
return ok({
|
|
4265
|
+
...presentation.value,
|
|
3757
4266
|
contact: contact.value,
|
|
3758
|
-
contactVisibility: contactVisibility.value,
|
|
3759
4267
|
openingHours: openingHours.value,
|
|
3760
|
-
socialLinks: socialLinks.value
|
|
3761
|
-
addressVisibility: addressVisibility.value,
|
|
3762
|
-
premises: premises.value
|
|
4268
|
+
socialLinks: socialLinks.value
|
|
3763
4269
|
});
|
|
3764
4270
|
}
|
|
3765
4271
|
function parseFieldVisibility(value, path) {
|
|
@@ -3853,6 +4359,7 @@ function parseAddressVisibility(value) {
|
|
|
3853
4359
|
}
|
|
3854
4360
|
function emptyPublicProfile() {
|
|
3855
4361
|
return {
|
|
4362
|
+
businessDescription: null,
|
|
3856
4363
|
contact: null,
|
|
3857
4364
|
contactVisibility: {
|
|
3858
4365
|
phone: "shown",
|
|
@@ -3928,7 +4435,7 @@ function parsePositiveInteger(value) {
|
|
|
3928
4435
|
return typeof value === "number" && Number.isSafeInteger(value) && value > 0 ? value : null;
|
|
3929
4436
|
}
|
|
3930
4437
|
function parseNewsletterListId(value) {
|
|
3931
|
-
return parseTrimmedMatchingString(value, UUID_PATTERN);
|
|
4438
|
+
return parseTrimmedMatchingString(typeof value === "string" ? value.toLowerCase() : value, UUID_PATTERN);
|
|
3932
4439
|
}
|
|
3933
4440
|
function parseMailchimpConnectionId(value) {
|
|
3934
4441
|
return parseTrimmedMatchingString(value, UUID_PATTERN);
|
|
@@ -3972,7 +4479,7 @@ function sameMailingListPlacementTargeting(left, right) {
|
|
|
3972
4479
|
}
|
|
3973
4480
|
function mailingListTargetingChoiceIds(targeting) {
|
|
3974
4481
|
switch (targeting.provider) {
|
|
3975
|
-
case "native": return targeting.selection.tag === "fixed" ? targeting.selection.topicIds : targeting.selection.offeredTopicIds;
|
|
4482
|
+
case "native": return targeting.selection.tag === "general" ? [] : targeting.selection.tag === "fixed" ? targeting.selection.topicIds : targeting.selection.offeredTopicIds;
|
|
3976
4483
|
case "brevo": return targeting.selection.tag === "fixed" ? targeting.selection.listIds : targeting.selection.offeredListIds;
|
|
3977
4484
|
case "mailchimp": return targeting.selection.tag === "fixed" ? targeting.selection.interestIds : targeting.selection.offeredInterestIds;
|
|
3978
4485
|
}
|
|
@@ -4002,7 +4509,10 @@ function resolveDefaultTarget(setup) {
|
|
|
4002
4509
|
switch (setup.provider) {
|
|
4003
4510
|
case "native": return {
|
|
4004
4511
|
provider: "native",
|
|
4005
|
-
|
|
4512
|
+
audience: setup.defaultAudience.kind === "general" ? { kind: "general" } : {
|
|
4513
|
+
kind: "topics",
|
|
4514
|
+
topicIds: [setup.defaultAudience.topicId]
|
|
4515
|
+
}
|
|
4006
4516
|
};
|
|
4007
4517
|
case "brevo": return {
|
|
4008
4518
|
provider: "brevo",
|
|
@@ -4023,16 +4533,28 @@ function resolveCustomTarget(targeting, visitorSelection) {
|
|
|
4023
4533
|
}
|
|
4024
4534
|
}
|
|
4025
4535
|
function resolveNativeTarget(targeting, selection) {
|
|
4536
|
+
if (targeting.selection.tag === "general") {
|
|
4537
|
+
return selection === undefined ? ok({
|
|
4538
|
+
provider: "native",
|
|
4539
|
+
audience: { kind: "general" }
|
|
4540
|
+
}) : err({ tag: "visitor_selection_not_allowed" });
|
|
4541
|
+
}
|
|
4026
4542
|
if (targeting.selection.tag === "fixed") {
|
|
4027
4543
|
return selection === undefined ? ok({
|
|
4028
4544
|
provider: "native",
|
|
4029
|
-
|
|
4545
|
+
audience: {
|
|
4546
|
+
kind: "topics",
|
|
4547
|
+
topicIds: targeting.selection.topicIds
|
|
4548
|
+
}
|
|
4030
4549
|
}) : err({ tag: "visitor_selection_not_allowed" });
|
|
4031
4550
|
}
|
|
4032
4551
|
if (selection === undefined) {
|
|
4033
4552
|
return targeting.selection.offeredTopicIds.length === 1 ? ok({
|
|
4034
4553
|
provider: "native",
|
|
4035
|
-
|
|
4554
|
+
audience: {
|
|
4555
|
+
kind: "topics",
|
|
4556
|
+
topicIds: targeting.selection.offeredTopicIds
|
|
4557
|
+
}
|
|
4036
4558
|
}) : err({ tag: "visitor_selection_required" });
|
|
4037
4559
|
}
|
|
4038
4560
|
if (selection.provider !== "native") {
|
|
@@ -4041,7 +4563,10 @@ function resolveNativeTarget(targeting, selection) {
|
|
|
4041
4563
|
const selected = selectedNonEmptySubset(selection.topicIds, targeting.selection.offeredTopicIds);
|
|
4042
4564
|
return selected.ok ? ok({
|
|
4043
4565
|
provider: "native",
|
|
4044
|
-
|
|
4566
|
+
audience: {
|
|
4567
|
+
kind: "topics",
|
|
4568
|
+
topicIds: selected.value
|
|
4569
|
+
}
|
|
4045
4570
|
}) : err({ tag: "visitor_selection_outside_offer" });
|
|
4046
4571
|
}
|
|
4047
4572
|
function resolveBrevoTarget(targeting, selection) {
|
|
@@ -4100,45 +4625,34 @@ function selectedNonEmptySubset(selected, offered) {
|
|
|
4100
4625
|
return ok([first, ...rest]);
|
|
4101
4626
|
}
|
|
4102
4627
|
function planMailingListChoicePresentation(targeting) {
|
|
4103
|
-
if (targeting.mode === "default" || targeting.selection.tag === "fixed") {
|
|
4628
|
+
if (targeting.mode === "default" || targeting.selection.tag === "fixed" || targeting.selection.tag === "general") {
|
|
4104
4629
|
return { tag: "hidden" };
|
|
4105
4630
|
}
|
|
4106
4631
|
switch (targeting.provider) {
|
|
4107
|
-
case "native": return
|
|
4108
|
-
tag: "automatic",
|
|
4109
|
-
selection: {
|
|
4110
|
-
provider: "native",
|
|
4111
|
-
topicIds: targeting.selection.offeredTopicIds
|
|
4112
|
-
}
|
|
4113
|
-
} : {
|
|
4114
|
-
tag: "visitor_choice",
|
|
4632
|
+
case "native": return presentVisitorSelection({
|
|
4115
4633
|
provider: "native",
|
|
4116
|
-
|
|
4117
|
-
};
|
|
4118
|
-
case "brevo": return
|
|
4119
|
-
tag: "automatic",
|
|
4120
|
-
selection: {
|
|
4121
|
-
provider: "brevo",
|
|
4122
|
-
listIds: targeting.selection.offeredListIds
|
|
4123
|
-
}
|
|
4124
|
-
} : {
|
|
4125
|
-
tag: "visitor_choice",
|
|
4634
|
+
topicIds: targeting.selection.offeredTopicIds
|
|
4635
|
+
}, targeting.selection.offeredTopicIds.length);
|
|
4636
|
+
case "brevo": return presentVisitorSelection({
|
|
4126
4637
|
provider: "brevo",
|
|
4127
|
-
|
|
4128
|
-
};
|
|
4129
|
-
case "mailchimp": return
|
|
4130
|
-
tag: "automatic",
|
|
4131
|
-
selection: {
|
|
4132
|
-
provider: "mailchimp",
|
|
4133
|
-
interestIds: targeting.selection.offeredInterestIds
|
|
4134
|
-
}
|
|
4135
|
-
} : {
|
|
4136
|
-
tag: "visitor_choice",
|
|
4638
|
+
listIds: targeting.selection.offeredListIds
|
|
4639
|
+
}, targeting.selection.offeredListIds.length);
|
|
4640
|
+
case "mailchimp": return presentVisitorSelection({
|
|
4137
4641
|
provider: "mailchimp",
|
|
4138
|
-
|
|
4139
|
-
};
|
|
4642
|
+
interestIds: targeting.selection.offeredInterestIds
|
|
4643
|
+
}, targeting.selection.offeredInterestIds.length);
|
|
4140
4644
|
}
|
|
4141
4645
|
}
|
|
4646
|
+
function presentVisitorSelection(selection, optionCount) {
|
|
4647
|
+
return optionCount === 1 ? {
|
|
4648
|
+
tag: "automatic",
|
|
4649
|
+
selection
|
|
4650
|
+
} : {
|
|
4651
|
+
tag: "visitor_choice",
|
|
4652
|
+
provider: selection.provider,
|
|
4653
|
+
optionCount
|
|
4654
|
+
};
|
|
4655
|
+
}
|
|
4142
4656
|
|
|
4143
4657
|
//#endregion
|
|
4144
4658
|
//#region ../core/src/mailing-list-targeting-parser.ts
|
|
@@ -4159,6 +4673,7 @@ function parseMailingListVisitorSelection(value) {
|
|
|
4159
4673
|
if (!isRecord$6(value)) return visitorSelectionError("shape");
|
|
4160
4674
|
switch (value.provider) {
|
|
4161
4675
|
case "native": {
|
|
4676
|
+
if (Object.keys(value).some((key) => key !== "provider" && key !== "topicIds")) return visitorSelectionError("shape");
|
|
4162
4677
|
const topicIds = parseVisitorIds(value.topicIds, parseNewsletterListId);
|
|
4163
4678
|
return topicIds === null ? visitorSelectionError("targets") : ok({
|
|
4164
4679
|
provider: "native",
|
|
@@ -4183,6 +4698,13 @@ function parseMailingListVisitorSelection(value) {
|
|
|
4183
4698
|
}
|
|
4184
4699
|
}
|
|
4185
4700
|
function parseNativeTargeting(selection) {
|
|
4701
|
+
if (selection.tag === "general") {
|
|
4702
|
+
return Object.keys(selection).length === 1 ? ok({
|
|
4703
|
+
mode: "custom",
|
|
4704
|
+
provider: "native",
|
|
4705
|
+
selection: { tag: "general" }
|
|
4706
|
+
}) : targetingError("selection");
|
|
4707
|
+
}
|
|
4186
4708
|
if (selection.tag === "fixed") {
|
|
4187
4709
|
const topicIds = parseNonEmptyUniqueIds(selection.topicIds, parseNewsletterListId);
|
|
4188
4710
|
return topicIds.ok ? ok({
|
|
@@ -4388,6 +4910,18 @@ function parseFooterEngagementSectionValue(value, sectionBase, path) {
|
|
|
4388
4910
|
}
|
|
4389
4911
|
}
|
|
4390
4912
|
|
|
4913
|
+
//#endregion
|
|
4914
|
+
//#region ../core/src/footer-navigation-layout.ts
|
|
4915
|
+
const footerNavigationLayouts = ["stack", "inline-wrap"];
|
|
4916
|
+
const defaultFooterNavigationLayout = "inline-wrap";
|
|
4917
|
+
function normalizeFooterNavigationLayout(value) {
|
|
4918
|
+
return value === "stack" ? "stack" : defaultFooterNavigationLayout;
|
|
4919
|
+
}
|
|
4920
|
+
/** The arrangement chooses presentation; the stored preference remains intact. */
|
|
4921
|
+
function effectiveFooterNavigationLayout(arrangement, stored) {
|
|
4922
|
+
return arrangement === "centred" ? "inline-wrap" : stored;
|
|
4923
|
+
}
|
|
4924
|
+
|
|
4391
4925
|
//#endregion
|
|
4392
4926
|
//#region ../core/src/footer-arrangement.ts
|
|
4393
4927
|
const sectionKinds = [
|
|
@@ -4402,85 +4936,119 @@ const sectionKinds = [
|
|
|
4402
4936
|
"legal-navigation",
|
|
4403
4937
|
"legal"
|
|
4404
4938
|
];
|
|
4405
|
-
const
|
|
4406
|
-
|
|
4939
|
+
const centredSectionKinds = [
|
|
4940
|
+
"brand",
|
|
4941
|
+
"supporting-text",
|
|
4942
|
+
"navigation",
|
|
4943
|
+
"contact",
|
|
4944
|
+
"business-address",
|
|
4945
|
+
"opening-hours",
|
|
4946
|
+
"social-links",
|
|
4947
|
+
"engagement",
|
|
4948
|
+
"legal",
|
|
4949
|
+
"legal-navigation"
|
|
4950
|
+
];
|
|
4951
|
+
/** Section ownership is exhaustive for both arrangements; content never changes placement. */
|
|
4952
|
+
const rowSectionGroups = {
|
|
4953
|
+
brand: "identity",
|
|
4954
|
+
"supporting-text": "identity",
|
|
4955
|
+
"social-links": "identity",
|
|
4956
|
+
navigation: "main-navigation",
|
|
4957
|
+
"business-address": "visit",
|
|
4958
|
+
contact: "visit",
|
|
4959
|
+
"opening-hours": "visit",
|
|
4960
|
+
engagement: "engagement",
|
|
4961
|
+
"legal-navigation": "legal-ending",
|
|
4962
|
+
legal: "legal-ending"
|
|
4963
|
+
};
|
|
4964
|
+
const centredSectionGroups = {
|
|
4965
|
+
...rowSectionGroups,
|
|
4966
|
+
"social-links": "social"
|
|
4967
|
+
};
|
|
4968
|
+
const rowGroupOrder = [
|
|
4407
4969
|
"identity",
|
|
4408
4970
|
"main-navigation",
|
|
4409
4971
|
"visit",
|
|
4410
4972
|
"engagement",
|
|
4411
4973
|
"legal-ending"
|
|
4412
4974
|
];
|
|
4413
|
-
|
|
4414
|
-
|
|
4415
|
-
|
|
4416
|
-
|
|
4417
|
-
|
|
4418
|
-
|
|
4419
|
-
|
|
4420
|
-
|
|
4421
|
-
|
|
4422
|
-
|
|
4423
|
-
|
|
4424
|
-
|
|
4425
|
-
|
|
4975
|
+
const centredGroupOrder = [
|
|
4976
|
+
"identity",
|
|
4977
|
+
"main-navigation",
|
|
4978
|
+
"visit",
|
|
4979
|
+
"social",
|
|
4980
|
+
"engagement",
|
|
4981
|
+
"legal-ending"
|
|
4982
|
+
];
|
|
4983
|
+
const groupSlots = {
|
|
4984
|
+
identity: "head",
|
|
4985
|
+
"main-navigation": "navigation",
|
|
4986
|
+
visit: "contact",
|
|
4987
|
+
social: "social",
|
|
4988
|
+
engagement: "panel",
|
|
4989
|
+
"legal-ending": "base"
|
|
4990
|
+
};
|
|
4991
|
+
const regionSlots = {
|
|
4992
|
+
"engagement-row": "panel",
|
|
4993
|
+
main: "stack",
|
|
4994
|
+
bottom: "base"
|
|
4995
|
+
};
|
|
4996
|
+
/** One policy owner for the served footer and its composition preview. */
|
|
4997
|
+
function footerArrangementPolicy(input) {
|
|
4998
|
+
const arrangement = input.arrangement ?? "simple";
|
|
4999
|
+
return {
|
|
5000
|
+
arrangement,
|
|
5001
|
+
kind: arrangement === "centred" || input.legalRegion === "separate" ? "separate-legal-region" : "integrated-legal",
|
|
5002
|
+
navigationLayout: effectiveFooterNavigationLayout(arrangement, normalizeFooterNavigationLayout(input.storedNavigationLayout))
|
|
5003
|
+
};
|
|
4426
5004
|
}
|
|
4427
|
-
function buildGroups(sections,
|
|
4428
|
-
const
|
|
4429
|
-
|
|
4430
|
-
|
|
4431
|
-
|
|
4432
|
-
|
|
4433
|
-
|
|
4434
|
-
|
|
4435
|
-
return groupSections === undefined || groupSections.length === 0 ? [] : [{
|
|
5005
|
+
function buildGroups(sections, policy) {
|
|
5006
|
+
const centred = policy.arrangement === "centred";
|
|
5007
|
+
const order = centred ? centredGroupOrder : rowGroupOrder;
|
|
5008
|
+
const owners = centred ? centredSectionGroups : rowSectionGroups;
|
|
5009
|
+
const sectionOrder = centred ? centredSectionKinds : sectionKinds;
|
|
5010
|
+
return order.flatMap((kind) => {
|
|
5011
|
+
const groupSections = sections.filter((section) => owners[section.kind] === kind).sort((left, right) => sectionOrder.indexOf(left.kind) - sectionOrder.indexOf(right.kind));
|
|
5012
|
+
return groupSections.length === 0 ? [] : [{
|
|
4436
5013
|
kind,
|
|
4437
|
-
width: kind === "main-navigation" && navigationLayout === "inline-wrap" ? "full-row" : "column",
|
|
4438
|
-
sections:
|
|
5014
|
+
width: kind === "main-navigation" && policy.navigationLayout === "inline-wrap" ? "full-row" : "column",
|
|
5015
|
+
sections: groupSections,
|
|
5016
|
+
...centred ? { slot: groupSlots[kind] } : {}
|
|
4439
5017
|
}];
|
|
4440
5018
|
});
|
|
4441
5019
|
}
|
|
4442
5020
|
function membershipKey(sections) {
|
|
4443
5021
|
const tokens = sections.map((section) => ({
|
|
4444
|
-
rank:
|
|
5022
|
+
rank: sectionKinds.indexOf(section.kind),
|
|
4445
5023
|
value: section.kind === "engagement" ? `engagement:${section.treatment}` : section.kind
|
|
4446
|
-
}));
|
|
4447
|
-
tokens.sort((left, right) => left.rank - right.rank);
|
|
5024
|
+
})).sort((left, right) => left.rank - right.rank);
|
|
4448
5025
|
return tokens.map(({ value }) => value).join("+") || "empty";
|
|
4449
5026
|
}
|
|
5027
|
+
function renderRegion(kind, groups, policy) {
|
|
5028
|
+
if (groups.length === 0) return [];
|
|
5029
|
+
const columns = kind !== "main" || policy.arrangement === "centred" ? 1 : Math.max(1, Math.min(groups.filter((group) => group.width === "column").length, 5));
|
|
5030
|
+
return [{
|
|
5031
|
+
kind,
|
|
5032
|
+
columns,
|
|
5033
|
+
groups,
|
|
5034
|
+
...policy.arrangement === "centred" ? { slot: regionSlots[kind] } : {}
|
|
5035
|
+
}];
|
|
5036
|
+
}
|
|
4450
5037
|
function planFooterArrangement(renderableSections, policy) {
|
|
4451
5038
|
const selectedSections = renderableSections.map(({ section }) => section);
|
|
4452
|
-
const groups = buildGroups(selectedSections, policy
|
|
4453
|
-
const
|
|
4454
|
-
const
|
|
4455
|
-
const
|
|
4456
|
-
const
|
|
4457
|
-
const
|
|
4458
|
-
const mainGroups = [...unsortedMainGroups.filter((group) => group.width === "column"), ...unsortedMainGroups.filter((group) => group.width === "full-row")];
|
|
4459
|
-
const regions = [];
|
|
4460
|
-
if (separateEngagement.length > 0) {
|
|
4461
|
-
regions.push({
|
|
4462
|
-
kind: "engagement-row",
|
|
4463
|
-
columns: 1,
|
|
4464
|
-
groups: separateEngagement
|
|
4465
|
-
});
|
|
4466
|
-
}
|
|
4467
|
-
if (mainGroups.length > 0) {
|
|
4468
|
-
regions.push({
|
|
4469
|
-
kind: "main",
|
|
4470
|
-
columns: Math.max(1, Math.min(mainGroups.filter((group) => group.width === "column").length, 5)),
|
|
4471
|
-
groups: mainGroups
|
|
4472
|
-
});
|
|
4473
|
-
}
|
|
4474
|
-
if (policy.kind === "separate-legal-region" && legalGroups.length > 0) {
|
|
4475
|
-
regions.push({
|
|
4476
|
-
kind: "bottom",
|
|
4477
|
-
columns: 1,
|
|
4478
|
-
groups: legalGroups
|
|
4479
|
-
});
|
|
4480
|
-
}
|
|
5039
|
+
const groups = buildGroups(selectedSections, policy);
|
|
5040
|
+
const separateEngagement = groups.filter((group) => group.kind === "engagement" && group.sections.some((section) => section.kind === "engagement" && section.treatment === "separate-row"));
|
|
5041
|
+
const layoutGroups = groups.filter((group) => !separateEngagement.includes(group));
|
|
5042
|
+
const legalGroups = policy.kind === "separate-legal-region" ? layoutGroups.filter((group) => group.kind === "legal-ending") : [];
|
|
5043
|
+
const unsortedMainGroups = layoutGroups.filter((group) => !legalGroups.includes(group));
|
|
5044
|
+
const mainGroups = policy.arrangement === "centred" ? unsortedMainGroups : [...unsortedMainGroups.filter((group) => group.width === "column"), ...unsortedMainGroups.filter((group) => group.width === "full-row")];
|
|
4481
5045
|
return {
|
|
4482
5046
|
membershipKey: membershipKey(selectedSections),
|
|
4483
|
-
regions
|
|
5047
|
+
regions: [
|
|
5048
|
+
...renderRegion("engagement-row", separateEngagement, policy),
|
|
5049
|
+
...renderRegion("main", mainGroups, policy),
|
|
5050
|
+
...renderRegion("bottom", legalGroups, policy)
|
|
5051
|
+
],
|
|
4484
5052
|
mobileGroups: separateEngagement.length === 0 ? groups : [...separateEngagement, ...layoutGroups]
|
|
4485
5053
|
};
|
|
4486
5054
|
}
|
|
@@ -4945,14 +5513,6 @@ function normalizeLegacyFooterContentToV1(value, options = {}) {
|
|
|
4945
5513
|
});
|
|
4946
5514
|
}
|
|
4947
5515
|
|
|
4948
|
-
//#endregion
|
|
4949
|
-
//#region ../core/src/footer-navigation-layout.ts
|
|
4950
|
-
const footerNavigationLayouts = ["stack", "inline-wrap"];
|
|
4951
|
-
const defaultFooterNavigationLayout = "inline-wrap";
|
|
4952
|
-
function normalizeFooterNavigationLayout(value) {
|
|
4953
|
-
return value === "stack" ? "stack" : defaultFooterNavigationLayout;
|
|
4954
|
-
}
|
|
4955
|
-
|
|
4956
5516
|
//#endregion
|
|
4957
5517
|
//#region ../core/src/mailing-list-setup.ts
|
|
4958
5518
|
function isRecord$3(value) {
|
|
@@ -4966,6 +5526,9 @@ function mailingListProviderName(provider) {
|
|
|
4966
5526
|
case "brevo": return "Brevo";
|
|
4967
5527
|
}
|
|
4968
5528
|
}
|
|
5529
|
+
function sameNewsletterAudience(left, right) {
|
|
5530
|
+
return left.kind === right.kind && (left.kind === "general" || right.kind === "topic" && left.topicId === right.topicId);
|
|
5531
|
+
}
|
|
4969
5532
|
const DEFAULT_MAILING_LIST_SUCCESS_MESSAGE = "Thanks — you're on the list.";
|
|
4970
5533
|
/**
|
|
4971
5534
|
* Seeded into a new setup so every signup form carries a preferences/unsubscribe
|
|
@@ -5013,6 +5576,7 @@ function resolveCollectedGlobalFields(form) {
|
|
|
5013
5576
|
switch (form.fields.preset) {
|
|
5014
5577
|
case "emailOnly": return phone;
|
|
5015
5578
|
case "emailName": return ["name", ...phone];
|
|
5579
|
+
case "emailFirstName": return ["first_name", ...phone];
|
|
5016
5580
|
case "emailFirstLast": return [
|
|
5017
5581
|
"first_name",
|
|
5018
5582
|
"last_name",
|
|
@@ -5029,6 +5593,7 @@ function resolveRequiredGlobalFields(fields) {
|
|
|
5029
5593
|
switch (fields.preset) {
|
|
5030
5594
|
case "emailOnly": return [];
|
|
5031
5595
|
case "emailName": return fields.name === "required" ? ["name"] : [];
|
|
5596
|
+
case "emailFirstName": return fields.firstName === "required" ? ["first_name"] : [];
|
|
5032
5597
|
case "emailFirstLast": return [...fields.firstName === "required" ? ["first_name"] : [], ...fields.lastName === "required" ? ["last_name"] : []];
|
|
5033
5598
|
case "emailNameCompany": return [...fields.name === "required" ? ["name"] : [], ...fields.company === "required" ? ["company"] : []];
|
|
5034
5599
|
}
|
|
@@ -5097,6 +5662,15 @@ function countDefaultMailingListPlacements(placementModes) {
|
|
|
5097
5662
|
|
|
5098
5663
|
//#endregion
|
|
5099
5664
|
//#region ../core/src/mailing-list-setup-parser.ts
|
|
5665
|
+
const newsletterAudienceSchema = z.unknown().transform((value, ctx) => {
|
|
5666
|
+
const parsed = parseNewsletterAudience(value);
|
|
5667
|
+
if (parsed.ok) return parsed.value;
|
|
5668
|
+
ctx.addIssue({
|
|
5669
|
+
code: "custom",
|
|
5670
|
+
message: "Choose a valid newsletter audience."
|
|
5671
|
+
});
|
|
5672
|
+
return z.NEVER;
|
|
5673
|
+
});
|
|
5100
5674
|
function parseMailingListGlobalForm(value) {
|
|
5101
5675
|
if (!isRecord$2(value)) return formError("shape");
|
|
5102
5676
|
const fields = parseGlobalFields(value.fields);
|
|
@@ -5153,51 +5727,69 @@ function parseConfiguredMailingListProvider(value) {
|
|
|
5153
5727
|
return setupError("provider");
|
|
5154
5728
|
}
|
|
5155
5729
|
switch (value.provider) {
|
|
5156
|
-
case "native":
|
|
5157
|
-
|
|
5158
|
-
|
|
5159
|
-
const confirmation = parseToggleConfirmation(value.confirmation);
|
|
5160
|
-
return confirmation === null ? setupError("confirmation") : ok({
|
|
5161
|
-
provider: "native",
|
|
5162
|
-
defaultTopicId,
|
|
5163
|
-
confirmation
|
|
5164
|
-
});
|
|
5165
|
-
}
|
|
5166
|
-
case "mailchimp": {
|
|
5167
|
-
const connectionId = parseMailchimpConnectionId(value.connectionId);
|
|
5168
|
-
if (connectionId === null) return setupError("connectionId");
|
|
5169
|
-
const accountId = parseMailchimpAccountId(value.accountId);
|
|
5170
|
-
if (accountId === null) return setupError("accountId");
|
|
5171
|
-
const defaultAudienceId = parseMailchimpAudienceId(value.defaultAudienceId);
|
|
5172
|
-
if (defaultAudienceId === null) return setupError("defaultTargetId");
|
|
5173
|
-
const confirmation = parseToggleConfirmation(value.confirmation);
|
|
5174
|
-
return confirmation === null ? setupError("confirmation") : ok({
|
|
5175
|
-
provider: "mailchimp",
|
|
5176
|
-
connectionId,
|
|
5177
|
-
accountId,
|
|
5178
|
-
defaultAudienceId,
|
|
5179
|
-
confirmation
|
|
5180
|
-
});
|
|
5181
|
-
}
|
|
5182
|
-
case "brevo": {
|
|
5183
|
-
const connectionId = parseBrevoConnectionId(value.connectionId);
|
|
5184
|
-
if (connectionId === null) return setupError("connectionId");
|
|
5185
|
-
const accountId = parseBrevoAccountId(value.accountId);
|
|
5186
|
-
if (accountId === null) return setupError("accountId");
|
|
5187
|
-
const defaultListId = parseBrevoListId(value.defaultListId);
|
|
5188
|
-
if (defaultListId === null) return setupError("defaultTargetId");
|
|
5189
|
-
const confirmation = parseBrevoConfirmation(value.confirmation);
|
|
5190
|
-
return confirmation === null ? setupError("confirmation") : ok({
|
|
5191
|
-
provider: "brevo",
|
|
5192
|
-
connectionId,
|
|
5193
|
-
accountId,
|
|
5194
|
-
defaultListId,
|
|
5195
|
-
confirmation
|
|
5196
|
-
});
|
|
5197
|
-
}
|
|
5730
|
+
case "native": return parseNativeSetup(value);
|
|
5731
|
+
case "mailchimp": return parseMailchimpSetup(value);
|
|
5732
|
+
case "brevo": return parseBrevoSetup(value);
|
|
5198
5733
|
default: return setupError("provider");
|
|
5199
5734
|
}
|
|
5200
5735
|
}
|
|
5736
|
+
function parseNativeSetup(value) {
|
|
5737
|
+
if ("defaultTopicId" in value) return setupError("defaultTargetId");
|
|
5738
|
+
const defaultAudience = parseNewsletterAudience(value.defaultAudience);
|
|
5739
|
+
if (!defaultAudience.ok) return setupError("defaultTargetId");
|
|
5740
|
+
const confirmation = parseToggleConfirmation(value.confirmation);
|
|
5741
|
+
return confirmation === null ? setupError("confirmation") : ok({
|
|
5742
|
+
provider: "native",
|
|
5743
|
+
defaultAudience: defaultAudience.value,
|
|
5744
|
+
confirmation
|
|
5745
|
+
});
|
|
5746
|
+
}
|
|
5747
|
+
function parseMailchimpSetup(value) {
|
|
5748
|
+
const connectionId = parseMailchimpConnectionId(value.connectionId);
|
|
5749
|
+
if (connectionId === null) return setupError("connectionId");
|
|
5750
|
+
const accountId = parseMailchimpAccountId(value.accountId);
|
|
5751
|
+
if (accountId === null) return setupError("accountId");
|
|
5752
|
+
const defaultAudienceId = parseMailchimpAudienceId(value.defaultAudienceId);
|
|
5753
|
+
if (defaultAudienceId === null) return setupError("defaultTargetId");
|
|
5754
|
+
const confirmation = parseToggleConfirmation(value.confirmation);
|
|
5755
|
+
return confirmation === null ? setupError("confirmation") : ok({
|
|
5756
|
+
provider: "mailchimp",
|
|
5757
|
+
connectionId,
|
|
5758
|
+
accountId,
|
|
5759
|
+
defaultAudienceId,
|
|
5760
|
+
confirmation
|
|
5761
|
+
});
|
|
5762
|
+
}
|
|
5763
|
+
function parseBrevoSetup(value) {
|
|
5764
|
+
const connectionId = parseBrevoConnectionId(value.connectionId);
|
|
5765
|
+
if (connectionId === null) return setupError("connectionId");
|
|
5766
|
+
const accountId = parseBrevoAccountId(value.accountId);
|
|
5767
|
+
if (accountId === null) return setupError("accountId");
|
|
5768
|
+
const defaultListId = parseBrevoListId(value.defaultListId);
|
|
5769
|
+
if (defaultListId === null) return setupError("defaultTargetId");
|
|
5770
|
+
const confirmation = parseBrevoConfirmation(value.confirmation);
|
|
5771
|
+
return confirmation === null ? setupError("confirmation") : ok({
|
|
5772
|
+
provider: "brevo",
|
|
5773
|
+
connectionId,
|
|
5774
|
+
accountId,
|
|
5775
|
+
defaultListId,
|
|
5776
|
+
confirmation
|
|
5777
|
+
});
|
|
5778
|
+
}
|
|
5779
|
+
function parseNewsletterAudience(value) {
|
|
5780
|
+
if (!isRecord$2(value)) return err("invalid_newsletter_audience");
|
|
5781
|
+
if (value.kind === "general" && Object.keys(value).length === 1) {
|
|
5782
|
+
return ok({ kind: "general" });
|
|
5783
|
+
}
|
|
5784
|
+
if (value.kind !== "topic" || Object.keys(value).some((key) => key !== "kind" && key !== "topicId")) {
|
|
5785
|
+
return err("invalid_newsletter_audience");
|
|
5786
|
+
}
|
|
5787
|
+
const topicId = parseNewsletterListId(value.topicId);
|
|
5788
|
+
return topicId === null ? err("invalid_newsletter_audience") : ok({
|
|
5789
|
+
kind: "topic",
|
|
5790
|
+
topicId
|
|
5791
|
+
});
|
|
5792
|
+
}
|
|
5201
5793
|
function parseGlobalFields(value) {
|
|
5202
5794
|
if (!isRecord$2(value) || typeof value.preset !== "string") return null;
|
|
5203
5795
|
switch (value.preset) {
|
|
@@ -5206,6 +5798,10 @@ function parseGlobalFields(value) {
|
|
|
5206
5798
|
preset: "emailName",
|
|
5207
5799
|
name: value.name
|
|
5208
5800
|
} : null;
|
|
5801
|
+
case "emailFirstName": return isRequirement(value.firstName) ? {
|
|
5802
|
+
preset: "emailFirstName",
|
|
5803
|
+
firstName: value.firstName
|
|
5804
|
+
} : null;
|
|
5209
5805
|
case "emailFirstLast": return isRequirement(value.firstName) && isRequirement(value.lastName) ? {
|
|
5210
5806
|
preset: "emailFirstLast",
|
|
5211
5807
|
firstName: value.firstName,
|
|
@@ -5281,7 +5877,13 @@ function setupError(field) {
|
|
|
5281
5877
|
//#region ../core/src/mailing-list-targeting-availability.ts
|
|
5282
5878
|
function resolveMailingListDefaultDestination(provider) {
|
|
5283
5879
|
switch (provider.provider) {
|
|
5284
|
-
case "native":
|
|
5880
|
+
case "native": {
|
|
5881
|
+
const audience = provider.defaultAudience;
|
|
5882
|
+
return audience.kind === "general" ? {
|
|
5883
|
+
id: "general",
|
|
5884
|
+
name: "General mailing list"
|
|
5885
|
+
} : provider.topics.find((item) => item.id === audience.topicId) ?? null;
|
|
5886
|
+
}
|
|
5285
5887
|
case "brevo": return provider.lists.find((item) => item.id === provider.defaultListId) ?? null;
|
|
5286
5888
|
case "mailchimp": return provider.audiences.find((item) => item.id === provider.defaultAudienceId) ?? null;
|
|
5287
5889
|
}
|
|
@@ -5446,11 +6048,12 @@ function parseRuntimeProvider(value) {
|
|
|
5446
6048
|
}
|
|
5447
6049
|
}
|
|
5448
6050
|
function parseNativeRuntimeProvider(value) {
|
|
5449
|
-
|
|
6051
|
+
if ("defaultTopicId" in value) return null;
|
|
6052
|
+
const defaultAudience = parseNewsletterAudience(value.defaultAudience);
|
|
5450
6053
|
const topics = parseNamedItems(value.topics, parseNewsletterListId);
|
|
5451
|
-
return
|
|
6054
|
+
return defaultAudience.ok && topics !== null ? {
|
|
5452
6055
|
provider: "native",
|
|
5453
|
-
|
|
6056
|
+
defaultAudience: defaultAudience.value,
|
|
5454
6057
|
topics
|
|
5455
6058
|
} : null;
|
|
5456
6059
|
}
|
|
@@ -5586,36 +6189,85 @@ function parseMailingListSignupProfile(form, input) {
|
|
|
5586
6189
|
}
|
|
5587
6190
|
} : name;
|
|
5588
6191
|
}
|
|
5589
|
-
case "
|
|
6192
|
+
case "emailFirstName": {
|
|
5590
6193
|
const firstName = resolveProfileField("first_name", form.fields.firstName, input.firstName);
|
|
5591
|
-
|
|
5592
|
-
const lastName = resolveProfileField("last_name", form.fields.lastName, input.lastName);
|
|
5593
|
-
return lastName.ok ? {
|
|
6194
|
+
return firstName.ok ? {
|
|
5594
6195
|
ok: true,
|
|
5595
6196
|
value: {
|
|
5596
|
-
preset: "
|
|
6197
|
+
preset: "emailFirstName",
|
|
5597
6198
|
email,
|
|
5598
6199
|
phone,
|
|
5599
|
-
firstName: firstName.value
|
|
5600
|
-
lastName: lastName.value
|
|
6200
|
+
firstName: firstName.value
|
|
5601
6201
|
}
|
|
5602
|
-
} :
|
|
6202
|
+
} : firstName;
|
|
5603
6203
|
}
|
|
5604
|
-
case "
|
|
5605
|
-
|
|
5606
|
-
|
|
5607
|
-
|
|
5608
|
-
|
|
5609
|
-
|
|
5610
|
-
|
|
5611
|
-
|
|
5612
|
-
|
|
5613
|
-
|
|
5614
|
-
|
|
5615
|
-
|
|
5616
|
-
|
|
5617
|
-
|
|
6204
|
+
case "emailFirstLast": return parseFirstLastProfile(form.fields, {
|
|
6205
|
+
email,
|
|
6206
|
+
phone
|
|
6207
|
+
}, input);
|
|
6208
|
+
case "emailNameCompany": return parseNameCompanyProfile(form.fields, {
|
|
6209
|
+
email,
|
|
6210
|
+
phone
|
|
6211
|
+
}, input);
|
|
6212
|
+
}
|
|
6213
|
+
}
|
|
6214
|
+
function parseFirstLastProfile(fields, base, input) {
|
|
6215
|
+
const firstName = resolveProfileField("first_name", fields.firstName, input.firstName);
|
|
6216
|
+
if (!firstName.ok) return firstName;
|
|
6217
|
+
const lastName = resolveProfileField("last_name", fields.lastName, input.lastName);
|
|
6218
|
+
return lastName.ok ? {
|
|
6219
|
+
ok: true,
|
|
6220
|
+
value: {
|
|
6221
|
+
...base,
|
|
6222
|
+
preset: "emailFirstLast",
|
|
6223
|
+
firstName: firstName.value,
|
|
6224
|
+
lastName: lastName.value
|
|
5618
6225
|
}
|
|
6226
|
+
} : lastName;
|
|
6227
|
+
}
|
|
6228
|
+
function parseNameCompanyProfile(fields, base, input) {
|
|
6229
|
+
const name = resolveProfileField("name", fields.name, input.name);
|
|
6230
|
+
if (!name.ok) return name;
|
|
6231
|
+
const company = resolveProfileField("company", fields.company, input.company);
|
|
6232
|
+
return company.ok ? {
|
|
6233
|
+
ok: true,
|
|
6234
|
+
value: {
|
|
6235
|
+
...base,
|
|
6236
|
+
preset: "emailNameCompany",
|
|
6237
|
+
name: name.value,
|
|
6238
|
+
company: company.value
|
|
6239
|
+
}
|
|
6240
|
+
} : company;
|
|
6241
|
+
}
|
|
6242
|
+
/** One projection consumed by native signup and external provider adapters. */
|
|
6243
|
+
function mailingListSignupProfileValues(profile) {
|
|
6244
|
+
const empty = {
|
|
6245
|
+
name: null,
|
|
6246
|
+
first_name: null,
|
|
6247
|
+
last_name: null,
|
|
6248
|
+
company: null,
|
|
6249
|
+
phone: profile.phone.tag === "collected" ? profile.phone.value : null
|
|
6250
|
+
};
|
|
6251
|
+
switch (profile.preset) {
|
|
6252
|
+
case "emailOnly": return empty;
|
|
6253
|
+
case "emailName": return {
|
|
6254
|
+
...empty,
|
|
6255
|
+
name: profile.name.value
|
|
6256
|
+
};
|
|
6257
|
+
case "emailFirstName": return {
|
|
6258
|
+
...empty,
|
|
6259
|
+
first_name: profile.firstName.value
|
|
6260
|
+
};
|
|
6261
|
+
case "emailFirstLast": return {
|
|
6262
|
+
...empty,
|
|
6263
|
+
first_name: profile.firstName.value,
|
|
6264
|
+
last_name: profile.lastName.value
|
|
6265
|
+
};
|
|
6266
|
+
case "emailNameCompany": return {
|
|
6267
|
+
...empty,
|
|
6268
|
+
name: profile.name.value,
|
|
6269
|
+
company: profile.company.value
|
|
6270
|
+
};
|
|
5619
6271
|
}
|
|
5620
6272
|
}
|
|
5621
6273
|
function resolveProfileField(field, requirement, input) {
|
|
@@ -6007,7 +6659,7 @@ function resolveExportDateRange(range, today) {
|
|
|
6007
6659
|
ok: true,
|
|
6008
6660
|
window: {
|
|
6009
6661
|
from: unsafeAsMoneyDateString("1970-01-01"),
|
|
6010
|
-
to: unsafeAsMoneyDateString(formatDate(today))
|
|
6662
|
+
to: unsafeAsMoneyDateString(formatDate$1(today))
|
|
6011
6663
|
}
|
|
6012
6664
|
};
|
|
6013
6665
|
}
|
|
@@ -6018,8 +6670,8 @@ function resolveExportDateRange(range, today) {
|
|
|
6018
6670
|
return {
|
|
6019
6671
|
ok: true,
|
|
6020
6672
|
window: {
|
|
6021
|
-
from: unsafeAsMoneyDateString(formatDate(from)),
|
|
6022
|
-
to: unsafeAsMoneyDateString(formatDate(to))
|
|
6673
|
+
from: unsafeAsMoneyDateString(formatDate$1(from)),
|
|
6674
|
+
to: unsafeAsMoneyDateString(formatDate$1(to))
|
|
6023
6675
|
}
|
|
6024
6676
|
};
|
|
6025
6677
|
}
|
|
@@ -6035,7 +6687,7 @@ function parseExportDate(value, field) {
|
|
|
6035
6687
|
};
|
|
6036
6688
|
}
|
|
6037
6689
|
const date = new Date(`${value}T00:00:00.000Z`);
|
|
6038
|
-
if (Number.isNaN(date.getTime()) || formatDate(date) !== value) {
|
|
6690
|
+
if (Number.isNaN(date.getTime()) || formatDate$1(date) !== value) {
|
|
6039
6691
|
return {
|
|
6040
6692
|
ok: false,
|
|
6041
6693
|
error: {
|
|
@@ -6061,7 +6713,7 @@ function presetDays(preset) {
|
|
|
6061
6713
|
function floorUtcDate(date) {
|
|
6062
6714
|
return new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()));
|
|
6063
6715
|
}
|
|
6064
|
-
function formatDate(date) {
|
|
6716
|
+
function formatDate$1(date) {
|
|
6065
6717
|
return date.toISOString().slice(0, 10);
|
|
6066
6718
|
}
|
|
6067
6719
|
function describeExportDateBasis(basis) {
|
|
@@ -7525,4 +8177,4 @@ function mergeBag(stored, patch, options) {
|
|
|
7525
8177
|
}
|
|
7526
8178
|
|
|
7527
8179
|
//#endregion
|
|
7528
|
-
export {
|
|
8180
|
+
export { parseUtcIsoDateTimeString as $, unsafeAsBookingSessionId as $t, parseFooterCompositionV1 as A, parseNonNegativeCents as At, normalizeLocationAddressText as B, parseApiKeyId as Bt, parseMailingListBlockId as C, unsafeAsStoragePath as Cn, publicEventPricingOptions as Ct, assessMailingListTargeting as D, ok as Dn, fromArray as Dt, parseMailingListRuntimeContext as E, err as En, resolvePricingOptionsPriceDisplay as Et, sameMailingListPlacementTargeting as F, unsafeAsPositiveCents as Ft, formatBookingDate as G, parseMediaAssetId as Gt, selectCategoryView as H, parseDatedOfferingCapacityHoldAuditRef as Ht, isCanonicalRichTextDoc as I, formatCurrencyAmount as It, formatLocalScheduleDate as J, parseRetiredCourseId as Jt, formatBookingDateParts as K, parseMembershipId as Kt, parsePublicContactDetails as L, parseCurrencyCode as Lt, parseMailingListPlacementTargeting as M, toCents as Mt, DEFAULT_MAILING_LIST_TARGETING as N, toNonNegativeCents as Nt, DEFAULT_MAILING_LIST_SUCCESS_MESSAGE as O, mapNonEmptyArray as Ot, planMailingListChoicePresentation as P, unsafeAsNonNegativeCents as Pt, getLocalScheduleTime as Q, unsafeAsBookingRequirementId as Qt, assertAllowedPublicUrl as R, assertNever as Rt, buildMailingListSignupBlockSourceRef as S, unsafeAsStorageBucketName as Sn, publicEventPricingDisplay as St, parseMailingListSignedSourceToken as T, unsafeAsUserId as Tn, resolveExactOrFreePriceDisplay as Tt, inferSiteDateLocale as U, parseDatedOfferingCapacityHoldId as Ut, toLocationCoordinates as V, parseCustomerId as Vt, buildBookingUtcDateWindow as W, parseEventSeriesId as Wt, getBookingLocalDateKey as X, parseUserId as Xt, formatLocalScheduleTime as Y, parseSiteId as Yt, getLocalScheduleDate as Z, unsafeAsAppointmentResourceId as Zt, resolveWholeSeriesBookingPhase as _, unsafeAsSafeDownloadFilename as _n, parseEventPageSurfaceSubject as _t, canonicalizeConfiguredBookingVerticalConfig as a, unsafeAsEventInstanceId as an, isLiveOrderInstalmentPlanStatus as at, parseManagementKey as b, unsafeAsSiteScopedStoragePath as bn, isPublicEventPricingOptionDisplayable as bt, resolveSiteVerticalBookingConfig as c, unsafeAsFileChecksumSha256 as cn, addIntervalPreservingMonthAnchor as ct, ORDINARY_EVENT_PRESET_VALUES as d, unsafeAsOriginalFilename as dn, getBookingInstalmentPlanIntervalCount as dt, unsafeAsCheckoutLineId as en, toBookingTimeZone as et, SURFACE_EVENT_PRESET_VALUES as f, unsafeAsPassId as fn, getBookingInstalmentProtectedDepositAmountCents as ft, orderedLiveRunSessions as g, unsafeAsProductId as gn, resolveFlexibleBalanceInitialPaymentCents as gt, CANCELLED_SESSION_STATUS as h, unsafeAsPricingOptionId as hn, resolveFlexibleBalanceDueAt as ht, areConfiguredBookingVerticalConfigsEqual as i, unsafeAsEntitlementId as in, validateBookingPaymentOptionKinds as it, footerNavigationLayouts as j, parsePositiveCents as jt, parseMailingListProviderScope as k, isNonNegativeWholeCents as kt, DEFAULT_EVENT_TYPE_PRESETS as l, unsafeAsMediaAssetId as ln, clampConfiguredAmount as lt, publicReadFreshnessSeconds as m, unsafeAsPositiveSeconds as mn, splitAmountWithRemainderInFirst as mt, EVENT_PRESET_VOCABULARY as n, unsafeAsDemoCapability as nn, toScheduledBookingDateTime as nt, parseVerticalId as o, unsafeAsEventOfferingId as on, isSettleableFlexibleBalanceContractStatus as ot, WHOLE_SERIES_EVENT_PRESET_VALUES as p, unsafeAsPositiveByteCount as pn, omitZeroAmountFutureRows as pt, formatBookingTime as q, parsePageId as qt, NAVIGATION_LOCATIONS as r, unsafeAsDetectedMimeType as rn, parseBookingTimeZone as rt, parseVerticalPresetId as s, unsafeAsEventSeriesId as sn, isSettleableOrderInstalmentPlanStatus as st, resolveEventCatalogue as t, unsafeAsDeclaredMimeType as tn, toScheduledBookingDateRange as tt, EVENT_PRESET_VALUES as u, unsafeAsOccurrenceId as un, getBookingInstalmentDepositRefundability as ut, createSecret as v, unsafeAsSiteFontId as vn, formatBookingPriceDisplay as vt, parseMailingListContentVersionId as w, unsafeAsUploadSessionId as wn, publicEventPricingType as wt, stableJsonStringify as x, unsafeAsStaffMemberId as xn, publicEventPricingCurrency as xt, exposeSecret as y, unsafeAsSiteId as yn, formatEventPricing as yt, isPresent as z, formatDurationUnitLabel as zt };
|