@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
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import z42, { z, ZodError } from 'zod';
2
+ import z41, { z } from 'zod';
3
3
  import 'react/jsx-runtime';
4
4
  import { createJiti } from 'jiti';
5
5
  import * as fs11 from 'fs';
@@ -56,13 +56,14 @@ function parseUuidBrand(value, unsafeConstructor) {
56
56
  }
57
57
  return ok(unsafeConstructor(normalized));
58
58
  }
59
- var UUID_PATTERN, unsafeAsSiteId, unsafeAsStorageBucketName, unsafeAsPositiveByteCount, unsafeAsPositiveSeconds, parseSiteId;
59
+ var UUID_PATTERN, unsafeAsSiteId, unsafeAsStorageBucketName, unsafeAsStoragePath, unsafeAsPositiveByteCount, unsafeAsPositiveSeconds, parseSiteId;
60
60
  var init_branded = __esm({
61
61
  "../core/src/branded.ts"() {
62
62
  init_result();
63
63
  UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
64
64
  unsafeAsSiteId = (id) => id;
65
65
  unsafeAsStorageBucketName = (value) => value;
66
+ unsafeAsStoragePath = (value) => value;
66
67
  unsafeAsPositiveByteCount = (value) => value;
67
68
  unsafeAsPositiveSeconds = (value) => value;
68
69
  parseSiteId = (value) => parseUuidBrand(value, unsafeAsSiteId);
@@ -168,6 +169,7 @@ function publicEventPricingType(pricing) {
168
169
  return "free";
169
170
  case "single_paid":
170
171
  case "ticket_types":
172
+ case "sliding_scale":
171
173
  case "course":
172
174
  return isFreePublicEventPriceDisplay(pricing.display) ? "free" : "paid";
173
175
  case "external":
@@ -229,11 +231,11 @@ function isValidTimeZone(timeZone) {
229
231
  }
230
232
  function getSafeTimeZone(timeZone) {
231
233
  const normalized = typeof timeZone === "string" ? timeZone.trim() : "";
232
- return normalized && isValidTimeZone(normalized) ? normalized : FALLBACK_TIMEZONE;
234
+ return normalized.length > 0 && isValidTimeZone(normalized) ? normalized : FALLBACK_TIMEZONE;
233
235
  }
234
236
  function parseStrictBookingTimeZone(timeZone) {
235
237
  const normalized = timeZone.trim();
236
- if (!normalized || !isValidTimeZone(normalized)) {
238
+ if (normalized.length === 0 || !isValidTimeZone(normalized)) {
237
239
  return null;
238
240
  }
239
241
  return normalized;
@@ -307,7 +309,7 @@ function parseScheduledBookingDateTime(input) {
307
309
  try {
308
310
  const startsAt = toUtcIsoDateTimeString(input.startsAt);
309
311
  const timeZone = parseStrictBookingTimeZone(input.timeZone);
310
- if (!timeZone) {
312
+ if (timeZone === null) {
311
313
  return {
312
314
  ok: false,
313
315
  field: "timeZone",
@@ -373,10 +375,10 @@ function normalizeLocationAddressText(value) {
373
375
  return null;
374
376
  }
375
377
  const trimmed = value.trim();
376
- return trimmed ? trimmed : null;
378
+ return trimmed.length > 0 ? trimmed : null;
377
379
  }
378
380
  function hasLocationCoordinates(value) {
379
- return typeof value?.lat === "number" && typeof value?.lng === "number";
381
+ return value != null && typeof value.lat === "number" && typeof value.lng === "number";
380
382
  }
381
383
  function toLocationCoordinates(value) {
382
384
  if (!hasLocationCoordinates(value)) {
@@ -392,6 +394,18 @@ var init_location = __esm({
392
394
  }
393
395
  });
394
396
 
397
+ // ../core/src/string.ts
398
+ function isNonEmptyString(value) {
399
+ return typeof value === "string" && value.length > 0;
400
+ }
401
+ function hasText(value) {
402
+ return isNonEmptyString(value);
403
+ }
404
+ var init_string = __esm({
405
+ "../core/src/string.ts"() {
406
+ }
407
+ });
408
+
395
409
  // ../core/src/business-address.ts
396
410
  var init_business_address = __esm({
397
411
  "../core/src/business-address.ts"() {
@@ -512,12 +526,6 @@ var init_slug = __esm({
512
526
  }
513
527
  });
514
528
 
515
- // ../core/src/string.ts
516
- var init_string = __esm({
517
- "../core/src/string.ts"() {
518
- }
519
- });
520
-
521
529
  // ../core/src/uuid.ts
522
530
  var init_uuid = __esm({
523
531
  "../core/src/uuid.ts"() {
@@ -644,8 +652,19 @@ var init_types = __esm({
644
652
  });
645
653
 
646
654
  // ../media-core/src/fileSafety.ts
655
+ function containsUnsafePathSegmentCharacter(value) {
656
+ return value.includes("/") || value.includes("\\") || CONTROL_CHARACTER_PATTERN.test(value);
657
+ }
658
+ function isReservedPathSegment(value) {
659
+ return value === "." || value === "..";
660
+ }
661
+ function isUnsafePathSegment(segment) {
662
+ return segment.trim().length === 0 || segment !== segment.trim() || isReservedPathSegment(segment) || containsUnsafePathSegmentCharacter(segment);
663
+ }
664
+ var CONTROL_CHARACTER_PATTERN;
647
665
  var init_fileSafety = __esm({
648
666
  "../media-core/src/fileSafety.ts"() {
667
+ CONTROL_CHARACTER_PATTERN = /[\u0000-\u001f\u007f]/u;
649
668
  }
650
669
  });
651
670
 
@@ -684,10 +703,20 @@ var init_fileDomain = __esm({
684
703
  });
685
704
 
686
705
  // ../media-core/src/fileStorage.ts
706
+ function parseStoragePath(value) {
707
+ return joinStoragePathSegments(value.split("/"));
708
+ }
709
+ function joinStoragePathSegments(segments) {
710
+ if (segments.some(isUnsafePathSegment)) {
711
+ return err("unsafe-path-segment");
712
+ }
713
+ return ok(unsafeAsStoragePath(segments.join("/")));
714
+ }
687
715
  var FILE_STORAGE_BUCKETS, PRIVATE_SITE_FILE_BUCKET_MIME_TYPES;
688
716
  var init_fileStorage = __esm({
689
717
  "../media-core/src/fileStorage.ts"() {
690
718
  init_src();
719
+ init_fileSafety();
691
720
  FILE_STORAGE_BUCKETS = {
692
721
  publicSite: unsafeAsStorageBucketName("media"),
693
722
  privateSite: unsafeAsStorageBucketName("site-files-private"),
@@ -839,8 +868,20 @@ var init_uploadVerificationContract = __esm({
839
868
  new Set(PRODUCT_FILE_EXTENSION_TAGS);
840
869
  }
841
870
  });
871
+
872
+ // ../media-core/src/videoPrep.ts
873
+ function unsafeAsPositiveVideoDurationSeconds(value) {
874
+ return value;
875
+ }
842
876
  var init_videoPrep = __esm({
843
877
  "../media-core/src/videoPrep.ts"() {
878
+ init_src();
879
+ ({
880
+ maxRawByteCount: unsafeAsPositiveByteCount(500 * 1024 * 1024),
881
+ inlineContentMaxDurationSeconds: unsafeAsPositiveVideoDurationSeconds(60),
882
+ backgroundVideoMaxDurationSeconds: unsafeAsPositiveVideoDurationSeconds(30),
883
+ targetMaxDimensionPixels: 1080
884
+ });
844
885
  }
845
886
  });
846
887
 
@@ -922,10 +963,10 @@ var init_identifiers = __esm({
922
963
 
923
964
  // ../media-core/src/url.ts
924
965
  function isRelativeDirectImageStoragePath(storagePath) {
925
- return RELATIVE_STORAGE_PATH_PREFIXES.some((prefix) => storagePath.startsWith(prefix));
966
+ return RELATIVE_STORAGE_PATH_PREFIXES.some((prefix) => storagePath.startsWith(prefix)) && parseStoragePath(storagePath).ok;
926
967
  }
927
968
  function isSiteScopedDirectImageStoragePath(storagePath) {
928
- return storagePath.startsWith("sites/");
969
+ return storagePath.startsWith("sites/") && parseStoragePath(storagePath).ok;
929
970
  }
930
971
  function encodeStoragePath(storagePath) {
931
972
  return storagePath.split("/").map((segment) => encodeURIComponent(segment)).join("/");
@@ -991,6 +1032,7 @@ function getDirectImageUrl(supabaseUrl, storagePath, storageBucket = "media", si
991
1032
  var RELATIVE_STORAGE_PATH_PREFIXES;
992
1033
  var init_url = __esm({
993
1034
  "../media-core/src/url.ts"() {
1035
+ init_fileStorage();
994
1036
  RELATIVE_STORAGE_PATH_PREFIXES = [
995
1037
  "originals/",
996
1038
  "variants/",
@@ -4894,44 +4936,44 @@ var init_styleTags = __esm({
4894
4936
  var hotspotSchema, rotationSchema, rectSchema, aspectCropSchema, transformSchema, mediaSchema;
4895
4937
  var init_media = __esm({
4896
4938
  "../theme-core/src/lib/media.ts"() {
4897
- hotspotSchema = z42.object({
4898
- x: z42.number().min(0).max(1),
4899
- y: z42.number().min(0).max(1),
4900
- radius: z42.number().optional()
4939
+ hotspotSchema = z41.object({
4940
+ x: z41.number().min(0).max(1),
4941
+ y: z41.number().min(0).max(1),
4942
+ radius: z41.number().optional()
4901
4943
  });
4902
- rotationSchema = z42.union([z42.literal(0), z42.literal(90), z42.literal(180), z42.literal(270)]);
4903
- rectSchema = z42.tuple([z42.number(), z42.number(), z42.number(), z42.number()]);
4904
- aspectCropSchema = z42.object({
4905
- aspect: z42.preprocess((value) => value == null ? void 0 : value, z42.string().optional()),
4906
- rect: z42.preprocess((value) => value == null ? void 0 : value, rectSchema.optional()),
4907
- hotspot: z42.preprocess((value) => value == null ? void 0 : value, hotspotSchema.optional()),
4908
- rotation: z42.preprocess((value) => value == null ? void 0 : value, rotationSchema.optional())
4944
+ rotationSchema = z41.union([z41.literal(0), z41.literal(90), z41.literal(180), z41.literal(270)]);
4945
+ rectSchema = z41.tuple([z41.number(), z41.number(), z41.number(), z41.number()]);
4946
+ aspectCropSchema = z41.object({
4947
+ aspect: z41.preprocess((value) => value == null ? void 0 : value, z41.string().optional()),
4948
+ rect: z41.preprocess((value) => value == null ? void 0 : value, rectSchema.optional()),
4949
+ hotspot: z41.preprocess((value) => value == null ? void 0 : value, hotspotSchema.optional()),
4950
+ rotation: z41.preprocess((value) => value == null ? void 0 : value, rotationSchema.optional())
4909
4951
  });
4910
- transformSchema = z42.object({
4911
- aspectCrops: z42.preprocess((value) => {
4952
+ transformSchema = z41.object({
4953
+ aspectCrops: z41.preprocess((value) => {
4912
4954
  if (!value || typeof value !== "object" || Array.isArray(value)) {
4913
4955
  return void 0;
4914
4956
  }
4915
4957
  return value;
4916
- }, z42.record(z42.string(), aspectCropSchema.catch({}))).optional(),
4958
+ }, z41.record(z41.string(), aspectCropSchema.catch({}))).optional(),
4917
4959
  rect: rectSchema.optional(),
4918
4960
  hotspot: hotspotSchema.optional(),
4919
4961
  rotation: rotationSchema.optional()
4920
4962
  });
4921
- mediaSchema = z42.object({
4922
- type: z42.enum(["image", "video", "audio", "document", "spreadsheet", "archive"]),
4923
- purpose: z42.string().optional(),
4924
- placeholder: z42.boolean().default(true).optional(),
4925
- assetId: z42.string().optional(),
4926
- identifier: z42.string().optional(),
4927
- src: z42.string().optional(),
4928
- alt: z42.string().optional(),
4929
- filename: z42.string().optional(),
4930
- mimeType: z42.string().optional(),
4931
- width: z42.number().optional(),
4932
- height: z42.number().optional(),
4933
- storageBucket: z42.string().optional(),
4934
- storagePath: z42.string().optional(),
4963
+ mediaSchema = z41.object({
4964
+ type: z41.enum(["image", "video", "audio", "document", "spreadsheet", "archive"]),
4965
+ purpose: z41.string().optional(),
4966
+ placeholder: z41.boolean().default(true).optional(),
4967
+ assetId: z41.string().optional(),
4968
+ identifier: z41.string().optional(),
4969
+ src: z41.string().optional(),
4970
+ alt: z41.string().optional(),
4971
+ filename: z41.string().optional(),
4972
+ mimeType: z41.string().optional(),
4973
+ width: z41.number().optional(),
4974
+ height: z41.number().optional(),
4975
+ storageBucket: z41.string().optional(),
4976
+ storagePath: z41.string().optional(),
4935
4977
  transform: transformSchema.optional()
4936
4978
  });
4937
4979
  }
@@ -18545,66 +18587,66 @@ var init_media2 = __esm({
18545
18587
  "archive",
18546
18588
  "audio"
18547
18589
  ];
18548
- hotspotSchema2 = z42.object({
18549
- x: z42.number().min(0).max(1),
18550
- y: z42.number().min(0).max(1),
18551
- radius: z42.number().optional()
18590
+ hotspotSchema2 = z41.object({
18591
+ x: z41.number().min(0).max(1),
18592
+ y: z41.number().min(0).max(1),
18593
+ radius: z41.number().optional()
18552
18594
  });
18553
- rotationSchema2 = z42.union([z42.literal(0), z42.literal(90), z42.literal(180), z42.literal(270)]);
18554
- rectSchema2 = z42.tuple([z42.number(), z42.number(), z42.number(), z42.number()]);
18555
- aspectCropSchema2 = z42.object({
18556
- aspect: z42.preprocess((value) => value == null ? void 0 : value, z42.string().optional()),
18557
- rect: z42.preprocess((value) => value == null ? void 0 : value, rectSchema2.optional()),
18558
- hotspot: z42.preprocess((value) => value == null ? void 0 : value, hotspotSchema2.optional()),
18559
- rotation: z42.preprocess((value) => value == null ? void 0 : value, rotationSchema2.optional())
18595
+ rotationSchema2 = z41.union([z41.literal(0), z41.literal(90), z41.literal(180), z41.literal(270)]);
18596
+ rectSchema2 = z41.tuple([z41.number(), z41.number(), z41.number(), z41.number()]);
18597
+ aspectCropSchema2 = z41.object({
18598
+ aspect: z41.preprocess((value) => value == null ? void 0 : value, z41.string().optional()),
18599
+ rect: z41.preprocess((value) => value == null ? void 0 : value, rectSchema2.optional()),
18600
+ hotspot: z41.preprocess((value) => value == null ? void 0 : value, hotspotSchema2.optional()),
18601
+ rotation: z41.preprocess((value) => value == null ? void 0 : value, rotationSchema2.optional())
18560
18602
  });
18561
- transformSchema2 = z42.object({
18562
- aspectCrops: z42.preprocess((value) => {
18603
+ transformSchema2 = z41.object({
18604
+ aspectCrops: z41.preprocess((value) => {
18563
18605
  if (!value || typeof value !== "object" || Array.isArray(value)) {
18564
18606
  return void 0;
18565
18607
  }
18566
18608
  return value;
18567
- }, z42.record(z42.string(), aspectCropSchema2.catch({}))).optional(),
18609
+ }, z41.record(z41.string(), aspectCropSchema2.catch({}))).optional(),
18568
18610
  rect: rectSchema2.optional(),
18569
18611
  hotspot: hotspotSchema2.optional(),
18570
18612
  rotation: rotationSchema2.optional()
18571
18613
  });
18572
- mediaPosterSchema = z42.discriminatedUnion("tag", [
18573
- z42.object({
18574
- tag: z42.literal("storage"),
18575
- assetId: z42.string().optional(),
18576
- storageBucket: z42.string().min(1),
18577
- storagePath: z42.string().min(1)
18614
+ mediaPosterSchema = z41.discriminatedUnion("tag", [
18615
+ z41.object({
18616
+ tag: z41.literal("storage"),
18617
+ assetId: z41.string().optional(),
18618
+ storageBucket: z41.string().min(1),
18619
+ storagePath: z41.string().min(1)
18578
18620
  }),
18579
- z42.object({
18580
- tag: z42.literal("external-src"),
18581
- assetId: z42.string().optional(),
18582
- src: z42.string().url()
18621
+ z41.object({
18622
+ tag: z41.literal("external-src"),
18623
+ assetId: z41.string().optional(),
18624
+ src: z41.string().url()
18583
18625
  })
18584
18626
  ]);
18585
- mediaBaseSchema = z42.object({
18586
- purpose: z42.string().optional(),
18587
- placeholder: z42.boolean().default(true).optional(),
18588
- assetId: z42.string().optional(),
18589
- identifier: z42.string().optional(),
18590
- src: z42.string().optional(),
18591
- alt: z42.string().optional(),
18592
- filename: z42.string().optional(),
18593
- mimeType: z42.string().optional(),
18594
- width: z42.number().optional(),
18595
- height: z42.number().optional(),
18596
- storageBucket: z42.string().optional(),
18597
- storagePath: z42.string().optional(),
18627
+ mediaBaseSchema = z41.object({
18628
+ purpose: z41.string().optional(),
18629
+ placeholder: z41.boolean().default(true).optional(),
18630
+ assetId: z41.string().optional(),
18631
+ identifier: z41.string().optional(),
18632
+ src: z41.string().optional(),
18633
+ alt: z41.string().optional(),
18634
+ filename: z41.string().optional(),
18635
+ mimeType: z41.string().optional(),
18636
+ width: z41.number().optional(),
18637
+ height: z41.number().optional(),
18638
+ storageBucket: z41.string().optional(),
18639
+ storagePath: z41.string().optional(),
18598
18640
  poster: mediaPosterSchema.optional(),
18599
18641
  transform: transformSchema2.optional()
18600
18642
  });
18601
- imageMediaSchema = mediaBaseSchema.extend({ type: z42.literal("image") });
18602
- videoMediaSchema = mediaBaseSchema.extend({ type: z42.literal("video") });
18603
- audioMediaSchema = mediaBaseSchema.extend({ type: z42.literal("audio") });
18604
- documentMediaSchema = mediaBaseSchema.extend({ type: z42.literal("document") });
18605
- spreadsheetMediaSchema = mediaBaseSchema.extend({ type: z42.literal("spreadsheet") });
18606
- archiveMediaSchema = mediaBaseSchema.extend({ type: z42.literal("archive") });
18607
- mediaSchema2 = z42.discriminatedUnion("type", [
18643
+ imageMediaSchema = mediaBaseSchema.extend({ type: z41.literal("image") });
18644
+ videoMediaSchema = mediaBaseSchema.extend({ type: z41.literal("video") });
18645
+ audioMediaSchema = mediaBaseSchema.extend({ type: z41.literal("audio") });
18646
+ documentMediaSchema = mediaBaseSchema.extend({ type: z41.literal("document") });
18647
+ spreadsheetMediaSchema = mediaBaseSchema.extend({ type: z41.literal("spreadsheet") });
18648
+ archiveMediaSchema = mediaBaseSchema.extend({ type: z41.literal("archive") });
18649
+ mediaSchema2 = z41.discriminatedUnion("type", [
18608
18650
  imageMediaSchema,
18609
18651
  videoMediaSchema,
18610
18652
  audioMediaSchema,
@@ -18795,9 +18837,12 @@ var init_schemas = __esm({
18795
18837
  });
18796
18838
  coursePricingSchema = z.object({
18797
18839
  bookingRequirement: z.enum(["none", "required"]),
18798
- pricingStrategy: z.enum(["free", "single", "tiered"]),
18840
+ pricingStrategy: z.enum(["free", "single", "tiered", "sliding_scale"]),
18799
18841
  currency: z.string(),
18800
18842
  singlePriceAmount: z.number().nullable(),
18843
+ slidingMinAmount: z.number().nullable().optional(),
18844
+ slidingMaxAmount: z.number().nullable().optional(),
18845
+ slidingSuggestedAmount: z.number().nullable().optional(),
18801
18846
  paymentTerms: blockBookingPaymentTermsSchema,
18802
18847
  options: z.array(coursePricingOptionSchema)
18803
18848
  });
@@ -18958,6 +19003,19 @@ var init_schemas2 = __esm({
18958
19003
  ticketTypes: z.array(publicEventTicketTypeSchema),
18959
19004
  display: publicEventTicketTypePriceDisplaySchema
18960
19005
  }),
19006
+ z.object({
19007
+ kind: z.literal("sliding_scale"),
19008
+ minAmount: z.number(),
19009
+ maxAmount: z.number(),
19010
+ suggestedAmount: z.number().nullable(),
19011
+ currency: z.string(),
19012
+ display: z.object({
19013
+ kind: z.literal("range"),
19014
+ minAmount: z.number(),
19015
+ maxAmount: z.number(),
19016
+ currency: z.string()
19017
+ })
19018
+ }),
18961
19019
  z.object({
18962
19020
  kind: z.literal("course"),
18963
19021
  display: z.object({ kind: z.literal("course"), display: publicCoursePriceDisplaySchema })
@@ -19412,7 +19470,7 @@ function isRecord5(value) {
19412
19470
  }
19413
19471
  function isPublicEventPricing(value) {
19414
19472
  if (!isRecord5(value) || typeof value.kind !== "string") return false;
19415
- return value.kind === "drop_in" || value.kind === "free_registration" || value.kind === "single_paid" || value.kind === "ticket_types" || value.kind === "course" || value.kind === "external";
19473
+ 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";
19416
19474
  }
19417
19475
  function isPublicEventTicketType(value) {
19418
19476
  return isRecord5(value) && typeof value.id === "string";
@@ -21840,6 +21898,7 @@ var init_booking_form_reserved_fields = __esm({
21840
21898
  "selectedDate",
21841
21899
  "selectedSlot",
21842
21900
  "discountCode",
21901
+ "selectedSlidingAmountInput",
21843
21902
  "selectedCollectionOptionKind",
21844
21903
  "selectedAppointmentPackageId"
21845
21904
  ];
@@ -29017,12 +29076,16 @@ function validationContext(options = {}) {
29017
29076
  allowIncomplete: isDraft || (options.allowIncomplete ?? false)
29018
29077
  };
29019
29078
  }
29079
+ function strictValidationContext(options = {}) {
29080
+ const ctx = validationContext(options);
29081
+ return {
29082
+ ...ctx,
29083
+ allowNull: options.allowNull ?? false
29084
+ };
29085
+ }
29020
29086
  function formatFieldPath(path28) {
29021
29087
  return path28.map((segment) => String(segment)).join(".");
29022
29088
  }
29023
- function toZodIssuePath(path28) {
29024
- return [...path28];
29025
- }
29026
29089
  function fieldIssueToMessage(issue5) {
29027
29090
  switch (issue5.kind) {
29028
29091
  case "required":
@@ -29259,70 +29322,10 @@ function resolveSelectConstraintSource(field) {
29259
29322
  return assertNever2(source);
29260
29323
  }
29261
29324
  }
29262
- function normalizeStoredContentValues(plans, content, options = {}) {
29263
- if (!content || typeof content !== "object" || Array.isArray(content)) {
29264
- return {};
29265
- }
29266
- const planMap = new Map(plans.map((plan) => [plan.fieldId, plan]));
29267
- const normalized = {};
29268
- const ctx = validationContext(options);
29269
- for (const [key, value] of Object.entries(content)) {
29270
- const plan = planMap.get(key);
29271
- normalized[key] = plan ? normalizeStoredFieldValueWithContext(plan, value, ctx) : value;
29272
- }
29273
- return normalized;
29274
- }
29275
- function normalizeStoredFieldValueWithContext(plan, value, ctx) {
29276
- if (value === null && !plan.required) {
29277
- return void 0;
29278
- }
29279
- switch (plan.kind) {
29280
- case "group":
29281
- return normalizeStoredObjectChildren(plan.children, value, childValidationContext(plan, ctx));
29282
- case "repeater":
29283
- return normalizeStoredRepeaterItems(plan, value, ctx);
29284
- case "string":
29285
- case "number":
29286
- case "boolean":
29287
- case "richText":
29288
- case "media":
29289
- case "link":
29290
- case "select":
29291
- case "passthrough":
29292
- return normalizeFieldValue(plan, value, ctx);
29293
- default:
29294
- return assertNever2(plan);
29295
- }
29296
- }
29297
- function normalizeStoredObjectChildren(children, value, ctx) {
29298
- if (!value || typeof value !== "object" || Array.isArray(value)) {
29299
- return value;
29300
- }
29301
- const normalized = { ...value };
29302
- for (const child of children) {
29303
- normalized[child.fieldId] = normalizeStoredFieldValueWithContext(
29304
- child,
29305
- normalized[child.fieldId],
29306
- ctx
29307
- );
29308
- }
29309
- return normalized;
29310
- }
29311
- function normalizeStoredRepeaterItems(plan, value, ctx) {
29312
- if (!isUnknownArray(value)) {
29313
- return value;
29314
- }
29315
- return value.map((item) => {
29316
- if (!item || typeof item !== "object" || Array.isArray(item)) {
29317
- return item;
29318
- }
29319
- const itemRecord = item;
29320
- const fields3 = plan.repeatedItemVariants ? plan.repeatedItemVariants.find((variant) => variant.typeId === itemRecord._type)?.fields : plan.repeatedItemPlan;
29321
- if (!fields3) {
29322
- return item;
29323
- }
29324
- return normalizeStoredObjectChildren(fields3, itemRecord, ctx);
29325
- });
29325
+ function validateFieldValue(plan, value, options = {}) {
29326
+ const ctx = strictValidationContext(options);
29327
+ const normalized = normalizeFieldValue(plan, value, ctx);
29328
+ return validateNormalizedFieldValue(plan, normalized, ctx);
29326
29329
  }
29327
29330
  function normalizeFieldValue(plan, value, ctx) {
29328
29331
  switch (plan.kind) {
@@ -29600,72 +29603,32 @@ function requiredIssue(plan, value) {
29600
29603
  if (Array.isArray(value)) return issue(plan, "required", { emptyOrigin: "array" });
29601
29604
  return issue(plan, "required");
29602
29605
  }
29603
- function fieldPlanToZod(plan, options = {}) {
29604
- const ctx = validationContext(options);
29605
- return z.any().transform((value) => normalizeFieldValue(plan, value, ctx)).superRefine((value, zodCtx) => {
29606
- for (const validationIssue of validateNormalizedFieldValue(plan, value, ctx)) {
29607
- addFieldIssueToZodContext(zodCtx, validationIssue, plan.path);
29608
- }
29609
- });
29606
+ function validateManifestValues(fields3, values, options = {}) {
29607
+ return deriveFieldValidationPlans(fields3).flatMap(
29608
+ (plan) => validateFieldValue(plan, values[plan.fieldId], options)
29609
+ );
29610
29610
  }
29611
- function addFieldIssueToZodContext(zodCtx, validationIssue, rootPath) {
29612
- const message = fieldIssueToMessage(validationIssue);
29613
- const path28 = relativeZodIssuePath(validationIssue.path, rootPath);
29614
- const issuePath = path28.length > 0 ? { path: toZodIssuePath(path28) } : {};
29615
- switch (validationIssue.kind) {
29616
- case "required":
29617
- if (validationIssue.emptyOrigin) {
29618
- zodCtx.addIssue({
29619
- ...issuePath,
29620
- code: "too_small",
29621
- origin: validationIssue.emptyOrigin,
29622
- minimum: 1,
29623
- inclusive: true,
29624
- message
29625
- });
29626
- return;
29627
- }
29628
- zodCtx.addIssue({ ...issuePath, code: "invalid_type", expected: "nonoptional", message });
29629
- return;
29630
- case "tooLong":
29631
- zodCtx.addIssue({
29632
- ...issuePath,
29633
- code: "too_big",
29634
- origin: "string",
29635
- maximum: validationIssue.maximum,
29636
- inclusive: true,
29637
- message
29638
- });
29639
- return;
29640
- case "invalidOption":
29641
- zodCtx.addIssue({ ...issuePath, code: "invalid_value", values: [], message });
29642
- return;
29643
- case "wrongType":
29644
- case "invalidEmail":
29645
- case "invalidPhone":
29646
- case "invalidPattern":
29647
- case "invalidUrl":
29648
- case "invalidDate":
29649
- case "invalidTime":
29650
- case "invalidDateTime":
29651
- case "invalidNumber":
29652
- case "tooSmall":
29653
- case "tooLarge":
29654
- case "invalidSlug":
29655
- case "tooFewItems":
29656
- case "tooManyItems":
29657
- case "invalidRichText":
29658
- case "invalidMedia":
29659
- case "invalidLink":
29660
- case "invalidReference":
29661
- zodCtx.addIssue({ ...issuePath, code: "custom", message });
29662
- return;
29663
- default:
29664
- assertNever2(validationIssue);
29665
- }
29611
+ function validateManifestContentForPush(fields3, values, options = {}) {
29612
+ const issues = validateManifestValues(fields3, values, options).map(toManifestContentValidationIssue);
29613
+ return issues.length === 0 ? { kind: "valid", issues: [] } : { kind: "invalid", issues };
29614
+ }
29615
+ function isTopLevelRequiredManifestContentIssue(issue5) {
29616
+ return issue5.requiredScope === "topLevel";
29617
+ }
29618
+ function formatManifestContentValidationIssue(issue5) {
29619
+ return `Invalid content${issue5.field ? ` in "${issue5.field}"` : ""}: ${issue5.message}`;
29620
+ }
29621
+ function toManifestContentValidationIssue(issue5) {
29622
+ return {
29623
+ kind: issue5.kind,
29624
+ field: formatFieldPath(issue5.path),
29625
+ message: fieldIssueToMessage(issue5),
29626
+ requiredScope: requiredScopeForIssue(issue5)
29627
+ };
29666
29628
  }
29667
- function relativeZodIssuePath(path28, rootPath) {
29668
- return startsWithFieldPath(path28, rootPath) ? path28.slice(rootPath.length) : path28;
29629
+ function requiredScopeForIssue(issue5) {
29630
+ if (issue5.kind !== "required") return null;
29631
+ return issue5.path.length === 1 ? "topLevel" : "nested";
29669
29632
  }
29670
29633
  function compilePattern(pattern) {
29671
29634
  try {
@@ -29746,13 +29709,6 @@ function isValidSelectValue(value, values, multiple) {
29746
29709
  }
29747
29710
  return typeof value === "string" && values.includes(value);
29748
29711
  }
29749
- function isEmptyValue(value) {
29750
- if (value === null || value === void 0) return true;
29751
- if (typeof value === "string" && value.trim() === "") return true;
29752
- if (Array.isArray(value) && value.length === 0) return true;
29753
- if (isEmptyRichTextDoc(value)) return true;
29754
- return false;
29755
- }
29756
29712
  function isPlainObject(value) {
29757
29713
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
29758
29714
  }
@@ -29763,16 +29719,6 @@ function isValidRichTextDoc(value) {
29763
29719
  const doc = richTextDoc(value);
29764
29720
  return Boolean(isPlainObject(doc) && doc.type === "doc");
29765
29721
  }
29766
- function isEmptyRichTextDoc(value) {
29767
- const doc = richTextDoc(value);
29768
- if (!isPlainObject(doc)) return false;
29769
- if (doc.type !== "doc") return false;
29770
- const content = doc.content;
29771
- if (!Array.isArray(content) || content.length === 0) return true;
29772
- if (content.length !== 1) return false;
29773
- const first = content[0];
29774
- return first?.type === "paragraph" && (!Array.isArray(first.content) || first.content.length === 0);
29775
- }
29776
29722
  function richTextDoc(value) {
29777
29723
  if (!isPlainObject(value)) return value;
29778
29724
  return isPlainObject(value.doc) ? value.doc : value;
@@ -29787,44 +29733,6 @@ function registerManifest(manifest) {
29787
29733
  manifestStore.set(manifest.name, manifest);
29788
29734
  return manifest;
29789
29735
  }
29790
- function preprocessEmptyValues(content) {
29791
- if (!content || typeof content !== "object" || Array.isArray(content)) {
29792
- return {};
29793
- }
29794
- const result = {};
29795
- for (const [key, value] of Object.entries(content)) {
29796
- result[key] = isEmptyValue(value) ? void 0 : value;
29797
- }
29798
- return result;
29799
- }
29800
- function createManifestValidator(manifestOrFields, options = {}) {
29801
- const isDraft = options.mode === "draft";
29802
- const plans = derivePlansFromManifestOrFields(manifestOrFields);
29803
- const baseSchema = deriveContentZodFromPlans(plans, options);
29804
- if (isDraft) {
29805
- return z.preprocess(
29806
- (content) => preprocessEmptyValues(
29807
- normalizeStoredContentValues(plans, content, options)
29808
- ),
29809
- baseSchema
29810
- );
29811
- }
29812
- return z.preprocess(
29813
- (content) => normalizeStoredContentValues(plans, content, options),
29814
- baseSchema
29815
- );
29816
- }
29817
- function deriveContentZodFromPlans(plans, options) {
29818
- const shape = {};
29819
- for (const plan of plans) {
29820
- shape[plan.fieldId] = fieldPlanToZod(plan, options);
29821
- }
29822
- return z.object(shape).catchall(z.unknown()).passthrough();
29823
- }
29824
- function derivePlansFromManifestOrFields(manifestOrFields) {
29825
- const fields3 = Array.isArray(manifestOrFields) ? manifestOrFields : manifestOrFields.fields ?? [];
29826
- return deriveFieldValidationPlans(fields3);
29827
- }
29828
29736
 
29829
29737
  // ../blocks/src/system/blocks/index.ts
29830
29738
  init_site_styles();
@@ -41542,11 +41450,11 @@ function extractRouteUpdatedAt(candidate) {
41542
41450
  }
41543
41451
  function resolveRouteTargetForStage(routeIdValue, routes, stageInput) {
41544
41452
  const routeId = typeof routeIdValue === "string" ? routeIdValue : null;
41545
- if (!routeId || !routes) return null;
41453
+ if (routeId === null || routeId.length === 0 || routes === void 0) return null;
41546
41454
  const routeEntry = routes[routeId];
41547
41455
  if (!isRouteVisibleInStage(routeEntry, stageInput)) return null;
41548
41456
  const href = extractRouteHref(routeEntry, stageInput);
41549
- if (!href) return null;
41457
+ if (href === null) return null;
41550
41458
  return {
41551
41459
  routeId,
41552
41460
  href,
@@ -46152,6 +46060,11 @@ function createOutput(options) {
46152
46060
  }
46153
46061
  };
46154
46062
  }
46063
+ function formatSize(bytes) {
46064
+ if (bytes < 1024) return `${bytes} B`;
46065
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
46066
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
46067
+ }
46155
46068
 
46156
46069
  // src/cli/errors.ts
46157
46070
  var ErrorCodes = {
@@ -48481,6 +48394,11 @@ var MIME_TYPES = {
48481
48394
  ".mp4": "video/mp4",
48482
48395
  ".webm": "video/webm",
48483
48396
  ".mov": "video/quicktime",
48397
+ ".mp3": "audio/mpeg",
48398
+ ".m4a": "audio/mp4",
48399
+ ".wav": "audio/wav",
48400
+ ".ogg": "audio/ogg",
48401
+ ".flac": "audio/flac",
48484
48402
  ".pdf": "application/pdf"
48485
48403
  };
48486
48404
  var EXTENSIONS_BY_MIME = {
@@ -48494,6 +48412,13 @@ var EXTENSIONS_BY_MIME = {
48494
48412
  "video/mp4": ".mp4",
48495
48413
  "video/webm": ".webm",
48496
48414
  "video/quicktime": ".mov",
48415
+ "audio/mpeg": ".mp3",
48416
+ "audio/mp4": ".m4a",
48417
+ "audio/wav": ".wav",
48418
+ "audio/x-wav": ".wav",
48419
+ "audio/ogg": ".ogg",
48420
+ "audio/webm": ".webm",
48421
+ "audio/flac": ".flac",
48497
48422
  "application/pdf": ".pdf"
48498
48423
  };
48499
48424
  function getMimeType(filename) {
@@ -48952,6 +48877,81 @@ var buildLocationNote = (locationsByIdentifier, identifier) => {
48952
48877
  const locations = locationsByIdentifier.get(identifier);
48953
48878
  return locations?.length ? ` Referenced at: ${locations.join(", ")}.` : "";
48954
48879
  };
48880
+ var locationsForIdentifier = (locationsByIdentifier, identifier) => {
48881
+ const locations = locationsByIdentifier.get(identifier);
48882
+ return locations?.length ? [...locations] : void 0;
48883
+ };
48884
+ var fileReportFields = (file) => {
48885
+ if (!file) return {};
48886
+ return {
48887
+ filename: file.filename,
48888
+ sizeBytes: file.data.length,
48889
+ mimeType: file.mimeType
48890
+ };
48891
+ };
48892
+ function classifyManagementApiError(error) {
48893
+ const code = error.code.toLowerCase();
48894
+ const message = error.message.toLowerCase();
48895
+ if (error.statusCode === 413 || code.includes("too_large") || message.includes("too large")) {
48896
+ return "max_object_size";
48897
+ }
48898
+ if (error.statusCode === 415 || code.includes("mime") || code.includes("content-type") || message.includes("mime") || message.includes("content-type")) {
48899
+ return "unsupported_mime";
48900
+ }
48901
+ if (error.statusCode === 402 || error.statusCode === 507 || code.includes("quota") || code.includes("storage") || message.includes("quota") || message.includes("storage limit")) {
48902
+ return "quota_or_storage_limit";
48903
+ }
48904
+ if (error.statusCode === 401 || error.statusCode === 403 || code.includes("auth") || code.includes("permission")) {
48905
+ return "auth_or_permission";
48906
+ }
48907
+ if (code === "sdk:network-error" || code === "sdk:timeout") {
48908
+ return "network";
48909
+ }
48910
+ if (code.startsWith("sdk:") || typeof error.statusCode === "number") {
48911
+ return "cms_api";
48912
+ }
48913
+ return "unknown";
48914
+ }
48915
+ function classifyErrorMessage(error) {
48916
+ const message = error.message.toLowerCase();
48917
+ if (message.includes("network") || message.includes("timeout") || message.includes("timed out")) {
48918
+ return "network";
48919
+ }
48920
+ if (message.includes("too large") || message.includes("payload too large") || message.includes("413")) {
48921
+ return "max_object_size";
48922
+ }
48923
+ if (message.includes("mime") || message.includes("content-type") || message.includes("unsupported media")) {
48924
+ return "unsupported_mime";
48925
+ }
48926
+ if (message.includes("quota") || message.includes("storage limit")) {
48927
+ return "quota_or_storage_limit";
48928
+ }
48929
+ if (message.includes("unauthorized") || message.includes("forbidden") || message.includes("permission")) {
48930
+ return "auth_or_permission";
48931
+ }
48932
+ return "unknown";
48933
+ }
48934
+ function classifyLocalMediaUploadFailure(error) {
48935
+ if (error instanceof ManagementApiError) {
48936
+ return classifyManagementApiError(error);
48937
+ }
48938
+ if (error instanceof Error) {
48939
+ return classifyErrorMessage(error);
48940
+ }
48941
+ return "unknown";
48942
+ }
48943
+ var rawErrorMessage = (error) => error instanceof Error ? error.message : String(error);
48944
+ var makeReport = (params) => {
48945
+ const failedIdentifiers = params.items.filter((item) => item.status === "failed").map((item) => item.identifier);
48946
+ const missingIdentifiers = params.items.filter((item) => item.status === "missing_local_file").map((item) => item.identifier);
48947
+ return {
48948
+ targetEnv: params.targetEnv,
48949
+ summary: { ...params.summary },
48950
+ items: params.items,
48951
+ failedIdentifiers,
48952
+ missingIdentifiers
48953
+ };
48954
+ };
48955
48955
  var loadLocalMediaFiles = async (contentDir, identifiers, manifest, errors) => {
48956
48956
  const localFiles = /* @__PURE__ */ new Map();
48957
48957
  for (const identifier of identifiers) {
@@ -48985,10 +48985,12 @@ var handleChecksumConflicts = async (options) => {
48985
48985
  assetsByIdentifier,
48986
48986
  missingIdentifiers,
48987
48987
  summary,
48988
+ reportItems,
48988
48989
  warnings,
48989
48990
  errors,
48990
48991
  locationsByIdentifier,
48991
48992
  dryRun,
48993
+ targetEnv,
48992
48994
  forceUpdateAsset
48993
48995
  } = options;
48994
48996
  const identifiersToReplace = /* @__PURE__ */ new Set();
@@ -48998,6 +49000,13 @@ var handleChecksumConflicts = async (options) => {
48998
49000
  summary.skipped += 1;
48999
49001
  const locationNote = buildLocationNote(locationsByIdentifier, identifier);
49000
49002
  warnings.push(`Missing local file for "${identifier}". Using CMS asset instead.${locationNote}`);
49003
+ reportItems.push({
49004
+ identifier,
49005
+ status: "skipped",
49006
+ targetEnv,
49007
+ locations: locationsForIdentifier(locationsByIdentifier, identifier),
49008
+ message: "Using existing CMS asset because no local file was found."
49009
+ });
49001
49010
  continue;
49002
49011
  }
49003
49012
  if (asset.checksumSha256 && asset.checksumSha256 !== localFile.checksum) {
@@ -49009,6 +49018,14 @@ var handleChecksumConflicts = async (options) => {
49009
49018
  } else {
49010
49019
  identifiersToReplace.add(identifier);
49011
49020
  }
49021
+ } else {
49022
+ reportItems.push({
49023
+ identifier,
49024
+ status: "resolved",
49025
+ targetEnv,
49026
+ ...fileReportFields(localFile),
49027
+ locations: locationsForIdentifier(locationsByIdentifier, identifier)
49028
+ });
49012
49029
  }
49013
49030
  }
49014
49031
  if (identifiersToReplace.size === 0) {
@@ -49031,10 +49048,12 @@ var resolveMissingByChecksum = async (options) => {
49031
49048
  localFiles,
49032
49049
  assetsByIdentifier,
49033
49050
  summary,
49051
+ reportItems,
49034
49052
  errors,
49035
49053
  warnings,
49036
49054
  locationsByIdentifier,
49037
49055
  dryRun,
49056
+ targetEnv,
49038
49057
  forceUpdateAsset
49039
49058
  } = options;
49040
49059
  const checksumCandidates = /* @__PURE__ */ new Map();
@@ -49045,6 +49064,13 @@ var resolveMissingByChecksum = async (options) => {
49045
49064
  errors.push(
49046
49065
  `Identifier "${identifier}" does not exist on the CMS and no local file was found. Add content/media/${identifier}.* or pull with --local-media first.${locationNote}`
49047
49066
  );
49067
+ reportItems.push({
49068
+ identifier,
49069
+ status: "missing_local_file",
49070
+ targetEnv,
49071
+ locations: locationsForIdentifier(locationsByIdentifier, identifier),
49072
+ message: `Add content/media/${identifier}.* or pull with --local-media first.`
49073
+ });
49048
49074
  continue;
49049
49075
  }
49050
49076
  checksumCandidates.set(identifier, localFile);
@@ -49065,6 +49091,15 @@ var resolveMissingByChecksum = async (options) => {
49065
49091
  const matches = assetsByChecksum.get(localFile.checksum) ?? [];
49066
49092
  if (matches.length === 0) {
49067
49093
  uploadPlans.push({ identifier, file: localFile });
49094
+ if (dryRun) {
49095
+ reportItems.push({
49096
+ identifier,
49097
+ status: "pending_upload",
49098
+ targetEnv,
49099
+ ...fileReportFields(localFile),
49100
+ locations: locationsForIdentifier(locationsByIdentifier, identifier)
49101
+ });
49102
+ }
49068
49103
  continue;
49069
49104
  }
49070
49105
  const exact = matches.find((asset) => asset.identifier === identifier);
@@ -49072,6 +49107,14 @@ var resolveMissingByChecksum = async (options) => {
49072
49107
  mapIdentifierToAsset(assetsByIdentifier, identifier, exact);
49073
49108
  missingIdentifiers.delete(identifier);
49074
49109
  summary.reused += 1;
49110
+ reportItems.push({
49111
+ identifier,
49112
+ status: "reused",
49113
+ targetEnv,
49114
+ ...fileReportFields(localFile),
49115
+ locations: locationsForIdentifier(locationsByIdentifier, identifier),
49116
+ message: "Reused existing CMS asset with matching identifier and checksum."
49117
+ });
49075
49118
  continue;
49076
49119
  }
49077
49120
  const unassigned = matches.filter((asset) => !asset.identifier);
@@ -49092,9 +49135,25 @@ var resolveMissingByChecksum = async (options) => {
49092
49135
  });
49093
49136
  summary.assigned += 1;
49094
49137
  mapIdentifierToAsset(assetsByIdentifier, identifier, assigned);
49138
+ reportItems.push({
49139
+ identifier,
49140
+ status: "assigned",
49141
+ targetEnv,
49142
+ ...fileReportFields(localFile),
49143
+ locations: locationsForIdentifier(locationsByIdentifier, identifier),
49144
+ message: "Assigned identifier to an existing matching CMS asset."
49145
+ });
49095
49146
  } else {
49096
49147
  summary.pendingAssignments += 1;
49097
49148
  mapIdentifierToAsset(assetsByIdentifier, identifier, { ...candidate, identifier });
49149
+ reportItems.push({
49150
+ identifier,
49151
+ status: "assigned",
49152
+ targetEnv,
49153
+ ...fileReportFields(localFile),
49154
+ locations: locationsForIdentifier(locationsByIdentifier, identifier),
49155
+ message: "Would assign identifier to an existing matching CMS asset."
49156
+ });
49098
49157
  }
49099
49158
  missingIdentifiers.delete(identifier);
49100
49159
  summary.reused += 1;
@@ -49113,9 +49172,25 @@ var resolveMissingByChecksum = async (options) => {
49113
49172
  });
49114
49173
  summary.assigned += 1;
49115
49174
  mapIdentifierToAsset(assetsByIdentifier, identifier, reassigned);
49175
+ reportItems.push({
49176
+ identifier,
49177
+ status: "assigned",
49178
+ targetEnv,
49179
+ ...fileReportFields(localFile),
49180
+ locations: locationsForIdentifier(locationsByIdentifier, identifier),
49181
+ message: "Assigned identifier to an existing matching CMS asset."
49182
+ });
49116
49183
  } else {
49117
49184
  summary.pendingAssignments += 1;
49118
49185
  mapIdentifierToAsset(assetsByIdentifier, identifier, { ...candidate, identifier });
49186
+ reportItems.push({
49187
+ identifier,
49188
+ status: "assigned",
49189
+ targetEnv,
49190
+ ...fileReportFields(localFile),
49191
+ locations: locationsForIdentifier(locationsByIdentifier, identifier),
49192
+ message: "Would assign identifier to an existing matching CMS asset."
49193
+ });
49119
49194
  }
49120
49195
  missingIdentifiers.delete(identifier);
49121
49196
  summary.reused += 1;
@@ -49129,7 +49204,7 @@ var resolveMissingByChecksum = async (options) => {
49129
49204
  return uploadPlans;
49130
49205
  };
49131
49206
  var uploadMissingAssets = async (options) => {
49132
- const { client, uploadPlans, assetsByIdentifier, summary, errors, dryRun } = options;
49207
+ const { client, uploadPlans, assetsByIdentifier, summary, reportItems, errors, dryRun, targetEnv, onEvent } = options;
49133
49208
  if (uploadPlans.length === 0) {
49134
49209
  return;
49135
49210
  }
@@ -49139,6 +49214,13 @@ var uploadMissingAssets = async (options) => {
49139
49214
  }
49140
49215
  const uploadedIdentifiers = [];
49141
49216
  for (const plan of uploadPlans) {
49217
+ const startedItem = {
49218
+ identifier: plan.identifier,
49219
+ status: "pending_upload",
49220
+ targetEnv,
49221
+ ...fileReportFields(plan.file)
49222
+ };
49223
+ onEvent?.({ type: "upload_started", item: startedItem });
49142
49224
  try {
49143
49225
  const result = await client.media.upload({
49144
49226
  data: plan.file.data,
@@ -49150,9 +49232,30 @@ var uploadMissingAssets = async (options) => {
49150
49232
  if (result.status === "created") {
49151
49233
  summary.uploaded += 1;
49152
49234
  }
49235
+ const uploadedItem = {
49236
+ identifier: plan.identifier,
49237
+ status: "uploaded",
49238
+ targetEnv,
49239
+ ...fileReportFields(plan.file),
49240
+ message: result.status === "created" ? "Uploaded local media file." : "CMS reported media already exists."
49241
+ };
49242
+ reportItems.push(uploadedItem);
49243
+ onEvent?.({ type: "upload_succeeded", item: uploadedItem });
49153
49244
  } catch (error) {
49154
49245
  const message = error instanceof Error ? error.message : String(error);
49155
- errors.push(`Failed to upload "${plan.identifier}": ${message}`);
49246
+ const failureKind = classifyLocalMediaUploadFailure(error);
49247
+ const failedItem = {
49248
+ identifier: plan.identifier,
49249
+ status: "failed",
49250
+ targetEnv,
49251
+ ...fileReportFields(plan.file),
49252
+ message: `Failed to upload "${plan.identifier}": ${message}`,
49253
+ failureKind,
49254
+ rawError: rawErrorMessage(error)
49255
+ };
49256
+ reportItems.push(failedItem);
49257
+ onEvent?.({ type: "upload_failed", item: failedItem });
49258
+ errors.push(`Failed to upload "${plan.identifier}" (${plan.file.filename}, ${plan.file.mimeType}): ${message}`);
49156
49259
  }
49157
49260
  }
49158
49261
  if (uploadedIdentifiers.length === 0) {
@@ -49169,10 +49272,11 @@ var uploadMissingAssets = async (options) => {
49169
49272
  }
49170
49273
  };
49171
49274
  async function syncLocalMediaForPush(options) {
49172
- const { contentDir, content, client, dryRun, forceUpdateAsset } = options;
49275
+ const { contentDir, content, client, dryRun, forceUpdateAsset, targetEnv, onEvent } = options;
49173
49276
  const manifest = await readMediaManifest(contentDir);
49174
49277
  const warnings = [];
49175
49278
  const errors = [];
49279
+ const reportItems = [];
49176
49280
  const existingIdentifiers = /* @__PURE__ */ new Set();
49177
49281
  walkLocalContentMedia(content, (value) => {
49178
49282
  if (typeof value.identifier === "string" && value.identifier.trim().length > 0) {
@@ -49238,6 +49342,7 @@ async function syncLocalMediaForPush(options) {
49238
49342
  content,
49239
49343
  manifest,
49240
49344
  summary,
49345
+ report: makeReport({ targetEnv, summary, items: reportItems }),
49241
49346
  warnings,
49242
49347
  errors,
49243
49348
  hasChanges: false
@@ -49254,10 +49359,12 @@ async function syncLocalMediaForPush(options) {
49254
49359
  assetsByIdentifier,
49255
49360
  missingIdentifiers,
49256
49361
  summary,
49362
+ reportItems,
49257
49363
  warnings,
49258
49364
  errors,
49259
49365
  locationsByIdentifier,
49260
49366
  dryRun,
49367
+ targetEnv,
49261
49368
  forceUpdateAsset
49262
49369
  });
49263
49370
  const uploadPlans = await resolveMissingByChecksum({
@@ -49266,10 +49373,12 @@ async function syncLocalMediaForPush(options) {
49266
49373
  localFiles,
49267
49374
  assetsByIdentifier,
49268
49375
  summary,
49376
+ reportItems,
49269
49377
  errors,
49270
49378
  warnings,
49271
49379
  locationsByIdentifier,
49272
49380
  dryRun,
49381
+ targetEnv,
49273
49382
  forceUpdateAsset
49274
49383
  });
49275
49384
  await uploadMissingAssets({
@@ -49277,8 +49386,11 @@ async function syncLocalMediaForPush(options) {
49277
49386
  uploadPlans,
49278
49387
  assetsByIdentifier,
49279
49388
  summary,
49389
+ reportItems,
49280
49390
  errors,
49281
- dryRun
49391
+ dryRun,
49392
+ targetEnv,
49393
+ onEvent
49282
49394
  });
49283
49395
  summary.resolved = assetsByIdentifier.size;
49284
49396
  for (const reference of mediaReferences) {
@@ -49301,6 +49413,7 @@ async function syncLocalMediaForPush(options) {
49301
49413
  content,
49302
49414
  manifest,
49303
49415
  summary,
49416
+ report: makeReport({ targetEnv, summary, items: reportItems }),
49304
49417
  warnings,
49305
49418
  errors,
49306
49419
  hasChanges
@@ -54067,18 +54180,22 @@ async function readJsonSafe(filePath) {
54067
54180
 
54068
54181
  // src/cli/commands/push/execute/diff.ts
54069
54182
  function displayDiff(params) {
54070
- const { output, diff, config: config2, dryRun, isRemote, jsonOutput, jsonDiffMode, localContent, remoteContent, humanDiff } = params;
54183
+ const { output, diff, config: config2, dryRun, isRemote, jsonOutput, jsonDiffMode, localContent, remoteContent, humanDiff, mediaReport } = params;
54071
54184
  const envLabel = isRemote ? "REMOTE" : "LOCAL";
54072
54185
  if (jsonDiffMode) {
54073
54186
  const jsonDiff = buildJsonDiff(diff, localContent, remoteContent, jsonDiffMode);
54074
- output.json(jsonDiff);
54187
+ output.json({
54188
+ ...jsonDiff,
54189
+ ...mediaReport ? { media: mediaReport } : {}
54190
+ });
54075
54191
  return;
54076
54192
  }
54077
54193
  if (jsonOutput) {
54078
54194
  output.json({
54079
54195
  summary: diff.summary,
54080
54196
  syncConfig: config2.sync,
54081
- dryRun
54197
+ dryRun,
54198
+ ...mediaReport ? { media: mediaReport } : {}
54082
54199
  });
54083
54200
  return;
54084
54201
  }
@@ -54408,7 +54525,8 @@ var salesWindowSchema = z.object({
54408
54525
  });
54409
54526
  });
54410
54527
  function validateChronologicalFields(input) {
54411
- if (!input.start || !input.end) return;
54528
+ if (input.start === void 0 || input.start.length === 0) return;
54529
+ if (input.end === void 0 || input.end.length === 0) return;
54412
54530
  if (Date.parse(input.start) < Date.parse(input.end)) return;
54413
54531
  input.ctx.addIssue({
54414
54532
  code: "custom",
@@ -54592,7 +54710,7 @@ var upsertNavigationMenuCommandSchema = z.object({
54592
54710
  location: z.enum(navigationLocations).optional(),
54593
54711
  role: z.enum(navigationMenuRoles).optional(),
54594
54712
  items: z.array(navigationItemSchema).readonly()
54595
- }).strict().refine((input) => input.name || input.location, {
54713
+ }).strict().refine((input) => input.name !== void 0 || input.location !== void 0, {
54596
54714
  message: "Navigation commands require either input.name or input.location."
54597
54715
  })
54598
54716
  }).strict();
@@ -54932,14 +55050,14 @@ var upsertBookingPassProductCommandSchema = z.object({
54932
55050
  productUseCase: z.enum(bookingPassProductUseCases).default("event_pass"),
54933
55051
  appointmentScope: appointmentPackageScopeSchema.optional()
54934
55052
  }).strict().superRefine((input, ctx) => {
54935
- if (input.productUseCase === "event_pass" && input.appointmentScope) {
55053
+ if (input.productUseCase === "event_pass" && input.appointmentScope !== void 0) {
54936
55054
  ctx.addIssue({
54937
55055
  code: "custom",
54938
55056
  path: ["appointmentScope"],
54939
55057
  message: "appointmentScope is only valid for appointment_package passes"
54940
55058
  });
54941
55059
  }
54942
- if (input.productUseCase === "appointment_package" && !input.appointmentScope) {
55060
+ if (input.productUseCase === "appointment_package" && input.appointmentScope === void 0) {
54943
55061
  ctx.addIssue({
54944
55062
  code: "custom",
54945
55063
  path: ["appointmentScope"],
@@ -55248,7 +55366,7 @@ var siteCommandBatchSchema = z.object({
55248
55366
  commands: z.array(siteCommandSchema).readonly()
55249
55367
  }).strict();
55250
55368
  function entryIdentifierForCommand(command) {
55251
- if (command.input.identifier) return command.input.identifier;
55369
+ if (command.input.identifier !== void 0 && command.input.identifier.length > 0) return command.input.identifier;
55252
55370
  switch (command.type) {
55253
55371
  case "upsertContentEntry":
55254
55372
  return refSlug(command.ref);
@@ -55259,13 +55377,13 @@ function entryIdentifierForCommand(command) {
55259
55377
  }
55260
55378
  }
55261
55379
  function pageIdentifierForCommand(command) {
55262
- if (command.input.identifier) return command.input.identifier;
55380
+ if (command.input.identifier !== void 0 && command.input.identifier.length > 0) return command.input.identifier;
55263
55381
  switch (command.type) {
55264
55382
  case "upsertPage":
55265
55383
  return refSlug(command.ref);
55266
55384
  case "publishPage":
55267
55385
  case "unpublishPage": {
55268
- if (!command.input.pageRef) {
55386
+ if (command.input.pageRef === void 0) {
55269
55387
  throw new Error(`Page command ${command.ref} is missing identifier and pageRef.`);
55270
55388
  }
55271
55389
  return refSlug(command.input.pageRef);
@@ -55279,7 +55397,7 @@ function pageIdentifierForBlockCommand(command) {
55279
55397
  return command.input.pageIdentifier;
55280
55398
  }
55281
55399
  function blockIdentifierForCommand(command) {
55282
- if (command.input.identifier) return command.input.identifier;
55400
+ if (command.input.identifier !== void 0 && command.input.identifier.length > 0) return command.input.identifier;
55283
55401
  switch (command.type) {
55284
55402
  case "upsertPageBlock":
55285
55403
  return refSlug(command.ref);
@@ -55885,7 +56003,7 @@ function getSiteCommandMetadata(type) {
55885
56003
  }
55886
56004
  function getSiteCommandLifecycleIntent(command) {
55887
56005
  if (command.type === "ensureTeamMemberProfile") {
55888
- return command.input.publish ? "publish" : "mutation";
56006
+ return command.input.publish === true ? "publish" : "mutation";
55889
56007
  }
55890
56008
  return getSiteCommandMetadata(command.type).lifecycleIntent;
55891
56009
  }
@@ -56040,7 +56158,7 @@ function commandRefContributions(command) {
56040
56158
  provides: [{ ref: command.ref, field: "ref" }],
56041
56159
  requires: [
56042
56160
  { ref: command.input.resourceRef, field: "input.resourceRef" },
56043
- ...command.input.serviceRef ? [{ ref: command.input.serviceRef, field: "input.serviceRef" }] : []
56161
+ ...command.input.serviceRef !== void 0 && command.input.serviceRef !== null ? [{ ref: command.input.serviceRef, field: "input.serviceRef" }] : []
56044
56162
  ]
56045
56163
  };
56046
56164
  case "upsertBlockTree":
@@ -56054,22 +56172,22 @@ function commandRefContributions(command) {
56054
56172
  case "upsertPageBlock":
56055
56173
  return {
56056
56174
  provides: [{ ref: command.ref, field: "ref" }],
56057
- requires: command.input.pageRef ? [{ ref: command.input.pageRef, field: "input.pageRef" }] : []
56175
+ requires: command.input.pageRef !== void 0 ? [{ ref: command.input.pageRef, field: "input.pageRef" }] : []
56058
56176
  };
56059
56177
  case "patchPageBlockContent":
56060
56178
  return {
56061
56179
  provides: [],
56062
- requires: command.input.pageRef ? [{ ref: command.input.pageRef, field: "input.pageRef" }] : []
56180
+ requires: command.input.pageRef !== void 0 ? [{ ref: command.input.pageRef, field: "input.pageRef" }] : []
56063
56181
  };
56064
56182
  case "deletePageBlock":
56065
56183
  return {
56066
56184
  provides: [],
56067
- requires: command.input.pageRef ? [{ ref: command.input.pageRef, field: "input.pageRef" }] : []
56185
+ requires: command.input.pageRef !== void 0 ? [{ ref: command.input.pageRef, field: "input.pageRef" }] : []
56068
56186
  };
56069
56187
  case "reorderPageBlocks":
56070
56188
  return {
56071
56189
  provides: [{ ref: command.ref, field: "ref" }],
56072
- requires: command.input.pageRef ? [{ ref: command.input.pageRef, field: "input.pageRef" }] : [],
56190
+ requires: command.input.pageRef !== void 0 ? [{ ref: command.input.pageRef, field: "input.pageRef" }] : [],
56073
56191
  requiresIfProvided: command.input.blocks.map((block, index) => ({
56074
56192
  ref: block.blockRef,
56075
56193
  field: `input.blocks[${index}].blockRef`
@@ -56079,7 +56197,7 @@ function commandRefContributions(command) {
56079
56197
  return {
56080
56198
  provides: [{ ref: command.ref, field: "ref" }],
56081
56199
  requires: [
56082
- ...command.input.linkedSubjectRef ? [{ ref: command.input.linkedSubjectRef, field: "input.linkedSubjectRef" }] : [],
56200
+ ...command.input.linkedSubjectRef !== void 0 ? [{ ref: command.input.linkedSubjectRef, field: "input.linkedSubjectRef" }] : [],
56083
56201
  ...(command.input.mediaRefs ?? []).map((ref, index) => ({
56084
56202
  ref,
56085
56203
  field: `input.mediaRefs[${index}]`
@@ -56096,18 +56214,18 @@ function commandRefContributions(command) {
56096
56214
  case "unpublishPage":
56097
56215
  return {
56098
56216
  provides: [],
56099
- requires: command.input.pageRef ? [{ ref: command.input.pageRef, field: "input.pageRef" }] : []
56217
+ requires: command.input.pageRef !== void 0 ? [{ ref: command.input.pageRef, field: "input.pageRef" }] : []
56100
56218
  };
56101
56219
  case "publishContentEntry":
56102
56220
  return {
56103
56221
  provides: [],
56104
- requires: command.input.contentEntryRef ? [{ ref: command.input.contentEntryRef, field: "input.contentEntryRef" }] : []
56222
+ requires: command.input.contentEntryRef !== void 0 ? [{ ref: command.input.contentEntryRef, field: "input.contentEntryRef" }] : []
56105
56223
  };
56106
56224
  case "unpublishContentEntry":
56107
56225
  case "deleteContentEntry":
56108
56226
  return {
56109
56227
  provides: [],
56110
- requires: command.input.contentEntryRef ? [{ ref: command.input.contentEntryRef, field: "input.contentEntryRef" }] : []
56228
+ requires: command.input.contentEntryRef !== void 0 ? [{ ref: command.input.contentEntryRef, field: "input.contentEntryRef" }] : []
56111
56229
  };
56112
56230
  default:
56113
56231
  return assertNever(command);
@@ -56152,7 +56270,7 @@ function collectOfferingRequires(input, intervals, intervalPath) {
56152
56270
  ];
56153
56271
  }
56154
56272
  function optionalRef(ref, field) {
56155
- return ref ? [{ ref, field }] : [];
56273
+ return ref !== void 0 && ref.length > 0 ? [{ ref, field }] : [];
56156
56274
  }
56157
56275
  function collectVenueRefsFromIntervals(intervals, path28) {
56158
56276
  return intervals.flatMap((interval, index) => optionalRef(interval.venueRef, `${path28}[${index}].venueRef`));
@@ -56217,19 +56335,19 @@ function eventSeriesStaticExecutionGaps(command) {
56217
56335
  "event_external_payment_unsupported",
56218
56336
  "External-payment event commands need public checkout/link policy mapping before mutation."
56219
56337
  )] : [],
56220
- ...command.input.waitlist && command.input.waitlist.kind !== "disabled" ? [staticGap(
56338
+ ...command.input.waitlist !== void 0 && command.input.waitlist.kind !== "disabled" ? [staticGap(
56221
56339
  "event_waitlist_requires_waitlist_adapter",
56222
56340
  "Event waitlist commands need waitlist service mapping before mutation."
56223
56341
  )] : [],
56224
- ...command.input.content?.imageRef || command.input.content?.mediaRefs ? [staticGap(
56342
+ ...command.input.content?.imageRef !== void 0 || command.input.content?.mediaRefs !== void 0 ? [staticGap(
56225
56343
  "event_media_content_requires_media_adapter",
56226
56344
  "Event media content needs media adapter mapping before mutation."
56227
56345
  )] : [],
56228
- ...command.input.content?.contentEntryRef ? [staticGap(
56346
+ ...command.input.content?.contentEntryRef !== void 0 ? [staticGap(
56229
56347
  "event_linked_content_requires_content_adapter",
56230
56348
  "Event linked content-entry refs need content adapter mapping before mutation."
56231
56349
  )] : [],
56232
- ...command.input.staffRefs?.length ? [staticGap(
56350
+ ...(command.input.staffRefs?.length ?? 0) > 0 ? [staticGap(
56233
56351
  "event_staff_assignment_unsupported",
56234
56352
  "Event staff refs need staff assignment mapping before mutation."
56235
56353
  )] : [],
@@ -56255,11 +56373,11 @@ function courseStaticExecutionGaps(command) {
56255
56373
  "course_external_payment_unsupported",
56256
56374
  "External-payment course commands need public checkout/link policy mapping before mutation."
56257
56375
  )] : [],
56258
- ...command.input.waitlist && command.input.waitlist.kind !== "disabled" ? [staticGap(
56376
+ ...command.input.waitlist !== void 0 && command.input.waitlist.kind !== "disabled" ? [staticGap(
56259
56377
  "course_waitlist_requires_waitlist_adapter",
56260
56378
  "Course waitlist commands need waitlist service mapping before mutation."
56261
56379
  )] : [],
56262
- ...command.input.staffRefs?.length ? [staticGap(
56380
+ ...(command.input.staffRefs?.length ?? 0) > 0 ? [staticGap(
56263
56381
  "course_staff_assignment_unsupported",
56264
56382
  "Course staff refs need staff assignment mapping before mutation."
56265
56383
  )] : []
@@ -56526,7 +56644,7 @@ function validateBatchRefs(batch) {
56526
56644
  requiresByCommand.set(command.ref, [...dedupeContributions(requires)]);
56527
56645
  for (const { ref } of provides) {
56528
56646
  const existing = providerByRef.get(ref);
56529
- if (existing) {
56647
+ if (existing !== void 0) {
56530
56648
  errors.push({
56531
56649
  code: "duplicate_resource_ref",
56532
56650
  resourceRef: ref,
@@ -56583,7 +56701,7 @@ function addInBatchProvidedRefRequirement(input) {
56583
56701
  const nextRequires = [...dedupeContributions([...currentRequires, input.requirement])];
56584
56702
  input.requiresByCommand.set(input.commandRef, nextRequires);
56585
56703
  const contribution = input.contributionsByCommand.get(input.commandRef);
56586
- if (contribution) {
56704
+ if (contribution !== void 0) {
56587
56705
  input.contributionsByCommand.set(input.commandRef, {
56588
56706
  ...contribution,
56589
56707
  requires: nextRequires
@@ -56629,7 +56747,7 @@ function checkPortalOrdersHaveUniqueSubjects(batch) {
56629
56747
  if (command.type !== "seedPortalOrder") continue;
56630
56748
  const key = portalOrderSubjectKey(command.input.subject);
56631
56749
  const previous = seenBySubject.get(key);
56632
- if (previous) {
56750
+ if (previous !== void 0) {
56633
56751
  errors.push(commandInvariantViolation(
56634
56752
  command.ref,
56635
56753
  "input.subject",
@@ -56751,7 +56869,7 @@ function checkTicketQuantitiesWithinCapacity(indexes) {
56751
56869
  function checkTicketsTargetTicketPricedEvents(indexes) {
56752
56870
  return indexes.ticketGroups.flatMap((tickets) => tickets.flatMap((ticket) => {
56753
56871
  const event = indexes.eventByRef.get(ticket.input.eventRef);
56754
- if (!event || event.input.pricing.kind === "ticket_types") return [];
56872
+ if (event === void 0 || event.input.pricing.kind === "ticket_types") return [];
56755
56873
  return [commandInvariantViolation(
56756
56874
  ticket.ref,
56757
56875
  "input.eventRef",
@@ -56762,10 +56880,10 @@ function checkTicketsTargetTicketPricedEvents(indexes) {
56762
56880
  function checkTicketCurrencyMatchesEvent(indexes) {
56763
56881
  return indexes.ticketGroups.flatMap((tickets) => tickets.flatMap((ticket) => {
56764
56882
  const event = indexes.eventByRef.get(ticket.input.eventRef);
56765
- if (!event || event.input.pricing.kind !== "ticket_types") return [];
56883
+ if (event === void 0 || event.input.pricing.kind !== "ticket_types") return [];
56766
56884
  const expectedCurrency = event.input.pricing.currency;
56767
56885
  const ticketCurrency = ticket.input.price.currency;
56768
- if (!expectedCurrency || !ticketCurrency || ticketCurrency === expectedCurrency) return [];
56886
+ if (!hasText(expectedCurrency) || !hasText(ticketCurrency) || ticketCurrency === expectedCurrency) return [];
56769
56887
  return [commandInvariantViolation(
56770
56888
  ticket.ref,
56771
56889
  "input.price.currency",
@@ -56793,10 +56911,11 @@ function orderCommands(commands, providerByRef, requiresByCommand) {
56793
56911
  const requires = requiresByCommand.get(command.ref) ?? [];
56794
56912
  for (const { ref } of requires) {
56795
56913
  const provider = providerByRef.get(ref);
56796
- if (!provider || provider === command.ref) continue;
56914
+ if (provider === void 0 || provider === command.ref) continue;
56797
56915
  if (!outgoing.has(provider)) outgoing.set(provider, /* @__PURE__ */ new Set());
56798
- if (!outgoing.get(provider)?.has(command.ref)) {
56799
- outgoing.get(provider)?.add(command.ref);
56916
+ const dependents = outgoing.get(provider);
56917
+ if (dependents !== void 0 && !dependents.has(command.ref)) {
56918
+ dependents.add(command.ref);
56800
56919
  indegree.set(command.ref, (indegree.get(command.ref) ?? 0) + 1);
56801
56920
  }
56802
56921
  }
@@ -56806,9 +56925,9 @@ function orderCommands(commands, providerByRef, requiresByCommand) {
56806
56925
  while (ready.length > 0) {
56807
56926
  ready.sort((left, right) => (authorIndex.get(left) ?? 0) - (authorIndex.get(right) ?? 0) || left.localeCompare(right));
56808
56927
  const nextRef = ready.shift();
56809
- if (!nextRef) continue;
56928
+ if (nextRef === void 0) continue;
56810
56929
  const command = commandByRef.get(nextRef);
56811
- if (command) ordered.push(command);
56930
+ if (command !== void 0) ordered.push(command);
56812
56931
  for (const dependent of outgoing.get(nextRef) ?? []) {
56813
56932
  const nextDegree = (indegree.get(dependent) ?? 0) - 1;
56814
56933
  indegree.set(dependent, nextDegree);
@@ -56931,7 +57050,7 @@ function stableStringify(value) {
56931
57050
  }
56932
57051
  function sortValue(value) {
56933
57052
  if (Array.isArray(value)) return value.map(sortValue);
56934
- if (value && typeof value === "object") return sortRecord(value);
57053
+ if (value !== null && typeof value === "object") return sortRecord(value);
56935
57054
  return value;
56936
57055
  }
56937
57056
  function sortRecord(record) {
@@ -58728,6 +58847,8 @@ function recordNavigationFailure(result, identifier, message) {
58728
58847
 
58729
58848
  // src/cli/site-commands/pageCommands.ts
58730
58849
  init_src();
58850
+
58851
+ // src/cli/sync/validation.ts
58731
58852
  function assertNeverField(field) {
58732
58853
  throw new Error(`Unhandled field type while extracting field ids: ${JSON.stringify(field)}`);
58733
58854
  }
@@ -58805,31 +58926,17 @@ function getDataKeys(data) {
58805
58926
  return new Set(Object.keys(data));
58806
58927
  }
58807
58928
  function validateBlockContent(data, manifest, customFields) {
58808
- const warnings = [];
58809
- try {
58810
- const manifestWithCustomFields = customFields ? { ...manifest, fields: [...manifest.fields, ...customFields] } : manifest;
58811
- const normalizedFields = parseFieldDefinitions([...manifestWithCustomFields.fields]);
58812
- const validator = createManifestValidator(normalizedFields, {
58813
- allowNull: true,
58814
- allowIncomplete: true
58815
- });
58816
- validator.parse(data);
58817
- } catch (error) {
58818
- if (error instanceof ZodError) {
58819
- for (const issue5 of error.issues) {
58820
- const fieldPath = issue5.path.join(".");
58821
- if (issue5.code === "invalid_type" && issue5.received === "undefined") {
58822
- continue;
58823
- }
58824
- warnings.push({
58825
- type: "invalid_content",
58826
- field: fieldPath || "(root)",
58827
- message: `Invalid content${fieldPath ? ` in "${fieldPath}"` : ""}: ${issue5.message}`
58828
- });
58829
- }
58830
- }
58831
- }
58832
- return warnings;
58929
+ const manifestWithCustomFields = customFields ? { ...manifest, fields: [...manifest.fields, ...customFields] } : manifest;
58930
+ const normalizedFields = parseFieldDefinitions([...manifestWithCustomFields.fields]);
58931
+ const validation = validateManifestContentForPush(normalizedFields, data);
58932
+ if (validation.kind === "valid") return [];
58933
+ return validation.issues.filter((issue5) => !isTopLevelRequiredManifestContentIssue(issue5)).map((issue5) => {
58934
+ return {
58935
+ type: "invalid_content",
58936
+ field: issue5.field || "(root)",
58937
+ message: formatManifestContentValidationIssue(issue5)
58938
+ };
58939
+ });
58833
58940
  }
58834
58941
  function validateBlockData(data, manifest, customFields) {
58835
58942
  const warnings = [];
@@ -60190,6 +60297,113 @@ async function syncMediaFilesForPush(params) {
60190
60297
  });
60191
60298
  }
60192
60299
 
60300
+ // src/cli/commands/push/execute/localMediaReporting.ts
60301
+ function targetSuffix(item) {
60302
+ return item.targetEnv ? ` to ${item.targetEnv}` : "";
60303
+ }
60304
+ function fileDetails(item) {
60305
+ const parts = [
60306
+ item.filename,
60307
+ typeof item.sizeBytes === "number" ? formatSize(item.sizeBytes) : void 0,
60308
+ item.mimeType
60309
+ ].filter((part) => Boolean(part));
60310
+ return parts.length ? ` (${parts.join(", ")})` : "";
60311
+ }
60312
+ function reportLocalMediaPushEvent(output, event) {
60313
+ switch (event.type) {
60314
+ case "upload_started":
60315
+ output.info(
60316
+ `Uploading media "${event.item.identifier}"${fileDetails(event.item)}${targetSuffix(event.item)}...`
60317
+ );
60318
+ return;
60319
+ case "upload_succeeded":
60320
+ output.info(
60321
+ `Uploaded media "${event.item.identifier}"${fileDetails(event.item)}${targetSuffix(event.item)}`
60322
+ );
60323
+ return;
60324
+ case "upload_failed":
60325
+ output.warn(
60326
+ `Failed to upload media "${event.item.identifier}"${fileDetails(event.item)}${targetSuffix(event.item)}: ${event.item.rawError ?? event.item.message ?? "Unknown error"}`
60327
+ );
60328
+ return;
60329
+ }
60330
+ }
60331
+ function reportLocalMediaPushSummary(params) {
60332
+ const { output, report, dryRun, includeResolved = false } = params;
60333
+ const { summary } = report;
60334
+ const pendingLabel = dryRun ? `${summary.pendingUploads} uploads, ${summary.pendingAssignments} identifier updates pending` : `${summary.uploaded} uploaded, ${summary.assigned} identifier updates`;
60335
+ output.info(
60336
+ `Local media${report.targetEnv ? ` (${report.targetEnv})` : ""}: ${summary.resolved} resolved, ${pendingLabel}`
60337
+ );
60338
+ for (const item of report.items) {
60339
+ if (!includeResolved && (item.status === "resolved" || item.status === "reused")) {
60340
+ continue;
60341
+ }
60342
+ switch (item.status) {
60343
+ case "pending_upload":
60344
+ output.info(
60345
+ ` Would upload "${item.identifier}"${fileDetails(item)}${targetSuffix(item)}`
60346
+ );
60347
+ break;
60348
+ case "assigned":
60349
+ output.info(` ${dryRun ? "Would assign" : "Assigned"} identifier "${item.identifier}"`);
60350
+ break;
60351
+ case "uploaded":
60352
+ output.info(` Uploaded "${item.identifier}"${fileDetails(item)}${targetSuffix(item)}`);
60353
+ break;
60354
+ case "missing_local_file":
60355
+ output.warn(` Missing local file for "${item.identifier}"${item.message ? `: ${item.message}` : ""}`);
60356
+ break;
60357
+ case "failed":
60358
+ output.warn(
60359
+ ` Failed "${item.identifier}"${fileDetails(item)}${item.failureKind ? ` [${item.failureKind}]` : ""}: ${item.rawError ?? item.message ?? "Unknown error"}`
60360
+ );
60361
+ break;
60362
+ case "skipped":
60363
+ output.info(` Skipped "${item.identifier}"${item.message ? `: ${item.message}` : ""}`);
60364
+ break;
60365
+ case "resolved":
60366
+ case "reused":
60367
+ output.info(` ${item.status === "reused" ? "Reused" : "Resolved"} "${item.identifier}"`);
60368
+ break;
60369
+ }
60370
+ }
60371
+ }
60372
+ async function syncLocalMediaForPushWithReporting(params) {
60373
+ const {
60374
+ output,
60375
+ contentDir,
60376
+ content,
60377
+ client,
60378
+ dryRun,
60379
+ targetEnv,
60380
+ isStructuredOutput,
60381
+ forceUpdateAsset,
60382
+ printSummary = true
60383
+ } = params;
60384
+ if (!isStructuredOutput) {
60385
+ output.info("Resolving local media identifiers...");
60386
+ }
60387
+ const result = await syncLocalMediaForPush({
60388
+ contentDir,
60389
+ content,
60390
+ client,
60391
+ dryRun,
60392
+ forceUpdateAsset,
60393
+ targetEnv,
60394
+ onEvent: isStructuredOutput ? void 0 : (event) => reportLocalMediaPushEvent(output, event)
60395
+ });
60396
+ result.warnings.forEach((warning) => output.warn(warning));
60397
+ if (!isStructuredOutput && printSummary && (result.report.items.length > 0 || result.hasChanges)) {
60398
+ reportLocalMediaPushSummary({
60399
+ output,
60400
+ report: result.report,
60401
+ dryRun
60402
+ });
60403
+ }
60404
+ return result;
60405
+ }
60406
+
60193
60407
  // src/cli/commands/push/execute/metadata.ts
60194
60408
  function mapIfUpdating(shouldUpdate, items, mapper) {
60195
60409
  return shouldUpdate ? items.map(mapper) : [];
@@ -60293,6 +60507,100 @@ ${errors}`
60293
60507
  output.error(message);
60294
60508
  }
60295
60509
  }
60510
+
60511
+ // src/cli/commands/push/scopes/commandBackedDatedOfferingScope.ts
60512
+ var VOLATILE_DATED_OFFERING_FIELDS = /* @__PURE__ */ new Set([
60513
+ "id",
60514
+ "siteId",
60515
+ "createdAt",
60516
+ "updatedAt",
60517
+ "contentUpdatedAt"
60518
+ ]);
60519
+ function normalizeDatedOfferingForComparison(value) {
60520
+ const normalized = JSON.parse(JSON.stringify(value));
60521
+ for (const field of VOLATILE_DATED_OFFERING_FIELDS) {
60522
+ delete normalized[field];
60523
+ }
60524
+ return normalized;
60525
+ }
60526
+ function createEmptyDryRunSummary() {
60527
+ return { created: 0, updated: 0, unchanged: 0, deleted: 0 };
60528
+ }
60529
+ function incrementDryRunSummary(summary, status) {
60530
+ switch (status) {
60531
+ case "created":
60532
+ return { ...summary, created: summary.created + 1 };
60533
+ case "updated":
60534
+ return { ...summary, updated: summary.updated + 1 };
60535
+ case "unchanged":
60536
+ return { ...summary, unchanged: summary.unchanged + 1 };
60537
+ case "deleted":
60538
+ return { ...summary, deleted: summary.deleted + 1 };
60539
+ }
60540
+ }
60541
+ function buildDatedOfferingDryRunPlan(input) {
60542
+ let summary = createEmptyDryRunSummary();
60543
+ const items = [];
60544
+ for (const item of input.localItems) {
60545
+ const identifier = input.config.getIdentifier(item);
60546
+ const remoteItem = input.config.findRemote(input.remoteItems, identifier);
60547
+ if (!remoteItem) {
60548
+ summary = incrementDryRunSummary(summary, "created");
60549
+ items.push({
60550
+ identifier,
60551
+ label: input.config.getDisplayLabel(item),
60552
+ status: "created",
60553
+ changes: []
60554
+ });
60555
+ continue;
60556
+ }
60557
+ const localObject = normalizeDatedOfferingForComparison(item);
60558
+ const remoteObject = normalizeDatedOfferingForComparison(remoteItem);
60559
+ const changes = findChangedFieldsWithValues(localObject, remoteObject);
60560
+ const status = changes.length > 0 ? "updated" : "unchanged";
60561
+ summary = incrementDryRunSummary(summary, status);
60562
+ items.push({
60563
+ identifier,
60564
+ label: input.config.getDisplayLabel(item),
60565
+ status,
60566
+ changes
60567
+ });
60568
+ }
60569
+ for (const identifier of input.orphanIdentifiers) {
60570
+ summary = incrementDryRunSummary(summary, "deleted");
60571
+ items.push({
60572
+ identifier,
60573
+ label: identifier,
60574
+ status: "deleted",
60575
+ changes: []
60576
+ });
60577
+ }
60578
+ return { summary, items };
60579
+ }
60580
+ function jsonDryRunReport(params) {
60581
+ const mode = params.jsonDiffMode ?? "summary";
60582
+ const changes = params.plan.items.filter((item) => item.status !== "unchanged").map((item) => ({
60583
+ type: params.scope,
60584
+ identifier: item.identifier,
60585
+ operation: item.status === "deleted" ? "delete" : item.status === "created" ? "create" : "update",
60586
+ ...mode === "full" ? { changes: item.changes } : {}
60587
+ }));
60588
+ return {
60589
+ mode,
60590
+ direction: "push",
60591
+ scope: params.scope,
60592
+ targetEnv: params.targetEnv,
60593
+ dryRun: true,
60594
+ summary: {
60595
+ creates: params.plan.summary.created,
60596
+ updates: params.plan.summary.updated,
60597
+ deletes: params.plan.summary.deleted,
60598
+ unchanged: params.plan.summary.unchanged
60599
+ },
60600
+ changes,
60601
+ ...params.media ? { media: params.media } : {}
60602
+ };
60603
+ }
60296
60604
  async function pushCommandBackedDatedOfferingScope(ctx, config2) {
60297
60605
  const noopResult = {
60298
60606
  status: "noop",
@@ -60372,58 +60680,84 @@ Run "riverbankcms pull ${config2.scopeCommand}" first to get latest, or use --fo
60372
60680
  const allLocalIdentifierSet = new Set(allLocalItems.map(config2.getIdentifier));
60373
60681
  const orphanIdentifiers = ctx.deleteOrphaned && !config2.shouldPushItem && remoteItems ? remoteItems.map(config2.getRemoteIdentifier).filter((identifier) => !allLocalIdentifierSet.has(identifier)) : [];
60374
60682
  if (ctx.dryRun) {
60375
- if (localItems.length > 0) {
60376
- ctx.output.info(`[DRY RUN] Would push ${localItems.length} ${config2.scopeName}`);
60683
+ const dryRunPlan = buildDatedOfferingDryRunPlan({
60684
+ localItems,
60685
+ remoteItems: remoteItems ?? [],
60686
+ orphanIdentifiers,
60687
+ config: config2
60688
+ });
60689
+ const plannedPushes = dryRunPlan.summary.created + dryRunPlan.summary.updated;
60690
+ if (ctx.jsonDiffMode) {
60691
+ ctx.output.json(jsonDryRunReport({
60692
+ scope: config2.scopeCommand,
60693
+ targetEnv: ctx.targetEnv,
60694
+ jsonDiffMode: ctx.jsonDiffMode,
60695
+ plan: dryRunPlan,
60696
+ media: config2.dryRunReportExtras?.media
60697
+ }));
60698
+ return {
60699
+ status: "dry-run",
60700
+ scopeCommand: config2.scopeCommand,
60701
+ scopeName: config2.scopeName,
60702
+ created: dryRunPlan.summary.created,
60703
+ updated: dryRunPlan.summary.updated,
60704
+ unchanged: dryRunPlan.summary.unchanged,
60705
+ deleted: dryRunPlan.summary.deleted,
60706
+ failed: 0,
60707
+ errors: [],
60708
+ media: config2.dryRunReportExtras?.media
60709
+ };
60710
+ }
60711
+ if (plannedPushes > 0) {
60712
+ ctx.output.info(
60713
+ `[DRY RUN] Would push ${plannedPushes} ${config2.scopeName} (${dryRunPlan.summary.created} create, ${dryRunPlan.summary.updated} update, ${dryRunPlan.summary.unchanged} unchanged)`
60714
+ );
60377
60715
  if (skippedUnchanged > 0) {
60378
- ctx.output.info(` (skipping ${skippedUnchanged} unchanged)`);
60379
- }
60380
- if (ctx.humanDiff && remoteItems) {
60381
- for (const item of localItems) {
60382
- const identifier = config2.getIdentifier(item);
60383
- const remoteItem = config2.findRemote(remoteItems, identifier);
60384
- if (!remoteItem) {
60385
- ctx.output.info(` + ${identifier}: ${config2.getDisplayLabel(item)} (new)`);
60386
- continue;
60387
- }
60388
- const localObject = JSON.parse(JSON.stringify(item));
60389
- const remoteObject = JSON.parse(JSON.stringify(remoteItem));
60390
- delete remoteObject.createdAt;
60391
- delete remoteObject.updatedAt;
60392
- delete remoteObject.contentUpdatedAt;
60393
- if (equal(localObject, remoteObject)) {
60394
- ctx.output.info(` = ${identifier}: ${config2.getDisplayLabel(item)} (unchanged)`);
60395
- } else {
60396
- ctx.output.info(` ~ ${identifier}: ${config2.getDisplayLabel(item)}`);
60397
- const changes = findChangedFieldsWithValues(localObject, remoteObject);
60398
- for (const change of changes) {
60716
+ ctx.output.info(` (skipping ${skippedUnchanged} filtered out)`);
60717
+ }
60718
+ } else if (dryRunPlan.summary.deleted === 0) {
60719
+ ctx.output.info(
60720
+ `[DRY RUN] No ${config2.scopeName} changes to push (${dryRunPlan.summary.unchanged} unchanged)`
60721
+ );
60722
+ }
60723
+ for (const item of dryRunPlan.items) {
60724
+ switch (item.status) {
60725
+ case "created":
60726
+ ctx.output.info(` + ${item.identifier}: ${item.label} (new)`);
60727
+ break;
60728
+ case "updated":
60729
+ ctx.output.info(` ~ ${item.identifier}: ${item.label}`);
60730
+ if (ctx.humanDiff) {
60731
+ for (const change of item.changes) {
60399
60732
  ctx.output.info(` ${change.path}: ${formatValue(change.before)} -> ${formatValue(change.after)}`);
60400
60733
  }
60401
60734
  }
60402
- }
60403
- } else {
60404
- for (const item of localItems) {
60405
- ctx.output.info(` - ${config2.getIdentifier(item)}: ${config2.getDisplayLabel(item)}`);
60406
- }
60735
+ break;
60736
+ case "unchanged":
60737
+ ctx.output.info(` = ${item.identifier}: ${item.label} (unchanged)`);
60738
+ break;
60407
60739
  }
60408
60740
  }
60409
- if (orphanIdentifiers.length > 0) {
60410
- ctx.output.info(`[DRY RUN] Would delete ${orphanIdentifiers.length} orphaned ${config2.scopeName}:`);
60411
- for (const identifier of orphanIdentifiers) {
60412
- ctx.output.info(` - ${identifier}`);
60741
+ if (dryRunPlan.summary.deleted > 0) {
60742
+ ctx.output.info(`[DRY RUN] Would delete ${dryRunPlan.summary.deleted} orphaned ${config2.scopeName}:`);
60743
+ for (const item of dryRunPlan.items.filter((candidate) => candidate.status === "deleted")) {
60744
+ ctx.output.info(` - ${item.identifier}`);
60413
60745
  }
60414
60746
  }
60415
- if (localItems.length > 0 || orphanIdentifiers.length > 0) {
60747
+ if (plannedPushes > 0 || dryRunPlan.summary.deleted > 0) {
60416
60748
  ctx.output.info("\nUse --yes (for remote) or remove --dry-run (for local) to apply changes.");
60417
60749
  }
60418
60750
  return {
60419
60751
  status: "dry-run",
60420
60752
  scopeCommand: config2.scopeCommand,
60421
60753
  scopeName: config2.scopeName,
60422
- created: 0,
60423
- updated: 0,
60424
- deleted: orphanIdentifiers.length,
60754
+ created: dryRunPlan.summary.created,
60755
+ updated: dryRunPlan.summary.updated,
60756
+ unchanged: dryRunPlan.summary.unchanged,
60757
+ deleted: dryRunPlan.summary.deleted,
60425
60758
  failed: 0,
60426
- errors: []
60759
+ errors: [],
60760
+ media: config2.dryRunReportExtras?.media
60427
60761
  };
60428
60762
  }
60429
60763
  const upserts = localItems.map((item) => ({
@@ -60548,22 +60882,23 @@ function createEmptyLocalContent() {
60548
60882
  };
60549
60883
  }
60550
60884
  async function syncLocalMediaForScopePush(ctx, content) {
60551
- ctx.output.info("Resolving local media identifiers...");
60552
- const result = await syncLocalMediaForPush({
60885
+ const result = await syncLocalMediaForPushWithReporting({
60886
+ output: ctx.output,
60553
60887
  contentDir: ctx.contentDir,
60554
60888
  content,
60555
60889
  client: ctx.client,
60556
60890
  dryRun: ctx.dryRun,
60557
- forceUpdateAsset: ctx.forceUpdateAsset
60891
+ forceUpdateAsset: ctx.forceUpdateAsset,
60892
+ targetEnv: ctx.targetEnv,
60893
+ isStructuredOutput: ctx.isStructuredOutput ?? ctx.isJsonOutput
60558
60894
  });
60559
- result.warnings.forEach((warning) => ctx.output.warn(warning));
60560
60895
  if (result.errors.length > 0) {
60561
- return { ok: false, errors: result.errors };
60896
+ return { ok: false, errors: result.errors, mediaReport: result.report };
60562
60897
  }
60563
60898
  if (!ctx.dryRun && !ctx.skipMeta) {
60564
60899
  await writeMediaManifest(ctx.contentDir, result.manifest);
60565
60900
  }
60566
- return { ok: true };
60901
+ return { ok: true, mediaReport: result.report };
60567
60902
  }
60568
60903
 
60569
60904
  // src/cli/commands/push/scopes/courses.ts
@@ -60785,7 +61120,8 @@ ${duplicate.filePaths.map((filePath) => ` - ${formatDuplicateEventFilePath(ct
60785
61120
  updated: 0,
60786
61121
  deleted: 0,
60787
61122
  failed: 0,
60788
- errors: []
61123
+ errors: [],
61124
+ media: mediaResult.mediaReport
60789
61125
  };
60790
61126
  }
60791
61127
  return pushCommandBackedDatedOfferingScope(ctx, {
@@ -60819,6 +61155,9 @@ ${duplicate.filePaths.map((filePath) => ` - ${formatDuplicateEventFilePath(ct
60819
61155
  await writeEvents(dir, pulledEvents, opts);
60820
61156
  },
60821
61157
  readOnlyStatusWarning: (event) => event.status === "completed" ? `Event ${event.identifier}: status "completed" is read-only; omitting status on push.` : null,
61158
+ dryRunReportExtras: {
61159
+ media: mediaResult.mediaReport
61160
+ },
60822
61161
  buildCompileInput: ({ source, siteId, targetEnv, upserts, deletes }) => ({
60823
61162
  source,
60824
61163
  siteId,
@@ -61679,6 +62018,8 @@ async function executeScopedPush(output, isRemote, options, globalOpts, scopeLab
61679
62018
  dryRun: options.dryRun,
61680
62019
  force: options.force ?? false,
61681
62020
  isJsonOutput: globalOpts.json ?? false,
62021
+ isStructuredOutput: Boolean(globalOpts.json || options.jsonDiffMode),
62022
+ jsonDiffMode: options.jsonDiffMode,
61682
62023
  forceUpdateAsset: options.forceUpdateAsset,
61683
62024
  deleteOrphaned: shouldDeleteOrphans,
61684
62025
  autoPullStale: options.autoPullStale ?? false,
@@ -62180,17 +62521,16 @@ ${errors}`
62180
62521
  }
62181
62522
  }
62182
62523
  }
62183
- output.info("Resolving local media identifiers...");
62184
- const localMediaResult = await syncLocalMediaForPush({
62524
+ const localMediaResult = await syncLocalMediaForPushWithReporting({
62525
+ output,
62185
62526
  contentDir,
62186
62527
  content: filteredLocal,
62187
62528
  client,
62188
62529
  dryRun,
62189
- forceUpdateAsset: options.forceUpdateAsset
62530
+ forceUpdateAsset: options.forceUpdateAsset,
62531
+ targetEnv: target,
62532
+ isStructuredOutput: jsonOutput || Boolean(jsonDiffMode)
62190
62533
  });
62191
- if (localMediaResult.warnings.length > 0) {
62192
- localMediaResult.warnings.forEach((warning) => output.warn(warning));
62193
- }
62194
62534
  if (localMediaResult.errors.length > 0) {
62195
62535
  output.error("Local media sync failed", {
62196
62536
  details: localMediaResult.errors.map((message) => ` - ${message}`).join("\n")
@@ -62228,15 +62568,12 @@ ${errors}`
62228
62568
  jsonDiffMode: jsonDiffMode ?? void 0,
62229
62569
  localContent: filteredLocal,
62230
62570
  remoteContent,
62231
- humanDiff
62571
+ humanDiff,
62572
+ mediaReport: localMediaResult.report
62232
62573
  });
62233
62574
  return { success: true };
62234
62575
  }
62235
62576
  if (localMediaResult && !dryRun) {
62236
- const mediaSummary = localMediaResult.summary;
62237
- output.info(
62238
- `Local media: ${mediaSummary.resolved} resolved, ${mediaSummary.uploaded} uploaded, ${mediaSummary.assigned} identifier updates`
62239
- );
62240
62577
  if (!skipMeta) {
62241
62578
  await writeMediaManifest(contentDir, localMediaResult.manifest);
62242
62579
  }
@@ -62269,7 +62606,8 @@ ${errors}`
62269
62606
  jsonDiffMode: jsonDiffMode ?? void 0,
62270
62607
  localContent: filteredLocal,
62271
62608
  remoteContent,
62272
- humanDiff
62609
+ humanDiff,
62610
+ mediaReport: localMediaResult.report
62273
62611
  });
62274
62612
  if (dryRun) {
62275
62613
  const preflight = preflightContentPushPlanAsCommandReport({
@@ -62340,13 +62678,6 @@ ${errors}`
62340
62678
  [DRY RUN] Would also push theme: ${themeName}`);
62341
62679
  }
62342
62680
  }
62343
- if (localMediaResult) {
62344
- const mediaSummary = localMediaResult.summary;
62345
- output.info(
62346
- `
62347
- [DRY RUN] Local media: ${mediaSummary.resolved} resolved, ${mediaSummary.pendingUploads} uploads, ${mediaSummary.pendingAssignments} identifier updates`
62348
- );
62349
- }
62350
62681
  if (options.syncMedia) {
62351
62682
  const extractable = localContentToExtractable(filteredLocal);
62352
62683
  const identifiers = extractMediaIdentifiers(extractable);
@@ -62385,10 +62716,6 @@ ${errors}`
62385
62716
  let hasFailures = syncResult.errors.length > 0;
62386
62717
  reportSyncResults({ output, result: syncResult, hasErrors: syncResult.errors.length > 0 });
62387
62718
  if (localMediaResult && !dryRun) {
62388
- const mediaSummary = localMediaResult.summary;
62389
- output.info(
62390
- `Local media: ${mediaSummary.resolved} resolved, ${mediaSummary.uploaded} uploaded, ${mediaSummary.assigned} identifier updates`
62391
- );
62392
62719
  if (!skipMeta) {
62393
62720
  await writeMediaManifest(contentDir, localMediaResult.manifest);
62394
62721
  }
@@ -62452,6 +62779,8 @@ ${errors}`
62452
62779
  dryRun: false,
62453
62780
  force: options.force ?? false,
62454
62781
  isJsonOutput,
62782
+ isStructuredOutput: isJsonOutput,
62783
+ jsonDiffMode: null,
62455
62784
  deleteOrphaned: false,
62456
62785
  autoPullStale: options.autoPullStale ?? false,
62457
62786
  skipMeta,
@@ -64508,6 +64837,12 @@ function buildBlockTypesTemplate() {
64508
64837
  "",
64509
64838
  "Reference list of all built-in CMS block types.",
64510
64839
  "The generated section is updated by `riverbankcms init-docs`.",
64840
+ "",
64841
+ "Authoring notes:",
64842
+ "- Fields marked `required` must be present with a valid value.",
64843
+ "- Optional fields may be omitted from pushed JSON; you do not need to include every key or set unused fields to `null`.",
64844
+ "- Defaults shown here document the editor/rendering contract. Include an optional field only when you want to override the default.",
64845
+ "- Required nested fields apply when their parent object or repeater item is present.",
64511
64846
  ""
64512
64847
  ].join("\n");
64513
64848
  const generated = buildBlockTypesGeneratedSection();
@@ -64526,6 +64861,12 @@ function buildSiteBlockTypesTemplate(state) {
64526
64861
  "- System blocks (`block.*`) with `blockFieldExtensions` and `blockFieldOptions` merged in",
64527
64862
  "- Custom blocks (`custom.*`) from `riverbank.config.ts`",
64528
64863
  "",
64864
+ "Authoring notes:",
64865
+ "- Fields marked `required` must be present with a valid value.",
64866
+ "- Optional fields may be omitted from pushed JSON; you do not need to include every key or set unused fields to `null`.",
64867
+ "- Defaults shown here document the editor/rendering contract. Include an optional field only when you want to override the default.",
64868
+ "- Required nested fields apply when their parent object or repeater item is present.",
64869
+ "",
64529
64870
  "The generated section is updated by `riverbankcms init-docs`.",
64530
64871
  ""
64531
64872
  ].join("\n");
@@ -65565,7 +65906,7 @@ var SimpleCache = class {
65565
65906
  };
65566
65907
 
65567
65908
  // src/version.ts
65568
- var SDK_VERSION = "0.90.1";
65909
+ var SDK_VERSION = "0.92.0";
65569
65910
 
65570
65911
  // src/client/error.ts
65571
65912
  var RiverbankApiError = class _RiverbankApiError extends Error {