@riverbankcms/sdk 0.90.1 → 0.92.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.
Files changed (113) hide show
  1. package/dist/{PreviewEditorSidebar-FNFRVSIM.mjs → PreviewEditorSidebar-3CI5MKV3.mjs} +3 -3
  2. package/dist/{PreviewEditorUI-3WXJFQXG.mjs → PreviewEditorUI-DKEP636I.mjs} +3 -3
  3. package/dist/SdkPreviewModeRuntime-BRGRDQFH.mjs +8 -0
  4. package/dist/_dts/api/src/bookingConfig.d.ts +13 -1
  5. package/dist/_dts/api/src/bookingOperations.d.ts +1 -0
  6. package/dist/_dts/api/src/bookingRefundOutcomes.d.ts +6 -6
  7. package/dist/_dts/api/src/customerMembershipOutcomes.d.ts +4 -4
  8. package/dist/_dts/api/src/publicExperienceEndpoints.d.ts +6 -0
  9. package/dist/_dts/blocks/src/contracts/proof-block-islands.d.ts +32 -0
  10. package/dist/_dts/blocks/src/system/blocks/courses/shared/pricing.d.ts +12 -1
  11. package/dist/_dts/blocks/src/system/blocks/courses/shared/schemas.d.ts +12 -0
  12. package/dist/_dts/blocks/src/system/blocks/courses/shared/types.d.ts +4 -1
  13. package/dist/_dts/blocks/src/system/blocks/events/shared/schemas.d.ts +44 -0
  14. package/dist/_dts/blocks/src/system/manifest/fieldValidation/index.d.ts +24 -0
  15. package/dist/_dts/blocks/src/system/runtime/api/types.d.ts +8 -1
  16. package/dist/_dts/blocks/src/system/runtime/hooks/useHeadlessBookingFlow.d.ts +8 -1
  17. package/dist/_dts/blocks/src/system/runtime/hooks/useHeadlessBookingFlow.state.d.ts +1 -0
  18. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.headless.state.d.ts +4 -0
  19. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.interactive.d.ts +40 -0
  20. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.reserved-fields.d.ts +1 -1
  21. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.state.d.ts +29 -0
  22. package/dist/_dts/blocks/src/system/runtime/nodes/booking-runtime-sources.d.ts +1 -0
  23. package/dist/_dts/blocks/src/system/runtime/nodes/course-registration/components.d.ts +6 -0
  24. package/dist/_dts/blocks/src/system/runtime/nodes/course-registration/useCourseRegistrationWizard.d.ts +8 -0
  25. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/TicketSelectionStep.d.ts +8 -0
  26. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/hooks.d.ts +1 -0
  27. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/types.d.ts +1 -1
  28. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventRegistrationSubmit.d.ts +1 -0
  29. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventRegistrationWizard.d.ts +9 -0
  30. package/dist/_dts/content-model/src/entry-slots/types.d.ts +110 -2
  31. package/dist/_dts/core/src/branded.d.ts +3 -0
  32. package/dist/_dts/core/src/event-pricing.d.ts +18 -1
  33. package/dist/_dts/core/src/money-input.d.ts +34 -4
  34. package/dist/_dts/core/src/string.d.ts +12 -0
  35. package/dist/_dts/db/src/generated/supabase/database.types.d.ts +70 -0
  36. package/dist/_dts/media-core/src/fileAssetCompatibility.d.ts +1 -1
  37. package/dist/_dts/media-core/src/filePersistence.d.ts +5 -1
  38. package/dist/_dts/media-core/src/fileStorage.d.ts +1 -0
  39. package/dist/_dts/media-core/src/videoPrep.d.ts +15 -6
  40. package/dist/_dts/media-core/src/videoSlotPolicy.d.ts +5 -5
  41. package/dist/_dts/sdk/src/cli/commands/push/execute/diff.d.ts +2 -0
  42. package/dist/_dts/sdk/src/cli/commands/push/execute/localMediaReporting.d.ts +23 -0
  43. package/dist/_dts/sdk/src/cli/commands/push/scopes/commandBackedDatedOfferingScope.d.ts +54 -0
  44. package/dist/_dts/sdk/src/cli/commands/push/scopes/mediaPrep.d.ts +7 -2
  45. package/dist/_dts/sdk/src/cli/commands/push/scopes/types.d.ts +6 -0
  46. package/dist/_dts/sdk/src/cli/media/local-sync.d.ts +35 -0
  47. package/dist/_dts/sdk/src/cli/sync/validation.d.ts +2 -2
  48. package/dist/_dts/sdk/src/rendering/islands/types.d.ts +23 -1
  49. package/dist/_dts/sdk/src/version.d.ts +1 -1
  50. package/dist/{chunk-SYYJZPKU.mjs → chunk-6D7PLF4M.mjs} +2 -2
  51. package/dist/{chunk-CR2VX432.mjs → chunk-I6EOKV6B.mjs} +568 -76
  52. package/dist/{chunk-FA6LVZ7C.mjs → chunk-LERKJM3E.mjs} +7 -7
  53. package/dist/{chunk-UG7I7S7W.mjs → chunk-U5YM4AWE.mjs} +1 -1
  54. package/dist/{chunk-H6TT5ZXI.mjs → chunk-UOMTCHZD.mjs} +1 -1
  55. package/dist/{chunk-BOQXMCSP.mjs → chunk-ZA2S7H34.mjs} +3 -3
  56. package/dist/cli/index.mjs +755 -414
  57. package/dist/cli/init-docs/content/workflow-add-block.md +48 -0
  58. package/dist/cli/init-docs/content/workflow-custom-block.md +10 -0
  59. package/dist/client/{accordion-4K7VGZ3I.mjs → accordion-BUDH2G3S.mjs} +2 -2
  60. package/dist/client/{bookingForm-3QXA3CIS.mjs → bookingForm-NQMCELVB.mjs} +90 -15
  61. package/dist/client/bookings.mjs +259 -32
  62. package/dist/client/{carousel-BEJKNGQ7.mjs → carousel-ONCEW6IJ.mjs} +3 -3
  63. package/dist/client/{cart-44BBM6XG.mjs → cart-V2TCK2GI.mjs} +7 -7
  64. package/dist/client/{checkout-THMHEYKF.mjs → checkout-ZI7SWNCS.mjs} +7 -7
  65. package/dist/client/{chunk-PEDNDLPB.mjs → chunk-AUMRQ242.mjs} +52 -5
  66. package/dist/client/{chunk-EJBHK74Y.mjs → chunk-B5UC2D6X.mjs} +7 -6
  67. package/dist/client/{chunk-DQIRKNZE.mjs → chunk-ERQDHUS2.mjs} +1 -1
  68. package/dist/client/{chunk-3H5CLFKT.mjs → chunk-GH6IIOOE.mjs} +39 -10
  69. package/dist/client/{chunk-ZIAF2DA4.mjs → chunk-HQWIJLYN.mjs} +1 -1
  70. package/dist/client/{chunk-4COPESPO.mjs → chunk-JXY6NHG6.mjs} +6 -6
  71. package/dist/client/{chunk-JV7ZNAOU.mjs → chunk-KXYEKEV6.mjs} +155 -17
  72. package/dist/client/{chunk-HIHOQGIP.mjs → chunk-LJCX6V7Q.mjs} +9 -9
  73. package/dist/client/{chunk-5AJIMWKS.mjs → chunk-N2WJPTF7.mjs} +3 -3
  74. package/dist/client/{chunk-KNTLBQ3N.mjs → chunk-QQNVQ62W.mjs} +1 -1
  75. package/dist/client/{chunk-B4H6QMPY.mjs → chunk-R3CZQLXF.mjs} +73 -8
  76. package/dist/client/{chunk-WHZQDPBZ.mjs → chunk-TNGL2WJF.mjs} +1 -0
  77. package/dist/client/{chunk-SLY6UDAS.mjs → chunk-ZJDBOLX7.mjs} +3 -3
  78. package/dist/client/client.mjs +548 -68
  79. package/dist/client/{courseRegistration-URX7RCCK.mjs → courseRegistration-JPWAQ6KM.mjs} +112 -12
  80. package/dist/client/{eventCalendar-GTENOQCE.mjs → eventCalendar-QDOCHBBV.mjs} +10 -10
  81. package/dist/client/{eventCombined-EZVB72MF.mjs → eventCombined-ZS2CXSIE.mjs} +10 -10
  82. package/dist/client/{eventDetails-CH4BJR5Z.mjs → eventDetails-5LOBMPLN.mjs} +10 -10
  83. package/dist/client/{eventListing-4BVOI5HS.mjs → eventListing-SBGY4I3L.mjs} +10 -10
  84. package/dist/client/{eventRegistration-37LPIKIE.mjs → eventRegistration-XGPIU3Z2.mjs} +10 -10
  85. package/dist/client/{form-FX3Y54YK.mjs → form-R7D4LZWW.mjs} +4 -4
  86. package/dist/client/{headerSection-UOZZGVYL.mjs → headerSection-RRLYUCGC.mjs} +3 -3
  87. package/dist/client/hooks.mjs +29 -9
  88. package/dist/client/{locationMap-VSIPKV35.mjs → locationMap-35ZJMRBZ.mjs} +3 -3
  89. package/dist/client/{newsletterForm-6FRJKNAF.mjs → newsletterForm-MJ2VCFUT.mjs} +4 -4
  90. package/dist/client/{productDetail-6AHMLXCO.mjs → productDetail-2O7YQNBX.mjs} +7 -7
  91. package/dist/client/{productList-M2CYIZVH.mjs → productList-FDP5BH7W.mjs} +7 -7
  92. package/dist/client/rendering/client.mjs +526 -64
  93. package/dist/client/rendering/islands.mjs +19 -19
  94. package/dist/client/rendering.mjs +547 -67
  95. package/dist/client/{shop-AUOT6GEX.mjs → shop-BGYJ3LDT.mjs} +7 -7
  96. package/dist/client/spam-protection.mjs +10 -10
  97. package/dist/preview-next/client/runtime.mjs +5 -5
  98. package/dist/{sdk-runtime-6GPJNLU6.mjs → sdk-runtime-B3TFXRXZ.mjs} +6 -6
  99. package/dist/server/components.mjs +179 -18
  100. package/dist/server/config-validation.mjs +30 -9
  101. package/dist/server/config.mjs +30 -9
  102. package/dist/server/data.mjs +29 -9
  103. package/dist/server/index.mjs +1 -1
  104. package/dist/server/navigation.mjs +2 -2
  105. package/dist/server/next.mjs +180 -19
  106. package/dist/server/page-converter.mjs +24 -7
  107. package/dist/server/prebuild.mjs +1 -1
  108. package/dist/server/rendering/server.mjs +179 -18
  109. package/dist/server/rendering.mjs +179 -18
  110. package/dist/server/routing.mjs +43 -19
  111. package/dist/server/server.mjs +30 -10
  112. package/package.json +1 -1
  113. package/dist/SdkPreviewModeRuntime-2UCIMKUB.mjs +0 -8
