riverbankcms 0.22.2 → 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,7 +1387,7 @@ 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" });
1390
+ if (!isRecord$10(value)) return err({ kind: "notObject" });
1389
1391
  const parsed = value.kind === "eventSeries" ? parseEventSeriesPageSurfaceSubject(value) : value.kind === "eventOffering" ? parseEventOfferingPageSurfaceSubject(value) : err({
1390
1392
  kind: "unsupportedSubject",
1391
1393
  subjectKind: value.kind
@@ -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
 
@@ -3111,28 +3113,6 @@ const RECTIFICATION_HISTORY_PROPAGATION_PLANS = {
3111
3113
  blocked_immutable_history: { kind: "blocked_immutable_history" }
3112
3114
  };
3113
3115
 
3114
- //#endregion
3115
- //#region ../core/src/location.ts
3116
- function normalizeLocationAddressText(value) {
3117
- if (typeof value !== "string") {
3118
- return null;
3119
- }
3120
- const trimmed = value.trim();
3121
- return trimmed.length > 0 ? trimmed : null;
3122
- }
3123
- function hasLocationCoordinates(value) {
3124
- return value != null && typeof value.lat === "number" && typeof value.lng === "number";
3125
- }
3126
- function toLocationCoordinates(value) {
3127
- if (!hasLocationCoordinates(value)) {
3128
- return null;
3129
- }
3130
- return {
3131
- lat: value.lat,
3132
- lng: value.lng
3133
- };
3134
- }
3135
-
3136
3116
  //#endregion
3137
3117
  //#region ../core/src/string.ts
3138
3118
  /**
@@ -3182,6 +3162,363 @@ function capitalize(str) {
3182
3162
  return str.charAt(0).toUpperCase() + str.slice(1);
3183
3163
  }
3184
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
+
3185
3522
  //#endregion
3186
3523
  //#region ../core/src/business-address.ts
3187
3524
  function normalizeCountryCode(value) {
@@ -3198,15 +3535,16 @@ function isLongitude(value) {
3198
3535
  return value >= -180 && value <= 180;
3199
3536
  }
3200
3537
  function buildBusinessAddressDisplayText(input) {
3201
- const displayText = [
3202
- trimmedStringOrNull(input.addressLine1),
3203
- trimmedStringOrNull(input.addressLine2),
3204
- trimmedStringOrNull(input.locality),
3205
- trimmedStringOrNull(input.region),
3206
- trimmedStringOrNull(input.postalCode),
3207
- normalizeCountryCode(input.countryCode)
3208
- ].filter((part) => part !== null).join(", ");
3209
- 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
+ });
3210
3548
  }
3211
3549
  function validateBusinessAddressDraft(input) {
3212
3550
  const addressLine1 = trimmedStringOrNull(input.addressLine1);
@@ -3378,6 +3716,18 @@ function syncStateOf(sync) {
3378
3716
  * reload handover is only worth presenting within it (issue 1570).
3379
3717
  */
3380
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
+ }
3381
3731
  function parseEditLeaseScope(input) {
3382
3732
  switch (input.nodeType) {
3383
3733
  case "page": {
@@ -4056,7 +4406,7 @@ const knownSocialPlatformLabels = {
4056
4406
  x: "X",
4057
4407
  youtube: "YouTube"
4058
4408
  };
4059
- function isRecord$8(value) {
4409
+ function isRecord$9(value) {
4060
4410
  return typeof value === "object" && value !== null && !Array.isArray(value);
4061
4411
  }
4062
4412
  function trimmedOptionalString(value) {
@@ -4066,7 +4416,7 @@ function trimmedOptionalString(value) {
4066
4416
  return trimmed.length > 0 ? trimmed : null;
4067
4417
  }
4068
4418
  function parsePublicContactDetails(value) {
4069
- if (!isRecord$8(value)) {
4419
+ if (!isRecord$9(value)) {
4070
4420
  return err({
4071
4421
  code: "invalid_shape",
4072
4422
  path: "contact",
@@ -4162,7 +4512,7 @@ function minutesSinceMidnight(value) {
4162
4512
  }
4163
4513
  function parseOpeningHoursDay(value, expectedWeekday, index) {
4164
4514
  const path = `openingHours.days.${index}`;
4165
- if (!isRecord$8(value) || value.weekday !== expectedWeekday) {
4515
+ if (!isRecord$9(value) || value.weekday !== expectedWeekday) {
4166
4516
  return err({
4167
4517
  code: "invalid_weekdays",
4168
4518
  path,
@@ -4183,7 +4533,7 @@ function parseOpeningHoursDay(value, expectedWeekday, index) {
4183
4533
  const intervals = [];
4184
4534
  for (const [intervalIndex, rawInterval] of value.intervals.entries()) {
4185
4535
  const intervalPath = `${path}.intervals.${intervalIndex}`;
4186
- if (!isRecord$8(rawInterval)) {
4536
+ if (!isRecord$9(rawInterval)) {
4187
4537
  return err({
4188
4538
  code: "invalid_interval",
4189
4539
  path: intervalPath,
@@ -4255,7 +4605,7 @@ function parseOpeningHoursWeek(rawDays) {
4255
4605
  ]);
4256
4606
  }
4257
4607
  function parseWeeklyOpeningHours(value) {
4258
- 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) {
4259
4609
  return err({
4260
4610
  code: "invalid_weekdays",
4261
4611
  path: "openingHours.days",
@@ -4324,7 +4674,7 @@ function parsePublicSocialLinks(value) {
4324
4674
  const ids = new Set();
4325
4675
  for (const [index, rawLink] of value.entries()) {
4326
4676
  const path = `socialLinks.${index}`;
4327
- if (!isRecord$8(rawLink)) {
4677
+ if (!isRecord$9(rawLink)) {
4328
4678
  return err({
4329
4679
  code: "invalid_social_link",
4330
4680
  path,
@@ -4397,7 +4747,7 @@ function parsePublicProfilePresentation(value) {
4397
4747
  });
4398
4748
  }
4399
4749
  function parsePublicProfile(value) {
4400
- if (!isRecord$8(value)) {
4750
+ if (!isRecord$9(value)) {
4401
4751
  return err({
4402
4752
  code: "invalid_shape",
4403
4753
  path: "",
@@ -4435,7 +4785,7 @@ function parseContactVisibility(value) {
4435
4785
  email: "shown"
4436
4786
  });
4437
4787
  }
4438
- if (!isRecord$8(value)) {
4788
+ if (!isRecord$9(value)) {
4439
4789
  return err({
4440
4790
  code: "invalid_contact_visibility",
4441
4791
  path: "contactVisibility",
@@ -4579,7 +4929,7 @@ function parsePublicExperience(value) {
4579
4929
 
4580
4930
  //#endregion
4581
4931
  //#region ../core/src/rich-text.ts
4582
- function isRecord$7(value) {
4932
+ function isRecord$8(value) {
4583
4933
  return typeof value === "object" && value !== null && !Array.isArray(value);
4584
4934
  }
4585
4935
  function hasOnlyKeys(value, allowed) {
@@ -4601,10 +4951,10 @@ function isDenseArrayOf(value, predicate) {
4601
4951
  return true;
4602
4952
  }
4603
4953
  function isTipTapMark(value) {
4604
- 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));
4605
4955
  }
4606
4956
  function isTipTapNode(value) {
4607
- 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))) {
4608
4958
  return false;
4609
4959
  }
4610
4960
  if (value.type === "text") {
@@ -4613,7 +4963,7 @@ function isTipTapNode(value) {
4613
4963
  return value.text === undefined;
4614
4964
  }
4615
4965
  function isCanonicalRichTextDoc(value) {
4616
- 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);
4617
4967
  }
4618
4968
 
4619
4969
  //#endregion
@@ -4853,10 +5203,10 @@ function presentVisitorSelection(selection, optionCount) {
4853
5203
  //#region ../core/src/mailing-list-targeting-parser.ts
4854
5204
  function parseMailingListPlacementTargeting(value) {
4855
5205
  if (value == null) return ok(DEFAULT_MAILING_LIST_TARGETING);
4856
- if (!isRecord$6(value)) return targetingError("shape");
5206
+ if (!isRecord$7(value)) return targetingError("shape");
4857
5207
  if (value.mode === "default") return ok({ mode: "default" });
4858
5208
  if (value.mode !== "custom") return targetingError("mode");
4859
- if (!isRecord$6(value.selection)) return targetingError("selection");
5209
+ if (!isRecord$7(value.selection)) return targetingError("selection");
4860
5210
  switch (value.provider) {
4861
5211
  case "native": return parseNativeTargeting(value.selection);
4862
5212
  case "brevo": return parseBrevoTargeting(value.selection);
@@ -4865,7 +5215,7 @@ function parseMailingListPlacementTargeting(value) {
4865
5215
  }
4866
5216
  }
4867
5217
  function parseMailingListVisitorSelection(value) {
4868
- if (!isRecord$6(value)) return visitorSelectionError("shape");
5218
+ if (!isRecord$7(value)) return visitorSelectionError("shape");
4869
5219
  switch (value.provider) {
4870
5220
  case "native": {
4871
5221
  if (Object.keys(value).some((key) => key !== "provider" && key !== "topicIds")) return visitorSelectionError("shape");
@@ -4996,7 +5346,7 @@ function parseVisitorIds(value, parseId) {
4996
5346
  const parsed = parseNonEmptyUniqueIds(value, parseId);
4997
5347
  return parsed.ok ? parsed.value : null;
4998
5348
  }
4999
- function isRecord$6(value) {
5349
+ function isRecord$7(value) {
5000
5350
  return typeof value === "object" && value !== null && !Array.isArray(value);
5001
5351
  }
5002
5352
  function targetingError(field) {
@@ -5014,7 +5364,7 @@ function visitorSelectionError(field) {
5014
5364
 
5015
5365
  //#endregion
5016
5366
  //#region ../core/src/footer-engagement.ts
5017
- function isRecord$5(value) {
5367
+ function isRecord$6(value) {
5018
5368
  return typeof value === "object" && value !== null && !Array.isArray(value);
5019
5369
  }
5020
5370
  function invalid(path, message) {
@@ -5048,7 +5398,7 @@ function parseEngagementBase(value, base, path) {
5048
5398
  }
5049
5399
  const treatment = parseTreatment(value.treatment, `${path}.treatment`);
5050
5400
  if (!treatment.ok) return treatment;
5051
- if (!isRecord$5(value.source)) {
5401
+ if (!isRecord$6(value.source)) {
5052
5402
  return err(invalid(`${path}.source`, "Footer engagement source is invalid."));
5053
5403
  }
5054
5404
  const intro = parseBoundedText(value.source.intro, `${path}.source.intro`, {
@@ -5095,7 +5445,7 @@ function parseFooterEngagementSectionValue(value, sectionBase, path) {
5095
5445
  const base = parseEngagementBase(value, sectionBase, path);
5096
5446
  if (!base.ok) return base;
5097
5447
  const source = value.source;
5098
- if (!isRecord$5(source)) {
5448
+ if (!isRecord$6(source)) {
5099
5449
  return err(invalid(`${path}.source`, "Footer engagement source is invalid."));
5100
5450
  }
5101
5451
  switch (source.kind) {
@@ -5256,7 +5606,7 @@ function unsafeAsFooterModuleId(value) {
5256
5606
  function parseFooterModuleId(value) {
5257
5607
  return parseSectionId(value, "sectionId");
5258
5608
  }
5259
- function isRecord$4(value) {
5609
+ function isRecord$5(value) {
5260
5610
  return typeof value === "object" && value !== null && !Array.isArray(value);
5261
5611
  }
5262
5612
  function isRichText(value) {
@@ -5286,7 +5636,7 @@ function parseHeading(value, path) {
5286
5636
  }
5287
5637
  function parseFooterSection(value, index) {
5288
5638
  const path = `sections.${index}`;
5289
- if (!isRecord$4(value)) {
5639
+ if (!isRecord$5(value)) {
5290
5640
  return err({
5291
5641
  code: "invalid_section",
5292
5642
  path,
@@ -5321,7 +5671,7 @@ function parseFooterSection(value, index) {
5321
5671
  }
5322
5672
  break;
5323
5673
  case "navigation":
5324
- 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") {
5325
5675
  return ok({
5326
5676
  ...base,
5327
5677
  kind: "navigation",
@@ -5334,7 +5684,7 @@ function parseFooterSection(value, index) {
5334
5684
  }
5335
5685
  break;
5336
5686
  case "legal-navigation":
5337
- 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") {
5338
5688
  return ok({
5339
5689
  ...base,
5340
5690
  kind: "legal-navigation",
@@ -5347,7 +5697,7 @@ function parseFooterSection(value, index) {
5347
5697
  }
5348
5698
  break;
5349
5699
  case "business-address":
5350
- if (isRecord$4(value.source) && value.source.kind === "business-address") {
5700
+ if (isRecord$5(value.source) && value.source.kind === "business-address") {
5351
5701
  return ok({
5352
5702
  ...base,
5353
5703
  kind: "business-address",
@@ -5359,7 +5709,7 @@ function parseFooterSection(value, index) {
5359
5709
  case "contact":
5360
5710
  case "opening-hours":
5361
5711
  case "social-links":
5362
- if (isRecord$4(value.source) && value.source.kind === "public-profile") {
5712
+ if (isRecord$5(value.source) && value.source.kind === "public-profile") {
5363
5713
  return ok({
5364
5714
  ...base,
5365
5715
  kind: value.kind,
@@ -5411,7 +5761,7 @@ function validateFooterComposition(composition) {
5411
5761
  return ok(composition);
5412
5762
  }
5413
5763
  function parseFooterCompositionV1(value) {
5414
- if (!isRecord$4(value)) {
5764
+ if (!isRecord$5(value)) {
5415
5765
  return err({
5416
5766
  code: "invalid_shape",
5417
5767
  path: "",
@@ -5444,7 +5794,7 @@ function parseFooterCompositionV1(value) {
5444
5794
  });
5445
5795
  }
5446
5796
  function parseLegacyPlacementSection(value, index, selectedIds) {
5447
- if (!isRecord$4(value)) {
5797
+ if (!isRecord$5(value)) {
5448
5798
  return err({
5449
5799
  code: "invalid_section",
5450
5800
  path: `modules.${index}`,
@@ -5452,7 +5802,7 @@ function parseLegacyPlacementSection(value, index, selectedIds) {
5452
5802
  });
5453
5803
  }
5454
5804
  const selected = typeof value.id === "string" && selectedIds.has(value.id);
5455
- const source = isRecord$4(value.source) ? value.source : null;
5805
+ const source = isRecord$5(value.source) ? value.source : null;
5456
5806
  const mapped = value.kind === "navigation" && source?.kind === "menu-role" && source.role === "footer" ? {
5457
5807
  ...value,
5458
5808
  source: {
@@ -5471,7 +5821,7 @@ function parseLegacyPlacementSection(value, index, selectedIds) {
5471
5821
  * It is intentionally not called by the runtime parser.
5472
5822
  */
5473
5823
  function upgradePlacementFooterCompositionV1(value) {
5474
- 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)) {
5475
5825
  return err({
5476
5826
  code: "invalid_shape",
5477
5827
  path: "",
@@ -5480,7 +5830,7 @@ function upgradePlacementFooterCompositionV1(value) {
5480
5830
  }
5481
5831
  const selectedIds = new Set();
5482
5832
  for (const [index, placement] of value.placements.entries()) {
5483
- if (!isRecord$4(placement) || typeof placement.moduleId !== "string") {
5833
+ if (!isRecord$5(placement) || typeof placement.moduleId !== "string") {
5484
5834
  return err({
5485
5835
  code: "invalid_shape",
5486
5836
  path: `placements.${index}`,
@@ -5695,7 +6045,7 @@ const defaultSections = (legacy, options) => {
5695
6045
  ];
5696
6046
  };
5697
6047
  function normalizeLegacyFooterContentToV1(value, options = {}) {
5698
- if (!isRecord$4(value)) {
6048
+ if (!isRecord$5(value)) {
5699
6049
  return err({
5700
6050
  code: "invalid_shape",
5701
6051
  path: "",
@@ -5710,7 +6060,7 @@ function normalizeLegacyFooterContentToV1(value, options = {}) {
5710
6060
 
5711
6061
  //#endregion
5712
6062
  //#region ../core/src/mailing-list-setup.ts
5713
- function isRecord$3(value) {
6063
+ function isRecord$4(value) {
5714
6064
  return typeof value === "object" && value !== null && !Array.isArray(value);
5715
6065
  }
5716
6066
  /** The name shown to people for each provider; the native one is the product brand. */
@@ -5825,7 +6175,7 @@ function mailingListProviderScopeFromConfigured(provider) {
5825
6175
  }
5826
6176
  }
5827
6177
  function parseMailingListProviderScope(value) {
5828
- if (!isRecord$3(value)) return err("invalid_mailing_list_provider_scope");
6178
+ if (!isRecord$4(value)) return err("invalid_mailing_list_provider_scope");
5829
6179
  if (value.provider === "native") return ok({ provider: "native" });
5830
6180
  if (value.provider === "brevo") {
5831
6181
  const accountId = parseBrevoAccountId(value.accountId);
@@ -5867,7 +6217,7 @@ const newsletterAudienceSchema = z.unknown().transform((value, ctx) => {
5867
6217
  return z.NEVER;
5868
6218
  });
5869
6219
  function parseMailingListGlobalForm(value) {
5870
- if (!isRecord$2(value)) return formError("shape");
6220
+ if (!isRecord$3(value)) return formError("shape");
5871
6221
  const fields = parseGlobalFields(value.fields);
5872
6222
  if (fields === null) return formError("fields");
5873
6223
  if (typeof value.includeOptionalPhone !== "boolean") {
@@ -5888,7 +6238,7 @@ function parseMailingListGlobalForm(value) {
5888
6238
  });
5889
6239
  }
5890
6240
  function parseMailingListSiteSetup(value) {
5891
- if (!isRecord$2(value)) return setupError("shape");
6241
+ if (!isRecord$3(value)) return setupError("shape");
5892
6242
  const siteId = parseSiteId(value.siteId);
5893
6243
  if (!siteId.ok) return setupError("siteId");
5894
6244
  if (value.tag === "not_configured") {
@@ -5918,7 +6268,7 @@ function parseConfiguredSiteSetup(value, siteId) {
5918
6268
  });
5919
6269
  }
5920
6270
  function parseConfiguredMailingListProvider(value) {
5921
- if (!isRecord$2(value) || typeof value.provider !== "string") {
6271
+ if (!isRecord$3(value) || typeof value.provider !== "string") {
5922
6272
  return setupError("provider");
5923
6273
  }
5924
6274
  switch (value.provider) {
@@ -5972,7 +6322,7 @@ function parseBrevoSetup(value) {
5972
6322
  });
5973
6323
  }
5974
6324
  function parseNewsletterAudience(value) {
5975
- if (!isRecord$2(value)) return err("invalid_newsletter_audience");
6325
+ if (!isRecord$3(value)) return err("invalid_newsletter_audience");
5976
6326
  if (value.kind === "general" && Object.keys(value).length === 1) {
5977
6327
  return ok({ kind: "general" });
5978
6328
  }
@@ -5986,7 +6336,7 @@ function parseNewsletterAudience(value) {
5986
6336
  });
5987
6337
  }
5988
6338
  function parseGlobalFields(value) {
5989
- if (!isRecord$2(value) || typeof value.preset !== "string") return null;
6339
+ if (!isRecord$3(value) || typeof value.preset !== "string") return null;
5990
6340
  switch (value.preset) {
5991
6341
  case "emailOnly": return { preset: "emailOnly" };
5992
6342
  case "emailName": return isRequirement(value.name) ? {
@@ -6011,11 +6361,11 @@ function parseGlobalFields(value) {
6011
6361
  }
6012
6362
  }
6013
6363
  function parseToggleConfirmation(value) {
6014
- if (!isRecord$2(value)) return null;
6364
+ if (!isRecord$3(value)) return null;
6015
6365
  return value.tag === "on" || value.tag === "off" ? { tag: value.tag } : null;
6016
6366
  }
6017
6367
  function parseBrevoConfirmation(value) {
6018
- if (!isRecord$2(value)) return null;
6368
+ if (!isRecord$3(value)) return null;
6019
6369
  if (value.tag === "off") return { tag: "off" };
6020
6370
  if (value.tag !== "on") return null;
6021
6371
  const templateId = parseBrevoConfirmationTemplateId(value.templateId);
@@ -6052,7 +6402,7 @@ function parseOptionalString(value) {
6052
6402
  function isRequirement(value) {
6053
6403
  return value === "required" || value === "optional";
6054
6404
  }
6055
- function isRecord$2(value) {
6405
+ function isRecord$3(value) {
6056
6406
  return typeof value === "object" && value !== null && !Array.isArray(value);
6057
6407
  }
6058
6408
  function formError(field) {
@@ -6175,7 +6525,7 @@ function assessMatchedChoices(matched, choices) {
6175
6525
  //#endregion
6176
6526
  //#region ../core/src/mailing-list-runtime.ts
6177
6527
  function parseMailingListRuntimeContext(value) {
6178
- if (!isRecord$1(value)) return invalidRuntimeContext();
6528
+ if (!isRecord$2(value)) return invalidRuntimeContext();
6179
6529
  if (value.tag === "not_configured") return ok({ tag: "not_configured" });
6180
6530
  if (value.tag !== "configured") return invalidRuntimeContext();
6181
6531
  return parseConfiguredRuntimeContext(value);
@@ -6223,7 +6573,7 @@ function parseBookingSignupOffer(value) {
6223
6573
  tag: "unavailable",
6224
6574
  reason: "disabled"
6225
6575
  };
6226
- if (!isRecord$1(value)) return null;
6576
+ if (!isRecord$2(value)) return null;
6227
6577
  if (value.tag === "offered") return { tag: "offered" };
6228
6578
  if (value.tag === "unavailable" && (value.reason === "disabled" || value.reason === "fields" || value.reason === "destination")) {
6229
6579
  return {
@@ -6234,7 +6584,7 @@ function parseBookingSignupOffer(value) {
6234
6584
  return null;
6235
6585
  }
6236
6586
  function parseRuntimeProvider(value) {
6237
- if (!isRecord$1(value)) return null;
6587
+ if (!isRecord$2(value)) return null;
6238
6588
  switch (value.provider) {
6239
6589
  case "native": return parseNativeRuntimeProvider(value);
6240
6590
  case "brevo": return parseBrevoRuntimeProvider(value);
@@ -6272,7 +6622,7 @@ function parseMailchimpRuntimeProvider(value) {
6272
6622
  } : null;
6273
6623
  }
6274
6624
  function parseMailchimpAudience(value) {
6275
- if (!isRecord$1(value) || !Array.isArray(value.interests)) return null;
6625
+ if (!isRecord$2(value) || !Array.isArray(value.interests)) return null;
6276
6626
  const id = parseMailchimpAudienceId(value.id);
6277
6627
  const name = parseName(value.name);
6278
6628
  const interests = Array.from(value.interests, parseMailchimpInterest);
@@ -6283,7 +6633,7 @@ function parseMailchimpAudience(value) {
6283
6633
  } : null;
6284
6634
  }
6285
6635
  function parseMailchimpInterest(value) {
6286
- if (!isRecord$1(value)) return null;
6636
+ if (!isRecord$2(value)) return null;
6287
6637
  const id = parseMailchimpInterestId(value.id);
6288
6638
  const name = parseName(value.name);
6289
6639
  const categoryName = parseName(value.categoryName);
@@ -6296,7 +6646,7 @@ function parseMailchimpInterest(value) {
6296
6646
  function parseNamedItems(value, parseId) {
6297
6647
  if (!Array.isArray(value)) return null;
6298
6648
  const items = Array.from(value, (item) => {
6299
- if (!isRecord$1(item)) return null;
6649
+ if (!isRecord$2(item)) return null;
6300
6650
  const id = parseId(item.id);
6301
6651
  const name = parseName(item.name);
6302
6652
  return id !== null && name !== null ? {
@@ -6311,7 +6661,7 @@ function parseName(value) {
6311
6661
  const name = value.trim();
6312
6662
  return name.length > 0 ? name : null;
6313
6663
  }
6314
- function isRecord$1(value) {
6664
+ function isRecord$2(value) {
6315
6665
  return typeof value === "object" && value !== null && !Array.isArray(value);
6316
6666
  }
6317
6667
  function invalidRuntimeContext() {
@@ -6585,11 +6935,11 @@ const PRIORITY_IDS = new Set([
6585
6935
  "emailaddress"
6586
6936
  ]);
6587
6937
  const MAX_COLUMNS = 5;
6588
- function isRecord(value) {
6938
+ function isRecord$1(value) {
6589
6939
  return typeof value === "object" && value !== null && !Array.isArray(value);
6590
6940
  }
6591
6941
  function isSchemaField(value) {
6592
- return isRecord(value) && typeof value.id === "string";
6942
+ return isRecord$1(value) && typeof value.id === "string";
6593
6943
  }
6594
6944
  function selectSubmissionPreviewFields(schemaFields, submissions) {
6595
6945
  const fields = Array.isArray(schemaFields) ? schemaFields.filter(isSchemaField) : [];
@@ -6682,7 +7032,7 @@ function valueIsMeaningful(value) {
6682
7032
  if (value === null || value === undefined) return false;
6683
7033
  if (typeof value === "string") return value.trim().length > 0;
6684
7034
  if (Array.isArray(value)) return value.length > 0;
6685
- if (isRecord(value)) return Object.keys(value).length > 0;
7035
+ if (isRecord$1(value)) return Object.keys(value).length > 0;
6686
7036
  return true;
6687
7037
  }
6688
7038
  function orderSubmissionFields(schemaFields, data) {
@@ -8477,4 +8827,32 @@ function resolvePublicSiteVisibility(input) {
8477
8827
  }
8478
8828
 
8479
8829
  //#endregion
8480
- export { resolveBookingDisplayContext as $, assertNever as $t, DEFAULT_MAILING_LIST_SUCCESS_MESSAGE as A, unsafeAsPositiveSeconds as An, deriveTotalTicketQuantity as At, parseWeeklyOpeningHours as B, unsafeAsUploadSessionId as Bn, resolvePricingOptionsPriceDisplay as Bt, stableJsonStringify as C, unsafeAsEventSeriesId as Cn, getBookingInstalmentDepositRefundability as Ct, parseMailingListSignedSourceToken as D, unsafeAsOriginalFilename as Dn, splitAmountWithRemainderInFirst as Dt, parseMailingListContentVersionId as E, unsafeAsOccurrenceId as En, omitZeroAmountFutureRows as Et, DEFAULT_MAILING_LIST_TARGETING as F, unsafeAsSiteId as Fn, publicEventPricingCurrency as Ft, selectCategoryView as G, parseNonNegativeCents as Gt, isPresent as H, err as Hn, mapNonEmptyArray as Ht, planMailingListChoicePresentation as I, unsafeAsSiteScopedStoragePath as In, publicEventPricingDisplay as It, formatDateTime as J, toNonNegativeCents as Jt, formatDate as K, parsePositiveCents as Kt, isCanonicalRichTextDoc as L, unsafeAsStaffMemberId as Ln, publicEventPricingOptions as Lt, parseFooterCompositionV1 as M, unsafeAsProductId as Mn, formatBookingPriceDisplay as Mt, footerNavigationLayouts as N, unsafeAsSafeDownloadFilename as Nn, formatEventPricing as Nt, parseMailingListRuntimeContext as O, unsafeAsPassId as On, resolveFlexibleBalanceDueAt as Ot, parseMailingListPlacementTargeting as P, unsafeAsSiteFontId as Pn, isPublicEventPricingOptionDisplayable as Pt, inferSiteDateLocale as Q, parseCurrencyCode as Qt, formatOpeningHoursRows as R, unsafeAsStorageBucketName as Rn, publicEventPricingType as Rt, parseManagementKey as S, unsafeAsEventOfferingId as Sn, clampConfiguredAmount as St, parseMailingListBlockId as T, unsafeAsMediaAssetId as Tn, getBookingInstalmentProtectedDepositAmountCents as Tt, normalizeLocationAddressText as U, ok as Un, mapReadonlyNonEmptyArray as Ut, assertAllowedPublicUrl as V, unsafeAsUserId as Vn, fromArray as Vt, toLocationCoordinates as W, isNonNegativeWholeCents as Wt, formatTime as X, unsafeAsPositiveCents as Xt, formatDateTimeRange as Y, unsafeAsNonNegativeCents as Yt, formatTimeRange as Z, formatCurrencyAmount as Zt, orderedLiveRunSessions as _, unsafeAsDeclaredMimeType as _n, validateBookingPaymentOptionKinds as _t, canonicalizeConfiguredBookingVerticalConfig as a, parseEventSeriesId as an, getLocalScheduleDate as at, createSecret as b, unsafeAsEntitlementId as bn, isSettleableOrderInstalmentPlanStatus as bt, resolveSiteVerticalBookingConfig as c, parsePageId as cn, parseBookingLocalDate as ct, ORDINARY_EVENT_PRESET_VALUES as d, parseSiteTermsVersionId as dn, resolveBookingBusinessTimeZone as dt, formatDurationUnitLabel as en, buildBookingUtcDateWindow as et, SURFACE_EVENT_PRESET_VALUES as f, parseUserId as fn, resolveBookingTimeZoneId as ft, nextLiveRunSessionStartMs as g, unsafeAsCheckoutLineId as gn, parseBookingTimeZone as gt, CANCELLED_SESSION_STATUS as h, unsafeAsBookingSessionId as hn, toUtcIsoDateTimeString as ht, areConfiguredBookingVerticalConfigsEqual as i, parseDatedOfferingCapacityHoldId as in, getBookingLocalDateKey as it, parseMailingListProviderScope as j, unsafeAsPricingOptionId as jn, parseEventPageSurfaceSubject as jt, assessMailingListTargeting as k, unsafeAsPositiveByteCount as kn, resolveFlexibleBalanceInitialPaymentCents as kt, DEFAULT_EVENT_TYPE_PRESETS as l, parseRetiredCourseId as ln, parseLocalScheduleTime as lt, publicReadFreshnessSeconds as m, unsafeAsBookingRequirementId as mn, toScheduledBookingDateTime as mt, EVENT_PRESET_VOCABULARY as n, parseCustomerId as nn, formatLocalScheduleDate as nt, parseVerticalId as o, parseMediaAssetId as on, getLocalScheduleTime as ot, WHOLE_SERIES_EVENT_PRESET_VALUES as p, unsafeAsAppointmentResourceId as pn, toBookingTimeZone as pt, formatDateRange as q, toCents as qt, NAVIGATION_LOCATIONS as r, parseDatedOfferingCapacityHoldAuditRef as rn, formatLocalScheduleTime as rt, parseVerticalPresetId as s, parseMembershipId as sn, localScheduleTimePattern as st, resolveEventCatalogue as t, parseApiKeyId as tn, compareLocalScheduleDates as tt, EVENT_PRESET_VALUES as u, parseSiteId as un, parseUtcIsoDateTimeString as ut, resolveWholeSeriesBookingPhase as v, unsafeAsDemoCapability as vn, isLiveOrderInstalmentPlanStatus as vt, slugify as w, unsafeAsFileChecksumSha256 as wn, getBookingInstalmentPlanIntervalCount as wt, exposeSecret as x, unsafeAsEventInstanceId as xn, addIntervalPreservingMonthAnchor as xt, resolveWholeSeriesRunLifecycle as y, unsafeAsDetectedMimeType as yn, isSettleableFlexibleBalanceContractStatus as yt, parsePublicContactDetails as z, unsafeAsStoragePath as zn, resolveExactOrFreePriceDisplay 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 };