@riverbankcms/sdk 0.91.0 → 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 (104) hide show
  1. package/dist/{PreviewEditorSidebar-3TT47WCF.mjs → PreviewEditorSidebar-3CI5MKV3.mjs} +2 -2
  2. package/dist/{PreviewEditorUI-ORCLLUNZ.mjs → PreviewEditorUI-DKEP636I.mjs} +2 -2
  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 +7 -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/db/src/generated/supabase/database.types.d.ts +70 -0
  35. package/dist/_dts/media-core/src/fileAssetCompatibility.d.ts +1 -1
  36. package/dist/_dts/media-core/src/filePersistence.d.ts +5 -1
  37. package/dist/_dts/media-core/src/fileStorage.d.ts +1 -0
  38. package/dist/_dts/media-core/src/videoPrep.d.ts +15 -6
  39. package/dist/_dts/media-core/src/videoSlotPolicy.d.ts +5 -5
  40. package/dist/_dts/sdk/src/cli/commands/push/execute/diff.d.ts +2 -0
  41. package/dist/_dts/sdk/src/cli/commands/push/execute/localMediaReporting.d.ts +23 -0
  42. package/dist/_dts/sdk/src/cli/commands/push/scopes/commandBackedDatedOfferingScope.d.ts +54 -0
  43. package/dist/_dts/sdk/src/cli/commands/push/scopes/mediaPrep.d.ts +7 -2
  44. package/dist/_dts/sdk/src/cli/commands/push/scopes/types.d.ts +6 -0
  45. package/dist/_dts/sdk/src/cli/media/local-sync.d.ts +35 -0
  46. package/dist/_dts/sdk/src/rendering/islands/types.d.ts +23 -1
  47. package/dist/_dts/sdk/src/version.d.ts +1 -1
  48. package/dist/{chunk-AFPMCLS7.mjs → chunk-6D7PLF4M.mjs} +1 -1
  49. package/dist/{chunk-RQUZYSES.mjs → chunk-I6EOKV6B.mjs} +520 -40
  50. package/dist/{chunk-S3YHJWEU.mjs → chunk-LERKJM3E.mjs} +5 -5
  51. package/dist/{chunk-GDT2QGIL.mjs → chunk-UOMTCHZD.mjs} +1 -1
  52. package/dist/cli/index.mjs +552 -80
  53. package/dist/client/{accordion-AFX37652.mjs → accordion-BUDH2G3S.mjs} +2 -2
  54. package/dist/client/{bookingForm-32V5QCOW.mjs → bookingForm-NQMCELVB.mjs} +89 -14
  55. package/dist/client/bookings.mjs +243 -17
  56. package/dist/client/{carousel-TJGQJ7ER.mjs → carousel-ONCEW6IJ.mjs} +3 -3
  57. package/dist/client/{cart-JUU2JEW4.mjs → cart-V2TCK2GI.mjs} +7 -7
  58. package/dist/client/{checkout-RD6BTFX4.mjs → checkout-ZI7SWNCS.mjs} +7 -7
  59. package/dist/client/{chunk-FMZZHAIR.mjs → chunk-AUMRQ242.mjs} +52 -5
  60. package/dist/client/{chunk-PMNAV6LO.mjs → chunk-B5UC2D6X.mjs} +7 -6
  61. package/dist/client/{chunk-6RN62XBV.mjs → chunk-ERQDHUS2.mjs} +1 -1
  62. package/dist/client/{chunk-RWYFG625.mjs → chunk-GH6IIOOE.mjs} +30 -2
  63. package/dist/client/{chunk-C4LP6BPG.mjs → chunk-HQWIJLYN.mjs} +1 -1
  64. package/dist/client/{chunk-RMOFBBNA.mjs → chunk-JXY6NHG6.mjs} +6 -6
  65. package/dist/client/{chunk-6QZIBNGV.mjs → chunk-KXYEKEV6.mjs} +154 -16
  66. package/dist/client/{chunk-E6VIWZUG.mjs → chunk-N2WJPTF7.mjs} +3 -3
  67. package/dist/client/{chunk-ISAUXU5R.mjs → chunk-QQNVQ62W.mjs} +1 -1
  68. package/dist/client/{chunk-MLBNVN4H.mjs → chunk-R3CZQLXF.mjs} +67 -4
  69. package/dist/client/{chunk-WHZQDPBZ.mjs → chunk-TNGL2WJF.mjs} +1 -0
  70. package/dist/client/{chunk-CKXEUWWA.mjs → chunk-ZJDBOLX7.mjs} +3 -3
  71. package/dist/client/client.mjs +515 -38
  72. package/dist/client/{courseRegistration-X63QAIVV.mjs → courseRegistration-JPWAQ6KM.mjs} +111 -11
  73. package/dist/client/{eventCalendar-5T24GCZL.mjs → eventCalendar-QDOCHBBV.mjs} +9 -9
  74. package/dist/client/{eventCombined-AZVTF22X.mjs → eventCombined-ZS2CXSIE.mjs} +9 -9
  75. package/dist/client/{eventDetails-7GPFNLGF.mjs → eventDetails-5LOBMPLN.mjs} +9 -9
  76. package/dist/client/{eventListing-QEUMTMUM.mjs → eventListing-SBGY4I3L.mjs} +9 -9
  77. package/dist/client/{eventRegistration-P2EDKCQZ.mjs → eventRegistration-XGPIU3Z2.mjs} +9 -9
  78. package/dist/client/{form-NUJ7H4IN.mjs → form-R7D4LZWW.mjs} +3 -3
  79. package/dist/client/{headerSection-JB7LECPL.mjs → headerSection-RRLYUCGC.mjs} +3 -3
  80. package/dist/client/hooks.mjs +22 -2
  81. package/dist/client/{locationMap-UEYWUCSW.mjs → locationMap-35ZJMRBZ.mjs} +3 -3
  82. package/dist/client/{newsletterForm-S2YZQ2X7.mjs → newsletterForm-MJ2VCFUT.mjs} +3 -3
  83. package/dist/client/{productDetail-H5MADGG7.mjs → productDetail-2O7YQNBX.mjs} +7 -7
  84. package/dist/client/{productList-DK7YON7H.mjs → productList-FDP5BH7W.mjs} +7 -7
  85. package/dist/client/rendering/client.mjs +495 -36
  86. package/dist/client/rendering/islands.mjs +19 -19
  87. package/dist/client/rendering.mjs +514 -37
  88. package/dist/client/{shop-6PA7RDRJ.mjs → shop-BGYJ3LDT.mjs} +7 -7
  89. package/dist/preview-next/client/runtime.mjs +3 -3
  90. package/dist/{sdk-runtime-JP5347OB.mjs → sdk-runtime-B3TFXRXZ.mjs} +4 -4
  91. package/dist/server/components.mjs +166 -7
  92. package/dist/server/config-validation.mjs +23 -2
  93. package/dist/server/config.mjs +23 -2
  94. package/dist/server/data.mjs +22 -2
  95. package/dist/server/index.mjs +1 -1
  96. package/dist/server/next.mjs +167 -8
  97. package/dist/server/page-converter.mjs +19 -2
  98. package/dist/server/prebuild.mjs +1 -1
  99. package/dist/server/rendering/server.mjs +166 -7
  100. package/dist/server/rendering.mjs +166 -7
  101. package/dist/server/routing.mjs +29 -5
  102. package/dist/server/server.mjs +23 -3
  103. package/package.json +1 -1
  104. package/dist/SdkPreviewModeRuntime-GMCDQPZZ.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
  }