@@ -123,6 +123,8 @@ function err(error) {
123
123
 
124
124
  // ../core/src/branded.ts
125
125
  var unsafeAsMediaAssetId = (id) => id;
126
+ var unsafeAsStorageBucketName = (value) => value;
127
+ var unsafeAsStoragePath = (value) => value;
126
128
 
127
129
  // ../core/src/assert-never.ts
128
130
  function assertNever(value, message = "Unexpected variant") {
@@ -177,6 +179,7 @@ function publicEventPricingType(pricing) {
177
179
  return "free";
178
180
  case "single_paid":
179
181
  case "ticket_types":
182
+ case "sliding_scale":
180
183
  case "course":
181
184
  return isFreePublicEventPriceDisplay(pricing.display) ? "free" : "paid";
182
185
  case "external":
@@ -189,6 +192,7 @@ function publicEventPricingCurrency(pricing) {
189
192
  case "free_registration":
190
193
  case "single_paid":
191
194
  case "ticket_types":
195
+ case "sliding_scale":
192
196
  return pricing.currency;
193
197
  case "course":
194
198
  return pricing.display.display.currency;
@@ -220,6 +224,8 @@ function formatCoursePriceDisplayLabel(display, options) {
220
224
  return `Course (${formatCurrencyAmount(display.amount, display.currency, options)})`;
221
225
  case "from":
222
226
  return `Course (From ${formatCurrencyAmount(display.amount, display.currency, options)})`;
227
+ case "range":
228
+ return `Course (${formatCurrencyAmount(display.minAmount, display.currency, options)} - ${formatCurrencyAmount(display.maxAmount, display.currency, options)})`;
223
229
  default:
224
230
  return assertNever(display);
225
231
  }
@@ -263,11 +269,11 @@ function isValidTimeZone(timeZone) {
263
269
  }
264
270
  function getSafeTimeZone(timeZone) {
265
271
  const normalized = typeof timeZone === "string" ? timeZone.trim() : "";
266
- return normalized && isValidTimeZone(normalized) ? normalized : FALLBACK_TIMEZONE;
272
+ return normalized.length > 0 && isValidTimeZone(normalized) ? normalized : FALLBACK_TIMEZONE;
267
273
  }
268
274
  function parseStrictBookingTimeZone(timeZone) {
269
275
  const normalized = timeZone.trim();
270
- if (!normalized || !isValidTimeZone(normalized)) {
276
+ if (normalized.length === 0 || !isValidTimeZone(normalized)) {
271
277
  return null;
272
278
  }
273
279
  return normalized;
@@ -344,7 +350,7 @@ function parseScheduledBookingDateTime(input) {
344
350
  try {
345
351
  const startsAt = toUtcIsoDateTimeString(input.startsAt);
346
352
  const timeZone = parseStrictBookingTimeZone(input.timeZone);
347
- if (!timeZone) {
353
+ if (timeZone === null) {
348
354
  return {
349
355
  ok: false,
350
356
  field: "timeZone",
@@ -479,10 +485,10 @@ function normalizeLocationAddressText(value) {
479
485
  return null;
480
486
  }
481
487
  const trimmed = value.trim();
482
- return trimmed ? trimmed : null;
488
+ return trimmed.length > 0 ? trimmed : null;
483
489
  }
484
490
  function hasLocationCoordinates(value) {
485
- return typeof value?.lat === "number" && typeof value?.lng === "number";
491
+ return value != null && typeof value.lat === "number" && typeof value.lng === "number";
486
492
  }
487
493
  function toLocationCoordinates(value) {
488
494
  if (!hasLocationCoordinates(value)) {
@@ -511,6 +517,77 @@ function resolvePlanningDateInput(input = {}) {
511
517
  return resolvePlanningNowDate(input);
512
518
  }
513
519
 
520
+ // ../media-core/src/fileSafety.ts
521
+ var CONTROL_CHARACTER_PATTERN = /[\u0000-\u001f\u007f]/u;
522
+ function containsUnsafePathSegmentCharacter(value) {
523
+ return value.includes("/") || value.includes("\\") || CONTROL_CHARACTER_PATTERN.test(value);
524
+ }
525
+ function isReservedPathSegment(value) {
526
+ return value === "." || value === "..";
527
+ }
528
+ function isUnsafePathSegment(segment) {
529
+ return segment.trim().length === 0 || segment !== segment.trim() || isReservedPathSegment(segment) || containsUnsafePathSegmentCharacter(segment);
530
+ }
531
+
532
+ // ../media-core/src/fileStorage.ts
533
+ var FILE_STORAGE_BUCKETS = {
534
+ publicSite: unsafeAsStorageBucketName("media"),
535
+ privateSite: unsafeAsStorageBucketName("site-files-private"),
536
+ temporary: unsafeAsStorageBucketName("temp-uploads")
537
+ };
538
+ var PUBLIC_SITE_FILE_STORAGE_BUCKETS = [
539
+ FILE_STORAGE_BUCKETS.publicSite,
540
+ // Existing site logo and font uploads predate the unified file buckets.
541
+ unsafeAsStorageBucketName("site-assets"),
542
+ unsafeAsStorageBucketName("site-fonts")
543
+ ];
544
+ var PRIVATE_SITE_FILE_BUCKET_MIME_TYPES = [
545
+ "application/pdf",
546
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
547
+ "text/plain",
548
+ "application/rtf",
549
+ "text/rtf",
550
+ "image/jpeg",
551
+ "image/png",
552
+ "image/webp",
553
+ "image/gif",
554
+ "image/avif",
555
+ "image/heic",
556
+ "image/heif",
557
+ "image/svg+xml",
558
+ "text/csv",
559
+ "application/csv",
560
+ "application/vnd.ms-excel",
561
+ "application/zip",
562
+ "application/x-zip-compressed",
563
+ "audio/mpeg",
564
+ "audio/mp4",
565
+ "audio/wav",
566
+ "audio/x-wav",
567
+ "audio/ogg",
568
+ "audio/webm",
569
+ "audio/flac",
570
+ "video/mp4",
571
+ "video/webm",
572
+ "video/quicktime"
573
+ ];
574
+ var TEMP_UPLOAD_BUCKET_MIME_TYPES = [
575
+ ...PRIVATE_SITE_FILE_BUCKET_MIME_TYPES,
576
+ "font/woff2",
577
+ "application/font-woff2",
578
+ "application/x-font-woff2",
579
+ "application/octet-stream"
580
+ ];
581
+ function parseStoragePath(value) {
582
+ return joinStoragePathSegments(value.split("/"));
583
+ }
584
+ function joinStoragePathSegments(segments) {
585
+ if (segments.some(isUnsafePathSegment)) {
586
+ return err("unsafe-path-segment");
587
+ }
588
+ return ok(unsafeAsStoragePath(segments.join("/")));
589
+ }
590
+
514
591
  // ../media-core/src/typeGuards.ts
515
592
  function isRecord(value) {
516
593
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
@@ -527,10 +604,10 @@ var RELATIVE_STORAGE_PATH_PREFIXES = [
527
604
  "imports/"
528
605
  ];
529
606
  function isRelativeDirectImageStoragePath(storagePath) {
530
- return RELATIVE_STORAGE_PATH_PREFIXES.some((prefix) => storagePath.startsWith(prefix));
607
+ return RELATIVE_STORAGE_PATH_PREFIXES.some((prefix) => storagePath.startsWith(prefix)) && parseStoragePath(storagePath).ok;
531
608
  }
532
609
  function isSiteScopedDirectImageStoragePath(storagePath) {
533
- return storagePath.startsWith("sites/");
610
+ return storagePath.startsWith("sites/") && parseStoragePath(storagePath).ok;
534
611
  }
535
612
  function encodeStoragePath(storagePath) {
536
613
  return storagePath.split("/").map((segment) => encodeURIComponent(segment)).join("/");
@@ -3003,6 +3080,21 @@ function fieldPlanToZod(plan, options = {}) {
3003
3080
  }
3004
3081
  });
3005
3082
  }
3083
+ function fieldPresenceForPlan(plan) {
3084
+ return plan.required ? { kind: "required" } : { kind: "optional" };
3085
+ }
3086
+ function fieldPlanToObjectPropertyZod(plan, options = {}) {
3087
+ const schema = fieldPlanToZod(plan, options);
3088
+ const presence = fieldPresenceForPlan(plan);
3089
+ switch (presence.kind) {
3090
+ case "required":
3091
+ return schema;
3092
+ case "optional":
3093
+ return schema.optional();
3094
+ default:
3095
+ return assertNever2(presence);
3096
+ }
3097
+ }
3006
3098
  function addFieldIssueToZodContext(zodCtx, validationIssue, rootPath) {
3007
3099
  const message = fieldIssueToMessage(validationIssue);
3008
3100
  const path = relativeZodIssuePath(validationIssue.path, rootPath);
@@ -3215,7 +3307,7 @@ function createManifestValidator(manifestOrFields, options = {}) {
3215
3307
  function deriveContentZodFromPlans(plans, options) {
3216
3308
  const shape = {};
3217
3309
  for (const plan of plans) {
3218
- shape[plan.fieldId] = fieldPlanToZod(plan, options);
3310
+ shape[plan.fieldId] = fieldPlanToObjectPropertyZod(plan, options);
3219
3311
  }
3220
3312
  return z5.object(shape).catchall(z5.unknown()).passthrough();
3221
3313
  }
@@ -26324,9 +26416,12 @@ var coursePricingOptionSchema = z43.object({
26324
26416
  });
26325
26417
  var coursePricingSchema = z43.object({
26326
26418
  bookingRequirement: z43.enum(["none", "required"]),
26327
- pricingStrategy: z43.enum(["free", "single", "tiered"]),
26419
+ pricingStrategy: z43.enum(["free", "single", "tiered", "sliding_scale"]),
26328
26420
  currency: z43.string(),
26329
26421
  singlePriceAmount: z43.number().nullable(),
26422
+ slidingMinAmount: z43.number().nullable().optional(),
26423
+ slidingMaxAmount: z43.number().nullable().optional(),
26424
+ slidingSuggestedAmount: z43.number().nullable().optional(),
26330
26425
  paymentTerms: blockBookingPaymentTermsSchema,
26331
26426
  options: z43.array(coursePricingOptionSchema)
26332
26427
  });
@@ -26480,6 +26575,19 @@ var publicEventPricingSchema = z44.discriminatedUnion("kind", [
26480
26575
  ticketTypes: z44.array(publicEventTicketTypeSchema),
26481
26576
  display: publicEventTicketTypePriceDisplaySchema
26482
26577
  }),
26578
+ z44.object({
26579
+ kind: z44.literal("sliding_scale"),
26580
+ minAmount: z44.number(),
26581
+ maxAmount: z44.number(),
26582
+ suggestedAmount: z44.number().nullable(),
26583
+ currency: z44.string(),
26584
+ display: z44.object({
26585
+ kind: z44.literal("range"),
26586
+ minAmount: z44.number(),
26587
+ maxAmount: z44.number(),
26588
+ currency: z44.string()
26589
+ })
26590
+ }),
26483
26591
  z44.object({
26484
26592
  kind: z44.literal("course"),
26485
26593
  display: z44.object({ kind: z44.literal("course"), display: publicCoursePriceDisplaySchema })
@@ -26896,7 +27004,7 @@ function isRecord6(value) {
26896
27004
  }
26897
27005
  function isPublicEventPricing(value) {
26898
27006
  if (!isRecord6(value) || typeof value.kind !== "string") return false;
26899
- return value.kind === "drop_in" || value.kind === "free_registration" || value.kind === "single_paid" || value.kind === "ticket_types" || value.kind === "course" || value.kind === "external";
27007
+ return value.kind === "drop_in" || value.kind === "free_registration" || value.kind === "single_paid" || value.kind === "sliding_scale" || value.kind === "ticket_types" || value.kind === "course" || value.kind === "external";
26900
27008
  }
26901
27009
  function isPublicEventTicketType(value) {
26902
27010
  return isRecord6(value) && typeof value.id === "string";
@@ -27513,7 +27621,9 @@ function getSelectableCoursePricingOptionsForNow(course, now) {
27513
27621
  return left.name.localeCompare(right.name);
27514
27622
  });
27515
27623
  }
27516
- function resolveCoursePricingState(course, selectedPricingOptionId, nowInput = {}) {
27624
+ function resolveCoursePricingState(course, selectedPricingOptionId, selectedSlidingAmountOrNowInput, nowInput = {}) {
27625
+ const selectedSlidingAmount = typeof selectedSlidingAmountOrNowInput === "number" || selectedSlidingAmountOrNowInput === null ? selectedSlidingAmountOrNowInput : null;
27626
+ const effectiveNowInput = typeof selectedSlidingAmountOrNowInput === "object" && selectedSlidingAmountOrNowInput !== null ? selectedSlidingAmountOrNowInput : nowInput;
27517
27627
  const currency = course.pricing?.currency ?? course.currency;
27518
27628
  if (!course.pricing) {
27519
27629
  const legacyAmount = course.priceCents ?? 0;
@@ -27523,6 +27633,8 @@ function resolveCoursePricingState(course, selectedPricingOptionId, nowInput = {
27523
27633
  selectableOptions: [],
27524
27634
  requiresSelection: false,
27525
27635
  selectedOption: null,
27636
+ slidingScale: null,
27637
+ selectedSlidingAmount: null,
27526
27638
  selectedPriceAmount: legacyAmount,
27527
27639
  selectedRequiresPayment: legacyAmount > 0,
27528
27640
  hasPaidSelection: legacyAmount > 0,
@@ -27537,6 +27649,8 @@ function resolveCoursePricingState(course, selectedPricingOptionId, nowInput = {
27537
27649
  selectableOptions: [],
27538
27650
  requiresSelection: false,
27539
27651
  selectedOption: null,
27652
+ slidingScale: null,
27653
+ selectedSlidingAmount: null,
27540
27654
  selectedPriceAmount: 0,
27541
27655
  selectedRequiresPayment: false,
27542
27656
  hasPaidSelection: false,
@@ -27550,6 +27664,8 @@ function resolveCoursePricingState(course, selectedPricingOptionId, nowInput = {
27550
27664
  selectableOptions: [],
27551
27665
  requiresSelection: false,
27552
27666
  selectedOption: null,
27667
+ slidingScale: null,
27668
+ selectedSlidingAmount: null,
27553
27669
  selectedPriceAmount: amount,
27554
27670
  selectedRequiresPayment: amount > 0,
27555
27671
  hasPaidSelection: amount > 0,
@@ -27559,7 +27675,7 @@ function resolveCoursePricingState(course, selectedPricingOptionId, nowInput = {
27559
27675
  case "tiered": {
27560
27676
  const selectableOptions = getSelectableCoursePricingOptionsForNow(
27561
27677
  course,
27562
- resolvePlanningDateInput(nowInput)
27678
+ resolvePlanningDateInput(effectiveNowInput)
27563
27679
  );
27564
27680
  const selectedOption = (selectedPricingOptionId ? selectableOptions.find((option) => option.id === selectedPricingOptionId) : null) ?? (selectableOptions.length === 1 ? selectableOptions[0] ?? null : null);
27565
27681
  const lowestAmount = selectableOptions.reduce((lowest, option) => {
@@ -27575,12 +27691,51 @@ function resolveCoursePricingState(course, selectedPricingOptionId, nowInput = {
27575
27691
  selectableOptions,
27576
27692
  requiresSelection: selectableOptions.length > 1,
27577
27693
  selectedOption,
27694
+ slidingScale: null,
27695
+ selectedSlidingAmount: null,
27578
27696
  selectedPriceAmount: selectedOption?.priceAmount ?? null,
27579
27697
  selectedRequiresPayment: (selectedOption?.priceAmount ?? 0) > 0,
27580
27698
  hasPaidSelection: selectableOptions.some((option) => option.priceAmount > 0),
27581
27699
  hasFreeSelection: selectableOptions.some((option) => option.priceAmount === 0)
27582
27700
  };
27583
27701
  }
27702
+ case "sliding_scale": {
27703
+ const minAmount = course.pricing.slidingMinAmount ?? null;
27704
+ const maxAmount = course.pricing.slidingMaxAmount ?? null;
27705
+ if (minAmount === null || maxAmount === null || minAmount < 0 || maxAmount < minAmount) {
27706
+ return {
27707
+ currency,
27708
+ display: { kind: "unavailable", currency },
27709
+ selectableOptions: [],
27710
+ requiresSelection: true,
27711
+ selectedOption: null,
27712
+ slidingScale: null,
27713
+ selectedSlidingAmount: null,
27714
+ selectedPriceAmount: null,
27715
+ selectedRequiresPayment: false,
27716
+ hasPaidSelection: false,
27717
+ hasFreeSelection: false
27718
+ };
27719
+ }
27720
+ const normalizedSelectedAmount = typeof selectedSlidingAmount === "number" && Number.isFinite(selectedSlidingAmount) ? selectedSlidingAmount : null;
27721
+ return {
27722
+ currency,
27723
+ display: { kind: "range", minAmount, maxAmount, currency },
27724
+ selectableOptions: [],
27725
+ requiresSelection: normalizedSelectedAmount === null,
27726
+ selectedOption: null,
27727
+ slidingScale: {
27728
+ minAmount,
27729
+ maxAmount,
27730
+ suggestedAmount: course.pricing.slidingSuggestedAmount ?? null
27731
+ },
27732
+ selectedSlidingAmount: normalizedSelectedAmount,
27733
+ selectedPriceAmount: normalizedSelectedAmount,
27734
+ selectedRequiresPayment: (normalizedSelectedAmount ?? 0) > 0,
27735
+ hasPaidSelection: maxAmount > 0,
27736
+ hasFreeSelection: minAmount === 0
27737
+ };
27738
+ }
27584
27739
  }
27585
27740
  }
27586
27741
  function formatCoursePriceDisplay(display, locale) {
@@ -28507,7 +28662,7 @@ function formatCalendarTitle(viewDate, view, days, monthNames = MONTH_NAMES) {
28507
28662
  if (view === "week") {
28508
28663
  const weekStart = days[0];
28509
28664
  const weekEnd = days[6];
28510
- if (!weekStart || !weekEnd) {
28665
+ if (weekStart === void 0 || weekEnd === void 0) {
28511
28666
  return `${monthNames[viewDate.getMonth()] ?? ""} ${viewDate.getFullYear()}`;
28512
28667
  }
28513
28668
  const startMonth = monthNames[weekStart.getMonth()] ?? "";
@@ -28613,7 +28768,9 @@ function getLocalDateKey(isoTimestamp, timeZone) {
28613
28768
  const year = parts.find((part) => part.type === "year")?.value;
28614
28769
  const month = parts.find((part) => part.type === "month")?.value;
28615
28770
  const day = parts.find((part) => part.type === "day")?.value;
28616
- if (!year || !month || !day) return null;
28771
+ if (year === void 0 || year.length === 0) return null;
28772
+ if (month === void 0 || month.length === 0) return null;
28773
+ if (day === void 0 || day.length === 0) return null;
28617
28774
  return `${year}-${month}-${day}`;
28618
28775
  }
28619
28776
  var validTimeZoneCache = /* @__PURE__ */ new Map();
@@ -28870,7 +29027,7 @@ function enumerateDateKeys(startDateKey, endDateKey) {
28870
29027
  }
28871
29028
  function parseDateKey(dateKey) {
28872
29029
  const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(dateKey);
28873
- if (!match) {
29030
+ if (match === null) {
28874
29031
  throw new Error(`Invalid timetable date key: ${dateKey}`);
28875
29032
  }
28876
29033
  const [, year, month, day] = match;
@@ -28890,7 +29047,7 @@ function groupItemsByDate(items, accessors) {
28890
29047
  const dateKey = getLocalDateKey(startsAt, timeZone);
28891
29048
  if (dateKey == null) continue;
28892
29049
  const existing = grouped.get(dateKey);
28893
- if (existing) {
29050
+ if (existing !== void 0) {
28894
29051
  existing.push(item);
28895
29052
  } else {
28896
29053
  grouped.set(dateKey, [item]);
@@ -37958,11 +38115,11 @@ function extractRouteUpdatedAt(candidate) {
37958
38115
  }
37959
38116
  function resolveRouteTargetForStage(routeIdValue, routes, stageInput) {
37960
38117
  const routeId = typeof routeIdValue === "string" ? routeIdValue : null;
37961
- if (!routeId || !routes) return null;
38118
+ if (routeId === null || routeId.length === 0 || routes === void 0) return null;
37962
38119
  const routeEntry = routes[routeId];
37963
38120
  if (!isRouteVisibleInStage(routeEntry, stageInput)) return null;
37964
38121
  const href = extractRouteHref(routeEntry, stageInput);
37965
- if (!href) return null;
38122
+ if (href === null) return null;
37966
38123
  return {
37967
38124
  routeId,
37968
38125
  href,
@@ -40033,6 +40190,7 @@ var bookingServiceSchema = z64.object({
40033
40190
  title: z64.string(),
40034
40191
  description: z64.string().nullable().optional().transform((value) => value ?? void 0),
40035
40192
  durationMinutes: z64.number().optional(),
40193
+ pricing: z64.custom().optional(),
40036
40194
  priceAmount: z64.number().nullable().optional(),
40037
40195
  priceCurrency: z64.string().nullable().optional(),
40038
40196
  paymentTerms: blockBookingPaymentTermsSchema.optional(),
@@ -68172,6 +68330,7 @@ var CANONICAL_REFUND_CONFLICT_CODES = [
68172
68330
  ];
68173
68331
  var CANONICAL_REFUND_PLANNER_ERROR_CODES = [
68174
68332
  ...CANONICAL_REFUND_CONFLICT_CODES,
68333
+ "invalid_amount",
68175
68334
  "amount_exceeds_remaining",
68176
68335
  "pass_revoke_requires_full_refund",
68177
68336
  "refund_failed"
@@ -68198,6 +68357,7 @@ var CUSTOMER_MEMBERSHIP_PAYMENT_REFUND_FAILED_CODES = [
68198
68357
  // ../api/src/bookingRefundOutcomes.ts
68199
68358
  var STANDARD_LINE_ITEM_REFUND_INVALID_CODES = [
68200
68359
  "missing_amount",
68360
+ "invalid_amount",
68201
68361
  "amount_exceeds_remaining",
68202
68362
  "credit_refunds_disabled",
68203
68363
  "missing_credit_customer",
@@ -68212,6 +68372,7 @@ var EVENT_ATTENDEE_REFUND_INVALID_CODES = [
68212
68372
  var MANAGED_PRODUCT_REFUND_INVALID_CODES = [
68213
68373
  "credit_refunds_disabled",
68214
68374
  "not_refundable",
68375
+ "invalid_amount",
68215
68376
  "amount_exceeds_remaining"
68216
68377
  ];
68217
68378
  var CUSTOMER_PASS_REFUND_INVALID_CODES = [