riverbankcms 0.22.1 → 0.23.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.
@@ -52,6 +52,7 @@ const unsafeAsPageId = (id) => id;
52
52
  const unsafeAsPageSurfaceId = (id) => id;
53
53
  const unsafeAsEditLeaseToken = (id) => id;
54
54
  const unsafeAsEditorClientId = (id) => id;
55
+ const unsafeAsPageDocumentCheckpointId = (id) => id;
55
56
  const unsafeAsOccurrenceId = (id) => id;
56
57
  const unsafeAsEventOfferingId = (id) => id;
57
58
  const unsafeAsEventSeriesId = (id) => id;
@@ -166,6 +167,7 @@ const parsePageId = (value) => parseUuidBrand(value, unsafeAsPageId);
166
167
  const parsePageSurfaceId = (value) => parseUuidBrand(value, unsafeAsPageSurfaceId);
167
168
  const parseEditLeaseToken = (value) => parseUuidBrand(value, unsafeAsEditLeaseToken);
168
169
  const parseEditorClientId = (value) => parseUuidBrand(value, unsafeAsEditorClientId);
170
+ const parsePageDocumentCheckpointId = (value) => parseUuidBrand(value, unsafeAsPageDocumentCheckpointId);
169
171
  const parseOccurrenceId = (value) => parseUuidBrand(value, unsafeAsOccurrenceId);
170
172
  const parseEventOfferingId = (value) => parseUuidBrand(value, unsafeAsEventOfferingId);
171
173
  const parseEventAttendeeTicketLineId = (value) => parseUuidBrand(value, unsafeAsEventAttendeeTicketLineId);
@@ -1385,15 +1387,15 @@ function parseEventPageSurfaceDestinationMode(value) {
1385
1387
  return value === "cms-managed" || value === "system-managed" ? value : undefined;
1386
1388
  }
1387
1389
  function parseEventPageSurfaceSubject(value) {
1388
- if (!isRecord$9(value)) return err({ kind: "notObject" });
1389
- switch (value.kind) {
1390
- case "eventSeries": return parseEventSeriesPageSurfaceSubject(value);
1391
- case "eventOffering": return parseEventOfferingPageSurfaceSubject(value);
1392
- default: return err({
1393
- kind: "unsupportedSubject",
1394
- subjectKind: value.kind
1395
- });
1396
- }
1390
+ if (!isRecord$10(value)) return err({ kind: "notObject" });
1391
+ const parsed = value.kind === "eventSeries" ? parseEventSeriesPageSurfaceSubject(value) : value.kind === "eventOffering" ? parseEventOfferingPageSurfaceSubject(value) : err({
1392
+ kind: "unsupportedSubject",
1393
+ subjectKind: value.kind
1394
+ });
1395
+ return parsed.ok && value.noindex === true ? ok({
1396
+ ...parsed.value,
1397
+ noindex: true
1398
+ }) : parsed;
1397
1399
  }
1398
1400
  function parseEventSeriesPageSurfaceSubject(value) {
1399
1401
  const eventSeriesId = parseEventSeriesId(value.eventSeriesId);
@@ -1458,7 +1460,7 @@ function parseEventSeriesIdList(values) {
1458
1460
  }
1459
1461
  return ok(parsed);
1460
1462
  }