@@ -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) {
@@ -40035,6 +40190,7 @@ var bookingServiceSchema = z64.object({
40035
40190
  title: z64.string(),
40036
40191
  description: z64.string().nullable().optional().transform((value) => value ?? void 0),
40037
40192
  durationMinutes: z64.number().optional(),
40193
+ pricing: z64.custom().optional(),
40038
40194
  priceAmount: z64.number().nullable().optional(),
40039
40195
  priceCurrency: z64.string().nullable().optional(),
40040
40196
  paymentTerms: blockBookingPaymentTermsSchema.optional(),
@@ -68174,6 +68330,7 @@ var CANONICAL_REFUND_CONFLICT_CODES = [
68174
68330
  ];
68175
68331
  var CANONICAL_REFUND_PLANNER_ERROR_CODES = [
68176
68332
  ...CANONICAL_REFUND_CONFLICT_CODES,
68333
+ "invalid_amount",
68177
68334
  "amount_exceeds_remaining",
68178
68335
  "pass_revoke_requires_full_refund",
68179
68336
  "refund_failed"
@@ -68200,6 +68357,7 @@ var CUSTOMER_MEMBERSHIP_PAYMENT_REFUND_FAILED_CODES = [
68200
68357
  // ../api/src/bookingRefundOutcomes.ts
68201
68358
  var STANDARD_LINE_ITEM_REFUND_INVALID_CODES = [
68202
68359
  "missing_amount",
68360
+ "invalid_amount",
68203
68361
  "amount_exceeds_remaining",
68204
68362
  "credit_refunds_disabled",
68205
68363
  "missing_credit_customer",
@@ -68214,6 +68372,7 @@ var EVENT_ATTENDEE_REFUND_INVALID_CODES = [
68214
68372
  var MANAGED_PRODUCT_REFUND_INVALID_CODES = [
68215
68373
  "credit_refunds_disabled",
68216
68374
  "not_refundable",
68375
+ "invalid_amount",
68217
68376
  "amount_exceeds_remaining"
68218
68377
  ];
68219
68378
  var CUSTOMER_PASS_REFUND_INVALID_CODES = [
@@ -126,6 +126,8 @@ function err(error) {
126
126
 
127
127
  // ../core/src/branded.ts
128
128
  var unsafeAsMediaAssetId = (id) => id;
129
+ var unsafeAsStorageBucketName = (value) => value;
130
+ var unsafeAsStoragePath = (value) => value;
129
131
 
130
132
  // ../core/src/assert-never.ts
131
133
  function assertNever(value, message = "Unexpected variant") {
@@ -180,6 +182,7 @@ function publicEventPricingType(pricing) {
180
182
  return "free";
181
183
  case "single_paid":
182
184
  case "ticket_types":
185
+ case "sliding_scale":
183
186
  case "course":
184
187
  return isFreePublicEventPriceDisplay(pricing.display) ? "free" : "paid";
185
188
  case "external":
@@ -192,6 +195,7 @@ function publicEventPricingCurrency(pricing) {
192
195
  case "free_registration":
193
196
  case "single_paid":
194
197
  case "ticket_types":
198
+ case "sliding_scale":
195
199
  return pricing.currency;
196
200
  case "course":
197
201
  return pricing.display.display.currency;
@@ -223,6 +227,8 @@ function formatCoursePriceDisplayLabel(display, options) {
223
227
  return `Course (${formatCurrencyAmount(display.amount, display.currency, options)})`;
224
228
  case "from":
225
229
  return `Course (From ${formatCurrencyAmount(display.amount, display.currency, options)})`;
230
+ case "range":
231
+ return `Course (${formatCurrencyAmount(display.minAmount, display.currency, options)} - ${formatCurrencyAmount(display.maxAmount, display.currency, options)})`;
226
232
  default:
227
233
  return assertNever(display);
228
234
  }
@@ -514,6 +520,77 @@ function resolvePlanningDateInput(input = {}) {
514
520
  return resolvePlanningNowDate(input);
515
521
  }
516
522
 
523
+ // ../media-core/src/fileSafety.ts
524
+ var CONTROL_CHARACTER_PATTERN = /[\u0000-\u001f\u007f]/u;
525
+ function containsUnsafePathSegmentCharacter(value) {
526
+ return value.includes("/") || value.includes("\\") || CONTROL_CHARACTER_PATTERN.test(value);
527
+ }
528
+ function isReservedPathSegment(value) {
529
+ return value === "." || value === "..";
530
+ }
531
+ function isUnsafePathSegment(segment) {
532
+ return segment.trim().length === 0 || segment !== segment.trim() || isReservedPathSegment(segment) || containsUnsafePathSegmentCharacter(segment);
533
+ }
534
+
535
+ // ../media-core/src/fileStorage.ts
536
+ var FILE_STORAGE_BUCKETS = {
537
+ publicSite: unsafeAsStorageBucketName("media"),
538
+ privateSite: unsafeAsStorageBucketName("site-files-private"),
539
+ temporary: unsafeAsStorageBucketName("temp-uploads")
540
+ };
541
+ var PUBLIC_SITE_FILE_STORAGE_BUCKETS = [
542
+ FILE_STORAGE_BUCKETS.publicSite,
543
+ // Existing site logo and font uploads predate the unified file buckets.
544
+ unsafeAsStorageBucketName("site-assets"),
545
+ unsafeAsStorageBucketName("site-fonts")
546
+ ];
547
+ var PRIVATE_SITE_FILE_BUCKET_MIME_TYPES = [
548
+ "application/pdf",
549
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
550
+ "text/plain",
551
+ "application/rtf",
552
+ "text/rtf",
553
+ "image/jpeg",
554
+ "image/png",
555
+ "image/webp",
556
+ "image/gif",
557
+ "image/avif",
558
+ "image/heic",
559
+ "image/heif",
560
+ "image/svg+xml",
561
+ "text/csv",
562
+ "application/csv",
563
+ "application/vnd.ms-excel",
564
+ "application/zip",
565
+ "application/x-zip-compressed",
566
+ "audio/mpeg",
567
+ "audio/mp4",
568
+ "audio/wav",
569
+ "audio/x-wav",
570
+ "audio/ogg",
571
+ "audio/webm",
572
+ "audio/flac",
573
+ "video/mp4",
574
+ "video/webm",
575
+ "video/quicktime"
576
+ ];
577
+ var TEMP_UPLOAD_BUCKET_MIME_TYPES = [
578
+ ...PRIVATE_SITE_FILE_BUCKET_MIME_TYPES,
579
+ "font/woff2",
580
+ "application/font-woff2",
581
+ "application/x-font-woff2",
582
+ "application/octet-stream"
583
+ ];
584
+ function parseStoragePath(value) {
585
+ return joinStoragePathSegments(value.split("/"));
586
+ }
587
+ function joinStoragePathSegments(segments) {
588
+ if (segments.some(isUnsafePathSegment)) {
589
+ return err("unsafe-path-segment");
590
+ }
591
+ return ok(unsafeAsStoragePath(segments.join("/")));
592
+ }
593
+
517
594
  // ../media-core/src/typeGuards.ts
518
595
  function isRecord(value) {
519
596
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
@@ -530,10 +607,10 @@ var RELATIVE_STORAGE_PATH_PREFIXES = [
530
607
  "imports/"
531
608
  ];
532
609
  function isRelativeDirectImageStoragePath(storagePath) {
533
- return RELATIVE_STORAGE_PATH_PREFIXES.some((prefix) => storagePath.startsWith(prefix));
610
+ return RELATIVE_STORAGE_PATH_PREFIXES.some((prefix) => storagePath.startsWith(prefix)) && parseStoragePath(storagePath).ok;
534
611
  }
535
612
  function isSiteScopedDirectImageStoragePath(storagePath) {
536
- return storagePath.startsWith("sites/");
613
+ return storagePath.startsWith("sites/") && parseStoragePath(storagePath).ok;
537
614
  }
538
615
  function encodeStoragePath(storagePath) {
539
616
  return storagePath.split("/").map((segment) => encodeURIComponent(segment)).join("/");
@@ -3006,6 +3083,21 @@ function fieldPlanToZod(plan, options = {}) {
3006
3083
  }
3007
3084
  });
3008
3085
  }
3086
+ function fieldPresenceForPlan(plan) {
3087
+ return plan.required ? { kind: "required" } : { kind: "optional" };
3088
+ }
3089
+ function fieldPlanToObjectPropertyZod(plan, options = {}) {
3090
+ const schema = fieldPlanToZod(plan, options);
3091
+ const presence = fieldPresenceForPlan(plan);
3092
+ switch (presence.kind) {
3093
+ case "required":
3094
+ return schema;
3095
+ case "optional":
3096
+ return schema.optional();
3097
+ default:
3098
+ return assertNever2(presence);
3099
+ }
3100
+ }
3009
3101
  function addFieldIssueToZodContext(zodCtx, validationIssue, rootPath) {
3010
3102
  const message = fieldIssueToMessage(validationIssue);
3011
3103
  const path = relativeZodIssuePath(validationIssue.path, rootPath);
@@ -3218,7 +3310,7 @@ function createManifestValidator(manifestOrFields, options = {}) {
3218
3310
  function deriveContentZodFromPlans(plans, options) {
3219
3311
  const shape = {};
3220
3312
  for (const plan of plans) {
3221
- shape[plan.fieldId] = fieldPlanToZod(plan, options);
3313
+ shape[plan.fieldId] = fieldPlanToObjectPropertyZod(plan, options);
3222
3314
  }
3223
3315
  return z5.object(shape).catchall(z5.unknown()).passthrough();
3224
3316
  }
@@ -26327,9 +26419,12 @@ var coursePricingOptionSchema = z43.object({
26327
26419
  });
26328
26420
  var coursePricingSchema = z43.object({
26329
26421
  bookingRequirement: z43.enum(["none", "required"]),
26330
- pricingStrategy: z43.enum(["free", "single", "tiered"]),
26422
+ pricingStrategy: z43.enum(["free", "single", "tiered", "sliding_scale"]),
26331
26423
  currency: z43.string(),
26332
26424
  singlePriceAmount: z43.number().nullable(),
26425
+ slidingMinAmount: z43.number().nullable().optional(),
26426
+ slidingMaxAmount: z43.number().nullable().optional(),
26427
+ slidingSuggestedAmount: z43.number().nullable().optional(),
26333
26428
  paymentTerms: blockBookingPaymentTermsSchema,
26334
26429
  options: z43.array(coursePricingOptionSchema)
26335
26430
  });
@@ -26483,6 +26578,19 @@ var publicEventPricingSchema = z44.discriminatedUnion("kind", [
26483
26578
  ticketTypes: z44.array(publicEventTicketTypeSchema),
26484
26579
  display: publicEventTicketTypePriceDisplaySchema
26485
26580
  }),
26581
+ z44.object({
26582
+ kind: z44.literal("sliding_scale"),
26583
+ minAmount: z44.number(),
26584
+ maxAmount: z44.number(),
26585
+ suggestedAmount: z44.number().nullable(),
26586
+ currency: z44.string(),
26587
+ display: z44.object({
26588
+ kind: z44.literal("range"),
26589
+ minAmount: z44.number(),
26590
+ maxAmount: z44.number(),
26591
+ currency: z44.string()
26592
+ })
26593
+ }),
26486
26594
  z44.object({
26487
26595
  kind: z44.literal("course"),
26488
26596
  display: z44.object({ kind: z44.literal("course"), display: publicCoursePriceDisplaySchema })
@@ -26899,7 +27007,7 @@ function isRecord6(value) {
26899
27007
  }
26900
27008
  function isPublicEventPricing(value) {
26901
27009
  if (!isRecord6(value) || typeof value.kind !== "string") return false;
26902
- return value.kind === "drop_in" || value.kind === "free_registration" || value.kind === "single_paid" || value.kind === "ticket_types" || value.kind === "course" || value.kind === "external";
27010
+ 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";
26903
27011
  }
26904
27012
  function isPublicEventTicketType(value) {
26905
27013
  return isRecord6(value) && typeof value.id === "string";
@@ -27516,7 +27624,9 @@ function getSelectableCoursePricingOptionsForNow(course, now) {
27516
27624
  return left.name.localeCompare(right.name);
27517
27625
  });
27518
27626
  }
27519
- function resolveCoursePricingState(course, selectedPricingOptionId, nowInput = {}) {
27627
+ function resolveCoursePricingState(course, selectedPricingOptionId, selectedSlidingAmountOrNowInput, nowInput = {}) {
27628
+ const selectedSlidingAmount = typeof selectedSlidingAmountOrNowInput === "number" || selectedSlidingAmountOrNowInput === null ? selectedSlidingAmountOrNowInput : null;
27629
+ const effectiveNowInput = typeof selectedSlidingAmountOrNowInput === "object" && selectedSlidingAmountOrNowInput !== null ? selectedSlidingAmountOrNowInput : nowInput;
27520
27630
  const currency = course.pricing?.currency ?? course.currency;
27521
27631
  if (!course.pricing) {
27522
27632
  const legacyAmount = course.priceCents ?? 0;
@@ -27526,6 +27636,8 @@ function resolveCoursePricingState(course, selectedPricingOptionId, nowInput = {
27526
27636
  selectableOptions: [],
27527
27637
  requiresSelection: false,
27528
27638
  selectedOption: null,
27639
+ slidingScale: null,
27640
+ selectedSlidingAmount: null,
27529
27641
  selectedPriceAmount: legacyAmount,
27530
27642
  selectedRequiresPayment: legacyAmount > 0,
27531
27643
  hasPaidSelection: legacyAmount > 0,
@@ -27540,6 +27652,8 @@ function resolveCoursePricingState(course, selectedPricingOptionId, nowInput = {
27540
27652
  selectableOptions: [],
27541
27653
  requiresSelection: false,
27542
27654
  selectedOption: null,
27655
+ slidingScale: null,
27656
+ selectedSlidingAmount: null,
27543
27657
  selectedPriceAmount: 0,
27544
27658
  selectedRequiresPayment: false,
27545
27659
  hasPaidSelection: false,
@@ -27553,6 +27667,8 @@ function resolveCoursePricingState(course, selectedPricingOptionId, nowInput = {
27553
27667
  selectableOptions: [],
27554
27668
  requiresSelection: false,
27555
27669
  selectedOption: null,
27670
+ slidingScale: null,
27671
+ selectedSlidingAmount: null,
27556
27672
  selectedPriceAmount: amount,
27557
27673
  selectedRequiresPayment: amount > 0,
27558
27674
  hasPaidSelection: amount > 0,
@@ -27562,7 +27678,7 @@ function resolveCoursePricingState(course, selectedPricingOptionId, nowInput = {
27562
27678
  case "tiered": {
27563
27679
  const selectableOptions = getSelectableCoursePricingOptionsForNow(
27564
27680
  course,
27565
- resolvePlanningDateInput(nowInput)
27681
+ resolvePlanningDateInput(effectiveNowInput)
27566
27682
  );
27567
27683
  const selectedOption = (selectedPricingOptionId ? selectableOptions.find((option) => option.id === selectedPricingOptionId) : null) ?? (selectableOptions.length === 1 ? selectableOptions[0] ?? null : null);
27568
27684
  const lowestAmount = selectableOptions.reduce((lowest, option) => {
@@ -27578,12 +27694,51 @@ function resolveCoursePricingState(course, selectedPricingOptionId, nowInput = {
27578
27694
  selectableOptions,
27579
27695
  requiresSelection: selectableOptions.length > 1,
27580
27696
  selectedOption,
27697
+ slidingScale: null,
27698
+ selectedSlidingAmount: null,
27581
27699
  selectedPriceAmount: selectedOption?.priceAmount ?? null,
27582
27700
  selectedRequiresPayment: (selectedOption?.priceAmount ?? 0) > 0,
27583
27701
  hasPaidSelection: selectableOptions.some((option) => option.priceAmount > 0),
27584
27702
  hasFreeSelection: selectableOptions.some((option) => option.priceAmount === 0)
27585
27703
  };
27586
27704
  }
27705
+ case "sliding_scale": {
27706
+ const minAmount = course.pricing.slidingMinAmount ?? null;
27707
+ const maxAmount = course.pricing.slidingMaxAmount ?? null;
27708
+ if (minAmount === null || maxAmount === null || minAmount < 0 || maxAmount < minAmount) {
27709
+ return {
27710
+ currency,
27711
+ display: { kind: "unavailable", currency },
27712
+ selectableOptions: [],
27713
+ requiresSelection: true,
27714
+ selectedOption: null,
27715
+ slidingScale: null,
27716
+ selectedSlidingAmount: null,
27717
+ selectedPriceAmount: null,
27718
+ selectedRequiresPayment: false,
27719
+ hasPaidSelection: false,
27720
+ hasFreeSelection: false
27721
+ };
27722
+ }
27723
+ const normalizedSelectedAmount = typeof selectedSlidingAmount === "number" && Number.isFinite(selectedSlidingAmount) ? selectedSlidingAmount : null;
27724
+ return {
27725
+ currency,
27726
+ display: { kind: "range", minAmount, maxAmount, currency },
27727
+ selectableOptions: [],
27728
+ requiresSelection: normalizedSelectedAmount === null,
27729
+ selectedOption: null,
27730
+ slidingScale: {
27731
+ minAmount,
27732
+ maxAmount,
27733
+ suggestedAmount: course.pricing.slidingSuggestedAmount ?? null
27734
+ },
27735
+ selectedSlidingAmount: normalizedSelectedAmount,
27736
+ selectedPriceAmount: normalizedSelectedAmount,
27737
+ selectedRequiresPayment: (normalizedSelectedAmount ?? 0) > 0,
27738
+ hasPaidSelection: maxAmount > 0,
27739
+ hasFreeSelection: minAmount === 0
27740
+ };
27741
+ }
27587
27742
  }
27588
27743
  }
27589
27744
  function formatCoursePriceDisplay(display, locale) {
@@ -40069,6 +40224,7 @@ var bookingServiceSchema = z64.object({
40069
40224
  title: z64.string(),
40070
40225
  description: z64.string().nullable().optional().transform((value) => value ?? void 0),
40071
40226
  durationMinutes: z64.number().optional(),
40227
+ pricing: z64.custom().optional(),
40072
40228
  priceAmount: z64.number().nullable().optional(),
40073
40229
  priceCurrency: z64.string().nullable().optional(),
40074
40230
  paymentTerms: blockBookingPaymentTermsSchema.optional(),
@@ -68225,6 +68381,7 @@ var CANONICAL_REFUND_CONFLICT_CODES = [
68225
68381
  ];
68226
68382
  var CANONICAL_REFUND_PLANNER_ERROR_CODES = [
68227
68383
  ...CANONICAL_REFUND_CONFLICT_CODES,
68384
+ "invalid_amount",
68228
68385
  "amount_exceeds_remaining",
68229
68386
  "pass_revoke_requires_full_refund",
68230
68387
  "refund_failed"
@@ -68251,6 +68408,7 @@ var CUSTOMER_MEMBERSHIP_PAYMENT_REFUND_FAILED_CODES = [
68251
68408
  // ../api/src/bookingRefundOutcomes.ts
68252
68409
  var STANDARD_LINE_ITEM_REFUND_INVALID_CODES = [
68253
68410
  "missing_amount",
68411
+ "invalid_amount",
68254
68412
  "amount_exceeds_remaining",
68255
68413
  "credit_refunds_disabled",
68256
68414
  "missing_credit_customer",
@@ -68265,6 +68423,7 @@ var EVENT_ATTENDEE_REFUND_INVALID_CODES = [
68265
68423
  var MANAGED_PRODUCT_REFUND_INVALID_CODES = [
68266
68424
  "credit_refunds_disabled",
68267
68425
  "not_refundable",
68426
+ "invalid_amount",
68268
68427
  "amount_exceeds_remaining"
68269
68428
  ];
68270
68429
  var CUSTOMER_PASS_REFUND_INVALID_CODES = [