@riverbankcms/sdk 0.98.0 → 0.99.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 (120) hide show
  1. package/dist/{PreviewEditorSidebar-CG3SSJND.mjs → PreviewEditorSidebar-TPOKCCKY.mjs} +3 -3
  2. package/dist/{PreviewEditorUI-RHNGKAAU.mjs → PreviewEditorUI-Y347GLC2.mjs} +3 -3
  3. package/dist/SdkPreviewModeRuntime-OGTXRQ4M.mjs +8 -0
  4. package/dist/_dts/ai/src/contracts/proposals.d.ts +36 -36
  5. package/dist/_dts/api/src/billing.d.ts +2 -0
  6. package/dist/_dts/api/src/commercePortalEndpoints.d.ts +5 -1
  7. package/dist/_dts/api/src/endpoints.d.ts +8 -0
  8. package/dist/_dts/api/src/index.d.ts +1 -1
  9. package/dist/_dts/api/src/siteOperations.d.ts +65 -1
  10. package/dist/_dts/billing/src/site-arrangements.d.ts +151 -0
  11. package/dist/_dts/billing/src/subscriptions/store.d.ts +2 -0
  12. package/dist/_dts/block-form/src/widgets/RepeaterField/utils/resolveThumbnail.d.ts +2 -1
  13. package/dist/_dts/blocks/src/PageRenderer.d.ts +6 -0
  14. package/dist/_dts/blocks/src/system/runtime/components/booking/DatePicker.d.ts +6 -2
  15. package/dist/_dts/blocks/src/system/runtime/components/booking/SuccessMessage.d.ts +3 -1
  16. package/dist/_dts/blocks/src/system/runtime/components/booking/TimeSlotSelector.d.ts +10 -4
  17. package/dist/_dts/blocks/src/system/runtime/hooks/useHeadlessBookingFlow.state.d.ts +2 -2
  18. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.headless.state.d.ts +11 -0
  19. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/StepIndicator.d.ts +3 -1
  20. package/dist/_dts/blocks/src/system/runtime/shared/components/FeedbackMessage.d.ts +2 -1
  21. package/dist/_dts/blocks/src/system/runtime/{nodes/event-registration → shared/components}/SelectableOptionCard.d.ts +11 -2
  22. package/dist/_dts/blocks/src/system/runtime/shared/components/StepIndicator.d.ts +16 -5
  23. package/dist/_dts/blocks/src/system/runtime/shared/components/index.d.ts +2 -0
  24. package/dist/_dts/blocks/src/system/runtime/shared/index.d.ts +2 -2
  25. package/dist/_dts/blocks/src/utils/date-formatting.d.ts +17 -1
  26. package/dist/_dts/db/src/generated/supabase/database.types.d.ts +274 -30
  27. package/dist/_dts/sdk/src/__mocks__/next-cache.d.ts +1 -1
  28. package/dist/_dts/sdk/src/cli/commands/push.d.ts +13 -0
  29. package/dist/_dts/sdk/src/cli/merge-remote/entryMergeReport.d.ts +6 -18
  30. package/dist/_dts/sdk/src/cli/merge-remote/entrySnapshots.d.ts +2 -4
  31. package/dist/_dts/sdk/src/cli/merge-remote/pageMergeReport.d.ts +6 -18
  32. package/dist/_dts/sdk/src/cli/merge-remote/pageSnapshots.d.ts +2 -4
  33. package/dist/_dts/sdk/src/cli/merge-remote/sharedBaseSnapshots.d.ts +32 -0
  34. package/dist/_dts/sdk/src/cli/merge-remote/sharedMergePlan.d.ts +27 -0
  35. package/dist/_dts/sdk/src/cli/merge-remote/sharedMergeReport.d.ts +63 -0
  36. package/dist/_dts/sdk/src/client/index.d.ts +6 -0
  37. package/dist/_dts/sdk/src/data/prefetchBlockData.d.ts +6 -1
  38. package/dist/_dts/sdk/src/next/types.d.ts +19 -0
  39. package/dist/_dts/sdk/src/prebuild/loader.d.ts +8 -1
  40. package/dist/_dts/sdk/src/rendering/blocks-page-renderer.d.ts +2 -0
  41. package/dist/_dts/sdk/src/rendering/components/pageShared.d.ts +4 -0
  42. package/dist/_dts/sdk/src/rendering/helpers/loadContent.d.ts +6 -0
  43. package/dist/_dts/sdk/src/rendering/helpers/loadPage.d.ts +8 -0
  44. package/dist/_dts/sdk/src/rendering/index.d.ts +7 -7
  45. package/dist/_dts/sdk/src/rendering/overrides.d.ts +2 -0
  46. package/dist/_dts/sdk/src/routing/resolveRoute.d.ts +18 -0
  47. package/dist/_dts/sdk/src/test/apiClient.d.ts +17 -0
  48. package/dist/_dts/sdk/src/test/bunDom.setup.d.ts +1 -0
  49. package/dist/_dts/sdk/src/test/env.d.ts +4 -0
  50. package/dist/_dts/sdk/src/version.d.ts +1 -1
  51. package/dist/_dts/site-commands/src/commands.d.ts +3 -3
  52. package/dist/_dts/theme-core/src/generated/containerResponsiveThemeCss.d.ts +1 -1
  53. package/dist/_dts/theme-core/src/interactive/generateBaseCSS.d.ts +6 -0
  54. package/dist/_dts/theme-core/src/status/contextualColors.d.ts +6 -0
  55. package/dist/_dts/theme-core/src/status/index.d.ts +1 -0
  56. package/dist/{chunk-H24OU7WG.mjs → chunk-4HXF2QLH.mjs} +2 -2
  57. package/dist/{chunk-QPXE2OUZ.mjs → chunk-EMJIT3ZJ.mjs} +1 -1
  58. package/dist/{chunk-PKDPQHB5.mjs → chunk-PM7HGDHM.mjs} +2 -2
  59. package/dist/{chunk-DBRI3PQF.mjs → chunk-XO34WBBP.mjs} +1383 -1143
  60. package/dist/{chunk-6WDBXCPX.mjs → chunk-YGTTEVUM.mjs} +7 -7
  61. package/dist/{chunk-V2BYFSPW.mjs → chunk-YWTCCOSF.mjs} +8 -0
  62. package/dist/cli/index.mjs +1010 -921
  63. package/dist/client/{accordion-Q2BDNL53.mjs → accordion-QSUEYL4L.mjs} +2 -2
  64. package/dist/client/{bookingForm-ZMP4P7EK.mjs → bookingForm-QYGAHPDP.mjs} +364 -300
  65. package/dist/client/bookings.mjs +697 -411
  66. package/dist/client/{carousel-LW3UXPWO.mjs → carousel-SM2LEWAU.mjs} +3 -3
  67. package/dist/client/{cart-Z6D3KS6K.mjs → cart-3N3SFKNQ.mjs} +7 -7
  68. package/dist/client/{checkout-YMT2QJQM.mjs → checkout-YFAYPKPZ.mjs} +7 -7
  69. package/dist/client/{chunk-XNTHVZ25.mjs → chunk-5DLGREUB.mjs} +1 -1
  70. package/dist/client/{chunk-SK2BMD22.mjs → chunk-CLZ7NBSP.mjs} +147 -75
  71. package/dist/client/{chunk-R4XK3CKR.mjs → chunk-CYJ3MUFP.mjs} +6 -5
  72. package/dist/client/{chunk-JNE6UI6U.mjs → chunk-H3H3ODO7.mjs} +1 -1
  73. package/dist/client/{chunk-IEOECM7U.mjs → chunk-HPEQ4YWW.mjs} +28 -73
  74. package/dist/client/{chunk-PCHACQEB.mjs → chunk-IIUIKJ4K.mjs} +15 -7
  75. package/dist/client/{chunk-KDP7ZRZV.mjs → chunk-IOAHWAQG.mjs} +2 -0
  76. package/dist/client/{chunk-26ZBRXFR.mjs → chunk-JTKBF3W2.mjs} +3 -3
  77. package/dist/client/{chunk-OLAOAZEO.mjs → chunk-K7KTSACR.mjs} +1 -1
  78. package/dist/client/{chunk-ET2MDQQT.mjs → chunk-R32M5HFS.mjs} +6 -6
  79. package/dist/client/{chunk-DRRQ7QSL.mjs → chunk-WEVT46PX.mjs} +3 -3
  80. package/dist/client/{chunk-HBQEAOG4.mjs → chunk-ZU65LTI3.mjs} +1 -1
  81. package/dist/client/client.mjs +1875 -1581
  82. package/dist/client/{courseRegistration-DGKCMC77.mjs → courseRegistration-LYBE7VVK.mjs} +7 -7
  83. package/dist/client/{eventCalendar-74Z2NNFM.mjs → eventCalendar-FMTB75X6.mjs} +9 -9
  84. package/dist/client/{eventCombined-GK2ODOX2.mjs → eventCombined-E4LUCJXT.mjs} +9 -9
  85. package/dist/client/{eventDetails-MONAGT3N.mjs → eventDetails-GELSRR4Z.mjs} +9 -9
  86. package/dist/client/{eventListing-SKGAO6PS.mjs → eventListing-TB623B6R.mjs} +9 -9
  87. package/dist/client/{eventRegistration-6KISGXRD.mjs → eventRegistration-NRIKHXTI.mjs} +9 -9
  88. package/dist/client/{form-FXPRTXHI.mjs → form-Y4U4IAXE.mjs} +3 -3
  89. package/dist/client/{headerSection-7NAN5WNB.mjs → headerSection-QSOVV5P7.mjs} +3 -3
  90. package/dist/client/hooks.mjs +115 -21
  91. package/dist/client/{locationMap-UERN74U4.mjs → locationMap-QYCAHH7H.mjs} +3 -3
  92. package/dist/client/{newsletterForm-SGWXMJ7U.mjs → newsletterForm-NWHY5TBY.mjs} +3 -3
  93. package/dist/client/{productDetail-HN3HWZQZ.mjs → productDetail-FYDMU2CE.mjs} +7 -7
  94. package/dist/client/{productList-YT22Z5UR.mjs → productList-D76CGACQ.mjs} +7 -7
  95. package/dist/client/rendering/client.mjs +1209 -975
  96. package/dist/client/rendering/islands.mjs +19 -19
  97. package/dist/client/rendering.mjs +1952 -1638
  98. package/dist/client/{shop-TKEDNWUS.mjs → shop-SOUACT5N.mjs} +7 -7
  99. package/dist/preview-next/before-render.mjs +8 -0
  100. package/dist/preview-next/client/runtime.mjs +5 -5
  101. package/dist/preview-next/middleware.mjs +8 -0
  102. package/dist/{sdk-runtime-LWNYCQF2.mjs → sdk-runtime-XPVE3LBA.mjs} +6 -6
  103. package/dist/server/components.mjs +917 -765
  104. package/dist/server/config-validation.mjs +100 -19
  105. package/dist/server/config.mjs +100 -19
  106. package/dist/server/data.mjs +115 -21
  107. package/dist/server/index.mjs +59 -25
  108. package/dist/server/next.mjs +1017 -816
  109. package/dist/server/page-converter.mjs +92 -19
  110. package/dist/server/prebuild-loader.mjs +42 -23
  111. package/dist/server/prebuild.mjs +1 -1
  112. package/dist/server/rendering/server.mjs +932 -767
  113. package/dist/server/rendering.mjs +968 -776
  114. package/dist/server/routing.mjs +162 -36
  115. package/dist/server/server.mjs +156 -32
  116. package/dist/server/theme-bridge.mjs +597 -505
  117. package/dist/server/theme.mjs +5 -4
  118. package/dist/styles/index.css +499 -490
  119. package/package.json +6 -4
  120. package/dist/SdkPreviewModeRuntime-OV5PNJBB.mjs +0 -8
@@ -4,14 +4,14 @@ import 'react/jsx-runtime';
4
4
  import { createJiti } from 'jiti';
5
5
  import * as fs11 from 'fs';
6
6
  import { existsSync, readFileSync } from 'fs';
7
- import * as path20 from 'path';
7
+ import * as path21 from 'path';
8
8
  import { dirname, resolve, isAbsolute } from 'path';
9
9
  import { fileURLToPath } from 'url';
10
10
  import { config } from 'dotenv';
11
11
  import { Command } from 'commander';
12
12
  import 'react';
13
13
  import * as fs2 from 'fs/promises';
14
- import { unlink, writeFile } from 'fs/promises';
14
+ import { writeFile, unlink } from 'fs/promises';
15
15
  import * as readline from 'readline';
16
16
  import prompts from 'prompts';
17
17
  import * as crypto2 from 'crypto';
@@ -5337,6 +5337,12 @@ var init_resolver = __esm({
5337
5337
  }
5338
5338
  });
5339
5339
 
5340
+ // ../theme-core/src/interactive/generateBaseCSS.ts
5341
+ var init_generateBaseCSS = __esm({
5342
+ "../theme-core/src/interactive/generateBaseCSS.ts"() {
5343
+ }
5344
+ });
5345
+
5340
5346
  // ../theme-core/src/buttons/effects/presets/background.ts