1461
- function isRecord$9(value) {
1463
+ function isRecord$10(value) {
1462
1464
  return typeof value === "object" && value !== null && !Array.isArray(value);
1463
1465
  }
1464
1466
 
@@ -2009,6 +2011,12 @@ function resolveBookingTimeZoneId(...candidates) {
2009
2011
  }
2010
2012
  /** Canonical business-zone admission, shared by server and public wire boundaries. */
2011
2013
  const DEFAULT_BOOKING_BUSINESS_TIME_ZONE = "Europe/London";
2014
+ /** Stored site zones must be valid; a broken read must not silently choose another zone. */
2015
+ function requireBookingTimeZone(value) {
2016
+ const parsed = parseBookingTimeZone(value);
2017
+ if (!parsed.ok) throw new Error("Expected a valid canonical site time zone");
2018
+ return parsed.value;
2019
+ }
2012
2020
  /** Effect boundary for browser-authored local inputs; formats no displayed date. */
2013
2021
  function getRuntimeBookingTimeZone() {
2014
2022
  return resolveBookingTimeZoneId(new Intl.DateTimeFormat("en-GB").resolvedOptions().timeZone);
@@ -3105,28 +3113,6 @@ const RECTIFICATION_HISTORY_PROPAGATION_PLANS = {
3105
3113
  blocked_immutable_history: { kind: "blocked_immutable_history" }
3106
3114
  };
3107
3115
 
3108
- //#endregion
3109
- //#region ../core/src/location.ts
3110
- function normalizeLocationAddressText(value) {
3111
- if (typeof value !== "string") {
3112
- return null;
3113
- }
3114
- const trimmed = value.trim();
3115
- return trimmed.length > 0 ? trimmed : null;
3116
- }
3117
- function hasLocationCoordinates(value) {
3118
- return value != null && typeof value.lat === "number" && typeof value.lng === "number";
3119
- }
3120
- function toLocationCoordinates(value) {
3121
- if (!hasLocationCoordinates(value)) {
3122
- return null;
3123
- }
3124
- return {
3125
- lat: value.lat,
3126
- lng: value.lng
3127
- };
3128
- }
3129
-
3130
3116
  //#endregion
3131
3117
  //#region ../core/src/string.ts
3132
3118
  /**
@@ -3176,6 +3162,363 @@ function capitalize(str) {
3176
3162
  return str.charAt(0).toUpperCase() + str.slice(1);
3177
3163
  }
3178
3164
 
3165
+ //#endregion
3166
+ //#region ../core/src/location.ts
3167
+ /** One complete, finite, bounded arrival pin; zero is a valid coordinate. */
3168
+ const locationPinSchema = z.strictObject({
3169
+ lat: z.number().min(-90).max(90),
3170
+ lng: z.number().min(-180).max(180)
3171
+ }).readonly().brand();
3172
+ const addressPart = z.string().trim().max(200).nullish().transform((value) => trimmedStringOrNull(value));
3173
+ /** Building identifies the place; unit/floor refine it without moving it. */
3174
+ const locationAddressSchema = z.strictObject({
3175
+ building: addressPart,
3176
+ unit: addressPart,
3177
+ floor: addressPart,
3178
+ street: addressPart,
3179
+ locality: addressPart,
3180
+ region: addressPart,
3181
+ postalCode: addressPart,
3182
+ country: addressPart.transform((value) => value?.length === 2 ? value.toUpperCase() : value)
3183
+ }).readonly().transform((address) => Object.values(address).some((part) => part !== null) ? address : null);
3184
+ const locationAddressMatchSchema = z.strictObject({
3185
+ point: locationPinSchema,
3186
+ precision: z.enum([
3187
+ "building",
3188
+ "street",
3189
+ "area",
3190
+ "unknown"
3191
+ ]),
3192
+ placeId: z.string().trim().max(1024).regex(/^[a-z][a-z0-9-]*:\S+$/),
3193
+ attribution: z.array(z.strictObject({
3194
+ text: z.string().trim().min(1).max(500),
3195
+ url: z.url().max(2048).refine((value) => /^https?:\/\//.test(value))
3196
+ }).readonly()).min(1).max(4).readonly()
3197
+ }).readonly();
3198
+ const locationValueSchema = z.strictObject({
3199
+ address: locationAddressSchema.nullable().default(null),
3200
+ pin: locationPinSchema.nullable().default(null),
3201
+ doorNote: z.string().trim().max(1e3).nullish().transform(trimmedStringOrNull),
3202
+ addressMatch: locationAddressMatchSchema.nullable().default(null),
3203
+ ownerConfirmedPinAndAddress: z.boolean().default(false)
3204
+ }).superRefine((value, context) => {
3205
+ if (value.address === null && value.pin === null) {
3206
+ context.addIssue({
3207
+ code: "custom",
3208
+ path: ["address"],
3209
+ message: "Use null to remove a location."
3210
+ });
3211
+ }
3212
+ if (value.address === null && value.addressMatch !== null) {
3213
+ context.addIssue({
3214
+ code: "custom",
3215
+ path: ["addressMatch"],
3216
+ message: "Address evidence requires an address."
3217
+ });
3218
+ }
3219
+ if (value.ownerConfirmedPinAndAddress && (value.address === null || value.pin === null)) {
3220
+ context.addIssue({
3221
+ code: "custom",
3222
+ path: ["ownerConfirmedPinAndAddress"],
3223
+ message: "Confirmation requires both address and pin."
3224
+ });
3225
+ }
3226
+ }).readonly();
3227
+ /** API/DB ingress parses once. Removed locations are represented by null. */
3228
+ function parseLocationValue(input) {
3229
+ const parsed = locationValueSchema.nullable().safeParse(input);
3230
+ return parsed.success ? ok(parsed.data) : err({
3231
+ kind: "invalid_location",
3232
+ issues: parsed.error.issues
3233
+ });
3234
+ }
3235
+ function formatLocationAddress(address) {
3236
+ if (address === null) return null;
3237
+ const parts = [
3238
+ address.building,
3239
+ address.street,
3240
+ address.unit,
3241
+ address.floor,
3242
+ address.locality,
3243
+ address.region,
3244
+ address.postalCode,
3245
+ address.country
3246
+ ];
3247
+ return parts.filter((part) => part !== null).join(", ") || null;
3248
+ }
3249
+ /** Permission belongs to the resource/source owner before this projection. */
3250
+ function projectPublicLocation(location) {
3251
+ return {
3252
+ address: location.address,
3253
+ displayAddress: formatLocationAddress(location.address),
3254
+ pin: location.pin,
3255
+ doorNote: location.doorNote,
3256
+ attribution: location.addressMatch?.attribution ?? []
3257
+ };
3258
+ }
3259
+ function normalizeLocationAddressText(value) {
3260
+ if (typeof value !== "string") {
3261
+ return null;
3262
+ }
3263
+ return trimmedStringOrNull(value);
3264
+ }
3265
+ function hasLocationCoordinates(value) {
3266
+ return value != null && typeof value.lat === "number" && Number.isFinite(value.lat) && Math.abs(value.lat) <= 90 && typeof value.lng === "number" && Number.isFinite(value.lng) && Math.abs(value.lng) <= 180;
3267
+ }
3268
+ function toLocationCoordinates(value) {
3269
+ if (!hasLocationCoordinates(value)) {
3270
+ return null;
3271
+ }
3272
+ return {
3273
+ lat: value.lat,
3274
+ lng: value.lng
3275
+ };
3276
+ }
3277
+
3278
+ //#endregion
3279
+ //#region ../core/src/location-relationship.ts
3280
+ /** Initial bounded policy; Opus can tune these values without changing callers. */
3281
+ const LOCATION_MATCH_THRESHOLDS_METRES = {
3282
+ building: 100,
3283
+ street: 300,
3284
+ area: 1e3
3285
+ };
3286
+ function locationDistanceMetres(a, b) {
3287
+ const radians = Math.PI / 180;
3288
+ const haversine = Math.sin((b.lat - a.lat) * radians / 2) ** 2 + Math.cos(a.lat * radians) * Math.cos(b.lat * radians) * Math.sin((b.lng - a.lng) * radians / 2) ** 2;
3289
+ return 6371e3 * 2 * Math.asin(Math.sqrt(Math.min(1, Math.max(0, haversine))));
3290
+ }
3291
+ /** Arrival pins are never substituted for missing provider address points. */
3292
+ function decideLocationRelationship(location) {
3293
+ if (location === null) return { kind: "empty" };
3294
+ if (location.pin === null) return { kind: "address_only" };
3295
+ if (location.address === null) return { kind: "pin_only" };
3296
+ if (location.addressMatch === null || location.addressMatch.precision === "unknown") {
3297
+ return { kind: "unchecked" };
3298
+ }
3299
+ const { point, precision } = location.addressMatch;
3300
+ const distanceMetres = locationDistanceMetres(point, location.pin);
3301
+ const thresholdMetres = LOCATION_MATCH_THRESHOLDS_METRES[precision];
3302
+ const beyondThreshold = distanceMetres > thresholdMetres * (1 + 8 * Number.EPSILON);
3303
+ return {
3304
+ kind: beyondThreshold ? "far" : precision === "building" ? "near" : "approximate",
3305
+ distanceMetres,
3306
+ thresholdMetres,
3307
+ precision
3308
+ };
3309
+ }
3310
+ const spatialAddressParts = [
3311
+ "building",
3312
+ "street",
3313
+ "locality",
3314
+ "postalCode",
3315
+ "country"
3316
+ ];
3317
+ const comparisonText = (text) => (text ?? "").trim().replace(/\s+/g, " ").toLowerCase();
3318
+ function sameMeaningfulAddress(a, b) {
3319
+ if (a === null || b === null) return a === b;
3320
+ return spatialAddressParts.every((part) => comparisonText(a[part]) === comparisonText(b[part]));
3321
+ }
3322
+ function samePin(a, b) {
3323
+ return a === null || b === null ? a === b : a.lat === b.lat && a.lng === b.lng;
3324
+ }
3325
+ /** Edits cannot carry forward old confirmation or address evidence by accident. */
3326
+ function editLocationValue(previous, details) {
3327
+ if (details.address === null && details.pin === null) return ok(null);
3328
+ if (previous === null) {
3329
+ return parseLocationValue({
3330
+ ...details,
3331
+ addressMatch: null,
3332
+ ownerConfirmedPinAndAddress: false
3333
+ });
3334
+ }
3335
+ const sameAddress = sameMeaningfulAddress(previous.address, details.address);
3336
+ const samePair = sameAddress && samePin(previous.pin, details.pin);
3337
+ return parseLocationValue({
3338
+ ...details,
3339
+ addressMatch: sameAddress ? previous.addressMatch : null,
3340
+ ownerConfirmedPinAndAddress: samePair && previous.ownerConfirmedPinAndAddress
3341
+ });
3342
+ }
3343
+ function confirmLocationPair(location) {
3344
+ return location.address !== null && location.pin !== null ? ok({
3345
+ ...location,
3346
+ ownerConfirmedPinAndAddress: true
3347
+ }) : err({ kind: "missing_address_or_pin" });
3348
+ }
3349
+ /** Forms receive the decided save value, rather than a collection of flags. */
3350
+ function decideLocationSave(location, activity) {
3351
+ if (activity === "address-check") return {
3352
+ kind: "blocked",
3353
+ reason: "pending_address_check"
3354
+ };
3355
+ if (activity === "reverse") return {
3356
+ kind: "blocked",
3357
+ reason: "pending_reverse"
3358
+ };
3359
+ const relationship = decideLocationRelationship(location);
3360
+ return relationship.kind === "far" && location?.ownerConfirmedPinAndAddress !== true ? {
3361
+ kind: "blocked",
3362
+ reason: "unconfirmed_mismatch"
3363
+ } : {
3364
+ kind: "ready",
3365
+ location
3366
+ };
3367
+ }
3368
+
3369
+ //#endregion
3370
+ //#region ../core/src/location-migration.ts
3371
+ /** Offline expand/contract conversions, not runtime fallback readers. */
3372
+ const legacyText = z.string().nullable().optional();
3373
+ const legacyCoordinatesSchema = z.strictObject({
3374
+ lat: z.number().min(-90).max(90).nullable().optional(),
3375
+ lng: z.number().min(-180).max(180).nullable().optional()
3376
+ }).superRefine((value, context) => {
3377
+ if (value.lat == null !== (value.lng == null)) {
3378
+ context.addIssue({
3379
+ code: "custom",
3380
+ message: "Legacy pin is incomplete."
3381
+ });
3382
+ }
3383
+ });
3384
+ const venueAddressSchema = z.strictObject({
3385
+ street: legacyText,
3386
+ line1: legacyText,
3387
+ line2: legacyText,
3388
+ city: legacyText,
3389
+ state: legacyText,
3390
+ region: legacyText,
3391
+ postalCode: legacyText,
3392
+ postal_code: legacyText,
3393
+ postcode: legacyText,
3394
+ country: legacyText,
3395
+ formatted: legacyText,
3396
+ summary: legacyText
3397
+ }).superRefine((value, context) => {
3398
+ const aliases = [
3399
+ [value.street, value.line1],
3400
+ [value.state, value.region],
3401
+ [
3402
+ value.postalCode,
3403
+ value.postal_code,
3404
+ value.postcode
3405
+ ],
3406
+ [value.formatted, value.summary]
3407
+ ];
3408
+ aliases.forEach((parts) => {
3409
+ const meaningful = parts.filter((part) => displayComparison(part) !== "");
3410
+ if (meaningful.some((part) => displayComparison(part) !== displayComparison(meaningful[0]))) {
3411
+ context.addIssue({
3412
+ code: "custom",
3413
+ message: "Legacy address aliases disagree."
3414
+ });
3415
+ }
3416
+ });
3417
+ }).nullable();
3418
+ const businessAddressSchema = legacyCoordinatesSchema.safeExtend({
3419
+ addressLine1: legacyText,
3420
+ addressLine2: legacyText,
3421
+ locality: legacyText,
3422
+ region: legacyText,
3423
+ postalCode: legacyText,
3424
+ countryCode: legacyText,
3425
+ displayAddress: legacyText
3426
+ });
3427
+ const customLocationSchema = legacyCoordinatesSchema.safeExtend({ addressText: legacyText });
3428
+ function finishConversion(address, coordinates) {
3429
+ const parsedAddress = locationAddressSchema.nullable().safeParse(address);
3430
+ if (!parsedAddress.success) return err({
3431
+ kind: "invalid_legacy_location",
3432
+ issues: parsedAddress.error.issues
3433
+ });
3434
+ const pin = coordinates.lat == null || coordinates.lng == null ? null : {
3435
+ lat: coordinates.lat,
3436
+ lng: coordinates.lng
3437
+ };
3438
+ if (parsedAddress.data === null && pin === null) return ok(null);
3439
+ const result = parseLocationValue({
3440
+ address: parsedAddress.data,
3441
+ pin,
3442
+ addressMatch: null,
3443
+ ownerConfirmedPinAndAddress: false
3444
+ });
3445
+ return result.ok ? result : err({
3446
+ kind: "invalid_legacy_location",
3447
+ issues: result.error.issues
3448
+ });
3449
+ }
3450
+ function convertVenue(input) {
3451
+ const address = venueAddressSchema.safeParse(input.addressJson ?? null);
3452
+ const coordinates = legacyCoordinatesSchema.safeParse(input.locationJson ?? {});
3453
+ if (!address.success) return err({
3454
+ kind: "invalid_legacy_location",
3455
+ issues: address.error.issues
3456
+ });
3457
+ if (!coordinates.success) return err({
3458
+ kind: "invalid_legacy_location",
3459
+ issues: coordinates.error.issues
3460
+ });
3461
+ const result = finishConversion(mapVenueAddress(address.data), coordinates.data);
3462
+ return checkDisplayText(result, firstText(address.data?.formatted, address.data?.summary));
3463
+ }
3464
+ const displayComparison = (text) => (text ?? "").trim().replace(/\s+/g, " ").toLowerCase();
3465
+ const firstText = (...parts) => parts.find((part) => part != null && part.trim().length > 0)?.trim() ?? null;
3466
+ function mapVenueAddress(address) {
3467
+ if (address === null) return null;
3468
+ const structured = {
3469
+ street: firstText(address.street, address.line1),
3470
+ unit: address.line2,
3471
+ locality: address.city,
3472
+ region: firstText(address.state, address.region),
3473
+ postalCode: firstText(address.postalCode, address.postal_code, address.postcode),
3474
+ country: address.country
3475
+ };
3476
+ return Object.values(structured).some((part) => displayComparison(part) !== "") ? structured : { street: firstText(address.formatted, address.summary) };
3477
+ }
3478
+ function checkDisplayText(result, text) {
3479
+ if (!result.ok) return result;
3480
+ const original = text?.trim() ?? "";
3481
+ const derived = formatLocationAddress(result.value?.address ?? null);
3482
+ return original.length > 0 && displayComparison(original) !== displayComparison(derived) ? err({
3483
+ kind: "display_address_conflict",
3484
+ original,
3485
+ derived
3486
+ }) : result;
3487
+ }
3488
+ function convertBusiness(value) {
3489
+ if (value == null) return ok(null);
3490
+ const parsed = businessAddressSchema.safeParse(value);
3491
+ if (!parsed.success) return err({
3492
+ kind: "invalid_legacy_location",
3493
+ issues: parsed.error.issues
3494
+ });
3495
+ const result = finishConversion({
3496
+ street: parsed.data.addressLine1,
3497
+ unit: parsed.data.addressLine2,
3498
+ locality: parsed.data.locality,
3499
+ region: parsed.data.region,
3500
+ postalCode: parsed.data.postalCode,
3501
+ country: parsed.data.countryCode
3502
+ }, parsed.data);
3503
+ return checkDisplayText(result, parsed.data.displayAddress);
3504
+ }
3505
+ function convertCustom(value) {
3506
+ if (value == null) return ok(null);
3507
+ const parsed = customLocationSchema.safeParse(value);
3508
+ return parsed.success ? finishConversion({ street: parsed.data.addressText }, parsed.data) : err({
3509
+ kind: "invalid_legacy_location",
3510
+ issues: parsed.error.issues
3511
+ });
3512
+ }
3513
+ /** Preserve pins exactly; never split free text or fabricate match evidence. */
3514
+ function convertLegacyLocation(input) {
3515
+ switch (input.kind) {
3516
+ case "venue": return convertVenue(input);
3517
+ case "business": return convertBusiness(input.value);
3518
+ case "custom": return convertCustom(input.value);
3519
+ }
3520
+ }
3521
+
3179
3522
  //#endregion
3180
3523
  //#region ../core/src/business-address.ts
3181
3524
  function normalizeCountryCode(value) {
@@ -3192,15 +3535,16 @@ function isLongitude(value) {
3192
3535
  return value >= -180 && value <= 180;
3193
3536
  }
3194
3537
  function buildBusinessAddressDisplayText(input) {
3195
- const displayText = [
3196
- trimmedStringOrNull(input.addressLine1),
3197
- trimmedStringOrNull(input.addressLine2),
3198
- trimmedStringOrNull(input.locality),
3199
- trimmedStringOrNull(input.region),
3200
- trimmedStringOrNull(input.postalCode),
3201
- normalizeCountryCode(input.countryCode)
3202
- ].filter((part) => part !== null).join(", ");
3203
- return displayText.length > 0 ? displayText : null;
3538
+ return formatLocationAddress({
3539
+ building: null,
3540
+ street: trimmedStringOrNull(input.addressLine1),
3541
+ unit: trimmedStringOrNull(input.addressLine2),
3542
+ floor: null,
3543
+ locality: trimmedStringOrNull(input.locality),
3544
+ region: trimmedStringOrNull(input.region),
3545
+ postalCode: trimmedStringOrNull(input.postalCode),
3546
+ country: normalizeCountryCode(input.countryCode)
3547
+ });
3204
3548
  }
3205
3549
  function validateBusinessAddressDraft(input) {
3206
3550
  const addressLine1 = trimmedStringOrNull(input.addressLine1);
@@ -3372,6 +3716,18 @@ function syncStateOf(sync) {
3372
3716
  * reload handover is only worth presenting within it (issue 1570).
3373
3717
  */
3374
3718
  const EDIT_LEASE_TTL_SECONDS = 60;
3719
+ /** One-use navigation transport for the same previous-client acquire contract. */
3720
+ const EDIT_LEASE_HANDOVER_QUERY_PARAM = "edit_lease_handover";
3721
+ /** Frozen at editor mount; reacquiring a lease never advances this session's admission stamp. */
3722
+ const PAGE_DOCUMENT_SESSION_CHECKPOINT_HEADER = "X-Riverbank-Page-Checkpoint";
3723
+ function parsePageDocumentSessionCheckpoint(value) {
3724
+ if (value === "legacy") return { kind: "legacy" };
3725
+ const parsed = parsePageDocumentCheckpointId(value);
3726
+ return parsed.ok ? {
3727
+ kind: "document",
3728
+ checkpointId: parsed.value
3729
+ } : undefined;
3730
+ }
3375
3731
  function parseEditLeaseScope(input) {
3376
3732
  switch (input.nodeType) {
3377
3733
  case "page": {
@@ -4050,7 +4406,7 @@ const knownSocialPlatformLabels = {
4050
4406
  x: "X",
4051
4407
  youtube: "YouTube"
4052
4408
  };
4053
- function isRecord$8(value) {
4409
+ function isRecord$9(value) {
4054
4410
  return typeof value === "object" && value !== null && !Array.isArray(value);
4055
4411
  }
4056
4412
  function trimmedOptionalString(value) {
@@ -4060,7 +4416,7 @@ function trimmedOptionalString(value) {
4060
4416
  return trimmed.length > 0 ? trimmed : null;
4061
4417
  }
4062
4418
  function parsePublicContactDetails(value) {
4063
- if (!isRecord$8(value)) {
4419
+ if (!isRecord$9(value)) {
4064
4420
  return err({
4065
4421
  code: "invalid_shape",
4066
4422
  path: "contact",
@@ -4156,7 +4512,7 @@ function minutesSinceMidnight(value) {
4156
4512
  }
4157
4513
  function parseOpeningHoursDay(value, expectedWeekday, index) {
4158
4514
  const path = `openingHours.days.${index}`;
4159
- if (!isRecord$8(value) || value.weekday !== expectedWeekday) {
4515
+ if (!isRecord$9(value) || value.weekday !== expectedWeekday) {
4160
4516
  return err({
4161
4517
  code: "invalid_weekdays",
4162
4518
  path,
@@ -4177,7 +4533,7 @@ function parseOpeningHoursDay(value, expectedWeekday, index) {
4177
4533
  const intervals = [];
4178
4534
  for (const [intervalIndex, rawInterval] of value.intervals.entries()) {
4179
4535
  const intervalPath = `${path}.intervals.${intervalIndex}`;
4180
- if (!isRecord$8(rawInterval)) {
4536
+ if (!isRecord$9(rawInterval)) {
4181
4537
  return err({
4182
4538
  code: "invalid_interval",
4183
4539
  path: intervalPath,
@@ -4249,7 +4605,7 @@ function parseOpeningHoursWeek(rawDays) {
4249
4605
  ]);
4250
4606
  }
4251
4607
  function parseWeeklyOpeningHours(value) {
4252
- if (!isRecord$8(value) || !Array.isArray(value.days) || value.days.length !== publicProfileWeekdays.length) {
4608
+ if (!isRecord$9(value) || !Array.isArray(value.days) || value.days.length !== publicProfileWeekdays.length) {
4253
4609
  return err({
4254
4610
  code: "invalid_weekdays",
4255
4611
  path: "openingHours.days",
@@ -4318,7 +4674,7 @@ function parsePublicSocialLinks(value) {
4318
4674
  const ids = new Set();
4319
4675
  for (const [index, rawLink] of value.entries()) {
4320
4676
  const path = `socialLinks.${index}`;
4321
- if (!isRecord$8(rawLink)) {
4677
+ if (!isRecord$9(rawLink)) {
4322
4678
  return err({
4323
4679
  code: "invalid_social_link",
4324
4680
  path,
@@ -4391,7 +4747,7 @@ function parsePublicProfilePresentation(value) {
4391
4747
  });
4392
4748
  }
4393
4749
  function parsePublicProfile(value) {
4394
- if (!isRecord$8(value)) {
4750
+ if (!isRecord$9(value)) {
4395
4751
  return err({
4396
4752
  code: "invalid_shape",
4397
4753
  path: "",
@@ -4429,7 +4785,7 @@ function parseContactVisibility(value) {
4429
4785
  email: "shown"
4430
4786
  });
4431
4787
  }
4432
- if (!isRecord$8(value)) {
4788
+ if (!isRecord$9(value)) {
4433
4789
  return err({
4434
4790
  code: "invalid_contact_visibility",
4435
4791
  path: "contactVisibility",
@@ -4573,7 +4929,7 @@ function parsePublicExperience(value) {
4573
4929
 
4574
4930
  //#endregion
4575
4931
  //#region ../core/src/rich-text.ts
4576
- function isRecord$7(value) {
4932
+ function isRecord$8(value) {
4577
4933
  return typeof value === "object" && value !== null && !Array.isArray(value);
4578
4934
  }
4579
4935
  function hasOnlyKeys(value, allowed) {
@@ -4595,10 +4951,10 @@ function isDenseArrayOf(value, predicate) {
4595
4951
  return true;
4596
4952
  }
4597
4953
  function isTipTapMark(value) {
4598
- return isRecord$7(value) && hasOnlyKeys(value, markKeys) && typeof value.type === "string" && value.type.length > 0 && (value.attrs === undefined || isRecord$7(value.attrs));
4954
+ return isRecord$8(value) && hasOnlyKeys(value, markKeys) && typeof value.type === "string" && value.type.length > 0 && (value.attrs === undefined || isRecord$8(value.attrs));
4599
4955
  }
4600
4956
  function isTipTapNode(value) {
4601
- 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))) {
4957
+ if (!isRecord$8(value) || !hasOnlyKeys(value, nodeKeys) || typeof value.type !== "string" || value.type.length === 0 || value.type === "doc" || value.attrs !== undefined && !isRecord$8(value.attrs) || value.marks !== undefined && (!Array.isArray(value.marks) || !isDenseArrayOf(value.marks, isTipTapMark)) || value.content !== undefined && (!Array.isArray(value.content) || !isDenseArrayOf(value.content, isTipTapNode))) {
4602
4958
  return false;
4603
4959
  }
4604
4960
  if (value.type === "text") {
@@ -4607,7 +4963,7 @@ function isTipTapNode(value) {
4607
4963
  return value.text === undefined;
4608
4964
  }
4609
4965
  function isCanonicalRichTextDoc(value) {
4610
- return isRecord$7(value) && hasOnlyKeys(value, rootKeys) && value.type === "doc" && Array.isArray(value.content) && isDenseArrayOf(value.content, isTipTapNode);
4966
+ return isRecord$8(value) && hasOnlyKeys(value, rootKeys) && value.type === "doc" && Array.isArray(value.content) && isDenseArrayOf(value.content, isTipTapNode);
4611
4967
  }
4612
4968
 
4613
4969
  //#endregion
@@ -4847,10 +5203,10 @@ function presentVisitorSelection(selection, optionCount) {
4847
5203
  //#region ../core/src/mailing-list-targeting-parser.ts
4848
5204
  function parseMailingListPlacementTargeting(value) {
4849
5205
  if (value == null) return ok(DEFAULT_MAILING_LIST_TARGETING);
4850
- if (!isRecord$6(value)) return targetingError("shape");
5206
+ if (!isRecord$7(value)) return targetingError("shape");
4851
5207
  if (value.mode === "default") return ok({ mode: "default" });
4852
5208
  if (value.mode !== "custom") return targetingError("mode");
4853
- if (!isRecord$6(value.selection)) return targetingError("selection");
5209
+ if (!isRecord$7(value.selection)) return targetingError("selection");
4854
5210
  switch (value.provider) {
4855
5211
  case "native": return parseNativeTargeting(value.selection);
4856
5212
  case "brevo": return parseBrevoTargeting(value.selection);
@@ -4859,7 +5215,7 @@ function parseMailingListPlacementTargeting(value) {
4859
5215
  }
4860
5216
  }
4861
5217
  function parseMailingListVisitorSelection(value) {
4862
- if (!isRecord$6(value)) return visitorSelectionError("shape");
5218
+ if (!isRecord$7(value)) return visitorSelectionError("shape");
4863
5219
  switch (value.provider) {
4864
5220
  case "native": {
4865
5221
  if (Object.keys(value).some((key) => key !== "provider" && key !== "topicIds")) return visitorSelectionError("shape");
@@ -4990,7 +5346,7 @@ function parseVisitorIds(value, parseId) {
4990
5346
  const parsed = parseNonEmptyUniqueIds(value, parseId);
4991
5347
  return parsed.ok ? parsed.value : null;
4992
5348
  }
4993
- function isRecord$6(value) {
5349
+ function isRecord$7(value) {
4994
5350
  return typeof value === "object" && value !== null && !Array.isArray(value);
4995
5351
  }
4996
5352
  function targetingError(field) {
@@ -5008,7 +5364,7 @@ function visitorSelectionError(field) {
5008
5364
 
5009
5365
  //#endregion
5010
5366
  //#region ../core/src/footer-engagement.ts
5011
- function isRecord$5(value) {
5367
+ function isRecord$6(value) {
5012
5368
  return typeof value === "object" && value !== null && !Array.isArray(value);
5013
5369
  }
5014
5370
  function invalid(path, message) {
@@ -5042,7 +5398,7 @@ function parseEngagementBase(value, base, path) {
5042
5398
  }
5043
5399
  const treatment = parseTreatment(value.treatment, `${path}.treatment`);
5044
5400
  if (!treatment.ok) return treatment;
5045
- if (!isRecord$5(value.source)) {
5401
+ if (!isRecord$6(value.source)) {
5046
5402
  return err(invalid(`${path}.source`, "Footer engagement source is invalid."));
5047
5403
  }
5048
5404
  const intro = parseBoundedText(value.source.intro, `${path}.source.intro`, {
@@ -5089,7 +5445,7 @@ function parseFooterEngagementSectionValue(value, sectionBase, path) {
5089
5445
  const base = parseEngagementBase(value, sectionBase, path);
5090
5446
  if (!base.ok) return base;
5091
5447
  const source = value.source;
5092
- if (!isRecord$5(source)) {
5448
+ if (!isRecord$6(source)) {
5093
5449
  return err(invalid(`${path}.source`, "Footer engagement source is invalid."));
5094
5450
  }
5095
5451
  switch (source.kind) {
@@ -5250,7 +5606,7 @@ function unsafeAsFooterModuleId(value) {
5250
5606
  function parseFooterModuleId(value) {
5251
5607
  return parseSectionId(value, "sectionId");
5252
5608
  }
5253
- function isRecord$4(value) {
5609
+ function isRecord$5(value) {
5254
5610
  return typeof value === "object" && value !== null && !Array.isArray(value);
5255
5611
  }
5256
5612
  function isRichText(value) {
@@ -5280,7 +5636,7 @@ function parseHeading(value, path) {
5280
5636
  }
5281
5637
  function parseFooterSection(value, index) {
5282
5638
  const path = `sections.${index}`;
5283
- if (!isRecord$4(value)) {
5639
+ if (!isRecord$5(value)) {
5284
5640
  return err({
5285
5641
  code: "invalid_section",
5286
5642
  path,
@@ -5315,7 +5671,7 @@ function parseFooterSection(value, index) {
5315
5671
  }
5316
5672
  break;
5317
5673
  case "navigation":
5318
- if (isRecord$4(value.source) && value.source.kind === "menu-role" && value.source.role === "main") {
5674
+ if (isRecord$5(value.source) && value.source.kind === "menu-role" && value.source.role === "main") {
5319
5675
  return ok({
5320
5676
  ...base,
5321
5677
  kind: "navigation",
@@ -5328,7 +5684,7 @@ function parseFooterSection(value, index) {
5328
5684
  }
5329
5685
  break;
5330
5686
  case "legal-navigation":
5331
- if (isRecord$4(value.source) && value.source.kind === "menu-role" && value.source.role === "legal-policy") {
5687
+ if (isRecord$5(value.source) && value.source.kind === "menu-role" && value.source.role === "legal-policy") {
5332
5688
  return ok({
5333
5689
  ...base,
5334
5690
  kind: "legal-navigation",
@@ -5341,7 +5697,7 @@ function parseFooterSection(value, index) {
5341
5697
  }
5342
5698
  break;
5343
5699
  case "business-address":
5344
- if (isRecord$4(value.source) && value.source.kind === "business-address") {
5700
+ if (isRecord$5(value.source) && value.source.kind === "business-address") {
5345
5701
  return ok({
5346
5702
  ...base,
5347
5703
  kind: "business-address",
@@ -5353,7 +5709,7 @@ function parseFooterSection(value, index) {
5353
5709
  case "contact":
5354
5710
  case "opening-hours":
5355
5711
  case "social-links":
5356
- if (isRecord$4(value.source) && value.source.kind === "public-profile") {
5712
+ if (isRecord$5(value.source) && value.source.kind === "public-profile") {
5357
5713
  return ok({
5358
5714
  ...base,
5359
5715
  kind: value.kind,
@@ -5405,7 +5761,7 @@ function validateFooterComposition(composition) {
5405
5761
  return ok(composition);
5406
5762
  }
5407
5763
  function parseFooterCompositionV1(value) {
5408
- if (!isRecord$4(value)) {
5764
+ if (!isRecord$5(value)) {
5409
5765
  return err({
5410
5766
  code: "invalid_shape",
5411
5767
  path: "",
@@ -5438,7 +5794,7 @@ function parseFooterCompositionV1(value) {
5438
5794
  });
5439
5795
  }
5440
5796
  function parseLegacyPlacementSection(value, index, selectedIds) {
5441
- if (!isRecord$4(value)) {
5797
+ if (!isRecord$5(value)) {
5442
5798
  return err({
5443
5799
  code: "invalid_section",
5444
5800
  path: `modules.${index}`,
@@ -5446,7 +5802,7 @@ function parseLegacyPlacementSection(value, index, selectedIds) {
5446
5802
  });
5447
5803
  }
5448
5804
  const selected = typeof value.id === "string" && selectedIds.has(value.id);
5449
- const source = isRecord$4(value.source) ? value.source : null;
5805
+ const source = isRecord$5(value.source) ? value.source : null;
5450
5806
  const mapped = value.kind === "navigation" && source?.kind === "menu-role" && source.role === "footer" ? {
5451
5807
  ...value,
5452
5808
  source: {
@@ -5465,7 +5821,7 @@ function parseLegacyPlacementSection(value, index, selectedIds) {
5465
5821
  * It is intentionally not called by the runtime parser.
5466
5822
  */
5467
5823
  function upgradePlacementFooterCompositionV1(value) {
5468
- if (!isRecord$4(value) || value.schemaVersion !== 1 || !Array.isArray(value.modules) || !Array.isArray(value.placements)) {
5824
+ if (!isRecord$5(value) || value.schemaVersion !== 1 || !Array.isArray(value.modules) || !Array.isArray(value.placements)) {
5469
5825
  return err({
5470
5826
  code: "invalid_shape",
5471
5827
  path: "",
@@ -5474,7 +5830,7 @@ function upgradePlacementFooterCompositionV1(value) {
5474
5830
  }
5475
5831
  const selectedIds = new Set();
5476
5832
  for (const [index, placement] of value.placements.entries()) {
5477
- if (!isRecord$4(placement) || typeof placement.moduleId !== "string") {
5833
+ if (!isRecord$5(placement) || typeof placement.moduleId !== "string") {
5478
5834
  return err({
5479
5835
  code: "invalid_shape",
5480
5836
  path: `placements.${index}`,
@@ -5689,7 +6045,7 @@ const defaultSections = (legacy, options) => {
5689
6045
  ];
5690
6046
  };
5691
6047
  function normalizeLegacyFooterContentToV1(value, options = {}) {
5692
- if (!isRecord$4(value)) {
6048
+ if (!isRecord$5(value)) {
5693
6049
  return err({
5694
6050
  code: "invalid_shape",
5695
6051
  path: "",
@@ -5704,7 +6060,7 @@ function normalizeLegacyFooterContentToV1(value, options = {}) {
5704
6060
 
5705
6061
  //#endregion
5706
6062
  //#region ../core/src/mailing-list-setup.ts
5707
- function isRecord$3(value) {
6063
+ function isRecord$4(value) {
5708
6064
  return typeof value === "object" && value !== null && !Array.isArray(value);
5709
6065
  }
5710
6066
  /** The name shown to people for each provider; the native one is the product brand. */
@@ -5819,7 +6175,7 @@ function mailingListProviderScopeFromConfigured(provider) {
5819
6175
  }
5820
6176
  }
5821
6177
  function parseMailingListProviderScope(value) {
5822
- if (!isRecord$3(value)) return err("invalid_mailing_list_provider_scope");
6178
+ if (!isRecord$4(value)) return err("invalid_mailing_list_provider_scope");
5823
6179
  if (value.provider === "native") return ok({ provider: "native" });
5824
6180
  if (value.provider === "brevo") {
5825
6181
  const accountId = parseBrevoAccountId(value.accountId);
@@ -5861,7 +6217,7 @@ const newsletterAudienceSchema = z.unknown().transform((value, ctx) => {
5861
6217
  return z.NEVER;
5862
6218
  });
5863
6219
  function parseMailingListGlobalForm(value) {
5864
- if (!isRecord$2(value)) return formError("shape");
6220
+ if (!isRecord$3(value)) return formError("shape");
5865
6221
  const fields = parseGlobalFields(value.fields);
5866
6222
  if (fields === null) return formError("fields");
5867
6223
  if (typeof value.includeOptionalPhone !== "boolean") {
@@ -5882,7 +6238,7 @@ function parseMailingListGlobalForm(value) {
5882
6238
  });
5883
6239
  }
5884
6240
  function parseMailingListSiteSetup(value) {
5885
- if (!isRecord$2(value)) return setupError("shape");
6241
+ if (!isRecord$3(value)) return setupError("shape");
5886
6242
  const siteId = parseSiteId(value.siteId);
5887
6243
  if (!siteId.ok) return setupError("siteId");
5888
6244
  if (value.tag === "not_configured") {
@@ -5912,7 +6268,7 @@ function parseConfiguredSiteSetup(value, siteId) {
5912
6268
  });
5913
6269
  }
5914
6270
  function parseConfiguredMailingListProvider(value) {
5915
- if (!isRecord$2(value) || typeof value.provider !== "string") {
6271
+ if (!isRecord$3(value) || typeof value.provider !== "string") {
5916
6272
  return setupError("provider");
5917
6273
  }
5918
6274
  switch (value.provider) {
@@ -5966,7 +6322,7 @@ function parseBrevoSetup(value) {
5966
6322
  });
5967
6323
  }
5968
6324
  function parseNewsletterAudience(value) {
5969
- if (!isRecord$2(value)) return err("invalid_newsletter_audience");
6325
+ if (!isRecord$3(value)) return err("invalid_newsletter_audience");
5970
6326
  if (value.kind === "general" && Object.keys(value).length === 1) {
5971
6327
  return ok({ kind: "general" });
5972
6328
  }
@@ -5980,7 +6336,7 @@ function parseNewsletterAudience(value) {
5980
6336
  });
5981
6337
  }
5982
6338
  function parseGlobalFields(value) {
5983
- if (!isRecord$2(value) || typeof value.preset !== "string") return null;
6339
+ if (!isRecord$3(value) || typeof value.preset !== "string") return null;
5984
6340
  switch (value.preset) {
5985
6341
  case "emailOnly": return { preset: "emailOnly" };
5986
6342
  case "emailName": return isRequirement(value.name) ? {
@@ -6005,11 +6361,11 @@ function parseGlobalFields(value) {
6005
6361
  }
6006
6362
  }
6007
6363
  function parseToggleConfirmation(value) {
6008
- if (!isRecord$2(value)) return null;
6364
+ if (!isRecord$3(value)) return null;
6009
6365
  return value.tag === "on" || value.tag === "off" ? { tag: value.tag } : null;
6010
6366
  }
6011
6367
  function parseBrevoConfirmation(value) {
6012
- if (!isRecord$2(value)) return null;
6368
+ if (!isRecord$3(value)) return null;
6013
6369
  if (value.tag === "off") return { tag: "off" };
6014
6370
  if (value.tag !== "on") return null;
6015
6371
  const templateId = parseBrevoConfirmationTemplateId(value.templateId);
@@ -6046,7 +6402,7 @@ function parseOptionalString(value) {
6046
6402
  function isRequirement(value) {
6047
6403
  return value === "required" || value === "optional";
6048
6404
  }
6049
- function isRecord$2(value) {
6405
+ function isRecord$3(value) {
6050
6406
  return typeof value === "object" && value !== null && !Array.isArray(value);
6051
6407
  }
6052
6408
  function formError(field) {
@@ -6169,7 +6525,7 @@ function assessMatchedChoices(matched, choices) {
6169
6525
  //#endregion
6170
6526
  //#region ../core/src/mailing-list-runtime.ts
6171
6527
  function parseMailingListRuntimeContext(value) {
6172
- if (!isRecord$1(value)) return invalidRuntimeContext();
6528
+ if (!isRecord$2(value)) return invalidRuntimeContext();
6173
6529
  if (value.tag === "not_configured") return ok({ tag: "not_configured" });
6174
6530
  if (value.tag !== "configured") return invalidRuntimeContext();
6175
6531
  return parseConfiguredRuntimeContext(value);
@@ -6217,7 +6573,7 @@ function parseBookingSignupOffer(value) {
6217
6573
  tag: "unavailable",
6218
6574
  reason: "disabled"
6219
6575
  };
6220
- if (!isRecord$1(value)) return null;
6576
+ if (!isRecord$2(value)) return null;
6221
6577
  if (value.tag === "offered") return { tag: "offered" };
6222
6578
  if (value.tag === "unavailable" && (value.reason === "disabled" || value.reason === "fields" || value.reason === "destination")) {
6223
6579
  return {
@@ -6228,7 +6584,7 @@ function parseBookingSignupOffer(value) {
6228
6584
  return null;
6229
6585
  }
6230
6586
  function parseRuntimeProvider(value) {
6231
- if (!isRecord$1(value)) return null;
6587
+ if (!isRecord$2(value)) return null;
6232
6588
  switch (value.provider) {
6233
6589
  case "native": return parseNativeRuntimeProvider(value);
6234
6590
  case "brevo": return parseBrevoRuntimeProvider(value);
@@ -6266,7 +6622,7 @@ function parseMailchimpRuntimeProvider(value) {
6266
6622
  } : null;
6267
6623
  }
6268
6624
  function parseMailchimpAudience(value) {
6269
- if (!isRecord$1(value) || !Array.isArray(value.interests)) return null;
6625
+ if (!isRecord$2(value) || !Array.isArray(value.interests)) return null;
6270
6626
  const id = parseMailchimpAudienceId(value.id);
6271
6627
  const name = parseName(value.name);
6272
6628
  const interests = Array.from(value.interests, parseMailchimpInterest);
@@ -6277,7 +6633,7 @@ function parseMailchimpAudience(value) {
6277
6633
  } : null;
6278
6634
  }
6279
6635
  function parseMailchimpInterest(value) {
6280
- if (!isRecord$1(value)) return null;
6636
+ if (!isRecord$2(value)) return null;
6281
6637
  const id = parseMailchimpInterestId(value.id);
6282
6638
  const name = parseName(value.name);
6283
6639
  const categoryName = parseName(value.categoryName);
@@ -6290,7 +6646,7 @@ function parseMailchimpInterest(value) {
6290
6646
  function parseNamedItems(value, parseId) {
6291
6647
  if (!Array.isArray(value)) return null;
6292
6648
  const items = Array.from(value, (item) => {
6293
- if (!isRecord$1(item)) return null;
6649
+ if (!isRecord$2(item)) return null;
6294
6650
  const id = parseId(item.id);
6295
6651
  const name = parseName(item.name);
6296
6652
  return id !== null && name !== null ? {
@@ -6305,7 +6661,7 @@ function parseName(value) {
6305
6661
  const name = value.trim();
6306
6662
  return name.length > 0 ? name : null;
6307
6663
  }
6308
- function isRecord$1(value) {
6664
+ function isRecord$2(value) {
6309
6665
  return typeof value === "object" && value !== null && !Array.isArray(value);
6310
6666
  }
6311
6667
  function invalidRuntimeContext() {
@@ -6579,11 +6935,11 @@ const PRIORITY_IDS = new Set([
6579
6935
  "emailaddress"
6580
6936
  ]);
6581
6937
  const MAX_COLUMNS = 5;
6582
- function isRecord(value) {
6938
+ function isRecord$1(value) {
6583
6939
  return typeof value === "object" && value !== null && !Array.isArray(value);
6584
6940
  }
6585
6941
  function isSchemaField(value) {
6586
- return isRecord(value) && typeof value.id === "string";
6942
+ return isRecord$1(value) && typeof value.id === "string";
6587
6943
  }
6588
6944
  function selectSubmissionPreviewFields(schemaFields, submissions) {
6589
6945
  const fields = Array.isArray(schemaFields) ? schemaFields.filter(isSchemaField) : [];
@@ -6676,7 +7032,7 @@ function valueIsMeaningful(value) {
6676
7032
  if (value === null || value === undefined) return false;
6677
7033
  if (typeof value === "string") return value.trim().length > 0;
6678
7034
  if (Array.isArray(value)) return value.length > 0;
6679
- if (isRecord(value)) return Object.keys(value).length > 0;
7035
+ if (isRecord$1(value)) return Object.keys(value).length > 0;
6680
7036
  return true;
6681
7037
  }
6682
7038
  function orderSubmissionFields(schemaFields, data) {
@@ -8471,4 +8827,32 @@ function resolvePublicSiteVisibility(input) {
8471
8827
  }
8472
8828
 
8473
8829
  //#endregion
8474
- export { resolveBookingDisplayContext as $, formatDurationUnitLabel as $t, DEFAULT_MAILING_LIST_SUCCESS_MESSAGE as A, unsafeAsPricingOptionId as An, parseEventPageSurfaceSubject as At, parseWeeklyOpeningHours as B, unsafeAsUserId as Bn, fromArray as Bt, stableJsonStringify as C, unsafeAsFileChecksumSha256 as Cn, getBookingInstalmentPlanIntervalCount as Ct, parseMailingListSignedSourceToken as D, unsafeAsPassId as Dn, resolveFlexibleBalanceDueAt as Dt, parseMailingListContentVersionId as E, unsafeAsOriginalFilename as En, splitAmountWithRemainderInFirst as Et, DEFAULT_MAILING_LIST_TARGETING as F, unsafeAsSiteScopedStoragePath as Fn, publicEventPricingDisplay as Ft, selectCategoryView as G, parsePositiveCents as Gt, isPresent as H, ok as Hn, mapReadonlyNonEmptyArray as Ht, planMailingListChoicePresentation as I, unsafeAsStaffMemberId as In, publicEventPricingOptions as It, formatDateTime as J, unsafeAsNonNegativeCents as Jt, formatDate as K, toCents as Kt, isCanonicalRichTextDoc as L, unsafeAsStorageBucketName as Ln, publicEventPricingType as Lt, parseFooterCompositionV1 as M, unsafeAsSafeDownloadFilename as Mn, formatEventPricing as Mt, footerNavigationLayouts as N, unsafeAsSiteFontId as Nn, isPublicEventPricingOptionDisplayable as Nt, parseMailingListRuntimeContext as O, unsafeAsPositiveByteCount as On, resolveFlexibleBalanceInitialPaymentCents as Ot, parseMailingListPlacementTargeting as P, unsafeAsSiteId as Pn, publicEventPricingCurrency as Pt, inferSiteDateLocale as Q, assertNever as Qt, formatOpeningHoursRows as R, unsafeAsStoragePath as Rn, resolveExactOrFreePriceDisplay as Rt, parseManagementKey as S, unsafeAsEventSeriesId as Sn, getBookingInstalmentDepositRefundability as St, parseMailingListBlockId as T, unsafeAsOccurrenceId as Tn, omitZeroAmountFutureRows as Tt, normalizeLocationAddressText as U, isNonNegativeWholeCents as Ut, assertAllowedPublicUrl as V, err as Vn, mapNonEmptyArray as Vt, toLocationCoordinates as W, parseNonNegativeCents as Wt, formatTime as X, formatCurrencyAmount as Xt, formatDateTimeRange as Y, unsafeAsPositiveCents as Yt, formatTimeRange as Z, parseCurrencyCode as Zt, orderedLiveRunSessions as _, unsafeAsDemoCapability as _n, isLiveOrderInstalmentPlanStatus as _t, canonicalizeConfiguredBookingVerticalConfig as a, parseMediaAssetId as an, getLocalScheduleDate as at, createSecret as b, unsafeAsEventInstanceId as bn, addIntervalPreservingMonthAnchor as bt, resolveSiteVerticalBookingConfig as c, parseRetiredCourseId as cn, parseBookingLocalDate as ct, ORDINARY_EVENT_PRESET_VALUES as d, parseUserId as dn, resolveBookingTimeZoneId as dt, parseApiKeyId as en, buildBookingUtcDateWindow as et, SURFACE_EVENT_PRESET_VALUES as f, unsafeAsAppointmentResourceId as fn, toBookingTimeZone as ft, nextLiveRunSessionStartMs as g, unsafeAsDeclaredMimeType as gn, validateBookingPaymentOptionKinds as gt, CANCELLED_SESSION_STATUS as h, unsafeAsCheckoutLineId as hn, parseBookingTimeZone as ht, areConfiguredBookingVerticalConfigsEqual as i, parseEventSeriesId as in, getBookingLocalDateKey as it, parseMailingListProviderScope as j, unsafeAsProductId as jn, formatBookingPriceDisplay as jt, assessMailingListTargeting as k, unsafeAsPositiveSeconds as kn, deriveTotalTicketQuantity as kt, DEFAULT_EVENT_TYPE_PRESETS as l, parseSiteId as ln, parseUtcIsoDateTimeString as lt, publicReadFreshnessSeconds as m, unsafeAsBookingSessionId as mn, toUtcIsoDateTimeString as mt, EVENT_PRESET_VOCABULARY as n, parseDatedOfferingCapacityHoldAuditRef as nn, formatLocalScheduleDate as nt, parseVerticalId as o, parseMembershipId as on, getLocalScheduleTime as ot, WHOLE_SERIES_EVENT_PRESET_VALUES as p, unsafeAsBookingRequirementId as pn, toScheduledBookingDateTime as pt, formatDateRange as q, toNonNegativeCents as qt, NAVIGATION_LOCATIONS as r, parseDatedOfferingCapacityHoldId as rn, formatLocalScheduleTime as rt, parseVerticalPresetId as s, parsePageId as sn, localScheduleTimePattern as st, resolveEventCatalogue as t, parseCustomerId as tn, compareLocalScheduleDates as tt, EVENT_PRESET_VALUES as u, parseSiteTermsVersionId as un, resolveBookingBusinessTimeZone as ut, resolveWholeSeriesBookingPhase as v, unsafeAsDetectedMimeType as vn, isSettleableFlexibleBalanceContractStatus as vt, slugify as w, unsafeAsMediaAssetId as wn, getBookingInstalmentProtectedDepositAmountCents as wt, exposeSecret as x, unsafeAsEventOfferingId as xn, clampConfiguredAmount as xt, resolveWholeSeriesRunLifecycle as y, unsafeAsEntitlementId as yn, isSettleableOrderInstalmentPlanStatus as yt, parsePublicContactDetails as z, unsafeAsUploadSessionId as zn, resolvePricingOptionsPriceDisplay as zt };
8830
+ //#region ../core/src/authored-values.ts
8831
+ /** Canonical authored equality: empty storage values and absent optional members agree. */
8832
+ function canonicalAuthoredValue(value) {
8833
+ if (value == null || value === "" || typeof value === "number" && Number.isNaN(value)) return null;
8834
+ if (Array.isArray(value)) return value.map(canonicalAuthoredValue);
8835
+ if (typeof value !== "object") return value;
8836
+ const entries = Object.entries(value).sort(([a], [b]) => a.localeCompare(b)).map(([key, member]) => [key, canonicalAuthoredValue(member)]).filter(([, member]) => member !== null);
8837
+ return entries.length === 0 ? null : Object.fromEntries(entries);
8838
+ }
8839
+ function authoredValuesEqual(left, right) {
8840
+ return JSON.stringify(canonicalAuthoredValue(left)) === JSON.stringify(canonicalAuthoredValue(right));
8841
+ }
8842
+
8843
+ //#endregion
8844
+ //#region ../core/src/record-guards.ts
8845
+ function isRecord(value) {
8846
+ return typeof value === "object" && value !== null && !Array.isArray(value);
8847
+ }
8848
+ /**
8849
+ * Type guard for plain object records (excludes class instances like Error/Date).
8850
+ */
8851
+ function isPlainRecord(value) {
8852
+ if (!isRecord(value)) return false;
8853
+ const proto = Object.getPrototypeOf(value);
8854
+ return proto === Object.prototype || proto === null;
8855
+ }
8856
+
8857
+ //#endregion
8858
+ export { inferSiteDateLocale as $, parseCurrencyCode as $t, assessMailingListTargeting as A, unsafeAsPositiveByteCount as An, resolveFlexibleBalanceInitialPaymentCents as At, parsePublicContactDetails as B, unsafeAsStoragePath as Bn, resolveExactOrFreePriceDisplay as Bt, parseManagementKey as C, unsafeAsEventOfferingId as Cn, clampConfiguredAmount as Ct, parseMailingListContentVersionId as D, unsafeAsOccurrenceId as Dn, omitZeroAmountFutureRows as Dt, parseMailingListBlockId as E, unsafeAsMediaAssetId as En, getBookingInstalmentProtectedDepositAmountCents as Et, parseMailingListPlacementTargeting as F, unsafeAsSiteFontId as Fn, isPublicEventPricingOptionDisplayable as Ft, isPresent as G, isNonNegativeWholeCents as Gt, assertAllowedPublicUrl as H, unsafeAsUserId as Hn, fromArray as Ht, DEFAULT_MAILING_LIST_TARGETING as I, unsafeAsSiteId as In, publicEventPricingCurrency as It, formatDateRange as J, toCents as Jt, selectCategoryView as K, parseNonNegativeCents as Kt, planMailingListChoicePresentation as L, unsafeAsSiteScopedStoragePath as Ln, publicEventPricingDisplay as Lt, parseMailingListProviderScope as M, unsafeAsPricingOptionId as Mn, parseEventPageSurfaceSubject as Mt, parseFooterCompositionV1 as N, unsafeAsProductId as Nn, formatBookingPriceDisplay as Nt, parseMailingListSignedSourceToken as O, unsafeAsOriginalFilename as On, splitAmountWithRemainderInFirst as Ot, footerNavigationLayouts as P, unsafeAsSafeDownloadFilename as Pn, formatEventPricing as Pt, formatTimeRange as Q, formatCurrencyAmount as Qt, isCanonicalRichTextDoc as R, unsafeAsStaffMemberId as Rn, publicEventPricingOptions as Rt, exposeSecret as S, unsafeAsEventInstanceId as Sn, addIntervalPreservingMonthAnchor as St, slugify as T, unsafeAsFileChecksumSha256 as Tn, getBookingInstalmentPlanIntervalCount as Tt, normalizeLocationAddressText as U, err as Un, mapNonEmptyArray as Ut, parseWeeklyOpeningHours as V, unsafeAsUploadSessionId as Vn, resolvePricingOptionsPriceDisplay as Vt, toLocationCoordinates as W, ok as Wn, mapReadonlyNonEmptyArray as Wt, formatDateTimeRange as X, unsafeAsNonNegativeCents as Xt, formatDateTime as Y, toNonNegativeCents as Yt, formatTime as Z, unsafeAsPositiveCents as Zt, nextLiveRunSessionStartMs as _, unsafeAsCheckoutLineId as _n, parseBookingTimeZone as _t, areConfiguredBookingVerticalConfigsEqual as a, parseDatedOfferingCapacityHoldId as an, getBookingLocalDateKey as at, resolveWholeSeriesRunLifecycle as b, unsafeAsDetectedMimeType as bn, isSettleableFlexibleBalanceContractStatus as bt, parseVerticalPresetId as c, parseMembershipId as cn, localScheduleTimePattern as ct, EVENT_PRESET_VALUES as d, parseSiteId as dn, parseUtcIsoDateTimeString as dt, assertNever as en, resolveBookingDisplayContext as et, ORDINARY_EVENT_PRESET_VALUES as f, parseSiteTermsVersionId as fn, resolveBookingBusinessTimeZone as ft, CANCELLED_SESSION_STATUS as g, unsafeAsBookingSessionId as gn, toUtcIsoDateTimeString as gt, publicReadFreshnessSeconds as h, unsafeAsBookingRequirementId as hn, toScheduledBookingDateTime as ht, NAVIGATION_LOCATIONS as i, parseDatedOfferingCapacityHoldAuditRef as in, formatLocalScheduleTime as it, DEFAULT_MAILING_LIST_SUCCESS_MESSAGE as j, unsafeAsPositiveSeconds as jn, deriveTotalTicketQuantity as jt, parseMailingListRuntimeContext as k, unsafeAsPassId as kn, resolveFlexibleBalanceDueAt as kt, resolveSiteVerticalBookingConfig as l, parsePageId as ln, parseBookingLocalDate as lt, WHOLE_SERIES_EVENT_PRESET_VALUES as m, unsafeAsAppointmentResourceId as mn, toBookingTimeZone as mt, resolveEventCatalogue as n, parseApiKeyId as nn, compareLocalScheduleDates as nt, canonicalizeConfiguredBookingVerticalConfig as o, parseEventSeriesId as on, getLocalScheduleDate as ot, SURFACE_EVENT_PRESET_VALUES as p, parseUserId as pn, resolveBookingTimeZoneId as pt, formatDate as q, parsePositiveCents as qt, EVENT_PRESET_VOCABULARY as r, parseCustomerId as rn, formatLocalScheduleDate as rt, parseVerticalId as s, parseMediaAssetId as sn, getLocalScheduleTime as st, authoredValuesEqual as t, formatDurationUnitLabel as tn, buildBookingUtcDateWindow as tt, DEFAULT_EVENT_TYPE_PRESETS as u, parseRetiredCourseId as un, parseLocalScheduleTime as ut, orderedLiveRunSessions as v, unsafeAsDeclaredMimeType as vn, validateBookingPaymentOptionKinds as vt, stableJsonStringify as w, unsafeAsEventSeriesId as wn, getBookingInstalmentDepositRefundability as wt, createSecret as x, unsafeAsEntitlementId as xn, isSettleableOrderInstalmentPlanStatus as xt, resolveWholeSeriesBookingPhase as y, unsafeAsDemoCapability as yn, isLiveOrderInstalmentPlanStatus as yt, formatOpeningHoursRows as z, unsafeAsStorageBucketName as zn, publicEventPricingType as zt };