5341
5347
  var init_background = __esm({
5342
5348
  "../theme-core/src/buttons/effects/presets/background.ts"() {
@@ -5452,6 +5458,7 @@ var init_generateButtonCss = __esm({
5452
5458
  init_types4();
5453
5459
  init_classNames();
5454
5460
  init_resolver();
5461
+ init_generateBaseCSS();
5455
5462
  init_generateEffectsCSS();
5456
5463
  init_constants();
5457
5464
  init_generateDefaultButtonSystem();
@@ -5987,15 +5994,16 @@ var init_joy_stamp = __esm({
5987
5994
  // 700, matching the mockup's chunky button labels.
5988
5995
  typography: "heading",
5989
5996
  fontWeight: 700,
5997
+ fontSize: "text-lg",
5990
5998
  borderWidth: 2,
5991
5999
  hoverTransform: "none",
5992
6000
  hoverColor: "none"
5993
6001
  },
5994
6002
  sizes: {
5995
- sm: { padding: "0.625rem 1.25rem", fontSize: "text-sm" },
5996
- md: { padding: "0.875rem 1.75rem", fontSize: "text-base" },
5997
- lg: { padding: "1.125rem 2.25rem", fontSize: "text-lg" },
5998
- xl: { padding: "1.25rem 2.75rem", fontSize: "text-xl" }
6003
+ sm: { padding: "0.625rem 1.25rem", fontSize: "text-base" },
6004
+ md: { padding: "0.875rem 1.75rem", fontSize: "text-lg" },
6005
+ lg: { padding: "1.125rem 2.25rem", fontSize: "text-xl" },
6006
+ xl: { padding: "1.25rem 2.75rem", fontSize: "text-2xl" }
5999
6007
  },
6000
6008
  variants: [
6001
6009
  {
@@ -6576,12 +6584,19 @@ var init_generateDefaultCardSystem = __esm({
6576
6584
  }
6577
6585
  });
6578
6586
 
6587
+ // ../theme-core/src/status/contextualColors.ts
6588
+ var init_contextualColors = __esm({
6589
+ "../theme-core/src/status/contextualColors.ts"() {
6590
+ }
6591
+ });
6592
+
6579
6593
  // ../theme-core/src/cards/generateCardCss.ts
6580
6594
  var init_generateCardCss = __esm({
6581
6595
  "../theme-core/src/cards/generateCardCss.ts"() {
6582
6596
  init_resolver();
6583
6597
  init_constants2();
6584
6598
  init_generateDefaultCardSystem();
6599
+ init_contextualColors();
6585
6600
  }
6586
6601
  });
6587
6602
 
@@ -13477,11 +13492,11 @@ function bind(from, options) {
13477
13492
  }
13478
13493
  });
13479
13494
  }
13480
- function when(path32, options) {
13495
+ function when(path33, options) {
13481
13496
  return (node) => ({
13482
13497
  ...node,
13483
13498
  $when: {
13484
- when: { from: path32 },
13499
+ when: { from: path33 },
13485
13500
  ...options?.equals !== void 0 ? { equals: options.equals } : {},
13486
13501
  ...options?.not ? { not: true } : {},
13487
13502
  ...options?.authoringPresence ? { authoringPresence: options.authoringPresence } : {}
@@ -13589,7 +13604,7 @@ var init_builder2 = __esm({
13589
13604
  });
13590
13605
 
13591
13606
  // ../blocks/src/system/node/fragments/backgroundLayer.ts
13592
- function backgroundLayer(path32, options = {}) {
13607
+ function backgroundLayer(path33, options = {}) {
13593
13608
  const {
13594
13609
  styleClassName = "background-style rb-absolute rb-inset-0 rb-z-neg-10 rb-h-full rb-w-full rb-pointer-events-none",
13595
13610
  imageClassName,
@@ -13603,7 +13618,7 @@ function backgroundLayer(path32, options = {}) {
13603
13618
  className: styleClassName,
13604
13619
  style: {
13605
13620
  $bind: {
13606
- from: path32,
13621
+ from: path33,
13607
13622
  transforms: [
13608
13623
  {
13609
13624
  id: "background.resolveStyle",
@@ -13613,20 +13628,20 @@ function backgroundLayer(path32, options = {}) {
13613
13628
  }
13614
13629
  }
13615
13630
  });
13616
- const imageLayer = createBackgroundImageNode(path32, imageClassName, {
13631
+ const imageLayer = createBackgroundImageNode(path33, imageClassName, {
13617
13632
  loading: imageLoading,
13618
13633
  fetchPriority: imageFetchPriority
13619
13634
  });
13620
- const overlayLayer = createBackgroundOverlayNode(path32, overlayClassName);
13635
+ const overlayLayer = createBackgroundOverlayNode(path33, overlayClassName);
13621
13636
  return omitImageLayer ? [styleLayer, overlayLayer] : [styleLayer, imageLayer, overlayLayer];
13622
13637
  }
13623
- function createBackgroundImageNode(path32, baseClassName = "rb-absolute rb-z-neg-10", options = {}) {
13624
- const imagePath = `${path32}.image`;
13638
+ function createBackgroundImageNode(path33, baseClassName = "rb-absolute rb-z-neg-10", options = {}) {
13639
+ const imagePath = `${path33}.image`;
13625
13640
  return media(
13626
13641
  {
13627
13642
  className: {
13628
13643
  $bind: {
13629
- from: path32,
13644
+ from: path33,
13630
13645
  transforms: [
13631
13646
  {
13632
13647
  id: "background.resolveImageClassName",
@@ -13637,7 +13652,7 @@ function createBackgroundImageNode(path32, baseClassName = "rb-absolute rb-z-neg
13637
13652
  },
13638
13653
  style: {
13639
13654
  $bind: {
13640
- from: path32,
13655
+ from: path33,
13641
13656
  transforms: [{ id: "background.resolveImageStyle" }]
13642
13657
  }
13643
13658
  },
@@ -13649,8 +13664,8 @@ function createBackgroundImageNode(path32, baseClassName = "rb-absolute rb-z-neg
13649
13664
  bind(imagePath)
13650
13665
  );
13651
13666
  }
13652
- function createBackgroundOverlayNode(path32, className = "background-overlay rb-absolute rb-inset-0 rb-z-neg-10 rb-h-full rb-w-full rb-pointer-events-none") {
13653
- const overlayPath = `${path32}.overlay`;
13667
+ function createBackgroundOverlayNode(path33, className = "background-overlay rb-absolute rb-inset-0 rb-z-neg-10 rb-h-full rb-w-full rb-pointer-events-none") {
13668
+ const overlayPath = `${path33}.overlay`;
13654
13669
  return el("div", {
13655
13670
  className,
13656
13671
  style: {
@@ -14490,10 +14505,10 @@ var init_sectionForegroundStyles = __esm({
14490
14505
  });
14491
14506
 
14492
14507
  // ../blocks/src/system/transforms/registry/boxStyles.ts
14493
- function readPath(source, path32) {
14494
- if (!source || !path32) return void 0;
14495
- if (!path32.includes(".")) return source[path32];
14496
- return path32.split(".").reduce((acc, segment) => {
14508
+ function readPath(source, path33) {
14509
+ if (!source || !path33) return void 0;
14510
+ if (!path33.includes(".")) return source[path33];
14511
+ return path33.split(".").reduce((acc, segment) => {
14497
14512
  if (acc && typeof acc === "object" && segment in acc) {
14498
14513
  return acc[segment];
14499
14514
  }
@@ -15485,27 +15500,27 @@ function scopePropValue(value, scope) {
15485
15500
  }
15486
15501
  return value;
15487
15502
  }
15488
- function scopeContentPath(path32, scope) {
15503
+ function scopeContentPath(path33, scope) {
15489
15504
  if (!scope || scope.length === 0) {
15490
- return path32;
15505
+ return path33;
15491
15506
  }
15492
- if (path32 === "content") {
15507
+ if (path33 === "content") {
15493
15508
  return `content.${scope}`;
15494
15509
  }
15495
- if (path32.startsWith("content.")) {
15496
- const remainder = path32.slice("content.".length);
15510
+ if (path33.startsWith("content.")) {
15511
+ const remainder = path33.slice("content.".length);
15497
15512
  return remainder.length > 0 ? `content.${scope}.${remainder}` : `content.${scope}`;
15498
15513
  }
15499
- if (path32.startsWith("content[")) {
15500
- return path32.replace(/^content/, `content.${scope}`);
15514
+ if (path33.startsWith("content[")) {
15515
+ return path33.replace(/^content/, `content.${scope}`);
15501
15516
  }
15502
- if (path32.startsWith("$root.")) {
15503
- return path32;
15517
+ if (path33.startsWith("$root.")) {
15518
+ return path33;
15504
15519
  }
15505
- if (path32.includes(".")) {
15506
- return path32;
15520
+ if (path33.includes(".")) {
15521
+ return path33;
15507
15522
  }
15508
- return `content.${scope}.${path32}`;
15523
+ return `content.${scope}.${path33}`;
15509
15524
  }
15510
15525
  var FRAGMENT_ID_PATTERN, FIELD_ID_PATTERN, dataLoaderSchema, fragmentDataSchema, fragmentConfigSchema, FragmentConfigError;
15511
15526
  var init_types14 = __esm({
@@ -18432,8 +18447,8 @@ function decodeSuccess(value) {
18432
18447
  function decodeFailure(issues) {
18433
18448
  return { ok: false, issues };
18434
18449
  }
18435
- function zodIssuePath(path32) {
18436
- return path32.flatMap((segment) => {
18450
+ function zodIssuePath(path33) {
18451
+ return path33.flatMap((segment) => {
18437
18452
  if (typeof segment === "string" || typeof segment === "number") {
18438
18453
  return [segment];
18439
18454
  }
@@ -27719,6 +27734,14 @@ var ENDPOINT_DEFINITIONS = {
27719
27734
  responseKind: "json",
27720
27735
  errors: []
27721
27736
  },
27737
+ adminResolveSiteBillingManualReview: {
27738
+ path: "/admin/sites/{siteId}/billing/manual-reviews/{reviewId}/resolve",
27739
+ method: "POST",
27740
+ tags: ["admin", "site-{siteId}", "billing"],
27741
+ auth: "admin",
27742
+ responseKind: "json",
27743
+ errors: []
27744
+ },
27722
27745
  // Admin GSC/SEO endpoints
27723
27746
  adminGscVerifyStart: {
27724
27747
  path: "/admin/seo/gsc/properties/verify/start",
@@ -29396,8 +29419,8 @@ function strictValidationContext(options = {}) {
29396
29419
  allowNull: options.allowNull ?? false
29397
29420
  };
29398
29421
  }
29399
- function formatFieldPath(path32) {
29400
- return path32.map((segment) => String(segment)).join(".");
29422
+ function formatFieldPath(path33) {
29423
+ return path33.map((segment) => String(segment)).join(".");
29401
29424
  }
29402
29425
  function parseFieldPathKey(key) {
29403
29426
  if (!key) return [];
@@ -29460,7 +29483,7 @@ function pluralize(label, count) {
29460
29483
  if (count === 1) return label;
29461
29484
  return label.endsWith("s") ? label : `${label}s`;
29462
29485
  }
29463
- function deriveFieldValidationPlan(field, path32 = [field.id]) {
29486
+ function deriveFieldValidationPlan(field, path33 = [field.id]) {
29464
29487
  const required = Boolean(field.required);
29465
29488
  switch (field.type) {
29466
29489
  case "text": {
@@ -29471,7 +29494,7 @@ function deriveFieldValidationPlan(field, path32 = [field.id]) {
29471
29494
  });
29472
29495
  if (typeof field.ui?.min === "number") constraints2.push({ kind: "numberMin", minimum: field.ui.min });
29473
29496
  if (typeof field.ui?.max === "number") constraints2.push({ kind: "numberMax", maximum: field.ui.max });
29474
- return makePlan("number", "number", field, path32, required, constraints2);
29497
+ return makePlan("number", "number", field, path33, required, constraints2);
29475
29498
  }
29476
29499
  const constraints = commonConstraints(required, {
29477
29500
  kind: field.ui?.widget === "iconPicker" ? "blockIconValue" : "textType"
@@ -29480,7 +29503,7 @@ function deriveFieldValidationPlan(field, path32 = [field.id]) {
29480
29503
  if (inputType === "tel") constraints.push({ kind: "phoneFormat" });
29481
29504
  if (field.ui?.pattern) constraints.push({ kind: "patternFormat", pattern: field.ui.pattern });
29482
29505
  if (typeof field.maxLength === "number") constraints.push({ kind: "maxLength", maximum: field.maxLength });
29483
- return makePlan("string", "string", field, path32, required, constraints);
29506
+ return makePlan("string", "string", field, path33, required, constraints);
29484
29507
  }
29485
29508
  case "number": {
29486
29509
  const constraints = commonConstraints(required, {
@@ -29488,34 +29511,34 @@ function deriveFieldValidationPlan(field, path32 = [field.id]) {
29488
29511
  });
29489
29512
  if (typeof field.min === "number") constraints.push({ kind: "numberMin", minimum: field.min });
29490
29513
  if (typeof field.max === "number") constraints.push({ kind: "numberMax", maximum: field.max });
29491
- return makePlan("number", "number", field, path32, required, constraints);
29514
+ return makePlan("number", "number", field, path33, required, constraints);
29492
29515
  }
29493
29516
  case "slug": {
29494
29517
  const constraints = commonConstraints(required, { kind: "textType" }, { kind: "slugFormat" });
29495
29518
  if (typeof field.maxLength === "number") constraints.push({ kind: "maxLength", maximum: field.maxLength });
29496
- return makePlan("string", "string", field, path32, required, constraints);
29519
+ return makePlan("string", "string", field, path33, required, constraints);
29497
29520
  }
29498
29521
  case "url":
29499
29522
  return makePlan(
29500
29523
  "string",
29501
29524
  "string",
29502
29525
  field,
29503
- path32,
29526
+ path33,
29504
29527
  required,
29505
29528
  commonConstraints(required, { kind: "textType" }, { kind: "urlFormat", allowRelative: Boolean(field.allowRelative) })
29506
29529
  );
29507
29530
  case "reference":
29508
- return makePlan("string", "string", field, path32, required, commonConstraints(required, { kind: "referenceText" }));
29531
+ return makePlan("string", "string", field, path33, required, commonConstraints(required, { kind: "referenceText" }));
29509
29532
  case "date":
29510
- return makePlan("string", "string", field, path32, required, commonConstraints(required, { kind: "textType" }, { kind: "dateFormat" }));
29533
+ return makePlan("string", "string", field, path33, required, commonConstraints(required, { kind: "textType" }, { kind: "dateFormat" }));
29511
29534
  case "time":
29512
- return makePlan("string", "string", field, path32, required, commonConstraints(required, { kind: "textType" }, { kind: "timeFormat" }));
29535
+ return makePlan("string", "string", field, path33, required, commonConstraints(required, { kind: "textType" }, { kind: "timeFormat" }));
29513
29536
  case "datetime":
29514
29537
  return makePlan(
29515
29538
  "string",
29516
29539
  "string",
29517
29540
  field,
29518
- path32,
29541
+ path33,
29519
29542
  required,
29520
29543
  commonConstraints(required, { kind: "textType" }, { kind: "datetimeFormat" })
29521
29544
  );
@@ -29524,7 +29547,7 @@ function deriveFieldValidationPlan(field, path32 = [field.id]) {
29524
29547
  "select",
29525
29548
  "select",
29526
29549
  field,
29527
- path32,
29550
+ path33,
29528
29551
  required,
29529
29552
  commonConstraints(required, {
29530
29553
  kind: "selectOption",
@@ -29533,53 +29556,53 @@ function deriveFieldValidationPlan(field, path32 = [field.id]) {
29533
29556
  })
29534
29557
  );
29535
29558
  case "richText":
29536
- return makePlan("richText", "object", field, path32, required, commonConstraints(required, { kind: "richTextDoc" }));
29559
+ return makePlan("richText", "object", field, path33, required, commonConstraints(required, { kind: "richTextDoc" }));
29537
29560
  case "inlineText": {
29538
29561
  const constraints = commonConstraints(required, { kind: "inlineText" });
29539
29562
  if (typeof field.maxLength === "number") {
29540
29563
  constraints.push({ kind: "maxPlainTextLength", maximum: field.maxLength });
29541
29564
  }
29542
29565
  return {
29543
- ...makePlan("inlineText", "array", field, path32, required, constraints),
29566
+ ...makePlan("inlineText", "array", field, path33, required, constraints),
29544
29567
  ...field.plainTextField ? { plainTextFallbackPath: parseFieldPathKey(field.plainTextField) } : {}
29545
29568
  };
29546
29569
  }
29547
29570
  case "media":
29548
29571
  case "file":
29549
29572
  return {
29550
- ...makePlan("media", "object", field, path32, required, commonConstraints(required, { kind: "mediaObject" })),
29573
+ ...makePlan("media", "object", field, path33, required, commonConstraints(required, { kind: "mediaObject" })),
29551
29574
  legacyStringType: legacyStringMediaTypeForField(field)
29552
29575
  };
29553
29576
  case "link":
29554
- return makePlan("link", "object", field, path32, required, commonConstraints(required, { kind: "linkObject" }));
29577
+ return makePlan("link", "object", field, path33, required, commonConstraints(required, { kind: "linkObject" }));
29555
29578
  case "boolean":
29556
- return makePlan("boolean", "boolean", field, path32, required, requiredConstraints(required));
29579
+ return makePlan("boolean", "boolean", field, path33, required, requiredConstraints(required));
29557
29580
  case "repeater":
29558
29581
  return {
29559
- ...makePlan("repeater", "array", field, path32, required, commonConstraints(required, { kind: "arrayType" })),
29582
+ ...makePlan("repeater", "array", field, path33, required, commonConstraints(required, { kind: "arrayType" })),
29560
29583
  ...field.polymorphic && field.itemTypes ? {
29561
- repeatedItemVariants: deriveRepeatedItemVariants(field, [...path32, 0])
29584
+ repeatedItemVariants: deriveRepeatedItemVariants(field, [...path33, 0])
29562
29585
  } : {
29563
- repeatedItemPlan: deriveNestedFieldPlans(getRepeaterFields(field), [...path32, 0])
29586
+ repeatedItemPlan: deriveNestedFieldPlans(getRepeaterFields(field), [...path33, 0])
29564
29587
  },
29565
29588
  constraints: withRepeaterItemConstraints(field, commonConstraints(required, { kind: "arrayType" }))
29566
29589
  };
29567
29590
  case "group":
29568
29591
  case "modal":
29569
29592
  return {
29570
- ...makePlan("group", "object", field, path32, required, requiredConstraints(required)),
29571
- children: deriveNestedFieldPlans(field.schema?.fields ?? [], path32),
29593
+ ...makePlan("group", "object", field, path33, required, requiredConstraints(required)),
29594
+ children: deriveNestedFieldPlans(field.schema?.fields ?? [], path33),
29572
29595
  allowNullChildren: field.type === "group" && field.ui?.widget === "locationPicker"
29573
29596
  };
29574
29597
  case "tabGroup":
29575
29598
  return {
29576
- ...makePlan("group", "object", field, path32, required, requiredConstraints(required)),
29577
- children: field.tabs.flatMap((tab) => deriveNestedFieldPlans(tab.fields, path32))
29599
+ ...makePlan("group", "object", field, path33, required, requiredConstraints(required)),
29600
+ children: field.tabs.flatMap((tab) => deriveNestedFieldPlans(tab.fields, path33))
29578
29601
  };
29579
29602
  case "presetOrCustom":
29580
29603
  case "contentTypeSelect":
29581
29604
  case "entryPicker":
29582
- return makePlan("passthrough", "unknown", field, path32, false, []);
29605
+ return makePlan("passthrough", "unknown", field, path33, false, []);
29583
29606
  default:
29584
29607
  return assertNever2(field);
29585
29608
  }
@@ -29593,14 +29616,14 @@ function commonConstraints(required, ...specific) {
29593
29616
  function requiredConstraints(required) {
29594
29617
  return required ? [{ kind: "required" }] : [];
29595
29618
  }
29596
- function makePlan(kind, valueKind, field, path32, required, constraints) {
29619
+ function makePlan(kind, valueKind, field, path33, required, constraints) {
29597
29620
  return {
29598
29621
  kind,
29599
29622
  valueKind,
29600
29623
  fieldId: field.id,
29601
29624
  label: field.label,
29602
29625
  fieldType: field.type,
29603
- path: path32,
29626
+ path: path33,
29604
29627
  required,
29605
29628
  visibility: fieldVisibility(field),
29606
29629
  constraints
@@ -29776,8 +29799,8 @@ function normalizeInlineTextFallbacks(plans, values, ctx) {
29776
29799
  values[plan.fieldId] = normalizeFieldValue(plan, plainTextToInlineText(fallback), ctx);
29777
29800
  }
29778
29801
  }
29779
- function getAtFieldPath(source, path32) {
29780
- return path32.reduce((current, segment) => {
29802
+ function getAtFieldPath(source, path33) {
29803
+ return path33.reduce((current, segment) => {
29781
29804
  if (!current || typeof current !== "object" || Array.isArray(current)) return void 0;
29782
29805
  return current[String(segment)];
29783
29806
  }, source);
@@ -29968,18 +29991,18 @@ function materializeRepeaterItemPlan(plan, parentPath, index) {
29968
29991
  return rebaseFieldPlanPath(plan, [...parentPath, 0], [...parentPath, index]);
29969
29992
  }
29970
29993
  function rebaseFieldPlanPath(plan, fromPrefix, toPrefix) {
29971
- const path32 = rebaseFieldPath(plan.path, fromPrefix, toPrefix);
29994
+ const path33 = rebaseFieldPath(plan.path, fromPrefix, toPrefix);
29972
29995
  switch (plan.kind) {
29973
29996
  case "group":
29974
29997
  return {
29975
29998
  ...plan,
29976
- path: path32,
29999
+ path: path33,
29977
30000
  children: plan.children.map((childPlan) => rebaseFieldPlanPath(childPlan, fromPrefix, toPrefix))
29978
30001
  };
29979
30002
  case "repeater":
29980
30003
  return {
29981
30004
  ...plan,
29982
- path: path32,
30005
+ path: path33,
29983
30006
  ...plan.repeatedItemVariants ? {
29984
30007
  repeatedItemVariants: plan.repeatedItemVariants.map((variant) => ({
29985
30008
  ...variant,
@@ -30001,7 +30024,7 @@ function rebaseFieldPlanPath(plan, fromPrefix, toPrefix) {
30001
30024
  case "passthrough":
30002
30025
  return {
30003
30026
  ...plan,
30004
- path: path32
30027
+ path: path33
30005
30028
  };
30006
30029
  default:
30007
30030
  return assertNever2(plan);
@@ -30019,14 +30042,14 @@ function validateInlineTextPlan(plan, value) {
30019
30042
  }
30020
30043
  return [];
30021
30044
  }
30022
- function rebaseFieldPath(path32, fromPrefix, toPrefix) {
30023
- if (!startsWithFieldPath(path32, fromPrefix)) {
30024
- throw new Error(`Cannot rebase field path ${formatFieldPath(path32)} from ${formatFieldPath(fromPrefix)}`);
30045
+ function rebaseFieldPath(path33, fromPrefix, toPrefix) {
30046
+ if (!startsWithFieldPath(path33, fromPrefix)) {
30047
+ throw new Error(`Cannot rebase field path ${formatFieldPath(path33)} from ${formatFieldPath(fromPrefix)}`);
30025
30048
  }
30026
- return [...toPrefix, ...path32.slice(fromPrefix.length)];
30049
+ return [...toPrefix, ...path33.slice(fromPrefix.length)];
30027
30050
  }
30028
- function startsWithFieldPath(path32, prefix) {
30029
- return prefix.every((segment, index) => path32[index] === segment);
30051
+ function startsWithFieldPath(path33, prefix) {
30052
+ return prefix.every((segment, index) => path33[index] === segment);
30030
30053
  }
30031
30054
  function issue(plan, kind, extra) {
30032
30055
  return {
@@ -33200,9 +33223,9 @@ function maybeBuildSupabaseTransformUrl(inputUrl, options) {
33200
33223
  const remainder = url.pathname.slice(idx + marker.length);
33201
33224
  const parts = remainder.split("/").filter(Boolean);
33202
33225
  const bucket = parts[0];
33203
- const path32 = parts.slice(1).join("/");
33204
- if (!bucket || !path32) return inputUrl;
33205
- url.pathname = `/storage/v1/render/image/public/${bucket}/${path32}`;
33226
+ const path33 = parts.slice(1).join("/");
33227
+ if (!bucket || !path33) return inputUrl;
33228
+ url.pathname = `/storage/v1/render/image/public/${bucket}/${path33}`;
33206
33229
  url.search = "";
33207
33230
  if (width) url.searchParams.set("width", String(width));
33208
33231
  if (height) url.searchParams.set("height", String(height));
@@ -42262,6 +42285,7 @@ init_resolver();
42262
42285
  init_types11();
42263
42286
  init_expandPalette();
42264
42287
  init_colorConversion();
42288
+ init_generateBaseCSS();
42265
42289
  init_generateEffectsCSS();
42266
42290
 
42267
42291
  // ../theme-core/src/header/generateHeaderCss.ts
@@ -42275,6 +42299,12 @@ init_resolver();
42275
42299
  // ../theme-core/src/layout/generateLayoutCss.ts
42276
42300
  init_breakpoints();
42277
42301
 
42302
+ // ../theme-core/src/status/generateStatusCss.ts
42303
+ init_contextualColors();
42304
+
42305
+ // ../theme-core/src/status/index.ts
42306
+ init_contextualColors();
42307
+
42278
42308
  // ../theme-core/src/runtime/buildThemeRuntime.ts
42279
42309
  init_tokens2();
42280
42310
 
@@ -42350,6 +42380,34 @@ ${root} {
42350
42380
  /* Order summary */
42351
42381
  --er-summary-bg: rgba(var(--tb-primary), 0.1);
42352
42382
  --er-summary-border: rgb(var(--tb-border));
42383
+
42384
+ /* Shared registration-surface mappings (issue 1174).
42385
+ Route the shared --rb-reg-* contract through this block's documented
42386
+ Tier 3 vars so existing --er-* overrides keep working unchanged. */
42387
+ --rb-reg-radius: var(--er-radius);
42388
+ --rb-reg-border: var(--er-border);
42389
+ --rb-reg-border-hover: var(--er-border-hover);
42390
+ --rb-reg-border-selected: var(--er-border-selected);
42391
+ --rb-reg-bg-selected: var(--er-payment-bg-selected);
42392
+ --rb-reg-option-bg: var(--er-control-bg);
42393
+ --rb-reg-option-hover-shadow: 0 8px 18px rgba(var(--tb-shadow, 15 23 42), 0.08);
42394
+ --rb-reg-surface-bg: rgb(var(--tb-surface));
42395
+ --rb-reg-on-surface: var(--er-on-surface);
42396
+ --rb-reg-on-surface-muted: var(--er-on-surface-muted);
42397
+ --rb-reg-on-surface-subtle: var(--er-on-surface-subtle);
42398
+ --rb-reg-on-surface-faint: var(--er-on-surface-faint);
42399
+ --rb-reg-check-bg: var(--er-check-bg);
42400
+ --rb-reg-check-text: var(--er-check-text);
42401
+ --rb-reg-step-active: var(--er-step-active);
42402
+ --rb-reg-step-completed: var(--er-step-completed);
42403
+ --rb-reg-step-inactive: var(--er-step-inactive);
42404
+ --rb-reg-step-text: var(--er-step-text);
42405
+ --rb-reg-step-text-active: var(--er-step-text-active);
42406
+ --rb-reg-step-connector: var(--er-step-connector);
42407
+ --rb-reg-summary-bg: var(--er-surface-muted);
42408
+ --rb-reg-summary-border: var(--er-border);
42409
+ --rb-reg-focus-ring: var(--er-focus-ring);
42410
+ --rb-reg-shell-line: var(--er-shell-line);
42353
42411
  }
42354
42412
  `;
42355
42413
  }
@@ -42482,25 +42540,40 @@ ${root} {
42482
42540
  --ab-info-bg: rgba(var(--tb-info), 0.1);
42483
42541
  --ab-info-text: rgb(var(--tb-info));
42484
42542
 
42485
- /* Loading/muted states */
42543
+ /* Muted summary state */
42486
42544
  --ab-muted-bg: rgba(var(--tb-text), 0.05);
42487
- --ab-muted-text: rgba(var(--tb-text), 0.6);
42488
- --ab-spinner-color: rgb(var(--tb-primary));
42489
42545
 
42490
- /* Form elements */
42491
- --ab-input-border: rgb(var(--tb-border));
42546
+ /* Focus ring used by shared registration-surface controls */
42492
42547
  --ab-input-focus-ring: rgba(var(--tb-primary), 0.3);
42493
42548
 
42494
- /* Buttons */
42495
- --ab-btn-primary-bg: rgb(var(--tb-primary));
42496
- --ab-btn-primary-text: rgb(var(--tb-background));
42497
- --ab-btn-primary-hover: rgba(var(--tb-primary), 0.9);
42498
- --ab-btn-secondary-border: rgb(var(--tb-border));
42499
- --ab-btn-secondary-hover: rgba(var(--tb-text), 0.05);
42500
-
42501
- /* Text opacity levels */
42502
- --ab-text-muted-opacity: 0.6;
42503
- --ab-text-faint-opacity: 0.4;
42549
+ /* Shared registration-surface mappings (issue 1174).
42550
+ Route the shared --rb-reg-* contract through this block's Tier 3 vars
42551
+ (palette tokens where no --ab-* var exists) so --ab-* overrides keep
42552
+ working as the block adopts the shared classes. */
42553
+ --rb-reg-radius: var(--ab-card-radius, var(--rb-block-radius));
42554
+ --rb-reg-border: var(--ab-card-border);
42555
+ --rb-reg-border-hover: var(--ab-card-border-hover);
42556
+ --rb-reg-border-selected: var(--ab-card-border-selected);
42557
+ --rb-reg-bg-selected: var(--ab-card-bg-selected);
42558
+ --rb-reg-option-bg: transparent;
42559
+ --rb-reg-option-hover-shadow: 0 8px 18px rgba(var(--tb-shadow, 15 23 42), 0.08);
42560
+ --rb-reg-surface-bg: rgb(var(--tb-surface));
42561
+ --rb-reg-on-surface: rgb(var(--tb-onSurface, var(--tb-text)));
42562
+ --rb-reg-on-surface-muted: rgba(var(--tb-onSurface, var(--tb-text)), 0.7);
42563
+ --rb-reg-on-surface-subtle: rgba(var(--tb-onSurface, var(--tb-text)), 0.6);
42564
+ --rb-reg-on-surface-faint: rgba(var(--tb-onSurface, var(--tb-text)), 0.5);
42565
+ --rb-reg-check-bg: var(--ab-check-bg);
42566
+ --rb-reg-check-text: var(--ab-check-text);
42567
+ --rb-reg-step-active: rgb(var(--tb-primary));
42568
+ --rb-reg-step-completed: rgb(var(--tb-success));
42569
+ --rb-reg-step-inactive: rgb(var(--tb-mutedText));
42570
+ --rb-reg-step-text: rgb(255 255 255);
42571
+ --rb-reg-step-text-active: rgb(var(--tb-primaryText, 255 255 255));
42572
+ --rb-reg-step-connector: rgba(var(--tb-border), 0.5);
42573
+ --rb-reg-summary-bg: var(--ab-muted-bg);
42574
+ --rb-reg-summary-border: var(--ab-card-border);
42575
+ --rb-reg-focus-ring: var(--ab-input-focus-ring);
42576
+ --rb-reg-shell-line: rgba(var(--tb-mutedText, 100 116 139), 0.22);
42504
42577
  }
42505
42578
  `;
42506
42579
  }
@@ -42791,6 +42864,35 @@ ${root} {
42791
42864
  /* Summary */
42792
42865
  --cr-summary-bg: rgba(var(--tb-primary), 0.1);
42793
42866
  --cr-summary-border: rgb(var(--tb-border));
42867
+
42868
+ /* Shared registration-surface mappings (issue 1174).
42869
+ Route the shared --rb-reg-* contract through this block's Tier 3 vars
42870
+ (palette tokens where no --cr-* var exists) so existing --cr-* overrides
42871
+ keep working unchanged. */
42872
+ --rb-reg-radius: var(--rb-block-radius);
42873
+ --rb-reg-border: var(--cr-border);
42874
+ --rb-reg-border-hover: var(--cr-border-hover);
42875
+ --rb-reg-border-selected: var(--cr-border-selected);
42876
+ --rb-reg-bg-selected: var(--cr-payment-bg-selected);
42877
+ --rb-reg-option-bg: rgb(var(--tb-background));
42878
+ --rb-reg-option-hover-shadow: 0 8px 18px rgba(var(--tb-shadow, 15 23 42), 0.08);
42879
+ --rb-reg-surface-bg: rgb(var(--tb-surface));
42880
+ --rb-reg-on-surface: var(--cr-on-surface);
42881
+ --rb-reg-on-surface-muted: rgba(var(--tb-onSurface, var(--tb-text)), 0.7);
42882
+ --rb-reg-on-surface-subtle: rgba(var(--tb-onSurface, var(--tb-text)), 0.6);
42883
+ --rb-reg-on-surface-faint: rgba(var(--tb-onSurface, var(--tb-text)), 0.5);
42884
+ --rb-reg-check-bg: var(--cr-check-bg);
42885
+ --rb-reg-check-text: var(--cr-check-text);
42886
+ --rb-reg-step-active: var(--cr-step-active);
42887
+ --rb-reg-step-completed: var(--cr-step-completed);
42888
+ --rb-reg-step-inactive: var(--cr-step-inactive);
42889
+ --rb-reg-step-text: var(--cr-step-text);
42890
+ --rb-reg-step-text-active: var(--cr-step-text-active);
42891
+ --rb-reg-step-connector: var(--cr-step-connector);
42892
+ --rb-reg-summary-bg: var(--cr-summary-bg);
42893
+ --rb-reg-summary-border: var(--cr-summary-border);
42894
+ --rb-reg-focus-ring: var(--cr-focus-ring);
42895
+ --rb-reg-shell-line: rgba(var(--tb-mutedText, 100 116 139), 0.22);
42794
42896
  }
42795
42897
  `;
42796
42898
  }
@@ -44690,8 +44792,8 @@ var TEMPLATE_BINDING_META_PATHS = [
44690
44792
  "createdAt",
44691
44793
  "updatedAt"
44692
44794
  ];
44693
- function describeInvalidTemplateBindingMetaPath(path32) {
44694
- return `Meta path "${path32}" is not valid. Allowed: ${TEMPLATE_BINDING_META_PATHS.join(", ")}`;
44795
+ function describeInvalidTemplateBindingMetaPath(path33) {
44796
+ return `Meta path "${path33}" is not valid. Allowed: ${TEMPLATE_BINDING_META_PATHS.join(", ")}`;
44695
44797
  }
44696
44798
 
44697
44799
  // ../content-model/src/routeTemplate.ts
@@ -45103,7 +45205,7 @@ var contentConfigSchema = contentConfigBaseSchema.superRefine((data, ctx) => {
45103
45205
  });
45104
45206
  }
45105
45207
  const paths = data.pages.map((p) => p.path);
45106
- const duplicatePaths = paths.filter((path32, i) => paths.indexOf(path32) !== i);
45208
+ const duplicatePaths = paths.filter((path33, i) => paths.indexOf(path33) !== i);
45107
45209
  if (duplicatePaths.length > 0) {
45108
45210
  ctx.addIssue({
45109
45211
  code: z.ZodIssueCode.custom,
@@ -45160,18 +45262,18 @@ function validateLayoutNodeTypes(layout) {
45160
45262
  errors
45161
45263
  };
45162
45264
  }
45163
- function validateNodeTypesRecursive(node, path32, errors) {
45265
+ function validateNodeTypesRecursive(node, path33, errors) {
45164
45266
  if (!ALLOWED_NODE_TYPES_SET.has(node.type)) {
45165
45267
  errors.push({
45166
- path: `${path32}.type`,
45268
+ path: `${path33}.type`,
45167
45269
  type: "invalid_node_type",
45168
45270
  value: node.type,
45169
- message: `Unknown node type "${node.type}" at ${path32}. Valid types: section, stack, text, etc.`
45271
+ message: `Unknown node type "${node.type}" at ${path33}. Valid types: section, stack, text, etc.`
45170
45272
  });
45171
45273
  }
45172
45274
  if (node.children && Array.isArray(node.children)) {
45173
45275
  node.children.forEach((child, index) => {
45174
- validateNodeTypesRecursive(child, `${path32}.children[${index}]`, errors);
45276
+ validateNodeTypesRecursive(child, `${path33}.children[${index}]`, errors);
45175
45277
  });
45176
45278
  }
45177
45279
  }
@@ -45183,45 +45285,45 @@ function validateTransformIds(layout) {
45183
45285
  errors
45184
45286
  };
45185
45287
  }
45186
- function validateTransformIdsRecursive(node, path32, errors) {
45288
+ function validateTransformIdsRecursive(node, path33, errors) {
45187
45289
  if (node.$bind?.transforms && Array.isArray(node.$bind.transforms)) {
45188
- validateTransformList(node.$bind.transforms, `${path32}.$bind.transforms`, errors);
45290
+ validateTransformList(node.$bind.transforms, `${path33}.$bind.transforms`, errors);
45189
45291
  }
45190
45292
  if (node.$repeat?.collection?.transforms && Array.isArray(node.$repeat.collection.transforms)) {
45191
- validateTransformList(node.$repeat.collection.transforms, `${path32}.$repeat.collection.transforms`, errors);
45293
+ validateTransformList(node.$repeat.collection.transforms, `${path33}.$repeat.collection.transforms`, errors);
45192
45294
  }
45193
45295
  if (node.$when?.when?.transforms && Array.isArray(node.$when.when.transforms)) {
45194
- validateTransformList(node.$when.when.transforms, `${path32}.$when.when.transforms`, errors);
45296
+ validateTransformList(node.$when.when.transforms, `${path33}.$when.when.transforms`, errors);
45195
45297
  }
45196
45298
  if (node.$scopes && Array.isArray(node.$scopes)) {
45197
45299
  node.$scopes.forEach((scope, index) => {
45198
45300
  if (scope.from?.transforms && Array.isArray(scope.from.transforms)) {
45199
- validateTransformList(scope.from.transforms, `${path32}.$scopes[${index}].from.transforms`, errors);
45301
+ validateTransformList(scope.from.transforms, `${path33}.$scopes[${index}].from.transforms`, errors);
45200
45302
  }
45201
45303
  });
45202
45304
  }
45203
45305
  if (node.props) {
45204
- validatePropsTransforms(node.props, `${path32}.props`, errors);
45306
+ validatePropsTransforms(node.props, `${path33}.props`, errors);
45205
45307
  }
45206
45308
  if (node.children && Array.isArray(node.children)) {
45207
45309
  node.children.forEach((child, index) => {
45208
- validateTransformIdsRecursive(child, `${path32}.children[${index}]`, errors);
45310
+ validateTransformIdsRecursive(child, `${path33}.children[${index}]`, errors);
45209
45311
  });
45210
45312
  }
45211
45313
  }
45212
- function validateTransformList(transforms, path32, errors) {
45314
+ function validateTransformList(transforms, path33, errors) {
45213
45315
  transforms.forEach((transform, index) => {
45214
45316
  if (!ALLOWED_TRANSFORM_IDS_SET.has(transform.id)) {
45215
45317
  errors.push({
45216
- path: `${path32}[${index}].id`,
45318
+ path: `${path33}[${index}].id`,
45217
45319
  type: "invalid_transform_id",
45218
45320
  value: transform.id,
45219
- message: `Unknown transform "${transform.id}" at ${path32}. Valid transforms: string.uppercase, value.fallback, etc.`
45321
+ message: `Unknown transform "${transform.id}" at ${path33}. Valid transforms: string.uppercase, value.fallback, etc.`
45220
45322
  });
45221
45323
  }
45222
45324
  });
45223
45325
  }
45224
- function validatePropsTransforms(props2, path32, errors) {
45326
+ function validatePropsTransforms(props2, path33, errors) {
45225
45327
  for (const [key, value] of Object.entries(props2)) {
45226
45328
  if (isBindingObject(value)) {
45227
45329
  const binding = value;
@@ -45229,16 +45331,16 @@ function validatePropsTransforms(props2, path32, errors) {
45229
45331
  binding.$bind.transforms.forEach((transform, index) => {
45230
45332
  if (!ALLOWED_TRANSFORM_IDS_SET.has(transform.id)) {
45231
45333
  errors.push({
45232
- path: `${path32}.${key}.$bind.transforms[${index}].id`,
45334
+ path: `${path33}.${key}.$bind.transforms[${index}].id`,
45233
45335
  type: "invalid_transform_id",
45234
45336
  value: transform.id,
45235
- message: `Unknown transform "${transform.id}" at ${path32}.${key}. Valid transforms: string.uppercase, value.fallback, etc.`
45337
+ message: `Unknown transform "${transform.id}" at ${path33}.${key}. Valid transforms: string.uppercase, value.fallback, etc.`
45236
45338
  });
45237
45339
  }
45238
45340
  });
45239
45341
  }
45240
45342
  } else if (value && typeof value === "object" && !Array.isArray(value)) {
45241
- validatePropsTransforms(value, `${path32}.${key}`, errors);
45343
+ validatePropsTransforms(value, `${path33}.${key}`, errors);
45242
45344
  }
45243
45345
  }
45244
45346
  }
@@ -45791,8 +45893,8 @@ async function readApiResponse(response, requestInfo, options = {}) {
45791
45893
  function createHttpClient(config2) {
45792
45894
  const baseUrl = `${config2.dashboardUrl}/api/sdk/${config2.siteId}`;
45793
45895
  const timeout = config2.timeout ?? 3e4;
45794
- async function request(method, path32, options) {
45795
- let url = `${baseUrl}${path32}`;
45896
+ async function request(method, path33, options) {
45897
+ let url = `${baseUrl}${path33}`;
45796
45898
  if (options?.params && Object.keys(options.params).length > 0) {
45797
45899
  const searchParams = new URLSearchParams(options.params);
45798
45900
  url = `${url}?${searchParams.toString()}`;
@@ -45815,7 +45917,7 @@ function createHttpClient(config2) {
45815
45917
  } catch (error) {
45816
45918
  const requestInfo2 = buildRequestInfo({
45817
45919
  method,
45818
- path: path32,
45920
+ path: path33,
45819
45921
  url,
45820
45922
  baseUrl,
45821
45923
  dashboardUrl: config2.dashboardUrl,
@@ -45840,7 +45942,7 @@ function createHttpClient(config2) {
45840
45942
  }
45841
45943
  const requestInfo = buildRequestInfo({
45842
45944
  method,
45843
- path: path32,
45945
+ path: path33,
45844
45946
  url,
45845
45947
  baseUrl,
45846
45948
  dashboardUrl: config2.dashboardUrl,
@@ -45870,17 +45972,17 @@ function createHttpClient(config2) {
45870
45972
  return json.data;
45871
45973
  }
45872
45974
  return {
45873
- async get(path32, params) {
45874
- return request("GET", path32, { params });
45975
+ async get(path33, params) {
45976
+ return request("GET", path33, { params });
45875
45977
  },
45876
- async post(path32, body) {
45877
- return request("POST", path32, { body });
45978
+ async post(path33, body) {
45979
+ return request("POST", path33, { body });
45878
45980
  },
45879
- async patch(path32, body) {
45880
- return request("PATCH", path32, { body });
45981
+ async patch(path33, body) {
45982
+ return request("PATCH", path33, { body });
45881
45983
  },
45882
- async delete(path32, body) {
45883
- await request("DELETE", path32, { body });
45984
+ async delete(path33, body) {
45985
+ await request("DELETE", path33, { body });
45884
45986
  }
45885
45987
  };
45886
45988
  }
@@ -46983,7 +47085,7 @@ function formatDateShort(isoDate) {
46983
47085
  }
46984
47086
  async function parseJsonData(options) {
46985
47087
  if (options.file) {
46986
- const filePath = path20.resolve(options.file);
47088
+ const filePath = path21.resolve(options.file);
46987
47089
  const content = await fs2.readFile(filePath, "utf-8");
46988
47090
  return JSON.parse(content);
46989
47091
  }
@@ -47361,12 +47463,12 @@ function formatPushConfigActionFailure() {
47361
47463
  async function pushToDashboard(output, dashboardUrl, siteId, apiKey, config2, options) {
47362
47464
  const normalizedDashboardUrl = dashboardUrl.replace(/\/+$/, "");
47363
47465
  const baseUrl = `${normalizedDashboardUrl}/api`;
47364
- const path32 = `/sites/${siteId}/sdk-config`;
47365
- const pushUrl = `${baseUrl}${path32}`;
47466
+ const path33 = `/sites/${siteId}/sdk-config`;
47467
+ const pushUrl = `${baseUrl}${path33}`;
47366
47468
  output.info(`${options?.dryRun ? "Previewing" : "Pushing"} config at ${pushUrl}...`);
47367
47469
  const requestInfo = {
47368
47470
  method: "POST",
47369
- path: path32,
47471
+ path: path33,
47370
47472
  url: pushUrl,
47371
47473
  baseUrl,
47372
47474
  dashboardUrl: normalizedDashboardUrl,
@@ -47773,6 +47875,18 @@ function stripEnvSpecificMediaFieldsInPlace(value) {
47773
47875
  stripEnvSpecificMediaFieldsInPlace(entry);
47774
47876
  }
47775
47877
  }
47878
+
47879
+ // src/cli/merge-remote/entryLocal.ts
47880
+ function pulledEntryToLocalEntry(entry) {
47881
+ return {
47882
+ identifier: entry.identifier,
47883
+ data: entry.data,
47884
+ status: entry.status,
47885
+ hasUnpublishedChanges: entry.hasUnpublishedChanges,
47886
+ ...entry.slug !== void 0 ? { slug: entry.slug } : {},
47887
+ ...entry.blocks !== void 0 ? { blocks: entry.blocks } : {}
47888
+ };
47889
+ }
47776
47890
  async function fileExists(filePath) {
47777
47891
  try {
47778
47892
  await fs2.access(filePath);
@@ -47792,7 +47906,7 @@ async function isDirectory(dirPath) {
47792
47906
  async function listFiles(dirPath, extension) {
47793
47907
  try {
47794
47908
  const files = await fs2.readdir(dirPath);
47795
- return files.filter((f) => f.endsWith(extension)).map((f) => path20.join(dirPath, f));
47909
+ return files.filter((f) => f.endsWith(extension)).map((f) => path21.join(dirPath, f));
47796
47910
  } catch (error) {
47797
47911
  const nodeError = error;
47798
47912
  if (nodeError.code === "ENOENT") {
@@ -47811,9 +47925,9 @@ async function writeJsonFile(filePath, data) {
47811
47925
  }
47812
47926
  async function writeJsonFileAtomic(filePath, data) {
47813
47927
  const content = JSON.stringify(data, null, 2) + "\n";
47814
- const tmpPath = path20.join(
47815
- path20.dirname(filePath),
47816
- `.${path20.basename(filePath)}.${process.pid}.${Date.now()}.tmp`
47928
+ const tmpPath = path21.join(
47929
+ path21.dirname(filePath),
47930
+ `.${path21.basename(filePath)}.${process.pid}.${Date.now()}.tmp`
47817
47931
  );
47818
47932
  try {
47819
47933
  await fs2.writeFile(tmpPath, content, "utf-8");
@@ -47833,80 +47947,101 @@ async function ensureDir(dirPath) {
47833
47947
  }
47834
47948
  }
47835
47949
 
47836
- // src/cli/merge-remote/entryLocal.ts
47837
- function pulledEntryToLocalEntry(entry) {
47950
+ // src/cli/merge-remote/sharedBaseSnapshots.ts
47951
+ function baseSnapshotRoot(contentDir, baseKind) {
47952
+ return path21.join(contentDir, ".riverbank", "merge-remote", baseKind);
47953
+ }
47954
+ function baseSnapshotStoredTarget(target) {
47838
47955
  return {
47839
- identifier: entry.identifier,
47840
- data: entry.data,
47841
- status: entry.status,
47842
- hasUnpublishedChanges: entry.hasUnpublishedChanges,
47843
- ...entry.slug !== void 0 ? { slug: entry.slug } : {},
47844
- ...entry.blocks !== void 0 ? { blocks: entry.blocks } : {}
47956
+ env: target.env,
47957
+ siteIdHash: siteIdHash(target.siteId)
47845
47958
  };
47846
47959
  }
47960
+ function siteScopedSnapshotDir(input) {
47961
+ return path21.join(input.rootDir, input.target.env, siteIdHash(input.target.siteId), input.leafDir);
47962
+ }
47963
+ async function writeBaseSnapshots(input) {
47964
+ await ensureLocalOnlySnapshotRoot(input.contentDir);
47965
+ await ensureDir(input.snapshotDir);
47966
+ const writtenFileNames = [];
47967
+ for (const item of input.items) {
47968
+ const snapshot = input.toSnapshot(item);
47969
+ const fileName = input.fileNameForSnapshot(snapshot);
47970
+ writtenFileNames.push(fileName);
47971
+ await writeJsonFile(path21.join(input.snapshotDir, fileName), snapshot);
47972
+ }
47973
+ if (input.cleanupMissing !== false) {
47974
+ await removeMissingSnapshotFiles(
47975
+ input.snapshotDir,
47976
+ new Set(writtenFileNames)
47977
+ );
47978
+ }
47979
+ return {
47980
+ rootDir: input.rootDir,
47981
+ count: input.items.length
47982
+ };
47983
+ }
47984
+ async function readBaseSnapshot(snapshotPath) {
47985
+ try {
47986
+ return await readJsonFile(snapshotPath);
47987
+ } catch (error) {
47988
+ if (error.code === "ENOENT") return null;
47989
+ throw error;
47990
+ }
47991
+ }
47992
+ function encodeSnapshotPathPart(value) {
47993
+ return encodeURIComponent(value).replace(/\./gu, "%2E");
47994
+ }
47995
+ async function ensureLocalOnlySnapshotRoot(contentDir) {
47996
+ const localRoot = path21.join(contentDir, ".riverbank");
47997
+ await ensureDir(localRoot);
47998
+ await writeFile(path21.join(localRoot, ".gitignore"), "*\n!.gitignore\n", "utf-8");
47999
+ }
48000
+ async function removeMissingSnapshotFiles(snapshotDir, expectedFileNames) {
48001
+ for (const existingFile of await listFiles(snapshotDir, ".json")) {
48002
+ if (!expectedFileNames.has(path21.basename(existingFile))) {
48003
+ await unlink(existingFile);
48004
+ }
48005
+ }
48006
+ }
48007
+ function siteIdHash(siteId) {
48008
+ return createHash("sha256").update(siteId).digest("hex").slice(0, 16);
48009
+ }
47847
48010
 
47848
48011
  // src/cli/merge-remote/entrySnapshots.ts
47849
48012
  var SNAPSHOT_VERSION = "entry-base.v1";
47850
48013
  function entryBaseSnapshotRoot(contentDir) {
47851
- return path20.join(contentDir, ".riverbank", "merge-remote", "entry-bases");
48014
+ return baseSnapshotRoot(contentDir, "entry-bases");
47852
48015
  }
47853
48016
  function entryBaseSnapshotPath(input) {
47854
- return path20.join(
47855
- entryBaseSnapshotRoot(input.contentDir),
47856
- input.target.env,
47857
- siteIdHash(input.target.siteId),
47858
- "entries",
47859
- encodePathPart(input.subject.contentType),
47860
- `${encodePathPart(input.subject.identifier)}.json`
48017
+ return path21.join(
48018
+ entrySnapshotTypeDir(input),
48019
+ `${entrySnapshotFileName(input.subject.identifier)}`
47861
48020
  );
47862
48021
  }
47863
48022
  async function writeEntryBaseSnapshots(input) {
47864
- await ensureLocalOnlySnapshotRoot(input.contentDir);
47865
- const typeDir = path20.dirname(entryBaseSnapshotPath({
48023
+ const typeDir = entrySnapshotTypeDir({
47866
48024
  contentDir: input.contentDir,
47867
48025
  target: input.target,
47868
- subject: {
47869
- contentType: input.contentType,
47870
- identifier: "__placeholder__"
47871
- }
47872
- }));
47873
- await ensureDir(typeDir);
47874
- for (const entry of input.entries) {
47875
- const snapshot = toEntryBaseSnapshot({
48026
+ subject: { contentType: input.contentType }
48027
+ });
48028
+ return writeBaseSnapshots({
48029
+ contentDir: input.contentDir,
48030
+ rootDir: entryBaseSnapshotRoot(input.contentDir),
48031
+ snapshotDir: typeDir,
48032
+ items: input.entries,
48033
+ toSnapshot: (entry) => toEntryBaseSnapshot({
47876
48034
  target: input.target,
47877
48035
  contentType: input.contentType,
47878
48036
  entry,
47879
48037
  meta: input.meta
47880
- });
47881
- await writeJsonFile(
47882
- entryBaseSnapshotPath({
47883
- contentDir: input.contentDir,
47884
- target: input.target,
47885
- subject: snapshot.subject
47886
- }),
47887
- snapshot
47888
- );
47889
- }
47890
- if (input.cleanupMissing !== false) {
47891
- const expectedFiles = new Set(input.entries.map((entry) => `${encodePathPart(entry.identifier)}.json`));
47892
- for (const existingFile of await listFiles(typeDir, ".json")) {
47893
- if (!expectedFiles.has(path20.basename(existingFile))) {
47894
- await unlink(existingFile);
47895
- }
47896
- }
47897
- }
47898
- return {
47899
- rootDir: entryBaseSnapshotRoot(input.contentDir),
47900
- count: input.entries.length
47901
- };
48038
+ }),
48039
+ fileNameForSnapshot: (snapshot) => entrySnapshotFileName(snapshot.subject.identifier),
48040
+ cleanupMissing: input.cleanupMissing
48041
+ });
47902
48042
  }
47903
48043
  async function readEntryBaseSnapshot(input) {
47904
- try {
47905
- return await readJsonFile(entryBaseSnapshotPath(input));
47906
- } catch (error) {
47907
- if (error.code === "ENOENT") return null;
47908
- throw error;
47909
- }
48044
+ return readBaseSnapshot(entryBaseSnapshotPath(input));
47910
48045
  }
47911
48046
  function toEntryBaseSnapshot(input) {
47912
48047
  const remoteVersion = input.meta.entries[input.entry.identifier];
@@ -47915,10 +48050,7 @@ function toEntryBaseSnapshot(input) {
47915
48050
  }
47916
48051
  return {
47917
48052
  version: SNAPSHOT_VERSION,
47918
- target: {
47919
- env: input.target.env,
47920
- siteIdHash: siteIdHash(input.target.siteId)
47921
- },
48053
+ target: baseSnapshotStoredTarget(input.target),
47922
48054
  subject: {
47923
48055
  contentType: input.contentType,
47924
48056
  identifier: input.entry.identifier
@@ -47928,16 +48060,18 @@ function toEntryBaseSnapshot(input) {
47928
48060
  entry: pulledEntryToLocalEntry(input.entry)
47929
48061
  };
47930
48062
  }
47931
- async function ensureLocalOnlySnapshotRoot(contentDir) {
47932
- const localRoot = path20.join(contentDir, ".riverbank");
47933
- await ensureDir(localRoot);
47934
- await writeFile(path20.join(localRoot, ".gitignore"), "*\n!.gitignore\n", "utf-8");
47935
- }
47936
- function siteIdHash(siteId) {
47937
- return createHash("sha256").update(siteId).digest("hex").slice(0, 16);
48063
+ function entrySnapshotTypeDir(input) {
48064
+ return path21.join(
48065
+ siteScopedSnapshotDir({
48066
+ rootDir: entryBaseSnapshotRoot(input.contentDir),
48067
+ target: input.target,
48068
+ leafDir: "entries"
48069
+ }),
48070
+ encodeSnapshotPathPart(input.subject.contentType)
48071
+ );
47938
48072
  }
47939
- function encodePathPart(value) {
47940
- return encodeURIComponent(value).replace(/\./gu, "%2E");
48073
+ function entrySnapshotFileName(identifier) {
48074
+ return `${encodeSnapshotPathPart(identifier)}.json`;
47941
48075
  }
47942
48076
 
47943
48077
  // src/cli/merge-remote/pageLocal.ts
@@ -47963,68 +48097,40 @@ function pulledPageToLocalPage(page) {
47963
48097
  // src/cli/merge-remote/pageSnapshots.ts
47964
48098
  var SNAPSHOT_VERSION2 = "page-base.v1";
47965
48099
  function pageBaseSnapshotRoot(contentDir) {
47966
- return path20.join(contentDir, ".riverbank", "merge-remote", "page-bases");
48100
+ return baseSnapshotRoot(contentDir, "page-bases");
47967
48101
  }
47968
48102
  function pageBaseSnapshotPath(input) {
47969
- return path20.join(
47970
- pageBaseSnapshotRoot(input.contentDir),
47971
- input.target.env,
47972
- siteIdHash2(input.target.siteId),
47973
- "pages",
47974
- `${encodePathPart2(input.subject.identifier)}.json`
48103
+ return path21.join(
48104
+ pageSnapshotDir(input),
48105
+ pageSnapshotFileName(input.subject.identifier)
47975
48106
  );
47976
48107
  }
47977
48108
  async function writePageBaseSnapshots(input) {
47978
- await ensureLocalOnlySnapshotRoot2(input.contentDir);
47979
- const pagesDir = path20.dirname(pageBaseSnapshotPath({
48109
+ const pagesDir = pageSnapshotDir({
47980
48110
  contentDir: input.contentDir,
47981
- target: input.target,
47982
- subject: { identifier: "__placeholder__" }
47983
- }));
47984
- await ensureDir(pagesDir);
47985
- for (const page of input.pages) {
47986
- const snapshot = toPageBaseSnapshot({
48111
+ target: input.target
48112
+ });
48113
+ return writeBaseSnapshots({
48114
+ contentDir: input.contentDir,
48115
+ rootDir: pageBaseSnapshotRoot(input.contentDir),
48116
+ snapshotDir: pagesDir,
48117
+ items: input.pages,
48118
+ toSnapshot: (page) => toPageBaseSnapshot({
47987
48119
  target: input.target,
47988
48120
  page,
47989
48121
  meta: input.meta
47990
- });
47991
- await writeJsonFile(
47992
- pageBaseSnapshotPath({
47993
- contentDir: input.contentDir,
47994
- target: input.target,
47995
- subject: snapshot.subject
47996
- }),
47997
- snapshot
47998
- );
47999
- }
48000
- if (input.cleanupMissing !== false) {
48001
- const expectedFiles = new Set(input.pages.map((page) => `${encodePathPart2(page.identifier)}.json`));
48002
- for (const existingFile of await listFiles(pagesDir, ".json")) {
48003
- if (!expectedFiles.has(path20.basename(existingFile))) {
48004
- await unlink(existingFile);
48005
- }
48006
- }
48007
- }
48008
- return {
48009
- rootDir: pageBaseSnapshotRoot(input.contentDir),
48010
- count: input.pages.length
48011
- };
48122
+ }),
48123
+ fileNameForSnapshot: (snapshot) => pageSnapshotFileName(snapshot.subject.identifier),
48124
+ cleanupMissing: input.cleanupMissing
48125
+ });
48012
48126
  }
48013
48127
  async function readPageBaseSnapshot(input) {
48014
- try {
48015
- return await readJsonFile(pageBaseSnapshotPath(input));
48016
- } catch (error) {
48017
- if (error.code === "ENOENT") return null;
48018
- throw error;
48019
- }
48128
+ return readBaseSnapshot(pageBaseSnapshotPath(input));
48020
48129
  }
48021
48130
  function toPageBaseSnapshot(input) {
48022
48131
  return {
48023
48132
  version: SNAPSHOT_VERSION2,
48024
- target: {
48025
- env: input.target.env,
48026
- siteIdHash: siteIdHash2(input.target.siteId)
48027
- },
48133
+ target: baseSnapshotStoredTarget(input.target),
48028
48134
  subject: {
48029
48135
  identifier: input.page.identifier
48030
48136
  },
@@ -48037,22 +48143,21 @@ function toPageBaseSnapshot(input) {
48037
48143
  page: pulledPageToLocalPage(input.page)
48038
48144
  };
48039
48145
  }
48040
- async function ensureLocalOnlySnapshotRoot2(contentDir) {
48041
- const localRoot = path20.join(contentDir, ".riverbank");
48042
- await ensureDir(localRoot);
48043
- await writeFile(path20.join(localRoot, ".gitignore"), "*\n!.gitignore\n", "utf-8");
48044
- }
48045
- function siteIdHash2(siteId) {
48046
- return createHash("sha256").update(siteId).digest("hex").slice(0, 16);
48146
+ function pageSnapshotDir(input) {
48147
+ return siteScopedSnapshotDir({
48148
+ rootDir: pageBaseSnapshotRoot(input.contentDir),
48149
+ target: input.target,
48150
+ leafDir: "pages"
48151
+ });
48047
48152
  }
48048
- function encodePathPart2(value) {
48049
- return encodeURIComponent(value).replace(/\./gu, "%2E");
48153
+ function pageSnapshotFileName(identifier) {
48154
+ return `${encodeSnapshotPathPart(identifier)}.json`;
48050
48155
  }
48051
48156
  function entryTypeDirPath(contentDir, contentType) {
48052
- return path20.join(contentDir, "entries", contentType);
48157
+ return path21.join(contentDir, "entries", contentType);
48053
48158
  }
48054
48159
  function entryFilePath(input) {
48055
- return path20.join(entryTypeDirPath(input.contentDir, input.contentType), `${input.identifier}.json`);
48160
+ return path21.join(entryTypeDirPath(input.contentDir, input.contentType), `${input.identifier}.json`);
48056
48161
  }
48057
48162
  var TARGET_MARKER_FILE = "_target.json";
48058
48163
  var metadataTargetMarkerSchema = z.object({
@@ -48069,23 +48174,23 @@ function metadataTargetFromEnvironment(env, environment) {
48069
48174
  };
48070
48175
  }
48071
48176
  function legacyMetadataDir(contentDir) {
48072
- return path20.join(contentDir, ".meta");
48177
+ return path21.join(contentDir, ".meta");
48073
48178
  }
48074
48179
  function scopedMetadataDir(contentDir, target) {
48075
- return path20.join(contentDir, ".meta", target.env);
48180
+ return path21.join(contentDir, ".meta", target.env);
48076
48181
  }
48077
48182
  function metadataFilePath(contentDir, fileName, target) {
48078
48183
  const dir = target ? scopedMetadataDir(contentDir, target) : legacyMetadataDir(contentDir);
48079
- return path20.join(dir, fileName);
48184
+ return path21.join(dir, fileName);
48080
48185
  }
48081
48186
  function legacyMetadataFilePath(contentDir, fileName) {
48082
- return path20.join(legacyMetadataDir(contentDir), fileName);
48187
+ return path21.join(legacyMetadataDir(contentDir), fileName);
48083
48188
  }
48084
48189
  async function ensureMetadataDir(contentDir, target) {
48085
48190
  const dir = target ? scopedMetadataDir(contentDir, target) : legacyMetadataDir(contentDir);
48086
48191
  await ensureDir(dir);
48087
48192
  if (target) {
48088
- await writeJsonFile(path20.join(dir, TARGET_MARKER_FILE), markerFromTarget(target));
48193
+ await writeJsonFile(path21.join(dir, TARGET_MARKER_FILE), markerFromTarget(target));
48089
48194
  }
48090
48195
  return dir;
48091
48196
  }
@@ -48141,7 +48246,7 @@ async function resolveMetadataReadPath(contentDir, fileName, target) {
48141
48246
  if (await hasMismatchedTargetMarker(scopedDir, target)) {
48142
48247
  return null;
48143
48248
  }
48144
- const scopedPath = await existingFilePath(path20.join(scopedDir, fileName), "scoped");
48249
+ const scopedPath = await existingFilePath(path21.join(scopedDir, fileName), "scoped");
48145
48250
  if (scopedPath) return scopedPath;
48146
48251
  return existingFilePath(legacyMetadataFilePath(contentDir, fileName), "legacy");
48147
48252
  }
@@ -48165,7 +48270,7 @@ async function existingFilePath(filePath, source) {
48165
48270
  async function hasMismatchedTargetMarker(dir, target) {
48166
48271
  let parsed;
48167
48272
  try {
48168
- const content = await fs2.readFile(path20.join(dir, TARGET_MARKER_FILE), "utf-8");
48273
+ const content = await fs2.readFile(path21.join(dir, TARGET_MARKER_FILE), "utf-8");
48169
48274
  const result = metadataTargetMarkerSchema.safeParse(JSON.parse(content));
48170
48275
  if (!result.success) return false;
48171
48276
  parsed = result.data;
@@ -48201,7 +48306,7 @@ function parseThemeMeta(value) {
48201
48306
  return { pulledAt: value.pulledAt, themes: value.themes };
48202
48307
  }
48203
48308
  async function writeEntries(contentDir, pulledEntries, options) {
48204
- const entriesDir = path20.join(contentDir, "entries");
48309
+ const entriesDir = path21.join(contentDir, "entries");
48205
48310
  const { contentType, entries, meta } = pulledEntries;
48206
48311
  const typeDir = entryTypeDirPath(contentDir, contentType);
48207
48312
  await ensureDir(typeDir);
@@ -48215,13 +48320,13 @@ async function writeEntries(contentDir, pulledEntries, options) {
48215
48320
  const existingFiles = await listFiles(typeDir, ".json");
48216
48321
  const newIdentifiers = new Set(entries.map((e) => `${e.identifier}.json`));
48217
48322
  for (const existingFile of existingFiles) {
48218
- const filename = path20.basename(existingFile);
48323
+ const filename = path21.basename(existingFile);
48219
48324
  if (!newIdentifiers.has(filename)) {
48220
48325
  await fs2.unlink(existingFile);
48221
48326
  }
48222
48327
  }
48223
48328
  }
48224
- const oldFormatFile = path20.join(entriesDir, `${contentType}.json`);
48329
+ const oldFormatFile = path21.join(entriesDir, `${contentType}.json`);
48225
48330
  try {
48226
48331
  await fs2.unlink(oldFormatFile);
48227
48332
  } catch (error) {
@@ -48273,12 +48378,12 @@ async function writeEntries(contentDir, pulledEntries, options) {
48273
48378
  return { dirPath: typeDir, metaPath, count: entries.length };
48274
48379
  }
48275
48380
  async function writePages(contentDir, pulledPages, options) {
48276
- const pagesDir = path20.join(contentDir, "pages");
48381
+ const pagesDir = path21.join(contentDir, "pages");
48277
48382
  await ensureDir(pagesDir);
48278
48383
  const filePaths = [];
48279
48384
  const pagesMeta = {};
48280
48385
  for (const page of pulledPages.pages) {
48281
- const filePath = path20.join(pagesDir, `${page.identifier}.json`);
48386
+ const filePath = path21.join(pagesDir, `${page.identifier}.json`);
48282
48387
  const localPage = convertPulledPagesToLocal([page])[0];
48283
48388
  if (!localPage) continue;
48284
48389
  stripEnvSpecificMediaFieldsInPlace(localPage);
@@ -48320,7 +48425,7 @@ async function writePages(contentDir, pulledPages, options) {
48320
48425
  }
48321
48426
  async function writeNavigation(contentDir, pulledNavigation, options) {
48322
48427
  await ensureDir(contentDir);
48323
- const filePath = path20.join(contentDir, "navigation.json");
48428
+ const filePath = path21.join(contentDir, "navigation.json");
48324
48429
  const localNavigation = convertPulledNavigationToLocal(pulledNavigation.menus);
48325
48430
  stripEnvSpecificMediaFieldsInPlace(localNavigation);
48326
48431
  await writeJsonFile(filePath, localNavigation);
@@ -48342,7 +48447,7 @@ async function writeNavigation(contentDir, pulledNavigation, options) {
48342
48447
  }
48343
48448
  async function writeSettings(contentDir, pulledSettings, options) {
48344
48449
  await ensureDir(contentDir);
48345
- const filePath = path20.join(contentDir, "settings.json");
48450
+ const filePath = path21.join(contentDir, "settings.json");
48346
48451
  stripEnvSpecificMediaFieldsInPlace(pulledSettings.settings);
48347
48452
  await writeJsonFile(filePath, pulledSettings.settings);
48348
48453
  if (!options?.skipMeta) {
@@ -48354,12 +48459,12 @@ async function writeSettings(contentDir, pulledSettings, options) {
48354
48459
  return filePath;
48355
48460
  }
48356
48461
  async function writeForms(contentDir, pulledForms, options) {
48357
- const formsDir = path20.join(contentDir, "forms");
48462
+ const formsDir = path21.join(contentDir, "forms");
48358
48463
  await ensureDir(formsDir);
48359
48464
  const filePaths = [];
48360
48465
  const formsMeta = {};
48361
48466
  for (const form2 of pulledForms.forms) {
48362
- const filePath = path20.join(formsDir, `${form2.slug}.json`);
48467
+ const filePath = path21.join(formsDir, `${form2.slug}.json`);
48363
48468
  const formPayload = {
48364
48469
  slug: form2.slug,
48365
48470
  name: form2.name,
@@ -48384,9 +48489,9 @@ async function writeForms(contentDir, pulledForms, options) {
48384
48489
  return { filePaths, metaPath };
48385
48490
  }
48386
48491
  async function writeTheme(contentDir, theme, themeName) {
48387
- const themesDir = path20.join(contentDir, "themes");
48492
+ const themesDir = path21.join(contentDir, "themes");
48388
48493
  await ensureDir(themesDir);
48389
- const filePath = path20.join(themesDir, `${themeName}.json`);
48494
+ const filePath = path21.join(themesDir, `${themeName}.json`);
48390
48495
  await writeJsonFile(filePath, theme);
48391
48496
  return filePath;
48392
48497
  }
@@ -48417,12 +48522,12 @@ async function writePulledTheme(contentDir, pulledTheme, themeName = "current",
48417
48522
  return { filePath, metaPath };
48418
48523
  }
48419
48524
  async function writeVenues(contentDir, pulledVenues, options) {
48420
- const venuesDir = path20.join(contentDir, "venues");
48525
+ const venuesDir = path21.join(contentDir, "venues");
48421
48526
  await ensureDir(venuesDir);
48422
48527
  const filePaths = [];
48423
48528
  const venuesMeta = {};
48424
48529
  for (const venue of pulledVenues.venues) {
48425
- const filePath = path20.join(venuesDir, `${venue.slug}.json`);
48530
+ const filePath = path21.join(venuesDir, `${venue.slug}.json`);
48426
48531
  await writeJsonFile(filePath, {
48427
48532
  slug: venue.slug,
48428
48533
  title: venue.title,
@@ -48449,12 +48554,12 @@ async function writeVenues(contentDir, pulledVenues, options) {
48449
48554
  return { filePaths, metaPath };
48450
48555
  }
48451
48556
  async function writeEventCategories(contentDir, pulledCategories, options) {
48452
- const categoriesDir = path20.join(contentDir, "event-categories");
48557
+ const categoriesDir = path21.join(contentDir, "event-categories");
48453
48558
  await ensureDir(categoriesDir);
48454
48559
  const filePaths = [];
48455
48560
  const categoriesMeta = {};
48456
48561
  for (const category of pulledCategories.eventCategories) {
48457
- const filePath = path20.join(categoriesDir, `${category.identifier}.json`);
48562
+ const filePath = path21.join(categoriesDir, `${category.identifier}.json`);
48458
48563
  await writeJsonFile(filePath, {
48459
48564
  identifier: category.identifier,
48460
48565
  name: category.name,
@@ -48478,12 +48583,12 @@ async function writeEventCategories(contentDir, pulledCategories, options) {
48478
48583
  return { filePaths, metaPath };
48479
48584
  }
48480
48585
  async function writeEvents(contentDir, pulledEvents, options) {
48481
- const eventsDir = path20.join(contentDir, "events");
48586
+ const eventsDir = path21.join(contentDir, "events");
48482
48587
  await ensureDir(eventsDir);
48483
48588
  const filePaths = [];
48484
48589
  const eventsMeta = {};
48485
48590
  for (const event of pulledEvents.events) {
48486
- const filePath = path20.join(eventsDir, `${event.identifier}.json`);
48591
+ const filePath = path21.join(eventsDir, `${event.identifier}.json`);
48487
48592
  const eventPayload = toWritableLocalEvent(event);
48488
48593
  stripEnvSpecificMediaFieldsInPlace(eventPayload);
48489
48594
  await writeJsonFile(filePath, eventPayload);
@@ -48530,12 +48635,12 @@ function toWritableLocalEvent(event) {
48530
48635
  };
48531
48636
  }
48532
48637
  async function writeCourses(contentDir, pulledCourses, options) {
48533
- const coursesDir = path20.join(contentDir, "courses");
48638
+ const coursesDir = path21.join(contentDir, "courses");
48534
48639
  await ensureDir(coursesDir);
48535
48640
  const filePaths = [];
48536
48641
  const coursesMeta = {};
48537
48642
  for (const course of pulledCourses.courses) {
48538
- const filePath = path20.join(coursesDir, `${course.identifier}.json`);
48643
+ const filePath = path21.join(coursesDir, `${course.identifier}.json`);
48539
48644
  const coursePayload = {
48540
48645
  identifier: course.identifier,
48541
48646
  title: course.title,
@@ -48573,7 +48678,7 @@ async function writeCourses(contentDir, pulledCourses, options) {
48573
48678
  }
48574
48679
  async function writeFooter(contentDir, pulledFooter, options) {
48575
48680
  await ensureDir(contentDir);
48576
- const filePath = path20.join(contentDir, "footer.json");
48681
+ const filePath = path21.join(contentDir, "footer.json");
48577
48682
  const localFooter = pulledFooter.footer ? convertPulledFooterToLocal(pulledFooter.footer) : {};
48578
48683
  stripEnvSpecificMediaFieldsInPlace(localFooter);
48579
48684
  await writeJsonFile(filePath, localFooter);
@@ -48648,7 +48753,7 @@ async function updateMetadataAfterPush(contentDir, remoteContent, options) {
48648
48753
  }
48649
48754
  }
48650
48755
  var MANIFEST_VERSION = 2;
48651
- var getManifestPath = (contentDir) => path20.join(contentDir, "media", ".manifest.json");
48756
+ var getManifestPath = (contentDir) => path21.join(contentDir, "media", ".manifest.json");
48652
48757
  var ensureDir2 = async (dirPath) => {
48653
48758
  try {
48654
48759
  await fs2.mkdir(dirPath, { recursive: true });
@@ -48707,7 +48812,7 @@ async function readMediaManifest(contentDir) {
48707
48812
  return createEmptyMediaManifest();
48708
48813
  }
48709
48814
  async function writeMediaManifest(contentDir, manifest) {
48710
- const mediaDir = path20.join(contentDir, "media");
48815
+ const mediaDir = path21.join(contentDir, "media");
48711
48816
  await ensureDir2(mediaDir);
48712
48817
  const updatedManifest = {
48713
48818
  ...manifest,
@@ -48760,12 +48865,12 @@ async function readEntriesFromDirectory(dirPath) {
48760
48865
  return entries;
48761
48866
  }
48762
48867
  async function findLegacyEntryFiles(contentDir) {
48763
- const entriesDir = path20.join(contentDir, "entries");
48868
+ const entriesDir = path21.join(contentDir, "entries");
48764
48869
  const legacyFiles = [];
48765
48870
  try {
48766
48871
  const items = await fs2.readdir(entriesDir);
48767
48872
  for (const item of items) {
48768
- const itemPath = path20.join(entriesDir, item);
48873
+ const itemPath = path21.join(entriesDir, item);
48769
48874
  if (item.endsWith(".json") && !await isDirectory(itemPath)) {
48770
48875
  legacyFiles.push(itemPath);
48771
48876
  }
@@ -48776,7 +48881,7 @@ async function findLegacyEntryFiles(contentDir) {
48776
48881
  return legacyFiles;
48777
48882
  }
48778
48883
  async function readEntries(contentDir, contentType, metadataTarget) {
48779
- const entriesDir = path20.join(contentDir, "entries");
48884
+ const entriesDir = path21.join(contentDir, "entries");
48780
48885
  const result = /* @__PURE__ */ new Map();
48781
48886
  const legacyFiles = await findLegacyEntryFiles(contentDir);
48782
48887
  if (legacyFiles.length > 0) {
@@ -48790,7 +48895,7 @@ async function readEntries(contentDir, contentType, metadataTarget) {
48790
48895
  for (const item of items) {
48791
48896
  if (item.isDirectory()) {
48792
48897
  const entries = await readEntriesFromDirectory(
48793
- path20.join(entriesDir, item.name)
48898
+ path21.join(entriesDir, item.name)
48794
48899
  );
48795
48900
  await applyEntryMetadata(contentDir, item.name, entries, metadataTarget);
48796
48901
  if (entries.length > 0) {
@@ -48832,7 +48937,7 @@ async function applyEntryMetadata(contentDir, contentType, entries, metadataTarg
48832
48937
  });
48833
48938
  }
48834
48939
  async function readPages(contentDir) {
48835
- const pagesDir = path20.join(contentDir, "pages");
48940
+ const pagesDir = path21.join(contentDir, "pages");
48836
48941
  const pages = [];
48837
48942
  const files = await listFiles(pagesDir, ".json");
48838
48943
  for (const filePath of files) {
@@ -48846,14 +48951,14 @@ async function readPages(contentDir) {
48846
48951
  return pages;
48847
48952
  }
48848
48953
  async function readNavigation(contentDir) {
48849
- const filePath = path20.join(contentDir, "navigation.json");
48954
+ const filePath = path21.join(contentDir, "navigation.json");
48850
48955
  if (!await fileExists(filePath)) {
48851
48956
  return null;
48852
48957
  }
48853
48958
  return readJsonFile(filePath);
48854
48959
  }
48855
48960
  async function readSettings(contentDir) {
48856
- const filePath = path20.join(contentDir, "settings.json");
48961
+ const filePath = path21.join(contentDir, "settings.json");
48857
48962
  if (!await fileExists(filePath)) {
48858
48963
  return null;
48859
48964
  }
@@ -48870,7 +48975,7 @@ async function readSettings(contentDir) {
48870
48975
  return parsed.data;
48871
48976
  }
48872
48977
  async function readForms(contentDir) {
48873
- const formsDir = path20.join(contentDir, "forms");
48978
+ const formsDir = path21.join(contentDir, "forms");
48874
48979
  const forms = [];
48875
48980
  const files = await listFiles(formsDir, ".json");
48876
48981
  for (const filePath of files) {
@@ -48884,7 +48989,7 @@ async function readForms(contentDir) {
48884
48989
  return forms;
48885
48990
  }
48886
48991
  async function readVenues(contentDir) {
48887
- const venuesDir = path20.join(contentDir, "venues");
48992
+ const venuesDir = path21.join(contentDir, "venues");
48888
48993
  const venues = [];
48889
48994
  const files = await listFiles(venuesDir, ".json");
48890
48995
  for (const filePath of files) {
@@ -48898,7 +49003,7 @@ async function readVenues(contentDir) {
48898
49003
  return venues;
48899
49004
  }
48900
49005
  async function readEventCategories(contentDir) {
48901
- const categoriesDir = path20.join(contentDir, "event-categories");
49006
+ const categoriesDir = path21.join(contentDir, "event-categories");
48902
49007
  const categories = [];
48903
49008
  const files = await listFiles(categoriesDir, ".json");
48904
49009
  for (const filePath of files) {
@@ -48915,7 +49020,7 @@ async function readEvents(contentDir) {
48915
49020
  return (await readEventsWithFilePaths(contentDir)).map(({ filePath: _filePath, ...event }) => event);
48916
49021
  }
48917
49022
  async function readEventsWithFilePaths(contentDir) {
48918
- const eventsDir = path20.join(contentDir, "events");
49023
+ const eventsDir = path21.join(contentDir, "events");
48919
49024
  const events = [];
48920
49025
  const files = await listFiles(eventsDir, ".json");
48921
49026
  for (const filePath of files) {
@@ -48929,7 +49034,7 @@ async function readEventsWithFilePaths(contentDir) {
48929
49034
  return events;
48930
49035
  }
48931
49036
  async function readCourses(contentDir) {
48932
- const coursesDir = path20.join(contentDir, "courses");
49037
+ const coursesDir = path21.join(contentDir, "courses");
48933
49038
  const courses = [];
48934
49039
  const files = await listFiles(coursesDir, ".json");
48935
49040
  for (const filePath of files) {
@@ -48943,8 +49048,8 @@ async function readCourses(contentDir) {
48943
49048
  return courses;
48944
49049
  }
48945
49050
  async function readTheme(contentDir, themeName) {
48946
- const themesDir = path20.join(contentDir, "themes");
48947
- const filePath = path20.join(themesDir, `${themeName}.json`);
49051
+ const themesDir = path21.join(contentDir, "themes");
49052
+ const filePath = path21.join(themesDir, `${themeName}.json`);
48948
49053
  if (!await fileExists(filePath)) {
48949
49054
  return null;
48950
49055
  }
@@ -48952,13 +49057,13 @@ async function readTheme(contentDir, themeName) {
48952
49057
  return { name: themeName, theme };
48953
49058
  }
48954
49059
  async function readThemes(contentDir) {
48955
- const themesDir = path20.join(contentDir, "themes");
49060
+ const themesDir = path21.join(contentDir, "themes");
48956
49061
  const themes = [];
48957
49062
  const files = await listFiles(themesDir, ".json");
48958
49063
  for (const filePath of files) {
48959
49064
  try {
48960
49065
  const theme = await readJsonFile(filePath);
48961
- const name = path20.basename(filePath, ".json");
49066
+ const name = path21.basename(filePath, ".json");
48962
49067
  themes.push({ name, theme });
48963
49068
  } catch (error) {
48964
49069
  console.warn(`Warning: Could not parse ${filePath}:`, error);
@@ -48967,7 +49072,7 @@ async function readThemes(contentDir) {
48967
49072
  return themes;
48968
49073
  }
48969
49074
  async function readFooter(contentDir) {
48970
- const filePath = path20.join(contentDir, "footer.json");
49075
+ const filePath = path21.join(contentDir, "footer.json");
48971
49076
  if (!await fileExists(filePath)) {
48972
49077
  return null;
48973
49078
  }
@@ -49517,7 +49622,7 @@ var EXTENSIONS_BY_MIME = {
49517
49622
  "application/pdf": ".pdf"
49518
49623
  };
49519
49624
  function getMimeType(filename) {
49520
- const ext = path20.extname(filename).toLowerCase();
49625
+ const ext = path21.extname(filename).toLowerCase();
49521
49626
  return MIME_TYPES[ext] ?? "application/octet-stream";
49522
49627
  }
49523
49628
  function getExtensionForMimeType(mimeType) {
@@ -49545,10 +49650,10 @@ var listMediaDirFiles = async (mediaDir) => {
49545
49650
  }
49546
49651
  };
49547
49652
  var findMatchingFilename = async (contentDir, identifier, manifest) => {
49548
- const mediaDir = path20.join(contentDir, MEDIA_DIR_NAME);
49653
+ const mediaDir = path21.join(contentDir, MEDIA_DIR_NAME);
49549
49654
  const manifestEntry = manifest.assets[identifier];
49550
49655
  if (manifestEntry?.filename) {
49551
- const candidatePath = path20.join(mediaDir, manifestEntry.filename);
49656
+ const candidatePath = path21.join(mediaDir, manifestEntry.filename);
49552
49657
  if (await fileExists2(candidatePath)) {
49553
49658
  return manifestEntry.filename;
49554
49659
  }
@@ -49556,7 +49661,7 @@ var findMatchingFilename = async (contentDir, identifier, manifest) => {
49556
49661
  const files = await listMediaDirFiles(mediaDir);
49557
49662
  const matches = files.filter((name) => {
49558
49663
  if (name.startsWith(".")) return false;
49559
- const parsed = path20.parse(name);
49664
+ const parsed = path21.parse(name);
49560
49665
  return parsed.name === identifier;
49561
49666
  });
49562
49667
  if (matches.length > 1) {
@@ -49567,8 +49672,8 @@ var findMatchingFilename = async (contentDir, identifier, manifest) => {
49567
49672
  async function loadLocalMediaFile(contentDir, identifier, manifest) {
49568
49673
  const filename = await findMatchingFilename(contentDir, identifier, manifest);
49569
49674
  if (!filename) return null;
49570
- const mediaDir = path20.join(contentDir, MEDIA_DIR_NAME);
49571
- const filePath = path20.join(mediaDir, filename);
49675
+ const mediaDir = path21.join(contentDir, MEDIA_DIR_NAME);
49676
+ const filePath = path21.join(mediaDir, filename);
49572
49677
  const data = await fs2.readFile(filePath);
49573
49678
  const checksum = sha256(data);
49574
49679
  const mimeType = getMimeType(filename);
@@ -49581,9 +49686,9 @@ async function loadLocalMediaFile(contentDir, identifier, manifest) {
49581
49686
  return { identifier, filename, filePath, mimeType, checksum, data };
49582
49687
  }
49583
49688
  async function writeLocalMediaFile(contentDir, filename, data) {
49584
- const mediaDir = path20.join(contentDir, MEDIA_DIR_NAME);
49689
+ const mediaDir = path21.join(contentDir, MEDIA_DIR_NAME);
49585
49690
  await fs2.mkdir(mediaDir, { recursive: true });
49586
- const filePath = path20.join(mediaDir, filename);
49691
+ const filePath = path21.join(mediaDir, filename);
49587
49692
  await fs2.writeFile(filePath, data);
49588
49693
  return filePath;
49589
49694
  }
@@ -49768,7 +49873,7 @@ var parseFilenameFromUrl = (src) => {
49768
49873
  }
49769
49874
  };
49770
49875
  var ensureFilenameExtension = (filename, mimeType) => {
49771
- if (path20.extname(filename)) return filename;
49876
+ if (path21.extname(filename)) return filename;
49772
49877
  const ext = getExtensionForMimeType(mimeType);
49773
49878
  return ext ? `${filename}${ext}` : filename;
49774
49879
  };
@@ -49833,7 +49938,7 @@ var importRichTextImageSrcToIdentifier = async (options) => {
49833
49938
  throw new Error("Unable to assign a unique identifier for rich text image import");
49834
49939
  };
49835
49940
  var buildLocalFilename = (identifier, asset) => {
49836
- const extensionFromFilename = path20.extname(asset.filename ?? "");
49941
+ const extensionFromFilename = path21.extname(asset.filename ?? "");
49837
49942
  const extension = extensionFromFilename || getExtensionForMimeType(asset.mimeType) || "";
49838
49943
  return extension ? `${identifier}${extension}` : identifier;
49839
49944
  };
@@ -50679,11 +50784,11 @@ async function syncLocalMediaForPull(options) {
50679
50784
  continue;
50680
50785
  }
50681
50786
  const localFilename = buildLocalFilename(value.identifier, resolvedAsset);
50682
- const localFilePath = path20.join(contentDir, "media", localFilename);
50787
+ const localFilePath = path21.join(contentDir, "media", localFilename);
50683
50788
  const existingEntry = manifest.assets[value.identifier];
50684
50789
  const previousFilename = existingEntry?.filename;
50685
50790
  if (previousFilename && previousFilename !== localFilename) {
50686
- const previousPath = path20.join(contentDir, "media", previousFilename);
50791
+ const previousPath = path21.join(contentDir, "media", previousFilename);
50687
50792
  if (await localMediaFileExists(previousPath)) {
50688
50793
  await fs2.unlink(previousPath).catch(() => {
50689
50794
  });
@@ -50771,10 +50876,10 @@ function itemSegment(key) {
50771
50876
  function collectSortedKeys(local, remote) {
50772
50877
  return Array.from(/* @__PURE__ */ new Set([...Object.keys(remote), ...Object.keys(local)])).sort((a, b) => a.localeCompare(b));
50773
50878
  }
50774
- function arrayIdentityMap(items, path32, identifyArrayItem) {
50879
+ function arrayIdentityMap(items, path33, identifyArrayItem) {
50775
50880
  const result = /* @__PURE__ */ new Map();
50776
50881
  for (let index = 0; index < items.length; index++) {
50777
- const key = identifyArrayItem({ path: path32, item: items[index], index });
50882
+ const key = identifyArrayItem({ path: path33, item: items[index], index });
50778
50883
  if (!key || result.has(key)) return null;
50779
50884
  result.set(key, { item: items[index], index });
50780
50885
  }
@@ -50800,8 +50905,8 @@ function isSensitivePropertyKey(key) {
50800
50905
  const normalized = key.replace(/([a-z0-9])([A-Z])/g, "$1_$2").toLowerCase();
50801
50906
  return /(^|[_-])(secret|token|password|credential|api_key|webhook_secret|mgmt_api_key|management_api_key)s?($|[_-])/.test(normalized);
50802
50907
  }
50803
- function hasSensitivePropertyPath(path32) {
50804
- return path32.some((segment) => segment.type === "property" && isSensitivePropertyKey(segment.key));
50908
+ function hasSensitivePropertyPath(path33) {
50909
+ return path33.some((segment) => segment.type === "property" && isSensitivePropertyKey(segment.key));
50805
50910
  }
50806
50911
  function sameMultiset(left, right) {
50807
50912
  if (left.length !== right.length) return false;
@@ -50819,19 +50924,19 @@ function sameMultiset(left, right) {
50819
50924
  }
50820
50925
  return counts.size === 0;
50821
50926
  }
50822
- function diffValues(local, remote, path32, options) {
50927
+ function diffValues(local, remote, path33, options) {
50823
50928
  const normalizedLocal = normalizeComparable(local);
50824
50929
  const normalizedRemote = normalizeComparable(remote);
50825
50930
  if (equal2(normalizedLocal, normalizedRemote)) return [];
50826
50931
  if (Array.isArray(normalizedLocal) && Array.isArray(normalizedRemote)) {
50827
- return diffArrays(normalizedLocal, normalizedRemote, path32, options);
50932
+ return diffArrays(normalizedLocal, normalizedRemote, path33, options);
50828
50933
  }
50829
50934
  if (isRecord19(normalizedLocal) && isRecord19(normalizedRemote)) {
50830
50935
  const diffs = [];
50831
50936
  for (const key of collectSortedKeys(normalizedLocal, normalizedRemote)) {
50832
50937
  const localHasKey = Object.prototype.hasOwnProperty.call(normalizedLocal, key);
50833
50938
  const remoteHasKey = Object.prototype.hasOwnProperty.call(normalizedRemote, key);
50834
- const nextPath = [...path32, propertySegment(key)];
50939
+ const nextPath = [...path33, propertySegment(key)];
50835
50940
  if (!remoteHasKey && localHasKey) {
50836
50941
  diffs.push({ kind: "added", path: nextPath, before: void 0, after: normalizedLocal[key] });
50837
50942
  continue;
@@ -50844,25 +50949,25 @@ function diffValues(local, remote, path32, options) {
50844
50949
  }
50845
50950
  return diffs;
50846
50951
  }
50847
- return [{ kind: "changed", path: path32, before: normalizedRemote, after: normalizedLocal }];
50952
+ return [{ kind: "changed", path: path33, before: normalizedRemote, after: normalizedLocal }];
50848
50953
  }
50849
- function diffArrays(local, remote, path32, options) {
50954
+ function diffArrays(local, remote, path33, options) {
50850
50955
  const identifyArrayItem = options.identifyArrayItem;
50851
50956
  if (identifyArrayItem) {
50852
- const localById = arrayIdentityMap(local, path32, identifyArrayItem);
50853
- const remoteById = arrayIdentityMap(remote, path32, identifyArrayItem);
50957
+ const localById = arrayIdentityMap(local, path33, identifyArrayItem);
50958
+ const remoteById = arrayIdentityMap(remote, path33, identifyArrayItem);
50854
50959
  if (localById && remoteById) {
50855
50960
  const diffs = [];
50856
50961
  const localOrder = Array.from(localById.keys());
50857
50962
  const remoteOrder = Array.from(remoteById.keys());
50858
50963
  if (localOrder.length === remoteOrder.length && localOrder.every((key) => remoteById.has(key)) && !equal2(localOrder, remoteOrder)) {
50859
- diffs.push({ kind: "list_reordered", path: path32, before: remoteOrder, after: localOrder });
50964
+ diffs.push({ kind: "list_reordered", path: path33, before: remoteOrder, after: localOrder });
50860
50965
  }
50861
50966
  const ids = Array.from(/* @__PURE__ */ new Set([...remoteOrder, ...localOrder])).sort((a, b) => a.localeCompare(b));
50862
50967
  for (const id of ids) {
50863
50968
  const localItem = localById.get(id);
50864
50969
  const remoteItem = remoteById.get(id);
50865
- const nextPath = [...path32, itemSegment(id)];
50970
+ const nextPath = [...path33, itemSegment(id)];
50866
50971
  if (!remoteItem && localItem) {
50867
50972
  diffs.push({ kind: "added", path: nextPath, before: void 0, after: localItem.item });
50868
50973
  continue;
@@ -50879,24 +50984,24 @@ function diffArrays(local, remote, path32, options) {
50879
50984
  }
50880
50985
  }
50881
50986
  if (sameMultiset(local, remote)) {
50882
- return [{ kind: "list_reordered", path: path32, before: remote, after: local }];
50987
+ return [{ kind: "list_reordered", path: path33, before: remote, after: local }];
50883
50988
  }
50884
50989
  if (local.length === remote.length) {
50885
50990
  const diffs = [];
50886
50991
  for (let index = 0; index < local.length; index++) {
50887
- diffs.push(...diffValues(local[index], remote[index], [...path32, indexSegment(index)], options));
50992
+ diffs.push(...diffValues(local[index], remote[index], [...path33, indexSegment(index)], options));
50888
50993
  }
50889
- return diffs.length > 0 ? diffs : [{ kind: "changed", path: path32, before: remote, after: local }];
50994
+ return diffs.length > 0 ? diffs : [{ kind: "changed", path: path33, before: remote, after: local }];
50890
50995
  }
50891
- return [{ kind: "changed", path: path32, before: remote, after: local }];
50996
+ return [{ kind: "changed", path: path33, before: remote, after: local }];
50892
50997
  }
50893
50998
  function buildFieldDiffs(local, remote, options = {}) {
50894
50999
  return diffValues(local, remote, [], options);
50895
51000
  }
50896
- function formatFieldPath2(path32) {
50897
- if (path32.length === 0) return "(root)";
51001
+ function formatFieldPath2(path33) {
51002
+ if (path33.length === 0) return "(root)";
50898
51003
  let result = "";
50899
- for (const segment of path32) {
51004
+ for (const segment of path33) {
50900
51005
  switch (segment.type) {
50901
51006
  case "property":
50902
51007
  result += result ? `.${segment.key}` : segment.key;
@@ -50971,11 +51076,11 @@ function findChangedFields(local, remote, prefix = "") {
50971
51076
  const changes = [];
50972
51077
  const allKeys = /* @__PURE__ */ new Set([...Object.keys(local), ...Object.keys(remote)]);
50973
51078
  for (const key of allKeys) {
50974
- const path32 = prefix ? `${prefix}.${key}` : key;
51079
+ const path33 = prefix ? `${prefix}.${key}` : key;
50975
51080
  const localVal = local[key];
50976
51081
  const remoteVal = remote[key];
50977
51082
  if (!equal2(localVal, remoteVal)) {
50978
- changes.push(path32);
51083
+ changes.push(path33);
50979
51084
  }
50980
51085
  }
50981
51086
  return changes;
@@ -52556,10 +52661,10 @@ function stripCanonicalEventEntriesFromPulledContent(content) {
52556
52661
  };
52557
52662
  }
52558
52663
  async function findLegacyEventEntryFiles(contentDir) {
52559
- const eventEntriesDir = path20.join(contentDir, "entries", CANONICAL_EVENT_ENTRY_TYPE);
52664
+ const eventEntriesDir = path21.join(contentDir, "entries", CANONICAL_EVENT_ENTRY_TYPE);
52560
52665
  try {
52561
52666
  const items = await fs2.readdir(eventEntriesDir, { withFileTypes: true });
52562
- return items.filter((item) => item.isFile() && item.name.endsWith(".json")).map((item) => path20.join(eventEntriesDir, item.name)).sort();
52667
+ return items.filter((item) => item.isFile() && item.name.endsWith(".json")).map((item) => path21.join(eventEntriesDir, item.name)).sort();
52563
52668
  } catch (error) {
52564
52669
  if (error.code === "ENOENT") {
52565
52670
  return [];
@@ -52569,7 +52674,7 @@ async function findLegacyEventEntryFiles(contentDir) {
52569
52674
  }
52570
52675
  function formatLegacyEventEntryWarning(files) {
52571
52676
  return {
52572
- files: files.map((file) => path20.relative(process.cwd(), file)),
52677
+ files: files.map((file) => path21.relative(process.cwd(), file)),
52573
52678
  suggestion: `Generic event entry files are ignored by broad sync. Run "${EVENT_MIGRATION_COMMAND}" to fold legacy event copy into content/events/*.json.`
52574
52679
  };
52575
52680
  }
@@ -53155,7 +53260,7 @@ Media Sync:
53155
53260
  });
53156
53261
  return;
53157
53262
  }
53158
- const contentDir = path20.resolve(options.output ?? "./content");
53263
+ const contentDir = path21.resolve(options.output ?? "./content");
53159
53264
  const envLabel = isRemote ? "REMOTE" : "LOCAL";
53160
53265
  const environment = loadEnvironment(isRemote);
53161
53266
  const metadataTarget = metadataTargetFromEnvironment(isRemote ? "remote" : "local", environment);
@@ -53226,7 +53331,7 @@ Media Sync:
53226
53331
  process.exitCode = 0;
53227
53332
  return;
53228
53333
  }
53229
- const fileRel = path20.join(path20.basename(contentDir), "themes", `${themeName}.json`);
53334
+ const fileRel = path21.join(path21.basename(contentDir), "themes", `${themeName}.json`);
53230
53335
  if (resolvedJsonDiffMode) {
53231
53336
  output.json({
53232
53337
  mode: resolvedJsonDiffMode,
@@ -53263,7 +53368,7 @@ Media Sync:
53263
53368
  process.exitCode = 0;
53264
53369
  return;
53265
53370
  }
53266
- const fileRel = path20.join(path20.basename(contentDir), "footer.json");
53371
+ const fileRel = path21.join(path21.basename(contentDir), "footer.json");
53267
53372
  if (resolvedJsonDiffMode) {
53268
53373
  output.json({
53269
53374
  mode: resolvedJsonDiffMode,
@@ -53470,7 +53575,7 @@ Media Sync:
53470
53575
  if (options.withTheme) {
53471
53576
  const themeName = options.name ?? "current";
53472
53577
  output.info(
53473
- `[DRY RUN] Would also pull theme to ${path20.join(path20.basename(contentDir), "themes", `${themeName}.json`)}`
53578
+ `[DRY RUN] Would also pull theme to ${path21.join(path21.basename(contentDir), "themes", `${themeName}.json`)}`
53474
53579
  );
53475
53580
  }
53476
53581
  const result = await pullAllContentWithCanonicalEntryPolicy(client, output);
@@ -53611,7 +53716,7 @@ Media Sync:
53611
53716
  const response = await prompts({
53612
53717
  type: "confirm",
53613
53718
  name: "overwrite",
53614
- message: `Content directory '${path20.basename(contentDir)}' already exists. Overwrite?`,
53719
+ message: `Content directory '${path21.basename(contentDir)}' already exists. Overwrite?`,
53615
53720
  initial: false
53616
53721
  });
53617
53722
  if (!response.overwrite) {
@@ -54346,8 +54451,8 @@ function normalizeLocalContentShape(content) {
54346
54451
  var identifierRegex = /^[a-z0-9][a-z0-9-]*$/;
54347
54452
  var currencyRegex = /^[A-Z]{3}$/;
54348
54453
  var isoDateTimeRegex = /^\d{4}-\d{2}-\d{2}T.+/;
54349
- function issue2(path32, message) {
54350
- return { path: path32, message };
54454
+ function issue2(path33, message) {
54455
+ return { path: path33, message };
54351
54456
  }
54352
54457
  function isRecord20(value) {
54353
54458
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -54364,27 +54469,27 @@ function isWholeMinuteIsoDateTime(value) {
54364
54469
  return Number.isFinite(epochMs) && epochMs % 6e4 === 0;
54365
54470
  }
54366
54471
  function validateTicketType(raw, index, currency) {
54367
- const path32 = ["ticketTypes", String(index)];
54368
- if (!isRecord20(raw)) return [issue2(path32, "Ticket type must be an object")];
54472
+ const path33 = ["ticketTypes", String(index)];
54473
+ if (!isRecord20(raw)) return [issue2(path33, "Ticket type must be an object")];
54369
54474
  const issues = [];
54370
54475
  const identifier = raw.identifier;
54371
54476
  if (typeof identifier !== "string" || !identifierRegex.test(identifier)) {
54372
54477
  issues.push(
54373
54478
  issue2(
54374
- [...path32, "identifier"],
54479
+ [...path33, "identifier"],
54375
54480
  "Ticket identifier must use lowercase letters, numbers, and hyphens"
54376
54481
  )
54377
54482
  );
54378
54483
  }
54379
54484
  const name = raw.name;
54380
54485
  if (typeof name !== "string" || name.trim().length === 0) {
54381
- issues.push(issue2([...path32, "name"], "Ticket name is required"));
54486
+ issues.push(issue2([...path33, "name"], "Ticket name is required"));
54382
54487
  }
54383
54488
  const priceAmount = raw.priceAmount;
54384
54489
  if (!isWholeNumber(priceAmount) || priceAmount < 0) {
54385
54490
  issues.push(
54386
54491
  issue2(
54387
- [...path32, "priceAmount"],
54492
+ [...path33, "priceAmount"],
54388
54493
  "Ticket priceAmount must be a non-negative integer"
54389
54494
  )
54390
54495
  );
@@ -54393,7 +54498,7 @@ function validateTicketType(raw, index, currency) {
54393
54498
  if (priceCurrency !== void 0 && priceCurrency !== null && priceCurrency !== currency) {
54394
54499
  issues.push(
54395
54500
  issue2(
54396
- [...path32, "priceCurrency"],
54501
+ [...path33, "priceCurrency"],
54397
54502
  "Ticket priceCurrency must match pricing.priceCurrency"
54398
54503
  )
54399
54504
  );
@@ -54402,7 +54507,7 @@ function validateTicketType(raw, index, currency) {
54402
54507
  if (sortOrder !== void 0 && (!isWholeNumber(sortOrder) || sortOrder < 0)) {
54403
54508
  issues.push(
54404
54509
  issue2(
54405
- [...path32, "sortOrder"],
54510
+ [...path33, "sortOrder"],
54406
54511
  "Ticket sortOrder must be a non-negative integer"
54407
54512
  )
54408
54513
  );
@@ -54411,7 +54516,7 @@ function validateTicketType(raw, index, currency) {
54411
54516
  if (capacityLimit2 !== void 0 && capacityLimit2 !== null && (!isWholeNumber(capacityLimit2) || capacityLimit2 < 1)) {
54412
54517
  issues.push(
54413
54518
  issue2(
54414
- [...path32, "capacityLimit"],
54519
+ [...path33, "capacityLimit"],
54415
54520
  "Ticket capacityLimit must be a positive integer"
54416
54521
  )
54417
54522
  );
@@ -54420,7 +54525,7 @@ function validateTicketType(raw, index, currency) {
54420
54525
  if (attendanceScope !== void 0 && attendanceScope !== "in_person" && attendanceScope !== "online" && attendanceScope !== "both") {
54421
54526
  issues.push(
54422
54527
  issue2(
54423
- [...path32, "attendanceScope"],
54528
+ [...path33, "attendanceScope"],
54424
54529
  "Ticket attendanceScope must be in_person, online, or both"
54425
54530
  )
54426
54531
  );
@@ -54429,7 +54534,7 @@ function validateTicketType(raw, index, currency) {
54429
54534
  if (saleStartsAt !== void 0 && saleStartsAt !== null && (typeof saleStartsAt !== "string" || !isWholeMinuteIsoDateTime(saleStartsAt))) {
54430
54535
  issues.push(
54431
54536
  issue2(
54432
- [...path32, "saleStartsAt"],
54537
+ [...path33, "saleStartsAt"],
54433
54538
  "Ticket saleStartsAt must be an ISO datetime aligned to a whole minute"
54434
54539
  )
54435
54540
  );
@@ -54438,7 +54543,7 @@ function validateTicketType(raw, index, currency) {
54438
54543
  if (saleEndsAt !== void 0 && saleEndsAt !== null && (typeof saleEndsAt !== "string" || !isWholeMinuteIsoDateTime(saleEndsAt))) {
54439
54544
  issues.push(
54440
54545
  issue2(
54441
- [...path32, "saleEndsAt"],
54546
+ [...path33, "saleEndsAt"],
54442
54547
  "Ticket saleEndsAt must be an ISO datetime aligned to a whole minute"
54443
54548
  )
54444
54549
  );
@@ -54446,7 +54551,7 @@ function validateTicketType(raw, index, currency) {
54446
54551
  if (typeof saleStartsAt === "string" && typeof saleEndsAt === "string" && Date.parse(saleEndsAt) <= Date.parse(saleStartsAt)) {
54447
54552
  issues.push(
54448
54553
  issue2(
54449
- [...path32, "saleEndsAt"],
54554
+ [...path33, "saleEndsAt"],
54450
54555
  "Ticket saleEndsAt must be after saleStartsAt"
54451
54556
  )
54452
54557
  );
@@ -54455,7 +54560,7 @@ function validateTicketType(raw, index, currency) {
54455
54560
  if (cmsTicketTypeId !== void 0 && cmsTicketTypeId !== null && (typeof cmsTicketTypeId !== "string" || cmsTicketTypeId.length === 0)) {
54456
54561
  issues.push(
54457
54562
  issue2(
54458
- [...path32, "cmsTicketTypeId"],
54563
+ [...path33, "cmsTicketTypeId"],
54459
54564
  "Ticket cmsTicketTypeId must be a non-empty string"
54460
54565
  )
54461
54566
  );
@@ -54639,8 +54744,8 @@ var supportedKinds = /* @__PURE__ */ new Set([
54639
54744
  "deferred_manual",
54640
54745
  "flexible_balance"
54641
54746
  ]);
54642
- function issue3(path32, message) {
54643
- return { path: path32, message };
54747
+ function issue3(path33, message) {
54748
+ return { path: path33, message };
54644
54749
  }
54645
54750
  function isRecord21(value) {
54646
54751
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -54657,15 +54762,15 @@ function isDepositRefundability(value) {
54657
54762
  function isSupportedOptionKind(value) {
54658
54763
  return typeof value === "string" && supportedKinds.has(value);
54659
54764
  }
54660
- function validateFlexibleBalanceDueDateRule(raw, path32) {
54765
+ function validateFlexibleBalanceDueDateRule(raw, path33) {
54661
54766
  if (!isRecord21(raw)) {
54662
- return [issue3(path32, "Flexible balance dueDateRule must be an object")];
54767
+ return [issue3(path33, "Flexible balance dueDateRule must be an object")];
54663
54768
  }
54664
54769
  if (raw.kind === "relative_to_start_date") {
54665
54770
  if (!isPositiveWholeNumber(raw.daysBeforeStart)) {
54666
54771
  return [
54667
54772
  issue3(
54668
- [...path32, "daysBeforeStart"],
54773
+ [...path33, "daysBeforeStart"],
54669
54774
  "Flexible balance daysBeforeStart must be a positive integer"
54670
54775
  )
54671
54776
  ];
@@ -54679,7 +54784,7 @@ function validateFlexibleBalanceDueDateRule(raw, path32) {
54679
54784
  if (typeof raw.dueAt !== "string" || !Number.isFinite(Date.parse(raw.dueAt))) {
54680
54785
  return [
54681
54786
  issue3(
54682
- [...path32, "dueAt"],
54787
+ [...path33, "dueAt"],
54683
54788
  "Flexible balance fixed dueAt must be an ISO datetime"
54684
54789
  )
54685
54790
  ];
@@ -54691,14 +54796,14 @@ function validateFlexibleBalanceDueDateRule(raw, path32) {
54691
54796
  }
54692
54797
  return [
54693
54798
  issue3(
54694
- [...path32, "kind"],
54799
+ [...path33, "kind"],
54695
54800
  "Flexible balance dueDateRule kind must be relative_to_start_date or fixed_calendar_date"
54696
54801
  )
54697
54802
  ];
54698
54803
  }
54699
- function validateFlexibleBalanceConfig(raw, path32) {
54804
+ function validateFlexibleBalanceConfig(raw, path33) {
54700
54805
  if (!isRecord21(raw)) {
54701
- return [issue3(path32, "Flexible balance config must be an object")];
54806
+ return [issue3(path33, "Flexible balance config must be an object")];
54702
54807
  }
54703
54808
  const issues = [];
54704
54809
  const upfrontAmountCents = raw.upfrontAmountCents;
@@ -54708,7 +54813,7 @@ function validateFlexibleBalanceConfig(raw, path32) {
54708
54813
  if (!isWholeNumber2(upfrontAmountCents) || upfrontAmountCents < 0) {
54709
54814
  issues.push(
54710
54815
  issue3(
54711
- [...path32, "upfrontAmountCents"],
54816
+ [...path33, "upfrontAmountCents"],
54712
54817
  "Flexible balance upfrontAmountCents must be a non-negative integer"
54713
54818
  )
54714
54819
  );
@@ -54718,7 +54823,7 @@ function validateFlexibleBalanceConfig(raw, path32) {
54718
54823
  if (!isDepositRefundability(depositRefundability)) {
54719
54824
  issues.push(
54720
54825
  issue3(
54721
- [...path32, "depositRefundability"],
54826
+ [...path33, "depositRefundability"],
54722
54827
  "Flexible balance depositRefundability must be refundable or non_refundable"
54723
54828
  )
54724
54829
  );
@@ -54727,7 +54832,7 @@ function validateFlexibleBalanceConfig(raw, path32) {
54727
54832
  }
54728
54833
  const dueDateRule = validateFlexibleBalanceDueDateRule(
54729
54834
  raw.dueDateRule,
54730
- [...path32, "dueDateRule"]
54835
+ [...path33, "dueDateRule"]
54731
54836
  );
54732
54837
  if (Array.isArray(dueDateRule)) {
54733
54838
  issues.push(...dueDateRule);
@@ -54742,14 +54847,14 @@ function validateFlexibleBalanceConfig(raw, path32) {
54742
54847
  };
54743
54848
  }
54744
54849
  function validateCollectionOption(raw, index) {
54745
- const path32 = ["allowedOptions", String(index)];
54850
+ const path33 = ["allowedOptions", String(index)];
54746
54851
  if (!isRecord21(raw)) {
54747
- return [issue3(path32, "Payment option must be an object")];
54852
+ return [issue3(path33, "Payment option must be an object")];
54748
54853
  }
54749
54854
  if (raw.kind === "instalment_plan") {
54750
54855
  return [
54751
54856
  issue3(
54752
- [...path32, "kind"],
54857
+ [...path33, "kind"],
54753
54858
  "Event instalment plans are not supported yet. Use upfront, deferred_manual, or flexible_balance."
54754
54859
  )
54755
54860
  ];
@@ -54757,7 +54862,7 @@ function validateCollectionOption(raw, index) {
54757
54862
  if (!isSupportedOptionKind(raw.kind)) {
54758
54863
  return [
54759
54864
  issue3(
54760
- [...path32, "kind"],
54865
+ [...path33, "kind"],
54761
54866
  "Payment option kind must be upfront, deferred_manual, or flexible_balance"
54762
54867
  )
54763
54868
  ];
@@ -54768,7 +54873,7 @@ function validateCollectionOption(raw, index) {
54768
54873
  return { kind: raw.kind };
54769
54874
  case "flexible_balance": {
54770
54875
  const config2 = validateFlexibleBalanceConfig(raw.config, [
54771
- ...path32,
54876
+ ...path33,
54772
54877
  "config"
54773
54878
  ]);
54774
54879
  if (Array.isArray(config2)) {
@@ -55502,7 +55607,7 @@ function groupStaleItems(staleItems) {
55502
55607
  ];
55503
55608
  }
55504
55609
  async function writeStaleEntries(contentDir, remoteContent, contentType, items, output, options) {
55505
- const entriesDir = path20.join(contentDir, "entries", contentType);
55610
+ const entriesDir = path21.join(contentDir, "entries", contentType);
55506
55611
  await ensureDir(entriesDir);
55507
55612
  const remoteEntries = remoteContent.entries[contentType] ?? [];
55508
55613
  const staleIds = new Set(items.map((i) => i.identifier));
@@ -55510,7 +55615,7 @@ async function writeStaleEntries(contentDir, remoteContent, contentType, items,
55510
55615
  if (!staleIds.has(remoteEntry.identifier)) continue;
55511
55616
  const entryData = mapEntryForOutput(remoteEntry);
55512
55617
  stripEnvSpecificMediaFieldsInPlace(entryData);
55513
- const filePath = path20.join(entriesDir, `${remoteEntry.identifier}.json`);
55618
+ const filePath = path21.join(entriesDir, `${remoteEntry.identifier}.json`);
55514
55619
  await writeJsonFile(filePath, entryData);
55515
55620
  output.info(` Refreshed entry: ${contentType}/${remoteEntry.identifier}`);
55516
55621
  }
@@ -55535,13 +55640,13 @@ async function writeStaleEntries(contentDir, remoteContent, contentType, items,
55535
55640
  }
55536
55641
  }
55537
55642
  async function writeStalePages(contentDir, remoteContent, items, output, options) {
55538
- const pagesDir = path20.join(contentDir, "pages");
55643
+ const pagesDir = path21.join(contentDir, "pages");
55539
55644
  await ensureDir(pagesDir);
55540
55645
  const staleIds = new Set(items.map((i) => i.identifier));
55541
55646
  for (const remotePage of remoteContent.pages) {
55542
55647
  if (!staleIds.has(remotePage.identifier)) continue;
55543
55648
  stripEnvSpecificMediaFieldsInPlace(remotePage);
55544
- const filePath = path20.join(pagesDir, `${remotePage.identifier}.json`);
55649
+ const filePath = path21.join(pagesDir, `${remotePage.identifier}.json`);
55545
55650
  await writeJsonFile(filePath, remotePage);
55546
55651
  output.info(` Refreshed page: ${remotePage.identifier}`);
55547
55652
  }
@@ -57703,13 +57808,13 @@ function collectOfferingRequires(input, intervals, intervalPath) {
57703
57808
  function optionalRef(ref, field) {
57704
57809
  return ref !== void 0 && ref.length > 0 ? [{ ref, field }] : [];
57705
57810
  }
57706
- function collectVenueRefsFromIntervals(intervals, path32) {
57707
- return intervals.flatMap((interval, index) => optionalRef(interval.venueRef, `${path32}[${index}].venueRef`));
57811
+ function collectVenueRefsFromIntervals(intervals, path33) {
57812
+ return intervals.flatMap((interval, index) => optionalRef(interval.venueRef, `${path33}[${index}].venueRef`));
57708
57813
  }
57709
- function collectNavigationRefs(items, path32) {
57814
+ function collectNavigationRefs(items, path33) {
57710
57815
  return items.flatMap((item, index) => {
57711
57816
  if (!isRecord23(item)) return [];
57712
- const itemPath = `${path32}[${index}]`;
57817
+ const itemPath = `${path33}[${index}]`;
57713
57818
  const refs = [];
57714
57819
  if (typeof item.pageRef === "string") {
57715
57820
  refs.push({ ref: item.pageRef, field: `${itemPath}.pageRef` });
@@ -57723,26 +57828,26 @@ function collectNavigationRefs(items, path32) {
57723
57828
  return refs;
57724
57829
  });
57725
57830
  }
57726
- function collectBlockRefs(blocks, path32) {
57831
+ function collectBlockRefs(blocks, path33) {
57727
57832
  return blocks.flatMap((block, index) => {
57728
57833
  if (!isRecord23(block)) return [];
57729
- const blockPath = `${path32}[${index}]`;
57834
+ const blockPath = `${path33}[${index}]`;
57730
57835
  return [
57731
57836
  ...collectNestedRefs(block.props, `${blockPath}.props`),
57732
57837
  ...collectNestedRefs(block.children, `${blockPath}.children`)
57733
57838
  ];
57734
57839
  });
57735
57840
  }
57736
- function collectNestedRefs(value, path32) {
57841
+ function collectNestedRefs(value, path33) {
57737
57842
  if (typeof value === "string") {
57738
57843
  const parsed = parseResourceRef(value);
57739
- return parsed.ok ? [{ ref: value, field: path32 }] : [];
57844
+ return parsed.ok ? [{ ref: value, field: path33 }] : [];
57740
57845
  }
57741
57846
  if (Array.isArray(value)) {
57742
- return value.flatMap((item, index) => collectNestedRefs(item, `${path32}[${index}]`));
57847
+ return value.flatMap((item, index) => collectNestedRefs(item, `${path33}[${index}]`));
57743
57848
  }
57744
57849
  if (!isRecord23(value)) return [];
57745
- return Object.entries(value).flatMap(([key, child]) => collectNestedRefs(child, `${path32}.${key}`));
57850
+ return Object.entries(value).flatMap(([key, child]) => collectNestedRefs(child, `${path33}.${key}`));
57746
57851
  }
57747
57852
 
57748
57853
  // ../site-commands/src/staticExecutionGaps.ts
@@ -58021,8 +58126,8 @@ function invalidPayloadError(input, issue5) {
58021
58126
  message: `${field}: ${issue5.message}`
58022
58127
  };
58023
58128
  }
58024
- function commandIndexForIssuePath(path32) {
58025
- return path32[0] === "commands" && typeof path32[1] === "number" ? path32[1] : -1;
58129
+ function commandIndexForIssuePath(path33) {
58130
+ return path33[0] === "commands" && typeof path33[1] === "number" ? path33[1] : -1;
58026
58131
  }
58027
58132
  function commandTypeForIssue(input, commandIndex) {
58028
58133
  if (!isRecord23(input) || !isUnknownArray3(input.commands)) return null;
@@ -58032,9 +58137,9 @@ function commandTypeForIssue(input, commandIndex) {
58032
58137
  function isUnknownArray3(value) {
58033
58138
  return Array.isArray(value);
58034
58139
  }
58035
- function formatIssuePath(path32) {
58036
- if (path32.length === 0) return "<root>";
58037
- return path32.reduce((formatted, segment) => {
58140
+ function formatIssuePath(path33) {
58141
+ if (path33.length === 0) return "<root>";
58142
+ return path33.reduce((formatted, segment) => {
58038
58143
  if (typeof segment === "number") return `${formatted}[${segment}]`;
58039
58144
  if (formatted.length === 0) return String(segment);
58040
58145
  return `${formatted}.${String(segment)}`;
@@ -58763,8 +58868,8 @@ init_src();
58763
58868
  var timeRegex = /^([01]\d|2[0-3]):([0-5]\d)(:([0-5]\d))?$/;
58764
58869
  var explicitOffsetDateTimeRegex = /^(\d{4})-(\d{2})-(\d{2})T([01]\d|2[0-3]):([0-5]\d)(?::([0-5]\d))?(\.\d{1,3})?(Z|[+-]([01]\d|2[0-3]):[0-5]\d)$/;
58765
58870
  var localDateTimeRegex = /^(\d{4})-(\d{2})-(\d{2})T([01]\d|2[0-3]):([0-5]\d)(?::([0-5]\d))?(\.\d{1,3})?$/;
58766
- function issue4(path32, message) {
58767
- return { path: path32, message };
58871
+ function issue4(path33, message) {
58872
+ return { path: path33, message };
58768
58873
  }
58769
58874
  function isValidDateParts(year, month, day) {
58770
58875
  const date = new Date(Date.UTC(year, month - 1, day));
@@ -61647,7 +61752,7 @@ async function executeFooterPush(input) {
61647
61752
  );
61648
61753
  }
61649
61754
  const cliConfig = await loadCliConfigForEnv(target);
61650
- const contentDir = path20.resolve(options.contentDir ?? cliConfig.contentDir);
61755
+ const contentDir = path21.resolve(options.contentDir ?? cliConfig.contentDir);
61651
61756
  if (!await contentDirExists(contentDir)) {
61652
61757
  return output.error(`Content directory not found: ${contentDir}`, {
61653
61758
  suggestion: 'Run "riverbankcms pull footer" first to download footer'
@@ -62520,7 +62625,7 @@ function findDuplicateLocalEventIdentifiers(events) {
62520
62625
  return [...filePathsByIdentifier.entries()].filter(([, filePaths]) => filePaths.length > 1).map(([identifier, filePaths]) => ({ identifier, filePaths }));
62521
62626
  }
62522
62627
  function formatDuplicateEventFilePath(contentDir, filePath) {
62523
- return path20.relative(contentDir, filePath) || filePath;
62628
+ return path21.relative(contentDir, filePath) || filePath;
62524
62629
  }
62525
62630
  function normalizeLocalPath(value) {
62526
62631
  const [withoutHash] = value.split("#");
@@ -62820,7 +62925,7 @@ function firstNestedContainerChange(localChanges, remoteChanges) {
62820
62925
  }
62821
62926
  function firstSameFieldConflictPath(localChanges, remoteChanges) {
62822
62927
  const remotePaths = new Set(remoteChanges.keys());
62823
- return [...localChanges.keys()].filter((path32) => remotePaths.has(path32)).sort()[0] ?? null;
62928
+ return [...localChanges.keys()].filter((path33) => remotePaths.has(path33)).sort()[0] ?? null;
62824
62929
  }
62825
62930
  function scalarMergeChanges(changes, label) {
62826
62931
  return [...changes.values()].map((change) => {
@@ -62836,24 +62941,24 @@ function mergeValueKind(value) {
62836
62941
  if (typeof value === "object") return "object";
62837
62942
  return "scalar";
62838
62943
  }
62839
- function mergeChange(path32, value, containerKind) {
62944
+ function mergeChange(path33, value, containerKind) {
62840
62945
  switch (containerKind) {
62841
62946
  case "array":
62842
- if (Array.isArray(value)) return { path: path32, value, containerKind };
62947
+ if (Array.isArray(value)) return { path: path33, value, containerKind };
62843
62948
  break;
62844
62949
  case "object":
62845
62950
  if (value && typeof value === "object" && !Array.isArray(value)) {
62846
- return { path: path32, value, containerKind };
62951
+ return { path: path33, value, containerKind };
62847
62952
  }
62848
62953
  break;
62849
62954
  case "null":
62850
- if (value === null || value === void 0) return { path: path32, value, containerKind };
62955
+ if (value === null || value === void 0) return { path: path33, value, containerKind };
62851
62956
  break;
62852
62957
  case "scalar":
62853
- if (isScalarMergeChangeValue(value)) return { path: path32, value, containerKind };
62958
+ if (isScalarMergeChangeValue(value)) return { path: path33, value, containerKind };
62854
62959
  break;
62855
62960
  }
62856
- throw new Error(`Invalid merge change at ${path32}.`);
62961
+ throw new Error(`Invalid merge change at ${path33}.`);
62857
62962
  }
62858
62963
  function isScalarMergeChangeValue(value) {
62859
62964
  return value === void 0 || value === null || ["boolean", "number", "string"].includes(typeof value);
@@ -63067,44 +63172,73 @@ function setPath(target, pathParts, value) {
63067
63172
  }
63068
63173
  setPath(target[head], rest, value);
63069
63174
  }
63070
- function expectStringValue(path32, value) {
63175
+ function expectStringValue(path33, value) {
63071
63176
  if (typeof value === "string") return value;
63072
- throw new Error(`Entry merge expected ${path32} to be a string.`);
63177
+ throw new Error(`Entry merge expected ${path33} to be a string.`);
63073
63178
  }
63074
- function expectBooleanValue(path32, value) {
63179
+ function expectBooleanValue(path33, value) {
63075
63180
  if (typeof value === "boolean") return value;
63076
- throw new Error(`Entry merge expected ${path32} to be a boolean.`);
63181
+ throw new Error(`Entry merge expected ${path33} to be a boolean.`);
63077
63182
  }
63078
63183
  function expectStatusValue(value) {
63079
63184
  if (value === "draft" || value === "published") return value;
63080
63185
  throw new Error("Entry merge expected status to be draft or published.");
63081
63186
  }
63082
63187
 
63188
+ // src/cli/merge-remote/sharedMergePlan.ts
63189
+ async function buildRemoteMergePlanWithConfig(config2) {
63190
+ const decisions = await Promise.all(config2.subjects().map(async (subject) => {
63191
+ const baseSnapshot = await config2.readBaseSnapshot(subject);
63192
+ return config2.planDecision({
63193
+ subject,
63194
+ base: baseSnapshot ? config2.valueFromBaseSnapshot(baseSnapshot) : null,
63195
+ local: config2.localValue(subject),
63196
+ remote: config2.remoteValue(subject)
63197
+ });
63198
+ }));
63199
+ return {
63200
+ decisions,
63201
+ summary: config2.summarize(decisions)
63202
+ };
63203
+ }
63204
+ function summarizeMergeDecisions(decisions, initialSummary, summaryKeyByDecisionKind) {
63205
+ const summary = { ...initialSummary };
63206
+ for (const decision of decisions) {
63207
+ const summaryKey = summaryKeyByDecisionKind[decision.kind];
63208
+ incrementSummaryField(summary, summaryKey);
63209
+ }
63210
+ return summary;
63211
+ }
63212
+ function incrementSummaryField(summary, summaryKey) {
63213
+ const currentValue = summary[summaryKey];
63214
+ if (typeof currentValue !== "number") {
63215
+ throw new Error(`Merge summary field ${String(summaryKey)} is not numeric.`);
63216
+ }
63217
+ summary[summaryKey] = currentValue + 1;
63218
+ }
63219
+
63083
63220
  // src/cli/merge-remote/entryMergePlan.ts
63084
- init_src();
63085
63221
  async function buildRemoteEntryMergePlan(input) {
63086
- const subjects = subjectsForScope(input.scope, input.localEntries, input.remoteEntries);
63087
- const decisions = await Promise.all(subjects.map(async (subject) => {
63088
- const baseSnapshot = await readEntryBaseSnapshot({
63222
+ const plan = await buildRemoteMergePlanWithConfig({
63223
+ subjects: () => subjectsForScope(input.scope, input.localEntries, input.remoteEntries),
63224
+ readBaseSnapshot: (subject) => readEntryBaseSnapshot({
63089
63225
  contentDir: input.contentDir,
63090
63226
  target: input.target,
63091
63227
  subject
63092
- });
63093
- return planEntryMerge({
63094
- subject,
63095
- base: baseSnapshot?.entry ?? null,
63096
- local: localEntryForSubject(input.localEntries, subject),
63097
- remote: remoteEntryForSubject(input.remoteEntries, subject)
63098
- });
63099
- }));
63228
+ }),
63229
+ valueFromBaseSnapshot: (snapshot) => snapshot.entry,
63230
+ localValue: (subject) => localEntryForSubject(input.localEntries, subject),
63231
+ remoteValue: (subject) => remoteEntryForSubject(input.remoteEntries, subject),
63232
+ planDecision: planEntryMerge,
63233
+ summarize: summarizeEntryMergeDecisions
63234
+ });
63100
63235
  return {
63101
63236
  scope: input.scope,
63102
- decisions,
63103
- summary: summarizeEntryMergeDecisions(decisions)
63237
+ ...plan
63104
63238
  };
63105
63239
  }
63106
63240
  function summarizeEntryMergeDecisions(decisions) {
63107
- const summary = {
63241
+ return summarizeMergeDecisions(decisions, {
63108
63242
  unchanged: 0,
63109
63243
  bootstrapBase: 0,
63110
63244
  preserveRemote: 0,
@@ -63113,39 +63247,18 @@ function summarizeEntryMergeDecisions(decisions) {
63113
63247
  applyLocalDelete: 0,
63114
63248
  autoMerge: 0,
63115
63249
  conflicts: 0
63116
- };
63117
- for (const decision of decisions) {
63118
- switch (decision.kind) {
63119
- case "unchanged":
63120
- summary.unchanged++;
63121
- break;
63122
- case "bootstrap_base":
63123
- summary.bootstrapBase++;
63124
- break;
63125
- case "preserve_remote":
63126
- summary.preserveRemote++;
63127
- break;
63128
- case "apply_local_create":
63129
- summary.applyLocalCreate++;
63130
- break;
63131
- case "apply_local_update":
63132
- summary.applyLocalUpdate++;
63133
- break;
63134
- case "apply_local_delete":
63135
- summary.applyLocalDelete++;
63136
- break;
63137
- case "auto_merge":
63138
- summary.autoMerge++;
63139
- break;
63140
- case "conflict":
63141
- summary.conflicts++;
63142
- break;
63143
- default:
63144
- assertNever(decision);
63145
- }
63146
- }
63147
- return summary;
63148
- }
63250
+ }, entrySummaryKeyByDecisionKind);
63251
+ }
63252
+ var entrySummaryKeyByDecisionKind = {
63253
+ unchanged: "unchanged",
63254
+ bootstrap_base: "bootstrapBase",
63255
+ preserve_remote: "preserveRemote",
63256
+ apply_local_create: "applyLocalCreate",
63257
+ apply_local_update: "applyLocalUpdate",
63258
+ apply_local_delete: "applyLocalDelete",
63259
+ auto_merge: "autoMerge",
63260
+ conflict: "conflicts"
63261
+ };
63149
63262
  function entryMergePushScope(input) {
63150
63263
  if (input.identifier && !input.contentType) {
63151
63264
  throw new Error("Entry merge scope requires contentType when identifier is provided.");
@@ -63203,87 +63316,64 @@ function remoteEntryForSubject(entriesByType, subject) {
63203
63316
  return pulledEntryToLocalEntry(remoteEntry);
63204
63317
  }
63205
63318
 
63206
- // src/cli/merge-remote/entryMergeReport.ts
63207
- function remoteEntryMergeJsonReport(input) {
63319
+ // src/cli/merge-remote/sharedMergeReport.ts
63320
+ function remoteMergeJsonReport(input) {
63208
63321
  return {
63209
63322
  kind: "push",
63210
- scope: "entries",
63323
+ scope: input.config.scope,
63211
63324
  mergeRemote: true,
63212
63325
  dryRun: input.dryRun,
63213
- summary: input.plan.summary,
63214
- decisions: input.plan.decisions.map(decisionReport)
63326
+ summary: input.summary,
63327
+ decisions: input.decisions.map(
63328
+ (decision) => decisionReport(input.config, decision)
63329
+ )
63215
63330
  };
63216
63331
  }
63217
- function writeRemoteEntryMergeHumanReport(output, plan, options) {
63332
+ function writeRemoteMergeHumanReport(output, config2, input) {
63218
63333
  output.info(`
63219
- ${options.dryRun ? "[DRY RUN] " : ""}Remote-aware entry merge plan:`);
63220
- output.info(formatSummary(plan));
63221
- const conflicts = plan.decisions.filter((decision) => decision.kind === "conflict");
63334
+ ${input.dryRun ? "[DRY RUN] " : ""}${config2.title}`);
63335
+ output.info(config2.summaryLines(input.summary).join("\n"));
63336
+ const conflicts = input.decisions.filter(isConflictDecision);
63222
63337
  if (conflicts.length > 0) {
63223
63338
  output.info("\nConflicts:");
63224
63339
  for (const decision of conflicts) {
63225
- if (decision.kind !== "conflict") continue;
63226
63340
  output.info(
63227
- ` - ${decision.subject.contentType}/${decision.subject.identifier}: ${decision.conflict.message}`
63341
+ ` - ${config2.subjectLabel(decision.subject)}: ${decision.conflict.message}`
63228
63342
  );
63229
63343
  }
63230
63344
  }
63231
- const changes = plan.decisions.filter((decision) => decision.kind !== "unchanged" && decision.kind !== "conflict");
63345
+ const changes = input.decisions.filter((decision) => decision.kind !== "unchanged" && decision.kind !== "conflict");
63232
63346
  if (changes.length > 0) {
63233
63347
  output.info("\nDecisions:");
63234
63348
  for (const decision of changes) {
63235
- output.info(` - ${formatDecisionLine(decision)}`);
63349
+ output.info(` - ${formatDecisionLine(config2, decision)}`);
63236
63350
  }
63237
63351
  }
63238
63352
  }
63239
- function formatSummary(plan) {
63240
- const { summary } = plan;
63241
- return [
63242
- ` Local creates: ${summary.applyLocalCreate}`,
63243
- ` Local updates: ${summary.applyLocalUpdate}`,
63244
- ` Local deletes: ${summary.applyLocalDelete}`,
63245
- ` Auto-merges: ${summary.autoMerge}`,
63246
- ` Remote preserved: ${summary.preserveRemote}`,
63247
- ` Base bootstraps: ${summary.bootstrapBase}`,
63248
- ` Unchanged: ${summary.unchanged}`,
63249
- ` Conflicts: ${summary.conflicts}`
63250
- ].join("\n");
63251
- }
63252
- function formatDecisionLine(decision) {
63253
- const subject = `${decision.subject.contentType}/${decision.subject.identifier}`;
63254
- switch (decision.kind) {
63255
- case "auto_merge":
63256
- return `${subject}: auto-merge local [${decision.localFieldPaths.join(", ")}] with remote [${decision.remoteFieldPaths.join(", ")}]`;
63257
- case "conflict":
63258
- return `${subject}: conflict (${decision.conflict.code})`;
63259
- case "apply_local_create":
63260
- return `${subject}: apply local create`;
63261
- case "apply_local_update":
63262
- return `${subject}: apply local update`;
63263
- case "apply_local_delete":
63264
- return `${subject}: apply local delete`;
63265
- case "preserve_remote":
63266
- return `${subject}: preserve remote`;
63267
- case "bootstrap_base":
63268
- return `${subject}: bootstrap missing base`;
63269
- case "unchanged":
63270
- return `${subject}: unchanged`;
63353
+ function formatDecisionLine(config2, decision) {
63354
+ const subject = config2.subjectLabel(decision.subject);
63355
+ if (isAutoMergeDecision(decision)) {
63356
+ return `${subject}: auto-merge local [${decision.localFieldPaths.join(", ")}] with remote [${decision.remoteFieldPaths.join(", ")}]`;
63357
+ }
63358
+ if (isConflictDecision(decision)) {
63359
+ return `${subject}: conflict (${decision.conflict.code})`;
63271
63360
  }
63361
+ const label = config2.decisionLabels[decision.kind];
63362
+ return `${subject}: ${label}`;
63272
63363
  }
63273
- function decisionReport(decision) {
63364
+ function decisionReport(config2, decision) {
63274
63365
  const base = {
63275
63366
  kind: decision.kind,
63276
- contentType: decision.subject.contentType,
63277
- identifier: decision.subject.identifier
63367
+ ...config2.subjectJson(decision.subject)
63278
63368
  };
63279
- if (decision.kind === "auto_merge") {
63369
+ if (isAutoMergeDecision(decision)) {
63280
63370
  return {
63281
63371
  ...base,
63282
63372
  localFieldPaths: decision.localFieldPaths,
63283
63373
  remoteFieldPaths: decision.remoteFieldPaths
63284
63374
  };
63285
63375
  }
63286
- if (decision.kind === "conflict") {
63376
+ if (isConflictDecision(decision)) {
63287
63377
  return {
63288
63378
  ...base,
63289
63379
  conflict: {
@@ -63295,6 +63385,56 @@ function decisionReport(decision) {
63295
63385
  }
63296
63386
  return base;
63297
63387
  }
63388
+ function isAutoMergeDecision(decision) {
63389
+ return decision.kind === "auto_merge";
63390
+ }
63391
+ function isConflictDecision(decision) {
63392
+ return decision.kind === "conflict";
63393
+ }
63394
+
63395
+ // src/cli/merge-remote/entryMergeReport.ts
63396
+ var entryDecisionLabels = {
63397
+ apply_local_create: "apply local create",
63398
+ apply_local_update: "apply local update",
63399
+ apply_local_delete: "apply local delete",
63400
+ preserve_remote: "preserve remote",
63401
+ bootstrap_base: "bootstrap missing base"
63402
+ };
63403
+ var entryMergeReportConfig = {
63404
+ scope: "entries",
63405
+ title: "Remote-aware entry merge plan:",
63406
+ summaryLines: (summary) => [
63407
+ ` Local creates: ${summary.applyLocalCreate}`,
63408
+ ` Local updates: ${summary.applyLocalUpdate}`,
63409
+ ` Local deletes: ${summary.applyLocalDelete}`,
63410
+ ` Auto-merges: ${summary.autoMerge}`,
63411
+ ` Remote preserved: ${summary.preserveRemote}`,
63412
+ ` Base bootstraps: ${summary.bootstrapBase}`,
63413
+ ` Unchanged: ${summary.unchanged}`,
63414
+ ` Conflicts: ${summary.conflicts}`
63415
+ ],
63416
+ subjectLabel: (subject) => `${subject.contentType}/${subject.identifier}`,
63417
+ subjectJson: (subject) => ({
63418
+ contentType: subject.contentType,
63419
+ identifier: subject.identifier
63420
+ }),
63421
+ decisionLabels: entryDecisionLabels
63422
+ };
63423
+ function remoteEntryMergeJsonReport(input) {
63424
+ return remoteMergeJsonReport({
63425
+ config: entryMergeReportConfig,
63426
+ decisions: input.plan.decisions,
63427
+ dryRun: input.dryRun,
63428
+ summary: input.plan.summary
63429
+ });
63430
+ }
63431
+ function writeRemoteEntryMergeHumanReport(output, plan, options) {
63432
+ writeRemoteMergeHumanReport(output, entryMergeReportConfig, {
63433
+ decisions: plan.decisions,
63434
+ dryRun: options.dryRun,
63435
+ summary: plan.summary
63436
+ });
63437
+ }
63298
63438
 
63299
63439
  // src/cli/merge-remote/entryRemote.ts
63300
63440
  var DEFAULT_PAGE_LIMIT2 = 100;
@@ -63586,9 +63726,6 @@ async function unlinkIfExists(filePath) {
63586
63726
  }
63587
63727
  }
63588
63728
 
63589
- // src/cli/merge-remote/pageMergePlan.ts
63590
- init_src();
63591
-
63592
63729
  // src/cli/merge-remote/pageMerge.ts
63593
63730
  function planPageMerge(input) {
63594
63731
  const { subject, base, local, remote } = input;
@@ -63801,13 +63938,13 @@ function setPagePath(page, pathParts, value) {
63801
63938
  throw new Error(`Unsupported page merge path: ${pathParts.join(".")}`);
63802
63939
  }
63803
63940
  }
63804
- function expectStringValue2(path32, value) {
63941
+ function expectStringValue2(path33, value) {
63805
63942
  if (typeof value === "string") return value;
63806
- throw new Error(`Page merge expected ${path32} to be a string.`);
63943
+ throw new Error(`Page merge expected ${path33} to be a string.`);
63807
63944
  }
63808
- function expectBooleanValue2(path32, value) {
63945
+ function expectBooleanValue2(path33, value) {
63809
63946
  if (typeof value === "boolean") return value;
63810
- throw new Error(`Page merge expected ${path32} to be a boolean.`);
63947
+ throw new Error(`Page merge expected ${path33} to be a boolean.`);
63811
63948
  }
63812
63949
  function expectStatusValue2(value) {
63813
63950
  if (value === "draft" || value === "published") return value;
@@ -63816,28 +63953,26 @@ function expectStatusValue2(value) {
63816
63953
 
63817
63954
  // src/cli/merge-remote/pageMergePlan.ts
63818
63955
  async function buildRemotePageMergePlan(input) {
63819
- const subjects = subjectsForScope2(input.scope, input.localPages, input.remotePages);
63820
- const decisions = await Promise.all(subjects.map(async (subject) => {
63821
- const baseSnapshot = await readPageBaseSnapshot({
63956
+ const plan = await buildRemoteMergePlanWithConfig({
63957
+ subjects: () => subjectsForScope2(input.scope, input.localPages, input.remotePages),
63958
+ readBaseSnapshot: (subject) => readPageBaseSnapshot({
63822
63959
  contentDir: input.contentDir,
63823
63960
  target: input.target,
63824
63961
  subject
63825
- });
63826
- return planPageMerge({
63827
- subject,
63828
- base: baseSnapshot?.page ?? null,
63829
- local: localPageForSubject(input.localPages, subject),
63830
- remote: remotePageForSubject(input.remotePages, subject)
63831
- });
63832
- }));
63962
+ }),
63963
+ valueFromBaseSnapshot: (snapshot) => snapshot.page,
63964
+ localValue: (subject) => localPageForSubject(input.localPages, subject),
63965
+ remoteValue: (subject) => remotePageForSubject(input.remotePages, subject),
63966
+ planDecision: planPageMerge,
63967
+ summarize: summarizePageMergeDecisions
63968
+ });
63833
63969
  return {
63834
63970
  scope: input.scope,
63835
- decisions,
63836
- summary: summarizePageMergeDecisions(decisions)
63971
+ ...plan
63837
63972
  };
63838
63973
  }
63839
63974
  function summarizePageMergeDecisions(decisions) {
63840
- const summary = {
63975
+ return summarizeMergeDecisions(decisions, {
63841
63976
  unchanged: 0,
63842
63977
  bootstrapBase: 0,
63843
63978
  preserveRemote: 0,
@@ -63845,36 +63980,17 @@ function summarizePageMergeDecisions(decisions) {
63845
63980
  applyLocalUpdate: 0,
63846
63981
  autoMerge: 0,
63847
63982
  conflicts: 0
63848
- };
63849
- for (const decision of decisions) {
63850
- switch (decision.kind) {
63851
- case "unchanged":
63852
- summary.unchanged++;
63853
- break;
63854
- case "bootstrap_base":
63855
- summary.bootstrapBase++;
63856
- break;
63857
- case "preserve_remote":
63858
- summary.preserveRemote++;
63859
- break;
63860
- case "apply_local_create":
63861
- summary.applyLocalCreate++;
63862
- break;
63863
- case "apply_local_update":
63864
- summary.applyLocalUpdate++;
63865
- break;
63866
- case "auto_merge":
63867
- summary.autoMerge++;
63868
- break;
63869
- case "conflict":
63870
- summary.conflicts++;
63871
- break;
63872
- default:
63873
- assertNever(decision);
63874
- }
63875
- }
63876
- return summary;
63877
- }
63983
+ }, pageSummaryKeyByDecisionKind);
63984
+ }
63985
+ var pageSummaryKeyByDecisionKind = {
63986
+ unchanged: "unchanged",
63987
+ bootstrap_base: "bootstrapBase",
63988
+ preserve_remote: "preserveRemote",
63989
+ apply_local_create: "applyLocalCreate",
63990
+ apply_local_update: "applyLocalUpdate",
63991
+ auto_merge: "autoMerge",
63992
+ conflict: "conflicts"
63993
+ };
63878
63994
  function pageMergePushScope(input) {
63879
63995
  if (input.identifier) {
63880
63996
  return {
@@ -63906,41 +64022,16 @@ function remotePageForSubject(pages, subject) {
63906
64022
  }
63907
64023
 
63908
64024
  // src/cli/merge-remote/pageMergeReport.ts
63909
- function remotePageMergeJsonReport(input) {
63910
- return {
63911
- kind: "push",
63912
- scope: "pages",
63913
- mergeRemote: true,
63914
- dryRun: input.dryRun,
63915
- summary: input.plan.summary,
63916
- decisions: input.plan.decisions.map(decisionReport2)
63917
- };
63918
- }
63919
- function writeRemotePageMergeHumanReport(output, plan, options) {
63920
- output.info(`
63921
- ${options.dryRun ? "[DRY RUN] " : ""}Remote-aware page merge plan:`);
63922
- output.info(formatSummary2(plan));
63923
- const conflicts = plan.decisions.filter((decision) => decision.kind === "conflict");
63924
- if (conflicts.length > 0) {
63925
- output.info("\nConflicts:");
63926
- for (const decision of conflicts) {
63927
- if (decision.kind !== "conflict") continue;
63928
- output.info(
63929
- ` - ${decision.subject.identifier}: ${decision.conflict.message}`
63930
- );
63931
- }
63932
- }
63933
- const changes = plan.decisions.filter((decision) => decision.kind !== "unchanged" && decision.kind !== "conflict");
63934
- if (changes.length > 0) {
63935
- output.info("\nDecisions:");
63936
- for (const decision of changes) {
63937
- output.info(` - ${formatDecisionLine2(decision)}`);
63938
- }
63939
- }
63940
- }
63941
- function formatSummary2(plan) {
63942
- const { summary } = plan;
63943
- return [
64025
+ var pageDecisionLabels = {
64026
+ apply_local_create: "apply local create",
64027
+ apply_local_update: "apply local update",
64028
+ preserve_remote: "preserve remote",
64029
+ bootstrap_base: "bootstrap missing base"
64030
+ };
64031
+ var pageMergeReportConfig = {
64032
+ scope: "pages",
64033
+ title: "Remote-aware page merge plan:",
64034
+ summaryLines: (summary) => [
63944
64035
  ` Local creates: ${summary.applyLocalCreate}`,
63945
64036
  ` Local updates: ${summary.applyLocalUpdate}`,
63946
64037
  ` Auto-merges: ${summary.autoMerge}`,
@@ -63948,50 +64039,27 @@ function formatSummary2(plan) {
63948
64039
  ` Base bootstraps: ${summary.bootstrapBase}`,
63949
64040
  ` Unchanged: ${summary.unchanged}`,
63950
64041
  ` Conflicts: ${summary.conflicts}`
63951
- ].join("\n");
63952
- }
63953
- function formatDecisionLine2(decision) {
63954
- const subject = decision.subject.identifier;
63955
- switch (decision.kind) {
63956
- case "auto_merge":
63957
- return `${subject}: auto-merge local [${decision.localFieldPaths.join(", ")}] with remote [${decision.remoteFieldPaths.join(", ")}]`;
63958
- case "conflict":
63959
- return `${subject}: conflict (${decision.conflict.code})`;
63960
- case "apply_local_create":
63961
- return `${subject}: apply local create`;
63962
- case "apply_local_update":
63963
- return `${subject}: apply local update`;
63964
- case "preserve_remote":
63965
- return `${subject}: preserve remote`;
63966
- case "bootstrap_base":
63967
- return `${subject}: bootstrap missing base`;
63968
- case "unchanged":
63969
- return `${subject}: unchanged`;
63970
- }
64042
+ ],
64043
+ subjectLabel: (subject) => subject.identifier,
64044
+ subjectJson: (subject) => ({
64045
+ identifier: subject.identifier
64046
+ }),
64047
+ decisionLabels: pageDecisionLabels
64048
+ };
64049
+ function remotePageMergeJsonReport(input) {
64050
+ return remoteMergeJsonReport({
64051
+ config: pageMergeReportConfig,
64052
+ decisions: input.plan.decisions,
64053
+ dryRun: input.dryRun,
64054
+ summary: input.plan.summary
64055
+ });
63971
64056
  }
63972
- function decisionReport2(decision) {
63973
- const base = {
63974
- kind: decision.kind,
63975
- identifier: decision.subject.identifier
63976
- };
63977
- if (decision.kind === "auto_merge") {
63978
- return {
63979
- ...base,
63980
- localFieldPaths: decision.localFieldPaths,
63981
- remoteFieldPaths: decision.remoteFieldPaths
63982
- };
63983
- }
63984
- if (decision.kind === "conflict") {
63985
- return {
63986
- ...base,
63987
- conflict: {
63988
- code: decision.conflict.code,
63989
- ..."fieldPath" in decision.conflict ? { fieldPath: decision.conflict.fieldPath } : {},
63990
- message: decision.conflict.message
63991
- }
63992
- };
63993
- }
63994
- return base;
64057
+ function writeRemotePageMergeHumanReport(output, plan, options) {
64058
+ writeRemoteMergeHumanReport(output, pageMergeReportConfig, {
64059
+ decisions: plan.decisions,
64060
+ dryRun: options.dryRun,
64061
+ summary: plan.summary
64062
+ });
63995
64063
  }
63996
64064
 
63997
64065
  // src/cli/merge-remote/pageMergePush.ts
@@ -64151,7 +64219,7 @@ function emptyPulledContent(overrides) {
64151
64219
  async function executeScopedPush(output, isRemote, options, globalOpts, scopeLabel, pullCommand2, shouldDeleteOrphans, pushFn, scopedOptions) {
64152
64220
  const target = isRemote ? "remote" : "local";
64153
64221
  const cliConfig = await loadCliConfigForEnv(target);
64154
- const contentDir = path20.resolve(options.contentDir ?? cliConfig.contentDir);
64222
+ const contentDir = path21.resolve(options.contentDir ?? cliConfig.contentDir);
64155
64223
  if (!await contentDirExists(contentDir)) {
64156
64224
  return output.error(`Content directory not found: ${contentDir}`, {
64157
64225
  suggestion: `Run "riverbankcms pull ${pullCommand2}" first to download ${scopeLabel}`
@@ -64389,7 +64457,7 @@ async function executePushForEnv(output, target, scope, type, identifier, option
64389
64457
  );
64390
64458
  }
64391
64459
  const cliConfig2 = await loadCliConfigForEnv(target);
64392
- const contentDir2 = path20.resolve(options.contentDir ?? cliConfig2.contentDir);
64460
+ const contentDir2 = path21.resolve(options.contentDir ?? cliConfig2.contentDir);
64393
64461
  if (!await contentDirExists(contentDir2)) {
64394
64462
  return output.error(`Content directory not found: ${contentDir2}`, {
64395
64463
  suggestion: 'Run "riverbankcms pull theme" first to download theme'
@@ -64556,7 +64624,7 @@ ${errors}`
64556
64624
  });
64557
64625
  }
64558
64626
  const cliConfig = await loadCliConfigForEnv(target);
64559
- const contentDir = path20.resolve(options.contentDir ?? cliConfig.contentDir);
64627
+ const contentDir = path21.resolve(options.contentDir ?? cliConfig.contentDir);
64560
64628
  if (!await contentDirExists(contentDir)) {
64561
64629
  return output.error(`Content directory not found: ${contentDir}`, {
64562
64630
  suggestion: 'Run "riverbankcms pull" first to download content, or specify a different directory with --content-dir'
@@ -64607,7 +64675,7 @@ ${errors}`
64607
64675
  if (legacyFiles.length > 0) {
64608
64676
  process.exitCode = 1;
64609
64677
  output.result(false, "Legacy entry file format detected (one file per content type).", {
64610
- files: legacyFiles.map((f) => path20.basename(f)),
64678
+ files: legacyFiles.map((f) => path21.basename(f)),
64611
64679
  suggestion: 'Run "riverbankcms migrate entries" to convert to content/entries/<type>/<identifier>.json (preserves local edits), or run "riverbankcms pull entries" to re-pull content in the new format.'
64612
64680
  });
64613
64681
  return { success: false };
@@ -65246,7 +65314,7 @@ function summarizePushAllExtras(local, remote, deleteOrphaned) {
65246
65314
  return dirty;
65247
65315
  }
65248
65316
  function verificationContentDir(options, cliConfig) {
65249
- return path20.resolve(options.contentDir ?? cliConfig.contentDir);
65317
+ return path21.resolve(options.contentDir ?? cliConfig.contentDir);
65250
65318
  }
65251
65319
  async function loadGenericComparison(input) {
65252
65320
  const cliConfig = await loadCliConfigForEnv(input.target);
@@ -65432,15 +65500,27 @@ function emitPushVerificationResult(output, result, jsonOutput) {
65432
65500
  }
65433
65501
 
65434
65502
  // src/cli/commands/push.ts
65435
- var pushCommand = new Command("push").description("Push content to CMS").argument(
65436
- "[scope]",
65437
- "What to push: entries, pages, navigation, forms, settings, footer, theme, venues, event-categories, events, courses, or all (default)"
65438
- ).argument("[type]", "Content type (entries), page identifier (pages), or theme name (theme)").argument("[identifier]", 'Entry identifier (when scope is "entries" and type is set)').option("--content-dir <dir>", "Content directory (overrides config)").option("--dry-run", "Show what would be pushed without making changes").option("--yes", "Skip confirmation prompt (required for --env=remote or --env=both)").option("--force", "Push even if remote content is newer (skip stale check)").option("--force-update-asset", "Replace CMS media when identifiers conflict (local media sync only)").option("--allow-truncated", "Push even if remote content was truncated (may cause incomplete sync)").option("--json-diff [mode]", "Output JSON diff (summary or full)", "summary").option("--with-config", "Push SDK schema/config before dependent file content").option("--with-theme", "Also push theme when pushing all content").option("--sync-media", "Sync media files from local to remote environment").option("--overwrite-media", "When using --sync-media, overwrite target media on checksum mismatch").option("--allow-missing-media", "For event pushes, report missing local media but continue pushing event config").option(
65439
- "--delete-missing",
65440
- "[Deprecated: use --delete-orphaned] Delete CMS entries not in local file (single content type only)"
65441
- ).option("--delete-orphaned", "Delete remote items not present in local files (entries, events, courses, venues, event-categories)").option("--auto-pull-stale", "Automatically pull stale content and retry push").option("--merge-remote", "Plan an entries/pages three-way merge that preserves remote edits").option("--no-meta", "Skip writing .meta/ and media manifest files (content files still written)").option("--diff", "Show human-readable field-level diff with before/after values (requires --dry-run)").option("--verify-noop", "After an applied push, re-fetch the target and fail if changes remain").addHelpText(
65442
- "after",
65443
- `
65503
+ function getProductionPushCommandDeps() {
65504
+ return {
65505
+ getOutputContext,
65506
+ runForEnvironments,
65507
+ allEnvSucceeded,
65508
+ executePushForEnv,
65509
+ verifyPushNoopForEnv,
65510
+ emitPushVerificationResult,
65511
+ isPushVerificationClean
65512
+ };
65513
+ }
65514
+ function createPushCommand(deps = getProductionPushCommandDeps()) {
65515
+ return new Command("push").description("Push content to CMS").argument(
65516
+ "[scope]",
65517
+ "What to push: entries, pages, navigation, forms, settings, footer, theme, venues, event-categories, events, courses, or all (default)"
65518
+ ).argument("[type]", "Content type (entries), page identifier (pages), or theme name (theme)").argument("[identifier]", 'Entry identifier (when scope is "entries" and type is set)').option("--content-dir <dir>", "Content directory (overrides config)").option("--dry-run", "Show what would be pushed without making changes").option("--yes", "Skip confirmation prompt (required for --env=remote or --env=both)").option("--force", "Push even if remote content is newer (skip stale check)").option("--force-update-asset", "Replace CMS media when identifiers conflict (local media sync only)").option("--allow-truncated", "Push even if remote content was truncated (may cause incomplete sync)").option("--json-diff [mode]", "Output JSON diff (summary or full)", "summary").option("--with-config", "Push SDK schema/config before dependent file content").option("--with-theme", "Also push theme when pushing all content").option("--sync-media", "Sync media files from local to remote environment").option("--overwrite-media", "When using --sync-media, overwrite target media on checksum mismatch").option("--allow-missing-media", "For event pushes, report missing local media but continue pushing event config").option(
65519
+ "--delete-missing",
65520
+ "[Deprecated: use --delete-orphaned] Delete CMS entries not in local file (single content type only)"
65521
+ ).option("--delete-orphaned", "Delete remote items not present in local files (entries, events, courses, venues, event-categories)").option("--auto-pull-stale", "Automatically pull stale content and retry push").option("--merge-remote", "Plan an entries/pages three-way merge that preserves remote edits").option("--no-meta", "Skip writing .meta/ and media manifest files (content files still written)").option("--diff", "Show human-readable field-level diff with before/after values (requires --dry-run)").option("--verify-noop", "After an applied push, re-fetch the target and fail if changes remain").addHelpText(
65522
+ "after",
65523
+ `
65444
65524
  Examples:
65445
65525
  $ riverbankcms push # Push all content to local
65446
65526
  $ riverbankcms push --env=remote --yes # Push to production
@@ -65514,124 +65594,126 @@ Media Sync:
65514
65594
  $ riverbankcms push --sync-media # Sync all content + media
65515
65595
  $ riverbankcms push entries blog --sync-media # Sync blog entries + their media
65516
65596
  `
65517
- ).action(
65518
- async (scope, type, identifier, options, command) => {
65519
- const { output, envTargets, globalOpts } = getOutputContext(command);
65520
- const jsonDiffMode = options.jsonDiff ? options.jsonDiff === "summary" || options.jsonDiff === "full" ? options.jsonDiff : null : void 0;
65521
- if (options.jsonDiff && !jsonDiffMode) {
65522
- output.error("Invalid value for --json-diff. Use summary or full.");
65523
- return;
65524
- }
65525
- if (options.diff && !options.dryRun) {
65526
- output.error("--diff requires --dry-run.");
65527
- return;
65528
- }
65529
- if (options.diff && options.jsonDiff) {
65530
- output.error("--diff and --json-diff are mutually exclusive.");
65531
- return;
65532
- }
65533
- if (options.diff && globalOpts.json) {
65534
- output.error("--diff and --json are mutually exclusive.");
65535
- return;
65536
- }
65537
- if (options.verifyNoop && options.dryRun) {
65538
- output.error("--verify-noop cannot be combined with --dry-run.");
65539
- return;
65540
- }
65541
- if (options.mergeRemote && envTargets.length > 1) {
65542
- process.exitCode = 1;
65543
- output.result(false, "--merge-remote does not support --env=both in v1.", {
65544
- suggestion: "Run one remote entries merge at a time with --env=remote."
65545
- });
65546
- return;
65547
- }
65548
- if (envTargets.length > 1) {
65549
- const results = await runForEnvironments(
65550
- envTargets,
65551
- async (target2) => {
65552
- const isRemote2 = target2 === "remote";
65553
- let dryRun2 = options.dryRun ?? false;
65554
- if (isRemote2 && !options.yes) {
65555
- dryRun2 = true;
65556
- output.info(`Remote push defaults to dry-run mode. Use --yes to apply changes.`);
65557
- }
65558
- if (options.verifyNoop && dryRun2) {
65559
- output.error("--verify-noop requires an applied push. Remove --dry-run or pass --yes for remote targets.");
65560
- return { success: false };
65561
- }
65562
- output.info(`
65597
+ ).action(
65598
+ async (scope, type, identifier, options, command) => {
65599
+ const { output, envTargets, globalOpts } = deps.getOutputContext(command);
65600
+ const jsonDiffMode = options.jsonDiff ? options.jsonDiff === "summary" || options.jsonDiff === "full" ? options.jsonDiff : null : void 0;
65601
+ if (options.jsonDiff && !jsonDiffMode) {
65602
+ output.error("Invalid value for --json-diff. Use summary or full.");
65603
+ return;
65604
+ }
65605
+ if (options.diff && !options.dryRun) {
65606
+ output.error("--diff requires --dry-run.");
65607
+ return;
65608
+ }
65609
+ if (options.diff && options.jsonDiff) {
65610
+ output.error("--diff and --json-diff are mutually exclusive.");
65611
+ return;
65612
+ }
65613
+ if (options.diff && globalOpts.json) {
65614
+ output.error("--diff and --json are mutually exclusive.");
65615
+ return;
65616
+ }
65617
+ if (options.verifyNoop && options.dryRun) {
65618
+ output.error("--verify-noop cannot be combined with --dry-run.");
65619
+ return;
65620
+ }
65621
+ if (options.mergeRemote && envTargets.length > 1) {
65622
+ process.exitCode = 1;
65623
+ output.result(false, "--merge-remote does not support --env=both in v1.", {
65624
+ suggestion: "Run one remote entries merge at a time with --env=remote."
65625
+ });
65626
+ return;
65627
+ }
65628
+ if (envTargets.length > 1) {
65629
+ const results = await deps.runForEnvironments(
65630
+ envTargets,
65631
+ async (target2) => {
65632
+ const isRemote2 = target2 === "remote";
65633
+ let dryRun2 = options.dryRun ?? false;
65634
+ if (isRemote2 && !options.yes) {
65635
+ dryRun2 = true;
65636
+ output.info(`Remote push defaults to dry-run mode. Use --yes to apply changes.`);
65637
+ }
65638
+ if (options.verifyNoop && dryRun2) {
65639
+ output.error("--verify-noop requires an applied push. Remove --dry-run or pass --yes for remote targets.");
65640
+ return { success: false };
65641
+ }
65642
+ output.info(`
65563
65643
  --- Pushing to ${target2} environment ---`);
65564
- const pushResult = await executePushForEnv(
65565
- output,
65566
- target2,
65567
- scope,
65568
- type,
65569
- identifier,
65570
- { ...options, dryRun: dryRun2, jsonDiffMode },
65571
- globalOpts
65572
- );
65573
- if (!pushResult.success || !options.verifyNoop) {
65574
- return pushResult;
65644
+ const pushResult = await deps.executePushForEnv(
65645
+ output,
65646
+ target2,
65647
+ scope,
65648
+ type,
65649
+ identifier,
65650
+ { ...options, dryRun: dryRun2, jsonDiffMode },
65651
+ globalOpts
65652
+ );
65653
+ if (!pushResult.success || !options.verifyNoop) {
65654
+ return pushResult;
65655
+ }
65656
+ const verification = await deps.verifyPushNoopForEnv({
65657
+ target: target2,
65658
+ scope,
65659
+ type,
65660
+ identifier,
65661
+ options
65662
+ });
65663
+ deps.emitPushVerificationResult(output, verification, globalOpts.json ?? false);
65664
+ return { success: deps.isPushVerificationClean(verification) };
65665
+ },
65666
+ output,
65667
+ {
65668
+ isResultSuccess: (result2) => result2.success,
65669
+ formatFailure: () => "Push completed with failures"
65575
65670
  }
65576
- const verification = await verifyPushNoopForEnv({
65577
- target: target2,
65578
- scope,
65579
- type,
65580
- identifier,
65581
- options
65582
- });
65583
- emitPushVerificationResult(output, verification, globalOpts.json ?? false);
65584
- return { success: isPushVerificationClean(verification) };
65585
- },
65586
- output,
65587
- {
65588
- isResultSuccess: (result2) => result2.success,
65589
- formatFailure: () => "Push completed with failures"
65671
+ );
65672
+ if (!deps.allEnvSucceeded(results)) {
65673
+ process.exit(1);
65590
65674
  }
65591
- );
65592
- if (!allEnvSucceeded(results)) {
65593
- process.exit(1);
65675
+ return;
65594
65676
  }
65595
- return;
65596
- }
65597
- const target = envTargets[0] ?? "local";
65598
- const isRemote = target === "remote";
65599
- let dryRun = options.dryRun ?? false;
65600
- if (isRemote && !options.yes) {
65601
- dryRun = true;
65602
- output.info("Remote push defaults to dry-run mode. Use --yes to apply changes.");
65603
- }
65604
- if (options.verifyNoop && dryRun) {
65605
- output.error("--verify-noop requires an applied push. Remove --dry-run or pass --yes for remote targets.");
65606
- return;
65607
- }
65608
- const result = await executePushForEnv(
65609
- output,
65610
- target,
65611
- scope,
65612
- type,
65613
- identifier,
65614
- { ...options, dryRun, jsonDiffMode },
65615
- globalOpts
65616
- );
65617
- if (!result.success) {
65618
- process.exit(1);
65619
- }
65620
- if (options.verifyNoop) {
65621
- const verification = await verifyPushNoopForEnv({
65677
+ const target = envTargets[0] ?? "local";
65678
+ const isRemote = target === "remote";
65679
+ let dryRun = options.dryRun ?? false;
65680
+ if (isRemote && !options.yes) {
65681
+ dryRun = true;
65682
+ output.info("Remote push defaults to dry-run mode. Use --yes to apply changes.");
65683
+ }
65684
+ if (options.verifyNoop && dryRun) {
65685
+ output.error("--verify-noop requires an applied push. Remove --dry-run or pass --yes for remote targets.");
65686
+ return;
65687
+ }
65688
+ const result = await deps.executePushForEnv(
65689
+ output,
65622
65690
  target,
65623
65691
  scope,
65624
65692
  type,
65625
65693
  identifier,
65626
- options
65627
- });
65628
- emitPushVerificationResult(output, verification, globalOpts.json ?? false);
65629
- if (!isPushVerificationClean(verification)) {
65694
+ { ...options, dryRun, jsonDiffMode },
65695
+ globalOpts
65696
+ );
65697
+ if (!result.success) {
65630
65698
  process.exit(1);
65631
65699
  }
65700
+ if (options.verifyNoop) {
65701
+ const verification = await deps.verifyPushNoopForEnv({
65702
+ target,
65703
+ scope,
65704
+ type,
65705
+ identifier,
65706
+ options
65707
+ });
65708
+ deps.emitPushVerificationResult(output, verification, globalOpts.json ?? false);
65709
+ if (!deps.isPushVerificationClean(verification)) {
65710
+ process.exit(1);
65711
+ }
65712
+ }
65632
65713
  }
65633
- }
65634
- );
65714
+ );
65715
+ }
65716
+ var pushCommand = createPushCommand();
65635
65717
 
65636
65718
  // src/cli/media/write-guard.ts
65637
65719
  var MEDIA_GUARD_BYPASS_ENV_VAR = "RIVERBANK_SKIP_MEDIA_GUARD";
@@ -68057,41 +68139,41 @@ function formatVisibleWhen(visibleWhen) {
68057
68139
  // src/cli/init-docs/index.ts
68058
68140
  var AGENTS_START = "<!-- RIVERBANK-CONTEXT-START -->";
68059
68141
  var AGENTS_END = "<!-- RIVERBANK-CONTEXT-END -->";
68060
- var currentDir2 = path20.dirname(fileURLToPath(import.meta.url));
68142
+ var currentDir2 = path21.dirname(fileURLToPath(import.meta.url));
68061
68143
  function getContentDir() {
68062
68144
  const isBundled = currentDir2.includes("/dist/cli") || currentDir2.endsWith("/dist/cli");
68063
68145
  if (isBundled) {
68064
- return path20.join(currentDir2, "init-docs", "content");
68146
+ return path21.join(currentDir2, "init-docs", "content");
68065
68147
  }
68066
- return path20.join(currentDir2, "content");
68148
+ return path21.join(currentDir2, "content");
68067
68149
  }
68068
68150
  function loadTemplate(name) {
68069
68151
  const contentDir = getContentDir();
68070
- const filePath = path20.join(contentDir, `${name}.md`);
68152
+ const filePath = path21.join(contentDir, `${name}.md`);
68071
68153
  return readFileSync(filePath, "utf-8");
68072
68154
  }
68073
68155
  async function initDocs(options) {
68074
68156
  const { rootDir, configPath, agentsPath } = options;
68075
- const docsDir = path20.join(rootDir, "docs");
68076
- const contextDir = path20.join(rootDir, "context");
68077
- const workflowsDir = path20.join(docsDir, "workflows");
68078
- const siteWorkflowsDir = path20.join(docsDir, "site-workflows");
68079
- const knowledgeDir = path20.join(contextDir, "knowledge");
68080
- const brandDir = path20.join(contextDir, "brand");
68157
+ const docsDir = path21.join(rootDir, "docs");
68158
+ const contextDir = path21.join(rootDir, "context");
68159
+ const workflowsDir = path21.join(docsDir, "workflows");
68160
+ const siteWorkflowsDir = path21.join(docsDir, "site-workflows");
68161
+ const knowledgeDir = path21.join(contextDir, "knowledge");
68162
+ const brandDir = path21.join(contextDir, "brand");
68081
68163
  await ensureDir3(workflowsDir);
68082
68164
  await ensureDir3(siteWorkflowsDir);
68083
68165
  await ensureDir3(knowledgeDir);
68084
68166
  await ensureDir3(brandDir);
68085
68167
  await writeFileIfMissing(
68086
- path20.join(docsDir, "getting-started.md"),
68168
+ path21.join(docsDir, "getting-started.md"),
68087
68169
  loadTemplate("getting-started")
68088
68170
  );
68089
68171
  await writeFileIfMissing(
68090
- path20.join(docsDir, "cli-reference.md"),
68172
+ path21.join(docsDir, "cli-reference.md"),
68091
68173
  loadTemplate("cli-reference")
68092
68174
  );
68093
68175
  await writeFileIfMissing(
68094
- path20.join(docsDir, "content-management.md"),
68176
+ path21.join(docsDir, "content-management.md"),
68095
68177
  loadTemplate("content-management")
68096
68178
  );
68097
68179
  const coreWorkflows = [
@@ -68112,46 +68194,46 @@ async function initDocs(options) {
68112
68194
  await Promise.all(
68113
68195
  coreWorkflows.map(
68114
68196
  ({ filename, template }) => fs2.writeFile(
68115
- path20.join(workflowsDir, filename),
68197
+ path21.join(workflowsDir, filename),
68116
68198
  loadTemplate(template),
68117
68199
  "utf-8"
68118
68200
  )
68119
68201
  )
68120
68202
  );
68121
68203
  await writeFileIfMissing(
68122
- path20.join(siteWorkflowsDir, "README.md"),
68204
+ path21.join(siteWorkflowsDir, "README.md"),
68123
68205
  loadTemplate("site-workflows-readme")
68124
68206
  );
68125
68207
  await writeFileIfMissing(
68126
- path20.join(contextDir, "brief.md"),
68208
+ path21.join(contextDir, "brief.md"),
68127
68209
  loadTemplate("context-brief")
68128
68210
  );
68129
68211
  await writeFileIfMissing(
68130
- path20.join(knowledgeDir, "README.md"),
68212
+ path21.join(knowledgeDir, "README.md"),
68131
68213
  loadTemplate("context-knowledge")
68132
68214
  );
68133
68215
  await writeFileIfMissing(
68134
- path20.join(brandDir, "README.md"),
68216
+ path21.join(brandDir, "README.md"),
68135
68217
  loadTemplate("context-brand")
68136
68218
  );
68137
68219
  const { config: config2, errorMessage } = await loadConfig(configPath, options.output);
68138
68220
  await upsertGeneratedDoc(
68139
- path20.join(docsDir, "schema.md"),
68221
+ path21.join(docsDir, "schema.md"),
68140
68222
  buildSchemaTemplate({ config: config2, errorMessage }),
68141
68223
  buildSchemaGeneratedSection({ config: config2, errorMessage })
68142
68224
  );
68143
68225
  await upsertGeneratedDoc(
68144
- path20.join(docsDir, "block-types.md"),
68226
+ path21.join(docsDir, "block-types.md"),
68145
68227
  buildBlockTypesTemplate(),
68146
68228
  buildBlockTypesGeneratedSection()
68147
68229
  );
68148
68230
  await upsertGeneratedDoc(
68149
- path20.join(docsDir, "block-types-site.md"),
68231
+ path21.join(docsDir, "block-types-site.md"),
68150
68232
  buildSiteBlockTypesTemplate({ config: config2, errorMessage }),
68151
68233
  buildSiteBlockTypesGeneratedSection({ config: config2, errorMessage })
68152
68234
  );
68153
68235
  await upsertGeneratedDoc(
68154
- path20.join(docsDir, "theme-schema.md"),
68236
+ path21.join(docsDir, "theme-schema.md"),
68155
68237
  buildThemeSchemaTemplate(),
68156
68238
  buildThemeSchemaGeneratedSection()
68157
68239
  );
@@ -68238,9 +68320,9 @@ async function upsertAgentsSection(filePath) {
68238
68320
  // src/cli/commands/init-docs.ts
68239
68321
  async function runInitDocs(options, command) {
68240
68322
  const { output, isJsonOutput } = createCommandContext(command);
68241
- const rootDir = path20.resolve(options.path ?? ".riverbank");
68242
- const configPath = path20.resolve(options.config ?? path20.join(process.cwd(), "riverbank.config.ts"));
68243
- const agentsPath = path20.resolve(process.cwd(), "AGENTS.md");
68323
+ const rootDir = path21.resolve(options.path ?? ".riverbank");
68324
+ const configPath = path21.resolve(options.config ?? path21.join(process.cwd(), "riverbank.config.ts"));
68325
+ const agentsPath = path21.resolve(process.cwd(), "AGENTS.md");
68244
68326
  await initDocs({
68245
68327
  rootDir,
68246
68328
  configPath,
@@ -68435,7 +68517,7 @@ var SimpleCache = class {
68435
68517
  };
68436
68518
 
68437
68519
  // src/version.ts
68438
- var SDK_VERSION = "0.98.0";
68520
+ var SDK_VERSION = "0.99.0";
68439
68521
 
68440
68522
  // src/client/error.ts
68441
68523
  var RiverbankApiError = class _RiverbankApiError extends Error {
@@ -69636,7 +69718,14 @@ function resolveAuth(config2) {
69636
69718
  'Authentication configuration is required. Provide either `auth` (recommended) or `apiKey` (deprecated). For public endpoints without auth, use: { auth: { type: "none" } }'
69637
69719
  );
69638
69720
  }
69721
+ var defaultRiverbankClientDeps = {
69722
+ createBearerAPIClient,
69723
+ createInternalAPIClient
69724
+ };
69639
69725
  function createRiverbankClient(config2) {
69726
+ return createRiverbankClientWithDeps(defaultRiverbankClientDeps, config2);
69727
+ }
69728
+ function createRiverbankClientWithDeps(deps, config2) {
69640
69729
  if (!config2.baseUrl) {
69641
69730
  throw new Error(
69642
69731
  "baseUrl is required when creating a Riverbank client. Expected format: https://dashboard.example.com/api (must include /api path)"
@@ -69679,7 +69768,7 @@ function createRiverbankClient(config2) {
69679
69768
  keyType = "preview";
69680
69769
  break;
69681
69770
  }
69682
- const baseApiClient = authConfig.type === "none" ? createInternalAPIClient(config2.baseUrl) : authConfig.type === "api-key" ? createBearerAPIClient(authConfig.key, config2.baseUrl) : createBearerAPIClient(authConfig.token, config2.baseUrl);
69771
+ const baseApiClient = authConfig.type === "none" ? deps.createInternalAPIClient(config2.baseUrl) : authConfig.type === "api-key" ? deps.createBearerAPIClient(authConfig.key, config2.baseUrl) : deps.createBearerAPIClient(authConfig.token, config2.baseUrl);
69683
69772
  const apiClient = withDefaultHeaders(baseApiClient, config2.defaultHeaders);
69684
69773
  const cache = new SimpleCache({
69685
69774
  maxSize: cacheMaxSize,
@@ -70046,17 +70135,17 @@ function createRiverbankClient(config2) {
70046
70135
  async function getPageWithResilienceInternal(params) {
70047
70136
  const {
70048
70137
  siteId,
70049
- path: path32,
70138
+ path: path33,
70050
70139
  preview = false,
70051
70140
  signal,
70052
70141
  contentContract = "compat"
70053
70142
  } = params;
70054
70143
  const publishedRuntimeCache = planPublishedRuntimeCache({
70055
70144
  endpoint: "getContentByPath",
70056
- params: { siteId, path: path32, preview, contentContract },
70145
+ params: { siteId, path: path33, preview, contentContract },
70057
70146
  siteId
70058
70147
  });
70059
- const cacheKey = publishedRuntimeCache?.cacheKey ?? `page:${siteId}:${path32}:${preview}:${contentContract}`;
70148
+ const cacheKey = publishedRuntimeCache?.cacheKey ?? `page:${siteId}:${path33}:${preview}:${contentContract}`;
70060
70149
  return resilientFetch(
70061
70150
  cacheKey,
70062
70151
  async (sig) => {
@@ -70064,7 +70153,7 @@ function createRiverbankClient(config2) {
70064
70153
  endpoint: "getContentByPath",
70065
70154
  params: {
70066
70155
  siteId,
70067
- path: path32,
70156
+ path: path33,
70068
70157
  preview: String(preview),
70069
70158
  ...contentContract === "native" ? { contentContract } : {}
70070
70159
  },
@@ -70076,7 +70165,7 @@ function createRiverbankClient(config2) {
70076
70165
  signal,
70077
70166
  publishedRuntimeCache,
70078
70167
  // Prebuild fallback only for published pages (not preview)
70079
- prebuildFallback: prebuildLoader && !preview && contentContract !== "native" ? () => prebuildLoader.loadPage(siteId, path32) : void 0
70168
+ prebuildFallback: prebuildLoader && !preview && contentContract !== "native" ? () => prebuildLoader.loadPage(siteId, path33) : void 0
70080
70169
  }
70081
70170
  );
70082
70171
  }
@@ -70568,17 +70657,17 @@ function createRiverbankClient(config2) {
70568
70657
  };
70569
70658
  },
70570
70659
  async checkRedirect(params) {
70571
- const { siteId, path: path32, signal } = params;
70572
- if (!siteId || !path32) {
70660
+ const { siteId, path: path33, signal } = params;
70661
+ if (!siteId || !path33) {
70573
70662
  throw new Error("checkRedirect() requires siteId and path");
70574
70663
  }
70575
- const cacheKey = `redirect:${siteId}:${path32}`;
70664
+ const cacheKey = `redirect:${siteId}:${path33}`;
70576
70665
  return resilientFetchData(
70577
70666
  cacheKey,
70578
70667
  async (sig) => {
70579
70668
  return await apiClient({
70580
70669
  endpoint: "checkRedirect",
70581
- params: { site: siteId, path: path32 },
70670
+ params: { site: siteId, path: path33 },
70582
70671
  options: { signal: sig }
70583
70672
  });
70584
70673
  },
@@ -70586,27 +70675,27 @@ function createRiverbankClient(config2) {
70586
70675
  );
70587
70676
  },
70588
70677
  async resolveRouteOutcome(params) {
70589
- const { siteId, path: path32, preview = false, signal } = params;
70590
- if (!siteId || !path32) {
70678
+ const { siteId, path: path33, preview = false, signal } = params;
70679
+ if (!siteId || !path33) {
70591
70680
  throw new Error("resolveRouteOutcome() requires siteId and path");
70592
70681
  }
70593
70682
  return unwrapResponse(
70594
70683
  await apiClient({
70595
70684
  endpoint: "resolveRouteOutcome",
70596
- params: { siteId, path: path32, preview: String(preview) },
70685
+ params: { siteId, path: path33, preview: String(preview) },
70597
70686
  options: { signal }
70598
70687
  })
70599
70688
  );
70600
70689
  },
70601
70690
  async resolveRouteDecision(params) {
70602
- const { siteId, path: path32, preview = false, signal } = params;
70603
- if (!siteId || !path32) {
70691
+ const { siteId, path: path33, preview = false, signal } = params;
70692
+ if (!siteId || !path33) {
70604
70693
  throw new Error("resolveRouteDecision() requires siteId and path");
70605
70694
  }
70606
70695
  return unwrapResponse(
70607
70696
  await apiClient({
70608
70697
  endpoint: "resolveRouteDecision",
70609
- params: { siteId, path: path32, preview: String(preview) },
70698
+ params: { siteId, path: path33, preview: String(preview) },
70610
70699
  options: { signal }
70611
70700
  })
70612
70701
  );
@@ -70718,7 +70807,7 @@ async function fetchAllEntries(client, siteId, contentType, onProgress) {
70718
70807
  async function prebuildSite(client, siteId, outputDir) {
70719
70808
  const site = await client.getSite({ id: siteId });
70720
70809
  const filename = "site.json";
70721
- const filePath = path20.join(outputDir, filename);
70810
+ const filePath = path21.join(outputDir, filename);
70722
70811
  const cacheFile = {
70723
70812
  data: site,
70724
70813
  generatedAt: (/* @__PURE__ */ new Date()).toISOString()
@@ -70727,7 +70816,7 @@ async function prebuildSite(client, siteId, outputDir) {
70727
70816
  return { files: [filename], size, siteData: site };
70728
70817
  }
70729
70818
  async function prebuildPages(client, siteId, routes, outputDir, onProgress) {
70730
- const pagesDir = path20.join(outputDir, "pages");
70819
+ const pagesDir = path21.join(outputDir, "pages");
70731
70820
  ensureDir4(pagesDir);
70732
70821
  const files = [];
70733
70822
  const pathMappings = {};
@@ -70747,7 +70836,7 @@ async function prebuildPages(client, siteId, routes, outputDir, onProgress) {
70747
70836
  try {
70748
70837
  const pageData = await client.getPage({ siteId, path: pagePath, preview: false });
70749
70838
  const filename = pathToFilename(pagePath);
70750
- const filePath = path20.join(pagesDir, filename);
70839
+ const filePath = path21.join(pagesDir, filename);
70751
70840
  const cacheFile = {
70752
70841
  data: pageData,
70753
70842
  path: pagePath,
@@ -70772,13 +70861,13 @@ async function prebuildPages(client, siteId, routes, outputDir, onProgress) {
70772
70861
  totalCount: pageIndex.length,
70773
70862
  generatedAt: (/* @__PURE__ */ new Date()).toISOString()
70774
70863
  };
70775
- const indexPath = path20.join(pagesDir, "_index.json");
70864
+ const indexPath = path21.join(pagesDir, "_index.json");
70776
70865
  totalSize += writeJsonFile3(indexPath, indexFile);
70777
70866
  files.push("pages/_index.json");
70778
70867
  return { files, size: totalSize, pathMappings };
70779
70868
  }
70780
70869
  async function prebuildEntries(client, siteId, contentTypes, outputDir, onProgress) {
70781
- const entriesDir = path20.join(outputDir, "entries");
70870
+ const entriesDir = path21.join(outputDir, "entries");
70782
70871
  ensureDir4(entriesDir);
70783
70872
  const files = [];
70784
70873
  let totalSize = 0;
@@ -70799,7 +70888,7 @@ async function prebuildEntries(client, siteId, contentTypes, outputDir, onProgre
70799
70888
  });
70800
70889
  }
70801
70890
  );
70802
- const typeDir = path20.join(entriesDir, contentType);
70891
+ const typeDir = path21.join(entriesDir, contentType);
70803
70892
  ensureDir4(typeDir);
70804
70893
  const cacheFile = {
70805
70894
  entries,
@@ -70808,14 +70897,14 @@ async function prebuildEntries(client, siteId, contentTypes, outputDir, onProgre
70808
70897
  generatedAt: (/* @__PURE__ */ new Date()).toISOString()
70809
70898
  };
70810
70899
  const filename = `entries/${contentType}/all.json`;
70811
- const filePath = path20.join(entriesDir, contentType, "all.json");
70900
+ const filePath = path21.join(entriesDir, contentType, "all.json");
70812
70901
  totalSize += writeJsonFile3(filePath, cacheFile);
70813
70902
  files.push(filename);
70814
70903
  }
70815
70904
  return { files, size: totalSize };
70816
70905
  }
70817
70906
  async function prebuildNavigation(siteData, outputDir, onProgress) {
70818
- const navDir = path20.join(outputDir, "navigation");
70907
+ const navDir = path21.join(outputDir, "navigation");
70819
70908
  ensureDir4(navDir);
70820
70909
  const files = [];
70821
70910
  let totalSize = 0;
@@ -70836,13 +70925,13 @@ async function prebuildNavigation(siteData, outputDir, onProgress) {
70836
70925
  generatedAt: (/* @__PURE__ */ new Date()).toISOString()
70837
70926
  };
70838
70927
  const filename = "navigation/menus.json";
70839
- const filePath = path20.join(navDir, "menus.json");
70928
+ const filePath = path21.join(navDir, "menus.json");
70840
70929
  totalSize += writeJsonFile3(filePath, cacheFile);
70841
70930
  files.push(filename);
70842
70931
  return { files, size: totalSize };
70843
70932
  }
70844
70933
  async function prebuildForms(client, siteId, outputDir, onProgress) {
70845
- const formsDir = path20.join(outputDir, "forms");
70934
+ const formsDir = path21.join(outputDir, "forms");
70846
70935
  ensureDir4(formsDir);
70847
70936
  const files = [];
70848
70937
  let totalSize = 0;
@@ -70867,7 +70956,7 @@ async function prebuildForms(client, siteId, outputDir, onProgress) {
70867
70956
  generatedAt: (/* @__PURE__ */ new Date()).toISOString()
70868
70957
  };
70869
70958
  const filename = "forms/forms.json";
70870
- const filePath = path20.join(formsDir, "forms.json");
70959
+ const filePath = path21.join(formsDir, "forms.json");
70871
70960
  totalSize += writeJsonFile3(filePath, cacheFile);
70872
70961
  files.push(filename);
70873
70962
  } catch (error) {
@@ -70985,7 +71074,7 @@ async function prebuildCache(options) {
70985
71074
  };
70986
71075
  const checksum = calculateChecksum(manifest);
70987
71076
  manifest.checksum = checksum;
70988
- const manifestPath = path20.join(outputDir, MANIFEST_FILENAME);
71077
+ const manifestPath = path21.join(outputDir, MANIFEST_FILENAME);
70989
71078
  writeJsonFile3(manifestPath, manifest);
70990
71079
  return {
70991
71080
  success: errors.length === 0,
@@ -71014,7 +71103,7 @@ async function loadDeployConfig() {
71014
71103
  }
71015
71104
  async function checkWorkingDirectoryClean(git, prebuildOutput) {
71016
71105
  const status = await git.status();
71017
- const dirtyFiles = status.files.map((f) => f.path).filter((path32) => !path32.startsWith(prebuildOutput));
71106
+ const dirtyFiles = status.files.map((f) => f.path).filter((path33) => !path33.startsWith(prebuildOutput));
71018
71107
  return {
71019
71108
  clean: dirtyFiles.length === 0,
71020
71109
  dirtyFiles
@@ -71545,25 +71634,25 @@ function mapMediaGuardDiagnosticsToAuditIssues(diagnostics) {
71545
71634
  }
71546
71635
  }));
71547
71636
  }
71548
- function extractEmbedReferences(data, path32 = []) {
71637
+ function extractEmbedReferences(data, path33 = []) {
71549
71638
  const refs = [];
71550
71639
  if (!data || typeof data !== "object") return refs;
71551
71640
  if (Array.isArray(data)) {
71552
71641
  data.forEach((item, index) => {
71553
- refs.push(...extractEmbedReferences(item, [...path32, String(index)]));
71642
+ refs.push(...extractEmbedReferences(item, [...path33, String(index)]));
71554
71643
  });
71555
71644
  return refs;
71556
71645
  }
71557
71646
  const obj = data;
71558
71647
  if (obj.kind === "embed" && typeof obj.contentType === "string" && typeof obj.identifier === "string") {
71559
71648
  refs.push({
71560
- path: path32.join("."),
71649
+ path: path33.join("."),
71561
71650
  contentType: obj.contentType,
71562
71651
  identifier: obj.identifier
71563
71652
  });
71564
71653
  }
71565
71654
  for (const [key, value] of Object.entries(obj)) {
71566
- refs.push(...extractEmbedReferences(value, [...path32, key]));
71655
+ refs.push(...extractEmbedReferences(value, [...path33, key]));
71567
71656
  }
71568
71657
  return refs;
71569
71658
  }
@@ -71744,7 +71833,7 @@ async function executeAuditForEnv(output, target, options, isJsonOutput) {
71744
71833
  const warnings = [];
71745
71834
  try {
71746
71835
  const cliConfig = await loadCliConfig();
71747
- const contentDir = path20.resolve(options.contentDir ?? cliConfig.contentDir);
71836
+ const contentDir = path21.resolve(options.contentDir ?? cliConfig.contentDir);
71748
71837
  if (!await contentDirExists(contentDir)) {
71749
71838
  errors.push({
71750
71839
  severity: "error",
@@ -72066,7 +72155,7 @@ async function executeCompareLocalVsCms(output, target, scope, contentType, opti
72066
72155
  const isRemote = target === "remote";
72067
72156
  try {
72068
72157
  const cliConfig = await loadCliConfig();
72069
- const contentDir = path20.resolve(options.contentDir ?? cliConfig.contentDir);
72158
+ const contentDir = path21.resolve(options.contentDir ?? cliConfig.contentDir);
72070
72159
  if (!await contentDirExists(contentDir)) {
72071
72160
  output.error(`Content directory not found: ${contentDir}`, {
72072
72161
  suggestion: 'Run "riverbankcms pull" first to download content'
@@ -72312,7 +72401,7 @@ function createDebugWriter(debugDir) {
72312
72401
  };
72313
72402
  }
72314
72403
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
72315
- const runDir = path20.join(debugDir, `manifest-${timestamp}`);
72404
+ const runDir = path21.join(debugDir, `manifest-${timestamp}`);
72316
72405
  let dirCreated = false;
72317
72406
  async function ensureDir5() {
72318
72407
  if (!dirCreated) {
@@ -72325,14 +72414,14 @@ function createDebugWriter(debugDir) {
72325
72414
  async writeText(filename, content) {
72326
72415
  try {
72327
72416
  await ensureDir5();
72328
- await fs2.writeFile(path20.join(runDir, filename), content, "utf-8");
72417
+ await fs2.writeFile(path21.join(runDir, filename), content, "utf-8");
72329
72418
  } catch {
72330
72419
  }
72331
72420
  },
72332
72421
  async writeJson(filename, value) {
72333
72422
  try {
72334
72423
  await ensureDir5();
72335
- await fs2.writeFile(path20.join(runDir, filename), JSON.stringify(value, null, 2), "utf-8");
72424
+ await fs2.writeFile(path21.join(runDir, filename), JSON.stringify(value, null, 2), "utf-8");
72336
72425
  } catch {
72337
72426
  }
72338
72427
  }
@@ -72497,7 +72586,7 @@ function formatThemeSummaryForPrompt(summary) {
72497
72586
  }
72498
72587
 
72499
72588
  // src/manifest/validation/layout-utils.ts
72500
- function collectLayoutNodeInfos(node, path32 = "layout", out = []) {
72589
+ function collectLayoutNodeInfos(node, path33 = "layout", out = []) {
72501
72590
  if (!node || typeof node !== "object") return out;
72502
72591
  const n = node;
72503
72592
  const type = typeof n.type === "string" ? n.type : "unknown";
@@ -72506,10 +72595,10 @@ function collectLayoutNodeInfos(node, path32 = "layout", out = []) {
72506
72595
  const b = n.$bind;
72507
72596
  if (typeof b.from === "string") bindFrom = b.from;
72508
72597
  }
72509
- out.push({ path: path32, type, bindFrom });
72598
+ out.push({ path: path33, type, bindFrom });
72510
72599
  if (Array.isArray(n.children)) {
72511
72600
  for (let i = 0; i < n.children.length; i++) {
72512
- collectLayoutNodeInfos(n.children[i], `${path32}.children[${i}]`, out);
72601
+ collectLayoutNodeInfos(n.children[i], `${path33}.children[${i}]`, out);
72513
72602
  }
72514
72603
  }
72515
72604
  return out;
@@ -72931,7 +73020,7 @@ function extractNestedHrefBindFromProps(props2) {
72931
73020
  const bind2 = href.$bind;
72932
73021
  return bind2 && typeof bind2 === "object" ? bind2 : null;
72933
73022
  }
72934
- function findMissingLinkHrefs(node, blockId, fields3, path32 = "layout", repeatStack = []) {
73023
+ function findMissingLinkHrefs(node, blockId, fields3, path33 = "layout", repeatStack = []) {
72935
73024
  const errors = [];
72936
73025
  if (!node || typeof node !== "object") return errors;
72937
73026
  const n = node;
@@ -72960,21 +73049,21 @@ function findMissingLinkHrefs(node, blockId, fields3, path32 = "layout", repeatS
72960
73049
  if (isBoundToLinkField) {
72961
73050
  if (!hrefBind || !hrefFrom) {
72962
73051
  errors.push({
72963
- path: path32,
72964
- message: `Block "${blockId}": ${nodeType} node at ${path32} is bound to a link field but is missing props.href binding`,
73052
+ path: path33,
73053
+ message: `Block "${blockId}": ${nodeType} node at ${path33} is bound to a link field but is missing props.href binding`,
72965
73054
  suggestion: `Add props.href: { "$bind": { "from": "${bindFrom ?? "content.yourLinkField"}", "fallback": null, "transforms": [{ "id": "links.resolve" }] } }`
72966
73055
  });
72967
73056
  } else if (!bindingHasTransform(hrefBind, "links.resolve")) {
72968
73057
  errors.push({
72969
- path: path32,
72970
- message: `Block "${blockId}": ${nodeType} node at ${path32} has props.href binding but is missing transforms: [{id:"links.resolve"}]`,
73058
+ path: path33,
73059
+ message: `Block "${blockId}": ${nodeType} node at ${path33} has props.href binding but is missing transforms: [{id:"links.resolve"}]`,
72971
73060
  suggestion: `Set props.href.$bind.transforms to [{ "id": "links.resolve" }].`
72972
73061
  });
72973
73062
  }
72974
73063
  if (bindFrom && bindFieldType === "link" && !bindingHasTransform(bind2, "links.label")) {
72975
73064
  errors.push({
72976
- path: path32,
72977
- message: `Block "${blockId}": ${nodeType} node at ${path32} binds label from a link field but is missing links.label transform`,
73065
+ path: path33,
73066
+ message: `Block "${blockId}": ${nodeType} node at ${path33} binds label from a link field but is missing links.label transform`,
72978
73067
  suggestion: `Set node.$bind.transforms to [{ "id": "links.label" }] so the label renders as text.`
72979
73068
  });
72980
73069
  }
@@ -72987,7 +73076,7 @@ function findMissingLinkHrefs(node, blockId, fields3, path32 = "layout", repeatS
72987
73076
  n.children[i],
72988
73077
  blockId,
72989
73078
  fields3,
72990
- `${path32}.children[${i}]`,
73079
+ `${path33}.children[${i}]`,
72991
73080
  nextRepeatStack
72992
73081
  )
72993
73082
  );
@@ -72995,7 +73084,7 @@ function findMissingLinkHrefs(node, blockId, fields3, path32 = "layout", repeatS
72995
73084
  }
72996
73085
  return errors;
72997
73086
  }
72998
- function detectRedundantLinkLabels(node, blockId, fields3, path32 = "layout", repeatStack = []) {
73087
+ function detectRedundantLinkLabels(node, blockId, fields3, path33 = "layout", repeatStack = []) {
72999
73088
  const errors = [];
73000
73089
  if (!node || typeof node !== "object") return errors;
73001
73090
  const n = node;
@@ -73017,7 +73106,7 @@ function detectRedundantLinkLabels(node, blockId, fields3, path32 = "layout", re
73017
73106
  const redundancies = findRedundantLinkTextSiblings(
73018
73107
  children,
73019
73108
  nextRepeatStack,
73020
- path32
73109
+ path33
73021
73110
  );
73022
73111
  errors.push(
73023
73112
  ...redundancies.map((r) => ({
@@ -73034,7 +73123,7 @@ function detectRedundantLinkLabels(node, blockId, fields3, path32 = "layout", re
73034
73123
  n.children[i],
73035
73124
  blockId,
73036
73125
  fields3,
73037
- `${path32}.children[${i}]`,
73126
+ `${path33}.children[${i}]`,
73038
73127
  nextRepeatStack
73039
73128
  )
73040
73129
  );
@@ -73273,19 +73362,19 @@ function extractBlockIdFromSelector(selector) {
73273
73362
  const match = selector.match(/\[data-block=(["'])(custom\.[^"']+)\1\]/);
73274
73363
  return match?.[2] ?? null;
73275
73364
  }
73276
- function validateNodeType(nodeType, path32, ctx) {
73365
+ function validateNodeType(nodeType, path33, ctx) {
73277
73366
  if (!ALLOWED_NODE_TYPES.includes(
73278
73367
  nodeType
73279
73368
  )) {
73280
73369
  return {
73281
- path: `${path32}.type`,
73282
- message: `Block "${ctx.blockId}": Unknown node type "${nodeType}" at ${path32}`,
73370
+ path: `${path33}.type`,
73371
+ message: `Block "${ctx.blockId}": Unknown node type "${nodeType}" at ${path33}`,
73283
73372
  suggestion: `ALLOWED: ${ALLOWED_NODE_TYPES.slice(0, 10).join(", ")}... FIX: Replace "${nodeType}" with a valid node type.`
73284
73373
  };
73285
73374
  }
73286
73375
  return null;
73287
73376
  }
73288
- function validateTransforms(transforms, path32, ctx) {
73377
+ function validateTransforms(transforms, path33, ctx) {
73289
73378
  const errors = [];
73290
73379
  for (let i = 0; i < transforms.length; i++) {
73291
73380
  const transform = transforms[i];
@@ -73294,7 +73383,7 @@ function validateTransforms(transforms, path32, ctx) {
73294
73383
  transform.id
73295
73384
  )) {
73296
73385
  errors.push({
73297
- path: `${path32}.transforms[${i}].id`,
73386
+ path: `${path33}.transforms[${i}].id`,
73298
73387
  message: `Block "${ctx.blockId}": Unknown transform "${transform.id}"`,
73299
73388
  suggestion: `ALLOWED: ${ALLOWED_TRANSFORM_IDS.slice(0, 8).join(", ")}... FIX: Replace with a valid transform ID or remove.`
73300
73389
  });
@@ -73303,7 +73392,7 @@ function validateTransforms(transforms, path32, ctx) {
73303
73392
  }
73304
73393
  return errors;
73305
73394
  }
73306
- function validateBinding(bind2, path32, ctx) {
73395
+ function validateBinding(bind2, path33, ctx) {
73307
73396
  const errors = [];
73308
73397
  if ("from" in bind2 && typeof bind2.from === "string") {
73309
73398
  const bindPath = bind2.from;
@@ -73311,7 +73400,7 @@ function validateBinding(bind2, path32, ctx) {
73311
73400
  const fieldId = bindPath.replace("content.", "").split(".")[0] ?? "";
73312
73401
  if (fieldId && !ctx.fieldIds.has(fieldId)) {
73313
73402
  errors.push({
73314
- path: `${path32}.from`,
73403
+ path: `${path33}.from`,
73315
73404
  message: `Block "${ctx.blockId}": $bind references unknown field "${fieldId}"`,
73316
73405
  suggestion: `DEFINED FIELDS: ${Array.from(ctx.fieldIds).join(", ")}. FIX: Add field { id: '${fieldId}', type: '...' } or use existing field.`
73317
73406
  });
@@ -73319,31 +73408,31 @@ function validateBinding(bind2, path32, ctx) {
73319
73408
  }
73320
73409
  }
73321
73410
  if ("transforms" in bind2 && Array.isArray(bind2.transforms)) {
73322
- errors.push(...validateTransforms(bind2.transforms, path32, ctx));
73411
+ errors.push(...validateTransforms(bind2.transforms, path33, ctx));
73323
73412
  }
73324
73413
  return errors;
73325
73414
  }
73326
- function validateLayoutDeep(node, blockId, fields3, path32 = "layout") {
73415
+ function validateLayoutDeep(node, blockId, fields3, path33 = "layout") {
73327
73416
  const ctx = {
73328
73417
  blockId,
73329
73418
  fieldIds: collectFieldIds(fields3)
73330
73419
  };
73331
- return validateLayoutNode(node, path32, ctx);
73420
+ return validateLayoutNode(node, path33, ctx);
73332
73421
  }
73333
- function validateLayoutNode(node, path32, ctx) {
73422
+ function validateLayoutNode(node, path33, ctx) {
73334
73423
  const errors = [];
73335
73424
  if (!node || typeof node !== "object") {
73336
73425
  return errors;
73337
73426
  }
73338
73427
  const n = node;
73339
73428
  if ("type" in n && typeof n.type === "string") {
73340
- const typeError = validateNodeType(n.type, path32, ctx);
73429
+ const typeError = validateNodeType(n.type, path33, ctx);
73341
73430
  if (typeError) errors.push(typeError);
73342
73431
  }
73343
73432
  if ("$bind" in n && n.$bind && typeof n.$bind === "object") {
73344
73433
  const bindErrors = validateBinding(
73345
73434
  n.$bind,
73346
- `${path32}.$bind`,
73435
+ `${path33}.$bind`,
73347
73436
  ctx
73348
73437
  );
73349
73438
  errors.push(...bindErrors);
@@ -73351,7 +73440,7 @@ function validateLayoutNode(node, path32, ctx) {
73351
73440
  if ("props" in n && n.props && typeof n.props === "object") {
73352
73441
  const propsErrors = validatePropsBindings(
73353
73442
  n.props,
73354
- `${path32}.props`,
73443
+ `${path33}.props`,
73355
73444
  ctx
73356
73445
  );
73357
73446
  errors.push(...propsErrors);
@@ -73360,7 +73449,7 @@ function validateLayoutNode(node, path32, ctx) {
73360
73449
  for (let i = 0; i < n.children.length; i++) {
73361
73450
  const childErrors = validateLayoutNode(
73362
73451
  n.children[i],
73363
- `${path32}.children[${i}]`,
73452
+ `${path33}.children[${i}]`,
73364
73453
  ctx
73365
73454
  );
73366
73455
  errors.push(...childErrors);
@@ -73368,17 +73457,17 @@ function validateLayoutNode(node, path32, ctx) {
73368
73457
  }
73369
73458
  return errors;
73370
73459
  }
73371
- function validatePropsBindings(props2, path32, ctx) {
73460
+ function validatePropsBindings(props2, path33, ctx) {
73372
73461
  const errors = [];
73373
73462
  for (const [key, value] of Object.entries(props2)) {
73374
73463
  if (value && typeof value === "object" && "$bind" in value) {
73375
73464
  const bind2 = value.$bind;
73376
- const bindErrors = validateBinding(bind2, `${path32}.${key}.$bind`, ctx);
73465
+ const bindErrors = validateBinding(bind2, `${path33}.${key}.$bind`, ctx);
73377
73466
  errors.push(...bindErrors);
73378
73467
  } else if (value && typeof value === "object" && !Array.isArray(value)) {
73379
73468
  const nestedErrors = validatePropsBindings(
73380
73469
  value,
73381
- `${path32}.${key}`,
73470
+ `${path33}.${key}`,
73382
73471
  ctx
73383
73472
  );
73384
73473
  errors.push(...nestedErrors);
@@ -73511,7 +73600,7 @@ function collectUsedFieldRefs(node) {
73511
73600
  visit(node, []);
73512
73601
  return { topLevel, nestedByRepeater, itemNameByRepeater };
73513
73602
  }
73514
- function findMissingBindings(node, blockId, path32 = "layout") {
73603
+ function findMissingBindings(node, blockId, path33 = "layout") {
73515
73604
  const errors = [];
73516
73605
  if (!node || typeof node !== "object") {
73517
73606
  return errors;
@@ -73521,15 +73610,15 @@ function findMissingBindings(node, blockId, path32 = "layout") {
73521
73610
  if ("$repeat" in n && n.$repeat && typeof n.$repeat === "object") {
73522
73611
  if (nodeType && CONTENT_NODE_TYPES.includes(nodeType)) {
73523
73612
  errors.push({
73524
- path: path32,
73525
- message: `Block "${blockId}": ${nodeType} node at ${path32} uses $repeat, but content nodes cannot be repeat containers`,
73613
+ path: path33,
73614
+ message: `Block "${blockId}": ${nodeType} node at ${path33} uses $repeat, but content nodes cannot be repeat containers`,
73526
73615
  suggestion: `Move $repeat to a container node (grid/stack/div) and put a ${nodeType} child inside with $bind.from like "item.field".`
73527
73616
  });
73528
73617
  }
73529
73618
  if (!Array.isArray(n.children) || n.children.length === 0) {
73530
73619
  errors.push({
73531
- path: path32,
73532
- message: `Block "${blockId}": node at ${path32} uses $repeat but has no children to repeat`,
73620
+ path: path33,
73621
+ message: `Block "${blockId}": node at ${path33} uses $repeat but has no children to repeat`,
73533
73622
  suggestion: 'Add one or more child nodes under children[] that bind to the repeat item (e.g., $bind.from: "item.text").'
73534
73623
  });
73535
73624
  }
@@ -73538,15 +73627,15 @@ function findMissingBindings(node, blockId, path32 = "layout") {
73538
73627
  const hasBind = "$bind" in n && n.$bind && typeof n.$bind === "object" && "from" in n.$bind;
73539
73628
  if (Array.isArray(n.children) && n.children.length > 0) {
73540
73629
  errors.push({
73541
- path: path32,
73542
- message: `Block "${blockId}": ${nodeType} node at ${path32} has children, but content nodes must have children: null`,
73630
+ path: path33,
73631
+ message: `Block "${blockId}": ${nodeType} node at ${path33} has children, but content nodes must have children: null`,
73543
73632
  suggestion: `Replace this ${nodeType} with a container node (div/stack/inline) and put the ${nodeType} nodes inside it.`
73544
73633
  });
73545
73634
  }
73546
73635
  if (!hasBind) {
73547
73636
  errors.push({
73548
- path: `${path32}`,
73549
- message: `Block "${blockId}": ${nodeType} node at ${path32} has no $bind - it won't display any content`,
73637
+ path: `${path33}`,
73638
+ message: `Block "${blockId}": ${nodeType} node at ${path33} has no $bind - it won't display any content`,
73550
73639
  suggestion: `Add $bind: { from: "content.fieldName" } to connect this ${nodeType} to a field. Example: { "type": "${nodeType}", "$bind": { "from": "content.headline" } }`
73551
73640
  });
73552
73641
  }
@@ -73556,7 +73645,7 @@ function findMissingBindings(node, blockId, path32 = "layout") {
73556
73645
  const childErrors = findMissingBindings(
73557
73646
  n.children[i],
73558
73647
  blockId,
73559
- `${path32}.children[${i}]`
73648
+ `${path33}.children[${i}]`
73560
73649
  );
73561
73650
  errors.push(...childErrors);
73562
73651
  }
@@ -73573,13 +73662,13 @@ function getMaxDepth(node, currentDepth = 0) {
73573
73662
  );
73574
73663
  }
73575
73664
  var CONTAINER_NODE_TYPES = ["section", "stack", "grid", "div", "inline"];
73576
- function detectPotentialTruncation(node, maxAllowedDepth, currentDepth = 0, path32 = "layout") {
73665
+ function detectPotentialTruncation(node, maxAllowedDepth, currentDepth = 0, path33 = "layout") {
73577
73666
  if (!node || typeof node !== "object") return [];
73578
73667
  const n = node;
73579
73668
  const truncatedPaths = [];
73580
73669
  if (currentDepth === maxAllowedDepth && n.children === null) {
73581
73670
  if (CONTAINER_NODE_TYPES.includes(n.type || "")) {
73582
- truncatedPaths.push(`${path32} (${n.type ?? "node"} at depth ${currentDepth})`);
73671
+ truncatedPaths.push(`${path33} (${n.type ?? "node"} at depth ${currentDepth})`);
73583
73672
  }
73584
73673
  }
73585
73674
  if (n.children && Array.isArray(n.children)) {
@@ -73589,7 +73678,7 @@ function detectPotentialTruncation(node, maxAllowedDepth, currentDepth = 0, path
73589
73678
  child,
73590
73679
  maxAllowedDepth,
73591
73680
  currentDepth + 1,
73592
- `${path32}.children[${i}]`
73681
+ `${path33}.children[${i}]`
73593
73682
  )
73594
73683
  );
73595
73684
  });
@@ -73609,8 +73698,8 @@ function formatValidationFeedback(errors, output) {
73609
73698
  `The layout reached the maximum depth of ${MAX_LAYOUT_DEPTH} levels.`
73610
73699
  );
73611
73700
  lines.push("These container nodes at the depth limit have no children:");
73612
- for (const path32 of truncatedPaths) {
73613
- lines.push(` \u26A0\uFE0F ${path32}`);
73701
+ for (const path33 of truncatedPaths) {
73702
+ lines.push(` \u26A0\uFE0F ${path33}`);
73614
73703
  }
73615
73704
  lines.push("");
73616
73705
  lines.push(
@@ -74073,11 +74162,11 @@ var pass3bOutputSchema = z.object({
74073
74162
  customCssAtRules: z.array(llmMediaAtRuleSchema).nullable(),
74074
74163
  rationale: z.string()
74075
74164
  });
74076
- function getNodeAtPath(layout, path32) {
74077
- if (path32 === "" || path32 === "root" || path32 === "layout") {
74165
+ function getNodeAtPath(layout, path33) {
74166
+ if (path33 === "" || path33 === "root" || path33 === "layout") {
74078
74167
  return layout;
74079
74168
  }
74080
- let normalizedPath = path32;
74169
+ let normalizedPath = path33;
74081
74170
  if (normalizedPath.startsWith("layout.")) {
74082
74171
  normalizedPath = normalizedPath.slice(7);
74083
74172
  }
@@ -75477,7 +75566,7 @@ The generated manifest can be added to your riverbank.config.ts customBlocks arr
75477
75566
  const { output } = getOutputContext(command);
75478
75567
  try {
75479
75568
  output.info("Reading input files...");
75480
- const htmlPath = path20.resolve(options.html);
75569
+ const htmlPath = path21.resolve(options.html);
75481
75570
  let html;
75482
75571
  try {
75483
75572
  html = await fs2.readFile(htmlPath, "utf-8");
@@ -75486,7 +75575,7 @@ The generated manifest can be added to your riverbank.config.ts customBlocks arr
75486
75575
  suggestion: "Check that the file exists and is readable"
75487
75576
  });
75488
75577
  }
75489
- const themePath = path20.resolve(options.theme);
75578
+ const themePath = path21.resolve(options.theme);
75490
75579
  let themeData;
75491
75580
  try {
75492
75581
  const themeJson = await fs2.readFile(themePath, "utf-8");
@@ -75511,7 +75600,7 @@ The generated manifest can be added to your riverbank.config.ts customBlocks arr
75511
75600
  }
75512
75601
  let css;
75513
75602
  if (options.css) {
75514
- const cssPath = path20.resolve(options.css);
75603
+ const cssPath = path21.resolve(options.css);
75515
75604
  try {
75516
75605
  css = await fs2.readFile(cssPath, "utf-8");
75517
75606
  } catch {
@@ -75526,7 +75615,7 @@ The generated manifest can be added to your riverbank.config.ts customBlocks arr
75526
75615
  return output.error("--retries must be a number between 1 and 10");
75527
75616
  }
75528
75617
  const expectedBlockCount = options.blocks;
75529
- const debugDir = options.debug ? path20.resolve(options.debug) : void 0;
75618
+ const debugDir = options.debug ? path21.resolve(options.debug) : void 0;
75530
75619
  let ai;
75531
75620
  try {
75532
75621
  ai = await loadAiRuntime(options.aiRuntime);
@@ -75569,7 +75658,7 @@ The generated manifest can be added to your riverbank.config.ts customBlocks arr
75569
75658
  }
75570
75659
  const jsonOutput = JSON.stringify(result.output, null, 2);
75571
75660
  if (options.output) {
75572
- const outputPath = path20.resolve(options.output);
75661
+ const outputPath = path21.resolve(options.output);
75573
75662
  await fs2.writeFile(outputPath, jsonOutput, "utf-8");
75574
75663
  output.success(`Manifest written to ${outputPath}`);
75575
75664
  output.info(`Generated ${result.output.blocks.length} block(s)`);
@@ -75595,7 +75684,7 @@ The generated manifest can be added to your riverbank.config.ts customBlocks arr
75595
75684
  var validateCommand = new Command("validate").description("Validate a manifest JSON file").requiredOption("--file <file>", "Manifest JSON file to validate").action(async (options, command) => {
75596
75685
  const { output } = getOutputContext(command);
75597
75686
  try {
75598
- const filePath = path20.resolve(options.file);
75687
+ const filePath = path21.resolve(options.file);
75599
75688
  let data;
75600
75689
  try {
75601
75690
  const json = await fs2.readFile(filePath, "utf-8");
@@ -76116,13 +76205,13 @@ function migrateLegacyEntryTitleInPlace(entry) {
76116
76205
  return { updated: true, migratedToDataTitle };
76117
76206
  }
76118
76207
  async function backupLegacyFile(contentDir, legacyFilePath, dryRun) {
76119
- const backupDir = path20.join(contentDir, ".legacy", "entries");
76120
- const destPath = path20.join(backupDir, path20.basename(legacyFilePath));
76208
+ const backupDir = path21.join(contentDir, ".legacy", "entries");
76209
+ const destPath = path21.join(backupDir, path21.basename(legacyFilePath));
76121
76210
  if (dryRun) return false;
76122
76211
  await ensureDir(backupDir);
76123
76212
  if (await fileExists(destPath)) {
76124
76213
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
76125
- const ext = path20.extname(destPath);
76214
+ const ext = path21.extname(destPath);
76126
76215
  const base = destPath.slice(0, -ext.length);
76127
76216
  await fs2.rename(legacyFilePath, `${base}.${timestamp}${ext}`);
76128
76217
  return true;
@@ -76145,7 +76234,7 @@ async function migrateLegacyEntriesFile(contentDir, legacyFilePath, options) {
76145
76234
  if (options.contentType && options.contentType !== contentType) {
76146
76235
  return { entriesWritten: 0, backedUp: false, legacyTitlesMigrated: 0, legacyTitleFilesUpdated: 0 };
76147
76236
  }
76148
- const typeDir = path20.join(contentDir, "entries", contentType);
76237
+ const typeDir = path21.join(contentDir, "entries", contentType);
76149
76238
  if (!options.dryRun) {
76150
76239
  await ensureDir(typeDir);
76151
76240
  }
@@ -76166,7 +76255,7 @@ async function migrateLegacyEntriesFile(contentDir, legacyFilePath, options) {
76166
76255
  const { updated, migratedToDataTitle } = migrateLegacyEntryTitleInPlace(entryUnknown);
76167
76256
  if (updated) legacyTitleFilesUpdated += 1;
76168
76257
  if (migratedToDataTitle) legacyTitlesMigrated += 1;
76169
- const entryPath = path20.join(typeDir, `${identifier}.json`);
76258
+ const entryPath = path21.join(typeDir, `${identifier}.json`);
76170
76259
  if (await fileExists(entryPath)) {
76171
76260
  if (!options.force) {
76172
76261
  const existing = await readJsonFile(entryPath);
@@ -76207,9 +76296,9 @@ async function migrateLegacyTitlesInDirectory(typeDir, options) {
76207
76296
  return { scanned, updatedFiles, titlesMigrated };
76208
76297
  }
76209
76298
  async function migrateEntries(options) {
76210
- const entriesDir = path20.join(options.contentDir, "entries");
76299
+ const entriesDir = path21.join(options.contentDir, "entries");
76211
76300
  const legacyFiles = await findLegacyEntryFiles(options.contentDir);
76212
- const filteredLegacyFiles = options.contentType ? legacyFiles.filter((f) => path20.basename(f, ".json") === options.contentType) : legacyFiles;
76301
+ const filteredLegacyFiles = options.contentType ? legacyFiles.filter((f) => path21.basename(f, ".json") === options.contentType) : legacyFiles;
76213
76302
  let legacyFilesMigrated = 0;
76214
76303
  let legacyFilesBackedUp = 0;
76215
76304
  let entriesWritten = 0;
@@ -76233,7 +76322,7 @@ async function migrateEntries(options) {
76233
76322
  for (const item of items) {
76234
76323
  if (!item.isDirectory()) continue;
76235
76324
  if (options.contentType && item.name !== options.contentType) continue;
76236
- const typeDir = path20.join(entriesDir, item.name);
76325
+ const typeDir = path21.join(entriesDir, item.name);
76237
76326
  const res = await migrateLegacyTitlesInDirectory(typeDir, { dryRun: options.dryRun });
76238
76327
  entryFilesScanned += res.scanned;
76239
76328
  legacyTitleFilesUpdated += res.updatedFiles;
@@ -76309,7 +76398,7 @@ function legacySlugCandidates(legacy) {
76309
76398
  return [...candidates];
76310
76399
  }
76311
76400
  async function readLegacyEventEntries(contentDir) {
76312
- const legacyDir = path20.join(contentDir, "entries", CANONICAL_EVENT_ENTRY_TYPE);
76401
+ const legacyDir = path21.join(contentDir, "entries", CANONICAL_EVENT_ENTRY_TYPE);
76313
76402
  const files = await listFiles(legacyDir, ".json");
76314
76403
  files.sort();
76315
76404
  const entries = [];
@@ -76331,12 +76420,12 @@ async function readLegacyEventEntries(contentDir) {
76331
76420
  });
76332
76421
  continue;
76333
76422
  }
76334
- const identifier = typeof raw.identifier === "string" && raw.identifier.trim() ? raw.identifier : path20.basename(filePath, ".json");
76423
+ const identifier = typeof raw.identifier === "string" && raw.identifier.trim() ? raw.identifier : path21.basename(filePath, ".json");
76335
76424
  entries.push({
76336
76425
  tag: "valid",
76337
76426
  legacy: {
76338
76427
  filePath,
76339
- fileBaseIdentifier: path20.basename(filePath, ".json"),
76428
+ fileBaseIdentifier: path21.basename(filePath, ".json"),
76340
76429
  entry: { ...raw, identifier, data: raw.data }
76341
76430
  }
76342
76431
  });
@@ -76344,7 +76433,7 @@ async function readLegacyEventEntries(contentDir) {
76344
76433
  return entries;
76345
76434
  }
76346
76435
  async function readCanonicalEventsWithPaths(contentDir) {
76347
- const eventsDir = path20.join(contentDir, "events");
76436
+ const eventsDir = path21.join(contentDir, "events");
76348
76437
  const files = await listFiles(eventsDir, ".json");
76349
76438
  files.sort();
76350
76439
  const events = [];
@@ -76621,7 +76710,7 @@ async function planEventMigration(contentDir) {
76621
76710
  });
76622
76711
  continue;
76623
76712
  }
76624
- const eventFilePath = eventFilePaths.get(event.identifier) ?? path20.join(contentDir, "events", `${event.identifier}.json`);
76713
+ const eventFilePath = eventFilePaths.get(event.identifier) ?? path21.join(contentDir, "events", `${event.identifier}.json`);
76625
76714
  if (mergePlan.fields.length === 0) {
76626
76715
  items.push({
76627
76716
  tag: "archiveLegacyOnly",
@@ -76654,15 +76743,15 @@ function isBlockedPlanItem(item) {
76654
76743
  return !isWritablePlanItem(item);
76655
76744
  }
76656
76745
  async function archiveLegacyFile(contentDir, legacyFilePath) {
76657
- const archiveDir = path20.join(contentDir, ".legacy", "entries", CANONICAL_EVENT_ENTRY_TYPE);
76746
+ const archiveDir = path21.join(contentDir, ".legacy", "entries", CANONICAL_EVENT_ENTRY_TYPE);
76658
76747
  await ensureDir(archiveDir);
76659
- const destinationPath = path20.join(archiveDir, path20.basename(legacyFilePath));
76748
+ const destinationPath = path21.join(archiveDir, path21.basename(legacyFilePath));
76660
76749
  if (!await fileExists(destinationPath)) {
76661
76750
  await fs2.rename(legacyFilePath, destinationPath);
76662
76751
  return;
76663
76752
  }
76664
76753
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
76665
- const ext = path20.extname(destinationPath);
76754
+ const ext = path21.extname(destinationPath);
76666
76755
  const base = destinationPath.slice(0, -ext.length);
76667
76756
  await fs2.rename(legacyFilePath, `${base}.${timestamp}${ext}`);
76668
76757
  }
@@ -76735,49 +76824,49 @@ function formatEventMigrationItem(item) {
76735
76824
  case "mergeLegacyIntoEvent":
76736
76825
  return [
76737
76826
  "merge",
76738
- path20.basename(item.legacyFilePath),
76827
+ path21.basename(item.legacyFilePath),
76739
76828
  item.eventIdentifier,
76740
76829
  item.mergedFields.join(", ")
76741
76830
  ];
76742
76831
  case "archiveLegacyOnly":
76743
76832
  return [
76744
76833
  "archive",
76745
- path20.basename(item.legacyFilePath),
76834
+ path21.basename(item.legacyFilePath),
76746
76835
  item.eventIdentifier,
76747
76836
  item.reason
76748
76837
  ];
76749
76838
  case "conflict":
76750
76839
  return [
76751
76840
  "conflict",
76752
- path20.basename(item.legacyFilePath),
76841
+ path21.basename(item.legacyFilePath),
76753
76842
  item.eventIdentifier,
76754
76843
  item.conflicts.join(", ")
76755
76844
  ];
76756
76845
  case "ambiguousMatch":
76757
76846
  return [
76758
76847
  "ambiguous",
76759
- path20.basename(item.legacyFilePath),
76848
+ path21.basename(item.legacyFilePath),
76760
76849
  item.candidateEventIdentifiers.join(", "),
76761
76850
  "Multiple canonical events matched this legacy entry."
76762
76851
  ];
76763
76852
  case "unmappableLegacyFields":
76764
76853
  return [
76765
76854
  "unmappable",
76766
- path20.basename(item.legacyFilePath),
76855
+ path21.basename(item.legacyFilePath),
76767
76856
  item.eventIdentifier ?? "",
76768
76857
  item.fields.join(", ")
76769
76858
  ];
76770
76859
  case "orphanedLegacy":
76771
76860
  return [
76772
76861
  "orphaned",
76773
- path20.basename(item.legacyFilePath),
76862
+ path21.basename(item.legacyFilePath),
76774
76863
  item.legacyIdentifier,
76775
76864
  item.reason
76776
76865
  ];
76777
76866
  case "invalidLegacyShape":
76778
76867
  return [
76779
76868
  "invalid",
76780
- path20.basename(item.legacyFilePath),
76869
+ path21.basename(item.legacyFilePath),
76781
76870
  "",
76782
76871
  item.reason
76783
76872
  ];
@@ -76812,7 +76901,7 @@ Examples:
76812
76901
  }
76813
76902
  try {
76814
76903
  const cliConfig = await loadCliConfig();
76815
- const contentDir = path20.resolve(options.contentDir ?? cliConfig.contentDir);
76904
+ const contentDir = path21.resolve(options.contentDir ?? cliConfig.contentDir);
76816
76905
  if (type === "event") {
76817
76906
  process.exitCode = 1;
76818
76907
  output.result(false, "`event` entries use the canonical events migration.", {
@@ -76883,7 +76972,7 @@ Examples:
76883
76972
  }
76884
76973
  try {
76885
76974
  const cliConfig = await loadCliConfig();
76886
- const contentDir = path20.resolve(options.contentDir ?? cliConfig.contentDir);
76975
+ const contentDir = path21.resolve(options.contentDir ?? cliConfig.contentDir);
76887
76976
  const confirmed = await confirmAction(
76888
76977
  options.dryRun ? "Preview event entry migration?" : "Migrate legacy event entries into canonical event files?",
76889
76978
  { yes: options.yes },
@@ -77150,7 +77239,7 @@ function planHumanResultOutput(input) {
77150
77239
  details.push(`Endpoint: ${result.plannedEndpoint.name} (${result.plannedEndpoint.url})`);
77151
77240
  }
77152
77241
  if (envWrite) {
77153
- details.push(`Env: ${envPatchLabel(envWrite.plan.tag)} at ${path20.relative(process.cwd(), envWrite.path)}`);
77242
+ details.push(`Env: ${envPatchLabel(envWrite.plan.tag)} at ${path21.relative(process.cwd(), envWrite.path)}`);
77154
77243
  } else if (hasSecret(result) && writeEnv) {
77155
77244
  details.push("Env: no local env file changes were made");
77156
77245
  }
@@ -77193,7 +77282,7 @@ Examples:
77193
77282
  dryRun: options.dryRun,
77194
77283
  vercel: options.vercel
77195
77284
  });
77196
- const envPath = path20.resolve(process.cwd(), ".env.local");
77285
+ const envPath = path21.resolve(process.cwd(), ".env.local");
77197
77286
  const envWrite = hasSecret(result) && writeEnv && !result.dryRun ? await writeEnvSecret(envPath, result.secret) : null;
77198
77287
  if (ctx.isJsonOutput) {
77199
77288
  ctx.output.json({
@@ -77274,8 +77363,8 @@ function parseContentFieldPath(value) {
77274
77363
  }
77275
77364
  return { ok: true, path: segments };
77276
77365
  }
77277
- function formatContentFieldPath(path32) {
77278
- return formatFieldPath2(path32);
77366
+ function formatContentFieldPath(path33) {
77367
+ return formatFieldPath2(path33);
77279
77368
  }
77280
77369
  function planPageContentEdit(page, operation) {
77281
77370
  if (page.identifier !== operation.pageIdentifier) {
@@ -77339,8 +77428,8 @@ function changedPlan(operation, before, after) {
77339
77428
  before,
77340
77429
  after,
77341
77430
  changes: buildFieldChanges(pageDiffRecord(after), pageDiffRecord(before), {
77342
- identifyArrayItem: ({ path: path32, item }) => {
77343
- const last = path32[path32.length - 1];
77431
+ identifyArrayItem: ({ path: path33, item }) => {
77432
+ const last = path33[path33.length - 1];
77344
77433
  if (last?.type !== "property" || last.key !== "blocks") return null;
77345
77434
  return blockIdentifier(item);
77346
77435
  }
@@ -77394,15 +77483,15 @@ function normalizeBlockPositions(blocks) {
77394
77483
  block.position = index;
77395
77484
  });
77396
77485
  }
77397
- function setFieldPath(target, path32, value) {
77486
+ function setFieldPath(target, path33, value) {
77398
77487
  let current = target;
77399
- for (let index = 0; index < path32.length; index++) {
77400
- const segment = path32[index];
77401
- const isLast = index === path32.length - 1;
77488
+ for (let index = 0; index < path33.length; index++) {
77489
+ const segment = path33[index];
77490
+ const isLast = index === path33.length - 1;
77402
77491
  if (!segment) return { ok: false, error: "Invalid empty path segment." };
77403
77492
  if (segment.type === "property") {
77404
77493
  if (!isRecord28(current)) {
77405
- return { ok: false, error: `Cannot set ${formatContentFieldPath(path32)} because ${segment.key} is not inside an object.` };
77494
+ return { ok: false, error: `Cannot set ${formatContentFieldPath(path33)} because ${segment.key} is not inside an object.` };
77406
77495
  }
77407
77496
  if (isLast) {
77408
77497
  current[segment.key] = value;
@@ -77552,12 +77641,12 @@ function renderEditPlan(output, plan, options) {
77552
77641
  }
77553
77642
  }
77554
77643
  async function resolveContentDir(contentDir) {
77555
- if (contentDir) return path20.resolve(contentDir);
77644
+ if (contentDir) return path21.resolve(contentDir);
77556
77645
  const cliConfig = await loadCliConfig();
77557
- return path20.resolve(cliConfig.contentDir);
77646
+ return path21.resolve(cliConfig.contentDir);
77558
77647
  }
77559
77648
  function pageFilePath(contentDir, pageIdentifier) {
77560
- return path20.join(contentDir, "pages", `${pageIdentifier}.json`);
77649
+ return path21.join(contentDir, "pages", `${pageIdentifier}.json`);
77561
77650
  }
77562
77651
  function createCommandOutput(command) {
77563
77652
  return createOutput(command.optsWithGlobals());